diff --git a/.gitignore b/.gitignore index b7b7fd3..d7b14bc 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,5 @@ npm-debug.log* yarn-debug.log* yarn-error.log* -.env \ No newline at end of file +.env +.crt \ No newline at end of file diff --git a/backend/Documentation.txt b/backend/Documentation.txt new file mode 100644 index 0000000..ff598e2 --- /dev/null +++ b/backend/Documentation.txt @@ -0,0 +1,84 @@ + + + +please note that as it stands the application runs on local host port 4000 so for any endpoints must start with the following + +REQUIRES VERIFICATION : if the user is not logged in and has a verified token they can not use this endpoint +the frontend should first login/signup and get the token and only then make requests + +http://localhost:4000 + +Endpoints for application + + +USER Endpoints : for this the convention is /user/{the desired endpoint} + + +http://localhost:4000/user + + +Post Requests : + +Login : + +- logs the user in and returns verification token in the response , this token is used for validation + +endpoint - http://localhost:4000/user/login + +Request body - [email , password ] + + +Signup : + +- signs user in creating an account if account already exists it sends back unsuccesfull along with the message +and returns verification token in the response , this token is used for validation + +endpoint - http://localhost:4000/user/signup + +Request body - [email , password ] + + +Get Requests : + + +REQUIRES VERIFICATION + +Balance : + + endpoint - http://localhost:4000/user/balance + +-Balance gets the users balance but please note this is an endpoint that REQUIRES VERIFICATION so if the user is not logged in and has a verified token they can not use this endpoint +the frontend should first login/signup and get the token and only then make requests + + + +http://localhost:4000/transactions + + +REQUIRES VERIFICATION + +Post requests : + + endpoint - http://localhost:4000/transactions/makeTransaction + + Request body - [ amount,title,description ] + + -the endpoint makes a transaction and adds it to the table of transactions it assigns it to our user , it automatically updates the specified users balance to account for the new transaction + + + + + +REQUIRES VERIFICATION + +Get requests : + +endpoint - http://localhost:4000/transactions/getTransactionByPage + +Params : pagenumber = x + +- for this you just need to in the request params assign a value pagenumber , this will return the users transactions. It bassicly just works in the way you would expect + if you do the pagenumber =1 you get the first ten transactions // frontend peeps please let me know if you want to change the number of requests + + + diff --git a/backend/src/certs/ca.crt b/backend/src/certs/ca.crt new file mode 100644 index 0000000..823a492 --- /dev/null +++ b/backend/src/certs/ca.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEQTCCAqmgAwIBAgIUKo2BX+ykzxZslXAlxKniKTUO1Z0wDQYJKoZIhvcNAQEM +BQAwOjE4MDYGA1UEAwwvZjdlNjkyMmYtYjc1Mi00ZWQzLWJhMjUtZTI1YjAwNjU0 +YTE3IFByb2plY3QgQ0EwHhcNMjQwODA0MjMzMjU0WhcNMzQwODAyMjMzMjU0WjA6 +MTgwNgYDVQQDDC9mN2U2OTIyZi1iNzUyLTRlZDMtYmEyNS1lMjViMDA2NTRhMTcg +UHJvamVjdCBDQTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAKSXRMAi +unkpsnRzCFavjmxpRNj+amFYjvem6rQIWe+YLtqw24Mk326iWv6fVCgESV0APWnM +vHp4HawWCqnpt3KVf6xTmAfNAbazODJZZTg3HHKidQSU4z/7cUUJdrneskjthYAD +4IxqE555PIWDMoFwq1/W14DihLRmuzdDOCaxH4EKfhSOjzxwyM/tQjVvauhpuAFy +TgnmBp8scue96F6hKTBccgBzA4xBT8lcj5KvCjLY6Fn2lQCU+Z0KPtqC97OWnu0l +/uiAzK6Ciu0hHRNQ+vo+Epj+Xeg+mcerg4TuZlJWCFatEfPmwBcpzXkkmkrUI/Qu +pjvlkYLX/R2MWTH/oG4zLbmpPQHVF8CXDxvfCpwcJCbO96VAy4sHKfwaX96Rbtge +urrFtvYQSI8REEnkIT/3zt9PxusL/caqNX0roW79qhCJ4D0BMaSMk1gkNl1fomJA +l1h7HsL+UGiYxOCyppmuVuiu3gtle76RGz/ZaKbCOiK0/GkxEa/8eTVBLwIDAQAB +oz8wPTAdBgNVHQ4EFgQUCboAowy7OHOkydNbBfuQ/iH23cUwDwYDVR0TBAgwBgEB +/wIBADALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEMBQADggGBAHmiS7RSqL8JaH9L +vbASqpSsFHTXCNkcy5qXbC12+srSX2NKvXDoA0Bp85kWnupuk4rmR6J7CQNl2Utk +hCaCxl5IpJ6IjqEdxoemnRrGRtGwHA68LUj3PofbWklxSgzkxXTkY1gKnTnUomj+ +PLyM2B4afe3yngB9gDxvePfFdu2K9ij1qA9UJL3ffuDSsStE4o0f/qHDf7i3L+9g +JDPx+fkxnv0Eco5vsPh9MigsMQvlfYLgeg69lcsI5jyqf6SKElaQaIF05PrqFk5L +cbWKnZYeNPH32DwowVHeTjzbKLybq4nMzhyhBbXkIkHgN2ib5cmUm6lEjyUUbKgG +ZoVF2/mYNB/Z/VobXDbWXZNHKAnoPISz2nVnGhMXw2CArBNd8fYmj+khe4IeVrcz +2Haa/SEbiknxymB3w2yIsMZMcv4PpPZ7OsZq98/IYmg6a7eEg+kyMVSi+a9O0syy +nxM1F7OXJD5zfups8JOOPLrlApyKmVdv/9iUq6DRn5V526+Jtg== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/backend/src/config/corsConfig.js b/backend/src/config/corsConfig.js new file mode 100644 index 0000000..6cc4f2d --- /dev/null +++ b/backend/src/config/corsConfig.js @@ -0,0 +1,18 @@ +const cors = require('cors'); + +const allowedOrigins = ['http://localhost:4000']; // Add your allowed origins here + +const corsOptions = { + origin: function (origin, callback) { + if (!origin || allowedOrigins.indexOf(origin) !== -1) { + callback(null, true); + } else { + callback(new Error('Not allowed by CORS')); + } + }, + methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], + allowedHeaders: ['Content-Type', 'Authorization'], + credentials: true, +}; + +module.exports = cors(corsOptions); \ No newline at end of file diff --git a/backend/src/config/db.js b/backend/src/config/db.js index d586839..1b1394b 100644 --- a/backend/src/config/db.js +++ b/backend/src/config/db.js @@ -3,6 +3,7 @@ const path = require('path'); const fs = require('fs'); require('dotenv').config(); // Load environment variables from .env file + const caCertPath = path.resolve(__dirname, process.env.CA_CERT_PATH); const pool = new Pool({ user: process.env.PG_USER, diff --git a/backend/src/controllers/transactionsController.js b/backend/src/controllers/transactionsController.js new file mode 100644 index 0000000..72afab2 --- /dev/null +++ b/backend/src/controllers/transactionsController.js @@ -0,0 +1,27 @@ + +const {getUserTransactionsByPage , makeTransaction} = require('../services/transactionService') +const jwt = require('jsonwebtoken'); + +exports.transaction = async (req, res) => { + const {amount,title,description} = req.body; + const userID = req.user.id; + try { + await makeTransaction(userID , amount , title , description ); + res.send({ success: true }); + } catch (error) { + console.error('Error making transactions', error); + res.status(500).send({ success: false, error: error.message }); + } +} + +exports.transactions = async(req , res) =>{ + const {pageNumber} = req.params; + const userID = req.user.id; + try{ + const result = await getUserTransactionsByPage(userID , pageNumber); + res.status(200).send({sucess : true , result : result}) + }catch{ + console.error('Error when getting transactions' , error); + res.status(500).send({ success: false, error: error.message }); + } +} \ No newline at end of file diff --git a/backend/src/routes/userRoutes.js b/backend/src/controllers/usersController.js similarity index 53% rename from backend/src/routes/userRoutes.js rename to backend/src/controllers/usersController.js index c7cee15..264ea80 100644 --- a/backend/src/routes/userRoutes.js +++ b/backend/src/controllers/usersController.js @@ -1,23 +1,8 @@ -const express = require('express'); -const { checkEmailExists, checkPasswordCorrect, createUser , getUserID, makeTransaction , getBalance, getUserTransactionsByPage} = require('../services/userService'); -const {isAuthenticated} = require('../middleware/autMiddleware') -const router = express.Router(); -const jwt = require('jsonwebtoken'); - -router.post('/checkEmailExists', async (req, res) => { - const email = req.body.email; - const emailExists = await checkEmailExists(email); - res.send({ emailExists }); -}); -router.post('/checkPasswordCorrect', async (req, res) => { - const email = req.body.email; - const password = req.body.password; - const passwordCorrect = await checkPasswordCorrect(email, password); - res.send({ passwordCorrect }); -}); +const { checkEmailExists, checkPasswordCorrect, createUser , getUserID, getBalance} = require('../services/userService'); +const jwt = require('jsonwebtoken'); -router.post('/login', async (req, res) => { +exports.login = async (req, res) => { const { email, password } = req.body; try { @@ -42,9 +27,9 @@ router.post('/login', async (req, res) => { console.error('Error in login:', error); res.status(500).send({ success: false, error: error.message }); } -}); - -router.post('/signup', async (req, res) => { +} + + exports.signup = async (req, res) => { const { email, password } = req.body; try { @@ -71,8 +56,9 @@ router.post('/signup', async (req, res) => { console.error('Error in signup:', error); res.status(500).send({ success: false, error: error.message }); } -}); -router.get('/getBalance', isAuthenticated, async (req, res) => { +} + + exports.balance = async (req, res) => { const userID = req.user.id; try { const result = await getBalance(userID); @@ -81,29 +67,4 @@ router.get('/getBalance', isAuthenticated, async (req, res) => { console.error('Error getting balance:', error); res.status(500).send({ success: false, error: error.message }); } -}); -router.post('/makeTransaction', isAuthenticated, async (req, res) => { - const {amount,title,description} = req.body; - - const userID = req.user.id; - try { - await makeTransaction(userID , amount , title , description ); - res.send({ success: true }); - } catch (error) { - console.error('Error making transactions', error); - res.status(500).send({ success: false, error: error.message }); - } -}); -router.post('/getTransactionByPage' , isAuthenticated , async(req , res) =>{ - const {pageNumber} = req.body; - const userID = req.user.id; - try{ - const result = await getUserTransactionsByPage(userID , pageNumber); - res.status(200).send({sucess : true , result : result}) - }catch{ - console.error('Error when getting transactions' , error); - res.status(500).send({ success: false, error: error.message }); - } -}) - -module.exports = router; \ No newline at end of file +} \ No newline at end of file diff --git a/backend/src/routes/transactions.js b/backend/src/routes/transactions.js new file mode 100644 index 0000000..5268dd8 --- /dev/null +++ b/backend/src/routes/transactions.js @@ -0,0 +1,12 @@ +const express = require('express'); +const {isAuthenticated} = require('../middleware/autMiddleware') +const router = express.Router(); +const jwt = require('jsonwebtoken'); +const {getUserTransactionsByPage , makeTransaction} = require('../services/transactionService') +const transactionController = require('../controllers/transactionsController') + + +router.post('/makeTransaction', isAuthenticated, transactionController.transaction); +router.get('/getTransactionByPage/:pageNumber' , isAuthenticated , transactionController.transactions); + +module.exports = router; \ No newline at end of file diff --git a/backend/src/routes/users.js b/backend/src/routes/users.js new file mode 100644 index 0000000..21b8b2a --- /dev/null +++ b/backend/src/routes/users.js @@ -0,0 +1,26 @@ +const express = require('express'); +const {isAuthenticated} = require('../middleware/autMiddleware') +const router = express.Router(); +const jwt = require('jsonwebtoken'); +const usersController = require('../controllers/usersController'); + +// router.post('/checkEmailExists', async (req, res) => { +// const email = req.body.email; +// const emailExists = await checkEmailExists(email); +// res.send({ emailExists }); +// }); + +// router.post('/checkPasswordCorrect', async (req, res) => { +// const email = req.body.email; +// const password = req.body.password; +// const passwordCorrect = await checkPasswordCorrect(email, password); +// res.send({ passwordCorrect }); +// }); + +router.post('/login', usersController.login); +router.post('/signup', usersController.signup); +router.get('/balance', isAuthenticated, usersController.balance); + + + +module.exports = router; \ No newline at end of file diff --git a/backend/src/server.js b/backend/src/server.js index 9bf5d89..d933b95 100644 --- a/backend/src/server.js +++ b/backend/src/server.js @@ -1,30 +1,22 @@ +//dependancies const express = require("express"); -const session = require("express-session"); const cors = require("cors"); -const userRoutes = require("./routes/userRoutes.js"); -const createTables = require("./config/createTables.js"); const jwt = require("jsonwebtoken"); +//config const pool = require("./config/db.js"); +const createTables = require("./config/createTables.js"); +const corsConfig = require("./config/corsConfig"); +//middleware const isAuthenticated = require("./middleware/autMiddleware.js"); - - +//routes +const userRoutes = require("./routes/users.js"); +const transactionRoutes = require("./routes/transactions") const app = express(); app.use(express.json()); app.use(express.urlencoded({ extended: true })); -app.use(cors({ - origin: function (origin, callback) { - if (!origin || allowedOrigins.indexOf(origin) !== -1) { - callback(null, true); - } else { - callback(new Error('Not allowed by CORS')); - } - }, - methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], - allowedHeaders: ['Content-Type', 'Authorization'], - credentials: true, -})); +app.use(corsConfig); pool.connect((err) => { if (err) { @@ -43,6 +35,7 @@ pool.connect((err) => { }); app.use('/user', userRoutes); +app.use('/transactions' , transactionRoutes); const port = 4000 diff --git a/backend/src/services/securePassword.js b/backend/src/services/securePassword.js index b924c39..864b9f5 100644 --- a/backend/src/services/securePassword.js +++ b/backend/src/services/securePassword.js @@ -12,7 +12,7 @@ async function hashPassword(password) { return hashedPassword; } catch (error) { - throw new Error('Error hashing password'); + throw new Error('Error hashing password password was' + password ); } } diff --git a/backend/src/services/transactionService.js b/backend/src/services/transactionService.js new file mode 100644 index 0000000..c0a0f87 --- /dev/null +++ b/backend/src/services/transactionService.js @@ -0,0 +1,60 @@ + +const { system } = require('nodemon/lib/config'); +const pool = require('../config/db'); + + + + +const getUserTransactionsByPage = async(userID , pageNumber) => { + + const pageSize = 10; + const offset = (pageNumber - 1) * pageSize; + try { + const query = { + text: ` + SELECT * FROM transactions + WHERE user_id = $1 + ORDER BY created_at ASC + LIMIT $2 + OFFSET $3 + `, + values: [userID, pageSize, offset] + }; + try { + const result = await pool.query(query); + return result.rows; + } catch{ + console.error("error when getting transactions" , error); + } + }catch { + console.error("error in function start" , error); + } +} + +const makeTransaction = async ( userID , amount , title , description) => { + try { + const addTransactionQuery = { + text: 'INSERT INTO transactions (user_id , amount , title , description) VALUES ($1, $2, $3, $4)' + , + values : [ userID, amount , title , description ] + } + const changeBalanceQuery = { + text : 'UPDATE users SET balance = balance + $1 WHERE id = $2', + values: [amount , userID] + } + try { + const result = await pool.query(addTransactionQuery); + const result2 = await pool.query(changeBalanceQuery); + console.log(`succesfuly made transaction user_id : ${userID} , amount : ${amount} , title : ${title} , description : ${description}`) + } catch(error){ + console.error('Error updating balance:', error); + } + } catch(error){ + console.error("problem with decrease balance function",error); + } +} + +module.exports = { + makeTransaction, + getUserTransactionsByPage +} \ No newline at end of file diff --git a/backend/src/services/userService.js b/backend/src/services/userService.js index 4dc9469..35f7c06 100644 --- a/backend/src/services/userService.js +++ b/backend/src/services/userService.js @@ -1,7 +1,7 @@ const { system } = require('nodemon/lib/config'); const pool = require('../config/db'); const { hashPassword, comparePasswords } = require('./securePassword'); -const { use } = require('../routes/userRoutes'); +const { use } = require('../routes/users'); const getUserID = async (email) => { @@ -144,7 +144,5 @@ module.exports = { checkPasswordCorrect, createUser, getUserID, - makeTransaction, getBalance, - getUserTransactionsByPage }; \ No newline at end of file