aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>2017-11-24 10:24:41 +0100
committerTeryk Bellahsene <teryk@users.noreply.github.com>2017-11-29 17:27:53 +0100
commitdb8fa0acfd35ecaf87f7a2295d35475b7956a350 (patch)
tree4e24c2609ded35906f82524c0772dd8b9048a6b1 /server
parent239a835a35e8df6504be145c5994358874b4ec5c (diff)
downloadsonarqube-db8fa0acfd35ecaf87f7a2295d35475b7956a350.tar.gz
sonarqube-db8fa0acfd35ecaf87f7a2295d35475b7956a350.zip
SONAR-9000 Add admin action to WS api/organizations/search
Diffstat (limited to 'server')
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/organization/ws/OrganizationsWsSupport.java11
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/organization/ws/SearchAction.java73
-rw-r--r--server/sonar-server/src/main/resources/org/sonar/server/organization/ws/search-example.json6
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/organization/ws/SearchActionTest.java81
4 files changed, 97 insertions, 74 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/ws/OrganizationsWsSupport.java b/server/sonar-server/src/main/java/org/sonar/server/organization/ws/OrganizationsWsSupport.java
index 7fff042cb82..cd4981c921b 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/organization/ws/OrganizationsWsSupport.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/organization/ws/OrganizationsWsSupport.java
@@ -24,7 +24,7 @@ import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.WebService;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.server.organization.OrganizationValidation;
-import org.sonarqube.ws.Organizations;
+import org.sonarqube.ws.Organizations.Organization;
import static org.sonar.core.util.Protobuf.setNullable;
import static org.sonar.server.organization.OrganizationValidation.DESCRIPTION_MAX_LENGTH;
@@ -107,19 +107,18 @@ public class OrganizationsWsSupport {
.setExampleValue("https://www.foo.com/foo.png");
}
- Organizations.Organization toOrganization(OrganizationDto dto) {
- return toOrganization(Organizations.Organization.newBuilder(), dto);
+ Organization.Builder toOrganization(OrganizationDto dto) {
+ return toOrganization(Organization.newBuilder(), dto);
}
- Organizations.Organization toOrganization(Organizations.Organization.Builder builder, OrganizationDto dto) {
+ Organization.Builder toOrganization(Organization.Builder builder, OrganizationDto dto) {
builder
- .clear()
.setName(dto.getName())
.setKey(dto.getKey())
.setGuarded(dto.isGuarded());
setNullable(dto.getDescription(), builder::setDescription);
setNullable(dto.getUrl(), builder::setUrl);
setNullable(dto.getAvatarUrl(), builder::setAvatar);
- return builder.build();
+ return builder;
}
}
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 edceff388b5..0adba4dfacd 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 java.util.Set;
import javax.annotation.CheckForNull;
import org.sonar.api.server.ws.Change;
import org.sonar.api.server.ws.Request;
@@ -34,9 +35,11 @@ import org.sonar.server.user.UserSession;
import org.sonarqube.ws.Organizations;
import org.sonarqube.ws.Organizations.Organization;
+import static java.util.Collections.emptySet;
+import static org.sonar.core.util.stream.MoreCollectors.toSet;
import static org.sonar.db.Pagination.forPage;
import static org.sonar.db.organization.OrganizationQuery.newOrganizationQueryBuilder;
-import static org.sonar.server.ws.WsUtils.checkRequest;
+import static org.sonar.db.permission.OrganizationPermission.ADMINISTER;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
import static org.sonarqube.ws.Common.Paging;
@@ -70,7 +73,7 @@ public class SearchAction implements OrganizationsWsAction {
action.createParam(PARAM_ORGANIZATIONS)
.setDescription("Comma-separated list of organization keys")
.setExampleValue(String.join(",", "my-org-1", "foocorp"))
- .setMinimumLength(2)
+ .setMaxValuesAllowed(MAX_SIZE)
.setRequired(false)
.setSince("6.3");
@@ -86,29 +89,40 @@ public class SearchAction implements OrganizationsWsAction {
@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 dbQuery = newOrganizationQueryBuilder()
- .setKeys(organizations)
- .setMember(userId)
- .build();
-
+ OrganizationQuery dbQuery = buildDbQuery(request);
int total = dbClient.organizationDao().countByQuery(dbSession, dbQuery);
Paging paging = buildWsPaging(request, total);
- List<OrganizationDto> dtos = dbClient.organizationDao().selectByQuery(
- dbSession,
- dbQuery,
- forPage(paging.getPageIndex()).andSize(paging.getPageSize()));
- writeResponse(request, response, dtos, paging);
+ List<OrganizationDto> organizations = dbClient.organizationDao().selectByQuery(dbSession, dbQuery, forPage(paging.getPageIndex()).andSize(paging.getPageSize()));
+ Set<String> adminOrganizationUuids = searchOrganizationWithAdminPermission(dbSession);
+ writeResponse(request, response, organizations, adminOrganizationUuids, paging);
}
}
- private void writeResponse(Request request, Response response, List<OrganizationDto> dtos, Paging paging) {
- Organizations.SearchWsResponse.Builder responseBuilder = Organizations.SearchWsResponse.newBuilder();
- responseBuilder.setPaging(paging);
- Organization.Builder organizationBuilder = Organization.newBuilder();
- dtos.forEach(dto -> responseBuilder.addOrganizations(wsSupport.toOrganization(organizationBuilder, dto)));
- writeProtobuf(responseBuilder.build(), request, response);
+ private OrganizationQuery buildDbQuery(Request request) {
+ return newOrganizationQueryBuilder()
+ .setKeys(request.paramAsStrings(PARAM_ORGANIZATIONS))
+ .setMember(getUserIdIfFilterOnMembership(request))
+ .build();
+ }
+
+ private Set<String> searchOrganizationWithAdminPermission(DbSession dbSession) {
+ Integer userId = userSession.getUserId();
+ return userId == null ? emptySet()
+ : dbClient.organizationDao().selectByPermission(dbSession, userId, ADMINISTER.getKey()).stream().map(OrganizationDto::getUuid).collect(toSet());
+ }
+
+ private void writeResponse(Request httpRequest, Response httpResponse, List<OrganizationDto> organizations, Set<String> adminOrganizationUuids, Paging paging) {
+ Organizations.SearchWsResponse.Builder response = Organizations.SearchWsResponse.newBuilder();
+ response.setPaging(paging);
+ Organization.Builder wsOrganization = Organization.newBuilder();
+ organizations
+ .forEach(o -> {
+ boolean isAdmin = adminOrganizationUuids.contains(o.getUuid());
+ wsOrganization.clear();
+ wsOrganization.setIsAdmin(isAdmin);
+ response.addOrganizations(wsSupport.toOrganization(wsOrganization, o));
+ });
+ writeProtobuf(response.build(), httpRequest, httpResponse);
}
private static Paging buildWsPaging(Request request, int total) {
@@ -120,23 +134,8 @@ public class SearchAction implements OrganizationsWsAction {
}
@CheckForNull
- private Integer getUserIdIfFilterMembership(Request request) {
+ private Integer getUserIdIfFilterOnMembership(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) {
- checkRequest(organizations.size() <= MAX_SIZE, "Size of '%s' (%d) must be less than %d", PARAM_ORGANIZATIONS, organizations.size(), MAX_SIZE);
- }
- return organizations;
+ return (userSession.isLoggedIn() && filterOnAuthenticatedUser) ? userSession.getUserId() : null;
}
-
}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/organization/ws/search-example.json b/server/sonar-server/src/main/resources/org/sonar/server/organization/ws/search-example.json
index 84a79a7e84a..481ae34e9ef 100644
--- a/server/sonar-server/src/main/resources/org/sonar/server/organization/ws/search-example.json
+++ b/server/sonar-server/src/main/resources/org/sonar/server/organization/ws/search-example.json
@@ -8,7 +8,8 @@
{
"key": "foo-company",
"name": "Foo Company",
- "guarded": true
+ "guarded": true,
+ "isAdmin": false
},
{
"key": "bar-company",
@@ -16,7 +17,8 @@
"description": "The Bar company produces quality software too.",
"url": "https://www.bar.com",
"avatar": "https://www.bar.com/logo.png",
- "guarded": false
+ "guarded": false,
+ "isAdmin": true
}
]
}
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 77adf57e92e..8eedbae42ec 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
@@ -32,9 +32,9 @@ import org.junit.rules.ExpectedException;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
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.GroupDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.organization.OrganizationValidationImpl;
import org.sonar.server.tester.UserSessionRule;
@@ -47,8 +47,10 @@ import org.sonarqube.ws.Organizations.SearchWsResponse;
import static java.lang.String.valueOf;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import static org.sonar.db.permission.OrganizationPermission.ADMINISTER;
import static org.sonar.server.organization.ws.SearchAction.PARAM_MEMBER;
import static org.sonar.test.JsonAssert.assertJson;
@@ -94,6 +96,7 @@ public class SearchActionTest {
assertThat(organizations.description()).isEqualTo("Comma-separated list of organization keys");
assertThat(organizations.exampleValue()).isEqualTo("my-org-1,foocorp");
assertThat(organizations.since()).isEqualTo("6.3");
+ assertThat(organizations.maxValuesAllowed()).isEqualTo(500);
WebService.Param page = action.param("p");
assertThat(page.isRequired()).isFalse();
@@ -113,9 +116,9 @@ public class SearchActionTest {
}
@Test
- public void verify_response_example() throws URISyntaxException, IOException {
+ public void json_example() throws URISyntaxException, IOException {
when(system2.now()).thenReturn(SOME_DATE, SOME_DATE + 1000);
- insertOrganization(new OrganizationDto()
+ OrganizationDto barOrganization = db.organizations().insert(new OrganizationDto()
.setUuid(Uuids.UUID_EXAMPLE_02)
.setKey("bar-company")
.setName("Bar Company")
@@ -123,18 +126,44 @@ public class SearchActionTest {
.setUrl("https://www.bar.com")
.setAvatarUrl("https://www.bar.com/logo.png")
.setGuarded(false));
- insertOrganization(new OrganizationDto()
+ OrganizationDto fooOrganization = db.organizations().insert(new OrganizationDto()
.setUuid(Uuids.UUID_EXAMPLE_01)
.setKey("foo-company")
.setName("Foo Company")
.setGuarded(true));
+ UserDto user = db.users().insertUser();
+ db.organizations().addMember(barOrganization, user);
+ db.organizations().addMember(fooOrganization, user);
+ db.users().insertPermissionOnUser(barOrganization, user, ADMINISTER);
+ userSession.logIn(user).addPermission(ADMINISTER, barOrganization);
TestRequest request = ws.newRequest()
.setMediaType(MediaTypes.JSON);
populateRequest(request, null, 25);
- String response = request.execute().getInput();
+ String result = request.execute().getInput();
- assertJson(response).isSimilarTo(ws.getDef().responseExampleAsString());
+ assertJson(ws.getDef().responseExampleAsString()).isSimilarTo(result);
+ assertJson(result).isSimilarTo(ws.getDef().responseExampleAsString());
+ }
+
+ @Test
+ public void is_admin_available_for_each_organization() {
+ OrganizationDto userAdminOrganization = db.organizations().insert();
+ OrganizationDto groupAdminOrganization = db.organizations().insert();
+ OrganizationDto browseOrganization = db.organizations().insert();
+ UserDto user = db.users().insertUser();
+ GroupDto group = db.users().insertGroup(groupAdminOrganization);
+ db.users().insertMember(group, user);
+ userSession.logIn(user).addPermission(ADMINISTER, userAdminOrganization);
+ db.users().insertPermissionOnUser(userAdminOrganization, user, ADMINISTER);
+ db.users().insertPermissionOnGroup(group, ADMINISTER);
+
+ SearchWsResponse result = call(ws.newRequest());
+
+ assertThat(result.getOrganizationsList()).extracting(Organization::getKey, Organization::getIsAdmin).containsExactlyInAnyOrder(
+ tuple(userAdminOrganization.getKey(), true),
+ tuple(browseOrganization.getKey(), false),
+ tuple(groupAdminOrganization.getKey(), true));
}
@Test
@@ -150,7 +179,7 @@ public class SearchActionTest {
@Test
public void request_returns_empty_on_table_with_single_row_when_not_requesting_the_first_page() {
when(system2.now()).thenReturn(SOME_DATE);
- insertOrganization(ORGANIZATION_DTO);
+ db.organizations().insert(ORGANIZATION_DTO);
assertThat(executeRequestAndReturnList(2, null)).isEmpty();
assertThat(executeRequestAndReturnList(2, 1)).isEmpty();
@@ -162,11 +191,11 @@ public class SearchActionTest {
@Test
public void request_returns_rows_ordered_by_createdAt_descending_applying_requested_paging() {
when(system2.now()).thenReturn(SOME_DATE, SOME_DATE + 1_000, SOME_DATE + 2_000, SOME_DATE + 3_000, SOME_DATE + 5_000);
- insertOrganization(ORGANIZATION_DTO.setUuid("uuid3").setKey("key-3"));
- insertOrganization(ORGANIZATION_DTO.setUuid("uuid1").setKey("key-1"));
- insertOrganization(ORGANIZATION_DTO.setUuid("uuid2").setKey("key-2"));
- insertOrganization(ORGANIZATION_DTO.setUuid("uuid5").setKey("key-5"));
- insertOrganization(ORGANIZATION_DTO.setUuid("uuid4").setKey("key-4"));
+ db.organizations().insert(ORGANIZATION_DTO.setUuid("uuid3").setKey("key-3"));
+ db.organizations().insert(ORGANIZATION_DTO.setUuid("uuid1").setKey("key-1"));
+ db.organizations().insert(ORGANIZATION_DTO.setUuid("uuid2").setKey("key-2"));
+ db.organizations().insert(ORGANIZATION_DTO.setUuid("uuid5").setKey("key-5"));
+ db.organizations().insert(ORGANIZATION_DTO.setUuid("uuid4").setKey("key-4"));
assertThat(executeRequestAndReturnList(1, 1))
.extracting(Organization::getKey)
@@ -202,11 +231,11 @@ public class SearchActionTest {
@Test
public void request_returns_only_specified_keys_ordered_by_createdAt_when_filtering_keys() {
when(system2.now()).thenReturn(SOME_DATE, SOME_DATE + 1_000, SOME_DATE + 2_000, SOME_DATE + 3_000, SOME_DATE + 5_000);
- insertOrganization(ORGANIZATION_DTO.setUuid("uuid3").setKey("key-3"));
- insertOrganization(ORGANIZATION_DTO.setUuid("uuid1").setKey("key-1"));
- insertOrganization(ORGANIZATION_DTO.setUuid("uuid2").setKey("key-2"));
- insertOrganization(ORGANIZATION_DTO.setUuid("uuid5").setKey("key-5"));
- insertOrganization(ORGANIZATION_DTO.setUuid("uuid4").setKey("key-4"));
+ db.organizations().insert(ORGANIZATION_DTO.setUuid("uuid3").setKey("key-3"));
+ db.organizations().insert(ORGANIZATION_DTO.setUuid("uuid1").setKey("key-1"));
+ db.organizations().insert(ORGANIZATION_DTO.setUuid("uuid2").setKey("key-2"));
+ db.organizations().insert(ORGANIZATION_DTO.setUuid("uuid5").setKey("key-5"));
+ db.organizations().insert(ORGANIZATION_DTO.setUuid("uuid4").setKey("key-4"));
assertThat(executeRequestAndReturnList(1, 10, "key-3", "key-1", "key-5"))
.extracting(Organization::getKey)
@@ -220,11 +249,11 @@ public class SearchActionTest {
@Test
public void result_is_paginated() {
when(system2.now()).thenReturn(SOME_DATE, SOME_DATE + 1_000, SOME_DATE + 2_000, SOME_DATE + 3_000, SOME_DATE + 5_000);
- insertOrganization(ORGANIZATION_DTO.setUuid("uuid3").setKey("key-3"));
- insertOrganization(ORGANIZATION_DTO.setUuid("uuid1").setKey("key-1"));
- insertOrganization(ORGANIZATION_DTO.setUuid("uuid2").setKey("key-2"));
- insertOrganization(ORGANIZATION_DTO.setUuid("uuid5").setKey("key-5"));
- insertOrganization(ORGANIZATION_DTO.setUuid("uuid4").setKey("key-4"));
+ db.organizations().insert(ORGANIZATION_DTO.setUuid("uuid3").setKey("key-3"));
+ db.organizations().insert(ORGANIZATION_DTO.setUuid("uuid1").setKey("key-1"));
+ db.organizations().insert(ORGANIZATION_DTO.setUuid("uuid2").setKey("key-2"));
+ db.organizations().insert(ORGANIZATION_DTO.setUuid("uuid5").setKey("key-5"));
+ db.organizations().insert(ORGANIZATION_DTO.setUuid("uuid4").setKey("key-4"));
SearchWsResponse response = call(1, 1, "key-1", "key-3", "key-5");
assertThat(response.getOrganizationsList()).extracting(Organization::getKey).containsOnly("key-5");
@@ -246,7 +275,7 @@ public class SearchActionTest {
@Test
public void request_returns_empty_when_filtering_on_non_existing_key() {
when(system2.now()).thenReturn(SOME_DATE);
- insertOrganization(ORGANIZATION_DTO);
+ db.organizations().insert(ORGANIZATION_DTO);
assertThat(executeRequestAndReturnList(1, 10, ORGANIZATION_DTO.getKey()))
.extracting(Organization::getKey)
@@ -276,12 +305,6 @@ public class SearchActionTest {
return request.executeProtobuf(SearchWsResponse.class);
}
- private void insertOrganization(OrganizationDto dto) {
- DbSession dbSession = db.getSession();
- db.getDbClient().organizationDao().insert(dbSession, dto, false);
- dbSession.commit();
- }
-
private SearchWsResponse call(@Nullable Integer page, @Nullable Integer pageSize, String... keys) {
TestRequest request = ws.newRequest();
populateRequest(request, page, pageSize, keys);