]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-4824 Prevent notification when user does not have Browse permission
authorEric Hartmann <hartmann.eric@gmail.com>
Wed, 13 Sep 2017 15:23:33 +0000 (17:23 +0200)
committerEric Hartmann <hartmann.eric@gmail.Com>
Mon, 2 Oct 2017 11:03:35 +0000 (13:03 +0200)
27 files changed:
server/sonar-db-dao/src/main/java/org/sonar/db/permission/AuthorizationDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/permission/AuthorizationMapper.java
server/sonar-db-dao/src/main/java/org/sonar/db/property/PropertiesDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/property/PropertiesMapper.java
server/sonar-db-dao/src/main/resources/org/sonar/db/permission/AuthorizationMapper.xml
server/sonar-db-dao/src/main/resources/org/sonar/db/property/PropertiesMapper.xml
server/sonar-db-dao/src/test/java/org/sonar/db/permission/AuthorizationDaoTest.java
server/sonar-db-dao/src/test/java/org/sonar/db/property/PropertiesDaoTest.java
server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/SendIssueNotificationsStep.java
server/sonar-server/src/main/java/org/sonar/server/issue/IssueUpdater.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/IssueChangeNotification.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/server/issue/IssueUpdaterTest.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/IssueChangeNotificationTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/notification/IssueChangesEmailTemplateTest.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/issue/ws/BulkChangeActionTest.java
server/sonar-server/src/test/java/org/sonar/server/notification/DefaultNotificationManagerTest.java
sonar-plugin-api/src/test/java/org/sonar/api/config/ConfigurationTest.java

index d92a139a1b5c6439f83027518f405922f62f7d2b..56ff394b3eb06bdef0080431cc7942e95f404ecb 100644 (file)
@@ -177,6 +177,13 @@ public class AuthorizationDao implements Dao {
     return mapper(dbSession).selectLoginsWithGlobalPermission(ADMINISTER.getKey());
   }
 
+  public Set<String> keepAuthorizedLoginsOnProject(DbSession dbSession, Set<String> logins, String projectUuid, String permission) {
+    return executeLargeInputsIntoSet(
+      logins,
+      partitionOfLogins -> mapper(dbSession).keepAuthorizedLoginsOnProject(partitionOfLogins, projectUuid, permission),
+      partitionSize -> partitionSize / 3);
+  }
+
   private static AuthorizationMapper mapper(DbSession dbSession) {
     return dbSession.getMapper(AuthorizationMapper.class);
   }
index da8ecbb5356a76169b916f81a5304d3b27da97cf..1c788ea1019947cf6cbead8ed5bf63b4c2bead54 100644 (file)
@@ -61,5 +61,9 @@ public interface AuthorizationMapper {
 
   Set<String> selectProjectPermissionsOfAnonymous(@Param("projectUuid") String projectUuid);
 
+  List<String> selectQualityProfileAdministratorLogins(@Param("permission") String permission);
+
+  Set<String> keepAuthorizedLoginsOnProject(@Param("logins") List<String> logins, @Param("projectUuid") String projectUuid, @Param("permission") String permission);
+
   List<String> selectLoginsWithGlobalPermission(@Param("permission") String permission);
 }
index f12f1027cfb3222573315db21da28306c7993ac5..4ee315136086149920f1466df01cd8da2628d68b 100644 (file)
@@ -32,6 +32,7 @@ import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.sonar.api.resources.Scopes;
 import org.sonar.api.utils.System2;
+import org.sonar.api.web.UserRole;
 import org.sonar.db.Dao;
 import org.sonar.db.DbSession;
 import org.sonar.db.MyBatis;
@@ -60,20 +61,17 @@ public class PropertiesDao implements Dao {
    * Returns the logins of users who have subscribed to the given notification dispatcher with the given notification channel.
    * If a resource ID is passed, the search is made on users who have specifically subscribed for the given resource.
    *
+   * Note that {@link  UserRole#USER} permission is not checked here, filter the results with
+   * {@link org.sonar.db.permission.AuthorizationDao#keepAuthorizedLoginsOnProject}
+   *
    * @return the list of logins (maybe be empty - obviously)
    */
-  public List<String> selectUsersForNotification(String notificationDispatcherKey, String notificationChannelKey, @Nullable String projectUuid) {
+  public Set<String> findUsersForNotification(String notificationDispatcherKey, String notificationChannelKey, @Nullable String projectUuid) {
     try (DbSession session = mybatis.openSession(false)) {
       return getMapper(session).findUsersForNotification(NOTIFICATION_PREFIX + notificationDispatcherKey + "." + notificationChannelKey, projectUuid);
     }
   }
 
-  public List<String> selectNotificationSubscribers(String notificationDispatcherKey, String notificationChannelKey, @Nullable String componentKey) {
-    try (DbSession session = mybatis.openSession(false)) {
-      return getMapper(session).findNotificationSubscribers(NOTIFICATION_PREFIX + notificationDispatcherKey + "." + notificationChannelKey, componentKey);
-    }
-  }
-
   public boolean hasProjectNotificationSubscribersForDispatchers(String projectUuid, Collection<String> dispatcherKeys) {
     try (DbSession session = mybatis.openSession(false);
       Connection connection = session.getConnection();
index ac422e3cd1deafb07f650c4b5750f996e4773528..b15395951f9409db4a8b6eaf53c6183c6aa0bece 100644 (file)
 package org.sonar.db.property;
 
 import java.util.List;
+import java.util.Set;
 import javax.annotation.Nullable;
 import org.apache.ibatis.annotations.Param;
 
 public interface PropertiesMapper {
 
-  List<String> findUsersForNotification(@Param("notifKey") String notificationKey, @Nullable @Param("projectUuid") String projectUuid);
-
-  List<String> findNotificationSubscribers(@Param("propKey") String propertyKey, @Nullable @Param("componentKey") String componentKey);
+  Set<String> findUsersForNotification(@Param("notifKey") String notificationKey, @Nullable @Param("projectUuid") String projectUuid);
 
   List<PropertyDto> selectGlobalProperties();
 
index 072fefe4e3d04b88507b07f5ad843abc8d7afc99..b43ede52e6932423d0e0ee86ae840685571ac856 100644 (file)
     gr.role = #{permission,jdbcType=VARCHAR} and
     gr.group_id is not null
   </select>
+
+  <select id="keepAuthorizedLoginsOnProject" parameterType="map" resultType="String">
+      SELECT u.login
+      FROM users u
+      INNER JOIN user_roles ur ON ur.user_id = u.id
+      INNER JOIN projects p ON p.uuid = #{projectUuid,jdbcType=VARCHAR}
+      WHERE
+        ur.organization_uuid = p.organization_uuid
+        AND ur.resource_id = p.id
+        AND ur.role = #{permission,jdbcType=VARCHAR}
+        AND u.login IN <foreach collection="logins" open="(" close=")" item="login" separator=",">#{login}</foreach>
+
+      UNION
+
+      SELECT u.login
+      FROM users u
+      INNER JOIN projects p ON p.uuid = #{projectUuid,jdbcType=VARCHAR}
+      INNER JOIN group_roles gr ON gr.organization_uuid = p.organization_uuid
+      INNER JOIN groups_users gu ON gr.group_id = gu.group_id
+      WHERE
+        gu.user_id = u.id
+        AND gr.role = #{permission,jdbcType=VARCHAR}
+        AND u.login IN <foreach collection="logins" open="(" close=")" item="login" separator=",">#{login}</foreach>
+
+    <if test="permission == 'user' or permission == 'codeviewer'">
+      UNION
+
+      SELECT u.login
+      FROM users u
+      INNER JOIN projects p ON p.uuid = #{projectUuid,jdbcType=VARCHAR}
+      WHERE
+        p.private = ${_false}
+        AND u.login IN <foreach collection="logins" open="(" close=")" item="login" separator=",">#{login}</foreach>
+    </if>
+  </select>
 </mapper>
index a9a520eb1ee1cae00c0837246bae628235edb775..43c4ee3a8d73e41f16036ed4a657a6b7c00abc73 100644 (file)
@@ -3,51 +3,30 @@
 
 <mapper namespace="org.sonar.db.property.PropertiesMapper">
 
-  <select id="findUsersForNotification" parameterType="map" resultType="String">
-    select
+  <select id="findUsersForNotification" parameterType="map" resultType="java.lang.String">
+    SELECT
       u.login
-    from
+    FROM
       users u
-    inner join properties p on
-      p.user_id=u.id
-    <choose>
-      <when test="projectUuid == null">
-        where
-          p.prop_key = #{notifKey,jdbcType=VARCHAR}
-          and p.text_value = 'true'
-          and p.resource_id is null
-      </when>
-      <otherwise>
-        inner join projects c on
-          c.id=p.resource_id
-        where
-          p.prop_key = #{notifKey,jdbcType=VARCHAR}
-          and p.text_value = 'true'
-          and c.uuid = #{projectUuid,jdbcType=VARCHAR}
-          and p.resource_id is not null
-      </otherwise>
-    </choose>
-  </select>
+    INNER JOIN properties p ON p.user_id = u.id
+    WHERE
+      p.prop_key = #{notifKey,jdbcType=VARCHAR}
+      AND p.text_value = 'true'
+      AND p.resource_id IS NULL
 
-  <select id="findNotificationSubscribers" parameterType="map" resultType="String">
-    select
+    UNION
+
+    SELECT
       u.login
-    from
-      properties p
-    inner join users u on
-      p.user_id = u.id
-      <if test="componentKey != null">
-        left outer join projects p1 on p.resource_id=p1.id and p1.kee=#{componentKey,jdbcType=VARCHAR}
-      </if>
-    where
-      p.prop_key = #{propKey,jdbcType=VARCHAR}
-      and p.text_value like 'true'
-      and (
-        p.resource_id is null
-        <if test="componentKey != null">
-          or p.resource_id=p1.id
-        </if>
-      )
+    FROM
+      users u
+    INNER JOIN projects c on c.uuid = #{projectUuid,jdbcType=VARCHAR}
+    INNER JOIN properties p ON p.user_id = u.id
+    WHERE
+      p.prop_key = #{notifKey,jdbcType=VARCHAR}
+      AND p.text_value = 'true'
+      AND p.resource_id = c.id
+
   </select>
 
   <sql id="columnsToScrapPropertyDto">
index 36595bc5d72ddd909dc9eee08f363a8eca8fe9cc..693266f67228d7cf892b47bccdf24567fbad72b7 100644 (file)
@@ -1028,4 +1028,69 @@ public class AuthorizationDaoTest {
     assertThat(logins).containsExactlyInAnyOrder(user1.getLogin(), user2.getLogin(), user3.getLogin());
   }
 
+  @Test
+  public void keepAuthorizedLoginsOnProject_return_correct_users_on_public_project() {
+    ComponentDto project = db.components().insertPublicProject(organization);
+
+    UserDto user1 = db.users().insertUser();
+
+    // admin with "direct" ADMIN role
+    UserDto admin1 = db.users().insertUser();
+    db.users().insertProjectPermissionOnUser(admin1, UserRole.ADMIN, project);
+
+    // admin2 with ADMIN role through group
+    UserDto admin2 = db.users().insertUser();
+    GroupDto adminGroup = db.users().insertGroup(organization, "ADMIN");
+    db.users().insertMember(adminGroup, admin2);
+    db.users().insertProjectPermissionOnGroup(adminGroup, UserRole.ADMIN, project);
+
+    assertThat(underTest.keepAuthorizedLoginsOnProject(dbSession, newHashSet(user1.getLogin()), project.uuid(), UserRole.USER))
+      .containsOnly(user1.getLogin());
+    assertThat(underTest.keepAuthorizedLoginsOnProject(dbSession, newHashSet(user1.getLogin(), admin1.getLogin(), admin2.getLogin()), project.uuid(), UserRole.USER))
+      .containsOnly(user1.getLogin(), admin1.getLogin(), admin2.getLogin());
+    assertThat(underTest.keepAuthorizedLoginsOnProject(dbSession, newHashSet(user1.getLogin(), admin1.getLogin(), admin2.getLogin()), project.uuid(), UserRole.ADMIN))
+      .containsOnly(admin1.getLogin(), admin2.getLogin());
+  }
+
+  @Test
+  public void keepAuthorizedLoginsOnProject_return_correct_users_on_private_project() {
+    ComponentDto project = db.components().insertPrivateProject(organization);
+
+    GroupDto userGroup = db.users().insertGroup(organization, "USERS");
+    GroupDto adminGroup = db.users().insertGroup(organization, "ADMIN");
+    db.users().insertProjectPermissionOnGroup(userGroup, UserRole.USER, project);
+    db.users().insertProjectPermissionOnGroup(adminGroup, UserRole.ADMIN, project);
+
+    // admin with "direct" ADMIN role
+    UserDto admin1 = db.users().insertUser();
+    db.users().insertProjectPermissionOnUser(admin1, UserRole.ADMIN, project);
+
+    // admin2 with ADMIN role through group
+    UserDto admin2 = db.users().insertUser();
+    db.users().insertMember(adminGroup, admin2);
+
+    // user1 with "direct" USER role
+    UserDto user1 = db.users().insertUser();
+    db.users().insertProjectPermissionOnUser(user1, UserRole.USER, project);
+
+    // user2 with USER role through group
+    UserDto user2 = db.users().insertUser();
+    db.users().insertMember(userGroup, user2);
+
+    // user without role
+    UserDto userWithNoRole = db.users().insertUser();
+
+    assertThat(underTest.keepAuthorizedLoginsOnProject(dbSession, newHashSet(userWithNoRole.getLogin()), project.uuid(), UserRole.USER))
+      .isEmpty();
+    assertThat(underTest.keepAuthorizedLoginsOnProject(dbSession, newHashSet(user1.getLogin()), project.uuid(), UserRole.USER))
+      .containsOnly(user1.getLogin());
+
+    Set<String> allLogins = newHashSet(admin1.getLogin(), admin2.getLogin(), user1.getLogin(), user2.getLogin(), userWithNoRole.getLogin());
+
+    // Admin does not have the USER permission set
+    assertThat(underTest.keepAuthorizedLoginsOnProject(dbSession, allLogins, project.uuid(), UserRole.USER))
+      .containsOnly(user1.getLogin(), user2.getLogin());
+    assertThat(underTest.keepAuthorizedLoginsOnProject(dbSession, allLogins, project.uuid(), UserRole.ADMIN))
+      .containsOnly(admin1.getLogin(), admin2.getLogin());
+  }
 }
index 8b0c455d92fa465bc394136747aaeaa358c5a538..84ec3a718d773676d4969420d24a8becf49709a8 100644 (file)
@@ -35,6 +35,7 @@ import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.junit.runner.RunWith;
 import org.sonar.api.utils.System2;
+import org.sonar.api.web.UserRole;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
@@ -80,79 +81,50 @@ public class PropertiesDaoTest {
 
   @Test
   public void shouldFindUsersForNotification() throws SQLException {
-    ComponentDto project1 = insertProject("uuid_45");
-    ComponentDto project2 = insertProject("uuid_56");
-    int userId1 = insertUser("user1");
-    int userId2 = insertUser("user2");
-    int userId3 = insertUser("user3");
-    insertProperty("notification.NewViolations.Email", "true", project1.getId(), userId2);
-    insertProperty("notification.NewViolations.Twitter", "true", null, userId3);
-    insertProperty("notification.NewViolations.Twitter", "true", project2.getId(), userId1);
-    insertProperty("notification.NewViolations.Twitter", "true", project2.getId(), userId3);
-
-    assertThat(underTest.selectUsersForNotification("NewViolations", "Email", null))
+    ComponentDto project1 = insertPrivateProject("uuid_45");
+    ComponentDto project2 = insertPrivateProject("uuid_56");
+    UserDto user1 = insertUser("user1");
+    UserDto user2 = insertUser("user2");
+    UserDto user3 = insertUser("user3");
+    insertProperty("notification.NewViolations.Email", "true", project1.getId(), user2.getId());
+    insertProperty("notification.NewViolations.Twitter", "true", null, user3.getId());
+    insertProperty("notification.NewViolations.Twitter", "true", project2.getId(), user1.getId());
+    insertProperty("notification.NewViolations.Twitter", "true", project1.getId(), user2.getId());
+    insertProperty("notification.NewViolations.Twitter", "true", project2.getId(), user3.getId());
+    dbTester.users().insertProjectPermissionOnUser(user2, UserRole.USER, project1);
+    dbTester.users().insertProjectPermissionOnUser(user3, UserRole.USER, project2);
+    dbTester.users().insertProjectPermissionOnUser(user1, UserRole.USER, project2);
+
+    assertThat(underTest.findUsersForNotification("NewViolations", "Email", null))
       .isEmpty();
 
-    assertThat(underTest.selectUsersForNotification("NewViolations", "Email", "uuid_78"))
+    assertThat(underTest.findUsersForNotification("NewViolations", "Email", "uuid_78"))
       .isEmpty();
 
-    assertThat(underTest.selectUsersForNotification("NewViolations", "Email", "uuid_45"))
-      .hasSize(1).containsOnly("user2");
-
-    assertThat(underTest.selectUsersForNotification("NewViolations", "Twitter", null))
-      .hasSize(1)
-      .containsOnly("user3");
-
-    assertThat(underTest.selectUsersForNotification("NewViolations", "Twitter", "uuid_78"))
-      .isEmpty();
-
-    assertThat(underTest.selectUsersForNotification("NewViolations", "Twitter", "uuid_56"))
-      .hasSize(2)
-      .containsOnly("user1", "user3");
-  }
-
-  @Test
-  public void findNotificationSubscribers() throws SQLException {
-    int userId1 = insertUser("user1");
-    int userId2 = insertUser("user2");
-    ComponentDto projectDto = insertProject("PROJECT_A");
-    long projectId = projectDto.getId();
-    String projectKey = projectDto.getDbKey();
-
-    // global subscription
-    insertProperty("notification.DispatcherWithGlobalSubscribers.Email", "true", null, userId2);
-    // project subscription
-    insertProperty("notification.DispatcherWithProjectSubscribers.Email", "true", projectId, userId1);
-    insertProperty("notification.DispatcherWithGlobalAndProjectSubscribers.Email", "true", 56L, userId1);
-    insertProperty("notification.DispatcherWithGlobalAndProjectSubscribers.Email", "true", projectId, userId1);
-    // global subscription
-    insertProperty("notification.DispatcherWithGlobalAndProjectSubscribers.Email", "true", null, userId2);
+    assertThat(underTest.findUsersForNotification("NewViolations", "Email", project1.uuid()))
+      .containsOnly("user2");
 
-    // Nobody is subscribed
-    assertThat(underTest.selectNotificationSubscribers("NotSexyDispatcher", "Email", projectKey))
+    assertThat(underTest.findUsersForNotification("NewViolations", "Email", project2.uuid()))
       .isEmpty();
 
-    // Global subscribers
-    assertThat(underTest.selectNotificationSubscribers("DispatcherWithGlobalSubscribers", "Email", projectKey))
-      .containsOnly("user2");
+    assertThat(underTest.findUsersForNotification("NewViolations", "Twitter", null))
+      .containsOnly("user3");
 
-    assertThat(underTest.selectNotificationSubscribers("DispatcherWithGlobalSubscribers", "Email", null))
-      .containsOnly("user2");
+    assertThat(underTest.findUsersForNotification("NewViolations", "Twitter", "uuid_78"))
+      .containsOnly("user3");
 
-    // Project subscribers
-    assertThat(underTest.selectNotificationSubscribers("DispatcherWithProjectSubscribers", "Email", projectKey))
-      .containsOnly("user1");
+    assertThat(underTest.findUsersForNotification("NewViolations", "Twitter", project1.uuid()))
+      .containsOnly("user2", "user3");
 
-    // Global + Project subscribers
-    assertThat(underTest.selectNotificationSubscribers("DispatcherWithGlobalAndProjectSubscribers", "Email", projectKey))
-      .containsOnly("user1", "user2");
+    assertThat(underTest.findUsersForNotification("NewViolations", "Twitter", project2.uuid()))
+      .containsOnly("user1", "user3");
   }
 
   @Test
   public void hasNotificationSubscribers() throws SQLException {
-    int userId1 = insertUser("user1");
-    int userId2 = insertUser("user2");
-    Long projectId = insertProject("PROJECT_A").getId();
+    int userId1 = insertUser("user1").getId();
+    int userId2 = insertUser("user2").getId();
+    Long projectId = insertPrivateProject("PROJECT_A").getId();
     // global subscription
     insertProperty("notification.DispatcherWithGlobalSubscribers.Email", "true", null, userId2);
     // project subscription
@@ -254,7 +226,7 @@ public class PropertiesDaoTest {
 
   @Test
   public void selectProjectProperties() throws SQLException {
-    ComponentDto projectDto = insertProject("A");
+    ComponentDto projectDto = insertPrivateProject("A");
     long projectId = projectDto.getId();
     // global
     insertProperty("global.one", "one", null, null);
@@ -279,7 +251,7 @@ public class PropertiesDaoTest {
   @Test
   @UseDataProvider("allValuesForSelect")
   public void selectProjectProperties_supports_all_values(String dbValue, String expected) throws SQLException {
-    ComponentDto projectDto = insertProject("A");
+    ComponentDto projectDto = insertPrivateProject("A");
     insertProperty("project.one", dbValue, projectDto.getId(), null);
 
     List<PropertyDto> dtos = underTest.selectProjectProperties(projectDto.getDbKey());
@@ -379,8 +351,8 @@ public class PropertiesDaoTest {
 
   @Test
   public void select_global_properties_by_keys() throws Exception {
-    insertProject("A");
-    int userId = insertUser("B");
+    insertPrivateProject("A");
+    int userId = insertUser("B").getId();
 
     String key = "key";
     String anotherKey = "anotherKey";
@@ -705,9 +677,9 @@ public class PropertiesDaoTest {
 
   @Test
   public void delete_project_property() throws SQLException {
-    long projectId1 = insertProject("A").getId();
-    long projectId2 = insertProject("B").getId();
-    long projectId3 = insertProject("C").getId();
+    long projectId1 = insertPrivateProject("A").getId();
+    long projectId2 = insertPrivateProject("B").getId();
+    long projectId3 = insertPrivateProject("C").getId();
     long id1 = insertProperty("global.one", "one", null, null);
     long id2 = insertProperty("global.two", "two", null, null);
     long id3 = insertProperty("struts.one", "one", projectId1, null);
@@ -822,7 +794,6 @@ public class PropertiesDaoTest {
       .hasNoResourceId()
       .hasUserId(100)
       .hasTextValue("new_user");
-
   }
 
   @Test
@@ -1068,7 +1039,7 @@ public class PropertiesDaoTest {
       " and resource_id" + (resourceId == null ? " is null" : "='" + resourceId + "'")).get("id");
   }
 
-  private ComponentDto insertProject(String uuid) {
+  private ComponentDto insertPrivateProject(String uuid) {
     String key = "project" + uuid;
     ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization(), uuid).setDbKey(key);
     dbClient.componentDao().insert(session, project);
@@ -1076,12 +1047,12 @@ public class PropertiesDaoTest {
     return project;
   }
 
-  private int insertUser(String login) {
+  private UserDto insertUser(String login) {
     UserDto dto = new UserDto().setLogin(login);
     DbSession session = dbTester.getSession();
     dbClient.userDao().insert(session, dto);
     session.commit();
-    return dto.getId();
+    return dto;
   }
 
   private static PropertyDtoAssert assertThatDto(@Nullable PropertyDto dto) {
index 930a75192be5392ca9999c090cef86833e3e2c93..6e26dcbad0741a054e967a066b00f473c491a072 100644 (file)
@@ -114,7 +114,7 @@ public class SendIssueNotificationsStep implements ComputationStep {
     IssueChangeNotification changeNotification = new IssueChangeNotification();
     changeNotification.setRuleName(rules.getByKey(issue.ruleKey()).getName());
     changeNotification.setIssue(issue);
-    changeNotification.setProject(project.getPublicKey(), project.getName(), getBranchName());
+    changeNotification.setProject(project.getPublicKey(), project.getName(), getBranchName(), project.getUuid());
     getComponentKey(issue).ifPresent(c -> changeNotification.setComponent(c.getPublicKey(), c.getName()));
     service.deliver(changeNotification);
   }
index a368b01ca7a3b98206eb3e6e2c6d6120dac1d616..4115aaac9b8bc1135d456297f6a55d58c10c7ad7 100644 (file)
@@ -80,7 +80,7 @@ public class IssueUpdater {
       .setIssue(issue)
       .setChangeAuthorLogin(context.login())
       .setRuleName(rule.map(RuleDefinitionDto::getName).orElse(null))
-      .setProject(project.getKey(), project.name(), project.getBranch())
+      .setProject(project)
       .setComponent(component)
       .setComment(comment));
     return issueDto;
index 86bd287e23033f38e409479e530140b68965cf71..d9115a37619ba88817525779ed5bd2dfc8b16ec8 100644 (file)
@@ -57,8 +57,8 @@ public class ChangesOnMyIssueNotificationDispatcher extends NotificationDispatch
 
   @Override
   public void dispatch(Notification notification, Context context) {
-    String projectKey = notification.getFieldValue("projectKey");
-    Multimap<String, NotificationChannel> subscribedRecipients = notificationManager.findNotificationSubscribers(this, projectKey);
+    String projectUuid = notification.getFieldValue("projectUuid");
+    Multimap<String, NotificationChannel> subscribedRecipients = notificationManager.findSubscribedRecipientsForDispatcher(this, projectUuid);
 
     // See available fields in the class IssueNotifications.
 
index 4e2dec4edc2be332901c8cd8f576659fcb6af7c9..87e1d62599a1b1856e06608edc4954ec056e8b30 100644 (file)
@@ -60,8 +60,8 @@ public class DoNotFixNotificationDispatcher extends NotificationDispatcher {
     String newResolution = notification.getFieldValue("new.resolution");
     if (Objects.equals(newResolution, Issue.RESOLUTION_FALSE_POSITIVE) || Objects.equals(newResolution, Issue.RESOLUTION_WONT_FIX)) {
       String author = notification.getFieldValue("changeAuthor");
-      String projectKey = notification.getFieldValue("projectKey");
-      Multimap<String, NotificationChannel> subscribedRecipients = notifications.findNotificationSubscribers(this, projectKey);
+      String projectUuid = notification.getFieldValue("projectUuid");
+      Multimap<String, NotificationChannel> subscribedRecipients = notifications.findSubscribedRecipientsForDispatcher(this, projectUuid);
       notify(author, context, subscribedRecipients);
     }
   }
index 477bde3049c08892886390bdc5e8bef19672c979..58d6b7296c39f76d0bfaaf3cf664962ed6f616f3 100644 (file)
@@ -54,11 +54,12 @@ public class IssueChangeNotification extends Notification {
   }
 
   public IssueChangeNotification setProject(ComponentDto project) {
-    return setProject(project.getKey(), project.longName(), project.getBranch());
+    return setProject(project.getKey(), project.name(), project.getBranch(), project.uuid());
   }
 
-  public IssueChangeNotification setProject(String projectKey, String projectName, @Nullable String branch) {
+  public IssueChangeNotification setProject(String projectKey, String projectName, @Nullable String branch, String projectUuid) {
     setFieldValue("projectName", projectName);
+    setFieldValue("projectUuid", projectUuid);
     setFieldValue("projectKey", projectKey);
     if (branch != null) {
       setFieldValue("branch", branch);
index a7d6357a13ee551c70d9b62a24ccecb6fa7d2164..ee980d09b51b512ee40da2d6954e6a356aa5715f 100644 (file)
@@ -53,9 +53,9 @@ public class MyNewIssuesNotificationDispatcher extends NotificationDispatcher {
 
   @Override
   public void dispatch(Notification notification, Context context) {
-    String projectKey = notification.getFieldValue("projectKey");
+    String projectUuid = notification.getFieldValue("projectUuid");
     String assignee = notification.getFieldValue("assignee");
-    Multimap<String, NotificationChannel> subscribedRecipients = manager.findNotificationSubscribers(this, projectKey);
+    Multimap<String, NotificationChannel> subscribedRecipients = manager.findSubscribedRecipientsForDispatcher(this, projectUuid);
 
     Collection<NotificationChannel> channels = subscribedRecipients.get(assignee);
     for (NotificationChannel channel : channels) {
index 58e4a3a9fb9eb060105625348ff6977a39907696..8b7787ea98a7f2f6f8b08edca32958dcc4ceb521 100644 (file)
@@ -54,8 +54,8 @@ public class NewIssuesNotificationDispatcher extends NotificationDispatcher {
 
   @Override
   public void dispatch(Notification notification, Context context) {
-    String projectKey = notification.getFieldValue("projectKey");
-    Multimap<String, NotificationChannel> subscribedRecipients = manager.findNotificationSubscribers(this, projectKey);
+    String projectUuid = notification.getFieldValue("projectUuid");
+    Multimap<String, NotificationChannel> subscribedRecipients = manager.findSubscribedRecipientsForDispatcher(this, projectUuid);
 
     for (Map.Entry<String, Collection<NotificationChannel>> channelsByRecipients : subscribedRecipients.asMap().entrySet()) {
       String userLogin = channelsByRecipients.getKey();
index fa819e856c8d116860e5e259a81d51e4c9ca99de..cb000d0cf9e12ba809669d37d81c1aba4d901c73 100644 (file)
@@ -21,24 +21,26 @@ package org.sonar.server.notification;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Lists;
 import com.google.common.collect.Multimap;
 import com.google.common.collect.SetMultimap;
 import java.io.IOException;
 import java.io.InvalidClassException;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
-import javax.annotation.Nullable;
+import java.util.Set;
 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.db.notification.NotificationQueueDao;
+import org.sonar.api.web.UserRole;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
 import org.sonar.db.notification.NotificationQueueDto;
-import org.sonar.db.property.PropertiesDao;
 
 import static java.util.Collections.singletonList;
+import static java.util.Objects.requireNonNull;
 
 public class DefaultNotificationManager implements NotificationManager {
 
@@ -47,25 +49,17 @@ public class DefaultNotificationManager implements NotificationManager {
   private static final String UNABLE_TO_READ_NOTIFICATION = "Unable to read notification";
 
   private NotificationChannel[] notificationChannels;
-  private NotificationQueueDao notificationQueueDao;
-  private PropertiesDao propertiesDao;
+  private final DbClient dbClient;
 
   private boolean alreadyLoggedDeserializationIssue = false;
 
   /**
    * Default constructor used by Pico
    */
-  public DefaultNotificationManager(NotificationChannel[] channels, NotificationQueueDao notificationQueueDao, PropertiesDao propertiesDao) {
+  public DefaultNotificationManager(NotificationChannel[] channels,
+    DbClient dbClient) {
     this.notificationChannels = channels;
-    this.notificationQueueDao = notificationQueueDao;
-    this.propertiesDao = propertiesDao;
-  }
-
-  /**
-   * Constructor if no notification channel
-   */
-  public DefaultNotificationManager(NotificationQueueDao notificationQueueDao, PropertiesDao propertiesDao) {
-    this(new NotificationChannel[0], notificationQueueDao, propertiesDao);
+    this.dbClient = dbClient;
   }
 
   /**
@@ -74,18 +68,18 @@ public class DefaultNotificationManager implements NotificationManager {
   @Override
   public void scheduleForSending(Notification notification) {
     NotificationQueueDto dto = NotificationQueueDto.toNotificationQueueDto(notification);
-    notificationQueueDao.insert(singletonList(dto));
+    dbClient.notificationQueueDao().insert(singletonList(dto));
   }
   /**
    * Give the notification queue so that it can be processed
    */
   public Notification getFromQueue() {
     int batchSize = 1;
-    List<NotificationQueueDto> notificationDtos = notificationQueueDao.selectOldest(batchSize);
+    List<NotificationQueueDto> notificationDtos = dbClient.notificationQueueDao().selectOldest(batchSize);
     if (notificationDtos.isEmpty()) {
       return null;
     }
-    notificationQueueDao.delete(notificationDtos);
+    dbClient.notificationQueueDao().delete(notificationDtos);
 
     return convertToNotification(notificationDtos);
   }
@@ -112,15 +106,15 @@ public class DefaultNotificationManager implements NotificationManager {
   }
 
   public long count() {
-    return notificationQueueDao.count();
+    return dbClient.notificationQueueDao().count();
   }
 
   /**
    * {@inheritDoc}
    */
   @Override
-  public Multimap<String, NotificationChannel> findSubscribedRecipientsForDispatcher(NotificationDispatcher dispatcher,
-    @Nullable String projectUuid) {
+  public Multimap<String, NotificationChannel> findSubscribedRecipientsForDispatcher(NotificationDispatcher dispatcher, String projectUuid) {
+    requireNonNull(projectUuid, "ProjectUUID is mandatory");
     String dispatcherKey = dispatcher.getKey();
 
     SetMultimap<String, NotificationChannel> recipients = HashMultimap.create();
@@ -128,38 +122,28 @@ public class DefaultNotificationManager implements NotificationManager {
       String channelKey = channel.getKey();
 
       // Find users subscribed globally to the dispatcher (i.e. not on a specific project)
-      addUsersToRecipientListForChannel(propertiesDao.selectUsersForNotification(dispatcherKey, channelKey, null), recipients, channel);
-
-      if (projectUuid != null) {
-        // Find users subscribed to the dispatcher specifically for the project
-        addUsersToRecipientListForChannel(propertiesDao.selectUsersForNotification(dispatcherKey, channelKey, projectUuid), recipients, channel);
+      // And users subscribed to the dispatcher specifically for the project
+      Set<String> subscribedUsers = dbClient.propertiesDao().findUsersForNotification(dispatcherKey, channelKey, projectUuid);
+
+      if (!subscribedUsers.isEmpty()) {
+        try (DbSession dbSession = dbClient.openSession(false)) {
+          Set<String> filteredSubscribedUsers = dbClient.authorizationDao().keepAuthorizedLoginsOnProject(dbSession, subscribedUsers, projectUuid, UserRole.USER);
+          addUsersToRecipientListForChannel(filteredSubscribedUsers, recipients, channel);
+        }
       }
     }
 
     return recipients;
   }
 
-  @Override
-  public Multimap<String, NotificationChannel> findNotificationSubscribers(NotificationDispatcher dispatcher, @Nullable String componentKey) {
-    String dispatcherKey = dispatcher.getKey();
-
-    SetMultimap<String, NotificationChannel> recipients = HashMultimap.create();
-    for (NotificationChannel channel : notificationChannels) {
-      addUsersToRecipientListForChannel(propertiesDao.selectNotificationSubscribers(dispatcherKey, channel.getKey(), componentKey), recipients, channel);
-    }
-
-    return recipients;
-  }
-
   @VisibleForTesting
   protected List<NotificationChannel> getChannels() {
     return Arrays.asList(notificationChannels);
   }
 
-  private static void addUsersToRecipientListForChannel(List<String> users, SetMultimap<String, NotificationChannel> recipients, NotificationChannel channel) {
+  private static void addUsersToRecipientListForChannel(Collection<String> users, SetMultimap<String, NotificationChannel> recipients, NotificationChannel channel) {
     for (String username : users) {
       recipients.put(username, channel);
     }
   }
-
 }
index 181c6bce56a525a281a6b500cb86db0d706b0a62..e06c4083d648a1b7e799f7f1a8284971f7216cfb 100644 (file)
@@ -20,7 +20,6 @@
 package org.sonar.server.notification;
 
 import com.google.common.collect.Multimap;
-import javax.annotation.Nullable;
 import org.sonar.api.notifications.Notification;
 import org.sonar.api.notifications.NotificationChannel;
 
@@ -54,6 +53,4 @@ public interface NotificationManager {
    * @return the list of user login along with the subscribed channels
    */
   Multimap<String, NotificationChannel> findSubscribedRecipientsForDispatcher(NotificationDispatcher dispatcher, String projectUuid);
-
-  Multimap<String, NotificationChannel> findNotificationSubscribers(NotificationDispatcher dispatcher, @Nullable String componentKey);
 }
index 8e33f079c96b8b2fe6fb9d28b27d065fe7650e8f..bf2b55409d6cbcb6b6cdfba4de97db5b566b8c0d 100644 (file)
@@ -117,6 +117,7 @@ public class IssueUpdaterTest {
     assertThat(issueChangeNotification.getFieldValue("componentKey")).isEqualTo(file.getDbKey());
     assertThat(issueChangeNotification.getFieldValue("componentName")).isEqualTo(file.longName());
     assertThat(issueChangeNotification.getFieldValue("projectKey")).isEqualTo(project.getDbKey());
+    assertThat(issueChangeNotification.getFieldValue("projectUuid")).isEqualTo(project.uuid());
     assertThat(issueChangeNotification.getFieldValue("projectName")).isEqualTo(project.name());
     assertThat(issueChangeNotification.getFieldValue("ruleName")).isEqualTo(rule.getName());
     assertThat(issueChangeNotification.getFieldValue("changeAuthor")).isEqualTo("john");
index 5bcb7421a66ee7d53bc9f228366470842000be0f..fc2b0fc13a2108a844848a03cceae73a54e269fe 100644 (file)
@@ -83,9 +83,11 @@ public class ChangesOnMyIssueNotificationDispatcherTest {
     recipients.put("simon", emailChannel);
     recipients.put("freddy", twitterChannel);
     recipients.put("godin", twitterChannel);
-    when(notifications.findNotificationSubscribers(dispatcher, "struts")).thenReturn(recipients);
+    when(notifications.findSubscribedRecipientsForDispatcher(dispatcher, "uuid1")).thenReturn(recipients);
 
-    Notification notification = new IssueChangeNotification().setFieldValue("projectKey", "struts")
+    Notification notification = new IssueChangeNotification()
+      .setFieldValue("projectKey", "struts")
+      .setFieldValue("projectUuid", "uuid1")
       .setFieldValue("changeAuthor", "olivier")
       .setFieldValue("assignee", "freddy");
     dispatcher.performDispatch(notification, context);
@@ -101,11 +103,15 @@ public class ChangesOnMyIssueNotificationDispatcherTest {
     recipients.put("simon", emailChannel);
     recipients.put("freddy", twitterChannel);
     recipients.put("godin", twitterChannel);
-    when(notifications.findNotificationSubscribers(dispatcher, "struts")).thenReturn(recipients);
+    when(notifications.findSubscribedRecipientsForDispatcher(dispatcher, "uuid1")).thenReturn(recipients);
 
     // change author is the assignee
-    dispatcher.performDispatch(new IssueChangeNotification().setFieldValue("projectKey", "struts")
-      .setFieldValue("changeAuthor", "simon").setFieldValue("assignee", "simon"), context);
+    dispatcher.performDispatch(
+      new IssueChangeNotification()
+        .setFieldValue("projectKey", "struts")
+        .setFieldValue("projectUuid", "uuid1")
+        .setFieldValue("changeAuthor", "simon")
+        .setFieldValue("assignee", "simon"), context);
 
     // no change author
     dispatcher.performDispatch(new IssueChangeNotification().setFieldValue("projectKey", "struts")
index 9c32306534089d68d770d1d420bfc28b77a413da..aaaf004ffb248dc042d562d859d9364ec3203466 100644 (file)
@@ -61,9 +61,10 @@ public class DoNotFixNotificationDispatcherTest {
     recipients.put("simon", emailChannel);
     recipients.put("freddy", twitterChannel);
     recipients.put("godin", twitterChannel);
-    when(notifications.findNotificationSubscribers(underTest, "struts")).thenReturn(recipients);
+    when(notifications.findSubscribedRecipientsForDispatcher(underTest, "uuid1")).thenReturn(recipients);
 
     Notification fpNotif = new IssueChangeNotification().setFieldValue("projectKey", "struts")
+      .setFieldValue("projectUuid", "uuid1")
       .setFieldValue("changeAuthor", "godin")
       .setFieldValue("new.resolution", Issue.RESOLUTION_FALSE_POSITIVE)
       .setFieldValue("assignee", "freddy");
@@ -81,11 +82,6 @@ public class DoNotFixNotificationDispatcherTest {
    */
   @Test
   public void ignore_other_resolutions() {
-    Multimap<String, NotificationChannel> recipients = HashMultimap.create();
-    recipients.put("simon", emailChannel);
-    recipients.put("freddy", twitterChannel);
-    when(notifications.findNotificationSubscribers(underTest, "struts")).thenReturn(recipients);
-
     Notification fixedNotif = new IssueChangeNotification().setFieldValue("projectKey", "struts")
       .setFieldValue("changeAuthor", "godin")
       .setFieldValue("new.resolution", Issue.RESOLUTION_FIXED)
index 18a513ca9fffed8ab72cf78397259188dc605e03..94ff9af63e89cce64e79fa37fd5b1117380afa0f 100644 (file)
@@ -84,16 +84,18 @@ public class IssueChangeNotificationTest {
 
   @Test
   public void set_project_without_branch() {
-    IssueChangeNotification result = notification.setProject("MyService", "My Service", null);
+    IssueChangeNotification result = notification.setProject("MyService", "My Service", null, "uuid1");
     assertThat(result.getFieldValue("projectKey")).isEqualTo("MyService");
+    assertThat(result.getFieldValue("projectUuid")).isEqualTo("uuid1");
     assertThat(result.getFieldValue("projectName")).isEqualTo("My Service");
     assertThat(result.getFieldValue("branch")).isNull();
   }
 
   @Test
   public void set_project_with_branch() {
-    IssueChangeNotification result = notification.setProject("MyService", "My Service", "feature1");
+    IssueChangeNotification result = notification.setProject("MyService", "My Service", "feature1", "uuid2");
     assertThat(result.getFieldValue("projectKey")).isEqualTo("MyService");
+    assertThat(result.getFieldValue("projectUuid")).isEqualTo("uuid2");
     assertThat(result.getFieldValue("projectName")).isEqualTo("My Service");
     assertThat(result.getFieldValue("branch")).isEqualTo("feature1");
   }
index 3e858e61915fa5c17381cca3f1e484923f1ab6b0..90ac0f3d1a43ac6152977949e0db16ded69bce16 100644 (file)
@@ -170,7 +170,7 @@ public class IssueChangesEmailTemplateTest {
 
     Notification notification = new IssueChangeNotification()
       .setChangeAuthorLogin("simon")
-      .setProject("Struts", "org.apache:struts", null);
+      .setProject("Struts", "org.apache:struts", null, "");
 
     EmailMessage message = underTest.format(notification);
     assertThat(message.getFrom()).isEqualTo("Simon");
@@ -182,7 +182,7 @@ public class IssueChangesEmailTemplateTest {
 
     Notification notification = new IssueChangeNotification()
       .setChangeAuthorLogin("simon")
-      .setProject("Struts", "org.apache:struts", null);
+      .setProject("Struts", "org.apache:struts", null, "");
 
     EmailMessage message = underTest.format(notification);
     assertThat(message.getFrom()).isEqualTo("simon");
index edb1620783246fe0246d7d3922d7b61baf72a66c..1ef6e596dbec8714fa324db1ce21747ee865909f 100644 (file)
@@ -58,10 +58,11 @@ public class MyNewIssuesNotificationDispatcherTest {
     Multimap<String, NotificationChannel> recipients = HashMultimap.create();
     recipients.put("user1", emailChannel);
     recipients.put("user2", twitterChannel);
-    when(notificationManager.findNotificationSubscribers(underTest, "struts")).thenReturn(recipients);
+    when(notificationManager.findSubscribedRecipientsForDispatcher(underTest, "uuid1")).thenReturn(recipients);
 
     Notification notification = new Notification(MyNewIssuesNotification.MY_NEW_ISSUES_NOTIF_TYPE)
       .setFieldValue("projectKey", "struts")
+      .setFieldValue("projectUuid", "uuid1")
       .setFieldValue("assignee", "user1");
     underTest.performDispatch(notification, context);
 
index f98b8536baa44d21e60b6ed8baeb2054ee29d248..54905e244f0baa76bff5d65d056a93c9406e2af8 100644 (file)
@@ -56,9 +56,11 @@ public class NewIssuesNotificationDispatcherTest {
     Multimap<String, NotificationChannel> recipients = HashMultimap.create();
     recipients.put("user1", emailChannel);
     recipients.put("user2", twitterChannel);
-    when(notifications.findNotificationSubscribers(dispatcher, "struts")).thenReturn(recipients);
+    when(notifications.findSubscribedRecipientsForDispatcher(dispatcher, "uuid1")).thenReturn(recipients);
 
-    Notification notification = new Notification(NewIssuesNotification.TYPE).setFieldValue("projectKey", "struts");
+    Notification notification = new Notification(NewIssuesNotification.TYPE)
+      .setFieldValue("projectKey", "struts")
+      .setFieldValue("projectUuid", "uuid1");
     dispatcher.performDispatch(notification, context);
 
     verify(context).addUser("user1", emailChannel);
index 5225acb63db7f68e6728b9fcad95818a90e0361e..df7bf6964728181d9ee990df924d07d167a1e948 100644 (file)
@@ -254,7 +254,7 @@ public class BulkChangeActionTest {
     verify(notificationManager).scheduleForSending(issueChangeNotificationCaptor.capture());
     assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("key")).isEqualTo(issueDto.getKey());
     assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("componentName")).isEqualTo(file.longName());
-    assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("projectName")).isEqualTo(project.longName());
+    assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("projectName")).isEqualTo(project.name());
     assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("projectKey")).isEqualTo(project.getDbKey());
     assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("ruleName")).isEqualTo(rule.getName());
     assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("changeAuthor")).isEqualTo(user.getLogin());
@@ -282,7 +282,7 @@ public class BulkChangeActionTest {
     verify(notificationManager).scheduleForSending(issueChangeNotificationCaptor.capture());
     assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("key")).isEqualTo(issueDto.getKey());
     assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("componentName")).isEqualTo(fileOnBranch.longName());
-    assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("projectName")).isEqualTo(project.longName());
+    assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("projectName")).isEqualTo(project.name());
     assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("projectKey")).isEqualTo(project.getDbKey());
     assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("ruleName")).isEqualTo(rule.getName());
     assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("changeAuthor")).isEqualTo(user.getLogin());
index 327db72773a83bf75342c9610f91e1655fedd2a3..da159a1d3e8571c5267c7934e23ea9d38d39b926 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.server.notification;
 
-import com.google.common.collect.Lists;
 import com.google.common.collect.Multimap;
 import java.io.InvalidClassException;
 import java.util.Arrays;
@@ -27,29 +26,41 @@ import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 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.db.DbClient;
+import org.sonar.db.DbTester;
 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 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.eq;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.only;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import static org.mockito.internal.verification.VerificationModeFactory.times;
 
 public class DefaultNotificationManagerTest {
 
-  private DefaultNotificationManager manager;
+  private DefaultNotificationManager underTest;
+
+  @Rule
+  public DbTester db = DbTester.create(System2.INSTANCE);
 
   @Mock
   private PropertiesDao propertiesDao;
@@ -66,28 +77,40 @@ public class DefaultNotificationManagerTest {
   @Mock
   private NotificationQueueDao notificationQueueDao;
 
+  @Mock
+  private AuthorizationDao authorizationDao;
+
+  @Mock
+  private DbClient dbClient;
+
+  @Captor
+  private ArgumentCaptor<List<String>> captorLogins;
+
   @Before
   public void setUp() {
     MockitoAnnotations.initMocks(this);
     when(dispatcher.getKey()).thenReturn("NewViolations");
     when(emailChannel.getKey()).thenReturn("Email");
     when(twitterChannel.getKey()).thenReturn("Twitter");
+    when(dbClient.propertiesDao()).thenReturn(propertiesDao);
+    when(dbClient.notificationQueueDao()).thenReturn(notificationQueueDao);
+    when(dbClient.authorizationDao()).thenReturn(authorizationDao);
 
-    manager = new DefaultNotificationManager(new NotificationChannel[] {emailChannel, twitterChannel}, notificationQueueDao, propertiesDao);
+    underTest = new DefaultNotificationManager(new NotificationChannel[] {emailChannel, twitterChannel}, dbClient);
   }
 
   @Test
   public void shouldProvideChannelList() {
-    assertThat(manager.getChannels()).containsOnly(emailChannel, twitterChannel);
+    assertThat(underTest.getChannels()).containsOnly(emailChannel, twitterChannel);
 
-    manager = new DefaultNotificationManager(notificationQueueDao, propertiesDao);
-    assertThat(manager.getChannels()).hasSize(0);
+    underTest = new DefaultNotificationManager(new NotificationChannel[] {} , db.getDbClient());
+    assertThat(underTest.getChannels()).hasSize(0);
   }
 
   @Test
   public void shouldPersist() {
     Notification notification = new Notification("test");
-    manager.scheduleForSending(notification);
+    underTest.scheduleForSending(notification);
 
     verify(notificationQueueDao, only()).insert(any(List.class));
   }
@@ -99,13 +122,14 @@ public class DefaultNotificationManagerTest {
     List<NotificationQueueDto> dtos = Arrays.asList(dto);
     when(notificationQueueDao.selectOldest(1)).thenReturn(dtos);
 
-    assertThat(manager.getFromQueue()).isNotNull();
+    assertThat(underTest.getFromQueue()).isNotNull();
 
     InOrder inOrder = inOrder(notificationQueueDao);
     inOrder.verify(notificationQueueDao).selectOldest(1);
     inOrder.verify(notificationQueueDao).delete(dtos);
   }
 
+
   // SONAR-4739
   @Test
   public void shouldNotFailWhenUnableToDeserialize() throws Exception {
@@ -114,65 +138,41 @@ public class DefaultNotificationManagerTest {
     List<NotificationQueueDto> dtos = Arrays.asList(dto1);
     when(notificationQueueDao.selectOldest(1)).thenReturn(dtos);
 
-    manager = spy(manager);
-    assertThat(manager.getFromQueue()).isNull();
-    assertThat(manager.getFromQueue()).isNull();
+    underTest = spy(underTest);
+    assertThat(underTest.getFromQueue()).isNull();
+    assertThat(underTest.getFromQueue()).isNull();
 
-    verify(manager, times(1)).logDeserializationIssue();
+    verify(underTest, times(1)).logDeserializationIssue();
   }
 
   @Test
   public void shouldFindNoRecipient() {
-    assertThat(manager.findSubscribedRecipientsForDispatcher(dispatcher, "uuid_45").asMap().entrySet()).hasSize(0);
+    assertThat(underTest.findSubscribedRecipientsForDispatcher(dispatcher, "uuid_45").asMap().entrySet()).hasSize(0);
   }
 
   @Test
   public void shouldFindSubscribedRecipientForGivenResource() {
-    when(propertiesDao.selectUsersForNotification("NewViolations", "Email", "uuid_45")).thenReturn(Lists.newArrayList("user1", "user2"));
-    when(propertiesDao.selectUsersForNotification("NewViolations", "Email", null)).thenReturn(Lists.newArrayList("user1", "user3"));
-    when(propertiesDao.selectUsersForNotification("NewViolations", "Twitter", "uuid_56")).thenReturn(Lists.newArrayList("user2"));
-    when(propertiesDao.selectUsersForNotification("NewViolations", "Twitter", null)).thenReturn(Lists.newArrayList("user3"));
-    when(propertiesDao.selectUsersForNotification("NewAlerts", "Twitter", null)).thenReturn(Lists.newArrayList("user4"));
-
-    Multimap<String, NotificationChannel> multiMap = manager.findSubscribedRecipientsForDispatcher(dispatcher, "uuid_45");
-    assertThat(multiMap.entries()).hasSize(4);
-
-    Map<String, Collection<NotificationChannel>> map = multiMap.asMap();
-    assertThat(map.get("user1")).containsOnly(emailChannel);
-    assertThat(map.get("user2")).containsOnly(emailChannel);
-    assertThat(map.get("user3")).containsOnly(emailChannel, twitterChannel);
-    assertThat(map.get("user4")).isNull();
-  }
-
-  @Test
-  public void shouldFindSubscribedRecipientForNoResource() {
-    when(propertiesDao.selectUsersForNotification("NewViolations", "Email", "uuid_45")).thenReturn(Lists.newArrayList("user1", "user2"));
-    when(propertiesDao.selectUsersForNotification("NewViolations", "Email", null)).thenReturn(Lists.newArrayList("user1", "user3"));
-    when(propertiesDao.selectUsersForNotification("NewViolations", "Twitter", "uuid_56")).thenReturn(Lists.newArrayList("user2"));
-    when(propertiesDao.selectUsersForNotification("NewViolations", "Twitter", null)).thenReturn(Lists.newArrayList("user3"));
-    when(propertiesDao.selectUsersForNotification("NewAlerts", "Twitter", null)).thenReturn(Lists.newArrayList("user4"));
-
-    Multimap<String, NotificationChannel> multiMap = manager.findSubscribedRecipientsForDispatcher(dispatcher, null);
+    when(propertiesDao.findUsersForNotification("NewViolations", "Email", "uuid_45"))
+      .thenReturn(newHashSet("user1", "user3"));
+    when(propertiesDao.findUsersForNotification("NewViolations", "Twitter", "uuid_56"))
+      .thenReturn(newHashSet("user2"));
+    when(propertiesDao.findUsersForNotification("NewViolations", "Twitter", "uuid_45"))
+      .thenReturn(newHashSet("user3"));
+    when(propertiesDao.findUsersForNotification("NewAlerts", "Twitter", "uuid_45"))
+      .thenReturn(newHashSet("user4"));
+
+    when(authorizationDao.keepAuthorizedLoginsOnProject(any(), eq(newHashSet("user1", "user3")), eq("uuid_45"), eq("user")))
+      .thenReturn(newHashSet("user1", "user3"));
+    when(authorizationDao.keepAuthorizedLoginsOnProject(any(), eq(newHashSet("user3")), eq("uuid_45"), eq("user")))
+      .thenReturn(newHashSet("user3"));
+
+    Multimap<String, NotificationChannel> multiMap = underTest.findSubscribedRecipientsForDispatcher(dispatcher, "uuid_45");
     assertThat(multiMap.entries()).hasSize(3);
 
     Map<String, Collection<NotificationChannel>> map = multiMap.asMap();
     assertThat(map.get("user1")).containsOnly(emailChannel);
-    assertThat(map.get("user3")).containsOnly(emailChannel, twitterChannel);
     assertThat(map.get("user2")).isNull();
+    assertThat(map.get("user3")).containsOnly(emailChannel, twitterChannel);
     assertThat(map.get("user4")).isNull();
   }
-
-  @Test
-  public void findNotificationSubscribers() {
-    when(propertiesDao.selectNotificationSubscribers("NewViolations", "Email", "struts")).thenReturn(Lists.newArrayList("user1", "user2"));
-    when(propertiesDao.selectNotificationSubscribers("NewViolations", "Twitter", "struts")).thenReturn(Lists.newArrayList("user2"));
-
-    Multimap<String, NotificationChannel> multiMap = manager.findNotificationSubscribers(dispatcher, "struts");
-    assertThat(multiMap.entries()).hasSize(3);
-
-    Map<String, Collection<NotificationChannel>> map = multiMap.asMap();
-    assertThat(map.get("user1")).containsOnly(emailChannel);
-    assertThat(map.get("user2")).containsOnly(emailChannel, twitterChannel);
-    assertThat(map.get("other")).isNull();
-  }
 }
index 6950f8dd5fcccab1185ee261e206bd3d1f4db834..53bc9ea4778fac0c5f639faeee4bfc5376da0157 100644 (file)
@@ -73,9 +73,9 @@ public class ConfigurationTest {
     String randomKey = RandomStringUtils.randomAlphabetic(3);
     String randomNumberOfWhitespaces = StringUtils.repeat(" ", 1 + new Random().nextInt(10));
 
-    assertThat(t.apply(underTest.put(randomKey, randomNumberOfWhitespaces + String.valueOf(value)), randomKey)).contains(value);
-    assertThat(t.apply(underTest.put(randomKey, String.valueOf(value) + randomNumberOfWhitespaces), randomKey)).contains(value);
-    assertThat(t.apply(underTest.put(randomKey, randomNumberOfWhitespaces + String.valueOf(value) + randomNumberOfWhitespaces), randomKey)).contains(value);
+    assertThat(t.apply(underTest.put(randomKey, randomNumberOfWhitespaces + String.valueOf(value)), randomKey)).isEqualTo(Optional.of(value));
+    assertThat(t.apply(underTest.put(randomKey, String.valueOf(value) + randomNumberOfWhitespaces), randomKey)).isEqualTo(Optional.of(value));
+    assertThat(t.apply(underTest.put(randomKey, randomNumberOfWhitespaces + String.valueOf(value) + randomNumberOfWhitespaces), randomKey)).isEqualTo(Optional.of(value));
   }
 
   private static class DumpMapConfiguration implements Configuration {