mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-04-04 06:47:19 +02:00
fix: paginate listRoles, null-guard permissions handler, fix export ordering
- Add limit/offset/total pagination to listRoles matching the groups pattern - Add countRoles data-layer method - Omit permissions from listRoles select (getRole returns full document) - Null-guard re-fetched role in updateRolePermissionsHandler - Move interleaved export below all imports in methods/index.ts
This commit is contained in:
parent
2a4cbfa41a
commit
2506644d58
5 changed files with 62 additions and 11 deletions
|
|
@ -58,6 +58,7 @@ function createReqRes(
|
|||
function createDeps(overrides: Partial<AdminRolesDeps> = {}): AdminRolesDeps {
|
||||
return {
|
||||
listRoles: jest.fn().mockResolvedValue([]),
|
||||
countRoles: jest.fn().mockResolvedValue(0),
|
||||
getRoleByName: jest.fn().mockResolvedValue(null),
|
||||
createRoleByName: jest.fn().mockResolvedValue(mockRole()),
|
||||
updateRoleByName: jest.fn().mockResolvedValue(mockRole()),
|
||||
|
|
@ -74,16 +75,46 @@ function createDeps(overrides: Partial<AdminRolesDeps> = {}): AdminRolesDeps {
|
|||
|
||||
describe('createAdminRolesHandlers', () => {
|
||||
describe('listRoles', () => {
|
||||
it('returns roles with 200', async () => {
|
||||
it('returns paginated roles with 200', async () => {
|
||||
const roles = [mockRole()];
|
||||
const deps = createDeps({ listRoles: jest.fn().mockResolvedValue(roles) });
|
||||
const deps = createDeps({
|
||||
listRoles: jest.fn().mockResolvedValue(roles),
|
||||
countRoles: jest.fn().mockResolvedValue(1),
|
||||
});
|
||||
const handlers = createAdminRolesHandlers(deps);
|
||||
const { req, res, status, json } = createReqRes();
|
||||
|
||||
await handlers.listRoles(req, res);
|
||||
|
||||
expect(status).toHaveBeenCalledWith(200);
|
||||
expect(json).toHaveBeenCalledWith({ roles });
|
||||
expect(json).toHaveBeenCalledWith({ roles, total: 1, limit: 50, offset: 0 });
|
||||
expect(deps.listRoles).toHaveBeenCalledWith({ limit: 50, offset: 0 });
|
||||
});
|
||||
|
||||
it('passes custom limit and offset from query', async () => {
|
||||
const deps = createDeps({
|
||||
countRoles: jest.fn().mockResolvedValue(100),
|
||||
});
|
||||
const handlers = createAdminRolesHandlers(deps);
|
||||
const { req, res, status, json } = createReqRes({
|
||||
query: { limit: '25', offset: '50' },
|
||||
});
|
||||
|
||||
await handlers.listRoles(req, res);
|
||||
|
||||
expect(status).toHaveBeenCalledWith(200);
|
||||
expect(json).toHaveBeenCalledWith({ roles: [], total: 100, limit: 25, offset: 50 });
|
||||
expect(deps.listRoles).toHaveBeenCalledWith({ limit: 25, offset: 50 });
|
||||
});
|
||||
|
||||
it('clamps limit to 200', async () => {
|
||||
const deps = createDeps();
|
||||
const handlers = createAdminRolesHandlers(deps);
|
||||
const { req, res } = createReqRes({ query: { limit: '999' } });
|
||||
|
||||
await handlers.listRoles(req, res);
|
||||
|
||||
expect(deps.listRoles).toHaveBeenCalledWith({ limit: 200, offset: 0 });
|
||||
});
|
||||
|
||||
it('returns 500 on error', async () => {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ interface RoleMemberParams extends RoleNameParams {
|
|||
}
|
||||
|
||||
export interface AdminRolesDeps {
|
||||
listRoles: () => Promise<IRole[]>;
|
||||
listRoles: (options?: { limit?: number; offset?: number }) => Promise<IRole[]>;
|
||||
countRoles: () => Promise<number>;
|
||||
getRoleByName: (name: string, fields?: string | string[] | null) => Promise<IRole | null>;
|
||||
createRoleByName: (roleData: Partial<IRole>) => Promise<IRole>;
|
||||
updateRoleByName: (name: string, updates: Partial<IRole>) => Promise<IRole | null>;
|
||||
|
|
@ -43,6 +44,7 @@ export interface AdminRolesDeps {
|
|||
export function createAdminRolesHandlers(deps: AdminRolesDeps) {
|
||||
const {
|
||||
listRoles,
|
||||
countRoles,
|
||||
getRoleByName,
|
||||
createRoleByName,
|
||||
updateRoleByName,
|
||||
|
|
@ -55,10 +57,12 @@ export function createAdminRolesHandlers(deps: AdminRolesDeps) {
|
|||
countUsersByRole,
|
||||
} = deps;
|
||||
|
||||
async function listRolesHandler(_req: ServerRequest, res: Response) {
|
||||
async function listRolesHandler(req: ServerRequest, res: Response) {
|
||||
try {
|
||||
const roles = await listRoles();
|
||||
return res.status(200).json({ roles });
|
||||
const limit = Math.min(Math.max(Number(req.query.limit) || 50, 1), 200);
|
||||
const offset = Math.max(Number(req.query.offset) || 0, 0);
|
||||
const [roles, total] = await Promise.all([listRoles({ limit, offset }), countRoles()]);
|
||||
return res.status(200).json({ roles, total, limit, offset });
|
||||
} catch (error) {
|
||||
logger.error('[adminRoles] listRoles error:', error);
|
||||
return res.status(500).json({ error: 'Failed to list roles' });
|
||||
|
|
@ -233,6 +237,9 @@ export function createAdminRolesHandlers(deps: AdminRolesDeps) {
|
|||
|
||||
await updateAccessPermissions(name, permissions, existing);
|
||||
const updated = await getRoleByName(name);
|
||||
if (!updated) {
|
||||
return res.status(404).json({ error: 'Role not found' });
|
||||
}
|
||||
return res.status(200).json({ role: updated });
|
||||
} catch (error) {
|
||||
logger.error('[adminRoles] updateRolePermissions error:', error);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue