diff --git a/src/modules/blogs/controllers/blogs.controller.ts b/src/modules/blogs/controllers/blogs.controller.ts index a8c7cc4..006ef6f 100644 --- a/src/modules/blogs/controllers/blogs.controller.ts +++ b/src/modules/blogs/controllers/blogs.controller.ts @@ -54,6 +54,13 @@ export class BlogsController { return this.blogsService.getBlogBySlug(paramDto.slug); } + @ApiOperation({ summary: "Get most visited blogs" }) + @SkipAuth() + @Get("most-visited") + getMostVisitedBlogs() { + return this.blogsService.getMostVisitedBlogs(); + } + @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 bb77347..e675416 100644 --- a/src/modules/blogs/entities/blog.entity.ts +++ b/src/modules/blogs/entities/blog.entity.ts @@ -34,6 +34,9 @@ export class Blog extends BaseEntity { @Column({ type: "boolean", default: true }) isActive: boolean; + @Column({ type: "int", default: 0 }) + viewCount: number; + @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 5f90889..aa0b4ba 100644 --- a/src/modules/blogs/providers/blogs.service.ts +++ b/src/modules/blogs/providers/blogs.service.ts @@ -148,16 +148,28 @@ export class BlogsService { } //*********************************** */ - async getBlogById(id: string) { + async getBlogById(id: string, isAdmin: boolean = false) { const blog = await this.findBlogById(id); const comments = await this.blogCommentsRepository.findBlogCommentsByBlogId(id); + + if (!isAdmin) { + blog.viewCount += 1; + await this.blogsRepository.save(blog); + } + return { blog, comments }; } //*********************************** */ - async getBlogBySlug(slug: string) { + async getBlogBySlug(slug: string, isAdmin: boolean = false) { const blog = await this.blogsRepository.findOneBySlug(slug); if (!blog) throw new BadRequestException(BlogMessage.BLOG_NOT_FOUND); + + if (!isAdmin) { + blog.viewCount += 1; + await this.blogsRepository.save(blog); + } + return { blog }; } //*********************************** */ @@ -238,4 +250,16 @@ export class BlogsService { if (!blog) throw new BadRequestException(BlogMessage.BLOG_NOT_FOUND); return blog; } + + async incrementViewCount(id: string) { + const blog = await this.findBlogById(id); + blog.viewCount += 1; + await this.blogsRepository.save(blog); + return { message: "View count incremented successfully" }; + } + + async getMostVisitedBlogs() { + const blogs = await this.blogsRepository.getMostVisitedBlogs(); + return { blogs }; + } } diff --git a/src/modules/blogs/repositories/blogs.repository.ts b/src/modules/blogs/repositories/blogs.repository.ts index 1e87ea5..67b81b3 100644 --- a/src/modules/blogs/repositories/blogs.repository.ts +++ b/src/modules/blogs/repositories/blogs.repository.ts @@ -30,6 +30,7 @@ export class BlogsRepository extends Repository { createdAt: true, content: true, tags: true, + viewCount: true, category: { id: true, title: true, @@ -48,6 +49,34 @@ export class BlogsRepository extends Repository { async findOneBySlug(slug: string): Promise { return this.findOne({ where: { slug, deletedAt: IsNull(), isActive: true }, + relations: { + author: true, + category: true, + }, + select: { + id: true, + title: true, + previewContent: true, + metaTitle: true, + metaDescription: true, + imageUrl: true, + slug: true, + createdAt: true, + content: true, + tags: true, + viewCount: true, + category: { + id: true, + title: true, + iconUrl: true, + description: true, + }, + author: { + id: true, + firstName: true, + lastName: true, + }, + }, }); } @@ -75,6 +104,7 @@ export class BlogsRepository extends Repository { "blog.imageUrl", "blog.slug", "blog.createdAt", + "blog.viewCount", "category.id", "category.iconUrl", "category.title", @@ -133,4 +163,32 @@ export class BlogsRepository extends Repository { return queryBuilder.getManyAndCount(); } + + async getMostVisitedBlogs(limit: number = 5) { + return this.createQueryBuilder("blog") + .where("blog.deletedAt IS NULL") + .andWhere("blog.isActive = :isActive", { isActive: true }) + .leftJoinAndSelect("blog.category", "category") + .leftJoinAndSelect("blog.author", "author") + .select([ + "blog.id", + "blog.title", + "blog.previewContent", + "blog.metaTitle", + "blog.metaDescription", + "blog.imageUrl", + "blog.slug", + "blog.createdAt", + "blog.viewCount", + "category.id", + "category.iconUrl", + "category.title", + "author.id", + "author.firstName", + "author.lastName", + ]) + .orderBy("blog.viewCount", "DESC") + .take(limit) + .getMany(); + } }