diff options
| author | Bobby <[email protected]> | 2022-05-01 01:02:38 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-05-01 01:02:38 -0400 |
| commit | b0b1938f0e2ae2d159f0a616f8043d0b7f24f2eb (patch) | |
| tree | 71ed919b888e83fb49d619d1ba338dcba43b245c /interface | |
| parent | fd8acf8d1b04368763a97d1452565aa71dcc118a (diff) | |
| parent | d527bddaeb3083d2a5ec787626e512eb45d3a967 (diff) | |
| download | Welfare-Schemes-DMQL-b0b1938f0e2ae2d159f0a616f8043d0b7f24f2eb.tar.xz Welfare-Schemes-DMQL-b0b1938f0e2ae2d159f0a616f8043d0b7f24f2eb.zip | |
Merge pull request #4 from luciferreeves/main
Main page changes
Diffstat (limited to 'interface')
| -rw-r--r-- | interface/config/db.config.js | 9 | ||||
| -rw-r--r-- | interface/controllers/citizens.controller.js | 27 | ||||
| -rw-r--r-- | interface/controllers/users.controller.js | 18 | ||||
| -rw-r--r-- | interface/functions/index.js | 5 | ||||
| -rw-r--r-- | interface/models/index.js | 2 | ||||
| -rw-r--r-- | interface/models/users.model.js | 20 | ||||
| -rw-r--r-- | interface/package-lock.json | 224 | ||||
| -rw-r--r-- | interface/package.json | 4 | ||||
| -rw-r--r-- | interface/public/login.js | 39 | ||||
| -rw-r--r-- | interface/public/logout.js | 5 | ||||
| -rw-r--r-- | interface/public/router.js | 7 | ||||
| -rw-r--r-- | interface/public/verify.js | 21 | ||||
| -rw-r--r-- | interface/routes/api/index.js | 80 | ||||
| -rw-r--r-- | interface/routes/index.js | 22 | ||||
| -rw-r--r-- | interface/views/citizens.ejs | 51 | ||||
| -rw-r--r-- | interface/views/index.ejs | 103 | ||||
| -rw-r--r-- | interface/views/partials/head.ejs | 7 | ||||
| -rw-r--r-- | interface/views/partials/navbar.ejs | 17 | ||||
| -rw-r--r-- | interface/views/partials/scripts.ejs | 9 |
19 files changed, 610 insertions, 60 deletions
diff --git a/interface/config/db.config.js b/interface/config/db.config.js index 9118d6c..ea90d0c 100644 --- a/interface/config/db.config.js +++ b/interface/config/db.config.js @@ -1,14 +1,15 @@ +require('dotenv').config(); module.exports = { // The name of the database - database: 'WelfareSchemes', + database: process.env.DATABASE, // The username used to connect to the database - username: 'postgres', + username: process.env.USERNAME, // The password used to connect to the database - password: 'lucifer', + password: process.env.PASSWORD, // The dialect of the database you are connecting to dialect: 'postgres', // The host of the database - host: 'localhost', + host: process.env.HOST, // The port of the database port: 5432, // Setup pool of connections to the database diff --git a/interface/controllers/citizens.controller.js b/interface/controllers/citizens.controller.js index 64522b1..b50ee74 100644 --- a/interface/controllers/citizens.controller.js +++ b/interface/controllers/citizens.controller.js @@ -1,11 +1,26 @@ const db = require("../models"); const citizens = db.citizens; -const op = db.Sequelize.Op; // Retrieve all citizens from the database. Limit the number of citizens returned to 10. exports.findXCitizens = () => { - const limit = 10; - return citizens.findAll({ - limit: limit - }); -} + const limit = 10; + return citizens.findAll({ + limit: limit, + }); +}; + +// Get total number of male and female citizens +exports.findGenderDistribution = () => { + // group by the 'gender' column + + /** + * This code is equivalent to the following SQL query: + * select count(gender), gender from citizens group by gender; + */ + + return citizens.findAll({ + group: ["gender"], + attributes: ["gender", [db.sequelize.fn("COUNT", "gender"), "genderCount"]], + raw: true + }); +}; diff --git a/interface/controllers/users.controller.js b/interface/controllers/users.controller.js new file mode 100644 index 0000000..fff4469 --- /dev/null +++ b/interface/controllers/users.controller.js @@ -0,0 +1,18 @@ +const { users } = require("../models"); +const db = require("../models"); +const citizens = db.citizens; +const op = db.Sequelize.Op; + +// Create a new user +exports.create = (username, password) => { + return users.create({ username, password }); +} + +// Get a user by their username +exports.findByUsername = (username) => { + return users.findOne({ + where: { + username: username + } + }); +} diff --git a/interface/functions/index.js b/interface/functions/index.js new file mode 100644 index 0000000..034dc80 --- /dev/null +++ b/interface/functions/index.js @@ -0,0 +1,5 @@ +const jwt = require('jsonwebtoken'); + +exports.verifyJWT = (jwtToken) => { + return jwt.verify(jwtToken, process.env.JWT_SECRET); +} diff --git a/interface/models/index.js b/interface/models/index.js index 852fb65..e799e1e 100644 --- a/interface/models/index.js +++ b/interface/models/index.js @@ -18,7 +18,9 @@ const sequelize = new Sequelize(databaseConfig.database, databaseConfig.username const db = {}; db.Sequelize = Sequelize; db.sequelize = sequelize; +db.users = require('./users.model')(Sequelize, sequelize); db.citizens = require('./citizens.model.js')(Sequelize, sequelize); db.village_master = require('./village_master.model.js')(Sequelize, sequelize); +db.bank_master = require('./bank_master.model.js')(Sequelize, sequelize); module.exports = db; diff --git a/interface/models/users.model.js b/interface/models/users.model.js new file mode 100644 index 0000000..df8b276 --- /dev/null +++ b/interface/models/users.model.js @@ -0,0 +1,20 @@ +module.exports = (Sequelize, sequelize) => { + const Users = sequelize.define("users", { + user_id: { + type: Sequelize.INTEGER, + allowNull: false, + primaryKey: true, + autoIncrement: true, + }, + username: { + type: Sequelize.STRING(155), + allowNull: false, + unique: true, + }, + password: { + type: Sequelize.STRING(155), + allowNull: false, + } + }); + return Users; +}
\ No newline at end of file diff --git a/interface/package-lock.json b/interface/package-lock.json index e4be03a..dc4079f 100644 --- a/interface/package-lock.json +++ b/interface/package-lock.json @@ -9,10 +9,14 @@ "version": "1.0.0", "license": "GPL-3.0-or-later", "dependencies": { + "async": "^3.2.3", + "bcryptjs": "^2.4.3", "body-parser": "^1.20.0", "cors": "^2.8.5", + "dotenv": "^16.0.0", "ejs": "^3.1.7", "express": "^4.17.3", + "jsonwebtoken": "^8.5.1", "pg": "^8.7.3", "pg-hstore": "^2.3.4", "sequelize": "^6.19.0" @@ -143,6 +147,11 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -283,6 +292,11 @@ "node": ">=8" } }, + "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/buffer-writer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", @@ -585,6 +599,14 @@ "node": ">=8" } }, + "node_modules/dotenv": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.0.tgz", + "integrity": "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==", + "engines": { + "node": ">=12" + } + }, "node_modules/dottie": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", @@ -596,6 +618,14 @@ "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", "dev": true }, + "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", @@ -1174,6 +1204,59 @@ "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", "dev": true }, + "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/keyv": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", @@ -1200,6 +1283,41 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "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/lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -2499,6 +2617,11 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" + }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -2603,6 +2726,11 @@ "fill-range": "^7.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=" + }, "buffer-writer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", @@ -2824,6 +2952,11 @@ "is-obj": "^2.0.0" } }, + "dotenv": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.0.tgz", + "integrity": "sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==" + }, "dottie": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", @@ -2835,6 +2968,14 @@ "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", "dev": true }, + "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", @@ -3275,6 +3416,54 @@ "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", "dev": true }, + "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" + } + }, "keyv": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", @@ -3298,6 +3487,41 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "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", diff --git a/interface/package.json b/interface/package.json index 87ca23a..9cca33f 100644 --- a/interface/package.json +++ b/interface/package.json @@ -12,10 +12,14 @@ "author": "Kumar Priyansh <[email protected]>", "license": "GPL-3.0-or-later", "dependencies": { + "async": "^3.2.3", + "bcryptjs": "^2.4.3", "body-parser": "^1.20.0", "cors": "^2.8.5", + "dotenv": "^16.0.0", "ejs": "^3.1.7", "express": "^4.17.3", + "jsonwebtoken": "^8.5.1", "pg": "^8.7.3", "pg-hstore": "^2.3.4", "sequelize": "^6.19.0" diff --git a/interface/public/login.js b/interface/public/login.js new file mode 100644 index 0000000..3396f81 --- /dev/null +++ b/interface/public/login.js @@ -0,0 +1,39 @@ +$(".ui.form").form({ + fields: { + username: "empty", + password: "empty", + }, +}); + +function login(event) { + event.preventDefault(); + const username = $("#username").val().trim(); + const password = $("#password").val().trim(); + + // make sure username is a-zA-Z0-9 + if (!username.match(/^[a-zA-Z0-9]+$/)) { + alert("Username must be alphanumeric"); + return; + } else { + // make request to /api/login + fetch("/api/login", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + username, + password, + }), + }).then((response) => { + if (response.status === 200) { + response.json().then((data) => { + localStorage.setItem("token", data.token); + window.location.href = "/"; + }); + } else { + alert("Invalid username or password"); + } + }); + } +} diff --git a/interface/public/logout.js b/interface/public/logout.js new file mode 100644 index 0000000..401f06d --- /dev/null +++ b/interface/public/logout.js @@ -0,0 +1,5 @@ +function logout(event) { + event.preventDefault(); + localStorage.removeItem("token"); + window.location.href = "/"; +} diff --git a/interface/public/router.js b/interface/public/router.js new file mode 100644 index 0000000..23f8115 --- /dev/null +++ b/interface/public/router.js @@ -0,0 +1,7 @@ +function route(page) { + if (!localStorage.getItem("token")) { + $("#loginButton").click(); + } else { + window.location.href = page; + } +}
\ No newline at end of file diff --git a/interface/public/verify.js b/interface/public/verify.js new file mode 100644 index 0000000..94025f8 --- /dev/null +++ b/interface/public/verify.js @@ -0,0 +1,21 @@ +const token = localStorage.getItem("token"); +if (token) { + fetch("/api/verify", { + method: "POST", + headers: { + Authorization: `Bearer ${token}`, + } + }).then(response => { + if (response.status === 200) { + $('#loginButton').hide(); + $('#logoutButton').show(); + } else { + window.location.href = "/"; + $('#loginButton').show(); + $('#logoutButton').hide(); + } + }); +} else { + $('#loginButton').show(); + $('#logoutButton').hide(); +} diff --git a/interface/routes/api/index.js b/interface/routes/api/index.js new file mode 100644 index 0000000..f21720b --- /dev/null +++ b/interface/routes/api/index.js @@ -0,0 +1,80 @@ +// API for logging in +const express = require("express"); +const router = express.Router(); +const jwt = require("jsonwebtoken"); +const bcyrpt = require("bcryptjs"); +const userController = require("../../controllers/users.controller"); +const { verifyJWT } = require("../../functions"); +require("dotenv").config(); + +router.post("/verify", (req, res) => { + // get token from auth header + const token = req.headers.authorization; + // verify token + const decoded = verifyJWT(token.replace("Bearer ", "")); + if (decoded) { + res.status(200).json({ + message: "Token is valid", + decoded: decoded, + }); + } else { + res.status(401).json({ + message: "Token is invalid", + }); + } +}); + +router.post("/create", (req, res) => { + const { username, password } = req.body; + const saltRounds = 10; + const hash = bcyrpt.hashSync(password, saltRounds); + userController.create(username, hash).then((user) => { + const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET, { + expiresIn: "1h", + }); + res.json({ + token, + user, + }); + }); +}); + +router.post("/login", (req, res) => { + const { username, password } = req.body; + // get user by username + userController.findByUsername(username).then((user) => { + if (!user) { + return res.status(400).json({ + message: "User not found", + }); + } + // check if password is correct + bcyrpt.compare(password, user.password).then((isMatch) => { + if (!isMatch) { + return res.status(400).json({ + message: "Invalid credentials", + }); + } + // generate jwt + const payload = { + id: user.id, + username: user.username, + }; + jwt.sign( + payload, + process.env.JWT_SECRET, + { + expiresIn: 3600, + }, + (err, token) => { + if (err) throw err; + res.json({ + token, + }); + } + ); + }); + }); +}); + +module.exports = router; diff --git a/interface/routes/index.js b/interface/routes/index.js index 17c2021..12cd088 100644 --- a/interface/routes/index.js +++ b/interface/routes/index.js @@ -1,14 +1,28 @@ const express = require("express"); const router = express.Router(); const citizensController = require("../controllers/citizens.controller"); +const api = require('./api'); -// Setup Hello World route -router.get("/", (req, res) => { +// Setup api routes +router.use('/api', api); + + +router.get('/', (req, res) => { + Promise.all([citizensController.findGenderDistribution()]).then(results => { + const [genderDistribution] = results; + res.render('index', { + title: 'Home Page', + genderDistribution + }); + }); +}); + +router.get("/citizens", (req, res) => { // Get the citizens from the database citizensController.findXCitizens().then(citizens => { - res.render("index", { + res.render("citizens", { citizens: citizens, - title: "Hello World" + title: "Citizens Data" }); }); }); diff --git a/interface/views/citizens.ejs b/interface/views/citizens.ejs new file mode 100644 index 0000000..97c98fa --- /dev/null +++ b/interface/views/citizens.ejs @@ -0,0 +1,51 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <%- include('partials/head') %> + </head> + + <body> + <%- include('partials/navbar') %> + <table class="ui selectable table"> + <thead> + <tr> + <th>Citizen ID</th> + <th>First Name</th> + <th>Middle Name</th> + <th>Last Name</th> + <th>Address</th> + <th>Mobile Number</th> + <th>Date of Birth</th> + <th>Gender</th> + <th>Marital Status</th> + <th>Disabled</th> + <th>Disabled Percentage</th> + <th>Caste</th> + <th>Village ID</th> + </tr> + </thead> + <tbody> + <% for(var i=0; i < citizens.length; i++) { %> + <tr> + <td><%= citizens[i].citizen_id %></td> + <td><%= citizens[i].first_name %></td> + <td> + <%= citizens[i].middle_name ? citizens[i].middle_name : '-' %> + </td> + <td><%= citizens[i].last_name %></td> + <td><%= citizens[i].address %></td> + <td><%= citizens[i].mobile_num %></td> + <td><%= citizens[i].dob %></td> + <td><%= citizens[i].gender %></td> + <td><%= citizens[i].marital_status %></td> + <td><%= citizens[i].disabled %></td> + <td><%= citizens[i].disbaled_percentage %></td> + <td><%= citizens[i].caste %></td> + <td><%= citizens[i].village_id %></td> + </tr> + <% } %> + </tbody> + </table> + </body> + <%- include('partials/scripts') %> +</html> diff --git a/interface/views/index.ejs b/interface/views/index.ejs index 827334b..99dc89b 100644 --- a/interface/views/index.ejs +++ b/interface/views/index.ejs @@ -5,46 +5,69 @@ </head> <body> + <div class="ui modal login"> + <i class="close icon"></i> + <div class="header">Log in to continue</div> + <div + class="ui padded container segment" + style="border: none; box-shadow: none" + > + <form class="ui form" method="post" onsubmit="login(event)"> + <div class="field"> + <label>Username</label> + <input + placeholder="Username" + name="username" + type="text" + autocomplete="off" + id="username" + /> + </div> + <div class="field"> + <label>Password</label> + <input + type="password" + name="password" + placeholder="password" + id="password" + /> + </div> + <div class="ui primary submit button" id="submit">Submit</div> + <div class="ui error message"></div> + </form> + </div> + </div> <%- include('partials/navbar') %> - <table class="ui selectable table"> - <thead> - <tr> - <th>Citizen ID</th> - <th>First Name</th> - <th>Middle Name</th> - <th>Last Name</th> - <th>Address</th> - <th>Mobile Number</th> - <th>Date of Birth</th> - <th>Gender</th> - <th>Marital Status</th> - <th>Disabled</th> - <th>Disabled Percentage</th> - <th>Caste</th> - <th>Village ID</th> - </tr> - </thead> - <tbody> - <% for(var i=0; i < citizens.length; i++) { %> - <tr> - <td><%= citizens[i].citizen_id %></td> - <td><%= citizens[i].first_name %></td> - <td> - <%= citizens[i].middle_name ? citizens[i].middle_name : '-' %> - </td> - <td><%= citizens[i].last_name %></td> - <td><%= citizens[i].address %></td> - <td><%= citizens[i].mobile_num %></td> - <td><%= citizens[i].dob %></td> - <td><%= citizens[i].gender %></td> - <td><%= citizens[i].marital_status %></td> - <td><%= citizens[i].disabled %></td> - <td><%= citizens[i].disbaled_percentage %></td> - <td><%= citizens[i].caste %></td> - <td><%= citizens[i].village_id %></td> - </tr> - <% } %> - </tbody> - </table> + <div class="ui main container segment"> + <div class="ui cards"> + <div class="card"> + <div class="content"> + <div class="header">Citizens</div> + <div class="description"> + <pre> + Gender Statistics:<br> + =====================<br> + Male: <%= genderDistribution[0].genderCount %><br> + Female: <%= genderDistribution[1].genderCount %><br> + ---------------------<br> + Total: <%= genderDistribution[0].genderCount + genderDistribution[1].genderCount %> + </pre> + Provides the details of all the citizens in the database + </div> + </div> + <div class="extra content"> + <div class="ui basic green button" onclick="route('citizens')"> + View Data + </div> + </div> + </div> + </div> + </div> </body> + <%- include('partials/scripts') %> + <script> + $(".ui.dropdown").dropdown(); + $(".login.modal").modal("attach events", ".loginButton", "show"); + </script> + <script src="/login.js"></script> </html> diff --git a/interface/views/partials/head.ejs b/interface/views/partials/head.ejs index c43233a..1296994 100644 --- a/interface/views/partials/head.ejs +++ b/interface/views/partials/head.ejs @@ -3,5 +3,8 @@ <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Welfare Schemes | <%= title %></title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/semantic.min.css"> -<script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script> -<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/semantic.min.js"></script> +<style> + pre, code{ + white-space:normal; + } +</style> diff --git a/interface/views/partials/navbar.ejs b/interface/views/partials/navbar.ejs index 6a46ff3..34116ea 100644 --- a/interface/views/partials/navbar.ejs +++ b/interface/views/partials/navbar.ejs @@ -1,5 +1,5 @@ <div class="ui menu"> - <a class="item active"> Home </a> + <a class="item"> Home </a> <div class="ui pointing dropdown link item"> <span class="text">View Data</span> <i class="dropdown icon"></i> @@ -42,7 +42,16 @@ </div> </div> </div> + <div class="right menu"> + <div class="item"> + <div class="ui icon input"> + <input type="text" placeholder="Search..." /> + <i class="search link icon"></i> + </div> + </div> + <a class="ui item loginButton" id="loginButton"> Log in </a> + <a class="ui item loginButton" id="logoutButton" onclick="logout(event)"> + Log out</a + > + </div> </div> -<script> - $(".ui.dropdown").dropdown(); -</script> diff --git a/interface/views/partials/scripts.ejs b/interface/views/partials/scripts.ejs new file mode 100644 index 0000000..a90467a --- /dev/null +++ b/interface/views/partials/scripts.ejs @@ -0,0 +1,9 @@ +<script + src="https://code.jquery.com/jquery-3.1.1.min.js" + integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" + crossorigin="anonymous" +></script> +<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/semantic.min.js"></script> +<script src="/verify.js"></script> +<script src="/router.js"></script> +<script src="/logout.js"></script> |
