diff options
author | Antoine Vigneau <antoine.vigneau@sonarsource.com> | 2023-12-21 17:19:14 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2023-12-22 20:03:03 +0000 |
commit | fce9db4d8dff4cce21eb3e9fbe72e7c1ad9f4540 (patch) | |
tree | 98ae0fa57abbc3e5dab809294b41286405e71d4d /server/sonar-webserver-webapi-v2 | |
parent | 7453617939eff3e8d3f5cc4c84f21b38c5c50701 (diff) | |
download | sonarqube-fce9db4d8dff4cce21eb3e9fbe72e7c1ad9f4540.tar.gz sonarqube-fce9db4d8dff4cce21eb3e9fbe72e7c1ad9f4540.zip |
SONAR-21121 Move Gitlab Config REST endpoints to Community edition
Diffstat (limited to 'server/sonar-webserver-webapi-v2')
13 files changed, 1048 insertions, 0 deletions
diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/WebApiEndpoints.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/WebApiEndpoints.java index bfb2288591b..26826997710 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/WebApiEndpoints.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/WebApiEndpoints.java @@ -36,6 +36,8 @@ public class WebApiEndpoints { public static final String CLEAN_CODE_POLICY_DOMAIN = "/clean-code-policy"; public static final String RULES_ENDPOINT = CLEAN_CODE_POLICY_DOMAIN + "/rules"; + public static final String GITLAB_CONFIGURATION_ENDPOINT = DOP_TRANSLATION_DOMAIN + "/gitlab-configurations"; + public static final String INTERNAL = "internal"; private WebApiEndpoints() { diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/controller/DefaultGitlabConfigurationController.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/controller/DefaultGitlabConfigurationController.java new file mode 100644 index 00000000000..588457f52bd --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/controller/DefaultGitlabConfigurationController.java @@ -0,0 +1,149 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.v2.api.gitlab.config.controller; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.sonar.server.common.gitlab.config.GitlabConfiguration; +import org.sonar.server.common.gitlab.config.GitlabConfigurationService; +import org.sonar.server.common.gitlab.config.SynchronizationType; +import org.sonar.server.common.gitlab.config.UpdateGitlabConfigurationRequest; +import org.sonar.server.user.UserSession; +import org.sonar.server.v2.api.gitlab.config.request.GitlabConfigurationCreateRestRequest; +import org.sonar.server.v2.api.gitlab.config.request.GitlabConfigurationUpdateRestRequest; +import org.sonar.server.v2.api.gitlab.config.resource.GitlabConfigurationResource; +import org.sonar.server.v2.api.gitlab.config.response.GitlabConfigurationSearchRestResponse; +import org.sonar.server.v2.api.response.PageRestResponse; + +import static org.sonar.server.common.gitlab.config.GitlabConfigurationService.UNIQUE_GITLAB_CONFIGURATION_ID; + +public class DefaultGitlabConfigurationController implements GitlabConfigurationController { + + private final UserSession userSession; + private final GitlabConfigurationService gitlabConfigurationService; + + public DefaultGitlabConfigurationController(UserSession userSession, GitlabConfigurationService gitlabConfigurationService) { + this.userSession = userSession; + this.gitlabConfigurationService = gitlabConfigurationService; + } + + @Override + public GitlabConfigurationResource getGitlabConfiguration(String id) { + userSession.checkIsSystemAdministrator(); + return getGitlabConfigurationResource(id); + } + + @Override + public GitlabConfigurationSearchRestResponse searchGitlabConfiguration() { + userSession.checkIsSystemAdministrator(); + + List<GitlabConfigurationResource> gitlabConfigurationResources = gitlabConfigurationService.findConfigurations() + .stream() + .map(DefaultGitlabConfigurationController::toGitLabConfigurationResource) + .toList(); + + PageRestResponse pageRestResponse = new PageRestResponse(1, 1000, gitlabConfigurationResources.size()); + return new GitlabConfigurationSearchRestResponse(gitlabConfigurationResources, pageRestResponse); + } + + @Override + public GitlabConfigurationResource create(GitlabConfigurationCreateRestRequest createRequest) { + userSession.checkIsSystemAdministrator(); + GitlabConfiguration createdConfiguration = gitlabConfigurationService.createConfiguration(toGitlabConfiguration(createRequest)); + return toGitLabConfigurationResource(createdConfiguration); + } + + + private static GitlabConfiguration toGitlabConfiguration(GitlabConfigurationCreateRestRequest createRestRequest) { + return new GitlabConfiguration( + UNIQUE_GITLAB_CONFIGURATION_ID, + createRestRequest.enabled(), + createRestRequest.applicationId(), + createRestRequest.url(), + createRestRequest.secret(), + createRestRequest.synchronizeGroups(), + toSynchronizationType(createRestRequest.synchronizationType()), + createRestRequest.allowUsersToSignUp() != null && createRestRequest.allowUsersToSignUp(), + createRestRequest.provisioningToken(), + createRestRequest.provisioningGroups() == null ? Set.of() : Set.copyOf(createRestRequest.provisioningGroups())); + } + + private GitlabConfigurationResource getGitlabConfigurationResource(String id) { + return toGitLabConfigurationResource(gitlabConfigurationService.getConfiguration(id)); + } + + @Override + public GitlabConfigurationResource updateGitlabConfiguration(String id, GitlabConfigurationUpdateRestRequest updateRequest) { + userSession.checkIsSystemAdministrator(); + UpdateGitlabConfigurationRequest updateGitlabConfigurationRequest = toUpdateGitlabConfigurationRequest(id, updateRequest); + return toGitLabConfigurationResource(gitlabConfigurationService.updateConfiguration(updateGitlabConfigurationRequest)); + } + + private static UpdateGitlabConfigurationRequest toUpdateGitlabConfigurationRequest(String id, + GitlabConfigurationUpdateRestRequest updateRequest) { + return UpdateGitlabConfigurationRequest.builder() + .gitlabConfigurationId(id) + .enabled(updateRequest.getEnabled().toNonNullUpdatedValue()) + .applicationId(updateRequest.getApplicationId().toNonNullUpdatedValue()) + .url(updateRequest.getUrl().toNonNullUpdatedValue()) + .secret(updateRequest.getSecret().toNonNullUpdatedValue()) + .synchronizeGroups(updateRequest.getSynchronizeGroups().toNonNullUpdatedValue()) + .synchronizationType(updateRequest.getSynchronizationType().map(DefaultGitlabConfigurationController::toSynchronizationType).toNonNullUpdatedValue()) + .allowUserToSignUp(updateRequest.getAllowUsersToSignUp().toNonNullUpdatedValue()) + .provisioningToken(updateRequest.getProvisioningToken().toUpdatedValue()) + .provisioningGroups(updateRequest.getProvisioningGroups().map(DefaultGitlabConfigurationController::getGroups).toNonNullUpdatedValue()) + .build(); + } + + private static Set<String> getGroups(List<String> groups) { + return new HashSet<>(groups); + } + + private static GitlabConfigurationResource toGitLabConfigurationResource(GitlabConfiguration configuration) { + return new GitlabConfigurationResource( + configuration.id(), + configuration.enabled(), + configuration.applicationId(), + configuration.url(), + configuration.synchronizeGroups(), + toRestSynchronizationType(configuration), + configuration.allowUsersToSignUp(), + sortGroups(configuration.provisioningGroups())); + } + + private static SynchronizationType toRestSynchronizationType(GitlabConfiguration configuration) { + return SynchronizationType.valueOf(configuration.synchronizationType().name()); + } + + private static SynchronizationType toSynchronizationType(SynchronizationType synchronizationType) { + return SynchronizationType.valueOf(synchronizationType.name()); + } + + private static List<String> sortGroups(Set<String> groups) { + return groups.stream().sorted().toList(); + } + + @Override + public void deleteGitlabConfiguration(String id) { + userSession.checkIsSystemAdministrator(); + gitlabConfigurationService.deleteConfiguration(id); + } +} diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/controller/GitlabConfigurationController.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/controller/GitlabConfigurationController.java new file mode 100644 index 00000000000..474da3d29cc --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/controller/GitlabConfigurationController.java @@ -0,0 +1,97 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.v2.api.gitlab.config.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.extensions.Extension; +import io.swagger.v3.oas.annotations.extensions.ExtensionProperty; +import javax.validation.Valid; +import org.sonar.server.v2.api.gitlab.config.request.GitlabConfigurationCreateRestRequest; +import org.sonar.server.v2.api.gitlab.config.request.GitlabConfigurationUpdateRestRequest; +import org.sonar.server.v2.api.gitlab.config.resource.GitlabConfigurationResource; +import org.sonar.server.v2.api.gitlab.config.response.GitlabConfigurationSearchRestResponse; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +import static org.sonar.server.v2.WebApiEndpoints.GITLAB_CONFIGURATION_ENDPOINT; +import static org.sonar.server.v2.WebApiEndpoints.INTERNAL; +import static org.sonar.server.v2.WebApiEndpoints.JSON_MERGE_PATCH_CONTENT_TYPE; + +@RequestMapping(GITLAB_CONFIGURATION_ENDPOINT) +@RestController +public interface GitlabConfigurationController { + + @GetMapping(path = "/{id}") + @ResponseStatus(HttpStatus.OK) + @Operation(summary = "Fetch a GitLab configuration", description = """ + Fetch a GitLab configuration. Requires 'Administer System' permission. + """, + extensions = @Extension(properties = {@ExtensionProperty(name = INTERNAL, value = "true")})) + GitlabConfigurationResource getGitlabConfiguration( + @PathVariable("id") @Parameter(description = "The id of the configuration to fetch.", required = true, in = ParameterIn.PATH) String id); + + @GetMapping + @Operation(summary = "Search GitLab configs", description = """ + Get the list of GitLab configurations. + Note that a single configuration is supported at this time. + Requires 'Administer System' permission. + """, + extensions = @Extension(properties = {@ExtensionProperty(name = INTERNAL, value = "true")})) + GitlabConfigurationSearchRestResponse searchGitlabConfiguration(); + + @PatchMapping(path = "/{id}", consumes = JSON_MERGE_PATCH_CONTENT_TYPE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseStatus(HttpStatus.OK) + @Operation(summary = "Update a Gitlab configuration", description = """ + Update a Gitlab configuration. Requires 'Administer System' permission. + """, + extensions = @Extension(properties = {@ExtensionProperty(name = INTERNAL, value = "true")})) + GitlabConfigurationResource updateGitlabConfiguration(@PathVariable("id") String id, @Valid @RequestBody GitlabConfigurationUpdateRestRequest updateRequest); + + @PostMapping + @Operation(summary = "Create Gitlab configuration", description = """ + Create a new Gitlab configuration. + Note that only a single configuration can exist at a time. + Requires 'Administer System' permission. + """, + extensions = @Extension(properties = {@ExtensionProperty(name = INTERNAL, value = "true")})) + GitlabConfigurationResource create(@Valid @RequestBody GitlabConfigurationCreateRestRequest createRequest); + + @DeleteMapping(path = "/{id}") + @ResponseStatus(HttpStatus.NO_CONTENT) + @Operation(summary = "Delete a GitLab configuration", description = """ + Delete a GitLab configuration. + Requires 'Administer System' permission. + """, + extensions = @Extension(properties = {@ExtensionProperty(name = INTERNAL, value = "true")})) + void deleteGitlabConfiguration( + @PathVariable("id") @Parameter(description = "The id of the configuration to delete.", required = true, in = ParameterIn.PATH) String id); + +} diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/controller/package-info.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/controller/package-info.java new file mode 100644 index 00000000000..5f2a9b2c298 --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/controller/package-info.java @@ -0,0 +1,23 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.v2.api.gitlab.config.controller; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/request/GitlabConfigurationCreateRestRequest.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/request/GitlabConfigurationCreateRestRequest.java new file mode 100644 index 00000000000..dadbe48f756 --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/request/GitlabConfigurationCreateRestRequest.java @@ -0,0 +1,65 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.v2.api.gitlab.config.request; + +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; +import javax.annotation.Nullable; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import org.sonar.server.common.gitlab.config.SynchronizationType; + +public record GitlabConfigurationCreateRestRequest( + + @NotNull + @Schema(description = "Enable Gitlab authentication") + boolean enabled, + + @NotEmpty + @Schema(description = "Gitlab Application id") + String applicationId, + @NotEmpty + @Schema(description = "Url of Gitlab instance for authentication (for instance https://gitlab.com)") + String url, + @NotEmpty + @Schema(accessMode = Schema.AccessMode.WRITE_ONLY, description = "Secret of the application") + String secret, + + @NotNull + @Schema(description = "Set whether to synchronize groups") + Boolean synchronizeGroups, + + @NotNull + @Schema(description = "Type of synchronization") + SynchronizationType synchronizationType, + @Nullable + @Schema(accessMode = Schema.AccessMode.WRITE_ONLY, description = "Gitlab token for provisioning") + String provisioningToken, + + @Schema(description = "Allow user to sign up") + @Nullable + Boolean allowUsersToSignUp, + + @ArraySchema(arraySchema = @Schema(description = "Root GitLab groups to provision.")) + @Nullable + List<String> provisioningGroups +) { +} diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/request/GitlabConfigurationUpdateRestRequest.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/request/GitlabConfigurationUpdateRestRequest.java new file mode 100644 index 00000000000..5616a86a0eb --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/request/GitlabConfigurationUpdateRestRequest.java @@ -0,0 +1,122 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.v2.api.gitlab.config.request; + +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; +import javax.validation.constraints.Size; +import org.sonar.server.common.gitlab.config.SynchronizationType; +import org.sonar.server.v2.common.model.UpdateField; + +public class GitlabConfigurationUpdateRestRequest { + + private UpdateField<Boolean> enabled = UpdateField.undefined(); + private UpdateField<String> applicationId = UpdateField.undefined(); + private UpdateField<String> url = UpdateField.undefined(); + private UpdateField<String> secret = UpdateField.undefined(); + private UpdateField<Boolean> synchronizeGroups = UpdateField.undefined(); + private UpdateField<SynchronizationType> synchronizationType = UpdateField.undefined(); + private UpdateField<Boolean> allowUsersToSignUp = UpdateField.undefined(); + private UpdateField<String> provisioningToken = UpdateField.undefined(); + private UpdateField<List<String>> provisioningGroups = UpdateField.undefined(); + + @Schema(implementation = Boolean.class, description = "Enable Gitlab authentication") + public UpdateField<Boolean> getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = UpdateField.withValue(enabled); + } + + @Schema(implementation = String.class, description = "Gitlab Application id") + public UpdateField<String> getApplicationId() { + return applicationId; + } + + public void setApplicationId(String applicationId) { + this.applicationId = UpdateField.withValue(applicationId); + } + + @Schema(implementation = String.class, description = "Url of Gitlab instance for authentication (for instance https://gitlab.com/api/v4)") + public UpdateField<String> getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = UpdateField.withValue(url); + } + + @Schema(implementation = String.class, description = "Secret of the application", nullable = true) + public UpdateField<String> getSecret() { + return secret; + } + + public void setSecret(String secret) { + this.secret = UpdateField.withValue(secret); + } + + @Schema(implementation = Boolean.class, description = "Set whether to synchronize groups") + public UpdateField<Boolean> getSynchronizeGroups() { + return synchronizeGroups; + } + + public void setSynchronizeGroups(Boolean synchronizeGroups) { + this.synchronizeGroups = UpdateField.withValue(synchronizeGroups); + } + + @Schema(implementation = SynchronizationType.class, description = "Type of synchronization") + public UpdateField<SynchronizationType> getSynchronizationType() { + return synchronizationType; + } + + public void setSynchronizationType(SynchronizationType synchronizationType) { + this.synchronizationType = UpdateField.withValue(synchronizationType); + } + + @Schema(implementation = Boolean.class, description = "Allow user to sign up") + public UpdateField<Boolean> getAllowUsersToSignUp() { + return allowUsersToSignUp; + } + + public void setAllowUsersToSignUp(Boolean allowUsersToSignUp) { + this.allowUsersToSignUp = UpdateField.withValue(allowUsersToSignUp); + } + + @Size(min = 1) + @Schema(implementation = String.class, description = "Gitlab token for provisioning", nullable = true) + public UpdateField<String> getProvisioningToken() { + return provisioningToken; + } + + public void setProvisioningToken(String provisioningToken) { + this.provisioningToken = UpdateField.withValue(provisioningToken); + } + + @ArraySchema(arraySchema = @Schema(description = "Root gitlab groups to provision."), schema = @Schema(implementation = String.class)) + public UpdateField<List<String>> getProvisioningGroups() { + return provisioningGroups; + } + + public void setProvisioningGroups(List<String> provisioningGroups) { + this.provisioningGroups = UpdateField.withValue(provisioningGroups); + } +} diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/request/package-info.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/request/package-info.java new file mode 100644 index 00000000000..9557f9af25b --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/request/package-info.java @@ -0,0 +1,23 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.v2.api.gitlab.config.request; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/resource/GitlabConfigurationResource.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/resource/GitlabConfigurationResource.java new file mode 100644 index 00000000000..eca624cc19a --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/resource/GitlabConfigurationResource.java @@ -0,0 +1,48 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.v2.api.gitlab.config.resource; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; +import org.sonar.server.common.gitlab.config.SynchronizationType; + +public record GitlabConfigurationResource( + + @Schema(accessMode = Schema.AccessMode.READ_ONLY) + String id, + + boolean enabled, + + @Schema(implementation = String.class, description = "Gitlab Application id") + String applicationId, + + @Schema(description = "Url of Gitlab instance for authentication (for instance https://gitlab.com/api/v4)") + String url, + + boolean synchronizeGroups, + + SynchronizationType synchronizationType, + + boolean allowUsersToSignUp, + + @Schema(description = "Root Gitlab groups to provision") + List<String> provisioningGroups +) { +} diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/resource/package-info.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/resource/package-info.java new file mode 100644 index 00000000000..47e29020ad5 --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/resource/package-info.java @@ -0,0 +1,23 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.v2.api.gitlab.config.resource; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/response/GitlabConfigurationSearchRestResponse.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/response/GitlabConfigurationSearchRestResponse.java new file mode 100644 index 00000000000..ddadc8c2913 --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/response/GitlabConfigurationSearchRestResponse.java @@ -0,0 +1,27 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.v2.api.gitlab.config.response; + +import java.util.List; +import org.sonar.server.v2.api.gitlab.config.resource.GitlabConfigurationResource; +import org.sonar.server.v2.api.response.PageRestResponse; + +public record GitlabConfigurationSearchRestResponse(List<GitlabConfigurationResource> gitlabConfigurations, PageRestResponse page) {} + diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/response/package-info.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/response/package-info.java new file mode 100644 index 00000000000..1d3e083fd97 --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/response/package-info.java @@ -0,0 +1,23 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.v2.api.gitlab.config.response; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/config/PlatformLevel4WebConfig.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/config/PlatformLevel4WebConfig.java index 3df7ae8ebe1..c1b63631b08 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/config/PlatformLevel4WebConfig.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/config/PlatformLevel4WebConfig.java @@ -22,6 +22,7 @@ package org.sonar.server.v2.config; import javax.annotation.Nullable; import org.sonar.api.resources.Languages; import org.sonar.db.DbClient; +import org.sonar.server.common.gitlab.config.GitlabConfigurationService; import org.sonar.server.common.group.service.GroupMembershipService; import org.sonar.server.common.group.service.GroupService; import org.sonar.server.common.health.CeStatusNodeCheck; @@ -35,10 +36,13 @@ import org.sonar.server.common.rule.service.RuleService; import org.sonar.server.common.text.MacroInterpreter; import org.sonar.server.common.user.service.UserService; import org.sonar.server.health.HealthChecker; +import org.sonar.server.management.ManagedInstanceService; import org.sonar.server.platform.NodeInformation; import org.sonar.server.rule.RuleDescriptionFormatter; import org.sonar.server.user.SystemPasscode; import org.sonar.server.user.UserSession; +import org.sonar.server.v2.api.gitlab.config.controller.DefaultGitlabConfigurationController; +import org.sonar.server.v2.api.gitlab.config.controller.GitlabConfigurationController; import org.sonar.server.v2.api.group.controller.DefaultGroupController; import org.sonar.server.v2.api.group.controller.GroupController; import org.sonar.server.v2.api.membership.controller.DefaultGroupMembershipController; @@ -121,4 +125,14 @@ public class PlatformLevel4WebConfig { return handlerMapping; } + @Bean + public GitlabConfigurationService gitlabConfigurationService(ManagedInstanceService managedInstanceService, DbClient dbClient) { + return new GitlabConfigurationService( managedInstanceService, dbClient); + } + + @Bean + public GitlabConfigurationController gitlabConfigurationController(UserSession userSession, GitlabConfigurationService gitlabConfigurationService) { + return new DefaultGitlabConfigurationController(userSession, gitlabConfigurationService); + } + } diff --git a/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/gitlab/config/DefaultGitlabConfigurationControllerTest.java b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/gitlab/config/DefaultGitlabConfigurationControllerTest.java new file mode 100644 index 00000000000..bcaea1bb2b5 --- /dev/null +++ b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/api/gitlab/config/DefaultGitlabConfigurationControllerTest.java @@ -0,0 +1,432 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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.v2.api.gitlab.config; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.server.common.NonNullUpdatedValue; +import org.sonar.server.common.UpdatedValue; +import org.sonar.server.common.gitlab.config.GitlabConfiguration; +import org.sonar.server.common.gitlab.config.GitlabConfigurationService; +import org.sonar.server.common.gitlab.config.SynchronizationType; +import org.sonar.server.common.gitlab.config.UpdateGitlabConfigurationRequest; +import org.sonar.server.exceptions.NotFoundException; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.v2.api.ControllerTester; +import org.sonar.server.v2.api.gitlab.config.controller.DefaultGitlabConfigurationController; +import org.sonar.server.v2.api.gitlab.config.resource.GitlabConfigurationResource; +import org.sonar.server.v2.api.gitlab.config.response.GitlabConfigurationSearchRestResponse; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.sonar.server.common.gitlab.config.SynchronizationType.AUTO_PROVISIONING; +import static org.sonar.server.common.gitlab.config.SynchronizationType.JIT; +import static org.sonar.server.v2.WebApiEndpoints.GITLAB_CONFIGURATION_ENDPOINT; +import static org.sonar.server.v2.WebApiEndpoints.JSON_MERGE_PATCH_CONTENT_TYPE; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +public class DefaultGitlabConfigurationControllerTest { + private static final Gson GSON = new GsonBuilder().create(); + + private static final GitlabConfiguration GITLAB_CONFIGURATION = new GitlabConfiguration( + "existing-id", + true, + "application-id", + "www.url.com", + "secret", + true, + AUTO_PROVISIONING, + true, + "provisioning-token", + Set.of("provisioning-group2", "provisioning-group1")); + private static final GitlabConfigurationResource EXPECTED_GITLAB_CONF_RESOURCE = new GitlabConfigurationResource( + GITLAB_CONFIGURATION.id(), + GITLAB_CONFIGURATION.enabled(), + GITLAB_CONFIGURATION.applicationId(), + GITLAB_CONFIGURATION.url(), + GITLAB_CONFIGURATION.synchronizeGroups(), + SynchronizationType.valueOf(GITLAB_CONFIGURATION.synchronizationType().name()), + GITLAB_CONFIGURATION.allowUsersToSignUp(), + List.of("provisioning-group1", "provisioning-group2")); + private static final String EXPECTED_CONFIGURATION = """ + { + "id": "existing-id", + "enabled": true, + "applicationId": "application-id", + "url": "www.url.com", + "synchronizeGroups": true, + "synchronizationType": "AUTO_PROVISIONING", + "allowUsersToSignUp": true, + "provisioningGroups": [ + "provisioning-group2", + "provisioning-group1" + ] + } + """; + + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + private final GitlabConfigurationService gitlabConfigurationService = mock(); + private final MockMvc mockMvc = ControllerTester.getMockMvc(new DefaultGitlabConfigurationController(userSession, gitlabConfigurationService)); + + @Test + public void fetchConfiguration_whenUserIsNotAdministrator_shouldReturnForbidden() throws Exception { + userSession.logIn().setNonSystemAdministrator(); + + mockMvc.perform(get(GITLAB_CONFIGURATION_ENDPOINT + "/1")) + .andExpectAll( + status().isForbidden(), + content().json("{\"message\":\"Insufficient privileges\"}")); + } + + @Test + public void fetchConfiguration_whenConfigNotFound_throws() throws Exception { + userSession.logIn().setSystemAdministrator(); + when(gitlabConfigurationService.getConfiguration("not-existing")).thenThrow(new NotFoundException("bla")); + + mockMvc.perform(get(GITLAB_CONFIGURATION_ENDPOINT + "/not-existing")) + .andExpectAll( + status().isNotFound(), + content().json("{\"message\":\"bla\"}")); + } + + @Test + public void fetchConfiguration_whenConfigFound_returnsIt() throws Exception { + userSession.logIn().setSystemAdministrator(); + when(gitlabConfigurationService.getConfiguration("existing-id")).thenReturn(GITLAB_CONFIGURATION); + + mockMvc.perform(get(GITLAB_CONFIGURATION_ENDPOINT + "/existing-id")) + .andExpectAll( + status().isOk(), + content().json(EXPECTED_CONFIGURATION)); + } + + @Test + public void search_whenNoParameters_shouldUseDefaultAndForwardToGroupMembershipService() throws Exception { + userSession.logIn().setSystemAdministrator(); + when(gitlabConfigurationService.findConfigurations()).thenReturn(Optional.of(GITLAB_CONFIGURATION)); + + MvcResult mvcResult = mockMvc.perform(get(GITLAB_CONFIGURATION_ENDPOINT)) + .andExpect(status().isOk()) + .andReturn(); + + GitlabConfigurationSearchRestResponse gitlabConfigurationResource = GSON.fromJson(mvcResult.getResponse().getContentAsString(), GitlabConfigurationSearchRestResponse.class); + + assertThat(gitlabConfigurationResource.page().pageSize()).isEqualTo(1000); + assertThat(gitlabConfigurationResource.page().pageIndex()).isEqualTo(1); + assertThat(gitlabConfigurationResource.page().total()).isEqualTo(1); + assertThat(gitlabConfigurationResource.gitlabConfigurations()).containsExactly(EXPECTED_GITLAB_CONF_RESOURCE); + } + + @Test + public void search_whenNoParametersAndNoConfig_shouldReturnEmptyList() throws Exception { + userSession.logIn().setSystemAdministrator(); + when(gitlabConfigurationService.findConfigurations()).thenReturn(Optional.empty()); + + MvcResult mvcResult = mockMvc.perform(get(GITLAB_CONFIGURATION_ENDPOINT)) + .andExpect(status().isOk()) + .andReturn(); + + GitlabConfigurationSearchRestResponse gitlabConfigurationResource = GSON.fromJson(mvcResult.getResponse().getContentAsString(), GitlabConfigurationSearchRestResponse.class); + + assertThat(gitlabConfigurationResource.page().pageSize()).isEqualTo(1000); + assertThat(gitlabConfigurationResource.page().pageIndex()).isEqualTo(1); + assertThat(gitlabConfigurationResource.page().total()).isZero(); + assertThat(gitlabConfigurationResource.gitlabConfigurations()).isEmpty(); + } + + @Test + public void updateConfiguration_whenUserIsNotAdministrator_shouldReturnForbidden() throws Exception { + userSession.logIn().setNonSystemAdministrator(); + + mockMvc.perform(patch(GITLAB_CONFIGURATION_ENDPOINT + "/existing-id") + .contentType(JSON_MERGE_PATCH_CONTENT_TYPE) + .content("{}")) + .andExpectAll( + status().isForbidden(), + content().json("{\"message\":\"Insufficient privileges\"}")); + } + + @Test + public void updateConfiguration_whenAllFieldsUpdated_performUpdates() throws Exception { + userSession.logIn().setSystemAdministrator(); + when(gitlabConfigurationService.updateConfiguration(any())).thenReturn(GITLAB_CONFIGURATION); + + String payload = """ + { + "enabled": true, + "applicationId": "application-id", + "url": "www.url.com", + "secret": "newSecret", + "synchronizeGroups": true, + "synchronizationType": "AUTO_PROVISIONING", + "allowUsersToSignUp": true, + "provisioningToken": "token", + "provisioningGroups": [ + "provisioning-group2", + "provisioning-group1" + ] + } + """; + + mockMvc.perform(patch(GITLAB_CONFIGURATION_ENDPOINT + "/existing-id") + .contentType(JSON_MERGE_PATCH_CONTENT_TYPE) + .content(payload)) + .andExpectAll( + status().isOk(), + content().json(EXPECTED_CONFIGURATION)); + + verify(gitlabConfigurationService).updateConfiguration(new UpdateGitlabConfigurationRequest( + "existing-id", + NonNullUpdatedValue.withValueOrThrow(true), + NonNullUpdatedValue.withValueOrThrow("application-id"), + NonNullUpdatedValue.withValueOrThrow("www.url.com"), + NonNullUpdatedValue.withValueOrThrow("newSecret"), + NonNullUpdatedValue.withValueOrThrow(true), + NonNullUpdatedValue.withValueOrThrow(AUTO_PROVISIONING), + NonNullUpdatedValue.withValueOrThrow(true), + UpdatedValue.withValue("token"), + NonNullUpdatedValue.withValueOrThrow(Set.of("provisioning-group2", "provisioning-group1")))); + } + + @Test + public void updateConfiguration_whenSomeFieldsUpdated_performUpdates() throws Exception { + userSession.logIn().setSystemAdministrator(); + when(gitlabConfigurationService.updateConfiguration(any())).thenReturn(GITLAB_CONFIGURATION); + + String payload = """ + { + "enabled": false, + "synchronizationType": "JIT", + "allowUsersToSignUp": false, + "provisioningToken": null + } + """; + + mockMvc.perform(patch(GITLAB_CONFIGURATION_ENDPOINT + "/existing-id") + .contentType(JSON_MERGE_PATCH_CONTENT_TYPE) + .content(payload)) + .andExpectAll( + status().isOk(), + content().json(EXPECTED_CONFIGURATION)); + + verify(gitlabConfigurationService).updateConfiguration(new UpdateGitlabConfigurationRequest( + "existing-id", + NonNullUpdatedValue.withValueOrThrow(false), + NonNullUpdatedValue.undefined(), + NonNullUpdatedValue.undefined(), + NonNullUpdatedValue.undefined(), + NonNullUpdatedValue.undefined(), + NonNullUpdatedValue.withValueOrThrow(JIT), + NonNullUpdatedValue.withValueOrThrow(false), + UpdatedValue.withValue(null), + NonNullUpdatedValue.undefined())); + } + + @Test + public void create_whenUserIsNotAdministrator_shouldReturnForbidden() throws Exception { + userSession.logIn().setNonSystemAdministrator(); + + mockMvc.perform( + post(GITLAB_CONFIGURATION_ENDPOINT) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .content(""" + { + "enabled": true, + "applicationId": "application-id", + "url": "www.url.com", + "secret": "123", + "synchronizeGroups": true, + "synchronizationType": "AUTO_PROVISIONING", + "allowUsersToSignUp": true, + "provisioningGroups": [ + "provisioning-group2", + "provisioning-group1" + ] + } + """)) + .andExpectAll( + status().isForbidden(), + content().json("{\"message\":\"Insufficient privileges\"}")); + } + + @Test + public void create_whenConfigCreated_returnsIt() throws Exception { + userSession.logIn().setSystemAdministrator(); + when(gitlabConfigurationService.createConfiguration(any())).thenReturn(GITLAB_CONFIGURATION); + + mockMvc.perform( + post(GITLAB_CONFIGURATION_ENDPOINT) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .content(""" + { + "enabled": true, + "applicationId": "application-id", + "secret": "123", + "url": "www.url.com", + "synchronizeGroups": true, + "synchronizationType": "AUTO_PROVISIONING", + "allowUsersToSignUp": true, + "provisioningGroups": [ + "provisioning-group2", + "provisioning-group1" + ] + } + + """)) + .andExpectAll( + status().isOk(), + content().json(""" + { + "id": "existing-id", + "enabled": true, + "applicationId": "application-id", + "url": "www.url.com", + "synchronizeGroups": true, + "synchronizationType": "AUTO_PROVISIONING", + "allowUsersToSignUp": true, + "provisioningGroups": [ + "provisioning-group2", + "provisioning-group1" + ] + } + """)); + + } + @Test + public void create_whenConfigCreatedWithoutOptionalParams_returnsIt() throws Exception { + userSession.logIn().setSystemAdministrator(); + when(gitlabConfigurationService.createConfiguration(any())).thenReturn(GITLAB_CONFIGURATION); + + mockMvc.perform( + post(GITLAB_CONFIGURATION_ENDPOINT) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .content(""" + { + "enabled": true, + "applicationId": "application-id", + "secret": "123", + "url": "www.url.com", + "synchronizeGroups": true, + "synchronizationType": "AUTO_PROVISIONING" + } + + """)) + .andExpectAll( + status().isOk(), + content().json(""" + { + "id": "existing-id", + "enabled": true, + "applicationId": "application-id", + "url": "www.url.com", + "synchronizeGroups": true, + "synchronizationType": "AUTO_PROVISIONING", + "allowUsersToSignUp": true, + "provisioningGroups": [ + "provisioning-group2", + "provisioning-group1" + ] + } + """)); + + } + + @Test + public void create_whenRequiredParameterIsMissing_shouldReturnBadRequest() throws Exception { + userSession.logIn().setSystemAdministrator(); + + mockMvc.perform( + post(GITLAB_CONFIGURATION_ENDPOINT) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .content(""" + { + "enabled": true, + "applicationId": "application-id", + "url": "www.url.com", + "synchronizeGroups": true, + "synchronizationType": "AUTO_PROVISIONING", + "allowUsersToSignUp": true, + "provisioningGroups": [ + "provisioning-group2", + "provisioning-group1" + ] + } + """)) + .andExpectAll( + status().isBadRequest(), + content().json( + "{\"message\":\"Value {} for field secret was rejected. Error: must not be empty.\"}")); + + } + + @Test + public void delete_whenUserIsNotAdministrator_shouldReturnForbidden() throws Exception { + userSession.logIn().setNonSystemAdministrator(); + + mockMvc.perform( + delete(GITLAB_CONFIGURATION_ENDPOINT + "/existing-id")) + .andExpectAll( + status().isForbidden(), + content().json("{\"message\":\"Insufficient privileges\"}")); + } + + @Test + public void delete_whenConfigIsDeleted_returnsNoContent() throws Exception { + userSession.logIn().setSystemAdministrator(); + + mockMvc.perform( + delete(GITLAB_CONFIGURATION_ENDPOINT + "/existing-id")) + .andExpectAll( + status().isNoContent()); + + verify(gitlabConfigurationService).deleteConfiguration("existing-id"); + } + + @Test + public void delete_whenConfigNotFound_returnsNotFound() throws Exception { + userSession.logIn().setSystemAdministrator(); + doThrow(new NotFoundException("Not found")).when(gitlabConfigurationService).deleteConfiguration("not-existing"); + + mockMvc.perform( + delete(GITLAB_CONFIGURATION_ENDPOINT + "/not-existing")) + .andExpectAll( + status().isNotFound(), + content().json("{\"message\":\"Not found\"}")); + } + +} |