diff --git a/backend/src/main/java/org/raddatz/familienarchiv/controller/CommentController.java b/backend/src/main/java/org/raddatz/familienarchiv/controller/CommentController.java new file mode 100644 index 00000000..1373f71f --- /dev/null +++ b/backend/src/main/java/org/raddatz/familienarchiv/controller/CommentController.java @@ -0,0 +1,122 @@ +package org.raddatz.familienarchiv.controller; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.raddatz.familienarchiv.dto.CreateCommentDTO; +import org.raddatz.familienarchiv.model.AppUser; +import org.raddatz.familienarchiv.model.DocumentComment; +import org.raddatz.familienarchiv.security.Permission; +import org.raddatz.familienarchiv.security.RequirePermission; +import org.raddatz.familienarchiv.service.CommentService; +import org.raddatz.familienarchiv.service.UserService; +import org.springframework.http.HttpStatus; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.UUID; + +@RestController +@RequiredArgsConstructor +@Slf4j +public class CommentController { + + private final CommentService commentService; + private final UserService userService; + + // ─── General document comments ──────────────────────────────────────────── + + @GetMapping("/api/documents/{documentId}/comments") + public List getDocumentComments(@PathVariable UUID documentId) { + return commentService.getCommentsForDocument(documentId); + } + + @PostMapping("/api/documents/{documentId}/comments") + @ResponseStatus(HttpStatus.CREATED) + @RequirePermission(Permission.ANNOTATE_ALL) + public DocumentComment postDocumentComment( + @PathVariable UUID documentId, + @RequestBody CreateCommentDTO dto, + Authentication authentication) { + AppUser author = resolveUser(authentication); + return commentService.postComment(documentId, null, dto.getContent(), author); + } + + @PostMapping("/api/documents/{documentId}/comments/{commentId}/replies") + @ResponseStatus(HttpStatus.CREATED) + @RequirePermission(Permission.ANNOTATE_ALL) + public DocumentComment replyToDocumentComment( + @PathVariable UUID documentId, + @PathVariable UUID commentId, + @RequestBody CreateCommentDTO dto, + Authentication authentication) { + AppUser author = resolveUser(authentication); + return commentService.replyToComment(documentId, commentId, dto.getContent(), author); + } + + // ─── Annotation comments ────────────────────────────────────────────────── + + @GetMapping("/api/documents/{documentId}/annotations/{annotationId}/comments") + public List getAnnotationComments(@PathVariable UUID annotationId) { + return commentService.getCommentsForAnnotation(annotationId); + } + + @PostMapping("/api/documents/{documentId}/annotations/{annotationId}/comments") + @ResponseStatus(HttpStatus.CREATED) + @RequirePermission(Permission.ANNOTATE_ALL) + public DocumentComment postAnnotationComment( + @PathVariable UUID documentId, + @PathVariable UUID annotationId, + @RequestBody CreateCommentDTO dto, + Authentication authentication) { + AppUser author = resolveUser(authentication); + return commentService.postComment(documentId, annotationId, dto.getContent(), author); + } + + @PostMapping("/api/documents/{documentId}/annotations/{annotationId}/comments/{commentId}/replies") + @ResponseStatus(HttpStatus.CREATED) + @RequirePermission(Permission.ANNOTATE_ALL) + public DocumentComment replyToAnnotationComment( + @PathVariable UUID documentId, + @PathVariable UUID commentId, + @RequestBody CreateCommentDTO dto, + Authentication authentication) { + AppUser author = resolveUser(authentication); + return commentService.replyToComment(documentId, commentId, dto.getContent(), author); + } + + // ─── Edit and delete (shared) ───────────────────────────────────────────── + + @PatchMapping("/api/documents/{documentId}/comments/{commentId}") + @RequirePermission(Permission.ANNOTATE_ALL) + public DocumentComment editComment( + @PathVariable UUID documentId, + @PathVariable UUID commentId, + @RequestBody CreateCommentDTO dto, + Authentication authentication) { + AppUser currentUser = resolveUser(authentication); + return commentService.editComment(documentId, commentId, dto.getContent(), currentUser); + } + + @DeleteMapping("/api/documents/{documentId}/comments/{commentId}") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void deleteComment( + @PathVariable UUID documentId, + @PathVariable UUID commentId, + Authentication authentication) { + AppUser currentUser = resolveUser(authentication); + commentService.deleteComment(documentId, commentId, currentUser); + } + + // ─── private helpers ────────────────────────────────────────────────────── + + private AppUser resolveUser(Authentication authentication) { + if (authentication == null || !authentication.isAuthenticated()) return null; + try { + return userService.findByUsername(authentication.getName()); + } catch (Exception e) { + log.warn("Could not resolve user for comment: {}", e.getMessage()); + return null; + } + } +} diff --git a/backend/src/main/java/org/raddatz/familienarchiv/dto/CreateCommentDTO.java b/backend/src/main/java/org/raddatz/familienarchiv/dto/CreateCommentDTO.java new file mode 100644 index 00000000..9caa4b1a --- /dev/null +++ b/backend/src/main/java/org/raddatz/familienarchiv/dto/CreateCommentDTO.java @@ -0,0 +1,8 @@ +package org.raddatz.familienarchiv.dto; + +import lombok.Data; + +@Data +public class CreateCommentDTO { + private String content; +}