postiz/apps/backend/src/api/routes/integrations.controller.ts

234 lines
6.7 KiB
TypeScript

import { Body, Controller, Delete, Get, Param, Post, Query } from '@nestjs/common';
import { ioRedis } from '@gitroom/nestjs-libraries/redis/redis.service';
import { ConnectIntegrationDto } from '@gitroom/nestjs-libraries/dtos/integrations/connect.integration.dto';
import { IntegrationManager } from '@gitroom/nestjs-libraries/integrations/integration.manager';
import { IntegrationService } from '@gitroom/nestjs-libraries/database/prisma/integrations/integration.service';
import { GetOrgFromRequest } from '@gitroom/nestjs-libraries/user/org.from.request';
import { Organization, User } from '@prisma/client';
import { ApiKeyDto } from '@gitroom/nestjs-libraries/dtos/integrations/api.key.dto';
import { IntegrationFunctionDto } from '@gitroom/nestjs-libraries/dtos/integrations/integration.function.dto';
import {
AuthorizationActions,
Sections,
} from '@gitroom/backend/services/auth/permissions/permissions.service';
import { CheckPolicies } from '@gitroom/backend/services/auth/permissions/permissions.ability';
import {pricing} from "@gitroom/nestjs-libraries/database/prisma/subscriptions/pricing";
import {ApiTags} from "@nestjs/swagger";
import { GetUserFromRequest } from '@gitroom/nestjs-libraries/user/user.from.request';
@ApiTags('Integrations')
@Controller('/integrations')
export class IntegrationsController {
constructor(
private _integrationManager: IntegrationManager,
private _integrationService: IntegrationService
) {}
@Get('/')
getIntegration() {
return this._integrationManager.getAllIntegrations();
}
@Get('/list')
async getIntegrationList(@GetOrgFromRequest() org: Organization) {
return {
integrations: (
await this._integrationService.getIntegrationsList(org.id)
).map((p) => ({
name: p.name,
id: p.id,
disabled: p.disabled,
picture: p.picture,
identifier: p.providerIdentifier,
type: p.type,
})),
};
}
@Get('/:id')
getSingleIntegration(
@Param('id') id: string,
@Query('order') order: string,
@GetUserFromRequest() user: User,
@GetOrgFromRequest() org: Organization
) {
return this._integrationService.getIntegrationForOrder(id, order, user.id, org.id);
}
@Get('/social/:integration')
@CheckPolicies([AuthorizationActions.Create, Sections.CHANNEL])
async getIntegrationUrl(@Param('integration') integration: string) {
if (
!this._integrationManager
.getAllowedSocialsIntegrations()
.includes(integration)
) {
throw new Error('Integration not allowed');
}
const integrationProvider =
this._integrationManager.getSocialIntegration(integration);
const { codeVerifier, state, url } =
await integrationProvider.generateAuthUrl();
await ioRedis.set(`login:${state}`, codeVerifier, 'EX', 300);
return { url };
}
@Post('/function')
async functionIntegration(
@GetOrgFromRequest() org: Organization,
@Body() body: IntegrationFunctionDto
) {
const getIntegration = await this._integrationService.getIntegrationById(
org.id,
body.id
);
if (!getIntegration) {
throw new Error('Invalid integration');
}
if (getIntegration.type === 'social') {
const integrationProvider = this._integrationManager.getSocialIntegration(
getIntegration.providerIdentifier
);
if (!integrationProvider) {
throw new Error('Invalid provider');
}
if (integrationProvider[body.name]) {
return integrationProvider[body.name](getIntegration.token, body.data);
}
throw new Error('Function not found');
}
if (getIntegration.type === 'article') {
const integrationProvider =
this._integrationManager.getArticlesIntegration(
getIntegration.providerIdentifier
);
if (!integrationProvider) {
throw new Error('Invalid provider');
}
if (integrationProvider[body.name]) {
return integrationProvider[body.name](getIntegration.token, body.data);
}
throw new Error('Function not found');
}
}
@Post('/article/:integration/connect')
@CheckPolicies([AuthorizationActions.Create, Sections.CHANNEL])
async connectArticle(
@GetOrgFromRequest() org: Organization,
@Param('integration') integration: string,
@Body() api: ApiKeyDto
) {
if (
!this._integrationManager
.getAllowedArticlesIntegrations()
.includes(integration)
) {
throw new Error('Integration not allowed');
}
if (!api) {
throw new Error('Missing api');
}
const integrationProvider =
this._integrationManager.getArticlesIntegration(integration);
const { id, name, token, picture } = await integrationProvider.authenticate(
api.api
);
if (!id) {
throw new Error('Invalid api key');
}
return this._integrationService.createOrUpdateIntegration(
org.id,
name,
picture,
'article',
String(id),
integration,
token
);
}
@Post('/social/:integration/connect')
@CheckPolicies([AuthorizationActions.Create, Sections.CHANNEL])
async connectSocialMedia(
@GetOrgFromRequest() org: Organization,
@Param('integration') integration: string,
@Body() body: ConnectIntegrationDto
) {
if (
!this._integrationManager
.getAllowedSocialsIntegrations()
.includes(integration)
) {
throw new Error('Integration not allowed');
}
const getCodeVerifier = await ioRedis.get(`login:${body.state}`);
if (!getCodeVerifier) {
throw new Error('Invalid state');
}
const integrationProvider =
this._integrationManager.getSocialIntegration(integration);
const { accessToken, expiresIn, refreshToken, id, name, picture } =
await integrationProvider.authenticate({
code: body.code,
codeVerifier: getCodeVerifier,
});
if (!id) {
throw new Error('Invalid api key');
}
return this._integrationService.createOrUpdateIntegration(
org.id,
name,
picture,
'social',
String(id),
integration,
accessToken,
refreshToken,
expiresIn
);
}
@Post('/disable')
disableChannel(
@GetOrgFromRequest() org: Organization,
@Body('id') id: string
) {
return this._integrationService.disableChannel(org.id, id);
}
@Post('/enable')
enableChannel(
@GetOrgFromRequest() org: Organization,
@Body('id') id: string
) {
return this._integrationService.enableChannel(
org.id,
// @ts-ignore
org?.subscription?.totalChannels || pricing.FREE.channel,
id
);
}
@Delete('/')
deleteChannel(
@GetOrgFromRequest() org: Organization,
@Body('id') id: string
) {
// @ts-ignore
return this._integrationService.deleteChannel(org.id, id);
}
}