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

View File

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

View File

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

View File

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

View File

@ -1,12 +1,24 @@
import { AfterChangeHook } from "payload/dist/globals/config/types"; import { AfterChangeHook } from "payload/dist/globals/config/types";
import { Collections, WebHookMessage, WebHookOperationType } from "../constants";
export const afterChangeWebhook: AfterChangeHook = async ({ doc, global }) => { export const afterChangeWebhook: AfterChangeHook = async ({ doc, global }) => {
const url = `${process.env.WEB_HOOK_URI}/collection-operation`; 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: { headers: {
Authorization: `Bearer ${process.env.WEB_HOOK_TOKEN}`, 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; return doc;
}; };

View File

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

View File

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

View File

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

View File

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