From 457243b31165633fa91158af0c7073f3dcbe0293 Mon Sep 17 00:00:00 2001 From: mattknatt Date: Tue, 31 Mar 2026 15:41:42 +0200 Subject: [PATCH 1/4] Add support for case notes functionality --- .../application/service/CaseMapper.java | 16 ++++++++- .../application/service/CaseNoteMapper.java | 29 +++++++++++++++ .../application/service/CaseService.java | 20 ++++++++++- .../persistence/CaseEntity.java | 12 ++++++- .../persistence/CaseNoteEntity.java | 35 +++++++++++++++++++ .../persistence/CaseNoteRepository.java | 10 ++++++ .../presentation/dto/CaseDTO.java | 10 +++--- .../presentation/dto/CaseNoteDTO.java | 33 +++++++++++++++++ .../presentation/web/UiController.java | 9 +++++ .../resources/templates/cases/detail.html | 24 +++++++++++++ 10 files changed, 191 insertions(+), 7 deletions(-) create mode 100644 src/main/java/org/example/projektarendehantering/application/service/CaseNoteMapper.java create mode 100644 src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseNoteEntity.java create mode 100644 src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseNoteRepository.java create mode 100644 src/main/java/org/example/projektarendehantering/presentation/dto/CaseNoteDTO.java diff --git a/src/main/java/org/example/projektarendehantering/application/service/CaseMapper.java b/src/main/java/org/example/projektarendehantering/application/service/CaseMapper.java index 80128e9..2a32d4a 100644 --- a/src/main/java/org/example/projektarendehantering/application/service/CaseMapper.java +++ b/src/main/java/org/example/projektarendehantering/application/service/CaseMapper.java @@ -4,12 +4,20 @@ import org.example.projektarendehantering.presentation.dto.CaseDTO; import org.springframework.stereotype.Component; +import java.util.stream.Collectors; + @Component public class CaseMapper { + private final CaseNoteMapper caseNoteMapper; + + public CaseMapper(CaseNoteMapper caseNoteMapper) { + this.caseNoteMapper = caseNoteMapper; + } + public CaseDTO toDTO(CaseEntity entity) { if (entity == null) return null; - return new CaseDTO( + CaseDTO dto = new CaseDTO( entity.getId(), entity.getStatus(), entity.getTitle(), @@ -17,6 +25,12 @@ public CaseDTO toDTO(CaseEntity entity) { entity.getCreatedAt(), entity.getPatient() != null ? entity.getPatient().getId() : null ); + if (entity.getNotes() != null) { + dto.setNotes(entity.getNotes().stream() + .map(caseNoteMapper::toDTO) + .collect(Collectors.toList())); + } + return dto; } public CaseEntity toEntity(CaseDTO dto) { diff --git a/src/main/java/org/example/projektarendehantering/application/service/CaseNoteMapper.java b/src/main/java/org/example/projektarendehantering/application/service/CaseNoteMapper.java new file mode 100644 index 0000000..a6a8f41 --- /dev/null +++ b/src/main/java/org/example/projektarendehantering/application/service/CaseNoteMapper.java @@ -0,0 +1,29 @@ +package org.example.projektarendehantering.application.service; + +import org.example.projektarendehantering.infrastructure.persistence.CaseNoteEntity; +import org.example.projektarendehantering.presentation.dto.CaseNoteDTO; +import org.springframework.stereotype.Component; + +@Component +public class CaseNoteMapper { + + public CaseNoteDTO toDTO(CaseNoteEntity entity) { + if (entity == null) return null; + return new CaseNoteDTO( + entity.getId(), + entity.getContent(), + entity.getAuthor(), + entity.getCreatedAt() + ); + } + + public CaseNoteEntity toEntity(CaseNoteDTO dto) { + if (dto == null) return null; + CaseNoteEntity entity = new CaseNoteEntity(); + entity.setId(dto.getId()); + entity.setContent(dto.getContent()); + entity.setAuthor(dto.getAuthor()); + entity.setCreatedAt(dto.getCreatedAt()); + return entity; + } +} diff --git a/src/main/java/org/example/projektarendehantering/application/service/CaseService.java b/src/main/java/org/example/projektarendehantering/application/service/CaseService.java index 503e045..fa30528 100644 --- a/src/main/java/org/example/projektarendehantering/application/service/CaseService.java +++ b/src/main/java/org/example/projektarendehantering/application/service/CaseService.java @@ -1,6 +1,8 @@ package org.example.projektarendehantering.application.service; import org.example.projektarendehantering.infrastructure.persistence.CaseEntity; +import org.example.projektarendehantering.infrastructure.persistence.CaseNoteEntity; +import org.example.projektarendehantering.infrastructure.persistence.CaseNoteRepository; import org.example.projektarendehantering.infrastructure.persistence.CaseRepository; import org.example.projektarendehantering.infrastructure.persistence.PatientEntity; import org.example.projektarendehantering.infrastructure.persistence.PatientRepository; @@ -22,11 +24,27 @@ public class CaseService { private final CaseRepository caseRepository; private final CaseMapper caseMapper; private final PatientRepository patientRepository; + private final CaseNoteRepository caseNoteRepository; - public CaseService(CaseRepository caseRepository, CaseMapper caseMapper, PatientRepository patientRepository) { + public CaseService(CaseRepository caseRepository, CaseMapper caseMapper, PatientRepository patientRepository, CaseNoteRepository caseNoteRepository) { this.caseRepository = caseRepository; this.caseMapper = caseMapper; this.patientRepository = patientRepository; + this.caseNoteRepository = caseNoteRepository; + } + + @Transactional + public void addNote(UUID caseId, String content, String author) { + CaseEntity caseEntity = caseRepository.findById(caseId) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Case not found")); + + CaseNoteEntity note = new CaseNoteEntity(); + note.setCaseEntity(caseEntity); + note.setContent(content); + note.setAuthor(author); + note.setCreatedAt(Instant.now()); + + caseNoteRepository.save(note); } @Transactional diff --git a/src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseEntity.java b/src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseEntity.java index 5a787fe..4a73cc0 100644 --- a/src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseEntity.java +++ b/src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseEntity.java @@ -2,6 +2,8 @@ import jakarta.persistence.*; import java.time.Instant; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; @Entity @@ -21,9 +23,13 @@ public class CaseEntity { @JoinColumn(name = "patient_id", nullable = false) private PatientEntity patient; + @OneToMany(mappedBy = "caseEntity", cascade = CascadeType.ALL, orphanRemoval = true) + @OrderBy("createdAt DESC") + private List notes = new ArrayList<>(); + public CaseEntity() {} - public CaseEntity(UUID id, String status, UUID ownerId, String title, String description, Instant createdAt, PatientEntity patient) { + public CaseEntity(UUID id, String status, UUID ownerId, String title, String description, Instant createdAt, PatientEntity patient, List notes) { this.id = id; this.status = status; this.ownerId = ownerId; @@ -31,6 +37,7 @@ public CaseEntity(UUID id, String status, UUID ownerId, String title, String des this.description = description; this.createdAt = createdAt; this.patient = patient; + this.notes = notes; } public UUID getId() { return id; } @@ -53,4 +60,7 @@ public CaseEntity(UUID id, String status, UUID ownerId, String title, String des public PatientEntity getPatient() { return patient; } public void setPatient(PatientEntity patient) { this.patient = patient; } + + public List getNotes() { return notes; } + } diff --git a/src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseNoteEntity.java b/src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseNoteEntity.java new file mode 100644 index 0000000..1eac7a2 --- /dev/null +++ b/src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseNoteEntity.java @@ -0,0 +1,35 @@ +package org.example.projektarendehantering.infrastructure.persistence; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.Instant; +import java.util.UUID; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "case_notes") +public class CaseNoteEntity { + + @Id + @GeneratedValue(strategy = GenerationType.UUID) + private UUID id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "case_id") + private CaseEntity caseEntity; + + private String content; + + private String author; + + private Instant createdAt; + + +} diff --git a/src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseNoteRepository.java b/src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseNoteRepository.java new file mode 100644 index 0000000..b443d74 --- /dev/null +++ b/src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseNoteRepository.java @@ -0,0 +1,10 @@ +package org.example.projektarendehantering.infrastructure.persistence; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.UUID; + +@Repository +public interface CaseNoteRepository extends JpaRepository { +} diff --git a/src/main/java/org/example/projektarendehantering/presentation/dto/CaseDTO.java b/src/main/java/org/example/projektarendehantering/presentation/dto/CaseDTO.java index e0c306e..9ecfed4 100644 --- a/src/main/java/org/example/projektarendehantering/presentation/dto/CaseDTO.java +++ b/src/main/java/org/example/projektarendehantering/presentation/dto/CaseDTO.java @@ -1,8 +1,8 @@ package org.example.projektarendehantering.presentation.dto; -import jakarta.validation.constraints.NotNull; - import java.time.Instant; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; public class CaseDTO { @@ -12,9 +12,8 @@ public class CaseDTO { private String title; private String description; private Instant createdAt; - - @NotNull private UUID patientId; + private List notes = new ArrayList<>(); public CaseDTO() {} @@ -44,4 +43,7 @@ public CaseDTO(UUID id, String status, String title, String description, Instant public UUID getPatientId() { return patientId; } public void setPatientId(UUID patientId) { this.patientId = patientId; } + + public List getNotes() { return notes; } + public void setNotes(List notes) { this.notes = notes; } } diff --git a/src/main/java/org/example/projektarendehantering/presentation/dto/CaseNoteDTO.java b/src/main/java/org/example/projektarendehantering/presentation/dto/CaseNoteDTO.java new file mode 100644 index 0000000..2f5660c --- /dev/null +++ b/src/main/java/org/example/projektarendehantering/presentation/dto/CaseNoteDTO.java @@ -0,0 +1,33 @@ +package org.example.projektarendehantering.presentation.dto; + +import java.time.Instant; +import java.util.UUID; + +public class CaseNoteDTO { + + private UUID id; + private String content; + private String author; + private Instant createdAt; + + public CaseNoteDTO() {} + + public CaseNoteDTO(UUID id, String content, String author, Instant createdAt) { + this.id = id; + this.content = content; + this.author = author; + this.createdAt = createdAt; + } + + public UUID getId() { return id; } + public void setId(UUID id) { this.id = id; } + + public String getContent() { return content; } + public void setContent(String content) { this.content = content; } + + public String getAuthor() { return author; } + public void setAuthor(String author) { this.author = author; } + + public Instant getCreatedAt() { return createdAt; } + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } +} diff --git a/src/main/java/org/example/projektarendehantering/presentation/web/UiController.java b/src/main/java/org/example/projektarendehantering/presentation/web/UiController.java index 6ef3f47..a119f7f 100644 --- a/src/main/java/org/example/projektarendehantering/presentation/web/UiController.java +++ b/src/main/java/org/example/projektarendehantering/presentation/web/UiController.java @@ -10,8 +10,10 @@ import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; import jakarta.validation.Valid; +import java.security.Principal; import java.util.UUID; @Controller @@ -23,6 +25,13 @@ public UiController(CaseService caseService) { this.caseService = caseService; } + @PostMapping("/ui/cases/{caseId}/notes") + public String addNote(@PathVariable UUID caseId, @RequestParam("content") String content, Principal principal) { + String author = principal != null ? principal.getName() : "Anonymous"; + caseService.addNote(caseId, content, author); + return "redirect:/ui/cases/" + caseId; + } + @GetMapping("/") public String index() { return "index"; diff --git a/src/main/resources/templates/cases/detail.html b/src/main/resources/templates/cases/detail.html index 1179be7..7968275 100644 --- a/src/main/resources/templates/cases/detail.html +++ b/src/main/resources/templates/cases/detail.html @@ -25,6 +25,30 @@

Case

Date
+ +
+

Notes

+
+

Note content

+
+ Author - + Date +
+
+

No notes yet.

+ +
+ +

Add Note

+
+ +
+ +
+
+

Error

Case not found.

From c94036e37c1a05ff1aa548411cc78d8aa554b6f9 Mon Sep 17 00:00:00 2001 From: mattknatt Date: Tue, 31 Mar 2026 15:46:22 +0200 Subject: [PATCH 2/4] Configure Lombok as an annotation processor via Maven compiler plugin --- pom.xml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e24a531..9b52e9c 100644 --- a/pom.xml +++ b/pom.xml @@ -84,7 +84,6 @@ org.projectlombok lombok - annotationProcessor org.springframework.security @@ -108,6 +107,18 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.projectlombok + lombok + + + + org.springframework.boot spring-boot-maven-plugin From 738b7b7b41a3e069748ec49758c9a45401d3c94e Mon Sep 17 00:00:00 2001 From: mattknatt Date: Tue, 31 Mar 2026 16:08:47 +0200 Subject: [PATCH 3/4] Ensure `notes` field is initialized with an empty list if null --- .../infrastructure/persistence/CaseEntity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseEntity.java b/src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseEntity.java index 2850592..3852dcb 100644 --- a/src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseEntity.java +++ b/src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseEntity.java @@ -37,7 +37,7 @@ public CaseEntity(UUID id, String status, UUID ownerId, String title, String des this.description = description; this.createdAt = createdAt; this.patient = patient; - this.notes = notes; + this.notes = notes != null ? notes : new ArrayList<>(); } public UUID getId() { return id; } From b3ff9c15d487008f3422715ee2b466a199c32916 Mon Sep 17 00:00:00 2001 From: mattknatt Date: Tue, 31 Mar 2026 16:26:29 +0200 Subject: [PATCH 4/4] fix fix --- .../application/service/CaseService.java | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/example/projektarendehantering/application/service/CaseService.java b/src/main/java/org/example/projektarendehantering/application/service/CaseService.java index 81cf9e8..6b5c11c 100644 --- a/src/main/java/org/example/projektarendehantering/application/service/CaseService.java +++ b/src/main/java/org/example/projektarendehantering/application/service/CaseService.java @@ -34,11 +34,12 @@ public class CaseService { private final CaseNoteRepository caseNoteRepository; private final EmployeeRepository employeeRepository; - public CaseService(CaseRepository caseRepository, CaseMapper caseMapper, PatientRepository patientRepository, CaseNoteRepository caseNoteRepository) { + public CaseService(CaseRepository caseRepository, CaseMapper caseMapper, PatientRepository patientRepository, CaseNoteRepository caseNoteRepository, EmployeeRepository employeeRepository) { this.caseRepository = caseRepository; this.caseMapper = caseMapper; this.patientRepository = patientRepository; this.caseNoteRepository = caseNoteRepository; + this.employeeRepository = employeeRepository; } @Transactional @@ -53,18 +54,6 @@ public void addNote(UUID caseId, String content, String author) { note.setCreatedAt(Instant.now()); caseNoteRepository.save(note); - - - public CaseService( - CaseRepository caseRepository, - CaseMapper caseMapper, - PatientRepository patientRepository, - EmployeeRepository employeeRepository - ) { - this.caseRepository = caseRepository; - this.caseMapper = caseMapper; - this.patientRepository = patientRepository; - this.employeeRepository = employeeRepository; } @Transactional