commit b7e852126c5c178257a7f762e5b60cfa9a62cb08 Author: meusinfirmary Date: Tue Apr 22 14:31:37 2025 +0700 Initial commit 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 0000000..1fd549b Binary files /dev/null and b/Message Notifikasi Apps Driver Tracker.xlsx differ 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 @@ + + + + + + + + + + + + + +
+