diff options
author | Teryk Bellahsene <teryk.bellahsene@sonarsource.com> | 2017-05-08 19:31:41 +0200 |
---|---|---|
committer | Teryk Bellahsene <teryk.bellahsene@sonarsource.com> | 2017-05-08 19:31:41 +0200 |
commit | d83ff5e2042f848a1640e84ecb30a867311cfae6 (patch) | |
tree | 1e614e9b16806824141f86d2f2d5364ed44d8c74 /server | |
parent | f16ba7b4228e0908d7dd7495be1d3905b14b577d (diff) | |
download | sonarqube-d83ff5e2042f848a1640e84ecb30a867311cfae6.tar.gz sonarqube-d83ff5e2042f848a1640e84ecb30a867311cfae6.zip |
SONAR-9182 Add visibility to WS api/projects/search
Diffstat (limited to 'server')
5 files changed, 90 insertions, 6 deletions
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentQuery.java b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentQuery.java index f5e6df3a26a..72ed52dd99c 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentQuery.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentQuery.java @@ -32,6 +32,7 @@ public class ComponentQuery { private final String nameOrKeyQuery; private final String[] qualifiers; private final String language; + private final Boolean isPrivate; private final Set<Long> componentIds; /** @@ -46,6 +47,7 @@ public class ComponentQuery { this.qualifiers = Builder.validateQualifiers(qualifiers); this.language = null; this.componentIds = null; + this.isPrivate = null; } private ComponentQuery(Builder builder) { @@ -53,6 +55,7 @@ public class ComponentQuery { this.qualifiers = builder.qualifiers; this.language = builder.language; this.componentIds = builder.componentIds; + this.isPrivate = builder.isPrivate; } public String[] getQualifiers() { @@ -82,6 +85,11 @@ public class ComponentQuery { return componentIds; } + @CheckForNull + public Boolean getPrivate() { + return isPrivate; + } + public static Builder builder() { return new Builder(); } @@ -90,6 +98,7 @@ public class ComponentQuery { private String nameOrKeyQuery; private String[] qualifiers; private String language; + private Boolean isPrivate; private Set<Long> componentIds; public Builder setNameOrKeyQuery(@Nullable String nameOrKeyQuery) { @@ -112,6 +121,11 @@ public class ComponentQuery { return this; } + public Builder setPrivate(@Nullable Boolean isPrivate) { + this.isPrivate = isPrivate; + return this; + } + protected static String[] validateQualifiers(@Nullable String... qualifiers) { checkArgument(qualifiers != null && qualifiers.length > 0, "At least one qualifier must be provided"); return qualifiers; diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml index 1c4920b51e3..fa61bb41a3b 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml @@ -298,6 +298,14 @@ upper(p.name) like #{query.nameOrKeyUpperLikeQuery,jdbcType=VARCHAR} escape '/' ) </if> + <if test="query.private!=null"> + <if test="query.private.equals(true)"> + and p.private=${_true} + </if> + <if test="query.private.equals(false)"> + and p.private=${_false} + </if> + </if> </sql> <select id="selectDescendants" resultType="Component"> diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java index 72e33569986..7e3e3208d01 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java @@ -961,6 +961,20 @@ public class ComponentDaoTest { } @Test + public void selectByQuery_filter_on_visibility() { + db.components().insertComponent(ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setKey("private-key")); + db.components().insertComponent(ComponentTesting.newPublicProjectDto(db.getDefaultOrganization()).setKey("public-key")); + + ComponentQuery privateProjectsQuery = ComponentQuery.builder().setPrivate(true).setQualifiers(Qualifiers.PROJECT).build(); + ComponentQuery publicProjectsQuery = ComponentQuery.builder().setPrivate(false).setQualifiers(Qualifiers.PROJECT).build(); + ComponentQuery allProjectsQuery = ComponentQuery.builder().setPrivate(null).setQualifiers(Qualifiers.PROJECT).build(); + + assertThat(underTest.selectByQuery(dbSession, privateProjectsQuery, 0, 10)).extracting(ComponentDto::getKey).containsExactly("private-key"); + assertThat(underTest.selectByQuery(dbSession, publicProjectsQuery, 0, 10)).extracting(ComponentDto::getKey).containsExactly("public-key"); + assertThat(underTest.selectByQuery(dbSession, allProjectsQuery, 0, 10)).extracting(ComponentDto::getKey).containsOnly("public-key", "private-key"); + } + + @Test public void selectByQuery_on_empty_list_of_component_id() { ComponentQuery dbQuery = ComponentQuery.builder().setQualifiers(Qualifiers.PROJECT).setComponentIds(emptySet()).build(); List<ComponentDto> result = underTest.selectByQuery(dbSession, dbQuery, 0, 10); diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java index 47b94ec9082..9db9df75b8b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java @@ -31,8 +31,9 @@ import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentQuery; import org.sonar.db.organization.OrganizationDto; -import org.sonar.server.organization.DefaultOrganizationProvider; import org.sonar.db.permission.OrganizationPermission; +import org.sonar.server.organization.DefaultOrganizationProvider; +import org.sonar.server.project.Visibility; import org.sonar.server.user.UserSession; import org.sonarqube.ws.WsProjects.SearchWsResponse; import org.sonarqube.ws.client.project.SearchWsRequest; @@ -41,6 +42,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static java.util.Optional.ofNullable; import static org.sonar.api.resources.Qualifiers.PROJECT; import static org.sonar.api.resources.Qualifiers.VIEW; +import static org.sonar.core.util.Protobuf.setNullable; import static org.sonar.server.project.Visibility.PRIVATE; import static org.sonar.server.project.Visibility.PUBLIC; import static org.sonar.server.ws.WsUtils.writeProtobuf; @@ -50,6 +52,7 @@ import static org.sonarqube.ws.client.project.ProjectsWsParameters.ACTION_SEARCH import static org.sonarqube.ws.client.project.ProjectsWsParameters.MAX_PAGE_SIZE; import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ORGANIZATION; import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_QUALIFIERS; +import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_VISIBILITY; public class SearchAction implements ProjectsWsAction { @@ -84,6 +87,15 @@ public class SearchAction implements ProjectsWsAction { .setPossibleValues(PROJECT, VIEW) .setDefaultValue(PROJECT); support.addOrganizationParam(action); + + action.createParam(PARAM_VISIBILITY) + .setDescription("Filter the projects that should be visible to everyone (%s), or only specific user/groups (%s).<br/>" + + "If no visibility is specified, the default project visibility of the organization will be used.", + Visibility.PUBLIC.getLabel(), Visibility.PRIVATE.getLabel()) + .setRequired(false) + .setInternal(true) + .setSince("6.4") + .setPossibleValues(Visibility.getLabels()); } @Override @@ -98,7 +110,9 @@ public class SearchAction implements ProjectsWsAction { .setQualifiers(request.mandatoryParamAsStrings(PARAM_QUALIFIERS)) .setQuery(request.param(Param.TEXT_QUERY)) .setPage(request.mandatoryParamAsInt(Param.PAGE)) - .setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE)).build(); + .setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE)) + .setVisibility(request.param(PARAM_VISIBILITY)) + .build(); } private SearchWsResponse doHandle(SearchWsRequest request) { @@ -115,10 +129,13 @@ public class SearchAction implements ProjectsWsAction { private static ComponentQuery buildQuery(SearchWsRequest request) { List<String> qualifiers = request.getQualifiers(); - return ComponentQuery.builder() + ComponentQuery.Builder query = ComponentQuery.builder() .setNameOrKeyQuery(request.getQuery()) - .setQualifiers(qualifiers.toArray(new String[qualifiers.size()])) - .build(); + .setQualifiers(qualifiers.toArray(new String[qualifiers.size()])); + + setNullable(request.getVisibility(), v -> query.setPrivate(Visibility.isPrivate(v))); + + return query.build(); } private Paging buildPaging(DbSession dbSession, SearchWsRequest request, OrganizationDto organization, ComponentQuery query) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java index 90ce3fd69ed..603873ebddb 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java @@ -64,6 +64,7 @@ import static org.sonar.db.permission.OrganizationPermission.ADMINISTER; import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_PROFILES; import static org.sonar.test.JsonAssert.assertJson; import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ORGANIZATION; +import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_VISIBILITY; public class SearchActionTest { @@ -98,6 +99,30 @@ public class SearchActionTest { } @Test + public void search_private_projects() { + userSession.addPermission(ADMINISTER, db.getDefaultOrganization()); + db.components().insertComponents( + ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setKey("private-key"), + ComponentTesting.newPublicProjectDto(db.getDefaultOrganization()).setKey("public-key")); + + SearchWsResponse response = call(SearchWsRequest.builder().setVisibility("private").build()); + + assertThat(response.getComponentsList()).extracting(Component::getKey).containsOnly("private-key"); + } + + @Test + public void search_public_projects() { + userSession.addPermission(ADMINISTER, db.getDefaultOrganization()); + db.components().insertComponents( + ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setKey("private-key"), + ComponentTesting.newPublicProjectDto(db.getDefaultOrganization()).setKey("public-key")); + + SearchWsResponse response = call(SearchWsRequest.builder().setVisibility("public").build()); + + assertThat(response.getComponentsList()).extracting(Component::getKey).containsOnly("public-key"); + } + + @Test public void search_projects_when_no_qualifier_set() throws IOException { userSession.addPermission(ADMINISTER, db.getDefaultOrganization()); db.components().insertComponents( @@ -226,7 +251,7 @@ public class SearchActionTest { assertThat(action.isInternal()).isTrue(); assertThat(action.since()).isEqualTo("6.3"); assertThat(action.handler()).isEqualTo(ws.getDef().handler()); - assertThat(action.params()).hasSize(5); + assertThat(action.params()).hasSize(6); assertThat(action.responseExample()).isEqualTo(getClass().getResource("search-example.json")); WebService.Param organization = action.param("organization"); @@ -254,6 +279,11 @@ public class SearchActionTest { assertThat(psParam.isRequired()).isFalse(); assertThat(psParam.defaultValue()).isEqualTo("100"); assertThat(psParam.description()).isEqualTo("Page size. Must be greater than 0 and less than 500"); + + WebService.Param visibilityParam = action.param("visibility"); + assertThat(visibilityParam.isRequired()).isFalse(); + assertThat(visibilityParam.description()).isEqualTo("Filter the projects that should be visible to everyone (public), or only specific user/groups (private).<br/>" + + "If no visibility is specified, the default project visibility of the organization will be used."); } @Test @@ -281,6 +311,7 @@ public class SearchActionTest { setNullable(wsRequest.getQuery(), query -> request.setParam(TEXT_QUERY, query)); setNullable(wsRequest.getPage(), page -> request.setParam(PAGE, String.valueOf(page))); setNullable(wsRequest.getPageSize(), pageSize -> request.setParam(PAGE_SIZE, String.valueOf(pageSize))); + setNullable(wsRequest.getVisibility(), v -> request.setParam(PARAM_VISIBILITY, v)); return request.executeProtobuf(SearchWsResponse.class); } |