+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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.organization;
-
-import org.sonar.api.ce.ComputeEngineSide;
-import org.sonar.api.server.ServerSide;
-import org.sonar.api.utils.MessageException;
-
-import static java.util.Objects.requireNonNull;
-
-/**
- * Available checks that will be done by the billing plugin.
- * When the billing plugin is not loaded, no check will be done.
- * This is not the interface that should be implemented by the plugin, but {@link BillingValidationsExtension}
- */
-@ComputeEngineSide
-@ServerSide
-public interface BillingValidations {
-
- /**
- * @throws BillingValidationsException when projects analysis on organization is not allowed
- */
- void checkBeforeProjectAnalysis(Organization organization);
-
- /**
- * @throws BillingValidationsException when the organization cannot use private projects
- */
- void checkCanUpdateProjectVisibility(Organization organization, boolean updateToPrivate);
-
- /**
- * @return true if the organization can use private projects
- */
- boolean canUpdateProjectVisibilityToPrivate(Organization organization);
-
- /**
- * Actions to do on an organization deletion
- */
- void onDelete(Organization organization);
-
- class Organization {
- private final String key;
- private final String uuid;
- private final String name;
-
- public Organization(String key, String uuid, String name) {
- this.key = requireNonNull(key, "Organization key cannot be null");
- this.uuid = requireNonNull(uuid, "Organization uuid cannot be null");
- this.name = requireNonNull(name, "Organization name cannot be null");
- }
-
- public String getKey() {
- return key;
- }
-
- public String getUuid() {
- return uuid;
- }
-
- public String getName() {
- return name;
- }
- }
-
- class BillingValidationsException extends MessageException {
- public BillingValidationsException(String message) {
- super(message);
- }
-
- /**
- * Does not fill in the stack trace
- *
- * @see java.lang.Throwable#fillInStackTrace()
- */
- @Override
- public synchronized Throwable fillInStackTrace() {
- return this;
- }
-
- @Override
- public String toString() {
- return getMessage();
- }
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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.organization;
-
-import org.sonar.api.ExtensionPoint;
-import org.sonar.api.ce.ComputeEngineSide;
-import org.sonar.api.server.ServerSide;
-
-/**
- * The billing plugin must implement this interface
- */
-@ServerSide
-@ComputeEngineSide
-@ExtensionPoint
-public interface BillingValidationsExtension extends BillingValidations {
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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.organization;
-
-import org.sonar.api.ce.ComputeEngineSide;
-import org.sonar.api.server.ServerSide;
-
-/**
- * The goal of this class is to handle the 2 different use case :
- * - The billing plugin exists, the proxy will redirect method calls to the plugin
- * - No billing plugin, every methods won't do anything
- */
-@ServerSide
-@ComputeEngineSide
-public interface BillingValidationsProxy extends BillingValidations {
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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.organization;
-
-import javax.annotation.Nullable;
-
-public class BillingValidationsProxyImpl implements BillingValidationsProxy {
-
- @Nullable
- private final BillingValidationsExtension billingValidationsExtension;
-
- public BillingValidationsProxyImpl(BillingValidationsExtension e) {
- this.billingValidationsExtension = e;
- }
-
- // Used when no plugin is providing the extension
- public BillingValidationsProxyImpl() {
- this.billingValidationsExtension = null;
- }
-
- @Override
- public void checkBeforeProjectAnalysis(Organization organization) {
- if (billingValidationsExtension == null) {
- return;
- }
- billingValidationsExtension.checkBeforeProjectAnalysis(organization);
- }
-
- @Override
- public void checkCanUpdateProjectVisibility(Organization organization, boolean updateToPrivate) {
- if (billingValidationsExtension == null) {
- return;
- }
- billingValidationsExtension.checkCanUpdateProjectVisibility(organization, updateToPrivate);
- }
-
- @Override
- public boolean canUpdateProjectVisibilityToPrivate(Organization organization) {
- return billingValidationsExtension == null || billingValidationsExtension.canUpdateProjectVisibilityToPrivate(organization);
- }
-
- @Override
- public void onDelete(Organization organization) {
- if (billingValidationsExtension == null) {
- return;
- }
- billingValidationsExtension.onDelete(organization);
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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.organization;
-
-import org.junit.Test;
-
-import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-import static org.sonar.server.organization.BillingValidations.Organization;
-
-public class BillingValidationsProxyImplTest {
-
- private static final Organization ORGANIZATION = new Organization("ORGANIZATION_KEY", "ORGANIZATION_UUID", "ORGANIZATION_NAME");
-
- private BillingValidationsExtension billingValidationsExtension = mock(BillingValidationsExtension.class);
-
- private BillingValidationsProxyImpl underTest;
-
- @Test
- public void checkOnProjectAnalysis_calls_extension_when_available() {
- underTest = new BillingValidationsProxyImpl(billingValidationsExtension);
-
- underTest.checkBeforeProjectAnalysis(ORGANIZATION);
-
- verify(billingValidationsExtension).checkBeforeProjectAnalysis(ORGANIZATION);
- }
-
- @Test
- public void checkOnProjectAnalysis_does_nothing_when_no_extension_available() {
- underTest = new BillingValidationsProxyImpl();
-
- underTest.checkBeforeProjectAnalysis(ORGANIZATION);
-
- verifyZeroInteractions(billingValidationsExtension);
- }
-
- @Test
- public void checkCanUpdateProjectsVisibility_calls_extension_when_available() {
- underTest = new BillingValidationsProxyImpl(billingValidationsExtension);
-
- underTest.checkCanUpdateProjectVisibility(ORGANIZATION, true);
-
- verify(billingValidationsExtension).checkCanUpdateProjectVisibility(ORGANIZATION, true);
- }
-
- @Test
- public void checkCanUpdateProjectsVisibility_does_nothing_when_no_extension_available() {
- underTest = new BillingValidationsProxyImpl();
-
- underTest.checkCanUpdateProjectVisibility(ORGANIZATION, true);
-
- verifyZeroInteractions(billingValidationsExtension);
- }
-
- @Test
- public void canUpdateProjectsVisibilityToPrivate_calls_extension_when_available() {
- underTest = new BillingValidationsProxyImpl(billingValidationsExtension);
- when(billingValidationsExtension.canUpdateProjectVisibilityToPrivate(ORGANIZATION)).thenReturn(false);
-
- boolean result = underTest.canUpdateProjectVisibilityToPrivate(ORGANIZATION);
-
- assertThat(result).isFalse();
- verify(billingValidationsExtension).canUpdateProjectVisibilityToPrivate(ORGANIZATION);
- }
-
- @Test
- public void canUpdateProjectsVisibilityToPrivate_return_true_when_no_extension() {
- underTest = new BillingValidationsProxyImpl();
-
- boolean result = underTest.canUpdateProjectVisibilityToPrivate(ORGANIZATION);
-
- assertThat(result).isTrue();
- verifyZeroInteractions(billingValidationsExtension);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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.organization.ws;
-
-import org.sonar.api.server.ws.WebService;
-
-public class OrganizationsWs implements WebService {
- private final OrganizationsWsAction[] actions;
-
- public OrganizationsWs(OrganizationsWsAction... actions) {
- this.actions = actions;
- }
-
- @Override
- public void define(Context context) {
- NewController controller = context.createController("api/organizations")
- .setSince("6.2")
- .setDescription("Manage organizations.");
- for (OrganizationsWsAction action : actions) {
- action.define(controller);
- }
- controller.done();
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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.organization.ws;
-
-import org.sonar.server.ws.WsAction;
-
-public interface OrganizationsWsAction extends WsAction {
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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.organization.ws;
-
-import org.sonar.core.platform.Module;
-import org.sonar.server.organization.MemberUpdater;
-
-public class OrganizationsWsModule extends Module {
-
- public OrganizationsWsModule() {
- // nothing to do here
- }
-
- @Override
- protected void configureModule() {
- add(
- OrganizationsWs.class,
- MemberUpdater.class,
- // actions
- SearchAction.class,
- SearchMembersAction.class);
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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.organization.ws;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import javax.annotation.Nullable;
-import org.sonar.api.server.ws.Change;
-import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.Response;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.api.server.ws.WebService.Param;
-import org.sonar.core.util.stream.MoreCollectors;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.alm.AlmAppInstallDto;
-import org.sonar.db.alm.OrganizationAlmBindingDto;
-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;
-
-import static java.lang.String.format;
-import static java.util.Collections.emptySet;
-import static java.util.Optional.ofNullable;
-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.db.permission.GlobalPermission.ADMINISTER;
-import static org.sonar.db.permission.GlobalPermission.PROVISION_PROJECTS;
-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";
- 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;
-
- public SearchAction(DbClient dbClient, UserSession userSession) {
- this.dbClient = dbClient;
- this.userSession = userSession;
- }
-
- @Override
- public void define(WebService.NewController context) {
- WebService.NewAction action = context.createAction(ACTION)
- .setPost(false)
- .setDescription("Search for organizations")
- .setResponseExample(getClass().getResource("search-example.json"))
- .setInternal(true)
- .setSince("6.2")
- .setChangelog(new Change("7.5", format("Return 'subscription' field when parameter '%s' is set to 'true'", PARAM_MEMBER)))
- .setChangelog(new Change("7.5", "Removed 'isAdmin' and return 'actions' for each organization"))
- .setChangelog(new Change("6.4", "Paging fields have been added to the response"))
- .setHandler(this);
-
- action.createParam(PARAM_ORGANIZATIONS)
- .setDescription("Comma-separated list of organization keys")
- .setExampleValue(String.join(",", "my-org-1", "foocorp"))
- .setMaxValuesAllowed(MAX_SIZE)
- .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("false")
- .setBooleanPossibleValues();
-
- action.addPagingParams(100, MAX_SIZE);
- }
-
- @Override
- public void handle(Request request, Response response) throws Exception {
- boolean onlyMembershipOrganizations = request.mandatoryParamAsBoolean(PARAM_MEMBER);
- if (onlyMembershipOrganizations) {
- userSession.checkLoggedIn();
- }
-
- try (DbSession dbSession = dbClient.openSession(false)) {
- OrganizationQuery dbQuery = buildDbQuery(request);
- int total = dbClient.organizationDao().countByQuery(dbSession, dbQuery);
- Paging paging = buildWsPaging(request, total);
- List<OrganizationDto> organizations = dbClient.organizationDao().selectByQuery(dbSession, dbQuery, forPage(paging.getPageIndex()).andSize(paging.getPageSize()));
- Set<String> adminOrganizationUuids = searchOrganizationWithAdminPermission(dbSession);
- Set<String> provisionOrganizationUuids = searchOrganizationWithProvisionPermission(dbSession);
- Map<String, OrganizationAlmBindingDto> organizationAlmBindingByOrgUuid = dbClient.organizationAlmBindingDao().selectByOrganizations(dbSession, organizations)
- .stream().collect(MoreCollectors.uniqueIndex(OrganizationAlmBindingDto::getOrganizationUuid));
- Map<String, AlmAppInstallDto> almAppInstallDtoByUuid = dbClient.almAppInstallDao().selectByOrganizations(dbSession, organizations)
- .stream().collect(MoreCollectors.uniqueIndex(AlmAppInstallDto::getUuid));
-
- Organizations.SearchWsResponse wsResponse = buildOrganizations(organizations, adminOrganizationUuids, provisionOrganizationUuids, organizationAlmBindingByOrgUuid,
- almAppInstallDtoByUuid, onlyMembershipOrganizations, paging);
- writeProtobuf(wsResponse, request, response);
- }
- }
-
- private OrganizationQuery buildDbQuery(Request request) {
- return newOrganizationQueryBuilder()
- .setKeys(request.paramAsStrings(PARAM_ORGANIZATIONS))
- .build();
- }
-
- private Set<String> searchOrganizationWithAdminPermission(DbSession dbSession) {
- String userUuid = userSession.getUuid();
- return userUuid == null ? emptySet()
- : dbClient.organizationDao().selectByPermission(dbSession, userUuid, ADMINISTER.getKey()).stream().map(OrganizationDto::getUuid).collect(toSet());
- }
-
- private Set<String> searchOrganizationWithProvisionPermission(DbSession dbSession) {
- String userUuid = userSession.getUuid();
- return userUuid == null ? emptySet()
- : dbClient.organizationDao().selectByPermission(dbSession, userUuid, PROVISION_PROJECTS.getKey()).stream().map(OrganizationDto::getUuid).collect(toSet());
- }
-
- private Organizations.SearchWsResponse buildOrganizations(List<OrganizationDto> organizations, Set<String> adminOrganizationUuids, Set<String> provisionOrganizationUuids,
- Map<String, OrganizationAlmBindingDto> organizationAlmBindingByOrgUuid, Map<String, AlmAppInstallDto> almAppInstallDtoByUuid, boolean onlyMembershipOrganizations,
- Paging paging) {
- Organizations.SearchWsResponse.Builder response = Organizations.SearchWsResponse.newBuilder();
- response.setPaging(paging);
- Organization.Builder wsOrganization = Organization.newBuilder();
- organizations
- .forEach(o -> {
- wsOrganization.clear();
- boolean isAdmin = userSession.isRoot() || adminOrganizationUuids.contains(o.getUuid());
- boolean canProvision = userSession.isRoot() || provisionOrganizationUuids.contains(o.getUuid());
- wsOrganization.setActions(Organization.Actions.newBuilder()
- .setAdmin(isAdmin)
- .setProvision(canProvision)
- .setDelete(isAdmin));
- OrganizationAlmBindingDto organizationAlmBinding = organizationAlmBindingByOrgUuid.get(o.getUuid());
- AlmAppInstallDto almAppinstall = organizationAlmBinding == null
- ? null
- : almAppInstallDtoByUuid.get(organizationAlmBinding.getAlmAppInstallUuid());
- response.addOrganizations(toOrganization(wsOrganization, o, organizationAlmBinding, almAppinstall, onlyMembershipOrganizations));
- });
- return response.build();
- }
-
- private static Organization.Builder toOrganization(Organization.Builder builder, OrganizationDto organization, @Nullable OrganizationAlmBindingDto organizationAlmBinding,
- @Nullable AlmAppInstallDto almAppInstallDto, boolean onlyMembershipOrganizations) {
- builder
- .setName(organization.getName())
- .setKey(organization.getKey());
- ofNullable(organization.getDescription()).ifPresent(builder::setDescription);
- ofNullable(organization.getUrl()).ifPresent(builder::setUrl);
- ofNullable(organization.getAvatarUrl()).ifPresent(builder::setAvatar);
- if (onlyMembershipOrganizations && organizationAlmBinding != null) {
- Organization.Alm.Builder almBuilder = Organization.Alm.newBuilder()
- .setKey(organizationAlmBinding.getAlm().getId())
- .setUrl(organizationAlmBinding.getUrl());
- if (almAppInstallDto != null) {
- almBuilder.setPersonal(almAppInstallDto.isOwnerUser());
- }
- builder.setAlm(almBuilder.build());
- }
- if (onlyMembershipOrganizations) {
- builder.setSubscription(Organizations.Subscription.valueOf(organization.getSubscription().name()));
- }
- return builder;
- }
-
- private static Paging buildWsPaging(Request request, int total) {
- return Paging.newBuilder()
- .setPageIndex(request.mandatoryParamAsInt(Param.PAGE))
- .setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE))
- .setTotal(total)
- .build();
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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.organization.ws;
-
-import com.google.common.collect.Ordering;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import javax.annotation.Nullable;
-import org.sonar.api.server.ws.Change;
-import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.Response;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.api.server.ws.WebService.Param;
-import org.sonar.api.server.ws.WebService.SelectionMode;
-import org.sonar.core.util.stream.MoreCollectors;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.organization.OrganizationDto;
-import org.sonar.db.user.UserDto;
-import org.sonar.server.es.SearchOptions;
-import org.sonar.server.es.SearchResult;
-import org.sonar.server.issue.AvatarResolver;
-import org.sonar.server.organization.DefaultOrganizationProvider;
-import org.sonar.server.user.UserSession;
-import org.sonar.server.user.index.UserDoc;
-import org.sonar.server.user.index.UserIndex;
-import org.sonar.server.user.index.UserQuery;
-import org.sonarqube.ws.Common;
-import org.sonarqube.ws.Organizations.SearchMembersWsResponse;
-import org.sonarqube.ws.Organizations.User;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Strings.emptyToNull;
-import static java.util.Optional.ofNullable;
-import static org.sonar.api.server.ws.WebService.SelectionMode.SELECTED;
-import static org.sonar.db.permission.GlobalPermission.ADMINISTER;
-import static org.sonar.server.es.SearchOptions.MAX_PAGE_SIZE;
-import static org.sonar.server.exceptions.NotFoundException.checkFoundWithOptional;
-import static org.sonar.server.ws.WsUtils.writeProtobuf;
-
-public class SearchMembersAction implements OrganizationsWsAction {
- private static final String ORGANIZATION_PARAM = "organization";
-
- private final DbClient dbClient;
- private final UserIndex userIndex;
- private final DefaultOrganizationProvider organizationProvider;
- private final UserSession userSession;
- private final AvatarResolver avatarResolver;
-
- public SearchMembersAction(DbClient dbClient, UserIndex userIndex, DefaultOrganizationProvider organizationProvider, UserSession userSession, AvatarResolver avatarResolver) {
- this.dbClient = dbClient;
- this.userIndex = userIndex;
- this.organizationProvider = organizationProvider;
- this.userSession = userSession;
- this.avatarResolver = avatarResolver;
- }
-
- @Override
- public void define(WebService.NewController context) {
- WebService.NewAction action = context.createAction("search_members")
- .setDescription("Search members of an organization.<br/>" +
- "Require organization membership.")
- .setResponseExample(getClass().getResource("search_members-example.json"))
- .setSince("6.4")
- .setInternal(true)
- .setChangelog(new Change("7.3", "This action now requires organization membership"))
- .setHandler(this);
-
- action.createSearchQuery("orwe", "names", "logins")
- .setMinimumLength(2);
- action.addPagingParams(50, MAX_PAGE_SIZE);
-
- action.createParam(Param.SELECTED)
- .setDescription("Depending on the value, show only selected items (selected=selected) or deselected items (selected=deselected).")
- .setInternal(true)
- .setDefaultValue(SELECTED.value())
- .setPossibleValues(SELECTED.value(), SelectionMode.DESELECTED.value());
-
- action.createParam(ORGANIZATION_PARAM)
- .setDescription("Organization key")
- .setInternal(true)
- .setRequired(false);
- }
-
- @Override
- public void handle(Request request, Response response) throws Exception {
- try (DbSession dbSession = dbClient.openSession(false)) {
- OrganizationDto organization = getOrganization(dbSession, request.param("organization"));
-
- UserQuery.Builder userQuery = buildUserQuery(request, organization);
- SearchOptions searchOptions = buildSearchOptions(request);
-
- SearchResult<UserDoc> searchResults = userIndex.search(userQuery.build(), searchOptions);
- List<String> orderedLogins = searchResults.getDocs().stream().map(UserDoc::login).collect(MoreCollectors.toList());
-
- List<UserDto> users = dbClient.userDao().selectByLogins(dbSession, orderedLogins).stream()
- .sorted(Ordering.explicit(orderedLogins).onResultOf(UserDto::getLogin))
- .collect(MoreCollectors.toList());
-
- Map<String, Integer> groupCountByLogin = null;
- if (userSession.hasPermission(ADMINISTER)) {
- groupCountByLogin = dbClient.groupMembershipDao().countGroupsByUsers(dbSession, orderedLogins);
- }
-
- Common.Paging wsPaging = buildWsPaging(request, searchResults);
- SearchMembersWsResponse wsResponse = buildResponse(users, wsPaging, groupCountByLogin);
-
- writeProtobuf(wsResponse, request, response);
- }
- }
-
- private SearchMembersWsResponse buildResponse(List<UserDto> users, Common.Paging wsPaging, @Nullable Map<String, Integer> groupCountByLogin) {
- SearchMembersWsResponse.Builder response = SearchMembersWsResponse.newBuilder();
-
- User.Builder wsUser = User.newBuilder();
- users.stream()
- .map(userDto -> {
- String login = userDto.getLogin();
- wsUser
- .clear()
- .setLogin(login);
- ofNullable(emptyToNull(userDto.getEmail())).ifPresent(text -> wsUser.setAvatar(avatarResolver.create(userDto)));
- ofNullable(userDto.getName()).ifPresent(wsUser::setName);
- ofNullable(groupCountByLogin).ifPresent(count -> wsUser.setGroupCount(groupCountByLogin.getOrDefault(login, 0)));
- return wsUser;
- })
- .forEach(response::addUsers);
- response.setPaging(wsPaging);
-
- return response.build();
- }
-
- private static UserQuery.Builder buildUserQuery(Request request, OrganizationDto organization) {
- UserQuery.Builder userQuery = UserQuery.builder();
- String textQuery = request.param(Param.TEXT_QUERY);
- checkArgument(textQuery == null || textQuery.length() >= 2, "Query length must be greater than or equal to 2");
- userQuery.setTextQuery(textQuery);
-
- SelectionMode selectionMode = SelectionMode.fromParam(request.mandatoryParam(Param.SELECTED));
- if (SelectionMode.DESELECTED.equals(selectionMode)) {
- userQuery.setExcludedOrganizationUuid(organization.getUuid());
- } else {
- userQuery.setOrganizationUuid(organization.getUuid());
- }
- return userQuery;
- }
-
- private static SearchOptions buildSearchOptions(Request request) {
- int pageSize = request.mandatoryParamAsInt(Param.PAGE_SIZE);
- return new SearchOptions().setPage(request.mandatoryParamAsInt(Param.PAGE), pageSize);
- }
-
- private static Common.Paging buildWsPaging(Request request, SearchResult<UserDoc> searchResults) {
- return Common.Paging.newBuilder()
- .setPageIndex(request.mandatoryParamAsInt(Param.PAGE))
- .setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE))
- .setTotal((int) searchResults.getTotal())
- .build();
- }
-
- private OrganizationDto getOrganization(DbSession dbSession, @Nullable String organizationParam) {
- String organizationKey = Optional.ofNullable(organizationParam)
- .orElseGet(organizationProvider.get()::getKey);
- return checkFoundWithOptional(
- dbClient.organizationDao().selectByKey(dbSession, organizationKey),
- "No organization with key '%s'", organizationKey);
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 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.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.server.organization.ws;
-
-import javax.annotation.ParametersAreNonnullByDefault;
import org.sonar.server.newcodeperiod.ws.NewCodePeriodsWsModule;
import org.sonar.server.notification.NotificationModule;
import org.sonar.server.notification.ws.NotificationWsModule;
-import org.sonar.server.organization.BillingValidationsProxyImpl;
-import org.sonar.server.organization.ws.OrganizationsWsModule;
import org.sonar.server.permission.DefaultTemplatesResolverImpl;
import org.sonar.server.permission.GroupPermissionChanger;
import org.sonar.server.permission.PermissionTemplateService;
UpdateCenterModule.class,
UpdateCenterWsModule.class,
- // organizations
- OrganizationsWsModule.class,
- BillingValidationsProxyImpl.class,
-
// quality profile
BuiltInQProfileDefinitionsBridge.class,
BuiltInQProfileRepositoryImpl.class,
@Generated("sonar-ws-generator")
public class AuthorsRequest {
- private String organization;
private String project;
private String ps;
private String q;
- /**
- * This is part of the internal API.
- * Example value: "my-org"
- */
- public AuthorsRequest setOrganization(String organization) {
- this.organization = organization;
- return this;
- }
-
- public String getOrganization() {
- return organization;
- }
-
/**
* Example value: "my_project"
*/
public AuthorsResponse authors(AuthorsRequest request) {
return call(
new GetRequest(path("authors"))
- .setParam("organization", request.getOrganization())
.setParam("project", request.getProject())
.setParam("ps", request.getPs())
.setParam("q", request.getQ()),
.setParam("componentUuid", request.getComponentUuid())
.setParam("createdAfter", request.getCreatedAfter())
.setParam("ps", request.getPs())
- .setMediaType(MediaTypes.JSON)
- ).content();
+ .setMediaType(MediaTypes.JSON)).content();
}
/**
new PostRequest(path("edit_comment"))
.setParam("comment", request.getComment())
.setParam("text", request.getText())
- .setMediaType(MediaTypes.JSON)
- ).content();
+ .setMediaType(MediaTypes.JSON)).content();
}
/**
.setParam("languages", request.getLanguages() == null ? null : request.getLanguages().stream().collect(Collectors.joining(",")))
.setParam("moduleUuids", request.getModuleUuids() == null ? null : request.getModuleUuids().stream().collect(Collectors.joining(",")))
.setParam("onComponentOnly", request.getOnComponentOnly())
- .setParam("organization", request.getOrganization())
.setParam("owaspTop10", request.getOwaspTop10() == null ? null : request.getOwaspTop10().stream().collect(Collectors.joining(",")))
.setParam("p", request.getP())
.setParam("projects", request.getProjects() == null ? null : request.getProjects().stream().collect(Collectors.joining(",")))
public TagsResponse tags(TagsRequest request) {
return call(
new GetRequest(path("tags"))
- .setParam("organization", request.getOrganization())
.setParam("project", request.getProject())
.setParam("ps", request.getPs())
.setParam("q", request.getQ()),
private List<String> languages;
private List<String> moduleUuids;
private String onComponentOnly;
- private String organization;
private List<String> owaspTop10;
private String p;
private List<String> projects;
return onComponentOnly;
}
- /**
- * This is part of the internal API.
- * Example value: "my-org"
- */
- public SearchRequest setOrganization(String organization) {
- this.organization = organization;
- return this;
- }
-
- public String getOrganization() {
- return organization;
- }
-
/**
* Possible values:
* <ul>
@Generated("sonar-ws-generator")
public class TagsRequest {
- private String organization;
private String project;
private String ps;
private String q;
- /**
- * This is part of the internal API.
- * Example value: "my-org"
- */
- public TagsRequest setOrganization(String organization) {
- this.organization = organization;
- return this;
- }
-
- public String getOrganization() {
- return organization;
- }
-
/**
* Example value: "my_project"
*/
*/
@Generated("sonar-ws-generator")
public class AppRequest {
-
- private String organization;
-
- /**
- * This is part of the internal API.
- * Example value: "my-org"
- */
- public AppRequest setOrganization(String organization) {
- this.organization = organization;
- return this;
- }
-
- public String getOrganization() {
- return organization;
- }
}
public String app(AppRequest request) {
return call(
new GetRequest(path("app"))
- .setParam("organization", request.getOrganization())
- .setMediaType(MediaTypes.JSON)
- ).content();
+ .setMediaType(MediaTypes.JSON)).content();
}
/**
call(
new PostRequest(path("delete"))
.setParam("key", request.getKey())
- .setMediaType(MediaTypes.JSON)
- ).content();
+ .setMediaType(MediaTypes.JSON)).content();
}
/**
new GetRequest(path("repositories"))
.setParam("language", request.getLanguage())
.setParam("q", request.getQ())
- .setMediaType(MediaTypes.JSON)
- ).content();
+ .setMediaType(MediaTypes.JSON)).content();
}
/**
.setParam("is_template", request.getIsTemplate())
.setParam("include_external", request.getIncludeExternal())
.setParam("languages", request.getLanguages() == null ? null : request.getLanguages().stream().collect(Collectors.joining(",")))
- .setParam("organization", request.getOrganization())
.setParam("p", request.getP())
.setParam("ps", request.getPs())
.setParam("q", request.getQ())
return call(
new GetRequest(path("show"))
.setParam("actives", request.getActives())
- .setParam("key", request.getKey())
- .setParam("organization", request.getOrganization()),
+ .setParam("key", request.getKey()),
ShowResponse.parser());
}
public String tags(TagsRequest request) {
return call(
new GetRequest(path("tags"))
- .setParam("organization", request.getOrganization())
.setParam("ps", request.getPs())
.setParam("q", request.getQ())
- .setMediaType(MediaTypes.JSON)
- ).content();
+ .setMediaType(MediaTypes.JSON)).content();
}
/**
.setParam("markdown_description", request.getMarkdownDescription())
.setParam("markdown_note", request.getMarkdownNote())
.setParam("name", request.getName())
- .setParam("organization", request.getOrganization())
.setParam("params", request.getParams() == null ? null : request.getParams().stream().collect(Collectors.joining(",")))
.setParam("remediation_fn_base_effort", request.getRemediationFnBaseEffort())
.setParam("remediation_fn_type", request.getRemediationFnType())
private List<String> inheritance;
private String isTemplate;
private List<String> languages;
- private String organization;
private List<String> owaspTop10;
private String p;
private String ps;
public String getIsTemplate() {
return isTemplate;
}
-
+
/**
* Possible values:
* <ul>
return languages;
}
- /**
- * This is part of the internal API.
- * Example value: "my-org"
- */
- public SearchRequest setOrganization(String organization) {
- this.organization = organization;
- return this;
- }
-
- public String getOrganization() {
- return organization;
- }
-
/**
* Possible values:
* <ul>
private String actives;
private String key;
- private String organization;
/**
* Possible values:
public String getKey() {
return key;
}
-
- /**
- * This is part of the internal API.
- * Example value: "my-org"
- */
- public ShowRequest setOrganization(String organization) {
- this.organization = organization;
- return this;
- }
-
- public String getOrganization() {
- return organization;
- }
}
@Generated("sonar-ws-generator")
public class TagsRequest {
- private String organization;
private String ps;
private String q;
- /**
- * This is part of the internal API.
- * Example value: "my-org"
- */
- public TagsRequest setOrganization(String organization) {
- this.organization = organization;
- return this;
- }
-
- public String getOrganization() {
- return organization;
- }
-
/**
* Example value: "20"
*/
private String markdownDescription;
private String markdownNote;
private String name;
- private String organization;
private List<String> params;
private String remediationFnBaseEffort;
private String remediationFnType;
return name;
}
- /**
- * This is part of the internal API.
- * Example value: "my-org"
- */
- public UpdateRequest setOrganization(String organization) {
- this.organization = organization;
- return this;
- }
-
- public String getOrganization() {
- return organization;
- }
-
/**
*/
public UpdateRequest setParams(List<String> params) {
private String id;
private String login;
private String name;
- private String organization;
/**
* Example value: "42"
public String getName() {
return name;
}
-
- /**
- * This is part of the internal API.
- * Example value: "my-org"
- */
- public AddUserRequest setOrganization(String organization) {
- this.organization = organization;
- return this;
- }
-
- public String getOrganization() {
- return organization;
- }
}
private String description;
private String name;
- private String organization;
/**
* Example value: "Default group for new users"
public String getName() {
return name;
}
-
- /**
- * This is part of the internal API.
- * Example value: "my-org"
- */
- public CreateRequest setOrganization(String organization) {
- this.organization = organization;
- return this;
- }
-
- public String getOrganization() {
- return organization;
- }
}
public class SearchRequest {
private List<String> f;
- private String organization;
private String p;
private String ps;
private String q;
return f;
}
- /**
- * This is part of the internal API.
- * Example value: "my-org"
- */
- public SearchRequest setOrganization(String organization) {
- this.organization = organization;
- return this;
- }
-
- public String getOrganization() {
- return organization;
- }
-
/**
* Example value: "42"
*/
import java.util.stream.Collectors;
import javax.annotation.Generated;
import org.sonarqube.ws.MediaTypes;
+import org.sonarqube.ws.UserGroups.CreateWsResponse;
+import org.sonarqube.ws.UserGroups.SearchWsResponse;
+import org.sonarqube.ws.UserGroups.UpdateWsResponse;
import org.sonarqube.ws.client.BaseService;
import org.sonarqube.ws.client.GetRequest;
import org.sonarqube.ws.client.PostRequest;
import org.sonarqube.ws.client.WsConnector;
-import org.sonarqube.ws.UserGroups.CreateWsResponse;
-import org.sonarqube.ws.UserGroups.SearchWsResponse;
-import org.sonarqube.ws.UserGroups.UpdateWsResponse;
/**
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/user_groups">Further information about this web service online</a>
.setParam("id", request.getId())
.setParam("login", request.getLogin())
.setParam("name", request.getName())
- .setParam("organization", request.getOrganization())
- .setMediaType(MediaTypes.JSON)
- ).content();
+ .setMediaType(MediaTypes.JSON)).content();
}
/**
return call(
new PostRequest(path("create"))
.setParam("description", request.getDescription())
- .setParam("name", request.getName())
- .setParam("organization", request.getOrganization()),
+ .setParam("name", request.getName()),
CreateWsResponse.parser());
}
new PostRequest(path("delete"))
.setParam("id", request.getId())
.setParam("name", request.getName())
- .setParam("organization", request.getOrganization())
- .setMediaType(MediaTypes.JSON)
- ).content();
+ .setMediaType(MediaTypes.JSON)).content();
}
/**
.setParam("id", request.getId())
.setParam("login", request.getLogin())
.setParam("name", request.getName())
- .setParam("organization", request.getOrganization())
- .setMediaType(MediaTypes.JSON)
- ).content();
+ .setMediaType(MediaTypes.JSON)).content();
}
/**
return call(
new GetRequest(path("search"))
.setParam("f", request.getF() == null ? null : request.getF().stream().collect(Collectors.joining(",")))
- .setParam("organization", request.getOrganization())
.setParam("p", request.getP())
.setParam("ps", request.getPs())
.setParam("q", request.getQ()),
new GetRequest(path("users"))
.setParam("id", request.getId())
.setParam("name", request.getName())
- .setParam("organization", request.getOrganization())
.setParam("p", request.getP())
.setParam("ps", request.getPs())
.setParam("q", request.getQ())
.setParam("selected", request.getSelected())
- .setMediaType(MediaTypes.JSON)
- ).content();
+ .setMediaType(MediaTypes.JSON)).content();
}
}