Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.example.projektarendehantering.infrastructure.persistence.EmployeeEntity;
import org.example.projektarendehantering.presentation.dto.EmployeeCreateDTO;
import org.example.projektarendehantering.presentation.dto.EmployeeDTO;
import org.example.projektarendehantering.presentation.dto.EmployeeUpdateDTO;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
Expand Down Expand Up @@ -36,5 +37,12 @@ public EmployeeEntity toEntity(EmployeeCreateDTO dto) {
.role(dto.getRole())
.build();
}

public void updateEntity(EmployeeUpdateDTO dto, EmployeeEntity entity) {
if (dto == null || entity == null) return;
entity.setDisplayName(dto.getDisplayName());
entity.setGithubUsername(dto.getGithubUsername());
entity.setRole(dto.getRole());
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.example.projektarendehantering.infrastructure.persistence.EmployeeRepository;
import org.example.projektarendehantering.presentation.dto.EmployeeCreateDTO;
import org.example.projektarendehantering.presentation.dto.EmployeeDTO;
import org.example.projektarendehantering.presentation.dto.EmployeeUpdateDTO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -41,6 +42,28 @@ public EmployeeDTO createEmployee(Actor actor, EmployeeCreateDTO dto) {
return employeeMapper.toDTO(employeeRepository.save(entity));
}

@Transactional
public EmployeeDTO updateEmployee(Actor actor, UUID id, EmployeeUpdateDTO dto) {
requireCanManageEmployees(actor);
EmployeeEntity entity = employeeRepository.findById(id)
.orElseThrow(() -> new BadRequestException("EMPLOYEE_NOT_FOUND", "Employee not found"));

if (!entity.getGithubUsername().equals(dto.getGithubUsername())) {
throw new BadRequestException("EMPLOYEE_USERNAME_IMMUTABLE", "Github username cannot be changed");
}

employeeMapper.updateEntity(dto, entity);
return employeeMapper.toDTO(employeeRepository.save(entity));
Comment thread
Tyreviel marked this conversation as resolved.
}

@Transactional
public void deleteEmployee(Actor actor, UUID id) {
requireCanManageEmployees(actor);
EmployeeEntity entity = employeeRepository.findById(id)
.orElseThrow(() -> new BadRequestException("EMPLOYEE_NOT_FOUND", "Employee not found"));
employeeRepository.delete(entity);
}

@Transactional(readOnly = true)
public Optional<EmployeeDTO> getEmployee(Actor actor, UUID id) {
requireCanManageEmployees(actor);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.example.projektarendehantering.infrastructure.persistence.PatientEntity;
import org.example.projektarendehantering.presentation.dto.PatientCreateDTO;
import org.example.projektarendehantering.presentation.dto.PatientDTO;
import org.example.projektarendehantering.presentation.dto.PatientUpdateDTO;
import org.springframework.stereotype.Component;

@Component
Expand All @@ -27,4 +28,11 @@ public PatientEntity toEntity(PatientCreateDTO dto) {
.personalIdentityNumber(dto.getPersonalIdentityNumber())
.build();
}

public void updateEntity(PatientUpdateDTO dto, PatientEntity entity) {
if (dto == null || entity == null) return;
entity.setFirstName(dto.getFirstName());
entity.setLastName(dto.getLastName());
entity.setPersonalIdentityNumber(dto.getPersonalIdentityNumber());
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package org.example.projektarendehantering.application.service;

import org.example.projektarendehantering.common.Actor;
import org.example.projektarendehantering.common.BadRequestException;
import org.example.projektarendehantering.common.ConflictException;
import org.example.projektarendehantering.common.NotAuthorizedException;
import org.example.projektarendehantering.common.Role;
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.example.projektarendehantering.presentation.dto.PatientUpdateDTO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -36,6 +41,33 @@ public PatientDTO createPatient(PatientCreateDTO patientDTO) {
return patientMapper.toDTO(patientRepository.save(entity));
}

@Transactional
public PatientDTO updatePatient(Actor actor, UUID id, PatientUpdateDTO dto) {
requireCanManagePatients(actor);
PatientEntity entity = patientRepository.findById(id)
.orElseThrow(() -> new BadRequestException("PATIENT_NOT_FOUND", "Patient not found"));

String newPin = dto.getPersonalIdentityNumber();
if (newPin != null && !newPin.isBlank()
&& !newPin.equals(entity.getPersonalIdentityNumber())) {
patientRepository.findByPersonalIdentityNumber(newPin)
.ifPresent(existing -> {
throw new ConflictException("Patient with personalIdentityNumber already exists");
});
}

patientMapper.updateEntity(dto, entity);
return patientMapper.toDTO(patientRepository.save(entity));
}

@Transactional
public void deletePatient(Actor actor, UUID id) {
requireCanManagePatients(actor);
PatientEntity entity = patientRepository.findById(id)
.orElseThrow(() -> new BadRequestException("PATIENT_NOT_FOUND", "Patient not found"));
patientRepository.delete(entity);
}
Comment thread
Tyreviel marked this conversation as resolved.

@Transactional(readOnly = true)
public Optional<PatientDTO> getPatient(UUID id) {
return patientRepository.findById(id).map(patientMapper::toDTO);
Expand All @@ -47,4 +79,14 @@ public List<PatientDTO> getAllPatients() {
.map(patientMapper::toDTO)
.collect(Collectors.toList());
}

private void requireCanManagePatients(Actor actor) {
if (actor == null) {
throw new NotAuthorizedException("Missing actor");
}
if (actor.role() == Role.MANAGER) {
return;
}
throw new NotAuthorizedException("Not allowed to manage patients");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.example.projektarendehantering.presentation.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.example.projektarendehantering.common.Role;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class EmployeeUpdateDTO {

@NotBlank
private String displayName;

@NotBlank
private String githubUsername;

@NotNull
private Role role;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.example.projektarendehantering.presentation.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PatientUpdateDTO {

@NotBlank
private String firstName;

@NotBlank
private String lastName;

@NotBlank
@Pattern(regexp = "^\\d{8}-\\d{4}$", message = "Use format YYYYMMDD-XXXX")
private String personalIdentityNumber;

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.example.projektarendehantering.infrastructure.security.SecurityActorAdapter;
import org.example.projektarendehantering.presentation.dto.EmployeeCreateDTO;
import org.example.projektarendehantering.presentation.dto.EmployeeDTO;
import org.example.projektarendehantering.presentation.dto.EmployeeUpdateDTO;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

Expand All @@ -25,6 +26,17 @@ public ResponseEntity<EmployeeDTO> createEmployee(@RequestBody @Valid EmployeeCr
return ResponseEntity.ok(employeeService.createEmployee(securityActorAdapter.currentUser(), dto));
}

@PutMapping("/{id}")
public ResponseEntity<EmployeeDTO> updateEmployee(@PathVariable UUID id, @RequestBody @Valid EmployeeUpdateDTO dto) {
return ResponseEntity.ok(employeeService.updateEmployee(securityActorAdapter.currentUser(), id, dto));
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteEmployee(@PathVariable UUID id) {
employeeService.deleteEmployee(securityActorAdapter.currentUser(), id);
return ResponseEntity.noContent().build();
}

@GetMapping("/{id}")
public ResponseEntity<EmployeeDTO> getEmployee(@PathVariable UUID id) {
return employeeService.getEmployee(securityActorAdapter.currentUser(), id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@
import org.example.projektarendehantering.presentation.dto.PatientCreateDTO;
import org.example.projektarendehantering.presentation.dto.CaseDTO;
import org.example.projektarendehantering.presentation.dto.PatientDTO;
import org.example.projektarendehantering.presentation.dto.PatientUpdateDTO;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.UUID;

// Adding more wierd stuff in the code base to commit things again cuz the rabbit rate limits suck :)
@RestController
@RequestMapping("/api/patients")
@RequiredArgsConstructor
Expand All @@ -25,10 +26,24 @@ public class PatientController {
private final SecurityActorAdapter securityActorAdapter;

@PostMapping
@PreAuthorize("hasRole('MANAGER')")
public ResponseEntity<PatientDTO> createPatient(@RequestBody @Valid PatientCreateDTO patientDTO) {
return ResponseEntity.ok(patientService.createPatient(patientDTO));
}

@PutMapping("/{id}")
@PreAuthorize("hasRole('MANAGER')")
public ResponseEntity<PatientDTO> updatePatient(@PathVariable UUID id, @RequestBody @Valid PatientUpdateDTO patientDTO) {
return ResponseEntity.ok(patientService.updatePatient(securityActorAdapter.currentUser(), id, patientDTO));
}

@DeleteMapping("/{id}")
@PreAuthorize("hasRole('MANAGER')")
public ResponseEntity<Void> deletePatient(@PathVariable UUID id) {
patientService.deletePatient(securityActorAdapter.currentUser(), id);
return ResponseEntity.noContent().build();
}
Comment thread
Tyreviel marked this conversation as resolved.

@GetMapping("/{id}")
public ResponseEntity<PatientDTO> getPatient(@PathVariable UUID id) {
return patientService.getPatient(id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,19 @@
import org.example.projektarendehantering.common.Role;
import org.example.projektarendehantering.infrastructure.security.SecurityActorAdapter;
import org.example.projektarendehantering.presentation.dto.EmployeeCreateDTO;
import org.example.projektarendehantering.presentation.dto.EmployeeDTO;
import org.example.projektarendehantering.presentation.dto.EmployeeUpdateDTO;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;

import java.util.UUID;

@Controller
public class EmployeeUiController {

Expand Down Expand Up @@ -53,4 +58,45 @@ public String createEmployee(@Valid @ModelAttribute("employeeCreateDTO") Employe
employeeService.createEmployee(actor, dto);
return "redirect:/ui/employees";
}

@GetMapping("/ui/employees/edit/{id}")
@PreAuthorize("hasRole('MANAGER')")
public String editEmployee(@PathVariable UUID id, Model model) {
Actor actor = securityActorAdapter.currentUser();
EmployeeDTO employee = employeeService.getEmployee(actor, id)
.orElseThrow(() -> new IllegalArgumentException("Invalid employee Id:" + id));

EmployeeUpdateDTO updateDto = EmployeeUpdateDTO.builder()
.displayName(employee.getDisplayName())
.githubUsername(employee.getGithubUsername())
.role(employee.getRole())
.build();

model.addAttribute("employeeUpdateDTO", updateDto);
model.addAttribute("employeeId", id);
model.addAttribute("roles", Role.values());
return "employees/edit";
}

@PostMapping("/ui/employees/update/{id}")
@PreAuthorize("hasRole('MANAGER')")
public String updateEmployee(@PathVariable UUID id, @Valid @ModelAttribute("employeeUpdateDTO") EmployeeUpdateDTO dto, BindingResult result, Model model) {
Actor actor = securityActorAdapter.currentUser();
if (result.hasErrors()) {
model.addAttribute("employeeId", id);
model.addAttribute("roles", Role.values());
return "employees/edit";
}

employeeService.updateEmployee(actor, id, dto);
return "redirect:/ui/employees";
}

@PostMapping("/ui/employees/delete/{id}")
@PreAuthorize("hasRole('MANAGER')")
public String deleteEmployee(@PathVariable UUID id) {
Actor actor = securityActorAdapter.currentUser();
employeeService.deleteEmployee(actor, id);
return "redirect:/ui/employees";
}
}
Loading