Add call recording schema and meeting bot scaffold (#21584)
## Summary - add 2.13 upgrade commands for call recording request status and dropping CalendarEvent recordingPreference - remove the recording preference from the core CalendarEvent standard object - add a scaffold-generated twenty-meeting-bot app with logo and the CalendarEvent meetingBotPreference field ## Tests - yarn install - yarn lint - yarn twenty dev:typecheck - git diff --check <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21584?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
This commit is contained in:
+109
-3
@@ -1,9 +1,12 @@
|
||||
import { Command } from 'nest-commander';
|
||||
import { TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER } from 'twenty-shared/application';
|
||||
import {
|
||||
STANDARD_OBJECTS,
|
||||
STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS,
|
||||
} from 'twenty-shared/metadata';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { ActiveOrSuspendedWorkspaceCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspace.command-runner';
|
||||
import { WorkspaceIteratorService } from 'src/database/commands/command-runners/workspace-iterator.service';
|
||||
@@ -12,6 +15,7 @@ import { buildNavigationCommandMenuItemOperationsOrThrow } from 'src/database/co
|
||||
import {
|
||||
buildCalendarEventFieldRenameUpdates,
|
||||
buildCallRecordingObjectRenameUpdates,
|
||||
LEGACY_CALENDAR_EVENT_RECORDING_PREFERENCE_FIELD_UNIVERSAL_IDENTIFIER,
|
||||
} from 'src/database/commands/upgrade-version-command/2-10/utils/call-recording-name-collision.util';
|
||||
import {
|
||||
getExistingOrStandardFlatEntityOrThrow,
|
||||
@@ -43,7 +47,6 @@ const CALL_RECORDING_OBJECT_METADATA_UNIVERSAL_IDENTIFIERS = [
|
||||
|
||||
const CALL_RECORDING_FIELD_METADATA_UNIVERSAL_IDENTIFIERS = [
|
||||
...getUniversalIdentifiers(STANDARD_OBJECTS.callRecording.fields),
|
||||
STANDARD_OBJECTS.calendarEvent.fields.recordingPreference.universalIdentifier,
|
||||
STANDARD_OBJECTS.calendarEvent.fields.callRecordings.universalIdentifier,
|
||||
];
|
||||
|
||||
@@ -92,6 +95,91 @@ const CALL_RECORDING_PAGE_LAYOUT_WIDGET_UNIVERSAL_IDENTIFIERS = [
|
||||
.timeline.widgets.timeline.universalIdentifier,
|
||||
];
|
||||
|
||||
// Preserves the shipped 2.10 upgrade path after recordingPreference moved out of
|
||||
// current standard metadata.
|
||||
const buildLegacyCalendarEventRecordingPreferenceFieldMetadata = ({
|
||||
calendarEventObjectMetadata,
|
||||
now,
|
||||
twentyStandardApplicationId,
|
||||
workspaceId,
|
||||
}: {
|
||||
calendarEventObjectMetadata: FlatObjectMetadata;
|
||||
now: string;
|
||||
twentyStandardApplicationId: string;
|
||||
workspaceId: string;
|
||||
}): FlatFieldMetadata<FieldMetadataType.SELECT> => ({
|
||||
id: uuidv4(),
|
||||
universalIdentifier:
|
||||
LEGACY_CALENDAR_EVENT_RECORDING_PREFERENCE_FIELD_UNIVERSAL_IDENTIFIER,
|
||||
applicationId: twentyStandardApplicationId,
|
||||
workspaceId,
|
||||
objectMetadataId: calendarEventObjectMetadata.id,
|
||||
type: FieldMetadataType.SELECT,
|
||||
name: 'recordingPreference',
|
||||
label: 'Recording Preference',
|
||||
description:
|
||||
'Whether to record this event, applied on top of the workspace policy',
|
||||
icon: 'IconSettingsAutomation',
|
||||
isActive: true,
|
||||
isSystem: false,
|
||||
isNullable: false,
|
||||
isUnique: false,
|
||||
isUIEditable: true,
|
||||
isLabelSyncedWithName: false,
|
||||
standardOverrides: null,
|
||||
defaultValue: "'AUTO'",
|
||||
settings: null,
|
||||
options: [
|
||||
{
|
||||
id: '4c4761ce-ffbf-4176-be7f-5cf5257c8bff',
|
||||
value: 'AUTO',
|
||||
label: 'Auto',
|
||||
position: 0,
|
||||
color: 'blue',
|
||||
},
|
||||
{
|
||||
id: '1ae19135-e1a1-4a96-b866-91643622e554',
|
||||
value: 'ON',
|
||||
label: 'On',
|
||||
position: 1,
|
||||
color: 'green',
|
||||
},
|
||||
{
|
||||
id: '8c69a74f-2ab7-4c19-a813-eb0ea3533fd3',
|
||||
value: 'OFF',
|
||||
label: 'Off',
|
||||
position: 2,
|
||||
color: 'gray',
|
||||
},
|
||||
],
|
||||
relationTargetFieldMetadataId: null,
|
||||
relationTargetObjectMetadataId: null,
|
||||
morphId: null,
|
||||
viewFieldIds: [],
|
||||
viewFilterIds: [],
|
||||
fieldPermissionIds: [],
|
||||
kanbanAggregateOperationViewIds: [],
|
||||
calendarViewIds: [],
|
||||
mainGroupByFieldMetadataViewIds: [],
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
applicationUniversalIdentifier:
|
||||
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
objectMetadataUniversalIdentifier:
|
||||
STANDARD_OBJECTS.calendarEvent.universalIdentifier,
|
||||
relationTargetObjectMetadataUniversalIdentifier: null,
|
||||
relationTargetFieldMetadataUniversalIdentifier: null,
|
||||
viewFilterUniversalIdentifiers: [],
|
||||
viewFieldUniversalIdentifiers: [],
|
||||
fieldPermissionUniversalIdentifiers: [],
|
||||
kanbanAggregateOperationViewUniversalIdentifiers: [],
|
||||
calendarViewUniversalIdentifiers: [],
|
||||
mainGroupByFieldMetadataViewUniversalIdentifiers: [],
|
||||
viewSortIds: [],
|
||||
viewSortUniversalIdentifiers: [],
|
||||
universalSettings: null,
|
||||
});
|
||||
|
||||
@RegisteredWorkspaceCommand('2.10.0', 1799000055000)
|
||||
@Command({
|
||||
name: 'upgrade:2-10:sync-call-recording-standard-objects',
|
||||
@@ -200,6 +288,22 @@ export class SyncCallRecordingStandardObjectsCommand extends ActiveOrSuspendedWo
|
||||
renamedCollisionObjectMetadatas,
|
||||
});
|
||||
|
||||
const legacyCalendarEventRecordingPreferenceFieldMetadata =
|
||||
flatFieldMetadataMaps.byUniversalIdentifier[
|
||||
LEGACY_CALENDAR_EVENT_RECORDING_PREFERENCE_FIELD_UNIVERSAL_IDENTIFIER
|
||||
];
|
||||
const legacyCalendarEventRecordingPreferenceFieldMetadataToCreate =
|
||||
isDefined(legacyCalendarEventRecordingPreferenceFieldMetadata)
|
||||
? []
|
||||
: [
|
||||
buildLegacyCalendarEventRecordingPreferenceFieldMetadata({
|
||||
calendarEventObjectMetadata,
|
||||
now,
|
||||
twentyStandardApplicationId: twentyStandardFlatApplication.id,
|
||||
workspaceId,
|
||||
}),
|
||||
];
|
||||
|
||||
const allFlatEntityOperationByMetadataName = {
|
||||
objectMetadata: {
|
||||
flatEntityToCreate:
|
||||
@@ -214,14 +318,16 @@ export class SyncCallRecordingStandardObjectsCommand extends ActiveOrSuspendedWo
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
fieldMetadata: {
|
||||
flatEntityToCreate:
|
||||
getStandardFlatEntitiesToCreateOrThrow<FlatFieldMetadata>({
|
||||
flatEntityToCreate: [
|
||||
...getStandardFlatEntitiesToCreateOrThrow<FlatFieldMetadata>({
|
||||
standardFlatEntityMaps:
|
||||
standardAllFlatEntityMaps.flatFieldMetadataMaps,
|
||||
existingFlatEntityMaps: flatFieldMetadataMaps,
|
||||
universalIdentifiers:
|
||||
CALL_RECORDING_FIELD_METADATA_UNIVERSAL_IDENTIFIERS,
|
||||
}),
|
||||
...legacyCalendarEventRecordingPreferenceFieldMetadataToCreate,
|
||||
],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
|
||||
+2
-2
@@ -6,6 +6,7 @@ import {
|
||||
buildCallRecordingObjectRenameUpdates,
|
||||
findCalendarEventFieldNameCollisionsForCallRecording,
|
||||
findCallRecordingObjectNameCollisions,
|
||||
LEGACY_CALENDAR_EVENT_RECORDING_PREFERENCE_FIELD_UNIVERSAL_IDENTIFIER,
|
||||
resolveAvailableOldCalendarEventFieldName,
|
||||
resolveAvailableOldCallRecordingObjectNames,
|
||||
} from 'src/database/commands/upgrade-version-command/2-10/utils/call-recording-name-collision.util';
|
||||
@@ -327,8 +328,7 @@ describe('findCalendarEventFieldNameCollisionsForCallRecording', () => {
|
||||
const maps = buildFlatFieldMetadataMaps([
|
||||
getCalendarEventFieldMetadataMock({
|
||||
universalIdentifier:
|
||||
STANDARD_OBJECTS.calendarEvent.fields.recordingPreference
|
||||
.universalIdentifier,
|
||||
LEGACY_CALENDAR_EVENT_RECORDING_PREFERENCE_FIELD_UNIVERSAL_IDENTIFIER,
|
||||
name: 'recordingPreference',
|
||||
}),
|
||||
getCalendarEventFieldMetadataMock({
|
||||
|
||||
+4
-2
@@ -15,6 +15,9 @@ const FIELD_OLD_NAME_SUFFIX = 'Old';
|
||||
const FIELD_OLD_LABEL_SUFFIX = ' (Old)';
|
||||
const MAX_OLD_NAME_ATTEMPTS = 100;
|
||||
|
||||
export const LEGACY_CALENDAR_EVENT_RECORDING_PREFERENCE_FIELD_UNIVERSAL_IDENTIFIER =
|
||||
'1d231e7e-9bbe-410b-8007-ea7678a83e58';
|
||||
|
||||
const CALL_RECORDING_CALENDAR_EVENT_FIELD_NAMES = [
|
||||
CALENDAR_EVENT_RECORDING_PREFERENCE_FIELD_NAME,
|
||||
CALENDAR_EVENT_CALL_RECORDINGS_FIELD_NAME,
|
||||
@@ -22,8 +25,7 @@ const CALL_RECORDING_CALENDAR_EVENT_FIELD_NAMES = [
|
||||
|
||||
const CALL_RECORDING_CALENDAR_EVENT_FIELD_UNIVERSAL_IDENTIFIERS =
|
||||
new Set<string>([
|
||||
STANDARD_OBJECTS.calendarEvent.fields.recordingPreference
|
||||
.universalIdentifier,
|
||||
LEGACY_CALENDAR_EVENT_RECORDING_PREFERENCE_FIELD_UNIVERSAL_IDENTIFIER,
|
||||
STANDARD_OBJECTS.calendarEvent.fields.callRecordings.universalIdentifier,
|
||||
]);
|
||||
|
||||
|
||||
+7
-1
@@ -1,6 +1,8 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { WorkspaceIteratorModule } from 'src/database/commands/command-runners/workspace-iterator.module';
|
||||
import { SyncCallRecordingRequestStatusCommand } from 'src/database/commands/upgrade-version-command/2-14/2-14-workspace-command-1799000065000-sync-call-recording-request-status.command';
|
||||
import { DropCalendarEventRecordingPreferenceCommand } from 'src/database/commands/upgrade-version-command/2-14/2-14-workspace-command-1799000066000-drop-calendar-event-recording-preference.command';
|
||||
import { FixStandardRelationFieldLabelsIconsCommand } from 'src/database/commands/upgrade-version-command/2-14/2-14-workspace-command-1799000040000-fix-standard-relation-field-labels-icons.command';
|
||||
import { ApplicationModule } from 'src/engine/core-modules/application/application.module';
|
||||
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
|
||||
@@ -13,6 +15,10 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace
|
||||
WorkspaceIteratorModule,
|
||||
WorkspaceMigrationModule,
|
||||
],
|
||||
providers: [FixStandardRelationFieldLabelsIconsCommand],
|
||||
providers: [
|
||||
FixStandardRelationFieldLabelsIconsCommand,
|
||||
SyncCallRecordingRequestStatusCommand,
|
||||
DropCalendarEventRecordingPreferenceCommand,
|
||||
],
|
||||
})
|
||||
export class V2_14_UpgradeVersionCommandModule {}
|
||||
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
import { Command } from 'nest-commander';
|
||||
|
||||
import { STANDARD_OBJECTS } from 'twenty-shared/metadata';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ActiveOrSuspendedWorkspaceCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspace.command-runner';
|
||||
import { WorkspaceIteratorService } from 'src/database/commands/command-runners/workspace-iterator.service';
|
||||
import { type RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspace.command-runner';
|
||||
import { getStandardFlatEntitiesToCreateOrThrow } from 'src/database/commands/upgrade-version-command/2-10/utils/get-standard-flat-entities-to-create-or-throw.util';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { RegisteredWorkspaceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-workspace-command.decorator';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { type FlatViewField } from 'src/engine/metadata-modules/flat-view-field/types/flat-view-field.type';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import { computeTwentyStandardApplicationAllFlatEntityMaps } from 'src/engine/workspace-manager/twenty-standard-application/utils/twenty-standard-application-all-flat-entity-maps.constant';
|
||||
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
|
||||
|
||||
const CALL_RECORDING_OBJECT_UNIVERSAL_IDENTIFIER =
|
||||
STANDARD_OBJECTS.callRecording.universalIdentifier;
|
||||
const CALL_RECORDING_REQUEST_STATUS_FIELD_UNIVERSAL_IDENTIFIER =
|
||||
STANDARD_OBJECTS.callRecording.fields.recordingRequestStatus
|
||||
.universalIdentifier;
|
||||
const CALL_RECORDING_REQUEST_STATUS_VIEW_FIELD_UNIVERSAL_IDENTIFIERS = [
|
||||
STANDARD_OBJECTS.callRecording.views.allCallRecordings.viewFields
|
||||
.recordingRequestStatus.universalIdentifier,
|
||||
STANDARD_OBJECTS.callRecording.views.callRecordingRecordPageFields.viewFields
|
||||
.recordingRequestStatus.universalIdentifier,
|
||||
];
|
||||
const CALL_RECORDING_REQUEST_STATUS_FIELD_NAME = 'recordingRequestStatus';
|
||||
|
||||
@RegisteredWorkspaceCommand('2.14.0', 1799000065000)
|
||||
@Command({
|
||||
name: 'upgrade:2-14:sync-call-recording-request-status',
|
||||
description:
|
||||
'Create the CallRecording recordingRequestStatus metadata in existing workspaces',
|
||||
})
|
||||
export class SyncCallRecordingRequestStatusCommand extends ActiveOrSuspendedWorkspaceCommandRunner {
|
||||
constructor(
|
||||
protected readonly workspaceIteratorService: WorkspaceIteratorService,
|
||||
private readonly applicationService: ApplicationService,
|
||||
private readonly workspaceCacheService: WorkspaceCacheService,
|
||||
private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService,
|
||||
) {
|
||||
super(workspaceIteratorService);
|
||||
}
|
||||
|
||||
override async runOnWorkspace({
|
||||
workspaceId,
|
||||
options,
|
||||
}: RunOnWorkspaceArgs): Promise<void> {
|
||||
const isDryRun = options.dryRun ?? false;
|
||||
|
||||
const { twentyStandardFlatApplication } =
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{ workspaceId },
|
||||
);
|
||||
|
||||
const { flatFieldMetadataMaps, flatObjectMetadataMaps, flatViewFieldMaps } =
|
||||
await this.workspaceCacheService.getOrRecompute(workspaceId, [
|
||||
'flatFieldMetadataMaps',
|
||||
'flatObjectMetadataMaps',
|
||||
'flatViewFieldMaps',
|
||||
]);
|
||||
|
||||
const existingCallRecordingObjectMetadata =
|
||||
flatObjectMetadataMaps.byUniversalIdentifier[
|
||||
CALL_RECORDING_OBJECT_UNIVERSAL_IDENTIFIER
|
||||
];
|
||||
|
||||
if (!isDefined(existingCallRecordingObjectMetadata)) {
|
||||
this.logger.log(
|
||||
`CallRecording object metadata does not exist for workspace ${workspaceId}, skipping`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const existingRecordingRequestStatusField =
|
||||
flatFieldMetadataMaps.byUniversalIdentifier[
|
||||
CALL_RECORDING_REQUEST_STATUS_FIELD_UNIVERSAL_IDENTIFIER
|
||||
];
|
||||
|
||||
if (
|
||||
!isDefined(existingRecordingRequestStatusField) &&
|
||||
hasFieldNameConflict({
|
||||
flatFieldMetadatas: Object.values(
|
||||
flatFieldMetadataMaps.byUniversalIdentifier,
|
||||
).filter(isDefined),
|
||||
callRecordingObjectMetadata: existingCallRecordingObjectMetadata,
|
||||
})
|
||||
) {
|
||||
this.logger.warn(
|
||||
`Field name "${CALL_RECORDING_REQUEST_STATUS_FIELD_NAME}" is already taken on CallRecording for workspace ${workspaceId}; skipping`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const { allFlatEntityMaps: standardAllFlatEntityMaps } =
|
||||
computeTwentyStandardApplicationAllFlatEntityMaps({
|
||||
now: new Date().toISOString(),
|
||||
workspaceId,
|
||||
twentyStandardApplicationId: twentyStandardFlatApplication.id,
|
||||
});
|
||||
|
||||
const recordingRequestStatusFieldsToCreate =
|
||||
getStandardFlatEntitiesToCreateOrThrow<FlatFieldMetadata>({
|
||||
standardFlatEntityMaps: standardAllFlatEntityMaps.flatFieldMetadataMaps,
|
||||
existingFlatEntityMaps: flatFieldMetadataMaps,
|
||||
universalIdentifiers: [
|
||||
CALL_RECORDING_REQUEST_STATUS_FIELD_UNIVERSAL_IDENTIFIER,
|
||||
],
|
||||
});
|
||||
const recordingRequestStatusViewFieldsToCreate =
|
||||
getStandardFlatEntitiesToCreateOrThrow<FlatViewField>({
|
||||
standardFlatEntityMaps: standardAllFlatEntityMaps.flatViewFieldMaps,
|
||||
existingFlatEntityMaps: flatViewFieldMaps,
|
||||
universalIdentifiers:
|
||||
CALL_RECORDING_REQUEST_STATUS_VIEW_FIELD_UNIVERSAL_IDENTIFIERS,
|
||||
});
|
||||
|
||||
const totalOperationCount =
|
||||
recordingRequestStatusFieldsToCreate.length +
|
||||
recordingRequestStatusViewFieldsToCreate.length;
|
||||
|
||||
if (totalOperationCount === 0) {
|
||||
this.logger.log(
|
||||
`CallRecording recordingRequestStatus metadata already exists for workspace ${workspaceId}, skipping`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`${isDryRun ? '[DRY RUN] ' : ''}Creating ${totalOperationCount} CallRecording recordingRequestStatus metadata item(s) for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
if (isDryRun) {
|
||||
return;
|
||||
}
|
||||
|
||||
const validateAndBuildResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
isSystemBuild: true,
|
||||
applicationUniversalIdentifier:
|
||||
twentyStandardFlatApplication.universalIdentifier,
|
||||
workspaceId,
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
fieldMetadata: {
|
||||
flatEntityToCreate: recordingRequestStatusFieldsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
viewField: {
|
||||
flatEntityToCreate: recordingRequestStatusViewFieldsToCreate,
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (validateAndBuildResult.status === 'fail') {
|
||||
throw new Error(
|
||||
`Failed to create CallRecording recordingRequestStatus metadata for workspace ${workspaceId}: ${JSON.stringify(
|
||||
validateAndBuildResult,
|
||||
null,
|
||||
2,
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`Created ${totalOperationCount} CallRecording recordingRequestStatus metadata item(s) for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const hasFieldNameConflict = ({
|
||||
flatFieldMetadatas,
|
||||
callRecordingObjectMetadata,
|
||||
}: {
|
||||
flatFieldMetadatas: FlatFieldMetadata[];
|
||||
callRecordingObjectMetadata: FlatObjectMetadata;
|
||||
}): boolean =>
|
||||
flatFieldMetadatas.some(
|
||||
(flatFieldMetadata) =>
|
||||
flatFieldMetadata.objectMetadataUniversalIdentifier ===
|
||||
callRecordingObjectMetadata.universalIdentifier &&
|
||||
flatFieldMetadata.name === CALL_RECORDING_REQUEST_STATUS_FIELD_NAME,
|
||||
);
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
import { Command } from 'nest-commander';
|
||||
|
||||
import { ActiveOrSuspendedWorkspaceCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspace.command-runner';
|
||||
import { WorkspaceIteratorService } from 'src/database/commands/command-runners/workspace-iterator.service';
|
||||
import { type RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspace.command-runner';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { RegisteredWorkspaceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-workspace-command.decorator';
|
||||
import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
|
||||
|
||||
const CALENDAR_EVENT_RECORDING_PREFERENCE_FIELD_UNIVERSAL_IDENTIFIER =
|
||||
'1d231e7e-9bbe-410b-8007-ea7678a83e58';
|
||||
|
||||
@RegisteredWorkspaceCommand('2.14.0', 1799000066000)
|
||||
@Command({
|
||||
name: 'upgrade:2-14:drop-calendar-event-recording-preference',
|
||||
description: 'Drop the CalendarEvent recordingPreference field metadata',
|
||||
})
|
||||
export class DropCalendarEventRecordingPreferenceCommand extends ActiveOrSuspendedWorkspaceCommandRunner {
|
||||
constructor(
|
||||
protected readonly workspaceIteratorService: WorkspaceIteratorService,
|
||||
private readonly applicationService: ApplicationService,
|
||||
private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService,
|
||||
private readonly workspaceCacheService: WorkspaceCacheService,
|
||||
) {
|
||||
super(workspaceIteratorService);
|
||||
}
|
||||
|
||||
override async runOnWorkspace({
|
||||
workspaceId,
|
||||
options,
|
||||
}: RunOnWorkspaceArgs): Promise<void> {
|
||||
const isDryRun = options.dryRun ?? false;
|
||||
|
||||
this.logger.log(
|
||||
`${isDryRun ? '[DRY RUN] ' : ''}Starting CalendarEvent recordingPreference field removal for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
const { flatFieldMetadataMaps } =
|
||||
await this.workspaceCacheService.getOrRecompute(workspaceId, [
|
||||
'flatFieldMetadataMaps',
|
||||
]);
|
||||
|
||||
const recordingPreferenceFieldMetadata =
|
||||
findFlatEntityByUniversalIdentifier<FlatFieldMetadata>({
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
universalIdentifier:
|
||||
CALENDAR_EVENT_RECORDING_PREFERENCE_FIELD_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
|
||||
if (!recordingPreferenceFieldMetadata) {
|
||||
this.logger.log(
|
||||
`CalendarEvent recordingPreference field already absent for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDryRun) {
|
||||
this.logger.log(
|
||||
`[DRY RUN] Would delete CalendarEvent recordingPreference field for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const { twentyStandardFlatApplication } =
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{ workspaceId },
|
||||
);
|
||||
|
||||
const validateAndBuildResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
isSystemBuild: true,
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
fieldMetadata: {
|
||||
flatEntityToCreate: [],
|
||||
flatEntityToDelete: [recordingPreferenceFieldMetadata],
|
||||
flatEntityToUpdate: [],
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier:
|
||||
twentyStandardFlatApplication.universalIdentifier,
|
||||
},
|
||||
);
|
||||
|
||||
if (validateAndBuildResult.status === 'fail') {
|
||||
this.logger.error(
|
||||
`Failed to delete CalendarEvent recordingPreference field:\n${JSON.stringify(
|
||||
validateAndBuildResult,
|
||||
null,
|
||||
2,
|
||||
)}`,
|
||||
);
|
||||
|
||||
throw new Error(
|
||||
`Failed to delete CalendarEvent recordingPreference field for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`Deleted CalendarEvent recordingPreference field for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user