diff --git a/src/main/java/com/ays/assignment/controller/AssignmentController.java b/src/main/java/com/ays/assignment/controller/AssignmentController.java index 6962ab1cd..5452e68dc 100644 --- a/src/main/java/com/ays/assignment/controller/AssignmentController.java +++ b/src/main/java/com/ays/assignment/controller/AssignmentController.java @@ -1,15 +1,20 @@ package com.ays.assignment.controller; import com.ays.assignment.model.Assignment; +import com.ays.assignment.model.dto.request.AssignmentListRequest; import com.ays.assignment.model.dto.request.AssignmentSaveRequest; import com.ays.assignment.model.dto.request.AssignmentSearchRequest; import com.ays.assignment.model.dto.response.AssignmentResponse; import com.ays.assignment.model.dto.response.AssignmentSearchResponse; +import com.ays.assignment.model.dto.response.AssignmentsResponse; import com.ays.assignment.model.mapper.AssignmentToAssignmentResponseMapper; import com.ays.assignment.model.mapper.AssignmentToAssignmentSearchResponseMapper; +import com.ays.assignment.model.mapper.AssignmentToAssignmentsResponseMapper; import com.ays.assignment.service.AssignmentSaveService; import com.ays.assignment.service.AssignmentSearchService; import com.ays.assignment.service.AssignmentService; +import com.ays.common.model.AysPage; +import com.ays.common.model.dto.response.AysPageResponse; import com.ays.common.model.dto.response.AysResponse; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -30,24 +35,34 @@ class AssignmentController { private final AssignmentSaveService assignmentSaveService; + private final AssignmentSearchService assignmentSearchService; + private final AssignmentService assignmentService; private static final AssignmentToAssignmentResponseMapper assignmentToAssignmentResponseMapper = AssignmentToAssignmentResponseMapper.initialize(); private static final AssignmentToAssignmentSearchResponseMapper assignmentToAssignmentSearchResponseMapper = AssignmentToAssignmentSearchResponseMapper.initialize(); + private static final AssignmentToAssignmentsResponseMapper assignmentToAssignmentsResponseMapper = AssignmentToAssignmentsResponseMapper.initialize(); /** - * Saves a new assignment to the system. - * Requires ADMIN authority. + * Gets an Assignments list based on the specified filters in the {@link AssignmentListRequest} + * Requires ADMIN authority * - * @param saveRequest The request object containing the assignment data to be saved. - * @return A response object containing the saved assignment data. + * @param listRequest The assignment request that contains the status filter + * @return A response object that contains the retrieved assignments' data + * @see AssignmentListRequest */ - @PostMapping("/assignment") + @PostMapping("/assignments") @PreAuthorize("hasAnyAuthority('ADMIN')") - public AysResponse saveAssignment(@RequestBody @Valid AssignmentSaveRequest saveRequest) { - assignmentSaveService.saveAssignment(saveRequest); - return AysResponse.SUCCESS; + public AysResponse> getAssignments(@RequestBody @Valid AssignmentListRequest listRequest) { + final AysPage pageOfAssignments = assignmentService.getAssignments(listRequest); + final AysPageResponse pageOfAssignmentsResponse = AysPageResponse + .builder() + .of(pageOfAssignments) + .content(assignmentToAssignmentsResponseMapper.map(pageOfAssignments.getContent())) + .filteredBy(listRequest.getFilter()) + .build(); + return AysResponse.successOf(pageOfAssignmentsResponse); } /** @@ -66,6 +81,20 @@ public AysResponse getAssignmentById(@PathVariable @UUID Str return AysResponse.successOf(assignmentResponse); } + /** + * Saves a new assignment to the system. + * Requires ADMIN authority. + * + * @param saveRequest The request object containing the assignment data to be saved. + * @return A response object containing the saved assignment data. + */ + @PostMapping("/assignment") + @PreAuthorize("hasAnyAuthority('ADMIN')") + public AysResponse saveAssignment(@RequestBody @Valid AssignmentSaveRequest saveRequest) { + assignmentSaveService.saveAssignment(saveRequest); + return AysResponse.SUCCESS; + } + /** * Retrieves nearest assignment by AssignmentSearchRequest. * Requires USER authority. @@ -80,4 +109,5 @@ public AysResponse searchUserAssignment(@RequestBody @ final AssignmentSearchResponse assignmentResponse = assignmentToAssignmentSearchResponseMapper.map(assignment); return AysResponse.successOf(assignmentResponse); } + } diff --git a/src/main/java/com/ays/assignment/model/dto/request/AssignmentListRequest.java b/src/main/java/com/ays/assignment/model/dto/request/AssignmentListRequest.java index c7a35f0a5..406ff6886 100644 --- a/src/main/java/com/ays/assignment/model/dto/request/AssignmentListRequest.java +++ b/src/main/java/com/ays/assignment/model/dto/request/AssignmentListRequest.java @@ -1,47 +1,64 @@ package com.ays.assignment.model.dto.request; import com.ays.assignment.model.enums.AssignmentStatus; +import com.ays.common.model.AysFiltering; import com.ays.common.model.dto.request.AysFilteringRequest; import com.ays.common.model.dto.request.AysPagingRequest; -import com.ays.common.util.validation.EnumValidation; import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.validation.Valid; import jakarta.validation.constraints.AssertTrue; -import lombok.Builder; -import lombok.Data; +import jakarta.validation.constraints.Digits; +import lombok.*; +import org.apache.commons.collections4.CollectionUtils; import org.springframework.data.jpa.domain.Specification; -import java.util.EnumSet; +import java.util.List; import java.util.Set; /** * Represents a request object for fetching a list of user assignment with pagination,sorting and filtering options * This class extends the {@link AysPagingRequest} class and adds additional validation rules for sorting. */ -@Data +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor @Builder public class AssignmentListRequest extends AysPagingRequest implements AysFilteringRequest { - private AssignmentStatus status; + @Valid + private Filter filter; /** - * Checks if the assignment status is valid. - * - * @return true if the assignment status is valid or null, false otherwise. + * Represents a filtering configuration for assignments based on the class fields. */ - @AssertTrue(message = "IS ASSIGNMENT STATUS NOT ACCEPTED") - private boolean isStatusAccepted() { + @Getter + @Setter + @AllArgsConstructor + @NoArgsConstructor + public static class Filter implements AysFiltering { - if (this.status == null) { - return true; - } - EnumSet acceptedAssignmentStatuses = EnumSet.of(AssignmentStatus.AVAILABLE, - AssignmentStatus.RESERVED, - AssignmentStatus.ASSIGNED, - AssignmentStatus.IN_PROGRESS, - AssignmentStatus.DONE - ); - return EnumValidation.anyOf(this.status, acceptedAssignmentStatuses); + /** + * List of assignment statuses used for filtering. + */ + private List statuses; + + @Valid + private PhoneNumber phoneNumber; + } + + @Getter + @Setter + @AllArgsConstructor + @NoArgsConstructor + public static class PhoneNumber { + + @Digits(integer = 7, fraction = 0, message = "MUST BE 7-DIGIT NUMBER") + private String countryCode; + + @Digits(integer = 13, fraction = 0, message = "MUST BE 13-DIGIT NUMBER") + private String lineNumber; } /** @@ -58,21 +75,49 @@ public boolean isSortPropertyAccepted() { return this.isPropertyAccepted(acceptedFilterFields); } + /** - * Converts the request into a JPA Specification that filters assignments based on the specified status, - * if it is provided. + * Converts the request into a JPA Specification that filters assignments based on the specified + * statuses and phoneNumber, if they are provided. * * @param clazz the class type of the specification. * @return the generated JPA Specification based on the request filters. */ @Override public Specification toSpecification(Class clazz) { + + if (this.filter == null) { + return Specification.allOf(); + } + Specification specification = Specification.where(null); - if (status != null) { - specification = specification.and((root, query, builder) -> - builder.equal(root.get("status"), status)); + + if (this.filter.phoneNumber != null) { + + if (this.filter.phoneNumber.getLineNumber() != null) { + Specification lineNumberSpecification = (root, query, criteriaBuilder) -> + criteriaBuilder.equal(root.get("lineNumber"), this.filter.phoneNumber.getLineNumber()); + + specification = specification.and(lineNumberSpecification); + } + + if (this.filter.phoneNumber.getCountryCode() != null) { + Specification countryCodeSpecification = (root, query, criteriaBuilder) + -> criteriaBuilder.equal(root.get("countryCode"), this.filter.phoneNumber.getCountryCode()); + + specification = specification.and(countryCodeSpecification); + } } - // Add more filter conditions if needed + + if (!CollectionUtils.isEmpty(this.filter.getStatuses())) { + Specification statusSpecification = this.filter.statuses.stream().map(status -> + (Specification) (root, query, criteriaBuilder) -> + criteriaBuilder.equal(root.get("status"), status)) + .reduce(Specification::or).orElse(null); + + specification = specification.and(statusSpecification); + } + return specification; } diff --git a/src/main/java/com/ays/assignment/model/dto/response/AssignmentsResponse.java b/src/main/java/com/ays/assignment/model/dto/response/AssignmentsResponse.java new file mode 100644 index 000000000..bb9038a3e --- /dev/null +++ b/src/main/java/com/ays/assignment/model/dto/response/AssignmentsResponse.java @@ -0,0 +1,38 @@ +package com.ays.assignment.model.dto.response; + +import com.ays.assignment.model.enums.AssignmentStatus; +import com.ays.common.model.dto.response.BaseResponse; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.SuperBuilder; + +@Data +@EqualsAndHashCode(callSuper = true) +@SuperBuilder +public class AssignmentsResponse extends BaseResponse { + + private String id; + private AssignmentStatus status; + private String description; + private String firstName; + private String lastName; + private Location location; + private User user; + + @Getter + @Setter + public static class Location { + private Double longitude; + private Double latitude; + } + + @Getter + @Setter + public static class User { + private String id; + private String firstName; + private String lastName; + } +} diff --git a/src/main/java/com/ays/assignment/model/mapper/AssignmentToAssignmentsResponseMapper.java b/src/main/java/com/ays/assignment/model/mapper/AssignmentToAssignmentsResponseMapper.java new file mode 100644 index 000000000..79a94064c --- /dev/null +++ b/src/main/java/com/ays/assignment/model/mapper/AssignmentToAssignmentsResponseMapper.java @@ -0,0 +1,34 @@ +package com.ays.assignment.model.mapper; + +import com.ays.assignment.model.Assignment; +import com.ays.assignment.model.dto.response.AssignmentsResponse; +import com.ays.common.model.mapper.BaseMapper; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +/** + * AssignmentEntityToAssignmentMapper is an interface that defines the mapping between an {@link Assignment} and an {@link AssignmentsResponse}. + * This interface uses the MapStruct annotation @Mapper to generate an implementation of this interface at compile-time. + *

The class provides a static method {@code initialize()} that returns an instance of the generated mapper implementation. + *

The interface extends the MapStruct interface {@link BaseMapper}, which defines basic mapping methods. + * The interface adds no additional mapping methods, but simply defines the types to be used in the mapping process. + */ + +@Mapper +public interface AssignmentToAssignmentsResponseMapper extends BaseMapper { + + @Override + @Mapping(target = "location.longitude", source = "point.x") + @Mapping(target = "location.latitude", source = "point.y") + AssignmentsResponse map(Assignment source); + + /** + * Initializes the mapper. + * + * @return the initialized mapper object. + */ + static AssignmentToAssignmentsResponseMapper initialize() { + return Mappers.getMapper(AssignmentToAssignmentsResponseMapper.class); + } +} diff --git a/src/main/java/com/ays/assignment/service/AssignmentService.java b/src/main/java/com/ays/assignment/service/AssignmentService.java index a3296cfa7..e51773ab5 100644 --- a/src/main/java/com/ays/assignment/service/AssignmentService.java +++ b/src/main/java/com/ays/assignment/service/AssignmentService.java @@ -2,6 +2,8 @@ import com.ays.assignment.model.Assignment; +import com.ays.assignment.model.dto.request.AssignmentListRequest; +import com.ays.common.model.AysPage; /** * Assignment Save Service to perform assignment related business operations. @@ -15,4 +17,12 @@ public interface AssignmentService { * @return Assignment */ Assignment getAssignmentById(String id); + + /** + * Get Assignments based on the specified filters in the {@link AssignmentListRequest} + * + * @param listRequest The request dto object + * @return Assignments list + */ + AysPage getAssignments(AssignmentListRequest listRequest); } diff --git a/src/main/java/com/ays/assignment/service/impl/AssignmentServiceImpl.java b/src/main/java/com/ays/assignment/service/impl/AssignmentServiceImpl.java index f926b23af..7b4a494de 100644 --- a/src/main/java/com/ays/assignment/service/impl/AssignmentServiceImpl.java +++ b/src/main/java/com/ays/assignment/service/impl/AssignmentServiceImpl.java @@ -1,6 +1,7 @@ package com.ays.assignment.service.impl; import com.ays.assignment.model.Assignment; +import com.ays.assignment.model.dto.request.AssignmentListRequest; import com.ays.assignment.model.entity.AssignmentEntity; import com.ays.assignment.model.mapper.AssignmentEntityToAssignmentMapper; import com.ays.assignment.repository.AssignmentRepository; @@ -11,10 +12,14 @@ import com.ays.location.model.entity.UserLocationEntity; import com.ays.location.model.mapper.UserLocationEntityToUserLocationMapper; import com.ays.location.repository.UserLocationRepository; +import com.ays.common.model.AysPage; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; import java.util.Optional; +import java.util.List; @Service @RequiredArgsConstructor @@ -57,4 +62,32 @@ public Assignment getAssignmentById(String id) { return assignment; } + /** + * Retrieves a paginated list of assignments based on the specified filters and the institution's identity. + * + * @param listRequest The request containing filters and pagination parameters. + * @return An {@link AysPage} object containing the filtered assignments. + */ + @Override + public AysPage getAssignments(AssignmentListRequest listRequest) { + + String institutionId = identity.getInstitutionId(); + + Specification byStatusAndPhoneNumber = listRequest.toSpecification(AssignmentEntity.class); + Specification byInstitutionId = (root, query, criteriaBuilder) -> + criteriaBuilder.equal(root.get("institutionId"), institutionId); + + Page assignmentEntities = assignmentRepository + .findAll(byStatusAndPhoneNumber.and(byInstitutionId), listRequest.toPageable()); + + List assignments = assignmentEntityToAssignmentMapper.map(assignmentEntities.getContent()); + + return AysPage.of( + listRequest.getFilter(), + assignmentEntities, + assignments + ); + } + + } diff --git a/src/main/java/com/ays/common/model/AysSpecification.java b/src/main/java/com/ays/common/model/AysSpecification.java index 1ec719813..bb175523d 100644 --- a/src/main/java/com/ays/common/model/AysSpecification.java +++ b/src/main/java/com/ays/common/model/AysSpecification.java @@ -18,7 +18,7 @@ public class AysSpecification { * A builder class for creating specifications in the context of AysSpecification. * Use this builder to construct predicates based on a provided filter. */ - @SuppressWarnings("unused") + @SuppressWarnings("This method is unused by the application directly but Spring is using it in the background.") public static class AysSpecificationBuilder { /** diff --git a/src/main/java/com/ays/common/model/dto/response/AysPageResponse.java b/src/main/java/com/ays/common/model/dto/response/AysPageResponse.java index a51fcf3d6..1d5d398fe 100644 --- a/src/main/java/com/ays/common/model/dto/response/AysPageResponse.java +++ b/src/main/java/com/ays/common/model/dto/response/AysPageResponse.java @@ -58,7 +58,7 @@ public class AysPageResponse { * * @param The type of content in the response. */ - @SuppressWarnings("unused") + @SuppressWarnings("This method is unused by the application directly but Spring is using it in the background.") public static class AysPageResponseBuilder { /** diff --git a/src/main/java/com/ays/common/util/AysListUtil.java b/src/main/java/com/ays/common/util/AysListUtil.java index a2f732119..4b17db170 100644 --- a/src/main/java/com/ays/common/util/AysListUtil.java +++ b/src/main/java/com/ays/common/util/AysListUtil.java @@ -18,7 +18,7 @@ public class AysListUtil { * @param the type parameter for the class * @return a List of objects of the specified class type */ - @SuppressWarnings({"unchecked", "unused"}) + @SuppressWarnings({"unchecked", "This method is unused by the application directly but Spring is using it in the background."}) public static List to(Object object, Class clazz) { return (List) object; } diff --git a/src/main/java/com/ays/user/model/dto/request/UserSupportStatusUpdateRequest.java b/src/main/java/com/ays/user/model/dto/request/UserSupportStatusUpdateRequest.java index 973756e75..a6de3dee3 100644 --- a/src/main/java/com/ays/user/model/dto/request/UserSupportStatusUpdateRequest.java +++ b/src/main/java/com/ays/user/model/dto/request/UserSupportStatusUpdateRequest.java @@ -25,7 +25,7 @@ public class UserSupportStatusUpdateRequest { private UserSupportStatus supportStatus; @AssertTrue(message = "IS NOT ACCEPTED") - @SuppressWarnings("unused") + @SuppressWarnings("This method is unused by the application directly but Spring is using it in the background.") private boolean isSupportStatusAccepted() { if (ObjectUtils.isEmpty(this.supportStatus)) { diff --git a/src/main/java/com/ays/user/model/dto/request/UserUpdateRequest.java b/src/main/java/com/ays/user/model/dto/request/UserUpdateRequest.java index dd9e6ebe0..21eaefe91 100644 --- a/src/main/java/com/ays/user/model/dto/request/UserUpdateRequest.java +++ b/src/main/java/com/ays/user/model/dto/request/UserUpdateRequest.java @@ -31,7 +31,7 @@ public class UserUpdateRequest { private UserStatus status; @AssertTrue(message = "IS NOT ACCEPTED") - @SuppressWarnings("unused") + @SuppressWarnings("This method is unused by the application directly but Spring is using it in the background.") private boolean isStatusAccepted() { if (ObjectUtils.isEmpty(this.status)) { @@ -43,7 +43,7 @@ private boolean isStatusAccepted() { } @AssertTrue(message = "IS NOT ACCEPTED") - @SuppressWarnings("unused") + @SuppressWarnings("This method is unused by the application directly but Spring is using it in the background.") private boolean isRoleAccepted() { if (ObjectUtils.isEmpty(this.role)) { diff --git a/src/test/java/com/ays/assignment/controller/AssignmentControllerTest.java b/src/test/java/com/ays/assignment/controller/AssignmentControllerTest.java index 3ca31c101..b17e80b0b 100644 --- a/src/test/java/com/ays/assignment/controller/AssignmentControllerTest.java +++ b/src/test/java/com/ays/assignment/controller/AssignmentControllerTest.java @@ -3,6 +3,8 @@ import com.ays.AbstractRestControllerTest; import com.ays.assignment.model.Assignment; import com.ays.assignment.model.AssignmentBuilder; +import com.ays.assignment.model.dto.request.AssignmentListRequest; +import com.ays.assignment.model.dto.request.AssignmentListRequestBuilder; import com.ays.assignment.model.dto.request.AssignmentSaveRequest; import com.ays.assignment.model.dto.request.AssignmentSaveRequestBuilder; import com.ays.assignment.model.dto.request.AssignmentSearchRequest; @@ -11,11 +13,18 @@ import com.ays.assignment.model.mapper.AssignmentEntityToAssignmentMapper; import com.ays.assignment.model.mapper.AssignmentToAssignmentSearchResponseMapper; import com.ays.assignment.model.dto.response.AssignmentResponse; +import com.ays.assignment.model.dto.response.AssignmentsResponse; +import com.ays.assignment.model.entity.AssignmentEntity; +import com.ays.assignment.model.entity.AssignmentEntityBuilder; +import com.ays.assignment.model.mapper.AssignmentEntityToAssignmentMapper; import com.ays.assignment.model.mapper.AssignmentToAssignmentResponseMapper; +import com.ays.assignment.model.mapper.AssignmentToAssignmentsResponseMapper; import com.ays.assignment.service.AssignmentSaveService; import com.ays.assignment.service.AssignmentService; +import com.ays.common.model.AysPage; import com.ays.assignment.service.AssignmentSearchService; import com.ays.common.model.AysPhoneNumberBuilder; +import com.ays.common.model.dto.response.AysPageResponse; import com.ays.common.model.dto.response.AysResponse; import com.ays.common.model.dto.response.AysResponseBuilder; import com.ays.common.util.AysRandomUtil; @@ -25,9 +34,13 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; import org.springframework.test.web.servlet.result.MockMvcResultHandlers; +import java.util.List; + class AssignmentControllerTest extends AbstractRestControllerTest { @@ -44,11 +57,12 @@ class AssignmentControllerTest extends AbstractRestControllerTest { private static final AssignmentEntityToAssignmentMapper ASSIGNMENT_ENTITY_TO_ASSIGNMENT_MAPPER = AssignmentEntityToAssignmentMapper.initialize(); private static final AssignmentToAssignmentSearchResponseMapper ASSIGNMENT_TO_ASSIGNMENT_SEARCH_RESPONSE_MAPPER = AssignmentToAssignmentSearchResponseMapper.initialize(); private static final AssignmentToAssignmentResponseMapper ASSIGNMENT_TO_ASSIGNMENT_RESPONSE_MAPPER = AssignmentToAssignmentResponseMapper.initialize(); + private static final AssignmentToAssignmentsResponseMapper ASSIGNMENT_TO_ASSIGNMENTS_RESPONSE_MAPPER = AssignmentToAssignmentsResponseMapper.initialize(); + private static final String BASE_PATH = "/api/v1"; - @Test void givenValidAssignmentSaveRequest_whenAssignmentSaved_thenReturnAssignmentSavedResponse() throws Exception { // Given @@ -228,5 +242,61 @@ void givenValidAssignmentSearchRequest_whenUserUnauthorizedForSearching_thenRetu .andExpect(AysMockResultMatchersBuilders.response() .doesNotExist()); } + @Test + void givenValidAssignmentListRequest_whenAssignmentsFound_thenReturnAysPageResponseOfAssignmentsResponse() throws Exception { + + // Given + AssignmentListRequest mockListRequest = new AssignmentListRequestBuilder().withValidValues().build(); + + // When + List mockAssignmentEntities = AssignmentEntityBuilder.generateValidAssignmentEntities(1); + Page mockPageAssignmentEntities = new PageImpl<>(mockAssignmentEntities); + List mockAssignments = ASSIGNMENT_ENTITY_TO_ASSIGNMENT_MAPPER.map(mockAssignmentEntities); + AysPage mockAysPageOfAssignments = AysPage + .of(mockListRequest.getFilter(),mockPageAssignmentEntities,mockAssignments); + + Mockito.when(assignmentService.getAssignments(mockListRequest)).thenReturn(mockAysPageOfAssignments); + + // Then + String endpoint = BASE_PATH.concat("/assignments"); + List mockAssignmentsResponse = ASSIGNMENT_TO_ASSIGNMENTS_RESPONSE_MAPPER.map(mockAssignments); + AysPageResponse pageOfAssignmentsResponse = AysPageResponse.builder() + .of(mockAysPageOfAssignments) + .content(mockAssignmentsResponse) + .build(); + + AysResponse> mockAysResponse = AysResponse.successOf(pageOfAssignmentsResponse); + mockMvc.perform(AysMockMvcRequestBuilders + .post(endpoint,mockAdminUserToken.getAccessToken(),mockListRequest)) + .andDo(MockMvcResultHandlers.print()) + .andExpect(AysMockResultMatchersBuilders.status().isOk()) + .andExpect(AysMockResultMatchersBuilders.time().isNotEmpty()) + .andExpect(AysMockResultMatchersBuilders.httpStatus().value(mockAysResponse.getHttpStatus().getReasonPhrase())) + .andExpect(AysMockResultMatchersBuilders.isSuccess().value(mockAysResponse.getIsSuccess())) + .andExpect(AysMockResultMatchersBuilders.response().isNotEmpty()); + + Mockito.verify(assignmentService,Mockito.times(1)).getAssignments(mockListRequest); + } + + @Test + void givenValidAssignmentListRequest_whenUserUnauthorizedForListing_thenReturnAccessDeniedException() throws Exception{ + + // Given + AssignmentListRequest mockListRequest = new AssignmentListRequestBuilder().withValidValues().build(); + + // Then + String endpoint = BASE_PATH.concat("/assignments"); + AysResponse mockResponse = AysResponseBuilder.FORBIDDEN; + + mockMvc.perform(AysMockMvcRequestBuilders + .post(endpoint,mockUserToken.getAccessToken(),mockListRequest)) + .andDo(MockMvcResultHandlers.print()) + .andExpect(AysMockResultMatchersBuilders.status().isForbidden()) + .andExpect(AysMockResultMatchersBuilders.time().isNotEmpty()) + .andExpect(AysMockResultMatchersBuilders.httpStatus().value(mockResponse.getHttpStatus().name())) + .andExpect(AysMockResultMatchersBuilders.isSuccess().value(mockResponse.getIsSuccess())) + .andExpect(AysMockResultMatchersBuilders.response().doesNotExist()); + + } } diff --git a/src/test/java/com/ays/assignment/controller/AssignmentSystemTest.java b/src/test/java/com/ays/assignment/controller/AssignmentSystemTest.java index 40b7bbc81..6210386e9 100644 --- a/src/test/java/com/ays/assignment/controller/AssignmentSystemTest.java +++ b/src/test/java/com/ays/assignment/controller/AssignmentSystemTest.java @@ -3,15 +3,22 @@ import com.ays.AbstractSystemTest; import com.ays.assignment.model.Assignment; import com.ays.assignment.model.AssignmentBuilder; +import com.ays.assignment.model.dto.request.AssignmentListRequest; +import com.ays.assignment.model.dto.request.AssignmentListRequestBuilder; import com.ays.assignment.model.dto.request.AssignmentSaveRequest; import com.ays.assignment.model.dto.request.AssignmentSaveRequestBuilder; import com.ays.assignment.model.dto.request.AssignmentSearchRequest; import com.ays.assignment.model.dto.request.AssignmentSearchRequestBuilder; import com.ays.assignment.model.dto.response.AssignmentResponse; +import com.ays.assignment.model.entity.AssignmentEntity; +import com.ays.assignment.model.entity.AssignmentEntityBuilder; +import com.ays.assignment.model.mapper.AssignmentEntityToAssignmentMapper; import com.ays.assignment.model.dto.response.AssignmentSearchResponse; import com.ays.assignment.model.mapper.AssignmentToAssignmentResponseMapper; +import com.ays.common.model.AysPage; import com.ays.assignment.model.mapper.AssignmentToAssignmentSearchResponseMapper; import com.ays.common.model.AysPhoneNumberBuilder; +import com.ays.common.model.dto.response.AysPageResponse; import com.ays.common.model.dto.response.AysResponse; import com.ays.common.model.dto.response.AysResponseBuilder; import com.ays.common.util.AysRandomUtil; @@ -20,13 +27,18 @@ import com.ays.util.AysMockResultMatchersBuilders; import com.ays.util.AysTestData; import org.junit.jupiter.api.Test; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; import org.springframework.test.web.servlet.result.MockMvcResultHandlers; +import java.util.List; + class AssignmentSystemTest extends AbstractSystemTest { private static final AssignmentToAssignmentResponseMapper ASSIGNMENT_TO_ASSIGNMENT_RESPONSE_MAPPER = AssignmentToAssignmentResponseMapper.initialize(); private final AssignmentToAssignmentSearchResponseMapper assignmentToAssignmentSearchResponseMapper = AssignmentToAssignmentSearchResponseMapper.initialize(); + private static final AssignmentEntityToAssignmentMapper ASSIGNMENT_ENTITY_TO_ASSIGNMENT_MAPPER = AssignmentEntityToAssignmentMapper.initialize(); private static final String BASE_PATH = "/api/v1"; @@ -197,4 +209,63 @@ void givenValidAssignmentSearchRequest_whenUserUnauthorizedForSearching_thenRetu .doesNotExist()); } + @Test + void givenValidAssignmentListRequest_whenAssignmentsFound_thenReturnAssignmentsResponse() throws Exception { + + // Given + AssignmentListRequest listRequest = new AssignmentListRequestBuilder().withValidValues().build(); + + List assignmentEntities = AssignmentEntityBuilder.generateValidAssignmentEntities(1); + Page pageOfAssignmentEntities = new PageImpl<>(assignmentEntities); + List assignments = ASSIGNMENT_ENTITY_TO_ASSIGNMENT_MAPPER.map(assignmentEntities); + AysPage aysPageOfAssignments = AysPage.of(pageOfAssignmentEntities,assignments); + AysPageResponse aysPageResponseOfAssignments = AysPageResponse.builder() + .of(aysPageOfAssignments).build(); + + // Then + String endpoint = BASE_PATH.concat("/assignments"); + MockHttpServletRequestBuilder mockHttpServletRequestBuilder = AysMockMvcRequestBuilders + .post(endpoint,adminUserTokenOne.getAccessToken(),listRequest); + + AysResponse> response = AysResponse.successOf(aysPageResponseOfAssignments); + + mockMvc.perform(mockHttpServletRequestBuilder) + .andDo(MockMvcResultHandlers.print()) + .andExpect(AysMockResultMatchersBuilders.status().isOk()) + .andExpect(AysMockResultMatchersBuilders.time() + .isNotEmpty()) + .andExpect(AysMockResultMatchersBuilders.httpStatus() + .value(response.getHttpStatus().name())) + .andExpect(AysMockResultMatchersBuilders.isSuccess() + .value(response.getIsSuccess())) + .andExpect(AysMockResultMatchersBuilders.response() + .isNotEmpty()); + } + + @Test + void givenValidAssignmentListRequest_whenUserUnauthorizedForListing_thenReturnAccessDeniedException() throws Exception { + + // Given + AssignmentListRequest listRequest = new AssignmentListRequestBuilder().withValidValues().build(); + + // Then + String endpoint = BASE_PATH.concat("/assignments"); + MockHttpServletRequestBuilder mockHttpServletRequestBuilder = AysMockMvcRequestBuilders + .post(endpoint,userTokenOne.getAccessToken(),listRequest); + + AysResponse response = AysResponseBuilder.FORBIDDEN; + + mockMvc.perform(mockHttpServletRequestBuilder) + .andDo(MockMvcResultHandlers.print()) + .andExpect(AysMockResultMatchersBuilders.status().isForbidden()) + .andExpect(AysMockResultMatchersBuilders.time() + .isNotEmpty()) + .andExpect(AysMockResultMatchersBuilders.httpStatus() + .value(response.getHttpStatus().name())) + .andExpect(AysMockResultMatchersBuilders.isSuccess() + .value(response.getIsSuccess())) + .andExpect(AysMockResultMatchersBuilders.response() + .doesNotExist()); + } + } diff --git a/src/test/java/com/ays/assignment/model/dto/request/AssignmentListRequestBuilder.java b/src/test/java/com/ays/assignment/model/dto/request/AssignmentListRequestBuilder.java new file mode 100644 index 000000000..02aee6694 --- /dev/null +++ b/src/test/java/com/ays/assignment/model/dto/request/AssignmentListRequestBuilder.java @@ -0,0 +1,56 @@ +package com.ays.assignment.model.dto.request; + +import com.ays.assignment.model.enums.AssignmentStatus; +import com.ays.common.model.AysPaging; +import com.ays.common.model.AysPagingBuilder; +import com.ays.common.model.AysSorting; +import com.ays.common.model.TestDataBuilder; + +import java.util.List; + +public class AssignmentListRequestBuilder extends TestDataBuilder { + + public AssignmentListRequestBuilder() { + super(AssignmentListRequest.class); + } + + public AssignmentListRequestBuilder withValidValues() { + return this + .initializeFilter() + .withStatuses(List.of(AssignmentStatus.AVAILABLE, AssignmentStatus.ASSIGNED)) + .withPhoneNumber(new AssignmentListRequest.PhoneNumber("90", "1234567890")) + .withPagination(new AysPagingBuilder().withValidValues().build()) + .withSort(null); + } + + private AssignmentListRequestBuilder initializeFilter() { + data.setFilter(new AssignmentListRequest.Filter()); + return this; + } + + public AssignmentListRequestBuilder withFilter(AssignmentListRequest.Filter filter) { + data.setFilter(filter); + return this; + } + + public AssignmentListRequestBuilder withStatuses(List statuses) { + data.getFilter().setStatuses(statuses); + return this; + } + + public AssignmentListRequestBuilder withPhoneNumber(AssignmentListRequest.PhoneNumber phoneNumber) { + data.getFilter().setPhoneNumber(phoneNumber); + return this; + } + + public AssignmentListRequestBuilder withPagination(AysPaging aysPaging) { + data.setPagination(aysPaging); + return this; + } + + public AssignmentListRequestBuilder withSort(List sorting) { + data.setSort(sorting); + return this; + } + +} diff --git a/src/test/java/com/ays/assignment/service/impl/AssignmentServiceImplTest.java b/src/test/java/com/ays/assignment/service/impl/AssignmentServiceImplTest.java index aa6a10421..32d91cc84 100644 --- a/src/test/java/com/ays/assignment/service/impl/AssignmentServiceImplTest.java +++ b/src/test/java/com/ays/assignment/service/impl/AssignmentServiceImplTest.java @@ -2,12 +2,16 @@ import com.ays.AbstractUnitTest; import com.ays.assignment.model.Assignment; +import com.ays.assignment.model.dto.request.AssignmentListRequest; +import com.ays.assignment.model.dto.request.AssignmentListRequestBuilder; import com.ays.assignment.model.entity.AssignmentEntity; import com.ays.assignment.model.entity.AssignmentEntityBuilder; import com.ays.assignment.model.mapper.AssignmentEntityToAssignmentMapper; import com.ays.assignment.repository.AssignmentRepository; import com.ays.assignment.util.exception.AysAssignmentNotExistByIdException; import com.ays.auth.model.AysIdentity; +import com.ays.common.model.AysPage; +import com.ays.common.model.AysPageBuilder; import com.ays.common.util.AysRandomUtil; import com.ays.location.model.UserLocation; import com.ays.location.model.entity.UserLocationEntity; @@ -19,7 +23,12 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import java.util.List; import java.util.Optional; @@ -110,4 +119,102 @@ void givenAssignmentId_whenAssignmentNotFound_thenThrowAysAssignmentNotExistById .getInstitutionId(); } + @Test + void givenAssignmentListRequest_whenAssignmentStatusIsAvailable_thenReturnAysPageAssignmentResponse() { + + // Given + String mockInstitutionId = AysRandomUtil.generateUUID(); + + AssignmentListRequest assignmentListRequest = new AssignmentListRequestBuilder() + .withValidValues() + .withPhoneNumber(null) + .build(); + + List mockAssignmentEntities = List.of(new AssignmentEntityBuilder() + .withValidFields().build()); + Page mockPageAssignmentEntities = new PageImpl<>(mockAssignmentEntities); + + List mockAssignments = ASSIGNMENT_ENTITY_TO_ASSIGNMENT_MAPPER.map(mockAssignmentEntities); + AysPage mockAysPageAssignments = AysPage.of(assignmentListRequest.getFilter(), mockPageAssignmentEntities, mockAssignments); + + // When + Mockito.when(identity.getInstitutionId()).thenReturn(mockInstitutionId); + Mockito.when(assignmentRepository.findAll(Mockito.any(Specification.class), Mockito.any(Pageable.class))) + .thenReturn(mockPageAssignmentEntities); + + // Then + AysPage aysPageAssignment = assignmentService.getAssignments(assignmentListRequest); + + AysPageBuilder.assertEquals(mockAysPageAssignments, aysPageAssignment); + + Mockito.verify(assignmentRepository, Mockito.times(1)) + .findAll(Mockito.any(Specification.class), Mockito.any(Pageable.class)); + Mockito.verify(identity, Mockito.times(1)).getInstitutionId(); + } + + @Test + void givenAssignmentListRequest_whenPhoneNumberIsAvailable_thenReturnAysPageAssignmentResponse() { + + // Given + String mockInstitutionId = AysRandomUtil.generateUUID(); + + AssignmentListRequest assignmentListRequest = new AssignmentListRequestBuilder() + .withValidValues() + .withStatuses(null) + .build(); + + List mockAssignmentEntities = List.of(new AssignmentEntityBuilder() + .withValidFields().build()); + Page mockPageAssignmentEntities = new PageImpl<>(mockAssignmentEntities); + + List mockAssignments = ASSIGNMENT_ENTITY_TO_ASSIGNMENT_MAPPER.map(mockAssignmentEntities); + AysPage mockAysPageAssignments = AysPage.of(assignmentListRequest.getFilter(), mockPageAssignmentEntities, mockAssignments); + + // When + Mockito.when(identity.getInstitutionId()).thenReturn(mockInstitutionId); + Mockito.when(assignmentRepository.findAll(Mockito.any(Specification.class), Mockito.any(Pageable.class))) + .thenReturn(mockPageAssignmentEntities); + + // Then + AysPage aysPageAssignment = assignmentService.getAssignments(assignmentListRequest); + + AysPageBuilder.assertEquals(mockAysPageAssignments, aysPageAssignment); + + Mockito.verify(assignmentRepository, Mockito.times(1)) + .findAll(Mockito.any(Specification.class), Mockito.any(Pageable.class)); + Mockito.verify(identity, Mockito.times(1)).getInstitutionId(); + } + + @Test + void givenAssignmentListRequest_whenAssignmentStatusAndPhoneNumberAvailable_thenReturnAysPageAssignmentResponse() { + + // Given + String mockInstitutionId = AysRandomUtil.generateUUID(); + + AssignmentListRequest assignmentListRequest = new AssignmentListRequestBuilder() + .withValidValues() + .build(); + + List mockAssignmentEntities = List.of(new AssignmentEntityBuilder() + .withValidFields().build()); + Page mockPageAssignmentEntities = new PageImpl<>(mockAssignmentEntities); + + List mockAssignments = ASSIGNMENT_ENTITY_TO_ASSIGNMENT_MAPPER.map(mockAssignmentEntities); + AysPage mockAysPageAssignments = AysPage.of(assignmentListRequest.getFilter(), mockPageAssignmentEntities, mockAssignments); + + // When + Mockito.when(identity.getInstitutionId()).thenReturn(mockInstitutionId); + Mockito.when(assignmentRepository.findAll(Mockito.any(Specification.class), Mockito.any(Pageable.class))) + .thenReturn(mockPageAssignmentEntities); + + // Then + AysPage aysPageAssignment = assignmentService.getAssignments(assignmentListRequest); + + AysPageBuilder.assertEquals(mockAysPageAssignments, aysPageAssignment); + + Mockito.verify(assignmentRepository, Mockito.times(1)) + .findAll(Mockito.any(Specification.class), Mockito.any(Pageable.class)); + Mockito.verify(identity, Mockito.times(1)).getInstitutionId(); + } + }