import { requireMonitor, requireUser, requireRole } from '#api/middlewares/index.js'; import { DbSpendHistory, UserType } from '#db/schemas/index.js'; import { RouteDescription, RouteMethod, RouteMethodList } from '#api/RouteDescription.js'; import { getUserById } from '#db/dbAccess/index.js'; import { SafeNSoundError } from '#util/error.js'; import Joi from 'joi'; const budgetModifySchema = new Joi.object({ venue: Joi.string().required().max(100), reason: Joi.string().required().max(500), amount: Joi.number().required().min(0), createdAt: Joi.forbidden() }); /** * @type {RouteDescription} */ export const getBudgetByUserRoute = { path: '/user/:id/budget', methods: { get: new RouteMethod({ exampleHeaders: { Authorization: 'Bearer {{accessToken}}' }, middlewares: [requireMonitor], description: 'Get the budget for a monitored user', async method(req, res) { if (req.user.type !== UserType.ADMIN) { if (!req.user.monitoredUsers.includes(req.params.id)) throw new SafeNSoundError({ errCode: 'UNAUTHORIZED', message: "You do not have permission to access this user's budget." }); } const user = await getUserById(req.params.id); res.send({ balance: user.balance }); } }), patch: new RouteMethod({ exampleHeaders: { Authorization: 'Bearer {{accessToken}}' }, exampleBody: { venue: 'Monitor 123', reason: 'Just short for a coke to deal with diabetes', amount: 0.15 }, middlewares: [requireMonitor], description: 'Add budget for a monitored user', async method(req, res) { if ( req.user.type !== UserType.ADMIN && !req.user.monitoredUsers.includes(req.params.id) ) throw new SafeNSoundError({ errCode: 'UNAUTHORIZED', message: "You do not have permission to update this user's budget." }); let data = await budgetModifySchema.validateAsync(req.body); const user = await getUserById(req.params.id); user.balance += data.amount; let histEntry = await DbSpendHistory.create({ venue: data.venue, reason: data.reason, amount: data.amount }); user.spendHistory.push(histEntry._id); await user.save(); res.send({ balance: user.balance }); } }) } }; /** * @type {RouteDescription} */ export const userBudgetRoute = { path: '/budget/@me', methods: { get: new RouteMethod({ exampleHeaders: { Authorization: 'Bearer {{accessToken}}' }, middlewares: [requireUser], async method(req, res) { res.send({ currentBalance: req.user.balance }); } }), patch: new RouteMethod({ exampleHeaders: { Authorization: 'Bearer {{accessToken}}' }, exampleBody: { venue: 'The Store', reason: 'Bought a coke', amount: 0.85 }, middlewares: [requireUser], description: 'Spend part of budget', async method(req, res) { let data = await budgetModifySchema.validateAsync(req.body); if (data.amount > req.user.balance) { throw new SafeNSoundError({ errCode: 'INSUFFICIENT_FUNDS', message: 'You do not have enough funds to complete this transaction.' }); } req.user.balance -= data.amount; let histEntry = await DbSpendHistory.create({ venue: data.venue, reason: data.reason, amount: data.amount }); req.user.spendHistory.push(histEntry._id); await req.user.save(); res.send({ balance: req.user.balance }); } }) } };