diff --git a/src/common/enums/message.enum.ts b/src/common/enums/message.enum.ts index f8f1e2f..a493234 100644 --- a/src/common/enums/message.enum.ts +++ b/src/common/enums/message.enum.ts @@ -146,14 +146,34 @@ export const enum TicketMessageEnum { TITLE_REQUIRED = "عنوان تیکت مورد نیاز است", TITLE_STRING = "عنوان تیکت باید یک رشته باشد", TITLE_LENGTH = "عنوان تیکت باید بین ۳ تا ۱۵۰ کاراکتر باشد", + SUBJECT_REQUIRED = "موضوع تیکت اجباری می‌باشد", + SUBJECT_STRING = "موضوع تیکت باید رشته باشد", + SUBJECT_LENGTH = "موضوع تیکت باید بین ۳ تا ۱۵۰ کاراکتر باشد", + PRIORITY_REQUIRED = "اولویت تیکت اجباری می‌باشد", + PRIORITY_INVALID = "اولویت تیکت باید یکی از مقادیر LOW، MEDIUM یا HIGH باشد", + CATEGORY_ID_REQUIRED = "شناسه دسته‌بندی نمی‌تواند خالی باشد", + CATEGORY_ID_SHOULD_BE_UUID = "شناسه دسته‌بندی باید یک UUID معتبر باشد", + DANAK_SERVICE_ID_REQUIRED = "شناسه سرویس داناک اجباری است", + DANAK_SERVICE_ID_SHOULD_BE_UUID = "شناسه سرویس داناک باید یک UUID معتبر باشد", + MESSAGE_REQUIRED = "متن پیام تیکت اجباری است", + MESSAGE_STRING = "متن پیام باید یک رشته باشد", + MESSAGE_LENGTH = "متن پیام باید بین ۵ تا ۵۰۰ کاراکتر باشد", + CATEGORY_EXIST = "دسته‌بندی با این نام قبلاً ثبت شده است", + CATEGORY_CREATED = "دسته‌بندی با موفقیت ایجاد شد", + CATEGORY_NOT_FOUND = "دسته‌بندی یافت نشد", USER_GROUP_ID_NOT_EMPTY = "شناسه گروه کاربری نمی‌تواند خالی باشد", + USER_GROUP_ID_SHOULD_BE_UUID = "شناسه گروه کاربری باید یک UUID معتبر باشد", + IS_ACTIVE_REQUIRED = "وضعیت تیکت مورد نیاز است", + IS_ACTIVE_SHOULD_BE_BOOLEAN = "وضعیت تیکت باید یک مقدار بولی (true/false) باشد", + CREATED = "تیکت با موفقیت ساخته شد", DESCRIPTION_REQUIRED = "توضیحات تیکت مورد نیاز است", DESCRIPTION_STRING = "توضیحات تیکت باید یک رشته باشد", DESCRIPTION_LENGTH = "توضیحات تیکت باید بین ۳ تا ۵۰۰ کاراکتر باشد", - USER_GROUP_ID_SHOULD_BE_UUID = "شناسه گروه کاربری باید یک یو یو آی دی باشد", - IS_ACTIVE_REQUIRED = "وضعیت تیکت مورد نیاز است", - IS_ACTIVE_SHOULD_BE_BOOLEAN = "وضعیت تیکت باید یک بولین باشد", - CATEGORY_EXIST = "دسته بندی با این نام قبلا ثبت شده است", - CATEGORY_CREATED = "دسته بندی با موفقیت ایجاد شد", - CATEGORY_NOT_FOUND = "دسته بندی یافت نشد", + CONTENT_REQUIRED = "محتوای پیام تیکت مورد نیاز است", + ATTACHMENT_REQUIRED = "آدرس فایل پیوست تیکت مورد نیاز است", + ATTACHMENT_SHOULD_BE_URL = "آدرس فایل پیوست تیکت باید یوآرال باشد", + CONTENT_STRING = "محتوای پیام تیکت باید یک رشته باشد", + MESSAGE_CREATED = "پیام تیکت با موفقیت ایجاد شد", + TICKET_NOT_FOUND = "تیکت مورد نظر یافت نشد", + CLOSED = "تیکت با موفقیت بسته شد", } diff --git a/src/modules/danak-services/DTO/danak-services-search-query.dto.ts b/src/modules/danak-services/DTO/danak-services-search-query.dto.ts new file mode 100644 index 0000000..4ffd82c --- /dev/null +++ b/src/modules/danak-services/DTO/danak-services-search-query.dto.ts @@ -0,0 +1,23 @@ +import { ApiPropertyOptional } from "@nestjs/swagger"; +import { IsEnum, IsOptional, IsString } from "class-validator"; + +import { PaginationDto } from "../../../common/DTO/pagination.dto"; +import { CategoryMessage } from "../../../common/enums/message.enum"; +import { ServiceStatus } from "../enums/service-status.enum"; + +export class DanakServicesSearchQueryDto extends PaginationDto { + @IsOptional() + @IsString({ message: CategoryMessage.CAT_ID_SHOULD_BE_UUID }) + @ApiPropertyOptional({ description: "Category id", example: "8b1e8b1e-8b1e-8b1e-8b1e-8b1e8b1e8b1e" }) + categoryId?: string; + + @IsOptional() + @IsEnum(ServiceStatus) + @ApiPropertyOptional({ description: "services status", enum: ServiceStatus, example: ServiceStatus.ACTIVE }) + status?: ServiceStatus; + + @IsOptional() + @IsString({ message: CategoryMessage.SEARCH_QUERY_STRING }) + @ApiPropertyOptional({ description: "Search query", example: "search query" }) + q?: string; +} diff --git a/src/modules/danak-services/danak-services.controller.ts b/src/modules/danak-services/danak-services.controller.ts index 4316409..c18d131 100644 --- a/src/modules/danak-services/danak-services.controller.ts +++ b/src/modules/danak-services/danak-services.controller.ts @@ -4,6 +4,7 @@ import { ApiOperation, ApiTags } from "@nestjs/swagger"; import { CategoryListSearchQueryDto, CategorySearchQueryDto } from "./DTO/category-search-query.dto"; import { CreateCategoryDto } from "./DTO/create-category.dto"; import { CreateServiceDto } from "./DTO/create-service.dto"; +import { DanakServicesSearchQueryDto } from "./DTO/danak-services-search-query.dto"; import { DanakServicesService } from "./providers/danak-services.service"; import { AuthGuards } from "../../common/decorators/auth-guard.decorator"; import { Pagination } from "../../common/decorators/pagination.decorator"; @@ -61,6 +62,14 @@ export class DanakServicesController { return this.danakServicesService.createService(createDto); } + @AuthGuards() + @ApiOperation({ summary: "get all danak services ==> admin route" }) + @Roles(RoleEnum.ADMIN) + @Get("list") + getServices(@Query() queryDto: DanakServicesSearchQueryDto) { + return this.danakServicesService.getServicesList(queryDto); + } + @AuthGuards() @Roles(RoleEnum.USER) @ApiOperation({ summary: "get all user purchased danak services" }) diff --git a/src/modules/danak-services/entities/danak-service.entity.ts b/src/modules/danak-services/entities/danak-service.entity.ts index 30b36c5..a8bc5e1 100644 --- a/src/modules/danak-services/entities/danak-service.entity.ts +++ b/src/modules/danak-services/entities/danak-service.entity.ts @@ -53,7 +53,7 @@ export class DanakService extends BaseEntity { }) category: DanakServiceCategory; - @OneToMany(() => DanakServiceImage, (danakServiceImage) => danakServiceImage.danakService, { eager: true, cascade: true }) + @OneToMany(() => DanakServiceImage, (danakServiceImage) => danakServiceImage.danakService, { cascade: true }) images: DanakServiceImage[]; @OneToMany(() => Announcement, (announcement) => announcement.service) diff --git a/src/modules/danak-services/providers/danak-services.service.ts b/src/modules/danak-services/providers/danak-services.service.ts index 7e05435..3040e67 100644 --- a/src/modules/danak-services/providers/danak-services.service.ts +++ b/src/modules/danak-services/providers/danak-services.service.ts @@ -1,5 +1,5 @@ import { BadRequestException, Injectable } from "@nestjs/common"; -import { FindOptionsWhere, IsNull } from "typeorm"; +import { Brackets, FindOptionsWhere, IsNull } from "typeorm"; import { ParamDto } from "../../../common/DTO/param.dto"; import { CategoryMessage, CommonMessage, ServiceMessage } from "../../../common/enums/message.enum"; @@ -7,6 +7,7 @@ import { PaginationUtils } from "../../utils/providers/pagination.utils"; import { CategoryListSearchQueryDto, CategorySearchQueryDto } from "../DTO/category-search-query.dto"; import { CreateCategoryDto } from "../DTO/create-category.dto"; import { CreateServiceDto } from "../DTO/create-service.dto"; +import { DanakServicesSearchQueryDto } from "../DTO/danak-services-search-query.dto"; import { DanakServiceCategory } from "../entities/danak-service-category.entity"; import { DanakServicesCategoryRepository } from "../repositories/danak-services-category.repository"; import { DanakServicesRepository } from "../repositories/danak-services.repository"; @@ -120,6 +121,43 @@ export class DanakServicesService { } /******************************************** */ + async getServicesList(queryDto: DanakServicesSearchQueryDto) { + const { limit, skip } = PaginationUtils(queryDto); + + const queryBuilder = this.danakServicesRepository + .createQueryBuilder("service") + .leftJoinAndSelect("service.category", "category") + .orderBy("service.createdAt", "DESC") + .skip(skip) + .take(limit); + + if (queryDto.status) { + queryBuilder.andWhere("service.status = :status", { status: queryDto.status }); + } + if (queryDto.categoryId) { + queryBuilder.andWhere("service.categoryId = :categoryId", { categoryId: queryDto.categoryId }); + } + + if (queryDto.q) { + queryBuilder.andWhere( + new Brackets((qb) => { + qb.where("service.name LIKE :q", { q: `%${queryDto.q}%` }) + .orWhere("service.description LIKE :q", { q: `%${queryDto.q}%` }) + .orWhere("service.softwareLanguage LIKE :q", { q: `%${queryDto.q}%` }) + .orWhere("service.author LIKE :q", { q: `%${queryDto.q}%` }); + }), + ); + } + const [services, count] = await queryBuilder.getManyAndCount(); + + return { + services, + count, + }; + } + + /******************************************** */ + async getServiceByName(name: string) { const danakService = await this.danakServicesRepository.findOneByName(name); if (!danakService) throw new BadRequestException(ServiceMessage.SERVICE_NOT_EXIST); diff --git a/src/modules/tickets/DTO/create-ticket-message.dto.ts b/src/modules/tickets/DTO/create-ticket-message.dto.ts new file mode 100644 index 0000000..481bb27 --- /dev/null +++ b/src/modules/tickets/DTO/create-ticket-message.dto.ts @@ -0,0 +1,17 @@ +import { ApiProperty } from "@nestjs/swagger"; +import { IsNotEmpty, IsOptional, IsString, IsUrl } from "class-validator"; + +import { TicketMessageEnum } from "../../../common/enums/message.enum"; + +export class CreateTicketMessageDto { + @IsNotEmpty({ message: TicketMessageEnum.CONTENT_REQUIRED }) + @IsString({ message: TicketMessageEnum.CONTENT_STRING }) + @ApiProperty({ description: "the content of message", example: "test message" }) + content: string; + + @IsOptional() + @IsNotEmpty({ message: TicketMessageEnum.ATTACHMENT_REQUIRED }) + @IsUrl({ protocols: ["http", "https"], require_protocol: true }, { message: TicketMessageEnum.ATTACHMENT_SHOULD_BE_URL }) + @ApiProperty({ description: "attachment url", example: "https://example.com/test.png" }) + attachmentUrl: string; +} diff --git a/src/modules/tickets/DTO/create-ticket-service.dto.ts b/src/modules/tickets/DTO/create-ticket-service.dto.ts deleted file mode 100644 index 05b1e9e..0000000 --- a/src/modules/tickets/DTO/create-ticket-service.dto.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { ApiProperty } from "@nestjs/swagger"; -import { IsEnum, IsNotEmpty, IsString, Length } from "class-validator"; - -import { TicketPriority } from "../enums/ticket-priority.enum"; - -export class CreateTicketDto { - @IsNotEmpty() - @IsString() - @Length(3, 150) - @ApiProperty() - title: string; - - @IsNotEmpty() - @IsString() - @Length(3, 150) - @ApiProperty() - subject: string; - - @IsNotEmpty() - @IsEnum(TicketPriority) - @ApiProperty({ enum: TicketPriority, example: TicketPriority.LOW, description: "LOW, MEDIUM, HIGH" }) - priority: TicketPriority; - - danakServiceId: string; - - categoryId: string; - - message: string; -} diff --git a/src/modules/tickets/DTO/create-ticket.dto.ts b/src/modules/tickets/DTO/create-ticket.dto.ts new file mode 100644 index 0000000..11f25a7 --- /dev/null +++ b/src/modules/tickets/DTO/create-ticket.dto.ts @@ -0,0 +1,41 @@ +import { ApiProperty } from "@nestjs/swagger"; +import { IsEnum, IsNotEmpty, IsOptional, IsString, IsUUID, Length } from "class-validator"; + +import { TicketMessageEnum } from "../../../common/enums/message.enum"; +import { TicketPriority } from "../enums/ticket-priority.enum"; + +export class CreateTicketDto { + @IsNotEmpty({ message: TicketMessageEnum.TITLE_REQUIRED }) + @IsString({ message: TicketMessageEnum.TITLE_STRING }) + @Length(3, 150, { message: TicketMessageEnum.TITLE_LENGTH }) + @ApiProperty({ description: "The ticket title", example: "Test title" }) + title: string; + + @IsNotEmpty({ message: TicketMessageEnum.SUBJECT_REQUIRED }) + @IsString({ message: TicketMessageEnum.SUBJECT_STRING }) + @Length(3, 150, { message: TicketMessageEnum.SUBJECT_LENGTH }) + @ApiProperty({ description: "Subject of the ticket", example: "Subject" }) + subject: string; + + @IsNotEmpty({ message: TicketMessageEnum.PRIORITY_REQUIRED }) + @IsEnum(TicketPriority, { message: TicketMessageEnum.PRIORITY_INVALID }) + @ApiProperty({ enum: TicketPriority, example: TicketPriority.LOW, description: "LOW, MEDIUM, HIGH" }) + priority: TicketPriority; + + @IsOptional() + @IsNotEmpty({ message: TicketMessageEnum.DANAK_SERVICE_ID_REQUIRED }) + @IsUUID("4", { message: TicketMessageEnum.DANAK_SERVICE_ID_SHOULD_BE_UUID }) + @ApiProperty({ description: "Service ID related to the ticket", example: "550e8400-e29b-41d4-a716-446655440000" }) + danakServiceId?: string; + + @IsNotEmpty({ message: TicketMessageEnum.CATEGORY_ID_REQUIRED }) + @IsUUID("4", { message: TicketMessageEnum.CATEGORY_ID_SHOULD_BE_UUID }) + @ApiProperty({ description: "Category ID of the ticket", example: "123e4567-e89b-12d3-a456-426614174000" }) + categoryId: string; + + @IsNotEmpty({ message: TicketMessageEnum.MESSAGE_REQUIRED }) + @IsString({ message: TicketMessageEnum.MESSAGE_STRING }) + @Length(5, 500, { message: TicketMessageEnum.MESSAGE_LENGTH }) + @ApiProperty({ description: "The message content of the ticket", example: "This is a detailed description of the issue." }) + message: string; +} diff --git a/src/modules/tickets/DTO/search-ticket-query.dto.ts b/src/modules/tickets/DTO/search-ticket-query.dto.ts new file mode 100644 index 0000000..020bc28 --- /dev/null +++ b/src/modules/tickets/DTO/search-ticket-query.dto.ts @@ -0,0 +1,12 @@ +import { ApiPropertyOptional } from "@nestjs/swagger"; +import { IsEnum, IsOptional } from "class-validator"; + +import { PaginationDto } from "../../../common/DTO/pagination.dto"; +import { TicketStatus } from "../enums/ticket-status.enum"; + +export class SearchTicketQueryDto extends PaginationDto { + @IsOptional() + @IsEnum(TicketStatus) + @ApiPropertyOptional({ enum: TicketStatus, description: "ticket status", example: TicketStatus.PENDING }) + status: TicketStatus; +} diff --git a/src/modules/tickets/entities/ticket.entity.ts b/src/modules/tickets/entities/ticket.entity.ts index 9c269a8..5942d98 100644 --- a/src/modules/tickets/entities/ticket.entity.ts +++ b/src/modules/tickets/entities/ticket.entity.ts @@ -1,4 +1,4 @@ -import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from "typeorm"; +import { Column, Entity, ManyToOne, OneToMany } from "typeorm"; import { TicketCategory } from "./ticket-category.entity"; import { TicketMessage } from "./ticket-message.entity"; @@ -25,21 +25,19 @@ export class Ticket extends BaseEntity { @Column({ type: "enum", enum: TicketPriority, nullable: false }) priority: TicketPriority; - @ManyToOne(() => DanakService, (danakService) => danakService.tickets, { onDelete: "RESTRICT", nullable: false }) + //TODO:set this to not nullable + @ManyToOne(() => DanakService, (danakService) => danakService.tickets, { onDelete: "RESTRICT", nullable: true }) danakService: DanakService; - @JoinColumn() @ManyToOne(() => User, (user) => user.tickets, { nullable: true }) assignedTo: User; - @JoinColumn() @ManyToOne(() => User, (user) => user.tickets, { onDelete: "CASCADE", nullable: false }) user: User; - @JoinColumn() @ManyToOne(() => TicketCategory, (category) => category.tickets, { onDelete: "RESTRICT", nullable: false }) category: TicketCategory; - @OneToMany(() => TicketMessage, (message) => message.ticket) + @OneToMany(() => TicketMessage, (message) => message.ticket, { cascade: true }) messages: TicketMessage[]; } diff --git a/src/modules/tickets/providers/tickets.service.ts b/src/modules/tickets/providers/tickets.service.ts index ad3a431..bd9acc8 100644 --- a/src/modules/tickets/providers/tickets.service.ts +++ b/src/modules/tickets/providers/tickets.service.ts @@ -6,14 +6,23 @@ import { CommonMessage, TicketMessageEnum } from "../../../common/enums/message. import { UsersService } from "../../users/providers/users.service"; import { PaginationUtils } from "../../utils/providers/pagination.utils"; import { CreateTicketCategoryDto } from "../DTO/create-ticket-category.dto"; +import { CreateTicketMessageDto } from "../DTO/create-ticket-message.dto"; +import { CreateTicketDto } from "../DTO/create-ticket.dto"; import { SearchTicketCategoryDto } from "../DTO/search-ticket-category.dto"; +import { SearchTicketQueryDto } from "../DTO/search-ticket-query.dto"; import { UpdateTicketCategoryDto } from "../DTO/update-ticket-category.dto"; +import { TicketMessage } from "../entities/ticket-message.entity"; +import { TicketStatus } from "../enums/ticket-status.enum"; import { TicketCategoryRepository } from "../repositories/tickets-category.repository"; +import { TicketMessagesRepository } from "../repositories/tickets-message.repository"; +import { TicketsRepository } from "../repositories/tickets.repository"; @Injectable() export class TicketsService { constructor( private readonly ticketsCategoryRepository: TicketCategoryRepository, + private readonly ticketsRepository: TicketsRepository, + private readonly ticketMessagesRepository: TicketMessagesRepository, private readonly usersService: UsersService, ) {} //******************************** */ @@ -93,5 +102,117 @@ export class TicketsService { //******************************** */ - async createTicket() {} + async createTicket(createDto: CreateTicketDto, userId: string) { + const { user } = await this.usersService.findOneById(userId); + const ticketCategory = await this.ticketsCategoryRepository.findCategoryById(createDto.categoryId); + if (!ticketCategory) throw new BadRequestException(TicketMessageEnum.CATEGORY_NOT_FOUND); + + // + const ticketMessage: Partial = { content: createDto.message, author: user }; + const ticket = this.ticketsRepository.create({ ...createDto, user, category: ticketCategory, messages: [ticketMessage] }); + + await this.ticketsRepository.save(ticket); + + return { + message: TicketMessageEnum.CREATED, + ticket, + }; + } + + //******************************** */ + + async getTickets(queryDto: SearchTicketQueryDto, userId: string) { + const { limit, skip } = PaginationUtils(queryDto); + + const findOptions = { + where: { + user: { id: userId }, + ...(queryDto.status && { status: queryDto.status }), + }, + relations: { + category: true, + user: true, + }, + order: { + createdAt: "DESC" as const, + }, + skip, + take: limit, + }; + + const [tickets, count] = await this.ticketsRepository.findAndCount(findOptions); + + return { + tickets, + count, + }; + } + + //******************************** */ + + async createTicketMessage(ticketId: string, createDto: CreateTicketMessageDto, userId: string) { + const ticket = await this.ticketsRepository.findTicketById(ticketId, userId); + if (!ticket) throw new BadRequestException(TicketMessageEnum.TICKET_NOT_FOUND); + // + const { user } = await this.usersService.findOneById(userId); + + const ticketMessage = this.ticketMessagesRepository.create({ ...createDto, author: user, ticket }); + + await this.ticketMessagesRepository.save(ticketMessage); + + return { + message: TicketMessageEnum.MESSAGE_CREATED, + ticketMessage, + }; + } + + //******************************** */ + + async getTicketMessages(ticketId: string, userId: string) { + const ticket = await this.ticketsRepository.findTicketById(ticketId, userId); + if (!ticket) throw new BadRequestException(TicketMessageEnum.TICKET_NOT_FOUND); + + const messages = await this.ticketMessagesRepository.findMessagesByTicketId(ticketId); + return { + messages, + }; + } + + //******************************** */ + + async closeTicketByUser(ticketId: string, userId: string) { + const ticket = await this.ticketsRepository.findTicketById(ticketId, userId); + if (!ticket) throw new BadRequestException(TicketMessageEnum.TICKET_NOT_FOUND); + + ticket.status = TicketStatus.CLOSED; + await this.ticketsRepository.save(ticket); + + return { + message: TicketMessageEnum.CLOSED, + }; + } + + //******************************** */ } + +// async getTickets(queryDto: SearchTicketQueryDto, userId: string) { +// const { limit, skip } = PaginationUtils(queryDto); +// //TODO:add danak-service to query +// const queryBuilder = this.ticketsRepository +// .createQueryBuilder("ticket") +// .leftJoinAndSelect("ticket.category", "category") +// .leftJoinAndSelect("ticket.user", "user") +// .where("user.id = :userId", { userId }) +// .orderBy("ticket.createdAt", "DESC"); + +// if (queryDto.status) { +// queryBuilder.andWhere("ticket.status = :status", { status: queryDto.status }); +// } + +// const [tickets, count] = await queryBuilder.skip(skip).take(limit).getManyAndCount(); + +// return { +// tickets, +// count, +// }; +// } diff --git a/src/modules/tickets/repositories/tickets-message.repository.ts b/src/modules/tickets/repositories/tickets-message.repository.ts index 04ef0c7..4f70570 100644 --- a/src/modules/tickets/repositories/tickets-message.repository.ts +++ b/src/modules/tickets/repositories/tickets-message.repository.ts @@ -9,4 +9,26 @@ export class TicketMessagesRepository extends Repository { constructor(@InjectRepository(TicketMessage) ticketMessagesRepository: Repository) { super(ticketMessagesRepository.target, ticketMessagesRepository.manager, ticketMessagesRepository.queryRunner); } + + async findMessagesByTicketId(ticketId: string): Promise { + return this.find({ + relations: { + author: true, + ticket: true, + }, + // select: { + // id: true, + // content: true, + // attachmentUrl: true, + // createdAt: true, + // author: { + // id: true, + // firstName: true, + // lastName: true, + // }, + // }, + where: { ticket: { id: ticketId } }, + order: { createdAt: "DESC" }, + }); + } } diff --git a/src/modules/tickets/repositories/tickets.repository.ts b/src/modules/tickets/repositories/tickets.repository.ts index f6e0076..dbd99c2 100644 --- a/src/modules/tickets/repositories/tickets.repository.ts +++ b/src/modules/tickets/repositories/tickets.repository.ts @@ -9,4 +9,8 @@ export class TicketsRepository extends Repository { constructor(@InjectRepository(Ticket) ticketsRepository: Repository) { super(ticketsRepository.target, ticketsRepository.manager, ticketsRepository.queryRunner); } + + async findTicketById(id: string, userId: string): Promise { + return this.findOneBy({ id, user: { id: userId } }); + } } diff --git a/src/modules/tickets/tickets.controller.ts b/src/modules/tickets/tickets.controller.ts index 5ddfc80..fa809f7 100644 --- a/src/modules/tickets/tickets.controller.ts +++ b/src/modules/tickets/tickets.controller.ts @@ -2,13 +2,18 @@ import { Body, Controller, Get, HttpCode, HttpStatus, Param, Patch, Post, Query import { ApiOperation, ApiTags } from "@nestjs/swagger"; import { CreateTicketCategoryDto } from "./DTO/create-ticket-category.dto"; +import { CreateTicketMessageDto } from "./DTO/create-ticket-message.dto"; +import { CreateTicketDto } from "./DTO/create-ticket.dto"; import { SearchTicketCategoryDto } from "./DTO/search-ticket-category.dto"; +import { SearchTicketQueryDto } from "./DTO/search-ticket-query.dto"; import { UpdateTicketCategoryDto } from "./DTO/update-ticket-category.dto"; import { TicketsService } from "./providers/tickets.service"; import { AuthGuards } from "../../common/decorators/auth-guard.decorator"; import { Pagination } from "../../common/decorators/pagination.decorator"; import { Roles } from "../../common/decorators/roles.decorator"; +import { UserDec } from "../../common/decorators/user.decorator"; import { ParamDto } from "../../common/DTO/param.dto"; +import { User } from "../users/entities/user.entity"; import { RoleEnum } from "../users/enums/role.enum"; @Controller("tickets") @@ -16,6 +21,8 @@ import { RoleEnum } from "../users/enums/role.enum"; export class TicketsController { constructor(private readonly ticketsService: TicketsService) {} + //----------------- ticket categories ------------------- + @ApiOperation({ summary: "Create ticket category => admin route" }) @AuthGuards() @Roles(RoleEnum.ADMIN) @@ -57,4 +64,47 @@ export class TicketsController { toggleCategoryStatus(@Param() paramDto: ParamDto) { return this.ticketsService.toggleCategoryStatus(paramDto); } + + //----------------- ticket and ticket messages ------------------- + + @ApiOperation({ summary: "create ticket ==> user route" }) + @AuthGuards() + @Roles(RoleEnum.USER) + @Post() + createTicket(@Body() createDto: CreateTicketDto, @UserDec() user: User) { + return this.ticketsService.createTicket(createDto, user.id); + } + + @ApiOperation({ summary: "Get all tickets of user ==> user route" }) + @AuthGuards() + @Roles(RoleEnum.USER) + @Pagination() + @Get() + getTickets(@Query() queryDto: SearchTicketQueryDto, @UserDec() user: User) { + return this.ticketsService.getTickets(queryDto, user.id); + } + + @ApiOperation({ summary: "create ticket messages" }) + @AuthGuards() + @Roles(RoleEnum.USER, RoleEnum.ADMIN) + @Post(":id/messages") + createTicketMessage(@Param() paramDto: ParamDto, @Body() createDto: CreateTicketMessageDto, @UserDec() user: User) { + return this.ticketsService.createTicketMessage(paramDto.id, createDto, user.id); + } + + @ApiOperation({ summary: "Get all ticket messages of user ==> user route" }) + @AuthGuards() + @Roles(RoleEnum.USER) + @Get(":id/messages") + getTicketMessages(@Param() paramDto: ParamDto, @UserDec() user: User) { + return this.ticketsService.getTicketMessages(paramDto.id, user.id); + } + + @ApiOperation({ summary: "close ticket by user ==> user route" }) + @AuthGuards() + @Roles(RoleEnum.USER) + @Get(":id/close") + closedTicketByUser(@Param() paramDto: ParamDto, @UserDec() user: User) { + return this.ticketsService.closeTicketByUser(paramDto.id, user.id); + } }