Skip to content

Commit

Permalink
SONAR-7835 Select user permissions
Browse files Browse the repository at this point in the history
  • Loading branch information
teryk authored and stas-vilchik committed Jul 12, 2016
1 parent fc55854 commit 72c0fa1
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 33 deletions.
Expand Up @@ -33,6 +33,7 @@
import org.sonar.db.user.UserPermissionDto; import org.sonar.db.user.UserPermissionDto;


import static com.google.common.collect.Maps.newHashMap; import static com.google.common.collect.Maps.newHashMap;
import static java.util.Collections.emptyList;
import static org.sonar.db.DatabaseUtils.executeLargeInputsWithoutOutput; import static org.sonar.db.DatabaseUtils.executeLargeInputsWithoutOutput;


public class PermissionDao implements Dao { public class PermissionDao implements Dao {
Expand Down Expand Up @@ -70,6 +71,10 @@ public int countUsersByQuery(DbSession dbSession, PermissionQuery query) {
} }


public List<UserPermissionDto> selectUserPermissionsByQuery(DbSession dbSession, PermissionQuery query) { public List<UserPermissionDto> selectUserPermissionsByQuery(DbSession dbSession, PermissionQuery query) {
if (query.getLogins() != null && query.getLogins().isEmpty()) {
return emptyList();
}

return mapper(dbSession).selectUserPermissionsByQuery(query); return mapper(dbSession).selectUserPermissionsByQuery(query);
} }


Expand Down
Expand Up @@ -36,7 +36,7 @@ public interface PermissionMapper {


int countUsersByQuery(@Param("query") PermissionQuery query); int countUsersByQuery(@Param("query") PermissionQuery query);


List<UserPermissionDto> selectUserPermissionsByQuery(PermissionQuery query); List<UserPermissionDto> selectUserPermissionsByQuery(@Param("query") PermissionQuery query);


List<GroupWithPermissionDto> selectGroups(Map<String, Object> parameters); List<GroupWithPermissionDto> selectGroups(Map<String, Object> parameters);


Expand Down
Expand Up @@ -19,6 +19,7 @@
*/ */
package org.sonar.db.permission; package org.sonar.db.permission;


import java.util.List;
import java.util.Locale; import java.util.Locale;
import javax.annotation.CheckForNull; import javax.annotation.CheckForNull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
Expand All @@ -34,7 +35,6 @@
* Query used to get users and groups permissions * Query used to get users and groups permissions
*/ */
public class PermissionQuery { public class PermissionQuery {

public static final int RESULTS_MAX_SIZE = 100; public static final int RESULTS_MAX_SIZE = 100;
public static final int SEARCH_QUERY_MIN_LENGTH = 3; public static final int SEARCH_QUERY_MIN_LENGTH = 3;
public static final int DEFAULT_PAGE_SIZE = 20; public static final int DEFAULT_PAGE_SIZE = 20;
Expand All @@ -46,6 +46,7 @@ public class PermissionQuery {
private final String searchQuery; private final String searchQuery;
private final String searchQueryToSql; private final String searchQueryToSql;
private final boolean withPermissionOnly; private final boolean withPermissionOnly;
private final List<String> logins;


private final int pageSize; private final int pageSize;
private final int pageOffset; private final int pageOffset;
Expand All @@ -59,6 +60,7 @@ private PermissionQuery(Builder builder) {
this.searchQueryToSql = builder.searchQuery == null ? null : buildLikeValue(builder.searchQuery, WildcardPosition.BEFORE_AND_AFTER).toLowerCase(Locale.ENGLISH); this.searchQueryToSql = builder.searchQuery == null ? null : buildLikeValue(builder.searchQuery, WildcardPosition.BEFORE_AND_AFTER).toLowerCase(Locale.ENGLISH);
this.pageSize = builder.pageSize; this.pageSize = builder.pageSize;
this.pageOffset = offset(builder.pageIndex, builder.pageSize); this.pageOffset = offset(builder.pageIndex, builder.pageSize);
this.logins = builder.logins;
} }


@CheckForNull @CheckForNull
Expand Down Expand Up @@ -97,6 +99,11 @@ public int getPageOffset() {
return pageOffset; return pageOffset;
} }


@CheckForNull
public List<String> getLogins() {
return logins;
}

public static Builder builder() { public static Builder builder() {
return new Builder(); return new Builder();
} }
Expand All @@ -107,6 +114,7 @@ public static class Builder {
private String template; private String template;
private String searchQuery; private String searchQuery;
private boolean withPermissionOnly; private boolean withPermissionOnly;
private List<String> logins;


private Integer pageIndex = DEFAULT_PAGE_INDEX; private Integer pageIndex = DEFAULT_PAGE_INDEX;
private Integer pageSize = DEFAULT_PAGE_SIZE; private Integer pageSize = DEFAULT_PAGE_SIZE;
Expand Down Expand Up @@ -150,11 +158,16 @@ public Builder withPermissionOnly() {
return this; return this;
} }


public Builder setLogins(@Nullable List<String> logins) {
this.logins = logins;
return this;
}

public PermissionQuery build() { public PermissionQuery build() {
this.pageIndex = firstNonNull(pageIndex, DEFAULT_PAGE_INDEX); this.pageIndex = firstNonNull(pageIndex, DEFAULT_PAGE_INDEX);
this.pageSize = firstNonNull(pageSize, DEFAULT_PAGE_SIZE); this.pageSize = firstNonNull(pageSize, DEFAULT_PAGE_SIZE);
checkArgument(searchQuery == null || searchQuery.length() >= 3); checkArgument(searchQuery == null || searchQuery.length() >= 3);
checkArgument(!(withPermissionOnly && permission == null)); checkArgument(logins == null || !logins.isEmpty());
return new PermissionQuery(this); return new PermissionQuery(this);
} }
} }
Expand Down
Expand Up @@ -3,17 +3,20 @@


<mapper namespace="org.sonar.db.permission.PermissionMapper"> <mapper namespace="org.sonar.db.permission.PermissionMapper">


<!-- TODO delete when not used anymore -->
<select id="selectUsers" parameterType="map" resultType="UserWithPermission"> <select id="selectUsers" parameterType="map" resultType="UserWithPermission">
SELECT u.login as login, u.name as name, u.email as email, user_role.role as permission SELECT u.login as login, u.name as name, u.email as email, user_role.role as permission
<include refid="usersSelection"/> <include refid="usersSelection"/>
ORDER BY u.name ORDER BY u.name
</select> </select>


<!-- TODO delete when not used anymore -->
<select id="countUsers" parameterType="map" resultType="int"> <select id="countUsers" parameterType="map" resultType="int">
SELECT count(u.login) SELECT count(u.login)
<include refid="usersSelection"/> <include refid="usersSelection"/>
</select> </select>


<!-- TODO delete when not used anymore -->
<sql id="usersSelection"> <sql id="usersSelection">
FROM users u FROM users u
LEFT JOIN user_roles user_role ON user_role.user_id=u.id LEFT JOIN user_roles user_role ON user_role.user_id=u.id
Expand All @@ -40,30 +43,41 @@
</where> </where>
</sql> </sql>


<sql id="userColumns">
<!-- lower(u.name) and u.id are present to order by with select distinct -->
u.login as login, u.name as name, u.email as email, lower(u.name), u.id
</sql>

<select id="selectUsersByQuery" parameterType="map" resultType="org.sonar.db.permission.UserRef"> <select id="selectUsersByQuery" parameterType="map" resultType="org.sonar.db.permission.UserRef">
select distinct <include refid="userColumns" /> select distinct <include refid="userColumns" />
<include refid="usersByQuery"/> <include refid="usersByQuery"/>
order by lower(u.name), u.name, u.id order by lower(u.name), u.name, u.id
</select> </select>


<sql id="userColumns">
<!-- lower(u.name) and u.id are present to order by with select distinct -->
u.login as login, u.name as name, u.email as email, lower(u.name), u.id
</sql>

<select id="countUsersByQuery" parameterType="map" resultType="int"> <select id="countUsersByQuery" parameterType="map" resultType="int">
select count(1) select count(1)
from ( from (
select distinct <include refid="userColumns" /> select distinct <include refid="userColumns" />
<include refid="usersByQuery"/>) <include refid="usersByQuery"/>)
</select> </select>


<select id="selectUserPermissionsByQuery" parameterType="map" resultType="UserRole">
select ur.user_id as userId, ur.resource_id as componentId, ur.role as permission
<include refid="usersByQuery" />
</select>

<sql id="usersByQuery"> <sql id="usersByQuery">
from users u from users u
left join user_roles ur ON ur.user_id=u.id left join user_roles ur ON ur.user_id=u.id
left join projects p on ur.resource_id = p.id left join projects p on ur.resource_id = p.id
<where> <where>
and u.active = ${_true} and u.active = ${_true}
<if test="query.logins != null">
and u.login in
<foreach collection="query.logins" open="(" close=")" item="login" separator=",">
#{login}
</foreach>
</if>
<if test="query.searchQueryToSql != null"> <if test="query.searchQueryToSql != null">
and lower(u.name) like #{query.searchQueryToSql} ESCAPE '/' and lower(u.name) like #{query.searchQueryToSql} ESCAPE '/'
</if> </if>
Expand All @@ -83,25 +97,6 @@
</where> </where>
</sql> </sql>


<select id="selectUserPermissionsByQuery" parameterType="map" resultType="UserRole">
select ur.user_id as userId, ur.resource_id as componentId, ur.role as permission
from user_roles ur
inner join users u on ur.user_id = u.id
left outer join projects p on ur.resource_id=p.id
<where>
<if test="query.logins != null">
and u.login in
<foreach collection="query.logins" open="(" close=")" item="login" separator=",">
#{login}
</foreach>
</if>
<if test="query.searchQueryToSql != null">
and (lower(u.name) like #{query.searchQueryToSql} ESCAPE '/')
</if>
</where>

</select>

<select id="usersCountByProjectIdAndPermission" parameterType="map" <select id="usersCountByProjectIdAndPermission" parameterType="map"
resultType="org.sonar.db.permission.CountByProjectAndPermissionDto"> resultType="org.sonar.db.permission.CountByProjectAndPermissionDto">
SELECT user_role.resource_id as componentId, user_role.role as permission, count(u.login) as count SELECT user_role.resource_id as componentId, user_role.role as permission, count(u.login) as count
Expand Down
Expand Up @@ -38,7 +38,9 @@
import org.sonar.db.user.UserDto; import org.sonar.db.user.UserDto;
import org.sonar.db.user.UserRoleDto; import org.sonar.db.user.UserRoleDto;


import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.sonar.api.web.UserRole.ADMIN; import static org.sonar.api.web.UserRole.ADMIN;
import static org.sonar.api.web.UserRole.ISSUE_ADMIN; import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
import static org.sonar.api.web.UserRole.USER; import static org.sonar.api.web.UserRole.USER;
Expand Down Expand Up @@ -159,16 +161,25 @@ public void select_users() {
permissionDb.addProjectPermissionToUser(UserRole.USER, user4.getId(), project.getId()); permissionDb.addProjectPermissionToUser(UserRole.USER, user4.getId(), project.getId());


PermissionQuery.Builder dbQuery = PermissionQuery.builder(); PermissionQuery.Builder dbQuery = PermissionQuery.builder();
List<UserRef> result = selectUsersByQuery(dbQuery); List<UserRef> users = selectUsersByQuery(dbQuery);
int count = countUsersByQuery(dbQuery); int count = countUsersByQuery(dbQuery);
List<UserPermissionDto> permissions = selectUserPermissionsByQuery(dbQuery);


assertThat(result) assertThat(users)
.hasSize(4) .hasSize(4)
.extracting(UserRef::getName) .extracting(UserRef::getName)
.containsExactly("1-name", "2-name", "3-name", "4-name"); .containsExactly("1-name", "2-name", "3-name", "4-name");
assertThat(result.get(0)).extracting(UserRef::getEmail, UserRef::getLogin) assertThat(users.get(0)).extracting(UserRef::getEmail, UserRef::getLogin)
.containsExactly(user1.getEmail(), user1.getLogin()); .containsExactly(user1.getEmail(), user1.getLogin());
assertThat(count).isEqualTo(4); assertThat(count).isEqualTo(4);

assertThat(permissions).hasSize(5).extracting(UserPermissionDto::getUserId, UserPermissionDto::getPermission)
.containsOnlyOnce(
tuple(user1.getId(), GlobalPermissions.SYSTEM_ADMIN),
tuple(user2.getId(), GlobalPermissions.SYSTEM_ADMIN),
tuple(user3.getId(), GlobalPermissions.SYSTEM_ADMIN),
tuple(user3.getId(), GlobalPermissions.PROVISIONING),
tuple(user4.getId(), UserRole.USER));
} }


@Test @Test
Expand All @@ -191,14 +202,35 @@ public void select_users_with_query() {
userDb.insertUser(newUserDto().setName("unknown")); userDb.insertUser(newUserDto().setName("unknown"));


PermissionQuery.Builder dbQuery = PermissionQuery.builder().setSearchQuery("nam"); PermissionQuery.Builder dbQuery = PermissionQuery.builder().setSearchQuery("nam");
List<UserRef> result = selectUsersByQuery(dbQuery); List<UserRef> users = selectUsersByQuery(dbQuery);
int count = countUsersByQuery(dbQuery); int count = countUsersByQuery(dbQuery);


assertThat(result).hasSize(1); assertThat(users).hasSize(1);
assertThat(result.get(0).getName()).isEqualTo("1-name"); assertThat(users.get(0).getName()).isEqualTo("1-name");
assertThat(count).isEqualTo(1); assertThat(count).isEqualTo(1);
} }


@Test
public void select_user_permissions() {
UserDto user = userDb.insertUser(newUserDto().setLogin("user-login"));
UserDto anotherUser = userDb.insertUser(newUserDto().setLogin("another-login"));
ComponentDto project = componentDb.insertComponent(newProjectDto());
permissionDb.addProjectPermissionToUser(UserRole.ADMIN, user.getId(), project.getId());
permissionDb.addProjectPermissionToUser(UserRole.ADMIN, anotherUser.getId(), project.getId());

PermissionQuery.Builder dbQuery = PermissionQuery.builder()
.setComponentUuid(project.uuid())
.setLogins(singletonList("user-login"))
.withPermissionOnly();
List<UserPermissionDto> result = selectUserPermissionsByQuery(dbQuery);

assertThat(result).hasSize(1);
UserPermissionDto userPermission = result.get(0);
assertThat(userPermission.getComponentId()).isEqualTo(project.getId());
assertThat(userPermission.getPermission()).isEqualTo(UserRole.ADMIN);
assertThat(userPermission.getUserId()).isEqualTo(user.getId());
}

@Test @Test
public void select_users_with_global_permissions() { public void select_users_with_global_permissions() {
UserDto user3 = userDb.insertUser(newUserDto().setName("3-name")); UserDto user3 = userDb.insertUser(newUserDto().setName("3-name"));
Expand Down Expand Up @@ -322,6 +354,10 @@ private int countUsersByQuery(PermissionQuery.Builder query) {
return underTest.countUsersByQuery(session, query.build()); return underTest.countUsersByQuery(session, query.build());
} }


private List<UserPermissionDto> selectUserPermissionsByQuery(PermissionQuery.Builder query) {
return underTest.selectUserPermissionsByQuery(session, query.build());
}

private void addPermissionToUser(String permission, long userId, long resourceId) { private void addPermissionToUser(String permission, long userId, long resourceId) {
dbTester.getDbClient().roleDao().insertUserRole(dbTester.getSession(), new UserRoleDto() dbTester.getDbClient().roleDao().insertUserRole(dbTester.getSession(), new UserRoleDto()
.setRole(permission) .setRole(permission)
Expand Down

0 comments on commit 72c0fa1

Please sign in to comment.