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 0db4823..c52ff39 100644 --- a/src/main/java/org/example/projektarendehantering/application/service/CaseService.java +++ b/src/main/java/org/example/projektarendehantering/application/service/CaseService.java @@ -14,6 +14,8 @@ import org.example.projektarendehantering.infrastructure.persistence.EmployeeRepository; import org.example.projektarendehantering.infrastructure.persistence.PatientEntity; import org.example.projektarendehantering.infrastructure.persistence.PatientRepository; +import org.example.projektarendehantering.infrastructure.persistence.UserAccountEntity; +import org.example.projektarendehantering.infrastructure.persistence.UserAccountRepository; import org.example.projektarendehantering.presentation.dto.CaseAssignmentDTO; import org.example.projektarendehantering.presentation.dto.CaseDTO; import org.springframework.http.HttpStatus; @@ -39,6 +41,7 @@ public class CaseService { private final PatientRepository patientRepository; private final CaseNoteRepository caseNoteRepository; private final EmployeeRepository employeeRepository; + private final UserAccountRepository userAccountRepository; private final AuditService auditService; @Transactional @@ -75,23 +78,29 @@ public CaseDTO createCase(Actor actor, CaseDTO caseDTO) { if (requestedPatientId != null && !actor.userId().equals(requestedPatientId)) { throw new NotAuthorizedException("Patients can only create cases for themselves"); } - requestedPatientId = actor.userId(); + requestedPatientId = null; } if (requestedPatientId == null) { - throw new BadRequestException("patientId is required"); + if (!isPatient(actor)) { + throw new BadRequestException("patientId is required"); + } } CaseEntity entity = caseMapper.toEntity(caseDTO); entity.setId(UUID.randomUUID()); - PatientEntity patient = patientRepository.findById(requestedPatientId).orElse(null); - if (patient == null) { - if (isPatient(actor) && actor.userId().equals(requestedPatientId)) { + PatientEntity patient; + if (isPatient(actor)) { + patient = patientRepository.findByUserAccount_Id(actor.userId()).orElseGet(() -> { + UserAccountEntity account = userAccountRepository.findById(actor.userId()) + .orElseThrow(() -> new NotAuthorizedException("Patient account not found")); PatientEntity self = new PatientEntity(); - self.setId(requestedPatientId); + self.setId(UUID.randomUUID()); + self.setUserAccount(account); self.setCreatedAt(Instant.now()); - patient = patientRepository.save(self); - } else { - throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Patient not found"); - } + return patientRepository.save(self); + }); + } else { + patient = patientRepository.findById(requestedPatientId) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Patient not found")); } entity.setPatient(patient); if (isDoctor(actor) || isManager(actor)) { @@ -198,7 +207,7 @@ public List getAllCases(Actor actor) { .collect(Collectors.toList()); } if (isPatient(actor)) { - return caseRepository.findAllByPatient_IdAndStatusNot(actor.userId(), CaseStatus.CLOSED).stream() + return caseRepository.findAllByPatient_UserAccount_IdAndStatusNot(actor.userId(), CaseStatus.CLOSED).stream() .map(caseMapper::toDTO) .collect(Collectors.toList()); } @@ -274,7 +283,7 @@ private void requireCanRead(Actor actor, CaseEntity entity) { if (isManager(actor)) return; if (isDoctor(actor) && actor.userId().equals(entity.getOwnerId())) return; if (isNurse(actor) && actor.userId().equals(entity.getHandlerId())) return; - if (isPatient(actor) && entity.getPatient() != null && actor.userId().equals(entity.getPatient().getId())) return; + if (isPatient(actor) && isActorPatientLinked(actor, entity)) return; throw new NotAuthorizedException("Not allowed to read this case"); } @@ -304,10 +313,16 @@ private boolean canRead(Actor actor, CaseEntity entity) { if (isManager(actor)) return true; if (isDoctor(actor) && actor.userId().equals(entity.getOwnerId())) return true; if (isNurse(actor) && actor.userId().equals(entity.getHandlerId())) return true; - if (isPatient(actor) && entity.getPatient() != null && actor.userId().equals(entity.getPatient().getId())) return true; + if (isPatient(actor) && isActorPatientLinked(actor, entity)) return true; return false; } + private boolean isActorPatientLinked(Actor actor, CaseEntity entity) { + return entity.getPatient() != null + && entity.getPatient().getUserAccount() != null + && actor.userId().equals(entity.getPatient().getUserAccount().getId()); + } + private boolean isManager(Actor actor) { return actor.role() == Role.MANAGER; } 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 7aea70f..79d68d1 100644 --- a/src/main/java/org/example/projektarendehantering/application/service/DocumentService.java +++ b/src/main/java/org/example/projektarendehantering/application/service/DocumentService.java @@ -236,8 +236,10 @@ 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; + if (actor.isPatient() + && caseEntity.getPatient() != null + && caseEntity.getPatient().getUserAccount() != null + && actor.userId().equals(caseEntity.getPatient().getUserAccount().getId())) return; throw new NotAuthorizedException("Not authorized to access documents for this case"); } } diff --git a/src/main/java/org/example/projektarendehantering/application/service/RegistrationService.java b/src/main/java/org/example/projektarendehantering/application/service/RegistrationService.java index d7a6c8e..c062918 100644 --- a/src/main/java/org/example/projektarendehantering/application/service/RegistrationService.java +++ b/src/main/java/org/example/projektarendehantering/application/service/RegistrationService.java @@ -14,7 +14,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.Instant; import java.util.Locale; +import java.util.UUID; @Service @RequiredArgsConstructor @@ -59,11 +61,12 @@ public void registerPatient(PatientRegistrationDTO registrationDTO) { } PatientEntity patientEntity = new PatientEntity(); - patientEntity.setId(savedAccount.getId()); + patientEntity.setId(UUID.randomUUID()); patientEntity.setFirstName(firstName); patientEntity.setLastName(lastName); patientEntity.setPersonalIdentityNumber(personalIdentityNumber); - patientEntity.setCreatedAt(savedAccount.getCreatedAt()); + patientEntity.setUserAccount(savedAccount); + patientEntity.setCreatedAt(savedAccount.getCreatedAt() != null ? savedAccount.getCreatedAt() : Instant.now()); try { patientRepository.save(patientEntity); diff --git a/src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseRepository.java b/src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseRepository.java index d298b22..283e93c 100644 --- a/src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseRepository.java +++ b/src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseRepository.java @@ -11,6 +11,7 @@ public interface CaseRepository extends JpaRepository { List findAllByStatusNot(CaseStatus status); List findAllByPatient_Id(UUID patientId); List findAllByPatient_IdAndStatusNot(UUID patientId, CaseStatus status); + List findAllByPatient_UserAccount_IdAndStatusNot(UUID userAccountId, CaseStatus status); List findAllByOwnerId(UUID ownerId); List findAllByOwnerIdAndStatusNot(UUID ownerId, CaseStatus status); List findAllByHandlerId(UUID handlerId); diff --git a/src/main/java/org/example/projektarendehantering/infrastructure/persistence/PatientEntity.java b/src/main/java/org/example/projektarendehantering/infrastructure/persistence/PatientEntity.java index 9c36dec..6066af5 100644 --- a/src/main/java/org/example/projektarendehantering/infrastructure/persistence/PatientEntity.java +++ b/src/main/java/org/example/projektarendehantering/infrastructure/persistence/PatientEntity.java @@ -28,6 +28,10 @@ public class PatientEntity { @Column(unique = true) private String personalIdentityNumber; + @OneToOne + @JoinColumn(name = "user_account_id", unique = true) + private UserAccountEntity userAccount; + private Instant createdAt; } diff --git a/src/main/java/org/example/projektarendehantering/infrastructure/persistence/PatientRepository.java b/src/main/java/org/example/projektarendehantering/infrastructure/persistence/PatientRepository.java index 9005464..0939fa2 100644 --- a/src/main/java/org/example/projektarendehantering/infrastructure/persistence/PatientRepository.java +++ b/src/main/java/org/example/projektarendehantering/infrastructure/persistence/PatientRepository.java @@ -7,5 +7,6 @@ public interface PatientRepository extends JpaRepository { Optional findByPersonalIdentityNumber(String personalIdentityNumber); + Optional findByUserAccount_Id(UUID userAccountId); } diff --git a/src/test/java/org/example/projektarendehantering/application/service/CaseServiceTest.java b/src/test/java/org/example/projektarendehantering/application/service/CaseServiceTest.java index a4d8998..3447f9d 100644 --- a/src/test/java/org/example/projektarendehantering/application/service/CaseServiceTest.java +++ b/src/test/java/org/example/projektarendehantering/application/service/CaseServiceTest.java @@ -41,6 +41,8 @@ class CaseServiceTest { @Mock private EmployeeRepository employeeRepository; @Mock + private UserAccountRepository userAccountRepository; + @Mock private CaseNoteMapper caseNoteMapper; @Mock private AuditService auditService; @@ -79,6 +81,9 @@ void setUp() { PatientEntity patient = new PatientEntity(); patient.setId(patientId); + UserAccountEntity patientUserAccount = new UserAccountEntity(); + patientUserAccount.setId(patientId); + patient.setUserAccount(patientUserAccount); caseEntity.setPatient(patient); } @@ -145,17 +150,22 @@ void createCase_shouldAllowDoctor() { void createCase_shouldAllowPatientAndForceOwnPatientId() { CaseDTO dto = new CaseDTO(); PatientEntity patient = new PatientEntity(); - patient.setId(patientActor.userId()); + patient.setId(UUID.randomUUID()); + UserAccountEntity patientUserAccount = new UserAccountEntity(); + patientUserAccount.setId(patientActor.userId()); + patient.setUserAccount(patientUserAccount); when(caseMapper.toEntity(dto)).thenReturn(new CaseEntity()); - when(patientRepository.findById(patientActor.userId())).thenReturn(Optional.of(patient)); + when(patientRepository.findByUserAccount_Id(patientActor.userId())).thenReturn(Optional.of(patient)); when(caseRepository.save(any(CaseEntity.class))).thenAnswer(i -> i.getArgument(0)); when(caseMapper.toDTO(any(CaseEntity.class))).thenReturn(new CaseDTO()); caseService.createCase(patientActor, dto); - verify(patientRepository).findById(patientActor.userId()); - verify(caseRepository).save(argThat(saved -> saved.getPatient() != null && patientActor.userId().equals(saved.getPatient().getId()))); + verify(patientRepository).findByUserAccount_Id(patientActor.userId()); + verify(caseRepository).save(argThat(saved -> saved.getPatient() != null + && saved.getPatient().getUserAccount() != null + && patientActor.userId().equals(saved.getPatient().getUserAccount().getId()))); } @Test @@ -465,13 +475,13 @@ void getClosedCases_shouldDenyDoctor() { @Test void getAllCases_shouldReturnPatientCasesForPatientActor() { - when(caseRepository.findAllByPatient_IdAndStatusNot(patientActor.userId(), CaseStatus.CLOSED)).thenReturn(List.of(caseEntity)); + when(caseRepository.findAllByPatient_UserAccount_IdAndStatusNot(patientActor.userId(), CaseStatus.CLOSED)).thenReturn(List.of(caseEntity)); when(caseMapper.toDTO(caseEntity)).thenReturn(new CaseDTO()); List result = caseService.getAllCases(patientActor); assertThat(result).hasSize(1); - verify(caseRepository).findAllByPatient_IdAndStatusNot(patientActor.userId(), CaseStatus.CLOSED); + verify(caseRepository).findAllByPatient_UserAccount_IdAndStatusNot(patientActor.userId(), CaseStatus.CLOSED); } @Test 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 8216480..985f7cc 100644 --- a/src/test/java/org/example/projektarendehantering/application/service/DocumentServiceTest.java +++ b/src/test/java/org/example/projektarendehantering/application/service/DocumentServiceTest.java @@ -12,6 +12,7 @@ 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.infrastructure.persistence.UserAccountEntity; import org.example.projektarendehantering.presentation.dto.DocumentDTO; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -85,6 +86,9 @@ void setUp() { PatientEntity patient = new PatientEntity(); patient.setId(patientId); + UserAccountEntity patientUserAccount = new UserAccountEntity(); + patientUserAccount.setId(patientId); + patient.setUserAccount(patientUserAccount); caseId = UUID.randomUUID(); caseEntity = new CaseEntity();