import { forwardRef, Inject, Injectable } from '@nestjs/common'; import { Integration } from '@prisma/client'; import { IntegrationManager } from '@gitroom/nestjs-libraries/integrations/integration.manager'; import { IntegrationService } from '@gitroom/nestjs-libraries/database/prisma/integrations/integration.service'; import { AuthTokenDetails, SocialProvider, } from '@gitroom/nestjs-libraries/integrations/social/social.integrations.interface'; import { TemporalService } from 'nestjs-temporal-core'; @Injectable() export class RefreshIntegrationService { constructor( private _integrationManager: IntegrationManager, @Inject(forwardRef(() => IntegrationService)) private _integrationService: IntegrationService, private _temporalService: TemporalService ) {} async refresh(integration: Integration): Promise { const socialProvider = this._integrationManager.getSocialIntegration( integration.providerIdentifier ); const refresh = await this.refreshProcess(integration, socialProvider); if (!refresh) { return false as const; } await this._integrationService.createOrUpdateIntegration( undefined, !!socialProvider.oneTimeToken, integration.organizationId, integration.name, integration.picture!, 'social', integration.internalId, integration.providerIdentifier, refresh.accessToken, refresh.refreshToken, refresh.expiresIn ); return refresh; } public async setBetweenSteps(integration: Integration) { await this._integrationService.setBetweenRefreshSteps(integration.id); await this._integrationService.informAboutRefreshError( integration.organizationId, integration ); } public async startRefreshWorkflow(orgId: string, id: string, integration: SocialProvider) { if (!integration.refreshCron) { return false; } return this._temporalService.client .getRawClient() ?.workflow.start(`refreshTokenWorkflow`, { workflowId: `refresh_${id}`, args: [{integrationId: id, organizationId: orgId}], taskQueue: 'main', workflowIdConflictPolicy: 'TERMINATE_EXISTING', }); } private async refreshProcess( integration: Integration, socialProvider: SocialProvider ): Promise { const refresh: false | AuthTokenDetails = await socialProvider .refreshToken(integration.refreshToken) .catch((err) => false); if (!refresh || !refresh.accessToken) { await this._integrationService.refreshNeeded( integration.organizationId, integration.id ); await this._integrationService.informAboutRefreshError( integration.organizationId, integration ); await this._integrationService.disconnectChannel( integration.organizationId, integration ); return false; } if ( !socialProvider.reConnect || integration.rootInternalId === integration.internalId ) { return refresh; } const reConnect = await socialProvider.reConnect( integration.rootInternalId, integration.internalId, refresh.accessToken ); return { ...refresh, ...reConnect, }; } }