From 02035a6bc9cb97b919bb118421df55ade11a9607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sercan=20Noyan=20Germiyano=C4=9Flu?= Date: Tue, 22 Aug 2023 18:47:47 +0300 Subject: [PATCH] #146 | Implement the process of Assignment for Save Operation (#147) --- .../controller/AssignmentController.java | 42 +++++++++ .../com/ays/assignment/model/Assignment.java | 4 +- .../dto/request/AssignmentSaveRequest.java | 43 +++++++++ .../model/entity/AssignmentEntity.java | 16 ++-- .../AssignmentEntityToAssignmentMapper.java | 29 ------ ...signmentSaveRequestToAssignmentMapper.java | 54 ++++++++++++ .../AssignmentToAssignmentEntityMapper.java | 28 ------ ...ository.java => AssignmentRepository.java} | 4 +- .../service/AssignmentSaveService.java | 17 ++++ .../impl/AssignmentSaveServiceImpl.java | 41 +++++++++ ...ysAssignmentAlreadyAvailableException.java | 2 +- .../AysAssignmentAlreadyDeletedException.java | 26 ++++++ .../com/ays/common/util/AysLocationUtil.java | 28 ++++++ .../db/changelog/changes/4-ays-ddl.xml | 20 ++--- .../db/changelog/changes/5-ays-dml.xml | 22 ++--- .../controller/AssignmentControllerTest.java | 88 +++++++++++++++++++ .../controller/AssignmentSystemTest.java | 76 ++++++++++++++++ .../assignment/model/AssignmentBuilder.java | 38 ++++++++ .../request/AssignmentSaveRequestBuilder.java | 53 +++++++++++ .../model/entity/AssignmentEntityBuilder.java | 84 ++++++++++++++++++ .../impl/AssignmentSaveServiceImplTest.java | 56 ++++++++++++ .../com/ays/common/model/TestDataBuilder.java | 21 +++++ 22 files changed, 704 insertions(+), 88 deletions(-) create mode 100644 src/main/java/com/ays/assignment/controller/AssignmentController.java create mode 100644 src/main/java/com/ays/assignment/model/dto/request/AssignmentSaveRequest.java create mode 100644 src/main/java/com/ays/assignment/model/mapper/AssignmentSaveRequestToAssignmentMapper.java rename src/main/java/com/ays/assignment/repository/{AssignmentEntityRepository.java => AssignmentRepository.java} (55%) create mode 100644 src/main/java/com/ays/assignment/service/AssignmentSaveService.java create mode 100644 src/main/java/com/ays/assignment/service/impl/AssignmentSaveServiceImpl.java create mode 100644 src/main/java/com/ays/assignment/util/exception/AysAssignmentAlreadyDeletedException.java create mode 100644 src/main/java/com/ays/common/util/AysLocationUtil.java create mode 100644 src/test/java/com/ays/assignment/controller/AssignmentControllerTest.java create mode 100644 src/test/java/com/ays/assignment/controller/AssignmentSystemTest.java create mode 100644 src/test/java/com/ays/assignment/model/AssignmentBuilder.java create mode 100644 src/test/java/com/ays/assignment/model/dto/request/AssignmentSaveRequestBuilder.java create mode 100644 src/test/java/com/ays/assignment/model/entity/AssignmentEntityBuilder.java create mode 100644 src/test/java/com/ays/assignment/service/impl/AssignmentSaveServiceImplTest.java diff --git a/src/main/java/com/ays/assignment/controller/AssignmentController.java b/src/main/java/com/ays/assignment/controller/AssignmentController.java new file mode 100644 index 000000000..d09b115cc --- /dev/null +++ b/src/main/java/com/ays/assignment/controller/AssignmentController.java @@ -0,0 +1,42 @@ +package com.ays.assignment.controller; + +import com.ays.assignment.model.dto.request.AssignmentSaveRequest; +import com.ays.assignment.service.AssignmentSaveService; +import com.ays.common.model.dto.response.AysResponse; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * REST controller class for managing assignment-related operations via HTTP requests. + * This controller handles the CRUD operations for assignments in the system. + * The mapping path for this controller is "/api/v1/assignment". + */ +@RestController +@RequestMapping("/api/v1") +@RequiredArgsConstructor +@Validated +class AssignmentController { + + private final AssignmentSaveService assignmentSaveService; + + + /** + * 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; + } +} diff --git a/src/main/java/com/ays/assignment/model/Assignment.java b/src/main/java/com/ays/assignment/model/Assignment.java index f32045701..7ab447ecb 100644 --- a/src/main/java/com/ays/assignment/model/Assignment.java +++ b/src/main/java/com/ays/assignment/model/Assignment.java @@ -8,6 +8,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.SuperBuilder; +import org.locationtech.jts.geom.Point; /** * Assignment Domain Model to perform data transfer from service layer to controller @@ -22,8 +23,7 @@ public class Assignment extends BaseDomainModel { private String firstName; private String lastName; private AysPhoneNumber phoneNumber; - private Double latitude; - private Double longitude; + private Point point; private AssignmentStatus status; private User user; diff --git a/src/main/java/com/ays/assignment/model/dto/request/AssignmentSaveRequest.java b/src/main/java/com/ays/assignment/model/dto/request/AssignmentSaveRequest.java new file mode 100644 index 000000000..c98332684 --- /dev/null +++ b/src/main/java/com/ays/assignment/model/dto/request/AssignmentSaveRequest.java @@ -0,0 +1,43 @@ +package com.ays.assignment.model.dto.request; + +import com.ays.common.model.AysPhoneNumber; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +/** + * A DTO class representing the request data for saving an assignment. + *

+ * This class provides getters and setters for the description, first name, last name, latitude, longitude and phone number fields. + * It also includes a builder pattern implementation for constructing instances of this class with optional parameters. + *

+ * The purpose of this class is to encapsulate the request data related to saving an assignment, allowing for easy + * transfer of the data between different layers of the application. + */ +@Getter +@Setter +@Builder +public class AssignmentSaveRequest { + + @NotBlank + private String description; + + @NotBlank + private String firstName; + + @NotBlank + private String lastName; + + @Valid + @NotNull + private AysPhoneNumber phoneNumber; + + @NotNull + private Double latitude; + + @NotNull + private Double longitude; +} diff --git a/src/main/java/com/ays/assignment/model/entity/AssignmentEntity.java b/src/main/java/com/ays/assignment/model/entity/AssignmentEntity.java index 4be00a77f..d1ae8afd9 100644 --- a/src/main/java/com/ays/assignment/model/entity/AssignmentEntity.java +++ b/src/main/java/com/ays/assignment/model/entity/AssignmentEntity.java @@ -2,6 +2,7 @@ import com.ays.assignment.model.enums.AssignmentStatus; import com.ays.common.model.entity.BaseEntity; +import com.ays.common.util.AysLocationUtil; import com.ays.institution.model.entity.InstitutionEntity; import com.ays.user.model.entity.UserEntity; import jakarta.persistence.*; @@ -10,8 +11,6 @@ import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; -import org.locationtech.jts.geom.Coordinate; -import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.geom.Point; /** @@ -55,7 +54,7 @@ public class AssignmentEntity extends BaseEntity { private Point point; @Enumerated(EnumType.STRING) - @Column(name = "ASSIGNMENT_STATUS") + @Column(name = "STATUS") private AssignmentStatus status; @OneToOne @@ -67,9 +66,7 @@ public class AssignmentEntity extends BaseEntity { private UserEntity user; public void setPoint(double latitude, double longitude) { - Coordinate coordinate = new Coordinate(latitude, longitude); - GeometryFactory geometryFactory = new GeometryFactory(); - this.point = geometryFactory.createPoint(coordinate); + this.point = AysLocationUtil.generatePoint(latitude, longitude); } public boolean isAvailable() { @@ -92,8 +89,15 @@ public boolean isDone() { return AssignmentStatus.DONE.equals(this.status); } + public void updateAssignmentStatus(AssignmentStatus assignmentStatus) { this.status = assignmentStatus; } + public abstract static class AssignmentEntityBuilder> extends BaseEntity.BaseEntityBuilder { + public B point(final Double latitude, final Double longitude) { + this.point = AysLocationUtil.generatePoint(latitude, longitude); + return this.self(); + } + } } diff --git a/src/main/java/com/ays/assignment/model/mapper/AssignmentEntityToAssignmentMapper.java b/src/main/java/com/ays/assignment/model/mapper/AssignmentEntityToAssignmentMapper.java index 45113a863..2959e2296 100644 --- a/src/main/java/com/ays/assignment/model/mapper/AssignmentEntityToAssignmentMapper.java +++ b/src/main/java/com/ays/assignment/model/mapper/AssignmentEntityToAssignmentMapper.java @@ -3,13 +3,10 @@ import com.ays.assignment.model.Assignment; import com.ays.assignment.model.entity.AssignmentEntity; import com.ays.common.model.mapper.BaseMapper; -import org.locationtech.jts.geom.Point; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; -import java.util.Optional; - /** * AssignmentEntityToAssignmentMapper is an interface that defines the mapping between an {@link AssignmentEntity} and an {@link Assignment}. * This interface uses the MapStruct annotation @Mapper to generate an implementation of this interface at compile-time. @@ -23,8 +20,6 @@ public interface AssignmentEntityToAssignmentMapper extends BaseMapperThe 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 AssignmentSaveRequestToAssignmentMapper extends BaseMapper { + + /** + * Maps an {@link AssignmentSaveRequest} object to an {@link AssignmentEntity} object for saving in the database. + * + * @param saveRequest the {@link AssignmentSaveRequest} object to be mapped. + * @param institutionId the {@link String} object. + * @return the mapped {@link UserEntity} object. + */ + default AssignmentEntity mapForSaving(AssignmentSaveRequest saveRequest, String institutionId) { + + return AssignmentEntity.builder() + .id(AysRandomUtil.generateUUID()) + .institutionId(institutionId) + .description(saveRequest.getDescription()) + .firstName(saveRequest.getFirstName()) + .lastName(saveRequest.getLastName()) + .lineNumber(saveRequest.getPhoneNumber().getLineNumber()) + .countryCode(saveRequest.getPhoneNumber().getCountryCode()) + .point(saveRequest.getLatitude(), saveRequest.getLongitude()) + .status(AssignmentStatus.AVAILABLE) + .build(); + } + + /** + * Initializes the mapper. + * + * @return the initialized mapper object. + */ + static AssignmentSaveRequestToAssignmentMapper initialize() { + return Mappers.getMapper(AssignmentSaveRequestToAssignmentMapper.class); + } + +} diff --git a/src/main/java/com/ays/assignment/model/mapper/AssignmentToAssignmentEntityMapper.java b/src/main/java/com/ays/assignment/model/mapper/AssignmentToAssignmentEntityMapper.java index b2efb9547..97b1f1099 100644 --- a/src/main/java/com/ays/assignment/model/mapper/AssignmentToAssignmentEntityMapper.java +++ b/src/main/java/com/ays/assignment/model/mapper/AssignmentToAssignmentEntityMapper.java @@ -3,11 +3,7 @@ import com.ays.assignment.model.Assignment; import com.ays.assignment.model.entity.AssignmentEntity; import com.ays.common.model.mapper.BaseMapper; -import org.locationtech.jts.geom.Coordinate; -import org.locationtech.jts.geom.GeometryFactory; -import org.locationtech.jts.geom.Point; import org.mapstruct.Mapper; -import org.mapstruct.Mapping; import org.mapstruct.factory.Mappers; /** @@ -20,15 +16,6 @@ @Mapper public interface AssignmentToAssignmentEntityMapper extends BaseMapper { - /** - * Maps UserAssignment to UserAssignmentEntity. - * - * @param assignment the UserAssignment object - * @return the mapped UserAssignmentEntity object - */ - @Mapping(target = "point", expression = "java(mapToPoint(assignment.getLatitude(), assignment.getLongitude()))") - AssignmentEntity map(Assignment assignment); - /** * Initializes the mapper. @@ -39,19 +26,4 @@ static AssignmentToAssignmentEntityMapper initialize() { return Mappers.getMapper(AssignmentToAssignmentEntityMapper.class); } - /** - * Maps latitude and longitude to the point field. - * - * @param latitude the latitude value - * @param longitude the longitude value - * @return the mapped Point object - */ - default Point mapToPoint(Double latitude, Double longitude) { - if (latitude != null && longitude != null) { - Coordinate coordinate = new Coordinate(latitude, longitude); - GeometryFactory geometryFactory = new GeometryFactory(); - return geometryFactory.createPoint(coordinate); - } - return null; - } } diff --git a/src/main/java/com/ays/assignment/repository/AssignmentEntityRepository.java b/src/main/java/com/ays/assignment/repository/AssignmentRepository.java similarity index 55% rename from src/main/java/com/ays/assignment/repository/AssignmentEntityRepository.java rename to src/main/java/com/ays/assignment/repository/AssignmentRepository.java index 9a9b45207..7f885974c 100644 --- a/src/main/java/com/ays/assignment/repository/AssignmentEntityRepository.java +++ b/src/main/java/com/ays/assignment/repository/AssignmentRepository.java @@ -2,10 +2,12 @@ import com.ays.assignment.model.entity.AssignmentEntity; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; /** * Repository interface for performing CRUD operations on UserAssignmentEntity objects. */ -public interface AssignmentEntityRepository extends JpaRepository { +public interface AssignmentRepository extends JpaRepository, JpaSpecificationExecutor { + } diff --git a/src/main/java/com/ays/assignment/service/AssignmentSaveService.java b/src/main/java/com/ays/assignment/service/AssignmentSaveService.java new file mode 100644 index 000000000..9a87ff541 --- /dev/null +++ b/src/main/java/com/ays/assignment/service/AssignmentSaveService.java @@ -0,0 +1,17 @@ +package com.ays.assignment.service; + +import com.ays.assignment.model.dto.request.AssignmentSaveRequest; + +/** + * Assignment Save Service to perform assignment related save business operations. + */ +public interface AssignmentSaveService { + + /** + * Saves a saveRequest to the database. + * + * @param saveRequest the AssignmentSaveRequest entity + * @return Assignment + */ + void saveAssignment(AssignmentSaveRequest saveRequest); +} diff --git a/src/main/java/com/ays/assignment/service/impl/AssignmentSaveServiceImpl.java b/src/main/java/com/ays/assignment/service/impl/AssignmentSaveServiceImpl.java new file mode 100644 index 000000000..0fe3655bd --- /dev/null +++ b/src/main/java/com/ays/assignment/service/impl/AssignmentSaveServiceImpl.java @@ -0,0 +1,41 @@ +package com.ays.assignment.service.impl; + +import com.ays.assignment.model.dto.request.AssignmentSaveRequest; +import com.ays.assignment.model.entity.AssignmentEntity; +import com.ays.assignment.model.mapper.AssignmentSaveRequestToAssignmentMapper; +import com.ays.assignment.repository.AssignmentRepository; +import com.ays.assignment.service.AssignmentSaveService; +import com.ays.auth.model.AysIdentity; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +/** + * UserSaveServiceImpl is an implementation of the {@link AssignmentSaveService} interface. + * It provides methods for saving assignment data and performing related operations by admin. + */ +@Service +@RequiredArgsConstructor +class AssignmentSaveServiceImpl implements AssignmentSaveService { + + private final AssignmentRepository assignmentRepository; + + private final AysIdentity identity; + + private static final AssignmentSaveRequestToAssignmentMapper assignmentSaveRequestToAssignmentMapper = AssignmentSaveRequestToAssignmentMapper.initialize(); + + /** + * Saves a new assignment based on the provided save request. + * + * @param saveRequest the request object containing assignment data to be saved + * @return the saved assignment + */ + @Override + public void saveAssignment(AssignmentSaveRequest saveRequest) { + + final AssignmentEntity assignmentEntity = assignmentSaveRequestToAssignmentMapper.mapForSaving(saveRequest, identity.getInstitutionId()); + + assignmentRepository.save(assignmentEntity); + + } + +} diff --git a/src/main/java/com/ays/assignment/util/exception/AysAssignmentAlreadyAvailableException.java b/src/main/java/com/ays/assignment/util/exception/AysAssignmentAlreadyAvailableException.java index ab47bd6de..e6c5ad387 100644 --- a/src/main/java/com/ays/assignment/util/exception/AysAssignmentAlreadyAvailableException.java +++ b/src/main/java/com/ays/assignment/util/exception/AysAssignmentAlreadyAvailableException.java @@ -5,7 +5,7 @@ import java.io.Serial; /** - * Exception thrown when a user assignment is available and attempting to perform an action that requires an assignment which is already available. + * Exception thrown when an assignment is available and attempting to perform an action that requires an assignment which is already available. */ public class AysAssignmentAlreadyAvailableException extends AysAlreadyException { diff --git a/src/main/java/com/ays/assignment/util/exception/AysAssignmentAlreadyDeletedException.java b/src/main/java/com/ays/assignment/util/exception/AysAssignmentAlreadyDeletedException.java new file mode 100644 index 000000000..f0b1ee4e7 --- /dev/null +++ b/src/main/java/com/ays/assignment/util/exception/AysAssignmentAlreadyDeletedException.java @@ -0,0 +1,26 @@ +package com.ays.assignment.util.exception; + +import com.ays.common.util.exception.AysAlreadyException; + +import java.io.Serial; + +/** + * Exception thrown when an assignment is deleted and attempting to perform an action that requires an assignment which is already deleted. + */ +public class AysAssignmentAlreadyDeletedException extends AysAlreadyException { + + /** + * Unique identifier for serialization. + */ + @Serial + private static final long serialVersionUID = 7742901037914306311L; + + /** + * Constructs a new {@code AysAssignmentAlreadyAvailableException} with the specified id. + * + * @param id the id of the assignment which is already available + */ + public AysAssignmentAlreadyDeletedException(String id) { + super("ASSIGNMENT IS ALREADY DELETED! id:" + id); + } +} diff --git a/src/main/java/com/ays/common/util/AysLocationUtil.java b/src/main/java/com/ays/common/util/AysLocationUtil.java new file mode 100644 index 000000000..c618bb882 --- /dev/null +++ b/src/main/java/com/ays/common/util/AysLocationUtil.java @@ -0,0 +1,28 @@ +package com.ays.common.util; + +import lombok.experimental.UtilityClass; +import org.locationtech.jts.geom.*; +import org.locationtech.jts.geom.impl.CoordinateArraySequence; + +/** + * Utility class for handling location-related operations. + * Provides methods to generate geometric points based on latitude and longitude coordinates. + */ +@UtilityClass +public class AysLocationUtil { + + /** + * Generates a Point object representing a location based on the provided latitude and longitude coordinates. + * + * @param latitude The latitude coordinate of the location. + * @param longitude The longitude coordinate of the location. + * @return A Point object representing the location. + */ + public static Point generatePoint(final Double latitude, final Double longitude) { + final Coordinate[] coordinates = new Coordinate[]{new Coordinate(latitude, longitude)}; + final CoordinateSequence coordinateSequence = new CoordinateArraySequence(coordinates); + final PrecisionModel precisionModel = new PrecisionModel(PrecisionModel.FLOATING); + return new GeometryFactory(precisionModel, 4326).createPoint(coordinateSequence); + } + +} diff --git a/src/main/resources/db/changelog/changes/4-ays-ddl.xml b/src/main/resources/db/changelog/changes/4-ays-ddl.xml index c4b966b30..307cbba10 100644 --- a/src/main/resources/db/changelog/changes/4-ays-ddl.xml +++ b/src/main/resources/db/changelog/changes/4-ays-ddl.xml @@ -47,17 +47,17 @@ - - @@ -69,10 +69,10 @@ - + - + diff --git a/src/main/resources/db/changelog/changes/5-ays-dml.xml b/src/main/resources/db/changelog/changes/5-ays-dml.xml index 23909b4f0..61d8b1c80 100644 --- a/src/main/resources/db/changelog/changes/5-ays-dml.xml +++ b/src/main/resources/db/changelog/changes/5-ays-dml.xml @@ -24,23 +24,23 @@ - INSERT INTO AYS_ASSIGNMENT (ID, DESCRIPTION, FIRST_NAME, LAST_NAME, COUNTRY_CODE, LINE_NUMBER, STATUS, + INSERT INTO AYS_ASSIGNMENT (ID, INSTITUTION_ID, DESCRIPTION, FIRST_NAME, LAST_NAME, COUNTRY_CODE, + LINE_NUMBER, STATUS, POINT, CREATED_USER, CREATED_AT) - VALUES ('3b30cac9-0645-48cb-bc98-2e928df521ab', '100L İçme Suyu İhtiyacı', 'Ahmet', 'Mehmet', - 90, 1234567890, 'AVAILABLE', ST_GeomFromText('POINT(40.981210 29.026083)', 4326), + VALUES ('3b30cac9-0645-48cb-bc98-2e928df521ab', '77ece256-bf0e-4bbe-801d-173083f8bdcf', + '100L İçme Suyu İhtiyacı', + 'Ahmet', 'Mehmet', '90', '1234567890', 'AVAILABLE', + ST_GeomFromText('POINT(40.981210 29.026083)', 4326), 'AYS', CURRENT_TIMESTAMP); - INSERT INTO AYS_ASSIGNMENT (ID, DESCRIPTION, FIRST_NAME, LAST_NAME, COUNTRY_CODE, LINE_NUMBER, STATUS, + INSERT INTO AYS_ASSIGNMENT (ID, INSTITUTION_ID, DESCRIPTION, FIRST_NAME, LAST_NAME, COUNTRY_CODE, + LINE_NUMBER, STATUS, POINT, CREATED_USER, CREATED_AT) - VALUES ('a9ec051e-3c4f-4cb5-ab08-e9dcee5e1f03', 'Kıyafet İhtiyacı', 'Cem', 'Orkun', - 90, 1234567890, 'AVAILABLE', ST_GeomFromText('POINT(40.981210 29.000000)', 4326), + VALUES ('a9ec051e-3c4f-4cb5-ab08-e9dcee5e1f03', '91df7ae9-d5b9-44ae-b54f-d5d55359c4a4', 'Kıyafet İhtiyacı', + 'Cem', 'Orkun', '90', '1234567890', 'AVAILABLE', + ST_GeomFromText('POINT(40.981210 29.000000)', 4326), 'AYS', CURRENT_TIMESTAMP); - INSERT INTO AYS_ASSIGNMENT (ID, DESCRIPTION, FIRST_NAME, LAST_NAME, COUNTRY_CODE, LINE_NUMBER, STATUS, - POINT, CREATED_USER, CREATED_AT) - VALUES ('7e1ebd41-a644-4596-a0f3-b4a71237b3c5', 'Yemek İhtiyacı', 'Ceren', 'Deniz', - 90, 1234567890, 'AVAILABLE', ST_GeomFromText('POINT(40.941210 29.123123)', 4326), - 'AYS', CURRENT_TIMESTAMP); diff --git a/src/test/java/com/ays/assignment/controller/AssignmentControllerTest.java b/src/test/java/com/ays/assignment/controller/AssignmentControllerTest.java new file mode 100644 index 000000000..d021d460c --- /dev/null +++ b/src/test/java/com/ays/assignment/controller/AssignmentControllerTest.java @@ -0,0 +1,88 @@ +package com.ays.assignment.controller; + +import com.ays.AbstractRestControllerTest; +import com.ays.assignment.model.dto.request.AssignmentSaveRequest; +import com.ays.assignment.model.dto.request.AssignmentSaveRequestBuilder; +import com.ays.assignment.service.AssignmentSaveService; +import com.ays.common.model.AysPhoneNumberBuilder; +import com.ays.common.model.dto.response.AysResponse; +import com.ays.common.model.dto.response.AysResponseBuilder; +import com.ays.common.util.exception.model.AysError; +import com.ays.util.AysMockMvcRequestBuilders; +import com.ays.util.AysMockResultMatchersBuilders; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; +import org.springframework.test.web.servlet.result.MockMvcResultHandlers; + + +class AssignmentControllerTest extends AbstractRestControllerTest { + + @MockBean + private AssignmentSaveService assignmentSaveService; + + private static final String BASE_PATH = "/api/v1"; + + @Test + void givenValidAssignmentSaveRequest_whenAssignmentSaved_thenReturnAssignmentSavedResponse() throws Exception { + // Given + AssignmentSaveRequest mockAssignmentSaveRequest = new AssignmentSaveRequestBuilder() + .withPhoneNumber(new AysPhoneNumberBuilder().withValidFields().build()) + .build(); + + // When + Mockito.doNothing().when(assignmentSaveService).saveAssignment(Mockito.any(AssignmentSaveRequest.class)); + + // Then + String endpoint = BASE_PATH.concat("/assignment"); + + AysResponse mockAysResponse = AysResponse.SUCCESS; + + mockMvc.perform(AysMockMvcRequestBuilders + .post(endpoint, mockAdminUserToken.getAccessToken(), mockAssignmentSaveRequest)) + .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() + .doesNotExist()); + + Mockito.verify(assignmentSaveService, Mockito.times(1)) + .saveAssignment(Mockito.any(AssignmentSaveRequest.class)); + + } + + + @Test + void givenValidAssignmentSaveRequest_whenUserUnauthorizedForSaving_thenReturnAccessDeniedException() throws Exception { + // Given + AssignmentSaveRequest mockAssignmentSaveRequest = new AssignmentSaveRequestBuilder() + .withPhoneNumber(new AysPhoneNumberBuilder().withValidFields().build()) + .build(); + + // Then + String endpoint = BASE_PATH.concat("/assignment"); + MockHttpServletRequestBuilder mockHttpServletRequestBuilder = AysMockMvcRequestBuilders + .post(endpoint, mockUserToken.getAccessToken(), mockAssignmentSaveRequest); + + AysResponse mockResponse = AysResponseBuilder.FORBIDDEN; + mockMvc.perform(mockHttpServletRequestBuilder) + .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 new file mode 100644 index 000000000..6802985f6 --- /dev/null +++ b/src/test/java/com/ays/assignment/controller/AssignmentSystemTest.java @@ -0,0 +1,76 @@ +package com.ays.assignment.controller; + +import com.ays.AbstractSystemTest; +import com.ays.assignment.model.dto.request.AssignmentSaveRequest; +import com.ays.assignment.model.dto.request.AssignmentSaveRequestBuilder; +import com.ays.common.model.AysPhoneNumberBuilder; +import com.ays.common.model.dto.response.AysResponse; +import com.ays.common.model.dto.response.AysResponseBuilder; +import com.ays.common.util.exception.model.AysError; +import com.ays.util.AysMockMvcRequestBuilders; +import com.ays.util.AysMockResultMatchersBuilders; +import org.junit.jupiter.api.Test; +import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; +import org.springframework.test.web.servlet.result.MockMvcResultHandlers; + +class AssignmentSystemTest extends AbstractSystemTest { + + private static final String BASE_PATH = "/api/v1"; + + @Test + void givenValidAssignmentSaveRequest_whenAssignmentSaved_thenReturnAssignmentSavedResponse() throws Exception { + // Given + AssignmentSaveRequest mockAssignmentSaveRequest = new AssignmentSaveRequestBuilder() + .withPhoneNumber(new AysPhoneNumberBuilder().withValidFields().build()) + .build(); + + + // Then + String endpoint = BASE_PATH.concat("/assignment"); + + AysResponse mockAysResponse = AysResponse.SUCCESS; + + mockMvc.perform(AysMockMvcRequestBuilders + .post(endpoint, adminUserTokenOne.getAccessToken(), mockAssignmentSaveRequest)) + .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() + .doesNotExist()); + + } + + + @Test + void givenValidAssignmentSaveRequest_whenUserUnauthorizedForSaving_thenReturnAccessDeniedException() throws Exception { + // Given + AssignmentSaveRequest mockAssignmentSaveRequest = new AssignmentSaveRequestBuilder() + .withPhoneNumber(new AysPhoneNumberBuilder().withValidFields().build()) + .build(); + + // Then + String endpoint = BASE_PATH.concat("/assignment"); + MockHttpServletRequestBuilder mockHttpServletRequestBuilder = AysMockMvcRequestBuilders + .post(endpoint, userTokenOne.getAccessToken(), mockAssignmentSaveRequest); + + AysResponse mockResponse = AysResponseBuilder.FORBIDDEN; + mockMvc.perform(mockHttpServletRequestBuilder) + .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/model/AssignmentBuilder.java b/src/test/java/com/ays/assignment/model/AssignmentBuilder.java new file mode 100644 index 000000000..2b6931f69 --- /dev/null +++ b/src/test/java/com/ays/assignment/model/AssignmentBuilder.java @@ -0,0 +1,38 @@ +package com.ays.assignment.model; + +import com.ays.assignment.model.enums.AssignmentStatus; +import com.ays.common.model.AysPhoneNumber; +import com.ays.common.model.TestDataBuilder; + +public class AssignmentBuilder extends TestDataBuilder { + + public AssignmentBuilder() { + super(Assignment.class); + } + + public AssignmentBuilder withDescription(String description) { + data.setDescription(description); + return this; + } + + public AssignmentBuilder withFirstName(String firstName) { + data.setFirstName(firstName); + return this; + } + + public AssignmentBuilder withLastName(String lastName) { + data.setLastName(lastName); + return this; + } + + public AssignmentBuilder withStatus(AssignmentStatus status) { + data.setStatus(status); + return this; + } + + public AssignmentBuilder withPhoneNumber(AysPhoneNumber phoneNumber) { + data.setPhoneNumber(phoneNumber); + return this; + } + +} diff --git a/src/test/java/com/ays/assignment/model/dto/request/AssignmentSaveRequestBuilder.java b/src/test/java/com/ays/assignment/model/dto/request/AssignmentSaveRequestBuilder.java new file mode 100644 index 000000000..2f24a443c --- /dev/null +++ b/src/test/java/com/ays/assignment/model/dto/request/AssignmentSaveRequestBuilder.java @@ -0,0 +1,53 @@ +package com.ays.assignment.model.dto.request; + +import com.ays.common.model.AysPhoneNumber; +import com.ays.common.model.AysPhoneNumberBuilder; +import com.ays.common.model.TestDataBuilder; + +public class AssignmentSaveRequestBuilder extends TestDataBuilder { + + public AssignmentSaveRequestBuilder() { + super(AssignmentSaveRequest.class); + } + + public AssignmentSaveRequestBuilder withValidFields() { + this.withFirstName("First Name"); + this.withLastName("Last Name"); + this.withLatitude(0.0); + this.withLongitude(0.0); + this.withDescription("Description"); + this.withPhoneNumber(new AysPhoneNumberBuilder().withValidFields().build()); + return this; + } + + public AssignmentSaveRequestBuilder withDescription(String description) { + data.setDescription(description); + return this; + } + + public AssignmentSaveRequestBuilder withPhoneNumber(AysPhoneNumber phoneNumber) { + data.setPhoneNumber(phoneNumber); + return this; + } + + public AssignmentSaveRequestBuilder withFirstName(String firstName) { + data.setFirstName(firstName); + return this; + } + + public AssignmentSaveRequestBuilder withLastName(String lastName) { + data.setLastName(lastName); + return this; + } + + public AssignmentSaveRequestBuilder withLatitude(Double latitude) { + data.setLatitude(latitude); + return this; + } + + public AssignmentSaveRequestBuilder withLongitude(Double longitude) { + data.setLongitude(longitude); + return this; + } + +} diff --git a/src/test/java/com/ays/assignment/model/entity/AssignmentEntityBuilder.java b/src/test/java/com/ays/assignment/model/entity/AssignmentEntityBuilder.java new file mode 100644 index 000000000..a510bff56 --- /dev/null +++ b/src/test/java/com/ays/assignment/model/entity/AssignmentEntityBuilder.java @@ -0,0 +1,84 @@ +package com.ays.assignment.model.entity; + +import com.ays.assignment.model.enums.AssignmentStatus; +import com.ays.common.model.AysPhoneNumber; +import com.ays.common.model.AysPhoneNumberBuilder; +import com.ays.common.model.TestDataBuilder; +import com.ays.common.util.AysRandomUtil; +import com.ays.institution.model.entity.InstitutionEntity; +import com.ays.institution.model.entity.InstitutionEntityBuilder; + +import java.util.ArrayList; +import java.util.List; + +public class AssignmentEntityBuilder extends TestDataBuilder { + + public AssignmentEntityBuilder() { + super(AssignmentEntity.class); + } + + public static List generateValidAssignmentEntities(int size) { + List userEntities = new ArrayList<>(); + for (int i = 0; i < size; i++) { + AssignmentEntity assignmentEntity = new AssignmentEntityBuilder().withValidFields().build(); + userEntities.add(assignmentEntity); + } + return userEntities; + } + + public AssignmentEntityBuilder withValidFields() { + InstitutionEntity institutionEntity = new InstitutionEntityBuilder().withValidFields().build(); + + return this + .withId(AysRandomUtil.generateUUID()) + .withInstitutionId(institutionEntity.getId()) + .withInstitution(institutionEntity) + .withPhoneNumber(new AysPhoneNumberBuilder().withValidFields().build()) + .withDescription("Description") + .withFirstName("First Name") + .withLastName("Last Name") + .withStatus(AssignmentStatus.AVAILABLE); + } + + public AssignmentEntityBuilder withId(String id) { + data.setId(id); + return this; + } + + public AssignmentEntityBuilder withInstitutionId(String institutionId) { + data.setInstitutionId(institutionId); + return this; + } + + public AssignmentEntityBuilder withPhoneNumber(AysPhoneNumber phoneNumber) { + data.setCountryCode(phoneNumber.getCountryCode()); + data.setLineNumber(phoneNumber.getLineNumber()); + return this; + } + + public AssignmentEntityBuilder withInstitution(InstitutionEntity institution) { + data.setInstitution(institution); + return this; + } + + public AssignmentEntityBuilder withDescription(String description) { + data.setDescription(description); + return this; + } + + public AssignmentEntityBuilder withFirstName(String firstName) { + data.setFirstName(firstName); + return this; + } + + public AssignmentEntityBuilder withLastName(String lastName) { + data.setLastName(lastName); + return this; + } + + public AssignmentEntityBuilder withStatus(AssignmentStatus status) { + data.setStatus(status); + return this; + } + +} diff --git a/src/test/java/com/ays/assignment/service/impl/AssignmentSaveServiceImplTest.java b/src/test/java/com/ays/assignment/service/impl/AssignmentSaveServiceImplTest.java new file mode 100644 index 000000000..991baaf93 --- /dev/null +++ b/src/test/java/com/ays/assignment/service/impl/AssignmentSaveServiceImplTest.java @@ -0,0 +1,56 @@ +package com.ays.assignment.service.impl; + +import com.ays.AbstractUnitTest; +import com.ays.assignment.model.dto.request.AssignmentSaveRequest; +import com.ays.assignment.model.dto.request.AssignmentSaveRequestBuilder; +import com.ays.assignment.model.entity.AssignmentEntity; +import com.ays.assignment.model.entity.AssignmentEntityBuilder; +import com.ays.assignment.repository.AssignmentRepository; +import com.ays.auth.model.AysIdentity; +import com.ays.common.util.AysRandomUtil; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; + + +class AssignmentSaveServiceImplTest extends AbstractUnitTest { + + @InjectMocks + private AssignmentSaveServiceImpl assignmentSaveService; + + @Mock + private AssignmentRepository assignmentRepository; + + @Mock + private AysIdentity identity; + + @Test + void givenValidAssignmentSaveRequest_whenAssignmentSaved_thenReturnSuccess() { + + // Given + AssignmentSaveRequest mockAssignmentSaveRequest = new AssignmentSaveRequestBuilder() + .withValidFields() + .build(); + + + AssignmentEntity mockAssignmentEntity = new AssignmentEntityBuilder() + .withValidFields().build(); + + // When + + Mockito.when(assignmentRepository.save(Mockito.any(AssignmentEntity.class))) + .thenReturn(mockAssignmentEntity); + + Mockito.when(identity.getInstitutionId()) + .thenReturn(AysRandomUtil.generateUUID()); + + // Then + assignmentSaveService.saveAssignment(mockAssignmentSaveRequest); + + Mockito.verify(assignmentRepository, Mockito.times(1)).save(Mockito.any(AssignmentEntity.class)); + Mockito.verify(identity, Mockito.times(1)).getInstitutionId(); + + } + +} diff --git a/src/test/java/com/ays/common/model/TestDataBuilder.java b/src/test/java/com/ays/common/model/TestDataBuilder.java index e005366e3..df82181e6 100644 --- a/src/test/java/com/ays/common/model/TestDataBuilder.java +++ b/src/test/java/com/ays/common/model/TestDataBuilder.java @@ -6,9 +6,15 @@ import org.jeasy.random.EasyRandom; import org.jeasy.random.EasyRandomParameters; import org.jeasy.random.FieldPredicates; +import org.jeasy.random.randomizers.AbstractRandomizer; import org.jeasy.random.randomizers.range.IntegerRangeRandomizer; import org.jeasy.random.randomizers.range.LongRangeRandomizer; import org.jeasy.random.randomizers.text.StringRandomizer; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.CoordinateSequence; +import org.locationtech.jts.geom.GeometryFactory; +import org.locationtech.jts.geom.Point; +import org.locationtech.jts.geom.impl.CoordinateArraySequence; import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils; import static org.jeasy.random.FieldPredicates.named; @@ -28,6 +34,8 @@ public abstract class TestDataBuilder { private static final LongRangeRandomizer LONG_RANGE_RANDOMIZER = new LongRangeRandomizer(1L, Long.MAX_VALUE); private static final CharacterRandomizer CHARACTER_RANDOMIZER = new CharacterRandomizer(); + private static final PointRandomizer POINT_RANDOMIZER = new PointRandomizer(); + public TestDataBuilder(Class clazz) { this(clazz, false); @@ -48,6 +56,7 @@ private EasyRandomParameters getExclusionParameters(boolean excludeRelations) { parameters.randomize(Integer.class, POSITIVE_INTEGER_RANDOMIZER); parameters.randomize(String.class, CHARACTER_RANDOMIZER); parameters.randomize(Long.class, LONG_RANGE_RANDOMIZER); + parameters.randomize(Point.class, POINT_RANDOMIZER); if (!excludeRelations) return parameters; @@ -82,3 +91,15 @@ public String getRandomValue() { } } + +class PointRandomizer extends AbstractRandomizer { + + @Override + public Point getRandomValue() { + Coordinate[] coordinates = new Coordinate[]{new Coordinate(40.991739, 29.024168)}; + CoordinateSequence coordinateSequence = new CoordinateArraySequence(coordinates); + GeometryFactory geometryFactory = new GeometryFactory(); + return geometryFactory.createPoint(coordinateSequence); + } +} +