0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-03-31 22:51:25 -05:00

feat(core): count role users and featured users (#2866)

This commit is contained in:
wangsijie 2023-01-09 13:03:28 +08:00 committed by GitHub
parent 8b179c0567
commit 225ccfed0a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 53 additions and 7 deletions

View file

@ -1,6 +1,6 @@
import type { UsersRole } from '@logto/schemas';
import { UsersRoles } from '@logto/schemas';
import { convertToIdentifiers } from '@logto/shared';
import { conditionalSql, convertToIdentifiers } from '@logto/shared';
import { sql } from 'slonik';
import envSet from '#src/env-set/index.js';
@ -14,11 +14,19 @@ export const findUsersRolesByUserId = async (userId: string) =>
where ${fields.userId}=${userId}
`);
export const findUsersRolesByRoleId = async (roleId: string) =>
export const findUsersRolesByRoleId = async (roleId: string, limit?: number) =>
envSet.pool.any<UsersRole>(sql`
select ${sql.join(Object.values(fields), sql`,`)}
from ${table}
where ${fields.roleId}=${roleId}
${conditionalSql(limit, (value) => sql`limit ${value}`)}
`);
export const countUsersRolesByRoleId = async (roleId: string) =>
envSet.pool.one<{ count: number }>(sql`
select count(*)
from ${table}
where ${fields.roleId}=${roleId}
`);
export const findFirstUsersRolesByRoleIdAndUserIds = async (roleId: string, userIds: string[]) =>

View file

@ -51,8 +51,10 @@ const {
findUsersRolesByRoleId,
deleteUsersRolesByUserIdAndRoleId,
findFirstUsersRolesByRoleIdAndUserIds,
countUsersRolesByRoleId,
} = await mockEsmWithActual('#src/queries/users-roles.js', () => ({
insertUsersRoles: jest.fn(),
countUsersRolesByRoleId: jest.fn(),
findUsersRolesByRoleId: jest.fn(),
findFirstUsersRolesByRoleIdAndUserIds: jest.fn(),
deleteUsersRolesByUserIdAndRoleId: jest.fn(),
@ -62,10 +64,24 @@ const roleRoutes = await pickDefault(import('./role.js'));
describe('role routes', () => {
const roleRequester = createRequester({ authedRoutes: roleRoutes });
it('GET /roles', async () => {
const response = await roleRequester.get('/roles');
it('GET /roles?page=1', async () => {
countUsersRolesByRoleId.mockResolvedValueOnce({ count: 1 });
findUsersByIds.mockResolvedValueOnce([mockUser]);
findUsersRolesByRoleId.mockResolvedValueOnce([]);
const response = await roleRequester.get('/roles?page=1&page_size=20');
expect(response.status).toEqual(200);
expect(response.body).toEqual([mockRole]);
expect(response.body).toEqual([
{
...mockRole,
usersCount: 1,
featuredUsers: [
{
id: mockUser.id,
avatar: mockUser.avatar,
},
],
},
]);
});
it('POST /roles', async () => {

View file

@ -1,5 +1,5 @@
import { buildIdGenerator } from '@logto/core-kit';
import type { ScopeResponse } from '@logto/schemas';
import type { RoleResponse, ScopeResponse } from '@logto/schemas';
import { Roles } from '@logto/schemas';
import { tryThat } from '@logto/shared';
import { object, string, z } from 'zod';
@ -25,6 +25,7 @@ import {
import { findScopeById, findScopesByIds } from '#src/queries/scope.js';
import { findUserById, findUsersByIds } from '#src/queries/user.js';
import {
countUsersRolesByRoleId,
deleteUsersRolesByUserIdAndRoleId,
findFirstUsersRolesByRoleIdAndUserIds,
findUsersRolesByRoleId,
@ -57,9 +58,23 @@ export default function roleRoutes<T extends AuthedRouter>(router: T) {
findRoles(search, limit, offset),
]);
const rolesResponse: RoleResponse[] = await Promise.all(
roles.map(async (role) => {
const { count } = await countUsersRolesByRoleId(role.id);
const usersRoles = await findUsersRolesByRoleId(role.id, 3);
const users = await findUsersByIds(usersRoles.map(({ userId }) => userId));
return {
...role,
usersCount: count,
featuredUsers: users.map(({ id, avatar }) => ({ id, avatar })),
};
})
);
// Return totalCount to pagination middleware
ctx.pagination.totalCount = count;
ctx.body = roles;
ctx.body = rolesResponse;
return next();
},

View file

@ -7,3 +7,4 @@ export * from './interactions.js';
export * from './search.js';
export * from './resource.js';
export * from './scope.js';
export * from './role.js';

View file

@ -0,0 +1,6 @@
import type { Role, User } from '../db-entries/index.js';
export type RoleResponse = Role & {
usersCount: number;
featuredUsers: Array<Pick<User, 'avatar' | 'id'>>;
};