update
This commit is contained in:
@@ -6,6 +6,7 @@ import userRouter from "../../modules/user/routes/user.router";
|
|||||||
import reportRouter from "../../modules/report/routes/report.router";
|
import reportRouter from "../../modules/report/routes/report.router";
|
||||||
import authMiddleware from "../middleware/auth.middleware";
|
import authMiddleware from "../middleware/auth.middleware";
|
||||||
import RoleRouter from "../../modules/roles/role.routes";
|
import RoleRouter from "../../modules/roles/role.routes";
|
||||||
|
import PermissionRouter from "../../modules/permission/permission.routes";
|
||||||
|
|
||||||
const mainRouter = router.Router();
|
const mainRouter = router.Router();
|
||||||
|
|
||||||
@@ -15,5 +16,6 @@ mainRouter.use("/ticket", authMiddleware, ticketRouter);
|
|||||||
mainRouter.use("/user", authMiddleware, userRouter);
|
mainRouter.use("/user", authMiddleware, userRouter);
|
||||||
mainRouter.use("/report", authMiddleware, reportRouter);
|
mainRouter.use("/report", authMiddleware, reportRouter);
|
||||||
mainRouter.use("/role", authMiddleware, RoleRouter);
|
mainRouter.use("/role", authMiddleware, RoleRouter);
|
||||||
|
mainRouter.use("/permission", authMiddleware, PermissionRouter);
|
||||||
|
|
||||||
export default mainRouter;
|
export default mainRouter;
|
||||||
|
|||||||
75
src/modules/permission/permission.controller.ts
Normal file
75
src/modules/permission/permission.controller.ts
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import { NextFunction, Request, Response } from "express";
|
||||||
|
import { Controller } from "../../core/controller/main.controller";
|
||||||
|
import PermissionService from "./permission.service";
|
||||||
|
import { ServerResponse } from "../../core/types";
|
||||||
|
|
||||||
|
class PermissionControllerClass extends Controller {
|
||||||
|
#service;
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.#service = PermissionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ایجاد دسترسی جدید
|
||||||
|
create = async (req:any, res: ServerResponse, next: NextFunction) => {
|
||||||
|
try {
|
||||||
|
const result = await this.#service.create(req.body);
|
||||||
|
return res.status(201).json({status:201,data:result});
|
||||||
|
} catch (error) {
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// دریافت لیست دسترسیها (با فیلتر و صفحهبندی)
|
||||||
|
getAll = async (req:any, res: ServerResponse, next: NextFunction) => {
|
||||||
|
try {
|
||||||
|
const result = await this.#service.getAll(req.query);
|
||||||
|
return res.status(200).json({status:200,data:result});
|
||||||
|
} catch (error) {
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// دریافت یک دسترسی خاص
|
||||||
|
getById = async (req:any, res: ServerResponse, next: NextFunction) => {
|
||||||
|
try {
|
||||||
|
const { id } = req.params;
|
||||||
|
const result = await this.#service.getById(id);
|
||||||
|
return res.status(200).json({status:200,data:result});
|
||||||
|
} catch (error) {
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ویرایش دسترسی
|
||||||
|
update = async (req:any, res: ServerResponse, next: NextFunction) => {
|
||||||
|
try {
|
||||||
|
const { id } = req.params;
|
||||||
|
const result = await this.#service.update(id, req.body);
|
||||||
|
return res.status(200).json({status:200,data:result});
|
||||||
|
} catch (error) {
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
getList = async(req:any,res:ServerResponse,next:NextFunction) => {
|
||||||
|
try {
|
||||||
|
const result = await this.#service.getList();
|
||||||
|
return res.status(200).json({status:200,data:result});
|
||||||
|
} catch (error) {
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// حذف دسترسی
|
||||||
|
delete = async (req:any, res: ServerResponse, next: NextFunction) => {
|
||||||
|
try {
|
||||||
|
const { id } = req.params;
|
||||||
|
const result = await this.#service.delete(id);
|
||||||
|
return res.status(200).json({status:200,data:result});
|
||||||
|
} catch (error) {
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const PermissionController = new PermissionControllerClass();
|
||||||
|
export default PermissionController;
|
||||||
19
src/modules/permission/permission.routes.ts
Normal file
19
src/modules/permission/permission.routes.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { Router } from "express";
|
||||||
|
import PermissionController from "./permission.controller";
|
||||||
|
|
||||||
|
const PermissionRouter = Router();
|
||||||
|
|
||||||
|
PermissionRouter.post("/create", PermissionController.create);
|
||||||
|
|
||||||
|
|
||||||
|
PermissionRouter.get("/all", PermissionController.getAll);
|
||||||
|
PermissionRouter.get("/list", PermissionController.getList);
|
||||||
|
|
||||||
|
PermissionRouter.get("/get/:id", PermissionController.getById);
|
||||||
|
|
||||||
|
|
||||||
|
PermissionRouter.put("/update/:id", PermissionController.update);
|
||||||
|
|
||||||
|
PermissionRouter.delete("/remove/:id", PermissionController.delete);
|
||||||
|
|
||||||
|
export default PermissionRouter;
|
||||||
81
src/modules/permission/permission.service.ts
Normal file
81
src/modules/permission/permission.service.ts
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import { Op } from "sequelize";
|
||||||
|
import createHttpError from "http-errors";
|
||||||
|
import Permission from "../../models/Permission";
|
||||||
|
|
||||||
|
class PermissionServiceClass {
|
||||||
|
async create(data: { name: string }) {
|
||||||
|
const existing = await Permission.findOne({ where: { name: data.name } });
|
||||||
|
if (existing) {
|
||||||
|
throw createHttpError.BadRequest("این دسترسی قبلاً ثبت شده است.");
|
||||||
|
}
|
||||||
|
return await Permission.create(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAll(query: any) {
|
||||||
|
const { page = 1, limit = 10, search, startDate, endDate } = query;
|
||||||
|
|
||||||
|
const offset = (page - 1) * limit;
|
||||||
|
const whereClause: any = {};
|
||||||
|
|
||||||
|
if (search) {
|
||||||
|
whereClause.name = { [Op.iLike]: `%${search}%` };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startDate || endDate) {
|
||||||
|
whereClause.createdAt = {};
|
||||||
|
if (startDate) whereClause.createdAt[Op.gte] = new Date(startDate);
|
||||||
|
if (endDate) {
|
||||||
|
const end = new Date(endDate);
|
||||||
|
end.setHours(23, 59, 59, 999);
|
||||||
|
whereClause.createdAt[Op.lte] = end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { count, rows } = await Permission.findAndCountAll({
|
||||||
|
where: whereClause,
|
||||||
|
order: [["createdAt", "DESC"]],
|
||||||
|
limit: parseInt(limit),
|
||||||
|
offset: parseInt(offset.toString()),
|
||||||
|
distinct: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: rows,
|
||||||
|
totalItems: count,
|
||||||
|
totalPages: Math.ceil(count / limit),
|
||||||
|
currentPage: parseInt(page),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
async getList() {
|
||||||
|
const data = await Permission.findAll({});
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
async getById(id: string) {
|
||||||
|
const permission = await Permission.findByPk(id);
|
||||||
|
if (!permission) {
|
||||||
|
throw createHttpError.NotFound("دسترسی مورد نظر یافت نشد.");
|
||||||
|
}
|
||||||
|
return permission;
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(id: string, data: { name: string }) {
|
||||||
|
const permission = await this.getById(id);
|
||||||
|
|
||||||
|
if (data.name && data.name !== permission.name) {
|
||||||
|
const existing = await Permission.findOne({ where: { name: data.name } });
|
||||||
|
if (existing) throw createHttpError.BadRequest("نام دسترسی تکراری است.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return await permission.update(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(id: string) {
|
||||||
|
const permission = await this.getById(id);
|
||||||
|
await permission.destroy();
|
||||||
|
return { message: "دسترسی با موفقیت حذف شد." };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const PermissionService = new PermissionServiceClass();
|
||||||
|
export default PermissionService;
|
||||||
@@ -23,9 +23,9 @@ class RoleControllerClass extends Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async findAll(_req: any, res: ServerResponse, next: NextFunction) {
|
async findAll(req: any, res: ServerResponse, next: NextFunction) {
|
||||||
try {
|
try {
|
||||||
const roles = await this.#serivce.findAll();
|
const roles = await this.#serivce.findAll(req);
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
status: 200,
|
status: 200,
|
||||||
@@ -36,6 +36,18 @@ class RoleControllerClass extends Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findList(req: any, res: ServerResponse, next: NextFunction) {
|
||||||
|
try {
|
||||||
|
const roles = await this.#serivce.findList();
|
||||||
|
|
||||||
|
return res.status(200).json({
|
||||||
|
status: 200,
|
||||||
|
data: roles,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
findById = async (req: any, res: ServerResponse, next: NextFunction) => {
|
findById = async (req: any, res: ServerResponse, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
const role = await this.#serivce.findById(req.params.id);
|
const role = await this.#serivce.findById(req.params.id);
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import RoleController from "./role.controller";
|
|||||||
|
|
||||||
const RoleRouter = Router();
|
const RoleRouter = Router();
|
||||||
RoleRouter.post("/create", RoleController.create);
|
RoleRouter.post("/create", RoleController.create);
|
||||||
RoleRouter.get("/list", RoleController.findAll);
|
RoleRouter.get("/list", RoleController.findList);
|
||||||
|
RoleRouter.get("/all", RoleController.findAll);
|
||||||
RoleRouter.get("/:id", RoleController.findById);
|
RoleRouter.get("/:id", RoleController.findById);
|
||||||
RoleRouter.put("/update/:id", RoleController.update);
|
RoleRouter.put("/update/:id", RoleController.update);
|
||||||
RoleRouter.delete("/remove/:id", RoleController.delete);
|
RoleRouter.delete("/remove/:id", RoleController.delete);
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
import createHttpError from "http-errors";
|
||||||
import Permission from "../../models/Permission";
|
import Permission from "../../models/Permission";
|
||||||
import Role from "../../models/Role";
|
import Role from "../../models/Role";
|
||||||
import User from "../../models/User";
|
import User from "../../models/User";
|
||||||
|
import { GlobalMessages } from "../../core/messages";
|
||||||
|
import { Op } from "sequelize";
|
||||||
|
|
||||||
class RoleServiceClass {
|
class RoleServiceClass {
|
||||||
async create(data: { name: string; description?: string }) {
|
async create(data: { name: string; description?: string,permissions:string[] }) {
|
||||||
const existingRole = await Role.findOne({
|
const existingRole = await Role.findOne({
|
||||||
where: { name: data.name },
|
where: { name: data.name },
|
||||||
});
|
});
|
||||||
@@ -12,15 +15,28 @@ class RoleServiceClass {
|
|||||||
throw new Error("Role already exists");
|
throw new Error("Role already exists");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1️⃣ ساخت Role
|
||||||
const role = await Role.create({
|
const role = await Role.create({
|
||||||
name: data.name,
|
name: data.name,
|
||||||
description: data.description,
|
description: data.description,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 2️⃣ اگر permission ارسال شده بود
|
||||||
|
if (data.permissions && data.permissions.length) {
|
||||||
|
const permissions = await Permission.findAll({
|
||||||
|
where: {
|
||||||
|
id: data.permissions,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 3️⃣ اتصال permissions به role
|
||||||
|
await role.setPermissions(permissions);
|
||||||
|
}
|
||||||
|
|
||||||
return role;
|
return role;
|
||||||
}
|
}
|
||||||
|
|
||||||
async findAll() {
|
async findList() {
|
||||||
return await Role.findAll({
|
return await Role.findAll({
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
@@ -37,6 +53,77 @@ class RoleServiceClass {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findAll(req: any) {
|
||||||
|
try {
|
||||||
|
const {
|
||||||
|
page = 1,
|
||||||
|
limit = 10,
|
||||||
|
name, // فیلتر نام نقش (اختیاری)
|
||||||
|
startDate,
|
||||||
|
endDate,
|
||||||
|
} = req.query;
|
||||||
|
|
||||||
|
// ۱. محاسبه offset برای صفحهبندی
|
||||||
|
const offset = (page - 1) * limit;
|
||||||
|
|
||||||
|
// ۲. ساخت آبجکت فیلترها به صورت داینامیک
|
||||||
|
const whereClause: any = {};
|
||||||
|
|
||||||
|
if (name) {
|
||||||
|
// استفاده از Op.iLike برای جستجوی متنی (Case-Insensitive) در دیتابیسهای PostgreSQL
|
||||||
|
// اگر از MySQL استفاده میکنید، از Op.like استفاده کنید
|
||||||
|
whereClause.name = { [Op.iLike]: `%${name}%` };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startDate || endDate) {
|
||||||
|
whereClause.createdAt = {};
|
||||||
|
if (startDate) {
|
||||||
|
whereClause.createdAt[Op.gte] = new Date(startDate); // تاریخ شروع (بزرگتر مساوی)
|
||||||
|
}
|
||||||
|
if (endDate) {
|
||||||
|
// تنظیم ساعت روی پایان روز برای شامل شدن کلِ روز آخر
|
||||||
|
const end = new Date(endDate);
|
||||||
|
end.setHours(23, 59, 59, 999);
|
||||||
|
whereClause.createdAt[Op.lte] = end; // تاریخ پایان (کوچکتر مساوی)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ۳. استفاده از findAndCountAll برای دریافت همزمان دیتا و تعداد کل رکوردها
|
||||||
|
const { count, rows } = await Role.findAndCountAll({
|
||||||
|
where: whereClause,
|
||||||
|
distinct: true, // اضافه کردن این خط مشکل شمارش تکراری را حل میکند
|
||||||
|
col: "id", // به صورت اختیاری مشخص کنید روی کدام ستون distinct انجام شود
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Permission,
|
||||||
|
as: "permissions",
|
||||||
|
through: { attributes: [] },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: User,
|
||||||
|
as: "users",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
order: [["createdAt", "DESC"]],
|
||||||
|
limit: parseInt(limit),
|
||||||
|
offset: parseInt(offset.toString()),
|
||||||
|
});
|
||||||
|
|
||||||
|
// ۴. خروجی استاندارد صفحهبندی شده
|
||||||
|
return {
|
||||||
|
data: rows,
|
||||||
|
totalItems: count,
|
||||||
|
totalPages: Math.ceil(count / limit),
|
||||||
|
currentPage: parseInt(page),
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
// مدیریت خطا مشابه متد Ticket
|
||||||
|
throw new createHttpError.InternalServerError(
|
||||||
|
GlobalMessages.errors.server,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async findById(id: string) {
|
async findById(id: string) {
|
||||||
const role = await Role.findByPk(id, {
|
const role = await Role.findByPk(id, {
|
||||||
include: [
|
include: [
|
||||||
|
|||||||
Reference in New Issue
Block a user