Fix RLS creation logic (#17815)
Fix after resolveEntityRelationUniversalIdentifiers introduction
```
FlatEntityMapsException [Error]: Could not find rowLevelPermissionPredicateGroup for given rowLevelPermissionPredicateGroupId
at resolveEntityRelationUniversalIdentifiers
```
- Creating util for RLS flat entity creation to be aligned with other
entities
- Progressively update the flat entity maps as each new group is built,
following the same optimistic pattern used by
computeUniversalFlatEntityMapsFromTo in the validate build and run. The
updated maps are now passed to computePredicateOperations so predicates
can also resolve references to the newly created groups.
- Adding more coverage
Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
This commit is contained in:
+71
@@ -0,0 +1,71 @@
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { resolveEntityRelationUniversalIdentifiers } from 'src/engine/metadata-modules/flat-entity/utils/resolve-entity-relation-universal-identifiers.util';
|
||||
import { type RowLevelPermissionPredicateGroupInput } from 'src/engine/metadata-modules/row-level-permission-predicate/dtos/inputs/upsert-row-level-permission-predicates.input';
|
||||
import { type FlatRowLevelPermissionPredicateGroup } from 'src/engine/metadata-modules/row-level-permission-predicate/types/flat-row-level-permission-predicate-group.type';
|
||||
|
||||
export const fromCreateRowLevelPermissionPredicateGroupInputToFlatRowLevelPermissionPredicateGroup =
|
||||
({
|
||||
input,
|
||||
roleId,
|
||||
workspaceId,
|
||||
roleUniversalIdentifier,
|
||||
flatApplication,
|
||||
flatObjectMetadataMaps,
|
||||
flatRowLevelPermissionPredicateGroupMaps,
|
||||
}: {
|
||||
input: RowLevelPermissionPredicateGroupInput;
|
||||
roleId: string;
|
||||
workspaceId: string;
|
||||
roleUniversalIdentifier: string;
|
||||
flatApplication: FlatApplication;
|
||||
} & Pick<AllFlatEntityMaps, 'flatObjectMetadataMaps'> & {
|
||||
flatRowLevelPermissionPredicateGroupMaps: FlatEntityMaps<FlatRowLevelPermissionPredicateGroup>;
|
||||
}): FlatRowLevelPermissionPredicateGroup => {
|
||||
const groupId = input.id ?? v4();
|
||||
const createdAt = new Date().toISOString();
|
||||
|
||||
const {
|
||||
objectMetadataUniversalIdentifier,
|
||||
parentRowLevelPermissionPredicateGroupUniversalIdentifier,
|
||||
} = resolveEntityRelationUniversalIdentifiers({
|
||||
metadataName: 'rowLevelPermissionPredicateGroup',
|
||||
foreignKeyValues: {
|
||||
objectMetadataId: input.objectMetadataId,
|
||||
parentRowLevelPermissionPredicateGroupId:
|
||||
input.parentRowLevelPermissionPredicateGroupId,
|
||||
},
|
||||
flatEntityMaps: {
|
||||
flatObjectMetadataMaps,
|
||||
flatRowLevelPermissionPredicateGroupMaps,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
id: groupId,
|
||||
workspaceId,
|
||||
roleId,
|
||||
roleUniversalIdentifier,
|
||||
objectMetadataId: input.objectMetadataId,
|
||||
objectMetadataUniversalIdentifier,
|
||||
logicalOperator: input.logicalOperator,
|
||||
parentRowLevelPermissionPredicateGroupId:
|
||||
input.parentRowLevelPermissionPredicateGroupId ?? null,
|
||||
parentRowLevelPermissionPredicateGroupUniversalIdentifier,
|
||||
positionInRowLevelPermissionPredicateGroup:
|
||||
input.positionInRowLevelPermissionPredicateGroup ?? null,
|
||||
childRowLevelPermissionPredicateGroupIds: [],
|
||||
childRowLevelPermissionPredicateGroupUniversalIdentifiers: [],
|
||||
rowLevelPermissionPredicateIds: [],
|
||||
rowLevelPermissionPredicateUniversalIdentifiers: [],
|
||||
createdAt,
|
||||
updatedAt: createdAt,
|
||||
deletedAt: null,
|
||||
universalIdentifier: groupId,
|
||||
applicationId: flatApplication.id,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
};
|
||||
};
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { resolveEntityRelationUniversalIdentifiers } from 'src/engine/metadata-modules/flat-entity/utils/resolve-entity-relation-universal-identifiers.util';
|
||||
import { type RowLevelPermissionPredicateInput } from 'src/engine/metadata-modules/row-level-permission-predicate/dtos/inputs/upsert-row-level-permission-predicates.input';
|
||||
import { type FlatRowLevelPermissionPredicateGroup } from 'src/engine/metadata-modules/row-level-permission-predicate/types/flat-row-level-permission-predicate-group.type';
|
||||
import { type FlatRowLevelPermissionPredicate } from 'src/engine/metadata-modules/row-level-permission-predicate/types/flat-row-level-permission-predicate.type';
|
||||
|
||||
export const fromCreateRowLevelPermissionPredicateInputToFlatRowLevelPermissionPredicate =
|
||||
({
|
||||
input,
|
||||
roleId,
|
||||
objectMetadataId,
|
||||
workspaceId,
|
||||
roleUniversalIdentifier,
|
||||
objectMetadataUniversalIdentifier,
|
||||
flatApplication,
|
||||
flatFieldMetadataMaps,
|
||||
flatRowLevelPermissionPredicateGroupMaps,
|
||||
}: {
|
||||
input: RowLevelPermissionPredicateInput;
|
||||
roleId: string;
|
||||
objectMetadataId: string;
|
||||
workspaceId: string;
|
||||
roleUniversalIdentifier: string;
|
||||
objectMetadataUniversalIdentifier: string;
|
||||
flatApplication: FlatApplication;
|
||||
} & Pick<AllFlatEntityMaps, 'flatFieldMetadataMaps'> & {
|
||||
flatRowLevelPermissionPredicateGroupMaps: FlatEntityMaps<FlatRowLevelPermissionPredicateGroup>;
|
||||
}): FlatRowLevelPermissionPredicate => {
|
||||
const predicateId = input.id ?? v4();
|
||||
const createdAt = new Date().toISOString();
|
||||
|
||||
const {
|
||||
fieldMetadataUniversalIdentifier,
|
||||
rowLevelPermissionPredicateGroupUniversalIdentifier,
|
||||
workspaceMemberFieldMetadataUniversalIdentifier,
|
||||
} = resolveEntityRelationUniversalIdentifiers({
|
||||
metadataName: 'rowLevelPermissionPredicate',
|
||||
foreignKeyValues: {
|
||||
fieldMetadataId: input.fieldMetadataId,
|
||||
rowLevelPermissionPredicateGroupId:
|
||||
input.rowLevelPermissionPredicateGroupId,
|
||||
workspaceMemberFieldMetadataId: input.workspaceMemberFieldMetadataId,
|
||||
},
|
||||
flatEntityMaps: {
|
||||
flatFieldMetadataMaps,
|
||||
flatRowLevelPermissionPredicateGroupMaps,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
id: predicateId,
|
||||
workspaceId,
|
||||
roleId,
|
||||
roleUniversalIdentifier,
|
||||
objectMetadataId,
|
||||
objectMetadataUniversalIdentifier,
|
||||
fieldMetadataId: input.fieldMetadataId,
|
||||
fieldMetadataUniversalIdentifier,
|
||||
operand: input.operand,
|
||||
value: input.value ?? null,
|
||||
subFieldName: input.subFieldName ?? null,
|
||||
workspaceMemberFieldMetadataId:
|
||||
input.workspaceMemberFieldMetadataId ?? null,
|
||||
workspaceMemberFieldMetadataUniversalIdentifier,
|
||||
workspaceMemberSubFieldName: input.workspaceMemberSubFieldName ?? null,
|
||||
rowLevelPermissionPredicateGroupId:
|
||||
input.rowLevelPermissionPredicateGroupId ?? null,
|
||||
rowLevelPermissionPredicateGroupUniversalIdentifier,
|
||||
positionInRowLevelPermissionPredicateGroup:
|
||||
input.positionInRowLevelPermissionPredicateGroup ?? null,
|
||||
createdAt,
|
||||
updatedAt: createdAt,
|
||||
deletedAt: null,
|
||||
universalIdentifier: predicateId,
|
||||
applicationId: flatApplication.id,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
};
|
||||
};
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { resolveEntityRelationUniversalIdentifiers } from 'src/engine/metadata-modules/flat-entity/utils/resolve-entity-relation-universal-identifiers.util';
|
||||
import { type RowLevelPermissionPredicateGroupInput } from 'src/engine/metadata-modules/row-level-permission-predicate/dtos/inputs/upsert-row-level-permission-predicates.input';
|
||||
import { type FlatRowLevelPermissionPredicateGroup } from 'src/engine/metadata-modules/row-level-permission-predicate/types/flat-row-level-permission-predicate-group.type';
|
||||
|
||||
export const fromUpdateRowLevelPermissionPredicateGroupInputToFlatRowLevelPermissionPredicateGroup =
|
||||
({
|
||||
input,
|
||||
existingGroup,
|
||||
flatRowLevelPermissionPredicateGroupMaps,
|
||||
}: {
|
||||
input: RowLevelPermissionPredicateGroupInput;
|
||||
existingGroup: FlatRowLevelPermissionPredicateGroup;
|
||||
flatRowLevelPermissionPredicateGroupMaps: FlatEntityMaps<FlatRowLevelPermissionPredicateGroup>;
|
||||
}): FlatRowLevelPermissionPredicateGroup => {
|
||||
const { parentRowLevelPermissionPredicateGroupUniversalIdentifier } =
|
||||
resolveEntityRelationUniversalIdentifiers({
|
||||
metadataName: 'rowLevelPermissionPredicateGroup',
|
||||
foreignKeyValues: {
|
||||
parentRowLevelPermissionPredicateGroupId:
|
||||
input.parentRowLevelPermissionPredicateGroupId,
|
||||
},
|
||||
flatEntityMaps: {
|
||||
flatRowLevelPermissionPredicateGroupMaps,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
...existingGroup,
|
||||
logicalOperator: input.logicalOperator,
|
||||
parentRowLevelPermissionPredicateGroupId:
|
||||
input.parentRowLevelPermissionPredicateGroupId ?? null,
|
||||
parentRowLevelPermissionPredicateGroupUniversalIdentifier,
|
||||
positionInRowLevelPermissionPredicateGroup:
|
||||
input.positionInRowLevelPermissionPredicateGroup ?? null,
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
};
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { resolveEntityRelationUniversalIdentifiers } from 'src/engine/metadata-modules/flat-entity/utils/resolve-entity-relation-universal-identifiers.util';
|
||||
import { type RowLevelPermissionPredicateInput } from 'src/engine/metadata-modules/row-level-permission-predicate/dtos/inputs/upsert-row-level-permission-predicates.input';
|
||||
import { type FlatRowLevelPermissionPredicateGroup } from 'src/engine/metadata-modules/row-level-permission-predicate/types/flat-row-level-permission-predicate-group.type';
|
||||
import { type FlatRowLevelPermissionPredicate } from 'src/engine/metadata-modules/row-level-permission-predicate/types/flat-row-level-permission-predicate.type';
|
||||
|
||||
export const fromUpdateRowLevelPermissionPredicateInputToFlatRowLevelPermissionPredicate =
|
||||
({
|
||||
input,
|
||||
existingPredicate,
|
||||
flatFieldMetadataMaps,
|
||||
flatRowLevelPermissionPredicateGroupMaps,
|
||||
}: {
|
||||
input: RowLevelPermissionPredicateInput;
|
||||
existingPredicate: FlatRowLevelPermissionPredicate;
|
||||
} & Pick<AllFlatEntityMaps, 'flatFieldMetadataMaps'> & {
|
||||
flatRowLevelPermissionPredicateGroupMaps: FlatEntityMaps<FlatRowLevelPermissionPredicateGroup>;
|
||||
}): FlatRowLevelPermissionPredicate => {
|
||||
const {
|
||||
fieldMetadataUniversalIdentifier,
|
||||
rowLevelPermissionPredicateGroupUniversalIdentifier,
|
||||
workspaceMemberFieldMetadataUniversalIdentifier,
|
||||
} = resolveEntityRelationUniversalIdentifiers({
|
||||
metadataName: 'rowLevelPermissionPredicate',
|
||||
foreignKeyValues: {
|
||||
fieldMetadataId: input.fieldMetadataId,
|
||||
rowLevelPermissionPredicateGroupId:
|
||||
input.rowLevelPermissionPredicateGroupId,
|
||||
workspaceMemberFieldMetadataId: input.workspaceMemberFieldMetadataId,
|
||||
},
|
||||
flatEntityMaps: {
|
||||
flatFieldMetadataMaps,
|
||||
flatRowLevelPermissionPredicateGroupMaps,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
...existingPredicate,
|
||||
fieldMetadataId: input.fieldMetadataId,
|
||||
fieldMetadataUniversalIdentifier,
|
||||
operand: input.operand,
|
||||
value: input.value ?? null,
|
||||
subFieldName: input.subFieldName ?? null,
|
||||
workspaceMemberFieldMetadataId:
|
||||
input.workspaceMemberFieldMetadataId ?? null,
|
||||
workspaceMemberFieldMetadataUniversalIdentifier,
|
||||
workspaceMemberSubFieldName: input.workspaceMemberSubFieldName ?? null,
|
||||
rowLevelPermissionPredicateGroupId:
|
||||
input.rowLevelPermissionPredicateGroupId ?? null,
|
||||
rowLevelPermissionPredicateGroupUniversalIdentifier,
|
||||
positionInRowLevelPermissionPredicateGroup:
|
||||
input.positionInRowLevelPermissionPredicateGroup ?? null,
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
};
|
||||
+84
-156
@@ -6,16 +6,22 @@ import { isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { BillingEntitlementKey } from 'src/engine/core-modules/billing/enums/billing-entitlement-key.enum';
|
||||
import { BillingService } from 'src/engine/core-modules/billing/services/billing.service';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { addFlatEntityToFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/add-flat-entity-to-flat-entity-maps-or-throw.util';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { resolveEntityRelationUniversalIdentifiers } from 'src/engine/metadata-modules/flat-entity/utils/resolve-entity-relation-universal-identifiers.util';
|
||||
import { fromCreateRowLevelPermissionPredicateGroupInputToFlatRowLevelPermissionPredicateGroup } from 'src/engine/metadata-modules/flat-row-level-permission-predicate/utils/from-create-row-level-permission-predicate-group-input-to-flat-row-level-permission-predicate-group.util';
|
||||
import { fromCreateRowLevelPermissionPredicateInputToFlatRowLevelPermissionPredicate } from 'src/engine/metadata-modules/flat-row-level-permission-predicate/utils/from-create-row-level-permission-predicate-input-to-flat-row-level-permission-predicate.util';
|
||||
import { fromFlatRowLevelPermissionPredicateGroupToDto } from 'src/engine/metadata-modules/flat-row-level-permission-predicate/utils/from-flat-row-level-permission-predicate-group-to-dto.util';
|
||||
import { fromFlatRowLevelPermissionPredicateToDto } from 'src/engine/metadata-modules/flat-row-level-permission-predicate/utils/from-flat-row-level-permission-predicate-to-dto.util';
|
||||
import { fromUpdateRowLevelPermissionPredicateGroupInputToFlatRowLevelPermissionPredicateGroup } from 'src/engine/metadata-modules/flat-row-level-permission-predicate/utils/from-update-row-level-permission-predicate-group-input-to-flat-row-level-permission-predicate-group.util';
|
||||
import { fromUpdateRowLevelPermissionPredicateInputToFlatRowLevelPermissionPredicate } from 'src/engine/metadata-modules/flat-row-level-permission-predicate/utils/from-update-row-level-permission-predicate-input-to-flat-row-level-permission-predicate.util';
|
||||
import {
|
||||
type RowLevelPermissionPredicateGroupInput,
|
||||
type RowLevelPermissionPredicateInput,
|
||||
@@ -206,19 +212,22 @@ export class RowLevelPermissionPredicateService {
|
||||
group.objectMetadataId === objectMetadataId,
|
||||
);
|
||||
|
||||
const { groupsToCreate, groupsToUpdate, groupsToDelete } =
|
||||
this.computePredicateGroupOperations({
|
||||
existingGroups,
|
||||
inputGroups: predicateGroups,
|
||||
roleId,
|
||||
workspaceId,
|
||||
flatRowLevelPermissionPredicateGroupMaps,
|
||||
flatRoleMaps,
|
||||
flatObjectMetadataMaps,
|
||||
workspaceCustomApplicationId: workspaceCustomFlatApplication.id,
|
||||
workspaceCustomApplicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
});
|
||||
const {
|
||||
groupsToCreate,
|
||||
groupsToUpdate,
|
||||
groupsToDelete,
|
||||
flatRowLevelPermissionPredicateGroupMaps:
|
||||
flatRowLevelPermissionPredicateGroupMapsWithCreatedGroups,
|
||||
} = this.computePredicateGroupOperations({
|
||||
existingGroups,
|
||||
inputGroups: predicateGroups,
|
||||
roleId,
|
||||
workspaceId,
|
||||
flatApplication: workspaceCustomFlatApplication,
|
||||
flatRowLevelPermissionPredicateGroupMaps,
|
||||
flatRoleMaps,
|
||||
flatObjectMetadataMaps,
|
||||
});
|
||||
|
||||
const { predicatesToCreate, predicatesToUpdate, predicatesToDelete } =
|
||||
this.computePredicateOperations({
|
||||
@@ -227,14 +236,13 @@ export class RowLevelPermissionPredicateService {
|
||||
roleId,
|
||||
objectMetadataId,
|
||||
workspaceId,
|
||||
flatApplication: workspaceCustomFlatApplication,
|
||||
flatRowLevelPermissionPredicateMaps,
|
||||
flatRowLevelPermissionPredicateGroupMaps,
|
||||
flatRowLevelPermissionPredicateGroupMaps:
|
||||
flatRowLevelPermissionPredicateGroupMapsWithCreatedGroups,
|
||||
flatRoleMaps,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
workspaceCustomApplicationId: workspaceCustomFlatApplication.id,
|
||||
workspaceCustomApplicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
});
|
||||
|
||||
await this.runUpsertMigration({
|
||||
@@ -294,31 +302,32 @@ export class RowLevelPermissionPredicateService {
|
||||
inputGroups,
|
||||
roleId,
|
||||
workspaceId,
|
||||
flatApplication,
|
||||
flatRowLevelPermissionPredicateGroupMaps,
|
||||
flatRoleMaps,
|
||||
flatObjectMetadataMaps,
|
||||
workspaceCustomApplicationId,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
}: {
|
||||
existingGroups: FlatRowLevelPermissionPredicateGroup[];
|
||||
inputGroups: RowLevelPermissionPredicateGroupInput[];
|
||||
roleId: string;
|
||||
workspaceId: string;
|
||||
flatApplication: FlatApplication;
|
||||
flatRowLevelPermissionPredicateGroupMaps: FlatEntityMaps<FlatRowLevelPermissionPredicateGroup>;
|
||||
flatRoleMaps: AllFlatEntityMaps['flatRoleMaps'];
|
||||
flatObjectMetadataMaps: AllFlatEntityMaps['flatObjectMetadataMaps'];
|
||||
workspaceCustomApplicationId: string;
|
||||
workspaceCustomApplicationUniversalIdentifier: string;
|
||||
}): {
|
||||
groupsToCreate: FlatRowLevelPermissionPredicateGroup[];
|
||||
groupsToUpdate: FlatRowLevelPermissionPredicateGroup[];
|
||||
groupsToDelete: FlatRowLevelPermissionPredicateGroup[];
|
||||
flatRowLevelPermissionPredicateGroupMaps: FlatEntityMaps<FlatRowLevelPermissionPredicateGroup>;
|
||||
} {
|
||||
const groupsToCreate: FlatRowLevelPermissionPredicateGroup[] = [];
|
||||
const groupsToUpdate: FlatRowLevelPermissionPredicateGroup[] = [];
|
||||
|
||||
const inputGroupIds = new Set<string>();
|
||||
|
||||
let currentGroupMaps = flatRowLevelPermissionPredicateGroupMaps;
|
||||
|
||||
const { roleUniversalIdentifier } =
|
||||
resolveEntityRelationUniversalIdentifiers({
|
||||
metadataName: 'rowLevelPermissionPredicateGroup',
|
||||
@@ -328,7 +337,6 @@ export class RowLevelPermissionPredicateService {
|
||||
|
||||
for (const inputGroup of inputGroups) {
|
||||
const groupId = inputGroup.id ?? v4();
|
||||
const createdAt = new Date().toISOString();
|
||||
|
||||
inputGroupIds.add(groupId);
|
||||
|
||||
@@ -338,69 +346,34 @@ export class RowLevelPermissionPredicateService {
|
||||
});
|
||||
|
||||
if (isDefined(existingGroup) && existingGroup.deletedAt === null) {
|
||||
const { parentRowLevelPermissionPredicateGroupUniversalIdentifier } =
|
||||
resolveEntityRelationUniversalIdentifiers({
|
||||
metadataName: 'rowLevelPermissionPredicateGroup',
|
||||
foreignKeyValues: {
|
||||
parentRowLevelPermissionPredicateGroupId:
|
||||
inputGroup.parentRowLevelPermissionPredicateGroupId,
|
||||
groupsToUpdate.push(
|
||||
fromUpdateRowLevelPermissionPredicateGroupInputToFlatRowLevelPermissionPredicateGroup(
|
||||
{
|
||||
input: inputGroup,
|
||||
existingGroup,
|
||||
flatRowLevelPermissionPredicateGroupMaps: currentGroupMaps,
|
||||
},
|
||||
flatEntityMaps: {
|
||||
flatRowLevelPermissionPredicateGroupMaps,
|
||||
},
|
||||
});
|
||||
|
||||
groupsToUpdate.push({
|
||||
...existingGroup,
|
||||
logicalOperator: inputGroup.logicalOperator,
|
||||
parentRowLevelPermissionPredicateGroupId:
|
||||
inputGroup.parentRowLevelPermissionPredicateGroupId ?? null,
|
||||
parentRowLevelPermissionPredicateGroupUniversalIdentifier,
|
||||
positionInRowLevelPermissionPredicateGroup:
|
||||
inputGroup.positionInRowLevelPermissionPredicateGroup ?? null,
|
||||
updatedAt: createdAt,
|
||||
});
|
||||
),
|
||||
);
|
||||
} else {
|
||||
const {
|
||||
objectMetadataUniversalIdentifier,
|
||||
parentRowLevelPermissionPredicateGroupUniversalIdentifier,
|
||||
} = resolveEntityRelationUniversalIdentifiers({
|
||||
metadataName: 'rowLevelPermissionPredicateGroup',
|
||||
foreignKeyValues: {
|
||||
objectMetadataId: inputGroup.objectMetadataId,
|
||||
parentRowLevelPermissionPredicateGroupId:
|
||||
inputGroup.parentRowLevelPermissionPredicateGroupId,
|
||||
},
|
||||
flatEntityMaps: {
|
||||
flatObjectMetadataMaps,
|
||||
flatRowLevelPermissionPredicateGroupMaps,
|
||||
},
|
||||
});
|
||||
const flatGroupToCreate =
|
||||
fromCreateRowLevelPermissionPredicateGroupInputToFlatRowLevelPermissionPredicateGroup(
|
||||
{
|
||||
input: { ...inputGroup, id: groupId },
|
||||
roleId,
|
||||
workspaceId,
|
||||
roleUniversalIdentifier,
|
||||
flatApplication,
|
||||
flatObjectMetadataMaps,
|
||||
flatRowLevelPermissionPredicateGroupMaps: currentGroupMaps,
|
||||
},
|
||||
);
|
||||
|
||||
groupsToCreate.push({
|
||||
id: groupId,
|
||||
workspaceId,
|
||||
roleId,
|
||||
roleUniversalIdentifier,
|
||||
objectMetadataId: inputGroup.objectMetadataId,
|
||||
objectMetadataUniversalIdentifier,
|
||||
logicalOperator: inputGroup.logicalOperator,
|
||||
parentRowLevelPermissionPredicateGroupId:
|
||||
inputGroup.parentRowLevelPermissionPredicateGroupId ?? null,
|
||||
parentRowLevelPermissionPredicateGroupUniversalIdentifier,
|
||||
positionInRowLevelPermissionPredicateGroup:
|
||||
inputGroup.positionInRowLevelPermissionPredicateGroup ?? null,
|
||||
childRowLevelPermissionPredicateGroupIds: [],
|
||||
childRowLevelPermissionPredicateGroupUniversalIdentifiers: [],
|
||||
rowLevelPermissionPredicateIds: [],
|
||||
rowLevelPermissionPredicateUniversalIdentifiers: [],
|
||||
createdAt,
|
||||
updatedAt: createdAt,
|
||||
deletedAt: null,
|
||||
universalIdentifier: groupId,
|
||||
applicationId: workspaceCustomApplicationId,
|
||||
applicationUniversalIdentifier:
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
groupsToCreate.push(flatGroupToCreate);
|
||||
|
||||
currentGroupMaps = addFlatEntityToFlatEntityMapsOrThrow({
|
||||
flatEntity: flatGroupToCreate,
|
||||
flatEntityMaps: currentGroupMaps,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -417,6 +390,7 @@ export class RowLevelPermissionPredicateService {
|
||||
groupsToCreate,
|
||||
groupsToUpdate,
|
||||
groupsToDelete,
|
||||
flatRowLevelPermissionPredicateGroupMaps: currentGroupMaps,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -426,26 +400,24 @@ export class RowLevelPermissionPredicateService {
|
||||
roleId,
|
||||
objectMetadataId,
|
||||
workspaceId,
|
||||
flatApplication,
|
||||
flatRowLevelPermissionPredicateMaps,
|
||||
flatRowLevelPermissionPredicateGroupMaps,
|
||||
flatRoleMaps,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
workspaceCustomApplicationId,
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
}: {
|
||||
existingPredicates: FlatRowLevelPermissionPredicate[];
|
||||
inputPredicates: RowLevelPermissionPredicateInput[];
|
||||
roleId: string;
|
||||
objectMetadataId: string;
|
||||
workspaceId: string;
|
||||
flatApplication: FlatApplication;
|
||||
flatRowLevelPermissionPredicateMaps: FlatEntityMaps<FlatRowLevelPermissionPredicate>;
|
||||
flatRowLevelPermissionPredicateGroupMaps: FlatEntityMaps<FlatRowLevelPermissionPredicateGroup>;
|
||||
flatRoleMaps: AllFlatEntityMaps['flatRoleMaps'];
|
||||
flatObjectMetadataMaps: AllFlatEntityMaps['flatObjectMetadataMaps'];
|
||||
flatFieldMetadataMaps: AllFlatEntityMaps['flatFieldMetadataMaps'];
|
||||
workspaceCustomApplicationId: string;
|
||||
workspaceCustomApplicationUniversalIdentifier: string;
|
||||
}): {
|
||||
predicatesToCreate: FlatRowLevelPermissionPredicate[];
|
||||
predicatesToUpdate: FlatRowLevelPermissionPredicate[];
|
||||
@@ -465,7 +437,6 @@ export class RowLevelPermissionPredicateService {
|
||||
|
||||
for (const inputPredicate of inputPredicates) {
|
||||
const predicateId = inputPredicate.id ?? v4();
|
||||
const createdAt = new Date().toISOString();
|
||||
|
||||
inputPredicateIds.add(predicateId);
|
||||
|
||||
@@ -474,79 +445,36 @@ export class RowLevelPermissionPredicateService {
|
||||
flatEntityMaps: flatRowLevelPermissionPredicateMaps,
|
||||
});
|
||||
|
||||
const {
|
||||
fieldMetadataUniversalIdentifier,
|
||||
rowLevelPermissionPredicateGroupUniversalIdentifier,
|
||||
workspaceMemberFieldMetadataUniversalIdentifier,
|
||||
} = resolveEntityRelationUniversalIdentifiers({
|
||||
metadataName: 'rowLevelPermissionPredicate',
|
||||
foreignKeyValues: {
|
||||
fieldMetadataId: inputPredicate.fieldMetadataId,
|
||||
rowLevelPermissionPredicateGroupId:
|
||||
inputPredicate.rowLevelPermissionPredicateGroupId,
|
||||
workspaceMemberFieldMetadataId:
|
||||
inputPredicate.workspaceMemberFieldMetadataId,
|
||||
},
|
||||
flatEntityMaps: {
|
||||
flatFieldMetadataMaps,
|
||||
flatRowLevelPermissionPredicateGroupMaps,
|
||||
},
|
||||
});
|
||||
|
||||
if (
|
||||
isDefined(existingPredicate) &&
|
||||
existingPredicate.deletedAt === null
|
||||
) {
|
||||
predicatesToUpdate.push({
|
||||
...existingPredicate,
|
||||
fieldMetadataId: inputPredicate.fieldMetadataId,
|
||||
fieldMetadataUniversalIdentifier,
|
||||
operand: inputPredicate.operand,
|
||||
value: inputPredicate.value ?? null,
|
||||
subFieldName: inputPredicate.subFieldName ?? null,
|
||||
workspaceMemberFieldMetadataId:
|
||||
inputPredicate.workspaceMemberFieldMetadataId ?? null,
|
||||
workspaceMemberFieldMetadataUniversalIdentifier,
|
||||
workspaceMemberSubFieldName:
|
||||
inputPredicate.workspaceMemberSubFieldName ?? null,
|
||||
rowLevelPermissionPredicateGroupId:
|
||||
inputPredicate.rowLevelPermissionPredicateGroupId ?? null,
|
||||
rowLevelPermissionPredicateGroupUniversalIdentifier,
|
||||
positionInRowLevelPermissionPredicateGroup:
|
||||
inputPredicate.positionInRowLevelPermissionPredicateGroup ?? null,
|
||||
updatedAt: createdAt,
|
||||
});
|
||||
predicatesToUpdate.push(
|
||||
fromUpdateRowLevelPermissionPredicateInputToFlatRowLevelPermissionPredicate(
|
||||
{
|
||||
input: inputPredicate,
|
||||
existingPredicate,
|
||||
flatFieldMetadataMaps,
|
||||
flatRowLevelPermissionPredicateGroupMaps,
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
predicatesToCreate.push({
|
||||
id: predicateId,
|
||||
workspaceId,
|
||||
roleId,
|
||||
roleUniversalIdentifier,
|
||||
objectMetadataId,
|
||||
objectMetadataUniversalIdentifier,
|
||||
fieldMetadataId: inputPredicate.fieldMetadataId,
|
||||
fieldMetadataUniversalIdentifier,
|
||||
operand: inputPredicate.operand,
|
||||
value: inputPredicate.value ?? null,
|
||||
subFieldName: inputPredicate.subFieldName ?? null,
|
||||
workspaceMemberFieldMetadataId:
|
||||
inputPredicate.workspaceMemberFieldMetadataId ?? null,
|
||||
workspaceMemberFieldMetadataUniversalIdentifier,
|
||||
workspaceMemberSubFieldName:
|
||||
inputPredicate.workspaceMemberSubFieldName ?? null,
|
||||
rowLevelPermissionPredicateGroupId:
|
||||
inputPredicate.rowLevelPermissionPredicateGroupId ?? null,
|
||||
rowLevelPermissionPredicateGroupUniversalIdentifier,
|
||||
positionInRowLevelPermissionPredicateGroup:
|
||||
inputPredicate.positionInRowLevelPermissionPredicateGroup ?? null,
|
||||
createdAt,
|
||||
updatedAt: createdAt,
|
||||
deletedAt: null,
|
||||
universalIdentifier: predicateId,
|
||||
applicationId: workspaceCustomApplicationId,
|
||||
applicationUniversalIdentifier:
|
||||
workspaceCustomApplicationUniversalIdentifier,
|
||||
});
|
||||
predicatesToCreate.push(
|
||||
fromCreateRowLevelPermissionPredicateInputToFlatRowLevelPermissionPredicate(
|
||||
{
|
||||
input: { ...inputPredicate, id: predicateId },
|
||||
roleId,
|
||||
objectMetadataId,
|
||||
workspaceId,
|
||||
roleUniversalIdentifier,
|
||||
objectMetadataUniversalIdentifier,
|
||||
flatApplication,
|
||||
flatFieldMetadataMaps,
|
||||
flatRowLevelPermissionPredicateGroupMaps,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+107
@@ -8,6 +8,7 @@ import {
|
||||
RowLevelPermissionPredicateGroupLogicalOperator,
|
||||
RowLevelPermissionPredicateOperand,
|
||||
} from 'twenty-shared/types';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { type UpsertRowLevelPermissionPredicatesInput } from 'src/engine/metadata-modules/row-level-permission-predicate/dtos/inputs/upsert-row-level-permission-predicates.input';
|
||||
@@ -444,4 +445,110 @@ describe('Row Level Permission Predicate upsert should succeed', () => {
|
||||
positionInRowLevelPermissionPredicateGroup: 0,
|
||||
});
|
||||
});
|
||||
|
||||
it('should create groups and predicates referencing those groups in a single call', async () => {
|
||||
const groupId = v4();
|
||||
|
||||
const input: UpsertRowLevelPermissionPredicatesInput = {
|
||||
roleId: createdRoleId,
|
||||
objectMetadataId: companyObjectMetadataId,
|
||||
predicates: [
|
||||
{
|
||||
fieldMetadataId: companyNameFieldMetadataId,
|
||||
operand: RowLevelPermissionPredicateOperand.CONTAINS,
|
||||
rowLevelPermissionPredicateGroupId: groupId,
|
||||
positionInRowLevelPermissionPredicateGroup: 0,
|
||||
},
|
||||
],
|
||||
predicateGroups: [
|
||||
{
|
||||
id: groupId,
|
||||
objectMetadataId: companyObjectMetadataId,
|
||||
logicalOperator: RowLevelPermissionPredicateGroupLogicalOperator.AND,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const { data } = await upsertRowLevelPermissionPredicates({
|
||||
expectToFail: false,
|
||||
input,
|
||||
});
|
||||
|
||||
expect(data.upsertRowLevelPermissionPredicates.predicates).toHaveLength(1);
|
||||
expect(
|
||||
data.upsertRowLevelPermissionPredicates.predicateGroups,
|
||||
).toHaveLength(1);
|
||||
expect(
|
||||
data.upsertRowLevelPermissionPredicates.predicateGroups[0],
|
||||
).toMatchObject({
|
||||
id: groupId,
|
||||
objectMetadataId: companyObjectMetadataId,
|
||||
logicalOperator: RowLevelPermissionPredicateGroupLogicalOperator.AND,
|
||||
});
|
||||
expect(data.upsertRowLevelPermissionPredicates.predicates[0]).toMatchObject(
|
||||
{
|
||||
fieldMetadataId: companyNameFieldMetadataId,
|
||||
rowLevelPermissionPredicateGroupId: groupId,
|
||||
positionInRowLevelPermissionPredicateGroup: 0,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('should create nested parent-child groups in a single call', async () => {
|
||||
const parentGroupId = v4();
|
||||
const childGroupId = v4();
|
||||
|
||||
const input: UpsertRowLevelPermissionPredicatesInput = {
|
||||
roleId: createdRoleId,
|
||||
objectMetadataId: companyObjectMetadataId,
|
||||
predicates: [],
|
||||
predicateGroups: [
|
||||
{
|
||||
id: parentGroupId,
|
||||
objectMetadataId: companyObjectMetadataId,
|
||||
logicalOperator: RowLevelPermissionPredicateGroupLogicalOperator.AND,
|
||||
parentRowLevelPermissionPredicateGroupId: null,
|
||||
},
|
||||
{
|
||||
id: childGroupId,
|
||||
objectMetadataId: companyObjectMetadataId,
|
||||
logicalOperator: RowLevelPermissionPredicateGroupLogicalOperator.OR,
|
||||
parentRowLevelPermissionPredicateGroupId: parentGroupId,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const { data } = await upsertRowLevelPermissionPredicates({
|
||||
expectToFail: false,
|
||||
input,
|
||||
});
|
||||
|
||||
expect(
|
||||
data.upsertRowLevelPermissionPredicates.predicateGroups,
|
||||
).toHaveLength(2);
|
||||
|
||||
const parentGroup =
|
||||
data.upsertRowLevelPermissionPredicates.predicateGroups.find(
|
||||
(group: { id: string }) => group.id === parentGroupId,
|
||||
);
|
||||
|
||||
const childGroup =
|
||||
data.upsertRowLevelPermissionPredicates.predicateGroups.find(
|
||||
(group: { id: string }) => group.id === childGroupId,
|
||||
);
|
||||
|
||||
expect(parentGroup).toBeDefined();
|
||||
expect(parentGroup?.parentRowLevelPermissionPredicateGroupId).toBeNull();
|
||||
expect(parentGroup?.logicalOperator).toBe(
|
||||
RowLevelPermissionPredicateGroupLogicalOperator.AND,
|
||||
);
|
||||
|
||||
expect(childGroup).toBeDefined();
|
||||
expect(childGroup?.parentRowLevelPermissionPredicateGroupId).toBe(
|
||||
parentGroupId,
|
||||
);
|
||||
expect(childGroup?.logicalOperator).toBe(
|
||||
RowLevelPermissionPredicateGroupLogicalOperator.OR,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user