[1/3] Rename permissionFlag to rolePermissionFlag + add permissionFlag catalog/backfill (#20481)
Split of #20377. ## Summary This PR separates available permission flags from per-role permission flag grants. Previously, `core.permissionFlag` stored the role assignment directly: `roleId + flag`. This PR renames that legacy grant table to `core.rolePermissionFlag`, then recreates `core.permissionFlag` as the catalog of available permission flags. ## What changed - Rename the existing `core.permissionFlag` grant table to `core.rolePermissionFlag`. - Add the new syncable `core.permissionFlag` catalog entity with key, label, description, icon, permission type, relevance flags, and custom/standard metadata. - Add stable `SystemPermissionFlag` universal identifiers for the built-in `PermissionFlagType` values. - Seed the standard permission flags for every workspace under the Twenty standard application. - Backfill existing role grants: - create missing catalog rows for existing grant keys, - add `rolePermissionFlag.permissionFlagId`, - migrate grants from the old string `flag` column to the new catalog FK, - replace the old `(flag, roleId)` uniqueness with `(permissionFlagId, roleId)`. - Rewire role permission flag caches, permission checks, role DTO mapping, and `upsertPermissionFlags` to resolve through the catalog. - Keep the existing public role permission API shape: product/app surfaces still talk about `permissionFlags` and return `{ id, roleId, flag }`. - Update metadata flat-entity machinery, migration builders, validators, action handlers, snapshots, generated schemas, docs, and app fixtures for the new `permissionFlag` / `rolePermissionFlag` split. ## Behavior after this PR - Existing permission flag grants keep working. - Existing GraphQL role permission flows keep the same public naming. - Standard permission flags are represented as catalog rows. - Permission checks now compare grants through catalog universal identifiers instead of the legacy `flag` column. - Workspace deletion cleanup now verifies both `permissionFlag` and `rolePermissionFlag`. ## What is not in this PR - Public GraphQL CRUD for custom permission flags. - App manifest support for declaring new custom permission flags. - Frontend UI for creating or assigning custom permission flags beyond the existing role permission flow. --------- Co-authored-by: Weiko <corentin@twenty.com>
This commit is contained in:
-23
@@ -1,23 +0,0 @@
|
||||
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,
|
||||
};
|
||||
};
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
import { type PermissionFlagManifest } from 'twenty-shared/application';
|
||||
import { SystemPermissionFlag } from 'twenty-shared/constants';
|
||||
|
||||
import { type UniversalFlatRolePermissionFlag } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-role-permission-flag.type';
|
||||
|
||||
export const fromPermissionFlagToUniversalFlatRolePermissionFlag = ({
|
||||
permissionFlag,
|
||||
roleUniversalIdentifier,
|
||||
applicationUniversalIdentifier,
|
||||
now,
|
||||
}: {
|
||||
permissionFlag: PermissionFlagManifest;
|
||||
roleUniversalIdentifier: string;
|
||||
applicationUniversalIdentifier: string;
|
||||
now: string;
|
||||
}): UniversalFlatRolePermissionFlag => {
|
||||
return {
|
||||
universalIdentifier: permissionFlag.universalIdentifier,
|
||||
applicationUniversalIdentifier,
|
||||
roleUniversalIdentifier,
|
||||
permissionFlagUniversalIdentifier:
|
||||
SystemPermissionFlag[permissionFlag.flag],
|
||||
flag: permissionFlag.flag,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
};
|
||||
};
|
||||
+1
-1
@@ -32,7 +32,7 @@ export const fromRoleManifestToUniversalFlatRole = ({
|
||||
roleTargetUniversalIdentifiers: [],
|
||||
objectPermissionUniversalIdentifiers: [],
|
||||
fieldPermissionUniversalIdentifiers: [],
|
||||
permissionFlagUniversalIdentifiers: [],
|
||||
rolePermissionFlagUniversalIdentifiers: [],
|
||||
rowLevelPermissionPredicateUniversalIdentifiers: [],
|
||||
rowLevelPermissionPredicateGroupUniversalIdentifiers: [],
|
||||
createdAt: now,
|
||||
|
||||
+9
-8
@@ -17,7 +17,7 @@ import { fromObjectPermissionManifestToUniversalFlatObjectPermission } from 'src
|
||||
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 { fromPermissionFlagToUniversalFlatRolePermissionFlag } from 'src/engine/core-modules/application/application-manifest/converters/from-permission-flag-to-universal-flat-role-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';
|
||||
@@ -214,14 +214,15 @@ export const computeApplicationManifestAllUniversalFlatEntityMaps = ({
|
||||
|
||||
for (const permissionFlag of roleManifest.permissionFlags ?? []) {
|
||||
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
|
||||
universalFlatEntity: fromPermissionFlagToUniversalFlatPermissionFlag({
|
||||
permissionFlag,
|
||||
roleUniversalIdentifier: roleManifest.universalIdentifier,
|
||||
applicationUniversalIdentifier,
|
||||
now,
|
||||
}),
|
||||
universalFlatEntity:
|
||||
fromPermissionFlagToUniversalFlatRolePermissionFlag({
|
||||
permissionFlag,
|
||||
roleUniversalIdentifier: roleManifest.universalIdentifier,
|
||||
applicationUniversalIdentifier,
|
||||
now,
|
||||
}),
|
||||
universalFlatEntityMapsToMutate:
|
||||
allUniversalFlatEntityMaps.flatPermissionFlagMaps,
|
||||
allUniversalFlatEntityMaps.flatRolePermissionFlagMaps,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user