diff --git a/api/useradminservice.yaml b/api/useradminservice.yaml index bcefd21b2..ae135e202 100644 --- a/api/useradminservice.yaml +++ b/api/useradminservice.yaml @@ -80,7 +80,7 @@ paths: content: 'application/hal+json': schema: - $ref: '#/components/schemas/CreateConsultantResponseDTO' + $ref: '#/components/schemas/ConsultantAdminResponseDTO' 400: description: BAD REQUEST - invalid/incomplete request or body object 401: @@ -108,7 +108,7 @@ paths: content: 'application/json': schema: - $ref: '#/components/schemas/GetConsultantResponseDTO' + $ref: '#/components/schemas/ConsultantAdminResponseDTO' 204: description: NO CONTENT - consultant with the specific id was not found 400: @@ -143,7 +143,7 @@ paths: content: 'application/json': schema: - $ref: '#/components/schemas/UpdateConsultantResponseDTO' + $ref: '#/components/schemas/ConsultantAdminResponseDTO' 400: description: BAD REQUEST - invalid/incomplete request 401: @@ -386,6 +386,8 @@ components: $ref: '#/components/schemas/HalLink' consultants: $ref: '#/components/schemas/HalLink' + createConsultant: + $ref: '#/components/schemas/HalLink' HalLink: type: object @@ -631,29 +633,13 @@ components: deleteDate: type: string - CreateConsultantResponseDTO: + ConsultantAdminResponseDTO: type: object properties: _embedded: $ref: '#/components/schemas/ConsultantDTO' _links: - $ref: '#/components/schemas/CreateLinks' - - GetConsultantResponseDTO: - type: object - properties: - _embedded: - $ref: '#/components/schemas/ConsultantDTO' - _links: - $ref: '#/components/schemas/GetLinks' - - UpdateConsultantResponseDTO: - type: object - properties: - _embedded: - $ref: '#/components/schemas/ConsultantDTO' - _links: - $ref: '#/components/schemas/UpdateLinks' + $ref: '#/components/schemas/ConsultantLinks' ConsultantSearchResultDTO: type: object @@ -661,11 +647,11 @@ components: _embedded: type: array items: - $ref: '#/components/schemas/ConsultantDTO' + $ref: '#/components/schemas/ConsultantAdminResponseDTO' _links: $ref: '#/components/schemas/PaginationLinks' - CreateLinks: + ConsultantLinks: type: object required: - self @@ -676,29 +662,9 @@ components: $ref: '#/components/schemas/HalLink' delete: $ref: '#/components/schemas/HalLink' - - GetLinks: - type: object - required: - - self - properties: - self: - $ref: '#/components/schemas/HalLink' - update: - $ref: '#/components/schemas/HalLink' - delete: - $ref: '#/components/schemas/HalLink' - - UpdateLinks: - type: object - required: - - self - properties: - self: - $ref: '#/components/schemas/HalLink' - consultant: + agencies: $ref: '#/components/schemas/HalLink' - delete: + addAgency: $ref: '#/components/schemas/HalLink' SessionFilter: diff --git a/src/main/java/de/caritas/cob/userservice/api/ApiResponseEntityExceptionHandler.java b/src/main/java/de/caritas/cob/userservice/api/ApiResponseEntityExceptionHandler.java index f54f728d9..9fa487746 100644 --- a/src/main/java/de/caritas/cob/userservice/api/ApiResponseEntityExceptionHandler.java +++ b/src/main/java/de/caritas/cob/userservice/api/ApiResponseEntityExceptionHandler.java @@ -4,6 +4,7 @@ import de.caritas.cob.userservice.api.exception.NoMasterKeyException; import de.caritas.cob.userservice.api.exception.httpresponses.BadRequestException; import de.caritas.cob.userservice.api.exception.httpresponses.ConflictException; +import de.caritas.cob.userservice.api.exception.httpresponses.CustomValidationHttpStatusException; import de.caritas.cob.userservice.api.exception.httpresponses.ForbiddenException; import de.caritas.cob.userservice.api.exception.httpresponses.InternalServerErrorException; import de.caritas.cob.userservice.api.exception.httpresponses.NoContentException; @@ -38,7 +39,10 @@ public class ApiResponseEntityExceptionHandler extends ResponseEntityExceptionHandler { /** - * Custom BadRequest exception + * Custom BadRequest exception. + * + * @param request the invoking request + * @param ex the thrown exception */ @ExceptionHandler({BadRequestException.class}) public ResponseEntity handleCustomBadRequest(final BadRequestException ex, @@ -49,7 +53,25 @@ public ResponseEntity handleCustomBadRequest(final BadRequestException e } /** - * Constraint violations + * Custom BadRequest exception with header reason. + * + * @param request the invoking request + * @param ex the thrown exception + */ + @ExceptionHandler({CustomValidationHttpStatusException.class}) + public ResponseEntity handleCustomBadRequest(final CustomValidationHttpStatusException ex, + final WebRequest request) { + ex.executeLogging(); + + return handleExceptionInternal(ex, null, ex.getCustomHttpHeader(), HttpStatus.BAD_REQUEST, + request); + } + + /** + * Constraint violations. + * + * @param request the invoking request + * @param ex the thrown exception */ @ExceptionHandler(ConstraintViolationException.class) public ResponseEntity handleBadRequest(final RuntimeException ex, @@ -60,7 +82,10 @@ public ResponseEntity handleBadRequest(final RuntimeException ex, } /** - * Incoming request body could not be deserialized + * Incoming request body could not be deserialized. + * + * @param request the invoking request + * @param ex the thrown exception */ @Override protected ResponseEntity handleHttpMessageNotReadable( @@ -72,7 +97,10 @@ protected ResponseEntity handleHttpMessageNotReadable( } /** - * @Valid on object fails validation + * On object fails validation. + * + * @param request the invoking request + * @param ex the thrown exception */ @Override protected ResponseEntity handleMethodArgumentNotValid( @@ -84,7 +112,7 @@ protected ResponseEntity handleMethodArgumentNotValid( } /** - * 401 - Unauthorized + * 401 - Unauthorized. * * @param ex {@link UnauthorizedException} * @param request {@link WebRequest} @@ -99,7 +127,10 @@ public ResponseEntity handleUnauthorized(final UnauthorizedException ex, } /** - * 409 - Conflict + * 409 - Conflict. + * + * @param request the invoking request + * @param ex the thrown exception */ @ExceptionHandler({InvalidDataAccessApiUsageException.class, DataAccessException.class}) protected ResponseEntity handleConflict(final RuntimeException ex, @@ -110,7 +141,10 @@ protected ResponseEntity handleConflict(final RuntimeException ex, } /** - * 409 - Conflict + * 409 - Conflict. + * + * @param request the invoking request + * @param ex the thrown exception */ @ExceptionHandler({ConflictException.class}) protected ResponseEntity handleCustomConflict(final ConflictException ex, @@ -121,7 +155,10 @@ protected ResponseEntity handleCustomConflict(final ConflictException ex } /** - * 403 - Forbidden + * 403 - Forbidden. + * + * @param request the invoking request + * @param ex the thrown exception */ @ExceptionHandler({ForbiddenException.class}) public ResponseEntity handleForbidden(final ForbiddenException ex, @@ -132,7 +169,10 @@ public ResponseEntity handleForbidden(final ForbiddenException ex, } /** - * 404 - Not Found + * 404 - Not Found. + * + * @param request the invoking request + * @param ex the thrown exception */ @ExceptionHandler({NotFoundException.class}) public ResponseEntity handleForbidden(final NotFoundException ex, @@ -143,7 +183,10 @@ public ResponseEntity handleForbidden(final NotFoundException ex, } /** - * 500 - Internal Server Error + * 500 - Internal Server Error. + * + * @param request the invoking request + * @param ex the thrown exception */ @ExceptionHandler({NullPointerException.class, IllegalArgumentException.class, IllegalStateException.class, KeycloakException.class, @@ -157,7 +200,10 @@ public ResponseEntity handleInternal(final RuntimeException ex, } /** - * 500 - Custom Internal Server Error + * 500 - Custom Internal Server Error. + * + * @param request the invoking request + * @param ex the thrown exception */ @ExceptionHandler({InternalServerErrorException.class}) public ResponseEntity handleInternal(final InternalServerErrorException ex, @@ -169,7 +215,10 @@ public ResponseEntity handleInternal(final InternalServerErrorException } /** - * 204 - No Content + * 204 - No Content. + * + * @param request the invoking request + * @param ex the thrown exception */ @ExceptionHandler({NoContentException.class}) public ResponseEntity handleInternal(final NoContentException ex, diff --git a/src/main/java/de/caritas/cob/userservice/api/admin/controller/UserAdminController.java b/src/main/java/de/caritas/cob/userservice/api/admin/controller/UserAdminController.java index f498a48b1..c983b41c9 100644 --- a/src/main/java/de/caritas/cob/userservice/api/admin/controller/UserAdminController.java +++ b/src/main/java/de/caritas/cob/userservice/api/admin/controller/UserAdminController.java @@ -5,18 +5,16 @@ import de.caritas.cob.userservice.api.admin.report.service.ViolationReportGenerator; import de.caritas.cob.userservice.api.admin.service.ConsultingTypeAdminService; import de.caritas.cob.userservice.api.admin.service.session.SessionAdminService; +import de.caritas.cob.userservice.api.model.ConsultantAdminResponseDTO; import de.caritas.cob.userservice.api.model.ConsultantAgencyAdminResultDTO; import de.caritas.cob.userservice.api.model.ConsultantFilter; import de.caritas.cob.userservice.api.model.ConsultantSearchResultDTO; import de.caritas.cob.userservice.api.model.ConsultingTypeAdminResultDTO; import de.caritas.cob.userservice.api.model.CreateConsultantDTO; -import de.caritas.cob.userservice.api.model.CreateConsultantResponseDTO; -import de.caritas.cob.userservice.api.model.GetConsultantResponseDTO; import de.caritas.cob.userservice.api.model.RootDTO; import de.caritas.cob.userservice.api.model.SessionAdminResultDTO; import de.caritas.cob.userservice.api.model.SessionFilter; import de.caritas.cob.userservice.api.model.UpdateConsultantDTO; -import de.caritas.cob.userservice.api.model.UpdateConsultantResponseDTO; import de.caritas.cob.userservice.api.model.ViolationDTO; import de.caritas.cob.userservice.generated.api.admin.controller.UseradminApi; import io.swagger.annotations.Api; @@ -89,12 +87,12 @@ public ResponseEntity getConsultingTypes( * Entry point to create a new consultant. * * @param createConsultantDTO (required) - * @return {@link CreateConsultantResponseDTO} + * @return {@link ConsultantAdminResponseDTO} */ @Override - public ResponseEntity createConsultant( + public ResponseEntity createConsultant( @Valid CreateConsultantDTO createConsultantDTO) { - return null; + return ResponseEntity.ok(this.consultantAdminFacade.createNewConsultant(createConsultantDTO)); } /** @@ -125,10 +123,10 @@ public ResponseEntity markConsultantForDeletion(@PathVariable String consu * * @param consultantId consultant id (required) * @param updateConsultantDTO (required) - * @return {@link UpdateConsultantResponseDTO} + * @return {@link ConsultantAdminResponseDTO} */ @Override - public ResponseEntity updateConsultant( + public ResponseEntity updateConsultant( @PathVariable String consultantId, @Valid UpdateConsultantDTO updateConsultantDTO) { return null; } @@ -137,11 +135,11 @@ public ResponseEntity updateConsultant( * Entry point to get a specific consultant. * * @param consultantId consultant id (required) - * @return {@link GetConsultantResponseDTO} + * @return {@link ConsultantAdminResponseDTO} */ @Override - public ResponseEntity getConsultant(String consultantId) { - GetConsultantResponseDTO responseDTO = this.consultantAdminFacade.findConsultant(consultantId); + public ResponseEntity getConsultant(String consultantId) { + ConsultantAdminResponseDTO responseDTO = this.consultantAdminFacade.findConsultant(consultantId); return ResponseEntity.ok(responseDTO); } diff --git a/src/main/java/de/caritas/cob/userservice/api/admin/facade/ConsultantAdminFacade.java b/src/main/java/de/caritas/cob/userservice/api/admin/facade/ConsultantAdminFacade.java index 996d59a3b..734d267ad 100644 --- a/src/main/java/de/caritas/cob/userservice/api/admin/facade/ConsultantAdminFacade.java +++ b/src/main/java/de/caritas/cob/userservice/api/admin/facade/ConsultantAdminFacade.java @@ -4,9 +4,12 @@ import de.caritas.cob.userservice.api.admin.service.consultant.ConsultantAdminFilterService; import de.caritas.cob.userservice.api.admin.service.consultant.ConsultantAdminService; import de.caritas.cob.userservice.api.model.ConsultantAgencyAdminResultDTO; +import de.caritas.cob.userservice.api.model.ConsultantAdminResponseDTO; import de.caritas.cob.userservice.api.model.ConsultantFilter; +import de.caritas.cob.userservice.api.model.ConsultantResponseDTO; import de.caritas.cob.userservice.api.model.ConsultantSearchResultDTO; -import de.caritas.cob.userservice.api.model.GetConsultantResponseDTO; +import de.caritas.cob.userservice.api.model.CreateConsultantDTO; +import de.caritas.cob.userservice.api.repository.consultant.Consultant; import lombok.NonNull; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -26,9 +29,9 @@ public class ConsultantAdminFacade { * Finds a consultant by given consultant id. * * @param consultantId the id of the consultant to search for - * @return the generated {@link GetConsultantResponseDTO} + * @return the generated {@link ConsultantResponseDTO} */ - public GetConsultantResponseDTO findConsultant(String consultantId) { + public ConsultantAdminResponseDTO findConsultant(String consultantId) { return this.consultantAdminService.findConsultantById(consultantId); } @@ -47,6 +50,17 @@ public ConsultantSearchResultDTO findFilteredConsultants(Integer page, Integer p consultantFilter); } + /** + * Creates a new {@link Consultant} based on the {@link CreateConsultantDTO} input. + * + * @param createConsultantDTO the input data used for {@link Consultant} creation + * @return the generated and persisted {@link Consultant} representation as {@link + * ConsultantAdminResponseDTO} + */ + public ConsultantAdminResponseDTO createNewConsultant(CreateConsultantDTO createConsultantDTO) { + return this.consultantAdminService.createNewConsultant(createConsultantDTO); + } + /** * Returns all Agencies for the given consultantId. * diff --git a/src/main/java/de/caritas/cob/userservice/api/admin/hallink/RootDTOBuilder.java b/src/main/java/de/caritas/cob/userservice/api/admin/hallink/RootDTOBuilder.java index 342f08bf2..9b7cc4f00 100644 --- a/src/main/java/de/caritas/cob/userservice/api/admin/hallink/RootDTOBuilder.java +++ b/src/main/java/de/caritas/cob/userservice/api/admin/hallink/RootDTOBuilder.java @@ -27,7 +27,9 @@ public RootDTO buildRootDTO() { .links(new RootLinks() .self(buildSelfLink()) .sessions(buildSessionsLink()) - .consultants(buildConsultantsLink())); + .consultants(buildConsultantsLink()) + .consultantAgencies(buildConsultantAgenciesLink()) + .createConsultant(buildCreateConsultantLink())); } private HalLink buildSelfLink() { @@ -46,4 +48,12 @@ private HalLink buildConsultantsLink() { MethodEnum.GET); } + private HalLink buildConsultantAgenciesLink() { + return buildHalLink(methodOn(UseradminApi.class).getConsultantAgency(null), MethodEnum.GET); + } + + private HalLink buildCreateConsultantLink() { + return buildHalLink(methodOn(UseradminApi.class).createConsultant(null), MethodEnum.POST); + } + } diff --git a/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantAdminService.java b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantAdminService.java index 71e05c336..0ecd444c5 100644 --- a/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantAdminService.java +++ b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantAdminService.java @@ -1,7 +1,10 @@ package de.caritas.cob.userservice.api.admin.service.consultant; +import de.caritas.cob.userservice.api.admin.service.consultant.create.ConsultantCreatorService; import de.caritas.cob.userservice.api.exception.httpresponses.NoContentException; -import de.caritas.cob.userservice.api.model.GetConsultantResponseDTO; +import de.caritas.cob.userservice.api.model.ConsultantAdminResponseDTO; +import de.caritas.cob.userservice.api.model.ConsultantResponseDTO; +import de.caritas.cob.userservice.api.model.CreateConsultantDTO; import de.caritas.cob.userservice.api.repository.consultant.Consultant; import de.caritas.cob.userservice.api.repository.consultant.ConsultantRepository; import lombok.NonNull; @@ -16,19 +19,35 @@ public class ConsultantAdminService { private final @NonNull ConsultantRepository consultantRepository; + private final @NonNull ConsultantCreatorService consultantCreatorService; /** - * Finds a {@link Consultant} by the given consultant id and throws a - * {@link NoContentException} if no consultant for given id exists. + * Finds a {@link Consultant} by the given consultant id and throws a {@link NoContentException} + * if no consultant for given id exists. * * @param consultantId the consultant id to search for - * @return a generated {@link GetConsultantResponseDTO} + * @return a generated {@link ConsultantResponseDTO} */ - public GetConsultantResponseDTO findConsultantById(String consultantId) { + public ConsultantAdminResponseDTO findConsultantById(String consultantId) { Consultant consultant = this.consultantRepository.findById(consultantId) .orElseThrow(() -> new NoContentException( String.format("Consultant with id %s not found", consultantId))); - return GetConsultantDTOBuilder.getInstance(consultant) + return ConsultantResponseDTOBuilder.getInstance(consultant) + .buildResponseDTO(); + } + + /** + * Creates a new {@link Consultant} based on the {@link CreateConsultantDTO} input. + * + * @param createConsultantDTO the input data used for {@link Consultant} creation + * @return the generated and persisted {@link Consultant} representation as {@link + * ConsultantAdminResponseDTO} + */ + public ConsultantAdminResponseDTO createNewConsultant(CreateConsultantDTO createConsultantDTO) { + Consultant newConsultant = + this.consultantCreatorService.createNewConsultant(createConsultantDTO); + + return ConsultantResponseDTOBuilder.getInstance(newConsultant) .buildResponseDTO(); } diff --git a/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantResponseDTOBuilder.java b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantResponseDTOBuilder.java new file mode 100644 index 000000000..afdc3c985 --- /dev/null +++ b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantResponseDTOBuilder.java @@ -0,0 +1,83 @@ +package de.caritas.cob.userservice.api.admin.service.consultant; + +import static java.util.Objects.requireNonNull; +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; + +import de.caritas.cob.userservice.api.admin.hallink.HalLinkBuilder; +import de.caritas.cob.userservice.api.admin.mapper.ConsultantAdminMapper; +import de.caritas.cob.userservice.api.model.ConsultantAdminResponseDTO; +import de.caritas.cob.userservice.api.model.ConsultantDTO; +import de.caritas.cob.userservice.api.model.ConsultantLinks; +import de.caritas.cob.userservice.api.model.HalLink; +import de.caritas.cob.userservice.api.model.HalLink.MethodEnum; +import de.caritas.cob.userservice.api.repository.consultant.Consultant; +import de.caritas.cob.userservice.generated.api.admin.controller.UseradminApi; + +/** + * Builder class to generate a {@link ConsultantAdminResponseDTO} containing available hal links and + * result of {@link ConsultantDTO} element. + */ +public class ConsultantResponseDTOBuilder implements HalLinkBuilder { + + private final Consultant consultant; + + private ConsultantResponseDTOBuilder(Consultant consultant) { + this.consultant = requireNonNull(consultant); + } + + /** + * Creates the {@link ConsultantResponseDTOBuilder} instance. + * + * @param consultant the source consultant + * @return a instance of {@link ConsultantResponseDTOBuilder} + */ + public static ConsultantResponseDTOBuilder getInstance(Consultant consultant) { + return new ConsultantResponseDTOBuilder(consultant); + } + + /** + * Generates the {@link ConsultantAdminResponseDTO} containing the {@link ConsultantDTO} resource + * and navigation hal links. + * + * @return the generated {@link ConsultantAdminResponseDTO} + */ + public ConsultantAdminResponseDTO buildResponseDTO() { + ConsultantDTO consultantDTO = new ConsultantAdminMapper(this.consultant).mapData(); + ConsultantLinks consultantLinks = new ConsultantLinks() + .self(buildSelfLink()) + .update(buildUpdateLink()) + .delete(buildDeleteLink()) + .agencies(buildAgenciesLink()) + .addAgency(buildAddAgencyLink()); + + return new ConsultantAdminResponseDTO() + .embedded(consultantDTO) + .links(consultantLinks); + } + + private HalLink buildSelfLink() { + return buildHalLink(methodOn(UseradminApi.class) + .getConsultant(this.consultant.getId()), MethodEnum.GET); + } + + private HalLink buildUpdateLink() { + return buildHalLink(methodOn(UseradminApi.class) + .updateConsultant(this.consultant.getId(), null), MethodEnum.PUT); + } + + private HalLink buildDeleteLink() { + return buildHalLink(methodOn(UseradminApi.class) + .markConsultantForDeletion(this.consultant.getId()), MethodEnum.DELETE); + } + + private HalLink buildAgenciesLink() { + return buildHalLink(methodOn(UseradminApi.class) + .getConsultantAgency(this.consultant.getId()), MethodEnum.GET); + } + + private HalLink buildAddAgencyLink() { + return buildHalLink(methodOn(UseradminApi.class) + .createConsultantAgency(this.consultant.getId(), null), MethodEnum.POST); + } + +} diff --git a/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantSearchResultBuilder.java b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantSearchResultBuilder.java index 91940fcb7..bd0808f2b 100644 --- a/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantSearchResultBuilder.java +++ b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantSearchResultBuilder.java @@ -3,7 +3,7 @@ import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; import de.caritas.cob.userservice.api.admin.hallink.HalLinkBuilder; -import de.caritas.cob.userservice.api.admin.mapper.ConsultantAdminMapper; +import de.caritas.cob.userservice.api.model.ConsultantAdminResponseDTO; import de.caritas.cob.userservice.api.model.ConsultantDTO; import de.caritas.cob.userservice.api.model.ConsultantFilter; import de.caritas.cob.userservice.api.model.ConsultantSearchResultDTO; @@ -83,9 +83,9 @@ public ConsultantSearchResultBuilder withPerPage(Integer perPage) { */ public ConsultantSearchResultDTO buildConsultantSearchResult() { Stream resultStream = fullTextQuery.getResultStream(); - List resultList = resultStream - .map(ConsultantAdminMapper::new) - .map(ConsultantAdminMapper::mapData) + List resultList = resultStream + .map(ConsultantResponseDTOBuilder::getInstance) + .map(ConsultantResponseDTOBuilder::buildResponseDTO) .collect(Collectors.toList()); PaginationLinks paginationLinks = new PaginationLinks() diff --git a/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/GetConsultantDTOBuilder.java b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/GetConsultantDTOBuilder.java deleted file mode 100644 index 5efd47b84..000000000 --- a/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/GetConsultantDTOBuilder.java +++ /dev/null @@ -1,71 +0,0 @@ -package de.caritas.cob.userservice.api.admin.service.consultant; - -import static java.util.Objects.requireNonNull; -import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; - -import de.caritas.cob.userservice.api.admin.hallink.HalLinkBuilder; -import de.caritas.cob.userservice.api.admin.mapper.ConsultantAdminMapper; -import de.caritas.cob.userservice.api.model.ConsultantDTO; -import de.caritas.cob.userservice.api.model.GetConsultantResponseDTO; -import de.caritas.cob.userservice.api.model.GetLinks; -import de.caritas.cob.userservice.api.model.HalLink; -import de.caritas.cob.userservice.api.model.HalLink.MethodEnum; -import de.caritas.cob.userservice.api.repository.consultant.Consultant; -import de.caritas.cob.userservice.generated.api.admin.controller.UseradminApi; - -/** - * Builder class to generate a {@link GetConsultantResponseDTO} containing available hal links - * and result of {@link ConsultantDTO} element. - */ -public class GetConsultantDTOBuilder implements HalLinkBuilder { - - private final Consultant consultant; - - private GetConsultantDTOBuilder(Consultant consultant) { - this.consultant = requireNonNull(consultant); - } - - /** - * Creates the {@link GetConsultantDTOBuilder} instance. - * - * @param consultant the source consultant - * @return a instance of {@link GetConsultantDTOBuilder} - */ - public static GetConsultantDTOBuilder getInstance(Consultant consultant) { - return new GetConsultantDTOBuilder(consultant); - } - - /** - * Generates the {@link GetConsultantResponseDTO} containing the {@link ConsultantDTO} resource - * and navigation hal links. - * - * @return the generated {@link GetConsultantResponseDTO} - */ - public GetConsultantResponseDTO buildResponseDTO() { - ConsultantDTO consultantDTO = new ConsultantAdminMapper(this.consultant).mapData(); - GetLinks getLinks = new GetLinks() - .self(buildSelfLink()) - .update(buildUpdateLink()) - .delete(buildDeleteLink()); - - return new GetConsultantResponseDTO() - .embedded(consultantDTO) - .links(getLinks); - } - - private HalLink buildSelfLink() { - return buildHalLink(methodOn(UseradminApi.class) - .getConsultant(this.consultant.getId()), MethodEnum.GET); - } - - private HalLink buildUpdateLink() { - return buildHalLink(methodOn(UseradminApi.class) - .updateConsultant(this.consultant.getId(), null), MethodEnum.PUT); - } - - private HalLink buildDeleteLink() { - return buildHalLink(methodOn(UseradminApi.class) - .markConsultantForDeletion(this.consultant.getId()), MethodEnum.DELETE); - } - -} diff --git a/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantCreationInput.java b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantCreationInput.java new file mode 100644 index 000000000..5d2f1ba36 --- /dev/null +++ b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantCreationInput.java @@ -0,0 +1,34 @@ +package de.caritas.cob.userservice.api.admin.service.consultant.create; + +import java.time.LocalDateTime; + +/** + * Definition for required input data used to create a new consultant. + */ +interface ConsultantCreationInput { + + Long getIdOld(); + + String getUserName(); + + String getEncodedUsername(); + + String getFirstName(); + + String getLastName(); + + String getEmail(); + + boolean isAbsent(); + + String getAbsenceMessage(); + + boolean isTeamConsultant(); + + boolean isLanguageFormal(); + + LocalDateTime getCreateDate(); + + LocalDateTime getUpdateDate(); + +} diff --git a/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantCreatorService.java b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantCreatorService.java new file mode 100644 index 000000000..f6d296281 --- /dev/null +++ b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantCreatorService.java @@ -0,0 +1,132 @@ +package de.caritas.cob.userservice.api.admin.service.consultant.create; + +import static de.caritas.cob.userservice.api.authorization.UserRole.CONSULTANT; +import static org.apache.commons.lang3.BooleanUtils.isTrue; +import static org.hibernate.validator.internal.util.CollectionHelper.asSet; + +import de.caritas.cob.userservice.api.exception.httpresponses.InternalServerErrorException; +import de.caritas.cob.userservice.api.exception.rocketchat.RocketChatLoginException; +import de.caritas.cob.userservice.api.helper.UserHelper; +import de.caritas.cob.userservice.api.model.CreateConsultantDTO; +import de.caritas.cob.userservice.api.model.keycloak.KeycloakCreateUserResponseDTO; +import de.caritas.cob.userservice.api.model.registration.UserDTO; +import de.caritas.cob.userservice.api.repository.consultant.Consultant; +import de.caritas.cob.userservice.api.service.ConsultantImportService.ImportRecord; +import de.caritas.cob.userservice.api.service.ConsultantService; +import de.caritas.cob.userservice.api.service.RocketChatService; +import de.caritas.cob.userservice.api.service.helper.KeycloakAdminClientHelper; +import java.util.Set; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +/** + * Creator class to generate new {@link Consultant} instances in database, keycloak and rocket + * chat. + */ +@Service +@RequiredArgsConstructor +public class ConsultantCreatorService { + + private final @NonNull KeycloakAdminClientHelper keycloakAdminClientHelper; + private final @NonNull RocketChatService rocketChatService; + private final @NonNull ConsultantService consultantService; + private final @NonNull UserHelper userHelper; + private final @NonNull ConsultantInputValidator consultantInputValidator; + + /** + * Creates a new {@link Consultant} by {@link CreateConsultantDTO} in database, keycloak and + * rocket chat. + * + * @param createConsultantDTO the input used for creation + * @return the generated {@link Consultant} + */ + public Consultant createNewConsultant(CreateConsultantDTO createConsultantDTO) { + ConsultantCreationInput consultantCreationInput = + new CreateConsultantDTOCreationInputAdapter(createConsultantDTO, this.userHelper); + return createNewConsultant(consultantCreationInput, asSet(CONSULTANT.getValue())); + } + + /** + * Creates a new {@link Consultant} by {@link ImportRecord} in database, keycloak and rocket + * chat. + * + * @param importRecord the input record from csv used by the importer service + * @param roles the roles to add to given {@link Consultant} + * @return the generated {@link Consultant} + */ + public Consultant createNewConsultant(ImportRecord importRecord, Set roles) { + ConsultantCreationInput consultantCreationInput = + new ImportRecordCreationInputAdapter(importRecord); + return createNewConsultant(consultantCreationInput, roles); + } + + private Consultant createNewConsultant(ConsultantCreationInput consultantCreationInput, + Set roles) { + String keycloakUserId = createKeycloakUser(consultantCreationInput); + + String password = userHelper.getRandomPassword(); + keycloakAdminClientHelper.updatePassword(keycloakUserId, password); + roles.forEach(roleName -> this.keycloakAdminClientHelper.updateRole(keycloakUserId, roleName)); + + String rocketChatUserId = + createRocketChatUser(consultantCreationInput, keycloakUserId, password); + + return consultantService.saveConsultant( + buildConsultant(consultantCreationInput, keycloakUserId, rocketChatUserId)); + } + + private String createKeycloakUser(ConsultantCreationInput consultantCreationInput) { + UserDTO userDto = buildUserDTO(consultantCreationInput.getUserName(), + consultantCreationInput.getEmail()); + + this.consultantInputValidator.validateUserDTO(userDto); + + KeycloakCreateUserResponseDTO response = + this.keycloakAdminClientHelper + .createKeycloakUser(userDto, consultantCreationInput.getFirstName(), + consultantCreationInput.getLastName()); + + this.consultantInputValidator.validateKeycloakResponse(response); + + return response.getUserId(); + } + + private String createRocketChatUser(ConsultantCreationInput consultantCreationInput, + String keycloakUserId, String password) { + try { + return this.rocketChatService + .getUserID(consultantCreationInput.getEncodedUsername(), password, true); + } catch (RocketChatLoginException e) { + throw new InternalServerErrorException( + String.format("Unable to login user with id %s first time", keycloakUserId)); + } + } + + private Consultant buildConsultant(ConsultantCreationInput consultantCreationInput, + String keycloakUserId, String rocketChatUserId) { + return Consultant.builder() + .id(keycloakUserId) + .idOld(consultantCreationInput.getIdOld()) + .username(consultantCreationInput.getEncodedUsername()) + .firstName(consultantCreationInput.getFirstName()) + .lastName(consultantCreationInput.getLastName()) + .email(consultantCreationInput.getEmail()) + .absent(isTrue(consultantCreationInput.isAbsent())) + .absenceMessage(consultantCreationInput.getAbsenceMessage()) + .teamConsultant(consultantCreationInput.isTeamConsultant()) + .rocketChatId(rocketChatUserId) + .languageFormal(consultantCreationInput.isLanguageFormal()) + .createDate(consultantCreationInput.getCreateDate()) + .updateDate(consultantCreationInput.getUpdateDate()) + .build(); + } + + private UserDTO buildUserDTO(String username, String email) { + UserDTO userDto = new UserDTO(); + userDto.setUsername(userHelper.encodeUsername(username)); + userDto.setEmail(email); + return userDto; + } + +} diff --git a/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantInputValidator.java b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantInputValidator.java new file mode 100644 index 000000000..9698b911a --- /dev/null +++ b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantInputValidator.java @@ -0,0 +1,85 @@ +package de.caritas.cob.userservice.api.admin.service.consultant.create; + +import static de.caritas.cob.userservice.api.exception.httpresponses.customheader.HttpStatusExceptionReason.EMAIL_NOT_AVAILABLE; +import static de.caritas.cob.userservice.api.exception.httpresponses.customheader.HttpStatusExceptionReason.EMAIL_NOT_VALID; +import static de.caritas.cob.userservice.api.exception.httpresponses.customheader.HttpStatusExceptionReason.MISSING_ABSENCE_MESSAGE_FOR_ABSENT_USER; +import static de.caritas.cob.userservice.api.exception.httpresponses.customheader.HttpStatusExceptionReason.USERNAME_NOT_AVAILABLE; +import static de.caritas.cob.userservice.api.exception.httpresponses.customheader.HttpStatusExceptionReason.USERNAME_NOT_VALID; +import static java.util.Objects.isNull; +import static org.apache.commons.lang3.BooleanUtils.isTrue; +import static org.apache.commons.lang3.StringUtils.isBlank; + +import de.caritas.cob.userservice.api.exception.httpresponses.CustomValidationHttpStatusException; +import de.caritas.cob.userservice.api.exception.httpresponses.customheader.HttpStatusExceptionReason; +import de.caritas.cob.userservice.api.exception.keycloak.KeycloakException; +import de.caritas.cob.userservice.api.model.CreateConsultantDTO; +import de.caritas.cob.userservice.api.model.keycloak.KeycloakCreateUserResponseDTO; +import de.caritas.cob.userservice.api.model.registration.UserDTO; +import javax.validation.Validator; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +/** + * Validation class for data transferred within consultant creation process. + */ +@Component +@RequiredArgsConstructor +public class ConsultantInputValidator { + + private static final String EMAIL_FIELD = "email"; + private static final String USERNAME_FIELD = "username"; + + private final @NonNull Validator validator; + + /** + * Validates if given {@link CreateConsultantDTO} has set the property absent to true and no + * therefore required absence message set. + * + * @param createConsultantDTO the input data to check + */ + public void validateCreateConsultantDTO(CreateConsultantDTO createConsultantDTO) { + if (isTrue(createConsultantDTO.getAbsent()) && isBlank( + createConsultantDTO.getAbsenceMessage())) { + throw new CustomValidationHttpStatusException(MISSING_ABSENCE_MESSAGE_FOR_ABSENT_USER); + } + } + + /** + * Validates email and username. + * + * @param userDTO the {@link UserDTO} to be validated + */ + public void validateUserDTO(UserDTO userDTO) { + validateField(userDTO, EMAIL_FIELD, EMAIL_NOT_VALID); + validateField(userDTO, USERNAME_FIELD, USERNAME_NOT_VALID); + } + + private void validateField(UserDTO userDTO, String fieldName, + HttpStatusExceptionReason failReason) { + this.validator.validate(userDTO).stream() + .filter(violation -> violation.getPropertyPath().toString().equals(fieldName)) + .findFirst() + .ifPresent(violation -> { + throw new CustomValidationHttpStatusException(failReason); + }); + } + + /** + * Validates the created keycloak object. + * + * @param keycloakResponse the keycloak response object to be validated + */ + public void validateKeycloakResponse(KeycloakCreateUserResponseDTO keycloakResponse) { + if (isNull(keycloakResponse.getUserId())) { + if (keycloakResponse.getResponseDTO().getUsernameAvailable().equals(0)) { + throw new CustomValidationHttpStatusException(USERNAME_NOT_AVAILABLE); + } + if (keycloakResponse.getResponseDTO().getEmailAvailable().equals(0)) { + throw new CustomValidationHttpStatusException(EMAIL_NOT_AVAILABLE); + } + throw new KeycloakException("ERROR: Keycloak user id is missing"); + } + } + +} diff --git a/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/CreateConsultantDTOCreationInputAdapter.java b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/CreateConsultantDTOCreationInputAdapter.java new file mode 100644 index 000000000..d2cfd5574 --- /dev/null +++ b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/CreateConsultantDTOCreationInputAdapter.java @@ -0,0 +1,140 @@ +package de.caritas.cob.userservice.api.admin.service.consultant.create; + +import static org.apache.commons.lang3.BooleanUtils.isTrue; + +import de.caritas.cob.userservice.api.helper.UserHelper; +import de.caritas.cob.userservice.api.model.CreateConsultantDTO; +import java.time.LocalDateTime; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +/** + * Adapter class to provide a {@link ConsultantCreationInput} based on a + * {@link CreateConsultantDTO}. + */ +@RequiredArgsConstructor +public class CreateConsultantDTOCreationInputAdapter implements ConsultantCreationInput { + + private final @NonNull CreateConsultantDTO createConsultantDTO; + private final @NonNull UserHelper userHelper; + + /** + * Provides the old id. + * + * @return always null here + */ + @Override + public Long getIdOld() { + return null; + } + + /** + * Provides the user name. + * + * @return the user name + */ + @Override + public String getUserName() { + return this.createConsultantDTO.getUsername(); + } + + /** + * Provides the encoded user name. + * + * @return the encoded user name + */ + @Override + public String getEncodedUsername() { + return this.userHelper.encodeUsername(createConsultantDTO.getUsername()); + } + + /** + * Provides the first name. + * + * @return the first name + */ + @Override + public String getFirstName() { + return this.createConsultantDTO.getFirstname(); + } + + /** + * Provides the last name. + * + * @return the last name + */ + @Override + public String getLastName() { + return this.createConsultantDTO.getLastname(); + } + + /** + * Provides the email address. + * + * @return the email address + */ + @Override + public String getEmail() { + return this.createConsultantDTO.getEmail(); + } + + /** + * Provides the absent flag. + * + * @return the absent flag + */ + @Override + public boolean isAbsent() { + return isTrue(this.createConsultantDTO.getAbsent()); + } + + /** + * Provides the absence message. + * + * @return the absence message + */ + @Override + public String getAbsenceMessage() { + return this.createConsultantDTO.getAbsenceMessage(); + } + + /** + * Provides the team consultant flag. + * + * @return the team consultant flag + */ + @Override + public boolean isTeamConsultant() { + return false; + } + + /** + * Provdes the language formal flag. + * + * @return the language formal flag + */ + @Override + public boolean isLanguageFormal() { + return isTrue(this.createConsultantDTO.getFormalLanguage()); + } + + /** + * Provides the created date. + * + * @return the created date + */ + @Override + public LocalDateTime getCreateDate() { + return LocalDateTime.now(); + } + + /** + * Provides the updated date. + * + * @return the updated date + */ + @Override + public LocalDateTime getUpdateDate() { + return LocalDateTime.now(); + } +} diff --git a/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ImportRecordCreationInputAdapter.java b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ImportRecordCreationInputAdapter.java new file mode 100644 index 000000000..81c427578 --- /dev/null +++ b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ImportRecordCreationInputAdapter.java @@ -0,0 +1,136 @@ +package de.caritas.cob.userservice.api.admin.service.consultant.create; + +import de.caritas.cob.userservice.api.service.ConsultantImportService.ImportRecord; +import java.time.LocalDateTime; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +/** + * Adapter class to provide a {@link ConsultantCreationInput} based on a + * {@link ImportRecord}. + */ +@RequiredArgsConstructor +public class ImportRecordCreationInputAdapter implements ConsultantCreationInput { + + private final @NonNull ImportRecord importRecord; + + /** + * Provides the old id. + * + * @return the old id + */ + @Override + public Long getIdOld() { + return this.importRecord.getIdOld(); + } + + /** + * Provides the user name. + * + * @return the user name + */ + @Override + public String getUserName() { + return this.importRecord.getUsername(); + } + + /** + * Provides the encoded user name. + * + * @return the encoded user name + */ + @Override + public String getEncodedUsername() { + return this.importRecord.getUsernameEncoded(); + } + + /** + * Provides the first name. + * + * @return the first name + */ + @Override + public String getFirstName() { + return this.importRecord.getFirstName(); + } + + /** + * Provides the last name. + * + * @return the last name + */ + @Override + public String getLastName() { + return this.importRecord.getLastName(); + } + + /** + * Provides the email address. + * + * @return the email address + */ + @Override + public String getEmail() { + return this.importRecord.getEmail(); + } + + /** + * Provides the absent flag. + * + * @return the absent flag + */ + @Override + public boolean isAbsent() { + return this.importRecord.isAbsent(); + } + + /** + * Provides the absence message. + * + * @return the absence message + */ + @Override + public String getAbsenceMessage() { + return this.importRecord.getAbsenceMessage(); + } + + /** + * Provides the team consultant flag. + * + * @return the team consultant flag + */ + @Override + public boolean isTeamConsultant() { + return this.importRecord.isTeamConsultant(); + } + + /** + * Provdes the language formal flag. + * + * @return the language formal flag + */ + @Override + public boolean isLanguageFormal() { + return this.importRecord.isFormalLanguage(); + } + + /** + * Provides the created date. + * + * @return the created date + */ + @Override + public LocalDateTime getCreateDate() { + return LocalDateTime.now(); + } + + /** + * Provides the updated date. + * + * @return the updated date + */ + @Override + public LocalDateTime getUpdateDate() { + return LocalDateTime.now(); + } +} diff --git a/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/CustomHttpStatusException.java b/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/CustomHttpStatusException.java index 9ebf328af..8fcc03eaf 100644 --- a/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/CustomHttpStatusException.java +++ b/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/CustomHttpStatusException.java @@ -2,12 +2,17 @@ import static java.util.Objects.nonNull; +import de.caritas.cob.userservice.api.service.LogService; import java.util.function.Consumer; -import lombok.Setter; public abstract class CustomHttpStatusException extends RuntimeException { - private Consumer loggingMethod; + private final Consumer loggingMethod; + + CustomHttpStatusException() { + super(); + this.loggingMethod = LogService::logWarn; + } CustomHttpStatusException(String message, Consumer loggingMethod) { super(message); diff --git a/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/CustomValidationHttpStatusException.java b/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/CustomValidationHttpStatusException.java new file mode 100644 index 000000000..451dbb0bf --- /dev/null +++ b/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/CustomValidationHttpStatusException.java @@ -0,0 +1,29 @@ +package de.caritas.cob.userservice.api.exception.httpresponses; + +import de.caritas.cob.userservice.api.exception.httpresponses.customheader.CustomHttpHeader; +import de.caritas.cob.userservice.api.exception.httpresponses.customheader.HttpStatusExceptionReason; +import org.springframework.http.HttpHeaders; + +/** + * Custom validation exception for http status with reason. + */ +public class CustomValidationHttpStatusException extends CustomHttpStatusException { + + private final HttpHeaders customHttpHeader; + + public CustomValidationHttpStatusException(HttpStatusExceptionReason httpStatusExceptionReason) { + super(); + this.customHttpHeader = new CustomHttpHeader(httpStatusExceptionReason) + .buildHeader(); + } + + /** + * Get the {@link @HttpHeaders} for the thrown exception. + * + * @return a value of {@link @HttpHeaders} + */ + public HttpHeaders getCustomHttpHeader() { + return this.customHttpHeader; + } + +} diff --git a/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/customheader/CustomHttpHeader.java b/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/customheader/CustomHttpHeader.java new file mode 100644 index 000000000..1064d6bd9 --- /dev/null +++ b/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/customheader/CustomHttpHeader.java @@ -0,0 +1,25 @@ +package de.caritas.cob.userservice.api.exception.httpresponses.customheader; + +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpHeaders; + +/* +* Custom http header with X-Reason header. + */ +@RequiredArgsConstructor +public class CustomHttpHeader { + + private final @NonNull HttpStatusExceptionReason httpStatusExceptionReason; + + /** + * Build the header object. + * + * @return an instance of {@link HttpHeaders} + */ + public HttpHeaders buildHeader() { + HttpHeaders headers = new HttpHeaders(); + headers.add("X-Reason", this.httpStatusExceptionReason.name()); + return headers; + } +} diff --git a/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/customheader/HttpStatusExceptionReason.java b/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/customheader/HttpStatusExceptionReason.java new file mode 100644 index 000000000..a2ed73168 --- /dev/null +++ b/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/customheader/HttpStatusExceptionReason.java @@ -0,0 +1,9 @@ +package de.caritas.cob.userservice.api.exception.httpresponses.customheader; + +public enum HttpStatusExceptionReason { + USERNAME_NOT_AVAILABLE, + USERNAME_NOT_VALID, + EMAIL_NOT_AVAILABLE, + EMAIL_NOT_VALID, + MISSING_ABSENCE_MESSAGE_FOR_ABSENT_USER +} diff --git a/src/main/java/de/caritas/cob/userservice/api/facade/CreateUserFacade.java b/src/main/java/de/caritas/cob/userservice/api/facade/CreateUserFacade.java index 59d78ff3c..9b504078f 100644 --- a/src/main/java/de/caritas/cob/userservice/api/facade/CreateUserFacade.java +++ b/src/main/java/de/caritas/cob/userservice/api/facade/CreateUserFacade.java @@ -122,7 +122,7 @@ private void updateKeycloakAccountAndCreateDatabaseUserAccount(String userId, Us .initializeNewConsultingType(userDTO, user, consultingTypeSettings); } - private String returnDummyEmailIfNoneGiven(UserDTO userDTO, String userId) throws Exception { + private String returnDummyEmailIfNoneGiven(UserDTO userDTO, String userId) { if (isBlank(userDTO.getEmail())) { return keycloakAdminClientHelper.updateDummyEmail(userId, userDTO); } diff --git a/src/main/java/de/caritas/cob/userservice/api/repository/consultant/Consultant.java b/src/main/java/de/caritas/cob/userservice/api/repository/consultant/Consultant.java index 3c059c035..0d94810b5 100644 --- a/src/main/java/de/caritas/cob/userservice/api/repository/consultant/Consultant.java +++ b/src/main/java/de/caritas/cob/userservice/api/repository/consultant/Consultant.java @@ -13,6 +13,7 @@ import javax.persistence.Table; import javax.validation.constraints.Size; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.NonNull; @@ -39,6 +40,7 @@ @NoArgsConstructor @Getter @Setter +@Builder @Indexed @AnalyzerDef(name = EMAIL_ANALYZER, tokenizer = @TokenizerDef(factory = ClassicTokenizerFactory.class), diff --git a/src/main/java/de/caritas/cob/userservice/api/service/ConsultantImportService.java b/src/main/java/de/caritas/cob/userservice/api/service/ConsultantImportService.java index b8fe211e4..79f350f6b 100644 --- a/src/main/java/de/caritas/cob/userservice/api/service/ConsultantImportService.java +++ b/src/main/java/de/caritas/cob/userservice/api/service/ConsultantImportService.java @@ -1,32 +1,30 @@ package de.caritas.cob.userservice.api.service; +import static org.apache.commons.collections4.CollectionUtils.isNotEmpty; import static org.apache.commons.lang3.BooleanUtils.isTrue; +import de.caritas.cob.userservice.api.admin.service.consultant.create.ConsultantCreatorService; import de.caritas.cob.userservice.api.authorization.Authorities.Authority; import de.caritas.cob.userservice.api.authorization.UserRole; import de.caritas.cob.userservice.api.exception.AgencyServiceHelperException; import de.caritas.cob.userservice.api.exception.ImportException; import de.caritas.cob.userservice.api.exception.httpresponses.InternalServerErrorException; -import de.caritas.cob.userservice.api.exception.keycloak.KeycloakException; import de.caritas.cob.userservice.api.exception.rocketchat.RocketChatRemoveUserFromGroupException; import de.caritas.cob.userservice.api.helper.UserHelper; import de.caritas.cob.userservice.api.manager.consultingtype.ConsultingTypeManager; import de.caritas.cob.userservice.api.manager.consultingtype.ConsultingTypeSettings; import de.caritas.cob.userservice.api.model.AgencyDTO; import de.caritas.cob.userservice.api.model.ConsultantSessionResponseDTO; -import de.caritas.cob.userservice.api.model.keycloak.KeycloakCreateUserResponseDTO; -import de.caritas.cob.userservice.api.model.registration.UserDTO; import de.caritas.cob.userservice.api.repository.consultant.Consultant; import de.caritas.cob.userservice.api.repository.consultantAgency.ConsultantAgency; import de.caritas.cob.userservice.api.repository.session.ConsultingType; import de.caritas.cob.userservice.api.repository.session.SessionStatus; import de.caritas.cob.userservice.api.service.helper.AgencyServiceHelper; import de.caritas.cob.userservice.api.service.helper.KeycloakAdminClientHelper; -import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.Reader; -import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; @@ -38,16 +36,18 @@ import java.util.Set; import java.util.stream.Collectors; import lombok.Getter; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; import lombok.Setter; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVRecord; import org.apache.commons.lang3.StringUtils; import org.apache.commons.validator.routines.EmailValidator; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @Service +@RequiredArgsConstructor public class ConsultantImportService { @Value("${consultant.import.filename}") @@ -55,46 +55,37 @@ public class ConsultantImportService { @Value("${consultant.import.protocol.filename}") private String protocolFilename; - @Autowired - private KeycloakAdminClientHelper keycloakAdminClientHelper; - @Autowired - private ConsultantService consultantService; - @Autowired - private ConsultantAgencyService consultantAgencyService; - @Autowired - private RocketChatService rocketChatService; - @Autowired - private ConsultingTypeManager consultingTypeManager; - @Autowired - private AgencyServiceHelper agencyServiceHelper; - @Autowired - private SessionService sessionService; - @Autowired - private UserHelper userHelper; - - private final String DELIMITER = ","; - private final String AGENCY_ROLE_DELIMITER = ";"; - private final String YES = "ja"; - private final boolean FORMAL_LANGUAGE_DEFAULT = true; - private final boolean TEAM_CONSULTANT_DEFAULT = false; - private final String NEWLINE_CHAR = "\r\n"; - private final String IMPORT_LOG_CHARSET = "UTF-8"; + private final @NonNull KeycloakAdminClientHelper keycloakAdminClientHelper; + private final @NonNull ConsultantService consultantService; + private final @NonNull ConsultantAgencyService consultantAgencyService; + private final @NonNull RocketChatService rocketChatService; + private final @NonNull ConsultingTypeManager consultingTypeManager; + private final @NonNull AgencyServiceHelper agencyServiceHelper; + private final @NonNull SessionService sessionService; + private final @NonNull UserHelper userHelper; + private final @NonNull ConsultantCreatorService consultantCreatorService; + + private static final String DELIMITER = ","; + private static final String AGENCY_ROLE_DELIMITER = ";"; + private static final String YES = "ja"; + private static final boolean FORMAL_LANGUAGE_DEFAULT = true; + private static final boolean TEAM_CONSULTANT_DEFAULT = false; + private static final String NEWLINE_CHAR = "\r\n"; private String protocolFile; public void startImport() { - protocolFile = protocolFilename + "." + System.currentTimeMillis(); + this.protocolFile = protocolFilename + "." + System.currentTimeMillis(); Reader in; - Iterable records = null; + List records; String logMessage; - String keycloakUserId; Consultant consultant = null; String rocketChatUserId = null; try { in = new FileReader(importFilename); - records = CSVFormat.DEFAULT.parse(in); + records = CSVFormat.DEFAULT.parse(in).getRecords(); } catch (Exception exception) { throw new InternalServerErrorException(exception.getMessage()); } @@ -115,9 +106,9 @@ public void startImport() { String[] agencyRoleSetArray = importRecord.getAgenciesAndRoleSets().split(DELIMITER); - HashSet roles = new HashSet(); - HashSet agencyIds = new HashSet(); - List formalLanguageList = new ArrayList(); + HashSet roles = new HashSet<>(); + HashSet agencyIds = new HashSet<>(); + List formalLanguageList = new ArrayList<>(); for (String agencyRoleSet : agencyRoleSetArray) { if (!agencyRoleSet.contains(AGENCY_ROLE_DELIMITER)) { @@ -127,7 +118,7 @@ public void startImport() { } String[] agencyRoleArray = agencyRoleSet.split(AGENCY_ROLE_DELIMITER); - AgencyDTO agency = null; + AgencyDTO agency; try { agency = agencyServiceHelper.getAgencyWithoutCaching(Long.valueOf(agencyRoleArray[0])); } catch (AgencyServiceHelperException agencyServiceHelperException) { @@ -234,58 +225,20 @@ public void startImport() { writeToImportLog(logMessage); if (importRecord.getConsultantId() == null) { - // Create keycloak user - UserDTO userDto = getUserDTO(importRecord.getUsername(), importRecord.getEmail()); - KeycloakCreateUserResponseDTO response; - try { - response = keycloakAdminClientHelper.createKeycloakUser(userDto, - importRecord.getFirstName(), importRecord.getLastName()); - } catch (KeycloakException keycloakException) { - throw new ImportException(String.format("ERROR: Keycloak user could not be created: %s", - keycloakException.getMessage())); - } catch (Exception ex) { - throw new ImportException( - String.format("ERROR: Keycloak user could not be created: %s", ex.getMessage())); - } - - if (response.getUserId() == null) { - throw new ImportException("ERROR: Keycloak user id is missing"); - } + consultant = this.consultantCreatorService.createNewConsultant(importRecord, roles); - keycloakUserId = response.getUserId(); - - logMessage = "Keycloak-ID: " + keycloakUserId; + logMessage = "Keycloak-ID: " + consultant.getId(); writeToImportLog(logMessage); - // Set keycloak password - String password = userHelper.getRandomPassword(); - keycloakAdminClientHelper.updatePassword(keycloakUserId, password); - - // Set consultant role - for (String roleName : roles) { - keycloakAdminClientHelper.updateRole(keycloakUserId, roleName); - } - - logMessage = "Roles: " + roles.stream().collect(Collectors.joining(",")); + logMessage = "Roles: " + String.join(",", roles); writeToImportLog(logMessage); - // Get the Rocket.Chat ID - rocketChatUserId = - rocketChatService.getUserID(importRecord.getUsernameEncoded(), password, true); - - logMessage = "RocketChat-ID: " + rocketChatUserId; + logMessage = "RocketChat-ID: " + consultant.getRocketChatId(); writeToImportLog(logMessage); - - // create consultant in db - consultant = consultantService.saveConsultant(getConsultant(keycloakUserId, - importRecord.getUsernameEncoded(), importRecord.getFirstName(), - importRecord.getLastName(), importRecord.getEmail(), importRecord.isAbsent, - importRecord.getAbsenceMessage(), importRecord.isTeamConsultant(), - importRecord.getIdOld(), rocketChatUserId, importRecord.isFormalLanguage())); } // create relations to agencies - Set consultantAgencies = new HashSet(); + Set consultantAgencies = new HashSet<>(); for (Long agencyId : agencyIds) { if (!consultantAgencyService.isConsultantInAgency(consultant.getId(), agencyId)) { consultantAgencies.add(consultantAgencyService @@ -294,15 +247,14 @@ public void startImport() { } consultant.setConsultantAgencies(consultantAgencies); - logMessage = "Agencies: " + agencyIds.stream().map(agencyId -> String.valueOf(agencyId)) + logMessage = "Agencies: " + agencyIds.stream().map(String::valueOf) .collect(Collectors.joining(",")); writeToImportLog(logMessage); // Enquiries List consultantSessionResponseDtoList = sessionService.getSessionsForConsultant(consultant, SessionStatus.NEW.getValue()); - if (consultantSessionResponseDtoList != null - && consultantSessionResponseDtoList.size() > 0) { + if (isNotEmpty(consultantSessionResponseDtoList)) { for (ConsultantSessionResponseDTO consultantSessionResponseDTO : consultantSessionResponseDtoList) { try { rocketChatService @@ -342,8 +294,7 @@ public void startImport() { logMessage = ""; List consultantTeamSessionResponseDtoList = sessionService.getTeamSessionsForConsultant(consultant); - if (consultantTeamSessionResponseDtoList != null - && consultantTeamSessionResponseDtoList.size() > 0) { + if (isNotEmpty(consultantTeamSessionResponseDtoList)) { for (ConsultantSessionResponseDTO consultantTeamSessionResponseDto : consultantTeamSessionResponseDtoList) { try { @@ -403,15 +354,9 @@ public void startImport() { } catch (ImportException wontImportException) { writeToImportLog(wontImportException.getMessage()); break; - } catch (FileNotFoundException fileNotFoundException) { + } catch (Exception fileNotFoundException) { fileNotFoundException.printStackTrace(); break; - } catch (IOException ioException) { - ioException.printStackTrace(); - break; - } catch (Exception exception) { - exception.printStackTrace(); - break; } } @@ -429,40 +374,13 @@ private void writeToImportLog(String message) { } try { - Files.write(Paths.get(protocolFile), (message + NEWLINE_CHAR).getBytes(IMPORT_LOG_CHARSET), + Files.write(Paths.get(protocolFile), (message + NEWLINE_CHAR).getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE, StandardOpenOption.APPEND); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } - private UserDTO getUserDTO(String username, String email) { - UserDTO userDto = new UserDTO(); - userDto.setUsername(userHelper.encodeUsername(username)); - userDto.setEmail(email); - return userDto; - } - - private Consultant getConsultant(String consultantId, String username, String firstName, - String lastName, String email, boolean isAbsent, String absenceMessage, - boolean isTeamConsultant, Long idOld, String rocketChatUserId, boolean languageFormal) { - Consultant consultant = new Consultant(); - consultant.setId(consultantId); - consultant.setUsername(username); - consultant.setFirstName(firstName); - consultant.setLastName(lastName); - consultant.setAbsent(isAbsent); - consultant.setAbsenceMessage(absenceMessage); - consultant.setIdOld(idOld); - consultant.setEmail(email); - consultant.setTeamConsultant(isTeamConsultant); - consultant.setRocketChatId(rocketChatUserId); - consultant.setLanguageFormal(languageFormal); - return consultant; - } - private ConsultantAgency getConsultantAgency(Consultant consultant, Long agencyId) { ConsultantAgency consultantAgency = new ConsultantAgency(); @@ -484,7 +402,7 @@ private ImportRecord getImportRecord(CSVRecord record) { importRecord.setLastName(StringUtils.trim(record.get(4))); String email = StringUtils.deleteWhitespace(record.get(5)); // If there is more than one email addresses...than catch the first one - if (email.indexOf(DELIMITER) != -1) { + if (email.contains(DELIMITER)) { email = email.substring(0, email.indexOf(DELIMITER)).trim(); } if (!EmailValidator.getInstance().isValid(email)) { @@ -493,7 +411,7 @@ private ImportRecord getImportRecord(CSVRecord record) { importRecord.getUsername())); } importRecord.setEmail(email); - importRecord.setAbsent((record.get(6).equals(YES)) ? true : false); + importRecord.setAbsent(record.get(6).equals(YES)); String absenceMessage = (record.get(7).trim().equals(StringUtils.EMPTY)) ? null : record.get(7).trim(); if (absenceMessage != null) { @@ -506,7 +424,7 @@ private ImportRecord getImportRecord(CSVRecord record) { @Getter @Setter - private class ImportRecord { + public static class ImportRecord { String consultantId; Long idOld; diff --git a/src/main/java/de/caritas/cob/userservice/api/service/helper/KeycloakAdminClientHelper.java b/src/main/java/de/caritas/cob/userservice/api/service/helper/KeycloakAdminClientHelper.java index 3239f4fac..94dd7f36a 100644 --- a/src/main/java/de/caritas/cob/userservice/api/service/helper/KeycloakAdminClientHelper.java +++ b/src/main/java/de/caritas/cob/userservice/api/service/helper/KeycloakAdminClientHelper.java @@ -35,7 +35,6 @@ * Helper class for the KeycloakService. Communicates to the Keycloak Admin API over the Keycloak * Admin Client. */ - @Service public class KeycloakAdminClientHelper { @@ -107,14 +106,14 @@ public KeycloakCreateUserResponseDTO createKeycloakUser(final UserDTO user) thro /** * Creates a user with firstname and lastname in Keycloak and returns its Keycloak user ID. * - * @param user {@link UserDTO} + * @param user {@link UserDTO} * @param firstName first name of user - * @param lastName last name of user + * @param lastName last name of user * @return {@link KeycloakCreateUserResponseDTO} */ @KeycloakAdminClientLogout public KeycloakCreateUserResponseDTO createKeycloakUser(final UserDTO user, - final String firstName, final String lastName) throws Exception { + final String firstName, final String lastName) { UserRepresentation kcUser = getUserRepresentation(user, firstName, lastName); Response response = getInstance().realm(KEYCLOAK_REALM).users().create(kcUser); KeycloakCreateUserResponseDTO keycloakResponse = new KeycloakCreateUserResponseDTO(); @@ -217,17 +216,16 @@ private String getCreatedUserId(final URI location) { * Assigns the role "user" to the given user ID. * * @param userId Keycloak user ID - * @throws Exception {@link Exception} */ @KeycloakAdminClientLogout - public void updateUserRole(final String userId) throws Exception { + public void updateUserRole(final String userId) { updateRole(userId, KEYCLOAK_USER_ROLE); } /** * Assigns the role with the given name to the given user ID. * - * @param userId Keycloak user ID + * @param userId Keycloak user ID * @param roleName Keycloak role name */ @KeycloakAdminClientLogout @@ -263,11 +261,11 @@ public void updateRole(final String userId, final String roleName) { /** * Updates the Keycloak password for a user. * - * @param userId Keycloak user ID + * @param userId Keycloak user ID * @param password user password */ @KeycloakAdminClientLogout - public void updatePassword(final String userId, final String password) throws Exception { + public void updatePassword(final String userId, final String password) { CredentialRepresentation newCredentials = getCredentialRepresentation(password); UserResource userResource = getInstance().realm(KEYCLOAK_REALM).users().get(userId); @@ -280,12 +278,11 @@ public void updatePassword(final String userId, final String password) throws Ex * success/error status possible, because the Keycloak Client doesn't provide one either. * * * @param userId Keycloak user ID - * @param user {@link UserDTO} + * @param user {@link UserDTO} * @return the (dummy) email address - * @throws Exception {@link Exception} */ @KeycloakAdminClientLogout - public String updateDummyEmail(final String userId, UserDTO user) throws Exception { + public String updateDummyEmail(final String userId, UserDTO user) { String dummyEmail = userHelper.getDummyEmail(userId); user.setEmail(dummyEmail); UserResource userResource = getInstance().realm(KEYCLOAK_REALM).users().get(userId); diff --git a/src/test/java/de/caritas/cob/userservice/api/admin/controller/UserAdminControllerAuthorizationIT.java b/src/test/java/de/caritas/cob/userservice/api/admin/controller/UserAdminControllerAuthorizationIT.java index 86b6a51bb..68a06a002 100644 --- a/src/test/java/de/caritas/cob/userservice/api/admin/controller/UserAdminControllerAuthorizationIT.java +++ b/src/test/java/de/caritas/cob/userservice/api/admin/controller/UserAdminControllerAuthorizationIT.java @@ -15,14 +15,18 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import com.fasterxml.jackson.databind.ObjectMapper; import de.caritas.cob.userservice.api.admin.facade.ConsultantAdminFacade; import de.caritas.cob.userservice.api.admin.report.service.ViolationReportGenerator; import de.caritas.cob.userservice.api.admin.service.ConsultingTypeAdminService; import de.caritas.cob.userservice.api.admin.service.session.SessionAdminService; import de.caritas.cob.userservice.api.authorization.Authorities.Authority; +import de.caritas.cob.userservice.api.model.CreateConsultantDTO; import javax.servlet.http.Cookie; +import org.jeasy.random.EasyRandom; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -31,6 +35,7 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; @@ -389,4 +394,57 @@ public void getConsultantAgencies_Should_ReturnOkAndCallConsultantAdminFacade_Wh verify(consultantAdminFacade, times(1)).findConsultantAgencies(eq(consultantId)); } + @Test + public void createConsultant_Should_ReturnForbiddenAndCallNoMethods_When_noCsrfTokenIsSet() + throws Exception { + mvc.perform(post(GET_CONSULTANT_PATH)) + .andExpect(status().isForbidden()); + + verifyNoMoreInteractions(consultantAdminFacade); + } + + @Test + public void createConsultant_Should_ReturnUnauthorizedAndCallNoMethods_When_noKeycloakAuthorizationIsPresent() + throws Exception { + mvc.perform(post(GET_CONSULTANT_PATH) + .cookie(CSRF_COOKIE) + .header(CSRF_HEADER, CSRF_VALUE)) + .andExpect(status().isUnauthorized()); + + verifyNoMoreInteractions(consultantAdminFacade); + } + + @Test + @WithMockUser( + authorities = {Authority.ASSIGN_CONSULTANT_TO_SESSION, Authority.ASSIGN_CONSULTANT_TO_ENQUIRY, + Authority.USE_FEEDBACK, Authority.TECHNICAL_DEFAULT, Authority.CONSULTANT_DEFAULT, + Authority.VIEW_AGENCY_CONSULTANTS, Authority.VIEW_ALL_PEER_SESSIONS, Authority.START_CHAT, + Authority.CREATE_NEW_CHAT, Authority.STOP_CHAT, Authority.UPDATE_CHAT}) + public void createConsultant_Should_ReturnForbiddenAndCallNoMethods_When_noUserAdminAuthority() + throws Exception { + mvc.perform(post(GET_CONSULTANT_PATH) + .cookie(CSRF_COOKIE) + .header(CSRF_HEADER, CSRF_VALUE)) + .andExpect(status().isForbidden()); + + verifyNoMoreInteractions(consultantAdminFacade); + } + + @Test + @WithMockUser(authorities = {Authority.USER_ADMIN}) + public void createConsultant_Should_ReturnOkAndCallConsultantAdminFilterService_When_userAdminAuthority() + throws Exception { + CreateConsultantDTO createConsultantDTO = + new EasyRandom().nextObject(CreateConsultantDTO.class); + + mvc.perform(post(GET_CONSULTANT_PATH) + .cookie(CSRF_COOKIE) + .header(CSRF_HEADER, CSRF_VALUE) + .contentType(MediaType.APPLICATION_JSON) + .content(new ObjectMapper().writeValueAsString(createConsultantDTO))) + .andExpect(status().isOk()); + + verify(consultantAdminFacade, times(1)).createNewConsultant(any()); + } + } diff --git a/src/test/java/de/caritas/cob/userservice/api/admin/controller/UserAdminControllerIT.java b/src/test/java/de/caritas/cob/userservice/api/admin/controller/UserAdminControllerIT.java index 1ec76d3c4..42f8b0282 100644 --- a/src/test/java/de/caritas/cob/userservice/api/admin/controller/UserAdminControllerIT.java +++ b/src/test/java/de/caritas/cob/userservice/api/admin/controller/UserAdminControllerIT.java @@ -7,15 +7,19 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import com.fasterxml.jackson.databind.ObjectMapper; import de.caritas.cob.userservice.api.admin.facade.ConsultantAdminFacade; import de.caritas.cob.userservice.api.admin.report.service.ViolationReportGenerator; import de.caritas.cob.userservice.api.admin.service.ConsultingTypeAdminService; import de.caritas.cob.userservice.api.admin.service.session.SessionAdminService; import de.caritas.cob.userservice.api.authorization.RoleAuthorizationAuthorityMapper; import de.caritas.cob.userservice.api.exception.httpresponses.NoContentException; +import de.caritas.cob.userservice.api.model.CreateConsultantDTO; +import org.jeasy.random.EasyRandom; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -25,6 +29,7 @@ import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.hateoas.client.LinkDiscoverers; +import org.springframework.http.MediaType; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; @@ -178,4 +183,27 @@ public void getConsultant_Should_returnNoContent_When_requiredConsultantDoesNotE .andExpect(status().isNoContent()); } + @Test + public void createConsultant_Should_returnOk_When_requiredCreateConsultantIsGiven() + throws Exception { + CreateConsultantDTO createConsultantDTO = + new EasyRandom().nextObject(CreateConsultantDTO.class); + + this.mvc.perform(post(GET_CONSULTANT_PATH) + .contentType(MediaType.APPLICATION_JSON) + .content(new ObjectMapper().writeValueAsString(createConsultantDTO))) + .andExpect(status().isOk()); + + verify(this.consultantAdminFacade, times(1)) + .createNewConsultant(any()); + } + + @Test + public void createConsultant_Should_returnBadRequest_When_requiredCreateConsultantIsMissing() + throws Exception { + this.mvc.perform(post(GET_CONSULTANT_PATH) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()); + } + } diff --git a/src/test/java/de/caritas/cob/userservice/api/admin/facade/ConsultantAdminFacadeTest.java b/src/test/java/de/caritas/cob/userservice/api/admin/facade/ConsultantAdminFacadeTest.java index 349d30993..a2767922e 100644 --- a/src/test/java/de/caritas/cob/userservice/api/admin/facade/ConsultantAdminFacadeTest.java +++ b/src/test/java/de/caritas/cob/userservice/api/admin/facade/ConsultantAdminFacadeTest.java @@ -60,4 +60,18 @@ public void findConsultantAgencies_Should_useConsultantAdminFilterService() { .findConsultantAgencies(eq(consultantId)); } + @Test + public void createNewConsultant_Should_useConsultantAdminServiceCorrectly() { + this.consultantAdminFacade.createNewConsultant(null); + + verify(this.consultantAdminService, times(1)).createNewConsultant(null); + } + + @Test + public void findConsultantAgencies_Should_useConsultantAgencyAdminServiceCorrectly() { + this.consultantAdminFacade.findConsultantAgencies(null); + + verify(this.consultantAgencyAdminService, times(1)).findConsultantAgencies(null); + } + } diff --git a/src/test/java/de/caritas/cob/userservice/api/admin/hallink/RootDTOBuilderTest.java b/src/test/java/de/caritas/cob/userservice/api/admin/hallink/RootDTOBuilderTest.java index 8977008a6..d958054d1 100644 --- a/src/test/java/de/caritas/cob/userservice/api/admin/hallink/RootDTOBuilderTest.java +++ b/src/test/java/de/caritas/cob/userservice/api/admin/hallink/RootDTOBuilderTest.java @@ -27,6 +27,15 @@ public void buildRootDTO_Should_returnRootDTOWithHalLinks() { assertThat(rootLinks.getConsultants().getMethod(), is(MethodEnum.GET)); assertThat(rootLinks.getSelf().getHref(), is("/useradmin")); assertThat(rootLinks.getSelf().getMethod(), is(MethodEnum.GET)); + assertThat(rootLinks.getConsultantAgencies(), notNullValue()); + assertThat(rootLinks.getConsultantAgencies().getHref(), + is("/useradmin/consultant/{consultantId}/agencies")); + assertThat(rootLinks.getConsultantAgencies().getMethod(), is(MethodEnum.GET)); + assertThat(rootLinks.getCreateConsultant(), notNullValue()); + assertThat(rootLinks.getCreateConsultant().getHref(), + is("/useradmin/consultant")); + assertThat(rootLinks.getCreateConsultant().getMethod(), is(MethodEnum.POST)); + } } diff --git a/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantAdminFilterServiceIT.java b/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantAdminFilterServiceIT.java index 251d99fa8..bf553a82c 100644 --- a/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantAdminFilterServiceIT.java +++ b/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantAdminFilterServiceIT.java @@ -60,7 +60,7 @@ public void findFilteredConsultants_Should_returnFullMappedConsultantSearchResul ConsultantSearchResultDTO consultants = this.consultantAdminFilterService .findFilteredConsultants(1, 1, new ConsultantFilter()); - ConsultantDTO consultantDTO = consultants.getEmbedded().iterator().next(); + ConsultantDTO consultantDTO = consultants.getEmbedded().iterator().next().getEmbedded(); assertThat(consultantDTO.getId(), notNullValue()); assertThat(consultantDTO.getUsername(), notNullValue()); assertThat(consultantDTO.getFirstname(), notNullValue()); @@ -97,7 +97,7 @@ public void findFilteredConsultants_Should_returnExpectedConsultant_When_allFilt .findFilteredConsultants(1, 100, consultantFilter); assertThat(result.getEmbedded(), hasSize(1)); - ConsultantDTO filteredConsultant = result.getEmbedded().iterator().next(); + ConsultantDTO filteredConsultant = result.getEmbedded().iterator().next().getEmbedded(); assertThat(filteredConsultant.getAbsent(), is(false)); assertThat(filteredConsultant.getEmail(), is("addiction@consultant.de")); assertThat(filteredConsultant.getLastname(), is("Consultant")); @@ -111,7 +111,8 @@ public void findFilteredConsultants_Should_returnNonAbsentConsultants_When_filte ConsultantSearchResultDTO result = this.consultantAdminFilterService .findFilteredConsultants(1, 100, consultantFilter); - result.getEmbedded().forEach(consultant -> assertThat(consultant.getAbsent(), is(false))); + result.getEmbedded() + .forEach(consultant -> assertThat(consultant.getEmbedded().getAbsent(), is(false))); } @Test @@ -121,7 +122,7 @@ public void findFilteredConsultants_Should_returnAllLastnameConsultants_When_fil ConsultantSearchResultDTO result = this.consultantAdminFilterService .findFilteredConsultants(1, 100, consultantFilter); - result.getEmbedded().forEach(consultant -> assertThat(consultant.getLastname(), + result.getEmbedded().forEach(consultant -> assertThat(consultant.getEmbedded().getLastname(), startsWith("Consultant"))); } @@ -132,7 +133,7 @@ public void findFilteredConsultants_Should_returnAllEmailConsultants_When_filter ConsultantSearchResultDTO result = this.consultantAdminFilterService .findFilteredConsultants(1, 100, consultantFilter); - result.getEmbedded().forEach(consultant -> assertThat(consultant.getEmail(), + result.getEmbedded().forEach(consultant -> assertThat(consultant.getEmbedded().getEmail(), is("addiction@caritas.de"))); } diff --git a/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantAdminServiceIT.java b/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantAdminServiceIT.java index dba8e16ec..06c9b2e00 100644 --- a/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantAdminServiceIT.java +++ b/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantAdminServiceIT.java @@ -4,17 +4,27 @@ import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.powermock.api.mockito.PowerMockito.when; import de.caritas.cob.userservice.UserServiceApplication; +import de.caritas.cob.userservice.api.admin.service.consultant.create.ConsultantCreatorService; import de.caritas.cob.userservice.api.exception.httpresponses.NoContentException; -import de.caritas.cob.userservice.api.model.GetConsultantResponseDTO; +import de.caritas.cob.userservice.api.model.ConsultantAdminResponseDTO; +import de.caritas.cob.userservice.api.model.CreateConsultantDTO; import de.caritas.cob.userservice.api.model.HalLink.MethodEnum; +import de.caritas.cob.userservice.api.repository.consultant.Consultant; +import org.jeasy.random.EasyRandom; import org.junit.Test; import org.junit.runner.RunWith; 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; @@ -29,9 +39,12 @@ public class ConsultantAdminServiceIT { @Autowired private ConsultantAdminService consultantAdminService; + @MockBean + private ConsultantCreatorService consultantCreatorService; + @Test public void findConsultantById_Should_returnExpectedConsultant_When_consultantIdExists() { - GetConsultantResponseDTO consultantById = this.consultantAdminService + ConsultantAdminResponseDTO consultantById = this.consultantAdminService .findConsultantById(EXISTING_CONSULTANT); assertThat(consultantById.getEmbedded(), notNullValue()); @@ -49,7 +62,7 @@ public void findConsultantById_Should_returnExpectedConsultant_When_consultantId @Test public void findConsultantById_Should_returnExpectedConsultantLinks_When_consultantIdExists() { - GetConsultantResponseDTO consultantById = this.consultantAdminService + ConsultantAdminResponseDTO consultantById = this.consultantAdminService .findConsultantById(EXISTING_CONSULTANT); assertThat(consultantById.getLinks(), notNullValue()); @@ -65,6 +78,14 @@ public void findConsultantById_Should_returnExpectedConsultantLinks_When_consult assertThat(consultantById.getLinks().getDelete().getHref(), endsWith("/useradmin/consultant/" + EXISTING_CONSULTANT)); assertThat(consultantById.getLinks().getDelete().getMethod(), is(MethodEnum.DELETE)); + assertThat(consultantById.getLinks().getAgencies(), notNullValue()); + assertThat(consultantById.getLinks().getAgencies().getHref(), + endsWith("/useradmin/consultant/" + EXISTING_CONSULTANT + "/agencies")); + assertThat(consultantById.getLinks().getAgencies().getMethod(), is(MethodEnum.GET)); + assertThat(consultantById.getLinks().getAddAgency(), notNullValue()); + assertThat(consultantById.getLinks().getAddAgency().getHref(), + endsWith("/useradmin/consultant/" + EXISTING_CONSULTANT + "/agency")); + assertThat(consultantById.getLinks().getAddAgency().getMethod(), is(MethodEnum.POST)); } @Test(expected = NoContentException.class) @@ -72,4 +93,19 @@ public void findConsultantById_Should_throwNoContentException_When_consultantIdD this.consultantAdminService.findConsultantById("Invalid"); } + @Test + public void createNewConsultant_Should_useCreatorServiceAndBuildConsultantAdminResponseDTO() { + CreateConsultantDTO createConsultantDTO = + new EasyRandom().nextObject(CreateConsultantDTO.class); + when(this.consultantCreatorService.createNewConsultant(any())) + .thenReturn(new EasyRandom().nextObject(Consultant.class)); + + ConsultantAdminResponseDTO result = + this.consultantAdminService.createNewConsultant(createConsultantDTO); + + verify(this.consultantCreatorService, times(1)).createNewConsultant(eq(createConsultantDTO)); + assertThat(result.getLinks(), notNullValue()); + assertThat(result.getEmbedded(), notNullValue()); + } + } diff --git a/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantCreatorServiceIT.java b/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantCreatorServiceIT.java new file mode 100644 index 000000000..bb1456ad1 --- /dev/null +++ b/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantCreatorServiceIT.java @@ -0,0 +1,157 @@ +package de.caritas.cob.userservice.api.admin.service.consultant.create; + +import static de.caritas.cob.userservice.api.authorization.UserRole.CONSULTANT; +import static de.caritas.cob.userservice.api.exception.httpresponses.customheader.HttpStatusExceptionReason.EMAIL_NOT_VALID; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hibernate.validator.internal.util.CollectionHelper.asSet; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +import de.caritas.cob.userservice.UserServiceApplication; +import de.caritas.cob.userservice.api.exception.httpresponses.CustomValidationHttpStatusException; +import de.caritas.cob.userservice.api.exception.httpresponses.InternalServerErrorException; +import de.caritas.cob.userservice.api.exception.rocketchat.RocketChatLoginException; +import de.caritas.cob.userservice.api.model.CreateConsultantDTO; +import de.caritas.cob.userservice.api.model.keycloak.KeycloakCreateUserResponseDTO; +import de.caritas.cob.userservice.api.repository.consultant.Consultant; +import de.caritas.cob.userservice.api.service.ConsultantImportService.ImportRecord; +import de.caritas.cob.userservice.api.service.RocketChatService; +import de.caritas.cob.userservice.api.service.helper.KeycloakAdminClientHelper; +import org.jeasy.random.EasyRandom; +import org.junit.Test; +import org.junit.runner.RunWith; +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; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = UserServiceApplication.class) +@TestPropertySource(properties = "spring.profiles.active=testing") +@AutoConfigureTestDatabase(replace = Replace.ANY) +public class ConsultantCreatorServiceIT { + + private static final String DUMMY_RC_ID = "rcUserId"; + private static final String VALID_USERNAME = "validUsername"; + private static final String VALID_EMAILADDRESS = "valid@emailaddress.de"; + + @Autowired + private ConsultantCreatorService consultantCreatorService; + + @MockBean + private RocketChatService rocketChatService; + + @MockBean + private KeycloakAdminClientHelper keycloakAdminClientHelper; + + private final EasyRandom easyRandom = new EasyRandom(); + + @Test + public void createNewConsultant_Should_returnExpectedCreatedConsultant_When_inputDataIsCorrect() + throws RocketChatLoginException { + when(rocketChatService.getUserID(anyString(), anyString(), anyBoolean())) + .thenReturn(DUMMY_RC_ID); + when(keycloakAdminClientHelper.createKeycloakUser(any(), anyString(), any())) + .thenReturn(easyRandom.nextObject(KeycloakCreateUserResponseDTO.class)); + CreateConsultantDTO createConsultantDTO = this.easyRandom.nextObject(CreateConsultantDTO.class); + createConsultantDTO.setUsername(VALID_USERNAME); + createConsultantDTO.setEmail(VALID_EMAILADDRESS); + + Consultant consultant = this.consultantCreatorService.createNewConsultant(createConsultantDTO); + + assertThat(consultant, notNullValue()); + assertThat(consultant.getId(), notNullValue()); + assertThat(consultant.getRocketChatId(), is(DUMMY_RC_ID)); + assertThat(consultant.getAbsenceMessage(), notNullValue()); + assertThat(consultant.getCreateDate(), notNullValue()); + assertThat(consultant.getUpdateDate(), notNullValue()); + assertThat(consultant.getUsername(), notNullValue()); + assertThat(consultant.getFirstName(), notNullValue()); + assertThat(consultant.getLastName(), notNullValue()); + assertThat(consultant.getEmail(), notNullValue()); + assertThat(consultant.getFullName(), notNullValue()); + } + + @Test + public void createNewConsultant_Should_returnExpectedCreatedConsultant_When_inputDataIsCorrectImportRecord() + throws RocketChatLoginException { + when(rocketChatService.getUserID(anyString(), anyString(), anyBoolean())) + .thenReturn(DUMMY_RC_ID); + when(keycloakAdminClientHelper.createKeycloakUser(any(), anyString(), any())) + .thenReturn(easyRandom.nextObject(KeycloakCreateUserResponseDTO.class)); + ImportRecord importRecord = this.easyRandom.nextObject(ImportRecord.class); + importRecord.setUsername(VALID_USERNAME); + importRecord.setEmail(VALID_EMAILADDRESS); + + Consultant consultant = this.consultantCreatorService.createNewConsultant(importRecord, + asSet(CONSULTANT.getValue())); + + assertThat(consultant, notNullValue()); + assertThat(consultant.getId(), notNullValue()); + assertThat(consultant.getRocketChatId(), is(DUMMY_RC_ID)); + assertThat(consultant.getAbsenceMessage(), notNullValue()); + assertThat(consultant.getCreateDate(), notNullValue()); + assertThat(consultant.getUpdateDate(), notNullValue()); + assertThat(consultant.getUsername(), notNullValue()); + assertThat(consultant.getFirstName(), notNullValue()); + assertThat(consultant.getLastName(), notNullValue()); + assertThat(consultant.getEmail(), notNullValue()); + assertThat(consultant.getFullName(), notNullValue()); + } + + @Test(expected = InternalServerErrorException.class) + public void createNewConsultant_Should_throwCustomValidationHttpStatusException_When_userCanNotBeCreatedInRocketChat() + throws RocketChatLoginException { + when(rocketChatService.getUserID(anyString(), anyString(), anyBoolean())) + .thenThrow(new RocketChatLoginException("")); + KeycloakCreateUserResponseDTO validKeycloakResponse = easyRandom.nextObject( + KeycloakCreateUserResponseDTO.class); + validKeycloakResponse.getResponseDTO().setUsernameAvailable(1); + validKeycloakResponse.getResponseDTO().setEmailAvailable(1); + when(keycloakAdminClientHelper.createKeycloakUser(any(), anyString(), any())) + .thenReturn(validKeycloakResponse); + CreateConsultantDTO createConsultantDTO = this.easyRandom.nextObject(CreateConsultantDTO.class); + createConsultantDTO.setUsername(VALID_USERNAME); + createConsultantDTO.setEmail(VALID_EMAILADDRESS); + + this.consultantCreatorService.createNewConsultant(createConsultantDTO); + } + + @Test(expected = CustomValidationHttpStatusException.class) + public void createNewConsultant_Should_throwCustomValidationHttpStatusException_When_keycloakIdIsMissing() + throws RocketChatLoginException { + when(rocketChatService.getUserID(anyString(), anyString(), anyBoolean())) + .thenReturn(DUMMY_RC_ID); + KeycloakCreateUserResponseDTO keycloakResponse = easyRandom.nextObject( + KeycloakCreateUserResponseDTO.class); + keycloakResponse.setUserId(null); + when(keycloakAdminClientHelper.createKeycloakUser(any(), anyString(), any())) + .thenReturn(keycloakResponse); + CreateConsultantDTO createConsultantDTO = this.easyRandom.nextObject(CreateConsultantDTO.class); + + this.consultantCreatorService.createNewConsultant(createConsultantDTO); + } + + @Test + public void createNewConsultant_Should_throwExpectedException_When_emailIsInvalid() { + CreateConsultantDTO createConsultantDTO = this.easyRandom.nextObject(CreateConsultantDTO.class); + createConsultantDTO.setEmail("invalid"); + + try { + this.consultantCreatorService.createNewConsultant(createConsultantDTO); + fail("Exception should be thrown"); + } catch (CustomValidationHttpStatusException e) { + assertThat(e.getCustomHttpHeader(), notNullValue()); + assertThat(e.getCustomHttpHeader().get("X-Reason").get(0), is(EMAIL_NOT_VALID.name())); + } + } + +} diff --git a/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantInputValidatorTest.java b/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantInputValidatorTest.java new file mode 100644 index 000000000..67e7d508b --- /dev/null +++ b/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantInputValidatorTest.java @@ -0,0 +1,132 @@ +package de.caritas.cob.userservice.api.admin.service.consultant.create; + +import static de.caritas.cob.userservice.api.exception.httpresponses.customheader.HttpStatusExceptionReason.EMAIL_NOT_AVAILABLE; +import static de.caritas.cob.userservice.api.exception.httpresponses.customheader.HttpStatusExceptionReason.MISSING_ABSENCE_MESSAGE_FOR_ABSENT_USER; +import static de.caritas.cob.userservice.api.exception.httpresponses.customheader.HttpStatusExceptionReason.USERNAME_NOT_AVAILABLE; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.fail; + +import de.caritas.cob.userservice.api.exception.httpresponses.CustomValidationHttpStatusException; +import de.caritas.cob.userservice.api.exception.keycloak.KeycloakException; +import de.caritas.cob.userservice.api.model.CreateConsultantDTO; +import de.caritas.cob.userservice.api.model.CreateUserResponseDTO; +import de.caritas.cob.userservice.api.model.keycloak.KeycloakCreateUserResponseDTO; +import javax.validation.Validator; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class ConsultantInputValidatorTest { + + @InjectMocks + private ConsultantInputValidator consultantInputValidator; + + @Mock + private Validator validator; + + @Test + public void validateCreateConsultantDTO_ShouldNot_throwException_When_consultantIsNotAbsent() { + CreateConsultantDTO createConsultantDTO = new CreateConsultantDTO() + .absent(false); + + try { + this.consultantInputValidator.validateCreateConsultantDTO(createConsultantDTO); + } catch (CustomValidationHttpStatusException e) { + fail("Exception should not be thrown"); + } + } + + @Test + public void validateCreateConsultantDTO_ShouldNot_throwException_When_consultantIsAbsentAndAbsenceMessageIsSet() { + CreateConsultantDTO createConsultantDTO = new CreateConsultantDTO() + .absent(true) + .absenceMessage("Absent"); + + try { + this.consultantInputValidator.validateCreateConsultantDTO(createConsultantDTO); + } catch (CustomValidationHttpStatusException e) { + fail("Exception should not be thrown"); + } + } + + @Test + public void validateCreateConsultantDTO_Should_throwExpectedException_When_consultantIsAbsentAndAbsenceMessageIsEmpty() { + CreateConsultantDTO createConsultantDTO = new CreateConsultantDTO() + .absent(true) + .absenceMessage(null); + + try { + this.consultantInputValidator.validateCreateConsultantDTO(createConsultantDTO); + fail("Exception should be thrown"); + } catch (CustomValidationHttpStatusException e) { + assertThat(e.getCustomHttpHeader(), notNullValue()); + assertThat(e.getCustomHttpHeader().get("X-Reason").get(0), + is(MISSING_ABSENCE_MESSAGE_FOR_ABSENT_USER.name())); + } + } + + @Test + public void validateKeycloakResponse_ShouldNot_throwException_When_keycloakResponseDTOIsValid() { + KeycloakCreateUserResponseDTO responseDTO = new KeycloakCreateUserResponseDTO(); + responseDTO.setUserId("userId"); + + try { + this.consultantInputValidator.validateKeycloakResponse(responseDTO); + } catch (Exception e) { + fail("Exception should not be thrown"); + } + } + + @Test(expected = KeycloakException.class) + public void validateKeycloakResponse_Should_throwKeycloakException_When_userIdIsNullAndUsernameAndEmailIsValid() { + KeycloakCreateUserResponseDTO responseDTO = new KeycloakCreateUserResponseDTO(); + CreateUserResponseDTO createUserResponseDTO = new CreateUserResponseDTO(); + createUserResponseDTO.setEmailAvailable(1); + createUserResponseDTO.setUsernameAvailable(1); + responseDTO.setResponseDTO(createUserResponseDTO); + + this.consultantInputValidator.validateKeycloakResponse(responseDTO); + } + + @Test + public void validateKeycloakResponse_Should_throwExpectedException_When_userIdIsNullAndUsernameIsInvalid() { + KeycloakCreateUserResponseDTO responseDTO = new KeycloakCreateUserResponseDTO(); + CreateUserResponseDTO createUserResponseDTO = new CreateUserResponseDTO(); + createUserResponseDTO.setEmailAvailable(1); + createUserResponseDTO.setUsernameAvailable(0); + responseDTO.setResponseDTO(createUserResponseDTO); + + try { + this.consultantInputValidator.validateKeycloakResponse(responseDTO); + fail("Exception should be thrown"); + } catch (CustomValidationHttpStatusException e) { + assertThat(e.getCustomHttpHeader(), notNullValue()); + assertThat(e.getCustomHttpHeader().get("X-Reason").get(0), + is(USERNAME_NOT_AVAILABLE.name())); + } + } + + @Test + public void validateKeycloakResponse_Should_throwExpectedException_When_userIdIsNullAndEmailIsInvalid() { + KeycloakCreateUserResponseDTO responseDTO = new KeycloakCreateUserResponseDTO(); + CreateUserResponseDTO createUserResponseDTO = new CreateUserResponseDTO(); + createUserResponseDTO.setEmailAvailable(0); + createUserResponseDTO.setUsernameAvailable(1); + responseDTO.setResponseDTO(createUserResponseDTO); + + try { + this.consultantInputValidator.validateKeycloakResponse(responseDTO); + fail("Exception should be thrown"); + } catch (CustomValidationHttpStatusException e) { + assertThat(e.getCustomHttpHeader(), notNullValue()); + assertThat(e.getCustomHttpHeader().get("X-Reason").get(0), + is(EMAIL_NOT_AVAILABLE.name())); + } + } + +} diff --git a/src/test/java/de/caritas/cob/userservice/api/service/KeycloakServiceTest.java b/src/test/java/de/caritas/cob/userservice/api/service/KeycloakServiceTest.java index b4d09dc42..caebef853 100644 --- a/src/test/java/de/caritas/cob/userservice/api/service/KeycloakServiceTest.java +++ b/src/test/java/de/caritas/cob/userservice/api/service/KeycloakServiceTest.java @@ -89,10 +89,9 @@ public void changePassword_Should_ReturnTrue_WhenKeycloakPasswordChangeWasSucces } @Test - public void changePassword_Should_ReturnFalseAndLogError_WhenKeycloakPasswordChangeFailsWithException() - throws Exception { + public void changePassword_Should_ReturnFalseAndLogError_WhenKeycloakPasswordChangeFailsWithException() { - Exception exception = new Exception(); + Exception exception = new RuntimeException(); doThrow(exception).when(keycloakAdminClientHelper).updatePassword(USER_ID, NEW_PW); assertFalse(keycloakService.changePassword(USER_ID, NEW_PW));