chore: update referral logic

This commit is contained in:
mahyargdz
2025-04-15 15:50:31 +03:30
parent bd4d9dbf0d
commit fb8f16deb4
19 changed files with 234 additions and 262 deletions
+4 -5
View File
@@ -6,25 +6,24 @@ import { BlogMessage } from "../../../common/enums/message.enum";
export class CreateBlogDto {
@IsNotEmpty({ message: BlogMessage.TITLE_REQUIRED })
@IsString({ message: BlogMessage.TITLE_STRING })
@MaxLength(150, { message: BlogMessage.TITLE_MAX_LENGTH })
@MaxLength(250, { message: BlogMessage.TITLE_MAX_LENGTH })
@ApiProperty({ description: "Title of the blog", example: "Blog Title" })
title: string;
@IsNotEmpty({ message: BlogMessage.SLUG_REQUIRED })
@IsString({ message: BlogMessage.SLUG_STRING })
@MaxLength(150, { message: BlogMessage.SLUG_MAX_LENGTH })
@MaxLength(250, { message: BlogMessage.SLUG_MAX_LENGTH })
@ApiProperty({ description: "Slug of the blog", example: "blog-title" })
slug: string;
@IsNotEmpty({ message: BlogMessage.PREVIEW_CONTENT_REQUIRED })
@IsString({ message: BlogMessage.PREVIEW_CONTENT_STRING })
@MaxLength(150, { message: BlogMessage.PREVIEW_CONTENT_MAX_LENGTH })
@MaxLength(600, { message: BlogMessage.PREVIEW_CONTENT_MAX_LENGTH })
@ApiProperty({ description: "Preview content of the blog", example: "Preview content of the blog" })
previewContent: string;
@IsNotEmpty({ message: BlogMessage.CONTENT_REQUIRED })
@IsString({ message: BlogMessage.CONTENT_STRING })
@MaxLength(600, { message: BlogMessage.CONTENT_MAX_LENGTH })
@ApiProperty({ description: "Content of the blog", example: "Content of the blog" })
content: string;
@@ -36,7 +35,7 @@ export class CreateBlogDto {
@IsNotEmpty({ message: BlogMessage.META_TITLE_REQUIRED })
@IsString({ message: BlogMessage.META_TITLE_STRING })
@MaxLength(60, { message: BlogMessage.META_TITLE_MAX_LENGTH })
@MaxLength(250, { message: BlogMessage.META_TITLE_MAX_LENGTH })
@ApiProperty({ description: "Meta title of the blog", example: "Meta title of the blog" })
metaTitle: string;
@@ -20,6 +20,6 @@ export class BlogCategory extends BaseEntity {
@OneToMany(() => Blog, (blog) => blog.category)
blogs: Blog[];
@DeleteDateColumn({ type: "timestamptz" })
@DeleteDateColumn()
deletedAt?: Date;
}
@@ -19,6 +19,6 @@ export class BlogComment extends BaseEntity {
@ManyToOne(() => User, (user) => user.blogComments)
user: User;
@ManyToOne(() => Blog, (blog) => blog.comments)
@ManyToOne(() => Blog, (blog) => blog.comments, { onDelete: "CASCADE" })
blog: Blog;
}
+8 -8
View File
@@ -7,10 +7,10 @@ import { User } from "../../users/entities/user.entity";
@Entity()
export class Blog extends BaseEntity {
@Column({ type: "varchar", length: 150, unique: true })
@Column({ type: "varchar", length: 250, unique: true })
title: string;
@Column({ type: "varchar", length: 150, unique: true })
@Column({ type: "varchar", length: 250, unique: true })
slug: string;
@Column({ type: "text" })
@@ -19,13 +19,13 @@ export class Blog extends BaseEntity {
@Column({ type: "text" })
content: string;
@Column({ type: "varchar", length: 150, nullable: true })
@Column({ type: "varchar", length: 250, nullable: true })
imageUrl: string;
@Column({ type: "varchar", length: 100, nullable: true })
@Column({ type: "varchar", length: 250, nullable: true })
metaTitle: string;
@Column({ type: "varchar", length: 160, nullable: true })
@Column({ type: "varchar", length: 250, nullable: true })
metaDescription: string;
@Column({ type: "simple-array", nullable: true })
@@ -40,15 +40,15 @@ export class Blog extends BaseEntity {
@Column({ type: "boolean", default: false })
isPinned: boolean;
@ManyToOne(() => User, (user) => user.blogs)
@ManyToOne(() => User, (user) => user.blogs, { onDelete: "CASCADE", nullable: false })
author: User;
@ManyToOne(() => BlogCategory, (category) => category.blogs)
@ManyToOne(() => BlogCategory, (category) => category.blogs, { nullable: false })
category: BlogCategory;
@OneToMany(() => BlogComment, (comment) => comment.blog)
comments: BlogComment[];
@DeleteDateColumn({ type: "timestamptz" })
@DeleteDateColumn()
deletedAt?: Date;
}
+27 -16
View File
@@ -56,9 +56,13 @@ export class BlogsService {
//*********************************** */
async deleteCategory(id: string) {
await this.findCategoryById(id);
const category = await this.blogCategoriesRepository.findOneBy({ id });
if (!category) throw new BadRequestException(BlogMessage.CATEGORY_NOT_FOUND);
await this.blogCategoriesRepository.softDelete(id);
await this.blogCategoriesRepository.softDelete({ id });
return {
message: CommonMessage.DELETED,
};
}
//*********************************** */
@@ -70,7 +74,10 @@ export class BlogsService {
await this.blogCategoriesRepository.save(category);
//
return { message: CommonMessage.UPDATE_SUCCESS, category };
return {
message: CommonMessage.UPDATE_SUCCESS,
category,
};
}
//*********************************** */
@@ -146,21 +153,24 @@ export class BlogsService {
//*********************************** */
async deleteBlog(id: string) {
await this.findBlogById(id);
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 };
await this.blogsRepository.softDelete({ id });
return {
message: CommonMessage.DELETED,
};
}
//*********************************** */
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);
}
if (isAdmin) return { blog };
blog.viewCount += 1;
await this.blogsRepository.save(blog);
const comments = await this.blogCommentsRepository.findBlogCommentsByBlogId(id);
return { blog, comments };
}
@@ -170,12 +180,13 @@ export class BlogsService {
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);
}
if (!isAdmin) return { blog };
return { blog };
blog.viewCount += 1;
await this.blogsRepository.save(blog);
const comments = await this.blogCommentsRepository.findBlogCommentsByBlogId(blog.id);
return { blog, comments };
}
//*********************************** */
@@ -13,73 +13,66 @@ export class BlogsRepository extends Repository<Blog> {
}
async findOneById(id: string): Promise<Blog | null> {
return this.findOne({
where: { id, deletedAt: IsNull() },
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,
isActive: true,
isPinned: true,
category: {
id: true,
title: true,
iconUrl: true,
description: true,
},
author: {
id: true,
firstName: true,
lastName: true,
},
},
});
const queryBuilder = this.createQueryBuilder("blog")
.leftJoinAndSelect("blog.author", "author")
.leftJoinAndSelect("blog.category", "category")
.where("blog.id = :id", { id })
.andWhere("blog.deletedAt IS NULL")
.select([
"blog.id",
"blog.title",
"blog.previewContent",
"blog.metaTitle",
"blog.metaDescription",
"blog.imageUrl",
"blog.slug",
"blog.createdAt",
"blog.content",
"blog.tags",
"blog.viewCount",
"blog.isActive",
"blog.isPinned",
"category.id",
"category.title",
"category.iconUrl",
"category.description",
"author.id",
"author.firstName",
"author.lastName",
]);
return queryBuilder.getOne();
}
async findOneBySlug(slug: string): Promise<Blog | null> {
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,
},
},
});
const queryBuilder = this.createQueryBuilder("blog")
.leftJoinAndSelect("blog.author", "author")
.leftJoinAndSelect("blog.category", "category")
.where("blog.slug = :slug", { slug })
.andWhere("blog.deletedAt IS NULL")
.andWhere("blog.isActive = :isActive", { isActive: true })
.select([
"blog.id",
"blog.title",
"blog.previewContent",
"blog.metaTitle",
"blog.metaDescription",
"blog.imageUrl",
"blog.slug",
"blog.createdAt",
"blog.content",
"blog.tags",
"blog.viewCount",
"category.id",
"category.title",
"category.iconUrl",
"category.description",
"author.id",
"author.firstName",
"author.lastName",
]);
return queryBuilder.getOne();
}
async fineOneByTitle(title: string): Promise<Blog | null> {