feat: filemanager s NAS pro projekty

- NasFileManager.php - filesystem helper (browse, upload, download, delete, rename, mkdir)
- project-files.php API - CRUD operace nad soubory projektu
- ProjectFileManager.jsx - React komponenta v detailu projektu
- Automaticke vytvoreni slozky pri vytvoreni projektu (rucne i z objednavky)
- Prejmenovani slozky pri zmene nazvu projektu
- Checkbox "Smazat i soubory na disku" pri mazani projektu/objednavky
- Path traversal ochrana, MIME validace, blocklist nebezpecnych typu
- Bily spinner v primary tlacitkach, ConfirmModal message jako div
- Case-insensitive rename fix pro Windows filesystem

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 13:06:34 +01:00
parent 9e3c95e576
commit 45fd930f76
69 changed files with 2776 additions and 71 deletions

View File

@@ -121,6 +121,10 @@ function handleCreateProject(PDO $pdo): void
'customer_id' => $customerId,
], "Ručně vytvořen projekt '$projectNumber'");
// Vytvorit slozku na NAS
$fm = new NasFileManager();
$fm->createProjectFolder($projectNumber, $name);
successResponse([
'project_id' => $projectId,
'project_number' => $projectNumber,
@@ -134,6 +138,9 @@ function handleCreateProject(PDO $pdo): void
function handleDeleteProject(PDO $pdo, int $id): void
{
$input = getJsonInput();
$deleteFiles = (bool) ($input['delete_files'] ?? false);
$stmt = $pdo->prepare(
'SELECT id, project_number, name, order_id, status FROM projects WHERE id = ?'
);
@@ -161,12 +168,18 @@ function handleDeleteProject(PDO $pdo, int $id): void
$pdo->commit();
// Smazat slozku na NAS pokud pozadovano
if ($deleteFiles) {
$fm = new NasFileManager();
$fm->deleteProjectFolder($project['project_number']);
}
AuditLog::logUpdate(
'projects_project',
$id,
['status' => $project['status']],
['status' => 'deleted'],
"Smazán ruční projekt '{$project['project_number']}'"
"Smazán ruční projekt '{$project['project_number']}'" . ($deleteFiles ? ' (včetně souborů)' : '')
);
successResponse(null, 'Projekt byl smazán');
@@ -254,6 +267,10 @@ function handleGetDetail(PDO $pdo, int $id): void
errorResponse('Projekt nebyl nalezen', 404);
}
// Kontrola existence slozky na NAS
$fm = new NasFileManager();
$project['has_nas_folder'] = $fm->projectFolderExists($project['project_number']);
successResponse($project);
}
@@ -344,6 +361,12 @@ function handleUpdateProject(PDO $pdo, int $id): void
$pdo->commit();
// Prejmenovani slozky na NAS pokud se zmenil nazev
if ($name !== $project['name']) {
$fm = new NasFileManager();
$fm->renameProjectFolder($project['project_number'], $name);
}
AuditLog::logUpdate(
'projects_project',
$id,