Built motion from commit 5e31ea4.|0.0.32
[motion.git] / server / api / custom_report / custom_report.controller.js
1 'use strict';
2
3 var _ = require('lodash');
4 var util = require('util');
5 var sequelize = require('../../models').sequelize;
6 var CustomReport = require('../../models').CustomReport;
7 var ReportField = require('../../models').ReportField;
8 var ExtractedReport = require('../../models').ExtractedReport;
9 var extractUtils = require('../../utils/report_extraction');
10
11 // Get list of custom reports
12 exports.index = function(req, res, next) {
13
14   var attributes = ['name', 'description', 'parent'];
15   var per_page = req.query.per_page ? parseInt(req.query.per_page, 10) : 100;
16   var page = req.query.page ? parseInt(req.query.page, 10) : 0;
17
18   var query = {
19     where: {},
20     limit: per_page,
21     offset: page * per_page
22   };
23
24   _.forIn(req.query, function(value, key) {
25     switch (key) {
26       case 'per_page':
27       case 'page':
28         break;
29       case 'sort_by':
30         query.order = util.format('%s %s', req.query.sort_by, req.query.sort_order || 'ASC') || null;
31         break;
32       case 'sort_order':
33         break;
34       case '$':
35         query.where.$or = [];
36         attributes.forEach(function(attribute) {
37           var tmp = {};
38           tmp[attribute] = {
39             $like: '%' + value + '%'
40           };
41
42           query.where.$or.push(tmp);
43         });
44         break;
45       case 'role':
46         query.where.role = {
47           $or: value.split(/[\s,]+/)
48         };
49         break;
50       case 'clientQuery':
51         var params = JSON.parse(value);
52         _.forOwn(params, function(pValue, pKey) {
53           query.where[pKey] = pValue;
54         });
55         break;
56       default:
57         query.where[key] = {
58           $like: {}
59         };
60         query.where[key].$like = '%' + value + '%';
61     }
62   });
63
64   CustomReport
65     .findAndCountAll(query)
66     .then(function(result) {
67       var total_pages = Math.ceil(result.count / per_page);
68       var next_page = total_pages > (query.offset + 1) ? util.format('%s://%s%s?page=%d', req.protocol, req.headers.host, req.baseUrl, page + 1) : null;
69       var previous_page = page > 0 ? util.format('%s://%s%s?page=%d', req.protocol, req.headers.host, req.baseUrl, page - 1) : null;
70
71       res.status(200).send({
72         count: result.count,
73         rows: result.rows,
74         next_page: next_page,
75         previous_page: previous_page,
76         total_pages: total_pages
77       });
78
79     })
80     .catch(function(err) {
81       res.status(500).send({
82         error: 'Something blew up!'
83       });
84     });
85 };
86
87 exports.preview = function(req, res) {
88   CustomReport
89     .findById(req.params.id, {
90       include: [{
91         all: true
92       }]
93     })
94     .then(function(report) {
95       console.log('found report');
96       if (!report) {
97         return res.sendStatus(404);
98       }
99       var query = buildReport(report.dataValues, req.query);
100       // console.log(query);
101       var queries = [sequelize.query(query, {
102         type: sequelize.QueryTypes.SELECT
103       })];
104       if (req.query.uiPagination) {
105         var countQuery = buildReport(report.dataValues, req.query, true);
106         queries.push(sequelize.query(countQuery, {
107           type: sequelize.QueryTypes.SELECT
108         }));
109       }
110       return queries;
111     })
112     .all()
113     .spread(function(results, totalItems) {
114       console.log(results.length);
115       console.log(totalItems);
116       res.status(200).send({
117         rows: results,
118         count: totalItems ? totalItems[0] : null
119       });
120     })
121     .catch(function(err) {
122       console.log(err);
123       return handleError(res, err);
124     });
125 };
126
127 exports.extractPdf = function(req, res) {
128   // console.log('extractPdf api function');
129   docExtract(req, res, 'PDF')
130 };
131
132 exports.extractCsv = function(req, res) {
133   // console.log('extractCsv api function');
134   docExtract(req, res, 'CSV');
135 };
136
137 function docExtract(req, res, typeFunction) {
138   // console.log('common docExtract api function');
139   if (!req.body.startDate || !req.body.endDate) {
140     return res.status(500).send({
141       message: 'MESSAGE_START_OR_END_DATE_MISSING'
142     });
143   }
144   CustomReport
145     .findById(req.params.id, {
146       include: [{
147         all: true
148       }]
149     })
150     .then(function(report) {
151       if (!report) {
152         return res.sendStatus(404);
153       }
154       // console.log('found the report, creating the new DB row for extracted reports..');
155       //CREATE A DB ROW IN A TABLE WITH THE REPORT INFO, QUERY DATES, AND THE STATUS 'ELABORATING'
156       return [report, ExtractedReport.create({
157         name: report.name,
158         startDate: req.body.startDate,
159         endDate: req.body.endDate,
160         output: typeFunction
161       })]
162     })
163     .spread(function(report, extractedReport) {
164       // console.log('created new extracted reports db entry, calling external extraction function: ' + typeFunction);
165       extractUtils['extract' + typeFunction](report, req.body.startDate, req.body.endDate, extractedReport.id);
166     })
167     .catch(function(err) {
168       console.log(err);
169       return handleError(res, err);
170     });
171   return res.sendStatus(200);
172 }
173
174 // Get a single report
175 exports.show = function(req, res) {
176   CustomReport
177     .findById(req.params.id, {
178       include: [{
179         all: true
180       }]
181     })
182     .then(function(report) {
183       if (!report) {
184         return res.sendStatus(404);
185       }
186       return res.send(report);
187     })
188     .catch(function(err) {
189       return handleError(res, err);
190     });
191 };
192
193 // Copy a custom report
194 exports.copy = function(req, res) {
195   CustomReport
196     .findById(req.params.id, {
197       include: [{
198         all: true
199       }]
200     })
201     .then(function(report) {
202       if (!report) {
203         return res.sendStatus(404);
204       }
205       var newReport = report.dataValues;
206       delete newReport.id;
207       delete newReport.createdAt;
208       delete newReport.updatedAt;
209       newReport.parent = req.body.parent;
210       newReport.Fields = _.pluck(newReport.Fields, 'dataValues');
211       _.forEach(newReport.Fields, function(elem) {
212         delete elem.id;
213         delete elem.CustomReportId;
214         delete elem.createdAt;
215         delete elem.updatedAt;
216       });
217
218       return CustomReport.create(newReport, {
219         include: [{
220           all: true
221         }]
222       });
223     })
224     .then(function() {
225       return res.sendStatus(201);
226     })
227     .catch(function(err) {
228       console.log(err);
229       return handleError(res, err);
230     });
231 };
232
233 // Import a report
234 exports.import = function(req, res) {
235   CustomReport
236     .create(req.body, {
237       include: [{
238         all: true
239       }]
240     })
241     .then(function(report) {
242       return res.status(201).send(report);
243     })
244     .catch(function(err) {
245       return handleError(res, err);
246     });
247 };
248
249 function buildReport(report, query, count) {
250   var fields = [],
251     groupBy = [],
252     orderBy = [];
253   _.forEach(report.Fields, function(elem) {
254     var field = '';
255     if (elem.function) {
256       switch (elem.function) {
257         case 'COUNT DISTINCT':
258           field = util.format('COUNT(DISTINCT %s)', elem.field);
259           break;
260         case 'GROUP_CONCAT ASC':
261           field = util.format('GROUP_CONCAT(%s ORDER BY %s ASC)', elem.field, elem.field);
262           break;
263         case 'GROUP_CONCAT DESC':
264           field = util.format('GROUP_CONCAT(%s ORDER BY %s DESC)', elem.field, elem.field);
265           break;
266         default:
267           field = util.format('%s(%s)', elem.function, elem.field);
268       }
269     } else {
270       field = elem.field;
271     }
272     fields.push(util.format('%s AS \'%s\'', field, elem.alias));
273     if (elem.groupBy) {
274       groupBy.push(elem.field);
275     }
276     if (elem.orderBy) {
277       orderBy.push(util.format('%s %s', elem.field, elem.orderBy));
278     }
279   });
280   var conditions = getConditions(JSON.parse(report.conditions).group);
281   var resultQuery = 'SELECT';
282   // query += fields.length ? ' ' + fields.join(',') : ' *';//right if you want to select all fields also
283   resultQuery += ' ' + fields.join(','); //generate a wrong query if there isn' t any field
284   if (count) {
285     resultQuery += ',COUNT(*)';
286   }
287   resultQuery += ' FROM ' + report.table;
288   resultQuery += conditions !== '()' ? ' WHERE ' + conditions : '';
289   var limit = false;
290   var offset = false;
291   if (query) {
292     _.forOwn(query, function(value, key) {
293       switch (key) {
294         case 'page':
295           if (query.perPage) {
296             limit = parseInt(query.perPage, 10);
297             offset = parseInt(value, 10) * limit;
298           }
299           break;
300         case 'perPage':
301           limit = parseInt(value, 10);
302           break;
303         case 'startDate':
304           resultQuery += ' AND createdAt >= \'' + value + '\'';
305           break;
306         case 'endDate':
307           resultQuery += ' AND createdAt <= \'' + value + '\'';
308           break;
309         case 'uiPagination':
310           break;
311         default:
312           var column = _.find(report.Fields, {
313             alias: key
314           }).field;
315           if (column) {
316             resultQuery += ' AND ' + column + ' LIKE \'%' + value + '%\'';
317           } else {
318             resultQuery += ' AND ' + key + ' LIKE \'%' + value + '%\'';
319           }
320       }
321     });
322   }
323   resultQuery += groupBy.length ? ' GROUP BY ' + groupBy.join(',') : '';
324   resultQuery += orderBy.length ? ' ORDER BY ' + orderBy.join(',') : '';
325   resultQuery += limit && !count ? ' LIMIT ' + limit : '';
326   resultQuery += offset && !count ? ' OFFSET ' + offset : '';
327   return resultQuery;
328 }
329
330 function getConditions(group) {
331   if (!group) return "";
332   for (var str = "(", i = 0; i < group.rules.length; i++) {
333     i > 0 && (str += " " + group.operator + " ");
334     str += group.rules[i].group ?
335       getConditions(group.rules[i].group) :
336       group.rules[i].field + " " + group.rules[i].condition + " '" + (group.rules[i].condition === 'LIKE' ? "%" + group.rules[i].value + "%" : group.rules[i].value) + "'";
337   }
338
339   return str + ')';
340 }
341
342 // Creates a new report in the DB.
343 exports.create = function(req, res) {
344   CustomReport
345     .create(req.body)
346     .then(function(report) {
347       return res.status(201).send(report);
348     })
349     .catch(function(err) {
350       return handleError(res, err);
351     });
352 };
353
354 // Updates an existing report in the DB.
355 exports.update = function(req, res) {
356   if (req.body.id) {
357     delete req.body.id;
358   }
359   ReportField.destroy({
360       where: {
361         CustomReportId: req.params.id
362       }
363     })
364     .then(function() {
365       return ReportField.bulkCreate(req.body.Fields);
366     })
367     .then(function() {
368       delete req.body.Fields;
369       return CustomReport.update(req.body, {
370         where: {
371           id: req.params.id
372         }
373       });
374     })
375     .then(function() {
376       return res.sendStatus(200);
377     })
378     .catch(function(err) {
379       console.log(err);
380       return handleError(res, err);
381     });
382 };
383
384 // Deletes a report from the DB.
385 exports.destroy = function(req, res) {
386   CustomReport
387     .findById(req.params.id)
388     .then(function(report) {
389       if (!report) {
390         return res.sendStatus(404);
391       }
392       report.destroy()
393         .then(function() {
394           return res.sendStatus(204);
395         })
396         .catch(function(err) {
397           return handleError(res, err);
398         });
399     })
400     .catch(function(err) {
401       return handleError(res, err);
402     });
403 };
404
405 exports.bulkDestroy = function(req, res) {
406   CustomReport
407     .destroy({
408       where: {
409         id: req.query.id
410       },
411       individualHooks: true
412     })
413     .then(function() {
414       return res.sendStatus(204);
415     })
416     .catch(function(err) {
417       return handleError(res, err);
418     });
419 };
420
421 function handleError(res, err) {
422   return res.status(500).send(err);
423 }