KEYCLOAK-8150 Improve loading user list
This commit is contained in:
parent
df76afb513
commit
bee3894cdf
6 changed files with 90 additions and 10 deletions
|
@ -42,6 +42,16 @@ public interface UsersResource {
|
|||
@QueryParam("first") Integer firstResult,
|
||||
@QueryParam("max") Integer maxResults);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
List<UserRepresentation> search(@QueryParam("username") String username,
|
||||
@QueryParam("firstName") String firstName,
|
||||
@QueryParam("lastName") String lastName,
|
||||
@QueryParam("email") String email,
|
||||
@QueryParam("first") Integer firstResult,
|
||||
@QueryParam("max") Integer maxResults,
|
||||
@QueryParam("briefRepresentation") Boolean briefRepresentation);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
List<UserRepresentation> search(@QueryParam("username") String username);
|
||||
|
@ -65,6 +75,29 @@ public interface UsersResource {
|
|||
@QueryParam("first") Integer firstResult,
|
||||
@QueryParam("max") Integer maxResults);
|
||||
|
||||
/**
|
||||
* Search for users whose username or email matches the value provided by {@code search}. The {@code search}
|
||||
* argument also allows finding users by specific attributes as follows:
|
||||
*
|
||||
* <ul>
|
||||
* <li><i>id:</i> - Find users by identifier. For instance, <i>id:aa497859-bbf5-44ac-bf1a-74dbffcaf197</i></li>
|
||||
* </ul>
|
||||
*
|
||||
* @param search the value to search. It can be the username, email or any of the supported options to query based on user attributes
|
||||
* @param firstResult the position of the first result to retrieve
|
||||
* @param maxResults the maximum number of results to retreive
|
||||
* @param briefRepresentation Only return basic information (only guaranteed to return id, username, created, first and last name,
|
||||
* email, enabled state, email verification state, federation link, and access.
|
||||
* Note that it means that namely user attributes, required actions, and not before are not returned.)
|
||||
* @return a list of {@link UserRepresentation}
|
||||
*/
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
List<UserRepresentation> search(@QueryParam("search") String search,
|
||||
@QueryParam("first") Integer firstResult,
|
||||
@QueryParam("max") Integer maxResults,
|
||||
@QueryParam("briefRepresentation") Boolean briefRepresentation);
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
List<UserRepresentation> list(@QueryParam("first") Integer firstResult,
|
||||
|
|
|
@ -166,6 +166,21 @@ public class ModelToRepresentation {
|
|||
return rep;
|
||||
}
|
||||
|
||||
public static UserRepresentation toBriefRepresentation(UserModel user) {
|
||||
UserRepresentation rep = new UserRepresentation();
|
||||
rep.setId(user.getId());
|
||||
rep.setUsername(user.getUsername());
|
||||
rep.setCreatedTimestamp(user.getCreatedTimestamp());
|
||||
rep.setLastName(user.getLastName());
|
||||
rep.setFirstName(user.getFirstName());
|
||||
rep.setEmail(user.getEmail());
|
||||
rep.setEnabled(user.isEnabled());
|
||||
rep.setEmailVerified(user.isEmailVerified());
|
||||
rep.setFederationLink(user.getFederationLink());
|
||||
|
||||
return rep;
|
||||
}
|
||||
|
||||
public static EventRepresentation toRepresentation(Event event) {
|
||||
EventRepresentation rep = new EventRepresentation();
|
||||
rep.setTime(event.getTime());
|
||||
|
|
|
@ -179,7 +179,8 @@ public class UsersResource {
|
|||
@QueryParam("email") String email,
|
||||
@QueryParam("username") String username,
|
||||
@QueryParam("first") Integer firstResult,
|
||||
@QueryParam("max") Integer maxResults) {
|
||||
@QueryParam("max") Integer maxResults,
|
||||
@QueryParam("briefRepresentation") Boolean briefRepresentation) {
|
||||
auth.users().requireQuery();
|
||||
|
||||
firstResult = firstResult != null ? firstResult : -1;
|
||||
|
@ -216,9 +217,12 @@ public class UsersResource {
|
|||
}
|
||||
|
||||
boolean canViewGlobal = auth.users().canView();
|
||||
boolean briefRepresentationB = briefRepresentation != null && briefRepresentation;
|
||||
for (UserModel user : userModels) {
|
||||
if (!canViewGlobal && !auth.users().canView(user)) continue;
|
||||
UserRepresentation userRep = ModelToRepresentation.toRepresentation(session, realm, user);
|
||||
UserRepresentation userRep = briefRepresentationB
|
||||
? ModelToRepresentation.toBriefRepresentation(user)
|
||||
: ModelToRepresentation.toRepresentation(session, realm, user);
|
||||
userRep.setAccess(auth.users().getAccess(user));
|
||||
results.add(userRep);
|
||||
}
|
||||
|
|
|
@ -86,12 +86,8 @@ import java.util.LinkedList;
|
|||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.keycloak.testsuite.Assert.assertNames;
|
||||
|
||||
/**
|
||||
|
@ -1407,14 +1403,36 @@ public class UserTest extends AbstractAdminTest {
|
|||
UsersResource users = adminClient.realms().realm("test").users();
|
||||
|
||||
for (int i = 0; i < 110; i++) {
|
||||
users.create(UserBuilder.create().username("test-" + i).build()).close();
|
||||
users.create(UserBuilder.create().username("test-" + i).addAttribute("aName", "aValue").build()).close();
|
||||
}
|
||||
|
||||
List<UserRepresentation> result = users.search("test", null, null);
|
||||
assertEquals(100, result.size());
|
||||
for (UserRepresentation user : result) {
|
||||
assertThat(user.getAttributes(), Matchers.notNullValue());
|
||||
assertThat(user.getAttributes().keySet(), Matchers.hasSize(1));
|
||||
assertThat(user.getAttributes(), Matchers.hasEntry(is("aName"), Matchers.contains("aValue")));
|
||||
}
|
||||
|
||||
assertEquals(100, users.search("test", null, null).size());
|
||||
assertEquals(105, users.search("test", 0, 105).size());
|
||||
assertEquals(111, users.search("test", 0, 1000).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultMaxResultsBrief() {
|
||||
UsersResource users = adminClient.realms().realm("test").users();
|
||||
|
||||
for (int i = 0; i < 110; i++) {
|
||||
users.create(UserBuilder.create().username("test-" + i).addAttribute("aName", "aValue").build()).close();
|
||||
}
|
||||
|
||||
List<UserRepresentation> result = users.search("test", null, null, true);
|
||||
assertEquals(100, result.size());
|
||||
for (UserRepresentation user : result) {
|
||||
assertThat(user.getAttributes(), Matchers.nullValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void switchEditUsernameAllowedOn(boolean enable) {
|
||||
RealmRepresentation rep = realm.toRepresentation();
|
||||
rep.setEditUsernameAllowed(enable);
|
||||
|
|
|
@ -82,6 +82,15 @@ public class UserBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public UserBuilder addAttribute(String name, String... values) {
|
||||
if (rep.getAttributes() == null) {
|
||||
rep.setAttributes(new HashMap<>());
|
||||
}
|
||||
|
||||
rep.getAttributes().put(name, Arrays.asList(values));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method makes sure that there is one single password for the user.
|
||||
*/
|
||||
|
|
|
@ -235,6 +235,7 @@ module.controller('UserListCtrl', function($scope, realm, User, UserSearchState,
|
|||
|
||||
UserSearchState.query.realm = realm.realm;
|
||||
$scope.query = UserSearchState.query;
|
||||
$scope.query.briefRepresentation = 'true';
|
||||
|
||||
if (!UserSearchState.isFirstSearch) $scope.searchQuery();
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue