diff --git a/packages/twenty-server/src/engine/api/rest/core/handlers/rest-api-create-many.handler.ts b/packages/twenty-server/src/engine/api/rest/core/handlers/rest-api-create-many.handler.ts index 5c23275fd3..c5f42237bf 100644 --- a/packages/twenty-server/src/engine/api/rest/core/handlers/rest-api-create-many.handler.ts +++ b/packages/twenty-server/src/engine/api/rest/core/handlers/rest-api-create-many.handler.ts @@ -5,10 +5,13 @@ import { } from '@nestjs/common'; import { type Request } from 'express'; +import isEmpty from 'lodash.isempty'; import { isDefined } from 'twenty-shared/utils'; import { RestApiBaseHandler } from 'src/engine/api/rest/core/interfaces/rest-api-base.handler'; +import { getAllSelectableFields } from 'src/engine/api/utils/get-all-selectable-fields.utils'; + @Injectable() export class RestApiCreateManyHandler extends RestApiBaseHandler { async handle(request: Request) { @@ -56,7 +59,24 @@ export class RestApiCreateManyHandler extends RestApiBaseHandler { this.getAuthContextFromRequest(request), ); - const createdRecords = await repository.insert(recordsToCreate); + let selectedColumns = undefined; + + if (!isEmpty(restrictedFields)) { + const selectableFields = getAllSelectableFields({ + restrictedFields, + objectMetadata, + }); + + selectedColumns = Object.keys(selectableFields).filter( + (key) => selectableFields[key], + ); + } + + const createdRecords = await repository.insert( + recordsToCreate, + undefined, + selectedColumns, + ); const createdRecordsIds = createdRecords.identifiers.map( (record) => record.id, ); diff --git a/packages/twenty-server/src/engine/api/rest/core/handlers/rest-api-create-one.handler.ts b/packages/twenty-server/src/engine/api/rest/core/handlers/rest-api-create-one.handler.ts index 0263a97c91..47a1e6d90e 100644 --- a/packages/twenty-server/src/engine/api/rest/core/handlers/rest-api-create-one.handler.ts +++ b/packages/twenty-server/src/engine/api/rest/core/handlers/rest-api-create-one.handler.ts @@ -5,10 +5,13 @@ import { } from '@nestjs/common'; import { type Request } from 'express'; +import isEmpty from 'lodash.isempty'; import { isDefined } from 'twenty-shared/utils'; import { RestApiBaseHandler } from 'src/engine/api/rest/core/interfaces/rest-api-base.handler'; +import { getAllSelectableFields } from 'src/engine/api/utils/get-all-selectable-fields.utils'; + @Injectable() export class RestApiCreateOneHandler extends RestApiBaseHandler { async handle(request: Request) { @@ -39,7 +42,24 @@ export class RestApiCreateOneHandler extends RestApiBaseHandler { this.getAuthContextFromRequest(request), ); - const createdRecordResult = await repository.insert(recordToCreate); + let selectedColumns = undefined; + + if (!isEmpty(restrictedFields)) { + const selectableFields = getAllSelectableFields({ + restrictedFields, + objectMetadata, + }); + + selectedColumns = Object.keys(selectableFields).filter( + (key) => selectableFields[key], + ); + } + + const createdRecordResult = await repository.insert( + recordToCreate, + undefined, + selectedColumns, + ); const createdRecord = createdRecordResult.identifiers[0]; const records = await this.getRecord({ diff --git a/packages/twenty-server/src/engine/api/rest/core/handlers/rest-api-update-one.handler.ts b/packages/twenty-server/src/engine/api/rest/core/handlers/rest-api-update-one.handler.ts index e930042e5c..43dcd495e1 100644 --- a/packages/twenty-server/src/engine/api/rest/core/handlers/rest-api-update-one.handler.ts +++ b/packages/twenty-server/src/engine/api/rest/core/handlers/rest-api-update-one.handler.ts @@ -5,11 +5,13 @@ import { } from '@nestjs/common'; import { type Request } from 'express'; +import isEmpty from 'lodash.isempty'; import { isDefined } from 'twenty-shared/utils'; import { RestApiBaseHandler } from 'src/engine/api/rest/core/interfaces/rest-api-base.handler'; import { parseCorePath } from 'src/engine/api/rest/core/query-builder/utils/path-parsers/parse-core-path.utils'; +import { getAllSelectableFields } from 'src/engine/api/utils/get-all-selectable-fields.utils'; @Injectable() export class RestApiUpdateOneHandler extends RestApiBaseHandler { @@ -34,7 +36,25 @@ export class RestApiUpdateOneHandler extends RestApiBaseHandler { objectMetadataMapItem: objectMetadata.objectMetadataMapItem, }); - const updatedRecord = await repository.update(recordId, overriddenBody); + let selectedColumns = undefined; + + if (!isEmpty(restrictedFields)) { + const selectableFields = getAllSelectableFields({ + restrictedFields, + objectMetadata, + }); + + selectedColumns = Object.keys(selectableFields).filter( + (key) => selectableFields[key], + ); + } + + const updatedRecord = await repository.update( + recordId, + overriddenBody, + undefined, + selectedColumns, + ); const updatedRecordId = updatedRecord.generatedMaps[0].id; diff --git a/packages/twenty-server/src/engine/core-modules/actor/services/created-by-from-auth-context.service.ts b/packages/twenty-server/src/engine/core-modules/actor/services/created-by-from-auth-context.service.ts index 61ab8babfd..04bd03c762 100644 --- a/packages/twenty-server/src/engine/core-modules/actor/services/created-by-from-auth-context.service.ts +++ b/packages/twenty-server/src/engine/core-modules/actor/services/created-by-from-auth-context.service.ts @@ -1,12 +1,17 @@ import { Injectable, Logger } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; import { isDefined } from 'twenty-shared/utils'; +import { Repository } from 'typeorm'; import { buildCreatedByFromApiKey } from 'src/engine/core-modules/actor/utils/build-created-by-from-api-key.util'; import { buildCreatedByFromFullNameMetadata } from 'src/engine/core-modules/actor/utils/build-created-by-from-full-name-metadata.util'; import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate'; import { type ActorMetadata } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type'; +import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; +import { getObjectMetadataMapItemByNameSingular } from 'src/engine/metadata-modules/utils/get-object-metadata-map-item-by-name-singular.util'; +import { WorkspaceMetadataCacheService } from 'src/engine/metadata-modules/workspace-metadata-cache/services/workspace-metadata-cache.service'; import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; import { type WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; @@ -18,18 +23,37 @@ export class CreatedByFromAuthContextService { private readonly logger = new Logger(CreatedByFromAuthContextService.name); constructor( + @InjectRepository(FieldMetadataEntity) + private readonly fieldMetadataRepository: Repository, private readonly twentyORMGlobalManager: TwentyORMGlobalManager, + private readonly workspaceMetadataCacheService: WorkspaceMetadataCacheService, ) {} async injectCreatedBy( records: CreateInput[], - _objectMetadataNameSingular: string, + objectMetadataNameSingular: string, authContext: AuthContext, ): Promise { const workspace = authContext.workspace; workspaceValidator.assertIsDefinedOrThrow(workspace); + const { objectMetadataMaps } = + await this.workspaceMetadataCacheService.getExistingOrRecomputeMetadataMaps( + { + workspaceId: workspace.id, + }, + ); + + const objectMetadata = getObjectMetadataMapItemByNameSingular( + objectMetadataMaps, + objectMetadataNameSingular, + ); + + if (!isDefined(objectMetadata?.fieldIdByName['createdBy'])) { + return records; + } + const clonedRecords = structuredClone(records); const createdBy = await this.buildCreatedBy(authContext);