diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2017-09-25 15:43:10 +0200 |
---|---|---|
committer | Stas Vilchik <stas.vilchik@sonarsource.com> | 2017-10-02 17:18:15 +0200 |
commit | bb0bd260f3742c010b9e7034ea5d6947e694a130 (patch) | |
tree | 172e2e72927424fcb131c0cfcce75fcd4c33b348 /server | |
parent | e212b5945cbd0fdfda9caeac6cf969732f11f74e (diff) | |
download | sonarqube-bb0bd260f3742c010b9e7034ea5d6947e694a130.tar.gz sonarqube-bb0bd260f3742c010b9e7034ea5d6947e694a130.zip |
SONAR-1330 Remove group permission to edit single quality profile
Diffstat (limited to 'server')
6 files changed, 362 insertions, 6 deletions
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditGroupsDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditGroupsDao.java index 1f429dc112e..b690eecdb09 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditGroupsDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditGroupsDao.java @@ -40,6 +40,10 @@ public class QProfileEditGroupsDao implements Dao { mapper(dbSession).insert(dto, system2.now()); } + public void deleteByQProfileAndGroup(DbSession dbSession, QProfileDto profile, GroupDto group) { + mapper(dbSession).delete(profile.getKee(), group.getId()); + } + private static QProfileEditGroupsMapper mapper(DbSession dbSession) { return dbSession.getMapper(QProfileEditGroupsMapper.class); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditGroupsMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditGroupsMapper.java index ce96f4ea4af..d4eb535299a 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditGroupsMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileEditGroupsMapper.java @@ -27,4 +27,6 @@ public interface QProfileEditGroupsMapper { void insert(@Param("dto") QProfileEditGroupsDto dto, @Param("now") long now); + void delete(@Param("qProfileUuid") String qProfileUuid, @Param("groupId") int groupId); + } diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/QProfileEditGroupsMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/QProfileEditGroupsMapper.xml index 40622269330..9be145a233e 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/QProfileEditGroupsMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/QProfileEditGroupsMapper.xml @@ -32,5 +32,11 @@ ) </insert> + <delete id="delete" parameterType="map"> + delete from qprofile_edit_groups + where qprofile_uuid = #{qProfileUuid, jdbcType=VARCHAR} + and group_id = #{groupId, jdbcType=INTEGER} + </delete> + </mapper> diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QProfileEditGroupsDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QProfileEditGroupsDaoTest.java index 41ed91c6e04..d19ccf125ca 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QProfileEditGroupsDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QProfileEditGroupsDaoTest.java @@ -71,4 +71,17 @@ public class QProfileEditGroupsDaoTest { entry("createdAt", NOW)); } + @Test + public void deleteByQProfileAndGroup() { + OrganizationDto organization = db.organizations().insert(); + QProfileDto profile = db.qualityProfiles().insert(organization); + GroupDto group = db.users().insertGroup(organization); + db.qualityProfiles().addGroupPermission(profile, group); + assertThat(underTest.exists(db.getSession(), profile, group)).isTrue(); + + underTest.deleteByQProfileAndGroup(db.getSession(), profile, group); + + assertThat(underTest.exists(db.getSession(), profile, group)).isFalse(); + } + } diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/RemoveGroupAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/RemoveGroupAction.java index 2df9637a2db..9c94c4f3289 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/RemoveGroupAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/RemoveGroupAction.java @@ -19,18 +19,38 @@ */ package org.sonar.server.qualityprofile.ws; +import java.util.Arrays; +import org.sonar.api.resources.Language; +import org.sonar.api.resources.Languages; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.organization.OrganizationDto; +import org.sonar.db.qualityprofile.QProfileDto; +import org.sonar.db.user.GroupDto; -import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01; +import static org.sonar.core.util.stream.MoreCollectors.toSet; import static org.sonar.server.qualityprofile.ws.QProfileWsSupport.createOrganizationParam; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_REMOVE_GROUP; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_GROUP; -import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROFILE; +import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE; +import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_ORGANIZATION; +import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_QUALITY_PROFILE; public class RemoveGroupAction implements QProfileWsAction { + private final DbClient dbClient; + private final QProfileWsSupport wsSupport; + private final Languages languages; + + public RemoveGroupAction(DbClient dbClient, QProfileWsSupport wsSupport, Languages languages) { + this.dbClient = dbClient; + this.wsSupport = wsSupport; + this.languages = languages; + } + @Override public void define(WebService.NewController context) { WebService.NewAction action = context @@ -42,10 +62,16 @@ public class RemoveGroupAction implements QProfileWsAction { .setInternal(true) .setSince("6.6"); - action.createParam(PARAM_PROFILE) - .setDescription("Quality Profile key.") + action.createParam(PARAM_QUALITY_PROFILE) + .setDescription("Quality Profile name") .setRequired(true) - .setExampleValue(UUID_EXAMPLE_01); + .setExampleValue("Recommended quality profile"); + + action + .createParam(PARAM_LANGUAGE) + .setDescription("Quality profile language") + .setRequired(true) + .setPossibleValues(Arrays.stream(languages.all()).map(Language::getKey).collect(toSet())); action.createParam(PARAM_GROUP) .setDescription("Group name") @@ -57,6 +83,21 @@ public class RemoveGroupAction implements QProfileWsAction { @Override public void handle(Request request, Response response) throws Exception { - // TODO + try (DbSession dbSession = dbClient.openSession(false)) { + OrganizationDto organization = wsSupport.getOrganizationByKey(dbSession, request.param(PARAM_ORGANIZATION)); + QProfileDto profile = wsSupport.getProfile(dbSession, organization, request.mandatoryParam(PARAM_QUALITY_PROFILE), request.mandatoryParam(PARAM_LANGUAGE)); + wsSupport.checkCanEdit(dbSession, profile); + GroupDto group = wsSupport.getGroup(dbSession, organization, request.mandatoryParam(PARAM_GROUP)); + removeGroup(dbSession, profile, group); + } + response.noContent(); + } + + private void removeGroup(DbSession dbSession, QProfileDto profile, GroupDto group) { + if (!dbClient.qProfileEditGroupsDao().exists(dbSession, profile, group)) { + return; + } + dbClient.qProfileEditGroupsDao().deleteByQProfileAndGroup(dbSession, profile, group); + dbSession.commit(); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/RemoveGroupActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/RemoveGroupActionTest.java new file mode 100644 index 00000000000..7e1321cd38a --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/RemoveGroupActionTest.java @@ -0,0 +1,290 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.qualityprofile.ws; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.resources.Languages; +import org.sonar.api.server.ws.WebService; +import org.sonar.db.DbTester; +import org.sonar.db.organization.OrganizationDto; +import org.sonar.db.permission.OrganizationPermission; +import org.sonar.db.qualityprofile.QProfileDto; +import org.sonar.db.user.GroupDto; +import org.sonar.db.user.UserDto; +import org.sonar.server.exceptions.BadRequestException; +import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.exceptions.NotFoundException; +import org.sonar.server.language.LanguageTesting; +import org.sonar.server.organization.TestDefaultOrganizationProvider; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.TestResponse; +import org.sonar.server.ws.WsActionTester; + +import static java.lang.String.format; +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_GROUP; +import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE; +import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_ORGANIZATION; +import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_QUALITY_PROFILE; + +public class RemoveGroupActionTest { + + private static final String XOO = "xoo"; + private static final Languages LANGUAGES = LanguageTesting.newLanguages(XOO); + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + @Rule + public DbTester db = DbTester.create(); + + private QProfileWsSupport wsSupport = new QProfileWsSupport(db.getDbClient(), userSession, TestDefaultOrganizationProvider.from(db)); + + private WsActionTester ws = new WsActionTester(new RemoveGroupAction(db.getDbClient(), wsSupport, LANGUAGES)); + + @Test + public void test_definition() { + WebService.Action def = ws.getDef(); + assertThat(def.key()).isEqualTo("remove_group"); + assertThat(def.isPost()).isTrue(); + assertThat(def.isInternal()).isTrue(); + assertThat(def.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("organization", "qualityProfile", "language", "group"); + } + + @Test + public void remove_group() { + OrganizationDto organization = db.organizations().insert(); + QProfileDto profile = db.qualityProfiles().insert(organization, p -> p.setLanguage(XOO)); + GroupDto group = db.users().insertGroup(organization); + db.qualityProfiles().addGroupPermission(profile, group); + userSession.logIn().addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, organization); + + TestResponse response = ws.newRequest() + .setParam(PARAM_QUALITY_PROFILE, profile.getName()) + .setParam(PARAM_LANGUAGE, XOO) + .setParam(PARAM_GROUP, group.getName()) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .execute(); + + assertThat(response.getStatus()).isEqualTo(204); + assertThat(db.getDbClient().qProfileEditGroupsDao().exists(db.getSession(), profile, group)).isFalse(); + } + + @Test + public void does_nothing_when_group_cannot_edit_profile() { + OrganizationDto organization = db.organizations().insert(); + QProfileDto profile = db.qualityProfiles().insert(organization, p -> p.setLanguage(XOO)); + GroupDto group = db.users().insertGroup(organization); + assertThat(db.getDbClient().qProfileEditGroupsDao().exists(db.getSession(), profile, group)).isFalse(); + userSession.logIn().addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, organization); + + ws.newRequest() + .setParam(PARAM_QUALITY_PROFILE, profile.getName()) + .setParam(PARAM_LANGUAGE, XOO) + .setParam(PARAM_GROUP, group.getName()) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .execute(); + + assertThat(db.getDbClient().qProfileEditGroupsDao().exists(db.getSession(), profile, group)).isFalse(); + } + + @Test + public void qp_administers_can_remove_group() { + OrganizationDto organization = db.organizations().insert(); + QProfileDto profile = db.qualityProfiles().insert(organization, p -> p.setLanguage(XOO)); + GroupDto group = db.users().insertGroup(organization); + db.qualityProfiles().addGroupPermission(profile, group); + userSession.logIn().addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, organization); + + ws.newRequest() + .setParam(PARAM_QUALITY_PROFILE, profile.getName()) + .setParam(PARAM_LANGUAGE, XOO) + .setParam(PARAM_GROUP, group.getName()) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .execute(); + + assertThat(db.getDbClient().qProfileEditGroupsDao().exists(db.getSession(), profile, group)).isFalse(); + } + + @Test + public void qp_editors_can_remove_group() { + OrganizationDto organization = db.organizations().insert(); + QProfileDto profile = db.qualityProfiles().insert(organization, p -> p.setLanguage(XOO)); + GroupDto group = db.users().insertGroup(organization); + db.qualityProfiles().addGroupPermission(profile, group); + UserDto userAllowedToEditProfile = db.users().insertUser(); + db.qualityProfiles().addUserPermission(profile, userAllowedToEditProfile); + userSession.logIn(userAllowedToEditProfile); + + ws.newRequest() + .setParam(PARAM_QUALITY_PROFILE, profile.getName()) + .setParam(PARAM_LANGUAGE, XOO) + .setParam(PARAM_GROUP, group.getName()) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .execute(); + + assertThat(db.getDbClient().qProfileEditGroupsDao().exists(db.getSession(), profile, group)).isFalse(); + } + + @Test + public void uses_default_organization_when_no_organization() { + OrganizationDto organization = db.getDefaultOrganization(); + QProfileDto profile = db.qualityProfiles().insert(organization, p -> p.setLanguage(XOO)); + GroupDto group = db.users().insertGroup(organization); + db.qualityProfiles().addGroupPermission(profile, group); + userSession.logIn().addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, organization); + + ws.newRequest() + .setParam(PARAM_QUALITY_PROFILE, profile.getName()) + .setParam(PARAM_LANGUAGE, XOO) + .setParam(PARAM_GROUP, group.getName()) + .execute(); + + assertThat(db.getDbClient().qProfileEditGroupsDao().exists(db.getSession(), profile, group)).isFalse(); + } + + @Test + public void fail_when_group_does_not_exist() { + OrganizationDto organization = db.organizations().insert(); + QProfileDto profile = db.qualityProfiles().insert(organization, p -> p.setLanguage(XOO)); + userSession.logIn().addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, organization); + + expectedException.expect(NotFoundException.class); + expectedException.expectMessage(format("No group with name 'unknown' in organization '%s'", organization.getKey())); + + ws.newRequest() + .setParam(PARAM_QUALITY_PROFILE, profile.getName()) + .setParam(PARAM_LANGUAGE, XOO) + .setParam(PARAM_GROUP, "unknown") + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .execute(); + } + + @Test + public void fail_when_qprofile_does_not_exist() { + OrganizationDto organization = db.organizations().insert(); + GroupDto group = db.users().insertGroup(organization); + userSession.logIn().addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, organization); + + expectedException.expect(NotFoundException.class); + expectedException.expectMessage(format("Quality Profile for language 'xoo' and name 'unknown' does not exist in organization '%s'", organization.getKey())); + + ws.newRequest() + .setParam(PARAM_QUALITY_PROFILE, "unknown") + .setParam(PARAM_LANGUAGE, XOO) + .setParam(PARAM_GROUP, group.getName()) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .execute(); + } + + @Test + public void fail_when_qprofile_does_not_belong_to_organization() { + OrganizationDto organization = db.organizations().insert(); + GroupDto group = db.users().insertGroup(organization); + OrganizationDto anotherOrganization = db.organizations().insert(); + QProfileDto profile = db.qualityProfiles().insert(anotherOrganization, p -> p.setLanguage(XOO)); + userSession.logIn().addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, organization); + + expectedException.expect(NotFoundException.class); + expectedException.expectMessage(format("Quality Profile for language 'xoo' and name '%s' does not exist in organization '%s'", profile.getName(), organization.getKey())); + + ws.newRequest() + .setParam(PARAM_QUALITY_PROFILE, profile.getName()) + .setParam(PARAM_LANGUAGE, XOO) + .setParam(PARAM_GROUP, group.getName()) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .execute(); + } + + @Test + public void fail_when_wrong_language() { + OrganizationDto organization = db.organizations().insert(); + QProfileDto profile = db.qualityProfiles().insert(organization, p -> p.setLanguage("unknown")); + GroupDto group = db.users().insertGroup(organization); + userSession.logIn().addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, organization); + + expectedException.expect(NotFoundException.class); + expectedException.expectMessage(format("Quality Profile for language 'xoo' and name '%s' does not exist in organization '%s'", profile.getName(), organization.getKey())); + + ws.newRequest() + .setParam(PARAM_QUALITY_PROFILE, profile.getName()) + .setParam(PARAM_LANGUAGE, XOO) + .setParam(PARAM_GROUP, group.getName()) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .execute(); + } + + @Test + public void fail_when_group_does_not_belong_to_organization() { + OrganizationDto organization = db.organizations().insert(); + OrganizationDto anotherOrganization = db.organizations().insert(); + GroupDto group = db.users().insertGroup(anotherOrganization); + QProfileDto profile = db.qualityProfiles().insert(organization, p -> p.setLanguage(XOO)); + userSession.logIn().addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, organization); + + expectedException.expect(NotFoundException.class); + expectedException.expectMessage(format("No group with name '%s' in organization '%s'", group.getName(), organization.getKey())); + + ws.newRequest() + .setParam(PARAM_QUALITY_PROFILE, profile.getName()) + .setParam(PARAM_LANGUAGE, XOO) + .setParam(PARAM_GROUP, group.getName()) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .execute(); + } + + @Test + public void fail_when_qp_is_built_in() { + OrganizationDto organization = db.organizations().insert(); + GroupDto group = db.users().insertGroup(organization); + QProfileDto profile = db.qualityProfiles().insert(organization, p -> p.setLanguage(XOO).setIsBuiltIn(true)); + userSession.logIn().addPermission(OrganizationPermission.ADMINISTER_QUALITY_PROFILES, organization); + + expectedException.expect(BadRequestException.class); + expectedException.expectMessage(String.format("Operation forbidden for built-in Quality Profile '%s' with language 'xoo'", profile.getName())); + + ws.newRequest() + .setParam(PARAM_QUALITY_PROFILE, profile.getName()) + .setParam(PARAM_LANGUAGE, XOO) + .setParam(PARAM_GROUP, group.getName()) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .execute(); + } + + @Test + public void fail_when_not_enough_permission() { + OrganizationDto organization = db.organizations().insert(); + QProfileDto profile = db.qualityProfiles().insert(organization, p -> p.setLanguage(XOO)); + GroupDto group = db.users().insertGroup(organization); + userSession.logIn(db.users().insertUser()).addPermission(OrganizationPermission.ADMINISTER_QUALITY_GATES, organization); + + expectedException.expect(ForbiddenException.class); + + ws.newRequest() + .setParam(PARAM_QUALITY_PROFILE, profile.getName()) + .setParam(PARAM_LANGUAGE, XOO) + .setParam(PARAM_GROUP, group.getName()) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .execute(); + } +} |