Skip to content

Commit

Permalink
feat: tenant super admin can create consultants for a tenant and the …
Browse files Browse the repository at this point in the history
…licence for that tenant is respected
  • Loading branch information
patric-dosch-vi committed Mar 20, 2024
1 parent 8e8dded commit b5c4a8a
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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());
}
}

Expand Down Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ Page<ConsultantBase> findAllByInfixAndAgencyIds(

long countByDeleteDateIsNull();

long countByTenantIdAndDeleteDateIsNull(Long tenantId);

@Query(
value =
"SELECT DISTINCT c.rocketChatId "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -22,25 +23,23 @@
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;
import org.springframework.boot.test.context.SpringBootTest;
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)
Expand All @@ -66,6 +65,8 @@ public class CreateConsultantSagaTenantAwareIT {

@MockBean private KeycloakService keycloakService;

@MockBean private AuthenticatedUser authenticatedUser;

private final EasyRandom easyRandom = new EasyRandom();

@AfterEach
Expand All @@ -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();
}
Expand All @@ -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 =
Expand All @@ -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);
Expand All @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

0 comments on commit b5c4a8a

Please sign in to comment.