File: /var/dev/farhangmoaser/web/routes/api/1.0/subscription.js
/**
* Express endpoints for /subscription address
* Version: 0.1
* Author: Babak Vandad
*
* Restful api for these addresses:
* GET /subscription/me
* GET /subscription/:id
* GET /subscription/
* PUT /subscription/
* POST /subscription/:id
* DELETE /subscription/:id
*/
var express = require('express');
var router = express.Router();
var path = require('path');
var consts = require(path.join(BASEDIR, 'consts'));
var authHelper = require(path.join(BASEDIR, 'helpers/auth'));
var DictionaryModel = require(path.join(BASEDIR, 'models/dictionary'));
var SubscriptionModel = require(path.join(BASEDIR, 'models/subscription'));
var UserAccessModel = require(path.join(BASEDIR, 'models/userAccess'));
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){
conn.release();
if(data)
res.json(data);
else
res.end();
};
/**
* makes a searchable string (does not remove spaces)
* @param {string} str user input or given entry title
* @return {string} searchable string
*/
var simplifyString = function(str){
return str
.trim()
.toLowerCase()
.replace(/[\t'\-! ()]/g, '')
.replace(/ +/g, ' ')
.replace(/[ًٌٍَُِّْـ.]/g, '')
.replace(/ي/g, 'ی')
.replace(/ى/g, 'ی')
.replace(/ك/g, 'ک')
.replace(/[àâä]/g, 'a')
.replace(/æ/g, 'ae')
.replace(/[îï]/g, 'i')
.replace(/[éèêë]/g, 'e')
.replace(/[ôö]/g, 'o')
.replace(/œ/g, 'oe')
.replace(/[ùûü]/g, 'u')
.replace(/ç/g, 'c')
.replace(/ñ/g, 'n')
.replace(/ÿ/g, 'y')
;
};
/* list subscriptions of the current user */
router.get('/me', authenticate, access('subscription:get-me', 'کاربر سابقه اشتراکهای خود را مشاهده کند'), async (req, res, next) => {
if(!req.user || !req.isAuthenticated()) return fail(res, null, consts.e.ERR_AUTH)();
let conn;
try {
conn = await db.getConnectionPromise();
}catch(err) { return fail(res, conn, consts.e.ERR_DB_ERROR)(); }
var query = {};
query.user = req.user.field('email');
if(req.query.hasOwnProperty('book')) query.book = parseInt(req.query.book);
if(req.query.hasOwnProperty('record')) query.record = parseInt(req.query.record);
if(req.query.hasOwnProperty('minDate')) query['>=dateExpire'] = req.query.minDate;
if(req.query.hasOwnProperty('date')) {
query['>=dateExpire'] = req.query.date;
query['<=dateStart'] = req.query.date;
}
if(req.query.hasOwnProperty('maxDate')) query['<=dateStart'] = req.query.maxDate;
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;
try {
let records = await SubscriptionModel.list(conn, query, limit, offset, req.query.orderBy);
// list of records based on criteria
let response = [];
let sum = await SubscriptionModel.count(conn, query)
records.forEach(record => {
delete record.user_searchable;
delete record.user_sortable;
delete record.created;
delete record.id;
delete record.record;
delete record.source_id;
delete record.user_id;
});
send(res, conn, {sum: sum, list: records});
}catch(e) {
fail(res, conn, consts.e.ERR_DB_ERROR)();
}
});
/* load a subscription by id */
router.get('/:id', authenticate, access('subscription:get-id', 'نمایش فهرست اشتراکهای یک کاربر'), function(req, res, next){
if(!req.params.id) return fail(res, null, consts.e.ERR_REQUIRED_FIELDS)('id is required.');
reqid = parseInt(req.params.id);
if(isNaN(reqid)) return fail(res, null, consts.e.ERR_MALFORMED_REQUEST)('requested id is not a number.');
db.getConnection(function(err, conn){
if(err) return fail(res, conn, err)();
var subscriptionModel = new SubscriptionModel(conn, {id: reqid});
subscriptionModel.load().then(
function(subscription){
if(!subscription) return fail(res, conn, consts.e.ERR_MISSING_RECORD)();
send(res, conn, subscription.fields());
}, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
/* list all subscriptions */
router.get('/', authenticate, access('subscription:get', 'نمایش فهرست اشتراکها'), function(req, res, next){
db.getConnection(function(err, conn){
if(err) return fail(res, conn, err)();
var query = {};
if(req.query.hasOwnProperty('user')) query.user = req.query.user;
if(req.query.hasOwnProperty('book')) query.book = req.query.book;
if(req.query.hasOwnProperty('record')) query.record = parseInt(req.query.record);
if(req.query.hasOwnProperty('state')) query.state = parseInt(req.query.state);
if(req.query.hasOwnProperty('minDate')) query['>=dateExpire'] = req.query.minDate;
if(req.query.hasOwnProperty('date')) {
query['>=dateExpire'] = req.query.date;
query['<=dateStart'] = req.query.date;
}
if(req.query.hasOwnProperty('maxDate')) query['<=dateStart'] = req.query.maxDate;
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;
if(req.query.hasOwnProperty('displayname'))
query['%%user_searchable'] = '%'+simplifyString(req.query.displayname)+'%';
if(req.query.hasOwnProperty('user') && (/^%/.exec(req.query.user) || /%$/.exec(req.query.user))){
delete query.user;
query['%%user'] = simplifyString(req.query.user);
}
// list of records based on criteria
var listQuery = function(records) {
var response = [];
return SubscriptionModel.count(conn, query).then(
function(sum) {
send(res, conn, {sum: sum, list: records});
}, fail(res, conn, consts.e.ERR_DB_ERROR));
};
SubscriptionModel.list(conn, query, limit, offset, req.query.orderBy).then(
listQuery, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
/* add a new subscription record */
router.put('/', authenticate, access('subscription:put', 'افزودن اشتراک'), function(req, res, next) {
if(!req.body.user || !req.body.book || !req.body.dateStart || !req.body.dateExpire)
return fail(res, null, consts.e.ERR_REQUIRED_FIELDS)();
db.getConnection(function(err, conn){
if(err) return fail(res, conn, err)();
(new UserModel(conn, {email: req.body.user})).load().then(
function(user) {
if(!user) return fail(res, conn, consts.ERR_MISSING_RECORD)();
(new DictionaryModel(conn, {uuid: req.body.book})).load().then(
function(book) {
if(!book) return fail(res, conn, consts.ERR_MISSING_RECORD)();
var data = {
user: user.field('id'),
book: book.field('id'),
dateStart: req.body.dateStart,
dateExpire: req.body.dateExpire,
}
if(req.body.record)
data.record = parseInt(req.body.record);
if(req.body.state)
data.state = parseInt(req.body.state);
var subscriptionModel = new SubscriptionModel(conn, data);
subscriptionModel.save().then(
function(subscription) {
subscription.load().then(
function() {
send(res, conn, subscription.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));
}, fail(res, conn, consts.e.ERR_DB_ERROR));
});
});
/* update an existing subscription record */
router.post('/:id', authenticate, access('subscription:post-id', 'ویرایش اطلاعات اشتراک'), function(req, res, next) {
if(!req.params.id)
return fail(res, null, consts.e.ERR_REQUIRED_FIELDS)();
reqid = parseInt(req.params.id);
if(isNaN(reqid)) return fail(res, null, consts.e.ERR_MALFORMED_REQUEST)('requested id is not a number.');
db.getConnection(function(err, conn){
if(err) return fail(res, conn, err)();
var subscriptionModel = new SubscriptionModel(conn, {id: reqid});
subscriptionModel.load(true).then(
function(subscription){
if(!subscription) return fail(res, conn, consts.e.ERR_MISSING_RECORD)();
// ignore user and book and record from request. only dates and state may be updated
if(req.body.hasOwnProperty('dateStart')) subscription.field('dateStart', req.body.dateStart);
if(req.body.hasOwnProperty('dateExpire')) subscription.field('dateExpire', req.body.dateExpire);
if(req.body.hasOwnProperty('state')) subscription.field('state', parseInt(req.body.state));
subscription.save().then(
function(subscription){
req.body.id = parseInt(req.params.id);
send(res, conn, req.body);
}, fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR)
);
});
});
/* delete a subscription record */
router.delete('/:id', authenticate, access('subscription:delete-id', 'حذف اشتراک'), 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)();
var subscriptionModel = new SubscriptionModel(conn, {id: parseInt(req.params.id)});
subscriptionModel.load(true).then(
function(subscription){
if(!subscription) return fail(res, conn, consts.e.ERR_MISSING_RECORD)();
subscription.delete().then(
function(){
send(res, conn, {id: req.params.id});
}, fail(res, conn, consts.e.ERR_DB_ERROR));
}, fail(res, conn, consts.e.ERR_DB_ERROR)
);
});
});
module.exports = router;