import { BadRequestException, Body, Controller, Delete, Get, Param, Patch, Post, Query, Res, StreamableFile, UploadedFile, UseGuards, UseInterceptors, } from '@nestjs/common'; import { FileInterceptor } from '@nestjs/platform-express'; import { memoryStorage } from 'multer'; import type { Response } from 'express'; import { JwtAuthGuard } from '../auth/jwt-auth.guard'; import { RequirePermission, SectionPermissionGuard } from '../auth/section-permission.guard'; import { CurrentUser } from '../auth/current-user.decorator'; import type { Actor } from '../common/record-scope'; import { OrgModuleGuard } from '../billing/org-module.guard'; import { RequireOrgModule } from '../billing/org-module.decorator'; import { BirthdaySmsDto, BulkDeletePeopleDto, CreatePersonDto, ListQueryDto, UpdatePersonDto } from './dto'; import { PeopleService } from './people.service'; import { ContactsExcelService } from './contacts-excel.service'; import { brand } from '@mento/shared'; const excelUpload = FileInterceptor('file', { storage: memoryStorage(), limits: { fileSize: 15_000_000 }, }); @Controller('people') @UseGuards(JwtAuthGuard, OrgModuleGuard, SectionPermissionGuard) @RequireOrgModule('customers') @RequirePermission('customers') export class PeopleController { constructor( private readonly peopleService: PeopleService, private readonly excelService: ContactsExcelService, ) {} @Get() list(@CurrentUser() user: Actor, @Query() query: ListQueryDto) { const hasMobile = query.hasMobile === '1' || query.hasMobile === 'true' ? true : undefined; return this.peopleService.list( user, query.q, query.page ?? 1, query.limit ?? 20, { mood: query.mood, sort: query.sort, importSource: query.importSource, province: query.province, city: query.city, hasMobile, disc: query.disc, groupId: query.groupId, }, ); } @Get('ids') listIds(@CurrentUser() user: Actor, @Query() query: ListQueryDto) { const hasMobile = query.hasMobile === '1' || query.hasMobile === 'true' ? true : undefined; return this.peopleService.listIds(user, query.q, { mood: query.mood, importSource: query.importSource, province: query.province, city: query.city, hasMobile, disc: query.disc, groupId: query.groupId, }); } @Get('source-stats') sourceStats(@CurrentUser() user: Actor) { return this.peopleService.sourceStats(user); } @Get('group-stats') groupStats(@CurrentUser() user: Actor) { return this.peopleService.groupStats(user); } @Get('export') async export( @CurrentUser() user: Actor, @Query('q') q: string | undefined, @Res({ passthrough: true }) res: Response, ) { const buffer = await this.excelService.exportPeople(user, q); res.set({ 'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'Content-Disposition': `attachment; filename="${brand.filePrefix}-people.xlsx"`, }); return new StreamableFile(buffer); } @Post('import/preview') @UseInterceptors(excelUpload) previewImport(@UploadedFile() file?: Express.Multer.File) { if (!file?.buffer?.length) { throw new BadRequestException('فایل ارسال نشده'); } return this.excelService.previewPeople(file); } @Post('import') @UseInterceptors(excelUpload) import( @CurrentUser() user: Actor, @UploadedFile() file?: Express.Multer.File, @Body('mapping') mapping?: string, @Body('sessionId') sessionId?: string, @Body('offset') offset?: string, @Body('limit') limit?: string, ) { if (!file?.buffer?.length && !sessionId) { throw new BadRequestException('فایل ارسال نشده'); } return this.excelService.importPeople(user, file, mapping, { sessionId, offset, limit, }); } @Get('birthdays') @RequirePermission('customers', { reads: true }) birthdays(@CurrentUser() user: Actor) { return this.peopleService.birthdaysThisMonth(user); } @Get(':id/sms-history') smsHistory( @CurrentUser() user: Actor, @Param('id') id: string, @Query('limit') limit?: string, ) { return this.peopleService.listSmsHistory( user, id, limit ? Number(limit) : 50, ); } @Post(':id/sms') sms( @CurrentUser() user: Actor, @Param('id') id: string, @Body() dto: BirthdaySmsDto, ) { return this.peopleService.sendSms(user, id, dto.text); } @Post(':id/birthday-sms') birthdaySms( @CurrentUser() user: Actor, @Param('id') id: string, @Body() dto: BirthdaySmsDto, ) { return this.peopleService.sendBirthdaySms(user, id, dto.text, Boolean(dto.force)); } @Get(':id') get(@CurrentUser() user: Actor, @Param('id') id: string) { return this.peopleService.get(user, id); } @Post('bulk-delete') bulkDelete(@CurrentUser() user: Actor, @Body() dto: BulkDeletePeopleDto) { return this.peopleService.removeMany(user, dto.ids); } @Post() create(@CurrentUser() user: Actor, @Body() dto: CreatePersonDto) { return this.peopleService.create(user, { ...dto, firstName: dto.firstName ?? '', lastName: dto.lastName ?? '', }); } @Patch(':id') update( @CurrentUser() user: Actor, @Param('id') id: string, @Body() dto: UpdatePersonDto, ) { return this.peopleService.update(user, id, dto); } @Delete(':id') async remove(@CurrentUser() user: Actor, @Param('id') id: string) { await this.peopleService.remove(user, id); return { ok: true }; } }