From 7585080670bd4505959cfc0a18be94cccc32367e Mon Sep 17 00:00:00 2001 From: morteza-mortezai Date: Mon, 9 Mar 2026 16:42:43 +0330 Subject: [PATCH] remove --- src/app.module.ts | 2 - src/modules/contact/contact.module.ts | 15 --- .../contact/controllers/contact.controller.ts | 108 ------------------ src/modules/contact/dto/create-contact.dto.ts | 26 ----- src/modules/contact/dto/find-contacts.dto.ts | 42 ------- .../contact/dto/update-contact-status.dto.ts | 10 -- src/modules/contact/dto/update-contact.dto.ts | 4 - .../contact/entities/contact.entity.ts | 26 ----- src/modules/contact/interface/interface.ts | 9 -- .../contact/providers/contact.service.ts | 108 ------------------ .../repositories/contact.repository.ts | 69 ----------- 11 files changed, 419 deletions(-) delete mode 100644 src/modules/contact/contact.module.ts delete mode 100644 src/modules/contact/controllers/contact.controller.ts delete mode 100644 src/modules/contact/dto/create-contact.dto.ts delete mode 100644 src/modules/contact/dto/find-contacts.dto.ts delete mode 100644 src/modules/contact/dto/update-contact-status.dto.ts delete mode 100644 src/modules/contact/dto/update-contact.dto.ts delete mode 100644 src/modules/contact/entities/contact.entity.ts delete mode 100644 src/modules/contact/interface/interface.ts delete mode 100644 src/modules/contact/providers/contact.service.ts delete mode 100644 src/modules/contact/repositories/contact.repository.ts diff --git a/src/app.module.ts b/src/app.module.ts index 6077619..c052616 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -14,7 +14,6 @@ import { FoodModule } from './modules/foods/food.module'; import { RolesModule } from './modules/roles/roles.module'; import { NotificationsModule } from './modules/notifications/notifications.module'; import { EventEmitterModule } from '@nestjs/event-emitter'; -import { ContactModule } from './modules/contact/contact.module'; import { CacheModule } from '@nestjs/cache-manager'; import { cacheConfig } from './config/cache.config'; import { BusinessModule } from './modules/business/business.module'; @@ -42,7 +41,6 @@ import { CatalogueModule } from './modules/catalogue/catalogue.module'; RolesModule, NotificationsModule, EventEmitterModule.forRoot(), - ContactModule, BusinessModule, CatalogueModule, ], diff --git a/src/modules/contact/contact.module.ts b/src/modules/contact/contact.module.ts deleted file mode 100644 index aee946f..0000000 --- a/src/modules/contact/contact.module.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Module } from '@nestjs/common'; -import { ContactService } from './providers/contact.service'; -import { ContactController } from './controllers/contact.controller'; -import { MikroOrmModule } from '@mikro-orm/nestjs'; -import { Contact } from './entities/contact.entity'; -import { ContactRepository } from './repositories/contact.repository'; -import { JwtModule } from '@nestjs/jwt'; - -@Module({ - imports: [MikroOrmModule.forFeature([Contact]), JwtModule], - controllers: [ContactController], - providers: [ContactService, ContactRepository], - exports: [ContactRepository], -}) -export class ContactModule {} diff --git a/src/modules/contact/controllers/contact.controller.ts b/src/modules/contact/controllers/contact.controller.ts deleted file mode 100644 index 83736fa..0000000 --- a/src/modules/contact/controllers/contact.controller.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { - Controller, - Get, - Post, - Body, - Patch, - Param, - Query, - UseGuards, - Delete, -} from '@nestjs/common'; -import { ContactService } from '../providers/contact.service'; -import { CreateContactDto } from '../dto/create-contact.dto'; -import { FindContactsDto } from '../dto/find-contacts.dto'; -import { UpdateContactStatusDto } from '../dto/update-contact-status.dto'; -import { ApiTags, ApiOperation, ApiBearerAuth, ApiParam, ApiQuery, ApiHeader } from '@nestjs/swagger'; -import { AdminAuthGuard } from 'src/modules/auth/guards/adminAuth.guard'; -import { SuperAdminAuthGuard } from 'src/modules/auth/guards/superAdminAuth.guard'; -import { OptionalAuthGuard } from 'src/modules/auth/guards/optinalAuth.guard'; -import { API_HEADER_SLUG } from 'src/common/constants'; -import { Permission } from 'src/common/enums/permission.enum'; -import { Permissions } from 'src/common/decorators/permissions.decorator'; -import { RestId } from 'src/common/decorators/rest-id.decorator'; -import { RestSlug } from 'src/common/decorators/rest-slug.decorator'; - -@ApiTags('contact') -@Controller() -export class ContactController { - constructor(private readonly contactService: ContactService) { } - - @UseGuards(OptionalAuthGuard) - @Post('public/contact') - @ApiOperation({ summary: 'Create a new contact (public endpoint)' }) - @ApiHeader(API_HEADER_SLUG) - async create(@Body() createContactDto: CreateContactDto, @RestSlug() slug: string, @RestId() restId?: string) { - return this.contactService.create(createContactDto, restId, slug); - } - - - @UseGuards(AdminAuthGuard) - @ApiBearerAuth() - @Permissions(Permission.MANAGE_CONTACTS) - @Get('admin/contact') - @ApiOperation({ summary: 'Get paginated list of contacts (admin only)' }) - @ApiQuery({ name: 'page', required: false, type: Number }) - @ApiQuery({ name: 'limit', required: false, type: Number }) - @ApiQuery({ name: 'search', required: false, type: String }) - @ApiQuery({ name: 'orderBy', required: false, type: String }) - @ApiQuery({ name: 'order', required: false, enum: ['asc', 'desc'] }) - @ApiQuery({ name: 'status', required: false, enum: ['new', 'seen'] }) - async findAllPaginated(@RestId() restId: string, @Query() dto: FindContactsDto) { - return this.contactService.findAllPaginatedAdmin(dto, restId); - } - - @UseGuards(AdminAuthGuard) - @ApiBearerAuth() - @Permissions(Permission.MANAGE_CONTACTS) - @Get('admin/contact/:id') - @ApiOperation({ summary: 'Get contact details by ID (admin only)' }) - @ApiParam({ name: 'id', description: 'Contact ID' }) - async findOne(@RestId() restId: string, @Param('id') id: string) { - return this.contactService.findOne(id, restId); - } - - @UseGuards(AdminAuthGuard) - @ApiBearerAuth() - @Permissions(Permission.MANAGE_CONTACTS) - @Patch('admin/contact/:id/status') - @ApiOperation({ summary: 'Update contact status (admin only)' }) - @ApiParam({ name: 'id', description: 'Contact ID' }) - async updateStatus(@RestId() restId: string, @Param('id') id: string, @Body() dto: UpdateContactStatusDto) { - return this.contactService.updateStatus(id, dto, restId); - } - - @UseGuards(AdminAuthGuard) - @ApiBearerAuth() - @Permissions(Permission.MANAGE_CONTACTS) - @Delete('admin/contact/:id') - @ApiOperation({ summary: 'Hard delete a contact (admin only)' }) - @ApiParam({ name: 'id', description: 'Contact ID' }) - async remove(@RestId() restId: string, @Param('id') id: string) { - await this.contactService.remove(id, restId); - } - - /*** Super Admin ***/ - @UseGuards(SuperAdminAuthGuard) - @ApiBearerAuth() - @Get('super-admin/contact') - @ApiOperation({ summary: 'Get paginated list of contacts (admin only)' }) - @ApiQuery({ name: 'page', required: false, type: Number }) - @ApiQuery({ name: 'limit', required: false, type: Number }) - @ApiQuery({ name: 'search', required: false, type: String }) - @ApiQuery({ name: 'orderBy', required: false, type: String }) - @ApiQuery({ name: 'order', required: false, enum: ['asc', 'desc'] }) - @ApiQuery({ name: 'status', required: false, enum: ['new', 'seen'] }) - async findAllPaginatedForSuper(@Query() dto: FindContactsDto) { - return this.contactService.findAllPaginatedSuper(dto); - } - - @UseGuards(SuperAdminAuthGuard) - @ApiBearerAuth() - @Get('super-admin/contact/:id') - @ApiOperation({ summary: 'Get contact details by ID (admin only)' }) - @ApiParam({ name: 'id', description: 'Contact ID' }) - async findOneForSuper(@Param('id') id: string) { - return this.contactService.findOne(id); - } -} diff --git a/src/modules/contact/dto/create-contact.dto.ts b/src/modules/contact/dto/create-contact.dto.ts deleted file mode 100644 index 134bd54..0000000 --- a/src/modules/contact/dto/create-contact.dto.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { IsNotEmpty, IsString, IsOptional, IsMobilePhone, IsEnum } from 'class-validator'; -import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; -import { ContactScope } from '../interface/interface'; - -export class CreateContactDto { - @IsOptional() - @IsString() - @ApiPropertyOptional({ example: 'Question about menu', description: 'Contact subject' }) - subject?: string; - - @IsNotEmpty() - @IsString() - @ApiProperty({ example: 'I have a question about your menu items', description: 'Contact content/message' }) - content!: string; - - @IsNotEmpty() - @IsEnum(['application', 'restaurant']) - @ApiProperty({ description: 'Contact Scope' }) - scope!: ContactScope; - - @IsOptional() - @IsString() - @IsMobilePhone('fa-IR') - @ApiPropertyOptional({ example: '09362532122', description: 'Phone number' }) - phone?: string; -} diff --git a/src/modules/contact/dto/find-contacts.dto.ts b/src/modules/contact/dto/find-contacts.dto.ts deleted file mode 100644 index 4a662bd..0000000 --- a/src/modules/contact/dto/find-contacts.dto.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { IsOptional, IsNumber, IsString, IsIn, IsEnum } from 'class-validator'; -import { ApiPropertyOptional } from '@nestjs/swagger'; -import { Type } from 'class-transformer'; -import { ContactStatusEnum } from '../interface/interface'; - -const sortOrderOptions = ['asc', 'desc'] as const; -type SortOrder = (typeof sortOrderOptions)[number]; - -export class FindContactsDto { - @IsOptional() - @IsNumber() - @Type(() => Number) - @ApiPropertyOptional({ example: 1, description: 'Page number', minimum: 1, default: 1 }) - page?: number = 1; - - @IsOptional() - @IsNumber() - @Type(() => Number) - @ApiPropertyOptional({ example: 10, description: 'Items per page', minimum: 1, default: 10 }) - limit?: number = 10; - - @IsOptional() - @IsString() - @ApiPropertyOptional({ example: 'menu', description: 'Search in subject, content, or phone' }) - search?: string; - - @IsOptional() - @IsString() - @ApiPropertyOptional({ example: 'createdAt', description: 'Field to sort by', default: 'createdAt' }) - orderBy?: string = 'createdAt'; - - @IsOptional() - @IsIn(sortOrderOptions) - @ApiPropertyOptional({ example: 'desc', enum: sortOrderOptions, default: 'desc' }) - order?: SortOrder = 'desc'; - - @IsOptional() - @IsEnum(ContactStatusEnum) - @ApiPropertyOptional({ enum: ContactStatusEnum, description: 'Filter by status' }) - status?: ContactStatusEnum; - -} diff --git a/src/modules/contact/dto/update-contact-status.dto.ts b/src/modules/contact/dto/update-contact-status.dto.ts deleted file mode 100644 index c68ced2..0000000 --- a/src/modules/contact/dto/update-contact-status.dto.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { IsEnum, IsNotEmpty } from 'class-validator'; -import { ApiProperty } from '@nestjs/swagger'; -import { ContactStatusEnum } from '../interface/interface'; - -export class UpdateContactStatusDto { - @IsNotEmpty() - @IsEnum(ContactStatusEnum) - @ApiProperty({ enum: ContactStatusEnum, description: 'New status for the contact' }) - status!: ContactStatusEnum; -} diff --git a/src/modules/contact/dto/update-contact.dto.ts b/src/modules/contact/dto/update-contact.dto.ts deleted file mode 100644 index 366df50..0000000 --- a/src/modules/contact/dto/update-contact.dto.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { PartialType } from '@nestjs/swagger'; -import { CreateContactDto } from './create-contact.dto'; - -export class UpdateContactDto extends PartialType(CreateContactDto) {} diff --git a/src/modules/contact/entities/contact.entity.ts b/src/modules/contact/entities/contact.entity.ts deleted file mode 100644 index 281855c..0000000 --- a/src/modules/contact/entities/contact.entity.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Entity, Enum, ManyToOne, Property } from '@mikro-orm/core'; -import { BaseEntity } from '../../../common/entities/base.entity'; -import { ContactScope, ContactStatusEnum } from '../interface/interface'; -import { Restaurant } from '../../restaurants/entities/restaurant.entity'; - -@Entity({ tableName: 'contacts' }) -export class Contact extends BaseEntity { - @Property({ nullable: true }) - subject?: string | null = null; - - @Property() - content!: string; - - @Property({ nullable: true }) - phone?: string | null = null; - - @Enum(() => ContactScope) - scope: ContactScope - - @ManyToOne(() => Restaurant, { nullable: true }) - restaurant?: Restaurant | null = null; - - - @Property({ default: ContactStatusEnum.New }) - status: ContactStatusEnum = ContactStatusEnum.New; -} diff --git a/src/modules/contact/interface/interface.ts b/src/modules/contact/interface/interface.ts deleted file mode 100644 index 70cb107..0000000 --- a/src/modules/contact/interface/interface.ts +++ /dev/null @@ -1,9 +0,0 @@ -export enum ContactStatusEnum { - New = 'new', - Seen = 'seen', -} - -export enum ContactScope { - APPLICATION = 'application', - RESTAURANT = 'restaurant', -} diff --git a/src/modules/contact/providers/contact.service.ts b/src/modules/contact/providers/contact.service.ts deleted file mode 100644 index 48fad03..0000000 --- a/src/modules/contact/providers/contact.service.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { Injectable, NotFoundException } from '@nestjs/common'; -import { CreateContactDto } from '../dto/create-contact.dto'; -import { FindContactsDto } from '../dto/find-contacts.dto'; -import { UpdateContactStatusDto } from '../dto/update-contact-status.dto'; -import { ContactRepository } from '../repositories/contact.repository'; -import { Contact } from '../entities/contact.entity'; -import { PaginatedResult } from 'src/common/interfaces/pagination.interface'; -import { ContactStatusEnum } from '../interface/interface'; -import { EntityManager } from '@mikro-orm/postgresql'; -import { ContactScope } from '../interface/interface'; -import { Restaurant } from '../../restaurants/entities/restaurant.entity'; - -@Injectable() -export class ContactService { - constructor( - private readonly contactRepository: ContactRepository, - private readonly em: EntityManager, - ) { } - - async create(dto: CreateContactDto, restId?: string, slug?: string): Promise { - - - let restaurant: Restaurant | null = null; - - if ((restId || slug) && dto.scope === ContactScope.RESTAURANT) { - restaurant = await this.em.findOne(Restaurant, { - ...(restId ? { id: restId } : {}) - , ...(slug ? { slug: slug } : {}) - }); - if (!restaurant) { - throw new NotFoundException(`Restaurant with ID ${restId} not found`); - } - } - - const contact = this.contactRepository.create({ - ...dto, - status: ContactStatusEnum.New, - restaurant, - }); - await this.em.persistAndFlush(contact); - return contact; - } - - async findAllPaginatedAdmin(dto: FindContactsDto, restaurantId?: string): Promise> { - return this.contactRepository.findAllPaginated({ - page: dto.page, - limit: dto.limit, - search: dto.search, - orderBy: dto.orderBy, - order: dto.order, - status: dto.status, - scope: ContactScope.RESTAURANT, - restaurantId - }); - } - async findAllPaginatedSuper(dto: FindContactsDto): Promise> { - return this.contactRepository.findAllPaginated({ - page: dto.page, - limit: dto.limit, - search: dto.search, - orderBy: dto.orderBy, - order: dto.order, - status: dto.status, - scope: ContactScope.APPLICATION - }); - } - - async findOne(id: string, restaurantId?: string): Promise { - const where: any = { id }; - if (restaurantId) { - where.restaurant = restaurantId; - } - - const contact = await this.contactRepository.findOne(where); - if (!contact) { - throw new NotFoundException(`Contact with ID ${id} not found`); - } - return contact; - } - - async updateStatus(id: string, dto: UpdateContactStatusDto, restaurantId?: string): Promise { - const where: any = { id }; - if (restaurantId) { - where.restaurant = restaurantId; - } - - const contact = await this.contactRepository.findOne(where); - if (!contact) { - throw new NotFoundException(`Contact with ID ${id} not found`); - } - contact.status = dto.status; - await this.em.persistAndFlush(contact); - return contact; - } - - async remove(id: string, restaurantId?: string): Promise { - const where: any = { id }; - if (restaurantId) { - where.restaurant = restaurantId; - } - - const contact = await this.contactRepository.findOne(where); - if (!contact) { - throw new NotFoundException(`Contact with ID ${id} not found`); - } - await this.em.removeAndFlush(contact); - } -} diff --git a/src/modules/contact/repositories/contact.repository.ts b/src/modules/contact/repositories/contact.repository.ts deleted file mode 100644 index 01f6278..0000000 --- a/src/modules/contact/repositories/contact.repository.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { EntityManager, EntityRepository } from '@mikro-orm/postgresql'; -import { FilterQuery } from '@mikro-orm/core'; -import { Contact } from '../entities/contact.entity'; -import { PaginatedResult } from 'src/common/interfaces/pagination.interface'; -import { ContactScope, ContactStatusEnum } from '../interface/interface'; - -type FindContactsOpts = { - page?: number; - limit?: number; - search?: string; - orderBy?: string; - order?: 'asc' | 'desc'; - status?: ContactStatusEnum; - scope?: ContactScope; - restaurantId?: string; -}; - -@Injectable() -export class ContactRepository extends EntityRepository { - constructor(readonly em: EntityManager) { - super(em, Contact); - } - - /** - * Find contacts with pagination and optional filters. - * Supports: search (subject/content/phone), status, ordering. - */ - async findAllPaginated(opts: FindContactsOpts = {}): Promise> { - const { page = 1, limit = 10, search, scope, orderBy = 'createdAt', order = 'desc', status, restaurantId } = opts; - - const offset = (page - 1) * limit; - - const where: FilterQuery = {}; - - if (status) { - where.status = status; - } - if (scope) { - where.scope = scope; - } - if (restaurantId) { - where.restaurant = restaurantId; - } - - if (search) { - const pattern = `%${search}%`; - where.$or = [{ subject: { $ilike: pattern } }, { content: { $ilike: pattern } }, { phone: { $ilike: pattern } }]; - } - - const [data, total] = await this.findAndCount(where, { - limit, - offset, - orderBy: { [orderBy]: order.toLowerCase() as 'asc' | 'desc' }, - }); - - const totalPages = Math.ceil(total / limit); - - return { - data, - meta: { - total, - page, - limit, - totalPages, - }, - }; - } -}