From 17bc9494c06c7c65bf268d5db334c8682d7b0d8a Mon Sep 17 00:00:00 2001 From: cavdy Date: Fri, 26 Apr 2019 14:44:34 +0100 Subject: [PATCH 1/4] bug(Account status accepts any value):Account status accepts any value Account is accepting any value as account status [Starts #165635593] --- server/v1/config/account.sql | 27 - server/v1/config/database.js | 20 - server/v1/config/transaction.sql | 28 - server/v1/config/user.sql | 27 - server/v1/helper/statusHelper.js | 6 + server/v1/middleware/jwt.js | 140 ++- server/v1/model/Transaction.js | 10 - .../model/{CreateAccount.js => accounts.js} | 0 server/v1/services/accounts.js | 35 +- server/v1/services/transaction.js | 2 +- server/v1/test/accounts.js | 1046 +++++++++-------- server/v1/test/signup.js | 2 +- 12 files changed, 659 insertions(+), 684 deletions(-) delete mode 100644 server/v1/config/account.sql delete mode 100644 server/v1/config/transaction.sql delete mode 100644 server/v1/config/user.sql delete mode 100644 server/v1/model/Transaction.js rename server/v1/model/{CreateAccount.js => accounts.js} (100%) diff --git a/server/v1/config/account.sql b/server/v1/config/account.sql deleted file mode 100644 index 9099c28..0000000 --- a/server/v1/config/account.sql +++ /dev/null @@ -1,27 +0,0 @@ --- Accounts SQL query - --- create accounts table -CREATE TABLE 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 -); - --- select all from accounts table -SELECT * FROM accounts LIMIT 10 - --- select account number fro accounts -SELECT accountNumber FROM accounts WHERE accountNumber=$1, ['accountNumber'] - --- insert into accounts table -INSERT into accounts values($1), ['value'] - --- delete from accounts table -DELETE FROM accounts; \ No newline at end of file diff --git a/server/v1/config/database.js b/server/v1/config/database.js index b6b0fbf..6dec7df 100644 --- a/server/v1/config/database.js +++ b/server/v1/config/database.js @@ -36,26 +36,6 @@ const dbConnection = { 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/transaction.sql b/server/v1/config/transaction.sql deleted file mode 100644 index fbabb50..0000000 --- a/server/v1/config/transaction.sql +++ /dev/null @@ -1,28 +0,0 @@ --- Transactions SQL query - --- create transactions table -CREATE TABLE transactions ( - id SERIAL PRIMARY KEY UNIQUE, - createdOn VARCHAR(40), - type VARCHAR(10), - accountNumber BIGINT, - cashier INTEGER, - amount FLOAT, - oldBalance FLOAT, - newBalance FLOAT -); - --- select all from transactions table -SELECT * FROM transactions LIMIT 10 - --- select account number fro transactions -SELECT accountNumber FROM transactions WHERE accountNumber=$1, ['accountNumber'] - --- insert into transactions table -INSERT into transactions values($1), ['value'] - --- update -UPDATE transactions SET balance=$1 WHERE accountnumber=$2, [newBalance, accountNumber] - --- delete from transactions table -DELETE FROM transactions; \ No newline at end of file diff --git a/server/v1/config/user.sql b/server/v1/config/user.sql deleted file mode 100644 index 22a415d..0000000 --- a/server/v1/config/user.sql +++ /dev/null @@ -1,27 +0,0 @@ --- Users SQL query - --- create users table -CREATE TABLE users ( - id SERIAL PRIMARY KEY UNIQUE, - email VARCHAR(80) UNIQUE, - firstName VARCHAR(20), - lastName VARCHAR(20), - password VARCHAR(80), - type VARCHAR(10), - isAdmin BOOLEAN -); - --- select all from users table -SELECT * FROM users LIMIT 10 - --- select email fro users -SELECT email FROM users WHERE email=$1, ['email'] - --- insert into users table -INSERT into users values($1), ['value'] - --- delete from users table -DELETE FROM users; - --- admin -INSERT into users(email, firstName, lastName, password, type, isAdmin) values('admin@banka.com', 'cavdy', 'ikenna', '$2a$10$CmmIst1.D3QjaWuafKbBaOuAFu0r9o7xxQY.0SMKiAN.h9z52a2y2', 'staff', true) \ No newline at end of file diff --git a/server/v1/helper/statusHelper.js b/server/v1/helper/statusHelper.js index a4b8df7..9858ab2 100644 --- a/server/v1/helper/statusHelper.js +++ b/server/v1/helper/statusHelper.js @@ -22,6 +22,12 @@ const statusHelper = { status: 409, data: error, }); + } else if (status === 403) { // conflict + res.status(403); + return res.json({ + status: 403, + data: error, + }); } else if (status === 201) { // created res.status(201); return res.json({ diff --git a/server/v1/middleware/jwt.js b/server/v1/middleware/jwt.js index 47ee931..2363b21 100644 --- a/server/v1/middleware/jwt.js +++ b/server/v1/middleware/jwt.js @@ -1,62 +1,78 @@ -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; +import jwt from 'jsonwebtoken'; +import dotenv from 'dotenv'; +import statusHelper from '../helper/statusHelper'; + +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) + return statusHelper + .statusHelper(req, + res, + 403, + 'you are not logged in', + ''); + } + }, + + /** + * 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 statusHelper + .statusHelper(req, + res, + 403, + 'you are not logged in', + ''); + } + 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 statusHelper + .statusHelper(req, + res, + 403, + 'invalid token', + ''); + } + req.authorizedData = authorizedData; + return next(); + }); + }, +}; + +export default jwtMiddleware; diff --git a/server/v1/model/Transaction.js b/server/v1/model/Transaction.js deleted file mode 100644 index 6538568..0000000 --- a/server/v1/model/Transaction.js +++ /dev/null @@ -1,10 +0,0 @@ -export default class Transaction { - constructor() { - this.transactionId = null; - this.accountNumber = null; - this.amount = null; - this.cashier = null; // cashier id - this.transactionType = null; // credit or debit - this.accountBalance = null; - } -} diff --git a/server/v1/model/CreateAccount.js b/server/v1/model/accounts.js similarity index 100% rename from server/v1/model/CreateAccount.js rename to server/v1/model/accounts.js diff --git a/server/v1/services/accounts.js b/server/v1/services/accounts.js index dfb3d28..ebf8519 100644 --- a/server/v1/services/accounts.js +++ b/server/v1/services/accounts.js @@ -1,5 +1,5 @@ import dbConnection from '../config/database'; -import AccountModel from '../model/CreateAccount'; +import AccountModel from '../model/accounts'; const CreateAccountService = { /** @@ -175,21 +175,26 @@ const CreateAccountService = { 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 }; + if (accountUpdate.status === 'active' || accountUpdate.status === 'dormant') { + 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 RETURNING accountnumber, status', + [accountUpdate.status, accountNumber]); + if (updateAccount.command === 'UPDATE') { + const { accountnumber, status } = updateAccount.rows[0]; + returnStatus = 200; + returnSuccess = { accountnumber, status }; + } + } else { + returnStatus = 404; + returnError = 'account not found'; } + } else { + returnStatus = 422; + returnError = 'account status can only be active or dormant'; } } else { returnStatus = 401; diff --git a/server/v1/services/transaction.js b/server/v1/services/transaction.js index b7d055e..3c22b0f 100644 --- a/server/v1/services/transaction.js +++ b/server/v1/services/transaction.js @@ -1,6 +1,6 @@ /* eslint-disable no-param-reassign */ import dbConnection from '../config/database'; -import TransactionModel from '../model/Transaction'; +import TransactionModel from '../model/transaction'; const TransactionService = { diff --git a/server/v1/test/accounts.js b/server/v1/test/accounts.js index e6904e4..9e6b1de 100644 --- a/server/v1/test/accounts.js +++ b/server/v1/test/accounts.js @@ -1,493 +1,553 @@ -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'); - }, - ); - }); -}); +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 patch account if not active or dormant', + 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}77`) + .set('Authorization', `Bearer ${token}`) + .send({ + status: 'dormants', + }); + expect(res1.body).to.be.an('object'); + expect(res1.body.status).to.equal(422); + expect(res1.body.data).to.equal('account status can only be active or dormant'); + }, + ); + + it( + 'when account 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) + .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}77`) + .set('Authorization', `Bearer ${token}`) + .send({ + status: 'dormant', + }); + expect(res1.body).to.be.an('object'); + expect(res1.body.status).to.equal(404); + expect(res1.body.data).to.equal('account not found'); + }, + ); + + 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/signup.js b/server/v1/test/signup.js index 6f9ab52..cff88ac 100644 --- a/server/v1/test/signup.js +++ b/server/v1/test/signup.js @@ -12,7 +12,7 @@ chai.use(chaiHttp); describe('Testing User Controller', () => { before(async () => { - await dbConnection.dbTesting('DELETE FROM users'); + await dbConnection.dbConnect('DELETE FROM users'); 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]); From f40055b59a1e54f2ca089373ed0423d8fb402641 Mon Sep 17 00:00:00 2001 From: cavdy Date: Fri, 26 Apr 2019 16:42:45 +0100 Subject: [PATCH 2/4] bug(Credit and debit transactions accepts strings):Credit and debit transactions accepts strings Credit and debit transactions accepts strings and other values [Starts #165638356] --- server/swagger.json | 6 +++--- server/v1/model/transaction.js | 10 ++++++++++ server/v1/services/accounts.js | 2 +- server/v1/services/transaction.js | 8 ++------ 4 files changed, 16 insertions(+), 10 deletions(-) create mode 100644 server/v1/model/transaction.js diff --git a/server/swagger.json b/server/swagger.json index edfda99..c6878c9 100644 --- a/server/swagger.json +++ b/server/swagger.json @@ -14,7 +14,7 @@ "v1/auth/signup": { "post": { "tags": [ - "Signup" + "Auth" ], "summary": "Users can signup", "description": "this endpoint uses get request to create users", @@ -65,7 +65,7 @@ "v1/auth/signup/addstaff": { "post": { "tags": [ - "Signup" + "Auth" ], "summary": "Admin can signup staffs", "description": "this endpoint uses get request to create users", @@ -135,7 +135,7 @@ "v1/auth/signin": { "post": { "tags": [ - "Signin" + "Auth" ], "summary": "Users can signup", "description": "this endpoint uses get request to create users", diff --git a/server/v1/model/transaction.js b/server/v1/model/transaction.js new file mode 100644 index 0000000..6538568 --- /dev/null +++ b/server/v1/model/transaction.js @@ -0,0 +1,10 @@ +export default class Transaction { + constructor() { + this.transactionId = null; + this.accountNumber = null; + this.amount = null; + this.cashier = null; // cashier id + this.transactionType = null; // credit or debit + this.accountBalance = null; + } +} diff --git a/server/v1/services/accounts.js b/server/v1/services/accounts.js index ebf8519..5e31f4a 100644 --- a/server/v1/services/accounts.js +++ b/server/v1/services/accounts.js @@ -18,7 +18,7 @@ const CreateAccountService = { // pulling users data from database const userDetails = await dbConnection - .dbConnect('SELECT id,firstname,lastname FROM users WHERE email=$1', + .dbConnect('SELECT * FROM users WHERE email=$1', [userData.email]); const { firstname, lastname, id } = userDetails.rows[0]; diff --git a/server/v1/services/transaction.js b/server/v1/services/transaction.js index 3c22b0f..970921e 100644 --- a/server/v1/services/transaction.js +++ b/server/v1/services/transaction.js @@ -33,9 +33,7 @@ const TransactionService = { ); const { accountnumber, balance } = accountDbData.rows[0]; - // check if a string - const checkForDigit = /^-?\d+\.?\d*$/; - if (checkForDigit.test(transactionData.amount)) { + if (typeof transactionData.amount === 'number') { // substract the passed in amount from the current balance const newBalance = balance - transactionData.amount; @@ -132,9 +130,7 @@ const TransactionService = { ); const { accountnumber, balance } = accountDbData.rows[0]; - // check if a string - const checkForDigit = /^-?\d+\.?\d*$/; - if (checkForDigit.test(transactionData.amount)) { + if (typeof transactionData.amount === 'number') { if (transactionData.amount <= 0) { returnStatus = 422; returnError = 'please credit an account with positive value'; From 04982bf80a03e688b6ca30280434bf3a278f24c1 Mon Sep 17 00:00:00 2001 From: cavdy Date: Sat, 27 Apr 2019 01:49:46 +0100 Subject: [PATCH 3/4] feature(Protect view account from other user):Protect view account from other user Protect view account so another user cant view another user account [Starts #165652538] --- server/v1/controllers/accounts.js | 4 +- server/v1/controllers/auth.js | 20 ---- server/v1/controllers/users.js | 20 ++++ server/v1/routes/auth.js | 5 - server/v1/routes/users.js | 5 + server/v1/services/accounts.js | 55 ++++++++-- server/v1/services/auth.js | 64 ------------ server/v1/services/users.js | 64 ++++++++++++ server/v1/test/accounts.js | 164 +++++++++++++++++++++++++++++- server/v1/test/signup.js | 11 +- 10 files changed, 308 insertions(+), 104 deletions(-) diff --git a/server/v1/controllers/accounts.js b/server/v1/controllers/accounts.js index fee96db..322a448 100644 --- a/server/v1/controllers/accounts.js +++ b/server/v1/controllers/accounts.js @@ -52,7 +52,7 @@ const CreateAccountController = { async specificAccounts(req, res) { const { accountNumber } = req.params; const specificAccounts = await AccountsService - .specificAccounts(accountNumber); + .specificAccounts(accountNumber, req.authorizedData); const data = await statusHelper .statusHelper(req, @@ -72,7 +72,7 @@ const CreateAccountController = { async allAccountTransaction(req, res) { const { accountNumber } = req.params; const transactionHistory = await AccountsService - .allAccountTransaction(accountNumber); + .allAccountTransaction(accountNumber, req.authorizedData); const data = await statusHelper .statusHelper(req, diff --git a/server/v1/controllers/auth.js b/server/v1/controllers/auth.js index c369c49..c11aead 100644 --- a/server/v1/controllers/auth.js +++ b/server/v1/controllers/auth.js @@ -40,26 +40,6 @@ const AuthController = { 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/users.js b/server/v1/controllers/users.js index 060f123..3759b49 100644 --- a/server/v1/controllers/users.js +++ b/server/v1/controllers/users.js @@ -59,6 +59,26 @@ const UsersController = { deleteUser.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 UserService + .createStaffs(userData, req.signintoken, req.authorizedData); + + const data = await statusHelper + .statusHelper(req, + res, + createdStaff.returnStatus, + createdStaff.returnError, + createdStaff.returnSuccess); + return data; + }, }; export default UsersController; diff --git a/server/v1/routes/auth.js b/server/v1/routes/auth.js index b307ebc..56093f7 100644 --- a/server/v1/routes/auth.js +++ b/server/v1/routes/auth.js @@ -7,10 +7,5 @@ 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/users.js b/server/v1/routes/users.js index 3a137a5..aaf9817 100644 --- a/server/v1/routes/users.js +++ b/server/v1/routes/users.js @@ -10,5 +10,10 @@ router.get('/:email/accounts', jwtMiddleware.verifyJwt, UsersController.getUsersAccounts); router.delete('/:id', jwtMiddleware.verifyJwt, UsersController.deleteUser); +router.post('/addstaff', + jwtMiddleware.checkToken, + jwtMiddleware.signinJwt, + jwtMiddleware.verifyJwt, + UsersController.createStaffs); export default router; diff --git a/server/v1/services/accounts.js b/server/v1/services/accounts.js index 5e31f4a..c575770 100644 --- a/server/v1/services/accounts.js +++ b/server/v1/services/accounts.js @@ -113,20 +113,38 @@ const CreateAccountService = { * Get specific account * @constructor * @param {*} accountNumber - recieve account number. + * @param {*} loggedIn - logged in details. */ - async specificAccounts(accountNumber) { + async specificAccounts(accountNumber, loggedIn) { let returnStatus; let returnSuccess = ''; let returnError = ''; + + const users = await dbConnection + .dbConnect('SELECT * from users WHERE email=$1', + [loggedIn.email]); + const { type, isadmin } = users.rows[0]; + 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]; + if (userAccount.rows[0].email === loggedIn.email) { + returnStatus = 200; + // eslint-disable-next-line prefer-destructuring + returnSuccess = userAccount.rows[0]; + } else if (type === 'staff' || isadmin === true) { + returnStatus = 200; + // eslint-disable-next-line prefer-destructuring + returnSuccess = userAccount.rows[0]; + } else { + returnStatus = 401; + returnError = 'sorry you can\'t view another user\'s account'; + } } else { returnStatus = 404; returnError = 'no account found'; } + return { returnStatus, returnSuccess, @@ -138,19 +156,42 @@ const CreateAccountService = { * Get all accounts trasactions that belongs to account number * @constructor * @param {*} accountNumber - recieve account number. + * @param {*} loggedIn - logged in details. */ - async allAccountTransaction(accountNumber) { + async allAccountTransaction(accountNumber, loggedIn) { let returnStatus; let returnSuccess = ''; let returnError = ''; + + const users = await dbConnection + .dbConnect('SELECT * from users WHERE email=$1', + [loggedIn.email]); + const { type, isadmin } = users.rows[0]; + const userTransaction = await dbConnection .dbConnect('SELECT * from transactions WHERE accountnumber=$1', [accountNumber]); + + const userAccount = await dbConnection + .dbConnect('SELECT email from accounts WHERE accountnumber=$1', + [accountNumber]); + if (userTransaction.rows.length > 0) { - returnStatus = 200; - returnSuccess = userTransaction.rows; + if (userAccount.rows[0].email === loggedIn.email) { + returnStatus = 200; + // eslint-disable-next-line prefer-destructuring + returnSuccess = userTransaction.rows; + } else if (type === 'staff' || isadmin === true) { + returnStatus = 200; + // eslint-disable-next-line prefer-destructuring + returnSuccess = userTransaction.rows; + } else { + returnStatus = 401; + returnError = 'sorry you can\'t view another user\'s transactions'; + } } else { returnStatus = 404; returnError = 'no transaction found'; } + return { returnStatus, returnSuccess, diff --git a/server/v1/services/auth.js b/server/v1/services/auth.js index 9af66d8..4c28fed 100644 --- a/server/v1/services/auth.js +++ b/server/v1/services/auth.js @@ -147,70 +147,6 @@ const AuthService = { 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/users.js b/server/v1/services/users.js index 47858dd..affaf17 100644 --- a/server/v1/services/users.js +++ b/server/v1/services/users.js @@ -1,4 +1,7 @@ +import bcrypt from 'bcryptjs'; import dbConnection from '../config/database'; +import UserModel from '../model/users'; +import registrationHelper from '../helper/registrationHelper'; const UsersServices = { /** @@ -125,6 +128,67 @@ const UsersServices = { 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) RETURNING id, firstname, lastname, email', + [userData.email, userData.firstName, userData.lastName, hash, userData.type, userData.isAdmin]); + if (response.command === 'INSERT') { + const user = new UserModel(); + user.id = response.rows[0].id; + user.firstName = response.rows[0].firstname; + user.lastName = response.rows[0].lastname; + user.email = response.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 UsersServices; diff --git a/server/v1/test/accounts.js b/server/v1/test/accounts.js index 9e6b1de..c152e95 100644 --- a/server/v1/test/accounts.js +++ b/server/v1/test/accounts.js @@ -36,6 +36,43 @@ describe('Testing Accounts Controller', () => { }, ); + it( + 'user can view their 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) + .post('/api/v1/accounts') + .set('Authorization', `Bearer ${token}`) + .send({ + type: 'savings', + }); + const { accountNumber } = res.body.data; + const res1 = await chai.request(app) + .get(`/api/v1/accounts/${accountNumber}`) + .set('Authorization', `Bearer ${token}`) + .send(); + expect(res1.body).to.be.an('object'); + expect(res1.body.status).to.equal(200); + expect(res1.body.data).to.have.property('id'); + expect(res1.body.data).to.have.property('email'); + expect(res1.body.data).to.have.property('firstname'); + expect(res1.body.data).to.have.property('lastname'); + expect(res1.body.data).to.have.property('accountnumber'); + expect(res1.body.data).to.have.property('createdon'); + expect(res1.body.data).to.have.property('owner'); + expect(res1.body.data).to.have.property('type'); + expect(res1.body.data).to.have.property('status'); + expect(res1.body.data).to.have.property('balance'); + }, + ); + it( 'admin or staff should see all accounts', async () => { @@ -250,6 +287,64 @@ describe('Testing Accounts Controller', () => { }, ); + it( + 'admin or staff should get any specific 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/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( + 'admin or staff should get any specific account transactions', + 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/${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( 'when account does not have transaction', async () => { @@ -272,7 +367,7 @@ describe('Testing Accounts Controller', () => { ); it( - 'when specific account does not have transaction', + 'when account does not have transaction', async () => { const signinUrl = '/api/v1/auth/signin'; const response = await chai.request(app) @@ -283,7 +378,72 @@ describe('Testing Accounts Controller', () => { }); const { token } = response.body.data; const res = await chai.request(app) - .get(`/api/v1/accounts/${314685979881}`) + .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 permission', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'deleteguy3@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get(`/api/v1/accounts/${3146859791}`) + .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 can\'t view another user\'s account'); + }, + ); + + it( + 'when specific account transaction does not have permission', + async () => { + const signinUrl = '/api/v1/auth/signin'; + const response = await chai.request(app) + .post(signinUrl) + .send({ + email: 'deleteguy3@banka.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(401); + expect(res.body.data) + .to.equal('sorry you can\'t view another user\'s transactions'); + }, + ); + + 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: 'admin@banka.com', + password: 'passworD4@', + }); + const { token } = response.body.data; + const res = await chai.request(app) + .get(`/api/v1/accounts/${314685979133}`) .set('Authorization', `Bearer ${token}`) .send(); expect(res.body).to.be.an('object'); diff --git a/server/v1/test/signup.js b/server/v1/test/signup.js index cff88ac..31c7657 100644 --- a/server/v1/test/signup.js +++ b/server/v1/test/signup.js @@ -25,6 +25,9 @@ describe('Testing User Controller', () => { 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]); + await dbConnection + .dbConnect('INSERT into users(email, firstName, lastName, password, type, isAdmin) values($1, $2, $3, $4, $5, $6)', + ['deleteguy3@banka.com', 'cavdy', 'ikenna', '$2a$10$CmmIst1.D3QjaWuafKbBaOuAFu0r9o7xxQY.0SMKiAN.h9z52a2y2', 'client', false]); }); describe('Testing signup controller', () => { const signupUrl = '/api/v1/auth/signup'; @@ -78,7 +81,7 @@ describe('Testing User Controller', () => { }); const { token } = response.body.data; const res = await chai.request(app) - .post('/api/v1/auth/signup/addstaff') + .post('/api/v1/users/addstaff') .set('Authorization', `Bearer ${token}`) .send({ firstName: 'cavdy', @@ -122,7 +125,7 @@ describe('Testing User Controller', () => { }); const { token } = response.body.data; const res = await chai.request(app) - .post('/api/v1/auth/signup/addstaff') + .post('/api/v1/users/addstaff') .set('Authorization', `Bearer ${token}`) .send({ type: 'staff', @@ -232,7 +235,7 @@ describe('Testing User Controller', () => { }); const { token } = response.body.data; const res = await chai.request(app) - .post('/api/v1/auth/signup/addstaff') + .post('/api/v1/users/addstaff') .set('Authorization', `Bearer ${token}`) .send({ firstName: 'cavdy', @@ -262,7 +265,7 @@ describe('Testing User Controller', () => { }); const { token } = response.body.data; const res = await chai.request(app) - .post('/api/v1/auth/signup/addstaff') + .post('/api/v1/users/addstaff') .set('Authorization', `Bearer ${token}`) .send({ firstName: 'cavdy', From bb6c722093e3fe2b7f16d3276477ed0eef924010 Mon Sep 17 00:00:00 2001 From: cavdy Date: Sat, 27 Apr 2019 03:19:15 +0100 Subject: [PATCH 4/4] feature(Delete user and delete all its data):Delete user and delete all its data Delete user and its data [Starts #165652955] --- server/v1/helper/statusHelper.js | 88 +++++++++++++++++--------------- server/v1/services/users.js | 30 +++++++++-- 2 files changed, 72 insertions(+), 46 deletions(-) diff --git a/server/v1/helper/statusHelper.js b/server/v1/helper/statusHelper.js index 9858ab2..331ded3 100644 --- a/server/v1/helper/statusHelper.js +++ b/server/v1/helper/statusHelper.js @@ -10,48 +10,52 @@ const statusHelper = { * @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 === 403) { // conflict - res.status(403); - return res.json({ - status: 403, - 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, - }); + switch (status) { + case 401: // unauthorized + res.status(401); + return res.json({ + status: 401, + data: error, + }); + case 409: // conflict + res.status(409); + return res.json({ + status: 409, + data: error, + }); + case 403: // forbidden + res.status(403); + return res.json({ + status: 403, + data: error, + }); + case 201: // created + res.status(201); + return res.json({ + status: 201, + data, + }); + case 200: // success + res.status(200); + return res.json({ + status: 200, + data, + }); + case 404: // not found + res.status(404); + return res.json({ + status: 404, + data: error, + }); + case 422: // unprocessable entity + res.status(422); + return res.json({ + status: 422, + data: error, + }); + default: + // do nothing + break; } }, }; diff --git a/server/v1/services/users.js b/server/v1/services/users.js index affaf17..9d1234b 100644 --- a/server/v1/services/users.js +++ b/server/v1/services/users.js @@ -85,11 +85,22 @@ const UsersServices = { [staff.email]); const { type, isadmin } = userDetails.rows[0]; - if (type === 'staff') { + if (type === 'staff') { // checks if staff const checkusers = await dbConnection - .dbConnect('SELECT type FROM users WHERE id=$1', [id]); + .dbConnect('SELECT email, type FROM users WHERE id=$1', [id]); if (checkusers.rows.length > 0) { - if (checkusers.rows[0].type === 'client') { + if (checkusers.rows[0].type === 'client') { // check if client + const delTransactions = await dbConnection + .dbConnect('SELECT * from accounts WHERE email=$1', + [checkusers.rows[0].email]); // loop through db for accounts + delTransactions.rows.map(async (del) => { + await dbConnection + .dbConnect('DELETE FROM transactions WHERE accountnumber=$1', + [del.accountnumber]); + await dbConnection + .dbConnect('DELETE FROM accounts WHERE accountnumber=$1', + [del.accountnumber]); + }); const accountDbData = await dbConnection .dbConnect('DELETE FROM users WHERE id=$1', [id]); if (accountDbData.command === 'DELETE') { @@ -106,8 +117,19 @@ const UsersServices = { } } else if (isadmin === true) { const checkusers = await dbConnection - .dbConnect('SELECT type FROM users WHERE id=$1', [id]); + .dbConnect('SELECT email, type FROM users WHERE id=$1', [id]); if (checkusers.rows.length > 0) { + const delTransactions = await dbConnection + .dbConnect('SELECT * from accounts WHERE email=$1', + [checkusers.rows[0].email]); + delTransactions.rows.map(async (del) => { + await dbConnection + .dbConnect('DELETE FROM transactions WHERE accountnumber=$1', + [del.accountnumber]); + await dbConnection + .dbConnect('DELETE FROM accounts WHERE accountnumber=$1', + [del.accountnumber]); + }); const accountDbData = await dbConnection .dbConnect('DELETE FROM users WHERE id=$1', [id]); if (accountDbData.command === 'DELETE') {