diff --git a/src/app.module.ts b/src/app.module.ts index c735a41..43e45d8 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -11,6 +11,7 @@ import { databaseConfigs } from "./configs/typeorm.config"; import { HTTPLogger } from "./core/middlewares/logger.middleware"; import { AnnoucementsModule } from "./modules/announcements/announcement.module"; import { AuthModule } from "./modules/auth/auth.module"; +import { CriticismModule } from "./modules/criticisms/criticisms.module"; import { DanakServicesModule } from "./modules/danak-services/danak-services.module"; import { TicketsModule } from "./modules/tickets/tickets.module"; import { UploaderModule } from "./modules/uploader/uploader.module"; @@ -29,6 +30,7 @@ import { UsersModule } from "./modules/users/users.module"; DanakServicesModule, AnnoucementsModule, UploaderModule, + CriticismModule, ], controllers: [], providers: [], diff --git a/src/common/enums/message.enum.ts b/src/common/enums/message.enum.ts index 9cbd211..89fabb8 100644 --- a/src/common/enums/message.enum.ts +++ b/src/common/enums/message.enum.ts @@ -68,6 +68,7 @@ export const enum CommonMessage { VALID_FOR_CHOOSE = "معتبر برای انتخاب", UPDATE_SUCCESS = "با موفقیت به روز رسانی شد", CREATED = "با موفقیت ایجاد شد", + DELETED = "با موفقیت حذف شد", ID_REQUIRED = "شناسه مورد نیاز است", ID_SHOULD_BE_UUID = "شناسه باید یک یو یو آی دی باشد", } @@ -124,3 +125,10 @@ export const enum AnnouncementMessage { CONTENT_IS_STRING = "متن اطلاعیه باید رشته باشد", CONTENT_MUST_BE_LONGER = "متن اطلاعیه باید حداقل ۱۰ کاراکتر باشد", } + +export const enum CriticismMessage { + TITLE_IS_REQUIRED = "عنوان انتقادات مورد نیاز است", + TITLE_STRING = "عنوان انتقادات باید یک رشته باشد", + CONTENT_IS_REQUIRED = "متن انتقادات مورد نیاز است", + CONTENT_IS_STRING = "متن انتقادات باید رشته باشد", +} diff --git a/src/modules/criticisms/DTO/create-criticism.dto.ts b/src/modules/criticisms/DTO/create-criticism.dto.ts new file mode 100644 index 0000000..e34bf8e --- /dev/null +++ b/src/modules/criticisms/DTO/create-criticism.dto.ts @@ -0,0 +1,25 @@ +import { ApiProperty } from "@nestjs/swagger"; +import { IsNotEmpty, IsOptional, IsString } from "class-validator"; + +import { CriticismMessage } from "../../../common/enums/message.enum"; + +export class CreateCriticismDto { + @IsNotEmpty({ message: CriticismMessage.TITLE_IS_REQUIRED }) + @IsString({ message: CriticismMessage.TITLE_STRING }) + @ApiProperty({ type: String, description: "title of criticism", example: "انتقاد بابت مشکلات" }) + title: string; + + @IsNotEmpty({ message: CriticismMessage.CONTENT_IS_REQUIRED }) + @IsString({ message: CriticismMessage.CONTENT_IS_STRING }) + @ApiProperty({ type: String, description: "description of criticism", example: "متن انتقاد" }) + content: string; + + @IsOptional() + @IsNotEmpty() + @IsString({ each: true }) + @ApiProperty({ + description: "The ulr of the criticism files", + example: ["https://example.com/image1.png", "https://example.com/image2.png"], + }) + files: string[]; +} diff --git a/src/modules/criticisms/criticisms.controller.ts b/src/modules/criticisms/criticisms.controller.ts new file mode 100644 index 0000000..e6033c2 --- /dev/null +++ b/src/modules/criticisms/criticisms.controller.ts @@ -0,0 +1,37 @@ +import { Body, Controller, Delete, Get, Param, Post } from "@nestjs/common"; +import { ApiOperation, ApiTags } from "@nestjs/swagger"; + +import { CreateCriticismDto } from "./DTO/create-criticism.dto"; +import { CriticismsService } from "./providers/criticisms.service"; +import { AuthGuards } from "../../common/decorators/auth-guard.decorator"; +import { Roles } from "../../common/decorators/roles.decorator"; +import { ParamDto } from "../../common/DTO/param.dto"; +import { RoleEnum } from "../users/enums/role.enum"; + +@Controller("criticisms") +@ApiTags("Criticism") +export class CriticismController { + constructor(private readonly criticismService: CriticismsService) {} + + @ApiOperation({ summary: "Create a new criticism" }) + @Post() + create(@Body() createDto: CreateCriticismDto) { + return this.criticismService.create(createDto); + } + + @AuthGuards() + @Roles(RoleEnum.ADMIN) + @ApiOperation({ summary: "Get all Criticism ===> login as admin" }) + @Get() + findAll() { + return this.criticismService.findAll(); + } + + @AuthGuards() + @Roles(RoleEnum.ADMIN) + @ApiOperation({ summary: "Delete one Criticism with id ===> login as admin" }) + @Delete(":id") + delete(@Param() paramDto: ParamDto) { + return this.criticismService.delete(paramDto.id); + } +} diff --git a/src/modules/criticisms/criticisms.module.ts b/src/modules/criticisms/criticisms.module.ts new file mode 100644 index 0000000..ea3110e --- /dev/null +++ b/src/modules/criticisms/criticisms.module.ts @@ -0,0 +1,17 @@ +import { Module } from "@nestjs/common"; +import { TypeOrmModule } from "@nestjs/typeorm"; + +import { CriticismController } from "./criticisms.controller"; +import { CriticismFile } from "./entities/criticism-file.entity"; +import { Criticism } from "./entities/criticism.entity"; +import { CriticismsService } from "./providers/criticisms.service"; +import { CriticismFileRepository } from "./repositories/criticisms-file.repository"; +import { CriticismRepository } from "./repositories/criticisms.repository"; + +@Module({ + imports: [TypeOrmModule.forFeature([Criticism, CriticismFile])], + providers: [CriticismsService, CriticismRepository, CriticismFileRepository], + controllers: [CriticismController], + exports: [], +}) +export class CriticismModule {} diff --git a/src/modules/criticisms/entities/criticism-file.entity.ts b/src/modules/criticisms/entities/criticism-file.entity.ts new file mode 100644 index 0000000..b54d3d6 --- /dev/null +++ b/src/modules/criticisms/entities/criticism-file.entity.ts @@ -0,0 +1,13 @@ +import { Column, Entity, ManyToOne } from "typeorm"; + +import { Criticism } from "./criticism.entity"; +import { BaseEntity } from "../../../common/entities/base.entity"; + +@Entity() +export class CriticismFile extends BaseEntity { + @Column({ type: "varchar", length: 255 }) + fileUrl: string; + + @ManyToOne(() => Criticism, (criticism) => criticism.files, { nullable: false, onDelete: "CASCADE" }) + criticism: Criticism[]; +} diff --git a/src/modules/criticisms/entities/criticism.entity.ts b/src/modules/criticisms/entities/criticism.entity.ts new file mode 100644 index 0000000..33fb606 --- /dev/null +++ b/src/modules/criticisms/entities/criticism.entity.ts @@ -0,0 +1,19 @@ +import { Column, Entity, OneToMany } from "typeorm"; + +import { CriticismFile } from "./criticism-file.entity"; +import { BaseEntity } from "../../../common/entities/base.entity"; + +@Entity() +export class Criticism extends BaseEntity { + @Column({ type: "int", generated: "identity", insert: false }) + numericId: number; + + @Column({ type: "varchar", length: 150, nullable: false }) + title: string; + + @Column({ type: "text", nullable: false }) + content: string; + + @OneToMany(() => CriticismFile, (criticismFile) => criticismFile.criticism, { eager: true, cascade: true }) + files: CriticismFile[]; +} diff --git a/src/modules/criticisms/providers/criticisms.service.ts b/src/modules/criticisms/providers/criticisms.service.ts new file mode 100644 index 0000000..367615d --- /dev/null +++ b/src/modules/criticisms/providers/criticisms.service.ts @@ -0,0 +1,38 @@ +import { BadRequestException, Injectable } from "@nestjs/common"; + +import { CommonMessage } from "../../../common/enums/message.enum"; +import { CreateCriticismDto } from "../DTO/create-criticism.dto"; +import { CriticismRepository } from "../repositories/criticisms.repository"; + +@Injectable() +export class CriticismsService { + constructor(private readonly criticismRepository: CriticismRepository) {} + + async create(createDto: CreateCriticismDto) { + const files = createDto.files.map((file) => { + return { fileUrl: file }; + }); + const criticism = this.criticismRepository.create({ + ...createDto, + files, + }); + await this.criticismRepository.save(criticism); + return { + message: CommonMessage.CREATED, + criticism, + }; + } + + async findAll() { + return await this.criticismRepository.find({}); + } + + async delete(id: string) { + const criticism = await this.criticismRepository.findOneBy({ id }); + if (!criticism) throw new BadRequestException(); + await this.criticismRepository.remove(criticism); + return { + message: CommonMessage.DELETED, + }; + } +} diff --git a/src/modules/criticisms/repositories/criticisms-file.repository.ts b/src/modules/criticisms/repositories/criticisms-file.repository.ts new file mode 100644 index 0000000..8265909 --- /dev/null +++ b/src/modules/criticisms/repositories/criticisms-file.repository.ts @@ -0,0 +1,12 @@ +import { Injectable } from "@nestjs/common"; +import { InjectRepository } from "@nestjs/typeorm"; +import { Repository } from "typeorm"; + +import { CriticismFile } from "../entities/criticism-file.entity"; + +@Injectable() +export class CriticismFileRepository extends Repository { + constructor(@InjectRepository(CriticismFile) criticismFileRepository: Repository) { + super(criticismFileRepository.target, criticismFileRepository.manager, criticismFileRepository.queryRunner); + } +} diff --git a/src/modules/criticisms/repositories/criticisms.repository.ts b/src/modules/criticisms/repositories/criticisms.repository.ts new file mode 100644 index 0000000..387076f --- /dev/null +++ b/src/modules/criticisms/repositories/criticisms.repository.ts @@ -0,0 +1,12 @@ +import { Injectable } from "@nestjs/common"; +import { InjectRepository } from "@nestjs/typeorm"; +import { Repository } from "typeorm"; + +import { Criticism } from "../entities/criticism.entity"; + +@Injectable() +export class CriticismRepository extends Repository { + constructor(@InjectRepository(Criticism) criticismRepository: Repository) { + super(criticismRepository.target, criticismRepository.manager, criticismRepository.queryRunner); + } +} diff --git a/src/modules/tickets/entities/ticket.entity.ts b/src/modules/tickets/entities/ticket.entity.ts index 8d6761f..7b0376e 100644 --- a/src/modules/tickets/entities/ticket.entity.ts +++ b/src/modules/tickets/entities/ticket.entity.ts @@ -1,11 +1,11 @@ import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from "typeorm"; import { TicketCategory } from "./ticket-category.entity"; +import { TicketMessage } from "./ticket-message.entity"; import { BaseEntity } from "../../../common/entities/base.entity"; import { User } from "../../users/entities/user.entity"; import { TicketPriority } from "../enums/ticket-priority.enum"; import { TicketStatus } from "../enums/ticket-status.enum"; -import { TicketMessage } from "./ticket-message.entity"; @Entity() export class Ticket extends BaseEntity {