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.

CreateAction.java 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2019 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 javax.annotation.CheckForNull;
  22. import javax.annotation.Nullable;
  23. import org.sonar.api.server.ws.Change;
  24. import org.sonar.api.server.ws.Request;
  25. import org.sonar.api.server.ws.Response;
  26. import org.sonar.api.server.ws.WebService;
  27. import org.sonar.db.DbClient;
  28. import org.sonar.db.DbSession;
  29. import org.sonar.db.component.ComponentDto;
  30. import org.sonar.db.organization.OrganizationDto;
  31. import org.sonar.server.component.ComponentUpdater;
  32. import org.sonar.server.project.Visibility;
  33. import org.sonar.server.user.UserSession;
  34. import org.sonarqube.ws.Projects.CreateWsResponse;
  35. import static org.apache.commons.lang.StringUtils.abbreviate;
  36. import static org.sonar.api.resources.Qualifiers.PROJECT;
  37. import static org.sonar.core.component.ComponentKeys.MAX_COMPONENT_KEY_LENGTH;
  38. import static org.sonar.db.component.ComponentValidator.MAX_COMPONENT_NAME_LENGTH;
  39. import static org.sonar.db.permission.OrganizationPermission.PROVISION_PROJECTS;
  40. import static org.sonar.server.component.NewComponent.newComponentBuilder;
  41. import static org.sonar.server.project.ws.ProjectsWsSupport.PARAM_ORGANIZATION;
  42. import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
  43. import static org.sonar.server.ws.WsUtils.writeProtobuf;
  44. import static org.sonarqube.ws.client.project.ProjectsWsParameters.ACTION_CREATE;
  45. import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_NAME;
  46. import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_PROJECT;
  47. import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_VISIBILITY;
  48. public class CreateAction implements ProjectsWsAction {
  49. private final ProjectsWsSupport support;
  50. private final DbClient dbClient;
  51. private final UserSession userSession;
  52. private final ComponentUpdater componentUpdater;
  53. public CreateAction(ProjectsWsSupport support, DbClient dbClient, UserSession userSession, ComponentUpdater componentUpdater) {
  54. this.support = support;
  55. this.dbClient = dbClient;
  56. this.userSession = userSession;
  57. this.componentUpdater = componentUpdater;
  58. }
  59. @Override
  60. public void define(WebService.NewController context) {
  61. WebService.NewAction action = context.createAction(ACTION_CREATE)
  62. .setDescription("Create a project.<br/>" +
  63. "Requires 'Create Projects' permission")
  64. .setSince("4.0")
  65. .setPost(true)
  66. .setResponseExample(getClass().getResource("create-example.json"))
  67. .setHandler(this);
  68. action.setChangelog(
  69. new Change("7.1", "The 'visibility' parameter is public"));
  70. action.createParam(PARAM_PROJECT)
  71. .setDescription("Key of the project")
  72. .setRequired(true)
  73. .setMaximumLength(MAX_COMPONENT_KEY_LENGTH)
  74. .setExampleValue(KEY_PROJECT_EXAMPLE_001);
  75. action.createParam(PARAM_NAME)
  76. .setDescription("Name of the project. If name is longer than %d, it is abbreviated.", MAX_COMPONENT_NAME_LENGTH)
  77. .setRequired(true)
  78. .setExampleValue("SonarQube");
  79. action.createParam(PARAM_VISIBILITY)
  80. .setDescription("Whether the created project should be visible to everyone, or only specific user/groups.<br/>" +
  81. "If no visibility is specified, the default project visibility of the organization will be used.")
  82. .setRequired(false)
  83. .setSince("6.4")
  84. .setPossibleValues(Visibility.getLabels());
  85. support.addOrganizationParam(action);
  86. }
  87. @Override
  88. public void handle(Request request, Response response) throws Exception {
  89. CreateRequest createRequest = toCreateRequest(request);
  90. writeProtobuf(doHandle(createRequest), request, response);
  91. }
  92. private CreateWsResponse doHandle(CreateRequest request) {
  93. try (DbSession dbSession = dbClient.openSession(false)) {
  94. OrganizationDto organization = support.getOrganization(dbSession, request.getOrganization());
  95. userSession.checkPermission(PROVISION_PROJECTS, organization);
  96. String visibility = request.getVisibility();
  97. boolean changeToPrivate = visibility == null ? dbClient.organizationDao().getNewProjectPrivate(dbSession, organization) : "private".equals(visibility);
  98. support.checkCanUpdateProjectsVisibility(organization, changeToPrivate);
  99. ComponentDto componentDto = componentUpdater.create(dbSession, newComponentBuilder()
  100. .setOrganizationUuid(organization.getUuid())
  101. .setKey(request.getProjectKey())
  102. .setName(request.getName())
  103. .setPrivate(changeToPrivate)
  104. .setQualifier(PROJECT)
  105. .build(),
  106. userSession.isLoggedIn() ? userSession.getUserId() : null);
  107. return toCreateResponse(componentDto);
  108. }
  109. }
  110. private static CreateRequest toCreateRequest(Request request) {
  111. return CreateRequest.builder()
  112. .setOrganization(request.param(PARAM_ORGANIZATION))
  113. .setProjectKey(request.mandatoryParam(PARAM_PROJECT))
  114. .setName(abbreviate(request.mandatoryParam(PARAM_NAME), MAX_COMPONENT_NAME_LENGTH))
  115. .setVisibility(request.param(PARAM_VISIBILITY))
  116. .build();
  117. }
  118. private static CreateWsResponse toCreateResponse(ComponentDto componentDto) {
  119. return CreateWsResponse.newBuilder()
  120. .setProject(CreateWsResponse.Project.newBuilder()
  121. .setKey(componentDto.getDbKey())
  122. .setName(componentDto.name())
  123. .setQualifier(componentDto.qualifier())
  124. .setVisibility(Visibility.getLabel(componentDto.isPrivate())))
  125. .build();
  126. }
  127. static class CreateRequest {
  128. private final String organization;
  129. private final String projectKey;
  130. private final String name;
  131. @CheckForNull
  132. private final String visibility;
  133. private CreateRequest(Builder builder) {
  134. this.organization = builder.organization;
  135. this.projectKey = builder.projectKey;
  136. this.name = builder.name;
  137. this.visibility = builder.visibility;
  138. }
  139. @CheckForNull
  140. public String getOrganization() {
  141. return organization;
  142. }
  143. @CheckForNull
  144. public String getProjectKey() {
  145. return projectKey;
  146. }
  147. @CheckForNull
  148. public String getName() {
  149. return name;
  150. }
  151. @CheckForNull
  152. public String getVisibility() {
  153. return visibility;
  154. }
  155. public static Builder builder() {
  156. return new Builder();
  157. }
  158. }
  159. static class Builder {
  160. private String organization;
  161. private String projectKey;
  162. private String name;
  163. @CheckForNull
  164. private String visibility;
  165. private Builder() {
  166. }
  167. public Builder setOrganization(@Nullable String organization) {
  168. this.organization = organization;
  169. return this;
  170. }
  171. public Builder setProjectKey(@Nullable String projectKey) {
  172. this.projectKey = projectKey;
  173. return this;
  174. }
  175. public Builder setName(@Nullable String name) {
  176. this.name = name;
  177. return this;
  178. }
  179. public Builder setVisibility(@Nullable String visibility) {
  180. this.visibility = visibility;
  181. return this;
  182. }
  183. public CreateRequest build() {
  184. return new CreateRequest(this);
  185. }
  186. }
  187. }