Migrate object permission to syncable entity (#18609)

Closes [#2223](https://github.com/twentyhq/core-team-issues/issues/2223)
This commit is contained in:
Abdul Rahman
2026-03-18 22:02:18 +05:30
committed by GitHub
parent 8ccaf635bc
commit 6d4d1a97bc
86 changed files with 2475 additions and 424 deletions
@@ -95,12 +95,14 @@ export const createStandardObjectFlatMetadata = <
targetTableName: 'DEPRECATED',
fieldIds: [],
indexMetadataIds: [],
objectPermissionIds: [],
viewIds: [],
createdAt: now,
updatedAt: now,
id: standardObjectMetadataRelatedEntityIds[nameSingular].id,
applicationUniversalIdentifier: twentyStandardApplicationId,
fieldUniversalIdentifiers: [],
objectPermissionUniversalIdentifiers: [],
viewUniversalIdentifiers: [],
indexMetadataUniversalIdentifiers: [],
labelIdentifierFieldMetadataUniversalIdentifier,
@@ -1,8 +1,8 @@
import { v4 } from 'uuid';
import { type FlatRole } from 'src/engine/metadata-modules/flat-role/types/flat-role.type';
import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications';
import { STANDARD_ROLE } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-role.constant';
import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications';
import { type AllStandardRoleName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-role-name.type';
import { type StandardBuilderArgs } from 'src/engine/workspace-manager/twenty-standard-application/types/metadata-standard-buillder-args.type';
@@ -74,6 +74,7 @@ export const createStandardRoleFlatMetadata = ({
updatedAt: now,
permissionFlagIds: [],
permissionFlagUniversalIdentifiers: [],
objectPermissionUniversalIdentifiers: [],
fieldPermissionIds: [],
objectPermissionIds: [],
roleTargetIds: [],
@@ -168,6 +168,7 @@ export const enrichCreateWorkspaceMigrationActionsWithIds = ({
case 'frontComponent':
case 'viewSort':
case 'permissionFlag':
case 'objectPermission':
case 'webhook': {
if (!isDefined(idByUniversalIdentifier)) {
return action;
@@ -20,6 +20,7 @@ import { WorkspaceMigrationFrontComponentActionsBuilderService } from 'src/engin
import { WorkspaceMigrationIndexActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/index/workspace-migration-index-actions-builder.service';
import { WorkspaceMigrationLogicFunctionActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/logic-function/workspace-migration-logic-function-actions-builder.service';
import { WorkspaceMigrationNavigationMenuItemActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/navigation-menu-item/workspace-migration-navigation-menu-item-actions-builder.service';
import { WorkspaceMigrationObjectPermissionActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/object-permission/workspace-migration-object-permission-actions-builder.service';
import { WorkspaceMigrationObjectActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/object/workspace-migration-object-actions-builder.service';
import { WorkspaceMigrationPageLayoutTabActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/page-layout-tab/workspace-migration-page-layout-tab-actions-builder.service';
import { WorkspaceMigrationPageLayoutWidgetActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/page-layout-widget/workspace-migration-page-layout-widget-actions-builder.service';
@@ -51,6 +52,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
private readonly workspaceMigrationViewGroupActionsBuilderService: WorkspaceMigrationViewGroupActionsBuilderService,
private readonly workspaceMigrationViewFieldGroupActionsBuilderService: WorkspaceMigrationViewFieldGroupActionsBuilderService,
private readonly workspaceMigrationViewSortActionsBuilderService: WorkspaceMigrationViewSortActionsBuilderService,
private readonly workspaceMigrationObjectPermissionActionsBuilderService: WorkspaceMigrationObjectPermissionActionsBuilderService,
private readonly workspaceMigrationPermissionFlagActionsBuilderService: WorkspaceMigrationPermissionFlagActionsBuilderService,
private readonly workspaceMigrationLogicFunctionActionsBuilderService: WorkspaceMigrationLogicFunctionActionsBuilderService,
private readonly workspaceMigrationRoleTargetActionsBuilderService: WorkspaceMigrationRoleTargetActionsBuilderService,
@@ -142,6 +144,7 @@ export class WorkspaceMigrationBuildOrchestratorService {
flatRowLevelPermissionPredicateMaps,
flatRowLevelPermissionPredicateGroupMaps,
flatRoleMaps,
flatObjectPermissionMaps,
flatPermissionFlagMaps,
flatRoleTargetMaps,
flatAgentMaps,
@@ -484,6 +487,34 @@ export class WorkspaceMigrationBuildOrchestratorService {
}
}
if (isDefined(flatObjectPermissionMaps)) {
const {
from: fromFlatObjectPermissionMaps,
to: toFlatObjectPermissionMaps,
} = flatObjectPermissionMaps;
const objectPermissionResult =
await this.workspaceMigrationObjectPermissionActionsBuilderService.validateAndBuild(
{
additionalCacheDataMaps,
from: fromFlatObjectPermissionMaps,
to: toFlatObjectPermissionMaps,
buildOptions,
dependencyOptimisticFlatEntityMaps: optimisticAllFlatEntityMaps,
workspaceId,
},
);
if (objectPermissionResult.status === 'fail') {
orchestratorFailureReport.objectPermission.push(
...objectPermissionResult.errors,
);
} else {
orchestratorActionsReport.objectPermission =
objectPermissionResult.actions;
}
}
if (isDefined(flatPermissionFlagMaps)) {
const { from: fromFlatPermissionFlagMaps, to: toFlatPermissionFlagMaps } =
flatPermissionFlagMaps;
@@ -839,6 +870,12 @@ export class WorkspaceMigrationBuildOrchestratorService {
...aggregatedOrchestratorActionsReport.roleTarget.update,
///
// Object permissions
...aggregatedOrchestratorActionsReport.objectPermission.delete,
...aggregatedOrchestratorActionsReport.objectPermission.create,
...aggregatedOrchestratorActionsReport.objectPermission.update,
///
// Permission flags
...aggregatedOrchestratorActionsReport.permissionFlag.delete,
...aggregatedOrchestratorActionsReport.permissionFlag.create,
@@ -19,8 +19,10 @@ exports[`ALL_UNIVERSAL_FLAT_ENTITY_FOREIGN_KEY_AGGREGATOR_PROPERTIES should matc
"objectMetadata": [
"fieldUniversalIdentifiers",
"indexMetadataUniversalIdentifiers",
"objectPermissionUniversalIdentifiers",
"viewUniversalIdentifiers",
],
"objectPermission": [],
"pageLayout": [
"tabUniversalIdentifiers",
],
@@ -31,6 +33,7 @@ exports[`ALL_UNIVERSAL_FLAT_ENTITY_FOREIGN_KEY_AGGREGATOR_PROPERTIES should matc
"permissionFlag": [],
"role": [
"roleTargetUniversalIdentifiers",
"objectPermissionUniversalIdentifiers",
"permissionFlagUniversalIdentifiers",
"rowLevelPermissionPredicateUniversalIdentifiers",
"rowLevelPermissionPredicateGroupUniversalIdentifiers",
@@ -38,6 +38,7 @@ export const ALL_JSONB_PROPERTIES_WITH_SERIALIZED_RELATION_BY_METADATA_NAME = {
commandMenuItem: {},
navigationMenuItem: {},
permissionFlag: {},
objectPermission: {},
frontComponent: {},
} as const satisfies {
[P in AllMetadataName]: Partial<{
@@ -0,0 +1,7 @@
import { type ObjectPermissionEntity } from 'src/engine/metadata-modules/object-permission/object-permission.entity';
import { type UniversalFlatEntityFrom } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-from.type';
export type UniversalFlatObjectPermission = UniversalFlatEntityFrom<
ObjectPermissionEntity,
'objectPermission'
>;
@@ -0,0 +1,24 @@
import { type BaseFlatCreateWorkspaceMigrationAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/base-flat-create-workspace-migration-action.type';
import { type BaseFlatDeleteWorkspaceMigrationAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/base-flat-delete-workspace-migration-action.type';
import { type BaseFlatUpdateWorkspaceMigrationAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/base-flat-update-workspace-migration-action.type';
import { type BaseUniversalCreateWorkspaceMigrationAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/base-universal-create-workspace-migration-action.type';
import { type BaseUniversalDeleteWorkspaceMigrationAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/base-universal-delete-workspace-migration-action.type';
import { type BaseUniversalUpdateWorkspaceMigrationAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/base-universal-update-workspace-migration-action.type';
export type FlatCreateObjectPermissionAction =
BaseFlatCreateWorkspaceMigrationAction<'objectPermission'>;
export type FlatUpdateObjectPermissionAction =
BaseFlatUpdateWorkspaceMigrationAction<'objectPermission'>;
export type FlatDeleteObjectPermissionAction =
BaseFlatDeleteWorkspaceMigrationAction<'objectPermission'>;
export type UniversalCreateObjectPermissionAction =
BaseUniversalCreateWorkspaceMigrationAction<'objectPermission'>;
export type UniversalUpdateObjectPermissionAction =
BaseUniversalUpdateWorkspaceMigrationAction<'objectPermission'>;
export type UniversalDeleteObjectPermissionAction =
BaseUniversalDeleteWorkspaceMigrationAction<'objectPermission'>;
@@ -0,0 +1,121 @@
import { Injectable } from '@nestjs/common';
import { ALL_METADATA_NAME } from 'twenty-shared/metadata';
import { WorkspaceEntityMigrationBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/services/workspace-entity-migration-builder.service';
import { UniversalUpdateObjectPermissionAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/object-permission/types/workspace-migration-object-permission-action.type';
import { FlatObjectPermissionValidatorService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-object-permission-validator.service';
import { UniversalFlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/universal-flat-entity-validation-args.type';
import { UniversalFlatEntityValidationReturnType } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/universal-flat-entity-validation-result.type';
import { FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/universal-flat-entity-update-validation-args.type';
@Injectable()
export class WorkspaceMigrationObjectPermissionActionsBuilderService extends WorkspaceEntityMigrationBuilderService<
typeof ALL_METADATA_NAME.objectPermission
> {
constructor(
private readonly flatObjectPermissionValidatorService: FlatObjectPermissionValidatorService,
) {
super(ALL_METADATA_NAME.objectPermission);
}
protected validateFlatEntityCreation(
args: UniversalFlatEntityValidationArgs<
typeof ALL_METADATA_NAME.objectPermission
>,
): UniversalFlatEntityValidationReturnType<
typeof ALL_METADATA_NAME.objectPermission,
'create'
> {
const validationResult =
this.flatObjectPermissionValidatorService.validateFlatObjectPermissionCreation(
args,
);
if (validationResult.errors.length > 0) {
return {
status: 'fail',
...validationResult,
};
}
const { flatEntityToValidate: flatObjectPermissionToValidate } = args;
return {
status: 'success',
action: {
type: 'create',
metadataName: 'objectPermission',
flatEntity: flatObjectPermissionToValidate,
},
};
}
protected validateFlatEntityDeletion(
args: UniversalFlatEntityValidationArgs<
typeof ALL_METADATA_NAME.objectPermission
>,
): UniversalFlatEntityValidationReturnType<
typeof ALL_METADATA_NAME.objectPermission,
'delete'
> {
const validationResult =
this.flatObjectPermissionValidatorService.validateFlatObjectPermissionDeletion(
args,
);
if (validationResult.errors.length > 0) {
return {
status: 'fail',
...validationResult,
};
}
const { flatEntityToValidate: flatObjectPermissionToValidate } = args;
return {
status: 'success',
action: {
type: 'delete',
metadataName: 'objectPermission',
universalIdentifier: flatObjectPermissionToValidate.universalIdentifier,
},
};
}
protected validateFlatEntityUpdate(
args: FlatEntityUpdateValidationArgs<
typeof ALL_METADATA_NAME.objectPermission
>,
): UniversalFlatEntityValidationReturnType<
typeof ALL_METADATA_NAME.objectPermission,
'update'
> {
const validationResult =
this.flatObjectPermissionValidatorService.validateFlatObjectPermissionUpdate(
args,
);
if (validationResult.errors.length > 0) {
return {
status: 'fail',
...validationResult,
};
}
const { universalIdentifier, flatEntityUpdate } = args;
const updateObjectPermissionAction: UniversalUpdateObjectPermissionAction =
{
type: 'update',
metadataName: 'objectPermission',
universalIdentifier,
update: flatEntityUpdate,
};
return {
status: 'success',
action: updateObjectPermissionAction,
};
}
}
@@ -0,0 +1,252 @@
import { Injectable } from '@nestjs/common';
import { msg, t } from '@lingui/core/macro';
import { ALL_METADATA_NAME } from 'twenty-shared/metadata';
import { isDefined } from 'twenty-shared/utils';
import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util';
import { PermissionsExceptionCode } from 'src/engine/metadata-modules/permissions/permissions.exception';
import { FailedFlatEntityValidation } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/types/failed-flat-entity-validation.type';
import { getEmptyFlatEntityValidationError } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/utils/get-flat-entity-validation-error.util';
import { FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/universal-flat-entity-update-validation-args.type';
import { UniversalFlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/universal-flat-entity-validation-args.type';
@Injectable()
export class FlatObjectPermissionValidatorService {
validateFlatObjectPermissionCreation({
flatEntityToValidate: flatObjectPermissionToValidate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatObjectPermissionMaps: optimisticFlatObjectPermissionMaps,
flatRoleMaps,
flatObjectMetadataMaps,
},
}: UniversalFlatEntityValidationArgs<
typeof ALL_METADATA_NAME.objectPermission
>): FailedFlatEntityValidation<'objectPermission', 'create'> {
const validationResult = getEmptyFlatEntityValidationError({
flatEntityMinimalInformation: {
universalIdentifier: flatObjectPermissionToValidate.universalIdentifier,
roleUniversalIdentifier:
flatObjectPermissionToValidate.roleUniversalIdentifier,
objectMetadataUniversalIdentifier:
flatObjectPermissionToValidate.objectMetadataUniversalIdentifier,
},
metadataName: 'objectPermission',
type: 'create',
});
const existingByUniversalId = findFlatEntityByUniversalIdentifier({
universalIdentifier: flatObjectPermissionToValidate.universalIdentifier,
flatEntityMaps: optimisticFlatObjectPermissionMaps,
});
if (isDefined(existingByUniversalId)) {
validationResult.errors.push({
code: PermissionsExceptionCode.INVALID_SETTING,
message: t`Object permission with universal identifier ${flatObjectPermissionToValidate.universalIdentifier} already exists`,
userFriendlyMessage: msg`Object permission already exists`,
});
}
const referencedRole = findFlatEntityByUniversalIdentifier({
universalIdentifier:
flatObjectPermissionToValidate.roleUniversalIdentifier,
flatEntityMaps: flatRoleMaps,
});
if (!isDefined(referencedRole)) {
validationResult.errors.push({
code: PermissionsExceptionCode.ROLE_NOT_FOUND,
message: t`Role not found`,
userFriendlyMessage: msg`Role not found`,
});
} else if (!referencedRole.isEditable) {
validationResult.errors.push({
code: PermissionsExceptionCode.ROLE_NOT_EDITABLE,
message: t`Role is not editable`,
userFriendlyMessage: msg`This role cannot be modified because it is a system role. Only custom roles can be edited.`,
});
}
const referencedObjectMetadata = findFlatEntityByUniversalIdentifier({
universalIdentifier:
flatObjectPermissionToValidate.objectMetadataUniversalIdentifier,
flatEntityMaps: flatObjectMetadataMaps,
});
if (!isDefined(referencedObjectMetadata)) {
validationResult.errors.push({
code: PermissionsExceptionCode.OBJECT_METADATA_NOT_FOUND,
message: t`Object metadata not found`,
userFriendlyMessage: msg`Object metadata not found`,
});
}
const duplicateForSameRoleAndObject = Object.values(
optimisticFlatObjectPermissionMaps.byUniversalIdentifier,
).filter(
(op) =>
isDefined(op) &&
op.roleUniversalIdentifier ===
flatObjectPermissionToValidate.roleUniversalIdentifier &&
op.objectMetadataUniversalIdentifier ===
flatObjectPermissionToValidate.objectMetadataUniversalIdentifier &&
op.universalIdentifier !==
flatObjectPermissionToValidate.universalIdentifier,
);
if (duplicateForSameRoleAndObject.length > 0) {
validationResult.errors.push({
code: PermissionsExceptionCode.INVALID_SETTING,
message: t`Object permission for this role and object already exists`,
userFriendlyMessage: msg`This object permission is already set for the role`,
});
}
return validationResult;
}
validateFlatObjectPermissionUpdate({
universalIdentifier,
flatEntityUpdate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatObjectPermissionMaps: optimisticFlatObjectPermissionMaps,
flatRoleMaps,
flatObjectMetadataMaps,
},
}: FlatEntityUpdateValidationArgs<
typeof ALL_METADATA_NAME.objectPermission
>): FailedFlatEntityValidation<'objectPermission', 'update'> {
const existingFlatObjectPermission = findFlatEntityByUniversalIdentifier({
universalIdentifier,
flatEntityMaps: optimisticFlatObjectPermissionMaps,
});
const validationResult = getEmptyFlatEntityValidationError({
flatEntityMinimalInformation: {
universalIdentifier,
},
metadataName: 'objectPermission',
type: 'update',
});
if (!isDefined(existingFlatObjectPermission)) {
validationResult.errors.push({
code: PermissionsExceptionCode.OBJECT_PERMISSION_NOT_FOUND,
message: t`Object permission to update not found`,
userFriendlyMessage: msg`Object permission not found`,
});
return validationResult;
}
const updatedFlatObjectPermission = {
...existingFlatObjectPermission,
...flatEntityUpdate,
};
const referencedRole = findFlatEntityByUniversalIdentifier({
universalIdentifier: updatedFlatObjectPermission.roleUniversalIdentifier,
flatEntityMaps: flatRoleMaps,
});
if (!isDefined(referencedRole)) {
validationResult.errors.push({
code: PermissionsExceptionCode.ROLE_NOT_FOUND,
message: t`Role not found`,
userFriendlyMessage: msg`Role not found`,
});
} else if (!referencedRole.isEditable) {
validationResult.errors.push({
code: PermissionsExceptionCode.ROLE_NOT_EDITABLE,
message: t`Role is not editable`,
userFriendlyMessage: msg`This role cannot be modified because it is a system role. Only custom roles can be edited.`,
});
}
if (isDefined(flatEntityUpdate.objectMetadataUniversalIdentifier)) {
const referencedObjectMetadata = findFlatEntityByUniversalIdentifier({
universalIdentifier:
updatedFlatObjectPermission.objectMetadataUniversalIdentifier,
flatEntityMaps: flatObjectMetadataMaps,
});
if (!isDefined(referencedObjectMetadata)) {
validationResult.errors.push({
code: PermissionsExceptionCode.OBJECT_METADATA_NOT_FOUND,
message: t`Object metadata not found`,
userFriendlyMessage: msg`Object metadata not found`,
});
}
}
const duplicateForSameRoleAndObject = Object.values(
optimisticFlatObjectPermissionMaps.byUniversalIdentifier,
).filter(
(op) =>
isDefined(op) &&
op.roleUniversalIdentifier ===
updatedFlatObjectPermission.roleUniversalIdentifier &&
op.objectMetadataUniversalIdentifier ===
updatedFlatObjectPermission.objectMetadataUniversalIdentifier &&
op.universalIdentifier !== universalIdentifier,
);
if (duplicateForSameRoleAndObject.length > 0) {
validationResult.errors.push({
code: PermissionsExceptionCode.INVALID_SETTING,
message: t`Object permission for this role and object already exists`,
userFriendlyMessage: msg`This object permission is already set for the role`,
});
}
return validationResult;
}
validateFlatObjectPermissionDeletion({
flatEntityToValidate: { universalIdentifier },
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatObjectPermissionMaps: optimisticFlatObjectPermissionMaps,
flatRoleMaps,
},
}: UniversalFlatEntityValidationArgs<
typeof ALL_METADATA_NAME.objectPermission
>): FailedFlatEntityValidation<'objectPermission', 'delete'> {
const validationResult = getEmptyFlatEntityValidationError({
flatEntityMinimalInformation: {
universalIdentifier,
},
metadataName: 'objectPermission',
type: 'delete',
});
const existingFlatObjectPermission = findFlatEntityByUniversalIdentifier({
universalIdentifier,
flatEntityMaps: optimisticFlatObjectPermissionMaps,
});
if (!isDefined(existingFlatObjectPermission)) {
validationResult.errors.push({
code: PermissionsExceptionCode.OBJECT_PERMISSION_NOT_FOUND,
message: t`Object permission to delete not found`,
userFriendlyMessage: msg`Object permission not found`,
});
} else {
const referencedRole = findFlatEntityByUniversalIdentifier({
universalIdentifier:
existingFlatObjectPermission.roleUniversalIdentifier,
flatEntityMaps: flatRoleMaps,
});
if (isDefined(referencedRole) && !referencedRole.isEditable) {
validationResult.errors.push({
code: PermissionsExceptionCode.ROLE_NOT_EDITABLE,
message: t`Role is not editable`,
userFriendlyMessage: msg`This role cannot be modified because it is a system role. Only custom roles can be edited.`,
});
}
}
return validationResult;
}
}
@@ -11,6 +11,7 @@ import { FlatIndexValidatorService } from 'src/engine/workspace-manager/workspac
import { FlatLogicFunctionValidatorService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-logic-function-validator.service';
import { FlatNavigationMenuItemValidatorService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-navigation-menu-item-validator.service';
import { FlatObjectMetadataValidatorService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-object-metadata-validator.service';
import { FlatObjectPermissionValidatorService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-object-permission-validator.service';
import { FlatPageLayoutTabValidatorService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-page-layout-tab-validator.service';
import { FlatPageLayoutValidatorService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-page-layout-validator.service';
import { FlatPageLayoutWidgetValidatorService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/validators/services/flat-page-layout-widget-validator.service';
@@ -39,6 +40,7 @@ import { FlatWebhookValidatorService } from 'src/engine/workspace-manager/worksp
FlatViewGroupValidatorService,
FlatViewFieldGroupValidatorService,
FlatViewSortValidatorService,
FlatObjectPermissionValidatorService,
FlatPermissionFlagValidatorService,
FlatIndexValidatorService,
FlatFieldMetadataValidatorService,
@@ -68,6 +70,7 @@ import { FlatWebhookValidatorService } from 'src/engine/workspace-manager/worksp
FlatViewGroupValidatorService,
FlatViewFieldGroupValidatorService,
FlatViewSortValidatorService,
FlatObjectPermissionValidatorService,
FlatPermissionFlagValidatorService,
FlatIndexValidatorService,
FlatFieldMetadataValidatorService,
@@ -9,6 +9,7 @@ import { WorkspaceMigrationFrontComponentActionsBuilderService } from 'src/engin
import { WorkspaceMigrationIndexActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/index/workspace-migration-index-actions-builder.service';
import { WorkspaceMigrationLogicFunctionActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/logic-function/workspace-migration-logic-function-actions-builder.service';
import { WorkspaceMigrationNavigationMenuItemActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/navigation-menu-item/workspace-migration-navigation-menu-item-actions-builder.service';
import { WorkspaceMigrationObjectPermissionActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/object-permission/workspace-migration-object-permission-actions-builder.service';
import { WorkspaceMigrationObjectActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/object/workspace-migration-object-actions-builder.service';
import { WorkspaceMigrationPageLayoutTabActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/page-layout-tab/workspace-migration-page-layout-tab-actions-builder.service';
import { WorkspaceMigrationPageLayoutWidgetActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/page-layout-widget/workspace-migration-page-layout-widget-actions-builder.service';
@@ -41,6 +42,7 @@ import { WorkspaceMigrationBuilderValidatorsModule } from 'src/engine/workspace-
WorkspaceMigrationViewGroupActionsBuilderService,
WorkspaceMigrationViewFieldGroupActionsBuilderService,
WorkspaceMigrationViewSortActionsBuilderService,
WorkspaceMigrationObjectPermissionActionsBuilderService,
WorkspaceMigrationPermissionFlagActionsBuilderService,
WorkspaceMigrationIndexActionsBuilderService,
WorkspaceMigrationLogicFunctionActionsBuilderService,
@@ -69,6 +71,7 @@ import { WorkspaceMigrationBuilderValidatorsModule } from 'src/engine/workspace-
WorkspaceMigrationViewGroupActionsBuilderService,
WorkspaceMigrationViewFieldGroupActionsBuilderService,
WorkspaceMigrationViewSortActionsBuilderService,
WorkspaceMigrationObjectPermissionActionsBuilderService,
WorkspaceMigrationPermissionFlagActionsBuilderService,
WorkspaceMigrationFieldActionsBuilderService,
WorkspaceMigrationLogicFunctionActionsBuilderService,
@@ -0,0 +1,64 @@
import { Injectable } from '@nestjs/common';
import { v4 } from 'uuid';
import {
FlatCreateObjectPermissionAction,
UniversalCreateObjectPermissionAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/object-permission/types/workspace-migration-object-permission-action.type';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/interfaces/workspace-migration-runner-action-handler-service.interface';
import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { resolveUniversalRelationIdentifiersToIds } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-universal-relation-identifiers-to-ids.util';
@Injectable()
export class CreateObjectPermissionActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
'create',
'objectPermission',
) {
override async transpileUniversalActionToFlatAction({
action,
allFlatEntityMaps,
flatApplication,
workspaceId,
}: WorkspaceMigrationActionRunnerArgs<UniversalCreateObjectPermissionAction>): Promise<FlatCreateObjectPermissionAction> {
const { roleId, objectMetadataId } =
resolveUniversalRelationIdentifiersToIds({
flatEntityMaps: allFlatEntityMaps,
metadataName: action.metadataName,
universalForeignKeyValues: action.flatEntity,
});
return {
...action,
flatEntity: {
...action.flatEntity,
roleId,
objectMetadataId,
applicationId: flatApplication.id,
id: action.id ?? v4(),
workspaceId,
},
};
}
async executeForMetadata(
context: WorkspaceMigrationActionRunnerContext<FlatCreateObjectPermissionAction>,
): Promise<void> {
const { flatAction, queryRunner } = context;
const { flatEntity } = flatAction;
await this.insertFlatEntitiesInRepository({
queryRunner,
flatEntities: [flatEntity],
});
}
async executeForWorkspaceSchema(
_context: WorkspaceMigrationActionRunnerContext<FlatCreateObjectPermissionAction>,
): Promise<void> {
return;
}
}
@@ -0,0 +1,50 @@
import { Injectable } from '@nestjs/common';
import { ObjectPermissionEntity } from 'src/engine/metadata-modules/object-permission/object-permission.entity';
import {
FlatDeleteObjectPermissionAction,
UniversalDeleteObjectPermissionAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/object-permission/types/workspace-migration-object-permission-action.type';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/interfaces/workspace-migration-runner-action-handler-service.interface';
import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
@Injectable()
export class DeleteObjectPermissionActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
'delete',
'objectPermission',
) {
constructor() {
super();
}
override async transpileUniversalActionToFlatAction(
context: WorkspaceMigrationActionRunnerArgs<UniversalDeleteObjectPermissionAction>,
): Promise<FlatDeleteObjectPermissionAction> {
return this.transpileUniversalDeleteActionToFlatDeleteAction(context);
}
async executeForMetadata(
context: WorkspaceMigrationActionRunnerContext<FlatDeleteObjectPermissionAction>,
): Promise<void> {
const { flatAction, queryRunner, workspaceId } = context;
const objectPermissionRepository =
queryRunner.manager.getRepository<ObjectPermissionEntity>(
ObjectPermissionEntity,
);
await objectPermissionRepository.delete({
id: flatAction.entityId,
workspaceId,
});
}
async executeForWorkspaceSchema(
_context: WorkspaceMigrationActionRunnerContext<FlatDeleteObjectPermissionAction>,
): Promise<void> {
return;
}
}
@@ -0,0 +1,71 @@
import { Injectable } from '@nestjs/common';
import { findFlatEntityByUniversalIdentifierOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier-or-throw.util';
import { ObjectPermissionEntity } from 'src/engine/metadata-modules/object-permission/object-permission.entity';
import {
FlatUpdateObjectPermissionAction,
UniversalUpdateObjectPermissionAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/object-permission/types/workspace-migration-object-permission-action.type';
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/interfaces/workspace-migration-runner-action-handler-service.interface';
import {
WorkspaceMigrationActionRunnerArgs,
WorkspaceMigrationActionRunnerContext,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { resolveUniversalUpdateRelationIdentifiersToIds } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-universal-update-relation-identifiers-to-ids.util';
@Injectable()
export class UpdateObjectPermissionActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
'update',
'objectPermission',
) {
constructor() {
super();
}
override async transpileUniversalActionToFlatAction(
context: WorkspaceMigrationActionRunnerArgs<UniversalUpdateObjectPermissionAction>,
): Promise<FlatUpdateObjectPermissionAction> {
const { action, allFlatEntityMaps } = context;
const flatObjectPermission = findFlatEntityByUniversalIdentifierOrThrow({
flatEntityMaps: allFlatEntityMaps.flatObjectPermissionMaps,
universalIdentifier: action.universalIdentifier,
});
const update = resolveUniversalUpdateRelationIdentifiersToIds({
metadataName: 'objectPermission',
universalUpdate: action.update,
allFlatEntityMaps,
});
return {
type: 'update',
metadataName: 'objectPermission',
entityId: flatObjectPermission.id,
update,
};
}
async executeForMetadata(
context: WorkspaceMigrationActionRunnerContext<FlatUpdateObjectPermissionAction>,
): Promise<void> {
const { flatAction, queryRunner, workspaceId } = context;
const { entityId, update } = flatAction;
const objectPermissionRepository =
queryRunner.manager.getRepository<ObjectPermissionEntity>(
ObjectPermissionEntity,
);
await objectPermissionRepository.update(
{ id: entityId, workspaceId },
update,
);
}
async executeForWorkspaceSchema(
_context: WorkspaceMigrationActionRunnerContext<FlatUpdateObjectPermissionAction>,
): Promise<void> {
return;
}
}
@@ -122,6 +122,7 @@ export const fromUniversalFlatObjectMetadataToFlatObjectMetadata = ({
fieldIds: [],
viewIds: [],
indexMetadataIds: [],
objectPermissionIds: [],
...emptyUniversalForeignKeyAggregators,
};
};
@@ -24,6 +24,9 @@ import { UpdateLogicFunctionActionHandlerService } from 'src/engine/workspace-ma
import { CreateNavigationMenuItemActionHandlerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/navigation-menu-item/services/create-navigation-menu-item-action-handler.service';
import { DeleteNavigationMenuItemActionHandlerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/navigation-menu-item/services/delete-navigation-menu-item-action-handler.service';
import { UpdateNavigationMenuItemActionHandlerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/navigation-menu-item/services/update-navigation-menu-item-action-handler.service';
import { CreateObjectPermissionActionHandlerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/object-permission/services/create-object-permission-action-handler.service';
import { DeleteObjectPermissionActionHandlerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/object-permission/services/delete-object-permission-action-handler.service';
import { UpdateObjectPermissionActionHandlerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/object-permission/services/update-object-permission-action-handler.service';
import { CreateObjectActionHandlerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/object/services/create-object-action-handler.service';
import { DeleteObjectActionHandlerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/object/services/delete-object-action-handler.service';
import { UpdateObjectActionHandlerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/object/services/update-object-action-handler.service';
@@ -141,6 +144,10 @@ import { UpdateWebhookActionHandlerService } from 'src/engine/workspace-manager/
UpdatePermissionFlagActionHandlerService,
DeletePermissionFlagActionHandlerService,
CreateObjectPermissionActionHandlerService,
UpdateObjectPermissionActionHandlerService,
DeleteObjectPermissionActionHandlerService,
CreateAgentActionHandlerService,
UpdateAgentActionHandlerService,
DeleteAgentActionHandlerService,
@@ -20,6 +20,7 @@ export const METADATA_EVENTS_TO_EMIT = {
commandMenuItem: true,
navigationMenuItem: true,
permissionFlag: true,
objectPermission: true,
rowLevelPermissionPredicate: true,
rowLevelPermissionPredicateGroup: true,
index: true,
@@ -90,6 +90,7 @@ const deriveAllMetadataEventsFromCreateAction = (
case 'frontComponent':
case 'navigationMenuItem':
case 'permissionFlag':
case 'objectPermission':
case 'viewSort':
case 'webhook': {
return [
@@ -54,6 +54,7 @@ const deriveAllMetadataEventsFromDeleteAction = ({
case 'frontComponent':
case 'navigationMenuItem':
case 'permissionFlag':
case 'objectPermission':
case 'viewSort':
case 'webhook': {
const flatEntityToDelete = findFlatEntityByIdInFlatEntityMapsOrThrow<
@@ -132,6 +132,7 @@ const deriveAllMetadataEventsFromUpdateAction = ({
case 'frontComponent':
case 'navigationMenuItem':
case 'permissionFlag':
case 'objectPermission':
case 'viewSort':
case 'webhook': {
const flatEntityMapsKey = getMetadataFlatEntityMapsKey(
@@ -69,6 +69,7 @@ export const optimisticallyApplyCreateActionOnAllFlatEntityMaps = ({
case 'frontComponent':
case 'navigationMenuItem':
case 'permissionFlag':
case 'objectPermission':
case 'webhook': {
addFlatEntityToFlatEntityAndRelatedEntityMapsThroughMutationOrThrow({
flatEntity: flatAction.flatEntity,
@@ -41,6 +41,7 @@ export const optimisticallyApplyDeleteActionOnAllFlatEntityMaps = ({
case 'frontComponent':
case 'navigationMenuItem':
case 'permissionFlag':
case 'objectPermission':
case 'webhook': {
const flatEntityToDelete = findFlatEntityByIdInFlatEntityMapsOrThrow<
MetadataFlatEntity<typeof flatAction.metadataName>
@@ -6,8 +6,8 @@ import { addFlatEntityToFlatEntityAndRelatedEntityMapsThroughMutationOrThrow } f
import { deleteFlatEntityFromFlatEntityAndRelatedEntityMapsThroughMutationOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/delete-flat-entity-from-flat-entity-and-related-entity-maps-through-mutation-or-throw.util';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util';
import { type AllFlatWorkspaceMigrationAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/workspace-migration-action-common';
import { replaceFlatEntityInFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/utils/replace-flat-entity-in-flat-entity-maps-through-mutation-or-throw.util';
import { type AllFlatWorkspaceMigrationAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/workspace-migration-action-common';
export type OptimisticallyApplyUpdateActionOnAllFlatEntityMapsArgs = {
flatAction: AllFlatWorkspaceMigrationAction<'update'>;
@@ -62,6 +62,7 @@ export const optimisticallyApplyUpdateActionOnAllFlatEntityMaps = ({
case 'frontComponent':
case 'navigationMenuItem':
case 'permissionFlag':
case 'objectPermission':
case 'webhook': {
const flatEntityMapsKey = getMetadataFlatEntityMapsKey(
flatAction.metadataName,