Ver código fonte

SONAR-13999 drop more organization utility classes

tags/8.7.0.41497
Jacek 3 anos atrás
pai
commit
8ac59775a1

+ 0
- 30
server/sonar-webserver-auth/src/main/java/org/sonar/server/organization/OrganizationAlmBinding.java Ver arquivo

@@ -1,30 +0,0 @@
/*
* 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.server.ServerSide;
import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;

@ServerSide
public interface OrganizationAlmBinding {

void bindOrganization(DbSession dbSession, OrganizationDto organization, String installationId, boolean isNewOrganization);
}

+ 0
- 180
server/sonar-webserver-auth/src/main/java/org/sonar/server/organization/OrganizationUpdater.java Ver arquivo

@@ -1,180 +0,0 @@
/*
* 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 java.util.function.Consumer;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.api.web.UserRole;
import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.usergroups.DefaultGroupCreatorImpl;

import static java.util.Objects.requireNonNull;

public interface OrganizationUpdater {
String OWNERS_GROUP_NAME = "Owners";
String OWNERS_GROUP_DESCRIPTION = "Owners of organization";
String PERM_TEMPLATE_NAME = "Default template";
String PERM_TEMPLATE_DESCRIPTION_PATTERN = "Default permission template of organization %s";

/**
* Create a new organization with the specified properties and of which the specified user will assign
* Administer Organization permission.
* <p>
* This method does several operations at once:
* <ol>
* <li>create an ungarded organization with the specified details</li>
* <li>create a group called {@link #OWNERS_GROUP_NAME Owners} with all organization wide permissions</li>
* <li>create a group called {@link DefaultGroupCreatorImpl#DEFAULT_GROUP_NAME members} with browse permissions</li>
* <li>make the specified user a member of these groups</li>
* <li>create a default template for the organization
* <ul>
* <li>name is {@link #PERM_TEMPLATE_NAME Default template}</li>
* <li>description follows pattern {@link #PERM_TEMPLATE_DESCRIPTION_PATTERN} based on the organization name</li>
* </ul>
* </li>
* <li>this permission template defines the specified permissions (which effectively makes projects public):
* <ul>
* <li>group {@link #OWNERS_GROUP_NAME Owners} : {@link UserRole#ADMIN ADMIN}</li>
* <li>group {@link #OWNERS_GROUP_NAME Owners} : {@link UserRole#ISSUE_ADMIN ISSUE_ADMIN}</li>
* <li>group {@link #OWNERS_GROUP_NAME Owners} : {@link UserRole#SECURITYHOTSPOT_ADMIN SECURITYHOTSPOT_ADMIN}</li>
* <li>group {@link #OWNERS_GROUP_NAME Owners} : {@link UserRole#SCAN SCAN}</li>
* <li>group {@link DefaultGroupCreatorImpl#DEFAULT_GROUP_NAME members} : {@link UserRole#USER USER}</li>
* <li>group {@link DefaultGroupCreatorImpl#DEFAULT_GROUP_NAME members} : {@link UserRole#CODEVIEWER CODEVIEWER}</li>
* </ul>
* </li>
* </ol>
* </p>
*
* @return the created organization
*
* @throws KeyConflictException if an organization with the specified key already exists
* @throws IllegalArgumentException if any field of {@code newOrganization} is invalid according to {@link OrganizationValidation}
*/
OrganizationDto create(DbSession dbSession, UserDto userCreator, NewOrganization newOrganization, Consumer<OrganizationDto> beforeCommit) throws KeyConflictException;

/**
* Update the personal organization key of a user.
* No update will be performed if generated key match the same key as existing one.
*
* @throws IllegalStateException if user has no no personal organization
* @throws IllegalStateException if personal organization uuid does not exist
* @throws IllegalStateException if an organization with the key generated from the login already exists
*/
void updateOrganizationKey(DbSession dbSession, OrganizationDto organization, String newKey);

final class KeyConflictException extends Exception {
KeyConflictException(String message) {
super(message);
}
}

final class NewOrganization {
private final String key;
private final String name;
@CheckForNull
private final String description;
@CheckForNull
private final String url;
@CheckForNull
private final String avatar;

private NewOrganization(Builder builder) {
this.key = builder.key;
this.name = builder.name;
this.description = builder.description;
this.url = builder.url;
this.avatar = builder.avatarUrl;
}

public String getKey() {
return key;
}

public String getName() {
return name;
}

@CheckForNull
public String getDescription() {
return description;
}

@CheckForNull
public String getUrl() {
return url;
}

@CheckForNull
public String getAvatar() {
return avatar;
}

public static NewOrganization.Builder newOrganizationBuilder() {
return new Builder();
}

public static final class Builder {
private String key;
private String name;
private String description;
private String url;
private String avatarUrl;

private Builder() {
// use factory method
}

public Builder setKey(String key) {
this.key = requireNonNull(key, "key can't be null");
return this;
}

public Builder setName(String name) {
this.name = requireNonNull(name, "name can't be null");
return this;
}

public Builder setDescription(@Nullable String description) {
this.description = description;
return this;
}

public Builder setUrl(@Nullable String url) {
this.url = url;
return this;
}

public Builder setAvatarUrl(@Nullable String avatarUrl) {
this.avatarUrl = avatarUrl;
return this;
}

public NewOrganization build() {
requireNonNull(key, "key can't be null");
requireNonNull(name, "name can't be null");
return new NewOrganization(this);
}
}
}

}

+ 0
- 240
server/sonar-webserver-auth/src/main/java/org/sonar/server/organization/OrganizationUpdaterImpl.java Ver arquivo

@@ -1,240 +0,0 @@
/*
* 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 java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import javax.annotation.Nullable;
import org.sonar.api.utils.System2;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.permission.GlobalPermission;
import org.sonar.db.permission.GroupPermissionDto;
import org.sonar.db.permission.template.DefaultTemplates;
import org.sonar.db.permission.template.PermissionTemplateDto;
import org.sonar.db.qualitygate.QualityGateDto;
import org.sonar.db.qualityprofile.DefaultQProfileDto;
import org.sonar.db.qualityprofile.OrgQProfileDto;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserGroupDto;
import org.sonar.server.permission.PermissionService;
import org.sonar.server.qualityprofile.BuiltInQProfile;
import org.sonar.server.qualityprofile.BuiltInQProfileRepository;
import org.sonar.server.qualityprofile.QProfileName;
import org.sonar.server.user.index.UserIndexer;
import org.sonar.server.usergroups.DefaultGroupCreator;

import static com.google.common.base.Preconditions.checkState;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
import static org.sonar.api.web.UserRole.ADMIN;
import static org.sonar.api.web.UserRole.CODEVIEWER;
import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
import static org.sonar.api.web.UserRole.SECURITYHOTSPOT_ADMIN;
import static org.sonar.api.web.UserRole.USER;
import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex;
import static org.sonar.db.organization.OrganizationDto.Subscription.FREE;
import static org.sonar.db.permission.GlobalPermission.SCAN;

// TODO remove
@Deprecated
public class OrganizationUpdaterImpl implements OrganizationUpdater {

private final DbClient dbClient;
private final System2 system2;
private final UuidFactory uuidFactory;
private final OrganizationValidation organizationValidation;
private final BuiltInQProfileRepository builtInQProfileRepository;
private final DefaultGroupCreator defaultGroupCreator;
private final UserIndexer userIndexer;
private final PermissionService permissionService;

public OrganizationUpdaterImpl(DbClient dbClient, System2 system2, UuidFactory uuidFactory,
OrganizationValidation organizationValidation, UserIndexer userIndexer,
BuiltInQProfileRepository builtInQProfileRepository, DefaultGroupCreator defaultGroupCreator, PermissionService permissionService) {
this.dbClient = dbClient;
this.system2 = system2;
this.uuidFactory = uuidFactory;
this.organizationValidation = organizationValidation;
this.userIndexer = userIndexer;
this.builtInQProfileRepository = builtInQProfileRepository;
this.defaultGroupCreator = defaultGroupCreator;
this.permissionService = permissionService;
}

@Override
public OrganizationDto create(DbSession dbSession, UserDto userCreator, NewOrganization newOrganization, Consumer<OrganizationDto> beforeCommit) throws KeyConflictException {
validate(newOrganization);
String key = newOrganization.getKey();
if (organizationKeyIsUsed(dbSession, key)) {
throw new KeyConflictException(format("Organization key '%s' is already used", key));
}

QualityGateDto builtInQualityGate = dbClient.qualityGateDao().selectBuiltIn(dbSession);
OrganizationDto organization = insertOrganization(dbSession, newOrganization, builtInQualityGate);
beforeCommit.accept(organization);
GroupDto ownerGroup = insertOwnersGroup(dbSession);
GroupDto defaultGroup = defaultGroupCreator.create(dbSession);
insertDefaultTemplateOnGroups(dbSession, organization, ownerGroup, defaultGroup);
addCurrentUserToGroup(dbSession, ownerGroup, userCreator.getUuid());
addCurrentUserToGroup(dbSession, defaultGroup, userCreator.getUuid());
try (DbSession batchDbSession = dbClient.openSession(true)) {
insertQualityProfiles(dbSession, batchDbSession);
batchDbSession.commit();

// Elasticsearch is updated when DB session is committed
userIndexer.commitAndIndex(dbSession, userCreator);

return organization;
}
}

@Override
public void updateOrganizationKey(DbSession dbSession, OrganizationDto organization, String newKey) {
String sanitizedKey = organizationValidation.generateKeyFrom(newKey);
if (organization.getKey().equals(sanitizedKey)) {
return;
}
checkKey(dbSession, sanitizedKey);
dbClient.organizationDao().update(dbSession, organization.setKey(sanitizedKey));
}

private void checkKey(DbSession dbSession, String key) {
checkState(!organizationKeyIsUsed(dbSession, key),
"Can't create organization with key '%s' because an organization with this key already exists", key);
}

private void validate(NewOrganization newOrganization) {
requireNonNull(newOrganization, "newOrganization can't be null");
organizationValidation.checkName(newOrganization.getName());
organizationValidation.checkKey(newOrganization.getKey());
organizationValidation.checkDescription(newOrganization.getDescription());
organizationValidation.checkUrl(newOrganization.getUrl());
organizationValidation.checkAvatar(newOrganization.getAvatar());
}

private OrganizationDto insertOrganization(DbSession dbSession, NewOrganization newOrganization, QualityGateDto builtInQualityGate, Consumer<OrganizationDto>... extendCreation) {
OrganizationDto res = new OrganizationDto()
.setUuid(uuidFactory.create())
.setName(newOrganization.getName())
.setKey(newOrganization.getKey())
.setDescription(newOrganization.getDescription())
.setUrl(newOrganization.getUrl())
.setDefaultQualityGateUuid(builtInQualityGate.getUuid())
.setAvatarUrl(newOrganization.getAvatar())
.setSubscription(FREE);
Arrays.stream(extendCreation).forEach(c -> c.accept(res));
dbClient.organizationDao().insert(dbSession, res, false);
return res;
}

private boolean organizationKeyIsUsed(DbSession dbSession, String key) {
return dbClient.organizationDao().selectByKey(dbSession, key).isPresent();
}

private void insertDefaultTemplateOnGroups(DbSession dbSession, OrganizationDto organizationDto, GroupDto ownerGroup, GroupDto defaultGroup) {
Date now = new Date(system2.now());
PermissionTemplateDto permissionTemplateDto = dbClient.permissionTemplateDao().insert(
dbSession,
new PermissionTemplateDto()
.setUuid(uuidFactory.create())
.setName(PERM_TEMPLATE_NAME)
.setDescription(format(PERM_TEMPLATE_DESCRIPTION_PATTERN, organizationDto.getName()))
.setCreatedAt(now)
.setUpdatedAt(now));

insertGroupPermission(dbSession, permissionTemplateDto, ADMIN, ownerGroup);
insertGroupPermission(dbSession, permissionTemplateDto, SCAN.getKey(), ownerGroup);
insertGroupPermission(dbSession, permissionTemplateDto, USER, defaultGroup);
insertGroupPermission(dbSession, permissionTemplateDto, CODEVIEWER, defaultGroup);
insertGroupPermission(dbSession, permissionTemplateDto, ISSUE_ADMIN, defaultGroup);
insertGroupPermission(dbSession, permissionTemplateDto, SECURITYHOTSPOT_ADMIN, defaultGroup);

dbClient.organizationDao().setDefaultTemplates(
dbSession,
organizationDto.getUuid(),
new DefaultTemplates().setProjectUuid(permissionTemplateDto.getUuid()));
}

private void insertGroupPermission(DbSession dbSession, PermissionTemplateDto template, String permission, @Nullable GroupDto group) {
dbClient.permissionTemplateDao().insertGroupPermission(dbSession, template.getUuid(), group == null ? null : group.getUuid(), permission);
}

private void insertQualityProfiles(DbSession dbSession, DbSession batchDbSession) {
Map<QProfileName, BuiltInQProfile> builtInsPerName = builtInQProfileRepository.get().stream()
.collect(uniqueIndex(BuiltInQProfile::getQProfileName));

List<DefaultQProfileDto> defaults = new ArrayList<>();
dbClient.qualityProfileDao().selectBuiltInRuleProfiles(dbSession).forEach(rulesProfile -> {
OrgQProfileDto dto = new OrgQProfileDto()
.setRulesProfileUuid(rulesProfile.getUuid())
.setUuid(uuidFactory.create());

QProfileName name = new QProfileName(rulesProfile.getLanguage(), rulesProfile.getName());
BuiltInQProfile builtIn = builtInsPerName.get(name);
if (builtIn == null || builtIn.isDefault()) {
// If builtIn == null, the plugin has been removed
// rows of table default_qprofiles must be inserted after org_qprofiles
// in order to benefit from batch SQL inserts
defaults.add(new DefaultQProfileDto()
.setQProfileUuid(dto.getUuid())
.setLanguage(rulesProfile.getLanguage()));
}

dbClient.qualityProfileDao().insert(batchDbSession, dto);
});

defaults.forEach(defaultQProfileDto -> dbClient.defaultQProfileDao().insertOrUpdate(dbSession, defaultQProfileDto));
}

/**
* Owners group has an hard coded name, a description based on the organization's name and has all global permissions.
*/
private GroupDto insertOwnersGroup(DbSession dbSession) {
GroupDto group = dbClient.groupDao().insert(dbSession, new GroupDto()
.setUuid(uuidFactory.create())
.setName(OWNERS_GROUP_NAME)
.setDescription(OWNERS_GROUP_DESCRIPTION));
permissionService.getGlobalPermissions().forEach(p -> addPermissionToGroup(dbSession, group, p));
return group;
}

private void addPermissionToGroup(DbSession dbSession, GroupDto group, GlobalPermission permission) {
dbClient.groupPermissionDao().insert(
dbSession,
new GroupPermissionDto()
.setUuid(uuidFactory.create())
.setGroupUuid(group.getUuid())
.setRole(permission.getKey()));
}

private void addCurrentUserToGroup(DbSession dbSession, GroupDto group, String createUserUuid) {
dbClient.userGroupDao().insert(
dbSession,
new UserGroupDto().setGroupUuid(group.getUuid()).setUserUuid(createUserUuid));
}
}

+ 0
- 107
server/sonar-webserver-auth/src/main/java/org/sonar/server/organization/OrganizationValidation.java Ver arquivo

@@ -1,107 +0,0 @@
/*
* 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.CheckForNull;
import javax.annotation.Nullable;

public interface OrganizationValidation {
int KEY_MIN_LENGTH = 1;
int KEY_MAX_LENGTH = 255;
int NAME_MIN_LENGTH = 1;
int NAME_MAX_LENGTH = 255;
int DESCRIPTION_MAX_LENGTH = 256;
int URL_MAX_LENGTH = 256;

/**
* Ensures the specified argument is a valid key by failing with an exception if it is not so.
* <p>
* A valid key is non null and its length is between {@link #KEY_MIN_LENGTH} and {@link #KEY_MAX_LENGTH}.
* </p>
*
* @return the argument
*
* @throws NullPointerException if argument is {@code null}.
* @throws IllegalArgumentException if argument is not a valid key.
*/
String checkKey(String keyCandidate);

/**
* Ensures the specified argument is a valid name by failing with an exception if it is not so.
* <p>
* A valid name is non null and its length is between {@link #NAME_MIN_LENGTH} and {@link #NAME_MAX_LENGTH}.
* </p>
*
* @return the argument
*
* @throws NullPointerException if argument is {@code null}.
* @throws IllegalArgumentException if argument is not a valid name.
*/
String checkName(String nameCandidate);

/**
* Ensures the specified argument is either {@code null}, empty or a valid description by failing with an exception
* if it is not so.
* <p>
* The length of a valid url can't be more than {@link #DESCRIPTION_MAX_LENGTH 256}.
* </p>
*
* @return the argument
*
* @throws IllegalArgumentException if argument is not a valid description.
*/
@CheckForNull
String checkDescription(@Nullable String descriptionCandidate);

/**
* Ensures the specified argument is either {@code null}, empty or a valid URL by failing with an exception if it is
* not so.
* <p>
* The length of a valid URL can't be more than {@link #URL_MAX_LENGTH 256}.
* </p>
*
* @return the argument
*
* @throws IllegalArgumentException if argument is not a valid url.
*/
@CheckForNull
String checkUrl(@Nullable String urlCandidate);

/**
* Ensures the specified argument is either {@code null}, empty or a valid avatar URL by failing with an exception if
* it is not so.
* <p>
* The length of a valid avatar URL can't be more than {@link #URL_MAX_LENGTH 256}.
* </p>
*
* @return the argument
*
* @throws IllegalArgumentException if argument is not a valid avatar url.
*/
@CheckForNull
String checkAvatar(@Nullable String avatarCandidate);

/**
* Transforms the specified string into a valid key.
*
* @see #checkKey(String)
*/
String generateKeyFrom(String source);
}

+ 0
- 83
server/sonar-webserver-auth/src/main/java/org/sonar/server/organization/OrganizationValidationImpl.java Ver arquivo

@@ -1,83 +0,0 @@
/*
* 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.CheckForNull;
import javax.annotation.Nullable;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
import static org.sonar.core.util.Slug.slugify;

public class OrganizationValidationImpl implements OrganizationValidation {

@Override
public String checkKey(String keyCandidate) {
requireNonNull(keyCandidate, "key can't be null");
checkArgument(keyCandidate.length() >= KEY_MIN_LENGTH, "Key must not be empty");
checkArgument(keyCandidate.length() <= KEY_MAX_LENGTH, "Key '%s' must be at most %s chars long", keyCandidate, KEY_MAX_LENGTH);
checkArgument(slugify(keyCandidate).equals(keyCandidate), "Key '%s' contains at least one invalid char", keyCandidate);

return keyCandidate;
}

@Override
public String checkName(String nameCandidate) {
requireNonNull(nameCandidate, "name can't be null");

checkArgument(nameCandidate.length() >= NAME_MIN_LENGTH, "Name must not be empty");
checkArgument(nameCandidate.length() <= NAME_MAX_LENGTH, "Name '%s' must be at most %s chars long", nameCandidate, NAME_MAX_LENGTH);

return nameCandidate;
}

@Override
public String checkDescription(@Nullable String descriptionCandidate) {
checkParamMaxLength(descriptionCandidate, "Description", DESCRIPTION_MAX_LENGTH);

return descriptionCandidate;
}

@Override
public String checkUrl(@Nullable String urlCandidate) {
checkParamMaxLength(urlCandidate, "Url", URL_MAX_LENGTH);

return urlCandidate;
}

@Override
public String checkAvatar(@Nullable String avatarCandidate) {
checkParamMaxLength(avatarCandidate, "Avatar", URL_MAX_LENGTH);

return avatarCandidate;
}

@CheckForNull
private static void checkParamMaxLength(@Nullable String value, String label, int maxLength) {
if (value != null) {
checkArgument(value.length() <= maxLength, "%s '%s' must be at most %s chars long", label, value, maxLength);
}
}

@Override
public String generateKeyFrom(String source) {
return slugify(source);
}
}

+ 0
- 336
server/sonar-webserver-auth/src/test/java/org/sonar/server/organization/OrganizationUpdaterImplTest.java Ver arquivo

@@ -1,336 +0,0 @@
/*
* 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 java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import org.apache.commons.lang.RandomStringUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.ResourceTypes;
import org.sonar.api.utils.System2;
import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.component.ResourceTypesRule;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.organization.OrganizationDto.Subscription;
import org.sonar.db.qualitygate.QualityGateDto;
import org.sonar.db.qualityprofile.QProfileDto;
import org.sonar.db.qualityprofile.RulesProfileDto;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserMembershipDto;
import org.sonar.db.user.UserMembershipQuery;
import org.sonar.server.es.EsTester;
import org.sonar.server.es.SearchOptions;
import org.sonar.server.permission.PermissionService;
import org.sonar.server.permission.PermissionServiceImpl;
import org.sonar.server.qualityprofile.BuiltInQProfile;
import org.sonar.server.qualityprofile.BuiltInQProfileRepositoryRule;
import org.sonar.server.qualityprofile.QProfileName;
import org.sonar.server.user.index.UserIndex;
import org.sonar.server.user.index.UserIndexer;
import org.sonar.server.user.index.UserQuery;
import org.sonar.server.usergroups.DefaultGroupCreator;
import org.sonar.server.usergroups.DefaultGroupCreatorImpl;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.server.language.LanguageTesting.newLanguage;
import static org.sonar.server.organization.OrganizationUpdater.NewOrganization.newOrganizationBuilder;

public class OrganizationUpdaterImplTest {
private static final long A_DATE = 12893434L;

private final OrganizationUpdater.NewOrganization FULL_POPULATED_NEW_ORGANIZATION = newOrganizationBuilder()
.setName("a-name")
.setKey("a-key")
.setDescription("a-description")
.setUrl("a-url")
.setAvatarUrl("a-avatar")
.build();

private final System2 system2 = new TestSystem2().setNow(A_DATE);

private static final Consumer<OrganizationDto> EMPTY_ORGANIZATION_CONSUMER = o -> {
};

@Rule
public DbTester db = DbTester.create(system2);
@Rule
public EsTester es = EsTester.create();
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Rule
public BuiltInQProfileRepositoryRule builtInQProfileRepositoryRule = new BuiltInQProfileRepositoryRule();

private final DbSession dbSession = db.getSession();

private final IllegalArgumentException exceptionThrownByOrganizationValidation = new IllegalArgumentException("simulate IAE thrown by OrganizationValidation");
private final DbClient dbClient = db.getDbClient();
private final UuidFactory uuidFactory = new SequenceUuidFactory();
private final OrganizationValidation organizationValidation = mock(OrganizationValidation.class);
private final UserIndexer userIndexer = new UserIndexer(dbClient, es.client());
private final UserIndex userIndex = new UserIndex(es.client(), system2);
private final DefaultGroupCreator defaultGroupCreator = new DefaultGroupCreatorImpl(dbClient, uuidFactory, TestDefaultOrganizationProvider.from(db));

private final ResourceTypes resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT);
private final PermissionService permissionService = new PermissionServiceImpl(resourceTypes);

private final OrganizationUpdaterImpl underTest = new OrganizationUpdaterImpl(dbClient, system2, uuidFactory, organizationValidation, userIndexer,
builtInQProfileRepositoryRule, defaultGroupCreator, permissionService);

@Test
public void create_creates_organization_with_properties_from_NewOrganization_arg() throws OrganizationUpdater.KeyConflictException {
builtInQProfileRepositoryRule.initialize();
UserDto user = db.users().insertUser();
db.qualityGates().insertBuiltInQualityGate();

underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION, EMPTY_ORGANIZATION_CONSUMER);

OrganizationDto organization = dbClient.organizationDao().selectByKey(dbSession, FULL_POPULATED_NEW_ORGANIZATION.getKey()).get();
assertThat(organization.getUuid()).isNotEmpty();
assertThat(organization.getKey()).isEqualTo(FULL_POPULATED_NEW_ORGANIZATION.getKey());
assertThat(organization.getName()).isEqualTo(FULL_POPULATED_NEW_ORGANIZATION.getName());
assertThat(organization.getDescription()).isEqualTo(FULL_POPULATED_NEW_ORGANIZATION.getDescription());
assertThat(organization.getUrl()).isEqualTo(FULL_POPULATED_NEW_ORGANIZATION.getUrl());
assertThat(organization.getAvatarUrl()).isEqualTo(FULL_POPULATED_NEW_ORGANIZATION.getAvatar());
assertThat(organization.getSubscription()).isEqualTo(Subscription.FREE);
assertThat(organization.getCreatedAt()).isEqualTo(A_DATE);
assertThat(organization.getUpdatedAt()).isEqualTo(A_DATE);
}

@Test
public void create_creates_members_group_and_add_current_user_to_it() throws OrganizationUpdater.KeyConflictException {
UserDto user = db.users().insertUser();
builtInQProfileRepositoryRule.initialize();
db.qualityGates().insertBuiltInQualityGate();

underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION, EMPTY_ORGANIZATION_CONSUMER);

verifyMembersGroup(user);
}

@Test
public void create_does_not_require_description_url_and_avatar_to_be_non_null() throws OrganizationUpdater.KeyConflictException {
builtInQProfileRepositoryRule.initialize();
UserDto user = db.users().insertUser();
db.qualityGates().insertBuiltInQualityGate();

underTest.create(dbSession, user, newOrganizationBuilder()
.setKey("key")
.setName("name")
.build(), EMPTY_ORGANIZATION_CONSUMER);

OrganizationDto organization = dbClient.organizationDao().selectByKey(dbSession, "key").get();
assertThat(organization.getKey()).isEqualTo("key");
assertThat(organization.getName()).isEqualTo("name");
assertThat(organization.getDescription()).isNull();
assertThat(organization.getUrl()).isNull();
assertThat(organization.getAvatarUrl()).isNull();
}

// TODO this test should be removed when default organization entry is removed from db. For now regardless of which org we provide, the test
// makes sure the user is assigned to default org
@Test
public void create_add_current_user_as_member_of_default_organization() throws OrganizationUpdater.KeyConflictException {
UserDto user = db.users().insertUser();
builtInQProfileRepositoryRule.initialize();
db.qualityGates().insertBuiltInQualityGate();

underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION, EMPTY_ORGANIZATION_CONSUMER);

assertThat(
userIndex.search(UserQuery.builder().setOrganizationUuid(db.getDefaultOrganization().getUuid()).setTextQuery(user.getLogin()).build(), new SearchOptions()).getTotal())
.isEqualTo(1L);
}

@Test
public void create_associates_to_built_in_quality_profiles() throws OrganizationUpdater.KeyConflictException {
BuiltInQProfile builtIn1 = builtInQProfileRepositoryRule.add(newLanguage("foo"), "qp1", true);
BuiltInQProfile builtIn2 = builtInQProfileRepositoryRule.add(newLanguage("foo"), "qp2");
builtInQProfileRepositoryRule.initialize();
insertRulesProfile(builtIn1);
insertRulesProfile(builtIn2);
UserDto user = db.users().insertUser();
db.qualityGates().insertBuiltInQualityGate();

underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION, EMPTY_ORGANIZATION_CONSUMER);

List<QProfileDto> profiles = dbClient.qualityProfileDao().selectAll(dbSession);
assertThat(profiles).extracting(p -> new QProfileName(p.getLanguage(), p.getName())).containsExactlyInAnyOrder(
builtIn1.getQProfileName(), builtIn2.getQProfileName());
assertThat(dbClient.qualityProfileDao().selectDefaultProfile(dbSession, "foo").getName())
.isEqualTo("qp1");
}

private void insertRulesProfile(BuiltInQProfile builtIn) {
RulesProfileDto dto = new RulesProfileDto()
.setIsBuiltIn(true)
.setUuid(RandomStringUtils.randomAlphabetic(40))
.setLanguage(builtIn.getLanguage())
.setName(builtIn.getName());
dbClient.qualityProfileDao().insert(db.getSession(), dto);
db.commit();
}

@Test
public void create_calls_consumer() throws OrganizationUpdater.KeyConflictException {
UserDto user = db.users().insertUser();
builtInQProfileRepositoryRule.initialize();
db.qualityGates().insertBuiltInQualityGate();
Boolean[] isConsumerCalled = new Boolean[] {false};

underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION, o -> {
isConsumerCalled[0] = true;
});

assertThat(isConsumerCalled[0]).isEqualTo(true);
}

@Test
public void create_throws_NPE_if_NewOrganization_arg_is_null() throws OrganizationUpdater.KeyConflictException {
UserDto user = db.users().insertUser();

expectedException.expect(NullPointerException.class);
expectedException.expectMessage("newOrganization can't be null");

underTest.create(dbSession, user, null, EMPTY_ORGANIZATION_CONSUMER);
}

@Test
public void create_throws_exception_thrown_by_checkValidKey() throws OrganizationUpdater.KeyConflictException {
UserDto user = db.users().insertUser();

when(organizationValidation.checkKey(FULL_POPULATED_NEW_ORGANIZATION.getKey()))
.thenThrow(exceptionThrownByOrganizationValidation);

createThrowsExceptionThrownByOrganizationValidation(user);
}

@Test
public void create_throws_exception_thrown_by_checkValidDescription() throws OrganizationUpdater.KeyConflictException {
UserDto user = db.users().insertUser();

when(organizationValidation.checkDescription(FULL_POPULATED_NEW_ORGANIZATION.getDescription())).thenThrow(exceptionThrownByOrganizationValidation);

createThrowsExceptionThrownByOrganizationValidation(user);
}

@Test
public void create_throws_exception_thrown_by_checkValidUrl() throws OrganizationUpdater.KeyConflictException {
UserDto user = db.users().insertUser();

when(organizationValidation.checkUrl(FULL_POPULATED_NEW_ORGANIZATION.getUrl())).thenThrow(exceptionThrownByOrganizationValidation);

createThrowsExceptionThrownByOrganizationValidation(user);
}

@Test
public void create_throws_exception_thrown_by_checkValidAvatar() throws OrganizationUpdater.KeyConflictException {
UserDto user = db.users().insertUser();

when(organizationValidation.checkAvatar(FULL_POPULATED_NEW_ORGANIZATION.getAvatar())).thenThrow(exceptionThrownByOrganizationValidation);

createThrowsExceptionThrownByOrganizationValidation(user);
}

private void createThrowsExceptionThrownByOrganizationValidation(UserDto user) throws OrganizationUpdater.KeyConflictException {
try {
underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION, EMPTY_ORGANIZATION_CONSUMER);
fail(exceptionThrownByOrganizationValidation + " should have been thrown");
} catch (IllegalArgumentException e) {
assertThat(e).isSameAs(exceptionThrownByOrganizationValidation);
}
}

@Test
public void create_fails_with_KeyConflictException_if_org_with_key_in_NewOrganization_arg_already_exists_in_db() throws OrganizationUpdater.KeyConflictException {
db.organizations().insertForKey(FULL_POPULATED_NEW_ORGANIZATION.getKey());
UserDto user = db.users().insertUser();

expectedException.expect(OrganizationUpdater.KeyConflictException.class);
expectedException.expectMessage("Organization key '" + FULL_POPULATED_NEW_ORGANIZATION.getKey() + "' is already used");

underTest.create(dbSession, user, FULL_POPULATED_NEW_ORGANIZATION, EMPTY_ORGANIZATION_CONSUMER);
}

@Test
public void update_personal_organization() {
OrganizationDto organization = db.organizations().insert(o -> o.setKey("old login"));
when(organizationValidation.generateKeyFrom("new_login")).thenReturn("new_login");

underTest.updateOrganizationKey(dbSession, organization, "new_login");

OrganizationDto organizationReloaded = dbClient.organizationDao().selectByUuid(dbSession, organization.getUuid()).get();
assertThat(organizationReloaded.getKey()).isEqualTo("new_login");
}

@Test
public void does_not_update_personal_organization_when_generated_organization_key_does_not_change() {
OrganizationDto organization = db.organizations().insert(o -> o.setKey("login"));
when(organizationValidation.generateKeyFrom("Login")).thenReturn("login");

underTest.updateOrganizationKey(dbSession, organization, "Login");

OrganizationDto organizationReloaded = dbClient.organizationDao().selectByUuid(dbSession, organization.getUuid()).get();
assertThat(organizationReloaded.getKey()).isEqualTo("login");
}

@Test
public void fail_to_update_personal_organization_when_new_key_already_exist() {
OrganizationDto organization = db.organizations().insert();
db.organizations().insert(o -> o.setKey("new_login"));
when(organizationValidation.generateKeyFrom("new_login")).thenReturn("new_login");

expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("Can't create organization with key 'new_login' because an organization with this key already exists");

underTest.updateOrganizationKey(dbSession, organization, "new_login");
}

private void verifyMembersGroup(UserDto user) {
Optional<GroupDto> groupOpt = dbClient.groupDao().selectByName(dbSession, "Members");
assertThat(groupOpt).isPresent();
GroupDto groupDto = groupOpt.get();
assertThat(groupDto.getDescription()).isEqualTo("All members of the organization");

assertThat(dbClient.groupPermissionDao().selectGlobalPermissionsOfGroup(dbSession, groupDto.getUuid())).isEmpty();
List<UserMembershipDto> members = dbClient.groupMembershipDao().selectMembers(
dbSession,
UserMembershipQuery.builder()
.groupUuid(groupDto.getUuid())
.membership(UserMembershipQuery.IN).build(),
0, Integer.MAX_VALUE);
assertThat(members)
.extracting(UserMembershipDto::getLogin)
.containsOnly(user.getLogin());
}

}

+ 0
- 240
server/sonar-webserver-auth/src/test/java/org/sonar/server/organization/OrganizationValidationImplTest.java Ver arquivo

@@ -1,240 +0,0 @@
/*
* 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 com.google.common.base.Strings;
import java.util.Random;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;

public class OrganizationValidationImplTest {
private static final String STRING_32_CHARS = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
private static final String STRING_64_CHARS = STRING_32_CHARS + STRING_32_CHARS;
private static final String STRING_256_CHARS = STRING_64_CHARS + STRING_64_CHARS + STRING_64_CHARS + STRING_64_CHARS;

private static final String STRING_255_CHARS = Strings.repeat("a", 255);

@Rule
public ExpectedException expectedException = ExpectedException.none();

private OrganizationValidationImpl underTest = new OrganizationValidationImpl();

@Test
public void checkValidKey_throws_NPE_if_arg_is_null() {
expectedException.expect(NullPointerException.class);
expectedException.expectMessage("key can't be null");

underTest.checkKey(null);
}

@Test
public void checkValidKey_throws_IAE_if_arg_is_empty() {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Key must not be empty");

underTest.checkKey("");
}

@Test
public void checkValidKey_throws_IAE_if_key_is_empty() {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Key must not be empty");

underTest.checkKey("");
}

@Test
public void checkValidKey_does_not_fail_if_arg_is_1_to_255_chars_long() {
String str = "a";
for (int i = 0; i < 254; i++) {
underTest.checkKey(str);
str += "a";
}
}

@Test
public void checkValidKey_throws_IAE_when_more_than_300_characters() {
String key = STRING_255_CHARS + "b";

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Key '" + key + "' must be at most 255 chars long");

underTest.checkKey(key);
}

@Test
public void checkValidKey_throws_IAE_if_arg_contains_invalid_chars() {
char[] invalidChars = {'é', '<', '@'};

for (char invalidChar : invalidChars) {
String str = "aa" + invalidChar;
try {
underTest.checkKey(str);
fail("A IllegalArgumentException should have been thrown");
} catch (IllegalArgumentException e) {
assertThat(e).hasMessage("Key '" + str + "' contains at least one invalid char");
}
}
}

@Test
public void checkValidName_throws_NPE_if_arg_is_null() {
expectedException.expect(NullPointerException.class);
expectedException.expectMessage("name can't be null");

underTest.checkName(null);
}

@Test
public void checkValidName_throws_IAE_if_empty() {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Name must not be empty");

underTest.checkName("");
}

@Test
public void checkValidName_does_not_fail_if_arg_is_1_to_255_chars_long() {
String str = "a";
for (int i = 0; i < 254; i++) {
underTest.checkName(str);
str += "a";
}
}

@Test
public void checkValidName_throws_IAE_when_more_than_255_characters() {
String str = STRING_255_CHARS + "b";

expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Name '" + str + "' must be at most 255 chars long");

underTest.checkName(str);
}

@Test
public void checkValidDescription_does_not_fail_if_arg_is_null() {
underTest.checkDescription(null);
}

@Test
public void checkValidDescription_does_not_fail_if_arg_is_empty() {
underTest.checkDescription("");
}

@Test
public void checkValidDescription_does_not_fail_if_arg_is_1_to_256_chars_long() {
String str = "1";
for (int i = 0; i < 256; i++) {
underTest.checkDescription(str);
str += "a";
}
}

@Test
public void checkValidDescription_throws_IAE_if_arg_is_more_than_256_chars_long() {
String str = STRING_256_CHARS;
underTest.checkDescription(str);
for (int i = 0; i < 5 + Math.abs(new Random().nextInt(10)); i++) {
str += "c";
try {
underTest.checkDescription(str);
fail("A IllegalArgumentException should have been thrown");
} catch (IllegalArgumentException e) {
assertThat(e).hasMessage("Description '" + str + "' must be at most 256 chars long");
}
}
}

@Test
public void checkValidUrl_does_not_fail_if_arg_is_null() {
underTest.checkUrl(null);
}

@Test
public void checkValidUrl_does_not_fail_if_arg_is_1_to_256_chars_long() {
String str = "1";
for (int i = 0; i < 256; i++) {
underTest.checkUrl(str);
str += "a";
}
}

@Test
public void checkValidUrl_throws_IAE_if_arg_is_more_than_256_chars_long() {
String str = STRING_256_CHARS;
underTest.checkUrl(str);
for (int i = 0; i < 5 + Math.abs(new Random().nextInt(10)); i++) {
str += "c";
try {
underTest.checkUrl(str);
fail("A IllegalArgumentException should have been thrown");
} catch (IllegalArgumentException e) {
assertThat(e).hasMessage("Url '" + str + "' must be at most 256 chars long");
}
}
}

@Test
public void checkValidAvatar_does_not_fail_if_arg_is_null() {
underTest.checkAvatar(null);
}

@Test
public void checkValidAvatar_does_not_fail_if_arg_is_1_to_256_chars_long() {
String str = "1";
for (int i = 0; i < 256; i++) {
underTest.checkAvatar(str);
str += "a";
}
}

@Test
public void checkValidAvatar_throws_IAE_if_arg_is_more_than_256_chars_long() {
String str = STRING_256_CHARS;
underTest.checkAvatar(str);
for (int i = 0; i < 5 + Math.abs(new Random().nextInt(10)); i++) {
str += "c";
try {
underTest.checkAvatar(str);
fail("A IllegalArgumentException should have been thrown");
} catch (IllegalArgumentException e) {
assertThat(e).hasMessage("Avatar '" + str + "' must be at most 256 chars long");
}
}
}

@Test
public void generateKeyFrom_returns_slug_of_arg() {
assertThat(underTest.generateKeyFrom("foo")).isEqualTo("foo");
assertThat(underTest.generateKeyFrom(" FOO ")).isEqualTo("foo");
assertThat(underTest.generateKeyFrom("he's here")).isEqualTo("he-s-here");
assertThat(underTest.generateKeyFrom("foo-bar")).isEqualTo("foo-bar");
assertThat(underTest.generateKeyFrom("foo_bar")).isEqualTo("foo_bar");
assertThat(underTest.generateKeyFrom("accents éà")).isEqualTo("accents-ea");
assertThat(underTest.generateKeyFrom("<foo>")).isEqualTo("foo");
assertThat(underTest.generateKeyFrom("<\"foo:\">")).isEqualTo("foo");
}

}

+ 0
- 1
server/sonar-webserver-webapi/src/main/java/org/sonar/server/organization/ws/OrganizationsWsModule.java Ver arquivo

@@ -32,7 +32,6 @@ public class OrganizationsWsModule extends Module {
protected void configureModule() {
add(
OrganizationsWs.class,
OrganizationsWsSupport.class,
MemberUpdater.class,
// actions
SearchAction.class,

+ 0
- 131
server/sonar-webserver-webapi/src/main/java/org/sonar/server/organization/ws/OrganizationsWsSupport.java Ver arquivo

@@ -1,131 +0,0 @@
/*
* 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 javax.annotation.CheckForNull;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.WebService;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.server.organization.OrganizationValidation;
import org.sonarqube.ws.Organizations.Organization;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Optional.ofNullable;
import static org.sonar.server.organization.OrganizationValidation.DESCRIPTION_MAX_LENGTH;
import static org.sonar.server.organization.OrganizationValidation.NAME_MAX_LENGTH;
import static org.sonar.server.organization.OrganizationValidation.NAME_MIN_LENGTH;
import static org.sonar.server.organization.OrganizationValidation.URL_MAX_LENGTH;

/**
* Factorizes code and constants between Organization WS's actions.
*/
public class OrganizationsWsSupport {
static final String PARAM_ORGANIZATION = "organization";
static final String PARAM_KEY = "key";
static final String PARAM_NAME = "name";
static final String PARAM_DESCRIPTION = "description";
static final String PARAM_URL = "url";
static final String PARAM_AVATAR_URL = "avatar";
static final String PARAM_LOGIN = "login";

private final OrganizationValidation organizationValidation;
private final DbClient dbClient;

public OrganizationsWsSupport(OrganizationValidation organizationValidation, DbClient dbClient) {
this.organizationValidation = organizationValidation;
this.dbClient = dbClient;
}

String getAndCheckMandatoryName(Request request) {
String name = request.mandatoryParam(PARAM_NAME);
organizationValidation.checkName(name);
return name;
}

@CheckForNull
String getAndCheckName(Request request) {
String name = request.param(PARAM_NAME);
if (name != null) {
organizationValidation.checkName(name);
}
return name;
}

@CheckForNull
String getAndCheckAvatar(Request request) {
return organizationValidation.checkAvatar(request.param(PARAM_AVATAR_URL));
}

@CheckForNull
String getAndCheckUrl(Request request) {
return organizationValidation.checkUrl(request.param(PARAM_URL));
}

@CheckForNull
String getAndCheckDescription(Request request) {
return organizationValidation.checkDescription(request.param(PARAM_DESCRIPTION));
}

void addOrganizationDetailsParams(WebService.NewAction action, boolean isNameRequired) {
action.createParam(PARAM_NAME)
.setRequired(isNameRequired)
.setMinimumLength(NAME_MIN_LENGTH)
.setMaximumLength(NAME_MAX_LENGTH)
.setDescription("Name of the organization")
.setExampleValue("Foo Company");

action.createParam(PARAM_DESCRIPTION)
.setRequired(false)
.setMaximumLength(DESCRIPTION_MAX_LENGTH)
.setDescription("Description of the organization.<br/> It must be less than 256 chars long.")
.setExampleValue("The Foo company produces quality software for Bar.");

action.createParam(PARAM_URL)
.setRequired(false)
.setMaximumLength(URL_MAX_LENGTH)
.setDescription("URL of the organization.<br/> It must be less than 256 chars long.")
.setExampleValue("https://www.foo.com");

action.createParam(PARAM_AVATAR_URL)
.setRequired(false)
.setMaximumLength(URL_MAX_LENGTH)
.setDescription("URL of the organization avatar.<br/> It must be less than 256 chars long.")
.setExampleValue("https://www.foo.com/foo.png");
}

Organization.Builder toOrganization(OrganizationDto dto) {
Organization.Builder builder = Organization.newBuilder();
builder
.setName(dto.getName())
.setKey(dto.getKey());
ofNullable(dto.getDescription()).ifPresent(builder::setDescription);
ofNullable(dto.getUrl()).ifPresent(builder::setUrl);
ofNullable(dto.getAvatarUrl()).ifPresent(builder::setAvatar);
return builder;
}


void checkMemberSyncIsDisabled(DbSession dbSession, OrganizationDto organization) {
dbClient.organizationAlmBindingDao().selectByOrganization(dbSession, organization).ifPresent(orgAlmBindingDto ->
checkArgument(!orgAlmBindingDto.isMembersSyncEnable(), "You can't add or remove members when synchronization of organization with alm is enabled."));
}
}

+ 2
- 2
server/sonar-webserver-webapi/src/main/java/org/sonar/server/organization/ws/SearchMembersAction.java Ver arquivo

@@ -54,10 +54,10 @@ 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.organization.ws.OrganizationsWsSupport.PARAM_ORGANIZATION;
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;
@@ -94,7 +94,7 @@ public class SearchMembersAction implements OrganizationsWsAction {
.setDefaultValue(SELECTED.value())
.setPossibleValues(SELECTED.value(), SelectionMode.DESELECTED.value());

action.createParam(PARAM_ORGANIZATION)
action.createParam(ORGANIZATION_PARAM)
.setDescription("Organization key")
.setInternal(true)
.setRequired(false);

+ 0
- 4
server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java Ver arquivo

@@ -111,8 +111,6 @@ 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.OrganizationUpdaterImpl;
import org.sonar.server.organization.OrganizationValidationImpl;
import org.sonar.server.organization.ws.OrganizationsWsModule;
import org.sonar.server.permission.DefaultTemplatesResolverImpl;
import org.sonar.server.permission.GroupPermissionChanger;
@@ -268,8 +266,6 @@ public class PlatformLevel4 extends PlatformLevel {
UpdateCenterWsModule.class,

// organizations
OrganizationValidationImpl.class,
OrganizationUpdaterImpl.class,
OrganizationsWsModule.class,
BillingValidationsProxyImpl.class,


Carregando…
Cancelar
Salvar