Fix role synchronisation (#19469)

As title
solves
https://discord.com/channels/1130383047699738754/1491167098398052503
This commit is contained in:
martmull
2026-04-09 11:36:16 +02:00
committed by GitHub
parent 5edc034f8b
commit 5eaabe95e7
18 changed files with 282 additions and 170 deletions
@@ -0,0 +1,59 @@
import { CoreApiClient } from 'twenty-client-sdk/core';
import { definePostInstallLogicFunction } from 'twenty-sdk';
const POST_CARDS_TO_SEED = [
{
name: 'Greetings from Paris',
content:
'Wish you were here! The Eiffel Tower looks even better in person. - Alex',
},
{
name: 'Hello from Tokyo',
content:
'The cherry blossoms are amazing this time of year. See you soon! - Sam',
},
];
const handler = async (): Promise<{
message: string;
createdIds: string[];
}> => {
console.log('Seeding 2 post cards...');
const client = new CoreApiClient();
const createdIds: string[] = [];
for (const postCard of POST_CARDS_TO_SEED) {
const { createPostCard } = await client.mutation({
createPostCard: {
__args: {
data: {
name: postCard.name,
content: postCard.content,
},
},
id: true,
},
});
if (!createPostCard?.id) {
throw new Error(`Failed to create post card "${postCard.name}"`);
}
createdIds.push(createPostCard.id);
}
console.log('Seeding complete!');
return {
message: `Seeded ${createdIds.length} post cards`,
createdIds,
};
};
export default definePostInstallLogicFunction({
universalIdentifier: '9f3d8c21-b471-4a82-8e5c-6f3a7b8c9d01',
name: 'seed-post-cards',
description: 'Seeds the workspace with 2 sample post card records.',
timeoutSeconds: 10,
handler,
});
@@ -33,7 +33,7 @@ export default defineRole({
objectUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER,
fieldUniversalIdentifier: CONTENT_FIELD_UNIVERSAL_IDENTIFIER,
canReadFieldValue: false,
canUpdateFieldValue: false,
canUpdateFieldValue: true,
},
],
permissionFlags: [PermissionFlag.APPLICATIONS],
@@ -153,12 +153,14 @@ const buildSyntheticRole = (
canReadFieldValue: permission.canReadFieldValue,
canUpdateFieldValue: permission.canUpdateFieldValue,
})),
permissionFlags: (defaultRole.permissionFlags ?? []).map((flag) => ({
__typename: 'PermissionFlag' as const,
id: uuidv4(),
roleId: defaultRole.universalIdentifier,
flag: flag as PermissionFlagType,
})),
permissionFlags: (defaultRole.permissionFlags ?? []).map(
(permissionFlag) => ({
__typename: 'PermissionFlag' as const,
id: uuidv4(),
roleId: defaultRole.universalIdentifier,
flag: permissionFlag.flag,
}),
),
});
const buildFieldMetadataItemFromMarketplaceField = (
@@ -363,6 +363,9 @@ export const EXPECTED_MANIFEST: Manifest = {
canBeAssignedToAgents: false,
canBeAssignedToUsers: true,
canBeAssignedToApiKeys: false,
fieldPermissions: [],
objectPermissions: [],
permissionFlags: [],
},
],
};
@@ -1499,6 +1499,9 @@ export const EXPECTED_MANIFEST: Manifest = {
description: 'A simple root-level role',
label: 'Root role',
universalIdentifier: 'c0c1c2c3-c4c5-4000-8000-000000000001',
fieldPermissions: [],
objectPermissions: [],
permissionFlags: [],
},
{
canBeAssignedToAgents: false,
@@ -1512,6 +1515,7 @@ export const EXPECTED_MANIFEST: Manifest = {
description: 'Default role for function Twenty client',
fieldPermissions: [
{
universalIdentifier: 'dbc86ced-bd2c-5874-93f1-1f72c5111991',
canReadFieldValue: false,
canUpdateFieldValue: false,
fieldUniversalIdentifier: '58a0a314-d7ea-4865-9850-7fb84e72f30b',
@@ -1521,6 +1525,7 @@ export const EXPECTED_MANIFEST: Manifest = {
label: 'Default function role',
objectPermissions: [
{
universalIdentifier: '99c7c326-04ca-5c8b-ad11-da6c5b819813',
canDestroyObjectRecords: false,
canReadObjectRecords: true,
canSoftDeleteObjectRecords: false,
@@ -1528,7 +1533,12 @@ export const EXPECTED_MANIFEST: Manifest = {
objectUniversalIdentifier: '54b589ca-eeed-4950-a176-358418b85c05',
},
],
permissionFlags: [PermissionFlagType.APPLICATIONS],
permissionFlags: [
{
universalIdentifier: '01d7865a-7700-5d49-b2aa-62623c2cbac7',
flag: PermissionFlagType.APPLICATIONS,
},
],
universalIdentifier: 'b648f87b-1d26-4961-b974-0908fd991061',
},
],
@@ -38,6 +38,8 @@ import {
import { getInputSchemaFromSourceCode } from 'twenty-shared/logic-function';
import { assertUnreachable } from 'twenty-shared/utils';
import { addMissingFieldOptionIds } from '@/cli/utilities/build/manifest/utils/add-missing-field-option-ids';
import { fromRoleConfigToRoleManifest } from '@/cli/utilities/build/manifest/utils/from-role-config-to-role-manifest';
import { type RoleConfig } from '@/sdk/roles/role-config';
const loadSources = async (appPath: string): Promise<string[]> => {
return await glob(['**/*.ts', '**/*.tsx'], {
@@ -170,11 +172,12 @@ export const buildManifest = async (
break;
}
case ManifestEntityKey.Roles: {
const extract = await extractManifestFromFile<RoleManifest>({
const extract = await extractManifestFromFile<RoleConfig>({
appPath,
filePath,
});
roles.push(extract.config);
const roleConfig = fromRoleConfigToRoleManifest(extract.config);
roles.push(roleConfig);
errors.push(...extract.errors);
rolesFilePaths.push(relativePath);
break;
@@ -0,0 +1,41 @@
import { type RoleConfig } from '@/sdk/roles/role-config';
import { type RoleManifest } from 'twenty-shared/application';
import { v5 as uuidv5 } from 'uuid';
const ROLE_UNIVERSAL_IDENTIFIER_NAMESPACE =
'b403ec59-4d80-4f22-85e6-717a192dc9cb';
export const fromRoleConfigToRoleManifest = (
roleConfig: RoleConfig,
): RoleManifest => {
return {
...roleConfig,
objectPermissions: (roleConfig.objectPermissions ?? []).map(
(objectPermission) => ({
...objectPermission,
universalIdentifier: uuidv5(
`${roleConfig.universalIdentifier}:${objectPermission.objectUniversalIdentifier}`,
ROLE_UNIVERSAL_IDENTIFIER_NAMESPACE,
),
}),
),
fieldPermissions: (roleConfig.fieldPermissions ?? []).map(
(fieldPermission) => ({
...fieldPermission,
universalIdentifier: uuidv5(
`${roleConfig.universalIdentifier}:${fieldPermission.objectUniversalIdentifier}:${fieldPermission.fieldUniversalIdentifier}`,
ROLE_UNIVERSAL_IDENTIFIER_NAMESPACE,
),
}),
),
permissionFlags: (roleConfig.permissionFlags ?? []).map(
(permissionFlag) => ({
universalIdentifier: uuidv5(
`${roleConfig.universalIdentifier}:${permissionFlag}`,
ROLE_UNIVERSAL_IDENTIFIER_NAMESPACE,
),
flag: permissionFlag,
}),
),
};
};
@@ -4,10 +4,10 @@ import { type LogicFunctionConfig } from '@/sdk/logic-functions/logic-function-c
import { type ObjectConfig } from '@/sdk/objects/object-config';
import { type PageLayoutConfig } from '@/sdk/page-layouts/page-layout-config';
import { type ViewConfig } from '@/sdk/views/view-config';
import { type RoleConfig } from '@/sdk/roles/role-config';
import {
type FieldManifest,
type NavigationMenuItemManifest,
type RoleManifest,
type SkillManifest,
} from 'twenty-shared/application';
@@ -23,7 +23,7 @@ export type DefinableEntity =
| FieldManifest
| FrontComponentConfig
| LogicFunctionConfig
| RoleManifest
| RoleConfig
| SkillManifest
| ViewConfig
| NavigationMenuItemManifest
@@ -1,8 +1,8 @@
import { createValidationResult } from '@/sdk/common/utils/create-validation-result';
import { type RoleManifest } from 'twenty-shared/application';
import { type DefineEntity } from '@/sdk/common/types/define-entity.type';
import { type RoleConfig } from '@/sdk/roles/role-config';
export const defineRole: DefineEntity<RoleManifest> = (config) => {
export const defineRole: DefineEntity<RoleConfig> = (config) => {
const errors = [];
if (!config.universalIdentifier) {
@@ -0,0 +1,15 @@
import type {
FieldPermissionManifest,
ObjectPermissionManifest,
RoleManifest,
} from 'twenty-shared/application';
import { type PermissionFlagType } from 'twenty-shared/constants';
export type RoleConfig = Omit<
RoleManifest,
'objectPermissions' | 'fieldPermissions' | 'permissionFlags'
> & {
objectPermissions?: Omit<ObjectPermissionManifest, 'universalIdentifier'>[];
fieldPermissions?: Omit<FieldPermissionManifest, 'universalIdentifier'>[];
permissionFlags?: PermissionFlagType[];
};
@@ -1,6 +1,6 @@
import { Injectable, Logger } from '@nestjs/common';
import { type Manifest, type RoleManifest } from 'twenty-shared/application';
import { type Manifest } from 'twenty-shared/application';
import { ALL_METADATA_NAME } from 'twenty-shared/metadata';
import { isDefined } from 'twenty-shared/utils';
@@ -15,9 +15,6 @@ import { computeApplicationManifestAllUniversalFlatEntityMaps } from 'src/engine
import { getApplicationSubAllFlatEntityMaps } from 'src/engine/core-modules/application/application-manifest/utils/get-application-sub-all-flat-entity-maps.util';
import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util';
import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util';
import { FieldPermissionService } from 'src/engine/metadata-modules/object-permission/field-permission/field-permission.service';
import { ObjectPermissionService } from 'src/engine/metadata-modules/object-permission/object-permission.service';
import { PermissionFlagService } from 'src/engine/metadata-modules/permission-flag/permission-flag.service';
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications';
import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception';
@@ -34,9 +31,6 @@ export class ApplicationManifestMigrationService {
private readonly workspaceCacheService: WorkspaceCacheService,
private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService,
private readonly applicationService: ApplicationService,
private readonly objectPermissionService: ObjectPermissionService,
private readonly fieldPermissionService: FieldPermissionService,
private readonly permissionFlagService: PermissionFlagService,
) {}
async syncMetadataFromManifest({
@@ -119,7 +113,7 @@ export class ApplicationManifestMigrationService {
`Metadata migration completed for application ${ownerFlatApplication.universalIdentifier}`,
);
await this.syncRolePermissionsAndDefaultRole({
await this.syncDefaultRoleAndSettingsCustomTab({
manifest,
workspaceId,
ownerFlatApplication,
@@ -131,13 +125,7 @@ export class ApplicationManifestMigrationService {
};
}
/**
* @deprecated should be remove once below issues are resolved:
* - [objectPermission](https://github.com/twentyhq/core-team-issues/issues/2223)
* - [fieldPermission](https://github.com/twentyhq/core-team-issues/issues/2224)
* - [permissionFlag](https://github.com/twentyhq/core-team-issues/issues/2225)
*/
private async syncRolePermissionsAndDefaultRole({
private async syncDefaultRoleAndSettingsCustomTab({
manifest,
workspaceId,
ownerFlatApplication,
@@ -148,13 +136,9 @@ export class ApplicationManifestMigrationService {
}) {
const {
flatRoleMaps: refreshedFlatRoleMaps,
flatObjectMetadataMaps: refreshedFlatObjectMetadataMaps,
flatFieldMetadataMaps: refreshedFlatFieldMetadataMaps,
flatFrontComponentMaps: refreshedFlatFrontComponentMaps,
} = await this.workspaceCacheService.getOrRecompute(workspaceId, [
'flatRoleMaps',
'flatObjectMetadataMaps',
'flatFieldMetadataMaps',
'flatFrontComponentMaps',
]);
@@ -173,14 +157,6 @@ export class ApplicationManifestMigrationService {
);
}
await this.syncApplicationRolePermissions({
role,
workspaceId,
roleId: flatRole.id,
refreshedFlatObjectMetadataMaps,
refreshedFlatFieldMetadataMaps,
});
if (
role.universalIdentifier ===
manifest.application.defaultRoleUniversalIdentifier
@@ -216,126 +192,4 @@ export class ApplicationManifestMigrationService {
...(isDefined(defaultRoleId) ? { defaultRoleId } : {}),
});
}
private async syncApplicationRolePermissions({
role,
workspaceId,
roleId,
refreshedFlatObjectMetadataMaps,
refreshedFlatFieldMetadataMaps,
}: {
role: RoleManifest;
workspaceId: string;
roleId: string;
refreshedFlatObjectMetadataMaps: Awaited<
ReturnType<WorkspaceCacheService['getOrRecompute']>
>['flatObjectMetadataMaps'];
refreshedFlatFieldMetadataMaps: Awaited<
ReturnType<WorkspaceCacheService['getOrRecompute']>
>['flatFieldMetadataMaps'];
}) {
if (
(role.objectPermissions ?? []).length > 0 ||
(role.fieldPermissions ?? []).length > 0
) {
const formattedObjectPermissions = role.objectPermissions
?.map((permission) => {
const flatObjectMetadata = findFlatEntityByUniversalIdentifier({
flatEntityMaps: refreshedFlatObjectMetadataMaps,
universalIdentifier: permission.objectUniversalIdentifier,
});
if (!isDefined(flatObjectMetadata)) {
throw new ApplicationException(
`Failed to find object with universalIdentifier ${permission.objectUniversalIdentifier}`,
ApplicationExceptionCode.OBJECT_NOT_FOUND,
);
}
return {
...permission,
objectMetadataId: flatObjectMetadata.id,
};
})
.filter(
(
permission,
): permission is typeof permission & { objectMetadataId: string } =>
isDefined(permission.objectMetadataId),
);
if (isDefined(formattedObjectPermissions)) {
await this.objectPermissionService.upsertObjectPermissions({
workspaceId,
input: {
roleId,
objectPermissions: formattedObjectPermissions,
},
});
}
const formattedFieldPermissions = role.fieldPermissions
?.map((permission) => {
const flatObjectMetadata = findFlatEntityByUniversalIdentifier({
flatEntityMaps: refreshedFlatObjectMetadataMaps,
universalIdentifier: permission.objectUniversalIdentifier,
});
if (!isDefined(flatObjectMetadata)) {
throw new ApplicationException(
`Failed to find object with universalIdentifier ${permission.objectUniversalIdentifier}`,
ApplicationExceptionCode.OBJECT_NOT_FOUND,
);
}
const flatFieldMetadata = findFlatEntityByUniversalIdentifier({
flatEntityMaps: refreshedFlatFieldMetadataMaps,
universalIdentifier: permission.fieldUniversalIdentifier,
});
if (!isDefined(flatFieldMetadata)) {
throw new ApplicationException(
`Failed to find field with universalIdentifier ${permission.fieldUniversalIdentifier}`,
ApplicationExceptionCode.FIELD_NOT_FOUND,
);
}
return {
...permission,
objectMetadataId: flatObjectMetadata.id,
fieldMetadataId: flatFieldMetadata.id,
};
})
.filter(
(
permission,
): permission is typeof permission & {
objectMetadataId: string;
fieldMetadataId: string;
} =>
isDefined(permission.objectMetadataId) &&
isDefined(permission.fieldMetadataId),
);
if (isDefined(formattedFieldPermissions)) {
await this.fieldPermissionService.upsertFieldPermissions({
workspaceId,
input: {
roleId,
fieldPermissions: formattedFieldPermissions,
},
});
}
}
if (isDefined(role.permissionFlags) && role.permissionFlags.length > 0) {
await this.permissionFlagService.upsertPermissionFlags({
workspaceId,
input: {
roleId,
permissionFlagKeys: role.permissionFlags,
},
});
}
}
}
@@ -7,8 +7,6 @@ import { ApplicationSyncService } from 'src/engine/core-modules/application/appl
import { ApplicationVariableEntityModule } from 'src/engine/core-modules/application/application-variable/application-variable.module';
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
import { FileStorageModule } from 'src/engine/core-modules/file-storage/file-storage.module';
import { ObjectPermissionModule } from 'src/engine/metadata-modules/object-permission/object-permission.module';
import { PermissionFlagModule } from 'src/engine/metadata-modules/permission-flag/permission-flag.module';
import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module';
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
import { WorkspaceMigrationGraphqlApiExceptionInterceptor } from 'src/engine/workspace-manager/workspace-migration/interceptors/workspace-migration-graphql-api-exception.interceptor';
@@ -21,8 +19,6 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace
ApplicationVariableEntityModule,
FeatureFlagModule,
FileStorageModule,
ObjectPermissionModule,
PermissionFlagModule,
PermissionsModule,
WorkspaceCacheModule,
WorkspaceMigrationModule,
@@ -0,0 +1,28 @@
import { type FieldPermissionManifest } from 'twenty-shared/application';
import { type UniversalFlatFieldPermission } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-permission.type';
export const fromFieldPermissionManifestToUniversalFlatFieldPermission = ({
fieldPermissionManifest,
roleUniversalIdentifier,
applicationUniversalIdentifier,
now,
}: {
fieldPermissionManifest: FieldPermissionManifest;
roleUniversalIdentifier: string;
applicationUniversalIdentifier: string;
now: string;
}): UniversalFlatFieldPermission => {
return {
universalIdentifier: fieldPermissionManifest.universalIdentifier,
applicationUniversalIdentifier,
roleUniversalIdentifier,
objectMetadataUniversalIdentifier:
fieldPermissionManifest.objectUniversalIdentifier,
fieldMetadataUniversalIdentifier:
fieldPermissionManifest.fieldUniversalIdentifier,
canReadFieldValue: fieldPermissionManifest.canReadFieldValue ?? null,
canUpdateFieldValue: fieldPermissionManifest.canUpdateFieldValue ?? null,
createdAt: now,
updatedAt: now,
};
};
@@ -0,0 +1,29 @@
import { type ObjectPermissionManifest } from 'twenty-shared/application';
import { type UniversalFlatObjectPermission } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-object-permission.type';
export const fromObjectPermissionManifestToUniversalFlatObjectPermission = ({
objectPermissionManifest,
roleUniversalIdentifier,
applicationUniversalIdentifier,
now,
}: {
objectPermissionManifest: ObjectPermissionManifest;
roleUniversalIdentifier: string;
applicationUniversalIdentifier: string;
now: string;
}): UniversalFlatObjectPermission => {
return {
universalIdentifier: objectPermissionManifest.universalIdentifier,
applicationUniversalIdentifier,
roleUniversalIdentifier,
objectMetadataUniversalIdentifier:
objectPermissionManifest.objectUniversalIdentifier,
canReadObjectRecords: objectPermissionManifest.canReadObjectRecords,
canUpdateObjectRecords: objectPermissionManifest.canUpdateObjectRecords,
canSoftDeleteObjectRecords:
objectPermissionManifest.canSoftDeleteObjectRecords,
canDestroyObjectRecords: objectPermissionManifest.canDestroyObjectRecords,
createdAt: now,
updatedAt: now,
};
};
@@ -0,0 +1,23 @@
import { type UniversalFlatPermissionFlag } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-permission-flag.type';
import { PermissionFlagManifest } from 'twenty-shared/application';
export const fromPermissionFlagToUniversalFlatPermissionFlag = ({
permissionFlag,
roleUniversalIdentifier,
applicationUniversalIdentifier,
now,
}: {
permissionFlag: PermissionFlagManifest;
roleUniversalIdentifier: string;
applicationUniversalIdentifier: string;
now: string;
}): UniversalFlatPermissionFlag => {
return {
universalIdentifier: permissionFlag.universalIdentifier,
applicationUniversalIdentifier,
roleUniversalIdentifier,
flag: permissionFlag.flag,
createdAt: now,
updatedAt: now,
};
};
@@ -4,13 +4,16 @@ import { isDefined } from 'twenty-shared/utils';
import { fromCommandMenuItemManifestToUniversalFlatCommandMenuItem } from 'src/engine/core-modules/application/application-manifest/converters/from-command-menu-item-manifest-to-universal-flat-command-menu-item.util';
import { fromFieldManifestToUniversalFlatFieldMetadata } from 'src/engine/core-modules/application/application-manifest/converters/from-field-manifest-to-universal-flat-field-metadata.util';
import { fromFieldPermissionManifestToUniversalFlatFieldPermission } from 'src/engine/core-modules/application/application-manifest/converters/from-field-permission-manifest-to-universal-flat-field-permission.util';
import { fromFrontComponentManifestToUniversalFlatFrontComponent } from 'src/engine/core-modules/application/application-manifest/converters/from-front-component-manifest-to-universal-flat-front-component.util';
import { fromLogicFunctionManifestToUniversalFlatLogicFunction } from 'src/engine/core-modules/application/application-manifest/converters/from-logic-function-manifest-to-universal-flat-logic-function.util';
import { fromNavigationMenuItemManifestToUniversalFlatNavigationMenuItem } from 'src/engine/core-modules/application/application-manifest/converters/from-navigation-menu-item-manifest-to-universal-flat-navigation-menu-item.util';
import { fromObjectManifestToUniversalFlatObjectMetadata } from 'src/engine/core-modules/application/application-manifest/converters/from-object-manifest-to-universal-flat-object-metadata.util';
import { fromObjectPermissionManifestToUniversalFlatObjectPermission } from 'src/engine/core-modules/application/application-manifest/converters/from-object-permission-manifest-to-universal-flat-object-permission.util';
import { fromPageLayoutManifestToUniversalFlatPageLayout } from 'src/engine/core-modules/application/application-manifest/converters/from-page-layout-manifest-to-universal-flat-page-layout.util';
import { fromPageLayoutTabManifestToUniversalFlatPageLayoutTab } from 'src/engine/core-modules/application/application-manifest/converters/from-page-layout-tab-manifest-to-universal-flat-page-layout-tab.util';
import { fromPageLayoutWidgetManifestToUniversalFlatPageLayoutWidget } from 'src/engine/core-modules/application/application-manifest/converters/from-page-layout-widget-manifest-to-universal-flat-page-layout-widget.util';
import { fromPermissionFlagToUniversalFlatPermissionFlag } from 'src/engine/core-modules/application/application-manifest/converters/from-permission-flag-to-universal-flat-permission-flag.util';
import { fromRoleManifestToUniversalFlatRole } from 'src/engine/core-modules/application/application-manifest/converters/from-role-manifest-to-universal-flat-role.util';
import { fromSkillManifestToUniversalFlatSkill } from 'src/engine/core-modules/application/application-manifest/converters/from-skill-manifest-to-universal-flat-skill.util';
import { computeSearchVectorUniversalSettingsFromObjectManifest } from 'src/engine/core-modules/application/application-manifest/utils/compute-search-vector-universal-settings-from-object-manifest.util';
@@ -144,6 +147,47 @@ export const computeApplicationManifestAllUniversalFlatEntityMaps = ({
}),
universalFlatEntityMapsToMutate: allUniversalFlatEntityMaps.flatRoleMaps,
});
for (const objectPermissionManifest of roleManifest.objectPermissions ??
[]) {
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
universalFlatEntity:
fromObjectPermissionManifestToUniversalFlatObjectPermission({
objectPermissionManifest,
roleUniversalIdentifier: roleManifest.universalIdentifier,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityMapsToMutate:
allUniversalFlatEntityMaps.flatObjectPermissionMaps,
});
}
for (const fieldPermissionManifest of roleManifest.fieldPermissions ?? []) {
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
universalFlatEntity:
fromFieldPermissionManifestToUniversalFlatFieldPermission({
fieldPermissionManifest,
roleUniversalIdentifier: roleManifest.universalIdentifier,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityMapsToMutate:
allUniversalFlatEntityMaps.flatFieldPermissionMaps,
});
}
for (const permissionFlag of roleManifest.permissionFlags ?? []) {
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
universalFlatEntity: fromPermissionFlagToUniversalFlatPermissionFlag({
permissionFlag,
roleUniversalIdentifier: roleManifest.universalIdentifier,
applicationUniversalIdentifier,
now,
}),
universalFlatEntityMapsToMutate:
allUniversalFlatEntityMaps.flatPermissionFlagMaps,
});
}
}
for (const skillManifest of manifest.skills ?? []) {
@@ -47,6 +47,7 @@ export type {
export type {
ObjectPermissionManifest,
FieldPermissionManifest,
PermissionFlagManifest,
RoleManifest,
} from './roleManifestType';
export type { ServerVariables } from './server-variables.type';
@@ -1,7 +1,7 @@
import { type PermissionFlagType } from '@/constants';
import { type SyncableEntityOptions } from '@/application/syncableEntityOptionsType';
export type ObjectPermissionManifest = {
export type ObjectPermissionManifest = SyncableEntityOptions & {
objectUniversalIdentifier: string;
canReadObjectRecords?: boolean;
canUpdateObjectRecords?: boolean;
@@ -9,13 +9,17 @@ export type ObjectPermissionManifest = {
canDestroyObjectRecords?: boolean;
};
export type FieldPermissionManifest = {
export type FieldPermissionManifest = SyncableEntityOptions & {
objectUniversalIdentifier: string;
fieldUniversalIdentifier: string;
canReadFieldValue?: boolean;
canUpdateFieldValue?: boolean;
};
export type PermissionFlagManifest = SyncableEntityOptions & {
flag: PermissionFlagType;
};
export type RoleManifest = SyncableEntityOptions & {
label: string;
description?: string;
@@ -31,5 +35,5 @@ export type RoleManifest = SyncableEntityOptions & {
canBeAssignedToApiKeys?: boolean;
objectPermissions?: ObjectPermissionManifest[];
fieldPermissions?: FieldPermissionManifest[];
permissionFlags?: PermissionFlagType[];
permissionFlags?: PermissionFlagManifest[];
};