Files
documenso/apps/web/src/pages/api/stripe/webhook/index.ts
2023-11-06 13:01:06 +11:00

174 lines
4.6 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 {
DocumentStatus,
FieldType,
ReadStatus,
SendStatus,
SigningStatus,
} from '@documenso/prisma/client';
const log = (...args: any[]) => console.log('[stripe]', ...args);
export const config = {
api: { bodyParser: false },
};
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
// eslint-disable-next-line turbo/no-undeclared-env-vars
// 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') {
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 document = await prisma.document.create({
data: {
title: 'Documenso Supporter Pledge.pdf',
status: DocumentStatus.COMPLETED,
userId: user.id,
document: readFileSync('./public/documenso-supporter-pledge.pdf').toString('base64'),
created: now,
},
});
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) {
document.document = await insertImageInPDF(
document.document,
signatureDataUrl,
field.positionX,
field.positionY,
field.page,
);
} else {
document.document = await insertTextInPDF(
document.document,
signatureText ?? '',
field.positionX,
field.positionY,
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: {
document: document.document,
},
}),
]);
}
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',
});
}