diff --git a/src/common/enums/message.enum.ts b/src/common/enums/message.enum.ts index e1e638b..0269178 100755 --- a/src/common/enums/message.enum.ts +++ b/src/common/enums/message.enum.ts @@ -664,4 +664,5 @@ export const enum BlogMessage { INVALID_DATE = "تاریخ نامعتبر است", IS_ACTIVE_SHOULD_BE_1_0 = "وضعیت فعال بودن باید یکی از ۱ یا ۰ باشد", SEARCH_QUERY_STRING = "رشته جستجو باید یک رشته باشد", + IS_PINNED_SHOULD_BE_A_BOOLEAN = "وضعیت سنجاق بودن باید یک بولین باشد", } diff --git a/src/modules/blogs/DTO/create-blog.dto.ts b/src/modules/blogs/DTO/create-blog.dto.ts index 03655d1..675f714 100644 --- a/src/modules/blogs/DTO/create-blog.dto.ts +++ b/src/modules/blogs/DTO/create-blog.dto.ts @@ -1,5 +1,5 @@ -import { ApiProperty } from "@nestjs/swagger"; -import { ArrayMinSize, IsArray, IsBoolean, IsNotEmpty, IsString, IsUUID, MaxLength } from "class-validator"; +import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger"; +import { ArrayMinSize, IsArray, IsBoolean, IsNotEmpty, IsOptional, IsString, IsUUID, MaxLength } from "class-validator"; import { BlogMessage } from "../../../common/enums/message.enum"; @@ -55,4 +55,12 @@ export class CreateBlogDto { @IsBoolean({ message: BlogMessage.IS_ACTIVE_SHOULD_BE_A_BOOLEAN }) @ApiProperty({ description: "Is active of the blog", example: true }) isActive: boolean; + + @ApiPropertyOptional({ + description: "Whether the blog is pinned or not", + default: false, + }) + @IsOptional() + @IsBoolean({ message: BlogMessage.IS_PINNED_SHOULD_BE_A_BOOLEAN }) + isPinned?: boolean; } diff --git a/src/modules/blogs/controllers/blogs.controller.ts b/src/modules/blogs/controllers/blogs.controller.ts index 006ef6f..ff5a68b 100644 --- a/src/modules/blogs/controllers/blogs.controller.ts +++ b/src/modules/blogs/controllers/blogs.controller.ts @@ -61,6 +61,12 @@ export class BlogsController { return this.blogsService.getMostVisitedBlogs(); } + @ApiOperation({ summary: "Get most pinned blogs" }) + @SkipAuth() + @Get("pinned") + getPinnedBlogs() { + return this.blogsService.getPinnedBlogs(); + } @ApiOperation({ summary: "Create a new blog (admin route)" }) @Post() @AdminRoute() diff --git a/src/modules/blogs/entities/blog.entity.ts b/src/modules/blogs/entities/blog.entity.ts index e675416..67e52e8 100644 --- a/src/modules/blogs/entities/blog.entity.ts +++ b/src/modules/blogs/entities/blog.entity.ts @@ -37,6 +37,9 @@ export class Blog extends BaseEntity { @Column({ type: "int", default: 0 }) viewCount: number; + @Column({ type: "boolean", default: false }) + isPinned: boolean; + @ManyToOne(() => User, (user) => user.blogs) author: User; diff --git a/src/modules/blogs/providers/blogs.service.ts b/src/modules/blogs/providers/blogs.service.ts index aa0b4ba..6f8a2b0 100644 --- a/src/modules/blogs/providers/blogs.service.ts +++ b/src/modules/blogs/providers/blogs.service.ts @@ -262,4 +262,16 @@ export class BlogsService { const blogs = await this.blogsRepository.getMostVisitedBlogs(); return { blogs }; } + + async getPinnedBlogs() { + const blogs = await this.blogsRepository.getPinnedBlogs(); + return { blogs }; + } + + async togglePinnedStatus(id: string) { + const blog = await this.findBlogById(id); + blog.isPinned = !blog.isPinned; + await this.blogsRepository.save(blog); + return { message: CommonMessage.UPDATE_SUCCESS, blog }; + } } diff --git a/src/modules/blogs/repositories/blogs.repository.ts b/src/modules/blogs/repositories/blogs.repository.ts index 67b81b3..6ac6771 100644 --- a/src/modules/blogs/repositories/blogs.repository.ts +++ b/src/modules/blogs/repositories/blogs.repository.ts @@ -191,4 +191,25 @@ export class BlogsRepository extends Repository { .take(limit) .getMany(); } + + async getPinnedBlogs(limit: number = 4) { + return this.createQueryBuilder("blog") + .where("blog.deletedAt IS NULL") + .andWhere("blog.isActive = :isActive", { isActive: true }) + .andWhere("blog.isPinned = :isPinned", { isPinned: true }) + .select([ + "blog.id", + "blog.title", + "blog.previewContent", + "blog.metaTitle", + "blog.metaDescription", + "blog.imageUrl", + "blog.slug", + "blog.createdAt", + "blog.viewCount", + ]) + .orderBy("blog.createdAt", "DESC") + .take(limit) + .getMany(); + } }