0045c353c6
* Layout Pages * Add Multi Select with Badges * Add MultiBadge * Add prevent close on click outside * Fix import issue * Import Table * Add Classnames to buttons * Add Switch Component * Update for webhooks * skip precommit hooks * Remove Infinite Load. Update Types * Create Webhook Dialog * Tidy Ups * Edit Webhook dialog * WIP Breadcurmbs * Changes from calls with Fabians * Breadcrumbs * Reorders * Fix Create Dialog * Rename MultiBadge to BadgeSelected * Fix and update Story file for Table * Adjust Padding for Buttons in Table * Add extra story, adjust padding for no buttons * Fix bug with Edit Select * fixed Webhook sorting + added Webhook.hasSecret and Webhook.projectId * fixed hydration mismatch * Changes from PR feedback * Validation Rule for Select * Reset Dialogs on Cancel. Conditionally render headers in Table * stricter webhook gql types * stricter webhook gql types * Fix initial dialogs * Quick Fixes * Add projectWebhooksRoute * Remove TableItemType * Fixes from PR * Fix broken Query * Fixes from PR * Fix based on PR * Fix from PR * Changes to index * Fix in index * Updates to Validation and Table * Add "by" prop to FormSelectBadges and renamed component * Use defineModel for Switch * Revert "Use defineModel for Switch" This reverts commit 6bc9e07a767cdc64f06c03b028150915e013ed4f. * Replace breadcrumbs with projectWebhooksRoute * Rename FormValues to WebhookFormValues * Add target blank and simplify trigger mapping * Fix casing of webhookFormValues * Change webhookModel to prevent props mutation * Remove unnecessary typecast * Webhook deletion now uses fieldNameWhitelist. * Use convertThrowIntoFetchResult and getFirstErrorMessage in Create * Use defineModel for handling open state of Dialogs * Optimise Switch component with defineModel * Merge Create and Edit Dialogs * Fix issue with Status Icons * Remove console log * WIP Merge of Edit and Create * Add optional placeholder to SelectBase. Update Events placeholder. * Add secret to Create webhook dialog * Update Watch * Rename Dialogs. Fix active select items * Fix Select active items * Simplify triggers, add secret to create call * Remove $webhooksId: String * fix: stale form state across edit/create webhook dialog sessions * Fix from PR * Swap t.text for t.id * Use enum for historyStatus * Use consistent story formatting * More consistent create/edit mutations * fix be linting errors --------- Co-authored-by: Kristaps Fabians Geikins <fabis94@live.com>
164 lines
4.6 KiB
JavaScript
164 lines
4.6 KiB
JavaScript
'use strict'
|
|
|
|
const knex = require('@/db/knex')
|
|
const { getStream } = require('@/modules/core/repositories/streams')
|
|
const crs = require('crypto-random-string')
|
|
|
|
const WebhooksConfig = () => knex('webhooks_config')
|
|
const WebhooksEvents = () => knex('webhooks_events')
|
|
const Users = () => knex('users')
|
|
|
|
const { getServerInfo } = require('../../core/services/generic')
|
|
const MAX_STREAM_WEBHOOKS = 100
|
|
|
|
module.exports = {
|
|
async createWebhook({ streamId, url, description, secret, enabled, triggers }) {
|
|
const streamWebhookCount = await module.exports.getStreamWebhooksCount({ streamId })
|
|
if (streamWebhookCount >= MAX_STREAM_WEBHOOKS) {
|
|
throw new Error(
|
|
`Maximum number of webhooks for a stream reached (${MAX_STREAM_WEBHOOKS})`
|
|
)
|
|
}
|
|
|
|
const triggersObj = Object.assign({}, ...triggers.map((x) => ({ [x]: true })))
|
|
|
|
const [{ id }] = await WebhooksConfig()
|
|
.returning('id')
|
|
.insert({
|
|
id: crs({ length: 10 }),
|
|
streamId,
|
|
url,
|
|
description,
|
|
secret,
|
|
enabled,
|
|
triggers: triggersObj
|
|
})
|
|
return id
|
|
},
|
|
|
|
async getWebhook({ id }) {
|
|
const webhook = await WebhooksConfig().select('*').where({ id }).first()
|
|
if (webhook) {
|
|
webhook.triggers = Object.keys(webhook.triggers)
|
|
}
|
|
|
|
return webhook
|
|
},
|
|
|
|
async updateWebhook({ id, url, description, secret, enabled, triggers }) {
|
|
const fieldsToUpdate = {
|
|
updatedAt: new Date()
|
|
}
|
|
if (url !== undefined) fieldsToUpdate.url = url
|
|
if (description !== undefined) fieldsToUpdate.description = description
|
|
if (secret !== undefined) fieldsToUpdate.secret = secret
|
|
if (enabled !== undefined) fieldsToUpdate.enabled = enabled
|
|
if (triggers !== undefined) {
|
|
const triggersObj = Object.assign({}, ...triggers.map((x) => ({ [x]: true })))
|
|
fieldsToUpdate.triggers = triggersObj
|
|
}
|
|
|
|
const [{ id: res }] = await WebhooksConfig()
|
|
.returning('id')
|
|
.where({ id })
|
|
.update(fieldsToUpdate)
|
|
return res
|
|
},
|
|
|
|
async deleteWebhook({ id }) {
|
|
return await WebhooksConfig().where({ id }).del()
|
|
},
|
|
|
|
async getStreamWebhooks({ streamId }) {
|
|
const webhooks = await WebhooksConfig()
|
|
.select('*')
|
|
.where({ streamId })
|
|
.orderBy('updatedAt', 'desc')
|
|
|
|
for (const webhook of webhooks) {
|
|
webhook.triggers = Object.keys(webhook.triggers)
|
|
}
|
|
|
|
return webhooks
|
|
},
|
|
|
|
async getStreamWebhooksCount({ streamId }) {
|
|
const [res] = await WebhooksConfig().count().where({ streamId })
|
|
return parseInt(res.count)
|
|
},
|
|
|
|
async dispatchStreamEvent({ streamId, event, eventPayload }, { trx } = {}) {
|
|
// Add server info
|
|
eventPayload.server = await getServerInfo()
|
|
eventPayload.server.canonicalUrl = process.env.CANONICAL_URL
|
|
delete eventPayload.server.id
|
|
|
|
// Add stream info
|
|
if (eventPayload.streamId) {
|
|
eventPayload.stream = await getStream(
|
|
{
|
|
streamId: eventPayload.streamId,
|
|
userId: eventPayload.userId
|
|
},
|
|
{ trx }
|
|
)
|
|
}
|
|
|
|
// Add user info (except email and pwd)
|
|
if (eventPayload.userId) {
|
|
eventPayload.user = await Users()
|
|
.where({ id: eventPayload.userId })
|
|
.select('*')
|
|
.first()
|
|
if (eventPayload.user) {
|
|
delete eventPayload.user.passwordDigest
|
|
delete eventPayload.user.email
|
|
}
|
|
}
|
|
|
|
// with this select, we must have the streamid available on the webhook config,
|
|
// even when the stream is deleted, to dispatch the stream deleted webhook events
|
|
const { rows } = await knex.raw(
|
|
`
|
|
SELECT * FROM webhooks_config WHERE "streamId" = ?
|
|
`,
|
|
[streamId]
|
|
)
|
|
for (const wh of rows) {
|
|
if (!wh.enabled) continue
|
|
if (!(event in wh.triggers)) continue
|
|
|
|
// Add webhook info (the key `webhook` will be replaced for each webhook configured, before serializing the payload and storing it)
|
|
eventPayload.webhook = wh
|
|
eventPayload.webhook.triggers = Object.keys(eventPayload.webhook.triggers)
|
|
delete eventPayload.webhook.secret
|
|
|
|
const q = WebhooksEvents().insert({
|
|
id: crs({ length: 20 }),
|
|
webhookId: wh.id,
|
|
payload: JSON.stringify(eventPayload)
|
|
})
|
|
if (trx) q.transacting(trx)
|
|
await q
|
|
}
|
|
},
|
|
|
|
async getLastWebhookEvents({ webhookId, limit }) {
|
|
if (!limit) {
|
|
limit = 100
|
|
}
|
|
|
|
return await WebhooksEvents()
|
|
.select('*')
|
|
.where({ webhookId })
|
|
.orderBy('lastUpdate', 'desc')
|
|
.limit(limit)
|
|
},
|
|
|
|
async getWebhookEventsCount({ webhookId }) {
|
|
const [res] = await WebhooksEvents().count().where({ webhookId })
|
|
|
|
return parseInt(res.count)
|
|
}
|
|
}
|