/src/main/java/com/atlassian/jconnect/jira/IssueActivityService.java
Java | 188 lines | 152 code | 19 blank | 17 comment | 15 complexity | da7cd80ec3f44cfe240d1eeb28bc900c MD5 | raw file
- package com.atlassian.jconnect.jira;
-
-
- import com.atlassian.crowd.embedded.api.User;
- import com.atlassian.jconnect.jira.customfields.BuiltInField;
- import com.atlassian.jconnect.rest.entities.CommentEntity;
- import com.atlassian.jconnect.rest.entities.IssueWithCommentsEntity;
- import com.atlassian.jconnect.rest.entities.IssuesWithCommentsEntity;
- import com.atlassian.jira.bc.issue.search.SearchService;
- import com.atlassian.jira.issue.CustomFieldManager;
- import com.atlassian.jira.issue.Issue;
- import com.atlassian.jira.issue.comments.Comment;
- import com.atlassian.jira.issue.comments.CommentManager;
- import com.atlassian.jira.issue.fields.CustomField;
- import com.atlassian.jira.issue.search.SearchException;
- import com.atlassian.jira.issue.search.SearchResults;
- import com.atlassian.jira.jql.builder.JqlClauseBuilder;
- import com.atlassian.jira.jql.builder.JqlQueryBuilder;
- import com.atlassian.jira.project.Project;
- import com.atlassian.jira.web.bean.PagerFilter;
- import com.atlassian.query.Query;
- import com.atlassian.query.order.SortOrder;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
-
- import java.util.ArrayList;
- import java.util.Date;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
-
- /**
- * Retrieves recent issue activity for a remote user.
- *
- */
- public class IssueActivityService
- {
- private static final Logger log = LoggerFactory.getLogger(IssueActivityService.class);
-
- private final CommentManager commentManager;
- private final SearchService searchService;
- private final UserHelper userHelper;
- private final JMCProjectService jmcProjectService;
- private final CustomFieldManager customFieldManager;
- /** Used to ensure there is no JQL injection in the UUID. */
- private static final Pattern PATTERN_UUID = Pattern.compile("([a-fA-F-\\d]{36})");
- /** Matches a projectname such as: AngryNerds, Angry-Nerds, Angry-Nerds124*/
- private static final Pattern PATTERN_PROJECT_NAME = Pattern.compile("([a-fA-F-\\d].*)");
-
- public IssueActivityService(CommentManager commentManager,
- SearchService searchService,
- UserHelper userHelper,
- CustomFieldManager customFieldManager,
- JMCProjectService jmcProjectService)
- {
- this.commentManager = commentManager;
- this.searchService = searchService;
- this.userHelper = userHelper;
- this.customFieldManager = customFieldManager;
- this.jmcProjectService = jmcProjectService;
- }
-
- /**
- * Gets all issues (and their comments) for a particular UUID if updates exist for at least 1 issue created by
- * the UUID.
- *
- * @param project the project to get the issues for
- * @param uuid the uuid that create the issue
- * @param sinceMillis the time in millis to search for updates from
- * @return if updates exist, all issues and their comments. if no updates exist since sinceMillis, an emptyp IssuesWithCommentsEntity is returned.
- */
- public IssuesWithCommentsEntity getIssuesWithCommentsIfUpdatesExists(final Project project, final String uuid, final long sinceMillis)
- {
- final IssuesWithCommentsEntity issuesWithComments =
- new IssuesWithCommentsEntity(new ArrayList<IssueWithCommentsEntity>(),
- System.currentTimeMillis(), !jmcProjectService.isCrashesEnabledFor(project));
-
- boolean issueHasUpdates = false;
- final User user = userHelper.getJMCSystemUser();
- if (user != null)
- {
- // CHECK FOR JQL INJECTION.
- if (!isValidUserParameter(uuid, PATTERN_UUID)) {
- return issuesWithComments;
- }
- final CustomField uuidField = this.customFieldManager.getCustomFieldObjectByName(BuiltInField.UUID.fieldName());
- if (uuidField == null) {
- log.warn("Custom field: " + BuiltInField.UUID.fieldName() + " is missing from this instance. Ensure JIRA Mobile Connect is enabled.");
- return null;
- }
-
- final JqlClauseBuilder userProjectClause =
- JqlQueryBuilder.newClauseBuilder().
- project().eq(project.getId()).and().
- customField(uuidField.getIdAsLong()).eq().string(uuid).and().
- reporter().eq().string(user.getName());
-
- final JqlClauseBuilder dateClause =
- JqlQueryBuilder.newClauseBuilder().
- updated().gtEq(new Date(sinceMillis));
-
- final Query query =
- JqlQueryBuilder.newBuilder().where().
- addClause(userProjectClause.buildClause()).
- and().
- addClause(dateClause.buildClause()).buildQuery();
- try {
- final long resultCount = searchService.searchCount(user, query);
- if (resultCount > 0)
- {
- // at least 1 issue has been updated by a non-mobile user, so retrieve and resend all data.
- issueHasUpdates = retrieveIssuesWithComments(userProjectClause, sinceMillis, issuesWithComments, user);
- }
- } catch (SearchException e) {
- log.error("Error looking for updates via JQL: " + query.getWhereClause(), e);
- }
- }
- if (log.isDebugEnabled()) {
- log.debug(uuid + " issue count " + issuesWithComments.getIssues().size());
- }
- return issueHasUpdates ?
- issuesWithComments : // if there are no updates, return an empty list.
- new IssuesWithCommentsEntity(new LinkedList<IssueWithCommentsEntity>(), System.currentTimeMillis(), !jmcProjectService.isCrashesEnabledFor(project));
- }
-
- private boolean retrieveIssuesWithComments(JqlClauseBuilder builder, long sinceMillis, IssuesWithCommentsEntity issuesWithComments, User user) {
-
- final Query query = JqlQueryBuilder.newBuilder(builder.buildQuery()).
- orderBy().updatedDate(SortOrder.DESC).
- buildQuery();
- try {
- final SearchResults searchResults = searchService.search(user, query, new PagerFilter(100)); // only ever return last 100 bits of feedback.
- final List<Issue> issues = searchResults.getIssues();
- boolean hasAtLeastOneUpdate = false;
- for (Issue issue : issues) {
- final List<CommentEntity> commentEntities = new ArrayList<CommentEntity>();
- boolean hasUpdates = false;
-
- List<Comment> comments = commentManager.getCommentsForUser(issue, user);
- for (Comment comment : comments) {
- final boolean systemUser = commentManager.isUserCommentAuthor(user, comment);
- if ((comment.getUpdated().getTime() > sinceMillis) && !systemUser) {
- hasUpdates = true;
- hasAtLeastOneUpdate = true;
- }
-
- CommentEntity commentEntity = new CommentEntity(comment.getAuthor(),
- systemUser,
- comment.getBody(),
- comment.getUpdated(),
- issue.getKey());
- commentEntities.add(commentEntity);
- }
-
- IssueWithCommentsEntity issueEntity = new IssueWithCommentsEntity(issue.getKey(),
- issue.getStatusObject().getName(),
- issue.getSummary(),
- issue.getDescription(),
- issue.getCreated(),
- issue.getUpdated(),
- commentEntities,
- hasUpdates);
-
- issuesWithComments.getIssues().add(issueEntity);
- }
- if (log.isDebugEnabled())
- log.debug(query.getWhereClause() + " issue count " + issuesWithComments.getIssues().size());
- return hasAtLeastOneUpdate;
- } catch (SearchException e) {
- log.error(e.getMessage(), e);
- }
-
- return false;
- }
-
- private boolean isValidUserParameter(String userEnteredString, Pattern matchPattern) {
- if (userEnteredString == null) {
- return false;
- }
- final Matcher matcher = matchPattern.matcher(userEnteredString);
- if (!matcher.matches()) {
- log.warn(userEnteredString + " is invalid.");
- return false;
- }
- return true;
- }
- }