From affee407ef7e757d57c8bb4b6796541444f1d252 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 28 Mar 2026 15:42:26 +0100 Subject: [PATCH] fix: allow WRITE_ALL users to create and delete annotations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @RequirePermission on POST and DELETE annotation endpoints previously only listed ANNOTATE_ALL. Users with WRITE_ALL (but not ANNOTATE_ALL) received 403. A user who can write documents should also be able to annotate them — both permissions now accepted on both methods. Also updates canAnnotate in +layout.server.ts to match, so the UI correctly reflects annotation capability for WRITE_ALL users. Tests: AnnotationControllerTest (+2 RED→GREEN). Co-Authored-By: Claude Sonnet 4.6 --- .../controller/AnnotationController.java | 4 ++-- .../controller/AnnotationControllerTest.java | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/backend/src/main/java/org/raddatz/familienarchiv/controller/AnnotationController.java b/backend/src/main/java/org/raddatz/familienarchiv/controller/AnnotationController.java index ce0e0f29..43b715d7 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/controller/AnnotationController.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/controller/AnnotationController.java @@ -35,7 +35,7 @@ public class AnnotationController { @PostMapping @ResponseStatus(HttpStatus.CREATED) - @RequirePermission(Permission.ANNOTATE_ALL) + @RequirePermission({Permission.ANNOTATE_ALL, Permission.WRITE_ALL}) public DocumentAnnotation createAnnotation( @PathVariable UUID documentId, @RequestBody CreateAnnotationDTO dto, @@ -47,7 +47,7 @@ public class AnnotationController { @DeleteMapping("/{annotationId}") @ResponseStatus(HttpStatus.NO_CONTENT) - @RequirePermission(Permission.ANNOTATE_ALL) + @RequirePermission({Permission.ANNOTATE_ALL, Permission.WRITE_ALL}) public void deleteAnnotation( @PathVariable UUID documentId, @PathVariable UUID annotationId, diff --git a/backend/src/test/java/org/raddatz/familienarchiv/controller/AnnotationControllerTest.java b/backend/src/test/java/org/raddatz/familienarchiv/controller/AnnotationControllerTest.java index 686ccf3e..f316bb31 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/controller/AnnotationControllerTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/controller/AnnotationControllerTest.java @@ -81,6 +81,29 @@ class AnnotationControllerTest { .andExpect(status().isForbidden()); } + @Test + @WithMockUser(authorities = "WRITE_ALL") + void createAnnotation_returns201_whenHasWriteAllPermission() throws Exception { + UUID docId = UUID.randomUUID(); + DocumentAnnotation saved = DocumentAnnotation.builder() + .id(UUID.randomUUID()).documentId(docId).pageNumber(1) + .x(0.1).y(0.1).width(0.2).height(0.2).color("#ff0000").build(); + when(documentService.getDocumentById(any())).thenReturn(Document.builder().build()); + when(annotationService.createAnnotation(any(), any(), any(), any())).thenReturn(saved); + + mockMvc.perform(post("/api/documents/" + docId + "/annotations") + .contentType(MediaType.APPLICATION_JSON) + .content(ANNOTATION_JSON)) + .andExpect(status().isCreated()); + } + + @Test + @WithMockUser(authorities = "WRITE_ALL") + void deleteAnnotation_returns204_whenHasWriteAllPermission() throws Exception { + mockMvc.perform(delete("/api/documents/" + UUID.randomUUID() + "/annotations/" + UUID.randomUUID())) + .andExpect(status().isNoContent()); + } + @Test @WithMockUser(authorities = "ANNOTATE_ALL") void createAnnotation_returns201_whenHasAnnotatePermission() throws Exception {