diff --git a/.env.template b/.env.template deleted file mode 100644 index 5563b35..0000000 --- a/.env.template +++ /dev/null @@ -1,4 +0,0 @@ -# GitHub OAuth2 Credentials (DO NOT COMMIT THE ACTUAL .env FILE) -# Get these from GitHub Settings -> Developer settings -> OAuth Apps -GITHUB_CLIENT_ID= -GITHUB_CLIENT_SECRET= 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 eec79f9..80128e9 100644 --- a/src/main/java/org/example/projektarendehantering/application/service/CaseMapper.java +++ b/src/main/java/org/example/projektarendehantering/application/service/CaseMapper.java @@ -14,7 +14,8 @@ public CaseDTO toDTO(CaseEntity entity) { entity.getStatus(), entity.getTitle(), entity.getDescription(), - entity.getCreatedAt() + entity.getCreatedAt(), + entity.getPatient() != null ? entity.getPatient().getId() : null ); } 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 ffd69e3..503e045 100644 --- a/src/main/java/org/example/projektarendehantering/application/service/CaseService.java +++ b/src/main/java/org/example/projektarendehantering/application/service/CaseService.java @@ -2,9 +2,13 @@ import org.example.projektarendehantering.infrastructure.persistence.CaseEntity; import org.example.projektarendehantering.infrastructure.persistence.CaseRepository; +import org.example.projektarendehantering.infrastructure.persistence.PatientEntity; +import org.example.projektarendehantering.infrastructure.persistence.PatientRepository; import org.example.projektarendehantering.presentation.dto.CaseDTO; +import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.server.ResponseStatusException; import java.time.Instant; import java.util.List; @@ -17,15 +21,23 @@ public class CaseService { private final CaseRepository caseRepository; private final CaseMapper caseMapper; + private final PatientRepository patientRepository; - public CaseService(CaseRepository caseRepository, CaseMapper caseMapper) { + public CaseService(CaseRepository caseRepository, CaseMapper caseMapper, PatientRepository patientRepository) { this.caseRepository = caseRepository; this.caseMapper = caseMapper; + this.patientRepository = patientRepository; } @Transactional public CaseDTO createCase(CaseDTO caseDTO) { + if (caseDTO.getPatientId() == null) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "patientId is required"); + } CaseEntity entity = caseMapper.toEntity(caseDTO); + PatientEntity patient = patientRepository.findById(caseDTO.getPatientId()) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Patient not found")); + entity.setPatient(patient); if (entity.getStatus() == null) { entity.setStatus("OPEN"); } @@ -47,4 +59,11 @@ public List getAllCases() { .map(caseMapper::toDTO) .collect(Collectors.toList()); } + + @Transactional(readOnly = true) + public List getCasesForPatient(UUID patientId) { + return caseRepository.findAllByPatient_Id(patientId).stream() + .map(caseMapper::toDTO) + .collect(Collectors.toList()); + } } diff --git a/src/main/java/org/example/projektarendehantering/application/service/PatientMapper.java b/src/main/java/org/example/projektarendehantering/application/service/PatientMapper.java new file mode 100644 index 0000000..aec111e --- /dev/null +++ b/src/main/java/org/example/projektarendehantering/application/service/PatientMapper.java @@ -0,0 +1,30 @@ +package org.example.projektarendehantering.application.service; + +import org.example.projektarendehantering.infrastructure.persistence.PatientEntity; +import org.example.projektarendehantering.presentation.dto.PatientCreateDTO; +import org.example.projektarendehantering.presentation.dto.PatientDTO; +import org.springframework.stereotype.Component; + +@Component +public class PatientMapper { + + public PatientDTO toDTO(PatientEntity entity) { + if (entity == null) return null; + return new PatientDTO( + entity.getId(), + entity.getFirstName(), + entity.getLastName(), + entity.getCreatedAt() + ); + } + + public PatientEntity toEntity(PatientCreateDTO dto) { + if (dto == null) return null; + PatientEntity entity = new PatientEntity(); + entity.setFirstName(dto.getFirstName()); + entity.setLastName(dto.getLastName()); + entity.setPersonalIdentityNumber(dto.getPersonalIdentityNumber()); + return entity; + } +} + diff --git a/src/main/java/org/example/projektarendehantering/application/service/PatientService.java b/src/main/java/org/example/projektarendehantering/application/service/PatientService.java new file mode 100644 index 0000000..b6c153f --- /dev/null +++ b/src/main/java/org/example/projektarendehantering/application/service/PatientService.java @@ -0,0 +1,55 @@ +package org.example.projektarendehantering.application.service; + +import org.example.projektarendehantering.infrastructure.persistence.PatientEntity; +import org.example.projektarendehantering.infrastructure.persistence.PatientRepository; +import org.example.projektarendehantering.presentation.dto.PatientCreateDTO; +import org.example.projektarendehantering.presentation.dto.PatientDTO; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.server.ResponseStatusException; + +import java.time.Instant; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; + +@Service +public class PatientService { + + private final PatientRepository patientRepository; + private final PatientMapper patientMapper; + + public PatientService(PatientRepository patientRepository, PatientMapper patientMapper) { + this.patientRepository = patientRepository; + this.patientMapper = patientMapper; + } + + @Transactional + public PatientDTO createPatient(PatientCreateDTO patientDTO) { + PatientEntity entity = patientMapper.toEntity(patientDTO); + entity.setId(UUID.randomUUID()); + entity.setCreatedAt(Instant.now()); + if (entity.getPersonalIdentityNumber() != null && !entity.getPersonalIdentityNumber().isBlank()) { + patientRepository.findByPersonalIdentityNumber(entity.getPersonalIdentityNumber()) + .ifPresent(existing -> { + throw new ResponseStatusException(HttpStatus.CONFLICT, "Patient with personalIdentityNumber already exists"); + }); + } + return patientMapper.toDTO(patientRepository.save(entity)); + } + + @Transactional(readOnly = true) + public Optional getPatient(UUID id) { + return patientRepository.findById(id).map(patientMapper::toDTO); + } + + @Transactional(readOnly = true) + public List getAllPatients() { + return patientRepository.findAll().stream() + .map(patientMapper::toDTO) + .collect(Collectors.toList()); + } +} + diff --git a/src/main/java/org/example/projektarendehantering/common/Actor.java b/src/main/java/org/example/projektarendehantering/common/Actor.java index 407e4d2..1b701e2 100644 --- a/src/main/java/org/example/projektarendehantering/common/Actor.java +++ b/src/main/java/org/example/projektarendehantering/common/Actor.java @@ -3,4 +3,6 @@ import java.util.UUID; public record Actor(UUID userId, Role role) { + + } 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 c058a00..5a787fe 100644 --- a/src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseEntity.java +++ b/src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseEntity.java @@ -1,7 +1,6 @@ package org.example.projektarendehantering.infrastructure.persistence; import jakarta.persistence.*; - import java.time.Instant; import java.util.UUID; @@ -18,15 +17,20 @@ public class CaseEntity { private String description; private Instant createdAt; + @ManyToOne(optional = false) + @JoinColumn(name = "patient_id", nullable = false) + private PatientEntity patient; + public CaseEntity() {} - public CaseEntity(UUID id, String status, UUID ownerId, String title, String description, Instant createdAt) { + public CaseEntity(UUID id, String status, UUID ownerId, String title, String description, Instant createdAt, PatientEntity patient) { this.id = id; this.status = status; this.ownerId = ownerId; this.title = title; this.description = description; this.createdAt = createdAt; + this.patient = patient; } public UUID getId() { return id; } @@ -46,4 +50,7 @@ public CaseEntity(UUID id, String status, UUID ownerId, String title, String des public Instant getCreatedAt() { return createdAt; } public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } + + public PatientEntity getPatient() { return patient; } + public void setPatient(PatientEntity patient) { this.patient = patient; } } 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 0eb62c0..7d40d5d 100644 --- a/src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseRepository.java +++ b/src/main/java/org/example/projektarendehantering/infrastructure/persistence/CaseRepository.java @@ -1,7 +1,10 @@ package org.example.projektarendehantering.infrastructure.persistence; import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; import java.util.UUID; public interface CaseRepository extends JpaRepository { + List findAllByPatient_Id(UUID patientId); } diff --git a/src/main/java/org/example/projektarendehantering/infrastructure/persistence/PatientEntity.java b/src/main/java/org/example/projektarendehantering/infrastructure/persistence/PatientEntity.java new file mode 100644 index 0000000..b5f129a --- /dev/null +++ b/src/main/java/org/example/projektarendehantering/infrastructure/persistence/PatientEntity.java @@ -0,0 +1,49 @@ +package org.example.projektarendehantering.infrastructure.persistence; + +import jakarta.persistence.*; + +import java.time.Instant; +import java.util.UUID; + +@Entity +@Table(name = "patients") +public class PatientEntity { + + @Id + @GeneratedValue(strategy = GenerationType.UUID) + private UUID id; + + private String firstName; + private String lastName; + + @Column(unique = true) + private String personalIdentityNumber; + + private Instant createdAt; + + public PatientEntity() {} + + public PatientEntity(UUID id, String firstName, String lastName, String personalIdentityNumber, Instant createdAt) { + this.id = id; + this.firstName = firstName; + this.lastName = lastName; + this.personalIdentityNumber = personalIdentityNumber; + this.createdAt = createdAt; + } + + public UUID getId() { return id; } + public void setId(UUID id) { this.id = id; } + + public String getFirstName() { return firstName; } + public void setFirstName(String firstName) { this.firstName = firstName; } + + public String getLastName() { return lastName; } + public void setLastName(String lastName) { this.lastName = lastName; } + + public String getPersonalIdentityNumber() { return personalIdentityNumber; } + public void setPersonalIdentityNumber(String personalIdentityNumber) { this.personalIdentityNumber = personalIdentityNumber; } + + public Instant getCreatedAt() { return createdAt; } + public void setCreatedAt(Instant createdAt) { this.createdAt = 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 new file mode 100644 index 0000000..9005464 --- /dev/null +++ b/src/main/java/org/example/projektarendehantering/infrastructure/persistence/PatientRepository.java @@ -0,0 +1,11 @@ +package org.example.projektarendehantering.infrastructure.persistence; + +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; +import java.util.UUID; + +public interface PatientRepository extends JpaRepository { + Optional findByPersonalIdentityNumber(String personalIdentityNumber); +} + 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 050fcb9..e0c306e 100644 --- a/src/main/java/org/example/projektarendehantering/presentation/dto/CaseDTO.java +++ b/src/main/java/org/example/projektarendehantering/presentation/dto/CaseDTO.java @@ -1,5 +1,7 @@ package org.example.projektarendehantering.presentation.dto; +import jakarta.validation.constraints.NotNull; + import java.time.Instant; import java.util.UUID; @@ -11,14 +13,18 @@ public class CaseDTO { private String description; private Instant createdAt; + @NotNull + private UUID patientId; + public CaseDTO() {} - public CaseDTO(UUID id, String status, String title, String description, Instant createdAt) { + public CaseDTO(UUID id, String status, String title, String description, Instant createdAt, UUID patientId) { this.id = id; this.status = status; this.title = title; this.description = description; this.createdAt = createdAt; + this.patientId = patientId; } public UUID getId() { return id; } @@ -35,4 +41,7 @@ public CaseDTO(UUID id, String status, String title, String description, Instant public Instant getCreatedAt() { return createdAt; } public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } + + public UUID getPatientId() { return patientId; } + public void setPatientId(UUID patientId) { this.patientId = patientId; } } diff --git a/src/main/java/org/example/projektarendehantering/presentation/dto/PatientCreateDTO.java b/src/main/java/org/example/projektarendehantering/presentation/dto/PatientCreateDTO.java new file mode 100644 index 0000000..4038ad4 --- /dev/null +++ b/src/main/java/org/example/projektarendehantering/presentation/dto/PatientCreateDTO.java @@ -0,0 +1,32 @@ +package org.example.projektarendehantering.presentation.dto; + +import jakarta.validation.constraints.NotBlank; + +public class PatientCreateDTO { + + @NotBlank + private String firstName; + + @NotBlank + private String lastName; + + private String personalIdentityNumber; + + public PatientCreateDTO() {} + + public PatientCreateDTO(String firstName, String lastName, String personalIdentityNumber) { + this.firstName = firstName; + this.lastName = lastName; + this.personalIdentityNumber = personalIdentityNumber; + } + + public String getFirstName() { return firstName; } + public void setFirstName(String firstName) { this.firstName = firstName; } + + public String getLastName() { return lastName; } + public void setLastName(String lastName) { this.lastName = lastName; } + + public String getPersonalIdentityNumber() { return personalIdentityNumber; } + public void setPersonalIdentityNumber(String personalIdentityNumber) { this.personalIdentityNumber = personalIdentityNumber; } +} + diff --git a/src/main/java/org/example/projektarendehantering/presentation/dto/PatientDTO.java b/src/main/java/org/example/projektarendehantering/presentation/dto/PatientDTO.java new file mode 100644 index 0000000..53bfb7f --- /dev/null +++ b/src/main/java/org/example/projektarendehantering/presentation/dto/PatientDTO.java @@ -0,0 +1,41 @@ +package org.example.projektarendehantering.presentation.dto; + +import jakarta.validation.constraints.NotBlank; + +import java.time.Instant; +import java.util.UUID; + +public class PatientDTO { + + private UUID id; + + @NotBlank + private String firstName; + + @NotBlank + private String lastName; + + private Instant createdAt; + + public PatientDTO() {} + + public PatientDTO(UUID id, String firstName, String lastName, Instant createdAt) { + this.id = id; + this.firstName = firstName; + this.lastName = lastName; + this.createdAt = createdAt; + } + + public UUID getId() { return id; } + public void setId(UUID id) { this.id = id; } + + public String getFirstName() { return firstName; } + public void setFirstName(String firstName) { this.firstName = firstName; } + + public String getLastName() { return lastName; } + public void setLastName(String lastName) { this.lastName = lastName; } + + public Instant getCreatedAt() { return createdAt; } + public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; } +} + diff --git a/src/main/java/org/example/projektarendehantering/presentation/rest/PatientController.java b/src/main/java/org/example/projektarendehantering/presentation/rest/PatientController.java new file mode 100644 index 0000000..a0b2430 --- /dev/null +++ b/src/main/java/org/example/projektarendehantering/presentation/rest/PatientController.java @@ -0,0 +1,49 @@ +package org.example.projektarendehantering.presentation.rest; + +import jakarta.validation.Valid; +import org.example.projektarendehantering.application.service.CaseService; +import org.example.projektarendehantering.application.service.PatientService; +import org.example.projektarendehantering.presentation.dto.PatientCreateDTO; +import org.example.projektarendehantering.presentation.dto.CaseDTO; +import org.example.projektarendehantering.presentation.dto.PatientDTO; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.UUID; + +@RestController +@RequestMapping("/api/patients") +public class PatientController { + + private final PatientService patientService; + private final CaseService caseService; + + public PatientController(PatientService patientService, CaseService caseService) { + this.patientService = patientService; + this.caseService = caseService; + } + + @PostMapping + public ResponseEntity createPatient(@RequestBody @Valid PatientCreateDTO patientDTO) { + return ResponseEntity.ok(patientService.createPatient(patientDTO)); + } + + @GetMapping("/{id}") + public ResponseEntity getPatient(@PathVariable UUID id) { + return patientService.getPatient(id) + .map(ResponseEntity::ok) + .orElse(ResponseEntity.notFound().build()); + } + + @GetMapping + public ResponseEntity> getAllPatients() { + return ResponseEntity.ok(patientService.getAllPatients()); + } + + @GetMapping("/{id}/cases") + public ResponseEntity> getCasesForPatient(@PathVariable UUID id) { + return ResponseEntity.ok(caseService.getCasesForPatient(id)); + } +} +