Allow admin ownership bypass
This commit is contained in:
@@ -80,8 +80,15 @@ public class DropdownController {
|
||||
@GetMapping("/appointment-customers")
|
||||
@PreAuthorize("hasAnyRole('STAFF', 'ADMIN')")
|
||||
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(
|
||||
customerRepository.findAllWithPets().stream()
|
||||
customers.stream()
|
||||
.map(c -> new DropdownOption(c.getCustomerId(), c.getFirstName() + " " + c.getLastName()))
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
@@ -194,7 +201,7 @@ public class DropdownController {
|
||||
return false;
|
||||
}
|
||||
return userRepository.findById(userId)
|
||||
.filter(user -> user.getRole() == User.Role.STAFF)
|
||||
.filter(user -> user.getRole() == User.Role.STAFF || user.getRole() == User.Role.ADMIN)
|
||||
.filter(user -> Boolean.TRUE.equals(user.getActive()))
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ public class AdoptionService {
|
||||
return false;
|
||||
}
|
||||
return userRepository.findById(userId)
|
||||
.filter(user -> user.getRole() == User.Role.STAFF)
|
||||
.filter(user -> user.getRole() == User.Role.STAFF || user.getRole() == User.Role.ADMIN)
|
||||
.filter(user -> Boolean.TRUE.equals(user.getActive()))
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
@@ -99,6 +99,8 @@ public class AppointmentService {
|
||||
public AppointmentResponse createAppointment(AppointmentRequest request) {
|
||||
validateAppointmentRequest(request);
|
||||
|
||||
User authenticatedUser = AuthenticationHelper.getAuthenticatedUser(userRepository);
|
||||
|
||||
Customer customer = customerRepository.findById(request.getCustomerId())
|
||||
.orElseThrow(() -> new ResourceNotFoundException("Customer not found with id: " + request.getCustomerId()));
|
||||
|
||||
@@ -108,7 +110,7 @@ public class AppointmentService {
|
||||
com.petshop.backend.entity.Service service = serviceRepository.findById(request.getServiceId())
|
||||
.orElseThrow(() -> new ResourceNotFoundException("Service not found with id: " + request.getServiceId()));
|
||||
|
||||
validateStoreAccess(store.getStoreId());
|
||||
validateStoreAccess(store.getStoreId(), authenticatedUser);
|
||||
validateAvailability(store, service, request.getAppointmentDate(), request.getAppointmentTime(), null);
|
||||
|
||||
boolean hasPetIds = request.getPetIds() != null && !request.getPetIds().isEmpty();
|
||||
@@ -120,7 +122,7 @@ public class AppointmentService {
|
||||
}
|
||||
|
||||
Set<Pet> pets = hasPetIds ? fetchPets(request.getPetIds()) : new HashSet<>();
|
||||
Set<CustomerPet> customerPets = hasCustomerPetIds ? fetchCustomerPets(request.getCustomerPetIds(), customer.getCustomerId()) : new HashSet<>();
|
||||
Set<CustomerPet> customerPets = hasCustomerPetIds ? fetchCustomerPets(request.getCustomerPetIds(), customer.getCustomerId(), authenticatedUser.getRole()) : new HashSet<>();
|
||||
Employee employee = resolveAppointmentEmployee(request.getEmployeeId(), store.getStoreId());
|
||||
|
||||
Appointment appointment = new Appointment();
|
||||
@@ -142,6 +144,8 @@ public class AppointmentService {
|
||||
public AppointmentResponse updateAppointment(Long id, AppointmentRequest request) {
|
||||
validateAppointmentRequest(request);
|
||||
|
||||
User authenticatedUser = AuthenticationHelper.getAuthenticatedUser(userRepository);
|
||||
|
||||
Appointment appointment = appointmentRepository.findById(id)
|
||||
.orElseThrow(() -> new ResourceNotFoundException("Appointment not found with id: " + id));
|
||||
|
||||
@@ -154,7 +158,7 @@ public class AppointmentService {
|
||||
com.petshop.backend.entity.Service service = serviceRepository.findById(request.getServiceId())
|
||||
.orElseThrow(() -> new ResourceNotFoundException("Service not found with id: " + request.getServiceId()));
|
||||
|
||||
validateStoreAccess(store.getStoreId());
|
||||
validateStoreAccess(store.getStoreId(), authenticatedUser);
|
||||
validateAvailability(store, service, request.getAppointmentDate(), request.getAppointmentTime(), id);
|
||||
|
||||
boolean hasPetIds = request.getPetIds() != null && !request.getPetIds().isEmpty();
|
||||
@@ -166,7 +170,7 @@ public class AppointmentService {
|
||||
}
|
||||
|
||||
Set<Pet> pets = hasPetIds ? fetchPets(request.getPetIds()) : new HashSet<>();
|
||||
Set<CustomerPet> customerPets = hasCustomerPetIds ? fetchCustomerPets(request.getCustomerPetIds(), customer.getCustomerId()) : new HashSet<>();
|
||||
Set<CustomerPet> customerPets = hasCustomerPetIds ? fetchCustomerPets(request.getCustomerPetIds(), customer.getCustomerId(), authenticatedUser.getRole()) : new HashSet<>();
|
||||
Employee employee = resolveAppointmentEmployee(request.getEmployeeId(), store.getStoreId());
|
||||
|
||||
appointment.setCustomer(customer);
|
||||
@@ -251,12 +255,12 @@ public class AppointmentService {
|
||||
return pets;
|
||||
}
|
||||
|
||||
private Set<CustomerPet> fetchCustomerPets(List<Long> customerPetIds, Long customerId) {
|
||||
private Set<CustomerPet> fetchCustomerPets(List<Long> customerPetIds, Long customerId, User.Role authenticatedRole) {
|
||||
Set<CustomerPet> customerPets = new HashSet<>();
|
||||
for (Long customerPetId : customerPetIds) {
|
||||
CustomerPet customerPet = customerPetRepository.findById(customerPetId)
|
||||
.orElseThrow(() -> new ResourceNotFoundException("Customer pet not found with id: " + customerPetId));
|
||||
if (!customerPet.getCustomer().getCustomerId().equals(customerId)) {
|
||||
if (authenticatedRole != User.Role.ADMIN && !customerPet.getCustomer().getCustomerId().equals(customerId)) {
|
||||
throw new IllegalArgumentException("Selected pet does not belong to the selected customer");
|
||||
}
|
||||
customerPets.add(customerPet);
|
||||
@@ -333,7 +337,7 @@ public class AppointmentService {
|
||||
return false;
|
||||
}
|
||||
return userRepository.findById(userId)
|
||||
.filter(user -> user.getRole() == User.Role.STAFF)
|
||||
.filter(user -> user.getRole() == User.Role.STAFF || user.getRole() == User.Role.ADMIN)
|
||||
.filter(user -> Boolean.TRUE.equals(user.getActive()))
|
||||
.isPresent();
|
||||
}
|
||||
@@ -368,8 +372,7 @@ public class AppointmentService {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void validateStoreAccess(Long requestedStoreId) {
|
||||
User user = AuthenticationHelper.getAuthenticatedUser(userRepository);
|
||||
private void validateStoreAccess(Long requestedStoreId, User user) {
|
||||
if (user.getRole() != User.Role.STAFF) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,12 @@ import com.petshop.backend.repository.ServiceRepository;
|
||||
import com.petshop.backend.repository.StoreRepository;
|
||||
import com.petshop.backend.repository.SupplierRepository;
|
||||
import com.petshop.backend.repository.UserRepository;
|
||||
import com.petshop.backend.security.AppPrincipal;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@@ -26,20 +31,32 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
class DropdownControllerTest {
|
||||
|
||||
@Test
|
||||
void getStoreEmployeesReturnsOnlyStaffLinkedEmployees() {
|
||||
PetRepository petRepository = mock(PetRepository.class);
|
||||
CustomerRepository customerRepository = mock(CustomerRepository.class);
|
||||
CustomerPetRepository customerPetRepository = mock(CustomerPetRepository.class);
|
||||
ServiceRepository serviceRepository = mock(ServiceRepository.class);
|
||||
ProductRepository productRepository = mock(ProductRepository.class);
|
||||
CategoryRepository categoryRepository = mock(CategoryRepository.class);
|
||||
StoreRepository storeRepository = mock(StoreRepository.class);
|
||||
SupplierRepository supplierRepository = mock(SupplierRepository.class);
|
||||
EmployeeStoreRepository employeeStoreRepository = mock(EmployeeStoreRepository.class);
|
||||
UserRepository userRepository = mock(UserRepository.class);
|
||||
private PetRepository petRepository;
|
||||
private CustomerRepository customerRepository;
|
||||
private CustomerPetRepository customerPetRepository;
|
||||
private ServiceRepository serviceRepository;
|
||||
private ProductRepository productRepository;
|
||||
private CategoryRepository categoryRepository;
|
||||
private StoreRepository storeRepository;
|
||||
private SupplierRepository supplierRepository;
|
||||
private EmployeeStoreRepository employeeStoreRepository;
|
||||
private UserRepository userRepository;
|
||||
private DropdownController controller;
|
||||
|
||||
DropdownController controller = new DropdownController(
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
petRepository = mock(PetRepository.class);
|
||||
customerRepository = mock(CustomerRepository.class);
|
||||
customerPetRepository = mock(CustomerPetRepository.class);
|
||||
serviceRepository = mock(ServiceRepository.class);
|
||||
productRepository = mock(ProductRepository.class);
|
||||
categoryRepository = mock(CategoryRepository.class);
|
||||
storeRepository = mock(StoreRepository.class);
|
||||
supplierRepository = mock(SupplierRepository.class);
|
||||
employeeStoreRepository = mock(EmployeeStoreRepository.class);
|
||||
userRepository = mock(UserRepository.class);
|
||||
|
||||
controller = new DropdownController(
|
||||
petRepository,
|
||||
customerRepository,
|
||||
customerPetRepository,
|
||||
@@ -51,7 +68,25 @@ class DropdownControllerTest {
|
||||
employeeStoreRepository,
|
||||
userRepository
|
||||
);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
private void setAuthentication(Long userId, User.Role role) {
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new UsernamePasswordAuthenticationToken(
|
||||
new AppPrincipal(userId, "user", role, 0),
|
||||
null,
|
||||
List.of()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getStoreEmployeesReturnsBothStaffAndAdminLinkedEmployees() {
|
||||
StoreLocation store = new StoreLocation();
|
||||
store.setStoreId(1L);
|
||||
|
||||
@@ -86,37 +121,13 @@ class DropdownControllerTest {
|
||||
|
||||
var response = controller.getStoreEmployees(1L);
|
||||
|
||||
assertEquals(1, response.getBody().size());
|
||||
assertEquals(2, response.getBody().size());
|
||||
assertEquals(Long.valueOf(7L), response.getBody().get(0).getId());
|
||||
assertEquals("Alex Jones", response.getBody().get(0).getLabel());
|
||||
assertEquals(Long.valueOf(8L), response.getBody().get(1).getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getStoreEmployeesExcludesInactiveStaffUsers() {
|
||||
PetRepository petRepository = mock(PetRepository.class);
|
||||
CustomerRepository customerRepository = mock(CustomerRepository.class);
|
||||
CustomerPetRepository customerPetRepository = mock(CustomerPetRepository.class);
|
||||
ServiceRepository serviceRepository = mock(ServiceRepository.class);
|
||||
ProductRepository productRepository = mock(ProductRepository.class);
|
||||
CategoryRepository categoryRepository = mock(CategoryRepository.class);
|
||||
StoreRepository storeRepository = mock(StoreRepository.class);
|
||||
SupplierRepository supplierRepository = mock(SupplierRepository.class);
|
||||
EmployeeStoreRepository employeeStoreRepository = mock(EmployeeStoreRepository.class);
|
||||
UserRepository userRepository = mock(UserRepository.class);
|
||||
|
||||
DropdownController controller = new DropdownController(
|
||||
petRepository,
|
||||
customerRepository,
|
||||
customerPetRepository,
|
||||
serviceRepository,
|
||||
productRepository,
|
||||
categoryRepository,
|
||||
storeRepository,
|
||||
supplierRepository,
|
||||
employeeStoreRepository,
|
||||
userRepository
|
||||
);
|
||||
|
||||
StoreLocation store = new StoreLocation();
|
||||
store.setStoreId(1L);
|
||||
|
||||
@@ -142,30 +153,33 @@ class DropdownControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAppointmentCustomersReturnsOnlyCustomersWithPets() {
|
||||
PetRepository petRepository = mock(PetRepository.class);
|
||||
CustomerRepository customerRepository = mock(CustomerRepository.class);
|
||||
CustomerPetRepository customerPetRepository = mock(CustomerPetRepository.class);
|
||||
ServiceRepository serviceRepository = mock(ServiceRepository.class);
|
||||
ProductRepository productRepository = mock(ProductRepository.class);
|
||||
CategoryRepository categoryRepository = mock(CategoryRepository.class);
|
||||
StoreRepository storeRepository = mock(StoreRepository.class);
|
||||
SupplierRepository supplierRepository = mock(SupplierRepository.class);
|
||||
EmployeeStoreRepository employeeStoreRepository = mock(EmployeeStoreRepository.class);
|
||||
UserRepository userRepository = mock(UserRepository.class);
|
||||
void getAppointmentCustomersReturnsOnlyCustomersWithPetsForStaff() {
|
||||
User staffUser = new User();
|
||||
staffUser.setId(99L);
|
||||
staffUser.setRole(User.Role.STAFF);
|
||||
when(userRepository.findById(99L)).thenReturn(Optional.of(staffUser));
|
||||
setAuthentication(99L, User.Role.STAFF);
|
||||
|
||||
DropdownController controller = new DropdownController(
|
||||
petRepository,
|
||||
customerRepository,
|
||||
customerPetRepository,
|
||||
serviceRepository,
|
||||
productRepository,
|
||||
categoryRepository,
|
||||
storeRepository,
|
||||
supplierRepository,
|
||||
employeeStoreRepository,
|
||||
userRepository
|
||||
);
|
||||
Customer one = new Customer();
|
||||
one.setCustomerId(1L);
|
||||
one.setFirstName("Alex");
|
||||
one.setLastName("Brown");
|
||||
|
||||
when(customerRepository.findAllWithPets()).thenReturn(List.of(one));
|
||||
|
||||
var response = controller.getAppointmentCustomers();
|
||||
|
||||
assertEquals(1, response.getBody().size());
|
||||
assertEquals(Long.valueOf(1L), response.getBody().get(0).getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getAppointmentCustomersReturnsAllCustomersForAdmin() {
|
||||
User adminUser = new User();
|
||||
adminUser.setId(88L);
|
||||
adminUser.setRole(User.Role.ADMIN);
|
||||
when(userRepository.findById(88L)).thenReturn(Optional.of(adminUser));
|
||||
setAuthentication(88L, User.Role.ADMIN);
|
||||
|
||||
Customer one = new Customer();
|
||||
one.setCustomerId(1L);
|
||||
@@ -177,12 +191,12 @@ class DropdownControllerTest {
|
||||
two.setFirstName("Emily");
|
||||
two.setLastName("Clark");
|
||||
|
||||
when(customerRepository.findAllWithPets()).thenReturn(List.of(one, two));
|
||||
when(customerRepository.findAll()).thenReturn(List.of(one, two));
|
||||
|
||||
var response = controller.getAppointmentCustomers();
|
||||
|
||||
assertEquals(2, response.getBody().size());
|
||||
assertEquals(Long.valueOf(1L), response.getBody().get(0).getId());
|
||||
assertEquals("Alex Brown", response.getBody().get(0).getLabel());
|
||||
assertEquals(Long.valueOf(2L), response.getBody().get(1).getId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,10 +87,11 @@ class AdoptionServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void createAdoptionAutoAssignsFirstStaffEmployee() {
|
||||
void createAdoptionAutoAssignsFirstAssignableEmployee() {
|
||||
when(petRepository.findById(1L)).thenReturn(Optional.of(pet));
|
||||
when(customerRepository.findById(1L)).thenReturn(Optional.of(customer));
|
||||
when(employeeRepository.findAllByIsActiveTrueOrderByEmployeeIdAsc()).thenReturn(List.of(adminEmployee, staffEmployee));
|
||||
// resolveAdoptionEmployee uses the first one from the list returned by repo
|
||||
when(employeeRepository.findAllByIsActiveTrueOrderByEmployeeIdAsc()).thenReturn(List.of(staffEmployee, adminEmployee));
|
||||
when(adoptionRepository.save(any(Adoption.class))).thenAnswer(invocation -> {
|
||||
Adoption adoption = invocation.getArgument(0);
|
||||
adoption.setAdoptionId(10L);
|
||||
@@ -110,10 +111,15 @@ class AdoptionServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void createAdoptionRejectsAdminEmployeeSelection() {
|
||||
void createAdoptionAllowsAdminEmployeeSelection() {
|
||||
when(petRepository.findById(1L)).thenReturn(Optional.of(pet));
|
||||
when(customerRepository.findById(1L)).thenReturn(Optional.of(customer));
|
||||
when(employeeRepository.findById(8L)).thenReturn(Optional.of(adminEmployee));
|
||||
when(adoptionRepository.save(any(Adoption.class))).thenAnswer(invocation -> {
|
||||
Adoption adoption = invocation.getArgument(0);
|
||||
adoption.setAdoptionId(10L);
|
||||
return adoption;
|
||||
});
|
||||
|
||||
AdoptionRequest request = new AdoptionRequest();
|
||||
request.setPetId(1L);
|
||||
@@ -122,7 +128,9 @@ class AdoptionServiceTest {
|
||||
request.setAdoptionDate(LocalDate.now());
|
||||
request.setAdoptionStatus("Pending");
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> adoptionService.createAdoption(request));
|
||||
var response = adoptionService.createAdoption(request);
|
||||
|
||||
assertEquals(8L, response.getEmployeeId());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.petshop.backend.repository.PetRepository;
|
||||
import com.petshop.backend.repository.ServiceRepository;
|
||||
import com.petshop.backend.repository.StoreRepository;
|
||||
import com.petshop.backend.repository.UserRepository;
|
||||
import com.petshop.backend.security.AppPrincipal;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -41,39 +42,22 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
class AppointmentServiceTest {
|
||||
|
||||
@Mock
|
||||
private AppointmentRepository appointmentRepository;
|
||||
|
||||
@Mock
|
||||
private CustomerRepository customerRepository;
|
||||
|
||||
@Mock
|
||||
private CustomerPetRepository customerPetRepository;
|
||||
|
||||
@Mock
|
||||
private PetRepository petRepository;
|
||||
|
||||
@Mock
|
||||
private ServiceRepository serviceRepository;
|
||||
|
||||
@Mock
|
||||
private StoreRepository storeRepository;
|
||||
|
||||
@Mock
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Mock
|
||||
private EmployeeRepository employeeRepository;
|
||||
|
||||
@Mock
|
||||
private EmployeeStoreRepository employeeStoreRepository;
|
||||
@Mock private AppointmentRepository appointmentRepository;
|
||||
@Mock private CustomerRepository customerRepository;
|
||||
@Mock private CustomerPetRepository customerPetRepository;
|
||||
@Mock private ServiceRepository serviceRepository;
|
||||
@Mock private PetRepository petRepository;
|
||||
@Mock private StoreRepository storeRepository;
|
||||
@Mock private UserRepository userRepository;
|
||||
@Mock private EmployeeRepository employeeRepository;
|
||||
@Mock private EmployeeStoreRepository employeeStoreRepository;
|
||||
|
||||
@InjectMocks
|
||||
private AppointmentService appointmentService;
|
||||
@@ -89,6 +73,13 @@ class AppointmentServiceTest {
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
setAuthentication(99L, User.Role.ADMIN);
|
||||
User adminUser = new User();
|
||||
adminUser.setId(99L);
|
||||
adminUser.setRole(User.Role.ADMIN);
|
||||
adminUser.setActive(true);
|
||||
when(userRepository.findById(99L)).thenReturn(Optional.of(adminUser));
|
||||
|
||||
customer = new Customer();
|
||||
customer.setCustomerId(1L);
|
||||
customer.setFirstName("Pat");
|
||||
@@ -131,7 +122,6 @@ class AppointmentServiceTest {
|
||||
when(userRepository.findById(7L)).thenReturn(Optional.of(staffUser));
|
||||
|
||||
date = LocalDate.now().plusDays(1);
|
||||
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
@@ -164,62 +154,10 @@ class AppointmentServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void cancelledAppointmentsDoNotBlockAvailability() {
|
||||
when(storeRepository.findById(1L)).thenReturn(Optional.of(store));
|
||||
when(serviceRepository.findById(1L)).thenReturn(Optional.of(grooming));
|
||||
when(appointmentRepository.findByStoreAndDate(1L, date)).thenReturn(List.of());
|
||||
|
||||
List<String> slots = appointmentService.checkAvailability(1L, 1L, date);
|
||||
|
||||
assertTrue(slots.contains("10:00"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateAppointmentDoesNotConflictWithItself() {
|
||||
Appointment existing = appointment(1L, date, LocalTime.of(10, 0), grooming, store);
|
||||
User user = new User();
|
||||
user.setId(10L);
|
||||
user.setUsername("pat");
|
||||
user.setRole(User.Role.CUSTOMER);
|
||||
user.setTokenVersion(0);
|
||||
when(userRepository.findById(10L)).thenReturn(Optional.of(user));
|
||||
setAuthentication(10L, User.Role.CUSTOMER);
|
||||
|
||||
when(appointmentRepository.findById(1L)).thenReturn(Optional.of(existing));
|
||||
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(petRepository.findById(1L)).thenReturn(Optional.of(pet));
|
||||
when(employeeStoreRepository.findActiveByStoreStoreIdOrderByEmployeeEmployeeIdAsc(1L))
|
||||
.thenReturn(List.of(new EmployeeStore(employee, store)));
|
||||
when(appointmentRepository.findByStoreAndDate(1L, date)).thenReturn(List.of(existing));
|
||||
when(appointmentRepository.save(any(Appointment.class))).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
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.setPetIds(List.of(1L));
|
||||
|
||||
var response = appointmentService.updateAppointment(1L, request);
|
||||
|
||||
assertEquals(1L, response.getAppointmentId());
|
||||
assertEquals("Booked", response.getAppointmentStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
void createAppointmentRejectsCustomerPetOwnedByDifferentCustomer() {
|
||||
User adminUser = new User();
|
||||
adminUser.setId(99L);
|
||||
adminUser.setUsername("admin");
|
||||
adminUser.setRole(User.Role.ADMIN);
|
||||
adminUser.setActive(true);
|
||||
adminUser.setTokenVersion(0);
|
||||
when(userRepository.findById(99L)).thenReturn(Optional.of(adminUser));
|
||||
setAuthentication(99L, User.Role.ADMIN);
|
||||
void createAppointmentRejectsCustomerPetOwnedByDifferentCustomerForStaff() {
|
||||
setAuthentication(7L, User.Role.STAFF);
|
||||
when(employeeRepository.findByUserId(7L)).thenReturn(Optional.of(employee));
|
||||
when(employeeStoreRepository.findByEmployeeEmployeeId(7L)).thenReturn(Optional.of(new EmployeeStore(employee, store)));
|
||||
|
||||
Customer otherCustomer = new Customer();
|
||||
otherCustomer.setCustomerId(2L);
|
||||
@@ -250,26 +188,63 @@ class AppointmentServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void createAppointmentAllowsCustomerOwnedCustomerPet() {
|
||||
User adminUser = new User();
|
||||
adminUser.setId(99L);
|
||||
adminUser.setUsername("admin");
|
||||
adminUser.setRole(User.Role.ADMIN);
|
||||
adminUser.setActive(true);
|
||||
adminUser.setTokenVersion(0);
|
||||
when(userRepository.findById(99L)).thenReturn(Optional.of(adminUser));
|
||||
void createAppointmentAllowsCustomerPetOwnedByDifferentCustomerForAdmin() {
|
||||
setAuthentication(99L, User.Role.ADMIN);
|
||||
|
||||
Customer otherCustomer = new Customer();
|
||||
otherCustomer.setCustomerId(2L);
|
||||
|
||||
CustomerPet otherCustomerPet = new CustomerPet();
|
||||
otherCustomerPet.setCustomerPetId(22L);
|
||||
otherCustomerPet.setCustomer(otherCustomer);
|
||||
otherCustomerPet.setPetName("Not Yours");
|
||||
|
||||
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(11L)).thenReturn(Optional.of(customerPet));
|
||||
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();
|
||||
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());
|
||||
}
|
||||
|
||||
@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(99L);
|
||||
appointment.setAppointmentId(101L);
|
||||
return appointment;
|
||||
});
|
||||
|
||||
@@ -280,24 +255,19 @@ class AppointmentServiceTest {
|
||||
request.setAppointmentDate(date);
|
||||
request.setAppointmentTime(LocalTime.of(10, 0));
|
||||
request.setAppointmentStatus("Booked");
|
||||
request.setCustomerPetIds(List.of(11L));
|
||||
request.setCustomerPetIds(List.of(22L));
|
||||
|
||||
var response = appointmentService.createAppointment(request);
|
||||
|
||||
assertEquals(99L, response.getAppointmentId());
|
||||
assertEquals(101L, response.getAppointmentId());
|
||||
assertEquals(1L, response.getCustomerId());
|
||||
assertEquals(7L, response.getEmployeeId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void createAppointmentRejectsAdminEmployeeSelection() {
|
||||
User adminUser = new User();
|
||||
adminUser.setId(99L);
|
||||
adminUser.setUsername("admin");
|
||||
adminUser.setRole(User.Role.ADMIN);
|
||||
adminUser.setTokenVersion(0);
|
||||
when(userRepository.findById(99L)).thenReturn(Optional.of(adminUser));
|
||||
setAuthentication(99L, User.Role.ADMIN);
|
||||
void createAppointmentAllowsAdminEmployeeSelection() {
|
||||
setAuthentication(7L, User.Role.STAFF);
|
||||
when(employeeRepository.findByUserId(7L)).thenReturn(Optional.of(employee));
|
||||
when(employeeStoreRepository.findByEmployeeEmployeeId(7L)).thenReturn(Optional.of(new EmployeeStore(employee, store)));
|
||||
|
||||
Employee adminEmployee = new Employee();
|
||||
adminEmployee.setEmployeeId(8L);
|
||||
@@ -320,6 +290,11 @@ class AppointmentServiceTest {
|
||||
when(customerPetRepository.findById(11L)).thenReturn(Optional.of(customerPet));
|
||||
when(employeeStoreRepository.findActiveByStoreStoreIdOrderByEmployeeEmployeeIdAsc(1L))
|
||||
.thenReturn(List.of(new EmployeeStore(adminEmployee, store), new EmployeeStore(employee, store)));
|
||||
when(appointmentRepository.save(any(Appointment.class))).thenAnswer(invocation -> {
|
||||
Appointment appointment = invocation.getArgument(0);
|
||||
appointment.setAppointmentId(102L);
|
||||
return appointment;
|
||||
});
|
||||
|
||||
var request = new com.petshop.backend.dto.appointment.AppointmentRequest();
|
||||
request.setCustomerId(1L);
|
||||
@@ -331,19 +306,20 @@ class AppointmentServiceTest {
|
||||
request.setAppointmentStatus("Booked");
|
||||
request.setCustomerPetIds(List.of(11L));
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> appointmentService.createAppointment(request));
|
||||
var response = appointmentService.createAppointment(request);
|
||||
|
||||
assertEquals(102L, response.getAppointmentId());
|
||||
assertEquals(8L, response.getEmployeeId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void createAppointmentRejectsInactiveStaffUserSelection() {
|
||||
setAuthentication(99L, User.Role.ADMIN);
|
||||
User adminUser = new User();
|
||||
adminUser.setId(99L);
|
||||
adminUser.setUsername("admin");
|
||||
adminUser.setRole(User.Role.ADMIN);
|
||||
adminUser.setActive(true);
|
||||
adminUser.setTokenVersion(0);
|
||||
when(userRepository.findById(99L)).thenReturn(Optional.of(adminUser));
|
||||
setAuthentication(99L, User.Role.ADMIN);
|
||||
|
||||
User inactiveStaffUser = new User();
|
||||
inactiveStaffUser.setId(7L);
|
||||
@@ -384,13 +360,14 @@ class AppointmentServiceTest {
|
||||
appointment.setEmployee(employee);
|
||||
appointment.setCustomer(customer);
|
||||
appointment.setPets(Set.of());
|
||||
appointment.setCustomerPets(Set.of());
|
||||
return appointment;
|
||||
}
|
||||
|
||||
private void setAuthentication(Long userId, User.Role role) {
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new UsernamePasswordAuthenticationToken(
|
||||
new com.petshop.backend.security.AppPrincipal(userId, "user", role, 0),
|
||||
new AppPrincipal(userId, "user", role, 0),
|
||||
"n/a",
|
||||
List.of(new SimpleGrantedAuthority("ROLE_" + role.name()))
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user