diff --git a/src/common/enums/permission.enum.ts b/src/common/enums/permission.enum.ts index 7187fc3..8927ea5 100644 --- a/src/common/enums/permission.enum.ts +++ b/src/common/enums/permission.enum.ts @@ -1,14 +1,18 @@ -export enum Permission { +export enum PermissionEnum { MANAGE_PRODUCTS = 'manage_products', MANAGE_CATEGORIES = 'manage_categories', // Order Management + VIEW_All_REQUEST_ORDERS = 'view_all_request_order', + VIEW_All_INVOICED_ORDERS = 'view_all_invoiced_orders', + VIEW_MY_ASSIGNED_INVOICED_REQUESTS = 'view_my_assigned_invoiced_requests', + VIEW_All_ORDERS = 'view_all_orders', - VIEW_MY_ASSIGNED_ORDERS='view_my_assigned_orders', CREATE_ORDER = 'create_order', UPDATE_ORDER = 'update_order', ASSIGN_DESIGNER = 'assign_designer', + CREATE_ORDER_PRINT='create_order_print', CHANGE_ORDER_STATUS = 'change_order_status', REMOVE_ORDER = 'remove_order', @@ -33,23 +37,26 @@ export enum Permission { * Permission titles mapping (Farsi) * Maps permission names to their Farsi titles */ -export const PermissionTitles: Record = { - [Permission.MANAGE_PRODUCTS]: 'مدیریت محصولات', - [Permission.MANAGE_CATEGORIES]: 'مدیریت دسته‌بندی‌ها', +export const PermissionTitles: Record = { + [PermissionEnum.MANAGE_PRODUCTS]: 'مدیریت محصولات', + [PermissionEnum.MANAGE_CATEGORIES]: 'مدیریت دسته‌بندی‌ها', - [Permission.CREATE_ORDER]: 'ایجاد سفارش جدید', - [Permission.UPDATE_ORDER]: 'ویرایش سفارش ', - [Permission.VIEW_All_ORDERS]: "مشاهده همه سفارش ها", - [Permission.ASSIGN_DESIGNER]: "اضافه کردن طراح به سفارش", - [Permission.CHANGE_ORDER_STATUS]: "تغییر وضعیت سفارش", - [Permission.REMOVE_ORDER]: "حذف سفارش", + [PermissionEnum.CREATE_ORDER]: 'ایجاد سفارش جدید', + [PermissionEnum.UPDATE_ORDER]: 'ویرایش سفارش ', + [PermissionEnum.VIEW_All_ORDERS]: "مشاهده همه سفارش ها", + [PermissionEnum.ASSIGN_DESIGNER]: "اضافه کردن طراح به سفارش", + [PermissionEnum.CHANGE_ORDER_STATUS]: "تغییر وضعیت سفارش", + [PermissionEnum.REMOVE_ORDER]: "حذف سفارش", - [Permission.MANAGE_ADMINS]: 'مدیریت مدیران', - [Permission.MANAGE_USERS]: 'مدیریت کاربران', - [Permission.MANAGE_ROLES]: 'مدیریت نقش‌ها', - [Permission.MANAGE_PAYMENTS]: 'مدیریت پرداخت‌ها', - [Permission.MANAGE_SETTINGS]: 'مدیریت تنظیمات', - [Permission.MANAGE_FORM_BUILDER]: "مدیریت فرم بیلدر", - [Permission.MANAGE_PRINT]: 'مدیریت فرم پرینت', - [Permission.VIEW_MY_ASSIGNED_ORDERS]: "مشاهده سفارشات اساین شده به من", + [PermissionEnum.MANAGE_ADMINS]: 'مدیریت مدیران', + [PermissionEnum.MANAGE_USERS]: 'مدیریت کاربران', + [PermissionEnum.MANAGE_ROLES]: 'مدیریت نقش‌ها', + [PermissionEnum.MANAGE_PAYMENTS]: 'مدیریت پرداخت‌ها', + [PermissionEnum.MANAGE_SETTINGS]: 'مدیریت تنظیمات', + [PermissionEnum.MANAGE_FORM_BUILDER]: "مدیریت فرم بیلدر", + [PermissionEnum.MANAGE_PRINT]: 'مدیریت فرم پرینت', + [PermissionEnum.VIEW_All_REQUEST_ORDERS]: "مشاهده همه درخواست سفارش ها", + [PermissionEnum.VIEW_All_INVOICED_ORDERS]: "مشاهده همه سفارشات پیش فاکتور شده", + [PermissionEnum.VIEW_MY_ASSIGNED_INVOICED_REQUESTS]: "مشاهده همه پیش فاکتور های من", + [PermissionEnum.CREATE_ORDER_PRINT]: "ایجاد سفارش چاپ" }; diff --git a/src/modules/admin/controllers/admin.controller.ts b/src/modules/admin/controllers/admin.controller.ts index ba44b64..7f6ebbf 100644 --- a/src/modules/admin/controllers/admin.controller.ts +++ b/src/modules/admin/controllers/admin.controller.ts @@ -6,7 +6,7 @@ import { ApiTags, ApiOperation, ApiBody, ApiBearerAuth, ApiParam } from '@nestjs import { AdminAuthGuard } from 'src/modules/auth/guards/adminAuth.guard'; import { AdminId } from 'src/common/decorators/admin-id.decorator'; import { Admin } from '../entities/admin.entity'; -import { Permission } from 'src/common/enums/permission.enum'; +import { PermissionEnum } from 'src/common/enums/permission.enum'; import { Permissions } from 'src/common/decorators/permissions.decorator'; // TODO : if admin deleted then recreated it must be doable @@ -14,7 +14,7 @@ import { Permissions } from 'src/common/decorators/permissions.decorator'; @ApiTags('admin') @UseGuards(AdminAuthGuard) @ApiBearerAuth() -@Permissions(Permission.MANAGE_ADMINS) +@Permissions(PermissionEnum.MANAGE_ADMINS) export class AdminController { constructor(private readonly adminService: AdminService) { } diff --git a/src/modules/admin/providers/admin.service.ts b/src/modules/admin/providers/admin.service.ts index 56587da..4156fce 100644 --- a/src/modules/admin/providers/admin.service.ts +++ b/src/modules/admin/providers/admin.service.ts @@ -8,6 +8,7 @@ import { CreateAdminDto } from '../dto/create-admin.dto'; import { AdminRepository } from '../repositories/admin.repository'; import { RoleRepository } from 'src/modules/roles/respository/role.repository'; import { NotificationPreference } from 'src/modules/notification/entities/notification-preference.entity'; +import { PermissionEnum } from 'src/common/enums/permission.enum'; @Injectable() export class AdminService { @@ -153,4 +154,20 @@ export class AdminService { } return admins } + + async hasPermission(adminId: string, permissionName: PermissionEnum): Promise { + const has = await this.adminRepository.count({ + id: adminId, + role: { + permissions: { + $some: { + name: permissionName + } + } + } + }) + + return !!has + + } } diff --git a/src/modules/admin/repositories/admin.repository.ts b/src/modules/admin/repositories/admin.repository.ts index 38519e3..46505ab 100644 --- a/src/modules/admin/repositories/admin.repository.ts +++ b/src/modules/admin/repositories/admin.repository.ts @@ -1,6 +1,7 @@ import { EntityManager, EntityRepository } from '@mikro-orm/postgresql'; import { Admin } from '../entities/admin.entity'; import { Injectable } from '@nestjs/common'; +import { PermissionEnum } from 'src/common/enums/permission.enum'; @Injectable() export class AdminRepository extends EntityRepository { @@ -10,7 +11,7 @@ export class AdminRepository extends EntityRepository { super(em, Admin); } - async findAdminsWithPermission(permission: string): Promise { + async findAdminsWithPermission(permission: PermissionEnum): Promise { const admins = await this.em.find( Admin, { role: { permissions: { name: permission } } }, diff --git a/src/modules/auth/guards/adminAuth.guard.ts b/src/modules/auth/guards/adminAuth.guard.ts index ea8bc9d..fa38607 100644 --- a/src/modules/auth/guards/adminAuth.guard.ts +++ b/src/modules/auth/guards/adminAuth.guard.ts @@ -13,7 +13,7 @@ import { JwtService } from '@nestjs/jwt'; import { ConfigService } from '@nestjs/config'; import { IAdminTokenPayload } from '../interfaces/IToken-payload'; import { PERMISSIONS_KEY } from '../../../common/decorators/permissions.decorator'; -import { PermissionsService } from 'src/modules/roles/providers/permissions.service'; +import { PermissionService } from 'src/modules/roles/providers/permissions.service'; export interface AdminAuthRequest extends Request { adminId: string; @@ -28,7 +28,7 @@ export class AdminAuthGuard implements CanActivate { private readonly jwtService: JwtService, @Inject(ConfigService) private readonly configService: ConfigService, - private readonly permissionsService: PermissionsService, + private readonly permissionsService: PermissionService, private readonly reflector: Reflector, ) { } diff --git a/src/modules/form-builder/controller/form-builder.controller.ts b/src/modules/form-builder/controller/form-builder.controller.ts index 3817446..75b9363 100644 --- a/src/modules/form-builder/controller/form-builder.controller.ts +++ b/src/modules/form-builder/controller/form-builder.controller.ts @@ -9,7 +9,7 @@ import { UpdateFieldDto } from '../dto/update-field.dto'; import { UpdateFieldOptionDto } from '../dto/update-field-option.dto'; import { FindFieldsGroupDto } from '../dto/find-field-group.dto'; import { Permissions } from 'src/common/decorators/permissions.decorator'; -import { Permission } from 'src/common/enums/permission.enum'; +import { PermissionEnum } from 'src/common/enums/permission.enum'; @Controller() @ApiBearerAuth() @@ -31,7 +31,7 @@ export class FormBuilderController { // ============= Admin ================= @Post('admin/entity/:id/field') @ApiOperation({ summary: 'Create field for entity' }) - @Permissions(Permission.MANAGE_FORM_BUILDER) + @Permissions(PermissionEnum.MANAGE_FORM_BUILDER) @UseGuards(AdminAuthGuard) createField(@Body() dto: CreateFieldDto, @Param('id') entityId: string) { return this.fieldService.create(+entityId, dto); @@ -61,7 +61,7 @@ export class FormBuilderController { @Patch('admin/entity/field/:id') @ApiOperation({ summary: 'Update field' }) @UseGuards(AdminAuthGuard) - @Permissions(Permission.MANAGE_FORM_BUILDER) + @Permissions(PermissionEnum.MANAGE_FORM_BUILDER) updateField(@Param('id') id: string, @Body() dto: UpdateFieldDto) { return this.fieldService.update(+id, dto); } @@ -69,7 +69,7 @@ export class FormBuilderController { @Delete('admin/entity/field/:id') @ApiOperation({ summary: 'Remove field' }) @UseGuards(AdminAuthGuard) - @Permissions(Permission.MANAGE_FORM_BUILDER) + @Permissions(PermissionEnum.MANAGE_FORM_BUILDER) removeField(@Param('id') id: string) { return this.fieldService.remove(+id); } @@ -79,7 +79,7 @@ export class FormBuilderController { @Post('admin/entity/field/:id/option') @ApiOperation({ summary: 'Create field Options ' }) @UseGuards(AdminAuthGuard) - @Permissions(Permission.MANAGE_FORM_BUILDER) + @Permissions(PermissionEnum.MANAGE_FORM_BUILDER) createFieldOption(@Body() dto: CreateFieldOptionDto, @Param('id') id: string) { return this.fieldOptionService.create(+id, dto); } @@ -101,7 +101,7 @@ export class FormBuilderController { @Patch('admin/entity/field/option/:id') @ApiOperation({ summary: 'Update field Option' }) @UseGuards(AdminAuthGuard) - @Permissions(Permission.MANAGE_FORM_BUILDER) + @Permissions(PermissionEnum.MANAGE_FORM_BUILDER) updateFieldOption(@Param('id') id: string, @Body() dto: UpdateFieldOptionDto) { return this.fieldOptionService.update(+id, dto); } @@ -109,7 +109,7 @@ export class FormBuilderController { @Delete('admin/entity/field/option/:id') @ApiOperation({ summary: 'Renopve field Option' }) @UseGuards(AdminAuthGuard) - @Permissions(Permission.MANAGE_FORM_BUILDER) + @Permissions(PermissionEnum.MANAGE_FORM_BUILDER) removeFieldOption(@Param('id') id: string) { return this.fieldOptionService.remove(+id); } diff --git a/src/modules/notification/controllers/notifications.controller.ts b/src/modules/notification/controllers/notifications.controller.ts index 41a1e24..598a79d 100644 --- a/src/modules/notification/controllers/notifications.controller.ts +++ b/src/modules/notification/controllers/notifications.controller.ts @@ -10,7 +10,7 @@ import { CreatePreferenceDto } from '../dto/create-preference.dto'; import { AdminId } from 'src/common/decorators/admin-id.decorator'; import { NotificationMessage } from 'src/common/enums/message.enum'; import { Permissions } from 'src/common/decorators/permissions.decorator'; -import { Permission } from 'src/common/enums/permission.enum'; +import { PermissionEnum } from 'src/common/enums/permission.enum'; @ApiTags('notifications') @Controller() diff --git a/src/modules/order/controllers/order.controller.ts b/src/modules/order/controllers/order.controller.ts index aa05775..237f519 100644 --- a/src/modules/order/controllers/order.controller.ts +++ b/src/modules/order/controllers/order.controller.ts @@ -15,6 +15,8 @@ import { UpdateOrderAsAdminDto } from '../dto/update-order.dto'; import { AdminAuthGuard } from 'src/modules/auth/guards/adminAuth.guard'; import { CreatePrintFormDto } from '../dto/create-print-form.dto'; import { FindOrderItemsDto } from '../dto/find-order-items.dto'; +import { Permissions } from 'src/common/decorators/permissions.decorator'; +import { PermissionEnum } from 'src/common/enums/permission.enum'; @ApiTags('orders') @ApiBearerAuth() @@ -94,6 +96,7 @@ export class OrderController { @Post('admin/orders') @UseGuards(AdminAuthGuard) + @Permissions(PermissionEnum.CREATE_ORDER) @ApiOperation({ summary: 'create order ' }) createOrderAsAdmin(@AdminId() adminId: string, @Body() body: CreateOrderAsAdminDto) { return this.orderService.createOrderAsAdmin(adminId, body); @@ -101,17 +104,18 @@ export class OrderController { @Get('admin/orders/request') @UseGuards(AdminAuthGuard) + @Permissions(PermissionEnum.VIEW_All_REQUEST_ORDERS) @ApiOperation({ summary: 'Get all order requests with pagination and filters' }) findOrderRequestAsAdmin(@Query() dto: FindOrdersDto) { return this.orderService.findOrderRequestsAsAdmin(dto); } - + // this route permission is handled inside service @Get('admin/orders/invoiced') @UseGuards(AdminAuthGuard) @ApiOperation({ summary: 'Get all invoiced orders with pagination and filters' }) - findInvoicedOrdersAsAdmin(@Query() dto: FindOrdersDto) { - return this.orderService.findOrderRequestsAsAdmin(dto); + findInvoicedOrdersAsAdmin(@Query() dto: FindOrdersDto, @AdminId() adminId: string) { + return this.orderService.findInvoicedOrdersAsAdmin(adminId, dto); } @Get('admin/orders/:id') @@ -123,6 +127,7 @@ export class OrderController { @Get('admin/orders/item/print') @UseGuards(AdminAuthGuard) + @Permissions(PermissionEnum.VIEW_All_ORDERS) @ApiOperation({ summary: 'get print orders' }) getPrintOrders(@Body() dto: FindOrderItemsDto) { return this.orderService.findPrintOrderItemsAsAdmin(dto); @@ -135,19 +140,6 @@ export class OrderController { return this.orderService.findOrderItemOrFailByItemId(+itemId); } - @Get('admin/orders/item/:id/print') - @UseGuards(AdminAuthGuard) - @ApiOperation({ summary: 'create order item print' }) - createOrderItemPrint(@Param('id') itemId: string) { - // return this.orderService.findOrderItemOrFailByItemId(+itemId); - } - // @Patch('admin/orders/:orderId') - // @UseGuards(AdminAuthGuard) - // @ApiOperation({ summary: 'Update Order ' }) - // updateOrder(@Param('orderId') orderId: string, @Body() dto: UpdateOrderAsAdminDto) { - // return this.orderService.updateOrderAsAdmin(orderId, dto); - // } - @Patch('admin/orders/:orderId') @UseGuards(AdminAuthGuard) @ApiOperation({ summary: 'Update Order ' }) @@ -157,6 +149,7 @@ export class OrderController { @Patch('admin/orders/:id/item/:itemId/print') @UseGuards(AdminAuthGuard) + @Permissions(PermissionEnum.CREATE_ORDER_PRINT) @ApiOperation({ summary: 'Create Print form for order item' }) createPrintForm(@Param('id') id: string, @Param('itemId') itemId: string, @Body() dto: CreatePrintFormDto) { return this.orderService.createPrintForm(id, +itemId, dto); diff --git a/src/modules/order/listeners/order.listeners.ts b/src/modules/order/listeners/order.listeners.ts index 6f45f34..7149a4d 100644 --- a/src/modules/order/listeners/order.listeners.ts +++ b/src/modules/order/listeners/order.listeners.ts @@ -2,7 +2,7 @@ import { Injectable, Logger } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; import { AdminRepository } from 'src/modules/admin/repositories/admin.repository'; import { OrderCreatedEvent, OrderStatusChangedEvent } from '../events/order.events'; -import { Permission } from 'src/common/enums/permission.enum'; +import { PermissionEnum } from 'src/common/enums/permission.enum'; import { NotifEvent } from 'src/modules/notification/interfaces/notification.interface'; import { NotificationService } from 'src/modules/notification/services/notification.service'; import { ConfigService } from '@nestjs/config'; diff --git a/src/modules/order/providers/order.service.ts b/src/modules/order/providers/order.service.ts index 257f90d..9db2582 100644 --- a/src/modules/order/providers/order.service.ts +++ b/src/modules/order/providers/order.service.ts @@ -30,8 +30,9 @@ import { AdminService } from 'src/modules/admin/providers/admin.service'; import { OrderItem } from '../entities/order-item.entity'; import { UpdateOrderAsAdminDto } from '../dto/update-order.dto'; import { CreatePrintFormDto } from '../dto/create-print-form.dto'; -import { Product } from 'src/modules/product/entities/product.entity'; import { FindOrderItemsDto } from '../dto/find-order-items.dto'; +import { PermissionService } from 'src/modules/roles/providers/permissions.service'; +import { PermissionEnum } from 'src/common/enums/permission.enum'; @Injectable() @@ -51,6 +52,7 @@ export class OrderService { private readonly eventEmitter: EventEmitter2, private readonly adminRepository: AdminRepository, private readonly paymentRepository: PaymentRepository, + private readonly permissionService: PermissionService, ) { } async createOrderAsAdmin(adminId: string, dto: CreateOrderAsAdminDto) { @@ -83,6 +85,7 @@ export class OrderService { // return updateOrder } + //TODO : clean async updateOrderAsAdmin2(orderId: string, dto: UpdateOrderAsAdminDto) { const order = await this.findOrderOrFail(orderId) @@ -291,8 +294,23 @@ export class OrderService { return orders } - async findInvoicedOrdersAsAdmin(dto: FindOrdersDto) { - const orders = await this.orderRepository.findAllPaginated({ ...dto, isInvoiced: true, }) + async findInvoicedOrdersAsAdmin(adminId: string, dto: FindOrdersDto) { + const canSeeAll = await this.adminService.hasPermission(adminId, PermissionEnum.VIEW_All_INVOICED_ORDERS) + + let canSeeAsigned = false + + if (!canSeeAll) { + canSeeAsigned = await this.adminService.hasPermission(adminId, PermissionEnum.VIEW_MY_ASSIGNED_INVOICED_REQUESTS) + } + + if (!canSeeAsigned && !canSeeAll) { + throw new BadRequestException("You dont have Permission") + } + + let designerId = canSeeAll ? undefined : adminId + + const orders = await this.orderRepository.findAllPaginated({ ...dto, isInvoiced: true, designerId }) + return orders } diff --git a/src/modules/order/repositories/order.repository.ts b/src/modules/order/repositories/order.repository.ts index 93ec9bf..c72fef3 100644 --- a/src/modules/order/repositories/order.repository.ts +++ b/src/modules/order/repositories/order.repository.ts @@ -10,6 +10,7 @@ import { FindOrdersDto } from '../dto/find-orders.dto'; class FindOrdersOpts extends FindOrdersDto { userId?: string; isInvoiced?: boolean; + designerId?: string }; @Injectable() @@ -29,7 +30,8 @@ export class OrderRepository extends EntityRepository { userId, from, to, - isInvoiced + isInvoiced, + designerId } = opts; const offset = (page - 1) * limit; @@ -60,11 +62,14 @@ export class OrderRepository extends EntityRepository { if (isInvoiced != undefined) { if (isInvoiced == true) { where.invoicedAt = { $not: null } - }else{ + } else { where.invoicedAt = null } } + if (designerId) { + where.items = { $some: { designer: { id: designerId } } } + } // Filter by date range if (from || to) { where.createdAt = {}; diff --git a/src/modules/payment/controllers/payment.controller.ts b/src/modules/payment/controllers/payment.controller.ts index 0121c68..ec68c85 100644 --- a/src/modules/payment/controllers/payment.controller.ts +++ b/src/modules/payment/controllers/payment.controller.ts @@ -18,7 +18,7 @@ import { FindPaymentsDto } from '../dto/find-payments.dto'; import { AdminAuthGuard } from 'src/modules/auth/guards/adminAuth.guard'; import { AdminId } from 'src/common/decorators/admin-id.decorator'; import { Permissions } from 'src/common/decorators/permissions.decorator'; -import { Permission } from 'src/common/enums/permission.enum'; +import { PermissionEnum } from 'src/common/enums/permission.enum'; @ApiTags('payment') @ApiBearerAuth() @@ -54,7 +54,7 @@ export class PaymentController { @Post('admin/payments/order/:id/pay') @UseGuards(AdminAuthGuard) - @Permissions(Permission.MANAGE_PAYMENTS) + @Permissions(PermissionEnum.MANAGE_PAYMENTS) @ApiOperation({ summary: 'Pay for an order as Admin' }) payOrderAsAdmin(@Param('orderId') orderId: string, @AdminId() adminId: string, @Body() dto: PayOrderDto) { return this.paymentService.payOrder(orderId, dto, adminId); @@ -62,7 +62,7 @@ export class PaymentController { @Post('admin/payments/online/:token/verify') @UseGuards(AdminAuthGuard) - @Permissions(Permission.MANAGE_PAYMENTS) + @Permissions(PermissionEnum.MANAGE_PAYMENTS) @ApiOperation({ summary: 'Verify online payment as admin' }) verifyOnlinePaymentAsAdmin(@Param('paymentId') token: string) { return this.paymentService.verifyOnlinePayment(token); @@ -70,7 +70,7 @@ export class PaymentController { @Post('admin/payments/:paymentId/cash/verify') @UseGuards(AdminAuthGuard) - @Permissions(Permission.MANAGE_PAYMENTS) + @Permissions(PermissionEnum.MANAGE_PAYMENTS) @ApiOperation({ summary: 'Verify cash payment' }) confirmPayment(@Param('paymentId') paymentId: string) { return this.paymentService.confirmCashPayment(paymentId); @@ -78,7 +78,7 @@ export class PaymentController { @Delete('admin/payments/:paymentId/cash/deny') @UseGuards(AdminAuthGuard) - @Permissions(Permission.MANAGE_PAYMENTS) + @Permissions(PermissionEnum.MANAGE_PAYMENTS) @ApiOperation({ summary: 'Deny cash payment' }) denyPayment(@Param('paymentId') paymentId: string) { return this.paymentService.denyCashPayment(paymentId); @@ -87,7 +87,7 @@ export class PaymentController { @Get('admin/payments') @UseGuards(AdminAuthGuard) - @Permissions(Permission.MANAGE_PAYMENTS) + @Permissions(PermissionEnum.MANAGE_PAYMENTS) @ApiOperation({ summary: 'get all payments as admin' }) findAllPayments(@Body() dto: FindPaymentsDto) { return this.paymentService.findAll(dto); diff --git a/src/modules/payment/listeners/payment.listeners.ts b/src/modules/payment/listeners/payment.listeners.ts index c5288d2..39f628f 100644 --- a/src/modules/payment/listeners/payment.listeners.ts +++ b/src/modules/payment/listeners/payment.listeners.ts @@ -2,7 +2,7 @@ import { Injectable, Logger } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; import { AdminRepository } from 'src/modules/admin/repositories/admin.repository'; import { onlinePaymentSucceedEvent, paymentSucceedEvent } from '../events/payment.events'; -import { Permission } from 'src/common/enums/permission.enum'; +import { PermissionEnum } from 'src/common/enums/permission.enum'; import { NotifEvent } from 'src/modules/notification/interfaces/notification.interface'; import { NotificationService } from 'src/modules/notification/services/notification.service'; import { ConfigService } from '@nestjs/config'; diff --git a/src/modules/print/controller/print.controller.ts b/src/modules/print/controller/print.controller.ts index 8035101..f88fa08 100644 --- a/src/modules/print/controller/print.controller.ts +++ b/src/modules/print/controller/print.controller.ts @@ -5,7 +5,7 @@ import { ApiBearerAuth, ApiOperation } from '@nestjs/swagger'; import { AdminAuthGuard } from '../../auth/guards/adminAuth.guard'; import { UpdateSectionDto } from '../dto/update-section.dto'; import { Permissions } from 'src/common/decorators/permissions.decorator'; -import { Permission } from 'src/common/enums/permission.enum'; +import { PermissionEnum } from 'src/common/enums/permission.enum'; @Controller('admin') @UseGuards(AdminAuthGuard) @@ -18,7 +18,7 @@ export class PrintController { /*================================ Section ========================== */ @Post('section') - @Permissions(Permission.MANAGE_PRINT) + @Permissions(PermissionEnum.MANAGE_PRINT) @ApiOperation({ summary: 'Create section' }) create(@Body() dto: CreateSectionDto) { return this.printService.create(dto); @@ -37,14 +37,14 @@ export class PrintController { } @Patch('section/:id') - @Permissions(Permission.MANAGE_PRINT) + @Permissions(PermissionEnum.MANAGE_PRINT) @ApiOperation({ summary: 'Update section' }) update(@Param('id') id: string, @Body() dto: UpdateSectionDto) { return this.printService.update(+id, dto); } @Delete('section/:id') - @Permissions(Permission.MANAGE_PRINT) + @Permissions(PermissionEnum.MANAGE_PRINT) @ApiOperation({ summary: 'Remove section' }) remove(@Param('id') id: string) { return this.printService.remove(+id); diff --git a/src/modules/product/controllers/product.controller.ts b/src/modules/product/controllers/product.controller.ts index 81529d3..bc9b495 100644 --- a/src/modules/product/controllers/product.controller.ts +++ b/src/modules/product/controllers/product.controller.ts @@ -11,7 +11,7 @@ import { ApiParam, ApiBearerAuth, } from '@nestjs/swagger'; -import { Permission } from 'src/common/enums/permission.enum'; +import { PermissionEnum } from 'src/common/enums/permission.enum'; import { Permissions } from 'src/common/decorators/permissions.decorator'; import { CreateCategoryDto } from '../dto/create-category.dto'; import { CategoryService } from '../providers/category.service'; @@ -35,7 +35,7 @@ export class ProductController { @Post('admin/category') @UseGuards(AdminAuthGuard) - @Permissions(Permission.MANAGE_CATEGORIES) + @Permissions(PermissionEnum.MANAGE_CATEGORIES) @ApiOperation({ summary: 'Create a new category' }) createCategory(@Body() createproductDto: CreateCategoryDto) { return this.categoryService.create(createproductDto); @@ -66,7 +66,7 @@ export class ProductController { @Patch('admin/category/:id') @UseGuards(AdminAuthGuard) - @Permissions(Permission.MANAGE_CATEGORIES) + @Permissions(PermissionEnum.MANAGE_CATEGORIES) @ApiOperation({ summary: 'Update a category' }) @ApiParam({ name: 'id', required: true }) @ApiBody({ type: UpdateCategoryDto }) @@ -76,7 +76,7 @@ export class ProductController { @Delete('admin/category/:id') @UseGuards(AdminAuthGuard) - @Permissions(Permission.MANAGE_CATEGORIES) + @Permissions(PermissionEnum.MANAGE_CATEGORIES) @ApiOperation({ summary: 'Delete (soft) a category' }) @ApiParam({ name: 'id', required: true }) removeCategory(@Param('id') id: string,) { @@ -95,7 +95,7 @@ export class ProductController { @Post('admin/product') @UseGuards(AdminAuthGuard) - @Permissions(Permission.MANAGE_PRODUCTS) + @Permissions(PermissionEnum.MANAGE_PRODUCTS) @ApiOperation({ summary: 'Create a new product' }) @ApiBody({ type: CreateproductDto }) create(@Body() createproductDto: CreateproductDto) { @@ -104,7 +104,7 @@ export class ProductController { @Get('admin/products') @UseGuards(AdminAuthGuard) - @Permissions(Permission.MANAGE_PRODUCTS) + @Permissions(PermissionEnum.MANAGE_PRODUCTS) @ApiOperation({ summary: 'Get a paginated list of products' }) @ApiQuery({ name: 'page', required: false, type: Number }) @ApiQuery({ name: 'limit', required: false, type: Number }) @@ -120,7 +120,7 @@ export class ProductController { @Get('admin/products/:id') @UseGuards(AdminAuthGuard) - @Permissions(Permission.MANAGE_PRODUCTS) + @Permissions(PermissionEnum.MANAGE_PRODUCTS) @ApiOperation({ summary: 'Get a product by id' }) @ApiParam({ name: 'id', required: true }) findById(@Param('id') id: string,) { @@ -129,7 +129,7 @@ export class ProductController { @Patch('admin/products/:id') @UseGuards(AdminAuthGuard) - @Permissions(Permission.MANAGE_PRODUCTS) + @Permissions(PermissionEnum.MANAGE_PRODUCTS) @ApiOperation({ summary: 'Update a product' }) @ApiParam({ name: 'id', required: true }) update(@Param('id') id: string, @Body() updateproductDto: UpdateproductDto) { @@ -138,7 +138,7 @@ export class ProductController { @Delete('admin/products/:id') @UseGuards(AdminAuthGuard) - @Permissions(Permission.MANAGE_PRODUCTS) + @Permissions(PermissionEnum.MANAGE_PRODUCTS) @ApiOperation({ summary: 'Delete (soft) a product' }) @ApiParam({ name: 'id', required: true }) remove(@Param('id') id: string,) { diff --git a/src/modules/roles/controllers/roles.controller.ts b/src/modules/roles/controllers/roles.controller.ts index c4c104d..626d4c5 100644 --- a/src/modules/roles/controllers/roles.controller.ts +++ b/src/modules/roles/controllers/roles.controller.ts @@ -1,13 +1,13 @@ import { Controller, Get, Post, Body, Param, Patch, Delete, UseGuards } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiBody, ApiBearerAuth } from '@nestjs/swagger'; import { RolesService } from '../providers/roles.service'; -import { PermissionsService } from '../providers/permissions.service'; +import { PermissionService } from '../providers/permissions.service'; import { CreateRoleDto } from '../dto/create-role.dto'; import { UpdateRoleDto } from '../dto/update-role.dto'; import { AdminAuthGuard } from 'src/modules/auth/guards/adminAuth.guard'; import { Permissions } from 'src/common/decorators/permissions.decorator'; import { AdminId } from 'src/common/decorators/admin-id.decorator'; -import { Permission } from 'src/common/enums/permission.enum'; +import { PermissionEnum } from 'src/common/enums/permission.enum'; @@ -18,39 +18,39 @@ import { Permission } from 'src/common/enums/permission.enum'; export class RolesController { constructor( private readonly roleService: RolesService, - private readonly permissionService: PermissionsService, + private readonly permissionService: PermissionService, ) { } @Post('admin/role') - @Permissions(Permission.MANAGE_ROLES) + @Permissions(PermissionEnum.MANAGE_ROLES) @ApiOperation({ summary: 'Create a new role' }) create(@Body() dto: CreateRoleDto,) { return this.roleService.create(dto); } @Get('admin/roles') - @Permissions(Permission.MANAGE_ROLES) + @Permissions(PermissionEnum.MANAGE_ROLES) @ApiOperation({ summary: 'Get all through restaurant roles with pagination and filters' }) findAll() { return this.roleService.findAll(); } @Get('admin/roles/permissions') - @Permissions(Permission.MANAGE_ROLES) + @Permissions(PermissionEnum.MANAGE_ROLES) @ApiOperation({ summary: 'Get all permissions that the admin has' }) async findAllPermissions(@AdminId() adminId: string,) { return this.permissionService.getAdminPermissions(adminId); } @Get('admin/roles/:id') - @Permissions(Permission.MANAGE_ROLES) + @Permissions(PermissionEnum.MANAGE_ROLES) @ApiOperation({ summary: 'Get a specific role by ID' }) findOne(@Param('id') id: string,) { return this.roleService.findOne(id); } @Patch('admin/roles/:id') - @Permissions(Permission.MANAGE_ROLES) + @Permissions(PermissionEnum.MANAGE_ROLES) @ApiOperation({ summary: 'Update a role' }) @ApiBody({ type: UpdateRoleDto }) update(@Param('id') id: string, @Body() dto: UpdateRoleDto,) { @@ -58,7 +58,7 @@ export class RolesController { } @Delete('admin/roles/:id') - @Permissions(Permission.MANAGE_ROLES) + @Permissions(PermissionEnum.MANAGE_ROLES) @ApiOperation({ summary: 'Delete a role' }) remove(@Param('id') id: string,) { return this.roleService.remove(id); diff --git a/src/modules/roles/entities/permission.entity.ts b/src/modules/roles/entities/permission.entity.ts index c10d895..a6d69f5 100755 --- a/src/modules/roles/entities/permission.entity.ts +++ b/src/modules/roles/entities/permission.entity.ts @@ -1,15 +1,16 @@ -import { Entity, Property, Unique, ManyToMany, Collection, PrimaryKey } from '@mikro-orm/core'; +import { Entity, Property, Unique, ManyToMany, Collection, PrimaryKey, Enum } from '@mikro-orm/core'; import { BaseEntity } from '../../../common/entities/base.entity'; import { Role } from './role.entity'; import { ulid } from 'ulid'; +import { PermissionEnum } from 'src/common/enums/permission.enum'; @Entity({ tableName: 'permissions' }) export class Permission extends BaseEntity { @PrimaryKey({ type: 'string', columnType: 'char(26)' }) id: string = ulid() - @Property({ unique: true }) - name!: string; + @Enum(() => PermissionEnum) + name!: PermissionEnum; @Property() title!: string; diff --git a/src/modules/roles/entities/role.entity.ts b/src/modules/roles/entities/role.entity.ts index 26bc617..1fa032c 100755 --- a/src/modules/roles/entities/role.entity.ts +++ b/src/modules/roles/entities/role.entity.ts @@ -1,11 +1,13 @@ -import { Collection, Entity, ManyToMany, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'; -import { BaseEntity } from '../../../common/entities/base.entity'; +import { Collection, Entity, ManyToMany, OneToMany, OptionalProps, PrimaryKey, Property } from '@mikro-orm/core'; import { Permission } from './permission.entity'; import { RolePermission } from './rolePermission.entity'; import { ulid } from 'ulid'; +import { Admin } from 'src/modules/admin/entities/admin.entity'; @Entity({ tableName: 'roles' }) -export class Role extends BaseEntity { +export class Role { + [OptionalProps]?: 'createdAt' | 'deletedAt' | 'admins'; + @PrimaryKey({ type: 'string', columnType: 'char(26)' }) id: string = ulid() @@ -21,5 +23,13 @@ export class Role extends BaseEntity { @ManyToMany({ entity: () => Permission, pivotEntity: () => RolePermission, inversedBy: p => p.roles }) permissions = new Collection(this); + @OneToMany(() => Admin, (admin) => admin.role) + admins: Admin + + @Property({ defaultRaw: 'now()', columnType: 'timestamptz' }) + createdAt: Date = new Date(); + + @Property({ nullable: true, columnType: 'timestamptz' }) + deletedAt?: Date; } diff --git a/src/modules/roles/providers/permissions.service.ts b/src/modules/roles/providers/permissions.service.ts index 5be75cb..340f062 100644 --- a/src/modules/roles/providers/permissions.service.ts +++ b/src/modules/roles/providers/permissions.service.ts @@ -1,12 +1,13 @@ -import { Injectable } from '@nestjs/common'; +import { BadRequestException, Injectable } from '@nestjs/common'; import { InjectRepository } from '@mikro-orm/nestjs'; import { EntityRepository } from '@mikro-orm/core'; import { Permission } from '../entities/permission.entity'; import { AdminRepository } from 'src/modules/admin/repositories/admin.repository'; +import { PermissionEnum } from 'src/common/enums/permission.enum'; @Injectable() -export class PermissionsService { +export class PermissionService { constructor( @InjectRepository(Permission) @@ -27,7 +28,11 @@ export class PermissionsService { { populate: ['role', 'role.permissions'] }, ); - if (!admin || !admin.role) { + if (!admin) { + throw new BadRequestException("Admin not found") + } + + if (!admin.role) { return []; } @@ -36,4 +41,12 @@ export class PermissionsService { return permissions } + + async getAdminPermissionsName(adminId: string) { + const permissions = await this.getAdminPermissions(adminId) + return permissions.map(p => p.name) + } + + + } diff --git a/src/modules/roles/roles.module.ts b/src/modules/roles/roles.module.ts index 1a78bd2..f9e500e 100644 --- a/src/modules/roles/roles.module.ts +++ b/src/modules/roles/roles.module.ts @@ -2,7 +2,7 @@ import { Global, Module } from '@nestjs/common'; import { MikroOrmModule } from '@mikro-orm/nestjs'; import { RolesService } from './providers/roles.service'; import { RolesController } from './controllers/roles.controller'; -import { PermissionsService } from './providers/permissions.service'; +import { PermissionService } from './providers/permissions.service'; import { Role } from './entities/role.entity'; import { Permission } from './entities/permission.entity'; import { RolePermission } from './entities/rolePermission.entity'; @@ -15,7 +15,7 @@ import { RoleRepository } from './respository/role.repository'; @Module({ imports: [MikroOrmModule.forFeature([Role, Permission, RolePermission]), JwtModule, UtilsModule, AdminModule], controllers: [RolesController], - providers: [RolesService, PermissionsService, RoleRepository], - exports: [RolesService, PermissionsService, RoleRepository], + providers: [RolesService, PermissionService, RoleRepository], + exports: [RolesService, PermissionService, RoleRepository], }) export class RolesModule { } diff --git a/src/seeders/data/permissions.data.ts b/src/seeders/data/permissions.data.ts index 286f078..8472a76 100644 --- a/src/seeders/data/permissions.data.ts +++ b/src/seeders/data/permissions.data.ts @@ -1,9 +1,9 @@ -import { Permission, PermissionTitles } from '../../common/enums/permission.enum'; +import { PermissionEnum, PermissionTitles } from '../../common/enums/permission.enum'; export const getPermissionsData = () => { - return Object.values(Permission).map(name => ({ + return Object.values(PermissionEnum).map(name => ({ name, title: PermissionTitles[name], })); diff --git a/src/seeders/data/roles.data.ts b/src/seeders/data/roles.data.ts index 03d558c..4e43711 100644 --- a/src/seeders/data/roles.data.ts +++ b/src/seeders/data/roles.data.ts @@ -1,10 +1,10 @@ -import { Permission } from '../../common/enums/permission.enum'; +import { PermissionEnum } from '../../common/enums/permission.enum'; export interface RoleConfig { name: string; title: string; isSystem: boolean; - permissionFilter: (permissionName: Permission) => boolean; + permissionFilter: (permissionName: PermissionEnum) => boolean; } export const rolesData: RoleConfig[] = [ @@ -12,7 +12,7 @@ export const rolesData: RoleConfig[] = [ name: 'admin', title: 'مدیرکل', isSystem: true, - permissionFilter: (name: Permission) => true + permissionFilter: (name: PermissionEnum) => true }, ]; diff --git a/src/seeders/permissions.seeder.ts b/src/seeders/permissions.seeder.ts index 5db378d..0cbc1ea 100644 --- a/src/seeders/permissions.seeder.ts +++ b/src/seeders/permissions.seeder.ts @@ -1,16 +1,16 @@ import type { EntityManager } from '@mikro-orm/core'; -import { Permission as PermissionEntity } from '../modules/roles/entities/permission.entity'; +import { Permission } from '../modules/roles/entities/permission.entity'; import { getPermissionsData } from './data/permissions.data'; export class PermissionsSeeder { - async run(em: EntityManager): Promise { + async run(em: EntityManager): Promise { const permissions = getPermissionsData(); - const createdPermissions: PermissionEntity[] = []; + const createdPermissions: Permission[] = []; for (const permData of permissions) { - let permission = await em.findOne(PermissionEntity, { name: permData.name }); + let permission = await em.findOne(Permission, { name: permData.name }); if (!permission) { - permission = em.create(PermissionEntity, permData); + permission = em.create(Permission, permData); em.persist(permission); } else { // Update existing permission's title if it changed diff --git a/src/seeders/roles.seeder.ts b/src/seeders/roles.seeder.ts index ba43b54..b5c7f94 100644 --- a/src/seeders/roles.seeder.ts +++ b/src/seeders/roles.seeder.ts @@ -1,11 +1,11 @@ import type { EntityManager } from '@mikro-orm/core'; import { Role } from '../modules/roles/entities/role.entity'; -import type { Permission } from '../common/enums/permission.enum'; -import type { Permission as PermissionEntity } from '../modules/roles/entities/permission.entity'; +import type { PermissionEnum } from '../common/enums/permission.enum'; +import type {Permission } from '../modules/roles/entities/permission.entity'; import { rolesData } from './data/roles.data'; export class RolesSeeder { - async run(em: EntityManager, permissions: PermissionEntity[]): Promise> { + async run(em: EntityManager, permissions: Permission[]): Promise> { const rolesMap = new Map(); for (const roleConfig of rolesData) { @@ -13,7 +13,7 @@ export class RolesSeeder { if (!role) { role = em.create(Role, { name: roleConfig.name, - title:'', + title: '', isSystem: true, }); @@ -21,7 +21,7 @@ export class RolesSeeder { // TypeScript knows role is not null here because we just created it const newRole = role; // Use the permission filter for all roles - const filteredPermissions = permissions.filter(p => roleConfig.permissionFilter(p.name as Permission)); + const filteredPermissions = permissions.filter(p => roleConfig.permissionFilter(p.name as PermissionEnum)); filteredPermissions.forEach(p => newRole.permissions.add(p)); em.persist(newRole);