Package models

Source Code of models.NotificationEvent

/**
* Yobi, Project Hosting SW
*
* Copyright 2013 NAVER Corp.
* http://yobi.io
*
* @Author Yi EungJun
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package models;

import controllers.UserApp;
import controllers.routes;
import models.enumeration.*;
import models.resource.GlobalResource;
import models.resource.Resource;
import models.resource.ResourceConvertible;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.joda.time.DateTime;
import org.tmatesoft.svn.core.SVNException;
import play.api.i18n.Lang;
import play.db.ebean.Model;
import play.i18n.Messages;
import play.libs.Akka;
import playRepository.*;
import scala.concurrent.duration.Duration;
import utils.EventConstants;
import utils.RouteUtil;

import javax.naming.LimitExceededException;
import javax.persistence.*;
import javax.servlet.ServletException;
import java.io.IOException;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static models.enumeration.EventType.*;

@Entity
public class NotificationEvent extends Model {
    private static final long serialVersionUID = 1L;

    @Id
    public Long id;

    public static Finder<Long, NotificationEvent> find = new Finder<>(Long.class, NotificationEvent.class);

    public String title;

    @Lob
    public String message;

    public Long senderId;

    @ManyToMany(cascade = CascadeType.ALL)
    public Set<User> receivers;

    @Temporal(TemporalType.TIMESTAMP)
    public Date created;

    @Enumerated(EnumType.STRING)
    public ResourceType resourceType;

    public String resourceId;

    @Enumerated(EnumType.STRING)
    public EventType eventType;

    @Lob
    public String oldValue;

    @Lob
    public String newValue;

    @OneToOne(mappedBy="notificationEvent", cascade = CascadeType.ALL)
    public NotificationMail notificationMail;

    public String getOldValue() {
        return oldValue;
    }

    @Transient
    public String getMessage() {
        return getMessage(Lang.defaultLang());
    }

    @Transient
    public String getMessage(Lang lang) {
        if (message != null) {
            return message;
        }

        switch (eventType) {
            case ISSUE_STATE_CHANGED:
                if (newValue.equals(State.CLOSED.state())) {
                    return Messages.get(lang, "notification.issue.closed");
                } else {
                    return Messages.get(lang, "notification.issue.reopened");
                }
            case ISSUE_ASSIGNEE_CHANGED:
                if (newValue == null) {
                    return Messages.get(lang, "notification.issue.unassigned");
                } else {
                    return Messages.get(lang, "notification.issue.assigned", newValue);
                }
            case NEW_ISSUE:
            case NEW_POSTING:
            case NEW_COMMENT:
            case NEW_PULL_REQUEST:
            case NEW_REVIEW_COMMENT:
            case NEW_COMMIT:
            case ISSUE_BODY_CHANGED:
                return newValue;
            case PULL_REQUEST_STATE_CHANGED:
                if (State.OPEN.state().equals(newValue)) {
                    return Messages.get(lang, "notification.pullrequest.reopened");
                } else {
                    return Messages.get(lang, "notification.pullrequest." + newValue);
                }
            case PULL_REQUEST_COMMIT_CHANGED:
                return newValue;
            case PULL_REQUEST_MERGED:
                return Messages.get(lang, "notification.type.pullrequest.merged." + newValue) + "\n" + StringUtils.defaultString(oldValue, StringUtils.EMPTY);
            case MEMBER_ENROLL_REQUEST:
                if (RequestState.REQUEST.name().equals(newValue)) {
                    return Messages.get(lang, "notification.member.enroll.request");
                } else  if (RequestState.ACCEPT.name().equals(newValue)) {
                    return Messages.get(lang, "notification.member.enroll.accept");
                } else {
                    return Messages.get(lang, "notification.member.enroll.cancel");
                }
            case ORGANIZATION_MEMBER_ENROLL_REQUEST:
                if (RequestState.REQUEST.name().equals(newValue)) {
                    return Messages.get(lang, "notification.organization.member.enroll.request");
                } else  if (RequestState.ACCEPT.name().equals(newValue)) {
                    return Messages.get(lang, "notification.organization.member.enroll.accept");
                } else {
                    return Messages.get(lang, "notification.organization.member.enroll.cancel");
                }
            case PULL_REQUEST_REVIEW_STATE_CHANGED:
                if (PullRequestReviewAction.DONE.name().equals(newValue)) {
                    return Messages.get(lang, "notification.pullrequest.reviewed", User.find.byId(senderId).loginId);
                } else {
                    return Messages.get(lang, "notification.pullrequest.unreviewed", User.find.byId(senderId).loginId);
                }
            case REVIEW_THREAD_STATE_CHANGED:
                if (newValue.equals(CommentThread.ThreadState.CLOSED.name())) {
                    return Messages.get(lang, "notification.reviewthread.closed");
                } else {
                    return Messages.get(lang, "notification.reviewthread.reopened");
                }
            default:
                return null;
        }
    }

    public User getSender() {
        return User.find.byId(this.senderId);
    }

    public Resource getResource() {
        return Resource.get(resourceType, resourceId);
    }

    public Project getProject() {
        switch(resourceType) {
            case ISSUE_ASSIGNEE:
                return Assignee.finder.byId(Long.valueOf(resourceId)).project;
            case PROJECT:
                return Project.find.byId(Long.valueOf(resourceId));
            default:
                Resource resource = getResource();
                if (resource != null) {
                    if (resource instanceof GlobalResource) {
                        return null;
                    } else {
                        return resource.getProject();
                    }
                } else {
                    return null;
                }
        }
    }

    public Organization getOrganization() {
        switch (resourceType) {
            case ORGANIZATION:
                return Organization.find.byId(Long.valueOf(resourceId));
            default:
                return null;
        }
    }

    public boolean resourceExists() {
        return Resource.exists(resourceType, resourceId);
    }

    public static void add(NotificationEvent event) {
        if (event.notificationMail == null) {
            event.notificationMail = new NotificationMail();
            event.notificationMail.notificationEvent = event;
        }

        Date draftDate = DateTime.now().minusMillis(EventConstants.DRAFT_TIME_IN_MILLIS).toDate();

        NotificationEvent lastEvent = NotificationEvent.find.where()
                .eq("resourceId", event.resourceId)
                .eq("resourceType", event.resourceType)
                .gt("created", draftDate)
                .orderBy("id desc").setMaxRows(1).findUnique();

        if (lastEvent != null) {
            if (lastEvent.eventType == event.eventType &&
                    event.senderId.equals(lastEvent.senderId)) {
                // If the last event is A -> B and the current event is B -> C,
                // they are merged into the new event A -> C.
                event.oldValue = lastEvent.getOldValue();
                lastEvent.delete();

                // If the last event is A -> B and the current event is B -> A,
                // they are removed.
                if (StringUtils.equals(event.oldValue, event.newValue)) {
                    return;
                }
            }
        }

        filterReceivers(event);
        if (event.receivers.isEmpty()) {
            return;
        }
        event.save();
        event.saveManyToManyAssociations("receivers");
    }

    private static void filterReceivers(final NotificationEvent event) {
        final Project project = event.getProject();
        if (project == null) {
            return;
        }

        final Resource resource = project.asResource();
        CollectionUtils.filter(event.receivers, new Predicate() {
            @Override
            public boolean evaluate(Object obj) {
                User receiver = (User) obj;
                if(receiver.loginId == null) {
                    return false;
                }

                if (!Watch.isWatching(receiver, resource)) {
                    return true;
                }
                return UserProjectNotification.isEnabledNotiType(receiver, project, event.eventType);
            }
        });
    }

    public static void deleteBy(Resource resource) {
        for (NotificationEvent event : NotificationEvent.find.where().where().eq("resourceType",
                resource.getType()).eq("resourceId", resource.getId()).findList()) {
            event.delete();
        }
    }

    /**
     * @see {@link controllers.PullRequestApp#newPullRequest(String, String)}
     */
    public static NotificationEvent afterNewPullRequest(User sender, PullRequest pullRequest) {
        NotificationEvent notiEvent = createFrom(sender, pullRequest);
        notiEvent.title = formatNewTitle(pullRequest);
        notiEvent.receivers = getReceiversWithRelatedAuthors(sender, pullRequest);
        notiEvent.eventType = NEW_PULL_REQUEST;
        notiEvent.oldValue = null;
        notiEvent.newValue = pullRequest.body;
        NotificationEvent.add(notiEvent);
        return notiEvent;
    }

    public String getUrlToView() {
        switch(eventType) {
            case MEMBER_ENROLL_REQUEST:
                if (getProject() == null) {
                    return null;
                } else {
                    return routes.ProjectApp.members(
                            getProject().owner, getProject().name).url();
                }
            case ORGANIZATION_MEMBER_ENROLL_REQUEST:
                Organization organization = getOrganization();
                if (organization == null) {
                    return null;
                }
                return routes.OrganizationApp.members(organization.name).url();

            case NEW_COMMIT:
                if (getProject() == null) {
                    return null;
                } else {
                    return routes.CodeHistoryApp.historyUntilHead(
                            getProject().owner, getProject().name).url();
                }
            default:
                return RouteUtil.getUrl(resourceType, resourceId);
        }
    }


    /**
     * @see {@link models.PullRequest#merge(models.PullRequestEventMessage)}
     * @see {@link controllers.PullRequestApp#addNotification(models.PullRequest, models.enumeration.State, models.enumeration.State)}
     */
    public static NotificationEvent afterPullRequestUpdated(User sender, PullRequest pullRequest, State oldState, State newState) {
        NotificationEvent notiEvent = createFrom(sender, pullRequest);
        notiEvent.title = formatReplyTitle(pullRequest);
        notiEvent.receivers = getReceivers(sender, pullRequest);
        notiEvent.eventType = PULL_REQUEST_STATE_CHANGED;
        notiEvent.oldValue = oldState.state();
        notiEvent.newValue = newState.state();
        NotificationEvent.add(notiEvent);
        return notiEvent;
    }

    /**
     * @see {@link actors.PullRequestActor#processPullRequestMerging(models.PullRequestEventMessage, models.PullRequest)}
     */
    public static NotificationEvent afterMerge(User sender, PullRequest pullRequest, GitConflicts conflicts, State state) {
        NotificationEvent notiEvent = createFrom(sender, pullRequest);
        notiEvent.title = formatReplyTitle(pullRequest);
        notiEvent.receivers = state == State.MERGED ? getReceiversWithRelatedAuthors(sender, pullRequest) : getReceivers(sender, pullRequest);
        notiEvent.eventType = PULL_REQUEST_MERGED;
        notiEvent.newValue = state.state();
        if (conflicts != null) {
            notiEvent.oldValue = StringUtils.join(conflicts.conflictFiles, "\n");
        }
        NotificationEvent.add(notiEvent);
        return notiEvent;
    }

    /**
     * @see {@link controllers.PullRequestApp#newComment(String, String, Long, String)}
     */
    public static void afterNewComment(User sender, PullRequest pullRequest,
                                       ReviewComment newComment, String urlToView) {
        NotificationEvent notiEvent = createFrom(sender, newComment);
        notiEvent.title = formatReplyTitle(pullRequest);
        Set<User> receivers = getMentionedUsers(newComment.getContents());
        receivers.addAll(getReceivers(sender, pullRequest));
        receivers.remove(User.findByLoginId(newComment.author.loginId));
        notiEvent.receivers = receivers;
        notiEvent.eventType = NEW_REVIEW_COMMENT;
        notiEvent.oldValue = null;
        notiEvent.newValue = newComment.getContents();

        NotificationEvent.add(notiEvent);
    }

    public static NotificationEvent afterNewPullRequest(PullRequest pullRequest) {
        return afterNewPullRequest(UserApp.currentUser(), pullRequest);
    }

    public static NotificationEvent afterPullRequestUpdated(PullRequest pullRequest, State oldState, State newState) {
        return afterPullRequestUpdated(UserApp.currentUser(), pullRequest, oldState, newState);
    }

    public static void afterNewComment(Comment comment) {
        AbstractPosting post = comment.getParent();

        NotificationEvent notiEvent = createFromCurrentUser(comment);
        notiEvent.title = formatReplyTitle(post);
        Set<User> receivers = getReceivers(post);
        receivers.addAll(getMentionedUsers(comment.contents));
        receivers.remove(UserApp.currentUser());
        notiEvent.receivers = receivers;
        notiEvent.eventType = NEW_COMMENT;
        notiEvent.oldValue = null;
        notiEvent.newValue = comment.contents;
        notiEvent.resourceType = comment.asResource().getType();
        notiEvent.resourceId = comment.asResource().getId();

        NotificationEvent.add(notiEvent);
    }

    public static void afterNewCommentWithState(Comment comment, State state) {
        AbstractPosting post = comment.getParent();

        NotificationEvent notiEvent = createFromCurrentUser(comment);
        notiEvent.title = formatReplyTitle(post);
        Set<User> receivers = getReceivers(post);
        receivers.addAll(getMentionedUsers(comment.contents));
        receivers.remove(UserApp.currentUser());
        notiEvent.receivers = receivers;
        notiEvent.eventType = NEW_COMMENT;
        notiEvent.oldValue = null;
        notiEvent.newValue = comment.contents + "\n" + state.state();
        notiEvent.resourceType = comment.asResource().getType();
        notiEvent.resourceId = comment.asResource().getId();

        NotificationEvent.add(notiEvent);
    }

    public static NotificationEvent afterStateChanged(State oldState, Issue issue) {
        NotificationEvent notiEvent = createFromCurrentUser(issue);
        notiEvent.title = formatReplyTitle(issue);
        notiEvent.receivers = getReceivers(issue);
        notiEvent.eventType = ISSUE_STATE_CHANGED;
        notiEvent.oldValue = oldState != null ? oldState.state() : null;
        notiEvent.newValue = issue.state.state();

        NotificationEvent.add(notiEvent);

        return notiEvent;
    }

    public static NotificationEvent afterStateChanged(
            CommentThread.ThreadState oldState, CommentThread thread)
            throws IOException, SVNException, ServletException {
        NotificationEvent notiEvent = createFromCurrentUser(thread);

        notiEvent.eventType = REVIEW_THREAD_STATE_CHANGED;
        notiEvent.oldValue = oldState.name() != null ? oldState.name() : null;
        notiEvent.newValue = thread.state.name();

        // Set receivers
        Set<User> receivers;
        if (thread.isOnPullRequest()) {
            PullRequest pullRequest = thread.pullRequest;
            notiEvent.title = formatReplyTitle(pullRequest);
            receivers = pullRequest.getWatchers();
        } else {
            String commitId;
            if (thread instanceof CodeCommentThread) {
                commitId = ((CodeCommentThread)thread).commitId;
            } else {
                commitId = ((NonRangedCodeCommentThread)thread).commitId;
            }
            Project project = thread.project;
            Commit commit = RepositoryService.getRepository(project).getCommit(commitId);
            notiEvent.title = formatReplyTitle(project, commit);
            receivers = commit.getWatchers(project);
        }
        receivers.remove(UserApp.currentUser());
        notiEvent.receivers = receivers;

        NotificationEvent.add(notiEvent);

        return notiEvent;
    }



    public static NotificationEvent afterAssigneeChanged(User oldAssignee, Issue issue) {
        NotificationEvent notiEvent = createFromCurrentUser(issue);

        Set<User> receivers = getReceivers(issue);
        if(oldAssignee != null) {
            notiEvent.oldValue = oldAssignee.loginId;
            if(!oldAssignee.loginId.equals(UserApp.currentUser().loginId)) {
                receivers.add(oldAssignee);
            }
        }

        if (issue.assignee != null) {
            notiEvent.newValue = User.find.byId(issue.assignee.user.id).loginId;
        }
        notiEvent.title = formatReplyTitle(issue);
        notiEvent.receivers = receivers;
        notiEvent.eventType = ISSUE_ASSIGNEE_CHANGED;

        NotificationEvent.add(notiEvent);

        return notiEvent;
    }

    public static void afterNewIssue(Issue issue) {
        NotificationEvent notiEvent = createFromCurrentUser(issue);
        notiEvent.title = formatNewTitle(issue);
        notiEvent.receivers = getReceivers(issue);
        notiEvent.eventType = NEW_ISSUE;
        notiEvent.oldValue = null;
        notiEvent.newValue = issue.body;

        NotificationEvent.add(notiEvent);
    }

    public static NotificationEvent afterIssueBodyChanged(String oldBody, Issue issue) {
        NotificationEvent notiEvent = createFromCurrentUser(issue);
        notiEvent.title = formatReplyTitle(issue);
        notiEvent.receivers = getReceivers(issue);
        notiEvent.eventType = EventType.ISSUE_BODY_CHANGED;
        notiEvent.oldValue = oldBody;
        notiEvent.newValue = issue.body;

        NotificationEvent.add(notiEvent);

        return notiEvent;
    }

    public static void afterNewPost(Posting post) {
        NotificationEvent notiEvent = createFromCurrentUser(post);
        notiEvent.title = formatNewTitle(post);
        notiEvent.receivers = getReceivers(post);
        notiEvent.eventType = NEW_POSTING;
        notiEvent.oldValue = null;
        notiEvent.newValue = post.body;

        NotificationEvent.add(notiEvent);
    }

    public static void afterNewCommitComment(Project project, ReviewComment comment,
                                             String commitId) throws
            IOException, SVNException, ServletException {
        Commit commit = RepositoryService.getRepository(project).getCommit(commitId);
        Set<User> watchers = commit.getWatchers(project);
        watchers.addAll(getMentionedUsers(comment.getContents()));
        watchers.remove(UserApp.currentUser());

        NotificationEvent notiEvent = createFromCurrentUser(comment);
        notiEvent.title = formatReplyTitle(project, commit);
        notiEvent.receivers = watchers;
        notiEvent.eventType = NEW_COMMENT;
        notiEvent.oldValue = null;
        notiEvent.newValue = comment.getContents();

        NotificationEvent.add(notiEvent);
    }

    public static void afterNewSVNCommitComment(Project project, CommitComment codeComment) throws IOException, SVNException, ServletException {
        Commit commit = RepositoryService.getRepository(project).getCommit(codeComment.commitId);
        Set<User> watchers = commit.getWatchers(project);
        watchers.addAll(getMentionedUsers(codeComment.contents));
        watchers.remove(UserApp.currentUser());

        NotificationEvent notiEvent = createFromCurrentUser(codeComment);
        notiEvent.title = formatReplyTitle(project, commit);
        notiEvent.receivers = watchers;
        notiEvent.eventType = NEW_COMMENT;
        notiEvent.oldValue = null;
        notiEvent.newValue = codeComment.contents;

        NotificationEvent.add(notiEvent);
    }

    public static void afterMemberRequest(Project project, User user, RequestState state) {
        NotificationEvent notiEvent = createFromCurrentUser(project);
        notiEvent.eventType = MEMBER_ENROLL_REQUEST;
        notiEvent.receivers = getReceivers(project);
        notiEvent.newValue = state.name();
        if (state == RequestState.ACCEPT || state == RequestState.REJECT) {
            notiEvent.receivers.remove(UserApp.currentUser());
            notiEvent.receivers.add(user);
        }

        switch (state) {
            case REQUEST:
                notiEvent.title = formatMemberRequestTitle(project, user);
                notiEvent.oldValue = RequestState.CANCEL.name();
                break;
            case CANCEL:
                notiEvent.title = formatMemberRequestCancelTitle(project, user);
                notiEvent.oldValue = RequestState.REQUEST.name();
                break;
            case ACCEPT:
                notiEvent.title = formatMemberAcceptTitle(project, user);
                notiEvent.oldValue = RequestState.REQUEST.name();
                break;
        }

        notiEvent.resourceType = project.asResource().getType();
        notiEvent.resourceId = project.asResource().getId();
        NotificationEvent.add(notiEvent);
    }

    public static void afterOrganizationMemberRequest(Organization organization, User user, RequestState state) {
        NotificationEvent notiEvent = createFromCurrentUser(organization);
        notiEvent.eventType = ORGANIZATION_MEMBER_ENROLL_REQUEST;
        notiEvent.receivers = getReceivers(organization);
        notiEvent.newValue = state.name();
        if (state == RequestState.ACCEPT || state == RequestState.REJECT) {
            notiEvent.receivers.remove(UserApp.currentUser());
            notiEvent.receivers.add(user);
        }

        switch (state) {
            case REQUEST:
                notiEvent.title = formatMemberRequestTitle(organization, user);
                notiEvent.oldValue = RequestState.CANCEL.name();
                break;
            case CANCEL:
                notiEvent.title = formatMemberRequestCancelTitle(organization, user);
                notiEvent.oldValue = RequestState.REQUEST.name();
                break;
            case ACCEPT:
                notiEvent.title = formatMemberAcceptTitle(organization, user);
                notiEvent.oldValue = RequestState.REQUEST.name();
                break;
        }

        notiEvent.resourceType = organization.asResource().getType();
        notiEvent.resourceId = organization.asResource().getId();
        NotificationEvent.add(notiEvent);
    }

    public static void afterNewCommits(List<RevCommit> commits, List<String> refNames, Project project, User sender, String title, Set<User> watchers) {
        NotificationEvent notiEvent = createFrom(sender, project);
        notiEvent.title = title;
        notiEvent.receivers = watchers;
        notiEvent.eventType = NEW_COMMIT;
        notiEvent.oldValue = null;
        notiEvent.newValue = newCommitsMessage(commits, refNames, project);
        notiEvent.resourceType = project.asResource().getType();
        notiEvent.resourceId = project.asResource().getId();
        NotificationEvent.add(notiEvent);
    }

    public static NotificationEvent afterReviewed(PullRequest pullRequest, PullRequestReviewAction reviewAction) {
        String title = formatReplyTitle(pullRequest);
        Resource resource = pullRequest.asResource();
        Set<User> receivers = pullRequest.getWatchers();
        receivers.add(pullRequest.contributor);
        User reviewer = UserApp.currentUser();
        receivers.remove(reviewer);

        NotificationEvent notiEvent = new NotificationEvent();
        notiEvent.created = new Date();
        notiEvent.title = title;
        notiEvent.senderId = reviewer.id;
        notiEvent.receivers = receivers;
        notiEvent.resourceId = resource.getId();
        notiEvent.resourceType = resource.getType();
        notiEvent.eventType = EventType.PULL_REQUEST_REVIEW_STATE_CHANGED;
        notiEvent.oldValue = reviewAction.getOppositAction().name();
        notiEvent.newValue = reviewAction.name();

        add(notiEvent);

        return notiEvent;
    }

    private static String newCommitsMessage(List<RevCommit> commits, List<String> refNames, Project project) {
        StringBuilder result = new StringBuilder();

        if(commits.size() > 0) {
            result.append("New Commits: \n");
            for(RevCommit commit : commits) {
                GitCommit gitCommit = new GitCommit(commit);
                result.append(gitCommit.getShortId());
                result.append(" ");
                result.append(gitCommit.getShortMessage());
                result.append("\n");
            }
        }

        if(refNames.size() > 0) {
            result.append("Branches: \n");
            for(String refName: refNames) {
                result.append(refName);
                result.append("\n");
            }
        }

        return result.toString();
    }

    private static NotificationEvent createFrom(User sender, ResourceConvertible rc) {
        NotificationEvent notiEvent = new NotificationEvent();
        notiEvent.senderId = sender.id;
        notiEvent.created = new Date();
        Resource resource = rc.asResource();
        notiEvent.resourceId = resource.getId();
        notiEvent.resourceType = resource.getType();
        return notiEvent;
    }

    /**
     * @see {@link #createFrom(models.User, models.resource.ResourceConvertible)}
     */
    private static NotificationEvent createFromCurrentUser(ResourceConvertible rc) {
        return createFrom(UserApp.currentUser(), rc);
    }

    private static Set<User> getReceivers(AbstractPosting abstractPosting) {
        Set<User> receivers = abstractPosting.getWatchers();
        receivers.addAll(getMentionedUsers(abstractPosting.body));
        receivers.remove(UserApp.currentUser());
        return receivers;
    }

    private static String getPrefixedNumber(AbstractPosting posting) {
        if (posting instanceof Issue) {
            return "#" + posting.getNumber();
        } else {
            return posting.getNumber().toString();
        }
    }

    private static String formatReplyTitle(AbstractPosting posting) {
        return String.format("Re: [%s] %s (%s)",
                posting.project.name, posting.title, getPrefixedNumber(posting));
    }

    private static String formatNewTitle(AbstractPosting posting) {
        return String.format("[%s] %s (%s)",
                posting.project.name, posting.title, getPrefixedNumber(posting));
    }

    private static String formatReplyTitle(Project project, Commit commit) {
        return String.format("Re: [%s] %s (%s)",
                project.name, commit.getShortMessage(), commit.getShortId());
    }

    private static Set<User> getReceivers(User sender, PullRequest pullRequest) {
        Set<User> watchers = getDefaultReceivers(pullRequest);
        watchers.remove(sender);
        return watchers;
    }

    private static Set<User> getDefaultReceivers(PullRequest pullRequest) {
        Set<User> watchers = pullRequest.getWatchers();
        watchers.addAll(getMentionedUsers(pullRequest.body));
        return watchers;
    }

    private static Set<User> getReceiversWithRelatedAuthors(User sender, PullRequest pullRequest) {
        Set<User> receivers = getDefaultReceivers(pullRequest);
        String failureMessage =
                "Failed to get authors related to the pullrequest " + pullRequest;
        try {
            Repository clonedRepository = GitRepository.buildMergingRepository(pullRequest);

            if (pullRequest.mergedCommitIdFrom != null
                    && pullRequest.mergedCommitIdTo != null) {
                receivers.addAll(GitRepository.getRelatedAuthors(
                        clonedRepository,
                        pullRequest.mergedCommitIdFrom,
                        pullRequest.mergedCommitIdTo));
            }
        } catch (LimitExceededException e) {
            for (ProjectUser member : pullRequest.toProject.members()) {
                receivers.add(member.user);
            }
            play.Logger.info(failureMessage
                    + ": Get all project members instead", e);
        } catch (GitAPIException e) {
            play.Logger.warn(failureMessage, e);
        } catch (IOException e) {
            play.Logger.warn(failureMessage, e);
        }
        receivers.remove(sender);
        return receivers;
    }

    private static String formatNewTitle(PullRequest pullRequest) {
        return String.format("[%s] %s (#%d)",
                pullRequest.toProject.name, pullRequest.title, pullRequest.number);
    }

    private static String formatReplyTitle(PullRequest pullRequest) {
        return String.format("Re: [%s] %s (#%s)",
                pullRequest.toProject.name, pullRequest.title, pullRequest.number);
    }

    private static Set<User> getReceivers(Project project) {
        Set<User> receivers = new HashSet<>();
        List<User> managers = User.findUsersByProject(project.id, RoleType.MANAGER);
        for (User manager : managers) {
            if (Watch.isWatching(manager, project.asResource())) {
                receivers.add(manager);
            }
        }
        return receivers;
    }

    private static Set<User> getReceivers(Organization organization) {
        Set<User> receivers = new HashSet<>();
        List<User> managers = User.findUsersByOrganization(organization.id, RoleType.ORG_ADMIN);
        receivers.addAll(managers);

        return receivers;
    }

    private static String formatMemberRequestTitle(Project project, User user) {
        return Messages.get("notification.member.request.title", project.name, user.loginId);
    }

    private static String formatMemberRequestCancelTitle(Project project, User user) {
        return Messages.get("notification.member.request.cancel.title", project.name, user.loginId);
    }

    private static String formatMemberRequestCancelTitle(Organization organization, User user) {
        return Messages.get("notification.member.request.cancel.title", organization.name, user.loginId);
    }

    private static String formatMemberRequestTitle(Organization organization, User user) {
        return Messages.get("notification.organization.member.request.title", organization.name, user.loginId);
    }

    private static String formatMemberAcceptTitle(Project project, User user) {
        return Messages.get("notification.member.request.accept.title", project.name, user.loginId);
    }

    private static String formatMemberAcceptTitle(Organization organization, User user) {
        return Messages.get("notification.member.request.accept.title", organization.name, user.loginId);
    }

    public static Set<User> getMentionedUsers(String body) {
        Matcher matcher = Pattern.compile("@" + User.LOGIN_ID_PATTERN_ALLOW_FORWARD_SLASH).matcher(body);
        Set<User> users = new HashSet<>();
        while(matcher.find()) {
            String mentionWord = matcher.group().substring(1);
            users.addAll(findOrganizationMembers(mentionWord));
            users.addAll(findProjectMembers(mentionWord));
            users.add(User.findByLoginId(mentionWord));
        }
        users.remove(User.anonymous);
        return users;
    }

    private static Set<User> findOrganizationMembers(String mentionWord) {
        Set<User> users = new HashSet<>();
        Organization org = Organization.findByName(mentionWord);
        if (org != null) {
            for (OrganizationUser orgUser : org.users) {
                users.add(orgUser.user);
            }
        }
        return users;
    }

    private static Set<User> findProjectMembers(String mentionWord) {
        Set<User> users = new HashSet<>();
        if(mentionWord.contains("/")){
            String projectName = mentionWord.substring(mentionWord.lastIndexOf("/")+1);
            String loginId = mentionWord.substring(0, mentionWord.lastIndexOf("/"));
            Project mentionedProject = Project.findByOwnerAndProjectName(loginId, projectName);
            if(mentionedProject == null) {
                return users;
            }
            for(ProjectUser projectUser: mentionedProject.members() ){
                users.add(projectUser.user);
            }
        }
        return users;
    }

    public static void scheduleDeleteOldNotifications() {
        if (EventConstants.KEEP_TIME_IN_DAYS > 0) {
            Akka.system().scheduler().schedule(
                Duration.create(1, TimeUnit.MINUTES),
                Duration.create(1, TimeUnit.DAYS),
                new Runnable() {
                    @Override
                    public void run() {
                        Date threshold = DateTime.now()
                                .minusDays(EventConstants.KEEP_TIME_IN_DAYS).toDate();
                        List<NotificationEvent> olds = find.where().lt("created", threshold).findList();

                        for (NotificationEvent old : olds) {
                            old.delete();
                        }
                    }
                },
                Akka.system().dispatcher()
           );
        }
    }

    public static void onStart() {
        scheduleDeleteOldNotifications();
    }

    public static List<NotificationEvent> findByReceiver(User user, int from, int size) {
        return find.where().eq("receivers.id", user.id)
                .order().desc("created")
                .setFirstRow(from).setMaxRows(size).findList();
    }
}
TOP

Related Classes of models.NotificationEvent

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.