[permissions] Update permission check layer (#13485)
Fixes https://github.com/twentyhq/core-team-issues/issues/1262 In this PR we add the update permission check layer by - for the graphql api: extracting columns to update from the expressionMap - for rest api: .save() is used so we need to add the permission layer to .save directly. We also take advantage of this PR to filter out non-readable fields from save response (other save returns the whole entity) - this was planned in https://github.com/twentyhq/core-team-issues/issues/1216 The current solution does not work with rest api depth 2 queries, but this seem to already not work on main (for timeout reasons though, so different). I offer to create a ticket to fix it altogether later.
This commit is contained in:
+1
-1
@@ -5,7 +5,7 @@ import { GraphQLInputObjectType } from 'graphql';
|
||||
import { WorkspaceBuildSchemaOptions } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-build-schema-options.interface';
|
||||
|
||||
import { TypeMapperService } from 'src/engine/api/graphql/workspace-schema-builder/services/type-mapper.service';
|
||||
import { generateFields } from 'src/engine/api/graphql/workspace-schema-builder/utils/generate-fields.utils';
|
||||
import { generateFields } from 'src/engine/api/graphql/workspace-schema-builder/utils/generate-fields.util';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { pascalCase } from 'src/utils/pascal-case';
|
||||
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import { GraphQLObjectType } from 'graphql';
|
||||
|
||||
import { WorkspaceBuildSchemaOptions } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-build-schema-options.interface';
|
||||
|
||||
import { generateFields } from 'src/engine/api/graphql/workspace-schema-builder/utils/generate-fields.utils';
|
||||
import { generateFields } from 'src/engine/api/graphql/workspace-schema-builder/utils/generate-fields.util';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { pascalCase } from 'src/utils/pascal-case';
|
||||
|
||||
|
||||
+5
-9
@@ -13,10 +13,10 @@ import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfa
|
||||
import { InputTypeDefinitionKind } from 'src/engine/api/graphql/workspace-schema-builder/factories/input-type-definition.factory';
|
||||
import { ObjectTypeDefinitionKind } from 'src/engine/api/graphql/workspace-schema-builder/factories/object-type-definition.factory';
|
||||
import { formatRelationConnectInputTarget } from 'src/engine/api/graphql/workspace-schema-builder/factories/relation-connect-input-type-definition.factory';
|
||||
import { isFieldMetadataRelationOrMorphRelation } from 'src/engine/api/graphql/workspace-schema-builder/utils/is-field-metadata-relation-or-morph-relation.utils';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { isFieldMetadataEntityOfType } from 'src/engine/utils/is-field-metadata-of-type.util';
|
||||
|
||||
type TypeFactory<T extends InputTypeDefinitionKind | ObjectTypeDefinitionKind> =
|
||||
{
|
||||
@@ -55,23 +55,19 @@ export const generateFields = <
|
||||
}): T extends InputTypeDefinitionKind
|
||||
? GraphQLInputFieldConfigMap
|
||||
: // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
GraphQLFieldConfigMap<any, any> => {
|
||||
const allGeneratedFields = {};
|
||||
|
||||
for (const fieldMetadata of objectMetadata.fields) {
|
||||
let generatedField;
|
||||
|
||||
const isRelation =
|
||||
isFieldMetadataEntityOfType(fieldMetadata, FieldMetadataType.RELATION) ||
|
||||
isFieldMetadataEntityOfType(
|
||||
fieldMetadata,
|
||||
FieldMetadataType.MORPH_RELATION,
|
||||
);
|
||||
const isRelation = isFieldMetadataRelationOrMorphRelation(fieldMetadata);
|
||||
|
||||
if (isRelation) {
|
||||
generatedField = generateRelationField({
|
||||
fieldMetadata,
|
||||
fieldMetadata: fieldMetadata as FieldMetadataEntity<
|
||||
FieldMetadataType.RELATION | FieldMetadataType.MORPH_RELATION
|
||||
>,
|
||||
kind,
|
||||
options,
|
||||
typeFactory,
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { isFieldMetadataEntityOfType } from 'src/engine/utils/is-field-metadata-of-type.util';
|
||||
|
||||
export const isFieldMetadataRelationOrMorphRelation = (
|
||||
fieldMetadata: FieldMetadataEntity<FieldMetadataType>,
|
||||
) => {
|
||||
return (
|
||||
isFieldMetadataEntityOfType(fieldMetadata, FieldMetadataType.RELATION) ||
|
||||
isFieldMetadataEntityOfType(fieldMetadata, FieldMetadataType.MORPH_RELATION)
|
||||
);
|
||||
};
|
||||
+1
-1
@@ -18,7 +18,7 @@ export class RestApiDeleteOneHandler extends RestApiBaseHandler {
|
||||
const { objectMetadata, repository, restrictedFields } =
|
||||
await this.getRepositoryAndMetadataOrFail(request);
|
||||
|
||||
const selectOptions = this.getSelectOptionsFromRestrictedFields({
|
||||
const selectOptions = this.getAllSelectableFields({
|
||||
restrictedFields,
|
||||
objectMetadata,
|
||||
});
|
||||
|
||||
+4
-2
@@ -23,7 +23,9 @@ export class RestApiUpdateOneHandler extends RestApiBaseHandler {
|
||||
const { objectMetadata, repository, restrictedFields } =
|
||||
await this.getRepositoryAndMetadataOrFail(request);
|
||||
|
||||
const recordToUpdate = await repository.findOneOrFail({
|
||||
// assert the record exists
|
||||
await repository.findOneOrFail({
|
||||
select: { id: true },
|
||||
where: { id: recordId },
|
||||
});
|
||||
|
||||
@@ -33,7 +35,7 @@ export class RestApiUpdateOneHandler extends RestApiBaseHandler {
|
||||
});
|
||||
|
||||
const updatedRecord = await repository.save({
|
||||
...recordToUpdate,
|
||||
id: recordId,
|
||||
...overriddenBody,
|
||||
});
|
||||
|
||||
|
||||
@@ -266,7 +266,7 @@ export abstract class RestApiBaseHandler {
|
||||
let selectOptions = undefined;
|
||||
|
||||
if (!isEmpty(restrictedFields)) {
|
||||
selectOptions = this.getSelectOptionsFromRestrictedFields({
|
||||
selectOptions = this.getAllSelectableFields({
|
||||
restrictedFields,
|
||||
objectMetadata,
|
||||
});
|
||||
@@ -311,7 +311,7 @@ export abstract class RestApiBaseHandler {
|
||||
};
|
||||
}
|
||||
|
||||
public getSelectOptionsFromRestrictedFields({
|
||||
public getAllSelectableFields({
|
||||
restrictedFields,
|
||||
objectMetadata,
|
||||
}: {
|
||||
@@ -406,7 +406,9 @@ export abstract class RestApiBaseHandler {
|
||||
const objectMetadataNameSingular =
|
||||
objectMetadata.objectMetadataMapItem.nameSingular;
|
||||
|
||||
const qb = repository.createQueryBuilder(objectMetadataNameSingular);
|
||||
const qb = repository
|
||||
.createQueryBuilder(objectMetadataNameSingular)
|
||||
.select('id');
|
||||
|
||||
const inputs = this.getVariablesFactory.create(
|
||||
recordId,
|
||||
|
||||
Reference in New Issue
Block a user