allow send data to webhook with rules
This commit is contained in:
@ -21,7 +21,7 @@ export enum RuleActionType {
|
||||
export enum RuleEventType {
|
||||
PageCreated = 'PAGE_CREATED',
|
||||
PageUpdated = 'PAGE_UPDATED',
|
||||
LabelCreated = 'PAGE_CREATED',
|
||||
LabelCreated = 'LABEL_CREATED',
|
||||
HighlightCreated = 'HIGHLIGHT_CREATED',
|
||||
}
|
||||
|
||||
|
||||
@ -2502,10 +2502,13 @@ export enum RuleActionType {
|
||||
Archive = 'ARCHIVE',
|
||||
Delete = 'DELETE',
|
||||
MarkAsRead = 'MARK_AS_READ',
|
||||
SendNotification = 'SEND_NOTIFICATION'
|
||||
SendNotification = 'SEND_NOTIFICATION',
|
||||
Webhook = 'WEBHOOK'
|
||||
}
|
||||
|
||||
export enum RuleEventType {
|
||||
HighlightCreated = 'HIGHLIGHT_CREATED',
|
||||
LabelCreated = 'LABEL_CREATED',
|
||||
PageCreated = 'PAGE_CREATED',
|
||||
PageUpdated = 'PAGE_UPDATED'
|
||||
}
|
||||
|
||||
@ -1879,9 +1879,12 @@ enum RuleActionType {
|
||||
DELETE
|
||||
MARK_AS_READ
|
||||
SEND_NOTIFICATION
|
||||
WEBHOOK
|
||||
}
|
||||
|
||||
enum RuleEventType {
|
||||
HIGHLIGHT_CREATED
|
||||
LABEL_CREATED
|
||||
PAGE_CREATED
|
||||
PAGE_UPDATED
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { LiqeQuery } from '@omnivore/liqe'
|
||||
import axios, { Method } from 'axios'
|
||||
import { ReadingProgressDataSource } from '../datasources/reading_progress_data_source'
|
||||
import { LibraryItem, LibraryItemState } from '../entity/library_item'
|
||||
import { Rule, RuleAction, RuleActionType, RuleEventType } from '../entity/rule'
|
||||
@ -28,6 +29,7 @@ interface RuleActionObj {
|
||||
userId: string
|
||||
action: RuleAction
|
||||
data: ItemEvent | LibraryItem
|
||||
ruleEventType: RuleEventType
|
||||
}
|
||||
type RuleActionFunc = (obj: RuleActionObj) => Promise<unknown>
|
||||
|
||||
@ -86,6 +88,29 @@ const sendNotification = async (obj: RuleActionObj) => {
|
||||
return sendPushNotifications(obj.userId, message, 'rule', data)
|
||||
}
|
||||
|
||||
const sendToWebhook = async (obj: RuleActionObj) => {
|
||||
const [url, method, contentType] = obj.action.params
|
||||
const [type, action] = obj.ruleEventType.split('_')
|
||||
|
||||
const body = {
|
||||
action,
|
||||
userId: obj.userId,
|
||||
[type]: obj.data,
|
||||
}
|
||||
|
||||
logger.info('triggering webhook', { url, method })
|
||||
|
||||
return axios.request({
|
||||
url,
|
||||
method: method as Method,
|
||||
headers: {
|
||||
'Content-Type': contentType,
|
||||
},
|
||||
data: body,
|
||||
timeout: 5000, // 5s
|
||||
})
|
||||
}
|
||||
|
||||
const getRuleAction = (
|
||||
actionType: RuleActionType
|
||||
): RuleActionFunc | undefined => {
|
||||
@ -100,6 +125,8 @@ const getRuleAction = (
|
||||
return markPageAsRead
|
||||
case RuleActionType.SendNotification:
|
||||
return sendNotification
|
||||
case RuleActionType.Webhook:
|
||||
return sendToWebhook
|
||||
default:
|
||||
logger.error('Unknown rule action type', actionType)
|
||||
return undefined
|
||||
@ -110,7 +137,8 @@ const triggerActions = async (
|
||||
libraryItemId: string,
|
||||
userId: string,
|
||||
rules: Rule[],
|
||||
data: ItemEvent
|
||||
data: ItemEvent,
|
||||
ruleEventType: RuleEventType
|
||||
) => {
|
||||
const actionPromises: Promise<unknown>[] = []
|
||||
|
||||
@ -165,6 +193,7 @@ const triggerActions = async (
|
||||
userId,
|
||||
action,
|
||||
data: results[0],
|
||||
ruleEventType,
|
||||
}
|
||||
|
||||
actionPromises.push(actionFunc(actionObj))
|
||||
@ -188,7 +217,7 @@ export const triggerRule = async (jobData: TriggerRuleJobData) => {
|
||||
return false
|
||||
}
|
||||
|
||||
await triggerActions(libraryItemId, userId, rules, data)
|
||||
await triggerActions(libraryItemId, userId, rules, data, ruleEventType)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@ -12,6 +12,8 @@ import {
|
||||
import { buildLogger } from './utils/logger'
|
||||
import { isYouTubeVideoURL } from './utils/youtube'
|
||||
|
||||
export type BaseEntityEvent = { id: string; userId: string }
|
||||
|
||||
const logger = buildLogger('pubsub')
|
||||
|
||||
const client = new PubSub()
|
||||
@ -46,7 +48,7 @@ export const createPubSubClient = (): PubsubClient => {
|
||||
Buffer.from(JSON.stringify({ userId, email, name, username }))
|
||||
)
|
||||
},
|
||||
entityCreated: async <T extends Record<string, any>>(
|
||||
entityCreated: async <T extends BaseEntityEvent>(
|
||||
type: EntityType,
|
||||
data: T,
|
||||
userId: string,
|
||||
@ -54,10 +56,10 @@ export const createPubSubClient = (): PubsubClient => {
|
||||
): Promise<void> => {
|
||||
// queue trigger rule job
|
||||
await enqueueTriggerRuleJob({
|
||||
userId,
|
||||
ruleEventType: `${type.toUpperCase()}_CREATED` as RuleEventType,
|
||||
libraryItemId,
|
||||
data,
|
||||
userId,
|
||||
libraryItemId,
|
||||
})
|
||||
// queue export item job
|
||||
await enqueueExportItem({
|
||||
@ -92,21 +94,20 @@ export const createPubSubClient = (): PubsubClient => {
|
||||
}
|
||||
}
|
||||
},
|
||||
entityUpdated: async <T extends Record<string, any>>(
|
||||
entityUpdated: async <T extends BaseEntityEvent>(
|
||||
type: EntityType,
|
||||
data: T,
|
||||
userId: string,
|
||||
libraryItemId: string
|
||||
): Promise<void> => {
|
||||
// queue trigger rule job
|
||||
if (type === EntityType.PAGE) {
|
||||
await enqueueTriggerRuleJob({
|
||||
userId,
|
||||
ruleEventType: RuleEventType.PageUpdated,
|
||||
libraryItemId,
|
||||
data,
|
||||
})
|
||||
}
|
||||
await enqueueTriggerRuleJob({
|
||||
userId,
|
||||
ruleEventType: RuleEventType.PageUpdated,
|
||||
libraryItemId,
|
||||
data,
|
||||
})
|
||||
|
||||
// queue export item job
|
||||
await enqueueExportItem({
|
||||
userId,
|
||||
@ -145,7 +146,7 @@ export const createPubSubClient = (): PubsubClient => {
|
||||
}
|
||||
|
||||
export enum EntityType {
|
||||
PAGE = 'page',
|
||||
ITEM = 'page',
|
||||
HIGHLIGHT = 'highlight',
|
||||
LABEL = 'label',
|
||||
RSS_FEED = 'feed',
|
||||
@ -158,13 +159,13 @@ export interface PubsubClient {
|
||||
name: string,
|
||||
username: string
|
||||
) => Promise<void>
|
||||
entityCreated: <T extends Record<string, any>>(
|
||||
entityCreated: <T extends BaseEntityEvent>(
|
||||
type: EntityType,
|
||||
data: T,
|
||||
userId: string,
|
||||
libraryItemId: string
|
||||
) => Promise<void>
|
||||
entityUpdated: <T extends Record<string, any>>(
|
||||
entityUpdated: <T extends BaseEntityEvent>(
|
||||
type: EntityType,
|
||||
data: T,
|
||||
userId: string,
|
||||
|
||||
@ -2167,6 +2167,7 @@ const schema = gql`
|
||||
DELETE
|
||||
MARK_AS_READ
|
||||
SEND_NOTIFICATION
|
||||
WEBHOOK
|
||||
}
|
||||
|
||||
type RulesError {
|
||||
@ -2181,6 +2182,8 @@ const schema = gql`
|
||||
enum RuleEventType {
|
||||
PAGE_CREATED
|
||||
PAGE_UPDATED
|
||||
LABEL_CREATED
|
||||
HIGHLIGHT_CREATED
|
||||
}
|
||||
|
||||
input SetRuleInput {
|
||||
|
||||
@ -59,7 +59,7 @@ export const createHighlight = async (
|
||||
|
||||
await pubsub.entityCreated<UpdateItemEvent>(
|
||||
EntityType.HIGHLIGHT,
|
||||
{ id: libraryItemId, highlights: [newHighlight] },
|
||||
{ id: libraryItemId, highlights: [newHighlight], userId },
|
||||
userId,
|
||||
libraryItemId
|
||||
)
|
||||
@ -107,7 +107,7 @@ export const mergeHighlights = async (
|
||||
|
||||
await pubsub.entityCreated<UpdateItemEvent>(
|
||||
EntityType.HIGHLIGHT,
|
||||
{ id: libraryItemId, highlights: [newHighlight] },
|
||||
{ id: libraryItemId, highlights: [newHighlight], userId },
|
||||
userId,
|
||||
libraryItemId
|
||||
)
|
||||
@ -142,7 +142,7 @@ export const updateHighlight = async (
|
||||
const libraryItemId = updatedHighlight.libraryItem.id
|
||||
await pubsub.entityUpdated<UpdateItemEvent>(
|
||||
EntityType.HIGHLIGHT,
|
||||
{ id: libraryItemId, highlights: [highlight] },
|
||||
{ id: libraryItemId, highlights: [highlight], userId },
|
||||
userId,
|
||||
libraryItemId
|
||||
)
|
||||
|
||||
@ -146,7 +146,7 @@ export const saveLabelsInLibraryItem = async (
|
||||
// create pubsub event
|
||||
await pubsub.entityCreated<UpdateItemEvent>(
|
||||
EntityType.LABEL,
|
||||
{ id: libraryItemId, labels },
|
||||
{ id: libraryItemId, labels, userId },
|
||||
userId,
|
||||
libraryItemId
|
||||
)
|
||||
@ -217,7 +217,7 @@ export const saveLabelsInHighlight = async (
|
||||
// create pubsub event
|
||||
await pubsub.entityCreated<UpdateItemEvent>(
|
||||
EntityType.LABEL,
|
||||
{ id: libraryItemId, highlights: [{ id: highlightId, labels }] },
|
||||
{ id: libraryItemId, highlights: [{ id: highlightId, labels }], userId },
|
||||
userId,
|
||||
libraryItemId
|
||||
)
|
||||
|
||||
@ -15,7 +15,7 @@ import { Highlight } from '../entity/highlight'
|
||||
import { Label } from '../entity/label'
|
||||
import { LibraryItem, LibraryItemState } from '../entity/library_item'
|
||||
import { BulkActionType, InputMaybe, SortParams } from '../generated/graphql'
|
||||
import { createPubSubClient, EntityType } from '../pubsub'
|
||||
import { BaseEntityEvent, createPubSubClient, EntityType } from '../pubsub'
|
||||
import { redisDataSource } from '../redis_data_source'
|
||||
import {
|
||||
authTrx,
|
||||
@ -37,10 +37,13 @@ type IgnoredFields =
|
||||
| 'links'
|
||||
| 'textContentHash'
|
||||
export type ItemEvent = CreateItemEvent | UpdateItemEvent
|
||||
export type CreateItemEvent = Omit<DeepPartial<LibraryItem>, IgnoredFields>
|
||||
export type UpdateItemEvent = Omit<
|
||||
QueryDeepPartialEntity<LibraryItem>,
|
||||
IgnoredFields
|
||||
export type CreateItemEvent = Merge<
|
||||
Omit<DeepPartial<LibraryItem>, IgnoredFields>,
|
||||
BaseEntityEvent
|
||||
>
|
||||
export type UpdateItemEvent = Merge<
|
||||
Omit<QueryDeepPartialEntity<LibraryItem>, IgnoredFields>,
|
||||
BaseEntityEvent
|
||||
>
|
||||
|
||||
export class RequiresSearchQueryError extends Error {
|
||||
@ -841,7 +844,7 @@ export const softDeleteLibraryItem = async (
|
||||
userId
|
||||
)
|
||||
|
||||
await pubsub.entityDeleted(EntityType.PAGE, id, userId)
|
||||
await pubsub.entityDeleted(EntityType.ITEM, id, userId)
|
||||
|
||||
return deletedLibraryItem
|
||||
}
|
||||
@ -883,13 +886,8 @@ export const updateLibraryItem = async (
|
||||
if (libraryItem.state === LibraryItemState.Succeeded) {
|
||||
// send create event if the item was created
|
||||
await pubsub.entityCreated<CreateItemEvent>(
|
||||
EntityType.PAGE,
|
||||
{
|
||||
...updatedLibraryItem,
|
||||
originalContent: undefined,
|
||||
readableContent: undefined,
|
||||
feedContent: undefined,
|
||||
},
|
||||
EntityType.ITEM,
|
||||
{ ...updatedLibraryItem, userId },
|
||||
userId,
|
||||
id
|
||||
)
|
||||
@ -898,13 +896,8 @@ export const updateLibraryItem = async (
|
||||
}
|
||||
|
||||
await pubsub.entityUpdated<UpdateItemEvent>(
|
||||
EntityType.PAGE,
|
||||
{
|
||||
...libraryItem,
|
||||
originalContent: undefined,
|
||||
readableContent: undefined,
|
||||
feedContent: undefined,
|
||||
},
|
||||
EntityType.ITEM,
|
||||
{ ...libraryItem, id, userId },
|
||||
userId,
|
||||
id
|
||||
)
|
||||
@ -966,8 +959,8 @@ export const updateLibraryItemReadingProgress = async (
|
||||
|
||||
const updatedItem = result[0][0]
|
||||
await pubsub.entityUpdated<UpdateItemEvent>(
|
||||
EntityType.PAGE,
|
||||
updatedItem,
|
||||
EntityType.ITEM,
|
||||
{ ...updatedItem, id, userId },
|
||||
userId,
|
||||
id
|
||||
)
|
||||
@ -1067,13 +1060,8 @@ export const createOrUpdateLibraryItem = async (
|
||||
}
|
||||
|
||||
await pubsub.entityCreated<CreateItemEvent>(
|
||||
EntityType.PAGE,
|
||||
{
|
||||
...newLibraryItem,
|
||||
originalContent: undefined,
|
||||
readableContent: undefined,
|
||||
feedContent: undefined,
|
||||
},
|
||||
EntityType.ITEM,
|
||||
{ ...newLibraryItem, userId },
|
||||
userId,
|
||||
newLibraryItem.id
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user