Browse Source

feat: service for webhook handler

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/5597/head
Pranav C 1 year ago
parent
commit
ed6817a70e
  1. 2
      packages/nocodb/src/app.module.ts
  2. 26
      packages/nocodb/src/db/BaseModelSqlv2.ts
  3. 18
      packages/nocodb/src/services/hook-handler.service.spec.ts
  4. 143
      packages/nocodb/src/services/hook-handler.service.ts

2
packages/nocodb/src/app.module.ts

@ -24,6 +24,7 @@ import type {
MiddlewareConsumer,
OnApplicationBootstrap,
} from '@nestjs/common';
import { HookHandlerService } from './services/hook-handler.service';
@Module({
imports: [
@ -43,6 +44,7 @@ import type {
LocalStrategy,
AuthTokenStrategy,
BaseViewStrategy,
HookHandlerService,
],
})
export class AppModule implements OnApplicationBootstrap {

26
packages/nocodb/src/db/BaseModelSqlv2.ts

@ -11,24 +11,17 @@ import {
UITypes,
ViewTypes,
} from 'nocodb-sdk';
import ejs from 'ejs';
import Validator from 'validator';
import { customAlphabet } from 'nanoid';
import DOMPurify from 'isomorphic-dompurify';
import { v4 as uuidv4 } from 'uuid';
import { NcError } from '../helpers/catchError';
import getAst from '../helpers/getAst';
import NcPluginMgrv2 from '../helpers/NcPluginMgrv2';
import {
_transformSubmittedFormDataForEmail,
invokeWebhook,
} from '../helpers/webhookHelpers';
import {
Audit,
Column,
Filter,
FormView,
Hook,
Model,
Project,
Sort,
@ -40,7 +33,8 @@ import {
COMPARISON_SUB_OPS,
IS_WITHIN_COMPARISON_SUB_OPS,
} from '../models/Filter';
import formSubmissionEmailTemplate from '../utils/common/formSubmissionEmailTemplate';
import Noco from '../Noco'
import { HANDLE_WEBHOOK } from '../services/hook-handler.service'
import formulaQueryBuilderv2 from './formulav2/formulaQueryBuilderv2';
import genRollupSelectv2 from './genRollupSelectv2';
import conditionV2 from './conditionV2';
@ -2496,6 +2490,18 @@ class BaseModelSqlv2 {
}
private async handleHooks(hookName, prevData, newData, req): Promise<void> {
Noco.eventEmitter.emit(HANDLE_WEBHOOK, {
hookName,
prevData,
newData,
user: req?.user,
viewId: this.viewId,
modelId: this.model.id,
tnPath: this.tnPath,
})
/*
const view = await View.get(this.viewId);
// handle form view data submission
@ -2585,7 +2591,7 @@ class BaseModelSqlv2 {
}
} catch (e) {
console.log('hooks :: error', hookName, e);
}
}*/
}
// @ts-ignore

18
packages/nocodb/src/services/hook-handler.service.spec.ts

@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { HookHandlerService } from './hook-handler.service';
describe('HookHandlerService', () => {
let service: HookHandlerService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [HookHandlerService],
}).compile();
service = module.get<HookHandlerService>(HookHandlerService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

143
packages/nocodb/src/services/hook-handler.service.ts

@ -0,0 +1,143 @@
import { Injectable } from '@nestjs/common';
import { UITypes, ViewTypes } from 'nocodb-sdk';
import ejs from 'ejs';
import NcPluginMgrv2 from '../helpers/NcPluginMgrv2';
import {
_transformSubmittedFormDataForEmail,
invokeWebhook,
} from '../helpers/webhookHelpers';
import { FormView, Hook, Model, View } from '../models';
import { IEventEmitter } from '../modules/event-emitter/event-emitter.interface';
import formSubmissionEmailTemplate from '../utils/common/formSubmissionEmailTemplate';
import type { OnModuleDestroy, OnModuleInit } from '@nestjs/common';
import type { UserType } from 'nocodb-sdk';
export const HANDLE_WEBHOOK = '__nc_handleHooks';
@Injectable()
export class HookHandlerService implements OnModuleInit, OnModuleDestroy {
private unsubscribe: () => void;
constructor(private readonly eventEmitter: IEventEmitter) {}
private async handleHooks({
hookName,
prevData,
newData,
user,
viewId,
modelId,
tnPath,
}: {
hookName;
prevData;
newData;
user: UserType;
viewId: string;
modelId: string;
tnPath: string;
}): Promise<void> {
const view = await View.get(viewId);
const model = await Model.get(modelId);
// handle form view data submission
if (
(hookName === 'after.insert' || hookName === 'after.bulkInsert') &&
view.type === ViewTypes.FORM
) {
try {
const formView = await view.getView<FormView>();
const { columns } = await FormView.getWithInfo(formView.fk_view_id);
const allColumns = await model.getColumns();
const fieldById = columns.reduce(
(o: Record<string, any>, f: Record<string, any>) => ({
...o,
[f.fk_column_id]: f,
}),
{},
);
let order = 1;
const filteredColumns = allColumns
?.map((c: Record<string, any>) => ({
...c,
fk_column_id: c.id,
fk_view_id: formView.fk_view_id,
...(fieldById[c.id] ? fieldById[c.id] : {}),
order: (fieldById[c.id] && fieldById[c.id].order) || order++,
id: fieldById[c.id] && fieldById[c.id].id,
}))
.sort(
(a: Record<string, any>, b: Record<string, any>) =>
a.order - b.order,
)
.filter(
(f: Record<string, any>) =>
f.show &&
f.uidt !== UITypes.Rollup &&
f.uidt !== UITypes.Lookup &&
f.uidt !== UITypes.Formula &&
f.uidt !== UITypes.QrCode &&
f.uidt !== UITypes.Barcode &&
f.uidt !== UITypes.SpecificDBType,
)
.sort(
(a: Record<string, any>, b: Record<string, any>) =>
a.order - b.order,
)
.map((c: Record<string, any>) => ({
...c,
required: !!(c.required || 0),
}));
const emails = Object.entries(JSON.parse(formView?.email) || {})
.filter((a) => a[1])
.map((a) => a[0]);
if (emails?.length) {
const transformedData = _transformSubmittedFormDataForEmail(
newData,
formView,
filteredColumns,
);
(await NcPluginMgrv2.emailAdapter(false))?.mailSend({
to: emails.join(','),
subject: 'NocoDB Form',
html: ejs.render(formSubmissionEmailTemplate, {
data: transformedData,
tn: tnPath,
_tn: model.title,
}),
});
}
} catch (e) {
console.log(e);
}
}
try {
const [event, operation] = hookName.split('.');
const hooks = await Hook.list({
fk_model_id: modelId,
event,
operation,
});
for (const hook of hooks) {
if (hook.active) {
invokeWebhook(hook, model, view, prevData, newData, user);
}
}
} catch (e) {
console.log('hooks :: error', hookName, e);
}
}
onModuleInit(): any {
this.unsubscribe = this.eventEmitter.on(
HANDLE_WEBHOOK,
this.handleHooks.bind(this),
);
}
onModuleDestroy() {
this.unsubscribe?.();
}
}
Loading…
Cancel
Save