Java tutorial
/* * #%L * Alfresco Repository * %% * Copyright (C) 2005 - 2016 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.repo.quickshare; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; import java.io.Serializable; import java.util.Map; import org.alfresco.model.ContentModel; import org.alfresco.model.QuickShareModel; import org.alfresco.repo.model.Repository; import org.alfresco.repo.node.archive.NodeArchiveService; import org.alfresco.repo.node.archive.RestoreNodeReport; import org.alfresco.repo.node.archive.RestoreNodeReport.RestoreStatus; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.repo.tenant.TenantUtil; import org.alfresco.repo.tenant.TenantUtil.TenantRunAsWork; import org.alfresco.service.cmr.attributes.AttributeService; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.quickshare.InvalidSharedIdException; import org.alfresco.service.cmr.quickshare.QuickShareDTO; import org.alfresco.service.cmr.quickshare.QuickShareService; import org.alfresco.service.cmr.repository.CopyService; import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.util.test.junitrules.AlfrescoPerson; import org.alfresco.util.test.junitrules.ApplicationContextInit; import org.alfresco.util.test.junitrules.TemporaryModels; import org.alfresco.util.test.junitrules.TemporaryNodes; import org.apache.commons.codec.binary.Base64; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.rules.RuleChain; import org.safehaus.uuid.UUID; import org.safehaus.uuid.UUIDGenerator; import org.springframework.context.ApplicationContext; /** * Quick share service tests. * * @author Alex Miller * @since Cloud/4.2 */ public class QuickShareServiceIntegrationTest { private static final ApplicationContextInit testContext = new ApplicationContextInit(); private static final String MODEL = "<?xml version='1.0' encoding='UTF-8'?>" + "<model name='lx:lxmodel' xmlns='http://www.alfresco.org/model/dictionary/1.0'>" + "<description>LX model</description>" + "<author>Peter Lfgren</author>" + "<version>1.0</version>" + "<imports>" + "<import uri='http://www.alfresco.org/model/dictionary/1.0' prefix='d' />" + "<import uri='http://www.alfresco.org/model/content/1.0' prefix='cm' />" + "</imports>" + "<namespaces>" + "<namespace uri='http://bugtestmodel' prefix='lx' />" + "</namespaces>" + "<constraints>" + "</constraints>" + "<types>" + "<type name='lx:doc'>" + "<title>LX dokument</title>" + "<parent>cm:content</parent>" + "<mandatory-aspects>" + "<aspect>cm:generalclassifiable</aspect>" + "</mandatory-aspects>" + "</type>" + "<type name='lx:doc2'>" + "<title>LX dokument 2</title>" + "<parent>cm:cmobject</parent>" + "</type>" + "</types>" + "</model>"; private static CopyService copyService; private static NodeService nodeService; private static QuickShareService quickShareService; private static DictionaryService dictionaryService; private static Repository repository; private static AttributeService attributeService; private static PermissionService permissionService; private static NodeArchiveService nodeArchiveService; private static AlfrescoPerson user1 = new AlfrescoPerson(testContext, "UserOne"); private static AlfrescoPerson user2 = new AlfrescoPerson(testContext, "UserTwo"); // A rule to manage test nodes reused across all the test methods @Rule public TemporaryNodes testNodes = new TemporaryNodes(testContext); @Rule public TemporaryModels temporaryModels = new TemporaryModels(testContext); @ClassRule public static RuleChain classChain = RuleChain.outerRule(testContext).around(user1).around(user2); private NodeRef testNode; private NodeRef userHome; @BeforeClass public static void beforeClass() throws Exception { findServices(); } private static void findServices() { ApplicationContext ctx = testContext.getApplicationContext(); copyService = ctx.getBean("CopyService", CopyService.class); dictionaryService = ctx.getBean("dictionaryService", DictionaryService.class); nodeService = ctx.getBean("NodeService", NodeService.class); quickShareService = ctx.getBean("QuickShareService", QuickShareService.class); repository = ctx.getBean("repositoryHelper", Repository.class); attributeService = ctx.getBean("AttributeService", AttributeService.class); permissionService = ctx.getBean("PermissionService", PermissionService.class); nodeArchiveService = ctx.getBean("nodeArchiveService", NodeArchiveService.class); } @Before public void createTestData() { userHome = repository.getUserHome(user1.getPersonNode()); testNode = testNodes.createNodeWithTextContent(userHome, "Quick Share Test Node", ContentModel.TYPE_CONTENT, user1.getUsername(), "Quick Share Test Node Content"); } @Test public void getMetaDataFromNodeRefByOwner() { Map<String, Object> metadata = AuthenticationUtil.runAs(new RunAsWork<Map<String, Object>>() { @Override public Map<String, Object> doWork() throws Exception { return quickShareService.getMetaData(testNode); } }, user1.getUsername()); assertNotNull(metadata); assertTrue(metadata.size() > 0); } @Test(expected = AccessDeniedException.class) public void getMetaDataFromNodeRefByNonOwner() { Map<String, Object> metadata = AuthenticationUtil.runAs(new RunAsWork<Map<String, Object>>() { @Override public Map<String, Object> doWork() throws Exception { return quickShareService.getMetaData(testNode); } }, user2.getUsername()); } @Test public void share() { share(testNode, user1.getUsername()); AuthenticationUtil.runAsSystem(new RunAsWork<Void>() { @Override public Void doWork() throws Exception { assertTrue(nodeService.getAspects(testNode).contains(QuickShareModel.ASPECT_QSHARE)); assertNotNull(nodeService.getProperty(testNode, QuickShareModel.PROP_QSHARE_SHAREDID)); assertEquals(user1.getUsername(), nodeService.getProperty(testNode, QuickShareModel.PROP_QSHARE_SHAREDBY)); return null; } }); } @Test public void unshare() { final QuickShareDTO dto = share(testNode, user1.getUsername()); unshare(dto.getId(), user1.getUsername()); AuthenticationUtil.runAsSystem(new RunAsWork<Void>() { @Override public Void doWork() throws Exception { assertFalse(nodeService.getAspects(testNode).contains(QuickShareModel.ASPECT_QSHARE)); assertNull(nodeService.getProperty(testNode, QuickShareModel.PROP_QSHARE_SHAREDID)); assertNull(nodeService.getProperty(testNode, QuickShareModel.PROP_QSHARE_SHAREDBY)); return null; } }); } // MNT-16224, RA-1093 @Test public void testDeleteAndRestoreSharedNode() { // Share the test node share(testNode, user1.getUsername()); AuthenticationUtil.runAsSystem(new RunAsWork<Void>() { @Override public Void doWork() throws Exception { assertTrue(nodeService.hasAspect(testNode, QuickShareModel.ASPECT_QSHARE)); return null; } }); // Delete and restore the shared node. testNode = AuthenticationUtil.runAs(new RunAsWork<NodeRef>() { @Override public NodeRef doWork() throws Exception { // Delete the shared node nodeService.deleteNode(testNode); // Check if the node has been archived final NodeRef archivedNode = nodeArchiveService.getArchivedNode(testNode); assertNotNull(archivedNode); // Restore the deleted shared node from trashcan RestoreNodeReport restoreNodeReport = nodeArchiveService.restoreArchivedNode(archivedNode); assertNotNull(restoreNodeReport); assertTrue(restoreNodeReport.getStatus() == RestoreStatus.SUCCESS); NodeRef restoredNodeRef = restoreNodeReport.getRestoredNodeRef(); assertNotNull(restoredNodeRef); return restoredNodeRef; } }, user1.getUsername()); // Check the restored node doesn't have the 'shared' aspect. AuthenticationUtil.runAsSystem(new RunAsWork<Void>() { @Override public Void doWork() throws Exception { assertFalse(nodeService.hasAspect(testNode, QuickShareModel.ASPECT_QSHARE)); assertNull(nodeService.getProperty(testNode, QuickShareModel.PROP_QSHARE_SHAREDID)); assertNull(nodeService.getProperty(testNode, QuickShareModel.PROP_QSHARE_SHAREDBY)); return null; } }); /** * Tests the scenario where the shared node has been deleted and restored before the fix (MNT-16224). * In this scenario the user should be able to un-share the restored node. */ { // Share the test node again final QuickShareDTO dto = share(testNode, user1.getUsername()); // Delete only the sharedId without removing the 'shared' aspect!(The cause of MNT-16224 and RA-1093) TenantUtil.runAsDefaultTenant(new TenantRunAsWork<Void>() { public Void doWork() throws Exception { attributeService.removeAttribute(".sharedIds", dto.getId()); return null; } }); // Check the 'shared' aspect does exist AuthenticationUtil.runAsSystem(new RunAsWork<Void>() { @Override public Void doWork() throws Exception { assertTrue(nodeService.hasAspect(testNode, QuickShareModel.ASPECT_QSHARE)); return null; } }); try { // Try to un-share the node even though the sharedId was deleted. unshare(dto.getId(), user2.getUsername()); fail("user2 shouldn't be able to un-share the node."); } catch (InvalidSharedIdException ex) { // Expected } // Un-share the node even though the sharedId was deleted. // This should succeed as the lookup will use TMDQ. unshare(dto.getId(), user1.getUsername()); // Check the 'shared' aspect does not exist AuthenticationUtil.runAsSystem(new RunAsWork<Void>() { @Override public Void doWork() throws Exception { assertFalse(nodeService.hasAspect(testNode, QuickShareModel.ASPECT_QSHARE)); return null; } }); } } private void unshare(final String sharedId, final String userName) { AuthenticationUtil.runAs(new RunAsWork<Void>() { @Override public Void doWork() throws Exception { quickShareService.unshareContent(sharedId); return null; } }, userName); } private QuickShareDTO share(final NodeRef nodeRef, String username) { return AuthenticationUtil.runAs(new RunAsWork<QuickShareDTO>() { @Override public QuickShareDTO doWork() throws Exception { return quickShareService.shareContent(nodeRef); } }, username); } @Test public void getMetadataFromShareId() { QuickShareDTO dto = share(testNode, user1.getUsername()); Map<String, Object> metadata = quickShareService.getMetaData(dto.getId()); assertNotNull(metadata); assertTrue(metadata.size() > 0); } @Test(expected = InvalidSharedIdException.class) public void getMetadataFromShareIdWithInvalidId() { UUID uuid = UUIDGenerator.getInstance().generateRandomBasedUUID(); String sharedId = Base64.encodeBase64URLSafeString(uuid.toByteArray()); // => 22 chars (eg. q3bEKPeDQvmJYgt4hJxOjw) Map<String, Object> metadata = quickShareService.getMetaData(sharedId); } @Test public void copyNode() { share(testNode, user1.getUsername()); AuthenticationUtil.runAs(new RunAsWork<Object>() { @Override public Object doWork() throws Exception { Assert.assertTrue(nodeService.hasAspect(testNode, QuickShareModel.ASPECT_QSHARE)); Assert.assertNotNull(nodeService.getProperty(testNode, QuickShareModel.PROP_QSHARE_SHAREDBY)); Assert.assertNotNull(nodeService.getProperty(testNode, QuickShareModel.PROP_QSHARE_SHAREDID)); Map<QName, Serializable> originalProps = nodeService.getProperties(testNode); NodeRef copyNodeRef = copyService.copyAndRename(testNode, userHome, ContentModel.ASSOC_CONTAINS, QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "copy"), true); Map<QName, Serializable> copyProps = nodeService.getProperties(copyNodeRef); Assert.assertFalse(nodeService.hasAspect(copyNodeRef, QuickShareModel.ASPECT_QSHARE)); Assert.assertNull(nodeService.getProperty(copyNodeRef, QuickShareModel.PROP_QSHARE_SHAREDBY)); Assert.assertNull(nodeService.getProperty(copyNodeRef, QuickShareModel.PROP_QSHARE_SHAREDID)); for (QName property : originalProps.keySet()) { if (property.equals(QuickShareModel.PROP_QSHARE_SHAREDBY) || property.equals(QuickShareModel.PROP_QSHARE_SHAREDID)) { continue; } Assert.assertTrue("Mising property " + property, copyProps.containsKey(property)); } return null; } }, user1.getUsername()); } /** * Content types that extend cm:content should be shareable. * * See https://issues.alfresco.com/jira/browse/ALF-16274. */ @Test public void testWithCustomContentType() { ByteArrayInputStream modelStream = new ByteArrayInputStream(MODEL.getBytes()); temporaryModels.loadModel(modelStream); QName sharableType = QName.createQName("{http://bugtestmodel}doc"); QName unsharableType = QName.createQName("{http://bugtestmodel}doc2"); final NodeRef sharableNode = testNodes.createNodeWithTextContent(userHome, "Quick Share Custom Type Sharable Test Node", sharableType, user1.getUsername(), "Quick Share Test Node Content"); Map<String, Object> metadata = getMetadata(sharableNode, user1); assertTrue((Boolean) metadata.get("sharable")); QuickShareDTO dto = share(sharableNode, user1.getUsername()); unshare(dto.getId(), user1.getUsername()); final NodeRef unsharableNode = testNodes.createNodeWithTextContent(userHome, "Quick Share Custom Type Unsharable Test Node", unsharableType, user1.getUsername(), "Quick Share Test Node Content"); metadata = getMetadata(unsharableNode, user1); assertFalse((Boolean) metadata.get("sharable")); boolean exceptionThrown = false; try { // Prior to fixing ALF-16274, this would throw an InvalidNodeRefException. share(unsharableNode, user1.getUsername()); } catch (InvalidNodeRefException ex) { exceptionThrown = true; } assertTrue("InvalidNodeRefException not thrown on trying to share an unsharable content type", exceptionThrown); } @SuppressWarnings("unchecked") private Map<String, Object> getMetadata(final NodeRef nodeRef, AlfrescoPerson user) { Map<String, Object> container = AuthenticationUtil.runAs(new RunAsWork<Map<String, Object>>() { @Override public Map<String, Object> doWork() throws Exception { return quickShareService.getMetaData(nodeRef); } }, user.getUsername()); return (Map<String, Object>) container.get("item"); } @Test public void cloud928() { final NodeRef node = testNodes.createNodeWithTextContent(userHome, "CLOUD-928 Test Node", ContentModel.TYPE_CONTENT, user1.getUsername(), "Quick Share Test Node Content"); QuickShareDTO dto = share(node, user1.getUsername()); attributeService.removeAttribute(QuickShareServiceImpl.ATTR_KEY_SHAREDIDS_ROOT, dto.getId()); AuthenticationUtil.runAs(new RunAsWork<Object>() { @Override public Object doWork() throws Exception { nodeService.deleteNode(node); return null; } }, user1.getUsername()); AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser(); Assert.assertFalse(nodeService.exists(node)); } /** * Test for MNT-11960 * <p> The node is created by user1 and shared by user2. * <p> The modifier should not change to user2 after sharing. */ @Test public void testModifierAfterSharing() { AuthenticationUtil.runAs(new RunAsWork<Void>() { @Override public Void doWork() throws Exception { permissionService.setPermission(testNode, user2.getUsername(), PermissionService.CONSUMER, true); return null; } }, user1.getUsername()); final Serializable modifiedDate = AuthenticationUtil.runAsSystem(new RunAsWork<Serializable>() { @Override public Serializable doWork() throws Exception { return nodeService.getProperty(testNode, ContentModel.PROP_MODIFIED); } }); share(testNode, user2.getUsername()); AuthenticationUtil.runAsSystem(new RunAsWork<Void>() { @Override public Void doWork() throws Exception { assertTrue(nodeService.getAspects(testNode).contains(ContentModel.ASPECT_AUDITABLE)); assertNotNull(nodeService.getProperty(testNode, ContentModel.PROP_MODIFIER)); assertEquals("The modifier has changed after sharing.", user1.getUsername(), nodeService.getProperty(testNode, ContentModel.PROP_MODIFIER)); assertNotNull(nodeService.getProperty(testNode, ContentModel.PROP_MODIFIED)); assertEquals("The modified date has changed after sharing.", modifiedDate, nodeService.getProperty(testNode, ContentModel.PROP_MODIFIED)); return null; } }); } /** * Test for MNT-15654 * <p> The node is created and shared by user1. Then unshared by user2 * <p> The modifier should not change to user2 after unsharing. */ @Test public void testModifierAfterUnSharing() { AuthenticationUtil.runAs(new RunAsWork<Void>() { @Override public Void doWork() throws Exception { permissionService.setPermission(testNode, user2.getUsername(), PermissionService.CONSUMER, true); return null; } }, user1.getUsername()); QuickShareDTO dto = share(testNode, user1.getUsername()); unshare(dto.getId(), user2.getUsername()); String modifier = AuthenticationUtil.runAsSystem(new RunAsWork<String>() { @Override public String doWork() throws Exception { return (String) nodeService.getProperty(testNode, ContentModel.PROP_MODIFIER); } }); assertEquals("The modifier has changed after sharing.", user1.getUsername(), modifier); } }