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

feat(core,schemas): add CRUD for consent organization resource scopes ()

feat(core,schemas): add crud for user consent organization resource scopes
This commit is contained in:
wangsijie 2024-04-30 15:09:13 +08:00 committed by GitHub
parent 2e96eea60c
commit 5adf3dfad7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 176 additions and 26 deletions
packages
console/src/pages/ApplicationDetails/ApplicationDetailsContent/Permissions/ApplicationScopesAssignmentModal
core/src
integration-tests/src
schemas/src/types

View file

@ -10,6 +10,11 @@ export const permissionTabs = Object.freeze({
title: 'application_details.permissions.api_resource', title: 'application_details.permissions.api_resource',
key: ApplicationUserConsentScopeType.ResourceScopes, key: ApplicationUserConsentScopeType.ResourceScopes,
}, },
[ApplicationUserConsentScopeType.OrganizationResourceScopes]: {
// TODO @xiaoyijun: update the title
title: 'application_details.permissions.api_resource',
key: ApplicationUserConsentScopeType.OrganizationResourceScopes,
},
[ApplicationUserConsentScopeType.OrganizationScopes]: { [ApplicationUserConsentScopeType.OrganizationScopes]: {
title: 'application_details.permissions.organization', title: 'application_details.permissions.organization',
key: ApplicationUserConsentScopeType.OrganizationScopes, key: ApplicationUserConsentScopeType.OrganizationScopes,

View file

@ -72,6 +72,8 @@ const useApplicationScopesAssignment = (applicationId: string) => {
[ApplicationUserConsentScopeType.UserScopes]: userScopesAssignment, [ApplicationUserConsentScopeType.UserScopes]: userScopesAssignment,
[ApplicationUserConsentScopeType.OrganizationScopes]: organizationScopesAssignment, [ApplicationUserConsentScopeType.OrganizationScopes]: organizationScopesAssignment,
[ApplicationUserConsentScopeType.ResourceScopes]: resourceScopesAssignment, [ApplicationUserConsentScopeType.ResourceScopes]: resourceScopesAssignment,
// TODO @xiaoyijun: Replace with correct scopes
[ApplicationUserConsentScopeType.OrganizationResourceScopes]: resourceScopesAssignment,
}), }),
[organizationScopesAssignment, resourceScopesAssignment, userScopesAssignment] [organizationScopesAssignment, resourceScopesAssignment, userScopesAssignment]
); );

View file

@ -32,6 +32,7 @@ export const createApplicationLibrary = (queries: Queries) => {
applications: { applications: {
findApplicationById, findApplicationById,
userConsentOrganizationScopes, userConsentOrganizationScopes,
userConsentOrganizationResourceScopes,
userConsentResourceScopes, userConsentResourceScopes,
userConsentUserScopes, userConsentUserScopes,
}, },
@ -76,16 +77,20 @@ export const createApplicationLibrary = (queries: Queries) => {
{ {
organizationScopes = [], organizationScopes = [],
resourceScopes = [], resourceScopes = [],
organizationResourceScopes = [],
}: { }: {
organizationScopes?: string[]; organizationScopes?: string[];
resourceScopes?: string[]; resourceScopes?: string[];
organizationResourceScopes?: string[];
}, },
tenantId: string tenantId: string
) => { ) => {
const [organizationScopesData, resourceScopesData] = await Promise.all([ const [organizationScopesData, resourceScopesData, organizationResourceScopesData] =
organizationScopesQuery.findByIds(organizationScopes), await Promise.all([
findScopesByIds(resourceScopes), organizationScopesQuery.findByIds(organizationScopes),
]); findScopesByIds(resourceScopes),
findScopesByIds(organizationResourceScopes),
]);
const invalidOrganizationScopes = organizationScopes.filter( const invalidOrganizationScopes = organizationScopes.filter(
(scope) => !organizationScopesData.some(({ id }) => id === scope) (scope) => !organizationScopesData.some(({ id }) => id === scope)
@ -95,22 +100,28 @@ export const createApplicationLibrary = (queries: Queries) => {
(scope) => !resourceScopesData.some(({ id }) => id === scope) (scope) => !resourceScopesData.some(({ id }) => id === scope)
); );
const invalidOrganizationResourceScopes = organizationResourceScopes.filter(
(scope) => !organizationResourceScopesData.some(({ id }) => id === scope)
);
// Assert that all scopes exist, return the missing ones // Assert that all scopes exist, return the missing ones
assertThat( assertThat(
invalidOrganizationScopes.length === 0 && invalidResourceScopes.length === 0, invalidOrganizationScopes.length === 0 &&
invalidResourceScopes.length === 0 &&
invalidOrganizationResourceScopes.length === 0,
new RequestError( new RequestError(
{ {
code: 'application.user_consent_scopes_not_found', code: 'application.user_consent_scopes_not_found',
status: 422, status: 422,
}, },
{ invalidOrganizationScopes, invalidResourceScopes } { invalidOrganizationScopes, invalidResourceScopes, invalidOrganizationResourceScopes }
) )
); );
const managementApiResourceIndicator = getManagementApiResourceIndicator(tenantId); const managementApiResourceIndicator = getManagementApiResourceIndicator(tenantId);
const managementApiScopes = await findScopesByIdsAndResourceIndicator( const managementApiScopes = await findScopesByIdsAndResourceIndicator(
resourceScopes, [...resourceScopes, ...organizationResourceScopes],
managementApiResourceIndicator managementApiResourceIndicator
); );
@ -129,10 +140,12 @@ export const createApplicationLibrary = (queries: Queries) => {
{ {
organizationScopes, organizationScopes,
resourceScopes, resourceScopes,
organizationResourceScopes,
userScopes, userScopes,
}: { }: {
organizationScopes?: string[]; organizationScopes?: string[];
resourceScopes?: string[]; resourceScopes?: string[];
organizationResourceScopes?: string[];
userScopes?: string[]; userScopes?: string[];
} }
) => { ) => {
@ -148,6 +161,12 @@ export const createApplicationLibrary = (queries: Queries) => {
); );
} }
if (organizationResourceScopes) {
await userConsentOrganizationResourceScopes.insert(
...organizationResourceScopes.map<[string, string]>((scope) => [applicationId, scope])
);
}
if (userScopes) { if (userScopes) {
await Promise.all( await Promise.all(
userScopes.map(async (userScope) => userScopes.map(async (userScope) =>
@ -181,6 +200,21 @@ export const createApplicationLibrary = (queries: Queries) => {
); );
}; };
const getApplicationUserConsentOrganizationResourceScopes = async (applicationId: string) => {
const [, scopes] = await userConsentOrganizationResourceScopes.getEntities(Scopes, {
applicationId,
});
const groupedScopes = groupResourceScopesByResourceId(scopes);
return Promise.all(
groupedScopes.map(async ({ resourceId, scopes }) => ({
resource: await findResourceById(resourceId),
scopes,
}))
);
};
const getApplicationUserConsentScopes = async (applicationId: string) => const getApplicationUserConsentScopes = async (applicationId: string) =>
userConsentUserScopes.findAllByApplicationId(applicationId); userConsentUserScopes.findAllByApplicationId(applicationId);
@ -198,6 +232,10 @@ export const createApplicationLibrary = (queries: Queries) => {
await userConsentResourceScopes.delete({ applicationId, scopeId }); await userConsentResourceScopes.delete({ applicationId, scopeId });
break; break;
} }
case ApplicationUserConsentScopeType.OrganizationResourceScopes: {
await userConsentOrganizationResourceScopes.delete({ applicationId, scopeId });
break;
}
case ApplicationUserConsentScopeType.UserScopes: { case ApplicationUserConsentScopeType.UserScopes: {
await userConsentUserScopes.deleteByApplicationIdAndScopeId(applicationId, scopeId); await userConsentUserScopes.deleteByApplicationIdAndScopeId(applicationId, scopeId);
break; break;
@ -250,6 +288,7 @@ export const createApplicationLibrary = (queries: Queries) => {
assignApplicationUserConsentScopes, assignApplicationUserConsentScopes,
getApplicationUserConsentOrganizationScopes, getApplicationUserConsentOrganizationScopes,
getApplicationUserConsentResourceScopes, getApplicationUserConsentResourceScopes,
getApplicationUserConsentOrganizationResourceScopes,
getApplicationUserConsentScopes, getApplicationUserConsentScopes,
deleteApplicationUserConsentScopesByTypeAndScopeId, deleteApplicationUserConsentScopesByTypeAndScopeId,
validateUserConsentOrganizationMembership, validateUserConsentOrganizationMembership,

View file

@ -2,6 +2,7 @@ import { type UserScope } from '@logto/core-kit';
import { import {
ApplicationUserConsentOrganizationScopes, ApplicationUserConsentOrganizationScopes,
ApplicationUserConsentResourceScopes, ApplicationUserConsentResourceScopes,
ApplicationUserConsentOrganizationResourceScopes,
ApplicationUserConsentUserScopes, ApplicationUserConsentUserScopes,
Applications, Applications,
OrganizationScopes, OrganizationScopes,
@ -32,6 +33,15 @@ export class ApplicationUserConsentResourceScopeQueries extends TwoRelationsQuer
} }
} }
export class ApplicationUserConsentOrganizationResourceScopeQueries extends TwoRelationsQueries<
typeof Applications,
typeof Scopes
> {
constructor(pool: CommonQueryMethods) {
super(pool, ApplicationUserConsentOrganizationResourceScopes.table, Applications, Scopes);
}
}
export const createApplicationUserConsentUserScopeQueries = (pool: CommonQueryMethods) => { export const createApplicationUserConsentUserScopeQueries = (pool: CommonQueryMethods) => {
const insert = buildInsertIntoWithPool(pool)(ApplicationUserConsentUserScopes, { const insert = buildInsertIntoWithPool(pool)(ApplicationUserConsentUserScopes, {
onConflict: { ignore: true }, onConflict: { ignore: true },

View file

@ -15,6 +15,7 @@ import type { OmitAutoSetFields } from '#src/utils/sql.js';
import ApplicationUserConsentOrganizationsQuery from './application-user-consent-organizations.js'; import ApplicationUserConsentOrganizationsQuery from './application-user-consent-organizations.js';
import { import {
ApplicationUserConsentOrganizationResourceScopeQueries,
ApplicationUserConsentOrganizationScopeQueries, ApplicationUserConsentOrganizationScopeQueries,
ApplicationUserConsentResourceScopeQueries, ApplicationUserConsentResourceScopeQueries,
createApplicationUserConsentUserScopeQueries, createApplicationUserConsentUserScopeQueries,
@ -253,6 +254,8 @@ export const createApplicationQueries = (pool: CommonQueryMethods) => {
deleteApplicationById, deleteApplicationById,
userConsentOrganizationScopes: new ApplicationUserConsentOrganizationScopeQueries(pool), userConsentOrganizationScopes: new ApplicationUserConsentOrganizationScopeQueries(pool),
userConsentResourceScopes: new ApplicationUserConsentResourceScopeQueries(pool), userConsentResourceScopes: new ApplicationUserConsentResourceScopeQueries(pool),
userConsentOrganizationResourceScopes:
new ApplicationUserConsentOrganizationResourceScopeQueries(pool),
userConsentUserScopes: createApplicationUserConsentUserScopeQueries(pool), userConsentUserScopes: createApplicationUserConsentUserScopeQueries(pool),
userConsentOrganizations: new ApplicationUserConsentOrganizationsQuery(pool), userConsentOrganizations: new ApplicationUserConsentOrganizationsQuery(pool),
}; };

View file

@ -15,6 +15,9 @@
"resourceScopes": { "resourceScopes": {
"description": "A list of resource scope id to assign to the application. Throws error if any given resource scope is not found." "description": "A list of resource scope id to assign to the application. Throws error if any given resource scope is not found."
}, },
"organizationResourceScopes": {
"description": "A list of organization resource scope id to assign to the application. Throws error if any given resource scope is not found."
},
"userScopes": { "userScopes": {
"description": "A list of user scope enum value to assign to the application." "description": "A list of user scope enum value to assign to the application."
} }
@ -51,6 +54,9 @@
"resourceScopes": { "resourceScopes": {
"description": "A list of resource scope details grouped by resource id assigned to the application." "description": "A list of resource scope details grouped by resource id assigned to the application."
}, },
"organizationResourceScopes": {
"description": "A list of organization resource scope details grouped by resource id assigned to the application."
},
"userScopes": { "userScopes": {
"description": "A list of user scope enum value assigned to the application." "description": "A list of user scope enum value assigned to the application."
} }

View file

@ -5,6 +5,7 @@ import {
} from '@logto/schemas'; } from '@logto/schemas';
import { object, string, nativeEnum } from 'zod'; import { object, string, nativeEnum } from 'zod';
import { EnvSet } from '#src/env-set/index.js';
import koaGuard from '#src/middleware/koa-guard.js'; import koaGuard from '#src/middleware/koa-guard.js';
import type { ManagementApiRouter, RouterInitArgs } from '../types.js'; import type { ManagementApiRouter, RouterInitArgs } from '../types.js';
@ -24,6 +25,7 @@ export default function applicationUserConsentScopeRoutes<T extends ManagementAp
assignApplicationUserConsentScopes, assignApplicationUserConsentScopes,
getApplicationUserConsentOrganizationScopes, getApplicationUserConsentOrganizationScopes,
getApplicationUserConsentResourceScopes, getApplicationUserConsentResourceScopes,
getApplicationUserConsentOrganizationResourceScopes,
getApplicationUserConsentScopes, getApplicationUserConsentScopes,
deleteApplicationUserConsentScopesByTypeAndScopeId, deleteApplicationUserConsentScopesByTypeAndScopeId,
}, },
@ -40,6 +42,7 @@ export default function applicationUserConsentScopeRoutes<T extends ManagementAp
body: object({ body: object({
organizationScopes: string().array().optional(), organizationScopes: string().array().optional(),
resourceScopes: string().array().optional(), resourceScopes: string().array().optional(),
organizationResourceScopes: string().array().optional(),
userScopes: nativeEnum(UserScope).array().optional(), userScopes: nativeEnum(UserScope).array().optional(),
}), }),
status: [201, 404, 422], status: [201, 404, 422],
@ -50,11 +53,15 @@ export default function applicationUserConsentScopeRoutes<T extends ManagementAp
body, body,
} = ctx.guard; } = ctx.guard;
// TODO @wangsijie: Remove this when feature is enabled in production
const { organizationResourceScopes, ...rest } = body;
const theBody = EnvSet.values.isDevFeaturesEnabled ? body : rest;
await validateThirdPartyApplicationById(applicationId); await validateThirdPartyApplicationById(applicationId);
await validateApplicationUserConsentScopes(body, tenantId); await validateApplicationUserConsentScopes(theBody, tenantId);
await assignApplicationUserConsentScopes(applicationId, body); await assignApplicationUserConsentScopes(applicationId, theBody);
ctx.status = 201; ctx.status = 201;
@ -68,7 +75,9 @@ export default function applicationUserConsentScopeRoutes<T extends ManagementAp
params: object({ params: object({
applicationId: string(), applicationId: string(),
}), }),
response: applicationUserConsentScopesResponseGuard, response: EnvSet.values.isDevFeaturesEnabled
? applicationUserConsentScopesResponseGuard
: applicationUserConsentScopesResponseGuard.omit({ organizationResourceScopes: true }),
status: [200, 404], status: [200, 404],
}), }),
async (ctx, next) => { async (ctx, next) => {
@ -77,17 +86,26 @@ export default function applicationUserConsentScopeRoutes<T extends ManagementAp
await findApplicationById(applicationId); await findApplicationById(applicationId);
// Note: The following queries will return full data schema, we rely on the response guard to filter out the fields we don't need. // Note: The following queries will return full data schema, we rely on the response guard to filter out the fields we don't need.
const [organizationScopes, resourceScopes, userScopes] = await Promise.all([ const [organizationScopes, resourceScopes, organizationResourceScopes, userScopes] =
getApplicationUserConsentOrganizationScopes(applicationId), await Promise.all([
getApplicationUserConsentResourceScopes(applicationId), getApplicationUserConsentOrganizationScopes(applicationId),
getApplicationUserConsentScopes(applicationId), getApplicationUserConsentResourceScopes(applicationId),
]); getApplicationUserConsentOrganizationResourceScopes(applicationId),
getApplicationUserConsentScopes(applicationId),
]);
ctx.body = { ctx.body = EnvSet.values.isDevFeaturesEnabled
organizationScopes, ? {
resourceScopes, organizationScopes,
userScopes, resourceScopes,
}; organizationResourceScopes,
userScopes,
}
: {
organizationScopes,
resourceScopes,
userScopes,
};
return next(); return next();
} }

View file

@ -11,6 +11,7 @@ export const assignUserConsentScopes = async (
payload: { payload: {
organizationScopes?: string[]; organizationScopes?: string[];
resourceScopes?: string[]; resourceScopes?: string[];
organizationResourceScopes?: string[];
userScopes?: UserScope[]; userScopes?: UserScope[];
} }
) => authedAdminApi.post(`applications/${applicationId}/user-consent-scopes`, { json: payload }); ) => authedAdminApi.post(`applications/${applicationId}/user-consent-scopes`, { json: payload });

View file

@ -16,6 +16,7 @@ describe('assign user consent scopes to application', () => {
const applicationIds = new Map<string, string>(); const applicationIds = new Map<string, string>();
const organizationScopes = new Map<string, string>(); const organizationScopes = new Map<string, string>();
const resourceScopes = new Map<string, string>(); const resourceScopes = new Map<string, string>();
const organizationResourceScopes = new Map<string, string>();
const resourceIds = new Set<string>(); const resourceIds = new Set<string>();
const organizationScopeApi = new OrganizationScopeApi(); const organizationScopeApi = new OrganizationScopeApi();
@ -52,6 +53,12 @@ describe('assign user consent scopes to application', () => {
resourceScopes.set('resourceScope1', resourceScope1.id); resourceScopes.set('resourceScope1', resourceScope1.id);
resourceScopes.set('resourceScope2', resourceScope2.id); resourceScopes.set('resourceScope2', resourceScope2.id);
const resourceScope3 = await createScope(resource.id);
const resourceScope4 = await createScope(resource.id);
organizationResourceScopes.set('resourceScope1', resourceScope3.id);
organizationResourceScopes.set('resourceScope2', resourceScope4.id);
}); });
afterAll(async () => { afterAll(async () => {
@ -75,6 +82,7 @@ describe('assign user consent scopes to application', () => {
assignUserConsentScopes(applicationIds.get('firstPartyApp')!, { assignUserConsentScopes(applicationIds.get('firstPartyApp')!, {
organizationScopes: Array.from(organizationScopes.values()), organizationScopes: Array.from(organizationScopes.values()),
resourceScopes: Array.from(resourceScopes.values()), resourceScopes: Array.from(resourceScopes.values()),
organizationResourceScopes: Array.from(organizationResourceScopes.values()),
}), }),
{ {
code: 'application.third_party_application_only', code: 'application.third_party_application_only',
@ -107,11 +115,24 @@ describe('assign user consent scopes to application', () => {
); );
}); });
it('should throw error when trying to assign a non-existing organization resource scope', async () => {
await expectRejects(
assignUserConsentScopes(applicationIds.get('thirdPartyApp')!, {
organizationResourceScopes: ['non-existing-resource-scope'],
}),
{
code: 'application.user_consent_scopes_not_found',
status: 422,
}
);
});
it('should assign scopes to third-party application successfully', async () => { it('should assign scopes to third-party application successfully', async () => {
await expect( await expect(
assignUserConsentScopes(applicationIds.get('thirdPartyApp')!, { assignUserConsentScopes(applicationIds.get('thirdPartyApp')!, {
organizationScopes: Array.from(organizationScopes.values()), organizationScopes: Array.from(organizationScopes.values()),
resourceScopes: Array.from(resourceScopes.values()), resourceScopes: Array.from(resourceScopes.values()),
organizationResourceScopes: Array.from(organizationResourceScopes.values()),
userScopes: [UserScope.Profile, UserScope.Email, UserScope.OrganizationRoles], userScopes: [UserScope.Profile, UserScope.Email, UserScope.OrganizationRoles],
}) })
).resolves.not.toThrow(); ).resolves.not.toThrow();
@ -122,6 +143,7 @@ describe('assign user consent scopes to application', () => {
assignUserConsentScopes(applicationIds.get('thirdPartyApp')!, { assignUserConsentScopes(applicationIds.get('thirdPartyApp')!, {
organizationScopes: [organizationScopes.get('organizationScope1')!], organizationScopes: [organizationScopes.get('organizationScope1')!],
resourceScopes: [resourceScopes.get('resourceScope1')!], resourceScopes: [resourceScopes.get('resourceScope1')!],
organizationResourceScopes: [organizationResourceScopes.get('resourceScope1')!],
userScopes: [UserScope.Profile], userScopes: [UserScope.Profile],
}) })
).resolves.not.toThrow(); ).resolves.not.toThrow();
@ -154,6 +176,18 @@ describe('assign user consent scopes to application', () => {
).toBeTruthy(); ).toBeTruthy();
} }
expect(result.organizationResourceScopes.length).toBe(1);
expect(result.organizationResourceScopes[0]!.resource.id).toBe(Array.from(resourceIds)[0]);
expect(result.organizationResourceScopes[0]!.scopes.length).toBe(
organizationResourceScopes.size
);
for (const resourceScopeId of organizationResourceScopes.values()) {
expect(
result.organizationResourceScopes[0]!.scopes.some(({ id }) => id === resourceScopeId)
).toBeTruthy();
}
expect(result.userScopes.length).toBe(3); expect(result.userScopes.length).toBe(3);
for (const userScope of [UserScope.Profile, UserScope.Email, UserScope.OrganizationRoles]) { for (const userScope of [UserScope.Profile, UserScope.Email, UserScope.OrganizationRoles]) {
@ -170,6 +204,7 @@ describe('assign user consent scopes to application', () => {
expect(result.organizationScopes.length).toBe(0); expect(result.organizationScopes.length).toBe(0);
expect(result.resourceScopes.length).toBe(0); expect(result.resourceScopes.length).toBe(0);
expect(result.organizationResourceScopes.length).toBe(0);
expect(result.userScopes.length).toBe(0); expect(result.userScopes.length).toBe(0);
await deleteApplication(newApp.id); await deleteApplication(newApp.id);
@ -214,6 +249,18 @@ describe('assign user consent scopes to application', () => {
} }
); );
await expectRejects(
deleteUserConsentScopes(
applicationIds.get('thirdPartyApp')!,
ApplicationUserConsentScopeType.OrganizationResourceScopes,
'non-existing-resource-scope'
),
{
code: 'entity.not_found',
status: 404,
}
);
await expectRejects( await expectRejects(
deleteUserConsentScopes( deleteUserConsentScopes(
applicationIds.get('thirdPartyApp')!, applicationIds.get('thirdPartyApp')!,
@ -232,6 +279,7 @@ describe('assign user consent scopes to application', () => {
assignUserConsentScopes(applicationIds.get('thirdPartyApp')!, { assignUserConsentScopes(applicationIds.get('thirdPartyApp')!, {
organizationScopes: Array.from(organizationScopes.values()), organizationScopes: Array.from(organizationScopes.values()),
resourceScopes: Array.from(resourceScopes.values()), resourceScopes: Array.from(resourceScopes.values()),
organizationResourceScopes: Array.from(organizationResourceScopes.values()),
userScopes: [UserScope.Profile, UserScope.Email, UserScope.OrganizationRoles], userScopes: [UserScope.Profile, UserScope.Email, UserScope.OrganizationRoles],
}) })
).resolves.not.toThrow(); ).resolves.not.toThrow();
@ -252,6 +300,14 @@ describe('assign user consent scopes to application', () => {
) )
).resolves.not.toThrow(); ).resolves.not.toThrow();
await expect(
deleteUserConsentScopes(
applicationIds.get('thirdPartyApp')!,
ApplicationUserConsentScopeType.OrganizationResourceScopes,
organizationResourceScopes.get('resourceScope1')!
)
).resolves.not.toThrow();
await expect( await expect(
deleteUserConsentScopes( deleteUserConsentScopes(
applicationIds.get('thirdPartyApp')!, applicationIds.get('thirdPartyApp')!,
@ -274,6 +330,12 @@ describe('assign user consent scopes to application', () => {
) )
).toBeUndefined(); ).toBeUndefined();
expect(
result.organizationResourceScopes[0]!.scopes.find(
({ id }) => id === organizationResourceScopes.get('resourceScope1')!
)
).toBeUndefined();
expect(result.userScopes.includes(UserScope.OrganizationRoles)).toBeFalsy(); expect(result.userScopes.includes(UserScope.OrganizationRoles)).toBeFalsy();
}); });
}); });

View file

@ -40,22 +40,26 @@ export const applicationPatchGuard = applicationCreateGuard.partial().omit({
isThirdParty: true, isThirdParty: true,
}); });
const resourceScopesGuard = z.array(
z.object({
resource: Resources.guard.pick({ id: true, name: true, indicator: true }),
scopes: z.array(Scopes.guard.pick({ id: true, name: true, description: true })),
})
);
export const applicationUserConsentScopesResponseGuard = z.object({ export const applicationUserConsentScopesResponseGuard = z.object({
organizationScopes: z.array( organizationScopes: z.array(
OrganizationScopes.guard.pick({ id: true, name: true, description: true }) OrganizationScopes.guard.pick({ id: true, name: true, description: true })
), ),
resourceScopes: z.array( resourceScopes: resourceScopesGuard,
z.object({ organizationResourceScopes: resourceScopesGuard,
resource: Resources.guard.pick({ id: true, name: true, indicator: true }),
scopes: z.array(Scopes.guard.pick({ id: true, name: true, description: true })),
})
),
userScopes: z.array(z.nativeEnum(UserScope)), userScopes: z.array(z.nativeEnum(UserScope)),
}); });
export enum ApplicationUserConsentScopeType { export enum ApplicationUserConsentScopeType {
OrganizationScopes = 'organization-scopes', OrganizationScopes = 'organization-scopes',
ResourceScopes = 'resource-scopes', ResourceScopes = 'resource-scopes',
OrganizationResourceScopes = 'organization-resource-scopes',
UserScopes = 'user-scopes', UserScopes = 'user-scopes',
} }