You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ProvisionedAction.java 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2018 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.server.project.ws;
  21. import com.google.common.io.Resources;
  22. import java.util.Date;
  23. import java.util.List;
  24. import java.util.Set;
  25. import java.util.function.Consumer;
  26. import javax.annotation.Nullable;
  27. import org.sonar.api.resources.Qualifiers;
  28. import org.sonar.api.server.ws.Change;
  29. import org.sonar.api.server.ws.Request;
  30. import org.sonar.api.server.ws.Response;
  31. import org.sonar.api.server.ws.WebService;
  32. import org.sonar.api.server.ws.WebService.Param;
  33. import org.sonar.api.utils.DateUtils;
  34. import org.sonar.db.DbClient;
  35. import org.sonar.db.DbSession;
  36. import org.sonar.db.component.ComponentDto;
  37. import org.sonar.db.component.ComponentQuery;
  38. import org.sonar.db.organization.OrganizationDto;
  39. import org.sonar.server.user.UserSession;
  40. import org.sonarqube.ws.Common.Paging;
  41. import org.sonarqube.ws.Components.ProvisionedWsResponse;
  42. import org.sonarqube.ws.Components.ProvisionedWsResponse.Component;
  43. import static com.google.common.collect.Sets.newHashSet;
  44. import static java.util.Optional.ofNullable;
  45. import static org.sonar.api.utils.Paging.offset;
  46. import static org.sonar.core.util.Protobuf.setNullable;
  47. import static org.sonar.core.util.stream.MoreCollectors.toList;
  48. import static org.sonar.db.permission.OrganizationPermission.PROVISION_PROJECTS;
  49. import static org.sonar.server.es.SearchOptions.MAX_LIMIT;
  50. import static org.sonar.server.project.Visibility.PRIVATE;
  51. import static org.sonar.server.project.Visibility.PUBLIC;
  52. import static org.sonar.server.project.ws.ProjectsWsSupport.PARAM_ORGANIZATION;
  53. import static org.sonar.server.ws.WsUtils.writeProtobuf;
  54. public class ProvisionedAction implements ProjectsWsAction {
  55. private static final Set<String> POSSIBLE_FIELDS = newHashSet("uuid", "key", "name", "creationDate", "visibility");
  56. private final ProjectsWsSupport support;
  57. private final DbClient dbClient;
  58. private final UserSession userSession;
  59. public ProvisionedAction(ProjectsWsSupport support, DbClient dbClient, UserSession userSession) {
  60. this.support = support;
  61. this.dbClient = dbClient;
  62. this.userSession = userSession;
  63. }
  64. @Override
  65. public void define(WebService.NewController controller) {
  66. WebService.NewAction action = controller.createAction("provisioned");
  67. action
  68. .setDescription(
  69. "Get the list of provisioned projects.<br> " +
  70. "Web service is deprecated. Use api/projects/search instead, with onProvisionedOnly=true.<br> " +
  71. "Require 'Create Projects' permission.")
  72. .setSince("5.2")
  73. .setDeprecatedSince("6.6")
  74. .setResponseExample(Resources.getResource(getClass(), "provisioned-example.json"))
  75. .setHandler(this)
  76. .addPagingParams(100, MAX_LIMIT)
  77. .addSearchQuery("sonar", "names", "keys")
  78. .addFieldsParam(POSSIBLE_FIELDS);
  79. action.setChangelog(
  80. new Change("6.4", "The 'uuid' field is deprecated in the response"),
  81. new Change("6.4", "Paging response fields is now in a Paging object"));
  82. support.addOrganizationParam(action);
  83. }
  84. @Override
  85. public void handle(Request request, Response response) throws Exception {
  86. userSession.checkLoggedIn();
  87. int page = request.mandatoryParamAsInt(Param.PAGE);
  88. int pageSize = request.mandatoryParamAsInt(Param.PAGE_SIZE);
  89. Set<String> desiredFields = desiredFields(request);
  90. String query = request.param(Param.TEXT_QUERY);
  91. try (DbSession dbSession = dbClient.openSession(false)) {
  92. OrganizationDto organization = support.getOrganization(dbSession, request.param(PARAM_ORGANIZATION));
  93. userSession.checkPermission(PROVISION_PROJECTS, organization);
  94. ComponentQuery dbQuery = buildDbQuery(query);
  95. List<ComponentDto> projects = dbClient.componentDao().selectByQuery(dbSession, organization.getUuid(), dbQuery, offset(page, pageSize), pageSize);
  96. int nbOfProjects = dbClient.componentDao().countByQuery(dbSession, organization.getUuid(), dbQuery);
  97. ProvisionedWsResponse result = ProvisionedWsResponse.newBuilder()
  98. .addAllProjects(writeProjects(projects, desiredFields))
  99. .setPaging(Paging.newBuilder()
  100. .setTotal(nbOfProjects)
  101. .setPageIndex(page)
  102. .setPageSize(pageSize))
  103. .build();
  104. writeProtobuf(result, request, response);
  105. }
  106. }
  107. private static ComponentQuery buildDbQuery(@Nullable String nameOrKeyQuery) {
  108. ComponentQuery.Builder dbQuery = ComponentQuery.builder()
  109. .setQualifiers(Qualifiers.PROJECT)
  110. .setOnProvisionedOnly(true);
  111. setNullable(nameOrKeyQuery, q -> {
  112. dbQuery.setPartialMatchOnKey(true);
  113. dbQuery.setNameOrKeyQuery(q);
  114. return dbQuery;
  115. });
  116. return dbQuery.build();
  117. }
  118. private static List<Component> writeProjects(List<ComponentDto> projects, Set<String> desiredFields) {
  119. return projects.stream().map(project -> {
  120. Component.Builder compBuilder = Component.newBuilder().setUuid(project.uuid());
  121. writeIfNeeded("key", project.getDbKey(), compBuilder::setKey, desiredFields);
  122. writeIfNeeded("name", project.name(), compBuilder::setName, desiredFields);
  123. writeIfNeeded("creationDate", project.getCreatedAt(), compBuilder::setCreationDate, desiredFields);
  124. writeIfNeeded("visibility", project.isPrivate() ? PRIVATE.getLabel() : PUBLIC.getLabel(), compBuilder::setVisibility, desiredFields);
  125. return compBuilder.build();
  126. }).collect(toList());
  127. }
  128. private static void writeIfNeeded(String fieldName, String value, Consumer<String> setter, Set<String> desiredFields) {
  129. if (desiredFields.contains(fieldName)) {
  130. setter.accept(value);
  131. }
  132. }
  133. private static void writeIfNeeded(String fieldName, @Nullable Date value, Consumer<String> setter, Set<String> desiredFields) {
  134. if (desiredFields.contains(fieldName)) {
  135. ofNullable(value).map(DateUtils::formatDateTime).ifPresent(setter);
  136. }
  137. }
  138. private static Set<String> desiredFields(Request request) {
  139. List<String> desiredFields = request.paramAsStrings(Param.FIELDS);
  140. if (desiredFields == null) {
  141. return POSSIBLE_FIELDS;
  142. }
  143. return newHashSet(desiredFields);
  144. }
  145. }