From 2f95836327eba761cb9c3182552040a1684a3558 Mon Sep 17 00:00:00 2001 From: Noam Date: Sun, 5 Dec 2021 22:12:51 +0200 Subject: [PATCH] converted to typescript --- app/config/{auth.config.js => auth.config.ts} | 2 +- app/config/{db.config.js => db.config.ts} | 2 +- ...{auth.controller.js => auth.controller.ts} | 20 +++++---- app/controllers/user.controller.js | 15 ------- app/controllers/user.controller.ts | 17 ++++++++ app/middleware/{authJwt.js => authJwt.ts} | 43 +++++++++++-------- app/middleware/index.js | 7 --- app/middleware/index.ts | 2 + .../{verifySignUp.js => verifySignUp.ts} | 14 +++--- app/models/{index.js => index.ts} | 29 +++++++------ app/models/role.model.js | 13 ------ app/models/role.model.ts | 22 ++++++++++ app/models/user.model.js | 15 ------- app/models/user.model.ts | 28 ++++++++++++ app/routes/{auth.routes.js => auth.routes.ts} | 9 ++-- app/routes/{user.routes.js => user.routes.ts} | 9 ++-- package.json | 14 ++++-- server.js => server.ts | 20 +++++---- tsconfig.json | 27 ++++++++++++ 19 files changed, 188 insertions(+), 120 deletions(-) rename app/config/{auth.config.js => auth.config.ts} (59%) rename app/config/{db.config.js => db.config.ts} (87%) rename app/controllers/{auth.controller.js => auth.controller.ts} (82%) delete mode 100644 app/controllers/user.controller.js create mode 100644 app/controllers/user.controller.ts rename app/middleware/{authJwt.js => authJwt.ts} (57%) delete mode 100644 app/middleware/index.js create mode 100644 app/middleware/index.ts rename app/middleware/{verifySignUp.js => verifySignUp.ts} (79%) rename app/models/{index.js => index.ts} (53%) delete mode 100644 app/models/role.model.js create mode 100644 app/models/role.model.ts delete mode 100644 app/models/user.model.js create mode 100644 app/models/user.model.ts rename app/routes/{auth.routes.js => auth.routes.ts} (61%) rename app/routes/{user.routes.js => user.routes.ts} (69%) rename server.js => server.ts (75%) create mode 100644 tsconfig.json diff --git a/app/config/auth.config.js b/app/config/auth.config.ts similarity index 59% rename from app/config/auth.config.js rename to app/config/auth.config.ts index 4819df3..e19541d 100644 --- a/app/config/auth.config.js +++ b/app/config/auth.config.ts @@ -1,3 +1,3 @@ -module.exports = { +export const config = { secret: "bezkoder-secret-key" }; diff --git a/app/config/db.config.js b/app/config/db.config.ts similarity index 87% rename from app/config/db.config.js rename to app/config/db.config.ts index d186745..adcedb5 100644 --- a/app/config/db.config.js +++ b/app/config/db.config.ts @@ -1,4 +1,4 @@ -module.exports = { +export const config = { HOST: "localhost", USER: "postgres", PASSWORD: "123", diff --git a/app/controllers/auth.controller.js b/app/controllers/auth.controller.ts similarity index 82% rename from app/controllers/auth.controller.js rename to app/controllers/auth.controller.ts index ca4682a..b2fbc81 100644 --- a/app/controllers/auth.controller.js +++ b/app/controllers/auth.controller.ts @@ -1,14 +1,16 @@ -const db = require("../models"); -const config = require("../config/auth.config"); +import { RequestHandler } from "express"; +import { db } from "../models"; +import { Op } from "sequelize"; +import { config } from "../config/auth.config"; const User = db.user; const Role = db.role; -const Op = db.Sequelize.Op; -var jwt = require("jsonwebtoken"); -var bcrypt = require("bcryptjs"); -exports.signup = (req, res) => { +import * as jwt from "jsonwebtoken"; +import * as bcrypt from "bcryptjs"; + +export const signup: RequestHandler = (req, res) => { // Save User to Database User.create({ username: req.body.username, @@ -24,12 +26,12 @@ exports.signup = (req, res) => { } } }).then(roles => { + user.setRoles(roles).then(() => { res.send({ message: "User registered successfully!" }); }); }); } else { - // user role = 1 user.setRoles([1]).then(() => { res.send({ message: "User registered successfully!" }); }); @@ -40,7 +42,7 @@ exports.signup = (req, res) => { }); }; -exports.signin = (req, res) => { +export const signin: RequestHandler = (req, res) => { User.findOne({ where: { username: req.body.username @@ -67,7 +69,7 @@ exports.signin = (req, res) => { expiresIn: 86400 // 24 hours }); - var authorities = []; + var authorities = [] as string[]; user.getRoles().then(roles => { for (let i = 0; i < roles.length; i++) { authorities.push("ROLE_" + roles[i].name.toUpperCase()); diff --git a/app/controllers/user.controller.js b/app/controllers/user.controller.js deleted file mode 100644 index e2fa15b..0000000 --- a/app/controllers/user.controller.js +++ /dev/null @@ -1,15 +0,0 @@ -exports.allAccess = (req, res) => { - res.status(200).send("Public Content."); -}; - -exports.userBoard = (req, res) => { - res.status(200).send("User Content."); -}; - -exports.adminBoard = (req, res) => { - res.status(200).send("Admin Content."); -}; - -exports.moderatorBoard = (req, res) => { - res.status(200).send("Moderator Content."); -}; diff --git a/app/controllers/user.controller.ts b/app/controllers/user.controller.ts new file mode 100644 index 0000000..35ecd68 --- /dev/null +++ b/app/controllers/user.controller.ts @@ -0,0 +1,17 @@ +import { RequestHandler } from "express"; + +export const allAccess: RequestHandler = (req, res) => { + res.status(200).send("Public Content."); +}; + +export const userBoard: RequestHandler = (req, res) => { + res.status(200).send("User Content."); +}; + +export const adminBoard: RequestHandler = (req, res) => { + res.status(200).send("Admin Content."); +}; + +export const moderatorBoard: RequestHandler = (req, res) => { + res.status(200).send("Moderator Content."); +}; diff --git a/app/middleware/authJwt.js b/app/middleware/authJwt.ts similarity index 57% rename from app/middleware/authJwt.js rename to app/middleware/authJwt.ts index 2cbe752..d1412d0 100644 --- a/app/middleware/authJwt.js +++ b/app/middleware/authJwt.ts @@ -1,10 +1,15 @@ -const jwt = require("jsonwebtoken"); -const config = require("../config/auth.config.js"); -const db = require("../models"); -const User = db.user; +import { RequestHandler } from 'express'; +import jwt from "jsonwebtoken"; +import { config } from "../config/auth.config"; +import { db } from "../models"; +import { User } from '../models/user.model'; -verifyToken = (req, res, next) => { - let token = req.headers["x-access-token"]; + + + + +const verifyToken: RequestHandler = (req, res, next) => { + let token = req.headers["x-access-token"] as string; if (!token) { return res.status(403).send({ @@ -12,20 +17,20 @@ verifyToken = (req, res, next) => { }); } - jwt.verify(token, config.secret, (err, decoded) => { + jwt.verify(token, config.secret, (err: any, decoded: any) => { if (err) { return res.status(401).send({ message: "Unauthorized!" }); } - req.userId = decoded.id; + (req as any).userId = decoded.id; next(); }); }; -isAdmin = (req, res, next) => { - User.findByPk(req.userId).then(user => { - user.getRoles().then(roles => { +const isAdmin: RequestHandler = (req, res, next) => { + User.findByPk((req as any).userId).then(user => { + user!.getRoles().then(roles => { for (let i = 0; i < roles.length; i++) { if (roles[i].name === "admin") { next(); @@ -41,9 +46,9 @@ isAdmin = (req, res, next) => { }); }; -isModerator = (req, res, next) => { - User.findByPk(req.userId).then(user => { - user.getRoles().then(roles => { +const isModerator: RequestHandler = (req, res, next) => { + User.findByPk((req as any).userId).then(user => { + user!.getRoles().then(roles => { for (let i = 0; i < roles.length; i++) { if (roles[i].name === "moderator") { next(); @@ -58,9 +63,9 @@ isModerator = (req, res, next) => { }); }; -isModeratorOrAdmin = (req, res, next) => { - User.findByPk(req.userId).then(user => { - user.getRoles().then(roles => { +const isModeratorOrAdmin: RequestHandler = (req, res, next) => { + User.findByPk((req as any).userId).then(user => { + user!.getRoles().then(roles => { for (let i = 0; i < roles.length; i++) { if (roles[i].name === "moderator") { next(); @@ -80,10 +85,10 @@ isModeratorOrAdmin = (req, res, next) => { }); }; -const authJwt = { +export const authJwt = { verifyToken: verifyToken, isAdmin: isAdmin, isModerator: isModerator, isModeratorOrAdmin: isModeratorOrAdmin }; -module.exports = authJwt; + diff --git a/app/middleware/index.js b/app/middleware/index.js deleted file mode 100644 index 78a3414..0000000 --- a/app/middleware/index.js +++ /dev/null @@ -1,7 +0,0 @@ -const authJwt = require("./authJwt"); -const verifySignUp = require("./verifySignUp"); - -module.exports = { - authJwt, - verifySignUp -}; diff --git a/app/middleware/index.ts b/app/middleware/index.ts new file mode 100644 index 0000000..3530b37 --- /dev/null +++ b/app/middleware/index.ts @@ -0,0 +1,2 @@ +export { authJwt } from "./authJwt"; +export { verifySignUp } from "./verifySignUp"; diff --git a/app/middleware/verifySignUp.js b/app/middleware/verifySignUp.ts similarity index 79% rename from app/middleware/verifySignUp.js rename to app/middleware/verifySignUp.ts index 2e2e030..44a6cbb 100644 --- a/app/middleware/verifySignUp.js +++ b/app/middleware/verifySignUp.ts @@ -1,8 +1,10 @@ -const db = require("../models"); +import { RequestHandler } from "express"; + +import { db } from "../models"; const ROLES = db.ROLES; const User = db.user; -checkDuplicateUsernameOrEmail = (req, res, next) => { +const checkDuplicateUsernameOrEmail: RequestHandler = (req, res, next) => { // Username User.findOne({ where: { @@ -34,7 +36,7 @@ checkDuplicateUsernameOrEmail = (req, res, next) => { }); }; -checkRolesExisted = (req, res, next) => { +const checkRolesExisted: RequestHandler = (req, res, next) => { if (req.body.roles) { for (let i = 0; i < req.body.roles.length; i++) { if (!ROLES.includes(req.body.roles[i])) { @@ -45,13 +47,13 @@ checkRolesExisted = (req, res, next) => { } } } - + next(); }; -const verifySignUp = { +export const verifySignUp = { checkDuplicateUsernameOrEmail: checkDuplicateUsernameOrEmail, checkRolesExisted: checkRolesExisted }; -module.exports = verifySignUp; + diff --git a/app/models/index.js b/app/models/index.ts similarity index 53% rename from app/models/index.js rename to app/models/index.ts index 99f94de..9ff6b9f 100644 --- a/app/models/index.js +++ b/app/models/index.ts @@ -1,14 +1,16 @@ -const config = require("../config/db.config.js"); +import { config } from "../config/db.config"; -const Sequelize = require("sequelize"); +import { Dialect, Sequelize } from "sequelize"; +import { initRole, Role } from "./role.model"; +import { initUsers, User } from "./user.model"; const sequelize = new Sequelize( config.DB, config.USER, config.PASSWORD, { host: config.HOST, - dialect: config.dialect, - operatorsAliases: false, + dialect: config.dialect as Dialect, + //operatorsAliases: false, pool: { max: config.pool.max, @@ -19,25 +21,24 @@ const sequelize = new Sequelize( } ); -const db = {}; - -db.Sequelize = Sequelize; -db.sequelize = sequelize; - -db.user = require("../models/user.model.js")(sequelize, Sequelize); -db.role = require("../models/role.model.js")(sequelize, Sequelize); +export const db = { + user: User, + role: Role, + sequelize, + ROLES: ["user", "admin", "moderator"] +}; +initUsers(sequelize); +initRole(sequelize); db.role.belongsToMany(db.user, { through: "user_roles", foreignKey: "roleId", otherKey: "userId" }); + db.user.belongsToMany(db.role, { through: "user_roles", foreignKey: "userId", otherKey: "roleId" }); -db.ROLES = ["user", "admin", "moderator"]; - -module.exports = db; diff --git a/app/models/role.model.js b/app/models/role.model.js deleted file mode 100644 index 345c247..0000000 --- a/app/models/role.model.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = (sequelize, Sequelize) => { - const Role = sequelize.define("roles", { - id: { - type: Sequelize.INTEGER, - primaryKey: true - }, - name: { - type: Sequelize.STRING - } - }); - - return Role; -}; diff --git a/app/models/role.model.ts b/app/models/role.model.ts new file mode 100644 index 0000000..a1d3f18 --- /dev/null +++ b/app/models/role.model.ts @@ -0,0 +1,22 @@ +import { DataTypes, Model, Sequelize } from 'sequelize'; +export class Role extends Model { + id!: number; + name!: string; +} +export function initRole(sequelize: Sequelize) { + + Role.init({ + id: { + type: DataTypes.INTEGER, + primaryKey: true + }, + name: { + type: DataTypes.STRING + } + }, + { + sequelize, + tableName: 'roles' + }); + return Role; +}; diff --git a/app/models/user.model.js b/app/models/user.model.js deleted file mode 100644 index 63b8c28..0000000 --- a/app/models/user.model.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = (sequelize, Sequelize) => { - const User = sequelize.define("users", { - username: { - type: Sequelize.STRING - }, - email: { - type: Sequelize.STRING - }, - password: { - type: Sequelize.STRING - } - }); - - return User; -}; diff --git a/app/models/user.model.ts b/app/models/user.model.ts new file mode 100644 index 0000000..50909b0 --- /dev/null +++ b/app/models/user.model.ts @@ -0,0 +1,28 @@ +import { DataTypes, Model, Sequelize } from "sequelize"; +import { Role } from "./role.model"; + +export class User extends Model { + id!: number; + username!: string; + email!: string; + password!: string; + setRoles!: (roles: (Role | number)[]) => Promise; + getRoles!: () => Promise +} +export function initUsers(sequelize: Sequelize) { + User.init({ + username: { + type: DataTypes.STRING + }, + email: { + type: DataTypes.STRING + }, + password: { + type: DataTypes.STRING + } + }, { + sequelize, + tableName: "users" + }); + +} \ No newline at end of file diff --git a/app/routes/auth.routes.js b/app/routes/auth.routes.ts similarity index 61% rename from app/routes/auth.routes.js rename to app/routes/auth.routes.ts index a4fcd91..af0c9c0 100644 --- a/app/routes/auth.routes.js +++ b/app/routes/auth.routes.ts @@ -1,8 +1,9 @@ -const { verifySignUp } = require("../middleware"); -const controller = require("../controllers/auth.controller"); +import { Express } from 'express'; +import { verifySignUp } from "../middleware"; +import * as controller from "../controllers/auth.controller"; -module.exports = function(app) { - app.use(function(req, res, next) { +export function authRoutes(app: Express) { + app.use(function (req, res, next) { res.header( "Access-Control-Allow-Headers", "x-access-token, Origin, Content-Type, Accept" diff --git a/app/routes/user.routes.js b/app/routes/user.routes.ts similarity index 69% rename from app/routes/user.routes.js rename to app/routes/user.routes.ts index 10f00c5..037af8c 100644 --- a/app/routes/user.routes.js +++ b/app/routes/user.routes.ts @@ -1,8 +1,9 @@ -const { authJwt } = require("../middleware"); -const controller = require("../controllers/user.controller"); +import { Express } from 'express'; +import { authJwt } from "../middleware"; +import * as controller from "../controllers/user.controller"; -module.exports = function(app) { - app.use(function(req, res, next) { +export function userRoutes(app: Express) { + app.use(function (req, res, next) { res.header( "Access-Control-Allow-Headers", "x-access-token, Origin, Content-Type, Accept" diff --git a/package.json b/package.json index 7b957cd..88770e2 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Node.js Demo for JWT Authentication with PostgreSQL", "main": "server.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "dev-node": "ts-node-dev server.ts" }, "keywords": [ "node js", @@ -16,13 +16,21 @@ "author": "bezkoder", "license": "ISC", "dependencies": { + "@types/bcryptjs": "^2.4.2", + "@types/cors": "^2.8.12", + "@types/jsonwebtoken": "^8.5.6", "bcryptjs": "^2.4.3", "body-parser": "^1.19.0", "cors": "^2.8.5", "express": "^4.17.1", "jsonwebtoken": "^8.5.1", - "pg": "^7.17.1", + "pg": "^8.7.1", "pg-hstore": "^2.3.3", - "sequelize": "^5.21.3" + "sequelize": "^6.12.0-beta.1", + "typescript": "^4.5.2" + }, + "devDependencies": { + "@types/express": "^4.17.13", + "ts-node-dev": "^1.1.8" } } diff --git a/server.js b/server.ts similarity index 75% rename from server.js rename to server.ts index c8e8642..8247d44 100644 --- a/server.js +++ b/server.ts @@ -1,6 +1,6 @@ -const express = require("express"); -const bodyParser = require("body-parser"); -const cors = require("cors"); +import express from "express"; +import bodyParser from "body-parser"; +import cors from "cors"; const app = express(); @@ -17,12 +17,14 @@ app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); // database -const db = require("./app/models"); +import { db } from "./app/models"; +import { authRoutes } from "./app/routes/auth.routes"; +import { userRoutes } from "./app/routes/user.routes"; const Role = db.role; // db.sequelize.sync(); // force: true will drop the table if it already exists -db.sequelize.sync({force: true}).then(() => { +db.sequelize.sync({ force: true }).then(() => { console.log('Drop and Resync Database with { force: true }'); initial(); }); @@ -33,8 +35,8 @@ app.get("/", (req, res) => { }); // routes -require('./app/routes/auth.routes')(app); -require('./app/routes/user.routes')(app); +authRoutes(app); +userRoutes(app); // set port, listen for requests const PORT = process.env.PORT || 8080; @@ -47,12 +49,12 @@ function initial() { id: 1, name: "user" }); - + Role.create({ id: 2, name: "moderator" }); - + Role.create({ id: 3, name: "admin" diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..e8bb9fb --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "outDir": "./build", + "module": "commonjs", + "rootDir": "../", + "noEmit": false, + "emitDecoratorMetadata": true, + "target": "es2021", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "experimentalDecorators": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true + } + + } \ No newline at end of file