Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

6382 create a command to add a uservar in the key value pair table for every account which needs to reconnect #6553

Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
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 { TypeORMService } from 'src/database/typeorm/typeorm.service';
import { BillingSubscriptionService } from 'src/engine/core-modules/billing/services/billing-subscription.service';
import {
KeyValuePair,
KeyValuePairType,
} from 'src/engine/core-modules/key-value-pair/key-value-pair.entity';
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
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 typeORMService: TypeORMService,
private readonly dataSourceService: DataSourceService,
private readonly workspaceCacheVersionService: WorkspaceCacheVersionService,
private readonly billingSubscriptionService: BillingSubscriptionService,
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
private readonly accountsToReconnectService: AccountsToReconnectService,
@InjectRepository(KeyValuePair, 'core')
private readonly keyValuePairRepository: Repository<KeyValuePair>,
) {
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 activeSubscriptionWorkspaceIds: string[] = [];

if (options.workspaceId) {
activeSubscriptionWorkspaceIds = [options.workspaceId];
} else {
activeSubscriptionWorkspaceIds =
bosiraphael marked this conversation as resolved.
Show resolved Hide resolved
await this.billingSubscriptionService.getActiveSubscriptionWorkspaceIds();
}

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

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

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

for (const workspaceId of activeSubscriptionWorkspaceIds) {
try {
const dataSourceMetadata =
await this.dataSourceService.getDataSourcesMetadataFromWorkspaceId(
workspaceId,
)[0];

const workspaceDataSource =
bosiraphael marked this conversation as resolved.
Show resolved Hide resolved
await this.typeORMService.connectToDataSource(dataSourceMetadata);

if (workspaceDataSource) {
bosiraphael marked this conversation as resolved.
Show resolved Hide resolved
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;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Consider wrapping the entire loop body in a try-catch to continue processing other accounts if one fails

}
} 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 @@ -25,6 +26,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 @@ -56,5 +58,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 @@ -21,11 +23,12 @@ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadat
import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module';
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 { ConnectedAccountModule } from 'src/modules/connected-account/connected-account.module';
import { ViewModule } from 'src/modules/view/view.module';

@Module({
imports: [
TypeOrmModule.forFeature([Workspace], 'core'),
TypeOrmModule.forFeature([Workspace, KeyValuePair], 'core'),
FileStorageModule,
OnboardingModule,
TypeORMModule,
Expand All @@ -40,6 +43,7 @@ import { ViewModule } from 'src/modules/view/view.module';
ViewModule,
BillingModule,
ObjectMetadataModule,
ConnectedAccountModule,
],
providers: [
UpdateFileFolderStructureCommand,
Expand All @@ -50,6 +54,7 @@ import { ViewModule } from 'src/modules/view/view.module';
SetWorkspaceActivationStatusCommand,
UpdateActivitiesCommand,
BackfillNewOnboardingUserVarsCommand,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: UpgradeTo0_23Command is duplicated in providers array

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,
})) ?? [];
bosiraphael marked this conversation as resolved.
Show resolved Hide resolved

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

accountsToReconnect.push(connectedAccountId);

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