aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>2017-05-08 19:31:41 +0200
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>2017-05-08 19:31:41 +0200
commitd83ff5e2042f848a1640e84ecb30a867311cfae6 (patch)
tree1e614e9b16806824141f86d2f2d5364ed44d8c74 /server
parentf16ba7b4228e0908d7dd7495be1d3905b14b577d (diff)
downloadsonarqube-d83ff5e2042f848a1640e84ecb30a867311cfae6.tar.gz
sonarqube-d83ff5e2042f848a1640e84ecb30a867311cfae6.zip
SONAR-9182 Add visibility to WS api/projects/search
Diffstat (limited to 'server')
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/component/ComponentQuery.java14
-rw-r--r--server/sonar-db-dao/src/main/resources/org/sonar/db/component/ComponentMapper.xml8
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/component/ComponentDaoTest.java14
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java27
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java33
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);
}