feat: introduce singleton webhook URL

This commit is contained in:
Ali BARIN
2023-06-07 22:29:40 +00:00
parent 92638c2e97
commit de7a35dfe9
19 changed files with 285 additions and 78 deletions

View File

@@ -1,12 +1,16 @@
import { QueryContext, ModelOptions } from 'objection';
import type { RelationMappings } from 'objection';
import { AES, enc } from 'crypto-js';
import { IRequest } from '@automatisch/types';
import App from './app';
import Base from './base';
import User from './user';
import Step from './step';
import ExtendedQueryBuilder from './query-builder';
import appConfig from '../config/app';
import { IJSONObject } from '@automatisch/types';
import Telemetry from '../helpers/telemetry';
import globalVariable from '../helpers/global-variable';
class Connection extends Base {
id!: string;
@@ -18,6 +22,9 @@ class Connection extends Base {
draft: boolean;
count?: number;
flowCount?: number;
user?: User;
steps?: Step[];
triggerSteps?: Step[];
static tableName = 'connections';
@@ -53,6 +60,17 @@ class Connection extends Base {
to: 'steps.connection_id',
},
},
triggerSteps: {
relation: Base.HasManyRelation,
modelClass: Step,
join: {
from: 'connections.id',
to: 'steps.connection_id',
},
filter(builder: ExtendedQueryBuilder<Step>) {
builder.where('type', '=', 'trigger');
},
},
});
encryptData(): void {
@@ -110,6 +128,27 @@ class Connection extends Base {
await super.$afterUpdate(opt, queryContext);
Telemetry.connectionUpdated(this);
}
async getApp() {
if (!this.key) return null;
return await App.findOneByKey(this.key);
}
async verifyWebhook(request: IRequest) {
if (!this.key) return true;
const app = await this.getApp();
const $ = await globalVariable({
connection: this,
request,
});
if (!app.auth?.verifyWebhook) return true;
return app.auth.verifyWebhook($);
}
}
export default Connection;

View File

@@ -18,6 +18,7 @@ class Flow extends Base {
active: boolean;
status: 'paused' | 'published' | 'draft';
steps: Step[];
triggerStep: Step;
published_at: string;
remoteWebhookId: string;
executions?: Execution[];
@@ -51,6 +52,20 @@ class Flow extends Base {
builder.orderBy('position', 'asc');
},
},
triggerStep: {
relation: Base.HasOneRelation,
modelClass: Step,
join: {
from: 'flows.id',
to: 'steps.flow_id',
},
filter(builder: ExtendedQueryBuilder<Step>) {
builder
.where('type', 'trigger')
.limit(1)
.first();
},
},
executions: {
relation: Base.HasManyRelation,
modelClass: Execution,

View File

@@ -1,5 +1,6 @@
import { URL } from 'node:url';
import { QueryContext, ModelOptions } from 'objection';
import get from 'lodash.get';
import type { IJSONObject, IStep } from '@automatisch/types';
import Base from './base';
import App from './app';
@@ -22,6 +23,7 @@ class Step extends Base {
connection?: Connection;
flow: Flow;
executionSteps: ExecutionStep[];
webhookPath?: string;
static tableName = 'steps';
@@ -43,6 +45,7 @@ class Step extends Base {
},
position: { type: 'integer' },
parameters: { type: 'object' },
webhookPath: { type: ['string', 'null'] },
},
};
@@ -77,17 +80,52 @@ class Step extends Base {
},
});
get webhookUrl() {
return new URL(this.webhookPath, appConfig.webhookUrl).toString();
}
get iconUrl() {
if (!this.appKey) return null;
return `${appConfig.baseUrl}/apps/${this.appKey}/assets/favicon.svg`;
}
get webhookUrl() {
if (this.appKey !== 'webhook') return null;
async computeWebhookPath() {
if (this.type === 'action') return null;
const url = new URL(`/webhooks/${this.flowId}`, appConfig.webhookUrl);
return url.toString();
const triggerCommand = await this.getTriggerCommand();
if (!triggerCommand) return null;
const {
useSingletonWebhook,
singletonWebhookRefValueParameter,
type,
} = triggerCommand;
const isWebhook = type === 'webhook';
if (!isWebhook) return null;
if (singletonWebhookRefValueParameter) {
const parameterValue = get(this.parameters, singletonWebhookRefValueParameter);
return `/webhooks/connections/${this.connectionId}/${parameterValue}`;
}
if (useSingletonWebhook) {
return `/webhooks/connections/${this.connectionId}`;
}
return `/webhooks/flows/${this.flowId}`;
}
async getWebhookUrl() {
if (this.type === 'action') return;
const path = await this.computeWebhookPath();
const webhookUrl = new URL(path, appConfig.webhookUrl).toString();
return webhookUrl;
}
async $afterInsert(queryContext: QueryContext) {
@@ -166,6 +204,18 @@ class Step extends Base {
return existingArguments;
}
async updateWebhookUrl() {
if (this.isAction) return this;
const payload = {
webhookPath: await this.computeWebhookPath(),
};
await this.$query().patchAndFetch(payload);
return this;
}
}
export default Step;