Skip to content

Commit

Permalink
Setup API endpoint for loan application
Browse files Browse the repository at this point in the history
Add files loansController.js and loansModel.js
Add file ValidateLoans.js for user input validation
Add file loans.js for loans data structure
Add Auth.js for user authentication
Add files loanHelper.js, utils.js
Add loansTest.js for test cases
  • Loading branch information
shonubijerry committed May 1, 2019
1 parent 29f7e03 commit a9019b5
Show file tree
Hide file tree
Showing 15 changed files with 572 additions and 37 deletions.
56 changes: 56 additions & 0 deletions server/controllers/loansController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import loansModel from '../model/loansModel'
import ResponseHelper from '../helpers/responseHelper'

/**
* @fileOverview - class manages all users logic
* @class - LoansController
* @requires - ../model/loansModel
* @requires - ../helpers/token
* @requires - ../helpers/errorStrings
* @exports - loansController.js
**/

class LoansController {

/**
* Create a loan application
* @param {object} req
* @param {object} res
*/

static createLoan (req, res) {

const userEmail = req.token.user.email;

const currentLoan = loansModel.checkCurrentLoan(userEmail)

if(currentLoan.isFound === true ) {

ResponseHelper.errorResponse(res, `You have an unpaid loan of ${currentLoan.loan.amount} which is under review or yet to be fully repaid`);

} else {
const newLoan = loansModel.createLoan(req, userEmail);

return res.status(201).send({
status: 201,
data: {
loanId: newLoan.id,
user: newLoan.user,
createdOn: newLoan.createdOn,
status: newLoan.status,
repaid: newLoan.repaid,
tenor: newLoan.tenor,
amount: newLoan.amount,
paymentInstallment: newLoan.paymentInstallment,
balance: newLoan.balance,
interest: newLoan.interest
}
});
}

}


}

export default LoansController;
56 changes: 56 additions & 0 deletions server/dummy/loans.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* @fileOverview - This module holds dummy data for loans
* @exports - loans object
*/
const loans = [
{
id: 1,
user: 'shonubijerry@gmail.com',
createdOn: '01/05/2019 2:16:17 PM',
status: 'approved',
repaid: true,
tenor: 5,
amount: 40000,
paymentInstallment: '8400.00',
balance: '0.00',
interest: '2000.00'
},
{
id: 2,
user: 'adeade@gmail.com',
createdOn: '01/04/2019 2:16:17 PM',
status: 'approved',
repaid: false,
tenor: 7,
amount: 80000,
paymentInstallment: '12000.00',
balance: '84000.00',
interest: '4000.00'
},
{
id: 3,
user: 'shonubijerry@gmail.com',
createdOn: '01/05/2019 2:17:34 PM',
status: 'approved',
repaid: true,
tenor: 5,
amount: 8960000,
paymentInstallment: '1881600.00',
balance: '0.00',
interest: '448000.00'
},
{
id: 4,
user: 'adeade@gmail.com',
createdOn: '01/05/2019 3:40:18 PM',
status: 'approved',
repaid: true,
tenor: 7,
amount: 60000,
paymentInstallment: '9000.00',
balance: '0.00',
interest: '3000.00'
}
];

export default loans;
3 changes: 3 additions & 0 deletions server/helpers/errorStrings.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ const errorStrings = {
passwordLength: 'Password must not be less than 6 characters',
loginFailure: 'Could not login. Email and password do not match',
emailNotExist: 'User does not exist',
notAuthenticated: 'You must login to have access to this feature',
validTenor: 'Tenor must range from 1 to 12 months',
validAmount: 'Amount must be digits',

}

Expand Down
42 changes: 42 additions & 0 deletions server/helpers/loanHelper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* @fileOverview - This class helps generate loan parameters
* @class LoanHelper
* @exports loanHelper
**/

class LoanHelper {

/**
* calculate interest
* @param {float} amount
* @returns {float}
*/

static getInterest(amount) {
return amount * 0.05;
}

/**
* calculate balance
* @param {float} amount
* @returns {float}
*/

static getBalance(amount) {
return amount + this.getInterest(amount);
}

/**
* calculate paymentInstallment
* @param {integer} tenor
* @returns {float}
*/

static getInstallment(amount, tenor) {
return this.getBalance(amount) / tenor;
}

}


export default LoanHelper;
73 changes: 65 additions & 8 deletions server/helpers/responseHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,74 @@
class ResponseHelper {

/**
* return error response
* success ok response 200
* @param {object} res
* @param {string} error
* @param {object} error
**/

static errorResponse(res, error){
return res.status(406).json({
status: 406,
error
});
}
static successOk(res, message){
return res.status(200).json({
status: 200,
data: {
message,
}
});
}

/**
* return unauthorized error response 401
* @param {object} res
* @param {object} error
* @returns {object} response json
**/

static errorUnauthorized(res, error){
return res.status(401).json({
status: 401,
error
});
}

// /**
// * return forbidden error response 403
// * @param {object} res
// * @param {object} error
// **/

// static forbiddenError(res, error){
// return res.status(403).json({
// status: 403,
// error
// });
// }

/**
* return unacceptable error response 404
* @param {object} res
* @param {object} error
**/

static errorNotFound(res, error){
return res.status(404).json({
status: 404,
error
});
}

/**
* return unacceptable error response 406
* @param {object} res
* @param {object} error
**/

static errorResponse(res, error){
return res.status(406).json({
status: 406,
error
});
}

}


export default ResponseHelper;
2 changes: 2 additions & 0 deletions server/helpers/rules.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ const rules = {
nameLength: /^[a-zA-Z]{2,30}$/,
passwordLength: /^.{6,}$/,
validUrl: /^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/,
validTenor: /^([1-9]|[0-1][0-2])$/,
validAmount: /^[0-9]+(\.[0-9]{1,2})?$/,
};

export default rules;
Expand Down
21 changes: 21 additions & 0 deletions server/helpers/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* @fileOverview - This class helps generate repeated codes
* @class Utils
* @exports Utils
**/

class Utils {

/**
* get present date and time
* @returns {string}
*/

static getNow() {
const d = new Date();
return `${d.toLocaleDateString()} ${d.toLocaleTimeString()}`;
}

}

export default Utils;
37 changes: 37 additions & 0 deletions server/middleware/Auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import jwt from 'jsonwebtoken';
import errorStrings from '../helpers/errorStrings';
import ResponseHelper from '../helpers/responseHelper';

const secretKey = process.env.SECRET_KEY;

/**
* @class Authenticate User
* @requires jsonwebtoken
* @requires '../helpers/errorStrings'
*/
class Auth {

/**
* Authenticate users
* @param {Object} request
* @param {Object} response
* @param {callback} next
* @return {Object}
*/

static authenticateUser(request, response, next) {
try {
const userToken = request.headers['x-access'] || request.headers.token;
const verifiedToken = jwt.verify(userToken, secretKey);
request.token = verifiedToken;
return next();
} catch (error) {
ResponseHelper.errorUnauthorized(response, errorStrings.notAuthenticated);
}

}


}

export default Auth;
51 changes: 51 additions & 0 deletions server/middleware/ValidateLoans.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import errorStrings from '../helpers/errorStrings';
import Validator from '../helpers/Validator';
import rules from '../helpers/rules';


/**
* @fileOverview Class to validate loans form submission
* @class ValidateLoans
* @requires ../helpers/errorStrings
* @requires ../helpers/Validator
* @requires ../helpers/rules
* @exports ValidateLoans
*/

class ValidateLoans {
/**
* validate signup input
* @param {Object} request
* @param {Object} response
* @callback {Function} next
*/

static validateApplication(request, response, next) {

const errors = ValidateLoans.checkApplicationErrors(request.body);

Validator.checkValidationErrors(response, errors, next);
}

/**
* collect all possible errors
* @param {Object} request
* @return {String} errors
*/

static checkApplicationErrors ({amount, tenor}) {
const errors = {};

if (!amount || !rules.empty.test(amount) || !rules.validAmount.test(amount))
errors.validAmount = errorStrings.validAmount;

if (!tenor || !rules.empty.test(tenor) || !rules.validTenor.test(tenor))
errors.validTenor = errorStrings.validTenor;

return errors;
}


}

export default ValidateLoans;

0 comments on commit a9019b5

Please sign in to comment.