From ccd7b6f61c5a1b5b2c5d25e5bf1e75d5d5e5968a Mon Sep 17 00:00:00 2001 From: Emily Date: Sun, 4 Jan 2026 22:12:16 -0800 Subject: [PATCH 01/14] initial commit --- .../routes/MembershipPayment.js | 88 +++++++++++++++++++ .../util/membershipPaymentQueries.js | 31 +++++++ 2 files changed, 119 insertions(+) create mode 100644 api/main_endpoints/routes/MembershipPayment.js create mode 100644 api/main_endpoints/util/membershipPaymentQueries.js diff --git a/api/main_endpoints/routes/MembershipPayment.js b/api/main_endpoints/routes/MembershipPayment.js new file mode 100644 index 000000000..a8cf7f467 --- /dev/null +++ b/api/main_endpoints/routes/MembershipPayment.js @@ -0,0 +1,88 @@ +const express = require('express'); +const router = express.Router(); + +const { + BAD_REQUEST, + SERVER_ERROR, + NOT_FOUND, + OK, +} = require('../../util/constants').STATUS_CODES; + +const User = require('../models/User'); +const { getMemberExpirationDate } = require('../util/userHelpers'); +const { findPayment, verifyPayment, rejectPayment } = require('../util/membershipPaymentQueries'); +const { decodeToken } = require('../../util/auth'); +const { writeLogToClient } = require('../../util/logging'); + +router.post('/verifyMembership', async (req, res) => { + const decoded = await decodeToken(req, membershipState.PENDING); + if (decoded.status !== OK) { + return res.sendStatus(decoded.status); + } + + const { confirmationCode } = req.body + const userId = decoded.token._id + + if (!confirmationCode) { + writeLogToClient(req.method, { + statusCode: BAD_REQUEST, + message: 'please type in your confirmation code', + }); + return res.sendStatus(BAD_REQUEST); + } + + try { + const paymentDocument = await findPayment(confirmationCode) + + if (!paymentDocument) { + writeLogToClient(req.method, { + statusCode: NOT_FOUND, + message: 'payment not found', + }); + return res.sendStatus(NOT_FOUND); + } + const paymentId = paymentDocument._id + const amount = paymentDocument.amount; + let accessLevel + let membershipValidUntil + + if (amount >= 30) { + accessLevel = membershipState.MEMBER + membershipValidUntil = getMemberExpirationDate(2) + } else if (amount >= 20) { + accessLevel = membershipState.MEMBER + membershipValidUntil = getMemberExpirationDate(1) + } else { + await rejectPayment(paymentId) + writeLogToClient(req.method, { + statusCode: BAD_REQUEST, + message: 'not enough money sent to become a member', + }); + return res.sendStatus(BAD_REQUEST); + } + + await verifyPayment(paymentId, userId) + await User.updateOne( + { _id: userId }, + { + $set: { + accessLevel, + membershipValidUntil + } + } + ) + + writeLogToClient(req.method, { + statusCode: OK, + message: 'successfully verified user', + }); + return res.sendStatus(OK); + + } catch (error){ + writeLogToClient(req.method, { + statusCode: SERVER_ERROR, + message: 'internal server error', + }); + return res.sendStatus(SERVER_ERROR); + } +}) diff --git a/api/main_endpoints/util/membershipPaymentQueries.js b/api/main_endpoints/util/membershipPaymentQueries.js new file mode 100644 index 000000000..8f7c1bed7 --- /dev/null +++ b/api/main_endpoints/util/membershipPaymentQueries.js @@ -0,0 +1,31 @@ +import MembershipPayment from '../main_endpoints/models/MembershipPayment.js'; +const status = { + PENDING: 'pending', + COMPLETED: 'completed', + REJECTED: 'rejected', +}; + +export async function findPayment(confirmationCode) { + return MembershipPayment.findOne({ + confirmationCode, + status: status.PENDING, + }); +} + +export async function verifyPayment(paymentId, userId) { + await MembershipPayment.updateOne( + { _id: paymentId }, + { $set: { + userId, + status: status.COMPLETED + }} + ) +} + +export async function rejectPayment(paymentId) { + await MembershipPayment.updateOne( + { _id: paymentId }, + { $set: { status: status.REJECTED } } + ); +} + From f2cccc7bd800f59cb2d03fa097a4bd2f7f1d5cbc Mon Sep 17 00:00:00 2001 From: Emily Date: Sun, 4 Jan 2026 22:15:34 -0800 Subject: [PATCH 02/14] fixed spacing --- api/main_endpoints/routes/MembershipPayment.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/main_endpoints/routes/MembershipPayment.js b/api/main_endpoints/routes/MembershipPayment.js index a8cf7f467..900aa1ded 100644 --- a/api/main_endpoints/routes/MembershipPayment.js +++ b/api/main_endpoints/routes/MembershipPayment.js @@ -17,7 +17,7 @@ const { writeLogToClient } = require('../../util/logging'); router.post('/verifyMembership', async (req, res) => { const decoded = await decodeToken(req, membershipState.PENDING); if (decoded.status !== OK) { - return res.sendStatus(decoded.status); + return res.sendStatus(decoded.status); } const { confirmationCode } = req.body @@ -42,7 +42,7 @@ router.post('/verifyMembership', async (req, res) => { return res.sendStatus(NOT_FOUND); } const paymentId = paymentDocument._id - const amount = paymentDocument.amount; + const amount = paymentDocument.amount let accessLevel let membershipValidUntil From 026fe55d816d1620b2adc199548a8f368805d33d Mon Sep 17 00:00:00 2001 From: Emily Date: Sun, 4 Jan 2026 22:24:47 -0800 Subject: [PATCH 03/14] fixed spacing 2 --- .../routes/MembershipPayment.js | 126 +++++++++--------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/api/main_endpoints/routes/MembershipPayment.js b/api/main_endpoints/routes/MembershipPayment.js index 900aa1ded..57e06a096 100644 --- a/api/main_endpoints/routes/MembershipPayment.js +++ b/api/main_endpoints/routes/MembershipPayment.js @@ -15,74 +15,74 @@ const { decodeToken } = require('../../util/auth'); const { writeLogToClient } = require('../../util/logging'); router.post('/verifyMembership', async (req, res) => { - const decoded = await decodeToken(req, membershipState.PENDING); - if (decoded.status !== OK) { - return res.sendStatus(decoded.status); - } + const decoded = await decodeToken(req, membershipState.PENDING); + if (decoded.status !== OK) { + return res.sendStatus(decoded.status); + } + + const { confirmationCode } = req.body; + const userId = decoded.token._id; - const { confirmationCode } = req.body - const userId = decoded.token._id + if (!confirmationCode) { + writeLogToClient(req.method, { + statusCode: BAD_REQUEST, + message: 'please type in your confirmation code', + }); + return res.sendStatus(BAD_REQUEST); + } - if (!confirmationCode) { - writeLogToClient(req.method, { - statusCode: BAD_REQUEST, - message: 'please type in your confirmation code', - }); - return res.sendStatus(BAD_REQUEST); + try { + const paymentDocument = await findPayment(confirmationCode); + + if (!paymentDocument) { + writeLogToClient(req.method, { + statusCode: NOT_FOUND, + message: 'payment not found', + }); + return res.sendStatus(NOT_FOUND); } + const paymentId = paymentDocument._id; + const amount = paymentDocument.amount; + let accessLevel; + let membershipValidUntil; - try { - const paymentDocument = await findPayment(confirmationCode) + if (amount >= 30) { + accessLevel = membershipState.MEMBER; + membershipValidUntil = getMemberExpirationDate(2); + } else if (amount >= 20) { + accessLevel = membershipState.MEMBER; + membershipValidUntil = getMemberExpirationDate(1); + } else { + await rejectPayment(paymentId); + writeLogToClient(req.method, { + statusCode: BAD_REQUEST, + message: 'not enough money sent to become a member', + }); + return res.sendStatus(BAD_REQUEST); + } - if (!paymentDocument) { - writeLogToClient(req.method, { - statusCode: NOT_FOUND, - message: 'payment not found', - }); - return res.sendStatus(NOT_FOUND); + await verifyPayment(paymentId, userId); + await User.updateOne( + { _id: userId }, + { + $set: { + accessLevel, + membershipValidUntil } - const paymentId = paymentDocument._id - const amount = paymentDocument.amount - let accessLevel - let membershipValidUntil - - if (amount >= 30) { - accessLevel = membershipState.MEMBER - membershipValidUntil = getMemberExpirationDate(2) - } else if (amount >= 20) { - accessLevel = membershipState.MEMBER - membershipValidUntil = getMemberExpirationDate(1) - } else { - await rejectPayment(paymentId) - writeLogToClient(req.method, { - statusCode: BAD_REQUEST, - message: 'not enough money sent to become a member', - }); - return res.sendStatus(BAD_REQUEST); - } - - await verifyPayment(paymentId, userId) - await User.updateOne( - { _id: userId }, - { - $set: { - accessLevel, - membershipValidUntil - } - } - ) + } + ); - writeLogToClient(req.method, { - statusCode: OK, - message: 'successfully verified user', - }); - return res.sendStatus(OK); + writeLogToClient(req.method, { + statusCode: OK, + message: 'successfully verified user', + }); + return res.sendStatus(OK); - } catch (error){ - writeLogToClient(req.method, { - statusCode: SERVER_ERROR, - message: 'internal server error', - }); - return res.sendStatus(SERVER_ERROR); - } -}) + } catch (error){ + writeLogToClient(req.method, { + statusCode: SERVER_ERROR, + message: 'internal server error', + }); + return res.sendStatus(SERVER_ERROR); + } +}); From 6e3675fdf33e543f1e8b47c80fd4df23cddd4148 Mon Sep 17 00:00:00 2001 From: Emily Date: Sun, 4 Jan 2026 22:25:20 -0800 Subject: [PATCH 04/14] fixed spacing 2 --- .../util/membershipPaymentQueries.js | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/api/main_endpoints/util/membershipPaymentQueries.js b/api/main_endpoints/util/membershipPaymentQueries.js index 8f7c1bed7..4f9def3a9 100644 --- a/api/main_endpoints/util/membershipPaymentQueries.js +++ b/api/main_endpoints/util/membershipPaymentQueries.js @@ -6,26 +6,26 @@ const status = { }; export async function findPayment(confirmationCode) { - return MembershipPayment.findOne({ - confirmationCode, - status: status.PENDING, - }); + return MembershipPayment.findOne({ + confirmationCode, + status: status.PENDING, + }); } export async function verifyPayment(paymentId, userId) { - await MembershipPayment.updateOne( - { _id: paymentId }, - { $set: { - userId, - status: status.COMPLETED - }} - ) + await MembershipPayment.updateOne( + { _id: paymentId }, + { $set: { + userId, + status: status.COMPLETED + }} + ); } export async function rejectPayment(paymentId) { - await MembershipPayment.updateOne( - { _id: paymentId }, - { $set: { status: status.REJECTED } } - ); + await MembershipPayment.updateOne( + { _id: paymentId }, + { $set: { status: status.REJECTED } } + ); } From a38266b72981d2c1122fbf56fae567c638026be9 Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 5 Jan 2026 10:53:37 -0800 Subject: [PATCH 05/14] updated logic and merged find and Verify functions --- .../routes/MembershipPayment.js | 37 +++---------- .../util/membershipPaymentQueries.js | 53 ++++++++++++------- 2 files changed, 41 insertions(+), 49 deletions(-) diff --git a/api/main_endpoints/routes/MembershipPayment.js b/api/main_endpoints/routes/MembershipPayment.js index 57e06a096..1d7b9fe1f 100644 --- a/api/main_endpoints/routes/MembershipPayment.js +++ b/api/main_endpoints/routes/MembershipPayment.js @@ -7,12 +7,11 @@ const { NOT_FOUND, OK, } = require('../../util/constants').STATUS_CODES; - +const membershipState = require('../../util/constants').MEMBERSHIP_STATE; const User = require('../models/User'); const { getMemberExpirationDate } = require('../util/userHelpers'); -const { findPayment, verifyPayment, rejectPayment } = require('../util/membershipPaymentQueries'); +const { findVerifyPayment, rejectPayment } = require('../util/membershipPaymentQueries'); const { decodeToken } = require('../../util/auth'); -const { writeLogToClient } = require('../../util/logging'); router.post('/verifyMembership', async (req, res) => { const decoded = await decodeToken(req, membershipState.PENDING); @@ -24,25 +23,17 @@ router.post('/verifyMembership', async (req, res) => { const userId = decoded.token._id; if (!confirmationCode) { - writeLogToClient(req.method, { - statusCode: BAD_REQUEST, - message: 'please type in your confirmation code', - }); return res.sendStatus(BAD_REQUEST); } try { - const paymentDocument = await findPayment(confirmationCode); - + const paymentDocument = await findVerifyPayment(confirmationCode, userId); + if (!paymentDocument) { - writeLogToClient(req.method, { - statusCode: NOT_FOUND, - message: 'payment not found', - }); return res.sendStatus(NOT_FOUND); } const paymentId = paymentDocument._id; - const amount = paymentDocument.amount; + const { amount } = paymentDocument; let accessLevel; let membershipValidUntil; @@ -54,14 +45,9 @@ router.post('/verifyMembership', async (req, res) => { membershipValidUntil = getMemberExpirationDate(1); } else { await rejectPayment(paymentId); - writeLogToClient(req.method, { - statusCode: BAD_REQUEST, - message: 'not enough money sent to become a member', - }); return res.sendStatus(BAD_REQUEST); } - - await verifyPayment(paymentId, userId); + await User.updateOne( { _id: userId }, { @@ -71,18 +57,9 @@ router.post('/verifyMembership', async (req, res) => { } } ); - - writeLogToClient(req.method, { - statusCode: OK, - message: 'successfully verified user', - }); return res.sendStatus(OK); - + } catch (error){ - writeLogToClient(req.method, { - statusCode: SERVER_ERROR, - message: 'internal server error', - }); return res.sendStatus(SERVER_ERROR); } }); diff --git a/api/main_endpoints/util/membershipPaymentQueries.js b/api/main_endpoints/util/membershipPaymentQueries.js index 4f9def3a9..129ba077c 100644 --- a/api/main_endpoints/util/membershipPaymentQueries.js +++ b/api/main_endpoints/util/membershipPaymentQueries.js @@ -5,27 +5,42 @@ const status = { REJECTED: 'rejected', }; -export async function findPayment(confirmationCode) { - return MembershipPayment.findOne({ - confirmationCode, - status: status.PENDING, +function findVerifyPayment(confirmationCode, userId) { + return new Promise((resolve) => { + try { + MembershipPayment.findOneAndUpdate( + { + confirmationCode, + status: status.PENDING, + amount: { $gte: 20 }, + }, + { + $set: { userId, status: status.COMPLETED }, + }, + { + new: true, + runValidators: true, + } + ).then(payment => resolve(payment)) + .catch(() => resolve(null)); + } catch (err) { + resolve(null); + } }); } -export async function verifyPayment(paymentId, userId) { - await MembershipPayment.updateOne( - { _id: paymentId }, - { $set: { - userId, - status: status.COMPLETED - }} - ); -} - -export async function rejectPayment(paymentId) { - await MembershipPayment.updateOne( - { _id: paymentId }, - { $set: { status: status.REJECTED } } - ); +function rejectPayment(paymentId) { + return new Promise((resolve) => { + try { + MembershipPayment.updateOne( + { _id: paymentId }, + { $set: { status: status.REJECTED } } + ).then(result => resolve(result)) + .catch(() => resolve(null)); + } catch (err) { + resolve(null); + } + }); } +module.exports = { findVerifyPayment, rejectPayment }; From 81da36f02e0363b26ce6c8cefdc38ad441315d9f Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 5 Jan 2026 10:54:43 -0800 Subject: [PATCH 06/14] fix spacing --- api/main_endpoints/routes/MembershipPayment.js | 6 +++--- api/main_endpoints/util/membershipPaymentQueries.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/api/main_endpoints/routes/MembershipPayment.js b/api/main_endpoints/routes/MembershipPayment.js index 1d7b9fe1f..a816ed6bd 100644 --- a/api/main_endpoints/routes/MembershipPayment.js +++ b/api/main_endpoints/routes/MembershipPayment.js @@ -28,7 +28,7 @@ router.post('/verifyMembership', async (req, res) => { try { const paymentDocument = await findVerifyPayment(confirmationCode, userId); - + if (!paymentDocument) { return res.sendStatus(NOT_FOUND); } @@ -47,7 +47,7 @@ router.post('/verifyMembership', async (req, res) => { await rejectPayment(paymentId); return res.sendStatus(BAD_REQUEST); } - + await User.updateOne( { _id: userId }, { @@ -58,7 +58,7 @@ router.post('/verifyMembership', async (req, res) => { } ); return res.sendStatus(OK); - + } catch (error){ return res.sendStatus(SERVER_ERROR); } diff --git a/api/main_endpoints/util/membershipPaymentQueries.js b/api/main_endpoints/util/membershipPaymentQueries.js index 129ba077c..d6723d428 100644 --- a/api/main_endpoints/util/membershipPaymentQueries.js +++ b/api/main_endpoints/util/membershipPaymentQueries.js @@ -22,7 +22,7 @@ function findVerifyPayment(confirmationCode, userId) { runValidators: true, } ).then(payment => resolve(payment)) - .catch(() => resolve(null)); + .catch(() => resolve(null)); } catch (err) { resolve(null); } @@ -36,7 +36,7 @@ function rejectPayment(paymentId) { { _id: paymentId }, { $set: { status: status.REJECTED } } ).then(result => resolve(result)) - .catch(() => resolve(null)); + .catch(() => resolve(null)); } catch (err) { resolve(null); } From 7fe7f3a6375c162a65c6396f382f074ad662191a Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 5 Jan 2026 16:10:12 -0800 Subject: [PATCH 07/14] refactor: improve payment verification and rejection logic --- .../routes/MembershipPayment.js | 32 ++++++---- .../util/membershipPaymentQueries.js | 61 +++++++++++-------- 2 files changed, 55 insertions(+), 38 deletions(-) diff --git a/api/main_endpoints/routes/MembershipPayment.js b/api/main_endpoints/routes/MembershipPayment.js index a816ed6bd..e5d7f4219 100644 --- a/api/main_endpoints/routes/MembershipPayment.js +++ b/api/main_endpoints/routes/MembershipPayment.js @@ -1,5 +1,6 @@ const express = require('express'); const router = express.Router(); +router.use(bodyParser.json()); const { BAD_REQUEST, @@ -11,7 +12,7 @@ const membershipState = require('../../util/constants').MEMBERSHIP_STATE; const User = require('../models/User'); const { getMemberExpirationDate } = require('../util/userHelpers'); const { findVerifyPayment, rejectPayment } = require('../util/membershipPaymentQueries'); -const { decodeToken } = require('../../util/auth'); +const { decodeToken } = require('../util/token-functions.js'); router.post('/verifyMembership', async (req, res) => { const decoded = await decodeToken(req, membershipState.PENDING); @@ -28,24 +29,34 @@ router.post('/verifyMembership', async (req, res) => { try { const paymentDocument = await findVerifyPayment(confirmationCode, userId); - - if (!paymentDocument) { + if (paymentDocument === null){ + throw new Error('Server error'); + } + if (paymentDocument === false){ return res.sendStatus(NOT_FOUND); } + const paymentId = paymentDocument._id; const { amount } = paymentDocument; - let accessLevel; let membershipValidUntil; + const accessLevel = membershipState.MEMBER; + + if (amount < 20){ + const rejected = await rejectPayment(paymentId); + if (rejected === null){ + throw new Error('Server error'); + } + if (rejected === false){ + return res.sendStatus(NOT_FOUND); + } + return res.sendStatus(BAD_REQUEST); + + } if (amount >= 30) { - accessLevel = membershipState.MEMBER; membershipValidUntil = getMemberExpirationDate(2); - } else if (amount >= 20) { - accessLevel = membershipState.MEMBER; - membershipValidUntil = getMemberExpirationDate(1); } else { - await rejectPayment(paymentId); - return res.sendStatus(BAD_REQUEST); + membershipValidUntil = getMemberExpirationDate(1); } await User.updateOne( @@ -58,7 +69,6 @@ router.post('/verifyMembership', async (req, res) => { } ); return res.sendStatus(OK); - } catch (error){ return res.sendStatus(SERVER_ERROR); } diff --git a/api/main_endpoints/util/membershipPaymentQueries.js b/api/main_endpoints/util/membershipPaymentQueries.js index d6723d428..0d09b3d39 100644 --- a/api/main_endpoints/util/membershipPaymentQueries.js +++ b/api/main_endpoints/util/membershipPaymentQueries.js @@ -7,39 +7,46 @@ const status = { function findVerifyPayment(confirmationCode, userId) { return new Promise((resolve) => { - try { - MembershipPayment.findOneAndUpdate( - { - confirmationCode, - status: status.PENDING, - amount: { $gte: 20 }, - }, - { - $set: { userId, status: status.COMPLETED }, - }, - { - new: true, - runValidators: true, + MembershipPayment.findOneAndUpdate( + { + confirmationCode, + status: status.PENDING, + }, + { + $set: { userId, status: status.COMPLETED }, + }, + { + new: true, + runValidators: true, + }, + (error, result) => { + if (error) { + return resolve(null); } - ).then(payment => resolve(payment)) - .catch(() => resolve(null)); - } catch (err) { - resolve(null); - } + if (!result) { + return resolve(false); + } + return resolve(result); + } + ); }); } function rejectPayment(paymentId) { return new Promise((resolve) => { - try { - MembershipPayment.updateOne( - { _id: paymentId }, - { $set: { status: status.REJECTED } } - ).then(result => resolve(result)) - .catch(() => resolve(null)); - } catch (err) { - resolve(null); - } + MembershipPayment.findByIdAndUpdate( + paymentId, + { $set: { status: status.REJECTED } }, + (error, result) => { + if (error) { + return resolve(null); + } + if (!result) { + return resolve(false); + } + return resolve(true); + } + ); }); } From d5f8c1438228ebd47570088fdc3fa96c6211f58f Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 5 Jan 2026 16:12:11 -0800 Subject: [PATCH 08/14] fix --- api/main_endpoints/routes/MembershipPayment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/main_endpoints/routes/MembershipPayment.js b/api/main_endpoints/routes/MembershipPayment.js index e5d7f4219..c8371ab21 100644 --- a/api/main_endpoints/routes/MembershipPayment.js +++ b/api/main_endpoints/routes/MembershipPayment.js @@ -39,7 +39,6 @@ router.post('/verifyMembership', async (req, res) => { const paymentId = paymentDocument._id; const { amount } = paymentDocument; let membershipValidUntil; - const accessLevel = membershipState.MEMBER; if (amount < 20){ const rejected = await rejectPayment(paymentId); @@ -59,6 +58,7 @@ router.post('/verifyMembership', async (req, res) => { membershipValidUntil = getMemberExpirationDate(1); } + const accessLevel = membershipState.MEMBER; await User.updateOne( { _id: userId }, { From 41059456cc1247827c6ea6fe161be4a878ea5242 Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 5 Jan 2026 17:24:57 -0800 Subject: [PATCH 09/14] refactor: improve error handling in membership payment verification and rejection --- .../routes/MembershipPayment.js | 4 +- .../util/membershipPaymentQueries.js | 75 +++++++++++-------- 2 files changed, 44 insertions(+), 35 deletions(-) diff --git a/api/main_endpoints/routes/MembershipPayment.js b/api/main_endpoints/routes/MembershipPayment.js index c8371ab21..085e8705a 100644 --- a/api/main_endpoints/routes/MembershipPayment.js +++ b/api/main_endpoints/routes/MembershipPayment.js @@ -30,7 +30,7 @@ router.post('/verifyMembership', async (req, res) => { try { const paymentDocument = await findVerifyPayment(confirmationCode, userId); if (paymentDocument === null){ - throw new Error('Server error'); + return res.sendStatus(SERVER_ERROR); } if (paymentDocument === false){ return res.sendStatus(NOT_FOUND); @@ -43,7 +43,7 @@ router.post('/verifyMembership', async (req, res) => { if (amount < 20){ const rejected = await rejectPayment(paymentId); if (rejected === null){ - throw new Error('Server error'); + return res.sendStatus(NOT_FOUND); } if (rejected === false){ return res.sendStatus(NOT_FOUND); diff --git a/api/main_endpoints/util/membershipPaymentQueries.js b/api/main_endpoints/util/membershipPaymentQueries.js index 0d09b3d39..27361c2ba 100644 --- a/api/main_endpoints/util/membershipPaymentQueries.js +++ b/api/main_endpoints/util/membershipPaymentQueries.js @@ -1,4 +1,5 @@ import MembershipPayment from '../main_endpoints/models/MembershipPayment.js'; + const status = { PENDING: 'pending', COMPLETED: 'completed', @@ -7,46 +8,54 @@ const status = { function findVerifyPayment(confirmationCode, userId) { return new Promise((resolve) => { - MembershipPayment.findOneAndUpdate( - { - confirmationCode, - status: status.PENDING, - }, - { - $set: { userId, status: status.COMPLETED }, - }, - { - new: true, - runValidators: true, - }, - (error, result) => { - if (error) { - return resolve(null); - } - if (!result) { - return resolve(false); + try { + MembershipPayment.findOneAndUpdate( + { + confirmationCode, + status: status.PENDING, + }, + { + $set: { userId, status: status.COMPLETED }, + }, + { + new: true, + runValidators: true, + }, + (error, result) => { + if (error) { + return resolve(null); + } + if (!result) { + return resolve(false); + } + return resolve(result); } - return resolve(result); - } - ); + ); + } catch (error) { + return resolve(null); + } }); } function rejectPayment(paymentId) { return new Promise((resolve) => { - MembershipPayment.findByIdAndUpdate( - paymentId, - { $set: { status: status.REJECTED } }, - (error, result) => { - if (error) { - return resolve(null); - } - if (!result) { - return resolve(false); + try { + MembershipPayment.findByIdAndUpdate( + paymentId, + { $set: { status: status.REJECTED } }, + (error, result) => { + if (error) { + return resolve(null); + } + if (!result) { + return resolve(false); + } + return resolve(true); } - return resolve(true); - } - ); + ); + } catch (error) { + return resolve(null); + } }); } From eec11649d54edf8d5426e096a7a1c7b651cbe88f Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 5 Jan 2026 17:25:21 -0800 Subject: [PATCH 10/14] fix --- api/main_endpoints/routes/MembershipPayment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/main_endpoints/routes/MembershipPayment.js b/api/main_endpoints/routes/MembershipPayment.js index 085e8705a..1cb6350cc 100644 --- a/api/main_endpoints/routes/MembershipPayment.js +++ b/api/main_endpoints/routes/MembershipPayment.js @@ -30,7 +30,7 @@ router.post('/verifyMembership', async (req, res) => { try { const paymentDocument = await findVerifyPayment(confirmationCode, userId); if (paymentDocument === null){ - return res.sendStatus(SERVER_ERROR); + return res.sendStatus(SERVER_ERROR); } if (paymentDocument === false){ return res.sendStatus(NOT_FOUND); From 06fc5eebfc77c239c53fef0209a78292b96126ed Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 5 Jan 2026 18:37:33 -0800 Subject: [PATCH 11/14] final fixes --- .../routes/MembershipPayment.js | 71 +++++++++---------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/api/main_endpoints/routes/MembershipPayment.js b/api/main_endpoints/routes/MembershipPayment.js index 1cb6350cc..fd3222c0c 100644 --- a/api/main_endpoints/routes/MembershipPayment.js +++ b/api/main_endpoints/routes/MembershipPayment.js @@ -1,5 +1,6 @@ const express = require('express'); const router = express.Router(); +const bodyParser = require('body-parser') router.use(bodyParser.json()); const { @@ -27,49 +28,45 @@ router.post('/verifyMembership', async (req, res) => { return res.sendStatus(BAD_REQUEST); } - try { - const paymentDocument = await findVerifyPayment(confirmationCode, userId); - if (paymentDocument === null){ + const paymentDocument = await findVerifyPayment(confirmationCode, userId); + if (paymentDocument === null){ + return res.sendStatus(SERVER_ERROR); + } + if (paymentDocument === false){ + return res.sendStatus(NOT_FOUND); + } + + const paymentId = paymentDocument._id; + const { amount } = paymentDocument; + let membershipValidUntil; + + if (amount < 20){ + const rejected = await rejectPayment(paymentId); + if (rejected === null){ return res.sendStatus(SERVER_ERROR); } - if (paymentDocument === false){ + if (rejected === false){ return res.sendStatus(NOT_FOUND); } + return res.sendStatus(BAD_REQUEST); - const paymentId = paymentDocument._id; - const { amount } = paymentDocument; - let membershipValidUntil; - - if (amount < 20){ - const rejected = await rejectPayment(paymentId); - if (rejected === null){ - return res.sendStatus(NOT_FOUND); - } - if (rejected === false){ - return res.sendStatus(NOT_FOUND); - } - return res.sendStatus(BAD_REQUEST); - - } + } - if (amount >= 30) { - membershipValidUntil = getMemberExpirationDate(2); - } else { - membershipValidUntil = getMemberExpirationDate(1); - } + if (amount >= 30) { + membershipValidUntil = getMemberExpirationDate(2); + } else { + membershipValidUntil = getMemberExpirationDate(1); + } - const accessLevel = membershipState.MEMBER; - await User.updateOne( - { _id: userId }, - { - $set: { - accessLevel, - membershipValidUntil - } + const accessLevel = membershipState.MEMBER; + await User.updateOne( + { _id: userId }, + { + $set: { + accessLevel, + membershipValidUntil } - ); - return res.sendStatus(OK); - } catch (error){ - return res.sendStatus(SERVER_ERROR); - } + } + ); + return res.sendStatus(OK); }); From 5d7079e9fdc9541f2f1cbf3deeafb51471a6733a Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 5 Jan 2026 18:37:57 -0800 Subject: [PATCH 12/14] final fixes --- api/main_endpoints/routes/MembershipPayment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/main_endpoints/routes/MembershipPayment.js b/api/main_endpoints/routes/MembershipPayment.js index fd3222c0c..afba4b726 100644 --- a/api/main_endpoints/routes/MembershipPayment.js +++ b/api/main_endpoints/routes/MembershipPayment.js @@ -1,6 +1,6 @@ const express = require('express'); const router = express.Router(); -const bodyParser = require('body-parser') +const bodyParser = require('body-parser'); router.use(bodyParser.json()); const { From 9a831fe70a5ebc91289fc4f98c169d4d059060e5 Mon Sep 17 00:00:00 2001 From: Emily Date: Tue, 6 Jan 2026 18:06:32 -0800 Subject: [PATCH 13/14] refactored updateMembershipExpiration --- .../routes/MembershipPayment.js | 34 +++++++++---------- api/main_endpoints/util/userHelpers.js | 25 ++++++++++++++ 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/api/main_endpoints/routes/MembershipPayment.js b/api/main_endpoints/routes/MembershipPayment.js index afba4b726..0544b2835 100644 --- a/api/main_endpoints/routes/MembershipPayment.js +++ b/api/main_endpoints/routes/MembershipPayment.js @@ -2,7 +2,6 @@ const express = require('express'); const router = express.Router(); const bodyParser = require('body-parser'); router.use(bodyParser.json()); - const { BAD_REQUEST, SERVER_ERROR, @@ -11,7 +10,7 @@ const { } = require('../../util/constants').STATUS_CODES; const membershipState = require('../../util/constants').MEMBERSHIP_STATE; const User = require('../models/User'); -const { getMemberExpirationDate } = require('../util/userHelpers'); +const { getMemberExpirationDate, updateMembershipExpiration } = require('../util/userHelpers'); const { findVerifyPayment, rejectPayment } = require('../util/membershipPaymentQueries'); const { decodeToken } = require('../util/token-functions.js'); @@ -38,7 +37,6 @@ router.post('/verifyMembership', async (req, res) => { const paymentId = paymentDocument._id; const { amount } = paymentDocument; - let membershipValidUntil; if (amount < 20){ const rejected = await rejectPayment(paymentId); @@ -49,24 +47,26 @@ router.post('/verifyMembership', async (req, res) => { return res.sendStatus(NOT_FOUND); } return res.sendStatus(BAD_REQUEST); - } + let semestersToAdd = 0 if (amount >= 30) { - membershipValidUntil = getMemberExpirationDate(2); - } else { - membershipValidUntil = getMemberExpirationDate(1); + semestersToAdd = 2 + } + else { + semestersToAdd = 1 } - - const accessLevel = membershipState.MEMBER; - await User.updateOne( - { _id: userId }, - { - $set: { - accessLevel, - membershipValidUntil - } - } + + const membershipUpdateResult = await updateMembershipExpiration( + decoded.token._id, + semestersToAdd ); + + if (membershipUpdateResult === null) { + return res.sendStatus(SERVER_ERROR); + } + if (membershipUpdateResult === false) { + return res.status(NOT_FOUND).send('User not found.'); + } return res.sendStatus(OK); }); diff --git a/api/main_endpoints/util/userHelpers.js b/api/main_endpoints/util/userHelpers.js index 8ac327872..022aa9abc 100644 --- a/api/main_endpoints/util/userHelpers.js +++ b/api/main_endpoints/util/userHelpers.js @@ -203,6 +203,30 @@ function checkIfPageCountResets(lastLogin) { return lastLoginWasOverOneWeekAgo || aSundayHasPassedSinceLastLogin; } +/** + * Update a user's membershipValidUntil date + * @param {String} userId - The user's ID + * @param {Number} numberOfSemestersToSignUpFor - Number of semesters to extend + * @returns {Object} result - Contains success status and message + */ +async function updateMembershipExpiration(userId, numberOfSemestersToSignUpFor) { + try { + const newExpiration = getMemberExpirationDate(numberOfSemestersToSignUpFor); + const user = await User.findByIdAndUpdate( + userId, + { membershipValidUntil: newExpiration }, + { new: true }, + ); + if (!user) { + return false; + } + return true; + } catch (error) { + logger.error('Error updating membership:', error); + return null; + } +} + module.exports = { registerUser, getMemberExpirationDate, @@ -211,4 +235,5 @@ module.exports = { userWithEmailExists, checkIfPageCountResets, findPasswordReset, + updateMembershipExpiration }; From 367630c84e07ec8e0278f49eed440a22d4833bbb Mon Sep 17 00:00:00 2001 From: Emily Date: Tue, 6 Jan 2026 18:07:39 -0800 Subject: [PATCH 14/14] fix spacing --- api/main_endpoints/routes/MembershipPayment.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/api/main_endpoints/routes/MembershipPayment.js b/api/main_endpoints/routes/MembershipPayment.js index 0544b2835..093dd8817 100644 --- a/api/main_endpoints/routes/MembershipPayment.js +++ b/api/main_endpoints/routes/MembershipPayment.js @@ -49,14 +49,13 @@ router.post('/verifyMembership', async (req, res) => { return res.sendStatus(BAD_REQUEST); } - let semestersToAdd = 0 + let semestersToAdd = 0; if (amount >= 30) { - semestersToAdd = 2 - } - else { - semestersToAdd = 1 + semestersToAdd = 2; + } else { + semestersToAdd = 1; } - + const membershipUpdateResult = await updateMembershipExpiration( decoded.token._id, semestersToAdd