From bf2973e8aef07f13f0183879632b8c8613e51243 Mon Sep 17 00:00:00 2001 From: cavdy Date: Thu, 25 Apr 2019 11:07:52 +0100 Subject: [PATCH] feedbacks fixes: Feedback fixes Seperate migration from database, write more test cases, write comments with jsdocs, make login and signup form in one, added more eslint configurations, fix auth to have prefix v1, fix eslint disable, fix codeclimate badge, fix on delete error, make initial account draft on creation, fix whitespace on signup form [Starts #165546870] --- .eslintrc.js | 44 +- .travis.yml | 4 +- package.json | 2 +- server/swagger.json | 6 +- server/v1/app.js | 92 ++- server/v1/config/database.js | 168 ++--- server/v1/config/migration.js | 58 ++ server/v1/controllers/accounts.js | 128 ++++ server/v1/controllers/auth.js | 65 ++ server/v1/controllers/createAccount.js | 73 -- server/v1/controllers/login.js | 15 - server/v1/controllers/register.js | 25 - server/v1/controllers/transaction.js | 107 ++- server/v1/controllers/users.js | 97 ++- server/v1/helper/registrationHelper.js | 127 ++-- server/v1/helper/statusHelper.js | 109 ++- server/v1/middleware/jwt.js | 101 ++- server/v1/routes/accounts.js | 15 + server/v1/routes/auth.js | 12 + server/v1/routes/createAccount.js | 15 - server/v1/routes/login.js | 10 - server/v1/routes/register.js | 11 - .../{createAccount.js => accounts.js} | 451 ++++++------ server/v1/services/auth.js | 192 +++++ server/v1/services/login.js | 61 -- server/v1/services/register.js | 106 --- server/v1/services/transaction.js | 317 +++++---- server/v1/services/users.js | 245 ++++--- server/v1/test/accounts.js | 673 +++++++++++++----- server/v1/test/signin.js | 209 +++--- server/v1/test/signup.js | 478 +++++++------ server/v1/test/tests.js | 31 +- server/v1/test/transactions.js | 400 ++++++++--- server/v1/test/users.js | 449 +++++++++--- 34 files changed, 3053 insertions(+), 1843 deletions(-) create mode 100644 server/v1/config/migration.js create mode 100644 server/v1/controllers/accounts.js create mode 100644 server/v1/controllers/auth.js delete mode 100644 server/v1/controllers/createAccount.js delete mode 100644 server/v1/controllers/login.js delete mode 100644 server/v1/controllers/register.js create mode 100644 server/v1/routes/accounts.js create mode 100644 server/v1/routes/auth.js delete mode 100644 server/v1/routes/createAccount.js delete mode 100644 server/v1/routes/login.js delete mode 100644 server/v1/routes/register.js rename server/v1/services/{createAccount.js => accounts.js} (70%) create mode 100644 server/v1/services/auth.js delete mode 100644 server/v1/services/login.js delete mode 100644 server/v1/services/register.js diff --git a/.eslintrc.js b/.eslintrc.js index 923c92b..85e96bd 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,3 +1,43 @@ module.exports = { - "extends": "airbnb-base" -}; \ No newline at end of file + "extends": "airbnb-base", + "env": { + "browser": true, + "es6": true, + "jquery": true, + "node": true, + "mocha": true + }, + "rules": { + "one-var": 0, + "one-var-declaration-per-line": 0, + "new-cap": 0, + "consistent-return": 0, + "no-param-reassign": 0, + "comma-dangle": 0, + "curly": ["error", "multi-line"], + "import/no-unresolved": [2, { + "commonjs": true + }], + "no-shadow": ["error", { + "allow": ["req", "res", "err"] + }], + "valid-jsdoc": ["error", { + "requireReturn": true, + "requireReturnType": true, + "requireParamDescription": false, + "requireReturnDescription": true + }], + "require-jsdoc": ["error", { + "require": { + "FunctionDeclaration": true, + "MethodDefinition": true, + "ClassDeclaration": true + } + }], + "max-len": ["error", { "code": 80 }], + "linebreak-style": [ + "error", + "windows" + ] + } +}; diff --git a/.travis.yml b/.travis.yml index e54ff98..95f246e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,5 +12,5 @@ script: after_success: - npm run coverage env: -global: - -- CODECLIMATE_REPO_TOKEN=c14abfc89b0eb06fcb10f480f4b3e47142ac181c60c21f0131b570e72b1fbeb7 \ No newline at end of file + global: + - CODECLIMATE_REPO_TOKEN=c14abfc89b0eb06fcb10f480f4b3e47142ac181c60c21f0131b570e72b1fbeb7 \ No newline at end of file diff --git a/package.json b/package.json index ba4c1e9..ba29e8c 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "start": "node ./server/build/app.js", "build": "babel -d ./server/build ./server/v1 -s", "dev": "nodemon --exec babel-node ./server/v1/app.js", - "test": "mocha --timeout 20000 ./server/v1/test/tests.js --recursive --require @babel/register --exit || true", + "test": "nyc mocha --timeout 30000 ./server/v1/test/tests.js --recursive --require @babel/register --exit || true", "generate-lcov": "nyc report --reporter=text-lcov > lcov.info", "coveralls-coverage": "coveralls < lcov.info", "codeclimate-coverage": "codeclimate-test-reporter < lcov.info", diff --git a/server/swagger.json b/server/swagger.json index 04added..edfda99 100644 --- a/server/swagger.json +++ b/server/swagger.json @@ -11,7 +11,7 @@ "https" ], "paths": { - "/auth/signup": { + "v1/auth/signup": { "post": { "tags": [ "Signup" @@ -62,7 +62,7 @@ } } }, - "/auth/signup/addstaff": { + "v1/auth/signup/addstaff": { "post": { "tags": [ "Signup" @@ -132,7 +132,7 @@ ] } }, - "/auth/signin": { + "v1/auth/signin": { "post": { "tags": [ "Signin" diff --git a/server/v1/app.js b/server/v1/app.js index c05d87b..a35be23 100644 --- a/server/v1/app.js +++ b/server/v1/app.js @@ -1,47 +1,45 @@ -import express from 'express'; -import bodyParser from 'body-parser'; -import cors from 'cors'; -import debug from 'debug'; -import swaggerUi from 'swagger-ui-express'; -import dbConnection from './config/database'; -import swaggerDocument from '../swagger'; -import RegisterRoute from './routes/register'; -import LoginRoute from './routes/login'; -import CreateAccountRoute from './routes/createAccount'; -import TransactionRoute from './routes/transaction'; -import UsersRoute from './routes/users'; -import jwtMiddleware from './middleware/jwt'; - -// instantiate expressjs -const app = express(); -const PORT = process.env.PORT || 5100; - -app.use(cors()); - -app.use(bodyParser.json()); -app.use(bodyParser.urlencoded({ extended: false })); - -// swagger -app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument)); - -// creating database tables -dbConnection.createTable(); - -// Index Route -app.get('/', (req, res) => { - res.send('welcome to Banka API'); -}); - -// creating the api version route -app.use('/api/auth/signup', RegisterRoute); -app.use('/api/auth/signin', LoginRoute); -app.use('/api/v1/accounts', jwtMiddleware.checkToken, CreateAccountRoute); -app.use('/api/v1/transactions', jwtMiddleware.checkToken, TransactionRoute); -app.use('/api/v1/users', jwtMiddleware.checkToken, UsersRoute); - -// listening to our port -app.listen(PORT, () => { - debug('server')(`server running on port: ${PORT}`); -}); - -export default app; +import express from 'express'; +import bodyParser from 'body-parser'; +import cors from 'cors'; +import debug from 'debug'; +import swaggerUi from 'swagger-ui-express'; +import migration from './config/migration'; +import swaggerDocument from '../swagger'; +import AuthRoute from './routes/auth'; +import CreateAccountRoute from './routes/accounts'; +import TransactionRoute from './routes/transaction'; +import UsersRoute from './routes/users'; +import jwtMiddleware from './middleware/jwt'; + +// instantiate expressjs +const app = express(); +const PORT = process.env.PORT || 5100; + +app.use(cors()); + +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: false })); + +// swagger +app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument)); + +// creating database tables +migration.createTable(); + +// Index Route +app.get('/', (req, res) => { + res.send('welcome to Banka API'); +}); + +// creating the api version route +app.use('/api/v1/auth', AuthRoute); +app.use('/api/v1/accounts', jwtMiddleware.checkToken, CreateAccountRoute); +app.use('/api/v1/transactions', jwtMiddleware.checkToken, TransactionRoute); +app.use('/api/v1/users', jwtMiddleware.checkToken, UsersRoute); + +// listening to our port +app.listen(PORT, () => { + debug('server')(`server running on port: ${PORT}`); +}); + +export default app; diff --git a/server/v1/config/database.js b/server/v1/config/database.js index 267ff1e..a7a944a 100644 --- a/server/v1/config/database.js +++ b/server/v1/config/database.js @@ -1,107 +1,61 @@ -import { Pool } from 'pg'; -import debug from 'debug'; -import dotenv from 'dotenv'; -import { parse } from 'pg-connection-string'; - -dotenv.config(); - -let conString; - -if (process.env.HEROKU_ACCESS === 'heroku_access') { - conString = parse(process.env.BANKA_DB); -} else { - conString = parse(process.env.DB_CONFIG); -} - -const pool = new Pool(conString); - -const dbConnection = { - async createTable() { - const users = - `CREATE TABLE IF NOT EXISTS - users ( - id SERIAL PRIMARY KEY UNIQUE, - email VARCHAR(80) UNIQUE, - firstName VARCHAR(20), - lastName VARCHAR(20), - password VARCHAR(80), - type VARCHAR(10), - isAdmin BOOLEAN - )`; - - const accounts = - `CREATE TABLE IF NOT EXISTS - accounts ( - id SERIAL PRIMARY KEY UNIQUE, - email VARCHAR(80), - firstName VARCHAR(20), - lastName VARCHAR(20), - accountNumber BIGINT UNIQUE, - createdOn VARCHAR(40), - owner INTEGER, - type VARCHAR(10), - status VARCHAR(10), - balance FLOAT - )`; - - const transactions = - `CREATE TABLE IF NOT EXISTS - transactions ( - id SERIAL PRIMARY KEY UNIQUE, - createdOn VARCHAR(40), - type VARCHAR(10), - accountNumber BIGINT, - cashier INTEGER, - amount FLOAT, - oldBalance FLOAT, - newBalance FLOAT - )`; - - try { - return (async () => { - const client = await pool.connect(); - try { - await client.query(users); - await client.query(accounts); - await client.query(transactions); - await client.query('INSERT into users(email, firstName, lastName, password, type, isAdmin) values($1, $2, $3, $4, $5, $6)', - ['admin@banka.com', 'cavdy', 'admin', process.env.ADMIN_PWD, 'staff', true]); - } finally { - client.release(); - } - })(); - } catch (e) { - return debug('query')(e.stack); - } - }, - async dbConnect(passedQuery, passedData) { - try { - return (async () => { - const client = await pool.connect(); - try { - return await client.query(passedQuery, passedData); - } finally { - client.release(); - } - })(); - } catch (e) { - return debug('query')(e.stack); - } - }, - async dbTesting(passedQuery) { - try { - return (async () => { - const client = await pool.connect(); - try { - return await client.query(passedQuery); - } finally { - client.release(); - } - })(); - } catch (e) { - return debug('query')(e.stack); - } - }, -}; - -export default dbConnection; +import { Pool } from 'pg'; +import debug from 'debug'; +import dotenv from 'dotenv'; +import { parse } from 'pg-connection-string'; + +dotenv.config(); + +let conString; + +if (process.env.HEROKU_ACCESS === 'heroku_access') { + conString = parse(process.env.BANKA_DB); +} else { + conString = parse(process.env.DB_CONFIG); +} + +const pool = new Pool(conString); + +const dbConnection = { + /** + * Connect to database + * @constructor + * @param {*} passedQuery - passed in SQL query. + * @param {*} passedData -passed in db values + */ + async dbConnect(passedQuery, passedData) { + try { + return (async () => { + const client = await pool.connect(); + try { + return await client.query(passedQuery, passedData); + } finally { + client.release(); + } + })(); + } catch (e) { + return debug('query')(e.stack); + } + }, + + /** + * Connect to database - For test + * @constructor + * @param {*} passedQuery - passed in SQL query. + */ + async dbTesting(passedQuery) { + try { + return (async () => { + const client = await pool.connect(); + try { + return await client.query(passedQuery); + } finally { + client.release(); + } + })(); + } catch (e) { + return debug('query')(e.stack); + } + }, +}; + +export default dbConnection; diff --git a/server/v1/config/migration.js b/server/v1/config/migration.js new file mode 100644 index 0000000..c8cff45 --- /dev/null +++ b/server/v1/config/migration.js @@ -0,0 +1,58 @@ +import dbConnection from './database'; + +const Migration = { + /** + * Migration + * @constructor + */ + async createTable() { + const users = ` + CREATE TABLE IF NOT EXISTS + users ( + id SERIAL PRIMARY KEY UNIQUE, + email VARCHAR(80) UNIQUE, + firstName VARCHAR(20), + lastName VARCHAR(20), + password VARCHAR(80), + type VARCHAR(10), + isAdmin BOOLEAN + )`; + + const accounts = ` + CREATE TABLE IF NOT EXISTS + accounts ( + id SERIAL PRIMARY KEY UNIQUE, + email VARCHAR(80), + firstName VARCHAR(20), + lastName VARCHAR(20), + accountNumber BIGINT UNIQUE, + createdOn VARCHAR(40), + owner INTEGER, + type VARCHAR(10), + status VARCHAR(10), + balance FLOAT + )`; + + const transactions = ` + CREATE TABLE IF NOT EXISTS + transactions ( + id SERIAL PRIMARY KEY UNIQUE, + createdOn VARCHAR(40), + type VARCHAR(10), + accountNumber BIGINT, + cashier INTEGER, + amount FLOAT, + oldBalance FLOAT, + newBalance FLOAT + )`; + + await dbConnection.dbConnect(users); + await dbConnection.dbConnect(accounts); + await dbConnection.dbConnect(transactions); + await dbConnection + .dbConnect('INSERT into users(email, firstName, lastName, password, type, isAdmin) values($1, $2, $3, $4, $5, $6)', + ['admin@banka.com', 'cavdy', 'admin', process.env.ADMIN_PWD, 'client', true]); + }, +}; + +export default Migration; diff --git a/server/v1/controllers/accounts.js b/server/v1/controllers/accounts.js new file mode 100644 index 0000000..fee96db --- /dev/null +++ b/server/v1/controllers/accounts.js @@ -0,0 +1,128 @@ +import AccountsService from '../services/accounts'; +import statusHelper from '../helper/statusHelper'; + +const CreateAccountController = { + /** + * Create accounts + * @constructor + * @param {*} req - get request. + * @param {*} res -get response + */ + async createAccount(req, res) { + const accountData = req.body; + const createdAccount = await AccountsService + .createAccount(accountData, req.authorizedData); + + const data = await statusHelper + .statusHelper(req, + res, + createdAccount.returnStatus, + createdAccount.returnError, + createdAccount.returnSuccess); + return data; + }, + + /** + * Get all accounts + * @constructor + * @param {*} req - get request. + * @param {*} res -get response + */ + async allAccounts(req, res) { + const queryParams = req.query.status; + const queryLimit = req.query.limit; + const allAccounts = await AccountsService + .allAccounts(queryParams, queryLimit, req.authorizedData); + + const data = await statusHelper + .statusHelper(req, + res, + allAccounts.returnStatus, + allAccounts.returnError, + allAccounts.returnSuccess); + return data; + }, + + /** + * Get specific account + * @constructor + * @param {*} req - get request. + * @param {*} res -get response + */ + async specificAccounts(req, res) { + const { accountNumber } = req.params; + const specificAccounts = await AccountsService + .specificAccounts(accountNumber); + + const data = await statusHelper + .statusHelper(req, + res, + specificAccounts.returnStatus, + specificAccounts.returnError, + specificAccounts.returnSuccess); + return data; + }, + + /** + * Get account transactions + * @constructor + * @param {*} req - get request. + * @param {*} res -get response + */ + async allAccountTransaction(req, res) { + const { accountNumber } = req.params; + const transactionHistory = await AccountsService + .allAccountTransaction(accountNumber); + + const data = await statusHelper + .statusHelper(req, + res, + transactionHistory.returnStatus, + transactionHistory.returnError, + transactionHistory.returnSuccess); + return data; + }, + + /** + * Patch account + * @constructor + * @param {*} req - get request. + * @param {*} res -get response + */ + async patchAccount(req, res) { + const { accountNumber } = req.params; + const accountStatus = req.body; + const updatedAccount = await AccountsService + .patchAccount(accountNumber, accountStatus, req.authorizedData); + + const data = await statusHelper + .statusHelper(req, + res, + updatedAccount.returnStatus, + updatedAccount.returnError, + updatedAccount.returnSuccess); + return data; + }, + + /** + * Delete accounts + * @constructor + * @param {*} req - get request. + * @param {*} res -get response + */ + async deleteAccount(req, res) { + const { accountNumber } = req.params; + const deleteAccount = await AccountsService + .deleteAccount(accountNumber, req.authorizedData); + + const data = await statusHelper + .statusHelper(req, + res, + deleteAccount.returnStatus, + deleteAccount.returnError, + deleteAccount.returnSuccess); + return data; + }, +}; + +export default CreateAccountController; diff --git a/server/v1/controllers/auth.js b/server/v1/controllers/auth.js new file mode 100644 index 0000000..c369c49 --- /dev/null +++ b/server/v1/controllers/auth.js @@ -0,0 +1,65 @@ +import AuthService from '../services/auth'; +import statusHelper from '../helper/statusHelper'; + +const AuthController = { + /** + * Login user + * @constructor + * @param {*} req - get request. + * @param {*} res -get response + */ + async loginUser(req, res) { + const userData = req.body; + const loggedUser = await AuthService.loginUser(userData, req.signintoken); + + const data = await statusHelper + .statusHelper(req, + res, + loggedUser.returnStatus, + loggedUser.returnError, + loggedUser.returnSuccess); + return data; + }, + + /** + * Signup user + * @constructor + * @param {*} req - get request. + * @param {*} res -get response + */ + async registerUser(req, res) { + const userData = req.body; + const createdUser = await AuthService + .registerUser(userData, req.signintoken); + + const data = await statusHelper + .statusHelper(req, + res, + createdUser.returnStatus, + createdUser.returnError, + createdUser.returnSuccess); + return data; + }, + + /** + * Signup staff + * @constructor + * @param {*} req - get request. + * @param {*} res -get response + */ + async createStaffs(req, res) { + const userData = req.body; + const createdStaff = await AuthService + .createStaffs(userData, req.signintoken, req.authorizedData); + + const data = await statusHelper + .statusHelper(req, + res, + createdStaff.returnStatus, + createdStaff.returnError, + createdStaff.returnSuccess); + return data; + }, +}; + +export default AuthController; diff --git a/server/v1/controllers/createAccount.js b/server/v1/controllers/createAccount.js deleted file mode 100644 index f15baae..0000000 --- a/server/v1/controllers/createAccount.js +++ /dev/null @@ -1,73 +0,0 @@ -import CreateAccountService from '../services/createAccount'; -import statusHelper from '../helper/statusHelper'; - -const CreateAccountController = { - async createAccount(req, res) { - const accountData = req.body; - const createdAccount = await CreateAccountService - .createAccount(accountData, req.authorizedData); - - const data = await statusHelper - .statusHelper('nothing', res, createdAccount.returnStatus, createdAccount.returnError, createdAccount.returnSuccess); - return data; - }, - - // all accounts - async allAccounts(req, res) { - const queryParams = req.query.status; - const queryLimit = req.query.limit; - const allAccounts = await CreateAccountService - .allAccounts(queryParams, queryLimit, req.authorizedData); - - const data = await statusHelper - .statusHelper('nothing', res, allAccounts.returnStatus, allAccounts.returnError, allAccounts.returnSuccess); - return data; - }, - - // specific account - async specificAccounts(req, res) { - const { accountNumber } = req.params; - const specificAccounts = await CreateAccountService - .specificAccounts(accountNumber); - - const data = await statusHelper - .statusHelper('nothing', res, specificAccounts.returnStatus, specificAccounts.returnError, specificAccounts.returnSuccess); - return data; - }, - - // get transaction history - async allAccountTransaction(req, res) { - const { accountNumber } = req.params; - const transactionHistory = await CreateAccountService - .allAccountTransaction(accountNumber); - - const data = await statusHelper - .statusHelper('nothing', res, transactionHistory.returnStatus, transactionHistory.returnError, transactionHistory.returnSuccess); - return data; - }, - - // patchAccount - async patchAccount(req, res) { - const { accountNumber } = req.params; - const accountStatus = req.body; - const updatedAccount = await CreateAccountService - .patchAccount(accountNumber, accountStatus, req.authorizedData); - - const data = await statusHelper - .statusHelper('nothing', res, updatedAccount.returnStatus, updatedAccount.returnError, updatedAccount.returnSuccess); - return data; - }, - - // deleteAccount - async deleteAccount(req, res) { - const { accountNumber } = req.params; - const deleteAccount = await CreateAccountService - .deleteAccount(accountNumber, req.authorizedData); - - const data = await statusHelper - .statusHelper('nothing', res, deleteAccount.returnStatus, deleteAccount.returnError, deleteAccount.returnSuccess); - return data; - }, -}; - -export default CreateAccountController; diff --git a/server/v1/controllers/login.js b/server/v1/controllers/login.js deleted file mode 100644 index 3d571c7..0000000 --- a/server/v1/controllers/login.js +++ /dev/null @@ -1,15 +0,0 @@ -import LoginService from '../services/login'; -import statusHelper from '../helper/statusHelper'; - -const LoginController = { - async loginUser(req, res) { - const userData = req.body; - const loggedUser = await LoginService.loginUser(userData, req.signintoken); - - const data = await statusHelper - .statusHelper('nothing', res, loggedUser.returnStatus, loggedUser.returnError, loggedUser.returnSuccess); - return data; - }, -}; - -export default LoginController; diff --git a/server/v1/controllers/register.js b/server/v1/controllers/register.js deleted file mode 100644 index 955daa5..0000000 --- a/server/v1/controllers/register.js +++ /dev/null @@ -1,25 +0,0 @@ -import RegisterService from '../services/register'; -import statusHelper from '../helper/statusHelper'; - -const RegisterController = { - async registerUser(req, res) { - const userData = req.body; - const createdUser = await RegisterService.registerUser(userData, req.signintoken); - - const data = await statusHelper - .statusHelper('nothing', res, createdUser.returnStatus, createdUser.returnError, createdUser.returnSuccess); - return data; - }, - - async createStaffs(req, res) { - const userData = req.body; - const createdStaff = await RegisterService - .createStaffs(userData, req.signintoken, req.authorizedData); - - const data = await statusHelper - .statusHelper('nothing', res, createdStaff.returnStatus, createdStaff.returnError, createdStaff.returnSuccess); - return data; - }, -}; - -export default RegisterController; diff --git a/server/v1/controllers/transaction.js b/server/v1/controllers/transaction.js index 11eb56d..cd2aeb9 100644 --- a/server/v1/controllers/transaction.js +++ b/server/v1/controllers/transaction.js @@ -1,39 +1,68 @@ -/* eslint-disable consistent-return */ -import TransactionService from '../services/transaction'; -import statusHelper from '../helper/statusHelper'; - -const TransactionController = { - async debitTransaction(req, res) { - const { accountNumber } = req.params; - const transactionData = req.body; - const debitedData = await TransactionService - .debitTransaction(accountNumber, req.authorizedData, transactionData); - - const data = await statusHelper - .statusHelper('nothing', res, debitedData.returnStatus, debitedData.returnError, debitedData.returnSuccess); - return data; - }, - - async getSpecificTransaction(req, res) { - const { transactionid } = req.params; - const getTransaction = await TransactionService - .getSpecificTransaction(transactionid); - - const data = await statusHelper - .statusHelper('nothing', res, getTransaction.returnStatus, getTransaction.returnError, getTransaction.returnSuccess); - return data; - }, - - async creditTransaction(req, res) { - const { accountNumber } = req.params; - const transactionData = req.body; - const creditedData = await TransactionService - .creditTransaction(accountNumber, req.authorizedData, transactionData); - - const data = await statusHelper - .statusHelper('nothing', res, creditedData.returnStatus, creditedData.returnError, creditedData.returnSuccess); - return data; - }, -}; - -export default TransactionController; +import TransactionService from '../services/transaction'; +import statusHelper from '../helper/statusHelper'; + +const TransactionController = { + /** + * Debit Account + * @constructor + * @param {*} req - get request. + * @param {*} res -get response + */ + async debitTransaction(req, res) { + const { accountNumber } = req.params; + const transactionData = req.body; + const debitedData = await TransactionService + .debitTransaction(accountNumber, req.authorizedData, transactionData); + + const data = await statusHelper + .statusHelper(req, + res, + debitedData.returnStatus, + debitedData.returnError, + debitedData.returnSuccess); + return data; + }, + + /** + * Get specific transaction + * @constructor + * @param {*} req - get request. + * @param {*} res -get response + */ + async getSpecificTransaction(req, res) { + const { transactionid } = req.params; + const getTransaction = await TransactionService + .getSpecificTransaction(transactionid); + + const data = await statusHelper + .statusHelper(req, + res, + getTransaction.returnStatus, + getTransaction.returnError, + getTransaction.returnSuccess); + return data; + }, + + /** + * Credit Account + * @constructor + * @param {*} req - get request. + * @param {*} res -get response + */ + async creditTransaction(req, res) { + const { accountNumber } = req.params; + const transactionData = req.body; + const creditedData = await TransactionService + .creditTransaction(accountNumber, req.authorizedData, transactionData); + + const data = await statusHelper + .statusHelper(req, + res, + creditedData.returnStatus, + creditedData.returnError, + creditedData.returnSuccess); + return data; + }, +}; + +export default TransactionController; diff --git a/server/v1/controllers/users.js b/server/v1/controllers/users.js index 6670788..060f123 100644 --- a/server/v1/controllers/users.js +++ b/server/v1/controllers/users.js @@ -1,33 +1,64 @@ -import UserService from '../services/users'; -import statusHelper from '../helper/statusHelper'; - -const UsersController = { - async getAllUsers(req, res) { - const queryLimit = req.query.limit; - const allUsers = await UserService.getAllUsers(req.authorizedData, queryLimit); - - const data = await statusHelper - .statusHelper('nothing', res, allUsers.returnStatus, allUsers.returnError, allUsers.returnSuccess); - return data; - }, - - async getUsersAccounts(req, res) { - const { email } = req.params; - const getUsersAccounts = await UserService.getUsersAccounts(email); - - const data = await statusHelper - .statusHelper('nothing', res, getUsersAccounts.returnStatus, getUsersAccounts.returnError, getUsersAccounts.returnSuccess); - return data; - }, - - async deleteUser(req, res) { - const { id } = req.params; - const deleteUser = await UserService.deleteUser(id, req.authorizedData); - - const data = await statusHelper - .statusHelper('nothing', res, deleteUser.returnStatus, deleteUser.returnError, deleteUser.returnSuccess); - return data; - }, -}; - -export default UsersController; +import UserService from '../services/users'; +import statusHelper from '../helper/statusHelper'; + +const UsersController = { + /** + * Get users + * @constructor + * @param {*} req - get request. + * @param {*} res -get response + */ + async getAllUsers(req, res) { + const queryLimit = req.query.limit; + const allUsers = await UserService + .getAllUsers(req.authorizedData, queryLimit); + + const data = await statusHelper + .statusHelper(req, + res, + allUsers.returnStatus, + allUsers.returnError, + allUsers.returnSuccess); + return data; + }, + + /** + * Get user accounts + * @constructor + * @param {*} req - get request. + * @param {*} res -get response + */ + async getUsersAccounts(req, res) { + const { email } = req.params; + const getUsersAccounts = await UserService.getUsersAccounts(email); + + const data = await statusHelper + .statusHelper(req, + res, + getUsersAccounts.returnStatus, + getUsersAccounts.returnError, + getUsersAccounts.returnSuccess); + return data; + }, + + /** + * Delete user + * @constructor + * @param {*} req - get request. + * @param {*} res -get response + */ + async deleteUser(req, res) { + const { id } = req.params; + const deleteUser = await UserService.deleteUser(id, req.authorizedData); + + const data = await statusHelper + .statusHelper(req, + res, + deleteUser.returnStatus, + deleteUser.returnError, + deleteUser.returnSuccess); + return data; + }, +}; + +export default UsersController; diff --git a/server/v1/helper/registrationHelper.js b/server/v1/helper/registrationHelper.js index 50056c4..a424b81 100644 --- a/server/v1/helper/registrationHelper.js +++ b/server/v1/helper/registrationHelper.js @@ -1,44 +1,83 @@ -/* eslint-disable one-var */ -/* eslint-disable one-var-declaration-per-line */ -const registrationHelper = { - async registrationHelper(userData) { - const firstnameAndLastnameRegex = /^[a-zA-Z ]{2,15}$/; - const emailRegex = /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,10})$/; - const passwordRegex = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/; - const returnValue = []; - let emailPassed, firstnamePassed, lastnamePassed, passwordPassed; - - // Check if email is valid - if (emailRegex.test(userData.email)) { - emailPassed = true; - } else { - returnValue.push('Email is required'); - } - - if (firstnameAndLastnameRegex.test(userData.firstName) && typeof userData.firstName !== 'undefined' && typeof userData.firstName === 'string') { - firstnamePassed = true; - } else { - returnValue.push('Firstname required'); - } - if (firstnameAndLastnameRegex.test(userData.lastName) && typeof userData.lastName !== 'undefined' && typeof userData.lastName === 'string') { - lastnamePassed = true; - } else { - returnValue.push('Lastname required'); - } - if (passwordRegex.test(userData.password) && typeof userData.password !== 'undefined' && userData.password !== null) { - passwordPassed = true; - } else { - returnValue.push('Password should contain atleast 8 characters, 1 uppercase letter, 1 lowercase letter, 1 number and 1 symbol or character'); - } - - return [ - firstnamePassed, - lastnamePassed, - emailPassed, - passwordPassed, - returnValue, - ]; - }, -}; - -export default registrationHelper; +const registrationHelper = { + /** + * Return validation status + * @constructor + * @param {*} userData - passed in user's data. + */ + async registrationHelper(userData) { + const firstnameAndLastnameRegex = /^[a-zA-Z ]{2,15}$/; + /* eslint max-len: ["error", { "ignoreRegExpLiterals": true }] */ + const emailRegex = /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,10})$/; + const passwordRegex = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/; + const whiteSpaces = /\s/g; + const returnValue = []; + let emailPassed, firstnamePassed, lastnamePassed, passwordPassed; + + let email; + let fname; + let lname; + let password; + + // strip spaces + if (typeof userData.email !== 'undefined') { + email = userData.email.replace(whiteSpaces, ''); + email = userData.email.trim(); + } + + if (typeof userData.firstName !== 'undefined') { + fname = userData.firstName.replace(whiteSpaces, ''); + fname = userData.firstName.trim(); + } + + if (typeof userData.lastName !== 'undefined') { + lname = userData.lastName.replace(whiteSpaces, ''); + lname = userData.lastName.trim(); + } + + if (typeof userData.password !== 'undefined') { + password = userData.password.replace(whiteSpaces, ''); + password = userData.password.trim(); + } + + // Check if email is valid + if (emailRegex.test(email) + && email !== '') { + emailPassed = true; + } else { + returnValue.push('Email is required'); + } + + if (firstnameAndLastnameRegex.test(fname) + && typeof fname === 'string' + && fname !== '') { + firstnamePassed = true; + } else { + returnValue.push('Firstname required'); + } + if (firstnameAndLastnameRegex.test(lname) + && typeof lname === 'string' + && lname !== '') { + lastnamePassed = true; + } else { + returnValue.push('Lastname required'); + } + if (passwordRegex.test(password) + && typeof password === 'string' + && password !== '') { + passwordPassed = true; + } else { + returnValue + .push('Password should contain atleast 8 characters, 1 uppercase letter, 1 lowercase letter, 1 number and 1 symbol or character'); + } + + return [ + firstnamePassed, + lastnamePassed, + emailPassed, + passwordPassed, + returnValue, + ]; + }, +}; + +export default registrationHelper; diff --git a/server/v1/helper/statusHelper.js b/server/v1/helper/statusHelper.js index ddd8cad..a4b8df7 100644 --- a/server/v1/helper/statusHelper.js +++ b/server/v1/helper/statusHelper.js @@ -1,56 +1,53 @@ -/* eslint-disable no-else-return */ -const statusHelper = { - async statusHelper(req, res, status, error, data) { - if (status === 401) { // unauthorized - res.status(401); - return res.json({ - status: 401, - data: error, - }); - } else if (status === 500) { // internal error - res.status(500); - return res.json({ - status: 500, - data: 'Internal Server Error', - }); - } else if (status === 409) { // conflict - res.status(409); - return res.json({ - status: 409, - data: error, - }); - } else if (status === 201) { // created - res.status(201); - return res.json({ - status: 201, - data, - }); - } else if (status === 200) { // success - res.status(200); - return res.json({ - status: 200, - data, - }); - } else if (status === 404) { // not found - res.status(404); - return res.json({ - status: 404, - data: error, - }); - } else if (status === 204) { // no content - res.status(204); - return res.json({ - status: 204, - data: error, - }); - } else if (status === 422) { - res.status(422); - return res.json({ // unprocessable entity - status: 422, - data: error, - }); - } - }, -}; - -export default statusHelper; +/* eslint-disable no-else-return */ +const statusHelper = { + /** + * Return json data base on the status + * @constructor + * @param {*} req - passed in req. + * @param {*} res -passed in res + * @param {*} status - passed in status + * @param {*} error - passed in error message + * @param {*} data - passed in success data + */ + async statusHelper(req, res, status, error, data) { + if (status === 401) { // unauthorized + res.status(401); + return res.json({ + status: 401, + data: error, + }); + } else if (status === 409) { // conflict + res.status(409); + return res.json({ + status: 409, + data: error, + }); + } else if (status === 201) { // created + res.status(201); + return res.json({ + status: 201, + data, + }); + } else if (status === 200) { // success + res.status(200); + return res.json({ + status: 200, + data, + }); + } else if (status === 404) { // not found + res.status(404); + return res.json({ + status: 404, + data: error, + }); + } else if (status === 422) { + res.status(422); + return res.json({ // unprocessable entity + status: 422, + data: error, + }); + } + }, +}; + +export default statusHelper; diff --git a/server/v1/middleware/jwt.js b/server/v1/middleware/jwt.js index bf875df..47ee931 100644 --- a/server/v1/middleware/jwt.js +++ b/server/v1/middleware/jwt.js @@ -1,39 +1,62 @@ -import jwt from 'jsonwebtoken'; -import dotenv from 'dotenv'; - -dotenv.config(); - -const jwtMiddleware = { - checkToken(req, res, next) { - const header = req.headers.authorization; - if (typeof header !== 'undefined') { - const bearer = header.split(' '); - const token = bearer[1]; - req.token = token; - next(); - } else { - // If header is undefined return Forbidden (403) - res.sendStatus(403); - } - }, - signinJwt(req, res, next) { - jwt.sign(req.body, process.env.JWTSECRETKEY, async (err, token) => { - if (err) { - return res.sendStatus(403); - } - req.signintoken = token; - return next(); - }); - }, - verifyJwt(req, res, next) { - jwt.verify(req.token, process.env.JWTSECRETKEY, (err, authorizedData) => { - if (err) { - return res.sendStatus(403); - } - req.authorizedData = authorizedData; - return next(); - }); - }, -}; - -export default jwtMiddleware; +import jwt from 'jsonwebtoken'; +import dotenv from 'dotenv'; + +dotenv.config(); + +const jwtMiddleware = { + /** + * Check Token + * @constructor + * @param {*} req - get request. + * @param {*} res -get response + * @param {*} next - run next + */ + checkToken(req, res, next) { + const header = req.headers.authorization; + if (typeof header !== 'undefined') { + const bearer = header.split(' '); + const token = bearer[1]; + req.token = token; + next(); + } else { + // If header is undefined return Forbidden (403) + res.sendStatus(403); + } + }, + + /** + * Signin Jwt + * @constructor + * @param {*} req - get request. + * @param {*} res -get response + * @param {*} next - run next + */ + signinJwt(req, res, next) { + jwt.sign(req.body, process.env.JWTSECRETKEY, async (err, token) => { + if (err) { + return res.sendStatus(403); + } + req.signintoken = token; + return next(); + }); + }, + + /** + * Verify Jwt + * @constructor + * @param {*} req - get request. + * @param {*} res -get response + * @param {*} next - run next + */ + verifyJwt(req, res, next) { + jwt.verify(req.token, process.env.JWTSECRETKEY, (err, authorizedData) => { + if (err) { + return res.sendStatus(403); + } + req.authorizedData = authorizedData; + return next(); + }); + }, +}; + +export default jwtMiddleware; diff --git a/server/v1/routes/accounts.js b/server/v1/routes/accounts.js new file mode 100644 index 0000000..fd8c343 --- /dev/null +++ b/server/v1/routes/accounts.js @@ -0,0 +1,15 @@ +import express from 'express'; +import jwtMiddleware from '../middleware/jwt'; +import AccountsController from '../controllers/accounts'; + +const router = express.Router(); + +// creating our routes +router.get('/', jwtMiddleware.verifyJwt, AccountsController.allAccounts); +router.get('/:accountNumber', jwtMiddleware.verifyJwt, AccountsController.specificAccounts); +router.get('/:accountNumber/transactions', jwtMiddleware.verifyJwt, AccountsController.allAccountTransaction); +router.post('/', jwtMiddleware.verifyJwt, AccountsController.createAccount); +router.patch('/:accountNumber', jwtMiddleware.verifyJwt, AccountsController.patchAccount); +router.delete('/:accountNumber', jwtMiddleware.verifyJwt, AccountsController.deleteAccount); + +export default router; diff --git a/server/v1/routes/auth.js b/server/v1/routes/auth.js new file mode 100644 index 0000000..f1177eb --- /dev/null +++ b/server/v1/routes/auth.js @@ -0,0 +1,12 @@ +import express from 'express'; +import jwtMiddleware from '../middleware/jwt'; +import AuthController from '../controllers/auth'; + +const router = express.Router(); + +// creating our routes +router.post('/signin', jwtMiddleware.signinJwt, AuthController.loginUser); +router.post('/signup', jwtMiddleware.signinJwt, AuthController.registerUser); +router.post('/signup/addstaff', jwtMiddleware.checkToken, jwtMiddleware.signinJwt, jwtMiddleware.verifyJwt, AuthController.createStaffs); + +export default router; diff --git a/server/v1/routes/createAccount.js b/server/v1/routes/createAccount.js deleted file mode 100644 index 9baac62..0000000 --- a/server/v1/routes/createAccount.js +++ /dev/null @@ -1,15 +0,0 @@ -import express from 'express'; -import jwtMiddleware from '../middleware/jwt'; -import CreateAccountController from '../controllers/createAccount'; - -const router = express.Router(); - -// creating our routes -router.get('/', jwtMiddleware.verifyJwt, CreateAccountController.allAccounts); -router.get('/:accountNumber', jwtMiddleware.verifyJwt, CreateAccountController.specificAccounts); -router.get('/:accountNumber/transactions', jwtMiddleware.verifyJwt, CreateAccountController.allAccountTransaction); -router.post('/', jwtMiddleware.verifyJwt, CreateAccountController.createAccount); -router.patch('/:accountNumber', jwtMiddleware.verifyJwt, CreateAccountController.patchAccount); -router.delete('/:accountNumber', jwtMiddleware.verifyJwt, CreateAccountController.deleteAccount); - -export default router; diff --git a/server/v1/routes/login.js b/server/v1/routes/login.js deleted file mode 100644 index 2314b3d..0000000 --- a/server/v1/routes/login.js +++ /dev/null @@ -1,10 +0,0 @@ -import express from 'express'; -import jwtMiddleware from '../middleware/jwt'; -import LoginController from '../controllers/login'; - -const router = express.Router(); - -// creating our routes -router.post('/', jwtMiddleware.signinJwt, LoginController.loginUser); - -export default router; diff --git a/server/v1/routes/register.js b/server/v1/routes/register.js deleted file mode 100644 index ab9b7c4..0000000 --- a/server/v1/routes/register.js +++ /dev/null @@ -1,11 +0,0 @@ -import express from 'express'; -import jwtMiddleware from '../middleware/jwt'; -import RegisterController from '../controllers/register'; - -const router = express.Router(); - -// creating our routes -router.post('/', jwtMiddleware.signinJwt, RegisterController.registerUser); -router.post('/addstaff', jwtMiddleware.checkToken, jwtMiddleware.signinJwt, jwtMiddleware.verifyJwt, RegisterController.createStaffs); - -export default router; diff --git a/server/v1/services/createAccount.js b/server/v1/services/accounts.js similarity index 70% rename from server/v1/services/createAccount.js rename to server/v1/services/accounts.js index 2d4ac4e..eae5a0f 100644 --- a/server/v1/services/createAccount.js +++ b/server/v1/services/accounts.js @@ -1,203 +1,248 @@ -/* eslint-disable no-param-reassign */ -import dbConnection from '../config/database'; -import AccountModel from '../model/CreateAccount'; - -const CreateAccountService = { - async createAccount(accountData, userData) { - let returnStatus; let returnSuccess = ''; let returnError = ''; - const accountNumberGenerator = Math.floor(Math.random() * 1000000000) + 3000000000; - const date = new Date(); - const createdOn = `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}`; - const balance = 0.00; - const status = 'active'; - - // pulling users data from database - const userDetails = await dbConnection - .dbConnect('SELECT id,firstname,lastname FROM users WHERE email=$1', [userData.email]); - const { firstname, lastname, id } = userDetails.rows[0]; - - // eslint-disable-next-line max-len - if (accountData.type === 'savings' || accountData.type === 'current') { - const response = await dbConnection - .dbConnect('INSERT into accounts(email, firstName, lastName, accountNumber, createdOn, owner, type, status, balance) values($1, $2, $3, $4, $5, $6, $7, $8, $9)', - [userData.email, firstname, lastname, accountNumberGenerator, createdOn, id, accountData.type, status, balance]); - if (response.command === 'INSERT') { - const accountDbData = await dbConnection - .dbConnect('SELECT id, accountnumber, createdon, owner, type, status, balance FROM accounts WHERE accountnumber=$1', [accountNumberGenerator]); - const account = new AccountModel(); - account.id = accountDbData.rows[0].id; - account.accountNumber = accountDbData.rows[0].accountnumber; - account.createdOn = accountDbData.rows[0].createdon; - account.owner = accountDbData.rows[0].owner; - account.type = accountDbData.rows[0].type; - account.status = accountDbData.rows[0].status; - account.balance = accountDbData.rows[0].balance; - returnStatus = 201; - returnSuccess = account; - } - } else { - returnStatus = 422; - returnError = 'account type can either be savings or current'; - } - - return { - returnStatus, - returnSuccess, - returnError, - }; - }, - - async allAccounts(queryParams, queryLimit, staff) { - let returnStatus; let returnSuccess = ''; let returnError = ''; - - // pulling users data from database - const userDetails = await dbConnection - .dbConnect('SELECT type, isadmin FROM users WHERE email=$1', [staff.email]); - const { type, isadmin } = userDetails.rows[0]; - - if (type === 'staff' || isadmin === true) { - if (typeof queryParams !== 'undefined' && typeof queryLimit !== 'undefined') { - const allAccounts = await dbConnection - .dbConnect('SELECT * from accounts WHERE status=$1 LIMIT $2', [queryParams, queryLimit]); - if (allAccounts.rows.length > 0) { - returnStatus = 200; - returnSuccess = allAccounts.rows; - } else { - returnStatus = 404; - returnError = 'no account found for this user'; - } - } else if (typeof queryParams === 'undefined' || typeof queryLimit !== 'undefined') { - const allAccounts = await dbConnection - .dbConnect('SELECT * from accounts LIMIT $1', [queryLimit]); - if (allAccounts.rows.length > 0) { - returnStatus = 200; - returnSuccess = allAccounts.rows; - } else { - returnStatus = 404; - returnError = 'no account found for this user'; - } - } else { - const allAccounts = await dbConnection - .dbConnect('SELECT * from accounts LIMIT $1', [10]); - returnStatus = 200; - returnSuccess = allAccounts.rows; - } - } else { - returnStatus = 401; - returnError = 'Sorry you don\'t have permission to perform this task'; - } - - return { - returnStatus, - returnSuccess, - returnError, - }; - }, - - async specificAccounts(accountNumber) { - let returnStatus; let returnSuccess = ''; let returnError = ''; - const userAccount = await dbConnection - .dbConnect('SELECT * from accounts WHERE accountnumber=$1', [accountNumber]); - if (userAccount.rows.length > 0) { - returnStatus = 200; - // eslint-disable-next-line prefer-destructuring - returnSuccess = userAccount.rows[0]; - } else { - returnStatus = 404; - returnError = 'no transaction found'; - } - return { - returnStatus, - returnSuccess, - returnError, - }; - }, - - async allAccountTransaction(accountNumber) { - let returnStatus; let returnSuccess = ''; let returnError = ''; - const userTransaction = await dbConnection - .dbConnect('SELECT * from transactions WHERE accountnumber=$1', [accountNumber]); - if (userTransaction.rows.length > 0) { - returnStatus = 200; - returnSuccess = userTransaction.rows; - } else { - returnStatus = 404; - returnError = 'no transaction found'; - } - return { - returnStatus, - returnSuccess, - returnError, - }; - }, - - async patchAccount(accountNumber, accountUpdate, staff) { - let returnStatus; let returnSuccess = ''; let returnError = ''; - - // pulling users data from database - const userDetails = await dbConnection - .dbConnect('SELECT type, isadmin FROM users WHERE email=$1', [staff.email]); - const { type, isadmin } = userDetails.rows[0]; - - if (type === 'staff' || isadmin === true) { - // eslint-disable-next-line no-plusplus - const accountDbData = await dbConnection - .dbConnect('SELECT accountnumber FROM accounts WHERE accountnumber=$1', [accountNumber]); - if (accountDbData.rows.length > 0) { - const updateAccount = await dbConnection - .dbConnect('UPDATE accounts SET status=$1 WHERE accountnumber=$2', [accountUpdate.status, accountNumber]); - if (updateAccount.command === 'UPDATE') { - const userDbData = await dbConnection.dbConnect('SELECT accountnumber, status FROM accounts WHERE accountnumber=$1', [accountNumber]); - const { accountnumber, status } = userDbData.rows[0]; - returnStatus = 200; - returnSuccess = { accountnumber, status }; - } else { - returnStatus = 500; - } - } - } else { - returnStatus = 401; - returnError = 'Sorry you don\'t have permission to perform this task'; - } - - return { - returnStatus, - returnSuccess, - returnError, - }; - }, - - async deleteAccount(accountNumber, staff) { - let returnStatus; let returnSuccess = ''; let returnError = ''; - - const userDetails = await dbConnection - .dbConnect('SELECT type, isadmin FROM users WHERE email=$1', [staff.email]); - const { type, isadmin } = userDetails.rows[0]; - - if (type === 'staff' || isadmin === true) { - const checkAccount = await dbConnection - .dbConnect('SELECT accountnumber FROM accounts WHERE accountnumber=$1', [accountNumber]); - if (checkAccount.rows.length > 0) { - const accountDbData = await dbConnection - .dbConnect('DELETE FROM accounts WHERE accountnumber=$1', [accountNumber]); - if (accountDbData.command === 'DELETE') { - returnStatus = 204; - returnSuccess = 'Account successfully deleted'; - } - } else { - returnStatus = 404; - returnError = 'no account found'; - } - } else { - returnStatus = 401; - returnError = 'Sorry you don\'t have permission to perform this task'; - } - return { - returnStatus, - returnSuccess, - returnError, - }; - }, -}; - -export default CreateAccountService; +import dbConnection from '../config/database'; +import AccountModel from '../model/CreateAccount'; + +const CreateAccountService = { + /** + * Create an account. + * @constructor + * @param {*} accountData - The title of the book. + * @param {*} userData - The author of the book. + */ + async createAccount(accountData, userData) { + let returnStatus; let returnSuccess = ''; let returnError = ''; + const ACNumberGenerator = Math.floor(Math.random() * 1000000000) + 3000000000; + const date = new Date(); + const createdOn = `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}`; + const balance = 0.00; + const status = 'draft'; + + // pulling users data from database + const userDetails = await dbConnection + .dbConnect('SELECT id,firstname,lastname FROM users WHERE email=$1', + [userData.email]); + const { firstname, lastname, id } = userDetails.rows[0]; + + if (accountData.type === 'savings' || accountData.type === 'current') { + const response = await dbConnection + .dbConnect('INSERT into accounts(email, firstName, lastName, accountNumber, createdOn, owner, type, status, balance) values($1, $2, $3, $4, $5, $6, $7, $8, $9)', + [userData.email, firstname, lastname, ACNumberGenerator, createdOn, id, accountData.type, status, balance]); + if (response.command === 'INSERT') { + const accountDbData = await dbConnection + .dbConnect('SELECT id, accountnumber, createdon, owner, type, status, balance FROM accounts WHERE accountnumber=$1', + [ACNumberGenerator]); + const account = new AccountModel(); + account.id = accountDbData.rows[0].id; + account.accountNumber = accountDbData.rows[0].accountnumber; + account.createdOn = accountDbData.rows[0].createdon; + account.owner = accountDbData.rows[0].owner; + account.type = accountDbData.rows[0].type; + account.status = accountDbData.rows[0].status; + account.balance = accountDbData.rows[0].balance; + returnStatus = 201; + returnSuccess = account; + } + } else { + returnStatus = 422; + returnError = 'account type can either be savings or current'; + } + + return { + returnStatus, + returnSuccess, + returnError, + }; + }, + + /** + * Get all accounts + * @constructor + * @param {*} queryParams - passed in query data. + * @param {*} queryLimit -passed query limit + * @param {*} staff - staff details passed in + */ + async allAccounts(queryParams, queryLimit, staff) { + let returnStatus; let returnSuccess = ''; let returnError = ''; + + // pulling users data from database + const userDetails = await dbConnection + .dbConnect('SELECT type, isadmin FROM users WHERE email=$1', + [staff.email]); + const { type, isadmin } = userDetails.rows[0]; + + if (type === 'staff' || isadmin === true) { + if (typeof queryParams !== 'undefined' + && typeof queryLimit !== 'undefined') { + const allAccounts = await dbConnection + .dbConnect('SELECT * from accounts WHERE status=$1 LIMIT $2', + [queryParams, queryLimit]); + if (allAccounts.rows.length > 0) { + returnStatus = 200; + returnSuccess = allAccounts.rows; + } else { + returnStatus = 404; + returnError = 'no account found'; + } + } else if (typeof queryParams === 'undefined' + || typeof queryLimit !== 'undefined') { + const allAccounts = await dbConnection + .dbConnect('SELECT * from accounts LIMIT $1', [queryLimit]); + if (allAccounts.rows.length > 0) { + returnStatus = 200; + returnSuccess = allAccounts.rows; + } + } else if (typeof queryParams === 'undefined' + && typeof queryLimit === 'undefined') { + const allAccounts = await dbConnection + .dbConnect('SELECT * from accounts LIMIT $1', [10]); + returnStatus = 200; + returnSuccess = allAccounts.rows; + } + } else { + returnStatus = 401; + returnError = 'Sorry you don\'t have permission to perform this task'; + } + + return { + returnStatus, + returnSuccess, + returnError, + }; + }, + + /** + * Get specific account + * @constructor + * @param {*} accountNumber - recieve account number. + */ + async specificAccounts(accountNumber) { + let returnStatus; let returnSuccess = ''; let returnError = ''; + const userAccount = await dbConnection + .dbConnect('SELECT * from accounts WHERE accountnumber=$1', + [accountNumber]); + if (userAccount.rows.length > 0) { + returnStatus = 200; + // eslint-disable-next-line prefer-destructuring + returnSuccess = userAccount.rows[0]; + } else { + returnStatus = 404; + returnError = 'no account found'; + } + return { + returnStatus, + returnSuccess, + returnError, + }; + }, + + /** + * Get all accounts trasactions that belongs to account number + * @constructor + * @param {*} accountNumber - recieve account number. + */ + async allAccountTransaction(accountNumber) { + let returnStatus; let returnSuccess = ''; let returnError = ''; + const userTransaction = await dbConnection + .dbConnect('SELECT * from transactions WHERE accountnumber=$1', + [accountNumber]); + if (userTransaction.rows.length > 0) { + returnStatus = 200; + returnSuccess = userTransaction.rows; + } else { + returnStatus = 404; + returnError = 'no transaction found'; + } + return { + returnStatus, + returnSuccess, + returnError, + }; + }, + + /** + * Patch account + * @constructor + * @param {*} accountNumber - recieve account number + * @param {*} accountUpdate -data to update + * @param {*} staff - staff details passed in + */ + async patchAccount(accountNumber, accountUpdate, staff) { + let returnStatus; let returnSuccess = ''; let returnError = ''; + + // pulling users data from database + const userDetails = await dbConnection + .dbConnect('SELECT type, isadmin FROM users WHERE email=$1', + [staff.email]); + const { type, isadmin } = userDetails.rows[0]; + + if (type === 'staff' || isadmin === true) { + const accountDbData = await dbConnection + .dbConnect('SELECT accountnumber FROM accounts WHERE accountnumber=$1', + [accountNumber]); + if (accountDbData.rows.length > 0) { + const updateAccount = await dbConnection + .dbConnect('UPDATE accounts SET status=$1 WHERE accountnumber=$2', + [accountUpdate.status, accountNumber]); + if (updateAccount.command === 'UPDATE') { + const userDbData = await dbConnection + .dbConnect('SELECT accountnumber, status FROM accounts WHERE accountnumber=$1', + [accountNumber]); + const { accountnumber, status } = userDbData.rows[0]; + returnStatus = 200; + returnSuccess = { accountnumber, status }; + } + } + } else { + returnStatus = 401; + returnError = 'Sorry you don\'t have permission to perform this task'; + } + + return { + returnStatus, + returnSuccess, + returnError, + }; + }, + + /** + * Delete account + * @constructor + * @param {*} accountNumber - recieve account number. + * @param {*} staff - staff details passed in + */ + async deleteAccount(accountNumber, staff) { + let returnStatus; let returnSuccess = ''; let returnError = ''; + + const userDetails = await dbConnection + .dbConnect('SELECT type, isadmin FROM users WHERE email=$1', + [staff.email]); + const { type, isadmin } = userDetails.rows[0]; + + if (type === 'staff' || isadmin === true) { + const checkAccount = await dbConnection + .dbConnect('SELECT accountnumber FROM accounts WHERE accountnumber=$1', + [accountNumber]); + if (checkAccount.rows.length > 0) { + const accountDbData = await dbConnection + .dbConnect('DELETE FROM accounts WHERE accountnumber=$1', + [accountNumber]); + if (accountDbData.command === 'DELETE') { + returnStatus = 200; + returnSuccess = 'Account successfully deleted'; + } + } else { + returnStatus = 404; + returnError = 'no account found'; + } + } else { + returnStatus = 401; + returnError = 'Sorry you don\'t have permission to perform this task'; + } + return { + returnStatus, + returnSuccess, + returnError, + }; + }, +}; + +export default CreateAccountService; diff --git a/server/v1/services/auth.js b/server/v1/services/auth.js new file mode 100644 index 0000000..0783121 --- /dev/null +++ b/server/v1/services/auth.js @@ -0,0 +1,192 @@ +import bcrypt from 'bcryptjs'; +import dbConnection from '../config/database'; +import UserModel from '../model/users'; +import registrationHelper from '../helper/registrationHelper'; + +const AuthService = { + /** + * Login user + * @constructor + * @param {*} userData - user form data. + * @param {*} token - user's token + */ + async loginUser(userData, token) { + /* eslint max-len: ["error", { "ignoreRegExpLiterals": true }] */ + const emailRegex = /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,10})$/; + const passwordRegex = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/; + let returnStatus; let returnSuccess = ''; let returnError = ''; + + // Check if email and password is valid + if (emailRegex.test(userData.email) + && passwordRegex.test(userData.password)) { + // check if email, if it exist get the user data + const emailresponse = await dbConnection + .dbConnect('SELECT * FROM users WHERE email=$1', [userData.email]); + if (emailresponse.rows.length > 0) { + // Load hash from your password DB. + const passwordUnhash = bcrypt + .compareSync(userData.password, emailresponse.rows[0].password); + if (passwordUnhash) { + // return users details + const user = new UserModel(); + user.id = emailresponse.rows[0].id; + user.firstName = emailresponse.rows[0].firstname; + user.lastName = emailresponse.rows[0].lastname; + user.email = emailresponse.rows[0].email; + user.token = token; + returnStatus = 201; + returnSuccess = user; + } else { + // else echo incorrect password + returnStatus = 422; + returnError = 'incorrect password'; + } + } else { + returnStatus = 404; + returnError = 'email does not exist'; + } + } else { + const error = []; + if (!emailRegex.test(userData.email)) { + returnStatus = 422; + error.push('invalid email address'); + } + + if (!passwordRegex.test(userData.password)) { + returnStatus = 422; + error + .push('Password should contain atleast 8 characters, 1 uppercase letter, 1 lowercase letter, 1 number and 1 symbol or character'); + } + returnError = error; + } + + + return { + returnStatus, + returnSuccess, + returnError, + }; + }, + + /** + * Register user + * @constructor + * @param {*} userData - user form data. + * @param {*} token - user's token + */ + async registerUser(userData, token) { + const returnData = await registrationHelper.registrationHelper(userData); + let returnStatus; let returnSuccess = ''; let returnError = ''; + + if (returnData[0] === true + && returnData[1] === true + && returnData[2] === true + && returnData[3] === true) { + const salt = bcrypt.genSaltSync(10); + const hash = bcrypt.hashSync(userData.password, salt); + userData.type = 'client'; + userData.isAdmin = false; + // checks if email exist + const emailresponse = await dbConnection + .dbConnect('SELECT email FROM users WHERE email=$1', + [userData.email]); + if (emailresponse.rows.length >= 1) { + returnStatus = 409; + returnError = 'email already exist'; + } else { + // email does not exist... you can insert data + const response = await dbConnection + .dbConnect('INSERT into users(email, firstName, lastName, password, type, isAdmin) values($1, $2, $3, $4, $5, $6)', + [userData.email, userData.firstName, userData.lastName, hash, userData.type, userData.isAdmin]); + if (response.command === 'INSERT') { + const userDbData = await dbConnection + .dbConnect('SELECT * FROM users WHERE email=$1', + [userData.email]); + const user = new UserModel(); + user.id = userDbData.rows[0].id; + user.firstName = userDbData.rows[0].firstname; + user.lastName = userDbData.rows[0].lastname; + user.email = userDbData.rows[0].email; + user.token = token; + returnStatus = 201; + returnSuccess = user; + } + } + } else { + returnStatus = 422; + // eslint-disable-next-line prefer-destructuring + returnError = returnData[4]; + } + return { + returnStatus, + returnSuccess, + returnError, + }; + }, + + /** + * Create staffs + * @constructor + * @param {*} userData - user form data. + * @param {*} token - user's token + * @param {*} admin - admin's token + */ + async createStaffs(userData, token, admin) { + const returnData = await registrationHelper.registrationHelper(userData); + let returnStatus; let returnSuccess = ''; let returnError = ''; + + const userDetails = await dbConnection + .dbConnect('SELECT isadmin FROM users WHERE email=$1', [admin.email]); + const { isadmin } = userDetails.rows[0]; + + if (isadmin === true) { + if (returnData[0] === true + && returnData[1] === true + && returnData[2] === true + && returnData[3] === true) { + const salt = bcrypt.genSaltSync(10); + const hash = bcrypt.hashSync(userData.password, salt); + // checks if email exist + const emailresponse = await dbConnection + .dbConnect('SELECT email FROM users WHERE email=$1', + [userData.email]); + if (emailresponse.rows.length >= 1) { + returnStatus = 409; + returnError = 'email already exist'; + } else { + // email does not exist... you can insert data + const response = await dbConnection + .dbConnect('INSERT into users(email, firstName, lastName, password, type, isAdmin) values($1, $2, $3, $4, $5, $6)', + [userData.email, userData.firstName, userData.lastName, hash, userData.type, userData.isAdmin]); + if (response.command === 'INSERT') { + const userDbData = await dbConnection + .dbConnect('SELECT * FROM users WHERE email=$1', + [userData.email]); + const user = new UserModel(); + user.id = userDbData.rows[0].id; + user.firstName = userDbData.rows[0].firstname; + user.lastName = userDbData.rows[0].lastname; + user.email = userDbData.rows[0].email; + user.token = token; + returnStatus = 201; + returnSuccess = user; + } + } + } else { + returnStatus = 422; + // eslint-disable-next-line prefer-destructuring + returnError = returnData[4]; + } + } else { + returnStatus = 401; + returnError = 'you must be an admin to create staffs'; + } + return { + returnStatus, + returnSuccess, + returnError, + }; + }, +}; + +export default AuthService; diff --git a/server/v1/services/login.js b/server/v1/services/login.js deleted file mode 100644 index f645676..0000000 --- a/server/v1/services/login.js +++ /dev/null @@ -1,61 +0,0 @@ -import bcrypt from 'bcryptjs'; -import dbConnection from '../config/database'; -import UserModel from '../model/users'; - -const LoginService = { - async loginUser(userData, token) { - const emailRegex = /^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,10})$/; - const passwordRegex = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/; - let returnStatus; let returnSuccess = ''; let returnError = ''; - - // Check if email and password is valid - if (emailRegex.test(userData.email) && passwordRegex.test(userData.password)) { - // check if email, if it exist get the user data - const emailresponse = await dbConnection.dbConnect('SELECT * FROM users WHERE email=$1', [userData.email]); - if (emailresponse.rows.length > 0) { - // Load hash from your password DB. - const passwordUnhash = bcrypt - .compareSync(userData.password, emailresponse.rows[0].password); - if (passwordUnhash) { - // return users details - const user = new UserModel(); - user.id = emailresponse.rows[0].id; - user.firstName = emailresponse.rows[0].firstname; - user.lastName = emailresponse.rows[0].lastname; - user.email = emailresponse.rows[0].email; - user.token = token; - returnStatus = 201; - returnSuccess = user; - } else { - // else echo incorrect password - returnStatus = 422; - returnError = 'incorrect password'; - } - } else { - returnStatus = 404; - returnError = 'email does not exist'; - } - } else { - const error = []; - if (!emailRegex.test(userData.email)) { - returnStatus = 422; - error.push('invalid email address'); - } - - if (!passwordRegex.test(userData.password)) { - returnStatus = 422; - error.push('Password should contain atleast 8 characters, 1 uppercase letter, 1 lowercase letter, 1 number and 1 symbol or character'); - } - returnError = error; - } - - - return { - returnStatus, - returnSuccess, - returnError, - }; - }, -}; - -export default LoginService; diff --git a/server/v1/services/register.js b/server/v1/services/register.js deleted file mode 100644 index e12958e..0000000 --- a/server/v1/services/register.js +++ /dev/null @@ -1,106 +0,0 @@ -/* eslint-disable no-param-reassign */ -import bcrypt from 'bcryptjs'; -import dbConnection from '../config/database'; -import registrationHelper from '../helper/registrationHelper'; -import UserModel from '../model/users'; - -const RegisterService = { - async registerUser(userData, token) { - const returnData = await registrationHelper.registrationHelper(userData); - let returnStatus; let returnSuccess = ''; let returnError = ''; - - // eslint-disable-next-line max-len - if (returnData[0] === true && returnData[1] === true && returnData[2] === true && returnData[3] === true) { - const salt = bcrypt.genSaltSync(10); - const hash = bcrypt.hashSync(userData.password, salt); - userData.type = 'client'; - userData.isAdmin = false; - // checks if email exist - const emailresponse = await dbConnection.dbConnect('SELECT email FROM users WHERE email=$1', [userData.email]); - if (emailresponse.rows.length >= 1) { - returnStatus = 409; - returnError = 'email already exist'; - } else { - // email does not exist... you can insert data - const response = await dbConnection.dbConnect('INSERT into users(email, firstName, lastName, password, type, isAdmin) values($1, $2, $3, $4, $5, $6)', - [userData.email, userData.firstName, userData.lastName, hash, userData.type, userData.isAdmin]); - if (response.command === 'INSERT') { - const userDbData = await dbConnection.dbConnect('SELECT * FROM users WHERE email=$1', [userData.email]); - const user = new UserModel(); - user.id = userDbData.rows[0].id; - user.firstName = userDbData.rows[0].firstname; - user.lastName = userDbData.rows[0].lastname; - user.email = userDbData.rows[0].email; - user.token = token; - returnStatus = 201; - returnSuccess = user; - } else { - returnStatus = 500; - } - } - } else { - returnStatus = 422; - // eslint-disable-next-line prefer-destructuring - returnError = returnData[4]; - } - return { - returnStatus, - returnSuccess, - returnError, - }; - }, - - async createStaffs(userData, token, admin) { - const returnData = await registrationHelper.registrationHelper(userData); - let returnStatus; let returnSuccess = ''; let returnError = ''; - - const userDetails = await dbConnection - .dbConnect('SELECT isadmin FROM users WHERE email=$1', [admin.email]); - const { isadmin } = userDetails.rows[0]; - - if (isadmin === true) { - // eslint-disable-next-line max-len - if (returnData[0] === true && returnData[1] === true && returnData[2] === true && returnData[3] === true) { - const salt = bcrypt.genSaltSync(10); - const hash = bcrypt.hashSync(userData.password, salt); - // checks if email exist - const emailresponse = await dbConnection.dbConnect('SELECT email FROM users WHERE email=$1', [userData.email]); - if (emailresponse.rows.length >= 1) { - returnStatus = 409; - returnError = 'email already exist'; - } else { - // email does not exist... you can insert data - const response = await dbConnection.dbConnect('INSERT into users(email, firstName, lastName, password, type, isAdmin) values($1, $2, $3, $4, $5, $6)', - [userData.email, userData.firstName, userData.lastName, hash, userData.type, userData.isAdmin]); - if (response.command === 'INSERT') { - const userDbData = await dbConnection.dbConnect('SELECT * FROM users WHERE email=$1', [userData.email]); - const user = new UserModel(); - user.id = userDbData.rows[0].id; - user.firstName = userDbData.rows[0].firstname; - user.lastName = userDbData.rows[0].lastname; - user.email = userDbData.rows[0].email; - user.token = token; - returnStatus = 201; - returnSuccess = user; - } else { - returnStatus = 500; - } - } - } else { - returnStatus = 422; - // eslint-disable-next-line prefer-destructuring - returnError = returnData[4]; - } - } else { - returnStatus = 401; - returnError = 'you must be an admin to create staffs'; - } - return { - returnStatus, - returnSuccess, - returnError, - }; - }, -}; - -export default RegisterService; diff --git a/server/v1/services/transaction.js b/server/v1/services/transaction.js index 9d659c0..b82101d 100644 --- a/server/v1/services/transaction.js +++ b/server/v1/services/transaction.js @@ -1,135 +1,182 @@ -/* eslint-disable no-param-reassign */ -import dbConnection from '../config/database'; -import TransactionModel from '../model/Transaction'; - -const TransactionService = { - async debitTransaction(accountNumber, loggedInUser, transactionData) { - let returnStatus; let returnSuccess = ''; let returnError = ''; - - // check the users table - const userDetails = await dbConnection - .dbConnect('SELECT id, type, isadmin FROM users WHERE email=$1', [loggedInUser.email]); - const { id, type, isadmin } = userDetails.rows[0]; - - // checks if logged in user is an admin or staff - if (type === 'staff' || isadmin === true) { - const date = new Date(); - const createdOn = `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}`; - - // pull accountnumber details from database - const accountDbData = await dbConnection - .dbConnect('SELECT accountnumber, balance FROM accounts WHERE accountnumber=$1', [accountNumber]); - const { accountnumber, balance } = accountDbData.rows[0]; - - // check if a string - const checkForDigit = /^-?\d+\.?\d*$/; - if (checkForDigit.test(transactionData.amount)) { - // substract the passed in amount from the current balance - const newBalance = balance - transactionData.amount; - const transactionDbData = await dbConnection - .dbConnect('INSERT into transactions(createdon, type, accountNumber, cashier, amount, oldbalance, newbalance) values($1, $2, $3, $4, $5,$6, $7)', - [createdOn, 'debit', accountnumber, id, transactionData.amount, balance, newBalance]); - if (transactionDbData.command === 'INSERT') { - // get the data from transaction - const accountData = await dbConnection.dbConnect('SELECT * FROM transactions WHERE accountnumber=$1', [accountNumber]); - // update the account table - await dbConnection.dbConnect('UPDATE accounts SET balance=$1 WHERE accountnumber=$2', [newBalance, accountNumber]); - const transaction = new TransactionModel(); - transaction.transactionId = accountData.rows[0].id; - transaction.accountNumber = accountData.rows[0].accountnumber; - transaction.amount = accountData.rows[0].amount; - transaction.cashier = accountData.rows[0].cashier; - transaction.transactionType = accountData.rows[0].type; - transaction.accountBalance = accountData.rows[0].newbalance; - returnStatus = 201; - returnSuccess = transaction; - } else { - returnStatus = 500; - } - } - } else { - returnStatus = 401; - returnError = 'You must be a staff or admin to perform this transaction'; - } - return { - returnStatus, - returnSuccess, - returnError, - }; - }, - - async getSpecificTransaction(transactionId) { - let returnStatus; let returnSuccess = ''; let returnError = ''; - const userTransaction = await dbConnection - .dbConnect('SELECT * from transactions WHERE id=$1', [transactionId]); - if (userTransaction.rows.length > 0) { - returnStatus = 200; - returnSuccess = userTransaction.rows; - } else { - returnStatus = 404; - returnError = 'no transaction found'; - } - return { - returnStatus, - returnSuccess, - returnError, - }; - }, - - async creditTransaction(accountNumber, loggedInUser, transactionData) { - let returnStatus; let returnSuccess = ''; let returnError = ''; - - // check the users table - const userDetails = await dbConnection - .dbConnect('SELECT id, type, isadmin FROM users WHERE email=$1', [loggedInUser.email]); - const { id, type, isadmin } = userDetails.rows[0]; - - // checks if logged in user is an admin or staff - if (type === 'staff' || isadmin === true) { - const date = new Date(); - const createdOn = `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}`; - - // pull accountnumber details from database - const accountDbData = await dbConnection - .dbConnect('SELECT accountnumber, balance FROM accounts WHERE accountnumber=$1', [accountNumber]); - const { accountnumber, balance } = accountDbData.rows[0]; - - // check if a string - const checkForDigit = /^-?\d+\.?\d*$/; - if (checkForDigit.test(transactionData.amount)) { - // add the passed in amount from the current balance - const newBalance = balance + transactionData.amount; - const transactionDbData = await dbConnection - .dbConnect('INSERT into transactions(createdon, type, accountNumber, cashier, amount, oldbalance, newbalance) values($1, $2, $3, $4, $5,$6, $7)', - [createdOn, 'credit', accountnumber, id, transactionData.amount, balance, newBalance]); - if (transactionDbData.command === 'INSERT') { - // get the data from transaction - const accountData = await dbConnection.dbConnect('SELECT * FROM transactions WHERE accountnumber=$1', [accountNumber]); - // update the account table - await dbConnection.dbConnect('UPDATE accounts SET balance=$1 WHERE accountnumber=$2', [newBalance, accountNumber]); - const transaction = new TransactionModel(); - transaction.transactionId = accountData.rows[0].id; - transaction.accountNumber = accountData.rows[0].accountnumber; - transaction.amount = accountData.rows[0].amount; - transaction.cashier = accountData.rows[0].cashier; - transaction.transactionType = accountData.rows[0].type; - transaction.accountBalance = accountData.rows[0].newbalance; - returnStatus = 201; - returnSuccess = transaction; - } else { - returnStatus = 500; - } - } - } else { - returnStatus = 401; - returnError = 'You must be a staff or admin to perform this transaction'; - } - return { - returnStatus, - returnSuccess, - returnError, - }; - }, -}; - -export default TransactionService; +/* eslint-disable no-param-reassign */ +import dbConnection from '../config/database'; +import TransactionModel from '../model/Transaction'; + +const TransactionService = { + + /** + * Debit Transaction + * @constructor + * @param {*} accountNumber - account number. + * @param {*} loggedInUser - logged in user + * @param {*} transactionData - transaction data + */ + async debitTransaction(accountNumber, loggedInUser, transactionData) { + let returnStatus; let returnSuccess = ''; let returnError = ''; + + // check the users table + const userDetails = await dbConnection + .dbConnect('SELECT id, type, isadmin FROM users WHERE email=$1', + [loggedInUser.email]); + const { id, type, isadmin } = userDetails.rows[0]; + + // checks if logged in user is an admin or staff + if (type === 'staff' || isadmin === true) { + const date = new Date(); + const createdOn = `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}`; + + // pull accountnumber details from database + const accountDbData = await dbConnection + .dbConnect( + 'SELECT accountnumber, balance FROM accounts WHERE accountnumber=$1', + [accountNumber] + ); + const { accountnumber, balance } = accountDbData.rows[0]; + + // check if a string + const checkForDigit = /^-?\d+\.?\d*$/; + if (checkForDigit.test(transactionData.amount)) { + // substract the passed in amount from the current balance + const newBalance = balance - transactionData.amount; + + // check if account balance is zero + if (newBalance < 0) { + returnStatus = 422; + returnError = 'Sorry this account is very low and can\'t be debited'; + } else { + const transactionDbData = await dbConnection + .dbConnect('INSERT into transactions(createdon, type, accountNumber, cashier, amount, oldbalance, newbalance) values($1, $2, $3, $4, $5,$6, $7)', + [createdOn, 'debit', accountnumber, id, transactionData.amount, balance, newBalance]); + if (transactionDbData.command === 'INSERT') { + // get the data from transaction + const accountData = await dbConnection + .dbConnect('SELECT * FROM transactions WHERE accountnumber=$1', + [accountNumber]); + // update the account table + const acBalance = await dbConnection + .dbConnect( + 'UPDATE accounts SET balance=$1 WHERE accountnumber=$2 RETURNING balance', + [newBalance, accountNumber] + ); + const transaction = new TransactionModel(); + transaction.transactionId = accountData.rows[0].id; + transaction.accountNumber = accountData.rows[0].accountnumber; + transaction.amount = accountData.rows[0].amount; + transaction.cashier = accountData.rows[0].cashier; + transaction.transactionType = accountData.rows[0].type; + transaction.accountBalance = acBalance.rows[0].balance; + returnStatus = 201; + returnSuccess = transaction; + } + } + } else { + returnStatus = 422; + returnError = 'please numbers only'; + } + } else { + returnStatus = 401; + returnError = 'You must be a staff or admin to perform this transaction'; + } + return { + returnStatus, + returnSuccess, + returnError, + }; + }, + + /** + * Get specific transaction + * @constructor + * @param {*} transactionId - transaction id. + */ + async getSpecificTransaction(transactionId) { + let returnStatus; let returnSuccess = ''; let returnError = ''; + const userTransaction = await dbConnection + .dbConnect('SELECT * from transactions WHERE id=$1', [transactionId]); + if (userTransaction.rows.length > 0) { + returnStatus = 200; + returnSuccess = userTransaction.rows; + } else { + returnStatus = 404; + returnError = 'no transaction found'; + } + return { + returnStatus, + returnSuccess, + returnError, + }; + }, + + /** + * Credit Transaction + * @constructor + * @param {*} accountNumber - account number. + * @param {*} loggedInUser - logged in user + * @param {*} transactionData - transaction data + */ + async creditTransaction(accountNumber, loggedInUser, transactionData) { + let returnStatus; let returnSuccess = ''; let returnError = ''; + + // check the users table + const userDetails = await dbConnection + .dbConnect('SELECT id, type, isadmin FROM users WHERE email=$1', + [loggedInUser.email]); + const { id, type, isadmin } = userDetails.rows[0]; + + // checks if logged in user is an admin or staff + if (type === 'staff' || isadmin === true) { + const date = new Date(); + const createdOn = `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}`; + + // pull accountnumber details from database + const accountDbData = await dbConnection + .dbConnect( + 'SELECT accountnumber, balance FROM accounts WHERE accountnumber=$1', + [accountNumber] + ); + const { accountnumber, balance } = accountDbData.rows[0]; + + // check if a string + const checkForDigit = /^-?\d+\.?\d*$/; + if (checkForDigit.test(transactionData.amount)) { + // add the passed in amount from the current balance + const newBalance = balance + transactionData.amount; + const transactionDbData = await dbConnection + .dbConnect('INSERT into transactions(createdon, type, accountNumber, cashier, amount, oldbalance, newbalance) values($1, $2, $3, $4, $5,$6, $7)', + [createdOn, 'credit', accountnumber, id, transactionData.amount, balance, newBalance]); + if (transactionDbData.command === 'INSERT') { + // get the data from transaction + const accountData = await dbConnection + .dbConnect('SELECT * FROM transactions WHERE accountnumber=$1', + [accountNumber]); + // update the account table + const acBalance = await dbConnection + .dbConnect('UPDATE accounts SET balance=$1 WHERE accountnumber=$2 RETURNING balance', + [newBalance, accountNumber]); + const transaction = new TransactionModel(); + transaction.transactionId = accountData.rows[0].id; + transaction.accountNumber = accountData.rows[0].accountnumber; + transaction.amount = accountData.rows[0].amount; + transaction.cashier = accountData.rows[0].cashier; + transaction.transactionType = accountData.rows[0].type; + transaction.accountBalance = acBalance.rows[0].balance; + returnStatus = 201; + returnSuccess = transaction; + } + } else { + returnStatus = 422; + returnError = 'please numbers only'; + } + } else { + returnStatus = 401; + returnError = 'You must be a staff or admin to perform this transaction'; + } + return { + returnStatus, + returnSuccess, + returnError, + }; + }, +}; + +export default TransactionService; diff --git a/server/v1/services/users.js b/server/v1/services/users.js index af71183..096426f 100644 --- a/server/v1/services/users.js +++ b/server/v1/services/users.js @@ -1,115 +1,130 @@ -import dbConnection from '../config/database'; - -const UsersServices = { - async getAllUsers(staff, queryLimit) { - let returnStatus; let returnSuccess = ''; let returnError = ''; - // check the users table - const userDetails = await dbConnection - .dbConnect('SELECT id, type, isadmin FROM users WHERE email=$1', [staff.email]); - const { type, isadmin } = userDetails.rows[0]; - - if (type === 'staff' || isadmin === true) { - if (typeof queryLimit !== 'undefined') { - const allAccounts = await dbConnection - .dbConnect('SELECT * from users LIMIT $1', [queryLimit]); - returnStatus = 200; - returnSuccess = allAccounts.rows; - } else { - const allAccounts = await dbConnection - .dbConnect('SELECT * from users LIMIT $1', [10]); - returnStatus = 200; - returnSuccess = allAccounts.rows; - } - } else { - returnStatus = 401; - returnError = 'You don\'t have permission to view this page'; - } - return { - returnStatus, - returnSuccess, - returnError, - }; - }, - - async getUsersAccounts(email) { - let returnStatus; let returnSuccess = ''; let returnError = ''; - const allAccounts = await dbConnection - .dbConnect('SELECT email from users WHERE email=$1', [email]); - if (allAccounts.rows.length > 0) { - const accountDbData = await dbConnection - .dbConnect('SELECT * from accounts WHERE email=$1', [email]); - if (accountDbData.rows.length > 0) { - returnStatus = 200; - returnSuccess = accountDbData.rows; - } else { - returnStatus = 404; - returnError = 'no account found for this user'; - } - } else { - returnStatus = 404; - returnError = 'email does not exist'; - } - return { - returnStatus, - returnSuccess, - returnError, - }; - }, - - async deleteUser(id, staff) { - let returnStatus; let returnSuccess = ''; let returnError = ''; - // check the users table - const userDetails = await dbConnection - .dbConnect('SELECT id, type, isadmin FROM users WHERE email=$1', [staff.email]); - const { type, isadmin } = userDetails.rows[0]; - - if (type === 'staff') { - const checkusers = await dbConnection - .dbConnect('SELECT type FROM users WHERE id=$1', [id]); - if (checkusers.rows.length > 0) { - if (checkusers.rows[0].type === 'client') { - const accountDbData = await dbConnection - .dbConnect('DELETE FROM users WHERE id=$1', [id]); - if (accountDbData.command === 'DELETE') { - returnStatus = 204; - returnSuccess = 'Account successfully deleted'; - } else { - returnStatus = 500; - } - } else { - returnStatus = 401; - returnError = 'you must be an admin to delete this staff'; - } - } else { - returnStatus = 404; - returnError = 'no account found'; - } - } else if (isadmin === true) { - const checkusers = await dbConnection - .dbConnect('SELECT type FROM users WHERE id=$1', [id]); - if (checkusers.rows.length > 0) { - const accountDbData = await dbConnection - .dbConnect('DELETE FROM users WHERE id=$1', [id]); - if (accountDbData.command === 'DELETE') { - returnStatus = 204; - returnSuccess = 'Account successfully deleted'; - } else { - returnStatus = 500; - } - } else { - returnStatus = 404; - returnError = 'no account found'; - } - } else { - returnStatus = 401; - returnError = 'You don\'t have permission to view this page'; - } - return { - returnStatus, - returnSuccess, - returnError, - }; - }, -}; - -export default UsersServices; +import dbConnection from '../config/database'; + +const UsersServices = { + /** + * Get all users + * @constructor + * @param {*} staff - get token details to check if staff or admin + * @param {*} queryLimit - Get query parameter + */ + async getAllUsers(staff, queryLimit) { + let returnStatus; let returnSuccess = ''; let returnError = ''; + // check the users table + const userDetails = await dbConnection + .dbConnect('SELECT id, type, isadmin FROM users WHERE email=$1', + [staff.email]); + const { type, isadmin } = userDetails.rows[0]; + + if (type === 'staff' || isadmin === true) { + if (typeof queryLimit !== 'undefined') { + const allAccounts = await dbConnection + .dbConnect('SELECT * from users LIMIT $1', [queryLimit]); + returnStatus = 200; + returnSuccess = allAccounts.rows; + } else { + const allAccounts = await dbConnection + .dbConnect('SELECT * from users LIMIT $1', [10]); + returnStatus = 200; + returnSuccess = allAccounts.rows; + } + } else { + returnStatus = 401; + returnError = 'You don\'t have permission to view this page'; + } + return { + returnStatus, + returnSuccess, + returnError, + }; + }, + + /** + * Get user's accounts by email + * @constructor + * @param {*} email - get user's email + */ + async getUsersAccounts(email) { + let returnStatus; let returnSuccess = ''; let returnError = ''; + const allAccounts = await dbConnection + .dbConnect('SELECT email from users WHERE email=$1', [email]); + if (allAccounts.rows.length > 0) { + const accountDbData = await dbConnection + .dbConnect('SELECT * from accounts WHERE email=$1', [email]); + if (accountDbData.rows.length > 0) { + returnStatus = 200; + returnSuccess = accountDbData.rows; + } else { + returnStatus = 404; + returnError = 'no account found for this user'; + } + } else { + returnStatus = 404; + returnError = 'email does not exist'; + } + return { + returnStatus, + returnSuccess, + returnError, + }; + }, + + /** + * Delete user + * @constructor + * @param {*} id - get user id + * @param {*} staff - get token details to check if staff or admin + */ + async deleteUser(id, staff) { + let returnStatus; let returnSuccess = ''; let returnError = ''; + // check the users table + const userDetails = await dbConnection + .dbConnect('SELECT id, type, isadmin FROM users WHERE email=$1', + [staff.email]); + const { type, isadmin } = userDetails.rows[0]; + + if (type === 'staff') { + const checkusers = await dbConnection + .dbConnect('SELECT type FROM users WHERE id=$1', [id]); + if (checkusers.rows.length > 0) { + if (checkusers.rows[0].type === 'client') { + const accountDbData = await dbConnection + .dbConnect('DELETE FROM users WHERE id=$1', [id]); + if (accountDbData.command === 'DELETE') { + returnStatus = 200; + returnSuccess = 'Account successfully deleted'; + } + } else { + returnStatus = 401; + returnError = 'you must be an admin to delete this staff'; + } + } else { + returnStatus = 404; + returnError = 'no account found'; + } + } else if (isadmin === true) { + const checkusers = await dbConnection + .dbConnect('SELECT type FROM users WHERE id=$1', [id]); + if (checkusers.rows.length > 0) { + const accountDbData = await dbConnection + .dbConnect('DELETE FROM users WHERE id=$1', [id]); + if (accountDbData.command === 'DELETE') { + returnStatus = 200; + returnSuccess = 'Account successfully deleted'; + } + } else { + returnStatus = 404; + returnError = 'no account found'; + } + } else { + returnStatus = 401; + returnError = 'You don\'t have permission to view this page'; + } + return { + returnStatus, + returnSuccess, + returnError, + }; + }, +}; + +export default UsersServices; diff --git a/server/v1/test/accounts.js b/server/v1/test/accounts.js index be5619f..e6904e4 100644 --- a/server/v1/test/accounts.js +++ b/server/v1/test/accounts.js @@ -1,180 +1,493 @@ -/* eslint-disable no-undef */ -import chaiHttp from 'chai-http'; -import chai, { expect } from 'chai'; - -import app from '../app'; - -chai.use(chaiHttp); - -describe('Testing Accounts Controller', () => { - describe('Testing accounts controller', () => { - it( - 'accounts should have all required details', - async () => { - const signinUrl = '/api/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'banka872@banka4.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .post('/api/v1/accounts') - .set('Authorization', `Bearer ${token}`) - .send({ - type: 'savings', - }); - expect(res.body).to.be.an('object'); - expect(res).to.have.status(201); - expect(res.body.data).to.have.property('id'); - expect(res.body.data).to.have.property('accountNumber'); - expect(res.body.data).to.have.property('createdOn'); - expect(res.body.data).to.have.property('owner'); - expect(res.body.data).to.have.property('type'); - expect(res.body.data).to.have.property('status'); - expect(res.body.data).to.have.property('balance'); - }, - ); - - it( - 'should not patch account if not staff or admin', - async () => { - const signinUrl = '/api/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'banka872@banka4.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .post('/api/v1/accounts') - .set('Authorization', `Bearer ${token}`) - .send({ - type: 'savings', - }); - const { accountnumber } = res.body.data; - const res1 = await chai.request(app) - .patch(`/api/v1/accounts/${accountnumber}`) - .set('Authorization', `Bearer ${token}`) - .send({ - status: 'dormant', - }); - expect(res1.body).to.be.an('object'); - expect(res1.body.status).to.equal(401); - expect(res1).to.have.status(401); - expect(res1.body.data).to.equal('Sorry you don\'t have permission to perform this task'); - }, - ); - - it( - 'should not delete account if not staff or admin', - async () => { - const signinUrl = '/api/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'banka872@banka4.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .post('/api/v1/accounts') - .set('Authorization', `Bearer ${token}`) - .send({ - type: 'savings', - }); - const { accountnumber } = res.body.data; - const res1 = await chai.request(app) - .delete(`/api/v1/accounts/${accountnumber}`) - .set('Authorization', `Bearer ${token}`) - .send(); - expect(res1.body).to.be.an('object'); - expect(res1.body.status).to.equal(401); - expect(res1).to.have.status(401); - expect(res1.body.data).to.equal('Sorry you don\'t have permission to perform this task'); - }, - ); - - it( - 'transaction should have these propertise', - async () => { - const signinUrl = '/api/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'banka872@banka4.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .get('/api/v1/accounts/3003801983/transactions') - .set('Authorization', `Bearer ${token}`) - .send(); - expect(res.body).to.be.an('object'); - expect(res).to.have.status(200); - expect(res.body.data[0]).to.have.property('id'); - expect(res.body.data[0]).to.have.property('createdon'); - expect(res.body.data[0]).to.have.property('type'); - expect(res.body.data[0]).to.have.property('accountnumber'); - expect(res.body.data[0]).to.have.property('cashier'); - expect(res.body.data[0]).to.have.property('amount'); - expect(res.body.data[0]).to.have.property('oldbalance'); - expect(res.body.data[0]).to.have.property('newbalance'); - }, - ); - - it( - 'get all accounts should have these propertise', - async () => { - const signinUrl = '/api/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'admin@banka.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .get('/api/v1/accounts') - .set('Authorization', `Bearer ${token}`) - .send(); - expect(res.body).to.be.an('object'); - expect(res).to.have.status(200); - expect(res.body.data[0]).to.have.property('id'); - expect(res.body.data[0]).to.have.property('email'); - expect(res.body.data[0]).to.have.property('firstname'); - expect(res.body.data[0]).to.have.property('lastname'); - expect(res.body.data[0]).to.have.property('accountnumber'); - expect(res.body.data[0]).to.have.property('createdon'); - expect(res.body.data[0]).to.have.property('owner'); - expect(res.body.data[0]).to.have.property('type'); - expect(res.body.data[0]).to.have.property('status'); - expect(res.body.data[0]).to.have.property('balance'); - }, - ); - - it( - 'should notify when account does not exist', - async () => { - const signinUrl = '/api/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'admin@banka.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .delete('/api/v1/accounts/883939378372') - .set('Authorization', `Bearer ${token}`) - .send(); - expect(res.body).to.be.an('object'); - expect(res.body.status).to.equal(404); - expect(res).to.have.status(404); - expect(res.body.data).to.equal('no account found'); - }, - ); - }); -}); +import chaiHttp from 'chai-http'; +import chai, { expect } from 'chai'; + +import app from '../app'; + +chai.use(chaiHttp); + +describe('Testing Accounts Controller', () => { + describe('Testing accounts controller', () => { + it( + 'accounts should have all required details', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/accounts') + .set('Authorization', `Bearer ${token}`) + .send({ + type: 'savings', + }); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(201); + expect(res.body.data).to.have.property('id'); + expect(res.body.data).to.have.property('accountNumber'); + expect(res.body.data).to.have.property('createdOn'); + expect(res.body.data).to.have.property('owner'); + expect(res.body.data).to.have.property('type'); + expect(res.body.data).to.have.property('status'); + expect(res.body.data).to.have.property('balance'); + }, + ); + + it( + 'admin or staff should see all accounts', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get('/api/v1/accounts') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(200); + expect(res.body.data[0]).to.have.property('id'); + expect(res.body.data[0]).to.have.property('email'); + expect(res.body.data[0]).to.have.property('firstname'); + expect(res.body.data[0]).to.have.property('lastname'); + expect(res.body.data[0]).to.have.property('accountnumber'); + expect(res.body.data[0]).to.have.property('createdon'); + expect(res.body.data[0]).to.have.property('owner'); + expect(res.body.data[0]).to.have.property('type'); + expect(res.body.data[0]).to.have.property('status'); + expect(res.body.data[0]).to.have.property('balance'); + }, + ); + + it( + 'admin or staff should see all accounts', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get('/api/v1/accounts') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(200); + expect(res.body.data[0]).to.have.property('id'); + expect(res.body.data[0]).to.have.property('email'); + expect(res.body.data[0]).to.have.property('firstname'); + expect(res.body.data[0]).to.have.property('lastname'); + expect(res.body.data[0]).to.have.property('accountnumber'); + expect(res.body.data[0]).to.have.property('createdon'); + expect(res.body.data[0]).to.have.property('owner'); + expect(res.body.data[0]).to.have.property('type'); + expect(res.body.data[0]).to.have.property('status'); + expect(res.body.data[0]).to.have.property('balance'); + }, + ); + + it( + 'admin or staff can pass limit to see all accounts', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get('/api/v1/accounts?limit=5') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(200); + expect(res.body.data[0]).to.have.property('id'); + expect(res.body.data[0]).to.have.property('email'); + expect(res.body.data[0]).to.have.property('firstname'); + expect(res.body.data[0]).to.have.property('lastname'); + expect(res.body.data[0]).to.have.property('accountnumber'); + expect(res.body.data[0]).to.have.property('createdon'); + expect(res.body.data[0]).to.have.property('owner'); + expect(res.body.data[0]).to.have.property('type'); + expect(res.body.data[0]).to.have.property('status'); + expect(res.body.data[0]).to.have.property('balance'); + }, + ); + + it( + 'admin or staff can pass status and limit to see all accounts', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get('/api/v1/accounts?status=active&limit=5') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body.data[0]).to.have.property('id'); + expect(res.body.data[0]).to.have.property('email'); + expect(res.body.data[0]).to.have.property('firstname'); + expect(res.body.data[0]).to.have.property('lastname'); + expect(res.body.data[0]).to.have.property('accountnumber'); + expect(res.body.data[0]).to.have.property('createdon'); + expect(res.body.data[0]).to.have.property('owner'); + expect(res.body.data[0]).to.have.property('type'); + expect(res.body.data[0]).to.have.property('status'); + expect(res.body.data[0]).to.have.property('balance'); + }, + ); + + it( + 'when query is not found', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get('/api/v1/accounts?status=engilsh&limit=5') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(404); + expect(res.body.data) + .to.equal('no account found'); + }, + ); + + it( + 'only admin should access all accounts', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get('/api/v1/accounts') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(401); + expect(res.body.data) + .to.equal('Sorry you don\'t have permission to perform this task'); + }, + ); + + it( + 'account type should only be savings or current', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/accounts') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(422); + expect(res.body.data) + .to.equal('account type can either be savings or current'); + }, + ); + + it( + 'should get specific account', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get(`/api/v1/accounts/${3003801983}`) + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(200); + expect(res.body.data).to.have.property('id'); + expect(res.body.data).to.have.property('email'); + expect(res.body.data).to.have.property('firstname'); + expect(res.body.data).to.have.property('lastname'); + expect(res.body.data).to.have.property('accountnumber'); + expect(res.body.data).to.have.property('createdon'); + expect(res.body.data).to.have.property('owner'); + expect(res.body.data).to.have.property('type'); + expect(res.body.data).to.have.property('status'); + expect(res.body.data).to.have.property('balance'); + }, + ); + + it( + 'when account does not have transaction', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get(`/api/v1/accounts/${3146859791}/transactions`) + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(404); + expect(res.body.data).to.equal('no transaction found'); + }, + ); + + it( + 'when specific account does not have transaction', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get(`/api/v1/accounts/${314685979881}`) + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(404); + expect(res.body.data).to.equal('no account found'); + }, + ); + + it( + 'should not patch account if not staff or admin', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/accounts') + .set('Authorization', `Bearer ${token}`) + .send({ + type: 'savings', + }); + const { accountnumber } = res.body.data; + const res1 = await chai.request(app) + .patch(`/api/v1/accounts/${accountnumber}`) + .set('Authorization', `Bearer ${token}`) + .send({ + status: 'dormant', + }); + expect(res1.body).to.be.an('object'); + expect(res1.body.status).to.equal(401); + expect(res1.body.data) + .to.equal('Sorry you don\'t have permission to perform this task'); + }, + ); + + it( + 'should patch account if staff or admin', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/accounts') + .set('Authorization', `Bearer ${token}`) + .send({ + type: 'savings', + }); + const { accountNumber } = res.body.data; + const res1 = await chai.request(app) + .patch(`/api/v1/accounts/${accountNumber}`) + .set('Authorization', `Bearer ${token}`) + .send({ + status: 'dormant', + }); + expect(res1.body).to.be.an('object'); + expect(res1.body.status).to.equal(200); + expect(res1.body.data).to.have.property('accountnumber'); + expect(res1.body.data).to.have.property('status'); + }, + ); + + it( + 'should not delete account if not staff or admin', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/accounts') + .set('Authorization', `Bearer ${token}`) + .send({ + type: 'savings', + }); + const { accountnumber } = res.body.data; + const res1 = await chai.request(app) + .delete(`/api/v1/accounts/${accountnumber}`) + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res1.body).to.be.an('object'); + expect(res1.body.status).to.equal(401); + expect(res1.body.data) + .to.equal('Sorry you don\'t have permission to perform this task'); + }, + ); + + it( + 'should delete account if staff or admin', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/accounts') + .set('Authorization', `Bearer ${token}`) + .send({ + type: 'savings', + }); + const { accountNumber } = res.body.data; + const res1 = await chai.request(app) + .delete(`/api/v1/accounts/${accountNumber}`) + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res1.body).to.be.an('object'); + expect(res1.status).to.equal(200); + expect(res1.body.data).to.equal('Account successfully deleted'); + }, + ); + + it( + 'transaction should have these propertise', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get('/api/v1/accounts/3003801983/transactions') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(200); + expect(res.body.data[0]).to.have.property('id'); + expect(res.body.data[0]).to.have.property('createdon'); + expect(res.body.data[0]).to.have.property('type'); + expect(res.body.data[0]).to.have.property('accountnumber'); + expect(res.body.data[0]).to.have.property('cashier'); + expect(res.body.data[0]).to.have.property('amount'); + expect(res.body.data[0]).to.have.property('oldbalance'); + expect(res.body.data[0]).to.have.property('newbalance'); + }, + ); + + it( + 'get all accounts should have these propertise', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get('/api/v1/accounts') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(200); + expect(res.body.data[0]).to.have.property('id'); + expect(res.body.data[0]).to.have.property('email'); + expect(res.body.data[0]).to.have.property('firstname'); + expect(res.body.data[0]).to.have.property('lastname'); + expect(res.body.data[0]).to.have.property('accountnumber'); + expect(res.body.data[0]).to.have.property('createdon'); + expect(res.body.data[0]).to.have.property('owner'); + expect(res.body.data[0]).to.have.property('type'); + expect(res.body.data[0]).to.have.property('status'); + expect(res.body.data[0]).to.have.property('balance'); + }, + ); + + it( + 'should notify when account does not exist', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .delete('/api/v1/accounts/883939378372') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(404); + expect(res.body.data).to.equal('no account found'); + }, + ); + }); +}); diff --git a/server/v1/test/signin.js b/server/v1/test/signin.js index a5ef6a5..cbfe7c6 100644 --- a/server/v1/test/signin.js +++ b/server/v1/test/signin.js @@ -1,104 +1,105 @@ -/* eslint-disable no-undef */ -import chaiHttp from 'chai-http'; -import chai, { expect } from 'chai'; - -import app from '../app'; - -chai.use(chaiHttp); - -describe('Testing User Controller', () => { - describe('Testing signin controller', () => { - const signinUrl = '/api/auth/signin'; - it( - 'should login when all the parameters are given', - async () => { - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'banka872@banka4.com', - password: 'passworD4@', - }); - expect(response.body.data).to.be.an('object'); - expect(response).to.have.status(201); - expect(response.body.data).to.have.property('id'); - expect(response.body.data).to.have.property('email'); - expect(response.body.data).to.have.property('firstName'); - expect(response.body.data).to.have.property('lastName'); - expect(response.body.data).to.have.property('token'); - }, - ); - - it( - 'should not signin a user when the email is missing', - async () => { - const response = await chai.request(app) - .post(signinUrl) - .send({ - password: 'passworD4@', - }); - expect(response.body).to.be.an('object'); - expect(response).to.have.status(422); - expect(response.body.data[0]).to.equal('invalid email address'); - }, - ); - - it( - 'should not signin a user when the email does not exist', - async () => { - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'banka85576@banka4.com', - password: 'passworD4@', - }); - expect(response.body).to.be.an('object'); - expect(response).to.have.status(404); - expect(response.body.data).to.equal('email does not exist'); - }, - ); - - it( - 'should not login a user when the password is missing', - async () => { - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'banka872@banka4.com', - }); - expect(response.body).to.be.an('object'); - expect(response).to.have.status(422); - expect(response.body.data[0]).to.equal('Password should contain atleast 8 characters, 1 uppercase letter, 1 lowercase letter, 1 number and 1 symbol or character'); - }, - ); - - it( - 'should not login a user when the password is incorrect', - async () => { - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'banka872@banka4.com', - password: 'passworD4@@', - }); - expect(response.body).to.be.an('object'); - expect(response).to.have.status(422); - expect(response.body.data).to.equal('incorrect password'); - }, - ); - - it( - 'should not register a user when the password do not meet requirement', - async () => { - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'banka872@banka4.com', - password: 'passworD4', - }); - expect(response.body).to.be.an('object'); - expect(response).to.have.status(422); - expect(response.body.data[0]).to.equal('Password should contain atleast 8 characters, 1 uppercase letter, 1 lowercase letter, 1 number and 1 symbol or character'); - }, - ); - }); -}); +import chaiHttp from 'chai-http'; +import chai, { expect } from 'chai'; + +import app from '../app'; + +chai.use(chaiHttp); + +describe('Testing User Controller', () => { + describe('Testing signin controller', () => { + const signinUrl = '/api/v1/auth/signin'; + it( + 'should login when all the parameters are given', + async () => { + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + expect(response.body).to.be.an('object'); + expect(response.body.status).to.equal(201); + expect(response.body.data).to.have.property('id'); + expect(response.body.data).to.have.property('email'); + expect(response.body.data).to.have.property('firstName'); + expect(response.body.data).to.have.property('lastName'); + expect(response.body.data).to.have.property('token'); + }, + ); + + it( + 'should not signin a user when the email is missing', + async () => { + const response = await chai.request(app) + .post(signinUrl) + .send({ + password: 'passworD4@', + }); + expect(response.body).to.be.an('object'); + expect(response.body.status).to.equal(422); + expect(response.body.data[0]).to.equal('invalid email address'); + }, + ); + + it( + 'should not signin a user when the email does not exist', + async () => { + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka85576@banka4.com', + password: 'passworD4@', + }); + expect(response.body).to.be.an('object'); + expect(response.body.status).to.equal(404); + expect(response.body.data).to.equal('email does not exist'); + }, + ); + + it( + 'should not login a user when the password is missing', + async () => { + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + }); + expect(response.body).to.be.an('object'); + expect(response.body.status).to.equal(422); + expect(response.body.data[0]) + .to.equal('Password should contain atleast 8 characters, 1 uppercase letter, 1 lowercase letter, 1 number and 1 symbol or character'); + }, + ); + + it( + 'should not login a user when the password is incorrect', + async () => { + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@@', + }); + expect(response.body).to.be.an('object'); + expect(response.body.status).to.equal(422); + expect(response.body.data).to.equal('incorrect password'); + }, + ); + + it( + 'should not register a user when the password do not meet requirement', + async () => { + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4', + }); + expect(response.body).to.be.an('object'); + expect(response.body.status).to.equal(422); + expect(response.body.data[0]) + .to.equal('Password should contain atleast 8 characters, 1 uppercase letter, 1 lowercase letter, 1 number and 1 symbol or character'); + }, + ); + }); +}); diff --git a/server/v1/test/signup.js b/server/v1/test/signup.js index 3ec5839..ac7acb1 100644 --- a/server/v1/test/signup.js +++ b/server/v1/test/signup.js @@ -1,198 +1,280 @@ -/* eslint-disable no-undef */ -import '@babel/polyfill'; -import chaiHttp from 'chai-http'; -import chai, { expect } from 'chai'; -import dbConnection from '../config/database'; - -import app from '../app'; - -chai.use(chaiHttp); - -describe('Testing User Controller', () => { - before(async () => { - await dbConnection.dbTesting('DELETE FROM users'); - await dbConnection - .dbConnect('INSERT into users(email, firstName, lastName, password, type, isAdmin) values($1, $2, $3, $4, $5, $6)', ['staff@banka.com', 'cavdy', 'ikenna', '$2a$10$CmmIst1.D3QjaWuafKbBaOuAFu0r9o7xxQY.0SMKiAN.h9z52a2y2', 'staff', false]); - await dbConnection - .dbConnect('INSERT into users(email, firstName, lastName, password, type, isAdmin) values($1, $2, $3, $4, $5, $6)', ['admin@banka.com', 'cavdy', 'ikenna', '$2a$10$CmmIst1.D3QjaWuafKbBaOuAFu0r9o7xxQY.0SMKiAN.h9z52a2y2', 'staff', true]); - }); - after(async () => { - await dbConnection.dbConnect('DELETE FROM users WHERE email=$1', ['admin@banka.com']); - }); - describe('Testing signup controller', () => { - const signupUrl = '/api/auth/signup'; - it( - 'should register a new user when all the parameters are given', - async () => { - const response = await chai.request(app) - .post(signupUrl) - .send({ - firstName: 'cavdy', - lastName: 'isaiah', - email: 'banka872@banka4.com', - password: 'passworD4@', - }); - expect(response).to.be.an('object'); - expect(response).to.have.status(201); - expect(response.body.data).to.have.property('id'); - expect(response.body.data).to.have.property('firstName'); - expect(response.body.data).to.have.property('lastName'); - expect(response.body.data).to.have.property('email'); - expect(response.body.data).to.have.property('token'); - }, - ); - - it( - 'should not register a user when the email already exist', - async () => { - const response = await chai.request(app) - .post(signupUrl) - .send({ - firstName: 'cavdy', - lastName: 'isaiah', - email: 'banka872@banka4.com', - password: 'passworD4@', - }); - expect(response).to.be.an('object'); - expect(response).to.have.status(409); - expect(response.body.data).to.equal('email already exist'); - }, - ); - - it( - 'should not register a user when the email is missing', - async () => { - const response = await chai.request(app) - .post(signupUrl) - .send({ - firstName: 'cavdy', - lastName: 'isaiah', - password: 'passworD4@', - }); - expect(response).to.be.an('object'); - expect(response).to.have.status(422); - expect(response.body.data[0]).to.equal('Email is required'); - }, - ); - - it( - 'should not register a user when the first name is missing', - async () => { - const response = await chai.request(app) - .post(signupUrl) - .send({ - lastName: 'isaiah', - email: 'banka873@banka4.com', - password: 'passworD4@', - }); - expect(response).to.be.an('object'); - expect(response).to.have.status(422); - expect(response.body.data[0]).to.equal('Firstname required'); - }, - ); - - it( - 'should not register a user when the last name is missing', - async () => { - const response = await chai.request(app) - .post(signupUrl) - .send({ - firstName: 'cavdy', - email: 'banka873@banka4.com', - password: 'passworD4@', - }); - expect(response).to.be.an('object'); - expect(response).to.have.status(422); - expect(response.body.data[0]).to.equal('Lastname required'); - }, - ); - - it( - 'should not register a user when the password is missing', - async () => { - const response = await chai.request(app) - .post(signupUrl) - .send({ - firstName: 'cavdy', - lastName: 'isaiah', - email: 'banka873@banka4.com', - }); - expect(response).to.be.an('object'); - expect(response).to.have.status(422); - expect(response.body.data[0]).to.equal('Password should contain atleast 8 characters, 1 uppercase letter, 1 lowercase letter, 1 number and 1 symbol or character'); - }, - ); - it( - 'should not register a user when the password do not meet requirement', - async () => { - const response = await chai.request(app) - .post(signupUrl) - .send({ - firstName: 'cavdy', - lastName: 'isaiah', - email: 'banka873@banka4.com', - password: 'passworD4', - }); - expect(response).to.be.an('object'); - expect(response).to.have.status(422); - expect(response.body.data[0]).to.equal('Password should contain atleast 8 characters, 1 uppercase letter, 1 lowercase letter, 1 number and 1 symbol or character'); - }, - ); - - it( - 'only admin can create staffs', - async () => { - const signinUrl = '/api/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'admin@banka.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .post('/api/auth/signup/addstaff') - .set('Authorization', `Bearer ${token}`) - .send({ - firstName: 'cavdy', - lastName: 'isaiah', - email: 'staff25@banka.com', - password: 'passworD4@', - }); - expect(res).to.be.an('object'); - expect(res).to.have.status(201); - expect(res.body.data).to.have.property('id'); - expect(res.body.data).to.have.property('firstName'); - expect(res.body.data).to.have.property('lastName'); - expect(res.body.data).to.have.property('email'); - expect(res.body.data).to.have.property('token'); - }, - ); - - it( - 'should not create staff if not admin', - async () => { - const signinUrl = '/api/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'banka872@banka4.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .post('/api/auth/signup/addstaff') - .set('Authorization', `Bearer ${token}`) - .send({ - firstName: 'cavdy', - lastName: 'isaiah', - email: 'staff8@banka.com', - password: 'passworD4@', - }); - expect(res).to.be.an('object'); - expect(res).to.have.status(401); - expect(res.body.data).to.equal('you must be an admin to create staffs'); - }, - ); - }); -}); +import '@babel/polyfill'; +import chaiHttp from 'chai-http'; +import chai, { expect } from 'chai'; +import dbConnection from '../config/database'; + +import app from '../app'; + +chai.use(chaiHttp); + +describe('Testing User Controller', () => { + before(async () => { + await dbConnection.dbTesting('DELETE FROM users'); + await dbConnection + .dbConnect('INSERT into users(email, firstName, lastName, password, type, isAdmin) values($1, $2, $3, $4, $5, $6)', + ['staff@banka.com', 'cavdy', 'ikenna', '$2a$10$CmmIst1.D3QjaWuafKbBaOuAFu0r9o7xxQY.0SMKiAN.h9z52a2y2', 'staff', false]); + await dbConnection + .dbConnect('INSERT into users(email, firstName, lastName, password, type, isAdmin) values($1, $2, $3, $4, $5, $6)', + ['admin@banka.com', 'cavdy', 'ikenna', '$2a$10$CmmIst1.D3QjaWuafKbBaOuAFu0r9o7xxQY.0SMKiAN.h9z52a2y2', 'client', true]); + await dbConnection + .dbConnect('INSERT into users(email, firstName, lastName, password, type, isAdmin) values($1, $2, $3, $4, $5, $6)', + ['deleteguy@banka.com', 'cavdy', 'ikenna', '$2a$10$CmmIst1.D3QjaWuafKbBaOuAFu0r9o7xxQY.0SMKiAN.h9z52a2y2', 'staff', true]); + await dbConnection + .dbConnect('INSERT into users(email, firstName, lastName, password, type, isAdmin) values($1, $2, $3, $4, $5, $6)', + ['deleteguy2@banka.com', 'cavdy', 'ikenna', '$2a$10$CmmIst1.D3QjaWuafKbBaOuAFu0r9o7xxQY.0SMKiAN.h9z52a2y2', 'client', true]); + }); + after(async () => { + await dbConnection + .dbConnect('DELETE FROM users WHERE email=$1', ['admin@banka.com']); + }); + describe('Testing signup controller', () => { + const signupUrl = '/api/v1/auth/signup'; + it( + 'should register a new user when all the parameters are given', + async () => { + const response = await chai.request(app) + .post(signupUrl) + .send({ + firstName: 'cavdy', + lastName: 'isaiah', + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + expect(response).to.be.an('object'); + expect(response).to.have.status(201); + expect(response.body.data).to.have.property('id'); + expect(response.body.data).to.have.property('firstName'); + expect(response.body.data).to.have.property('lastName'); + expect(response.body.data).to.have.property('email'); + expect(response.body.data).to.have.property('token'); + }, + ); + + it( + 'should not register a user when the email already exist', + async () => { + const response = await chai.request(app) + .post(signupUrl) + .send({ + firstName: 'cavdy', + lastName: 'isaiah', + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + expect(response).to.be.an('object'); + expect(response).to.have.status(409); + expect(response.body.data).to.equal('email already exist'); + }, + ); + + it( + 'should not create a staff when the email already exist', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/auth/signup/addstaff') + .set('Authorization', `Bearer ${token}`) + .send({ + firstName: 'cavdy', + lastName: 'isaiah', + email: 'banka872@banka4.com', + password: 'passworD4@', + type: 'staff', + isAdmin: false, + }); + expect(res).to.be.an('object'); + expect(res.body.status).to.equal(409); + expect(res.body.data).to.equal('email already exist'); + }, + ); + + it( + 'should not register when all fields are missing', + async () => { + const response = await chai.request(app) + .post(signupUrl) + .send(); + expect(response).to.be.an('object'); + expect(response).to.have.status(422); + expect(response.body.data[0]).to.equal('Email is required'); + expect(response.body.data[1]).to.equal('Firstname required'); + expect(response.body.data[2]).to.equal('Lastname required'); + expect(response.body.data[3]) + .to.equal('Password should contain atleast 8 characters, 1 uppercase letter, 1 lowercase letter, 1 number and 1 symbol or character'); + }, + ); + + it( + 'should not create staff when all fields are missing', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/auth/signup/addstaff') + .set('Authorization', `Bearer ${token}`) + .send({ + type: 'staff', + isAdmin: false, + }); + expect(res).to.be.an('object'); + expect(res.body.status).to.equal(422); + expect(res.body.data[0]).to.equal('Email is required'); + expect(res.body.data[1]).to.equal('Firstname required'); + expect(res.body.data[2]).to.equal('Lastname required'); + expect(res.body.data[3]) + .to.equal('Password should contain atleast 8 characters, 1 uppercase letter, 1 lowercase letter, 1 number and 1 symbol or character'); + }, + ); + + it( + 'should not register a user when the email is missing', + async () => { + const response = await chai.request(app) + .post(signupUrl) + .send({ + firstName: 'cavdy', + lastName: 'isaiah', + password: 'passworD4@', + }); + expect(response).to.be.an('object'); + expect(response).to.have.status(422); + expect(response.body.data[0]).to.equal('Email is required'); + }, + ); + + it( + 'should not register a user when the first name is missing', + async () => { + const response = await chai.request(app) + .post(signupUrl) + .send({ + lastName: 'isaiah', + email: 'banka873@banka4.com', + password: 'passworD4@', + }); + expect(response).to.be.an('object'); + expect(response).to.have.status(422); + expect(response.body.data[0]).to.equal('Firstname required'); + }, + ); + + it( + 'should not register a user when the last name is missing', + async () => { + const response = await chai.request(app) + .post(signupUrl) + .send({ + firstName: 'cavdy', + email: 'banka873@banka4.com', + password: 'passworD4@', + }); + expect(response).to.be.an('object'); + expect(response).to.have.status(422); + expect(response.body.data[0]).to.equal('Lastname required'); + }, + ); + + it( + 'should not register a user when the password is missing', + async () => { + const response = await chai.request(app) + .post(signupUrl) + .send({ + firstName: 'cavdy', + lastName: 'isaiah', + email: 'banka873@banka4.com', + }); + expect(response).to.be.an('object'); + expect(response).to.have.status(422); + expect(response.body.data[0]) + .to.equal('Password should contain atleast 8 characters, 1 uppercase letter, 1 lowercase letter, 1 number and 1 symbol or character'); + }, + ); + it( + 'should not register a user when the password do not meet requirement', + async () => { + const response = await chai.request(app) + .post(signupUrl) + .send({ + firstName: 'cavdy', + lastName: 'isaiah', + email: 'banka873@banka4.com', + password: 'passworD4', + }); + expect(response).to.be.an('object'); + expect(response).to.have.status(422); + expect(response.body.data[0]) + .to.equal('Password should contain atleast 8 characters, 1 uppercase letter, 1 lowercase letter, 1 number and 1 symbol or character'); + }, + ); + + it( + 'only admin can create staffs', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/auth/signup/addstaff') + .set('Authorization', `Bearer ${token}`) + .send({ + firstName: 'cavdy', + lastName: 'isaiah', + email: 'staff25@banka.com', + password: 'passworD4@', + }); + expect(res).to.be.an('object'); + expect(res).to.have.status(201); + expect(res.body.data).to.have.property('id'); + expect(res.body.data).to.have.property('firstName'); + expect(res.body.data).to.have.property('lastName'); + expect(res.body.data).to.have.property('email'); + expect(res.body.data).to.have.property('token'); + }, + ); + + it( + 'should not create staff if not admin', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/auth/signup/addstaff') + .set('Authorization', `Bearer ${token}`) + .send({ + firstName: 'cavdy', + lastName: 'isaiah', + email: 'staff8@banka.com', + password: 'passworD4@', + }); + expect(res).to.be.an('object'); + expect(res).to.have.status(401); + expect(res.body.data).to.equal('you must be an admin to create staffs'); + }, + ); + }); +}); diff --git a/server/v1/test/tests.js b/server/v1/test/tests.js index b81e147..67ccbd6 100644 --- a/server/v1/test/tests.js +++ b/server/v1/test/tests.js @@ -1,5 +1,26 @@ -import './accounts'; -import './signin'; -import './transactions'; -import './users'; -import './signup'; +import './accounts'; +import './signin'; +import './transactions'; +import './users'; +import './signup'; + +import chaiHttp from 'chai-http'; +import chai, { expect } from 'chai'; + +import app from '../app'; + +chai.use(chaiHttp); + +describe('Testing Accounts Controller', () => { + describe('Testing accounts controller', () => { + it( + 'accounts should have all required details', + async () => { + const res = await chai.request(app) + .get('/') + .send(); + expect(res.text).to.equal('welcome to Banka API'); + }, + ); + }); +}); diff --git a/server/v1/test/transactions.js b/server/v1/test/transactions.js index d331009..95cb59f 100644 --- a/server/v1/test/transactions.js +++ b/server/v1/test/transactions.js @@ -1,113 +1,287 @@ -/* eslint-disable no-undef */ -import chaiHttp from 'chai-http'; -import chai, { expect } from 'chai'; - -import app from '../app'; - -chai.use(chaiHttp); - -describe('Testing Transactions Controller', () => { - describe('Testing transactions controller', () => { - it( - 'transactions should have all required propertise', - async () => { - const signinUrl = '/api/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'admin@banka.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .post('/api/v1/transactions/3003801983/debit') - .set('Authorization', `Bearer ${token}`) - .send({ - amount: 500, - }); - expect(res.body).to.be.an('object'); - expect(res).to.have.status(201); - expect(res.body.data).to.have.property('transactionId'); - expect(res.body.data).to.have.property('accountNumber'); - expect(res.body.data).to.have.property('cashier'); - expect(res.body.data).to.have.property('amount'); - expect(res.body.data).to.have.property('transactionType'); - expect(res.body.data).to.have.property('accountBalance'); - }, - ); - - it( - 'only admin and staffs should perform debit transaction', - async () => { - const signinUrl = '/api/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'banka872@banka4.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .post('/api/v1/transactions/3003801983/debit') - .set('Authorization', `Bearer ${token}`) - .send({ - amount: 500, - }); - expect(res.body).to.be.an('object'); - expect(res).to.have.status(401); - expect(res.body.data).to.equal('You must be a staff or admin to perform this transaction'); - }, - ); - - it( - 'transaction should have these propertise', - async () => { - const signinUrl = '/api/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'banka872@banka4.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .get('/api/v1/transactions/4') - .set('Authorization', `Bearer ${token}`) - .send(); - expect(res.body).to.be.an('object'); - expect(res).to.have.status(200); - expect(res.body.data[0]).to.have.property('id'); - expect(res.body.data[0]).to.have.property('createdon'); - expect(res.body.data[0]).to.have.property('type'); - expect(res.body.data[0]).to.have.property('accountnumber'); - expect(res.body.data[0]).to.have.property('cashier'); - expect(res.body.data[0]).to.have.property('amount'); - expect(res.body.data[0]).to.have.property('oldbalance'); - expect(res.body.data[0]).to.have.property('newbalance'); - }, - ); - - it( - 'only admin and staffs should perform credit transaction', - async () => { - const signinUrl = '/api/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'banka872@banka4.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .post('/api/v1/transactions/3003801983/credit') - .set('Authorization', `Bearer ${token}`) - .send({ - amount: 500, - }); - expect(res.body).to.be.an('object'); - expect(res).to.have.status(401); - expect(res.body.data).to.equal('You must be a staff or admin to perform this transaction'); - }, - ); - }); -}); +import chaiHttp from 'chai-http'; +import chai, { expect } from 'chai'; + +import app from '../app'; + +chai.use(chaiHttp); + +describe('Testing Transactions Controller', () => { + describe('Testing transactions controller', () => { + it( + 'transactions should have all required propertise', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/transactions/3003801983/credit') + .set('Authorization', `Bearer ${token}`) + .send({ + amount: 500, + }); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(201); + expect(res.body.data).to.have.property('transactionId'); + expect(res.body.data).to.have.property('accountNumber'); + expect(res.body.data).to.have.property('cashier'); + expect(res.body.data).to.have.property('amount'); + expect(res.body.data).to.have.property('transactionType'); + expect(res.body.data).to.have.property('accountBalance'); + }, + ); + + it( + 'only admin and staffs should perform debit transaction', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/transactions/3003801983/credit') + .set('Authorization', `Bearer ${token}`) + .send({ + amount: 1000, + }); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(401); + expect(res.body.data) + .to.equal('You must be a staff or admin to perform this transaction'); + }, + ); + + it( + 'should not perform debit transaction when on zero balance', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/transactions/3404704124/debit') + .set('Authorization', `Bearer ${token}`) + .send({ + amount: 500, + }); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(422); + expect(res.body.data) + .to.equal('Sorry this account is very low and can\'t be debited'); + }, + ); + + it( + 'admin and staff can debit account', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/transactions/3003801983/debit') + .set('Authorization', `Bearer ${token}`) + .send({ + amount: 500, + }); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(201); + expect(res.body.data).to.have.property('transactionId'); + expect(res.body.data).to.have.property('accountNumber'); + expect(res.body.data).to.have.property('amount'); + expect(res.body.data).to.have.property('cashier'); + expect(res.body.data).to.have.property('transactionType'); + expect(res.body.data).to.have.property('accountBalance'); + }, + ); + + it( + 'transaction should have these propertise', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get('/api/v1/transactions/4') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(200); + expect(res.body.data[0]).to.have.property('id'); + expect(res.body.data[0]).to.have.property('createdon'); + expect(res.body.data[0]).to.have.property('type'); + expect(res.body.data[0]).to.have.property('accountnumber'); + expect(res.body.data[0]).to.have.property('cashier'); + expect(res.body.data[0]).to.have.property('amount'); + expect(res.body.data[0]).to.have.property('oldbalance'); + expect(res.body.data[0]).to.have.property('newbalance'); + }, + ); + + it( + 'only admin and staffs should perform credit transaction', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/transactions/3003801983/credit') + .set('Authorization', `Bearer ${token}`) + .send({ + amount: 500, + }); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(401); + expect(res.body.data) + .to.equal('You must be a staff or admin to perform this transaction'); + }, + ); + + it( + 'only admin and staffs should perform debit transaction', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/transactions/3003801983/debit') + .set('Authorization', `Bearer ${token}`) + .send({ + amount: 500, + }); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(401); + expect(res.body.data) + .to.equal('You must be a staff or admin to perform this transaction'); + }, + ); + + it( + 'should not debit when not number', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/transactions/3003801983/debit') + .set('Authorization', `Bearer ${token}`) + .send({ + amount: 'fffff', + }); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(422); + expect(res.body.data) + .to.equal('please numbers only'); + }, + ); + + it( + 'should not credit when not number', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/transactions/3003801983/credit') + .set('Authorization', `Bearer ${token}`) + .send({ + amount: 'fffff', + }); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(422); + expect(res.body.data) + .to.equal('please numbers only'); + }, + ); + + it( + 'admin and staffs can perform credit transaction', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .post('/api/v1/transactions/3003801983/credit') + .set('Authorization', `Bearer ${token}`) + .send({ + amount: 500, + }); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(201); + expect(res.body.data).to.have.property('transactionId'); + expect(res.body.data).to.have.property('accountNumber'); + expect(res.body.data).to.have.property('amount'); + expect(res.body.data).to.have.property('cashier'); + expect(res.body.data).to.have.property('transactionType'); + expect(res.body.data).to.have.property('accountBalance'); + }, + ); + + it( + 'check if transaction id exist', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get('/api/v1/transactions/6000') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(404); + expect(res.body.data).to.equal('no transaction found'); + }, + ); + }); +}); diff --git a/server/v1/test/users.js b/server/v1/test/users.js index 72948ff..9a6cb6a 100644 --- a/server/v1/test/users.js +++ b/server/v1/test/users.js @@ -1,101 +1,348 @@ -/* eslint-disable no-undef */ -import chaiHttp from 'chai-http'; -import chai, { expect } from 'chai'; - -import app from '../app'; - -chai.use(chaiHttp); - -describe('Testing All Users Controller', () => { - describe('Testing all accounts controller', () => { - it( - 'users should have all required details', - async () => { - const signinUrl = '/api/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'admin@banka.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .get('/api/v1/users') - .set('Authorization', `Bearer ${token}`) - .send(); - expect(res.body).to.be.an('object'); - expect(res).to.have.status(200); - expect(res.body.data[0]).to.have.property('id'); - expect(res.body.data[0]).to.have.property('firstname'); - expect(res.body.data[0]).to.have.property('lastname'); - expect(res.body.data[0]).to.have.property('email'); - expect(res.body.data[0]).to.have.property('password'); - expect(res.body.data[0]).to.have.property('type'); - expect(res.body.data[0]).to.have.property('isadmin'); - }, - ); - - it( - 'should not see all users if not admin or staff', - async () => { - const signinUrl = '/api/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'banka872@banka4.com', - password: 'passworD4@', - }); - const { token } = response.body.data; - const res = await chai.request(app) - .get('/api/v1/users') - .set('Authorization', `Bearer ${token}`) - .send(); - expect(res.body).to.be.an('object'); - expect(res).to.have.status(401); - expect(res.body.data).to.equal('You don\'t have permission to view this page'); - }, - ); - - it( - 'only staffs and admin can delete users', - async () => { - const signinUrl = '/api/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'banka872@banka4.com', - password: 'passworD4@', - }); - const { id, token } = response.body.data; - const res = await chai.request(app) - .delete(`/api/v1/users/${id}`) - .set('Authorization', `Bearer ${token}`) - .send(); - expect(res.body).to.be.an('object'); - expect(res).to.have.status(401); - expect(res.body.data).to.equal('You don\'t have permission to view this page'); - }, - ); - - it( - 'only admin can delete any users', - async () => { - const signinUrl = '/api/auth/signin'; - const response = await chai.request(app) - .post(signinUrl) - .send({ - email: 'staff@banka.com', - password: 'passworD4@', - }); - const { id, token } = response.body.data; - const res = await chai.request(app) - .delete(`/api/v1/users/${id}`) - .set('Authorization', `Bearer ${token}`) - .send(); - expect(res.body).to.be.an('object'); - expect(res).to.have.status(401); - expect(res.body.data).to.equal('you must be an admin to delete this staff'); - }, - ); - }); -}); +import chaiHttp from 'chai-http'; +import chai, { expect } from 'chai'; + +import app from '../app'; + +chai.use(chaiHttp); + +describe('Testing All Users Controller', () => { + describe('Testing all accounts controller', () => { + it( + 'users should have all required details', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get('/api/v1/users') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res).to.have.status(200); + expect(res.body.data[0]).to.have.property('id'); + expect(res.body.data[0]).to.have.property('firstname'); + expect(res.body.data[0]).to.have.property('lastname'); + expect(res.body.data[0]).to.have.property('email'); + expect(res.body.data[0]).to.have.property('password'); + expect(res.body.data[0]).to.have.property('type'); + expect(res.body.data[0]).to.have.property('isadmin'); + }, + ); + + it( + 'when limit query is passed', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get('/api/v1/users?limit=10') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res).to.have.status(200); + expect(res.body.data[0]).to.have.property('id'); + expect(res.body.data[0]).to.have.property('firstname'); + expect(res.body.data[0]).to.have.property('lastname'); + expect(res.body.data[0]).to.have.property('email'); + expect(res.body.data[0]).to.have.property('password'); + expect(res.body.data[0]).to.have.property('type'); + expect(res.body.data[0]).to.have.property('isadmin'); + }, + ); + + it( + 'check if email does not exist', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get('/api/v1/users/banka872@ban.com/accounts') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(404); + expect(res.body.data).to.equal('email does not exist'); + }, + ); + + it( + 'only admin or staff to see all users', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get('/api/v1/users') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(401); + expect(res.body.data) + .to.equal('You don\'t have permission to view this page'); + }, + ); + + it( + 'check if email does not have a bank account', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get('/api/v1/users/deleteguy2@banka.com/accounts') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(404); + expect(res.body.data).to.equal('no account found for this user'); + }, + ); + + it( + 'get users account by email', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get('/api/v1/users') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res).to.have.status(200); + expect(res.body.data[0]).to.have.property('id'); + expect(res.body.data[0]).to.have.property('firstname'); + expect(res.body.data[0]).to.have.property('lastname'); + expect(res.body.data[0]).to.have.property('email'); + expect(res.body.data[0]).to.have.property('password'); + expect(res.body.data[0]).to.have.property('type'); + expect(res.body.data[0]).to.have.property('isadmin'); + }, + ); + + it( + 'if no token was passed', + async () => { + const res = await chai.request(app) + .get('/api/v1/users') + .send(); + expect(res).to.have.status(403); + }, + ); + + it( + 'if wrong token was passed', + async () => { + const res = await chai.request(app) + .get('/api/v1/users') + .set('Authorization', 'Bearer ujhhs88s88s8888') + .send(); + expect(res.status).to.equal(403); + }, + ); + + it( + 'should not see all users if not admin or staff', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get('/api/v1/users/banka872@banka4.com/accounts') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(200); + expect(res.body.data[0]).to.have.property('id'); + expect(res.body.data[0]).to.have.property('email'); + expect(res.body.data[0]).to.have.property('firstname'); + expect(res.body.data[0]).to.have.property('lastname'); + expect(res.body.data[0]).to.have.property('accountnumber'); + expect(res.body.data[0]).to.have.property('createdon'); + expect(res.body.data[0]).to.have.property('owner'); + expect(res.body.data[0]).to.have.property('type'); + expect(res.body.data[0]).to.have.property('status'); + expect(res.body.data[0]).to.have.property('balance'); + }, + ); + + it( + 'only staffs and admin can delete users', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'banka872@banka4.com', + password: 'passworD4@', + }); + const { id, token } = response.body.data; + const res = await chai.request(app) + .delete(`/api/v1/users/${id}`) + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res).to.have.status(401); + expect(res.body.data) + .to.equal('You don\'t have permission to view this page'); + }, + ); + + it( + 'only admin can delete any users', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'staff@banka.com', + password: 'passworD4@', + }); + const { id, token } = response.body.data; + const res = await chai.request(app) + .delete(`/api/v1/users/${id}`) + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res).to.have.status(401); + expect(res.body.data) + .to.equal('you must be an admin to delete this staff'); + }, + ); + + it( + 'only admin can delete all users', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const res = await chai.request(app) + .post(signinUrl) + .send({ + email: 'deleteguy@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const { id } = res.body.data; + const res1 = await chai.request(app) + .delete(`/api/v1/users/${id}`) + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res1.body).to.be.an('object'); + expect(res1.body.status).to.equal(200); + expect(res1.body.data).to.equal('Account successfully deleted'); + }, + ); + + it( + 'staffs can delete all users that is not a staff or admin', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'staff@banka.com', + password: 'passworD4@', + }); + const res = await chai.request(app) + .post(signinUrl) + .send({ + email: 'deleteguy2@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const { id } = res.body.data; + const res1 = await chai.request(app) + .delete(`/api/v1/users/${id}`) + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res1.body).to.be.an('object'); + expect(res1.body.status).to.equal(200); + expect(res1.body.data).to.equal('Account successfully deleted'); + }, + ); + + it( + 'check if user does not exist as an admin', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .delete('/api/v1/users/6000') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(404); + expect(res.body.data).to.equal('no account found'); + }, + ); + + it( + 'check if user does not exist as a staff', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'staff@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .delete('/api/v1/users/6000') + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res.body).to.be.an('object'); + expect(res.body.status).to.equal(404); + expect(res.body.data).to.equal('no account found'); + }, + ); + }); +});