diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/audit-service.properties b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/audit-service.properties
index da0adf2b30..b5e7c4079c 100644
--- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/audit-service.properties
+++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/messages/audit-service.properties
@@ -16,6 +16,7 @@ rm.audit.fileTo=File to
rm.audit.createHold=Create Hold
rm.audit.deleteHold=Delete Hold
rm.audit.addToHold=Add To Hold
+rm.audit.removeFromHold=Remove From Hold
rm.audit.audit-start=Audit Start
rm.audit.audit-stop=Audit Stop
rm.audit.audit-clear=Audit Clear
diff --git a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-audit-context.xml b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-audit-context.xml
index be43164702..ac1382d699 100644
--- a/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-audit-context.xml
+++ b/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/rm-audit-context.xml
@@ -147,4 +147,10 @@
+
+
+
+
+
+
diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/audit/event/RemoveFromHoldAuditEvent.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/audit/event/RemoveFromHoldAuditEvent.java
new file mode 100644
index 0000000000..48f419f701
--- /dev/null
+++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/audit/event/RemoveFromHoldAuditEvent.java
@@ -0,0 +1,82 @@
+/*
+ * #%L
+ * Alfresco Records Management Module
+ * %%
+ * Copyright (C) 2005 - 2019 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.module.org_alfresco_module_rm.audit.event;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.module.org_alfresco_module_rm.hold.HoldServicePolicies;
+import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
+import org.alfresco.repo.policy.annotation.Behaviour;
+import org.alfresco.repo.policy.annotation.BehaviourBean;
+import org.alfresco.repo.policy.annotation.BehaviourKind;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.namespace.QName;
+
+/**
+ * Delete from hold audit event.
+ *
+ * @author Chris Shields
+ * @since 3.3
+ */
+@BehaviourBean
+public class RemoveFromHoldAuditEvent extends AuditEvent implements HoldServicePolicies.OnRemoveFromHoldPolicy
+{
+ /** Node Service */
+ private NodeService nodeService;
+
+ /**
+ * Sets the node service
+ *
+ * @param nodeService nodeService to set
+ */
+ public void setNodeService(NodeService nodeService)
+ {
+ this.nodeService = nodeService;
+ }
+
+ /**
+ * @see @see org.alfresco.module.org_alfresco_module_rm.hold.HoldServicePolicies.OnRemoveFromHoldPolicy#onRemoveFromHold(org.alfresco.service.cmr.repository.NodeRef, org.alfresco.service.cmr.repository.NodeRef)
+ */
+ @Override
+ @Behaviour
+ (
+ kind = BehaviourKind.CLASS,
+ type = "rma:hold",
+ notificationFrequency = NotificationFrequency.EVERY_EVENT
+ )
+ public void onRemoveFromHold(NodeRef holdNodeRef, NodeRef contentNodeRef)
+ {
+ Map auditProperties = HoldUtils.makePropertiesMap(holdNodeRef, nodeService);
+ auditProperties.put(ContentModel.PROP_NAME, nodeService.getProperty(contentNodeRef, ContentModel.PROP_NAME));
+
+ recordsManagementAuditService.auditEvent(contentNodeRef, getName(), auditProperties, null, true);
+ }
+}
diff --git a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/hold/HoldServiceImpl.java b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/hold/HoldServiceImpl.java
index 32400091e0..61f2e8b389 100644
--- a/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/hold/HoldServiceImpl.java
+++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/hold/HoldServiceImpl.java
@@ -99,9 +99,6 @@ public class HoldServiceImpl extends ServiceBaseImpl
/** Logger */
private static Log logger = LogFactory.getLog(HoldServiceImpl.class);
- /** Audit event keys */
- private static final String AUDIT_REMOVE_FROM_HOLD = "removeFromHold";
-
/** I18N */
private static final String MSG_ERR_ACCESS_DENIED = "permissions.err_access_denied";
@@ -219,16 +216,6 @@ public class HoldServiceImpl extends ServiceBaseImpl
*/
public void init()
{
- AuthenticationUtil.runAsSystem(new RunAsWork()
- {
- @Override
- public Void doWork() throws Exception
- {
- recordsManagementAuditService.registerAuditEvent(new AuditEvent(AUDIT_REMOVE_FROM_HOLD, "capability.RemoveFromHold.title"));
- return null;
- }
- });
-
// Register the policies
beforeCreateHoldPolicyDelegate = getPolicyComponent().registerClassPolicy(BeforeCreateHoldPolicy.class);
onCreateHoldPolicyDelegate = getPolicyComponent().registerClassPolicy(OnCreateHoldPolicy.class);
@@ -820,10 +807,6 @@ public class HoldServiceImpl extends ServiceBaseImpl
transactionalResourceHelper.getSet("frozen").add(nodeRef);
nodeService.removeChild(hold, nodeRef);
- // audit that the node has been removed from the hold
- // TODO add details of the hold that the node was removed from
- recordsManagementAuditService.auditEvent(nodeRef, AUDIT_REMOVE_FROM_HOLD);
-
return null;
});
removedHolds.add(hold);
diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordsManagementAuditServiceImplTest.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordsManagementAuditServiceImplTest.java
index 532d3f6d98..3d246fea3c 100644
--- a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordsManagementAuditServiceImplTest.java
+++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/legacy/service/RecordsManagementAuditServiceImplTest.java
@@ -28,11 +28,13 @@
package org.alfresco.module.org_alfresco_module_rm.test.legacy.service;
import java.io.Serializable;
+import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.stream.Collectors;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditEntry;
@@ -735,6 +737,183 @@ public class RecordsManagementAuditServiceImplTest extends BaseRMTestCase
});
}
+
+ /**
+ * Given I have an item in a hold
+ * When I remove the item from the hold
+ * Then there will be an audit entry for the item removed from the hold, including both the item name and hold name
+ */
+ @org.junit.Test
+ public void testAuditForRemoveContentFromHold()
+ {
+ doBehaviourDrivenTest(new BehaviourDrivenTest()
+ {
+ final static String REMOVE_FROM_HOLD_AUDIT_EVENT = "Remove From Hold";
+
+ String holdName = "Hold " + GUID.generate();
+ NodeRef hold;
+
+ Map auditEventProperties;
+
+ @Override
+ public void given()
+ {
+ rmAuditService.clearAuditLog(filePlan);
+ hold = utils.createHold(filePlan, holdName, "Reason " + GUID.generate());
+ utils.addItemToHold(hold, dmDocument);
+ }
+
+ @Override
+ public void when()
+ {
+ utils.removeItemFromHold(hold, dmDocument);
+ }
+
+ @Override
+ public void then()
+ {
+ auditEventProperties = getAuditEntry(REMOVE_FROM_HOLD_AUDIT_EVENT).getBeforeProperties();
+
+ // check remove from hold audit event includes the hold name
+ assertEquals("Remove From Hold event does not include hold name.", holdName,
+ auditEventProperties.get(HOLD_NAME));
+
+ // check remove from hold audit event includes the content name
+ String contentName = (String) nodeService.getProperty(dmDocument, PROP_NAME);
+ assertEquals("Remove From Hold event does not include content name.", contentName,
+ auditEventProperties.get(PROP_NAME));
+ }
+
+ @Override
+ public void after()
+ {
+ // Stop and delete all entries
+ rmAuditService.stopAuditLog(filePlan);
+ rmAuditService.clearAuditLog(filePlan);
+ }
+ });
+
+ }
+
+
+ /**
+ * Given I have removed an item from multiple holds
+ * When I will get the RM audit filter by remove from hold events
+ * Then there will be entries for the item removed from each hold, including both the item name and hold name
+ */
+ @org.junit.Test
+ public void testAuditForRemoveContentFromMultipleHolds()
+ {
+ doBehaviourDrivenTest(new BehaviourDrivenTest()
+ {
+ final static String REMOVE_FROM_HOLD_AUDIT_EVENT = "Remove From Hold";
+
+ String holdName1 = "Hold " + GUID.generate();
+ String holdName2 = "Hold " + GUID.generate();
+ NodeRef hold1, hold2;
+
+ List