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 a7867c92..20717feb 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/controller/DocumentController.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/controller/DocumentController.java @@ -3,6 +3,7 @@ package org.raddatz.familienarchiv.controller; import java.io.IOException; import java.time.LocalDate; import java.util.ArrayList; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Optional; @@ -272,7 +273,7 @@ public class DocumentController { // Dedupe duplicate document IDs while preserving submission order. A // double-click on "Alle X editieren" would otherwise hit each document // twice and inflate the `updated` count returned to the user. - java.util.LinkedHashSet uniqueIds = new java.util.LinkedHashSet<>(dto.getDocumentIds()); + LinkedHashSet uniqueIds = new LinkedHashSet<>(dto.getDocumentIds()); for (UUID id : uniqueIds) { try { @@ -324,7 +325,7 @@ public class DocumentController { @PostMapping(value = "/batch-metadata", consumes = MediaType.APPLICATION_JSON_VALUE) @RequirePermission(Permission.READ_ALL) - public List batchMetadata(@RequestBody BatchMetadataRequest request, Authentication authentication) { + public List batchMetadata(@RequestBody @Valid BatchMetadataRequest request, Authentication authentication) { if (request == null || request.ids() == null || request.ids().isEmpty()) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "ids is required"); } diff --git a/backend/src/test/java/org/raddatz/familienarchiv/controller/DocumentControllerTest.java b/backend/src/test/java/org/raddatz/familienarchiv/controller/DocumentControllerTest.java index 5d2ea90b..cbf2ece6 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/controller/DocumentControllerTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/controller/DocumentControllerTest.java @@ -996,6 +996,24 @@ class DocumentControllerTest { .andExpect(jsonPath("$.code").value("BULK_EDIT_TOO_MANY_IDS")); } + @Test + @WithMockUser(authorities = "WRITE_ALL") + void patchBulk_returns400_whenArchiveBoxExceeds255Chars() throws Exception { + // Tobias C2 — DocumentBulkEditDTO.archiveBox carries @Size(max=255). + // Without @Valid on @RequestBody this would silently land an + // arbitrarily long string; the test pins both the annotation and + // the controller-level @Valid wiring. + when(userService.findByEmail(any())).thenReturn(AppUser.builder().id(UUID.randomUUID()).build()); + UUID id = UUID.randomUUID(); + String tooLong = "x".repeat(256); + + String body = "{\"documentIds\":[\"" + id + "\"],\"archiveBox\":\"" + tooLong + "\"}"; + mockMvc.perform(patch("/api/documents/bulk") + .contentType(MediaType.APPLICATION_JSON) + .content(body)) + .andExpect(status().isBadRequest()); + } + @Test @WithMockUser(authorities = "WRITE_ALL") void patchBulk_acceptsExactly500Ids_atTheCap() throws Exception { diff --git a/frontend/src/lib/components/document/BulkDocumentEditLayout.svelte b/frontend/src/lib/components/document/BulkDocumentEditLayout.svelte index 3e062058..12ef0aa3 100644 --- a/frontend/src/lib/components/document/BulkDocumentEditLayout.svelte +++ b/frontend/src/lib/components/document/BulkDocumentEditLayout.svelte @@ -1,7 +1,7 @@