beech-api 3.9.0-beta.8-rc → 3.9.57

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.
@@ -2,6 +2,7 @@ const walk = require("walk");
2
2
  const fs = require("fs");
3
3
  const moment = require("moment");
4
4
  const { checkRoleMiddlewareWithDefaultProject } = require("../../cli/core/middleware/express/jwtCheckAllow");
5
+ const { Limiter, Duplicater } = require("../../cli/core/middleware/index");
5
6
 
6
7
  function walkModel(cb) {
7
8
  try {
@@ -390,59 +391,109 @@ async function retrieving(authEndpoint, Projects, req, res, next) {
390
391
  });
391
392
  }
392
393
 
394
+ // Duplicater cache for each config, avoid create new instance with same config
395
+ const duplicaterCache = new Map();
396
+ function getDuplicaterInstance(dupConfig = {}) {
397
+ const key = JSON.stringify(dupConfig || {});
398
+ if (!duplicaterCache.has(key)) {
399
+ duplicaterCache.set(key, Duplicater(dupConfig || {}));
400
+ }
401
+ return duplicaterCache.get(key);
402
+ }
403
+
404
+ // Limiter cache for each config, avoid create new instance with same config
405
+ const limiterCache = new Map();
406
+ function getLimiterInstance(rateConfig = {}) {
407
+ const key = JSON.stringify(rateConfig);
408
+ if (!limiterCache.has(key)) {
409
+ limiterCache.set(key, Limiter(rateConfig));
410
+ }
411
+ return limiterCache.get(key);
412
+ }
413
+
393
414
  const byPassCheckRole = (Projects, method, passport_config) => {
394
415
  return async function (req, res, next) {
395
- if(passport_config[0] !== undefined) {
396
- if(req.params.hash == passport_config[0].replace(/^\/|\/$/g, "")) {
397
- return next();
398
- } else {
399
- if(passport_config[1].jwt_allow === true) {
400
- let leaveMeAlone = await Projects.slice(0);
401
- await filterProjectForByPass(leaveMeAlone, req.originalUrl.replace(_publicPath_, '/'), req, res, async (err, Project) => {
402
- if(!err) {
403
- if(Project.options.defaultEndpoint === undefined || Project.options.defaultEndpoint === true) {
404
- // Project is not use options
405
- return Credentials(req, res, () => {
406
- return checkRoleMiddlewareWithDefaultProject(null)(req, res, next);
407
- });
408
- } else {
409
- // Method is set
410
- if(Project.options.defaultEndpoint[method]) {
411
- if(Project.options.defaultEndpoint[method]["allow"] === undefined || Project.options.defaultEndpoint[method]["allow"] === true) {
412
- if(Project.options.defaultEndpoint[method]["jwt"]?.allow === false) {
413
- // by project jwt_allow is false
414
- return checkRoleMiddlewareWithDefaultProject(null)(req, res, next);
415
- } else {
416
- return Credentials(req, res, () => {
417
- return checkRoleMiddlewareWithDefaultProject(Project.options.defaultEndpoint[method].jwt?.broken_role)(req, res, next);
418
- });
419
- }
416
+ try {
417
+ if(passport_config[0] !== undefined) {
418
+ if(req.params.hash == passport_config[0].replace(/^\/|\/$/g, "")) {
419
+ return next();
420
+ } else {
421
+ if(passport_config[1].jwt_allow === true) {
422
+ let leaveMeAlone = await Projects.slice(0);
423
+ await filterProjectForByPass(leaveMeAlone, req.originalUrl.replace(_publicPath_, '/'), req, res, async (err, Project) => {
424
+ if(!err) {
425
+ // Set Duplicater and Limiter for each project with method
426
+ const dupConfig = (Project.options?.defaultEndpoint?.[method]?.duplicate_request) ? Project.options.defaultEndpoint[method].duplicate_request : {};
427
+ const duplicaterMiddleware = getDuplicaterInstance(dupConfig);
428
+ return duplicaterMiddleware(req, res, (err) => {
429
+ if (!err) {
430
+ const rateConfig = (Project.options?.defaultEndpoint?.[method]?.rate_limit) ? Project.options.defaultEndpoint[method].rate_limit : {};
431
+ const limiterMiddleware = getLimiterInstance(rateConfig);
432
+ limiterMiddleware(req, res, (err) => {
433
+ if (!err) {
434
+ if(Project.options.defaultEndpoint === undefined || Project.options.defaultEndpoint === true) {
435
+ // Project is not use options
436
+ return Credentials(req, res, () => {
437
+ return checkRoleMiddlewareWithDefaultProject(null)(req, res, next);
438
+ });
439
+ } else {
440
+ // Method is set
441
+ if(Project.options.defaultEndpoint[method]) {
442
+ if(Project.options.defaultEndpoint[method]["allow"] === undefined || Project.options.defaultEndpoint[method]["allow"] === true) {
443
+ if(Project.options.defaultEndpoint[method]["jwt"]?.allow === false) {
444
+ // by project jwt_allow is false
445
+ return checkRoleMiddlewareWithDefaultProject(null)(req, res, next);
446
+ } else {
447
+ //return Credentials(req, res, () => {
448
+ // return checkRoleMiddlewareWithDefaultProject(Project.options.defaultEndpoint[method].jwt?.broken_role)(req, res, next);
449
+ //});
450
+ return Credentials(req, res, () => checkRoleMiddlewareWithDefaultProject(Project.options.defaultEndpoint[method].jwt?.broken_role || null)(req, res, next));
451
+ }
452
+ } else {
453
+ // METHOD.allow is false || METHOD.allow is undefined
454
+ return notfound(res);
455
+ }
456
+ } else if(Project.options.defaultEndpoint[method] === true || Project.options.defaultEndpoint[method] === undefined) {
457
+ // Method is not set
458
+ return Credentials(req, res, () => {
459
+ return checkRoleMiddlewareWithDefaultProject(null)(req, res, next);
460
+ });
461
+ } else {
462
+ // METHOD is false || METHOD is not undefined
463
+ return notfound(res);
464
+ }
465
+ }
466
+ } else {
467
+ return res.status(429).json({
468
+ code: 429,
469
+ status: "TOO_MANY_REQUEST",
470
+ message: "Too Many Requests.",
471
+ });
472
+ }
473
+ });
420
474
  } else {
421
- // METHOD.allow is false || METHOD.allow is undefined
422
- return notfound(res);
475
+ return res.status(409).json({
476
+ code: 409,
477
+ status: "DUPLICATE_REQUEST",
478
+ message: "Duplicate request detected.",
479
+ });
423
480
  }
424
- } else if(Project.options.defaultEndpoint[method] === true || Project.options.defaultEndpoint[method] === undefined) {
425
- // Method is not set
426
- return Credentials(req, res, () => {
427
- return checkRoleMiddlewareWithDefaultProject(null)(req, res, next);
428
- });
429
- } else {
430
- // METHOD is false || METHOD is not undefined
431
- return notfound(res);
432
- }
481
+ });
482
+ } else {
483
+ return errMessage(err, res);
433
484
  }
434
- } else {
435
- return errMessage(err, res);
436
- }
437
- });
438
- } else {
439
- // global jwt_allow is false
440
- return next();
485
+ });
486
+ } else {
487
+ // global jwt_allow is false
488
+ return next();
489
+ }
441
490
  }
491
+ } else {
492
+ // passport config not found
493
+ return next();
442
494
  }
443
- } else {
444
- // passport config not found
445
- return next();
495
+ } catch (error) {
496
+ return errMessage(error, res);
446
497
  }
447
498
  }
448
499
  }
@@ -489,58 +540,102 @@ function Base() {
489
540
  // When lost IF
490
541
  let leaveMeAlone = await Projects.slice(0);
491
542
  let reqUrl = req.originalUrl.replace(_publicPath_, '/');
543
+ let bodyIsArray = Array.isArray(req.body);
492
544
  await filterProject(leaveMeAlone, reqUrl, "", "", req, res, async (err, Project) => {
493
545
  if (!err) {
494
546
  try {
495
547
  // Leave pool by project for check pool error
496
548
  let pool = Project.sequelize;
497
- // Store with body
498
- await Project.create(req.body).then((created) => {
499
- // @return
500
- res.status(201).json({
501
- code: 201,
502
- status: "CREATE_SUCCESS",
503
- createdId: (created.id) ? created.id : created[Project.primaryKeyAttributes[0]],
504
- });
505
- }).catch((error) => {
506
- if(pool.options.logging) {
507
- // @return with all error
508
- res.status(501).json({
509
- code: 501,
510
- status: "CREATE_FAILED",
511
- error: error,
512
- });
513
- } else {
514
- if(error.sql) {
515
- delete error.sql;
516
- if(error.errors) {
517
- delete error.errors;
518
- }
519
- if(error.parent) {
520
- delete error.parent;
521
- }
522
- if(error.original) {
523
- delete error.original.sql;
524
- if(error.original.parameters) {
525
- delete error.original.parameters;
526
- }
527
- }
528
- if(error.parameters) {
529
- delete error.parameters;
530
- }
531
- // @return with some error
532
- res.status(501).json({
533
- code: 501,
534
- status: "CREATE_FAILED",
535
- error: error,
549
+ // Transaction create
550
+ Project.transaction(async t => {
551
+ try {
552
+ if (bodyIsArray) {
553
+ // Store with bulk body
554
+ const bulkCreated = await Project.bulkCreate(req.body, { transaction: t });
555
+ await t.commit();
556
+ // @return
557
+ res.status(201).json({
558
+ code: 201,
559
+ status: "CREATE_SUCCESS",
560
+ mode: {
561
+ type: "BULK",
562
+ affectedRows: bulkCreated.length,
563
+ },
564
+ createdId: [
565
+ ...bulkCreated.map(item => (item.id) ? item.id : item[Project.primaryKeyAttributes[0]]),
566
+ ],
536
567
  });
537
568
  } else {
538
- // @return with some string error
569
+ // Store with single body
570
+ const singleCreated = await Project.create(req.body, { transaction: t });
571
+ await t.commit();
572
+ // @return
573
+ res.status(201).json({
574
+ code: 201,
575
+ status: "CREATE_SUCCESS",
576
+ mode: {
577
+ type: "SINGLE",
578
+ affectedRows: 1,
579
+ },
580
+ createdId: (singleCreated.id) ? singleCreated.id : singleCreated[Project.primaryKeyAttributes[0]],
581
+ });
582
+ }
583
+ } catch (error) {
584
+ await t.rollback();
585
+ if(pool.options.logging) {
586
+ // @return with all error
539
587
  res.status(501).json({
540
588
  code: 501,
541
589
  status: "CREATE_FAILED",
542
- error: String(error),
590
+ mode: {
591
+ debug: true,
592
+ type: (bodyIsArray) ? "BULK" : "SINGLE",
593
+ affectedRows: 0,
594
+ },
595
+ error: error,
543
596
  });
597
+ } else {
598
+ if(error.sql) {
599
+ delete error.sql;
600
+ if(error.errors) {
601
+ delete error.errors;
602
+ }
603
+ if(error.parent) {
604
+ delete error.parent;
605
+ }
606
+ if(error.original) {
607
+ delete error.original.sql;
608
+ if(error.original.parameters) {
609
+ delete error.original.parameters;
610
+ }
611
+ }
612
+ if(error.parameters) {
613
+ delete error.parameters;
614
+ }
615
+ // @return with some error
616
+ res.status(501).json({
617
+ code: 501,
618
+ status: "CREATE_FAILED",
619
+ mode: {
620
+ debug: false,
621
+ type: (bodyIsArray) ? "BULK" : "SINGLE",
622
+ affectedRows: 0,
623
+ },
624
+ error: error,
625
+ });
626
+ } else {
627
+ // @return with some string error
628
+ res.status(501).json({
629
+ code: 501,
630
+ status: "CREATE_FAILED",
631
+ mode: {
632
+ debug: false,
633
+ type: (bodyIsArray) ? "BULK" : "SINGLE",
634
+ affectedRows: 0,
635
+ },
636
+ error: String(error),
637
+ });
638
+ }
544
639
  }
545
640
  }
546
641
  });
@@ -562,62 +657,103 @@ function Base() {
562
657
  await filterProject(leaveMeAlone, reqUrl, "", "PATCH", req, res, async (err, Project) => {
563
658
  if (!err) {
564
659
  try {
565
- // Leave pool by project for check pool error
566
- let pool = Project.sequelize;
567
- // Assign update pk
568
- let updatePk = { [Project.primaryKeyAttributes[0]]: req.params.id };
569
- // Patch with body
570
- await Project.update(req.body, {
571
- where: updatePk,
572
- }).then((updated) => {
573
- // @return
574
- res.status(200).json({
575
- code: 200,
576
- status: "UPDATE_SUCCESS",
577
- result: {
578
- updateId: req.params.id,
579
- affectedRows: updated[0],
660
+ // Check body is empty
661
+ if(Object.keys(req.body).length === 0) {
662
+ return res.status(400).json({
663
+ code: 400,
664
+ status: "BAD_REQUEST",
665
+ message: "Bad request.",
666
+ info: {
667
+ status: "BAD_ENTIRY",
668
+ message: "Unprocessable Entity.",
580
669
  },
581
670
  });
582
- }).catch((error) => {
583
- if(pool.options.logging) {
584
- // @return with all error
585
- res.status(501).json({
586
- code: 501,
587
- status: "UPDATE_FAILED",
588
- error: error,
589
- });
590
- } else {
591
- if(error.sql) {
592
- delete error.sql;
593
- if(error.parent) {
594
- delete error.parent;
595
- }
596
- if(error.original) {
597
- delete error.original.sql;
598
- if(error.original.parameters) {
599
- delete error.original.parameters;
600
- }
601
- }
602
- if(error.parameters) {
603
- delete error.parameters;
604
- }
605
- if(error.errors) {
606
- delete error.errors;
607
- }
608
- // @return with some error
609
- res.status(501).json({
610
- code: 501,
611
- status: "UPDATE_FAILED",
612
- error: error,
671
+ }
672
+ // Leave pool by project for check pool error
673
+ let pool = Project.sequelize;
674
+ // Transaction update|patch
675
+ Project.transaction(async t => {
676
+ try {
677
+ // Assign update pk
678
+ let updatePk = { [Project.primaryKeyAttributes[0]]: req.params.id };
679
+ // Patch with body
680
+ const updated = await Project.update(req.body, {
681
+ where: updatePk,
682
+ }, { transaction: t });
683
+ if(updated[0]) {
684
+ await t.commit();
685
+ // @return
686
+ res.status(200).json({
687
+ code: 200,
688
+ status: "UPDATE_SUCCESS",
689
+ mode: {
690
+ debug: true,
691
+ },
692
+ result: {
693
+ updateId: req.params.id,
694
+ affectedRows: updated[0],
695
+ },
613
696
  });
614
697
  } else {
615
- // @return with some string error
698
+ await t.rollback();
699
+ res.status(406).json({
700
+ code: 406,
701
+ status: "NOT_ACCEPTABLE",
702
+ result: {
703
+ affectedRows: updated[0],
704
+ },
705
+ });
706
+ }
707
+ } catch (error) {
708
+ await t.rollback();
709
+ if(pool.options.logging) {
710
+ // @return with all error
616
711
  res.status(501).json({
617
712
  code: 501,
618
713
  status: "UPDATE_FAILED",
619
- error: String(error),
714
+ mode: {
715
+ debug: false,
716
+ },
717
+ error: error,
620
718
  });
719
+ } else {
720
+ if(error.sql) {
721
+ delete error.sql;
722
+ if(error.parent) {
723
+ delete error.parent;
724
+ }
725
+ if(error.original) {
726
+ delete error.original.sql;
727
+ if(error.original.parameters) {
728
+ delete error.original.parameters;
729
+ }
730
+ }
731
+ if(error.parameters) {
732
+ delete error.parameters;
733
+ }
734
+ if(error.errors) {
735
+ delete error.errors;
736
+ }
737
+ // @return with some error
738
+ res.status(501).json({
739
+ code: 501,
740
+ status: "UPDATE_FAILED",
741
+ mode: {
742
+ debug: false,
743
+ },
744
+ error: error,
745
+ });
746
+ } else {
747
+ // @return with some string error
748
+ res.status(501).json({
749
+ code: 501,
750
+ status: "UPDATE_FAILED",
751
+ mode: {
752
+ debug: false,
753
+ },
754
+ error: String(error),
755
+ });
756
+ }
621
757
  }
622
758
  }
623
759
  });
@@ -640,71 +776,85 @@ function Base() {
640
776
  try {
641
777
  // Leave pool by project for check pool error
642
778
  let pool = Project.sequelize;
643
- // Assign delete pk
644
- let deletePk = { [Project.primaryKeyAttributes[0]]: req.params.id };
645
- // Delete with params
646
- await Project.destroy({
647
- where: deletePk,
648
- }).then((deleted) => {
649
- if (deleted) {
650
- // @return
651
- res.status(200).json({
652
- code: 200,
653
- status: "DELETE_SUCCESS",
654
- result: {
655
- deleteId: req.params.id,
656
- affectedRows: deleted,
657
- },
658
- });
659
- } else {
660
- res.status(406).json({
661
- code: 406,
662
- status: "NOT_ACCEPTABLE",
663
- result: {
664
- deleteId: req.params.id,
665
- affectedRows: deleted,
666
- },
667
- });
668
- }
669
- }).catch((error) => {
670
- if(pool.options.logging) {
671
- // @return with all error
672
- res.status(501).json({
673
- code: 501,
674
- status: "DELETE_FAILED",
675
- error: error,
676
- });
677
- } else {
678
- if(error.sql) {
679
- delete error.sql;
680
- if(error.parent) {
681
- delete error.parent;
682
- }
683
- if(error.original) {
684
- delete error.original.sql;
685
- if(error.original.parameters) {
686
- delete error.original.parameters;
687
- }
688
- }
689
- if(error.parameters) {
690
- delete error.parameters;
691
- }
692
- if(error.errors) {
693
- delete error.errors;
694
- }
695
- // @return with some error
696
- res.status(501).json({
697
- code: 501,
698
- status: "DELETE_FAILED",
699
- error: error,
779
+ // Transaction update|patch
780
+ Project.transaction(async t => {
781
+ try {
782
+ // Assign delete pk
783
+ let deletePk = { [Project.primaryKeyAttributes[0]]: req.params.id };
784
+ // Delete with params
785
+ const deleted = await Project.destroy({
786
+ where: deletePk,
787
+ }, { transaction: t });
788
+ if (deleted) {
789
+ await t.commit();
790
+ // @return
791
+ res.status(200).json({
792
+ code: 200,
793
+ status: "DELETE_SUCCESS",
794
+ result: {
795
+ deleteId: req.params.id,
796
+ affectedRows: deleted,
797
+ },
700
798
  });
701
799
  } else {
702
- // @return with some string error
800
+ await t.rollback();
801
+ res.status(406).json({
802
+ code: 406,
803
+ status: "NOT_ACCEPTABLE",
804
+ result: {
805
+ affectedRows: deleted,
806
+ },
807
+ });
808
+ }
809
+ } catch (error) {
810
+ if(pool.options.logging) {
811
+ // @return with all error
703
812
  res.status(501).json({
704
813
  code: 501,
705
814
  status: "DELETE_FAILED",
706
- error: String(error),
815
+ mode: {
816
+ debug: true,
817
+ },
818
+ error: error,
707
819
  });
820
+ } else {
821
+ if(error.sql) {
822
+ delete error.sql;
823
+ if(error.parent) {
824
+ delete error.parent;
825
+ }
826
+ if(error.original) {
827
+ delete error.original.sql;
828
+ if(error.original.parameters) {
829
+ delete error.original.parameters;
830
+ }
831
+ }
832
+ if(error.parameters) {
833
+ delete error.parameters;
834
+ }
835
+ if(error.errors) {
836
+ delete error.errors;
837
+ }
838
+ // @return with some error
839
+ res.status(501).json({
840
+ code: 501,
841
+ status: "DELETE_FAILED",
842
+ mode: {
843
+ debug: false,
844
+ },
845
+ error: error,
846
+ });
847
+ } else {
848
+ // @return with some string error
849
+ res.status(501).json({
850
+ code: 501,
851
+ status: "DELETE_FAILED",
852
+ mode: {
853
+ debug: false,
854
+ },
855
+ error: String(error),
856
+ });
857
+ }
708
858
  }
709
859
  }
710
860
  });