mirror of
https://github.com/documenso/documenso.git
synced 2025-11-12 15:53:02 +10:00
feat: test webhook functionality (#1886)
This commit is contained in:
@ -1,5 +1,8 @@
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
import { TEAM_MEMBER_ROLE_PERMISSIONS_MAP } from '../../constants/teams';
|
||||
import { buildTeamWhereQuery } from '../../utils/teams';
|
||||
|
||||
export type GetWebhookByIdOptions = {
|
||||
id: string;
|
||||
userId: number;
|
||||
@ -10,23 +13,11 @@ export const getWebhookById = async ({ id, userId, teamId }: GetWebhookByIdOptio
|
||||
return await prisma.webhook.findFirstOrThrow({
|
||||
where: {
|
||||
id,
|
||||
userId,
|
||||
team: {
|
||||
id: teamId,
|
||||
teamGroups: {
|
||||
some: {
|
||||
organisationGroup: {
|
||||
organisationGroupMembers: {
|
||||
some: {
|
||||
organisationMember: {
|
||||
userId,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
team: buildTeamWhereQuery({
|
||||
teamId,
|
||||
userId,
|
||||
roles: TEAM_MEMBER_ROLE_PERMISSIONS_MAP.MANAGE_TEAM,
|
||||
}),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
44
packages/lib/server-only/webhooks/trigger-test-webhook.ts
Normal file
44
packages/lib/server-only/webhooks/trigger-test-webhook.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import type { WebhookTriggerEvents } from '@prisma/client';
|
||||
|
||||
import { getWebhookById } from './get-webhook-by-id';
|
||||
import { generateSampleWebhookPayload } from './trigger/generate-sample-data';
|
||||
import { triggerWebhook } from './trigger/trigger-webhook';
|
||||
|
||||
export type TriggerTestWebhookOptions = {
|
||||
id: string;
|
||||
event: WebhookTriggerEvents;
|
||||
userId: number;
|
||||
teamId: number;
|
||||
};
|
||||
|
||||
export const triggerTestWebhook = async ({
|
||||
id,
|
||||
event,
|
||||
userId,
|
||||
teamId,
|
||||
}: TriggerTestWebhookOptions) => {
|
||||
const webhook = await getWebhookById({ id, userId, teamId });
|
||||
|
||||
if (!webhook.enabled) {
|
||||
throw new Error('Webhook is disabled');
|
||||
}
|
||||
|
||||
if (!webhook.eventTriggers.includes(event)) {
|
||||
throw new Error(`Webhook does not support event: ${event}`);
|
||||
}
|
||||
|
||||
const samplePayload = generateSampleWebhookPayload(event, webhook.webhookUrl);
|
||||
|
||||
try {
|
||||
await triggerWebhook({
|
||||
event,
|
||||
data: samplePayload,
|
||||
userId,
|
||||
teamId,
|
||||
});
|
||||
|
||||
return { success: true, message: 'Test webhook triggered successfully' };
|
||||
} catch (error) {
|
||||
return { success: false, error: error instanceof Error ? error.message : 'Unknown error' };
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,485 @@
|
||||
import {
|
||||
DocumentDistributionMethod,
|
||||
DocumentSigningOrder,
|
||||
DocumentSource,
|
||||
DocumentStatus,
|
||||
DocumentVisibility,
|
||||
ReadStatus,
|
||||
RecipientRole,
|
||||
SendStatus,
|
||||
SigningStatus,
|
||||
WebhookTriggerEvents,
|
||||
} from '@prisma/client';
|
||||
|
||||
import type { WebhookPayload } from '../../../types/webhook-payload';
|
||||
|
||||
export const generateSampleWebhookPayload = (
|
||||
event: WebhookTriggerEvents,
|
||||
webhookUrl: string,
|
||||
): WebhookPayload => {
|
||||
const now = new Date();
|
||||
const basePayload = {
|
||||
id: 10,
|
||||
externalId: null,
|
||||
userId: 1,
|
||||
authOptions: null,
|
||||
formValues: null,
|
||||
visibility: DocumentVisibility.EVERYONE,
|
||||
title: 'documenso.pdf',
|
||||
status: DocumentStatus.DRAFT,
|
||||
documentDataId: 'hs8qz1ktr9204jn7mg6c5dxy0',
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
completedAt: null,
|
||||
deletedAt: null,
|
||||
teamId: null,
|
||||
templateId: null,
|
||||
source: DocumentSource.DOCUMENT,
|
||||
documentMeta: {
|
||||
id: 'doc_meta_123',
|
||||
subject: 'Please sign this document',
|
||||
message: 'Hello, please review and sign this document.',
|
||||
timezone: 'UTC',
|
||||
password: null,
|
||||
dateFormat: 'MM/DD/YYYY',
|
||||
redirectUrl: null,
|
||||
signingOrder: DocumentSigningOrder.PARALLEL,
|
||||
allowDictateNextSigner: false,
|
||||
typedSignatureEnabled: true,
|
||||
uploadSignatureEnabled: true,
|
||||
drawSignatureEnabled: true,
|
||||
language: 'en',
|
||||
distributionMethod: DocumentDistributionMethod.EMAIL,
|
||||
emailSettings: null,
|
||||
},
|
||||
recipients: [
|
||||
{
|
||||
id: 52,
|
||||
documentId: 10,
|
||||
templateId: null,
|
||||
email: 'signer@documenso.com',
|
||||
name: 'John Doe',
|
||||
token: 'SIGNING_TOKEN',
|
||||
documentDeletedAt: null,
|
||||
expired: null,
|
||||
signedAt: null,
|
||||
authOptions: null,
|
||||
signingOrder: 1,
|
||||
rejectionReason: null,
|
||||
role: RecipientRole.SIGNER,
|
||||
readStatus: ReadStatus.NOT_OPENED,
|
||||
signingStatus: SigningStatus.NOT_SIGNED,
|
||||
sendStatus: SendStatus.NOT_SENT,
|
||||
},
|
||||
],
|
||||
Recipient: [
|
||||
{
|
||||
id: 52,
|
||||
documentId: 10,
|
||||
templateId: null,
|
||||
email: 'signer@documenso.com',
|
||||
name: 'John Doe',
|
||||
token: 'SIGNING_TOKEN',
|
||||
documentDeletedAt: null,
|
||||
expired: null,
|
||||
signedAt: null,
|
||||
authOptions: null,
|
||||
signingOrder: 1,
|
||||
rejectionReason: null,
|
||||
role: RecipientRole.SIGNER,
|
||||
readStatus: ReadStatus.NOT_OPENED,
|
||||
signingStatus: SigningStatus.NOT_SIGNED,
|
||||
sendStatus: SendStatus.NOT_SENT,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
if (event === WebhookTriggerEvents.DOCUMENT_CREATED) {
|
||||
return {
|
||||
event,
|
||||
payload: {
|
||||
...basePayload,
|
||||
status: DocumentStatus.DRAFT,
|
||||
},
|
||||
createdAt: now.toISOString(),
|
||||
webhookEndpoint: webhookUrl,
|
||||
};
|
||||
}
|
||||
|
||||
if (event === WebhookTriggerEvents.DOCUMENT_SENT) {
|
||||
return {
|
||||
event,
|
||||
payload: {
|
||||
...basePayload,
|
||||
status: DocumentStatus.PENDING,
|
||||
recipients: [
|
||||
{
|
||||
...basePayload.recipients[0],
|
||||
email: 'signer2@documenso.com',
|
||||
name: 'Signer 2',
|
||||
role: RecipientRole.VIEWER,
|
||||
sendStatus: SendStatus.SENT,
|
||||
documentDeletedAt: null,
|
||||
expired: null,
|
||||
signedAt: null,
|
||||
authOptions: null,
|
||||
signingOrder: 1,
|
||||
rejectionReason: null,
|
||||
readStatus: ReadStatus.NOT_OPENED,
|
||||
signingStatus: SigningStatus.NOT_SIGNED,
|
||||
},
|
||||
],
|
||||
Recipient: [
|
||||
{
|
||||
...basePayload.Recipient[0],
|
||||
email: 'signer1@documenso.com',
|
||||
name: 'Signer 1',
|
||||
token: 'SIGNING_TOKEN',
|
||||
signingOrder: 2,
|
||||
role: RecipientRole.SIGNER,
|
||||
sendStatus: SendStatus.SENT,
|
||||
documentDeletedAt: null,
|
||||
expired: null,
|
||||
signedAt: null,
|
||||
authOptions: null,
|
||||
rejectionReason: null,
|
||||
readStatus: ReadStatus.NOT_OPENED,
|
||||
signingStatus: SigningStatus.NOT_SIGNED,
|
||||
},
|
||||
],
|
||||
},
|
||||
createdAt: now.toISOString(),
|
||||
webhookEndpoint: webhookUrl,
|
||||
};
|
||||
}
|
||||
|
||||
if (event === WebhookTriggerEvents.DOCUMENT_OPENED) {
|
||||
return {
|
||||
event,
|
||||
payload: {
|
||||
...basePayload,
|
||||
status: DocumentStatus.PENDING,
|
||||
recipients: [
|
||||
{
|
||||
...basePayload.recipients[0],
|
||||
email: 'signer2@documenso.com',
|
||||
name: 'Signer 2',
|
||||
role: RecipientRole.VIEWER,
|
||||
readStatus: ReadStatus.OPENED,
|
||||
sendStatus: SendStatus.SENT,
|
||||
documentDeletedAt: null,
|
||||
expired: null,
|
||||
signedAt: null,
|
||||
authOptions: null,
|
||||
signingOrder: 1,
|
||||
rejectionReason: null,
|
||||
signingStatus: SigningStatus.NOT_SIGNED,
|
||||
},
|
||||
],
|
||||
Recipient: [
|
||||
{
|
||||
...basePayload.Recipient[0],
|
||||
email: 'signer2@documenso.com',
|
||||
name: 'Signer 2',
|
||||
role: RecipientRole.VIEWER,
|
||||
readStatus: ReadStatus.OPENED,
|
||||
sendStatus: SendStatus.SENT,
|
||||
documentDeletedAt: null,
|
||||
expired: null,
|
||||
signedAt: null,
|
||||
authOptions: null,
|
||||
signingOrder: 1,
|
||||
rejectionReason: null,
|
||||
signingStatus: SigningStatus.NOT_SIGNED,
|
||||
},
|
||||
],
|
||||
},
|
||||
createdAt: now.toISOString(),
|
||||
webhookEndpoint: webhookUrl,
|
||||
};
|
||||
}
|
||||
|
||||
if (event === WebhookTriggerEvents.DOCUMENT_SIGNED) {
|
||||
return {
|
||||
event,
|
||||
payload: {
|
||||
...basePayload,
|
||||
status: DocumentStatus.COMPLETED,
|
||||
completedAt: now,
|
||||
recipients: [
|
||||
{
|
||||
...basePayload.recipients[0],
|
||||
id: 51,
|
||||
email: 'signer1@documenso.com',
|
||||
name: 'Signer 1',
|
||||
token: 'SIGNING_TOKEN',
|
||||
signedAt: now,
|
||||
authOptions: {
|
||||
accessAuth: null,
|
||||
actionAuth: null,
|
||||
},
|
||||
readStatus: ReadStatus.OPENED,
|
||||
signingStatus: SigningStatus.SIGNED,
|
||||
sendStatus: SendStatus.SENT,
|
||||
documentDeletedAt: null,
|
||||
expired: null,
|
||||
signingOrder: 1,
|
||||
rejectionReason: null,
|
||||
},
|
||||
],
|
||||
Recipient: [
|
||||
{
|
||||
...basePayload.Recipient[0],
|
||||
id: 51,
|
||||
email: 'signer1@documenso.com',
|
||||
name: 'Signer 1',
|
||||
token: 'SIGNING_TOKEN',
|
||||
signedAt: now,
|
||||
authOptions: {
|
||||
accessAuth: null,
|
||||
actionAuth: null,
|
||||
},
|
||||
readStatus: ReadStatus.OPENED,
|
||||
signingStatus: SigningStatus.SIGNED,
|
||||
sendStatus: SendStatus.SENT,
|
||||
documentDeletedAt: null,
|
||||
expired: null,
|
||||
signingOrder: 1,
|
||||
rejectionReason: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
createdAt: now.toISOString(),
|
||||
webhookEndpoint: webhookUrl,
|
||||
};
|
||||
}
|
||||
|
||||
if (event === WebhookTriggerEvents.DOCUMENT_COMPLETED) {
|
||||
return {
|
||||
event,
|
||||
payload: {
|
||||
...basePayload,
|
||||
status: DocumentStatus.COMPLETED,
|
||||
completedAt: now,
|
||||
recipients: [
|
||||
{
|
||||
id: 50,
|
||||
documentId: 10,
|
||||
templateId: null,
|
||||
email: 'signer2@documenso.com',
|
||||
name: 'Signer 2',
|
||||
token: 'SIGNING_TOKEN',
|
||||
documentDeletedAt: null,
|
||||
expired: null,
|
||||
signedAt: now,
|
||||
authOptions: {
|
||||
accessAuth: null,
|
||||
actionAuth: null,
|
||||
},
|
||||
signingOrder: 1,
|
||||
rejectionReason: null,
|
||||
role: RecipientRole.VIEWER,
|
||||
readStatus: ReadStatus.OPENED,
|
||||
signingStatus: SigningStatus.SIGNED,
|
||||
sendStatus: SendStatus.SENT,
|
||||
},
|
||||
{
|
||||
id: 51,
|
||||
documentId: 10,
|
||||
templateId: null,
|
||||
email: 'signer1@documenso.com',
|
||||
name: 'Signer 1',
|
||||
token: 'SIGNING_TOKEN',
|
||||
documentDeletedAt: null,
|
||||
expired: null,
|
||||
signedAt: now,
|
||||
authOptions: {
|
||||
accessAuth: null,
|
||||
actionAuth: null,
|
||||
},
|
||||
signingOrder: 2,
|
||||
rejectionReason: null,
|
||||
role: RecipientRole.SIGNER,
|
||||
readStatus: ReadStatus.OPENED,
|
||||
signingStatus: SigningStatus.SIGNED,
|
||||
sendStatus: SendStatus.SENT,
|
||||
},
|
||||
],
|
||||
Recipient: [
|
||||
{
|
||||
id: 50,
|
||||
documentId: 10,
|
||||
templateId: null,
|
||||
email: 'signer2@documenso.com',
|
||||
name: 'Signer 2',
|
||||
token: 'SIGNING_TOKEN',
|
||||
documentDeletedAt: null,
|
||||
expired: null,
|
||||
signedAt: now,
|
||||
authOptions: {
|
||||
accessAuth: null,
|
||||
actionAuth: null,
|
||||
},
|
||||
signingOrder: 1,
|
||||
rejectionReason: null,
|
||||
role: RecipientRole.VIEWER,
|
||||
readStatus: ReadStatus.OPENED,
|
||||
signingStatus: SigningStatus.SIGNED,
|
||||
sendStatus: SendStatus.SENT,
|
||||
},
|
||||
{
|
||||
id: 51,
|
||||
documentId: 10,
|
||||
templateId: null,
|
||||
email: 'signer1@documenso.com',
|
||||
name: 'Signer 1',
|
||||
token: 'SIGNING_TOKEN',
|
||||
documentDeletedAt: null,
|
||||
expired: null,
|
||||
signedAt: now,
|
||||
authOptions: {
|
||||
accessAuth: null,
|
||||
actionAuth: null,
|
||||
},
|
||||
signingOrder: 2,
|
||||
rejectionReason: null,
|
||||
role: RecipientRole.SIGNER,
|
||||
readStatus: ReadStatus.OPENED,
|
||||
signingStatus: SigningStatus.SIGNED,
|
||||
sendStatus: SendStatus.SENT,
|
||||
},
|
||||
],
|
||||
},
|
||||
createdAt: now.toISOString(),
|
||||
webhookEndpoint: webhookUrl,
|
||||
};
|
||||
}
|
||||
|
||||
if (event === WebhookTriggerEvents.DOCUMENT_REJECTED) {
|
||||
return {
|
||||
event,
|
||||
payload: {
|
||||
...basePayload,
|
||||
status: DocumentStatus.PENDING,
|
||||
recipients: [
|
||||
{
|
||||
...basePayload.recipients[0],
|
||||
signedAt: now,
|
||||
authOptions: {
|
||||
accessAuth: null,
|
||||
actionAuth: null,
|
||||
},
|
||||
rejectionReason: 'I do not agree with the terms',
|
||||
readStatus: ReadStatus.OPENED,
|
||||
signingStatus: SigningStatus.REJECTED,
|
||||
sendStatus: SendStatus.SENT,
|
||||
documentDeletedAt: null,
|
||||
expired: null,
|
||||
signingOrder: 1,
|
||||
},
|
||||
],
|
||||
Recipient: [
|
||||
{
|
||||
...basePayload.Recipient[0],
|
||||
signedAt: now,
|
||||
authOptions: {
|
||||
accessAuth: null,
|
||||
actionAuth: null,
|
||||
},
|
||||
rejectionReason: 'I do not agree with the terms',
|
||||
readStatus: ReadStatus.OPENED,
|
||||
signingStatus: SigningStatus.REJECTED,
|
||||
sendStatus: SendStatus.SENT,
|
||||
documentDeletedAt: null,
|
||||
expired: null,
|
||||
signingOrder: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
createdAt: now.toISOString(),
|
||||
webhookEndpoint: webhookUrl,
|
||||
};
|
||||
}
|
||||
|
||||
if (event === WebhookTriggerEvents.DOCUMENT_CANCELLED) {
|
||||
return {
|
||||
event,
|
||||
payload: {
|
||||
...basePayload,
|
||||
id: 7,
|
||||
externalId: null,
|
||||
userId: 3,
|
||||
status: DocumentStatus.PENDING,
|
||||
documentDataId: 'cm6exvn93006hi02ru90a265a',
|
||||
documentMeta: {
|
||||
...basePayload.documentMeta,
|
||||
id: 'cm6exvn96006ji02rqvzjvwoy',
|
||||
subject: '',
|
||||
message: '',
|
||||
timezone: 'Etc/UTC',
|
||||
dateFormat: 'yyyy-MM-dd hh:mm a',
|
||||
redirectUrl: '',
|
||||
emailSettings: {
|
||||
documentDeleted: true,
|
||||
documentPending: true,
|
||||
recipientSigned: true,
|
||||
recipientRemoved: true,
|
||||
documentCompleted: true,
|
||||
ownerDocumentCompleted: true,
|
||||
recipientSigningRequest: true,
|
||||
},
|
||||
},
|
||||
recipients: [
|
||||
{
|
||||
id: 7,
|
||||
documentId: 7,
|
||||
templateId: null,
|
||||
email: 'signer1@documenso.com',
|
||||
name: 'Signer 1',
|
||||
token: 'SIGNING_TOKEN',
|
||||
documentDeletedAt: null,
|
||||
expired: null,
|
||||
signedAt: null,
|
||||
authOptions: {
|
||||
accessAuth: null,
|
||||
actionAuth: null,
|
||||
},
|
||||
signingOrder: 1,
|
||||
rejectionReason: null,
|
||||
role: RecipientRole.SIGNER,
|
||||
readStatus: ReadStatus.NOT_OPENED,
|
||||
signingStatus: SigningStatus.NOT_SIGNED,
|
||||
sendStatus: SendStatus.SENT,
|
||||
},
|
||||
],
|
||||
Recipient: [
|
||||
{
|
||||
id: 7,
|
||||
documentId: 7,
|
||||
templateId: null,
|
||||
email: 'signer@documenso.com',
|
||||
name: 'Signer',
|
||||
token: 'SIGNING_TOKEN',
|
||||
documentDeletedAt: null,
|
||||
expired: null,
|
||||
signedAt: null,
|
||||
authOptions: {
|
||||
accessAuth: null,
|
||||
actionAuth: null,
|
||||
},
|
||||
signingOrder: 1,
|
||||
rejectionReason: null,
|
||||
role: RecipientRole.SIGNER,
|
||||
readStatus: ReadStatus.NOT_OPENED,
|
||||
signingStatus: SigningStatus.NOT_SIGNED,
|
||||
sendStatus: SendStatus.SENT,
|
||||
},
|
||||
],
|
||||
},
|
||||
createdAt: now.toISOString(),
|
||||
webhookEndpoint: webhookUrl,
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error(`Unsupported event type: ${event}`);
|
||||
};
|
||||
@ -1,4 +1,4 @@
|
||||
import type { Document, DocumentMeta, Recipient } from '@prisma/client';
|
||||
import type { Document, DocumentMeta, Recipient, WebhookTriggerEvents } from '@prisma/client';
|
||||
import {
|
||||
DocumentDistributionMethod,
|
||||
DocumentSigningOrder,
|
||||
@ -87,6 +87,13 @@ export const ZWebhookDocumentSchema = z.object({
|
||||
export type TWebhookRecipient = z.infer<typeof ZWebhookRecipientSchema>;
|
||||
export type TWebhookDocument = z.infer<typeof ZWebhookDocumentSchema>;
|
||||
|
||||
export type WebhookPayload = {
|
||||
event: WebhookTriggerEvents;
|
||||
payload: TWebhookDocument;
|
||||
createdAt: string;
|
||||
webhookEndpoint: string;
|
||||
};
|
||||
|
||||
export const mapDocumentToWebhookDocumentPayload = (
|
||||
document: Document & {
|
||||
recipients: Recipient[];
|
||||
|
||||
Reference in New Issue
Block a user