From aeb38982ca6a520be3fb1a9e1d924d33b076a503 Mon Sep 17 00:00:00 2001 From: kaveh Date: Sun, 22 Dec 2024 16:52:30 +0330 Subject: [PATCH] Init commit --- app.js | 1 + components/belonging/belongingController.js | 48 ++ components/belonging/belongingModel.js | 40 ++ components/belonging/belongingRoutes.js | 20 + components/belonging/belongingService.js | 40 ++ components/permission/permissionController.js | 52 ++ components/permission/permissionModel.js | 33 + components/permission/permissionRoutes.js | 40 ++ components/permission/permissionSeeder.js | 18 + components/permission/permissionService.js | 39 + components/permission/permissionValidator.js | 0 components/role/roleController.js | 52 ++ components/role/roleModel.js | 39 + components/role/roleRoutes.js | 20 + components/role/roleSeeder.js | 36 + components/role/roleService.js | 40 ++ components/role/roleValidator.js | 0 components/user/userController.js | 78 ++ components/user/userModel.js | 30 + components/user/userRoutes.js | 24 + components/user/userService.js | 64 ++ docker-compose.yml | 59 -- middlewares/loginCheck.js | 53 ++ middlewares/permissionMiddleware.js | 76 ++ package-lock.json | 668 +++++++++++++++++- package.json | 8 +- setup/databaseConnection.js | 7 +- setup/routerEndpoints.js | 15 +- 28 files changed, 1532 insertions(+), 68 deletions(-) create mode 100644 components/belonging/belongingController.js create mode 100644 components/belonging/belongingModel.js create mode 100644 components/belonging/belongingRoutes.js create mode 100644 components/belonging/belongingService.js create mode 100644 components/permission/permissionController.js create mode 100644 components/permission/permissionModel.js create mode 100644 components/permission/permissionRoutes.js create mode 100644 components/permission/permissionSeeder.js create mode 100644 components/permission/permissionService.js create mode 100644 components/permission/permissionValidator.js create mode 100644 components/role/roleController.js create mode 100644 components/role/roleModel.js create mode 100644 components/role/roleRoutes.js create mode 100644 components/role/roleSeeder.js create mode 100644 components/role/roleService.js create mode 100644 components/role/roleValidator.js create mode 100644 components/user/userController.js create mode 100644 components/user/userModel.js create mode 100644 components/user/userRoutes.js create mode 100644 components/user/userService.js delete mode 100644 docker-compose.yml create mode 100644 middlewares/loginCheck.js create mode 100644 middlewares/permissionMiddleware.js diff --git a/app.js b/app.js index e72515c..da8f99b 100644 --- a/app.js +++ b/app.js @@ -1,3 +1,4 @@ +console.log('Running Something') require('dotenv').config({ path: './config/.env' }) const express = require('express') const databaseConnection = require('./setup/databaseConnection.js') diff --git a/components/belonging/belongingController.js b/components/belonging/belongingController.js new file mode 100644 index 0000000..aabe7f0 --- /dev/null +++ b/components/belonging/belongingController.js @@ -0,0 +1,48 @@ +const catchAsync = require('../../globalErrorHandler/catchAsync') +const belongingService = require('./belongingService') + +exports.getAllBelongings = catchAsync(async (req, res, next) => { + const belongings = await belongingService.getAllBelongings() + + res.status(200).json({ + status: 'success', + results: belongings.length, + data: belongings, + }) +}) + +exports.createBelonging = catchAsync(async (req, res, next) => { + const belonging = await belongingService.createBelonging(req.body) + + res.status(201).json({ + status: 'success', + data: belonging, + }) +}) + +exports.getBelonging = catchAsync(async (req, res, next) => { + const belonging = await belongingService.getBelonging(req.params.belongingId) + + res.status(200).json({ + status: 'success', + data: belonging, + }) +}) + +exports.updateBelonging = catchAsync(async (req, res, next) => { + const belonging = await belongingService.updateBelonging(req.params.belongingId, req.body) + + res.status(200).json({ + status: 'success', + data: belonging, + }) +}) + +exports.deleteBelonging = catchAsync(async (req, res, next) => { + await belongingService.deleteBelonging(req.params.belongingId) + + res.status(204).json({ + status: 'success', + data: null, + }) +}) diff --git a/components/belonging/belongingModel.js b/components/belonging/belongingModel.js new file mode 100644 index 0000000..5ac887e --- /dev/null +++ b/components/belonging/belongingModel.js @@ -0,0 +1,40 @@ +const mongoose = require('mongoose') +const ObjectID = mongoose.Schema.Types.ObjectId + +const belongingSchema = new mongoose.Schema( + { + belongingCode: { + type: String, + required: true, + unique: true, + }, + belongingCategory: { + type: ObjectID, + ref: 'Category' + }, + projectCode: { + type: String, + required: true, + default: false, + }, + relatedProjects : [String], + location: { + type: { + type: String, + enum: ['Point'], // GeoJSON type + required: true, + }, + coordinates: { + type: [Number], // Array of numbers: [longitude, latitude] + required: true, + }, + }, + documents: [String] + }, + { timestamps: true } +) + +belongingSchema.index({ location: '2dsphere' }); // Enable geospatial queries + +const Belonging = mongoose.model('Belonging', belongingSchema) +module.exports = Belonging diff --git a/components/belonging/belongingRoutes.js b/components/belonging/belongingRoutes.js new file mode 100644 index 0000000..0e8fc7e --- /dev/null +++ b/components/belonging/belongingRoutes.js @@ -0,0 +1,20 @@ +const express = require('express') +const belongingController = require('./belongingController') +const perm = require('../../middlewares/permissionMiddleware') +const loginCheck = require('../../middlewares/loginCheck') + +const router = new express.Router() + +router.use(loginCheck.loginProtect) + +router.get('/admin/get-all', perm.requires('getallbelongings'), belongingController.getAllBelongings) + +router.post('/admin/create', perm.requires('createabelonging'), belongingController.createBelonging) + +router.get('/admin/get-one/:belongingId', perm.requires('getabelonging'), belongingController.getBelonging) + +router.put('/admin/update/:belongingId', perm.requires('updateabelonging'), belongingController.updateBelonging) + +router.delete('/admin/delete/:belongingId', perm.requires('deleteabelonging'), belongingController.deleteBelonging) + +module.exports = router diff --git a/components/belonging/belongingService.js b/components/belonging/belongingService.js new file mode 100644 index 0000000..a2643bb --- /dev/null +++ b/components/belonging/belongingService.js @@ -0,0 +1,40 @@ +const Belonging = require('./belongingModel') +const AppError = require('../../globalErrorHandler/AppError') + +module.exports.getAllBelongings = async () => { + return Belonging.find({}, null, null) +} + +module.exports.createBelonging = async (data) => { + return Belonging.create(data, null) +} + +module.exports.getBelonging = async (belongingId) => { + const belonging = await Belonging.findById(belongingId, null, null) + + if (!belonging) { + throw new AppError('NoBelongingFound', 404, {}) + } + + return belonging +} + +module.exports.updateBelonging = async (belongingId, data) => { + const belonging = await Belonging.findOneAndUpdate({ _id: belongingId }, data, { new: true }) + + if (!belonging) { + throw new AppError('NoBelongingFound', 404, {}) + } + + return belonging +} + +module.exports.deleteBelonging = async (belongingId) => { + const belonging = await Belonging.findByIdAndUpdate(belongingId, { isActive: false }, { new: true }) + + if (!belonging) { + throw new AppError('NoBelongingFound', 404, {}) + } + + return null +} diff --git a/components/permission/permissionController.js b/components/permission/permissionController.js new file mode 100644 index 0000000..a8ef0e6 --- /dev/null +++ b/components/permission/permissionController.js @@ -0,0 +1,52 @@ +const catchAsync = require('../../globalErrorHandler/catchAsync') +const AppError = require('../../globalErrorHandler/AppError') +const Permission = require('./permissionModel') +const permissionService = require('./permissionService') + +exports.getAllPermissions = catchAsync(async (req, res, next) => { + const permissions = await permissionService.getAllPermissions() + + res.status(200).json({ + status: 'success', + results: permissions.length, + data: permissions, + }) +}) + +exports.createPermission = catchAsync(async (req, res, next) => { + const permission = await permissionService.createPermission( + req.body.englishName, + req.body.persianName + ) + + res.status(201).json({ + status: 'success', + data: permission, + }) +}) + +exports.getPermission = catchAsync(async (req, res, next) => { + const permission = await permissionService.getPermission(req.params.id) + + res.status(200).json({ + status: 'success', + data: permission, + }) +}) + +exports.updatePermission = catchAsync(async (req, res, next) => { + const updatePermission = await permissionService.updatePermission(data) + res.status(200).json({ + status: 'success', + data: permission, + }) +}) + +exports.deletePermission = catchAsync(async (req, res, next) => { + await permissionService.deletePermission(req.params.id) + + res.status(204).json({ + status: 'success', + data: null, + }) +}) diff --git a/components/permission/permissionModel.js b/components/permission/permissionModel.js new file mode 100644 index 0000000..4ec037e --- /dev/null +++ b/components/permission/permissionModel.js @@ -0,0 +1,33 @@ +const mongoose = require('mongoose') + +const permissionSchema = new mongoose.Schema({ + englishName: { + type: String, + required: [true, 'A permission must have a English name'], + }, + nativeName: { + type: String, + required: [true, 'A permission must have a Persian name'], + }, + key: { + type: String, + required: [true, 'Missing the key'], + unique: true, + }, + isActive: { + type: Boolean, + default: true, + select: false, + }, + category: { + type: String, + }, +}) + +permissionSchema.pre(/^find/, function (next) { + this.find({ active: { $ne: false } }) + next() +}) + +const Permission = mongoose.model('Permission', permissionSchema) +module.exports = Permission diff --git a/components/permission/permissionRoutes.js b/components/permission/permissionRoutes.js new file mode 100644 index 0000000..41bcff0 --- /dev/null +++ b/components/permission/permissionRoutes.js @@ -0,0 +1,40 @@ +const express = require('express') +const permissionController = require('./permissionController') +const perm = require('../../middlewares/permissionMiddleware') +const loginCheck = require('../../middlewares/loginCheck') + +const router = new express.Router() + +router.use(loginCheck.loginProtect) + +router.get( + '/', + perm.requires('getallpermissions'), + permissionController.getAllPermissions +) + +router.post( + '/', + perm.requires('createpermission'), + permissionController.createPermission +) + +router.get( + '/:id', + perm.requires('getpermission'), + permissionController.getPermission +) + +router.put( + '/:id', + perm.requires('updatepermission'), + permissionController.updatePermission +) + +router.delete( + '/:id', + perm.requires('deletepermission'), + permissionController.deletePermission +) + +module.exports = router diff --git a/components/permission/permissionSeeder.js b/components/permission/permissionSeeder.js new file mode 100644 index 0000000..eb00d54 --- /dev/null +++ b/components/permission/permissionSeeder.js @@ -0,0 +1,18 @@ +const Permission = require('./permissionModel') +const chalk = require('chalk') + +const runSeeder = async () => { + const permissions = [] + + await Permission.deleteMany({}) + console.log(chalk.red('Deleted all permission records.')) + + await Permission.insertMany(permissions, null) + console.log( + chalk.green.bold( + `PERMISSION: Created ${permissions.length} permission(s)` + ) + ) +} + +module.exports = { runSeeder } diff --git a/components/permission/permissionService.js b/components/permission/permissionService.js new file mode 100644 index 0000000..c928d90 --- /dev/null +++ b/components/permission/permissionService.js @@ -0,0 +1,39 @@ +const Permission = require('./permissionModel') +const AppError = require('../../globalErrorHandler/AppError') + +module.exports.getAllPermissions = async () => { + return Permission.find({}) +} + +module.exports.createPermission = async (englishName, persianName) => { + return await Permission.create({ + englishName, + persianName, + }) +} + +module.exports.getPermission = async (permissionId) => { + const permission = await Permission.findById(permissionId) + + if (!permission) { + throw AppError('NoPermissionFound', 404, {}) + } + + return permission +} + +module.exports.updatePermission = async (data) => { + const permission = await Permission.findOneAndUpdate(data) + + if (!permission) { + throw AppError('NoPermissionFound', 404, {}) + } + + return permission +} + +module.exports.deletePermission = async (permissionId) => { + await Permission.findOneAndDelete({ _id: permissionId }) + + return null +} diff --git a/components/permission/permissionValidator.js b/components/permission/permissionValidator.js new file mode 100644 index 0000000..e69de29 diff --git a/components/role/roleController.js b/components/role/roleController.js new file mode 100644 index 0000000..3aed3e7 --- /dev/null +++ b/components/role/roleController.js @@ -0,0 +1,52 @@ +const catchAsync = require('../../globalErrorHandler/catchAsync') +const AppError = require('../../globalErrorHandler/AppError') +const Role = require('./roleModel') +const roleService = require('./roleService') + +exports.getAllRoles = catchAsync(async (req, res, next) => { + const roles = await roleService.getAllRoles() + + res.status(200).json({ + status: 'success', + results: roles.length, + data: roles, + }) +}) + +exports.createRole = catchAsync(async (req, res, next) => { + const role = await roleService.createRole( + req.body.englishName, + req.body.persianName + ) + + res.status(201).json({ + status: 'success', + data: role, + }) +}) + +exports.getRole = catchAsync(async (req, res, next) => { + const role = await roleService.getRole(req.body.id) + + res.status(200).json({ + status: 'success', + data: role, + }) +}) + +exports.updateRole = catchAsync(async (req, res, next) => { + const updateRole = await roleService.updateRole(data) + res.status(200).json({ + status: 'success', + data: role, + }) +}) + +exports.deleteRole = catchAsync(async (req, res, next) => { + await roleService.deleteRole(req.body.id) + + res.status(204).json({ + status: 'success', + data: null, + }) +}) diff --git a/components/role/roleModel.js b/components/role/roleModel.js new file mode 100644 index 0000000..2daf125 --- /dev/null +++ b/components/role/roleModel.js @@ -0,0 +1,39 @@ +const mongoose = require('mongoose') +const ObjectID = mongoose.Schema.Types.ObjectId + +const roleSchema = new mongoose.Schema( + { + englishName: { + type: String, + unique: true, + required: true, + }, + nativeName: { + type: String, + required: [ + true, + 'A role must have a equivalent in Persian language', + ], + }, + permissions: [ + { + type: ObjectID, + ref: 'Permission', + }, + ], + isActive: { + type: Boolean, + default: true, + select: false, + }, + }, + { + toJSON: { virtuals: true }, + toObject: { virtuals: true }, + timestamps: true, + } +) + +const Role = mongoose.model('Role', roleSchema) + +module.exports = Role diff --git a/components/role/roleRoutes.js b/components/role/roleRoutes.js new file mode 100644 index 0000000..b824ad5 --- /dev/null +++ b/components/role/roleRoutes.js @@ -0,0 +1,20 @@ +const express = require('express') +const roleController = require('./roleController') +const perm = require('../../middlewares/permissionMiddleware') +const loginCheck = require('../../middlewares/loginCheck') + +const router = new express.Router() + +router.use(loginCheck.loginProtect) + +router.get('/admin/get-all', perm.requires('getallroles'), roleController.getAllRoles) + +router.post('/admin/create', perm.requires('createarole'), roleController.createRole) + +router.get('/admin/get-one/:roleId', perm.requires('getarole'), roleController.getRole) + +router.put('/admin/update/:roleId', perm.requires('updatearole'), roleController.updateRole) + +router.delete('/admin/delete/:roleId', perm.requires('deletearole'), roleController.deleteRole) + +module.exports = router diff --git a/components/role/roleSeeder.js b/components/role/roleSeeder.js new file mode 100644 index 0000000..8648875 --- /dev/null +++ b/components/role/roleSeeder.js @@ -0,0 +1,36 @@ +const Role = require('./roleModel') +const chalk = require('chalk') + +const runSeeder = async () => { + const roles = [ + { + _id: '66a0144569a37efa10d13628', + englishName: 'Admin', + nativeName: 'ادمین', + permissions: ['66a014057b80c4788e41aab7'], + isActive: true, + }, + { + _id: '66a2da5b9b989a8909948848', + englishName: 'SuperAdmin', + nativeName: 'ادمین اصلی', + permissions: [], + isActive: true, + }, + { + _id: '66a0144569a37efa10d13629', + englishName: 'User', + nativeName: 'کاربر', + permissions: [], + isActive: true, + }, + ] + + await Role.deleteMany({}) + console.log(chalk.red('Deleted all role records.')) + + await Role.insertMany(roles, null) + console.log(chalk.green.bold(`ROLE: Created ${roles.length} role(s)`)) +} + +module.exports = { runSeeder } diff --git a/components/role/roleService.js b/components/role/roleService.js new file mode 100644 index 0000000..917db0b --- /dev/null +++ b/components/role/roleService.js @@ -0,0 +1,40 @@ +const Role = require('./roleModel') +const AppError = require('../../globalErrorHandler/AppError') + +module.exports.getAllRoles = async () => { + return Role.find({}, null, null) +} + +module.exports.createRole = async (data) => { + return Role.create(data, null) +} + +module.exports.getRole = async (roleId) => { + const role = await Role.findById(roleId) + + if (!role) { + throw new AppError('NoRoleFound', 404, {}) + } + + return role +} + +module.exports.updateRole = async (roleId, data) => { + const role = await Role.findOneAndUpdate({ _id: roleId},data, null) + + if (!role) { + throw new AppError('NoRoleFound', 404, {}) + } + + return role +} + +module.exports.deleteRole = async (roleId) => { + const role = await Role.findByIdAndUpdate(roleId, { isActive: false }, null) + + if (!role) { + throw new AppError('NoRoleFound', 404, {}) + } + + return null +} diff --git a/components/role/roleValidator.js b/components/role/roleValidator.js new file mode 100644 index 0000000..e69de29 diff --git a/components/user/userController.js b/components/user/userController.js new file mode 100644 index 0000000..0af2808 --- /dev/null +++ b/components/user/userController.js @@ -0,0 +1,78 @@ +// userController.js +const catchAsync = require('../../globalErrorHandler/catchAsync') +const userService = require('./userService') + +exports.loginUser = catchAsync(async (req, res, next) => { + const user = await userService.loginUser(req.body.rawPassword) + const maxAge = 60 * 60 * 24 * 90 + + res.cookie('raw-password', user.rawPassword, { + httpOnly: true, + maxAge: maxAge * 1000, + path: '/', + }) + + res.status(200).json({ + status: 'success', + data: user, + }) +}) + +exports.logoutUser = catchAsync(async (req, res, next) => { + res.cookie('raw-password', '', { + httpOnly: true, + maxAge: 0, + path: '/', + }) + + res.status(200).json({ + status: 'success', + message: 'کاربر خارج شد', + }) +}) + +exports.getAllUsers = catchAsync(async (req, res, next) => { + const users = await userService.getAllUsers() + + res.status(200).json({ + status: 'success', + results: users.length, + data: users, + }) +}) + +exports.getUser = catchAsync(async (req, res, next) => { + const user = await userService.getUser(req.params.userId) + + res.status(200).json({ + status: 'success', + data: user, + }) +}) + +exports.createUser = catchAsync(async (req, res, next) => { + const user = await userService.createUser(req.body) + + res.status(201).json({ + status: 'success', + data: user, + }) +}) + +exports.updateUser = catchAsync(async (req, res, next) => { + const user = await userService.updateUser(req.params.userId, req.body) + + res.status(200).json({ + status: 'success', + data: user, + }) +}) + +exports.deleteUser = catchAsync(async (req, res, next) => { + await userService.deleteUser(req.params.userId) + + res.status(204).json({ + status: 'success', + data: null, + }) +}) diff --git a/components/user/userModel.js b/components/user/userModel.js new file mode 100644 index 0000000..2cb84f1 --- /dev/null +++ b/components/user/userModel.js @@ -0,0 +1,30 @@ +const mongoose = require('mongoose') +const ObjectID = mongoose.Schema.Types.ObjectId + +const userSchema = new mongoose.Schema( + { + name: String, + password: { + type: String, + required: true, + trim: true, + }, + isActive: { + type: Boolean, + default: true, + }, + role: { + type: ObjectID, + ref: 'Role' + }, + isAdmin: { + type: Boolean, + default: false, + }, + }, + { toJSON: { virtuals: true }, toObject: { virtuals: true }, timestamps: true } +) + +const User = mongoose.model('User', userSchema) + +module.exports = User diff --git a/components/user/userRoutes.js b/components/user/userRoutes.js new file mode 100644 index 0000000..0013c05 --- /dev/null +++ b/components/user/userRoutes.js @@ -0,0 +1,24 @@ +// userRoutes.js +const express = require('express') +const userController = require('./userController') +const loginCheck = require('../../middlewares/loginCheck') + +const router = new express.Router() + +router.post('/login', userController.loginUser) +router.post('/logout', userController.logoutUser) + +router.use(loginCheck.loginProtect) +// router.use(loginCheck.adminProtect) + +router.get('/', userController.getAllUsers) + +router.get('/:userId', userController.getUser) + +router.post('/', userController.createUser) + +router.put('/:userId', userController.updateUser) + +router.delete('/:userId', userController.deleteUser) + +module.exports = router diff --git a/components/user/userService.js b/components/user/userService.js new file mode 100644 index 0000000..09c3ee9 --- /dev/null +++ b/components/user/userService.js @@ -0,0 +1,64 @@ +// userService.js +const User = require('./userModel') +const AppError = require('../../globalErrorHandler/AppError') +const loginUser = async (rawPassword) => { + const user = await User.findOne({ rawPassword }, null, null) + + if (!user) { + throw new AppError('WrongPassword', 404, {}) + } + + return user +} + +const getAllUsers = async () => { + const users = await User.find({}, null, null) + for (let user of users) { + user.activatedCodes = await codeService.getCodeCount(user._id) + } + + return users +} + +const getUser = async (userId) => { + const user = await User.findById({ _id: userId }, null, null) + + if (!user) { + throw AppError('NoUserFound', 404, {}) + } + + return user +} + +const createUser = async (data) => { + return User.create(data, null) +} + +const updateUser = async (userId, data) => { + const user = await User.findOneAndUpdate({ _id: userId }, data, { new: true }) + + if (!user) { + throw AppError('NoUserFound', 404, {}) + } + + return user +} + +const deleteUser = async (userId) => { + const user = await User.findOneAndDelete({ _id: userId }) + + if (!user) { + throw AppError('NoUserFound', 404, {}) + } + + return null +} + +module.exports = { + loginUser, + getUser, + getAllUsers, + deleteUser, + updateUser, + createUser, +} diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index f757eba..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,59 +0,0 @@ -version: '3.8' -services: - app: - build: - context: . - ports: - - "3000:3000" - depends_on: - - mongodb - - redis - - typesense - - minio - environment: - MONGO_URI: mongodb://mongodb:27017/marbm - REDIS_HOST: redis - TYPESENSE_API_KEY: typesense-key - MINIO_ENDPOINT: http://minio:9000 - MINIO_ACCESS_KEY: minio - MINIO_SECRET_KEY: minio123 - - mongodb: - image: mongo:6.0 - container_name: mongodb - ports: - - "27017:27017" - volumes: - - mongodb_data:/data/db - - redis: - image: redis:7 - container_name: redis - ports: - - "6379:6379" - - typesense: - image: typesense/typesense:0.24.0 - container_name: typesense - ports: - - "8108:8108" - environment: - TYPESENSE_API_KEY: typesense-key - - minio: - image: minio/minio:latest - container_name: minio - ports: - - "9000:9000" - - "9001:9001" - command: server /data --console-address ":9001" - environment: - MINIO_ROOT_USER: minio - MINIO_ROOT_PASSWORD: minio123 - volumes: - - minio_data:/data - -volumes: - mongodb_data: - postgres_data: - minio_data: diff --git a/middlewares/loginCheck.js b/middlewares/loginCheck.js new file mode 100644 index 0000000..1a0e439 --- /dev/null +++ b/middlewares/loginCheck.js @@ -0,0 +1,53 @@ +const { promisify } = require('util') +const jwt = require('jsonwebtoken') +const User = require('../components/user/userModel') +const AppError = require('../globalErrorHandler/AppError') + +exports.loginProtect = async (req, res, next) => { + // 1) Getting token and check if it's there + let token + + token = req.cookies.jwt || req.cookies['crm-jwt'] + + if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) { + token = req.headers.authorization.split(' ')[1] + } + + if (!token) { + return next(new AppError('NotLoggedIn', 401)) + } + + // 2) Verification token + let decodedToken + try { + decodedToken = await promisify(jwt.verify)(token, process.env.JWT_SECRET) + } catch (err) {} + + if (!decodedToken) { + return next(new AppError('TokenUserNotExist', 401)) + } + + // 3) check if user still exist + const loggedInUser = await User.findById(decodedToken.id).populate('role addresses') + + if (!loggedInUser) { + return next(new AppError('TokenUserNotExist', 401, {})) + } + + // 4) check if user changed password after the token was issued + // if (loggedInUser.changedPasswordAfter(decodedToken.iat)) { + // return next(new AppError('UserChangedPasswordRecently', 401)) + // } + + // GRANT ACCESS TO PROTECTED ROUTE + req.user = loggedInUser + next() +} + +exports.webServiceProtect = async (req, res, next) => { + if (req.query.token !== process.env.WEB_SERVICE_TOKEN) { + return next(new AppError('NoWebServiceAccess', 401)) + } + + next() +} diff --git a/middlewares/permissionMiddleware.js b/middlewares/permissionMiddleware.js new file mode 100644 index 0000000..ac20844 --- /dev/null +++ b/middlewares/permissionMiddleware.js @@ -0,0 +1,76 @@ +const Permission = require('../components/permission/permissionModel') +const Role = require('../components/role/roleModel') +const AppError = require('../globalErrorHandler/AppError') +const catchAsync = require('../globalErrorHandler/catchAsync') +const User = require('../components/user/userModel') +const ErrorLocalization = require('../globalErrorHandler/errorLocalization') +const el = new ErrorLocalization() + +let checker = (arr, target) => arr.includes(target) + +const requires = (...permissions) => { + return async (req, res, next) => { + const role = await Role.findById(req.user.role) + const perm = await Permission.findOne({ key: permissions[0] }) + const rolePerm = role?.permissions || [] + const userPerm = req.user.extraPermissions || [] + + // some features: permission denied when all roles are not same --> we want to access user with either roles + if ( + !checker(rolePerm, perm?._id) && + !checker(userPerm, perm?._id) && + role._id.toString() !== process.env.SUPER_ADMIN_ID + ) { + throw new AppError('NoPermissionAccess', 403, {}) + } + + next() + } +} + +const adminCheck = () => { + return async (req, res, next) => { + try { + const user = await User.findOne({ + phoneNumber: req.body.phoneNumber, + }).populate('role') + + if (!user) { + throw new AppError('UserDoesNotExist', 403, {}) + } + + const perm = await Permission.findOne( + { key: 'admindashboard' }, + null, + null + ) + let rolePerm = user.role?.permissions || [] + let userPerm = user.extraPermissions || [] + // some features: permission denied when all roles are not same --> we want to access user with either roles + if ( + !checker(rolePerm, perm?._id) && + !checker(userPerm, perm?._id) && + user.role?._id.toString() !== process.env.SUPER_ADMIN_ID + ) { + throw new AppError('NoPermissionAccess', 403, {}) + } + + next() + } catch (err) { + console.log(err) + err.message = el.getErrorText(err.name, err.parameters, 'persian') + res.status(500).json({ + status: 'error', + message: + err.message || + 'An error occurred while checking permissions.', + }) + } + } +} + +module.exports = { + checker, + requires, + adminCheck, +} diff --git a/package-lock.json b/package-lock.json index 3d3ede5..d450703 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,11 +10,38 @@ "license": "ISC", "dependencies": { "body-parser": "^1.20.3", + "chalk": "^5.3.0", "compression": "^1.7.5", "cookie-parser": "^1.4.7", "cors": "^2.8.5", "dotenv": "^16.4.7", - "express": "^4.21.2" + "express": "^4.21.2", + "jsonwebtoken": "^9.0.2", + "mongoose": "^8.9.0" + }, + "devDependencies": { + "nodemon": "^3.1.9" + } + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.9.tgz", + "integrity": "sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" + }, + "node_modules/@types/whatwg-url": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "dependencies": { + "@types/webidl-conversions": "*" } }, "node_modules/accepts": { @@ -37,11 +64,42 @@ "node": ">= 0.6" } }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "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==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/body-parser": { "version": "1.20.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", @@ -65,6 +123,41 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "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==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bson": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.1.tgz", + "integrity": "sha512-P92xmHDQjSKPLHqFxefqMxASNq/aWJMEZugpCjf+AF/pgcUpMMQCg7t7+ewko0/u8AapvF3luf/FoehddEK+sA==", + "engines": { + "node": ">=16.20.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": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -100,6 +193,41 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -128,6 +256,12 @@ "node": ">= 0.8.0" } }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -233,6 +367,14 @@ "node": ">= 0.4" } }, + "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", @@ -339,6 +481,18 @@ "node": ">= 0.6" } }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/finalhandler": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", @@ -372,6 +526,20 @@ "node": ">= 0.6" } }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -403,6 +571,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -414,6 +594,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -462,6 +651,12 @@ "node": ">=0.10.0" } }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -475,6 +670,136 @@ "node": ">= 0.10" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "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": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "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/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/kareem": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz", + "integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, "node_modules/math-intrinsics": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.0.0.tgz", @@ -491,6 +816,11 @@ "node": ">= 0.6" } }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" + }, "node_modules/merge-descriptors": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", @@ -545,6 +875,138 @@ "node": ">= 0.6" } }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mongodb": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.12.0.tgz", + "integrity": "sha512-RM7AHlvYfS7jv7+BXund/kR64DryVI+cHbVAy9P61fnb1RcWZqOW1/Wj2YhqMCx+MuYhqTRGv7AwHBzmsCKBfA==", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.9", + "bson": "^6.10.1", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", + "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==", + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^13.0.0" + } + }, + "node_modules/mongoose": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.9.0.tgz", + "integrity": "sha512-b58zY3PLNBcoz6ZXFckr0leJcVVBMAOBvD+7Bj2ZjghAwntXmNnqwlDixTKQU3UYoQIGTv+AQx/0ThsvaeVrCA==", + "dependencies": { + "bson": "^6.10.1", + "kareem": "2.6.3", + "mongodb": "~6.12.0", + "mpath": "0.9.0", + "mquery": "5.0.0", + "ms": "2.1.3", + "sift": "17.1.3" + }, + "engines": { + "node": ">=16.20.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mongoose" + } + }, + "node_modules/mongoose/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/mpath": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", + "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mquery": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", + "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", + "dependencies": { + "debug": "4.x" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/mquery/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/mquery/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/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -558,6 +1020,66 @@ "node": ">= 0.6" } }, + "node_modules/nodemon": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz", + "integrity": "sha512-hdr1oIb2p6ZSxu3PB2JWWYS7ZQ0qvaZsc3hK8DR8f02kRzc8rjYmxAIvdz+aYC+8F2IjNaB7HMcSDg8nQpJxyg==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/nodemon/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==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -609,6 +1131,18 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -621,6 +1155,20 @@ "node": ">= 0.10" } }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, "node_modules/qs": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", @@ -657,6 +1205,18 @@ "node": ">= 0.8" } }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -681,6 +1241,17 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/send": { "version": "0.19.0", "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", @@ -804,6 +1375,31 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/sift": { + "version": "17.1.3", + "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz", + "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==" + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -812,6 +1408,30 @@ "node": ">= 0.8" } }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -820,6 +1440,26 @@ "node": ">=0.6" } }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -832,6 +1472,12 @@ "node": ">= 0.6" } }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -855,6 +1501,26 @@ "engines": { "node": ">= 0.8" } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", + "dependencies": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=16" + } } } } diff --git a/package.json b/package.json index fd66a76..3769713 100644 --- a/package.json +++ b/package.json @@ -12,10 +12,16 @@ "description": "", "dependencies": { "body-parser": "^1.20.3", + "chalk": "^5.3.0", "compression": "^1.7.5", "cookie-parser": "^1.4.7", "cors": "^2.8.5", "dotenv": "^16.4.7", - "express": "^4.21.2" + "express": "^4.21.2", + "jsonwebtoken": "^9.0.2", + "mongoose": "^8.9.0" + }, + "devDependencies": { + "nodemon": "^3.1.9" } } diff --git a/setup/databaseConnection.js b/setup/databaseConnection.js index df28c66..bda7ab6 100644 --- a/setup/databaseConnection.js +++ b/setup/databaseConnection.js @@ -12,8 +12,13 @@ module.exports = (app) => { } mongoose .connect(connectionString, {}) - .then(function () { + .then(async function () { console.log('MongoDB Database Connected') + const MyModel = mongoose.model('MyCollection', new mongoose.Schema({name: String})); + + // Create a document to force MongoDB to actually create the DB and collection + await MyModel.create({name: 'test'}); + app.listen(port, function () { console.log('Server Started On Port ' + port) }) diff --git a/setup/routerEndpoints.js b/setup/routerEndpoints.js index 6a39b01..3f274f4 100644 --- a/setup/routerEndpoints.js +++ b/setup/routerEndpoints.js @@ -2,15 +2,18 @@ const express = require('express') const AppError = require('../globalErrorHandler/AppError') const catchAsync = require('../globalErrorHandler/catchAsync') const userRoutes = require('../components/user/userRoutes') -const codeRoutes = require('../components/code/codeRoutes') -const CRMRoutes = require('../components/pages/crmRoutes') -const LoginRoute = require('../components/pages/loginRoutes') +const roleRoutes = require('../components/role/roleRoutes') +const permissionRoutes = require('../components/permission/permissionRoutes') +const belongingRoutes = require('../components/belonging/belongingRoutes') +// const codeRoutes = require('../components/code/codeRoutes') +// const CRMRoutes = require('../components/pages/crmRoutes') +// const LoginRoute = require('../components/pages/loginRoutes') const routerEndpoints = new express.Router() -routerEndpoints.use('/', LoginRoute) routerEndpoints.use('/users', userRoutes) -routerEndpoints.use('/codes', codeRoutes) -routerEndpoints.use('/admin', CRMRoutes) +routerEndpoints.use('/permissions', permissionRoutes) +routerEndpoints.use('/belongings', belongingRoutes) +routerEndpoints.use('/roles', roleRoutes) module.exports = routerEndpoints