zet-lib 1.2.31 → 1.2.32

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/index.js CHANGED
@@ -12,6 +12,7 @@ module.exports = {
12
12
  zMail: require('./Mail'),
13
13
  moduleLib: require('./moduleLib'),
14
14
  zApp: require('./zapp'),
15
+ zAppRouter: require('./zAppRouter'),
15
16
  zComponent: require('./zComponent'),
16
17
  zFn: require('./zFn'),
17
18
  zFunction: require('./zFunction'),
@@ -0,0 +1,1298 @@
1
+ const express = require('express')
2
+ const router = express.Router()
3
+ const csrf = require('csurf')
4
+ const csrfProtection = csrf({ cookie: true })
5
+ const zRoute = require('./zRoute')
6
+ const connection = require('./connection')
7
+ const access = require('./access')
8
+ const myCache = require('./cache')
9
+ const Util = require('./Util')
10
+ const moment = require('moment')
11
+ const fs = require('fs')
12
+ const moduleLib = require('./moduleLib')
13
+ var env = process.env.NODE_ENV || 'development'
14
+ var ecosystem = require(`${dirRoot}/ecosystem.config.js`)
15
+ const config = require('dotenv').config()
16
+ const debug = require('./debug')
17
+ const io = require('./io')
18
+ const Mail = require('./Mail')
19
+ const zCache = require('./zCache')
20
+ const pm2 = require('pm2')
21
+
22
+ /*
23
+ ajax Post
24
+ */
25
+ router.post('/zajax', zRoute.ajax)
26
+ router.get('/ztypeahead/:table/:field', zRoute.typeahead)
27
+ router.post('/ztypeaheadpost/:table/:field', zRoute.typeaheadpost)
28
+
29
+ //password
30
+ router.post('/password-change', zRoute.changePassword)
31
+ router.post('/reset-password/:forgot_password', zRoute.resetPassword)
32
+ //logout
33
+ router.get('/logout', zRoute.logout)
34
+ /*
35
+ function for build form for table type
36
+ */
37
+ router.post('/buildform', csrfProtection, zRoute.buildForm)
38
+ /*
39
+ function for tab access if any
40
+ */
41
+ router.post('/ztab-access', csrfProtection, zRoute.tabAccess)
42
+
43
+ router.get('/profile', csrfProtection, access, async (req, res) => {
44
+ const MYMODELS = myCache.get('MYMODELS')
45
+ let MYMODEL = MYMODELS['zuser']
46
+ let result = await connection.result({ table: 'zuser', where: { id: res.locals.userId } })
47
+ let role = await connection.result({ table: 'zrole', where: { id: result.role_id } })
48
+ let canEditCompany = false
49
+ if (result.role_id == 1 || result.role_id == 2) {
50
+ canEditCompany = true
51
+ }
52
+ let company = await connection.result({ table: 'zcompany', where: { id: res.locals.companyId } })
53
+ let verify_signed = result.verify_signed ? '/uploads/zuser/' + result.verify_signed : '/img/user.png'
54
+ res.render('layouts/' + layout, {
55
+ menu: { menu: 'profile' },
56
+ data: result,
57
+ attributeData: MYMODEL,
58
+ role: role,
59
+ company: company,
60
+ canEditCompany: canEditCompany,
61
+ verify_signed: verify_signed,
62
+ routeName: 'zuser',
63
+ csrfToken: req.csrfToken(),
64
+ renderHead: 'index/profile_head.ejs',
65
+ renderBody: 'index/profile.ejs',
66
+ renderEnd: 'index/profilejs.ejs',
67
+ })
68
+ })
69
+
70
+ router.post('/profile', access, async (req, res) => {
71
+ const MYMODELS = myCache.get('MYMODELS')
72
+ let MYMODEL = MYMODELS['zuser']
73
+ let json = Util.jsonSuccess(LANGUAGE['data_saved'])
74
+ let userId = req.session.user.id
75
+ let dataPost = zRoute.post(req, res, MYMODEL, 'zuser', req.body)
76
+ let data = dataPost['zuser']
77
+ if (req.body.company) {
78
+ await connection.update({
79
+ table: 'zcompany',
80
+ data: { name: req.body.company },
81
+ where: {
82
+ id: res.locals.companyId,
83
+ },
84
+ })
85
+ }
86
+ await connection.update({
87
+ table: 'zuser',
88
+ data: data,
89
+ where: {
90
+ id: userId,
91
+ },
92
+ })
93
+ for (var keys in data) {
94
+ req.session.user[keys] = data[keys]
95
+ }
96
+ req.session.sessionFlash = json
97
+ if (data.image) {
98
+ json.image = Util.imageProfile(data.image)
99
+ }
100
+ res.json(json)
101
+ })
102
+
103
+ router.post('/profile-sign', access, async (req, res) => {
104
+ const MYMODELS = myCache.get('MYMODELS')
105
+ let MYMODEL = MYMODELS['zuser']
106
+ let json = Util.jsonSuccess(LANGUAGE['data_saved'])
107
+ let userId = res.locals.userId
108
+ let image = req.body.image
109
+ let ext = req.body.ext
110
+ let base64Image = image.split(';base64,').pop()
111
+ let filename = `${Util.generateUnique(10)}${res.locals.userId}.${ext}`
112
+ await connection.update({
113
+ table: 'zuser',
114
+ where: {
115
+ id: res.locals.userId,
116
+ },
117
+ data: {
118
+ verify_signed: filename,
119
+ },
120
+ })
121
+ fs.writeFile(dirRoot + '/public/uploads/zuser/' + filename, base64Image, { encoding: 'base64' }, function (err) {})
122
+ res.json(json)
123
+ })
124
+
125
+ router.get('/znotification/:token', async (req, res) => {
126
+ const MYMODELS = myCache.get('MYMODELS')
127
+ let MYMODEL = MYMODELS['zuser']
128
+ let token = req.params.token
129
+ let url = '/dashboard'
130
+ let results = await connection.results({ table: 'znotification', where: { token: token } })
131
+ if (results.length) {
132
+ let data = {
133
+ status: 2,
134
+ }
135
+ await connection.update({ table: 'znotification', data: data, where: { token: token } })
136
+ if (results[0].link) {
137
+ return res.redirect(results[0].link)
138
+ }
139
+ }
140
+ return res.redirect(url)
141
+ })
142
+
143
+ router.post('/notification-data', csrfProtection, async (req, res) => {
144
+ let id = req.query.id
145
+ let rows = await connection.results({
146
+ table: 'znotification',
147
+ where: {
148
+ user_id: res.locals.userId,
149
+ //status: 1
150
+ },
151
+ limit: 10,
152
+ orderBy: ['id', 'desc'],
153
+ })
154
+
155
+ let rowsCount = await connection.result({
156
+ select: ' count(id) as count ',
157
+ table: 'znotification',
158
+ where: {
159
+ user_id: res.locals.userId,
160
+ },
161
+ })
162
+ let arr = []
163
+ rows.forEach(function (item) {
164
+ item.ago = moment(item.updated_at).fromNow()
165
+ item.avatar = res.locals.userAvatar
166
+ arr.push(item)
167
+ })
168
+
169
+ let data = {
170
+ count: rowsCount.count,
171
+ data: arr,
172
+ }
173
+
174
+ res.json(data)
175
+ })
176
+
177
+ //check status user login in session
178
+ router.put('/zuser-session', csrfProtection, async (req, res) => {
179
+ let json = Util.flashError('err')
180
+ if (USER_ID > 0) {
181
+ json = Util.jsonSuccess('Success')
182
+ }
183
+ res.json(json)
184
+ })
185
+
186
+ router.get('/login', csrfProtection, async (req, res) => {
187
+ if (res.locals.isLogin) {
188
+ return res.redirect(process.env.APP_AFTER_LOGIN)
189
+ } else {
190
+ await zFunction('form_login', req, res)
191
+ }
192
+ const isError = req.query.err == 1 ? true : false
193
+ if (isError) {
194
+ res.locals.error = null
195
+ }
196
+ res.locals.menuApp = 'login'
197
+ res.render('layouts/blank', {
198
+ isError: isError,
199
+ csrfToken: req.csrfToken(),
200
+ renderHead: 'index/logincss.ejs',
201
+ renderBody: 'index/login.ejs',
202
+ })
203
+ })
204
+
205
+ router.post('/login', csrfProtection, async (req, res) => {
206
+ await zRoute.login(req.body.username, req.body.password, req, res)
207
+ })
208
+
209
+ router.post('/login-ajax', csrfProtection, async (req, res) => {
210
+ res.json(await zRoute.loginAjax(req.body.username, req.body.password, req, res))
211
+ })
212
+
213
+ router.get('/signup', csrfProtection, async (req, res) => {
214
+ res.locals.menuApp = 'signup'
215
+ if (res.locals.isLogin) {
216
+ return res.redirect(CONFIG.app.afterLogin)
217
+ } else {
218
+ await zFunction('form_register', req, res)
219
+ }
220
+ res.render('layouts/blank', {
221
+ renderBody: 'index/signup.ejs',
222
+ })
223
+ })
224
+
225
+ router.post('/signup', async (req, res) => {
226
+ let body = req.body
227
+ let menuData = {}
228
+ let userCompany = {}
229
+ let user = {}
230
+ let company = {}
231
+ try {
232
+ let validation = registrationValidation(body)
233
+ if (validation.status == 0) {
234
+ res.json(Util.flashError(validation.message))
235
+ return false
236
+ }
237
+ let dataCompany = {
238
+ code: Util.generateUnique(5),
239
+ name: body.company,
240
+ created_at: Util.now(),
241
+ updated_at: Util.now(),
242
+ created_by: 1,
243
+ updated_by: 1,
244
+ }
245
+ company = await connection.insert({
246
+ table: 'zcompany',
247
+ data: dataCompany,
248
+ })
249
+ let dataCache = zCache.myCache.has(body.username)
250
+ ? zCache.get(body.username)
251
+ : {
252
+ fullname: '',
253
+ email: '',
254
+ image: '',
255
+ }
256
+ let dataUser = {
257
+ company_id: company.id,
258
+ created_at: Util.now(),
259
+ updated_at: Util.now(),
260
+ created_by: 1,
261
+ updated_by: 1,
262
+ role_id: 2,
263
+ token: Util.generateUnique(28),
264
+ username: body.username,
265
+ email: body.username,
266
+ password: Util.hash(body.password),
267
+ fullname: body.fullname,
268
+ image: !dataCache.image ? '' : dataCache.image,
269
+ active: 1,
270
+ language: '1',
271
+ }
272
+ user = await connection.insert({
273
+ table: 'zuser',
274
+ data: dataUser,
275
+ })
276
+
277
+ //insert user company
278
+ userCompany = await connection.insert({
279
+ table: 'zuser_company',
280
+ data: {
281
+ role_id: 2,
282
+ company_id: company.id,
283
+ user_id: user.id,
284
+ },
285
+ })
286
+
287
+ let menu = await connection.result({
288
+ table: 'zmenu',
289
+ where: {
290
+ id: 1,
291
+ },
292
+ })
293
+ //insert menu dari user yang sudah ada menu
294
+ menuData = await connection.insert({
295
+ table: 'zmenu',
296
+ data: {
297
+ company_id: company.id,
298
+ created_at: Util.now(),
299
+ updated_at: Util.now(),
300
+ created_by: 1,
301
+ updated_by: 1,
302
+ name: menu.name,
303
+ json: JSON.stringify(menu.json),
304
+ active: 1,
305
+ },
306
+ })
307
+ await zRoute.loginAjax(dataUser.username, body.password, req, res)
308
+ //refresh cache
309
+ await zCache.renew()
310
+ res.json(Util.jsonSuccess(LANGUAGE.success))
311
+ } catch (e) {
312
+ if (menuData && menuData.id) {
313
+ await connection.delete({
314
+ table: 'zmenu',
315
+ where: {
316
+ id: menuData.id,
317
+ },
318
+ })
319
+ }
320
+ if (userCompany && userCompany.id) {
321
+ await connection.delete({
322
+ table: 'zuser_company',
323
+ where: {
324
+ id: userCompany.id,
325
+ },
326
+ })
327
+ }
328
+ if (user && user.id) {
329
+ await connection.delete({
330
+ table: 'zuser',
331
+ where: {
332
+ id: user.id,
333
+ },
334
+ })
335
+ }
336
+ if (company && company.id) {
337
+ await connection.delete({
338
+ table: 'zcompany',
339
+ where: {
340
+ id: company.id,
341
+ },
342
+ })
343
+ }
344
+ res.json(Util.flashError(e.toString()))
345
+ }
346
+ })
347
+
348
+ const registrationValidation = (body) => {
349
+ let json = {
350
+ message: 'ok',
351
+ status: 0,
352
+ }
353
+ if (!Util.validateEmail(body.username)) {
354
+ json.message = 'Email format is wrong!!'
355
+ }
356
+ if (body.password != body.confirm_password) {
357
+ json.message = 'Password not equal to confirm password'
358
+ }
359
+ if (body.password.length < 6) {
360
+ json.message = 'Password must be at least 6 chars'
361
+ }
362
+ if (body.fullname.length < 3) {
363
+ json.message = 'Fullname must be at least 3 chars'
364
+ }
365
+ if (body.company.length < 3) {
366
+ json.message = 'Company Name must be at least 3 chars'
367
+ }
368
+ json.status = json.message == 'ok' ? 1 : 0
369
+ return json
370
+ }
371
+
372
+ const registrationCUSTOMValidation = (body) => {
373
+ var json = {
374
+ message: 'ok',
375
+ status: 0,
376
+ }
377
+ if (!Util.validateEmail(body.username)) {
378
+ json.message = 'Format email salah'
379
+ }
380
+ if (body.password != body.confirm_password) {
381
+ json.message = 'Password dan repasword tidak cocok'
382
+ }
383
+ if (body.password.length < 6) {
384
+ json.message = 'Password kurang dari 6 '
385
+ }
386
+ if (body.fullname.length < 6) {
387
+ json.message = 'Nama lengkap kurang lengkap'
388
+ }
389
+ if (body.phone.length < 6) {
390
+ json.message = 'No telp kurang lengkap'
391
+ }
392
+ json.status = json.message == 'ok' ? 1 : 0
393
+ return json
394
+ }
395
+
396
+ router.post('/signup-custom', async (req, res) => {
397
+ var body = req.body
398
+ try {
399
+ var validation = registrationCUSTOMValidation(body)
400
+ if (validation.status == 0) {
401
+ res.json(Util.flashError(validation.message))
402
+ return false
403
+ }
404
+
405
+ var dataUser = {
406
+ company_id: 1,
407
+ created_at: Util.now(),
408
+ updated_at: Util.now(),
409
+ created_by: 1,
410
+ updated_by: 1,
411
+ role_id: 4,
412
+ token: Util.generateUnique(28),
413
+ username: body.username,
414
+ email: body.username,
415
+ password: Util.hash(body.password),
416
+ fullname: body.fullname,
417
+ phone: body.phone,
418
+ verify_signed: 'lizhn63iqA8CVDQeOw8.png',
419
+ active: 0,
420
+ language: '2',
421
+ }
422
+ var user = await connection.insert({
423
+ table: 'zuser',
424
+ data: dataUser,
425
+ })
426
+ var userCompany = await connection.insert({
427
+ table: 'zuser_company',
428
+ data: {
429
+ role_id: 4,
430
+ company_id: 1,
431
+ user_id: user.id,
432
+ },
433
+ })
434
+ /* await zRoute.loginAjax(dataUser.username, body.password, req, res);
435
+ //refresh cache
436
+ await zCache.renew();*/
437
+
438
+ res.json(Util.jsonSuccess('Successfuly'))
439
+ } catch (e) {
440
+ res.json(Util.flashError(e.toString()))
441
+ }
442
+ })
443
+
444
+ router.post('/gridprint', async (req, res) => {
445
+ let html = ''
446
+ let id = req.body.id
447
+ let table = req.body.table
448
+ if (id) {
449
+ let results = await connection.results({
450
+ table: 'zapprovals',
451
+ where: {
452
+ id_data: id,
453
+ table: table,
454
+ },
455
+ })
456
+ if (results.length) {
457
+ let result = results[0]
458
+ if (result.status == 3 || result.status == 4) {
459
+ html += `<button class="btn btn-sm btn-info gridprint" data-token="${result.token}"><span class="fa fa-print"></span></button> `
460
+ }
461
+ }
462
+ }
463
+ res.json(html)
464
+ })
465
+
466
+ router.get('/failed', async function (req, res) {
467
+ let template = 'fronts'
468
+ res.render('layouts/' + template, {
469
+ menu: 'failed',
470
+ renderBody: 'index/failed.ejs',
471
+ Util: Util,
472
+ })
473
+ })
474
+
475
+ router.get('/forgot', csrfProtection, async (req, res) => {
476
+ const MYMODELS = myCache.get('MYMODELS')
477
+ let MYMODEL = MYMODELS['zuser']
478
+ if (res.locals.isLogin) {
479
+ return res.redirect('/dashboard')
480
+ }
481
+ let script = `submitForm('forgot-form',"","",function(data){if (data.status == 1) {
482
+ toastrForm(data);spinner.hide();
483
+ setTimeout(function () {location.href='/';},6000);
484
+ }});`
485
+ await moduleLib.custom(req, res, script)
486
+
487
+ res.render('layouts/fronts', {
488
+ csrfToken: req.csrfToken(),
489
+ attributeData: MYMODEL,
490
+ routeName: 'zuser',
491
+ data: MYMODEL.datas,
492
+ renderBody: 'index/forgot.ejs',
493
+ })
494
+ })
495
+
496
+ router.post('/forgot', csrfProtection, async (req, res) => {
497
+ let json = Util.jsonError('email', 'Email not found in our database')
498
+ let routeName = 'user'
499
+ const MYMODELS = myCache.get('MYMODELS')
500
+ let MYMODEL = MYMODELS['zuser']
501
+ let data = zRoute.post(req, res, MYMODEL)['zuser']
502
+ var port = ecosystem.apps[0].env.PORT
503
+ var url = env == 'production' ? process.env.APP_URL : 'http://localhost:' + port
504
+ let email = data.email || ' '
505
+ email = email.trim()
506
+ if (email.length > 5) {
507
+ let rows = await connection.results({
508
+ table: 'zuser',
509
+ where: {
510
+ email: email,
511
+ },
512
+ })
513
+ if (rows.length > 0) {
514
+ let post = {
515
+ forgot_password: Util.generateUnique(23),
516
+ }
517
+ await connection.update({
518
+ table: 'zuser',
519
+ where: {
520
+ id: rows[0].id,
521
+ },
522
+ data: post,
523
+ })
524
+ let options = {
525
+ to: email,
526
+ subject: 'Forgot Password',
527
+ }
528
+ let datas = {
529
+ config: {
530
+ app: {
531
+ url: url,
532
+ },
533
+ },
534
+ url: url,
535
+ link: url + '/reset-password/' + post.forgot_password,
536
+ }
537
+ Mail.forgotPassword(datas, options)
538
+ json = Util.jsonSuccess('Please check your email to reset ')
539
+ }
540
+ }
541
+
542
+ res.json(json)
543
+ })
544
+
545
+ router.get('/reset-password/:forgot_password', csrfProtection, async (req, res) => {
546
+ let forgot_password = req.params.forgot_password || ''
547
+ let activated = false
548
+ if (forgot_password != '') {
549
+ let results = await connection.results({
550
+ table: 'zuser',
551
+ where: {
552
+ forgot_password: forgot_password,
553
+ },
554
+ })
555
+ if (results.length > 0) {
556
+ activated = true
557
+ }
558
+ }
559
+ var script = `submitForm('form-group','','',function(data){
560
+ if(data.status==1){
561
+ location.href = '/login'
562
+ }
563
+ });`
564
+ await moduleLib.custom(req, res, script)
565
+ res.render('layouts/fronts', {
566
+ activated: activated,
567
+ csrfToken: req.csrfToken(),
568
+ forgot_password: forgot_password,
569
+ renderBody: 'index/reset-password.ejs',
570
+ })
571
+ })
572
+
573
+ router.get('/no-access', async (req, res) => {
574
+ let myview = 'fronts'
575
+ if (req.session.user) {
576
+ myview = 'main'
577
+ }
578
+ res.render('layouts/' + myview, {
579
+ data: { table: 'error' },
580
+ menu: 'error',
581
+ renderBody: 'index/no-access.ejs',
582
+ })
583
+ })
584
+
585
+ router.get('/page_not_found', async (req, res) => {
586
+ res.render('layouts/page_not_found', {
587
+ data: { table: 'error' },
588
+ menu: 'error',
589
+ //renderBody: "index/no-found.ejs",
590
+ })
591
+ })
592
+
593
+ // for change company session
594
+ router.get('/session/:id', access, async (req, res) => {
595
+ let companies = res.locals.zcompanies
596
+ let user = await connection.result({
597
+ table: 'zuser',
598
+ where: {
599
+ id: res.locals.userId,
600
+ },
601
+ })
602
+ for (let i = 0; i < companies.length; i++) {
603
+ if (companies[i].id == req.params.id) {
604
+ user.company_id = req.params.id
605
+ await zRoute.handleSession(req, user)
606
+ var post = {
607
+ company_id: companies[i].id,
608
+ role_id: companies[i].role_id,
609
+ }
610
+ await connection.update({
611
+ table: 'zuser',
612
+ data: post,
613
+ where: {
614
+ id: res.locals.userId,
615
+ },
616
+ })
617
+ }
618
+ }
619
+ var backURL = req.header('Referer') || '/'
620
+ // do your thang
621
+ res.redirect(backURL)
622
+ })
623
+
624
+ //RESTART
625
+ router.get('/restart', access, async (req, res) => {
626
+ var room = res.locals.user.token
627
+ if (env == 'production') {
628
+ pm2.connect(function (err) {
629
+ if (err) {
630
+ io.to(room).emit('error', err.toString())
631
+ }
632
+ pm2.restart(process.env.PM2_NAME, (err, proc) => {
633
+ io.to(room).emit('message', 'Restart done')
634
+ })
635
+ })
636
+ } else {
637
+ io.to(room).emit('message', 'Restart done')
638
+ }
639
+ res.json('ok')
640
+ })
641
+
642
+ //ERROR UI
643
+ router.get('/error', async (err, req, res, next) => {
644
+ res.locals.message = err.message
645
+ res.locals.error = req.app.get('env') === 'development' ? err : err
646
+ // render the error page
647
+ res.status(err.status || 500)
648
+ debug(req, res, err)
649
+ res.render('layouts/' + layout, {
650
+ renderBody: 'index/error.ejs',
651
+ })
652
+ })
653
+
654
+ //APPROVAL SYSTEMS
655
+ router.post('/zzapproval', async (req, res) => {
656
+ let json = Util.jsonSuccess(LANGUAGE['data_saved'])
657
+ const MYMODELS = myCache.get('MYMODELS')
658
+ let MYMODEL = MYMODELS['zapprovals']
659
+ const port = ecosystem.apps[0].env.PORT
660
+ let users = Util.arrayToObject(await connection.results({ table: 'zuser' }), 'id')
661
+ try {
662
+ let userId = res.locals.userId
663
+ let data = zRoute.post(req, res, MYMODEL)[MYMODEL.table]
664
+ let validator = zRoute.validator(data, MYMODEL)
665
+ if (validator.status == 0) return res.json(validator.message)
666
+ if (data.status == 2) {
667
+ if (!data.approvers) {
668
+ return res.json(Util.flashError('Approvers empty'))
669
+ }
670
+ if (data.title == '') {
671
+ return res.json(Util.flashError('Title empty', 'title'))
672
+ }
673
+ }
674
+ //update template for newst
675
+ var row = await connection.result({ table: 'zfields', where: { table: data.table } })
676
+ var jsonApproval = row.approval_json || {}
677
+ data.template = jsonApproval.content || {}
678
+ var approvers = []
679
+ if (typeof data.approvers == 'string') {
680
+ data.approvers = JSON.parse(data.approvers)
681
+ }
682
+ approvers = data.approvers || []
683
+ if (approvers.length > 1) {
684
+ approvers = approvers.filter(Util.arrayUnique)
685
+ }
686
+ data.approvers = JSON.stringify(approvers)
687
+ let knowings = []
688
+ if (typeof data.knowings == 'string') {
689
+ data.knowings = JSON.parse(data.knowings)
690
+ }
691
+ knowings = data.knowings || []
692
+ if (knowings.length > 1) {
693
+ knowings = knowings.filter(Util.arrayUnique)
694
+ }
695
+ data.knowings = JSON.stringify(knowings)
696
+ let allUsers = [...approvers, ...knowings]
697
+
698
+ let statusApprovers = approvers.reduce((result, item) => {
699
+ return [...result, { user: item, status: 2 }]
700
+ }, [])
701
+ data.approved_stats = JSON.stringify({
702
+ stats: `0/${approvers.length}`,
703
+ status: statusApprovers,
704
+ })
705
+ let knowingStatus = knowings.reduce((result, item) => {
706
+ return [...result, { user: item, status: 7 }]
707
+ }, [])
708
+
709
+ data.knowing_stats = JSON.stringify({
710
+ stats: `0/${knowings.length}`,
711
+ status: knowingStatus,
712
+ })
713
+ let results = await connection.results({
714
+ table: MYMODEL.table,
715
+ where: { table: data.table, id_data: data.id_data },
716
+ })
717
+ if (results.length) {
718
+ let query = await zRoute.updateSQL(req, res, MYMODEL.table, data, { id: results[0].id })
719
+ data.id = results[0].id
720
+ } else {
721
+ var query = await zRoute.insertSQL(req, res, MYMODEL.table, data)
722
+ data.id = query.id
723
+ }
724
+ if (data.status == 2) {
725
+ //send activity
726
+ /* await zRoute.insertSQL(req, res, "zactivity", {
727
+ user_id: res.locals.userId,
728
+ table: MYMODEL.table,
729
+ id_data: data.id,
730
+ status: data.status,
731
+ status_label: MYMODEL.widgets.status.fields[data.status],
732
+ title: MYMODEL.widgets.status.fields[data.status],
733
+ description: users[res.locals.userId].fname + " " +users[res.locals.userId].lname ,
734
+ data: JSON.stringify(data)
735
+ });*/
736
+ //if serial
737
+ if (data.type == 2) {
738
+ approvers = [approvers[0]]
739
+ }
740
+ let sectionsAprrovers = approvers.reduce((temp, item, index) => {
741
+ return [
742
+ ...temp,
743
+ {
744
+ title: users[item].fullname,
745
+ description: '@' + users[item].fullname,
746
+ rowId: 'row' + index,
747
+ },
748
+ ]
749
+ }, [])
750
+ let sectionsKnowings = knowings.reduce((temp, item, index) => {
751
+ return [
752
+ ...temp,
753
+ {
754
+ title: users[item].fullname,
755
+ description: '@' + users[item].fullname,
756
+ rowId: 'row' + index,
757
+ },
758
+ ]
759
+ }, [])
760
+ let sections = []
761
+ sections.push({ title: 'Approvers', rows: sectionsAprrovers })
762
+ if (sectionsKnowings) {
763
+ sections.push({ title: 'Knowings', rows: sectionsKnowings })
764
+ }
765
+ approvers.forEach(async (item, num) => {
766
+ let post = {
767
+ title_id: data.id,
768
+ user_id: item,
769
+ status: 7,
770
+ type: 1,
771
+ token: Util.uuid(),
772
+ }
773
+ await zRoute.insertSQL(req, res, 'zapprovals_details', post)
774
+ let link = env == 'production' ? process.env.APP_URL + '/za/' + post.token : `http://localhost:${port}/za/${post.token}`
775
+ let email = users[post.user_id].email
776
+
777
+ post.subject = `Need Approve ${data.title}`
778
+ post.buttonTitle = `Approve Now`
779
+ post.title = `NEED APPROVE DOCUMENT`
780
+ post.link = link
781
+ post.url = CONFIG.app.url
782
+ post.description = `Hai ${users[post.user_id].fullname} <br>
783
+
784
+
785
+ We have some document for you.<br>
786
+ Please click the link above to view the document.`
787
+
788
+ post.note = `If you click the link, it's will be automatically acknowledged`
789
+ Mail.gmail(req, res, post, email)
790
+
791
+ //send to whatsapp
792
+ let phone = Util.phoneWA(users[post.user_id].phone)
793
+ if (phone) {
794
+ var textWa = ''
795
+ textWa += `*NEED APPROVE DOCUMENT* \r\n_${data.title}_\r\nHai ${users[post.user_id].fullname} \r\n \r\n`
796
+ textWa += 'We have some document for you.\r\n'
797
+ textWa += `Please click the link above to view the document.\r\n${link}`
798
+
799
+ /* await whatsapp({
800
+ to: phone,
801
+ text: textWa,
802
+ sections: JSON.stringify(sections),
803
+ buttonText: "Click me for details"
804
+ });*/
805
+ }
806
+
807
+ //send notification
808
+ /* await zRoute.insertSQL(req, res, "znotification", {
809
+ user_id: item,
810
+ table: MYMODEL.table,
811
+ id_data: data.id,
812
+ status: 1,
813
+ link: "/za/" + post.token,
814
+ status_label: MYMODEL.widgets.status.fields[1],
815
+ title: `Need Approve`,
816
+ description: data.title,
817
+ token: post.token
818
+ });*/
819
+
820
+ //send todolist
821
+ /* await zRoute.insertSQL(req, res, "ztodolist", {
822
+ user_id: item,
823
+ table: MYMODEL.table,
824
+ id_data: data.id,
825
+ status: 1,
826
+ link: "/za/" + post.token,
827
+ status_label: MYMODEL.widgets.status.fields[1],
828
+ title: `Need Approve`,
829
+ description: data.title,
830
+ users: JSON.stringify(allUsers)
831
+ });*/
832
+
833
+ //send toastr using socket.io
834
+ io.to(users[item].token).emit('message', 'Need Approve ' + data.title)
835
+ })
836
+
837
+ knowings.map(async (item) => {
838
+ let post = {
839
+ title_id: data.id,
840
+ user_id: item,
841
+ status: 7,
842
+ type: 2,
843
+ token: Util.uuid(),
844
+ }
845
+ await zRoute.insertSQL(req, res, 'zapprovals_details', post)
846
+ let link = env == 'production' ? process.env.APP_URL + '/za/' + post.token : `http://localhost:${port}/za/${post.token}`
847
+ let email = users[post.user_id].email
848
+
849
+ post.subject = `Need acknowledge ${data.title}`
850
+ post.buttonTitle = `Acknowledge Now`
851
+ post.title = `NEED ACKNOWLEDGE DOCUMENT`
852
+
853
+ post.link = link
854
+ post.url = CONFIG.app.url
855
+ post.description = `Hai ${users[post.user_id].fullname} <br>
856
+
857
+
858
+ We have some document for you.<br>
859
+ Please click the link above to view the document.`
860
+
861
+ post.note = `If you click the link, it's will be automatically acknowledged`
862
+ Mail.gmail(req, res, post, email)
863
+
864
+ //send to whatsapp
865
+ let phone = Util.phoneWA(users[post.user_id].phone)
866
+ if (phone) {
867
+ var textWa = ''
868
+ textWa += `*NEED ACKNOWLEDGE DOCUMENT* \r\n_${data.title}_\r\nHai ${users[post.user_id].fullname} \r\n \r\n`
869
+ textWa += 'We have some document for you.\r\n'
870
+ textWa += `Please click the link above to view the document.\r\n${link}`
871
+ /* await whatsapp({
872
+ to: phone,
873
+ text: textWa,
874
+ sections: JSON.stringify(sections),
875
+ buttonText: "Click me for details"
876
+ });*/
877
+ }
878
+
879
+ //send activity
880
+ /* await cRoute.insertSQL(req, res, "zactivity",{
881
+ user_id:item,
882
+ table:MYMODEL.table,
883
+ id_data:data.id,
884
+ status:7,
885
+ status_label: MYMODEL.widgets.status.fields[7],
886
+ title : MYMODEL.widgets.status.fields[7],
887
+ description: data.title,
888
+ data:JSON.stringify(data)
889
+ });*/
890
+
891
+ //send notification
892
+ /* await zRoute.insertSQL(req, res, "znotification", {
893
+ user_id: item,
894
+ table: MYMODEL.table,
895
+ id_data: data.id,
896
+ status: 1,
897
+ link: "/za/" + post.token,
898
+ status_label: MYMODEL.widgets.status.fields[1],
899
+ title: `Need Acknowledge`,
900
+ description: data.title,
901
+ token: post.token
902
+ });
903
+
904
+ //send todolist
905
+ await zRoute.insertSQL(req, res, "ztodolist", {
906
+ user_id: item,
907
+ table: MYMODEL.table,
908
+ id_data: data.id,
909
+ status: 1,
910
+ link: "/za/" + post.token,
911
+ status_label: MYMODEL.widgets.status.fields[1],
912
+ title: `Need Acknowledge`,
913
+ description: data.title,
914
+ users: JSON.stringify(allUsers)
915
+ });*/
916
+ io.to(users[item].token).emit('message', 'Need Acknowledge ' + data.title)
917
+ })
918
+ }
919
+ } catch (err) {
920
+ if (Object.prototype.hasOwnProperty.call(err, 'sqlMessage')) {
921
+ json = Util.flashError(err.sqlMessage)
922
+ } else {
923
+ json = Util.flashError(err.toString())
924
+ }
925
+ debug(req, res, err)
926
+ }
927
+ res.json(json)
928
+ })
929
+
930
+ router.get('/za/:token', csrfProtection, async (req, res) => {
931
+ let token = req.params.token
932
+ let data = {},
933
+ data2 = {}
934
+ let template = ''
935
+ let result
936
+ let isClosed = false
937
+ let footers = ''
938
+ let details = []
939
+ let routeName = env == 'production' ? process.env.APP_URL : `http://localhost:${port}`
940
+ let statusLabel = ''
941
+ let knowings = []
942
+ const MYMODELS = myCache.get('MYMODELS')
943
+ let MYMODEL = MYMODELS['zapprovals']
944
+ let users = Util.arrayToObject(await connection.results({ table: 'zuser' }), 'id')
945
+ try {
946
+ result = await connection.result({
947
+ select: '*, zapprovals.id as ide, zapprovals_details.token as usertoken, zapprovals.status as statuse, zapprovals_details.status as mystatus, zapprovals_details.type as user_type, zapprovals_details.updated_at',
948
+ table: 'zapprovals_details',
949
+ joins: ['LEFT JOIN zapprovals ON (zapprovals_details.title_id = zapprovals.id)', 'LEFT JOIN employee ON (zapprovals_details.user_id = employee.id)'],
950
+ where: { 'zapprovals_details.token': token },
951
+ })
952
+ let approvers = result.approvers
953
+ knowings = result.knowings ? result.knowings : []
954
+
955
+ statusLabel = MYMODEL.widgets.status.fields[result.statuse]
956
+ routeName = routeName + '/' + result.table + '/view/' + result.id_data
957
+ if (result.statuse == 3 || result.statuse == 4 || result.mystatus == 3 || result.mystatus == 4) {
958
+ isClosed = true
959
+ }
960
+ details = await connection.results({ table: 'zapprovals_details', where: { title_id: result.ide } })
961
+ if (result.user_type == 2) {
962
+ isClosed = true
963
+ var post = {
964
+ status: 6, //read
965
+ }
966
+ await connection.update({ table: 'zapprovals_details', data: post, where: { token: token } })
967
+
968
+ //set stats
969
+ //{"stats":"0/1","status":[{"user":"12","status":0}]}
970
+ let knowing_stats = result.knowing_stats || {}
971
+ let statuses = knowing_stats.status
972
+ let stats = knowing_stats.stats
973
+ let explode = stats.split('/')
974
+ let count = parseInt(explode[0])
975
+ let newStatus = []
976
+ knowings = result.knowings || []
977
+ statuses.map((item) => {
978
+ if (item.user == result.user_id && result.mystatus != 3) {
979
+ item.status = 3
980
+ if (count < knowings.length) {
981
+ count = count + 1
982
+ }
983
+ newStatus.push(item)
984
+ } else {
985
+ newStatus.push(item)
986
+ }
987
+ })
988
+ if (result.mystatus != 3) {
989
+ post = {
990
+ knowing_stats: JSON.stringify({ stats: count + '/' + explode[1], status: newStatus }),
991
+ }
992
+ await connection.update({ table: 'zapprovals', data: post, where: { id: result.ide } })
993
+ //var users = await zRoute.getUsers();
994
+ var message = users[result.user_id].fullname + ' has readed document ' + result.title
995
+ details.forEach(function (item) {
996
+ io.to(users[item.user_id].token).emit('message', message)
997
+ })
998
+ }
999
+ }
1000
+
1001
+ MYMODEL = MYMODELS[result.table]
1002
+ let row = await connection.result({ table: MYMODEL.table, where: { id: result.id_data } })
1003
+ data = await zRoute.viewTable(req, res, MYMODEL, row)
1004
+ template = result.template
1005
+ for (var key in data) {
1006
+ template = Util.replaceAll(template, '{{' + key + '}}', data[key])
1007
+ }
1008
+
1009
+ footers = await zRoute.approversFooter(details)
1010
+
1011
+ //send activity
1012
+ if (result.mystatus == 7) {
1013
+ MYMODEL = MYMODELS['zapprovals']
1014
+ /* await connection.insert({
1015
+ table: "zactivity",
1016
+ data: {
1017
+ company_id: result.company_id,
1018
+ created_at: Util.now(),
1019
+ created_by: result.user_id,
1020
+ updated_by: result.user_id,
1021
+ user_id: result.user_id,
1022
+ table: MYMODEL.table,
1023
+ id_data: result.ide,
1024
+ status: 6,
1025
+ status_label: MYMODEL.widgets.status.fields[6],
1026
+ title: `${MYMODEL.widgets.status.fields[6]}`,
1027
+ description: `Ok `,
1028
+ data: JSON.stringify(data)
1029
+ }
1030
+ });
1031
+ */
1032
+
1033
+ await connection.update({
1034
+ table: 'zapprovals_details',
1035
+ where: {
1036
+ token: token,
1037
+ },
1038
+ data: { status: 6 },
1039
+ })
1040
+ }
1041
+ } catch (err) {
1042
+ debug(req, res, err)
1043
+ res.send('Not Found')
1044
+ }
1045
+ res.render('layouts/blank', {
1046
+ routeName: routeName,
1047
+ Util: Util,
1048
+ data: data,
1049
+ statusLabel: statusLabel,
1050
+ template: template,
1051
+ result: result,
1052
+ statusLabel: statusLabel,
1053
+ isClosed: isClosed,
1054
+ footers: footers,
1055
+ csrfToken: req.csrfToken(),
1056
+ token: result.usertoken,
1057
+ tokendoc: token,
1058
+ renderHead: 'index/zacss.ejs',
1059
+ renderBody: 'index/za.ejs',
1060
+ renderEnd: 'index/zajs.ejs',
1061
+ })
1062
+ })
1063
+
1064
+ router.post('/za/:token', csrfProtection, async (req, res) => {
1065
+ let token = req.params.token
1066
+ let comments = req.body.comments
1067
+ let status = req.body.status
1068
+ let json = Util.jsonSuccess('Success')
1069
+ let data = {},
1070
+ data2 = {}
1071
+ let template = ''
1072
+ let approvers = [],
1073
+ knowings = []
1074
+ let users = Util.arrayToObject(await connection.results({ table: 'zuser' }), 'id')
1075
+ let employee_user = users
1076
+ const MYMODELS = myCache.get('MYMODELS')
1077
+ let MYMODEL = MYMODELS['zapprovals']
1078
+ let post = {}
1079
+ try {
1080
+ var results = await connection.results({
1081
+ select: '*,zapprovals_details.status as approvers_status, zapprovals.created_by as submiter, zapprovals.type as typee, zapprovals.status as statuse, zapprovals_details.id as detaild_id, zapprovals.id as ide, zapprovals.approvers as approvers ',
1082
+ table: 'zapprovals_details',
1083
+ joins: ['LEFT JOIN zapprovals ON (zapprovals_details.title_id = zapprovals.id)'],
1084
+ where: { 'zapprovals_details.token': token },
1085
+ })
1086
+ if (!results.length) {
1087
+ return res.json(Util.jsonError('Data not found!'))
1088
+ }
1089
+
1090
+ var result = results[0]
1091
+ if (result.approvers_status == 3 || result.approvers_status == 4) {
1092
+ return res.json(Util.jsonError('You have submited.'))
1093
+ }
1094
+ post = {
1095
+ status: status,
1096
+ comments: comments,
1097
+ updated_at: Util.now(),
1098
+ }
1099
+ let update = await connection.update({ table: 'zapprovals_details', data: post, where: { id: result.detaild_id } })
1100
+ let details = await connection.results({ table: 'zapprovals_details', where: { title_id: result.ide } })
1101
+ approvers = result.approvers
1102
+ knowings = result.knowings || []
1103
+ let stats = 0
1104
+ let status_stats = []
1105
+ let approversSigned = []
1106
+ //{"stats":"0/2","status":[{"user":"12","status":2},{"user":"35","status":2}]}
1107
+ let last_status
1108
+ details.map((item) => {
1109
+ if (item.type == 1) {
1110
+ if (item.status == 4 || item.status == 3) {
1111
+ stats++
1112
+ approversSigned.push(item.user_id + '')
1113
+ }
1114
+ status_stats.push({
1115
+ user: item.user_id,
1116
+ status: item.status,
1117
+ })
1118
+ last_status = item.status
1119
+ }
1120
+ })
1121
+
1122
+ post.approved_stats = JSON.stringify({
1123
+ stats: stats + '/' + approvers.length,
1124
+ status: status_stats,
1125
+ })
1126
+ if (stats == approvers.length) {
1127
+ post.status = last_status
1128
+ } else {
1129
+ post.status = 5
1130
+ }
1131
+ if (status == 4) {
1132
+ post.status = 4
1133
+ }
1134
+ await connection.update({ table: 'zapprovals', data: post, where: { id: result.ide } })
1135
+
1136
+ //send activity
1137
+ await connection.insert({
1138
+ table: 'zactivity',
1139
+ data: {
1140
+ company_id: result.company_id,
1141
+ created_at: Util.now(),
1142
+ created_by: result.user_id,
1143
+ updated_by: result.user_id,
1144
+ user_id: result.user_id,
1145
+ table: MYMODEL.table,
1146
+ id_data: result.ide,
1147
+ status: status,
1148
+ status_label: MYMODEL.widgets.status.fields[status],
1149
+ title: MYMODEL.widgets.status.fields[status],
1150
+ description: comments,
1151
+ data: JSON.stringify(post),
1152
+ },
1153
+ })
1154
+
1155
+ //send notification
1156
+ if (status == 3 || status == 4) {
1157
+ let message = `Document ${result.title} has ${MYMODEL.widgets.status[status]};`
1158
+ approvers.forEach(function (item) {
1159
+ io.to(users[item].token).emit('message', message)
1160
+ })
1161
+ if (status == 3) {
1162
+ // if type is serial is step by step
1163
+ //send notification and generate email
1164
+ //approversSigned
1165
+ if (result.typee == 2) {
1166
+ //get approvers has already sign
1167
+
1168
+ approversSigned.push(result.user_id)
1169
+ var newApprovers = approvers.filter((item) => {
1170
+ return !approversSigned.includes(item)
1171
+ })
1172
+ var item = newApprovers.length ? newApprovers[0] : ''
1173
+ if (item) {
1174
+ post = {
1175
+ title_id: result.ide,
1176
+ user_id: employee_user[item].user_id,
1177
+ status: 7,
1178
+ type: 1,
1179
+ comments: comments,
1180
+ token: Util.uuid(),
1181
+ company_id: result.company_id,
1182
+ created_at: Util.now(),
1183
+ updated_at: Util.now(),
1184
+ created_by: employee_user[item].user_id,
1185
+ updated_by: employee_user[item].user_id,
1186
+ }
1187
+ await connection.insert({
1188
+ table: 'zapprovals_details',
1189
+ data: post,
1190
+ })
1191
+ let link = CONFIG.app.url + '/za/' + post.token
1192
+ let email = users[item].username
1193
+
1194
+ post.subject = `Need Approve ${result.title}`
1195
+ post.buttonTitle = `Approve Now`
1196
+ post.title = `NEED APPROVE DOCUMENT`
1197
+ post.link = link
1198
+ post.url = CONFIG.app.url
1199
+ post.description = `Hai ${users[item].fullname} <br>
1200
+
1201
+
1202
+ We have some document for you.<br>
1203
+ Please click the link above to view the document.`
1204
+
1205
+ post.note = `If you click the link, it's will be automatically acknowledged`
1206
+ Mail.gmail(req, res, post, email)
1207
+
1208
+ //send to whatsapp
1209
+ let sectionsAprrovers = approvers.reduce((temp, item, index) => {
1210
+ return [
1211
+ ...temp,
1212
+ {
1213
+ title: users[item].fullname + ' ' + users[item].position,
1214
+ description: '@' + users[item].fullname + ' ' + users[item].position,
1215
+ rowId: 'roe' + index,
1216
+ },
1217
+ ]
1218
+ }, [])
1219
+ let sectionsKnowings = knowings.reduce((temp, item, index) => {
1220
+ return [
1221
+ ...temp,
1222
+ {
1223
+ title: users[item].fullname + ' ' + users[item].position,
1224
+ description: '@' + users[item].fullname + ' ' + users[item].position,
1225
+ rowId: 'roe' + index,
1226
+ },
1227
+ ]
1228
+ }, [])
1229
+ let sections = []
1230
+ sections.push({ title: 'Approvers', rows: sectionsAprrovers })
1231
+ if (sectionsKnowings) {
1232
+ sections.push({ title: 'Knowings', rows: sectionsKnowings })
1233
+ }
1234
+ //send notification
1235
+ await connection.insert({
1236
+ table: 'znotification',
1237
+ data: {
1238
+ company_id: result.company_id,
1239
+ created_at: Util.now(),
1240
+ created_by: employee_user[result.user_id].user_id,
1241
+ updated_by: employee_user[result.user_id].user_id,
1242
+ user_id: item,
1243
+ table: MYMODEL.table,
1244
+ id_data: data.id,
1245
+ status: 1,
1246
+ link: '/za/' + post.token,
1247
+ status_label: 'Unread',
1248
+ title: `Need Approve`,
1249
+ description: data.title,
1250
+ token: post.token,
1251
+ },
1252
+ })
1253
+
1254
+ //send todolist
1255
+ await connection.insert({
1256
+ table: 'ztodolist',
1257
+ data: {
1258
+ company_id: result.company_id,
1259
+ created_at: Util.now(),
1260
+ created_by: employee_user[result.user_id].user_id,
1261
+ updated_by: employee_user[result.user_id].user_id,
1262
+ user_id: item,
1263
+ table: MYMODEL.table,
1264
+ id_data: result.ide,
1265
+ status: 1,
1266
+ link: '/za/' + post.token,
1267
+ status_label: 'Unread',
1268
+ title: `Need Approve`,
1269
+ description: result.title,
1270
+ users: JSON.stringify(approvers),
1271
+ },
1272
+ })
1273
+
1274
+ //send toastr using socket.io
1275
+ io.to(users[item].token).emit('message', 'Need Approve for document : ' + result.title)
1276
+ }
1277
+ }
1278
+ }
1279
+ }
1280
+ } catch (err) {
1281
+ debug(req, res, err)
1282
+ json = Util.flashError(err.toString())
1283
+ }
1284
+
1285
+ res.json(json)
1286
+ })
1287
+
1288
+ router.get('/zdownload/zgenerator/:table', async (req, res) => {
1289
+ var table = req.params.table
1290
+ var path = `${dirRoot}/public/uploads/zgenerator/${table}.json`
1291
+ res.download(path, function (err) {
1292
+ if (err) {
1293
+ //console.log(err);
1294
+ }
1295
+ })
1296
+ })
1297
+
1298
+ module.exports = router
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zet-lib",
3
- "version": "1.2.31",
3
+ "version": "1.2.32",
4
4
  "description": "zet is a library that part of zet generator.",
5
5
  "engines": {
6
6
  "node": ">=18"