0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-01-06 20:40:08 -05:00

feat(core): add pagination and search to role users (#2927)

This commit is contained in:
wangsijie 2023-01-12 17:28:23 +08:00 committed by GitHub
parent 6d874d5250
commit 900b87b9a5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 52 additions and 10 deletions

View file

@ -105,7 +105,7 @@ export const createUserQueries = (pool: CommonQueryMethods) => {
`
);
const buildUserConditions = (search: Search, excludeUserIds: string[]) => {
const buildUserConditions = (search: Search, excludeUserIds: string[], userIds?: string[]) => {
const hasSearch = search.matches.length > 0;
const searchFields = [
Users.fields.id,
@ -127,6 +127,16 @@ export const createUserQueries = (pool: CommonQueryMethods) => {
`;
}
if (userIds) {
return sql`
where ${fields.id} in (${userIds.length > 0 ? sql.join(userIds, sql`, `) : sql`null`})
${conditionalSql(
hasSearch,
() => sql`and (${buildConditionsFromSearch(search, searchFields)})`
)}
`;
}
return conditionalSql(
hasSearch,
() => sql`where ${buildConditionsFromSearch(search, searchFields)}`
@ -135,18 +145,23 @@ export const createUserQueries = (pool: CommonQueryMethods) => {
const defaultUserSearch = { matches: [], isCaseSensitive: false, joint: SearchJointMode.Or };
const countUsers = async (search: Search = defaultUserSearch, excludeUserIds: string[] = []) =>
const countUsers = async (
search: Search = defaultUserSearch,
excludeUserIds: string[] = [],
userIds?: string[]
) =>
pool.one<{ count: number }>(sql`
select count(*)
from ${table}
${buildUserConditions(search, excludeUserIds)}
${buildUserConditions(search, excludeUserIds, userIds)}
`);
const findUsers = async (
limit: number,
offset: number,
search: Search,
excludeUserIds: string[] = []
excludeUserIds: string[] = [],
userIds?: string[]
) =>
pool.any<User>(
sql`
@ -155,7 +170,7 @@ export const createUserQueries = (pool: CommonQueryMethods) => {
sql`,`
)}
from ${table}
${buildUserConditions(search, excludeUserIds)}
${buildUserConditions(search, excludeUserIds, userIds)}
limit ${limit}
offset ${offset}
`

View file

@ -44,6 +44,8 @@ const { insertRolesScopes } = rolesScopes;
const users = {
findUsersByIds: jest.fn(),
findUserById: jest.fn(),
countUsers: jest.fn(async () => ({ count: 1 })),
findUsers: jest.fn(async () => [mockUser]),
};
const { findUsersByIds } = users;

View file

@ -30,7 +30,7 @@ export default function roleRoutes<T extends AuthedRouter>(
updateRoleById,
},
scopes: { findScopeById },
users: { findUserById, findUsersByIds },
users: { findUserById, findUsersByIds, countUsers, findUsers },
usersRoles: {
countUsersRolesByRoleId,
deleteUsersRolesByUserIdAndRoleId,
@ -190,6 +190,7 @@ export default function roleRoutes<T extends AuthedRouter>(
router.get(
'/roles/:id/users',
koaPagination(),
koaGuard({
params: object({ id: string().min(1) }),
}),
@ -197,13 +198,37 @@ export default function roleRoutes<T extends AuthedRouter>(
const {
params: { id },
} = ctx.guard;
const { limit, offset } = ctx.pagination;
const { searchParams } = ctx.request.URL;
await findRoleById(id);
const usersRoles = await findUsersRolesByRoleId(id);
const users = await findUsersByIds(usersRoles.map(({ userId }) => userId));
ctx.body = users.map((user) => pick(user, ...userInfoSelectFields));
return next();
return tryThat(
async () => {
const search = parseSearchParamsForSearch(searchParams);
const usersRoles = await findUsersRolesByRoleId(id);
const userIds = usersRoles.map(({ userId }) => userId);
const [{ count }, users] = await Promise.all([
countUsers(search, undefined, userIds),
findUsers(limit, offset, search, undefined, userIds),
]);
ctx.pagination.totalCount = count;
ctx.body = users.map((user) => pick(user, ...userInfoSelectFields));
return next();
},
(error) => {
if (error instanceof TypeError) {
throw new RequestError(
{ code: 'request.invalid_input', details: error.message },
error
);
}
throw error;
}
);
}
);