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

OrganizationUpdaterImpl.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2020 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.server.organization;
  21. import java.util.ArrayList;
  22. import java.util.Arrays;
  23. import java.util.Date;
  24. import java.util.List;
  25. import java.util.Map;
  26. import java.util.function.Consumer;
  27. import javax.annotation.Nullable;
  28. import org.sonar.api.utils.System2;
  29. import org.sonar.core.util.UuidFactory;
  30. import org.sonar.db.DbClient;
  31. import org.sonar.db.DbSession;
  32. import org.sonar.db.organization.DefaultTemplates;
  33. import org.sonar.db.organization.OrganizationDto;
  34. import org.sonar.db.organization.OrganizationMemberDto;
  35. import org.sonar.db.permission.GroupPermissionDto;
  36. import org.sonar.db.permission.OrganizationPermission;
  37. import org.sonar.db.permission.template.PermissionTemplateDto;
  38. import org.sonar.db.qualitygate.QualityGateDto;
  39. import org.sonar.db.qualityprofile.DefaultQProfileDto;
  40. import org.sonar.db.qualityprofile.OrgQProfileDto;
  41. import org.sonar.db.user.GroupDto;
  42. import org.sonar.db.user.UserDto;
  43. import org.sonar.db.user.UserGroupDto;
  44. import org.sonar.server.permission.PermissionService;
  45. import org.sonar.server.qualityprofile.BuiltInQProfile;
  46. import org.sonar.server.qualityprofile.BuiltInQProfileRepository;
  47. import org.sonar.server.qualityprofile.QProfileName;
  48. import org.sonar.server.user.index.UserIndexer;
  49. import org.sonar.server.usergroups.DefaultGroupCreator;
  50. import static com.google.common.base.Preconditions.checkState;
  51. import static java.lang.String.format;
  52. import static java.util.Objects.requireNonNull;
  53. import static org.sonar.api.web.UserRole.ADMIN;
  54. import static org.sonar.api.web.UserRole.CODEVIEWER;
  55. import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
  56. import static org.sonar.api.web.UserRole.SECURITYHOTSPOT_ADMIN;
  57. import static org.sonar.api.web.UserRole.USER;
  58. import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex;
  59. import static org.sonar.db.organization.OrganizationDto.Subscription.FREE;
  60. import static org.sonar.db.permission.OrganizationPermission.SCAN;
  61. public class OrganizationUpdaterImpl implements OrganizationUpdater {
  62. private final DbClient dbClient;
  63. private final System2 system2;
  64. private final UuidFactory uuidFactory;
  65. private final OrganizationValidation organizationValidation;
  66. private final BuiltInQProfileRepository builtInQProfileRepository;
  67. private final DefaultGroupCreator defaultGroupCreator;
  68. private final UserIndexer userIndexer;
  69. private final PermissionService permissionService;
  70. public OrganizationUpdaterImpl(DbClient dbClient, System2 system2, UuidFactory uuidFactory,
  71. OrganizationValidation organizationValidation, UserIndexer userIndexer,
  72. BuiltInQProfileRepository builtInQProfileRepository, DefaultGroupCreator defaultGroupCreator, PermissionService permissionService) {
  73. this.dbClient = dbClient;
  74. this.system2 = system2;
  75. this.uuidFactory = uuidFactory;
  76. this.organizationValidation = organizationValidation;
  77. this.userIndexer = userIndexer;
  78. this.builtInQProfileRepository = builtInQProfileRepository;
  79. this.defaultGroupCreator = defaultGroupCreator;
  80. this.permissionService = permissionService;
  81. }
  82. @Override
  83. public OrganizationDto create(DbSession dbSession, UserDto userCreator, NewOrganization newOrganization, Consumer<OrganizationDto> beforeCommit) throws KeyConflictException {
  84. validate(newOrganization);
  85. String key = newOrganization.getKey();
  86. if (organizationKeyIsUsed(dbSession, key)) {
  87. throw new KeyConflictException(format("Organization key '%s' is already used", key));
  88. }
  89. QualityGateDto builtInQualityGate = dbClient.qualityGateDao().selectBuiltIn(dbSession);
  90. OrganizationDto organization = insertOrganization(dbSession, newOrganization, builtInQualityGate);
  91. beforeCommit.accept(organization);
  92. insertOrganizationMember(dbSession, organization, userCreator.getUuid());
  93. dbClient.qualityGateDao().associate(dbSession, uuidFactory.create(), organization, builtInQualityGate);
  94. GroupDto ownerGroup = insertOwnersGroup(dbSession, organization);
  95. GroupDto defaultGroup = defaultGroupCreator.create(dbSession);
  96. insertDefaultTemplateOnGroups(dbSession, organization, ownerGroup, defaultGroup);
  97. addCurrentUserToGroup(dbSession, ownerGroup, userCreator.getUuid());
  98. addCurrentUserToGroup(dbSession, defaultGroup, userCreator.getUuid());
  99. try (DbSession batchDbSession = dbClient.openSession(true)) {
  100. insertQualityProfiles(dbSession, batchDbSession);
  101. batchDbSession.commit();
  102. // Elasticsearch is updated when DB session is committed
  103. userIndexer.commitAndIndex(dbSession, userCreator);
  104. return organization;
  105. }
  106. }
  107. @Override
  108. public void updateOrganizationKey(DbSession dbSession, OrganizationDto organization, String newKey) {
  109. String sanitizedKey = organizationValidation.generateKeyFrom(newKey);
  110. if (organization.getKey().equals(sanitizedKey)) {
  111. return;
  112. }
  113. checkKey(dbSession, sanitizedKey);
  114. dbClient.organizationDao().update(dbSession, organization.setKey(sanitizedKey));
  115. }
  116. private void checkKey(DbSession dbSession, String key) {
  117. checkState(!organizationKeyIsUsed(dbSession, key),
  118. "Can't create organization with key '%s' because an organization with this key already exists", key);
  119. }
  120. private void validate(NewOrganization newOrganization) {
  121. requireNonNull(newOrganization, "newOrganization can't be null");
  122. organizationValidation.checkName(newOrganization.getName());
  123. organizationValidation.checkKey(newOrganization.getKey());
  124. organizationValidation.checkDescription(newOrganization.getDescription());
  125. organizationValidation.checkUrl(newOrganization.getUrl());
  126. organizationValidation.checkAvatar(newOrganization.getAvatar());
  127. }
  128. private OrganizationDto insertOrganization(DbSession dbSession, NewOrganization newOrganization, QualityGateDto builtInQualityGate, Consumer<OrganizationDto>... extendCreation) {
  129. OrganizationDto res = new OrganizationDto()
  130. .setUuid(uuidFactory.create())
  131. .setName(newOrganization.getName())
  132. .setKey(newOrganization.getKey())
  133. .setDescription(newOrganization.getDescription())
  134. .setUrl(newOrganization.getUrl())
  135. .setDefaultQualityGateUuid(builtInQualityGate.getUuid())
  136. .setAvatarUrl(newOrganization.getAvatar())
  137. .setSubscription(FREE);
  138. Arrays.stream(extendCreation).forEach(c -> c.accept(res));
  139. dbClient.organizationDao().insert(dbSession, res, false);
  140. return res;
  141. }
  142. private boolean organizationKeyIsUsed(DbSession dbSession, String key) {
  143. return dbClient.organizationDao().selectByKey(dbSession, key).isPresent();
  144. }
  145. private void insertDefaultTemplateOnGroups(DbSession dbSession, OrganizationDto organizationDto, GroupDto ownerGroup, GroupDto defaultGroup) {
  146. Date now = new Date(system2.now());
  147. PermissionTemplateDto permissionTemplateDto = dbClient.permissionTemplateDao().insert(
  148. dbSession,
  149. new PermissionTemplateDto()
  150. .setUuid(uuidFactory.create())
  151. .setName(PERM_TEMPLATE_NAME)
  152. .setDescription(format(PERM_TEMPLATE_DESCRIPTION_PATTERN, organizationDto.getName()))
  153. .setCreatedAt(now)
  154. .setUpdatedAt(now));
  155. insertGroupPermission(dbSession, permissionTemplateDto, ADMIN, ownerGroup);
  156. insertGroupPermission(dbSession, permissionTemplateDto, SCAN.getKey(), ownerGroup);
  157. insertGroupPermission(dbSession, permissionTemplateDto, USER, defaultGroup);
  158. insertGroupPermission(dbSession, permissionTemplateDto, CODEVIEWER, defaultGroup);
  159. insertGroupPermission(dbSession, permissionTemplateDto, ISSUE_ADMIN, defaultGroup);
  160. insertGroupPermission(dbSession, permissionTemplateDto, SECURITYHOTSPOT_ADMIN, defaultGroup);
  161. dbClient.organizationDao().setDefaultTemplates(
  162. dbSession,
  163. organizationDto.getUuid(),
  164. new DefaultTemplates().setProjectUuid(permissionTemplateDto.getUuid()));
  165. }
  166. private void insertGroupPermission(DbSession dbSession, PermissionTemplateDto template, String permission, @Nullable GroupDto group) {
  167. dbClient.permissionTemplateDao().insertGroupPermission(dbSession, template.getUuid(), group == null ? null : group.getUuid(), permission);
  168. }
  169. private void insertQualityProfiles(DbSession dbSession, DbSession batchDbSession) {
  170. Map<QProfileName, BuiltInQProfile> builtInsPerName = builtInQProfileRepository.get().stream()
  171. .collect(uniqueIndex(BuiltInQProfile::getQProfileName));
  172. List<DefaultQProfileDto> defaults = new ArrayList<>();
  173. dbClient.qualityProfileDao().selectBuiltInRuleProfiles(dbSession).forEach(rulesProfile -> {
  174. OrgQProfileDto dto = new OrgQProfileDto()
  175. .setRulesProfileUuid(rulesProfile.getUuid())
  176. .setUuid(uuidFactory.create());
  177. QProfileName name = new QProfileName(rulesProfile.getLanguage(), rulesProfile.getName());
  178. BuiltInQProfile builtIn = builtInsPerName.get(name);
  179. if (builtIn == null || builtIn.isDefault()) {
  180. // If builtIn == null, the plugin has been removed
  181. // rows of table default_qprofiles must be inserted after org_qprofiles
  182. // in order to benefit from batch SQL inserts
  183. defaults.add(new DefaultQProfileDto()
  184. .setQProfileUuid(dto.getUuid())
  185. .setLanguage(rulesProfile.getLanguage()));
  186. }
  187. dbClient.qualityProfileDao().insert(batchDbSession, dto);
  188. });
  189. defaults.forEach(defaultQProfileDto -> dbClient.defaultQProfileDao().insertOrUpdate(dbSession, defaultQProfileDto));
  190. }
  191. /**
  192. * Owners group has an hard coded name, a description based on the organization's name and has all global permissions.
  193. */
  194. private GroupDto insertOwnersGroup(DbSession dbSession, OrganizationDto organization) {
  195. GroupDto group = dbClient.groupDao().insert(dbSession, new GroupDto()
  196. .setUuid(uuidFactory.create())
  197. .setName(OWNERS_GROUP_NAME)
  198. .setDescription(OWNERS_GROUP_DESCRIPTION));
  199. permissionService.getGlobalPermissions().forEach(p -> addPermissionToGroup(dbSession, group, p));
  200. return group;
  201. }
  202. private void addPermissionToGroup(DbSession dbSession, GroupDto group, OrganizationPermission permission) {
  203. dbClient.groupPermissionDao().insert(
  204. dbSession,
  205. new GroupPermissionDto()
  206. .setUuid(uuidFactory.create())
  207. .setGroupUuid(group.getUuid())
  208. .setRole(permission.getKey()));
  209. }
  210. private void addCurrentUserToGroup(DbSession dbSession, GroupDto group, String createUserUuid) {
  211. dbClient.userGroupDao().insert(
  212. dbSession,
  213. new UserGroupDto().setGroupUuid(group.getUuid()).setUserUuid(createUserUuid));
  214. }
  215. private void insertOrganizationMember(DbSession dbSession, OrganizationDto organizationDto, String userUuid) {
  216. dbClient.organizationMemberDao().insert(dbSession, new OrganizationMemberDto()
  217. .setOrganizationUuid(organizationDto.getUuid())
  218. .setUserUuid(userUuid));
  219. }
  220. }