diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/GroupsResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/GroupsResource.java index ce6db747fc..2a4b40af24 100755 --- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/GroupsResource.java +++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/GroupsResource.java @@ -67,6 +67,29 @@ public interface GroupsResource { @QueryParam("first") Integer first, @QueryParam("max") Integer max); + /** + * Counts all groups. + * @return The number of groups. + */ + @GET + @NoCache + @Path("/count") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + Response count(); + + /** + * Counts groups by name search. + * @param search max number of occurrences + * @return The number of group containing search therm. + */ + @GET + @NoCache + @Path("/count") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + Response count(@QueryParam("search") String search); + /** * create or add a top level realm groupSet or create child. This will update the group and set the parent if it exists. Create it and set the parent * if the group doesn't exist. diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java index d39646305d..5b99ff1451 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java @@ -1200,6 +1200,16 @@ public class RealmAdapter implements CachedRealmModel { return cacheSession.getGroups(this); } + @Override + public Long getGroupsCount() { + return cacheSession.getGroupsCount(this); + } + + @Override + public Long getGroupsCountByNameContaining(String search) { + return cacheSession.getGroupsCountByNameContaining(this, search); + } + @Override public List getTopLevelGroups() { return cacheSession.getTopLevelGroups(this); diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java index 47267ada62..6c654238bf 100755 --- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java +++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java @@ -841,6 +841,16 @@ public class RealmCacheSession implements CacheRealmProvider { return list; } + @Override + public Long getGroupsCount(RealmModel realm) { + return getDelegate().getGroupsCount(realm); + } + + @Override + public Long getGroupsCountByNameContaining(RealmModel realm, String search) { + return getDelegate().getGroupsCountByNameContaining(realm, search); + } + @Override public List getTopLevelGroups(RealmModel realm) { String cacheKey = getTopGroupsQueryCacheKey(realm.getId()); diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java index 683f7a31e6..306f674b7a 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java @@ -322,6 +322,25 @@ public class JpaRealmProvider implements RealmProvider { Collectors.toList(), Collections::unmodifiableList)); } + @Override + public Long getGroupsCount(RealmModel realm) { + Long count = em.createNamedQuery("getGroupCount", Long.class) + .setParameter("realm", realm.getId()) + .getSingleResult(); + + return count; + } + + @Override + public Long getGroupsCountByNameContaining(RealmModel realm, String search) { + Long count = em.createNamedQuery("getGroupCountByNameContaining", Long.class) + .setParameter("realm", realm.getId()) + .setParameter("name", search) + .getSingleResult(); + + return count; + } + @Override public List getTopLevelGroups(RealmModel realm) { RealmEntity ref = em.getReference(RealmEntity.class, realm.getId()); diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java index e53ef2f6b6..a217af3a8c 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java @@ -1674,6 +1674,16 @@ public class RealmAdapter implements RealmModel, JpaModel { return session.realms().getGroups(this); } + @Override + public Long getGroupsCount() { + return session.realms().getGroupsCount(this); + } + + @Override + public Long getGroupsCountByNameContaining(String search) { + return session.realms().getGroupsCountByNameContaining(this, search); + } + @Override public List getTopLevelGroups() { return session.realms().getTopLevelGroups(this); diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/GroupEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/GroupEntity.java index 77bc44dc19..1f7dc09796 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/GroupEntity.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/GroupEntity.java @@ -28,7 +28,9 @@ import java.util.Collection; @NamedQueries({ @NamedQuery(name="getGroupIdsByParent", query="select u.id from GroupEntity u where u.parent = :parent"), @NamedQuery(name="getGroupIdsByNameContaining", query="select u.id from GroupEntity u where u.realm.id = :realm and u.name like concat('%',:search,'%') order by u.name ASC"), - @NamedQuery(name="getTopLevelGroupIds", query="select u.id from GroupEntity u where u.parent is null and u.realm.id = :realm") + @NamedQuery(name="getTopLevelGroupIds", query="select u.id from GroupEntity u where u.parent is null and u.realm.id = :realm"), + @NamedQuery(name="getGroupCount", query="select count(u) from GroupEntity u where u.realm.id = :realm"), + @NamedQuery(name="getGroupCountByNameContaining", query="select count(u) from GroupEntity u where u.realm.id = :realm and u.name like concat('%',:name,'%')") }) @Entity @Table(name="KEYCLOAK_GROUP") diff --git a/server-spi/src/main/java/org/keycloak/models/RealmModel.java b/server-spi/src/main/java/org/keycloak/models/RealmModel.java index f90a9d73eb..133c247076 100755 --- a/server-spi/src/main/java/org/keycloak/models/RealmModel.java +++ b/server-spi/src/main/java/org/keycloak/models/RealmModel.java @@ -397,6 +397,8 @@ public interface RealmModel extends RoleContainerModel { GroupModel getGroupById(String id); List getGroups(); + Long getGroupsCount(); + Long getGroupsCountByNameContaining(String search); List getTopLevelGroups(); List getTopLevelGroups(Integer first, Integer max); List searchForGroupByName(String search, Integer first, Integer max); diff --git a/server-spi/src/main/java/org/keycloak/models/RealmProvider.java b/server-spi/src/main/java/org/keycloak/models/RealmProvider.java index 3e1a1c9221..72c11ad701 100755 --- a/server-spi/src/main/java/org/keycloak/models/RealmProvider.java +++ b/server-spi/src/main/java/org/keycloak/models/RealmProvider.java @@ -40,6 +40,10 @@ public interface RealmProvider extends Provider { List getGroups(RealmModel realm); + Long getGroupsCount(RealmModel realm); + + Long getGroupsCountByNameContaining(RealmModel realm, String search); + List getTopLevelGroups(RealmModel realm); List getTopLevelGroups(RealmModel realm, Integer first, Integer max); @@ -89,6 +93,8 @@ public interface RealmProvider extends Provider { ClientTemplateModel getClientTemplateById(String id, RealmModel realm); GroupModel getGroupById(String id, RealmModel realm); + + List getRealms(); boolean removeRealm(String id); void close(); diff --git a/services/src/main/java/org/keycloak/services/resources/admin/GroupsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/GroupsResource.java index 7c61fe9a3e..e5b4676961 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/GroupsResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/GroupsResource.java @@ -101,6 +101,25 @@ public class GroupsResource { return resource; } + /** + * Returns the groups counts. + * + * @return + */ + @GET + @NoCache + @Path("/count") + public Response getGroupCount(@QueryParam("search") String search) { + auth.requireView(); + Long results; + if (Objects.nonNull(search)) { + results = realm.getGroupsCountByNameContaining(search); + } else { + results = realm.getGroupsCount(); + } + return Response.ok(results).build(); + } + /** * create or add a top level realm groupSet or create child. This will update the group and set the parent if it exists. Create it and set the parent * if the group doesn't exist.