Skip to content

Commit

Permalink
SONAR-6479 WS permissions/users search users with a specific permission
Browse files Browse the repository at this point in the history
  • Loading branch information
teryk committed Aug 6, 2015
1 parent 4d119d3 commit b4e4af1
Show file tree
Hide file tree
Showing 24 changed files with 2,258 additions and 126 deletions.
Expand Up @@ -30,44 +30,60 @@
import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.Paging;
import org.sonar.core.permission.GroupWithPermission;
import org.sonar.core.permission.UserWithPermission;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ResourceDao;
import org.sonar.db.component.ResourceDto;
import org.sonar.db.component.ResourceQuery;
import org.sonar.db.permission.GroupWithPermissionDto;
import org.sonar.db.permission.PermissionDao;
import org.sonar.db.permission.PermissionQuery;
import org.sonar.db.permission.PermissionTemplateDao;
import org.sonar.db.permission.PermissionTemplateDto;
import org.sonar.core.permission.UserWithPermission;
import org.sonar.db.permission.UserWithPermissionDto;
import org.sonar.db.component.ResourceDao;
import org.sonar.db.component.ResourceDto;
import org.sonar.db.component.ResourceQuery;
import org.sonar.server.exceptions.NotFoundException;

import static com.google.common.collect.Lists.newArrayList;

@ServerSide
public class PermissionFinder {

private final DbClient dbClient;

private final PermissionDao permissionDao;
private final ResourceDao resourceDao;

private final PermissionTemplateDao permissionTemplateDao;

public PermissionFinder(PermissionDao permissionDao, ResourceDao resourceDao, PermissionTemplateDao permissionTemplateDao) {
this.resourceDao = resourceDao;
this.permissionDao = permissionDao;
this.permissionTemplateDao = permissionTemplateDao;
public PermissionFinder(DbClient dbClient) {
this.dbClient = dbClient;
this.resourceDao = dbClient.resourceDao();
this.permissionDao = dbClient.permissionDao();
this.permissionTemplateDao = dbClient.permissionTemplateDao();
}

public UserWithPermissionQueryResult findUsersWithPermission(PermissionQuery query) {
Long componentId = componentId(query.component());
int limit = limit(query);
return toUserQueryResult(permissionDao.selectUsers(query, componentId, offset(query), limit), limit);
int limit = query.pageSize();
DbSession dbSession = dbClient.openSession(false);
try {
int total = permissionDao.countUsers(dbSession, query, componentId);
return toUserQueryResult(permissionDao.selectUsers(dbSession, query, componentId, offset(query), limit), total);
} finally {
dbClient.closeSession(dbSession);
}
}

public UserWithPermissionQueryResult findUsersWithPermissionTemplate(PermissionQuery query) {
Long permissionTemplateId = templateId(query.template());
int limit = limit(query);
return toUserQueryResult(permissionTemplateDao.selectUsers(query, permissionTemplateId, offset(query), limit), limit);
int limit = query.pageSize();
DbSession dbSession = dbClient.openSession(false);
try {
int total = permissionTemplateDao.countUsers(dbSession, query, permissionTemplateId);
return toUserQueryResult(permissionTemplateDao.selectUsers(dbSession, query, permissionTemplateId, offset(query), limit), total);
} finally {
dbClient.closeSession(dbSession);
}
}

/**
Expand All @@ -86,14 +102,8 @@ public GroupWithPermissionQueryResult findGroupsWithPermissionTemplate(Permissio
return toGroupQueryResult(permissionTemplateDao.selectGroups(query, permissionTemplateId), query);
}

private static UserWithPermissionQueryResult toUserQueryResult(List<UserWithPermissionDto> dtos, int limit) {
boolean hasMoreResults = false;
if (dtos.size() == limit) {
hasMoreResults = true;
// Removed last entry as it's only need to know if there more results or not
dtos.remove(dtos.size() - 1);
}
return new UserWithPermissionQueryResult(toUserWithPermissionList(dtos), hasMoreResults);
private static UserWithPermissionQueryResult toUserQueryResult(List<UserWithPermissionDto> dtos, int total) {
return new UserWithPermissionQueryResult(toUserWithPermissionList(dtos), total);
}

private static List<UserWithPermission> toUserWithPermissionList(List<UserWithPermissionDto> dtos) {
Expand Down Expand Up @@ -140,11 +150,6 @@ private static int offset(PermissionQuery query) {
return (pageIndex - 1) * pageSize;
}

private static int limit(PermissionQuery query) {
// Add one to page size in order to be able to know if there's more results or not
return query.pageSize() + 1;
}

private List<GroupWithPermissionDto> filterMembership(List<GroupWithPermissionDto> dtos, PermissionQuery query) {
return newArrayList(Iterables.filter(dtos, new GroupWithPermissionMatchQuery(query)));
}
Expand Down
Expand Up @@ -20,17 +20,15 @@

package org.sonar.server.permission;

import java.util.Map;
import org.sonar.api.server.ws.WebService.SelectionMode;

import org.sonar.db.permission.PermissionQuery;
import org.sonar.db.user.GroupMembershipQuery;
import org.sonar.server.util.RubyUtils;

import java.util.Map;

public class PermissionQueryParser {

private PermissionQueryParser(){
private PermissionQueryParser() {
// Utility class
}

Expand All @@ -39,15 +37,15 @@ static PermissionQuery toQuery(Map<String, Object> params) {
builder.permission((String) params.get("permission"));
builder.component((String) params.get("component"));
builder.template((String) params.get("template"));
builder.membership(membership(params));
builder.membership(toMembership((String) params.get("selected")));
builder.search((String) params.get("query"));
builder.pageIndex(RubyUtils.toInteger(params.get("page")));
builder.pageSize(RubyUtils.toInteger(params.get("pageSize")));
return builder.build();
}

private static String membership(Map<String, Object> params) {
SelectionMode selectionMode = SelectionMode.fromParam((String) params.get("selected"));
public static String toMembership(String selectionModeString) {
SelectionMode selectionMode = SelectionMode.fromParam(selectionModeString);
if (SelectionMode.SELECTED == selectionMode) {
return GroupMembershipQuery.IN;
} else if (SelectionMode.DESELECTED == selectionMode) {
Expand All @@ -57,5 +55,4 @@ private static String membership(Map<String, Object> params) {
}
}


}
Expand Up @@ -47,10 +47,11 @@
@ServerSide
public class PermissionService {



private enum Operation {
ADD, REMOVE
ADD, REMOVE;
}

private static final String OBJECT_TYPE_USER = "User";
private static final String OBJECT_TYPE_GROUP = "Group";
private static final String NOT_FOUND_FORMAT = "%s %s does not exist";
Expand All @@ -61,7 +62,6 @@ private enum Operation {
private final IssueAuthorizationIndexer issueAuthorizationIndexer;
private final UserSession userSession;
private final ComponentFinder componentFinder;

public PermissionService(DbClient dbClient, PermissionRepository permissionRepository, PermissionFinder finder,
IssueAuthorizationIndexer issueAuthorizationIndexer, UserSession userSession, ComponentFinder componentFinder) {
this.dbClient = dbClient;
Expand Down
Expand Up @@ -20,26 +20,31 @@

package org.sonar.server.permission;

import org.sonar.core.permission.UserWithPermission;

import java.util.List;
import org.sonar.core.permission.UserWithPermission;

public class UserWithPermissionQueryResult {

private List<UserWithPermission> users;
private boolean hasMoreResults;
private final List<UserWithPermission> users;
private final int total;
private final boolean hasMoreResults;

public UserWithPermissionQueryResult(List<UserWithPermission> users, boolean hasMoreResults) {
public UserWithPermissionQueryResult(List<UserWithPermission> users, int total) {
this.users = users;
this.hasMoreResults = hasMoreResults;
this.total = total;
this.hasMoreResults = total > users.size();
}

public List<UserWithPermission> users() {
return users;
}

public int total() {
return total;
}

// called by Ruby Code
public boolean hasMoreResults() {
return hasMoreResults;
}

}
Expand Up @@ -30,6 +30,7 @@ protected void configureModule() {
AddGroupAction.class,
AddUserAction.class,
RemoveGroupAction.class,
RemoveUserAction.class);
RemoveUserAction.class,
UsersAction.class);
}
}
@@ -0,0 +1,126 @@
/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube 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.
*
* SonarQube 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.permission.ws;

import com.google.common.io.Resources;
import java.util.List;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.WebService.Param;
import org.sonar.api.server.ws.WebService.SelectionMode;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.core.permission.UserWithPermission;
import org.sonar.core.util.ProtobufJsonFormat;
import org.sonar.db.permission.PermissionQuery;
import org.sonar.server.permission.PermissionFinder;
import org.sonar.server.permission.UserWithPermissionQueryResult;
import org.sonar.server.plugins.MimeTypes;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.Common;
import org.sonarqube.ws.Permissions;

import static com.google.common.base.Objects.firstNonNull;
import static org.sonar.server.permission.PermissionQueryParser.toMembership;

public class UsersAction implements PermissionsWsAction {

private final UserSession userSession;
private final PermissionFinder permissionFinder;

public UsersAction(UserSession userSession, PermissionFinder permissionFinder) {
this.userSession = userSession;
this.permissionFinder = permissionFinder;
}

@Override
public void define(WebService.NewController context) {
WebService.NewAction action = context.createAction("users")
.setSince("5.2")
.setDescription(String.format("List permission's users.<br /> " +
"If the query parameter '%s' is specified, the '%s' parameter is '%s'.",
Param.TEXT_QUERY, Param.SELECTED, SelectionMode.ALL.value()))
.addPagingParams(100)
.addSearchQuery("stas", "names")
.addSelectionModeParam()
.setInternal(true)
.setResponseExample(Resources.getResource(getClass(), "users-example.json"))
.setHandler(this);

action.createParam("permission")
.setExampleValue("scan")
.setRequired(true)
.setPossibleValues(GlobalPermissions.ALL);
}

@Override
public void handle(Request request, Response response) throws Exception {
String permission = request.mandatoryParam("permission");
String selected = request.param(Param.SELECTED);
int page = request.mandatoryParamAsInt(Param.PAGE);
int pageSize = request.mandatoryParamAsInt(Param.PAGE_SIZE);
String query = request.param(Param.TEXT_QUERY);
if (query != null) {
selected = SelectionMode.ALL.value();
}

userSession
.checkLoggedIn()
.checkGlobalPermission(GlobalPermissions.SYSTEM_ADMIN);

PermissionQuery.Builder permissionQuery = PermissionQuery.builder()
.permission(permission)
.pageIndex(page)
.pageSize(pageSize)
.membership(toMembership(firstNonNull(selected, SelectionMode.SELECTED.value())));
if (query != null) {
permissionQuery.search(query);
}

UserWithPermissionQueryResult usersResult = permissionFinder.findUsersWithPermission(permissionQuery.build());
List<UserWithPermission> usersWithPermission = usersResult.users();

Permissions.UsersResponse.Builder userResponse = Permissions.UsersResponse.newBuilder();
Permissions.UsersResponse.User.Builder user = Permissions.UsersResponse.User.newBuilder();
Common.Paging.Builder paging = Common.Paging.newBuilder();
for (UserWithPermission userWithPermission : usersWithPermission) {
userResponse.addUsers(
user
.clear()
.setLogin(userWithPermission.login())
.setName(userWithPermission.name())
.setSelected(userWithPermission.hasPermission()));
userResponse.setPaging(
paging
.clear()
.setPages(page)
.setPageSize(pageSize)
.setTotal(usersResult.total())
);
}

response.stream().setMediaType(MimeTypes.JSON);
JsonWriter json = response.newJsonWriter();
ProtobufJsonFormat.write(userResponse.build(), json);
json.close();
}
}
@@ -0,0 +1,20 @@
{
"users": [
{
"login": "admin",
"name": "Administrator",
"selected": true
},
{
"login": "george.orwell",
"name": "George Orwell",
"selected": true
}
],
"paging": {
"pageSize": 100,
"total": 2,
"pages": 1
}
}

0 comments on commit b4e4af1

Please sign in to comment.