summaryrefslogtreecommitdiffstats
path: root/sonar-server
diff options
context:
space:
mode:
authorEvgeny Mandrikov <mandrikov@gmail.com>2011-07-21 11:45:41 +0400
committerEvgeny Mandrikov <mandrikov@gmail.com>2011-07-22 18:52:15 +0400
commit957e62ce77e23d31d59f9369657e91a9dd616c84 (patch)
treeb78bf8831d41c82fa34cd071a3783f756f08d745 /sonar-server
parente0e528211faad3fdf469c83bcbc7aecf6c25a234 (diff)
downloadsonarqube-957e62ce77e23d31d59f9369657e91a9dd616c84.tar.gz
sonarqube-957e62ce77e23d31d59f9369657e91a9dd616c84.zip
SONAR-2607 Provide email notifications on review changes
* Add email templates. * Add server component - UserFinder.
Diffstat (limited to 'sonar-server')
-rw-r--r--sonar-server/src/main/java/org/sonar/server/notifications/NotificationService.java6
-rw-r--r--sonar-server/src/main/java/org/sonar/server/notifications/reviews/ReviewsNotificationManager.java66
-rw-r--r--sonar-server/src/main/java/org/sonar/server/platform/Platform.java2
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/models/review.rb65
-rw-r--r--sonar-server/src/test/java/org/sonar/server/notifications/reviews/ReviewsNotificationManagerTest.java42
-rw-r--r--sonar-server/src/test/resources/org/sonar/server/notifications/reviews/fixture.xml15
6 files changed, 109 insertions, 87 deletions
diff --git a/sonar-server/src/main/java/org/sonar/server/notifications/NotificationService.java b/sonar-server/src/main/java/org/sonar/server/notifications/NotificationService.java
index b88cf62146b..b408a05bfd7 100644
--- a/sonar-server/src/main/java/org/sonar/server/notifications/NotificationService.java
+++ b/sonar-server/src/main/java/org/sonar/server/notifications/NotificationService.java
@@ -136,9 +136,9 @@ public class NotificationService implements ServerComponent {
}
for (Map.Entry<String, Collection<NotificationChannel>> entry : recipients.asMap().entrySet()) {
String username = entry.getKey();
- Collection<NotificationChannel> channels = entry.getValue();
- LOG.info("For user {} via {}", username, channels);
- for (NotificationChannel channel : channels) {
+ Collection<NotificationChannel> userChannels = entry.getValue();
+ LOG.info("For user {} via {}", username, userChannels);
+ for (NotificationChannel channel : userChannels) {
channel.deliver(notification, username);
}
}
diff --git a/sonar-server/src/main/java/org/sonar/server/notifications/reviews/ReviewsNotificationManager.java b/sonar-server/src/main/java/org/sonar/server/notifications/reviews/ReviewsNotificationManager.java
index e8200bd4b06..a89a5667acf 100644
--- a/sonar-server/src/main/java/org/sonar/server/notifications/reviews/ReviewsNotificationManager.java
+++ b/sonar-server/src/main/java/org/sonar/server/notifications/reviews/ReviewsNotificationManager.java
@@ -19,49 +19,69 @@
*/
package org.sonar.server.notifications.reviews;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.lang.StringUtils;
import org.sonar.api.ServerComponent;
-import org.sonar.api.database.model.Review;
-import org.sonar.api.database.model.User;
import org.sonar.api.notifications.Notification;
import org.sonar.api.notifications.NotificationManager;
-import org.sonar.jpa.session.DatabaseSessionFactory;
+
+import com.google.common.collect.Sets;
/**
* @since 2.10
*/
public class ReviewsNotificationManager implements ServerComponent {
- private DatabaseSessionFactory sessionFactory;
private NotificationManager notificationManager;
- public ReviewsNotificationManager(DatabaseSessionFactory sessionFactory, NotificationManager notificationManager) {
- this.sessionFactory = sessionFactory;
+ public ReviewsNotificationManager(NotificationManager notificationManager) {
this.notificationManager = notificationManager;
}
/**
- * Visibility has been relaxed for tests.
+ * @param reviewId id of review, which was modified
+ * @param author author of change (username)
+ * @param creator author of review (username)
+ * @param assignee current assignee (username)
+ * @param oldComment old text of comment
+ * @param comment new text of comment
*/
- User getUserById(Integer id) {
- return sessionFactory.getSession().getEntity(User.class, id);
+ public void notifyCommentChanged(Long reviewId, String author, String creator, String assignee, String oldComment, String newComment) {
+ Notification notification = new Notification("review-changed")
+ .setFieldValue("reviewId", String.valueOf(reviewId))
+ .setFieldValue("author", author)
+ .setFieldValue("creator", creator)
+ .setFieldValue("assignee", assignee)
+ .setFieldValue("old.comment", oldComment)
+ .setFieldValue("new.comment", newComment);
+ notificationManager.scheduleForSending(notification);
}
/**
- * Visibility has been relaxed for tests.
+ * @param reviewId reviewId id of review, which was modified
+ * @param author author of change (username)
+ * @param oldValues map of old values
+ * @param newValues map of new values
*/
- Review getReviewById(Long id) {
- return sessionFactory.getSession().getEntity(Review.class, id);
- }
-
- public void notifyCommentAdded(Long reviewId, Integer userId, String comment) {
- Review review = getReviewById(reviewId);
- User author = getUserById(userId);
-
- Notification notification = new Notification("review");
- notification // FIXME include info about review
- .setFieldValue("author", author.getLogin())
- .setFieldValue("comment", comment);
-
+ public void notifyChanged(Long reviewId, String author, Map<String, String> oldValues, Map<String, String> newValues) {
+ Notification notification = new Notification("review-changed")
+ .setFieldValue("reviewId", author)
+ .setFieldValue("author", author)
+ .setFieldValue("creator", newValues.get("creator"))
+ .setFieldValue("assignee", newValues.get("assignee"));
+ Set<String> fields = Sets.newHashSet();
+ fields.addAll(oldValues.keySet());
+ fields.addAll(newValues.keySet());
+ for (String field : fields) {
+ String oldValue = oldValues.get(field);
+ String newValue = newValues.get(field);
+ if ( !StringUtils.equals(oldValue, newValue)) {
+ notification.setFieldValue("new." + field, newValue);
+ notification.setFieldValue("old." + field, oldValue);
+ }
+ }
notificationManager.scheduleForSending(notification);
}
diff --git a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
index df234f0c490..7b5ef8fac7f 100644
--- a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
+++ b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
@@ -40,6 +40,7 @@ import org.sonar.api.utils.TimeProfiler;
import org.sonar.core.components.DefaultMetricFinder;
import org.sonar.core.components.DefaultModelFinder;
import org.sonar.core.components.DefaultRuleFinder;
+import org.sonar.core.components.DefaultUserFinder;
import org.sonar.core.notifications.DefaultNotificationManager;
import org.sonar.jpa.dao.DaoFacade;
import org.sonar.jpa.dao.MeasuresDao;
@@ -185,6 +186,7 @@ public final class Platform {
servicesContainer.as(Characteristics.CACHE).addComponent(ProfilesConsole.class);
servicesContainer.as(Characteristics.CACHE).addComponent(RulesConsole.class);
servicesContainer.as(Characteristics.CACHE).addComponent(JRubyI18n.class);
+ servicesContainer.as(Characteristics.CACHE).addComponent(DefaultUserFinder.class);
// Notifications
servicesContainer.as(Characteristics.CACHE).addComponent(NotificationService.class);
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/review.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/review.rb
index 94df7aed6d6..d4fe68c3808 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/models/review.rb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/models/review.rb
@@ -54,15 +54,14 @@ class Review < ActiveRecord::Base
# REVIEW CORE METHODS
#
#
-
+
# params are mandatory:
# - :user
# - :text
def create_comment(params={})
comment = comments.create!(params)
touch
-
- Java::OrgSonarServerUi::JRubyFacade.getInstance().getReviewsNotificationManager().notifyCommentAdded(id.to_i, comment.user.id.to_i, comment.text.to_java)
+ # TODO notification_manager.notifyCommentChanged(id.to_i, current_user.login.to_java, self.user.login.to_java, self.assignee.login.to_java, nil, comment.text.to_java)
end
def edit_comment(comment_id, comment_text)
@@ -76,25 +75,61 @@ class Review < ActiveRecord::Base
def edit_last_comment(comment_text)
comment=comments.last
+ old_comment_text=comment.text
comment.text=comment_text
comment.save!
touch
+ # TODO notification_manager.notifyCommentChanged(id.to_i, current_user.login.to_java, self.user.login.to_java, self.assignee.login.to_java, old_comment.to_java, comment.text.to_java)
end
-
+
def delete_comment(comment_id)
comment=comments.find(comment_id)
comments.pop
if comment
+ old_comment_text=comment.text
comment.delete
touch
+ # TODO notification_manager.notifyCommentChanged(id.to_i, current_user.login.to_java, self.user.login.to_java, self.assignee.login.to_java, old_comment_text.to_java, nil)
end
end
-
+
+ def notification_manager
+ Java::OrgSonarServerUi::JRubyFacade.getInstance().getReviewsNotificationManager()
+ end
+
+ def to_java_map()
+ map = java.util.HashMap.new({
+ :creator => user.login.to_java,
+ :assignee => assignee == nil ? nil : assignee.login.to_java,
+ :status => status.to_java,
+ :resolution => resolution.to_java
+ })
+ map
+ end
+
def reassign(user)
+ old = self.to_java_map
self.assignee = user
self.save!
+ # TODO notification_manager.notifyChanged(id.to_i, current_user.login.to_java, old, to_java_map)
end
-
+
+ def reopen
+ old = self.to_java_map
+ self.status = STATUS_REOPENED
+ self.resolution = nil
+ self.save!
+ # TODO notification_manager.notifyChanged(id.to_i, current_user.login.to_java, old, to_java_map)
+ end
+
+ def resolve
+ old = self.to_java_map
+ self.status = STATUS_RESOLVED
+ self.resolution = 'FIXED'
+ self.save!
+ # TODO notification_manager.notifyChanged(id.to_i, current_user.login.to_java, old, to_java_map)
+ end
+
# params are mandatory:
# - :user (mandatory)
# - :text (mandatory)
@@ -112,13 +147,15 @@ class Review < ActiveRecord::Base
end
end
create_comment(:user => params[:user], :text => params[:text])
+ old = self.to_java_map
self.assignee = nil
self.status = is_false_positive ? STATUS_RESOLVED : STATUS_REOPENED
self.resolution = is_false_positive ? 'FALSE-POSITIVE' : nil
self.save!
+ # TODO notification_manager.notifyChanged(id.to_i, current_user.login.to_java, old, to_java_map)
end
end
-
+
def false_positive
resolution == 'FALSE-POSITIVE'
end
@@ -143,20 +180,6 @@ class Review < ActiveRecord::Base
status == STATUS_OPEN
end
- def reopen
- self.status = STATUS_REOPENED
- self.resolution = nil
- self.save!
- end
-
- def resolve
- self.status = STATUS_RESOLVED
- self.resolution = 'FIXED'
- self.save!
- end
-
-
-
#
#
# SEARCH METHODS
diff --git a/sonar-server/src/test/java/org/sonar/server/notifications/reviews/ReviewsNotificationManagerTest.java b/sonar-server/src/test/java/org/sonar/server/notifications/reviews/ReviewsNotificationManagerTest.java
index 8e0eaba6953..187d3e965b3 100644
--- a/sonar-server/src/test/java/org/sonar/server/notifications/reviews/ReviewsNotificationManagerTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/notifications/reviews/ReviewsNotificationManagerTest.java
@@ -19,39 +19,31 @@
*/
package org.sonar.server.notifications.reviews;
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
import org.junit.Before;
-import org.junit.Test;
-import org.sonar.api.database.model.Review;
-import org.sonar.api.database.model.User;
-import org.sonar.jpa.test.AbstractDbUnitTestCase;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.sonar.api.notifications.Notification;
+import org.sonar.api.notifications.NotificationManager;
-public class ReviewsNotificationManagerTest extends AbstractDbUnitTestCase {
+public class ReviewsNotificationManagerTest { // FIXME implement
+ private Notification notification;
private ReviewsNotificationManager manager;
@Before
public void setUp() {
- setupData(getClass().getResourceAsStream("fixture.xml"));
- manager = new ReviewsNotificationManager(getSessionFactory(), null);
- }
-
- @Test
- public void shouldGetReviewById() {
- Review review = manager.getReviewById(3L);
- assertThat(review.getUserId(), is(1));
- assertThat(review.getAssigneeId(), is(2));
- assertThat(review.getTitle(), is("Review #3"));
- }
-
- @Test
- public void shouldGetUserById() {
- User user = manager.getUserById(1);
- assertThat(user.getLogin(), is("simon"));
- assertThat(user.getName(), is("Simon Brandhof"));
- assertThat(user.getEmail(), is("simon.brandhof@sonarsource.com"));
+ NotificationManager delegate = mock(NotificationManager.class);
+ doAnswer(new Answer() {
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ notification = (Notification) invocation.getArguments()[0];
+ return null;
+ }
+ }).when(delegate).scheduleForSending(any(Notification.class));
+ manager = new ReviewsNotificationManager(delegate);
}
}
diff --git a/sonar-server/src/test/resources/org/sonar/server/notifications/reviews/fixture.xml b/sonar-server/src/test/resources/org/sonar/server/notifications/reviews/fixture.xml
deleted file mode 100644
index d9a64d90337..00000000000
--- a/sonar-server/src/test/resources/org/sonar/server/notifications/reviews/fixture.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<dataset>
-
- <users id="1" login="simon" name="Simon Brandhof" email="simon.brandhof@sonarsource.com" />
- <users id="2" login="godin" name="Evgeny Mandrikov" email="evgeny.mandrikov@sonarsource.com" />
-
- <!-- Review created by Simon and assigned to him -->
- <reviews id="1" user_id="1" assignee_id="1" title="Review #1" />
-
- <!-- Review created by Evgeny and not assigned -->
- <reviews id="2" user_id="2" assignee_id="[null]" title="Review #2" />
-
- <!-- Review created by Simon and assigned to Evgeny -->
- <reviews id="3" user_id="1" assignee_id="2" title="Review #3" />
-
-</dataset> \ No newline at end of file