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.

SearchAction.java 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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.usergroups.ws;
  21. import java.util.Arrays;
  22. import java.util.HashSet;
  23. import java.util.List;
  24. import java.util.Map;
  25. import java.util.Set;
  26. import org.sonar.api.server.ws.Change;
  27. import org.sonar.api.server.ws.Request;
  28. import org.sonar.api.server.ws.Response;
  29. import org.sonar.api.server.ws.WebService.NewController;
  30. import org.sonar.api.server.ws.WebService.Param;
  31. import org.sonar.api.utils.Paging;
  32. import org.sonar.core.util.stream.MoreCollectors;
  33. import org.sonar.db.DbClient;
  34. import org.sonar.db.DbSession;
  35. import org.sonar.db.user.GroupDto;
  36. import org.sonar.server.es.SearchOptions;
  37. import org.sonar.server.user.UserSession;
  38. import org.sonar.server.usergroups.DefaultGroupFinder;
  39. import static java.util.Optional.ofNullable;
  40. import static org.apache.commons.lang.StringUtils.defaultIfBlank;
  41. import static org.sonar.api.utils.Paging.forPageIndex;
  42. import static org.sonar.db.permission.OrganizationPermission.ADMINISTER;
  43. import static org.sonar.server.es.SearchOptions.MAX_PAGE_SIZE;
  44. import static org.sonar.server.ws.WsUtils.writeProtobuf;
  45. import static org.sonarqube.ws.UserGroups.Group;
  46. import static org.sonarqube.ws.UserGroups.SearchWsResponse;
  47. public class SearchAction implements UserGroupsWsAction {
  48. private static final String FIELD_NAME = "name";
  49. private static final String FIELD_DESCRIPTION = "description";
  50. private static final String FIELD_MEMBERS_COUNT = "membersCount";
  51. private static final List<String> ALL_FIELDS = Arrays.asList(FIELD_NAME, FIELD_DESCRIPTION, FIELD_MEMBERS_COUNT);
  52. private final DbClient dbClient;
  53. private final UserSession userSession;
  54. private final DefaultGroupFinder defaultGroupFinder;
  55. public SearchAction(DbClient dbClient, UserSession userSession, DefaultGroupFinder defaultGroupFinder) {
  56. this.dbClient = dbClient;
  57. this.userSession = userSession;
  58. this.defaultGroupFinder = defaultGroupFinder;
  59. }
  60. @Override
  61. public void define(NewController context) {
  62. context.createAction("search")
  63. .setDescription("Search for user groups.<br>" +
  64. "Requires the following permission: 'Administer System'.")
  65. .setHandler(this)
  66. .setResponseExample(getClass().getResource("search-example.json"))
  67. .setSince("5.2")
  68. .addFieldsParam(ALL_FIELDS)
  69. .addPagingParams(100, MAX_PAGE_SIZE)
  70. .addSearchQuery("sonar-users", "names")
  71. .setChangelog(
  72. new Change("8.4", "Field 'id' in the response is deprecated. Format changes from integer to string."),
  73. new Change("6.4", "Paging response fields moved to a Paging object"),
  74. new Change("6.4", "'default' response field has been added"));
  75. }
  76. @Override
  77. public void handle(Request request, Response response) throws Exception {
  78. int page = request.mandatoryParamAsInt(Param.PAGE);
  79. int pageSize = request.mandatoryParamAsInt(Param.PAGE_SIZE);
  80. SearchOptions options = new SearchOptions()
  81. .setPage(page, pageSize);
  82. String query = defaultIfBlank(request.param(Param.TEXT_QUERY), "");
  83. Set<String> fields = neededFields(request);
  84. try (DbSession dbSession = dbClient.openSession(false)) {
  85. userSession.checkLoggedIn().checkPermission(ADMINISTER);
  86. GroupDto defaultGroup = defaultGroupFinder.findDefaultGroup(dbSession);
  87. int limit = dbClient.groupDao().countByQuery(dbSession, query);
  88. Paging paging = forPageIndex(page).withPageSize(pageSize).andTotal(limit);
  89. List<GroupDto> groups = dbClient.groupDao().selectByQuery(dbSession, query, options.getOffset(), pageSize);
  90. List<String> groupUuids = groups.stream().map(GroupDto::getUuid).collect(MoreCollectors.toList(groups.size()));
  91. Map<String, Integer> userCountByGroup = dbClient.groupMembershipDao().countUsersByGroups(dbSession, groupUuids);
  92. writeProtobuf(buildResponse(groups, userCountByGroup, fields, paging, defaultGroup), request, response);
  93. }
  94. }
  95. private static Set<String> neededFields(Request request) {
  96. Set<String> fields = new HashSet<>();
  97. List<String> fieldsFromRequest = request.paramAsStrings(Param.FIELDS);
  98. if (fieldsFromRequest == null || fieldsFromRequest.isEmpty()) {
  99. fields.addAll(ALL_FIELDS);
  100. } else {
  101. fields.addAll(fieldsFromRequest);
  102. }
  103. return fields;
  104. }
  105. private static SearchWsResponse buildResponse(List<GroupDto> groups, Map<String, Integer> userCountByGroup, Set<String> fields, Paging paging, GroupDto defaultGroup) {
  106. SearchWsResponse.Builder responseBuilder = SearchWsResponse.newBuilder();
  107. groups.forEach(group -> responseBuilder
  108. .addGroups(toWsGroup(group, userCountByGroup.get(group.getName()), fields, defaultGroup.getUuid().equals(group.getUuid()))));
  109. responseBuilder.getPagingBuilder()
  110. .setPageIndex(paging.pageIndex())
  111. .setPageSize(paging.pageSize())
  112. .setTotal(paging.total())
  113. .build();
  114. return responseBuilder.build();
  115. }
  116. private static Group toWsGroup(GroupDto group, Integer memberCount, Set<String> fields, boolean isDefault) {
  117. Group.Builder groupBuilder = Group.newBuilder()
  118. .setId(group.getUuid())
  119. .setDefault(isDefault);
  120. if (fields.contains(FIELD_NAME)) {
  121. groupBuilder.setName(group.getName());
  122. }
  123. if (fields.contains(FIELD_DESCRIPTION)) {
  124. ofNullable(group.getDescription()).ifPresent(groupBuilder::setDescription);
  125. }
  126. if (fields.contains(FIELD_MEMBERS_COUNT)) {
  127. groupBuilder.setMembersCount(memberCount);
  128. }
  129. return groupBuilder.build();
  130. }
  131. }