diff --git a/src/main/java/org/example/projektarendehantering/application/service/DocumentService.java b/src/main/java/org/example/projektarendehantering/application/service/DocumentService.java index f08e89f..c787e8b 100644 --- a/src/main/java/org/example/projektarendehantering/application/service/DocumentService.java +++ b/src/main/java/org/example/projektarendehantering/application/service/DocumentService.java @@ -164,6 +164,9 @@ public S3Resource downloadDocument(Actor actor, UUID documentId) { @Transactional public void deleteDocument(Actor actor, UUID documentId) { + if (actor.isPatient()) { + throw new NotAuthorizedException("Patients are not allowed to delete documents"); + } DocumentEntity entity = documentRepository.findById(documentId) .orElseThrow(() -> new BadRequestException("Document not found")); @@ -215,6 +218,8 @@ private void validateAccess(Actor actor, CaseEntity caseEntity) { if (actor.isManager()) return; if (actor.isDoctor() && actor.userId().equals(caseEntity.getOwnerId())) return; if (actor.isNurse() && actor.userId().equals(caseEntity.getHandlerId())) return; + if (actor.isPatient() && caseEntity.getPatient() != null + && actor.userId().equals(caseEntity.getPatient().getId())) return; throw new NotAuthorizedException("Not authorized to access documents for this case"); } } diff --git a/src/main/resources/templates/cases/detail.html b/src/main/resources/templates/cases/detail.html index a997963..cb21737 100644 --- a/src/main/resources/templates/cases/detail.html +++ b/src/main/resources/templates/cases/detail.html @@ -103,7 +103,8 @@

Documents

Date -
+
diff --git a/src/test/java/org/example/projektarendehantering/application/service/DocumentServiceTest.java b/src/test/java/org/example/projektarendehantering/application/service/DocumentServiceTest.java index b59b564..680806b 100644 --- a/src/test/java/org/example/projektarendehantering/application/service/DocumentServiceTest.java +++ b/src/test/java/org/example/projektarendehantering/application/service/DocumentServiceTest.java @@ -9,6 +9,7 @@ import org.example.projektarendehantering.infrastructure.persistence.CaseRepository; import org.example.projektarendehantering.infrastructure.persistence.DocumentEntity; import org.example.projektarendehantering.infrastructure.persistence.DocumentRepository; +import org.example.projektarendehantering.infrastructure.persistence.PatientEntity; import org.example.projektarendehantering.presentation.dto.DocumentDTO; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -22,6 +23,7 @@ import java.io.IOException; import java.io.InputStream; import java.time.Instant; +import java.util.List; import java.util.Optional; import java.util.UUID; @@ -50,23 +52,30 @@ class DocumentServiceTest { private Actor doctorActor; private Actor managerActor; + private Actor patientActor; private UUID caseId; private CaseEntity caseEntity; @BeforeEach void setUp() { ReflectionTestUtils.setField(documentService, "bucket", "test-bucket"); - + UUID doctorId = UUID.randomUUID(); UUID managerId = UUID.randomUUID(); + UUID patientId = UUID.randomUUID(); doctorActor = new Actor(doctorId, Role.DOCTOR, "Doctor", "doctor_user"); managerActor = new Actor(managerId, Role.MANAGER, "Manager", "manager_user"); + patientActor = new Actor(patientId, Role.PATIENT, "Patient", "patient_user"); + + PatientEntity patient = new PatientEntity(); + patient.setId(patientId); caseId = UUID.randomUUID(); caseEntity = new CaseEntity(); caseEntity.setId(caseId); caseEntity.setOwnerId(doctorId); + caseEntity.setPatient(patient); } @Test @@ -130,4 +139,52 @@ void deleteDocument_shouldAllowOwner() { verify(s3Template).deleteObject(eq("test-bucket"), eq("some-key")); verify(documentRepository).delete(docEntity); } + + @Test + void uploadDocument_shouldAllowPatientOnOwnCase() throws IOException { + MockMultipartFile file = new MockMultipartFile("file", "test.txt", "text/plain", "hello".getBytes()); + when(caseRepository.findById(caseId)).thenReturn(Optional.of(caseEntity)); + when(documentRepository.save(any(DocumentEntity.class))).thenAnswer(i -> { + DocumentEntity e = i.getArgument(0); + e.setId(UUID.randomUUID()); + return e; + }); + when(documentMapper.toDTO(any(DocumentEntity.class))).thenReturn( + new DocumentDTO(UUID.randomUUID(), "test.txt", "text/plain", 5, Instant.now(), patientActor.userId(), caseId)); + + DocumentDTO result = documentService.uploadDocument(patientActor, caseId, file); + + assertThat(result).isNotNull(); + verify(s3Template).upload(eq("test-bucket"), anyString(), any(InputStream.class), any(ObjectMetadata.class)); + } + + @Test + void uploadDocument_shouldDenyPatientOnOtherCase() { + Actor otherPatient = new Actor(UUID.randomUUID(), Role.PATIENT, "Other", "other_patient"); + MockMultipartFile file = new MockMultipartFile("file", "test.txt", "text/plain", "hello".getBytes()); + when(caseRepository.findById(caseId)).thenReturn(Optional.of(caseEntity)); + + assertThatThrownBy(() -> documentService.uploadDocument(otherPatient, caseId, file)) + .isInstanceOf(NotAuthorizedException.class); + } + + @Test + void listDocuments_shouldAllowPatientOnOwnCase() { + when(caseRepository.findById(caseId)).thenReturn(Optional.of(caseEntity)); + when(documentRepository.findAllByCaseEntityId(caseId)).thenReturn(List.of()); + + documentService.listDocuments(patientActor, caseId); + + verify(documentRepository).findAllByCaseEntityId(caseId); + } + + @Test + void deleteDocument_shouldDenyPatient() { + UUID docId = UUID.randomUUID(); + + assertThatThrownBy(() -> documentService.deleteDocument(patientActor, docId)) + .isInstanceOf(NotAuthorizedException.class); + + verify(documentRepository, never()).findById(any()); + } }