package org.sonar.db.qualitygate;
import java.util.Collection;
+import java.util.List;
import org.sonar.api.utils.System2;
import org.sonar.db.Dao;
import org.sonar.db.DbSession;
+import org.sonar.db.Pagination;
import org.sonar.db.user.GroupDto;
+import org.sonar.db.user.SearchGroupMembershipDto;
+import org.sonar.db.user.SearchGroupsQuery;
import static org.sonar.core.util.stream.MoreCollectors.toList;
import static org.sonar.db.DatabaseUtils.executeLargeInputs;
private static QualityGateGroupPermissionsMapper mapper(DbSession dbSession) {
return dbSession.getMapper(QualityGateGroupPermissionsMapper.class);
}
+
+ public List<SearchGroupMembershipDto> selectByQuery(DbSession dbSession, SearchGroupsQuery query, Pagination pagination) {
+ return mapper(dbSession).selectByQuery(query, pagination);
+ }
+
+ public int countByQuery(DbSession dbSession, SearchGroupsQuery query) {
+ return mapper(dbSession).countByQuery(query);
+ }
}
import java.util.List;
import org.apache.ibatis.annotations.Param;
+import org.sonar.db.Pagination;
+import org.sonar.db.user.SearchGroupMembershipDto;
+import org.sonar.db.user.SearchGroupsQuery;
public interface QualityGateGroupPermissionsMapper {
List<QualityGateGroupPermissionsDto> selectByQualityGateAndGroups(@Param("qualityGateUuid") String qualityGateUuid, @Param("groupUuids") List<String> groupUuids);
void insert(@Param("dto") QualityGateGroupPermissionsDto dto, @Param("now") long now);
+
+ List<SearchGroupMembershipDto> selectByQuery(@Param("query") SearchGroupsQuery query, @Param("pagination") Pagination pagination);
+
+ int countByQuery(@Param("query") SearchGroupsQuery query);
}
--- /dev/null
+/*
+ * 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 java.util.Locale;
+import org.sonar.db.user.SearchGroupsQuery;
+
+import static org.sonar.db.DaoUtils.buildLikeValue;
+import static org.sonar.db.WildcardPosition.BEFORE_AND_AFTER;
+
+public class SearchQualityGateGroupsQuery extends SearchGroupsQuery {
+
+ private final String qualityGateUuid;
+
+ public SearchQualityGateGroupsQuery(Builder builder) {
+ this.qualityGateUuid = builder.qualityGate.getUuid();
+ this.query = builder.getQuery();
+ this.membership = builder.getMembership();
+ this.querySqlLowercase = query == null ? null : buildLikeValue(query, BEFORE_AND_AFTER).toLowerCase(Locale.ENGLISH);
+ }
+
+ public String getQualityGateUuid() {
+ return qualityGateUuid;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder extends SearchGroupsQuery.Builder<Builder> {
+ private QualityGateDto qualityGate;
+
+ public Builder setQualityGate(QualityGateDto qualityGate) {
+ this.qualityGate = qualityGate;
+ return this;
+ }
+
+ public SearchQualityGateGroupsQuery build() {
+ initMembership();
+ return new SearchQualityGateGroupsQuery(this);
+ }
+ }
+}
+++ /dev/null
-/*
- * 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.qualityprofile;
-
-public class GroupMembershipDto {
-
- private String groupUuid;
- // Set by MyBatis
- private String uuid;
-
- public String getGroupUuid() {
- return groupUuid;
- }
-
- public GroupMembershipDto setGroupUuid(String groupUuid) {
- this.groupUuid = groupUuid;
- return this;
- }
-
- public boolean isSelected() {
- return uuid != null;
- }
-
-}
import org.sonar.db.DbSession;
import org.sonar.db.Pagination;
import org.sonar.db.user.GroupDto;
+import org.sonar.db.user.SearchGroupMembershipDto;
import static org.sonar.core.util.stream.MoreCollectors.toList;
import static org.sonar.db.DatabaseUtils.executeLargeInputs;
.isEmpty();
}
- public int countByQuery(DbSession dbSession, SearchGroupsQuery query) {
+ public int countByQuery(DbSession dbSession, SearchQualityProfileGroupsQuery query) {
return mapper(dbSession).countByQuery(query);
}
- public List<GroupMembershipDto> selectByQuery(DbSession dbSession, SearchGroupsQuery query, Pagination pagination) {
+ public List<SearchGroupMembershipDto> selectByQuery(DbSession dbSession, SearchQualityProfileGroupsQuery query, Pagination pagination) {
return mapper(dbSession).selectByQuery(query, pagination);
}
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.sonar.db.Pagination;
+import org.sonar.db.user.SearchGroupMembershipDto;
public interface QProfileEditGroupsMapper {
List<QProfileEditGroupsDto> selectByQProfileAndGroups(@Param("qProfileUuid") String qProfileUuid, @Param("groupUuids") List<String> groupUuids);
- int countByQuery(@Param("query") SearchGroupsQuery query);
+ int countByQuery(@Param("query") SearchQualityProfileGroupsQuery query);
- List<GroupMembershipDto> selectByQuery(@Param("query") SearchGroupsQuery query, @Param("pagination") Pagination pagination);
+ List<SearchGroupMembershipDto> selectByQuery(@Param("query") SearchQualityProfileGroupsQuery query, @Param("pagination") Pagination pagination);
List<String> selectQProfileUuidsByGroups(@Param("groupUuids") List<String> groupUuids);
+++ /dev/null
-/*
- * 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.qualityprofile;
-
-import com.google.common.collect.ImmutableSet;
-import java.util.Locale;
-import java.util.Set;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.apache.commons.lang.StringUtils;
-
-import static com.google.common.base.MoreObjects.firstNonNull;
-import static com.google.common.base.Preconditions.checkArgument;
-import static org.sonar.db.DaoUtils.buildLikeValue;
-import static org.sonar.db.WildcardPosition.BEFORE_AND_AFTER;
-
-public class SearchGroupsQuery {
-
- public static final String ANY = "ANY";
- public static final String IN = "IN";
- public static final String OUT = "OUT";
- public static final Set<String> AVAILABLE_MEMBERSHIPS = ImmutableSet.of(ANY, IN, OUT);
-
- private final String qProfileUuid;
- private final String query;
- private final String membership;
-
- // for internal use in MyBatis
- final String querySqlLowercase;
-
- private SearchGroupsQuery(Builder builder) {
- this.qProfileUuid = builder.profile.getKee();
- this.query = builder.query;
- this.membership = builder.membership;
- this.querySqlLowercase = query == null ? null : buildLikeValue(query, BEFORE_AND_AFTER).toLowerCase(Locale.ENGLISH);
- }
-
- public String getQProfileUuid() {
- return qProfileUuid;
- }
-
- public String getMembership() {
- return membership;
- }
-
- @CheckForNull
- public String getQuery() {
- return query;
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static class Builder {
- private QProfileDto profile;
- private String query;
- private String membership;
-
- private Builder() {
- }
-
- public Builder setProfile(QProfileDto profile) {
- this.profile = profile;
- return this;
- }
-
- public Builder setMembership(@Nullable String membership) {
- this.membership = membership;
- return this;
- }
-
- public Builder setQuery(@Nullable String s) {
- this.query = StringUtils.defaultIfBlank(s, null);
- return this;
- }
-
- private void initMembership() {
- membership = firstNonNull(membership, ANY);
- checkArgument(AVAILABLE_MEMBERSHIPS.contains(membership),
- "Membership is not valid (got " + membership + "). Availables values are " + AVAILABLE_MEMBERSHIPS);
- }
-
- public SearchGroupsQuery build() {
- initMembership();
- return new SearchGroupsQuery(this);
- }
- }
-}
--- /dev/null
+/*
+ * 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.qualityprofile;
+
+import java.util.Locale;
+import org.sonar.db.user.SearchGroupsQuery;
+
+import static org.sonar.db.DaoUtils.buildLikeValue;
+import static org.sonar.db.WildcardPosition.BEFORE_AND_AFTER;
+
+public class SearchQualityProfileGroupsQuery extends SearchGroupsQuery {
+
+ private final String qProfileUuid;
+
+ public SearchQualityProfileGroupsQuery(Builder builder) {
+ this.qProfileUuid = builder.profile.getKee();
+ this.query = builder.getQuery();
+ this.membership = builder.getMembership();
+ this.querySqlLowercase = query == null ? null : buildLikeValue(query, BEFORE_AND_AFTER).toLowerCase(Locale.ENGLISH);
+ }
+
+ public String getQProfileUuid() {
+ return qProfileUuid;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder extends SearchGroupsQuery.Builder<Builder> {
+ private QProfileDto profile;
+
+ public Builder setProfile(QProfileDto profile) {
+ this.profile = profile;
+ return this;
+ }
+
+ public SearchQualityProfileGroupsQuery build() {
+ initMembership();
+ return new SearchQualityProfileGroupsQuery(this);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.user;
+
+public class SearchGroupMembershipDto {
+
+ private String groupUuid;
+ // Set by MyBatis
+ private String uuid;
+
+ public String getGroupUuid() {
+ return groupUuid;
+ }
+
+ public SearchGroupMembershipDto setGroupUuid(String groupUuid) {
+ this.groupUuid = groupUuid;
+ return this;
+ }
+
+ public boolean isSelected() {
+ return uuid != null;
+ }
+
+}
--- /dev/null
+/*
+ * 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.user;
+
+import java.util.Set;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.StringUtils;
+
+import static com.google.common.base.MoreObjects.firstNonNull;
+import static com.google.common.base.Preconditions.checkArgument;
+
+public abstract class SearchGroupsQuery {
+
+ public static final String ANY = "ANY";
+ public static final String IN = "IN";
+ public static final String OUT = "OUT";
+ public static final Set<String> AVAILABLE_MEMBERSHIPS = Set.of(ANY, IN, OUT);
+
+ protected String query;
+ protected String membership;
+
+ // for internal use in MyBatis
+ protected String querySqlLowercase;
+
+ public String getMembership() {
+ return membership;
+ }
+
+ @CheckForNull
+ public String getQuery() {
+ return query;
+ }
+
+ public abstract static class Builder<T extends Builder<T>> {
+ private String query;
+ private String membership;
+
+ public String getQuery(){
+ return query;
+ }
+
+ public T setQuery(@Nullable String s) {
+ this.query = StringUtils.defaultIfBlank(s, null);
+ return self();
+ }
+
+ public String getMembership(){
+ return membership;
+ }
+
+ public T setMembership(@Nullable String membership) {
+ this.membership = membership;
+ return self();
+ }
+
+ public void initMembership() {
+ membership = firstNonNull(membership, ANY);
+ checkArgument(AVAILABLE_MEMBERSHIPS.contains(membership),
+ "Membership is not valid (got " + membership + "). Availables values are " + AVAILABLE_MEMBERSHIPS);
+ }
+
+ @SuppressWarnings("unchecked")
+ final T self() {
+ return (T) this;
+ }
+ }
+}
and qggp.quality_gate_uuid = #{qualityGateUuid, jdbcType=VARCHAR}
</select>
+ <select id="selectByQuery" parameterType="map" resultType="org.sonar.db.user.SearchGroupMembershipDto">
+ SELECT g.uuid as groupUuid, g.name as name, qggp.uuid as uuid
+ <include refid="sqlSelectByQuery"/>
+ ORDER BY g.name ASC
+ LIMIT #{pagination.pageSize,jdbcType=INTEGER}
+ OFFSET #{pagination.offset,jdbcType=INTEGER}
+ </select>
+
+ <select id="selectByQuery" parameterType="map" resultType="org.sonar.db.user.SearchGroupMembershipDto" databaseId="mssql">
+ select * from (
+ select row_number() over(order by g.name asc) as number,
+ g.uuid as groupUuid, g.name as name, qggp.uuid as uuid
+ <include refid="sqlSelectByQuery" />
+ ) as query
+ where
+ query.number between #{pagination.startRowNumber,jdbcType=INTEGER} and #{pagination.endRowNumber,jdbcType=INTEGER}
+ order by query.name asc
+ </select>
+
+ <select id="selectByQuery" parameterType="map" resultType="org.sonar.db.user.SearchGroupMembershipDto" databaseId="oracle">
+ select * from (
+ select rownum as rn, t.* from (
+ select g.uuid as groupUuid, g.name as name, qggp.uuid as uuid
+ <include refid="sqlSelectByQuery"/>
+ order by g.name ASC
+ ) t
+ ) t
+ where
+ t.rn between #{pagination.startRowNumber,jdbcType=INTEGER} and #{pagination.endRowNumber,jdbcType=INTEGER}
+ </select>
+
+ <select id="countByQuery" resultType="int">
+ select count(g.uuid)
+ <include refid="sqlSelectByQuery" />
+ </select>
+
+ <sql id="sqlSelectByQuery">
+ FROM groups g
+ LEFT JOIN qgate_group_permissions qggp ON qggp.group_uuid=g.uuid AND qggp.quality_gate_uuid=#{query.qualityGateUuid, jdbcType=VARCHAR}
+ <where>
+ <choose>
+ <when test="query.getMembership() == 'IN'">
+ AND qggp.uuid IS NOT NULL
+ </when>
+ <when test="query.getMembership() == 'OUT'">
+ AND qggp.uuid IS NULL
+ </when>
+ </choose>
+ <if test="query.getQuery() != null">
+ AND (LOWER(g.name) LIKE #{query.querySqlLowercase} ESCAPE '/')
+ </if>
+ </where>
+ </sql>
+
<insert id="insert" useGeneratedKeys="false" parameterType="map">
insert into qgate_group_permissions(
uuid,
<include refid="sqlSelectByQuery" />
</select>
- <select id="selectByQuery" parameterType="map" resultType="org.sonar.db.qualityprofile.GroupMembershipDto">
+ <select id="selectByQuery" parameterType="map" resultType="org.sonar.db.user.SearchGroupMembershipDto">
SELECT g.uuid as groupUuid, g.name as name, qeg.uuid as uuid
<include refid="sqlSelectByQuery"/>
ORDER BY g.name ASC
OFFSET #{pagination.offset,jdbcType=INTEGER}
</select>
- <select id="selectByQuery" parameterType="map" resultType="org.sonar.db.qualityprofile.GroupMembershipDto" databaseId="mssql">
+ <select id="selectByQuery" parameterType="map" resultType="org.sonar.db.user.SearchGroupMembershipDto" databaseId="mssql">
select * from (
select row_number() over(order by g.name asc) as number,
g.uuid as groupUuid, g.name as name, qeg.uuid as uuid
order by query.name asc
</select>
- <select id="selectByQuery" parameterType="map" resultType="org.sonar.db.qualityprofile.GroupMembershipDto" databaseId="oracle">
+ <select id="selectByQuery" parameterType="map" resultType="org.sonar.db.user.SearchGroupMembershipDto" databaseId="oracle">
select * from (
select rownum as rn, t.* from (
select g.uuid as groupUuid, g.name as name, qeg.uuid as uuid
import org.sonar.core.util.Uuids;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
+import org.sonar.db.Pagination;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.GroupTesting;
+import org.sonar.db.user.SearchGroupMembershipDto;
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+import static org.sonar.db.qualitygate.SearchQualityGateGroupsQuery.builder;
+import static org.sonar.db.user.SearchGroupsQuery.ANY;
+import static org.sonar.db.user.SearchGroupsQuery.IN;
+import static org.sonar.db.user.SearchGroupsQuery.OUT;
public class QualityGateGroupPermissionsDaoTest {
assertThat(underTest.exists(dbSession, randomAlphabetic(5), randomAlphabetic(5))).isFalse();
}
+ @Test
+ public void countByQuery() {
+ QualityGateDto qualityGateDto = insertQualityGate();
+ GroupDto group1 = dbTester.users().insertGroup();
+ GroupDto group2 = dbTester.users().insertGroup();
+ GroupDto group3 = dbTester.users().insertGroup();
+
+ insertQualityGateGroupPermission(qualityGateDto.getUuid(), group1.getUuid());
+ insertQualityGateGroupPermission(qualityGateDto.getUuid(), group2.getUuid());
+
+ assertThat(underTest.exists(dbSession, qualityGateDto, List.of(group1, group2))).isTrue();
+
+ assertThat(underTest.countByQuery(dbSession, builder()
+ .setQualityGate(qualityGateDto)
+ .setMembership(ANY).build()))
+ .isEqualTo(3);
+
+ assertThat(underTest.countByQuery(dbSession, builder()
+ .setQualityGate(qualityGateDto)
+ .setMembership(IN).build()))
+ .isEqualTo(2);
+
+ assertThat(underTest.countByQuery(dbSession, builder()
+ .setQualityGate(qualityGateDto)
+ .setMembership(OUT).build()))
+ .isEqualTo(1);
+ }
+
+ @Test
+ public void selectByQuery() {
+ QualityGateDto qualityGateDto = insertQualityGate();
+ GroupDto group1 = dbTester.users().insertGroup();
+ GroupDto group2 = dbTester.users().insertGroup();
+ GroupDto group3 = dbTester.users().insertGroup();
+
+ insertQualityGateGroupPermission(qualityGateDto.getUuid(), group1.getUuid());
+ insertQualityGateGroupPermission(qualityGateDto.getUuid(), group2.getUuid());
+
+ assertThat(underTest.selectByQuery(dbSession, builder()
+ .setQualityGate(qualityGateDto)
+ .setMembership(ANY).build(), Pagination.all()))
+ .extracting(SearchGroupMembershipDto::getGroupUuid, SearchGroupMembershipDto::isSelected)
+ .containsExactlyInAnyOrder(
+ tuple(group1.getUuid(), true),
+ tuple(group2.getUuid(), true),
+ tuple(group3.getUuid(), false));
+
+ assertThat(underTest.selectByQuery(dbSession, builder()
+ .setQualityGate(qualityGateDto)
+ .setMembership(IN).build(),
+ Pagination.all()))
+ .extracting(SearchGroupMembershipDto::getGroupUuid, SearchGroupMembershipDto::isSelected)
+ .containsExactlyInAnyOrder(tuple(group1.getUuid(), true), tuple(group2.getUuid(), true));
+
+ assertThat(underTest.selectByQuery(dbSession, builder()
+ .setQualityGate(qualityGateDto)
+ .setMembership(OUT).build(),
+ Pagination.all()))
+ .extracting(SearchGroupMembershipDto::getGroupUuid, SearchGroupMembershipDto::isSelected)
+ .containsExactlyInAnyOrder(tuple(group3.getUuid(), false));
+ }
+
+ @Test
+ public void selectByQuery_search_by_name() {
+ QualityGateDto qualityGateDto = insertQualityGate();
+ GroupDto group1 = dbTester.users().insertGroup("sonar-users-project");
+ GroupDto group2 = dbTester.users().insertGroup("sonar-users-qprofile");
+ GroupDto group3 = dbTester.users().insertGroup("sonar-admin");
+
+ insertQualityGateGroupPermission(qualityGateDto.getUuid(), group1.getUuid());
+ insertQualityGateGroupPermission(qualityGateDto.getUuid(), group2.getUuid());
+ insertQualityGateGroupPermission(qualityGateDto.getUuid(), group3.getUuid());
+
+ assertThat(underTest.selectByQuery(dbSession, builder()
+ .setQualityGate(qualityGateDto)
+ .setMembership(IN)
+ .setQuery("project").build(),
+ Pagination.all()))
+ .extracting(SearchGroupMembershipDto::getGroupUuid)
+ .containsExactlyInAnyOrder(group1.getUuid());
+
+ assertThat(underTest.selectByQuery(dbSession, builder()
+ .setQualityGate(qualityGateDto)
+ .setMembership(IN)
+ .setQuery("UserS").build(),
+ Pagination.all()))
+ .extracting(SearchGroupMembershipDto::getGroupUuid)
+ .containsExactlyInAnyOrder(group1.getUuid(), group2.getUuid());
+ }
+
+ @Test
+ public void selectByQuery_with_paging() {
+ QualityGateDto qualityGateDto = insertQualityGate();
+ GroupDto group1 = dbTester.users().insertGroup("group1");
+ GroupDto group2 = dbTester.users().insertGroup("group2");
+ GroupDto group3 = dbTester.users().insertGroup("group3");
+
+ insertQualityGateGroupPermission(qualityGateDto.getUuid(), group1.getUuid());
+ insertQualityGateGroupPermission(qualityGateDto.getUuid(), group2.getUuid());
+
+ assertThat(underTest.selectByQuery(dbSession, builder()
+ .setQualityGate(qualityGateDto)
+ .setMembership(ANY)
+ .build(),
+ Pagination.forPage(1).andSize(1)))
+ .extracting(SearchGroupMembershipDto::getGroupUuid)
+ .containsExactly(group1.getUuid());
+
+ assertThat(underTest.selectByQuery(dbSession, builder()
+ .setQualityGate(qualityGateDto)
+ .setMembership(ANY)
+ .build(),
+ Pagination.forPage(3).andSize(1)))
+ .extracting(SearchGroupMembershipDto::getGroupUuid)
+ .containsExactly(group3.getUuid());
+
+ assertThat(underTest.selectByQuery(dbSession, builder()
+ .setQualityGate(qualityGateDto)
+ .setMembership(ANY)
+ .build(),
+ Pagination.forPage(1).andSize(10)))
+ .extracting(SearchGroupMembershipDto::getGroupUuid)
+ .containsExactly(group1.getUuid(), group2.getUuid(), group3.getUuid());
+ }
+
private QualityGateDto insertQualityGate() {
QualityGateDto qg = new QualityGateDto()
.setUuid(randomAlphabetic(5))
import org.sonar.db.DbTester;
import org.sonar.db.Pagination;
import org.sonar.db.user.GroupDto;
+import org.sonar.db.user.SearchGroupMembershipDto;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
import static org.assertj.core.api.Assertions.tuple;
-import static org.sonar.db.qualityprofile.SearchGroupsQuery.ANY;
-import static org.sonar.db.qualityprofile.SearchGroupsQuery.IN;
-import static org.sonar.db.qualityprofile.SearchGroupsQuery.OUT;
-import static org.sonar.db.qualityprofile.SearchGroupsQuery.builder;
+import static org.sonar.db.qualityprofile.SearchQualityProfileGroupsQuery.ANY;
+import static org.sonar.db.qualityprofile.SearchQualityProfileGroupsQuery.IN;
+import static org.sonar.db.qualityprofile.SearchQualityProfileGroupsQuery.OUT;
+import static org.sonar.db.qualityprofile.SearchQualityProfileGroupsQuery.builder;
public class QProfileEditGroupsDaoTest {
assertThat(underTest.selectByQuery(db.getSession(), builder()
.setProfile(profile)
.setMembership(ANY).build(), Pagination.all()))
- .extracting(GroupMembershipDto::getGroupUuid, GroupMembershipDto::isSelected)
+ .extracting(SearchGroupMembershipDto::getGroupUuid, SearchGroupMembershipDto::isSelected)
.containsExactlyInAnyOrder(
tuple(group1.getUuid(), true),
tuple(group2.getUuid(), true),
.setProfile(profile)
.setMembership(IN).build(),
Pagination.all()))
- .extracting(GroupMembershipDto::getGroupUuid, GroupMembershipDto::isSelected)
+ .extracting(SearchGroupMembershipDto::getGroupUuid, SearchGroupMembershipDto::isSelected)
.containsExactlyInAnyOrder(tuple(group1.getUuid(), true), tuple(group2.getUuid(), true));
assertThat(underTest.selectByQuery(db.getSession(), builder()
.setProfile(profile)
.setMembership(OUT).build(),
Pagination.all()))
- .extracting(GroupMembershipDto::getGroupUuid, GroupMembershipDto::isSelected)
+ .extracting(SearchGroupMembershipDto::getGroupUuid, SearchGroupMembershipDto::isSelected)
.containsExactlyInAnyOrder(tuple(group3.getUuid(), false));
}
.setMembership(IN)
.setQuery("project").build(),
Pagination.all()))
- .extracting(GroupMembershipDto::getGroupUuid)
+ .extracting(SearchGroupMembershipDto::getGroupUuid)
.containsExactlyInAnyOrder(group1.getUuid());
assertThat(underTest.selectByQuery(db.getSession(), builder()
.setMembership(IN)
.setQuery("UserS").build(),
Pagination.all()))
- .extracting(GroupMembershipDto::getGroupUuid)
+ .extracting(SearchGroupMembershipDto::getGroupUuid)
.containsExactlyInAnyOrder(group1.getUuid(), group2.getUuid());
}
.setMembership(ANY)
.build(),
Pagination.forPage(1).andSize(1)))
- .extracting(GroupMembershipDto::getGroupUuid)
+ .extracting(SearchGroupMembershipDto::getGroupUuid)
.containsExactly(group1.getUuid());
assertThat(underTest.selectByQuery(db.getSession(), builder()
.setMembership(ANY)
.build(),
Pagination.forPage(3).andSize(1)))
- .extracting(GroupMembershipDto::getGroupUuid)
+ .extracting(SearchGroupMembershipDto::getGroupUuid)
.containsExactly(group3.getUuid());
assertThat(underTest.selectByQuery(db.getSession(), builder()
.setMembership(ANY)
.build(),
Pagination.forPage(1).andSize(10)))
- .extracting(GroupMembershipDto::getGroupUuid)
+ .extracting(SearchGroupMembershipDto::getGroupUuid)
.containsExactly(group1.getUuid(), group2.getUuid(), group3.getUuid());
}
UpdateConditionAction.class,
ProjectStatusAction.class,
GetByProjectAction.class,
- AddGroupAction.class
+ AddGroupAction.class,
+ SearchGroupsAction.class
);
}
}
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 ACTION_SEARCH_GROUPS = "search_groups";
public static final String PARAM_ANALYSIS_ID = "analysisId";
public static final String PARAM_BRANCH = "branch";
--- /dev/null
+/*
+ * 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.List;
+import java.util.Map;
+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.stream.MoreCollectors;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.qualitygate.QualityGateDto;
+import org.sonar.db.user.SearchGroupMembershipDto;
+import org.sonar.db.user.SearchGroupsQuery;
+import org.sonar.db.user.GroupDto;
+import org.sonarqube.ws.Common;
+import org.sonarqube.ws.Qualitygates;
+
+import static java.util.Optional.ofNullable;
+import static org.sonar.api.server.ws.WebService.Param.PAGE;
+import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE;
+import static org.sonar.api.server.ws.WebService.Param.SELECTED;
+import static org.sonar.api.server.ws.WebService.Param.TEXT_QUERY;
+import static org.sonar.api.server.ws.WebService.SelectionMode.ALL;
+import static org.sonar.api.server.ws.WebService.SelectionMode.DESELECTED;
+import static org.sonar.api.server.ws.WebService.SelectionMode.fromParam;
+import static org.sonar.core.util.stream.MoreCollectors.toList;
+import static org.sonar.db.Pagination.forPage;
+import static org.sonar.db.qualitygate.SearchQualityGateGroupsQuery.builder;
+import static org.sonar.db.user.SearchGroupsQuery.ANY;
+import static org.sonar.db.user.SearchGroupsQuery.IN;
+import static org.sonar.db.user.SearchGroupsQuery.OUT;
+import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.ACTION_SEARCH_GROUPS;
+import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_GATE_NAME;
+import static org.sonar.server.ws.WsUtils.writeProtobuf;
+
+public class SearchGroupsAction implements QualityGatesWsAction {
+
+ private static final Map<WebService.SelectionMode, String> MEMBERSHIP = Map.of(WebService.SelectionMode.SELECTED, IN, DESELECTED, OUT, ALL, ANY);
+
+ private final DbClient dbClient;
+ private final QualityGatesWsSupport wsSupport;
+
+ public SearchGroupsAction(DbClient dbClient, QualityGatesWsSupport wsSupport) {
+ this.dbClient = dbClient;
+ this.wsSupport = wsSupport;
+ }
+
+ @Override
+ public void define(WebService.NewController context) {
+ WebService.NewAction action = context
+ .createAction(ACTION_SEARCH_GROUPS)
+ .setDescription("List the groups that are allowed 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)
+ .setInternal(true)
+ .addSelectionModeParam()
+ .addSearchQuery("sonar", "group names")
+ .addPagingParams(25)
+ .setResponseExample(getClass().getResource("search_groups-example.json"))
+ .setSince("9.2");
+
+ action.createParam(PARAM_GATE_NAME)
+ .setDescription("Quality Gate name")
+ .setRequired(true)
+ .setExampleValue("SonarSource Way");
+ }
+
+ @Override
+ public void handle(Request request, Response response) throws Exception {
+ SearchQualityGateUsersRequest wsRequest = buildRequest(request);
+ try (DbSession dbSession = dbClient.openSession(false)) {
+ QualityGateDto gate = wsSupport.getByName(dbSession, wsRequest.getQualityGate());
+ wsSupport.checkCanLimitedEdit(dbSession, gate);
+
+ SearchGroupsQuery query = builder()
+ .setQualityGate(gate)
+ .setQuery(wsRequest.getQuery())
+ .setMembership(MEMBERSHIP.get(fromParam(wsRequest.getSelected())))
+ .build();
+ int total = dbClient.qualityGateGroupPermissionsDao().countByQuery(dbSession, query);
+ List<SearchGroupMembershipDto> groupMemberships = dbClient.qualityGateGroupPermissionsDao().selectByQuery(dbSession, query,
+ forPage(wsRequest.getPage()).andSize(wsRequest.getPageSize()));
+ Map<String, GroupDto> groupsByUuid = dbClient.groupDao().selectByUuids(dbSession,
+ groupMemberships.stream().map(SearchGroupMembershipDto::getGroupUuid).collect(MoreCollectors.toList()))
+ .stream()
+ .collect(MoreCollectors.uniqueIndex(GroupDto::getUuid));
+ writeProtobuf(
+ Qualitygates.SearchGroupsResponse.newBuilder()
+ .addAllGroups(groupMemberships.stream()
+ .map(groupsMembership -> toGroup(groupsByUuid.get(groupsMembership.getGroupUuid()), groupsMembership.isSelected()))
+ .collect(toList()))
+ .setPaging(buildPaging(wsRequest, total)).build(),
+ request, response);
+ }
+ }
+
+ private static SearchQualityGateUsersRequest buildRequest(Request request) {
+ return SearchQualityGateUsersRequest.builder()
+ .setQualityGate(request.mandatoryParam(PARAM_GATE_NAME))
+ .setQuery(request.param(TEXT_QUERY))
+ .setSelected(request.mandatoryParam(SELECTED))
+ .setPage(request.mandatoryParamAsInt(PAGE))
+ .setPageSize(request.mandatoryParamAsInt(PAGE_SIZE))
+ .build();
+ }
+
+ private static Qualitygates.SearchGroupsResponse.Group toGroup(GroupDto group, boolean isSelected) {
+ Qualitygates.SearchGroupsResponse.Group.Builder builder = Qualitygates.SearchGroupsResponse.Group.newBuilder()
+ .setName(group.getName())
+ .setSelected(isSelected);
+ ofNullable(group.getDescription()).ifPresent(builder::setDescription);
+ return builder.build();
+ }
+
+ private static Common.Paging buildPaging(SearchQualityGateUsersRequest wsRequest, int total) {
+ return Common.Paging.newBuilder()
+ .setPageIndex(wsRequest.getPage())
+ .setPageSize(wsRequest.getPageSize())
+ .setTotal(total)
+ .build();
+ }
+
+}
--- /dev/null
+/*
+ * 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.server.user.ws.SearchUsersRequest;
+
+class SearchQualityGateUsersRequest extends SearchUsersRequest {
+ private String qualityGate;
+
+ private SearchQualityGateUsersRequest(Builder builder) {
+ this.qualityGate = builder.qualityGate;
+ this.selected = builder.getSelected();
+ this.query = builder.getQuery();
+ this.page = builder.getPage();
+ this.pageSize = builder.getPageSize();
+ }
+
+ public String getQualityGate() {
+ return qualityGate;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder extends SearchUsersRequest.Builder<Builder> {
+ private String qualityGate;
+
+ public Builder setQualityGate(String qualityGate) {
+ this.qualityGate = qualityGate;
+ return this;
+ }
+
+ public SearchQualityGateUsersRequest build() {
+ return new SearchQualityGateUsersRequest(this);
+ }
+ }
+}
*/
package org.sonar.server.qualityprofile.ws;
-import com.google.common.collect.ImmutableMap;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
-import org.sonar.db.qualityprofile.GroupMembershipDto;
import org.sonar.db.qualityprofile.QProfileDto;
-import org.sonar.db.qualityprofile.SearchGroupsQuery;
+import org.sonar.db.qualityprofile.SearchQualityProfileGroupsQuery;
import org.sonar.db.user.GroupDto;
+import org.sonar.db.user.SearchGroupMembershipDto;
import org.sonarqube.ws.Common;
import org.sonarqube.ws.Qualityprofiles;
import static org.sonar.core.util.stream.MoreCollectors.toList;
import static org.sonar.core.util.stream.MoreCollectors.toSet;
import static org.sonar.db.Pagination.forPage;
-import static org.sonar.db.qualityprofile.SearchGroupsQuery.ANY;
-import static org.sonar.db.qualityprofile.SearchGroupsQuery.IN;
-import static org.sonar.db.qualityprofile.SearchGroupsQuery.OUT;
-import static org.sonar.db.qualityprofile.SearchGroupsQuery.builder;
+import static org.sonar.db.qualityprofile.SearchQualityProfileGroupsQuery.ANY;
+import static org.sonar.db.qualityprofile.SearchQualityProfileGroupsQuery.IN;
+import static org.sonar.db.qualityprofile.SearchQualityProfileGroupsQuery.OUT;
+import static org.sonar.db.qualityprofile.SearchQualityProfileGroupsQuery.builder;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_SEARCH_GROUPS;
import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE;
public class SearchGroupsAction implements QProfileWsAction {
- private static final Map<WebService.SelectionMode, String> MEMBERSHIP = ImmutableMap.of(WebService.SelectionMode.SELECTED, IN, DESELECTED, OUT, ALL, ANY);
+ private static final Map<WebService.SelectionMode, String> MEMBERSHIP = Map.of(WebService.SelectionMode.SELECTED, IN, DESELECTED, OUT, ALL, ANY);
private final DbClient dbClient;
private final QProfileWsSupport wsSupport;
@Override
public void handle(Request request, Response response) throws Exception {
- SearchUsersRequest wsRequest = buildRequest(request);
+ SearchQualityProfileUsersRequest wsRequest = buildRequest(request);
try (DbSession dbSession = dbClient.openSession(false)) {
QProfileDto profile = wsSupport.getProfile(dbSession, wsRequest.getQualityProfile(), wsRequest.getLanguage());
wsSupport.checkCanEdit(dbSession, profile);
- SearchGroupsQuery query = builder()
+ SearchQualityProfileGroupsQuery query = builder()
.setProfile(profile)
.setQuery(wsRequest.getQuery())
.setMembership(MEMBERSHIP.get(fromParam(wsRequest.getSelected())))
.build();
int total = dbClient.qProfileEditGroupsDao().countByQuery(dbSession, query);
- List<GroupMembershipDto> groupMemberships = dbClient.qProfileEditGroupsDao().selectByQuery(dbSession, query,
+ List<SearchGroupMembershipDto> groupMemberships = dbClient.qProfileEditGroupsDao().selectByQuery(dbSession, query,
forPage(wsRequest.getPage()).andSize(wsRequest.getPageSize()));
Map<String, GroupDto> groupsByUuid = dbClient.groupDao().selectByUuids(dbSession,
- groupMemberships.stream().map(GroupMembershipDto::getGroupUuid).collect(MoreCollectors.toList()))
+ groupMemberships.stream().map(SearchGroupMembershipDto::getGroupUuid).collect(MoreCollectors.toList()))
.stream()
.collect(MoreCollectors.uniqueIndex(GroupDto::getUuid));
writeProtobuf(
}
}
- private static SearchUsersRequest buildRequest(Request request) {
- return SearchUsersRequest.builder()
+ private static SearchQualityProfileUsersRequest buildRequest(Request request) {
+ return SearchQualityProfileUsersRequest.builder()
.setQualityProfile(request.mandatoryParam(PARAM_QUALITY_PROFILE))
.setLanguage(request.mandatoryParam(PARAM_LANGUAGE))
.setQuery(request.param(TEXT_QUERY))
return builder.build();
}
- private static Common.Paging buildPaging(SearchUsersRequest wsRequest, int total) {
+ private static Common.Paging buildPaging(SearchQualityProfileUsersRequest wsRequest, int total) {
return Common.Paging.newBuilder()
.setPageIndex(wsRequest.getPage())
.setPageSize(wsRequest.getPageSize())
--- /dev/null
+/*
+ * 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.qualityprofile.ws;
+
+import org.sonar.server.user.ws.SearchUsersRequest;
+
+class SearchQualityProfileUsersRequest extends SearchUsersRequest {
+ private String qualityProfile;
+ private String language;
+
+ private SearchQualityProfileUsersRequest(Builder builder) {
+ this.qualityProfile = builder.qualityProfile;
+ this.language = builder.language;
+ this.selected = builder.getSelected();
+ this.query = builder.getQuery();
+ this.page = builder.getPage();
+ this.pageSize = builder.getPageSize();
+ }
+
+ public String getQualityProfile() {
+ return qualityProfile;
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder extends SearchUsersRequest.Builder<Builder> {
+ private String qualityProfile;
+ private String language;
+
+ public Builder setQualityProfile(String qualityProfile) {
+ this.qualityProfile = qualityProfile;
+ return this;
+ }
+
+ public Builder setLanguage(String language) {
+ this.language = language;
+ return this;
+ }
+
+ public SearchQualityProfileUsersRequest build() {
+ return new SearchQualityProfileUsersRequest(this);
+ }
+ }
+}
@Override
public void handle(Request request, Response response) throws Exception {
- SearchUsersRequest wsRequest = buildRequest(request);
+ SearchQualityProfileUsersRequest wsRequest = buildRequest(request);
try (DbSession dbSession = dbClient.openSession(false)) {
QProfileDto profile = wsSupport.getProfile(dbSession, wsRequest.getQualityProfile(), wsRequest.getLanguage());
wsSupport.checkCanEdit(dbSession, profile);
}
}
- private static SearchUsersRequest buildRequest(Request request) {
- return SearchUsersRequest.builder()
+ private static SearchQualityProfileUsersRequest buildRequest(Request request) {
+ return SearchQualityProfileUsersRequest.builder()
.setQualityProfile(request.mandatoryParam(PARAM_QUALITY_PROFILE))
.setLanguage(request.mandatoryParam(PARAM_LANGUAGE))
.setQuery(request.param(TEXT_QUERY))
.build();
}
- private static Common.Paging buildPaging(SearchUsersRequest wsRequest, int total) {
+ private static Common.Paging buildPaging(SearchQualityProfileUsersRequest wsRequest, int total) {
return Common.Paging.newBuilder()
.setPageIndex(wsRequest.getPage())
.setPageSize(wsRequest.getPageSize())
+++ /dev/null
-/*
- * 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.qualityprofile.ws;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-class SearchUsersRequest {
- private String qualityProfile;
- private String language;
- private String selected;
- private String query;
- private Integer page;
- private Integer pageSize;
-
- private SearchUsersRequest(Builder builder) {
- this.qualityProfile = builder.qualityProfile;
- this.language = builder.language;
- this.selected = builder.selected;
- this.query = builder.query;
- this.page = builder.page;
- this.pageSize = builder.pageSize;
- }
-
- public String getQualityProfile() {
- return qualityProfile;
- }
-
- public String getLanguage() {
- return language;
- }
-
- @CheckForNull
- public String getQuery() {
- return query;
- }
-
- public String getSelected() {
- return selected;
- }
-
- public Integer getPage() {
- return page;
- }
-
- public Integer getPageSize() {
- return pageSize;
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static class Builder {
- private String qualityProfile;
- private String language;
- private String selected;
- private String query;
- private Integer page;
- private Integer pageSize;
-
- public Builder setQualityProfile(String qualityProfile) {
- this.qualityProfile = qualityProfile;
- return this;
- }
-
- public Builder setLanguage(String language) {
- this.language = language;
- return this;
- }
-
- public Builder setSelected(String selected) {
- this.selected = selected;
- return this;
- }
-
- public Builder setQuery(@Nullable String query) {
- this.query = query;
- return this;
- }
-
- public Builder setPage(Integer page) {
- this.page = page;
- return this;
- }
-
- public Builder setPageSize(Integer pageSize) {
- this.pageSize = pageSize;
- return this;
- }
-
- public SearchUsersRequest build() {
- return new SearchUsersRequest(this);
- }
- }
-}
--- /dev/null
+/*
+ * 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.user.ws;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+public abstract class SearchUsersRequest {
+ protected String selected;
+ protected String query;
+ protected Integer page;
+ protected Integer pageSize;
+
+ @CheckForNull
+ public String getQuery() {
+ return query;
+ }
+
+ public String getSelected() {
+ return selected;
+ }
+
+ public Integer getPage() {
+ return page;
+ }
+
+ public Integer getPageSize() {
+ return pageSize;
+ }
+
+ public abstract static class Builder<T extends Builder<T>> {
+ private String selected;
+ private String query;
+ private Integer page;
+ private Integer pageSize;
+
+ public String getSelected() {
+ return selected;
+ }
+
+ public T setSelected(String selected) {
+ this.selected = selected;
+ return self();
+ }
+
+ public String getQuery() {
+ return query;
+ }
+
+ public T setQuery(@Nullable String query) {
+ this.query = query;
+ return self();
+ }
+
+ public Integer getPage() {
+ return page;
+ }
+
+ public T setPage(Integer page) {
+ this.page = page;
+ return self();
+ }
+
+ public Integer getPageSize() {
+ return pageSize;
+ }
+
+ public T setPageSize(Integer pageSize) {
+ this.pageSize = pageSize;
+ return self();
+ }
+
+ @SuppressWarnings("unchecked")
+ final T self() {
+ return (T) this;
+ }
+ }
+}
--- /dev/null
+{
+ "paging": {
+ "pageSize": 25,
+ "total": 2,
+ "pageIndex": 1
+ },
+ "groups": [
+ {
+ "name": "users",
+ "description": "Users",
+ "selected": true
+ },
+ {
+ "name": "administrators",
+ "description": "Administrators",
+ "selected": false
+ }
+ ]
+}
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
new QualityGateWsModule().configure(container);
- assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 19);
+ assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 20);
}
}
--- /dev/null
+/*
+ * 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.assertj.core.api.Assertions;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.server.ws.WebService;
+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.WsActionTester;
+import org.sonarqube.ws.Qualitygates;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.server.ws.WebService.Param.PAGE;
+import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE;
+import static org.sonar.api.server.ws.WebService.Param.TEXT_QUERY;
+import static org.sonar.db.permission.GlobalPermission.ADMINISTER_QUALITY_GATES;
+import static org.sonar.db.user.GroupTesting.newGroupDto;
+import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_GATE_NAME;
+import static org.sonar.test.JsonAssert.assertJson;
+import static org.sonarqube.ws.MediaTypes.JSON;
+
+public class SearchGroupsActionTest {
+ private static final String XOO = "xoo";
+ private static final String FOO = "foo";
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+ @Rule
+ public UserSessionRule userSession = UserSessionRule.standalone();
+ @Rule
+ public DbTester db = DbTester.create();
+
+ private final QualityGatesWsSupport wsSupport = new QualityGatesWsSupport(db.getDbClient(), userSession, TestComponentFinder.from(db));
+
+ private final WsActionTester ws = new WsActionTester(new SearchGroupsAction(db.getDbClient(), wsSupport));
+
+ @Test
+ public void test_definition() {
+ WebService.Action def = ws.getDef();
+ assertThat(def.key()).isEqualTo("search_groups");
+ assertThat(def.isPost()).isFalse();
+ assertThat(def.isInternal()).isTrue();
+ assertThat(def.params()).extracting(WebService.Param::key)
+ .containsExactlyInAnyOrder("gateName", "selected", "q", "p", "ps");
+ }
+
+ @Test
+ public void test_example() {
+ QualityGateDto gate = db.qualityGates().insertQualityGate();
+ GroupDto group1 = db.users().insertGroup(newGroupDto().setName("users").setDescription("Users"));
+ GroupDto group2 = db.users().insertGroup(newGroupDto().setName("administrators").setDescription("Administrators"));
+ db.qualityGates().addGroupPermission(gate, group1);
+ userSession.logIn().addPermission(ADMINISTER_QUALITY_GATES);
+
+ String result = ws.newRequest()
+ .setParam(PARAM_GATE_NAME, gate.getName())
+ .setParam(WebService.Param.SELECTED, "all")
+ .setMediaType(JSON)
+ .execute()
+ .getInput();
+
+ assertJson(ws.getDef().responseExampleAsString()).isSimilarTo(result);
+ }
+
+ @Test
+ public void search_all_groups() {
+ QualityGateDto gate = db.qualityGates().insertQualityGate();
+ GroupDto group1 = db.users().insertGroup();
+ GroupDto group2 = db.users().insertGroup();
+ db.qualityGates().addGroupPermission(gate, group1);
+ userSession.logIn().addPermission(ADMINISTER_QUALITY_GATES);
+
+ Qualitygates.SearchGroupsResponse response = ws.newRequest()
+ .setParam(PARAM_GATE_NAME, gate.getName())
+ .setParam(WebService.Param.SELECTED, "all")
+ .executeProtobuf(Qualitygates.SearchGroupsResponse.class);
+
+ assertThat(response.getGroupsList())
+ .extracting(Qualitygates.SearchGroupsResponse.Group::getName,
+ Qualitygates.SearchGroupsResponse.Group::getDescription, Qualitygates.SearchGroupsResponse.Group::getSelected)
+ .containsExactlyInAnyOrder(
+ Assertions.tuple(group1.getName(), group1.getDescription(), true),
+ Assertions.tuple(group2.getName(), group2.getDescription(), false));
+ }
+
+ @Test
+ public void search_selected_groups() {
+ QualityGateDto gate = db.qualityGates().insertQualityGate();
+ GroupDto group1 = db.users().insertGroup();
+ GroupDto group2 = db.users().insertGroup();
+ db.qualityGates().addGroupPermission(gate, group1);
+ userSession.logIn().addPermission(ADMINISTER_QUALITY_GATES);
+
+ Qualitygates.SearchGroupsResponse response = ws.newRequest()
+ .setParam(PARAM_GATE_NAME, gate.getName())
+ .setParam(WebService.Param.SELECTED, "selected")
+ .executeProtobuf(Qualitygates.SearchGroupsResponse.class);
+
+ assertThat(response.getGroupsList())
+ .extracting(Qualitygates.SearchGroupsResponse.Group::getName,
+ Qualitygates.SearchGroupsResponse.Group::getDescription, Qualitygates.SearchGroupsResponse.Group::getSelected)
+ .containsExactlyInAnyOrder(
+ Assertions.tuple(group1.getName(), group1.getDescription(), true));
+ }
+
+ @Test
+ public void search_deselected_groups() {
+ QualityGateDto gate = db.qualityGates().insertQualityGate();
+ GroupDto group1 = db.users().insertGroup();
+ GroupDto group2 = db.users().insertGroup();
+ db.qualityGates().addGroupPermission(gate, group1);
+ userSession.logIn().addPermission(ADMINISTER_QUALITY_GATES);
+
+ Qualitygates.SearchGroupsResponse response = ws.newRequest()
+ .setParam(PARAM_GATE_NAME, gate.getName())
+ .setParam(WebService.Param.SELECTED, "deselected")
+ .executeProtobuf(Qualitygates.SearchGroupsResponse.class);
+
+ assertThat(response.getGroupsList())
+ .extracting(Qualitygates.SearchGroupsResponse.Group::getName,
+ Qualitygates.SearchGroupsResponse.Group::getDescription, Qualitygates.SearchGroupsResponse.Group::getSelected)
+ .containsExactlyInAnyOrder(
+ Assertions.tuple(group2.getName(), group2.getDescription(), false));
+ }
+
+ @Test
+ public void search_by_name() {
+ QualityGateDto gate = db.qualityGates().insertQualityGate();
+ GroupDto group1 = db.users().insertGroup("sonar-users-project");
+ GroupDto group2 = db.users().insertGroup("sonar-users-qgate");
+ GroupDto group3 = db.users().insertGroup("sonar-admin");
+ db.qualityGates().addGroupPermission(gate, group1);
+ db.qualityGates().addGroupPermission(gate, group2);
+ db.qualityGates().addGroupPermission(gate, group3);
+ userSession.logIn().addPermission(ADMINISTER_QUALITY_GATES);
+
+ Qualitygates.SearchGroupsResponse response = ws.newRequest()
+ .setParam(PARAM_GATE_NAME, gate.getName())
+ .setParam(TEXT_QUERY, "UsErS")
+ .setParam(WebService.Param.SELECTED, "all")
+ .executeProtobuf(Qualitygates.SearchGroupsResponse.class);
+
+ assertThat(response.getGroupsList()).extracting(Qualitygates.SearchGroupsResponse.Group::getName)
+ .containsExactlyInAnyOrder(group1.getName(), group2.getName());
+ }
+
+ @Test
+ public void group_without_description() {
+ QualityGateDto gate = db.qualityGates().insertQualityGate();
+ GroupDto group = db.users().insertGroup(newGroupDto().setDescription(null));
+ db.qualityGates().addGroupPermission(gate, group);
+ userSession.logIn().addPermission(ADMINISTER_QUALITY_GATES);
+
+ Qualitygates.SearchGroupsResponse response = ws.newRequest()
+ .setParam(PARAM_GATE_NAME, gate.getName())
+ .setParam(WebService.Param.SELECTED, "all")
+ .executeProtobuf(Qualitygates.SearchGroupsResponse.class);
+
+ assertThat(response.getGroupsList())
+ .extracting(Qualitygates.SearchGroupsResponse.Group::getName, Qualitygates.SearchGroupsResponse.Group::hasDescription)
+ .containsExactlyInAnyOrder(Assertions.tuple(group.getName(), false));
+ }
+
+ @Test
+ public void paging_search() {
+ QualityGateDto gate = db.qualityGates().insertQualityGate();
+ GroupDto group3 = db.users().insertGroup("group3");
+ GroupDto group1 = db.users().insertGroup("group1");
+ GroupDto group2 = db.users().insertGroup("group2");
+ db.qualityGates().addGroupPermission(gate, group1);
+ db.qualityGates().addGroupPermission(gate, group2);
+ userSession.logIn().addPermission(ADMINISTER_QUALITY_GATES);
+
+ assertThat(ws.newRequest()
+ .setParam(PARAM_GATE_NAME, gate.getName())
+ .setParam(WebService.Param.SELECTED, "all")
+ .setParam(PAGE, "1")
+ .setParam(PAGE_SIZE, "1")
+ .executeProtobuf(Qualitygates.SearchGroupsResponse.class).getGroupsList())
+ .extracting(Qualitygates.SearchGroupsResponse.Group::getName)
+ .containsExactly(group1.getName());
+
+ assertThat(ws.newRequest()
+ .setParam(PARAM_GATE_NAME, gate.getName())
+ .setParam(WebService.Param.SELECTED, "all")
+ .setParam(PAGE, "3")
+ .setParam(PAGE_SIZE, "1")
+ .executeProtobuf(Qualitygates.SearchGroupsResponse.class).getGroupsList())
+ .extracting(Qualitygates.SearchGroupsResponse.Group::getName)
+ .containsExactly(group3.getName());
+
+ assertThat(ws.newRequest()
+ .setParam(PARAM_GATE_NAME, gate.getName())
+ .setParam(WebService.Param.SELECTED, "all")
+ .setParam(PAGE, "1")
+ .setParam(PAGE_SIZE, "10")
+ .executeProtobuf(Qualitygates.SearchGroupsResponse.class).getGroupsList())
+ .extracting(Qualitygates.SearchGroupsResponse.Group::getName)
+ .containsExactly(group1.getName(), group2.getName(), group3.getName());
+ }
+
+ @Test
+ public void uses_global_permission() {
+ QualityGateDto gate = db.qualityGates().insertQualityGate();
+ GroupDto group = db.users().insertGroup();
+ db.qualityGates().addGroupPermission(gate, group);
+ userSession.logIn().addPermission(ADMINISTER_QUALITY_GATES);
+
+ Qualitygates.SearchGroupsResponse response = ws.newRequest()
+ .setParam(PARAM_GATE_NAME, gate.getName())
+ .setParam(WebService.Param.SELECTED, "all")
+ .executeProtobuf(Qualitygates.SearchGroupsResponse.class);
+
+ assertThat(response.getGroupsList())
+ .extracting(Qualitygates.SearchGroupsResponse.Group::getName)
+ .containsExactlyInAnyOrder(group.getName());
+ }
+
+ @Test
+ public void qg_administers_can_search_groups() {
+ QualityGateDto gate = db.qualityGates().insertQualityGate();
+ GroupDto group = db.users().insertGroup();
+ db.qualityGates().addGroupPermission(gate, group);
+ userSession.logIn().addPermission(GlobalPermission.ADMINISTER_QUALITY_GATES);
+
+ Qualitygates.SearchGroupsResponse response = ws.newRequest()
+ .setParam(PARAM_GATE_NAME, gate.getName())
+ .setParam(WebService.Param.SELECTED, "all")
+ .executeProtobuf(Qualitygates.SearchGroupsResponse.class);
+
+ assertThat(response.getGroupsList())
+ .extracting(Qualitygates.SearchGroupsResponse.Group::getName)
+ .containsExactlyInAnyOrder(group.getName());
+ }
+
+ @Test
+ public void qg_editors_can_search_groups() {
+ QualityGateDto gate = db.qualityGates().insertQualityGate();
+ GroupDto group = db.users().insertGroup();
+ db.qualityGates().addGroupPermission(gate, group);
+ UserDto userAllowedToEditQualityGate = db.users().insertUser();
+ db.qualityGates().addUserPermission(gate, userAllowedToEditQualityGate);
+ userSession.logIn(userAllowedToEditQualityGate);
+
+ Qualitygates.SearchGroupsResponse response = ws.newRequest()
+ .setParam(PARAM_GATE_NAME, gate.getName())
+ .setParam(WebService.Param.SELECTED, "all")
+ .executeProtobuf(Qualitygates.SearchGroupsResponse.class);
+
+ assertThat(response.getGroupsList())
+ .extracting(Qualitygates.SearchGroupsResponse.Group::getName)
+ .containsExactlyInAnyOrder(group.getName());
+ }
+
+ @Test
+ public void fail_when_qgate_does_not_exist() {
+ userSession.logIn().addPermission(GlobalPermission.ADMINISTER_QUALITY_GATES);
+
+ expectedException.expect(NotFoundException.class);
+ expectedException.expectMessage("No quality gate has been found for name unknown");
+
+ ws.newRequest()
+ .setParam(PARAM_GATE_NAME, "unknown")
+ .execute();
+ }
+
+ @Test
+ public void fail_when_not_enough_permission() {
+ QualityGateDto gate = db.qualityGates().insertQualityGate();
+ userSession.logIn(db.users().insertUser());
+
+ expectedException.expect(ForbiddenException.class);
+
+ ws.newRequest()
+ .setParam(PARAM_GATE_NAME, gate.getName())
+ .execute();
+ }
+
+}
optional bool manageConditions = 6;
}
+// WS api/qualitygates/search_groups
+message SearchGroupsResponse {
+ optional sonarqube.ws.commons.Paging paging = 1;
+ repeated Group groups = 2;
+
+ message Group {
+ optional string name = 1;
+ optional string description = 2;
+ optional bool selected = 3;
+ }
+}
+