diff --git a/config/alfresco/activities/activities-feed-context.xml b/config/alfresco/activities/activities-feed-context.xml
index e6d0a14511..2882decd3d 100644
--- a/config/alfresco/activities/activities-feed-context.xml
+++ b/config/alfresco/activities/activities-feed-context.xml
@@ -82,6 +82,8 @@
+
+
alfresco/extension/templates/activities
diff --git a/source/java/org/alfresco/repo/activities/ActivityPostServiceImpl.java b/source/java/org/alfresco/repo/activities/ActivityPostServiceImpl.java
index 3189f4f4fc..76ce293a3d 100644
--- a/source/java/org/alfresco/repo/activities/ActivityPostServiceImpl.java
+++ b/source/java/org/alfresco/repo/activities/ActivityPostServiceImpl.java
@@ -22,6 +22,7 @@ import java.sql.SQLException;
import java.util.Date;
import org.alfresco.error.AlfrescoRuntimeException;
+import org.alfresco.repo.activities.post.lookup.PostLookup;
import org.alfresco.repo.domain.activities.ActivityPostDAO;
import org.alfresco.repo.domain.activities.ActivityPostEntity;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
@@ -29,9 +30,9 @@ import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.cmr.activities.ActivityPostService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
-import org.springframework.extensions.surf.util.ParameterCheck;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.springframework.extensions.surf.util.ParameterCheck;
/**
* Activity Post Service Implementation
@@ -84,7 +85,7 @@ public class ActivityPostServiceImpl implements ActivityPostService
ParameterCheck.mandatory("nodeRef", nodeRef);
StringBuffer sb = new StringBuffer();
- sb.append("{").append("\"nodeRef\":\"").append(nodeRef.toString()).append("\"").append("}");
+ sb.append("{").append("\""+PostLookup.JSON_NODEREF_LOOKUP+"\":\"").append(nodeRef.toString()).append("\"").append("}");
postActivity(activityType, siteId, appTool, sb.toString(), ActivityPostEntity.STATUS.PENDING);
}
@@ -97,7 +98,7 @@ public class ActivityPostServiceImpl implements ActivityPostService
ParameterCheck.mandatory("nodeRef", nodeRef);
StringBuffer sb = new StringBuffer();
- sb.append("{").append("\"nodeRef\":\"").append(nodeRef.toString()).append("\"").append(",")
+ sb.append("{").append("\""+PostLookup.JSON_NODEREF_LOOKUP+"\":\"").append(nodeRef.toString()).append("\"").append(",")
.append("\"name\":\"").append(name).append("\"")
.append("}");
@@ -116,10 +117,10 @@ public class ActivityPostServiceImpl implements ActivityPostService
ParameterCheck.mandatory("parentNodeRef", parentNodeRef);
StringBuffer sb = new StringBuffer();
- sb.append("{").append("\"nodeRef\":\"").append(nodeRef.toString()).append("\"").append(",")
- .append("\"name\":\"").append(name).append("\"").append(",")
- .append("\"typeQName\":\"").append(typeQName.toPrefixString()).append("\"").append(",") // TODO toPrefixString does not return prefix ??!!
- .append("\"parentNodeRef\":\"").append(parentNodeRef.toString()).append("\"")
+ sb.append("{").append("\""+PostLookup.JSON_NODEREF_LOOKUP+"\":\"").append(nodeRef.toString()).append("\"").append(",")
+ .append("\""+PostLookup.JSON_NAME+"\":\"").append(name).append("\"").append(",")
+ .append("\""+PostLookup.JSON_TYPEQNAME+"\":\"").append(typeQName.toPrefixString()).append("\"").append(",") // TODO toPrefixString does not return prefix ??!!
+ .append("\""+PostLookup.JSON_NODEREF_PARENT+"\":\"").append(parentNodeRef.toString()).append("\"")
.append("}");
postActivity(activityType, siteId, appTool, sb.toString(), ActivityPostEntity.STATUS.PENDING);
diff --git a/source/java/org/alfresco/repo/activities/feed/FeedTaskProcessor.java b/source/java/org/alfresco/repo/activities/feed/FeedTaskProcessor.java
index 68e8827260..db8902be63 100644
--- a/source/java/org/alfresco/repo/activities/feed/FeedTaskProcessor.java
+++ b/source/java/org/alfresco/repo/activities/feed/FeedTaskProcessor.java
@@ -257,7 +257,14 @@ public abstract class FeedTaskProcessor
excludedConnections++;
}
else
- {
+ {
+ // read permission check
+ if (! canRead(ctx, connectedUser, model))
+ {
+ excludedConnections++;
+ continue;
+ }
+
for (String fmTemplate : fmTemplates)
{
// determine format - based on template naming convention
@@ -448,6 +455,11 @@ public abstract class FeedTaskProcessor
return members;
}
+ protected boolean canRead(RepoCtx ctx, final String connectedUser, Map model) throws Exception
+ {
+ throw new UnsupportedOperationException("FeedTaskProcessor: Remote callback for 'canRead' not implemented");
+ }
+
protected Map> getActivityTypeTemplates(String repoEndPoint, String ticket, String subPath) throws Exception
{
StringBuffer sbUrl = new StringBuffer();
diff --git a/source/java/org/alfresco/repo/activities/feed/local/LocalFeedTaskProcessor.java b/source/java/org/alfresco/repo/activities/feed/local/LocalFeedTaskProcessor.java
index 361b5d9128..aab6ad4ab2 100644
--- a/source/java/org/alfresco/repo/activities/feed/local/LocalFeedTaskProcessor.java
+++ b/source/java/org/alfresco/repo/activities/feed/local/LocalFeedTaskProcessor.java
@@ -28,6 +28,7 @@ import java.util.Set;
import org.alfresco.repo.activities.feed.FeedTaskProcessor;
import org.alfresco.repo.activities.feed.RepoCtx;
+import org.alfresco.repo.activities.post.lookup.PostLookup;
import org.alfresco.repo.domain.activities.ActivityFeedDAO;
import org.alfresco.repo.domain.activities.ActivityFeedEntity;
import org.alfresco.repo.domain.activities.ActivityPostDAO;
@@ -37,7 +38,13 @@ import org.alfresco.repo.domain.activities.FeedControlEntity;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.template.ClassPathRepoTemplateLoader;
import org.alfresco.service.cmr.repository.ContentService;
+import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.repository.StoreRef;
+import org.alfresco.service.cmr.security.AccessPermission;
+import org.alfresco.service.cmr.security.AccessStatus;
+import org.alfresco.service.cmr.security.AuthorityType;
+import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.site.SiteService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -68,6 +75,8 @@ public class LocalFeedTaskProcessor extends FeedTaskProcessor implements Applica
private SiteService siteService;
private NodeService nodeService;
private ContentService contentService;
+ private PermissionService permissionService;
+
private String defaultEncoding;
private List templateSearchPaths;
private boolean useRemoteCallbacks;
@@ -107,6 +116,11 @@ public class LocalFeedTaskProcessor extends FeedTaskProcessor implements Applica
this.contentService = contentService;
}
+ public void setPermissionService(PermissionService permissionService)
+ {
+ this.permissionService = permissionService;
+ }
+
public void setDefaultEncoding(String defaultEncoding)
{
this.defaultEncoding = defaultEncoding;
@@ -206,6 +220,105 @@ public class LocalFeedTaskProcessor extends FeedTaskProcessor implements Applica
}
}
+ protected boolean canRead(RepoCtx ctx, final String connectedUser, Map model) throws Exception
+ {
+ if (useRemoteCallbacks)
+ {
+ // note: not implemented
+ return super.canRead(ctx, connectedUser, model);
+ }
+ else
+ {
+ if (permissionService == null)
+ {
+ // if permission service not configured then fallback (ie. no read permission check)
+ return true;
+ }
+
+ String nodeRefStr = (String)model.get(PostLookup.JSON_NODEREF);
+ if (nodeRefStr == null)
+ {
+ nodeRefStr = (String)model.get(PostLookup.JSON_NODEREF_PARENT);
+ }
+
+ if (nodeRefStr != null)
+ {
+ final NodeRef nodeRef = new NodeRef(nodeRefStr);
+
+ return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork()
+ {
+ public Boolean doWork() throws Exception
+ {
+ return canReadImpl(connectedUser, nodeRef);
+ }
+ }, AuthenticationUtil.getSystemUserName());
+ }
+
+ return true;
+ }
+ }
+
+ private boolean canReadImpl(final String connectedUser, final NodeRef nodeRef) throws Exception
+ {
+ // check for read permission
+ long start = System.currentTimeMillis();
+
+ try
+ {
+ // note: deleted node does not exist (hence no permission, although default permission check would return true which is problematic)
+ final NodeRef checkNodeRef;
+ if (nodeService.exists(nodeRef))
+ {
+ checkNodeRef = nodeRef;
+ }
+ else
+ {
+ // TODO: require ghosting - this is temp workaround (we should not rely on archive - may be permanently deleted, ie. not archived or already purged)
+ NodeRef archiveNodeRef = new NodeRef(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, nodeRef.getId());
+ if (! nodeService.exists(archiveNodeRef))
+ {
+ return false;
+ }
+ checkNodeRef = archiveNodeRef;
+ }
+
+ if (connectedUser.equals(""))
+ {
+ // site feed (public site)
+ Set perms = permissionService.getAllSetPermissions(checkNodeRef);
+ for (AccessPermission perm : perms)
+ {
+ if (perm.getAuthority().equals(PermissionService.ALL_AUTHORITIES) &&
+ perm.getAuthorityType().equals(AuthorityType.EVERYONE) &&
+ perm.getPermission().equals(PermissionService.READ_PERMISSIONS) &&
+ perm.getAccessStatus().equals(AccessStatus.ALLOWED))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ else
+ {
+ // user feed
+ return AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork()
+ {
+ public Boolean doWork() throws Exception
+ {
+ return (permissionService.hasPermission(checkNodeRef, PermissionService.READ) == AccessStatus.ALLOWED);
+ }
+ }, connectedUser);
+ }
+ }
+ finally
+ {
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("canRead: " + nodeRef + " in "+(System.currentTimeMillis()-start)+" msecs");
+ }
+ }
+ }
+
@Override
protected Map> getActivityTypeTemplates(String repoEndPoint, String ticket, String subPath) throws Exception
{
diff --git a/source/java/org/alfresco/repo/activities/post/lookup/PostLookup.java b/source/java/org/alfresco/repo/activities/post/lookup/PostLookup.java
index 646e004ec6..13bf58e35c 100644
--- a/source/java/org/alfresco/repo/activities/post/lookup/PostLookup.java
+++ b/source/java/org/alfresco/repo/activities/post/lookup/PostLookup.java
@@ -62,6 +62,20 @@ public class PostLookup
private PersonService personService;
private TenantService tenantService;
+ public static final String JSON_NODEREF_LOOKUP = "nodeRefL"; // requires additional lookup
+
+ public static final String JSON_NODEREF = "nodeRef";
+ public static final String JSON_NODEREF_PARENT = "parentNodeRef";
+
+ public static final String JSON_FIRSTNAME = "firstName";
+ public static final String JSON_LASTNAME = "lastName";
+
+ public static final String JSON_NAME = "name";
+ public static final String JSON_TYPEQNAME = "typeQName";
+ public static final String JSON_PARENT_NODEREF = "parentNodeRef";
+ public static final String JSON_DISPLAY_PATH = "displayPath";
+
+
public void setPostDAO(ActivityPostDAO postDAO)
{
this.postDAO = postDAO;
@@ -139,9 +153,9 @@ public class PostLookup
String activityDataStr = null;
- if (! jo.isNull("nodeRef"))
+ if (! jo.isNull(JSON_NODEREF_LOOKUP))
{
- String nodeRefStr = jo.getString("nodeRef");
+ String nodeRefStr = jo.getString(JSON_NODEREF_LOOKUP);
NodeRef nodeRef = new NodeRef(nodeRefStr);
// lookup additional node data
@@ -154,8 +168,8 @@ public class PostLookup
Pair firstLastName = lookupPerson(postUserId);
if (firstLastName != null)
{
- jo.put("firstName", firstLastName.getFirst());
- jo.put("lastName", firstLastName.getSecond());
+ jo.put(JSON_FIRSTNAME, firstLastName.getFirst());
+ jo.put(JSON_LASTNAME, firstLastName.getSecond());
activityDataStr = jo.toString();
}
@@ -283,22 +297,22 @@ public class PostLookup
public JSONObject execute() throws Throwable
{
String name = "";
- if (! jo.isNull("name"))
+ if (! jo.isNull(JSON_NAME))
{
- name = jo.getString("name");
+ name = jo.getString(JSON_NAME);
}
NodeRef parentNodeRef = null;
- if (! jo.isNull("parentNodeRef"))
+ if (! jo.isNull(JSON_PARENT_NODEREF))
{
- parentNodeRef = new NodeRef(jo.getString("parentNodeRef"));
+ parentNodeRef = new NodeRef(jo.getString(JSON_PARENT_NODEREF));
}
String typeQName = "";
- if (! jo.isNull("typeQName"))
+ if (! jo.isNull(JSON_TYPEQNAME))
{
- typeQName = jo.getString("typeQName");
+ typeQName = jo.getString(JSON_TYPEQNAME);
}
String displayPath = "";
@@ -341,25 +355,25 @@ public class PostLookup
// parent node exists, lookup parent node path
path = nodeService.getPath(parentNodeRef);
}
-
+
if (path != null)
{
// lookup display path
displayPath = path.toDisplayPath(nodeService, permissionService);
-
+
// note: for now, also tack on the node name
displayPath += "/" + name;
}
// merge with existing activity data
- jo.put("name", name);
- jo.put("nodeRef", nodeRef.toString());
- jo.put("typeQName", typeQName);
- jo.put("parentNodeRef", (parentNodeRef != null ? parentNodeRef.toString() : null));
- jo.put("displayPath", displayPath);
- jo.put("firstName", firstName);
- jo.put("lastName", lastName);
-
+ jo.put(JSON_NAME, name);
+ jo.put(JSON_NODEREF, nodeRef.toString());
+ jo.put(JSON_TYPEQNAME, typeQName);
+ jo.put(JSON_PARENT_NODEREF, (parentNodeRef != null ? parentNodeRef.toString() : null));
+ jo.put(JSON_DISPLAY_PATH, displayPath);
+ jo.put(JSON_FIRSTNAME, firstName);
+ jo.put(JSON_LASTNAME, lastName);
+
return jo;
}
};