mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
fix(core): fix unpaginated scopes response (#3810)
This commit is contained in:
parent
f20f65407f
commit
e57fc80bd4
4 changed files with 45 additions and 19 deletions
|
@ -66,6 +66,11 @@ export const mockScope: Scope = {
|
|||
createdAt: 1_645_334_775_356,
|
||||
};
|
||||
|
||||
export const mockScopeWithResource = {
|
||||
...mockScope,
|
||||
resource: mockResource,
|
||||
};
|
||||
|
||||
export const mockRole: Role = {
|
||||
tenantId: 'fake_tenant',
|
||||
id: 'role_id',
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { Role } from '@logto/schemas';
|
||||
import { pickDefault } from '@logto/shared/esm';
|
||||
|
||||
import { mockRole, mockScope, mockResource } from '#src/__mocks__/index.js';
|
||||
import { mockRole, mockScope, mockResource, mockScopeWithResource } from '#src/__mocks__/index.js';
|
||||
import { mockId, mockStandardId } from '#src/test-utils/nanoid.js';
|
||||
import { MockTenant } from '#src/test-utils/tenant.js';
|
||||
import { createRequester } from '#src/utils/test-utils.js';
|
||||
|
@ -68,7 +68,16 @@ describe('role scope routes', () => {
|
|||
findScopesByIds.mockResolvedValueOnce([mockScope]);
|
||||
const response = await roleRequester.get(`/roles/${mockRole.id}/scopes`);
|
||||
expect(response.status).toEqual(200);
|
||||
expect(response.body).toEqual([mockScope]);
|
||||
expect(response.body).toEqual([mockScopeWithResource]);
|
||||
});
|
||||
|
||||
it('GET /roles/:id/scopes (with pagination)', async () => {
|
||||
findRoleById.mockResolvedValueOnce(mockRole);
|
||||
findRolesScopesByRoleId.mockResolvedValueOnce([]);
|
||||
findScopesByIds.mockResolvedValueOnce([mockScope]);
|
||||
const response = await roleRequester.get(`/roles/${mockRole.id}/scopes?page=1`);
|
||||
expect(response.status).toEqual(200);
|
||||
expect(response.body).toEqual([mockScopeWithResource]);
|
||||
});
|
||||
|
||||
it('POST /roles/:id/scopes', async () => {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import type { ScopeResponse } from '@logto/schemas';
|
||||
import type { Scope, ScopeResponse } from '@logto/schemas';
|
||||
import { scopeResponseGuard } from '@logto/schemas';
|
||||
import { generateStandardId } from '@logto/shared';
|
||||
import { tryThat } from '@silverhand/essentials';
|
||||
import { object, string } from 'zod';
|
||||
|
@ -21,11 +22,26 @@ export default function roleScopeRoutes<T extends AuthedRouter>(
|
|||
scopes: { findScopeById, findScopesByIds, countScopesByScopeIds, searchScopesByScopeIds },
|
||||
} = queries;
|
||||
|
||||
const attachResourceToScopes = async (scopes: readonly Scope[]): Promise<ScopeResponse[]> => {
|
||||
const resources = await findResourcesByIds(scopes.map(({ resourceId }) => resourceId));
|
||||
return scopes.map((scope) => {
|
||||
const resource = resources.find(({ id }) => id === scope.resourceId);
|
||||
|
||||
assertThat(resource, new Error(`Cannot find resource for id ${scope.resourceId}`));
|
||||
|
||||
return {
|
||||
...scope,
|
||||
resource,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
router.get(
|
||||
'/roles/:id/scopes',
|
||||
koaPagination({ isOptional: true }),
|
||||
koaGuard({
|
||||
params: object({ id: string().min(1) }),
|
||||
response: scopeResponseGuard.array(),
|
||||
}),
|
||||
async (ctx, next) => {
|
||||
const {
|
||||
|
@ -43,7 +59,9 @@ export default function roleScopeRoutes<T extends AuthedRouter>(
|
|||
const scopeIds = rolesScopes.map(({ scopeId }) => scopeId);
|
||||
|
||||
if (disabled) {
|
||||
ctx.body = await searchScopesByScopeIds(scopeIds, search);
|
||||
const scopes = await searchScopesByScopeIds(scopeIds, search);
|
||||
|
||||
ctx.body = await attachResourceToScopes(scopes);
|
||||
|
||||
return next();
|
||||
}
|
||||
|
@ -53,21 +71,9 @@ export default function roleScopeRoutes<T extends AuthedRouter>(
|
|||
searchScopesByScopeIds(scopeIds, search, limit, offset),
|
||||
]);
|
||||
|
||||
const resources = await findResourcesByIds(scopes.map(({ resourceId }) => resourceId));
|
||||
const result: ScopeResponse[] = scopes.map((scope) => {
|
||||
const resource = resources.find(({ id }) => id === scope.resourceId);
|
||||
|
||||
assertThat(resource, new Error(`Cannot find resource for id ${scope.resourceId}`));
|
||||
|
||||
return {
|
||||
...scope,
|
||||
resource,
|
||||
};
|
||||
});
|
||||
|
||||
// Return totalCount to pagination middleware
|
||||
ctx.pagination.totalCount = count;
|
||||
ctx.body = result;
|
||||
ctx.body = await attachResourceToScopes(scopes);
|
||||
|
||||
return next();
|
||||
},
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
import type { Resource, Scope } from '../db-entries/index.js';
|
||||
import { type z } from 'zod';
|
||||
|
||||
export type ScopeResponse = Scope & { resource: Resource };
|
||||
import { Resources, Scopes } from '../db-entries/index.js';
|
||||
|
||||
export const scopeResponseGuard = Scopes.guard.extend({
|
||||
resource: Resources.guard,
|
||||
});
|
||||
|
||||
export type ScopeResponse = z.infer<typeof scopeResponseGuard>;
|
||||
|
|
Loading…
Reference in a new issue