]> source.dussan.org Git - sonarqube.git/commitdiff
SONARCLOUD-381 Create api/organization/sync_members
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Tue, 12 Feb 2019 10:59:29 +0000 (11:59 +0100)
committersonartech <sonartech@sonarsource.com>
Wed, 6 Mar 2019 10:30:41 +0000 (11:30 +0100)
* Rename organisation to organization in some SonarCloud directories/classes
* Add WS api/organizations/sync_members
* Get list of members from a GitHub organization
* sync_members fails when members sync is disabled

16 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/user/UserDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/user/UserMapper.java
server/sonar-db-dao/src/main/resources/org/sonar/db/permission/AuthorizationMapper.xml
server/sonar-db-dao/src/main/resources/org/sonar/db/user/UserMapper.xml
server/sonar-db-dao/src/test/java/org/sonar/db/permission/AuthorizationDaoTest.java
server/sonar-db-dao/src/test/java/org/sonar/db/user/UserDaoTest.java
server/sonar-server/src/main/java/org/sonar/server/organization/MemberUpdater.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/organization/ws/AddMemberAction.java
server/sonar-server/src/main/java/org/sonar/server/organization/ws/OrganizationsWsModule.java
server/sonar-server/src/main/java/org/sonar/server/organization/ws/RemoveMemberAction.java
server/sonar-server/src/test/java/org/sonar/server/organization/MemberUpdaterTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/organization/ws/AddMemberActionTest.java
server/sonar-server/src/test/java/org/sonar/server/organization/ws/OrganizationsWsModuleTest.java
server/sonar-server/src/test/java/org/sonar/server/organization/ws/RemoveMemberActionTest.java

index ea20cd1a87be5972cea764688ce4ec3fb944078c..6cc176675f0894f2347619796133f99954fcbe7f 100644 (file)
@@ -41,7 +41,7 @@ import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_
 public class AuthorizationDao implements Dao {
 
   /**
-  * Loads all the permissions granted to logged-in user for the specified organization
+  * Loads all the permissions granted to user for the specified organization
   */
   public Set<String> selectOrganizationPermissions(DbSession dbSession, String organizationUuid, int userId) {
     return mapper(dbSession).selectOrganizationPermissions(organizationUuid, userId);
@@ -94,6 +94,14 @@ public class AuthorizationDao implements Dao {
     return mapper(dbSession).countUsersWithGlobalPermissionExcludingUser(organizationUuid, permission, excludedUserId);
   }
 
+  /**
+   * The list of users who have the global permission.
+   * The anyone virtual group is not taken into account.
+   */
+  public List<Integer> selectUserIdsWithGlobalPermission(DbSession dbSession, String organizationUuid, String permission) {
+    return mapper(dbSession).selectUserIdsWithGlobalPermission(organizationUuid, permission);
+  }
+
   /**
    * The number of users who will still have the permission if the user {@code userId}
    * is removed from group {@code groupId}. The anyone virtual group is not taken into account.
index 31fba10b72f873936654398a8d49b5397caaadb8..454bef1daf347ec0e0badd492f9c2237a9903ab1 100644 (file)
@@ -39,6 +39,8 @@ public interface AuthorizationMapper {
   int countUsersWithGlobalPermissionExcludingUser(@Param("organizationUuid") String organizationUuid, @Param("permission") String permission,
     @Param("excludedUserId") int excludedUserId);
 
+  List<Integer> selectUserIdsWithGlobalPermission(@Param("organizationUuid") String organizationUuid, @Param("permission") String permission);
+
   int countUsersWithGlobalPermissionExcludingGroupMember(@Param("organizationUuid") String organizationUuid,
     @Param("permission") String permission, @Param("groupId") int groupId, @Param("userId") int userId);
 
index b1650456e5354cbf370e15cb2f5a80d95a227a0a..7fe0e24e73df7fb97c33b5d50b9d0d2ab802d703 100644 (file)
@@ -173,6 +173,10 @@ public class UserDao implements Dao {
     return mapper(dbSession).selectByExternalIdAndIdentityProvider(externalId, externalIdentityProvider);
   }
 
+  public List<UserDto> selectByExternalIdsAndIdentityProvider(DbSession dbSession, Collection<String> externalIds, String externalIdentityProvider) {
+    return executeLargeInputs(externalIds, e -> mapper(dbSession).selectByExternalIdsAndIdentityProvider(e, externalIdentityProvider));
+  }
+
   @CheckForNull
   public UserDto selectByExternalLoginAndIdentityProvider(DbSession dbSession, String externalLogin, String externalIdentityProvider) {
     return mapper(dbSession).selectByExternalLoginAndIdentityProvider(externalLogin, externalIdentityProvider);
index dde13c8a06f545c807b158e91fc5975cd1c65a64..8f1a77c7b86ee418ac569c80d4c97460026b3121 100644 (file)
@@ -62,6 +62,9 @@ public interface UserMapper {
   @CheckForNull
   UserDto selectByExternalIdAndIdentityProvider(@Param("externalId") String externalId, @Param("externalIdentityProvider") String externalExternalIdentityProvider);
 
+  List<UserDto> selectByExternalIdsAndIdentityProvider(@Param("externalIds") List<String> externalIds, @Param("externalIdentityProvider") String externalExternalIdentityProvider);
+
+  @CheckForNull
   UserDto selectByExternalLoginAndIdentityProvider(@Param("externalLogin") String externalLogin, @Param("externalIdentityProvider") String externalExternalIdentityProvider);
 
   void scrollAll(ResultHandler<UserDto> handler);
index 45fb21902cb290bbf8fb340a174b685d97cbb968..c0dfcd373e9130d0c91c90db91d3b64cb5e5d63b 100644 (file)
@@ -8,16 +8,16 @@
     from group_roles gr
     inner join groups_users gu on gr.group_id=gu.group_id
     where
-    gr.organization_uuid=#{organizationUuid,jdbcType=VARCHAR} and
+    gr.organization_uuid=#{organizationUuid, jdbcType=VARCHAR} and
     gr.resource_id is null and
-    gu.user_id=#{userId,jdbcType=INTEGER}
+    gu.user_id=#{userId, jdbcType=INTEGER}
 
     union
 
     select gr.role
     from group_roles gr
     where
-    gr.organization_uuid=#{organizationUuid,jdbcType=VARCHAR} and
+    gr.organization_uuid=#{organizationUuid, jdbcType=VARCHAR} and
     gr.group_id is null and
     gr.resource_id is null
 
@@ -26,8 +26,8 @@
     select ur.role
     from user_roles ur
     where
-    ur.organization_uuid=#{organizationUuid,jdbcType=VARCHAR} and
-    ur.user_id=#{userId,jdbcType=INTEGER}
+    ur.organization_uuid=#{organizationUuid, jdbcType=VARCHAR} and
+    ur.user_id=#{userId, jdbcType=INTEGER}
     and ur.resource_id is null
   </select>
 
@@ -35,7 +35,7 @@
     select gr.role
     from group_roles gr
     where
-    gr.organization_uuid=#{organizationUuid,jdbcType=VARCHAR} and
+    gr.organization_uuid=#{organizationUuid, jdbcType=VARCHAR} and
     gr.resource_id is null and
     gr.group_id is null
   </select>
       from groups_users gu
       inner join group_roles gr on gr.group_id = gu.group_id
       where
-      gr.organization_uuid = #{organizationUuid,jdbcType=VARCHAR} and
-      gr.role = #{permission,jdbcType=VARCHAR} and
+      gr.organization_uuid = #{organizationUuid, jdbcType=VARCHAR} and
+      gr.role = #{permission, jdbcType=VARCHAR} and
       gr.resource_id is null and
       gr.group_id is not null and
-      gr.group_id != #{excludedGroupId,jdbcType=INTEGER}
+      gr.group_id != #{excludedGroupId, jdbcType=INTEGER}
 
       union
 
       select ur.user_id
       from user_roles ur
       where
-      ur.organization_uuid = #{organizationUuid,jdbcType=VARCHAR} and
+      ur.organization_uuid = #{organizationUuid, jdbcType=VARCHAR} and
       ur.resource_id is null and
-      ur.role = #{permission,jdbcType=VARCHAR}
+      ur.role = #{permission, jdbcType=VARCHAR}
     ) remaining
   </select>
 
     from groups_users gu
     inner join group_roles gr on gr.group_id = gu.group_id
     where
-    gr.organization_uuid = #{organizationUuid,jdbcType=VARCHAR} and
-    gr.role = #{permission,jdbcType=VARCHAR} and
+    gr.organization_uuid = #{organizationUuid, jdbcType=VARCHAR} and
+    gr.role = #{permission, jdbcType=VARCHAR} and
     gr.resource_id is null and
     gr.group_id is not null and
-    gu.user_id != #{excludedUserId,jdbcType=INTEGER}
+    gu.user_id != #{excludedUserId, jdbcType=INTEGER}
 
     union
 
     select ur.user_id
     from user_roles ur
     where
-    ur.organization_uuid = #{organizationUuid,jdbcType=VARCHAR} and
+    ur.organization_uuid = #{organizationUuid, jdbcType=VARCHAR} and
     ur.resource_id is null and
-    ur.role = #{permission,jdbcType=VARCHAR} and
-    ur.user_id != #{excludedUserId,jdbcType=INTEGER}
+    ur.role = #{permission, jdbcType=VARCHAR} and
+    ur.user_id != #{excludedUserId, jdbcType=INTEGER}
     ) remaining
   </select>
 
+  <select id="selectUserIdsWithGlobalPermission" parameterType="map" resultType="int">
+    select gu.user_id
+    from groups_users gu
+    inner join group_roles gr on gr.group_id = gu.group_id
+    where
+    gr.organization_uuid = #{organizationUuid, jdbcType=VARCHAR} and
+    gr.role = #{permission, jdbcType=VARCHAR} and
+    gr.resource_id is null and
+    gr.group_id is not null
+
+    union
+
+    select ur.user_id
+    from user_roles ur
+    where
+    ur.organization_uuid = #{organizationUuid, jdbcType=VARCHAR} and
+    ur.resource_id is null and
+    ur.role = #{permission, jdbcType=VARCHAR}
+  </select>
+
   <select id="countUsersWithGlobalPermissionExcludingGroupMember" parameterType="map" resultType="int">
     select count(1) from
     (
     from groups_users gu
     inner join group_roles gr on gr.group_id = gu.group_id
     where
-    gr.organization_uuid = #{organizationUuid,jdbcType=VARCHAR} and
-    gr.role = #{permission,jdbcType=VARCHAR} and
+    gr.organization_uuid = #{organizationUuid, jdbcType=VARCHAR} and
+    gr.role = #{permission, jdbcType=VARCHAR} and
     gr.resource_id is null and
     gr.group_id is not null and
-    (gu.group_id != #{groupId,jdbcType=INTEGER} or gu.user_id != #{userId,jdbcType=INTEGER})
+    (gu.group_id != #{groupId, jdbcType=INTEGER} or gu.user_id != #{userId, jdbcType=INTEGER})
 
     union
 
     select ur.user_id
     from user_roles ur
     where
-    ur.organization_uuid = #{organizationUuid,jdbcType=VARCHAR} and
+    ur.organization_uuid = #{organizationUuid, jdbcType=VARCHAR} and
     ur.resource_id is null and
-    ur.role = #{permission,jdbcType=VARCHAR}
+    ur.role = #{permission, jdbcType=VARCHAR}
     ) remaining
   </select>
 
     from groups_users gu
     inner join group_roles gr on gr.group_id = gu.group_id
     where
-    gr.organization_uuid = #{organizationUuid,jdbcType=VARCHAR} and
-    gr.role = #{permission,jdbcType=VARCHAR} and
+    gr.organization_uuid = #{organizationUuid, jdbcType=VARCHAR} and
+    gr.role = #{permission, jdbcType=VARCHAR} and
     gr.resource_id is null and
     gr.group_id is not null
 
     select ur.user_id
     from user_roles ur
     where
-    ur.organization_uuid = #{organizationUuid,jdbcType=VARCHAR} and
+    ur.organization_uuid = #{organizationUuid, jdbcType=VARCHAR} and
     ur.resource_id is null and
-    ur.role = #{permission,jdbcType=VARCHAR} and
-    ur.user_id != #{userId,jdbcType=INTEGER}
+    ur.role = #{permission, jdbcType=VARCHAR} and
+    ur.user_id != #{userId, jdbcType=INTEGER}
     ) remaining
   </select>
 
     from group_roles gr
     inner join groups_users gu on gr.group_id = gu.group_id
     where
-    gr.role = #{permission,jdbcType=VARCHAR} and
+    gr.role = #{permission, jdbcType=VARCHAR} and
     gr.resource_id is null and
     gr.group_id is not null and
-    gu.user_id = #{userId,jdbcType=INTEGER}
+    gu.user_id = #{userId, jdbcType=INTEGER}
 
     union
 
     from user_roles ur
     where
     ur.resource_id is null and
-    ur.role = #{permission,jdbcType=VARCHAR} and
-    ur.user_id = #{userId,jdbcType=INTEGER}
+    ur.role = #{permission, jdbcType=VARCHAR} and
+    ur.user_id = #{userId, jdbcType=INTEGER}
   </select>
 
   <select id="keepAuthorizedProjectIdsForUser" parameterType="map" resultType="long">
     from
       group_roles gr
     where
-      gr.role=#{role,jdbcType=VARCHAR}
+      gr.role=#{role, jdbcType=VARCHAR}
       and (
         gr.group_id is null
         or exists (
         )
       )
       and <foreach collection="componentIds" open="(" close=")" item="element" index="index" separator=" or ">
-            gr.resource_id=#{element,jdbcType=BIGINT}
+            gr.resource_id=#{element, jdbcType=BIGINT}
           </foreach>
 
     union
     inner join projects p on
       p.id = ur.resource_id
     where
-      ur.role=#{role,jdbcType=VARCHAR}
-      and ur.user_id=#{userId,jdbcType=INTEGER}
+      ur.role=#{role, jdbcType=VARCHAR}
+      and ur.user_id=#{userId, jdbcType=INTEGER}
       and <foreach collection="componentIds" open="(" close=")" item="element" index="index" separator=" or ">
-        p.id=#{element,jdbcType=BIGINT}
+        p.id=#{element, jdbcType=BIGINT}
       </foreach>
 
     union
     from
       group_roles gr
     where
-      gr.role=#{role,jdbcType=VARCHAR}
+      gr.role=#{role, jdbcType=VARCHAR}
       and gr.group_id is null
       and <foreach collection="componentIds" open="(" close=")" item="element" index="index" separator=" or ">
-            gr.resource_id=#{element,jdbcType=BIGINT}
+            gr.resource_id=#{element, jdbcType=BIGINT}
           </foreach>
 
     union
     projects p
     where
     <foreach collection="componentIds" open="(" close=")" item="element" index="index" separator=" or ">
-      p.id=#{element,jdbcType=BIGINT}
+      p.id=#{element ,jdbcType=BIGINT}
     </foreach>
     and p.private = ${_false}
-    and #{role,jdbcType=VARCHAR} in ('user','codeviewer')
+    and #{role, jdbcType=VARCHAR} in ('user','codeviewer')
   </sql>
 
   <select id="keepAuthorizedProjectUuidsForUser" parameterType="map" resultType="String">
     from projects p
     inner join group_roles gr on p.id = gr.resource_id
     where
-      gr.role = #{permission,jdbcType=VARCHAR}
+      gr.role = #{permission, jdbcType=VARCHAR}
       and (gr.group_id is null or exists (
         select 1 from groups_users gu
         where
           gu.user_id = #{userId, jdbcType=INTEGER}
           and gr.group_id = gu.group_id)
       )
-      and p.uuid in <foreach collection="projectUuids" open="(" close=")" item="projectUuid" index="index" separator=",">#{projectUuid,jdbcType=VARCHAR}</foreach>
+      and p.uuid in <foreach collection="projectUuids" open="(" close=")" item="projectUuid" index="index" separator=",">#{projectUuid, jdbcType=VARCHAR}</foreach>
 
     union
 
     from projects p
     inner join user_roles ur on p.id = ur.resource_id
     where
-      ur.role=#{permission,jdbcType=VARCHAR}
-      and ur.user_id=#{userId,jdbcType=INTEGER}
-      and p.uuid in <foreach collection="projectUuids" open="(" close=")" item="projectUuid" index="index" separator=",">#{projectUuid,jdbcType=VARCHAR}</foreach>
+      ur.role=#{permission, jdbcType=VARCHAR}
+      and ur.user_id=#{userId, jdbcType=INTEGER}
+      and p.uuid in <foreach collection="projectUuids" open="(" close=")" item="projectUuid" index="index" separator=",">#{projectUuid, jdbcType=VARCHAR}</foreach>
 
     <if test="permission == 'user' or permission == 'codeviewer'">
       union
       select p.uuid
       from projects p
       where
-        p.uuid in <foreach collection="projectUuids" open="(" close=")" item="projectUuid" index="index" separator=",">#{projectUuid,jdbcType=VARCHAR}</foreach>
+        p.uuid in <foreach collection="projectUuids" open="(" close=")" item="projectUuid" index="index" separator=",">#{projectUuid, jdbcType=VARCHAR}</foreach>
         and p.private = ${_false}
     </if>
   </select>
     from projects p
     inner join group_roles gr on p.id = gr.resource_id
     where
-      gr.role=#{permission,jdbcType=VARCHAR}
+      gr.role=#{permission, jdbcType=VARCHAR}
       and gr.group_id is null
-      and p.uuid in <foreach collection="projectUuids" open="(" close=")" item="projectUuid" index="index" separator=",">#{projectUuid,jdbcType=VARCHAR}</foreach>
+      and p.uuid in <foreach collection="projectUuids" open="(" close=")" item="projectUuid" index="index" separator=",">#{projectUuid, jdbcType=VARCHAR}</foreach>
 
     <if test="permission == 'user' or permission == 'codeviewer'">
       union
       select p.uuid
       from projects p
       where
-      p.uuid in <foreach collection="projectUuids" open="(" close=")" item="projectUuid" index="index" separator=",">#{projectUuid,jdbcType=VARCHAR}</foreach>
+      p.uuid in <foreach collection="projectUuids" open="(" close=")" item="projectUuid" index="index" separator=",">#{projectUuid, jdbcType=VARCHAR}</foreach>
       and p.private = ${_false}
     </if>
   </select>
     inner join group_roles gr on
       gr.group_id=gu.group_id
     where
-      gr.resource_id=#{componentId,jdbcType=BIGINT}
-      and gr.role=#{role,jdbcType=VARCHAR}
+      gr.resource_id=#{componentId, jdbcType=BIGINT}
+      and gr.role=#{role, jdbcType=VARCHAR}
       and gu.user_id in
         <foreach collection="userIds" open="(" close=")" item="id" separator=",">
-          #{id,jdbcType=BIGINT}
+          #{id, jdbcType=BIGINT}
         </foreach>
 
     union
     from
       user_roles ur
     where
-      ur.resource_id=#{componentId,jdbcType=BIGINT}
-      and ur.role=#{role,jdbcType=VARCHAR}
+      ur.resource_id=#{componentId, jdbcType=BIGINT}
+      and ur.role=#{role, jdbcType=VARCHAR}
       and ur.user_id IN
         <foreach collection="userIds" open="(" close=")" item="id" separator=",">
-          #{id,jdbcType=BIGINT}
+          #{id, jdbcType=BIGINT}
         </foreach>
 
     union
     where
       u.id in
         <foreach collection="userIds" open="(" close=")" item="id" separator=",">
-          #{id,jdbcType=BIGINT}
+          #{id, jdbcType=BIGINT}
         </foreach>
       and exists (
         select
         from
           projects p
         where
-          p.id =#{componentId,jdbcType=BIGINT}
+          p.id =#{componentId, jdbcType=BIGINT}
           and p.private = ${_false}
-          and #{role,jdbcType=VARCHAR} in ('user','codeviewer')
+          and #{role, jdbcType=VARCHAR} in ('user','codeviewer')
       )
   </select>
 
     from user_roles ur
     inner join projects p on p.id = ur.resource_id
     where
-      p.uuid = #{projectUuid,jdbcType=VARCHAR} and
+      p.uuid = #{projectUuid, jdbcType=VARCHAR} and
       p.organization_uuid = ur.organization_uuid and
-      ur.user_id = #{userId,jdbcType=BIGINT}
+      ur.user_id = #{userId, jdbcType=BIGINT}
 
     union
 
     inner join groups_users gu on gr.group_id = gu.group_id
     inner join projects p on p.id = gr.resource_id
     where
-      p.uuid = #{projectUuid,jdbcType=VARCHAR} and
+      p.uuid = #{projectUuid, jdbcType=VARCHAR} and
       p.organization_uuid = gr.organization_uuid and
-      gu.user_id = #{userId,jdbcType=BIGINT}
+      gu.user_id = #{userId, jdbcType=BIGINT}
 
     union
 
     inner join projects p on
       p.id = gr.resource_id
     where
-      p.uuid = #{projectUuid,jdbcType=VARCHAR}
+      p.uuid = #{projectUuid, jdbcType=VARCHAR}
       and p.organization_uuid = gr.organization_uuid
       and gr.group_id is null
   </sql>
     from user_roles ur
     inner join users u on u.id=ur.user_id
     where
-    ur.role=#{permission,jdbcType=VARCHAR}
+    ur.role=#{permission, jdbcType=VARCHAR}
     and ur.resource_id is null
 
     union
     inner join groups_users gu on gr.group_id = gu.group_id
     inner join users u on u.id=gu.user_id
     where
-    gr.role = #{permission,jdbcType=VARCHAR} and
+    gr.role = #{permission, jdbcType=VARCHAR} and
     gr.resource_id is null and
     gr.group_id is not null
   </select>
     select u.login
     from users u
     where
-      u.login in <foreach collection="logins" open="(" close=")" item="login" separator=",">#{login,jdbcType=VARCHAR}</foreach>
+      u.login in <foreach collection="logins" open="(" close=")" item="login" separator=",">#{login, jdbcType=VARCHAR}</foreach>
       and (
         exists (
           select 1
           from user_roles ur
           inner join projects p on p.id = ur.resource_id and p.organization_uuid = ur.organization_uuid
           where
-            p.kee =  #{projectKey,jdbcType=VARCHAR}
-            and ur.role = #{permission,jdbcType=VARCHAR}
+            p.kee =  #{projectKey, jdbcType=VARCHAR}
+            and ur.role = #{permission, jdbcType=VARCHAR}
             and ur.user_id = u.id
         ) or exists (
           select 1
           inner join group_roles gr on gr.resource_id = p.id and gr.organization_uuid = p.organization_uuid
           inner join groups_users gu on gu.group_id = gr.group_id
           where
-            p.kee  =  #{projectKey,jdbcType=VARCHAR}
+            p.kee  =  #{projectKey, jdbcType=VARCHAR}
             and gu.user_id = u.id
-            and gr.role = #{permission,jdbcType=VARCHAR}
+            and gr.role = #{permission, jdbcType=VARCHAR}
         )
         <if test="permission == 'user' or permission == 'codeviewer'">
           or exists (
             select 1
             from projects p
             where
-              p.kee =  #{projectKey,jdbcType=VARCHAR}
+              p.kee =  #{projectKey, jdbcType=VARCHAR}
               and p.private = ${_false}
           )
         </if>
index 1a08f28b2bbaf64d376c246a0eae1e0586daf400..bf0ee3a5d812a1bb00d1d145d145f07e34c12210 100644 (file)
         SELECT
         <include refid="userColumns"/>
         FROM users u
-        WHERE u.uuid=#{uuid}
+        WHERE u.uuid=#{uuid, jdbcType=VARCHAR}
     </select>
 
     <select id="selectByLogin" parameterType="String" resultType="User">
         SELECT
         <include refid="userColumns"/>
         FROM users u
-        WHERE u.login=#{login}
+        WHERE u.login=#{login, jdbcType=VARCHAR}
     </select>
 
     <select id="selectNullableByScmAccountOrLoginOrEmail" parameterType="map" resultType="User">
         <include refid="userColumns"/>
         FROM users u
         WHERE
-        u.login=#{scmAccount}
-        OR u.email=#{scmAccount}
-        OR u.scm_accounts like #{likeScmAccount}
+        u.login=#{scmAccount, jdbcType=VARCHAR}
+        OR u.email=#{scmAccount, jdbcType=VARCHAR}
+        OR u.scm_accounts like #{likeScmAccount, jdbcType=VARCHAR}
     </select>
 
     <select id="selectUser" parameterType="int" resultType="User">
         SELECT
         <include refid="userColumns"/>
         FROM users u
-        WHERE u.id=#{id}
+        WHERE u.id=#{id, jdbcType=INTEGER}
     </select>
 
     <select id="selectUserByLogin" parameterType="string" resultType="User">
         SELECT
         <include refid="userColumns"/>
         FROM users u
-        WHERE u.login=#{id} AND u.active=${_true}
+        WHERE u.login=#{id, jdbcType=INTEGER} AND u.active=${_true}
     </select>
 
     <select id="selectByLogins" parameterType="string" resultType="User">
@@ -72,7 +72,7 @@
         FROM users u
         WHERE u.login in
         <foreach collection="list" open="(" close=")" item="login" separator=",">
-            #{login}
+            #{login, jdbcType=VARCHAR}
         </foreach>
     </select>
 
@@ -82,7 +82,7 @@
         FROM users u
         WHERE u.uuid in
         <foreach collection="list" open="(" close=")" item="uuid" separator=",">
-            #{uuid}
+            #{uuid, jdbcType=VARCHAR}
         </foreach>
     </select>
 
@@ -98,7 +98,7 @@
         FROM users u
         WHERE u.id in
         <foreach collection="ids" open="(" close=")" item="id" separator=",">
-            #{id}
+            #{id, jdbcType=INTEGER}
         </foreach>
     </select>
 
             <if test="logins != null and logins.size() > 0">
                 u.login IN
                 <foreach item="login" index="index" collection="logins" open="(" separator="," close=")">
-                    #{login}
+                    #{login, jdbcType=VARCHAR}
                 </foreach>
             </if>
             <if test="includeDeactivated==false">
                 AND u.active=${_true}
             </if>
             <if test="searchText != null">
-                AND (u.login LIKE #{searchTextSql} ESCAPE '/' OR u.name LIKE #{searchTextSql} ESCAPE '/')
+                AND (u.login LIKE #{searchTextSql, jdbcType=VARCHAR} ESCAPE '/' OR u.name LIKE #{searchTextSql, jdbcType=VARCHAR} ESCAPE '/')
             </if>
             <if test="mustBeRoot != null and mustBeRoot==true">
                 AND u.is_root = ${_true}
         SELECT
         <include refid="userColumns"/>
         FROM users u
-        WHERE u.external_id=#{externalId} AND u.external_identity_provider=#{externalIdentityProvider, jdbcType=VARCHAR}
+        WHERE u.external_id=#{externalId, jdbcType=VARCHAR} AND u.external_identity_provider=#{externalIdentityProvider, jdbcType=VARCHAR}
+    </select>
+
+    <select id="selectByExternalIdsAndIdentityProvider" parameterType="map" resultType="User">
+        SELECT
+        <include refid="userColumns"/>
+        FROM users u
+        WHERE u.external_identity_provider=#{externalIdentityProvider, jdbcType=VARCHAR}
+        AND u.external_id in
+        <foreach collection="externalIds" open="(" close=")" item="externalId" separator=",">
+            #{externalId, jdbcType=VARCHAR}
+        </foreach>
     </select>
 
     <select id="selectByExternalLoginAndIdentityProvider" parameterType="map" resultType="User">
         SELECT
         <include refid="userColumns"/>
         FROM users u
-        WHERE u.external_login=#{externalLogin} AND u.external_identity_provider=#{externalIdentityProvider, jdbcType=VARCHAR}
+        WHERE u.external_login=#{externalLogin, jdbcType=VARCHAR} AND u.external_identity_provider=#{externalIdentityProvider, jdbcType=VARCHAR}
     </select>
 
     <select id="countRootUsersButLogin" parameterType="String" resultType="long">
index 3bbc75e078ba60d811dec27d5fee4aeea0d6dfce..6b66d3b28da89f7b0efcc2f0a3a5c89d0be32482 100644 (file)
@@ -48,6 +48,7 @@ import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
 import static org.sonar.db.permission.OrganizationPermission.ADMINISTER;
 import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_GATES;
 import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_PROFILES;
+import static org.sonar.db.permission.OrganizationPermission.PROVISION_PROJECTS;
 import static org.sonar.db.permission.OrganizationPermission.SCAN;
 
 public class AuthorizationDaoTest {
@@ -225,6 +226,35 @@ public class AuthorizationDaoTest {
       organization.getUuid(), "missingPermission", group1.getId())).isEqualTo(0);
   }
 
+  @Test
+  public void selectUserIdsWithGlobalPermission() {
+    // group g1 has the permission p1 and has members user1 and user2
+    // user3 has the permission
+    UserDto user1 = db.users().insertUser();
+    UserDto user2 = db.users().insertUser();
+    UserDto user3 = db.users().insertUser();
+
+    OrganizationDto organization = db.organizations().insert();
+    GroupDto group1 = db.users().insertGroup(organization);
+    db.users().insertPermissionOnGroup(group1, ADMINISTER);
+    db.users().insertPermissionOnGroup(group1, PROVISION_PROJECTS);
+    db.users().insertMember(group1, user1);
+    db.users().insertMember(group1, user2);
+    db.users().insertPermissionOnUser(organization, user3, ADMINISTER);
+    db.users().insertPermissionOnAnyone(organization, ADMINISTER);
+
+    // other organizations are ignored
+    OrganizationDto org2 = db.organizations().insert();
+    db.users().insertPermissionOnUser(org2, user1, ADMINISTER);
+
+    assertThat(underTest.selectUserIdsWithGlobalPermission(db.getSession(), organization.getUuid(), ADMINISTER.getKey()))
+      .containsExactlyInAnyOrder(user1.getId(), user2.getId(), user3.getId());
+    assertThat(underTest.selectUserIdsWithGlobalPermission(db.getSession(), organization.getUuid(), PROVISION_PROJECTS.getKey()))
+      .containsExactlyInAnyOrder(user1.getId(), user2.getId());
+    assertThat(underTest.selectUserIdsWithGlobalPermission(db.getSession(), org2.getUuid(), ADMINISTER.getKey()))
+      .containsExactlyInAnyOrder(user1.getId());
+  }
+
   @Test
   public void keepAuthorizedProjectIds_returns_empty_for_group_AnyOne_if_project_set_is_empty_on_public_project() {
     assertThat(underTest.keepAuthorizedProjectIds(dbSession, Collections.emptySet(), null, UserRole.USER))
index 4ca9024c59e11663449beda8f0523aa39e626a29..5e55b7a7706d501d0b6acdbc77875090193645bd 100644 (file)
@@ -37,6 +37,7 @@ import org.sonar.db.organization.OrganizationDto;
 
 import static java.util.Arrays.asList;
 import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
 import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.groups.Tuple.tuple;
@@ -611,6 +612,22 @@ public class UserDaoTest {
     assertThat(underTest.selectByExternalIdAndIdentityProvider(session, "unknown", "unknown")).isNull();
   }
 
+  @Test
+  public void select_by_external_ids_and_identity_provider() {
+    UserDto user1 = db.users().insertUser(u -> u.setExternalIdentityProvider("github"));
+    UserDto user2 = db.users().insertUser(u -> u.setExternalIdentityProvider("github"));
+    UserDto user3 = db.users().insertUser(u -> u.setExternalIdentityProvider("bitbucket"));
+    UserDto disableUser = db.users().insertDisabledUser(u -> u.setExternalIdentityProvider("github"));
+
+    assertThat(underTest.selectByExternalIdsAndIdentityProvider(session, singletonList(user1.getExternalId()), "github"))
+      .extracting(UserDto::getUuid).containsExactlyInAnyOrder(user1.getUuid());
+    assertThat(underTest.selectByExternalIdsAndIdentityProvider(session,
+      asList(user1.getExternalId(), user2.getExternalId(), user3.getExternalId(), disableUser.getExternalId()), "github"))
+        .extracting(UserDto::getUuid).containsExactlyInAnyOrder(user1.getUuid(), user2.getUuid(), disableUser.getUuid());
+    assertThat(underTest.selectByExternalIdsAndIdentityProvider(session, singletonList("unknown"), "github")).isEmpty();
+    assertThat(underTest.selectByExternalIdsAndIdentityProvider(session, singletonList(user1.getExternalId()), "unknown")).isEmpty();
+  }
+
   @Test
   public void select_by_external_login_and_identity_provider() {
     UserDto activeUser = db.users().insertUser();
diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/MemberUpdater.java b/server/sonar-server/src/main/java/org/sonar/server/organization/MemberUpdater.java
new file mode 100644 (file)
index 0000000..24dd4ea
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.organization;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.organization.OrganizationDto;
+import org.sonar.db.organization.OrganizationMemberDto;
+import org.sonar.db.user.UserDto;
+import org.sonar.db.user.UserGroupDto;
+import org.sonar.server.user.index.UserIndexer;
+import org.sonar.server.usergroups.DefaultGroupFinder;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.Sets.difference;
+import static java.util.Collections.singletonList;
+import static java.util.stream.Collectors.toSet;
+import static org.sonar.api.CoreProperties.DEFAULT_ISSUE_ASSIGNEE;
+import static org.sonar.core.util.stream.MoreCollectors.toList;
+import static org.sonar.db.permission.OrganizationPermission.ADMINISTER;
+
+public class MemberUpdater {
+
+  private final DbClient dbClient;
+  private final DefaultGroupFinder defaultGroupFinder;
+  private final UserIndexer userIndexer;
+
+  public MemberUpdater(DbClient dbClient, DefaultGroupFinder defaultGroupFinder, UserIndexer userIndexer) {
+    this.dbClient = dbClient;
+    this.defaultGroupFinder = defaultGroupFinder;
+    this.userIndexer = userIndexer;
+  }
+
+  public void addMember(DbSession dbSession, OrganizationDto organization, UserDto user) {
+    addMembers(dbSession, organization, singletonList(user));
+  }
+
+  public void addMembers(DbSession dbSession, OrganizationDto organization, List<UserDto> users) {
+    Set<Integer> currentMemberIds = new HashSet<>(dbClient.organizationMemberDao().selectUserIdsByOrganizationUuid(dbSession, organization.getUuid()));
+    List<UserDto> usersToAdd = users.stream()
+      .filter(UserDto::isActive)
+      .filter(u -> !currentMemberIds.contains(u.getId()))
+      .collect(toList());
+    if (usersToAdd.isEmpty()){
+      return;
+    }
+    usersToAdd.forEach(u -> addMemberInDb(dbSession, organization, u));
+    userIndexer.commitAndIndex(dbSession, usersToAdd);
+  }
+
+  private void addMemberInDb(DbSession dbSession, OrganizationDto organization, UserDto user) {
+    dbClient.organizationMemberDao().insert(dbSession, new OrganizationMemberDto()
+      .setOrganizationUuid(organization.getUuid())
+      .setUserId(user.getId()));
+    dbClient.userGroupDao().insert(dbSession,
+      new UserGroupDto().setGroupId(defaultGroupFinder.findDefaultGroup(dbSession, organization.getUuid()).getId()).setUserId(user.getId()));
+  }
+
+  public void removeMember(DbSession dbSession, OrganizationDto organization, UserDto user) {
+    removeMembers(dbSession, organization, singletonList(user));
+  }
+
+  public void removeMembers(DbSession dbSession, OrganizationDto organization, List<UserDto> users) {
+    Set<Integer> currentMemberIds = new HashSet<>(dbClient.organizationMemberDao().selectUserIdsByOrganizationUuid(dbSession, organization.getUuid()));
+    List<UserDto> usersToRemove = users.stream()
+      .filter(UserDto::isActive)
+      .filter(u -> currentMemberIds.contains(u.getId()))
+      .collect(toList());
+    if (usersToRemove.isEmpty()){
+      return;
+    }
+
+    Set<Integer> userIdsToRemove = usersToRemove.stream().map(UserDto::getId).collect(toSet());
+    Set<Integer> adminIds = new HashSet<>(dbClient.authorizationDao().selectUserIdsWithGlobalPermission(dbSession, organization.getUuid(), ADMINISTER.getKey()));
+    checkArgument(!difference(adminIds, userIdsToRemove).isEmpty(), "The last administrator member cannot be removed");
+
+    usersToRemove.forEach(u -> removeMemberInDb(dbSession, organization, u));
+    userIndexer.commitAndIndex(dbSession, usersToRemove);
+  }
+
+  private void removeMemberInDb(DbSession dbSession, OrganizationDto organization, UserDto user) {
+    int userId = user.getId();
+    String organizationUuid = organization.getUuid();
+    dbClient.userPermissionDao().deleteOrganizationMemberPermissions(dbSession, organizationUuid, userId);
+    dbClient.permissionTemplateDao().deleteUserPermissionsByOrganization(dbSession, organizationUuid, userId);
+    dbClient.qProfileEditUsersDao().deleteByOrganizationAndUser(dbSession, organization, user);
+    dbClient.userGroupDao().deleteByOrganizationAndUser(dbSession, organizationUuid, userId);
+    dbClient.propertiesDao().deleteByOrganizationAndUser(dbSession, organizationUuid, userId);
+    dbClient.propertiesDao().deleteByOrganizationAndMatchingLogin(dbSession, organizationUuid, user.getLogin(), singletonList(DEFAULT_ISSUE_ASSIGNEE));
+
+    dbClient.organizationMemberDao().delete(dbSession, organizationUuid, userId);
+  }
+
+}
index a4f4ceec2777f6a7c68e302af1375cd07cf14a34..6e3dfb7d8dd90c6b587f5c144ac8f03d003cbec4 100644 (file)
@@ -26,15 +26,12 @@ import org.sonar.api.server.ws.WebService.NewController;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.organization.OrganizationDto;
-import org.sonar.db.organization.OrganizationMemberDto;
 import org.sonar.db.permission.OrganizationPermission;
 import org.sonar.db.user.GroupMembershipQuery;
 import org.sonar.db.user.UserDto;
-import org.sonar.db.user.UserGroupDto;
 import org.sonar.server.issue.ws.AvatarResolver;
+import org.sonar.server.organization.MemberUpdater;
 import org.sonar.server.user.UserSession;
-import org.sonar.server.user.index.UserIndexer;
-import org.sonar.server.usergroups.DefaultGroupFinder;
 import org.sonarqube.ws.Organizations.AddMemberWsResponse;
 import org.sonarqube.ws.Organizations.User;
 
@@ -51,19 +48,17 @@ import static org.sonar.server.ws.WsUtils.writeProtobuf;
 public class AddMemberAction implements OrganizationsWsAction {
   private final DbClient dbClient;
   private final UserSession userSession;
-  private final UserIndexer userIndexer;
-  private final DefaultGroupFinder defaultGroupFinder;
   private final AvatarResolver avatarResolver;
   private final OrganizationsWsSupport wsSupport;
+  private final MemberUpdater memberUpdater;
 
-  public AddMemberAction(DbClient dbClient, UserSession userSession, UserIndexer userIndexer, DefaultGroupFinder defaultGroupFinder,
-    AvatarResolver avatarResolver, OrganizationsWsSupport wsSupport) {
+  public AddMemberAction(DbClient dbClient, UserSession userSession, AvatarResolver avatarResolver, OrganizationsWsSupport wsSupport,
+    MemberUpdater memberUpdater) {
     this.dbClient = dbClient;
     this.userSession = userSession;
-    this.userIndexer = userIndexer;
-    this.defaultGroupFinder = defaultGroupFinder;
     this.avatarResolver = avatarResolver;
     this.wsSupport = wsSupport;
+    this.memberUpdater = memberUpdater;
   }
 
   @Override
@@ -98,10 +93,10 @@ public class AddMemberAction implements OrganizationsWsAction {
     try (DbSession dbSession = dbClient.openSession(false)) {
       OrganizationDto organization = checkFoundWithOptional(dbClient.organizationDao().selectByKey(dbSession, organizationKey), "Organization '%s' is not found",
         organizationKey);
-      UserDto user = checkFound(dbClient.userDao().selectByLogin(dbSession, login), "User '%s' is not found", login);
+      userSession.checkPermission(OrganizationPermission.ADMINISTER, organization);
       wsSupport.checkMemberSyncIsDisabled(dbSession, organization);
-
-      addMember(dbSession, organization, user);
+      UserDto user = checkFound(dbClient.userDao().selectByLogin(dbSession, login), "User '%s' is not found", login);
+      memberUpdater.addMember(dbSession, organization, user);
 
       int groups = dbClient.groupMembershipDao().countGroups(dbSession, GroupMembershipQuery.builder()
         .organizationUuid(organization.getUuid())
@@ -112,20 +107,6 @@ public class AddMemberAction implements OrganizationsWsAction {
     }
   }
 
-  private void addMember(DbSession dbSession, OrganizationDto organization, UserDto user) {
-    userSession.checkPermission(OrganizationPermission.ADMINISTER, organization);
-    if (isMemberOf(dbSession, organization, user)) {
-      return;
-    }
-
-    dbClient.organizationMemberDao().insert(dbSession, new OrganizationMemberDto()
-      .setOrganizationUuid(organization.getUuid())
-      .setUserId(user.getId()));
-    dbClient.userGroupDao().insert(dbSession,
-      new UserGroupDto().setGroupId(defaultGroupFinder.findDefaultGroup(dbSession, organization.getUuid()).getId()).setUserId(user.getId()));
-    userIndexer.commitAndIndex(dbSession, user);
-  }
-
   private AddMemberWsResponse buildResponse(UserDto user, int groups) {
     AddMemberWsResponse.Builder response = AddMemberWsResponse.newBuilder();
     User.Builder wsUser = User.newBuilder()
@@ -137,8 +118,4 @@ public class AddMemberAction implements OrganizationsWsAction {
     return response.build();
   }
 
-  private boolean isMemberOf(DbSession dbSession, OrganizationDto organizationDto, UserDto userDto) {
-    return dbClient.organizationMemberDao().select(dbSession, organizationDto.getUuid(), userDto.getId()).isPresent();
-  }
-
 }
index 695466e83e1184840a1da80f38b67f0976c644ec..d912f07069e2ab71b2b83bb57a567bba238069fb 100644 (file)
@@ -21,6 +21,7 @@ package org.sonar.server.organization.ws;
 
 import org.sonar.api.config.Configuration;
 import org.sonar.core.platform.Module;
+import org.sonar.server.organization.MemberUpdater;
 import org.sonar.server.organization.OrganisationSupport;
 
 import static org.sonar.process.ProcessProperties.Property.SONARCLOUD_ENABLED;
@@ -49,6 +50,7 @@ public class OrganizationsWsModule extends Module {
         AddMemberAction.class,
         CreateAction.class,
         DeleteAction.class,
+        MemberUpdater.class,
         RemoveMemberAction.class,
         UpdateAction.class,
         SetMembersSyncAction.class);
index 02e085860b892bb80f71ce460e0e6202e92a590b..405c0098cf01f18c85ae0525a2a2b94a08386ef4 100644 (file)
@@ -27,30 +27,28 @@ import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.organization.OrganizationDto;
 import org.sonar.db.user.UserDto;
+import org.sonar.server.organization.MemberUpdater;
 import org.sonar.server.user.UserSession;
-import org.sonar.server.user.index.UserIndexer;
 
-import static java.util.Collections.singletonList;
-import static org.sonar.api.CoreProperties.DEFAULT_ISSUE_ASSIGNEE;
 import static org.sonar.db.permission.OrganizationPermission.ADMINISTER;
 import static org.sonar.server.organization.ws.OrganizationsWsSupport.PARAM_LOGIN;
 import static org.sonar.server.organization.ws.OrganizationsWsSupport.PARAM_ORGANIZATION;
 import static org.sonar.server.ws.KeyExamples.KEY_ORG_EXAMPLE_001;
 import static org.sonar.server.ws.WsUtils.checkFound;
 import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;
-import static org.sonar.server.ws.WsUtils.checkRequest;
 
 public class RemoveMemberAction implements OrganizationsWsAction {
   private final DbClient dbClient;
   private final UserSession userSession;
-  private final UserIndexer userIndexer;
   private final OrganizationsWsSupport wsSupport;
+  private final MemberUpdater memberUpdater;
 
-  public RemoveMemberAction(DbClient dbClient, UserSession userSession, UserIndexer userIndexer, OrganizationsWsSupport wsSupport) {
+  public RemoveMemberAction(DbClient dbClient, UserSession userSession, OrganizationsWsSupport wsSupport,
+    MemberUpdater memberUpdater) {
     this.dbClient = dbClient;
     this.userSession = userSession;
-    this.userIndexer = userIndexer;
     this.wsSupport = wsSupport;
+    this.memberUpdater = memberUpdater;
   }
 
   @Override
@@ -84,33 +82,13 @@ public class RemoveMemberAction implements OrganizationsWsAction {
     try (DbSession dbSession = dbClient.openSession(false)) {
       OrganizationDto organization = checkFoundWithOptional(dbClient.organizationDao().selectByKey(dbSession, organizationKey),
         "Organization '%s' is not found", organizationKey);
-      UserDto user = checkFound(dbClient.userDao().selectActiveUserByLogin(dbSession, login), "User '%s' is not found", login);
       userSession.checkPermission(ADMINISTER, organization);
       wsSupport.checkMemberSyncIsDisabled(dbSession, organization);
-      dbClient.organizationMemberDao().select(dbSession, organization.getUuid(), user.getId())
-        .ifPresent(om -> removeMember(dbSession, organization, user));
+
+      UserDto user = checkFound(dbClient.userDao().selectActiveUserByLogin(dbSession, login), "User '%s' is not found", login);
+      memberUpdater.removeMember(dbSession, organization, user);
     }
     response.noContent();
   }
 
-  private void removeMember(DbSession dbSession, OrganizationDto organization, UserDto user) {
-    ensureLastAdminIsNotRemoved(dbSession, organization, user);
-    int userId = user.getId();
-    String organizationUuid = organization.getUuid();
-    dbClient.userPermissionDao().deleteOrganizationMemberPermissions(dbSession, organizationUuid, userId);
-    dbClient.permissionTemplateDao().deleteUserPermissionsByOrganization(dbSession, organizationUuid, userId);
-    dbClient.qProfileEditUsersDao().deleteByOrganizationAndUser(dbSession, organization, user);
-    dbClient.userGroupDao().deleteByOrganizationAndUser(dbSession, organizationUuid, userId);
-    dbClient.propertiesDao().deleteByOrganizationAndUser(dbSession, organizationUuid, userId);
-    dbClient.propertiesDao().deleteByOrganizationAndMatchingLogin(dbSession, organizationUuid, user.getLogin(), singletonList(DEFAULT_ISSUE_ASSIGNEE));
-
-    dbClient.organizationMemberDao().delete(dbSession, organizationUuid, userId);
-    userIndexer.commitAndIndex(dbSession, user);
-  }
-
-  private void ensureLastAdminIsNotRemoved(DbSession dbSession, OrganizationDto organizationDto, UserDto user) {
-    int remainingAdmins = dbClient.authorizationDao().countUsersWithGlobalPermissionExcludingUser(dbSession,
-      organizationDto.getUuid(), ADMINISTER.getKey(), user.getId());
-    checkRequest(remainingAdmins > 0, "The last administrator member cannot be removed");
-  }
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/organization/MemberUpdaterTest.java b/server/sonar-server/src/test/java/org/sonar/server/organization/MemberUpdaterTest.java
new file mode 100644 (file)
index 0000000..c89dc36
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.organization;
+
+import java.util.HashSet;
+import javax.annotation.Nullable;
+import org.assertj.core.groups.Tuple;
+import org.elasticsearch.action.search.SearchRequestBuilder;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.organization.OrganizationDto;
+import org.sonar.db.permission.OrganizationPermission;
+import org.sonar.db.permission.template.PermissionTemplateDto;
+import org.sonar.db.permission.template.PermissionTemplateUserDto;
+import org.sonar.db.property.PropertyDto;
+import org.sonar.db.property.PropertyQuery;
+import org.sonar.db.qualityprofile.QProfileDto;
+import org.sonar.db.user.GroupDto;
+import org.sonar.db.user.GroupMembershipDto;
+import org.sonar.db.user.GroupMembershipQuery;
+import org.sonar.db.user.UserDto;
+import org.sonar.server.es.EsTester;
+import org.sonar.server.es.SearchOptions;
+import org.sonar.server.user.index.UserDoc;
+import org.sonar.server.user.index.UserIndex;
+import org.sonar.server.user.index.UserIndexDefinition;
+import org.sonar.server.user.index.UserIndexer;
+import org.sonar.server.user.index.UserQuery;
+import org.sonar.server.usergroups.DefaultGroupFinder;
+
+import static java.lang.String.format;
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
+import static org.elasticsearch.index.query.QueryBuilders.termQuery;
+import static org.sonar.api.CoreProperties.DEFAULT_ISSUE_ASSIGNEE;
+import static org.sonar.api.web.UserRole.CODEVIEWER;
+import static org.sonar.api.web.UserRole.USER;
+import static org.sonar.db.permission.OrganizationPermission.ADMINISTER;
+import static org.sonar.db.permission.OrganizationPermission.SCAN;
+import static org.sonar.db.user.GroupMembershipQuery.IN;
+import static org.sonar.server.user.index.UserIndexDefinition.FIELD_ORGANIZATION_UUIDS;
+import static org.sonar.server.user.index.UserIndexDefinition.FIELD_UUID;
+
+public class MemberUpdaterTest {
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+  @Rule
+  public EsTester es = EsTester.create();
+  @Rule
+  public DbTester db = DbTester.create();
+
+  private DbClient dbClient = db.getDbClient();
+  private UserIndex userIndex = new UserIndex(es.client(), System2.INSTANCE);
+  private UserIndexer userIndexer = new UserIndexer(dbClient, es.client());
+
+  private MemberUpdater underTest = new MemberUpdater(dbClient, new DefaultGroupFinder(dbClient), userIndexer);
+
+  @Test
+  public void add_member_in_db_and_user_index() {
+    OrganizationDto organization = db.organizations().insert();
+    db.users().insertDefaultGroup(organization, "Members");
+    UserDto user = db.users().insertUser();
+
+    underTest.addMember(db.getSession(), organization, user);
+
+    assertUserIsMember(organization, user);
+    assertThat(userIndex.search(UserQuery.builder().build(), new SearchOptions()).getDocs())
+      .extracting(UserDoc::login, UserDoc::organizationUuids)
+      .containsExactlyInAnyOrder(tuple(user.getLogin(), singletonList(organization.getUuid())));
+  }
+
+  @Test
+  public void does_not_fail_to_add_member_if_user_already_added_in_organization() {
+    OrganizationDto organization = db.organizations().insert();
+    GroupDto defaultGroup = db.users().insertDefaultGroup(organization, "Members");
+    UserDto user = db.users().insertUser();
+    db.organizations().addMember(organization, user);
+    db.users().insertMember(defaultGroup, user);
+    assertUserIsMember(organization, user);
+
+    underTest.addMember(db.getSession(), organization, user);
+
+    assertUserIsMember(organization, user);
+  }
+
+  @Test
+  public void add_member_fails_when_organization_has_no_default_group() {
+    OrganizationDto organization = db.organizations().insert();
+    UserDto user = db.users().insertUser();
+
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage(format("Default group cannot be found on organization '%s'", organization.getUuid()));
+
+    underTest.addMember(db.getSession(), organization, user);
+  }
+
+  @Test
+  public void add_members_in_db_and_user_index() {
+    OrganizationDto organization = db.organizations().insert();
+    db.users().insertDefaultGroup(organization, "Members");
+    UserDto user1 = db.users().insertUser();
+    UserDto user2 = db.users().insertUser();
+    UserDto disableUser = db.users().insertDisabledUser();
+
+    underTest.addMembers(db.getSession(), organization, asList(user1, user2, disableUser));
+
+    assertUserIsMember(organization, user1);
+    assertUserIsMember(organization, user2);
+    assertUserIsNotMember(organization, disableUser);
+    assertThat(userIndex.search(UserQuery.builder().build(), new SearchOptions()).getDocs())
+      .extracting(UserDoc::login, UserDoc::organizationUuids)
+      .containsExactlyInAnyOrder(
+        tuple(user1.getLogin(), singletonList(organization.getUuid())),
+        tuple(user2.getLogin(), singletonList(organization.getUuid())));
+  }
+
+  @Test
+  public void add_members_does_not_fail_when_one_user_is_already_member_of_organization() {
+    OrganizationDto organization = db.organizations().insert();
+    GroupDto defaultGroup = db.users().insertDefaultGroup(organization, "Members");
+    UserDto userAlreadyMember = db.users().insertUser();
+    db.organizations().addMember(organization, userAlreadyMember);
+    db.users().insertMember(defaultGroup, userAlreadyMember);
+    UserDto userNotMember = db.users().insertUser();
+    userIndexer.indexOnStartup(new HashSet<>());
+
+    underTest.addMembers(db.getSession(), organization, asList(userAlreadyMember, userNotMember));
+
+    assertUserIsMember(organization, userAlreadyMember);
+    assertUserIsMember(organization, userNotMember);
+    assertThat(userIndex.search(UserQuery.builder().build(), new SearchOptions()).getDocs())
+      .extracting(UserDoc::login, UserDoc::organizationUuids)
+      .containsExactlyInAnyOrder(
+        tuple(userAlreadyMember.getLogin(), singletonList(organization.getUuid())),
+        tuple(userNotMember.getLogin(), singletonList(organization.getUuid())));
+  }
+
+  @Test
+  public void remove_member_from_db_and_user_index() {
+    OrganizationDto organization = db.organizations().insert();
+    GroupDto defaultGroup = db.users().insertDefaultGroup(organization, "Members");
+    UserDto user = db.users().insertUser();
+    UserDto adminUser = db.users().insertAdminByUserPermission(organization);
+    db.organizations().addMember(organization, user, adminUser);
+    db.users().insertMember(defaultGroup, user);
+    userIndexer.indexOnStartup(new HashSet<>());
+
+    underTest.removeMember(db.getSession(), organization, user);
+
+    assertUserIsNotMember(organization, user);
+  }
+
+  @Test
+  public void remove_members_from_db_and_user_index() {
+    OrganizationDto organization = db.organizations().insert();
+    GroupDto defaultGroup = db.users().insertDefaultGroup(organization, "Members");
+    UserDto user1 = db.users().insertUser();
+    UserDto user2 = db.users().insertUser();
+    UserDto adminUser = db.users().insertAdminByUserPermission(organization);
+    db.organizations().addMember(organization, user1, user2, adminUser);
+    db.users().insertMember(defaultGroup, user1);
+    db.users().insertMember(defaultGroup, user2);
+    db.users().insertMember(defaultGroup, adminUser);
+    userIndexer.indexOnStartup(new HashSet<>());
+
+    underTest.removeMembers(db.getSession(), organization, asList(user1, user2));
+
+    assertUserIsNotMember(organization, user1);
+    assertUserIsNotMember(organization, user2);
+    assertUserIsMember(organization, adminUser);
+  }
+
+  @Test
+  public void remove_member_removes_permissions() {
+    OrganizationDto organization = db.organizations().insert();
+    ComponentDto project = db.components().insertPrivateProject(organization);
+    GroupDto defaultGroup = db.users().insertDefaultGroup(organization, "Members");
+    UserDto user = db.users().insertUser();
+    UserDto adminUser = db.users().insertAdminByUserPermission(organization);
+    db.organizations().addMember(organization, user, adminUser);
+    db.users().insertMember(defaultGroup, user);
+    UserDto anotherUser = db.users().insertUser();
+    OrganizationDto anotherOrganization = db.organizations().insert();
+    ComponentDto anotherProject = db.components().insertPrivateProject(anotherOrganization);
+    userIndexer.indexOnStartup(new HashSet<>());
+
+    db.users().insertPermissionOnUser(organization, user, ADMINISTER);
+    db.users().insertPermissionOnUser(organization, user, SCAN);
+    db.users().insertPermissionOnUser(anotherOrganization, user, ADMINISTER);
+    db.users().insertPermissionOnUser(anotherOrganization, user, SCAN);
+    db.users().insertPermissionOnUser(organization, anotherUser, ADMINISTER);
+    db.users().insertPermissionOnUser(organization, anotherUser, SCAN);
+    db.users().insertProjectPermissionOnUser(user, CODEVIEWER, project);
+    db.users().insertProjectPermissionOnUser(user, USER, project);
+    db.users().insertProjectPermissionOnUser(user, CODEVIEWER, anotherProject);
+    db.users().insertProjectPermissionOnUser(user, USER, anotherProject);
+    db.users().insertProjectPermissionOnUser(anotherUser, CODEVIEWER, project);
+    db.users().insertProjectPermissionOnUser(anotherUser, USER, project);
+
+    underTest.removeMember(db.getSession(), organization, user);
+
+    assertUserIsNotMember(organization, user);
+    assertOrgPermissionsOfUser(user, organization);
+    assertOrgPermissionsOfUser(user, anotherOrganization, ADMINISTER, SCAN);
+    assertOrgPermissionsOfUser(anotherUser, organization, ADMINISTER, SCAN);
+    assertProjectPermissionsOfUser(user, project);
+    assertProjectPermissionsOfUser(user, anotherProject, CODEVIEWER, USER);
+    assertProjectPermissionsOfUser(anotherUser, project, CODEVIEWER, USER);
+  }
+
+  @Test
+  public void remove_member_removes_template_permissions() {
+    OrganizationDto organization = db.organizations().insert();
+    GroupDto defaultGroup = db.users().insertDefaultGroup(organization, "Members");
+    UserDto user = db.users().insertUser();
+    UserDto adminUser = db.users().insertAdminByUserPermission(organization);
+    db.organizations().addMember(organization, user, adminUser);
+    db.users().insertMember(defaultGroup, user);
+    userIndexer.indexOnStartup(new HashSet<>());
+
+    OrganizationDto anotherOrganization = db.organizations().insert();
+    UserDto anotherUser = db.users().insertUser();
+    PermissionTemplateDto template = db.permissionTemplates().insertTemplate(organization);
+    PermissionTemplateDto anotherTemplate = db.permissionTemplates().insertTemplate(anotherOrganization);
+    String permission = "browse";
+    db.permissionTemplates().addUserToTemplate(template.getId(), user.getId(), permission);
+    db.permissionTemplates().addUserToTemplate(template.getId(), anotherUser.getId(), permission);
+    db.permissionTemplates().addUserToTemplate(anotherTemplate.getId(), user.getId(), permission);
+
+    underTest.removeMember(db.getSession(), organization, user);
+
+    assertThat(dbClient.permissionTemplateDao().selectUserPermissionsByTemplateId(db.getSession(), template.getId())).extracting(PermissionTemplateUserDto::getUserId)
+      .containsOnly(anotherUser.getId());
+    assertThat(dbClient.permissionTemplateDao().selectUserPermissionsByTemplateId(db.getSession(), anotherTemplate.getId())).extracting(PermissionTemplateUserDto::getUserId)
+      .containsOnly(user.getId());
+  }
+
+  @Test
+  public void remove_member_removes_qprofiles_user_permission() {
+    OrganizationDto organization = db.organizations().insert();
+    GroupDto defaultGroup = db.users().insertDefaultGroup(organization, "Members");
+    UserDto user = db.users().insertUser();
+    UserDto adminUser = db.users().insertAdminByUserPermission(organization);
+    db.organizations().addMember(organization, user, adminUser);
+    db.users().insertMember(defaultGroup, user);
+    userIndexer.indexOnStartup(new HashSet<>());
+
+    OrganizationDto anotherOrganization = db.organizations().insert();
+    db.organizations().addMember(anotherOrganization, user);
+    QProfileDto profile = db.qualityProfiles().insert(organization);
+    QProfileDto anotherProfile = db.qualityProfiles().insert(anotherOrganization);
+    db.qualityProfiles().addUserPermission(profile, user);
+    db.qualityProfiles().addUserPermission(anotherProfile, user);
+
+    underTest.removeMember(db.getSession(), organization, user);
+
+    assertThat(db.getDbClient().qProfileEditUsersDao().exists(db.getSession(), profile, user)).isFalse();
+    assertThat(db.getDbClient().qProfileEditUsersDao().exists(db.getSession(), anotherProfile, user)).isTrue();
+  }
+
+  @Test
+  public void remove_member_removes_user_from_organization_groups() {
+    OrganizationDto organization = db.organizations().insert();
+    GroupDto defaultGroup = db.users().insertDefaultGroup(organization, "Members");
+    UserDto user = db.users().insertUser();
+    UserDto adminUser = db.users().insertAdminByUserPermission(organization);
+    db.organizations().addMember(organization, user, adminUser);
+    db.users().insertMember(defaultGroup, user);
+    userIndexer.indexOnStartup(new HashSet<>());
+
+    OrganizationDto anotherOrganization = db.organizations().insert();
+    UserDto anotherUser = db.users().insertUser();
+    GroupDto group = db.users().insertGroup(organization);
+    GroupDto anotherGroup = db.users().insertGroup(anotherOrganization);
+    db.users().insertMembers(group, user, anotherUser);
+    db.users().insertMembers(anotherGroup, user, anotherUser);
+
+    underTest.removeMember(db.getSession(), organization, user);
+
+    assertThat(dbClient.groupMembershipDao().selectGroupIdsByUserId(db.getSession(), user.getId()))
+      .containsOnly(anotherGroup.getId());
+    assertThat(dbClient.groupMembershipDao().selectGroupIdsByUserId(db.getSession(), anotherUser.getId()))
+      .containsOnly(group.getId(), anotherGroup.getId());
+  }
+
+  @Test
+  public void remove_member_removes_user_from_default_organization_group() {
+    OrganizationDto organization = db.organizations().insert();
+    GroupDto defaultGroup = db.users().insertDefaultGroup(organization, "Members");
+    UserDto user = db.users().insertUser();
+    UserDto adminUser = db.users().insertAdminByUserPermission(organization);
+    db.organizations().addMember(organization, user, adminUser);
+    db.users().insertMember(defaultGroup, user);
+    userIndexer.indexOnStartup(new HashSet<>());
+
+    underTest.removeMember(db.getSession(), organization, user);
+
+    assertThat(dbClient.groupMembershipDao().selectGroupIdsByUserId(db.getSession(), user.getId())).isEmpty();
+  }
+
+  @Test
+  public void remove_member_removes_user_from_org_properties() {
+    OrganizationDto organization = db.organizations().insert();
+    ComponentDto project = db.components().insertPrivateProject(organization);
+    GroupDto defaultGroup = db.users().insertDefaultGroup(organization, "Members");
+    UserDto user = db.users().insertUser();
+    UserDto adminUser = db.users().insertAdminByUserPermission(organization);
+    db.organizations().addMember(organization, user, adminUser);
+    db.users().insertMember(defaultGroup, user);
+    userIndexer.indexOnStartup(new HashSet<>());
+
+    OrganizationDto anotherOrganization = db.organizations().insert();
+    ComponentDto anotherProject = db.components().insertPrivateProject(anotherOrganization);
+    UserDto anotherUser = db.users().insertUser();
+    insertProperty("KEY_11", "VALUE", project.getId(), user.getId());
+    insertProperty("KEY_12", "VALUE", project.getId(), user.getId());
+    insertProperty("KEY_11", "VALUE", project.getId(), anotherUser.getId());
+    insertProperty("KEY_11", "VALUE", anotherProject.getId(), user.getId());
+
+    underTest.removeMember(db.getSession(), organization, user);
+
+    assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder().setComponentId(project.getId()).build(), db.getSession()))
+      .hasSize(1).extracting(PropertyDto::getUserId).containsOnly(anotherUser.getId());
+    assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder().setComponentId(anotherProject.getId()).build(), db.getSession())).extracting(PropertyDto::getUserId)
+      .hasSize(1).containsOnly(user.getId());
+  }
+
+  @Test
+  public void remove_member_removes_user_from_default_assignee_properties() {
+    OrganizationDto organization = db.organizations().insert();
+    ComponentDto project = db.components().insertPrivateProject(organization);
+    GroupDto defaultGroup = db.users().insertDefaultGroup(organization, "Members");
+    UserDto user = db.users().insertUser();
+    UserDto adminUser = db.users().insertAdminByUserPermission(organization);
+    db.organizations().addMember(organization, user, adminUser);
+    db.users().insertMember(defaultGroup, user);
+    userIndexer.indexOnStartup(new HashSet<>());
+
+    OrganizationDto anotherOrganization = db.organizations().insert();
+    ComponentDto anotherProject = db.components().insertPrivateProject(anotherOrganization);
+    UserDto anotherUser = db.users().insertUser();
+    insertProperty(DEFAULT_ISSUE_ASSIGNEE, user.getLogin(), project.getId(), null);
+    insertProperty("ANOTHER_KEY", user.getLogin(), project.getId(), null);
+    insertProperty(DEFAULT_ISSUE_ASSIGNEE, anotherUser.getLogin(), project.getId(), null);
+    insertProperty(DEFAULT_ISSUE_ASSIGNEE, user.getLogin(), anotherProject.getId(), null);
+
+    underTest.removeMember(db.getSession(), organization, user);
+
+    assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder().setComponentId(project.getId()).build(), db.getSession()))
+      .hasSize(2).extracting(PropertyDto::getKey, PropertyDto::getValue)
+      .containsOnly(Tuple.tuple("ANOTHER_KEY", user.getLogin()), Tuple.tuple(DEFAULT_ISSUE_ASSIGNEE, anotherUser.getLogin()));
+    assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder().setComponentId(anotherProject.getId()).build(), db.getSession())).extracting(PropertyDto::getValue)
+      .hasSize(1).containsOnly(user.getLogin());
+  }
+
+  @Test
+  public void fail_to_remove_members_when_no_more_admin() {
+    OrganizationDto organization = db.organizations().insert();
+    GroupDto defaultGroup = db.users().insertDefaultGroup(organization, "Members");
+    GroupDto adminGroup = db.users().insertGroup(organization);
+    db.users().insertPermissionOnGroup(adminGroup, ADMINISTER);
+    UserDto user1 = db.users().insertUser();
+    UserDto admin1 = db.users().insertAdminByUserPermission(organization);
+    UserDto admin2 = db.users().insertUser();
+    db.organizations().addMember(organization, user1, admin1, admin2);
+    db.users().insertMember(defaultGroup, user1);
+    db.users().insertMember(defaultGroup, admin1);
+    db.users().insertMember(defaultGroup, admin2);
+    db.users().insertMember(adminGroup, admin2);
+    userIndexer.indexOnStartup(new HashSet<>());
+
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("The last administrator member cannot be removed");
+
+    underTest.removeMembers(db.getSession(), organization, asList(admin1, admin2));
+  }
+
+  private void assertUserIsMember(OrganizationDto organization, UserDto user) {
+    assertThat(dbClient.organizationMemberDao().select(db.getSession(), organization.getUuid(), user.getId())).isPresent();
+    Integer defaultGroupId = dbClient.organizationDao().getDefaultGroupId(db.getSession(), organization.getUuid()).get();
+    assertThat(db.getDbClient().groupMembershipDao().selectGroups(
+      db.getSession(),
+      GroupMembershipQuery.builder().membership(IN).organizationUuid(organization.getUuid()).build(),
+      user.getId(), 0, 10))
+        .extracting(GroupMembershipDto::getId)
+        .containsOnly(defaultGroupId.longValue());
+  }
+
+  private void assertUserIsNotMember(OrganizationDto organization, UserDto user) {
+    assertThat(dbClient.organizationMemberDao().select(db.getSession(), organization.getUuid(), user.getId())).isNotPresent();
+    SearchRequestBuilder request = es.client().prepareSearch(UserIndexDefinition.INDEX_TYPE_USER)
+      .setQuery(boolQuery()
+        .must(termQuery(FIELD_ORGANIZATION_UUIDS, organization.getUuid()))
+        .must(termQuery(FIELD_UUID, user.getUuid())));
+    assertThat(request.get().getHits().getHits()).isEmpty();
+  }
+
+  private void assertOrgPermissionsOfUser(UserDto user, OrganizationDto organization, OrganizationPermission... permissions) {
+    assertThat(dbClient.userPermissionDao().selectGlobalPermissionsOfUser(db.getSession(), user.getId(), organization.getUuid()).stream()
+      .map(OrganizationPermission::fromKey))
+        .containsOnly(permissions);
+  }
+
+  private void assertProjectPermissionsOfUser(UserDto user, ComponentDto project, String... permissions) {
+    assertThat(dbClient.userPermissionDao().selectProjectPermissionsOfUser(db.getSession(), user.getId(), project.getId())).containsOnly(permissions);
+  }
+
+  private void insertProperty(String key, @Nullable String value, @Nullable Long resourceId, @Nullable Integer userId) {
+    PropertyDto dto = new PropertyDto().setKey(key)
+      .setResourceId(resourceId)
+      .setUserId(userId)
+      .setValue(value);
+    db.properties().insertProperty(dto);
+  }
+
+}
index 659c02040c0939e47f3727e296fc908a2b2139bb..481ded94aa35f2770f3596923d09c35679ce281e 100644 (file)
  */
 package org.sonar.server.organization.ws;
 
-import java.util.List;
 import java.util.stream.IntStream;
 import javax.annotation.Nullable;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.server.ws.WebService;
-import org.sonar.api.utils.System2;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
@@ -36,16 +34,13 @@ import org.sonar.db.user.GroupMembershipDto;
 import org.sonar.db.user.GroupMembershipQuery;
 import org.sonar.db.user.UserDto;
 import org.sonar.server.es.EsTester;
-import org.sonar.server.es.SearchOptions;
 import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.issue.ws.AvatarResolverImpl;
+import org.sonar.server.organization.MemberUpdater;
 import org.sonar.server.organization.OrganizationValidationImpl;
 import org.sonar.server.tester.UserSessionRule;
-import org.sonar.server.user.index.UserDoc;
-import org.sonar.server.user.index.UserIndex;
 import org.sonar.server.user.index.UserIndexer;
-import org.sonar.server.user.index.UserQuery;
 import org.sonar.server.usergroups.DefaultGroupFinder;
 import org.sonar.server.ws.TestRequest;
 import org.sonar.server.ws.WsActionTester;
@@ -67,17 +62,18 @@ public class AddMemberActionTest {
   public UserSessionRule userSession = UserSessionRule.standalone().logIn().setRoot();
   @Rule
   public EsTester es = EsTester.create();
-  private UserIndex userIndex = new UserIndex(es.client(), System2.INSTANCE);
   @Rule
   public DbTester db = DbTester.create();
+
   private DbClient dbClient = db.getDbClient();
   private DbSession dbSession = db.getSession();
   private OrganizationsWsSupport wsSupport = new OrganizationsWsSupport(new OrganizationValidationImpl(), dbClient);
   private WsActionTester ws = new WsActionTester(
-    new AddMemberAction(dbClient, userSession, new UserIndexer(dbClient, es.client()), new DefaultGroupFinder(dbClient), new AvatarResolverImpl(), wsSupport));
+    new AddMemberAction(dbClient, userSession, new AvatarResolverImpl(), wsSupport,
+      new MemberUpdater(dbClient, new DefaultGroupFinder(dbClient), new UserIndexer(dbClient, es.client()))));
 
   @Test
-  public void add_member_in_db_and_user_index() {
+  public void add_member() {
     OrganizationDto organization = db.organizations().insert();
     db.users().insertDefaultGroup(organization, "default");
     UserDto user = db.users().insertUser();
@@ -85,9 +81,6 @@ public class AddMemberActionTest {
     call(organization.getKey(), user.getLogin());
 
     assertMember(organization.getUuid(), user.getId());
-    List<UserDoc> userDocs = userIndex.search(UserQuery.builder().build(), new SearchOptions()).getDocs();
-    assertThat(userDocs).hasSize(1);
-    assertThat(userDocs.get(0).organizationUuids()).containsOnly(organization.getUuid());
   }
 
   @Test
index 89448f24806016efebfa594d040d4e308438d412..8f8b36f71d4d0f127b94de5d979ef5721c7d143b 100644 (file)
@@ -49,7 +49,7 @@ public class OrganizationsWsModuleTest {
     underTest.configure(container);
 
     assertThat(container.getPicoContainer().getComponentAdapters())
-      .hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 12);
+      .hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 13);
   }
 
 }
index b5e01453546c821a4cf01f403125c1c095885702..b474218e75f336f2ff68058fef126e0bcf1259e6 100644 (file)
@@ -21,8 +21,6 @@ package org.sonar.server.organization.ws;
 
 import java.util.HashSet;
 import javax.annotation.Nullable;
-import org.elasticsearch.action.search.SearchRequestBuilder;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
@@ -31,27 +29,19 @@ import org.sonar.api.utils.System2;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
-import org.sonar.db.component.ComponentDto;
 import org.sonar.db.organization.OrganizationDto;
-import org.sonar.db.permission.OrganizationPermission;
-import org.sonar.db.permission.template.PermissionTemplateDto;
-import org.sonar.db.permission.template.PermissionTemplateUserDto;
-import org.sonar.db.property.PropertyDto;
-import org.sonar.db.property.PropertyQuery;
-import org.sonar.db.qualityprofile.QProfileDto;
-import org.sonar.db.user.GroupDto;
 import org.sonar.db.user.UserDto;
 import org.sonar.server.es.EsTester;
 import org.sonar.server.es.SearchOptions;
-import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.organization.MemberUpdater;
 import org.sonar.server.organization.OrganizationValidationImpl;
 import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.user.index.UserIndex;
-import org.sonar.server.user.index.UserIndexDefinition;
 import org.sonar.server.user.index.UserIndexer;
 import org.sonar.server.user.index.UserQuery;
+import org.sonar.server.usergroups.DefaultGroupFinder;
 import org.sonar.server.ws.TestRequest;
 import org.sonar.server.ws.TestResponse;
 import org.sonar.server.ws.WsActionTester;
@@ -60,24 +50,15 @@ import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
 import static java.util.Arrays.asList;
 import static java.util.Optional.ofNullable;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.groups.Tuple.tuple;
-import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
-import static org.elasticsearch.index.query.QueryBuilders.termQuery;
-import static org.sonar.api.CoreProperties.DEFAULT_ISSUE_ASSIGNEE;
-import static org.sonar.api.web.UserRole.CODEVIEWER;
-import static org.sonar.api.web.UserRole.USER;
 import static org.sonar.db.permission.OrganizationPermission.ADMINISTER;
 import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_GATES;
-import static org.sonar.db.permission.OrganizationPermission.SCAN;
 import static org.sonar.server.organization.ws.OrganizationsWsSupport.PARAM_ORGANIZATION;
-import static org.sonar.server.user.index.UserIndexDefinition.FIELD_ORGANIZATION_UUIDS;
-import static org.sonar.server.user.index.UserIndexDefinition.FIELD_UUID;
 
 public class RemoveMemberActionTest {
   @Rule
   public ExpectedException expectedException = ExpectedException.none();
   @Rule
-  public UserSessionRule userSession = UserSessionRule.standalone().logIn().setRoot();
+  public UserSessionRule userSession = UserSessionRule.standalone();
   @Rule
   public EsTester es = EsTester.create();
   @Rule
@@ -89,54 +70,19 @@ public class RemoveMemberActionTest {
   private UserIndexer userIndexer = new UserIndexer(dbClient, es.client());
   private OrganizationsWsSupport wsSupport = new OrganizationsWsSupport(new OrganizationValidationImpl(), dbClient);
 
-  private WsActionTester ws = new WsActionTester(new RemoveMemberAction(dbClient, userSession, userIndexer, wsSupport));
+  private WsActionTester ws = new WsActionTester(new RemoveMemberAction(dbClient, userSession, wsSupport,
+    new MemberUpdater(dbClient, new DefaultGroupFinder(dbClient), new UserIndexer(dbClient, es.client()))));
 
-  private OrganizationDto organization;
-  private ComponentDto project;
-  private UserDto user;
-
-  @Before
-  public void setUp() {
-    organization = db.organizations().insert();
-    project = db.components().insertPrivateProject(organization);
-
-    user = db.users().insertUser();
+  @Test
+  public void remove_member() {
+    OrganizationDto organization = db.organizations().insert();
+    UserDto user = db.users().insertUser();
     db.organizations().addMember(organization, user);
-
     UserDto adminUser = db.users().insertAdminByUserPermission(organization);
     db.organizations().addMember(organization, adminUser);
-
     userIndexer.indexOnStartup(new HashSet<>());
-  }
-
-  @Test
-  public void definition() {
-    WebService.Action definition = ws.getDef();
-
-    assertThat(definition.key()).isEqualTo("remove_member");
-    assertThat(definition.since()).isEqualTo("6.4");
-    assertThat(definition.isPost()).isTrue();
-    assertThat(definition.isInternal()).isTrue();
-    assertThat(definition.params()).extracting(WebService.Param::key).containsOnly("organization", "login");
-
-    WebService.Param organization = definition.param("organization");
-    assertThat(organization.isRequired()).isTrue();
-
-    WebService.Param login = definition.param("login");
-    assertThat(login.isRequired()).isTrue();
-  }
-
-  @Test
-  public void no_content_http_204_returned() {
-    TestResponse result = call(organization.getKey(), user.getLogin());
-
-    assertThat(result.getStatus()).isEqualTo(HTTP_NO_CONTENT);
-    assertThat(result.getInput()).isEmpty();
-  }
-
-  @Test
-  public void remove_member_from_db_and_user_index() {
     assertMember(organization.getUuid(), user);
+    userSession.logIn().addPermission(ADMINISTER, organization);
 
     call(organization.getKey(), user.getLogin());
 
@@ -144,154 +90,50 @@ public class RemoveMemberActionTest {
   }
 
   @Test
-  public void remove_organization_permissions() {
-    UserDto anotherUser = db.users().insertUser();
-    OrganizationDto anotherOrganization = db.organizations().insert();
-    ComponentDto anotherProject = db.components().insertPrivateProject(anotherOrganization);
+  public void no_content_http_204_returned() {
+    OrganizationDto organization = db.organizations().insert();
+    UserDto user = db.users().insertUser();
+    db.organizations().addMember(organization, user);
+    UserDto adminUser = db.users().insertAdminByUserPermission(organization);
+    db.organizations().addMember(organization, adminUser);
+    userIndexer.indexOnStartup(new HashSet<>());
     assertMember(organization.getUuid(), user);
-    db.users().insertPermissionOnUser(organization, user, ADMINISTER);
-    db.users().insertPermissionOnUser(organization, user, SCAN);
-    db.users().insertPermissionOnUser(anotherOrganization, user, ADMINISTER);
-    db.users().insertPermissionOnUser(anotherOrganization, user, SCAN);
-    db.users().insertPermissionOnUser(organization, anotherUser, ADMINISTER);
-    db.users().insertPermissionOnUser(organization, anotherUser, SCAN);
-    db.users().insertProjectPermissionOnUser(user, CODEVIEWER, project);
-    db.users().insertProjectPermissionOnUser(user, USER, project);
-    db.users().insertProjectPermissionOnUser(user, CODEVIEWER, anotherProject);
-    db.users().insertProjectPermissionOnUser(user, USER, anotherProject);
-    db.users().insertProjectPermissionOnUser(anotherUser, CODEVIEWER, project);
-    db.users().insertProjectPermissionOnUser(anotherUser, USER, project);
-
-    call(organization.getKey(), user.getLogin());
-
-    assertNotAMember(organization.getUuid(), user);
-    assertOrgPermissionsOfUser(user, organization);
-    assertOrgPermissionsOfUser(user, anotherOrganization, ADMINISTER, SCAN);
-    assertOrgPermissionsOfUser(anotherUser, organization, ADMINISTER, SCAN);
-    assertProjectPermissionsOfUser(user, project);
-    assertProjectPermissionsOfUser(user, anotherProject, CODEVIEWER, USER);
-    assertProjectPermissionsOfUser(anotherUser, project, CODEVIEWER, USER);
-  }
-
-  @Test
-  public void remove_template_permissions() {
-    OrganizationDto anotherOrganization = db.organizations().insert();
-    UserDto anotherUser = db.users().insertUser();
-    PermissionTemplateDto template = db.permissionTemplates().insertTemplate(organization);
-    PermissionTemplateDto anotherTemplate = db.permissionTemplates().insertTemplate(anotherOrganization);
-    String permission = "PERMISSION";
-    db.permissionTemplates().addUserToTemplate(template.getId(), user.getId(), permission);
-    db.permissionTemplates().addUserToTemplate(template.getId(), anotherUser.getId(), permission);
-    db.permissionTemplates().addUserToTemplate(anotherTemplate.getId(), user.getId(), permission);
-
-    call(organization.getKey(), user.getLogin());
-
-    assertThat(dbClient.permissionTemplateDao().selectUserPermissionsByTemplateId(dbSession, template.getId())).extracting(PermissionTemplateUserDto::getUserId)
-      .containsOnly(anotherUser.getId());
-    assertThat(dbClient.permissionTemplateDao().selectUserPermissionsByTemplateId(dbSession, anotherTemplate.getId())).extracting(PermissionTemplateUserDto::getUserId)
-      .containsOnly(user.getId());
-  }
-
-  @Test
-  public void remove_qprofiles_user_permission() {
-    OrganizationDto anotherOrganization = db.organizations().insert();
-    db.organizations().addMember(anotherOrganization, user);
-    QProfileDto profile = db.qualityProfiles().insert(organization);
-    QProfileDto anotherProfile = db.qualityProfiles().insert(anotherOrganization);
-    db.qualityProfiles().addUserPermission(profile, user);
-    db.qualityProfiles().addUserPermission(anotherProfile, user);
-
-    call(organization.getKey(), user.getLogin());
-
-    assertThat(db.getDbClient().qProfileEditUsersDao().exists(dbSession, profile, user)).isFalse();
-    assertThat(db.getDbClient().qProfileEditUsersDao().exists(dbSession, anotherProfile, user)).isTrue();
-  }
-
-  @Test
-  public void remove_from_organization_groups() {
-    OrganizationDto anotherOrganization = db.organizations().insert();
-    UserDto anotherUser = db.users().insertUser();
-    GroupDto group = db.users().insertGroup(organization);
-    GroupDto anotherGroup = db.users().insertGroup(anotherOrganization);
-    db.users().insertMembers(group, user, anotherUser);
-    db.users().insertMembers(anotherGroup, user, anotherUser);
-
-    call(organization.getKey(), user.getLogin());
-
-    assertThat(dbClient.groupMembershipDao().selectGroupIdsByUserId(dbSession, user.getId()))
-      .containsOnly(anotherGroup.getId());
-    assertThat(dbClient.groupMembershipDao().selectGroupIdsByUserId(dbSession, anotherUser.getId()))
-      .containsOnly(group.getId(), anotherGroup.getId());
-  }
-
-  @Test
-  public void remove_from_default_organization_group() {
-    GroupDto defaultGroup = db.users().insertDefaultGroup(organization, "default");
-    db.users().insertMember(defaultGroup, user);
-
-    call(organization.getKey(), user.getLogin());
-
-    assertThat(dbClient.groupMembershipDao().selectGroupIdsByUserId(dbSession, user.getId())).isEmpty();
-  }
-
-  @Test
-  public void remove_from_org_properties() {
-    OrganizationDto anotherOrganization = db.organizations().insert();
-    ComponentDto anotherProject = db.components().insertPrivateProject(anotherOrganization);
-    UserDto anotherUser = db.users().insertUser();
-    insertProperty("KEY_11", "VALUE", project.getId(), user.getId());
-    insertProperty("KEY_12", "VALUE", project.getId(), user.getId());
-    insertProperty("KEY_11", "VALUE", project.getId(), anotherUser.getId());
-    insertProperty("KEY_11", "VALUE", anotherProject.getId(), user.getId());
-
-    call(organization.getKey(), user.getLogin());
-
-    assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder().setComponentId(project.getId()).build(), dbSession))
-      .hasSize(1).extracting(PropertyDto::getUserId).containsOnly(anotherUser.getId());
-    assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder().setComponentId(anotherProject.getId()).build(), dbSession)).extracting(PropertyDto::getUserId)
-      .hasSize(1).containsOnly(user.getId());
-  }
-
-  @Test
-  public void remove_from_default_assignee_properties() {
-    OrganizationDto anotherOrganization = db.organizations().insert();
-    ComponentDto anotherProject = db.components().insertPrivateProject(anotherOrganization);
-    UserDto anotherUser = db.users().insertUser();
-    insertProperty(DEFAULT_ISSUE_ASSIGNEE, user.getLogin(), project.getId(), null);
-    insertProperty("ANOTHER_KEY", user.getLogin(), project.getId(), null);
-    insertProperty(DEFAULT_ISSUE_ASSIGNEE, anotherUser.getLogin(), project.getId(), null);
-    insertProperty(DEFAULT_ISSUE_ASSIGNEE, user.getLogin(), anotherProject.getId(), null);
+    userSession.logIn().addPermission(ADMINISTER, organization);
 
-    call(organization.getKey(), user.getLogin());
+    TestResponse result = call(organization.getKey(), user.getLogin());
 
-    assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder().setComponentId(project.getId()).build(), dbSession))
-      .hasSize(2).extracting(PropertyDto::getKey, PropertyDto::getValue)
-      .containsOnly(tuple("ANOTHER_KEY", user.getLogin()), tuple(DEFAULT_ISSUE_ASSIGNEE, anotherUser.getLogin()));
-    assertThat(dbClient.propertiesDao().selectByQuery(PropertyQuery.builder().setComponentId(anotherProject.getId()).build(), dbSession)).extracting(PropertyDto::getValue)
-      .hasSize(1).containsOnly(user.getLogin());
+    assertThat(result.getStatus()).isEqualTo(HTTP_NO_CONTENT);
+    assertThat(result.getInput()).isEmpty();
   }
 
   @Test
   public void user_is_removed_only_from_designated_organization() {
+    OrganizationDto organization = db.organizations().insert();
+    UserDto user = db.users().insertUser();
+    db.organizations().addMember(organization, user);
+    UserDto adminUser = db.users().insertAdminByUserPermission(organization);
+    db.organizations().addMember(organization, adminUser);
+    userIndexer.indexOnStartup(new HashSet<>());
+    assertMember(organization.getUuid(), user);
     OrganizationDto anotherOrg = db.organizations().insert();
     db.organizations().addMember(anotherOrg, user);
-
-    call(organization.getKey(), user.getLogin());
-
-    assertMember(anotherOrg.getUuid(), user);
-  }
-
-  @Test
-  public void remove_member_as_organization_admin() {
     userSession.logIn().addPermission(ADMINISTER, organization);
 
     call(organization.getKey(), user.getLogin());
 
-    assertNotAMember(organization.getUuid(), user);
+    assertMember(anotherOrg.getUuid(), user);
   }
 
   @Test
   public void do_not_fail_if_user_already_removed_from_organization() {
+    OrganizationDto organization = db.organizations().insert();
+    UserDto user = db.users().insertUser();
+    db.organizations().addMember(organization, user);
+    UserDto adminUser = db.users().insertAdminByUserPermission(organization);
+    db.organizations().addMember(organization, adminUser);
+    userIndexer.indexOnStartup(new HashSet<>());
+    assertMember(organization.getUuid(), user);
+    userSession.logIn().addPermission(ADMINISTER, organization);
     call(organization.getKey(), user.getLogin());
 
     call(organization.getKey(), user.getLogin());
@@ -299,6 +141,9 @@ public class RemoveMemberActionTest {
 
   @Test
   public void fail_if_login_does_not_exist() {
+    OrganizationDto organization = db.organizations().insert();
+    userSession.logIn().addPermission(ADMINISTER, organization);
+
     expectedException.expect(NotFoundException.class);
     expectedException.expectMessage("User 'login-42' is not found");
 
@@ -307,6 +152,8 @@ public class RemoveMemberActionTest {
 
   @Test
   public void fail_if_organization_does_not_exist() {
+    UserDto user = db.users().insertUser();
+
     expectedException.expect(NotFoundException.class);
     expectedException.expectMessage("Organization 'org-42' is not found");
 
@@ -315,6 +162,9 @@ public class RemoveMemberActionTest {
 
   @Test
   public void fail_if_no_login_provided() {
+    OrganizationDto organization = db.organizations().insert();
+    userSession.logIn().addPermission(ADMINISTER, organization);
+
     expectedException.expect(IllegalArgumentException.class);
 
     call(organization.getKey(), null);
@@ -322,6 +172,8 @@ public class RemoveMemberActionTest {
 
   @Test
   public void fail_if_no_organization_provided() {
+    UserDto user = db.users().insertUser();
+
     expectedException.expect(IllegalArgumentException.class);
 
     call(null, user.getLogin());
@@ -329,6 +181,12 @@ public class RemoveMemberActionTest {
 
   @Test
   public void fail_if_insufficient_permissions() {
+    OrganizationDto organization = db.organizations().insert();
+    UserDto user = db.users().insertUser();
+    db.organizations().addMember(organization, user);
+    UserDto adminUser = db.users().insertAdminByUserPermission(organization);
+    db.organizations().addMember(organization, adminUser);
+    userIndexer.indexOnStartup(new HashSet<>());
     userSession.logIn().addPermission(ADMINISTER_QUALITY_GATES, organization);
 
     expectedException.expect(ForbiddenException.class);
@@ -341,6 +199,7 @@ public class RemoveMemberActionTest {
     OrganizationDto organization = db.organizations().insert();
     db.alm().insertOrganizationAlmBinding(organization, db.alm().insertAlmAppInstall());
     UserDto user = db.users().insertUser();
+    userSession.logIn().addPermission(ADMINISTER, organization);
 
     expectedException.expect(IllegalArgumentException.class);
 
@@ -355,6 +214,7 @@ public class RemoveMemberActionTest {
     UserDto admin2 = db.users().insertAdminByUserPermission(anotherOrganization);
     db.organizations().addMember(anotherOrganization, admin2);
     userIndexer.commitAndIndex(db.getSession(), asList(admin1, admin2));
+    userSession.logIn().addPermission(ADMINISTER, anotherOrganization);
 
     call(anotherOrganization.getKey(), admin1.getLogin());
 
@@ -369,13 +229,31 @@ public class RemoveMemberActionTest {
     db.organizations().addMember(anotherOrganization, admin);
     UserDto user = db.users().insertUser();
     db.organizations().addMember(anotherOrganization, user);
+    userSession.logIn().addPermission(ADMINISTER, anotherOrganization);
 
-    expectedException.expect(BadRequestException.class);
+    expectedException.expect(IllegalArgumentException.class);
     expectedException.expectMessage("The last administrator member cannot be removed");
 
     call(anotherOrganization.getKey(), admin.getLogin());
   }
 
+  @Test
+  public void definition() {
+    WebService.Action definition = ws.getDef();
+
+    assertThat(definition.key()).isEqualTo("remove_member");
+    assertThat(definition.since()).isEqualTo("6.4");
+    assertThat(definition.isPost()).isTrue();
+    assertThat(definition.isInternal()).isTrue();
+    assertThat(definition.params()).extracting(WebService.Param::key).containsOnly("organization", "login");
+
+    WebService.Param organization = definition.param("organization");
+    assertThat(organization.isRequired()).isTrue();
+
+    WebService.Param login = definition.param("login");
+    assertThat(login.isRequired()).isTrue();
+  }
+
   private TestResponse call(@Nullable String organizationKey, @Nullable String login) {
     TestRequest request = ws.newRequest();
     ofNullable(organizationKey).ifPresent(o -> request.setParam(PARAM_ORGANIZATION, o));
@@ -386,7 +264,6 @@ public class RemoveMemberActionTest {
 
   private void assertNotAMember(String organizationUuid, UserDto user) {
     assertThat(dbClient.organizationMemberDao().select(dbSession, organizationUuid, user.getId())).isNotPresent();
-    assertMemberInIndex(organizationUuid, user, false);
   }
 
   private void assertMember(String organizationUuid, UserDto user) {
@@ -397,36 +274,6 @@ public class RemoveMemberActionTest {
       .build(),
       new SearchOptions()).getDocs())
         .hasSize(1);
-    assertMemberInIndex(organizationUuid, user, true);
   }
 
-  private void assertMemberInIndex(String organizationUuid, UserDto user, boolean isMember) {
-    SearchRequestBuilder request = es.client().prepareSearch(UserIndexDefinition.INDEX_TYPE_USER)
-      .setQuery(boolQuery()
-        .must(termQuery(FIELD_ORGANIZATION_UUIDS, organizationUuid))
-        .must(termQuery(FIELD_UUID, user.getUuid())));
-    if (isMember) {
-      assertThat(request.get().getHits().getHits()).hasSize(1);
-    } else {
-      assertThat(request.get().getHits().getHits()).isEmpty();
-    }
-  }
-
-  private void assertOrgPermissionsOfUser(UserDto user, OrganizationDto organization, OrganizationPermission... permissions) {
-    assertThat(dbClient.userPermissionDao().selectGlobalPermissionsOfUser(dbSession, user.getId(), organization.getUuid()).stream()
-      .map(OrganizationPermission::fromKey))
-        .containsOnly(permissions);
-  }
-
-  private void assertProjectPermissionsOfUser(UserDto user, ComponentDto project, String... permissions) {
-    assertThat(dbClient.userPermissionDao().selectProjectPermissionsOfUser(dbSession, user.getId(), project.getId())).containsOnly(permissions);
-  }
-
-  private void insertProperty(String key, @Nullable String value, @Nullable Long resourceId, @Nullable Integer userId) {
-    PropertyDto dto = new PropertyDto().setKey(key)
-      .setResourceId(resourceId)
-      .setUserId(userId)
-      .setValue(value);
-    db.properties().insertProperty(dto);
-  }
 }