diff --git a/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/CreateConsultantSaga.java b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/CreateConsultantSaga.java index e66ea92bc..8f44b31a7 100644 --- a/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/CreateConsultantSaga.java +++ b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/CreateConsultantSaga.java @@ -4,6 +4,7 @@ import static de.caritas.cob.userservice.api.config.auth.UserRole.CONSULTANT; import static de.caritas.cob.userservice.api.config.auth.UserRole.GROUP_CHAT_CONSULTANT; import static de.caritas.cob.userservice.api.helper.json.JsonSerializationUtils.serializeToJsonString; +import static java.util.Objects.*; import static org.apache.commons.lang3.BooleanUtils.isTrue; import static org.hibernate.validator.internal.util.CollectionHelper.asSet; @@ -74,12 +75,16 @@ public class CreateConsultantSaga { private Consultant createNewConsultantWithoutAppointment( CreateConsultantDTO createConsultantDTO) { - assertLicensesNotExceeded(); + validateTenantId(createConsultantDTO); + setCurrentTenant(createConsultantDTO); + + assertLicensesNotExceeded(createConsultantDTO); + this.userAccountInputValidator.validateAbsence( new CreateConsultantDTOAbsenceInputAdapter(createConsultantDTO)); + ConsultantCreationInput consultantCreationInput = new CreateConsultantDTOCreationInputAdapter(createConsultantDTO); - assignCurrentTenantContext(createConsultantDTO); var roles = asSet(CONSULTANT.getValue()); addGroupChatConsultantRole(createConsultantDTO, roles); @@ -138,13 +143,15 @@ private void createConsultantInAppointmentServiceOrRollback( } private void validateTenantId(CreateConsultantDTO createConsultantDTO) { - if (authenticatedUser.isTenantSuperAdmin()) { - if (createConsultantDTO.getTenantId() == null) { - throw new BadRequestException( - "TenantId must be set if consultant is created by superadmin"); + if (multiTenancyEnabled) { + if (authenticatedUser.isTenantSuperAdmin()) { + if (createConsultantDTO.getTenantId() == null) { + throw new BadRequestException( + "TenantId must be set if consultant is created by superadmin"); + } + } else { + checkIfTenantIdMatch(createConsultantDTO); } - } else { - checkIfTenantIdMatch(createConsultantDTO); } } @@ -261,12 +268,10 @@ private Consultant createConsultantInMariaDBOrRollback( } } - private void assignCurrentTenantContext(CreateConsultantDTO createConsultantDTO) { - if (multiTenancyEnabled) { - validateTenantId(createConsultantDTO); - if (!authenticatedUser.isTenantSuperAdmin() && createConsultantDTO.getTenantId() == null) { - createConsultantDTO.setTenantId(TenantContext.getCurrentTenant()); - } + private void setCurrentTenant(CreateConsultantDTO createConsultantDTO) { + if (multiTenancyEnabled + && (!authenticatedUser.isTenantSuperAdmin() && createConsultantDTO.getTenantId() == null)) { + createConsultantDTO.setTenantId(TenantContext.getCurrentTenant()); } } @@ -376,10 +381,15 @@ private UserDTO buildUserDTO(String username, String email, Long tenantId) { return userDto; } - private void assertLicensesNotExceeded() { + private void assertLicensesNotExceeded(CreateConsultantDTO createConsultantDTO) { if (multiTenancyEnabled) { - TenantDTO tenantById = tenantAdminService.getTenantById(TenantContext.getCurrentTenant()); - long numberOfActiveConsultants = consultantService.getNumberOfActiveConsultants(); + TenantDTO tenantById = tenantAdminService.getTenantById(createConsultantDTO.getTenantId()); + long numberOfActiveConsultants = + authenticatedUser.isTenantSuperAdmin() + ? consultantService.getNumberOfActiveConsultants(createConsultantDTO.getTenantId()) + : consultantService.getNumberOfActiveConsultants(); + + assert nonNull(tenantById.getLicensing()); Integer allowedNumberOfUsers = tenantById.getLicensing().getAllowedNumberOfUsers(); if (numberOfActiveConsultants >= allowedNumberOfUsers) { throw new CustomValidationHttpStatusException( diff --git a/src/main/java/de/caritas/cob/userservice/api/port/out/ConsultantRepository.java b/src/main/java/de/caritas/cob/userservice/api/port/out/ConsultantRepository.java index 567762642..10eea197c 100644 --- a/src/main/java/de/caritas/cob/userservice/api/port/out/ConsultantRepository.java +++ b/src/main/java/de/caritas/cob/userservice/api/port/out/ConsultantRepository.java @@ -64,6 +64,8 @@ Page findAllByInfixAndAgencyIds( long countByDeleteDateIsNull(); + long countByTenantIdAndDeleteDateIsNull(Long tenantId); + @Query( value = "SELECT DISTINCT c.rocketChatId " diff --git a/src/main/java/de/caritas/cob/userservice/api/service/ConsultantService.java b/src/main/java/de/caritas/cob/userservice/api/service/ConsultantService.java index d41139f57..131e5dbed 100644 --- a/src/main/java/de/caritas/cob/userservice/api/service/ConsultantService.java +++ b/src/main/java/de/caritas/cob/userservice/api/service/ConsultantService.java @@ -153,6 +153,10 @@ public long getNumberOfActiveConsultants() { return consultantRepository.countByDeleteDateIsNull(); } + public long getNumberOfActiveConsultants(Long tenantId) { + return consultantRepository.countByTenantIdAndDeleteDateIsNull(tenantId); + } + private void addConsultantToken(Consultant consultant, String mobileToken) { verifyTokenDoesNotAlreadyExist(mobileToken); var consultantMobileToken = new ConsultantMobileToken(); diff --git a/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/create/CreateConsultantSagaTenantAwareIT.java b/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/create/CreateConsultantSagaTenantAwareIT.java index 2624605f1..6e88116b6 100644 --- a/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/create/CreateConsultantSagaTenantAwareIT.java +++ b/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/create/CreateConsultantSagaTenantAwareIT.java @@ -8,6 +8,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -22,17 +23,16 @@ import de.caritas.cob.userservice.api.admin.service.tenant.TenantAdminService; import de.caritas.cob.userservice.api.exception.httpresponses.CustomValidationHttpStatusException; import de.caritas.cob.userservice.api.exception.rocketchat.RocketChatLoginException; +import de.caritas.cob.userservice.api.helper.AuthenticatedUser; import de.caritas.cob.userservice.api.model.Consultant; import de.caritas.cob.userservice.api.port.out.ConsultantRepository; import de.caritas.cob.userservice.api.tenant.TenantContext; -import de.caritas.cob.userservice.api.tenant.TenantData; import de.caritas.cob.userservice.tenantadminservice.generated.web.model.Licensing; import de.caritas.cob.userservice.tenantadminservice.generated.web.model.TenantDTO; import org.jeasy.random.EasyRandom; import org.junit.Test; import org.junit.jupiter.api.AfterEach; import org.junit.runner.RunWith; -import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace; @@ -40,7 +40,6 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.util.ReflectionTestUtils; import org.springframework.transaction.annotation.Transactional; @RunWith(SpringRunner.class) @@ -66,6 +65,8 @@ public class CreateConsultantSagaTenantAwareIT { @MockBean private KeycloakService keycloakService; + @MockBean private AuthenticatedUser authenticatedUser; + private final EasyRandom easyRandom = new EasyRandom(); @AfterEach @@ -77,10 +78,36 @@ public void tearDown() { public void createNewConsultant_Should_throwCustomValidationHttpStatusException_When_LicensesAreExceeded() { // given - givenTenantApiCall(); - createConsultant("username1"); - createConsultant("username2"); + TenantContext.setCurrentTenant(1L); + var tenant = new TenantDTO().licensing(new Licensing().allowedNumberOfUsers(2)); + when(tenantAdminService.getTenantById(anyLong())).thenReturn(tenant); + + createConsultant(1L, "username1"); + createConsultant(1L, "username2"); CreateConsultantDTO createConsultantDTO = this.easyRandom.nextObject(CreateConsultantDTO.class); + createConsultantDTO.setTenantId(null); + + // when, then + this.createConsultantSaga.createNewConsultant(createConsultantDTO); + rollbackDBState(); + } + + @Test(expected = CustomValidationHttpStatusException.class) + public void + createNewConsultant_Should_throwCustomValidationHttpStatusException_When_userIsSuperAdminAndLicensesAreExceededForGivenTenant() { + // given + TenantContext.setCurrentTenant(0L); + var tenant = new TenantDTO().licensing(new Licensing().allowedNumberOfUsers(2)); + when(tenantAdminService.getTenantById(anyLong())).thenReturn(tenant); + + when(authenticatedUser.isTenantSuperAdmin()).thenReturn(true); + + createConsultant(2L, "username1"); + createConsultant(2L, "username2"); + CreateConsultantDTO createConsultantDTO = this.easyRandom.nextObject(CreateConsultantDTO.class); + createConsultantDTO.setTenantId(2L); + + // when, then this.createConsultantSaga.createNewConsultant(createConsultantDTO); rollbackDBState(); } @@ -101,14 +128,13 @@ public void tearDown() { .settings( new de.caritas.cob.userservice.tenantadminservice.generated.web.model.Settings() .featureGroupChatV2Enabled(false)); - when(tenantAdminService.getTenantById(Mockito.anyLong())).thenReturn(tenant); + when(tenantAdminService.getTenantById(anyLong())).thenReturn(tenant); CreateConsultantDTO createConsultantDTO = this.easyRandom.nextObject(CreateConsultantDTO.class); createConsultantDTO.setTenantId(TENANT_ID); createConsultantDTO.setUsername(VALID_USERNAME); createConsultantDTO.setEmail(VALID_EMAILADDRESS); createConsultantDTO.setIsGroupchatConsultant(true); - createConsultantDTO.setTenantId(1L); // when ConsultantAdminResponseDTO consultant = @@ -123,10 +149,10 @@ public void tearDown() { assertThat(consultant.getEmbedded().getId(), notNullValue()); } - private void createConsultant(String username) { + private void createConsultant(Long tenantId, String username) { Consultant consultant = new Consultant(); consultant.setAppointments(null); - consultant.setTenantId(1L); + consultant.setTenantId(tenantId); consultant.setId(username); consultant.setRocketChatId(username); consultant.setUsername(username); @@ -151,16 +177,4 @@ private void rollbackDBState() { consultantRepository.saveAll(all); TenantContext.clear(); } - - private void givenTenantApiCall() { - var currentTenant = new TenantData(1L, "testdomain"); - TenantContext.setCurrentTenantData(currentTenant); - var dummyTenant = new TenantDTO(); - var licensing = new Licensing(); - licensing.setAllowedNumberOfUsers(2); - dummyTenant.setLicensing(licensing); - ReflectionTestUtils.setField(createConsultantSaga, "tenantAdminService", tenantAdminService); - when(tenantAdminService.getTenantById(TenantContext.getCurrentTenant())) - .thenReturn(dummyTenant); - } } diff --git a/src/test/java/de/caritas/cob/userservice/api/service/ConsultantServiceTest.java b/src/test/java/de/caritas/cob/userservice/api/service/ConsultantServiceTest.java index f14de2da5..148d2cee2 100644 --- a/src/test/java/de/caritas/cob/userservice/api/service/ConsultantServiceTest.java +++ b/src/test/java/de/caritas/cob/userservice/api/service/ConsultantServiceTest.java @@ -203,45 +203,64 @@ void findConsultantsByAgencyId_Should_ReturnListOfConsultants() { @ParameterizedTest @NullAndEmptySource void addMobileAppToken_Should_callNoOtherMethods_When_mobileTokenIsNullOrEmpty(String token) { - this.consultantService.addMobileAppToken(null, token); + consultantService.addMobileAppToken(null, token); - verifyNoMoreInteractions(this.consultantMobileTokenRepository); - verifyNoMoreInteractions(this.consultantRepository); + verifyNoMoreInteractions(consultantMobileTokenRepository); + verifyNoMoreInteractions(consultantRepository); } @Test void addMobileAppToken_Should_callNoOtherMethods_When_consultantDoesNotExist() { - when(this.consultantRepository.findByIdAndDeleteDateIsNull(any())).thenReturn(Optional.empty()); + when(consultantRepository.findByIdAndDeleteDateIsNull(any())).thenReturn(Optional.empty()); - this.consultantService.addMobileAppToken("id", "token"); + consultantService.addMobileAppToken("id", "token"); - verifyNoMoreInteractions(this.consultantMobileTokenRepository); - verifyNoMoreInteractions(this.consultantRepository); + verifyNoMoreInteractions(consultantMobileTokenRepository); + verifyNoMoreInteractions(consultantRepository); } @Test void addMobileAppToken_Should_addMobileTokenToConsultant_When_consultantExists() { var consultant = new EasyRandom().nextObject(Consultant.class); consultant.getConsultantMobileTokens().clear(); - when(this.consultantRepository.findByIdAndDeleteDateIsNull(any())) + when(consultantRepository.findByIdAndDeleteDateIsNull(any())) .thenReturn(Optional.of(consultant)); - this.consultantService.addMobileAppToken("id", "token"); + consultantService.addMobileAppToken("id", "token"); - verify(this.consultantMobileTokenRepository, times(1)).findByMobileAppToken("token"); - verify(this.consultantMobileTokenRepository, times(1)).save(any()); + verify(consultantMobileTokenRepository, times(1)).findByMobileAppToken("token"); + verify(consultantMobileTokenRepository, times(1)).save(any()); assertThat(consultant.getConsultantMobileTokens(), hasSize(1)); } @Test void addMobileAppToken_Should_throwConflictException_When_tokenAlreadyExists() { var consultant = new EasyRandom().nextObject(Consultant.class); - when(this.consultantRepository.findByIdAndDeleteDateIsNull(any())) + when(consultantRepository.findByIdAndDeleteDateIsNull(any())) .thenReturn(Optional.of(consultant)); - when(this.consultantMobileTokenRepository.findByMobileAppToken(any())) + when(consultantMobileTokenRepository.findByMobileAppToken(any())) .thenReturn(Optional.of(new ConsultantMobileToken())); - assertThrows( - ConflictException.class, () -> this.consultantService.addMobileAppToken("id", "token")); + assertThrows(ConflictException.class, () -> consultantService.addMobileAppToken("id", "token")); + } + + @Test + void getNumberOfActiveConsultants_Should_ReturnNumberOfActiveConsultants() { + when(consultantRepository.countByDeleteDateIsNull()).thenReturn(1L); + + var result = consultantService.getNumberOfActiveConsultants(); + + verify(consultantRepository).countByDeleteDateIsNull(); + assertEquals(1L, result); + } + + @Test + void getNumberOfActiveConsultantsByTenantId_Should_ReturnNumberOfActiveConsultants() { + when(consultantRepository.countByTenantIdAndDeleteDateIsNull(1L)).thenReturn(1L); + + var result = consultantService.getNumberOfActiveConsultants(1L); + + verify(consultantRepository).countByTenantIdAndDeleteDateIsNull(1L); + assertEquals(1L, result); } }