Skip to content

Commit

Permalink
6382 create a command to add a uservar in the key value pair table fo…
Browse files Browse the repository at this point in the history
…r every account which needs to reconnect (#6553)

Closes #6382

Create SetUserVarsAccountsToReconnectCommand.
This command loops on all workspaces and:
- deletes all user vars with deprecated key `ACCOUNTS_TO_RECONNECT`
- creates a key value pair of type `USER_VAR` with a key of
`ACCOUNTS_TO_RECONNECT_INSUFFICIENT_PERMISSIONS` for all connect
accounts with a message channel or calendar channel with status
`FAILED_INSUFFICIENT_PERMISSIONS`
  • Loading branch information
bosiraphael authored Aug 7, 2024
1 parent 2abb6ad commit 5a72b94
Show file tree
Hide file tree
Showing 9 changed files with 220 additions and 62 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import { Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';

import chalk from 'chalk';
import { Command, CommandRunner, Option } from 'nest-commander';
import { Repository } from 'typeorm';

import {
KeyValuePair,
KeyValuePairType,
} from 'src/engine/core-modules/key-value-pair/key-value-pair.entity';
import {
Workspace,
WorkspaceActivationStatus,
} from 'src/engine/core-modules/workspace/workspace.entity';
import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.service';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { CalendarChannelSyncStatus } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity';
import { AccountsToReconnectService } from 'src/modules/connected-account/services/accounts-to-reconnect.service';
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
import { AccountsToReconnectKeys } from 'src/modules/connected-account/types/accounts-to-reconnect-key-value.type';
import { MessageChannelSyncStatus } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';

interface SetUserVarsAccountsToReconnectCommandOptions {
workspaceId?: string;
}

@Command({
name: 'upgrade-0.23:set-user-vars-accounts-to-reconnect',
description: 'Set user vars accounts to reconnect',
})
export class SetUserVarsAccountsToReconnectCommand extends CommandRunner {
private readonly logger = new Logger(
SetUserVarsAccountsToReconnectCommand.name,
);
constructor(
private readonly workspaceCacheVersionService: WorkspaceCacheVersionService,
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
private readonly accountsToReconnectService: AccountsToReconnectService,
@InjectRepository(KeyValuePair, 'core')
private readonly keyValuePairRepository: Repository<KeyValuePair>,
@InjectRepository(Workspace, 'core')
private readonly workspaceRepository: Repository<Workspace>,
) {
super();
}

@Option({
flags: '-w, --workspace-id [workspace_id]',
description: 'workspace id. Command runs on all workspaces if not provided',
required: false,
})
parseWorkspaceId(value: string): string {
return value;
}

async run(
_passedParam: string[],
options: SetUserVarsAccountsToReconnectCommandOptions,
): Promise<void> {
let activeWorkspaceIds: string[] = [];

if (options.workspaceId) {
activeWorkspaceIds = [options.workspaceId];
} else {
const activeWorkspaces = await this.workspaceRepository.find({
where: {
activationStatus: WorkspaceActivationStatus.ACTIVE,
...(options.workspaceId && { id: options.workspaceId }),
},
});

activeWorkspaceIds = activeWorkspaces.map((workspace) => workspace.id);
}

if (!activeWorkspaceIds.length) {
this.logger.log(chalk.yellow('No workspace found'));

return;
} else {
this.logger.log(
chalk.green(
`Running command on ${activeWorkspaceIds.length} workspaces`,
),
);
}

// Remove all deprecated user vars
await this.keyValuePairRepository.delete({
type: KeyValuePairType.USER_VAR,
key: 'ACCOUNTS_TO_RECONNECT',
});

for (const workspaceId of activeWorkspaceIds) {
try {
const connectedAccountRepository =
await this.twentyORMGlobalManager.getRepositoryForWorkspace<ConnectedAccountWorkspaceEntity>(
workspaceId,
'connectedAccount',
);

try {
const connectedAccountsInFailedInsufficientPermissions =
await connectedAccountRepository.find({
select: {
id: true,
accountOwner: {
userId: true,
},
},
where: [
{
messageChannels: {
syncStatus:
MessageChannelSyncStatus.FAILED_INSUFFICIENT_PERMISSIONS,
},
},
{
calendarChannels: {
syncStatus:
CalendarChannelSyncStatus.FAILED_INSUFFICIENT_PERMISSIONS,
},
},
],
relations: {
accountOwner: true,
},
});

for (const connectedAccount of connectedAccountsInFailedInsufficientPermissions) {
try {
await this.accountsToReconnectService.addAccountToReconnectByKey(
AccountsToReconnectKeys.ACCOUNTS_TO_RECONNECT_INSUFFICIENT_PERMISSIONS,
connectedAccount.accountOwner.userId,
workspaceId,
connectedAccount.id,
);
} catch (error) {
this.logger.error(
`Failed to add account to reconnect for workspace ${workspaceId}: ${error.message}`,
);
throw error;
}
}
} catch (error) {
this.logger.log(
chalk.red(`Running command on workspace ${workspaceId} failed`),
);
throw error;
}

await this.workspaceCacheVersionService.incrementVersion(workspaceId);

this.logger.log(
chalk.green(`Running command on workspace ${workspaceId} done`),
);
} catch (error) {
this.logger.error(
`Migration failed for workspace ${workspaceId}: ${error.message}`,
);
}
}

this.logger.log(chalk.green(`Command completed!`));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,26 +83,16 @@ export class SetWorkspaceActivationStatusCommand extends CommandRunner {
await this.typeORMService.connectToDataSource(dataSourceMetadata);

if (workspaceDataSource) {
const queryRunner = workspaceDataSource.createQueryRunner();

await queryRunner.connect();
await queryRunner.startTransaction();

try {
await this.workspaceRepository.update(
{ id: workspaceId },
{ activationStatus: WorkspaceActivationStatus.ACTIVE },
);

await queryRunner.commitTransaction();
} catch (error) {
await queryRunner.rollbackTransaction();
this.logger.log(
chalk.red(`Running command on workspace ${workspaceId} failed`),
);
throw error;
} finally {
await queryRunner.release();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { BackfillNewOnboardingUserVarsCommand } from 'src/database/commands/upgr
import { MigrateDomainNameFromTextToLinksCommand } from 'src/database/commands/upgrade-version/0-23/0-23-migrate-domain-to-links.command';
import { MigrateLinkFieldsToLinksCommand } from 'src/database/commands/upgrade-version/0-23/0-23-migrate-link-fields-to-links.command';
import { MigrateMessageChannelSyncStatusEnumCommand } from 'src/database/commands/upgrade-version/0-23/0-23-migrate-message-channel-sync-status-enum.command';
import { SetUserVarsAccountsToReconnectCommand } from 'src/database/commands/upgrade-version/0-23/0-23-set-user-vars-accounts-to-reconnect.command';
import { SetWorkspaceActivationStatusCommand } from 'src/database/commands/upgrade-version/0-23/0-23-set-workspace-activation-status.command';
import { UpdateActivitiesCommand } from 'src/database/commands/upgrade-version/0-23/0-23-update-activities.command';
import { UpdateFileFolderStructureCommand } from 'src/database/commands/upgrade-version/0-23/0-23-update-file-folder-structure.command';
Expand All @@ -27,6 +28,7 @@ export class UpgradeTo0_23Command extends CommandRunner {
private readonly setWorkspaceActivationStatusCommand: SetWorkspaceActivationStatusCommand,
private readonly updateActivitiesCommand: UpdateActivitiesCommand,
private readonly backfillNewOnboardingUserVarsCommand: BackfillNewOnboardingUserVarsCommand,
private readonly setUserVarsAccountsToReconnectCommand: SetUserVarsAccountsToReconnectCommand,
) {
super();
}
Expand Down Expand Up @@ -62,5 +64,6 @@ export class UpgradeTo0_23Command extends CommandRunner {
});
await this.updateActivitiesCommand.run(_passedParam, options);
await this.backfillNewOnboardingUserVarsCommand.run(_passedParam, options);
await this.setUserVarsAccountsToReconnectCommand.run(_passedParam, options);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import { BackfillNewOnboardingUserVarsCommand } from 'src/database/commands/upgr
import { MigrateDomainNameFromTextToLinksCommand } from 'src/database/commands/upgrade-version/0-23/0-23-migrate-domain-to-links.command';
import { MigrateLinkFieldsToLinksCommand } from 'src/database/commands/upgrade-version/0-23/0-23-migrate-link-fields-to-links.command';
import { MigrateMessageChannelSyncStatusEnumCommand } from 'src/database/commands/upgrade-version/0-23/0-23-migrate-message-channel-sync-status-enum.command';
import { SetUserVarsAccountsToReconnectCommand } from 'src/database/commands/upgrade-version/0-23/0-23-set-user-vars-accounts-to-reconnect.command';
import { SetWorkspaceActivationStatusCommand } from 'src/database/commands/upgrade-version/0-23/0-23-set-workspace-activation-status.command';
import { UpdateActivitiesCommand } from 'src/database/commands/upgrade-version/0-23/0-23-update-activities.command';
import { UpdateFileFolderStructureCommand } from 'src/database/commands/upgrade-version/0-23/0-23-update-file-folder-structure.command';
import { UpgradeTo0_23Command } from 'src/database/commands/upgrade-version/0-23/0-23-upgrade-version.command';
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
import { BillingModule } from 'src/engine/core-modules/billing/billing.module';
import { KeyValuePair } from 'src/engine/core-modules/key-value-pair/key-value-pair.entity';
import { OnboardingModule } from 'src/engine/core-modules/onboarding/onboarding.module';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { FileStorageModule } from 'src/engine/integrations/file-storage/file-storage.module';
Expand All @@ -22,12 +24,13 @@ import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadat
import { WorkspaceCacheVersionModule } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.module';
import { WorkspaceStatusModule } from 'src/engine/workspace-manager/workspace-status/workspace-manager.module';
import { WorkspaceSyncMetadataCommandsModule } from 'src/engine/workspace-manager/workspace-sync-metadata/commands/workspace-sync-metadata-commands.module';
import { ConnectedAccountModule } from 'src/modules/connected-account/connected-account.module';
import { ViewModule } from 'src/modules/view/view.module';

@Module({
imports: [
TypeOrmModule.forFeature([Workspace, KeyValuePair], 'core'),
WorkspaceSyncMetadataCommandsModule,
TypeOrmModule.forFeature([Workspace], 'core'),
FileStorageModule,
OnboardingModule,
TypeORMModule,
Expand All @@ -42,16 +45,17 @@ import { ViewModule } from 'src/modules/view/view.module';
ViewModule,
BillingModule,
ObjectMetadataModule,
ConnectedAccountModule,
],
providers: [
UpdateFileFolderStructureCommand,
UpgradeTo0_23Command,
MigrateLinkFieldsToLinksCommand,
MigrateDomainNameFromTextToLinksCommand,
MigrateMessageChannelSyncStatusEnumCommand,
SetWorkspaceActivationStatusCommand,
UpdateActivitiesCommand,
BackfillNewOnboardingUserVarsCommand,
SetUserVarsAccountsToReconnectCommand,
UpgradeTo0_23Command,
],
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { TypeOrmModule } from '@nestjs/typeorm';

import { BillingModule } from 'src/engine/core-modules/billing/billing.module';
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
import { UserVarsModule } from 'src/engine/core-modules/user/user-vars/user-vars.module';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module';
Expand All @@ -25,6 +24,7 @@ import { CalendarChannelEventAssociationWorkspaceEntity } from 'src/modules/cale
import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity';
import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity';
import { CalendarEventWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event.workspace-entity';
import { ConnectedAccountModule } from 'src/modules/connected-account/connected-account.module';
import { RefreshAccessTokenManagerModule } from 'src/modules/connected-account/refresh-access-token-manager/refresh-access-token-manager.module';
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity';
Expand Down Expand Up @@ -53,7 +53,7 @@ import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/sta
BillingModule,
RefreshAccessTokenManagerModule,
CalendarEventParticipantManagerModule,
UserVarsModule,
ConnectedAccountModule,
],
providers: [
CalendarChannelSyncStatusService,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Injectable } from '@nestjs/common';

import { UserVarsService } from 'src/engine/core-modules/user/user-vars/services/user-vars.service';
import { CacheStorageService } from 'src/engine/integrations/cache-storage/cache-storage.service';
import { InjectCacheStorage } from 'src/engine/integrations/cache-storage/decorators/cache-storage.decorator';
import { CacheStorageNamespace } from 'src/engine/integrations/cache-storage/types/cache-storage-namespace.enum';
Expand All @@ -10,18 +9,16 @@ import {
CalendarChannelSyncStatus,
CalendarChannelWorkspaceEntity,
} from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity';
import {
AccountsToReconnectKeyValueType,
AccountsToReconnectKeys,
} from 'src/modules/connected-account/types/accounts-to-reconnect-key-value.type';
import { AccountsToReconnectService } from 'src/modules/connected-account/services/accounts-to-reconnect.service';
import { AccountsToReconnectKeys } from 'src/modules/connected-account/types/accounts-to-reconnect-key-value.type';

@Injectable()
export class CalendarChannelSyncStatusService {
constructor(
private readonly twentyORMManager: TwentyORMManager,
@InjectCacheStorage(CacheStorageNamespace.Calendar)
private readonly cacheStorage: CacheStorageService,
private readonly userVarsService: UserVarsService<AccountsToReconnectKeyValueType>,
private readonly accountsToReconnectService: AccountsToReconnectService,
) {}

public async scheduleFullCalendarEventListFetch(calendarChannelId: string) {
Expand Down Expand Up @@ -194,24 +191,11 @@ export class CalendarChannelSyncStatusService {
const userId = calendarChannel.connectedAccount.accountOwner.userId;
const connectedAccountId = calendarChannel.connectedAccount.id;

const accountsToReconnect =
(await this.userVarsService.get({
userId,
workspaceId,
key: AccountsToReconnectKeys.ACCOUNTS_TO_RECONNECT_INSUFFICIENT_PERMISSIONS,
})) ?? [];

if (accountsToReconnect.includes(connectedAccountId)) {
return;
}

accountsToReconnect.push(connectedAccountId);

await this.userVarsService.set({
await this.accountsToReconnectService.addAccountToReconnectByKey(
AccountsToReconnectKeys.ACCOUNTS_TO_RECONNECT_INSUFFICIENT_PERMISSIONS,
userId,
workspaceId,
key: AccountsToReconnectKeys.ACCOUNTS_TO_RECONNECT_INSUFFICIENT_PERMISSIONS,
value: accountsToReconnect,
});
connectedAccountId,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,31 @@ export class AccountsToReconnectService {
value: updatedAccountsToReconnect,
});
}

public async addAccountToReconnectByKey(
key: AccountsToReconnectKeys,
userId: string,
workspaceId: string,
connectedAccountId: string,
) {
const accountsToReconnect =
(await this.userVarsService.get({
userId,
workspaceId,
key,
})) ?? [];

if (accountsToReconnect.includes(connectedAccountId)) {
return;
}

accountsToReconnect.push(connectedAccountId);

await this.userVarsService.set({
userId,
workspaceId,
key,
value: accountsToReconnect,
});
}
}
Loading

0 comments on commit 5a72b94

Please sign in to comment.