Search in sources :

Example 6 with ActivityPostEntity

use of org.alfresco.repo.domain.activities.ActivityPostEntity in project alfresco-repository by Alfresco.

the class ActivityPostDAOImpl method deletePosts.

public int deletePosts(Date keepDate, ActivityPostEntity.STATUS status) throws SQLException {
    ActivityPostEntity params = new ActivityPostEntity();
    params.setPostDate(keepDate);
    params.setStatus(status.toString());
    return template.delete("alfresco.activities.delete_activity_posts_older_than_date", params);
}
Also used : ActivityPostEntity(org.alfresco.repo.domain.activities.ActivityPostEntity)

Example 7 with ActivityPostEntity

use of org.alfresco.repo.domain.activities.ActivityPostEntity in project alfresco-repository by Alfresco.

the class ActivityPostDAOImpl method updatePost.

public int updatePost(long id, String siteNetwork, String activityData, ActivityPostEntity.STATUS status) throws SQLException {
    ActivityPostEntity post = new ActivityPostEntity();
    post.setId(id);
    post.setSiteNetwork(siteNetwork);
    post.setActivityData(activityData);
    post.setStatus(status.toString());
    post.setLastModified(new Date());
    return template.update("alfresco.activities.update_activity_post_data", post);
}
Also used : ActivityPostEntity(org.alfresco.repo.domain.activities.ActivityPostEntity) Date(java.util.Date)

Example 8 with ActivityPostEntity

use of org.alfresco.repo.domain.activities.ActivityPostEntity in project alfresco-repository by Alfresco.

the class ActivityPostDAOImpl method updatePostStatus.

public int updatePostStatus(long id, ActivityPostEntity.STATUS status) throws SQLException {
    ActivityPostEntity post = new ActivityPostEntity();
    post.setId(id);
    post.setStatus(status.toString());
    post.setLastModified(new Date());
    return template.update("alfresco.activities.update_activity_post_status", post);
}
Also used : ActivityPostEntity(org.alfresco.repo.domain.activities.ActivityPostEntity) Date(java.util.Date)

Example 9 with ActivityPostEntity

use of org.alfresco.repo.domain.activities.ActivityPostEntity in project alfresco-repository by Alfresco.

the class FeedTaskProcessor method process.

public void process(int jobTaskNode, long minSeq, long maxSeq, RepoCtx ctx) throws Exception {
    long startTime = System.currentTimeMillis();
    if (logger.isDebugEnabled()) {
        logger.debug("Process: jobTaskNode '" + jobTaskNode + "' from seq '" + minSeq + "' to seq '" + maxSeq + "' on this node from grid job.");
    }
    ActivityPostEntity selector = new ActivityPostEntity();
    selector.setJobTaskNode(jobTaskNode);
    selector.setMinId(minSeq);
    selector.setMaxId(maxSeq);
    selector.setStatus(ActivityPostEntity.STATUS.POSTED.toString());
    List<ActivityPostEntity> activityPosts = null;
    int totalGenerated = 0;
    try {
        activityPosts = selectPosts(selector);
        if (logger.isDebugEnabled()) {
            logger.debug("Process: " + activityPosts.size() + " activity posts");
        }
        // local caches for this run of activity posts
        // site -> site members
        Map<String, Set<String>> siteConnectedUsers = new HashMap<String, Set<String>>();
        // user -> followers
        Map<Pair<String, String>, Set<String>> followerConnectedUsers = new HashMap<Pair<String, String>, Set<String>>();
        // <user, site> -> true/false (note: used when following, implied as true for site members)
        Map<Pair<String, String>, Boolean> canUserReadSite = new HashMap<Pair<String, String>, Boolean>();
        Map<String, List<FeedControlEntity>> userFeedControls = new HashMap<String, List<FeedControlEntity>>();
        List<String> fmTemplates = Arrays.asList(new String[] { "activities/org/alfresco/generic.json.ftl" });
        // for each activity post ...
        for (ActivityPostEntity activityPost : activityPosts) {
            String postingUserId = activityPost.getUserId();
            String activityType = activityPost.getActivityType();
            if (fmTemplates.size() == 0) {
                logger.error("Skipping activity post " + activityPost.getId() + " since no specific/generic templates for activityType: " + activityType);
                updatePostStatus(activityPost.getId(), ActivityPostEntity.STATUS.ERROR);
                continue;
            }
            Map<String, Object> model = null;
            try {
                model = JSONtoFmModel.convertJSONObjectToMap(activityPost.getActivityData());
            } catch (JSONException je) {
                logger.error("Skipping activity post " + activityPost.getId() + " due to invalid activity data: ", je);
                updatePostStatus(activityPost.getId(), ActivityPostEntity.STATUS.ERROR);
                continue;
            }
            String nodeRefStr = (String) model.get(PostLookup.JSON_NODEREF);
            try {
                // If a nodeRef is present, then it must be valid.
                if (nodeRefStr != null) {
                    // Attempt to create a nodeRef, making use of the constructor's validation.
                    new NodeRef(nodeRefStr);
                }
            } catch (Exception e) {
                logger.error("Skipping activity post " + activityPost.getId() + " due to invalid nodeRef: " + nodeRefStr);
                updatePostStatus(activityPost.getId(), ActivityPostEntity.STATUS.ERROR);
                continue;
            }
            // note: for MT share, site id should already be mangled - in addition to extra tenant domain info
            String thisSite = activityPost.getSiteNetwork();
            String tenantDomain = (String) model.get(PostLookup.JSON_TENANT_DOMAIN);
            if (thisSite != null) {
                if (tenantDomain != null) {
                    thisSite = getTenantName(thisSite, tenantDomain);
                } else {
                    // for backwards compatibility
                    tenantDomain = getTenantDomain(thisSite);
                }
            }
            if (tenantDomain == null) {
                tenantDomain = TenantService.DEFAULT_DOMAIN;
            }
            model.put(ActivityFeedEntity.KEY_ACTIVITY_FEED_TYPE, activityPost.getActivityType());
            model.put(ActivityFeedEntity.KEY_ACTIVITY_FEED_SITE, thisSite);
            model.put("userId", activityPost.getUserId());
            model.put("id", activityPost.getId());
            // post date rather than time that feed is generated
            model.put("date", activityPost.getPostDate());
            model.put("xmldate", new ISO8601DateFormatMethod());
            model.put("repoEndPoint", ctx.getRepoEndPoint());
            // Get recipients of this post
            Set<String> recipients = null;
            try {
                recipients = getRecipients(ctx, thisSite, activityPost.getUserId(), tenantDomain, siteConnectedUsers, followerConnectedUsers, canUserReadSite);
            } catch (Exception e) {
                logger.error("Skipping activity post " + activityPost.getId() + " since failed to get recipients: ", e);
                updatePostStatus(activityPost.getId(), ActivityPostEntity.STATUS.ERROR);
                continue;
            }
            try {
                startTransaction();
                if (logger.isTraceEnabled()) {
                    logger.trace("Process: " + recipients.size() + " candidate connections for activity post " + activityPost.getId());
                }
                int excludedConnections = 0;
                for (String recipient : recipients) {
                    List<FeedControlEntity> feedControls = null;
                    if (!recipient.equals("")) {
                        // Get user's feed controls
                        feedControls = userFeedControls.get(recipient);
                        if (feedControls == null) {
                            feedControls = getFeedControls(recipient);
                            userFeedControls.put(recipient, feedControls);
                        }
                    }
                    // filter based on opt-out feed controls (if any)
                    if (!acceptActivity(activityPost, feedControls)) {
                        excludedConnections++;
                    } else {
                        // node read permission check (if nodeRef is present)
                        if (!canRead(ctx, recipient, model)) {
                            excludedConnections++;
                            continue;
                        }
                        for (String fmTemplate : fmTemplates) {
                            String formatFound = FeedTaskProcessor.FEED_FORMAT_JSON;
                            ActivityFeedEntity feed = new ActivityFeedEntity();
                            // MNT-9104 If username contains uppercase letters the action of joining a site will not be displayed in "My activities"
                            if (!userNamesAreCaseSensitive) {
                                recipient = recipient.toLowerCase();
                                postingUserId = postingUserId.toLowerCase();
                            }
                            feed.setFeedUserId(recipient);
                            feed.setPostUserId(postingUserId);
                            feed.setActivityType(activityType);
                            String activitySummary = null;
                            // allows JSON to simply pass straight through
                            activitySummary = activityPost.getActivityData();
                            if (!activitySummary.equals("")) {
                                if (activitySummary.length() > ActivityFeedDAO.MAX_LEN_ACTIVITY_SUMMARY) {
                                    logger.warn("Skip feed entry (activity post " + activityPost.getId() + ") since activity summary - exceeds " + ActivityFeedDAO.MAX_LEN_ACTIVITY_SUMMARY + " chars: " + activitySummary);
                                } else {
                                    feed.setActivitySummary(activitySummary);
                                    feed.setSiteNetwork(thisSite);
                                    feed.setAppTool(activityPost.getAppTool());
                                    feed.setPostDate(activityPost.getPostDate());
                                    feed.setPostId(activityPost.getId());
                                    feed.setFeedDate(new Date());
                                    // Insert activity feed
                                    // ignore returned feedId
                                    insertFeedEntry(feed);
                                    totalGenerated++;
                                }
                            } else {
                                if (logger.isDebugEnabled()) {
                                    logger.debug("Empty template result for activityType '" + activityType + "' using format '" + formatFound + "' hence skip feed entry (activity post " + activityPost.getId() + ")");
                                }
                            }
                        }
                    }
                }
                updatePostStatus(activityPost.getId(), ActivityPostEntity.STATUS.PROCESSED);
                commitTransaction();
                if (logger.isDebugEnabled()) {
                    logger.debug("Processed: " + (recipients.size() - excludedConnections) + " connections for activity post " + activityPost.getId() + " (excluded " + excludedConnections + ")");
                }
            } finally {
                endTransaction();
            }
        }
    } catch (SQLException se) {
        logger.error(se);
        throw se;
    } finally {
        int postCnt = activityPosts == null ? 0 : activityPosts.size();
        // TODO i18n info message
        StringBuilder sb = new StringBuilder();
        sb.append("Generated ").append(totalGenerated).append(" activity feed entr").append(totalGenerated == 1 ? "y" : "ies");
        sb.append(" for ").append(postCnt).append(" activity post").append(postCnt != 1 ? "s" : "").append(" (in ").append(System.currentTimeMillis() - startTime).append(" msecs)");
        logger.info(sb.toString());
    }
}
Also used : HashSet(java.util.HashSet) Set(java.util.Set) HashMap(java.util.HashMap) SQLException(java.sql.SQLException) ActivityPostEntity(org.alfresco.repo.domain.activities.ActivityPostEntity) ActivityFeedEntity(org.alfresco.repo.domain.activities.ActivityFeedEntity) NodeRef(org.alfresco.service.cmr.repository.NodeRef) FeedControlEntity(org.alfresco.repo.domain.activities.FeedControlEntity) ArrayList(java.util.ArrayList) List(java.util.List) Pair(org.alfresco.util.Pair) JSONException(org.json.JSONException) ISO8601DateFormatMethod(org.alfresco.repo.template.ISO8601DateFormatMethod) URISyntaxException(java.net.URISyntaxException) TemplateException(freemarker.template.TemplateException) SQLException(java.sql.SQLException) JSONException(org.json.JSONException) MalformedURLException(java.net.MalformedURLException) IOException(java.io.IOException) FileNotFoundException(java.io.FileNotFoundException) Date(java.util.Date) JSONObject(org.json.JSONObject)

Example 10 with ActivityPostEntity

use of org.alfresco.repo.domain.activities.ActivityPostEntity in project alfresco-repository by Alfresco.

the class ActivityPostServiceImpl method postActivity.

private void postActivity(final String activityType, String siteId, String appTool, String activityData, ActivityPostEntity.STATUS status, String userId, final Client client, final FileInfo contentNodeInfo) {
    NodeRef nodeRef = null;
    try {
        // optional - default to empty string
        if (siteId == null) {
            siteId = "";
        } else if (siteId.length() > ActivityPostDAO.MAX_LEN_SITE_ID) {
            throw new IllegalArgumentException("Invalid siteId - exceeds " + ActivityPostDAO.MAX_LEN_SITE_ID + " chars: " + siteId);
        }
        // optional - default to empty string
        if (appTool == null) {
            appTool = "";
        } else if (appTool.length() > ActivityPostDAO.MAX_LEN_APP_TOOL_ID) {
            throw new IllegalArgumentException("Invalid app tool - exceeds " + ActivityPostDAO.MAX_LEN_APP_TOOL_ID + " chars: " + appTool);
        }
        // required
        ParameterCheck.mandatoryString("activityType", activityType);
        if (activityType.length() > ActivityPostDAO.MAX_LEN_ACTIVITY_TYPE) {
            throw new IllegalArgumentException("Invalid activity type - exceeds " + ActivityPostDAO.MAX_LEN_ACTIVITY_TYPE + " chars: " + activityType);
        }
        if (ignoredActivityTypes != null && ignoredActivityTypes.contains(activityType)) {
            // do not log the activity for ignored activity types.
            logger.debug("Ignoring activity type for posting: " + activityType);
            return;
        }
        // optional - default to empty string
        if (activityData == null) {
            activityData = "";
        }
        try {
            if (activityData.length() > 0) {
                JSONObject jo = new JSONObject(new JSONTokener(activityData));
                if (AuthenticationUtil.isMtEnabled()) {
                    // MT share - add tenantDomain
                    jo.put(PostLookup.JSON_TENANT_DOMAIN, tenantService.getCurrentUserDomain());
                    activityData = jo.toString();
                }
                nodeRef = checkNodeRef(jo);
                // ALF-10362 - belts-and-braces (note: Share sets "title" from cm:name)
                if (jo.has(PostLookup.JSON_TITLE)) {
                    String title = jo.getString(PostLookup.JSON_TITLE);
                    if (title.length() > ActivityPostDAO.MAX_LEN_NAME) {
                        jo.put(PostLookup.JSON_TITLE, title.substring(0, 255));
                        activityData = jo.toString();
                    }
                }
            }
        } catch (JSONException e) {
        // throw new IllegalArgumentException("Invalid activity data - not valid JSON: " + e);
        // According to test data in org/alfresco/repo/activities/script/test_activityService.js
        // invalid JSON should be OK.
        }
        if (activityData.length() > ActivityPostDAO.MAX_LEN_ACTIVITY_DATA) {
            throw new IllegalArgumentException("Invalid activity data - exceeds " + ActivityPostDAO.MAX_LEN_ACTIVITY_DATA + " chars: " + activityData);
        }
        // required
        ParameterCheck.mandatoryString("userId", userId);
        if (userId.length() > ActivityPostDAO.MAX_LEN_USER_ID) {
            throw new IllegalArgumentException("Invalid user - exceeds " + ActivityPostDAO.MAX_LEN_USER_ID + " chars: " + userId);
        }
    } catch (IllegalArgumentException e) {
        // log error and throw exception
        logger.error(e);
        throw new IllegalArgumentException("Failed to post activity: " + e, e);
    }
    try {
        final Date postDate = new Date();
        final ActivityPostEntity activityPost = new ActivityPostEntity();
        final String network = tenantService.getName(siteId);
        final String site = siteId;
        final NodeRef finalNodeRef = nodeRef;
        // MNT-9104 If username contains uppercase letters the action of joining a site will not be displayed in "My activities"
        if (!userNamesAreCaseSensitive) {
            userId = userId.toLowerCase();
        }
        activityPost.setUserId(userId);
        activityPost.setSiteNetwork(network);
        activityPost.setAppTool(appTool);
        activityPost.setActivityData(activityData);
        activityPost.setActivityType(activityType);
        activityPost.setPostDate(postDate);
        activityPost.setStatus(status.toString());
        activityPost.setLastModified(postDate);
        eventPublisher.publishEvent(new EventPreparator() {

            @Override
            public Event prepareEvent(String user, String networkId, String transactionId) {
                String filename = null, nodeType = null, mime = null, encoding = null;
                long size = 0l;
                String nodeId = finalNodeRef != null ? finalNodeRef.getId() : null;
                FileInfo fileInfo = contentNodeInfo;
                // Use content info
                if (fileInfo != null) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Enhancing the Activity Event with fileInfo provided for node " + nodeId);
                    }
                    if (nodeId == null) {
                        nodeId = fileInfo.getNodeRef().getId();
                    }
                    filename = fileInfo.getName();
                    nodeType = fileInfo.getType().toString();
                    if (!fileInfo.isFolder()) {
                        // It's a file so get more info
                        ContentData contentData = fileInfo.getContentData();
                        if (contentData != null) {
                            mime = contentData.getMimetype();
                            size = contentData.getSize();
                            encoding = contentData.getEncoding();
                        }
                    }
                }
                return new ActivityEvent(activityType, transactionId, networkId, user, nodeId, site, nodeType, client, activityPost.getActivityData(), filename, mime, size, encoding);
            }
        });
        // hash the userid to generate a job task node
        int nodeCount = estGridSize;
        int userHashCode = userId.hashCode();
        int nodeHash = (userHashCode % nodeCount) + 1;
        activityPost.setJobTaskNode(nodeHash);
        try {
            long postId = postDAO.insertPost(activityPost);
            if (logger.isDebugEnabled()) {
                activityPost.setId(postId);
                logger.debug("Posted: " + activityPost);
            }
        } catch (SQLException e) {
            throw new AlfrescoRuntimeException("Failed to post activity: " + e, e);
        } catch (Throwable t) {
            throw new AlfrescoRuntimeException("Failed to post activity: " + t, t);
        }
    } catch (AlfrescoRuntimeException e) {
        // log error, subsume exception (for post activity)
        logger.error(e);
    }
}
Also used : ActivityEvent(org.alfresco.sync.events.types.ActivityEvent) SQLException(java.sql.SQLException) JSONException(org.json.JSONException) ActivityPostEntity(org.alfresco.repo.domain.activities.ActivityPostEntity) Date(java.util.Date) JSONTokener(org.json.JSONTokener) NodeRef(org.alfresco.service.cmr.repository.NodeRef) EventPreparator(org.alfresco.sync.repo.events.EventPreparator) ContentData(org.alfresco.service.cmr.repository.ContentData) JSONObject(org.json.JSONObject) FileInfo(org.alfresco.service.cmr.model.FileInfo) ActivityEvent(org.alfresco.sync.events.types.ActivityEvent) Event(org.alfresco.sync.events.types.Event) AlfrescoRuntimeException(org.alfresco.error.AlfrescoRuntimeException)

Aggregations

ActivityPostEntity (org.alfresco.repo.domain.activities.ActivityPostEntity)11 SQLException (java.sql.SQLException)6 JSONObject (org.json.JSONObject)6 Date (java.util.Date)5 JSONException (org.json.JSONException)5 LockAcquisitionException (org.alfresco.repo.lock.LockAcquisitionException)4 JobExecutionException (org.quartz.JobExecutionException)4 ArrayList (java.util.ArrayList)3 List (java.util.List)3 TenantUtil (org.alfresco.repo.tenant.TenantUtil)3 NodeRef (org.alfresco.service.cmr.repository.NodeRef)3 Pair (org.alfresco.util.Pair)3 HashMap (java.util.HashMap)2 JSONTokener (org.json.JSONTokener)2 TemplateException (freemarker.template.TemplateException)1 FileNotFoundException (java.io.FileNotFoundException)1 IOException (java.io.IOException)1 MalformedURLException (java.net.MalformedURLException)1 URISyntaxException (java.net.URISyntaxException)1 HashSet (java.util.HashSet)1