mirror of
https://codeberg.org/PLG-Development/PLG-MuDiCS
synced 2026-07-05 16:37:09 +00:00
chore(control + display): improve api urls, paths and file_names
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
type TreeElement
|
||||
} from './types';
|
||||
import { dev } from '$app/environment';
|
||||
import { get_sanitized_file_url } from './utils';
|
||||
|
||||
export async function get_screenshot(ip: string): Promise<Blob | null> {
|
||||
const options = { method: 'PATCH' };
|
||||
@@ -18,7 +19,7 @@ export async function get_screenshot(ip: string): Promise<Blob | null> {
|
||||
|
||||
export async function open_file(ip: string, path_to_file: string): Promise<void> {
|
||||
const options = { method: 'PATCH', headers: { 'content-type': 'application/octet-stream' } };
|
||||
await request_display(ip, `/file${path_to_file}`, options);
|
||||
await request_display(ip, get_sanitized_file_url(path_to_file), options);
|
||||
}
|
||||
|
||||
export async function send_keyboard_input(ip: string, key: string): Promise<void> {
|
||||
@@ -165,7 +166,7 @@ export async function show_blackscreen(ip: string): Promise<void> {
|
||||
export async function get_thumbnail_blob(ip: string, path_to_file: string): Promise<Blob | null> {
|
||||
const raw_response = await request_display(
|
||||
ip,
|
||||
`/file/preview${path_to_file}`,
|
||||
get_sanitized_file_url(path_to_file, true),
|
||||
{ method: 'GET' },
|
||||
[415]
|
||||
);
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { dev } from '$app/environment';
|
||||
import { db } from './files_display.db';
|
||||
import { get_display_by_id } from './stores/displays';
|
||||
import { remove_all_files_without_display, remove_file_from_display } from './stores/files';
|
||||
import {
|
||||
get_current_folder_elements,
|
||||
remove_all_files_without_display,
|
||||
remove_file_from_display
|
||||
} from './stores/files';
|
||||
import { notifications } from './stores/notification';
|
||||
import { generate_thumbnail } from './stores/thumbnails';
|
||||
import {
|
||||
@@ -10,7 +14,7 @@ import {
|
||||
type FileTransferTask,
|
||||
type Inode
|
||||
} from './types';
|
||||
import { get_uuid, make_valid_name } from './utils';
|
||||
import { get_sanitized_file_url, get_uuid, make_valid_name } from './utils';
|
||||
|
||||
let is_processing: boolean = false;
|
||||
const tasks: FileTransferTask[] = [];
|
||||
@@ -22,8 +26,14 @@ export async function add_upload(
|
||||
) {
|
||||
if (file_list.length === 0) return;
|
||||
|
||||
const used_file_names: string[] = await (
|
||||
await get_current_folder_elements(current_file_path, selected_display_ids)
|
||||
).map((e) => e.name);
|
||||
|
||||
for (const file of file_list) {
|
||||
const file_name = make_valid_name(file.name);
|
||||
const file_name = generate_valid_file_name(file.name, used_file_names);
|
||||
used_file_names.push(file_name);
|
||||
|
||||
const db_file: Inode = {
|
||||
path: current_file_path,
|
||||
name: file_name,
|
||||
@@ -67,6 +77,28 @@ export async function add_upload(
|
||||
await start_task_processing();
|
||||
}
|
||||
|
||||
function generate_valid_file_name(original_file_name: string, used_file_names: string[]): string {
|
||||
const regex = /\s\((\d{1,3})\)$/;
|
||||
|
||||
let name: string = make_valid_name(original_file_name);
|
||||
while (used_file_names.includes(name)) {
|
||||
const last_dot = name.lastIndexOf('.');
|
||||
let name_without_extension = last_dot > 0 ? name.slice(0, last_dot) : name;
|
||||
const extension = last_dot > 0 ? name.slice(last_dot) : '';
|
||||
if (!regex.test(name_without_extension)) {
|
||||
name_without_extension += ' (1)';
|
||||
} else {
|
||||
const match = name_without_extension.match(regex);
|
||||
const current_number: number = match ? Number(match[1]) : 0;
|
||||
console.log("current", current_number)
|
||||
name_without_extension = name_without_extension.replace(regex, ` (${current_number + 1})`);
|
||||
}
|
||||
name = name_without_extension + extension;
|
||||
console.log(name)
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
async function start_task_processing() {
|
||||
if (!is_processing) {
|
||||
is_processing = tasks.length !== 0;
|
||||
@@ -94,9 +126,6 @@ async function start_task_loop() {
|
||||
}
|
||||
}
|
||||
|
||||
function file_url(ip: string, path: string, file_name: string) {
|
||||
return `http://${ip}:1323/api/file${path}${encodeURIComponent(file_name)}`;
|
||||
}
|
||||
|
||||
async function upload(task: FileTransferTask): Promise<void> {
|
||||
if (task.type !== 'upload' || !task.file) return;
|
||||
@@ -108,7 +137,7 @@ async function upload(task: FileTransferTask): Promise<void> {
|
||||
|
||||
return new Promise<void>((resolve) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', file_url(task.display_ip, task.path, task.file_name), true);
|
||||
xhr.open('POST', `http://${task.display_ip}:1323/api${get_sanitized_file_url(task.path + task.file_name)}`, true);
|
||||
xhr.setRequestHeader('content-type', 'application/octet-stream');
|
||||
|
||||
xhr.upload.onprogress = (e) => {
|
||||
@@ -152,7 +181,7 @@ async function upload(task: FileTransferTask): Promise<void> {
|
||||
if (!!inode_element && inode_element.thumbnail === null) {
|
||||
await generate_thumbnail(task.display_ip, task.path, inode_element);
|
||||
}
|
||||
}, 0);
|
||||
}, 10);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ const supported_file_types: Record<string, SupportedFileType> = supported_file_t
|
||||
>;
|
||||
|
||||
const invalid_first_regex = /^[^a-zA-ZäöüßÄÖÜ0-9_]/u;
|
||||
const invalid_rest_regex = /[^a-zA-ZäöüßÄÖÜ0-9 _\-()$${}.,+$€!?%&=/]/gu;
|
||||
const invalid_rest_regex = /[^a-zA-ZäöüßÄÖÜ0-9 _\-()$${}.,+$€!=/]/gu;
|
||||
|
||||
export function is_valid_name(input: string): boolean {
|
||||
return !invalid_rest_regex.test(input) && first_letter_is_valid(input);
|
||||
@@ -19,10 +19,10 @@ export function first_letter_is_valid(input: string): boolean {
|
||||
}
|
||||
|
||||
export function make_valid_name(input: string): string {
|
||||
const s = input.normalize("NFC");
|
||||
const s = input.normalize('NFC');
|
||||
if (s.length === 0) return 'Datei';
|
||||
let out = s.replace(invalid_rest_regex, "_");
|
||||
out = out.replace(invalid_first_regex, "_");
|
||||
let out = s.replace(invalid_rest_regex, '_');
|
||||
out = out.replace(invalid_first_regex, '_');
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -44,7 +44,9 @@ export function get_file_type(file: Inode): SupportedFileType | null {
|
||||
}
|
||||
|
||||
export function get_accepted_file_type_string(): string {
|
||||
return Object.values(supported_file_types).map((e) => e.mime_type).join(',');
|
||||
return Object.values(supported_file_types)
|
||||
.map((e) => e.mime_type)
|
||||
.join(',');
|
||||
}
|
||||
|
||||
export function get_uuid(): string {
|
||||
@@ -102,3 +104,12 @@ export function display_status_to_info(status: DisplayStatus): string {
|
||||
return '???';
|
||||
}
|
||||
}
|
||||
|
||||
export function get_sanitized_file_url(file_path: string, is_preview = false) {
|
||||
const pathSegments = file_path
|
||||
.split('/')
|
||||
.filter(Boolean)
|
||||
.map((seg) => encodeURIComponent(seg));
|
||||
|
||||
return `/file/${is_preview ? 'preview/' : ''}${[...pathSegments].join('/')}`;
|
||||
}
|
||||
|
||||
+12
-3
@@ -10,6 +10,7 @@ import (
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -146,12 +147,20 @@ func qrRoute(c echo.Context) error {
|
||||
|
||||
func extractFilePathMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(ctx echo.Context) error {
|
||||
pathParam := ctx.Param("path")
|
||||
fullPath, exists, err := pkg.ResolveStorageFilePath(pathParam)
|
||||
raw := ctx.Param("path")
|
||||
|
||||
decoded, err := url.PathUnescape(raw)
|
||||
if err != nil {
|
||||
slog.Warn("Failed to validate file path", "path", pathParam, "error", err)
|
||||
slog.Warn("Invalid path encoding", "path", raw, "error", err)
|
||||
return ctx.JSON(http.StatusBadRequest, shared.ErrorResponse{Description: "Invalid file path"})
|
||||
}
|
||||
|
||||
fullPath, exists, err := pkg.ResolveStorageFilePath(decoded)
|
||||
if err != nil {
|
||||
slog.Warn("Failed to validate file path", "path", decoded, "error", err)
|
||||
return ctx.JSON(http.StatusBadRequest, shared.ErrorResponse{Description: "Invalid file path"})
|
||||
}
|
||||
|
||||
ctx.Set("fullPath", fullPath)
|
||||
ctx.Set("fileExists", exists)
|
||||
return next(ctx)
|
||||
|
||||
Reference in New Issue
Block a user