String author = notif.getFieldValue("changeAuthor");
StringBuilder sb = new StringBuilder();
- appendField(sb, "Project", null, notif.getFieldValue("projectName"));
+ String projectName = notif.getFieldValue("projectName");
+ appendField(sb, "Project", null, projectName);
appendField(sb, "Component", null, StringUtils.defaultString(notif.getFieldValue("componentName"), notif.getFieldValue("componentKey")));
appendField(sb, "Rule", null, notif.getFieldValue("ruleName"));
appendField(sb, "Message", null, notif.getFieldValue("message"));
+ appendField(sb, "Comment", null, notif.getFieldValue("comment"));
sb.append('\n');
appendField(sb, "Assignee", notif.getFieldValue("old.assignee"), notif.getFieldValue("new.assignee"));
EmailMessage message = new EmailMessage()
.setMessageId("issue-changes/" + issueKey)
- .setSubject("Issue #" + issueKey)
+ .setSubject("Project "+ projectName +", change on issue #" + issueKey)
.setMessage(sb.toString());
if (author != null) {
message.setFrom(getUserFullName(author));
EmailMessage message = new EmailMessage()
.setMessageId("new-issues/" + notification.getFieldValue("projectKey"))
- .setSubject("New issues for project " + projectName)
+ .setSubject("Project " + projectName + ", new issues")
.setMessage(sb.toString());
return message;
#
#------------------------------------------------------------------------------
notification.channel.EmailNotificationChannel=Email
+notification.dispatcher.information=Subscribe to following channels to be notified when the related events occur. A notification is never sent to the author of the event.
notification.dispatcher.ChangesOnMyIssue=Changes in issues assigned to me or reported by me
notification.dispatcher.NewIssues=New issues
notification.dispatcher.NewAlerts=New alerts
.setFieldValue("key", "ABCDE")
.setFieldValue("ruleName", "Avoid Cycles")
.setFieldValue("message", "Has 3 cycles")
+ .setFieldValue("comment", "How to fix it?")
.setFieldValue("old.assignee", "simon")
.setFieldValue("new.assignee", "louis")
.setFieldValue("new.resolution", "FALSE-POSITIVE")
EmailMessage message = template.format(notification);
assertThat(message.getMessageId()).isEqualTo("issue-changes/ABCDE");
- assertThat(message.getSubject()).isEqualTo("Issue #ABCDE");
+ assertThat(message.getSubject()).isEqualTo("Project Struts, change on issue #ABCDE");
assertThat(message.getMessage()).contains("Rule: Avoid Cycles");
assertThat(message.getMessage()).contains("Message: Has 3 cycles");
+ assertThat(message.getMessage()).contains("Comment: How to fix it?");
assertThat(message.getMessage()).contains("Assignee: louis (was simon)");
assertThat(message.getMessage()).contains("Resolution: FALSE-POSITIVE");
assertThat(message.getMessage()).contains("See it in SonarQube: http://nemo.sonarsource.org/issue/show/ABCDE");
/**
* <pre>
- * Subject: New issues for project Foo
+ * Subject: Project Struts, new issues
* From: Sonar
*
* Project: Foo
EmailMessage message = template.format(notification);
assertThat(message.getMessageId()).isEqualTo("new-issues/org.apache:struts");
- assertThat(message.getSubject()).isEqualTo("New issues for project Struts");
+ assertThat(message.getSubject()).isEqualTo("Project Struts, new issues");
assertThat(message.getMessage()).isEqualTo("" +
"Project: Struts\n" +
"32 new issues\n" +
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
+
import java.util.Locale;
import java.util.Map;
@CheckForNull
public Notification sendChanges(DefaultIssue issue, IssueChangeContext context, Rule rule, Component project, @Nullable Component component) {
if (issue.diffs() != null) {
- Notification notification = newNotification(project, "issue-changes");
- notification.setFieldValue("key", issue.key());
- notification.setFieldValue("changeAuthor", context.login());
- notification.setFieldValue("reporter", issue.reporter());
- notification.setFieldValue("assignee", issue.assignee());
- notification.setFieldValue("message", issue.message());
- notification.setFieldValue("ruleName", ruleName(rule));
- notification.setFieldValue("componentKey", issue.componentKey());
- if (component != null) {
- notification.setFieldValue("componentName", component.name());
- }
+ Notification notification = createNotification(issue, context, rule, project, component, null);
+ notificationsManager.scheduleForSending(notification);
+ return notification;
+ }
+ return null;
+ }
- for (Map.Entry<String, FieldDiffs.Diff> entry : issue.diffs().diffs().entrySet()) {
+ @CheckForNull
+ public Notification sendChanges(DefaultIssue issue, IssueChangeContext context, IssueQueryResult queryResult, @Nullable String comment) {
+ Notification notification = createNotification(issue, context, queryResult.rule(issue), queryResult.project(issue), queryResult.component(issue), comment);
+ notificationsManager.scheduleForSending(notification);
+ return notification;
+ }
+
+ private Notification createNotification(DefaultIssue issue, IssueChangeContext context, Rule rule, Component project, @Nullable Component component, @Nullable String comment){
+ Notification notification = newNotification(project, "issue-changes");
+ notification.setFieldValue("key", issue.key());
+ notification.setFieldValue("changeAuthor", context.login());
+ notification.setFieldValue("reporter", issue.reporter());
+ notification.setFieldValue("assignee", issue.assignee());
+ notification.setFieldValue("message", issue.message());
+ notification.setFieldValue("ruleName", ruleName(rule));
+ notification.setFieldValue("componentKey", issue.componentKey());
+ if (component != null) {
+ notification.setFieldValue("componentName", component.name());
+ }
+ if (comment != null) {
+ notification.setFieldValue("comment", comment);
+ }
+
+ FieldDiffs diffs = issue.diffs();
+ if (diffs != null) {
+ for (Map.Entry<String, FieldDiffs.Diff> entry : diffs.diffs().entrySet()) {
String type = entry.getKey();
FieldDiffs.Diff diff = entry.getValue();
notification.setFieldValue("old." + type, diff.oldValue() != null ? diff.oldValue().toString() : null);
notification.setFieldValue("new." + type, diff.newValue() != null ? diff.newValue().toString() : null);
}
- notificationsManager.scheduleForSending(notification);
- return notification;
}
- return null;
+ return notification;
}
private String ruleName(@Nullable Rule rule) {
assertThat(notification.getFieldValue("new.status")).isEqualTo("RESOLVED");
Mockito.verify(manager).scheduleForSending(notification);
}
+
+ @Test
+ public void sendChangesWithComment() throws Exception {
+ IssueChangeContext context = IssueChangeContext.createScan(new Date());
+ DefaultIssue issue = new DefaultIssue()
+ .setMessage("the message")
+ .setKey("ABCDE")
+ .setAssignee("freddy")
+ .setComponentKey("struts:Action")
+ .setProjectKey("struts");
+ DefaultIssueQueryResult queryResult = new DefaultIssueQueryResult(Arrays.<Issue>asList(issue));
+ queryResult.addProjects(Arrays.<Component>asList(new Project("struts")));
+
+ Notification notification = issueNotifications.sendChanges(issue, context, queryResult, "I don't know how to fix it?");
+
+ assertThat(notification.getFieldValue("message")).isEqualTo("the message");
+ assertThat(notification.getFieldValue("key")).isEqualTo("ABCDE");
+ assertThat(notification.getFieldValue("comment")).isEqualTo("I don't know how to fix it?");
+ Mockito.verify(manager).scheduleForSending(notification);
+ }
}
import com.google.common.base.Strings;
import org.sonar.api.ServerComponent;
import org.sonar.api.issue.IssueComment;
+import org.sonar.api.issue.IssueQuery;
+import org.sonar.api.issue.IssueQueryResult;
import org.sonar.api.web.UserRole;
-import org.sonar.core.issue.DefaultIssue;
-import org.sonar.core.issue.DefaultIssueComment;
-import org.sonar.core.issue.IssueChangeContext;
-import org.sonar.core.issue.IssueUpdater;
+import org.sonar.core.issue.*;
import org.sonar.core.issue.db.IssueChangeDao;
import org.sonar.core.issue.db.IssueChangeDto;
import org.sonar.core.issue.db.IssueStorage;
import org.sonar.server.user.UserSession;
+import java.util.Arrays;
import java.util.Date;
public class IssueCommentService implements ServerComponent {
private final IssueChangeDao changeDao;
private final IssueStorage storage;
private final DefaultIssueFinder finder;
+ private final IssueNotifications issueNotifications;
- public IssueCommentService(IssueUpdater updater, IssueChangeDao changeDao, IssueStorage storage, DefaultIssueFinder finder) {
+ public IssueCommentService(IssueUpdater updater, IssueChangeDao changeDao, IssueStorage storage, DefaultIssueFinder finder, IssueNotifications issueNotifications) {
this.updater = updater;
this.changeDao = changeDao;
this.storage = storage;
this.finder = finder;
+ this.issueNotifications = issueNotifications;
}
public IssueComment findComment(String commentKey) {
public IssueComment addComment(String issueKey, String text, UserSession userSession) {
verifyLoggedIn(userSession);
- DefaultIssue issue = finder.findByKey(issueKey, UserRole.USER);
+
+ IssueQueryResult queryResult = loadIssue(issueKey);
+ DefaultIssue issue = (DefaultIssue) queryResult.first();
IssueChangeContext context = IssueChangeContext.createUser(new Date(), userSession.login());
updater.addComment(issue, text, context);
storage.save(issue);
+ issueNotifications.sendChanges(issue, context, queryResult, text);
return issue.comments().get(issue.comments().size() - 1);
}
throw new IllegalStateException("User is not logged in");
}
}
+
+ public IssueQueryResult loadIssue(String issueKey) {
+ IssueQuery query = IssueQuery.builder().issueKeys(Arrays.asList(issueKey)).requiredRole(UserRole.USER).build();
+ return finder.find(query);
+ }
}
<h2><%= message('my_profile.overall_notifications.title') -%></h2>
- <table class="form">
- <tr>
- <td></td>
- <% for channel in @channels %>
- <td class="center"><b><%= message('notification.channel.' + channel.getKey()) -%></b></td>
- <% end %>
- </tr>
- <% for dispatcher in @global_dispatchers %>
- <tr>
- <td><%= message('notification.dispatcher.' + dispatcher) -%></td>
- <%
- for channel in @channels
- notification_id = dispatcher + '.' + channel.getKey()
- check_box_id = 'global_notifs[' + notification_id + ']'
- check_box_checked = @global_notifications[notification_id]
- %>
- <td class="center">
- <%= check_box_tag check_box_id, 'true', check_box_checked %>
- </td>
- <% end %>
- </tr>
+<span><%= message('notification.dispatcher.information') -%></span>
+<br/><br/>
+<table class="form">
+ <tr>
+ <td></td>
+ <% for channel in @channels %>
+ <td class="center"><b><%= message('notification.channel.' + channel.getKey()) -%></b></td>
+ <% end %>
+ </tr>
+ <% for dispatcher in @global_dispatchers %>
+ <tr>
+ <td><%= message('notification.dispatcher.' + dispatcher) -%></td>
+ <%
+ for channel in @channels
+ notification_id = dispatcher + '.' + channel.getKey()
+ check_box_id = 'global_notifs[' + notification_id + ']'
+ check_box_checked = @global_notifications[notification_id]
+ %>
+ <td class="center">
+ <%= check_box_tag check_box_id, 'true', check_box_checked %>
+ </td>
<% end %>
- </table>
+ </tr>
+ <% end %>
+</table>