diff --git a/caab-api/open-api-specification.yml b/caab-api/open-api-specification.yml index bd21102..4f0e7c2 100644 --- a/caab-api/open-api-specification.yml +++ b/caab-api/open-api-specification.yml @@ -1178,6 +1178,189 @@ paths: description: 'Not found' '500': description: 'Internal server error' + /notification-attachments: + get: + tags: + - notification attachments + summary: 'Get Notification Attachments' + operationId: 'getNotificationAttachments' + x-spring-paginated: true + parameters: + - name: 'notification-reference' + in: 'query' + schema: + type: 'string' + example: '1234567890' + - name: 'provider-id' + in: 'query' + schema: + type: 'string' + example: '1234567890' + - name: 'document-type' + in: 'query' + schema: + type: 'string' + example: 'type' + - name: 'send-by' + in: 'query' + schema: + type: 'string' + example: 'type' + responses: + '200': + description: 'Successful operation' + content: + application/json: + schema: + $ref: "#/components/schemas/notificationAttachmentDetails" + '400': + description: 'Bad request' + '401': + description: 'Unauthorized' + '403': + description: 'Forbidden' + '404': + description: 'Not found' + '500': + description: 'Internal server error' + post: + tags: + - notification attachments + summary: 'Create Notification Attachment' + operationId: 'createNotificationAttachment' + requestBody: + description: Create Notification Attachment + content: + application/json: + schema: + $ref: '#/components/schemas/notificationAttachmentDetail' + parameters: + - name: 'Caab-User-Login-Id' + in: header + required: true + schema: + type: 'string' + example: 'SOMEUSER@COMPANY.CO.UK' + responses: + '200': + description: 'Successful operation' + '400': + description: 'Bad request' + '401': + description: 'Unauthorized' + '403': + description: 'Forbidden' + '404': + description: 'Not found' + '500': + description: 'Internal server error' + delete: + tags: + - notification attachments + summary: 'Remove Notification Attachments' + operationId: 'removeNotificationAttachments' + parameters: + - name: 'notification-reference' + in: 'query' + schema: + type: 'string' + example: '1234567890' + - name: 'provider-id' + in: 'query' + schema: + type: 'string' + example: '1234567890' + - name: 'document-type' + in: 'query' + schema: + type: 'string' + example: 'type' + - name: 'send-by' + in: 'query' + schema: + type: 'string' + example: 'type' + - name: 'Caab-User-Login-Id' + in: header + required: true + schema: + type: 'string' + example: 'SOMEUSER@COMPANY.CO.UK' + responses: + '204': + description: 'No Content' + '400': + description: 'Bad request' + '401': + description: 'Unauthorized' + '403': + description: 'Forbidden' + '404': + description: 'Not found' + '500': + description: 'Internal server error' + /notification-attachments/{notification-attachment-id}: + get: + tags: + - notification attachments + summary: 'Get Notification Attachment' + operationId: 'getNotificationAttachment' + parameters: + - name: 'notification-attachment-id' + in: 'path' + required: true + schema: + type: 'integer' + format: 'int64' + example: '1234567890' + responses: + '200': + description: 'Successful operation' + content: + application/json: + schema: + $ref: "#/components/schemas/notificationAttachmentDetail" + '400': + description: 'Bad request' + '401': + description: 'Unauthorized' + '403': + description: 'Forbidden' + '404': + description: 'Not found' + '500': + description: 'Internal server error' + delete: + tags: + - notification attachments + summary: 'Remove a Notification Attachment' + operationId: 'removeNotificationAttachment' + parameters: + - name: 'notification-attachment-id' + in: 'path' + required: true + schema: + type: 'integer' + format: 'int64' + - name: 'Caab-User-Login-Id' + in: header + required: true + schema: + type: 'string' + example: 'SOMEUSER@COMPANY.CO.UK' + responses: + '204': + description: 'No Content' + '400': + description: 'Bad request' + '401': + description: 'Unauthorized' + '403': + description: 'Forbidden' + '404': + description: 'Not found' + '500': + description: 'Internal server error' /evidence: get: tags: @@ -2511,6 +2694,47 @@ components: $ref: "#/components/schemas/stringDisplayValue" provider_case_reference: type: 'string' + notificationAttachmentDetails: + allOf: + - $ref: "#/components/schemas/page" + type: 'object' + properties: + content: + type: 'array' + default: [ ] + items: + $ref: '#/components/schemas/baseNotificationAttachmentDetail' + baseNotificationAttachmentDetail: + type: 'object' + properties: + id: + type: 'integer' + provider_id: + type: 'string' + document_type: + $ref: '#/components/schemas/stringDisplayValue' + description: + type: 'string' + file_name: + type: 'string' + send_by: + type: 'string' + status: + type: 'string' + number: + type: 'integer' + format: 'int64' + notification_reference: + type: 'string' + audit_trail: + $ref: '#/components/schemas/auditDetail' + notificationAttachmentDetail: + type: 'object' + allOf: + - $ref: "#/components/schemas/baseNotificationAttachmentDetail" + properties: + file_data: + type: 'string' evidenceDocumentDetails: allOf: - $ref: "#/components/schemas/page" diff --git a/caab-service/src/integrationTest/java/uk/gov/laa/ccms/data/api/controller/BaseNotificationAttachmentControllerIntegrationTest.java b/caab-service/src/integrationTest/java/uk/gov/laa/ccms/data/api/controller/BaseNotificationAttachmentControllerIntegrationTest.java new file mode 100644 index 0000000..f47e5a3 --- /dev/null +++ b/caab-service/src/integrationTest/java/uk/gov/laa/ccms/data/api/controller/BaseNotificationAttachmentControllerIntegrationTest.java @@ -0,0 +1,427 @@ +package uk.gov.laa.ccms.data.api.controller; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.net.URI; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.jdbc.Sql; +import uk.gov.laa.ccms.caab.api.controller.NotificationAttachmentController; +import uk.gov.laa.ccms.caab.api.service.NotificationAttachmentService; +import uk.gov.laa.ccms.caab.model.BaseNotificationAttachmentDetail; +import uk.gov.laa.ccms.caab.model.NotificationAttachmentDetail; +import uk.gov.laa.ccms.caab.model.NotificationAttachmentDetails; + +public abstract class BaseNotificationAttachmentControllerIntegrationTest extends AbstractControllerIntegrationTest { + + @Autowired + private NotificationAttachmentController notificationAttachmentController; + + @Autowired + private NotificationAttachmentService notificationAttachmentService; + + @Test + public void testCreateNotificationAttachment() throws Exception { + + NotificationAttachmentDetail notificationAttachmentDetail = loadObjectFromJson( + "/json/notification_attachment_new.json", NotificationAttachmentDetail.class); + + String auditUser = "audit@user.com"; + + // Call the createNotificationAttachment method directly + ResponseEntity responseEntity = + notificationAttachmentController.createNotificationAttachment(auditUser, notificationAttachmentDetail); + + assertEquals(HttpStatus.CREATED, responseEntity.getStatusCode()); + URI locationUri = responseEntity.getHeaders().getLocation(); + + String path = locationUri.getPath(); + String id = path.substring(path.lastIndexOf('/') + 1); + + NotificationAttachmentDetail savedNotificationAttachmentDetail = + notificationAttachmentService.getNotificationAttachment(Long.valueOf(id)); + + assertAuditTrail(savedNotificationAttachmentDetail.getAuditTrail(), auditUser); + + // Clear the audit trail for comparison purposes. + savedNotificationAttachmentDetail.setAuditTrail(null); + + // null/ignore the ids as theses are generated by the database + savedNotificationAttachmentDetail.setId(null); + + assertEquals(notificationAttachmentDetail, savedNotificationAttachmentDetail); + } + + @Test + @Sql(scripts = "/sql/notification_attachment_insert.sql") + public void testGetNotificationAttachments_unfilteredReturnsAll() { + + // Call the getNotificationAttachments method directly + ResponseEntity responseEntity = + notificationAttachmentController.getNotificationAttachments( + null, + null, + null, + null, + Pageable.unpaged() + ); + + assertNotNull(responseEntity); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertNotNull(responseEntity.getBody()); + assertNotNull(responseEntity.getBody().getContent()); + assertEquals(3, responseEntity.getBody().getContent().size()); + + NotificationAttachmentDetail firstRetrievedNotificationAttachmentDetail = + notificationAttachmentService.getNotificationAttachment(282L); + NotificationAttachmentDetail secondRetrievedNotificationAttachmentDetail = + notificationAttachmentService.getNotificationAttachment(283L); + NotificationAttachmentDetail thirdRetrievedNotificationAttachmentDetail = + notificationAttachmentService.getNotificationAttachment(284L); + + compareData(firstRetrievedNotificationAttachmentDetail, responseEntity.getBody().getContent().get(0)); + compareData(secondRetrievedNotificationAttachmentDetail, responseEntity.getBody().getContent().get(1)); + compareData(thirdRetrievedNotificationAttachmentDetail, responseEntity.getBody().getContent().get(2)); + } + + @Test + @Sql(scripts = "/sql/notification_attachment_insert.sql") + public void testGetNotificationAttachments_byNotificationReference() { + + // Call the getNotificationAttachments method directly + ResponseEntity responseEntity = + notificationAttachmentController.getNotificationAttachments( + "123451", + null, + null, + null, + Pageable.unpaged() + ); + + assertNotNull(responseEntity); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertNotNull(responseEntity.getBody()); + assertNotNull(responseEntity.getBody().getContent()); + assertEquals(1, responseEntity.getBody().getContent().size()); + + NotificationAttachmentDetail retrievedNotificationAttachmentDetail = + notificationAttachmentService.getNotificationAttachment(282L); + + compareData(retrievedNotificationAttachmentDetail, responseEntity.getBody().getContent().getFirst()); + } + + @Test + @Sql(scripts = "/sql/notification_attachment_insert.sql") + public void testGetNotificationAttachments_usingAllFields() { + + // Call the getNotificationAttachments method directly + ResponseEntity responseEntity = + notificationAttachmentController.getNotificationAttachments( + "123451", + "123452", + "123453", + "Electronic", + Pageable.unpaged() + ); + + assertNotNull(responseEntity); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertNotNull(responseEntity.getBody()); + assertNotNull(responseEntity.getBody().getContent()); + assertEquals(1, responseEntity.getBody().getContent().size()); + + NotificationAttachmentDetail retrievedNotificationAttachmentDetails = + notificationAttachmentService.getNotificationAttachment(282L); + + compareData(retrievedNotificationAttachmentDetails, responseEntity.getBody().getContent().getFirst()); + } + + @Test + @Sql(scripts = "/sql/notification_attachment_insert.sql") + public void testGetNotificationAttachments_byProviderId() { + + // Call the getNotificationAttachments method directly + ResponseEntity responseEntity = + notificationAttachmentController.getNotificationAttachments( + null, + "123452", + null, + null, + Pageable.unpaged() + ); + + assertNotNull(responseEntity); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertNotNull(responseEntity.getBody()); + assertNotNull(responseEntity.getBody().getContent()); + assertEquals(1, responseEntity.getBody().getContent().size()); + + NotificationAttachmentDetail retrievedNotificationAttachmentDetails = + notificationAttachmentService.getNotificationAttachment(282L); + + compareData(retrievedNotificationAttachmentDetails, responseEntity.getBody().getContent().getFirst()); + } + + @Test + @Sql(scripts = "/sql/notification_attachment_insert.sql") + public void testGetNotificationAttachments_byDocumentType() { + + // Call the getNotificationAttachments method directly + ResponseEntity responseEntity = + notificationAttachmentController.getNotificationAttachments( + null, + null, + "123456", + null, + Pageable.unpaged() + ); + + assertNotNull(responseEntity); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertNotNull(responseEntity.getBody()); + assertNotNull(responseEntity.getBody().getContent()); + assertEquals(1, responseEntity.getBody().getContent().size()); + + NotificationAttachmentDetail retrievedNotificationAttachmentDetails = + notificationAttachmentService.getNotificationAttachment(283L); + + compareData(retrievedNotificationAttachmentDetails, responseEntity.getBody().getContent().getFirst()); + } + + @Test + @Sql(scripts = "/sql/notification_attachment_insert.sql") + public void testGetNotificationAttachments_bySendBy() { + + // Call the getNotificationAttachments method directly + ResponseEntity responseEntity = + notificationAttachmentController.getNotificationAttachments( + null, + null, + null, + "Electronic", + Pageable.unpaged() + ); + + assertNotNull(responseEntity); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertNotNull(responseEntity.getBody()); + assertNotNull(responseEntity.getBody().getContent()); + assertEquals(2, responseEntity.getBody().getContent().size()); + + NotificationAttachmentDetail firstRetrievedNotificationAttachmentDetail = + notificationAttachmentService.getNotificationAttachment(282L); + NotificationAttachmentDetail secondRetrievedNotificationAttachmentDetail = + notificationAttachmentService.getNotificationAttachment(283L); + + compareData(firstRetrievedNotificationAttachmentDetail, responseEntity.getBody().getContent().getFirst()); + compareData(secondRetrievedNotificationAttachmentDetail, responseEntity.getBody().getContent().getLast()); + } + + @Test + @Sql(scripts = "/sql/notification_attachment_insert.sql") + public void testGetNotificationAttachment() { + + // Call the getNotificationAttachment method directly + ResponseEntity responseEntity = + notificationAttachmentController.getNotificationAttachment(282L); + + assertNotNull(responseEntity); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertNotNull(responseEntity.getBody()); + assertEquals(282, responseEntity.getBody().getId()); + } + + @Test + @Sql(scripts = "/sql/notification_attachment_insert.sql") + public void testRemoveNotificationAttachment() { + + // Call the removeNotificationAttachments method directly + ResponseEntity responseEntity = + notificationAttachmentController.removeNotificationAttachment(282L, + caabUserLoginId); + + assertNotNull(responseEntity); + assertEquals(HttpStatus.NO_CONTENT, responseEntity.getStatusCode()); + + NotificationAttachmentDetails queriedDocuments = + notificationAttachmentController.getNotificationAttachments( + "123451", + "123452", + "123453", + "Electronic", + Pageable.unpaged() + ).getBody(); + + assertNotNull(queriedDocuments); + assertTrue(queriedDocuments.getContent().isEmpty()); + } + + @Test + @Sql(scripts = "/sql/notification_attachment_insert.sql") + public void testRemoveNotificationAttachments_usingAllFields() { + + // Call the removeNotificationAttachments method directly + ResponseEntity responseEntity = + notificationAttachmentController.removeNotificationAttachments( + "Caab-user-login-id", + "123451", + "123452", + "123453", + "Electronic" + ); + + assertNotNull(responseEntity); + assertEquals(HttpStatus.NO_CONTENT, responseEntity.getStatusCode()); + + // Check that only 1 of the NotificationAttachments (with Send By = Electronic) has been deleted. + NotificationAttachmentDetails queriedDocuments = + notificationAttachmentController.getNotificationAttachments( + null, + null, + null, + "Electronic", + Pageable.unpaged() + ).getBody(); + + assertNotNull(queriedDocuments); + assertEquals(1, queriedDocuments.getContent().size()); + } + + @Test + @Sql(scripts = "/sql/notification_attachment_insert.sql") + public void testRemoveNotificationAttachments_byNotificationReference() { + + // Call the removeNotificationAttachments method directly + ResponseEntity responseEntity = + notificationAttachmentController.removeNotificationAttachments( + "Caab-user-login-id", + "123451", + null, + null, + null + ); + + assertNotNull(responseEntity); + assertEquals(HttpStatus.NO_CONTENT, responseEntity.getStatusCode()); + + NotificationAttachmentDetails queriedDocuments = + notificationAttachmentController.getNotificationAttachments( + "123451", + null, + null, + null, + Pageable.unpaged() + ).getBody(); + + assertNotNull(queriedDocuments); + assertTrue(queriedDocuments.getContent().isEmpty()); + } + + @Test + @Sql(scripts = "/sql/notification_attachment_insert.sql") + public void testRemoveNotificationAttachments_byProviderId() { + + // Call the removeNotificationAttachments method directly + ResponseEntity responseEntity = + notificationAttachmentController.removeNotificationAttachments( + "Caab-user-login-id", + null, + "123452", + null, + null + ); + + assertNotNull(responseEntity); + assertEquals(HttpStatus.NO_CONTENT, responseEntity.getStatusCode()); + + NotificationAttachmentDetails queriedDocuments = + notificationAttachmentController.getNotificationAttachments( + null, + "123452", + null, + null, + Pageable.unpaged() + ).getBody(); + + assertNotNull(queriedDocuments); + assertTrue(queriedDocuments.getContent().isEmpty()); + } + + @Test + @Sql(scripts = "/sql/notification_attachment_insert.sql") + public void testRemoveNotificationAttachments_byDocumentType() { + + // Call the removeNotificationAttachments method directly + ResponseEntity responseEntity = + notificationAttachmentController.removeNotificationAttachments( + "Caab-user-login-id", + null, + null, + "123453", + null + ); + + assertNotNull(responseEntity); + assertEquals(HttpStatus.NO_CONTENT, responseEntity.getStatusCode()); + + NotificationAttachmentDetails queriedDocuments = + notificationAttachmentController.getNotificationAttachments( + null, + null, + "123453", + null, + Pageable.unpaged() + ).getBody(); + + assertNotNull(queriedDocuments); + assertTrue(queriedDocuments.getContent().isEmpty()); + } + + @Test + @Sql(scripts = "/sql/notification_attachment_insert.sql") + public void testRemoveNotificationAttachments_bySendBy() { + + // Call the removeNotificationAttachments method directly + ResponseEntity responseEntity = + notificationAttachmentController.removeNotificationAttachments( + "Caab-user-login-id", + null, + null, + null, + "Electronic" + ); + + assertNotNull(responseEntity); + assertEquals(HttpStatus.NO_CONTENT, responseEntity.getStatusCode()); + + NotificationAttachmentDetails queriedDocuments = + notificationAttachmentController.getNotificationAttachments( + null, + null, + null, + "Electronic", + Pageable.unpaged() + ).getBody(); + + assertNotNull(queriedDocuments); + assertTrue(queriedDocuments.getContent().isEmpty()); + } + + private static void compareData(NotificationAttachmentDetail retrievedNotificationAttachmentDetail, + BaseNotificationAttachmentDetail baseNotificationAttachmentDetail) { + assertEquals(retrievedNotificationAttachmentDetail.getId(), baseNotificationAttachmentDetail.getId()); + assertEquals(retrievedNotificationAttachmentDetail.getDescription(), baseNotificationAttachmentDetail.getDescription()); + assertEquals(retrievedNotificationAttachmentDetail.getDocumentType(), baseNotificationAttachmentDetail.getDocumentType()); + assertEquals(retrievedNotificationAttachmentDetail.getFileName(), baseNotificationAttachmentDetail.getFileName()); + assertEquals(retrievedNotificationAttachmentDetail.getProviderId(), baseNotificationAttachmentDetail.getProviderId()); + assertEquals(retrievedNotificationAttachmentDetail.getNumber(), baseNotificationAttachmentDetail.getNumber()); + assertEquals(retrievedNotificationAttachmentDetail.getSendBy(), baseNotificationAttachmentDetail.getSendBy()); + assertEquals(retrievedNotificationAttachmentDetail.getStatus(), baseNotificationAttachmentDetail.getStatus()); + } + +} diff --git a/caab-service/src/integrationTest/java/uk/gov/laa/ccms/data/api/controller/NotificationAttachmentControllerIntegrationLocalTest.java b/caab-service/src/integrationTest/java/uk/gov/laa/ccms/data/api/controller/NotificationAttachmentControllerIntegrationLocalTest.java new file mode 100644 index 0000000..38fed7a --- /dev/null +++ b/caab-service/src/integrationTest/java/uk/gov/laa/ccms/data/api/controller/NotificationAttachmentControllerIntegrationLocalTest.java @@ -0,0 +1,23 @@ +package uk.gov.laa.ccms.data.api.controller; + +import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.AFTER_TEST_METHOD; +import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.BEFORE_TEST_METHOD; +import static org.springframework.test.context.jdbc.SqlMergeMode.MergeMode.MERGE; + +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.jdbc.SqlMergeMode; +import uk.gov.laa.ccms.caab.api.CaabApiApplication; + +@SpringBootTest(classes = CaabApiApplication.class) +@SqlMergeMode(MERGE) +@ActiveProfiles("local") +@Sql(executionPhase = AFTER_TEST_METHOD, scripts = "/sql/delete_data.sql") +@Sql(executionPhase = BEFORE_TEST_METHOD, scripts = "/sql/delete_data.sql") +public class NotificationAttachmentControllerIntegrationLocalTest extends BaseNotificationAttachmentControllerIntegrationTest { + + //this runs all tests in BaseNotificationAttachmentControllerIntegrationTest, do not add anything here + //this is an easy way to run the tests if you have the containerised database running locally already + +} diff --git a/caab-service/src/integrationTest/java/uk/gov/laa/ccms/data/api/controller/NotificationAttachmentControllerIntegrationTest.java b/caab-service/src/integrationTest/java/uk/gov/laa/ccms/data/api/controller/NotificationAttachmentControllerIntegrationTest.java new file mode 100644 index 0000000..a67db37 --- /dev/null +++ b/caab-service/src/integrationTest/java/uk/gov/laa/ccms/data/api/controller/NotificationAttachmentControllerIntegrationTest.java @@ -0,0 +1,26 @@ +package uk.gov.laa.ccms.data.api.controller; + +import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.BEFORE_TEST_METHOD; +import static org.springframework.test.context.jdbc.SqlMergeMode.MergeMode.MERGE; + +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.jdbc.SqlConfig; +import org.springframework.test.context.jdbc.SqlConfig.ErrorMode; +import org.springframework.test.context.jdbc.SqlConfig.TransactionMode; +import org.springframework.test.context.jdbc.SqlMergeMode; +import uk.gov.laa.ccms.caab.api.CaabApiApplication; +import uk.gov.laa.ccms.data.api.IntegrationTestInterface; + +@SpringBootTest(classes = CaabApiApplication.class) +@SqlMergeMode(MERGE) +@Sql(executionPhase = BEFORE_TEST_METHOD, scripts = "/sql/application_tables_drop_schema.sql", config = @SqlConfig(transactionMode = TransactionMode.ISOLATED, errorMode = ErrorMode.CONTINUE_ON_ERROR)) +@Sql(executionPhase = BEFORE_TEST_METHOD, scripts = "/sql/application_tables_create_schema.sql", config = @SqlConfig(transactionMode = TransactionMode.ISOLATED)) +public class NotificationAttachmentControllerIntegrationTest extends BaseNotificationAttachmentControllerIntegrationTest implements + IntegrationTestInterface { + + //this runs all tests in BaseNotificationAttachmentControllerIntegrationTest, do not add anything here + //running this class takes longer than the local version, but it is used for running tests in a pipeline + +} + diff --git a/caab-service/src/integrationTest/resources/json/notification_attachment_new.json b/caab-service/src/integrationTest/resources/json/notification_attachment_new.json new file mode 100644 index 0000000..8f749da --- /dev/null +++ b/caab-service/src/integrationTest/resources/json/notification_attachment_new.json @@ -0,0 +1,14 @@ +{ + "file_data": "YmxhIGJsYQ==", + "provider_id": "12345", + "document_type": { + "id": "12345", + "display_value": "Document Type" + }, + "description": "description", + "file_name": "file name", + "send_by": "send by", + "status": "status", + "number": "1", + "notification_reference": "12345" +} \ No newline at end of file diff --git a/caab-service/src/integrationTest/resources/sql/application_tables_create_schema.sql b/caab-service/src/integrationTest/resources/sql/application_tables_create_schema.sql index f00c1f8..aedd795 100644 --- a/caab-service/src/integrationTest/resources/sql/application_tables_create_schema.sql +++ b/caab-service/src/integrationTest/resources/sql/application_tables_create_schema.sql @@ -526,6 +526,26 @@ CREATE TABLE XXCCMS_EVIDENCE_DOCUMENTS PRIMARY KEY ("ID") ); +CREATE TABLE XXCCMS_NOTIFICATION_ATTACHMENT +( + "ID" NUMBER(19,0) NOT NULL, + "NOTIFICATION_REFERENCE" VARCHAR2(50 CHAR) NOT NULL, + "PROVIDER_ID" VARCHAR2(19 CHAR) NOT NULL, + "NOTIFICATION_NUMBER" NUMBER(19,0), + "TYPE" VARCHAR2(50 CHAR), + "TYPE_DISPLAY_VALUE" VARCHAR2(50 CHAR), + "SEND_BY" VARCHAR2(50 CHAR), + "DESCRIPTION" VARCHAR2(50 CHAR), + "STATUS" VARCHAR2(50 CHAR), + "FILE_NAME" VARCHAR2(255 CHAR), + "FILE_BYTES" BLOB, + "CREATED" TIMESTAMP (6) DEFAULT SYSDATE NOT NULL, + "CREATED_BY" VARCHAR2(50 CHAR) DEFAULT USER NOT NULL, + "MODIFIED" TIMESTAMP (6), + "MODIFIED_BY" VARCHAR2(50 CHAR), + PRIMARY KEY ("ID") +); + CREATE INDEX XXCCMS_APPLICATION_I2 ON XXCCMS_APPLICATION (FK_COST_STRUCTURE); CREATE INDEX XXCCMS_APPLICATION_I3 ON XXCCMS_APPLICATION (FK_CORRESPONDENCE_ADDRESS); CREATE INDEX XXCCMS_COST_ENTRY_I1 on XXCCMS_COST_ENTRY (FK_COST_STRUCTURE); diff --git a/caab-service/src/integrationTest/resources/sql/application_tables_drop_schema.sql b/caab-service/src/integrationTest/resources/sql/application_tables_drop_schema.sql index facf5c5..1cc5d59 100644 --- a/caab-service/src/integrationTest/resources/sql/application_tables_drop_schema.sql +++ b/caab-service/src/integrationTest/resources/sql/application_tables_drop_schema.sql @@ -26,6 +26,7 @@ DROP TABLE XXCCMS_APPLICATION; DROP TABLE XXCCMS_COST_STRUCTURE; DROP TABLE XXCCMS_ADDRESS; DROP TABLE XXCCMS_EVIDENCE_DOCUMENTS; +DROP TABLE XXCCMS_NOTIFICATION_ATTACHMENT; -- drop sequence DROP SEQUENCE XXCCMS_GENERATED_ID_S; diff --git a/caab-service/src/integrationTest/resources/sql/delete_data.sql b/caab-service/src/integrationTest/resources/sql/delete_data.sql index 587eed7..a743615 100644 --- a/caab-service/src/integrationTest/resources/sql/delete_data.sql +++ b/caab-service/src/integrationTest/resources/sql/delete_data.sql @@ -22,3 +22,4 @@ DELETE FROM XXCCMS_APPLICATION; DELETE FROM XXCCMS_COST_STRUCTURE; DELETE FROM XXCCMS_ADDRESS; DELETE FROM XXCCMS_EVIDENCE_DOCUMENTS; +DELETE FROM XXCCMS_NOTIFICATION_ATTACHMENT; diff --git a/caab-service/src/integrationTest/resources/sql/notification_attachment_insert.sql b/caab-service/src/integrationTest/resources/sql/notification_attachment_insert.sql new file mode 100644 index 0000000..7d85a94 --- /dev/null +++ b/caab-service/src/integrationTest/resources/sql/notification_attachment_insert.sql @@ -0,0 +1,104 @@ +INSERT INTO XXCCMS_NOTIFICATION_ATTACHMENT ( + ID, + NOTIFICATION_REFERENCE, + PROVIDER_ID, + NOTIFICATION_NUMBER, + "TYPE", + TYPE_DISPLAY_VALUE, + SEND_BY, + DESCRIPTION, + STATUS, + FILE_NAME, + FILE_BYTES, + CREATED, + CREATED_BY, + MODIFIED, + MODIFIED_BY +) +VALUES ( + 282, + '123451', + '123452', + 1, + '123453', + 'Document Type', + 'Electronic', + 'Description', + 'Status', + 'File Name', + TO_BLOB('626C6120626C61'), + SYSDATE, + 'SOMEUSER@COMPANY.CO.UK', + null, + null +); + +INSERT INTO XXCCMS_NOTIFICATION_ATTACHMENT ( + ID, + NOTIFICATION_REFERENCE, + PROVIDER_ID, + NOTIFICATION_NUMBER, + "TYPE", + TYPE_DISPLAY_VALUE, + SEND_BY, + DESCRIPTION, + STATUS, + FILE_NAME, + FILE_BYTES, + CREATED, + CREATED_BY, + MODIFIED, + MODIFIED_BY +) +VALUES ( + 283, + '123454', + '123455', + 1, + '123456', + 'Document Type', + 'Electronic', + 'Description', + 'Status', + 'File Name', + TO_BLOB('626C6120626C61'), + SYSDATE, + 'SOMEOTHERUSER@COMPANY.CO.UK', + null, + null +); + +INSERT INTO XXCCMS_NOTIFICATION_ATTACHMENT ( + ID, + NOTIFICATION_REFERENCE, + PROVIDER_ID, + NOTIFICATION_NUMBER, + "TYPE", + TYPE_DISPLAY_VALUE, + SEND_BY, + DESCRIPTION, + STATUS, + FILE_NAME, + FILE_BYTES, + CREATED, + CREATED_BY, + MODIFIED, + MODIFIED_BY +) +VALUES ( + 284, + '123457', + '123458', + 1, + '123459', + 'Document Type', + 'Post', + 'Description', + 'Status', + 'File Name', + TO_BLOB('626C6120626C61'), + SYSDATE, + 'SOMEOTHEROTHERUSER@COMPANY.CO.UK', + null, + null +); \ No newline at end of file diff --git a/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/controller/NotificationAttachmentController.java b/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/controller/NotificationAttachmentController.java new file mode 100644 index 0000000..2ada8e8 --- /dev/null +++ b/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/controller/NotificationAttachmentController.java @@ -0,0 +1,98 @@ +package uk.gov.laa.ccms.caab.api.controller; + +import java.net.URI; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; +import uk.gov.laa.ccms.caab.api.NotificationAttachmentsApi; +import uk.gov.laa.ccms.caab.api.service.NotificationAttachmentService; +import uk.gov.laa.ccms.caab.model.NotificationAttachmentDetail; +import uk.gov.laa.ccms.caab.model.NotificationAttachmentDetails; + +/** + * Controller handling notification attachment related requests. Implements the {@code + * NotificationAttachmentsApi} interface for standardized endpoint definitions and provides the + * necessary endpoints to manage and retrieve notification attachment data. + */ +@RestController +@RequiredArgsConstructor +public class NotificationAttachmentController implements NotificationAttachmentsApi { + + private final NotificationAttachmentService notificationAttachmentService; + + @Override + public ResponseEntity getNotificationAttachments( + final String notificationReference, + final String providerId, + final String documentType, + final String sendBy, + final Pageable pageable) { + + NotificationAttachmentDetails notificationAttachmentDetails = + notificationAttachmentService.getNotificationAttachments( + notificationReference, providerId, documentType, sendBy, pageable); + + return new ResponseEntity<>(notificationAttachmentDetails, HttpStatus.OK); + } + + @Override + public ResponseEntity getNotificationAttachment( + final Long notificationAttachmentId) { + + NotificationAttachmentDetail notificationAttachmentDetail = + notificationAttachmentService.getNotificationAttachment(notificationAttachmentId); + + return new ResponseEntity<>(notificationAttachmentDetail, HttpStatus.OK); + } + + @Override + public ResponseEntity createNotificationAttachment( + final String caabUserLoginId, + final NotificationAttachmentDetail notificationAttachmentDetail) { + + Long notificationAttachmentId = + notificationAttachmentService.createNotificationAttachment(notificationAttachmentDetail); + + URI uri = + ServletUriComponentsBuilder.fromCurrentRequest() + .path("/{id}") + .buildAndExpand(notificationAttachmentId) + .toUri(); + + HttpHeaders headers = new HttpHeaders(); + headers.setLocation(uri); + + return new ResponseEntity<>(headers, HttpStatus.CREATED); + } + + @Override + public ResponseEntity removeNotificationAttachment( + final Long notificationAttachmentId, + final String caabUserLoginId) { + + notificationAttachmentService.removeNotificationAttachment(notificationAttachmentId); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @Override + public ResponseEntity removeNotificationAttachments( + final String caabUserLoginId, + final String notificationReference, + final String providerId, + final String documentType, + final String sendBy) { + + notificationAttachmentService.removeNotificationAttachments( + notificationReference, + providerId, + documentType, + sendBy); + + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + +} diff --git a/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/entity/NotificationAttachment.java b/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/entity/NotificationAttachment.java new file mode 100644 index 0000000..dfdb03a --- /dev/null +++ b/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/entity/NotificationAttachment.java @@ -0,0 +1,112 @@ +package uk.gov.laa.ccms.caab.api.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.Lob; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.Table; +import java.io.Serializable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +/** + * Represents a notification attachment entity associated with the "XXCCMS_NOTIFICAITON_ATTACHMENT" + * table. + * + *

This entity is utilized to manage and persist notification attachment data + * within the CCMS system. It makes use of the "XXCCMS_GENERATED_ID_S" + * sequence for generating unique identifiers.

+ */ +@Entity +@EntityListeners(AuditingEntityListener.class) +@Table(name = "XXCCMS_NOTIFICATION_ATTACHMENT") +@SequenceGenerator( + allocationSize = 1, + sequenceName = "XXCCMS_GENERATED_ID_S", + name = "XXCCMS_NOTIFICATION_ATTACHMENT_S") +@Getter +@Setter +@RequiredArgsConstructor +public class NotificationAttachment implements Serializable { + + /** + * The unique identifier for the NotificationAttachment. + */ + @Id + @GeneratedValue(generator = "XXCCMS_NOTIFICATION_ATTACHMENT_S") + private Long id; + + /** + * ID for the notification this attachment belongs to. + */ + @Column(name = "NOTIFICATION_REFERENCE") + private String notificationReference; + + /** + * The related provider ID. + */ + @Column(name = "PROVIDER_ID", length = 19) + private String providerId; + + /** + * The number for this attachment. + */ + @Column(name = "NOTIFICATION_NUMBER") + private Long number; + + /** + * The type of document. + */ + @Column(name = "TYPE", length = 50) + private String documentType; + + /** + * The display value for the document type. + */ + @Column(name = "TYPE_DISPLAY_VALUE", length = 50) + private String documentTypeDisplayValue; + + /** + * Whether the document is postal or electronic. + */ + @Column(name = "SEND_BY", length = 50) + private String sendBy; + + /** + * The description of the file. + */ + @Column(name = "DESCRIPTION") + private String description; + + /** + * The status of the document. + */ + @Column(name = "STATUS", length = 50) + private String status; + + /** + * The document file name. + */ + @Column(name = "FILE_NAME") + private String fileName; + + /** + * The document file data. + */ + @Column(name = "FILE_BYTES") + @Lob + private byte[] fileBytes; + + /** + * Audit trail info. + */ + @Embedded + private AuditTrail auditTrail = new AuditTrail(); + +} diff --git a/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/mapper/EvidenceMapper.java b/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/mapper/EvidenceMapper.java index 4c40e7a..467107e 100644 --- a/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/mapper/EvidenceMapper.java +++ b/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/mapper/EvidenceMapper.java @@ -1,7 +1,6 @@ package uk.gov.laa.ccms.caab.api.mapper; -import java.util.Base64; import org.mapstruct.InheritInverseConfiguration; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @@ -18,7 +17,7 @@ @Mapper(componentModel = "spring", uses = CommonMapper.class) -public interface EvidenceMapper { +public interface EvidenceMapper extends FileDataMapper { EvidenceDocumentDetails toEvidenceDocumentDetails( final Page evidenceDocuments); @@ -39,12 +38,4 @@ EvidenceDocumentDetail toEvidenceDocumentDetail( uk.gov.laa.ccms.caab.api.entity.EvidenceDocument toEvidenceDocument( final EvidenceDocumentDetail evidenceDocumentDetail); - default String toBase64String(byte[] bytes) { - return bytes != null ? Base64.getEncoder().encodeToString(bytes) : null; - } - - default byte[] toByteArrayFromBase64EncodedString(String base64EncodedString) { - return Base64.getDecoder().decode(base64EncodedString); - } - } diff --git a/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/mapper/FileDataMapper.java b/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/mapper/FileDataMapper.java new file mode 100644 index 0000000..171fd9b --- /dev/null +++ b/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/mapper/FileDataMapper.java @@ -0,0 +1,30 @@ +package uk.gov.laa.ccms.caab.api.mapper; + +import java.util.Base64; + +/** + * A Mixin style interface which provides pre-defined file data mapping methods. + */ +public interface FileDataMapper { + + /** + * Convert a byte array to a base64 encoded string. + * + * @param bytes of the file content. + * @return a base64 encoded String of the file content. + */ + default String toBase64String(byte[] bytes) { + return bytes != null ? Base64.getEncoder().encodeToString(bytes) : null; + } + + /** + * Convert a base64 encoded string of binary data to a byte array. + * + * @param base64EncodedString of the file content + * @return a byte array of the file content. + */ + default byte[] toByteArrayFromBase64EncodedString(String base64EncodedString) { + return Base64.getDecoder().decode(base64EncodedString); + } + +} diff --git a/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/mapper/NotificationAttachmentMapper.java b/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/mapper/NotificationAttachmentMapper.java new file mode 100644 index 0000000..d5f5290 --- /dev/null +++ b/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/mapper/NotificationAttachmentMapper.java @@ -0,0 +1,41 @@ +package uk.gov.laa.ccms.caab.api.mapper; + +import org.mapstruct.InheritInverseConfiguration; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.springframework.data.domain.Page; +import uk.gov.laa.ccms.caab.api.entity.NotificationAttachment; +import uk.gov.laa.ccms.caab.model.BaseNotificationAttachmentDetail; +import uk.gov.laa.ccms.caab.model.NotificationAttachmentDetail; +import uk.gov.laa.ccms.caab.model.NotificationAttachmentDetails; + +/** + * Interface responsible for mapping and transforming objects related + * to the notification attachment domain. It bridges the gap between the data model + * and the service or API layers, ensuring consistent object translation. + */ + +@Mapper(componentModel = "spring", + uses = CommonMapper.class) +public interface NotificationAttachmentMapper extends FileDataMapper { + + NotificationAttachmentDetails toNotificationAttachmentDetails( + final Page notificationAttachments); + + @Mapping(target = "documentType.id", source = "documentType") + @Mapping(target = "documentType.displayValue", source = "documentTypeDisplayValue") + BaseNotificationAttachmentDetail toBaseNotificationAttachmentDetail( + final uk.gov.laa.ccms.caab.api.entity.NotificationAttachment notificationAttachment); + + @Mapping(target = "documentType.id", source = "documentType") + @Mapping(target = "documentType.displayValue", source = "documentTypeDisplayValue") + @Mapping(target = "fileData", source = "fileBytes") + NotificationAttachmentDetail toNotificationAttachmentDetail( + final uk.gov.laa.ccms.caab.api.entity.NotificationAttachment notificationAttachment); + + @InheritInverseConfiguration + @Mapping(target = "auditTrail", ignore = true) + uk.gov.laa.ccms.caab.api.entity.NotificationAttachment toNotificationAttachment( + final NotificationAttachmentDetail notificationAttachmentDetail); + +} diff --git a/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/repository/NotificationAttachmentRepository.java b/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/repository/NotificationAttachmentRepository.java new file mode 100644 index 0000000..f316c10 --- /dev/null +++ b/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/repository/NotificationAttachmentRepository.java @@ -0,0 +1,17 @@ +package uk.gov.laa.ccms.caab.api.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import uk.gov.laa.ccms.caab.api.entity.NotificationAttachment; + +/** + * Repository interface for managing {@link NotificationAttachment} entities. + * + *

This interface provides CRUD (Create, Read, Update, Delete) operations for the {@link + * NotificationAttachment} entity, leveraging the power of Spring Data JPA. It automatically + * provides methods to save, find, and delete notification attachment documents, amongst other + * common operations found within {@link JpaRepository}. + */ +public interface NotificationAttachmentRepository + extends JpaRepository, + JpaSpecificationExecutor {} diff --git a/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/service/NotificationAttachmentService.java b/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/service/NotificationAttachmentService.java new file mode 100644 index 0000000..739525d --- /dev/null +++ b/caab-service/src/main/java/uk/gov/laa/ccms/caab/api/service/NotificationAttachmentService.java @@ -0,0 +1,137 @@ +package uk.gov.laa.ccms.caab.api.service; + +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Example; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import uk.gov.laa.ccms.caab.api.entity.NotificationAttachment; +import uk.gov.laa.ccms.caab.api.exception.CaabApiException; +import uk.gov.laa.ccms.caab.api.mapper.NotificationAttachmentMapper; +import uk.gov.laa.ccms.caab.api.repository.NotificationAttachmentRepository; +import uk.gov.laa.ccms.caab.model.NotificationAttachmentDetail; +import uk.gov.laa.ccms.caab.model.NotificationAttachmentDetails; + +/** + * Service responsible for handling notification attachment operations. + * + * @see NotificationAttachmentRepository + * @see NotificationAttachmentMapper + */ +@Service +@RequiredArgsConstructor +@Slf4j +public class NotificationAttachmentService { + + private final NotificationAttachmentRepository repository; + private final NotificationAttachmentMapper mapper; + + /** + * Get a Page of NotificationAttachments for the supplied search criteria. + * + * @param providerId - the provider id. + * @param documentType - the document type. + * @param pageable - the pageable settings. + * @return NotificationAttachmentDetails wrapping a page of NotificationAttachments. + */ + public NotificationAttachmentDetails getNotificationAttachments( + final String notificationReference, + final String providerId, + final String documentType, + final String sendBy, + final Pageable pageable) { + + Example exampleDocument = + buildExampleDocument(notificationReference, providerId, documentType, sendBy); + + return mapper.toNotificationAttachmentDetails(repository.findAll(exampleDocument, pageable)); + } + + /** + * Get a single NotificationAttachmentDetail by id. + * + * @param id - the notification attachment id. + * @return NotificationAttachmentDetail with the matching id, or else an error. + */ + public NotificationAttachmentDetail getNotificationAttachment(final Long id) { + + return repository + .findById(id) + .map(mapper::toNotificationAttachmentDetail) + .orElseThrow( + () -> + new CaabApiException( + String.format("Failed to find notification attachment with id: %s", id), + HttpStatus.NOT_FOUND)); + } + + /** + * Create a new NotificationAttachment entry. + * + * @param notificationAttachmentDetail - the notification attachment to create. + * @return the id of the newly created notification attachment. + */ + public Long createNotificationAttachment( + final NotificationAttachmentDetail notificationAttachmentDetail) { + + uk.gov.laa.ccms.caab.api.entity.NotificationAttachment createdNotificationAttachment = + repository.save(mapper.toNotificationAttachment(notificationAttachmentDetail)); + + return createdNotificationAttachment.getId(); + } + + /** + * Removes a notification attachment entry. If the notification attachment is not found, a + * CaabApiException is thrown. + * + * @param notificationAttachmentId The unique identifier of the notification attachment to be + * removed. + * @throws CaabApiException If the notification attachment with the specified ID is not found. + */ + @Transactional + public void removeNotificationAttachment(final Long notificationAttachmentId) { + + if (repository.existsById(notificationAttachmentId)) { + repository.deleteById(notificationAttachmentId); + } else { + throw new CaabApiException( + String.format("NotificationAttachment with id: %s not found", notificationAttachmentId), + HttpStatus.NOT_FOUND); + } + } + + /** + * Remove all notification attachments which match the provided search criteria. + * + * @param providerId - the provider id. + * @param documentType - the document type. + */ + @Transactional + public void removeNotificationAttachments( + final String notificationReference, + final String providerId, + final String documentType, + final String sendBy) { + + Example exampleDocument = + buildExampleDocument(notificationReference, providerId, documentType, sendBy); + + repository.deleteAll(repository.findAll(exampleDocument)); + } + + private Example buildExampleDocument( + final String notificationReference, + final String providerId, + final String documentType, + final String sendBy) { + + NotificationAttachment exampleDocument = new NotificationAttachment(); + exampleDocument.setNotificationReference(notificationReference); + exampleDocument.setProviderId(providerId); + exampleDocument.setDocumentType(documentType); + exampleDocument.setSendBy(sendBy); + return Example.of(exampleDocument); + } +} diff --git a/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/controller/NotificationAttachmentControllerTest.java b/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/controller/NotificationAttachmentControllerTest.java new file mode 100644 index 0000000..c159957 --- /dev/null +++ b/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/controller/NotificationAttachmentControllerTest.java @@ -0,0 +1,145 @@ +package uk.gov.laa.ccms.caab.api.controller; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; +import static uk.gov.laa.ccms.caab.api.util.ModelUtils.buildNotificationAttachmentDetail; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PageableHandlerMethodArgumentResolver; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import uk.gov.laa.ccms.caab.api.service.NotificationAttachmentService; +import uk.gov.laa.ccms.caab.model.NotificationAttachmentDetail; +import uk.gov.laa.ccms.caab.model.NotificationAttachmentDetails; + +@ExtendWith(SpringExtension.class) +@WebAppConfiguration +public class NotificationAttachmentControllerTest { + + private final String caabUserLoginId = "userLoginId"; + @Mock + private NotificationAttachmentService notificationAttachmentService; + @InjectMocks + private NotificationAttachmentController notificationAttachmentController; + private MockMvc mockMvc; + private ObjectMapper objectMapper; + + @BeforeEach + public void setup() { + mockMvc = standaloneSetup(notificationAttachmentController).setCustomArgumentResolvers( + new PageableHandlerMethodArgumentResolver()).build(); + + objectMapper = new ObjectMapper(); + } + + @Test + public void removeNotificationAttachment_RemovesEntry() throws Exception { + Long notificationAttachmentId = 2L; + + doNothing().when(notificationAttachmentService).removeNotificationAttachment(notificationAttachmentId); + + this.mockMvc.perform( + delete("/notification-attachments/{notification-attachment-id}", notificationAttachmentId) + .header("Caab-User-Login-Id", caabUserLoginId)) + .andExpect(status().isNoContent()); + + verify(notificationAttachmentService).removeNotificationAttachment(notificationAttachmentId); + } + + @Test + public void getNotificationAttachments_returnsCorrectly() throws Exception { + NotificationAttachmentDetail notificationAttachmentDetail = buildNotificationAttachmentDetail(); + + when( + notificationAttachmentService.getNotificationAttachments( + eq(notificationAttachmentDetail.getNotificationReference()), + eq(notificationAttachmentDetail.getProviderId()), + eq(notificationAttachmentDetail.getDocumentType().getId()), + eq(notificationAttachmentDetail.getSendBy()), + any(Pageable.class))).thenReturn( + new NotificationAttachmentDetails()); + + this.mockMvc.perform(get("/notification-attachments") + .param("notification-reference", notificationAttachmentDetail.getNotificationReference()) + .param("provider-id", notificationAttachmentDetail.getProviderId()) + .param("document-type", notificationAttachmentDetail.getDocumentType().getId()) + .param("send-by", notificationAttachmentDetail.getSendBy())) + .andDo(print()) + .andExpect(status().isOk()); + + verify(notificationAttachmentService).getNotificationAttachments( + eq(notificationAttachmentDetail.getNotificationReference()), + eq(notificationAttachmentDetail.getProviderId()), + eq(notificationAttachmentDetail.getDocumentType().getId()), + eq(notificationAttachmentDetail.getSendBy()), + any(Pageable.class)); + } + + @Test + public void getNotificationAttachment_returnsCorrectly() throws Exception { + NotificationAttachmentDetail notificationAttachmentDetail = buildNotificationAttachmentDetail(); + + when( + notificationAttachmentService.getNotificationAttachment(notificationAttachmentDetail.getId().longValue())).thenReturn( + new NotificationAttachmentDetail()); + + this.mockMvc.perform( + get("/notification-attachments/{notification-attachment-id}", notificationAttachmentDetail.getId().longValue())) + .andDo(print()).andExpect(status().isOk()); + + verify(notificationAttachmentService).getNotificationAttachment(notificationAttachmentDetail.getId().longValue()); + } + + @Test + public void createNotificationAttachment_isCreated() throws Exception { + NotificationAttachmentDetail notificationAttachmentDetail = buildNotificationAttachmentDetail(); + + when(notificationAttachmentService.createNotificationAttachment(notificationAttachmentDetail)).thenReturn( + notificationAttachmentDetail.getId().longValue()); + + this.mockMvc.perform(post("/notification-attachments").header("Caab-User-Login-Id", caabUserLoginId) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(notificationAttachmentDetail))) + .andExpect(status().isCreated()).andExpect( + header().string("Location", "http://localhost/notification-attachments/" + notificationAttachmentDetail.getId())); + } + + @Test + public void removeNotificationAttachments_callsServiceMethod() throws Exception { + NotificationAttachmentDetail notificationAttachmentDetail = buildNotificationAttachmentDetail(); + + this.mockMvc.perform(delete("/notification-attachments") + .header("Caab-User-Login-Id", caabUserLoginId) + .param("notification-reference", notificationAttachmentDetail.getNotificationReference()) + .param("provider-id", notificationAttachmentDetail.getProviderId()) + .param("document-type", notificationAttachmentDetail.getDocumentType().getId()) + .param("send-by", notificationAttachmentDetail.getSendBy())) + .andDo(print()) + .andExpect(status().isNoContent()); + + verify(notificationAttachmentService).removeNotificationAttachments( + notificationAttachmentDetail.getNotificationReference(), + notificationAttachmentDetail.getProviderId(), + notificationAttachmentDetail.getDocumentType().getId(), + notificationAttachmentDetail.getSendBy()); + } + +} diff --git a/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/mapper/NotificationAttachmentMapperTest.java b/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/mapper/NotificationAttachmentMapperTest.java new file mode 100644 index 0000000..9b190fe --- /dev/null +++ b/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/mapper/NotificationAttachmentMapperTest.java @@ -0,0 +1,97 @@ +package uk.gov.laa.ccms.caab.api.mapper; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static uk.gov.laa.ccms.caab.api.util.ModelUtils.buildNotificationAttachment; +import static uk.gov.laa.ccms.caab.api.util.ModelUtils.buildNotificationAttachmentDetail; + +import java.text.ParseException; +import java.util.Base64; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import uk.gov.laa.ccms.caab.api.entity.NotificationAttachment; +import uk.gov.laa.ccms.caab.model.NotificationAttachmentDetail; +import uk.gov.laa.ccms.caab.model.NotificationAttachmentDetails; + +@ExtendWith(MockitoExtension.class) +public class NotificationAttachmentMapperTest { + + @InjectMocks + private final NotificationAttachmentMapper mapper = new NotificationAttachmentMapperImpl(); + + @BeforeEach + public void setup() throws ParseException { + } + + @Test + public void testToNotificationAttachmentDetails_null() { + NotificationAttachmentDetails notificationAttachmentDetails = mapper.toNotificationAttachmentDetails(null); + assertNull(notificationAttachmentDetails); + } + + @Test + public void testToNotificationAttachmentDetails() { + Page notificationAttachments = new PageImpl<>(List.of(new NotificationAttachment())); + + NotificationAttachmentDetails result = mapper.toNotificationAttachmentDetails(notificationAttachments); + + assertNotNull(result); + assertNotNull(result.getContent()); + assertEquals(1, result.getContent().size()); + } + + @Test + public void testToNotificationAttachmentDetail() { + // Construct NotificationAttachment + NotificationAttachment notificationAttachment = buildNotificationAttachment(); + + // Convert NotificationAttachment to NotificationAttachmentDetail + NotificationAttachmentDetail result = mapper.toNotificationAttachmentDetail(notificationAttachment); + + assertNotNull(result); + assertNotNull(result.getAuditTrail()); + assertEquals(notificationAttachment.getDescription(), result.getDescription()); + assertEquals(notificationAttachment.getDocumentType(), result.getDocumentType().getId()); + assertEquals(notificationAttachment.getDocumentTypeDisplayValue(), result.getDocumentType().getDisplayValue()); + assertEquals(Base64.getEncoder().encodeToString(notificationAttachment.getFileBytes()), result.getFileData()); + assertEquals(notificationAttachment.getFileName(), result.getFileName()); + assertEquals(notificationAttachment.getId().intValue(), result.getId()); + assertEquals(notificationAttachment.getNotificationReference(), result.getNotificationReference()); + assertEquals(notificationAttachment.getProviderId(), result.getProviderId()); + assertEquals(notificationAttachment.getSendBy(), result.getSendBy()); + assertEquals(notificationAttachment.getStatus(), result.getStatus()); + assertEquals(notificationAttachment.getNumber(), result.getNumber()); + } + + @Test + public void testToNotificationAttachment() { + // Construct NotificationAttachmentDetail + NotificationAttachmentDetail notificationAttachmentDetail = buildNotificationAttachmentDetail(); + + // Convert NotificationAttachmentDetail to NotificationAttachment + NotificationAttachment result = mapper.toNotificationAttachment(notificationAttachmentDetail); + + assertNotNull(result); + assertNotNull(result.getAuditTrail()); + assertEquals(notificationAttachmentDetail.getDescription(), result.getDescription()); + assertEquals(notificationAttachmentDetail.getDocumentType().getId(), result.getDocumentType()); + assertEquals(notificationAttachmentDetail.getDocumentType().getDisplayValue(), result.getDocumentTypeDisplayValue()); + assertArrayEquals(Base64.getDecoder().decode(notificationAttachmentDetail.getFileData()), result.getFileBytes()); + assertEquals(notificationAttachmentDetail.getFileName(), result.getFileName()); + assertEquals(notificationAttachmentDetail.getId().intValue(), result.getId()); + assertEquals(notificationAttachmentDetail.getNotificationReference(), result.getNotificationReference()); + assertEquals(notificationAttachmentDetail.getProviderId(), result.getProviderId()); + assertEquals(notificationAttachmentDetail.getSendBy(), result.getSendBy()); + assertEquals(notificationAttachmentDetail.getStatus(), result.getStatus()); + assertEquals(notificationAttachmentDetail.getNumber(), result.getNumber()); + } + +} diff --git a/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/service/NotificationAttachmentServiceTest.java b/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/service/NotificationAttachmentServiceTest.java new file mode 100644 index 0000000..99b0840 --- /dev/null +++ b/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/service/NotificationAttachmentServiceTest.java @@ -0,0 +1,151 @@ +package uk.gov.laa.ccms.caab.api.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static uk.gov.laa.ccms.caab.api.util.ModelUtils.buildNotificationAttachment; +import static uk.gov.laa.ccms.caab.api.util.ModelUtils.buildNotificationAttachmentDetail; + +import java.util.List; +import java.util.Optional; +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; +import org.springframework.data.domain.Example; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import uk.gov.laa.ccms.caab.api.entity.NotificationAttachment; +import uk.gov.laa.ccms.caab.api.exception.CaabApiException; +import uk.gov.laa.ccms.caab.api.mapper.NotificationAttachmentMapper; +import uk.gov.laa.ccms.caab.api.repository.NotificationAttachmentRepository; +import uk.gov.laa.ccms.caab.model.NotificationAttachmentDetail; +import uk.gov.laa.ccms.caab.model.NotificationAttachmentDetails; + +@ExtendWith(MockitoExtension.class) +public class NotificationAttachmentServiceTest { + + @Mock + private NotificationAttachmentRepository repository; + + @Mock + private NotificationAttachmentMapper mapper; + + @InjectMocks + private NotificationAttachmentService notificationAttachmentService; + + @Test + void createNotificationAttachment_createsNotificationAttachment() { + NotificationAttachmentDetail notificationAttachmentDetail = new NotificationAttachmentDetail(); + NotificationAttachment notificationAttachment = buildNotificationAttachment(); + + when(mapper.toNotificationAttachment(notificationAttachmentDetail)).thenReturn(notificationAttachment); + when(repository.save(notificationAttachment)).thenReturn(notificationAttachment); + + Long result = notificationAttachmentService.createNotificationAttachment(notificationAttachmentDetail); + + assertNotNull(result); + assertEquals(notificationAttachment.getId(), result); + + verify(mapper).toNotificationAttachment(notificationAttachmentDetail); + verify(repository).save(notificationAttachment); + } + + @Test + void getNotificationAttachmentDetails_queriesByExample() { + NotificationAttachment notificationAttachment = buildNotificationAttachment(); + + NotificationAttachmentDetails expectedResponse = new NotificationAttachmentDetails(); + + Page notificationAttachmentPage = new PageImpl<>( + List.of(buildNotificationAttachment())); + + when(repository.findAll(any(Example.class), + eq(Pageable.unpaged()))).thenReturn(notificationAttachmentPage); + when(mapper.toNotificationAttachmentDetails(notificationAttachmentPage)).thenReturn(expectedResponse); + + NotificationAttachmentDetails result = notificationAttachmentService.getNotificationAttachments( + notificationAttachment.getNotificationReference(), + notificationAttachment.getProviderId(), + notificationAttachment.getDocumentType(), + notificationAttachment.getSendBy(), + Pageable.unpaged()); + + assertNotNull(result); + assertEquals(expectedResponse, result); + + verify(repository).findAll(any(Example.class), eq(Pageable.unpaged())); + verify(mapper).toNotificationAttachmentDetails(notificationAttachmentPage); + } + + @Test + void getNotificationAttachmentDetail_retrievesCorrectly() { + NotificationAttachmentDetail notificationAttachmentDetail = buildNotificationAttachmentDetail(); + + NotificationAttachment notificationAttachment = buildNotificationAttachment(); + + when(repository.findById(notificationAttachmentDetail.getId().longValue())).thenReturn(Optional.of(notificationAttachment)); + when(mapper.toNotificationAttachmentDetail(notificationAttachment)).thenReturn(notificationAttachmentDetail); + + NotificationAttachmentDetail result = notificationAttachmentService.getNotificationAttachment(notificationAttachmentDetail.getId().longValue()); + + assertNotNull(result); + assertEquals(notificationAttachmentDetail, result); + + verify(repository).findById(notificationAttachmentDetail.getId().longValue()); + verify(mapper).toNotificationAttachmentDetail(notificationAttachment); + } + + @Test + void removeNotificationAttachment_whenExists_removesEntry() { + Long notificationAttachmentId = 1L; + when(repository.existsById(notificationAttachmentId)).thenReturn(true); + doNothing().when(repository).deleteById(notificationAttachmentId); + + notificationAttachmentService.removeNotificationAttachment(notificationAttachmentId); + + verify(repository).existsById(notificationAttachmentId); + verify(repository).deleteById(notificationAttachmentId); + } + + @Test + void removeNotificationAttachment_whenNotExists_throwsException() { + Long notificationAttachmentId = 1L; + when(repository.existsById(notificationAttachmentId)).thenReturn(false); + + CaabApiException exception = assertThrows(CaabApiException.class, () -> + notificationAttachmentService.removeNotificationAttachment(notificationAttachmentId)); + + assertEquals("NotificationAttachment with id: 1 not found", exception.getMessage()); + assertEquals(HttpStatus.NOT_FOUND, exception.getHttpStatus()); + } + + @Test + void removeNotificationAttachmentDetails_deletesBasedOnExample() { + NotificationAttachment notificationAttachment = buildNotificationAttachment(); + + List notificationAttachments = + List.of(buildNotificationAttachment()); + + when(repository.findAll(any(Example.class))).thenReturn(notificationAttachments); + + notificationAttachmentService.removeNotificationAttachments( + notificationAttachment.getNotificationReference(), + notificationAttachment.getProviderId(), + notificationAttachment.getDocumentType(), + notificationAttachment.getSendBy()); + + verify(repository).findAll(any(Example.class)); + verify(repository).deleteAll(notificationAttachments); + + } + +} diff --git a/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/util/ModelUtils.java b/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/util/ModelUtils.java index 322d83e..87ec49a 100644 --- a/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/util/ModelUtils.java +++ b/caab-service/src/test/java/uk/gov/laa/ccms/caab/api/util/ModelUtils.java @@ -16,6 +16,7 @@ import uk.gov.laa.ccms.caab.api.entity.FinancialAward; import uk.gov.laa.ccms.caab.api.entity.LandAward; import uk.gov.laa.ccms.caab.api.entity.LiableParty; +import uk.gov.laa.ccms.caab.api.entity.NotificationAttachment; import uk.gov.laa.ccms.caab.api.entity.Opponent; import uk.gov.laa.ccms.caab.api.entity.OtherAssetAward; import uk.gov.laa.ccms.caab.api.entity.ProceedingOutcome; @@ -29,6 +30,7 @@ import uk.gov.laa.ccms.caab.model.FinancialAwardDetail; import uk.gov.laa.ccms.caab.model.LandAwardDetail; import uk.gov.laa.ccms.caab.model.LiablePartyDetail; +import uk.gov.laa.ccms.caab.model.NotificationAttachmentDetail; import uk.gov.laa.ccms.caab.model.OpponentDetail; import uk.gov.laa.ccms.caab.model.OtherAssetAwardDetail; import uk.gov.laa.ccms.caab.model.ProceedingOutcomeDetail; @@ -198,6 +200,42 @@ public static EvidenceDocumentDetail buildEvidenceDocumentDetail() { .transferStatus("stat"); } + public static NotificationAttachment buildNotificationAttachment() { + NotificationAttachment notificationAttachment = new NotificationAttachment(); + notificationAttachment.setAuditTrail(buildAuditTrail()); + notificationAttachment.setDescription("descr"); + notificationAttachment.setDocumentType("doctype"); + notificationAttachment.setDocumentTypeDisplayValue("doc type"); + notificationAttachment.setFileBytes("the file data".getBytes()); + notificationAttachment.setFileName("name"); + notificationAttachment.setId(123L); + notificationAttachment.setNotificationReference("notref"); + notificationAttachment.setProviderId("provId"); + notificationAttachment.setNumber(1L); + notificationAttachment.setSendBy("sendby"); + notificationAttachment.setStatus("status"); + + return notificationAttachment; + } + + public static NotificationAttachmentDetail buildNotificationAttachmentDetail() { + return new NotificationAttachmentDetail() + .auditTrail(buildAuditDetail()) + .description("descr") + .documentType(new StringDisplayValue() + .id("doctype") + .displayValue("doc type")) + .fileData(Base64.getEncoder().encodeToString("the file data".getBytes())) + .fileName("name") + .id(123) + .notificationReference("notref") + .providerId("provId") + .number(1L) + .sendBy("sendby") + .status("status"); + } + + public static CaseOutcome buildCaseOutcome() { CaseOutcome caseOutcome = new CaseOutcome(); caseOutcome.setAuditTrail(buildAuditTrail());