]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7024 support permission for global and project subscribers
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Wed, 20 Sep 2017 15:38:55 +0000 (17:38 +0200)
committerEric Hartmann <hartmann.eric@gmail.Com>
Mon, 2 Oct 2017 11:03:35 +0000 (13:03 +0200)
15 files changed:
server/sonar-server/src/main/java/org/sonar/ce/notification/ReportAnalysisFailureNotificationDispatcher.java
server/sonar-server/src/main/java/org/sonar/server/event/NewAlerts.java
server/sonar-server/src/main/java/org/sonar/server/issue/notification/ChangesOnMyIssueNotificationDispatcher.java
server/sonar-server/src/main/java/org/sonar/server/issue/notification/DoNotFixNotificationDispatcher.java
server/sonar-server/src/main/java/org/sonar/server/issue/notification/MyNewIssuesNotificationDispatcher.java
server/sonar-server/src/main/java/org/sonar/server/issue/notification/NewIssuesNotificationDispatcher.java
server/sonar-server/src/main/java/org/sonar/server/notification/DefaultNotificationManager.java
server/sonar-server/src/main/java/org/sonar/server/notification/NotificationManager.java
server/sonar-server/src/test/java/org/sonar/ce/notification/ReportAnalysisFailureNotificationDispatcherTest.java
server/sonar-server/src/test/java/org/sonar/server/event/NewAlertsTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/notification/ChangesOnMyIssueNotificationDispatcherTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/notification/DoNotFixNotificationDispatcherTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/notification/MyNewIssuesNotificationDispatcherTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesNotificationDispatcherTest.java
server/sonar-server/src/test/java/org/sonar/server/notification/DefaultNotificationManagerTest.java

index 574bb17e5949de13031cc24fe47246d11ff1d022..2481d9937ae43625f93d3a0ae36e06e059609a92 100644 (file)
@@ -53,7 +53,8 @@ public class ReportAnalysisFailureNotificationDispatcher extends NotificationDis
   @Override
   public void dispatch(Notification notification, Context context) {
     String projectUuid = notification.getFieldValue("project.uuid");
-    Multimap<String, NotificationChannel> subscribedRecipients = manager.findSubscribedRecipientsForDispatcher(this, projectUuid);
+    Multimap<String, NotificationChannel> subscribedRecipients = manager.findSubscribedRecipientsForDispatcher(
+      this, projectUuid, NotificationManager.SubscriberPermissionsOnProject.ALL_MUST_HAVE_ROLE_USER);
 
     for (Map.Entry<String, Collection<NotificationChannel>> channelsByRecipients : subscribedRecipients.asMap().entrySet()) {
       String userLogin = channelsByRecipients.getKey();
index 3c94a00e449b8d620e4dfe54fa0ac4a06b512b9e..87804f12be299f3b98c9c5f9196e2383c3cf5926 100644 (file)
@@ -28,6 +28,8 @@ import org.sonar.server.notification.NotificationDispatcher;
 import org.sonar.server.notification.NotificationDispatcherMetadata;
 import org.sonar.server.notification.NotificationManager;
 
+import static org.sonar.server.notification.NotificationManager.SubscriberPermissionsOnProject.ALL_MUST_HAVE_ROLE_USER;
+
 /**
  * This dispatcher means: "notify me each new alert event".
  *
@@ -58,7 +60,8 @@ public class NewAlerts extends NotificationDispatcher {
   public void dispatch(Notification notification, Context context) {
     String projectUuid = notification.getFieldValue("projectUuid");
     if (projectUuid != null) {
-      Multimap<String, NotificationChannel> subscribedRecipients = notifications.findSubscribedRecipientsForDispatcher(this, projectUuid);
+      Multimap<String, NotificationChannel> subscribedRecipients = notifications.findSubscribedRecipientsForDispatcher(
+        this, projectUuid, ALL_MUST_HAVE_ROLE_USER);
 
       for (Map.Entry<String, Collection<NotificationChannel>> channelsByRecipients : subscribedRecipients.asMap().entrySet()) {
         String userLogin = channelsByRecipients.getKey();
index d9115a37619ba88817525779ed5bd2dfc8b16ec8..9f0031d9d816816363c5f241e1cac44aade3f4c9 100644 (file)
@@ -29,6 +29,8 @@ import org.sonar.server.notification.NotificationDispatcher;
 import org.sonar.server.notification.NotificationDispatcherMetadata;
 import org.sonar.server.notification.NotificationManager;
 
+import static org.sonar.server.notification.NotificationManager.SubscriberPermissionsOnProject.ALL_MUST_HAVE_ROLE_USER;
+
 /**
  * This dispatcher means: "notify me when a change is done on an issue that is assigned to me or reported by me".
  *
@@ -58,7 +60,8 @@ public class ChangesOnMyIssueNotificationDispatcher extends NotificationDispatch
   @Override
   public void dispatch(Notification notification, Context context) {
     String projectUuid = notification.getFieldValue("projectUuid");
-    Multimap<String, NotificationChannel> subscribedRecipients = notificationManager.findSubscribedRecipientsForDispatcher(this, projectUuid);
+    Multimap<String, NotificationChannel> subscribedRecipients = notificationManager.findSubscribedRecipientsForDispatcher(
+      this, projectUuid, ALL_MUST_HAVE_ROLE_USER);
 
     // See available fields in the class IssueNotifications.
 
index 87e1d62599a1b1856e06608edc4954ec056e8b30..5c86e435af06fac51231217b65316077e512949c 100644 (file)
@@ -30,6 +30,8 @@ import org.sonar.server.notification.NotificationDispatcher;
 import org.sonar.server.notification.NotificationDispatcherMetadata;
 import org.sonar.server.notification.NotificationManager;
 
+import static org.sonar.server.notification.NotificationManager.SubscriberPermissionsOnProject.ALL_MUST_HAVE_ROLE_USER;
+
 /**
  * This dispatcher means: "notify me when an issue is resolved as false positive or won't fix".
  */
@@ -61,7 +63,8 @@ public class DoNotFixNotificationDispatcher extends NotificationDispatcher {
     if (Objects.equals(newResolution, Issue.RESOLUTION_FALSE_POSITIVE) || Objects.equals(newResolution, Issue.RESOLUTION_WONT_FIX)) {
       String author = notification.getFieldValue("changeAuthor");
       String projectUuid = notification.getFieldValue("projectUuid");
-      Multimap<String, NotificationChannel> subscribedRecipients = notifications.findSubscribedRecipientsForDispatcher(this, projectUuid);
+      Multimap<String, NotificationChannel> subscribedRecipients = notifications.findSubscribedRecipientsForDispatcher(
+        this, projectUuid, ALL_MUST_HAVE_ROLE_USER);
       notify(author, context, subscribedRecipients);
     }
   }
index ee980d09b51b512ee40da2d6954e6a356aa5715f..3b50d87b305ee4c476e03ffc7e0e7b8d31060be8 100644 (file)
@@ -27,6 +27,8 @@ import org.sonar.server.notification.NotificationDispatcher;
 import org.sonar.server.notification.NotificationDispatcherMetadata;
 import org.sonar.server.notification.NotificationManager;
 
+import static org.sonar.server.notification.NotificationManager.SubscriberPermissionsOnProject.ALL_MUST_HAVE_ROLE_USER;
+
 /**
  * This dispatcher means: "notify me when new issues are introduced during project analysis"
  */
@@ -55,7 +57,8 @@ public class MyNewIssuesNotificationDispatcher extends NotificationDispatcher {
   public void dispatch(Notification notification, Context context) {
     String projectUuid = notification.getFieldValue("projectUuid");
     String assignee = notification.getFieldValue("assignee");
-    Multimap<String, NotificationChannel> subscribedRecipients = manager.findSubscribedRecipientsForDispatcher(this, projectUuid);
+    Multimap<String, NotificationChannel> subscribedRecipients = manager.findSubscribedRecipientsForDispatcher(
+        this, projectUuid, ALL_MUST_HAVE_ROLE_USER);
 
     Collection<NotificationChannel> channels = subscribedRecipients.get(assignee);
     for (NotificationChannel channel : channels) {
index 8b7787ea98a7f2f6f8b08edca32958dcc4ceb521..cd404a4af6c7b240db9a10bde09258da5d1d3188 100644 (file)
@@ -28,6 +28,8 @@ import org.sonar.server.notification.NotificationDispatcher;
 import org.sonar.server.notification.NotificationDispatcherMetadata;
 import org.sonar.server.notification.NotificationManager;
 
+import static org.sonar.server.notification.NotificationManager.SubscriberPermissionsOnProject.ALL_MUST_HAVE_ROLE_USER;
+
 /**
  * This dispatcher means: "notify me when new issues are introduced during project analysis"
  */
@@ -55,7 +57,8 @@ public class NewIssuesNotificationDispatcher extends NotificationDispatcher {
   @Override
   public void dispatch(Notification notification, Context context) {
     String projectUuid = notification.getFieldValue("projectUuid");
-    Multimap<String, NotificationChannel> subscribedRecipients = manager.findSubscribedRecipientsForDispatcher(this, projectUuid);
+    Multimap<String, NotificationChannel> subscribedRecipients = manager.findSubscribedRecipientsForDispatcher(
+      this, projectUuid, ALL_MUST_HAVE_ROLE_USER);
 
     for (Map.Entry<String, Collection<NotificationChannel>> channelsByRecipients : subscribedRecipients.asMap().entrySet()) {
       String userLogin = channelsByRecipients.getKey();
index 20998f7e012885c99faa6662a17075d9a61b1ce0..d7fd1c0b7f5a9932b1bb7f6f1821578be5fe24bf 100644 (file)
@@ -26,17 +26,18 @@ import com.google.common.collect.Multimap;
 import java.io.IOException;
 import java.io.InvalidClassException;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import javax.annotation.Nullable;
 import org.sonar.api.notifications.Notification;
 import org.sonar.api.notifications.NotificationChannel;
 import org.sonar.api.utils.SonarException;
 import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
-import org.sonar.api.web.UserRole;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.notification.NotificationQueueDto;
@@ -117,7 +118,8 @@ public class DefaultNotificationManager implements NotificationManager {
    * {@inheritDoc}
    */
   @Override
-  public Multimap<String, NotificationChannel> findSubscribedRecipientsForDispatcher(NotificationDispatcher dispatcher, String projectUuid) {
+  public Multimap<String, NotificationChannel> findSubscribedRecipientsForDispatcher(NotificationDispatcher dispatcher, String projectUuid,
+    SubscriberPermissionsOnProject subscriberPermissionsOnProject) {
     requireNonNull(projectUuid, "ProjectUUID is mandatory");
     String dispatcherKey = dispatcher.getKey();
 
@@ -131,7 +133,7 @@ public class DefaultNotificationManager implements NotificationManager {
 
     ImmutableSetMultimap.Builder<String, NotificationChannel> builder = ImmutableSetMultimap.builder();
     try (DbSession dbSession = dbClient.openSession(false)) {
-      Set<String> authorizedLogins = keepAuthorizedLogins(projectUuid, subscriberAndChannels, dbSession);
+      Set<String> authorizedLogins = keepAuthorizedLogins(dbSession, projectUuid, subscriberAndChannels, subscriberPermissionsOnProject);
       subscriberAndChannels.stream()
         .filter(subscriberAndChannel -> authorizedLogins.contains(subscriberAndChannel.getSubscriber().getLogin()))
         .forEach(subscriberAndChannel -> builder.put(subscriberAndChannel.getSubscriber().getLogin(), subscriberAndChannel.getChannel()));
@@ -140,20 +142,38 @@ public class DefaultNotificationManager implements NotificationManager {
   }
 
   private Stream<SubscriberAndChannel> toSubscriberAndChannels(String dispatcherKey, String projectUuid, NotificationChannel notificationChannel) {
-    return dbClient.propertiesDao().findUsersForNotification(dispatcherKey, notificationChannel.getKey(), projectUuid)
+    Set<Subscriber> usersForNotification = dbClient.propertiesDao().findUsersForNotification(dispatcherKey, notificationChannel.getKey(), projectUuid);
+    return usersForNotification
       .stream()
       .map(login -> new SubscriberAndChannel(login, notificationChannel));
   }
 
-  private Set<String> keepAuthorizedLogins(String projectUuid, Set<SubscriberAndChannel> subscriberAndChannels, DbSession dbSession) {
+  private Set<String> keepAuthorizedLogins(DbSession dbSession, String projectUuid, Set<SubscriberAndChannel> subscriberAndChannels,
+    SubscriberPermissionsOnProject requiredPermissions) {
+    if (requiredPermissions.getGlobalSubscribers().equals(requiredPermissions.getProjectSubscribers())) {
+      return keepAuthorizedLogins(dbSession, projectUuid, subscriberAndChannels, null, requiredPermissions.getGlobalSubscribers());
+    } else {
+      return Stream
+        .concat(
+          keepAuthorizedLogins(dbSession, projectUuid, subscriberAndChannels, true, requiredPermissions.getGlobalSubscribers()).stream(),
+          keepAuthorizedLogins(dbSession, projectUuid, subscriberAndChannels, false, requiredPermissions.getProjectSubscribers()).stream())
+        .collect(Collectors.toSet());
+    }
+  }
+
+  private Set<String> keepAuthorizedLogins(DbSession dbSession, String projectUuid, Set<SubscriberAndChannel> subscriberAndChannels,
+    @Nullable Boolean global, String permission) {
     Set<String> logins = subscriberAndChannels.stream()
-      .map(DefaultNotificationManager.SubscriberAndChannel::getSubscriber)
-      .map(Subscriber::getLogin)
+      .filter(s -> global == null || s.getSubscriber().isGlobal() == global)
+      .map(s -> s.getSubscriber().getLogin())
       .collect(Collectors.toSet());
-    return dbClient.authorizationDao().keepAuthorizedLoginsOnProject(dbSession, logins, projectUuid, UserRole.USER);
+    if (logins.isEmpty()) {
+      return Collections.emptySet();
+    }
+    return dbClient.authorizationDao().keepAuthorizedLoginsOnProject(dbSession, logins, projectUuid, permission);
   }
 
-  private final class SubscriberAndChannel {
+  private static final class SubscriberAndChannel {
     private final Subscriber subscriber;
     private final NotificationChannel channel;
 
@@ -162,11 +182,11 @@ public class DefaultNotificationManager implements NotificationManager {
       this.channel = channel;
     }
 
-    public Subscriber getSubscriber() {
+    Subscriber getSubscriber() {
       return subscriber;
     }
 
-    public NotificationChannel getChannel() {
+    NotificationChannel getChannel() {
       return channel;
     }
 
index e06c4083d648a1b7e799f7f1a8284971f7216cfb..59fc67cfa7995c913b7b5c51be055dd2df6c8ef4 100644 (file)
 package org.sonar.server.notification;
 
 import com.google.common.collect.Multimap;
+import java.util.Objects;
 import org.sonar.api.notifications.Notification;
 import org.sonar.api.notifications.NotificationChannel;
+import org.sonar.api.web.UserRole;
+
+import static java.util.Objects.requireNonNull;
 
 /**
  * The notification manager receives notifications and is in charge of storing them so that they are processed by the notification service.
@@ -50,7 +54,51 @@ public interface NotificationManager {
    *
    * @param dispatcher the dispatcher for which this list of users is requested
    * @param projectUuid UUID of the project
+   * @param subscriberPermissionsOnProject the required permission for global and project subscribers
+   *
    * @return the list of user login along with the subscribed channels
    */
-  Multimap<String, NotificationChannel> findSubscribedRecipientsForDispatcher(NotificationDispatcher dispatcher, String projectUuid);
+  Multimap<String, NotificationChannel> findSubscribedRecipientsForDispatcher(NotificationDispatcher dispatcher, String projectUuid,
+    SubscriberPermissionsOnProject subscriberPermissionsOnProject);
+
+  final class SubscriberPermissionsOnProject {
+    public static final SubscriberPermissionsOnProject ALL_MUST_HAVE_ROLE_USER = new SubscriberPermissionsOnProject(UserRole.USER);
+
+    private final String globalSubscribers;
+    private final String projectSubscribers;
+
+    public SubscriberPermissionsOnProject(String globalAndProjectSubscribers) {
+      this(globalAndProjectSubscribers, globalAndProjectSubscribers);
+    }
+
+    public SubscriberPermissionsOnProject(String globalSubscribers, String projectSubscribers) {
+      this.globalSubscribers = requireNonNull(globalSubscribers, "global subscribers's required permission can't be null");
+      this.projectSubscribers = requireNonNull(projectSubscribers, "project subscribers's required permission can't be null");
+    }
+
+    public String getGlobalSubscribers() {
+      return globalSubscribers;
+    }
+
+    public String getProjectSubscribers() {
+      return projectSubscribers;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (this == o) {
+        return true;
+      }
+      if (o == null || getClass() != o.getClass()) {
+        return false;
+      }
+      SubscriberPermissionsOnProject that = (SubscriberPermissionsOnProject) o;
+      return globalSubscribers.equals(that.globalSubscribers) && projectSubscribers.equals(that.projectSubscribers);
+    }
+
+    @Override
+    public int hashCode() {
+      return Objects.hash(globalSubscribers, projectSubscribers);
+    }
+  }
 }
index f842b17506f6a47e37fd6da25b53aaefe7fcee56..92c233a8fc841e97b88f3482bd47d8cc6d3e4e9c 100644 (file)
@@ -23,6 +23,7 @@ import com.google.common.collect.HashMultimap;
 import org.junit.Test;
 import org.sonar.api.notifications.Notification;
 import org.sonar.api.notifications.NotificationChannel;
+import org.sonar.api.web.UserRole;
 import org.sonar.server.notification.NotificationDispatcher;
 import org.sonar.server.notification.NotificationDispatcherMetadata;
 import org.sonar.server.notification.NotificationManager;
@@ -88,7 +89,7 @@ public class ReportAnalysisFailureNotificationDispatcherTest {
     multimap.put(login1, channel2);
     multimap.put(login2, channel2);
     multimap.put(login2, channel3);
-    when(notificationManager.findSubscribedRecipientsForDispatcher(underTest, projectUuid))
+    when(notificationManager.findSubscribedRecipientsForDispatcher(underTest, projectUuid, new NotificationManager.SubscriberPermissionsOnProject(UserRole.USER)))
       .thenReturn(multimap);
 
     underTest.performDispatch(notificationMock, contextMock);
@@ -106,7 +107,7 @@ public class ReportAnalysisFailureNotificationDispatcherTest {
     String projectUuid = randomAlphanumeric(9);
     when(notificationMock.getFieldValue("project.uuid")).thenReturn(projectUuid);
     HashMultimap<String, NotificationChannel> multimap = HashMultimap.create();
-    when(notificationManager.findSubscribedRecipientsForDispatcher(underTest, projectUuid))
+    when(notificationManager.findSubscribedRecipientsForDispatcher(underTest, projectUuid, new NotificationManager.SubscriberPermissionsOnProject(UserRole.USER)))
       .thenReturn(multimap);
 
     underTest.performDispatch(notificationMock, contextMock);
index c3cc294cca3346c80dbb7e2beffa74fa0abb3043..bb20ef863d9e9c3ee31c7e59c6c98d92076ca475 100644 (file)
@@ -24,6 +24,7 @@ import com.google.common.collect.Multimap;
 import org.junit.Test;
 import org.sonar.api.notifications.Notification;
 import org.sonar.api.notifications.NotificationChannel;
+import org.sonar.api.web.UserRole;
 import org.sonar.server.notification.NotificationDispatcher;
 import org.sonar.server.notification.NotificationManager;
 
@@ -50,7 +51,7 @@ public class NewAlertsTest {
     Multimap<String, NotificationChannel> recipients = HashMultimap.create();
     recipients.put("user1", emailChannel);
     recipients.put("user2", twitterChannel);
-    when(notificationManager.findSubscribedRecipientsForDispatcher(dispatcher, "uuid_34")).thenReturn(recipients);
+    when(notificationManager.findSubscribedRecipientsForDispatcher(dispatcher, "uuid_34", new NotificationManager.SubscriberPermissionsOnProject(UserRole.USER))).thenReturn(recipients);
 
     Notification notification = new Notification("alerts").setFieldValue("projectUuid", "uuid_34");
     dispatcher.performDispatch(notification, context);
@@ -65,7 +66,7 @@ public class NewAlertsTest {
     Multimap<String, NotificationChannel> recipients = HashMultimap.create();
     recipients.put("user1", emailChannel);
     recipients.put("user2", twitterChannel);
-    when(notificationManager.findSubscribedRecipientsForDispatcher(dispatcher, "uuid_34")).thenReturn(recipients);
+    when(notificationManager.findSubscribedRecipientsForDispatcher(dispatcher, "uuid_34", new NotificationManager.SubscriberPermissionsOnProject(UserRole.USER))).thenReturn(recipients);
 
     Notification notification = new Notification("alerts");
     dispatcher.performDispatch(notification, context);
index fc2b0fc13a2108a844848a03cceae73a54e269fe..e58a9a71a60966dc2af2c33b33835c60c13cf50c 100644 (file)
@@ -28,6 +28,7 @@ import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
 import org.sonar.api.notifications.Notification;
 import org.sonar.api.notifications.NotificationChannel;
+import org.sonar.api.web.UserRole;
 import org.sonar.server.notification.NotificationDispatcher;
 import org.sonar.server.notification.NotificationDispatcherMetadata;
 import org.sonar.server.notification.NotificationManager;
@@ -83,7 +84,8 @@ public class ChangesOnMyIssueNotificationDispatcherTest {
     recipients.put("simon", emailChannel);
     recipients.put("freddy", twitterChannel);
     recipients.put("godin", twitterChannel);
-    when(notifications.findSubscribedRecipientsForDispatcher(dispatcher, "uuid1")).thenReturn(recipients);
+    when(notifications.findSubscribedRecipientsForDispatcher(dispatcher, "uuid1",
+        new NotificationManager.SubscriberPermissionsOnProject(UserRole.USER))).thenReturn(recipients);
 
     Notification notification = new IssueChangeNotification()
       .setFieldValue("projectKey", "struts")
@@ -103,7 +105,7 @@ public class ChangesOnMyIssueNotificationDispatcherTest {
     recipients.put("simon", emailChannel);
     recipients.put("freddy", twitterChannel);
     recipients.put("godin", twitterChannel);
-    when(notifications.findSubscribedRecipientsForDispatcher(dispatcher, "uuid1")).thenReturn(recipients);
+    when(notifications.findSubscribedRecipientsForDispatcher(dispatcher, "uuid1", new NotificationManager.SubscriberPermissionsOnProject(UserRole.USER))).thenReturn(recipients);
 
     // change author is the assignee
     dispatcher.performDispatch(
index aaaf004ffb248dc042d562d859d9364ec3203466..c1467623791e92122c702452de017344da39ebf1 100644 (file)
@@ -25,6 +25,7 @@ import org.junit.Test;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.notifications.Notification;
 import org.sonar.api.notifications.NotificationChannel;
+import org.sonar.api.web.UserRole;
 import org.sonar.server.notification.NotificationDispatcher;
 import org.sonar.server.notification.NotificationDispatcherMetadata;
 import org.sonar.server.notification.NotificationManager;
@@ -61,7 +62,7 @@ public class DoNotFixNotificationDispatcherTest {
     recipients.put("simon", emailChannel);
     recipients.put("freddy", twitterChannel);
     recipients.put("godin", twitterChannel);
-    when(notifications.findSubscribedRecipientsForDispatcher(underTest, "uuid1")).thenReturn(recipients);
+    when(notifications.findSubscribedRecipientsForDispatcher(underTest, "uuid1", new NotificationManager.SubscriberPermissionsOnProject(UserRole.USER))).thenReturn(recipients);
 
     Notification fpNotif = new IssueChangeNotification().setFieldValue("projectKey", "struts")
       .setFieldValue("projectUuid", "uuid1")
index 1ef6e596dbec8714fa324db1ce21747ee865909f..cb5f38c7f7a294ffc53afb214ccafba5fd0f37c7 100644 (file)
@@ -25,6 +25,7 @@ import org.junit.Before;
 import org.junit.Test;
 import org.sonar.api.notifications.Notification;
 import org.sonar.api.notifications.NotificationChannel;
+import org.sonar.api.web.UserRole;
 import org.sonar.server.notification.NotificationDispatcher;
 import org.sonar.server.notification.NotificationManager;
 
@@ -58,7 +59,7 @@ public class MyNewIssuesNotificationDispatcherTest {
     Multimap<String, NotificationChannel> recipients = HashMultimap.create();
     recipients.put("user1", emailChannel);
     recipients.put("user2", twitterChannel);
-    when(notificationManager.findSubscribedRecipientsForDispatcher(underTest, "uuid1")).thenReturn(recipients);
+    when(notificationManager.findSubscribedRecipientsForDispatcher(underTest, "uuid1", new NotificationManager.SubscriberPermissionsOnProject(UserRole.USER))).thenReturn(recipients);
 
     Notification notification = new Notification(MyNewIssuesNotification.MY_NEW_ISSUES_NOTIF_TYPE)
       .setFieldValue("projectKey", "struts")
index 54905e244f0baa76bff5d65d056a93c9406e2af8..c59fc50191be0d65d17c485d4d70d552655541c1 100644 (file)
@@ -25,6 +25,7 @@ import org.junit.Before;
 import org.junit.Test;
 import org.sonar.api.notifications.Notification;
 import org.sonar.api.notifications.NotificationChannel;
+import org.sonar.api.web.UserRole;
 import org.sonar.server.notification.NotificationDispatcher;
 import org.sonar.server.notification.NotificationManager;
 
@@ -56,7 +57,7 @@ public class NewIssuesNotificationDispatcherTest {
     Multimap<String, NotificationChannel> recipients = HashMultimap.create();
     recipients.put("user1", emailChannel);
     recipients.put("user2", twitterChannel);
-    when(notifications.findSubscribedRecipientsForDispatcher(dispatcher, "uuid1")).thenReturn(recipients);
+    when(notifications.findSubscribedRecipientsForDispatcher(dispatcher, "uuid1", new NotificationManager.SubscriberPermissionsOnProject(UserRole.USER))).thenReturn(recipients);
 
     Notification notification = new Notification(NewIssuesNotification.TYPE)
       .setFieldValue("projectKey", "struts")
index 7d16cba9a05f3101961552c834cd4407a76c399e..e4f6b7b3c554b298002b97b2b7a4de0f9ecfb143 100644 (file)
@@ -25,28 +25,28 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import org.apache.commons.lang.RandomStringUtils;
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
 import org.mockito.InOrder;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 import org.sonar.api.notifications.Notification;
 import org.sonar.api.notifications.NotificationChannel;
-import org.sonar.api.utils.System2;
+import org.sonar.api.web.UserRole;
 import org.sonar.db.DbClient;
-import org.sonar.db.DbTester;
+import org.sonar.db.DbSession;
 import org.sonar.db.notification.NotificationQueueDao;
 import org.sonar.db.notification.NotificationQueueDto;
 import org.sonar.db.permission.AuthorizationDao;
 import org.sonar.db.property.PropertiesDao;
 import org.sonar.db.property.Subscriber;
+import org.sonar.server.notification.NotificationManager.SubscriberPermissionsOnProject;
 
 import static com.google.common.collect.Sets.newHashSet;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anySet;
+import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
@@ -60,39 +60,21 @@ public class DefaultNotificationManagerTest {
 
   private DefaultNotificationManager underTest;
 
-  @Rule
-  public DbTester db = DbTester.create(System2.INSTANCE);
-
-  @Mock
-  private PropertiesDao propertiesDao;
-
-  @Mock
-  private NotificationDispatcher dispatcher;
-
-  @Mock
-  private NotificationChannel emailChannel;
-
-  @Mock
-  private NotificationChannel twitterChannel;
-
-  @Mock
-  private NotificationQueueDao notificationQueueDao;
-
-  @Mock
-  private AuthorizationDao authorizationDao;
-
-  @Mock
-  private DbClient dbClient;
-
-  @Captor
-  private ArgumentCaptor<List<String>> captorLogins;
+  private PropertiesDao propertiesDao = mock(PropertiesDao.class);
+  private NotificationDispatcher dispatcher = mock(NotificationDispatcher.class);
+  private NotificationChannel emailChannel = mock(NotificationChannel.class);
+  private NotificationChannel twitterChannel = mock(NotificationChannel.class);
+  private NotificationQueueDao notificationQueueDao = mock(NotificationQueueDao.class);
+  private AuthorizationDao authorizationDao = mock(AuthorizationDao.class);
+  private DbClient dbClient = mock(DbClient.class);
+  private DbSession dbSession = mock(DbSession.class);
 
   @Before
   public void setUp() {
-    MockitoAnnotations.initMocks(this);
     when(dispatcher.getKey()).thenReturn("NewViolations");
     when(emailChannel.getKey()).thenReturn("Email");
     when(twitterChannel.getKey()).thenReturn("Twitter");
+    when(dbClient.openSession(anyBoolean())).thenReturn(dbSession);
     when(dbClient.propertiesDao()).thenReturn(propertiesDao);
     when(dbClient.notificationQueueDao()).thenReturn(notificationQueueDao);
     when(dbClient.authorizationDao()).thenReturn(authorizationDao);
@@ -104,7 +86,7 @@ public class DefaultNotificationManagerTest {
   public void shouldProvideChannelList() {
     assertThat(underTest.getChannels()).containsOnly(emailChannel, twitterChannel);
 
-    underTest = new DefaultNotificationManager(new NotificationChannel[] {}, db.getDbClient());
+    underTest = new DefaultNotificationManager(new NotificationChannel[] {}, dbClient);
     assertThat(underTest.getChannels()).hasSize(0);
   }
 
@@ -147,26 +129,60 @@ public class DefaultNotificationManagerTest {
 
   @Test
   public void shouldFindNoRecipient() {
-    assertThat(underTest.findSubscribedRecipientsForDispatcher(dispatcher, "uuid_45").asMap().entrySet()).hasSize(0);
+    assertThat(underTest.findSubscribedRecipientsForDispatcher(dispatcher, "uuid_45", new SubscriberPermissionsOnProject(UserRole.USER)).asMap().entrySet())
+      .hasSize(0);
   }
 
   @Test
   public void shouldFindSubscribedRecipientForGivenResource() {
-    when(propertiesDao.findUsersForNotification("NewViolations", "Email", "uuid_45"))
+    String projectUuid = "uuid_45";
+    when(propertiesDao.findUsersForNotification("NewViolations", "Email", projectUuid))
       .thenReturn(newHashSet(new Subscriber("user1", false), new Subscriber("user3", false), new Subscriber("user3", true)));
     when(propertiesDao.findUsersForNotification("NewViolations", "Twitter", "uuid_56"))
       .thenReturn(newHashSet(new Subscriber("user2", false)));
-    when(propertiesDao.findUsersForNotification("NewViolations", "Twitter", "uuid_45"))
+    when(propertiesDao.findUsersForNotification("NewViolations", "Twitter", projectUuid))
       .thenReturn(newHashSet(new Subscriber("user3", true)));
-    when(propertiesDao.findUsersForNotification("NewAlerts", "Twitter", "uuid_45"))
+    when(propertiesDao.findUsersForNotification("NewAlerts", "Twitter", projectUuid))
       .thenReturn(newHashSet(new Subscriber("user4", false)));
 
-    when(authorizationDao.keepAuthorizedLoginsOnProject(any(), eq(newHashSet("user1", "user3")), eq("uuid_45"), eq("user")))
+    when(authorizationDao.keepAuthorizedLoginsOnProject(dbSession, newHashSet("user1", "user3"), projectUuid, "user"))
       .thenReturn(newHashSet("user1", "user3"));
-    when(authorizationDao.keepAuthorizedLoginsOnProject(any(), eq(newHashSet("user3")), eq("uuid_45"), eq("user")))
+
+    Multimap<String, NotificationChannel> multiMap = underTest.findSubscribedRecipientsForDispatcher(dispatcher, projectUuid,
+      SubscriberPermissionsOnProject.ALL_MUST_HAVE_ROLE_USER);
+    assertThat(multiMap.entries()).hasSize(3);
+
+    Map<String, Collection<NotificationChannel>> map = multiMap.asMap();
+    assertThat(map.get("user1")).containsOnly(emailChannel);
+    assertThat(map.get("user2")).isNull();
+    assertThat(map.get("user3")).containsOnly(emailChannel, twitterChannel);
+    assertThat(map.get("user4")).isNull();
+
+    // code is optimized to perform only 1 SQL requests for all channels
+    verify(authorizationDao, times(1)).keepAuthorizedLoginsOnProject(eq(dbSession), anySet(), anyString(), anyString());
+  }
+
+  @Test
+  public void should_apply_distinct_permission_filtering_global_or_project_subscribers() {
+    String globalPermission = RandomStringUtils.randomAlphanumeric(4);
+    String projectPermission = RandomStringUtils.randomAlphanumeric(5);
+    String projectUuid = "uuid_45";
+    when(propertiesDao.findUsersForNotification("NewViolations", "Email", projectUuid))
+      .thenReturn(newHashSet(new Subscriber("user1", false), new Subscriber("user3", false), new Subscriber("user3", true)));
+    when(propertiesDao.findUsersForNotification("NewViolations", "Twitter", "uuid_56"))
+      .thenReturn(newHashSet(new Subscriber("user2", false)));
+    when(propertiesDao.findUsersForNotification("NewViolations", "Twitter", projectUuid))
+      .thenReturn(newHashSet(new Subscriber("user3", true)));
+    when(propertiesDao.findUsersForNotification("NewAlerts", "Twitter", projectUuid))
+      .thenReturn(newHashSet(new Subscriber("user4", false)));
+
+    when(authorizationDao.keepAuthorizedLoginsOnProject(dbSession, newHashSet("user3", "user4"), projectUuid, globalPermission))
       .thenReturn(newHashSet("user3"));
+    when(authorizationDao.keepAuthorizedLoginsOnProject(dbSession, newHashSet("user1", "user3"), projectUuid, projectPermission))
+      .thenReturn(newHashSet("user1", "user3"));
 
-    Multimap<String, NotificationChannel> multiMap = underTest.findSubscribedRecipientsForDispatcher(dispatcher, "uuid_45");
+    Multimap<String, NotificationChannel> multiMap = underTest.findSubscribedRecipientsForDispatcher(dispatcher, projectUuid,
+      new SubscriberPermissionsOnProject(globalPermission, projectPermission));
     assertThat(multiMap.entries()).hasSize(3);
 
     Map<String, Collection<NotificationChannel>> map = multiMap.asMap();
@@ -174,5 +190,57 @@ public class DefaultNotificationManagerTest {
     assertThat(map.get("user2")).isNull();
     assertThat(map.get("user3")).containsOnly(emailChannel, twitterChannel);
     assertThat(map.get("user4")).isNull();
+
+    // code is optimized to perform only 2 SQL requests for all channels
+    verify(authorizationDao, times(1)).keepAuthorizedLoginsOnProject(eq(dbSession), anySet(), anyString(), eq(globalPermission));
+    verify(authorizationDao, times(1)).keepAuthorizedLoginsOnProject(eq(dbSession), anySet(), anyString(), eq(projectPermission));
+  }
+
+  @Test
+  public void do_not_call_db_for_project_permission_filtering_if_there_is_no_project_subscriber() {
+    String globalPermission = RandomStringUtils.randomAlphanumeric(4);
+    String projectPermission = RandomStringUtils.randomAlphanumeric(5);
+    String projectUuid = "uuid_45";
+    when(propertiesDao.findUsersForNotification("NewViolations", "Email", projectUuid))
+        .thenReturn(newHashSet(new Subscriber("user3", true)));
+    when(propertiesDao.findUsersForNotification("NewViolations", "Twitter", projectUuid))
+        .thenReturn(newHashSet(new Subscriber("user3", true)));
+
+    when(authorizationDao.keepAuthorizedLoginsOnProject(dbSession, newHashSet("user3"), projectUuid, globalPermission))
+        .thenReturn(newHashSet("user3"));
+
+    Multimap<String, NotificationChannel> multiMap = underTest.findSubscribedRecipientsForDispatcher(dispatcher, projectUuid,
+        new SubscriberPermissionsOnProject(globalPermission, projectPermission));
+    assertThat(multiMap.entries()).hasSize(2);
+
+    Map<String, Collection<NotificationChannel>> map = multiMap.asMap();
+    assertThat(map.get("user3")).containsOnly(emailChannel, twitterChannel);
+
+    verify(authorizationDao, times(1)).keepAuthorizedLoginsOnProject(eq(dbSession), anySet(), anyString(), eq(globalPermission));
+    verify(authorizationDao, times(0)).keepAuthorizedLoginsOnProject(eq(dbSession), anySet(), anyString(), eq(projectPermission));
+  }
+
+  @Test
+  public void do_not_call_db_for_project_permission_filtering_if_there_is_no_global_subscriber() {
+    String globalPermission = RandomStringUtils.randomAlphanumeric(4);
+    String projectPermission = RandomStringUtils.randomAlphanumeric(5);
+    String projectUuid = "uuid_45";
+    when(propertiesDao.findUsersForNotification("NewViolations", "Email", projectUuid))
+        .thenReturn(newHashSet(new Subscriber("user3", false)));
+    when(propertiesDao.findUsersForNotification("NewViolations", "Twitter", projectUuid))
+        .thenReturn(newHashSet(new Subscriber("user3", false)));
+
+    when(authorizationDao.keepAuthorizedLoginsOnProject(dbSession, newHashSet("user3"), projectUuid, projectPermission))
+        .thenReturn(newHashSet("user3"));
+
+    Multimap<String, NotificationChannel> multiMap = underTest.findSubscribedRecipientsForDispatcher(dispatcher, projectUuid,
+        new SubscriberPermissionsOnProject(globalPermission, projectPermission));
+    assertThat(multiMap.entries()).hasSize(2);
+
+    Map<String, Collection<NotificationChannel>> map = multiMap.asMap();
+    assertThat(map.get("user3")).containsOnly(emailChannel, twitterChannel);
+
+    verify(authorizationDao, times(0)).keepAuthorizedLoginsOnProject(eq(dbSession), anySet(), anyString(), eq(globalPermission));
+    verify(authorizationDao, times(1)).keepAuthorizedLoginsOnProject(eq(dbSession), anySet(), anyString(), eq(projectPermission));
   }
 }