diff --git a/config/alfresco/public-rest-context.xml b/config/alfresco/public-rest-context.xml
index a5ce32ae10..de53df7b8d 100644
--- a/config/alfresco/public-rest-context.xml
+++ b/config/alfresco/public-rest-context.xml
@@ -471,6 +471,7 @@
+
diff --git a/source/java/org/alfresco/rest/api/impl/NodesImpl.java b/source/java/org/alfresco/rest/api/impl/NodesImpl.java
index f4d146f038..8bf26ec08a 100644
--- a/source/java/org/alfresco/rest/api/impl/NodesImpl.java
+++ b/source/java/org/alfresco/rest/api/impl/NodesImpl.java
@@ -47,7 +47,9 @@ import org.alfresco.model.ContentModel;
import org.alfresco.model.QuickShareModel;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
+import org.alfresco.repo.Client;
import org.alfresco.repo.action.executer.ContentMetadataExtracter;
+import org.alfresco.repo.activities.ActivityType;
import org.alfresco.repo.content.ContentLimitViolationException;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.model.Repository;
@@ -99,6 +101,7 @@ import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ActionDefinition;
import org.alfresco.service.cmr.action.ActionService;
+import org.alfresco.service.cmr.activities.ActivityPoster;
import org.alfresco.service.cmr.dictionary.AspectDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
@@ -159,6 +162,7 @@ import org.springframework.http.MediaType;
public class NodesImpl implements Nodes
{
private static final Log logger = LogFactory.getLog(NodesImpl.class);
+ private static final String APP_TOOL = "API";
private enum Type
{
@@ -181,6 +185,7 @@ public class NodesImpl implements Nodes
private OwnableService ownableService;
private AuthorityService authorityService;
private ThumbnailService thumbnailService;
+ private ActivityPoster poster;
private BehaviourFilter behaviourFilter;
@@ -254,6 +259,11 @@ public class NodesImpl implements Nodes
this.defaultIgnoreTypesAndAspects = ignoreTypesAndAspects;
}
+ public void setPoster(ActivityPoster poster)
+ {
+ this.poster = poster;
+ }
+
// excluded namespaces (aspects and properties)
private static final List EXCLUDED_NS = Arrays.asList(NamespaceService.SYSTEM_MODEL_1_0_URI);
@@ -1482,6 +1492,7 @@ public class NodesImpl implements Nodes
private NodeRef createNodeImpl(NodeRef parentNodeRef, String nodeName, QName nodeTypeQName, Map props)
{
+ NodeRef newNode = null;
if (props == null)
{
props = new HashMap<>(1);
@@ -1493,13 +1504,24 @@ public class NodesImpl implements Nodes
QName assocQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, QName.createValidLocalName(nodeName));
try
{
- return nodeService.createNode(parentNodeRef, ContentModel.ASSOC_CONTAINS, assocQName, nodeTypeQName, props).getChildRef();
+ newNode = nodeService.createNode(parentNodeRef, ContentModel.ASSOC_CONTAINS, assocQName, nodeTypeQName, props).getChildRef();
}
catch (DuplicateChildNodeNameException dcne)
{
// duplicate - name clash
throw new ConstraintViolatedException(dcne.getMessage());
}
+
+ boolean isFolder = isSubClass(nodeTypeQName, ContentModel.TYPE_FOLDER);
+ boolean isContent = isSubClass(nodeTypeQName, ContentModel.TYPE_CONTENT);
+
+ if (isFolder || isContent)
+ {
+ FileInfo fileInfo = fileFolderService.getFileInfo(newNode);
+ poster.postSiteAwareFileFolderActivity(isFolder?ActivityType.FOLDER_ADDED:ActivityType.FILE_ADDED, null, TenantUtil.getCurrentDomain(),
+ null, parentNodeRef, newNode, nodeName, APP_TOOL, Client.asType(Client.ClientType.script), fileInfo);
+ }
+ return newNode;
}
// check cm:cmobject (but *not* cm:systemfolder)
@@ -1715,7 +1737,16 @@ public class NodesImpl implements Nodes
}
}
- return getFolderOrDocument(nodeRef.getId(), parameters);
+ Node updatedNode = getFolderOrDocument(nodeRef.getId(), parameters);
+ boolean isContent = isSubClass(nodeTypeQName, ContentModel.TYPE_CONTENT);
+
+ if (isContent)
+ {
+ FileInfo fileInfo = fileFolderService.getFileInfo(nodeRef);
+ poster.postSiteAwareFileFolderActivity(ActivityType.FILE_UPDATED, null, TenantUtil.getCurrentDomain(),
+ null, updatedNode.getParentId(), updatedNode.getNodeRef(), updatedNode.getName(), APP_TOOL, Client.asType(Client.ClientType.script), fileInfo);
+ }
+ return updatedNode;
}
@Override
@@ -1855,12 +1886,14 @@ public class NodesImpl implements Nodes
}
String versionComment = parameters.getParameter(PARAM_VERSION_COMMENT);
- return updateExistingFile(nodeRef, contentInfo, stream, parameters, versionMajor, versionComment);
+ final String fileName = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
+ return updateExistingFile(null, nodeRef, fileName, contentInfo, stream, parameters, versionMajor, versionComment);
}
- private Node updateExistingFile(NodeRef nodeRef, BasicContentInfo contentInfo, InputStream stream, Parameters parameters, Boolean versionMajor, String versionComment)
+ private Node updateExistingFile(NodeRef parentNodeRef, NodeRef nodeRef, String fileName, BasicContentInfo contentInfo, InputStream stream, Parameters parameters, Boolean versionMajor, String versionComment)
{
boolean isVersioned = versionService.isVersioned(nodeRef);
+ FileInfo fileInfo = fileFolderService.getFileInfo(nodeRef);
behaviourFilter.disableBehaviour(nodeRef, ContentModel.ASPECT_VERSIONABLE);
try
@@ -1877,6 +1910,9 @@ public class NodesImpl implements Nodes
createVersion(nodeRef, isVersioned, versionType, versionComment);
}
+ poster.postSiteAwareFileFolderActivity(ActivityType.FILE_UPDATED, null, TenantUtil.getCurrentDomain(),
+ null, parentNodeRef, nodeRef, fileName, APP_TOOL, Client.asType(Client.ClientType.script), fileInfo);
+
extractMetadata(nodeRef);
}
finally
@@ -2081,7 +2117,7 @@ public class NodesImpl implements Nodes
{
// overwrite existing (versionable) file
BasicContentInfo contentInfo = new ContentInfoImpl(content.getMimetype(), content.getEncoding(), -1, null);
- return updateExistingFile(existingFile, contentInfo, content.getInputStream(), parameters, majorVersion, versionComment);
+ return updateExistingFile(parentNodeRef, existingFile, fileName, contentInfo, content.getInputStream(), parameters, majorVersion, versionComment);
}
else
{
diff --git a/source/test-java/org/alfresco/rest/api/tests/ActivitiesPostingTest.java b/source/test-java/org/alfresco/rest/api/tests/ActivitiesPostingTest.java
new file mode 100644
index 0000000000..16ffc15c1b
--- /dev/null
+++ b/source/test-java/org/alfresco/rest/api/tests/ActivitiesPostingTest.java
@@ -0,0 +1,143 @@
+package org.alfresco.rest.api.tests;
+
+import static org.alfresco.rest.api.tests.util.RestApiUtil.toJsonAsStringNonNull;
+import static org.junit.Assert.*;
+
+import org.alfresco.repo.activities.ActivityType;
+import org.alfresco.repo.security.authentication.AuthenticationUtil;
+import org.alfresco.repo.tenant.TenantUtil;
+import org.alfresco.repo.transaction.RetryingTransactionHelper;
+import org.alfresco.rest.api.Activities;
+import org.alfresco.rest.api.tests.client.HttpResponse;
+import org.alfresco.rest.api.tests.client.PublicApiClient;
+import org.alfresco.rest.api.tests.client.data.Activity;
+import org.alfresco.rest.api.tests.client.data.ContentInfo;
+import org.alfresco.rest.api.tests.client.data.Document;
+import org.alfresco.rest.api.tests.client.data.Folder;
+import org.alfresco.rest.api.tests.util.RestApiUtil;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.security.MutableAuthenticationService;
+import org.alfresco.service.cmr.security.PersonService;
+import org.alfresco.service.cmr.site.SiteVisibility;
+import org.json.simple.JSONObject;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by gethin on 22/03/16.
+ */
+public class ActivitiesPostingTest extends AbstractBaseApiTest
+{
+ protected MutableAuthenticationService authenticationService;
+ protected PersonService personService;
+
+ RepoService.TestNetwork networkOne;
+ RepoService.TestPerson u1;
+ RepoService.TestSite tSite;
+ NodeRef docLibNodeRef;
+
+ @Override
+ public String getScope()
+ {
+ return "public";
+ }
+
+ @Before
+ public void setup() throws Exception
+ {
+ authenticationService = applicationContext.getBean("authenticationService", MutableAuthenticationService.class);
+ personService = applicationContext.getBean("personService", PersonService.class);
+
+ networkOne = getTestFixture().getRandomNetwork();
+ u1 = networkOne.createUser();
+ tSite = createSite(networkOne, u1, SiteVisibility.PRIVATE);
+
+ AuthenticationUtil.setFullyAuthenticatedUser(u1.getId());
+ docLibNodeRef = tSite.getContainerNodeRef("documentLibrary");
+ AuthenticationUtil.clearCurrentSecurityContext();
+ }
+
+
+ @After
+ public void tearDown() throws Exception
+ {
+ AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser();
+ transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback()
+ {
+ @Override
+ public Void execute() throws Throwable
+ {
+ if (personService.personExists(u1.getId()))
+ {
+ authenticationService.deleteAuthentication(u1.getId());
+ personService.deletePerson(u1.getId());
+ }
+ return null;
+ }
+ });
+ AuthenticationUtil.clearCurrentSecurityContext();
+ }
+
+ @Test
+ public void testCreateUpdate() throws Exception
+ {
+ String folder1 = "folder" + System.currentTimeMillis() + "_1";
+ Folder createdFolder = createFolder(u1.getId(), docLibNodeRef.getId(), folder1, null);
+ assertNotNull(createdFolder);
+
+ Document d1 = new Document();
+ d1.setName("d1.txt");
+ d1.setNodeType("cm:content");
+ ContentInfo ci = new ContentInfo();
+ ci.setMimeType("text/plain");
+ d1.setContent(ci);
+
+ // create empty file
+ HttpResponse response = post(getNodeChildrenUrl(createdFolder.getId()), u1.getId(), toJsonAsStringNonNull(d1), 201);
+ Document documentResp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Document.class);
+
+ //Update the file
+ Document dUpdate = new Document();
+ dUpdate.setName("d1b.txt");
+ response = put(URL_NODES, u1.getId(), documentResp.getId(), toJsonAsStringNonNull(dUpdate), null, 200);
+
+ repoService.generateFeed();
+
+ Map meParams = new HashMap<>();
+ meParams.put("who", String.valueOf(Activities.ActivityWho.me));
+ PublicApiClient.ListResponse activities = publicApiClient.people().getActivities(u1.getId(), meParams);
+ assertEquals(activities.getList().size(),3);
+ Activity act = matchActivity(activities.getList(), ActivityType.FOLDER_ADDED, u1.getId(), tSite.getSiteId(), docLibNodeRef.getId(), folder1);
+ assertNotNull(act);
+
+ act = matchActivity(activities.getList(), ActivityType.FILE_ADDED, u1.getId(), tSite.getSiteId(), createdFolder.getId(), d1.getName());
+ assertNotNull(act);
+
+ act = matchActivity(activities.getList(), ActivityType.FILE_UPDATED, u1.getId(), tSite.getSiteId(), createdFolder.getId(), dUpdate.getName());
+ assertNotNull(act);
+
+ }
+
+ private Activity matchActivity(List list, String type, String user, String siteId, String parentId, String title)
+ {
+ for (Activity act:list)
+ {
+ if (type.equals(act.getActivityType())
+ && user.equals(act.getPostPersonId())
+ && siteId.equals(act.getSiteId())
+ && parentId.equals(act.getSummary().get("parentObjectId"))
+ && title.equals((act.getSummary().get("title"))))
+ {
+ return act;
+ }
+ }
+ return null;
+ }
+}