Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions migrations/20180223063545-changetype-transaction-id.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@


module.exports = {
up: (queryInterface, Sequelize) => {
queryInterface.changeColumn(
'transactions',
'transactionId',
{
type: Sequelize.STRING,
},
);
},

down: (queryInterface, Sequelize) => {
queryInterface.changeColumn(
'transactions',
'transactionId',
{
type: Sequelize.STRING,
},
);
},
};
7 changes: 5 additions & 2 deletions routes/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
const ping = require('./ping');
const userRegistration = require('./userRegister');

const { route: userRegistration } = require('./userRegister');
const userLogin = require('./userLogin');
const send = require('./send');
const request = require('./request');
const auth = require('./auth');
const history = require('./history');

module.exports = [].concat(ping, userRegistration, userLogin, auth, history);
module.exports = [].concat(ping, userRegistration, userLogin, auth, history, send, request);
58 changes: 58 additions & 0 deletions routes/request.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const Models = require('../models');
const Joi = require('joi');

const requestSwagger = {
responses: {
200: {
description: 'Success',
schema: Joi.object({
message: Joi.string().example('request created successfully'),
}).label('Result'),
},
400: { description: 'Bad Request' },
},
};
const requestPayloadValidation = Joi.object({
toId: Joi.number().integer().min(1).example(1),
amount: Joi.number().integer().min(0).example(500),
reason: Joi.string().example('food'),
});
const route = [
{
method: 'POST',
path: '/transaction/request',
config: {
tags: ['api'],
description: 'request money',
notes: 'request money from another user',
plugins: {
'hapi-swagger': requestSwagger,
},
validate: {
payload: requestPayloadValidation,
},
auth: 'jwt',
},
handler: (request, response) => {
const toId = request.payload.toId;
const amt = request.payload.amount;
const currentUserId = request.auth.credentials.userId;
const reason = request.payload.reason;
// create transaction
Models.transactions.create({
transactionId: `${currentUserId}_${toId}_${new Date()}`,
fromId: currentUserId,
toId,
amount: amt,
reason,
status: 'PENDING',
timeStamp: new Date(),
createdAt: new Date(),
updatedAt: new Date(),
}).then(() => {
response({ statusCode: 201, message: 'transaction added' });
});
},
}];

module.exports = route;
82 changes: 82 additions & 0 deletions routes/send.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
const Models = require('../models');
const Joi = require('joi');

const sendSwagger = {
responses: {
200: {
description: 'Success',
schema: Joi.object({
message: Joi.string().example('request created successfully'),
}).label('Result'),
},
400: { description: 'Bad Request' },
},
};
const sendPayloadValidation = Joi.object({
toId: Joi.number().integer().min(1).example(1),
amount: Joi.number().integer().min(0).example(500),
reason: Joi.string().example('food'),
});
const getUserBalance = userId => new Promise((resolve) => {
Models.userDetails.findOne({ where: { userId } })
.then((item) => {
resolve(item.balance);
});
});

const route = [
{
method: 'POST',
path: '/transaction/send',
config: {
tags: ['api'],
description: 'send money',
notes: 'send money from another user',
plugins: {
'hapi-swagger': sendSwagger,
},
validate: {
payload: sendPayloadValidation,
},
auth: 'jwt',
},
handler: (request, response) => {
const toId = request.payload.toId;
const amt = request.payload.amount;
const currentUserId = request.auth.credentials.userId;
const reason = request.payload.reason;
// console.log(`${toId} ${amt}${currentUserId}${reason}`);
getUserBalance(currentUserId).then((balance) => {
if (amt > balance) {
response('insufficient balance');
} else {
const futureBalance = balance - amt;
// deduct balance from fromId
Models.userDetails.update(
{ balance: futureBalance },
{ where: { userId: currentUserId } },
).then(() => {
// create transaction
console.log('yup coming in transaction database');
Models.transactions.create({
transactionId: `${currentUserId}_${toId}_${new Date()}`,
fromId: currentUserId,
toId,
amount: amt,
reason,
status: 'PENDING',
timeStamp: new Date(),
createdAt: new Date(),
updatedAt: new Date(),
});
}).then(() => {
response({ statusCode: 201, message: 'transaction added' });
});
}
});
},

},
];

module.exports = route;
16 changes: 16 additions & 0 deletions seeders/20180214174923-additional-users.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@


module.exports = {
up: (queryInterface, Sequelize) => queryInterface.bulkInsert('userDetails', [{
userId: 4,
phone: '1234567890',
accountNo: '0987654322',
firstName: 'Rachel',
lastName: 'A',
balance: 5000,
createdAt: new Date(),
updatedAt: new Date(),
}], {}),

down: (queryInterface, Sequelize) => queryInterface.bulkDelete('userDetails', null, {}),
};
63 changes: 63 additions & 0 deletions tests/routes/request.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
const server = require('../../server');

describe('request validation', () => {
test('Test for successful POST request', (done) => {
const request = {
method: 'POST',
url: '/transaction/request',
credentials: {
userId: 4,
},
payload: JSON.stringify({ toId: 2, amount: 500, reason: 'food' }),
};
server.inject(request, (response) => {
expect(response.result.statusCode).toBe(201);
done();
});
});

test('Test for unsuccessful POST request if toId is not a number', (done) => {
const request = {
method: 'POST',
url: '/transaction/request',
credentials: {
userId: 4,
},
payload: JSON.stringify({ toId: 'm', amount: 500, reason: 'food' }),
};
server.inject(request, (response) => {
expect(response.statusCode).toBe(400);
done();
});
});
test('Test for unsuccessful POST request if amount is not a number', (done) => {
const request = {
method: 'POST',
url: '/transaction/request',
credentials: {
userId: 4,
},
payload: JSON.stringify({ toId: 2, amount: '500m', reason: 'food' }),
};
server.inject(request, (response) => {
expect(response.statusCode).toBe(400);
done();
});
});


test('Test for unsuccessful POST request if reason is not a string', (done) => {
const request = {
method: 'POST',
url: '/transaction/request',
credentials: {
userId: 4,
},
payload: JSON.stringify({ toId: 2, amount: 500, reason: 22 }),
};
server.inject(request, (response) => {
expect(response.statusCode).toBe(400);
done();
});
});
});
63 changes: 63 additions & 0 deletions tests/routes/send.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
const server = require('../../server');

describe('request validation', () => {
test('Test for successful POST request', (done) => {
const request = {
method: 'POST',
url: '/transaction/send',
credentials: {
userId: 4,
},
payload: JSON.stringify({ toId: 2, amount: 500, reason: 'food' }),
};
server.inject(request, (response) => {
expect(response.result.statusCode).toBe(201);
done();
});
});

test('Test for unsuccessful POST request if toId is not a number', (done) => {
const request = {
method: 'POST',
url: '/transaction/send',
credentials: {
userId: 4,
},
payload: JSON.stringify({ toId: 'm', amount: 500, reason: 'food' }),
};
server.inject(request, (response) => {
expect(response.statusCode).toBe(400);
done();
});
});
test('Test for unsuccessful POST request if amount is not a number', (done) => {
const request = {
method: 'POST',
url: '/transaction/send',
credentials: {
userId: 4,
},
payload: JSON.stringify({ toId: 2, amount: '500m', reason: 'food' }),
};
server.inject(request, (response) => {
expect(response.statusCode).toBe(400);
done();
});
});


test('Test for unsuccessful POST request if reason is not a string', (done) => {
const request = {
method: 'POST',
url: '/transaction/send',
credentials: {
userId: 4,
},
payload: JSON.stringify({ toId: 2, amount: 500, reason: 22 }),
};
server.inject(request, (response) => {
expect(response.statusCode).toBe(400);
done();
});
});
});