beech-api 3.8.0 → 3.9.75

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.
Files changed (59) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +1715 -1244
  3. package/index.js +2 -2
  4. package/package.json +92 -83
  5. package/packages/cli/beech +9 -10
  6. package/packages/cli/bin/beech-app.js +389 -389
  7. package/packages/cli/bin/beech-service.js +262 -132
  8. package/packages/cli/core/auth/Credentials.js +174 -147
  9. package/packages/cli/core/auth/Passport.js +664 -592
  10. package/packages/cli/core/auth/_Request.js +12 -12
  11. package/packages/cli/core/configure/_gitignore +16 -15
  12. package/packages/cli/core/configure/_sequelizerc +9 -9
  13. package/packages/cli/core/configure/app.config-basic.js +55 -55
  14. package/packages/cli/core/configure/app.config-sequelize.js +88 -88
  15. package/packages/cli/core/configure/beech.config.js +9 -9
  16. package/packages/cli/core/configure/global.config-basic.js +8 -8
  17. package/packages/cli/core/configure/global.config-sequelize.js +8 -8
  18. package/packages/cli/core/configure/jest.config.js +6 -6
  19. package/packages/cli/core/configure/jsconfig.json +8 -7
  20. package/packages/cli/core/configure/passport.config.js +97 -97
  21. package/packages/cli/core/databases/mysql.js +94 -95
  22. package/packages/cli/core/databases/sequelize.js +187 -179
  23. package/packages/cli/core/databases/test.js +251 -170
  24. package/packages/cli/core/file-walk/file-walk.js +35 -35
  25. package/packages/cli/core/generator/_endpoints +15 -15
  26. package/packages/cli/core/generator/_endpoints_basic +42 -42
  27. package/packages/cli/core/generator/_help +26 -18
  28. package/packages/cli/core/generator/_help_create +10 -10
  29. package/packages/cli/core/generator/_help_service +10 -10
  30. package/packages/cli/core/generator/_helpers +9 -9
  31. package/packages/cli/core/generator/_helpers_basic +22 -22
  32. package/packages/cli/core/generator/_models +6 -29
  33. package/packages/cli/core/generator/_models_basic +13 -22
  34. package/packages/cli/core/generator/_package +23 -20
  35. package/packages/cli/core/generator/_scheduler +32 -22
  36. package/packages/cli/core/generator/_spec +29 -29
  37. package/packages/cli/core/generator/index.js +1081 -738
  38. package/packages/cli/core/helpers/2fa.js +106 -85
  39. package/packages/cli/core/helpers/math.js +115 -103
  40. package/packages/cli/core/helpers/poolEntity.js +103 -59
  41. package/packages/cli/core/index.js +264 -188
  42. package/packages/cli/core/middleware/express/duplicateRequest.js +16 -12
  43. package/packages/cli/core/middleware/express/jwtCheckAllow.js +86 -68
  44. package/packages/cli/core/middleware/express/rateLimit.js +29 -17
  45. package/packages/cli/core/middleware/express/slowDown.js +2 -2
  46. package/packages/cli/core/middleware/index.js +6 -6
  47. package/packages/cli/core/middleware/origin/guard/advance.js +75 -74
  48. package/packages/cli/core/middleware/origin/whitelist/cors.js +94 -94
  49. package/packages/cli/core/services/http.express.js +481 -441
  50. package/packages/cli/core/test/check-node.js +21 -0
  51. package/packages/cli/core/test/utils.js +7 -7
  52. package/packages/cli/entry +10 -0
  53. package/packages/lib/index.js +6 -6
  54. package/packages/lib/src/endpoint.js +947 -532
  55. package/packages/lib/src/guard.js +60 -60
  56. package/packages/lib/src/salt.js +3 -3
  57. package/packages/lib/src/schema.js +96 -93
  58. package/packages/lib/src/specificExpress.js +7 -7
  59. package/packages/lib/src/user.js +271 -271
@@ -1,532 +1,947 @@
1
- const walk = require("walk");
2
- const fs = require("fs");
3
- const { checkRoleMiddlewareWithDefaultProject } = require("../../cli/core/middleware/express/jwtCheckAllow");
4
-
5
- function walkModel(cb) {
6
- try {
7
- let jsfiles = [];
8
- let walker = walk.walk(appRoot + "/src/models", { followLinks: false });
9
- // Walk file on push
10
- walker.on("file", (root, stat, next) => {
11
- jsfiles.push(root + "/" + stat.name);
12
- next();
13
- });
14
- // Walking
15
- walker.on("end", () => {
16
- let preProject = [];
17
- if(jsfiles.length) {
18
- jsfiles.forEach((file, k) => {
19
- let schemaPath = "@/models" + file.split("models")[1].replace(/\\/g, "/");
20
- let endpoint = file
21
- .split("models")[1]
22
- .replace(/\\/g, "/")
23
- .replace(/_/g, "-")
24
- .toLowerCase()
25
- .slice(0, -3);
26
- preProject.push([schemaPath, endpoint]);
27
- if (jsfiles.length == k + 1) {
28
- cb(null, preProject);
29
- }
30
- });
31
- } else {
32
- // model not found.
33
- cb(null, preProject);
34
- }
35
- });
36
- } catch (error) {
37
- cb(error, null);
38
- }
39
- }
40
-
41
- function filterProject(Projects, reqUrl, req, res, cb) {
42
- try {
43
- let pj = Projects.shift();
44
- let regx = new RegExp(pj[1] + "?[^\/].?[a-zA-Z0-9].*$", 'g');
45
- let regxMatch = reqUrl.match(regx);
46
- let regxMatchLength = (regxMatch) ? regxMatch.length: 0;
47
- if (pj[1] == reqUrl) {
48
- return checkOffset(Object.values(require(pj[0]))[0], req, res, (thenChecked) => {
49
- if(thenChecked) {
50
- return cb(null, Object.values(require(pj[0]))[0]);
51
- }
52
- });
53
- } else if(regxMatchLength) {
54
- return checkOffset(Object.values(require(pj[0]))[0], req, res, (thenChecked) => {
55
- if(thenChecked) {
56
- return cb(null, Object.values(require(pj[0]))[0]);
57
- }
58
- });
59
- }
60
- // Finally recursive filterProject function
61
- if (Projects.length > 0) {
62
- filterProject(Projects, reqUrl, req, res, cb);
63
- } else {
64
- // not match
65
- return notfound(res);
66
- }
67
- } catch (error) {
68
- cb(error, null);
69
- }
70
- }
71
-
72
- function checkOffset(Project, req, res, cb) {
73
- if (!Project) {
74
- return notfound(res);
75
- }
76
- // check offset is Ingeter as well as Zero number
77
- let offset = req.params.offset || undefined;
78
- let limit = req.params.limit || undefined;
79
- let offsetRegxMatch = (offset !== undefined) ? offset.match(/^[0-9]+$/) : undefined;
80
- let limitRegxMatch = (limit !== undefined) ? limit.match(/^[0-9]+$/) : undefined;
81
- if (offsetRegxMatch && limitRegxMatch) {
82
- cb(true);
83
- } else {
84
- if(offset === undefined) {
85
- cb(true);
86
- } else {
87
- return notfound(res);
88
- }
89
- }
90
- }
91
-
92
- function notfound(res) {
93
- return res.status(404).json({
94
- code: 404,
95
- status: "404_NOT_FOUND",
96
- message: "The Endpoint not found!.",
97
- });
98
- }
99
-
100
- function errMessage(err, res) {
101
- let errTurnOffDbDefine = JSON.stringify(err.toString()).match(/'define'/);
102
- let errTurnOffDbOption = JSON.stringify(err.toString()).match(/'options'/);
103
- if(errTurnOffDbDefine || errTurnOffDbOption) {
104
- // @return
105
- return res.status(500).json({
106
- code: 500,
107
- status: "ERR_INTERNAL_SERVER",
108
- message: "Database connection name is CLOSED.",
109
- });
110
- } else {
111
- // @return
112
- return res.status(500).json({
113
- code: 500,
114
- status: "ERR_INTERNAL_SERVER",
115
- message: err.toString(),
116
- });
117
- }
118
- }
119
-
120
- const byPassCheckRole = (Projects, method, passport_config) => {
121
- return async function (req, res, next) {
122
- if(passport_config[0] !== undefined) {
123
- if(req.params.hash == passport_config[0].replace(/^\/|\/$/g, "")) {
124
- return next();
125
- } else {
126
- if(passport_config[1].jwt_allow === true) {
127
- let leaveMeAlone = await Projects.slice(0);
128
- await filterProject(leaveMeAlone, req.originalUrl.replace(_publicPath_, '/'), req, res, async (err, Project) => {
129
- if(!err) {
130
- if(Project.options.defaultEndpoint === undefined || Project.options.defaultEndpoint === true) {
131
- // Project is not use options
132
- return Credentials(req, res, () => {
133
- return checkRoleMiddlewareWithDefaultProject(null)(req, res, next);
134
- });
135
- } else {
136
- // Method is set
137
- if(Project.options.defaultEndpoint[method]) {
138
- if(Project.options.defaultEndpoint[method]["allow"] === undefined || Project.options.defaultEndpoint[method]["allow"] === true) {
139
- if(Project.options.defaultEndpoint[method]["jwt"]?.allow === false) {
140
- // by project jwt_allow is false
141
- return checkRoleMiddlewareWithDefaultProject(null)(req, res, next);
142
- } else {
143
- return Credentials(req, res, () => {
144
- return checkRoleMiddlewareWithDefaultProject(Project.options.defaultEndpoint[method].jwt?.broken_role)(req, res, next);
145
- });
146
- }
147
- } else {
148
- return notfound(res);
149
- }
150
- } else {
151
- // Method is not set
152
- return Credentials(req, res, () => {
153
- return checkRoleMiddlewareWithDefaultProject(null)(req, res, next);
154
- });
155
- }
156
- }
157
- } else {
158
- return errMessage(err, res);
159
- }
160
- });
161
- } else {
162
- // global jwt_allow is false
163
- return next();
164
- }
165
- }
166
- }
167
- }
168
- }
169
-
170
- function Base() {
171
- return new Promise((resolve, reject) => {
172
- try {
173
- walkModel((err, Projects) => {
174
- if (err) {
175
- reject(err);
176
- } else {
177
- const checkPassport = new Promise((resolve) => {
178
- const passport_config_file = appRoot + "/passport.config.js";
179
- let passport_config_auth = undefined;
180
- if (fs.existsSync(passport_config_file)) {
181
- const _passport_config_ = require(passport_config_file);
182
- resolve([_passport_config_.auth_endpoint || "/authentication", _passport_config_]);
183
- } else {
184
- // passport config not found
185
- resolve([passport_config_auth, _passport_config_]);
186
- }
187
- });
188
- // passport conifg promise
189
- checkPassport.then((passport_config) => {
190
- if(Projects.length) {
191
- // GET method with ALL data, default: limit rows 100
192
- endpoint.get("/:hash", (req, res, next) => byPassCheckRole(Projects, "GET", passport_config)(req, res, next), async (req, res, next) => {
193
- let leaveMeAlone = await Projects.slice(0);
194
- await filterProject(leaveMeAlone, req.originalUrl.replace(_publicPath_, '/'), req, res, async (err, Project) => {
195
- if (!err) {
196
- try {
197
- const results = await Project.findAll({
198
- offset: 0,
199
- limit: (Project.options.limitRows) ? Project.options.limitRows : 100,
200
- });
201
- // @ return
202
- await res.json({
203
- code: 200,
204
- status: "SUCCESS",
205
- results,
206
- length: results.length,
207
- });
208
- } catch (error) {
209
- // @return
210
- return errMessage(error, res);
211
- }
212
- } else {
213
- // @return
214
- return errMessage(err, res);
215
- }
216
- });
217
- });
218
- // GET method with id
219
- endpoint.get("/:hash/:id", (req, res, next) => byPassCheckRole(Projects, "GET", passport_config)(req, res, next), async (req, res, next) => {
220
- // allow official stetragy
221
- if(req.params.id == "google" || req.params.id == "facebook") {
222
- return next();
223
- }
224
- // filter GET project
225
- let leaveMeAlone = await Projects.slice(0);
226
- await filterProject(leaveMeAlone, req.originalUrl.replace(_publicPath_, '/'), req, res, async (err, Project) => {
227
- if (!err) {
228
- try {
229
- const results = await Project.findByPk(req.params.id);
230
- // @ return
231
- await res.json({
232
- code: 200,
233
- status: "SUCCESS",
234
- results,
235
- });
236
- } catch (error) {
237
- // @return
238
- return errMessage(error, res);
239
- }
240
- } else {
241
- // @return
242
- return errMessage(err, res);
243
- }
244
- });
245
- });
246
- // GET method with :limit and :offset
247
- endpoint.get("/:hash/:limit/:offset", (req, res, next) => byPassCheckRole(Projects, "GET", passport_config)(req, res, next), async (req, res, next) => {
248
- // allow official stetragy
249
- if(req.params.limit == "google" || req.params.limit == "facebook" || req.params.offset == "callback") {
250
- return next();
251
- }
252
- // filter GET limit,offset project
253
- let leaveMeAlone = await Projects.slice(0);
254
- await filterProject(leaveMeAlone, req.originalUrl.replace(_publicPath_, '/'), req, res, async (err, Project) => {
255
- if (!err) {
256
- try {
257
- const results = await Project.findAll({
258
- offset: parseInt(req.params.offset) || 0,
259
- limit: (parseInt(req.params.limit) === 0) ? 0 : parseInt(req.params.limit),
260
- });
261
- // @ return
262
- await res.json({
263
- code: 200,
264
- status: "SUCCESS",
265
- results,
266
- length: results.length,
267
- });
268
- } catch (error) {
269
- // @return
270
- return errMessage(error, res);
271
- }
272
- } else {
273
- // @return
274
- return errMessage(err, res);
275
- }
276
- });
277
- });
278
- // POST method
279
- endpoint.post("/:hash", (req, res, next) => byPassCheckRole(Projects, "POST", passport_config)(req, res, next), async (req, res, next) => {
280
- // Check auth request match send next
281
- if(passport_config[0] !== undefined) {
282
- if(req.params.hash == passport_config[0].replace(/^\/|\/$/g, "")) {
283
- return next();
284
- }
285
- }
286
- // When lost IF
287
- let leaveMeAlone = await Projects.slice(0);
288
- await filterProject(leaveMeAlone, req.originalUrl.replace(_publicPath_, '/'), req, res, async (err, Project) => {
289
- if (!err) {
290
- try {
291
- // Leave pool by project for check pool error
292
- let pool = Project.sequelize;
293
- // Store with body
294
- await Project.create(req.body).then((created) => {
295
- // @return
296
- res.status(201).json({
297
- code: 201,
298
- status: "CREATE_SUCCESS",
299
- createdId: (created.id) ? created.id : created[Project.primaryKeyAttributes[0]],
300
- });
301
- }).catch((error) => {
302
- if(pool.options.logging) {
303
- // @return with all error
304
- res.status(501).json({
305
- code: 501,
306
- status: "CREATE_FAILED",
307
- error: error,
308
- });
309
- } else {
310
- if(error.sql) {
311
- delete error.sql;
312
- if(error.errors) {
313
- delete error.errors;
314
- }
315
- if(error.parent) {
316
- delete error.parent;
317
- }
318
- if(error.original) {
319
- delete error.original.sql;
320
- if(error.original.parameters) {
321
- delete error.original.parameters;
322
- }
323
- }
324
- if(error.parameters) {
325
- delete error.parameters;
326
- }
327
- // @return with some error
328
- res.status(501).json({
329
- code: 501,
330
- status: "CREATE_FAILED",
331
- error: error,
332
- });
333
- } else {
334
- // @return with some string error
335
- res.status(501).json({
336
- code: 501,
337
- status: "CREATE_FAILED",
338
- error: String(error),
339
- });
340
- }
341
- }
342
- });
343
- } catch (error) {
344
- // @return
345
- return errMessage(error, res);
346
- }
347
- } else {
348
- // @return
349
- return errMessage(err, res);
350
- }
351
- });
352
- });
353
- // PATCH method
354
- endpoint.patch("/:hash/:id", (req, res, next) => byPassCheckRole(Projects, "PATCH", passport_config)(req, res, next), async (req, res, next) => {
355
- let leaveMeAlone = await Projects.slice(0);
356
- await filterProject(leaveMeAlone, req.originalUrl.replace(_publicPath_, '/'), req, res, async (err, Project) => {
357
- if (!err) {
358
- try {
359
- // Leave pool by project for check pool error
360
- let pool = Project.sequelize;
361
- // Assign update pk
362
- let updatePk = {
363
- [Project.primaryKeyAttributes[0]]: req.params.id
364
- };
365
- // Patch with body
366
- await Project.update(req.body, {
367
- where: updatePk,
368
- }).then((updated) => {
369
- // @return
370
- res.status(200).json({
371
- code: 200,
372
- status: "UPDATE_SUCCESS",
373
- result: {
374
- updateId: req.params.id,
375
- affectedRows: updated[0],
376
- },
377
- });
378
- }).catch((error) => {
379
- if(pool.options.logging) {
380
- // @return with all error
381
- res.status(501).json({
382
- code: 501,
383
- status: "UPDATE_FAILED",
384
- error: error,
385
- });
386
- } else {
387
- if(error.sql) {
388
- delete error.sql;
389
- if(error.parent) {
390
- delete error.parent;
391
- }
392
- if(error.original) {
393
- delete error.original.sql;
394
- if(error.original.parameters) {
395
- delete error.original.parameters;
396
- }
397
- }
398
- if(error.parameters) {
399
- delete error.parameters;
400
- }
401
- if(error.errors) {
402
- delete error.errors;
403
- }
404
- // @return with some error
405
- res.status(501).json({
406
- code: 501,
407
- status: "UPDATE_FAILED",
408
- error: error,
409
- });
410
- } else {
411
- // @return with some string error
412
- res.status(501).json({
413
- code: 501,
414
- status: "UPDATE_FAILED",
415
- error: String(error),
416
- });
417
- }
418
- }
419
- });
420
- } catch (error) {
421
- // @return
422
- return errMessage(error, res);
423
- }
424
- } else {
425
- // @return
426
- return errMessage(err, res);
427
- }
428
- });
429
- });
430
- // DELETE method
431
- endpoint.delete("/:hash/:id", (req, res, next) => byPassCheckRole(Projects, "DELETE", passport_config)(req, res, next), async (req, res, next) => {
432
- let leaveMeAlone = await Projects.slice(0);
433
- await filterProject(leaveMeAlone, req.originalUrl.replace(_publicPath_, '/'), req, res, async (err, Project) => {
434
- if (!err) {
435
- try {
436
- // Leave pool by project for check pool error
437
- let pool = Project.sequelize;
438
- // Assign delete pk
439
- let deletePk = {
440
- [Project.primaryKeyAttributes[0]]: req.params.id
441
- };
442
- // Delete with params
443
- await Project.destroy({
444
- where: deletePk,
445
- }).then((deleted) => {
446
- if (deleted) {
447
- // @return
448
- res.status(200).json({
449
- code: 200,
450
- status: "DELETE_SUCCESS",
451
- result: {
452
- deleteId: req.params.id,
453
- affectedRows: deleted,
454
- },
455
- });
456
- } else {
457
- res.status(406).json({
458
- code: 406,
459
- status: "NOT_ACCEPTABLE",
460
- result: {
461
- deleteId: req.params.id,
462
- affectedRows: deleted,
463
- },
464
- });
465
- }
466
- }).catch((error) => {
467
- if(pool.options.logging) {
468
- // @return with all error
469
- res.status(501).json({
470
- code: 501,
471
- status: "DELETE_FAILED",
472
- error: error,
473
- });
474
- } else {
475
- if(error.sql) {
476
- delete error.sql;
477
- if(error.parent) {
478
- delete error.parent;
479
- }
480
- if(error.original) {
481
- delete error.original.sql;
482
- if(error.original.parameters) {
483
- delete error.original.parameters;
484
- }
485
- }
486
- if(error.parameters) {
487
- delete error.parameters;
488
- }
489
- if(error.errors) {
490
- delete error.errors;
491
- }
492
- // @return with some error
493
- res.status(501).json({
494
- code: 501,
495
- status: "DELETE_FAILED",
496
- error: error,
497
- });
498
- } else {
499
- // @return with some string error
500
- res.status(501).json({
501
- code: 501,
502
- status: "DELETE_FAILED",
503
- error: String(error),
504
- });
505
- }
506
- }
507
- });
508
- } catch (error) {
509
- // @return
510
- return errMessage(error, res);
511
- }
512
- } else {
513
- // @return
514
- return errMessage(err, res);
515
- }
516
- });
517
- });
518
- }
519
- // resolve it.
520
- resolve(true);
521
- }).catch((err) => {
522
- reject(err);
523
- });
524
- }
525
- });
526
- } catch (error) {
527
- reject(error);
528
- }
529
- });
530
- }
531
-
532
- module.exports = { Base };
1
+ const walk = require("walk");
2
+ const fs = require("fs");
3
+ const moment = require("moment");
4
+ const { checkRoleMiddlewareWithDefaultProject } = require("../../cli/core/middleware/express/jwtCheckAllow");
5
+ const { Limiter, Duplicater } = require("../../cli/core/middleware/index");
6
+
7
+ function walkModel(cb) {
8
+ try {
9
+ let jsfiles = [];
10
+ let walker = walk.walk(appRoot + "/src/models", { followLinks: false });
11
+ // Walk file on push
12
+ walker.on("file", (root, stat, next) => {
13
+ jsfiles.push(root + "/" + stat.name);
14
+ next();
15
+ });
16
+ // Walking
17
+ walker.on("end", () => {
18
+ let preProject = [];
19
+ if(jsfiles.length) {
20
+ jsfiles.forEach((file, k) => {
21
+ let schemaPath = "@/models" + file.split("models")[1].replace(/\\/g, "/");
22
+ let endpoint = file
23
+ .split("models")[1]
24
+ .replace(/\\/g, "/")
25
+ .replace(/_/g, "-")
26
+ .toLowerCase()
27
+ .slice(0, -3);
28
+ preProject.push([schemaPath, endpoint]);
29
+ if (jsfiles.length == k + 1) {
30
+ cb(null, preProject);
31
+ }
32
+ });
33
+ } else {
34
+ // model not found.
35
+ cb(null, preProject);
36
+ }
37
+ });
38
+ } catch (error) {
39
+ cb(error, null);
40
+ }
41
+ }
42
+
43
+ function filterProject(Projects, reqUrl, params = "", method = "", req, res, cb) {
44
+ try {
45
+ let pj = Projects.shift();
46
+ let leaveParamsAlone = params.slice(0);
47
+ let paramsItem = leaveParamsAlone.replace(/^\/|\/$/g, "").split('/');
48
+ let leaveReqUrlAlone = reqUrl.slice(0);
49
+ let newParams = params.split("/").filter((e) => (e !== 'undefined')).join("/");
50
+ let urlWithoutParams = leaveReqUrlAlone.replace(newParams, '').split("?")[0].replace(/\/$/, "");
51
+ // sub-way for PATCH method
52
+ urlWithoutParams = (method == "PATCH" || method == "DELETE") ? urlWithoutParams.substring(0, urlWithoutParams.lastIndexOf('/')) : urlWithoutParams;
53
+ // check match project by url
54
+ if(pj[1] == urlWithoutParams) {
55
+ return checkOffset(Object.values(require(pj[0]))[0], req, res, (thenChecked) => {
56
+ if(thenChecked) {
57
+ return cb(null, Object.values(require(pj[0]))[0], paramsItem);
58
+ }
59
+ });
60
+ }
61
+ // Finally recursive filterProject function
62
+ if (Projects.length > 0) {
63
+ filterProject(Projects, reqUrl, params, method, req, res, cb);
64
+ } else {
65
+ // not match
66
+ return notfound(res);
67
+ }
68
+ } catch (error) {
69
+ console.log(error);
70
+ cb(error, null, []);
71
+ }
72
+ }
73
+
74
+ function filterProjectForByPass(Projects, reqUrl, req, res, cb) {
75
+ try {
76
+ let pj = Projects.shift();
77
+ let regx = new RegExp(pj[1] + "?[^\/].?[a-zA-Z0-9].*$", 'g');
78
+ let regxMatch = reqUrl.match(regx);
79
+ let regxMatchLength = (regxMatch) ? regxMatch.length: 0;
80
+ if (pj[1] == reqUrl) {
81
+ return checkOffset(Object.values(require(pj[0]))[0], req, res, (thenChecked) => {
82
+ if(thenChecked) {
83
+ return cb(null, Object.values(require(pj[0]))[0]);
84
+ }
85
+ });
86
+ } else if(regxMatchLength) {
87
+ return checkOffset(Object.values(require(pj[0]))[0], req, res, (thenChecked) => {
88
+ if(thenChecked) {
89
+ return cb(null, Object.values(require(pj[0]))[0]);
90
+ }
91
+ });
92
+ }
93
+ // Finally recursive filterProjectForByPass function
94
+ if (Projects.length > 0) {
95
+ filterProjectForByPass(Projects, reqUrl, req, res, cb);
96
+ } else {
97
+ // not match
98
+ return notfound(res);
99
+ }
100
+ } catch (error) {
101
+ cb(error, null);
102
+ }
103
+ }
104
+
105
+ function checkOffset(Project, req, res, cb) {
106
+ if (!Project) {
107
+ return notfound(res);
108
+ }
109
+ // check offset is Ingeter as well as Zero number
110
+ let offset = req.params.offset || undefined;
111
+ let limit = req.params.limit || undefined;
112
+ let offsetRegxMatch = (offset !== undefined) ? offset.match(/^[0-9]+$/) : undefined;
113
+ let limitRegxMatch = (limit !== undefined) ? limit.match(/^[0-9]+$/) : undefined;
114
+ if (offsetRegxMatch && limitRegxMatch) {
115
+ cb(true);
116
+ } else {
117
+ if(offset === undefined) {
118
+ cb(true);
119
+ } else {
120
+ return notfound(res);
121
+ }
122
+ }
123
+ }
124
+
125
+ function notfound(res) {
126
+ return res.status(404).json({
127
+ code: 404,
128
+ status: "404_NOT_FOUND",
129
+ message: "The Endpoint not found!.",
130
+ });
131
+ }
132
+
133
+ function errMessage(err, res) {
134
+ let errTurnOffDbDefine = JSON.stringify(err.toString()).match(/'define'/);
135
+ let errTurnOffDbOption = JSON.stringify(err.toString()).match(/'options'/);
136
+ if(errTurnOffDbDefine || errTurnOffDbOption) {
137
+ // @return
138
+ return res.status(500).json({
139
+ code: 500,
140
+ status: "ERR_INTERNAL_SERVER",
141
+ message: "Database connection name is CLOSED.",
142
+ });
143
+ } else {
144
+ // @return
145
+ return res.status(500).json({
146
+ code: 500,
147
+ status: "ERR_INTERNAL_SERVER",
148
+ message: err.toString(),
149
+ });
150
+ }
151
+ }
152
+
153
+ function whereCond(objectCond, cb) {
154
+ if(typeof objectCond === 'object' && Object.keys(objectCond).length) {
155
+ let keys = Object.keys(objectCond);
156
+ let where = {};
157
+ let orderBy = {};
158
+ let groupBy = {};
159
+ // Start Recursive for Check Where condition OR GroupBy OR OrderBy
160
+ recursiveWhereCond(keys, objectCond, where, groupBy, orderBy, (err, cbWhere, cbGroupBy, cbOrderBy) => {
161
+ cb(err, cbWhere, cbGroupBy, cbOrderBy);
162
+ });
163
+ } else {
164
+ cb(null, {}, { group: { groupby: [] } }, { order: { orderby: [] } });
165
+ }
166
+ }
167
+
168
+ function getValueType(value) {
169
+ if (typeof value === 'string') {
170
+ // Check for ISO-like date string with optional time part
171
+ const isoDateRegex = /^\d{4}-\d{2}-\d{2}(?:[ T]\d{2}:\d{2}:\d{2})?$/;
172
+ const date = new Date(value);
173
+ if (!isNaN(date.getTime()) && isoDateRegex.test(value)) {
174
+ return 'Date';
175
+ }
176
+ return 'String';
177
+ }
178
+ if (typeof value === 'number' && !isNaN(value)) return 'Number';
179
+ if (typeof value === 'boolean') return 'Boolean';
180
+ if (value instanceof Date && !isNaN(value)) return 'Date';
181
+ if (value === null) return 'Null';
182
+ if (typeof value === 'undefined') return 'Undefined';
183
+ if (Array.isArray(value)) return 'Array';
184
+ if (typeof value === 'function') return 'Function';
185
+ if (typeof value === 'symbol') return 'Symbol';
186
+ if (typeof value === 'bigint') return 'BigInt';
187
+ if (typeof value === 'object') return 'Object';
188
+ return 'Unknown';
189
+ }
190
+
191
+ async function recursiveWhereCond(keys, objectCond, where, groupBy, orderBy, cb) {
192
+ if(keys.length > 0) {
193
+ let k = keys.shift();
194
+ // Check param key for Where condition OR GroupBy OR OrderBy
195
+ if(k == 'orderby') {
196
+ let oderByValueItemFromQueryString = objectCond[k].replace(/\w+/g, '"$&"').replace(/\[\s*\]/g, '[]');
197
+ // Check Array syntax from Query String
198
+ isValidArrayFormat(oderByValueItemFromQueryString, (err, isArray, strArr) => {
199
+ if(err) {
200
+ cb(["SyntaxError: Unexpected end of Array or String input", ` (${k})`], null, null, null);
201
+ return;
202
+ } else {
203
+ let order = JSON.parse(strArr);
204
+ orderBy[k] = order.length ? order : null;
205
+ // Recursive re-call function
206
+ recursiveWhereCond(keys, objectCond, where, groupBy, orderBy, cb);
207
+ }
208
+ });
209
+ } else if(k == 'groupby') {
210
+ let groupByValueItemFromQueryString = objectCond[k].replace(/\w+/g, '"$&"').replace(/\[\s*\]/g, '[]');
211
+ // Check Array syntax from Query String
212
+ isValidArrayFormat(groupByValueItemFromQueryString, (err, isArray, strArr) => {
213
+ if(err) {
214
+ cb(["SyntaxError: Unexpected end of Array or String input", ` (${k})`], null, null, null);
215
+ return;
216
+ } else {
217
+ let group = JSON.parse(strArr);
218
+ groupBy[k] = group.length ? group : null;
219
+ // Recursive re-call function
220
+ recursiveWhereCond(keys, objectCond, where, groupBy, orderBy, cb);
221
+ }
222
+ });
223
+ } else {
224
+ // 1. Get raw value, force to String and replace %22 to double quote "
225
+ let rawInput = objectCond[k];
226
+ if (Array.isArray(rawInput)) {
227
+ rawInput = rawInput.join(",");
228
+ }
229
+ let decodedQueryString = String(rawInput).replace(/%22/g, '"').replace(/'/g, '"');
230
+ // 2. Advanced decoding logic (works for all operations like LIKE, EQUAL, IN, BETWEEN)
231
+ // Force to look for groups of language codes (% followed by two hexadecimal digits like %E0, %B8)
232
+ // It will capture consecutive codes as a single group and decode them together for accuracy
233
+ decodedQueryString = decodedQueryString.replace(/(?:%[0-9A-F]{2})+/gi, (match) => {
234
+ try {
235
+ return decodeURIComponent(match);
236
+ } catch (e) {
237
+ // This fallback will attempt to decode each %XX sequence individually, which can help recover partial decoding even if the full group is malformed
238
+ return match.replace(/%([0-9A-F]{2})/gi, (subMatch) => {
239
+ try { return decodeURIComponent(subMatch); } catch { return subMatch; }
240
+ });
241
+ }
242
+ });
243
+ // 3. Special handling for BETWEEN and NOT BETWEEN operations to ensure date formats are preserved correctly
244
+ let isBetweenOp = decodedQueryString.toLowerCase().includes('between') || decodedQueryString.toLowerCase().includes('notbetween');
245
+ if (isBetweenOp) {
246
+ try {
247
+ let arrayMatch = decodedQueryString.match(/\[\s*(between|notbetween)\s*,\s*(\[.*\])\s*\]/i);
248
+ if (arrayMatch && arrayMatch[2]) {
249
+ let op = arrayMatch[1];
250
+ let dateArrayStr = arrayMatch[2];
251
+ if (!dateArrayStr.includes('"')) {
252
+ dateArrayStr = dateArrayStr.replace(/([^\[\],]+)/g, '"$1"');
253
+ }
254
+ let parsedDates = JSON.parse(dateArrayStr);
255
+ if (Array.isArray(parsedDates) && parsedDates.length >= 2) {
256
+ // Trim and remove any extraneous quotes from the parsed date strings
257
+ let dateStart = parsedDates[0].trim().replace(/"/g, '');
258
+ let dateEnd = parsedDates[1].trim().replace(/"/g, '');
259
+ // Ensure that if the date string is in a format like "2026-05-17 00:00:00", it is converted to "2026-05-17T00:00:00" for proper Date parsing
260
+ dateStart = dateStart.replace(' ', 'T');
261
+ dateEnd = dateEnd.replace(' ', 'T');
262
+ decodedQueryString = `[${op},${dateStart},${dateEnd}]`;
263
+ }
264
+ }
265
+ } catch (err) {
266
+ cb(["SyntaxError: Invalid format for BETWEEN/NOT BETWEEN operation", ` (${k})`], null, null, null);
267
+ return;
268
+ }
269
+ }
270
+ // 4. Format the decoded query string to prepare for Sequelize operators
271
+ let fieldValueItemFromQueryString = decodedQueryString.replace(/([^[\]," ]+)/g, '"$1"').replace(/""/g, '"');
272
+ let valueItem = decodedQueryString.replace(/[\[\]']+/g, '').replace(/"/g, '').split(',');
273
+ let cleanValueItem = valueItem.map((e) => e.trim()).filter((e) => e !== '');
274
+ // Check Array syntax from Query String
275
+ isValidArrayFormat(fieldValueItemFromQueryString, async (err) => {
276
+ if(err || cleanValueItem.length < 1) {
277
+ cb(["SyntaxError: Unexpected end of Array or String input", ` (${k})`], null, null, null);
278
+ return;
279
+ } else {
280
+ try {
281
+ let targetValue = cleanValueItem[1];
282
+ if (cleanValueItem[0] === 'like' || cleanValueItem[0] === 'notLike') {
283
+ targetValue = cleanValueItem.slice(1).join("");
284
+ }
285
+ where[k] = (cleanValueItem[1])
286
+ ? {
287
+ [Op[cleanValueItem[0]]]: (cleanValueItem[1] == 'null') ? null :
288
+ (cleanValueItem[1] == 'true') ? true :
289
+ (cleanValueItem[1] == 'false') ? false :
290
+ (cleanValueItem[0] == 'between' || cleanValueItem[0] == 'notBetween') ? [
291
+ (getValueType(cleanValueItem[1]) == 'Date')
292
+ ? (() => {
293
+ let mDate = moment(cleanValueItem[1]);
294
+ if (cleanValueItem[1].length <= 10 && !cleanValueItem[1].includes(':')) {
295
+ mDate.startOf('day');
296
+ }
297
+ return mDate.format('YYYY-MM-DD HH:mm:ss');
298
+ })()
299
+ : cleanValueItem[1],
300
+ (getValueType(cleanValueItem[2]) == 'Date')
301
+ ? (() => {
302
+ let mDate = moment(cleanValueItem[2]);
303
+ if (cleanValueItem[2].length <= 10 && !cleanValueItem[2].includes(':')) {
304
+ mDate.endOf('day');
305
+ }
306
+ return mDate.format('YYYY-MM-DD HH:mm:ss');
307
+ })()
308
+ : cleanValueItem[2],
309
+ ] :
310
+ (cleanValueItem[0] == 'or' || cleanValueItem[0] == 'in' || cleanValueItem[0] == 'notIn') ? [...cleanValueItem.slice(1)] :
311
+ (cleanValueItem[0] == 'like') ? targetValue :
312
+ (cleanValueItem[0] == 'notLike') ? targetValue :
313
+ (cleanValueItem[0] == 'startsWith') ? cleanValueItem[1] :
314
+ (cleanValueItem[0] == 'endsWith') ? cleanValueItem[1] :
315
+ (cleanValueItem[0] == 'substring') ? cleanValueItem[1] :
316
+ [cleanValueItem[1]]
317
+ }
318
+ : cleanValueItem[0];
319
+ // Recursive re-call function
320
+ recursiveWhereCond(keys, objectCond, where, groupBy, orderBy, cb);
321
+ } catch (error) {
322
+ return cb([`Error with (${k})`, error], null, null, null);
323
+ }
324
+ }
325
+ });
326
+ }
327
+ } else {
328
+ // End of recursive function
329
+ cb(null, where, groupBy, orderBy);
330
+ }
331
+ }
332
+
333
+ function isValidArrayFormat(str, cb) {
334
+ try {
335
+ const parsed = JSON.parse(str);
336
+ cb(null, Array.isArray(parsed), str);
337
+ } catch (err) {
338
+ cb(err, false, null);
339
+ }
340
+ }
341
+
342
+ // function parseRawQuery(search) {
343
+ // const rawParams = {};
344
+ // if (search.startsWith('?')) {
345
+ // const queryString = search.slice(1); // Remove '?'
346
+ // const pairs = queryString.split('&');
347
+
348
+ // for (const pair of pairs) {
349
+ // const [key, value = ''] = pair.split('=');
350
+ // if (key) {
351
+ // rawParams[key] = value;
352
+ // }
353
+ // }
354
+ // }
355
+ // return rawParams;
356
+ // }
357
+
358
+ async function findAll(Project, where, offset, group, order, limitRow, cb) {
359
+ try {
360
+ await Project.findAll({
361
+ where,
362
+ group: (group.groupby) ? group.groupby : [],
363
+ order: (order.orderby) ? [order.orderby] : [],
364
+ offset: offset,
365
+ limit: limitRow,
366
+ }).then((results) => {
367
+ cb(null, results)
368
+ }).catch((error) => {
369
+ cb(error, null);
370
+ });
371
+ } catch (error) {
372
+ cb(error, null);
373
+ }
374
+ }
375
+
376
+ async function retrieving(authEndpoint, Projects, req, res, next) {
377
+ let params = req.params;
378
+ let hash = "/" + req.params.hash;
379
+ // allow official stetragy
380
+ if(hash == authEndpoint && (params[0] == "/facebook" || params[0] == "/facebook/callback" || params[0] == "/google" || params[0] == "/google/callback")) {
381
+ return next();
382
+ }
383
+ // declare variable for check request with params
384
+ let leaveMeAlone = await Projects.slice(0);
385
+ let mergeDuoVar = [req.params.limit, req.params.offset].map((e) => (e || 'undefined')).join("/");
386
+ let reqUrl = req.originalUrl.replace(_publicPath_, '/');
387
+ let checkConditionIsQueryOrId = Object.keys(req.query).length
388
+ ? req.query
389
+ : 'undefined';
390
+ /**
391
+ * Function whereCond with callback property
392
+ *
393
+ * @where Object|String
394
+ *
395
+ */
396
+ whereCond(checkConditionIsQueryOrId, async (err, where, groupBy, orderBy) => {
397
+ if(err) {
398
+ res.status(400).json({
399
+ code: 400,
400
+ status: "BAD_REQUEST",
401
+ err: String(err),
402
+ });
403
+ } else {
404
+ /**
405
+ * Filter Project with callback property
406
+ *
407
+ * @err String
408
+ * @Project Require
409
+ * @params Object [0=limit, 1=offset]
410
+ *
411
+ */
412
+ await filterProject(leaveMeAlone, reqUrl, "/".concat(mergeDuoVar), "", req, res, async (err, Project, params) => {
413
+ if (!err) {
414
+ try {
415
+ // declare default limit offset
416
+ let offset = 0;
417
+ let limitRow = await (Project.options.limitRows) ? Project.options.limitRows : 100;
418
+ // check assign limit, offset ?
419
+ if ((params[0] && params[0] != 'undefined') && ((params[1] && params[1] != 'undefined') || parseInt(params[1]) === 0)) {
420
+ // Only case: /limit/offset
421
+ limitRow = parseInt(params[0]);
422
+ offset = parseInt(params[1]);
423
+ }
424
+ // findAll data
425
+ await findAll(Project, where, offset, groupBy, orderBy, limitRow, (err, results) => {
426
+ if(err) {
427
+ res.status(500).json({
428
+ code: 500,
429
+ status: "READ_CATCH",
430
+ err: String(err),
431
+ });
432
+ } else {
433
+ // @ return findAll
434
+ res.json({
435
+ code: 200,
436
+ status: "SUCCESS",
437
+ results,
438
+ length: results.length,
439
+ limitRow,
440
+ });
441
+ }
442
+ });
443
+ } catch (error) {
444
+ // @return
445
+ return errMessage(error, res);
446
+ }
447
+ } else {
448
+ // @return
449
+ return errMessage(err, res);
450
+ }
451
+ });
452
+ }
453
+ });
454
+ }
455
+
456
+ // Duplicater cache for each config, avoid create new instance with same config
457
+ const duplicaterCache = new Map();
458
+ function getDuplicaterInstance(dupConfig = {}) {
459
+ const key = JSON.stringify(dupConfig || {});
460
+ if (!duplicaterCache.has(key)) {
461
+ duplicaterCache.set(key, Duplicater(dupConfig || {}));
462
+ }
463
+ return duplicaterCache.get(key);
464
+ }
465
+
466
+ // Limiter cache for each config, avoid create new instance with same config
467
+ const limiterCache = new Map();
468
+ function getLimiterInstance(rateConfig = {}) {
469
+ const key = JSON.stringify(rateConfig);
470
+ if (!limiterCache.has(key)) {
471
+ limiterCache.set(key, Limiter(rateConfig));
472
+ }
473
+ return limiterCache.get(key);
474
+ }
475
+
476
+ const byPassCheckRole = (Projects, method, passport_config) => {
477
+ return async function (req, res, next) {
478
+ try {
479
+ if(passport_config[0] !== undefined) {
480
+ if(req.params.hash == passport_config[0].replace(/^\/|\/$/g, "")) {
481
+ return next();
482
+ } else {
483
+ if(passport_config[1].jwt_allow === true) {
484
+ let leaveMeAlone = await Projects.slice(0);
485
+ await filterProjectForByPass(leaveMeAlone, req.originalUrl.replace(_publicPath_, '/'), req, res, async (err, Project) => {
486
+ if(!err) {
487
+ // Set Duplicater and Limiter for each project with method
488
+ const dupConfig = (Project.options?.defaultEndpoint?.[method]?.duplicate_request) ? Project.options.defaultEndpoint[method].duplicate_request : {};
489
+ const duplicaterMiddleware = getDuplicaterInstance(dupConfig);
490
+ return duplicaterMiddleware(req, res, (err) => {
491
+ if (!err) {
492
+ const rateConfig = (Project.options?.defaultEndpoint?.[method]?.rate_limit) ? Project.options.defaultEndpoint[method].rate_limit : {};
493
+ const limiterMiddleware = getLimiterInstance(rateConfig);
494
+ limiterMiddleware(req, res, (err) => {
495
+ if (!err) {
496
+ if(Project.options.defaultEndpoint === undefined || Project.options.defaultEndpoint === true) {
497
+ // Project is not use options
498
+ return Credentials(req, res, () => {
499
+ return checkRoleMiddlewareWithDefaultProject(null)(req, res, next);
500
+ });
501
+ } else {
502
+ // Method is set
503
+ if(Project.options.defaultEndpoint[method]) {
504
+ if(Project.options.defaultEndpoint[method]["allow"] === undefined || Project.options.defaultEndpoint[method]["allow"] === true) {
505
+ if(Project.options.defaultEndpoint[method]["jwt"]?.allow === false) {
506
+ // by project jwt_allow is false
507
+ return checkRoleMiddlewareWithDefaultProject(null)(req, res, next);
508
+ } else {
509
+ //return Credentials(req, res, () => {
510
+ // return checkRoleMiddlewareWithDefaultProject(Project.options.defaultEndpoint[method].jwt?.broken_role)(req, res, next);
511
+ //});
512
+ return Credentials(req, res, () => checkRoleMiddlewareWithDefaultProject(Project.options.defaultEndpoint[method].jwt?.broken_role || null)(req, res, next));
513
+ }
514
+ } else {
515
+ // METHOD.allow is false || METHOD.allow is undefined
516
+ return notfound(res);
517
+ }
518
+ } else if(Project.options.defaultEndpoint[method] === true || Project.options.defaultEndpoint[method] === undefined) {
519
+ // Method is not set
520
+ return Credentials(req, res, () => {
521
+ return checkRoleMiddlewareWithDefaultProject(null)(req, res, next);
522
+ });
523
+ } else {
524
+ // METHOD is false || METHOD is not undefined
525
+ return notfound(res);
526
+ }
527
+ }
528
+ } else {
529
+ return res.status(429).json({
530
+ code: 429,
531
+ status: "TOO_MANY_REQUEST",
532
+ message: "Too Many Requests.",
533
+ });
534
+ }
535
+ });
536
+ } else {
537
+ return res.status(409).json({
538
+ code: 409,
539
+ status: "DUPLICATE_REQUEST",
540
+ message: "Duplicate request detected.",
541
+ });
542
+ }
543
+ });
544
+ } else {
545
+ return errMessage(err, res);
546
+ }
547
+ });
548
+ } else {
549
+ // global jwt_allow is false
550
+ return next();
551
+ }
552
+ }
553
+ } else {
554
+ // passport config not found
555
+ return next();
556
+ }
557
+ } catch (error) {
558
+ return errMessage(error, res);
559
+ }
560
+ }
561
+ }
562
+
563
+ function Base() {
564
+ return new Promise((resolve, reject) => {
565
+ try {
566
+ walkModel((err, Projects) => {
567
+ if (err) {
568
+ reject(err);
569
+ } else {
570
+ const checkPassport = new Promise((resolve) => {
571
+ const passport_config_file = appRoot + "/passport.config.js";
572
+ let passport_config_auth = undefined;
573
+ if (fs.existsSync(passport_config_file)) {
574
+ const _passport_config_ = require(passport_config_file);
575
+ resolve([_passport_config_.auth_endpoint || "/authentication", _passport_config_]);
576
+ } else {
577
+ // passport config not found
578
+ resolve([passport_config_auth, {}]);
579
+ }
580
+ });
581
+ // passport conifg promise
582
+ checkPassport.then((passport_config) => {
583
+ if(Projects.length) {
584
+ // GET method with /:limit/:offset
585
+ endpoint.get("/:hash([a-zA-Z0-9-]+)*/:limit([0-9]+)/:offset([0-9]+)", (req, res, next) => byPassCheckRole(Projects, "GET", passport_config)(req, res, next), async (req, res, next) => {
586
+ await retrieving(passport_config[0], Projects, req, res, next);
587
+ });
588
+
589
+ // GET method only hash/*
590
+ endpoint.get("/:hash([a-zA-Z0-9-]+)*", (req, res, next) => byPassCheckRole(Projects, "GET", passport_config)(req, res, next), async (req, res, next) => {
591
+ await retrieving(passport_config[0], Projects, req, res, next);
592
+ });
593
+
594
+ // POST method
595
+ endpoint.post("/:hash*", (req, res, next) => byPassCheckRole(Projects, "POST", passport_config)(req, res, next), async (req, res, next) => {
596
+ // Check auth request match send next
597
+ if(passport_config[0] !== undefined) {
598
+ if(req.params.hash == passport_config[0].replace(/^\/|\/$/g, "")) {
599
+ return next();
600
+ }
601
+ }
602
+ // When lost IF
603
+ let leaveMeAlone = await Projects.slice(0);
604
+ let reqUrl = req.originalUrl.replace(_publicPath_, '/');
605
+ let bodyIsArray = Array.isArray(req.body);
606
+ await filterProject(leaveMeAlone, reqUrl, "", "", req, res, async (err, Project) => {
607
+ if (!err) {
608
+ try {
609
+ // Leave pool by project for check pool error
610
+ let pool = Project.sequelize;
611
+ // Transaction create
612
+ Project.transaction(async t => {
613
+ try {
614
+ if (bodyIsArray) {
615
+ // Store with bulk body
616
+ const bulkCreated = await Project.bulkCreate(req.body, { transaction: t });
617
+ await t.commit();
618
+ // @return
619
+ res.status(201).json({
620
+ code: 201,
621
+ status: "CREATE_SUCCESS",
622
+ mode: {
623
+ type: "BULK",
624
+ affectedRows: bulkCreated.length,
625
+ },
626
+ createdId: [
627
+ ...bulkCreated.map(item => (item.id) ? item.id : item[Project.primaryKeyAttributes[0]]),
628
+ ],
629
+ });
630
+ } else {
631
+ // Store with single body
632
+ const singleCreated = await Project.create(req.body, { transaction: t });
633
+ await t.commit();
634
+ // @return
635
+ res.status(201).json({
636
+ code: 201,
637
+ status: "CREATE_SUCCESS",
638
+ mode: {
639
+ type: "SINGLE",
640
+ affectedRows: 1,
641
+ },
642
+ createdId: (singleCreated.id) ? singleCreated.id : singleCreated[Project.primaryKeyAttributes[0]],
643
+ });
644
+ }
645
+ } catch (error) {
646
+ await t.rollback();
647
+ if(pool.options.logging) {
648
+ // @return with all error
649
+ res.status(501).json({
650
+ code: 501,
651
+ status: "CREATE_FAILED",
652
+ mode: {
653
+ debug: true,
654
+ type: (bodyIsArray) ? "BULK" : "SINGLE",
655
+ affectedRows: 0,
656
+ },
657
+ error: error,
658
+ });
659
+ } else {
660
+ if(error.sql) {
661
+ delete error.sql;
662
+ if(error.errors) {
663
+ delete error.errors;
664
+ }
665
+ if(error.parent) {
666
+ delete error.parent;
667
+ }
668
+ if(error.original) {
669
+ delete error.original.sql;
670
+ if(error.original.parameters) {
671
+ delete error.original.parameters;
672
+ }
673
+ }
674
+ if(error.parameters) {
675
+ delete error.parameters;
676
+ }
677
+ // @return with some error
678
+ res.status(501).json({
679
+ code: 501,
680
+ status: "CREATE_FAILED",
681
+ mode: {
682
+ debug: false,
683
+ type: (bodyIsArray) ? "BULK" : "SINGLE",
684
+ affectedRows: 0,
685
+ },
686
+ error: error,
687
+ });
688
+ } else {
689
+ // @return with some string error
690
+ res.status(501).json({
691
+ code: 501,
692
+ status: "CREATE_FAILED",
693
+ mode: {
694
+ debug: false,
695
+ type: (bodyIsArray) ? "BULK" : "SINGLE",
696
+ affectedRows: 0,
697
+ },
698
+ error: String(error),
699
+ });
700
+ }
701
+ }
702
+ }
703
+ });
704
+ } catch (error) {
705
+ // @return
706
+ return errMessage(error, res);
707
+ }
708
+ } else {
709
+ // @return
710
+ return errMessage(err, res);
711
+ }
712
+ });
713
+ });
714
+
715
+ // PATCH method
716
+ endpoint.patch("/:hash*/:id([a-zA-Z0-9-]+)", (req, res, next) => byPassCheckRole(Projects, "PATCH", passport_config)(req, res, next), async (req, res, next) => {
717
+ let leaveMeAlone = await Projects.slice(0);
718
+ let reqUrl = req.originalUrl.replace(_publicPath_, '/');
719
+ await filterProject(leaveMeAlone, reqUrl, "", "PATCH", req, res, async (err, Project) => {
720
+ if (!err) {
721
+ try {
722
+ // Check body is empty
723
+ if(Object.keys(req.body).length === 0) {
724
+ return res.status(400).json({
725
+ code: 400,
726
+ status: "BAD_REQUEST",
727
+ message: "Bad request.",
728
+ info: {
729
+ status: "BAD_ENTIRY",
730
+ message: "Unprocessable Entity.",
731
+ },
732
+ });
733
+ }
734
+ // Leave pool by project for check pool error
735
+ let pool = Project.sequelize;
736
+ // Transaction update|patch
737
+ Project.transaction(async t => {
738
+ try {
739
+ // Assign update pk
740
+ let updatePk = { [Project.primaryKeyAttributes[0]]: req.params.id };
741
+ // Patch with body
742
+ const updated = await Project.update(req.body, {
743
+ where: updatePk,
744
+ }, { transaction: t });
745
+ if(updated[0]) {
746
+ await t.commit();
747
+ // @return
748
+ res.status(200).json({
749
+ code: 200,
750
+ status: "UPDATE_SUCCESS",
751
+ mode: {
752
+ debug: true,
753
+ },
754
+ result: {
755
+ updateId: req.params.id,
756
+ affectedRows: updated[0],
757
+ },
758
+ });
759
+ } else {
760
+ await t.rollback();
761
+ res.status(406).json({
762
+ code: 406,
763
+ status: "NOT_ACCEPTABLE",
764
+ result: {
765
+ affectedRows: updated[0],
766
+ },
767
+ });
768
+ }
769
+ } catch (error) {
770
+ await t.rollback();
771
+ if(pool.options.logging) {
772
+ // @return with all error
773
+ res.status(501).json({
774
+ code: 501,
775
+ status: "UPDATE_FAILED",
776
+ mode: {
777
+ debug: false,
778
+ },
779
+ error: error,
780
+ });
781
+ } else {
782
+ if(error.sql) {
783
+ delete error.sql;
784
+ if(error.parent) {
785
+ delete error.parent;
786
+ }
787
+ if(error.original) {
788
+ delete error.original.sql;
789
+ if(error.original.parameters) {
790
+ delete error.original.parameters;
791
+ }
792
+ }
793
+ if(error.parameters) {
794
+ delete error.parameters;
795
+ }
796
+ if(error.errors) {
797
+ delete error.errors;
798
+ }
799
+ // @return with some error
800
+ res.status(501).json({
801
+ code: 501,
802
+ status: "UPDATE_FAILED",
803
+ mode: {
804
+ debug: false,
805
+ },
806
+ error: error,
807
+ });
808
+ } else {
809
+ // @return with some string error
810
+ res.status(501).json({
811
+ code: 501,
812
+ status: "UPDATE_FAILED",
813
+ mode: {
814
+ debug: false,
815
+ },
816
+ error: String(error),
817
+ });
818
+ }
819
+ }
820
+ }
821
+ });
822
+ } catch (error) {
823
+ // @return
824
+ return errMessage(error, res);
825
+ }
826
+ } else {
827
+ // @return
828
+ return errMessage(err, res);
829
+ }
830
+ });
831
+ });
832
+
833
+ // DELETE method
834
+ endpoint.delete("/:hash*/:id([a-zA-Z0-9-]+)", (req, res, next) => byPassCheckRole(Projects, "DELETE", passport_config)(req, res, next), async (req, res, next) => {
835
+ let leaveMeAlone = await Projects.slice(0);
836
+ await filterProject(leaveMeAlone, req.originalUrl.replace(_publicPath_, '/'), "", "DELETE", req, res, async (err, Project) => {
837
+ if (!err) {
838
+ try {
839
+ // Leave pool by project for check pool error
840
+ let pool = Project.sequelize;
841
+ // Transaction update|patch
842
+ Project.transaction(async t => {
843
+ try {
844
+ // Assign delete pk
845
+ let deletePk = { [Project.primaryKeyAttributes[0]]: req.params.id };
846
+ // Delete with params
847
+ const deleted = await Project.destroy({
848
+ where: deletePk,
849
+ }, { transaction: t });
850
+ if (deleted) {
851
+ await t.commit();
852
+ // @return
853
+ res.status(200).json({
854
+ code: 200,
855
+ status: "DELETE_SUCCESS",
856
+ result: {
857
+ deleteId: req.params.id,
858
+ affectedRows: deleted,
859
+ },
860
+ });
861
+ } else {
862
+ await t.rollback();
863
+ res.status(406).json({
864
+ code: 406,
865
+ status: "NOT_ACCEPTABLE",
866
+ result: {
867
+ affectedRows: deleted,
868
+ },
869
+ });
870
+ }
871
+ } catch (error) {
872
+ if(pool.options.logging) {
873
+ // @return with all error
874
+ res.status(501).json({
875
+ code: 501,
876
+ status: "DELETE_FAILED",
877
+ mode: {
878
+ debug: true,
879
+ },
880
+ error: error,
881
+ });
882
+ } else {
883
+ if(error.sql) {
884
+ delete error.sql;
885
+ if(error.parent) {
886
+ delete error.parent;
887
+ }
888
+ if(error.original) {
889
+ delete error.original.sql;
890
+ if(error.original.parameters) {
891
+ delete error.original.parameters;
892
+ }
893
+ }
894
+ if(error.parameters) {
895
+ delete error.parameters;
896
+ }
897
+ if(error.errors) {
898
+ delete error.errors;
899
+ }
900
+ // @return with some error
901
+ res.status(501).json({
902
+ code: 501,
903
+ status: "DELETE_FAILED",
904
+ mode: {
905
+ debug: false,
906
+ },
907
+ error: error,
908
+ });
909
+ } else {
910
+ // @return with some string error
911
+ res.status(501).json({
912
+ code: 501,
913
+ status: "DELETE_FAILED",
914
+ mode: {
915
+ debug: false,
916
+ },
917
+ error: String(error),
918
+ });
919
+ }
920
+ }
921
+ }
922
+ });
923
+ } catch (error) {
924
+ // @return
925
+ return errMessage(error, res);
926
+ }
927
+ } else {
928
+ // @return
929
+ return errMessage(err, res);
930
+ }
931
+ });
932
+ });
933
+ }
934
+ // resolve it.
935
+ resolve(true);
936
+ }).catch((err) => {
937
+ reject(err);
938
+ });
939
+ }
940
+ });
941
+ } catch (error) {
942
+ reject(error);
943
+ }
944
+ });
945
+ }
946
+
947
+ module.exports = { Base };