aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>2017-11-23 16:51:17 +0100
committerTeryk Bellahsene <teryk@users.noreply.github.com>2017-11-29 17:27:53 +0100
commit239a835a35e8df6504be145c5994358874b4ec5c (patch)
tree391117d97c5c7c45ae301a93434b908d1ce800d9
parenta8d35ff57c84a084268cac3937729536f60e0cd7 (diff)
downloadsonarqube-239a835a35e8df6504be145c5994358874b4ec5c.tar.gz
sonarqube-239a835a35e8df6504be145c5994358874b4ec5c.zip
SONAR-9000 Filter on membership in WS api/organizations/search
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationQuery.java23
-rw-r--r--server/sonar-db-dao/src/main/resources/org/sonar/db/organization/OrganizationMapper.xml4
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationDaoTest.java36
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/organization/ws/SearchAction.java36
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/organization/ws/SearchActionTest.java69
5 files changed, 135 insertions, 33 deletions
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationQuery.java b/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationQuery.java
index cfa220de493..79ded911581 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationQuery.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/organization/OrganizationQuery.java
@@ -30,9 +30,21 @@ import static org.sonar.core.util.stream.MoreCollectors.toSet;
public class OrganizationQuery {
private static final OrganizationQuery NO_QUERY = newOrganizationQueryBuilder().build();
private final Set<String> keys;
+ private final Integer userId;
private OrganizationQuery(Builder builder) {
this.keys = builder.keys;
+ this.userId = builder.member;
+ }
+
+ @CheckForNull
+ public Set<String> getKeys() {
+ return keys;
+ }
+
+ @CheckForNull
+ public Integer getMember() {
+ return userId;
}
public static OrganizationQuery returnAll() {
@@ -43,13 +55,9 @@ public class OrganizationQuery {
return new Builder();
}
- @CheckForNull
- public Set<String> getKeys() {
- return keys;
- }
-
public static class Builder {
private Set<String> keys;
+ private Integer member;
private Builder() {
// use static factory method
@@ -64,6 +72,11 @@ public class OrganizationQuery {
return this;
}
+ public Builder setMember(@Nullable Integer userId) {
+ this.member = userId;
+ return this;
+ }
+
public OrganizationQuery build() {
return new OrganizationQuery(this);
}
diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/organization/OrganizationMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/organization/OrganizationMapper.xml
index 457d2639594..4f23af35bea 100644
--- a/server/sonar-db-dao/src/main/resources/org/sonar/db/organization/OrganizationMapper.xml
+++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/organization/OrganizationMapper.xml
@@ -97,6 +97,10 @@
<sql id="sqlSelectByQuery">
from organizations org
+ <if test="query.member != null">
+ inner join organization_members om on org.uuid=om.organization_uuid
+ and om.user_id=#{query.member,jdbcType=INTEGER}
+ </if>
<where>
<if test="query.keys != null">
org.kee in
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationDaoTest.java
index 12740780895..a747b2a82bf 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationDaoTest.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/organization/OrganizationDaoTest.java
@@ -499,6 +499,42 @@ public class OrganizationDaoTest {
}
@Test
+ public void selectByQuery_filter_on_a_member() {
+ OrganizationDto organization = dbTester.organizations().insert();
+ OrganizationDto anotherOrganization = dbTester.organizations().insert();
+ OrganizationDto organizationWithoutMember = dbTester.organizations().insert();
+ UserDto user = dbTester.users().insertUser();
+ dbTester.organizations().addMember(organization, user);
+ dbTester.organizations().addMember(anotherOrganization, user);
+
+ List<OrganizationDto> result = underTest.selectByQuery(dbSession, OrganizationQuery.newOrganizationQueryBuilder().setMember(user.getId()).build(), forPage(1).andSize(100));
+
+ assertThat(result).extracting(OrganizationDto::getUuid)
+ .containsExactlyInAnyOrder(organization.getUuid(), anotherOrganization.getUuid())
+ .doesNotContain(organizationWithoutMember.getUuid());
+ }
+
+ @Test
+ public void selectByQuery_filter_on_a_member_and_keys() {
+ OrganizationDto organization = dbTester.organizations().insert();
+ OrganizationDto anotherOrganization = dbTester.organizations().insert();
+ OrganizationDto organizationWithoutKeyProvided = dbTester.organizations().insert();
+ OrganizationDto organizationWithoutMember = dbTester.organizations().insert();
+ UserDto user = dbTester.users().insertUser();
+ dbTester.organizations().addMember(organization, user);
+ dbTester.organizations().addMember(anotherOrganization, user);
+ dbTester.organizations().addMember(organizationWithoutKeyProvided, user);
+
+ List<OrganizationDto> result = underTest.selectByQuery(dbSession, OrganizationQuery.newOrganizationQueryBuilder()
+ .setKeys(Arrays.asList(organization.getKey(), anotherOrganization.getKey(), organizationWithoutMember.getKey()))
+ .setMember(user.getId()).build(), forPage(1).andSize(100));
+
+ assertThat(result).extracting(OrganizationDto::getUuid)
+ .containsExactlyInAnyOrder(organization.getUuid(), anotherOrganization.getUuid())
+ .doesNotContain(organizationWithoutKeyProvided.getUuid(), organizationWithoutMember.getUuid());
+ }
+
+ @Test
public void getDefaultTemplates_returns_empty_when_table_is_empty() {
assertThat(underTest.getDefaultTemplates(dbSession, ORGANIZATION_DTO_1.getUuid())).isEmpty();
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/organization/ws/SearchAction.java
index 957bf0d7111..edceff388b5 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/organization/ws/SearchAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/organization/ws/SearchAction.java
@@ -20,6 +20,7 @@
package org.sonar.server.organization.ws;
import java.util.List;
+import javax.annotation.CheckForNull;
import org.sonar.api.server.ws.Change;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
@@ -29,6 +30,7 @@ import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.organization.OrganizationQuery;
+import org.sonar.server.user.UserSession;
import org.sonarqube.ws.Organizations;
import org.sonarqube.ws.Organizations.Organization;
@@ -39,16 +41,18 @@ import static org.sonar.server.ws.WsUtils.writeProtobuf;
import static org.sonarqube.ws.Common.Paging;
public class SearchAction implements OrganizationsWsAction {
- private static final String PARAM_ORGANIZATIONS = "organizations";
- private static final String PARAM_MEMBER = "member";
+ static final String PARAM_ORGANIZATIONS = "organizations";
+ static final String PARAM_MEMBER = "member";
private static final String ACTION = "search";
private static final int MAX_SIZE = 500;
private final DbClient dbClient;
+ private final UserSession userSession;
private final OrganizationsWsSupport wsSupport;
- public SearchAction(DbClient dbClient, OrganizationsWsSupport wsSupport) {
+ public SearchAction(DbClient dbClient, UserSession userSession, OrganizationsWsSupport wsSupport) {
this.dbClient = dbClient;
+ this.userSession = userSession;
this.wsSupport = wsSupport;
}
@@ -70,22 +74,30 @@ public class SearchAction implements OrganizationsWsAction {
.setRequired(false)
.setSince("6.3");
+ action.createParam(PARAM_MEMBER)
+ .setDescription("Filter organizations based on whether the authenticated user is a member. If false, no filter applies.")
+ .setSince("7.0")
+ .setDefaultValue(String.valueOf(false))
+ .setBooleanPossibleValues();
+
action.addPagingParams(100, MAX_SIZE);
}
@Override
public void handle(Request request, Response response) throws Exception {
try (DbSession dbSession = dbClient.openSession(false)) {
+ Integer userId = getUserIdIfFilterMembership(request);
List<String> organizations = getOrganizationKeys(request);
- OrganizationQuery organizationQuery = newOrganizationQueryBuilder()
+ OrganizationQuery dbQuery = newOrganizationQueryBuilder()
.setKeys(organizations)
+ .setMember(userId)
.build();
- int total = dbClient.organizationDao().countByQuery(dbSession, organizationQuery);
+ int total = dbClient.organizationDao().countByQuery(dbSession, dbQuery);
Paging paging = buildWsPaging(request, total);
List<OrganizationDto> dtos = dbClient.organizationDao().selectByQuery(
dbSession,
- organizationQuery,
+ dbQuery,
forPage(paging.getPageIndex()).andSize(paging.getPageSize()));
writeResponse(request, response, dtos, paging);
}
@@ -107,6 +119,18 @@ public class SearchAction implements OrganizationsWsAction {
.build();
}
+ @CheckForNull
+ private Integer getUserIdIfFilterMembership(Request request) {
+ boolean filterOnAuthenticatedUser = request.mandatoryParamAsBoolean(PARAM_MEMBER);
+ if (!filterOnAuthenticatedUser) {
+ return null;
+ }
+
+ userSession.checkLoggedIn();
+ return userSession.getUserId();
+ }
+
+ @CheckForNull
private static List<String> getOrganizationKeys(Request request) {
List<String> organizations = request.paramAsStrings(PARAM_ORGANIZATIONS);
if (organizations != null) {
diff --git a/server/sonar-server/src/test/java/org/sonar/server/organization/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/organization/ws/SearchActionTest.java
index 62b0a59d998..77adf57e92e 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/organization/ws/SearchActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/organization/ws/SearchActionTest.java
@@ -35,7 +35,9 @@ import org.sonar.core.util.Uuids;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
+import org.sonar.db.user.UserDto;
import org.sonar.server.organization.OrganizationValidationImpl;
+import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsActionTester;
import org.sonarqube.ws.Common.Paging;
@@ -47,6 +49,7 @@ import static java.lang.String.valueOf;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import static org.sonar.server.organization.ws.SearchAction.PARAM_MEMBER;
import static org.sonar.test.JsonAssert.assertJson;
public class SearchActionTest {
@@ -64,23 +67,25 @@ public class SearchActionTest {
private System2 system2 = mock(System2.class);
@Rule
- public DbTester dbTester = DbTester.create(system2).setDisableDefaultOrganization(true);
+ public UserSessionRule userSession = UserSessionRule.standalone();
+ @Rule
+ public DbTester db = DbTester.create(system2).setDisableDefaultOrganization(true);
@Rule
public ExpectedException expectedException = ExpectedException.none();
- private SearchAction underTest = new SearchAction(dbTester.getDbClient(), new OrganizationsWsSupport(new OrganizationValidationImpl()));
- private WsActionTester wsTester = new WsActionTester(underTest);
+ private SearchAction underTest = new SearchAction(db.getDbClient(), userSession, new OrganizationsWsSupport(new OrganizationValidationImpl()));
+ private WsActionTester ws = new WsActionTester(underTest);
@Test
- public void verify_define() {
- WebService.Action action = wsTester.getDef();
+ public void definition() {
+ WebService.Action action = ws.getDef();
assertThat(action.key()).isEqualTo("search");
assertThat(action.isPost()).isFalse();
assertThat(action.description()).isEqualTo("Search for organizations");
assertThat(action.isInternal()).isTrue();
assertThat(action.since()).isEqualTo("6.2");
assertThat(action.handler()).isEqualTo(underTest);
- assertThat(action.params()).hasSize(3);
+ assertThat(action.params()).hasSize(4);
assertThat(action.responseExample()).isEqualTo(getClass().getResource("search-example.json"));
WebService.Param organizations = action.param("organizations");
@@ -100,6 +105,11 @@ public class SearchActionTest {
assertThat(pageSize.defaultValue()).isEqualTo("100");
assertThat(pageSize.maximumValue()).isEqualTo(500);
assertThat(pageSize.description()).isEqualTo("Page size. Must be greater than 0 and less than 500");
+
+ WebService.Param member = action.param("member");
+ assertThat(member.since()).isEqualTo("7.0");
+ assertThat(member.defaultValue()).isEqualTo(String.valueOf(false));
+ assertThat(member.isRequired()).isFalse();
}
@Test
@@ -119,9 +129,12 @@ public class SearchActionTest {
.setName("Foo Company")
.setGuarded(true));
- String response = executeJsonRequest(null, 25);
+ TestRequest request = ws.newRequest()
+ .setMediaType(MediaTypes.JSON);
+ populateRequest(request, null, 25);
+ String response = request.execute().getInput();
- assertJson(response).isSimilarTo(wsTester.getDef().responseExampleAsString());
+ assertJson(response).isSimilarTo(ws.getDef().responseExampleAsString());
}
@Test
@@ -213,19 +226,19 @@ public class SearchActionTest {
insertOrganization(ORGANIZATION_DTO.setUuid("uuid5").setKey("key-5"));
insertOrganization(ORGANIZATION_DTO.setUuid("uuid4").setKey("key-4"));
- SearchWsResponse response = executeRequest(1, 1, "key-1", "key-3", "key-5");
+ SearchWsResponse response = call(1, 1, "key-1", "key-3", "key-5");
assertThat(response.getOrganizationsList()).extracting(Organization::getKey).containsOnly("key-5");
assertThat(response.getPaging()).extracting(Paging::getPageIndex, Paging::getPageSize, Paging::getTotal).containsOnly(1, 1, 3);
- response = executeRequest(1, 2, "key-1", "key-3", "key-5");
+ response = call(1, 2, "key-1", "key-3", "key-5");
assertThat(response.getOrganizationsList()).extracting(Organization::getKey).containsOnly("key-5", "key-1");
assertThat(response.getPaging()).extracting(Paging::getPageIndex, Paging::getPageSize, Paging::getTotal).containsOnly(1, 2, 3);
- response = executeRequest(2, 2, "key-1", "key-3", "key-5");
+ response = call(2, 2, "key-1", "key-3", "key-5");
assertThat(response.getOrganizationsList()).extracting(Organization::getKey).containsOnly("key-3");
assertThat(response.getPaging()).extracting(Paging::getPageIndex, Paging::getPageSize, Paging::getTotal).containsOnly(2, 2, 3);
- response = executeRequest(null, null);
+ response = call(null, null);
assertThat(response.getOrganizationsList()).extracting(Organization::getKey).hasSize(5);
assertThat(response.getPaging()).extracting(Paging::getPageIndex, Paging::getPageSize, Paging::getTotal).containsOnly(1, 100, 5);
}
@@ -240,27 +253,39 @@ public class SearchActionTest {
.containsExactly(ORGANIZATION_DTO.getKey());
}
+ @Test
+ public void filter_organization_user_is_member_of() {
+ UserDto user = db.users().insertUser();
+ userSession.logIn(user);
+ OrganizationDto organization = db.organizations().insert();
+ OrganizationDto organizationWithoutMember = db.organizations().insert();
+ db.organizations().addMember(organization, user);
+
+ SearchWsResponse result = call(ws.newRequest().setParam(PARAM_MEMBER, String.valueOf(true)));
+
+ assertThat(result.getOrganizationsList()).extracting(Organization::getKey)
+ .containsExactlyInAnyOrder(organization.getKey())
+ .doesNotContain(organizationWithoutMember.getKey());
+ }
+
private List<Organization> executeRequestAndReturnList(@Nullable Integer page, @Nullable Integer pageSize, String... keys) {
- return executeRequest(page, pageSize, keys).getOrganizationsList();
+ return call(page, pageSize, keys).getOrganizationsList();
}
- private SearchWsResponse executeRequest(@Nullable Integer page, @Nullable Integer pageSize, String... keys) {
- TestRequest request = wsTester.newRequest();
- populateRequest(request, page, pageSize, keys);
+ private SearchWsResponse call(TestRequest request) {
return request.executeProtobuf(SearchWsResponse.class);
}
private void insertOrganization(OrganizationDto dto) {
- DbSession dbSession = dbTester.getSession();
- dbTester.getDbClient().organizationDao().insert(dbSession, dto, false);
+ DbSession dbSession = db.getSession();
+ db.getDbClient().organizationDao().insert(dbSession, dto, false);
dbSession.commit();
}
- private String executeJsonRequest(@Nullable Integer page, @Nullable Integer pageSize, String... keys) {
- TestRequest request = wsTester.newRequest()
- .setMediaType(MediaTypes.JSON);
+ private SearchWsResponse call(@Nullable Integer page, @Nullable Integer pageSize, String... keys) {
+ TestRequest request = ws.newRequest();
populateRequest(request, page, pageSize, keys);
- return request.execute().getInput();
+ return call(request);
}
private void populateRequest(TestRequest request, @Nullable Integer page, @Nullable Integer pageSize, String... keys) {