Send webhook on all operation on all collections and global

This commit is contained in:
DrMint 2024-06-15 17:28:51 +02:00
parent 8391b18764
commit 0ccf62aa8d
9 changed files with 101 additions and 43 deletions

View File

@ -2,7 +2,6 @@ import { text } from "payload/dist/fields/validations";
import { mustBeAdmin } from "../../accesses/collections/mustBeAdmin";
import { shownOnlyToAdmin } from "../../accesses/collections/shownOnlyToAdmin";
import { CollectionGroups, Collections } from "../../constants";
import { afterOperationWebhook } from "../../hooks/afterOperationWebhook";
import { buildCollectionConfig } from "../../utils/collectionConfig";
import { getAllEndpoint } from "./endpoints/getAllEndpoint";
import { importFromStrapi } from "./endpoints/importFromStrapi";
@ -27,9 +26,6 @@ export const Currencies = buildCollectionConfig({
hidden: shownOnlyToAdmin,
},
access: { create: mustBeAdmin, update: mustBeAdmin, delete: mustBeAdmin },
hooks: {
afterOperation: [afterOperationWebhook],
},
endpoints: [importFromStrapi, getAllEndpoint],
timestamps: false,
fields: [

View File

@ -2,7 +2,6 @@ import { text } from "payload/dist/fields/validations";
import { mustBeAdmin } from "../../accesses/collections/mustBeAdmin";
import { shownOnlyToAdmin } from "../../accesses/collections/shownOnlyToAdmin";
import { CollectionGroups, Collections } from "../../constants";
import { afterOperationWebhook } from "../../hooks/afterOperationWebhook";
import { buildCollectionConfig } from "../../utils/collectionConfig";
import { getAllEndpoint } from "./endpoints/getAllEndpoint";
import { importFromStrapi } from "./endpoints/importFromStrapi";
@ -28,9 +27,6 @@ export const Languages = buildCollectionConfig({
hidden: shownOnlyToAdmin,
},
access: { create: mustBeAdmin, update: mustBeAdmin, delete: mustBeAdmin },
hooks: {
afterOperation: [afterOperationWebhook],
},
timestamps: false,
endpoints: [importFromStrapi, getAllEndpoint],
fields: [

View File

@ -4,7 +4,6 @@ import { QuickFilters, languageBasedFilters } from "../../components/QuickFilter
import { CollectionGroups, Collections } from "../../constants";
import { rowField } from "../../fields/rowField/rowField";
import { translatedFields } from "../../fields/translatedFields/translatedFields";
import { afterOperationWebhook } from "../../hooks/afterOperationWebhook";
import { beforeDuplicateAddCopyTo } from "../../hooks/beforeDuplicateAddCopyTo";
import { buildCollectionConfig } from "../../utils/collectionConfig";
import { getAllEndpoint } from "./endpoints/getAllEndpoint";
@ -43,9 +42,6 @@ export const Wordings: CollectionConfig = buildCollectionConfig({
create: mustBeAdmin,
delete: mustBeAdmin,
},
hooks: {
afterOperation: [afterOperationWebhook],
},
endpoints: [getAllEndpoint],
fields: [
{

View File

@ -86,6 +86,20 @@ export enum AttributeTypes {
Tags = "Tags",
}
/* WEB HOOKS */
export interface WebHookMessage {
collection: Collections;
operation: WebHookOperationType;
id?: string;
}
export enum WebHookOperationType {
create = "create",
update = "update",
delete = "delete",
}
/* RICH TEXT */
export type RichTextContent = {

View File

@ -1,12 +1,24 @@
import { AfterChangeHook } from "payload/dist/globals/config/types";
import { Collections, WebHookMessage, WebHookOperationType } from "../constants";
export const afterChangeWebhook: AfterChangeHook = async ({ doc, global }) => {
const url = `${process.env.WEB_HOOK_URI}/collection-operation`;
await fetch(url, {
const message: WebHookMessage = {
collection: global.slug as Collections,
operation: WebHookOperationType.update,
};
fetch(url, {
headers: {
Authorization: `Bearer ${process.env.WEB_HOOK_TOKEN}`,
Collection: global.slug,
"Content-Type": "application/json",
},
body: JSON.stringify(message),
method: "POST",
}).catch((e) => {
console.warn("Error while sending webhook", url, e);
});
return doc;
};

View File

@ -1,18 +1,58 @@
import { AfterOperationHook } from "payload/dist/collections/config/types";
import { Collections, WebHookMessage, WebHookOperationType } from "../constants";
const convertOperationToWebHookOperationType = (
operation: string
): WebHookOperationType | undefined => {
switch (operation) {
case "create":
return WebHookOperationType.create;
case "update":
case "updateByID":
return WebHookOperationType.update;
case "delete":
case "deleteByID":
return WebHookOperationType.delete;
default:
return undefined;
}
};
export const afterOperationWebhook: AfterOperationHook = ({ result, collection, operation }) => {
const operationType = convertOperationToWebHookOperationType(operation);
if (!operationType) return result;
if (operationType === WebHookOperationType.update) {
if ("_status" in result && result._status === "draft") {
return result;
}
}
if (!("id" in result)) {
return result;
}
const message: WebHookMessage = {
collection: collection.slug as Collections,
operation: operationType,
id: result.id,
};
export const afterOperationWebhook: AfterOperationHook = async ({
result,
collection,
operation,
}) => {
if (["create", "delete", "deleteByID", "update", "updateByID"].includes(operation)) {
const url = `${process.env.WEB_HOOK_URI}/collection-operation`;
await fetch(url, {
fetch(url, {
headers: {
Authorization: `Bearer ${process.env.WEB_HOOK_TOKEN}`,
Collection: collection.slug,
"Content-Type": "application/json",
},
body: JSON.stringify(message),
method: "POST",
}).catch((e) => {
console.warn("Error while sending webhook", url, e);
});
}
return result;
};

View File

@ -1,5 +1,6 @@
import { GeneratedTypes } from "payload";
import { CollectionConfig } from "payload/types";
import { afterOperationWebhook } from "../hooks/afterOperationWebhook";
import { formatToPascalCase } from "./string";
type CollectionConfigWithPlugins = CollectionConfig;
@ -15,4 +16,8 @@ export type BuildCollectionConfig = Omit<
export const buildCollectionConfig = (config: BuildCollectionConfig): CollectionConfig => ({
...config,
typescript: { interface: formatToPascalCase(config.labels.singular) },
hooks: {
...config.hooks,
afterOperation: [...(config.hooks?.afterOperation ?? []), afterOperationWebhook],
},
});

View File

@ -14,7 +14,7 @@ import {
isNodeUploadNode,
isUploadNodeAudioNode,
isUploadNodeImageNode,
isUploadNodeVideoNode
isUploadNodeVideoNode,
} from "../constants";
import {
EndpointAttribute,

View File

@ -1,6 +1,6 @@
import { CollectionBeforeChangeHook, CollectionConfig, RelationshipField } from "payload/types";
import { Collections } from "../constants";
import { BuildCollectionConfig } from "./collectionConfig";
import { BuildCollectionConfig, buildCollectionConfig } from "./collectionConfig";
const fields = { updatedBy: "updatedBy" };
@ -19,17 +19,16 @@ const updatedByField = (): RelationshipField => ({
type BuildVersionedCollectionConfig = Omit<BuildCollectionConfig, "timestamps" | "versions">;
export const buildVersionedCollectionConfig = ({
hooks: { beforeChange, ...otherHooks } = {},
fields,
...otherParams
}: BuildVersionedCollectionConfig): CollectionConfig => ({
...otherParams,
export const buildVersionedCollectionConfig = (
config: BuildVersionedCollectionConfig
): CollectionConfig =>
buildCollectionConfig({
...config,
timestamps: true,
versions: { drafts: { autosave: true } },
hooks: {
...otherHooks,
beforeChange: [...(beforeChange ?? []), beforeChangeUpdatedBy],
...config.hooks,
beforeChange: [...(config.hooks?.beforeChange ?? []), beforeChangeUpdatedBy],
},
fields: [...fields, updatedByField()],
});
fields: [...config.fields, updatedByField()],
});