From: Zipeng WU Date: Mon, 11 Oct 2021 15:54:08 +0000 (+0200) Subject: SONAR-15500 Create api/qualitygates/add_user service X-Git-Tag: 9.2.0.49834~129 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=2d5130b8f3150af215721aa44d76fa97612874f1;p=sonarqube.git SONAR-15500 Create api/qualitygates/add_user service --- diff --git a/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java b/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java index 5d2b3174ddb..1feb4af67ad 100644 --- a/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java +++ b/server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java @@ -87,6 +87,7 @@ public final class SqTables { "qprofile_edit_groups", "qprofile_edit_users", "quality_gates", + "qgate_user_permissions", "qgate_group_permissions", "quality_gate_conditions", "saml_message_ids", diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java b/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java index f288a33053d..2212356d10d 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java @@ -67,6 +67,7 @@ import org.sonar.db.purge.PurgeDao; import org.sonar.db.qualitygate.ProjectQgateAssociationDao; import org.sonar.db.qualitygate.QualityGateConditionDao; import org.sonar.db.qualitygate.QualityGateDao; +import org.sonar.db.qualitygate.QualityGateUserPermissionsDao; import org.sonar.db.qualityprofile.ActiveRuleDao; import org.sonar.db.qualityprofile.DefaultQProfileDao; import org.sonar.db.qualityprofile.QProfileChangeDao; @@ -146,6 +147,7 @@ public class DaoModule extends Module { QProfileEditUsersDao.class, QualityGateConditionDao.class, QualityGateDao.class, + QualityGateUserPermissionsDao.class, QualityProfileDao.class, QualityProfileExportDao.class, RoleDao.class, diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java b/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java index 3efb4aee142..2eb29ee9eb0 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java @@ -65,6 +65,7 @@ import org.sonar.db.purge.PurgeDao; import org.sonar.db.qualitygate.ProjectQgateAssociationDao; import org.sonar.db.qualitygate.QualityGateConditionDao; import org.sonar.db.qualitygate.QualityGateDao; +import org.sonar.db.qualitygate.QualityGateUserPermissionsDao; import org.sonar.db.qualityprofile.ActiveRuleDao; import org.sonar.db.qualityprofile.DefaultQProfileDao; import org.sonar.db.qualityprofile.QProfileChangeDao; @@ -134,6 +135,7 @@ public class DbClient { private final PurgeDao purgeDao; private final QualityGateDao qualityGateDao; private final QualityGateConditionDao gateConditionDao; + private final QualityGateUserPermissionsDao qualityGateUserPermissionsDao; private final ProjectQgateAssociationDao projectQgateAssociationDao; private final DuplicationDao duplicationDao; private final NotificationQueueDao notificationQueueDao; @@ -209,6 +211,7 @@ public class DbClient { eventComponentChangeDao = getDao(map, EventComponentChangeDao.class); purgeDao = getDao(map, PurgeDao.class); qualityGateDao = getDao(map, QualityGateDao.class); + qualityGateUserPermissionsDao = getDao(map, QualityGateUserPermissionsDao.class); gateConditionDao = getDao(map, QualityGateConditionDao.class); projectQgateAssociationDao = getDao(map, ProjectQgateAssociationDao.class); duplicationDao = getDao(map, DuplicationDao.class); @@ -417,6 +420,10 @@ public class DbClient { return gateConditionDao; } + public QualityGateUserPermissionsDao qualityGateUserPermissionDao() { + return qualityGateUserPermissionsDao; + } + public ProjectQgateAssociationDao projectQgateAssociationDao() { return projectQgateAssociationDao; } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java b/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java index 5d25b239f8f..03b4dd33ab3 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java @@ -115,6 +115,7 @@ import org.sonar.db.qualitygate.ProjectQgateAssociationMapper; import org.sonar.db.qualitygate.QualityGateConditionDto; import org.sonar.db.qualitygate.QualityGateConditionMapper; import org.sonar.db.qualitygate.QualityGateDto; +import org.sonar.db.qualitygate.QualityGateUserPermissionsMapper; import org.sonar.db.qualitygate.QualityGateMapper; import org.sonar.db.qualityprofile.ActiveRuleDto; import org.sonar.db.qualityprofile.ActiveRuleMapper; @@ -278,6 +279,7 @@ public class MyBatis implements Startable { QProfileEditUsersMapper.class, QualityGateConditionMapper.class, QualityGateMapper.class, + QualityGateUserPermissionsMapper.class, QualityProfileMapper.class, QualityProfileExportMapper.class, RoleMapper.class, diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/QualityGateUserPermissionsDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/QualityGateUserPermissionsDao.java new file mode 100644 index 00000000000..e79dc9ecfde --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/QualityGateUserPermissionsDao.java @@ -0,0 +1,58 @@ +/* + * 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.db.qualitygate; + +import javax.annotation.Nullable; +import org.sonar.api.utils.System2; +import org.sonar.db.Dao; +import org.sonar.db.DbSession; +import org.sonar.db.user.UserDto; + +public class QualityGateUserPermissionsDao implements Dao { + + private final System2 system2; + + public QualityGateUserPermissionsDao(System2 system2) { + this.system2 = system2; + } + + public boolean exists(DbSession dbSession, QualityGateDto qualityGate, UserDto user) { + return this.exists(dbSession, qualityGate.getUuid(), user.getUuid()); + } + + public boolean exists(DbSession dbSession, @Nullable String qualityGateUuid, @Nullable String userUuid) { + if (qualityGateUuid == null || userUuid == null) { + return false; + } + return selectByQualityGateAndUser(dbSession, qualityGateUuid, userUuid) != null; + } + + public QualityGateUserPermissionsDto selectByQualityGateAndUser(DbSession dbSession, String qualityGateUuid, String userUuid) { + return mapper(dbSession).selectByQualityGateAndUser(qualityGateUuid, userUuid); + } + + public void insert(DbSession dbSession, QualityGateUserPermissionsDto dto) { + mapper(dbSession).insert(dto, system2.now()); + } + + private static QualityGateUserPermissionsMapper mapper(DbSession dbSession) { + return dbSession.getMapper(QualityGateUserPermissionsMapper.class); + } +} diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/QualityGateUserPermissionsDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/QualityGateUserPermissionsDto.java new file mode 100644 index 00000000000..5d0dcc1a995 --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/QualityGateUserPermissionsDto.java @@ -0,0 +1,64 @@ +/* + * 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.db.qualitygate; + +public class QualityGateUserPermissionsDto { + + private String uuid; + private String userUuid; + private String qualityGateUuid; + + public QualityGateUserPermissionsDto() { + } + + public QualityGateUserPermissionsDto(String uuid, String userUuid, String qualityGateUuid) { + this.uuid = uuid; + this.userUuid = userUuid; + this.qualityGateUuid = qualityGateUuid; + } + + public String getUuid() { + return uuid; + } + + public QualityGateUserPermissionsDto setUuid(String uuid) { + this.uuid = uuid; + return this; + } + + public String getUserUuid() { + return userUuid; + } + + public QualityGateUserPermissionsDto setUserUuid(String userUuid) { + this.userUuid = userUuid; + return this; + } + + public String getQualityGateUuid() { + return qualityGateUuid; + } + + public QualityGateUserPermissionsDto setQualityGateUuid(String qProfileUuid) { + this.qualityGateUuid = qProfileUuid; + return this; + } + +} diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/QualityGateUserPermissionsMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/QualityGateUserPermissionsMapper.java new file mode 100644 index 00000000000..b67289f69dc --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/QualityGateUserPermissionsMapper.java @@ -0,0 +1,30 @@ +/* + * 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.db.qualitygate; + +import org.apache.ibatis.annotations.Param; + +public interface QualityGateUserPermissionsMapper { + + QualityGateUserPermissionsDto selectByQualityGateAndUser(@Param("qualityGateUuid") String qualityGateUuid, @Param("userUuid") String userUuid); + + void insert(@Param("dto") QualityGateUserPermissionsDto dto, @Param("now") long now); + +} diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/qualitygate/QualityGateUserPermissionsMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/qualitygate/QualityGateUserPermissionsMapper.xml new file mode 100644 index 00000000000..411e29b1904 --- /dev/null +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/qualitygate/QualityGateUserPermissionsMapper.xml @@ -0,0 +1,37 @@ + + + + + + + qup.uuid as "uuid", + qup.user_uuid as "userUuid", + qup.quality_gate_uuid as "qualityGateUuid" + + + + + + insert into qgate_user_permissions( + uuid, + user_uuid, + quality_gate_uuid, + created_at + ) values ( + #{dto.uuid, jdbcType=VARCHAR}, + #{dto.userUuid, jdbcType=VARCHAR}, + #{dto.qualityGateUuid, jdbcType=VARCHAR}, + #{now, jdbcType=BIGINT} + ) + + + + + diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/QualityGateUserPermissionsDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/QualityGateUserPermissionsDaoTest.java new file mode 100644 index 00000000000..1ce212780c9 --- /dev/null +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/QualityGateUserPermissionsDaoTest.java @@ -0,0 +1,67 @@ +/* + * 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.db.qualitygate; + +import org.junit.Rule; +import org.junit.Test; +import org.sonar.api.utils.System2; +import org.sonar.db.DbSession; +import org.sonar.db.DbTester; +import org.sonar.db.user.UserDbTester; +import org.sonar.db.user.UserDto; + +import static org.assertj.core.api.Assertions.assertThat; + +public class QualityGateUserPermissionsDaoTest { + @Rule + public final DbTester db = DbTester.create(System2.INSTANCE); + + private final DbSession dbSession = db.getSession(); + private final UserDbTester userDbTester = new UserDbTester(db); + private final QualityGateDbTester qualityGateDbTester = new QualityGateDbTester(db); + private final QualityGateUserPermissionsDao underTest = db.getDbClient().qualityGateUserPermissionDao(); + + @Test + public void insert() { + UserDto user = userDbTester.insertUser(); + QualityGateDto qualityGate = qualityGateDbTester.insertQualityGate(); + QualityGateUserPermissionsDto qualityGateUserPermissions = new QualityGateUserPermissionsDto("uuid", user.getUuid(), qualityGate.getUuid()); + underTest.insert(dbSession, qualityGateUserPermissions); + dbSession.commit(); + + QualityGateUserPermissionsDto fromDB = underTest.selectByQualityGateAndUser(dbSession, qualityGate.getUuid(), user.getUuid()); + assertThat(fromDB.getQualityGateUuid()).isEqualTo(qualityGate.getUuid()); + assertThat(fromDB.getUserUuid()).isEqualTo(user.getUuid()); + assertThat(fromDB.getUuid()).isEqualTo("uuid"); + } + + @Test + public void exist() { + UserDto user = userDbTester.insertUser(); + QualityGateDto qualityGate = qualityGateDbTester.insertQualityGate(); + QualityGateUserPermissionsDto qualityGateUserPermissions = new QualityGateUserPermissionsDto("uuid", user.getUuid(), qualityGate.getUuid()); + underTest.insert(dbSession, qualityGateUserPermissions); + dbSession.commit(); + + assertThat(underTest.exists(dbSession, qualityGate.getUuid(), user.getUuid())).isTrue(); + assertThat(underTest.exists(dbSession, qualityGate, user)).isTrue(); + } + +} \ No newline at end of file diff --git a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/qualitygate/QualityGateDbTester.java b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/qualitygate/QualityGateDbTester.java index e6da05b13dd..6dbbe27587e 100644 --- a/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/qualitygate/QualityGateDbTester.java +++ b/server/sonar-db-dao/src/testFixtures/java/org/sonar/db/qualitygate/QualityGateDbTester.java @@ -30,6 +30,7 @@ import org.sonar.db.DbTester; import org.sonar.db.metric.MetricDto; import org.sonar.db.project.ProjectDto; import org.sonar.db.property.PropertyDto; +import org.sonar.db.user.UserDto; import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; import static org.apache.commons.lang.RandomStringUtils.randomNumeric; @@ -102,4 +103,13 @@ public class QualityGateDbTester { public Optional selectQGateUuidByComponentUuid(String componentUuid) { return dbClient.projectQgateAssociationDao().selectQGateUuidByProjectUuid(dbSession, componentUuid); } + + public void addUserPermission(QualityGateDto qualityGateDto, UserDto user) { + dbClient.qualityGateUserPermissionDao().insert(dbSession, new QualityGateUserPermissionsDto() + .setUuid(Uuids.createFast()) + .setUserUuid(user.getUuid()) + .setQualityGateUuid(qualityGateDto.getUuid()) + ); + dbSession.commit(); + } } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/AddUserAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/AddUserAction.java new file mode 100644 index 00000000000..c71e858085d --- /dev/null +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/AddUserAction.java @@ -0,0 +1,110 @@ +/* + * 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 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.QualityGateUserPermissionsDto; +import org.sonar.db.user.UserDto; + +import static org.sonar.server.exceptions.NotFoundException.checkFound; +import static org.sonar.server.qualitygate.ws.CreateAction.NAME_MAXIMUM_LENGTH; +import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.ACTION_ADD_USER; +import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_GATE_NAME; +import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_LOGIN; + +public class AddUserAction implements QualityGatesWsAction { + + private final DbClient dbClient; + private final UuidFactory uuidFactory; + private final QualityGatesWsSupport wsSupport; + + public AddUserAction(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_USER) + .setDescription("Allow a user to edit a Quality Gate.
" + + "Requires one of the following permissions:" + + "") + .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_LOGIN) + .setDescription("User login") + .setRequired(true) + .setExampleValue("john.doe"); + + } + + @Override + public void handle(Request request, Response response) throws Exception { + final String login = request.mandatoryParam(PARAM_LOGIN); + final String qualityGateName = request.mandatoryParam(PARAM_GATE_NAME); + + try (DbSession dbSession = dbClient.openSession(false)) { + QualityGateDto qualityGateDto = wsSupport.getByName(dbSession, qualityGateName); + wsSupport.checkCanLimitedEdit(dbSession, qualityGateDto); + UserDto user = getUser(dbSession, login); + addUser(dbSession, qualityGateDto, user); + } + response.noContent(); + } + + private UserDto getUser(DbSession dbSession, String login) { + UserDto user = dbClient.userDao().selectByLogin(dbSession, login); + checkFound(user, "User with login '%s' is not found", login); + return user; + } + + private void addUser(DbSession dbSession, QualityGateDto qualityGate, UserDto user) { + if (dbClient.qualityGateUserPermissionDao().exists(dbSession, qualityGate, user)) { + return; + } + dbClient.qualityGateUserPermissionDao().insert(dbSession, + new QualityGateUserPermissionsDto() + .setUuid(uuidFactory.create()) + .setUserUuid(user.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 c323de119be..b453501cf57 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 @@ -25,6 +25,7 @@ public class QualityGateWsModule extends Module { @Override protected void configureModule() { add( + AddUserAction.class, QualityGatesWsSupport.class, QualityGatesWs.class, ListAction.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 77a15c49831..960ec78b0fd 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_USER = "add_user"; public static final String PARAM_ANALYSIS_ID = "analysisId"; public static final String PARAM_BRANCH = "branch"; 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 c48519d4315..c3daf8d406d 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 @@ -86,6 +86,18 @@ public class QualityGatesWsSupport { userSession.checkPermission(ADMINISTER_QUALITY_GATES); } + void checkCanLimitedEdit(DbSession dbSession, QualityGateDto qualityGate) { + checkNotBuiltIn(qualityGate); + if (!userSession.hasPermission(ADMINISTER_QUALITY_GATES) && !userHasPermission(dbSession, qualityGate)) { + throw insufficientPrivilegesException(); + } + } + + boolean userHasPermission(DbSession dbSession, QualityGateDto qualityGate) { + return userSession.isLoggedIn() && dbClient.qualityGateUserPermissionDao().exists(dbSession, qualityGate.getUuid(), userSession.getUuid()); + } + + void checkCanAdminProject(ProjectDto project) { if (userSession.hasPermission(ADMINISTER_QUALITY_GATES) || userSession.hasProjectPermission(ADMIN, project)) { diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/AddUserActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/AddUserActionTest.java new file mode 100644 index 00000000000..b2fea3ffa02 --- /dev/null +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/AddUserActionTest.java @@ -0,0 +1,167 @@ +/* + * 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 org.junit.Rule; +import org.junit.Test; +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.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.user.UsersWsParameters.PARAM_LOGIN; + +public class AddUserActionTest { + @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 AddUserAction(dbClient, uuidFactory, wsSupport)); + + @Test + public void test_definition() { + WebService.Action def = ws.getDef(); + assertThat(def.key()).isEqualTo("add_user"); + assertThat(def.isPost()).isTrue(); + assertThat(def.isInternal()).isTrue(); + assertThat(def.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("login", "gateName"); + } + + @Test + public void add_user() { + QualityGateDto qualityGateDto = db.qualityGates().insertQualityGate(); + UserDto user = db.users().insertUser(); + userSession.logIn().addPermission(GlobalPermission.ADMINISTER_QUALITY_GATES); + + TestResponse response = ws.newRequest() + .setParam(PARAM_GATE_NAME, qualityGateDto.getName()) + .setParam(PARAM_LOGIN, user.getLogin()) + .execute(); + + assertThat(response.getStatus()).isEqualTo(204); + assertThat(dbClient.qualityGateUserPermissionDao().exists(db.getSession(), qualityGateDto, user)).isTrue(); + } + + @Test + public void does_nothing_when_user_can_already_edit_qualityGateDto() { + QualityGateDto qualityGateDto = db.qualityGates().insertQualityGate(); + UserDto user = db.users().insertUser(); + db.qualityGates().addUserPermission(qualityGateDto, user); + assertThat(dbClient.qualityGateUserPermissionDao().exists(db.getSession(), qualityGateDto, user)).isTrue(); + userSession.logIn().addPermission(GlobalPermission.ADMINISTER_QUALITY_GATES); + + ws.newRequest() + .setParam(PARAM_GATE_NAME, qualityGateDto.getName()) + .setParam(PARAM_LOGIN, user.getLogin()) + .execute(); + + assertThat(dbClient.qualityGateUserPermissionDao().exists(db.getSession(), qualityGateDto, user)).isTrue(); + } + + @Test + public void quality_gate_administers_can_add_user() { + QualityGateDto qualityGateDto = db.qualityGates().insertQualityGate(); + UserDto user = db.users().insertUser(); + userSession.logIn().addPermission(GlobalPermission.ADMINISTER_QUALITY_GATES); + + ws.newRequest() + .setParam(PARAM_GATE_NAME, qualityGateDto.getName()) + .setParam(PARAM_LOGIN, user.getLogin()) + .execute(); + + assertThat(dbClient.qualityGateUserPermissionDao().exists(db.getSession(), qualityGateDto, user)).isTrue(); + } + + @Test + public void quality_gate_editors_can_add_user() { + QualityGateDto qualityGateDto = db.qualityGates().insertQualityGate(); + UserDto user = db.users().insertUser(); + UserDto userAllowedToEditQualityGate = db.users().insertUser(); + db.qualityGates().addUserPermission(qualityGateDto, userAllowedToEditQualityGate); + userSession.logIn(userAllowedToEditQualityGate); + + ws.newRequest() + .setParam(PARAM_GATE_NAME, qualityGateDto.getName()) + .setParam(PARAM_LOGIN, user.getLogin()) + .execute(); + + assertThat(dbClient.qualityGateUserPermissionDao().exists(db.getSession(), qualityGateDto, user)).isTrue(); + } + + @Test + public void fail_when_user_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_LOGIN, "unknown"); + + assertThatThrownBy(() -> request.execute()) + .isInstanceOf(NotFoundException.class) + .hasMessage("User with login 'unknown' is not found"); + + } + + @Test + public void fail_when_qualityGateDto_does_not_exist() { + UserDto user = db.users().insertUser(); + userSession.logIn().addPermission(GlobalPermission.ADMINISTER_QUALITY_GATES); + + TestRequest request = ws.newRequest() + .setParam(PARAM_GATE_NAME, "unknown") + .setParam(PARAM_LOGIN, user.getLogin()); + + 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(); + UserDto user = db.users().insertUser(); + + TestRequest request = ws.newRequest() + .setParam(PARAM_GATE_NAME, qualityGateDto.getName()) + .setParam(PARAM_LOGIN, user.getLogin()); + + assertThatThrownBy(() -> request.execute()).isInstanceOf(ForbiddenException.class); + } +} \ No newline at end of file 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 073a71ca5a2..dc59e33e600 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 + 17); + assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 18); } }