canina/backend/src/admin/admin.controller.ts
parsaaghayi dc88677169
Some checks failed
Deploy Canina / deploy (push) Waiting to run
E2E Playwright Tests / Run Full E2E & Security Suites (push) Failing after 11s
fix(security): resolve all critical, high, and medium security vulnerabilities
2026-09-23 22:05:12 +03:30

358 lines
12 KiB
TypeScript

import {
Controller,
Get,
Post,
Put,
Delete,
Body,
Param,
Query,
UseGuards,
BadRequestException,
} from '@nestjs/common';
import { AdminService, CouponInput } from './admin.service';
import { ProductDto } from './dto/product.dto';
import {
UpdatePricingSettingsDto,
ApplyGlobalMarginsDto,
BulkPriceAdjustmentDto,
} from './dto/pricing.dto';
import { AdminQueryDto } from './dto/admin-query.dto';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import {
ApiTags,
ApiBearerAuth,
ApiOperation,
ApiQuery,
} from '@nestjs/swagger';
import { CreateUserDto, UpdateUserDto } from './dto/user.dto';
import { SettingsService } from '../settings/settings.service';
import { RolesGuard } from '../common/guards/roles.guard';
import { Roles } from '../common/decorators/roles.decorator';
@ApiTags('Admin - مدیریت سیستم')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('Admin', 'SUPER_ADMIN')
@Controller('admin')
export class AdminController {
constructor(
private readonly adminService: AdminService,
private readonly settingsService: SettingsService,
) {}
@Get('dashboard/stats')
@ApiOperation({ summary: 'داشبورد مدیریت و آمار کلیدی سیستم' })
async getDashboardStats() {
const data = await this.adminService.getDashboardStats();
return { success: true, data };
}
@Get('users')
@ApiOperation({ summary: 'لیست کاربران سیستم (با صفحه‌بندی)' })
@ApiQuery({ name: 'page', required: false, description: 'شماره صفحه' })
@ApiQuery({ name: 'limit', required: false, description: 'تعداد آیتم‌ها' })
@ApiQuery({ name: 'search', required: false, description: 'جستجو' })
async getUsers(@Query() query: AdminQueryDto) {
const result = await this.adminService.getUsers(query);
return { success: true, ...result };
}
@Post('users')
@ApiOperation({ summary: 'ایجاد کاربر جدید توسط ادمین' })
async createUser(@Body() dto: CreateUserDto) {
const user = await this.adminService.createUser(dto);
return {
success: true,
message: 'کاربر جدید با موفقیت ایجاد شد',
data: user,
};
}
@Get('users/:id')
@ApiOperation({ summary: 'جزئیات کاربر' })
async getUserDetails(@Param('id') id: string) {
const data = await this.adminService.getUserDetails(id);
return { success: true, data };
}
@Put('users/:id')
@ApiOperation({ summary: 'ویرایش مشخصات کامل کاربر' })
async updateUser(@Param('id') id: string, @Body() dto: UpdateUserDto) {
const user = await this.adminService.updateUser(id, dto);
return {
success: true,
message: 'اطلاعات کاربر با موفقیت ویرایش شد',
data: user,
};
}
@Delete('users/:id')
@ApiOperation({ summary: 'حذف کاربر و داده‌های مرتبط' })
async deleteUser(@Param('id') id: string) {
await this.adminService.deleteUser(id);
return {
success: true,
message: 'کاربر با موفقیت از سیستم حذف شد',
};
}
@Put('users/:id/role')
@ApiOperation({ summary: 'تغییر نقش کاربر' })
async updateUserRole(@Param('id') id: string, @Body('role') role: string) {
const user = await this.adminService.updateUserRole(id, role);
return { success: true, data: user };
}
@Post('users/:id/wallet-adjust')
@ApiOperation({ summary: 'شارژ یا کسر مستقیم کیف پول کاربر توسط ادمین' })
async adjustWallet(
@Param('id') id: string,
@Body('amount') amount: number,
@Body('type') type: 'deposit' | 'withdrawal' | 'refund',
@Body('description') description?: string,
) {
const numAmount = Number(amount);
if (!numAmount || isNaN(numAmount) || numAmount <= 0) {
throw new BadRequestException('مبلغ باید یک عدد مثبت باشد');
}
if (numAmount > 100_000_000_000) {
throw new BadRequestException('مبلغ بیش از حد مجاز است');
}
if (!['deposit', 'withdrawal', 'refund'].includes(type)) {
throw new BadRequestException('نوع تراکنش معتبر نیست');
}
const result = await this.adminService.adjustUserWallet(
id,
numAmount,
type,
description,
);
return {
success: true,
message: 'موجود کیف پول با موفقیت بروزرسانی شد',
data: result,
};
}
@Get('products')
@ApiOperation({ summary: 'لیست محصولات (مدیریت)' })
@ApiQuery({ name: 'page', required: false, description: 'شماره صفحه' })
@ApiQuery({ name: 'limit', required: false, description: 'تعداد آیتم‌ها' })
@ApiQuery({ name: 'search', required: false, description: 'جستجو' })
async getProducts(@Query() query: AdminQueryDto) {
const result = await this.adminService.getProducts(query);
return { success: true, ...result };
}
@Post('products')
@ApiOperation({ summary: 'ایجاد محصول جدید' })
async createProduct(@Body() data: ProductDto) {
const product = await this.adminService.createProduct(data);
return { success: true, data: product };
}
@Put('products/:id')
@ApiOperation({ summary: 'ویرایش محصول' })
async updateProduct(@Param('id') id: string, @Body() data: ProductDto) {
const product = await this.adminService.updateProduct(id, data);
return {
success: true,
data: product,
};
}
@Delete('products/:id')
@ApiOperation({ summary: 'حذف محصول' })
async deleteProduct(@Param('id') id: string) {
await this.adminService.deleteProduct(id);
return { success: true };
}
@Get('pricing/settings')
@ApiOperation({ summary: 'دریافت تنظیمات هوشمند قیمت‌گذاری و گرد کردن' })
async getPricingSettings() {
const data = await this.adminService.getPricingSettings();
return { success: true, data };
}
@Put('pricing/settings')
@ApiOperation({ summary: 'بروزرسانی تنظیمات هوشمند قیمت‌گذاری و گرد کردن' })
async updatePricingSettings(@Body() dto: UpdatePricingSettingsDto) {
return this.adminService.updatePricingSettings(dto);
}
@Post('pricing/apply-global-margins')
@ApiOperation({ summary: 'اعمال سراسری درصد سود تک و عمده بر روی محصولات' })
async applyGlobalMargins(@Body() dto: ApplyGlobalMarginsDto) {
return this.adminService.applyGlobalMargins(dto);
}
@Post('pricing/bulk-adjust')
@ApiOperation({
summary: 'تغییرات گروهی قیمت (درصدی یا مبلغ ثابت) بر روی محصولات',
})
async bulkPriceAdjustment(@Body() dto: BulkPriceAdjustmentDto) {
return this.adminService.bulkPriceAdjustment(dto);
}
@Get('orders')
@ApiOperation({ summary: 'لیست سفارش‌ها (مدیریت)' })
@ApiQuery({ name: 'page', required: false, description: 'شماره صفحه' })
@ApiQuery({ name: 'limit', required: false, description: 'تعداد آیتم‌ها' })
@ApiQuery({ name: 'status', required: false, description: 'فیلتر وضعیت' })
async getOrders(@Query() query: AdminQueryDto) {
const result = await this.adminService.getOrders(query);
return { success: true, ...result };
}
@Get('orders/:id')
@ApiOperation({ summary: 'دریافت جزئیات کامل یک سفارش با شناسه' })
async getOrderById(@Param('id') id: string) {
const order = await this.adminService.getOrderById(id);
return { success: true, data: order };
}
@Put('orders/:id/status')
@ApiOperation({ summary: 'بروزرسانی وضعیت سفارش' })
async updateOrderStatus(
@Param('id') id: string,
@Body('status') status: string,
@Body('trackingCode') trackingCode?: string,
@Body('trackingNumber') trackingNumber?: string,
) {
const finalTracking =
trackingNumber !== undefined ? trackingNumber : trackingCode;
const order = await this.adminService.updateOrderStatus(
id,
status,
finalTracking,
);
return { success: true, data: order };
}
@Post('orders/:id/refund-wallet')
@ApiOperation({ summary: 'استرداد مستقیم مبلغ سفارش به کیف پول کاربر' })
async refundOrderToWallet(
@Param('id') id: string,
@Body('amount') amount?: number,
@Body('reason') reason?: string,
) {
const result = await this.adminService.refundOrderToWallet(
id,
amount ? Number(amount) : undefined,
reason,
);
return result;
}
@Get('coupons')
@ApiOperation({ summary: 'لیست کد تخفیف‌ها' })
@ApiQuery({ name: 'page', required: false, description: 'شماره صفحه' })
@ApiQuery({ name: 'limit', required: false, description: 'تعداد آیتم‌ها' })
@ApiQuery({ name: 'search', required: false, description: 'جستجو' })
async getCoupons(@Query() query: AdminQueryDto) {
const coupons = await this.adminService.getCoupons(query);
return { success: true, ...coupons };
}
@Post('coupons')
@ApiOperation({ summary: 'ایجاد کد تخفیف جدید' })
async createCoupon(@Body() data: CouponInput) {
const coupon = await this.adminService.createCoupon(data);
return { success: true, data: coupon };
}
@Put('coupons/:id')
@ApiOperation({ summary: 'ویرایش کد تخفیف' })
async updateCoupon(@Param('id') id: string, @Body() data: CouponInput) {
const coupon = await this.adminService.updateCoupon(id, data);
return { success: true, data: coupon };
}
@Put('coupons/:id/toggle')
@ApiOperation({ summary: 'فعال/غیرفعال کردن کد تخفیف' })
async toggleCoupon(
@Param('id') id: string,
@Body('isActive') isActive: boolean,
) {
const coupon = await this.adminService.toggleCoupon(id, isActive);
return { success: true, data: coupon };
}
@Delete('coupons/:id')
@ApiOperation({ summary: 'حذف کد تخفیف' })
async deleteCoupon(@Param('id') id: string) {
await this.adminService.deleteCoupon(id);
return { success: true };
}
@Get('doctors')
@ApiOperation({ summary: 'لیست پزشکان و متخصصین' })
async getDoctors() {
const data = await this.adminService.getDoctors();
return { success: true, data };
}
@Post('doctors')
@ApiOperation({ summary: 'افزودن پزشک جدید' })
async createDoctor(
@Body()
body: {
name: string;
title: string;
avatarUrl?: string;
bio?: string;
clinic?: string;
},
) {
const data = await this.adminService.createDoctor(body);
return { success: true, data };
}
@Put('doctors/:id')
@ApiOperation({ summary: 'ویرایش پزشک' })
async updateDoctor(
@Param('id') id: string,
@Body()
body: {
name?: string;
title?: string;
avatarUrl?: string;
bio?: string;
clinic?: string;
},
) {
const data = await this.adminService.updateDoctor(id, body);
return { success: true, data };
}
@Delete('doctors/:id')
@ApiOperation({ summary: 'حذف پزشک' })
async deleteDoctor(@Param('id') id: string) {
await this.adminService.deleteDoctor(id);
return { success: true };
}
@Get('settings')
@ApiOperation({ summary: 'دریافت تنظیمات کلی سیستم' })
async getSettings() {
const data = await this.settingsService.getUiTexts();
const map: Record<string, string> = {};
data.forEach((item) => {
map[item.key] = item.value;
});
return { success: true, data: map };
}
@Put('settings')
@ApiOperation({ summary: 'بروزرسانی تنظیمات کلی سیستم' })
async updateSettings(@Body() body: Record<string, string>) {
await this.settingsService.updateBulkUiTexts(body);
return { success: true, data: body };
}
}