diff --git a/backend/src/main/java/org/raddatz/familienarchiv/controller/DocumentController.java b/backend/src/main/java/org/raddatz/familienarchiv/controller/DocumentController.java index 3da987d8..0c6f6c4d 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/controller/DocumentController.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/controller/DocumentController.java @@ -57,8 +57,13 @@ public class DocumentController { try { FileService.S3FileDownload download = fileService.downloadFile(doc.getFilePath()); + // Prefer the content type stored at upload time; fall back to whatever S3 reports + String contentType = (doc.getContentType() != null && !doc.getContentType().isBlank()) + ? doc.getContentType() + : download.contentType(); + return ResponseEntity.ok() - .contentType(MediaType.parseMediaType(download.contentType())) + .contentType(MediaType.parseMediaType(contentType)) .header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + doc.getOriginalFilename() + "\"") .body(download.resource()); } catch (FileService.StorageFileNotFoundException e) { diff --git a/backend/src/main/java/org/raddatz/familienarchiv/model/Document.java b/backend/src/main/java/org/raddatz/familienarchiv/model/Document.java index 833f0fdd..150c4d45 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/model/Document.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/model/Document.java @@ -32,6 +32,10 @@ public class Document { @Column(name = "file_path") private String filePath; + // MIME-Type, gespeichert beim Upload (z.B. "application/pdf", "image/jpeg") + @Column(name = "content_type") + private String contentType; + // Originaler Dateiname beim Upload (z.B. "Brief_Oma_1940.pdf") @Column(name = "original_filename", nullable = false) private String originalFilename; diff --git a/backend/src/main/java/org/raddatz/familienarchiv/service/DocumentService.java b/backend/src/main/java/org/raddatz/familienarchiv/service/DocumentService.java index 8ca4dcd4..d0dd0184 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/service/DocumentService.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/service/DocumentService.java @@ -13,11 +13,11 @@ import org.raddatz.familienarchiv.repository.PersonRepository; import org.raddatz.familienarchiv.repository.TagRepository; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.domain.Specification; -import org.springframework.http.HttpStatus; +import org.raddatz.familienarchiv.exception.DomainException; +import org.raddatz.familienarchiv.exception.ErrorCode; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; -import org.springframework.web.server.ResponseStatusException; import java.io.IOException; import java.time.LocalDate; @@ -69,6 +69,7 @@ public class DocumentService { // 3. Update Database document.setFilePath(s3Key); + document.setContentType(file.getContentType()); if (document.getStatus() == DocumentStatus.PLACEHOLDER) { document.setStatus(DocumentStatus.UPLOADED); } @@ -79,7 +80,7 @@ public class DocumentService { @Transactional public Document updateDocument(UUID id, DocumentUpdateDTO dto, MultipartFile newFile) throws IOException { Document doc = documentRepository.findById(id) - .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Dokument nicht gefunden")); + .orElseThrow(() -> DomainException.notFound(ErrorCode.DOCUMENT_NOT_FOUND, "Document not found: " + id)); // 1. Einfache Felder Update doc.setTitle(dto.getTitle()); @@ -125,6 +126,7 @@ public class DocumentService { doc.setFilePath(s3Key); doc.setOriginalFilename(newFile.getOriginalFilename()); + doc.setContentType(newFile.getContentType()); doc.setStatus(DocumentStatus.UPLOADED); } diff --git a/backend/src/main/java/org/raddatz/familienarchiv/service/FileService.java b/backend/src/main/java/org/raddatz/familienarchiv/service/FileService.java index f8999ba2..30f421b4 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/service/FileService.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/service/FileService.java @@ -66,21 +66,10 @@ public class FileService { ResponseInputStream s3Object = s3Client.getObject(getObjectRequest); - // 1. Versuche Content-Type von S3 zu bekommen + // Use whatever content type S3 has stored (set at upload time) String contentType = s3Object.response().contentType(); - - // 2. FIX: Wenn S3 "octet-stream" sagt (oder null ist), raten wir anhand der Endung - if (contentType == null || contentType.isEmpty() || contentType.equals("application/octet-stream")) { - String keyLower = s3Key.toLowerCase(); - if (keyLower.endsWith(".pdf")) { - contentType = "application/pdf"; - } else if (keyLower.endsWith(".jpg") || keyLower.endsWith(".jpeg")) { - contentType = "image/jpeg"; - } else if (keyLower.endsWith(".png")) { - contentType = "image/png"; - } else { - contentType = "application/octet-stream"; // Fallback - } + if (contentType == null || contentType.isBlank()) { + contentType = "application/octet-stream"; } return new S3FileDownload(new InputStreamResource(s3Object), contentType); diff --git a/backend/src/main/java/org/raddatz/familienarchiv/service/MassImportService.java b/backend/src/main/java/org/raddatz/familienarchiv/service/MassImportService.java index fb39d0bd..da04d58a 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/service/MassImportService.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/service/MassImportService.java @@ -140,12 +140,22 @@ public class MassImportService { return; } + // Detect MIME type from the local file + String contentType; + try { + contentType = Files.probeContentType(file.toPath()); + } catch (IOException e) { + contentType = null; + } + if (contentType == null) contentType = "application/octet-stream"; + // Upload zu S3 String s3Key = "documents/" + UUID.randomUUID() + "_" + file.getName(); try { s3Client.putObject(PutObjectRequest.builder() .bucket(bucketName) .key(s3Key) + .contentType(contentType) .build(), RequestBody.fromFile(file)); } catch (Exception e) { @@ -160,6 +170,7 @@ public class MassImportService { .build()); doc.setFilePath(s3Key); + doc.setContentType(contentType); doc.setStatus(DocumentStatus.UPLOADED); // Jetzt ist es da! doc.setDocumentDate(date); doc.setLocation(location); diff --git a/backend/src/main/resources/db/migration/V3__add_content_type_to_documents.sql b/backend/src/main/resources/db/migration/V3__add_content_type_to_documents.sql new file mode 100644 index 00000000..143edacb --- /dev/null +++ b/backend/src/main/resources/db/migration/V3__add_content_type_to_documents.sql @@ -0,0 +1 @@ +ALTER TABLE documents ADD COLUMN content_type character varying(255);