mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
[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 <ST28@ford.com> Co-authored-by: suneet-gupta <suneet.gupta@hyland.com>
This commit is contained in:
@@ -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<String> 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<String> includeParam)
|
||||
{
|
||||
return (!isMinimalInfo && propertyFilter.isAllowed(RMNode.PARAM_IS_CLOSED)) || (isMinimalInfo && includeParam.contains(RMNode.PARAM_IS_CLOSED));
|
||||
}
|
||||
|
||||
private boolean isRecordCategory(boolean isMinimalInfo, BeanPropertiesFilter propertyFilter, List<String> 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<String> 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<QName, Serializable>
|
||||
*/
|
||||
public Map<QName, Serializable> createRetentionActionDefinitionParams(RetentionScheduleActionDefinition nodeInfo)
|
||||
{
|
||||
Map<QName, Serializable> 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<String> 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<DispositionActionDefinition>
|
||||
*/
|
||||
public List<DispositionActionDefinition> getRetentionActions(NodeRef retentionScheduleNodeRef)
|
||||
{
|
||||
List<ChildAssociationRef> 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<DispositionActionDefinition> 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);
|
||||
}
|
||||
}
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
* #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;
|
||||
}
|
||||
}
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
* #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;
|
||||
}
|
||||
}
|
@@ -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<RetentionScheduleActionDefinition> actions;
|
||||
}
|
||||
|
||||
public boolean getIsRecordLevel()
|
||||
{
|
||||
return isRecordLevel;
|
||||
}
|
||||
|
||||
public void setIsRecordLevel(boolean recordLevel)
|
||||
{
|
||||
isRecordLevel = recordLevel;
|
||||
}
|
||||
}
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
* #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;
|
||||
}
|
||||
}
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
* #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<RetentionScheduleActionDefinition>,
|
||||
RelationshipResourceAction.Create<RetentionScheduleActionDefinition>
|
||||
{
|
||||
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<RetentionScheduleActionDefinition> create(String retentionScheduleId, List<RetentionScheduleActionDefinition> 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<QName, Serializable> 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<RetentionScheduleActionDefinition> 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<RetentionScheduleActionDefinition> readAll(String retentionScheduleId, Parameters parameters)
|
||||
{
|
||||
checkNotBlank("retentionScheduleId", retentionScheduleId);
|
||||
mandatory("parameters", parameters);
|
||||
NodeRef retentionScheduleNodeRef = apiUtils.lookupAndValidateNodeType(retentionScheduleId, RecordsManagementModel.TYPE_DISPOSITION_SCHEDULE);
|
||||
List<DispositionActionDefinition> actions = nodesModelFactory.getRetentionActions(retentionScheduleNodeRef);
|
||||
List<RetentionScheduleActionDefinition> 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<DispositionActionDefinition> actions = nodesModelFactory.getRetentionActions(retentionScheduleNodeRef);
|
||||
Set<String> 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<String> 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<String> completedActions, String stepName)
|
||||
{
|
||||
return completedActions.contains(stepName) && !stepName.equals(RetentionSteps.TRANSFER.stepName);
|
||||
}
|
||||
|
||||
private boolean firstStepValidation(List<DispositionActionDefinition> actions, String stepName)
|
||||
{
|
||||
return actions.isEmpty()
|
||||
&& !stepName.equals(RetentionSteps.CUTOFF.stepName) && (!stepName.equals(RetentionSteps.RETAIN.stepName));
|
||||
}
|
||||
|
||||
private boolean isCutOffStepAllowed(Set<String> 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<String> events)
|
||||
{
|
||||
return !events.isEmpty() && events.stream()
|
||||
.anyMatch(event -> Arrays.stream(RetentionEvents.values())
|
||||
.noneMatch(retentionEvent -> retentionEvent.eventName.equals(event)));
|
||||
}
|
||||
}
|
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
* #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
|
||||
{
|
||||
|
||||
}
|
@@ -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<RetentionSchedule>,
|
||||
RelationshipResourceAction.Create<RetentionSchedule>
|
||||
{
|
||||
@@ -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<RetentionSchedule> create(String recordCategoryId, List<RetentionSchedule> nodeInfos, Parameters parameters)
|
||||
@@ -83,7 +101,7 @@ public class RetentionScheduleRelation implements RelationshipResourceAction.Rea
|
||||
Map<QName, Serializable> 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);
|
||||
|
Reference in New Issue
Block a user