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.

TemplateUsersAction.java 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2023 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.permission.ws.template;
  21. import com.google.common.collect.Multimap;
  22. import com.google.common.collect.Ordering;
  23. import com.google.common.collect.TreeMultimap;
  24. import java.util.List;
  25. import org.sonar.api.server.ws.Request;
  26. import org.sonar.api.server.ws.Response;
  27. import org.sonar.api.server.ws.WebService;
  28. import org.sonar.api.server.ws.WebService.Param;
  29. import org.sonar.api.utils.Paging;
  30. import org.sonar.db.DbClient;
  31. import org.sonar.db.DbSession;
  32. import org.sonar.db.permission.PermissionQuery;
  33. import org.sonar.db.permission.template.PermissionTemplateDto;
  34. import org.sonar.db.permission.template.PermissionTemplateUserDto;
  35. import org.sonar.db.user.UserDto;
  36. import org.sonar.server.common.avatar.AvatarResolver;
  37. import org.sonar.server.permission.RequestValidator;
  38. import org.sonar.server.permission.ws.PermissionWsSupport;
  39. import org.sonar.server.permission.ws.PermissionsWsAction;
  40. import org.sonar.server.permission.ws.WsParameters;
  41. import org.sonar.server.user.UserSession;
  42. import org.sonarqube.ws.Permissions;
  43. import org.sonarqube.ws.Permissions.UsersWsResponse;
  44. import static com.google.common.base.Strings.emptyToNull;
  45. import static java.util.Optional.ofNullable;
  46. import static org.sonar.api.server.ws.WebService.Param.PAGE;
  47. import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE;
  48. import static org.sonar.api.server.ws.WebService.Param.TEXT_QUERY;
  49. import static org.sonar.db.permission.PermissionQuery.DEFAULT_PAGE_SIZE;
  50. import static org.sonar.db.permission.PermissionQuery.RESULTS_MAX_SIZE;
  51. import static org.sonar.db.permission.PermissionQuery.SEARCH_QUERY_MIN_LENGTH;
  52. import static org.sonar.server.permission.PermissionPrivilegeChecker.checkGlobalAdmin;
  53. import static org.sonar.server.permission.ws.WsParameters.createTemplateParameters;
  54. import static org.sonar.server.ws.WsUtils.writeProtobuf;
  55. import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION;
  56. public class TemplateUsersAction implements PermissionsWsAction {
  57. private final DbClient dbClient;
  58. private final UserSession userSession;
  59. private final PermissionWsSupport wsSupport;
  60. private final AvatarResolver avatarResolver;
  61. private final WsParameters wsParameters;
  62. private final RequestValidator requestValidator;
  63. public TemplateUsersAction(DbClient dbClient, UserSession userSession, PermissionWsSupport wsSupport, AvatarResolver avatarResolver,
  64. WsParameters wsParameters, RequestValidator requestValidator) {
  65. this.dbClient = dbClient;
  66. this.userSession = userSession;
  67. this.wsSupport = wsSupport;
  68. this.avatarResolver = avatarResolver;
  69. this.wsParameters = wsParameters;
  70. this.requestValidator = requestValidator;
  71. }
  72. @Override
  73. public void define(WebService.NewController context) {
  74. WebService.NewAction action = context
  75. .createAction("template_users")
  76. .setSince("5.2")
  77. .setDescription("Lists the users with their permission as individual users rather than through group affiliation on the chosen template. <br />" +
  78. "This service defaults to all users, but can be limited to users with a specific permission by providing the desired permission.<br>" +
  79. "Requires the following permission: 'Administer System'.")
  80. .addPagingParams(DEFAULT_PAGE_SIZE, RESULTS_MAX_SIZE)
  81. .setInternal(true)
  82. .setResponseExample(getClass().getResource("template_users-example.json"))
  83. .setHandler(this);
  84. action.createParam(Param.TEXT_QUERY)
  85. .setMinimumLength(SEARCH_QUERY_MIN_LENGTH)
  86. .setDescription("Limit search to user names that contain the supplied string. <br/>" +
  87. "When this parameter is not set, only users having at least one permission are returned.")
  88. .setExampleValue("eri");
  89. wsParameters.createProjectPermissionParameter(action).setRequired(false);
  90. createTemplateParameters(action);
  91. }
  92. @Override
  93. public void handle(Request wsRequest, Response wsResponse) throws Exception {
  94. try (DbSession dbSession = dbClient.openSession(false)) {
  95. WsTemplateRef templateRef = WsTemplateRef.fromRequest(wsRequest);
  96. PermissionTemplateDto template = wsSupport.findTemplate(dbSession, templateRef);
  97. checkGlobalAdmin(userSession);
  98. PermissionQuery query = buildQuery(wsRequest);
  99. int total = dbClient.permissionTemplateDao().countUserLoginsByQueryAndTemplate(dbSession, query, template.getUuid());
  100. Paging paging = Paging.forPageIndex(wsRequest.mandatoryParamAsInt(PAGE)).withPageSize(wsRequest.mandatoryParamAsInt(PAGE_SIZE)).andTotal(total);
  101. List<UserDto> users = findUsers(dbSession, query, template);
  102. List<PermissionTemplateUserDto> permissionTemplateUsers = dbClient.permissionTemplateDao().selectUserPermissionsByTemplateIdAndUserLogins(dbSession, template.getUuid(),
  103. users.stream().map(UserDto::getLogin).toList());
  104. Permissions.UsersWsResponse templateUsersResponse = buildResponse(users, permissionTemplateUsers, paging);
  105. writeProtobuf(templateUsersResponse, wsRequest, wsResponse);
  106. }
  107. }
  108. private PermissionQuery buildQuery(Request wsRequest) {
  109. String textQuery = wsRequest.param(TEXT_QUERY);
  110. String permission = wsRequest.param(PARAM_PERMISSION);
  111. PermissionQuery.Builder query = PermissionQuery.builder()
  112. .setPermission(permission != null ? requestValidator.validateProjectPermission(permission) : null)
  113. .setPageIndex(wsRequest.mandatoryParamAsInt(PAGE))
  114. .setPageSize(wsRequest.mandatoryParamAsInt(PAGE_SIZE))
  115. .setSearchQuery(textQuery);
  116. return query.build();
  117. }
  118. private Permissions.UsersWsResponse buildResponse(List<UserDto> users, List<PermissionTemplateUserDto> permissionTemplateUsers, Paging paging) {
  119. Multimap<String, String> permissionsByUserUuid = TreeMultimap.create();
  120. permissionTemplateUsers.forEach(userPermission -> permissionsByUserUuid.put(userPermission.getUserUuid(), userPermission.getPermission()));
  121. UsersWsResponse.Builder responseBuilder = UsersWsResponse.newBuilder();
  122. users.forEach(user -> {
  123. Permissions.User.Builder userResponse = responseBuilder.addUsersBuilder()
  124. .setLogin(user.getLogin())
  125. .addAllPermissions(permissionsByUserUuid.get(user.getUuid()));
  126. ofNullable(user.getEmail()).ifPresent(userResponse::setEmail);
  127. ofNullable(user.getName()).ifPresent(userResponse::setName);
  128. ofNullable(emptyToNull(user.getEmail())).ifPresent(u -> userResponse.setAvatar(avatarResolver.create(user)));
  129. });
  130. responseBuilder.getPagingBuilder()
  131. .setPageIndex(paging.pageIndex())
  132. .setPageSize(paging.pageSize())
  133. .setTotal(paging.total())
  134. .build();
  135. return responseBuilder.build();
  136. }
  137. private List<UserDto> findUsers(DbSession dbSession, PermissionQuery query, PermissionTemplateDto template) {
  138. List<String> orderedLogins = dbClient.permissionTemplateDao().selectUserLoginsByQueryAndTemplate(dbSession, query, template.getUuid());
  139. return Ordering.explicit(orderedLogins).onResultOf(UserDto::getLogin).immutableSortedCopy(dbClient.userDao().selectByLogins(dbSession, orderedLogins));
  140. }
  141. }