SearchAction.class,
CreateAction.class,
DeleteAction.class,
- UpdateAction.class);
+ UpdateAction.class,
+ UsersAction.class);
}
}
--- /dev/null
+/*
+ * 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.usergroups.ws;
+
+import java.util.List;
+import javax.annotation.Nullable;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService.NewAction;
+import org.sonar.api.server.ws.WebService.NewController;
+import org.sonar.api.server.ws.WebService.Param;
+import org.sonar.api.utils.Paging;
+import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.user.GroupDto;
+import org.sonar.core.user.GroupMembershipQuery;
+import org.sonar.core.user.UserMembershipDto;
+import org.sonar.core.user.UserMembershipQuery;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.exceptions.NotFoundException;
+
+public class UsersAction implements UserGroupsWsAction {
+
+ private static final String PARAM_ID = "id";
+ private static final String PARAM_SELECTED = "selected";
+
+ private static final String SELECTION_ALL = "all";
+ private static final String SELECTION_SELECTED = "selected";
+ private static final String SELECTION_DESELECTED = "deselected";
+
+ private final DbClient dbClient;
+
+ public UsersAction(DbClient dbClient) {
+ this.dbClient = dbClient;
+ }
+
+ @Override
+ public void define(NewController context) {
+ NewAction action = context.createAction("users")
+ .setDescription("List the members of a group.")
+ .setHandler(this)
+ .setResponseExample(getClass().getResource("example-users.json"))
+ .setSince("5.2");
+
+ action.createParam(PARAM_ID)
+ .setDescription("A group ID")
+ .setExampleValue("42")
+ .setRequired(true);
+
+ action.createParam(PARAM_SELECTED)
+ .setDescription("If specified, only show users who belong to this group (selected) or not (deselected).")
+ .setPossibleValues(SELECTION_SELECTED, SELECTION_DESELECTED, SELECTION_ALL)
+ .setDefaultValue(SELECTION_ALL);
+
+ action.createParam(Param.TEXT_QUERY)
+ .setDescription("If specified, only show users whose name or login contains the query.")
+ .setExampleValue("freddy");
+
+ action.addPagingParams(25);
+ }
+
+ @Override
+ public void handle(Request request, Response response) throws Exception {
+ Long groupId = request.mandatoryParamAsLong(PARAM_ID);
+ int pageSize = request.mandatoryParamAsInt(Param.PAGE_SIZE);
+ int page = request.mandatoryParamAsInt(Param.PAGE);
+ String queryString = request.param(Param.TEXT_QUERY);
+ String selected = request.param(PARAM_SELECTED);
+
+ UserMembershipQuery query = UserMembershipQuery.builder()
+ .groupId(groupId)
+ .memberSearch(queryString)
+ .membership(getMembership(selected))
+ .pageIndex(page)
+ .pageSize(pageSize)
+ .build();
+
+ DbSession session = dbClient.openSession(false);
+ try {
+ GroupDto group = dbClient.groupDao().selectById(session, groupId);
+ if (group == null) {
+ throw new NotFoundException(String.format("Unable to find a group with ID '%d'", groupId));
+ }
+ int total = dbClient.groupMembershipDao().countMembers(session, query);
+ Paging paging = Paging.create(pageSize, page, total);
+ List<UserMembershipDto> users = dbClient.groupMembershipDao().selectMembers(session, query, paging.offset(), pageSize);
+
+ JsonWriter json = response.newJsonWriter().beginObject();
+ writeMembers(json, users);
+ writePaging(json, paging);
+ json.endObject().close();
+ } finally {
+ session.close();
+ }
+ }
+
+ private void writeMembers(JsonWriter json, List<UserMembershipDto> users) {
+ json.name("users").beginArray();
+ for (UserMembershipDto user : users) {
+ json.beginObject()
+ .prop("login", user.getLogin())
+ .prop("name", user.getName())
+ .prop("selected", user.getGroupId() != null)
+ .endObject();
+ }
+ json.endArray();
+ }
+
+ private void writePaging(JsonWriter json, Paging paging) {
+ json.prop("p", paging.pageIndex())
+ .prop("ps", paging.pageSize())
+ .prop("total", paging.total());
+ }
+
+ private String getMembership(@Nullable String selected) {
+ String membership = GroupMembershipQuery.ANY;
+ if (SELECTION_SELECTED.equals(selected)) {
+ membership = GroupMembershipQuery.IN;
+ } else if (SELECTION_DESELECTED.equals(selected)) {
+ membership = GroupMembershipQuery.OUT;
+ }
+ return membership;
+ }
+}
--- /dev/null
+/*
+ * 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.usergroups.ws;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.utils.System2;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.core.user.GroupDto;
+import org.sonar.core.user.GroupMembershipDao;
+import org.sonar.core.user.UserDto;
+import org.sonar.core.user.UserGroupDto;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.user.db.GroupDao;
+import org.sonar.server.user.db.UserDao;
+import org.sonar.server.user.db.UserGroupDao;
+import org.sonar.server.ws.WsTester;
+
+public class UsersActionTest {
+
+ @ClassRule
+ public static final DbTester dbTester = new DbTester();
+
+ WebService.Controller controller;
+
+ WsTester tester;
+
+ DbClient dbClient;
+
+ DbSession session;
+
+ @Before
+ public void setUp() {
+ dbTester.truncateTables();
+
+ System2 system2 = new System2();
+ UserDao userDao = new UserDao(dbTester.myBatis(), system2);
+ GroupDao groupDao = new GroupDao(system2);
+ UserGroupDao userGroupDao = new UserGroupDao();
+ GroupMembershipDao groupMembershipDao = new GroupMembershipDao(dbTester.myBatis());
+
+ dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), userDao, groupDao, userGroupDao, groupMembershipDao);
+ session = dbClient.openSession(false);
+ session.commit();
+
+ tester = new WsTester(new UserGroupsWs(new UsersAction(dbClient)));
+ controller = tester.controller("api/users");
+
+ }
+
+ @After
+ public void tearDown() {
+ session.close();
+ }
+
+ @Test(expected = NotFoundException.class)
+ public void fail_on_unknown_user() throws Exception {
+ tester.newGetRequest("api/usergroups", "users")
+ .setParam("id", "42")
+ .setParam("login", "john").execute();
+ }
+
+ @Test
+ public void empty_users() throws Exception {
+ GroupDto group = createGroup();
+ session.commit();
+
+ tester.newGetRequest("api/usergroups", "users")
+ .setParam("login", "john")
+ .setParam("id", group.getId().toString())
+ .execute()
+ .assertJson(getClass(), "empty.json");
+ }
+
+ @Test
+ public void all_users() throws Exception {
+ GroupDto group = createGroup();
+ UserDto groupUser = createUser("ada", "Ada Lovelace");
+ createUser("grace", "Grace Hopper");
+ addUserToGroup(groupUser, group);
+ session.commit();
+
+ tester.newGetRequest("api/usergroups", "users")
+ .setParam("id", group.getId().toString())
+ .execute()
+ .assertJson(getClass(), "all.json");
+ }
+
+ @Test
+ public void selected_users() throws Exception {
+ GroupDto group = createGroup();
+ UserDto groupUser = createUser("ada", "Ada Lovelace");
+ createUser("grace", "Grace Hopper");
+ addUserToGroup(groupUser, group);
+ session.commit();
+
+ tester.newGetRequest("api/usergroups", "users")
+ .setParam("id", group.getId().toString())
+ .setParam("selected", "selected")
+ .execute()
+ .assertJson(getClass(), "selected.json");
+ }
+
+ @Test
+ public void deselected_users() throws Exception {
+ GroupDto group = createGroup();
+ UserDto groupUser = createUser("ada", "Ada Lovelace");
+ createUser("grace", "Grace Hopper");
+ addUserToGroup(groupUser, group);
+ session.commit();
+
+ tester.newGetRequest("api/usergroups", "users")
+ .setParam("id", group.getId().toString())
+ .setParam("selected", "deselected")
+ .execute()
+ .assertJson(getClass(), "deselected.json");
+ }
+
+ @Test
+ public void paging() throws Exception {
+ GroupDto group = createGroup();
+ UserDto groupUser = createUser("ada", "Ada Lovelace");
+ createUser("grace", "Grace Hopper");
+ addUserToGroup(groupUser, group);
+ session.commit();
+
+ tester.newGetRequest("api/usergroups", "users")
+ .setParam("id", group.getId().toString())
+ .setParam("ps", "1")
+ .execute()
+ .assertJson(getClass(), "all_page1.json");
+
+ tester.newGetRequest("api/usergroups", "users")
+ .setParam("id", group.getId().toString())
+ .setParam("ps", "1")
+ .setParam("p", "2")
+ .execute()
+ .assertJson(getClass(), "all_page2.json");
+ }
+
+ @Test
+ public void filtering() throws Exception {
+ GroupDto group = createGroup();
+ UserDto groupUser = createUser("ada", "Ada Lovelace");
+ createUser("grace", "Grace Hopper");
+ addUserToGroup(groupUser, group);
+ session.commit();
+
+ tester.newGetRequest("api/usergroups", "users")
+ .setParam("id", group.getId().toString())
+ .setParam("q", "ace")
+ .execute()
+ .assertJson(getClass(), "all.json");
+
+ tester.newGetRequest("api/usergroups", "users")
+ .setParam("id", group.getId().toString())
+ .setParam("q", "love")
+ .execute()
+ .assertJson(getClass(), "all_ada.json");
+ }
+
+ private GroupDto createGroup() {
+ return dbClient.groupDao().insert(session, new GroupDto()
+ .setName("sonar-users"));
+ }
+
+ private UserDto createUser(String login, String name) {
+ return dbClient.userDao().insert(session, new UserDto().setLogin(login).setName(name));
+ }
+
+ private void addUserToGroup(UserDto user, GroupDto usersGroup) {
+ dbClient.userGroupDao().insert(session, new UserGroupDto().setUserId(user.getId()).setGroupId(usersGroup.getId()));
+ }
+}
--- /dev/null
+{
+ "p": 1,
+ "total": 2,
+ "users": [
+ {"login": "ada", "name": "Ada Lovelace", "selected": true},
+ {"login": "grace", "name": "Grace Hopper", "selected": false}
+ ]
+}
\ No newline at end of file
--- /dev/null
+{
+ "p": 1,
+ "total": 1,
+ "users": [
+ {"login": "ada", "name": "Ada Lovelace", "selected": true}
+ ]
+}
\ No newline at end of file
--- /dev/null
+{
+ "p": 1,
+ "ps": 1,
+ "total": 2,
+ "users": [
+ {"login": "ada", "name": "Ada Lovelace", "selected": true}
+ ]
+}
\ No newline at end of file
--- /dev/null
+{
+ "p": 2,
+ "ps": 1,
+ "total": 2,
+ "users": [
+ {"login": "grace", "name": "Grace Hopper", "selected": false}
+ ]
+}
\ No newline at end of file
--- /dev/null
+{
+ "p": 1,
+ "total": 1,
+ "users": [
+ {"login": "ada", "name": "Ada Lovelace", "selected": true}
+ ]
+}
\ No newline at end of file
--- /dev/null
+{
+ "p": 1,
+ "total": 1,
+ "users": [
+ {"login": "grace", "name": "Grace Hopper", "selected": false}
+ ]
+}
\ No newline at end of file
--- /dev/null
+{
+ "p": 1,
+ "total": 0,
+ "users": []
+}
\ No newline at end of file
--- /dev/null
+{
+ "p": 1,
+ "total": 1,
+ "users": [
+ {"login": "ada", "name": "Ada Lovelace", "selected": true}
+ ]
+}
\ No newline at end of file
return mapper(session).countGroups(params);
}
+ public List<UserMembershipDto> selectMembers(SqlSession session, UserMembershipQuery query, int offset, int limit) {
+ Map<String, Object> params = ImmutableMap.of("query", query, "groupId", query.groupId());
+ return mapper(session).selectMembers(params, new RowBounds(offset, limit));
+ }
+
+ public int countMembers(SqlSession session, UserMembershipQuery query) {
+ Map<String, Object> params = ImmutableMap.of("query", query, "groupId", query.groupId());
+ return mapper(session).countMembers(params);
+ }
+
public Map<String, Integer> countUsersByGroups(final DbSession session, Collection<Long> groupIds) {
final Map<String, Integer> result = Maps.newHashMap();
DaoUtils.executeLargeInputs(groupIds, new Function<List<Long>, List<GroupUserCount>>() {
int countGroups(Map<String, Object> params);
+ List<UserMembershipDto> selectMembers(Map<String, Object> params, RowBounds rowBounds);
+
+ int countMembers(Map<String, Object> params);
+
List<GroupUserCount> countUsersByGroup(@Param("groupIds") List<Long> groupIds);
List<LoginGroup> selectGroupsByLogins(@Param("logins") List<String> logins);
--- /dev/null
+/*
+ * 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.core.user;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+/**
+ * @since 5.2
+ */
+public class UserMembershipDto {
+
+ private Long id;
+ private Long groupId;
+ private String login;
+ private String name;
+
+ public Long getId() {
+ return id;
+ }
+
+ public UserMembershipDto setId(Long id) {
+ this.id = id;
+ return this;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public UserMembershipDto setName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ @CheckForNull
+ public String getLogin() {
+ return login;
+ }
+
+ public UserMembershipDto setLogin(@Nullable String login) {
+ this.login = login;
+ return this;
+ }
+
+ @CheckForNull
+ public Long getGroupId() {
+ return groupId;
+ }
+
+ public UserMembershipDto setGroupId(@Nullable Long groupId) {
+ this.groupId = groupId;
+ return this;
+ }
+}
--- /dev/null
+/*
+ * 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.core.user;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.StringUtils;
+
+public class UserMembershipQuery {
+
+ public static final int DEFAULT_PAGE_INDEX = 1;
+ public static final int DEFAULT_PAGE_SIZE = 100;
+
+ public static final String ANY = "ANY";
+ public static final String IN = "IN";
+ public static final String OUT = "OUT";
+ public static final Set<String> AVAILABLE_MEMBERSHIP = ImmutableSet.of(ANY, IN, OUT);
+
+ private final Long groupId;
+ private final String membership;
+
+ private final String memberSearch;
+
+ // for internal use in MyBatis
+ final String memberSearchSql;
+
+ // max results per page
+ private final int pageSize;
+
+ // index of selected page. Start with 1.
+ private final int pageIndex;
+
+
+ private UserMembershipQuery(Builder builder) {
+ this.groupId = builder.groupId;
+ this.membership = builder.membership;
+ this.memberSearch = builder.memberSearch;
+ this.memberSearchSql = memberSearchToSql(memberSearch);
+
+ this.pageSize = builder.pageSize;
+ this.pageIndex = builder.pageIndex;
+ }
+
+ private String memberSearchToSql(@Nullable String s) {
+ String sql = null;
+ if (s != null) {
+ sql = StringUtils.replace(StringUtils.upperCase(s), "%", "/%");
+ sql = StringUtils.replace(sql, "_", "/_");
+ sql = "%" + sql + "%";
+ }
+ return sql;
+ }
+
+ public Long groupId() {
+ return groupId;
+ }
+
+ @CheckForNull
+ public String membership() {
+ return membership;
+ }
+
+ /**
+ * Search for users names/logins containing a given string
+ */
+ @CheckForNull
+ public String memberSearch() {
+ return memberSearch;
+ }
+
+ public int pageSize() {
+ return pageSize;
+ }
+
+ public int pageIndex() {
+ return pageIndex;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private Long groupId;
+ private String membership;
+ private String memberSearch;
+
+ private Integer pageIndex = DEFAULT_PAGE_INDEX;
+ private Integer pageSize = DEFAULT_PAGE_SIZE;
+
+ private Builder() {
+ }
+
+ public Builder groupId(Long groupId) {
+ this.groupId = groupId;
+ return this;
+ }
+
+ public Builder membership(@Nullable String membership) {
+ this.membership = membership;
+ return this;
+ }
+
+ public Builder memberSearch(@Nullable String s) {
+ this.memberSearch = StringUtils.defaultIfBlank(s, null);
+ return this;
+ }
+
+ public Builder pageSize(@Nullable Integer i) {
+ this.pageSize = i;
+ return this;
+ }
+
+ public Builder pageIndex(@Nullable Integer i) {
+ this.pageIndex = i;
+ return this;
+ }
+
+ private void initMembership() {
+ if (membership == null) {
+ membership = UserMembershipQuery.ANY;
+ } else {
+ Preconditions.checkArgument(AVAILABLE_MEMBERSHIP.contains(membership),
+ "Membership is not valid (got " + membership + "). Availables values are " + AVAILABLE_MEMBERSHIP);
+ }
+ }
+
+ private void initPageSize() {
+ if (pageSize == null) {
+ pageSize = DEFAULT_PAGE_SIZE;
+ }
+ }
+
+ private void initPageIndex() {
+ if (pageIndex == null) {
+ pageIndex = DEFAULT_PAGE_INDEX;
+ }
+ Preconditions.checkArgument(pageIndex > 0, "Page index must be greater than 0 (got " + pageIndex + ")");
+ }
+
+ public UserMembershipQuery build() {
+ Preconditions.checkNotNull(groupId, "Group ID cant be null.");
+ initMembership();
+ initPageIndex();
+ initPageSize();
+ return new UserMembershipQuery(this);
+ }
+ }
+}
</where>
</select>
+ <sql id="userCommonClauses">
+ FROM users u
+ LEFT JOIN groups_users gu ON gu.user_id=u.id AND gu.group_id=#{groupId}
+ <where>
+ <choose>
+ <when test="query.membership() == 'IN'">
+ AND gu.group_id IS NOT NULL
+ </when>
+ <when test="query.membership() == 'OUT'">
+ AND gu.group_id IS NULL
+ </when>
+ </choose>
+ <if test="query.memberSearch() != null">
+ AND ((UPPER(u.login) LIKE #{query.memberSearchSql} ESCAPE '/') OR (UPPER(u.name) LIKE #{query.memberSearchSql} ESCAPE '/'))
+ </if>
+ AND u.active=${_true}
+ </where>
+ </sql>
+
+ <select id="selectMembers" parameterType="map" resultType="org.sonar.core.user.UserMembershipDto">
+ SELECT u.id as id, u.login as login, u.name as name, gu.group_id as groupId
+ <include refid="userCommonClauses" />
+ ORDER BY u.name ASC
+ </select>
+
+ <select id="countMembers" parameterType="map" resultType="int">
+ SELECT COUNT(u.id)
+ <include refid="userCommonClauses" />
+ </select>
+
</mapper>
session.close();
}
}
+
+ @Test
+ public void count_members() {
+ dbTester.prepareDbUnit(getClass(), "shared_plus_empty_group.xml");
+ DbSession session = dbTester.myBatis().openSession(false);
+
+ try {
+ // 100 has 1 member and 1 non member
+ assertThat(dao.countMembers(session, UserMembershipQuery.builder().groupId(100L).membership(UserMembershipQuery.IN).build())).isEqualTo(1);
+ assertThat(dao.countMembers(session, UserMembershipQuery.builder().groupId(100L).membership(UserMembershipQuery.OUT).build())).isEqualTo(1);
+ // 101 has 2 members
+ assertThat(dao.countMembers(session, UserMembershipQuery.builder().groupId(101L).membership(UserMembershipQuery.IN).build())).isEqualTo(2);
+ assertThat(dao.countMembers(session, UserMembershipQuery.builder().groupId(101L).membership(UserMembershipQuery.OUT).build())).isZero();
+ // 102 has 1 member and 1 non member
+ assertThat(dao.countMembers(session, UserMembershipQuery.builder().groupId(102L).membership(UserMembershipQuery.IN).build())).isEqualTo(1);
+ assertThat(dao.countMembers(session, UserMembershipQuery.builder().groupId(102L).membership(UserMembershipQuery.OUT).build())).isEqualTo(1);
+ // 103 has no member
+ assertThat(dao.countMembers(session, UserMembershipQuery.builder().groupId(103L).membership(UserMembershipQuery.IN).build())).isZero();
+ assertThat(dao.countMembers(session, UserMembershipQuery.builder().groupId(103L).membership(UserMembershipQuery.OUT).build())).isEqualTo(2);
+ } finally {
+ session.close();
+ }
+ }
+
+ @Test
+ public void select_group_members_by_query() {
+ dbTester.prepareDbUnit(getClass(), "shared_plus_empty_group.xml");
+
+ DbSession session = dbTester.myBatis().openSession(false);
+
+ try {
+ // 100 has 1 member
+ assertThat(dao.selectMembers(session, UserMembershipQuery.builder().groupId(100L).membership(UserMembershipQuery.IN).build(), 0, 10)).hasSize(1);
+ // 101 has 2 members
+ assertThat(dao.selectMembers(session, UserMembershipQuery.builder().groupId(101L).membership(UserMembershipQuery.IN).build(), 0, 10)).hasSize(2);
+ // 102 has 1 member
+ assertThat(dao.selectMembers(session, UserMembershipQuery.builder().groupId(102L).membership(UserMembershipQuery.IN).build(), 0, 10)).hasSize(1);
+ // 103 has no member
+ assertThat(dao.selectMembers(session, UserMembershipQuery.builder().groupId(103L).membership(UserMembershipQuery.IN).build(), 0, 10)).isEmpty();
+ } finally {
+ session.close();
+ }
+ }
+
+ @Test
+ public void select_users_not_affected_to_a_group_by_query() {
+ dbTester.prepareDbUnit(getClass(), "shared_plus_empty_group.xml");
+
+ DbSession session = dbTester.myBatis().openSession(false);
+
+ try {
+ // 100 has 1 member
+ assertThat(dao.selectMembers(session, UserMembershipQuery.builder().groupId(100L).membership(UserMembershipQuery.OUT).build(), 0, 10)).hasSize(1);
+ // 101 has 2 members
+ assertThat(dao.selectMembers(session, UserMembershipQuery.builder().groupId(101L).membership(UserMembershipQuery.OUT).build(), 0, 10)).isEmpty();
+ // 102 has 1 member
+ assertThat(dao.selectMembers(session, UserMembershipQuery.builder().groupId(102L).membership(UserMembershipQuery.OUT).build(), 0, 10)).hasSize(1);
+ // 103 has no member
+ assertThat(dao.selectMembers(session, UserMembershipQuery.builder().groupId(103L).membership(UserMembershipQuery.OUT).build(), 0, 10)).hasSize(2);
+ } finally {
+ session.close();
+ }
+ }
+
+ @Test
+ public void search_by_user_name_or_login() {
+ dbTester.prepareDbUnit(getClass(), "shared_plus_empty_group.xml");
+
+ DbSession session = dbTester.myBatis().openSession(false);
+
+ try {
+
+ List<UserMembershipDto> result = dao.selectMembers(session, UserMembershipQuery.builder().groupId(100L).memberSearch("admin").build(), 0, 10);
+ assertThat(result).hasSize(2);
+
+ assertThat(result.get(0).getName()).isEqualTo("Admin");
+ assertThat(result.get(1).getName()).isEqualTo("Not Admin");
+
+ result = dao.selectMembers(session, UserMembershipQuery.builder().groupId(100L).memberSearch("not").build(), 0, 10);
+ assertThat(result).hasSize(1);
+
+ } finally {
+ session.close();
+ }
+ }
+
+ @Test
+ public void search_by_login_or_name_with_capitalization() {
+ dbTester.prepareDbUnit(getClass(), "shared_plus_empty_group.xml");
+
+ DbSession session = dbTester.myBatis().openSession(false);
+
+ try {
+ List<UserMembershipDto> result = dao.selectMembers(session, UserMembershipQuery.builder().groupId(100L).memberSearch("admin").build(), 0, 10);
+ assertThat(result).hasSize(2);
+
+ result = dao.selectMembers(session, UserMembershipQuery.builder().groupId(100L).memberSearch("AdMiN").build(), 0, 10);
+ assertThat(result).hasSize(2);
+ } finally {
+ session.close();
+ }
+
+ }
+
+ @Test
+ public void should_be_sorted_by_user_name() {
+ dbTester.prepareDbUnit(getClass(), "shared_plus_empty_group.xml");
+
+ DbSession session = dbTester.myBatis().openSession(false);
+
+ try {
+ List<UserMembershipDto> result = dao.selectMembers(session, UserMembershipQuery.builder().groupId(100L).build(), 0, 10);
+ assertThat(result).hasSize(2);
+ assertThat(result.get(0).getName()).isEqualTo("Admin");
+ assertThat(result.get(1).getName()).isEqualTo("Not Admin");
+ } finally {
+ session.close();
+ }
+ }
+
+ @Test
+ public void members_should_be_paginated() {
+ dbTester.prepareDbUnit(getClass(), "shared_plus_empty_group.xml");
+
+ DbSession session = dbTester.myBatis().openSession(false);
+
+ try {
+ List<UserMembershipDto> result = dao.selectMembers(session, UserMembershipQuery.builder().groupId(100L).build(), 0, 2);
+ assertThat(result).hasSize(2);
+ assertThat(result.get(0).getName()).isEqualTo("Admin");
+ assertThat(result.get(1).getName()).isEqualTo("Not Admin");
+
+ result = dao.selectMembers(session, UserMembershipQuery.builder().groupId(100L).build(), 1, 2);
+ assertThat(result).hasSize(1);
+ assertThat(result.get(0).getName()).isEqualTo("Not Admin");
+
+ result = dao.selectMembers(session, UserMembershipQuery.builder().groupId(100L).build(), 2, 1);
+ assertThat(result).isEmpty();
+ } finally {
+ session.close();
+ }
+ }
}
<!-- user 201 is in users group -->
<groups_users user_id="201" group_id="101"/>
+ <users id="200" login="admin" name="Admin" active="[true]"/>
+ <users id="201" login="not.admin" name="Not Admin" active="[true]"/>
+ <users id="202" login="inactive" name="Inactive" active="[false]"/>
+
</dataset>