rename ticket to chat

This commit is contained in:
2026-02-23 11:01:21 +03:30
parent 8303a4c108
commit cc9f52652d
14 changed files with 162 additions and 179 deletions
@@ -1,10 +1,10 @@
import { ApiProperty } from "@nestjs/swagger";
import { IsNotEmpty, IsOptional, IsString, IsUrl, Length } from "class-validator";
import { AttachmentType } from "../interfaces/ticket";
import { AttachmentType } from "../interfaces/chat";
import { TicketMessageEnum } from "../../../common/enums/message.enum";
export class CreateTicketDto {
export class CreateChatDto {
@IsNotEmpty({ message: TicketMessageEnum.MESSAGE_REQUIRED })
@IsString({ message: TicketMessageEnum.MESSAGE_STRING })
@Length(5, 5000, { message: TicketMessageEnum.MESSAGE_LENGTH })
@@ -1,5 +1,5 @@
import { PaginationDto } from "../../../common/DTO/pagination.dto";
export class FindTicketQueryDto extends PaginationDto {
export class FindChatQueryDto extends PaginationDto {
}
+6
View File
@@ -0,0 +1,6 @@
import { PartialType } from "@nestjs/swagger";
import { CreateChatDto } from "./create-chat.dto";
export class UpdateChatDto extends PartialType(CreateChatDto) { }
+24
View File
@@ -0,0 +1,24 @@
import { Module } from "@nestjs/common";
import { Chat } from "./entities/ticket.entity";
import { ChattService } from "./providers/chat.service";
import { ChatRepository } from "./repositories/chat.repository";
import { ChatController } from "./controller/chat.controller";
import { MikroOrmModule } from "@mikro-orm/nestjs";
import { AdminModule } from "../admin/admin.module";
import { UserModule } from "../user/user.module";
import { JwtModule } from "@nestjs/jwt";
@Module({
imports: [
MikroOrmModule.forFeature([Chat]),
AdminModule,
UserModule,
JwtModule.register({})
],
providers: [ChattService, ChatRepository],
controllers: [ChatController],
exports: [ChattService, ChatRepository],
})
export class ChatModule { }
+78
View File
@@ -0,0 +1,78 @@
import { Body, Controller, Delete, Get, Param, Patch, Post, Query, UseGuards } from "@nestjs/common";
import { ApiBearerAuth, ApiOperation, ApiTags } from "@nestjs/swagger";
import { CreateChatDto } from "../DTO/create-chat.dto";
import { FindChatQueryDto } from "../DTO/search-chat-query.dto";
import { ChattService } from "../providers/chat.service";
import { UserId } from "src/common/decorators";
import { AdminId } from "src/common/decorators/admin-id.decorator";
import { UpdateChatDto } from "../DTO/update-chat.dto";
import { AdminAuthGuard } from "src/modules/auth/guards/adminAuth.guard";
import { AuthGuard } from "src/modules/auth/guards/auth.guard";
@Controller()
@ApiTags("Chats")
@ApiBearerAuth()
export class ChatController {
constructor(private readonly chatService: ChattService) { }
@Post('public/chat/ref/:id')
@UseGuards(AuthGuard)
@ApiOperation({ summary: "create chat ==> user route" })
createTicket(@Param('id') id: string, @Body() createDto: CreateChatDto, @UserId() userId: string) {
return this.chatService.createChatAsUser(id, createDto, userId);
}
@Get('public/chat/ref/:id')
@UseGuards(AuthGuard)
@ApiOperation({ summary: "Get all order item tickets ==> user route" })
getTickets(@Query() queryDto: FindChatQueryDto, @Param('id') id: string, @UserId() userId: string) {
return this.chatService.getChats(id, queryDto, userId);
}
@Patch('public/chat/:id')
@UseGuards(AuthGuard)
@ApiOperation({ summary: "Delete chat ==> admin route" })
updateTicket(@Param('id') id: string, @UserId() userId: string, @Body() body: UpdateChatDto) {
return this.chatService.updatechatAsUser(id, userId, body);
}
@Delete('public/chat/:id')
@ApiOperation({ summary: "Delete chat ==> admin route" })
@UseGuards(AuthGuard)
deleteTicket(@Param('id') id: string, @UserId() userId: string) {
return this.chatService.deletechatAsUSer(id, userId);
}
/*=========================== Admin ============================== */
@Post('admin/chat/ref/:id')
@UseGuards(AdminAuthGuard)
@ApiOperation({ summary: "create chat ==> admin route" })
createTicketAsAdmin(@Param('id') itemId: string, @Body() createDto: CreateChatDto, @AdminId() adminId: string) {
return this.chatService.createChatAsAdmin(itemId, createDto, adminId);
}
@Get('admin/chat/ref/:id')
@UseGuards(AdminAuthGuard)
@ApiOperation({ summary: "Get all order item tickets ==> admin route" })
getTicketsAsAdmin(@Query() queryDto: FindChatQueryDto, @Param('id') itemId: string) {
return this.chatService.getChats(itemId, queryDto);
}
@Patch('admin/chat/:id')
@UseGuards(AdminAuthGuard)
@ApiOperation({ summary: "Update chat ==> admin route" })
updateTicketAsAdmin(@Param('id') id: string, @AdminId() adminId: string, @Body() body: UpdateChatDto) {
return this.chatService.updatechatAsAdmin(id, adminId, body);
}
@Delete('admin/chat/:id')
@UseGuards(AdminAuthGuard)
@ApiOperation({ summary: "Delete chat ==> admin route" })
deleteTicketAsAdmin(@Param('id') id: string, @AdminId() adminId: string) {
return this.chatService.deletechatAsAdmin(id, adminId);
}
}
@@ -2,16 +2,15 @@ import {
Entity,
ManyToOne,
Property,
PrimaryKey,
OptionalProps,
} from '@mikro-orm/core';
import { User } from "../../user/entities/user.entity";
import { Admin } from 'src/modules/admin/entities/admin.entity';
import { AttachmentType } from '../interfaces/ticket';
import { AttachmentType } from '../interfaces/chat';
import { BaseEntity } from 'src/common/entities/base.entity';
@Entity()
export class Ticket extends BaseEntity {
export class Chat extends BaseEntity {
[OptionalProps]?: 'createdAt' | 'deletedAt'
@@ -30,8 +29,8 @@ export class Ticket extends BaseEntity {
@Property({ type: 'string' })
refId!: string
@ManyToOne(() => Ticket, { nullable: true })
parent?: Ticket
@ManyToOne(() => Chat, { nullable: true })
parent?: Chat
@Property({ defaultRaw: 'now()', columnType: 'timestamptz' })
createdAt: Date = new Date();
@@ -1,29 +1,26 @@
import { TicketRepository } from "../repositories/tickets.repository";
import { ChatRepository } from "../repositories/chat.repository";
import { BadRequestException, Injectable } from "@nestjs/common";
import { CreateTicketDto } from "../DTO/create-ticket.dto";
import { CreateChatDto } from "../DTO/create-chat.dto";
import { User } from "src/modules/user/entities/user.entity";
import { UserRepository } from "src/modules/user/repositories/user.repository";
import { AdminRepository } from "src/modules/admin/repositories/admin.repository";
import { Admin } from "src/modules/admin/entities/admin.entity";
import { FindTicketQueryDto } from "../DTO/search-ticket-query.dto";
import { FindChatQueryDto } from "../DTO/search-chat-query.dto";
import { EntityManager } from "@mikro-orm/postgresql";
import { UpdateTicketDto } from "../DTO/update-ticket.dto";
import { Ticket } from "../entities/ticket.entity";
import { AdminService } from "src/modules/admin/providers/admin.service";
import { UpdateChatDto } from "../DTO/update-chat.dto";
import { Chat } from "../entities/ticket.entity";
import { AdminService } from "src/modules/admin/providers/admin.service";
import { UserService } from "src/modules/user/providers/user.service";
@Injectable()
export class TicketService {
export class ChattService {
constructor(
private readonly ticketsRepository: TicketRepository,
// private readonly orderItemRepository: OrderItemRepository,
private readonly chatRepository: ChatRepository,
private readonly adminService: AdminService,
private readonly userService: UserService,
private readonly em: EntityManager,
) { }
async createTicketAsAdmin(refId: string, dto: CreateTicketDto, adminId: string) {
async createChatAsAdmin(refId: string, dto: CreateChatDto, adminId: string) {
// const orderItem = await this.findOrderItemOrFail(refId)
@@ -31,69 +28,67 @@ export class TicketService {
admin = await this.adminService.findOrFail(adminId)
const ticket = await this.createTicket(refId, dto, undefined, admin)
const ticket = await this.createChat(refId, dto, undefined, admin)
return ticket
}
async createTicketAsUser(refId: string, dto: CreateTicketDto, userId: string) {
// const orderItem = await this.findOrderItemOrFail(refId)
async createChatAsUser(refId: string, dto: CreateChatDto, userId: string) {
const user = await this.userService.findOrFail(userId)
const ticket = await this.createTicket(refId, dto, user, undefined)
const ticket = await this.createChat(refId, dto, user, undefined)
return ticket
}
async updateTicketAsUser(ticketId: string, userId: string, dto: UpdateTicketDto) {
async updatechatAsUser(ticketId: string, userId: string, dto: UpdateChatDto) {
const ticket = await this.findOneOrFail(ticketId)
this.assertUserOwner(ticket, userId)
await this.updateTicket(ticket, dto)
await this.updateChat(ticket, dto)
return { message: 'success' }
}
async updateTicketAsAdmin(ticketId: string, adminId: string, dto: UpdateTicketDto) {
async updatechatAsAdmin(ticketId: string, adminId: string, dto: UpdateChatDto) {
const ticket = await this.findOneOrFail(ticketId)
this.assertAdminOwner(ticket, adminId)
await this.updateTicket(ticket, dto)
await this.updateChat(ticket, dto)
return { message: 'success' }
}
async deleteTicketAsUser(ticketId: string, userId: string) {
async deletechatAsUser(ticketId: string, userId: string) {
const ticket = await this.findOneOrFail(ticketId)
this.assertUserOwner(ticket, userId)
await this.deleteTicket(ticket)
await this.deleteChat(ticket)
return { message: 'success' }
}
async deleteTicketAsAdmin(ticketId: string, adminId: string) {
async deletechatAsAdmin(ticketId: string, adminId: string) {
const ticket = await this.findOneOrFail(ticketId)
this.assertAdminOwner(ticket, adminId)
await this.deleteTicket(ticket)
await this.deleteChat(ticket)
return { message: 'success' }
}
async deleteTicketAsUSer(ticketId: string, userId: string) {
async deletechatAsUSer(ticketId: string, userId: string) {
const ticket = await this.findOneOrFail(ticketId)
// if (ticket.orderItem.order.user.id !== userId) {
// throw new BadRequestException("You can not Delete this Ticket")
@@ -106,22 +101,22 @@ export class TicketService {
// ================ Core Logic ============
async getTickets(refId: string, queryDto: FindTicketQueryDto, userId?: string) {
async getChats(refId: string, queryDto: FindChatQueryDto, userId?: string) {
// const orderItem = await this.findOrderItemOrFail(refId)
const data = await this.ticketsRepository.findAllPaginated({ ...queryDto, refId });
const data = await this.chatRepository.findAllPaginated({ ...queryDto, refId });
return data
}
async createTicket(refId:string,dto: CreateTicketDto, user?: User, admin?: Admin) {
async createChat(refId: string, dto: CreateChatDto, user?: User, admin?: Admin) {
const { content, attachments } = dto
if (!user && !admin) {
throw new BadRequestException("One of user or admin is required")
}
const ticket = this.ticketsRepository.create({
const ticket = this.chatRepository.create({
content,
attachments,
admin,
@@ -129,20 +124,20 @@ export class TicketService {
refId
})
await this.ticketsRepository.em.persistAndFlush(ticket)
await this.chatRepository.em.persistAndFlush(ticket)
return ticket
}
async deleteTicket(ticket: Ticket) {
await this.em.removeAndFlush(ticket)
async deleteChat(chat: Chat) {
await this.em.removeAndFlush(chat)
return true
}
async updateTicket(ticket: Ticket, dto: UpdateTicketDto) {
async updateChat(chat: Chat, dto: UpdateChatDto) {
this.ticketsRepository.assign(ticket, dto, {
this.chatRepository.assign(chat, dto, {
onlyProperties: true,
})
@@ -154,15 +149,15 @@ export class TicketService {
// ================ Helpers =================
async findOneOrFail(ticketId: string) {
const ticket = await this.ticketsRepository.findOne({ id: ticketId },
{ populate: [ 'user'] })
const ticket = await this.chatRepository.findOne({ id: ticketId },
{ populate: ['user'] })
if (!ticket) {
throw new BadRequestException('ticket not found!')
}
return ticket
}
assertUserOwner(ticket: Ticket, userId: string) {
assertUserOwner(ticket: Chat, userId: string) {
if (!ticket.user) {
throw new BadRequestException("User not found!")
}
@@ -172,7 +167,7 @@ export class TicketService {
}
}
assertAdminOwner(ticket: Ticket, adminId: string) {
assertAdminOwner(ticket: Chat, adminId: string) {
if (!ticket.admin) {
throw new BadRequestException("Admin not found!")
}
@@ -182,14 +177,4 @@ export class TicketService {
}
}
// async findOrderItemOrFail(refId: string) {
// const orderItem = await this.orderItemRepository.findOne({ id: refId }, { populate: ['order', 'order.user'] })
// if (!orderItem) {
// throw new BadRequestException("orderItem not found!")
// }
// return orderItem
// }
}
@@ -1,22 +1,22 @@
import { EntityManager, EntityRepository, FilterQuery } from '@mikro-orm/postgresql';
import { Injectable } from '@nestjs/common';
import { Ticket } from '../entities/ticket.entity';
import { FindTicketQueryDto } from '../DTO/search-ticket-query.dto';
import { Chat } from '../entities/ticket.entity';
import { FindChatQueryDto } from '../DTO/search-chat-query.dto';
import { PaginatedResult } from 'src/common/interfaces/pagination.interface';
class FindOrdersOpts extends FindTicketQueryDto {
class FindOrdersOpts extends FindChatQueryDto {
refId: string;
};
@Injectable()
export class TicketRepository extends EntityRepository<Ticket> {
export class ChatRepository extends EntityRepository<Chat> {
constructor(
readonly em: EntityManager,
) {
super(em, Ticket);
super(em, Chat);
}
async findAllPaginated(opts: FindOrdersOpts): Promise<PaginatedResult<Ticket>> {
async findAllPaginated(opts: FindOrdersOpts): Promise<PaginatedResult<Chat>> {
const {
page = 1,
limit = 10,
@@ -25,7 +25,7 @@ export class TicketRepository extends EntityRepository<Ticket> {
const offset = (page - 1) * limit;
const where: FilterQuery<Ticket> = {
const where: FilterQuery<Chat> = {
refId
};
+2 -2
View File
@@ -15,7 +15,7 @@ import { NotificationsModule } from '../notification/notifications.module';
import { UserModule } from '../user/user.module';
import { UtilsModule } from '../util/utils.module';
import { ProductModule } from '../product/product.module';
import { TicketModule } from '../ticket/ticket.module';
import { ChatModule } from '../chat/chat.module';
import { OrderPrintRepository } from './repositories/order-print.repository';
@Module({
@@ -29,7 +29,7 @@ import { OrderPrintRepository } from './repositories/order-print.repository';
UtilsModule,
forwardRef(() => UserModule),
ProductModule,
forwardRef(() => TicketModule)
forwardRef(() => ChatModule)
],
controllers: [OrderController],
providers: [OrderService, OrderRepository, OrderListeners,
+4 -4
View File
@@ -10,8 +10,8 @@ import { UserService } from 'src/modules/user/providers/user.service';
import { OrderStatusEnum } from '../interface/order.interface';
import { ProductService } from 'src/modules/product/providers/product.service';
import { ProductRepository } from 'src/modules/product/repositories/product.repository';
import { TicketService } from 'src/modules/ticket/providers/tickets.service';
import { TicketRepository } from 'src/modules/ticket/repositories/tickets.repository';
import { ChattService } from 'src/modules/chat/providers/chat.service';
import { ChatRepository } from 'src/modules/chat/repositories/chat.repository';
import { AdminRepository } from 'src/modules/admin/repositories/admin.repository';
import { Order } from '../entities/order.entity';
import { PaymentRepository } from 'src/modules/payment/repositories/payment.repository';
@@ -45,8 +45,8 @@ export class OrderService {
private readonly orderPrintRepository: OrderPrintRepository,
private readonly productService: ProductService,
private readonly productRepository: ProductRepository,
private readonly ticketRepository: TicketRepository,
private readonly ticketService: TicketService,
private readonly ticketRepository: ChatRepository,
private readonly ticketService: ChattService,
private readonly eventEmitter: EventEmitter2,
private readonly adminRepository: AdminRepository,
private readonly paymentRepository: PaymentRepository,
@@ -1,6 +0,0 @@
import { PartialType } from "@nestjs/swagger";
import { CreateTicketDto } from "./create-ticket.dto";
export class UpdateTicketDto extends PartialType(CreateTicketDto){}
@@ -1,78 +0,0 @@
import { Body, Controller, Delete, Get, Param, Patch, Post, Query, UseGuards } from "@nestjs/common";
import { ApiBearerAuth, ApiOperation, ApiTags } from "@nestjs/swagger";
import { CreateTicketDto } from "../DTO/create-ticket.dto";
import { FindTicketQueryDto } from "../DTO/search-ticket-query.dto";
import { TicketService } from "../providers/tickets.service";
import { UserId } from "src/common/decorators";
import { AdminId } from "src/common/decorators/admin-id.decorator";
import { UpdateTicketDto } from "../DTO/update-ticket.dto";
import { AdminAuthGuard } from "src/modules/auth/guards/adminAuth.guard";
import { AuthGuard } from "src/modules/auth/guards/auth.guard";
@Controller()
@ApiTags("Tickets")
@ApiBearerAuth()
export class TicketController {
constructor(private readonly ticketsService: TicketService) { }
@Post('public/ticket/ref/:id')
@UseGuards(AuthGuard)
@ApiOperation({ summary: "create ticket ==> user route" })
createTicket(@Param('id') id: string, @Body() createDto: CreateTicketDto, @UserId() userId: string) {
return this.ticketsService.createTicketAsUser(id, createDto, userId);
}
@Get('public/ticket/ref/:id')
@UseGuards(AuthGuard)
@ApiOperation({ summary: "Get all order item tickets ==> user route" })
getTickets(@Query() queryDto: FindTicketQueryDto, @Param('id') id: string, @UserId() userId: string) {
return this.ticketsService.getTickets(id, queryDto, userId);
}
@Patch('public/ticket/:id')
@UseGuards(AuthGuard)
@ApiOperation({ summary: "Delete Ticket ==> admin route" })
updateTicket(@Param('id') id: string, @UserId() userId: string, @Body() body: UpdateTicketDto) {
return this.ticketsService.updateTicketAsUser(id, userId, body);
}
@Delete('public/ticket/:id')
@ApiOperation({ summary: "Delete Ticket ==> admin route" })
@UseGuards(AuthGuard)
deleteTicket(@Param('id') id: string, @UserId() userId: string) {
return this.ticketsService.deleteTicketAsUSer(id, userId);
}
/*=========================== Admin ============================== */
@Post('admin/ticket/ref/:id')
@UseGuards(AdminAuthGuard)
@ApiOperation({ summary: "create ticket ==> admin route" })
createTicketAsAdmin(@Param('id') itemId: string, @Body() createDto: CreateTicketDto, @AdminId() adminId: string) {
return this.ticketsService.createTicketAsAdmin(itemId, createDto, adminId);
}
@Get('admin/ticket/ref/:id')
@UseGuards(AdminAuthGuard)
@ApiOperation({ summary: "Get all order item tickets ==> admin route" })
getTicketsAsAdmin(@Query() queryDto: FindTicketQueryDto, @Param('id') itemId: string) {
return this.ticketsService.getTickets(itemId, queryDto);
}
@Patch('admin/ticket/:id')
@UseGuards(AdminAuthGuard)
@ApiOperation({ summary: "Update Ticket ==> admin route" })
updateTicketAsAdmin(@Param('id') id: string, @AdminId() adminId: string, @Body() body: UpdateTicketDto) {
return this.ticketsService.updateTicketAsAdmin(id, adminId, body);
}
@Delete('admin/ticket/:id')
@UseGuards(AdminAuthGuard)
@ApiOperation({ summary: "Delete Ticket ==> admin route" })
deleteTicketAsAdmin(@Param('id') id: string, @AdminId() adminId: string) {
return this.ticketsService.deleteTicketAsAdmin(id, adminId);
}
}
-25
View File
@@ -1,25 +0,0 @@
import { forwardRef, Module } from "@nestjs/common";
import { Ticket } from "./entities/ticket.entity";
import { TicketService } from "./providers/tickets.service";
import { TicketRepository } from "./repositories/tickets.repository";
import { TicketController } from "./controller/ticket.controller";
import { MikroOrmModule } from "@mikro-orm/nestjs";
import { AdminModule } from "../admin/admin.module";
import { UserModule } from "../user/user.module";
import { JwtModule } from "@nestjs/jwt";
@Module({
imports: [
// forwardRef(() => OrderModule),
MikroOrmModule.forFeature([Ticket]),
AdminModule,
UserModule,
JwtModule.register({})
],
providers: [TicketService, TicketRepository],
controllers: [TicketController],
exports: [TicketService, TicketRepository],
})
export class TicketModule { }