zet-lib 6.0.0 → 6.0.2

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/README.md CHANGED
@@ -13,3 +13,52 @@ Installation
13
13
  ------------
14
14
 
15
15
  npm install zet-lib
16
+
17
+ Safe installation
18
+ -----------------
19
+
20
+ `zet-lib` includes some optional heavy features, such as browser/PDF automation and image processing.
21
+ If your app only needs the core helpers (database, cache, utilities, routers, mail, etc), a normal install is enough:
22
+
23
+ npm install zet-lib
24
+
25
+ If you want to avoid browser downloads in CI/CD or server environments:
26
+
27
+ PUPPETEER_SKIP_DOWNLOAD=1 npm install zet-lib
28
+
29
+ Optional features
30
+ -----------------
31
+
32
+ - `puppeteer`
33
+ - Used for browser/PDF style features.
34
+ - Starting from `zet-lib@6`, it is treated as optional during install.
35
+ - If you use a feature that needs Puppeteer and it is not installed, `zet-lib` will throw a clear error message.
36
+ - To install it explicitly:
37
+
38
+ npm install puppeteer
39
+
40
+ - `sharp`
41
+ - Used for image processing/compression features.
42
+ - It is optional because some environments do not need it or may have native install constraints.
43
+ - To install it explicitly:
44
+
45
+ npm install --include=optional sharp
46
+
47
+ Performance note
48
+ ----------------
49
+
50
+ `zet-lib` lazily loads its exports. This means `require("zet-lib")` will not immediately load all heavy modules.
51
+ Only the feature you access will load its underlying dependency tree.
52
+
53
+ Examples
54
+ --------
55
+
56
+ Use only core utilities:
57
+
58
+ const { Util, connection } = require("zet-lib");
59
+
60
+ Use Puppeteer-powered features:
61
+
62
+ const { puppeteer } = require("zet-lib");
63
+
64
+ // Make sure puppeteer is installed in your project first.
package/lib/index.js CHANGED
@@ -1,73 +1,95 @@
1
1
  "use strict";
2
2
 
3
- // Core modules - loaded immediately (lightweight)
4
- const coreModules = {
5
- access: require("./access"),
6
- Util: require("./Util"),
7
- myCache: require("./cache"),
8
- connection: require("./connection"),
9
- zDataTable: require("./zdataTable"),
10
- zDebug: require("./debug"),
11
- zForm: require("./Form"),
12
- io: require("./io"),
13
- zMail: require("./Mail"),
14
- moduleLib: require("./moduleLib"),
15
- Model: require("./Model"),
16
- zApp: require("./zapp"),
17
- zAppRouter: require("./zAppRouter"),
18
- zComponent: require("./zComponent"),
19
- zFn: require("./zFn"),
20
- zFunction: require("./zFunction"),
21
- zMenuRouter: require("./zMenuRouter"),
22
- zGeneratorRouter: require("./zGeneratorRouter"),
23
- zViewGenerator: require("./zViewGenerator"),
24
- zReport: require("./zReport"),
25
- zRoute: require("./zRoute"),
26
- zRole: require("./zRole"),
27
- zRoleRouter: require("./zRoleRouter"),
28
- zPage: require("./zPage"),
29
- zTester: require("./zTester"),
30
- zCache: require("./zCache"),
31
- zDropbox: require("./zDropbox"),
32
- csrf: require("./csrf")
33
- };
3
+ function lazyRequire(modulePath) {
4
+ return () => require(modulePath);
5
+ }
34
6
 
35
- // Heavy dependencies - lazy loaded (only when accessed)
36
- const lazyModules = {
37
- get puppeteer() {
38
- return require("puppeteer");
39
- },
40
- get moment() {
41
- return require("moment");
42
- },
43
- get ejs() {
44
- return require("ejs");
45
- },
46
- get axios() {
47
- return require("axios");
48
- },
49
- get Excel() {
50
- return require("exceljsremake");
51
- },
52
- get pm2() {
7
+ function optionalRequire(moduleName, installHint) {
8
+ return () => {
9
+ try {
10
+ return require(moduleName);
11
+ } catch (error) {
12
+ if (error && error.code === "MODULE_NOT_FOUND") {
13
+ const message =
14
+ installHint ||
15
+ `Optional dependency "${moduleName}" is not installed. Install it to use this feature.`;
16
+ const wrapped = new Error(message);
17
+ wrapped.code = "MODULE_NOT_FOUND";
18
+ wrapped.cause = error;
19
+ throw wrapped;
20
+ }
21
+ throw error;
22
+ }
23
+ };
24
+ }
25
+
26
+ const exportsMap = {
27
+ access: lazyRequire("./access"),
28
+ Util: lazyRequire("./Util"),
29
+ myCache: lazyRequire("./cache"),
30
+ connection: lazyRequire("./connection"),
31
+ zDataTable: lazyRequire("./zdataTable"),
32
+ zDebug: lazyRequire("./debug"),
33
+ zForm: lazyRequire("./Form"),
34
+ io: lazyRequire("./io"),
35
+ zMail: lazyRequire("./Mail"),
36
+ moduleLib: lazyRequire("./moduleLib"),
37
+ Model: lazyRequire("./Model"),
38
+ zApp: lazyRequire("./zapp"),
39
+ zAppRouter: lazyRequire("./zAppRouter"),
40
+ zComponent: lazyRequire("./zComponent"),
41
+ zFn: lazyRequire("./zFn"),
42
+ zFunction: lazyRequire("./zFunction"),
43
+ zMenuRouter: lazyRequire("./zMenuRouter"),
44
+ zGeneratorRouter: lazyRequire("./zGeneratorRouter"),
45
+ zViewGenerator: lazyRequire("./zViewGenerator"),
46
+ zReport: lazyRequire("./zReport"),
47
+ zRoute: lazyRequire("./zRoute"),
48
+ zRole: lazyRequire("./zRole"),
49
+ zRoleRouter: lazyRequire("./zRoleRouter"),
50
+ zPage: lazyRequire("./zPage"),
51
+ zTester: lazyRequire("./zTester"),
52
+ zCache: lazyRequire("./zCache"),
53
+ zDropbox: lazyRequire("./zDropbox"),
54
+ csrf: lazyRequire("./csrf"),
55
+ puppeteer: optionalRequire(
56
+ "puppeteer",
57
+ 'Optional dependency "puppeteer" is not installed. Install it with `npm install --include=optional zet-lib` or `npm install puppeteer` to use browser/PDF features.'
58
+ ),
59
+ moment: lazyRequire("moment"),
60
+ ejs: lazyRequire("ejs"),
61
+ axios: lazyRequire("axios"),
62
+ Excel: lazyRequire("exceljsremake"),
63
+ pm2: () => {
53
64
  try {
54
65
  return require("pm2");
55
66
  } catch (e) {
56
67
  return null;
57
68
  }
58
69
  },
59
- get nodemailer() {
60
- return require("nodemailer");
61
- },
62
- get readXlsxFile() {
63
- return require("read-excel-file/node");
64
- },
65
- get JSZip() {
66
- return require("jszip");
67
- },
68
- get pg() {
69
- return require("pg");
70
- }
70
+ nodemailer: lazyRequire("nodemailer"),
71
+ readXlsxFile: lazyRequire("read-excel-file/node"),
72
+ JSZip: lazyRequire("jszip"),
73
+ pg: lazyRequire("pg")
71
74
  };
72
75
 
73
- module.exports = Object.assign({}, coreModules, lazyModules);
76
+ const exported = {};
77
+
78
+ for (const [key, resolver] of Object.entries(exportsMap)) {
79
+ Object.defineProperty(exported, key, {
80
+ enumerable: true,
81
+ configurable: true,
82
+ get() {
83
+ const value = resolver();
84
+ Object.defineProperty(exported, key, {
85
+ value,
86
+ enumerable: true,
87
+ configurable: true,
88
+ writable: false
89
+ });
90
+ return value;
91
+ }
92
+ });
93
+ }
94
+
95
+ module.exports = exported;
@@ -1,359 +1,359 @@
1
- const router = require('express').Router();
2
- const {csrf} = require('zet-lib');
3
- const csrfProtection = csrf({cookie: true});
4
- const {Util, access, connection, moduleLib, zDebug, zRoute, zRole, zDataTable, zForm} = require('zet-lib');
5
- const MYMODEL = require('./../models/[[[TABLE_NAME]]]');
6
-
7
- router.get('/', async (req, res) => {
8
- await zRoute.attributeData(res, MYMODEL);
9
- let dataTable = new zDataTable(res.locals);
10
- dataTable.filterMODEL = await zRoute.dataTableFilterSync(req,res, MYMODEL, res.locals.gridFilter);
11
- const levels = zRole.myLevel(req, res, MYMODEL.table);
12
- dataTable.levels = levels;
13
- res.render(`layouts/${layout}`, {
14
- dataTable: dataTable,
15
- levels : levels,
16
- titleHeader: `<strong class="text text-info">${MYMODEL.title}</strong>`,
17
- breadcrumb : zForm.breadcrumbIndex(),
18
- myModal : zForm.modal({
19
- attributeData: res.locals.attributeData,
20
- visibles: res.locals.visibles,
21
- invisibles: res.locals.invisibles,
22
- routeName: MYMODEL.table,
23
- }, LANGUAGE),
24
- renderHead: `${MYMODEL.routeName}/indexcss.ejs`,
25
- renderBody: `${MYMODEL.routeName}/index.ejs`,
26
- renderEnd: `${MYMODEL.routeName}/indexjs.ejs`
27
- });
28
- });
29
-
30
- router.post('/list', async (req, res) => {
31
- const data = await zRoute.listData(req, res, MYMODEL, zRole);
32
- res.json(data);
33
- });
34
-
35
- router.get('/create', csrfProtection, async(req, res) => {
36
- let data = MYMODEL.datas;
37
- const zForms = await zRoute.formsFieldSync(req, res, MYMODEL, data);
38
- res.render(`layouts/${layout}`, {
39
- data: data,
40
- zForms: zForms,
41
- titleHeader: `${LANGUAGE['form_create']} : <strong><a href="/${MYMODEL.routeName}">${MYMODEL.title}</a></strong>`,
42
- csrfToken: req.csrfToken(),
43
- breadcrumb : zForm.breadcrumbCreate(MYMODEL.routeName),
44
- renderBody: `${MYMODEL.routeName}/create.ejs`,
45
- renderEnd: `${MYMODEL.routeName}/createjs.ejs`
46
- });
47
- });
48
-
49
- router.post('/create', csrfProtection, async (req, res) => {
50
- let json = Util.jsonSuccess(LANGUAGE['data_saved']);
51
- try {
52
- let data = zRoute.post(req,res, MYMODEL)[MYMODEL.routeName];
53
- const validator = zRoute.validator(data, MYMODEL);
54
- if(validator.status == 0) return res.json(validator.message);
55
- const result = await zRoute.insertSQL(req, res, MYMODEL.table, data);
56
- json.data=result;
57
- } catch (err) {
58
- if(Object.hasOwn(err,"sqlMessage")){
59
- json = Util.flashError(err.sqlMessage);
60
- } else {
61
- json = Util.flashError(err.toString());
62
- }
63
- zDebug(req, res, err);
64
- }
65
- res.json(json);
66
- });
67
-
68
- router.get('/update/:id', csrfProtection, async (req, res) => {
69
- const id = parseInt(req.params.id);
70
- const results = await connection.results({
71
- select:zRoute.selectData(MYMODEL),
72
- table: MYMODEL.table,
73
- where: {
74
- id: id,
75
- company_id: res.locals.companyId
76
- }
77
- });
78
- if (results.length == 0) {
79
- req.session.sessionFlash = Util.flashError(LANGUAGE['data_not_found']);
80
- return res.redirect('/' + MYMODEL.routeName);
81
- }
82
- let data = results[0];
83
- const zForms = await zRoute.formsFieldSync(req, res, MYMODEL, data);
84
- res.render(`layouts/${layout}`, {
85
- data: data,
86
- zForms: zForms,
87
- titleHeader: `${LANGUAGE['form_update']} : <strong><a href="/${MYMODEL.routeName}">${MYMODEL.title}</a></strong>`,
88
- csrfToken: req.csrfToken(),
89
- breadcrumb : zForm.breadcrumbUpdate(MYMODEL.routeName, id),
90
- renderBody: `${MYMODEL.routeName}/update.ejs`,
91
- renderEnd: `${MYMODEL.routeName}/updatejs.ejs`,
92
- });
93
- });
94
-
95
- router.post('/update/:id', csrfProtection, async (req, res) => {
96
- let json = Util.jsonSuccess(LANGUAGE['data_saved']);
97
- try {
98
- const id = parseInt(req.params.id);
99
- let data = zRoute.post(req,res, MYMODEL)[MYMODEL.routeName];
100
- const validator = zRoute.validator(data, MYMODEL);
101
- if(validator.status == 0) return res.json(validator.message);
102
- const result = await zRoute.updateSQL(req, res,MYMODEL.table, data, {id:id});
103
- json.data=result;
104
- } catch (err) {
105
- console.log(err)
106
- if(Object.hasOwn(err,"sqlMessage")){
107
- json = Util.flashError(err.sqlMessage);
108
- } else {
109
- json = Util.flashError(err.toString());
110
- }
111
- zDebug(req, res, err)
112
- }
113
- res.json(json);
114
- });
115
-
116
- router.delete('/delete', async (req, res) => {
117
- const id = req.body.id;
118
- let json = Util.jsonSuccess(LANGUAGE['data_delete']);
119
- try {
120
- await zRoute.deleteSQL(MYMODEL.table, id, res.locals.companyId);
121
- } catch (err) {
122
- json = Util.flashError(err.toString());
123
- zDebug(req, res, err)
124
- }
125
- res.json(json);
126
- });
127
-
128
- router.get('/view/:id', async (req, res) => {
129
- await zRoute.attributeData(res, MYMODEL);
130
- const id = req.params.id;
131
- let data = {};
132
- let zForms = {};
133
- try {
134
- const results = await connection.results({select:zRoute.selectData(MYMODEL),table:MYMODEL.table,where:{id:id}});
135
- if (results.length == 0) {
136
- req.session.sessionFlash = Util.flashError(LANGUAGE['data_not_found']);
137
- return res.redirect('/' + MYMODEL.routeName);
138
- }
139
- data = results[0];
140
- zForms = await zRoute.viewFormsSync(req, res, MYMODEL, data);
141
- } catch (err){
142
- zDebug(req, res, err);
143
- res.send("Err");
144
- }
145
- res.render(`layouts/${layout}`, {
146
- data: data,
147
- Util:Util,
148
- zForms:zForms,
149
- titleHeader: `View : <strong><a href="/${MYMODEL.routeName}">${MYMODEL.title}</a></strong>`,
150
- breadcrumb : zForm.breadcrumbView(MYMODEL.routeName),
151
- levels: zRole.myLevel(req, res, MYMODEL.table),
152
- renderBody: `${MYMODEL.routeName}/view.ejs`
153
- });
154
- });
155
-
156
- router.get('/excel-query', async (req,res) => {
157
- await zRoute.excelQuery(req, res, MYMODEL);
158
- });
159
-
160
- router.get('/excel', async (req, res) => {
161
- const fields = MYMODEL.keysExcel;
162
- const results = await connection.results({
163
- table: MYMODEL.table,
164
- where: {company_id: res.locals.companyId},
165
- orderBy: ['id', 'DESC']
166
- });
167
- await zRoute.excel(req, res, MYMODEL, fields, results);
168
- });
169
-
170
- router.get('/sample', async (req, res) => {
171
- let fields = [];
172
- for (let i = 0; i < MYMODEL.keysExcel.length; i++) {
173
- if (!Util.in_array(MYMODEL.keysExcel[i], Util.nots)) {
174
- fields.push(MYMODEL.keysExcel[i]);
175
- }
176
- }
177
- const results = await connection.results({
178
- table:MYMODEL.table,
179
- where:{
180
- company_id:res.locals.companyId
181
- },
182
- orderBy:["id","desc"], limit:10
183
- });
184
- let callback=(result,field)=> {
185
- return MYMODEL.widgets[field] && MYMODEL.widgets[field].name == 'datepicker' ? Util.dateSql(result[field]) : result[field];
186
- };
187
- await zRoute.excel(req, res, MYMODEL, fields, results, callback);
188
- });
189
-
190
- router.get('/import',csrfProtection, async (req, res) => {
191
- const room = res.locals.token;
192
- res.render(`layouts/${layout}`, {
193
- room: room,
194
- titleHeader: `Import / Upload data : <strong><a href="/${MYMODEL.routeName}">${MYMODEL.title}</a></strong>`,
195
- csrfToken: req.csrfToken(),
196
- breadcrumb : zForm.breadcrumbImport(MYMODEL.routeName),
197
- renderBody: `${MYMODEL.routeName}/import.ejs`,
198
- renderEnd: `${MYMODEL.routeName}/importjs.ejs`
199
- });
200
- });
201
-
202
-
203
- router.post('/import', async(req, res) => {
204
- res.json(await zRoute.import(req,res,MYMODEL));
205
- });
206
-
207
- router.get('/approval/:id', async (req, res) => {
208
- await zRoute.attributeData(res, MYMODEL);
209
- const id = req.params.id;
210
- let data = {};
211
- let data2 = {};
212
- let zForms = {};
213
- let zForms2 = {};
214
- let result = {};
215
- try {
216
- result = await connection.result({table: MYMODEL.table, where: {id: id}});
217
- if (!result.id) {
218
- req.session.sessionFlash = Util.flashError(LANGUAGE['data_not_found']);
219
- return res.redirect('/' + MYMODEL.routeName);
220
- }
221
- data=result;
222
- moduleLib.editor(req, res);
223
- zForms = await zRoute.viewFormsSync(req, res, MYMODEL, result);
224
- const contentScript = `$("#submit_draft").on("click", function () {$("#status").val(1);ajaxPost("/zzapproval",$("#form-group").serializeArray(), function (data) {
225
- if (data.status == 0) {
226
- toastr.error(data.message, data.title);
227
- } else {
228
- toastr.success(data.title, data.message);
229
- }
230
- });});
231
- $("#submit").on("click", function () {
232
- $('[name="zapprovals[status]"]').val(2);
233
- ajaxPost("/zzapproval",$("#form-group").serializeArray(), function (data) {
234
- if (data.status == 0) {
235
- toastr.error(data.message, data.title);
236
- } else {
237
- toastr.success(data.title, data.message);
238
- location.href = "";
239
- }
240
- });
241
- });
242
- `;
243
- await moduleLib.addScript(req, res, contentScript);
244
- const MODEL_APROVALS = require("./../models/zapprovals");
245
- const rows = await connection.results({
246
- table: "zapprovals",
247
- where: {table: MYMODEL.table, company_id: res.locals.companyId, id_data: id}
248
- });
249
- if (rows.length) {
250
- data2 = rows[0];
251
- } else {
252
- let obj = {};
253
- obj.token = Util.uuid();
254
- obj.status = 1;
255
- obj.table = MYMODEL.table;
256
- obj.company_id = res.locals.companyId;
257
- obj.id_data = id;
258
- obj.created_by = res.locals.userId;
259
- obj.updated_by = res.locals.userId;
260
- obj.created_at = Util.now();
261
- let zfields = await connection.result({table: "zfields", where: {table: MYMODEL.table}});
262
- let jsonApproval = zfields.approval_json || {}
263
- obj.template = jsonApproval.content || {}
264
- let title = jsonApproval.title;
265
- if (title) {
266
- let titleData = title;
267
- for (var key in data) {
268
- titleData = Util.replaceAll(titleData, "{{" + key + "}}", data[key])
269
- }
270
- obj.title = titleData
271
- }
272
- if (jsonApproval.hasOwnProperty("approvers")) {
273
- obj.approvers = JSON.stringify(jsonApproval.approvers);
274
- obj.knowings = JSON.stringify(jsonApproval.knowings);
275
- obj.type = 1;
276
- }
277
- //insert default data
278
- await connection.insert({table: "zapprovals", data: obj});
279
- data2 = obj;
280
- }
281
- zForms2 = await zRoute.formsFieldSync(req, res, MODEL_APROVALS, data2);
282
- } catch (err) {
283
- zDebug(req, res, err);
284
- res.send("Err");
285
- }
286
- res.render(`layouts/${layout}`, {
287
- zForms: zForms,
288
- zForms2: zForms2,
289
- data: result,
290
- result:result,
291
- data2: data2,
292
- Util: Util,
293
- levels: zRole.myLevel(req, res, MYMODEL.table),
294
- breadcrumb : zForm.breadcrumbApproval(MYMODEL.routeName, id),
295
- renderBody: `${MYMODEL.routeName}/approval.ejs`
296
- });
297
- });
298
-
299
- router.get('/preview/:token', async (req, res) => {
300
- let token = req.params.token;
301
- let data = {}, data2 = {};
302
- let template = "";
303
- let footers = "";
304
- try {
305
- let zfields = await connection.result({table: "zfields", where: {table: MYMODEL.table}});
306
- let jsonApproval = zfields.approval_json || {}
307
- let mytemplate = jsonApproval.content || {}
308
- let results = await connection.results({table: "zapprovals", where: {token: token}});
309
- if (results.length == 0) {
310
- req.session.sessionFlash = Util.flashError(LANGUAGE['data_not_found']);
311
- return res.redirect('/' + MYMODEL.routeName);
312
- }
313
- if(results[0].status == 1){
314
- await connection.update({
315
- table : "zapprovals",
316
- data: {
317
- template : mytemplate
318
- },
319
- where : {
320
- token:token
321
- }
322
- })
323
- results = await connection.results({table: "zapprovals", where: {token: token}});
324
- }
325
- let MYMODEL2 = require("./../models/zapprovals")
326
- data = await zRoute.viewTable(req, res, MYMODEL2, results[0], true);
327
- let row = await connection.result({table: results[0].table, where: {id: results[0].id_data}});
328
- data2 = await zRoute.viewTable(req, res, MYMODEL, row, true);
329
- template = data.template;
330
- let title = data.title || ""
331
- for (var key in data2) {
332
- template = Util.replaceAll(template, "{{" + key + "}}", data2[key])
333
- title = Util.replaceAll(title, "{{" + key + "}}", data2[key])
334
- }
335
- data.title = title;
336
- var details = await connection.results({table: "zapprovals_details", where: {title_id: results[0].id}});
337
- if (details.length) {
338
- footers = await zRoute.approversFooter(details);
339
- }
340
- } catch (err) {
341
- zDebug(req, res, err);
342
- res.send("Err");
343
- }
344
- res.render(`layouts/blank`, {
345
- template: template,
346
- data: data,
347
- footers: footers,
348
- Util: Util,
349
- details: details,
350
- renderBody: 'index/zapprovals_preview.ejs'
351
- });
352
- });
353
-
354
- router.post('/grid', access, zRoute.postGrid);
355
- router.post('/reload', access, zRoute.postGridReload);
356
- router.post('/chains', access, zRoute.chains);
357
- router.post('/get_attributes',access, zRoute.getAttributes);
358
-
359
- module.exports = router;
1
+ const router = require('express').Router();
2
+ const {csrf} = require('zet-lib');
3
+ const csrfProtection = csrf({cookie: true});
4
+ const {Util, access, connection, moduleLib, zDebug, zRoute, zRole, zDataTable, zForm} = require('zet-lib');
5
+ const MYMODEL = require('./../models/[[[TABLE_NAME]]]');
6
+
7
+ router.get('/', async (req, res) => {
8
+ await zRoute.attributeData(res, MYMODEL);
9
+ let dataTable = new zDataTable(res.locals);
10
+ dataTable.filterMODEL = await zRoute.dataTableFilterSync(req,res, MYMODEL, res.locals.gridFilter);
11
+ const levels = zRole.myLevel(req, res, MYMODEL.table);
12
+ dataTable.levels = levels;
13
+ res.render(`layouts/${layout}`, {
14
+ dataTable: dataTable,
15
+ levels : levels,
16
+ titleHeader: `<strong class="text text-info">${MYMODEL.title}</strong>`,
17
+ breadcrumb : zForm.breadcrumbIndex(),
18
+ myModal : zForm.modal({
19
+ attributeData: res.locals.attributeData,
20
+ visibles: res.locals.visibles,
21
+ invisibles: res.locals.invisibles,
22
+ routeName: MYMODEL.table,
23
+ }, LANGUAGE),
24
+ renderHead: `${MYMODEL.routeName}/indexcss.ejs`,
25
+ renderBody: `${MYMODEL.routeName}/index.ejs`,
26
+ renderEnd: `${MYMODEL.routeName}/indexjs.ejs`
27
+ });
28
+ });
29
+
30
+ router.post('/list', async (req, res) => {
31
+ const data = await zRoute.listData(req, res, MYMODEL, zRole);
32
+ res.json(data);
33
+ });
34
+
35
+ router.get('/create', csrfProtection, async(req, res) => {
36
+ let data = MYMODEL.datas;
37
+ const zForms = await zRoute.formsFieldSync(req, res, MYMODEL, data);
38
+ res.render(`layouts/${layout}`, {
39
+ data: data,
40
+ zForms: zForms,
41
+ titleHeader: `${LANGUAGE['form_create']} : <strong><a href="/${MYMODEL.routeName}">${MYMODEL.title}</a></strong>`,
42
+ csrfToken: req.csrfToken(),
43
+ breadcrumb : zForm.breadcrumbCreate(MYMODEL.routeName),
44
+ renderBody: `${MYMODEL.routeName}/create.ejs`,
45
+ renderEnd: `${MYMODEL.routeName}/createjs.ejs`
46
+ });
47
+ });
48
+
49
+ router.post('/create', csrfProtection, async (req, res) => {
50
+ let json = Util.jsonSuccess(LANGUAGE['data_saved']);
51
+ try {
52
+ let data = zRoute.post(req,res, MYMODEL)[MYMODEL.routeName];
53
+ const validator = zRoute.validator(data, MYMODEL);
54
+ if(validator.status == 0) return res.json(validator.message);
55
+ const result = await zRoute.insertSQL(req, res, MYMODEL.table, data);
56
+ json.data=result;
57
+ } catch (err) {
58
+ if(Object.hasOwn(err,"sqlMessage")){
59
+ json = Util.flashError(err.sqlMessage);
60
+ } else {
61
+ json = Util.flashError(err.toString());
62
+ }
63
+ zDebug(req, res, err);
64
+ }
65
+ res.json(json);
66
+ });
67
+
68
+ router.get('/update/:id', csrfProtection, async (req, res) => {
69
+ const id = parseInt(req.params.id);
70
+ const results = await connection.results({
71
+ select:zRoute.selectData(MYMODEL),
72
+ table: MYMODEL.table,
73
+ where: {
74
+ id: id,
75
+ company_id: res.locals.companyId
76
+ }
77
+ });
78
+ if (results.length == 0) {
79
+ req.session.sessionFlash = Util.flashError(LANGUAGE['data_not_found']);
80
+ return res.redirect('/' + MYMODEL.routeName);
81
+ }
82
+ let data = results[0];
83
+ const zForms = await zRoute.formsFieldSync(req, res, MYMODEL, data);
84
+ res.render(`layouts/${layout}`, {
85
+ data: data,
86
+ zForms: zForms,
87
+ titleHeader: `${LANGUAGE['form_update']} : <strong><a href="/${MYMODEL.routeName}">${MYMODEL.title}</a></strong>`,
88
+ csrfToken: req.csrfToken(),
89
+ breadcrumb : zForm.breadcrumbUpdate(MYMODEL.routeName, id),
90
+ renderBody: `${MYMODEL.routeName}/update.ejs`,
91
+ renderEnd: `${MYMODEL.routeName}/updatejs.ejs`,
92
+ });
93
+ });
94
+
95
+ router.post('/update/:id', csrfProtection, async (req, res) => {
96
+ let json = Util.jsonSuccess(LANGUAGE['data_saved']);
97
+ try {
98
+ const id = parseInt(req.params.id);
99
+ let data = zRoute.post(req,res, MYMODEL)[MYMODEL.routeName];
100
+ const validator = zRoute.validator(data, MYMODEL);
101
+ if(validator.status == 0) return res.json(validator.message);
102
+ const result = await zRoute.updateSQL(req, res,MYMODEL.table, data, {id:id});
103
+ json.data=result;
104
+ } catch (err) {
105
+ console.log(err)
106
+ if(Object.hasOwn(err,"sqlMessage")){
107
+ json = Util.flashError(err.sqlMessage);
108
+ } else {
109
+ json = Util.flashError(err.toString());
110
+ }
111
+ zDebug(req, res, err)
112
+ }
113
+ res.json(json);
114
+ });
115
+
116
+ router.delete('/delete', async (req, res) => {
117
+ const id = req.body.id;
118
+ let json = Util.jsonSuccess(LANGUAGE['data_delete']);
119
+ try {
120
+ await zRoute.deleteSQL(MYMODEL.table, id, res.locals.companyId);
121
+ } catch (err) {
122
+ json = Util.flashError(err.toString());
123
+ zDebug(req, res, err)
124
+ }
125
+ res.json(json);
126
+ });
127
+
128
+ router.get('/view/:id', async (req, res) => {
129
+ await zRoute.attributeData(res, MYMODEL);
130
+ const id = req.params.id;
131
+ let data = {};
132
+ let zForms = {};
133
+ try {
134
+ const results = await connection.results({select:zRoute.selectData(MYMODEL),table:MYMODEL.table,where:{id:id}});
135
+ if (results.length == 0) {
136
+ req.session.sessionFlash = Util.flashError(LANGUAGE['data_not_found']);
137
+ return res.redirect('/' + MYMODEL.routeName);
138
+ }
139
+ data = results[0];
140
+ zForms = await zRoute.viewFormsSync(req, res, MYMODEL, data);
141
+ } catch (err){
142
+ zDebug(req, res, err);
143
+ res.send("Err");
144
+ }
145
+ res.render(`layouts/${layout}`, {
146
+ data: data,
147
+ Util:Util,
148
+ zForms:zForms,
149
+ titleHeader: `View : <strong><a href="/${MYMODEL.routeName}">${MYMODEL.title}</a></strong>`,
150
+ breadcrumb : zForm.breadcrumbView(MYMODEL.routeName),
151
+ levels: zRole.myLevel(req, res, MYMODEL.table),
152
+ renderBody: `${MYMODEL.routeName}/view.ejs`
153
+ });
154
+ });
155
+
156
+ router.get('/excel-query', async (req,res) => {
157
+ await zRoute.excelQuery(req, res, MYMODEL);
158
+ });
159
+
160
+ router.get('/excel', async (req, res) => {
161
+ const fields = MYMODEL.keysExcel;
162
+ const results = await connection.results({
163
+ table: MYMODEL.table,
164
+ where: {company_id: res.locals.companyId},
165
+ orderBy: ['id', 'DESC']
166
+ });
167
+ await zRoute.excel(req, res, MYMODEL, fields, results);
168
+ });
169
+
170
+ router.get('/sample', async (req, res) => {
171
+ let fields = [];
172
+ for (let i = 0; i < MYMODEL.keysExcel.length; i++) {
173
+ if (!Util.in_array(MYMODEL.keysExcel[i], Util.nots)) {
174
+ fields.push(MYMODEL.keysExcel[i]);
175
+ }
176
+ }
177
+ const results = await connection.results({
178
+ table:MYMODEL.table,
179
+ where:{
180
+ company_id:res.locals.companyId
181
+ },
182
+ orderBy:["id","desc"], limit:10
183
+ });
184
+ let callback=(result,field)=> {
185
+ return MYMODEL.widgets[field] && MYMODEL.widgets[field].name == 'datepicker' ? Util.dateSql(result[field]) : result[field];
186
+ };
187
+ await zRoute.excel(req, res, MYMODEL, fields, results, callback);
188
+ });
189
+
190
+ router.get('/import',csrfProtection, async (req, res) => {
191
+ const room = res.locals.token;
192
+ res.render(`layouts/${layout}`, {
193
+ room: room,
194
+ titleHeader: `Import / Upload data : <strong><a href="/${MYMODEL.routeName}">${MYMODEL.title}</a></strong>`,
195
+ csrfToken: req.csrfToken(),
196
+ breadcrumb : zForm.breadcrumbImport(MYMODEL.routeName),
197
+ renderBody: `${MYMODEL.routeName}/import.ejs`,
198
+ renderEnd: `${MYMODEL.routeName}/importjs.ejs`
199
+ });
200
+ });
201
+
202
+
203
+ router.post('/import', async(req, res) => {
204
+ res.json(await zRoute.import(req,res,MYMODEL));
205
+ });
206
+
207
+ router.get('/approval/:id', async (req, res) => {
208
+ await zRoute.attributeData(res, MYMODEL);
209
+ const id = req.params.id;
210
+ let data = {};
211
+ let data2 = {};
212
+ let zForms = {};
213
+ let zForms2 = {};
214
+ let result = {};
215
+ try {
216
+ result = await connection.result({table: MYMODEL.table, where: {id: id}});
217
+ if (!result.id) {
218
+ req.session.sessionFlash = Util.flashError(LANGUAGE['data_not_found']);
219
+ return res.redirect('/' + MYMODEL.routeName);
220
+ }
221
+ data=result;
222
+ moduleLib.editor(req, res);
223
+ zForms = await zRoute.viewFormsSync(req, res, MYMODEL, result);
224
+ const contentScript = `$("#submit_draft").on("click", function () {$("#status").val(1);ajaxPost("/zzapproval",$("#form-group").serializeArray(), function (data) {
225
+ if (data.status == 0) {
226
+ toastr.error(data.message, data.title);
227
+ } else {
228
+ toastr.success(data.title, data.message);
229
+ }
230
+ });});
231
+ $("#submit").on("click", function () {
232
+ $('[name="zapprovals[status]"]').val(2);
233
+ ajaxPost("/zzapproval",$("#form-group").serializeArray(), function (data) {
234
+ if (data.status == 0) {
235
+ toastr.error(data.message, data.title);
236
+ } else {
237
+ toastr.success(data.title, data.message);
238
+ location.href = "";
239
+ }
240
+ });
241
+ });
242
+ `;
243
+ await moduleLib.addScript(req, res, contentScript);
244
+ const MODEL_APROVALS = require("./../models/zapprovals");
245
+ const rows = await connection.results({
246
+ table: "zapprovals",
247
+ where: {table: MYMODEL.table, company_id: res.locals.companyId, id_data: id}
248
+ });
249
+ if (rows.length) {
250
+ data2 = rows[0];
251
+ } else {
252
+ let obj = {};
253
+ obj.token = Util.uuid();
254
+ obj.status = 1;
255
+ obj.table = MYMODEL.table;
256
+ obj.company_id = res.locals.companyId;
257
+ obj.id_data = id;
258
+ obj.created_by = res.locals.userId;
259
+ obj.updated_by = res.locals.userId;
260
+ obj.created_at = Util.now();
261
+ let zfields = await connection.result({table: "zfields", where: {table: MYMODEL.table}});
262
+ let jsonApproval = zfields.approval_json || {}
263
+ obj.template = jsonApproval.content || {}
264
+ let title = jsonApproval.title;
265
+ if (title) {
266
+ let titleData = title;
267
+ for (var key in data) {
268
+ titleData = Util.replaceAll(titleData, "{{" + key + "}}", data[key])
269
+ }
270
+ obj.title = titleData
271
+ }
272
+ if (jsonApproval.hasOwnProperty("approvers")) {
273
+ obj.approvers = JSON.stringify(jsonApproval.approvers);
274
+ obj.knowings = JSON.stringify(jsonApproval.knowings);
275
+ obj.type = 1;
276
+ }
277
+ //insert default data
278
+ await connection.insert({table: "zapprovals", data: obj});
279
+ data2 = obj;
280
+ }
281
+ zForms2 = await zRoute.formsFieldSync(req, res, MODEL_APROVALS, data2);
282
+ } catch (err) {
283
+ zDebug(req, res, err);
284
+ res.send("Err");
285
+ }
286
+ res.render(`layouts/${layout}`, {
287
+ zForms: zForms,
288
+ zForms2: zForms2,
289
+ data: result,
290
+ result:result,
291
+ data2: data2,
292
+ Util: Util,
293
+ levels: zRole.myLevel(req, res, MYMODEL.table),
294
+ breadcrumb : zForm.breadcrumbApproval(MYMODEL.routeName, id),
295
+ renderBody: `${MYMODEL.routeName}/approval.ejs`
296
+ });
297
+ });
298
+
299
+ router.get('/preview/:token', async (req, res) => {
300
+ let token = req.params.token;
301
+ let data = {}, data2 = {};
302
+ let template = "";
303
+ let footers = "";
304
+ try {
305
+ let zfields = await connection.result({table: "zfields", where: {table: MYMODEL.table}});
306
+ let jsonApproval = zfields.approval_json || {}
307
+ let mytemplate = jsonApproval.content || {}
308
+ let results = await connection.results({table: "zapprovals", where: {token: token}});
309
+ if (results.length == 0) {
310
+ req.session.sessionFlash = Util.flashError(LANGUAGE['data_not_found']);
311
+ return res.redirect('/' + MYMODEL.routeName);
312
+ }
313
+ if(results[0].status == 1){
314
+ await connection.update({
315
+ table : "zapprovals",
316
+ data: {
317
+ template : mytemplate
318
+ },
319
+ where : {
320
+ token:token
321
+ }
322
+ })
323
+ results = await connection.results({table: "zapprovals", where: {token: token}});
324
+ }
325
+ let MYMODEL2 = require("./../models/zapprovals")
326
+ data = await zRoute.viewTable(req, res, MYMODEL2, results[0], true);
327
+ let row = await connection.result({table: results[0].table, where: {id: results[0].id_data}});
328
+ data2 = await zRoute.viewTable(req, res, MYMODEL, row, true);
329
+ template = data.template;
330
+ let title = data.title || ""
331
+ for (var key in data2) {
332
+ template = Util.replaceAll(template, "{{" + key + "}}", data2[key])
333
+ title = Util.replaceAll(title, "{{" + key + "}}", data2[key])
334
+ }
335
+ data.title = title;
336
+ var details = await connection.results({table: "zapprovals_details", where: {title_id: results[0].id}});
337
+ if (details.length) {
338
+ footers = await zRoute.approversFooter(details);
339
+ }
340
+ } catch (err) {
341
+ zDebug(req, res, err);
342
+ res.send("Err");
343
+ }
344
+ res.render(`layouts/blank`, {
345
+ template: template,
346
+ data: data,
347
+ footers: footers,
348
+ Util: Util,
349
+ details: details,
350
+ renderBody: 'index/zapprovals_preview.ejs'
351
+ });
352
+ });
353
+
354
+ router.post('/grid', access, zRoute.postGrid);
355
+ router.post('/reload', access, zRoute.postGridReload);
356
+ router.post('/chains', access, zRoute.chains);
357
+ router.post('/get_attributes',access, zRoute.getAttributes);
358
+
359
+ module.exports = router;
package/lib/zAppRouter.js CHANGED
@@ -21,7 +21,6 @@ const zCache = require("./zCache");
21
21
  const getPm2 = require("./optionalPm2");
22
22
  const zFunction = require("./zFunction");
23
23
  const qs = require("qs");
24
- const zip = require("express-zip");
25
24
  const path = require("path");
26
25
 
27
26
  // Lazy load sharp with error handling for cross-platform compatibility
@@ -46,6 +45,25 @@ const fetch = require("isomorphic-fetch");
46
45
  const JSZip = require("jszip");
47
46
  const zDropbox = require("./zDropbox");
48
47
 
48
+ async function sendZipResponse(res, files, zipName) {
49
+ const archive = new JSZip();
50
+ for (const file of files) {
51
+ const content = await fs.readFile(file.path);
52
+ archive.file(file.name, content);
53
+ }
54
+
55
+ const buffer = await archive.generateAsync({
56
+ type: "nodebuffer",
57
+ compression: "DEFLATE",
58
+ compressionOptions: { level: 9 }
59
+ });
60
+
61
+ res.setHeader("Content-Type", "application/zip");
62
+ res.setHeader("Content-Disposition", `attachment; filename="${zipName}"`);
63
+ res.setHeader("Content-Length", buffer.length);
64
+ res.send(buffer);
65
+ }
66
+
49
67
  if (typeof global.dirRoot === 'undefined') {
50
68
  global.dirRoot = Util.dirRoot;
51
69
  }
@@ -1767,7 +1785,7 @@ router.get("/zdownloads-dropzone/:table/:field/:id", async (req, res) => {
1767
1785
  }
1768
1786
  }
1769
1787
  io.to(room).emit("message", `Zip files complete...`);
1770
- res.zip(arr, `${field}_${table}_${id}.zip`);
1788
+ await sendZipResponse(res, arr, `${field}_${table}_${id}.zip`);
1771
1789
  } catch (e) {
1772
1790
  console.log(e);
1773
1791
  res.json(e + "");
@@ -2,9 +2,7 @@ const express = require('express')
2
2
  const router = express.Router()
3
3
  // setup route middlewares
4
4
  const csrf = require('./csrf')
5
- const bodyParser = require('body-parser')
6
5
  const path = require('path')
7
- const parseForm = bodyParser.urlencoded({ extended: true })
8
6
  const csrfProtection = csrf({ cookie: true })
9
7
  const getPm2 = require('./optionalPm2')
10
8
  const env = process.env.NODE_ENV || 'development'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zet-lib",
3
- "version": "6.0.0",
3
+ "version": "6.0.2",
4
4
  "description": "zet is a library that part of zet generator.",
5
5
  "engines": {
6
6
  "node": ">=18"
@@ -21,39 +21,35 @@
21
21
  "!lib/**/__tests__/"
22
22
  ],
23
23
  "scripts": {
24
- "lint": "standard",
25
- "test-find": "find ./lib/**/__tests__ -name *.test.js | xargs mocha",
26
- "test": "npm run lint && npm run unit",
27
- "unit": "nyc node test.js"
24
+ "test": "npm run unit",
25
+ "unit": "node -e \"console.log('No automated tests are configured for this repo yet.')\""
28
26
  },
29
27
  "sideEffects": false,
30
28
  "dependencies": {
31
- "axios": "^1.15.0",
29
+ "axios": "^1.18.1",
32
30
  "dotenv": "^16.5.0",
33
31
  "dropbox": "^10.34.0",
34
- "ejs": "^3.1.10",
35
- "exceljsremake": "^0.1.4",
36
- "express-zip": "^3.0.0",
32
+ "ejs": "^6.0.1",
33
+ "exceljsremake": "^0.1.5",
37
34
  "fs-extra": "^11.3.4",
38
35
  "isomorphic-fetch": "^3.0.0",
39
36
  "js-sha256": "^0.11.1",
40
37
  "jszip": "^3.10.1",
41
38
  "moment": "^2.30.1",
42
39
  "node-cache": "^5.1.2",
43
- "nodemailer": "^8.0.5",
40
+ "nodemailer": "^9.0.3",
44
41
  "pg": "^8.16.3",
45
- "puppeteer": "^25.1.0",
46
42
  "qs": "^6.14.0",
47
43
  "randomstring": "^1.3.1",
48
44
  "read-excel-file": "^5.8.0",
49
45
  "socket.io": "^4.8.3"
50
46
  },
51
47
  "optionalDependencies": {
52
- "sharp": "^0.34.1"
48
+ "puppeteer": "^25.1.0",
49
+ "sharp": "^0.35.3"
53
50
  },
54
51
  "devDependencies": {
55
- "nyc": "^18.0.0",
56
- "standard": "^17.1.2"
52
+ "nyc": "^18.0.0"
57
53
  },
58
54
  "overrides": {
59
55
  "istanbul-lib-processinfo": {