Files
dsc-api/src/modules/blogs/providers/blogs.service.ts
T
mahyargdz d69755a690 fix: bug
2025-04-23 15:04:03 +03:30

350 lines
12 KiB
TypeScript
Executable File

import { BadRequestException, Injectable } from "@nestjs/common";
import { Not } from "typeorm";
import { AdminMessage, BlogMessage, CommonMessage } from "../../../common/enums/message.enum";
import { CategoryListSearchQueryDto } from "../../danak-services/DTO/category-search-query.dto";
import { UsersService } from "../../users/providers/users.service";
import { BlogCommentQueryDto } from "../DTO/blog-comment-query.dto";
import { CreateBlogDto } from "../DTO/create-blog.dto";
import { CreateBlogCategoryDto } from "../DTO/create-category.dto";
import { CreateCommentDto } from "../DTO/create-comment.dto";
import { BlogListSearchQueryDto, BlogSearchQueryDto } from "../DTO/search-blog-query.dto";
import { UpdateBlogDto } from "../DTO/update-blog.dto";
import { UpdateBlogCategoryDto } from "../DTO/update-category.dto";
import { UpdateCommentStatusDto } from "../DTO/update-comment-status.dto";
import { CommentStatus } from "../enums/comment-status.enum";
import { BlogCategoriesRepository } from "../repositories/blog-categories.repository";
import { BlogCommentsRepository } from "../repositories/blog-comments.repository";
import { BlogsRepository } from "../repositories/blogs.repository";
@Injectable()
export class BlogsService {
constructor(
private readonly blogsRepository: BlogsRepository,
private readonly blogCommentsRepository: BlogCommentsRepository,
private readonly blogCategoriesRepository: BlogCategoriesRepository,
private readonly usersService: UsersService,
) {}
//*********************************** */
async createCategory(createCategoryDto: CreateBlogCategoryDto) {
const existingCategory = await this.blogCategoriesRepository.findOneBy({ title: createCategoryDto.title });
if (existingCategory) throw new BadRequestException(BlogMessage.CATEGORY_ALREADY_EXISTS);
const category = await this.blogCategoriesRepository.createCategory(createCategoryDto);
return {
message: CommonMessage.CREATED,
category,
};
}
//*********************************** */
async updateCategory(id: string, updateCategoryDto: UpdateBlogCategoryDto) {
const category = await this.findCategoryById(id);
if (updateCategoryDto.title) {
await this.checkCategoryExists(updateCategoryDto.title, id);
}
await this.blogCategoriesRepository.save({ ...category, ...updateCategoryDto });
return {
message: CommonMessage.UPDATE_SUCCESS,
category,
};
}
//*********************************** */
async deleteCategory(id: string, userId: string) {
const isSuperAdmin = await this.usersService.isSuperAdmin(userId);
if (!isSuperAdmin) throw new BadRequestException(AdminMessage.NOT_ALLOWED);
const category = await this.blogCategoriesRepository.findOneBy({ id });
if (!category) throw new BadRequestException(BlogMessage.CATEGORY_NOT_FOUND);
const blogs = await this.blogsRepository.find({ where: { category: { id } }, take: 2 });
if (blogs.length > 0) throw new BadRequestException(BlogMessage.CATEGORY_HAS_BLOGS);
await this.blogCategoriesRepository.remove(category);
return {
message: CommonMessage.DELETED,
};
}
//*********************************** */
async toggleCategoryStatus(id: string) {
const category = await this.findCategoryById(id);
//
category.isActive = !category.isActive;
await this.blogCategoriesRepository.save(category);
//
return {
message: CommonMessage.UPDATE_SUCCESS,
category,
};
}
//*********************************** */
async getCategory(id: string) {
const category = await this.findCategoryById(id);
return { category };
}
//*********************************** */
async getCategoriesUserSide() {
const categories = await this.blogCategoriesRepository.getCategoriesUserSide();
return { categories };
}
//*********************************** */
async getCategories(queryDto: CategoryListSearchQueryDto) {
const [categories, count] = await this.blogCategoriesRepository.getCategories(queryDto);
return { categories, count, paginate: true };
}
//*********************************** */
async createBlog(createBlogDto: CreateBlogDto, authorId: string) {
const existingBlog = await this.blogsRepository.findOne({ where: { title: createBlogDto.title } });
if (existingBlog) throw new BadRequestException(BlogMessage.BLOG_ALREADY_EXISTS);
const category = await this.findCategoryById(createBlogDto.categoryId);
const slug = this.generateSlug(createBlogDto.slug);
const blog = this.blogsRepository.create({
...createBlogDto,
author: { id: authorId },
category,
slug,
});
await this.blogsRepository.save(blog);
return {
message: CommonMessage.CREATED,
blog,
};
}
//*********************************** */
async updateBlog(id: string, updateBlogDto: UpdateBlogDto) {
const blog = await this.findBlogById(id);
if (updateBlogDto.title) {
const existBlog = await this.blogsRepository.findOne({ where: { title: updateBlogDto.title, id: Not(id) } });
if (existBlog) throw new BadRequestException(BlogMessage.BLOG_ALREADY_EXISTS);
}
if (updateBlogDto.categoryId) {
const category = await this.findCategoryById(updateBlogDto.categoryId);
blog.category = category;
}
if (updateBlogDto.slug) {
const existBlog = await this.blogsRepository.findOne({ where: { slug: updateBlogDto.slug, id: Not(id) } });
if (existBlog) throw new BadRequestException(BlogMessage.BLOG_ALREADY_EXISTS);
}
await this.blogsRepository.save({
...blog,
...updateBlogDto,
slug: this.generateSlug(updateBlogDto.slug ?? blog.slug),
});
return {
message: CommonMessage.UPDATE_SUCCESS,
blog,
};
}
//*********************************** */
async deleteBlog(id: string, userId: string) {
const isSuperAdmin = await this.usersService.isSuperAdmin(userId);
if (!isSuperAdmin) throw new BadRequestException(AdminMessage.NOT_ALLOWED);
const blog = await this.blogsRepository.findOneBy({ id });
if (!blog) throw new BadRequestException(BlogMessage.BLOG_NOT_FOUND);
await this.blogsRepository.softDelete({ id });
return {
message: CommonMessage.DELETED,
};
}
//*********************************** */
async getBlogById(id: string, isAdmin: boolean = false) {
const blog = await this.findBlogById(id);
if (isAdmin) return { blog };
blog.viewCount += 1;
await this.blogsRepository.save(blog);
const comments = await this.blogCommentsRepository.findBlogCommentsByBlogId(id);
return { blog, comments };
}
//*********************************** */
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) return { blog };
blog.viewCount += 1;
await this.blogsRepository.save(blog);
const comments = await this.blogCommentsRepository.findBlogCommentsByBlogId(blog.id);
return { blog, comments };
}
//*********************************** */
async getBlogsPublic(queryDto: BlogSearchQueryDto) {
const [blogs, count] = await this.blogsRepository.getBlogsForUserSide(queryDto);
//;
return {
blogs,
count,
paginate: true,
};
}
//*********************************** */
async getCombinedBlogs() {
const [pinnedBlogs, mostVisitedBlogs] = await Promise.all([
this.blogsRepository.getPinnedBlogs(),
this.blogsRepository.getMostVisitedBlogs(),
]);
return { pinnedBlogs, mostVisitedBlogs };
}
//*********************************** */
async getBlogList(queryDto: BlogListSearchQueryDto) {
const [blogs, count] = await this.blogsRepository.getBlogListForAdmin(queryDto);
return { blogs, count, paginate: true };
}
//*********************************** */
async createComment(blogId: string, createCommentDto: CreateCommentDto, userId: string) {
const blog = await this.findBlogById(blogId);
const { user } = await this.usersService.findOneById(userId);
const comment = this.blogCommentsRepository.create({
...createCommentDto,
blog,
user,
status: CommentStatus.PENDING,
});
await this.blogCommentsRepository.save(comment);
return {
message: CommonMessage.CREATED,
comment,
};
}
//*********************************** */
async updateCommentStatus(commentId: string, updateCommentStatusDto: UpdateCommentStatusDto) {
const comment = await this.blogCommentsRepository.findOneById(commentId);
if (!comment) throw new BadRequestException(BlogMessage.COMMENT_NOT_FOUND);
comment.status = updateCommentStatusDto.status;
await this.blogCommentsRepository.save(comment);
return {
message: CommonMessage.UPDATE_SUCCESS,
comment,
};
}
//*********************************** */
async getBlogCommentsForAdmin(blogId: string) {
const comments = await this.blogCommentsRepository.findBlogCommentsForAdmin(blogId);
return { comments };
}
//*********************************** */
async getAllCommentForAdmin(queryDto: BlogCommentQueryDto) {
const [comments, count] = await this.blogCommentsRepository.getAllCommentsForAdmin(queryDto);
return { comments, count, paginate: true };
}
//*********************************** */
private generateSlug(slug: string): string {
if (!slug) return "";
// Replace spaces and special characters with hyphens, preserve Farsi characters
return slug
.trim()
.replace(/[&\\#,+()$~%.'":*?<>{}]/g, "") // Remove special characters
.replace(/\s+/g, "-") // Replace spaces with hyphens
.replace(/-+/g, "-") // Replace multiple hyphens with single hyphen
.trim();
}
//*********************************** */
private async checkCategoryExists(title: string, id?: string) {
const existingCategory = await this.blogCategoriesRepository.findOneBy({ title, ...(id && { id: Not(id) }) });
if (existingCategory) throw new BadRequestException(BlogMessage.CATEGORY_ALREADY_EXISTS);
}
//*********************************** */
private async findCategoryById(id: string) {
const category = await this.blogCategoriesRepository.findOneById(id);
if (!category) throw new BadRequestException(BlogMessage.CATEGORY_NOT_FOUND);
return category;
}
//*********************************** */
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 };
}
//*********************************** */
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 };
}
//*********************************** */
async toggleBlogStatus(id: string) {
const blog = await this.findBlogById(id);
blog.isActive = !blog.isActive;
//
await this.blogsRepository.save(blog);
return { message: CommonMessage.UPDATE_SUCCESS, blog };
}
//*********************************** */
private async findBlogById(id: string) {
const blog = await this.blogsRepository.findOneById(id);
if (!blog) throw new BadRequestException(BlogMessage.BLOG_NOT_FOUND);
return blog;
}
}