Enforce pet ownership rules

This commit is contained in:
2026-04-05 23:35:05 -06:00
parent bdd5566493
commit 8d3430bd75
4 changed files with 10 additions and 67 deletions

View File

@@ -80,15 +80,8 @@ public class DropdownController {
@GetMapping("/appointment-customers") @GetMapping("/appointment-customers")
@PreAuthorize("hasAnyRole('STAFF', 'ADMIN')") @PreAuthorize("hasAnyRole('STAFF', 'ADMIN')")
public ResponseEntity<List<DropdownOption>> getAppointmentCustomers() { public ResponseEntity<List<DropdownOption>> getAppointmentCustomers() {
User user = com.petshop.backend.util.AuthenticationHelper.getAuthenticatedUser(userRepository);
List<com.petshop.backend.entity.Customer> customers;
if (user.getRole() == User.Role.ADMIN) {
customers = customerRepository.findAll();
} else {
customers = customerRepository.findAllWithPets();
}
return ResponseEntity.ok( return ResponseEntity.ok(
customers.stream() customerRepository.findAllWithPets().stream()
.map(c -> new DropdownOption(c.getCustomerId(), c.getFirstName() + " " + c.getLastName())) .map(c -> new DropdownOption(c.getCustomerId(), c.getFirstName() + " " + c.getLastName()))
.collect(Collectors.toList()) .collect(Collectors.toList())
); );

View File

@@ -122,7 +122,7 @@ public class AppointmentService {
} }
Set<Pet> pets = hasPetIds ? fetchPets(request.getPetIds()) : new HashSet<>(); Set<Pet> pets = hasPetIds ? fetchPets(request.getPetIds()) : new HashSet<>();
Set<CustomerPet> customerPets = hasCustomerPetIds ? fetchCustomerPets(request.getCustomerPetIds(), customer.getCustomerId(), authenticatedUser.getRole()) : new HashSet<>(); Set<CustomerPet> customerPets = hasCustomerPetIds ? fetchCustomerPets(request.getCustomerPetIds(), customer.getCustomerId()) : new HashSet<>();
Employee employee = resolveAppointmentEmployee(request.getEmployeeId(), store.getStoreId()); Employee employee = resolveAppointmentEmployee(request.getEmployeeId(), store.getStoreId());
Appointment appointment = new Appointment(); Appointment appointment = new Appointment();
@@ -170,7 +170,7 @@ public class AppointmentService {
} }
Set<Pet> pets = hasPetIds ? fetchPets(request.getPetIds()) : new HashSet<>(); Set<Pet> pets = hasPetIds ? fetchPets(request.getPetIds()) : new HashSet<>();
Set<CustomerPet> customerPets = hasCustomerPetIds ? fetchCustomerPets(request.getCustomerPetIds(), customer.getCustomerId(), authenticatedUser.getRole()) : new HashSet<>(); Set<CustomerPet> customerPets = hasCustomerPetIds ? fetchCustomerPets(request.getCustomerPetIds(), customer.getCustomerId()) : new HashSet<>();
Employee employee = resolveAppointmentEmployee(request.getEmployeeId(), store.getStoreId()); Employee employee = resolveAppointmentEmployee(request.getEmployeeId(), store.getStoreId());
appointment.setCustomer(customer); appointment.setCustomer(customer);
@@ -255,12 +255,12 @@ public class AppointmentService {
return pets; return pets;
} }
private Set<CustomerPet> fetchCustomerPets(List<Long> customerPetIds, Long customerId, User.Role authenticatedRole) { private Set<CustomerPet> fetchCustomerPets(List<Long> customerPetIds, Long customerId) {
Set<CustomerPet> customerPets = new HashSet<>(); Set<CustomerPet> customerPets = new HashSet<>();
for (Long customerPetId : customerPetIds) { for (Long customerPetId : customerPetIds) {
CustomerPet customerPet = customerPetRepository.findById(customerPetId) CustomerPet customerPet = customerPetRepository.findById(customerPetId)
.orElseThrow(() -> new ResourceNotFoundException("Customer pet not found with id: " + customerPetId)); .orElseThrow(() -> new ResourceNotFoundException("Customer pet not found with id: " + customerPetId));
if (authenticatedRole != User.Role.ADMIN && !customerPet.getCustomer().getCustomerId().equals(customerId)) { if (!customerPet.getCustomer().getCustomerId().equals(customerId)) {
throw new IllegalArgumentException("Selected pet does not belong to the selected customer"); throw new IllegalArgumentException("Selected pet does not belong to the selected customer");
} }
customerPets.add(customerPet); customerPets.add(customerPet);

View File

@@ -173,7 +173,7 @@ class DropdownControllerTest {
} }
@Test @Test
void getAppointmentCustomersReturnsAllCustomersForAdmin() { void getAppointmentCustomersReturnsOnlyCustomersWithPetsForAdmin() {
User adminUser = new User(); User adminUser = new User();
adminUser.setId(88L); adminUser.setId(88L);
adminUser.setRole(User.Role.ADMIN); adminUser.setRole(User.Role.ADMIN);
@@ -185,17 +185,11 @@ class DropdownControllerTest {
one.setFirstName("Alex"); one.setFirstName("Alex");
one.setLastName("Brown"); one.setLastName("Brown");
Customer two = new Customer(); when(customerRepository.findAllWithPets()).thenReturn(List.of(one));
two.setCustomerId(2L);
two.setFirstName("Emily");
two.setLastName("Clark");
when(customerRepository.findAll()).thenReturn(List.of(one, two));
var response = controller.getAppointmentCustomers(); var response = controller.getAppointmentCustomers();
assertEquals(2, response.getBody().size()); assertEquals(1, response.getBody().size());
assertEquals(Long.valueOf(1L), response.getBody().get(0).getId()); assertEquals(Long.valueOf(1L), response.getBody().get(0).getId());
assertEquals(Long.valueOf(2L), response.getBody().get(1).getId());
} }
} }

View File

@@ -188,7 +188,7 @@ class AppointmentServiceTest {
} }
@Test @Test
void createAppointmentAllowsCustomerPetOwnedByDifferentCustomerForAdmin() { void createAppointmentRejectsCustomerPetOwnedByDifferentCustomer() {
setAuthentication(99L, User.Role.ADMIN); setAuthentication(99L, User.Role.ADMIN);
Customer otherCustomer = new Customer(); Customer otherCustomer = new Customer();
@@ -206,11 +206,6 @@ class AppointmentServiceTest {
.thenReturn(List.of(new EmployeeStore(employee, store))); .thenReturn(List.of(new EmployeeStore(employee, store)));
when(appointmentRepository.findByStoreAndDate(1L, date)).thenReturn(List.of()); when(appointmentRepository.findByStoreAndDate(1L, date)).thenReturn(List.of());
when(customerPetRepository.findById(22L)).thenReturn(Optional.of(otherCustomerPet)); when(customerPetRepository.findById(22L)).thenReturn(Optional.of(otherCustomerPet));
when(appointmentRepository.save(any(Appointment.class))).thenAnswer(invocation -> {
Appointment appt = invocation.getArgument(0);
appt.setAppointmentId(101L);
return appt;
});
var request = new com.petshop.backend.dto.appointment.AppointmentRequest(); var request = new com.petshop.backend.dto.appointment.AppointmentRequest();
request.setCustomerId(1L); request.setCustomerId(1L);
@@ -221,46 +216,7 @@ class AppointmentServiceTest {
request.setAppointmentStatus("Booked"); request.setAppointmentStatus("Booked");
request.setCustomerPetIds(List.of(22L)); request.setCustomerPetIds(List.of(22L));
var response = appointmentService.createAppointment(request); assertThrows(IllegalArgumentException.class, () -> appointmentService.createAppointment(request));
assertEquals(101L, response.getAppointmentId());
}
@Test
void createAppointmentAllowsAnyPetForAdmin() {
setAuthentication(99L, User.Role.ADMIN);
Customer otherCustomer = new Customer();
otherCustomer.setCustomerId(22L);
CustomerPet otherCustomerPet = new CustomerPet();
otherCustomerPet.setCustomerPetId(22L);
otherCustomerPet.setCustomer(otherCustomer);
when(customerRepository.findById(1L)).thenReturn(Optional.of(customer));
when(storeRepository.findById(1L)).thenReturn(Optional.of(store));
when(serviceRepository.findById(1L)).thenReturn(Optional.of(grooming));
when(employeeStoreRepository.findActiveByStoreStoreIdOrderByEmployeeEmployeeIdAsc(1L))
.thenReturn(List.of(new EmployeeStore(employee, store)));
when(appointmentRepository.findByStoreAndDate(1L, date)).thenReturn(List.of());
when(customerPetRepository.findById(22L)).thenReturn(Optional.of(otherCustomerPet));
when(appointmentRepository.save(any(Appointment.class))).thenAnswer(invocation -> {
Appointment appointment = invocation.getArgument(0);
appointment.setAppointmentId(101L);
return appointment;
});
var request = new com.petshop.backend.dto.appointment.AppointmentRequest();
request.setCustomerId(1L);
request.setStoreId(1L);
request.setServiceId(1L);
request.setAppointmentDate(date);
request.setAppointmentTime(LocalTime.of(10, 0));
request.setAppointmentStatus("Booked");
request.setCustomerPetIds(List.of(22L));
var response = appointmentService.createAppointment(request);
assertEquals(101L, response.getAppointmentId());
assertEquals(1L, response.getCustomerId());
} }
@Test @Test