From 92fbaf29d4defe2adb69b91f1dfa771c29ae8622 Mon Sep 17 00:00:00 2001 From: SathishK-T <166369440+SathishK-T@users.noreply.github.com> Date: Fri, 28 Jun 2024 17:26:17 +0530 Subject: [PATCH] [APPS-2838][APPS-2839] POST and GET API implementation for the Retention Schedule Steps (#2721) * [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API * [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API * [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API * [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API * [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API * [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API * [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API * [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API * [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API * [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API * [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API * [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API * [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API * [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API * [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API * [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API * [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API * [APPS-2838][APPS-2839] Fixed Junit Testcases * [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API --------- Co-authored-by: Sathish Kumar Co-authored-by: suneet-gupta --- .../retentionschedule/RetentionSchedule.java | 9 + .../RetentionScheduleStepCollection.java | 33 ++ .../RetentionScheduleStepEntry.java | 38 ++ .../gscore/api/RetentionScheduleAPI.java | 73 ++++ .../RetentionScheduleStepTests.java | 358 ++++++++++++++++++ .../RetentionScheduleTests.java | 6 +- .../rm-public-rest-context.xml | 8 + .../rest/api/impl/ApiNodesModelFactory.java | 145 ++++++- .../rm/rest/api/model/RetentionEvents.java | 56 +++ .../rm/rest/api/model/RetentionPeriod.java | 55 +++ .../rm/rest/api/model/RetentionSchedule.java | 13 +- .../rm/rest/api/model/RetentionSteps.java | 46 +++ .../RetentionScheduleActionRelation.java | 243 ++++++++++++ .../RetentionScheduleEntityResource.java | 38 ++ .../RetentionScheduleRelation.java | 24 +- .../RetentionScheduleModelUnitTest.java | 48 ++- .../UnprocessableContentException.java | 40 ++ .../alfresco/public-rest-context.xml | 1 + 18 files changed, 1196 insertions(+), 38 deletions(-) create mode 100644 amps/ags/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/retentionschedule/RetentionScheduleStepCollection.java create mode 100644 amps/ags/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/retentionschedule/RetentionScheduleStepEntry.java create mode 100644 amps/ags/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/retentionschedule/RetentionScheduleStepTests.java create mode 100644 amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/model/RetentionEvents.java create mode 100644 amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/model/RetentionPeriod.java create mode 100644 amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/model/RetentionSteps.java create mode 100644 amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/retentionschedule/RetentionScheduleActionRelation.java create mode 100644 amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/retentionschedule/RetentionScheduleEntityResource.java create mode 100644 remote-api/src/main/java/org/alfresco/rest/framework/core/exceptions/UnprocessableContentException.java diff --git a/amps/ags/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/retentionschedule/RetentionSchedule.java b/amps/ags/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/retentionschedule/RetentionSchedule.java index 63ba5045a8..0e41e74dab 100644 --- a/amps/ags/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/retentionschedule/RetentionSchedule.java +++ b/amps/ags/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/retentionschedule/RetentionSchedule.java @@ -46,4 +46,13 @@ public class RetentionSchedule extends TestModel private boolean isRecordLevel; private boolean isUnpublishedUpdates; private List actions; + + public boolean getIsRecordLevel() + { + return isRecordLevel; + } + + public void setIsRecordLevel(boolean recordLevel) { + isRecordLevel = recordLevel; + } } diff --git a/amps/ags/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/retentionschedule/RetentionScheduleStepCollection.java b/amps/ags/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/retentionschedule/RetentionScheduleStepCollection.java new file mode 100644 index 0000000000..a0e13dc630 --- /dev/null +++ b/amps/ags/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/retentionschedule/RetentionScheduleStepCollection.java @@ -0,0 +1,33 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2024 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * - + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * - + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * - + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * - + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.rest.rm.community.model.retentionschedule; + +import org.alfresco.rest.core.RestModels; + +public class RetentionScheduleStepCollection extends RestModels +{ +} diff --git a/amps/ags/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/retentionschedule/RetentionScheduleStepEntry.java b/amps/ags/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/retentionschedule/RetentionScheduleStepEntry.java new file mode 100644 index 0000000000..715185236b --- /dev/null +++ b/amps/ags/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/retentionschedule/RetentionScheduleStepEntry.java @@ -0,0 +1,38 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2024 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * - + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * - + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * - + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * - + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.rest.rm.community.model.retentionschedule; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import org.alfresco.rest.core.RestModels; + +@Data +public class RetentionScheduleStepEntry extends RestModels +{ + @JsonProperty + private RetentionScheduleActionDefinition entry; +} diff --git a/amps/ags/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RetentionScheduleAPI.java b/amps/ags/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RetentionScheduleAPI.java index 83a2a142d4..ba0db9b0de 100644 --- a/amps/ags/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RetentionScheduleAPI.java +++ b/amps/ags/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RetentionScheduleAPI.java @@ -28,7 +28,9 @@ package org.alfresco.rest.rm.community.requests.gscore.api; import org.alfresco.rest.core.RMRestWrapper; import org.alfresco.rest.rm.community.model.retentionschedule.RetentionSchedule; +import org.alfresco.rest.rm.community.model.retentionschedule.RetentionScheduleActionDefinition; import org.alfresco.rest.rm.community.model.retentionschedule.RetentionScheduleCollection; +import org.alfresco.rest.rm.community.model.retentionschedule.RetentionScheduleStepCollection; import org.alfresco.rest.rm.community.requests.RMModelRequest; import static org.alfresco.rest.core.RestRequest.requestWithBody; @@ -122,4 +124,75 @@ public class RetentionScheduleAPI extends RMModelRequest { return getRetentionSchedule(recordCategoryId, EMPTY); } + + /** + * Creates a step in the retention schedule. + * + * @param retentionScheduleActionDefinition The retentionScheduleActionDefinition model + * @param retentionScheduleId The identifier of a retention schedule id + * @param parameters The URL parameters to add + * @return The created {@link RetentionScheduleActionDefinition} + * @throws RuntimeException for the following cases: + *
    + *
  • {@code retentionScheduleId} is not a valid format or {@code retentionScheduleId} is invalid
  • + *
  • authentication fails
  • + *
  • current user does not have permission to add children to {@code retentionScheduleId}
  • + *
  • {@code retentionScheduleId} does not exist
  • + *
  • new name clashes with an existing node in the current parent container
  • + *
+ */ + public RetentionScheduleActionDefinition createRetentionScheduleStep(RetentionScheduleActionDefinition retentionScheduleActionDefinition, String retentionScheduleId, String parameters) + { + mandatoryString("retentionScheduleId", retentionScheduleId); + mandatoryObject("retentionScheduleActionDefinition", retentionScheduleActionDefinition); + + return getRmRestWrapper().processModel(RetentionScheduleActionDefinition.class, requestWithBody( + POST, + toJson(retentionScheduleActionDefinition), + "retention-schedules/{retentionScheduleId}/retention-steps", + retentionScheduleId, + parameters + )); + } + + /** + * See {@link #createRetentionScheduleStep(RetentionScheduleActionDefinition, String)} (RetentionSchedule, String, String)} + */ + public RetentionScheduleActionDefinition createRetentionScheduleStep(RetentionScheduleActionDefinition retentionScheduleActionDefinition, String retentionScheduleId) + { + return createRetentionScheduleStep(retentionScheduleActionDefinition, retentionScheduleId, EMPTY); + } + + /** + * Gets the retentionSchedule of a record category. + * + * @param retentionScheduleId The identifier of a record category + * @param parameters The URL parameters to add + * @return The {@link RetentionScheduleActionDefinition} for the given {@code recordCategoryId} + * @throws RuntimeException for the following cases: + *
    + *
  • authentication fails
  • + *
  • current user does not have permission to read {@code recordCategoryId}
  • + *
  • {@code recordCategoryId} does not exist
  • + *
+ */ + public RetentionScheduleStepCollection getRetentionScheduleStep(String retentionScheduleId, String parameters) + { + mandatoryString("retentionScheduleId", retentionScheduleId); + + return getRmRestWrapper().processModels(RetentionScheduleStepCollection.class, simpleRequest( + GET, + "retention-schedules/{retentionScheduleId}/retention-steps?{parameters}", + retentionScheduleId, + parameters + )); + } + + /** + * See {@link #getRetentionScheduleStep(String, String)} + */ + public RetentionScheduleStepCollection getRetentionScheduleStep(String recordCategoryId) + { + return getRetentionScheduleStep(recordCategoryId, EMPTY); + } } \ No newline at end of file diff --git a/amps/ags/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/retentionschedule/RetentionScheduleStepTests.java b/amps/ags/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/retentionschedule/RetentionScheduleStepTests.java new file mode 100644 index 0000000000..60359e6f74 --- /dev/null +++ b/amps/ags/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/retentionschedule/RetentionScheduleStepTests.java @@ -0,0 +1,358 @@ +/*- + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2024 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * - + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * - + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * - + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * - + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.rest.rm.community.retentionschedule; + +import org.alfresco.rest.rm.community.base.BaseRMRestTest; +import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory; +import org.alfresco.rest.rm.community.model.retentionschedule.RetentionSchedule; +import org.alfresco.rest.rm.community.model.retentionschedule.RetentionScheduleActionDefinition; +import org.alfresco.rest.rm.community.model.retentionschedule.RetentionScheduleStepCollection; +import org.alfresco.rest.v0.RMRolesAndActionsAPI; +import org.alfresco.utility.model.UserModel; +import org.springframework.beans.factory.annotation.Autowired; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.alfresco.rest.core.v0.BaseAPI.RM_SITE_ID; +import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric; +import static org.alfresco.utility.data.RandomData.getRandomName; +import static org.springframework.http.HttpStatus.BAD_REQUEST; +import static org.springframework.http.HttpStatus.CONFLICT; +import static org.springframework.http.HttpStatus.CREATED; +import static org.springframework.http.HttpStatus.FORBIDDEN; +import static org.springframework.http.HttpStatus.NOT_FOUND; +import static org.springframework.http.HttpStatus.OK; +import static org.springframework.http.HttpStatus.UNAUTHORIZED; +import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY; +import static org.testng.Assert.assertNotNull; +import static org.testng.AssertJUnit.assertEquals; + +/** + * Retention schedule step test case + */ +public class RetentionScheduleStepTests extends BaseRMRestTest +{ + private RecordCategory recordCategory; + private RetentionSchedule createdRetentionSchedule; + private final RetentionScheduleActionDefinition retentionScheduleActionDefinition = new RetentionScheduleActionDefinition(); + private RetentionScheduleActionDefinition createdRetentionActionDefinition; + private UserModel nonRMuser; + private final List recordCategories = new ArrayList<>(); + private static final String TEST_USER = "testUser"; + private static final String RECORD_CATEGORY = "recordCategory"; + private static final String PERIOD_PROPERTY = "cm:created"; + private static final String AUTHORITY = "authority"; + private static final String INSTRUCTIONS = "instructions"; + private static final int PERIOD_AMOUNT = 5; + private static final String PERIOD = "month"; + private static final List EVENTS = Arrays.asList("case_closed","abolished"); + private static final String TRANSFER_STEP = "transfer"; + private static final String RETAIN_STEP = "retain"; + private static final String INVALID_PERIOD = "random"; + private static final String CUTOFF_STEP = "cutoff"; + private static final String DESTROY_STEP = "destroy"; + private static final String INVALID_PASSWORD = "wrongPassword"; + + @Autowired + private RMRolesAndActionsAPI rmRolesAndActionsAPI; + + @BeforeClass(alwaysRun = true) + public void preconditionForRetentionScheduleStepTests() + { + createRMSiteIfNotExists(); + // create a non rm user + nonRMuser = dataUser.createRandomTestUser(TEST_USER); + //Create record category + recordCategory = createRootCategory(getRandomName(RECORD_CATEGORY)); + recordCategories.add(recordCategory.getId()); + RetentionSchedule retentionSchedule = new RetentionSchedule(); + retentionSchedule.setAuthority(AUTHORITY + getRandomAlphanumeric()); + retentionSchedule.setInstructions(INSTRUCTIONS + getRandomAlphanumeric()); + retentionSchedule.setIsRecordLevel(false); + //Create retention schedule with a valid user + createdRetentionSchedule = getRestAPIFactory().getRetentionScheduleAPI() + .createRetentionSchedule(retentionSchedule, recordCategory.getId()); + + retentionScheduleActionDefinition.setName(RETAIN_STEP); + retentionScheduleActionDefinition.setDescription(INSTRUCTIONS); + retentionScheduleActionDefinition.setPeriodAmount(PERIOD_AMOUNT); + retentionScheduleActionDefinition.setPeriodProperty(PERIOD_PROPERTY); + retentionScheduleActionDefinition.setPeriod(PERIOD); + retentionScheduleActionDefinition.setCombineDispositionStepConditions(false); + retentionScheduleActionDefinition.setEligibleOnFirstCompleteEvent(true); + retentionScheduleActionDefinition.setEvents(EVENTS); + } + + @Test(priority = 1) + public void createRetentionScheduleStepFor422() + { + RetentionScheduleActionDefinition actionDefinition = getRetentionScheduleActionDefinition(); + //Creating the first action "transfer" should give 422 + actionDefinition.setName(TRANSFER_STEP); + //Create retention schedule action definition + getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition,createdRetentionSchedule.getId()); + // Verify the status code + assertStatusCode(UNPROCESSABLE_ENTITY); + } + + @Test(priority = 2) + public void createRetentionScheduleStepWithInvalidPeriodValue() + { + RetentionScheduleActionDefinition actionDefinition = getRetentionScheduleActionDefinition(); + actionDefinition.setName(RETAIN_STEP); + //Invalid period value + actionDefinition.setPeriod(INVALID_PERIOD); + //Create retention schedule action definition + getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition,createdRetentionSchedule.getId()); + // Verify the status code + assertStatusCode(BAD_REQUEST); + } + + @Test(priority = 3) + public void createRetentionScheduleWithInvalidStep() + { + RecordCategory recordCategory = createRootCategory(getRandomName(RECORD_CATEGORY)); + recordCategories.add(recordCategory.getId()); + RetentionSchedule retentionSchedule = createRetentionSchedule(recordCategory); + RetentionScheduleActionDefinition actionDefinition = getRetentionScheduleActionDefinition(); + actionDefinition.setName(RETAIN_STEP); + getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition,retentionSchedule.getId()); + + assertStatusCode(CREATED); + + RetentionScheduleActionDefinition actionDefinition1 = getRetentionScheduleActionDefinition(); + actionDefinition1.setName(TRANSFER_STEP); + getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition1,retentionSchedule.getId()); + + assertStatusCode(CREATED); + + RetentionScheduleActionDefinition actionDefinition2 = getRetentionScheduleActionDefinition(); + actionDefinition2.setName(CUTOFF_STEP); + //Create retention schedule action definition + getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition2,retentionSchedule.getId()); + // Verify the status code + assertStatusCode(CONFLICT); + } + + @Test(priority = 4) + public void createRetentionScheduleWithInvalidStepAfterDestroy() + { + RecordCategory recordCategory = createRootCategory(getRandomName(RECORD_CATEGORY)); + recordCategories.add(recordCategory.getId()); + RetentionSchedule retentionSchedule = createRetentionSchedule(recordCategory); + RetentionScheduleActionDefinition actionDefinition = getRetentionScheduleActionDefinition(); + actionDefinition.setName(RETAIN_STEP); + getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition,retentionSchedule.getId()); + + assertStatusCode(CREATED); + + RetentionScheduleActionDefinition actionDefinition1 = getRetentionScheduleActionDefinition(); + actionDefinition1.setName(DESTROY_STEP); + getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition1,retentionSchedule.getId()); + + assertStatusCode(CREATED); + + RetentionScheduleActionDefinition actionDefinition2 = getRetentionScheduleActionDefinition(); + actionDefinition2.setName(CUTOFF_STEP); + //Create retention schedule action definition + getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition2,retentionSchedule.getId()); + // Verify the status code + assertStatusCode(CONFLICT); + } + + @Test(priority = 5) + public void createRetentionScheduleWithSameStep() + { + RecordCategory recordCategory = createRootCategory(getRandomName(RECORD_CATEGORY)); + recordCategories.add(recordCategory.getId()); + RetentionSchedule retentionSchedule = createRetentionSchedule(recordCategory); + RetentionScheduleActionDefinition actionDefinition = getRetentionScheduleActionDefinition(); + actionDefinition.setName(RETAIN_STEP); + getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition,retentionSchedule.getId()); + + assertStatusCode(CREATED); + + RetentionScheduleActionDefinition actionDefinition1 = getRetentionScheduleActionDefinition(); + actionDefinition1.setName(RETAIN_STEP); + getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition1,retentionSchedule.getId()); + + // Verify the status code + assertStatusCode(CONFLICT); + } + + @Test(priority = 6) + public void createRetentionScheduleWithMultipleTransferStep() + { + RecordCategory recordCategory = createRootCategory(getRandomName(RECORD_CATEGORY)); + recordCategories.add(recordCategory.getId()); + RetentionSchedule retentionSchedule = createRetentionSchedule(recordCategory); + RetentionScheduleActionDefinition actionDefinition = getRetentionScheduleActionDefinition(); + actionDefinition.setName(RETAIN_STEP); + getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition,retentionSchedule.getId()); + + assertStatusCode(CREATED); + + RetentionScheduleActionDefinition actionDefinition1 = getRetentionScheduleActionDefinition(); + actionDefinition1.setName(TRANSFER_STEP); + getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition1, retentionSchedule.getId()); + + RetentionScheduleActionDefinition actionDefinition2 = getRetentionScheduleActionDefinition(); + actionDefinition2.setName(TRANSFER_STEP); + getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition2, retentionSchedule.getId()); + // Verify the status code + assertStatusCode(CREATED); + } + + @Test(priority = 7) + public void createRetentionScheduleStepFor201() + { + //Create retention schedule action definition + createdRetentionActionDefinition = getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(retentionScheduleActionDefinition,createdRetentionSchedule.getId()); + // Verify the status code + assertStatusCode(CREATED); + // Find this retention schedule is created one or not + assertEquals(createdRetentionActionDefinition.getName(), retentionScheduleActionDefinition.getName()); + assertEquals(createdRetentionActionDefinition.getDescription(), retentionScheduleActionDefinition.getDescription()); + assertEquals(createdRetentionActionDefinition.getPeriodAmount(), retentionScheduleActionDefinition.getPeriodAmount()); + assertEquals(createdRetentionActionDefinition.isCombineDispositionStepConditions(), retentionScheduleActionDefinition.isCombineDispositionStepConditions()); + assertEquals(createdRetentionActionDefinition.isEligibleOnFirstCompleteEvent(), retentionScheduleActionDefinition.isEligibleOnFirstCompleteEvent()); + } + + @Test(priority = 8) + public void createRetentionScheduleStepFor401() + { + //Create retention schedule action definition + getRestAPIFactory().getRetentionScheduleAPI(new UserModel(getAdminUser().getUsername(), INVALID_PASSWORD)).createRetentionScheduleStep(retentionScheduleActionDefinition,createdRetentionSchedule.getId()); + // Verify the status code + assertStatusCode(UNAUTHORIZED); + } + + @Test(priority = 9) + public void createRetentionScheduleStepFor403() + { + //Create retention schedule action definition + getRestAPIFactory().getRetentionScheduleAPI(nonRMuser).createRetentionScheduleStep(retentionScheduleActionDefinition,createdRetentionSchedule.getId()); + // Verify the status code + assertStatusCode(FORBIDDEN); + } + + @Test(priority = 10) + public void retentionScheduleStepFor400() + { + getRestAPIFactory().getRetentionScheduleAPI().getRetentionScheduleStep(recordCategory.getId()); + // Verify the status code + assertStatusCode(BAD_REQUEST); + } + + @Test(priority = 11) + public void createRetentionScheduleStepFor404() + { + //Create retention schedule action definition + getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(retentionScheduleActionDefinition,getRandomAlphanumeric()); + // Verify the status code + assertStatusCode(NOT_FOUND); + } + + @Test(priority = 12) + public void retentionScheduleStepFor403() + { + // Get retention schedule steps with user having no rights + getRestAPIFactory().getRetentionScheduleAPI(nonRMuser).getRetentionScheduleStep(createdRetentionSchedule.getId()); + // Verify the status code + assertStatusCode(FORBIDDEN); + } + + @Test(priority = 13) + public void retentionScheduleStepFor401() + { + getRestAPIFactory().getRetentionScheduleAPI(new UserModel(getAdminUser().getUsername(), INVALID_PASSWORD)).getRetentionScheduleStep(createdRetentionSchedule.getId()); + // Verify the status code + assertStatusCode(UNAUTHORIZED); + } + + @Test(priority = 14) + public void retentionScheduleStepWith200() + { + RetentionScheduleStepCollection receiveRetentionStepCollection = getRestAPIFactory().getRetentionScheduleAPI().getRetentionScheduleStep(createdRetentionSchedule.getId()); + // Verify the status code + assertStatusCode(OK); + receiveRetentionStepCollection.getEntries().forEach(c -> + { + RetentionScheduleActionDefinition retentionActionDef = c.getEntry(); + assertNotNull(retentionActionDef.getId()); + // Find this retention schedule is created one or not + assertEquals(createdRetentionActionDefinition.getId(), retentionActionDef.getId()); + assertEquals(createdRetentionActionDefinition.getName(), retentionActionDef.getName()); + assertEquals(createdRetentionActionDefinition.getDescription(), retentionActionDef.getDescription()); + assertEquals(createdRetentionActionDefinition.getPeriod(), retentionActionDef.getPeriod()); + assertEquals(createdRetentionActionDefinition.getPeriodAmount(), retentionActionDef.getPeriodAmount()); + assertEquals(createdRetentionActionDefinition.isCombineDispositionStepConditions(), retentionActionDef.isCombineDispositionStepConditions()); + assertEquals(createdRetentionActionDefinition.isEligibleOnFirstCompleteEvent(), retentionActionDef.isEligibleOnFirstCompleteEvent()); + }); + } + + private RetentionSchedule createRetentionSchedule(RecordCategory recordCategory) + { + RetentionSchedule retentionSchedule = new RetentionSchedule(); + retentionSchedule.setAuthority(AUTHORITY + getRandomAlphanumeric()); + retentionSchedule.setInstructions(INSTRUCTIONS + getRandomAlphanumeric()); + retentionSchedule.setIsRecordLevel(false); + //Create retention schedule with a valid user + retentionSchedule = getRestAPIFactory().getRetentionScheduleAPI() + .createRetentionSchedule(retentionSchedule, recordCategory.getId()); + // Verify the status code + assertStatusCode(CREATED); + return retentionSchedule; + } + + private static RetentionScheduleActionDefinition getRetentionScheduleActionDefinition() + { + RetentionScheduleActionDefinition actionDefinition = new RetentionScheduleActionDefinition(); + actionDefinition.setDescription(INSTRUCTIONS); + actionDefinition.setPeriodAmount(PERIOD_AMOUNT); + actionDefinition.setPeriodProperty(PERIOD_PROPERTY); + actionDefinition.setPeriod(PERIOD); + actionDefinition.setCombineDispositionStepConditions(false); + actionDefinition.setEligibleOnFirstCompleteEvent(true); + actionDefinition.setEvents(EVENTS); + return actionDefinition; + } + + @AfterClass(alwaysRun = true) + public void cleanUpRetentionScheduleStepTests() + { + rmRolesAndActionsAPI.deleteAllItemsInContainer(getDataUser().usingAdmin().getAdminUser().getUsername(), + getDataUser().usingAdmin().getAdminUser().getPassword(), RM_SITE_ID, recordCategory.getName()); + recordCategories.forEach(this::deleteRecordCategory); + dataUser.deleteUser(nonRMuser); + } +} \ No newline at end of file diff --git a/amps/ags/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/retentionschedule/RetentionScheduleTests.java b/amps/ags/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/retentionschedule/RetentionScheduleTests.java index 017530e385..c15c6774a4 100644 --- a/amps/ags/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/retentionschedule/RetentionScheduleTests.java +++ b/amps/ags/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/retentionschedule/RetentionScheduleTests.java @@ -145,7 +145,7 @@ public class RetentionScheduleTests extends BaseRMRestTest boolean isRecordLevel = false; retentionSchedule.setAuthority(authority); retentionSchedule.setInstructions(instructions); - retentionSchedule.setRecordLevel(isRecordLevel); + retentionSchedule.setIsRecordLevel(isRecordLevel); //Create retention schedule with a valid user createdRetentionSchedule = getRestAPIFactory().getRetentionScheduleAPI() @@ -155,7 +155,7 @@ public class RetentionScheduleTests extends BaseRMRestTest assertStatusCode(CREATED); assertEquals(createdRetentionSchedule.getAuthority(), authority); assertEquals(createdRetentionSchedule.getInstructions(), instructions); - assertFalse(createdRetentionSchedule.isRecordLevel()); + assertFalse(createdRetentionSchedule.getIsRecordLevel()); assertNotNull(createdRetentionSchedule.getId()); } @@ -254,7 +254,7 @@ public class RetentionScheduleTests extends BaseRMRestTest assertEquals(createdRetentionSchedule.getParentId(),retentionSchedule.getParentId()); assertEquals(createdRetentionSchedule.getAuthority(), retentionSchedule.getAuthority()); assertEquals(createdRetentionSchedule.getInstructions(), retentionSchedule.getInstructions()); - assertEquals(createdRetentionSchedule.isRecordLevel(), retentionSchedule.isRecordLevel()); + assertEquals(createdRetentionSchedule.getIsRecordLevel(), retentionSchedule.getIsRecordLevel()); assertEquals(createdRetentionSchedule.isUnpublishedUpdates(), retentionSchedule.isUnpublishedUpdates()); }); } diff --git a/amps/ags/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-public-rest-context.xml b/amps/ags/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-public-rest-context.xml index 970c73a5ee..efb01d2730 100644 --- a/amps/ags/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-public-rest-context.xml +++ b/amps/ags/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-public-rest-context.xml @@ -31,6 +31,7 @@ + @@ -154,6 +155,13 @@ + + + + + + + diff --git a/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/impl/ApiNodesModelFactory.java b/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/impl/ApiNodesModelFactory.java index 7cd3334d67..b392993023 100644 --- a/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/impl/ApiNodesModelFactory.java +++ b/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/impl/ApiNodesModelFactory.java @@ -35,9 +35,12 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.IntStream; import org.alfresco.model.ContentModel; +import org.alfresco.module.org_alfresco_module_rm.RecordsManagementServiceRegistry; import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionActionDefinition; +import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionActionDefinitionImpl; import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule; import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService; import org.alfresco.module.org_alfresco_module_rm.event.RecordsManagementEvent; @@ -56,6 +59,8 @@ import org.alfresco.rm.rest.api.model.Record; import org.alfresco.rm.rest.api.model.RecordCategory; import org.alfresco.rm.rest.api.model.RecordCategoryChild; import org.alfresco.rm.rest.api.model.RecordFolder; +import org.alfresco.rm.rest.api.model.RetentionPeriod; +import org.alfresco.rm.rest.api.model.RetentionSteps; import org.alfresco.rm.rest.api.model.Transfer; import org.alfresco.rm.rest.api.model.TransferChild; import org.alfresco.rm.rest.api.model.TransferContainer; @@ -75,8 +80,9 @@ import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; - -import static org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel.PROP_COMBINE_DISPOSITION_STEP_CONDITIONS; +import org.alfresco.service.namespace.RegexQNamePattern; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Utility class containing Alfresco and RM java services required by the API @@ -88,6 +94,9 @@ import static org.alfresco.module.org_alfresco_module_rm.model.RecordsManagement public class ApiNodesModelFactory { + /** Logger */ + private static final Logger LOGGER = LoggerFactory.getLogger(ApiNodesModelFactory.class); + // excluded namespaces (aspects, properties, assoc types) public static final List EXCLUDED_NS = Arrays.asList(NamespaceService.SYSTEM_MODEL_1_0_URI); @@ -109,6 +118,7 @@ public class ApiNodesModelFactory private PersonService personService; private DispositionService dispositionService; private ServiceRegistry serviceRegistry; + private RecordsManagementServiceRegistry services; public NodeService getNodeService() { @@ -160,6 +170,11 @@ public class ApiNodesModelFactory this.serviceRegistry = serviceRegistry; } + public void setRecordsManagementServiceRegistry(RecordsManagementServiceRegistry services) + { + this.services = services; + } + /** * Helper method that sets the basic information for most of the node types. * @@ -511,15 +526,15 @@ public class ApiNodesModelFactory } if(RecordsManagementModel.TYPE_RECORD_FOLDER.equals(info.getType())) { - if((!isMinimalInfo && propertyFilter.isAllowed(RecordCategoryChild.PARAM_IS_RECORD_FOLDER)) || (isMinimalInfo && includeParam.contains(RecordCategoryChild.PARAM_IS_RECORD_FOLDER))) + if (isRecordFolder(isMinimalInfo, propertyFilter, includeParam)) { recordCategoryChild.setIsRecordFolder(true); } - if((!isMinimalInfo && propertyFilter.isAllowed(RecordCategoryChild.PARAM_IS_RECORD_CATEGORY)) || (isMinimalInfo && includeParam.contains(RecordCategoryChild.PARAM_IS_RECORD_CATEGORY))) + if (isRecordCategory(isMinimalInfo, propertyFilter, includeParam)) { recordCategoryChild.setIsRecordCategory(false); } - if((!isMinimalInfo && propertyFilter.isAllowed(RMNode.PARAM_IS_CLOSED)) || (isMinimalInfo && includeParam.contains(RMNode.PARAM_IS_CLOSED))) + if (isRecordCategoryChildClosed(isMinimalInfo, propertyFilter, includeParam)) { recordCategoryChild.setIsClosed((Boolean) nodeService.getProperty(info.getNodeRef(), RecordsManagementModel.PROP_IS_CLOSED)); } @@ -530,11 +545,11 @@ public class ApiNodesModelFactory } else { - if((!isMinimalInfo && propertyFilter.isAllowed(RecordCategoryChild.PARAM_IS_RECORD_FOLDER)) || (isMinimalInfo && includeParam.contains(RecordCategoryChild.PARAM_IS_RECORD_FOLDER))) + if (isRecordFolder(isMinimalInfo, propertyFilter, includeParam)) { recordCategoryChild.setIsRecordFolder(false); } - if((!isMinimalInfo && propertyFilter.isAllowed(RecordCategoryChild.PARAM_IS_RECORD_CATEGORY)) || (isMinimalInfo && includeParam.contains(RecordCategoryChild.PARAM_IS_RECORD_CATEGORY))) + if (isRecordCategory(isMinimalInfo, propertyFilter, includeParam)) { recordCategoryChild.setIsRecordCategory(true); } @@ -543,13 +558,28 @@ public class ApiNodesModelFactory DispositionSchedule ds = dispositionService.getDispositionSchedule(info.getNodeRef()); recordCategoryChild.setHasRetentionSchedule(ds != null); } - if((!isMinimalInfo && propertyFilter.isAllowed(RMNode.PARAM_IS_CLOSED)) || (isMinimalInfo && includeParam.contains(RMNode.PARAM_IS_CLOSED))) + if (isRecordCategoryChildClosed(isMinimalInfo, propertyFilter, includeParam)) { recordCategoryChild.setIsClosed(null); } } } + private boolean isRecordCategoryChildClosed(boolean isMinimalInfo, BeanPropertiesFilter propertyFilter, List includeParam) + { + return (!isMinimalInfo && propertyFilter.isAllowed(RMNode.PARAM_IS_CLOSED)) || (isMinimalInfo && includeParam.contains(RMNode.PARAM_IS_CLOSED)); + } + + private boolean isRecordCategory(boolean isMinimalInfo, BeanPropertiesFilter propertyFilter, List includeParam) + { + return (!isMinimalInfo && propertyFilter.isAllowed(RecordCategoryChild.PARAM_IS_RECORD_CATEGORY)) || (isMinimalInfo && includeParam.contains(RecordCategoryChild.PARAM_IS_RECORD_CATEGORY)); + } + + private boolean isRecordFolder(boolean isMinimalInfo, BeanPropertiesFilter propertyFilter, List includeParam) + { + return (!isMinimalInfo && propertyFilter.isAllowed(RecordCategoryChild.PARAM_IS_RECORD_FOLDER)) || (isMinimalInfo && includeParam.contains(RecordCategoryChild.PARAM_IS_RECORD_FOLDER)); + } + /** * Utility method that maps record specific fields @@ -572,7 +602,8 @@ public class ApiNodesModelFactory { Serializable val = info.getProperties().get(ContentModel.PROP_CONTENT); - if ((val != null) && (val instanceof ContentData)) { + if (val instanceof ContentData) + { ContentData cd = (ContentData)val; String mimeType = cd.getMimetype(); String mimeTypeName = serviceRegistry.getMimetypeService().getDisplaysByMimetype().get(mimeType); @@ -914,7 +945,7 @@ public class ApiNodesModelFactory } retentionSchedule.setInstructions(dispositionSchedule.getDispositionInstructions()); retentionSchedule.setAuthority(dispositionSchedule.getDispositionAuthority()); - retentionSchedule.setRecordLevel(dispositionSchedule.isRecordLevelDisposition()); + retentionSchedule.setIsRecordLevel(dispositionSchedule.isRecordLevelDisposition()); boolean unpublishedUpdates = dispositionSchedule.getDispositionActionDefinitions().stream() .map(DispositionActionDefinition::getNodeRef) @@ -951,9 +982,9 @@ public class ApiNodesModelFactory retentionScheduleActionDefinition.setName(dispositionActionDefinition.getName()); retentionScheduleActionDefinition.setDescription(dispositionActionDefinition.getDescription()); retentionScheduleActionDefinition.setEligibleOnFirstCompleteEvent(dispositionActionDefinition.eligibleOnFirstCompleteEvent()); - if (nodeService.getProperty(dispositionActionDefinition.getNodeRef(), PROP_COMBINE_DISPOSITION_STEP_CONDITIONS) != null) + if (nodeService.getProperty(dispositionActionDefinition.getNodeRef(), RecordsManagementModel.PROP_COMBINE_DISPOSITION_STEP_CONDITIONS) != null) { - retentionScheduleActionDefinition.setCombineDispositionStepConditions((Boolean) nodeService.getProperty(dispositionActionDefinition.getNodeRef(), PROP_COMBINE_DISPOSITION_STEP_CONDITIONS)); + retentionScheduleActionDefinition.setCombineDispositionStepConditions((Boolean) nodeService.getProperty(dispositionActionDefinition.getNodeRef(), RecordsManagementModel.PROP_COMBINE_DISPOSITION_STEP_CONDITIONS)); } retentionScheduleActionDefinition.setLocation(dispositionActionDefinition.getLocation()); if (dispositionActionDefinition.getGhostOnDestroy() != null) @@ -970,9 +1001,11 @@ public class ApiNodesModelFactory */ private void mapPeriodProperties(DispositionActionDefinition dispositionActionDefinition, RetentionScheduleActionDefinition retentionScheduleActionDefinition) { - if(dispositionActionDefinition.getPeriodProperty() != null) { + if(dispositionActionDefinition.getPeriodProperty() != null) + { retentionScheduleActionDefinition.setPeriodProperty(dispositionActionDefinition.getPeriodProperty().toPrefixString(namespaceService)); } + String period = dispositionActionDefinition.getPeriod().toString(); if (!period.isEmpty()) { @@ -982,19 +1015,22 @@ public class ApiNodesModelFactory // period -> 'month' // periodAmount -> 10 String[] periodArray = period.split("\\|"); + if (periodArray.length > 0) { retentionScheduleActionDefinition.setPeriod(periodArray[0]); } + if (periodArray.length > 1) { try { retentionScheduleActionDefinition.setPeriodAmount(Integer.parseInt(periodArray[1])); } - catch (NumberFormatException e) + catch (NumberFormatException numberFormatException) { - throw new NumberFormatException("Error parsing period amount: " + e.getMessage()); + LOGGER.error("Error parsing period amount: {}{}", numberFormatException.getMessage(), periodArray[1], numberFormatException); + throw numberFormatException; } } } @@ -1033,4 +1069,83 @@ public class ApiNodesModelFactory retentionSchedule.setActions(actions); } } + + /** + * this method is used for creation of retention schedule action definition params + * @param nodeInfo retention schedule action definition + * @return Map + */ + public Map createRetentionActionDefinitionParams(RetentionScheduleActionDefinition nodeInfo) + { + Map actionDefinitionParams= new HashMap<>(); + actionDefinitionParams.put(RecordsManagementModel.PROP_DISPOSITION_ACTION_NAME, nodeInfo.getName()); + actionDefinitionParams.put(RecordsManagementModel.PROP_DISPOSITION_DESCRIPTION, nodeInfo.getDescription()); + StringBuilder retentionPeriod = new StringBuilder(nodeInfo.getPeriod()).append("|"); + if(isPeriodAmountApplicable(nodeInfo.getPeriod())) + { + retentionPeriod.append(nodeInfo.getPeriodAmount()); + } + actionDefinitionParams.put(RecordsManagementModel.PROP_DISPOSITION_PERIOD, retentionPeriod.toString()); + QName periodProperty = QName.createQName(nodeInfo.getPeriodProperty(), namespaceService); + actionDefinitionParams.put(RecordsManagementModel.PROP_DISPOSITION_PERIOD_PROPERTY, periodProperty); + actionDefinitionParams.put(RecordsManagementModel.PROP_DISPOSITION_EVENT_COMBINATION, + nodeInfo.isEligibleOnFirstCompleteEvent()); + actionDefinitionParams.put(RecordsManagementModel.PROP_COMBINE_DISPOSITION_STEP_CONDITIONS, + nodeInfo.isCombineDispositionStepConditions()); + actionDefinitionParams.put(RecordsManagementModel.PROP_DISPOSITION_LOCATION, + nodeInfo.getLocation()); + List inputEvents = nodeInfo.getEvents(); + actionDefinitionParams.put(RecordsManagementModel.PROP_DISPOSITION_EVENT, (Serializable) inputEvents); + if (RetentionSteps.DESTROY.stepName.equals(nodeInfo.getName()) && nodeInfo.isRetainRecordMetadataAfterDestruction()) + { + actionDefinitionParams.put(RecordsManagementModel.PROP_DISPOSITION_ACTION_GHOST_ON_DESTROY, "ghost"); + } + else + { + actionDefinitionParams.put(RecordsManagementModel.PROP_DISPOSITION_ACTION_GHOST_ON_DESTROY, "delete"); + } + return actionDefinitionParams; + } + + /** + * this method is used retrieve retention schedule action details + * @param retentionScheduleNodeRef nodeRef + * @return List + */ + public List getRetentionActions(NodeRef retentionScheduleNodeRef) + { + List assocs = nodeService.getChildAssocs( + retentionScheduleNodeRef, + RecordsManagementModel.ASSOC_DISPOSITION_ACTION_DEFINITIONS, + RegexQNamePattern.MATCH_ALL); + // we are getting disposition action definitions based on retention schedule child association. + // setting the index value for each action. + List actions; + actions = IntStream.range(0, assocs.size()) + .mapToObj(index -> + { + ChildAssociationRef assoc = assocs.get(index); + return new DispositionActionDefinitionImpl( + services.getRecordsManagementEventService(), + services.getRecordsManagementActionService(), + nodeService, + assoc.getChildRef(), + index); + }) + .collect(Collectors.toList()); + return actions; + } + + /** + * this method is used to check period amount applicable or not for particular period + * @param period period + * @return boolean + */ + private boolean isPeriodAmountApplicable(String period) + { + // periodAmount property only applicable for following periods + // day, week, month, quarter, year and duration + return period.equals(RetentionPeriod.DAY.periodName) || period.equals(RetentionPeriod.MONTH.periodName) || period.equals(RetentionPeriod.QUARTER.periodName) + || period.equals(RetentionPeriod.WEEK.periodName) || period.equals(RetentionPeriod.XML_DURATION.periodName) || period.equals(RetentionPeriod.YEAR.periodName); + } } \ No newline at end of file diff --git a/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/model/RetentionEvents.java b/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/model/RetentionEvents.java new file mode 100644 index 0000000000..76b330ce7f --- /dev/null +++ b/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/model/RetentionEvents.java @@ -0,0 +1,56 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2024 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * - + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * - + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * - + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * - + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.rm.rest.api.model; + +/** + * Retention event values + */ +public enum RetentionEvents +{ + CASE_CLOSED("case_closed"), + ABOLISHED("abolished"), + RE_DESIGNATED("re_designated"), + NO_LONGER_NEEDED("no_longer_needed"), + SUPERSEDED("superseded"), + VERSIONED("versioned"), + STUDY_COMPLETE("study_complete"), + TRAINING_COMPLETE("training_complete"), + TRANSFERRED_INACTIVE_STORAGE("related_record_trasfered_inactive_storage"), + OBSOLETE("obsolete"), + ALLOWANCES_GRANTED_TERMINATED("all_allowances_granted_are_terminated"), + WGI_ACTION_COMPLETE("WGI_action_complete"), + SEPARATION("separation"), + CASE_COMPLETE("case_complete"), + DECLASSIFICATION_REVIEW("declassification_review"); + + public final String eventName; + + RetentionEvents(String eventName) + { + this.eventName = eventName; + } +} \ No newline at end of file diff --git a/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/model/RetentionPeriod.java b/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/model/RetentionPeriod.java new file mode 100644 index 0000000000..21bfb4cdf6 --- /dev/null +++ b/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/model/RetentionPeriod.java @@ -0,0 +1,55 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2024 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * - + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * - + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * - + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * - + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.rm.rest.api.model; + +/** + * Retention period values + */ +public enum RetentionPeriod +{ + DAY("day"), + END_OF_FINANCIAL_MONTH("fmend"), + END_OF_FINANCIAL_QUARTER("fqend"), + END_OF_FINANCIAL_YEAR("fyend"), + IMMEDIATELY("immediately"), + END_OF_MONTH("monthend"), + END_OF_QUARTER("quarterend"), + END_OF_YEAR("yearend"), + MONTH("month"), + NONE("none"), + QUARTER("quarter"), + WEEK("week"), + XML_DURATION("duration"), + YEAR("year"); + + public final String periodName; + + RetentionPeriod(String periodName) + { + this.periodName = periodName; + } +} \ No newline at end of file diff --git a/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/model/RetentionSchedule.java b/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/model/RetentionSchedule.java index 1f698d0f33..d1869ebf86 100644 --- a/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/model/RetentionSchedule.java +++ b/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/model/RetentionSchedule.java @@ -27,6 +27,7 @@ package org.alfresco.rm.rest.api.model; import lombok.Data; + import java.util.List; /** @@ -42,4 +43,14 @@ public class RetentionSchedule private boolean isRecordLevel; private boolean isUnpublishedUpdates; private List actions; -} + + public boolean getIsRecordLevel() + { + return isRecordLevel; + } + + public void setIsRecordLevel(boolean recordLevel) + { + isRecordLevel = recordLevel; + } +} \ No newline at end of file diff --git a/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/model/RetentionSteps.java b/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/model/RetentionSteps.java new file mode 100644 index 0000000000..e8ecbd32bf --- /dev/null +++ b/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/model/RetentionSteps.java @@ -0,0 +1,46 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2024 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * - + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * - + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * - + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * - + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.rm.rest.api.model; + +/** + * Retention steps values + */ +public enum RetentionSteps +{ + RETAIN("retain"), + CUTOFF("cutoff"), + TRANSFER("transfer"), + ACCESSION("accession"), + DESTROY("destroy"); + + public final String stepName; + + RetentionSteps(String stepName) + { + this.stepName = stepName; + } +} \ No newline at end of file diff --git a/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/retentionschedule/RetentionScheduleActionRelation.java b/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/retentionschedule/RetentionScheduleActionRelation.java new file mode 100644 index 0000000000..8e4c443751 --- /dev/null +++ b/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/retentionschedule/RetentionScheduleActionRelation.java @@ -0,0 +1,243 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2024 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * - + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * - + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * - + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * - + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.rm.rest.api.retentionschedule; + +import org.alfresco.module.org_alfresco_module_rm.RecordsManagementServiceRegistry; +import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionActionDefinition; +import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule; +import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionScheduleImpl; +import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel; +import org.alfresco.rest.framework.WebApiDescription; +import org.alfresco.rest.framework.core.exceptions.ConstraintViolatedException; +import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; +import org.alfresco.rest.framework.core.exceptions.UnprocessableContentException; +import org.alfresco.rest.framework.resource.RelationshipResource; +import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction; +import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; +import org.alfresco.rest.framework.resource.parameters.Parameters; +import org.alfresco.rm.rest.api.impl.ApiNodesModelFactory; +import org.alfresco.rm.rest.api.impl.FilePlanComponentsApiUtils; +import org.alfresco.rm.rest.api.model.RetentionEvents; +import org.alfresco.rm.rest.api.model.RetentionPeriod; +import org.alfresco.rm.rest.api.model.RetentionScheduleActionDefinition; +import org.alfresco.rm.rest.api.model.RetentionSteps; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.alfresco.module.org_alfresco_module_rm.util.RMParameterCheck.checkNotBlank; +import static org.alfresco.util.ParameterCheck.mandatory; + +/** + * Retention schedule action relation is used to perform the retention schedule step operations. + */ +@RelationshipResource(name = "retention-steps", entityResource = RetentionScheduleEntityResource.class, title = "Retention Schedule Action") +public class RetentionScheduleActionRelation implements RelationshipResourceAction.Read, + RelationshipResourceAction.Create +{ + private FilePlanComponentsApiUtils apiUtils; + protected NodeService nodeService; + private RecordsManagementServiceRegistry service; + private ApiNodesModelFactory nodesModelFactory; + + public void setApiUtils(FilePlanComponentsApiUtils apiUtils) + { + this.apiUtils = apiUtils; + } + + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + public void setNodesModelFactory(ApiNodesModelFactory nodesModelFactory) + { + this.nodesModelFactory = nodesModelFactory; + } + + public void setRecordsManagementServiceRegistry(RecordsManagementServiceRegistry service) + { + this.service = service; + } + + @Override + @WebApiDescription(title="Create a retention schedule step for the particular retention schedule using the 'retentionScheduleId'") + public List create(String retentionScheduleId, List nodeInfos, Parameters parameters) + { + checkNotBlank("retentionScheduleId", retentionScheduleId); + mandatory("entity", nodeInfos); + mandatory("parameters", parameters); + NodeRef retentionScheduleNodeRef = apiUtils.lookupAndValidateNodeType(retentionScheduleId, RecordsManagementModel.TYPE_DISPOSITION_SCHEDULE); + // validation for the order of the step + retentionScheduleStepValidation(retentionScheduleNodeRef, nodeInfos.get(0)); + // request property validation + retentionScheduleRequestValidation(nodeInfos.get(0)); + // create the parameters for the action definition + Map actionDefinitionParams = nodesModelFactory.createRetentionActionDefinitionParams(nodeInfos.get(0)); + // create the child association from the schedule to the action definition + NodeRef actionNodeRef = this.nodeService.createNode(retentionScheduleNodeRef, + RecordsManagementModel.ASSOC_DISPOSITION_ACTION_DEFINITIONS, + QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, + QName.createValidLocalName(nodeInfos.get(0).getName())), + RecordsManagementModel.TYPE_DISPOSITION_ACTION_DEFINITION, actionDefinitionParams).getChildRef(); + DispositionSchedule dispositionSchedule = new DispositionScheduleImpl(service, nodeService, retentionScheduleNodeRef); + DispositionActionDefinition dispositionActionDefinition = dispositionSchedule.getDispositionActionDefinition(actionNodeRef.getId()); + List responseActions = new ArrayList<>(); + if (dispositionActionDefinition != null) + { + responseActions.add(nodesModelFactory.mapRetentionScheduleActionDefData(dispositionActionDefinition)); + } + return responseActions; + } + + @Override + @WebApiDescription(title = "Return a paged list of retention schedule action definition based on the 'retentionScheduleId'") + public CollectionWithPagingInfo readAll(String retentionScheduleId, Parameters parameters) + { + checkNotBlank("retentionScheduleId", retentionScheduleId); + mandatory("parameters", parameters); + NodeRef retentionScheduleNodeRef = apiUtils.lookupAndValidateNodeType(retentionScheduleId, RecordsManagementModel.TYPE_DISPOSITION_SCHEDULE); + List actions = nodesModelFactory.getRetentionActions(retentionScheduleNodeRef); + List actionDefinitionList = actions.stream() + .map(nodesModelFactory::mapRetentionScheduleActionDefData) + .collect(Collectors.toList()); + return CollectionWithPagingInfo.asPaged(parameters.getPaging(), actionDefinitionList, false, + actionDefinitionList.size()); + } + + /** + * this method is used to validate the order of the retention schedule step + * @param retentionScheduleNodeRef nodeRef + * @param retentionScheduleActionDefinition retention schedule action definition + */ + private void retentionScheduleStepValidation(NodeRef retentionScheduleNodeRef, RetentionScheduleActionDefinition retentionScheduleActionDefinition) + { + List actions = nodesModelFactory.getRetentionActions(retentionScheduleNodeRef); + Set completedActions = new HashSet<>(); + if (!actions.isEmpty()) + { + completedActions = actions.stream() + .map(DispositionActionDefinition::getName) + .collect(Collectors.toSet()); + } + + if (completedActions.contains(RetentionSteps.DESTROY.stepName)) + { + throw new ConstraintViolatedException("Invalid Step - destroy action is already added . No other action is allowed after Destroy."); + } + + if (checkStepAlreadyExists(completedActions, retentionScheduleActionDefinition.getName())) + { + throw new ConstraintViolatedException("Invalid Step - This step already exists. You can’t create it again. Only transfer action is allowed multiple times."); + } + + if (firstStepValidation(actions, retentionScheduleActionDefinition.getName())) + { + throw new UnprocessableContentException("Invalid Step - cutoff or retain should be the first step"); + } + + if (isCutOffStepAllowed(completedActions, retentionScheduleActionDefinition.getName())) + { + throw new ConstraintViolatedException("Invalid Step - Can't use cutoff after transfer or accession"); + } + } + + /** + * this method is used to validate the request of the retention schedule + * @param retentionScheduleActionDefinition retention schedule action definition + */ + private void retentionScheduleRequestValidation(RetentionScheduleActionDefinition retentionScheduleActionDefinition) + { + // step name validation + if (invalidStepNameCheck(retentionScheduleActionDefinition.getName())) + { + throw new InvalidArgumentException("name value is invalid : " +retentionScheduleActionDefinition.getName()); + } + // period value validation + if (invalidPeriodCheck(retentionScheduleActionDefinition.getPeriod())) + { + throw new InvalidArgumentException("period value is invalid : " +retentionScheduleActionDefinition.getPeriod()); + } + // event name validation + if (invalidEventNameCheck(retentionScheduleActionDefinition.getEvents())) + { + throw new InvalidArgumentException("event value is invalid: " + retentionScheduleActionDefinition.getEvents()); + } + // periodProperty validation + List validPeriodProperties = Arrays.asList("cm:created", "rma:cutOffDate", "rma:dispositionAsOf"); + if (validPeriodProperties.stream().noneMatch(retentionScheduleActionDefinition.getPeriodProperty()::equals)) + { + throw new InvalidArgumentException("periodProperty value is invalid: " + retentionScheduleActionDefinition.getPeriodProperty()); + } + } + + private boolean checkStepAlreadyExists(Set completedActions, String stepName) + { + return completedActions.contains(stepName) && !stepName.equals(RetentionSteps.TRANSFER.stepName); + } + + private boolean firstStepValidation(List actions, String stepName) + { + return actions.isEmpty() + && !stepName.equals(RetentionSteps.CUTOFF.stepName) && (!stepName.equals(RetentionSteps.RETAIN.stepName)); + } + + private boolean isCutOffStepAllowed(Set completedActions, String stepName) + { + return (completedActions.contains(RetentionSteps.TRANSFER.stepName) || completedActions.contains(RetentionSteps.ACCESSION.stepName)) + && stepName.equals(RetentionSteps.CUTOFF.stepName); + } + + private boolean invalidStepNameCheck(String stepName) + { + return stepName != null && Arrays.stream(RetentionSteps.values()) + .noneMatch(retentionStep -> retentionStep.stepName.equals(stepName)); + } + + private boolean invalidPeriodCheck(String period) + { + return period != null && Arrays.stream(RetentionPeriod.values()) + .noneMatch(retentionPeriod -> retentionPeriod.periodName.equals(period)); + } + + private boolean invalidEventNameCheck(List events) + { + return !events.isEmpty() && events.stream() + .anyMatch(event -> Arrays.stream(RetentionEvents.values()) + .noneMatch(retentionEvent -> retentionEvent.eventName.equals(event))); + } +} \ No newline at end of file diff --git a/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/retentionschedule/RetentionScheduleEntityResource.java b/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/retentionschedule/RetentionScheduleEntityResource.java new file mode 100644 index 0000000000..e305fdedf7 --- /dev/null +++ b/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/retentionschedule/RetentionScheduleEntityResource.java @@ -0,0 +1,38 @@ +/* + * #%L + * Alfresco Records Management Module + * %% + * Copyright (C) 2005 - 2024 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * - + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * - + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * - + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * - + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.rm.rest.api.retentionschedule; + +import org.alfresco.rest.framework.resource.EntityResource; + +/** + * Retention schedule entity resource + */ +@EntityResource(name="retention-schedules", title = "Retention Schedule") +public class RetentionScheduleEntityResource +{ + +} \ No newline at end of file diff --git a/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/retentionschedule/RetentionScheduleRelation.java b/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/retentionschedule/RetentionScheduleRelation.java index 60a7a3b856..86583c27da 100644 --- a/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/retentionschedule/RetentionScheduleRelation.java +++ b/amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/rm/rest/api/retentionschedule/RetentionScheduleRelation.java @@ -54,13 +54,11 @@ import static org.alfresco.module.org_alfresco_module_rm.model.RecordsManagement import static org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel.TYPE_RECORD_CATEGORY; import static org.alfresco.module.org_alfresco_module_rm.util.RMParameterCheck.checkNotBlank; import static org.alfresco.util.ParameterCheck.mandatory; -import lombok.Data; /** * Retention schedule relation is used perform retention schedule operation for a record category. */ @RelationshipResource(name = "retention-schedules", entityResource = RecordCategoriesEntityResource.class, title = "Retention Schedule") -@Data public class RetentionScheduleRelation implements RelationshipResourceAction.Read, RelationshipResourceAction.Create { @@ -70,6 +68,26 @@ public class RetentionScheduleRelation implements RelationshipResourceAction.Rea private DispositionService dispositionService; protected NodeService nodeService; + public void setApiUtils(FilePlanComponentsApiUtils apiUtils) + { + this.apiUtils = apiUtils; + } + + public void setNodesModelFactory(ApiNodesModelFactory nodesModelFactory) + { + this.nodesModelFactory = nodesModelFactory; + } + + public void setDispositionService(DispositionService dispositionService) + { + this.dispositionService = dispositionService; + } + + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + @Override @WebApiDescription(title="Create a retention schedule for the particular record category using the 'recordCategoryId'") public List create(String recordCategoryId, List nodeInfos, Parameters parameters) @@ -83,7 +101,7 @@ public class RetentionScheduleRelation implements RelationshipResourceAction.Rea Map dsProps = new HashMap<>(); dsProps.put(PROP_DISPOSITION_AUTHORITY, nodeInfos.get(0).getAuthority()); dsProps.put(PROP_DISPOSITION_INSTRUCTIONS, nodeInfos.get(0).getInstructions()); - dsProps.put(PROP_RECORD_LEVEL_DISPOSITION, nodeInfos.get(0).isRecordLevel()); + dsProps.put(PROP_RECORD_LEVEL_DISPOSITION, nodeInfos.get(0).getIsRecordLevel()); DispositionSchedule dispositionSchedule = dispositionService.createDispositionSchedule(parentNodeRef, dsProps); RetentionSchedule retentionSchedule = nodesModelFactory.mapRetentionScheduleData(dispositionSchedule); result.add(retentionSchedule); diff --git a/amps/ags/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/disposition/RetentionScheduleModelUnitTest.java b/amps/ags/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/disposition/RetentionScheduleModelUnitTest.java index 2b89472fde..7c8b1b3411 100644 --- a/amps/ags/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/disposition/RetentionScheduleModelUnitTest.java +++ b/amps/ags/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/disposition/RetentionScheduleModelUnitTest.java @@ -39,7 +39,6 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.when; /** @@ -72,11 +71,17 @@ public class RetentionScheduleModelUnitTest extends BaseUnitTest when(dispositionSchedule.isRecordLevelDisposition()).thenReturn(false); when(mockedNodeService.getPrimaryParent(nodeRef)).thenReturn(childAssociationRef); // Call the method - RetentionSchedule expectedResult = apiNodesModelFactory.mapRetentionScheduleData(dispositionSchedule); - assertEquals(expectedResult.getId(), dispositionSchedule.getNodeRef().getId()); - assertEquals(expectedResult.getAuthority(), dispositionSchedule.getDispositionAuthority()); - assertEquals(expectedResult.getInstructions(), dispositionSchedule.getDispositionInstructions()); - assertEquals(expectedResult.isRecordLevel(), dispositionSchedule.isRecordLevelDisposition()); + RetentionSchedule actualResult = apiNodesModelFactory.mapRetentionScheduleData(dispositionSchedule); + + //Expected Result + RetentionSchedule expectedResult = new RetentionSchedule(); + expectedResult.setId(nodeRef.getId()); + expectedResult.setParentId(filePlan.getId()); + expectedResult.setAuthority(AUTHORITY); + expectedResult.setInstructions(INSTRUCTIONS); + + // Assertions + assertEquals(expectedResult, actualResult); } @Test @@ -96,15 +101,26 @@ public class RetentionScheduleModelUnitTest extends BaseUnitTest when(dispositionActionDefinition.getId()).thenReturn(nodeRef.getId()); when(mockedNodeService.getPrimaryParent(nodeRef)).thenReturn(childAssociationRef); // Call the method - RetentionScheduleActionDefinition expectedResult = apiNodesModelFactory.mapRetentionScheduleActionDefData(dispositionActionDefinition); - String resultPeriod = expectedResult.getPeriod() + "|" + expectedResult.getPeriodAmount(); - // Assertions - assertEquals(expectedResult.getId(), dispositionActionDefinition.getId()); - assertEquals(expectedResult.getName(), dispositionActionDefinition.getName()); - assertEquals(expectedResult.getDescription(), dispositionActionDefinition.getDescription()); - assertEquals(expectedResult.getIndex(), dispositionActionDefinition.getIndex()); - assertEquals(expectedResult.getLocation(), dispositionActionDefinition.getLocation()); - assertEquals(new Period(resultPeriod), dispositionActionDefinition.getPeriod()); - assertTrue(expectedResult.isRetainRecordMetadataAfterDestruction()); + RetentionScheduleActionDefinition actualResult = apiNodesModelFactory.mapRetentionScheduleActionDefData(dispositionActionDefinition); + + //Expected Result + RetentionScheduleActionDefinition expectedResult = getRetentionScheduleActionDefinition(nodeRef); + + // Assertion + assertEquals(expectedResult, actualResult); + } + + private static RetentionScheduleActionDefinition getRetentionScheduleActionDefinition(NodeRef nodeRef) + { + RetentionScheduleActionDefinition expectedResult = new RetentionScheduleActionDefinition(); + expectedResult.setId(nodeRef.getId()); + expectedResult.setName(RETAIN_STEP); + expectedResult.setDescription("Description"); + expectedResult.setIndex(1); + expectedResult.setLocation("location"); + expectedResult.setPeriod("month"); + expectedResult.setPeriodAmount(10); + expectedResult.setRetainRecordMetadataAfterDestruction(true); + return expectedResult; } } \ No newline at end of file diff --git a/remote-api/src/main/java/org/alfresco/rest/framework/core/exceptions/UnprocessableContentException.java b/remote-api/src/main/java/org/alfresco/rest/framework/core/exceptions/UnprocessableContentException.java new file mode 100644 index 0000000000..df2babf44d --- /dev/null +++ b/remote-api/src/main/java/org/alfresco/rest/framework/core/exceptions/UnprocessableContentException.java @@ -0,0 +1,40 @@ +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2024 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.rest.framework.core.exceptions; + +/** + * Unprocessable Content + */ +public class UnprocessableContentException extends ApiException +{ + + private static final long serialVersionUID = -6857652090677361159L; + + public UnprocessableContentException(String msgId) + { + super(msgId); + } +} \ No newline at end of file diff --git a/remote-api/src/main/resources/alfresco/public-rest-context.xml b/remote-api/src/main/resources/alfresco/public-rest-context.xml index f5627ad823..2f8497a061 100644 --- a/remote-api/src/main/resources/alfresco/public-rest-context.xml +++ b/remote-api/src/main/resources/alfresco/public-rest-context.xml @@ -178,6 +178,7 @@ +