Stripe start create subscription

This commit is contained in:
Jonathan Barrow
2022-06-19 20:30:51 -04:00
parent 17d404870f
commit afe23b57ab
8 changed files with 689 additions and 6 deletions

25
src/database.js Normal file
View File

@@ -0,0 +1,25 @@
const mongoose = require('mongoose');
const PNIDSchema = require('./schema/pnid');
const config = require('../config.json');
const accountServerConfig = config.database.account;
const accountServerURI = `mongodb://${accountServerConfig.address}:${accountServerConfig.port}/${accountServerConfig.database_name}`;
let accountServerDBConnection;
let PNID;
async function connect() {
accountServerDBConnection = await mongoose.createConnection(accountServerURI, accountServerConfig.options);
accountServerDBConnection.on('error', console.error.bind(console, 'Mongoose connection error:'));
accountServerDBConnection.on('close', () => {
accountServerDBConnection.removeAllListeners();
});
PNID = accountServerDBConnection.model('PNID', PNIDSchema);
module.exports.PNID = PNID;
}
module.exports = {
connect,
PNID
};

View File

@@ -1,10 +1,15 @@
const { Router } = require('express');
const express = require('express');
const crypto = require('crypto');
const DiscordOauth2 = require('discord-oauth2');
const { v4: uuidv4 } = require('uuid');
const AdmZip = require('adm-zip');
const Stripe = require('stripe');
const database = require('../database');
const util = require('../util');
const config = require('../../config.json');
const { Router } = express;
const stripe = new Stripe(config.stripe.secret_key);
const router = new Router();
const aesKey = Buffer.from(config.aes_key, 'hex');
@@ -494,4 +499,150 @@ router.get('/miieditor', async (request, response) => {
});
});
router.get('/upgrade', async (request, response) => {
// Verify the user is logged in
if (!request.cookies.access_token || !request.cookies.refresh_token || !request.cookies.ph) {
return response.redirect('/account/login');
}
const renderData = {
layout: 'main',
locale: util.getLocale(request.locale.region, request.locale.language),
localeString: request.locale.toString(),
error: request.cookies.error
};
const { data: prices } = await stripe.prices.list();
const { data: products } = await stripe.products.list();
renderData.tiers = products.filter(product => product.active).map(product => {
const price = prices.find(price => price.product === product.id);
return {
price_id: price.id,
thumbnail: product.images[0],
name: product.name,
description: product.description,
price: (price.unit_amount / 100).toLocaleString('en-US', { style: 'currency', currency: 'USD' }),
};
});
response.render('account/upgrade', renderData);
});
router.post('/checkout/:priceId', async (request, response) => {
// Verify the user is logged in
if (!request.cookies.access_token || !request.cookies.refresh_token || !request.cookies.ph) {
return response.redirect('/account/login');
}
// Attempt to get user data
let apiResponse = await util.apiGetRequest('/v1/user', {
'Authorization': `${request.cookies.token_type} ${request.cookies.access_token}`
});
if (apiResponse.statusCode !== 200) {
// Assume expired, refresh and retry request
apiResponse = await util.apiPostGetRequest('/v1/login', {}, {
refresh_token: request.cookies.refresh_token,
grant_type: 'refresh_token'
});
if (apiResponse.statusCode !== 200) {
return response.redirect('/account/login');
}
const tokens = apiResponse.body;
response.cookie('refresh_token', tokens.refresh_token, { domain: '.pretendo.network' });
response.cookie('access_token', tokens.access_token, { domain: '.pretendo.network' });
response.cookie('token_type', tokens.token_type, { domain: '.pretendo.network' });
apiResponse = await util.apiGetRequest('/v1/user', {
'Authorization': `${tokens.token_type} ${tokens.access_token}`
});
}
// If still failed, something went horribly wrong
if (apiResponse.statusCode !== 200) {
return response.redirect('/account/login');
}
// Set user account info to render data
const account = apiResponse.body;
const pid = account.pid;
let customer;
const { data: searchResults } = await await stripe.customers.search({
query: `metadata['pnid_pid']:'${pid}'`
});
if (searchResults.length !== 0) {
customer = searchResults[0];
} else {
customer = await stripe.customers.create({
metadata: {
pnid_pid: pid
}
});
}
const priceId = request.params.priceId;
const session = await stripe.checkout.sessions.create({
line_items: [
{
price: priceId,
quantity: 1,
},
],
customer: customer.id,
mode: 'subscription',
success_url: `${config.http.base_url}/account?upgrade_success=true`,
cancel_url: `${config.http.base_url}/account?upgrade_success=false`
});
response.redirect(303, session.url);
});
router.post('/stripe-wh', express.raw({ type: 'application/json' }), async (request, response) => {
const stripeSignature = request.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(request.body, stripeSignature, config.stripe.webhook_secret);
} catch (err) {
return response.status(400).send(`Webhook Error: ${err.message}`);
}
if (event.type === 'customer.subscription.updated' || event.type === 'customer.subscription.deleted') {
const subscription = event.data.object;
const product = await stripe.products.retrieve(subscription.plan.product);
const customer = await stripe.customers.retrieve(subscription.customer);
const pid = Number(customer.metadata.pnid_pid);
const pnid = await database.PNID.findOne({ pid });
if (product.metadata.beta === 'true') {
switch (subscription.status) {
case 'active':
pnid.access_level = 1;
break;
case 'canceled': // Subscription was cancled
case 'unpaid': // User missed too many payments
pnid.access_level = 0;
break;
default:
break;
}
await pnid.save();
}
}
response.json({ received: true });
});
module.exports = router;

13
src/schema/pnid.js Normal file
View File

@@ -0,0 +1,13 @@
const { Schema } = require('mongoose');
// Only define what we will be using
const PNIDSchema = new Schema({
pid: {
type: Number,
unique: true
},
server_access_level: String,
access_level: Number,
});
module.exports = PNIDSchema;

View File

@@ -6,6 +6,7 @@ const morgan = require('morgan');
const expressLocale = require('express-locale');
const cookieParser = require('cookie-parser');
const logger = require('./logger');
const database = require('./database');
const util = require('./util');
const config = require('../config.json');
@@ -156,6 +157,8 @@ app.engine('handlebars', handlebars({
app.set('view engine', 'handlebars');
logger.info('Starting server');
app.listen(port, () => {
logger.success(`Server listening on http://localhost:${port}`);
database.connect().then(() => {
app.listen(port, () => {
logger.success(`Server listening on http://localhost:${port}`);
});
});