private void onCommentChanged(GwtConversation conversation, Comment comment, Map properties) { conversation.getProject().updateHomepage(comment.getParent(), false); if (comment.isPublished() && properties.containsKey("published")) { subscriptionService.notifySubscribers( comment.getParent(), "New comment posted by " + comment.getAuthorLabel(), conversation.getProject(), null); } }
@Override public void onPublishRelease(GwtConversation conversation, String releaseId) { Project project = conversation.getProject(); Release release = (Release) getDaoService().getEntityById(releaseId); if (!release.isProject(project)) throw new PermissionDeniedException(); release.release(project, conversation.getSession().getUser(), webApplication); }
private void onTaskChanged(GwtConversation conversation, Task task, Map properties) { // update sprint day snapshot after change conversation .getProject() .getCurrentSprint() .getDaySnapshot(Date.today()) .updateWithCurrentSprint(); Requirement requirement = task.getRequirement(); if (requirement.isInCurrentSprint()) { User currentUser = conversation.getSession().getUser(); if (task.isClosed() && properties.containsKey("remainingWork")) { String event = currentUser.getName() + " closed " + task.getReferenceAndLabel(); if (requirement.isTasksClosed()) { event += ", all tasks closed in " + requirement.getReferenceAndLabel(); } postProjectEvent(conversation, event, task); } else if (task.isOwnerSet() && properties.containsKey("ownerId")) { postProjectEvent( conversation, currentUser.getName() + " claimed " + task.getReferenceAndLabel(), task); } if (!task.isOwnerSet() && properties.containsKey("ownerId")) { postProjectEvent( conversation, currentUser.getName() + " unclaimed " + task.getReferenceAndLabel(), task); } if (!task.isClosed() && requirement.isRejectDateSet()) { requirement.setRejectDate(null); sendToClients(conversation, requirement); } } }
@Override public void onRequestReleaseIssues(GwtConversation conversation, String releaseId) { assertProjectSelected(conversation); Project project = conversation.getProject(); Release release = releaseDao.getById(releaseId); if (!release.isProject(project)) throw new PermissionDeniedException(); conversation.sendToClient(release.getIssues()); }
@Override public void onSearch(GwtConversation conversation, String text) { Project project = conversation.getProject(); if (project == null) return; List<AEntity> foundEntities = project.search(text); log.debug("Found entities for search", "\"" + text + "\"", "->", foundEntities); conversation.sendToClient(foundEntities); }
@Override public void onRequestRequirementEstimationVotes( GwtConversation conversation, String requirementId) { assertProjectSelected(conversation); Project project = conversation.getProject(); Requirement requirement = requirementDao.getById(requirementId); if (!requirement.isProject(project)) throw new PermissionDeniedException(); conversation.sendToClient(requirement.getEstimationVotes()); }
@Override public void onCloseProject(GwtConversation conversation) { Project project = conversation.getProject(); if (project != null && conversation.getSession().getGwtConversations().size() < 2) { ProjectUserConfig config = project.getUserConfig(conversation.getSession().getUser()); config.reset(); sendToClients(conversation, config); } conversation.clearRemoteEntities(); conversation.setProject(null); }
@Override public void onActivateRequirementEstimationVoting( GwtConversation conversation, String requirementId) { Requirement requirement = requirementDao.getById(requirementId); if (requirement == null || !requirement.isProject(conversation.getProject())) throw new PermissionDeniedException(); requirement.initializeEstimationVotes(); requirement.setWorkEstimationVotingActive(true); requirement.setWorkEstimationVotingShowoff(false); sendToClients(conversation, requirement); sendToClients(conversation, requirement.getEstimationVotes()); }
@Override public void onRequestHistory(GwtConversation conversation) { assertProjectSelected(conversation); Project project = conversation.getProject(); Set<SprintReport> reports = project.getSprintReports(); Set<AEntity> entities = new HashSet<AEntity>(); entities.addAll(reports); for (SprintReport report : reports) { entities.addAll(getAssociatedEntities(report)); } conversation.sendToClient(entities); }
private void postProjectEvent(GwtConversation conversation, String message, AEntity subject) { assertProjectSelected(conversation); Project project = conversation.getProject(); webApplication.postProjectEvent(project, message, subject); try { sendProjectEventEmails( message, subject, project, conversation.getSession().getUser().getEmail()); } catch (Throwable ex) { log.error("Sending project event notification emails failed.", ex); } }
@Override public void onRequestEntityByReference(GwtConversation conversation, String reference) { assertProjectSelected(conversation); Project project = conversation.getProject(); AEntity entity = project.getEntityByReference(reference); if (entity == null) { log.info("Requested entity not found:", reference); } else { conversation.sendToClient(entity); conversation.sendToClient(getAssociatedEntities(entity)); } }
@Override public void onDeleteEntity(GwtConversation conversation, String entityId) { AEntity entity = getDaoService().getEntityById(entityId); User user = conversation.getSession().getUser(); if (!Auth.isDeletable(entity, user)) throw new PermissionDeniedException(); if (entity instanceof File) { File file = (File) entity; file.deleteFile(); } if (entity instanceof Task) { // update sprint day snapshot before delete conversation .getProject() .getCurrentSprint() .getDaySnapshot(Date.today()) .updateWithCurrentSprint(); } ADao dao = getDaoService().getDao(entity); dao.deleteEntity(entity); if (entity instanceof Task) onTaskDeleted(conversation, (Task) entity); Project project = conversation.getProject(); if (project != null) { for (GwtConversation c : webApplication.getConversationsByProject(project, conversation)) { c.getNextData().addDeletedEntity(entityId); } } if (user != null && project != null) { ProjectUserConfig config = project.getUserConfig(user); config.touch(); sendToClients(conversation, config); } }
@Override public void onRequestForum(GwtConversation conversation, boolean all) { Project project = conversation.getProject(); Set<AEntity> parents = new HashSet<AEntity>(); for (Subject subject : project.getSubjects()) { if (subject.getComments().isEmpty()) parents.add(subject); } for (Comment comment : project.getLatestComments()) { AEntity parent = comment.getParent(); if (!all && !conversation.isAvailableOnClient(parent) && comment.getDateAndTime().getPeriodToNow().abs().toDays() > 7) continue; conversation.sendToClient(comment); parents.add(parent); } conversation.sendToClient(parents); }
private void onTaskDeleted(GwtConversation conversation, Task task) { // update sprint day snapshot after delete conversation .getProject() .getCurrentSprint() .getDaySnapshot(Date.today()) .updateWithCurrentSprint(); Requirement requirement = task.getRequirement(); if (requirement.isInCurrentSprint()) { if (task.isOwnerSet()) { postProjectEvent( conversation, conversation.getSession().getUser().getName() + " deleted " + task.getReferenceAndLabel(), task); } } }
@Override public void onPullStoryToSprint(GwtConversation conversation, String storyId) { assertProjectSelected(conversation); Requirement story = requirementDao.getById(storyId); Project project = conversation.getProject(); Sprint sprint = project.getCurrentSprint(); User currentUser = conversation.getSession().getUser(); sprint.pullRequirement(story, currentUser); postProjectEvent( conversation, currentUser.getName() + " pulled " + story.getReferenceAndLabel() + " to current sprint", story); sendToClients(conversation, sprint); sendToClients(conversation, story); sendToClients(conversation, story.getTasksInSprint()); }
@Override public void onSwitchToNextSprint(GwtConversation conversation) { assertProjectSelected(conversation); Project project = conversation.getProject(); Sprint oldSprint = project.getCurrentSprint(); for (Requirement requirement : oldSprint.getRequirements()) { if (!requirement.isClosed()) { requirement.setDirty(true); sendToClients(conversation, requirement); } } Sprint newSprint = project.switchToNextSprint(); postProjectEvent( conversation, conversation.getSession().getUser() + " switched to next sprint ", newSprint); sendToClients(conversation, project.getSprints()); sendToClients(conversation, project.getSprintReports()); sendToClients(conversation, project.getRequirements()); sendToClients(conversation, project.getTasks()); // TODO optimize: no history tasks sendToClients(conversation, oldSprint.getReleases()); sendToClients(conversation, project); }
@Override public void onConvertIssueToStory(GwtConversation conversation, String issueId) { Issue issue = issueDao.getById(issueId); Requirement story = requirementDao.postRequirement(issue); issue.appendToStatement("Created Story " + story.getReference() + " in Product Backlog."); issue.setCloseDate(Date.today()); sendToClients(conversation, story); sendToClients(conversation, issue); User currentUser = conversation.getSession().getUser(); postProjectEvent( conversation, currentUser.getName() + " created " + story.getReference() + " from " + issue.getReferenceAndLabel(), issue); changeDao.postChange(issue, currentUser, "storyId", null, story.getId()); changeDao.postChange(story, currentUser, "issueId", null, issue.getId()); subscriptionService.copySubscribers(issue, story); subscriptionService.notifySubscribers( story, "Story created from " + issue, conversation.getProject(), null); }
@Override public void onSendIssueReplyEmail( GwtConversation conversation, String issueId, String from, String to, String subject, String text) { assertProjectSelected(conversation); Issue issue = issueDao.getById(issueId); if (Str.isEmail(from)) { emailSender.sendEmail(conversation.getProject(), to, subject, text); } else { emailSender.sendEmail(from, to, subject, text); } User user = conversation.getSession().getUser(); postProjectEvent( conversation, user.getName() + " emailed a response to " + issue.getReferenceAndLabel(), issue); Change change = changeDao.postChange(issue, user, "@reply", null, text); conversation.sendToClient(change); }
private void assertProjectSelected(GwtConversation conversation) { if (conversation.getProject() == null) throw new RuntimeException("No project selected."); }
@Override public void onCreateEntity(GwtConversation conversation, String type, Map properties) { String id = (String) properties.get("id"); if (id == null) throw new NullPointerException("id == null"); ADao dao = getDaoService().getDaoByName(type); AEntity entity = dao.newEntityInstance(id); entity.updateProperties(properties); User currentUser = conversation.getSession().getUser(); Project currentProject = conversation.getProject(); if (entity instanceof Numbered) { ((Numbered) entity).updateNumber(); } if (entity instanceof Project) { Project project = (Project) entity; project.addParticipant(currentUser); project.addAdmin(currentUser); project.addProductOwner(currentUser); project.addScrumMaster(currentUser); project.addTeamMember(currentUser); } if (entity instanceof Comment) { Comment comment = (Comment) entity; comment.setDateAndTime(DateAndTime.now()); postProjectEvent( conversation, comment.getAuthor().getName() + " commented on " + comment.getParent(), comment.getParent()); currentProject.updateHomepage(comment.getParent(), true); } if (entity instanceof ChatMessage) { ChatMessage chatMessage = (ChatMessage) entity; chatMessage.setDateAndTime(DateAndTime.now()); } if (entity instanceof Impediment) { Impediment impediment = (Impediment) entity; impediment.setDate(Date.today()); } if (entity instanceof Issue) { Issue issue = (Issue) entity; issue.setDate(DateAndTime.now()); issue.setCreator(currentUser); } if (entity instanceof Task) { Task task = (Task) entity; Requirement requirement = task.getRequirement(); requirement.setRejectDate(null); requirement.setClosed(false); sendToClients(conversation, requirement); } if (entity instanceof BlogEntry) { BlogEntry blogEntry = (BlogEntry) entity; blogEntry.setDateAndTime(DateAndTime.now()); blogEntry.addAuthor(currentUser); } if (entity instanceof Change) { Change change = (Change) entity; change.setDateAndTime(DateAndTime.now()); change.setUser(currentUser); } if (!(entity instanceof Transient)) dao.saveEntity(entity); sendToClients(conversation, entity); if (entity instanceof Requirement) { Requirement requirement = (Requirement) entity; Requirement epic = requirement.getEpic(); String value = null; if (epic != null) { value = epic.getReferenceAndLabel(); Change change = changeDao.postChange(epic, currentUser, "@split", null, requirement.getReference()); conversation.sendToClient(change); } Change change = changeDao.postChange(requirement, currentUser, "@created", null, value); conversation.sendToClient(change); } if (entity instanceof Task || entity instanceof Wikipage || entity instanceof Risk || entity instanceof Impediment || entity instanceof Issue || entity instanceof BlogEntry) { Change change = changeDao.postChange(entity, currentUser, "@created", null, null); conversation.sendToClient(change); } if (currentUser != null && currentProject != null) { ProjectUserConfig config = currentProject.getUserConfig(currentUser); config.touch(); sendToClients(conversation, config); } }
@Override public void onChangeProperties(GwtConversation conversation, String entityId, Map properties) { AEntity entity = getDaoService().getEntityById(entityId); User currentUser = conversation.getSession().getUser(); if (!Auth.isEditable(entity, currentUser)) throw new PermissionDeniedException(); Sprint previousRequirementSprint = entity instanceof Requirement ? ((Requirement) entity).getSprint() : null; if (entity instanceof Requirement) { postChangeIfChanged(conversation, entity, properties, currentUser, "label"); postChangeIfChanged(conversation, entity, properties, currentUser, "description"); postChangeIfChanged(conversation, entity, properties, currentUser, "testDescription"); postChangeIfChanged(conversation, entity, properties, currentUser, "sprintId"); postChangeIfChanged(conversation, entity, properties, currentUser, "closed"); postChangeIfChanged(conversation, entity, properties, currentUser, "issueId"); } Project project = conversation.getProject(); if (entity instanceof Task) { // update sprint day snapshot before change if (project.isCurrentSprintSet()) project.getCurrentSprint().getDaySnapshot(Date.today()).updateWithCurrentSprint(); postChangeIfChanged(conversation, entity, properties, currentUser, "label"); postChangeIfChanged(conversation, entity, properties, currentUser, "description"); } if (entity instanceof Wikipage) { postChangeIfChanged(conversation, entity, properties, currentUser, "text"); } if (entity instanceof Risk) { postChangeIfChanged(conversation, entity, properties, currentUser, "description"); postChangeIfChanged(conversation, entity, properties, currentUser, "probability"); postChangeIfChanged(conversation, entity, properties, currentUser, "impact"); postChangeIfChanged(conversation, entity, properties, currentUser, "probabilityMitigation"); postChangeIfChanged(conversation, entity, properties, currentUser, "impactMitigation"); } if (entity instanceof Impediment) { postChangeIfChanged(conversation, entity, properties, currentUser, "description"); postChangeIfChanged(conversation, entity, properties, currentUser, "solution"); postChangeIfChanged(conversation, entity, properties, currentUser, "closed"); } if (entity instanceof Issue) { postChangeIfChanged(conversation, entity, properties, currentUser, "description"); postChangeIfChanged(conversation, entity, properties, currentUser, "statement"); postChangeIfChanged(conversation, entity, properties, currentUser, "closeDate"); postChangeIfChanged(conversation, entity, properties, currentUser, "storyId"); } if (entity instanceof BlogEntry) { postChangeIfChanged(conversation, entity, properties, currentUser, "text"); } entity.updateProperties(properties); if (entity instanceof Task) onTaskChanged(conversation, (Task) entity, properties); if (entity instanceof Requirement) onRequirementChanged( conversation, (Requirement) entity, properties, previousRequirementSprint); if (entity instanceof Impediment) onImpedimentChanged(conversation, (Impediment) entity, properties); if (entity instanceof Issue) onIssueChanged(conversation, (Issue) entity, properties); if (entity instanceof BlogEntry) onBlogEntryChanged(conversation, (BlogEntry) entity, properties); if (entity instanceof Comment) onCommentChanged(conversation, (Comment) entity, properties); if (entity instanceof SystemConfig) onSystemConfigChanged(conversation, (SystemConfig) entity, properties); if (entity instanceof Wikipage) onWikipageChanged(conversation, (Wikipage) entity, properties); Project currentProject = project; if (currentUser != null && currentProject != null) { ProjectUserConfig config = currentProject.getUserConfig(currentUser); config.touch(); sendToClients(conversation, config); } conversation.clearRemoteEntitiesByType(Change.class); sendToClients(conversation, entity); }
@Override public void onUpdateProjectHomepage(GwtConversation conversation) { assertProjectSelected(conversation); Project project = conversation.getProject(); project.updateHomepage(); }
@Override public void onRequestClosedIssues(GwtConversation conversation) { assertProjectSelected(conversation); Project project = conversation.getProject(); conversation.sendToClient(project.getClosedIssues()); }
private void onRequirementChanged( GwtConversation conversation, Requirement requirement, Map properties, Sprint previousRequirementSprint) { Project currentProject = conversation.getProject(); Sprint sprint = requirement.getSprint(); boolean inCurrentSprint = sprint != null && currentProject.isCurrentSprint(sprint); User currentUser = conversation.getSession().getUser(); if (properties.containsKey("description") || properties.containsKey("testDescription") || properties.containsKey("qualitysIds")) { requirement.setDirty(true); conversation.sendToClient(requirement); } if (properties.containsKey("rejectDate") && requirement.isRejectDateSet()) { postProjectEvent( conversation, currentUser.getName() + " rejected " + requirement.getReferenceAndLabel(), requirement); } if (properties.containsKey("accepted") && requirement.isRejectDateSet()) { postProjectEvent( conversation, currentUser.getName() + " accepted " + requirement.getReferenceAndLabel(), requirement); } if (sprint != previousRequirementSprint) { if (properties.containsKey("sprintId")) { if (inCurrentSprint) { postProjectEvent( conversation, currentUser.getName() + " pulled " + requirement.getReferenceAndLabel() + " to current sprint", requirement); subscriptionService.notifySubscribers( requirement, "Story pulled to current Sprint", conversation.getProject(), null); } else { postProjectEvent( conversation, currentUser.getName() + " kicked " + requirement.getReferenceAndLabel() + " from current sprint", requirement); subscriptionService.notifySubscribers( requirement, "Story kicked from current Sprint", conversation.getProject(), null); } } } if (properties.containsKey("estimatedWork")) { requirement.initializeEstimationVotes(); requirement.setDirty(false); requirement.setWorkEstimationVotingShowoff(false); requirement.setWorkEstimationVotingActive(false); conversation.sendToClient(requirement); } requirement.getProject().getCurrentSprintSnapshot().update(); }
@Override public void onTouchLastActivity(GwtConversation conversation) { Project project = conversation.getProject(); if (project == null) return; project.getUserConfig(conversation.getSession().getUser()).touch(); }
private void onIssueChanged(GwtConversation conversation, Issue issue, Map properties) { User currentUser = conversation.getSession().getUser(); if (properties.containsKey("closeDate")) { if (issue.isClosed()) { issue.setCloseDate(Date.today()); postProjectEvent( conversation, currentUser.getName() + " closed " + issue.getReferenceAndLabel(), issue); subscriptionService.notifySubscribers( issue, "Issue closed", conversation.getProject(), null); } else { postProjectEvent( conversation, currentUser.getName() + " reopened " + issue.getReferenceAndLabel(), issue); subscriptionService.notifySubscribers( issue, "Issue reopened", conversation.getProject(), null); } } if (properties.containsKey("ownerId") && issue.isOwnerSet()) { if (!issue.isFixed()) { postProjectEvent( conversation, currentUser.getName() + " claimed " + issue.getReferenceAndLabel(), issue); } Release nextRelease = issue.getProject().getNextRelease(); if (nextRelease != null && issue.isFixReleasesEmpty()) { issue.setFixReleases(Collections.singleton(nextRelease)); } } if (properties.containsKey("fixDate")) { if (issue.isFixed()) { postProjectEvent( conversation, currentUser.getName() + " fixed " + issue.getReferenceAndLabel(), issue); } else { postProjectEvent( conversation, currentUser.getName() + " rejected fix for " + issue.getReferenceAndLabel(), issue); } } if (properties.containsKey("urgent")) { if (issue.isBug()) { Release currentRelease = issue.getProject().getCurrentRelease(); if (issue.isAffectedReleasesEmpty() && currentRelease != null) { issue.setAffectedReleases(Collections.singleton(currentRelease)); } } } if (properties.containsKey("acceptDate")) { if (issue.isIdea() || issue.isBug()) { postProjectEvent( conversation, currentUser.getName() + " accepted " + issue.getReferenceAndLabel(), issue); subscriptionService.notifySubscribers( issue, "Issue accepted", conversation.getProject(), null); } } issue.getProject().updateHomepage(issue, false); }