public abstract void deliver(Notification notification, String username);
+ @Override
+ public String toString() {
+ return getKey();
+ }
+
}
*/
public abstract void dispatch(Notification notification, Context context);
+ @Override
+ public String toString() {
+ return getKey();
+ }
+
}
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;
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;
/**
* 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;
}
}
}
- 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());
}
}
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
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
$('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/>
--- /dev/null
+/*
+ * 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));
+ }
+
+}
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));
}
--- /dev/null
+<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