9957057d1f
In this PR we adapt field permission to two things 1. Connect: the recent insertion of the connect feature introduces the possibility to have "connect" objects in typeORM's expressionMap's valueSet, where we previously only had column names (if i followed correctly). For instance for a person object that a N - 1 relationship to company, person will have both companyId and company as possible valueSet keys for the upsert. We need to reflect that in our `getColumnNameToFieldMetadataIdMap` util that returns a map containing every possible value we could encounter in valueSet. In an attempt to tie this to the schema generation where this is introduced, I created the shallow util extractGraphQLRelationFieldNames (probably ill-named - im willing to update the name if @etiennejouan has a better idea?) to remind us that these two are linked. 2. CreateMany: When calling query builders methods directly on custom object (like we do in graphql-create-many-resolver), we need to be careful to call them with a selection of readable fields. We had a debate on whether we should compute this selection containing all readable fields by default under the hood when no selected fields are indicated. I am still not 100% convinced as I think it should remain the caller's responsibility, but this case reminds us that it could easily be forgotten by developers - although it is all the more the case as we don't have seeds yet that help us realize that ([PR on the way](https://github.com/twentyhq/twenty/pull/13646)).
101 lines
3.6 KiB
TypeScript
101 lines
3.6 KiB
TypeScript
import { CompositeType } from 'src/engine/metadata-modules/field-metadata/interfaces/composite-type.interface';
|
|
import { FieldMetadataRelationSettings } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
|
|
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
|
|
|
|
import { extractGraphQLRelationFieldNames } from 'src/engine/api/graphql/workspace-schema-builder/utils/extract-graphql-relation-field-names.util';
|
|
import { isFieldMetadataRelationOrMorphRelation } from 'src/engine/api/graphql/workspace-schema-builder/utils/is-field-metadata-relation-or-morph-relation.utils';
|
|
import { compositeTypeDefinitions } from 'src/engine/metadata-modules/field-metadata/composite-types';
|
|
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
|
import { computeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
|
|
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
|
|
import {
|
|
PermissionsException,
|
|
PermissionsExceptionCode,
|
|
} from 'src/engine/metadata-modules/permissions/permissions.exception';
|
|
import { ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
|
|
|
|
export type ColumnNameProcessor = {
|
|
processCompositeField: ({
|
|
fieldMetadataId,
|
|
fieldMetadata,
|
|
compositeType,
|
|
}: {
|
|
fieldMetadataId: string;
|
|
fieldMetadata: FieldMetadataEntity;
|
|
compositeType: CompositeType;
|
|
}) => void;
|
|
processRelationField: ({
|
|
fieldMetadataId,
|
|
fieldMetadata,
|
|
joinColumnName,
|
|
connectFieldName,
|
|
}: {
|
|
fieldMetadataId: string;
|
|
fieldMetadata: FieldMetadataEntity;
|
|
joinColumnName: string;
|
|
connectFieldName?: string;
|
|
}) => void;
|
|
processSimpleField: ({
|
|
fieldMetadataId,
|
|
fieldMetadata,
|
|
columnName,
|
|
}: {
|
|
fieldMetadataId: string;
|
|
fieldMetadata: FieldMetadataEntity;
|
|
columnName: string;
|
|
}) => void;
|
|
};
|
|
|
|
export function processFieldMetadataForColumnNameMapping(
|
|
objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps,
|
|
processor: ColumnNameProcessor,
|
|
) {
|
|
for (const [fieldMetadataId, fieldMetadata] of Object.entries(
|
|
objectMetadataItemWithFieldMaps.fieldsById,
|
|
)) {
|
|
if (isCompositeFieldMetadataType(fieldMetadata.type)) {
|
|
const compositeType = compositeTypeDefinitions.get(fieldMetadata.type);
|
|
|
|
if (!compositeType) {
|
|
throw new PermissionsException(
|
|
`Composite type not found for field metadata type ${fieldMetadata.type}`,
|
|
PermissionsExceptionCode.COMPOSITE_TYPE_NOT_FOUND,
|
|
);
|
|
}
|
|
|
|
processor.processCompositeField({
|
|
fieldMetadataId,
|
|
fieldMetadata,
|
|
compositeType,
|
|
});
|
|
} else {
|
|
if (isFieldMetadataRelationOrMorphRelation(fieldMetadata)) {
|
|
const fieldMetadataSettings =
|
|
fieldMetadata.settings as FieldMetadataRelationSettings;
|
|
|
|
if (fieldMetadataSettings?.relationType === RelationType.ONE_TO_MANY) {
|
|
continue;
|
|
}
|
|
|
|
const { joinColumnName, fieldMetadataName } =
|
|
extractGraphQLRelationFieldNames(fieldMetadata);
|
|
|
|
processor.processRelationField({
|
|
fieldMetadataId,
|
|
fieldMetadata,
|
|
joinColumnName,
|
|
connectFieldName: fieldMetadataName,
|
|
});
|
|
} else {
|
|
const columnName = computeColumnName(fieldMetadata);
|
|
|
|
processor.processSimpleField({
|
|
fieldMetadataId,
|
|
fieldMetadata,
|
|
columnName,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|