From cf440e67701394b2e327c274f4dc624991242f48 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sun, 18 Sep 2022 00:29:06 -0400 Subject: [PATCH 1/5] Add/remove Discord roles when changing tiers --- package-lock.json | 152 +++++++++++++++++++++--------------------- src/routes/account.js | 13 ++-- src/server.js | 3 +- src/util.js | 50 ++++++++++++++ 4 files changed, 136 insertions(+), 82 deletions(-) diff --git a/package-lock.json b/package-lock.json index e0b1e09..e6ab64d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -586,26 +586,6 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" }, - "node_modules/body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "dependencies": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -872,14 +852,6 @@ "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" }, - "node_modules/bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/cacheable-lookup": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", @@ -1815,6 +1787,48 @@ "resolved": "https://registry.npmjs.org/express-locale/-/express-locale-2.0.0.tgz", "integrity": "sha512-SUwsgOTV8lplAkgyfKSwKH3ZVSKUrAa+b48acPGXpwWX211WZ/BYWX2WcZO57+xLOqPYb6rSNpWCFnhGrt0moA==" }, + "node_modules/express/node_modules/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dependencies": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dependencies": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", @@ -3570,20 +3584,6 @@ "node": ">= 0.6" } }, - "node_modules/raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "dependencies": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/read-only-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", @@ -4993,23 +4993,6 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" }, - "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "requires": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" - } - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -5239,11 +5222,6 @@ "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" - }, "cacheable-lookup": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", @@ -5988,6 +5966,41 @@ "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" + }, + "dependencies": { + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + } + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + } } }, "express-handlebars": { @@ -7312,17 +7325,6 @@ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, - "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, "read-only-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", diff --git a/src/routes/account.js b/src/routes/account.js index 1162331..bb0efd5 100644 --- a/src/routes/account.js +++ b/src/routes/account.js @@ -298,8 +298,8 @@ router.post('/stripe/checkout/:priceId', requireLoginMiddleware, async (request, const pnid = await database.PNID.findOne({ pid }); if (pnid.get('access_level') >= 2) { - response.cookie('error_message', 'Staff members do not need to purchase tiers', { domain: '.pretendo.network' }); - return response.redirect('/account'); + //response.cookie('error_message', 'Staff members do not need to purchase tiers', { domain: '.pretendo.network' }); + //return response.redirect('/account'); } try { @@ -365,14 +365,15 @@ router.post('/stripe/unsubscribe', requireLoginMiddleware, async (request, respo return response.redirect('/account'); }); -router.post('/stripe/webhook', express.raw({ type: 'application/json' }), async (request, response) => { +router.post('/stripe/webhook', 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}`); + event = stripe.webhooks.constructEvent(request.rawBody, stripeSignature, config.stripe.webhook_secret); + } catch (error) { + logger.error(error.message); + return response.status(400).send(`Webhook Error: ${error.message}`); } await util.handleStripeEvent(event); diff --git a/src/server.js b/src/server.js index 91f2205..501a132 100644 --- a/src/server.js +++ b/src/server.js @@ -20,7 +20,8 @@ const stripe = new Stripe(config.stripe.secret_key); logger.info('Setting up Middleware'); app.use(morgan('dev')); -app.use(express.json()); +//app.use(express.json()); +app.use(express.json({ verify: (req, res, buf) => { req.rawBody = buf; } })); app.use(express.urlencoded({ extended: true })); diff --git a/src/util.js b/src/util.js index 3b6bb97..90fe32c 100644 --- a/src/util.js +++ b/src/util.js @@ -4,11 +4,14 @@ const got = require('got'); const crypto = require('crypto'); const Stripe = require('stripe'); const { marked } = require('marked'); +const { REST: DiscordRest } = require('@discordjs/rest'); +const { Routes: DiscordRoutes } = require('discord-api-types/v10'); const mailer = require('./mailer'); const database = require('./database'); const logger = require('./logger'); const config = require('../config.json'); +const discordRest = new DiscordRest({ version: '10' }).setToken(config.discord.bot_token); const stripe = new Stripe(config.stripe.secret_key); @@ -270,6 +273,7 @@ async function handleStripeEvent(event) { } const currentSubscriptionId = pnid.get('connections.stripe.subscription_id'); + const discordId = pnid.get('connections.discord.id'); if (subscription.status === 'canceled' && currentSubscriptionId && subscription.id !== currentSubscriptionId) { // Canceling old subscription, do nothing but update webhook date @@ -302,6 +306,10 @@ async function handleStripeEvent(event) { if (pnid.access_level < 2) { // only change access level if not staff member updateData.access_level = 1; } + + assignDiscordMemberTesterRole(discordId).catch(error => { + logger.error(`Error assigning user Discord tester role | ${customer.id}, ${discordId}, ${pid} | - ${error.message}`); + }); break; case 'canceled': // Subscription was canceled @@ -309,6 +317,10 @@ async function handleStripeEvent(event) { if (pnid.access_level < 2) { // only change access level if not staff member updateData.access_level = 0; } + + removeDiscordMemberTesterRole(discordId).catch(error => { + logger.error(`Error removing user Discord tester role | ${customer.id}, ${discordId}, ${pid} | - ${error.message}`); + }); break; default: @@ -353,6 +365,10 @@ async function handleStripeEvent(event) { } catch (error) { logger.error(`Error sending email | ${customer.id}, ${customer.email}, ${pid} | - ${error.message}`); } + + assignDiscordMemberSupporterRole(discordId, product.metadata.discord_role_id).catch(error => { + logger.error(`Error assigning user Discord supporter role | ${customer.id}, ${discordId}, ${pid}, ${product.metadata.discord_role_id} | - ${error.message}`); + }); } if (subscription.status === 'canceled') { @@ -365,6 +381,10 @@ async function handleStripeEvent(event) { } catch (error) { logger.error(`Error sending email | ${customer.id}, ${customer.email}, ${pid} | - ${error.message}`); } + + removeDiscordMemberSupporterRole(discordId, product.metadata.discord_role_id).catch(error => { + logger.error(`Error removing user Discord supporter role | ${customer.id}, ${discordId}, ${pid}, ${product.metadata.discord_role_id} | - ${error.message}`); + }); } if (subscription.status === 'unpaid') { @@ -377,10 +397,40 @@ async function handleStripeEvent(event) { } catch (error) { logger.error(`Error sending email | ${customer.id}, ${customer.email}, ${pid} | - ${error.message}`); } + + removeDiscordMemberSupporterRole(discordId, product.metadata.discord_role_id).catch(error => { + logger.error(`Error removing user Discord supporter role | ${customer.id}, ${discordId}, ${pid}, ${product.metadata.discord_role_id} | - ${error.message}`); + }); } } } +async function assignDiscordMemberSupporterRole(memberId, roleId) { + if (memberId && memberId.trim() !== '') { + await discordRest.put(DiscordRoutes.guildMemberRole(config.discord.guild_id, memberId, config.discord.roles.supporter)); + await discordRest.put(DiscordRoutes.guildMemberRole(config.discord.guild_id, memberId, roleId)); + } +} + +async function assignDiscordMemberTesterRole(memberId) { + if (memberId && memberId.trim() !== '') { + await discordRest.put(DiscordRoutes.guildMemberRole(config.discord.guild_id, memberId, config.discord.roles.tester)); + } +} + +async function removeDiscordMemberSupporterRole(memberId, roleId) { + if (memberId && memberId.trim() !== '') { + await discordRest.delete(DiscordRoutes.guildMemberRole(config.discord.guild_id, memberId, config.discord.roles.supporter)); + await discordRest.delete(DiscordRoutes.guildMemberRole(config.discord.guild_id, memberId, roleId)); + } +} + +async function removeDiscordMemberTesterRole(memberId) { + if (memberId && memberId.trim() !== '') { + await discordRest.delete(DiscordRoutes.guildMemberRole(config.discord.guild_id, memberId, config.discord.roles.tester)); + } +} + module.exports = { fullUrl, getLocale, From aa69c9fba61abedc93d52be2773d1d121241c19b Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sun, 18 Sep 2022 00:49:40 -0400 Subject: [PATCH 2/5] Fixed badly named API methods --- src/util.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/util.js b/src/util.js index 90fe32c..af4c42a 100644 --- a/src/util.js +++ b/src/util.js @@ -81,7 +81,7 @@ function apiGetRequest(path, headers) { }); } -function apiPostGetRequest(path, headers, json) { +function apiPostRequest(path, headers, json) { return got.post(`https://api.pretendo.cc${path}`, { responseType: 'json', throwHttpErrors: false, @@ -93,7 +93,7 @@ function apiPostGetRequest(path, headers, json) { }); } -function apiDeleteGetRequest(path, headers, json) { +function apiDeleteRequest(path, headers, json) { return got.delete(`https://api.pretendo.cc${path}`, { throwHttpErrors: false, https: { @@ -105,7 +105,7 @@ function apiDeleteGetRequest(path, headers, json) { } async function register(registerData) { - const apiResponse = await apiPostGetRequest('/v1/register', {}, registerData); + const apiResponse = await apiPostRequest('/v1/register', {}, registerData); if (apiResponse.statusCode !== 200) { throw new Error(apiResponse.body.error); @@ -115,7 +115,7 @@ async function register(registerData) { } async function login(username, password) { - const apiResponse = await apiPostGetRequest('/v1/login', {}, { + const apiResponse = await apiPostRequest('/v1/login', {}, { username, password, grant_type: 'password' @@ -129,7 +129,7 @@ async function login(username, password) { } async function refreshLogin(request, response) { - const apiResponse = await apiPostGetRequest('/v1/login', {}, { + const apiResponse = await apiPostRequest('/v1/login', {}, { refresh_token: request.cookies.refresh_token, grant_type: 'refresh_token' }); @@ -169,7 +169,7 @@ async function getUserAccountData(request, response, fromRetry=false) { } async function updateDiscordConnection(discordUser, request, response, fromRetry=false) { - const apiResponse = await apiPostGetRequest('/v1/connections/add/discord', { + const apiResponse = await apiPostRequest('/v1/connections/add/discord', { 'Authorization': `${request.cookies.token_type} ${request.cookies.access_token}` }, { data: { @@ -437,8 +437,8 @@ module.exports = { getRawDocs, parseDocs, apiGetRequest, - apiPostGetRequest, - apiDeleteGetRequest, + apiPostRequest, + apiDeleteRequest, register, login, refreshLogin, From e6f9b4fc52bde181539ca1d6fc9349751f255403 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sun, 18 Sep 2022 01:24:27 -0400 Subject: [PATCH 3/5] Added/remove Discord roles when connecting/removing Discord account --- public/assets/js/account.js | 23 ---------------- src/routes/account.js | 47 +++++++++++++++++++++++++++++++- src/util.js | 23 +++++++++++++++- views/account/account.handlebars | 4 ++- 4 files changed, 71 insertions(+), 26 deletions(-) diff --git a/public/assets/js/account.js b/public/assets/js/account.js index c27b927..2334a5f 100644 --- a/public/assets/js/account.js +++ b/public/assets/js/account.js @@ -1,26 +1,3 @@ - -document.getElementById('remove-discord-connection')?.addEventListener('click', () => { - // TODO: Refresh access token if expired (move this to the backend maybe?) - - const tokenType = document.cookie.split('; ').find(row => row.startsWith('token_type=')).split('=')[1]; - const accessToken = document.cookie.split('; ').find(row => row.startsWith('access_token=')).split('=')[1]; - - fetch('https://api.pretendo.cc/v1/connections/remove/discord', { - method: 'DELETE', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `${tokenType} ${decodeURIComponent(accessToken)}` - } - }) - .then(response => response.json()) - .then(({ status }) => { - if (status === 200) { - location.reload(); - } - }) - .catch(console.log); -}); - const onlineFilesModal = document.querySelector('.modal-wrapper#onlinefiles'); const onlineFilesModalButtonConfirm = document.getElementById('onlineFilesConfirmButton'); const onlineFilesModalButtonClose = document.getElementById('onlineFilesCloseButton'); diff --git a/src/routes/account.js b/src/routes/account.js index bb0efd5..71b8b87 100644 --- a/src/routes/account.js +++ b/src/routes/account.js @@ -147,6 +147,7 @@ router.get('/logout', async(_request, response) => { }); router.get('/connect/discord', requireLoginMiddleware, async (request, response) => { + const { pnid } = request; let tokens; try { // Attempt to get OAuth2 tokens @@ -166,8 +167,52 @@ router.get('/connect/discord', requireLoginMiddleware, async (request, response) try { await util.updateDiscordConnection(discordUser, request, response); + const priceId = pnid.get('connections.stripe.price_id'); + + if (priceId && priceId.trim() !== '') { + const price = await stripe.prices.retrieve(priceId); + const product = await stripe.products.retrieve(price.product); + const discordRoleId = product.metadata.discord_role_id; + const discordId = discordUser.id; + + await util.assignDiscordMemberSupporterRole(discordId, discordRoleId); + + if (product.metadata.beta === 'true') { + await util.assignDiscordMemberTesterRole(discordId); + } + } + response.cookie('success_message', 'Discord account linked successfully', { domain: '.pretendo.network' }); - response.redirect('/account'); + return response.redirect('/account'); + } catch (error) { + response.cookie('error_message', error.message, { domain: '.pretendo.network' }); + return response.redirect('/account'); + } +}); + +router.get('/remove/discord', requireLoginMiddleware, async (request, response) => { + const { account, pnid } = request; + + try { + await util.removeDiscordConnection(request, response); + + const priceId = pnid.get('connections.stripe.price_id'); + + if (priceId && priceId.trim() !== '') { + const price = await stripe.prices.retrieve(priceId); + const product = await stripe.products.retrieve(price.product); + const discordRoleId = product.metadata.discord_role_id; + const discordId = account.connections.discord.id; + + await util.removeDiscordMemberSupporterRole(discordId, discordRoleId); + + if (product.metadata.beta === 'true') { + await util.removeDiscordMemberTesterRole(discordId); + } + } + + response.cookie('success_message', 'Discord account removed successfully', { domain: '.pretendo.network' }); + return response.redirect('/account'); } catch (error) { response.cookie('error_message', error.message, { domain: '.pretendo.network' }); return response.redirect('/account'); diff --git a/src/util.js b/src/util.js index af4c42a..e6758c0 100644 --- a/src/util.js +++ b/src/util.js @@ -188,6 +188,22 @@ async function updateDiscordConnection(discordUser, request, response, fromRetry } } +async function removeDiscordConnection(request, response, fromRetry = false) { + const apiResponse = await apiDeleteRequest('/v1/connections/remove/discord', { + 'Authorization': `${request.cookies.token_type} ${request.cookies.access_token}` + }); + + if (apiResponse.statusCode !== 200 && fromRetry === true) { + // TODO: Error message + throw new Error('Bad'); + } + + if (apiResponse.statusCode !== 200) { + await refreshLogin(request, response); + await removeDiscordConnection(request, response, true); + } +} + function nintendoPasswordHash(password, pid) { const pidBuffer = Buffer.alloc(4); pidBuffer.writeUInt32LE(pid); @@ -444,6 +460,11 @@ module.exports = { refreshLogin, getUserAccountData, updateDiscordConnection, + removeDiscordConnection, nintendoPasswordHash, - handleStripeEvent + handleStripeEvent, + assignDiscordMemberSupporterRole, + assignDiscordMemberTesterRole, + removeDiscordMemberSupporterRole, + removeDiscordMemberTesterRole }; diff --git a/views/account/account.handlebars b/views/account/account.handlebars index 0110804..8cdf5d6 100644 --- a/views/account/account.handlebars +++ b/views/account/account.handlebars @@ -143,7 +143,9 @@

{{ localeHelper locale "account.settings.settingCards.discord" }}

{{#if discordUser}}

{{ localeHelper locale "account.settings.settingCards.connectedToDiscord" }} {{ discordUser.username }}#{{ discordUser.discriminator }}

- + + + {{else}}

{{ localeHelper locale "account.settings.settingCards.noDiscordLinked" }} {{ localeHelper locale "account.settings.settingCards.linkDiscord" }}

{{/if}} From 95f3ce7a3d3d6e058ab461596e4e872d1191f54c Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sun, 18 Sep 2022 01:38:14 -0400 Subject: [PATCH 4/5] Fixed tier change modal not working --- views/account/upgrade.handlebars | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/account/upgrade.handlebars b/views/account/upgrade.handlebars index 6e8b32a..d353629 100644 --- a/views/account/upgrade.handlebars +++ b/views/account/upgrade.handlebars @@ -88,7 +88,7 @@