0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-02-24 22:05:56 -05:00

fix(core): show all organization permissions (#7070)

* fix(core): show all organization permissions

* chore: update changeset

* test: update org scopes tests
This commit is contained in:
Xiao Yijun 2025-02-24 17:26:16 +08:00 committed by GitHub
parent 31adfb6ac2
commit f15602f198
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 40 additions and 11 deletions

View file

@ -0,0 +1,10 @@
---
"@logto/core": patch
---
fix: incorrect pagination behavior in organization role scopes APIs
- Fix `/api/organization-roles/{id}/scopes` and `/api/organization-roles/{id}/resource-scopes` endpoints to:
- Return all scopes when no pagination parameters are provided
- Support optional pagination when query parameters are present
- Fix Console to properly display all organization role scopes on the organization template page

View file

@ -102,7 +102,7 @@
"/api/organization-roles/{id}/scopes": {
"get": {
"summary": "Get organization role scopes",
"description": "Get all organization scopes that are assigned to the specified organization role.",
"description": "Get organization scopes that are assigned to the specified organization role with optional pagination.",
"responses": {
"200": {
"description": "A list of organization scopes."
@ -174,7 +174,7 @@
"/api/organization-roles/{id}/resource-scopes": {
"get": {
"summary": "Get organization role resource scopes",
"description": "Get all resource scopes that are assigned to the specified organization role.",
"description": "Get resource scopes that are assigned to the specified organization role with optional pagination.",
"responses": {
"200": {
"description": "A list of resource scopes."

View file

@ -127,8 +127,8 @@ export default function organizationRoleRoutes<T extends ManagementApiRouter>(
}
);
router.addRelationRoutes(rolesScopes, 'scopes');
router.addRelationRoutes(rolesResourceScopes, 'resource-scopes');
router.addRelationRoutes(rolesScopes, 'scopes', { isPaginationOptional: true });
router.addRelationRoutes(rolesResourceScopes, 'resource-scopes', { isPaginationOptional: true });
originalRouter.use(router.routes());
}

View file

@ -9,7 +9,7 @@
"/api/organization-scopes": {
"get": {
"summary": "Get organization scopes",
"description": "Get organization scopes that match with pagination.",
"description": "Get organization scopes that match with optional pagination.",
"responses": {
"200": {
"description": "A list of organization scopes."

View file

@ -19,6 +19,7 @@ export default function organizationScopeRoutes<T extends ManagementApiRouter>(
middlewares: [],
errorHandler,
searchFields: ['name'],
isPaginationOptional: true,
});
originalRouter.use(router.routes());

View file

@ -86,6 +86,11 @@ type SchemaRouterConfig<Key extends string> = {
* If not provided, the `schema.guard` will be used.
*/
entityGuard?: z.ZodTypeAny;
/**
* If the GET route's pagination is optional.
* @default false
*/
isPaginationOptional?: boolean;
};
type RelationRoutesConfig = {
@ -313,12 +318,12 @@ export default class SchemaRouter<
#addRoutes() {
const { queries, schema, config } = this;
const { disabled, searchFields, idLength, entityGuard } = config;
const { disabled, searchFields, idLength, entityGuard, isPaginationOptional } = config;
if (!disabled.get) {
this.get(
'/',
koaPagination(),
koaPagination({ isOptional: isPaginationOptional }),
koaGuard({
query: z.object({ q: z.string().optional() }),
response: (entityGuard ?? schema.guard).array(),

View file

@ -299,6 +299,10 @@ describe('organization scope data hook events', () => {
expect(organizationScopeCreateHook?.payload.event).toBe('OrganizationScope.Created');
});
afterAll(async () => {
await organizationScopeApi.cleanUp();
});
it.each(organizationScopeDataHookTestCases)(
'test case %#: %p',
async ({ route, event, method, endpoint, payload }) => {

View file

@ -39,15 +39,21 @@ describe('organization scope APIs', () => {
expect(scopes).toContainEqual(expect.objectContaining({ name: name2, description: null }));
});
it('should get organization scopes with pagination', async () => {
// Add 20 scopes to exceed the default page size
it('should get organization scopes with optional pagination', async () => {
const pageSize = 20;
// Create scopes to exceed the default page size
const createCount = pageSize + 10;
await Promise.all(
Array.from({ length: 30 }).map(async () => scopeApi.create({ name: 'test' + randomId() }))
Array.from({ length: createCount }).map(async () =>
scopeApi.create({ name: 'test' + randomId() })
)
);
// Should return all scopes if no pagination is provided
const scopes = await scopeApi.getList();
expect(scopes).toHaveLength(20);
expect(scopes).toHaveLength(createCount);
// Should return paginated scopes based on specified page number and page size
const scopes2 = await scopeApi.getList(
new URLSearchParams({
page: '2',

View file

@ -390,6 +390,9 @@ describe('organization user APIs', () => {
await organizationApi.addUserRoles(organization.id, user.id, [role2.id]);
const newScopes = await organizationApi.getUserOrganizationScopes(organization.id, user.id);
expect(newScopes.map(({ name }) => name)).toEqual([scope1.name]);
// Clean up
await organizationApi.cleanUp();
});
});
});