Skip to content

Commit

Permalink
Add Render, Fly.io integrations and reduce integrations page reloads
Browse files Browse the repository at this point in the history
  • Loading branch information
dangtony98 committed Jan 21, 2023
1 parent 0680351 commit 0c351c0
Show file tree
Hide file tree
Showing 45 changed files with 1,097 additions and 351 deletions.
83 changes: 73 additions & 10 deletions backend/src/controllers/v1/integrationAuthController.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { Request, Response } from 'express';
import { Types } from 'mongoose';
import * as Sentry from '@sentry/node';
import axios from 'axios';
import { readFileSync } from 'fs';
import { IntegrationAuth, Integration } from '../../models';
import {
Integration,
IntegrationAuth,
Bot
} from '../../models';
import { INTEGRATION_SET, INTEGRATION_OPTIONS } from '../../variables';
import { IntegrationService } from '../../services';
import { getApps, revokeAccess } from '../../integrations';
Expand Down Expand Up @@ -44,7 +47,7 @@ export const oAuthExchange = async (
environment: environments[0].slug,
});
} catch (err) {
Sentry.setUser(null);
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get OAuth2 code-token exchange'
Expand All @@ -56,6 +59,67 @@ export const oAuthExchange = async (
});
};

/**
* Save integration access token as part of integration [integration] for workspace with id [workspaceId]
* @param req
* @param res
*/
export const saveIntegrationAccessToken = async (
req: Request,
res: Response
) => {
// TODO: refactor
let integrationAuth;
try {
const {
workspaceId,
accessToken,
integration
}: {
workspaceId: string;
accessToken: string;
integration: string;
} = req.body;

integrationAuth = await IntegrationAuth.findOneAndUpdate({
workspace: new Types.ObjectId(workspaceId),
integration
}, {
workspace: new Types.ObjectId(workspaceId),
integration
}, {
new: true,
upsert: true
});

const bot = await Bot.findOne({
workspace: new Types.ObjectId(workspaceId),
isActive: true
});

if (!bot) throw new Error('Bot must be enabled to save integration access token');

// encrypt and save integration access token
integrationAuth = await IntegrationService.setIntegrationAuthAccess({
integrationAuthId: integrationAuth._id.toString(),
accessToken,
accessExpiresAt: undefined
});

if (!integrationAuth) throw new Error('Failed to save integration access token');
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to save access token for integration'
});
}

return res.status(200).send({
integrationAuth
});
}

/**
* Return list of applications allowed for integration with integration authorization id [integrationAuthId]
* @param req
Expand All @@ -70,7 +134,7 @@ export const getIntegrationAuthApps = async (req: Request, res: Response) => {
accessToken: req.accessToken
});
} catch (err) {
Sentry.setUser(null);
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to get integration authorization applications'
Expand All @@ -89,22 +153,21 @@ export const getIntegrationAuthApps = async (req: Request, res: Response) => {
* @returns
*/
export const deleteIntegrationAuth = async (req: Request, res: Response) => {
let integrationAuth;
try {
const { integrationAuthId } = req.params;

await revokeAccess({
integrationAuth = await revokeAccess({
integrationAuth: req.integrationAuth,
accessToken: req.accessToken
});
} catch (err) {
Sentry.setUser(null);
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to delete integration authorization'
});
}

return res.status(200).send({
message: 'Successfully deleted integration authorization'
integrationAuth
});
}
85 changes: 40 additions & 45 deletions backend/src/controllers/v1/integrationController.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,43 @@
import { Request, Response } from 'express';
import { readFileSync } from 'fs';
import * as Sentry from '@sentry/node';
import { Integration, Bot, BotKey } from '../../models';
import {
Integration,
Workspace,
Bot,
BotKey
} from '../../models';
import { EventService } from '../../services';
import { eventPushSecrets } from '../../events';

interface Key {
encryptedKey: string;
nonce: string;
}
/**
* Create/initialize an (empty) integration for integration authorization
* @param req
* @param res
* @returns
*/
export const createIntegration = async (req: Request, res: Response) => {
let integration;
try {
// initialize new integration after saving integration access token
integration = await new Integration({
workspace: req.integrationAuth.workspace._id,
isActive: false,
app: null,
environment: req.integrationAuth.workspace?.environments[0].slug,
integration: req.integrationAuth.integration,
integrationAuth: req.integrationAuth._id
}).save();
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: 'Failed to create integration'
});
}

interface PushSecret {
ciphertextKey: string;
ivKey: string;
tagKey: string;
hashKey: string;
ciphertextValue: string;
ivValue: string;
tagValue: string;
hashValue: string;
type: 'shared' | 'personal';
return res.status(200).send({
integration
});
}

/**
Expand All @@ -36,13 +54,12 @@ export const updateIntegration = async (req: Request, res: Response) => {

try {
const {
app,
environment,
isActive,
target, // vercel-specific integration param
context, // netlify-specific integration param
siteId, // netlify-specific integration param
owner // github-specific integration param
app,
appId,
targetEnvironment,
owner, // github-specific integration param
} = req.body;

integration = await Integration.findOneAndUpdate(
Expand All @@ -53,9 +70,8 @@ export const updateIntegration = async (req: Request, res: Response) => {
environment,
isActive,
app,
target,
context,
siteId,
appId,
targetEnvironment,
owner
},
{
Expand Down Expand Up @@ -101,27 +117,6 @@ export const deleteIntegration = async (req: Request, res: Response) => {
});

if (!integration) throw new Error('Failed to find integration');

const integrations = await Integration.find({
workspace: integration.workspace
});

if (integrations.length === 0) {
// case: no integrations left, deactivate bot
const bot = await Bot.findOneAndUpdate({
workspace: integration.workspace
}, {
isActive: false
}, {
new: true
});

if (bot) {
await BotKey.deleteOne({
bot: bot._id
});
}
}
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
Expand Down
5 changes: 2 additions & 3 deletions backend/src/helpers/integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ const syncIntegrationsHelper = async ({
}) => {
let integrations;
try {

integrations = await Integration.find({
workspace: workspaceId,
isActive: true,
Expand All @@ -142,7 +141,7 @@ const syncIntegrationsHelper = async ({
workspaceId: integration.workspace.toString(),
environment: integration.environment
});

const integrationAuth = await IntegrationAuth.findById(integration.integrationAuth);
if (!integrationAuth) throw new Error('Failed to find integration auth');

Expand Down Expand Up @@ -316,7 +315,7 @@ const setIntegrationAuthAccessHelper = async ({
}: {
integrationAuthId: string;
accessToken: string;
accessExpiresAt: Date;
accessExpiresAt: Date | undefined;
}) => {
let integrationAuth;
try {
Expand Down
Loading

0 comments on commit 0c351c0

Please sign in to comment.