diff --git a/backend/package-lock.json b/backend/package-lock.json index 6731089747c84f84bccc3b9267a1cdbde633174b..48978bb04c09913f57cb6ecbc0f5a9fd83de30f9 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -4,6 +4,11 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@types/node": { + "version": "11.11.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.5.tgz", + "integrity": "sha512-pz6wNe/XwyesgfVX7P6B0hY3TnTAYXk6KSTLdpQfbuq3be+hnMoCuFzE+yLTskPdBwmNiGRL2TAsnF09aRugvQ==" + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -39,6 +44,11 @@ "color-convert": "^1.9.0" } }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" + }, "anymatch": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", @@ -161,11 +171,21 @@ "safe-buffer": "5.1.2" } }, + "bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" + }, "binary-extensions": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.0.tgz", "integrity": "sha512-EgmjVLMn22z7eGGv3kcnHwSnJXmFHjISTY9E/S5lIcTD3Oxw05QTcBLNkJFzcb3cNueUdF/IN4U+d78V0zO8Hw==" }, + "bluebird": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", + "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==" + }, "body-parser": { "version": "1.18.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", @@ -233,6 +253,11 @@ } } }, + "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=" + }, "buffer-writer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", @@ -329,6 +354,15 @@ "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=" }, + "cls-bluebird": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cls-bluebird/-/cls-bluebird-2.1.0.tgz", + "integrity": "sha1-N+8eCAqP+1XC9BZPU28ZGeeWiu4=", + "requires": { + "is-bluebird": "^1.0.2", + "shimmer": "^1.1.0" + } + }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -514,11 +548,24 @@ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz", "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==" }, + "dottie": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.1.tgz", + "integrity": "sha512-ch5OQgvGDK2u8pSZeSYAQaV/lczImd7pMJ7BcEPXmnFVjy4yJIzP6CsODJUTH8mg1tyH1Z2abOiuJO3DjZ/GBw==" + }, "duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" }, + "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", @@ -815,7 +862,8 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", @@ -936,6 +984,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -1047,7 +1096,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -1353,6 +1403,11 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" }, + "inflection": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", + "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=" + }, "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", @@ -1394,6 +1449,11 @@ "binary-extensions": "^1.0.0" } }, + "is-bluebird": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-bluebird/-/is-bluebird-1.0.2.tgz", + "integrity": "sha1-CWQ5Bg9KpBGr7hkUOoTWpVNG1uI=" + }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", @@ -1553,6 +1613,49 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, + "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.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "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" + } + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -1566,6 +1669,46 @@ "package-json": "^4.0.0" } }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, + "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=" + }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -1686,6 +1829,19 @@ } } }, + "moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" + }, + "moment-timezone": { + "version": "0.5.23", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.23.tgz", + "integrity": "sha512-WHFH85DkCfiNMDX5D3X7hpNH3/PUhjTGcD0U1SgfBGZxJ3qUmJh5FdvaFjcClxOvB3rzdfj4oRffbI38jEnC1w==", + "requires": { + "moment": ">= 2.9.0" + } + }, "morgan": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", @@ -1929,6 +2085,14 @@ "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-0.1.3.tgz", "integrity": "sha1-2hhHsglA5C7hSSvq9l1J2RskXfc=" }, + "pg-hstore": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/pg-hstore/-/pg-hstore-2.3.2.tgz", + "integrity": "sha1-9+8FPnubiSrphq8vfL6GQy388k8=", + "requires": { + "underscore": "^1.7.0" + } + }, "pg-int8": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", @@ -2128,6 +2292,14 @@ "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" }, + "retry-as-promised": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-3.2.0.tgz", + "integrity": "sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==", + "requires": { + "any-promise": "^1.3.0" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -2179,6 +2351,57 @@ "statuses": "~1.4.0" } }, + "sequelize": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-5.1.0.tgz", + "integrity": "sha512-LmjEAedMTItkIx0mcBfXVmdkkIQOc+1reuv+UpqSADGvQofZ4Sn9ElUBE8egLgCK4oWjy1Ybsju+YDAJpCv1ww==", + "requires": { + "bluebird": "^3.5.0", + "cls-bluebird": "^2.1.0", + "debug": "^4.1.1", + "depd": "^2.0.0", + "dottie": "^2.0.0", + "inflection": "1.12.0", + "lodash": "^4.17.11", + "moment": "^2.24.0", + "moment-timezone": "^0.5.21", + "retry-as-promised": "^3.1.0", + "semver": "^5.6.0", + "sequelize-pool": "^1.0.2", + "toposort-class": "^1.0.1", + "uuid": "^3.2.1", + "validator": "^10.11.0", + "wkx": "^0.4.6" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "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.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "sequelize-pool": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-1.0.2.tgz", + "integrity": "sha512-VMKl/gCCdIvB1gFZ7p+oqLFEyZEz3oMMYjkKvfEC7GoO9bBcxmfOOU9RdkoltfXGgBZFigSChihRly2gKtsh2w==", + "requires": { + "bluebird": "^3.5.3" + } + }, "serve-static": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", @@ -2229,6 +2452,11 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" }, + "shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" + }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -2492,6 +2720,11 @@ "repeat-string": "^1.6.1" } }, + "toposort-class": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", + "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" + }, "touch": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", @@ -2517,6 +2750,11 @@ "debug": "^2.2.0" } }, + "underscore": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", + "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" + }, "union-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", @@ -2653,6 +2891,16 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + }, + "validator": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", + "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -2674,6 +2922,14 @@ "string-width": "^2.1.1" } }, + "wkx": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.4.6.tgz", + "integrity": "sha512-LHxXlzRCYQXA9ZHgs8r7Gafh0gVOE8o3QmudM1PIkOdkXXjW7Thcl+gb2P2dRuKgW8cqkitCRZkkjtmWzpHi7A==", + "requires": { + "@types/node": "*" + } + }, "write-file-atomic": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.2.tgz", diff --git a/backend/package.json b/backend/package.json index 780e847736674f9fe184f3b929f66b24ae90cbb2..34e5edcf328627082ef02ab3eb0fa94d280eece6 100644 --- a/backend/package.json +++ b/backend/package.json @@ -4,19 +4,23 @@ "description": "", "main": "index.js", "scripts": { - "start": "node .\\node_modules\\nodemon\\bin\\nodemon.js src\\app.js", + "start": "node src/app.js", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { + "bcryptjs": "^2.4.3", "body-parser": "^1.18.3", "cors": "^2.8.5", "dotenv": "^6.2.0", "express": "^4.16.4", + "jsonwebtoken": "^8.5.1", "morgan": "^1.9.1", "nodemon": "^1.18.10", - "pg": "^7.8.2" + "pg": "^7.8.2", + "pg-hstore": "^2.3.2", + "sequelize": "^5.1.0" } } diff --git a/backend/src/app.js b/backend/src/app.js index dbd21ce3da319eeda5b304519d2e46633698527c..d2ed579cf0a5af595795b7843d5ea80da7c4a6d8 100644 --- a/backend/src/app.js +++ b/backend/src/app.js @@ -1,5 +1,4 @@ require('dotenv').load() -//const config = require('./config') const express = require('express') const bodyParser = require('body-parser') const cors = require('cors') @@ -10,9 +9,43 @@ app.use(morgan('combined')) app.use(bodyParser.json()) app.use(cors()) -var routes = require('./routes') +const db = require('./config/db.config.js'); +const Role = db.role; +// force: true will drop the table if it already exists +db.sequelize.sync({force: true}).then(() => { + console.log('Drop and Resync with { force: true }'); + initial(); +}); + +var routes = require('./router/router') routes(app) -port = process.env.PORT || 8000 -app.listen(port) -console.log("API listening on port " + port) \ No newline at end of file +var server = app.listen(process.env.PORT, function () { + + var host = server.address().address + var port = server.address().port + + console.log("App listening at http://%s:%s", host, port) +}) + +function initial(){ + Role.create({ + id: 1, + name: 'Master Admin Diskominfo' + }); + + Role.create({ + id: 2, + name: 'Admin Diskominfo' + }); + + Role.create({ + id: 3, + name: 'Admin Dinas' + }); + + Role.create({ + id: 4, + name: 'Member Dinas' + }) +} \ No newline at end of file diff --git a/backend/src/config/config.js b/backend/src/config/config.js new file mode 100644 index 0000000000000000000000000000000000000000..6970701d800720b6ef086d7f798865b34a87b7e2 --- /dev/null +++ b/backend/src/config/config.js @@ -0,0 +1,5 @@ +module.exports = { + 'secret': 'much-secret-such-key-wow', + ROLEs: ['Master Admin Diskominfo', 'Admin Diskominfo', 'Admin Dinas', 'Member Dinas'], + jwtExpireTime: 300 +}; \ No newline at end of file diff --git a/backend/src/config/db.config.js b/backend/src/config/db.config.js new file mode 100644 index 0000000000000000000000000000000000000000..407da55c31c9ed6c8f7088aa8cae25a84f8fbbab --- /dev/null +++ b/backend/src/config/db.config.js @@ -0,0 +1,25 @@ +const env = require('./env'); + +const Sequelize = require('sequelize'); +const sequelize = new Sequelize(env.database, env.username, env.password, { + host: env.host, + dialect: env.dialect, + pool: { + max: env.pool.max, + min: env.pool.min, + acquire: env.pool.acquire, + idle: env.pool.idle + } +}); + +const db = {}; + +db.Sequelize = Sequelize; +db.sequelize = sequelize; + +db.user = require('../model/user.model.js')(sequelize, Sequelize); +db.role = require('../model/role.model.js')(sequelize, Sequelize); + +db.user.belongsTo(db.role, {foreignKey: 'roleId'}); + +module.exports = db; diff --git a/backend/src/config/env.js b/backend/src/config/env.js new file mode 100644 index 0000000000000000000000000000000000000000..1c40c141809535a788e48dbb0498a73321d1532f --- /dev/null +++ b/backend/src/config/env.js @@ -0,0 +1,15 @@ +const env = { + database: process.env.DB_NAME, + username: process.env.DB_USERNAME, + password: process.env.DB_PASSWORD, + host: process.env.DB_HOST, + dialect: process.env.DB_DIALECT, + pool: { + max: parseInt(process.env.DB_POOL_MAX), + min: parseInt(process.env.DB_POOL_MIN), + acquire: parseInt(process.env.DB_POOL_ACQUIRE), + idle: parseInt(process.env.DB_POOL_IDLE) + } + }; + + module.exports = env; \ No newline at end of file diff --git a/backend/src/controller/authController.js b/backend/src/controller/authController.js new file mode 100644 index 0000000000000000000000000000000000000000..1229722495ae423586b59a3196193d17d2089d93 --- /dev/null +++ b/backend/src/controller/authController.js @@ -0,0 +1,64 @@ +const db = require('../config/db.config.js'); +const config = require('../config/config.js'); +var jwt = require('jsonwebtoken'); +var bcrypt = require('bcryptjs'); +const User = db.user; +const Role = db.role; + +exports.signup = (req, res) => { + console.log("Processing func -> signup"); + User.create({ + name: req.body.name, + email: req.body.email, + username: req.body.username, + password: bcrypt.hashSync(req.body.password) + }).then(user => { + Role.findOne({ + where: { + name: req.body.role + } + }).then(role => { + user.setRole(role).then(() => { + res.send("User registered successfully!"); + }) + }).catch(err => { + res.status(500).send('Error -> ' + err); + }); + }).catch(err => { + res.status(500).send('Fail! Error -> ' + err); + }); +} + +exports.signin = (req, res) => { + console.log('Sign in'); + + User.findOne({ + where: { + username: req.body.username + } + }).then(user => { + if(!user) { + return res.status(404).send('User not found!'); + } + + var isPasswordValid = bcrypt.compareSync(req.body.password, user.password); + if(!isPasswordValid) { + return res.status(401).send({ + auth: false, + accessToken: null, + reason: "Invalid password!" + }); + } + + var token = jwt.sign({id: user.id}, config.secret, { + expiresIn: config.jwtExpireTime + }); + + res.status(200).send({ + auth: true, + accessToken: token + }); + }).catch(err => { + res.status(500).send('Error -> ' + err); + }); +} diff --git a/backend/src/controller/hello.js b/backend/src/controller/hello.js index 4b749edfbad336c7d4f5961c7c068c7a52804268..4fd79ffdc1e9c7bf66bdf50f4230687dc8992d8b 100644 --- a/backend/src/controller/hello.js +++ b/backend/src/controller/hello.js @@ -1,5 +1,5 @@ 'use strict' -var pool = require('../db'); +var pool = require('../config/db.config.js'); exports.index = (req, res) => { pool.connect((err, client, done) => { if (err) throw err diff --git a/backend/src/controller/testController.js b/backend/src/controller/testController.js new file mode 100644 index 0000000000000000000000000000000000000000..b4364164da46e4ee4fe2b6724c3d2623ea72acee --- /dev/null +++ b/backend/src/controller/testController.js @@ -0,0 +1,50 @@ +const db = require('../config/db.config.js'); +const config = require('../config/config.js'); +const User = db.user; +const Role = db.role; + +exports.memberContent = (req, res) => { + User.findOne({ + where: { + id: req.userId + }, + attributes: ['id', 'name', 'username', 'email'], + include: [{ + model: Role, + attributes: ['id', 'name'] + }] + }).then(user => { + res.status(200).json({ + "description": "User Content Page", + "user": user + }) + }).catch(err => { + res.status(500).json({ + "description": "Can not access User Page", + "error": er + }); + }) +} + +exports.adminContent = (req, res) => { + User.findOne({ + where: { + id: req.userId + }, + attributes: ['name', 'username', 'email'], + include: [{ + model: Role, + attributes: ['id', 'name'], + }] + }).then(user => { + res.status(200).json({ + "description": "Admin Content Page", + "user": user + }) + }).catch(err => { + res.status(500).json({ + "description": "Can not access Admin Page", + "error": err + }); + }) +} \ No newline at end of file diff --git a/backend/src/db.js b/backend/src/db.js deleted file mode 100644 index bf820290ea01008d3eb230589f6be0457d5b5a35..0000000000000000000000000000000000000000 --- a/backend/src/db.js +++ /dev/null @@ -1,17 +0,0 @@ -const {Pool, Client} = require('pg') -var pool = new Pool({ - user: process.env.DB_USERNAME, - host: process.env.DB_HOST, - database: process.env.DB_NAME, - password: process.env.DB_PASSWORD, - port: process.env.DB_PORT -}); - -pool.connect(function(err){ - if (err) throw err; - else{ - console.log("Database connected!"); - } -}); - -module.exports = pool \ No newline at end of file diff --git a/backend/src/model/role.model.js b/backend/src/model/role.model.js new file mode 100644 index 0000000000000000000000000000000000000000..0b24eed15494413ad20ba0eb41c4999c08ea2afa --- /dev/null +++ b/backend/src/model/role.model.js @@ -0,0 +1,13 @@ +module.exports = (sequelize, Sequelize) => { + const Role = sequelize.define('roles', { + id: { + type: Sequelize.INTEGER, + primaryKey: true + }, + name: { + type: Sequelize.STRING + } + }); + + return Role; +} \ No newline at end of file diff --git a/backend/src/model/user.model.js b/backend/src/model/user.model.js new file mode 100644 index 0000000000000000000000000000000000000000..b92245a322ef2b8574e41b52ec6d8b194b676cbb --- /dev/null +++ b/backend/src/model/user.model.js @@ -0,0 +1,18 @@ +module.exports = (sequelize, Sequelize) => { + const User = sequelize.define('users', { + name: { + type: Sequelize.STRING + }, + email: { + type: Sequelize.STRING + }, + password: { + type: Sequelize.STRING + }, + username: { + type: Sequelize.STRING + } + }); + + return User +} \ No newline at end of file diff --git a/backend/src/router/router.js b/backend/src/router/router.js new file mode 100644 index 0000000000000000000000000000000000000000..44632f6eb0e65db8de7878bbc91bd970e5237792 --- /dev/null +++ b/backend/src/router/router.js @@ -0,0 +1,15 @@ +const verifySignUp = require('./verifySignUp'); +const authJwt = require('./verifyJwtToken'); + +module.exports = function(app) { + const authController = require('../controller/authController.js'); + const testController = require('../controller/testController.js'); + app.post('/api/auth/signup', [verifySignUp.checkDuplicateUserNameOrEmail, verifySignUp.checkRolesExisted], authController.signup); + app.post('/api/auth/login', authController.signin); + + app.get('/api/test/admin', [authJwt.verifyToken, authJwt.isAdmin], testController.adminContent); + app.get('/api/test/member', [authJwt.verifyToken], testController.memberContent); + // Sample Hello + var hello = require('../controller/hello') + app.route('/hello').get(hello.index) +} \ No newline at end of file diff --git a/backend/src/router/verifyJwtToken.js b/backend/src/router/verifyJwtToken.js new file mode 100644 index 0000000000000000000000000000000000000000..9ddda869a2c3225da5421065783c05681e599898 --- /dev/null +++ b/backend/src/router/verifyJwtToken.js @@ -0,0 +1,48 @@ +const jwt = require('jsonwebtoken'); +const config = require('../config/config.js'); +const db = require('../config/db.config.js'); +const User = db.user; +const Role = db.role; + +verifyToken = (req, res, next) => { + let token = req.headers['x-access-token']; + + if (!token) { + res.status(403).send({ + message: 'No token provided!', + auth: false + }); + return; + } + + jwt.verify(token, config.secret, (err, decoded) => { + if (err) { + return res.status(500).send({ + message: 'Fail to auth. Error -> ' + err, + auth: false + }); + } + req.userId = decoded.id; + next(); + }); +} + +isAdmin = (req, res, next) => { + User.findByPk(req.userId) + .then(user => { + user.getRole().then(role => { + if (role === 'Master Admin Diskominfo' || role === 'Admin Diskominfo' || role === 'Admin Dinas') { + next(); + return; + } + res.status(403).send('Require Admin Role!'); + return; + }) + }) +} + +const verifyJwtToken = {}; +verifyJwtToken.verifyToken = verifyToken; +verifyJwtToken.isAdmin = isAdmin; + +module.exports = verifyJwtToken; \ No newline at end of file diff --git a/backend/src/router/verifySignUp.js b/backend/src/router/verifySignUp.js new file mode 100644 index 0000000000000000000000000000000000000000..1a4502713dd19a10ece81f4c6fdc53d308938f1e --- /dev/null +++ b/backend/src/router/verifySignUp.js @@ -0,0 +1,44 @@ +const db = require('../config/db.config.js'); +const config = require('../config/config.js'); +const ROLEs = config.ROLEs; +const User = db.user; + +checkDuplicateUserNameOrEmail = (req, res, next) => { + User.findOne({ + where: { + username: req.body.username + } + }).then(user => { + if (user) { + res.status(400).send("Fail -> Username is already taken!"); + return; + } + User.findOne({ + where: { + email: req.body.email + } + }).then(user => { + if (user) { + res.status(400).send("Fail -> Email is already in use!"); + return; + } + + next(); + }); + }); +} + +checkRolesExisted = (req, res, next) => { + if(!ROLEs.includes(req.body.role)) { + res.status(400).send("Fail -> Role does NOT exist = " + req.body.role); + return; + } + + next(); +} + +const verifySignUp = {}; +verifySignUp.checkDuplicateUserNameOrEmail = checkDuplicateUserNameOrEmail; +verifySignUp.checkRolesExisted = checkRolesExisted; + +module.exports = verifySignUp; \ No newline at end of file diff --git a/backend/src/routes.js b/backend/src/routes.js deleted file mode 100644 index 32e32701e845e514dd3471e2846256d9d4077da5..0000000000000000000000000000000000000000 --- a/backend/src/routes.js +++ /dev/null @@ -1,23 +0,0 @@ -module.exports = function(app) { - /* app.get('/hello', (req, res) => { - pool.connect((err, client, done) => { - if (err) throw err - client.query('SELECT NOW()', (err, res) => { - done() - if (err) { - console.log(err.stack) - } else { - console.log(res.rows[0]) - } - }) - }); - res.send( - [{ - title: "Hello Cat!", - description: "Hi there! How are you?" - }] - ) - }) */ - var hello = require('./controller/hello') - app.route('/hello').get(hello.index) -} \ No newline at end of file