diff --git a/backend/download.php b/backend/download.php new file mode 100644 index 0000000..9872f7c --- /dev/null +++ b/backend/download.php @@ -0,0 +1,54 @@ +prepare("SELECT original_name, mime_type FROM file_attachments WHERE stored_name = ?"); +$stmt->execute([basename($file)]); +$att = $stmt->fetch(PDO::FETCH_ASSOC); + +$originalName = $att ? $att['original_name'] : basename($file); +$mimeType = $att && $att['mime_type'] ? $att['mime_type'] : mime_content_type($path); + +$ext = strtolower(pathinfo($originalName, PATHINFO_EXTENSION)); +$viewable = in_array($ext, ['txt', 'md', 'pdf', 'csv']); + +if ($mode === 'view' && $viewable) { + header('Content-Disposition: inline; filename="' . $originalName . '"'); + header('Content-Type: ' . $mimeType); + header('Content-Length: ' . filesize($path)); + header('X-File-Name: ' . $originalName); + header('X-File-Viewable: 1'); + readfile($path); + exit; +} + +header('Content-Description: File Transfer'); +header('Content-Type: application/octet-stream'); +header('Content-Disposition: attachment; filename="' . $originalName . '"'); +header('Content-Length: ' . filesize($path)); +header('Cache-Control: no-cache'); +readfile($path); \ No newline at end of file diff --git a/docker/nginx.conf b/docker/nginx.conf index 31899cd..2da9b7e 100644 --- a/docker/nginx.conf +++ b/docker/nginx.conf @@ -16,7 +16,15 @@ server { location /uploads/ { alias /var/www/uploads/; - add_header Content-Disposition 'inline'; + internal; + } + + location /download/ { + fastcgi_pass php:9000; + fastcgi_param SCRIPT_FILENAME /var/www/backend/download.php; + fastcgi_param REQUEST_URI $request_uri; + fastcgi_param QUERY_STRING $query_string; + include fastcgi_params; } location / { diff --git a/frontend/assets/css/style.css b/frontend/assets/css/style.css index f11a204..64cb0aa 100644 --- a/frontend/assets/css/style.css +++ b/frontend/assets/css/style.css @@ -282,4 +282,15 @@ kbd { .attachment-item a:hover { color: #60a5fa; text-decoration: underline !important; +} + +/* File Viewer */ +#fileViewerModal .modal-content { + border-color: var(--neptune-border); +} + +#fileViewerBody pre { + margin: 0; + white-space: pre-wrap; + word-break: break-word; } \ No newline at end of file diff --git a/frontend/assets/js/app.js b/frontend/assets/js/app.js index b317a91..8487899 100644 --- a/frontend/assets/js/app.js +++ b/frontend/assets/js/app.js @@ -588,13 +588,20 @@ async function renderAttachments(eventId, container) { container.innerHTML = attachments.map(a => { const icon = getFileIcon(a.mime_type, a.original_name); const size = formatFileSize(a.file_size); + const ext = a.original_name.split('.').pop().toLowerCase(); + const viewable = ['txt', 'md', 'csv'].includes(ext); + const href = viewable ? '#' : '/download/?file=' + encodeURIComponent(a.stored_name) + '&mode=download'; + const onclick = viewable ? ` onclick="event.preventDefault();openFileViewer('${esc(a.stored_name)}','${esc(a.original_name)}')"` : ''; return `
+ +