diff --git a/api/useradminservice.yaml b/api/useradminservice.yaml index 7fd27b6bb..64ebedd98 100644 --- a/api/useradminservice.yaml +++ b/api/useradminservice.yaml @@ -558,6 +558,68 @@ paths: description: INTERNAL SERVER ERROR - server encountered unexpected condition security: - Bearer: [ ] + + /useradmin/agencyadmins/search: + get: + tags: + - admin-user-controller + summary: 'Get Agency admins matching the given query [Auth: user-admin]' + operationId: searchAgencyAdmins + parameters: + - name: query + in: query + description: URL-encoded infix to search for in first name, last name, or email. + A non-encoded star symbol searches for all. + required: true + schema: + type: string + minLength: 1 + - name: page + in: query + description: Page number (first page = 1) + schema: + type: integer + default: 1 + minimum: 1 + - name: perPage + in: query + description: Number of items returned per page + schema: + type: integer + default: 10 + minimum: 1 + - name: field + in: query + description: field to sort by + schema: + type: string + enum: [ FIRSTNAME, LASTNAME, EMAIL ] + default: FIRSTNAME + pattern: '^(FIRSTNAME|LASTNAME|EMAIL)$' + - name: order + in: query + description: sort order + schema: + type: string + enum: [ ASC, DESC ] + default: ASC + pattern: '^(ASC|DESC)$' + responses: + 200: + description: OK - successful operation + content: + 'application/hal+json': + schema: + $ref: '#/components/schemas/AgencyAdminSearchResultDTO' + 400: + description: BAD REQUEST - invalid/incomplete request or body object + 401: + description: UNAUTHORIZED - no/invalid role/authorization + 500: + description: INTERNAL SERVER ERROR - server encountered unexpected condition + security: + - Bearer: [ ] + /useradmin/agencyadmins/{adminId}: get: tags: @@ -1181,6 +1243,8 @@ components: $ref: '#/components/schemas/HalLink' agencies: $ref: '#/components/schemas/HalLink' + addAgency: + $ref: '#/components/schemas/HalLink' SessionFilter: type: object diff --git a/src/main/java/de/caritas/cob/userservice/api/UserServiceMapper.java b/src/main/java/de/caritas/cob/userservice/api/UserServiceMapper.java index 469ce4eca..b6b994c87 100644 --- a/src/main/java/de/caritas/cob/userservice/api/UserServiceMapper.java +++ b/src/main/java/de/caritas/cob/userservice/api/UserServiceMapper.java @@ -7,6 +7,9 @@ import com.neovisionaries.i18n.LanguageCode; import de.caritas.cob.userservice.api.adapters.web.dto.AgencyDTO; import de.caritas.cob.userservice.api.helper.UsernameTranscoder; +import de.caritas.cob.userservice.api.model.Admin; +import de.caritas.cob.userservice.api.model.Admin.AdminBase; +import de.caritas.cob.userservice.api.model.AdminAgency.AdminAgencyBase; import de.caritas.cob.userservice.api.model.Appointment; import de.caritas.cob.userservice.api.model.Appointment.AppointmentStatus; import de.caritas.cob.userservice.api.model.Consultant; @@ -121,6 +124,40 @@ public Map mapOf( consultants); } + public Map mapOfAdmin( + Page adminsPage, + List fullAdmins, + List agencyDTOs, + List agenciesOfAdmin) { + var agencyLookupMap = + agencyDTOs.stream().collect(Collectors.toMap(AgencyDTO::getId, Function.identity())); + + var fullAdminLookupMap = + fullAdmins.stream().collect(Collectors.toMap(Admin::getId, Function.identity())); + + var adminAgencyLookupMap = + agenciesOfAdmin.stream().collect(Collectors.groupingBy(AdminAgencyBase::getAdminId)); + + var admins = new ArrayList>(); + adminsPage.forEach( + adminBase -> { + var fullAdmin = fullAdminLookupMap.get(adminBase.getId()); + var agencies = mapOfAdmin(fullAdmin, agencyLookupMap, adminAgencyLookupMap); + var consultantMap = mapOfAdmin(adminBase, fullAdmin, agencies); + admins.add(consultantMap); + }); + + return Map.of( + "totalElements", + (int) adminsPage.getTotalElements(), + "isFirstPage", + adminsPage.isFirst(), + "isLastPage", + adminsPage.isLast(), + "admins", + admins); + } + private List> mapOf( Consultant consultant, Map agencyLookupMap, @@ -147,6 +184,31 @@ && isAgencyUnique(agencyIdsAdded, agencyId)) { return agencies; } + private List> mapOfAdmin( + Admin admin, + Map agencyLookupMap, + Map> aaLookupMap) { + var agencies = new ArrayList>(); + var agencyIdsAdded = new HashSet(); + + if (aaLookupMap.containsKey(admin.getId())) { + aaLookupMap + .get(admin.getId()) + .forEach( + adminAgency -> { + var agencyId = adminAgency.getAgencyId(); + if (agencyLookupMap.containsKey(agencyId) + && isAgencyUnique(agencyIdsAdded, agencyId)) { + var agencyDTO = agencyLookupMap.get(agencyId); + agencies.add(mapOf(agencyDTO)); + agencyIdsAdded.add(agencyId); + } + }); + } + + return agencies; + } + private Map mapOf(AgencyDTO agencyDTO) { Map agencyMap = new HashMap<>(); agencyMap.put("id", agencyDTO.getId()); @@ -195,6 +257,26 @@ public Map mapOf( return map; } + public Map mapOfAdmin( + AdminBase adminBase, Admin fullAdmin, List> agencies) { + + Map map = new HashMap<>(); + map.put("id", adminBase.getId()); + map.put("email", adminBase.getEmail()); + map.put("firstName", adminBase.getFirstName()); + map.put("lastName", adminBase.getLastName()); + map.put("username", fullAdmin.getUsername()); + map.put( + "createdAt", + nonNull(fullAdmin.getCreateDate()) ? fullAdmin.getCreateDate().toString() : null); + map.put( + "updatedAt", + nonNull(fullAdmin.getUpdateDate()) ? fullAdmin.getUpdateDate().toString() : null); + map.put("agencies", agencies); + + return map; + } + public Optional> mapOf(Optional optionalSession) { if (optionalSession.isEmpty()) { return Optional.empty(); diff --git a/src/main/java/de/caritas/cob/userservice/api/adapters/web/controller/UserAdminController.java b/src/main/java/de/caritas/cob/userservice/api/adapters/web/controller/UserAdminController.java index 371d5e60d..636118a50 100644 --- a/src/main/java/de/caritas/cob/userservice/api/adapters/web/controller/UserAdminController.java +++ b/src/main/java/de/caritas/cob/userservice/api/adapters/web/controller/UserAdminController.java @@ -21,15 +21,19 @@ import de.caritas.cob.userservice.api.adapters.web.dto.UpdateAdminConsultantDTO; import de.caritas.cob.userservice.api.adapters.web.dto.UpdateAgencyAdminDTO; import de.caritas.cob.userservice.api.adapters.web.dto.ViolationDTO; +import de.caritas.cob.userservice.api.adapters.web.mapping.AdminAgencyDtoMapper; import de.caritas.cob.userservice.api.admin.facade.AdminAgencyFacade; import de.caritas.cob.userservice.api.admin.facade.ConsultantAdminFacade; import de.caritas.cob.userservice.api.admin.facade.UserAdminFacade; import de.caritas.cob.userservice.api.admin.hallink.RootDTOBuilder; import de.caritas.cob.userservice.api.admin.report.service.ViolationReportGenerator; import de.caritas.cob.userservice.api.admin.service.session.SessionAdminService; +import de.caritas.cob.userservice.api.helper.AuthenticatedUser; import de.caritas.cob.userservice.api.service.appointment.AppointmentService; import de.caritas.cob.userservice.generated.api.adapters.web.controller.UseradminApi; import io.swagger.annotations.Api; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import javax.validation.Valid; @@ -53,6 +57,8 @@ public class UserAdminController implements UseradminApi { private final @NonNull UserAdminFacade userAdminFacade; private final @NonNull AdminAgencyFacade adminAgencyFacade; private final @NonNull AppointmentService appointmentService; + private final @NonNull AdminAgencyDtoMapper adminAgencyDtoMapper; + private final @NotNull AuthenticatedUser authenticatedUser; /** * Creates the root hal based navigation entity. @@ -317,4 +323,25 @@ public ResponseEntity setAdminAgenciesRelation( this.adminAgencyFacade.setAdminAgenciesRelation(adminId, newAdminAgencyRelationDTOs); return new ResponseEntity<>(HttpStatus.OK); } + + @Override + public ResponseEntity searchAgencyAdmins( + String query, Integer page, Integer perPage, String field, String order) { + var decodedInfix = URLDecoder.decode(query, StandardCharsets.UTF_8).trim(); + var isAscending = order.equalsIgnoreCase("asc"); + var mappedField = adminAgencyDtoMapper.mappedFieldOf(field); + var resultMap = + adminAgencyFacade.findAgencyAdminsByInfix( + decodedInfix, + authenticatedUser.getUserId(), + page - 1, + perPage, + mappedField, + isAscending); + var result = + adminAgencyDtoMapper.agencyAdminSearchResultOf( + resultMap, query, page, perPage, field, order); + + return ResponseEntity.ok(result); + } } diff --git a/src/main/java/de/caritas/cob/userservice/api/adapters/web/mapping/AdminAgencyDtoMapper.java b/src/main/java/de/caritas/cob/userservice/api/adapters/web/mapping/AdminAgencyDtoMapper.java new file mode 100644 index 000000000..6b14bd2a1 --- /dev/null +++ b/src/main/java/de/caritas/cob/userservice/api/adapters/web/mapping/AdminAgencyDtoMapper.java @@ -0,0 +1,134 @@ +package de.caritas.cob.userservice.api.adapters.web.mapping; + +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; + +import de.caritas.cob.userservice.api.adapters.web.controller.UserAdminController; +import de.caritas.cob.userservice.api.adapters.web.dto.AdminDTO; +import de.caritas.cob.userservice.api.adapters.web.dto.AdminLinks; +import de.caritas.cob.userservice.api.adapters.web.dto.AdminResponseDTO; +import de.caritas.cob.userservice.api.adapters.web.dto.AgencyAdminResponseDTO; +import de.caritas.cob.userservice.api.adapters.web.dto.AgencyAdminSearchResultDTO; +import de.caritas.cob.userservice.api.adapters.web.dto.HalLink; +import de.caritas.cob.userservice.api.adapters.web.dto.HalLink.MethodEnum; +import de.caritas.cob.userservice.api.adapters.web.dto.PaginationLinks; +import de.caritas.cob.userservice.generated.api.adapters.web.controller.UseradminApi; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.springframework.http.HttpEntity; +import org.springframework.stereotype.Service; + +@Service +public class AdminAgencyDtoMapper implements DtoMapperUtils { + + public AgencyAdminSearchResultDTO agencyAdminSearchResultOf( + Map resultMap, + String query, + Integer page, + Integer perPage, + String field, + String order) { + var admins = new ArrayList(); + + var adminMaps = (List>) resultMap.get("admins"); + adminMaps.forEach( + adminMap -> { + var response = new AdminResponseDTO(); + response.setEmbedded(adminDtoOf(adminMap)); + response.setLinks(consultantLinksOf(adminMap)); + admins.add(response); + }); + + var result = new AgencyAdminSearchResultDTO(); + result.setTotal((Integer) resultMap.get("totalElements")); + result.setEmbedded(admins); + + var pagination = new PaginationLinks().self(pageLinkOf(query, page, perPage, field, order)); + if (!(boolean) resultMap.get("isFirstPage")) { + pagination.previous(pageLinkOf(query, page - 1, perPage, field, order)); + } + if (!(boolean) resultMap.get("isLastPage")) { + pagination.next(pageLinkOf(query, page + 1, perPage, field, order)); + } + result.setLinks(pagination); + + return result; + } + + public AdminLinks consultantLinksOf(Map adminMap) { + var id = (String) adminMap.get("id"); + + return new AdminLinks() + .self(adminLinkOf(id, MethodEnum.GET)) + .update(adminLinkOf(id, MethodEnum.PUT)) + .delete(adminLinkOf(id, MethodEnum.DELETE)) + .agencies(adminAgencyLinkOf(id, MethodEnum.GET)) + .addAgency(adminAgencyLinkOf(id, MethodEnum.POST)); + } + + public HalLink adminAgencyLinkOf(String id, MethodEnum method) { + var userAdminApi = methodOn(UseradminApi.class); + HttpEntity httpEntity; + if (method == MethodEnum.POST) { + httpEntity = userAdminApi.createAdminAgencyRelation(id, null); + } else { + httpEntity = userAdminApi.getAdminAgencies(id); + } + + return halLinkOf(httpEntity, method); + } + + private HalLink pageLinkOf(String query, int page, int perPage, String field, String order) { + var httpEntity = + methodOn(UserAdminController.class).searchAgencyAdmins(query, page, perPage, field, order); + + return halLinkOf(httpEntity, MethodEnum.GET); + } + + public HalLink adminLinkOf(String id, MethodEnum method) { + var userAdminApi = methodOn(UseradminApi.class); + HttpEntity httpEntity; + switch (method) { + case PUT: + httpEntity = userAdminApi.updateAgencyAdmin(id, null); + break; + case DELETE: + httpEntity = userAdminApi.deleteAgencyAdmin(id); + break; + default: + httpEntity = userAdminApi.getAgencyAdmin(id); + } + + return halLinkOf(httpEntity, method); + } + + private AdminDTO adminDtoOf(Map consultantMap) { + var adminDTO = new AdminDTO(); + adminDTO.setId((String) consultantMap.get("id")); + adminDTO.setEmail((String) consultantMap.get("email")); + adminDTO.setFirstname((String) consultantMap.get("firstName")); + adminDTO.setLastname((String) consultantMap.get("lastName")); + adminDTO.setUsername((String) consultantMap.get("username")); + adminDTO.setCreateDate((String) consultantMap.get("createdAt")); + adminDTO.setUpdateDate((String) consultantMap.get("updatedAt")); + + var agencies = new ArrayList(); + var agencyMaps = (ArrayList>) consultantMap.get("agencies"); + agencyMaps.forEach( + agencyMap -> { + var agency = new AgencyAdminResponseDTO(); + agency.setId((Long) agencyMap.get("id")); + agency.setName((String) agencyMap.get("name")); + agency.setPostcode((String) agencyMap.get("postcode")); + agency.setCity((String) agencyMap.get("city")); + agency.setDescription((String) agencyMap.get("description")); + agency.setTeamAgency((Boolean) agencyMap.get("isTeamAgency")); + agency.setOffline((Boolean) agencyMap.get("isOffline")); + agency.setConsultingType((Integer) agencyMap.get("consultingType")); + agencies.add(agency); + }); + adminDTO.setAgencies(agencies); + + return adminDTO; + } +} diff --git a/src/main/java/de/caritas/cob/userservice/api/adapters/web/mapping/ConsultantDtoMapper.java b/src/main/java/de/caritas/cob/userservice/api/adapters/web/mapping/ConsultantDtoMapper.java index 28704d71a..422f89cc8 100644 --- a/src/main/java/de/caritas/cob/userservice/api/adapters/web/mapping/ConsultantDtoMapper.java +++ b/src/main/java/de/caritas/cob/userservice/api/adapters/web/mapping/ConsultantDtoMapper.java @@ -1,13 +1,10 @@ package de.caritas.cob.userservice.api.adapters.web.mapping; -import static java.util.Objects.isNull; -import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; import de.caritas.cob.userservice.api.adapters.web.controller.UserController; import de.caritas.cob.userservice.api.adapters.web.dto.AgencyAdminResponseDTO; import de.caritas.cob.userservice.api.adapters.web.dto.AgencyDTO; -import de.caritas.cob.userservice.api.adapters.web.dto.AgencyResponseDTO; import de.caritas.cob.userservice.api.adapters.web.dto.ConsultantAdminResponseDTO; import de.caritas.cob.userservice.api.adapters.web.dto.ConsultantDTO; import de.caritas.cob.userservice.api.adapters.web.dto.ConsultantLinks; @@ -15,8 +12,6 @@ import de.caritas.cob.userservice.api.adapters.web.dto.ConsultantSearchResultDTO; import de.caritas.cob.userservice.api.adapters.web.dto.HalLink; import de.caritas.cob.userservice.api.adapters.web.dto.HalLink.MethodEnum; -import de.caritas.cob.userservice.api.adapters.web.dto.LanguageCode; -import de.caritas.cob.userservice.api.adapters.web.dto.LanguageResponseDTO; import de.caritas.cob.userservice.api.adapters.web.dto.PaginationLinks; import de.caritas.cob.userservice.api.adapters.web.dto.UpdateAdminConsultantDTO; import de.caritas.cob.userservice.api.adapters.web.dto.UpdateConsultantDTO; @@ -25,13 +20,12 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.stream.Collectors; import org.springframework.http.HttpEntity; import org.springframework.stereotype.Service; @Service -public class ConsultantDtoMapper { +public class ConsultantDtoMapper implements DtoMapperUtils { public UpdateAdminConsultantDTO updateAdminConsultantOf( UpdateConsultantDTO updateConsultantDTO, Consultant consultant) { @@ -61,38 +55,6 @@ public ConsultantResponseDTO consultantResponseDtoOf( return consultantResponseDto; } - public String languageOf(LanguageCode languageCode) { - return isNull(languageCode) ? null : languageCode.getValue(); - } - - public List languageStringsOf(List languages) { - return isNull(languages) - ? null - : languages.stream().map(this::languageOf).collect(Collectors.toList()); - } - - public AgencyResponseDTO agencyResponseDtoOf(AgencyDTO agencyDTO) { - return new AgencyResponseDTO() - .id(agencyDTO.getId()) - .city(agencyDTO.getCity()) - .consultingType(agencyDTO.getConsultingType()) - .postcode(agencyDTO.getPostcode()) - .name(agencyDTO.getName()) - .description(agencyDTO.getDescription()) - .teamAgency(agencyDTO.getTeamAgency()) - .offline(agencyDTO.getOffline()); - } - - public LanguageResponseDTO languageResponseDtoOf(Set languageCodes) { - var languages = - languageCodes.stream().sorted().map(LanguageCode::fromValue).collect(Collectors.toList()); - - var dto = new LanguageResponseDTO(); - dto.setLanguages(languages); - - return dto; - } - @SuppressWarnings("unchecked") public ConsultantSearchResultDTO consultantSearchResultOf( Map resultMap, @@ -211,32 +173,4 @@ public HalLink pageLinkOf(String query, int page, int perPage, String field, Str return halLinkOf(httpEntity, MethodEnum.GET); } - - public HalLink halLinkOf(HttpEntity httpEntity, MethodEnum method) { - var link = linkTo(httpEntity).withSelfRel(); - - return new HalLink().href(link.getHref()).method(method).templated(link.isTemplated()); - } - - public String mappedFieldOf(String field) { - switch (field) { - case "FIRSTNAME": - return "firstName"; - case "LASTNAME": - return "lastName"; - case "EMAIL": - return "email"; - default: - } - - throw new IllegalArgumentException("Mapping of field '" + field + "' not supported."); - } - - public String chatIdOf(Map sessionMap) { - if (sessionMap.containsKey("chatId")) { - return sessionMap.get("chatId"); - } - - return null; - } } diff --git a/src/main/java/de/caritas/cob/userservice/api/adapters/web/mapping/DtoMapperUtils.java b/src/main/java/de/caritas/cob/userservice/api/adapters/web/mapping/DtoMapperUtils.java new file mode 100644 index 000000000..d9f82b398 --- /dev/null +++ b/src/main/java/de/caritas/cob/userservice/api/adapters/web/mapping/DtoMapperUtils.java @@ -0,0 +1,79 @@ +package de.caritas.cob.userservice.api.adapters.web.mapping; + +import static java.util.Objects.isNull; +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; + +import de.caritas.cob.userservice.api.adapters.web.dto.AgencyDTO; +import de.caritas.cob.userservice.api.adapters.web.dto.AgencyResponseDTO; +import de.caritas.cob.userservice.api.adapters.web.dto.HalLink; +import de.caritas.cob.userservice.api.adapters.web.dto.HalLink.MethodEnum; +import de.caritas.cob.userservice.api.adapters.web.dto.LanguageCode; +import de.caritas.cob.userservice.api.adapters.web.dto.LanguageResponseDTO; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import org.springframework.http.HttpEntity; + +public interface DtoMapperUtils { + + default String languageOf(LanguageCode languageCode) { + return isNull(languageCode) ? null : languageCode.getValue(); + } + + default List languageStringsOf(List languages) { + return isNull(languages) + ? null + : languages.stream().map(this::languageOf).collect(Collectors.toList()); + } + + default AgencyResponseDTO agencyResponseDtoOf(AgencyDTO agencyDTO) { + return new AgencyResponseDTO() + .id(agencyDTO.getId()) + .city(agencyDTO.getCity()) + .consultingType(agencyDTO.getConsultingType()) + .postcode(agencyDTO.getPostcode()) + .name(agencyDTO.getName()) + .description(agencyDTO.getDescription()) + .teamAgency(agencyDTO.getTeamAgency()) + .offline(agencyDTO.getOffline()); + } + + default LanguageResponseDTO languageResponseDtoOf(Set languageCodes) { + var languages = + languageCodes.stream().sorted().map(LanguageCode::fromValue).collect(Collectors.toList()); + + var dto = new LanguageResponseDTO(); + dto.setLanguages(languages); + + return dto; + } + + default HalLink halLinkOf(HttpEntity httpEntity, MethodEnum method) { + var link = linkTo(httpEntity).withSelfRel(); + + return new HalLink().href(link.getHref()).method(method).templated(link.isTemplated()); + } + + default String mappedFieldOf(String field) { + switch (field) { + case "FIRSTNAME": + return "firstName"; + case "LASTNAME": + return "lastName"; + case "EMAIL": + return "email"; + default: + } + + throw new IllegalArgumentException("Mapping of field '" + field + "' not supported."); + } + + default String chatIdOf(Map sessionMap) { + if (sessionMap.containsKey("chatId")) { + return sessionMap.get("chatId"); + } + + return null; + } +} diff --git a/src/main/java/de/caritas/cob/userservice/api/admin/facade/AdminAgencyFacade.java b/src/main/java/de/caritas/cob/userservice/api/admin/facade/AdminAgencyFacade.java index d5a6ad237..6933c8c55 100644 --- a/src/main/java/de/caritas/cob/userservice/api/admin/facade/AdminAgencyFacade.java +++ b/src/main/java/de/caritas/cob/userservice/api/admin/facade/AdminAgencyFacade.java @@ -13,9 +13,12 @@ import de.caritas.cob.userservice.api.admin.service.admin.AdminAgencyService; import de.caritas.cob.userservice.api.admin.service.admin.search.AdminFilterService; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import lombok.NonNull; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort.Direction; import org.springframework.stereotype.Service; @Service @@ -80,4 +83,16 @@ private void enrichAdminsWithAgencies(AgencyAdminSearchResultDTO filteredAdmins) adminAgencyRelationService.appendAgenciesForAdmins(admins); } } + + public Map findAgencyAdminsByInfix( + final String infix, + final String adminId, + final int pageNumber, + final int pageSize, + final String fieldName, + final boolean isAscending) { + var direction = isAscending ? Direction.ASC : Direction.DESC; + var pageRequest = PageRequest.of(pageNumber, pageSize, direction, fieldName); + return this.adminAgencyService.findAgencyAdminsByInfix(infix, adminId, pageRequest); + } } diff --git a/src/main/java/de/caritas/cob/userservice/api/admin/service/admin/AdminAgencyRelationService.java b/src/main/java/de/caritas/cob/userservice/api/admin/service/admin/AdminAgencyRelationService.java index 514ece933..3d219de6a 100644 --- a/src/main/java/de/caritas/cob/userservice/api/admin/service/admin/AdminAgencyRelationService.java +++ b/src/main/java/de/caritas/cob/userservice/api/admin/service/admin/AdminAgencyRelationService.java @@ -11,6 +11,7 @@ import de.caritas.cob.userservice.api.admin.service.agency.AgencyAdminService; import de.caritas.cob.userservice.api.exception.httpresponses.CustomValidationHttpStatusException; import de.caritas.cob.userservice.api.model.AdminAgency; +import de.caritas.cob.userservice.api.model.AdminAgency.AdminAgencyBase; import de.caritas.cob.userservice.api.port.out.AdminAgencyRepository; import java.util.List; import java.util.Set; @@ -57,7 +58,7 @@ public void appendAgenciesForAdmins(final Set admins) { var adminAgencies = adminAgencyRepository.findByAdminIdIn(adminIds); var agencyIds = - adminAgencies.stream().map(AdminAgency::getAgencyId).collect(Collectors.toSet()); + adminAgencies.stream().map(AdminAgencyBase::getAgencyId).collect(Collectors.toSet()); var agencies = this.agencyAdminService.retrieveAllAgencies().stream() @@ -71,12 +72,12 @@ public void appendAgenciesForAdmins(final Set admins) { private List resolveAgenciesOfAdmin( final String adminId, - final List adminAgencies, + final List adminAgencies, final List agencies) { var agencyIdsOfAdmin = adminAgencies.stream() - .filter(adminAgency -> adminId.equals(adminAgency.getAdmin().getId())) - .map(AdminAgency::getAgencyId) + .filter(adminAgency -> adminId.equals(adminAgency.getAdminId())) + .map(AdminAgencyBase::getAgencyId) .collect(Collectors.toList()); return agencies.stream() diff --git a/src/main/java/de/caritas/cob/userservice/api/admin/service/admin/AdminAgencyService.java b/src/main/java/de/caritas/cob/userservice/api/admin/service/admin/AdminAgencyService.java index ae4c63982..f4a0a5b66 100644 --- a/src/main/java/de/caritas/cob/userservice/api/admin/service/admin/AdminAgencyService.java +++ b/src/main/java/de/caritas/cob/userservice/api/admin/service/admin/AdminAgencyService.java @@ -1,5 +1,6 @@ package de.caritas.cob.userservice.api.admin.service.admin; +import de.caritas.cob.userservice.api.UserServiceMapper; import de.caritas.cob.userservice.api.adapters.web.dto.AdminResponseDTO; import de.caritas.cob.userservice.api.adapters.web.dto.CreateAgencyAdminDTO; import de.caritas.cob.userservice.api.adapters.web.dto.UpdateAgencyAdminDTO; @@ -7,11 +8,17 @@ import de.caritas.cob.userservice.api.admin.service.admin.delete.DeleteAdminService; import de.caritas.cob.userservice.api.admin.service.admin.search.RetrieveAdminService; import de.caritas.cob.userservice.api.admin.service.admin.update.UpdateAdminService; -import de.caritas.cob.userservice.api.admin.service.agency.AgencyAdminService; import de.caritas.cob.userservice.api.model.Admin; +import de.caritas.cob.userservice.api.model.Admin.AdminBase; +import de.caritas.cob.userservice.api.model.AdminAgency.AdminAgencyBase; +import de.caritas.cob.userservice.api.service.agency.AgencyService; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import lombok.NonNull; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; @Service @@ -22,7 +29,8 @@ public class AdminAgencyService { private final @NonNull CreateAdminService createAdminService; private final @NonNull UpdateAdminService updateAdminService; private final @NonNull DeleteAdminService deleteAdminService; - private final @NonNull AgencyAdminService agencyService; + private final @NonNull UserServiceMapper userServiceMapper; + private final @NonNull AgencyService agencyService; public AdminResponseDTO createNewAdminAgency(final CreateAgencyAdminDTO createAgencyAdminDTO) { final Admin newAdmin = createAdminService.createNewAdminAgency(createAgencyAdminDTO); @@ -45,7 +53,24 @@ public void deleteAgencyAdmin(final String adminId) { } public List findAgenciesOfAdmin(final String adminId) { - var adminAgencyIds = retrieveAdminService.findAgencyIdsOfAdmin(adminId); - return adminAgencyIds; + return retrieveAdminService.findAgencyIdsOfAdmin(adminId); + } + + public Map findAgencyAdminsByInfix( + String infix, String adminId, PageRequest pageRequest) { + Page adminsPage = retrieveAdminService.findAllByInfix(infix, pageRequest); + var adminIds = adminsPage.stream().map(AdminBase::getId).collect(Collectors.toSet()); + var fullAdmins = retrieveAdminService.findAllById(adminIds); + + var agenciesOfAdmin = retrieveAdminService.agenciesOfAdmin(adminIds); + var agencyIds = + agenciesOfAdmin.stream() + .map(AdminAgencyBase::getAgencyId) + .distinct() + .collect(Collectors.toList()); + + var agencies = agencyService.getAgenciesWithoutCaching(agencyIds); + + return userServiceMapper.mapOfAdmin(adminsPage, fullAdmins, agencies, agenciesOfAdmin); } } diff --git a/src/main/java/de/caritas/cob/userservice/api/admin/service/admin/search/AdminFilterService.java b/src/main/java/de/caritas/cob/userservice/api/admin/service/admin/search/AdminFilterService.java index 0d42f4fac..b8973f04c 100644 --- a/src/main/java/de/caritas/cob/userservice/api/admin/service/admin/search/AdminFilterService.java +++ b/src/main/java/de/caritas/cob/userservice/api/admin/service/admin/search/AdminFilterService.java @@ -9,7 +9,6 @@ import de.caritas.cob.userservice.api.admin.service.admin.AdminSearchResultBuilder; import de.caritas.cob.userservice.api.admin.service.admin.search.querybuilder.AdminFilterQueryBuilder; import de.caritas.cob.userservice.api.model.Admin; -import de.caritas.cob.userservice.api.model.Consultant; import java.util.function.Predicate; import java.util.stream.Stream; import javax.persistence.EntityManagerFactory; @@ -54,11 +53,7 @@ protected FullTextQuery buildFilteredQuery( AdminFilter adminFilter, FullTextEntityManager fullTextEntityManager) { var queryBuilder = - fullTextEntityManager - .getSearchFactory() - .buildQueryBuilder() - .forEntity(Consultant.class) - .get(); + fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(Admin.class).get(); var query = AdminFilterQueryBuilder.getInstance(queryBuilder).onAdminFilter(adminFilter).buildQuery(); diff --git a/src/main/java/de/caritas/cob/userservice/api/admin/service/admin/search/RetrieveAdminService.java b/src/main/java/de/caritas/cob/userservice/api/admin/service/admin/search/RetrieveAdminService.java index 0c38a72d1..0547e9359 100644 --- a/src/main/java/de/caritas/cob/userservice/api/admin/service/admin/search/RetrieveAdminService.java +++ b/src/main/java/de/caritas/cob/userservice/api/admin/service/admin/search/RetrieveAdminService.java @@ -3,14 +3,19 @@ import de.caritas.cob.userservice.api.exception.httpresponses.BadRequestException; import de.caritas.cob.userservice.api.exception.httpresponses.NoContentException; import de.caritas.cob.userservice.api.model.Admin; +import de.caritas.cob.userservice.api.model.Admin.AdminBase; import de.caritas.cob.userservice.api.model.AdminAgency; +import de.caritas.cob.userservice.api.model.AdminAgency.AdminAgencyBase; import de.caritas.cob.userservice.api.port.out.AdminAgencyRepository; import de.caritas.cob.userservice.api.port.out.AdminRepository; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; import lombok.NonNull; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; @Service @@ -38,4 +43,16 @@ public List findAgencyIdsOfAdmin(final String adminId) { .map(AdminAgency::getAgencyId) .collect(Collectors.toList()); } + + public Page findAllByInfix(String infix, PageRequest pageRequest) { + return adminRepository.findAllByInfix(infix, pageRequest); + } + + public List findAllById(Set adminIds) { + return adminRepository.findAllByIdIn(adminIds); + } + + public List agenciesOfAdmin(Set adminIds) { + return adminAgencyRepository.findByAdminIdIn(adminIds); + } } diff --git a/src/main/java/de/caritas/cob/userservice/api/model/Admin.java b/src/main/java/de/caritas/cob/userservice/api/model/Admin.java index 2d4d77745..3c0fa7b91 100644 --- a/src/main/java/de/caritas/cob/userservice/api/model/Admin.java +++ b/src/main/java/de/caritas/cob/userservice/api/model/Admin.java @@ -120,4 +120,15 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(id); } + + public interface AdminBase { + + String getId(); + + String getFirstName(); + + String getLastName(); + + String getEmail(); + } } diff --git a/src/main/java/de/caritas/cob/userservice/api/model/AdminAgency.java b/src/main/java/de/caritas/cob/userservice/api/model/AdminAgency.java index 0242b3004..34cbd8d55 100644 --- a/src/main/java/de/caritas/cob/userservice/api/model/AdminAgency.java +++ b/src/main/java/de/caritas/cob/userservice/api/model/AdminAgency.java @@ -63,4 +63,13 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(id); } + + public interface AdminAgencyBase { + + Long getId(); + + Long getAgencyId(); + + String getAdminId(); + } } diff --git a/src/main/java/de/caritas/cob/userservice/api/port/out/AdminAgencyRepository.java b/src/main/java/de/caritas/cob/userservice/api/port/out/AdminAgencyRepository.java index 9d24c2dd4..8f783f0fc 100644 --- a/src/main/java/de/caritas/cob/userservice/api/port/out/AdminAgencyRepository.java +++ b/src/main/java/de/caritas/cob/userservice/api/port/out/AdminAgencyRepository.java @@ -1,6 +1,7 @@ package de.caritas.cob.userservice.api.port.out; import de.caritas.cob.userservice.api.model.AdminAgency; +import de.caritas.cob.userservice.api.model.AdminAgency.AdminAgencyBase; import java.util.List; import java.util.Set; import org.springframework.data.repository.CrudRepository; @@ -18,5 +19,6 @@ public interface AdminAgencyRepository extends CrudRepository @Transactional void deleteByAdminId(String adminId); - List findByAdminIdIn(Set adminIds); + @SuppressWarnings("all") + List findByAdminIdIn(Set adminIds); } diff --git a/src/main/java/de/caritas/cob/userservice/api/port/out/AdminRepository.java b/src/main/java/de/caritas/cob/userservice/api/port/out/AdminRepository.java index ab0b6f8ee..9d19aae04 100644 --- a/src/main/java/de/caritas/cob/userservice/api/port/out/AdminRepository.java +++ b/src/main/java/de/caritas/cob/userservice/api/port/out/AdminRepository.java @@ -1,6 +1,28 @@ package de.caritas.cob.userservice.api.port.out; import de.caritas.cob.userservice.api.model.Admin; +import de.caritas.cob.userservice.api.model.Admin.AdminBase; +import java.util.List; +import java.util.Set; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; -public interface AdminRepository extends CrudRepository {} +public interface AdminRepository extends CrudRepository { + + @Query( + value = + "SELECT a.id as id, a.firstName as firstName, a.lastName as lastName, a.email as email " + + "FROM Admin a " + + "WHERE" + + " ?1 = '*' " + + " OR (" + + " UPPER(a.firstName) LIKE CONCAT('%', UPPER(?1), '%')" + + " OR UPPER(a.lastName) LIKE CONCAT('%', UPPER(?1), '%')" + + " OR UPPER(a.email) LIKE CONCAT('%', UPPER(?1), '%')" + + " )") + Page findAllByInfix(String infix, Pageable pageable); + + List findAllByIdIn(Set adminIds); +} diff --git a/src/test/java/de/caritas/cob/userservice/api/adapters/web/controller/UserAdminControllerIT.java b/src/test/java/de/caritas/cob/userservice/api/adapters/web/controller/UserAdminControllerIT.java index 7787aa70e..5ba99374c 100644 --- a/src/test/java/de/caritas/cob/userservice/api/adapters/web/controller/UserAdminControllerIT.java +++ b/src/test/java/de/caritas/cob/userservice/api/adapters/web/controller/UserAdminControllerIT.java @@ -22,6 +22,7 @@ import de.caritas.cob.userservice.api.adapters.web.dto.CreateConsultantDTO; import de.caritas.cob.userservice.api.adapters.web.dto.UpdateAdminConsultantDTO; import de.caritas.cob.userservice.api.adapters.web.dto.UpdateAgencyAdminDTO; +import de.caritas.cob.userservice.api.adapters.web.mapping.AdminAgencyDtoMapper; import de.caritas.cob.userservice.api.admin.facade.AdminAgencyFacade; import de.caritas.cob.userservice.api.admin.facade.ConsultantAdminFacade; import de.caritas.cob.userservice.api.admin.facade.UserAdminFacade; @@ -29,6 +30,7 @@ import de.caritas.cob.userservice.api.admin.service.session.SessionAdminService; import de.caritas.cob.userservice.api.config.auth.RoleAuthorizationAuthorityMapper; import de.caritas.cob.userservice.api.exception.httpresponses.NoContentException; +import de.caritas.cob.userservice.api.helper.AuthenticatedUser; import de.caritas.cob.userservice.api.service.appointment.AppointmentService; import java.util.ArrayList; import java.util.UUID; @@ -99,6 +101,10 @@ public class UserAdminControllerIT { @MockBean private AdminAgencyFacade adminAgencyFacade; + @MockBean private AdminAgencyDtoMapper adminAgencyDtoMapper; + + @MockBean private AuthenticatedUser authenticatedUser; + @Test public void getSessions_Should_returnBadRequest_When_requiredPaginationParamsAreMissing() throws Exception { diff --git a/src/test/java/de/caritas/cob/userservice/api/admin/facade/AdminAgencyFacadeTest.java b/src/test/java/de/caritas/cob/userservice/api/admin/facade/AdminAgencyFacadeTest.java new file mode 100644 index 000000000..f2c29942b --- /dev/null +++ b/src/test/java/de/caritas/cob/userservice/api/admin/facade/AdminAgencyFacadeTest.java @@ -0,0 +1,133 @@ +package de.caritas.cob.userservice.api.admin.facade; + +import static org.mockito.ArgumentMatchers.anySet; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import de.caritas.cob.userservice.api.adapters.web.dto.AdminDTO; +import de.caritas.cob.userservice.api.adapters.web.dto.AdminFilter; +import de.caritas.cob.userservice.api.adapters.web.dto.AdminResponseDTO; +import de.caritas.cob.userservice.api.adapters.web.dto.AgencyAdminSearchResultDTO; +import de.caritas.cob.userservice.api.adapters.web.dto.CreateAdminAgencyRelationDTO; +import de.caritas.cob.userservice.api.adapters.web.dto.CreateAgencyAdminDTO; +import de.caritas.cob.userservice.api.adapters.web.dto.Sort; +import de.caritas.cob.userservice.api.adapters.web.dto.UpdateAgencyAdminDTO; +import de.caritas.cob.userservice.api.admin.service.admin.AdminAgencyRelationService; +import de.caritas.cob.userservice.api.admin.service.admin.AdminAgencyService; +import de.caritas.cob.userservice.api.admin.service.admin.search.AdminFilterService; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class AdminAgencyFacadeTest { + + @InjectMocks private AdminAgencyFacade adminAgencyFacade; + @Mock private AdminAgencyService adminAgencyService; + @Mock private AdminAgencyRelationService adminAgencyRelationService; + @Mock private AdminFilterService adminFilterService; + + @Test + void findAgencyAdmin_Should_useAdminAgencyService() { + final String adminId = "123"; + + this.adminAgencyFacade.findAgencyAdmin(adminId); + + verify(this.adminAgencyService).findAgencyAdmin(adminId); + } + + @Test + void createNewAdminAgency_Should_useAdminAgencyService() { + CreateAgencyAdminDTO createAgencyAdminDTO = mock(CreateAgencyAdminDTO.class); + + this.adminAgencyFacade.createNewAdminAgency(createAgencyAdminDTO); + + verify(this.adminAgencyService).createNewAdminAgency(createAgencyAdminDTO); + } + + @Test + void updateAgencyAdmin_Should_useAdminAgencyService() { + String adminId = "123"; + UpdateAgencyAdminDTO updateAgencyAdminDTO = mock(UpdateAgencyAdminDTO.class); + + this.adminAgencyFacade.updateAgencyAdmin(adminId, updateAgencyAdminDTO); + + verify(this.adminAgencyService).updateAgencyAdmin(adminId, updateAgencyAdminDTO); + } + + @Test + void deleteAgencyAdmin_Should_useAdminAgencyService() { + String adminId = "123"; + + this.adminAgencyFacade.deleteAgencyAdmin(adminId); + + verify(this.adminAgencyService).deleteAgencyAdmin(adminId); + } + + @Test + void findAdminUserAgencyIds_Should_useAdminAgencyService() { + String adminId = "123"; + + this.adminAgencyFacade.findAdminUserAgencyIds(adminId); + + verify(this.adminAgencyService).findAgenciesOfAdmin(adminId); + } + + @Test + void createNewAdminAgencyRelation_Should_useAdminAgencyRelationService() { + String adminId = "123"; + CreateAdminAgencyRelationDTO createAdminAgencyRelationDTO = + mock(CreateAdminAgencyRelationDTO.class); + + this.adminAgencyFacade.createNewAdminAgencyRelation(adminId, createAdminAgencyRelationDTO); + + verify(this.adminAgencyRelationService) + .createAdminAgencyRelation(adminId, createAdminAgencyRelationDTO); + } + + @Test + void deleteAdminAgencyRelation_Should_useAdminAgencyRelationService() { + String adminId = "123"; + long agencyId = 2L; + + this.adminAgencyFacade.deleteAdminAgencyRelation(adminId, agencyId); + + verify(this.adminAgencyRelationService).deleteAdminAgencyRelation(adminId, agencyId); + } + + @Test + void setAdminAgenciesRelation_Should_useAdminAgencyRelationService() { + String adminId = "123"; + List newAdminAgencyRelationDTOS = new ArrayList<>(); + + this.adminAgencyFacade.setAdminAgenciesRelation(adminId, newAdminAgencyRelationDTOS); + + verify(this.adminAgencyRelationService) + .synchronizeAdminAgenciesRelation(adminId, newAdminAgencyRelationDTOS); + } + + @Test + void findFilteredAdminsAgency_Should_useAdminAgencyRelationService_and_useAdminFilterService() { + Integer page = 1; + Integer perPage = 10; + AdminFilter adminFilter = mock(AdminFilter.class); + Sort sort = mock(Sort.class); + AgencyAdminSearchResultDTO agencyAdminSearchResultDTO = mock(AgencyAdminSearchResultDTO.class); + AdminResponseDTO adminResponseDTO = mock(AdminResponseDTO.class); + when(adminResponseDTO.getEmbedded()).thenReturn(mock(AdminDTO.class)); + when(agencyAdminSearchResultDTO.getEmbedded()).thenReturn(List.of(adminResponseDTO)); + + when(adminFilterService.findFilteredAdmins(page, perPage, adminFilter, sort)) + .thenReturn(agencyAdminSearchResultDTO); + + this.adminAgencyFacade.findFilteredAdminsAgency(page, perPage, adminFilter, sort); + + verify(this.adminFilterService).findFilteredAdmins(page, perPage, adminFilter, sort); + verify(this.adminAgencyRelationService).appendAgenciesForAdmins(anySet()); + } +}