]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-2599 First draft of settings for notifications in user profile
authorEvgeny Mandrikov <mandrikov@gmail.com>
Wed, 20 Jul 2011 15:09:57 +0000 (19:09 +0400)
committerEvgeny Mandrikov <mandrikov@gmail.com>
Wed, 20 Jul 2011 19:18:56 +0000 (23:18 +0400)
sonar-plugin-api/src/main/java/org/sonar/api/notifications/NotificationChannel.java
sonar-plugin-api/src/main/java/org/sonar/api/notifications/NotificationDispatcher.java
sonar-server/src/main/java/org/sonar/server/notifications/NotificationService.java
sonar-server/src/main/webapp/WEB-INF/app/controllers/account_controller.rb
sonar-server/src/main/webapp/WEB-INF/app/views/account/index.html.erb
sonar-server/src/test/java/org/sonar/server/notifications/NotificationServiceDbTest.java [new file with mode: 0644]
sonar-server/src/test/java/org/sonar/server/notifications/NotificationServiceTest.java
sonar-server/src/test/resources/org/sonar/server/notifications/NotificationServiceDbTest/fixture.xml [new file with mode: 0644]

index 5be114919635905bfe5fcae5ffce1c9251920c43..cbdf9cb0bf3a39852004c42520ce64562b614c41 100644 (file)
@@ -43,4 +43,9 @@ public abstract class NotificationChannel implements ServerExtension {
 
   public abstract void deliver(Notification notification, String username);
 
+  @Override
+  public String toString() {
+    return getKey();
+  }
+
 }
index 6886725e5961f37db6e524a3999e7500066266a4..237fe6a37cfbba7ecd993744d993b04f7cfda4ab 100644 (file)
@@ -52,4 +52,9 @@ public abstract class NotificationDispatcher implements ServerExtension {
    */
   public abstract void dispatch(Notification notification, Context context);
 
+  @Override
+  public String toString() {
+    return getKey();
+  }
+
 }
index b77fe0e629648e20b8bd3afa3751659e728d5d61..b88cf62146bd82b993c45c36536e6c607d7f3bdd 100644 (file)
@@ -25,15 +25,18 @@ import com.google.common.collect.Sets;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.ServerComponent;
+import org.sonar.api.database.DatabaseSession;
+import org.sonar.api.database.configuration.Property;
+import org.sonar.api.database.model.User;
 import org.sonar.api.notifications.Notification;
 import org.sonar.api.notifications.NotificationChannel;
 import org.sonar.api.notifications.NotificationDispatcher;
 import org.sonar.api.utils.TimeProfiler;
 import org.sonar.core.notifications.DefaultNotificationManager;
 import org.sonar.jpa.entity.NotificationQueueElement;
+import org.sonar.jpa.session.DatabaseSessionFactory;
 
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
@@ -49,6 +52,7 @@ public class NotificationService implements ServerComponent {
   private ScheduledExecutorService executorService;
   private long period = 10; // FIXME small value just for tests
 
+  private DatabaseSessionFactory sessionFactory;
   private DefaultNotificationManager manager;
   private NotificationChannel[] channels;
   private NotificationDispatcher[] dispatchers;
@@ -56,12 +60,13 @@ public class NotificationService implements ServerComponent {
   /**
    * Default constructor when no channels.
    */
-  public NotificationService(DefaultNotificationManager manager, NotificationDispatcher[] dispatchers) {
-    this(manager, dispatchers, new NotificationChannel[0]);
+  public NotificationService(DatabaseSessionFactory sessionFactory, DefaultNotificationManager manager, NotificationDispatcher[] dispatchers) {
+    this(sessionFactory, manager, dispatchers, new NotificationChannel[0]);
     LOG.warn("There is no channels - all notifications would be ignored!");
   }
 
-  public NotificationService(DefaultNotificationManager manager, NotificationDispatcher[] dispatchers, NotificationChannel[] channels) {
+  public NotificationService(DatabaseSessionFactory sessionFactory, DefaultNotificationManager manager, NotificationDispatcher[] dispatchers, NotificationChannel[] channels) {
+    this.sessionFactory = sessionFactory;
     this.manager = manager;
     this.channels = channels;
     this.dispatchers = dispatchers;
@@ -129,17 +134,34 @@ public class NotificationService implements ServerComponent {
         }
       }
     }
-    for (Map.Entry<String, NotificationChannel> entry : recipients.entries()) {
+    for (Map.Entry<String, Collection<NotificationChannel>> entry : recipients.asMap().entrySet()) {
       String username = entry.getKey();
-      NotificationChannel channel = entry.getValue();
-      LOG.info("For user {} via {}", username, channel);
-      channel.deliver(notification, username);
+      Collection<NotificationChannel> channels = entry.getValue();
+      LOG.info("For user {} via {}", username, channels);
+      for (NotificationChannel channel : channels) {
+        channel.deliver(notification, username);
+      }
     }
     TIME_PROFILER.stop();
   }
 
+  public List<NotificationDispatcher> getDispatchers() {
+    return Arrays.asList(dispatchers);
+  }
+
+  public List<NotificationChannel> getChannels() {
+    return Arrays.asList(channels);
+  }
+
+  /**
+   * Visibility has been relaxed for tests.
+   */
   boolean isEnabled(String username, NotificationChannel channel, NotificationDispatcher dispatcher) {
-    return true; // FIXME for the moment we will accept everything
+    DatabaseSession session = sessionFactory.getSession();
+    User user = session.getSingleResult(User.class, "login", username);
+    String notificationKey = "notification." + dispatcher.getKey() + "." + channel.getKey();
+    Property property = session.getSingleResult(Property.class, "userId", user.getId(), "key", notificationKey);
+    return property != null && "true".equals(property.getValue());
   }
 
 }
index 340ce2bfc3af4f77594843df52b1fe4df2f51b5e..807b9bb79d63508ea6a5dd5d76f3b04ef40ccb3e 100644 (file)
@@ -24,7 +24,13 @@ class AccountController < ApplicationController
   before_filter :login_required
 
   def index
-
+    notification_service = java_facade.getCoreComponentByClassname('org.sonar.server.notifications.NotificationService')
+    @channels = notification_service.getChannels()
+    @dispatchers = notification_service.getDispatchers()
+    @notifications = {}
+    for property in Property.find(:all, :conditions => ['prop_key like ? AND user_id = ?', 'notification.%', current_user.id])
+      @notifications[property.key.sub('notification.', '')] = true
+    end
   end
 
   def change_password
@@ -47,4 +53,12 @@ class AccountController < ApplicationController
     end
     redirect_to :controller => 'account', :action => 'index'
   end
+
+  def update_notifications
+    notifications = params[:notifications]
+    Property.delete_all(['prop_key like ? AND user_id = ?', 'notification.%', current_user.id])
+    notifications.each_key { |key| current_user.set_property(:prop_key => 'notification.' + key, :text_value => 'true') } unless notifications.nil?
+    redirect_to :action => 'index'
+  end
+
 end
index 23486909d8914cad624f95ed7efc1d33673a2910..5a2faf1a95bc4d95398b5dcd3ce9f68d07cbe886 100644 (file)
     $('pass_form_tag').focusFirstElement();
   //]]>
        </script>
-<% end -%>
\ No newline at end of file
+<% end -%>
+<br/>
+
+<h1>Notifications</h1>
+<br/>
+<% form_tag({:action => 'update_notifications'}, {:method => 'post'}) do %>
+  <table>
+    <tr>
+      <td></td>
+      <% for channel in @channels %>
+      <td><%= channel.getKey() %></td>
+      <% end %>
+    </tr>
+    <% for dispatcher in @dispatchers %>
+    <tr>
+      <td><%= dispatcher.getKey() %></td>
+      <td>
+        <%
+        for channel in @channels
+          notification_id = dispatcher.getKey() + '.' + channel.getKey()
+          check_box_id = 'notifications[' + notification_id + ']'
+          check_box_checked = @notifications[notification_id]
+        %>
+          <%= check_box_tag check_box_id, 'true', check_box_checked %>
+        <% end %>
+      </td>
+    </tr>
+    <% end %>
+  </table>
+  <br/>
+  <%= submit_tag %>
+<% end %>
+<br/>
diff --git a/sonar-server/src/test/java/org/sonar/server/notifications/NotificationServiceDbTest.java b/sonar-server/src/test/java/org/sonar/server/notifications/NotificationServiceDbTest.java
new file mode 100644 (file)
index 0000000..a7a57c9
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.server.notifications;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.notifications.NotificationChannel;
+import org.sonar.api.notifications.NotificationDispatcher;
+import org.sonar.jpa.test.AbstractDbUnitTestCase;
+
+public class NotificationServiceDbTest extends AbstractDbUnitTestCase {
+
+  private NotificationService notificationService;
+
+  @Before
+  public void setUp() {
+    setupData("fixture");
+    notificationService = new NotificationService(getSessionFactory(), null, null);
+  }
+
+  @Test
+  public void should() {
+    NotificationChannel email = mock(NotificationChannel.class);
+    when(email.getKey()).thenReturn("EmailNotificationChannel");
+    NotificationDispatcher commentOnReviewAssignedToMe = mock(NotificationDispatcher.class);
+    when(commentOnReviewAssignedToMe.getKey()).thenReturn("CommentOnReviewAssignedToMe");
+
+    assertThat(notificationService.isEnabled("simon", email, commentOnReviewAssignedToMe), is(true));
+    assertThat(notificationService.isEnabled("godin", email, commentOnReviewAssignedToMe), is(false));
+  }
+
+}
index 46633e27a906f73e62224e781fd99b9c8cdae88c..d17ada1756205840a2338633274b8ac1d9d9c259 100644 (file)
@@ -77,7 +77,7 @@ public class NotificationServiceTest {
     NotificationDispatcher[] dispatchers = new NotificationDispatcher[] { commentOnReviewAssignedToMe, commentOnReviewCreatedByMe };
     NotificationChannel[] channels = new NotificationChannel[] { emailChannel, gtalkChannel };
     manager = mock(DefaultNotificationManager.class);
-    service = spy(new NotificationService(manager, dispatchers, channels));
+    service = spy(new NotificationService(null, manager, dispatchers, channels));
     doReturn(false).when(service).isEnabled(any(String.class), any(NotificationChannel.class), any(NotificationDispatcher.class));
   }
 
diff --git a/sonar-server/src/test/resources/org/sonar/server/notifications/NotificationServiceDbTest/fixture.xml b/sonar-server/src/test/resources/org/sonar/server/notifications/NotificationServiceDbTest/fixture.xml
new file mode 100644 (file)
index 0000000..83c713e
--- /dev/null
@@ -0,0 +1,8 @@
+<dataset>
+
+  <users id="1" login="simon" />
+  <users id="2" login="godin" />
+
+  <properties user_id="1" prop_key="notification.CommentOnReviewAssignedToMe.EmailNotificationChannel" text_value="true"/>
+
+</dataset>
\ No newline at end of file