From 728078f1e51cc1a48603f5e74517af0fcf886936 Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 27 May 2026 12:34:58 +0200 Subject: [PATCH] fix(dates): preserve stored date precision when edit omits it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updateDocument unconditionally set metaDatePrecision/End/Raw from the DTO, so saving an unrelated edit (a multipart PUT where the form omits the precision controls) clobbered the stored precision with null — fabricating a precision the user never chose. Apply each field only when the DTO carries it, mirroring the existing metadataComplete/scriptType guards. Refs #666 Co-Authored-By: Claude Opus 4.7 --- .../document/DocumentService.java | 23 +++++++++++++--- .../document/DocumentServiceTest.java | 27 +++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/backend/src/main/java/org/raddatz/familienarchiv/document/DocumentService.java b/backend/src/main/java/org/raddatz/familienarchiv/document/DocumentService.java index 19961140..4106332a 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/document/DocumentService.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/document/DocumentService.java @@ -378,9 +378,7 @@ public class DocumentService { // 1. Einfache Felder Update doc.setTitle(dto.getTitle()); doc.setDocumentDate(dto.getDocumentDate()); - doc.setMetaDatePrecision(dto.getMetaDatePrecision()); - doc.setMetaDateEnd(dto.getMetaDateEnd()); - doc.setMetaDateRaw(dto.getMetaDateRaw()); + applyDatePrecision(doc, dto); doc.setLocation(dto.getLocation()); doc.setTranscription(dto.getTranscription()); doc.setSummary(dto.getSummary()); @@ -449,6 +447,25 @@ public class DocumentService { return saved; } + /** + * Applies the three date-precision fields only when the DTO carries them. + * A null field means "not submitted" — overwriting the stored value with null + * would fabricate a precision the user never chose, the exact dishonesty #666 + * exists to prevent. A row with a genuinely-unknown precision must keep it when + * an unrelated edit (e.g. a location typo) is saved. + */ + private void applyDatePrecision(Document doc, DocumentUpdateDTO dto) { + if (dto.getMetaDatePrecision() != null) { + doc.setMetaDatePrecision(dto.getMetaDatePrecision()); + } + if (dto.getMetaDateEnd() != null) { + doc.setMetaDateEnd(dto.getMetaDateEnd()); + } + if (dto.getMetaDateRaw() != null) { + doc.setMetaDateRaw(dto.getMetaDateRaw()); + } + } + @Transactional public Document updateDocumentTags(UUID docId, List tagNames) { Document doc = documentRepository.findById(docId) diff --git a/backend/src/test/java/org/raddatz/familienarchiv/document/DocumentServiceTest.java b/backend/src/test/java/org/raddatz/familienarchiv/document/DocumentServiceTest.java index d603608e..658d4c31 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/document/DocumentServiceTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/document/DocumentServiceTest.java @@ -164,6 +164,33 @@ class DocumentServiceTest { assertThat(doc.getMetaDateRaw()).isEqualTo("10.–11. Januar 1917"); } + @Test + void updateDocument_preservesStoredPrecision_whenDtoOmitsIt() throws Exception { + // Editing a doc (e.g. fixing a location typo) without touching the precision + // controls must NOT fabricate a precision. The form omits the three precision + // fields → they arrive null on the DTO → the stored values must be preserved. + UUID id = UUID.randomUUID(); + Document doc = Document.builder() + .id(id) + .metaDatePrecision(DatePrecision.MONTH) + .metaDateEnd(LocalDate.of(1916, 6, 30)) + .metaDateRaw("Juni 1916") + .receivers(new HashSet<>()) + .tags(new HashSet<>()) + .build(); + when(documentRepository.findById(id)).thenReturn(Optional.of(doc)); + when(documentRepository.save(any())).thenReturn(doc); + + DocumentUpdateDTO dto = new DocumentUpdateDTO(); + dto.setLocation("Berlin"); // unrelated edit; precision fields left null + + documentService.updateDocument(id, dto, null, null); + + assertThat(doc.getMetaDatePrecision()).isEqualTo(DatePrecision.MONTH); + assertThat(doc.getMetaDateEnd()).isEqualTo(LocalDate.of(1916, 6, 30)); + assertThat(doc.getMetaDateRaw()).isEqualTo("Juni 1916"); + } + // ─── deleteTagCascading ─────────────────────────────────────────────────── @Test