start working on integrating stripe

This commit is contained in:
adueck 2022-10-12 23:36:20 +05:00
parent c9fac35ee3
commit 9fc109449d
7 changed files with 1829 additions and 2 deletions

View File

@ -29,6 +29,7 @@
"pug": "^3.0.2",
"redis": "^3.1.2",
"session-file-store": "^1.5.0",
"stripe": "^10.13.0",
"uuid": "^8.3.2"
},
"devDependencies": {

View File

@ -7,6 +7,7 @@ import authRouter from "./routers/auth-router";
import apiRouter from "./routers/api-router";
import inProd from "./lib/inProd";
import feedbackRouter from "./routers/feedback-router";
import paymentRouter from "./routers/payment-router";
const app = express();
@ -29,7 +30,8 @@ setupPassport(passport);
app.use("/", authRouter(passport));
// REST API - returning json
app.use("/api", apiRouter);
app.use("/feedback", feedbackRouter)
app.use("/feedback", feedbackRouter);
app.use("/payment", paymentRouter);
// START 💨 //
app.listen(4000, () => console.log("Server Has Started on 4000"));

View File

@ -9,6 +9,7 @@ const names = [
"LINGDOCS_ACCOUNT_GITHUB_CLIENT_SECRET",
"LINGDOCS_ACCOUNT_RECAPTCHA_SECRET",
"LINGDOCS_ACCOUNT_UPGRADE_PASSWORD",
"STRIPE_SECRET_KEY",
];
const values = names.map((name) => ({
@ -33,4 +34,5 @@ export default {
githubClientSecret: values[7].value,
recaptchaSecret: values[8].value,
upgradePassword: values[9].value,
stripeSecretKey: values[10].value,
};

View File

@ -300,7 +300,10 @@ const authRouter = (passport: PassportStatic) => {
});
router.post("/sign-out", (req, res) => {
req.logOut();
req.logOut((err) => {
console.error("error logging out");
console.error(err);
});
res.redirect("/");
});

View File

@ -0,0 +1,125 @@
import express from "express";
import * as T from "../../../website/src/types/account-types";
import env from "../lib/env-vars";
import Stripe from "stripe";
const stripe = new Stripe(env.stripeSecretKey, {
apiVersion: "2022-08-01",
});
const paymentRouter = express.Router();
// Guard all api with authentication
paymentRouter.use((req, res, next) => {
if (req.isAuthenticated()) {
return next();
}
const r: T.APIResponse = { ok: false, error: "401 Unauthorized" };
return res.status(401).send(r);
});
paymentRouter.post("/create-checkout-session", async (req, res, next) => {
const prices = await stripe.prices.list({
lookup_keys: [req.body.lookup_key],
expand: ['data.product'],
});
const session = await stripe.checkout.sessions.create({
billing_address_collection: 'auto',
line_items: [
{
price: prices.data[0].id,
// For metered billing, do not pass quantity
quantity: 1,
},
],
mode: 'subscription',
success_url: `/success`,
cancel_url: `/cancel`,
});
if (!session.url) {
return next("error creating session url");
}
res.redirect(303, session.url);
});
paymentRouter.post('/create-portal-session', async (req, res, next) => {
if (!req.user) {
return next("error finding user");
}
const portalSession = await stripe.billingPortal.sessions.create({
customer: req.user.userId,
return_url: "/",
});
res.redirect(303, portalSession.url);
});
paymentRouter.post(
'/webhook',
express.raw({ type: 'application/json' }),
(request, response) => {
let event = request.body;
// Replace this endpoint secret with your endpoint's unique secret
// If you are testing with the CLI, find the secret by running 'stripe listen'
// If you are using an endpoint defined with the API or dashboard, look in your webhook settings
// at https://dashboard.stripe.com/webhooks
const endpointSecret = 'whsec_12345';
// Only verify the event if you have an endpoint secret defined.
// Otherwise use the basic event deserialized with JSON.parse
if (endpointSecret) {
// Get the signature sent by Stripe
const signature = request.headers['stripe-signature'] || "";
try {
event = stripe.webhooks.constructEvent(
request.body,
signature,
endpointSecret
);
} catch (err: any) {
console.log(`⚠️ Webhook signature verification failed.`, err.message);
return response.sendStatus(400);
}
}
let subscription;
let status;
// Handle the event
switch (event.type) {
case 'customer.subscription.trial_will_end':
subscription = event.data.object;
status = subscription.status;
console.log(`Subscription status is ${status}.`);
// Then define and call a method to handle the subscription trial ending.
// handleSubscriptionTrialEnding(subscription);
break;
case 'customer.subscription.deleted':
subscription = event.data.object;
status = subscription.status;
console.log(`Subscription status is ${status}.`);
// Then define and call a method to handle the subscription deleted.
// handleSubscriptionDeleted(subscriptionDeleted);
break;
case 'customer.subscription.created':
subscription = event.data.object;
status = subscription.status;
console.log(`Subscription status is ${status}.`);
// Then define and call a method to handle the subscription created.
// handleSubscriptionCreated(subscription);
break;
case 'customer.subscription.updated':
subscription = event.data.object;
status = subscription.status;
console.log(`Subscription status is ${status}.`);
// Then define and call a method to handle the subscription update.
// handleSubscriptionUpdated(subscription);
break;
default:
// Unexpected event type
console.log(`Unhandled event type ${event.type}.`);
}
// Return a 200 response to acknowledge receipt of the event
response.send();
}
);
export default paymentRouter;

View File

@ -26,6 +26,11 @@
<body>
<div class="container">
<h1 class="my-4">LingDocs Auth Admin</h1>
<form action="/payment/create-checkout-session" method="POST">
<!-- Add a hidden field with the lookup_key of your Price -->
<input type="hidden" name="lookup_key" value="student-yearly" />
<button id="checkout-and-portal-button" type="submit">Checkout</button>
</form>
<p><%= users.length %> Users</p>
<table class="table">
<thead>

1689
account/yarn.lock Normal file

File diff suppressed because it is too large Load Diff