264 lines
8.1 KiB
TypeScript
264 lines
8.1 KiB
TypeScript
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
|
import { IntegrationRepository } from '@gitroom/nestjs-libraries/database/prisma/integrations/integration.repository';
|
|
import { IntegrationManager } from '@gitroom/nestjs-libraries/integrations/integration.manager';
|
|
import { InstagramProvider } from '@gitroom/nestjs-libraries/integrations/social/instagram.provider';
|
|
import { FacebookProvider } from '@gitroom/nestjs-libraries/integrations/social/facebook.provider';
|
|
import { SocialProvider } from '@gitroom/nestjs-libraries/integrations/social/social.integrations.interface';
|
|
import { Integration } from '@prisma/client';
|
|
import { NotificationService } from '@gitroom/nestjs-libraries/database/prisma/notifications/notification.service';
|
|
import { LinkedinPageProvider } from '@gitroom/nestjs-libraries/integrations/social/linkedin.page.provider';
|
|
|
|
@Injectable()
|
|
export class IntegrationService {
|
|
constructor(
|
|
private _integrationRepository: IntegrationRepository,
|
|
private _integrationManager: IntegrationManager,
|
|
private _notificationService: NotificationService
|
|
) {}
|
|
createOrUpdateIntegration(
|
|
org: string,
|
|
name: string,
|
|
picture: string,
|
|
type: 'article' | 'social',
|
|
internalId: string,
|
|
provider: string,
|
|
token: string,
|
|
refreshToken = '',
|
|
expiresIn?: number,
|
|
username?: string,
|
|
isBetweenSteps = false,
|
|
refresh?: string
|
|
) {
|
|
return this._integrationRepository.createOrUpdateIntegration(
|
|
org,
|
|
name,
|
|
picture,
|
|
type,
|
|
internalId,
|
|
provider,
|
|
token,
|
|
refreshToken,
|
|
expiresIn,
|
|
username,
|
|
isBetweenSteps,
|
|
refresh
|
|
);
|
|
}
|
|
|
|
getIntegrationsList(org: string) {
|
|
return this._integrationRepository.getIntegrationsList(org);
|
|
}
|
|
|
|
getIntegrationForOrder(id: string, order: string, user: string, org: string) {
|
|
return this._integrationRepository.getIntegrationForOrder(
|
|
id,
|
|
order,
|
|
user,
|
|
org
|
|
);
|
|
}
|
|
|
|
getIntegrationById(org: string, id: string) {
|
|
return this._integrationRepository.getIntegrationById(org, id);
|
|
}
|
|
|
|
async refreshToken(provider: SocialProvider, refresh: string) {
|
|
try {
|
|
const { refreshToken, accessToken, expiresIn } =
|
|
await provider.refreshToken(refresh);
|
|
|
|
if (!refreshToken || !accessToken || !expiresIn) {
|
|
return false;
|
|
}
|
|
|
|
return { refreshToken, accessToken, expiresIn };
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async informAboutRefreshError(orgId: string, integration: Integration) {
|
|
await this._notificationService.inAppNotification(
|
|
orgId,
|
|
`Could not refresh your ${integration.providerIdentifier} channel`,
|
|
`Could not refresh your ${integration.providerIdentifier} channel. Please go back to the system and connect it again ${process.env.FRONTEND_URL}/launches`,
|
|
true
|
|
);
|
|
}
|
|
|
|
async refreshNeeded(org: string, id: string) {
|
|
return this._integrationRepository.refreshNeeded(org, id);
|
|
}
|
|
|
|
async refreshTokens() {
|
|
const integrations = await this._integrationRepository.needsToBeRefreshed();
|
|
for (const integration of integrations) {
|
|
const provider = this._integrationManager.getSocialIntegration(
|
|
integration.providerIdentifier
|
|
);
|
|
|
|
const data = await this.refreshToken(provider, integration.refreshToken!);
|
|
|
|
if (!data) {
|
|
await this.informAboutRefreshError(
|
|
integration.organizationId,
|
|
integration
|
|
);
|
|
await this._integrationRepository.refreshNeeded(
|
|
integration.organizationId,
|
|
integration.id
|
|
);
|
|
return;
|
|
}
|
|
|
|
const { refreshToken, accessToken, expiresIn } = data;
|
|
|
|
await this.createOrUpdateIntegration(
|
|
integration.organizationId,
|
|
integration.name,
|
|
integration.picture!,
|
|
'social',
|
|
integration.internalId,
|
|
integration.providerIdentifier,
|
|
accessToken,
|
|
refreshToken,
|
|
expiresIn
|
|
);
|
|
}
|
|
}
|
|
|
|
async disableChannel(org: string, id: string) {
|
|
return this._integrationRepository.disableChannel(org, id);
|
|
}
|
|
|
|
async enableChannel(org: string, totalChannels: number, id: string) {
|
|
const integrations = (
|
|
await this._integrationRepository.getIntegrationsList(org)
|
|
).filter((f) => !f.disabled);
|
|
if (integrations.length >= totalChannels) {
|
|
throw new Error('You have reached the maximum number of channels');
|
|
}
|
|
|
|
return this._integrationRepository.enableChannel(org, id);
|
|
}
|
|
|
|
async deleteChannel(org: string, id: string) {
|
|
const isTherePosts = await this._integrationRepository.countPostsForChannel(
|
|
org,
|
|
id
|
|
);
|
|
if (isTherePosts) {
|
|
throw new HttpException(
|
|
'There are posts for this channel',
|
|
HttpStatus.NOT_ACCEPTABLE
|
|
);
|
|
}
|
|
|
|
return this._integrationRepository.deleteChannel(org, id);
|
|
}
|
|
|
|
async disableIntegrations(org: string, totalChannels: number) {
|
|
return this._integrationRepository.disableIntegrations(org, totalChannels);
|
|
}
|
|
|
|
async checkForDeletedOnceAndUpdate(org: string, page: string) {
|
|
return this._integrationRepository.checkForDeletedOnceAndUpdate(org, page);
|
|
}
|
|
|
|
async saveInstagram(
|
|
org: string,
|
|
id: string,
|
|
data: { pageId: string; id: string }
|
|
) {
|
|
const getIntegration = await this._integrationRepository.getIntegrationById(
|
|
org,
|
|
id
|
|
);
|
|
if (getIntegration && !getIntegration.inBetweenSteps) {
|
|
throw new HttpException('Invalid request', HttpStatus.BAD_REQUEST);
|
|
}
|
|
|
|
const instagram = this._integrationManager.getSocialIntegration(
|
|
'instagram'
|
|
) as InstagramProvider;
|
|
const getIntegrationInformation = await instagram.fetchPageInformation(
|
|
getIntegration?.token!,
|
|
data
|
|
);
|
|
|
|
await this.checkForDeletedOnceAndUpdate(org, getIntegrationInformation.id);
|
|
await this._integrationRepository.updateIntegration(id, {
|
|
picture: getIntegrationInformation.picture,
|
|
internalId: getIntegrationInformation.id,
|
|
name: getIntegrationInformation.name,
|
|
inBetweenSteps: false,
|
|
token: getIntegrationInformation.access_token,
|
|
profile: getIntegrationInformation.username,
|
|
});
|
|
|
|
return { success: true };
|
|
}
|
|
|
|
async saveLinkedin(org: string, id: string, page: string) {
|
|
const getIntegration = await this._integrationRepository.getIntegrationById(
|
|
org,
|
|
id
|
|
);
|
|
if (getIntegration && !getIntegration.inBetweenSteps) {
|
|
throw new HttpException('Invalid request', HttpStatus.BAD_REQUEST);
|
|
}
|
|
|
|
const linkedin = this._integrationManager.getSocialIntegration(
|
|
'linkedin-page'
|
|
) as LinkedinPageProvider;
|
|
|
|
const getIntegrationInformation = await linkedin.fetchPageInformation(
|
|
getIntegration?.token!,
|
|
page
|
|
);
|
|
|
|
await this.checkForDeletedOnceAndUpdate(org, String(getIntegrationInformation.id));
|
|
|
|
await this._integrationRepository.updateIntegration(String(id), {
|
|
picture: getIntegrationInformation.picture,
|
|
internalId: String(getIntegrationInformation.id),
|
|
name: getIntegrationInformation.name,
|
|
inBetweenSteps: false,
|
|
token: getIntegrationInformation.access_token,
|
|
profile: getIntegrationInformation.username,
|
|
});
|
|
|
|
return { success: true };
|
|
}
|
|
|
|
async saveFacebook(org: string, id: string, page: string) {
|
|
const getIntegration = await this._integrationRepository.getIntegrationById(
|
|
org,
|
|
id
|
|
);
|
|
if (getIntegration && !getIntegration.inBetweenSteps) {
|
|
throw new HttpException('Invalid request', HttpStatus.BAD_REQUEST);
|
|
}
|
|
|
|
const facebook = this._integrationManager.getSocialIntegration(
|
|
'facebook'
|
|
) as FacebookProvider;
|
|
const getIntegrationInformation = await facebook.fetchPageInformation(
|
|
getIntegration?.token!,
|
|
page
|
|
);
|
|
|
|
await this.checkForDeletedOnceAndUpdate(org, getIntegrationInformation.id);
|
|
await this._integrationRepository.updateIntegration(id, {
|
|
picture: getIntegrationInformation.picture,
|
|
internalId: getIntegrationInformation.id,
|
|
name: getIntegrationInformation.name,
|
|
inBetweenSteps: false,
|
|
token: getIntegrationInformation.access_token,
|
|
profile: getIntegrationInformation.username,
|
|
});
|
|
|
|
return { success: true };
|
|
}
|
|
}
|