From b7e852126c5c178257a7f762e5b60cfa9a62cb08 Mon Sep 17 00:00:00 2001 From: meusinfirmary Date: Tue, 22 Apr 2025 14:31:37 +0700 Subject: [PATCH] Initial commit --- .env | 85 + .env.dev | 92 + .env.example | 22 + .env.local | 75 + .env.prod | 78 + .gitignore | 7 + Dockerfile | 9 + Message Notifikasi Apps Driver Tracker.xlsx | Bin 0 -> 10887 bytes README.MD | 0 abcd.json | 2902 ++++++++++++++ app.js | 567 +++ app.js.express | 51 + app.js.gps | 98 + app_dev_restapi.js | 26 + app_scheduler.js | 33 + backup/.gitignore | 1 + config/dbMysqlConn.js | 41 + config/netConn.js | 3 + config/request.js | 22 + config/response.js | 95 + controllers/AuthController.js | 167 + controllers/DummyController.js | 165 + controllers/OrderController.js | 821 ++++ controllers/ServiceDriverController.js | 2610 +++++++++++++ controllers/WorkerController.js | 564 +++ controllers/ZoneController.js | 134 + docker-compose.yml | 39 + ...er-firebase-adminsdk-7tcet-7399bbf4fc.json | 12 + ...er-firebase-adminsdk-7tcet-c817089752.json | 12 + files/keys/google-services.json | 40 + files/mails/admInfoOrder.ejs | 70 + files/mails/adminInfoNoVdrAccOrd.ejs | 70 + files/mails/bidOrderMail.ejs | 98 + files/mails/clientCreateOrd.ejs | 86 + files/mails/clientOrdHaveBeenAccMail.ejs | 107 + files/mails/driverGetOrderMail.ejs | 80 + files/mails/financeInfoDanaAmount.ejs | 46 + files/mails/financeInfoTfPocket.ejs | 88 + files/mails/template/end.ejs | 48 + files/mails/template/start.ejs | 356 ++ files/mails/vdrAccOrderMail.ejs | 95 + files/mails/zoningMail.ejs | 52 + files/public/OpenSans-B9K8.ttf | Bin 0 -> 217360 bytes .../NVCrVnY_km5eldKtXvghZGtF.ttf_0.png | Bin 0 -> 73387 bytes .../OpenSans-B9K8.ttf_neon_100/neon_100.fnt | 99 + .../FWd0hhbQQsviQcgc8vksJ1t0.ttf_0.png | Bin 0 -> 8652 bytes .../OpenSans-B9K8.ttf_neon_16/neon_16.fnt | 99 + .../MlLA3aDGaXpxSgao3dSOGIYD.ttf_0.png | Bin 0 -> 19037 bytes .../OpenSans-B9K8.ttf_neon_32/neon_32.fnt | 99 + .../0cqXNM8gYrt7OJ5mzJ_o3PUe.ttf_0.png | Bin 0 -> 42582 bytes .../OpenSans-B9K8.ttf_neon_64/neon_64.fnt | 99 + files/public/img_white_bg.png | Bin 0 -> 84147 bytes library/LibBullAdapter.js | 38 + library/LibCurl.js | 300 ++ library/LibDevice.js | 573 +++ library/LibFile.js | 45 + library/LibFirebase.js | 72 + library/LibHelper.js | 97 + library/LibImgGeotagging.js | 140 + library/LibJwt.js | 55 + library/LibLogReqResApi.js | 28 + library/LibMail.js | 1163 ++++++ library/LibMysqlHelper.js | 206 + library/LibPassword.js | 39 + library/LibQueueBlastOrder.js | 82 + library/LibRedisConn.js | 9 + library/LibSchedulerDrvBlastNotif.js | 93 + library/LibSchedulerDrvUpLoc.js | 93 + library/LibSchedulerDrvUpLocIdle.js | 93 + library/LibSchedulerDrvUpPhoto.js | 93 + library/LibSchedulerGpsTrackerWakeUp.js | 133 + library/LibSchedulerReverseGeocode.js | 93 + library/LibWinston.js | 53 + middleware/AuthDriverMiddleware.js | 37 + middleware/AuthDriverMiddlewareNotStrict.js | 26 + middleware/AuthMiddleware.js | 32 + middleware/MorganMiddleware.js | 17 + models/DanaModels.js | 80 + models/DriversModels.js | 295 ++ models/DummyModels.js | 214 ++ models/GpsTracksModels.js | 596 +++ models/LogbookKeysModels.js | 155 + models/LogbookOrdersModels.js | 144 + models/LogbookTypesModels.js | 144 + models/LogsSchNotifModels.js | 91 + models/OrdersAItemsModels.js | 88 + models/OrdersCheckpointsModels.js | 120 + models/OrdersDriversUploadsModels.js | 68 + models/OrdersDropsModels.js | 36 + models/OrdersLogsTfModels.js | 129 + models/OrdersModels.js | 702 ++++ models/OrdersPckDropsModels.js | 90 + models/OrdersPickupsModels.js | 36 + models/OrdersTerminsModels.js | 121 + models/OrdersVendorsModels.js | 277 ++ models/PatientsStatusModels.js | 85 + models/RegionModels.js | 57 + models/UsersModels.js | 121 + models/VhcModels.js | 101 + models/ZoneModels.js | 313 ++ package-lock.json | 3357 +++++++++++++++++ package.json | 44 + response_api_driver.md | 490 +++ routes/ServiceDriverRoute.js | 49 + routes/routes.js | 47 + routes/routes_without_scheduler.js | 47 + test.js | 50 + test_device.js | 121 + workers/BlastOrderWorker.js | 137 + workers/BlastOrderWorkerBAK.js | 117 + workers/DrvBlastNotifWorker.js | 75 + workers/DrvUpLocIdleWorker.js | 116 + workers/DrvUpLocWorker.js | 137 + workers/DrvUpPhotoWorker.js | 107 + workers/ReverseGeocodeWorker.js | 258 ++ 115 files changed, 23188 insertions(+) create mode 100755 .env create mode 100755 .env.dev create mode 100644 .env.example create mode 100755 .env.local create mode 100755 .env.prod create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 Message Notifikasi Apps Driver Tracker.xlsx create mode 100644 README.MD create mode 100644 abcd.json create mode 100644 app.js create mode 100644 app.js.express create mode 100644 app.js.gps create mode 100644 app_dev_restapi.js create mode 100644 app_scheduler.js create mode 100644 backup/.gitignore create mode 100644 config/dbMysqlConn.js create mode 100644 config/netConn.js create mode 100644 config/request.js create mode 100644 config/response.js create mode 100644 controllers/AuthController.js create mode 100644 controllers/DummyController.js create mode 100644 controllers/OrderController.js create mode 100644 controllers/ServiceDriverController.js create mode 100644 controllers/WorkerController.js create mode 100644 controllers/ZoneController.js create mode 100644 docker-compose.yml create mode 100644 files/keys/bingcorp-tracker-firebase-adminsdk-7tcet-7399bbf4fc.json create mode 100644 files/keys/bingcorp-tracker-firebase-adminsdk-7tcet-c817089752.json create mode 100644 files/keys/google-services.json create mode 100644 files/mails/admInfoOrder.ejs create mode 100644 files/mails/adminInfoNoVdrAccOrd.ejs create mode 100644 files/mails/bidOrderMail.ejs create mode 100644 files/mails/clientCreateOrd.ejs create mode 100644 files/mails/clientOrdHaveBeenAccMail.ejs create mode 100644 files/mails/driverGetOrderMail.ejs create mode 100644 files/mails/financeInfoDanaAmount.ejs create mode 100644 files/mails/financeInfoTfPocket.ejs create mode 100644 files/mails/template/end.ejs create mode 100644 files/mails/template/start.ejs create mode 100644 files/mails/vdrAccOrderMail.ejs create mode 100644 files/mails/zoningMail.ejs create mode 100644 files/public/OpenSans-B9K8.ttf create mode 100644 files/public/OpenSans-B9K8.ttf_neon_100/NVCrVnY_km5eldKtXvghZGtF.ttf_0.png create mode 100644 files/public/OpenSans-B9K8.ttf_neon_100/neon_100.fnt create mode 100644 files/public/OpenSans-B9K8.ttf_neon_16/FWd0hhbQQsviQcgc8vksJ1t0.ttf_0.png create mode 100644 files/public/OpenSans-B9K8.ttf_neon_16/neon_16.fnt create mode 100644 files/public/OpenSans-B9K8.ttf_neon_32/MlLA3aDGaXpxSgao3dSOGIYD.ttf_0.png create mode 100644 files/public/OpenSans-B9K8.ttf_neon_32/neon_32.fnt create mode 100644 files/public/OpenSans-B9K8.ttf_neon_64/0cqXNM8gYrt7OJ5mzJ_o3PUe.ttf_0.png create mode 100644 files/public/OpenSans-B9K8.ttf_neon_64/neon_64.fnt create mode 100644 files/public/img_white_bg.png create mode 100644 library/LibBullAdapter.js create mode 100644 library/LibCurl.js create mode 100644 library/LibDevice.js create mode 100644 library/LibFile.js create mode 100644 library/LibFirebase.js create mode 100644 library/LibHelper.js create mode 100644 library/LibImgGeotagging.js create mode 100644 library/LibJwt.js create mode 100644 library/LibLogReqResApi.js create mode 100644 library/LibMail.js create mode 100644 library/LibMysqlHelper.js create mode 100644 library/LibPassword.js create mode 100644 library/LibQueueBlastOrder.js create mode 100644 library/LibRedisConn.js create mode 100644 library/LibSchedulerDrvBlastNotif.js create mode 100644 library/LibSchedulerDrvUpLoc.js create mode 100644 library/LibSchedulerDrvUpLocIdle.js create mode 100644 library/LibSchedulerDrvUpPhoto.js create mode 100644 library/LibSchedulerGpsTrackerWakeUp.js create mode 100644 library/LibSchedulerReverseGeocode.js create mode 100644 library/LibWinston.js create mode 100644 middleware/AuthDriverMiddleware.js create mode 100644 middleware/AuthDriverMiddlewareNotStrict.js create mode 100644 middleware/AuthMiddleware.js create mode 100644 middleware/MorganMiddleware.js create mode 100644 models/DanaModels.js create mode 100644 models/DriversModels.js create mode 100644 models/DummyModels.js create mode 100644 models/GpsTracksModels.js create mode 100644 models/LogbookKeysModels.js create mode 100644 models/LogbookOrdersModels.js create mode 100644 models/LogbookTypesModels.js create mode 100644 models/LogsSchNotifModels.js create mode 100644 models/OrdersAItemsModels.js create mode 100644 models/OrdersCheckpointsModels.js create mode 100644 models/OrdersDriversUploadsModels.js create mode 100644 models/OrdersDropsModels.js create mode 100644 models/OrdersLogsTfModels.js create mode 100644 models/OrdersModels.js create mode 100644 models/OrdersPckDropsModels.js create mode 100644 models/OrdersPickupsModels.js create mode 100644 models/OrdersTerminsModels.js create mode 100644 models/OrdersVendorsModels.js create mode 100644 models/PatientsStatusModels.js create mode 100644 models/RegionModels.js create mode 100644 models/UsersModels.js create mode 100644 models/VhcModels.js create mode 100644 models/ZoneModels.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 response_api_driver.md create mode 100644 routes/ServiceDriverRoute.js create mode 100644 routes/routes.js create mode 100644 routes/routes_without_scheduler.js create mode 100644 test.js create mode 100644 test_device.js create mode 100644 workers/BlastOrderWorker.js create mode 100644 workers/BlastOrderWorkerBAK.js create mode 100644 workers/DrvBlastNotifWorker.js create mode 100644 workers/DrvUpLocIdleWorker.js create mode 100644 workers/DrvUpLocWorker.js create mode 100644 workers/DrvUpPhotoWorker.js create mode 100644 workers/ReverseGeocodeWorker.js diff --git a/.env b/.env new file mode 100755 index 0000000..d30fb19 --- /dev/null +++ b/.env @@ -0,0 +1,85 @@ +# APP CONFIG +PORT=6014 +PORT_EXPRESS=3400 +PORT_UDP=20203 +# NODE_ENV=development +NODE_ENV=production +API_VERSION=1 +PATH_URL=/tracking +TZ=Asia/Jakarta + +# DATABASE CONFIG +# CONNECTIONLIMIT=10 +# # DBHOST=149.129.214.64 +# DBHOST=8.215.31.239 +# DBUSER=root +# DBPASSWORD=vYR/+QHD4lJ8y/v2 +# DATABASE=db_trucking +# ACQRTIMEOUT=10000 + +# DATABASE CONFIG BONCENG(mariadb) +# CONNECTIONLIMIT=10 +# DBHOST=147.139.133.230 +# DBUSER=boncengdball +# DBPASSWORD=rtzL8NI4TchNNwu7 +# DATABASE=db_trucking +# ACQRTIMEOUT=10000 + +# DATABASE CONFIG BONCENG(mariadb 10.7) +CONNECTIONLIMIT=10 +DBHOST=127.0.0.1 +DBUSER=root +DBPASSWORD=root +DATABASE=db_fleet +ACQRTIMEOUT=10000 + +# REDIS CONFIG +# if using local system +# REDIS_HOST=localhost +# if using docker +REDIS_HOST=redis +REDIS_PORT=6379 +REDIS_SCHEDULER_REVERSE_GEO=scheduleReverseGeocode +REDIS_QUEUE_BLAST_ORDER=queueBlastOrder +REDIS_SCHEDULER_DRV_UP_LOC=scheduleDrvUpLoc +REDIS_SCHEDULER_DRV_UP_PHOTO=scheduleDrvUpPhoto +REDIS_SCHEDULER_DRV_UP_LOC_IDLE=scheduleDrvUpLocIdle +REDIS_SCHEDULER_DRV_BLAST_NOTIF=schedulerDrvBlastNotif +REDIS_SCHEDULER_GPS_TRACKER_WAKEUP=schedulerGpsTrackerWakeUp + +# SMTP MAILTRAP RAFIF +SMTP_HOST=smtp.mailtrap.io +SMTP_PORT=2525 +SMTP_USER=e9aace0ebb3398 +SMTP_PASW=c8f9ccee5122d6 +SMTP_FROM=rafifrest@gmail.com + +# SMTP BONCENG NO REPLY +# SMTP_HOST=bagaspati.iixcp.rumahweb.com +# SMTP_PORT=465 +# SMTP_USER=non-reply@bonceng-indonesia.com +# SMTP_PASW=eGgKSpJAuv1p +# SMTP_FROM=non-reply@bonceng-indonesia.com + +# SCHEDULER BULLMQ CONFIG (CUSTOM) +# sekali jalan maximal looping +SCHEDULE_REVERSE_GEO_MAX_LOOP=10 +SCHEDULE_REVERSE_GEO_TIME=*/2 * * * * +SCHEDULE_DRV_UP_LOC_MAX_LOOP=1 +SCHEDULE_DRV_UP_LOC_TIME=*/1 * * * * +SCHEDULE_DRV_UP_PHOTO_MAX_LOOP=1 +SCHEDULE_DRV_UP_PHOTO_TIME=0 */1 * * * +SCHEDULE_DRV_UP_LOC_IDLE_MAX_LOOP=1 +SCHEDULE_DRV_UP_LOC_IDLE_TIME=0 */5 * * * +SCHEDULE_DRV_BLAST_NOTIF_MAX_LOOP=1 +SCHEDULE_DRV_BLAST_NOTIF_TIME=0 */6 * * * +SCHEDULE_GPS_TRACKER_WAKEUP_MAX_LOOP=1 +SCHEDULE_GPS_TRACKER_WAKEUP_TIME=*/1 * * * * + +CS_MAIL=customer-service@bonceng-indonesia.com +CS_PHONE=082123622686 +CS_ADDR='Jalan RC Veteran 11A, Rempoa, Bintaro, Pesanggrahan, Kota Jakarta Selatan 12330' +MAIL_ASSET=http://149.129.214.64/fms_dev/mails/v0/assets/ + +FMS_URL=http://149.129.214.64/fms_dev/ +API_DANA_BINGCORP=http://api.simerahputih.com/dana_bingcorp/ \ No newline at end of file diff --git a/.env.dev b/.env.dev new file mode 100755 index 0000000..4a7a123 --- /dev/null +++ b/.env.dev @@ -0,0 +1,92 @@ +# APP CONFIG +PORT=6014 +PORT_EXPRESS=3200 +PORT_UDP=20203 +NODE_ENV=development +# NODE_ENV=production +API_VERSION=1 +PATH_URL=/tracking_dev +TZ=Asia/Jakarta + +# DATABASE CONFIG +# GAJADI DIPAKE, St_Distance_Sphere gaada diversion maria db server dev +# CONNECTIONLIMIT=10 +# DBHOST=117.53.46.186 +# DBUSER=development +# DBPASSWORD=MAN[7Dpzn[ +# DATABASE=db_trucking +# ACQRTIMEOUT=10000 +# CONNECTIONLIMIT=10 +# # DBHOST=149.129.214.64 +# DBHOST=8.215.31.239 +# DBUSER=root +# DBPASSWORD=vYR/+QHD4lJ8y/v2 +# DATABASE=db_trucking_dev +# ACQRTIMEOUT=10000 + +# DATABASE CONFIG BONCENG(mariadb) +# CONNECTIONLIMIT=10 +# DBHOST=147.139.133.230 +# DBUSER=boncengdball +# DBPASSWORD=rtzL8NI4TchNNwu7 +# DATABASE=db_trucking_dev +# ACQRTIMEOUT=10000 + +# DATABASE CONFIG BONCENG(mariadb 10.7) +CONNECTIONLIMIT=10 +DBHOST=149.129.244.66 +DBUSER=all +DBPASSWORD=UC90vjAQG0w= +DATABASE=db_trucking_dev +ACQRTIMEOUT=10000 + +# REDIS CONFIG +# if using local system +REDIS_HOST=localhost +# if using docker +# REDIS_HOST=redis +REDIS_PORT=6379 +REDIS_SCHEDULER_REVERSE_GEO=scheduleReverseGeocode_dev +REDIS_QUEUE_BLAST_ORDER=queueBlastOrder_dev +REDIS_SCHEDULER_DRV_UP_LOC=scheduleDrvUpLoc_dev +REDIS_SCHEDULER_DRV_UP_PHOTO=scheduleDrvUpPhoto_dev +REDIS_SCHEDULER_DRV_UP_LOC_IDLE=scheduleDrvUpLocIdle_dev +REDIS_SCHEDULER_DRV_BLAST_NOTIF=schedulerDrvBlastNotif_dev +REDIS_SCHEDULER_GPS_TRACKER_WAKEUP=schedulerGpsTrackerWakeUp_dev + +# SMTP BONCENG NO REPLY +# SMTP_HOST=bagaspati.iixcp.rumahweb.com +# SMTP_PORT=465 +# SMTP_USER=non-reply@bonceng-indonesia.com +# SMTP_PASW=eGgKSpJAuv1p +# SMTP_FROM=non-reply@bonceng-indonesia.com + +# SMTP MAILTRAP RAFIF +SMTP_HOST=smtp.mailtrap.io +SMTP_PORT=2525 +SMTP_USER=e9aace0ebb3398 +SMTP_PASW=c8f9ccee5122d6 +SMTP_FROM=rafifrest@gmail.com + +# SCHEDULER BULLMQ CONFIG (CUSTOM) +# sekali jalan maximal looping +SCHEDULE_REVERSE_GEO_MAX_LOOP=10 +SCHEDULE_REVERSE_GEO_TIME=*/2 * * * * +SCHEDULE_DRV_UP_LOC_MAX_LOOP=1 +SCHEDULE_DRV_UP_LOC_TIME=*/1 * * * * +SCHEDULE_DRV_UP_PHOTO_MAX_LOOP=1 +SCHEDULE_DRV_UP_PHOTO_TIME=0 */1 * * * +SCHEDULE_DRV_UP_LOC_IDLE_MAX_LOOP=1 +SCHEDULE_DRV_UP_LOC_IDLE_TIME=0 */5 * * * +SCHEDULE_DRV_BLAST_NOTIF_MAX_LOOP=1 +SCHEDULE_DRV_BLAST_NOTIF_TIME=0 */1 * * * +SCHEDULE_GPS_TRACKER_WAKEUP_MAX_LOOP=1 +SCHEDULE_GPS_TRACKER_WAKEUP_TIME=*/1 * * * * + +CS_MAIL=customer-service@bonceng-indonesia.com +CS_PHONE=082123622686 +CS_ADDR='Jalan RC Veteran 11A, Rempoa, Bintaro, Pesanggrahan, Kota Jakarta Selatan 12330' +MAIL_ASSET=http://149.129.214.64/fms_dev/mails/v0/assets/ + +FMS_URL=http://149.129.214.64/fms_dev/ +API_DANA_BINGCORP=http://api.simerahputih.com/dana_bingcorp/ \ No newline at end of file diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..c80d248 --- /dev/null +++ b/.env.example @@ -0,0 +1,22 @@ +# APP CONFIG +PORT=6014 +PORT_EXPRESS=3400 +NODE_ENV=development +# NODE_ENV=production +API_VERSION=1 +TZ=Asia/Jakarta + +# DATABASE CONFIG +CONNECTIONLIMIT=10 +DBHOST=localhost +DBUSER=local +DBPASSWORD= +DATABASE=db_trucking +ACQRTIMEOUT=10000 + +# REDIS CONFIG +# if using local system +# REDIS_HOST=localhost +# if using docker +REDIS_HOST=redis +REDIS_PORT=6379 \ No newline at end of file diff --git a/.env.local b/.env.local new file mode 100755 index 0000000..3039c6b --- /dev/null +++ b/.env.local @@ -0,0 +1,75 @@ +# APP CONFIG +PORT=6014 +PORT_EXPRESS=3400 +PORT_UDP=20203 +NODE_ENV=development +# NODE_ENV=production +API_VERSION=1 +PATH_URL=/trucking +TZ=Asia/Jakarta + +# DATABASE CONFIG LOCAL +# CONNECTIONLIMIT=10 +# # DBHOST=192.168.68.148 +# DBHOST=192.168.43.109 +# DBUSER=root +# DBPASSWORD=root +# DATABASE=db_trucking +# ACQRTIMEOUT=10000 +# # DATABASE CONFIG DEV +# # CONNECTIONLIMIT=10 +# # DBHOST=149.129.214.64 +# # DBUSER=root +# # DBPASSWORD=vYR/+QHD4lJ8y/v2 +# # DATABASE=db_trucking_dev +# # ACQRTIMEOUT=10000 + +# DATABASE CONFIG BONCENG(mariadb) +CONNECTIONLIMIT=10 +DBHOST=147.139.133.230 +DBUSER=boncengdball +DBPASSWORD=rtzL8NI4TchNNwu7 +DATABASE=db_trucking_dev +ACQRTIMEOUT=10000 + +# REDIS CONFIG +# if using local system +# REDIS_HOST=localhost +# if using docker +REDIS_HOST=redis +REDIS_PORT=6379 +REDIS_SCHEDULER_REVERSE_GEO=scheduleReverseGeocode +REDIS_QUEUE_BLAST_ORDER=queueBlastOrder +REDIS_SCHEDULER_DRV_UP_LOC=scheduleDrvUpLoc +REDIS_SCHEDULER_DRV_UP_PHOTO=scheduleDrvUpPhoto +REDIS_SCHEDULER_DRV_UP_LOC_IDLE=scheduleDrvUpLocIdle +REDIS_SCHEDULER_GPS_TRACKER_WAKEUP=schedulerGpsTrackerWakeUp + +# SMTP MAILTRAP RAFIF +SMTP_HOST=smtp.mailtrap.io +SMTP_PORT=2525 +SMTP_USER=e9aace0ebb3398 +SMTP_PASW=c8f9ccee5122d6 +SMTP_FROM=rafifrest@gmail.com + +# SCHEDULER BULLMQ CONFIG (CUSTOM) +# sekali jalan maximal looping +SCHEDULE_REVERSE_GEO_MAX_LOOP=10 +SCHEDULE_REVERSE_GEO_TIME=*/2 * * * * +SCHEDULE_DRV_UP_LOC_MAX_LOOP=1 +SCHEDULE_DRV_UP_LOC_TIME=*/5 * * * * +SCHEDULE_DRV_UP_PHOTO_MAX_LOOP=1 +SCHEDULE_DRV_UP_PHOTO_TIME=0 */1 * * * +SCHEDULE_DRV_UP_LOC_IDLE_MAX_LOOP=1 +SCHEDULE_DRV_UP_LOC_IDLE_TIME=0 */1 * * * +SCHEDULE_GPS_TRACKER_WAKEUP_MAX_LOOP=1 +SCHEDULE_GPS_TRACKER_WAKEUP_TIME=*/1 * * * * + +CS_MAIL=customer-service@bonceng-indonesia.com +CS_PHONE=082123622686 +CS_ADDR='Jalan RC Veteran 11A, Rempoa, Bintaro, Pesanggrahan, Kota Jakarta Selatan 12330' +MAIL_ASSET=http://117.53.46.186/trucking-app/mails/v0/assets/ + +# FMS_URL=http://149.129.214.64/fms_dev/ +FMS_URL=http://192.168.68.105:5000/trucking/ +API_DANA_BINGCORP=http://api.simerahputih.com/dana_bingcorp/ \ No newline at end of file diff --git a/.env.prod b/.env.prod new file mode 100755 index 0000000..ac34824 --- /dev/null +++ b/.env.prod @@ -0,0 +1,78 @@ +# APP CONFIG +PORT=6014 +PORT_EXPRESS=3400 +PORT_UDP=20203 +# NODE_ENV=development +NODE_ENV=production +API_VERSION=1 +PATH_URL=/tracking +TZ=Asia/Jakarta + +# DATABASE CONFIG +# CONNECTIONLIMIT=10 +# # DBHOST=149.129.214.64 +# DBHOST=8.215.31.239 +# DBUSER=root +# DBPASSWORD=vYR/+QHD4lJ8y/v2 +# DATABASE=db_trucking +# ACQRTIMEOUT=10000 + +# DATABASE CONFIG BONCENG(mariadb) +# CONNECTIONLIMIT=10 +# DBHOST=147.139.133.230 +# DBUSER=boncengdball +# DBPASSWORD=rtzL8NI4TchNNwu7 +# DATABASE=db_trucking +# ACQRTIMEOUT=10000 + +# DATABASE CONFIG BONCENG(mariadb 10.7) +CONNECTIONLIMIT=10 +DBHOST=149.129.244.66 +DBUSER=all +DBPASSWORD=UC90vjAQG0w= +DATABASE=db_trucking +ACQRTIMEOUT=10000 + +# REDIS CONFIG +# if using local system +REDIS_HOST=localhost +# if using docker +# REDIS_HOST=redis +REDIS_PORT=6379 +REDIS_SCHEDULER_REVERSE_GEO=scheduleReverseGeocode +REDIS_QUEUE_BLAST_ORDER=queueBlastOrder +REDIS_SCHEDULER_DRV_UP_LOC=scheduleDrvUpLoc +REDIS_SCHEDULER_DRV_UP_PHOTO=scheduleDrvUpPhoto +REDIS_SCHEDULER_DRV_UP_LOC_IDLE=scheduleDrvUpLocIdle +REDIS_SCHEDULER_DRV_BLAST_NOTIF=schedulerDrvBlastNotif +REDIS_SCHEDULER_GPS_TRACKER_WAKEUP=schedulerGpsTrackerWakeUp + +# SMTP BONCENG NO REPLY +SMTP_HOST=bagaspati.iixcp.rumahweb.com +SMTP_PORT=465 +SMTP_USER=non-reply@bonceng-indonesia.com +SMTP_PASW=eGgKSpJAuv1p +SMTP_FROM=non-reply@bonceng-indonesia.com + +# SCHEDULER BULLMQ CONFIG (CUSTOM) +# sekali jalan maximal looping +SCHEDULE_REVERSE_GEO_MAX_LOOP=20 +SCHEDULE_REVERSE_GEO_TIME=*/2 * * * * +SCHEDULE_DRV_UP_LOC_MAX_LOOP=1 +SCHEDULE_DRV_UP_LOC_TIME=*/1 * * * * +SCHEDULE_DRV_UP_PHOTO_MAX_LOOP=1 +SCHEDULE_DRV_UP_PHOTO_TIME=0 */1 * * * +SCHEDULE_DRV_UP_LOC_IDLE_MAX_LOOP=1 +SCHEDULE_DRV_UP_LOC_IDLE_TIME=0 */5 * * * +SCHEDULE_DRV_BLAST_NOTIF_MAX_LOOP=1 +SCHEDULE_DRV_BLAST_NOTIF_TIME=0 */6 * * * +SCHEDULE_GPS_TRACKER_WAKEUP_MAX_LOOP=1 +SCHEDULE_GPS_TRACKER_WAKEUP_TIME=*/1 * * * * + +CS_MAIL=customer-service@bonceng-indonesia.com +CS_PHONE=082123622686 +CS_ADDR='Jalan RC Veteran 11A, Rempoa, Bintaro, Pesanggrahan, Kota Jakarta Selatan 12330' +MAIL_ASSET=https://bingkis-corporate.com/fms/mails/v0/assets/ + +FMS_URL=https://bingkis-corporate.com/fms/ +API_DANA_BINGCORP=http://api.simerahputih.com/dana_bingcorp/ \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e6d0e13 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +node_modules/ +logs/ +# .env +# .env.* +.vscode +.DS_Store +files/storage \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b98a930 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM node:12-alpine as base + +WORKDIR /var/www/html/services/trucking + +COPY ./ /var/www/html/services/trucking + +RUN npm install -g nodemon + +RUN npm install && mv /var/www/html/services/trucking/node_modules /node_modules diff --git a/Message Notifikasi Apps Driver Tracker.xlsx b/Message Notifikasi Apps Driver Tracker.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..1fd549b421110c5a94a0f25d0e9e0f7f52753831 GIT binary patch literal 10887 zcmeHN(uLse4#C|eIKgdjcXx-u-GVy|?wSO57~CyDkPzGhfk4pU_LALu@9t*z z{R{5x58c0Eri!P#Kp*ZCXRWwRyOFoftRvGFWk)=`5Dn%HiRGoD*+}+1?;2Jf%0%ElT9ezwal9Zx~+NM zbWshYS8#lL7mgM?B*Dcwx+v^~ulwYgnJtv;9y_R`j8)9hmU})|U^775F-XcYXemAc zM?Fzttjh2!6?%w<(CcRlS8tY$)33%#qol;SRgw(V`|*JeJ8u(W(2ns2O_ERn!r7UK zjWuZ~S_M7mqBfO~@9HFVW26XLzP{eb4^b&A4Kzu-^pm}oi0>74L0=b0-1iQkPaaPS zrF3B0C=Cq66x!9VfWM8S@Z1}O46r5L+PD*ldQIjDd^1~7>omtLfW`!!gzU#-H(&bX z@rB;mW3e!olh7@qMc&on$20w&o}eI<|3c0t4K~Uj&xn(M<{r{BIgNl8_O7ffKhOUo z<$o~~|8(n>$qGvSY{=oqGWQW9S97b0=wfo7qB8B|>H$HrD`-t|#Z*MA-L%B$>V%v)^~++qwADXv!@bu=pR|M2obPKiNkS)GJ|!86m-^1ud5;F#MHi5h1a(56nsnh zm>oEuR<@5K9LXntIFpGp;%aKOSnW4rPkwPjsG(-fXH#pM2jr*lHZr&GIhV-p#(MB$ zR?HburQpK6=J+T*OkHphsN2YO`XSeQfCr(!V&r5rB!=|e+H;=zJ4pcV%S>*cpNKRR z1Oy=jJfxRB>+d}AbOPF$Iyu?>%whlL4CHend-n3*eRL#G*bcBEzc~);3Z3qBNq$rw zug?zW2?iAP_Q?9FYJAn1v=ucElHm$rs6thAGf^Y`>{nr>Apr!S5FMxwv;{D zglKrBq;*9W*~Hm)g^Cj^Q(MKt%KdS{PEpCcU4-I2uc~ooe<(;@kC@Bib%9*^(6Fd0 zp&4UnHCmgb&hAZaZ1<~zESuakM0 zHZUM3__frs{bsg!T-HXXN}DGnE<+PQ|?Fj{!3e za08x*yUalVE%cCP)%J29@TJ*K5JDHkuKjFD`DOQU#+$~~97XVvWE6?-VT6@s9sx`D z;gXaujlS~dLH@Q{w>UQ#Mw^!S3*mGy#$HxpE2B$4Kjs0e#GX-gz|(i&hil8h1u3W? z#Q`5?3)0LoI@=jjmtLQl;8N3$LCiEihv+;k{pc+8MeZ^OovuaGrG4Kwk@=y$<hnt!ZHAt)+Zs@g$BA#h z^ZNN;lOw_U`e0@#zMPv0;p}DbhMd~X`w{gt!hvy%9UFIwzS2sBRV}$)TS?qrv$LHww99zDeRrK0%e^u*!udd3k@U zF%h?Lo)z5J4{!WZ24!aul%ZHuCh(Ivv73Z)~;{XF=UGHhSRAk23vtftFXv&hW- znAysG1BZNfG1#gZjGu8z^skW(A*Jsirm7|hU{k;BE~rzc`+=Md=> z#bc`ZjVE^xDDW+mu=uVB=}uv7jfQQ`+v*JrAD;<7D@Us|yK9py{O03usc+*P{bRVY z8DQ%?-bqjA@H>^>6S9L)I&8Pf_JSa+S>`nbTyse%=5^~1-H3$3-Td&;O9Q^jrFAH3 zy;B;}rcWLTjf{)jpK~Gnd@?ojU@E>_`;?ScnysQTUA11NPPwD_C6SgZ=*!&7r+L8$ zj6v$v#a_&ZIq)HzB_$OPuE=omym|pwD)rJwmP0Po_~innfXr>u+Jal~F0b9HHr;wg z3C^mqXcIB0xi3VdLTlAKwyXM7MkvuJ-7L7H+eb+P?IF#2boHWLUe6TRIGI1Ejqh}uTNo`cq zDR=K_uhYyya`r&Ju97`nE`AsQrqw`9Qjt~0gzGvUEi+8iMOAil1rf0zGE*w}&!5z< zoLbUlvv%CaRRX(j&A%dzpK|vCgQ^P%`aWsrI#WX}a`C+?wz5wBW}CG~#~6vz)$iMQJdu_#AiM)KJyvncRsti zdD~mK{>%X5ntFE2Y}f&$hr;lk?Ojxp$;Rzm3MgR?$XUIHIC_c_?(Fr+{3LhB0%z1N zHuF`?M7}aiB&7ad1$aoLzcy`HE4dGXV(S8TO(ZPJfHXYpk8OZldZ|=$4qAO#!fmLk z6YsM}1NBU(w>)|Plo#+igI;#>e4eWe%c`Q~oEoYKPKc#2?6q@5Eex-yy)DoXj$re6 zTwqKvTi{)j9uOkQZauX4Gcl>z?I(CSBVdszlO}3-RBh^aMVc;$sl=OvryT~0=( zNaOpd=xkSoW&xpIvP;bmO@g}IvW>94r~ywiYwIm@t=ho}vFBz3P(=FZR2ZPLLfx`j z(N!OJI`T%$ws$Bh#aBe%<7nW7;o;y`hR7r|_KDk?KQ<}YF#;$Qk)TdL+cz{R6$7q~ z7|jamQ|PSBi>Wrb6&|7-A&<;K=S0hk>(Ouv?!jLaOZxP`vWE-w(X<+cP_EVw+VS89 zMt(L$GZrtn2WqS1N#7ggUIwqvmc+lspqC4%6*8&lTs3fRP6}x*q6#T;YS~jv0ZJZ7 z&9!OZIhj5h=`1r$9FZem(v0+YE^(i@vcR&UI2j=(-iw9_y{j=RCG-70aNUqgNX$~p zvTWUHw!(HJ;Q(oAm|s5EFkyNKZT;=q8YY_iEzF`z1AkZSsm(*wu03r}i{b&&GUKes zz;)xJb@o`kHjy$qDP!x-MwCa^;Pu_yR=>S>D(vJZJ^9?z$nZ%feWqMzKd?5-Y$l#p zx-hKk9*WvKf^6lmM=wK{42?F|X39X<ngsGRnd>E`_iXTF>B;H+|d5P~i zb7RG5Q67x>2w1E8xQLz6jQFYq=dYH*R-+NF{m?t|m*8)lTp+Pz0(YopcxS;l+GUs2vm*xq|>w$3zStm zRN3|bT@REP>Br8uZ?EzKe9qlYXF4-{q%)BElGBX3l+T26Viz)~X43-gc~Yka_6n=&$J0F#s_ zgv}SI2iAs@BDZZwBGrh}zt-=M$hCZHbueFmZKT&fFZbP0x#fqQvV<(KHJl}^$<`CR zgk#>f7mu}u94gwGO#e|O5vAf#RZU)-f@eoJ_K4#(M9>RWD%q{kL1d*V`1;luI=+p8 zW$IaYOs8;68sk=VdK7@hbC);uBK z$CLf@h;E_4AA2|bM)lw(202GKYBjZ^xdfx9hX=ehqwdF(Z>K!_pJ-3}2DxH;y`0+RhC9^)5s5f7G!Uh&L-9zYWm;V%?bILQ<^-lgDoKP{m#$_ zYZjG5RXz#!S0r6A=3h8~fxXf+)vQz!KGF2&w`NRl+G^pf~NuHsyczy|s0un;v#LD&TD=i4keGirttuS9~ zvp}?ww-%Embse#pouqhfA+<3UOM=Y{O%qX^0{rLiQ=0=0UmeTCRO8F8u_%W)U_TF>s zr6;5-EKGvl=^cnao6h2^L~sMb6)BUQk9FQkk8^UR>t}BbSHrpMr@L~?S;N;g7L#_F z=ek1|mlvY8nH_$?V>HKSdwEJ7bvvBopra2kgY9CT{?HxMv2bkfmQ~tl!M2c-6xUg= zGMH9Cl+4>MG{UqTO9@lRy5bhAJvq_x7wTS|GzDfQ5$=pQ`BPPQisxPlakGk6;L5hF z_ee0wH(vDmapLKKvOQg)(&s*Hp3Qzx5*?hk#?su)Rr0Xi9-o&3MK+_ev3oH zu#=>qZ4IWOQJWeNaJ*@PY?V zv!3sWp5X(jcsve(KVkE^^TFmM#JYW&bD2KZ2R9fXBof~t7wb`{Q z8)W$Q$t`6+Lf{KZ#hLi0dWKTR2SsLJwH*r>6?4uT(6RZ+KL)CojX8guLqVrQu|K+@ zL1np-lL;PK=@a+0gS!;3&}lWT@JQ~suDb}+0U-DKc5J0%&JxZuSkT8gkoT?Xp0b!z zIwjrh4ABUP+c;(=MJEn^y@QXI`6+q77=tYLu4$}5 z$HBuk%(6*{4!TpZcxzY`RO0K7n^y8Q!jsZE}l~`{_pAcXASCVZDHZ& z%KF>ow;Y_4GU~X@h8}(lbBhXnjM*ev2lF8~9e<( zepz*CP$`B0N|mrU6Wvi=!2HOhfwk^R=8- z^>s#xm>$TOy8CWj7ENg@k{@4I<>gD?0AG&Ja3Lgf5y3SuWy2-taA!$+bLhp-3cK;Y zr^<6)$Ej0Jcgw?$ksd2c5fv7uB3=>5{{hq|YWU7$$focH8V*r{6}fNv&;$~Y>UJ6w z{rHM)T9T|CbNvqQ))xIlOYZYZZ{NH8`ZJU@><&7dPkwLjEBO2%!8U@`y9?Gepdx&u#L7(KR2s6(4j_C-g3P zJO^O=NxGi=-01m*KRx|+0wwFA_K~4Wwuos5HDZ(6(2+J1k;}}~*aFntuO`(c3toRC z1+QfGuZXsNUMidp)vOoJlQmLNj1t(N?0wHf2mT_Kedg>?$=OWAkX6O2F;n24uofMH zmbC zVb^WD`hL@M?67-uKi*ArM#u`cDGa&JbmWnyAyKVfG=E%zn$;LLuLNNnO{HGSs|+wy z(y~quCqth9{=a{1n-g8K%vnCS%(b66h5fv`=e~}swF%I|T+Iz=<7o9;IT)+4>^Lie z?k~MXDit6iS>(Pnqf91?L#P3hiuryYPX2R>7m@G$A$6&rP=hRz#eA=zcD?6h4xg(Y z+GM~doXSz{_j7Clf_oMsfIYGD9k%vdgTs7FW0LY0j8)bdLWvWTQmjVEmF_)VW2g-? z;9c=NJr&isOA(%uh5D&7so{Lf%;h0;+-54Edn)OL&qIgQdk*v^MxOE8VFEAeZeRZO zmpMP`r+dbxd*Uo-G`L1qtrH_czi-kS2o6}yFO7!j7p6KZGPcfazJfI<>V>7L2f;p! zRRkvL%ZR%+Li_U6Q|uUHZMYw@=LPI)%VjDTE||js1hk!XB@cB{np)+7zGo@89i=aJ z(SpWRl7q{>&+yOVg0?wEYnxhl%8k z+~5MG4-8$ly+AzJrG&?AEKXi(UpSLjiE*EW96jg7Rjfwn+5^WCfM6Acw2yTw3tOQ_ zK9c5e!_-J-4X2p?d|16HYBhXKobn{20TzktL9_qDuUHx4Ds?xskJq5;LFN z*is6Kv)L2{TeBgf#hr`k7O}gixLah}KZL2zqzPPG!p^JrN+21X4-!TA5|&WSN++3& zm@cPeaW5CAanDje-MB3j8|V&+otO&EXPoD|{P@Ryqb^Ju^1J6EY!2i9jrANq>#dxW zWyj*5v0iJ*Q=|*dOom>Pe2$xId9CWw%V8Y7(s+DnQnsS&4z)yv2zLFO< z@Y&=Xa005VMO=vXUh?0o+7-9=02To)q=f@&6uyQYODFY%ZJzdhVJ)0ql3v5o z*)EUcva%+Pb4^Hz@@Rbd>4DP6ba=Eg-Va(P3vUP)Mm8bVm8XYQO?hZFf565F!^pwY0b2-Y8s4zqas+D+ z?XWTUv*S^I==FW>BJzz-7cPL=giydg4S!^6GDJbjcVUnyA;CkIVaZwPAztF9Rl?xz zd=O|uHft=PO}N@FUN=45cN$^@hk+fRM#f%QM`s|~b~&zkcKW{n+Y?XHXx~i<>NK(T zARg+<)8I2=v`Nyu7NR~q?q}BW;~Dx6Nzf2Pox&F77)ks2vyJ-?!g@gj7hh@eq2d$n zR;J!cDTE;{gnr>p=mT8f$ZgU3_X_-N6+fa97wjSXkslmk@fuIhLF->RAxBHkF_aCx z126yy_{>`q{iRsKIi4;KRMUv4vb5G^hkOWSnkc-TYhg8fS(!3F|6#{PP)IT2{_&!r z^%zSA_u^__^BC*AOBT1=Sn2E4$L{UY*G7&B{`G#GqvXN@dvK;Mr9{jFOS z@Ph{NRH)@{>?rgYGj@3x0!q1XRRnLl;tP&|U-n@%+D_0t{9J+~G4Yf@aLfi0F1#mz z{eE`u34O(Dbu^5EkyLo{-7#v0myI6!TMp2!>BUrKH9SQ)FZ-y5U?|F`aL{x)h{#V_ zLf(B)8P?WY^u5bc9vYS z0NdLxVJtKJoruzY^uUWSfCTdnpvlbgC33_|I$9Q8WUcIvCGr=le17XO{_L7$mSo(r zst&~ue6dNQ(TnZ9<;A`9uXq-CRwZR=3qJ+4zjt3fClGm+pT7!y&b%1UI-I$a znKIDH*_GAI325;%tUXKC|C8UIA6;y+fm}Zue%LY0llZ8AcJsLzk^?P6JCKZ5r2}bn zxvKJpZ1nK*SYf$JlV-~TIC=LaC*AzK^IfPCTeB*Mv@CWp1eIDx@&R#YHSQ)h%x9HR zn<}a=dl0x2F&|=LZTdjLR>fTSTEQrSvbue4@!XR(A$1l+=%1w4$UC(eDBqn+Hw_L&rmpaXqL@J#|q_CQH$>PH3s zZ_QTNvl|SFSA6wQhRSS;EN2E!Zm{mV{CxJy!&B`&2O)3>tlkh5C}#Fe)iZ=aE-Q;4 zf0~>FI8c^JgiBX@6u)Y6+)p>s>^VjYM9Is3h%xAW)Y%A5kiQL~-ElZOY1J*Dh@0h# zwKB=7-qHgKQKnoMPn?-`RZSU1niU0NzNP9U*D~8eP&U6lT*m%=_x$VTudq=)tK=Dm zvd`E@|1%6toSpxN!e{vX>&Qtl_^F44AH&_DiCx95*n=?4Qa z?&V~ecL&rf7+7`UA0GL2bofjrQPm_=nUPR6_NLzhRh(hh-i+P)kCJ+N;^p&-&vebO zc+uTFOA!@U$6si|;G>wxKH$ETTSFgAMYkrje#HV@{;Ei#T0#HThE>c!52~eCuw_G* zDP{}MlhmW7Y%nmIm=IqP|2W@>SoXF5?JB*cF}0Ja+h^-BwQ@K+)gEOm->D%V#D&_A z(ol-gV0p_)=8UiA`z46T!C^vb)t9Iai5!wszCvw1ISe!105+`SG>^^^y zp7SsRFQh#xkXv~Pg7jU?K(33Ck$phk4?=+`#MWWMjc~5c9lk8qMGYa&LGlg7pyHXt z@Ju7#xbi8+dWi8d#`l)aaSFC~KqF*sZ$P+R+^xmBMC-v9e9^w>=gm1$TQGisH_G3r za;N4fKdp6uc8%}3sfpFW^wdGu5~rxVbC<TV$4ix>{@aHx6 znJ#}CFZ$K+uR|7pHtd7_t-$(!MlOE!^Q+|kho}2z(e4)k{#WB)^}Rog$B}=p^8Tat z{c8HF%JGLOB>HcrziJ-8I{39u^M`{Vy#FlxZ(W;Tz5H64{^8{l;qQ0wYn}S5hhJ-m zKRnoz{Np-)t0;c;^4DDbhYtt{00jiZ-!k{F=6{W`e>R_{`jh#;BCfI=%ri!QPOu?C N3_WiSDrkRx`ad&)0CoTX literal 0 HcmV?d00001 diff --git a/README.MD b/README.MD new file mode 100644 index 0000000..e69de29 diff --git a/abcd.json b/abcd.json new file mode 100644 index 0000000..9b42a93 --- /dev/null +++ b/abcd.json @@ -0,0 +1,2902 @@ +{ + "name": "fs", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "fs", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "base64url": "^3.0.1", + "bcrypt": "^5.0.1", + "crypto-js": "^4.1.1", + "dotenv": "^10.0.0", + "express": "^4.17.2", + "formidable": "^2.0.1", + "jsonwebtoken": "^8.5.1", + "moment": "^2.29.1", + "morgan": "^1.10.0", + "mysql": "^2.18.1", + "path": "^0.12.7", + "validatorjs": "^3.22.1", + "winston": "^3.3.3" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", + "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.8.tgz", + "integrity": "sha512-CMGKi28CF+qlbXh26hDe6NxCd7amqeAzEqnS6IHeO6LoaKyM/n+Xw3HT1COdq8cuioOdlKdqn/hCmqPUOMOywg==", + "dependencies": { + "detect-libc": "^1.0.3", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.5", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dependencies": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agent-base/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "node_modules/async": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.2.tgz", + "integrity": "sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g==" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/bcrypt": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.1.tgz", + "integrity": "sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw==", + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "node-addon-api": "^3.1.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", + "engines": { + "node": "*" + } + }, + "node_modules/body-parser": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.1.tgz", + "integrity": "sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA==", + "dependencies": { + "bytes": "3.1.1", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.9.6", + "raw-body": "2.4.2", + "type-is": "~1.6.18" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "node_modules/bytes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", + "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "node_modules/color-string": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz", + "integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/colors": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.1.tgz", + "integrity": "sha512-urbBmMVnD1vk0mUwCpnWv06P3f16EF+RMTtIXTkylJk5mAdfrMepu9B3hhSnL8DGkc1Ra6pENJHrXTKvcAZ0wA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/crypto-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", + "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dezalgo": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", + "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "engines": { + "node": ">=10" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.2.tgz", + "integrity": "sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg==", + "dependencies": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.4.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.9.6", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/fecha": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", + "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==" + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, + "node_modules/formidable": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.0.1.tgz", + "integrity": "sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ==", + "dependencies": { + "dezalgo": "1.0.3", + "hexoid": "1.0.0", + "once": "1.4.0", + "qs": "6.9.3" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/formidable/node_modules/qs": { + "version": "6.9.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz", + "integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==", + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "node_modules/hexoid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", + "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", + "engines": { + "node": ">=8" + } + }, + "node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=4", + "npm": ">=1.4.28" + } + }, + "node_modules/jsonwebtoken/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, + "node_modules/logform": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.3.0.tgz", + "integrity": "sha512-graeoWUH2knKbGthMtuG1EfaSPMZFZBIrhuJHhkS5ZseFBrc7DupCzihOQAzsK/qIKPQaPJ/lFQFctILUY5ARQ==", + "dependencies": { + "colors": "^1.2.1", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^1.1.0", + "triple-beam": "^1.3.0" + } + }, + "node_modules/logform/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "dependencies": { + "mime-db": "1.51.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", + "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", + "engines": { + "node": "*" + } + }, + "node_modules/morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/morgan/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/mysql": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", + "dependencies": { + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", + "safe-buffer": "5.1.2", + "sqlstring": "2.3.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mysql/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==" + }, + "node_modules/node-fetch": { + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz", + "integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", + "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=", + "dependencies": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==", + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz", + "integrity": "sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==", + "dependencies": { + "bytes": "3.1.1", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-stable-stringify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz", + "integrity": "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "1.8.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/signal-exit": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", + "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==" + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/sqlstring": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "engines": { + "node": "*" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "node_modules/triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/util/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/validatorjs": { + "version": "3.22.1", + "resolved": "https://registry.npmjs.org/validatorjs/-/validatorjs-3.22.1.tgz", + "integrity": "sha512-451KiCt/3E8qV/8fOUdO0YkA8zUdQBNVxubg9jvgEB+JAg9IlRKrClzwq2ir2ndj7TWmPYQ7bXFb4BxcyX2iWw==" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/winston": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", + "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "dependencies": { + "@dabh/diagnostics": "^2.0.2", + "async": "^3.1.0", + "is-stream": "^2.0.0", + "logform": "^2.2.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.4.0" + }, + "engines": { + "node": ">= 6.4.0" + } + }, + "node_modules/winston-transport": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.1.tgz", + "integrity": "sha512-ciZRlU4CSjHqHe8RQG1iPxKMRVwv6ZJ0RC7DxStKWd0KjpAhPDy5gVYSCpIUq+5CUsP+IyNOTZy1X0tO2QZqjg==", + "dependencies": { + "logform": "^2.2.0", + "readable-stream": "^3.4.0", + "triple-beam": "^1.2.0" + }, + "engines": { + "node": ">= 6.4.0" + } + }, + "node_modules/winston-transport/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/winston/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + }, + "dependencies": { + "@dabh/diagnostics": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", + "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", + "requires": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "@mapbox/node-pre-gyp": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.8.tgz", + "integrity": "sha512-CMGKi28CF+qlbXh26hDe6NxCd7amqeAzEqnS6IHeO6LoaKyM/n+Xw3HT1COdq8cuioOdlKdqn/hCmqPUOMOywg==", + "requires": { + "detect-libc": "^1.0.3", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.5", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "async": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.2.tgz", + "integrity": "sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g==" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base64url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==" + }, + "basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "requires": { + "safe-buffer": "5.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "bcrypt": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.1.tgz", + "integrity": "sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw==", + "requires": { + "@mapbox/node-pre-gyp": "^1.0.0", + "node-addon-api": "^3.1.0" + } + }, + "bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" + }, + "body-parser": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.1.tgz", + "integrity": "sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA==", + "requires": { + "bytes": "3.1.1", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.9.6", + "raw-body": "2.4.2", + "type-is": "~1.6.18" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "bytes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", + "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==" + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + }, + "color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "requires": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-string": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz", + "integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" + }, + "colors": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.1.tgz", + "integrity": "sha512-urbBmMVnD1vk0mUwCpnWv06P3f16EF+RMTtIXTkylJk5mAdfrMepu9B3hhSnL8DGkc1Ra6pENJHrXTKvcAZ0wA==" + }, + "colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "requires": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "crypto-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", + "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + }, + "dezalgo": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", + "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.2.tgz", + "integrity": "sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.4.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.9.6", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "fecha": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", + "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==" + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, + "formidable": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.0.1.tgz", + "integrity": "sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ==", + "requires": { + "dezalgo": "1.0.3", + "hexoid": "1.0.0", + "once": "1.4.0", + "qs": "6.9.3" + }, + "dependencies": { + "qs": { + "version": "6.9.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz", + "integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==" + } + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "requires": { + "minipass": "^3.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "hexoid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", + "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==" + }, + "http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "requires": { + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, + "logform": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.3.0.tgz", + "integrity": "sha512-graeoWUH2knKbGthMtuG1EfaSPMZFZBIrhuJHhkS5ZseFBrc7DupCzihOQAzsK/qIKPQaPJ/lFQFctILUY5ARQ==", + "requires": { + "colors": "^1.2.1", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^1.1.0", + "triple-beam": "^1.3.0" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" + }, + "mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "requires": { + "mime-db": "1.51.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minipass": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", + "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", + "requires": { + "yallist": "^4.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" + }, + "morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "requires": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, + "dependencies": { + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "mysql": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", + "requires": { + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", + "safe-buffer": "5.1.2", + "sqlstring": "2.3.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==" + }, + "node-fetch": { + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz", + "integrity": "sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "requires": { + "abbrev": "1" + } + }, + "npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "requires": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "requires": { + "fn.name": "1.x.x" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", + "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=", + "requires": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "qs": { + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz", + "integrity": "sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==", + "requires": { + "bytes": "3.1.1", + "http-errors": "1.8.1", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safe-stable-stringify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz", + "integrity": "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "send": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "1.8.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serve-static": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.2" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "signal-exit": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", + "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==" + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "requires": { + "is-arrayish": "^0.3.1" + } + }, + "sqlstring": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=" + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + } + }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "validatorjs": { + "version": "3.22.1", + "resolved": "https://registry.npmjs.org/validatorjs/-/validatorjs-3.22.1.tgz", + "integrity": "sha512-451KiCt/3E8qV/8fOUdO0YkA8zUdQBNVxubg9jvgEB+JAg9IlRKrClzwq2ir2ndj7TWmPYQ7bXFb4BxcyX2iWw==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "winston": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", + "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "requires": { + "@dabh/diagnostics": "^2.0.2", + "async": "^3.1.0", + "is-stream": "^2.0.0", + "logform": "^2.2.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.4.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "winston-transport": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.1.tgz", + "integrity": "sha512-ciZRlU4CSjHqHe8RQG1iPxKMRVwv6ZJ0RC7DxStKWd0KjpAhPDy5gVYSCpIUq+5CUsP+IyNOTZy1X0tO2QZqjg==", + "requires": { + "logform": "^2.2.0", + "readable-stream": "^3.4.0", + "triple-beam": "^1.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } +} diff --git a/app.js b/app.js new file mode 100644 index 0000000..1754c87 --- /dev/null +++ b/app.js @@ -0,0 +1,567 @@ +require('dotenv').config({ path: '.env' }); +require('events').EventEmitter.prototype._maxListeners = 30; +// start for gps-tracking +const net = require('net'); +const dgram = require('dgram'); +const crc = require('crc'); +const moment = require('moment'); +const LibDevice = require('./library/LibDevice'); +const GpsTracksModels = require('./models/GpsTracksModels'); +const ZoneModels = require('./models/ZoneModels'); +const VhcModels = require('./models/VhcModels'); +const LibMail = require('./library/LibMail'); +const LibHelper = require('./library/LibHelper'); +const nanoid = require('nanoid').nanoid; +// end for gps-tracking + +// start for normal http request +const express = require('express'); +const LibBullAdapter = require('./library/LibBullAdapter'); +const routes = require('./routes/routes'); +// const routes = require('./routes/routes_without_scheduler'); +const app = express(); +// end for normal http request + +// start for logging +const LibWinston = require('./library/LibWinston'); + +const logName = 'libUdp'; +const Logger = LibWinston.initialize(logName); +// end for logging + +// start commit / log message from gps +async function commitMessage(now, logDevice) { + try { + // don't log + if (!logDevice.original_hex) { + return false; + } + // in the future don't log to db if device_id not found in vhc + const vhc = await VhcModels.getVhcByDeviceId(logDevice.device_id); + const lastTrack = await GpsTracksModels.get2LastLocByDeviceId(logDevice.device_id); + + if (['heartbeat', 'alarm'].includes(logDevice.action)) { + // set engine stts moving,idling,stopped + if (logDevice.ignition == GpsTracksModels.STTS_IGNITION_HIGH) { + if (logDevice.speed) { + logDevice.stts_engine = GpsTracksModels.STTS_EN_MOVING; + } else { + if (lastTrack.length > 0) { + const checkLastHeartbeat = await GpsTracksModels.getLastHeartbeatToDeterminIdling(logDevice.device_id, lastTrack[0].crt, now); + if (checkLastHeartbeat.length >= 3) { + logDevice.stts_engine = GpsTracksModels.STTS_EN_IDLING; + } else { + logDevice.stts_engine = lastTrack[0].stts_engine; + } + } + } + } else { + logDevice.stts_engine = GpsTracksModels.STTS_EN_STOPING; + } + } + // get last ignition, stts_engine, stts_alarm, stts_charge, stts_acc, stts_volt, stts_switch + if (['location'].includes(logDevice.action)) { + // get last ignition + const lastHeartbeatOrAlarm = await GpsTracksModels.get2LastHeartbeatOrAlarm(logDevice.device_id); + if (lastHeartbeatOrAlarm.length > 0) { + logDevice.ignition = lastHeartbeatOrAlarm[0].ignition; + logDevice.stts_gps = lastHeartbeatOrAlarm[0].stts_gps; + logDevice.stts_gsm = lastHeartbeatOrAlarm[0].stts_gsm; + } else { + logDevice.ignition = lastHeartbeatOrAlarm[0].ignition; + logDevice.stts_gps = lastHeartbeatOrAlarm[0].stts_gps; + logDevice.stts_gsm = lastHeartbeatOrAlarm[0].stts_gsm; + } + // set engine stts moving,idling,stopped + if (logDevice.ignition == GpsTracksModels.STTS_IGNITION_HIGH) { + if (logDevice.speed) { + logDevice.stts_engine = GpsTracksModels.STTS_EN_MOVING; + } else { + if (lastTrack.length > 0) { + const checkLastHeartbeat = await GpsTracksModels.getLastHeartbeatToDeterminIdling(logDevice.device_id, lastTrack[0].crt, now); + if (checkLastHeartbeat.length >= 3) { + logDevice.stts_engine = GpsTracksModels.STTS_EN_IDLING; + } else { + logDevice.stts_engine = lastTrack[0].stts_engine; + } + } + } + // get stts_alarm, stts_charge, stts_acc, stts_volt, stts_switch + } else { + logDevice.stts_engine = GpsTracksModels.STTS_EN_STOPING; + } + logDevice.stts_oil_electricity = lastHeartbeatOrAlarm[0].stts_oil_electricity; + logDevice.stts_alarm = lastHeartbeatOrAlarm[0].stts_alarm; + logDevice.stts_charge = lastHeartbeatOrAlarm[0].stts_charge; + logDevice.stts_acc = lastHeartbeatOrAlarm[0].stts_acc; + logDevice.stts_volt = lastHeartbeatOrAlarm[0].stts_volt; + logDevice.stts_switch = lastHeartbeatOrAlarm[0].stts_switch; + } + + // sekarang heartbeat diinject data lokasi juga dari lokasi terakhir + if (['heartbeat'].includes(logDevice.action)) { + if (lastTrack.length > 0) { + logDevice.latitude = lastTrack[0].latitude; + logDevice.longitude = lastTrack[0].longitude; + logDevice.speed = lastTrack[0].speed; + logDevice.orientation = lastTrack[0].orientation; + if (logDevice.latitude) { + logDevice.stts_reverse_geo = GpsTracksModels.STTS_REVERSE_GEO_NOT; + } + + logDevice.length_gps = lastTrack[0].length_gps; + logDevice.pos_stlt_gps = lastTrack[0].pos_stlt_gps; + logDevice.pos_type_gps = lastTrack[0].pos_type_gps; + logDevice.is_pos_gps = lastTrack[0].is_pos_gps; + + // jika gapengen dimunculin di last movement + // logDevice.crt = lastTrack[0].crt; + // logDevice.crt_format = lastTrack[0].crt_format; + // logDevice.crt_d = lastTrack[0].crt_d; + // logDevice.crt_d_format = lastTrack[0].crt_d_format; + // jika pengen di munculin di last movement + logDevice.crt = now; + logDevice.crt_format = moment.unix(now).format('YYYY-MM-DD HH:mm:ss'); + logDevice.crt_d = now; + logDevice.crt_d_format = moment.unix(now).format('YYYY-MM-DD HH:mm:ss'); + } + } + + // count milleage + if (logDevice.latitude != null && logDevice.longitude != null && lastTrack.length > 0) { + const distance = LibHelper.haversineGreatCircleDistance(lastTrack[0].latitude, lastTrack[0].longitude, logDevice.latitude, logDevice.longitude, LibHelper.EARTH_RADIUS_KM); + const distance_km = LibHelper.kmToKm(distance, 100000000); + // console.log(`GPS TRACKER UP LOCATION => device_id:${logDevice.device_id} vhc_id:${(vhc[0]) ? vhc[0].vid : 0}, distance_km:${distance_km}`); + // validasi jika lebih dari 3km, ga disimpan + if (distance_km >= 3) { + GpsTracksModels.bundleCreate2(logDevice, logDevice); // jika tidak disimpan malah jadi bug, jadi akan update lokasi terus dengan kalkulasi jarak sebelumnya jadi makan lama makin lebar, mending disimpen terus milleagenya jadi 0 aja + return false; + } + logDevice.pre_milleage = distance_km; + logDevice.sum_milleage = (lastTrack[0].sum_milleage + logDevice.pre_milleage).toFixed(8); + if (vhc.length > 0) { + logDevice.vhc_id = (vhc[0]) ? vhc[0].vid : 0; + if (lastTrack[0].vhc_id == logDevice.vhc_id) { + logDevice.vhc_milleage = (lastTrack[0].vhc_milleage + logDevice.pre_milleage).toFixed(8); + } else { + logDevice.vhc_milleage = ((vhc[0]) ? vhc[0].sum_milleage : 0 + logDevice.pre_milleage).toFixed(8); + } + VhcModels.update((vhc[0]) ? vhc[0].vid : 0, { sum_milleage: logDevice.vhc_milleage }); + } + } + + // truck zoning spawn + if (logDevice.latitude != null && logDevice.longitude != null) { // && vhc.length > 0 + // log tracking + const currTrack = await GpsTracksModels.bundleCreate2(logDevice, logDevice); + // console.log('GT06 HAS LOCATION AND CHECK ZONE'); + const inCircle = await ZoneModels.getInCircle(logDevice.latitude, logDevice.longitude); + const inShape = await ZoneModels.getInShape(logDevice.latitude, logDevice.longitude); + const insideSpawnZone = []; + for (let zone of inCircle) { + insideSpawnZone.push(zone); + } + for (let zone of inShape) { + insideSpawnZone.push(zone); + } + + /** + * get lastSpawn desc index 0, where leave_at = 0 + * kalo gaada create, dengan isi field enter_at aja, kalo ada didalam zona + * kalo ada update, dengan isi field leave_at aja, kalo udah diluar zona + */ + const lastSpawn = await GpsTracksModels.listSpawnZone({ + source: GpsTracksModels.SOURCE_GPS_TRACKER, + device_id: logDevice.device_id, + vhc_id: (vhc[0]) ? vhc[0].vid : 0, + leave_at_d: 0, + order_by: 'ORDER BY id DESC', + limit: 1, + }); + + if (lastSpawn.length > 0) { + let is_leave_zone = 1; + for (const insideZone of insideSpawnZone) { + if (insideZone.zid === lastSpawn[0].zone_id) is_leave_zone = 0; + } + if (is_leave_zone === 1 && lastSpawn[0].device_id == logDevice.device_id) { + GpsTracksModels.updt2SpawnZone({ + leave_lat: logDevice.latitude, + leave_lng: logDevice.longitude, + leave_at_d: logDevice.crt_d || now, + leave_at_d_format: moment.unix(logDevice.crt_d || now).format('YYYY-MM-DD HH:mm:ss'), + leave_at_s: now, + leave_at_s_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'), + updt: now, + updt_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'), + }, lastSpawn[0].id); + } + } else { + for (let zone of insideSpawnZone) { + let mailData = { + pic_name: zone.pic_name, + pic_mail: zone.pic_mail, + z_name: zone.name, + z_type_name: zone.type_name, + z_workflow_name: zone.workflow_type_name, + shiptocode: zone.shiptocode, + z_fulladdress: zone.fulladdress, + v_nopol: ((vhc[0]) ? vhc[0].nopol1 : 0 || '') + ((vhc[0]) ? vhc[0].nopol2 : 0 || '') + ((vhc[0]) ? vhc[0].nopol3 : 0 || ''), + da_name: (vhc[0]) ? vhc[0].da_name : 0 || '', + da_phone: '+' + ((vhc[0]) ? vhc[0].da_phone_code : 0 || '') + ((vhc[0]) ? vhc[0].da_phone : 0 || ''), + }; + // LibMail.sendVhcSpawnZoneMail(`${(vhc[0]) ? vhc[0].nopol1 : 0 || ''}${(vhc[0]) ? vhc[0].nopol2 : 0 || ''}${(vhc[0]) ? vhc[0].nopol3 : 0 || ''} entering zone ${mailData.z_name}`, mailData.pic_mail, mailData); + + if (logDevice.device_id === '0865784052395871') console.log(1234567890); + GpsTracksModels.create2SpawnZone({ + device_id: logDevice.device_id, + master_id: Number(currTrack.result.insertId), + enter_lat: logDevice.latitude, + enter_lng: logDevice.longitude, + enter_at_d: logDevice.crt_d || now, + enter_at_d_format: moment.unix(logDevice.crt_d || now).format('YYYY-MM-DD HH:mm:ss'), + enter_at_s: now, + enter_at_s_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'), + zone_id: zone.zid, + zone_name: zone.name, + vhc_id: (vhc[0]) ? vhc[0].vid : 0, + source: GpsTracksModels.SOURCE_GPS_TRACKER, + crt: now, + crt_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'), + }); + if (logDevice.device_id === '0865784052395871') console.log('DISINI'); + } + } + } else { + // log tracking + GpsTracksModels.bundleCreate2(logDevice, logDevice); + } + } catch (e) { + console.error(e); + } +} +// end commit / log message from gps + +// start for gps-tracking TCP ONLY +const devices = []; +const netConn = require('./config/netConn'); +/** + * uniquely identify a socket with Node.js + * https://stackoverflow.com/questions/6805432/how-to-uniquely-identify-a-socket-with-node-js + */ +net.createServer({ + allowHalfOpen: true, +}, function (c) { // c mean connection + + // save connections + c.id = nanoid(); + + c.pipe(c); + + c.on('data', async (buffer_req) => { + const now = moment().unix(); + const me = LibDevice.identifyProtocolFromBuffer(buffer_req); + // console.log('app ', buffer_req); + + const logDevice = { + original_hex: me.ori_string, + protocol: (me.protocol_name == 'unknown') ? null : me.protocol_name, + action: null, + device_id: null, + latitude: null, + longitude: null, + speed: null, + orientation: 0, + ignition: 0, + stts_engine: 0, + stts_gps: 0, + length_gps: 0, + pos_stlt_gps: 0, + pos_type_gps: 0, + is_pos_gps: 0, + stts_gsm: 0, + stts_oil_electricity: 0, + stts_alarm: 0, + stts_charge: 0, + stts_acc: 0, + stts_volt: 0, + stts_switch: 0, + stts_reverse_geo: 0, + pre_milleage: 0, + source: GpsTracksModels.SOURCE_GPS_TRACKER, + vhc_id: 0, + drv_id: 0, + crt: now, + crt_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'), + crt_d: 0, + crt_d_format: null, + crt_s: now, + crt_s_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'), + }; + + if (me.protocol_name == 'gt06') { + // const act = LibDevice.gt06Action(me, device.device_id || null); + let dvc_id = devices[c.id]; + const act = LibDevice.gt06Action(me, dvc_id || null); + + if (act.action_type == 'login') { + logDevice.action = act.action_type; + logDevice.device_id = act.device_id; + + devices[c.id] = act.device_id; + netConn[act.device_id] = c; + if (typeof act.buffer_resp != 'undefined') { + c.write(act.buffer_resp); + } + } + else if (act.action_type == 'location') { + logDevice.action = act.action_type; + logDevice.device_id = act.device_id; + + logDevice.latitude = act.gps_data.latitude || null; + logDevice.longitude = act.gps_data.longitude || null; + logDevice.speed = act.gps_data.speed; + logDevice.orientation = act.gps_data.orientation; + if (logDevice.latitude) { + logDevice.stts_reverse_geo = GpsTracksModels.STTS_REVERSE_GEO_NOT; + } + + logDevice.length_gps = act.gps_data.quantity_pos_satellites_c; + logDevice.pos_stlt_gps = act.gps_data.quantity_pos_satellites_b; + logDevice.pos_type_gps = (Number(act.gps_data.realtime_dif_gps) === 0) ? GpsTracksModels.STTS_POS_TYPE_GPS_RLTM : GpsTracksModels.STTS_POS_TYPE_GPS_DIFF; + logDevice.is_pos_gps = (Number(act.gps_data.positioning_gps)) ? GpsTracksModels.STTS_IS_POS_GPS_HAS : GpsTracksModels.STTS_IS_POS_GPS_NOT; + + logDevice.crt = moment(act.gps_data.date).unix(); + logDevice.crt_format = moment(act.gps_data.date).format('YYYY-MM-DD HH:mm:ss'); + logDevice.crt_d = moment(act.gps_data.date).unix(); + logDevice.crt_d_format = moment(act.gps_data.date).format('YYYY-MM-DD HH:mm:ss'); + } + else if (act.action_type == 'heartbeat') { + logDevice.action = act.action_type; + logDevice.device_id = act.device_id; + + logDevice.ignition = Number(act.stts_data.terminal_info.acc) ? GpsTracksModels.STTS_IGNITION_HIGH : GpsTracksModels.STTS_IGNITION_LOW; + logDevice.stts_gps = (act.stts_data.terminal_info.gps_tracking) ? GpsTracksModels.STTS_GPS_ON : GpsTracksModels.STTS_GPS_OFF; // 1=>on, 2=>off + logDevice.stts_gsm = Number(act.stts_data.gsm_signal_strength) + 1; // 1=>no signal, n>1=>get signal + + logDevice.stts_oil_electricity = (Number(act.stts_data.terminal_info.oil_electricity) === 0) ? GpsTracksModels.STTS_OIL_ELECTRIC_ON : GpsTracksModels.STTS_OIL_ELECTRIC_OFF; // 1=>on, 2=>off + + let stts_alarm = Number(act.stts_data.terminal_info.stts); + if (stts_alarm == 0) { + logDevice.stts_alarm = GpsTracksModels.STTS_ALARM_NORMAL; + } else if (stts_alarm == 1) { + logDevice.stts_alarm = GpsTracksModels.STTS_ALARM_SHOCK; + } else if (stts_alarm == 2) { + logDevice.stts_alarm = GpsTracksModels.STTS_ALARM_POWER_CUT; + } else if (stts_alarm == 3) { + logDevice.stts_alarm = GpsTracksModels.STTS_ALARM_LOW_BATTERY; + } else if (stts_alarm == 4) { + logDevice.stts_alarm = GpsTracksModels.STTS_ALARM_SOS; + } + + logDevice.stts_charge = Number(act.stts_data.terminal_info.charge) ? GpsTracksModels.STTS_CHARGE_ON : GpsTracksModels.STTS_CHARGE_OFF; + logDevice.stts_acc = Number(act.stts_data.terminal_info.acc) ? GpsTracksModels.STTS_ACC_HIGH : GpsTracksModels.STTS_ACC_LOW; + logDevice.stts_switch = Number(act.stts_data.terminal_info.is_active) ? GpsTracksModels.STTS_SWITCH_ON : GpsTracksModels.STTS_SWITCH_OFF; + logDevice.stts_volt = Number(act.stts_data.voltage_level) + 1; + + if (typeof act.buffer_resp != 'undefined') { + c.write(act.buffer_resp); + } + } + else if (act.action_type == 'alarm') { + logDevice.action = act.action_type; + logDevice.device_id = act.device_id; + + logDevice.latitude = act.gps_data.latitude || null; + logDevice.longitude = act.gps_data.longitude || null; + logDevice.speed = act.gps_data.speed; + logDevice.orientation = act.gps_data.orientation; + if (logDevice.latitude) { + logDevice.stts_reverse_geo = GpsTracksModels.STTS_REVERSE_GEO_NOT; + } + + logDevice.length_gps = act.gps_data.quantity_pos_satellites_c; + logDevice.pos_stlt_gps = act.gps_data.quantity_pos_satellites_b; + logDevice.pos_type_gps = (Number(act.gps_data.realtime_dif_gps) === 0) ? GpsTracksModels.STTS_POS_TYPE_GPS_RLTM : GpsTracksModels.STTS_POS_TYPE_GPS_DIFF; + logDevice.is_pos_gps = (Number(act.gps_data.positioning_gps)) ? GpsTracksModels.STTS_IS_POS_GPS_HAS : GpsTracksModels.STTS_IS_POS_GPS_NOT; + + logDevice.ignition = Number(act.stts_data.terminal_info.acc) ? GpsTracksModels.STTS_IGNITION_HIGH : GpsTracksModels.STTS_IGNITION_LOW; + logDevice.stts_gps = (act.stts_data.terminal_info.gps_tracking) ? GpsTracksModels.STTS_GPS_ON : GpsTracksModels.STTS_GPS_OFF; // 1=>on, 2=>off + logDevice.stts_gsm = Number(act.stts_data.gsm_signal_strength) + 1; // 1=>no signal, n>1=>get signal + + logDevice.stts_oil_electricity = (Number(act.stts_data.terminal_info.oil_electricity) === 0) ? GpsTracksModels.STTS_OIL_ELECTRIC_ON : GpsTracksModels.STTS_OIL_ELECTRIC_OFF; // 1=>on, 2=>off + + let stts_alarm = Number(act.stts_data.terminal_info.stts); + if (stts_alarm == 0) { + logDevice.stts_alarm = GpsTracksModels.STTS_ALARM_NORMAL; + } else if (stts_alarm == 1) { + logDevice.stts_alarm = GpsTracksModels.STTS_ALARM_SHOCK; + } else if (stts_alarm == 2) { + logDevice.stts_alarm = GpsTracksModels.STTS_ALARM_POWER_CUT; + } else if (stts_alarm == 3) { + logDevice.stts_alarm = GpsTracksModels.STTS_ALARM_LOW_BATTERY; + } else if (stts_alarm == 4) { + logDevice.stts_alarm = GpsTracksModels.STTS_ALARM_SOS; + } + + logDevice.stts_charge = Number(act.stts_data.terminal_info.charge) ? GpsTracksModels.STTS_CHARGE_ON : GpsTracksModels.STTS_CHARGE_OFF; + logDevice.stts_acc = Number(act.stts_data.terminal_info.acc) ? GpsTracksModels.STTS_ACC_HIGH : GpsTracksModels.STTS_ACC_LOW; + logDevice.stts_switch = Number(act.stts_data.terminal_info.is_active) ? GpsTracksModels.STTS_SWITCH_ON : GpsTracksModels.STTS_SWITCH_OFF; + logDevice.stts_volt = Number(act.stts_data.voltage_level) + 1; + + logDevice.crt = moment(act.gps_data.date).unix(); + logDevice.crt_format = moment(act.gps_data.date).format('YYYY-MM-DD HH:mm:ss'); + logDevice.crt_d = moment(act.gps_data.date).unix(); + logDevice.crt_d_format = moment(act.gps_data.date).format('YYYY-MM-DD HH:mm:ss'); + + if (typeof act.buffer_resp != 'undefined') { + c.write(act.buffer_resp); + } + } + // act.action_type == 'other' + else { + logDevice.action = act.action_type; + logDevice.device_id = act.device_id; + } + } + + commitMessage(now, logDevice); + }); + c.on('end', () => { + }); + c.on('close', () => { + }); + + // unused + c.on('drain', (a) => { + console.log('client drain', a); + }); + c.on('error', (a) => { + console.error('client error', a); + }); + c.on('lookup', (a) => { + console.log('client lookup', a); + }); + c.on('ready', (a) => { + console.log('client ready', a); + }); + c.on('timeout', (a) => { + console.log('client timeout', a); + }); + + // not work for gps tracker + // https://stackoverflow.com/questions/17245881/how-do-i-debug-error-econnreset-in-node-js + // c.write("\n"); + // c.write("\n"); + // c.write("\n"); + // c.write("\n"); + // c.write("\n"); + // c.end(); + + c.pipe(c); +}).listen(process.env.PORT, () => { + console.log('Server gps tracker running at port ' + process.env.PORT); +}); +// end for gps-tracking TCP ONLY + +// start for normal http request +app.use(express.json({ limit: '10mb' })); // parsing application/json +app.use(express.urlencoded({ extended: true, limit: '10mb' })); // parsing application/x-www-form-urlencoded +app.use(async function (req, res, next) { + // set control allowed headers + res.header('Access-Control-Allow-Origin', '*'); + res.header('Access-Control-Allow-Methods', 'OPTIONS,GET,HEAD,PUT,PATCH,POST,DELETE'); + res.header('Access-Control-Allow-Headers', 'Accept, Authorization, Content-Type, X-Requested-With, Range, x-api-key, x-forwarded-for'); + next(); +}); +app.use(process.env.PATH_URL + '/bull/monitor', LibBullAdapter.getRouter()); +routes.use(app); +app.listen(process.env.PORT_EXPRESS, () => { + console.log('Express server running at port ' + process.env.PORT_EXPRESS); +}); +// end for normal http request + +// start for gps-tracking UDP ONLY +const udp = dgram.createSocket('udp4'); + +const devices1 = []; +udp.on('message', (msg, rinfo) => { + const buffer_req = Buffer.from(msg, 'utf8'); + console.log('20203', buffer_req); + console.log('20203', rinfo); + Logger.log('info', buffer_req.toString('hex')); + + const now = moment().unix(); + const me = LibDevice.identifyProtocolFromBuffer(buffer_req, {isEelinkCustom: 1}); + console.log('port 20203 ', me); + + const logDevice = { + original_hex: me.ori_buffer, + protocol: (me.protocol_name == 'unknown') ? null : me.protocol_name, + action: null, + device_id: null, + latitude: null, + longitude: null, + speed: null, + orientation: 0, + ignition: 0, + stts_engine: 0, + stts_gps: 0, + length_gps: 0, + pos_stlt_gps: 0, + pos_type_gps: 0, + is_pos_gps: 0, + stts_gsm: 0, + stts_oil_electricity: 0, + stts_alarm: 0, + stts_charge: 0, + stts_acc: 0, + stts_volt: 0, + stts_switch: 0, + stts_reverse_geo: 0, + pre_milleage: 0, + source: GpsTracksModels.SOURCE_GPS_TRACKER, + crt: now, + crt_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'), + crt_d: 0, + crt_d_format: null, + crt_s: now, + crt_s_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'), + }; + + if (me.protocol_name === 'eelinkCustom') { + let dvc_id = devices1[`${rinfo.address}:${rinfo.port}`]; + const act = LibDevice.eelinkCustomAction(me, dvc_id || null); + console.log('act 20203', act); + + if (act.action_type == 'exist_data') { + logDevice.action = act.action_type; + logDevice.device_id = act.device_id; + + devices1[`${rinfo.address}:${rinfo.port}`] = act.device_id; + if (typeof act.buffer_resp != 'undefined') { + udp.send(act.buffer_resp, 0, act.buffer_resp.length, rinfo.port, rinfo.address, function(err, bytes) { + if (err) throw err; + console.log('UDP message sent to ' + rinfo.address +':'+ rinfo.port); + console.log('20203', bytes); + }); + } + + + } + } +}); +udp.on('error', (err) => { + console.log(`udp error:\n${err.stack}`); + udp.close(); +}); +udp.on('close',function(){ + console.log('udp socket is closed !'); +}); +udp.on('listening', () => { + const address = udp.address(); + console.log(`udp listening ${address.address}:${address.port}`); +}); + +udp.bind(process.env.PORT_UDP); +// end for gps-tracking UDP ONLY \ No newline at end of file diff --git a/app.js.express b/app.js.express new file mode 100644 index 0000000..47a0988 --- /dev/null +++ b/app.js.express @@ -0,0 +1,51 @@ +require('dotenv').config({ path: '.env' }); +const express = require('express'); +const formidable = require('formidable'); +const routes = require('./routes/routes'); +const MorganMiddleware = require('./middleware/MorganMiddleware'); + +const app = express(); + +app.use(MorganMiddleware); + +app.use(express.json({ limit: '10mb' })); // parsing application/json +app.use(express.urlencoded({ extended: true })); // parsing application/x-www-form-urlencoded +// parsing form-data +app.use(async function (req, res, next) { + try { + let isMultipart = req.headers['content-type'].includes('multipart/form-data', 0); + if (isMultipart) { + let form = new formidable.IncomingForm(); + let parseFormData = async function () { + return new Promise((resolve, reject) => { + form.parse(req, function (err, fields, files) { + if (err) { + reject(err); + return; + } + req.body = fields; + resolve(true); + }) + }) + } + await parseFormData(); + } + } catch (e) { + } + next(); +}); + +app.use(async function (req, res, next) { + // set control allowed headers + res.header('Access-Control-Allow-Origin', '*'); + res.header('Access-Control-Allow-Methods', 'OPTIONS,GET,HEAD,PUT,PATCH,POST,DELETE'); + res.header('Access-Control-Allow-Headers', 'Accept, Authorization, Content-Type, X-Requested-With, Range, x-api-key, x-forwarded-for'); + next(); +}); + +// api +routes.use(app); + +app.listen(process.env.PORT, () => { + console.log('Service running at port ' + process.env.PORT); +}); \ No newline at end of file diff --git a/app.js.gps b/app.js.gps new file mode 100644 index 0000000..173207b --- /dev/null +++ b/app.js.gps @@ -0,0 +1,98 @@ +require('dotenv').config({ path: '.env' }); +const gps = require('gps-tracking'); +const express = require('express'); +const LibBullAdapter = require('./library/LibBullAdapter'); +const routes = require('./routes/routes'); +const app = express(); + +// start for gps-tracking +const options = { + 'debug': true, + 'port': process.env.PORT, + 'device_adapter': "ET200" +} + +const server = gps.server(options, function (device, connection) { + + /* Available device variables: + ---------------------------- + device.uid -> Set when the first packet is parsed + device.name -> You can set a custon name for this device. + device.ip -> IP of the device + device.port --> Device port + */ + + // console.log('start: 0'); + // console.log(device); + // console.log('end: 0'); + + /****************************** LOGIN ******************************/ + device.on("login_request", function (device_id, msg_parts) { + // console.log('start: login_request'); + // console.log({device_id, msg_parts}); + //Do some stuff before authenticate the device... + // This way you can prevent from anyone to send their position without your consent + this.login_authorized(true, msg_parts); //Accept the login request. + // console.log('end: login_request'); + }); + + device.on("login", function () { + // console.log('start: login'); + // console.log("Hi! i'm " + device.uid); + // console.log('end: login'); + }); + + device.on("login_rejected", function () { + console.log('start: login_rejected'); + console.log('end: login_rejected'); + }); + + + /****************************** PING - When the gps sends their position ******************************/ + device.on("ping", function (data) { + // //After the ping is received + // console.log('start: ping'); + // console.log(data); + // // console.log("I'm here now: " + gps_data.latitude + ", " + gps_data.longitude); + // console.log('end: ping'); + return data; + }); + + + /****************************** ALARM - When the gps sends and alarm ******************************/ + device.on("alarm", function (alarm_code, alarm_data, msg_data) { + // console.log('start: alarm'); + // console.log(msg_data); + // console.log("Help! Something happend: " + alarm_code + " (" + alarm_data.msg + ")"); + // console.log('end: alarm'); + //call_me(); + }); + + + /****************************** MISC ******************************/ + device.on("handshake", function () { + // console.log('start: handshake'); + // console.log('end: handshake'); + }); + +}); + +server.setDebug(true); +// end for gps-tracking + +// start for normal http request +app.use(express.json({ limit: '1mb' })); // parsing application/json +app.use(express.urlencoded({ extended: true })); // parsing application/x-www-form-urlencoded +app.use(async function (req, res, next) { + // set control allowed headers + res.header('Access-Control-Allow-Origin', '*'); + res.header('Access-Control-Allow-Methods', 'OPTIONS,GET,HEAD,PUT,PATCH,POST,DELETE'); + res.header('Access-Control-Allow-Headers', 'Accept, Authorization, Content-Type, X-Requested-With, Range, x-api-key, x-forwarded-for'); + next(); +}); +app.use(process.env.PATH_URL + '/bull/monitor', LibBullAdapter.getRouter()); +routes.use(app); +app.listen(process.env.PORT_EXPRESS, () => { + console.log('Express server running at port ' + process.env.PORT_EXPRESS); +}); +// end for normal http request \ No newline at end of file diff --git a/app_dev_restapi.js b/app_dev_restapi.js new file mode 100644 index 0000000..87cfdb7 --- /dev/null +++ b/app_dev_restapi.js @@ -0,0 +1,26 @@ +require('dotenv').config({ path: '.env' }); +require('events').EventEmitter.prototype._maxListeners = 30; + +// start for normal http request +const express = require('express'); +// const LibBullAdapter = require('./library/LibBullAdapter'); +const routes = require('./routes/routes_without_scheduler'); +const app = express(); +// end for normal http request + +// start for normal http request +app.use(express.json({ limit: '10mb' })); // parsing application/json +app.use(express.urlencoded({ extended: true, limit: '10mb' })); // parsing application/x-www-form-urlencoded +app.use(async function (req, res, next) { + // set control allowed headers + res.header('Access-Control-Allow-Origin', '*'); + res.header('Access-Control-Allow-Methods', 'OPTIONS,GET,HEAD,PUT,PATCH,POST,DELETE'); + res.header('Access-Control-Allow-Headers', 'Accept, Authorization, Content-Type, X-Requested-With, Range, x-api-key, x-forwarded-for'); + next(); +}); +// app.use(process.env.PATH_URL + '/bull/monitor', LibBullAdapter.getRouter()); +routes.use(app); +app.listen(process.env.PORT_EXPRESS, () => { + console.log('Express server running at port ' + process.env.PORT_EXPRESS); +}); +// end for normal http request \ No newline at end of file diff --git a/app_scheduler.js b/app_scheduler.js new file mode 100644 index 0000000..be6851f --- /dev/null +++ b/app_scheduler.js @@ -0,0 +1,33 @@ +require('dotenv').config({ path: '.env' }); +require('events').EventEmitter.prototype._maxListeners = 30; + +// start for normal http request +const express = require('express'); +const LibBullAdapter = require('./library/LibBullAdapter'); +const routes = require('./routes/routes'); +const app = express(); +// end for normal http request + +// start for normal http request +app.use(express.json({ limit: '10mb' })); // parsing application/json +app.use(express.urlencoded({ extended: true, limit: '10mb' })); // parsing application/x-www-form-urlencoded +app.use(async function (req, res, next) { + // set control allowed headers + res.header('Access-Control-Allow-Origin', '*'); + res.header('Access-Control-Allow-Methods', 'OPTIONS,GET,HEAD,PUT,PATCH,POST,DELETE'); + res.header('Access-Control-Allow-Headers', 'Accept, Authorization, Content-Type, X-Requested-With, Range, x-api-key, x-forwarded-for'); + next(); +}); +app.use(process.env.PATH_URL + '/bull/monitor', LibBullAdapter.getRouter()); +routes.use(app); +app.listen(process.env.PORT_EXPRESS, () => { + console.log('Express server running at port ' + process.env.PORT_EXPRESS); +}); +// end for normal http request + + + +/** + * https://redis.io/commands/keys/ => keys *SCanvasing-InvoiceMails* + * https://stackoverflow.com/questions/4006324/how-to-atomically-delete-keys-matching-a-pattern-using-redis => redis-cli KEYS *YOUR_KEY_PREFIX* | xargs redis-cli DEL + */ \ No newline at end of file diff --git a/backup/.gitignore b/backup/.gitignore new file mode 100644 index 0000000..9bfb325 --- /dev/null +++ b/backup/.gitignore @@ -0,0 +1 @@ +!node_modules/ \ No newline at end of file diff --git a/config/dbMysqlConn.js b/config/dbMysqlConn.js new file mode 100644 index 0000000..7491113 --- /dev/null +++ b/config/dbMysqlConn.js @@ -0,0 +1,41 @@ +const mysql = require('mysql'); + +const pool = mysql.createPool({ + connectionLimit: process.env.CONNECTIONLIMIT, + host: process.env.DBHOST, + user: process.env.DBUSER, + password: process.env.DBPASSWORD, + database: process.env.DATABASE, + acquireTimeout: Number(process.env.ACQRTIMEOUT), // in ms +}); + +pool.getConnection((err, conn) => { + if (err) { + if (err.code === 'PROTOCOL_CONNECTION_LOST') { + console.error('Koneksi database ditutup.'); + } + if (err.code === 'ER_CON_COUNT_ERROR') { + console.error('Basis data memiliki terlalu banyak koneksi.'); + } + if (err.code === 'ECONNREFUSED') { + console.error('Koneksi database ditolak.'); + } + console.error(err); + } + if (conn) conn.release(); + return; +}) + +// pool.on('acquire', function (connection) { +// console.log('Connection %d acquired', connection.threadId); +// }); + +// pool.on('connection', function (connection) { +// console.log('Connection %d connect', connection.threadId); +// }); + +// pool.on('release', function (connection) { +// console.log('Connection %d released', connection.threadId); +// }); + +module.exports = pool; \ No newline at end of file diff --git a/config/netConn.js b/config/netConn.js new file mode 100644 index 0000000..9c8a58c --- /dev/null +++ b/config/netConn.js @@ -0,0 +1,3 @@ +const netConn = []; + +module.exports = netConn; \ No newline at end of file diff --git a/config/request.js b/config/request.js new file mode 100644 index 0000000..85ebbea --- /dev/null +++ b/config/request.js @@ -0,0 +1,22 @@ +const request = { + osm_reverse_geo: { + urlBase: 'https://nominatim.openstreetmap.org', + urlPath: 'reverse', + urlFull: 'https://nominatim.openstreetmap.org/reverse', + method: 'GET', + data: { + format: 'geojson' // xml,json,jsonv2,geojson(prefer),geocodejson + }, + }, + kodepos_region: { + urlBase: 'https://kodepos.vercel.app', + urlPath: 'search', + urlFull: 'https://kodepos.vercel.app/search', + method: 'GET', + data: { + json: 'true' + }, + }, +}; + +module.exports = request; \ No newline at end of file diff --git a/config/response.js b/config/response.js new file mode 100644 index 0000000..1d67c2e --- /dev/null +++ b/config/response.js @@ -0,0 +1,95 @@ +// default response by http code, maybe can be customed on controller +// custom format response, maybe can be customed on controller + +const response = { + 200: { + meta: { + code: '200', + type: 'success', + message: 'the request succeeded', + }, + data: '', + }, + 201: { + meta: { + code: '201', + type: 'success', + message: 'resource created', + }, + data: '', + }, + 202: { + meta: { + code: '202', + type: 'success', + message: 'resource accepted, but in progress', + }, + data: '', + }, + 400: { + meta: { + code: '400', + type: 'bad_request', + message: 'bad request', + }, + data: '', + }, + 401: { + meta: { + code: '401', + type: 'unauthenticated', + message: 'unauthenticated', + }, + data: '', + }, + 404: { + meta: { + code: '404', + type: 'not_found', + message: 'resource not found', + }, + data: '', + }, + 422: { + meta: { + code: '422', + type: 'unprocessable_entity', + message: 'bad input', + }, + data: '', + }, + 500: { + meta: { + code: '500', + type: 'error', + message: 'error', + }, + data: '', + }, + email_unique: { + meta: { + code: '400', + type: 'email_unique', + message: 'email must be unique', + }, + data: '', + }, + wrong_password: { + meta: { + code: '400', + type: 'wrong_password', + message: 'wrong password', + }, + data: '', + }, + status_not_valid: { + meta: { + code: '400', + type: 'status_not_valid', + message: 'status not valid', + }, + data: '', + }, +}; + +module.exports = response; \ No newline at end of file diff --git a/controllers/AuthController.js b/controllers/AuthController.js new file mode 100644 index 0000000..83f2142 --- /dev/null +++ b/controllers/AuthController.js @@ -0,0 +1,167 @@ +const moment = require('moment'); +const Validator = require('validatorjs'); +const Helper = require('../library/LibHelper'); +const UsersModels = require('../models/UsersModels'); +const LibPassword = require('../library/LibPassword'); +const LibJwt = require('../library/LibJwt'); +const response = require('../config/response'); + +Validator.useLang('en'); + +class AuthController { + + async register(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + + // input validation + const input = { + first_name: req.body.first_name, + last_name: req.body.last_name, + email: req.body.email, + password: req.body.password, + crt_at: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'), + updt_at: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'), + }; + const rulesInput = { + first_name: 'required|string|max:45', + last_name: 'required|string|max:45', + email: 'required|email|max:45', + password: 'required|string|min:6|max:16', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + + return res.status(200).json(apiRes); + } + + // check email unique + const getUsers = await UsersModels.findEmail(input.email); + if (getUsers.length > 0) { + apiRes.meta = response['email_unique'].meta; + return res.status(200).json(apiRes); + } + + // create account + input.password = await LibPassword.hashPw(input.password); // hash password + const respCreateUser = await UsersModels.create(input); + + // success response + apiRes.meta = response[201].meta; + apiRes.data = (await UsersModels.find(respCreateUser.insertId))[0]; + return res.status(201).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + + async login(req, res) { + let apiRes = {} + try { + const now = moment().unix() + + // input validation + const input = { + email: req.body.email, + password: req.body.password, + }; + const rulesInput = { + email: 'required|email', + password: 'required|string', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + + return res.status(200).json(apiRes); + } + + // login + const getUsers = await UsersModels.findEmail(input.email); + if (getUsers.length < 1) { + apiRes = JSON.parse(JSON.stringify(response[404])); + return res.status(200).json(apiRes); + } + const isPwValid = await LibPassword.checkPw(getUsers[0].password, input.password); + if (!isPwValid) { + apiRes.meta = response['wrong_password'].meta; + return res.status(200).json(apiRes); + } + + await UsersModels.update({is_login: 1}, getUsers[0].id); + + // success response + const jwt = await LibJwt.createToken({ + uid: getUsers[0].id + }); + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success login'; + apiRes.data = getUsers[0]; + apiRes.token = jwt.token; + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + + async profile(req, res) { + let apiRes = {} + try { + const now = moment().unix(); + const { uid } = req.jwt; + + const getUsers = await UsersModels.find(uid); + if (getUsers.length < 1) { + apiRes = JSON.parse(JSON.stringify(response[404])); + return res.status(200).json(apiRes); + } + + delete getUsers[0].password; + + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.data = getUsers[0]; + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + + async logout(req, res) { + let apiRes = {} + try { + const now = moment().unix(); + const { uid } = req.jwt; + + const getUsers = await UsersModels.find(uid); + if (getUsers.length < 1) { + apiRes = JSON.parse(JSON.stringify(response[404])); + return res.status(200).json(apiRes); + } + + await UsersModels.update({is_login: 0}, uid); + + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success logout'; + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + +} + +const object = new AuthController(); + +module.exports = object; \ No newline at end of file diff --git a/controllers/DummyController.js b/controllers/DummyController.js new file mode 100644 index 0000000..b68b5a9 --- /dev/null +++ b/controllers/DummyController.js @@ -0,0 +1,165 @@ +const moment = require('moment'); +const Validator = require('validatorjs'); +const Helper = require('../library/LibHelper'); +const DummyModels = require('../models/DummyModels'); +const response = require('../config/response'); +const LibMail = require('../library/LibMail'); + +Validator.useLang('en'); + +class DummyController { + + async logging(req, res) { + let apiRes = {} + const now = moment().unix(); + try { + apiRes.meta = response[201].meta; + + const insLog = { + ip: req.ip, + ips: JSON.stringify([...req.ips]), + // protocol: req.protocol || null, + method: req.method, + path: req.path, + headers: JSON.stringify({ ...req.headers }), + params: JSON.stringify({ ...req.params }), + request: JSON.stringify({ ...req.query, ...req.body }), + cookies: JSON.stringify({ ...req.cookies }), + xhr: req.xhr, + response: JSON.stringify(apiRes), + crt: now, + }; + await DummyModels.create(insLog); + + return res.status(201).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + + const insLog = { + method: req.method, + response: JSON.stringify(apiRes), + crt: now, + }; + await DummyModels.create(insLog); + + return res.status(500).json(apiRes); + } + } + + async distance(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + + const { latFrom, lngFrom, latTo, lngTo } = req.query; + + // input validation + const input = { + latFrom: latFrom, + lngFrom: lngFrom, + latTo: latTo, + lngTo: lngTo, + }; + const rulesInput = { + latFrom: 'required|string|max:25', + lngFrom: 'required|string|max:25', + latTo: 'required|string|max:25', + lngTo: 'required|string|max:25', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + return res.status(200).json(apiRes); + } + + const respData = {}; + // round up with precisions digits => 4 == (10000) + // reference: https://stackoverflow.com/questions/11832914/how-to-round-to-at-most-2-decimal-places-if-necessary + // const precisionDigits = 10000; + + // distance == miles + // const distance = Helper.haversineGreatCircleDistance(latFrom, lngFrom, latTo, lngTo, Helper.EARTH_RADIUS_MILES); + // respData.distance_km = Helper.milesToKm(distance); + // respData.distance_miles = Helper.milesToMiles(distance); + // respData.distance_meters = Helper.milesToMeters(distance); + + // distance == km + const distance = Helper.haversineGreatCircleDistance(latFrom, lngFrom, latTo, lngTo, Helper.EARTH_RADIUS_KM); + respData.distance_km = Helper.kmToKm(distance); + respData.distance_miles = Helper.kmToMiles(distance); + respData.distance_meters = Helper.kmToMeters(distance); + + // distance == meters + // const distance = Helper.haversineGreatCircleDistance(latFrom, lngFrom, latTo, lngTo, Helper.EARTH_RADIUS_M); + // respData.distance_km = Helper.metersToKm(distance); + // respData.distance_miles = Helper.metersToMiles(distance); + // respData.distance_meters = Helper.metersToMeters(distance); + + // success response + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success get distance'; + apiRes.data = respData; + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + + async sendEmail(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + + const { subject, to } = req.body; + + // input validation + const input = { + subject, + to + }; + const rulesInput = { + subject: 'required|string|max:125', + to: 'required|string|max:255', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + return res.status(200).json(apiRes); + } + + const mailData = { + pic_name: 'Rafif Mulia', + pic_mail: 'rafifrest@gmail.com', + z_name: 'REST-01', + z_type_name: 'Warehousing', + z_workflow_name: 'Parking', + shiptocode: '12330', + z_fulladdress: 'Jl. Perdagangan No.101, RT.4/RW.7, Bintaro, Kec. Pesanggrahan, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12330', + v_nopol: 'B 3633 EVV', + da_name: 'Chienghou Zou', + da_phone: '+62 8128 8789 878', + }; + const resp = await LibMail.sendVhcSpawnZoneMail(subject, to, mailData); + + // success response + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success send email'; + apiRes.data = resp; + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + +} + +const object = new DummyController(); + +module.exports = object; \ No newline at end of file diff --git a/controllers/OrderController.js b/controllers/OrderController.js new file mode 100644 index 0000000..6da195e --- /dev/null +++ b/controllers/OrderController.js @@ -0,0 +1,821 @@ +const moment = require('moment'); +const Validator = require('validatorjs'); +const Helper = require('../library/LibHelper'); +const response = require('../config/response'); +const LibMail = require('../library/LibMail'); +const DanaModels = require('../models/DanaModels'); +// const LibQueueBlastOrder = require('../library/LibQueueBlastOrder'); + +Validator.useLang('en'); + +class OrderController { + + async createOrder(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + + const { + trx_code, + trx_at, + client_id, + client_name, + client_phone, + client_mail, + client_addr, + client_prefer_type_truck, + // weight, + // cbm, + // koli, + pickup_zone_title, + pickup_zone_addr, + pickup_at, + drop_zone_title, + drop_zone_addr, + vendors, + admins, + } = req.body; + + // input validation + const input = { + trx_code, + trx_at, + client_id, + client_name, + client_phone, + client_mail, + // client_addr, + client_prefer_type_truck, + // weight, + // cbm, + // koli, + pickup_zone_title, + pickup_zone_addr, + pickup_at, + drop_zone_title, + drop_zone_addr, + vendors, + admins, + }; + const rulesInput = { + trx_code: 'required|string', + trx_at: 'required|numeric', + client_id: 'required|integer', + client_name: 'required|string|max:255', + client_phone: 'required|string', + client_mail: 'required|email', + // client_addr: 'required|string', + client_prefer_type_truck: 'present|string', + // weight: 'required|numeric', + // cbm: 'required|numeric', + // koli: 'required|numeric', + pickup_zone_title: 'required|string', + pickup_zone_addr: 'required|string', + pickup_at: 'required|numeric', + drop_zone_title: 'required|string', + drop_zone_addr: 'required|string', + // vendors: 'required|array', + // 'vendors.*.vendor_id': 'required|integer', + // 'vendors.*.vendor_name': 'required|string|max:255', + // 'vendors.*.vendor_phone': 'required|string', + // 'vendors.*.vendor_mail': 'required|email', + // 'vendors.*.vendor_addr': 'present|string', + // 'vendors.*.vendor_acc_link': 'required|string', + // 'vendors.*.vendor_reject_link': 'required|string', + admins: 'required|array', + 'admins.*.admin_id': 'required|integer', + 'admins.*.admin_name': 'required|string|max:255', + 'admins.*.admin_phone': 'required|string', + 'admins.*.admin_mail': 'required|email', + // 'admins.*.admin_addr': 'present|string', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + + return res.status(200).json(apiRes); + } + + let resp = {}; + // for (let vendor of vendors) { + // let bidOrderMailData = { + // client_id, + // client_name, + // client_phone, + // client_mail, + // client_addr, + // client_prefer_type_truck: client_prefer_type_truck, + // weight: Number(weight), + // cbm: Number(cbm), + // koli: Number(koli), + // pickup_zone_title, + // pickup_zone_addr, + // pickup_at: moment.unix(pickup_at).format('DD MMM YYYY HH:mm') + ' WIB', + // drop_zone_title, + // drop_zone_addr, + // vendor_id: vendor.vendor_id, + // vendor_name: vendor.vendor_name, + // vendor_phone: vendor.vendor_phone, + // vendor_mail: vendor.vendor_mail, + // vendor_addr: vendor.vendor_addr, + // }; + // LibMail.sendBidOrderMail('Ada Order Masuk', vendor.vendor_mail, bidOrderMailData); + // } + + for (let admin of admins) { + let infoOrderMailData = { + trx_code, + trx_at: moment.unix(trx_at).format('DD MMM YYYY HH:mm') + ' WIB', + client_id, + client_name, + client_phone, + client_mail, + // client_addr, + client_prefer_type_truck: client_prefer_type_truck, + // weight: Number(weight), + // cbm: Number(cbm), + // koli: Number(koli), + pickup_zone_title, + pickup_zone_addr, + pickup_at: moment.unix(pickup_at).format('DD MMM YYYY HH:mm') + ' WIB', + drop_zone_title, + drop_zone_addr, + admin_id: admin.admin_id, + admin_name: admin.admin_name, + admin_phone: admin.admin_phone, + admin_mail: admin.admin_mail, + // admin_addr: admin.admin_addr, + }; + LibMail.sendAdminInfoOrdMail('Ada Order Masuk', admin.admin_mail, infoOrderMailData); + } + + let clientCreateOrdMailData = { + trx_code, + trx_at: moment.unix(trx_at).format('DD MMM YYYY HH:mm') + ' WIB', + client_id, + client_name, + client_phone, + client_mail, + // client_addr, + client_prefer_type_truck: client_prefer_type_truck, + // weight: Number(weight), + // cbm: Number(cbm), + // koli: Number(koli), + pickup_zone_title, + pickup_zone_addr, + pickup_at: moment.unix(pickup_at).format('DD MMM YYYY HH:mm') + ' WIB', + drop_zone_title, + drop_zone_addr, + }; + LibMail.sendClientCreateOrdMail('Kamu Telah Membuat Order ' + trx_code, client_mail, clientCreateOrdMailData); + + // success response + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success create new order'; + apiRes.data = resp; + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + + async emailToVendor(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + + const { + trx_code, + trx_at, + client_id, + client_name, + client_phone, + client_mail, + // client_addr, + client_prefer_type_truck, + // weight, + // cbm, + // koli, + pickup_zone_title, + pickup_zone_addr, + pickup_at, + drop_zone_title, + drop_zone_addr, + vendors, + } = req.body; + + // input validation + const input = { + trx_code, + trx_at, + client_id, + client_name, + client_phone, + client_mail, + // client_addr, + client_prefer_type_truck, + // weight, + // cbm, + // koli, + pickup_zone_title, + pickup_zone_addr, + pickup_at, + drop_zone_title, + drop_zone_addr, + vendors, + }; + + const rulesInput = { + trx_code: 'required|string', + trx_at: 'required|numeric', + client_id: 'required|integer', + client_name: 'required|string|max:255', + client_phone: 'required|string', + client_mail: 'required|email', + // client_addr: 'required|string', + client_prefer_type_truck: 'present|string', + // weight: 'required|numeric', + // cbm: 'required|numeric', + // koli: 'required|numeric', + pickup_zone_title: 'required|string', + pickup_zone_addr: 'required|string', + pickup_at: 'required|numeric', + drop_zone_title: 'required|string', + drop_zone_addr: 'required|string', + vendors: 'required|array', + 'vendors.*.vendor_id': 'required|integer', + 'vendors.*.vendor_name': 'required|string|max:255', + 'vendors.*.vendor_phone': 'required|string', + 'vendors.*.vendor_mail': 'required|email', + // 'vendors.*.vendor_addr': 'present|string', + 'vendors.*.vendor_acc_link': 'required|string', + // 'vendors.*.vendor_reject_link': 'required|string', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + + return res.status(200).json(apiRes); + } + + let resp = {}; + for (let vendor of vendors) { + let bidOrderMailData = { + trx_code, + // client_id, + client_name, + client_phone, + client_mail, + // client_addr, + client_prefer_type_truck: client_prefer_type_truck, + // weight: Number(weight), + // cbm: Number(cbm), + // koli: Number(koli), + pickup_zone_title, + pickup_zone_addr, + pickup_at: moment.unix(pickup_at).format('DD MMM YYYY HH:mm') + ' WIB', + drop_zone_title, + drop_zone_addr, + // vendor_id: vendor.vendor_id, + vendor_name: vendor.vendor_name, + vendor_phone: vendor.vendor_phone, + vendor_mail: vendor.vendor_mail, + vendor_addr: vendor.vendor_addr, + vendor_acc_link: vendor.vendor_acc_link, + }; + LibMail.sendBidOrderMail('Ada Order Masuk', vendor.vendor_mail, bidOrderMailData); + } + + // success response + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success send email'; + apiRes.data = resp; + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + + async emailVdrAccOrder(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + + const { + trx_code, + trx_at, + client_id, + client_name, + client_phone, + client_mail, + // client_addr, + client_prefer_type_truck, + // weight, + // cbm, + // koli, + pickup_zone_title, + pickup_zone_addr, + pickup_at, + drop_zone_title, + drop_zone_addr, + vendors, + drivers, + } = req.body; + + // input validation + const input = { + trx_code, + trx_at, + client_id, + client_name, + client_phone, + client_mail, + // client_addr, + client_prefer_type_truck, + // weight, + // cbm, + // koli, + pickup_zone_title, + pickup_zone_addr, + pickup_at, + drop_zone_title, + drop_zone_addr, + vendors, + drivers, + }; + const rulesInput = { + trx_code: 'required|string', + trx_at: 'required|numeric', + client_id: 'required|integer', + client_name: 'required|string|max:255', + client_phone: 'required|string', + client_mail: 'required|email', + // client_addr: 'required|string', + client_prefer_type_truck: 'present|string', + // weight: 'required|numeric', + // cbm: 'required|numeric', + // koli: 'required|numeric', + pickup_zone_title: 'required|string', + pickup_zone_addr: 'required|string', + pickup_at: 'required|numeric', + drop_zone_title: 'required|string', + drop_zone_addr: 'required|string', + vendors: 'required|array', + 'vendors.*.vendor_id': 'required|integer', + 'vendors.*.vendor_name': 'required|string|max:255', + 'vendors.*.vendor_phone': 'required|string', + 'vendors.*.vendor_mail': 'required|email', + // 'vendors.*.vendor_addr': 'present|string', + 'vendors.*.vendor_acc_at': 'required|numeric', + drivers: 'required|array', + 'drivers.*.driver_id': 'required|integer', + 'drivers.*.driver_name': 'required|string|max:255', + 'drivers.*.driver_phone': 'required|string', + 'drivers.*.driver_mail': 'required|email', + // 'drivers.*.driver_addr': 'present|string', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + + return res.status(200).json(apiRes); + } + + let resp = {}; + for (let vendor of vendors) { + let vdrAccOrderMailData = { + trx_code, + // client_id, + client_name, + client_phone, + client_mail, + // client_addr, + client_prefer_type_truck: client_prefer_type_truck, + // weight: Number(weight), + // cbm: Number(cbm), + // koli: Number(koli), + pickup_zone_title, + pickup_zone_addr, + pickup_at: moment.unix(pickup_at).format('DD MMM YYYY HH:mm') + ' WIB', + drop_zone_title, + drop_zone_addr, + // vendor_id: vendor.vendor_id, + vendor_name: vendor.vendor_name, + vendor_phone: vendor.vendor_phone, + vendor_mail: vendor.vendor_mail, + vendor_addr: vendor.vendor_addr, + acc_at: moment.unix(vendor.vendor_acc_at).format('DD MMM YYYY HH:mm') + ' WIB', + }; + LibMail.sendVdrAccOrderMail('Kamu Telah Menerima Order', vendor.vendor_mail, vdrAccOrderMailData); + } + + for (let driver of drivers) { + let driverGetOrderMailData = { + trx_code, + // client_id, + client_name, + client_phone, + client_mail, + // client_addr, + client_prefer_type_truck: client_prefer_type_truck, + // weight: Number(weight), + // cbm: Number(cbm), + // koli: Number(koli), + pickup_zone_title, + pickup_zone_addr, + pickup_at: moment.unix(pickup_at).format('DD MMM YYYY HH:mm') + ' WIB', + drop_zone_title, + drop_zone_addr, + // driver_id: driver.driver_id, + driver_name: driver.driver_name, + driver_phone: driver.driver_phone, + driver_mail: driver.driver_mail, + driver_addr: driver.driver_addr, + acc_at: moment.unix(vendors[0].vendor_acc_at).format('DD MMM YYYY HH:mm') + ' WIB', + }; + LibMail.sendDrvGetOrderMail('Kamu Mendapatkan Order', driver.driver_mail, driverGetOrderMailData); + } + + let sendClientOrderHaveBeenAccMailData = { + trx_code, + // client_id, + client_name, + client_phone, + client_mail, + // client_addr, + client_prefer_type_truck: client_prefer_type_truck, + // weight: Number(weight), + // cbm: Number(cbm), + // koli: Number(koli), + pickup_zone_title, + pickup_zone_addr, + pickup_at: moment.unix(pickup_at).format('DD MMM YYYY HH:mm') + ' WIB', + drop_zone_title, + drop_zone_addr, + // vendor_id: vendors[0].vendor_id, + vendor_name: vendors[0].vendor_name, + vendor_phone: vendors[0].vendor_phone, + vendor_mail: vendors[0].vendor_mail, + vendor_addr: vendors[0].vendor_addr, + // driver_id: drivers[0].driver_id, + driver_name: drivers[0].driver_name, + driver_phone: drivers[0].driver_phone, + driver_mail: drivers[0].driver_mail, + driver_addr: drivers[0].driver_addr, + acc_at: moment.unix(vendors[0].vendor_acc_at).format('DD MMM YYYY HH:mm') + ' WIB', + }; + LibMail.sendClientOrderHaveBeenAccMail('Order Kamu Telah Diambil Driver', client_mail, sendClientOrderHaveBeenAccMailData); + + // success response + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success send email'; + apiRes.data = resp; + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + + async delayBlastOrderBAK(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + + const { + ord_id, + ord_code, + current_ord_vdr_id, + next_ord_vdr_id, + next_vdr_bid_token, + next_vdr_acc_link, + } = req.body; + + // input validation + const input = { + ord_id, + ord_code, + current_ord_vdr_id, + next_ord_vdr_id, + next_vdr_bid_token, + next_vdr_acc_link, + }; + + const rulesInput = { + ord_id: 'required|integer|min:1', + ord_code: 'required|string', + current_ord_vdr_id: 'required|integer|min:1', + next_ord_vdr_id: 'present|array', + next_vdr_bid_token: 'present|array', + next_vdr_acc_link: 'present|array', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + + return res.status(200).json(apiRes); + } + + LibQueueBlastOrder.addQueue({ + ord_id, + ord_code, + current_ord_vdr_id, + next_ord_vdr_id, + next_vdr_bid_token, + next_vdr_acc_link, + label: 'Delay Blast Order to Another Vendor', + delay: 10 * (60 * 1000), // 600000 || 10 minute || 10 * (60 * 1000) + }); + + // success response + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success blast order'; + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + + async delayBlastOrder(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + + const { + ord_id, + ord_code, + base_link, + } = req.body; + + // input validation + const input = { + ord_id, + ord_code, + base_link, + }; + + const rulesInput = { + ord_id: 'required|integer|min:1', + ord_code: 'required|string', + base_link: 'required|string', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + + return res.status(200).json(apiRes); + } + + LibQueueBlastOrder.addQueue({ + ord_id, + ord_code, + base_link, + delay: 10 * (60 * 1000), // 600000 || 10 minute || 10 * (60 * 1000) + }); + LibQueueBlastOrder.addQueue({ + ord_id, + ord_code, + base_link, + delay: 20 * (60 * 1000), // 600000 || 20 minute || 20 * (60 * 1000) + }); + LibQueueBlastOrder.addQueue({ + ord_id, + ord_code, + base_link, + delay: 30 * (60 * 1000), // 600000 || 30 minute || 30 * (60 * 1000) + }); + + // success response + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success blast order'; + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + + async sendFinanceInfoTfPocket(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + + const { + trx_code, + drv_name, + pickup_zone_title, + pickup_zone_addr, + drop_zone_title, + drop_zone_addr, + pocket_total, + bank_name, + bank_code, + bank_branch_name, + bank_acc_name, + bank_acc_no, + admins, + } = req.body; + + // input validation + const input = { + trx_code, + drv_name, + pickup_zone_title, + pickup_zone_addr, + drop_zone_title, + drop_zone_addr, + pocket_total, + bank_name, + bank_code, + bank_branch_name, + bank_acc_name, + bank_acc_no, + admins, + }; + const rulesInput = { + trx_code: 'required|string|max:255', + drv_name: 'required|string|max:255', + pickup_zone_title: 'required|string|max:255', + pickup_zone_addr: 'required|string', + drop_zone_title: 'required|string|max:255', + drop_zone_addr: 'required|string', + pocket_total: 'required|string|max:255', + bank_name: 'required|string', + bank_code: 'required|string|max:255', + bank_branch_name: 'string', + bank_acc_name: 'required|string', + bank_acc_no: 'required|string', + admins: 'required|array', + // 'admins.*.admin_id': 'required|integer', + 'admins.*.admin_name': 'required|string|max:255', + 'admins.*.admin_phone': 'required|string', + 'admins.*.admin_mail': 'required|email', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + + return res.status(200).json(apiRes); + } + + let resp = {}; + + let mailData = { + trx_code, + drv_name, + pickup_zone_title, + pickup_zone_addr, + drop_zone_title, + drop_zone_addr, + pocket_total, + bank_name, + bank_code, + bank_branch_name, + bank_acc_name, + bank_acc_no, + }; + + for (let admin of admins) { + mailData.admin_name = admin.admin_name; + LibMail.sendFinanceInfoTfPocket('Transfer uang saku order ' + trx_code, admin.admin_mail, mailData); + } + + // success response + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success send mail'; + apiRes.data = resp; + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + + async sendFinanceInfoDanaAmount(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + + const { + trx_code, + drv_name, + pickup_zone_title, + pickup_zone_addr, + drop_zone_title, + drop_zone_addr, + pocket_total, + bank_name, + bank_code, + bank_branch_name, + bank_acc_name, + bank_acc_no, + admins, + } = req.body; + + // input validation + const input = { + trx_code, + drv_name, + pickup_zone_title, + pickup_zone_addr, + drop_zone_title, + drop_zone_addr, + pocket_total, + bank_name, + bank_code, + bank_branch_name, + bank_acc_name, + bank_acc_no, + admins, + }; + const rulesInput = { + trx_code: 'required|string|max:255', + drv_name: 'required|string|max:255', + pickup_zone_title: 'required|string|max:255', + pickup_zone_addr: 'required|string', + drop_zone_title: 'string|max:255', + drop_zone_addr: 'string', + pocket_total: 'required|string|max:255', + bank_name: 'required|string', + bank_code: 'required|string|max:255', + bank_branch_name: 'string', + bank_acc_name: 'required|string', + bank_acc_no: 'required|string', + admins: 'required|array', + // 'admins.*.admin_id': 'required|integer', + 'admins.*.admin_name': 'required|string|max:255', + 'admins.*.admin_phone': 'required|string', + 'admins.*.admin_mail': 'required|email', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + + return res.status(200).json(apiRes); + } + + const danas = await DanaModels.list({'id': DanaModels.PK_ID, 'limit': 1}); + if (danas.length < 1) { + apiRes = JSON.parse(JSON.stringify(response[400])); + apiRes.meta.message = 'dana error'; + return res.status(200).json(apiRes); + } + const dana = danas[0]; + + let resp = {}; + + let mailData = { + trx_code, + drv_name, + pickup_zone_title, + pickup_zone_addr, + drop_zone_title, + drop_zone_addr, + pocket_total, + bank_name, + bank_code, + bank_branch_name, + bank_acc_name, + bank_acc_no, + dana_current: 'Rp'+((new Intl.NumberFormat('id-ID')).format(dana.amt)).split('.').join('-').split(',').join('.').split('-').join(','), // yang . => - || , => . || - => ,, + dana_minimum: 'Rp'+((new Intl.NumberFormat('id-ID')).format(DanaModels.MINIMUM_AMT)).split('.').join('-').split(',').join('.').split('-').join(','), // yang . => - || , => . || - => ,, + }; + + for (let admin of admins) { + mailData.admin_name = admin.admin_name; + LibMail.sendFinanceInfoDanaAmount('Saldo Dana Tidak Mencukupi', admin.admin_mail, mailData); + } + + // success response + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success send mail'; + apiRes.data = resp; + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + +} + +const object = new OrderController(); + +module.exports = object; \ No newline at end of file diff --git a/controllers/ServiceDriverController.js b/controllers/ServiceDriverController.js new file mode 100644 index 0000000..19f79eb --- /dev/null +++ b/controllers/ServiceDriverController.js @@ -0,0 +1,2610 @@ +const fs = require('fs'); +const moment = require('moment'); +const Validator = require('validatorjs'); +const path = require("path"); +const axios = require('axios').default; +const url = require('url'); +const mysql = require('mysql'); +const response = require('../config/response'); +const Helper = require('../library/LibHelper'); +// const LibPassword = require('../library/LibPassword'); +const LibJwt = require('../library/LibJwt'); +const LibHelper = require('../library/LibHelper'); +const LibFirebase = require('../library/LibFirebase'); +const LibCurl = require('../library/LibCurl'); +const LibFile = require('../library/LibFile'); +const LibMail = require('../library/LibMail'); +const LibLogReqResApi = require('../library/LibLogReqResApi'); +const LibImgGeotagging = require('../library/LibImgGeotagging'); +const GpsTracksModels = require('../models/GpsTracksModels'); +const DriversModels = require('../models/DriversModels'); +const OrdersModels = require('../models/OrdersModels'); +const OrdersPickupsModels = require('../models/OrdersPickupsModels'); +const OrdersDropsModels = require('../models/OrdersDropsModels'); +const OrdersPckDropsModels = require('../models/OrdersPckDropsModels'); +const OrdersDriversUploadsModels = require('../models/OrdersDriversUploadsModels'); +const OrdersCheckpointsModels = require('../models/OrdersCheckpointsModels'); +const VhcModels = require('../models/VhcModels'); +const ZoneModels = require('../models/ZoneModels'); +const UsersModels = require('../models/UsersModels'); +const OrdersAItemsModels = require('../models/OrdersAItemsModels'); +const OrdersTerminsModels = require('../models/OrdersTerminsModels'); +const LogbookKeysModels = require('../models/LogbookKeysModels'); +const LogbookOrdersModels = require('../models/LogbookOrdersModels'); +const OrdersLogsTfModels = require('../models/OrdersLogsTfModels'); +const DanaModels = require('../models/DanaModels'); + +Validator.useLang('id'); +moment.locale('id'); + +class ServiceDriverController { + + // AUTHENTIFICATION + async login(req, res) { + let apiRes = {} + try { + const now = moment().unix() + + // input validation + const input = { + phone: req.body.phone, + device_id: req.body.device_id, + fcm_token: req.body.fcm_token, + lat: req.body.lat, + lng: req.body.lng, + brand: req.body.brand || '0', + product: req.body.product || '0', + model: req.body.model || '0', + type: req.body.type || '0', + manufacture: req.body.manufacture || '0', + android_id: req.body.android_id || '0', + host: req.body.host || '0', + hardware: req.body.hardware || '0', + display: req.body.display || '0', + board: req.body.board || '0', + bootloader: req.body.bootloader || '0', + v_sdk_int: req.body.v_sdk_int || '0', + v_preview_sdk_int: req.body.v_preview_sdk_int || '0', + v_release: req.body.v_release || '0', + v_incremental: req.body.v_incremental || '0', + v_codename: req.body.v_codename || '0', + v_base_os: req.body.v_base_os || '0', + v_security_patch: req.body.v_security_patch || '0', + // password: req.body.password, + }; + const rulesInput = { + phone: 'required|integer', + device_id: 'required|string|max:16', + fcm_token: 'required|string|max:255', + lat: 'required|string|max:125', + lng: 'required|string|max:125', + brand: 'string|max:125', + product: 'string|max:125', + model: 'string|max:125', + type: 'string|max:125', + manufacture: 'string|max:125', + android_id: 'string|max:125', + host: 'string|max:125', + hardware: 'string|max:125', + display: 'string|max:125', + board: 'string|max:125', + bootloader: 'string|max:125', + v_sdk_int: 'string|max:125', + v_preview_sdk_int: 'string|max:125', + v_release: 'string|max:125', + v_incremental: 'string|max:125', + v_codename: 'string|max:125', + v_base_os: 'string|max:125', + v_security_patch: 'string|max:125', + // password: 'required|string', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + // login + const getDrivers = await DriversModels.findPhone(input.phone); + if (getDrivers.length < 1) { + apiRes = JSON.parse(JSON.stringify(response[404])); + apiRes.meta.code += '_1'; + apiRes.meta.message = 'account not found'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + // const isPwValid = await LibPassword.checkPw(getDrivers[0].password, input.password); + // if (!isPwValid) { + // apiRes.meta = JSON.parse(JSON.stringify(response['wrong_password'].meta)); + // return res.status(200).json(apiRes); + // } + + /** + * create or update t_users based on t_drivers data without password, with role as driver + * create or update t_phone_devices + * case multiple device => update hanya berlaku jika device_id(IMEI) sama, jadi did bisa duplicate namun device_id(IMEI) tidak ada yang duplicate + * case single device => update hanya berlaku jika did sama, jadi tidak ada did dan device_id(IMEI) yang duplicate + * harus tentuin salah satu mau single / multiple, soalnya nanti bingung ngambil fcm_tokennya + * is_login ? taro di t_phone_devices aja, jadi ketauan kalo dia logout + * login_lat & login_lng ? taro di t_phone_devices aja, jadi ketauan device ini adanya dimana + * jika sedang ada yang login maka driver tidak bisa dihapus + */ + + // yang sekarang 1 device 1 driver + const checkDeviceByDid = await DriversModels.getDeviceByDid(getDrivers[0].id); + let phone_device_id = 0; + if (checkDeviceByDid.length < 1) { + const checkDeviceByImei = await DriversModels.getDeviceByImei(input.device_id); + if (checkDeviceByImei.length < 1) { + const insDevice = { ...input }; + insDevice.did = getDrivers[0].id; + insDevice.is_active = DriversModels.IS_ACTIVE; + insDevice.is_login = DriversModels.IS_LOGIN; + insDevice.login_lat = input.lat; + insDevice.login_lng = input.lng; + insDevice.login_at = now; + insDevice.crt = now; + insDevice.updt = now; + delete insDevice.phone; + delete insDevice.lat; + delete insDevice.lng; + const insPhoneDevice = await DriversModels.insPhoneDevice(insDevice); + phone_device_id = insPhoneDevice.insertId; + } else { + if (checkDeviceByImei[0].is_login === DriversModels.IS_LOGIN) { + if (checkDeviceByImei[0].device_id !== input.device_id) { // || checkDeviceByImei[0].phone !== input.phone + apiRes = JSON.parse(JSON.stringify(response[400])); + apiRes.meta.code += '_2'; + apiRes.meta.message = 'account is used by another phone, please contact customer service'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + } + const updtDevice = { ...input }; + updtDevice.did = getDrivers[0].id; + updtDevice.is_active = DriversModels.IS_ACTIVE; + updtDevice.is_login = DriversModels.IS_LOGIN; + updtDevice.login_lat = input.lat; + updtDevice.login_lng = input.lng; + updtDevice.login_at = now; + updtDevice.updt = now; + delete updtDevice.phone; + delete updtDevice.lat; + delete updtDevice.lng; + const updtPhoneDevice = await DriversModels.updtPhoneDevice(updtDevice, checkDeviceByImei[0].id); + phone_device_id = checkDeviceByImei[0].id; + } + } else { + if (checkDeviceByDid[0].is_login === DriversModels.IS_LOGIN) { + if (checkDeviceByDid[0].device_id !== input.device_id) { // || checkDeviceByDid[0].phone !== input.phone + apiRes = JSON.parse(JSON.stringify(response[400])); + apiRes.meta.code += '_2'; + apiRes.meta.message = 'account is used by another phone, please contact customer service'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + } + const updtDevice = { ...input }; + updtDevice.did = getDrivers[0].id; + updtDevice.is_active = DriversModels.IS_ACTIVE; + updtDevice.is_login = DriversModels.IS_LOGIN; + updtDevice.login_lat = input.lat; + updtDevice.login_lng = input.lng; + updtDevice.login_at = now; + updtDevice.updt = now; + delete updtDevice.phone; + delete updtDevice.lat; + delete updtDevice.lng; + const updtPhoneDevice = await DriversModels.updtPhoneDevice(updtDevice, checkDeviceByDid[0].id); + phone_device_id = checkDeviceByDid[0].id; + } + + delete getDrivers[0].client_group_id; + delete getDrivers[0].client_div_id; + delete getDrivers[0].client_gp_id; + // delete getDrivers[0].status; + delete getDrivers[0].is_in_ord; + delete getDrivers[0].ord_id; + delete getDrivers[0].ord_code; + delete getDrivers[0].ord_ids; + delete getDrivers[0].ord_code; + + // success response + const jwt = await LibJwt.createToken({ + did: getDrivers[0].id, + phone: getDrivers[0].phone, + device_id: input.device_id, + phone_device_id, + uid: 0, + }); + + const profileDriver = { + drv_id: getDrivers[0].id, + nik: getDrivers[0].nik, + fullname: getDrivers[0].fullname, + fullname2: getDrivers[0].fullname2 || '', + phone: getDrivers[0].phone_code + '' +getDrivers[0].phone, + phone2: getDrivers[0].phone2_code + '' +getDrivers[0].phone2, + email: getDrivers[0].email || '', + dob: moment(getDrivers[0].dob).format('DD-MM-YYYY'), + age: getDrivers[0].age || 0, + gender: (getDrivers[0].gender === 1) ? 'Laki-Laki' : 'Perempuan', + blood: getDrivers[0].blood || '', + fulladdress: getDrivers[0].fulladdress || '', + vdr_id: getDrivers[0].vendor_id || 0, + // status: getDrivers[0].status, + // is_in_ord: getDrivers[0].is_in_ord, + // ord_ids: (getDrivers[0].ord_ids === null) ? getDrivers[0].ord_ids : JSON.parse(getDrivers[0].ord_ids), + token: jwt.token, + }; + + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success login'; + apiRes.data = profileDriver; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + LibLogReqResApi.log(req, apiRes); + return res.status(500).json(apiRes); + } + } + + async profile(req, res) { + let apiRes = {} + try { + const now = moment().unix(); + const { did } = req.auth; + + const getDrivers = await DriversModels.find(did); + if (getDrivers.length < 1) { + apiRes = JSON.parse(JSON.stringify(response[404])); + apiRes.meta.code += '_1'; + apiRes.meta.message = 'account not found, please login again'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + const profileDriver = { + drv_id: getDrivers[0].id, + nik: getDrivers[0].nik, + fullname: getDrivers[0].fullname, + fullname2: getDrivers[0].fullname2 || '', + phone: getDrivers[0].phone_code + '' +getDrivers[0].phone, + phone2: getDrivers[0].phone2_code + '' +getDrivers[0].phone2, + email: getDrivers[0].email || '', + dob: (getDrivers[0].dob) ? moment(getDrivers[0].dob).format('DD-MM-YYYY') : '', + age: getDrivers[0].age || 0, + gender: (getDrivers[0].gender === 1) ? 'Laki-Laki' : 'Perempuan', + blood: getDrivers[0].blood || '', + fulladdress: getDrivers[0].fulladdress || '', + vdr_id: getDrivers[0].vendor_id || 0, + // status: getDrivers[0].status, + // is_in_ord: getDrivers[0].is_in_ord, + // ord_ids: (getDrivers[0].ord_ids === null) ? getDrivers[0].ord_ids : JSON.parse(getDrivers[0].ord_ids), + }; + + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.data = profileDriver; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + LibLogReqResApi.log(req, apiRes); + return res.status(500).json(apiRes); + } + } + + async logout(req, res) { + let apiRes = {} + try { + const now = moment().unix(); + const { phone_device_id } = req.auth; + + const updtDevice = { + is_login: DriversModels.IS_LOGOUT, + logout_at: now, + }; + const updtPhoneDevice = await DriversModels.updtPhoneDevice(updtDevice, phone_device_id); + + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success logout'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + LibLogReqResApi.log(req, apiRes); + return res.status(500).json(apiRes); + } + } + + // JOBS + async listActiveJobs(req, res) { + let apiRes = {} + try { + const now = moment().unix(); + + // console.log(Buffer.from(`32_34_34_28`, 'ascii').toString('hex')); + + const { did, device_id, phone } = req.auth; + + const filter = { + is_active: OrdersModels.IS_ACTIVE, + // order_status: [OrdersModels.STTS_HAVE_GET_VHC,OrdersModels.STTS_PCK,OrdersModels.STTS_GO,OrdersModels.STTS_ARV,OrdersModels.STTS_DROP], + delivery_statuses: [ + OrdersPckDropsModels.STTS_DELIVERY_OTW_PICKUP,OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_PICKUP,OrdersPckDropsModels.STTS_DELIVERY_PROCESS_PICKUP + ,OrdersPckDropsModels.STTS_DELIVERY_FINISH_PICKUP,OrdersPckDropsModels.STTS_DELIVERY_TRAVEL_DOC,OrdersPckDropsModels.STTS_DELIVERY_OTW_DROP + ,OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_DROP,OrdersPckDropsModels.STTS_DELIVERY_PROCESS_DROP,OrdersPckDropsModels.STTS_DELIVERY_FINISH_DROP + // ,OrdersPckDropsModels.STTS_DELIVERY_HANDOVER_DOC + ], + get_prefer_type_truck: 1, + couple_pck_drop: 1, + get_pic_zone: 1, + did, + }; + const activeOrders = await OrdersModels.listOrders(filter); + if (activeOrders.length < 1) { + apiRes = JSON.parse(JSON.stringify(response[404])); + apiRes.meta.code = '200'; // += '_1'; + apiRes.meta.message = 'there are no active orders'; + apiRes.data = []; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const formattedActiveOrders = [], includedPckId = [], includedDropId = []; + for (const row of activeOrders) { + if (includedPckId.includes(row.ord_pck_id) || includedDropId.includes(row.ord_drop_id)) continue; + includedPckId.push(row.ord_pck_id); + includedDropId.push(row.ord_drop_id); + + const detail_id = Buffer.from(`${row.ord_id}_${row.ord_pck_id}_${row.ord_drop_id}_${row.ord_pck_drop_id}`, 'ascii').toString('hex'); + // const decoded_detail_id = Buffer.from('34365f34305f3339', 'hex').toString('ascii'); + + let status_desc = ''; + if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_OTW_PICKUP) { status_desc = 'Kendaraan Menuju Lokasi Jemput'; } + else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_PICKUP) { status_desc = 'Kendaraan Tiba dilokasi Jemput'; } + else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_PROCESS_PICKUP) { status_desc = 'Kendaraan Memuat Barang'; } + else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_FINISH_PICKUP) { status_desc = 'Kendaraan Selesai Memuat Barang'; } + else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_TRAVEL_DOC) { status_desc = 'Driver Sudah Mengupload Dokumen Perjalanan'; } + else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_OTW_DROP) { status_desc = 'Kendaraan Menuju Lokasi Pengantaran'; } + else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_DROP) { status_desc = 'Kendaraan Sampai Dilokasi Pengantaran'; } + else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_PROCESS_DROP) { status_desc = 'Kendaraan Membongkar Barang'; } + else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_FINISH_DROP) { status_desc = 'Kendaraan Selesai Membongkar Barang'; } + else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_HANDOVER_DOC) { status_desc = 'Driver Sudah Mengupload Dokumen Serah Terima'; } + + // validate is_going / ongoing by pickup date + let is_ongoing = false; + if (row.set_pck_at) { + let cur_date = moment.unix(now).set({hour:0,minute:0,second:0,millisecond:0}); // as start + let pck_date = moment.unix(row.set_pck_at).set({hour:0,minute:0,second:0,millisecond:0}); // as end + let duration = moment.duration(pck_date.diff(cur_date)); + if (duration.asDays() <= 0) { + is_ongoing = true; + } + } + + // https://stackoverflow.com/questions/23299950/convert-date-to-utc-using-moment-js + formattedActiveOrders.push({ + detail_id, + // ord_pck_drop_id: row.ord_pck_drop_id, + ord_id: row.ord_id, + ord_code: row.ord_code, + // pck_total: row.pck_total, + // drop_total: row.drop_total, + is_ongoing, + pck: { + id: row.ord_pck_id, + set_at_unix: row.set_pck_at, + // set_at_raw: (row.set_pck_at != 0) ? moment.unix(row.set_pck_at).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '', // utc + set_at_raw: (row.set_pck_at != 0) ? moment.unix(row.set_pck_at).format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '', // gmt +7 + // stts: row.stts_pck, + name: row.pck_name, + addr: row.pck_addr, + pic_name: row.pck_pic_name, + pic_phone: row.pck_pic_phone_code + '' + row.pck_pic_phone_val, + pic_mail: row.pck_pic_mail || '', + client_name: row.c_name, + client_phone: row.c_phone_code + '' + row.c_phone_val, + client_mail: row.c_mail, + client_prefer_truck_type: row.prefer_truck_type_name || '', + }, + // going_at_unix: row.going_at, + // going_at_raw: (row.going_at != 0) ? moment.unix(row.going_at).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '', + // going_note: row.going_note, + drop: { + id: row.ord_drop_id, + // stts: row.ord_drop_stts, + name: row.drop_name, + addr: row.drop_addr, + pic_name: row.drop_pic_name, + pic_phone: row.drop_pic_phone_code + '' + row.drop_pic_phone_val, + pic_mail: row.drop_pic_mail || '', + client_name: row.c_name, + client_phone: row.c_phone_code + '' + row.c_phone_val, + client_mail: row.c_mail, + client_prefer_truck_type: row.prefer_truck_type_name || '', + }, + // arrived_at_unix: row.arrived_at, + // arrived_at_raw: (row.arrived_at != 0) ? moment.unix(row.arrived_at).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '', + // arrived_note: row.arrived_note, + lead_time: row.lead_time, + lead_time_unit: row.lead_time_unit, + // buy_price: row.buy_price, + status: row.stts_delivery, + status_desc, + // c_name: row.c_name, + // c_phone: row.c_phone_code + '' + row.c_phone_val, + // c_mail: row.c_mail, + // prefer_truck_type: row.prefer_truck_type, + // prefer_truck_type_name: row.prefer_truck_type_name || '', + vdr: { + name: row.vdr_name, + phone: row.vdr_phone_code + '' + row.vdr_phone_val, + mail: row.vdr_mail, + addr: row.vdr_addr, + }, + drv: { + name: row.drv_name, + kenek_name: row.drv_name2, + phone: row.drv_phone_code + '' + row.drv_phone_val, + kenek_phone: row.drv_phone2_code + '' + row.drv_phone2_val, + mail: row.drv_mail, + addr: row.drv_addr, + }, + vhc: { + name_bukan_nopol: row.vhc_name, + nopol1: row.vhc_nopol1, + nopol2: row.vhc_nopol2, + nopol3: row.vhc_nopol3, + nopol_full: row.vhc_nopol1 + ' ' + row.vhc_nopol2 + ' ' + row.vhc_nopol3, + }, + }); + } + + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.data = formattedActiveOrders; + // apiRes.raw = activeOrders; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + LibLogReqResApi.log(req, apiRes); + return res.status(500).json(apiRes); + } + } + + async detailJobs(req, res) { + let apiRes = {} + try { + const now = moment().unix(); + + const { did, device_id, phone } = req.auth; + const { detail_id } = req.params; + + // input validation + const input = { + detail_id, + }; + const rulesInput = { + detail_id: 'required|string', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const decoded_detail_id = Buffer.from(detail_id, 'hex').toString('ascii'); + const split_detail_id = decoded_detail_id.split('_'); + if (split_detail_id.length !== 4) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.code += '_1'; + apiRes.meta.message = 'detail id not valid'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + const [ ord_id, pck_id, drop_id, ord_pck_drop_id ] = split_detail_id; + + const filter = { + ord_id, + pck_id, + drop_id, + ord_pck_drop_id, + // is_active: OrdersModels.IS_ACTIVE, + // order_status: [OrdersModels.STTS_HAVE_GET_VHC,OrdersModels.STTS_PCK,OrdersModels.STTS_GO,OrdersModels.STTS_ARV,OrdersModels.STTS_DROP], + get_prefer_type_truck: 1, + couple_pck_drop: 1, + get_pic_zone: 1, + did, + }; + const activeOrders = await OrdersModels.listOrders(filter); + if (activeOrders.length < 1) { + apiRes = JSON.parse(JSON.stringify(response[404])); + apiRes.meta.code += '_4'; + apiRes.meta.message = 'job not found'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const drvUps = await OrdersDriversUploadsModels.list({ ord_id,pck_id,drop_id,ord_pck_drop_id }); + /** + * 0 => disable + * 1 => enable + * 2 => finish + */ + const menu = { + menu_arrived_pickup: { + content: '1. Foto sudah dilokasi muat', + status: 0, + photo: '', + }, + menu_process_pickup: { + content: '2. Foto sedang memuat barang', + status: 0, + photo: '', + }, + menu_finish_pickup: { + content: '3. Foto selesai memuat barang', + status: 0, + photo: '', + }, + menu_travel_document: { + content: '4. Foto dokumen perjalanan', + status: 0, + photo: '', + }, + menu_otw_drop: { + content: '5. Foto saat diperjalanan (/2jam)', + status: 0, + photo: [], + }, + menu_arrived_drop: { + content: '6. Foto tiba dilokasi bongkar', + status: 0, + photo: '', + }, + menu_process_drop: { + content: '7. Foto proses bongkar', + status: 0, + photo: '', + }, + menu_finish_drop: { + content: '8. Foto selesai bongkar', + status: 0, + photo: '', + }, + menu_handover_document: { + content: '9. Foto dokumen serah terima', + status: 0, + photo: '', + }, + menu_accident: { + content: 'Menu Accident', + status: 1, + photo: [], + }, + }; + for (const drvUp of drvUps) { + if (drvUp.stts === OrdersDriversUploadsModels.PHOTO_STATUS_ARRIVED_PICKUP) { + menu.menu_arrived_pickup.status = 2; + menu.menu_arrived_pickup.photo = drvUp.img; + } else if (drvUp.stts === OrdersDriversUploadsModels.PHOTO_STATUS_PROCESS_PICKUP) { + menu.menu_process_pickup.status = 2; + menu.menu_process_pickup.photo = drvUp.img; + } else if (drvUp.stts === OrdersDriversUploadsModels.PHOTO_STATUS_FINISH_PICKUP) { + menu.menu_finish_pickup.status = 2; + menu.menu_finish_pickup.photo = drvUp.img; + } else if (drvUp.stts === OrdersDriversUploadsModels.PHOTO_STATUS_TRAVEL_DOCUMENT) { + menu.menu_travel_document.status = 2; + menu.menu_travel_document.photo = drvUp.img; + } else if (drvUp.stts === OrdersDriversUploadsModels.PHOTO_STATUS_OTW_DROP) { + // if (row.drv_app_lock_menu_otw_drop_at !== 0) { menu.menu_otw_drop.status = 2; } else { menu.menu_otw_drop.status = 1; } + menu.menu_otw_drop.status = 2; + menu.menu_otw_drop.photo.push(drvUp.img); + } else if (drvUp.stts === OrdersDriversUploadsModels.PHOTO_STATUS_ARRIVED_DROP) { + menu.menu_arrived_drop.status = 2; + menu.menu_arrived_drop.photo = drvUp.img; + } else if (drvUp.stts === OrdersDriversUploadsModels.PHOTO_STATUS_PROCESS_DROP) { + menu.menu_process_drop.status = 2; + menu.menu_process_drop.photo = drvUp.img; + } else if (drvUp.stts === OrdersDriversUploadsModels.PHOTO_STATUS_FINISH_DROP) { + menu.menu_finish_drop.status = 2; + menu.menu_finish_drop.photo = drvUp.img; + } else if (drvUp.stts === OrdersDriversUploadsModels.PHOTO_STATUS_HANDOVER_DOCUMENT) { + menu.menu_handover_document.status = 2; + menu.menu_handover_document.photo = drvUp.img; + } else if (drvUp.stts === OrdersDriversUploadsModels.PHOTO_STATUS_ACCIDENT) { + menu.menu_accident.status = 1; + menu.menu_accident.photo.push(drvUp.img); + } + } + + const formattedActiveOrders = [], includedPckId = [], includedDropId = []; + for (const row of activeOrders) { + if (includedPckId.includes(row.ord_pck_id) || includedDropId.includes(row.ord_drop_id)) continue; + includedPckId.push(row.ord_pck_id); + includedDropId.push(row.ord_drop_id); + + const detail_id = Buffer.from(`${row.ord_id}_${row.ord_pck_id}_${row.ord_drop_id}_${row.ord_pck_drop_id}`, 'ascii').toString('hex'); + // const decoded_detail_id = Buffer.from('34365f34305f3339', 'hex').toString('ascii'); + + let status_desc = ''; + let is_wait_aprv_otw_drop = 0; // 0=>disable, 1=>enable + let is_wait_aprv_otw_drop_desc = ''; + + // old way + // if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_OTW_PICKUP) { status_desc = 'Kendaraan Menuju Lokasi Jemput'; menu.menu_arrived_pickup.status = 1; } + // else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_PICKUP) { status_desc = 'Kendaraan Tiba dilokasi Jemput'; menu.menu_process_pickup.status = 1; } + // else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_PROCESS_PICKUP) { status_desc = 'Kendaraan Memuat Barang'; menu.menu_finish_pickup.status = 1; } + // else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_FINISH_PICKUP) { + // status_desc = 'Kendaraan Selesai Memuat Barang'; + // if (menu.menu_travel_document.status === 2) { menu.menu_otw_drop.status = 1; } else { menu.menu_travel_document.status = 1; } + // } + // else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_OTW_DROP) { + // status_desc = 'Kendaraan Menuju Lokasi Pengantaran'; + // if (row.drv_app_lock_menu_otw_drop_at !== 0) { menu.menu_arrived_drop.status = 1; } else { menu.menu_otw_drop.status = 1; } + // } + // else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_DROP) { status_desc = 'Kendaraan Sampai Dilokasi Pengantaran'; menu.menu_process_drop.status = 1; } + // else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_PROCESS_DROP) { status_desc = 'Kendaraan Membongkar Barang'; menu.menu_finish_drop.status = 1; } + // else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_FINISH_DROP) { + // status_desc = 'Kendaraan Selesai Membongkar Barang'; + // if (menu.menu_handover_document.status === 2) { } else { menu.menu_handover_document.status = 1; } + // } + // new way + if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_OTW_PICKUP) { status_desc = 'Kendaraan Menuju Lokasi Jemput'; menu.menu_arrived_pickup.status = 1; } + else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_PICKUP) { status_desc = 'Kendaraan Tiba dilokasi Jemput'; menu.menu_process_pickup.status = 1; } + else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_PROCESS_PICKUP) { status_desc = 'Kendaraan Memuat Barang'; menu.menu_finish_pickup.status = 1; } + else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_FINISH_PICKUP) { status_desc = 'Kendaraan Selesai Memuat Barang'; menu.menu_travel_document.status = 1; } + else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_TRAVEL_DOC) { + status_desc = 'Driver Sudah Mengupload Dokumen Perjalanan'; + if (row.is_aprv_pck == OrdersPckDropsModels.IS_APRV_YES) { + menu.menu_otw_drop.status = 1; + is_wait_aprv_otw_drop = 1; + is_wait_aprv_otw_drop_desc = 'Menunggu persetujuan dari checker'; + } else { + menu.menu_otw_drop.status = 0; // disable sementara, seharusnya 0 + } + } + else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_OTW_DROP) { + status_desc = 'Kendaraan Menuju Lokasi Pengantaran'; + if (row.drv_app_lock_menu_otw_drop_at !== 0) { menu.menu_arrived_drop.status = 1; } else { menu.menu_otw_drop.status = 1; } + } + else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_DROP) { status_desc = 'Kendaraan Sampai Dilokasi Pengantaran'; menu.menu_process_drop.status = 1; } + else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_PROCESS_DROP) { status_desc = 'Kendaraan Membongkar Barang'; menu.menu_finish_drop.status = 1; } + else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_FINISH_DROP) { status_desc = 'Kendaraan Selesai Membongkar Barang'; menu.menu_handover_document.status = 1; } + else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_HANDOVER_DOC) { status_desc = 'Driver Sudah Mengupload Dokumen Serah Terima'; } + + // validate is_going / ongoing by pickup date + let is_ongoing = false; + if (row.set_pck_at) { + let cur_date = moment.unix(now).set({hour:0,minute:0,second:0,millisecond:0}); // as start + let pck_date = moment.unix(row.set_pck_at).set({hour:0,minute:0,second:0,millisecond:0}); // as end + let duration = moment.duration(pck_date.diff(cur_date)); + if (duration.asDays() <= 0) { + is_ongoing = true; + } + } + + formattedActiveOrders.push({ + detail_id, + // ord_pck_drop_id: row.ord_pck_drop_id, + ord_id: row.ord_id, + ord_code: row.ord_code, + // pck_total: row.pck_total, + // drop_total: row.drop_total, + is_ongoing, + pck: { + id: row.ord_pck_id, + set_at_unix: row.set_pck_at, + // set_at_raw: (row.set_pck_at != 0) ? moment.unix(row.set_pck_at).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '', // utc + set_at_raw: (row.set_pck_at != 0) ? moment.unix(row.set_pck_at).format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '', // gmt +7 + // stts: row.stts_pck, + name: row.pck_name, + addr: row.pck_addr, + pic_name: row.pck_pic_name, + pic_phone: row.pck_pic_phone_code + '' + row.pck_pic_phone_val, + pic_mail: row.pck_pic_mail || '', + client_name: row.c_name, + client_phone: row.c_phone_code + '' + row.c_phone_val, + client_mail: row.c_mail, + client_prefer_truck_type: row.prefer_truck_type_name || '', + }, + // going_at_unix: row.going_at, + // going_at_raw: (row.going_at != 0) ? moment.unix(row.going_at).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '', + // going_note: row.going_note, + drop: { + id: row.ord_drop_id, + // stts: row.ord_drop_stts, + name: row.drop_name, + addr: row.drop_addr, + pic_name: row.drop_pic_name, + pic_phone: row.drop_pic_phone_code + '' + row.drop_pic_phone_val, + pic_mail: row.drop_pic_mail || '', + client_name: row.c_name, + client_phone: row.c_phone_code + '' + row.c_phone_val, + client_mail: row.c_mail, + client_prefer_truck_type: row.prefer_truck_type_name || '', + }, + // arrived_at_unix: row.arrived_at, + // arrived_at_raw: (row.arrived_at != 0) ? moment.unix(row.arrived_at).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '', + // arrived_note: row.arrived_note, + lead_time: row.lead_time, + lead_time_unit: row.lead_time_unit, + // buy_price: row.buy_price, + status: row.stts_delivery, + status_desc, + is_wait_aprv_otw_drop, + is_wait_aprv_otw_drop_desc, + // c_name: row.c_name, + // c_phone: row.c_phone_code + '' + row.c_phone_val, + // c_mail: row.c_mail, + // prefer_truck_type: row.prefer_truck_type, + // prefer_truck_type_name: row.prefer_truck_type_name || '', + vdr: { + name: row.vdr_name, + phone: row.vdr_phone_code + '' + row.vdr_phone_val, + mail: row.vdr_mail, + addr: row.vdr_addr, + }, + drv: { + name: row.drv_name, + kenek_name: row.drv_name2, + phone: row.drv_phone_code + '' + row.drv_phone_val, + kenek_phone: row.drv_phone2_code + '' + row.drv_phone2_val, + mail: row.drv_mail, + addr: row.drv_addr, + }, + vhc: { + name_bukan_nopol: row.vhc_name, + nopol1: row.vhc_nopol1, + nopol2: row.vhc_nopol2, + nopol3: row.vhc_nopol3, + nopol_full: row.vhc_nopol1 + ' ' + row.vhc_nopol2 + ' ' + row.vhc_nopol3, + }, + menu, + }); + } + + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.data = formattedActiveOrders[0]; + // apiRes.raw = activeOrders; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + LibLogReqResApi.log(req, apiRes); + return res.status(500).json(apiRes); + } + } + + async jobPhotoTransitions(req, res) { + let apiRes = {} + try { + const now = moment().unix(); + + const { did, device_id, phone } = req.auth; + const { detail_id, type_up_photo, photo, lat, lng, photo_at } = req.body; + // input validation + const input = { + detail_id, + type_up_photo, + photo, + lat, + lng, + photo_at, + }; + const rulesInput = { + detail_id: 'required|string', + type_up_photo: 'required|numeric|max:12', + photo: 'required|string', + lat: 'required|string|max:125', + lng: 'required|string|max:125', + photo_at: 'required|numeric', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const decoded_detail_id = Buffer.from(detail_id, 'hex').toString('ascii'); + const split_detail_id = decoded_detail_id.split('_'); + if (split_detail_id.length !== 4) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.code += '_1'; + apiRes.meta.message = 'detail id not valid'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + const [ ord_id, pck_id, drop_id, ord_pck_drop_id ] = split_detail_id; + + const required_type_up_photo = [OrdersDriversUploadsModels.PHOTO_STATUS_OTW_PICKUP,OrdersDriversUploadsModels.PHOTO_STATUS_ARRIVED_PICKUP,OrdersDriversUploadsModels.PHOTO_STATUS_PROCESS_PICKUP,OrdersDriversUploadsModels.PHOTO_STATUS_FINISH_PICKUP,OrdersDriversUploadsModels.PHOTO_STATUS_TRAVEL_DOCUMENT,OrdersDriversUploadsModels.PHOTO_STATUS_OTW_DROP,OrdersDriversUploadsModels.PHOTO_STATUS_ARRIVED_DROP,OrdersDriversUploadsModels.PHOTO_STATUS_PROCESS_DROP,OrdersDriversUploadsModels.PHOTO_STATUS_FINISH_DROP,OrdersDriversUploadsModels.PHOTO_STATUS_HANDOVER_DOCUMENT,OrdersDriversUploadsModels.PHOTO_STATUS_ACCIDENT]; + if (!required_type_up_photo.includes(type_up_photo)) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.code += '_2'; + apiRes.meta.message = 'type up photo not valid'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const filter = { + ord_id, + pck_id, + drop_id, + ord_pck_drop_id, + // is_active: OrdersModels.IS_ACTIVE, + // order_status: [OrdersModels.STTS_HAVE_GET_VHC,OrdersModels.STTS_PCK,OrdersModels.STTS_GO,OrdersModels.STTS_ARV,OrdersModels.STTS_DROP], + get_prefer_type_truck: 1, + couple_pck_drop: 1, + get_pic_zone: 1, + did, + }; + const activeOrders = await OrdersModels.listOrders(filter); + if (activeOrders.length < 1) { + apiRes = JSON.parse(JSON.stringify(response[404])); + apiRes.meta.code += '_4'; + apiRes.meta.message = 'job not found'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + // validate inside zone + const check_pck_zone = [OrdersDriversUploadsModels.PHOTO_STATUS_ARRIVED_PICKUP,OrdersDriversUploadsModels.PHOTO_STATUS_PROCESS_PICKUP,OrdersDriversUploadsModels.PHOTO_STATUS_FINISH_PICKUP,OrdersDriversUploadsModels.PHOTO_STATUS_TRAVEL_DOCUMENT]; + const check_drop_zone = [OrdersDriversUploadsModels.PHOTO_STATUS_ARRIVED_DROP,OrdersDriversUploadsModels.PHOTO_STATUS_PROCESS_DROP,OrdersDriversUploadsModels.PHOTO_STATUS_FINISH_DROP,OrdersDriversUploadsModels.PHOTO_STATUS_HANDOVER_DOCUMENT]; + if (check_pck_zone.includes(type_up_photo)) { + const inCircle = await ZoneModels.getOrdInCircle(lat, lng, { zid: activeOrders[0].pck_id }); + const inShape = await ZoneModels.getOrdInShape(lat, lng, { zid: activeOrders[0].pck_id }); + if (inCircle.length < 1 && inShape.length < 1) { + apiRes = JSON.parse(JSON.stringify(response[400])); + apiRes.meta.code += '_2'; + apiRes.meta.message = 'driver should inside pickup zone'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + } + // else if (check_drop_zone.includes(type_up_photo)) { + // const inCircle = await ZoneModels.getOrdInCircle(lat, lng, { zid: activeOrders[0].drop_id }); + // const inShape = await ZoneModels.getOrdInShape(lat, lng, { zid: activeOrders[0].drop_id }); + // if (inCircle.length < 1 && inShape.length < 1) { + // apiRes = JSON.parse(JSON.stringify(response[400])); + // apiRes.meta.code += '_3'; + // apiRes.meta.message = 'driver should inside drop zone'; + LibLogReqResApi.log(req, apiRes); + // return res.status(200).json(apiRes); + // } + // } + + // status transitions + const insUploads = []; + const updtOrd = {}, updtPck = {}, updtDrop = {}, updtPckDrop = {}; + if (type_up_photo == OrdersDriversUploadsModels.PHOTO_STATUS_ARRIVED_PICKUP) { + // t_orders + updtOrd.id = ord_id; + updtOrd.status = OrdersModels.STTS_PCK; + // t_orders_pickups + updtPck.id = pck_id; + updtPck.stts_pck = OrdersPickupsModels.STTS_PCK_WAIT; + // updtPck.pck_enter_at = now; + // t_orders_pck_drops + updtPckDrop.id = ord_pck_drop_id; + updtPckDrop.stts = OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_PICKUP; + } else if (type_up_photo == OrdersDriversUploadsModels.PHOTO_STATUS_PROCESS_PICKUP) { + // t_orders + updtOrd.id = ord_id; + updtOrd.status = OrdersModels.STTS_PCK; + // t_orders_pickups + updtPck.id = pck_id; + updtPck.stts_pck = OrdersPickupsModels.STTS_PCK_PICKING; + updtPck.pck_at = now; + // t_orders_pck_drops + updtPckDrop.id = ord_pck_drop_id; + updtPckDrop.stts = OrdersPckDropsModels.STTS_DELIVERY_PROCESS_PICKUP; + } else if (type_up_photo == OrdersDriversUploadsModels.PHOTO_STATUS_FINISH_PICKUP) { + // t_orders + updtOrd.id = ord_id; + updtOrd.status = OrdersModels.STTS_GO; + updtOrd.going_at = now; + // t_orders_pickups + updtPck.id = pck_id; + updtPck.stts_pck = OrdersPickupsModels.STTS_PCK_PICKED; + // t_orders_pck_drops + updtPckDrop.id = ord_pck_drop_id; + updtPckDrop.stts = OrdersPckDropsModels.STTS_DELIVERY_FINISH_PICKUP; + } else if (type_up_photo == OrdersDriversUploadsModels.PHOTO_STATUS_TRAVEL_DOCUMENT) { + // t_orders + updtOrd.id = ord_id; + updtOrd.status = OrdersModels.STTS_GO; + // t_orders_pickups + updtPck.id = pck_id; + updtPck.stts_pck = OrdersPickupsModels.STTS_PCK_PICKED; + // updtPck.pck_leave_at = now; + // t_orders_pck_drops + updtPckDrop.id = ord_pck_drop_id; + updtPckDrop.stts = OrdersPckDropsModels.STTS_DELIVERY_TRAVEL_DOC; + } else if (type_up_photo == OrdersDriversUploadsModels.PHOTO_STATUS_OTW_DROP) { + // t_orders + updtOrd.id = ord_id; + updtOrd.status = OrdersModels.STTS_GO; + // t_orders_pickups + updtPck.id = pck_id; + updtPck.stts_pck = OrdersPickupsModels.STTS_PCK_PICKED; + // t_orders_drops + updtDrop.id = drop_id; + updtDrop.stts_drop = OrdersDropsModels.STTS_DROP_WAIT; + // t_orders_pck_drops + updtPckDrop.id = ord_pck_drop_id; + updtPckDrop.stts = OrdersPckDropsModels.STTS_DELIVERY_OTW_DROP; + } else if (type_up_photo == OrdersDriversUploadsModels.PHOTO_STATUS_ARRIVED_DROP) { + // t_orders + updtOrd.id = ord_id; + updtOrd.status = OrdersModels.STTS_ARV; + updtOrd.arrived_at = now; + // t_orders_drops + updtDrop.id = drop_id; + updtDrop.stts_drop = OrdersDropsModels.STTS_DROP_WAIT; + // updtDrop.drop_enter_at = now; + // t_orders_pck_drops + updtPckDrop.id = ord_pck_drop_id; + updtPckDrop.stts = OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_DROP; + } else if (type_up_photo == OrdersDriversUploadsModels.PHOTO_STATUS_PROCESS_DROP) { + // t_orders + updtOrd.id = ord_id; + updtOrd.status = OrdersModels.STTS_ARV; + // t_orders_drops + updtDrop.id = drop_id; + updtDrop.stts_drop = OrdersDropsModels.STTS_DROP_DROPPING; + updtDrop.drop_at = now; + // t_orders_pck_drops + updtPckDrop.id = ord_pck_drop_id; + updtPckDrop.stts = OrdersPckDropsModels.STTS_DELIVERY_PROCESS_DROP; + } else if (type_up_photo == OrdersDriversUploadsModels.PHOTO_STATUS_FINISH_DROP) { + // t_orders + updtOrd.id = ord_id; + updtOrd.status = OrdersModels.STTS_DROP; + // t_orders_drops + updtDrop.id = drop_id; + updtDrop.stts_drop = OrdersDropsModels.STTS_DROP_DROPED; + // t_orders_pck_drops + updtPckDrop.id = ord_pck_drop_id; + updtPckDrop.stts = OrdersPckDropsModels.STTS_DELIVERY_FINISH_DROP; + } else if (type_up_photo == OrdersDriversUploadsModels.PHOTO_STATUS_HANDOVER_DOCUMENT) { + // t_orders + updtOrd.id = ord_id; + updtOrd.status = OrdersModels.STTS_CLIENT_PAY; + // t_orders_drops + updtDrop.id = drop_id; + updtDrop.stts_drop = OrdersDropsModels.STTS_DROP_DROPED; + // updtDrop.drop_leave_at = now; + // t_orders_pck_drops + updtPckDrop.id = ord_pck_drop_id; + updtPckDrop.stts = OrdersPckDropsModels.STTS_DELIVERY_HANDOVER_DOC; + + // kalau sudah selesai drop vhc & driver bisa order lagi + let remaining_multi_drops = await OrdersPckDropsModels.listOrdPckDrop({ ord_id, not_stts: [OrdersPckDropsModels.STTS_DELIVERY_FINISH_DROP, OrdersPckDropsModels.STTS_DELIVERY_HANDOVER_DOC] }); + let vehicle = await VhcModels.getVhcById(activeOrders[0].vhc_id); + let updtVhc = {}; + if (vehicle[0].ord_ids) { + let vhc_in_ord_ids = JSON.parse(vehicle[0].ord_ids); + for (let key in vhc_in_ord_ids) { + if (vhc_in_ord_ids[key] == ord_id) { + if (vhc_in_ord_ids.length <= 1) { + if (remaining_multi_drops.length < 1) { + updtVhc = { + is_in_ord: VhcModels.IN_ORD_NO, + ord_id: 0, + ord_code: 0, + ord_ids: null, + }; + } else { + vhc_in_ord_ids.splice(key, 1); + updtVhc['ord_ids'] = vhc_in_ord_ids; + updtVhc['ord_ids'] = JSON.stringify(updtVhc['ord_ids']); + if (vehicle[0].ord_id == ord_id) updtVhc['ord_id'] = 0; + if (vehicle[0].ord_code == activeOrders[0].ord_code) updtVhc['ord_code'] = 0; + } + } else { + vhc_in_ord_ids.splice(key, 1); + updtVhc['ord_ids'] = vhc_in_ord_ids; + updtVhc['ord_ids'] = JSON.stringify(updtVhc['ord_ids']); + if (vehicle[0].ord_id == ord_id) updtVhc['ord_id'] = 0; + if (vehicle[0].ord_code == activeOrders[0].ord_code) updtVhc['ord_code'] = 0; + } + } + } + } + // if (updtVhc) VhcModles.update(activeOrders[0].vhc_id, updtVhc); + let driver = await DriversModels.find(activeOrders[0].drv_id); + let updtDrv = {}; + if (driver[0].ord_ids) { + let drv_in_ord_ids = JSON.parse(driver[0].ord_ids); + for (let key in drv_in_ord_ids) { + if (drv_in_ord_ids[key] == ord_id) { + if (drv_in_ord_ids.length <= 1) { + if (remaining_multi_drops.length < 1) { + updtDrv = { + is_in_ord: DriversModels.IN_ORD_NO, + ord_id: 0, + ord_code: 0, + ord_ids: null, + }; + } else { + drv_in_ord_ids.splice(key, 1); + updtDrv['ord_ids'] = drv_in_ord_ids; + updtDrv['ord_ids'] = JSON.stringify(updtDrv['ord_ids']); + if (driver[0].ord_id == ord_id) updtDrv['ord_id'] = 0; + if (driver[0].ord_code == activeOrders[0].ord_code) updtDrv['ord_code'] = 0; + } + } else { + drv_in_ord_ids.splice(key, 1); + updtDrv['ord_ids'] = drv_in_ord_ids; + updtDrv['ord_ids'] = JSON.stringify(updtDrv['ord_ids']); + if (driver[0].ord_id == ord_id) updtDrv['ord_id'] = 0; + if (driver[0].ord_code == activeOrders[0].ord_code) updtDrv['ord_code'] = 0; + } + } + } + } + // if (updtDrv) DriversModels.update(updtDrv, activeOrders[0].drv_id); + } else if (type_up_photo == OrdersDriversUploadsModels.PHOTO_STATUS_ACCIDENT) { + // t_orders + updtOrd.id = ord_id; + // updtOrd.is_accident = OrdersModels.IS_ACCIDENT; + // updtOrd.acdnt_at = now; + // t_orders_pck_drops + updtPckDrop.id = ord_pck_drop_id; + updtPckDrop.is_accident = OrdersModels.IS_ACCIDENT; + updtPckDrop.acdnt_at = now; + } + + let stts_reverse_geo = 0; + const respRGeo = await LibCurl.reverseGeo(lat, lng); + let { country_id, country_code, country_text, state_id, state_text, city_id, city_text, district_id, district_text, village_id, village_text, postcode, streets, fulladdress, log_reverse_geo } = respRGeo.addrData || {}; + if (respRGeo.type === 'sc') { + stts_reverse_geo = GpsTracksModels.STTS_REVERSE_GEO_SC; + } else if (respRGeo.type === 'no_available') { + stts_reverse_geo = GpsTracksModels.STTS_REVERSE_GEO_LOST; + } else if (respRGeo.type === 'fail') { + stts_reverse_geo = GpsTracksModels.STTS_REVERSE_GEO_ER; + } else if (respRGeo.type === 'error') { + stts_reverse_geo = GpsTracksModels.STTS_REVERSE_GEO_ER; + } + + // start geotagging image + const tempFileName = moment().valueOf() + '.jpeg'; + const tempFileNamePath = path.resolve(__dirname, '../files/storage') + '/' + tempFileName; + await LibImgGeotagging.create(tempFileName, tempFileNamePath, photo, {fulladdress, lat, lng, photo_at}); + + const apiSavePhotos = process.env.FMS_URL + 'api/v1/storage/save_photos'; + const namePhoto = `ords_pcks_drops/${ord_pck_drop_id}/drvs_ups/${did}/${now}.jpeg`; + const respSavePhotos = await LibCurl.formurlencoded(apiSavePhotos, { + names: [namePhoto], + photos: [fs.readFileSync(tempFileNamePath, {encoding: 'base64'})], + }); + + LibFile.remove(tempFileName); + if (respSavePhotos.type !== 'sc') { + apiRes = JSON.parse(JSON.stringify(response[400])); + apiRes.meta.code += '_1'; + apiRes.meta.message = 'fail upload photo'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + // end geotagging image + + // get region_id + if (!village_id) { + const region = await LibCurl.getRegionId(postcode); + if (typeof region.addrData !== 'undefined') { + if (region.addrData.state_id) state_id = region.addrData.state_id; + if (region.addrData.state_text) state_text = region.addrData.state_text.toUpperCase(); + if (region.addrData.city_id) city_id = region.addrData.city_id; + if (region.addrData.city_text) city_text = region.addrData.city_text.toUpperCase(); + if (region.addrData.district_id) district_id = region.addrData.district_id; + if (region.addrData.district_text) district_text = region.addrData.district_text.toUpperCase(); + if (region.addrData.village_id) village_id = region.addrData.village_id; + if (region.addrData.village_text) village_text = region.addrData.village_text.toUpperCase(); + } + } + + // t_orders_drivers_uploads + insUploads.push({ + did, + ord_id, + ord_code: activeOrders[0].ord_code, + pck_id, + drop_id, + ord_pck_drop_id, + stts: type_up_photo, + is_active: OrdersDriversUploadsModels.IS_ACTIVE, + img: process.env.FMS_URL + `storage/${namePhoto}`, + // desc: undefined, + lat, lng, + country_id: country_id || null, + country_code: country_code || null, + country_text: country_text || null, + state_id: state_id || null, + state_text: state_text || null, + city_id: city_id || null, + city_text: city_text || null, + district_id: district_id || null, + district_text: district_text || null, + village_id: village_id || null, + village_text: village_text || null, + postcode: postcode || null, + streets: streets || null, + fulladdress: fulladdress || null, + stts_reverse_geo, log_reverse_geo, + crt: now, crt_drv_at: photo_at, crt_by: did, + updt: now, updt_by: did, + }); + + OrdersModels.bundleInsDrvUploads(insUploads, updtOrd, updtPck, updtDrop, updtPckDrop); + + apiRes = JSON.parse(JSON.stringify(response[200])); + // apiRes.data = activeOrders; + // apiRes.raw = respRGeo.addrData || {}; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + LibLogReqResApi.log(req, apiRes); + return res.status(500).json(apiRes); + } + } + + async lockMenu(req, res) { + let apiRes = {} + try { + const now = moment().unix(); + + const { did, device_id, phone } = req.auth; + const { detail_id, type_lock_menu } = req.body; + // input validation + const input = { + detail_id, + type_lock_menu, + }; + const rulesInput = { + detail_id: 'required|string', + type_lock_menu: 'required|numeric|max:12', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const decoded_detail_id = Buffer.from(detail_id, 'hex').toString('ascii'); + const split_detail_id = decoded_detail_id.split('_'); + if (split_detail_id.length !== 4) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.code += '_1'; + apiRes.meta.message = 'detail id not valid'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + const [ ord_id, pck_id, drop_id, ord_pck_drop_id ] = split_detail_id; + + const required_type_lock_menu = [OrdersDriversUploadsModels.PHOTO_STATUS_OTW_PICKUP,OrdersDriversUploadsModels.PHOTO_STATUS_ARRIVED_PICKUP,OrdersDriversUploadsModels.PHOTO_STATUS_PROCESS_PICKUP,OrdersDriversUploadsModels.PHOTO_STATUS_FINISH_PICKUP,OrdersDriversUploadsModels.PHOTO_STATUS_TRAVEL_DOCUMENT,OrdersDriversUploadsModels.PHOTO_STATUS_OTW_DROP,OrdersDriversUploadsModels.PHOTO_STATUS_ARRIVED_DROP,OrdersDriversUploadsModels.PHOTO_STATUS_PROCESS_DROP,OrdersDriversUploadsModels.PHOTO_STATUS_FINISH_DROP,OrdersDriversUploadsModels.PHOTO_STATUS_HANDOVER_DOCUMENT,OrdersDriversUploadsModels.PHOTO_STATUS_ACCIDENT]; + if (!required_type_lock_menu.includes(type_lock_menu)) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.code += '_2'; + apiRes.meta.message = 'type lock menu not valid'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const filter = { + ord_id, + pck_id, + drop_id, + ord_pck_drop_id, + // is_active: OrdersModels.IS_ACTIVE, + // order_status: [OrdersModels.STTS_HAVE_GET_VHC,OrdersModels.STTS_PCK,OrdersModels.STTS_GO,OrdersModels.STTS_ARV,OrdersModels.STTS_DROP], + get_prefer_type_truck: 1, + couple_pck_drop: 1, + get_pic_zone: 1, + did, + }; + const activeOrders = await OrdersModels.listOrders(filter); + if (activeOrders.length < 1) { + apiRes = JSON.parse(JSON.stringify(response[404])); + apiRes.meta.code += '_4'; + apiRes.meta.message = 'job not found'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const insUploads = []; + const updtOrd = {}, updtPck = {}, updtDrop = {}, updtPckDrop = {}; + if (type_lock_menu === OrdersDriversUploadsModels.PHOTO_STATUS_OTW_DROP) { + // t_orders + updtOrd.id = ord_id; + updtOrd.status = OrdersModels.STTS_GO; + // t_orders_pickups + updtPck.id = pck_id; + updtPck.stts_pck = OrdersPickupsModels.STTS_PCK_PICKED; + // t_orders_drops + updtDrop.id = drop_id; + updtDrop.stts_drop = OrdersDropsModels.STTS_DROP_WAIT; + // t_orders_pck_drops + updtPckDrop.id = ord_pck_drop_id; + updtPckDrop.drv_app_lock_menu_otw_drop_at = now; + updtPckDrop.stts = OrdersPckDropsModels.STTS_DELIVERY_OTW_DROP; + } + + OrdersModels.bundleInsDrvUploads(insUploads, updtOrd, updtPck, updtDrop, updtPckDrop); + + apiRes = JSON.parse(JSON.stringify(response[200])); + // apiRes.data = activeOrders; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + LibLogReqResApi.log(req, apiRes); + return res.status(500).json(apiRes); + } + } + + // FINANCE + async listPockets(req, res) { + let apiRes = {} + try { + const now = moment().unix(); + const { did, device_id, phone } = req.auth; + + // input validation + const input = {}; + const rulesInput = {}; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const checkpoints = await OrdersCheckpointsModels.list({ + did, + is_paid: OrdersCheckpointsModels.IS_PAID_OFF, + order_by: ' ORDER BY checkpoint.pocket_paid_at ASC', + }); + if (checkpoints.length < 1) { + apiRes = JSON.parse(JSON.stringify(response[404])); + apiRes.meta.code += '_1'; + apiRes.meta.message = 'there are no received pocket money'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const formattedCheckpoints = []; + for (const checkpoint of checkpoints) { + formattedCheckpoints.push({ + checkpoint_id: checkpoint.checkpoint_id, + ord_id: checkpoint.ord_id, + ord_code: checkpoint.ord_code, + ord_pocket_id: checkpoint.ord_pocket_id, + // pocket_sort: checkpoint.pocket_sort, + pocket_total: checkpoint.pocket_total, + pocket_is_paid: checkpoint.pocket_is_paid, + pocket_paid_at: checkpoint.pocket_paid_at, + pocket_paid_at_raw: (checkpoint.pocket_paid_at != 0) ? moment.unix(checkpoint.pocket_paid_at).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '', + // pocket_paid_by: checkpoint.pocket_paid_by, + pocket_paid_by_name: checkpoint.pocket_paid_by_name || '', + }); + } + + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.data = formattedCheckpoints; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + LibLogReqResApi.log(req, apiRes); + return res.status(500).json(apiRes); + } + } + + async detailPocket(req, res) { + let apiRes = {} + try { + const now = moment().unix(); + const { did, device_id, phone } = req.auth; + const { checkpoint_id } = req.params; + + // input validation + const input = { + checkpoint_id, + }; + const rulesInput = { + 'checkpoint_id': 'required|integer', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const checkpoints = await OrdersCheckpointsModels.list({ + did, + checkpoint_id, + limit: 1, + }); + if (checkpoints.length < 1) { + apiRes = JSON.parse(JSON.stringify(response[404])); + apiRes.meta.code += '_1'; + apiRes.meta.message = 'pocket money not found'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const formattedCheckpoints = []; + for (const checkpoint of checkpoints) { + formattedCheckpoints.push({ + checkpoint_id: checkpoint.checkpoint_id, + ord_id: checkpoint.ord_id, + ord_code: checkpoint.ord_code, + ord_pocket_id: checkpoint.ord_pocket_id, + // pocket_sort: checkpoint.pocket_sort, + pocket_total: checkpoint.pocket_total, + pocket_is_paid: checkpoint.pocket_is_paid, + pocket_paid_at: checkpoint.pocket_paid_at, + pocket_paid_at_raw: (checkpoint.pocket_paid_at != 0) ? moment.unix(checkpoint.pocket_paid_at).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '', + // pocket_paid_by: checkpoint.pocket_paid_by, + pocket_paid_by_name: checkpoint.pocket_paid_by_name || '', + }); + } + + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.data = formattedCheckpoints[0]; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + LibLogReqResApi.log(req, apiRes); + return res.status(500).json(apiRes); + } + } + + // LOGBOOK + async listLogBooks(req, res) { + let apiRes = {} + try { + const now = moment().unix(); + + const { did, device_id, phone } = req.auth; + + const filter = { + is_active: LogbookKeysModels.IS_ACTIVE, + }; + const listKeys = await LogbookKeysModels.list(filter); + if (listKeys.length < 1) { + apiRes = JSON.parse(JSON.stringify(response[404])); + apiRes.meta.code = '200'; // += '_1'; + apiRes.meta.message = 'there are no list logbook'; + apiRes.data = []; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const formattedListKeys = [], includedLogbookId = []; + for (const row of listKeys) { + if (includedLogbookId.includes(row.lgb_id)) continue; + includedLogbookId.push(row.lgb_id); + + // https://stackoverflow.com/questions/23299950/convert-date-to-utc-using-moment-js + formattedListKeys.push({ + lgb_id: row.lgb_id, + lgb_name: row.name, + updt_at: row.updt, + updt_at_raw: (row.updt != 0) ? moment.unix(row.updt).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '', + }); + } + + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.data = formattedListKeys; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + LibLogReqResApi.log(req, apiRes); + return res.status(500).json(apiRes); + } + } + + async detailLogBook(req, res) { + let apiRes = {} + try { + const now = moment().unix(); + + const { did, device_id, phone } = req.auth; + const { lgb_id } = req.params; + + // input validation + const input = { + lgb_id, + }; + const rulesInput = { + 'lgb_id': 'required|integer', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const filter = { + lgb_id, + is_active: LogbookKeysModels.IS_ACTIVE, + limit: 1, + }; + const listKeys = await LogbookKeysModels.list(filter); + if (listKeys.length < 1) { + apiRes = JSON.parse(JSON.stringify(response[404])); + apiRes.meta.code += '_4'; + apiRes.meta.message = 'logbook not found'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const formattedListKeys = [], includedLogbookId = []; + for (const row of listKeys) { + if (includedLogbookId.includes(row.lgb_id)) continue; + includedLogbookId.push(row.lgb_id); + + const params = []; + row.keys = JSON.parse(row.keys); + row.units = JSON.parse(row.units); + row.dtypes = JSON.parse(row.dtypes); + for (let i in row.keys) { + params.push({ + key: row.keys[i], + unit: row.units[i], + dtype: row.dtypes[i], + value: "", + }) + } + + // https://stackoverflow.com/questions/23299950/convert-date-to-utc-using-moment-js + formattedListKeys.push({ + lgb_id: row.lgb_id, + lgb_name: row.name, + updt_at: row.updt, + updt_at_raw: (row.updt != 0) ? moment.unix(row.updt).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '', + params, + }); + } + + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.data = formattedListKeys[0]; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + LibLogReqResApi.log(req, apiRes); + return res.status(500).json(apiRes); + } + } + + async insOrdLogBook(req, res) { + let apiRes = {} + try { + const now = moment().unix(); + + const { did, device_id, phone } = req.auth; + const { lgb_id, detail_id, params } = req.body; + + // input validation + const input = { + lgb_id, + detail_id, + params, + }; + const rulesInput = { + 'lgb_id': 'required|integer', + 'detail_id': 'required|string', + 'params': 'required|array', + 'params.*.key': 'required|string|max:255', + 'params.*.unit': 'required|string|max:255', + 'params.*.dtype': 'required|string|max:255', + 'params.*.value': 'required|string', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const decoded_detail_id = Buffer.from(detail_id, 'hex').toString('ascii'); + const split_detail_id = decoded_detail_id.split('_'); + if (split_detail_id.length !== 4) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.code += '_1'; + apiRes.meta.message = 'detail id not valid'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + const [ ord_id, pck_id, drop_id, ord_pck_drop_id ] = split_detail_id; + + const filter = { + ord_id, + pck_id, + drop_id, + ord_pck_drop_id, + // is_active: OrdersModels.IS_ACTIVE, + // order_status: [OrdersModels.STTS_HAVE_GET_VHC,OrdersModels.STTS_PCK,OrdersModels.STTS_GO,OrdersModels.STTS_ARV,OrdersModels.STTS_DROP], + get_prefer_type_truck: 1, + couple_pck_drop: 1, + get_pic_zone: 1, + did, + }; + const activeOrders = await OrdersModels.listOrders(filter); + if (activeOrders.length < 1) { + apiRes = JSON.parse(JSON.stringify(response[404])); + apiRes.meta.code += '_4'; + apiRes.meta.message = 'job not found'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const filter1 = { + lgb_id, + is_active: LogbookKeysModels.IS_ACTIVE, + join_type: 1, + limit: 1, + }; + const listKeys = await LogbookKeysModels.list(filter1); + if (listKeys.length < 1) { + apiRes = JSON.parse(JSON.stringify(response[404])); + apiRes.meta.code += '_5'; + apiRes.meta.message = 'logbook not found'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + let dy_cols = "(COLUMN_CREATE(", photo = ''; + let values = []; + for (const param of params) { + // dy_cols += "'key', '" + param.key + "', 'unit', '" + param.unit + "', 'dtype', '" + param.dtype + "', 'value', '" + param.value + "',"; // as reference only + + if (param.dtype === LogbookKeysModels.IMG_BASE64) { + // start reverse geo + let stts_reverse_geo = 0; + const respRGeo = await LibCurl.reverseGeo(param.lat, param.lng); + let { country_id, country_code, country_text, state_id, state_text, city_id, city_text, district_id, district_text, village_id, village_text, postcode, streets, fulladdress, log_reverse_geo } = respRGeo.addrData || {}; + if (respRGeo.type === 'sc') { + stts_reverse_geo = GpsTracksModels.STTS_REVERSE_GEO_SC; + } else if (respRGeo.type === 'no_available') { + stts_reverse_geo = GpsTracksModels.STTS_REVERSE_GEO_LOST; + } else if (respRGeo.type === 'fail') { + stts_reverse_geo = GpsTracksModels.STTS_REVERSE_GEO_ER; + } else if (respRGeo.type === 'error') { + stts_reverse_geo = GpsTracksModels.STTS_REVERSE_GEO_ER; + } + // end reverse geo + + // start get region_id + // if (!village_id) { + // const region = await LibCurl.getRegionId(postcode); + // if (typeof region.addrData !== 'undefined') { + // if (region.addrData.state_id) state_id = region.addrData.state_id; + // if (region.addrData.state_text) state_text = region.addrData.state_text.toUpperCase(); + // if (region.addrData.city_id) city_id = region.addrData.city_id; + // if (region.addrData.city_text) city_text = region.addrData.city_text.toUpperCase(); + // if (region.addrData.district_id) district_id = region.addrData.district_id; + // if (region.addrData.district_text) district_text = region.addrData.district_text.toUpperCase(); + // if (region.addrData.village_id) village_id = region.addrData.village_id; + // if (region.addrData.village_text) village_text = region.addrData.village_text.toUpperCase(); + // } + // } + // // end get region_id + + // start geotagging image + const tempFileName = moment().valueOf() + '.jpeg'; + const tempFileNamePath = path.resolve(__dirname, '../files/storage') + '/' + tempFileName; + await LibImgGeotagging.create(tempFileName, tempFileNamePath, param.value, {fulladdress: fulladdress || '', lat: param.lat || '', lng: param.lng || '', photo_at: param.photo_at || ''}); + + const apiSavePhotos = process.env.FMS_URL + 'api/v1/storage/save_photos'; + const namePhoto = `ords_pcks_drops/${ord_pck_drop_id}/drvs_logbooks/${did}/${now}.jpeg`; + const respSavePhotos = await LibCurl.formurlencoded(apiSavePhotos, { + names: [namePhoto], + photos: [fs.readFileSync(tempFileNamePath, {encoding: 'base64'})], + }); + + LibFile.remove(tempFileName); + if (respSavePhotos.type !== 'sc') { + apiRes = JSON.parse(JSON.stringify(response[400])); + apiRes.meta.code += '_1'; + apiRes.meta.message = 'fail upload photo'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + // end geotagging image + + param.value = process.env.FMS_URL + `storage/${namePhoto}`; + } + + // start dy_cols + dy_cols += "'" + param.key + "', '" + param.value + "',"; + values.push(param.value); + // end dy_cols + } + dy_cols = dy_cols.slice(0, -1) + "))"; + dy_cols = mysql.raw(dy_cols); + + const insOrdLogbook = { + ord_id, + ord_code: activeOrders[0].ord_code, + lgb_key_id: lgb_id, + lgb_key_name: listKeys[0].name, + lgb_type_id: listKeys[0].type, + lgb_type_name: listKeys[0].type_name, + vhc_id: activeOrders[0].vhc_id, + drv_id: did, + is_active: LogbookOrdersModels.IS_ACTIVE, + dy_cols, + keys: listKeys[0].keys, + units: listKeys[0].units, + dtypes: listKeys[0].dtypes, + values: JSON.stringify(values), + crt: now, + crt_by: did, + updt: now, + updt_by: did, + }; + await LogbookOrdersModels.ins(insOrdLogbook); + + apiRes = JSON.parse(JSON.stringify(response[200])); + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + LibLogReqResApi.log(req, apiRes); + return res.status(500).json(apiRes); + } + } + + async listOrdLogBooks(req, res) { + let apiRes = {} + try { + const now = moment().unix(); + + const { did, device_id, phone } = req.auth; + + const filter = { + is_active: LogbookOrdersModels.IS_ACTIVE, + }; + const listKeys = await LogbookOrdersModels.list(filter); + if (listKeys.length < 1) { + apiRes = JSON.parse(JSON.stringify(response[404])); + apiRes.meta.code = '200'; // += '_1'; + apiRes.meta.message = 'there are no list orders logbooks'; + apiRes.data = []; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const formattedListKeys = [], includedLogbookId = []; + for (const row of listKeys) { + if (includedLogbookId.includes(row.ord_lgb_id)) continue; + includedLogbookId.push(row.ord_lgb_id); + + // https://stackoverflow.com/questions/23299950/convert-date-to-utc-using-moment-js + formattedListKeys.push({ + ord_lgb_id: row.ord_lgb_id, + lgb_key_id: row.lgb_key_id, + lgb_key_name: row.lgb_key_name, + lgb_type_id: row.lgb_type_id, + lgb_type_name: row.lgb_type_name, + dy_cols: (row.dy_cols_json == null) ? '' : JSON.parse(row.dy_cols_json), + keys: JSON.parse(row.keys), + units: JSON.parse(row.units), + dtypes: JSON.parse(row.dtypes), + values: JSON.parse(row.values), + crt_at: row.crt, + crt_at_raw: (row.crt != 0) ? moment.unix(row.crt).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '', + updt_at: row.updt, + updt_at_raw: (row.updt != 0) ? moment.unix(row.updt).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '', + }); + } + + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.data = formattedListKeys; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + LibLogReqResApi.log(req, apiRes); + return res.status(500).json(apiRes); + } + } + + async detailOrdLogBook(req, res) { + let apiRes = {} + try { + const now = moment().unix(); + + const { did, device_id, phone } = req.auth; + const { ord_lgb_id } = req.params; + + // input validation + const input = { + ord_lgb_id, + }; + const rulesInput = { + 'ord_lgb_id': 'required|integer', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const filter = { + ord_lgb_id, + is_active: LogbookOrdersModels.IS_ACTIVE, + limit: 1, + }; + const listKeys = await LogbookOrdersModels.list(filter); + if (listKeys.length < 1) { + apiRes = JSON.parse(JSON.stringify(response[404])); + apiRes.meta.code += '_4'; + apiRes.meta.message = 'order logbook not found'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const formattedListKeys = [], includedLogbookId = []; + for (const row of listKeys) { + if (includedLogbookId.includes(row.ord_lgb_id)) continue; + includedLogbookId.push(row.ord_lgb_id); + + // https://stackoverflow.com/questions/23299950/convert-date-to-utc-using-moment-js + formattedListKeys.push({ + ord_lgb_id: row.ord_lgb_id, + lgb_key_id: row.lgb_key_id, + lgb_key_name: row.lgb_key_name, + lgb_type_id: row.lgb_type_id, + lgb_type_name: row.lgb_type_name, + dy_cols: (row.dy_cols_json == null) ? '' : JSON.parse(row.dy_cols_json), + keys: JSON.parse(row.keys), + units: JSON.parse(row.units), + dtypes: JSON.parse(row.dtypes), + values: JSON.parse(row.values), + crt_at: row.crt, + crt_at_raw: (row.crt != 0) ? moment.unix(row.crt).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '', + updt_at: row.updt, + updt_at_raw: (row.updt != 0) ? moment.unix(row.updt).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '', + }); + } + + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.data = formattedListKeys[0]; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + LibLogReqResApi.log(req, apiRes); + return res.status(500).json(apiRes); + } + } + + // RUNNING BACKGROUD + // up lat,long data per 1 minute + async upLocation(req, res) { + let apiRes = {} + try { + const now = moment().unix(); + + const { did, device_id, phone, phone_device_id } = req.auth; + const { lat, lng, req_at } = req.body; + + // input validation + const input = { + lat, + lng, + req_at, + }; + const rulesInput = { + lat: 'required|string|max:125', + lng: 'required|string|max:125', + req_at: 'required|numeric', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const filter = { + did, + // order_status: [OrdersModels.STTS_HAVE_GET_VHC,OrdersModels.STTS_PCK,OrdersModels.STTS_GO,OrdersModels.STTS_ARV,OrdersModels.STTS_DROP], + is_active: OrdersModels.IS_ACTIVE, + delivery_statuses: [ + OrdersPckDropsModels.STTS_DELIVERY_OTW_PICKUP,OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_PICKUP,OrdersPckDropsModels.STTS_DELIVERY_PROCESS_PICKUP + ,OrdersPckDropsModels.STTS_DELIVERY_FINISH_PICKUP,OrdersPckDropsModels.STTS_DELIVERY_TRAVEL_DOC,OrdersPckDropsModels.STTS_DELIVERY_OTW_DROP + ,OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_DROP,OrdersPckDropsModels.STTS_DELIVERY_PROCESS_DROP,OrdersPckDropsModels.STTS_DELIVERY_FINISH_DROP + // ,OrdersPckDropsModels.STTS_DELIVERY_HANDOVER_DOC + ], + couple_pck_drop: 1, + }; + // kalo mau track yang nonactive, gausah ngeget vhc, lansung insert aja dengan vhc_id: 0 + // const updtToOrders = await OrdersModels.listActiveOrdVhc(filter); + const updtToOrders = await OrdersModels.listOrders(filter); + + /** + * get lat, lng to all checkpoints paid = 0, sort != 1, order.dlt is null, + * kenakan ke checkpoints yang order stts_deliverynya lebih dari travel dokumen + * jika ada case negative di inCircle ada dan di di inShape ada maka mana yang didahulukan ? langsung dikenain aja 2-2nya + * pastikan dulu ada di activeOrder + * kenakan yang ord_pck_id lebih awal + */ + // BISA BUAT DEBUGGING: where_not_pocket_is_paid: OrdersCheckpointsModels.IS_PAID_OFF + // BUAT PRODUCTION: pocket_is_paid: OrdersCheckpointsModels.IS_UNPAID + const inCircle = await ZoneModels.getCheckpointsInCircle(lat, lng, {drv_id: did, pocket_is_paid: OrdersCheckpointsModels.IS_UNPAID, pocket_sort: '!= 1', stts_delivery: [OrdersPckDropsModels.STTS_DELIVERY_OTW_DROP,OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_DROP,OrdersPckDropsModels.STTS_DELIVERY_PROCESS_DROP,OrdersPckDropsModels.STTS_DELIVERY_FINISH_DROP,OrdersPckDropsModels.STTS_DELIVERY_HANDOVER_DOC]}); + const inShape = await ZoneModels.getCheckpointsInShape(lat, lng, {drv_id: did, pocket_is_paid: OrdersCheckpointsModels.IS_UNPAID, pocket_sort: '!= 1', stts_delivery: [OrdersPckDropsModels.STTS_DELIVERY_OTW_DROP,OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_DROP,OrdersPckDropsModels.STTS_DELIVERY_PROCESS_DROP,OrdersPckDropsModels.STTS_DELIVERY_FINISH_DROP,OrdersPckDropsModels.STTS_DELIVERY_HANDOVER_DOC]}); + let insideZones = []; + if (inCircle.length > 0 || inShape.length > 0) { + for (const circle of inCircle) { + // hit api disbure + if (circle.drv_bank_id == 0 || circle.drv_bank_acc_number == null) continue; + insideZones.push(circle); + } + for (const shape of inShape) { + // hit api disbure + if (shape.drv_bank_id == 0 || shape.drv_bank_acc_number == null) continue; + insideZones.push(shape); + } + } + // checkpoints + if (insideZones.length > 0) { + const UNIT_TYPE_UNIT = 3; + + let admins = await UsersModels.getUsersActiveByRole(UsersModels.ROLE_FINANCE); + let admins_data = []; + for (const admin of admins) { + admins_data.push({ + 'admin_id': admin.id, + 'admin_name': admin.first_name, + 'admin_phone': admin.phone_code + ' ' + admin.phone, + 'admin_mail': admin.email, + 'admin_addr': '' + }); + } + + for (const insideZone of insideZones) { + const insOrdAItems = { + 'ord_id': insideZone.ord_id, + 'ord_code': insideZone.ord_code, + 'flow_type': OrdersAItemsModels.FLOW_TYPE_PAYMENT, + 'cash_type': OrdersAItemsModels.TYPE_CASH_OUT, + 'a_item_type': OrdersAItemsModels.A_TYPE_SECONDARY, + 'unit_id': 0, + 'unit_type': UNIT_TYPE_UNIT, + 'amt_base_flat': insideZone.pocket_total, + 'unit_qty': 0, + 'amt_tax_type': 0, + 'amt_tax_ppn_percent': 0, + 'amt_tax_ppn_flat': 0, + 'amt_tax_pph_percent': 0, + 'amt_tax_pph_flat': 0, + 'amt_total_tax_flat': 0, + 'amt_result_flat': insideZone.pocket_total, + 'amt_total_flat': insideZone.pocket_total, + 'only_vdr': OrdersAItemsModels.ONLY_VDR_YES, + 'bank_id': insideZone.drv_bank_id, + 'bank_name': insideZone.drv_bank_name, + 'bank_code': insideZone.drv_bank_code, + 'bank_short_name': insideZone.drv_bank_short_name, + 'bank_branch_name': insideZone.drv_bank_branch_name || null, + 'bank_acc_name': insideZone.drv_bank_acc_name, + 'bank_acc_number': insideZone.drv_bank_acc_number, + 'ref_ord_id': insideZone.ord_id, + 'ref_ord_code': insideZone.ord_code, + 'crt': now, + 'crt_by': 0, + 'updt': now, + 'updt_by': 0, + 'desc': 'Uang Saku Driver di ' + insideZone.name, + }; + + insOrdAItems.calc_to_vdr = OrdersAItemsModels.CALC_TO_VDR_YES; + let termins = []; + termins = await OrdersTerminsModels.listWithFilter({ + 'ord_id': insideZone.ord_id, + 'termin_for': OrdersTerminsModels.TERMIN_FOR_VENDOR, + 'termin_is_paid': OrdersTerminsModels.IS_PAID_NO, + 'in_stts_merge': [ + OrdersAItemsModels.STTS_MERGE_NO, + OrdersAItemsModels.STTS_MERGE_RESULT, + ], + }); + insOrdAItems.v_termin_id = 0; + insOrdAItems.ref_v_termin_id = 0; + if (termins.length > 0) { + insOrdAItems.v_termin_id = termins[0].id; + insOrdAItems.ref_v_termin_id = termins[0].id; + } + if (insOrdAItems.v_termin_id === 0) { + termins = await OrdersTerminsModels.listWithFilter({ + 'ord_id': insideZone.ord_id, + 'termin_for': OrdersTerminsModels.TERMIN_FOR_VENDOR, + 'in_stts_merge': [ + OrdersAItemsModels.STTS_MERGE_NO, + OrdersAItemsModels.STTS_MERGE_RESULT, + ], + }); + insOrdAItems.v_termin_id = termins[termins.length - 1].id; + insOrdAItems.ref_v_termin_id = termins[termins.length - 1].id; + } + + const mailData = { + trx_code: insideZone.ord_code, + drv_name: insideZone.drv_name, + // pickup_zone_title, + // pickup_zone_addr, + // drop_zone_title, + // drop_zone_addr, + pocket_total: 'Rp'+((new Intl.NumberFormat('id-ID')).format(insideZone.pocket_total)).split('.').join('-').split(',').join('.').split('-').join(','), // yang . => - || , => . || - => , + bank_name: insideZone.drv_bank_name, + bank_code: insideZone.drv_bank_code, + bank_branch_name: insideZone.drv_bank_branch_name || '', + bank_acc_name: insideZone.drv_bank_acc_name, + bank_acc_no: insideZone.drv_bank_acc_number, + }; + for (const updtOrd of updtToOrders) { + if (updtOrd.id === insideZone.ord_id) { + mailData.pickup_zone_title = updtOrd.pck_name; + mailData.pickup_zone_addr = updtOrd.pck_addr; + mailData.drop_zone_title = updtOrd.drop_name; + mailData.drop_zone_addr = updtOrd.drop_addr; + } + } + + const danas = await DanaModels.list({'id': DanaModels.PK_ID, 'limit': 1}); + if (danas.length < 1) { + apiRes = JSON.parse(JSON.stringify(response[400])); + apiRes.meta.message = 'dana error'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + const dana = danas[0]; + + const payloadDana = { + 'ord_id': insideZone.ord_id, + 'ord_code': insideZone.ord_code, + 'checkpoint_id': insideZone.checkpoint_id, + 'bank_code': insideZone.drv_bank_code, + 'bank_name': insideZone.drv_bank_name, + 'bank_branch': insideZone.drv_bank_branch_name || null, + 'amt': insideZone.pocket_total, + 'acc_name': insideZone.drv_bank_acc_name, + 'acc_number': insideZone.drv_bank_acc_number, + 'device_id': device_id, + }; + + if (dana.amt > insideZone.pocket_total && dana.amt > DanaModels.MINIMUM_AMT) { + const axInstance = axios.create(); + axios.defaults.timeout = 3000; + axios.defaults.crossDomain = true; + const respDana = await axInstance.post(process.env.API_DANA_BINGCORP + 'order/create', payloadDana, { + timeout: 3000, + headers: { + // 'Host': '127.0.0.1', + 'Content-Type': 'application/json', + } + }); + const respDataDana = respDana.data || {}; + if (respDana.status != 200 || respDataDana.meta.code != 200) { + const insLogsTf = { + 'ord_id': insideZone.ord_id, + 'ord_code': insideZone.ord_code, + 'type': OrdersLogsTfModels.TYPE_TF_CHECKPOINT, + 'checkpoint_id': insideZone.checkpoint_id, + 'amount': insideZone.pocket_total, + 'stts': OrdersLogsTfModels.STTS_FAIL, + 'fail_at': moment().unix(), + 'note': respDataDana.data.note || 0, + 'bank_id': insideZone.drv_bank_id, + 'bank_name': insideZone.drv_bank_name, + 'bank_code': insideZone.drv_bank_code, + 'bank_short_name': insideZone.drv_bank_short_name, + 'bank_branch_name': insideZone.drv_bank_branch_name || null, + 'bank_acc_name': insideZone.drv_bank_acc_name, + 'bank_acc_number': insideZone.drv_bank_acc_number, + 'method': OrdersLogsTfModels.METHOD_DANA, + 'url': process.env.API_DANA_BINGCORP + 'order/create', + 'ref_code': respDataDana.data.dana_reference_no || 0, + 'req_data': JSON.stringify(payloadDana), + 'resp_data': JSON.stringify(respDataDana), + 'crt': moment().unix(), + 'updt': moment().unix(), + }; + const updtOrdCheckpoint = { + 'id': insideZone.checkpoint_id, + 'pocket_is_paid': OrdersCheckpointsModels.IS_TF_FAIL, + 'pocket_paid_note': respDataDana.data.note, + 'pocket_paid_at': now, + 'pocket_paid_by': 0, + 'bank_id': insideZone.drv_bank_id, + 'bank_name': insideZone.drv_bank_name, + 'bank_code': insideZone.drv_bank_code, + 'bank_short_name': insideZone.drv_bank_short_name, + 'bank_branch_name': insideZone.drv_bank_branch_name || null, + 'bank_acc_name': insideZone.drv_bank_acc_name, + 'bank_acc_number': insideZone.drv_bank_acc_number, + 'tf_method': OrdersCheckpointsModels.TF_METHOD_DANA, + 'tf_at': now, + 'tf_url': process.env.API_DANA_BINGCORP + 'order/create', + 'tf_ref_code': respDataDana.data.dana_reference_no || 0, + 'tf_note': respDataDana.data.note || 0, + 'tf_req_data': JSON.stringify(payloadDana), + 'tf_resp_data': JSON.stringify(respDataDana), + }; + await OrdersCheckpointsModels.bundleUpdt(updtOrdCheckpoint, {}, insLogsTf); + continue; + } + + const insLogsTf = { + 'ord_id': insideZone.ord_id, + 'ord_code': insideZone.ord_code, + 'type': OrdersLogsTfModels.TYPE_TF_CHECKPOINT, + 'checkpoint_id': insideZone.checkpoint_id, + 'amount': insideZone.pocket_total, + 'stts': OrdersLogsTfModels.STTS_PAID, + 'paid_at': moment().unix(), + 'note': respDataDana.data.note || 0, + 'bank_id': insideZone.drv_bank_id, + 'bank_name': insideZone.drv_bank_name, + 'bank_code': insideZone.drv_bank_code, + 'bank_short_name': insideZone.drv_bank_short_name, + 'bank_branch_name': insideZone.drv_bank_branch_name || null, + 'bank_acc_name': insideZone.drv_bank_acc_name, + 'bank_acc_number': insideZone.drv_bank_acc_number, + 'method': OrdersLogsTfModels.METHOD_DANA, + 'url': process.env.API_DANA_BINGCORP + 'order/create', + 'ref_code': respDataDana.data.dana_reference_no || 0, + 'req_data': JSON.stringify(payloadDana), + 'resp_data': JSON.stringify(respDataDana), + 'crt': moment().unix(), + 'updt': moment().unix(), + }; + const updtOrdCheckpoint = { + 'id': insideZone.checkpoint_id, + 'pocket_is_paid': OrdersCheckpointsModels.IS_PAID_OFF, + 'pocket_paid_at': now, + 'pocket_paid_by': 0, + 'bank_id': insideZone.drv_bank_id, + 'bank_name': insideZone.drv_bank_name, + 'bank_code': insideZone.drv_bank_code, + 'bank_short_name': insideZone.drv_bank_short_name, + 'bank_branch_name': insideZone.drv_bank_branch_name || null, + 'bank_acc_name': insideZone.drv_bank_acc_name, + 'bank_acc_number': insideZone.drv_bank_acc_number, + 'tf_method': OrdersCheckpointsModels.TF_METHOD_DANA, + 'tf_at': now, + 'tf_url': process.env.API_DANA_BINGCORP + 'order/create', + 'tf_ref_code': respDataDana.data.dana_reference_no || 0, + 'tf_note': respDataDana.data.note || 0, + 'tf_req_data': JSON.stringify(payloadDana), + 'tf_resp_data': JSON.stringify(respDataDana), + }; + const updtDana = { + 'id': dana.id, + 'amt': mysql.raw('amt-'+insideZone.pocket_total), + }; + + await OrdersCheckpointsModels.bundleUpdt(updtOrdCheckpoint, insOrdAItems, insLogsTf, updtDana); + } else { + for (const admin of admins_data) { + mailData.admin_name = admin.admin_name; + mailData.dana_current = 'Rp'+((new Intl.NumberFormat('id-ID')).format(dana.amt)).split('.').join('-').split(',').join('.').split('-').join(','); // yang . => - || , => . || - => ,, + mailData.dana_minimum = 'Rp'+((new Intl.NumberFormat('id-ID')).format(DanaModels.MINIMUM_AMT)).split('.').join('-').split(',').join('.').split('-').join(','); // yang . => - || , => . || - => ,, + LibMail.sendFinanceInfoDanaAmount('Saldo Dana Tidak Mencukupi', admin.admin_mail, mailData); + } + } + + for (const admin of admins_data) { + mailData.admin_name = admin.admin_name; + LibMail.sendFinanceInfoTfPocket('Transfer uang saku order ' + mailData.trx_code, admin.admin_mail, mailData); + } + } + } + + // spawn zone + const inSpawnCircle = await ZoneModels.getCheckpointsInCircle(lat, lng, {drv_id: did}); + const inSpawnShape = await ZoneModels.getCheckpointsInShape(lat, lng, {drv_id: did}); + let insideSpawnZone = []; + if (inSpawnCircle.length > 0 || inSpawnShape.length > 0) { + for (const circle of inSpawnCircle) { + // hit api disbure + if (circle.drv_bank_id == 0 || circle.drv_bank_acc_number == null) continue; + insideSpawnZone.push(circle); + } + for (const shape of inSpawnShape) { + // hit api disbure + if (shape.drv_bank_id == 0 || shape.drv_bank_acc_number == null) continue; + insideSpawnZone.push(shape); + } + } + + let logDevices = []; + + if (updtToOrders.length > 0) { + const includedVhcId = []; + for (const updtOrd of updtToOrders) { + if (includedVhcId.includes(updtOrd.vhc_id)) continue; + includedVhcId.push(updtOrd.vhc_id); + + const logDevice = { + original_hex: null, + protocol: GpsTracksModels.PROTOCOL_SMARTPHONE, + action: GpsTracksModels.ACT_LOCATION, + device_id, + latitude: lat, + longitude: lng, + speed: null, + orientation: 0, + stts_engine: GpsTracksModels.STTS_EN_MOVING, + stts_gps: GpsTracksModels.STTS_GPS_ON, + stts_gsm: GpsTracksModels.STTS_GSM_STRONG_SIGNAL, + stts_reverse_geo: GpsTracksModels.STTS_REVERSE_GEO_NOT, + pre_milleage: 0, // dari jarak sebelumnya ke sekarang + sum_milleage: 0, // calculated on device_id (IMEI) + vhc_milleage: 0, // calucalted on vhc_id + drv_milleage: 0, // calucalted on drv_id + vhc_id: updtOrd.vhc_id, + drv_id: did, + source: GpsTracksModels.SOURCE_SMARTPHONE, + crt: now, + crt_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'), + crt_d: req_at, + crt_d_format: moment.unix(req_at).format('YYYY-MM-DD HH:mm:ss'), + crt_s: now, + crt_s_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'), + }; + + const lastTrack = await GpsTracksModels.get2LastLoc({vhc_id: updtOrd.vhc_id}); + // const lastTrack = await GpsTracksModels.get2LastLoc({device_id}); // kurang cocok by device_id, karena ada case update lokasi tanpa orderan yang sedang aktif + // count milleage + if (logDevice.latitude != null && logDevice.longitude != null && lastTrack.length > 0) { + const distance = LibHelper.haversineGreatCircleDistance(lastTrack[0].latitude, lastTrack[0].longitude, logDevice.latitude, logDevice.longitude, LibHelper.EARTH_RADIUS_KM); + const distance_km = LibHelper.kmToKm(distance, 100000000); + console.log(`DRIVER UP LOCATION => vhc_id:${updtOrd.vhc_id}, did:${did}, distance_km:${distance_km}`); + if (distance_km < 3) { + const vhc = await VhcModels.getVhcById(logDevice.vhc_id); + if (vhc.length > 0) { + logDevice.pre_milleage = distance_km; + logDevice.sum_milleage = (lastTrack[0].sum_milleage + logDevice.pre_milleage).toFixed(8); + if (lastTrack[0].vhc_id == logDevice.vhc_id) { + logDevice.vhc_milleage = (lastTrack[0].vhc_milleage + logDevice.pre_milleage).toFixed(8); + } else { + logDevice.vhc_milleage = (vhc[0].sum_milleage + logDevice.pre_milleage).toFixed(8); + } + const drv = await DriversModels.find(did); + if (drv.length > 0) { + if (lastTrack[0].did == logDevice.did) { + logDevice.drv_milleage = (lastTrack[0].drv_milleage + logDevice.pre_milleage).toFixed(8); + } else { + logDevice.drv_milleage = (drv[0].sum_milleage + logDevice.pre_milleage).toFixed(8); + } + DriversModels.update({ sum_milleage: logDevice.drv_milleage }, did); + } + // VhcModels.update(updtOrd.vhc_id, { sum_milleage: logDevice.vhc_milleage }); + } + } + } + + logDevices.push(logDevice); + const currTrack = await GpsTracksModels.bundleCreate2(logDevice, {}); + + /** + * get lastSpawn desc index 0, where leave_at = 0 + * kalo gaada create, dengan isi field enter_at aja, kalo ada didalam zona + * kalo ada update, dengan isi field leave_at aja, kalo udah diluar zona + */ + const lastSpawn = await GpsTracksModels.listSpawnZone({ + source: GpsTracksModels.SOURCE_SMARTPHONE, + vhc_id: updtOrd.vhc_id, + drv_id: did, + ord_id: updtOrd.ord_id, + // ord_code: updtOrd.ord_code, + leave_at_d: 0, + order_by: 'ORDER BY id DESC', + limit: 1, + }); + + if (lastSpawn.length > 0) { + let is_leave_zone = 1, is_leave_zone_pck = 1, is_leave_zone_drop = 1; + for (const insideZone of insideSpawnZone) { + if (insideZone.ord_id === updtOrd.ord_id && insideZone.zid === lastSpawn[0].zone_id) is_leave_zone = 0; + if (insideZone.zid === updtOrd.pck_id) is_leave_zone_pck = 0; + if (insideZone.zid === updtOrd.drop_id) is_leave_zone_drop = 0; + } + if (is_leave_zone === 1 && lastSpawn[0].ord_id === updtOrd.ord_id) { + GpsTracksModels.updt2SpawnZone({ + leave_lat: lat, + leave_lng: lng, + leave_at_d: req_at, + leave_at_d_format: moment.unix(req_at).format('YYYY-MM-DD HH:mm:ss'), + leave_at_s: now, + leave_at_s_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'), + updt: now, + updt_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'), + }, lastSpawn[0].id); + } + if (is_leave_zone_pck === 1 && updtOrd.pck_leave_at === 0) { + OrdersPickupsModels.updt({ + id: updtOrd.ord_pck_id, + pck_leave_at: req_at, + }); + } + if (is_leave_zone_drop === 1 && is_leave_zone_pck === 0 && updtOrd.pck_leave_at !== 0 && updtOrd.drop_leave_at === 0) { + OrdersDropsModels.updt({ + id: updtOrd.ord_drop_id, + drop_leave_at: req_at, + }); + } + } else { + for (const insideZone of insideSpawnZone) { + if (insideZone.ord_id === updtOrd.ord_id) { + GpsTracksModels.create2SpawnZone({ + device_id: device_id, + master_id: Number(currTrack.result.insertId), + enter_lat: lat, + enter_lng: lng, + enter_at_d: req_at, + enter_at_d_format: moment.unix(req_at).format('YYYY-MM-DD HH:mm:ss'), + enter_at_s: now, + enter_at_s_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'), + zone_id: insideZone.zid, + zone_name: insideZone.name, + vhc_id: updtOrd.vhc_id, + drv_id: did, + ord_id: insideZone.ord_id, + ord_pck_drop_id: insideZone.ord_pck_drop_id, + // ord_code: insideZone.ord_code, + source: GpsTracksModels.SOURCE_SMARTPHONE, + crt: now, + crt_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'), + }); + } + if (insideZone.zid === updtOrd.pck_id && updtOrd.pck_enter_at === 0) { + OrdersPickupsModels.updt({ + id: updtOrd.ord_pck_id, + pck_enter_at: req_at, + }); + } + if (insideZone.zid === updtOrd.drop_id && updtOrd.drop_enter_at === 0) { + OrdersDropsModels.updt({ + id: updtOrd.ord_drop_id, + drop_enter_at: req_at, + }); + } + } + } + } + } else { + const logDevice = { + original_hex: null, + protocol: GpsTracksModels.PROTOCOL_SMARTPHONE, + action: GpsTracksModels.ACT_LOCATION, + device_id, + latitude: lat, + longitude: lng, + speed: null, + orientation: 0, + stts_engine: GpsTracksModels.STTS_EN_MOVING, + stts_gps: GpsTracksModels.STTS_GPS_ON, + stts_gsm: GpsTracksModels.STTS_GSM_STRONG_SIGNAL, + stts_reverse_geo: GpsTracksModels.STTS_REVERSE_GEO_NOT, + pre_milleage: 0, // dari jarak sebelumnya ke sekarang + sum_milleage: 0, // calculated on device_id (IMEI) + vhc_milleage: 0, // calucalted on vhc_id + drv_milleage: 0, // calucalted on drv_id + vhc_id: 0, + drv_id: did, + source: GpsTracksModels.SOURCE_SMARTPHONE, + crt: now, + crt_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'), + crt_d: req_at, + crt_d_format: moment.unix(req_at).format('YYYY-MM-DD HH:mm:ss'), + crt_s: now, + crt_s_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'), + }; + + const lastTrack = await GpsTracksModels.get2LastLoc({drv_id: did}); + // count milleage + if (logDevice.latitude != null && logDevice.longitude != null && lastTrack.length > 0) { + const distance = LibHelper.haversineGreatCircleDistance(lastTrack[0].latitude, lastTrack[0].longitude, logDevice.latitude, logDevice.longitude, LibHelper.EARTH_RADIUS_KM); + const distance_km = LibHelper.kmToKm(distance, 100000000); + console.log(`DRIVER UP LOCATION => did:${did}, distance_km:${distance_km}`); + if (distance_km < 3) { + const drv = await DriversModels.find(did); + if (drv.length > 0) { + logDevice.pre_milleage = distance_km; + logDevice.sum_milleage = (lastTrack[0].sum_milleage + logDevice.pre_milleage).toFixed(8); + if (lastTrack[0].did == logDevice.did) { + logDevice.drv_milleage = (lastTrack[0].drv_milleage + logDevice.pre_milleage).toFixed(8); + } else { + logDevice.drv_milleage = (drv[0].sum_milleage + logDevice.pre_milleage).toFixed(8); + } + DriversModels.update({ sum_milleage: logDevice.drv_milleage }, did); + } + } + } + + logDevices.push(logDevice); + const currTrack = await GpsTracksModels.bundleCreate2(logDevice, {}); + + /** + * get lastSpawn desc index 0, where leave_at = 0 + * kalo gaada create, dengan isi field enter_at aja, kalo ada didalam zona + * kalo ada update, dengan isi field leave_at aja, kalo udah diluar zona + */ + const lastSpawn = await GpsTracksModels.listSpawnZone({ + source: GpsTracksModels.SOURCE_SMARTPHONE, + vhc_id: 0, + drv_id: did, + ord_id: 0, + // ord_code: 0, + leave_at_d: 0, + order_by: 'ORDER BY id DESC', + limit: 1, + }); + if (lastSpawn.length > 0) { + let is_leave_zone = 1; + for (const insideZone of insideSpawnZone) { + if (insideZone.zid === lastSpawn[0].zone_id) is_leave_zone = 0; + } + if (is_leave_zone === 1) { + GpsTracksModels.updt2SpawnZone({ + leave_lat: lat, + leave_lng: lng, + leave_at_d: req_at, + leave_at_d_format: moment.unix(req_at).format('YYYY-MM-DD HH:mm:ss'), + leave_at_s: now, + leave_at_s_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'), + updt: now, + updt_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'), + }, lastSpawn[0].id); + } + } else { + for (const insideZone of insideSpawnZone) { + GpsTracksModels.create2SpawnZone({ + device_id: device_id, + master_id: Number(currTrack.result.insertId), + enter_lat: lat, + enter_lng: lng, + enter_at_d: req_at, + enter_at_d_format: moment.unix(req_at).format('YYYY-MM-DD HH:mm:ss'), + enter_at_s: now, + enter_at_s_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'), + zone_id: insideZone.zid, + zone_name: insideZone.name, + vhc_id: 0, + drv_id: did, + ord_id: 0, + // ord_code: 0, + source: GpsTracksModels.SOURCE_SMARTPHONE, + crt: now, + crt_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'), + }); + } + } + } + + apiRes = JSON.parse(JSON.stringify(response[200])); + // apiRes.raw = updtToOrders; + // apiRes.logDevices = logDevices; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + LibLogReqResApi.log(req, apiRes); + return res.status(500).json(apiRes); + } + } + + // OTHERS + async notif(req, res) { + let apiRes = {} + try { + const now = moment().unix(); + const { did, title, body, type, fcm_token, silent_notif } = req.body; + + // input validation + const input = { + did, + fcm_token, + title, + body, + type, + silent_notif, + }; + const rulesInput = { + did: 'required|integer', + fcm_token: 'required|string', + title: 'string|max:255', + body: 'string', + type: 'required|integer', + silent_notif: 'boolean', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const optFirebase = { + priority: 'normal', + android: { + priority: 'high', + }, + click_action: 'FLUTTER_NOTIFICATION_CLICK', + }; + let content_available = 'false'; + if (silent_notif === 'true' || silent_notif === true) { + optFirebase.content_available = true; // ios + content_available = 'true'; + } + + // const phoneDevice = await DriversModels.getDeviceByDid(did); + // if (phoneDevice.length < 1) { + // apiRes = JSON.parse(JSON.stringify(response[404])); + // apiRes.meta.code += '_1'; + // apiRes.meta.message = 'account not found, driver not login'; + LibLogReqResApi.log(req, apiRes); + // return res.status(200).json(apiRes); + // } + // if (phoneDevice[0].is_login !== DriversModels.IS_LOGIN) { + // apiRes = JSON.parse(JSON.stringify(response[404])); + // apiRes.meta.code += '_1'; + // apiRes.meta.message = 'account not found, driver not login'; + LibLogReqResApi.log(req, apiRes); + // return res.status(200).json(apiRes); + // } + + // phoneDevice[0].fcm_token + const libFirebase = new LibFirebase(); + let notifTitle = title || ''; + let notifBody = body || ''; + if (silent_notif === 'true' || silent_notif === true) { + optFirebase.priority = 'high'; + await libFirebase.sendToDevice(fcm_token, { + notification: { + title: 'Notifikasi Cek Lokasi', // notifTitle, + body: 'Harap Dihiraukan', // notifBody, + }, + data: { + title: notifTitle, + body: notifBody, + type: '' + type, + detail_id: '', + content_available, + } + }, optFirebase); + } else { + await libFirebase.sendToDevice(fcm_token, { + notification: { + title: notifTitle, + body: notifBody, + }, + data: { + title: notifTitle, + body: notifBody, + type: '' + type, + detail_id: '', + content_available, + } + }, optFirebase); + } + + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success send notification'; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + LibLogReqResApi.log(req, apiRes); + return res.status(500).json(apiRes); + } + } + + // DEV ONLY + async lastLatLng(req, res) { + let apiRes = {} + try { + const now = moment().unix(); + const { did } = req.query; + + // input validation + const input = { + did, + }; + const rulesInput = { + did: 'required|integer', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } + + const getLastLoc = await GpsTracksModels.getLastLocAndAddrByDid({did, limit: 100}); + const formatLastLoc = []; + + for (const lst of getLastLoc) { + formatLastLoc.push({ + id: lst.id, + did: lst.drv_id, + device_id: lst.device_id, + latitude: lst.latitude, + longitude: lst.longitude, + state_text: lst.state_text, + city_text: lst.city_text, + district_text: lst.district_text, + village_text: lst.village_text, + streets_text: lst.streets_text, + fulladdress: lst.fulladdress, + crt_device_unix: lst.crt_d, + crt_dvice_raw: lst.crt_d_format, + crt_server_unix: lst.crt_s, + crt_server_raw: lst.crt_s_format, + }); + } + + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.data = formatLastLoc; + LibLogReqResApi.log(req, apiRes); + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + LibLogReqResApi.log(req, apiRes); + return res.status(500).json(apiRes); + } + } +} + +const object = new ServiceDriverController(); + +module.exports = object; \ No newline at end of file diff --git a/controllers/WorkerController.js b/controllers/WorkerController.js new file mode 100644 index 0000000..a2373ea --- /dev/null +++ b/controllers/WorkerController.js @@ -0,0 +1,564 @@ +const moment = require('moment'); +const Validator = require('validatorjs'); +const Helper = require('../library/LibHelper'); +const GpsTracksModels = require('../models/GpsTracksModels'); +const response = require('../config/response'); +const LibSchedulerReverseGeocode = require('../library/LibSchedulerReverseGeocode'); +const LibQueueBlastOrder = require('../library/LibQueueBlastOrder'); +const LibSchedulerDrvUpLoc = require('../library/LibSchedulerDrvUpLoc'); +const LibSchedulerDrvUpPhoto = require('../library/LibSchedulerDrvUpPhoto'); +const LibSchedulerDrvUpLocIdle = require('../library/LibSchedulerDrvUpLocIdle'); +const LibSchedulerDrvBlastNotif = require('../library/LibSchedulerDrvBlastNotif'); +const LibSchedulerGpsTrackerWakeUp = require('../library/LibSchedulerGpsTrackerWakeUp'); +// START TESTING +const axios = require('axios').default; +const url = require('url'); +const request = require('../config/request'); +// END TESTING + +Validator.useLang('en'); + +class WorkerController { + + /** + * QUEUE + */ + + async add(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + const { name, data } = req.body; + + // input validation + const input = { + name, + }; + const rulesInput = { + name: 'required|string', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + + return res.status(200).json(apiRes); + } + + if (name === LibSchedulerReverseGeocode.name) { + LibSchedulerReverseGeocode.runQueueScheduler({ + label: 'Reverse geocoding from gps tracker latlng', + }); + } else if (name === LibQueueBlastOrder.name) { + LibQueueBlastOrder.addQueue({ + ...data, + label: 'Blast Order to Another Vendor', + delay: 5000, // 600000 || 10 minute + }); + } else if (name === LibSchedulerDrvUpLoc.name) { + LibSchedulerDrvUpLoc.runQueueScheduler({ + label: 'Scheduler driver up location', + }); + } else if (name === LibSchedulerDrvUpPhoto.name) { + LibSchedulerDrvUpPhoto.runQueueScheduler({ + label: 'Scheduler driver up photo', + }); + } else if (name === LibSchedulerDrvUpLocIdle.name) { + LibSchedulerDrvUpLocIdle.runQueueScheduler({ + label: 'Scheduler driver up location idle', + }); + } else if (name === LibSchedulerDrvBlastNotif.name) { + LibSchedulerDrvBlastNotif.runQueueScheduler({ + label: 'Scheduler driver blast notif', + }); + } else if (name === LibSchedulerGpsTrackerWakeUp.name) { + LibSchedulerGpsTrackerWakeUp.runQueueScheduler({ + label: 'Scheduler gps tracker wakeup', + }); + } else { + apiRes = JSON.parse(JSON.stringify(response[404])); + return res.status(200).json(apiRes); + } + + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success add queue'; + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + + async getJobs(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + const { name } = req.body; + + // input validation + const input = { + name, + }; + const rulesInput = { + name: 'required|string', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + + return res.status(200).json(apiRes); + } + + let gets = undefined; + if (name === LibSchedulerReverseGeocode.name) { + gets = await LibSchedulerReverseGeocode.getJobs(); + } else if (name === LibQueueBlastOrder.name) { + gets = await LibQueueBlastOrder.getJobs(); + } else if (name === LibSchedulerDrvUpLoc.name) { + gets = await LibSchedulerDrvUpLoc.getJobs(); + } else if (name === LibSchedulerDrvUpPhoto.name) { + LibSchedulerDrvUpPhoto.getJobs(); + } else if (name === LibSchedulerDrvUpLocIdle.name) { + gets = await LibSchedulerDrvUpLocIdle.getJobs(); + } else if (name === LibSchedulerDrvBlastNotif.name) { + gets = await LibSchedulerDrvBlastNotif.getJobs(); + } else if (name === LibSchedulerGpsTrackerWakeUp.name) { + gets = await LibSchedulerGpsTrackerWakeUp.getJobs(); + } else { + apiRes = JSON.parse(JSON.stringify(response[404])); + return res.status(200).json(apiRes); + } + + // success response + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success get jobs'; + apiRes.data = gets; + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + + async getRepeatableJobs(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + const { name } = req.body; + + // input validation + const input = { + name, + }; + const rulesInput = { + name: 'required|string', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + + return res.status(200).json(apiRes); + } + + let gets = undefined; + if (name === LibSchedulerReverseGeocode.name) { + gets = await LibSchedulerReverseGeocode.getRepeatableJobs(); + } else if (name === LibQueueBlastOrder.name) { + gets = await LibQueueBlastOrder.getRepeatableJobs(); + } else if (name === LibSchedulerDrvUpLoc.name) { + gets = await LibSchedulerDrvUpLoc.getRepeatableJobs(); + } else if (name === LibSchedulerDrvUpPhoto.name) { + LibSchedulerDrvUpPhoto.getRepetableJobs(); + } else if (name === LibSchedulerDrvUpLocIdle.name) { + gets = await LibSchedulerDrvUpLocIdle.getRepeatableJobs(); + } else if (name === LibSchedulerDrvBlastNotif.name) { + gets = await LibSchedulerDrvBlastNotif.getRepeatableJobs(); + } else if (name === LibSchedulerGpsTrackerWakeUp.name) { + gets = await LibSchedulerGpsTrackerWakeUp.getRepeatableJobs(); + } else { + apiRes = JSON.parse(JSON.stringify(response[404])); + return res.status(200).json(apiRes); + } + + // success response + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success get repeatable jobs'; + apiRes.data = gets; + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + + async resume(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + const { name } = req.body; + + // input validation + const input = { + name, + }; + const rulesInput = { + name: 'required|string', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + + return res.status(200).json(apiRes); + } + + if (name === LibSchedulerReverseGeocode.name) { + LibSchedulerReverseGeocode.resumeQueue(); + } else if (name === LibQueueBlastOrder.name) { + LibQueueBlastOrder.resumeQueue(); + } else if (name === LibSchedulerDrvUpLoc.name) { + LibSchedulerDrvUpLoc.resumeQueue(); + } else if (name === LibSchedulerDrvUpLocIdle.name) { + LibSchedulerDrvUpLocIdle.resumeQueue(); + } else if (name === LibSchedulerDrvUpPhoto.name) { + LibSchedulerDrvUpPhoto.resumeQueue(); + } else if (name === LibSchedulerDrvBlastNotif.name) { + LibSchedulerDrvBlastNotif.resumeQueue(); + } else if (name === LibSchedulerGpsTrackerWakeUp.name) { + LibSchedulerGpsTrackerWakeUp.resumeQueue(); + } else { + apiRes = JSON.parse(JSON.stringify(response[404])); + return res.status(200).json(apiRes); + } + + // success response + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success resume'; + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + + async pause(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + const { name } = req.body; + + // input validation + const input = { + name, + }; + const rulesInput = { + name: 'required|string', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + + return res.status(200).json(apiRes); + } + + if (name === LibSchedulerReverseGeocode.name) { + LibSchedulerReverseGeocode.pauseQueue(); + } else if (name === LibQueueBlastOrder.name) { + LibQueueBlastOrder.pauseQueue(); + } else if (name === LibSchedulerDrvUpLoc.name) { + LibSchedulerDrvUpLoc.pauseQueue(); + } else if (name === LibSchedulerDrvUpPhoto.name) { + LibSchedulerDrvUpPhoto.pauseQueue(); + } else if (name === LibSchedulerDrvUpLocIdle.name) { + LibSchedulerDrvUpLocIdle.pauseQueue(); + } else if (name === LibSchedulerDrvBlastNotif.name) { + LibSchedulerDrvBlastNotif.pauseQueue(); + } else if (name === LibSchedulerGpsTrackerWakeUp.name) { + LibSchedulerGpsTrackerWakeUp.pauseQueue(); + } else { + apiRes = JSON.parse(JSON.stringify(response[404])); + return res.status(200).json(apiRes); + } + + // success response + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success pause job'; + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + + async drain(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + const { name } = req.body; + + // input validation + const input = { + name, + }; + const rulesInput = { + name: 'required|string', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + + return res.status(200).json(apiRes); + } + + if (name === LibSchedulerReverseGeocode.name) { + LibSchedulerReverseGeocode.drainQueue(); + } else if (name === LibQueueBlastOrder.name) { + LibQueueBlastOrder.drainQueue(); + } else if (name === LibSchedulerDrvUpLoc.name) { + LibSchedulerDrvUpLoc.drainQueue() + } else if (name === LibSchedulerDrvUpPhoto.name) { + LibSchedulerDrvUpPhoto.drainQueue(); + } else if (name === LibSchedulerDrvUpLocIdle.name) { + LibSchedulerDrvUpLocIdle.drainQueue() + } else if (name === LibSchedulerDrvBlastNotif.name) { + LibSchedulerDrvBlastNotif.drainQueue() + } else if (name === LibSchedulerGpsTrackerWakeUp.name) { + LibSchedulerGpsTrackerWakeUp.drainQueue() + } else { + apiRes = JSON.parse(JSON.stringify(response[404])); + return res.status(200).json(apiRes); + } + + // success response + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success drain queue'; + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + + async obliterate(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + const { name } = req.body; + + // input validation + const input = { + name, + }; + const rulesInput = { + name: 'required|string', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + + return res.status(200).json(apiRes); + } + + if (name === LibSchedulerReverseGeocode.name) { + LibSchedulerReverseGeocode.obliterateQueue(); + } else if (name === LibQueueBlastOrder.name) { + LibQueueBlastOrder.obliterateQueue(); + } else if (name === LibSchedulerDrvUpLoc.name) { + LibSchedulerDrvUpLoc.obliterateQueue(); + } else if (name === LibSchedulerDrvUpPhoto.name) { + LibSchedulerDrvUpPhoto.obliterateQueue(); + } else if (name === LibSchedulerDrvUpLocIdle.name) { + LibSchedulerDrvUpLocIdle.obliterateQueue(); + } else if (name === LibSchedulerDrvBlastNotif.name) { + LibSchedulerDrvBlastNotif.obliterateQueue(); + } else if (name === LibSchedulerGpsTrackerWakeUp.name) { + LibSchedulerGpsTrackerWakeUp.obliterateQueue(); + } else { + apiRes = JSON.parse(JSON.stringify(response[404])); + return res.status(200).json(apiRes); + } + + // success response + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success obliterateQueue queue'; + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + + /** + * WORKERS + */ + + async start(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + const { name } = req.body; + + // input validation + const input = { + name, + }; + const rulesInput = { + name: 'required|string', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + + return res.status(200).json(apiRes); + } + + // just work if before this set have waiting list, so new queue will not be processed + if (name === LibSchedulerReverseGeocode.name) { + LibSchedulerReverseGeocode.setWorker(); + } else if (name === LibQueueBlastOrder.name) { + LibQueueBlastOrder.setWorker(); + } else if (name === LibSchedulerDrvUpLoc.name) { + LibSchedulerDrvUpLoc.setWorker(); + } else if (name === LibSchedulerDrvUpPhoto.name) { + LibSchedulerDrvUpPhoto.setWorker(); + } else if (name === LibSchedulerDrvUpLocIdle.name) { + LibSchedulerDrvUpLocIdle.setWorker(); + } else if (name === LibSchedulerDrvBlastNotif.name) { + LibSchedulerDrvBlastNotif.setWorker(); + } else if (name === LibSchedulerGpsTrackerWakeUp.name) { + LibSchedulerGpsTrackerWakeUp.setWorker(); + } else { + apiRes = JSON.parse(JSON.stringify(response[404])); + return res.status(200).json(apiRes); + } + + // success response + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success start worker'; + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + + async shutdown(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + const { name } = req.body; + + // input validation + const input = { + name, + }; + const rulesInput = { + name: 'required|string', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + return res.status(200).json(apiRes); + } + + if (name === LibSchedulerReverseGeocode.name) { + LibSchedulerReverseGeocode.workerShutDown(); + } else if (name === LibQueueBlastOrder.name) { + LibQueueBlastOrder.workerShutDown(); + } else if (name === LibSchedulerDrvUpLoc.name) { + LibSchedulerDrvUpLoc.workerShutDown(); + } else if (name === LibSchedulerDrvUpPhoto.name) { + LibSchedulerDrvUpPhoto.workerShutDown(); + } else if (name === LibSchedulerDrvUpLocIdle.name) { + LibSchedulerDrvUpLocIdle.workerShutDown(); + } else if (name === LibSchedulerDrvBlastNotif.name) { + LibSchedulerDrvBlastNotif.workerShutDown(); + } else if (name === LibSchedulerGpsTrackerWakeUp.name) { + LibSchedulerGpsTrackerWakeUp.workerShutDown(); + } else { + apiRes = JSON.parse(JSON.stringify(response[404])); + return res.status(200).json(apiRes); + } + + // success response + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success shutdown worker'; + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + + /** + * DO THE PROCESS VIA REQUEST + */ + + async revgeo(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + + // input validation + // const input = { }; + // const rulesInput = { }; + // const isInputValid = new Validator(input, rulesInput); + // if (isInputValid.fails()) { + // apiRes = JSON.parse(JSON.stringify(response[422])); + // apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + // return res.status(200).json(apiRes); + // } + + let params = new url.URLSearchParams({ + lat: req.body.lat, + lon: req.body.lon, + format: 'geojson', + }); + const axInstance = axios.create(); + axios.defaults.timeout = 3000; + axios.defaults.crossDomain = true; + // respReverseGeo = await axios({ + // url: request.osm_reverse_geo.urlFull, + // method: request.osm_reverse_geo.method, + // params: params, + // timeout: 3000, + // responseType: 'json', + // }); + let respReverseGeo = await axInstance.get(request.osm_reverse_geo.urlFull + '?' + params.toString(), { + timeout: 3000, + }); + + // success response + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success reverse geocode'; + apiRes.meta.data = respReverseGeo.data; + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + // apiRes.debug = e.response.data; + return res.status(500).json(apiRes); + } + } + +} + +const object = new WorkerController(); + +module.exports = object; \ No newline at end of file diff --git a/controllers/ZoneController.js b/controllers/ZoneController.js new file mode 100644 index 0000000..bfba76a --- /dev/null +++ b/controllers/ZoneController.js @@ -0,0 +1,134 @@ +const moment = require('moment'); +const Validator = require('validatorjs'); +const Helper = require('../library/LibHelper'); +const ZoneModels = require('../models/ZoneModels'); +const response = require('../config/response'); +const axios = require('axios').default; +const url = require('url'); +const request = require('../config/request'); + +Validator.useLang('en'); + +class ZoneController { + + async nearest(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + const { lat, lng, meters } = req.query; + + // input validation + const input = { + lat: lat, + lng: lng, + meters: meters, + }; + const rulesInput = { + lat: 'required|string|max:25', + lng: 'required|string|max:25', + meters: 'required|numeric', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + return res.status(200).json(apiRes); + } + + const nearest = await ZoneModels.getNearest(lat, lng, meters); + + // success response + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success get nearest zone in meters: ' + meters; + apiRes.count = nearest.length; + apiRes.data = nearest; + + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + + async inCircle(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + const { lat, lng } = req.query; + + // input validation + const input = { + lat: lat, + lng: lng, + }; + const rulesInput = { + lat: 'required|string|max:25', + lng: 'required|string|max:25', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + return res.status(200).json(apiRes); + } + + const inCircle = await ZoneModels.getInCircle(lat, lng); + + // success response + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success get in circle zone'; + apiRes.count = inCircle.length; + apiRes.data = inCircle; + + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + + async inShape(req, res) { + let apiRes = {}; + try { + const now = moment().unix(); + const { lat, lng } = req.query; + + // input validation + const input = { + lat: lat, + lng: lng, + }; + const rulesInput = { + lat: 'required|string|max:25', + lng: 'required|string|max:25', + }; + const isInputValid = new Validator(input, rulesInput); + if (isInputValid.fails()) { + apiRes = JSON.parse(JSON.stringify(response[422])); + apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message + return res.status(200).json(apiRes); + } + + const inShape = await ZoneModels.getInShape(lat, lng); + + // success response + apiRes = JSON.parse(JSON.stringify(response[200])); + apiRes.meta.message = 'success get in shape zone'; + apiRes.count = inShape.length; + apiRes.data = inShape; + + return res.status(200).json(apiRes); + } catch (e) { + apiRes = JSON.parse(JSON.stringify(response[500])); + apiRes.meta.message += Helper.setErrMsg(': ' + e.message); + return res.status(500).json(apiRes); + } + } + +} + +const object = new ZoneController(); + +module.exports = object; \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..1e937a5 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,39 @@ +version: "3.7" +services: + app: + build: + context: ./ + dockerfile: Dockerfile + image: trucking-node + container_name: trucking-node + restart: unless-stopped + working_dir: /var/www/html/services/trucking + volumes: + - .:/var/www/html/services/trucking + ports: + - "6014:6014" + - "3400:3400" + networks: + - trucking-node + entrypoint: [ "/bin/sh", "-c" ] + command: + - | + mv /node_modules /var/www/html/services/trucking/node_modules + npm run app_scheduler + + redis: + image: redis:alpine + container_name: trucking-redis + restart: unless-stopped + ports: + - "6380:6379" + networks: + - trucking-node + entrypoint: [ "/bin/sh", "-c" ] + command: + - | + redis-server + +networks: + trucking-node: + driver: bridge diff --git a/files/keys/bingcorp-tracker-firebase-adminsdk-7tcet-7399bbf4fc.json b/files/keys/bingcorp-tracker-firebase-adminsdk-7tcet-7399bbf4fc.json new file mode 100644 index 0000000..b78ce01 --- /dev/null +++ b/files/keys/bingcorp-tracker-firebase-adminsdk-7tcet-7399bbf4fc.json @@ -0,0 +1,12 @@ +{ + "type": "service_account", + "project_id": "bingcorp-tracker", + "private_key_id": "7399bbf4fca3bc4205b32f1a3b9adb740e005aaf", + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDTpSHA3BozL9mB\nq/2p78/seNNjB7fGwRWIU+s55wAhI46SWgbRs8rpSbVskN8m+KssJPGQg423sj6d\nY72uxULbGVuoM7jRphj52PfxajhUU8VhLWk0oPZqz66arAxiRBQZXrgUgk3jTj3G\nGnkgdFOF/pgBSc8XvN7CUE3A6ktteu2DkKbAI6itP8uA5xp8wtmBfc8hU4pIe1mi\nhrI+WUF2tIO5NsblbhcZWBzodBOTxq3wkcbuLarWWb2rrL7HEbRnG0TzsGRl+Hso\npcGjLwdz2FZuW2HJGWSABqazazlmDEnqk2PDJFsUCyZV38tE+zfvPvh1DnCmNvBB\n7YXW8aPPAgMBAAECggEAL3Po23r+DNf/polPeJiiP9zfWGbUl6WXFFfsd7EJYGS+\nhKXWvZHYPvId0VeyEOTUTDOETeiRD8zRKSzBzLvBv6ox2Mav+6GIHAy/mss8Efwu\nVxl9ayVj2pLyDQ/iPu4Qq5eHImIM4JgcVZx95/7s8zAgGLnZyvK3501mAYkGnGb4\nuO4sqIJsWUa2xmztBgJ9C09VCcBsp0qbFsNV7rA6ygumuvHenXEKvABHtXLqRdBs\nhdoSah4CYqbD80DpEdZVQirS13BjromQ2f3iN9icdBzX2dS6HYCm/fRvKk03HK8N\nPtJNkeaQLG6I955pNSAomV6wm5Z4abmEPPYv8mv/0QKBgQD85SiazR4xJK5DmkeS\nYhxW2Fi9hM0AShtyIjcV4uMgYB5mQ/bxQIuyx8bchUoTPHf7l1IN1nGIBLA37ePU\nuEWqxZfQ2x1yFXEAKL214piRuVXK48kc5734hKQFeTkhNonhMEyoci1SrAhSDsXH\nbeSggtAiVQFzIgCCFH28qmwpjQKBgQDWPlNSUpR8uwEZ19q90UbzCWC3RsiPyGEM\nKxMk4FHC1Hq2y/dL87UyKOL3UupzUGVowMKyktT4nHhP3zhgBu7CFk9GM6BgecNR\nivTmVZoLKZr4sj+weZzZuwDWa+lii3XU4te/CoH9cqk4c7aFQmtWV8hi5AfDf17Z\nqdKoX/y1ywKBgCZJg2Y8W6/Q/9kYSHGvDN9RDc5Thr3eel1DNNfJa92A79lHvOE1\nhnDgsgi83UQgSYH7nN6fcrzHCO7Ow0l3RITgOWXTZpfZCyyc/mvFDJgzWPvIlLAd\nnbM8UaDKg421thYzu8dc0ePMS84wklzpFE4AwAYSnI+TvEP1WjvwCUQZAoGBAIIz\nFkftT7gNnbmq6JB64ndIt7IqHjDjQbc3Zkb+3DFfF8SHaB6MWQ3Gs0hC56B0t2xV\n2PzVJwB/ds5zhbs1+1uQW1T6gviehwjDPdnNI/SssDV7fiEthxj7AKNOqWLuBgn+\nYccEB8OTLyvThpStrLWoW2td0SoJ+galohQZYWbJAoGAVnpfqm2j3mpmebNpAVDy\nzfGKsEo6QBiUeyoGIyRnWqw+jg/jP4a6ytryuUfL/u0QilVXZxSeEZ51wAfpXjud\nCNTVSIFja1df4tp2vgQifJw3y/SpK0IVDs3vBoxL2kCknpDEAnKBbhUv3WVqSCg2\n3ULAhzsRuh3d7Vs/hdMfgOI=\n-----END PRIVATE KEY-----\n", + "client_email": "firebase-adminsdk-7tcet@bingcorp-tracker.iam.gserviceaccount.com", + "client_id": "104296203536255131294", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-7tcet%40bingcorp-tracker.iam.gserviceaccount.com" +} diff --git a/files/keys/bingcorp-tracker-firebase-adminsdk-7tcet-c817089752.json b/files/keys/bingcorp-tracker-firebase-adminsdk-7tcet-c817089752.json new file mode 100644 index 0000000..2d42a9e --- /dev/null +++ b/files/keys/bingcorp-tracker-firebase-adminsdk-7tcet-c817089752.json @@ -0,0 +1,12 @@ +{ + "type": "service_account", + "project_id": "bingcorp-tracker", + "private_key_id": "c817089752ecb864e685fc23acc65fcb4c14cffe", + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDGNPI/mray4qQ/\noOxUSbVB2IRiQgxUAifKumWq7/r8229+2ZJQHXuHu8fGPHzS8U9VtZ50pyRyW8kF\n6mrKjmHOG/0EKZPx/GWa/mSpDGENEpKsDIPRrbfrUjZs0oILRXQC1Dvh6USq0th6\nQdFFUiXb8oL03IpSdmUQscUICM1IdS75IAxPRhAg8UQlG9GQggqM7jyKpzwncW4M\nRY+VoCN3znx+X5Hn7OBMcF5IbGq4Fuk4GKgHjkqoHeNUtswrF6k6ZAUdvPie0rhw\n+cFYQdt6O0VcgTA0GtlMUrm5IPxJhD1jLL8p8Mr9kckp1xzqHnxfdqCgOgydIjRM\ns0VCMB77AgMBAAECggEAMXjptmKBk6jqYk9iba9wJJ1MfdIKjbV0BS/9TGtV9GM5\nMypPUNvrB3ghZyOV7Hj62mPYxzko6bprNKTMPv7G/tERmEZgfRgIrGUu7tr+Jmsq\nXPNKu71mmMAOgZ8Rgoq1aDddMwgscY7rJajj+S+F755afY/Gnsqac05L5bN8ucbE\nt9w8zvcut9nKpcMGHSjhgIacTFnAsjw6ZN485UDHKNoxL7DPdMILtJcqzK9dufvQ\n4yf4ps+3VBxLgXEw6yUU5PfFJxIPhZ9VHGOjWCcqsNN0XIiWB5wLpTdwFSqr1+fL\nleRPo1aRY/IqhrFvLqjGSjukxfMtlRjpvHAUTsNw4QKBgQD/kOSAWLM+h1krgm26\nPf7B+0A2cIwVO+Qc1f7JCYgzZA3/xQoclmL5pr+llc6wiLPFTucomu5sD+X8Es1i\nY5Zcxtr7FuUXraNBXsExfzRsGDpD3Skp2Jzq29+eqof5lgFZaLxfW1fPRAgvH0Ml\n32kcG2huWJHvBenA1zeX0yP1QwKBgQDGix3lPgfibEunlop5WZovOcHa3LIAA8t3\n8aBb4sx3xFrTRPYyB+39dGk2FiV/sjofw57MmNhc/EIM6kMEvR0TlDuqHIPUbV5/\nPqeeB6ZSHiTbT+DzuyR9FVnDkKLSpa630cBCI/LVT+Bzb3UbAPGU7WtEEIHn8FKq\nxo1ZoaG36QKBgQCinaqX9FjRj8PwiISTfkEtY1b/jOvF0x8aLhx6BWOx95dkyRbf\nC94cprrJfSJQeBuTj9pMnxDYl+EqXThsw5t4m1vZaz8Iqwb3YHijqyJLKbthVUeN\nBfULCC8pQa9V49ol7xv1vSSJkOt4OHc8kQTLyrDPjfIF2ohbmVYZeFMoCwKBgAMV\ngh9feUvhFsPBqOD9rVFyejpmFzW82VpBnJYQzdBGcoq5lYFtchrvxfqbGXYEVLbN\nmRfgf+vh1zzQHr5iGaOGN+8Khlm0YTVkycHAqKq54SSu9vWSQJzYyg4pnv3aqP4d\n+fiNCmaZ2QiyAIWs3BPOJE5oWzw5FW+lqehshFCRAoGAW8ebJPM8BAcmYnLzF+6d\nnbmMm7jYG+H3oXWmPm64wJZbB96KlKO6zv3s8H3HxDh1IH30gwXEjJlDfweSrBKg\n+kTodZf8AiZ9ehXRfrTYoAaEVoa1VxOnmlxvBLHm/jNsFQ3EKHSkHBMgpXuw1ew1\n+boJf7x3wYYenIozHGpRMYI=\n-----END PRIVATE KEY-----\n", + "client_email": "firebase-adminsdk-7tcet@bingcorp-tracker.iam.gserviceaccount.com", + "client_id": "104296203536255131294", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-7tcet%40bingcorp-tracker.iam.gserviceaccount.com" +} diff --git a/files/keys/google-services.json b/files/keys/google-services.json new file mode 100644 index 0000000..ed9c590 --- /dev/null +++ b/files/keys/google-services.json @@ -0,0 +1,40 @@ +{ + "project_info": { + "project_number": "805397037863", + "firebase_url": "https://bingcorp-tracker-default-rtdb.asia-southeast1.firebasedatabase.app", + "project_id": "bingcorp-tracker", + "storage_bucket": "bingcorp-tracker.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:805397037863:android:dd7678e4f5da382d209f02", + "android_client_info": { + "package_name": "com.example.bingcopapp" + } + }, + "oauth_client": [ + { + "client_id": "805397037863-pe9itqcudrnjcvv76f68tgni2cqd1c4i.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyCO2sI-MFlAWS-4uzm9wX5QhCZDyvMWBi4" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "805397037863-pe9itqcudrnjcvv76f68tgni2cqd1c4i.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/files/mails/admInfoOrder.ejs b/files/mails/admInfoOrder.ejs new file mode 100644 index 0000000..13cb891 --- /dev/null +++ b/files/mails/admInfoOrder.ejs @@ -0,0 +1,70 @@ +<%- include('template/start', {asset: asset}) %> + + + + + + + +
+
+

Halo <%= admin_name %>,

+

+ Ada client telah membuat order pada tanggal <%= trx_at %> dengan kriteria berikut: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Order_Code<%= trx_code %>
Pickup_At + <%= pickup_at %> +
Client_Name<%= client_name %>
Client_Phone<%= client_phone %>
Client_Mail<%= client_mail %>
Pickup_Zone + <%= pickup_zone_title %>
+ <%= pickup_zone_addr %> +
Drop_Zone + <%= drop_zone_title %>
+ <%= drop_zone_addr %> +
+
+

+ Segera lakukan pencarian vendor +

+

+ Butuh bantuan ? Segera hubungi layanan pelanggan Bonceng di <%= cs_phone %> atau email ke <%= cs_mail %>. +

+

+ Email ini dibuat secara otomatis. Mohon tidak mengirimkan balasan ke email ini. +

+
+
+ + + +<%- include('template/end', {asset: asset, cs_mail: cs_mail, cs_phone: cs_phone, cs_addr: cs_addr}) %> \ No newline at end of file diff --git a/files/mails/adminInfoNoVdrAccOrd.ejs b/files/mails/adminInfoNoVdrAccOrd.ejs new file mode 100644 index 0000000..9fb2007 --- /dev/null +++ b/files/mails/adminInfoNoVdrAccOrd.ejs @@ -0,0 +1,70 @@ +<%- include('template/start', {asset: asset}) %> + + + + + + + +
+
+

Halo <%= admin_name %>,

+

+ Order pada tanggal <%= trx_at %>, tidak ada vendor yang menerima / menginginkan order dengan kriteria berikut: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Order_Code<%= trx_code %>
Pickup_At + <%= pickup_at %> +
Client_Name<%= client_name %>
Client_Phone<%= client_phone %>
Client_Mail<%= client_mail %>
Pickup_Zone + <%= pickup_zone_title %>
+ <%= pickup_zone_addr %> +
Drop_Zone + <%= drop_zone_title %>
+ <%= drop_zone_addr %> +
+
+

+ Segera lakukan pencarian / assign vendor secara manual +

+

+ Butuh bantuan ? Segera hubungi layanan pelanggan Bonceng di <%= cs_phone %> atau email ke <%= cs_mail %>. +

+

+ Email ini dibuat secara otomatis. Mohon tidak mengirimkan balasan ke email ini. +

+
+
+ + + +<%- include('template/end', {asset: asset, cs_mail: cs_mail, cs_phone: cs_phone, cs_addr: cs_addr}) %> \ No newline at end of file diff --git a/files/mails/bidOrderMail.ejs b/files/mails/bidOrderMail.ejs new file mode 100644 index 0000000..4c367ab --- /dev/null +++ b/files/mails/bidOrderMail.ejs @@ -0,0 +1,98 @@ +<%- include('template/start', {asset: asset}) %> + + + + + + + +
+
+

Halo <%= vendor_name %>,

+

+ Ada order masuk dengan kriteria berikut: +

+ + + + + + + + + + + + + + + + + + + <% if(client_prefer_type_truck !== ''){ %> + + + + + <% } %> + + <% /* %> + <% if(weight !== 0){ %> + + + + + <% } %> + <% if(cbm !== 0){ %> + + + + + <% } %> + <% if(koli !== 0){ %> + + + + + <% } %> + <% */ %> + + + + + + + + + + + + + + +
Order_Code<%= trx_code %>
Client_Name<%= client_name %>
Client_Phone<%= client_phone %>
Client_Mail<%= client_mail %>
Preferred_Type<%= client_prefer_type_truck %>
Weight<%= weight %> Kg
Volume<%= cbm %> m³
Koli<%= koli %> Pcs
Pickup_Zone + <%= pickup_zone_title %>
+ <%= pickup_zone_addr %> +
Pickup_At + <%= pickup_at %> +
Drop_Zone + <%= drop_zone_title %>
+ <%= drop_zone_addr %> +
+
+

+ Jika kamu ingin mengambil order ini, silahkan segera klik link berikut: <%= vendor_acc_link %> +

+

+ Butuh bantuan ? Segera hubungi layanan pelanggan Bonceng di <%= cs_phone %> atau email ke <%= cs_mail %>. +

+

+ Email ini dibuat secara otomatis. Mohon tidak mengirimkan balasan ke email ini. +

+
+
+ + + +<%- include('template/end', {asset: asset, cs_mail: cs_mail, cs_phone: cs_phone, cs_addr: cs_addr}) %> \ No newline at end of file diff --git a/files/mails/clientCreateOrd.ejs b/files/mails/clientCreateOrd.ejs new file mode 100644 index 0000000..9f193e6 --- /dev/null +++ b/files/mails/clientCreateOrd.ejs @@ -0,0 +1,86 @@ +<%- include('template/start', {asset: asset}) %> + + + + + + + +
+
+

Halo <%= client_name %>,

+

+ Kamu telah membuat order pada tanggal <%= trx_at %> dengan kriteria berikut: +

+ + + + + + + <% if(client_prefer_type_truck !== ''){ %> + + + + + <% } %> + + <% /* %> + <% if(weight !== 0){ %> + + + + + <% } %> + <% if(cbm !== 0){ %> + + + + + <% } %> + <% if(koli !== 0){ %> + + + + + <% } %> + <% */ %> + + + + + + + + + + + + + + +
Order_Code<%= trx_code %>
Preferred_Type<%= client_prefer_type_truck %>
Weight<%= weight %> Kg
Volume<%= cbm %> m³
Koli<%= koli %> Pcs
Pickup_Zone + <%= pickup_zone_title %>
+ <%= pickup_zone_addr %> +
Pickup_At + <%= pickup_at %> +
Drop_Zone + <%= drop_zone_title %>
+ <%= drop_zone_addr %> +
+
+

+ Jika kamu tidak membuat transaksi ini, silahkan segera hubungi layanan pelanggan Bonceng. +

+

+ Butuh bantuan ? Segera hubungi layanan pelanggan Bonceng di <%= cs_phone %> atau email ke <%= cs_mail %>. +

+

+ Email ini dibuat secara otomatis. Mohon tidak mengirimkan balasan ke email ini. +

+
+
+ + + +<%- include('template/end', {asset: asset, cs_mail: cs_mail, cs_phone: cs_phone, cs_addr: cs_addr}) %> \ No newline at end of file diff --git a/files/mails/clientOrdHaveBeenAccMail.ejs b/files/mails/clientOrdHaveBeenAccMail.ejs new file mode 100644 index 0000000..8a9f696 --- /dev/null +++ b/files/mails/clientOrdHaveBeenAccMail.ejs @@ -0,0 +1,107 @@ +<%- include('template/start', {asset: asset}) %> + + + + + + + +
+
+

Halo <%= client_name %>,

+

+ Order kamu telah diterima pada tanggal <%= acc_at %> oleh <%= driver_name %>, dengan kriteria berikut: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <% if(client_prefer_type_truck !== ''){ %> + + + + + <% } %> + + <% /* %> + <% if(weight !== 0){ %> + + + + + <% } %> + <% if(cbm !== 0){ %> + + + + + <% } %> + <% if(koli !== 0){ %> + + + + + <% } %> + <% */ %> + + + + + + + + + + + + + + +
Order_Code<%= trx_code %>
Driver_Name<%= driver_name %>
Driver_Phone<%= driver_phone %>
Driver_Mail<%= driver_mail %>
Vendor_Name<%= vendor_name %>
Vendor_Phone<%= vendor_phone %>
Vendor_Mail<%= vendor_mail %>
Preferred_Type<%= client_prefer_type_truck %>
Weight<%= weight %> Kg
Volume<%= cbm %> m³
Koli<%= koli %> Pcs
Pickup_Zone + <%= pickup_zone_title %>
+ <%= pickup_zone_addr %> +
Pickup_At + <%= pickup_at %> +
Drop_Zone + <%= drop_zone_title %>
+ <%= drop_zone_addr %> +
+
+

+ Butuh bantuan ? Segera hubungi layanan pelanggan Bonceng di <%= cs_phone %> atau email ke <%= cs_mail %>. +

+

+ Email ini dibuat secara otomatis. Mohon tidak mengirimkan balasan ke email ini. +

+
+
+ + + +<%- include('template/end', {asset: asset, cs_mail: cs_mail, cs_phone: cs_phone, cs_addr: cs_addr}) %> \ No newline at end of file diff --git a/files/mails/driverGetOrderMail.ejs b/files/mails/driverGetOrderMail.ejs new file mode 100644 index 0000000..fe274f1 --- /dev/null +++ b/files/mails/driverGetOrderMail.ejs @@ -0,0 +1,80 @@ +<%- include('template/start', {asset: asset}) %> + + + + + + + +
+
+

Halo <%= driver_name %>,

+

+ Kamu telah mendapatkan order pada tanggal <%= acc_at %>, dengan kriteria berikut: +

+ + + + + + + + + + + + + + + + <% /* %> + <% if(weight !== 0){ %> + + + + + <% } %> + <% if(cbm !== 0){ %> + + + + + <% } %> + <% if(koli !== 0){ %> + + + + + <% } %> + <% */ %> + + + + + + +
Order_Code<%= trx_code %>
Pickup_Zone + <%= pickup_zone_title %>
+ <%= pickup_zone_addr %> +
Pickup_At + <%= pickup_at %> +
Weight<%= weight %> Kg
Volume<%= cbm %> m³
Koli<%= koli %> Pcs
Drop_Zone + <%= drop_zone_title %>
+ <%= drop_zone_addr %> +
+
+

+ Silahkan segera temui vendor untuk mendapatkan Delivery Order dan pickup ke lokasi tujuan +

+

+ Butuh bantuan ? Segera hubungi layanan pelanggan Bonceng di <%= cs_phone %> atau email ke <%= cs_mail %>. +

+

+ Email ini dibuat secara otomatis. Mohon tidak mengirimkan balasan ke email ini. +

+
+
+ + + +<%- include('template/end', {asset: asset, cs_mail: cs_mail, cs_phone: cs_phone, cs_addr: cs_addr}) %> \ No newline at end of file diff --git a/files/mails/financeInfoDanaAmount.ejs b/files/mails/financeInfoDanaAmount.ejs new file mode 100644 index 0000000..02f682a --- /dev/null +++ b/files/mails/financeInfoDanaAmount.ejs @@ -0,0 +1,46 @@ +<%- include('template/start', {asset: asset}) %> + + + + + + + +
+
+

Halo <%= admin_name %>,

+

+ Tidak bisa melakukan transfer uang saku, dikarenakan dana saat ini tidak mencukupi untuk melakukan transfer. +

+ + + + + + + + + + + + + + + +
Dana Saat Ini<%= dana_current %>
Minimum Saldo Dana<%= dana_minimum %>
Jumlah Transfer Uang Saku<%= pocket_total %>
+
+

+ Segera tambah saldo dana. +

+

+ Butuh bantuan ? Segera hubungi layanan pelanggan Bonceng di <%= cs_phone %> atau email ke <%= cs_mail %>. +

+

+ Email ini dibuat secara otomatis. Mohon tidak mengirimkan balasan ke email ini. +

+
+
+ + + +<%- include('template/end', {asset: asset, cs_mail: cs_mail, cs_phone: cs_phone, cs_addr: cs_addr}) %> \ No newline at end of file diff --git a/files/mails/financeInfoTfPocket.ejs b/files/mails/financeInfoTfPocket.ejs new file mode 100644 index 0000000..e5ed070 --- /dev/null +++ b/files/mails/financeInfoTfPocket.ejs @@ -0,0 +1,88 @@ +<%- include('template/start', {asset: asset}) %> + + + + + + + +
+
+

Halo <%= admin_name %>,

+

+ Transfer uang saku kepada driver <% drv_name %>, dengan rincian: +

+ + + + + + + + + + + <% if(drop_zone_title !== ''){ %> + + + + + <% } %> + + + + + + + + + + + + + + + + + + + + + <% if(bank_branch_name !== ''){ %> + + + + + <% } %> + + + + + + + + + +
Order Code<%= trx_code %>
Pickup Zone + <%= pickup_zone_title %>
+ <%= pickup_zone_addr %> +
Drop Zone + <%= drop_zone_title %>
+ <%= drop_zone_addr %> +
  
Nominal<%= pocket_total %>
  
Bank<%= bank_name %>
Kode<%= bank_code %>
Cabang<%= bank_branch_name %>
Pemilik Rekening<%= bank_acc_name %>
No Rekening<%= bank_acc_no %>
+
+

+ Segera lakukan pembayaran +

+

+ Butuh bantuan ? Segera hubungi layanan pelanggan Bonceng di <%= cs_phone %> atau email ke <%= cs_mail %>. +

+

+ Email ini dibuat secara otomatis. Mohon tidak mengirimkan balasan ke email ini. +

+
+
+ + + +<%- include('template/end', {asset: asset, cs_mail: cs_mail, cs_phone: cs_phone, cs_addr: cs_addr}) %> \ No newline at end of file diff --git a/files/mails/template/end.ejs b/files/mails/template/end.ejs new file mode 100644 index 0000000..7aabbac --- /dev/null +++ b/files/mails/template/end.ejs @@ -0,0 +1,48 @@ + + + + +

+ Butuh bantuan? hubungi kami: + <%= cs_phone %>
+ <%= cs_mail %> +

+ + + + + + + + + + + + + \ No newline at end of file diff --git a/files/mails/template/start.ejs b/files/mails/template/start.ejs new file mode 100644 index 0000000..98379dc --- /dev/null +++ b/files/mails/template/start.ejs @@ -0,0 +1,356 @@ + + + + + + + + + + + + + +
+