import { ItemsService } from './items'; import { Item, PrimaryKey, AbstractServiceOptions } from '../types'; import emitter from '../emitter'; import { ListenerFn } from 'eventemitter2'; import { Webhook } from '../types'; import axios from 'axios'; import logger from '../logger'; let registered: { event: string; handler: ListenerFn }[] = []; export class WebhooksService extends ItemsService { constructor(options?: AbstractServiceOptions) { super('directus_webhooks', options); } async register() { this.unregister(); const webhooks = await this.knex .select('*') .from('directus_webhooks') .where({ status: 'active' }); for (const webhook of webhooks) { if (webhook.actions === '*') { if (webhook.collections === '*') { const event = 'item.*.*'; const handler = this.createHandler(webhook); emitter.on(event, handler); registered.push({ event, handler }); } else { for (const collection of webhook.collections.split(',')) { const event = `item.*.${collection}`; const handler = this.createHandler(webhook); emitter.on(event, handler); registered.push({ event, handler }); } } } else { for (const action of webhook.actions.split(',')) { if (webhook.collections === '*') { const event = `item.${action}.*`; const handler = this.createHandler(webhook); emitter.on(event, handler); registered.push({ event, handler }); } else { for (const collection of webhook.collections.split(',')) { const event = `item.${action}.${collection}`; const handler = this.createHandler(webhook); emitter.on(event, handler); registered.push({ event, handler }); } } } } } } unregister() { for (const { event, handler } of registered) { emitter.off(event, handler); } registered = []; } createHandler(webhook: Webhook): ListenerFn { return async (data) => { try { await axios({ url: webhook.url, method: webhook.method, data: webhook.data ? data : null, }); } catch (error) { logger.warn(`Webhook "${webhook.name}" (id: ${webhook.id}) failed`); logger.warn(error); } }; } async create(data: Partial[]): Promise; async create(data: Partial): Promise; async create(data: Partial | Partial[]): Promise { const result = await super.create(data); await this.register(); return result; } update(data: Partial, keys: PrimaryKey[]): Promise; update(data: Partial, key: PrimaryKey): Promise; update(data: Partial[]): Promise; async update( data: Partial | Partial[], key?: PrimaryKey | PrimaryKey[] ): Promise { const result = await super.update(data, key as any); await this.register(); return result; } delete(key: PrimaryKey): Promise; delete(keys: PrimaryKey[]): Promise; async delete(key: PrimaryKey | PrimaryKey[]): Promise { const result = await super.delete(key as any); await this.register(); return result; } }