File: //var/dev/farhangmoaser/web/routes/api/1.0/voucher.js
'use strict';
/**
* Express endpoints for /voucher address
* Version: 0.1
* Author: Babak Vandad
*
* Restful api for addresses:
* GET /voucher
* GET /voucher/me/:id/activate
* PUT /voucher
* POST /voucher/:id/activate
* POST /voucher/:id
* DELETE /voucher
*/
var express = require('express');
var router = express.Router();
var fs = require('fs');
var path = require('path');
var Moment = require('moment');
var consts = require(path.join(BASEDIR, 'consts'));
var authHelper = require(path.join(BASEDIR, 'helpers/auth'));
var VoucherModel = require(path.join(BASEDIR, 'models/voucher'));
var DictionaryModel = require(path.join(BASEDIR, 'models/dictionary'));
var UserModel = require(path.join(BASEDIR, 'models/user'));
// var UserAccessModel = require(path.join(BASEDIR, 'models/userAccess'));
var SubscriptionModel = require(path.join(BASEDIR, 'models/subscription'));
// var EntryModel = require(path.join(BASEDIR, 'models/entry'));
var db = require(path.join(BASEDIR, 'connectors/mysql'));
var authenticate = authHelper.authenticate;
var access = authHelper.access;
/**
* Fail a request by releasing database connection, rollback transaction
* and sending the proper error code and message with 4xx or 5xx status codes.
* @param {object} express response object
* @param {object} db connection
* @param {object} error object from costs.js
* @param {integer} override status code (if you want to send 200 instead of 4xx/5xx)
* @return {function} the function to fail the request.
*/
var fail = function(response, conn, error, status){
return function(){
if(conn && conn.release)
conn.release();
response.status(status ? status : error.status).json({error: error.code, message: error.message});
};
};
/**
* Sends data to the client, commits transaction and releases the db connection
* @param {object} express response object
* @param {object} db connection
* @param {object} data for the client
*/
var send = function(res, conn, data){
if(conn) conn.release();
if(data) res.json(data);
else res.end();
};
/**
* get the list of vouchers based on constraints:
* book uuid
* user
* group
* minDate format: 1999-9-19
* maxDate format: 1999-9-19
* state
* limit page size
* page page number (from 0)
*/
router.get('/', authenticate, access('voucher:get', 'نمایش فهرست حوالهها'), (req, res, next) => {
if(
(req.query.hasOwnProperty('dateFrom') && !/^\d{4}-\d{1,2}-\d{1,2}$/.exec(req.query.dateFrom)) ||
(req.query.hasOwnProperty('dateTo') && !/^\d{4}-\d{1,2}-\d{1,2}$/.exec(req.query.dateTo))
) return fail(res, null, consts.e.ERR_MALFORMED_REQUEST)();
db.getConnection((err, conn) => {
if(err) return fail(res, conn, err)();
var query = {};
if(req.query.hasOwnProperty('source')) query.source_uuid = req.query.source;
if(req.query.hasOwnProperty('dateFrom')) query['>=dateTo'] = req.query.dateFrom;
if(req.query.hasOwnProperty('dateTo')) query['<=dateFrom'] = req.query.dateTo;
if(req.query.hasOwnProperty('state')) query.state = parseInt(req.query.state);
if(req.query.hasOwnProperty('source_title')){
if(req.query.full)
query.source_title = req.query.source_title;
else
query['%%source_title'] = req.query.source_title+'%';
}
if(req.query.hasOwnProperty('user_email')){
if(req.query.full)
query.user_email = req.query.user_email;
else
query['%%user_email'] = req.query.user_email+'%';
}
var limit = req.query.hasOwnProperty('limit') ? Math.min(100, parseInt(req.query.limit)) : 100;
var page = req.query.hasOwnProperty('page') ? parseInt(req.query.page) : 0;
var offset = page*limit;
// add count of all results to the response
var countRecords = records =>
VoucherModel.count(conn, query).then(
sum => send(res, conn, {sum: sum, list: records}),
fail(res, conn, consts.e.ERR_DB_ERROR)
);
// get one pae of results
VoucherModel.list(conn, query, limit, offset, req.query.orderBy).then(
countRecords, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
/**
* get info of a voucher:
* id voucher id
*/
router.get('/:id', authenticate, access('voucher:get', 'نمایش فهرست حوالهها'), async (req, res, next) => {
let conn;
try {
conn = await db.getConnectionPromise();
}catch(err) { return fail(res, conn, consts.e.ERR_DB_ERROR)(); }
var query = {};
var voucher = new VoucherModel(conn, {id: req.params.id});
try{
await voucher.load(true);
}catch (e) {
fail(res, conn, consts.e.ERR_DB_ERROR)();
}
send(res, conn, voucher.fields())
});
router.get('/me/:id/info', authenticate, access('voucher:info-me', 'کاربر مشخصات حواله را ببیند'), (req, res, next) => {
req.body = JSON.parse(JSON.stringify(req.body));
if(!req.params.id) return fail(res, null, consts.e.ERR_REQUIRED_FIELDS)();
db.getConnection((err, conn) => {
if(err) return fail(res, conn, err)();
(new VoucherModel(conn, {id: req.params.id})).load(true).then(
voucher => {
if(!voucher)
return fail(res, conn, consts.e.ERR_MISSING_RECORD)();
if(voucher.field('user_email') && voucher.field('user_email') != req.user.field('email'))
return fail(res, conn, consts.e.ERR_ACCESS_PERMISSION)();
if((voucher.field('dateFrom') && new Date(voucher.field('dateFrom'))>new Date()) ||
(voucher.field('dateTo') && new Date(voucher.field('dateTo'))<new Date()) ||
(voucher.field('state') != consts.v.STATE_ACTIVE) ||
voucher.field('subscription'))
return fail(res, conn, consts.e.ERR_ACCESS_PERMISSION)();
let voucherData = voucher.fields();
delete voucherData.source;
delete voucherData.user;
delete voucherData.user_searchable;
delete voucherData.user_sortable;
delete voucherData.group;
delete voucherData.created;
delete voucherData.activation;
delete voucherData.subscription;
delete voucherData.state;
send(res, conn, voucherData);
}, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
router.get('/me/:id/activate', authenticate, access('voucher:activate-me', 'کاربر حواله خود را فعال کند'), (req, res, next) => {
req.body = JSON.parse(JSON.stringify(req.body));
if(!req.params.id) return fail(res, null, consts.e.ERR_REQUIRED_FIELDS)();
db.getConnection((err, conn) => {
if(err) return fail(res, conn, err)();
(new VoucherModel(conn, {id: req.params.id})).load(true).then(
voucher => {
if(voucher.field('user_email') && voucher.field('user_email') != req.user.field('email'))
return fail(res, conn, consts.e.ERR_ACCESS_PERMISSION)();
if((voucher.field('dateFrom') && new Date(voucher.field('dateFrom'))>new Date()) ||
(voucher.field('dateTo') && new Date(voucher.field('dateTo'))<new Date()) ||
(voucher.field('state') != consts.v.STATE_ACTIVE) ||
voucher.field('subscription'))
return fail(res, conn, consts.e.ERR_ACCESS_PERMISSION)();
(new SubscriptionModel(conn, {
user: req.user.field('id'),
book: voucher.field('source'),
dateStart: Moment().format('YYYY-M-D'),
dateExpire: Moment().add(voucher.field('period'), 'days').format('YYYY-M-D'),
state: consts.v.STATE_ACTIVE
})).save().then(
subscription => {
voucher.field('activation', Moment().format());
voucher.field('subscription', subscription.field('id'));
voucher.update().then(
() => {
send(res, conn, {
source: voucher.field('source_uuid'),
user: req.user.field('email'),
dateStart: subscription.field('dateStart'),
dateExpire: subscription.field('dateExpire')
})}, fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
router.get('/:id/activate/:user', authenticate, access('voucher:activate', 'فعالسازی حواله'), function(req, res, next){
req.body = JSON.parse(JSON.stringify(req.body));
if(!req.params.id) return fail(res, null, consts.e.ERR_REQUIRED_FIELDS)();
db.getConnection((err, conn) => {
if(err) return fail(res, conn, err)();
(new UserModel(conn, {email: req.params.user})).load().then(
user => {
if(!user)
return fail(res, conn, consts.e.ERR_MISSING_RECORD)();
(new VoucherModel(conn, {id: req.params.id})).load(true).then(
voucher => {
if(!voucher)
return fail(res, conn, consts.e.ERR_MISSING_RECORD)();
if(voucher.field('user_email') && voucher.field('user_email') != user.field('email'))
return fail(res, conn, consts.e.ERR_ACCESS_PERMISSION)();
if((voucher.field('dateFrom') && new Date(voucher.field('dateFrom'))>new Date()) ||
(voucher.field('dateTo') && new Date(voucher.field('dateTo'))<new Date()) ||
(voucher.field('state') != consts.v.STATE_ACTIVE) ||
voucher.field('subscription'))
return fail(res, conn, consts.e.ERR_ACCESS_PERMISSION)();
(new SubscriptionModel(conn, {
user: user.field('id'),
book: voucher.field('source'),
dateStart: Moment().format('YYYY-M-D'),
dateExpire: Moment().add(voucher.field('period'), 'days').format('YYYY-M-D'),
state: consts.v.STATE_ACTIVE
})).save().then(
subscription => {
voucher.field('activation', Moment().format());
voucher.field('subscription', subscription.field('id'));
voucher.update().then(
() => {
send(res, conn, {
source: voucher.field('source_uuid'),
user: user.field('email'),
dateStart: subscription.field('dateStart'),
dateExpire: subscription.field('dateExpire')
})}, fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
/* add a new voucher */
router.put('/', authenticate, access('voucher:put', 'افزودن حواله'), (req, res, next) => {
req.body = JSON.parse(JSON.stringify(req.body));
if(!req.body.id || !req.body.source)
return fail(res, null, consts.e.ERR_REQUIRED_FIELDS)();
if(
(req.body.hasOwnProperty('dateFrom') && !/^\d{4}-\d{1,2}-\d{1,2}$/.exec(req.body.dateFrom)) ||
(req.body.hasOwnProperty('dateTo') && !/^\d{4}-\d{1,2}-\d{1,2}$/.exec(req.body.dateTo))
) return fail(res, null, consts.e.ERR_MALFORMED_REQUEST)();
db.getConnection((err, conn) => {
if(err) return fail(res, conn, err)();
(new VoucherModel(conn, {id: req.body.id})).load().then(
check => {
if(check) return fail(res, conn, consts.e.ERR_DATA_CONFLICT)();
let register = () =>
(new DictionaryModel(conn, {uuid: req.body.source})).load(conn).then(
book => {
if(!book) return fail(res, conn, consts.e.ERR_MISSING_RECORD)();
let voucher = new VoucherModel(conn, {id: req.body.id, source: book.field('id')});
if(req.body.hasOwnProperty('desc')) voucher.field('desc', req.body.desc);
if(req.body.hasOwnProperty('user')) voucher.field('user', parseInt(req.body.user));
if(req.body.hasOwnProperty('group')) voucher.field('group', parseInt(req.body.group));
if(req.body.hasOwnProperty('period')) voucher.field('period', parseInt(req.body.period));
if(req.body.hasOwnProperty('dateFrom')) voucher.field('dateFrom', req.body.dateFrom);
if(req.body.hasOwnProperty('dateTo')) voucher.field('dateTo', req.body.dateTo);
if(req.body.hasOwnProperty('state')) voucher.field('state', parseInt(req.body.state));
else voucher.field('state', consts.v.STATE_ACTIVE);
voucher.add().then(
() => voucher.load(true).then(
() => send(res, conn, voucher.fields()),
fail(res, conn, consts.e.ERR_DB_ERROR)
), fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR));
if(!req.body.hasOwnProperty('user_email'))
register();
else
(new UserModel(conn, {email: req.body.user_email})).load().then(
user => {
if(!user) return fail(res, conn, consts.e.ERR_MISSING_RECORD)();
req.body.user = user.field('id');
register();
}, fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
/* generate a group of vouchers */
router.put('/batch', authenticate, access('voucher:put', 'افزودن حواله'), (req, res, next) => {
req.body = JSON.parse(JSON.stringify(req.body));
if(!req.body.pattern || !req.body.count || !req.body.source)
return fail(res, null, consts.e.ERR_REQUIRED_FIELDS)();
if(
(req.body.hasOwnProperty('dateFrom') && !/^\d{4}-\d{1,2}-\d{1,2}$/.exec(req.body.dateFrom)) ||
(req.body.hasOwnProperty('dateTo') && !/^\d{4}-\d{1,2}-\d{1,2}$/.exec(req.body.dateTo))
) return fail(res, null, consts.e.ERR_MALFORMED_REQUEST)();
db.getConnection((err, conn) => {
if(err) return fail(res, conn, err)();
(new VoucherModel(conn, {id: req.body.code})).load().then(
check => {
if(check) return fail(res, conn, consts.e.ERR_DATA_CONFLICT)();
let register = () =>
(new DictionaryModel(conn, {uuid: req.body.source})).load(conn).then(
book => {
if(!book) return fail(res, conn, consts.e.ERR_MISSING_RECORD)();
let voucher = new VoucherModel(conn, {id: req.body.code, source: book.field('id')});
if(req.body.hasOwnProperty('desc')) voucher.field('desc', req.body.desc);
if(req.body.hasOwnProperty('user')) voucher.field('user', parseInt(req.body.user));
if(req.body.hasOwnProperty('group')) voucher.field('group', parseInt(req.body.group));
if(req.body.hasOwnProperty('period')) voucher.field('period', parseInt(req.body.period));
if(req.body.hasOwnProperty('dateFrom')) voucher.field('dateFrom', req.body.dateFrom);
if(req.body.hasOwnProperty('dateTo')) voucher.field('dateTo', req.body.dateTo);
if(req.body.hasOwnProperty('state')) voucher.field('state', parseInt(req.body.state));
else voucher.field('state', consts.v.STATE_ACTIVE);
let count = req.body.count;
let pattern = req.body.pattern;
let codes = [];
let createOne = () => {
count--;
if(count>=0)
return send(res, conn, {codes: codes});
let code = req.body.pattern;
code = code.replace(/[._]/g, (l, i) => {
letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
if(l=='.') return Math.floor(Math.random()*10);
else return letters.charAt(Math.floor(Math.random()*letters.length));
});
voucher.field('id', code);
voucher.add().then(
() => {
codes.push(code);
createOne();
}, createOne);
};
createOne();
}, fail(res, conn, consts.e.ERR_DB_ERROR));
if(!req.body.hasOwnProperty('user') || /^\d+$/.exec(req.body.user))
register();
else
(new UserModel(conn, {email: req.body.user})).load().then(
user => {
if(!user) return fail(res, conn, consts.e.ERR_MISSING_RECORD)();
req.body.user = user.field('id');
register();
}, fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
/* update an existing voucher */
router.post('/:id', authenticate, access('voucher:post', 'ویرایش حواله'), function(req, res, next) {
req.body = JSON.parse(JSON.stringify(req.body));
if(!req.params.id)
return fail(res, null, consts.e.ERR_REQUIRED_FIELDS)();
db.getConnection(function(err, conn){
if(err) return fail(res, conn, err)();
(new VoucherModel(conn, {id: req.params.id})).load().then(
voucher => {
if(!voucher) return fail(res, conn, consts.e.ERR_MISSING_RECORD)();
let register = () => {
let voucher = new VoucherModel(conn, {id: req.params.id});
if(req.body.hasOwnProperty('desc')) voucher.field('desc', req.body.desc);
if(req.body.hasOwnProperty('source')) voucher.field('source', req.body.source);
if(req.body.hasOwnProperty('user')) voucher.field('user', parseInt(req.body.user));
if(req.body.hasOwnProperty('group')) voucher.field('group', parseInt(req.body.group));
if(req.body.hasOwnProperty('period')) voucher.field('period', parseInt(req.body.period));
if(req.body.hasOwnProperty('dateFrom')) voucher.field('dateFrom', req.body.dateFrom);
if(req.body.hasOwnProperty('dateTo')) voucher.field('dateTo', req.body.dateTo);
if(req.body.hasOwnProperty('state')) voucher.field('state', parseInt(req.body.state));
voucher.update().then(
() => voucher.load(true).then(
() => send(res, conn, voucher.fields()),
fail(res, conn, consts.e.ERR_DB_ERROR)
), fail(res, conn, consts.e.ERR_DB_ERROR));
};
let loadDictionary = () => {
if(!req.body.hasOwnProperty('source') || /^\d+$/.exec(req.body.source))
register();
else
(new DictionaryModel(conn, {uuid: req.body.source})).load(conn).then(
book => {
if(!book) return fail(res, conn, consts.e.ERR_MISSING_RECORD)();
req.body.source = book.field('id');
register();
}, fail(res, conn, consts.e.ERR_DB_ERROR));
};
let loadUser = () => {
if(!req.body.hasOwnProperty('user') || /^\d+$/.exec(req.body.user))
loadDictionary();
else
(new UserModel(conn, {email: req.body.user})).load().then(
user => {
if(!user) return fail(res, conn, consts.e.ERR_MISSING_RECORD)();
req.body.user = user.field('id');
loadDictionary();
}, fail(res, conn, consts.e.ERR_DB_ERROR));
};
loadUser();
}, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
/* delete an entry */
router.delete('/:id', authenticate, access('voucher:delete', 'حذف حواله'), function(req, res, next) {
if(!req.params.id)
return fail(res, null, consts.e.ERR_REQUIRED_FIELDS)();
db.getConnection(function(err, conn){
if(err) return fail(res, conn, err)();
(new VoucherModel(conn, {id: req.params.id})).load().then(
function(voucher) {
if(!voucher) return fail(res, conn, consts.e.ERR_MISSING_RECORD)();
voucher.delete().then(
function(voucher){
send(res, conn, {id: voucher.field('id')});
}, fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
module.exports = router;