diff --git a/src/core/constants/index.ts b/src/core/constants/index.ts index 7ed0cb5..b7474d5 100644 --- a/src/core/constants/index.ts +++ b/src/core/constants/index.ts @@ -1,4 +1,149 @@ export const JWT_SECRET = process.env.JWT_SECRET || "secret"; -export const TOKEN_NAME = 'userToken' +export const TOKEN_NAME = "userToken"; -export const requestType = ['software','hardware','his','rahkaran','taradod','general'] \ No newline at end of file +export const requestType = [ + "software", + "hardware", + "his", + "rahkaran", + "taradod", + "general", +]; + +export const permissions = [ + "filter.view", + /* ================================ + ✅ TICKETS + ================================= */ + "ticket.create", + "ticket.view", + "ticket.view_all", + "ticket.update", + "ticket.delete", + "ticket.assign", + "ticket.change_status", + "ticket.close", + "ticket.reopen", + "ticket.comment", + "ticket.internal_note", + "ticket.upload_file", + "ticket.merge", + "ticket.export", + + /* ================================ + ✅ USERS + ================================= */ + "user.view", + "user.view_all", + "user.create", + "user.update", + "user.delete", + "user.activate", + "user.deactivate", + "user.assign_role", + + /* ================================ + ✅ ROLES + ================================= */ + "role.view", + "role.create", + "role.update", + "role.delete", + + /* ================================ + ✅ PERMISSIONS + ================================= */ + "permission.view", + "permission.assign_to_role", + "permission.assign_to_user", + + /* ================================ + ✅ DEPARTMENTS + ================================= */ + "department.view", + "department.create", + "department.update", + "department.delete", + + /* ================================ + ✅ REPORTS - SYSTEM LEVEL + ================================= */ + "report.system.view", + "report.system.export", + + "report.department.view", + "report.department.export", + + "report.operator.view", + "report.operator.export", + + "report.sla.view", + "report.sla.export", + + "report.kpi.view", + "report.kpi.export", + + "report.trend.view", + "report.closure_rate.view", + "report.critical.view", + "report.avg_resolution.view", + "report.aging.view", + "report.agent_efficiency.view", + "report.department_load.view", + "report.prediction.view", + "report.export_excel", + + /* ================================ + ✅ DASHBOARD + ================================= */ + "dashboard.view", + "dashboard.view_advanced", + + /* ================================ + ✅ SLA MANAGEMENT + ================================= */ + "sla.view", + "sla.create", + "sla.update", + "sla.delete", + + /* ================================ + ✅ REQUEST TYPES + ================================= */ + "request_type.view", + "request_type.create", + "request_type.update", + "request_type.delete", + + /* ================================ + ✅ TAGS + ================================= */ + "tag.view", + "tag.create", + "tag.update", + "tag.delete", + + /* ================================ + ✅ SETTINGS + ================================= */ + "settings.view", + "settings.update", + + /* ================================ + ✅ LOGS + ================================= */ + "log.view", + "audit.view", + + /* ================================ + ✅ OPERATOR / PERFORMANCE + ================================= */ + "operator.view", + "operator.performance.view", + "operator.performance.export", + + "permission.view_all", + "permission.create", + "permission.update", + "permission.delete", +] as const; diff --git a/src/core/middleware/auth.middleware.ts b/src/core/middleware/auth.middleware.ts index 9c58c51..ab20b84 100644 --- a/src/core/middleware/auth.middleware.ts +++ b/src/core/middleware/auth.middleware.ts @@ -2,28 +2,66 @@ import { NextFunction } from "express"; import { ServerResponse } from "../types"; import { JWT_SECRET, TOKEN_NAME } from "../constants"; import createHttpError from "http-errors"; +import User from "../../models/User"; +import Permission from "../../models/Permission"; +import Role from "../../models/Role"; const jwt = require("jsonwebtoken"); -const authMiddleware = (req:any, res:ServerResponse, next:NextFunction) => { - // ۱. خواندن توکن از کوکی‌ها - const token = req.cookies[TOKEN_NAME]; // TOKEN_NAME همان متغیری است که در زمان ست کردن کوکی داشتید +const authMiddleware = async ( + req: any, + res: ServerResponse, + next: NextFunction, +) => { + const token = req.cookies[TOKEN_NAME]; if (!token) { - throw new createHttpError.Unauthorized("لطفا وارد حساب كاربري خود شويد") + return next( + new createHttpError.Unauthorized("لطفا وارد حساب كاربري خود شويد"), + ); } try { - // ۲. اعتبارسنجی توکن با استفاده از همان SECRET - const decoded = jwt.verify(token, JWT_SECRET); + const decoded = jwt.verify(token, JWT_SECRET) as { + id: number; + roleId: number; + }; - // ۳. قرار دادن اطلاعات کاربر در آبجکت درخواست برای استفاده در مسیرهای بعدی - req.user = decoded; + const user = await User.findByPk(decoded.id, { + attributes: ["id", "roleId"], + include: [ + { + model: Role, + as: "role", + attributes: ["id", "name"], + include: [ + { + model: Permission, + as: "permissions", + attributes: ["name"], + through: { attributes: [] }, + }, + ], + }, + ], + }); - next(); // ادامه به مسیر اصلی - } catch (error) { - throw new createHttpError.Forbidden("حساب كاربري شما نامعتبر است") + if (!user) { + return next(new createHttpError.Unauthorized("کاربر یافت نشد")); + } + + const permissions = user?.role?.permissions?.map((p: any) => p.name) || []; + + req.user = { + id: user.id, + roleId: user.roleId, + permissions, + }; + + next(); + } catch (err) { + return next(new createHttpError.Forbidden("حساب كاربري شما نامعتبر است")); } }; -export default authMiddleware +export default authMiddleware; diff --git a/src/core/middleware/check-permission.ts b/src/core/middleware/check-permission.ts index 7e3c5f7..9f1016c 100644 --- a/src/core/middleware/check-permission.ts +++ b/src/core/middleware/check-permission.ts @@ -1,46 +1,65 @@ -import Permission from "../../models/Permission"; -import RolePermission from "../../models/RolePermission"; -import UserPermission from "../../models/UserPermission"; +import { NextFunction } from "express"; +import { PermissionType } from "../types"; +import createHttpError from "http-errors"; +// export function checkPermission(permissionName: string) { +// return async (req: any, res: any, next: any) => { +// const user = req.user; -export function checkPermission(permissionName: string) { - return async (req: any, res: any, next: any) => { +// const permission = await Permission.findOne({ +// where: { name: permissionName }, +// }); + +// if (!permission) { +// return res.status(403).json({ message: "Permission not found" }); +// } + +// // ✅ 1- چک سطح کاربر +// const userPermission = await UserPermission.findOne({ +// where: { +// userId: user.id, +// permissionId: permission.id, +// }, +// }); + +// if (userPermission) { +// return next(); +// } + +// // ✅ 2- چک سطح رول +// const rolePermission = await RolePermission.findOne({ +// where: { +// roleId: user.roleId, +// permissionId: permission.id, +// }, +// }); + +// if (rolePermission) { +// return next(); +// } + +// return res.status(403).json({ +// message: "Access Denied", +// }); +// }; +// } + +export function requirePermission(permission: PermissionType[]) { + return (req: any, res: any, next: NextFunction) => { const user = req.user; - const permission = await Permission.findOne({ - where: { name: permissionName }, - }); - - if (!permission) { - return res.status(403).json({ message: "Permission not found" }); + if (!user) { + throw new createHttpError.Unauthorized("وارد حساب كاربري خود شويد"); } - // ✅ 1- چک سطح کاربر - const userPermission = await UserPermission.findOne({ - where: { - userId: user.id, - permissionId: permission.id, - }, - }); + const userPermissions: PermissionType[] = user.permissions || []; - if (userPermission) { - return next(); + const hasPermission = permission.some((p) => userPermissions.includes(p)); + + if (!hasPermission) { + throw new createHttpError.Forbidden("به اين قسمت دسترسي نداريد"); } - // ✅ 2- چک سطح رول - const rolePermission = await RolePermission.findOne({ - where: { - roleId: user.roleId, - permissionId: permission.id, - }, - }); - - if (rolePermission) { - return next(); - } - - return res.status(403).json({ - message: "Access Denied", - }); + next(); }; } diff --git a/src/core/types/index.ts b/src/core/types/index.ts index 6e7cc6b..4309ff1 100644 --- a/src/core/types/index.ts +++ b/src/core/types/index.ts @@ -1,4 +1,5 @@ import { Response } from "express"; +import { permissions } from "../constants"; export interface ServerResponseObject { status: number; @@ -69,30 +70,29 @@ export interface ticketRequestTypeDataType { updatedAt?: Date; } - - // reports export interface TicketStats { - total: number - open: number - inProgress: number - resolved: number - closed: number + total: number; + open: number; + inProgress: number; + resolved: number; + closed: number; } export interface DepartmentReport { - departmentId: string - departmentName: string - totalTickets: number - openTickets: number - resolvedTickets: number + departmentId: string; + departmentName: string; + totalTickets: number; + openTickets: number; + resolvedTickets: number; } export interface AgentReport { - userId: string - fullname: string - totalAssigned: number - resolved: number - open: number + userId: string; + fullname: string; + totalAssigned: number; + resolved: number; + open: number; } +export type PermissionType = (typeof permissions)[number]; diff --git a/src/models/Role.ts b/src/models/Role.ts index 606892d..51b5c4a 100644 --- a/src/models/Role.ts +++ b/src/models/Role.ts @@ -1,92 +1,97 @@ - import { - Model, - DataTypes, - Optional, - Sequelize, - BelongsToManySetAssociationsMixin, - BelongsToManyAddAssociationsMixin, - BelongsToManyRemoveAssociationsMixin, - BelongsToManyGetAssociationsMixin, - HasManyGetAssociationsMixin - } from "sequelize"; - import User from "./User"; - import Permission from "./Permission"; +import { + Model, + DataTypes, + Optional, + Sequelize, + BelongsToManySetAssociationsMixin, + BelongsToManyAddAssociationsMixin, + BelongsToManyRemoveAssociationsMixin, + BelongsToManyGetAssociationsMixin, + HasManyGetAssociationsMixin, +} from "sequelize"; +import User from "./User"; +import Permission from "./Permission"; +interface RoleAttributes { + id: string; + name: string; + description?: string; + createdAt?: Date; + updatedAt?: Date; +} - interface RoleAttributes { - id: string; - name: string; - description?: string; - createdAt?: Date; - updatedAt?: Date; - } +interface RoleCreationAttributes extends Optional< + RoleAttributes, + "id" | "description" +> {} - interface RoleCreationAttributes - extends Optional {} +class Role + extends Model + implements RoleAttributes +{ + public id!: string; + public name!: string; + public description?: string; + public permissions?: Permission[]; - class Role - extends Model - implements RoleAttributes - { - public id!: string; - public name!: string; - public description?: string; + public readonly createdAt!: Date; + public readonly updatedAt!: Date; - public readonly createdAt!: Date; - public readonly updatedAt!: Date; + // Users relation + public getUsers!: HasManyGetAssociationsMixin; - // Users relation - public getUsers!: HasManyGetAssociationsMixin; + // Permissions relation + public getPermissions!: BelongsToManyGetAssociationsMixin; + public setPermissions!: BelongsToManySetAssociationsMixin; + public addPermissions!: BelongsToManyAddAssociationsMixin; + public removePermissions!: BelongsToManyRemoveAssociationsMixin< + Permission, + string + >; - // Permissions relation - public getPermissions!: BelongsToManyGetAssociationsMixin; - public setPermissions!: BelongsToManySetAssociationsMixin; - public addPermissions!: BelongsToManyAddAssociationsMixin; - public removePermissions!: BelongsToManyRemoveAssociationsMixin; - - static initModel(sequelize: Sequelize): typeof Role { - Role.init( - { - id: { - type: DataTypes.UUID, - primaryKey: true, - defaultValue: DataTypes.UUIDV4, - }, - - name: { - type: DataTypes.STRING, - unique: true, - allowNull: false, - }, - - description: { - type: DataTypes.STRING, - }, + static initModel(sequelize: Sequelize): typeof Role { + Role.init( + { + id: { + type: DataTypes.UUID, + primaryKey: true, + defaultValue: DataTypes.UUIDV4, }, - { - sequelize, - modelName: "Role", - tableName: "roles", - timestamps: true, - } - ); - return Role; - } + name: { + type: DataTypes.STRING, + unique: true, + allowNull: false, + }, - static associate(models: any) { - Role.hasMany(models.User, { - foreignKey: "roleId", - as: "users", - }); + description: { + type: DataTypes.STRING, + }, + }, + { + sequelize, + modelName: "Role", + tableName: "roles", + timestamps: true, + }, + ); - Role.belongsToMany(models.Permission, { - through: models.RolePermission, - foreignKey: "roleId", - otherKey: "permissionId", - as: "permissions", - }); - } + return Role; } - export default Role; + static associate(models: any) { + Role.hasMany(models.User, { + foreignKey: "roleId", + as: "users", + }); + + Role.belongsToMany(models.Permission, { + through: models.RolePermission, + foreignKey: "roleId", + otherKey: "permissionId", + as: "permissions", + }); + } +} + +export default Role; diff --git a/src/models/User.ts b/src/models/User.ts index 3296783..4eba44a 100644 --- a/src/models/User.ts +++ b/src/models/User.ts @@ -1,9 +1,5 @@ -import { - Model, - DataTypes, - Optional, - Sequelize -} from "sequelize"; +import { Model, DataTypes, Optional, Sequelize } from "sequelize"; +import Role from "./Role"; interface UserAttributes { id: string; @@ -15,8 +11,7 @@ interface UserAttributes { updatedAt?: Date; } -interface UserCreationAttributes - extends Optional {} +interface UserCreationAttributes extends Optional {} class User extends Model @@ -27,6 +22,7 @@ class User public nationalCode!: string; public mobile!: string; public roleId!: string; + public role?: Role; public readonly createdAt!: Date; public readonly updatedAt!: Date; @@ -69,26 +65,22 @@ class User modelName: "User", tableName: "users", timestamps: true, - } + }, ); return User; } static associate(models: any) { - User.belongsTo(models.Role, { foreignKey: "roleId", as: "role", }); - - User.hasMany(models.Ticket, { foreignKey: "assignedTo", as: "assignedTickets", }); - } } diff --git a/src/modules/auth/controller/auth.controller.ts b/src/modules/auth/controller/auth.controller.ts index 8f339c7..f21ef9d 100644 --- a/src/modules/auth/controller/auth.controller.ts +++ b/src/modules/auth/controller/auth.controller.ts @@ -7,7 +7,6 @@ import { TOKEN_NAME } from "../../../core/constants"; import { GlobalMessages } from "../../../core/messages"; import { Controller } from "../../../core/controller/main.controller"; - class AuthControllerClass extends Controller { #service; @@ -16,6 +15,19 @@ class AuthControllerClass extends Controller { this.#service = AuthService; } + async Me(req: any, res: ServerResponse, next: NextFunction) { + try { + const data = await this.#service.Me(req); + + return res.status(200).json({ + data, + status: 200, + message: "Ok", + }); + } catch (error) { + next(error); + } + } async login(req: any, res: ServerResponse, next: NextFunction) { try { await AuthValidationSchema.validateAsync(req.body || {}); diff --git a/src/modules/auth/routes/auth.routes.ts b/src/modules/auth/routes/auth.routes.ts index c202fa9..d0459ff 100644 --- a/src/modules/auth/routes/auth.routes.ts +++ b/src/modules/auth/routes/auth.routes.ts @@ -1,10 +1,11 @@ -import express from 'express' -import AuthController from '../controller/auth.controller'; +import express from "express"; +import AuthController from "../controller/auth.controller"; +import authMiddleware from "../../../core/middleware/auth.middleware"; -const authRouter = express.Router(); +const authRouter = express.Router(); +authRouter.get("/me", authMiddleware, AuthController.Me); +authRouter.post("/login", AuthController.login); +authRouter.post("/logout", AuthController.logout); -authRouter.post('/login',AuthController.login) -authRouter.post('/logout',AuthController.logout) - -export default authRouter; \ No newline at end of file +export default authRouter; diff --git a/src/modules/auth/services/auth.service.ts b/src/modules/auth/services/auth.service.ts index a5b937d..27ca28c 100644 --- a/src/modules/auth/services/auth.service.ts +++ b/src/modules/auth/services/auth.service.ts @@ -4,6 +4,8 @@ import jwt from "jsonwebtoken"; import dotenv from "dotenv"; import User from "../../../models/User"; import { JWT_SECRET } from "../../../core/constants"; +import Role from "../../../models/Role"; +import Permission from "../../../models/Permission"; dotenv.config(); class AuthServiceClass { @@ -39,6 +41,46 @@ class AuthServiceClass { ); } } + async Me(req:any) { + const userId = req.user?.id; + + if (!userId) { + throw new createHttpError.Unauthorized("کاربر احراز هویت نشده است"); + } + + const user = await User.findByPk(userId, { + attributes: ["id", "fullname", "mobile", "roleId"], + include: [ + { + model: Role, + as: "role", + attributes: ["id", "name"], + include: [ + { + model: Permission, + as: "permissions", + attributes: ["name"], + through: { attributes: [] }, + }, + ], + }, + ], + }); + + if (!user) { + throw new createHttpError.NotFound("کاربر پیدا نشد"); + } + + const permissions = user.role?.permissions?.map((p: any) => p.name) || []; + + return { + id: user.id, + fullname: user.fullname, + mobile: user.mobile, + role: user.role?.name, + permissions, + }; + } } const AuthService = new AuthServiceClass(); diff --git a/src/modules/department/routes/department.routes.ts b/src/modules/department/routes/department.routes.ts index a5aaad4..defed0e 100644 --- a/src/modules/department/routes/department.routes.ts +++ b/src/modules/department/routes/department.routes.ts @@ -1,13 +1,48 @@ import router from "express"; import DepartmentController from "../controller/department.controller"; +import authMiddleware from "../../../core/middleware/auth.middleware"; +import { requirePermission } from "../../../core/middleware/check-permission"; const departmentRouter = router.Router(); +departmentRouter.get( + "/all", + authMiddleware, + requirePermission(["department.view"]), + DepartmentController.getAll, +); -departmentRouter.get("/all", DepartmentController.getAll); -departmentRouter.get("/list", DepartmentController.getAllList); -departmentRouter.get("/get/:id", DepartmentController.getById); -departmentRouter.post("/create", DepartmentController.create); -departmentRouter.delete("/delete/:id", DepartmentController.delete); -departmentRouter.put("/update/:id", DepartmentController.update); +departmentRouter.get( + "/list", + authMiddleware, + DepartmentController.getAllList, +); + +departmentRouter.get( + "/get/:id", + authMiddleware, + requirePermission(["department.view"]), + DepartmentController.getById, +); + +departmentRouter.post( + "/create", + authMiddleware, + requirePermission(["department.create"]), + DepartmentController.create, +); + +departmentRouter.delete( + "/delete/:id", + authMiddleware, + requirePermission(["department.delete"]), + DepartmentController.delete, +); + +departmentRouter.put( + "/update/:id", + authMiddleware, + requirePermission(["department.update"]), + DepartmentController.update, +); export default departmentRouter; diff --git a/src/modules/permission/permission.routes.ts b/src/modules/permission/permission.routes.ts index 22f777c..572e8ef 100644 --- a/src/modules/permission/permission.routes.ts +++ b/src/modules/permission/permission.routes.ts @@ -1,19 +1,21 @@ import { Router } from "express"; import PermissionController from "./permission.controller"; +import { requirePermission } from "../../core/middleware/check-permission"; +import authMiddleware from "../../core/middleware/auth.middleware"; const PermissionRouter = Router(); -PermissionRouter.post("/create", PermissionController.create); +PermissionRouter.post("/create",authMiddleware,requirePermission(["permission.create"]),PermissionController.create); -PermissionRouter.get("/all", PermissionController.getAll); -PermissionRouter.get("/list", PermissionController.getList); +PermissionRouter.get("/all", authMiddleware,requirePermission(["permission.view_all"]),PermissionController.getAll); +PermissionRouter.get("/list", authMiddleware,PermissionController.getList); -PermissionRouter.get("/get/:id", PermissionController.getById); +PermissionRouter.get("/get/:id", authMiddleware,requirePermission(["permission.view"]),PermissionController.getById); -PermissionRouter.put("/update/:id", PermissionController.update); +PermissionRouter.put("/update/:id", authMiddleware,requirePermission(["permission.update"]),PermissionController.update); -PermissionRouter.delete("/remove/:id", PermissionController.delete); +PermissionRouter.delete("/remove/:id", authMiddleware,requirePermission(["permission.delete"]),PermissionController.delete); export default PermissionRouter; diff --git a/src/modules/report/routes/report.router.ts b/src/modules/report/routes/report.router.ts index 19a8f59..7ace249 100644 --- a/src/modules/report/routes/report.router.ts +++ b/src/modules/report/routes/report.router.ts @@ -1,60 +1,62 @@ import { Router } from "express"; import ReportController from "../controller/report.controller"; +import authMiddleware from "../../../core/middleware/auth.middleware"; +import { requirePermission } from "../../../core/middleware/check-permission"; const reportRouter = Router(); reportRouter.get( - "/stats", + "/stats",authMiddleware,requirePermission(["report.system.view"]), // requireAuth, // requirePermission("VIEW_REPORTS"), ReportController.ticketStats, ); reportRouter.get( - "/departments", + "/departments",authMiddleware,requirePermission(["report.department.view"]), // requireAuth, // requirePermission("VIEW_REPORTS"), ReportController.departmentReport, ); reportRouter.get( - "/agents", + "/agents",authMiddleware,requirePermission(["report.operator.view"]), // requireAuth, // requirePermission("VIEW_REPORTS"), ReportController.agentPerformance, ); reportRouter.get( - "/avg-resolution", + "/avg-resolution",authMiddleware,requirePermission(["report.avg_resolution.view"]), // requireAuth, // requirePermission("VIEW_REPORTS"), ReportController.avgResolution, ); reportRouter.get( - "/critical", + "/critical",authMiddleware,requirePermission(["report.critical.view"]), // requireAuth, // requirePermission("VIEW_REPORTS"), ReportController.criticalTickets, ); -reportRouter.get("/trend", ReportController.ticketsPerDay) +reportRouter.get("/trend",authMiddleware,requirePermission(["report.trend.view"]), ReportController.ticketsPerDay) -reportRouter.get("/closure-rate", ReportController.closureRate) +reportRouter.get("/closure-rate",authMiddleware,requirePermission(["report.closure_rate.view"]), ReportController.closureRate) -reportRouter.get("/sla", ReportController.slaBreach) +reportRouter.get("/sla",authMiddleware,requirePermission(["report.sla.view"]), ReportController.slaBreach) -reportRouter.get("/aging", ReportController.aging) +reportRouter.get("/aging",authMiddleware,requirePermission(["report.aging.view"]), ReportController.aging) -reportRouter.get("/agent-efficiency", ReportController.agentEfficiency) +reportRouter.get("/agent-efficiency",authMiddleware,requirePermission(["report.agent_efficiency.view"]), ReportController.agentEfficiency) -reportRouter.get("/department-load", ReportController.departmentLoad) +reportRouter.get("/department-load",authMiddleware,requirePermission(["report.department_load.view"]), ReportController.departmentLoad) -reportRouter.get("/kpi", ReportController.kpi) +reportRouter.get("/kpi",authMiddleware,requirePermission(["report.kpi.view"]), ReportController.kpi) -reportRouter.get("/prediction", ReportController.prediction) +reportRouter.get("/prediction",authMiddleware,requirePermission(["report.prediction.view"]), ReportController.prediction) -reportRouter.get("/export-excel", ReportController.exportExcel) +reportRouter.get("/export-excel",authMiddleware,requirePermission(["report.export_excel"]), ReportController.exportExcel) diff --git a/src/modules/roles/role.routes.ts b/src/modules/roles/role.routes.ts index 48ab79e..cb86325 100644 --- a/src/modules/roles/role.routes.ts +++ b/src/modules/roles/role.routes.ts @@ -1,16 +1,18 @@ import { Router } from "express"; import RoleController from "./role.controller"; +import authMiddleware from "../../core/middleware/auth.middleware"; +import { requirePermission } from "../../core/middleware/check-permission"; const RoleRouter = Router(); -RoleRouter.post("/create", RoleController.create); -RoleRouter.get("/list", RoleController.findList); -RoleRouter.get("/all", RoleController.findAll); -RoleRouter.get("/:id", RoleController.findById); -RoleRouter.put("/update/:id", RoleController.update); -RoleRouter.delete("/remove/:id", RoleController.delete); +RoleRouter.post("/create", authMiddleware,requirePermission(["role.create"]),RoleController.create); +RoleRouter.get("/list", authMiddleware,RoleController.findList); +RoleRouter.get("/all", authMiddleware,requirePermission(["role.view"]),RoleController.findAll); +RoleRouter.get("/:id", authMiddleware,requirePermission(["role.view"]),RoleController.findById); +RoleRouter.put("/update/:id", authMiddleware,requirePermission(["role.update"]),RoleController.update); +RoleRouter.delete("/remove/:id", authMiddleware,requirePermission(["role.delete"]),RoleController.delete); -RoleRouter.post("/:id/permissions/assign", RoleController.assignPermissions); -RoleRouter.post("/:id/permissions/add", RoleController.addPermissions); -RoleRouter.post("/:id/permissions/remove", RoleController.removePermissions); +RoleRouter.post("/:id/permissions/assign", authMiddleware,requirePermission(["permission.assign_to_role"]),RoleController.assignPermissions); +RoleRouter.post("/:id/permissions/add", authMiddleware,RoleController.addPermissions); +RoleRouter.post("/:id/permissions/remove", authMiddleware,RoleController.removePermissions); export default RoleRouter; diff --git a/src/modules/ticket/routes/ticket.routes.ts b/src/modules/ticket/routes/ticket.routes.ts index 660ff04..6eda6a6 100644 --- a/src/modules/ticket/routes/ticket.routes.ts +++ b/src/modules/ticket/routes/ticket.routes.ts @@ -1,14 +1,16 @@ import express from "express"; import TicketController from "../controller/ticket.controller"; +import authMiddleware from "../../../core/middleware/auth.middleware"; +import { requirePermission } from "../../../core/middleware/check-permission"; const ticketRouter = express.Router(); -ticketRouter.post("/create", TicketController.create); -ticketRouter.get("/all", TicketController.getAll); -ticketRouter.get("/all/export", TicketController.getAllExport); -ticketRouter.get("/all/report", TicketController.getAllReport); -ticketRouter.get("/get/:id", TicketController.getById); -ticketRouter.put("/update/:id", TicketController.update); -ticketRouter.delete("/remove/:id", TicketController.remove); +ticketRouter.post("/create", authMiddleware,requirePermission(["ticket.create"]),TicketController.create); +ticketRouter.get("/all", authMiddleware,requirePermission(["ticket.view_all"]),TicketController.getAll); +ticketRouter.get("/all/export", authMiddleware,requirePermission(["ticket.export"]),TicketController.getAllExport); +ticketRouter.get("/all/report", authMiddleware,TicketController.getAllReport); +ticketRouter.get("/get/:id",authMiddleware,requirePermission(["ticket.view"]), TicketController.getById); +ticketRouter.put("/update/:id", authMiddleware,requirePermission(["ticket.update"]),TicketController.update); +ticketRouter.delete("/remove/:id",authMiddleware,requirePermission(["ticket.delete"]), TicketController.remove); export default ticketRouter; diff --git a/src/modules/user/routes/user.router.ts b/src/modules/user/routes/user.router.ts index 26566f7..93b9fa2 100644 --- a/src/modules/user/routes/user.router.ts +++ b/src/modules/user/routes/user.router.ts @@ -1,13 +1,44 @@ import router from "express"; import UserController from "../controller/user.controller"; +import { requirePermission } from "../../../core/middleware/check-permission"; +import authMiddleware from "../../../core/middleware/auth.middleware"; const userRouter = router.Router(); -userRouter.get("/all", UserController.getAll); -userRouter.get("/list", UserController.getList); -userRouter.get("/get/:id", UserController.getById); -userRouter.post("/create", UserController.create); -userRouter.put("/update/:id", UserController.update); -userRouter.delete("/delete/:id", UserController.delete); +userRouter.get( + "/all", + authMiddleware, + requirePermission(["user.view_all"]), + UserController.getAll, +); +userRouter.get( + "/list", + authMiddleware, + UserController.getList, +); +userRouter.get( + "/get/:id", + authMiddleware, + requirePermission(["user.view"]), + UserController.getById, +); +userRouter.post( + "/create", + authMiddleware, + requirePermission(["user.create"]), + UserController.create, +); +userRouter.put( + "/update/:id", + authMiddleware, + requirePermission(["user.update"]), + UserController.update, +); +userRouter.delete( + "/delete/:id", + authMiddleware, + requirePermission(["user.delete"]), + UserController.delete, +); export default userRouter; diff --git a/src/seeders/permission.seed.ts b/src/seeders/permission.seed.ts index 747db12..860240b 100644 --- a/src/seeders/permission.seed.ts +++ b/src/seeders/permission.seed.ts @@ -1,129 +1,8 @@ +import { permissions } from "../core/constants"; import Permission from "../models/Permission"; export async function seedPermissions() { - const permissions = [ - "filter.view", - /* ================================ - ✅ TICKETS - ================================= */ - "ticket.create", - "ticket.view", - "ticket.view_all", - "ticket.update", - "ticket.delete", - "ticket.assign", - "ticket.change_status", - "ticket.close", - "ticket.reopen", - "ticket.comment", - "ticket.internal_note", - "ticket.upload_file", - "ticket.merge", - "ticket.export", - - /* ================================ - ✅ USERS - ================================= */ - "user.view", - "user.view_all", - "user.create", - "user.update", - "user.delete", - "user.activate", - "user.deactivate", - "user.assign_role", - - /* ================================ - ✅ ROLES - ================================= */ - "role.view", - "role.create", - "role.update", - "role.delete", - - /* ================================ - ✅ PERMISSIONS - ================================= */ - "permission.view", - "permission.assign_to_role", - "permission.assign_to_user", - - /* ================================ - ✅ DEPARTMENTS - ================================= */ - "department.view", - "department.create", - "department.update", - "department.delete", - - /* ================================ - ✅ REPORTS - SYSTEM LEVEL - ================================= */ - "report.system.view", - "report.system.export", - - "report.department.view", - "report.department.export", - - "report.operator.view", - "report.operator.export", - - "report.sla.view", - "report.sla.export", - - "report.kpi.view", - "report.kpi.export", - - /* ================================ - ✅ DASHBOARD - ================================= */ - "dashboard.view", - "dashboard.view_advanced", - - /* ================================ - ✅ SLA MANAGEMENT - ================================= */ - "sla.view", - "sla.create", - "sla.update", - "sla.delete", - - /* ================================ - ✅ REQUEST TYPES - ================================= */ - "request_type.view", - "request_type.create", - "request_type.update", - "request_type.delete", - - /* ================================ - ✅ TAGS - ================================= */ - "tag.view", - "tag.create", - "tag.update", - "tag.delete", - - /* ================================ - ✅ SETTINGS - ================================= */ - "settings.view", - "settings.update", - - /* ================================ - ✅ LOGS - ================================= */ - "log.view", - "audit.view", - - /* ================================ - ✅ OPERATOR / PERFORMANCE - ================================= */ - "operator.view", - "operator.performance.view", - "operator.performance.export", - ]; - + let createdCount = 0; for (const name of permissions) { diff --git a/src/seeders/rolePermission.ts b/src/seeders/rolePermission.ts index 0e9c9b1..15f6b69 100644 --- a/src/seeders/rolePermission.ts +++ b/src/seeders/rolePermission.ts @@ -39,83 +39,144 @@ export async function seedRolePermissions() { /* ========================================= ✅ MANAGER (دسترسی بالا) ========================================== */ + /* ========================================= + ✅ MANAGER +========================================= */ + /* ========================================= + ✅ MANAGER +========================================= */ await assignPermissions("manager", [ - // tickets + /* ---------- Tickets ---------- */ "ticket.view_all", "ticket.assign", "ticket.change_status", + "ticket.close", + "ticket.reopen", + "ticket.merge", "ticket.export", + "ticket.create", - // users + /* ---------- Users ---------- */ + "user.view", "user.view_all", "user.create", "user.update", + "user.activate", + "user.deactivate", + "user.assign_role", - // reports + /* ---------- Roles ---------- */ + "role.view", + + /* ---------- Permissions ---------- */ + "permission.view", + "permission.view_all", + "permission.assign_to_role", + "permission.assign_to_user", + + /* ---------- Departments ---------- */ + "department.view", + "department.create", + "department.update", + + /* ---------- Reports ---------- */ "report.system.view", + "report.system.export", "report.department.view", + "report.department.export", "report.operator.view", + "report.operator.export", "report.sla.view", "report.kpi.view", + "report.trend.view", + "report.closure_rate.view", + "report.critical.view", + "report.avg_resolution.view", + "report.aging.view", + "report.agent_efficiency.view", + "report.department_load.view", + "report.prediction.view", + "report.export_excel", - "report.system.export", - "report.department.export", - - // dashboard + /* ---------- Dashboard ---------- */ "dashboard.view_advanced", - // operator + /* ---------- Operator ---------- */ + "operator.view", "operator.performance.view", - ]); + "operator.performance.export", + /* ---------- Logs ---------- */ + "log.view", + "audit.view", + ]); /* ========================================= - ✅ SUPERVISOR - ========================================== */ + ✅ SUPERVISOR +========================================= */ await assignPermissions("supervisor", [ + /* Tickets */ "ticket.view_all", "ticket.assign", "ticket.change_status", "ticket.comment", + "ticket.internal_note", + "ticket.close", + "ticket.reopen", + /* Reports */ "report.department.view", "report.operator.view", + "report.trend.view", + "report.closure_rate.view", + "report.aging.view", + /* Dashboard */ "dashboard.view", + + /* Operator */ + "operator.view", + "operator.performance.view", ]); /* ========================================= - ✅ SENIOR EXPERT - ========================================== */ + ✅ SENIOR EXPERT +========================================= */ await assignPermissions("senior_expert", [ "ticket.view", "ticket.change_status", "ticket.comment", "ticket.internal_note", + "ticket.upload_file", "dashboard.view", ]); /* ========================================= - ✅ EXPERT - ========================================== */ + ✅ EXPERT +========================================= */ await assignPermissions("expert", [ "ticket.view", "ticket.change_status", "ticket.comment", + "ticket.upload_file", ]); /* ========================================= - ✅ TECHNICIAN - ========================================== */ - await assignPermissions("technician", ["ticket.view", "ticket.comment"]); - + ✅ TECHNICIAN +========================================= */ + await assignPermissions("technician", [ + "ticket.view", + "ticket.comment", + "ticket.upload_file", + ]); /* ========================================= - ✅ NORMAL USER - ========================================== */ + ✅ NORMAL USER +========================================= */ await assignPermissions("user", [ "ticket.create", "ticket.view", "ticket.comment", + "ticket.upload_file", ]); console.log("✅ RolePermissions seeded successfully");