]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-20392 Add API v2 endpoint to update GitHub permission mapping.
authorWojtek Wajerowicz <115081248+wojciech-wajerowicz-sonarsource@users.noreply.github.com>
Wed, 13 Sep 2023 13:30:09 +0000 (15:30 +0200)
committersonartech <sonartech@sonarsource.com>
Fri, 15 Sep 2023 20:03:05 +0000 (20:03 +0000)
31 files changed:
server/sonar-db-dao/src/it/java/org/sonar/db/provisioning/GithubPermissionsMappingDaoIT.java
server/sonar-db-dao/src/main/java/org/sonar/db/provisioning/GithubPermissionsMappingDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/provisioning/GithubPermissionsMappingMapper.java
server/sonar-db-dao/src/main/resources/org/sonar/db/provisioning/GithubPermissionsMappingMapper.xml
server/sonar-webserver-common/src/it/java/org/sonar/server/common/github/permissions/GithubPermissionsMappingServiceIT.java
server/sonar-webserver-common/src/main/java/org/sonar/server/common/github/permissions/GithubPermissionsMappingService.java
server/sonar-webserver-common/src/main/java/org/sonar/server/common/github/permissions/PermissionMappingChange.java [new file with mode: 0644]
server/sonar-webserver-common/src/main/java/org/sonar/server/common/github/permissions/SonarqubePermissions.java
server/sonar-webserver-common/src/main/java/org/sonar/server/common/permission/Operation.java [new file with mode: 0644]
server/sonar-webserver-common/src/main/java/org/sonar/server/common/permission/package-info.java [new file with mode: 0644]
server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/controller/DefaultGithubPermissionsController.java
server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/controller/GithubPermissionsController.java
server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/request/GithubPermissionMappingUpdateRequest.java [new file with mode: 0644]
server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/request/PermissionMappingUpdate.java [new file with mode: 0644]
server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/request/package-info.java [new file with mode: 0644]
server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/user/request/UserUpdateRestRequest.java
server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/common/model/UpdateField.java
server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/config/PlatformLevel4WebConfig.java
server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/github/permissions/controller/DefaultGithubPermissionsControllerTest.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/GroupPermissionChangerIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/UserPermissionChangerIT.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ComponentUpdater.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/GroupPermissionChange.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/GroupPermissionChanger.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/PermissionChange.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/UserPermissionChange.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/UserPermissionChanger.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/ws/AddGroupAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/ws/AddUserAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/ws/RemoveGroupAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/ws/RemoveUserAction.java

index 33839955dd7d64c56c1b7e8cf356dd430ca3562e..4751e5d6cedaec25958ed0e9ecb8fc52db276162 100644 (file)
@@ -66,6 +66,21 @@ public class GithubPermissionsMappingDaoIT {
     assertThat(newValueCaptor.getValue().getSonarqubePermission()).isEqualTo(githubPermissionsMappingDto.sonarqubePermission());
   }
 
+  @Test
+  public void delete_deletesGithubPermissionsMappingDto() {
+    GithubPermissionsMappingDto githubPermissionsMappingDto = new GithubPermissionsMappingDto(MAPPING_UUID, "GH_role", "SQ_role");
+
+    underTest.insert(dbSession, githubPermissionsMappingDto);
+    underTest.delete(dbSession, "GH_role", "SQ_role");
+
+    Set<GithubPermissionsMappingDto> savedGithubPermissionsMappings = underTest.findAll(dbSession);
+    assertThat(savedGithubPermissionsMappings).isEmpty();
+
+    verify(auditPersister).deleteGithubPermissionsMapping(eq(dbSession), newValueCaptor.capture());
+    assertThat(newValueCaptor.getValue().getGithubRole()).isEqualTo("GH_role");
+    assertThat(newValueCaptor.getValue().getSonarqubePermission()).isEqualTo("SQ_role");
+  }
+
   @Test
   public void findAll_shouldReturnAllGithubOrganizationGroup() {
     GithubPermissionsMappingDto mapping1 = new GithubPermissionsMappingDto(MAPPING_UUID, "GH_role", "SQ_role");
@@ -79,8 +94,22 @@ public class GithubPermissionsMappingDaoIT {
     assertThat(all).hasSize(2)
       .containsExactlyInAnyOrder(
         mapping1,
-        mapping2
-      );
+        mapping2);
+  }
+
+  @Test
+  public void findAllForGithubRole_shouldReturnPermissionsForTheRole() {
+    GithubPermissionsMappingDto mapping1 = new GithubPermissionsMappingDto(MAPPING_UUID, "GH_role", "SQ_role");
+    GithubPermissionsMappingDto mapping2 = new GithubPermissionsMappingDto(MAPPING_UUID + "2", "GH_role2", "SQ_role");
+    GithubPermissionsMappingDto mapping3 = new GithubPermissionsMappingDto(MAPPING_UUID + "3", "GH_role2", "SQ_role2");
+    underTest.insert(dbSession, mapping1);
+    underTest.insert(dbSession, mapping2);
+    underTest.insert(dbSession, mapping3);
+
+    Set<GithubPermissionsMappingDto> forRole2 = underTest.findAllForGithubRole(dbSession, "GH_role2");
+    assertThat(forRole2).hasSize(2)
+      .containsExactlyInAnyOrder(mapping2, mapping3);
+
   }
 
 }
index b97b3ea421dc8758f4fb817c1eef62b6a5b3bceb..18c4784d940997f8a2d5f3844d18986d2015fdc1 100644 (file)
@@ -37,19 +37,22 @@ public class GithubPermissionsMappingDao implements Dao {
     return mapper(dbSession).selectAll();
   }
 
+  public Set<GithubPermissionsMappingDto> findAllForGithubRole(DbSession dbSession, String githubRole) {
+    return mapper(dbSession).selectAllForGithubRole(githubRole);
+  }
+
   public void insert(DbSession dbSession, GithubPermissionsMappingDto githubPermissionsMappingDto) {
     mapper(dbSession).insert(githubPermissionsMappingDto);
-    auditPersister.addGithubPermissionsMapping(dbSession, toNewValueForAuditLogs(githubPermissionsMappingDto));
+    auditPersister.addGithubPermissionsMapping(dbSession, toNewValueForAuditLogs(githubPermissionsMappingDto.githubRole(), githubPermissionsMappingDto.sonarqubePermission()));
   }
 
-  public void delete(DbSession dbSession, GithubPermissionsMappingDto githubPermissionsMappingDto) {
-    // TODO SONAR-20397
-    auditPersister.deleteGithubPermissionsMapping(dbSession, toNewValueForAuditLogs(githubPermissionsMappingDto));
+  public void delete(DbSession dbSession, String githubRole, String sonarqubePermission) {
+    mapper(dbSession).delete(githubRole, sonarqubePermission);
+    auditPersister.deleteGithubPermissionsMapping(dbSession, toNewValueForAuditLogs(githubRole, sonarqubePermission));
   }
 
-  private static GithubPermissionsMappingNewValue toNewValueForAuditLogs(GithubPermissionsMappingDto githubPermissionsMappingDto) {
-    return new GithubPermissionsMappingNewValue(githubPermissionsMappingDto.githubRole(),
-      githubPermissionsMappingDto.sonarqubePermission());
+  private static GithubPermissionsMappingNewValue toNewValueForAuditLogs(String githubRole, String sonarqubePermission) {
+    return new GithubPermissionsMappingNewValue(githubRole, sonarqubePermission);
   }
 
   private static GithubPermissionsMappingMapper mapper(DbSession session) {
index c59a911a335a1c31292684e410407d71f20b88f1..bb2eb7fb114c387bf1ebab75758aeeab30f5751c 100644 (file)
 package org.sonar.db.provisioning;
 
 import java.util.Set;
+import org.apache.ibatis.annotations.Param;
 
 public interface GithubPermissionsMappingMapper {
 
   Set<GithubPermissionsMappingDto> selectAll();
 
+  Set<GithubPermissionsMappingDto> selectAllForGithubRole(String githubRole);
+
   void insert(GithubPermissionsMappingDto githubPermissionsMappingDto);
 
+  void delete(@Param("githubRole") String githubRole, @Param("sonarqubePermission") String sonarqubePermission);
 }
index 7f739bc60a51f580a8f05ab78b30f07ae86053a2..9a813f6d050b4c78eaba5be7a8e5bd278d6a8182 100644 (file)
     )
   </insert>
 
+  <delete id="delete" parameterType="GithubPermissionsMapping">
+    delete from github_perms_mapping
+    where github_role = #{githubRole,jdbcType=VARCHAR} AND sonarqube_permission = #{sonarqubePermission,jdbcType=VARCHAR}
+  </delete>
+
   <select id="selectAll" resultType="GithubPermissionsMapping">
     SELECT
       <include refid="githubPermissionsMappingColumns"/>
     FROM github_perms_mapping gpm
   </select>
 
+  <select id="selectAllForGithubRole" resultType="GithubPermissionsMapping">
+    SELECT
+      <include refid="githubPermissionsMappingColumns"/>
+    FROM github_perms_mapping gpm
+    WHERE gpm.github_role =  #{githubRole,jdbcType=VARCHAR}
+  </select>
+
 </mapper>
index 14345c59bdc752d4b54f64fac3b59426517a2820..711683b1055a01784b4f5cbf38db27033be13b57 100644 (file)
@@ -24,11 +24,14 @@ import java.util.Map;
 import java.util.Set;
 import org.junit.Rule;
 import org.junit.Test;
+import org.sonar.core.util.SequenceUuidFactory;
+import org.sonar.core.util.UuidFactory;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.audit.AuditPersister;
 import org.sonar.db.provisioning.GithubPermissionsMappingDao;
 import org.sonar.db.provisioning.GithubPermissionsMappingDto;
+import org.sonar.server.common.permission.Operation;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
@@ -40,6 +43,7 @@ import static org.sonar.server.common.github.permissions.GithubPermissionsMappin
 
 public class GithubPermissionsMappingServiceIT {
 
+  private static final SonarqubePermissions NO_SQ_PERMISSIONS = new SonarqubePermissions(false, false, false, false, false, false);
   @Rule
   public DbTester db = DbTester.create();
   private final DbSession dbSession = db.getSession();
@@ -47,19 +51,20 @@ public class GithubPermissionsMappingServiceIT {
   private final AuditPersister auditPersister = mock();
   private final GithubPermissionsMappingDao githubPermissionsMappingDao = new GithubPermissionsMappingDao(auditPersister);
 
-  private final GithubPermissionsMappingService underTest = new GithubPermissionsMappingService(db.getDbClient(), githubPermissionsMappingDao);
+  private final UuidFactory uuidFactory = new SequenceUuidFactory();
+
+  private final GithubPermissionsMappingService underTest = new GithubPermissionsMappingService(db.getDbClient(), githubPermissionsMappingDao, uuidFactory);
 
   @Test
   public void getPermissionsMapping_whenMappingNotDefined_returnMappingEntirelyFalse() {
     List<GithubPermissionsMapping> actualPermissionsMapping = underTest.getPermissionsMapping();
 
     List<GithubPermissionsMapping> expectedPermissionsMapping = List.of(
-      new GithubPermissionsMapping(READ_GITHUB_ROLE, new SonarqubePermissions(false, false, false, false, false, false)),
-      new GithubPermissionsMapping(TRIAGE_GITHUB_ROLE, new SonarqubePermissions(false, false, false, false, false, false)),
-      new GithubPermissionsMapping(WRITE_GITHUB_ROLE, new SonarqubePermissions(false, false, false, false, false, false)),
-      new GithubPermissionsMapping(MAINTAIN_GITHUB_ROLE, new SonarqubePermissions(false, false, false, false, false, false)),
-      new GithubPermissionsMapping(ADMIN_GITHUB_ROLE, new SonarqubePermissions(false, false, false, false, false, false))
-    );
+      new GithubPermissionsMapping(READ_GITHUB_ROLE, NO_SQ_PERMISSIONS),
+      new GithubPermissionsMapping(TRIAGE_GITHUB_ROLE, NO_SQ_PERMISSIONS),
+      new GithubPermissionsMapping(WRITE_GITHUB_ROLE, NO_SQ_PERMISSIONS),
+      new GithubPermissionsMapping(MAINTAIN_GITHUB_ROLE, NO_SQ_PERMISSIONS),
+      new GithubPermissionsMapping(ADMIN_GITHUB_ROLE, NO_SQ_PERMISSIONS));
 
     assertThat(actualPermissionsMapping).containsAll(expectedPermissionsMapping);
   }
@@ -68,19 +73,17 @@ public class GithubPermissionsMappingServiceIT {
   public void getPermissionsMapping_whenMappingDefined_returnMapping() {
     Map<String, Set<String>> githubRolesToSqPermissions = Map.of(
       READ_GITHUB_ROLE, Set.of("user", "codeviewer"),
-      WRITE_GITHUB_ROLE, Set.of("user", "codeviewer", "issueadmin", "securityhotspotadmin", "admin", "scan")
-    );
+      WRITE_GITHUB_ROLE, Set.of("user", "codeviewer", "issueadmin", "securityhotspotadmin", "admin", "scan"));
     persistGithubPermissionsMapping(githubRolesToSqPermissions);
 
     List<GithubPermissionsMapping> actualPermissionsMapping = underTest.getPermissionsMapping();
 
     List<GithubPermissionsMapping> expectedPermissionsMapping = List.of(
       new GithubPermissionsMapping(READ_GITHUB_ROLE, new SonarqubePermissions(true, true, false, false, false, false)),
-      new GithubPermissionsMapping(TRIAGE_GITHUB_ROLE, new SonarqubePermissions(false, false, false, false, false, false)),
+      new GithubPermissionsMapping(TRIAGE_GITHUB_ROLE, NO_SQ_PERMISSIONS),
       new GithubPermissionsMapping(WRITE_GITHUB_ROLE, new SonarqubePermissions(true, true, true, true, true, true)),
-      new GithubPermissionsMapping(MAINTAIN_GITHUB_ROLE, new SonarqubePermissions(false, false, false, false, false, false)),
-      new GithubPermissionsMapping(ADMIN_GITHUB_ROLE, new SonarqubePermissions(false, false, false, false, false, false))
-    );
+      new GithubPermissionsMapping(MAINTAIN_GITHUB_ROLE, NO_SQ_PERMISSIONS),
+      new GithubPermissionsMapping(ADMIN_GITHUB_ROLE, NO_SQ_PERMISSIONS));
 
     assertThat(actualPermissionsMapping).containsAll(expectedPermissionsMapping);
   }
@@ -96,4 +99,78 @@ public class GithubPermissionsMappingServiceIT {
     dbSession.commit();
   }
 
+  @Test
+  public void updatePermissionsMappings_shouldAddAndRemovePermissions() {
+    Map<String, Set<String>> githubRolesToSqPermissions = Map.of(READ_GITHUB_ROLE, Set.of("user", "codeviewer"));
+    persistGithubPermissionsMapping(githubRolesToSqPermissions);
+
+    PermissionMappingChange permToAdd1 = new PermissionMappingChange(READ_GITHUB_ROLE, "issueadmin", Operation.ADD);
+    PermissionMappingChange permToAdd2 = new PermissionMappingChange(READ_GITHUB_ROLE, "scan", Operation.ADD);
+    PermissionMappingChange permToRemove1 = new PermissionMappingChange(READ_GITHUB_ROLE, "user", Operation.REMOVE);
+    PermissionMappingChange permToRemove2 = new PermissionMappingChange(READ_GITHUB_ROLE, "codeviewer", Operation.REMOVE);
+
+    underTest.updatePermissionsMappings(Set.of(permToAdd1, permToAdd2, permToRemove1, permToRemove2));
+
+    GithubPermissionsMapping updatedPermissionsMapping = underTest.getPermissionsMappingForGithubRole(READ_GITHUB_ROLE);
+
+    GithubPermissionsMapping expectedPermissionsMapping = new GithubPermissionsMapping(READ_GITHUB_ROLE, new SonarqubePermissions(false, false, true, false, false, true));
+    assertThat(updatedPermissionsMapping).isEqualTo(expectedPermissionsMapping);
+  }
+
+  @Test
+  public void updatePermissionsMappings_whenRemovingNonExistingPermission_isNoOp() {
+    PermissionMappingChange permToRemove1 = new PermissionMappingChange(READ_GITHUB_ROLE, "user", Operation.REMOVE);
+
+    underTest.updatePermissionsMappings(Set.of(permToRemove1));
+
+    GithubPermissionsMapping updatedPermissionsMapping = underTest.getPermissionsMappingForGithubRole(READ_GITHUB_ROLE);
+
+    GithubPermissionsMapping expectedPermissionsMapping = new GithubPermissionsMapping(READ_GITHUB_ROLE, NO_SQ_PERMISSIONS);
+    assertThat(updatedPermissionsMapping).isEqualTo(expectedPermissionsMapping);
+  }
+
+  @Test
+  public void updatePermissionsMappings_whenAddingAlreadyExistingPermission_isNoOp() {
+    Map<String, Set<String>> githubRolesToSqPermissions = Map.of(READ_GITHUB_ROLE, Set.of("user", "codeviewer"));
+    persistGithubPermissionsMapping(githubRolesToSqPermissions);
+    PermissionMappingChange permToAdd1 = new PermissionMappingChange(READ_GITHUB_ROLE, "user", Operation.ADD);
+
+    underTest.updatePermissionsMappings(Set.of(permToAdd1));
+
+    GithubPermissionsMapping updatedPermissionsMapping = underTest.getPermissionsMappingForGithubRole(READ_GITHUB_ROLE);
+
+    GithubPermissionsMapping expectedPermissionsMapping = new GithubPermissionsMapping(READ_GITHUB_ROLE, new SonarqubePermissions(true, true, false, false, false, false));
+    assertThat(updatedPermissionsMapping).isEqualTo(expectedPermissionsMapping);
+  }
+
+  @Test
+  public void updatePermissionsMappings_handlesUpdatesForDifferentRoles() {
+    PermissionMappingChange permToAdd1 = new PermissionMappingChange(READ_GITHUB_ROLE, "user", Operation.ADD);
+    PermissionMappingChange permToAdd2 = new PermissionMappingChange(WRITE_GITHUB_ROLE, "user", Operation.ADD);
+
+    underTest.updatePermissionsMappings(Set.of(permToAdd1, permToAdd2));
+
+    SonarqubePermissions userOnlySqPermission = new SonarqubePermissions(true, false, false, false, false, false);
+
+    GithubPermissionsMapping updatedPermissionsMapping = underTest.getPermissionsMappingForGithubRole(READ_GITHUB_ROLE);
+    assertThat(updatedPermissionsMapping).isEqualTo(new GithubPermissionsMapping(READ_GITHUB_ROLE, userOnlySqPermission));
+
+    updatedPermissionsMapping = underTest.getPermissionsMappingForGithubRole(WRITE_GITHUB_ROLE);
+    assertThat(updatedPermissionsMapping).isEqualTo(new GithubPermissionsMapping(WRITE_GITHUB_ROLE, userOnlySqPermission));
+  }
+
+  @Test
+  public void getPermissionsMappingForGithubRole_shouldReturnMappingOnlyForRole() {
+    Map<String, Set<String>> githubRolesToSqPermissions = Map.of(
+      READ_GITHUB_ROLE, Set.of("user", "codeviewer"),
+      WRITE_GITHUB_ROLE, Set.of("user", "codeviewer", "issueadmin", "securityhotspotadmin", "admin", "scan"));
+    persistGithubPermissionsMapping(githubRolesToSqPermissions);
+
+    GithubPermissionsMapping actualPermissionsMapping = underTest.getPermissionsMappingForGithubRole(READ_GITHUB_ROLE);
+
+    GithubPermissionsMapping expectedPermissionsMapping = new GithubPermissionsMapping(READ_GITHUB_ROLE, new SonarqubePermissions(true, true, false, false, false, false));
+
+    assertThat(actualPermissionsMapping).isEqualTo(expectedPermissionsMapping);
+  }
+
 }
index abbcb18964e1fe9fd49f8e4f2b4a99a8722c42e0..c5b48cb0f613784b909eba9137dcce2ca421154d 100644 (file)
@@ -24,6 +24,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.function.Consumer;
 import org.sonar.api.web.UserRole;
+import org.sonar.core.util.UuidFactory;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.provisioning.GithubPermissionsMappingDao;
@@ -31,6 +32,8 @@ import org.sonar.db.provisioning.GithubPermissionsMappingDto;
 
 import static java.util.stream.Collectors.groupingBy;
 import static java.util.stream.Collectors.toSet;
+import static org.sonar.server.common.permission.Operation.ADD;
+import static org.sonar.server.common.permission.Operation.REMOVE;
 
 public class GithubPermissionsMappingService {
   public static final String READ_GITHUB_ROLE = "read";
@@ -44,8 +47,7 @@ public class GithubPermissionsMappingService {
     TRIAGE_GITHUB_ROLE,
     WRITE_GITHUB_ROLE,
     MAINTAIN_GITHUB_ROLE,
-    ADMIN_GITHUB_ROLE
-  );
+    ADMIN_GITHUB_ROLE);
 
   private static final Map<String, Consumer<SonarqubePermissions.Builder>> permissionAsStringToSonarqubePermission = Map.of(
     UserRole.USER, builder -> builder.user(true),
@@ -58,10 +60,18 @@ public class GithubPermissionsMappingService {
 
   private final DbClient dbClient;
   private final GithubPermissionsMappingDao githubPermissionsMappingDao;
+  private final UuidFactory uuidFactory;
 
-  public GithubPermissionsMappingService(DbClient dbClient, GithubPermissionsMappingDao githubPermissionsMappingDao) {
+  public GithubPermissionsMappingService(DbClient dbClient, GithubPermissionsMappingDao githubPermissionsMappingDao, UuidFactory uuidFactory) {
     this.dbClient = dbClient;
     this.githubPermissionsMappingDao = githubPermissionsMappingDao;
+    this.uuidFactory = uuidFactory;
+  }
+
+  public GithubPermissionsMapping getPermissionsMappingForGithubRole(String githubRole) {
+    try (DbSession dbSession = dbClient.openSession(false)) {
+      return toGithubPermissionsMapping(getPermissionsMappingForGithubRole(dbSession, githubRole), githubRole);
+    }
   }
 
   public List<GithubPermissionsMapping> getPermissionsMapping() {
@@ -70,27 +80,65 @@ public class GithubPermissionsMappingService {
     }
   }
 
+  private static GithubPermissionsMapping toGithubPermissionsMapping(Set<GithubPermissionsMappingDto> githubPermissionsMappingDtos, String githubRole) {
+    return new GithubPermissionsMapping(githubRole, getSonarqubePermissions(githubPermissionsMappingDtos));
+  }
+
   private static List<GithubPermissionsMapping> toGithubPermissionsMappings(Set<GithubPermissionsMappingDto> githubPermissionsMappingDtos) {
     Map<String, Set<GithubPermissionsMappingDto>> githubRoleToGithubPermissionsMappingDto = githubPermissionsMappingDtos.stream()
       .collect(groupingBy(GithubPermissionsMappingDto::githubRole, toSet()));
     return GITHUB_BASE_ROLE.stream()
-      .map(githubRole -> toGithubPermissionsMapping(githubRoleToGithubPermissionsMappingDto.get(githubRole), githubRole))
+      .map(githubRole -> toGithubPermissionsMapping(githubRoleToGithubPermissionsMappingDto.getOrDefault(githubRole, Set.of()), githubRole))
       .toList();
   }
 
-  private static GithubPermissionsMapping toGithubPermissionsMapping(Set<GithubPermissionsMappingDto> githubPermissionsMappingDtos, String githubRole) {
-    return new GithubPermissionsMapping(githubRole, getSonarqubePermissions(githubPermissionsMappingDtos));
+  public void updatePermissionsMappings(Set<PermissionMappingChange> permissionChanges) {
+    try (DbSession dbSession = dbClient.openSession(false)) {
+      Map<String, List<PermissionMappingChange>> githubRolesToChanges = permissionChanges.stream()
+        .collect(groupingBy(PermissionMappingChange::githubRole));
+      githubRolesToChanges.forEach((githubRole, changes) -> updatePermissionsMappings(dbSession, githubRole, changes));
+      dbSession.commit();
+    }
+  }
+
+  private void updatePermissionsMappings(DbSession dbSession, String githubRole, List<PermissionMappingChange> permissionChanges) {
+    Set<String> currentPermissionsForRole = getSqPermissionsForGithubRole(dbSession, githubRole);
+    removePermissions(dbSession, permissionChanges, currentPermissionsForRole);
+    addPermissions(dbSession, permissionChanges, currentPermissionsForRole);
+  }
+
+  private Set<String> getSqPermissionsForGithubRole(DbSession dbSession, String githubRole) {
+    return getPermissionsMappingForGithubRole(dbSession, githubRole).stream()
+      .map(GithubPermissionsMappingDto::sonarqubePermission)
+      .collect(toSet());
+  }
+
+  private Set<GithubPermissionsMappingDto> getPermissionsMappingForGithubRole(DbSession dbSession, String githubRole) {
+    return githubPermissionsMappingDao.findAllForGithubRole(dbSession, githubRole);
+  }
+
+  private void removePermissions(DbSession dbSession, List<PermissionMappingChange> permissionChanges, Set<String> currentPermissionsForRole) {
+    permissionChanges.stream()
+      .filter(permissionMappingChange -> REMOVE.equals(permissionMappingChange.operation()))
+      .filter(permissionMappingChange -> currentPermissionsForRole.contains(permissionMappingChange.sonarqubePermission()))
+      .forEach(mapping -> githubPermissionsMappingDao.delete(dbSession, mapping.githubRole(), mapping.sonarqubePermission()));
+  }
+
+  private void addPermissions(DbSession dbSession, List<PermissionMappingChange> permissionChanges, Set<String> currentPermissionsForRole) {
+    permissionChanges.stream()
+      .filter(permissionMappingChange -> ADD.equals(permissionMappingChange.operation()))
+      .filter(permissionMappingChange -> !currentPermissionsForRole.contains(permissionMappingChange.sonarqubePermission()))
+      .forEach(
+        mapping -> githubPermissionsMappingDao.insert(dbSession, new GithubPermissionsMappingDto(uuidFactory.create(), mapping.githubRole(), mapping.sonarqubePermission()))
+      );
   }
 
   private static SonarqubePermissions getSonarqubePermissions(Set<GithubPermissionsMappingDto> githubPermissionsMappingDtos) {
     SonarqubePermissions.Builder builder = SonarqubePermissions.Builder.builder();
-    if (githubPermissionsMappingDtos != null) {
-      githubPermissionsMappingDtos.stream()
-        .map(GithubPermissionsMappingDto::sonarqubePermission)
-        .map(permissionAsStringToSonarqubePermission::get)
-        .forEach(builderConsumer -> builderConsumer.accept(builder));
-    }
+    githubPermissionsMappingDtos.stream()
+      .map(GithubPermissionsMappingDto::sonarqubePermission)
+      .map(permissionAsStringToSonarqubePermission::get)
+      .forEach(builderConsumer -> builderConsumer.accept(builder));
     return builder.build();
   }
-
 }
diff --git a/server/sonar-webserver-common/src/main/java/org/sonar/server/common/github/permissions/PermissionMappingChange.java b/server/sonar-webserver-common/src/main/java/org/sonar/server/common/github/permissions/PermissionMappingChange.java
new file mode 100644 (file)
index 0000000..4045d12
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.common.github.permissions;
+
+import org.sonar.server.common.permission.Operation;
+
+public record PermissionMappingChange(String githubRole, String sonarqubePermission, Operation operation) {
+}
index cfdd0bf8d73bb4c499c6d6a995de71cfc0c42875..0600c42ed3dbdceb56101ea5065224f38309f4ac 100644 (file)
@@ -22,7 +22,7 @@ package org.sonar.server.common.github.permissions;
 public record SonarqubePermissions(
   boolean user,
   boolean codeViewer,
-  boolean issueadmin,
+  boolean issueAdmin,
   boolean securityHotspotAdmin,
   boolean admin,
   boolean scan) {
diff --git a/server/sonar-webserver-common/src/main/java/org/sonar/server/common/permission/Operation.java b/server/sonar-webserver-common/src/main/java/org/sonar/server/common/permission/Operation.java
new file mode 100644 (file)
index 0000000..d8fb495
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.common.permission;
+
+public enum Operation {
+  ADD, REMOVE
+}
diff --git a/server/sonar-webserver-common/src/main/java/org/sonar/server/common/permission/package-info.java b/server/sonar-webserver-common/src/main/java/org/sonar/server/common/permission/package-info.java
new file mode 100644 (file)
index 0000000..b0f18ec
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.server.common.permission;
+
+import javax.annotation.ParametersAreNonnullByDefault;
index 2268fa20afb409378c4faccc1d36516dc5b8e5a9..207987c6ea444a4d6d3192b2d723300f9567d714 100644 (file)
  */
 package org.sonar.server.v2.api.github.permissions.controller;
 
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
+import javax.validation.Valid;
 import org.sonar.server.common.github.permissions.GithubPermissionsMapping;
 import org.sonar.server.common.github.permissions.GithubPermissionsMappingService;
+import org.sonar.server.common.github.permissions.PermissionMappingChange;
+import org.sonar.server.common.permission.Operation;
 import org.sonar.server.user.UserSession;
 import org.sonar.server.v2.api.github.permissions.model.RestGithubPermissionsMapping;
+import org.sonar.server.v2.api.github.permissions.request.GithubPermissionMappingUpdateRequest;
+import org.sonar.server.v2.api.github.permissions.request.PermissionMappingUpdate;
 import org.sonar.server.v2.api.github.permissions.response.GithubPermissionsMappingRestResponse;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
 
-public class DefaultGithubPermissionsController implements GithubPermissionsController{
+import static org.sonar.api.web.UserRole.ADMIN;
+import static org.sonar.api.web.UserRole.CODEVIEWER;
+import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
+import static org.sonar.api.web.UserRole.SCAN;
+import static org.sonar.api.web.UserRole.SECURITYHOTSPOT_ADMIN;
+import static org.sonar.api.web.UserRole.USER;
+
+public class DefaultGithubPermissionsController implements GithubPermissionsController {
 
   private UserSession userSession;
   private GithubPermissionsMappingService githubPermissionsMappingService;
@@ -38,15 +54,42 @@ public class DefaultGithubPermissionsController implements GithubPermissionsCont
 
   @Override
   public GithubPermissionsMappingRestResponse fetchAll() {
-    userSession.checkLoggedIn().checkIsSystemAdministrator();
+    userSession.checkIsSystemAdministrator();
     List<GithubPermissionsMapping> permissionsMapping = githubPermissionsMappingService.getPermissionsMapping();
     return new GithubPermissionsMappingRestResponse(toRestResources(permissionsMapping));
   }
 
+  @Override
+  public RestGithubPermissionsMapping updateMapping(@PathVariable("githubRole") String githubRole, @Valid @RequestBody GithubPermissionMappingUpdateRequest request) {
+    userSession.checkIsSystemAdministrator();
+    PermissionMappingUpdate update = request.permissions();
+    Set<PermissionMappingChange> changes = new HashSet<>();
+
+    update.getUser().map(shouldAddPermission -> toPermissionMappingChange(githubRole, USER, shouldAddPermission)).applyIfDefined(changes::add);
+    update.getCodeViewer().map(shouldAddPermission -> toPermissionMappingChange(githubRole, CODEVIEWER, shouldAddPermission)).applyIfDefined(changes::add);
+    update.getIssueAdmin().map(shouldAddPermission -> toPermissionMappingChange(githubRole, ISSUE_ADMIN, shouldAddPermission)).applyIfDefined(changes::add);
+    update.getSecurityHotspotAdmin().map(shouldAddPermission -> toPermissionMappingChange(githubRole, SECURITYHOTSPOT_ADMIN, shouldAddPermission)).applyIfDefined(changes::add);
+    update.getAdmin().map(shouldAddPermission -> toPermissionMappingChange(githubRole, ADMIN, shouldAddPermission)).applyIfDefined(changes::add);
+    update.getScan().map(shouldAddPermission -> toPermissionMappingChange(githubRole, SCAN, shouldAddPermission)).applyIfDefined(changes::add);
+
+    githubPermissionsMappingService.updatePermissionsMappings(changes);
+
+    return toRestGithubPermissionMapping(githubPermissionsMappingService.getPermissionsMappingForGithubRole(githubRole));
+
+  }
+
+  private static PermissionMappingChange toPermissionMappingChange(String githubRole, String sonarqubePermission, boolean shouldAddPermission) {
+    return new PermissionMappingChange(githubRole, sonarqubePermission, shouldAddPermission ? Operation.ADD : Operation.REMOVE);
+  }
+
   private static List<RestGithubPermissionsMapping> toRestResources(List<GithubPermissionsMapping> permissionsMapping) {
     return permissionsMapping.stream()
-      .map(e -> new RestGithubPermissionsMapping(e.roleName(), e.roleName(), e.permissions()))
+      .map(DefaultGithubPermissionsController::toRestGithubPermissionMapping)
       .toList();
   }
 
+  private static RestGithubPermissionsMapping toRestGithubPermissionMapping(GithubPermissionsMapping githubPermissionsMapping) {
+    return new RestGithubPermissionsMapping(githubPermissionsMapping.roleName(), githubPermissionsMapping.roleName(), githubPermissionsMapping.permissions());
+  }
+
 }
index 78f91f42e82e7c21771bf482a3df316dc6e20153..51bd43f62c5b7b266adf6e688cdb0c86272ed0be 100644 (file)
 package org.sonar.server.v2.api.github.permissions.controller;
 
 import io.swagger.v3.oas.annotations.Operation;
+import javax.validation.Valid;
 import org.sonar.server.v2.WebApiEndpoints;
+import org.sonar.server.v2.api.github.permissions.model.RestGithubPermissionsMapping;
+import org.sonar.server.v2.api.github.permissions.request.GithubPermissionMappingUpdateRequest;
 import org.sonar.server.v2.api.github.permissions.response.GithubPermissionsMappingRestResponse;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PatchMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.ResponseStatus;
 import org.springframework.web.bind.annotation.RestController;
 
+import static org.sonar.server.v2.WebApiEndpoints.JSON_MERGE_PATCH_CONTENT_TYPE;
+
 @RequestMapping(WebApiEndpoints.GITHUB_PERMISSIONS_ENDPOINT)
 @RestController
 public interface GithubPermissionsController {
@@ -38,4 +46,9 @@ public interface GithubPermissionsController {
   @Operation(summary = "Fetch the GitHub permissions mapping", description = "Requires Administer System permission.")
   GithubPermissionsMappingRestResponse fetchAll();
 
+  @PatchMapping(path = "/{githubRole}", consumes = JSON_MERGE_PATCH_CONTENT_TYPE, produces = MediaType.APPLICATION_JSON_VALUE)
+  @ResponseStatus(HttpStatus.OK)
+  @Operation(summary = "Update a single Github permission mapping", description = "Update a single Github permission mapping")
+  RestGithubPermissionsMapping updateMapping(@PathVariable("githubRole") String githubRole, @Valid @RequestBody GithubPermissionMappingUpdateRequest request);
+
 }
diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/request/GithubPermissionMappingUpdateRequest.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/request/GithubPermissionMappingUpdateRequest.java
new file mode 100644 (file)
index 0000000..a7e5e0a
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.v2.api.github.permissions.request;
+
+public record GithubPermissionMappingUpdateRequest(
+  PermissionMappingUpdate permissions) {
+}
diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/request/PermissionMappingUpdate.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/request/PermissionMappingUpdate.java
new file mode 100644 (file)
index 0000000..f82cb45
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.v2.api.github.permissions.request;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import org.sonar.server.v2.common.model.UpdateField;
+
+public class PermissionMappingUpdate {
+  private UpdateField<Boolean> user = UpdateField.undefined();
+  private UpdateField<Boolean> codeViewer = UpdateField.undefined();
+  private UpdateField<Boolean> issueAdmin = UpdateField.undefined();
+  private UpdateField<Boolean> securityHotspotAdmin = UpdateField.undefined();
+  private UpdateField<Boolean> admin = UpdateField.undefined();
+  private UpdateField<Boolean> scan = UpdateField.undefined();
+
+  @Schema(implementation = Boolean.class)
+  public UpdateField<Boolean> getUser() {
+    return user;
+  }
+
+  public void setUser(Boolean user) {
+    this.user = UpdateField.withValue(user);
+  }
+
+  @Schema(implementation = Boolean.class)
+  public UpdateField<Boolean> getCodeViewer() {
+    return codeViewer;
+  }
+
+  public void setCodeViewer(Boolean codeViewer) {
+    this.codeViewer = UpdateField.withValue(codeViewer);
+  }
+
+  @Schema(implementation = Boolean.class)
+  public UpdateField<Boolean> getIssueAdmin() {
+    return issueAdmin;
+  }
+
+  public void setIssueAdmin(Boolean issueAdmin) {
+    this.issueAdmin = UpdateField.withValue(issueAdmin);
+  }
+
+  @Schema(implementation = Boolean.class)
+  public UpdateField<Boolean> getSecurityHotspotAdmin() {
+    return securityHotspotAdmin;
+  }
+
+  public void setSecurityHotspotAdmin(Boolean securityHotspotAdmin) {
+    this.securityHotspotAdmin = UpdateField.withValue(securityHotspotAdmin);
+  }
+
+  @Schema(implementation = Boolean.class)
+  public UpdateField<Boolean> getAdmin() {
+    return admin;
+  }
+
+  public void setAdmin(Boolean admin) {
+    this.admin = UpdateField.withValue(admin);
+  }
+
+  @Schema(implementation = Boolean.class)
+  public UpdateField<Boolean> getScan() {
+    return scan;
+  }
+
+  public void setScan(Boolean scan) {
+    this.scan = UpdateField.withValue(scan);
+  }
+}
diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/request/package-info.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/permissions/request/package-info.java
new file mode 100644 (file)
index 0000000..2aa3f05
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.server.v2.api.github.permissions.request;
+
+import javax.annotation.ParametersAreNonnullByDefault;
index 5418c74664edabf17a2787b96a860ffe18d30eb1..123254d66fb9304c0f05483742d1ab5d02096807 100644 (file)
@@ -34,7 +34,7 @@ public class UserUpdateRestRequest {
 
   @Size(max = 200)
   @Schema(description = "User first name and last name", implementation = String.class)
-  public UpdateField< String> getName() {
+  public UpdateField<String> getName() {
     return name;
   }
 
index d07b6a9e7a56528f9e7cf9d45dd6b4979ed4ed37..916b3a22b709f1e005de1c62df3e638a51f501ba 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.server.v2.common.model;
 
 import java.util.function.Consumer;
+import java.util.function.Function;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import javax.validation.valueextraction.UnwrapByDefault;
@@ -57,6 +58,13 @@ public class UpdateField<T> {
     }
   }
 
+  public <U> UpdateField<U> map(Function<T, U> mappingFunction) {
+    if (isDefined) {
+      return withValue(mappingFunction.apply(value));
+    }
+    return undefined();
+  }
+
   @Override
   public String toString() {
     return value.toString();
index b2c0b654ce44bd5af638609c8e78a5738e345bbc..4b3796c7a643885441ade075134604fddd0db4d6 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.server.v2.config;
 
 import javax.annotation.Nullable;
+import org.sonar.core.util.UuidFactory;
 import org.sonar.db.DbClient;
 import org.sonar.db.provisioning.GithubPermissionsMappingDao;
 import org.sonar.server.common.github.permissions.GithubPermissionsMappingService;
@@ -80,8 +81,8 @@ public class PlatformLevel4WebConfig {
   }
 
   @Bean
-  public GithubPermissionsMappingService githubPermissionsMappingService(DbClient dbClient, GithubPermissionsMappingDao githubPermissionsMappingDao) {
-    return new GithubPermissionsMappingService(dbClient, githubPermissionsMappingDao);
+  public GithubPermissionsMappingService githubPermissionsMappingService(DbClient dbClient, GithubPermissionsMappingDao githubPermissionsMappingDao, UuidFactory uuidFactory) {
+    return new GithubPermissionsMappingService(dbClient, githubPermissionsMappingDao, uuidFactory);
   }
 
   @Bean
index a31f46ae2ab6586b55f960aa635691feb20bab2d..3ed8b3346c6bab31be96a55d6e456609b7b2296e 100644 (file)
@@ -22,11 +22,15 @@ package org.sonar.server.v2.api.github.permissions.controller;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import java.util.List;
+import java.util.Set;
 import org.junit.Rule;
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
 import org.sonar.server.common.github.permissions.GithubPermissionsMapping;
 import org.sonar.server.common.github.permissions.GithubPermissionsMappingService;
+import org.sonar.server.common.github.permissions.PermissionMappingChange;
 import org.sonar.server.common.github.permissions.SonarqubePermissions;
+import org.sonar.server.common.permission.Operation;
 import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.v2.api.ControllerTester;
 import org.sonar.server.v2.api.github.permissions.model.RestGithubPermissionsMapping;
@@ -36,22 +40,25 @@ import org.springframework.test.web.servlet.MvcResult;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.sonar.server.v2.WebApiEndpoints.GITHUB_PERMISSIONS_ENDPOINT;
+import static org.sonar.server.v2.WebApiEndpoints.JSON_MERGE_PATCH_CONTENT_TYPE;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
 public class DefaultGithubPermissionsControllerTest {
+
+  public static final String GITHUB_ROLE = "role1";
+  private static final Gson gson = new GsonBuilder().create();
+
   @Rule
   public UserSessionRule userSession = UserSessionRule.standalone();
   private final GithubPermissionsMappingService githubPermissionsMappingService = mock();
-
   private final MockMvc mockMvc = ControllerTester.getMockMvc(new DefaultGithubPermissionsController(userSession, githubPermissionsMappingService));
 
-  private static final Gson gson = new GsonBuilder().create();
-
-
   @Test
   public void fetchMapping_whenUserIsNotAdministrator_shouldReturnForbidden() throws Exception {
     userSession.logIn().setNonSystemAdministrator();
@@ -67,9 +74,8 @@ public class DefaultGithubPermissionsControllerTest {
     userSession.logIn().setSystemAdministrator();
 
     List<GithubPermissionsMapping> mapping = List.of(
-      new GithubPermissionsMapping("role1", new SonarqubePermissions(true, false, true, false, true, false)),
-      new GithubPermissionsMapping("role2", new SonarqubePermissions(false, true, false, true, false, true))
-    );
+      new GithubPermissionsMapping(GITHUB_ROLE, new SonarqubePermissions(true, false, true, false, true, false)),
+      new GithubPermissionsMapping("role2", new SonarqubePermissions(false, true, false, true, false, true)));
     when(githubPermissionsMappingService.getPermissionsMapping()).thenReturn(mapping);
 
     MvcResult mvcResult = mockMvc.perform(get(GITHUB_PERMISSIONS_ENDPOINT))
@@ -86,4 +92,60 @@ public class DefaultGithubPermissionsControllerTest {
       .toList();
   }
 
+  @Test
+  public void updateMapping_whenUserIsNotAdministrator_shouldReturnForbidden() throws Exception {
+    userSession.logIn().setNonSystemAdministrator();
+
+    mockMvc.perform(
+        patch(GITHUB_PERMISSIONS_ENDPOINT + "/" + GITHUB_ROLE)
+          .contentType(JSON_MERGE_PATCH_CONTENT_TYPE)
+          .content("""
+            {
+                "user": true,
+                "codeViewer": false,
+                "admin": true
+            }
+            """))
+      .andExpectAll(
+        status().isForbidden(),
+        content().json("{\"message\":\"Insufficient privileges\"}"));
+  }
+
+  @Test
+  public void updateMapping_shouldUpdateMapping() throws Exception {
+    userSession.logIn().setSystemAdministrator();
+    GithubPermissionsMapping updatedRolePermissions = new GithubPermissionsMapping(GITHUB_ROLE, new SonarqubePermissions(true, false, false, true, true, false));
+
+    when(githubPermissionsMappingService.getPermissionsMappingForGithubRole(GITHUB_ROLE)).thenReturn(updatedRolePermissions);
+
+    MvcResult mvcResult = mockMvc.perform(
+        patch(GITHUB_PERMISSIONS_ENDPOINT + "/" + GITHUB_ROLE)
+          .contentType(JSON_MERGE_PATCH_CONTENT_TYPE)
+          .content("""
+            {
+              "permissions": {
+                "user": true,
+                "codeViewer": false,
+                "admin": true
+              }
+            }
+            """))
+      .andExpect(status().isOk())
+      .andReturn();
+
+    RestGithubPermissionsMapping response = gson.fromJson(mvcResult.getResponse().getContentAsString(), RestGithubPermissionsMapping.class);
+
+    RestGithubPermissionsMapping expectedResponse = new RestGithubPermissionsMapping(GITHUB_ROLE, GITHUB_ROLE, new SonarqubePermissions(true, false, false, true, true, false));
+    assertThat(response).isEqualTo(expectedResponse);
+
+    ArgumentCaptor<Set<PermissionMappingChange>> permissionMappingChangesCaptor = ArgumentCaptor.forClass(Set.class);
+    verify(githubPermissionsMappingService).updatePermissionsMappings(permissionMappingChangesCaptor.capture());
+    assertThat(permissionMappingChangesCaptor.getValue())
+      .containsExactlyInAnyOrder(
+        new PermissionMappingChange(GITHUB_ROLE, "codeviewer", Operation.REMOVE),
+        new PermissionMappingChange(GITHUB_ROLE, "user", Operation.ADD),
+        new PermissionMappingChange(GITHUB_ROLE, "admin", Operation.ADD)
+      );
+  }
+
 }
index 07179bf33e76f38e11832bba6c65d9ffe2124471..0676f3f992f99b8a0dc3ecc698e368ebb8267386 100644 (file)
@@ -38,6 +38,7 @@ import org.sonar.db.permission.GroupPermissionDto;
 import org.sonar.db.project.ProjectDto;
 import org.sonar.db.user.GroupDto;
 import org.sonar.db.user.UserDto;
+import org.sonar.server.common.permission.Operation;
 import org.sonar.server.exceptions.BadRequestException;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -70,14 +71,14 @@ public class GroupPermissionChangerIT {
 
   @Test
   public void apply_adds_global_permission_to_group() {
-    apply(new GroupPermissionChange(PermissionChange.Operation.ADD, ADMINISTER_QUALITY_PROFILES.getKey(), null, group, permissionService));
+    apply(new GroupPermissionChange(Operation.ADD, ADMINISTER_QUALITY_PROFILES.getKey(), null, group, permissionService));
 
     assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(ADMINISTER_QUALITY_PROFILES.getKey());
   }
 
   @Test
   public void apply_adds_global_permission_to_group_AnyOne() {
-    apply(new GroupPermissionChange(PermissionChange.Operation.ADD, ADMINISTER_QUALITY_PROFILES.getKey(), null, null, permissionService));
+    apply(new GroupPermissionChange(Operation.ADD, ADMINISTER_QUALITY_PROFILES.getKey(), null, null, permissionService));
 
     assertThat(db.users().selectAnyonePermissions(null)).containsOnly(ADMINISTER_QUALITY_PROFILES.getKey());
   }
@@ -86,7 +87,7 @@ public class GroupPermissionChangerIT {
   public void apply_fails_with_BadRequestException_when_adding_any_permission_to_group_AnyOne_on_private_project() {
     permissionService.getAllProjectPermissions()
       .forEach(perm -> {
-        GroupPermissionChange change = new GroupPermissionChange(PermissionChange.Operation.ADD, perm, privateProject, null, permissionService);
+        GroupPermissionChange change = new GroupPermissionChange(Operation.ADD, perm, privateProject, null, permissionService);
         try {
           apply(change);
           fail("a BadRequestException should have been thrown");
@@ -103,7 +104,7 @@ public class GroupPermissionChangerIT {
 
     permissionService.getAllProjectPermissions()
       .forEach(perm -> {
-        apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, perm, privateProject, null, permissionService));
+        apply(new GroupPermissionChange(Operation.REMOVE, perm, privateProject, null, permissionService));
 
         assertThat(db.users().selectAnyonePermissions(privateProject.getUuid())).contains(perm);
       });
@@ -136,7 +137,7 @@ public class GroupPermissionChangerIT {
 
   private void applyAddsPermissionToGroupOnPrivateProject(String permission) {
 
-    apply(new GroupPermissionChange(PermissionChange.Operation.ADD, permission, privateProject, group, permissionService));
+    apply(new GroupPermissionChange(Operation.ADD, permission, privateProject, group, permissionService));
 
     assertThat(db.users().selectGroupPermissions(group, null)).isEmpty();
     assertThat(db.users().selectGroupPermissions(group, privateProject)).containsOnly(permission);
@@ -170,28 +171,28 @@ public class GroupPermissionChangerIT {
   private void applyRemovesPermissionFromGroupOnPrivateProject(String permission) {
     db.users().insertEntityPermissionOnGroup(group, permission, privateProject);
 
-    apply(new GroupPermissionChange(PermissionChange.Operation.ADD, permission, privateProject, group, permissionService), permission);
+    apply(new GroupPermissionChange(Operation.ADD, permission, privateProject, group, permissionService), permission);
 
     assertThat(db.users().selectGroupPermissions(group, privateProject)).containsOnly(permission);
   }
 
   @Test
   public void apply_has_no_effect_when_adding_USER_permission_to_group_AnyOne_on_a_public_project() {
-    apply(new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.USER, publicProject, null, permissionService));
+    apply(new GroupPermissionChange(Operation.ADD, UserRole.USER, publicProject, null, permissionService));
 
     assertThat(db.users().selectAnyonePermissions(publicProject.getUuid())).isEmpty();
   }
 
   @Test
   public void apply_has_no_effect_when_adding_CODEVIEWER_permission_to_group_AnyOne_on_a_public_project() {
-    apply(new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.CODEVIEWER, publicProject, null, permissionService));
+    apply(new GroupPermissionChange(Operation.ADD, UserRole.CODEVIEWER, publicProject, null, permissionService));
 
     assertThat(db.users().selectAnyonePermissions(publicProject.getUuid())).isEmpty();
   }
 
   @Test
   public void apply_fails_with_BadRequestException_when_adding_permission_ADMIN_to_group_AnyOne_on_a_public_project() {
-    GroupPermissionChange change = new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.ADMIN, publicProject, null, permissionService);
+    GroupPermissionChange change = new GroupPermissionChange(Operation.ADD, UserRole.ADMIN, publicProject, null, permissionService);
     assertThatThrownBy(() -> apply(change))
       .isInstanceOf(BadRequestException.class)
       .hasMessage("It is not possible to add the 'admin' permission to group 'Anyone'.");
@@ -199,21 +200,21 @@ public class GroupPermissionChangerIT {
 
   @Test
   public void apply_adds_permission_ISSUE_ADMIN_to_group_AnyOne_on_a_public_project() {
-    apply(new GroupPermissionChange(PermissionChange.Operation.ADD, UserRole.ISSUE_ADMIN, publicProject, null, permissionService));
+    apply(new GroupPermissionChange(Operation.ADD, UserRole.ISSUE_ADMIN, publicProject, null, permissionService));
 
     assertThat(db.users().selectAnyonePermissions(publicProject.getUuid())).containsOnly(UserRole.ISSUE_ADMIN);
   }
 
   @Test
   public void apply_adds_permission_SCAN_EXECUTION_to_group_AnyOne_on_a_public_project() {
-    apply(new GroupPermissionChange(PermissionChange.Operation.ADD, GlobalPermission.SCAN.getKey(), publicProject, null, permissionService));
+    apply(new GroupPermissionChange(Operation.ADD, GlobalPermission.SCAN.getKey(), publicProject, null, permissionService));
 
     assertThat(db.users().selectAnyonePermissions(publicProject.getUuid())).containsOnly(GlobalPermission.SCAN.getKey());
   }
 
   @Test
   public void apply_fails_with_BadRequestException_when_removing_USER_permission_from_group_AnyOne_on_a_public_project() {
-    GroupPermissionChange change = new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.USER, publicProject, null, permissionService);
+    GroupPermissionChange change = new GroupPermissionChange(Operation.REMOVE, UserRole.USER, publicProject, null, permissionService);
     assertThatThrownBy(() -> apply(change))
       .isInstanceOf(BadRequestException.class)
       .hasMessage("Permission user can't be removed from a public component");
@@ -221,7 +222,7 @@ public class GroupPermissionChangerIT {
 
   @Test
   public void apply_fails_with_BadRequestException_when_removing_CODEVIEWER_permission_from_group_AnyOne_on_a_public_project() {
-    GroupPermissionChange change = new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.CODEVIEWER, publicProject, null, permissionService);
+    GroupPermissionChange change = new GroupPermissionChange(Operation.REMOVE, UserRole.CODEVIEWER, publicProject, null, permissionService);
     assertThatThrownBy(() -> apply(change))
       .isInstanceOf(BadRequestException.class)
       .hasMessage("Permission codeviewer can't be removed from a public component");
@@ -245,14 +246,14 @@ public class GroupPermissionChangerIT {
   private void applyRemovesPermissionFromGroupAnyOneOnAPublicProject(String permission) {
     db.users().insertEntityPermissionOnAnyone(permission, publicProject);
 
-    apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, permission, publicProject, null, permissionService), permission);
+    apply(new GroupPermissionChange(Operation.REMOVE, permission, publicProject, null, permissionService), permission);
 
     assertThat(db.users().selectAnyonePermissions(publicProject.getUuid())).isEmpty();
   }
 
   @Test
   public void apply_fails_with_BadRequestException_when_removing_USER_permission_from_a_group_on_a_public_project() {
-    GroupPermissionChange change = new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.USER, publicProject, group, permissionService);
+    GroupPermissionChange change = new GroupPermissionChange(Operation.REMOVE, UserRole.USER, publicProject, group, permissionService);
     assertThatThrownBy(() -> apply(change))
       .isInstanceOf(BadRequestException.class)
       .hasMessage("Permission user can't be removed from a public component");
@@ -260,7 +261,7 @@ public class GroupPermissionChangerIT {
 
   @Test
   public void apply_fails_with_BadRequestException_when_removing_CODEVIEWER_permission_from_a_group_on_a_public_project() {
-    GroupPermissionChange change = new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.CODEVIEWER, publicProject, group, permissionService);
+    GroupPermissionChange change = new GroupPermissionChange(Operation.REMOVE, UserRole.CODEVIEWER, publicProject, group, permissionService);
     assertThatThrownBy(() -> apply(change))
       .isInstanceOf(BadRequestException.class)
       .hasMessage("Permission codeviewer can't be removed from a public component");
@@ -268,7 +269,7 @@ public class GroupPermissionChangerIT {
 
   @Test
   public void add_permission_to_anyone() {
-    apply(new GroupPermissionChange(PermissionChange.Operation.ADD, ADMINISTER_QUALITY_PROFILES.getKey(), null, null, permissionService));
+    apply(new GroupPermissionChange(Operation.ADD, ADMINISTER_QUALITY_PROFILES.getKey(), null, null, permissionService));
 
     assertThat(db.users().selectGroupPermissions(group, null)).isEmpty();
     assertThat(db.users().selectAnyonePermissions(null)).containsOnly(ADMINISTER_QUALITY_PROFILES.getKey());
@@ -278,7 +279,7 @@ public class GroupPermissionChangerIT {
   public void do_nothing_when_adding_permission_that_already_exists() {
     db.users().insertPermissionOnGroup(group, ADMINISTER_QUALITY_GATES);
 
-    apply(new GroupPermissionChange(PermissionChange.Operation.ADD, ADMINISTER_QUALITY_GATES.getKey(), null, group, permissionService));
+    apply(new GroupPermissionChange(Operation.ADD, ADMINISTER_QUALITY_GATES.getKey(), null, group, permissionService));
 
     assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(ADMINISTER_QUALITY_GATES.getKey());
   }
@@ -290,7 +291,7 @@ public class GroupPermissionChangerIT {
       .filter(perm -> !UserRole.ADMIN.equals(perm) && !GlobalPermission.SCAN.getKey().equals(perm))
       .forEach(perm -> {
         try {
-          new GroupPermissionChange(PermissionChange.Operation.ADD, perm, privateProject, group, permissionService);
+          new GroupPermissionChange(Operation.ADD, perm, privateProject, group, permissionService);
           fail("a BadRequestException should have been thrown for permission " + perm);
         } catch (BadRequestException e) {
           assertThat(e).hasMessage("Invalid project permission '" + perm +
@@ -306,7 +307,7 @@ public class GroupPermissionChangerIT {
       .filter(perm -> !UserRole.ADMIN.equals(perm) && !GlobalPermission.SCAN.getKey().equals(perm))
       .forEach(perm -> {
         try {
-          new GroupPermissionChange(PermissionChange.Operation.ADD, perm, publicProject, group, permissionService);
+          new GroupPermissionChange(Operation.ADD, perm, publicProject, group, permissionService);
           fail("a BadRequestException should have been thrown for permission " + perm);
         } catch (BadRequestException e) {
           assertThat(e).hasMessage("Invalid project permission '" + perm +
@@ -322,7 +323,7 @@ public class GroupPermissionChangerIT {
       .filter(perm -> !GlobalPermission.SCAN.getKey().equals(perm) && !GlobalPermission.ADMINISTER.getKey().equals(perm))
       .forEach(permission -> {
         try {
-          new GroupPermissionChange(PermissionChange.Operation.ADD, permission, null, group, permissionService);
+          new GroupPermissionChange(Operation.ADD, permission, null, group, permissionService);
           fail("a BadRequestException should have been thrown for permission " + permission);
         } catch (BadRequestException e) {
           assertThat(e).hasMessage("Invalid global permission '" + permission + "'. Valid values are [admin, gateadmin, profileadmin, provisioning, scan]");
@@ -335,7 +336,7 @@ public class GroupPermissionChangerIT {
     db.users().insertPermissionOnGroup(group, ADMINISTER_QUALITY_GATES);
     db.users().insertPermissionOnGroup(group, PROVISION_PROJECTS);
 
-    apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, ADMINISTER_QUALITY_GATES.getKey(), null, group, permissionService), ADMINISTER_QUALITY_GATES.getKey(),
+    apply(new GroupPermissionChange(Operation.REMOVE, ADMINISTER_QUALITY_GATES.getKey(), null, group, permissionService), ADMINISTER_QUALITY_GATES.getKey(),
       PROVISION_PROJECTS.getKey());
 
     assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(PROVISION_PROJECTS.getKey());
@@ -347,7 +348,7 @@ public class GroupPermissionChangerIT {
     db.users().insertEntityPermissionOnGroup(group, UserRole.ISSUE_ADMIN, privateProject);
     db.users().insertEntityPermissionOnGroup(group, UserRole.CODEVIEWER, privateProject);
 
-    apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.ISSUE_ADMIN, privateProject, group, permissionService), UserRole.ISSUE_ADMIN,
+    apply(new GroupPermissionChange(Operation.REMOVE, UserRole.ISSUE_ADMIN, privateProject, group, permissionService), UserRole.ISSUE_ADMIN,
       UserRole.CODEVIEWER);
 
     assertThat(db.users().selectGroupPermissions(group, null)).containsOnly(ADMINISTER_QUALITY_GATES.getKey());
@@ -356,7 +357,7 @@ public class GroupPermissionChangerIT {
 
   @Test
   public void do_not_fail_if_removing_a_permission_that_does_not_exist() {
-    apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, UserRole.ISSUE_ADMIN, privateProject, group, permissionService));
+    apply(new GroupPermissionChange(Operation.REMOVE, UserRole.ISSUE_ADMIN, privateProject, group, permissionService));
 
     assertThat(db.users().selectGroupPermissions(group, null)).isEmpty();
     assertThat(db.users().selectGroupPermissions(group, privateProject)).isEmpty();
@@ -366,7 +367,7 @@ public class GroupPermissionChangerIT {
   public void fail_to_remove_admin_permission_if_no_more_admins() {
     db.users().insertPermissionOnGroup(group, ADMINISTER);
 
-    GroupPermissionChange change = new GroupPermissionChange(PermissionChange.Operation.REMOVE, ADMINISTER.getKey(), null, group, permissionService);
+    GroupPermissionChange change = new GroupPermissionChange(Operation.REMOVE, ADMINISTER.getKey(), null, group, permissionService);
     Set<String> permission = Set.of("admin");
     DbSession session = db.getSession();
     assertThatThrownBy(() -> underTest.apply(session, permission, change))
@@ -380,7 +381,7 @@ public class GroupPermissionChangerIT {
     UserDto admin = db.users().insertUser();
     db.users().insertGlobalPermissionOnUser(admin, ADMINISTER);
 
-    apply(new GroupPermissionChange(PermissionChange.Operation.REMOVE, ADMINISTER.getKey(), null, group, permissionService), ADMINISTER.getKey());
+    apply(new GroupPermissionChange(Operation.REMOVE, ADMINISTER.getKey(), null, group, permissionService), ADMINISTER.getKey());
 
     assertThat(db.users().selectGroupPermissions(group, null)).isEmpty();
   }
index 167bc6b2392136228a0ac8343dfaa4176fabbac0..5bb52d99ac4af761840fd3f1c63ad89867c12d91 100644 (file)
@@ -42,8 +42,8 @@ import org.sonar.server.exceptions.BadRequestException;
 import static java.util.stream.Collectors.toSet;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.sonar.server.permission.PermissionChange.Operation.ADD;
-import static org.sonar.server.permission.PermissionChange.Operation.REMOVE;
+import static org.sonar.server.common.permission.Operation.ADD;
+import static org.sonar.server.common.permission.Operation.REMOVE;
 import static org.sonar.server.permission.PermissionServiceImpl.ALL_PROJECT_PERMISSIONS;
 
 public class UserPermissionChangerIT {
index 99bbd34801a927110d55e618321ffb1c79f36b48..1eeb768ad5aa1dfb41f6fa0b4d8d0a6db16757c2 100644 (file)
@@ -42,7 +42,7 @@ import org.sonar.db.project.ProjectDto;
 import org.sonar.db.user.UserDto;
 import org.sonar.server.es.Indexers;
 import org.sonar.server.favorite.FavoriteUpdater;
-import org.sonar.server.permission.PermissionChange;
+import org.sonar.server.common.permission.Operation;
 import org.sonar.server.permission.PermissionService;
 import org.sonar.server.permission.PermissionTemplateService;
 import org.sonar.server.permission.PermissionUpdater;
@@ -173,7 +173,7 @@ public class ComponentUpdater {
   }
 
   private UserPermissionChange toUserPermissionChange(String permission, ProjectDto projectDto, UserDto userDto) {
-    return new UserPermissionChange(PermissionChange.Operation.ADD, permission, projectDto, userDto, permissionService);
+    return new UserPermissionChange(Operation.ADD, permission, projectDto, userDto, permissionService);
   }
 
   private void addToFavourites(DbSession dbSession, ProjectDto projectDto, @Nullable String userUuid, @Nullable String userLogin) {
index 8f42ac9419f007a4375766b66e0c76da6da20646..61964275fe8406b4b0ab32a5263958722ca09cc1 100644 (file)
@@ -23,6 +23,7 @@ import java.util.Optional;
 import javax.annotation.Nullable;
 import org.sonar.db.entity.EntityDto;
 import org.sonar.db.user.GroupDto;
+import org.sonar.server.common.permission.Operation;
 
 public class GroupPermissionChange extends PermissionChange {
 
index da4c8bcea8c5eaa8925869d654fc668d2fb60ffd..2c09169535dbf64585f5f424acd912b8885c2382 100644 (file)
@@ -33,8 +33,8 @@ import org.sonar.db.permission.GroupPermissionDto;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static java.lang.String.format;
 import static org.sonar.server.exceptions.BadRequestException.checkRequest;
-import static org.sonar.server.permission.PermissionChange.Operation.ADD;
-import static org.sonar.server.permission.PermissionChange.Operation.REMOVE;
+import static org.sonar.server.common.permission.Operation.ADD;
+import static org.sonar.server.common.permission.Operation.REMOVE;
 
 public class GroupPermissionChanger implements GranteeTypeSpecificPermissionUpdater<GroupPermissionChange> {
 
index affcb9ea4418450e1b984be8bccfd985d3de30d4..52f111d4604f7b671ebbf1f42968d4680acda657 100644 (file)
@@ -23,16 +23,13 @@ import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.sonar.db.entity.EntityDto;
 import org.sonar.db.permission.GlobalPermission;
+import org.sonar.server.common.permission.Operation;
 
 import static java.util.Objects.requireNonNull;
 import static org.sonar.server.exceptions.BadRequestException.checkRequest;
 
 public abstract class PermissionChange {
 
-  public enum Operation {
-    ADD, REMOVE
-  }
-
   private final Operation operation;
   private final String permission;
   private final EntityDto entity;
index ccec4df78184219a00c3b5c79ce50c73d131a01f..3e7a7831df4c73676f780b8b62872d0469835508 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.server.permission;
 import javax.annotation.Nullable;
 import org.sonar.db.entity.EntityDto;
 import org.sonar.db.user.UserId;
+import org.sonar.server.common.permission.Operation;
 
 import static java.util.Objects.requireNonNull;
 
index 446f592be91be382fd96730dc4569839095267c4..ad226c275b83b40822b9bcaf26477b7237d85043 100644 (file)
@@ -31,8 +31,8 @@ import org.sonar.db.permission.GlobalPermission;
 import org.sonar.db.permission.UserPermissionDto;
 
 import static org.sonar.server.exceptions.BadRequestException.checkRequest;
-import static org.sonar.server.permission.PermissionChange.Operation.ADD;
-import static org.sonar.server.permission.PermissionChange.Operation.REMOVE;
+import static org.sonar.server.common.permission.Operation.ADD;
+import static org.sonar.server.common.permission.Operation.REMOVE;
 
 /**
  * Adds and removes user permissions. Both global and project scopes are supported.
index f0265f8a32a998c7eef5e385b9b3d708da378bdd..7aea2e2ff8f06668641388e0b8ccec8da1f75946 100644 (file)
@@ -30,7 +30,7 @@ import org.sonar.db.entity.EntityDto;
 import org.sonar.db.user.GroupDto;
 import org.sonar.server.common.management.ManagedInstanceChecker;
 import org.sonar.server.permission.GroupPermissionChange;
-import org.sonar.server.permission.PermissionChange;
+import org.sonar.server.common.permission.Operation;
 import org.sonar.server.permission.PermissionService;
 import org.sonar.server.permission.PermissionUpdater;
 import org.sonar.server.user.UserSession;
@@ -94,7 +94,7 @@ public class AddGroupAction implements PermissionsWsAction {
       }
       wsSupport.checkPermissionManagementAccess(userSession, entityDto);
       GroupPermissionChange change = new GroupPermissionChange(
-        PermissionChange.Operation.ADD,
+        Operation.ADD,
         request.mandatoryParam(PARAM_PERMISSION),
         entityDto,
         groupDto,
index e119759bb022d24d36f3e37b0b3056e0848455ac..04b9a237d3a0aa9d8d8a1232af1ccc7797b12e7d 100644 (file)
@@ -28,7 +28,7 @@ import org.sonar.db.DbSession;
 import org.sonar.db.entity.EntityDto;
 import org.sonar.db.user.UserId;
 import org.sonar.server.common.management.ManagedInstanceChecker;
-import org.sonar.server.permission.PermissionChange;
+import org.sonar.server.common.permission.Operation;
 import org.sonar.server.permission.PermissionService;
 import org.sonar.server.permission.PermissionUpdater;
 import org.sonar.server.permission.UserPermissionChange;
@@ -97,7 +97,7 @@ public class AddUserAction implements PermissionsWsAction {
       UserId user = wsSupport.findUser(dbSession, userLogin);
 
       UserPermissionChange change = new UserPermissionChange(
-        PermissionChange.Operation.ADD,
+        Operation.ADD,
         request.mandatoryParam(PARAM_PERMISSION),
         entityDto,
         user,
index 60d429f55eb1526090c3d52e8ca11ab902e7a961..4ca82e687264964cb570bb044493a058d6e84b82 100644 (file)
@@ -30,7 +30,7 @@ import org.sonar.db.user.GroupDto;
 import org.sonar.server.common.management.ManagedInstanceChecker;
 import org.sonar.server.permission.GroupPermissionChange;
 import org.sonar.server.permission.GroupUuidOrAnyone;
-import org.sonar.server.permission.PermissionChange;
+import org.sonar.server.common.permission.Operation;
 import org.sonar.server.permission.PermissionService;
 import org.sonar.server.permission.PermissionUpdater;
 import org.sonar.server.user.UserSession;
@@ -100,7 +100,7 @@ public class RemoveGroupAction implements PermissionsWsAction {
       wsSupport.checkRemovingOwnBrowsePermissionOnPrivateProject(dbSession, userSession, entityDto, permission, GroupUuidOrAnyone.from(groupDto));
 
       GroupPermissionChange change = new GroupPermissionChange(
-        PermissionChange.Operation.REMOVE,
+        Operation.REMOVE,
         permission,
         entityDto,
         groupDto,
index d688ad8d78a604b98958a4ddab691e91f556ef80..9ac7fa0b3b860162bb8701edcdcbe18e23e6407b 100644 (file)
@@ -27,7 +27,7 @@ import org.sonar.db.DbSession;
 import org.sonar.db.entity.EntityDto;
 import org.sonar.db.user.UserId;
 import org.sonar.server.common.management.ManagedInstanceChecker;
-import org.sonar.server.permission.PermissionChange;
+import org.sonar.server.common.permission.Operation;
 import org.sonar.server.permission.PermissionService;
 import org.sonar.server.permission.PermissionUpdater;
 import org.sonar.server.permission.UserPermissionChange;
@@ -95,7 +95,7 @@ public class RemoveUserAction implements PermissionsWsAction {
         managedInstanceChecker.throwIfUserAndProjectAreManaged(dbSession, userIdDto.getUuid(), entityDto.getUuid());
       }
       UserPermissionChange change = new UserPermissionChange(
-        PermissionChange.Operation.REMOVE,
+        Operation.REMOVE,
         permission,
         entityDto,
         userIdDto,