chore: criticism pagination
This commit is contained in:
@@ -132,4 +132,5 @@ export const enum CriticismMessage {
|
|||||||
CONTENT_IS_REQUIRED = "متن انتقادات مورد نیاز است",
|
CONTENT_IS_REQUIRED = "متن انتقادات مورد نیاز است",
|
||||||
CONTENT_IS_STRING = "متن انتقادات باید رشته باشد",
|
CONTENT_IS_STRING = "متن انتقادات باید رشته باشد",
|
||||||
NOT_FOUND = "انتقادی با این ایدی یافت نشد",
|
NOT_FOUND = "انتقادی با این ایدی یافت نشد",
|
||||||
|
SEARCH_QUERY_STRING = "رشته جستجو باید یک رشته باشد",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { ApiPropertyOptional } from "@nestjs/swagger";
|
||||||
|
import { IsDateString, IsOptional, IsString } from "class-validator";
|
||||||
|
|
||||||
|
import { PaginationDto } from "../../../common/DTO/pagination.dto";
|
||||||
|
import { CriticismMessage } from "../../../common/enums/message.enum";
|
||||||
|
|
||||||
|
export class SearchCriticismQueryDto extends PaginationDto {
|
||||||
|
@IsOptional()
|
||||||
|
@IsDateString()
|
||||||
|
@ApiPropertyOptional({ description: "since query", example: "2025-01-27" })
|
||||||
|
since?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsString({ message: CriticismMessage.SEARCH_QUERY_STRING })
|
||||||
|
@ApiPropertyOptional({ description: "Search query", example: "search query" })
|
||||||
|
q?: string;
|
||||||
|
}
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
import { Body, Controller, Delete, Get, Param, Post } from "@nestjs/common";
|
import { Body, Controller, Delete, Get, Param, Post, Query } from "@nestjs/common";
|
||||||
import { ApiOperation, ApiTags } from "@nestjs/swagger";
|
import { ApiOperation, ApiTags } from "@nestjs/swagger";
|
||||||
|
|
||||||
import { CreateCriticismDto } from "./DTO/create-criticism.dto";
|
import { CreateCriticismDto } from "./DTO/create-criticism.dto";
|
||||||
|
import { SearchCriticismQueryDto } from "./DTO/search-criticism-query.dto";
|
||||||
import { CriticismsService } from "./providers/criticisms.service";
|
import { CriticismsService } from "./providers/criticisms.service";
|
||||||
import { AuthGuards } from "../../common/decorators/auth-guard.decorator";
|
import { AuthGuards } from "../../common/decorators/auth-guard.decorator";
|
||||||
import { Roles } from "../../common/decorators/roles.decorator";
|
import { Roles } from "../../common/decorators/roles.decorator";
|
||||||
|
import { UserDec } from "../../common/decorators/user.decorator";
|
||||||
import { ParamDto } from "../../common/DTO/param.dto";
|
import { ParamDto } from "../../common/DTO/param.dto";
|
||||||
|
import { User } from "../users/entities/user.entity";
|
||||||
import { RoleEnum } from "../users/enums/role.enum";
|
import { RoleEnum } from "../users/enums/role.enum";
|
||||||
|
|
||||||
@Controller("criticisms")
|
@Controller("criticisms")
|
||||||
@@ -13,18 +16,19 @@ import { RoleEnum } from "../users/enums/role.enum";
|
|||||||
export class CriticismController {
|
export class CriticismController {
|
||||||
constructor(private readonly criticismService: CriticismsService) {}
|
constructor(private readonly criticismService: CriticismsService) {}
|
||||||
|
|
||||||
|
@AuthGuards()
|
||||||
@ApiOperation({ summary: "Create a new criticism" })
|
@ApiOperation({ summary: "Create a new criticism" })
|
||||||
@Post()
|
@Post()
|
||||||
create(@Body() createDto: CreateCriticismDto) {
|
create(@Body() createDto: CreateCriticismDto, @UserDec() user: User) {
|
||||||
return this.criticismService.create(createDto);
|
return this.criticismService.create(createDto, user.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@Roles(RoleEnum.ADMIN)
|
@Roles(RoleEnum.ADMIN)
|
||||||
@ApiOperation({ summary: "Get all Criticism ===> login as admin" })
|
@ApiOperation({ summary: "Get all Criticism ===> login as admin" })
|
||||||
@Get()
|
@Get()
|
||||||
findAll() {
|
findAll(@Query() queryDto: SearchCriticismQueryDto) {
|
||||||
return this.criticismService.findAll();
|
return this.criticismService.findAll(queryDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
|
|||||||
@@ -7,9 +7,10 @@ import { Criticism } from "./entities/criticism.entity";
|
|||||||
import { CriticismsService } from "./providers/criticisms.service";
|
import { CriticismsService } from "./providers/criticisms.service";
|
||||||
import { CriticismFileRepository } from "./repositories/criticisms-file.repository";
|
import { CriticismFileRepository } from "./repositories/criticisms-file.repository";
|
||||||
import { CriticismRepository } from "./repositories/criticisms.repository";
|
import { CriticismRepository } from "./repositories/criticisms.repository";
|
||||||
|
import { UsersModule } from "../users/users.module";
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [TypeOrmModule.forFeature([Criticism, CriticismFile])],
|
imports: [TypeOrmModule.forFeature([Criticism, CriticismFile]), UsersModule],
|
||||||
providers: [CriticismsService, CriticismRepository, CriticismFileRepository],
|
providers: [CriticismsService, CriticismRepository, CriticismFileRepository],
|
||||||
controllers: [CriticismController],
|
controllers: [CriticismController],
|
||||||
exports: [],
|
exports: [],
|
||||||
|
|||||||
@@ -1,19 +1,24 @@
|
|||||||
import { Column, Entity, OneToMany } from "typeorm";
|
import { Column, Entity, Index, ManyToOne, OneToMany } from "typeorm";
|
||||||
|
|
||||||
import { CriticismFile } from "./criticism-file.entity";
|
import { CriticismFile } from "./criticism-file.entity";
|
||||||
import { BaseEntity } from "../../../common/entities/base.entity";
|
import { BaseEntity } from "../../../common/entities/base.entity";
|
||||||
|
import { User } from "../../users/entities/user.entity";
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class Criticism extends BaseEntity {
|
export class Criticism extends BaseEntity {
|
||||||
@Column({ type: "int", generated: "identity", insert: false })
|
@Column({ type: "int", generated: "identity", insert: false })
|
||||||
numericId: number;
|
numericId: number;
|
||||||
|
|
||||||
|
@Index("title")
|
||||||
@Column({ type: "varchar", length: 150, nullable: false })
|
@Column({ type: "varchar", length: 150, nullable: false })
|
||||||
title: string;
|
title: string;
|
||||||
|
|
||||||
@Column({ type: "text", nullable: false })
|
@Column({ type: "text", nullable: false })
|
||||||
content: string;
|
content: string;
|
||||||
|
|
||||||
|
@ManyToOne(() => User, (user) => user.criticisms, { nullable: false, onDelete: "CASCADE" })
|
||||||
|
user: User;
|
||||||
|
|
||||||
@Column({ type: "boolean", default: false })
|
@Column({ type: "boolean", default: false })
|
||||||
isRead: boolean;
|
isRead: boolean;
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,27 @@
|
|||||||
import { BadRequestException, Injectable } from "@nestjs/common";
|
import { BadRequestException, Injectable } from "@nestjs/common";
|
||||||
|
|
||||||
import { CommonMessage, CriticismMessage } from "../../../common/enums/message.enum";
|
import { CommonMessage, CriticismMessage } from "../../../common/enums/message.enum";
|
||||||
|
import { UsersService } from "../../users/providers/users.service";
|
||||||
|
import { PaginationUtils } from "../../utils/providers/pagination.utils";
|
||||||
import { CreateCriticismDto } from "../DTO/create-criticism.dto";
|
import { CreateCriticismDto } from "../DTO/create-criticism.dto";
|
||||||
|
import { SearchCriticismQueryDto } from "../DTO/search-criticism-query.dto";
|
||||||
import { CriticismRepository } from "../repositories/criticisms.repository";
|
import { CriticismRepository } from "../repositories/criticisms.repository";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CriticismsService {
|
export class CriticismsService {
|
||||||
constructor(private readonly criticismRepository: CriticismRepository) {}
|
constructor(
|
||||||
|
private readonly criticismRepository: CriticismRepository,
|
||||||
|
private readonly usersService: UsersService,
|
||||||
|
) {}
|
||||||
|
|
||||||
async create(createDto: CreateCriticismDto) {
|
async create(createDto: CreateCriticismDto, userId: string) {
|
||||||
|
const { user } = await this.usersService.findOneById(userId);
|
||||||
const files = createDto.files.map((file) => {
|
const files = createDto.files.map((file) => {
|
||||||
return { fileUrl: file };
|
return { fileUrl: file };
|
||||||
});
|
});
|
||||||
const criticism = this.criticismRepository.create({
|
const criticism = this.criticismRepository.create({
|
||||||
...createDto,
|
...createDto,
|
||||||
|
user,
|
||||||
files,
|
files,
|
||||||
});
|
});
|
||||||
await this.criticismRepository.save(criticism);
|
await this.criticismRepository.save(criticism);
|
||||||
@@ -25,10 +33,25 @@ export class CriticismsService {
|
|||||||
|
|
||||||
//##################################### ##
|
//##################################### ##
|
||||||
|
|
||||||
async findAll() {
|
async findAll(queryDto: SearchCriticismQueryDto) {
|
||||||
const criticisms = await this.criticismRepository.find();
|
const { limit, skip } = PaginationUtils(queryDto);
|
||||||
|
|
||||||
|
const queryBuilder = this.criticismRepository.createQueryBuilder("criticism");
|
||||||
|
|
||||||
|
if (queryDto.since) {
|
||||||
|
queryBuilder.andWhere("criticism.createdAt >= :since", { since: queryDto.since });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queryDto.q) {
|
||||||
|
queryBuilder.andWhere("criticism.title LIKE :q", { q: `%${queryDto.q}%` });
|
||||||
|
}
|
||||||
|
queryBuilder.orderBy("criticism.createdAt", "DESC");
|
||||||
|
|
||||||
|
const [criticisms, count] = await queryBuilder.skip(skip).take(limit).getManyAndCount();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
criticisms,
|
criticisms,
|
||||||
|
count,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Column, Entity, ManyToMany, ManyToOne, OneToMany } from "typeorm";
|
|||||||
import { Role } from "./role.entity";
|
import { Role } from "./role.entity";
|
||||||
import { UserGroup } from "./user-group.entity";
|
import { UserGroup } from "./user-group.entity";
|
||||||
import { BaseEntity } from "../../../common/entities/base.entity";
|
import { BaseEntity } from "../../../common/entities/base.entity";
|
||||||
|
import { Criticism } from "../../criticisms/entities/criticism.entity";
|
||||||
import { TicketMessage } from "../../tickets/entities/ticket-message.entity";
|
import { TicketMessage } from "../../tickets/entities/ticket-message.entity";
|
||||||
import { Ticket } from "../../tickets/entities/ticket.entity";
|
import { Ticket } from "../../tickets/entities/ticket.entity";
|
||||||
|
|
||||||
@@ -43,4 +44,7 @@ export class User extends BaseEntity {
|
|||||||
|
|
||||||
@ManyToMany(() => UserGroup, (group) => group.users)
|
@ManyToMany(() => UserGroup, (group) => group.users)
|
||||||
groups: UserGroup[];
|
groups: UserGroup[];
|
||||||
|
|
||||||
|
@OneToMany(() => Criticism, (criticism) => criticism.user)
|
||||||
|
criticisms: Criticism[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { BadRequestException, Injectable, Logger } from "@nestjs/common";
|
import { BadRequestException, Injectable } from "@nestjs/common";
|
||||||
import slugify from "slugify";
|
import slugify from "slugify";
|
||||||
import { In, Not } from "typeorm";
|
import { In, Not } from "typeorm";
|
||||||
|
|
||||||
@@ -31,7 +31,6 @@ export class UsersService {
|
|||||||
name: true,
|
name: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
private logger = new Logger(UsersService.name);
|
|
||||||
constructor(
|
constructor(
|
||||||
private userRepository: UserRepository,
|
private userRepository: UserRepository,
|
||||||
private roleRepository: RoleRepository,
|
private roleRepository: RoleRepository,
|
||||||
@@ -40,8 +39,15 @@ export class UsersService {
|
|||||||
|
|
||||||
/************************************************************ */
|
/************************************************************ */
|
||||||
|
|
||||||
|
async findOneById(id: string) {
|
||||||
|
const user = await this.userRepository.findOneBy({ id });
|
||||||
|
if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND);
|
||||||
|
return { user };
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************ */
|
||||||
|
|
||||||
async getMe(userId: string) {
|
async getMe(userId: string) {
|
||||||
this.logger.debug("sss");
|
|
||||||
const user = await this.userRepository.findOne({ where: { id: userId }, select: this.userSelect });
|
const user = await this.userRepository.findOne({ where: { id: userId }, select: this.userSelect });
|
||||||
if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND);
|
if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND);
|
||||||
return { user };
|
return { user };
|
||||||
|
|||||||
Reference in New Issue
Block a user