This commit is contained in:
2026-06-16 11:32:07 +03:30
parent fdda306e85
commit b5bfd13ea2
17 changed files with 626 additions and 358 deletions

View File

@@ -1,4 +1,149 @@
export const JWT_SECRET = process.env.JWT_SECRET || "secret"; 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'] 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;

View File

@@ -2,28 +2,66 @@ import { NextFunction } from "express";
import { ServerResponse } from "../types"; import { ServerResponse } from "../types";
import { JWT_SECRET, TOKEN_NAME } from "../constants"; import { JWT_SECRET, TOKEN_NAME } from "../constants";
import createHttpError from "http-errors"; 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 jwt = require("jsonwebtoken");
const authMiddleware = (req:any, res:ServerResponse, next:NextFunction) => { const authMiddleware = async (
// ۱. خواندن توکن از کوکی‌ها req: any,
const token = req.cookies[TOKEN_NAME]; // TOKEN_NAME همان متغیری است که در زمان ست کردن کوکی داشتید res: ServerResponse,
next: NextFunction,
) => {
const token = req.cookies[TOKEN_NAME];
if (!token) { if (!token) {
throw new createHttpError.Unauthorized("لطفا وارد حساب كاربري خود شويد") return next(
new createHttpError.Unauthorized("لطفا وارد حساب كاربري خود شويد"),
);
} }
try { try {
// ۲. اعتبارسنجی توکن با استفاده از همان SECRET const decoded = jwt.verify(token, JWT_SECRET) as {
const decoded = jwt.verify(token, JWT_SECRET); id: number;
roleId: number;
};
// ۳. قرار دادن اطلاعات کاربر در آبجکت درخواست برای استفاده در مسیرهای بعدی const user = await User.findByPk(decoded.id, {
req.user = decoded; attributes: ["id", "roleId"],
include: [
{
model: Role,
as: "role",
attributes: ["id", "name"],
include: [
{
model: Permission,
as: "permissions",
attributes: ["name"],
through: { attributes: [] },
},
],
},
],
});
next(); // ادامه به مسیر اصلی if (!user) {
} catch (error) { return next(new createHttpError.Unauthorized("کاربر یافت نشد"));
throw new createHttpError.Forbidden("حساب كاربري شما نامعتبر است") }
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;

View File

@@ -1,46 +1,65 @@
import Permission from "../../models/Permission"; import { NextFunction } from "express";
import RolePermission from "../../models/RolePermission"; import { PermissionType } from "../types";
import UserPermission from "../../models/UserPermission"; 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) { // const permission = await Permission.findOne({
return async (req: any, res: any, next: any) => { // 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 user = req.user;
const permission = await Permission.findOne({ if (!user) {
where: { name: permissionName }, throw new createHttpError.Unauthorized("وارد حساب كاربري خود شويد");
});
if (!permission) {
return res.status(403).json({ message: "Permission not found" });
} }
// ✅ 1- چک سطح کاربر const userPermissions: PermissionType[] = user.permissions || [];
const userPermission = await UserPermission.findOne({
where: {
userId: user.id,
permissionId: permission.id,
},
});
if (userPermission) { const hasPermission = permission.some((p) => userPermissions.includes(p));
return next();
if (!hasPermission) {
throw new createHttpError.Forbidden("به اين قسمت دسترسي نداريد");
} }
// ✅ 2- چک سطح رول next();
const rolePermission = await RolePermission.findOne({
where: {
roleId: user.roleId,
permissionId: permission.id,
},
});
if (rolePermission) {
return next();
}
return res.status(403).json({
message: "Access Denied",
});
}; };
} }

View File

@@ -1,4 +1,5 @@
import { Response } from "express"; import { Response } from "express";
import { permissions } from "../constants";
export interface ServerResponseObject { export interface ServerResponseObject {
status: number; status: number;
@@ -69,30 +70,29 @@ export interface ticketRequestTypeDataType {
updatedAt?: Date; updatedAt?: Date;
} }
// reports // reports
export interface TicketStats { export interface TicketStats {
total: number total: number;
open: number open: number;
inProgress: number inProgress: number;
resolved: number resolved: number;
closed: number closed: number;
} }
export interface DepartmentReport { export interface DepartmentReport {
departmentId: string departmentId: string;
departmentName: string departmentName: string;
totalTickets: number totalTickets: number;
openTickets: number openTickets: number;
resolvedTickets: number resolvedTickets: number;
} }
export interface AgentReport { export interface AgentReport {
userId: string userId: string;
fullname: string fullname: string;
totalAssigned: number totalAssigned: number;
resolved: number resolved: number;
open: number open: number;
} }
export type PermissionType = (typeof permissions)[number];

View File

@@ -1,92 +1,97 @@
import { import {
Model, Model,
DataTypes, DataTypes,
Optional, Optional,
Sequelize, Sequelize,
BelongsToManySetAssociationsMixin, BelongsToManySetAssociationsMixin,
BelongsToManyAddAssociationsMixin, BelongsToManyAddAssociationsMixin,
BelongsToManyRemoveAssociationsMixin, BelongsToManyRemoveAssociationsMixin,
BelongsToManyGetAssociationsMixin, BelongsToManyGetAssociationsMixin,
HasManyGetAssociationsMixin HasManyGetAssociationsMixin,
} from "sequelize"; } from "sequelize";
import User from "./User"; import User from "./User";
import Permission from "./Permission"; import Permission from "./Permission";
interface RoleAttributes {
id: string;
name: string;
description?: string;
createdAt?: Date;
updatedAt?: Date;
}
interface RoleAttributes { interface RoleCreationAttributes extends Optional<
id: string; RoleAttributes,
name: string; "id" | "description"
description?: string; > {}
createdAt?: Date;
updatedAt?: Date;
}
interface RoleCreationAttributes class Role
extends Optional<RoleAttributes, "id" | "description"> {} extends Model<RoleAttributes, RoleCreationAttributes>
implements RoleAttributes
{
public id!: string;
public name!: string;
public description?: string;
public permissions?: Permission[];
class Role public readonly createdAt!: Date;
extends Model<RoleAttributes, RoleCreationAttributes> public readonly updatedAt!: Date;
implements RoleAttributes
{
public id!: string;
public name!: string;
public description?: string;
public readonly createdAt!: Date; // Users relation
public readonly updatedAt!: Date; public getUsers!: HasManyGetAssociationsMixin<User>;
// Users relation // Permissions relation
public getUsers!: HasManyGetAssociationsMixin<User>; public getPermissions!: BelongsToManyGetAssociationsMixin<Permission>;
public setPermissions!: BelongsToManySetAssociationsMixin<Permission, string>;
public addPermissions!: BelongsToManyAddAssociationsMixin<Permission, string>;
public removePermissions!: BelongsToManyRemoveAssociationsMixin<
Permission,
string
>;
// Permissions relation static initModel(sequelize: Sequelize): typeof Role {
public getPermissions!: BelongsToManyGetAssociationsMixin<Permission>; Role.init(
public setPermissions!: BelongsToManySetAssociationsMixin<Permission, string>; {
public addPermissions!: BelongsToManyAddAssociationsMixin<Permission, string>; id: {
public removePermissions!: BelongsToManyRemoveAssociationsMixin<Permission, string>; type: DataTypes.UUID,
primaryKey: true,
static initModel(sequelize: Sequelize): typeof Role { defaultValue: DataTypes.UUIDV4,
Role.init(
{
id: {
type: DataTypes.UUID,
primaryKey: true,
defaultValue: DataTypes.UUIDV4,
},
name: {
type: DataTypes.STRING,
unique: true,
allowNull: false,
},
description: {
type: DataTypes.STRING,
},
}, },
{
sequelize,
modelName: "Role",
tableName: "roles",
timestamps: true,
}
);
return Role; name: {
} type: DataTypes.STRING,
unique: true,
allowNull: false,
},
static associate(models: any) { description: {
Role.hasMany(models.User, { type: DataTypes.STRING,
foreignKey: "roleId", },
as: "users", },
}); {
sequelize,
modelName: "Role",
tableName: "roles",
timestamps: true,
},
);
Role.belongsToMany(models.Permission, { return Role;
through: models.RolePermission,
foreignKey: "roleId",
otherKey: "permissionId",
as: "permissions",
});
}
} }
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;

View File

@@ -1,9 +1,5 @@
import { import { Model, DataTypes, Optional, Sequelize } from "sequelize";
Model, import Role from "./Role";
DataTypes,
Optional,
Sequelize
} from "sequelize";
interface UserAttributes { interface UserAttributes {
id: string; id: string;
@@ -15,8 +11,7 @@ interface UserAttributes {
updatedAt?: Date; updatedAt?: Date;
} }
interface UserCreationAttributes interface UserCreationAttributes extends Optional<UserAttributes, "id"> {}
extends Optional<UserAttributes, "id"> {}
class User class User
extends Model<UserAttributes, UserCreationAttributes> extends Model<UserAttributes, UserCreationAttributes>
@@ -27,6 +22,7 @@ class User
public nationalCode!: string; public nationalCode!: string;
public mobile!: string; public mobile!: string;
public roleId!: string; public roleId!: string;
public role?: Role;
public readonly createdAt!: Date; public readonly createdAt!: Date;
public readonly updatedAt!: Date; public readonly updatedAt!: Date;
@@ -69,26 +65,22 @@ class User
modelName: "User", modelName: "User",
tableName: "users", tableName: "users",
timestamps: true, timestamps: true,
} },
); );
return User; return User;
} }
static associate(models: any) { static associate(models: any) {
User.belongsTo(models.Role, { User.belongsTo(models.Role, {
foreignKey: "roleId", foreignKey: "roleId",
as: "role", as: "role",
}); });
User.hasMany(models.Ticket, { User.hasMany(models.Ticket, {
foreignKey: "assignedTo", foreignKey: "assignedTo",
as: "assignedTickets", as: "assignedTickets",
}); });
} }
} }

View File

@@ -7,7 +7,6 @@ import { TOKEN_NAME } from "../../../core/constants";
import { GlobalMessages } from "../../../core/messages"; import { GlobalMessages } from "../../../core/messages";
import { Controller } from "../../../core/controller/main.controller"; import { Controller } from "../../../core/controller/main.controller";
class AuthControllerClass extends Controller { class AuthControllerClass extends Controller {
#service; #service;
@@ -16,6 +15,19 @@ class AuthControllerClass extends Controller {
this.#service = AuthService; 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) { async login(req: any, res: ServerResponse, next: NextFunction) {
try { try {
await AuthValidationSchema.validateAsync(req.body || {}); await AuthValidationSchema.validateAsync(req.body || {});

View File

@@ -1,10 +1,11 @@
import express from 'express' import express from "express";
import AuthController from '../controller/auth.controller'; 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("/login", AuthController.login);
authRouter.post('/logout',AuthController.logout) authRouter.post("/logout", AuthController.logout);
export default authRouter; export default authRouter;

View File

@@ -4,6 +4,8 @@ import jwt from "jsonwebtoken";
import dotenv from "dotenv"; import dotenv from "dotenv";
import User from "../../../models/User"; import User from "../../../models/User";
import { JWT_SECRET } from "../../../core/constants"; import { JWT_SECRET } from "../../../core/constants";
import Role from "../../../models/Role";
import Permission from "../../../models/Permission";
dotenv.config(); dotenv.config();
class AuthServiceClass { 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(); const AuthService = new AuthServiceClass();

View File

@@ -1,13 +1,48 @@
import router from "express"; import router from "express";
import DepartmentController from "../controller/department.controller"; import DepartmentController from "../controller/department.controller";
import authMiddleware from "../../../core/middleware/auth.middleware";
import { requirePermission } from "../../../core/middleware/check-permission";
const departmentRouter = router.Router(); const departmentRouter = router.Router();
departmentRouter.get(
"/all",
authMiddleware,
requirePermission(["department.view"]),
DepartmentController.getAll,
);
departmentRouter.get("/all", DepartmentController.getAll); departmentRouter.get(
departmentRouter.get("/list", DepartmentController.getAllList); "/list",
departmentRouter.get("/get/:id", DepartmentController.getById); authMiddleware,
departmentRouter.post("/create", DepartmentController.create); DepartmentController.getAllList,
departmentRouter.delete("/delete/:id", DepartmentController.delete); );
departmentRouter.put("/update/:id", DepartmentController.update);
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; export default departmentRouter;

View File

@@ -1,19 +1,21 @@
import { Router } from "express"; import { Router } from "express";
import PermissionController from "./permission.controller"; import PermissionController from "./permission.controller";
import { requirePermission } from "../../core/middleware/check-permission";
import authMiddleware from "../../core/middleware/auth.middleware";
const PermissionRouter = Router(); const PermissionRouter = Router();
PermissionRouter.post("/create", PermissionController.create); PermissionRouter.post("/create",authMiddleware,requirePermission(["permission.create"]),PermissionController.create);
PermissionRouter.get("/all", PermissionController.getAll); PermissionRouter.get("/all", authMiddleware,requirePermission(["permission.view_all"]),PermissionController.getAll);
PermissionRouter.get("/list", PermissionController.getList); 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; export default PermissionRouter;

View File

@@ -1,60 +1,62 @@
import { Router } from "express"; import { Router } from "express";
import ReportController from "../controller/report.controller"; import ReportController from "../controller/report.controller";
import authMiddleware from "../../../core/middleware/auth.middleware";
import { requirePermission } from "../../../core/middleware/check-permission";
const reportRouter = Router(); const reportRouter = Router();
reportRouter.get( reportRouter.get(
"/stats", "/stats",authMiddleware,requirePermission(["report.system.view"]),
// requireAuth, // requireAuth,
// requirePermission("VIEW_REPORTS"), // requirePermission("VIEW_REPORTS"),
ReportController.ticketStats, ReportController.ticketStats,
); );
reportRouter.get( reportRouter.get(
"/departments", "/departments",authMiddleware,requirePermission(["report.department.view"]),
// requireAuth, // requireAuth,
// requirePermission("VIEW_REPORTS"), // requirePermission("VIEW_REPORTS"),
ReportController.departmentReport, ReportController.departmentReport,
); );
reportRouter.get( reportRouter.get(
"/agents", "/agents",authMiddleware,requirePermission(["report.operator.view"]),
// requireAuth, // requireAuth,
// requirePermission("VIEW_REPORTS"), // requirePermission("VIEW_REPORTS"),
ReportController.agentPerformance, ReportController.agentPerformance,
); );
reportRouter.get( reportRouter.get(
"/avg-resolution", "/avg-resolution",authMiddleware,requirePermission(["report.avg_resolution.view"]),
// requireAuth, // requireAuth,
// requirePermission("VIEW_REPORTS"), // requirePermission("VIEW_REPORTS"),
ReportController.avgResolution, ReportController.avgResolution,
); );
reportRouter.get( reportRouter.get(
"/critical", "/critical",authMiddleware,requirePermission(["report.critical.view"]),
// requireAuth, // requireAuth,
// requirePermission("VIEW_REPORTS"), // requirePermission("VIEW_REPORTS"),
ReportController.criticalTickets, 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)

View File

@@ -1,16 +1,18 @@
import { Router } from "express"; import { Router } from "express";
import RoleController from "./role.controller"; import RoleController from "./role.controller";
import authMiddleware from "../../core/middleware/auth.middleware";
import { requirePermission } from "../../core/middleware/check-permission";
const RoleRouter = Router(); const RoleRouter = Router();
RoleRouter.post("/create", RoleController.create); RoleRouter.post("/create", authMiddleware,requirePermission(["role.create"]),RoleController.create);
RoleRouter.get("/list", RoleController.findList); RoleRouter.get("/list", authMiddleware,RoleController.findList);
RoleRouter.get("/all", RoleController.findAll); RoleRouter.get("/all", authMiddleware,requirePermission(["role.view"]),RoleController.findAll);
RoleRouter.get("/:id", RoleController.findById); RoleRouter.get("/:id", authMiddleware,requirePermission(["role.view"]),RoleController.findById);
RoleRouter.put("/update/:id", RoleController.update); RoleRouter.put("/update/:id", authMiddleware,requirePermission(["role.update"]),RoleController.update);
RoleRouter.delete("/remove/:id", RoleController.delete); RoleRouter.delete("/remove/:id", authMiddleware,requirePermission(["role.delete"]),RoleController.delete);
RoleRouter.post("/:id/permissions/assign", RoleController.assignPermissions); RoleRouter.post("/:id/permissions/assign", authMiddleware,requirePermission(["permission.assign_to_role"]),RoleController.assignPermissions);
RoleRouter.post("/:id/permissions/add", RoleController.addPermissions); RoleRouter.post("/:id/permissions/add", authMiddleware,RoleController.addPermissions);
RoleRouter.post("/:id/permissions/remove", RoleController.removePermissions); RoleRouter.post("/:id/permissions/remove", authMiddleware,RoleController.removePermissions);
export default RoleRouter; export default RoleRouter;

View File

@@ -1,14 +1,16 @@
import express from "express"; import express from "express";
import TicketController from "../controller/ticket.controller"; import TicketController from "../controller/ticket.controller";
import authMiddleware from "../../../core/middleware/auth.middleware";
import { requirePermission } from "../../../core/middleware/check-permission";
const ticketRouter = express.Router(); const ticketRouter = express.Router();
ticketRouter.post("/create", TicketController.create); ticketRouter.post("/create", authMiddleware,requirePermission(["ticket.create"]),TicketController.create);
ticketRouter.get("/all", TicketController.getAll); ticketRouter.get("/all", authMiddleware,requirePermission(["ticket.view_all"]),TicketController.getAll);
ticketRouter.get("/all/export", TicketController.getAllExport); ticketRouter.get("/all/export", authMiddleware,requirePermission(["ticket.export"]),TicketController.getAllExport);
ticketRouter.get("/all/report", TicketController.getAllReport); ticketRouter.get("/all/report", authMiddleware,TicketController.getAllReport);
ticketRouter.get("/get/:id", TicketController.getById); ticketRouter.get("/get/:id",authMiddleware,requirePermission(["ticket.view"]), TicketController.getById);
ticketRouter.put("/update/:id", TicketController.update); ticketRouter.put("/update/:id", authMiddleware,requirePermission(["ticket.update"]),TicketController.update);
ticketRouter.delete("/remove/:id", TicketController.remove); ticketRouter.delete("/remove/:id",authMiddleware,requirePermission(["ticket.delete"]), TicketController.remove);
export default ticketRouter; export default ticketRouter;

View File

@@ -1,13 +1,44 @@
import router from "express"; import router from "express";
import UserController from "../controller/user.controller"; import UserController from "../controller/user.controller";
import { requirePermission } from "../../../core/middleware/check-permission";
import authMiddleware from "../../../core/middleware/auth.middleware";
const userRouter = router.Router(); const userRouter = router.Router();
userRouter.get("/all", UserController.getAll); userRouter.get(
userRouter.get("/list", UserController.getList); "/all",
userRouter.get("/get/:id", UserController.getById); authMiddleware,
userRouter.post("/create", UserController.create); requirePermission(["user.view_all"]),
userRouter.put("/update/:id", UserController.update); UserController.getAll,
userRouter.delete("/delete/:id", UserController.delete); );
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; export default userRouter;

View File

@@ -1,128 +1,7 @@
import { permissions } from "../core/constants";
import Permission from "../models/Permission"; import Permission from "../models/Permission";
export async function seedPermissions() { 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; let createdCount = 0;

View File

@@ -39,83 +39,144 @@ export async function seedRolePermissions() {
/* ========================================= /* =========================================
✅ MANAGER (دسترسی بالا) ✅ MANAGER (دسترسی بالا)
========================================== */ ========================================== */
/* =========================================
✅ MANAGER
========================================= */
/* =========================================
✅ MANAGER
========================================= */
await assignPermissions("manager", [ await assignPermissions("manager", [
// tickets /* ---------- Tickets ---------- */
"ticket.view_all", "ticket.view_all",
"ticket.assign", "ticket.assign",
"ticket.change_status", "ticket.change_status",
"ticket.close",
"ticket.reopen",
"ticket.merge",
"ticket.export", "ticket.export",
"ticket.create",
// users /* ---------- Users ---------- */
"user.view",
"user.view_all", "user.view_all",
"user.create", "user.create",
"user.update", "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.view",
"report.system.export",
"report.department.view", "report.department.view",
"report.department.export",
"report.operator.view", "report.operator.view",
"report.operator.export",
"report.sla.view", "report.sla.view",
"report.kpi.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", /* ---------- Dashboard ---------- */
"report.department.export",
// dashboard
"dashboard.view_advanced", "dashboard.view_advanced",
// operator /* ---------- Operator ---------- */
"operator.view",
"operator.performance.view", "operator.performance.view",
]); "operator.performance.export",
/* ---------- Logs ---------- */
"log.view",
"audit.view",
]);
/* ========================================= /* =========================================
✅ SUPERVISOR ✅ SUPERVISOR
========================================== */ ========================================= */
await assignPermissions("supervisor", [ await assignPermissions("supervisor", [
/* Tickets */
"ticket.view_all", "ticket.view_all",
"ticket.assign", "ticket.assign",
"ticket.change_status", "ticket.change_status",
"ticket.comment", "ticket.comment",
"ticket.internal_note",
"ticket.close",
"ticket.reopen",
/* Reports */
"report.department.view", "report.department.view",
"report.operator.view", "report.operator.view",
"report.trend.view",
"report.closure_rate.view",
"report.aging.view",
/* Dashboard */
"dashboard.view", "dashboard.view",
/* Operator */
"operator.view",
"operator.performance.view",
]); ]);
/* ========================================= /* =========================================
✅ SENIOR EXPERT ✅ SENIOR EXPERT
========================================== */ ========================================= */
await assignPermissions("senior_expert", [ await assignPermissions("senior_expert", [
"ticket.view", "ticket.view",
"ticket.change_status", "ticket.change_status",
"ticket.comment", "ticket.comment",
"ticket.internal_note", "ticket.internal_note",
"ticket.upload_file",
"dashboard.view", "dashboard.view",
]); ]);
/* ========================================= /* =========================================
✅ EXPERT ✅ EXPERT
========================================== */ ========================================= */
await assignPermissions("expert", [ await assignPermissions("expert", [
"ticket.view", "ticket.view",
"ticket.change_status", "ticket.change_status",
"ticket.comment", "ticket.comment",
"ticket.upload_file",
]); ]);
/* ========================================= /* =========================================
✅ TECHNICIAN ✅ TECHNICIAN
========================================== */ ========================================= */
await assignPermissions("technician", ["ticket.view", "ticket.comment"]); await assignPermissions("technician", [
"ticket.view",
"ticket.comment",
"ticket.upload_file",
]);
/* ========================================= /* =========================================
✅ NORMAL USER ✅ NORMAL USER
========================================== */ ========================================= */
await assignPermissions("user", [ await assignPermissions("user", [
"ticket.create", "ticket.create",
"ticket.view", "ticket.view",
"ticket.comment", "ticket.comment",
"ticket.upload_file",
]); ]);
console.log("✅ RolePermissions seeded successfully"); console.log("✅ RolePermissions seeded successfully");