mirror of
https://github.com/documenso/documenso.git
synced 2025-11-10 04:22:32 +10:00
198 lines
5.3 KiB
TypeScript
198 lines
5.3 KiB
TypeScript
import { NextApiRequest, NextApiResponse } from 'next';
|
|
|
|
import { randomBytes } from 'crypto';
|
|
import { readFileSync } from 'fs';
|
|
import { buffer } from 'micro';
|
|
|
|
import { insertImageInPDF } from '@documenso/lib/server-only/pdf/insert-image-in-pdf';
|
|
import { insertTextInPDF } from '@documenso/lib/server-only/pdf/insert-text-in-pdf';
|
|
import { redis } from '@documenso/lib/server-only/redis';
|
|
import { Stripe, stripe } from '@documenso/lib/server-only/stripe';
|
|
import { prisma } from '@documenso/prisma';
|
|
import {
|
|
DocumentDataType,
|
|
DocumentStatus,
|
|
FieldType,
|
|
ReadStatus,
|
|
SendStatus,
|
|
SigningStatus,
|
|
} from '@documenso/prisma/client';
|
|
|
|
const log = (...args: unknown[]) => console.log('[stripe]', ...args);
|
|
|
|
export const config = {
|
|
api: { bodyParser: false },
|
|
};
|
|
|
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|
// if (!process.env.NEXT_PUBLIC_ALLOW_SUBSCRIPTIONS) {
|
|
// return res.status(500).json({
|
|
// success: false,
|
|
// message: 'Subscriptions are not enabled',
|
|
// });
|
|
// }
|
|
|
|
const sig =
|
|
typeof req.headers['stripe-signature'] === 'string' ? req.headers['stripe-signature'] : '';
|
|
|
|
if (!sig) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: 'No signature found in request',
|
|
});
|
|
}
|
|
|
|
log('constructing body...');
|
|
const body = await buffer(req);
|
|
log('constructed body');
|
|
|
|
const event = stripe.webhooks.constructEvent(
|
|
body,
|
|
sig,
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion, turbo/no-undeclared-env-vars
|
|
process.env.NEXT_PRIVATE_STRIPE_WEBHOOK_SECRET!,
|
|
);
|
|
log('event-type:', event.type);
|
|
|
|
if (event.type === 'checkout.session.completed') {
|
|
// This is required since we don't want to create a guard for every event type
|
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
const session = event.data.object as Stripe.Checkout.Session;
|
|
|
|
if (session.metadata?.source === 'landing') {
|
|
const user = await prisma.user.findFirst({
|
|
where: {
|
|
id: Number(session.client_reference_id),
|
|
},
|
|
});
|
|
|
|
if (!user) {
|
|
return res.status(500).json({
|
|
success: false,
|
|
message: 'User not found',
|
|
});
|
|
}
|
|
|
|
const signatureText = session.metadata?.signatureText || user.name;
|
|
let signatureDataUrl = '';
|
|
|
|
if (session.metadata?.signatureDataUrl) {
|
|
const result = await redis.get<string>(`signature:${session.metadata.signatureDataUrl}`);
|
|
|
|
if (result) {
|
|
signatureDataUrl = result;
|
|
}
|
|
}
|
|
|
|
const now = new Date();
|
|
|
|
const bytes64 = readFileSync('./public/documenso-supporter-pledge.pdf').toString('base64');
|
|
|
|
const { id: documentDataId } = await prisma.documentData.create({
|
|
data: {
|
|
type: DocumentDataType.BYTES_64,
|
|
data: bytes64,
|
|
initialData: bytes64,
|
|
},
|
|
});
|
|
|
|
const document = await prisma.document.create({
|
|
data: {
|
|
title: 'Documenso Supporter Pledge.pdf',
|
|
status: DocumentStatus.COMPLETED,
|
|
userId: user.id,
|
|
documentDataId,
|
|
},
|
|
include: {
|
|
documentData: true,
|
|
},
|
|
});
|
|
|
|
const { documentData } = document;
|
|
|
|
if (!documentData) {
|
|
throw new Error(`Document ${document.id} has no document data`);
|
|
}
|
|
|
|
const recipient = await prisma.recipient.create({
|
|
data: {
|
|
name: user.name ?? '',
|
|
email: user.email,
|
|
token: randomBytes(16).toString('hex'),
|
|
signedAt: now,
|
|
readStatus: ReadStatus.OPENED,
|
|
sendStatus: SendStatus.SENT,
|
|
signingStatus: SigningStatus.SIGNED,
|
|
documentId: document.id,
|
|
},
|
|
});
|
|
|
|
const field = await prisma.field.create({
|
|
data: {
|
|
documentId: document.id,
|
|
recipientId: recipient.id,
|
|
type: FieldType.SIGNATURE,
|
|
page: 0,
|
|
positionX: 77,
|
|
positionY: 638,
|
|
inserted: false,
|
|
customText: '',
|
|
},
|
|
});
|
|
|
|
if (signatureDataUrl) {
|
|
documentData.data = await insertImageInPDF(
|
|
documentData.data,
|
|
signatureDataUrl,
|
|
field.positionX.toNumber(),
|
|
field.positionY.toNumber(),
|
|
field.page,
|
|
);
|
|
} else {
|
|
documentData.data = await insertTextInPDF(
|
|
documentData.data,
|
|
signatureText ?? '',
|
|
field.positionX.toNumber(),
|
|
field.positionY.toNumber(),
|
|
field.page,
|
|
);
|
|
}
|
|
|
|
await Promise.all([
|
|
prisma.signature.create({
|
|
data: {
|
|
fieldId: field.id,
|
|
recipientId: recipient.id,
|
|
signatureImageAsBase64: signatureDataUrl || undefined,
|
|
typedSignature: signatureDataUrl ? '' : signatureText,
|
|
},
|
|
}),
|
|
prisma.document.update({
|
|
where: {
|
|
id: document.id,
|
|
},
|
|
data: {
|
|
documentData: {
|
|
update: {
|
|
data: documentData.data,
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
]);
|
|
}
|
|
|
|
return res.status(200).json({
|
|
success: true,
|
|
message: 'Webhook received',
|
|
});
|
|
}
|
|
|
|
log('Unhandled webhook event', event.type);
|
|
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: 'Unhandled webhook event',
|
|
});
|
|
}
|