From 04f7904998746f345b7b9d44200419d73b4d9e95 Mon Sep 17 00:00:00 2001 From: nekopudding <61680928+nekopudding@users.noreply.github.com> Date: Sun, 3 Jul 2022 18:45:09 -0700 Subject: [PATCH] Revise backend auth (#53) * dev: fix account endpoints * fix: fix isAccountant casting * dev: fix goal endpoints * dev: fix transaction/plaid/stripe/report endpoints * fix: fix updateTransaction parameters --- .../main_modules/accounts/account-routes.js | 93 +++++++------------ .../main_modules/accounts/account-store.js | 79 ++++++++-------- server/src/main_modules/accounts/models.js | 5 +- .../main_modules/accounts/profile/profile.js | 7 +- server/src/main_modules/goals/goal-routes.js | 77 +++++---------- server/src/main_modules/goals/goal-store.js | 25 ++--- server/src/main_modules/goals/models.js | 2 +- .../src/main_modules/reports/report-routes.js | 24 +---- .../transactions/transaction-routes.js | 75 ++++----------- .../transactions/transaction-store.js | 42 ++++----- server/src/routes.js | 1 + server/src/utils/get-defined-fields.js | 2 +- server/src/utils/plaid/plaid-routes.js | 53 +++++------ server/src/utils/stripe/stripe-routes.js | 88 ++++++++---------- 14 files changed, 222 insertions(+), 351 deletions(-) diff --git a/server/src/main_modules/accounts/account-routes.js b/server/src/main_modules/accounts/account-routes.js index cf10913..c2b8695 100644 --- a/server/src/main_modules/accounts/account-routes.js +++ b/server/src/main_modules/accounts/account-routes.js @@ -3,103 +3,78 @@ const { getDefinedFields } = require.main.require("./utils/get-defined-fields"); const { fieldsAreNotNull } = require("../../utils/get-defined-fields"); const { generateToken, authenticate } = require("./account-auth"); const { createAccount, findAccountById, updateProfile, createReview, deleteAccount, createSubscription, updateSubscription } = require("./account-store"); +const { Account } = require('./models'); const _ = require.main.require('./utils/tests/model-samples') module.exports = function(app) { app.route('/accounts') - .post((req,res,next) => { + .post(async (req,res,next) => { const df = getDefinedFields(req.query); - const {firstname,lastname,email,age,profession,isAccountant} = df; - if (!fieldsAreNotNull({firstname,lastname,email,age,profession,isAccountant})) { + const {accountId,avatar,firstname,lastname,email,age,profession,isAccountant} = df; + if (!fieldsAreNotNull({accountId,firstname,lastname,email,age,profession,isAccountant})) { return next(new Error('missing params')); } - createAccount({ - profile: { firstname,lastname,email,age,profession}, - isAccountant: isAccountant + await createAccount({ + accountId, + profile: { avatar,firstname,lastname,email,age,profession}, + isAccountant }, (err,newAccount) => { if (err) { return next(err); } - res.json({ - token: generateToken(newAccount.id), //will be changed so frontend generates token - data: newAccount - }); + res.json(newAccount) + }) }); app.route('/accounts/:accountId') .get((req,res,next) => { - const {accountId} = req.params; - const {token} = req.query; - authenticate(token,accountId, (err,foundAccount) => { - if (err) return next(err) - if (!foundAccount) return next(new Error('account not found')); - return res.json(foundAccount); - }); - }) - .put((req,res,next) => { - const {accountId} = req.params; - const {token} = req.query; - - authenticate(token,accountId, (err,foundAccount) => { + Account.findOne({accountId: req.params.accountId},(err,account) => { if (err) return next(err); - if (!foundAccount) return next(new Error('account not found')) - updateProfile(foundAccount.id,req.query, (err,foundAccount) => { - if (err) return next(err); - return res.json(foundAccount) - }) + if (!account) return res.status(404).end('account not found'); + return res.json(account); }) }) - .delete((req,res,next) => { - const {accountId} = req.params; - const {token} = req.query; - authenticate(token,accountId, (err,foundAccount) => { + .put((req,res,next) => { + updateProfile(req.params.accountId,req.query, (err,account) => { if (err) return next(err); - if(!foundAccount) return next(new Error('account not found')); - deleteAccount(foundAccount.id, (err) => { - if (err) return next(err); - return res.end('account deleted'); - }) + if (!account) return res.status(404).end('account not found'); + return res.json(account) }) }) + .delete(async (req,res,next) => { + const deletedAccount = await deleteAccount(req.params.accountId); + if (!deletedAccount) return res.status(404).end('account not found') + return res.end('account deleted'); + }) app.route('/reviews/:accountantId') .post((req,res,next) => { const {accountantId} = req.params; - const df = getDefinedFields({accountantId,...req.query}); - const {token,authorId,date,rating,title,content} = df; - if (!fieldsAreNotNull({authorId,date,rating,title,token})) { return next(new Error('missing params'))} - authenticate(token,authorId, (err,foundAccount) => { + const df = getDefinedFields(req.query); + const {authorId,date,rating,title,content} = df; + if (!fieldsAreNotNull({authorId,date,rating,title})) { return next(new Error('missing params'))} + createReview(accountantId,df, (err,account) => { if (err) return next(err); - if (!foundAccount) return next(new Error('accountant not found')) - createReview(foundAccount.id,{accountId: accountantId,...df}, (err,foundAccount) => { - if (err) return next(err); - return res.json(foundAccount) - }) + if (!account) return res.status(404).end('account not found'); + return res.json(account) }) }) app.route('/subscription/:accountId') .post((req,res,next) => { const {accountId} = req.params; - const {token, subscriptionDate,expiryDate} = req.query; - authenticate(token,accountId, (err,foundAccount) => { + createSubscription(accountId,req.query, (err,account) => { if (err) return next(err); - if (!foundAccount) return next(new Error('account not found')) - createSubscription(foundAccount.id,req.query, (err,foundAccount) => { - if (err) return next(err); - return res.json(foundAccount) - }) + if (!account) return res.status(404).end('account not found'); + return res.json(account) }) }) .put((req,res,next) => { const {accountId} = req.params; const {token, expiryDate} = req.query; - authenticate(token,accountId, (err,foundAccount) => { + updateSubscription(accountId,req.query, (err,account) => { if (err) return next(err); - if (!foundAccount) return next(new Error('account not found')) - updateSubscription(foundAccount.id,req.query, (err,foundAccount) => { - if (err) return next(err); - return res.json(foundAccount) - }) + if (!account) return res.status(404).end('account not found'); + return res.json(account) }) }) } \ No newline at end of file diff --git a/server/src/main_modules/accounts/account-store.js b/server/src/main_modules/accounts/account-store.js index a027e7d..9bfc655 100644 --- a/server/src/main_modules/accounts/account-store.js +++ b/server/src/main_modules/accounts/account-store.js @@ -19,71 +19,70 @@ module.exports = { * - @param {Error} err - potential error thrown by mongoose * - @param {Account} createdAccount - the account that was successfully created */ - createAccount: (data,callback) => { - const account = new Account({...data}); + createAccount: async (data,callback) => { + const foundAccount = await Account.findOne({accountId: data.accountId}); + if (foundAccount) return callback(new Error('account already exists'),foundAccount); + + const isAccountant = (data.isAccountant === 'true'); + const account = new Account({...data, isAccountant}); //cast to boolean as http can only send string - account.save((err,createdAccount) => { - const userTransaction = new UserTransaction({userId:createdAccount.id}); - const userGoal = new UserGoal({userId: createdAccount.id}); - const userReport = new UserReport({userId: createdAccount.id}) - userTransaction.save(); - userGoal.save(); - userReport.save(); - callback(err,createdAccount); + account.save((err,account) => { + if (!isAccountant && !err) { + console.log('creating goals/transaction/reports document') + const userTransaction = new UserTransaction({userId: data.accountId}); + const userGoal = new UserGoal({userId: data.accountId}); + const userReport = new UserReport({userId: data.accountId}) + userTransaction.save(err => err && console.log(err)); + userGoal.save(err => err && console.log(err)); + userReport.save(err => err && console.log(err)); + } + + callback(err,account); }); }, /** - * Wrapper for mongoose findById. - * @param {string} id - * @param {function} callback - run on query result - * - @param {Error} err - error thrown by mongoose - * - @param {Account} foundAccount - account found by query - */ - findAccountById:(id,callback) => { - Account.findById(id, (err,foundAccount) => callback(err,foundAccount)); - }, - /** - * Wrapper for mongoose findByIdAndUpdate + * Wrapper for mongoose findOneAndUpdate * @param {string} id * @param {object} data - must contain fields: firsname,lastname,email,age,profession,hasAccountant * @param {*} callback */ updateProfile:(id,data,callback) => { - const {avatar,firstname,lastname,email,age,profession,hasAccountant} = data; + const {avatar,firstname,lastname,email,age,profession} = data; - const fieldsToUpdate = parseProfileData({avatar,firstname,lastname,email,age,profession,hasAccountant}) - Account.findByIdAndUpdate(id,{$set: fieldsToUpdate}, + const fieldsToUpdate = parseProfileData({avatar,firstname,lastname,email,age,profession}) + Account.findOneAndUpdate({accountId: id},{$set: fieldsToUpdate}, {returnDocument: 'after'}, - (err,foundAccount) => { - if(err) console.log(err); - callback(err,foundAccount) + (err,account) => { + callback(err,account) } ); }, - deleteAccount: (id,callback) => { - Account.deleteOne({id: id}, (err) => { - if (err) console.log(err); - callback(err); - }); + deleteAccount: async (id,callback) => { + const account = await Account.findOne({accountId: id}); + await Account.deleteOne({accountId: id}); + await UserGoal.deleteOne({userId: id}) + await UserTransaction.deleteOne({userId: id}); + await UserReport.deleteOne({userId:id}); + return account; }, - createReview: (accountId,data,callback) => { + createReview: (accountantId,data,callback) => { const {authorId,date,rating,title,content} = data; const newReview = {authorId,date,rating,title,content}; - Account.findByIdAndUpdate(accountId,{$push: {reviews: newReview}}, + Account.findOneAndUpdate({accountId: accountantId},{$push: {reviews: newReview}}, {returnDocument: 'after'}, - (err,foundAccount) => { + (err,account) => { if(err) console.log(err); - callback(err,foundAccount) + callback(err,account) } ); }, - createSubscription: (accountId,data,callback) => { + createSubscription: (id,data,callback) => { const {subscriptionDate,expiryDate} = data; const fieldsToUpdate = parseSubscriptionData({subscriptionDate,expiryDate}) - Account.findByIdAndUpdate(accountId,{$set: fieldsToUpdate}, + Account.findOneAndUpdate({accountId: id},{$set: fieldsToUpdate}, {returnDocument: 'after'}, (err,foundAccount) => { if(err) console.log(err); @@ -91,10 +90,10 @@ module.exports = { } ); }, - updateSubscription: (accountId,data,callback) => { + updateSubscription: (id,data,callback) => { const {expiryDate} = data; const fieldsToUpdate = parseSubscriptionData({expiryDate}) - Account.findByIdAndUpdate(accountId,{$set: fieldsToUpdate}, + Account.findOneAndUpdate({accountId: id},{$set: fieldsToUpdate}, {returnDocument: 'after'}, (err,foundAccount) => { if(err) console.log(err); diff --git a/server/src/main_modules/accounts/models.js b/server/src/main_modules/accounts/models.js index 7546a77..431efea 100644 --- a/server/src/main_modules/accounts/models.js +++ b/server/src/main_modules/accounts/models.js @@ -6,12 +6,11 @@ const accountDB = mongoose.createConnection('mongodb://localhost/accountDB') const {r_string,r_bool,r_num, r_date} = require.main.require('./utils/types/mongo-required') const accountSchema = new mongoose.Schema({ + accountId: r_string, profile: {type: profileSchema, required: true}, isAccountant: r_bool, - isAuthenticated: {...r_bool, default: false}, - authenticateExpiryDate: {...r_date, default: '2022'}, reviews: {type: [reviewSchema], default: []}, - subscription: subscriptionSchema, + subscription: {type: subscriptionSchema, default: {subscriptionDate: '2022', expiryDate: '2022'}}, stripeCustomerId: String, stripeSubscriptionId: String }) diff --git a/server/src/main_modules/accounts/profile/profile.js b/server/src/main_modules/accounts/profile/profile.js index 1b8b006..2d21a2f 100644 --- a/server/src/main_modules/accounts/profile/profile.js +++ b/server/src/main_modules/accounts/profile/profile.js @@ -9,8 +9,6 @@ const profileSchema = new mongoose.Schema({ email: r_string, age: r_num, profession: r_string, - numberOfClients: Number, - hasAccountant: {...r_bool, default: false}, }) /** @@ -19,8 +17,8 @@ const profileSchema = new mongoose.Schema({ * @param {object} fields - some or all of the fields in the profile schema */ function parseProfileData(fields) { - const {avatar,firstname,lastname,email,age,profession,hasAccountant} = fields; - const df = getDefinedFields({avatar,firstname,lastname,email,age,profession,hasAccountant}); + const {avatar,firstname,lastname,email,age,profession} = fields; + const df = getDefinedFields({avatar,firstname,lastname,email,age,profession}); const fieldsToUpdate = { ...(df.avatar && {"profile.avatar": df.avatar}), @@ -29,7 +27,6 @@ function parseProfileData(fields) { ...(df.email && {"profile.email": df.email}), ...(df.age && {"profile.age": df.age}), ...(df.profession && {"profile.profession": df.profession}), - ...(df.hasAccountant && {"profile.hasAccountant": df.hasAccountant}), } return fieldsToUpdate; } diff --git a/server/src/main_modules/goals/goal-routes.js b/server/src/main_modules/goals/goal-routes.js index dd46fda..6672cfa 100644 --- a/server/src/main_modules/goals/goal-routes.js +++ b/server/src/main_modules/goals/goal-routes.js @@ -1,5 +1,6 @@ const { fieldsAreNotNull } = require('../../utils/get-defined-fields'); const { findGoals, deleteGoals, findGoal, updateGoal, deleteGoal,createGoal } = require('./goal-store'); +const { UserGoal } = require('./models'); const { getDefinedFields } = require.main.require("./utils/get-defined-fields"); const { authenticate } = require.main.require("./main_modules/accounts/account-auth"); @@ -7,82 +8,50 @@ const { authenticate } = require.main.require("./main_modules/accounts/account-a module.exports = function(app) { app.route('/goals/:userId') .get((req,res,next) => { - const {userId} = req.params; - const {token} = req.query; - authenticate(token,userId,(err,foundAccount) => { - if (err) return next(err) - if (!foundAccount) return next(new Error('account not found')); - findGoals(userId,(err,foundGoals) => { - if (err) return next(err); - return res.json(foundGoals); - }) + UserGoal.findOne({userId: req.params.userId},(err,userGoal) => { + if (err) return next(err); + if (!userGoal) return res.status(404).end('account not found'); + return res.json(userGoal.goals); }) }) .post((req,res,next) => { - const {userId} = req.params; const df = getDefinedFields(req.query); - const {title,target,current,deadline,token} = df; - if (!fieldsAreNotNull({title,target,current,deadline,token})) {next(new Error('missing params'))} - - authenticate(token,userId,(err,foundAccount) => { - if (err) return next(err) - if (!foundAccount) return next(new Error('account not found')); - createGoal(userId,{title,target,current,deadline},(err,foundGoals) => { - if (err) return next(err); - return res.json(foundGoals); - }) + const {title,target,current,deadline} = df; + if (!fieldsAreNotNull({title,target,current,deadline})) {next(new Error('missing params'))} + createGoal(req.params.userId,{title,target,current,deadline},(err,foundGoals) => { + if (err) return next(err); + return res.json(foundGoals); }) }) .delete((req,res,next) => { - const {userId} = req.params; - const {token} = req.query; - authenticate(token,userId,(err,foundAccount) => { - if (err) return next(err) - if (!foundAccount) return next(new Error('account not found')); - deleteGoals(foundAccount.id, (err) => { - if (err) return next(err); - return res.end('goals deleted'); - }) + deleteGoals(req.params.userId, (err,usergoal) => { + if (err) return next(err); + if (!usergoal) return res.status(404).end('account not found'); + return res.end('goals deleted'); }) }) app.route('/goals/:userId/:goalId') .get((req,res,next) => { const {userId,goalId} = req.params; - const {token} = req.query; - authenticate(token,userId,(err,foundAccount) => { - if (err) return next(err) - if (!foundAccount) return next(new Error('account not found')); - findGoal(userId,goalId,(err,foundGoal) => { - if (err) return next(err); - return res.json(foundGoal); - }) + findGoal(userId,goalId,(err,foundGoal) => { + if (err) return next(err); + return res.json(foundGoal); }) }) .put((req,res,next) => { const {userId,goalId} = req.params; - const {token} = req.query - authenticate(token,userId,(err,foundAccount) => { - if (err) return next(err) - if (!foundAccount) return next(new Error('account not found')); - updateGoal(userId,goalId,req.query,(err,foundGoal) => { - if (err) return next(err); - return res.json(foundGoal); - }) + updateGoal(userId,goalId,req.query,(err,goal) => { + if (err) return next(err); + return res.json(goal); }) }) .delete((req,res,next) => { const {userId,goalId} = req.params; - const {token} = req.query; - - authenticate(token,userId,(err,foundAccount) => { - if (err) return next(err) - if (!foundAccount) return next(new Error('account not found')); - deleteGoal(userId,goalId,(err) => { - if (err) return next(err); - return res.end('goal deleted'); - }) + deleteGoal(userId,goalId,(err) => { + if (err) return next(err); + return res.end('goal deleted'); }) }) } \ No newline at end of file diff --git a/server/src/main_modules/goals/goal-store.js b/server/src/main_modules/goals/goal-store.js index 8b506b9..21c90a3 100644 --- a/server/src/main_modules/goals/goal-store.js +++ b/server/src/main_modules/goals/goal-store.js @@ -37,12 +37,12 @@ module.exports = { const newGoal = {title,target,current,deadline}; UserGoal.findOneAndUpdate({userId: accountId},{ $push: { goals: newGoal } }, {returnDocument: 'after'}, - (err,foundUserGoal) => { + (err,usergoal) => { let goal; - if (!foundUserGoal) { - return callback(new Error('user not found'),null); + if (!usergoal) { + return callback(new Error('account not found'),null); } - goal = foundUserGoal.goals[foundUserGoal.goals.length - 1] + goal = usergoal.goals[usergoal.goals.length - 1] // console.log('goal created'); if (goal) return callback(err,goal); @@ -59,25 +59,26 @@ module.exports = { }]}, {$set: fieldsToUpdate}, {returnDocument: 'after'}, - (err,foundUserGoal) => { - if (!foundUserGoal) return callback(new Error('goal not found'),null); - const goal = getItemFromList(foundUserGoal.goals,goalId); + (err,usergoal) => { + if (!usergoal) return callback(new Error('account/goal not found'),null); + const goal = getItemFromList(usergoal.goals,goalId); if (goal) return callback(err,goal); return callback(new Error('goal update unsuccessful'),null); } ) }, deleteGoals: (accountId,callback) => { - UserGoal.findOneAndUpdate({userId: accountId}, {goals: []},(err) => { - if (err) console.log(err); - callback(err); + UserGoal.findOneAndUpdate({userId: accountId}, {goals: []},{returnDocument:'after'},(err,usergoal) => { + if (err) callback(err,null); + if (!usergoal) callback(new Error('account not found'), null); + callback(err,usergoal); }) }, deleteGoal: (accountId,goalId,callback) => { UserGoal.findOneAndUpdate({userId: accountId},{$pull: {goals: {_id: goalId}}}, {returnDocument: 'after'}, - (err,foundUserGoal) => { - const goal = getItemFromList(foundUserGoal.goals,goalId); + (err,usergoal) => { + const goal = getItemFromList(usergoal.goals,goalId); if (goal) callback(new Error('goal deletion unsuccessful')); return callback(err); } diff --git a/server/src/main_modules/goals/models.js b/server/src/main_modules/goals/models.js index ad5ff70..fba7efa 100644 --- a/server/src/main_modules/goals/models.js +++ b/server/src/main_modules/goals/models.js @@ -5,7 +5,7 @@ const {r_string,r_bool,r_num,r_date} = require.main.require('./utils/types/mongo const goalSchema = new mongoose.Schema({ title: r_string, target: r_num, - current: r_num, + current: {...r_num, default: 0}, deadline: r_date, }) diff --git a/server/src/main_modules/reports/report-routes.js b/server/src/main_modules/reports/report-routes.js index 88dbb3b..15792d4 100644 --- a/server/src/main_modules/reports/report-routes.js +++ b/server/src/main_modules/reports/report-routes.js @@ -4,50 +4,32 @@ const { UserReport } = require("./models"); module.exports = function(app) { app.route('/reports/:userId') .get((req,res,next) => { - authenticate(req.query.token, req.params.userId, (err,foundUser) => { - if (err || !foundUser) { - authenticate(req.query.token, req.query.accountantId, (err,foundUser) => { - if (err || !foundUser) - return next(err); - }) - } - UserReport.findOne({userId: req.params.userId}, (err,userReport) => { - if (err || !userReport) return next(err); - return res.send(userReport); - }) + UserReport.findOne({userId: req.params.userId}, (err,userReport) => { + if (err || !userReport) return next(err); + return res.send(userReport); }) }) .delete((req,res,next) => { - authenticate(req.query.token, userId, (err,foundUser) => { - if (err || !foundUser) return next(err); UserReport.findOneAndUpdate({userId: req.params.userId}, {reports: []}, (err,userReport) => { if (err || !userReport) return next(err); res.send(userReport); }) - }) - }) app.route('/reports/:userId/:reportId') .get((req,res) => { - authenticate(req.query.token, req.query.accountantId, (err,foundUser) => { - if (err || !foundUser) return next(err); UserReport.findOne({userId: req.params.userId}, (err,userReport) => { if (err || !userReport) return next(err); const report = userReport.reports.filter(r => r.id === req.params.reportId)[0] return res.send(report); }) - }) }) .put((req,res) => { - authenticate(req.query.token, req.query.accountantId, (err,foundUser) => { - if (err || !foundUser) return next(err); UserReport.findOne({userId: req.params.userId}, (err,userReport) => { if (err || !userReport) return next(err); const report = userReport.reports.filter(r => r.id === req.params.reportId)[0] return res.send(report); }) - }) }) .delete((req,res) => { res.send(req.params); diff --git a/server/src/main_modules/transactions/transaction-routes.js b/server/src/main_modules/transactions/transaction-routes.js index 7d92baa..6b6f226 100644 --- a/server/src/main_modules/transactions/transaction-routes.js +++ b/server/src/main_modules/transactions/transaction-routes.js @@ -6,82 +6,47 @@ const { authenticate } = require.main.require("./main_modules/accounts/account-a module.exports = function(app) { app.route('/transactions/:userId') .get((req,res,next) => { - const {userId} = req.params; - const {token} = req.query; - authenticate(token,userId,(err,foundAccount) => { - if (err) return next(err) - if (!foundAccount) return next(new Error('account not found')); - findTransactions(userId,(err,foundTransactions) => { - if (err) return next(err); - return res.json(foundTransactions); - }) + findTransactions(req.params.userId,(err,foundTransactions) => { + if (err) return next(err); + return res.json(foundTransactions); }) }) .post((req,res,next) => { - const {userId} = req.params; const df = getDefinedFields(req.query); - const {title,category,date,amount,isIncome,receipt,token} = df; - if (!fieldsAreNotNull({title,category,amount,isIncome,token})) {return next(new Error('missing params'))} - - authenticate(token,userId,(err,foundAccount) => { - if (err) return next(err) - if (!foundAccount) return next(new Error('account not found')); - createTransaction(userId,{title,category,date,amount,isIncome,receipt},(err,foundTransactions) => { - if (err) return next(err); - return res.json(foundTransactions); - }) + const {title,category,date,amount,isIncome,receipt} = df; + if (!fieldsAreNotNull({title,category,amount,isIncome})) {return next(new Error('missing params'))} + createTransaction(req.params.userId,{title,category,date,amount,isIncome,receipt},(err,foundTransactions) => { + if (err) return next(err); + return res.json(foundTransactions); }) }) .delete((req,res,next) => { - const {userId} = req.params; - const {token} = req.query; - authenticate(token,userId,(err,foundAccount) => { - if (err) return next(err) - if (!foundAccount) return next(new Error('account not found')); - deleteTransactions(foundAccount.id, (err) => { - if (err) return next(err); - return res.end('transactions deleted'); - }) + deleteTransactions(req.params.userId, (err) => { + if (err) return next(err); + return res.end('transactions deleted'); }) }) app.route('/transactions/:userId/:transactionId') .get((req,res,next) => { const {userId,transactionId} = req.params; - const {token} = req.query; - authenticate(token,userId,(err,foundAccount) => { - if (err) return next(err) - if (!foundAccount) return next(new Error('account not found')); - findTransaction(userId,transactionId,(err,foundTransaction) => { - if (err) return next(err); - return res.json(foundTransaction); - }) + findTransaction(userId,transactionId,(err,foundTransaction) => { + if (err) return next(err); + return res.json(foundTransaction); }) }) .put((req,res,next) => { const {userId,transactionId} = req.params; - const {token} = req.query - - authenticate(token,userId,(err,foundAccount) => { - if (err) return next(err) - if (!foundAccount) return next(new Error('account not found')); - updateTransaction(userId,transactionId,req.query,(err,foundTransaction) => { - if (err) return next(err); - return res.json(foundTransaction); - }) + updateTransaction(userId,transactionId,req.query,(err,foundTransaction) => { + if (err) return next(err); + return res.json(foundTransaction); }) }) .delete((req,res,next) => { const {userId,transactionId} = req.params; - const {token} = req.query; - - authenticate(token,userId,(err,foundAccount) => { - if (err) return next(err) - if (!foundAccount) return next(new Error('account not found')); - deleteTransaction(userId,transactionId,(err) => { - if (err) return next(err); - return res.end('transaction deleted'); - }) + deleteTransaction(userId,transactionId,(err) => { + if (err) return next(err); + return res.end('transaction deleted'); }) }) } \ No newline at end of file diff --git a/server/src/main_modules/transactions/transaction-store.js b/server/src/main_modules/transactions/transaction-store.js index 6c39ff5..59353f1 100644 --- a/server/src/main_modules/transactions/transaction-store.js +++ b/server/src/main_modules/transactions/transaction-store.js @@ -46,13 +46,14 @@ function createUserTransaction(userId,transactions,callback) { } module.exports = { findTransactions: (accountId,callback) => { - UserTransaction.findOne({userId: accountId},(err,foundUserTransaction) => - callback(err,formatTransactions(foundUserTransaction)) + UserTransaction.findOne({userId: accountId},(err,usertransaction) => + callback(err,formatTransactions(usertransaction)) ) }, findTransaction: (accountId,transactionId,callback) => { - UserTransaction.findOne({userId:accountId},(err,foundUserTransaction) => { - const transaction = getItemFromList(foundUserTransaction.transactions,transactionId); + UserTransaction.findOne({userId:accountId},(err,usertransaction) => { + if (!usertransaction) return callback(new Error('account not found'),null); + const transaction = getItemFromList(usertransaction.transactions,transactionId); if (transaction) return callback(err,formatTransaction(transaction)); return callback(new Error('transaction not found'),null); }) @@ -61,19 +62,16 @@ module.exports = { const {title,category,date,amount,isIncome,receipt,plaidTransactionId} = data; let newTransaction; if (!fieldsAreNotNull({title,category,date,amount,isIncome}) && receipt) { - parsePhysicalReceipt(receipt); - console.log('extracting receipt...') + return next(new Error('missing params')) //will change later to parse receipt } else newTransaction = {title,category,date,amount: Math.abs(amount),isIncome,receipt,plaidTransactionId}; UserTransaction.findOneAndUpdate({userId: accountId},{ $push: { transactions: newTransaction } }, {returnDocument: 'after'}, - (err,foundUserTransaction) => { + (err,usertransaction) => { let transaction; - if (!foundUserTransaction) { - return callback(new Error('user not found'),null); - } - transaction = foundUserTransaction.transactions[foundUserTransaction.transactions.length - 1] + if (!usertransaction) return callback(new Error('account not found'),null); + transaction = usertransaction.transactions[usertransaction.transactions.length - 1] if (transaction) return callback(err,formatTransaction(transaction)); return callback(new Error('transaction creation unsuccessful'),null); @@ -81,33 +79,35 @@ module.exports = { ) }, updateTransaction: (accountId,transactionId,data,callback) => { - const {title,target,current,deadline} = data; - const fieldsToUpdate = parseTransactionData({title,target,current,deadline}); + const {title,category,date,amount,isIncome,receipt} = data; + const fieldsToUpdate = parseTransactionData({title,category,date,amount,isIncome,receipt}); UserTransaction.findOneAndUpdate({$and:[{userId: accountId}, { transactions: { $elemMatch: { _id: transactionId }} }]}, {$set: fieldsToUpdate}, {returnDocument: 'after'}, - (err,foundUserTransaction) => { - if (!foundUserTransaction) return callback(new Error('transaction not found'),null); - const transaction = getItemFromList(foundUserTransaction.transactions,transactionId); + (err,usertransaction) => { + if (!usertransaction) return callback(new Error('account/transaction not found'),null); + const transaction = getItemFromList(usertransaction.transactions,transactionId); if (transaction) return callback(err,formatTransaction(transaction)); return callback(new Error('transaction update unsuccessful'),null); } ) }, deleteTransactions: (accountId,callback) => { - UserTransaction.deleteOne({userId: accountId}, (err) => { - if (err) console.log(err); - callback(err); + UserTransaction.findOneAndUpdate({userId: accountId}, {transactions: []},(err,usertransaction) => { + if (err) return callback(err); + if (!usertransaction) return callback(new Error('account not found')) + return callback(err); }) }, deleteTransaction: (accountId,transactionId,callback) => { UserTransaction.findOneAndUpdate({userId: accountId},{$pull: {transactions: {_id: transactionId}}}, {returnDocument: 'after'}, - (err,foundUserTransaction) => { - const transaction = getItemFromList(foundUserTransaction.transactions,transactionId); + (err,usertransaction) => { + if (!usertransaction) return callback(new Error('account not found'),null); + const transaction = getItemFromList(usertransaction.transactions,transactionId); if (transaction) callback(new Error('transaction deletion unsuccessful')); return callback(err); } diff --git a/server/src/routes.js b/server/src/routes.js index 67d5038..6af595f 100644 --- a/server/src/routes.js +++ b/server/src/routes.js @@ -33,6 +33,7 @@ module.exports = function(app) { return next(err) } if (err) { + console.log(err); return res.status(400).end(err.message); } res.status(400).end('missing parameters'); diff --git a/server/src/utils/get-defined-fields.js b/server/src/utils/get-defined-fields.js index 87370f8..9714425 100644 --- a/server/src/utils/get-defined-fields.js +++ b/server/src/utils/get-defined-fields.js @@ -29,7 +29,7 @@ function isValid(field) { function fieldsAreNotNull(fields) { let notNull = true; for (let field in fields) { - if (!field) { + if (!field || field === undefined || field === '') { console.log(`missing ${field}`); notNull = false; } diff --git a/server/src/utils/plaid/plaid-routes.js b/server/src/utils/plaid/plaid-routes.js index 2a1351c..9b342c1 100644 --- a/server/src/utils/plaid/plaid-routes.js +++ b/server/src/utils/plaid/plaid-routes.js @@ -10,37 +10,32 @@ fx.rates = {//other rates need to be defined if we want to support other currenc "CAD": 1.29, } function saveTransactions(recently_added,userId, token, next) { - authenticate(token,userId,(err,foundAccount) => { - if (err) return next(err) - if (!foundAccount) return next(new Error('account not found')); - console.log('saving auto imported transactions') - for (let t of recently_added) { - // console.log(t) - let {amount,category,date,name,iso_currency_code,transaction_id} = t; - let isIncome,convertedAmount; - if (amount < 0) isIncome = true; - // console.log(iso_currency_code); - convertedAmount = Math.abs(Math.round(fx(amount).from(iso_currency_code).to("CAD")*100)/100); //round to .2d - if (!fieldsAreNotNull({name,category: category[0],convertedAmount,isIncome})) { - return next(new Error('missing params')) + for (let t of recently_added) { + // console.log(t) + let {amount,category,date,name,iso_currency_code,transaction_id} = t; + let isIncome,convertedAmount; + if (amount < 0) isIncome = true; + // console.log(iso_currency_code); + convertedAmount = Math.abs(Math.round(fx(amount).from(iso_currency_code).to("CAD")*100)/100); //round to .2d + if (!fieldsAreNotNull({name,category: category[0],convertedAmount,isIncome})) { + return next(new Error('missing params')) + } + findTransaction(userId,transaction_id,(err,foundTransaction)=> { + if (!foundTransaction) { + createTransaction(userId,{ + title: name, + category: category[0], + date, + amount: convertedAmount, + isIncome, + plaidTransactionId: transaction_id + },(err,foundTransactions) => { + if (err) return next(err); + }) } - findTransaction(userId,transaction_id,(err,foundTransaction)=> { - if (!foundTransaction) { - createTransaction(userId,{ - title: name, - category: category[0], - date, - amount: convertedAmount, - isIncome, - plaidTransactionId: transaction_id - },(err,foundTransactions) => { - if (err) return next(err); - }) - } - }) + }) - } - }) + } } function findTransaction(userId,plaidTransactionId, callback) { UserTransaction.findOne({$and:[{userId: userId}, { diff --git a/server/src/utils/stripe/stripe-routes.js b/server/src/utils/stripe/stripe-routes.js index 129a1cf..9e5d84e 100644 --- a/server/src/utils/stripe/stripe-routes.js +++ b/server/src/utils/stripe/stripe-routes.js @@ -28,8 +28,8 @@ async function createSession(userId, customerId) { return session; } -function findUserById(userId, callback) { - Account.findById(userId, (err,foundUser) => { +function findUser(userId, callback) { + Account.findOne({accountId:userId}, (err,foundUser) => { if (err || !foundUser) return callback(new Error('user not found')) @@ -77,58 +77,49 @@ module.exports = function(app) { }) app.post('/stripe/checkout/:userId', async (req,res,next) => { const {userId} = req.params; - const {token} = req.query; let customerId; - authenticate(token,userId, async (err,foundAccount) => { - if (err) return next(err); - if (!foundAccount) return next(new Error('account not found')); - findUserById(userId, async (err,foundUser) => { - if (!foundUser.stripeCustomerId) { - console.log('initializing new customer...') - customerId = await createCustomerForUser(foundUser).id; - Account.findByIdAndUpdate(foundUser.id, { stripeCustomerId: newCustomer.id }, async (err,updatedUser) => { - if (err) { return next(err)} - }); - } else if (subscriptionIsActive(foundUser)) { - return res.send('subscription already active'); - } else { - customerId = foundUser.stripeCustomerId; - } - const ephemeralKey = await stripe.ephemeralKeys.create( - {customer: customerId}, - {apiVersion: '2020-08-27'} - ); - const paymentIntent = await stripe.paymentIntents.create({ - amount: 5000, - currency: 'cad', - customer: customerId, - automatic_payment_methods: { - enabled: true, - }, + findUser(userId, async (err,foundUser) => { + if (!foundUser.stripeCustomerId) { + console.log('initializing new customer...') + customerId = await createCustomerForUser(foundUser).id; + Account.findByIdAndUpdate(foundUser.id, { stripeCustomerId: newCustomer.id }, async (err,updatedUser) => { + if (err) { return next(err)} }); - res.json({ - paymentIntent: paymentIntent.client_secret, - ephemeralKey: ephemeralKey.secret, - customer: customerId, - publishableKey: process.env.STRIPE_PUBLIC_KEY - }); - }) + } else if (subscriptionIsActive(foundUser)) { + return res.send('subscription already active'); + } else { + customerId = foundUser.stripeCustomerId; + } + const ephemeralKey = await stripe.ephemeralKeys.create( + {customer: customerId}, + {apiVersion: '2020-08-27'} + ); + const paymentIntent = await stripe.paymentIntents.create({ + amount: 5000, + currency: 'cad', + customer: customerId, + automatic_payment_methods: { + enabled: true, + }, + }); + res.json({ + paymentIntent: paymentIntent.client_secret, + ephemeralKey: ephemeralKey.secret, + customer: customerId, + publishableKey: process.env.STRIPE_PUBLIC_KEY + }); }) }) app.post('/stripe/checkout/sessions/:userId', async (req,res,next) => { console.log('creating session...') const {userId} = req.params; - const {token} = req.query; - authenticate(token,userId, async (err,foundAccount) => { - if (err) return next(err); - if (!foundAccount) return next(new Error('account not found')); - findUserById(userId, async (err,foundUser) => { + findUser(userId, async (err,foundUser) => { let session; if (!foundUser.stripeCustomerId) { console.log('initializing new customer...') const newCustomer = await createCustomerForUser(foundUser); const newSubscription = await createSubscriptionForCustomer(newCustomer); - Account.findByIdAndUpdate(foundUser.id, { stripeCustomerId: newCustomer.id,stripeSubscriptionId: newSubscription.id }, async (err,updatedUser) => { + Account.findOneAndUpdate(userId, { stripeCustomerId: newCustomer.id,stripeSubscriptionId: newSubscription.id }, async (err,updatedUser) => { if (err) { return next(err)} session = await createSession(userId,updatedUser.stripeCustomerId); @@ -140,17 +131,14 @@ module.exports = function(app) { } res.send(session.url); }) - }) }) app.post('/stripe/portal/sessions/:userId', async (req,res,next) => { const returnUrl = 'http://localhost:8000/stripe/order/cancel'; - authenticate(req.query.token,req.params.userId, async (err,foundAccount) => { - const portalSession = await stripe.billingPortal.sessions.create({ - customer: foundAccount.stripeCustomerId, - return_url: returnUrl, - }); - res.json(portalSession); - }) + const portalSession = await stripe.billingPortal.sessions.create({ + customer: foundAccount.stripeCustomerId, + return_url: returnUrl, + }); + res.json(portalSession); }) //listens for auto-billing to update subscription status in Account