zet-lib 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/zRoute.js ADDED
@@ -0,0 +1,3226 @@
1
+ /**
2
+ * For default route controller
3
+ * service for routes
4
+ */
5
+ const excelToJson = require('convert-excel-to-json');
6
+ const qs = require('qs');
7
+ //for generate PDF
8
+ const puppeteer = require('puppeteer');
9
+ const ejs = require('ejs');
10
+ const Util = require('./Util');
11
+ const connection = require('./connection');
12
+ const gridTable = 'zgrid';
13
+ const fs = require('fs-extra');
14
+ const io = require('./io');
15
+ const myCache = require('./cache');
16
+ const moment = require('moment');
17
+ const debug = require("./debug");
18
+ const moduleLib = require("./moduleLib");
19
+ const cForm = require("./Form");
20
+ const config = require('dotenv').config();
21
+ //const dirRoot = process.env.dirRoot;
22
+
23
+ const zRoute = {};
24
+
25
+ zRoute.tableHasNoCompanyId = ['zcompany', 'zrole', 'zgrid'];
26
+
27
+ //get all models
28
+ zRoute.MYMODELS = () => {
29
+ let obj = {};
30
+ const dir = `${dirRoot}/models`;
31
+ let models = Util.getAllFiles(dir);
32
+ for (const item of models) {
33
+ let name = item.replace('.js', '');
34
+ obj[name] = require(`${dir}/${name}`)
35
+ }
36
+ return obj;
37
+ };
38
+
39
+ //get all routes
40
+ zRoute.ROUTES = () => {
41
+ let arr = [];
42
+ const dir = `${dirRoot}/routes`;
43
+ let routes = Util.getAllFiles(dir);
44
+ for (const item of routes) {
45
+ let name = item.replace('.js', '');
46
+ if (name != "index"){
47
+ arr.push(name)
48
+ }
49
+ }
50
+ return arr;
51
+ };
52
+
53
+ /*
54
+ Auto updated_at,created_at,company_id,created_by,updated_by
55
+ */
56
+ zRoute.commons = (req, res, type = "create") => {
57
+ let data = {
58
+ company_id: res.locals.companyId,
59
+ created_at: Util.now(),
60
+ updated_at: Util.now(),
61
+ created_by: res.locals.userId,
62
+ updated_by: res.locals.userId
63
+ };
64
+ if (type != "create") {
65
+ delete data.created_at;
66
+ delete data.created_by;
67
+ return data;
68
+ } else {
69
+ return data;
70
+ }
71
+ };
72
+
73
+ /*
74
+ post data handling
75
+ */
76
+ zRoute.postData = (obj) => {
77
+ return qs.parse(obj);
78
+ };
79
+
80
+ zRoute.post = (req, res, MYMODEL, routeName, body) => {
81
+ routeName = routeName || MYMODEL.routeName;
82
+ body = body || req.body;
83
+ let post = qs.parse(body);
84
+ let isEmptyFiles = Util.isEmptyObject(req.files);
85
+ let time = new Date().getTime();
86
+ let path_tmp = dirRoot + "/public/uploads/" + routeName + "/";
87
+ let hasFile = false;
88
+ let files;
89
+ let checkboxes = [];
90
+ let multies = [];
91
+ fs.ensureDir(path_tmp, err => {
92
+ console.log('ensureDir',err); // => null
93
+ });
94
+ if (!isEmptyFiles) {
95
+ files = qs.parse(req.files);
96
+ let fileRoute = files[routeName];
97
+ for (let key in fileRoute) {
98
+ let filename = time + fileRoute[key].name;
99
+ if (Array.isArray(fileRoute[key])) {
100
+ hasFile = true;
101
+ //add folder again
102
+ fs.ensureDir(path_tmp + key, err => {
103
+ console.log('ensureDir',err); // => null
104
+ });
105
+ } else {
106
+ fileRoute[key].mv(path_tmp + filename, function (err) {
107
+ if (err) {
108
+ console.log('fileempty move',err); // => null
109
+ return res.status(500).send(err);
110
+ }
111
+ });
112
+ post[routeName][key] = filename;
113
+ }
114
+ }
115
+ }
116
+ let widgets = MYMODEL.widgets;
117
+ let tags = [];
118
+ let val;
119
+ for (let key in post[routeName]) {
120
+ let widgetName = widgets[key].name;
121
+ val = post[routeName][key];
122
+ switch (widgetName) {
123
+ case "dropdown_checkbox" :
124
+ let checkboxArr = [];
125
+ for (let k in post[routeName][key]) {
126
+ if (post[routeName][key][k] == 1) {
127
+ checkboxArr.push(k)
128
+ }
129
+ }
130
+ post[routeName][key] = JSON.stringify(checkboxArr);
131
+ break;
132
+
133
+ case "tags" :
134
+ tags.push(key);
135
+ let value = post[routeName][key] || "";
136
+ let dataValue;
137
+ if (value) {
138
+ if (typeof value == "object") {
139
+ dataValue = value;
140
+ dataValue = JSON.stringify(dataValue);
141
+ } else {
142
+ if (value.substring(0, 1) == "{") {
143
+ dataValue = `[${value.substring(1, (value.length - 1))}]`;
144
+ } else if (value.substring(0, 1) == "[") {
145
+ dataValue = value;
146
+ } else {
147
+ var arr = [];
148
+ arr.push(value);
149
+ dataValue = JSON.stringify(arr);
150
+ }
151
+ }
152
+ }
153
+ post[routeName][key] = dataValue;
154
+ break;
155
+
156
+ case "dropdown_multi" :
157
+ post[routeName][key] = JSON.stringify(post[routeName][key]);
158
+ break;
159
+
160
+ case "lexical" :
161
+ post[routeName][key] = JSON.stringify(post[routeName][key]);
162
+ //console.log(post[routeName][key]);
163
+ break;
164
+
165
+ case "table" :
166
+ const MODEL_TABLE = require('./../models/' + widgets[key].table);
167
+ const postTableData = post[routeName][key];
168
+ const widgetTables = MODEL_TABLE.widgets;
169
+ const dataTable = []
170
+ const nots = Util.nots;
171
+ const reqfiles = req.files;
172
+ if (postTableData.length) {
173
+ for (let i = 0; i < postTableData.length; i++) {
174
+ let item = postTableData[i];
175
+ for (const k in widgetTables) {
176
+ if (!Util.in_array(k, nots)) {
177
+ if (widgetTables[k].name == "number") {
178
+ item[k] = Util.toNumber(item[k]);
179
+ }
180
+ if (widgetTables[k].name == "file" || widgetTables[k].name == "image") {
181
+ var fileImageName = `${MYMODEL.table}[${key}][${i}][${k}]`;
182
+ if (reqfiles && Object.hasOwn(reqfiles, fileImageName)) {
183
+ var kname = Util.generateUnique(5) + "_" + req.files[fileImageName].name;
184
+ item[k] = kname;
185
+ req.files[fileImageName].mv(path_tmp + key + "/" + kname, function (err) {
186
+ if (err) {
187
+ return res.status(500).send(err);
188
+ }
189
+ });
190
+ }
191
+ }
192
+ }
193
+ }
194
+ }
195
+ }
196
+ post[routeName][key] = JSON.stringify(postTableData);
197
+ break;
198
+
199
+ case "multi_line_editor" :
200
+ post[routeName][key] = JSON.stringify(post[routeName][key]);
201
+ break;
202
+
203
+ case "relation" :
204
+ post[routeName][key] = val ? val : null;
205
+ break;
206
+
207
+ case "typeahead" :
208
+ post[routeName][key] = val ? val : null;
209
+ break;
210
+
211
+ case "datepicker" :
212
+ post[routeName][key] = val ? val : null;
213
+ break;
214
+
215
+ case "datetime" :
216
+ val = post[routeName][key];
217
+ post[routeName][key] = val ? val : null;
218
+ break;
219
+
220
+ case "integer" :
221
+ if (typeof val == "string") {
222
+ const onlyNumbers = val.replace(/\D/g, '');
223
+ val = parseInt(onlyNumbers);
224
+ }
225
+ post[routeName][key] = val ? val : null;
226
+ break;
227
+ }
228
+ }
229
+ //check if widget have a tag default null
230
+ for (let key in widgets) {
231
+ if (widgets[key].name == "tags") {
232
+ if (!tags.includes(key)) {
233
+ post[routeName][key] = null;
234
+ }
235
+ }
236
+ if (widgets[key].name == "table") {
237
+ if (!post[routeName][key]) {
238
+ post[routeName][key] = null;
239
+ }
240
+ }
241
+ }
242
+ return post;
243
+ };
244
+
245
+ zRoute.attributeData = async (res, MYMODEL, obj) => {
246
+ obj = obj || null;
247
+ const userId = res.locals.userId || 0;
248
+ const routeName = MYMODEL.routeName;
249
+ let attributeData, labels, visibles, invisibles, filter;
250
+ attributeData = MYMODEL;
251
+ const zgrid = await connection.results({
252
+ table: 'zgrid',
253
+ where: {user_id: userId, route_name: routeName}
254
+ });
255
+ if (zgrid.length) {
256
+ visibles = zgrid[0].visibles ? zgrid[0].visibles : MYMODEL.grids.visibles;
257
+ invisibles = zgrid[0].invisibles ? zgrid[0].invisibles : MYMODEL.grids.invisibles;
258
+ filter = zgrid[0].filter ? zgrid[0].filter : null;
259
+ } else {
260
+ visibles = MYMODEL.grids.visibles;
261
+ invisibles = MYMODEL.grids.invisibles;
262
+ filter = null;
263
+
264
+ }
265
+ attributeData.labels = MYMODEL.labels;
266
+
267
+ res.locals.routeName = routeName;
268
+ res.locals.attributeData = attributeData;
269
+ res.locals.visibles = visibles;
270
+ res.locals.invisibles = invisibles;
271
+ res.locals.gridFilter = filter;
272
+ res.locals.visiblesObj = visibles.reduce((result, item) => {
273
+ return {...result, [item]: MYMODEL.labels[item]}
274
+ }, {});
275
+ };
276
+
277
+
278
+ /*
279
+ For ajax purpose
280
+ */
281
+ zRoute.ajax = async (req, res) => {
282
+ let body = req.body;
283
+ let table = body.table;
284
+ let type = body.type;
285
+ let results;
286
+ let obj = {
287
+ table: table
288
+ };
289
+ if (body.where) {
290
+ obj.where = body.where;
291
+ }
292
+ if (body.data) {
293
+ obj.data = body.data;
294
+ }
295
+ if (!table) {
296
+ io.to(res.locals.token).emit("error", "table must be set");
297
+ return false;
298
+ }
299
+ if (!type) {
300
+ io.to(res.locals.token).emit("error", "type must be set, select insert update or delete");
301
+ return false;
302
+ }
303
+ let params = roles[res.locals.roleId].params;
304
+ if (!params.hasOwnProperty(table)) {
305
+ io.to(res.locals.token).emit("error", "You have no access to this page");
306
+ }
307
+ let MYMODEL = require(`./../models/${table}`);
308
+ if (type == "select") {
309
+ if (params[table].includes("index")) {
310
+ results = await connection.results(obj)
311
+ } else {
312
+ io.to(res.locals.token).emit("error", "You have no access to this page");
313
+ }
314
+ } else if (type == "update") {
315
+ if (params[table].includes("update")) {
316
+ results = await connection.update(obj)
317
+ } else {
318
+ io.to(res.locals.token).emit("error", "You have no access to this page");
319
+ }
320
+ } else if (type == "insert") {
321
+ if (params[table].includes("create")) {
322
+ results = await connection.insert(obj);
323
+ } else {
324
+ io.to(res.locals.token).emit("error", "You have no access to this page");
325
+ }
326
+ } else if (type == "delete") {
327
+ if (params[table].includes("delete")) {
328
+ results = await connection.delete(obj)
329
+ } else {
330
+ io.to(res.locals.token).emit("error", "You have no access to this page");
331
+ }
332
+ }
333
+ res.json({
334
+ results: results,
335
+ MYMODEL: MYMODEL
336
+ });
337
+ };
338
+
339
+ zRoute.validator = function (datas, MYMODEL) {
340
+ let obj = MYMODEL.fields;
341
+ let labels = MYMODEL.labels;
342
+ let fields = Util.requiredFields(obj);
343
+ let message = "";
344
+ let status = 1;
345
+ let field = "";
346
+ fields.map((item) => {
347
+ if (datas.hasOwnProperty(item)) {
348
+ if (!datas[item] || datas[item] == "") {
349
+ status = 0;
350
+ field = item;
351
+ message = Util.jsonError(item, labels[item] + " " + LANGUAGE.form_not_empty);
352
+ }
353
+ }
354
+ });
355
+ let widgets = MYMODEL.widgets;
356
+ let numbers = [];
357
+ for (let key in widgets) {
358
+ if (widgets[key].name == "number") {
359
+ numbers.push(key);
360
+ }
361
+ }
362
+ if (numbers.length) {
363
+ for (let key in datas) {
364
+ if (Util.in_array(key, numbers)) {
365
+ datas[key] = Util.replaceAll("" + datas[key], ".", "");
366
+ datas[key] = parseFloat(datas[key]) || 0;
367
+ }
368
+ }
369
+ }
370
+ return {
371
+ status: status,
372
+ message: message,
373
+ field: field
374
+ };
375
+ };
376
+
377
+ zRoute.selectData = (MYMODEL) => {
378
+ let widgets = MYMODEL.widgets;
379
+ let arr = [];
380
+ let data = '*';
381
+ for (let key in widgets) {
382
+ if (widgets[key].name == 'virtual') {
383
+ arr.push(widgets[key].fields);
384
+ }
385
+ }
386
+ if (arr.length) {
387
+ data += ',';
388
+ data += arr.join(',');
389
+ }
390
+ return data;
391
+ };
392
+
393
+ zRoute.relations = async (req, res, table) => {
394
+ try {
395
+ const MYMODEL = require("./../models/" + table);
396
+ let relations = {}
397
+ relations["zattributes"] = {}
398
+ relations["zvirtuals"] = {}
399
+ let typeahead = {}
400
+ let hasAttributes = false;
401
+ let zattributes = {};
402
+ let company_id = res.locals.companyId;
403
+ //f0r widgets
404
+ for (let key in MYMODEL.widgets) {
405
+ const keyRow = key + "Row";
406
+ const keyFields = key + "Fields";
407
+ const keyObject = key + "Object";
408
+ const widget = MYMODEL.widgets[key];
409
+ const widgetName = MYMODEL.widgets[key].name;
410
+ let emptyArray = Util.arrayUnShift(['id', 'zname']);
411
+
412
+ if (widgetName == "dropdown_multi") {
413
+ let obj = {
414
+ select: widget.fields.join(",") + " as zname ",
415
+ table: widget.table,
416
+ where: {company_id: company_id},
417
+ orderBy: ['zname', 'asc']
418
+ };
419
+ if (Util.in_array(widget.table, zRoute.tableHasNoCompanyId)) {
420
+ delete obj.where;
421
+ }
422
+ const cacheKey = `${obj.table}_${widget.table}___${key}_${company_id}`;
423
+ let results = {};
424
+ if (myCache.has(cacheKey)) {
425
+ results = myCache.get(cacheKey);
426
+ } else {
427
+ results = await connection.results(obj);
428
+ }
429
+ relations[key] = [Util.arrayUnShift(['id', 'zname']), ...results];
430
+ relations[keyObject] = Util.arrayWithObject(relations[key], 'id', 'zname');
431
+ } else if (widgetName == "table") {
432
+ let MODEL_TABLE = require(`./../models/${widget.table}`);
433
+ let nots = [...CONFIG.generator.notRenderField, ...['no', 'actionColumn']];
434
+ let obj = {}
435
+ let visibles = MODEL_TABLE.grids.visibles;
436
+ let invisibles = MODEL_TABLE.grids.invisibles;
437
+ let properties = {}
438
+ visibles.forEach(function (item) {
439
+ if (!Util.in_array(item, nots)) {
440
+ obj[item] = MODEL_TABLE.labels[item];
441
+ properties[item] = MODEL_TABLE.widgets[item]
442
+ }
443
+ });
444
+ invisibles.forEach(function (item) {
445
+ if (!Util.in_array(item, nots)) {
446
+ obj[item] = MODEL_TABLE.labels[item];
447
+ properties[item] = MODEL_TABLE.widgets[item]
448
+ }
449
+ });
450
+ relations[key] = obj;
451
+ relations[`properties_${key}`] = properties;
452
+ relations[keyRow] = await zRoute.relations(req, res, widget.table);
453
+ relations[key + "Table"] = widget.table;
454
+ //let MODEL_TABLE = require("./../models/" + MYMODEL.widgets[key].table);
455
+ relations[key + "TABLE"] = await zRoute.relations(req, res, MODEL_TABLE.table);
456
+
457
+ } else if (widgetName == "multi_line_editor") {
458
+ let MODEL_TABLE = require(`./../models/${widget.table}`);
459
+ relations[keyFields] = MYMODEL.widgets[key].fields;
460
+ relations[key] = await zRoute.relations(req, res, widget.table);
461
+
462
+ } else if (widgetName == "select") {
463
+ relations[key] = widget.fields;
464
+ relations[key + "Array"] = widget.array;
465
+ relations[keyFields] = widget.fields;
466
+ relations[keyObject] = Util.objectToGridFormat(relations[key], true);
467
+
468
+ } else if (widgetName == "radio") {
469
+ relations[key] = widget.fields;
470
+ relations[key + "Array"] = widget.array;
471
+ relations[keyFields] = widget.fields;
472
+ relations[keyObject] = Util.objectToGridFormat(relations[key], true);
473
+
474
+ } else if (widgetName == "relation") {
475
+ let select = widget.fields.join(",") + " as zname ";
476
+ let obj = {
477
+ select: select,
478
+ table: widget.table,
479
+ where: {company_id: company_id},
480
+ orderBy : ['zname', 'asc']
481
+ };
482
+ if (Util.in_array(widget.table, zRoute.tableHasNoCompanyId)) {
483
+ delete obj.where;
484
+ }
485
+
486
+ if (widget.hasOwnProperty("please_select")) {
487
+ if (widget.please_select != undefined) {
488
+ if (widget.please_select != "") {
489
+ emptyArray = {
490
+ 'id': '',
491
+ 'zname': widget.please_select
492
+ }
493
+ }
494
+ }
495
+ }
496
+ let cacheKey = `${widget.table}_${MYMODEL.table}___${key}_${company_id}`;
497
+ if(key == 'created_by' || key == 'updated_by') {
498
+ cacheKey = `zuser_${key}_${company_id}`;
499
+ }
500
+ let results;
501
+ if (myCache.has(cacheKey)) {
502
+ results = myCache.get(cacheKey);
503
+ } else {
504
+ results = await connection.results(obj);
505
+ }
506
+ relations[key] = [emptyArray, ...results];
507
+ relations[keyFields] = widget.fields;
508
+ relations[keyObject] = Util.arrayWithObject(relations[key], 'id', 'zname');
509
+ if (widget.isAttributes) {
510
+ zattributes[key] = Util.arrayToObject(results, "id");
511
+ hasAttributes = true;
512
+ }
513
+ } else if (widgetName == "dropdown_chain") {
514
+ const obj = {
515
+ select: widget.fields.join(",") + " as zname ",
516
+ table: widget.table,
517
+ where: {company_id: company_id},
518
+ orderBy: ['id', 'asc']
519
+ };
520
+ if (Util.in_array(widget.table, zRoute.tableHasNoCompanyId)) {
521
+ delete obj.where;
522
+ }
523
+ const cacheKey = `${widget.table}_${MYMODEL.table}___${key}_${company_id}`;
524
+ let results;
525
+ if (myCache.has(cacheKey)) {
526
+ results = myCache.get(cacheKey);
527
+ } else {
528
+ results = await connection.results(obj);
529
+ }
530
+ relations[key] = [Util.arrayUnShift(['id', 'zname']), ...results];
531
+ relations[keyFields] = widget.fields;
532
+ relations[keyObject] = Util.arrayWithObject(relations[key], 'id', 'zname');
533
+ } else if (widgetName == "typeahead") {
534
+ let select = widget.fields.join(",") + " as zname ";
535
+ let obj = {
536
+ select: select,
537
+ table: widget.table,
538
+ where: {company_id: company_id},
539
+ orderBy: ['zname', 'asc']
540
+ };
541
+ if (Util.in_array(widget.table, zRoute.tableHasNoCompanyId)) {
542
+ delete obj.where;
543
+ }
544
+ const cacheKey = `${widget.table}_${MYMODEL.table}___${key}_${company_id}`;
545
+ let results;
546
+ if (myCache.has(cacheKey)) {
547
+ results = myCache.get(cacheKey);
548
+ } else {
549
+ results = await connection.results(obj);
550
+ }
551
+ relations[key] = [Util.arrayUnShift(['id', 'zname']), ...results];
552
+ relations[keyObject] = Util.arrayWithObject(relations[key], 'id', 'zname');
553
+ relations[keyFields] = widget.fields;
554
+
555
+ } else if (widgetName == "switch") {
556
+ relations[key] = Util.modulesSwitch(widget.fields);
557
+ relations[keyFields] = widget.fields;
558
+
559
+ } else if (widgetName == "virtual") {
560
+ relations["zvirtuals"][key] = widget.fields;
561
+ }
562
+ }
563
+
564
+ let selectZvirtuals = "";
565
+ for (let key in relations["zvirtuals"]) {
566
+ selectZvirtuals += `${relations['zvirtuals'][key]} , `
567
+ }
568
+ if (selectZvirtuals) {
569
+ relations.selectZvirtuals = selectZvirtuals;
570
+ }
571
+
572
+ return relations;
573
+ } catch (err) {
574
+ debug(req, res, err);
575
+ }
576
+ };
577
+
578
+ /*
579
+ Function to create filter elements on data table grid
580
+ */
581
+
582
+ zRoute.dataTableFilterSync = async (req, res, MYMODEL, filter) => {
583
+ const relations = await zRoute.relations(req, res, MYMODEL.table);
584
+ const dataTable = zRoute.dataTableFilter(MYMODEL, relations, filter);
585
+ return dataTable;
586
+ };
587
+
588
+ zRoute.dataTableFilter = (MYMODEL, relations, filter) => {
589
+ filter = filter || {}
590
+ let filterColumns = filter.hasOwnProperty("columns") ? filter.columns : [];
591
+ let filterObject = {}
592
+ let filterKey = '';
593
+ let isFilter = false;
594
+ filterColumns.forEach(function (item) {
595
+ var value = item.search.value
596
+ if (value) {
597
+ filterKey += ` $("#data_table_${filter.fields[item.data]}").change(); `
598
+ filterObject[filter.fields[item.data]] = Util.replaceAll(value, "%", "");
599
+ isFilter = true;
600
+ }
601
+ });
602
+ if (isFilter) {
603
+ filterKey += ` $("select[name='dataTable_length']").val(${filter.length}); $("select[name='dataTable_length']").change(); `
604
+ }
605
+ let fields = MYMODEL.fields;
606
+ let widgets = MYMODEL.widgets;
607
+ let types = {}
608
+ let dataTable = {};
609
+ let options;
610
+ for (let key in fields) {
611
+ let html = '';
612
+ const value = filterObject.hasOwnProperty(key) ? filterObject[key] : "";
613
+ if (key == "id") {
614
+ types[key] = 'input';
615
+ dataTable[key] = `<input type="number" placeholder="${fields[key].title}" value="${value}" id="data_table_${key}" >`;
616
+ } else {
617
+ if (widgets.hasOwnProperty(key)) {
618
+ const widgetName = widgets[key].name;
619
+ switch (widgetName) {
620
+ case "switch" :
621
+ options = relations[key].reduce((result, item) => {
622
+ var selected = value === item.id ? " selected " : "";
623
+ return result + `<option value="${item.id}" ${selected}>${item.name}</option>`
624
+ }, "");
625
+ dataTable[key] = `<select id="data_table_${key}" class="form-control form-select" >${options}</select>`;
626
+ types[key] = 'select';
627
+ break;
628
+
629
+ case "color" :
630
+ dataTable[key] = `<input type="color" class="form-control form-control-color" value="${value}" id="data_table_${key}" >`;
631
+ types[key] = 'input';
632
+ break;
633
+
634
+ case "relation" :
635
+ options = relations[key].reduce((result, item) => {
636
+ var selected = value === item.id ? " selected " : "";
637
+ return result + `<option value="${item.id}" ${selected}>${item.zname}</option>`
638
+ }, "");
639
+ dataTable[key] = `<select id="data_table_${key}" class="form-control form-select " >${options}</select>`;
640
+ types[key] = 'select';
641
+ break;
642
+
643
+ case "dropdown_multi" :
644
+ options = relations[key].reduce((result, item) => {
645
+ var selected = value == item.id ? " selected " : "";
646
+ return result + `<option value="${item.id}" ${selected} >${item.zname}</option>`
647
+ }, "");
648
+ dataTable[key] = `<select id="data_table_${key}" class="form-control form-select " >${options}</select>`;
649
+ types[key] = 'select';
650
+ break;
651
+
652
+ case "dropdown_chain" :
653
+ options = relations[key].reduce((result, item) => {
654
+ var selected = value == item.id ? " selected " : "";
655
+ return result + `<option value="${item.id}" ${selected}>${item.zname}</option>`
656
+ }, "");
657
+ dataTable[key] = `<select id="data_table_${key}" class="form-control form-select " >${options}</select>`;
658
+ types[key] = 'select';
659
+ break;
660
+
661
+ case "select" :
662
+ let please_select = widgets[key].please_select;
663
+ options = `<option value=""> </option>`;
664
+ if (please_select != undefined) {
665
+ if (please_select != "") {
666
+ options = `<option value="">${please_select}</option>`;
667
+ }
668
+ }
669
+ for (var k in relations[key]) {
670
+ const selected = value === k ? " selected " : "";
671
+ options += `<option value="${k}" ${selected}>${relations[key][k]}</option>`;
672
+ }
673
+ dataTable[key] = `<select id="data_table_${key}" class="form-control form-select " >${options}</select>`;
674
+ types[key] = 'select';
675
+ break;
676
+
677
+ case "radio" :
678
+ options = `<option value=""> </option>`;
679
+ var items = relations[key + "Array"] || [];
680
+ if (items) {
681
+ items.forEach(function (item) {
682
+ let selected = item.value == value ? ' selected ' : '';
683
+ options += `<option value="${item.value}" ${selected}>${item.label}</option>`;
684
+ });
685
+ } else {
686
+ for (var k in relations[key]) {
687
+ let selected = value === k ? " selected " : "";
688
+ options += `<option value="${k}" ${selected}>${relations[key][k]}</option>`;
689
+ }
690
+ }
691
+ dataTable[key] = `<select id="data_table_${key}" class="form-control form-select " >${options}</select>`;
692
+ types[key] = 'select';
693
+ break;
694
+
695
+ case "typeahead" :
696
+ options = relations[key].reduce((result, item) => {
697
+ var selected = value === item.id ? " selected " : "";
698
+ return result + `<option value="${item.id}" ${selected}>${item.zname}</option>`
699
+ }, "");
700
+ dataTable[key] = `<select id="data_table_${key}" class="form-control form-select " >${options}</select>`;
701
+ types[key] = 'select';
702
+ break;
703
+
704
+ case "number" :
705
+ dataTable[key] = `<input type="text" class="form-control " value="${value}" id="data_table_${key}" >`;
706
+ types[key] = 'input';
707
+ break;
708
+
709
+ case "integer" :
710
+ dataTable[key] = `<input type="number" class="form-control " value="${value}" id="data_table_${key}" >`;
711
+ types[key] = 'input';
712
+ break;
713
+
714
+ /*case "json" :
715
+ dataTable[key] = `<input type="number" class="form-control form-control-sm" value="${value}" id="data_table_${key}" >`;
716
+ types[key] = 'input';
717
+ break;*/
718
+
719
+ case "virtual" :
720
+ dataTable[key] = ``;
721
+ break;
722
+
723
+ default :
724
+ dataTable[key] = `<input type="text" class="form-control " value="${value}" id="data_table_${key}" >`;
725
+ types[key] = 'input';
726
+ break;
727
+ }
728
+ } else {
729
+ dataTable[key] = ``;
730
+ }
731
+ }
732
+ }
733
+
734
+ dataTable.MYMODEL = MYMODEL;
735
+ dataTable.RELATIONS = relations;
736
+ dataTable.TYPES = types;
737
+ dataTable.FILTER = filter;
738
+ dataTable.FILTEROBJECT = filterObject;
739
+ dataTable.FILTERKEY = filterKey;
740
+ return dataTable;
741
+ };
742
+
743
+ zRoute.dataTableData = (key, value, MYMODEL, relations) => {
744
+ relations = relations || {}
745
+ var keyFields = key + "Fields";
746
+ var keyObject = key + "Object";
747
+ let myvalue = value;
748
+ var widgetName = MYMODEL.widgets[key] ? MYMODEL.widgets[key].name : "";
749
+ if (widgetName) {
750
+ switch (widgetName) {
751
+ case "switch" :
752
+ myvalue = relations[keyFields][value] || "";
753
+ break;
754
+
755
+ case "color" :
756
+ myvalue = `<input type="color" value="${value}">`;
757
+ break;
758
+
759
+ case "relation" :
760
+ myvalue = relations[keyObject][value] || "";
761
+ break;
762
+
763
+ case "dropdown_multi" :
764
+ let arr = value ? value : [];
765
+ if (arr.length) {
766
+ let myarr = [];
767
+ arr.forEach(function (item) {
768
+ myarr.push(relations[keyObject][item]);
769
+ });
770
+ myvalue = myarr.length ? myarr.join(", ") : "";
771
+ }
772
+ break;
773
+
774
+ case "dropdown_chain" :
775
+ myvalue = relations[key][value] || "";
776
+ break;
777
+
778
+ case "select" :
779
+ myvalue = relations[keyFields][value] || "";
780
+ break;
781
+
782
+ case "radio" :
783
+ myvalue = relations[keyFields][value] || "";
784
+ break;
785
+
786
+ case "typeahead" :
787
+ myvalue = relations[keyObject][value] || "";
788
+ break;
789
+
790
+ case "datetime" :
791
+ myvalue = Util.timeSql(value);
792
+ break;
793
+
794
+ case "datepicker" :
795
+ myvalue = Util.dateFormat(value, MYMODEL.widgets[key].format);
796
+ break;
797
+
798
+ case "number" :
799
+ myvalue = Util.formatNumber(value);
800
+ break;
801
+
802
+ case "integer" :
803
+ myvalue = parseInt(value);
804
+ break;
805
+
806
+ case "image" :
807
+ myvalue = Util.fileView("/uploads/" + MYMODEL.routeName + "/", value);
808
+ break;
809
+
810
+ case "file" :
811
+ myvalue = Util.fileView("/uploads/" + MYMODEL.routeName + "/", value);
812
+ break;
813
+
814
+ case "password" :
815
+ myvalue = "xxxxxx";
816
+ break;
817
+
818
+ case "json" :
819
+ myvalue = value ? JSON.stringify(value).replaceAll('","', '", "') : '';
820
+ break;
821
+
822
+ default :
823
+ value = value || "";
824
+ myvalue = value.length > 50 ? value.substring(0, 50) : value;
825
+ }
826
+ }
827
+ return myvalue;
828
+ };
829
+
830
+ zRoute.users = async (req) => {
831
+ if (!Object.prototype.hasOwnProperty.call(req.session, "user")) {
832
+ return [];
833
+ } else {
834
+ return await connection.query('SELECT zuser.id, zuser.fullname as zname FROM zuser LEFT JOIN zuser ON (zuser.id = zuser_company.user_id) WHERE zuser_company.company_id = ?', [req.session.user.company_id]);
835
+ }
836
+ };
837
+
838
+ zRoute.usersObj = {id: '', fullname: ''};
839
+ zRoute.usersArr = ['id', 'fullname'];
840
+ zRoute.usersDropdown = async (req) => {
841
+ return [zRoute.usersObj, ...await zRoute.users(req)];
842
+ };
843
+
844
+ zRoute.getUsers = async () => {
845
+ return Util.arrayToObject(await connection.results({table: "zuser"}), "id");
846
+ };
847
+
848
+ zRoute.changePassword = async (req, res) => {
849
+ let userId = req.session.user.id;
850
+ let query = req.body;
851
+ let passwordNow = query.passwordNow.trim();
852
+ let password = query.password.trim();
853
+ let passwordRepeat = query.passwordRepeat.trim();
854
+ let password_pattern = Util.regexPassword(6, 20)
855
+ if (!password.match(password_pattern)) {
856
+ return res.json(Util.jsonError('password', LANGUAGE.password_combine))
857
+ }
858
+ if (password != passwordRepeat) {
859
+ return res.json(Util.jsonError('password', LANGUAGE.password_equal))
860
+ }
861
+ let user = await connection.results({
862
+ table: "zuser",
863
+ where: {
864
+ id: userId,
865
+ password: Util.hash(passwordNow)
866
+ }
867
+ });
868
+ if (user.length == 0) {
869
+ return res.json(Util.jsonError('passwordNow', LANGUAGE.password_wrong))
870
+ }
871
+ let data = {
872
+ password: Util.hash(password)
873
+ };
874
+ await connection.update({
875
+ table: "zuser",
876
+ where: {
877
+ id: userId
878
+ },
879
+ data: data
880
+ });
881
+ res.json(Util.jsonSuccess(LANGUAGE.change_password_success))
882
+ };
883
+
884
+ zRoute.resetPassword = async (req, res) => {
885
+ let query = req.body;
886
+ let password = query.password;
887
+ let password_repeat = query.password_repeat.trim();
888
+ let password_pattern = Util.regexPassword(6, 20)
889
+ let forgot_password = req.params.forgot_password || "";
890
+ let json = Util.jsonError('password', LANGUAGE.link_expired);
891
+ if (forgot_password == "")
892
+ return res.json(Util.jsonError('password', LANGUAGE.link_expired))
893
+ if (!password.match(password_pattern))
894
+ return res.json(Util.jsonError('password', LANGUAGE.password_combine))
895
+ if (password != password_repeat)
896
+ return res.json(Util.jsonError('password', LANGUAGE.password_equal))
897
+
898
+ const results = await connection.results({
899
+ table: "zuser",
900
+ where: {
901
+ forgot_password: forgot_password
902
+ }
903
+ });
904
+ if (results.length > 0) {
905
+ await connection.update({
906
+ table: "zuser",
907
+ data: {
908
+ password: Util.hash(password),
909
+ forgot_password: ""
910
+ },
911
+ where: {
912
+ id: results[0].id
913
+ }
914
+ });
915
+ req.session.sessionFlash = Util.jsonSuccess(LANGUAGE.change_password_success);
916
+ json = Util.jsonSuccess(LANGUAGE.success)
917
+ } else {
918
+ json = Util.jsonError('password', LANGUAGE.link_expired)
919
+ }
920
+ res.json(json);
921
+ };
922
+
923
+ zRoute.loginAuth = async (username, fields) => {
924
+ let results = await connection.results({table: "zuser", where: {username: username}});
925
+ if (results.length) {
926
+ await connection.update({table: "zuser", data: fields, where: {id: results[0].id}});
927
+ //back to query to completed
928
+ results = await connection.results({table: "zuser", where: {id: results[0].id}})
929
+ }
930
+ return results;
931
+ };
932
+
933
+ zRoute.loginNormal = async (username, password) => {
934
+ let result = await connection.result({
935
+ table: "zuser",
936
+ where: {username: username}
937
+ });
938
+ if (!result) {
939
+ return [];
940
+ } else {
941
+ const match = Util.hashCompare(password, result.password);
942
+ if (match) {
943
+ return [result];
944
+ }
945
+ }
946
+ return [];
947
+ };
948
+
949
+ zRoute.loginAjax = async (username, password, req, res, isSocialLogin, url = "") => {
950
+ let redirect = '';
951
+ let data = {
952
+ status: 0,
953
+ url: redirect
954
+ };
955
+ try {
956
+ isSocialLogin = isSocialLogin || false;
957
+ const rows = isSocialLogin ? await zRoute.loginAuth(username, password) : await zRoute.loginNormal(username, password);
958
+ if (rows.length > 0) {
959
+ if (rows[0].active == 1) {
960
+ await zRoute.handleSession(req, rows[0]);
961
+ redirect = url == "" ? `${process.env.APP_AFTER_LOGIN}` : url;
962
+ data = {
963
+ status: 1,
964
+ url: redirect
965
+ }
966
+ } else {
967
+ data = {
968
+ status: 2,
969
+ url: redirect
970
+ }
971
+ }
972
+ }
973
+ } catch (err) {
974
+ debug(req, res, err);
975
+ res.json("Error : " + err.toString());
976
+ }
977
+ return data;
978
+ };
979
+
980
+ zRoute.login = async (username, password, req, res, isSocialLogin, url = "") => {
981
+ isSocialLogin = isSocialLogin || false;
982
+ let data = await zRoute.loginAjax(username, password, req, res, isSocialLogin, url);
983
+ let redirect = data.url;
984
+ if (data.status == 1) {
985
+ res.redirect(redirect);
986
+ } else {
987
+ req.session.sessionFlashc = 1;
988
+ res.locals.sessionFlash = 1;
989
+ res.redirect(url == "" ? process.env.APP_AFTER_LOGIN : "/" + url);
990
+ }
991
+ };
992
+
993
+ zRoute.logout = async (req, res) => {
994
+ req.session.destroy(function (err) {
995
+ if (err) console.log('/logout err', err);
996
+ res.redirect(process.env.APP_AFTER_LOGOUT);
997
+ });
998
+ };
999
+
1000
+ zRoute.handleSession = async (req, user) => {
1001
+ const company = await connection.result({
1002
+ table: "zcompany",
1003
+ where: {
1004
+ id: user.company_id
1005
+ }
1006
+ });
1007
+ const userCompany = await connection.results({
1008
+ table: "zuser_company",
1009
+ joins: [
1010
+ "LEFT JOIN zcompany ON (zcompany.id = zuser_company.company_id)"
1011
+ ],
1012
+ where: {
1013
+ "zuser_company.user_id": user.id
1014
+ }
1015
+ });
1016
+
1017
+ if (!userCompany.length) {
1018
+ req.session.user = {}
1019
+ } else {
1020
+ const userCompanyObject = Util.arrayToObject(userCompany, "company_id");
1021
+ const role = await connection.result({
1022
+ table: "zrole",
1023
+ where: {
1024
+ id: userCompanyObject[user.company_id].role_id
1025
+ }
1026
+ });
1027
+ user.roleName = role.name;
1028
+ let roleKeys = role.params ? role.params : {};
1029
+ user.roleKeys = Object.keys(roleKeys);
1030
+ user.company = company;
1031
+ user.companies = userCompany;
1032
+ req.session.user = user;
1033
+ }
1034
+ };
1035
+
1036
+ zRoute.excelQuery = async (req, res, MYMODEL) => {
1037
+ //check directory for import not export
1038
+ const dir = `${dirRoot}/public/excel/tmp`;
1039
+ if (!fs.existsSync(dir)) {
1040
+ fs.mkdirSync(dir);
1041
+ }
1042
+ //end
1043
+ let reqQuery = req.query;
1044
+ let zSearch = reqQuery.zsearch == 1 ? true : false;
1045
+ let zall = reqQuery.all == 1 ? true : false;
1046
+ let zstandart = reqQuery.zstandart == 1 ? true : false;
1047
+ await zRoute.attributeData(res, MYMODEL);
1048
+ const results = await connection.results({
1049
+ table: "zgrid",
1050
+ where: {
1051
+ route_name: MYMODEL.routeName,
1052
+ user_id: res.locals.userId
1053
+ }
1054
+ });
1055
+ let rows = [];
1056
+ let fields = [];
1057
+ let body = {};
1058
+ let select = "";
1059
+ let allfields = Object.keys(MYMODEL.widgets);
1060
+ if (results.length) {
1061
+ let result = results[0];
1062
+ body = result.filter;
1063
+ fields = body.fields.filter(item => item != "no" && item != "actionColumn");
1064
+ select = Util.selectMysql(fields);
1065
+ if (zall) {
1066
+ let difference = allfields.filter(x => !fields.includes(x));
1067
+ let arr = [...fields, ...difference];
1068
+ select = arr.join(",");
1069
+ }
1070
+ let whereArray = [];
1071
+ let columns = body.columns;
1072
+ columns.forEach(function (item) {
1073
+ if (item.search.value) {
1074
+ whereArray.push({
1075
+ field: body.fields[item.data],
1076
+ option: MYMODEL.options[body.fields[item.data]],
1077
+ value: item.search.value,
1078
+ operator: "AND"
1079
+ });
1080
+ }
1081
+ });
1082
+ const orderColumn = body.fields[body.order[0].column] == "actionColumn" ? "id" : body.fields[body.order[0].column] == "no" ? "id" : body.fields[body.order[0].column] == "actionColum" ? "id" : body.fields[body.order[0].column];
1083
+ if (zstandart) {
1084
+ select = "*";
1085
+ }
1086
+ const obj = {
1087
+ select: select,
1088
+ table: MYMODEL.table,
1089
+ whereArray: whereArray,
1090
+ /* limit: body.length,
1091
+ offset : body.start,*/
1092
+ orderBy: [orderColumn, body.order[0].dir]
1093
+ };
1094
+ if (!zall) {
1095
+ obj.limit = body.length;
1096
+ obj.offset = body.start;
1097
+ }
1098
+ rows = await connection.results(obj);
1099
+ } else {
1100
+ rows = await connection.results({
1101
+ select: Util.selectMysql(fields),
1102
+ table: MYMODEL.table,
1103
+ limit: reqQuery.pageSize,
1104
+ offset: parseInt(reqQuery.pageSize) - 1,
1105
+ orderBy: ["id", "desc"]
1106
+ });
1107
+ }
1108
+ if (zall) {
1109
+ fields = select.split(",");
1110
+ }
1111
+
1112
+ const ztype = reqQuery.ztype == 1 ? true : false;
1113
+ if (ztype) {
1114
+ await zRoute.pdf(req, res, MYMODEL, fields, rows);
1115
+ } else {
1116
+ await zRoute.excel(req, res, MYMODEL, fields, rows);
1117
+ }
1118
+ };
1119
+
1120
+ // for excels
1121
+ zRoute.excel = async (req, res, MYMODEL, fields, rows, callback, fileName) => {
1122
+ //if any other custom value then callback needed
1123
+ callback = callback || function () {};
1124
+ const Excel = require('exceljs');
1125
+ const workbook = new Excel.Workbook();
1126
+ let worksheet = workbook.addWorksheet(res.locals.routeName, {pageSetup: {paperSize: 9, orientation: 'landscape'}})
1127
+ worksheet.properties.defaultColWidth = 13;
1128
+ const params = req.query;
1129
+ const isRaws = params.zraws == 1 ? true : false;
1130
+ const sequence = Util.excelSequence();
1131
+ const labels = MYMODEL.labels;
1132
+ let start = 4, num = 1, routeName = res.locals.routeName;
1133
+ // properties
1134
+ const yellow = {
1135
+ type: 'pattern',
1136
+ pattern: 'solid',
1137
+ fgColor: {argb: 'FFFFFF00'},
1138
+ bgColor: {argb: 'FF0000FF'}
1139
+ };
1140
+ const blue = {
1141
+ type: 'pattern',
1142
+ pattern: 'solid',
1143
+ fgColor: {argb: '96C8FB'},
1144
+ bgColor: {argb: '96C8FB'}
1145
+ };
1146
+ const center = {vertical: 'middle', horizontal: 'center', wrapText: true};
1147
+ const bold = {bold: true};
1148
+ //end properties
1149
+ for (let i = 0; i < fields.length; i++) {
1150
+ worksheet.getCell(sequence[i] + '1').value = labels[fields[i]];
1151
+ worksheet.getCell(sequence[i] + '1').fill = blue;
1152
+ worksheet.getCell(sequence[i] + '1').font = bold;
1153
+ worksheet.getCell(sequence[i] + '1').alignment = center;
1154
+ }
1155
+ for (let i = 0; i < fields.length; i++) {
1156
+ worksheet.getCell(sequence[i] + '2').value = fields[i];
1157
+ worksheet.getCell(sequence[i] + '2').fill = yellow;
1158
+ worksheet.getCell(sequence[i] + '2').alignment = center;
1159
+ }
1160
+ worksheet.mergeCells('A3:' + sequence[(fields.length - 1)] + '3');
1161
+ worksheet.getCell('A3').value = 'DATA';
1162
+ worksheet.getCell('A3').font = bold;
1163
+ worksheet.getCell('A3').alignment = center;
1164
+
1165
+ //check relations
1166
+ let isRelations = false;
1167
+ let relations = [], tableObj = {}, obj = {}, dropdowns = [], passwords = [];
1168
+ let usersObj = await zRoute.getUsers();
1169
+ if (Object.prototype.hasOwnProperty.call(MYMODEL, "widgets")) {
1170
+ for (let key in MYMODEL.widgets) {
1171
+ let widget = MYMODEL.widgets[key];
1172
+ if (widget.name == "password") {
1173
+ passwords.push(key)
1174
+ } else if (widget.name == "select") {
1175
+ tableObj[key] = widget.fields;
1176
+ } else if (widget.name == "switch") {
1177
+ tableObj[key] = widget.fields;
1178
+ } else if (widget.name == "relation") {
1179
+ var rowsarr = await connection.results({
1180
+ table: widget.table,
1181
+ select: widget.fields[0] + "," + widget.fields[1] + " as zname "
1182
+ });
1183
+ //save to object
1184
+ relations[key] = Util.arrayToObject(rowsarr, "id")
1185
+ }
1186
+ }
1187
+ }
1188
+
1189
+ rows.forEach(function (result) {
1190
+ fields.forEach((field, i) => {
1191
+ let t;
1192
+ if (field == 'company_id') {
1193
+ t = !callback(result, field) ? result.company_id : callback(result, field);
1194
+ } else if (field == 'created_at' || field == 'created_at') {
1195
+ t = !callback(result, field) ? Util.timeSql(result[field]) : callback(result, field);
1196
+ } else if (field == 'updated_at' || field == 'updated_at') {
1197
+ t = !callback(result, field) ? Util.timeSql(result[field]) : callback(result, field);
1198
+ } else if (Util.in_array(field, CONFIG.generator.createdupdated_by)) {
1199
+ if (isRaws) {
1200
+ t = !callback(result, field) ? result[field] : callback(result, field);
1201
+ } else {
1202
+ t = !callback(result, field) ? usersObj[result[field]] : callback(result, field);
1203
+ }
1204
+ } else {
1205
+ // callback will call if you have
1206
+ if (Util.in_array(field, relations)) {
1207
+ if (isRaws) {
1208
+ t = !callback(result, field) ? result[field] : callback(result, field);
1209
+ } else {
1210
+ const objectData = tableObj[field] || {};
1211
+ if (!callback(result, field)) {
1212
+ if (result[field] && Object.hasOwn(objectData[result[field]], "zname")) {
1213
+ t = objectData[result[field]]["zname"];
1214
+ } else {
1215
+ t = result[field];
1216
+ }
1217
+ } else {
1218
+ t = callback(result, field);
1219
+ }
1220
+ }
1221
+ } else if (Util.in_array(field, dropdowns)) {
1222
+ t = !callback(result, field) ? MYMODEL.dropdowns[field].fields[result[field]] : callback(result, field);
1223
+ } else if (Util.in_array(field, passwords)) {
1224
+ t = 'xxxxxx';
1225
+ } else if (MYMODEL.widgets[field].name == "select") {
1226
+ if (isRaws) {
1227
+ t = !callback(result, field) ? result[field] : callback(result, field);
1228
+ } else {
1229
+ t = !callback(result, field) ? Object.hasOwn(tableObj[field], result[field]) ? tableObj[field][result[field]] : result[field] : callback(result, field);
1230
+ }
1231
+ } else if (MYMODEL.widgets[field].name == "datetime") {
1232
+ if (isRaws) {
1233
+ t = !callback(result, field) ? Util.timeSql(result[field]) : callback(result, field);
1234
+ } else {
1235
+ t = !callback(result, field) ? Util.timeSql(result[field]) : callback(result, field);
1236
+ }
1237
+ } else if (MYMODEL.widgets[field].name == "datepicker") {
1238
+ if (isRaws) {
1239
+ t = !callback(result, field) ? Util.dateFormat(result[field]) : callback(result, field);
1240
+ } else {
1241
+ t = !callback(result, field) ? Util.dateFormat(result[field]) : callback(result, field);
1242
+ }
1243
+ } else if (MYMODEL.widgets[field].name == "switch") {
1244
+ if (isRaws) {
1245
+ t = !callback(result, field) ? result[field] : callback(result, field);
1246
+ } else {
1247
+ t = !callback(result, field) ? tableObj[field][result[field]] || "" : callback(result, field);
1248
+ }
1249
+ } else if (MYMODEL.widgets[field].name == "relation") {
1250
+ if (isRaws) {
1251
+ t = !callback(result, field) ? result[field] : callback(result, field);
1252
+ } else {
1253
+ if (relations[field][result[field]]) {
1254
+ t = !callback(result, field) ? relations[field][result[field]].zname || "" : callback(result, field);
1255
+ }
1256
+ }
1257
+ } else {
1258
+ t = !callback(result, field) ? result[field] : callback(result, field);
1259
+ }
1260
+ }
1261
+ worksheet.getCell(sequence[i] + start).value = t;
1262
+ });
1263
+ start++;
1264
+ num++
1265
+ });
1266
+
1267
+ fileName = fileName || routeName + '_' + new Date().getTime() + '.xlsx'
1268
+ res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
1269
+ res.setHeader('Content-Disposition', 'attachment; filename=' + fileName);
1270
+ await workbook.xlsx.write(res);
1271
+ res.end();
1272
+ };
1273
+
1274
+ //for pdf
1275
+ zRoute.pdf = async (req, res, MYMODEL, fields, rows, callback) => {
1276
+ io.to(res.locals.token).emit("message", "Please wait, compiling..")
1277
+ callback = callback || function () {};
1278
+ let labels = MYMODEL.labels;
1279
+ let html = ``
1280
+ html += `<h2>${MYMODEL.title}</h2>`;
1281
+ html += `<br>`;
1282
+ html += `<div class="container">`
1283
+ html += `<table class="table">`;
1284
+ html += `<thead><tr>`
1285
+ for (var i = 0; i < fields.length; i++) {
1286
+ html += `<td>${labels[fields[i]]}</td>`
1287
+ }
1288
+ html += `</tr></thead>`;
1289
+ //check relations
1290
+ let isRelations = false;
1291
+ let relations = [], tableObj = {}, obj = {}, dropdowns = [], passwords = [];
1292
+ let usersObj = await zRoute.getUsers();
1293
+ if (Object.prototype.hasOwnProperty.call(MYMODEL, "widgets")) {
1294
+ for (let key in MYMODEL.widgets) {
1295
+ let widget = MYMODEL.widgets[key];
1296
+ if (widget.name == "password") {
1297
+ passwords.push(key)
1298
+ } else if (widget.name == "select") {
1299
+ tableObj[key] = widget.fields;
1300
+ } else if (widget.name == "switch") {
1301
+ tableObj[key] = widget.fields;
1302
+ } else if (widget.name == "relation") {
1303
+ const rowsarr = await connection.results({
1304
+ table: widget.table,
1305
+ select: widget.fields[0] + "," + widget.fields[1] + " as zname "
1306
+ })
1307
+ //save to object
1308
+ relations[key] = Util.arrayToObject(rowsarr, "id")
1309
+ }
1310
+ }
1311
+ }
1312
+ html += `<tbody>`;
1313
+ rows.forEach(function (result) {
1314
+ html += `<tr>`
1315
+ fields.forEach((field, i) => {
1316
+ var t;
1317
+ if (field == 'company_id') {
1318
+ t = !callback(result, field) ? result.company_id : callback(result, field);
1319
+ } else if (field == 'created_at' || field == 'created_at') {
1320
+ t = !callback(result, field) ? Util.timeSql(result[field]) : callback(result, field);
1321
+ } else if (field == 'updated_at' || field == 'updated_at') {
1322
+ t = !callback(result, field) ? Util.timeSql(result[field]) : callback(result, field);
1323
+ } else if (Util.in_array(field, CONFIG.generator.createdupdated_by)) {
1324
+ t = !callback(result, field) ? usersObj[result[field]] : callback(result, field);
1325
+ } else {
1326
+ // callback will call if you have
1327
+ if (Util.in_array(field, relations)) {
1328
+ const objectData = tableObj[field] || {};
1329
+ if (!callback(result, field)) {
1330
+ if (result[field] && Object.hasOwn(objectData[result[field]], "zname")) {
1331
+ t = objectData[result[field]]["zname"];
1332
+ } else {
1333
+ t = result[field];
1334
+ }
1335
+ } else {
1336
+ t = callback(result, field);
1337
+ }
1338
+
1339
+ } else if (Util.in_array(field, dropdowns)) {
1340
+ t = !callback(result, field) ? MYMODEL.dropdowns[field].fields[result[field]] : callback(result, field);
1341
+ } else if (Util.in_array(field, passwords)) {
1342
+ t = 'xxxxxx';
1343
+ } else if (MYMODEL.widgets[field].name == "select") {
1344
+ t = !callback(result, field) ? Object.hasOwn(tableObj[field], result[field]) ? tableObj[field][result[field]] : result[field] : callback(result, field);
1345
+ } else if (MYMODEL.widgets[field].name == "datetime") {
1346
+ t = !callback(result, field) ? Util.timeSql(result[field]) : callback(result, field);
1347
+ } else if (MYMODEL.widgets[field].name == "datepicker") {
1348
+ t = !callback(result, field) ? Util.dateFormat(result[field]) : callback(result, field);
1349
+ } else if (MYMODEL.widgets[field].name == "switch") {
1350
+ t = !callback(result, field) ? tableObj[field][result[field]] || "" : callback(result, field);
1351
+ } else if (MYMODEL.widgets[field].name == "relation") {
1352
+ if (relations[field][result[field]]) {
1353
+ t = !callback(result, field) ? relations[field][result[field]].zname || "" : callback(result, field);
1354
+ }
1355
+ } else {
1356
+ t = !callback(result, field) ? result[field] || "" : callback(result, field);
1357
+ }
1358
+ }
1359
+ //worksheet.getCell(sequence[i] + start).value = t;
1360
+ html += `<td>${t}</td>`
1361
+ });
1362
+ html += `</tr>`
1363
+ });
1364
+
1365
+ html += `</tbody></table></div>`;
1366
+ let time = Util.timeSql();
1367
+ time = Util.replaceAll(time, " ", "_");
1368
+ let file = {content: html};
1369
+ let count = fields.length;
1370
+ let options = {}
1371
+ if (count > 8) {
1372
+ options = {
1373
+ landscape: true
1374
+ }
1375
+ } else if (count > 10) {
1376
+ options = {
1377
+ format: 'A3',
1378
+ //landscape:true
1379
+ }
1380
+ } else if (count > 12) {
1381
+ options = {
1382
+ format: 'A3',
1383
+ landscape: true
1384
+ }
1385
+ } else if (count > 14) {
1386
+ options = {
1387
+ format: 'A2',
1388
+ //landscape:true
1389
+ }
1390
+ } else if (count > 16) {
1391
+ options = {
1392
+ format: 'A0',
1393
+ landscape: true
1394
+ }
1395
+ }
1396
+ const pdf = await zRoute.generatePDF(file, 'pdf_blank', options);
1397
+ res.download(pdf, MYMODEL.table + time + ".pdf");
1398
+ };
1399
+
1400
+ /*
1401
+ let options = { format: 'A4' };
1402
+ // Example of options with args //
1403
+ // let options = { format: 'A4', args: ['--no-sandbox', '--disable-setuid-sandbox'] };
1404
+
1405
+ let file = { content: "<h1>Welcome to html-pdf-node</h1>" };
1406
+ // or //
1407
+ let file = { url: "https://example.com" };
1408
+ let layout = "pdf_blank";
1409
+ var pdf = await zRoute.generatePDF(file, layout,options)
1410
+ */
1411
+ zRoute.generatePDF = async (file, layout = "pdf_bootstrap", options = {}) => {
1412
+ // we are using headless mode
1413
+ let args = [
1414
+ '--headless=new',
1415
+ '--no-sandbox',
1416
+ '--disable-setuid-sandbox',
1417
+ ];
1418
+ let env = CONFIG.environment;
1419
+ let puppeterOptions = {
1420
+ args: args
1421
+ };
1422
+ if (env == "production") {
1423
+ puppeterOptions.executablePath = '/usr/bin/google-chrome-stable';
1424
+ puppeterOptions.defaultViewport = {width: 1920, height: 1080};
1425
+ }
1426
+ const browser = await puppeteer.launch(puppeterOptions);
1427
+ const page = await browser.newPage();
1428
+ let mylayout = `${dirRoot}/views/layouts/${layout}.ejs`
1429
+ if (file.content) {
1430
+ const html = await ejs.renderFile(mylayout, {data: file.content}, {async: true});
1431
+ await page.setContent(html, {
1432
+ waitUntil: 'load', timeout: 60000, // wait for page to load completely
1433
+ });
1434
+ } else {
1435
+ await page.goto(file.url, {
1436
+ waitUntil: 'load', timeout: 60000 // wait for page to load completely
1437
+ });
1438
+ }
1439
+ let fileName = new Date().getTime() + ".pdf";
1440
+ const filePath = `${dirRoot}/public/_pdf/${fileName}`;
1441
+ const myoptions = {
1442
+ path: filePath,
1443
+ format: 'A4',
1444
+ };
1445
+ for (let key in options) {
1446
+ myoptions[key] = options[key];
1447
+ }
1448
+ await page.pdf(myoptions);
1449
+ await browser.close();
1450
+ return filePath;
1451
+ };
1452
+
1453
+
1454
+ /*
1455
+ Grids Data Table
1456
+ save grid
1457
+ */
1458
+ zRoute.dataTableSave = async (routeName, userId, body) => {
1459
+ const results = await connection.results({
1460
+ table: "zgrid",
1461
+ where: {
1462
+ user_id: userId,
1463
+ route_name: routeName
1464
+ }
1465
+ });
1466
+ if (results.length) {
1467
+ await connection.update({
1468
+ table: "zgrid",
1469
+ data: {
1470
+ visibles: JSON.stringify(body.fields),
1471
+ filter: JSON.stringify(body)
1472
+ },
1473
+ where: {
1474
+ user_id: userId,
1475
+ route_name: routeName
1476
+ }
1477
+ })
1478
+ } else {
1479
+ await connection.insert({
1480
+ table: "zgrid",
1481
+ data: {
1482
+ route_name: routeName,
1483
+ user_id: userId,
1484
+ visibles: JSON.stringify(body.fields),
1485
+ filter: JSON.stringify(body)
1486
+ },
1487
+ where: {
1488
+ user_id: userId,
1489
+ route_name: routeName
1490
+ }
1491
+ })
1492
+ }
1493
+ return "ok";
1494
+ };
1495
+
1496
+ zRoute.listData = async (req, res, MYMODEL, zRole) => {
1497
+ const relations = await zRoute.relations(req, res, MYMODEL.table);
1498
+ const body = req.body;
1499
+ const fields = body.fields;
1500
+ const select = Util.selectMysql(fields, relations);
1501
+ let whereArray = [];
1502
+ const columns = body.columns;
1503
+ whereArray.push({
1504
+ field: "company_id",
1505
+ option: "=",
1506
+ value: res.locals.companyId,
1507
+ operator: "AND"
1508
+ });
1509
+ columns.forEach(function (item) {
1510
+ if (item.search.value) {
1511
+ whereArray.push({
1512
+ field: fields[item.data],
1513
+ option: MYMODEL.options[fields[item.data]],
1514
+ value: item.search.value,
1515
+ operator: "AND"
1516
+ })
1517
+ }
1518
+ });
1519
+ const orderColumn = fields[body.order[0].column] == "actionColumn" ? "id" : fields[body.order[0].column] == "no" ? "id" : fields[body.order[0].column] == "actionColum" ? "id" : fields[body.order[0].column];
1520
+ const rows = await connection.results({
1521
+ select: select,
1522
+ table: MYMODEL.table,
1523
+ whereArray: whereArray,
1524
+ limit: body.length,
1525
+ offset: body.start,
1526
+ orderBy: [orderColumn, body.order[0].dir]
1527
+ });
1528
+ const count = await connection.result({
1529
+ select: "count(id) as count",
1530
+ table: MYMODEL.table,
1531
+ whereArray: whereArray
1532
+ });
1533
+ let datas = [];
1534
+ const levels = zRole.levels(MYMODEL.routeName, zRole.routes.indexOf(MYMODEL.routeName) > -1 ? await zRole.rules(res.locals.roleId) : {});
1535
+ rows.forEach(function (row, index) {
1536
+ let arr = [];
1537
+ fields.forEach(function (item) {
1538
+ if (item == "no") {
1539
+ arr.push((index + 1 + parseInt(body.start)));
1540
+ } else if (item == "actionColumn") {
1541
+ arr.push(zRoute.actionButtons(levels, row, MYMODEL.table));
1542
+ } else {
1543
+ arr.push(zRoute.dataTableData(item, row[item], MYMODEL, relations));
1544
+ }
1545
+ });
1546
+ datas.push(arr)
1547
+ });
1548
+ const data = {
1549
+ draw: body.draw,
1550
+ recordsTotal: count.count || 0,
1551
+ recordsFiltered: count.count || 0,
1552
+ data: datas
1553
+ };
1554
+ //save grid filter async
1555
+ zRoute.dataTableSave(MYMODEL.routeName, res.locals.userId, body);
1556
+ res.json(data);
1557
+ };
1558
+
1559
+ zRoute.actionButtons = (levels, row, table, callback = null) => {
1560
+ let arr = [];
1561
+ let obj = {}
1562
+ if (levels.delete) {
1563
+ let icon_delete = `<span class="icon-small icons-danger" title="${LANGUAGE.delete}" ><img data-id="${row.id}" class="icons-bg-white griddelete icon-image" src="/assets/icons/trash-filled.svg"></span>`;
1564
+ arr.push(icon_delete);
1565
+ obj['delete'] = icon_delete;
1566
+ }
1567
+ if (levels.update) {
1568
+ let icon_update = `<span class="icon-small icons-primary" title="${LANGUAGE.update}" ><img data-id="${row.id}" class="icons-bg-white gridupdate icon-image" src="/assets/icons/edit.svg"></span>`;
1569
+ arr.push(icon_update);
1570
+ obj['update'] = icon_update;
1571
+ }
1572
+ if (levels.view) {
1573
+ let icon_view = `<span class="icon-small icons-light" title="${LANGUAGE.view}" ><img data-id="${row.id}" class="icons-bg-black gridview icon-image" src="/assets/icons/eye.svg"></span>`;
1574
+ arr.push(icon_view);
1575
+ obj['view'] = icon_view;
1576
+ }
1577
+ if (levels.approval) {
1578
+ let icon_approval = `<span class="icon-small icons-warning" title="${LANGUAGE.approval}" ><img data-id="${row.id}" class="icons-bg-white gridapproval icon-image" src="/assets/icons/rubber-stamp.svg"></span>`;
1579
+ arr.push(icon_approval);
1580
+ obj['approval'] = icon_approval;
1581
+ }
1582
+ let view = '<div class="no-wrap">';
1583
+ view += arr.join("&nbsp;");
1584
+ view += `</div>`;
1585
+ if (callback) {
1586
+ callback({
1587
+ arr: arr,
1588
+ view: view,
1589
+ levels: levels,
1590
+ row: row,
1591
+ table: table,
1592
+ obj: obj
1593
+ });
1594
+ }
1595
+
1596
+ return view;
1597
+ };
1598
+
1599
+ zRoute.dataTableViewLevel = (levels, row, table) => {
1600
+ return zRoute.actionButtons(levels, row, table);
1601
+ };
1602
+
1603
+ zRoute.postGridReload = async (req, res) => {
1604
+ let routeName = res.locals.routeName;
1605
+ let userId = res.locals.userId;
1606
+ let json = Util.jsonSuccess("Successfully to reset grid filter ");
1607
+ await connection.delete({
1608
+ table: gridTable,
1609
+ where: {user_id: userId, route_name: routeName}
1610
+ });
1611
+ //await zRoute.attributeData(res, )
1612
+ res.json(json)
1613
+ };
1614
+
1615
+ zRoute.postGrid = async (req, res) => {
1616
+ try {
1617
+ let query = req.body;
1618
+ //console.log(query);
1619
+ let visible = query.serialize_left;
1620
+ let invisible = query.serialize_right;
1621
+ let post = {
1622
+ user_id: res.locals.userId,
1623
+ route_name: res.locals.routeName,
1624
+ visibles: visible,
1625
+ invisibles: invisible,
1626
+ company_id: 1,
1627
+ updated_at: Util.now()
1628
+ };
1629
+ let results = await connection.results({
1630
+ table: gridTable,
1631
+ where: {user_id: res.locals.userId, route_name: res.locals.routeName}
1632
+ });
1633
+ if (results.length == 0) {
1634
+ await connection.insert({table: gridTable, data: post});
1635
+ } else {
1636
+ await connection.update({table: gridTable, data: post, where: {id: results[0].id}})
1637
+ }
1638
+ res.json(Util.jsonSuccess(LANGUAGE['grid_saved']))
1639
+ } catch (err) {
1640
+ debug(req, res, err);
1641
+ res.json(err)
1642
+ }
1643
+ };
1644
+
1645
+ zRoute.chains = async (req, res) => {
1646
+ try {
1647
+ let body = req.body;
1648
+ let id = body.id;
1649
+ let currentValue = body.currentValue;
1650
+ let target = body.target;
1651
+ let column = body.column;
1652
+ let table = body.table;
1653
+ let name = body.name;
1654
+ let data = {}
1655
+ let obj = body.obj;
1656
+ if (id) {
1657
+ const results = await connection.results({
1658
+ select: ` id, ${name} as zname `,
1659
+ table: table,
1660
+ where: {
1661
+ [column]: id,
1662
+ company_id: res.locals.companyId
1663
+ },
1664
+ orderBy: ["zname", "asc"]
1665
+ });
1666
+ data[target] = `<option value="">Please Select</option>`;
1667
+ if (results.length) {
1668
+ results.forEach(function (result) {
1669
+ var selected = result.id == currentValue ? " selected " : "";
1670
+ data[target] += `<option value="${result.id}" ${selected} >${result.zname}</option>`;
1671
+ });
1672
+ }
1673
+ }
1674
+ res.json(data);
1675
+ } catch (e) {
1676
+ res.json(Util.flashError(e.toString()));
1677
+ }
1678
+ };
1679
+
1680
+ zRoute.getAttributes = async (req, res) => {
1681
+ let id = req.body.id;
1682
+ let table = req.body.table;
1683
+ let result = {}
1684
+ if(id && table) {
1685
+ result = await connection.result({
1686
+ table : table,
1687
+ where : {
1688
+ id:id
1689
+ }
1690
+ })
1691
+ }
1692
+ res.json(result);
1693
+ };
1694
+
1695
+ zRoute.formUser = (relations = {}, data = {}) => {
1696
+ let obj = {}
1697
+ let isUser = false;
1698
+ if (data.hasOwnProperty('created_by')) {
1699
+ isUser = true;
1700
+ if (relations.hasOwnProperty('created_byObject')) {
1701
+ obj.created_by = relations.created_byObject[data['created_by']];
1702
+ obj.updated_by = relations.updated_byObject[data['updated_by']];
1703
+ obj.created_at = Util.timeSql(data['created_at']);
1704
+ obj.updated_at = Util.timeSql(data['updated_at']);
1705
+ }
1706
+ }
1707
+ obj.isUser = isUser;
1708
+ return obj;
1709
+ };
1710
+
1711
+ zRoute.formField = (req, res, MYMODEL, relations, data = {}) => {
1712
+ let forms = zRoute.forms(req, res, MYMODEL, relations, data);
1713
+ let obj = forms.obj;
1714
+ for (let key in obj) {
1715
+ forms.build[key] = cForm.build(obj[key]);
1716
+ }
1717
+ forms.users = zRoute.formUser(relations, data);
1718
+ return forms;
1719
+ };
1720
+
1721
+ zRoute.formsFieldSync = async (req, res, MYMODEL, data = {}) => {
1722
+ const relations = await zRoute.relations(req, res, MYMODEL.table);
1723
+ let forms = zRoute.forms(req, res, MYMODEL, relations, data);
1724
+ let obj = forms.obj;
1725
+ for (let key in obj) {
1726
+ forms.build[key] = cForm.build(obj[key]);
1727
+ }
1728
+ zRoute.moduleLib(req, res, MYMODEL, relations, forms);
1729
+ return forms;
1730
+ };
1731
+
1732
+ zRoute.formFieldSync = async (req, res, MYMODEL, relations, data = {}) => {
1733
+ let forms = zRoute.forms(req, res, MYMODEL, relations, data);
1734
+ let obj = forms.obj;
1735
+ for (let key in obj) {
1736
+ forms.build[key] = cForm.build(obj[key]);
1737
+ }
1738
+ zRoute.moduleLib(req, res, MYMODEL, relations, forms);
1739
+ return forms;
1740
+ };
1741
+
1742
+ zRoute.forms = (req, res, MYMODEL, relations, data = {}) => {
1743
+ relations = relations || {};
1744
+ let fields = MYMODEL.fields;
1745
+ let dropdowns = MYMODEL.dropdowns || {};
1746
+ let modules = MYMODEL.modules || {};
1747
+ let relationsModel = MYMODEL.relations || {};
1748
+ let widgets = MYMODEL.widgets || {};
1749
+ let additionalScripts = {};
1750
+ let forms = {};
1751
+ let tabIndex = 0;
1752
+ forms.label = {};
1753
+ forms.field = {};
1754
+ forms.obj = {};
1755
+ forms.build = {}
1756
+ forms.fn = {};
1757
+ forms.group = {};
1758
+ forms.scriptGroup = "";
1759
+ let script = '';
1760
+ for (let key in fields) {
1761
+ // for label
1762
+ //forms.label[key] = cForm.label(key, fields[key].title, fields[key].required);
1763
+ //for object property
1764
+ let obj = {
1765
+ type: "text",
1766
+ id: key,
1767
+ routeName: MYMODEL.routeName,
1768
+ name: MYMODEL.table + "[" + fields[key].name + "]",
1769
+ title: fields[key].title || "",
1770
+ required: fields[key].required,
1771
+ placeholder: fields[key].placeholder || "",
1772
+ value: data[key] == undefined ? "" : data[key],
1773
+ frameworkcss: res.locals.frameworkcss,
1774
+ form_css: res.locals.form_css,
1775
+ float: fields[key].float || false,
1776
+ inline: fields[key].inline || false,
1777
+ attributes: widgets[key],
1778
+ tabIndex: tabIndex,
1779
+ labelOptions: "",
1780
+ class: 'form-control '
1781
+ };
1782
+
1783
+ //check if widgets
1784
+ if (widgets.hasOwnProperty(key)) {
1785
+ tabIndex++;
1786
+ let widgetName = widgets[key].name;
1787
+ let keyFields = key + "Fields";
1788
+ if (widgets[key].hasOwnProperty("information")) {
1789
+ obj.information = widgets[key].information;
1790
+ }
1791
+ obj.readonly = widgets[key].readonly || false;
1792
+ obj.class = 'form-control ';
1793
+ switch (widgetName) {
1794
+ case "text" :
1795
+ if (widgets[key].hidden) {
1796
+ obj.type = "hidden";
1797
+ } else {
1798
+ obj.type = "input";
1799
+ }
1800
+ break;
1801
+ case "tags" :
1802
+ obj.type = "tags";
1803
+ break;
1804
+ case "checkbox" :
1805
+ obj.type = "checkbox";
1806
+ break;
1807
+ case "range" :
1808
+ obj.type = "range";
1809
+ break;
1810
+ case "color" :
1811
+ obj.type = "color";
1812
+ break;
1813
+ case "textarea" :
1814
+ if (widgets[key].hidden) {
1815
+ obj.style = "display:none";
1816
+ }
1817
+ obj.type = "textarea";
1818
+ break;
1819
+ case "image" :
1820
+ obj.type = "image";
1821
+ obj.width = widgets[key].width || '300';
1822
+ break;
1823
+ case "file" :
1824
+ obj.type = "file";
1825
+ break;
1826
+ case "email" :
1827
+ obj.type = "email";
1828
+ break;
1829
+ case "lexical" :
1830
+ obj.type = "lexical";
1831
+ if (obj.value) {
1832
+ script += `document.addEventListener("DOMContentLoaded", () => {
1833
+ setTimeout(function () {
1834
+ window.importFile(window.LexicalEditor,${JSON.stringify(obj.value)});
1835
+ }, 1000);
1836
+ });`;
1837
+ }
1838
+ break;
1839
+ case "select" :
1840
+ obj.type = "select";
1841
+ obj.data = relations[key];
1842
+ obj.array = relations[key + "Array"];
1843
+ obj.please_select = widgets[key].please_select;
1844
+ break;
1845
+ case "radio" :
1846
+ obj.type = "radio";
1847
+ obj.data = relations[key]
1848
+ obj.array = relations[key + "Array"];
1849
+ break;
1850
+ case "switch" :
1851
+ obj.type = "switch";
1852
+ obj.class = "form-control switch";
1853
+ break;
1854
+ case "dropdown_checkbox" :
1855
+ obj.type = "dropdown_checkbox";
1856
+ obj.data = widgets[key].fields || [];
1857
+ break;
1858
+ case "relation" :
1859
+ obj.type = "select";
1860
+ var htmlOptions = ` <a href="/${widgets[key].table}" target="_blank"> > </a>`;
1861
+ forms.label[key] = cForm.label(key, fields[key].title, fields[key].required, htmlOptions);
1862
+ obj.data = relations[key];
1863
+ obj.please_select = widgets[key].please_select;
1864
+ break;
1865
+ case "typeahead" :
1866
+ obj.type = "typeahead";
1867
+ forms.label[key] = cForm.label(key, fields[key].title, fields[key].required);
1868
+ obj.data = relations[key];
1869
+ obj.typeaheadvalue = !data[key] ? "" : relations[key + "Object"][data[key]];
1870
+ break;
1871
+ case "dropdown_chain" :
1872
+ obj.type = "select";
1873
+ var htmlOptions = ` <a href="/${widgets[key].table}" target="_blank"> > </a>`;
1874
+ forms.label[key] = cForm.label(key, fields[key].title, fields[key].required, htmlOptions);
1875
+ obj.data = relations[key + "Row"];
1876
+ break;
1877
+ case "dropdown_multi" :
1878
+ obj.type = "multi";
1879
+ obj.data = relations[key] || [];
1880
+ obj.multi = relations[key + "Object"];
1881
+ break;
1882
+ case "number" :
1883
+ obj.type = "number";
1884
+ obj.class = "form-control number";
1885
+ break;
1886
+ case "integer" :
1887
+ obj.type = "number";
1888
+ obj.class = "form-control number";
1889
+ break;
1890
+ case "email" :
1891
+ obj.type = "input";
1892
+ break;
1893
+ case "password" :
1894
+ obj.type = "password";
1895
+ break;
1896
+ case "datepicker" :
1897
+ obj.type = "datepicker";
1898
+ obj.class = "form-control datepicker";
1899
+ obj.value = obj.value == "0000-00-00" ? "" : Util.dateSql(obj.value);
1900
+ break;
1901
+ case "datetime" :
1902
+ obj.type = "datetimepicker";
1903
+ obj.class = "form-control datetimepicker";
1904
+ obj.value = obj.value == "0000-00-00 00:00:00" ? "" : Util.timeSql(obj.value);
1905
+ break;
1906
+ case "clockpicker" :
1907
+ obj.type = "input";
1908
+ obj.class = "form-control clockpicker";
1909
+ break;
1910
+ case "editor" :
1911
+ obj.type = "textarea";
1912
+ obj.class = "form-control editor";
1913
+ break;
1914
+ case "tinymce" :
1915
+ obj.type = "textarea";
1916
+ obj.class = "form-control tinymce";
1917
+ break;
1918
+ case "ide_editor" :
1919
+ forms.label[key] = cForm.label(key, fields[key].title, fields[key].required, ` <span class="badge bg-primary float-end boxy-small">${widgets[key].language}</span>`);
1920
+ obj.labelOptions = ` <span class="badge bg-primary float-end boxy-small">${widgets[key].language}</span>`;
1921
+ obj.type = "ide_editor";
1922
+ obj.class = "form-control ide_editor";
1923
+ var myobjvalue = obj.value;
1924
+ if (myobjvalue.includes("`")) {
1925
+ myobjvalue = Util.replaceAll(obj.value, "`", "\\`");
1926
+ }
1927
+ if (myobjvalue.includes("</script>")) {
1928
+ myobjvalue = Util.replaceAll(myobjvalue, "</script>", "<//script>");
1929
+ }
1930
+ if (myobjvalue.includes("${")) {
1931
+ myobjvalue = Util.replaceAll(myobjvalue, "${", "$___{");
1932
+ }
1933
+ script += ` var ide_editor_${key} = \`${myobjvalue}\`;`;
1934
+ break;
1935
+ case "table" :
1936
+ obj.type = "table";
1937
+ obj.data = relations[key];
1938
+ obj.properties = relations[`properties_${key}`];
1939
+ break;
1940
+ case "multi_line_editor" :
1941
+ obj.type = "multi_line_editor";
1942
+ obj.data = relations[key];
1943
+ obj.description = widgets[key].description;
1944
+ obj.fields = relations[key + "Fields"];
1945
+ break;
1946
+ case "json" :
1947
+ obj.type = "json";
1948
+ obj.data = relations[key];
1949
+ break;
1950
+ case "virtual" :
1951
+ obj.type = "virtual";
1952
+ break;
1953
+
1954
+ default :
1955
+ obj.type = "text";
1956
+ break;
1957
+ }
1958
+ } else {
1959
+ obj.type = "text";
1960
+ }
1961
+ forms.obj[key] = obj;
1962
+ //forms.build[key] = cForm.build(obj[key]);
1963
+ }
1964
+ forms.users = zRoute.formUser(relations, data);
1965
+ if(script) {
1966
+ res.locals.relationsVariable = `<script>${script}</script>`;
1967
+ }
1968
+ return forms;
1969
+ };
1970
+
1971
+ zRoute.viewFormPlainText = (req, res, MYMODEL, relations, data = {}) => {
1972
+ return zRoute.viewForm(req, res, MYMODEL, relations, data);
1973
+ };
1974
+
1975
+ zRoute.viewFormsSync = async (req, res, MYMODEL, data = {}) => {
1976
+ const relations = await zRoute.relations(req, res, MYMODEL.table);
1977
+ let forms = zRoute.viewForm(req, res, MYMODEL, relations, data);
1978
+ //zRoute.moduleLib(req, res, MYMODEL, relations, forms);
1979
+ let tables = [];
1980
+ for (let key in forms.obj) {
1981
+ if(forms.obj[key].type == 'table') {
1982
+ let obj = forms.obj[key];
1983
+ let MODEL = require(`./../models/${MYMODEL.widgets[obj.id].table}`);
1984
+ const relationsTable = await zRoute.relations(req,res,MODEL.table);
1985
+ let tableForms = zRoute.viewForm(req,res,MODEL,relationsTable, obj.value || []);
1986
+ let properties = obj.properties;
1987
+ let tableProperties = {};
1988
+ for(let k in properties) {
1989
+ tableProperties[k] = tableForms.obj[k];
1990
+ }
1991
+ let html = ``;
1992
+ html += `<div class="card boxy"><div class="card-header"><h5 class="card-title">${obj.title}</h5></div><div class="card-body"><div class="table-responsive">
1993
+ <table class="table table-hover table-sm">
1994
+ <thead>
1995
+ <tr>`;
1996
+ for(let k in obj.data) {
1997
+ html += `<th>${obj.data[k]}</th>`;
1998
+ }
1999
+ html += `</tr></thead><tbody>`;
2000
+ let val = obj.value || [];
2001
+ if(val.length) {
2002
+ val.forEach(function (item) {
2003
+ let myforms = zRoute.viewForm(req,res,MODEL,relationsTable,item)
2004
+ html += `<tr>`;
2005
+ for(let k in obj.data) {
2006
+ html += `<td>${cForm.field(myforms.obj[k])}</td>`;
2007
+ }
2008
+ html += `</tr>`;
2009
+ });
2010
+ }
2011
+ html += `</tbody></table></div></div></div>`;
2012
+ forms.obj[key].html = html;
2013
+ forms.obj[key].type = "data_table";
2014
+ }
2015
+ forms.build[key] = cForm.build(forms.obj[key]);
2016
+ }
2017
+ return forms;
2018
+ };
2019
+
2020
+ zRoute.viewFormSync = (req, res, MYMODEL, relations, data = {}) => {
2021
+ let forms = zRoute.viewForm(req, res, MYMODEL, relations, data);
2022
+ zRoute.moduleLib(req, res, MYMODEL, relations, forms);
2023
+ for (let key in forms.obj) {
2024
+ forms.build[key] = cForm.build(forms.obj[key]);
2025
+ }
2026
+ return forms;
2027
+ };
2028
+
2029
+ zRoute.viewForm = (req, res, MYMODEL, relations, data = {}) => {
2030
+ let forms = zRoute.forms(req, res, MYMODEL, relations, data);
2031
+ const widgets = MYMODEL.widgets;
2032
+ let obj = forms.obj;
2033
+ let prepend = '';
2034
+ let value = '';
2035
+ for (let key in obj) {
2036
+ if (widgets.hasOwnProperty(key)) {
2037
+ let className = 'form-control-plaintext ';
2038
+ if (widgets[key].float) {
2039
+ className += ` boxy-small`;
2040
+ } else {
2041
+ className += ` purple-border`;
2042
+ }
2043
+ obj[key].class = className;
2044
+ obj[key].readonly = true;
2045
+ obj[key].placeholder = " ";
2046
+ obj[key].view_only = true;
2047
+ //obj[key].disabled = true;
2048
+ let widgetName = widgets[key].name;
2049
+ switch (widgetName) {
2050
+ case "password" :
2051
+ obj[key].value = "xxxxxx";
2052
+ break;
2053
+ case "image" :
2054
+ obj[key].type = "plaintext";
2055
+ let width = widgets[key].width || '300';
2056
+ obj[key].value = "<br><br>" + Util.fileView(`/uploads/${MYMODEL.routeName}/`, data[key], {
2057
+ width: width,
2058
+ class: 'boxy'
2059
+ });
2060
+ break;
2061
+ case "file" :
2062
+ obj[key].type = "plaintext";
2063
+ obj[key].value = "<br><br>" + Util.fileView(`/uploads/${MYMODEL.routeName}/`, data[key], {withIcon: true});
2064
+ break;
2065
+ case "switch" :
2066
+ obj[key].type = "plaintext";
2067
+ if (widgets[key].inline) {
2068
+ prepend = `<br>`
2069
+ }
2070
+ if (widgets[key].float) {
2071
+ prepend = `<br>`
2072
+ }
2073
+ value = data[key] ? widgets[key].fields[data[key]] : widgets[key].fields[0];
2074
+ obj[key].value = `${prepend}<div class="purple-border">${value}</div>`;
2075
+ break;
2076
+ case "relation" :
2077
+ obj[key].type = "text";
2078
+ obj[key].value = relations[key + "Object"][data[key]] || "";
2079
+ break;
2080
+ case "select" :
2081
+ obj[key].type = "text";
2082
+ obj[key].value = widgets[key].fields[[data[key]]] || "";
2083
+ break;
2084
+ case "radio" :
2085
+ obj[key].type = "text";
2086
+ obj[key].value = widgets[key].fields[[data[key]]] || "";
2087
+ break;
2088
+ case "datepicker" :
2089
+ obj[key].type = "text";
2090
+ obj[key].value = Util.dateSql(data[key], widgets[key].format) || "";
2091
+ break;
2092
+ case "editor" :
2093
+ obj[key].type = "textarea";
2094
+ obj[key].value = data[key] || "";
2095
+ break;
2096
+ case "range" :
2097
+ obj[key].type = "text";
2098
+ obj[key].value = data[key] || "";
2099
+ break;
2100
+ case "typeahead" :
2101
+ obj[key].type = "text";
2102
+ obj[key].value = relations[key + "Object"][data[key]] || "";
2103
+ break;
2104
+ }
2105
+ }
2106
+ //forms.build[key] = cForm.build(obj[key]);
2107
+ }
2108
+ forms.users = zRoute.formUser(relations, data);
2109
+ return forms;
2110
+ };
2111
+
2112
+ zRoute.usersCommon = (res) => {
2113
+ return {
2114
+ company_id: res.locals.companyId || 1,
2115
+ updated_by: res.locals.userId || 1,
2116
+ created_by: res.locals.userId || 1,
2117
+ created_at: Util.now(),
2118
+ updated_at: Util.now()
2119
+ }
2120
+ };
2121
+
2122
+ zRoute.viewTable = async (req, res, MYMODEL, results, isPreview, hasKeys = "") => {
2123
+ isPreview = isPreview || false;
2124
+ let data = {};
2125
+ let widgets = MYMODEL.widgets;
2126
+ let widgetsArray = Object.keys(widgets);
2127
+ let routeName = MYMODEL.routeName;
2128
+ let hasIdeEditor = false;
2129
+ let hasLexical = false;
2130
+ let editors = [];
2131
+ let lexicals = {};
2132
+ let row = {};
2133
+ for (let key in results) {
2134
+ if (Util.in_array(key, widgetsArray)) {
2135
+ let widgetName = widgets[key].name;
2136
+ let html = '';
2137
+ let arr = [];
2138
+ switch (widgetName) {
2139
+ case "datepicker" :
2140
+ data[key] = Util.dateSql(results[key], widgets[key].format || "");
2141
+ break;
2142
+ case "color" :
2143
+ data[key] = `<input type="color" value="${results[key]}">`;
2144
+ break;
2145
+ case "number" :
2146
+ data[key] = Util.formatNumber(results[key]);
2147
+ break;
2148
+ case "image" :
2149
+ if (hasKeys) {
2150
+ data[key] = Util.fileView("/uploads/" + hasKeys + "/", results[key]);
2151
+ } else {
2152
+ data[key] = Util.fileView("/uploads/" + routeName + "/", results[key]);
2153
+ }
2154
+ break;
2155
+ case "file" :
2156
+ if (hasKeys) {
2157
+ data[key] = Util.fileView("/uploads/" + hasKeys + "/", results[key]);
2158
+ } else {
2159
+ data[key] = Util.fileView("/uploads/" + routeName + "/", results[key]);
2160
+ }
2161
+ break;
2162
+ case "password" :
2163
+ data[key] = "xxxxxxxx";
2164
+ break;
2165
+ case "datetime" :
2166
+ data[key] = Util.timeSql(results[key], widgets[key].format || "");
2167
+ break;
2168
+ case "switch" :
2169
+ data[key] = widgets[key].fields[results[key]] || "";
2170
+ break;
2171
+ case "select" :
2172
+ data[key] = widgets[key].fields[results[key]] || "";
2173
+ break;
2174
+ case "radio" :
2175
+ data[key] = widgets[key].fields[results[key]] || "";
2176
+ break;
2177
+ case "relation" :
2178
+ if (results[key]) {
2179
+ row = await connection.result({
2180
+ table: widgets[key].table,
2181
+ select: widgets[key].fields[1] + " as zname",
2182
+ where: {id: results[key]}
2183
+ }) || {};
2184
+ }
2185
+ data[key] = !row.zname ? "" : row.zname;
2186
+ break;
2187
+ case "typeahead" :
2188
+ if (results[key]) {
2189
+ row = await connection.result({
2190
+ table: widgets[key].table,
2191
+ select: widgets[key].fields[1] + " as zname",
2192
+ where: {id: results[key]}
2193
+ }) || {};
2194
+ }
2195
+ data[key] = !row.zname ? "" : row.zname;
2196
+ break;
2197
+ case "dropdown_multi" :
2198
+ rows = await connection.results({
2199
+ select: widgets[key].fields.join(",") + "as zname",
2200
+ table: widgets[key].table
2201
+ });
2202
+ let valArr = Util.arrayToList(results[key], Util.arrayWithObject(rows, "id", "zname"))
2203
+ data[key] = typeof valArr == "object" ? valArr.join("<br>") : valArr;
2204
+ break;
2205
+ case "dropdown_chain" :
2206
+ if (results[key]) {
2207
+ row = await connection.result({
2208
+ table: widgets[key].table,
2209
+ select: widgets[key].fields[1] + " as zname",
2210
+ where: {id: results[key]}
2211
+ }) || {};
2212
+ }
2213
+ data[key] = !row.zname ? "" : row.zname;
2214
+ break;
2215
+
2216
+ case "dropdown_checkbox" :
2217
+ arr = widgets[key].fields || [];
2218
+ let val = results[key] || [];
2219
+ arr.map(item => {
2220
+ var checked = val.includes(item) ? 'checked="checked"' : "";
2221
+ html += `<div class="checkbox">
2222
+ <label class="">
2223
+ <input type="checkbox" ${checked} >
2224
+ ${item}
2225
+ </label>
2226
+ </div>`;
2227
+ })
2228
+ data[key] = html;
2229
+ break;
2230
+
2231
+ case "ide_editor" :
2232
+ hasIdeEditor = true;
2233
+ editors.push(key);
2234
+ const editorValue = !results ? "" : Util.replaceAll(results[key], "</script>", `<//script>`);
2235
+ //data[key] = editorValue;
2236
+ moduleLib.addScript(req, res, "var ide_editor_" + key + " = `" + editorValue + "` ");
2237
+ break;
2238
+ case "lexical" :
2239
+ hasLexical = true;
2240
+ /*
2241
+ lexicals[key] = results[key];
2242
+ data[key] = `<div id="lexical${key}"></div><div id="text${key}" style="display:none"></div><div id="container${key}"></div>`;
2243
+ */
2244
+ break;
2245
+ case "json" :
2246
+ data[key] = results[key] ? JSON.stringify(results[key], undefined, 2) : "";
2247
+ break;
2248
+ case "table" :
2249
+ let tableClass = isPreview ? "" : "table-striped table-hover";
2250
+ //let html = '';
2251
+
2252
+ html = `<table class="table ${tableClass}">`;
2253
+ html += `<tr>`;
2254
+ let MODEL_TABLE = require("./../models/" + MYMODEL.widgets[key].table);
2255
+ var nots = [...CONFIG.generator.notRenderField, ...['no', 'actionColumn']];
2256
+ var visibles = MODEL_TABLE.grids.visibles || [];
2257
+ var invisibles = MODEL_TABLE.grids.invisibles || [];
2258
+ var obj = {}
2259
+ visibles.forEach(function (item) {
2260
+ if (!Util.in_array(item, nots)) {
2261
+ obj[item] = MODEL_TABLE.labels[item];
2262
+ html += `<th>${MODEL_TABLE.labels[item]}</th>`;
2263
+ }
2264
+ });
2265
+ invisibles.forEach(function (item) {
2266
+ if (!Util.in_array(item, nots)) {
2267
+ obj[item] = MODEL_TABLE.labels[item];
2268
+ html += `<th>${MODEL_TABLE.labels[item]}</th>`;
2269
+ }
2270
+ });
2271
+ html += `</tr>`;
2272
+ arr = results[key] || [];
2273
+ for (let i = 0; i < arr.length; i++) {
2274
+ var item = arr[i];
2275
+ var data_table = await zRoute.viewTable(req, res, MODEL_TABLE, item, false, `${MYMODEL.table}/${key}`);
2276
+ html += `<tr>`;
2277
+ for (var k in obj) {
2278
+ html += `<td>${data_table[k]}</td>`;
2279
+ }
2280
+ html += `</tr>`;
2281
+ }
2282
+ html += `</table>`;
2283
+ data[key] = html;
2284
+ break;
2285
+
2286
+ default :
2287
+ data[key] = results[key];
2288
+ }
2289
+ } else {
2290
+ data[key] = results[key];
2291
+ }
2292
+ }
2293
+ if (hasIdeEditor) {
2294
+ var contentScript = '';
2295
+ editors.forEach(function (item) {
2296
+ contentScript += `var editor_${item} = ace.edit("editor_${item}");
2297
+ editor_${item}.getSession().setMode("ace/mode/${widgets[item].language}");
2298
+ editor_${item}.setValue(ace_value(ide_editor_${item}));
2299
+ $("#editor_${item}").css({height:${widgets[item].height ? widgets[item].height : 400}});
2300
+ `;
2301
+ });
2302
+ moduleLib.ideCDN(req, res);
2303
+ moduleLib.addScript(req, res, contentScript)
2304
+ }
2305
+
2306
+ if (hasLexical) {
2307
+ /* var scriptForm = '';
2308
+ moduleLib.lexical(req,res);
2309
+ for(var key in lexicals) {
2310
+ scriptForm += `document.addEventListener("DOMContentLoaded", () => {
2311
+ window.buildLexicalEditor("lexical${key}");
2312
+ });
2313
+ setTimeout(function () {
2314
+ window.importFile(window.LexicalEditor,${JSON.stringify(lexicals[key])});
2315
+ $(".toolbar").hide();
2316
+ $(".${key} .ContentEditable__root").focus();
2317
+ $(".action-button .lock").click();
2318
+ $(".actions").hide();
2319
+ $("#text${key}").html(window.LexicalGetContent);
2320
+ }, 1000);
2321
+ `
2322
+ };
2323
+ moduleLib.addScript(req,res,scriptForm);*/
2324
+ }
2325
+ return data;
2326
+ };
2327
+
2328
+
2329
+ //generate all scripts in one line
2330
+ zRoute.moduleLib = (req, res, MYMODEL, relations, zForms = "", data = {}) => {
2331
+ //check a file in directory
2332
+ //make a directory
2333
+ let table = MYMODEL.table;
2334
+ let path_script = `${dirRoot}/public/runtime/script/${table}`;
2335
+ Util.dirExist(path_script,true);
2336
+ let path_head = `${dirRoot}/public/runtime/head/${table}`;
2337
+ Util.dirExist(path_head,true);
2338
+ let path_end = `${dirRoot}/public/runtime/end/${table}`;
2339
+ Util.dirExist(path_end,true);
2340
+ let files = Util.getAllFiles(path_script);
2341
+ let head = res.locals.moduleHead;
2342
+ let end = res.locals.moduleEnd;
2343
+ if(files.length) {
2344
+ let head_files = Util.getAllFiles(path_head);
2345
+ let end_files = Util.getAllFiles(path_end);
2346
+ if(head_files.length) {
2347
+ head += Util.readFile(`${path_head}/head.txt`);
2348
+ }
2349
+ if(end_files.length) {
2350
+ end += Util.readFile(`${path_end}/end.txt`);
2351
+ }
2352
+ end += `<script src="/runtime/script/${table}/${files[0]}"></script>`;
2353
+ } else {
2354
+ let jsObj = zRoute.generateJS(req, res, MYMODEL, relations);
2355
+ let time = new Date().getTime();
2356
+ Util.deleteAllFiles(path_head);
2357
+ Util.deleteAllFiles(path_end);
2358
+ //minify js
2359
+ const uglifyJS = require("uglify-js");
2360
+ Util.writeFile(`${path_script}/${time}.js`, uglifyJS.minify(jsObj.script));
2361
+ Util.writeFile(`${path_head}/head.txt`, jsObj.head);
2362
+ Util.writeFile(`${path_end}/end.txt`, jsObj.end);
2363
+ end += `<script src="/runtime/script/${table}/${time}/.js"></script>`;
2364
+ if(jsObj.head) {
2365
+ head +=jsObj.head;
2366
+ }
2367
+ if(jsObj.end) {
2368
+ end += jsObj.end;
2369
+ }
2370
+ }
2371
+
2372
+ if(head) {
2373
+ res.locals.moduleHead = head;
2374
+ }
2375
+ if(end) {
2376
+ res.locals.moduleEnd = end;
2377
+ }
2378
+ };
2379
+
2380
+ /*
2381
+ Generate javascript code into runtime folder
2382
+ */
2383
+ zRoute.generateJS = (req, res, MYMODEL, relations, zForms = "", data = {}) => {
2384
+ //add additional script
2385
+ let lib_css = '';
2386
+ let scriptForm = '';
2387
+ let lib_js = '';
2388
+ let headObj = {};
2389
+ let endObj = {};
2390
+ if (zForms) {
2391
+ //moduleLib.addScript(req, res, zForms.scriptGroup);
2392
+ //scriptForm += zForms.scriptGroup;
2393
+ }
2394
+ let obj = {};
2395
+ let widgets = MYMODEL.widgets,
2396
+ widgetsArray = Object.keys(widgets) || [];
2397
+ let hasDatePicker = false;
2398
+ let hasNumber = false;
2399
+ let hasClockPicker = false;
2400
+ let hasEditor = false;
2401
+ let hasDateTimePicker = false;
2402
+ let hasTable = false;
2403
+ let chainsObj = {}
2404
+ let chainsArr = [];
2405
+ let hasChain = false;
2406
+ let hasIde = false;
2407
+ let hasTinymce = false;
2408
+ let defaultScript = "";
2409
+ let hasTags = false;
2410
+ let hasLexical = false;
2411
+ let lexicals = [];
2412
+ let hasAttributes = [];
2413
+ for (let key in widgets) {
2414
+ if (widgets[key].name == "datepicker") {
2415
+ hasDatePicker = true;
2416
+ } else if (widgets[key].name == "number") {
2417
+ hasNumber = true;
2418
+ } else if (widgets[key].name == "clockpicker") {
2419
+ hasClockPicker = true;
2420
+ } else if (widgets[key].name == "editor") {
2421
+ hasEditor = true;
2422
+ } else if (widgets[key].name == "ide_editor") {
2423
+ hasIde = true;
2424
+ } else if (widgets[key].name == "switch") {
2425
+ let switchObj = moduleLib.switch(req, res, `#${key}`, widgets[key].fields);
2426
+ scriptForm += switchObj.script;
2427
+ headObj.switch = switchObj.head;
2428
+ endObj.switch = switchObj.end;
2429
+ } else if (widgets[key].name == "typeahead") {
2430
+ let typeaheadObj = moduleLib.typeahead(req, res, `#${key}Typeahead`, relations[key]);
2431
+ scriptForm += typeaheadObj.script;
2432
+ headObj.typeahead = typeaheadObj.head;
2433
+ endObj.typeahead = typeaheadObj.end;
2434
+ } else if (widgets[key].name == "datetime") {
2435
+ hasDateTimePicker = true;
2436
+ } else if (widgets[key].name == "table") {
2437
+ hasTable = true;
2438
+ } else if (widgets[key].name == "tags") {
2439
+ hasTags = true;
2440
+ } else if (widgets[key].name == "lexical") {
2441
+ hasLexical = true;
2442
+ lexicals.push(key);
2443
+ } else if (widgets[key].name == "tinymce") {
2444
+ hasTinymce = true;
2445
+ }
2446
+ // has chains
2447
+ if (widgets[key].name == "relation") {
2448
+ if (widgets[key].isChain) {
2449
+ if (widgets[key].chains.length) {
2450
+ chainsObj[key] = widgets[key].chains;
2451
+ hasChain = true;
2452
+ }
2453
+ }
2454
+ //relation_all_attributes
2455
+ if (widgets[key].isAttributes) {
2456
+ hasAttributes.push(key);
2457
+ }
2458
+ }
2459
+ }
2460
+ if (hasDatePicker) {
2461
+ let datePickerObj = moduleLib.datepicker(req, res);
2462
+ scriptForm += datePickerObj.script;
2463
+ headObj.datepicker = datePickerObj.head;
2464
+ endObj.datepicker = datePickerObj.end;
2465
+ }
2466
+ if (hasNumber) {
2467
+ let numberObj = moduleLib.number(req, res);
2468
+ scriptForm += numberObj.script;
2469
+ headObj.number = numberObj.head;
2470
+ endObj.number = numberObj.end;
2471
+ }
2472
+ if (hasClockPicker) {
2473
+ let clockpickerObj = moduleLib.clockpicker(req, res);
2474
+ scriptForm += clockpickerObj.script;
2475
+ headObj.clockpicker = clockpickerObj.head;
2476
+ endObj.clockpicker = clockpickerObj.end;
2477
+ }
2478
+ if (hasEditor) {
2479
+ let editorObj = moduleLib.editor(req, res);
2480
+ scriptForm += editorObj.script;
2481
+ headObj.editor = editorObj.head;
2482
+ endObj.editor = editorObj.end;
2483
+ }
2484
+ if (hasDateTimePicker) {
2485
+ let datetimepickerObj = moduleLib.datetimepicker(req, res);
2486
+ scriptForm += datetimepickerObj.script;
2487
+ headObj.datetimepicker = datetimepickerObj.head;
2488
+ endObj.datetimepicker = datetimepickerObj.end;
2489
+ }
2490
+ /*if (hasTable) {
2491
+ scriptForm += moduleLib.script(req, res, MYMODEL.table);
2492
+ }*/
2493
+ if (hasIde) {
2494
+ let ideCDNObj = moduleLib.ideCDN(req, res);
2495
+ //scriptForm += ideCDNObj.script;
2496
+ //headObj.ideCDN = ideCDNObj.head;
2497
+ endObj.ideCDN = ideCDNObj.end;
2498
+ }
2499
+ if (hasTags) {
2500
+ let tagsObj = moduleLib.tags(req, res);
2501
+ scriptForm += tagsObj.script;
2502
+ headObj.tags = tagsObj.head;
2503
+ endObj.tags = tagsObj.end;
2504
+ }
2505
+
2506
+ if (hasTinymce) {
2507
+ let tinymceObj = moduleLib.tinymce(req, res);
2508
+ scriptForm += tinymceObj.script;
2509
+ headObj.tinymce = tinymceObj.head;
2510
+ endObj.tinymce = tinymceObj.end;
2511
+ }
2512
+
2513
+ if (hasLexical) {
2514
+ moduleLib.lexical(req, res);
2515
+ lexicals.forEach(function (lexical) {
2516
+ scriptForm += `document.addEventListener("DOMContentLoaded", () => {
2517
+ window.buildLexicalEditor("${lexical}");
2518
+ });`
2519
+ });
2520
+ }
2521
+
2522
+ if (hasChain) {
2523
+ for (let key in chainsObj) {
2524
+ if (chainsObj[key].length > 0) {
2525
+ scriptForm += `$("body").on("change", "#${key}", function () {`;
2526
+ chainsObj[key].forEach(function (objItem) {
2527
+ scriptForm += `chains("${key}","${objItem.table}","${objItem.target}","${objItem.column}","${objItem.name}", $("#${objItem.target}").val());`;
2528
+ });
2529
+ scriptForm += `});${Util.newLine}`;
2530
+ chainsObj[key].forEach(function (objItem) {
2531
+ scriptForm += ` if($("#${objItem.target}").val()){`
2532
+ scriptForm += `chains("${key}","${objItem.table}","${objItem.target}","${objItem.column}","${objItem.name}", $("#${objItem.target}").val());`;
2533
+ scriptForm += `}${Util.newLine}`
2534
+ })
2535
+ }
2536
+ }
2537
+ }
2538
+
2539
+ defaultScript = `${Util.newLine} $(function () {
2540
+ $(".isfile").each(function (index, value) {
2541
+ let filename = $(this).attr("data-filename") || "";
2542
+ let id = $(this).attr("data-id");
2543
+ let table = $(this).attr("data-table") || " ";
2544
+ let width = $(this).attr("data-width") || "300";
2545
+ if (filename.length > 3) {
2546
+ if(filename.includes('https:')) {
2547
+ $("#file"+id).attr("src",filename);
2548
+ } else {
2549
+ let ext = filename.substring(filename.lastIndexOf('.') + 1).toLowerCase();
2550
+ if (ext == "gif" || ext == "png" || ext == "jpeg" || ext == "jpg" || ext == "bmp" || ext == "webp" || ext == "jiff" || ext == "svg") {
2551
+ $("#file"+id).attr("src","/uploads/"+table+"/"+filename).attr("width",width+"px");
2552
+ } else {
2553
+ let file = 'file.png';
2554
+ if(ext == "docx" || ext == "doc") {
2555
+ file = 'word.png'
2556
+ } else if(ext == 'xls' || ext == 'xlsx') {
2557
+ file = 'excel.png'
2558
+ } else if(ext == 'pdf') {
2559
+ file = 'pdf.png'
2560
+ } else if(ext == 'ppt' || ext == 'pptx'){
2561
+ file = 'ppt.png';
2562
+ } else if(ext == 'txt') {
2563
+ file = 'txt.png';
2564
+ } else if(ext == 'zip') {
2565
+ file = 'zip.jpg';
2566
+ } else if(ext == 'rar') {
2567
+ file = 'rar.jpg';
2568
+ } else if(ext == 'rar') {
2569
+ file = 'file.png';
2570
+ }
2571
+ $("#file"+id).attr("src","/img/"+file).attr("height","45px").attr("width","45px").addClass("boxy-small");
2572
+ }
2573
+ $("#file"+id).on("click", function () {
2574
+ location.href = "/uploads/"+table+"/"+filename;
2575
+ });
2576
+ }
2577
+ }
2578
+ if($(this).data("required") == true) {
2579
+ var imageElement = "#file"+id;
2580
+ if(!$(imageElement).attr("src")) {
2581
+ $("#"+id).attr("required",true);
2582
+ }
2583
+ }
2584
+ });
2585
+ });`;
2586
+
2587
+ for (let keys in widgets) {
2588
+ let widgetName = widgets[keys].name;
2589
+ switch (widgetName) {
2590
+ case "multi_line_editor" :
2591
+ scriptForm += `$(".text-toggle").on("click", function(){
2592
+ let editorId = $(this).data("id");
2593
+ $("#"+editorId).attr("type","text");
2594
+ $("#a_"+editorId).hide();
2595
+ $("#"+editorId).show();
2596
+ });
2597
+
2598
+ $(".editor-value").on("change",function(index,item){
2599
+ if($(this).attr("type") == "text") {
2600
+ if($(this).val()) {
2601
+ var editorId = $(this).data("id");
2602
+ $("#a_"+editorId).html($(this).val()).show();
2603
+ $(this).attr("type","hidden");
2604
+ }
2605
+ }
2606
+ });`;
2607
+ break;
2608
+
2609
+ case "dropdown_multi" :
2610
+ scriptForm += ` $("#dropdownadd${keys}").on("click", function () {
2611
+ var val = $("#${keys}").val();
2612
+ if(val == ""){
2613
+ alert("Please select data");
2614
+ return false;
2615
+ }
2616
+ var count = $(".span${keys}").length;
2617
+ var data = "<span class='span${keys}' > "+(count+1)+". <input type='hidden' name='${MYMODEL.table}[${keys}][]' value='"+val+"' /> " + $("#${keys} option:selected").text()+" <i class='fa fa-trash pointer text-danger pull-right' onclick='$(this).closest(\`span\`).remove();' title='Delete'></i><br></span>";
2618
+ $("#dropdownbox${keys}").append(data);
2619
+ $("#${keys}").val("");
2620
+ });${Util.newLine}`;
2621
+ break;
2622
+
2623
+ case "table" :
2624
+ let MODEL_TABLE = require("./../models/" + MYMODEL.widgets[keys].table);
2625
+ //let MODEL_TABLE_RELATIONS = await zRoute.relations(req, res, MODEL_TABLE.table);
2626
+ //relations[key + "TABLE"]
2627
+ let MODEL_TABLE_RELATIONS = relations[keys + "TABLE"];
2628
+ let zForm = zRoute.formField(req, res, MODEL_TABLE, MODEL_TABLE_RELATIONS);
2629
+ zRoute.moduleLib(req, res, MODEL_TABLE, MODEL_TABLE_RELATIONS, zForms);
2630
+ let trash = `trash_${keys}_${MYMODEL.widgets[keys].table}`;
2631
+ let trtd = '';
2632
+ for (let key in relations[keys]) {
2633
+ obj = zForm.obj[key] || {}
2634
+ let name = MYMODEL.table + "[" + keys + "][${increment}][" + key + "]";
2635
+ obj.name = name;
2636
+ //obj.class = MYMODEL.table + "_" + keys + "_" + key;
2637
+ obj.class = `${MYMODEL.table}_${keys}_${key} form-control`;
2638
+ obj.id = key;
2639
+ obj.options = {
2640
+ "data-name": key,
2641
+ "data-id": obj.class
2642
+ };
2643
+ trtd += `<td class="td_${key}_${MYMODEL.widgets[keys].table}">${cForm.field(obj)}</td>`;
2644
+ }
2645
+
2646
+ trtd += `<td style="vertical-align:top"><span class="fas fa-trash-alt ${trash}" ></span></td></tr>`;
2647
+ let subname = MYMODEL.table + "_" + keys;
2648
+ scriptForm += `$("table").on("click", ".${trash}", function () {$(this).closest('tr').remove();});`;
2649
+ scriptForm += Util.newLine;
2650
+ scriptForm += 'var append' + keys + ' = function (increment) {return `<tr data-id="${increment}" data-name="' + MYMODEL.table + '[' + keys + ']">';
2651
+ scriptForm += trtd;
2652
+ scriptForm += "`}";
2653
+ scriptForm += Util.newLine;
2654
+ scriptForm += `var append${keys}Max = $('tbody#body-${keys}>tr').length;${Util.newLine}`;
2655
+ scriptForm += `function ${keys}Handler(){
2656
+ var index = $("#body-${keys}>tr").length || 0;
2657
+ $("#body-${keys}>tr").each(function (index, tr) {
2658
+ let dataname = $(tr).data("name") || "";
2659
+ $(tr).attr("data-id", index);
2660
+ if(dataname != "") {
2661
+ var inputs = $(tr).find("input");
2662
+ inputs.each(function (i,input) {
2663
+ if($(input).data("name")){
2664
+ $(input).removeAttr("name");
2665
+ $(input).attr("name",dataname+"["+index+"]["+$(input).data("name")+"]");
2666
+ }
2667
+ if($(input).attr("type") == "file") {
2668
+
2669
+ }
2670
+ });
2671
+
2672
+ var selects = $(tr).find("select");
2673
+ selects.each(function (i,input) {
2674
+ if($(input).data("name")){
2675
+ $(input).removeAttr("name");
2676
+ $(input).attr("name",dataname+"["+index+"]["+$(input).data("name")+"]");
2677
+ }
2678
+ });
2679
+
2680
+ var textareas = $(tr).find("textarea");
2681
+ textareas.each(function (i,input) {
2682
+ if($(input).data("name")){
2683
+ $(input).removeAttr("name");
2684
+ $(input).attr("name",dataname+"["+index+"]["+$(input).data("name")+"]");
2685
+ }
2686
+ });
2687
+ }
2688
+
2689
+ }); ${Util.newLine}};${Util.newLine}`;
2690
+
2691
+ scriptForm += ` $(function () {
2692
+ $('#add${keys}').on('click',function(){
2693
+ $('#body-${keys}').append(append${keys}(append${keys}Max));
2694
+ append${keys}Max++;
2695
+ ${keys}Handler();
2696
+ });
2697
+ var ${keys} = $("#body-${keys}").data("value") ? $("#body-${keys}").data("value") : [];
2698
+ ${keys}.forEach(function (myobj, index) {
2699
+ $("#body-${keys}").append(append${keys}(index));
2700
+ ${keys}Handler();
2701
+ for(var key in myobj){
2702
+ if($(".${subname}_" + key).eq(index).attr("type") == "checkbox" && myobj[key] == 1){
2703
+ $(".${subname}_" + key).eq(index).prop("checked", true);
2704
+ $(".${subname}_" + key).eq(index).val(myobj[key] ? myobj[key] : '');
2705
+ } else if($(".${subname}_" + key).eq(index).attr("type") == "file"){
2706
+ var myimg = myobj[key] ? myobj[key] : '';
2707
+ var pathName = "/uploads/${MYMODEL.table}/${keys}/";
2708
+ if(myimg) {
2709
+ var filename = filenamex = pathName+myimg;
2710
+ if (!myimg.match(/\\.(jpg|jpeg|png|gif|svg|jiff)$/i)) {
2711
+ filename = "/img/file.png";
2712
+ }
2713
+ $(".${subname}_" + key).eq(index).closest("TD").find("img").attr("src",filename).addClass("boxy");
2714
+ $(".${subname}_" + key).eq(index).closest("TD").append('<a href="'+filenamex+'" target="_blank" style="font-size: 12px">'+myimg+'</a>');
2715
+ }
2716
+ } else {
2717
+ $(".${subname}_" + key).eq(index).val(myobj[key] ? myobj[key] : '');
2718
+ }
2719
+
2720
+ }
2721
+ append${keys}Max = index + 1;
2722
+ });
2723
+ });${Util.newLine}`;
2724
+ break;
2725
+
2726
+ case "ide_editor" :
2727
+ //var additionalScripts = `if (!!session.$worker) {session.$worker.send("setOptions", [{"esversion": 9,"esnext": false,}]);}`;
2728
+ let script_annotaions = '';
2729
+ let script_enabled = '';
2730
+ let script_looping = '';
2731
+ if (widgets[keys].language == "javascript") {
2732
+ script_annotaions = `editor_${keys}.session.setOption("useWorker", true);`;
2733
+ script_enabled = `editor_${keys}.session.setOption("useWorker", true);`;
2734
+ script_looping = `
2735
+ var errors = editor_${keys}.getSession().getAnnotations().filter(a=>a.type==='error');
2736
+ arr = [];
2737
+ errors.forEach(function(erItem) {
2738
+ if(erItem.text == 'Missing ";" before statement') {
2739
+ } else {
2740
+ arr.push(erItem);
2741
+ }
2742
+ });
2743
+ editor_${keys}.getSession().setAnnotations(arr);
2744
+ editor_${keys}.session.setOption("useWorker", true);
2745
+ `;
2746
+ }
2747
+ scriptForm += `var editor_${keys} = ace.edit("editor_${keys}");
2748
+ editor_${keys}.getSession().setMode("ace/mode/${widgets[keys].language}");
2749
+ editor_${keys}.setValue(ace_value(ide_editor_${keys}));
2750
+ $("#${keys}").text(ace_value(ide_editor_${keys}));
2751
+ $("#editor_${keys}").css({height:${widgets[keys].height ? widgets[keys].height : 400}});
2752
+ ${script_annotaions}
2753
+ editor_${keys}.on("change",function(e,session){
2754
+ $("#${keys}").text(editor_${keys}.getValue());
2755
+ });
2756
+ `;
2757
+
2758
+ break;
2759
+ }
2760
+ }
2761
+
2762
+ if(hasAttributes) {
2763
+ hasAttributes.forEach(function (item) {
2764
+ let tableItem = MYMODEL.widgets[item].table;
2765
+ scriptForm += `
2766
+ function getAttribute_${item}(cb){
2767
+ ajaxPost('/${MYMODEL.table}/get_attributes',{id:$('#${item}').val(),table:'${tableItem}'},function(dt){cb(dt);});
2768
+ };
2769
+ `;
2770
+ });
2771
+ }
2772
+ scriptForm += defaultScript;
2773
+
2774
+ let head = '';
2775
+ let end = '';
2776
+ for(let key in headObj) {
2777
+ if(headObj[key]){
2778
+ head += headObj[key];
2779
+ }
2780
+ }
2781
+ for(let key in endObj) {
2782
+ if(endObj[key]) {
2783
+ end += endObj[key];
2784
+ }
2785
+ }
2786
+
2787
+ return {
2788
+ script : scriptForm,
2789
+ head : head,
2790
+ end : end
2791
+ }
2792
+ };
2793
+
2794
+ /*
2795
+ MySQL CRUD with context
2796
+ */
2797
+ zRoute.insertSQL = async (req, res, table, data) => {
2798
+ let MYMODEL = require("./../models/" + table);
2799
+ let fields = MYMODEL.keys;
2800
+ if (fields.includes("company_id")) data.company_id = res.locals.companyId || 1;
2801
+ if (fields.includes("updated_at")) data.updated_at = Util.now();
2802
+ if (fields.includes("created_at")) data.created_at = Util.now();
2803
+ if (fields.includes("updated_by")) data.updated_by = res.locals.userId || 1;
2804
+ if (fields.includes("created_by")) data.created_by = res.locals.userId || 1;
2805
+ const result = await connection.insert({table: table, data: data});
2806
+ zRoute.modelsCacheRenew(table, res.locals.companyId);
2807
+ return result;
2808
+ };
2809
+
2810
+ zRoute.updateSQL = async (req, res, table, data, whereData) => {
2811
+ let MYMODEL = require("./../models/" + table);
2812
+ let fields = MYMODEL.keys;
2813
+ if (fields.includes('updated_at')) {
2814
+ data.updated_at = Util.now();
2815
+ }
2816
+ if (fields.includes('updated_by')) {
2817
+ data.updated_by = res.locals.userId;
2818
+ }
2819
+ //check if has table and image/file
2820
+ let hasImages = false;
2821
+ let tables = [];
2822
+ let tableFields = {}
2823
+ for (let key in MYMODEL.widgets) {
2824
+ if (MYMODEL.widgets[key].name == "table") {
2825
+ tableFields[key] = [];
2826
+ const MYMODEL_TABLE = require("./../models/" + MYMODEL.widgets[key].table);
2827
+ for (let q in MYMODEL_TABLE.widgets) {
2828
+ if (MYMODEL_TABLE.widgets[q].name == "file" || MYMODEL_TABLE.widgets[q].name == "image") {
2829
+ hasImages = true;
2830
+ tables.push(key);
2831
+ tableFields[key].push(q);
2832
+ }
2833
+ }
2834
+ }
2835
+ }
2836
+ if (hasImages) {
2837
+ let result = await connection.result({
2838
+ table: MYMODEL.table,
2839
+ where: whereData
2840
+ });
2841
+ tables.forEach((item) => {
2842
+ let dataTables = data[item] ? JSON.parse(data[item]) : [];
2843
+ let temp = [];
2844
+ if (dataTables.length) {
2845
+ dataTables.forEach((obj, index) => {
2846
+ tableFields[item].forEach((key) => {
2847
+ if (!obj[key]) {
2848
+ let resultItem = result[item];
2849
+ if(resultItem && Object.prototype.hasOwnProperty.call(resultItem,index)) {
2850
+ let resultItemIndex = resultItem[index];
2851
+ if(resultItemIndex && Object.prototype.hasOwnProperty.call(resultItemIndex,key)) {
2852
+ obj[key] = !result[item][index] ? "" : result[item][index][key];
2853
+ }
2854
+ }
2855
+ }
2856
+ });
2857
+ temp.push(obj);
2858
+ });
2859
+ data[item] = JSON.stringify(temp);
2860
+ }
2861
+ });
2862
+ }
2863
+ delete data.created_at;
2864
+ delete data.created_by;
2865
+ const result = await connection.update({table: table, where: whereData, data: data});
2866
+ zRoute.modelsCacheRenew(table, res.locals.companyId);
2867
+ return result;
2868
+ };
2869
+
2870
+ zRoute.deleteSQL = async (table, id, company_id) => {
2871
+ try {
2872
+ const where = {
2873
+ id: id,
2874
+ company_id: company_id
2875
+ };
2876
+ const results = await connection.results({
2877
+ table: table,
2878
+ where: where
2879
+ });
2880
+ if (results.length) {
2881
+ await connection.delete({table: table, where: where});
2882
+ zRoute.modelsCacheRenew(table, company_id);
2883
+ } else {
2884
+ throw Error('Data not found');
2885
+ }
2886
+ return results[0];
2887
+ } catch (e) {
2888
+ throw Error(e.toString());
2889
+ }
2890
+ };
2891
+
2892
+ //for import
2893
+ zRoute.import = async (req, res, MYMODEL) => {
2894
+ const userId = res.locals[CONFIG.generator.userId];
2895
+ const room = res.locals.token;
2896
+ let progress = 0;
2897
+ let datas = [];
2898
+ let headers = [];
2899
+ let dataObj = {};
2900
+ let fields = Object.keys(MYMODEL.fields);
2901
+ dataObj.type = MYMODEL.routeName;
2902
+ let jsonObj = {
2903
+ progress: progress,
2904
+ headers: headers,
2905
+ datas: datas
2906
+ };
2907
+ let json = Util.jsonSuccess(LANGUAGE['import_success']);
2908
+ try {
2909
+ if (Object.keys(req.files).length == 0) {
2910
+ return res.json(Util.flashError(LANGUAGE['import_no_file']));
2911
+ }
2912
+ } catch (err) {
2913
+ return res.json(Util.flashError(err.toString()));
2914
+ }
2915
+ const filename = `${dirRoot}/public/excel/tmp/${Util.generateUnique()}.xlsx`;
2916
+ let excelFile = req.files.excel, labels = MYMODEL.labels, keys = {};
2917
+ if(!excelFile) {
2918
+ return res.json(Util.flashError(LANGUAGE['import_no_file']));
2919
+ }
2920
+ await Util.moveFile(excelFile, filename);
2921
+ io.to(room).emit('message', LANGUAGE['import_process']);
2922
+ const toJson = excelToJson({source: fs.readFileSync(filename)});
2923
+ let result;
2924
+ for (let prop in toJson) {
2925
+ let i = 0;
2926
+ if (i == 0) result = toJson[prop];
2927
+ i++;
2928
+ }
2929
+ if (!result.length) {
2930
+ let message = "No Data Found!!. Please uploading an excel file into 1 sheet only. Can not Multiple sheets";
2931
+ io.to(room).emit('message', message);
2932
+ res.json(Util.flashError(message));
2933
+ return;
2934
+ }
2935
+ //convert to table header
2936
+ let hd = '<tr>';
2937
+ for (let prop in result[1]) {
2938
+ let i = 0;
2939
+ keys[prop] = result[1][prop];
2940
+ hd += `<th>${result[0][prop]}</th>`;
2941
+ headers.push({i: i, prop: prop, value: result[0][prop]});
2942
+ i++;
2943
+ }
2944
+ hd += `<th>${LANGUAGE['noted']}</th>`;
2945
+ hd += `</tr>`;
2946
+ //convert to table header
2947
+ io.to(room).emit('import', hd);
2948
+
2949
+ let isInsert = true;
2950
+ hd += `<tr>`
2951
+ for (let i = 3; i < result.length; i++) {
2952
+ const data = {}
2953
+ hd += `${(i - 2)}`
2954
+ for (var prop in keys) {
2955
+ let value = result[i][prop];
2956
+ if (value) {
2957
+ data[keys[prop]] = value;
2958
+ }
2959
+ hd += `<td>${value}</td>`
2960
+ if (keys[prop] == "id")
2961
+ isInsert = false;
2962
+ }
2963
+ try {
2964
+ if (isInsert) {
2965
+ if (Util.in_array("company_id", fields)) data.company_id = res.locals.companyId;
2966
+ if (Util.in_array("created_at", fields)) data.created_at = Util.now();
2967
+ if (Util.in_array("created_by", fields)) data.created_by = res.locals.userId;
2968
+ if (Util.in_array("updated_at", fields)) data.updated_at = Util.now();
2969
+ if (Util.in_array("updated_by", fields)) data.updated_by = res.locals.userId;
2970
+ await connection.insert({table: MYMODEL.table, data: data});
2971
+ } else {
2972
+ if (Util.in_array("updated_at", fields)) data.updated_at = Util.now();
2973
+ if (Util.in_array("updated_by", fields)) data.updated_by = res.locals.userId;
2974
+ var update = await connection.update({
2975
+ table: MYMODEL.table,
2976
+ data: data,
2977
+ where: {
2978
+ id: data.id
2979
+ }
2980
+ })
2981
+ }
2982
+ hd += `<td class='text text-success'>${LANGUAGE['success']}</td>`
2983
+ } catch (err) {
2984
+ hd += `<td class='text text-danger'>${err.toString()}</td>`
2985
+ }
2986
+ hd += '</tr>';
2987
+ io.to(room).emit('import', hd);
2988
+ }
2989
+ hd += '';
2990
+ io.to(room).emit('import', hd);
2991
+ fs.removeSync(filename);
2992
+ if (myCache.has(MYMODEL.table)) {
2993
+ zRoute.modelsCacheRenew(req,res,MYMODEL);
2994
+ }
2995
+ res.json(json);
2996
+ };
2997
+
2998
+ zRoute.buildFileModel = (json, index = 0) => {
2999
+ //let text = `module.exports = { ${Util.newLine}`;
3000
+ let text = '';
3001
+ let separator = index == 0 ? "" : Util.tabs(index);
3002
+ for (let key in json) {
3003
+ text += `${separator}${Util.tabs(2)} ${key} : `;
3004
+ let type = typeof json[key];
3005
+ if (type == "string") {
3006
+ let title = Util.replaceAll(json[key], '"', "'");
3007
+ text += `"${title}",${Util.newLine}`;
3008
+ } else if (Array.isArray(json[key])) {
3009
+ let textArray = '';
3010
+ let isStringArray = false;
3011
+ if (json[key].length == 0) {
3012
+ text += `[], ${Util.newLine}`;
3013
+ } else {
3014
+ json[key].map((item) => {
3015
+ if (typeof item == "string") {
3016
+ isStringArray = true;
3017
+ textArray += `${Util.tabs(3)} ${separator}"${Util.replaceAll(item, '"', "'")}",${Util.newLine}`;
3018
+ }
3019
+ });
3020
+ if (isStringArray) {
3021
+ text += `[${Util.newLine}${textArray.slice(0, -3)}${Util.newLine}${separator}${Util.tabs(2)} ], ${Util.newLine}`;
3022
+ } else {
3023
+ text += `${JSON.stringify(json[key])}, ${Util.newLine}`
3024
+ }
3025
+ }
3026
+
3027
+ } else if (type == "boolean") {
3028
+ text += json[key] ? "true" : "false";
3029
+ text += "," + Util.newLine;
3030
+ } else if (type == "object") {
3031
+ text += `{${Util.newLine}`;
3032
+ let textObjext = zRoute.buildFileModel(json[key], (index + 1));
3033
+ text += textObjext.slice(0, -3);
3034
+ text += `${Util.newLine}${separator}${Util.tabs(2)} }, ${Util.newLine}`
3035
+ } else {
3036
+ text += `"", ${Util.newLine}`
3037
+ }
3038
+ }
3039
+ //text += '}';
3040
+ return text;
3041
+ };
3042
+
3043
+ zRoute.approversFooter = async (results, noActivity) => {
3044
+ noActivity = noActivity || false;
3045
+ let MYMODEL = require("./../models/zapprovals_details");
3046
+ let users = Util.arrayToObject(await connection.results({table: "zuser"}), "id");
3047
+ let html = '';
3048
+ let id = 0;
3049
+ let knowings = [], approvals = [];
3050
+ results.forEach(function (result) {
3051
+ if (result.type == 2) {
3052
+ let html = "";
3053
+ html += `<span class="status-approver">${MYMODEL.widgets.status.fields[result.status]}</span>`;
3054
+ html += `<p > <span style="text-decoration: underline;">${users[result.user_id].fullname}</span><span class="small-time"> ${users[result.user_id].position}</span></p>`;
3055
+ knowings.push(html);
3056
+ }
3057
+ if (result.type == 1) {
3058
+ let html = "";
3059
+ let sign = users[result.user_id].verify_signed && result.status == 3 ? `<img src="${CONFIG.app.url}/uploads/zuser/${users[result.user_id].verify_signed}" width="200">` : MYMODEL.widgets.status.fields[result.status];
3060
+ //var sign = "";
3061
+ html += `<span class="status-approver">${sign}</span>`;
3062
+ html += `<p class="footer-title"> <span style="text-decoration: underline;">${users[result.user_id].fullname}</span><span class="small-time"> ${users[result.user_id].position} <br> ${Util.dateFormat(result.updated_at, "DD MMM YYYY HH:mm")}</span></p>
3063
+ `;
3064
+ approvals.push(html);
3065
+ }
3066
+ })
3067
+
3068
+ let divColumn = (num) => {
3069
+ if (!num)
3070
+ return "";
3071
+
3072
+ if (num > 4) {
3073
+ num = num % 4;
3074
+ }
3075
+
3076
+ var div = "";
3077
+ if (num == 1) {
3078
+ div = "col-12 text-center";
3079
+ } else if (num == 2) {
3080
+ div = "col-6 text-center";
3081
+ } else if (num == 3) {
3082
+ div = "col-4 text-center";
3083
+ } else {
3084
+ div = "col-3 text-center";
3085
+ }
3086
+ return div;
3087
+ }
3088
+
3089
+ html += `<div class="row"><div class="col-12 text-center "><h5 class="knowing">Menyetujui</h5></div></div>`;
3090
+ html += `<div class="row d-flex justify-content-start align-items-end">`;
3091
+ let divClass = divColumn(approvals.length);
3092
+ approvals.forEach(function (item) {
3093
+ html += `<div class="${divClass}">`
3094
+ html += item;
3095
+ html += `</div>`;
3096
+ });
3097
+ html += `</div>`;
3098
+
3099
+ const knowingDiv = divColumn(knowings.length)
3100
+ if (knowings.length) {
3101
+ html += `<div class="row align-items-end"><div class="col-12 text-center mt-5"><h5 class="knowing">Mengetahui</h5></div></div>`;
3102
+ html += `<div class="row">`;
3103
+ knowings.forEach(function (item) {
3104
+ html += `<div class="${knowingDiv}">`
3105
+ html += item;
3106
+ html += `</div>`;
3107
+ })
3108
+ html += `</div>`;
3109
+ }
3110
+ return html;
3111
+ };
3112
+
3113
+
3114
+ /*
3115
+ Caches include WPA
3116
+ cache models in so it's no need call database repeatly
3117
+ */
3118
+
3119
+ zRoute.modelsCache = async() => {
3120
+ let models = zRoute.MYMODELS() || {};
3121
+ delete models.zrole;
3122
+ delete models.zuser_company;
3123
+ let obj = {};
3124
+ let companies;
3125
+ let mustCaches = ['relation', 'typeahead', 'multi_line_editor', 'dropdown_multi'];
3126
+ let nots = ['created_by','updated_by'];
3127
+ for (let keys in models) {
3128
+ let widgets = models[keys].widgets;
3129
+ for (let key in widgets) {
3130
+ if (Util.in_array(widgets[key].name, mustCaches)) {
3131
+ let widget = widgets[key];
3132
+ let table = widget.table;
3133
+ if (widget.fields[1] != undefined) {
3134
+ if (!obj[table]) {
3135
+ obj[table] = {}
3136
+ }
3137
+ if(!Util.in_array(key,nots)){
3138
+ obj[table][`${keys}___${key}`] = `${widgets[key].fields[1]} as ${key}`;
3139
+ }
3140
+ }
3141
+ }
3142
+ }
3143
+ }
3144
+ companies = await connection.results({
3145
+ table : 'zcompany'
3146
+ });
3147
+ obj.zuser = {};
3148
+ obj.zuser = {
3149
+ created_by : 'fullname as created_by',
3150
+ updated_by : 'fullname as updated_by'
3151
+ };
3152
+
3153
+ try {
3154
+ for(let keys in obj) {
3155
+ let checks = await connection.query(`SELECT EXISTS ( SELECT 1 FROM pg_tables WHERE tablename = '${keys}') AS oke;`);
3156
+ if(checks[0].oke) {
3157
+ if (!Util.in_array(keys, zRoute.tableHasNoCompanyId)) {
3158
+ let selects = ``;
3159
+ for(let key in obj[keys]) {
3160
+ selects += `${obj[keys][key]},`;
3161
+ }
3162
+ selects += `id, company_id`;
3163
+ for(const company of companies) {
3164
+ const results = await connection.results({
3165
+ table: keys,
3166
+ select: selects,
3167
+ where : {
3168
+ company_id : company.id
3169
+ }
3170
+ });
3171
+ for (let key in obj[keys]) {
3172
+ const splits = key.split("___") || [];
3173
+ let item = splits.length > 1 ? splits[1] : key;
3174
+ let arr = [];
3175
+ for (const result of results) {
3176
+ arr.push({id: result.id, zname: result[item]});
3177
+ }
3178
+ const myarray = Util.sortArray(arr, 'zname');
3179
+ myCache.set(`${keys}_${key}_${company.id}`, myarray);
3180
+ }
3181
+ }
3182
+ }
3183
+ }
3184
+ }
3185
+ } catch (e) {
3186
+ //debug(req,res,e.toString());
3187
+ console.log('modelsCache :',e.toString())
3188
+ }
3189
+
3190
+ return obj;
3191
+ };
3192
+
3193
+ zRoute.modelsCacheRenew = (table, companyId) => {
3194
+ if(myCache.has('MODELS_RELATIONS')) {
3195
+ let MODELS = myCache.get('MODELS_RELATIONS');
3196
+ let arr = Object.keys(MODELS) || [];
3197
+ let obj = MODELS[table] || {};
3198
+ if(Util.in_array(table,arr)) {
3199
+ let selects = '';
3200
+ for (let key in obj) {
3201
+ selects += `${obj[key]},`
3202
+ }
3203
+ selects += `id`;
3204
+ connection.results({
3205
+ select : selects,
3206
+ table : table,
3207
+ where : {
3208
+ company_id : companyId
3209
+ }
3210
+ }).then(function (results) {
3211
+ for (let key in obj) {
3212
+ const splits = key.split("___") || [];
3213
+ let item = splits.length > 1 ? splits[1] : key;
3214
+ let arr = [];
3215
+ for (const result of results) {
3216
+ arr.push({id: result.id, zname: result[item]});
3217
+ }
3218
+ const myarray = Util.sortArray(arr, 'zname');
3219
+ myCache.set(`${table}_${key}_${companyId}`, myarray);
3220
+ }
3221
+ });
3222
+ }
3223
+ }
3224
+ };
3225
+
3226
+ module.exports = zRoute;