diff options
author | belen-pruvost-sonarsource <belen.pruvost@sonarsource.com> | 2021-10-13 18:25:51 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2021-10-22 20:03:27 +0000 |
commit | 06672268a78369a8442e1d8f291b2d80c6d95f9a (patch) | |
tree | 9bbcee010a24b2294e07e4f4558905bc255d5bb5 /server/sonar-webserver-webapi | |
parent | 2d5130b8f3150af215721aa44d76fa97612874f1 (diff) | |
download | sonarqube-06672268a78369a8442e1d8f291b2d80c6d95f9a.tar.gz sonarqube-06672268a78369a8442e1d8f291b2d80c6d95f9a.zip |
SONAR-15441 - Create api/qualitygates/add_group endpoint
Diffstat (limited to 'server/sonar-webserver-webapi')
6 files changed, 298 insertions, 4 deletions
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/AddGroupAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/AddGroupAction.java new file mode 100644 index 00000000000..c3cfa0c7c6b --- /dev/null +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/AddGroupAction.java @@ -0,0 +1,112 @@ +/* + * SonarQube + * Copyright (C) 2009-2021 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.qualitygate.ws; + +import java.util.Optional; +import org.jetbrains.annotations.NotNull; +import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.Response; +import org.sonar.api.server.ws.WebService; +import org.sonar.core.util.UuidFactory; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.qualitygate.QualityGateDto; +import org.sonar.db.qualitygate.QualityGateGroupPermissionsDto; +import org.sonar.db.user.GroupDto; + +import static org.sonar.server.exceptions.NotFoundException.checkFoundWithOptional; +import static org.sonar.server.qualitygate.ws.CreateAction.NAME_MAXIMUM_LENGTH; +import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.ACTION_ADD_GROUP; +import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_GATE_NAME; +import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_GROUP_NAME; + +public class AddGroupAction implements QualityGatesWsAction { + private final DbClient dbClient; + private final UuidFactory uuidFactory; + private final QualityGatesWsSupport wsSupport; + + public AddGroupAction(DbClient dbClient, UuidFactory uuidFactory, QualityGatesWsSupport wsSupport) { + this.dbClient = dbClient; + this.uuidFactory = uuidFactory; + this.wsSupport = wsSupport; + } + + @Override + public void define(WebService.NewController context) { + WebService.NewAction action = context + .createAction(ACTION_ADD_GROUP) + .setDescription("Allow a group of users to edit a Quality Gate.<br>" + + "Requires one of the following permissions:" + + "<ul>" + + " <li>'Administer Quality Gates'</li>" + + " <li>Edit right on the specified quality gate</li>" + + "</ul>") + .setHandler(this) + .setPost(true) + .setInternal(true) + .setSince("9.2"); + + action.createParam(PARAM_GATE_NAME) + .setDescription("Quality Gate name") + .setRequired(true) + .setMaximumLength(NAME_MAXIMUM_LENGTH) + .setExampleValue("SonarSource Way"); + + action.createParam(PARAM_GROUP_NAME) + .setDescription("Group name or 'anyone' (case insensitive)") + .setRequired(true) + .setExampleValue("sonar-administrators"); + + } + + @Override + public void handle(Request request, Response response) throws Exception { + final String groupName = request.mandatoryParam(PARAM_GROUP_NAME); + final String qualityGateName = request.mandatoryParam(PARAM_GATE_NAME); + + try (DbSession dbSession = dbClient.openSession(false)) { + QualityGateDto qualityGateDto = wsSupport.getByName(dbSession, qualityGateName); + wsSupport.checkCanLimitedEdit(dbSession, qualityGateDto); + GroupDto group = getGroup(dbSession, groupName); + addGroup(dbSession, qualityGateDto, group); + } + response.noContent(); + } + + @NotNull + private GroupDto getGroup(DbSession dbSession, String groupName) { + Optional<GroupDto> group = dbClient.groupDao().selectByName(dbSession, groupName); + checkFoundWithOptional(group, "Group with name '%s' is not found", groupName); + return group.get(); + } + + private void addGroup(DbSession dbSession, QualityGateDto qualityGate, GroupDto group) { + if (dbClient.qualityGateGroupPermissionsDao().exists(dbSession, qualityGate, group)) { + return; + } + dbClient.qualityGateGroupPermissionsDao().insert(dbSession, + new QualityGateGroupPermissionsDto() + .setUuid(uuidFactory.create()) + .setGroupUuid(group.getUuid()) + .setQualityGateUuid(qualityGate.getUuid())); + dbSession.commit(); + } + +} diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGateWsModule.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGateWsModule.java index b453501cf57..b018c949ffb 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGateWsModule.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGateWsModule.java @@ -42,8 +42,8 @@ public class QualityGateWsModule extends Module { DeleteConditionAction.class, UpdateConditionAction.class, ProjectStatusAction.class, - GetByProjectAction.class - + GetByProjectAction.class, + AddGroupAction.class ); } } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsParameters.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsParameters.java index 960ec78b0fd..cc2e826581e 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsParameters.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsParameters.java @@ -29,6 +29,7 @@ public class QualityGatesWsParameters { public static final String ACTION_CREATE = "create"; public static final String ACTION_CREATE_CONDITION = "create_condition"; public static final String ACTION_UPDATE_CONDITION = "update_condition"; + public static final String ACTION_ADD_GROUP = "add_group"; public static final String ACTION_ADD_USER = "add_user"; public static final String PARAM_ANALYSIS_ID = "analysisId"; diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsSupport.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsSupport.java index c3daf8d406d..a958f63c638 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsSupport.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsSupport.java @@ -88,11 +88,17 @@ public class QualityGatesWsSupport { void checkCanLimitedEdit(DbSession dbSession, QualityGateDto qualityGate) { checkNotBuiltIn(qualityGate); - if (!userSession.hasPermission(ADMINISTER_QUALITY_GATES) && !userHasPermission(dbSession, qualityGate)) { + if (!userSession.hasPermission(ADMINISTER_QUALITY_GATES) + && !userHasPermission(dbSession, qualityGate) + && !userHasGroupPermission(dbSession, qualityGate)) { throw insufficientPrivilegesException(); } } + boolean userHasGroupPermission(DbSession dbSession, QualityGateDto qualityGate) { + return userSession.isLoggedIn() && dbClient.qualityGateGroupPermissionsDao().exists(dbSession, qualityGate, userSession.getGroups()); + } + boolean userHasPermission(DbSession dbSession, QualityGateDto qualityGate) { return userSession.isLoggedIn() && dbClient.qualityGateUserPermissionDao().exists(dbSession, qualityGate.getUuid(), userSession.getUuid()); } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/AddGroupActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/AddGroupActionTest.java new file mode 100644 index 00000000000..4b871cc4f2d --- /dev/null +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/AddGroupActionTest.java @@ -0,0 +1,175 @@ +/* + * SonarQube + * Copyright (C) 2009-2021 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.qualitygate.ws; + +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.sonar.api.server.ws.WebService; +import org.sonar.api.utils.System2; +import org.sonar.core.util.UuidFactory; +import org.sonar.core.util.UuidFactoryFast; +import org.sonar.db.DbClient; +import org.sonar.db.DbTester; +import org.sonar.db.permission.GlobalPermission; +import org.sonar.db.qualitygate.QualityGateDto; +import org.sonar.db.user.GroupDto; +import org.sonar.db.user.UserDto; +import org.sonar.server.component.TestComponentFinder; +import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.exceptions.NotFoundException; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.TestRequest; +import org.sonar.server.ws.TestResponse; +import org.sonar.server.ws.WsActionTester; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_GATE_NAME; +import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_GROUP_NAME; + +@RunWith(DataProviderRunner.class) +public class AddGroupActionTest { + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + @Rule + public DbTester db = DbTester.create(System2.INSTANCE); + + private final DbClient dbClient = db.getDbClient(); + private final QualityGatesWsSupport wsSupport = new QualityGatesWsSupport(dbClient, userSession, TestComponentFinder.from(db)); + private final UuidFactory uuidFactory = UuidFactoryFast.getInstance(); + private final WsActionTester ws = new WsActionTester(new AddGroupAction(dbClient, uuidFactory, wsSupport)); + + @Test + public void test_definition() { + WebService.Action def = ws.getDef(); + assertThat(def.key()).isEqualTo("add_group"); + assertThat(def.isPost()).isTrue(); + assertThat(def.isInternal()).isTrue(); + assertThat(def.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("groupName", "gateName"); + } + + @Test + public void add_group() { + QualityGateDto qualityGateDto = db.qualityGates().insertQualityGate(); + GroupDto group = db.users().insertDefaultGroup(); + userSession.logIn().addPermission(GlobalPermission.ADMINISTER_QUALITY_GATES); + + TestResponse response = ws.newRequest() + .setParam(PARAM_GATE_NAME, qualityGateDto.getName()) + .setParam(PARAM_GROUP_NAME, group.getName()) + .execute(); + + assertThat(response.getStatus()).isEqualTo(204); + assertThat(dbClient.qualityGateGroupPermissionsDao().exists(db.getSession(), qualityGateDto, group)).isTrue(); + } + + @Test + public void does_nothing_when_group_can_already_edit_qualityGateDto() { + QualityGateDto qualityGateDto = db.qualityGates().insertQualityGate(); + GroupDto group = db.users().insertDefaultGroup(); + + db.qualityGates().addGroupPermission(qualityGateDto, group); + assertThat(dbClient.qualityGateGroupPermissionsDao().exists(db.getSession(), qualityGateDto, group)).isTrue(); + userSession.logIn().addPermission(GlobalPermission.ADMINISTER_QUALITY_GATES); + + ws.newRequest() + .setParam(PARAM_GATE_NAME, qualityGateDto.getName()) + .setParam(PARAM_GROUP_NAME, group.getName()) + .execute(); + + assertThat(dbClient.qualityGateGroupPermissionsDao().exists(db.getSession(), qualityGateDto, group)).isTrue(); + } + + @Test + public void quality_gate_administers_can_add_group() { + QualityGateDto qualityGateDto = db.qualityGates().insertQualityGate(); + GroupDto group = db.users().insertDefaultGroup(); + userSession.logIn().addPermission(GlobalPermission.ADMINISTER_QUALITY_GATES); + + ws.newRequest() + .setParam(PARAM_GATE_NAME, qualityGateDto.getName()) + .setParam(PARAM_GROUP_NAME, group.getName()) + .execute(); + + assertThat(dbClient.qualityGateGroupPermissionsDao().exists(db.getSession(), qualityGateDto, group)).isTrue(); + } + + @Test + public void quality_gate_editors_can_add_group() { + QualityGateDto qualityGateDto = db.qualityGates().insertQualityGate(); + + GroupDto originalGroup = db.users().insertDefaultGroup(); + UserDto userAllowedToEditQualityGate = db.users().insertUser(); + db.users().insertMember(originalGroup, userAllowedToEditQualityGate); + + db.qualityGates().addGroupPermission(qualityGateDto, originalGroup); + userSession.logIn(userAllowedToEditQualityGate).setGroups(originalGroup); + GroupDto newGroup = db.users().insertGroup(); + + ws.newRequest() + .setParam(PARAM_GATE_NAME, qualityGateDto.getName()) + .setParam(PARAM_GROUP_NAME, newGroup.getName()) + .execute(); + + assertThat(dbClient.qualityGateGroupPermissionsDao().exists(db.getSession(), qualityGateDto, originalGroup)).isTrue(); + } + + @Test + public void fail_when_group_does_not_exist() { + QualityGateDto qualityGateDto = db.qualityGates().insertQualityGate(); + userSession.logIn().addPermission(GlobalPermission.ADMINISTER_QUALITY_GATES); + + TestRequest request = ws.newRequest() + .setParam(PARAM_GATE_NAME, qualityGateDto.getName()) + .setParam(PARAM_GROUP_NAME, "unknown"); + + assertThatThrownBy(() -> request.execute()) + .isInstanceOf(NotFoundException.class) + .hasMessage("Group with name 'unknown' is not found"); + } + + @Test + public void fail_when_qualityGateDto_does_not_exist() { + GroupDto group = db.users().insertDefaultGroup(); + userSession.logIn().addPermission(GlobalPermission.ADMINISTER_QUALITY_GATES); + + TestRequest request = ws.newRequest() + .setParam(PARAM_GATE_NAME, "unknown") + .setParam(PARAM_GROUP_NAME, group.getName()); + + assertThatThrownBy(() -> request.execute()) + .isInstanceOf(NotFoundException.class) + .hasMessage("No quality gate has been found for name unknown"); + } + + @Test + public void fail_when_not_enough_permission() { + QualityGateDto qualityGateDto = db.qualityGates().insertQualityGate(); + GroupDto group = db.users().insertDefaultGroup(); + + TestRequest request = ws.newRequest() + .setParam(PARAM_GATE_NAME, qualityGateDto.getName()) + .setParam(PARAM_GROUP_NAME, group.getName()); + + assertThatThrownBy(() -> request.execute()).isInstanceOf(ForbiddenException.class); + } +} diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/QualityGateWsModuleTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/QualityGateWsModuleTest.java index dc59e33e600..d7b30969647 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/QualityGateWsModuleTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/QualityGateWsModuleTest.java @@ -30,7 +30,7 @@ public class QualityGateWsModuleTest { public void verify_count_of_added_components() { ComponentContainer container = new ComponentContainer(); new QualityGateWsModule().configure(container); - assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 18); + assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 19); } } |