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..2141f524c6 --- /dev/null +++ b/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/audit/event/RemoveFromHoldAuditEvent.java @@ -0,0 +1,84 @@ +/* + * #%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 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 b54f9fcf8f..258d3124b6 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"; private static final String MSG_ERR_HOLD_PERMISSION_GENERIC_ERROR = "rm.hold.generic-permission-error"; @@ -221,16 +218,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); @@ -833,10 +820,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..6212c45b3f 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,6 +28,7 @@ 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; @@ -70,6 +71,12 @@ public class RecordsManagementAuditServiceImplTest extends BaseRMTestCase /** Test start time */ private Date testStartTime; + /** + * Remove from hold audit event name. + */ + private static final String REMOVE_FROM_HOLD_AUDIT_EVENT = "Remove From Hold"; + + /** * @see org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase#setUp() */ @@ -502,8 +509,7 @@ public class RecordsManagementAuditServiceImplTest extends BaseRMTestCase public void when() throws Exception { // set the audit wuery param - RecordsManagementAuditQueryParameters params = new RecordsManagementAuditQueryParameters(); - params.setEvent(DELETE_USER_AUDIT_EVENT); + RecordsManagementAuditQueryParameters params = createAuditQueryParameters(DELETE_USER_AUDIT_EVENT); // get the audit events for "Delete Person" entry = getAuditTrail(params, 1, ADMIN_USER); @@ -558,8 +564,7 @@ public class RecordsManagementAuditServiceImplTest extends BaseRMTestCase public void when() throws Exception { // set the audit query param - RecordsManagementAuditQueryParameters params = new RecordsManagementAuditQueryParameters(); - params.setEvent(CREATE_USER_AUDIT_EVENT); + RecordsManagementAuditQueryParameters params = createAuditQueryParameters(CREATE_USER_AUDIT_EVENT); // get the audit events for "Create Person" entry = getAuditTrail(params, 1, ADMIN_USER); @@ -735,6 +740,163 @@ 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() + { + String holdName = "Hold " + GUID.generate(); + NodeRef hold; + + @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() + { + Map 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() + { + String holdName1 = "Hold " + GUID.generate(); + String holdName2 = "Hold " + GUID.generate(); + NodeRef hold1, hold2; + + @Override + public void given() + { + rmAuditService.clearAuditLog(filePlan); + + hold1 = utils.createHold(filePlan, holdName1, "Reason " + GUID.generate()); + hold2 = utils.createHold(filePlan, holdName2, "Reason " + GUID.generate()); + utils.addItemToHold(hold1, dmDocument); + utils.addItemToHold(hold2, dmDocument); + } + + @Override + public void when() + { + utils.removeItemsFromHolds(Arrays.asList(hold1, hold2), Arrays.asList(dmDocument)); + } + + @Override + public void then() + { + List auditEntries = getAuditEntries(REMOVE_FROM_HOLD_AUDIT_EVENT); + + // check remove from hold audit event exists for both holds + assertEquals(2, auditEntries.size()); + } + + @Override + public void after() + { + // Stop and delete all entries + rmAuditService.stopAuditLog(filePlan); + rmAuditService.clearAuditLog(filePlan); + } + }); + + } + + + /** + * Given I have removed items from a hold + * When I will get the RM audit filter by remove from hold events + * Then there will be entries for the items removed from the hold, including both the item name and hold name + */ + @org.junit.Test + public void testAuditForRemoveMultipleContentFromHold() + { + doBehaviourDrivenTest(new BehaviourDrivenTest() + { + String holdName = "Hold " + GUID.generate(); + NodeRef hold; + + @Override + public void given() + { + rmAuditService.clearAuditLog(filePlan); + + hold = utils.createHold(filePlan, holdName, "Reason " + GUID.generate()); + utils.addItemToHold(hold, dmDocument); + utils.addItemToHold(hold, dmDocument1); + } + + @Override + public void when() + { + utils.removeItemsFromHolds(Arrays.asList(hold), Arrays.asList(dmDocument, dmDocument1)); + } + + @Override + public void then() + { + List auditEntries = getAuditEntries(REMOVE_FROM_HOLD_AUDIT_EVENT); + + // check remove from hold audit event exists for both documents + assertEquals(2, auditEntries.size()); + } + + @Override + public void after() + { + // Stop and delete all entries + rmAuditService.stopAuditLog(filePlan); + rmAuditService.clearAuditLog(filePlan); + } + }); + + } + + /** === Helper methods === */ private List getAuditTrail(String asUser) @@ -785,13 +947,11 @@ public class RecordsManagementAuditServiceImplTest extends BaseRMTestCase private RecordsManagementAuditEntry getAuditEntry(String auditEvent) { - // set the audit query param for the given event - RecordsManagementAuditQueryParameters params = new RecordsManagementAuditQueryParameters(); - params.setEvent(auditEvent); + // create the audit query parameters for the given event + RecordsManagementAuditQueryParameters params = createAuditQueryParameters(auditEvent); // get the audit entries for the given event - List auditEntries; - auditEntries = getAuditTrail(params, 1, ADMIN_USER); + List auditEntries = getAuditEntryAssertOnlyOne(params); // verify we have the expected audit event RecordsManagementAuditEntry auditEntry = auditEntries.get(0); @@ -800,4 +960,37 @@ public class RecordsManagementAuditServiceImplTest extends BaseRMTestCase // return the properties of the audit event return auditEntry; } + + private List getAuditEntryAssertOnlyOne(RecordsManagementAuditQueryParameters params) + { + List auditEntries; + auditEntries = getAuditTrail(params, 1, ADMIN_USER); + return auditEntries; + } + + private List getAuditEntries(String auditEvent) + { + // create the audit query parameters for the given event + RecordsManagementAuditQueryParameters params = createAuditQueryParameters(auditEvent); + + // get the audit entries for the given event + List auditEntries = getAllAuditEntries(params); + + return auditEntries; + } + + private List getAllAuditEntries(RecordsManagementAuditQueryParameters params) + { + List auditEntries; + auditEntries = getAuditTrail(params, -1, ADMIN_USER); + return auditEntries; + } + + private RecordsManagementAuditQueryParameters createAuditQueryParameters(String auditEvent) + { + RecordsManagementAuditQueryParameters params = new RecordsManagementAuditQueryParameters(); + params.setEvent(auditEvent); + return params; + } + } diff --git a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/CommonRMTestUtils.java b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/CommonRMTestUtils.java index cf7e449f24..692ac87edc 100644 --- a/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/CommonRMTestUtils.java +++ b/rm-community/rm-community-repo/test/java/org/alfresco/module/org_alfresco_module_rm/test/util/CommonRMTestUtils.java @@ -443,4 +443,27 @@ public class CommonRMTestUtils implements RecordsManagementModel { holdService.addToHold(holdNodeRef, contentNodeRef); } + + /** + * Util method to remove content from a hold. + * + * @param holdNodeRef hold node reference + * @param contentNodeRef content node reference + */ + public void removeItemFromHold(NodeRef holdNodeRef, NodeRef contentNodeRef) + { + holdService.removeFromHold(holdNodeRef, contentNodeRef); + } + + /** + * Util method to remove items from holds. + * + * @param holdNodeRefs the list {@link NodeRef}s of the holds + * @param contentNodeRef the list of items which will be removed from the given holds + */ + public void removeItemsFromHolds(List holdNodeRefs, List contentNodeRef) + { + holdService.removeFromHolds(holdNodeRefs, contentNodeRef); + } + } diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/audit/event/RemoveFromHoldAuditEventUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/audit/event/RemoveFromHoldAuditEventUnitTest.java new file mode 100644 index 0000000000..57fcaad37f --- /dev/null +++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/audit/event/RemoveFromHoldAuditEventUnitTest.java @@ -0,0 +1,95 @@ +/* + * #%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 static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.isNull; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + +import java.util.Map; + +import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.util.GUID; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +/** + * Unit tests for {@link RemoveFromHoldAuditEvent}. + * + * @author Chris Shields + * @since 3.3 + */ +public class RemoveFromHoldAuditEventUnitTest extends BaseUnitTest +{ + @InjectMocks + private RemoveFromHoldAuditEvent removeFromHoldAuditEvent; + + @Mock + private NodeService mockedNodeService; + + private NodeRef holdNodeRef; + private NodeRef contentNodeRef; + + /** + * Set up the mocks. + */ + @Before + public void setUp() + { + initMocks(this); + + holdNodeRef = generateNodeRef(); + String holdName = "Hold " + GUID.generate(); + + contentNodeRef = generateNodeRef(); + String contentName = "Content " + GUID.generate(); + + when(mockedNodeService.getProperty(holdNodeRef, PROP_NAME)).thenReturn(holdName); + when(mockedNodeService.getProperty(contentNodeRef, PROP_NAME)).thenReturn(contentName); + } + + /** + * Check that the remove from hold event calls an audit event. + */ + @Test + public void testRemoveFromHoldCausesAuditEvent() + { + removeFromHoldAuditEvent.onRemoveFromHold(holdNodeRef, contentNodeRef); + verify(mockedRecordsManagementAuditService, times(1)).auditEvent(eq(contentNodeRef), any(String.class), any(Map.class), isNull(Map.class), eq(true)); + } + +} diff --git a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/hold/HoldServiceImplUnitTest.java b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/hold/HoldServiceImplUnitTest.java index e42b9508c3..d070548983 100644 --- a/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/hold/HoldServiceImplUnitTest.java +++ b/rm-community/rm-community-repo/unit-test/java/org/alfresco/module/org_alfresco_module_rm/hold/HoldServiceImplUnitTest.java @@ -474,7 +474,6 @@ public class HoldServiceImplUnitTest extends BaseUnitTest verify(mockedNodeService, never()).removeChild(hold, recordFolder); verify(mockedNodeService, never()).removeAspect(recordFolder, ASPECT_FROZEN); verify(mockedNodeService, never()).removeAspect(record, ASPECT_FROZEN); - verify(mockedRecordsManagementAuditService, never()).auditEvent(eq(recordFolder), anyString()); } @Test @@ -491,7 +490,6 @@ public class HoldServiceImplUnitTest extends BaseUnitTest verify(mockedNodeService, times(1)).removeChild(hold, recordFolder); verify(mockedNodeService, times(1)).removeAspect(recordFolder, ASPECT_FROZEN); verify(mockedNodeService, times(1)).removeAspect(record, ASPECT_FROZEN); - verify(mockedRecordsManagementAuditService, times(1)).auditEvent(eq(recordFolder), anyString()); } @Test @@ -515,7 +513,6 @@ public class HoldServiceImplUnitTest extends BaseUnitTest verify(mockedNodeService, times(1)).removeChild(hold2, recordFolder); verify(mockedNodeService, times(1)).removeAspect(recordFolder, ASPECT_FROZEN); verify(mockedNodeService, times(1)).removeAspect(record, ASPECT_FROZEN); - verify(mockedRecordsManagementAuditService, times(2)).auditEvent(any(NodeRef.class), anyString()); } @Test