Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 90f056ea6c | |||
| 3c05ab394a | |||
| e24d7938d0 | |||
| f140031266 | |||
| 503695b28c | |||
| b75765a6d8 | |||
| 5fdd69acb8 | |||
| 80ee6798b7 | |||
| aa43136946 | |||
| cb4f5907e5 | |||
| a861cba5c3 |
@@ -1,5 +1,5 @@
|
||||
import { IsEnum, IsString } from 'class-validator';
|
||||
import { BlogPermission } from 'src/blog/bloga.permission.enum';
|
||||
import { BlogPermission } from 'src/blog/blog.permission.enum';
|
||||
|
||||
export class CreateBlogDto {
|
||||
@IsString()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { IsEnum, IsString } from 'class-validator';
|
||||
import { BlogPermission } from 'src/blog/bloga.permission.enum';
|
||||
import { BlogPermission } from 'src/blog/blog.permission.enum';
|
||||
|
||||
export class UpdateBlogDto {
|
||||
@IsString()
|
||||
|
||||
@@ -22,7 +22,7 @@ export class BlogController {
|
||||
constructor(
|
||||
private readonly blogService: BlogService,
|
||||
private readonly userService: UserService,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
@Get()
|
||||
getBlogs() {
|
||||
@@ -71,7 +71,13 @@ export class BlogController {
|
||||
const blog = await this.blogService.findById(id);
|
||||
if (!blog) throw new BadRequestException('文章不存在');
|
||||
|
||||
return await this.blogService.getComments(id);
|
||||
/** @todo 对文章可读性进行更详细的判定 */
|
||||
|
||||
if (!blog.permissions.includes(BlogPermission.Public) && !blog.permissions.includes(BlogPermission.ByPassword)) {
|
||||
throw new BadRequestException('文章不存在或未公开');
|
||||
}
|
||||
|
||||
return await this.blogService.getComments(blog);
|
||||
}
|
||||
|
||||
// 该接口允许匿名评论,但仍需验证userId合法性
|
||||
@@ -87,6 +93,10 @@ export class BlogController {
|
||||
const blog = await this.blogService.findById(id);
|
||||
if (!blog) throw new BadRequestException('文章不存在');
|
||||
|
||||
if (!blog.permissions.includes(BlogPermission.AllowComments)) {
|
||||
throw new BadRequestException('作者关闭了该文章的评论功能');
|
||||
}
|
||||
|
||||
const user = userId ? await this.userService.findById(userId) : null;
|
||||
|
||||
const ip = req.headers['x-forwarded-for'] || req.ip;
|
||||
|
||||
@@ -2,4 +2,5 @@ export enum BlogPermission {
|
||||
Public = 'Public',
|
||||
ByPassword = 'ByPassword',
|
||||
List = 'List',
|
||||
AllowComments = 'AllowComments',
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ export class BlogService {
|
||||
private readonly blogRepository: Repository<Blog>,
|
||||
@InjectRepository(BlogComment)
|
||||
private readonly blogCommentRepository: Repository<BlogComment>,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
async list(
|
||||
option: {
|
||||
@@ -95,24 +95,40 @@ export class BlogService {
|
||||
await this.blogRepository.increment({ id }, 'viewCount', 1);
|
||||
}
|
||||
|
||||
async getComments(blogId: string) {
|
||||
const blog = await this.findById(blogId);
|
||||
if (!blog) {
|
||||
throw new Error('文章不存在');
|
||||
}
|
||||
|
||||
return this.blogCommentRepository.find({
|
||||
where: { blog },
|
||||
async getComments(blog: Blog) {
|
||||
const comments = await this.blogCommentRepository.find({
|
||||
where: { blog: { id: blog.id } },
|
||||
relations: ['user'],
|
||||
order: {
|
||||
createdAt: 'DESC',
|
||||
},
|
||||
});
|
||||
|
||||
return comments.map(comment => {
|
||||
const { blog, user, ...rest } = comment;
|
||||
return {
|
||||
...rest,
|
||||
user: user ? {
|
||||
userId: user.userId,
|
||||
username: user.username,
|
||||
nickname: user.nickname,
|
||||
} : null,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async createComment(comment: Partial<BlogComment>) {
|
||||
const newComment = this.blogCommentRepository.create(comment);
|
||||
return this.blogCommentRepository.save(newComment);
|
||||
const savedComment = await this.blogCommentRepository.save(newComment, {});
|
||||
const { blog, user, ...commentWithoutBlog } = savedComment;
|
||||
return {
|
||||
...commentWithoutBlog,
|
||||
user: user ? {
|
||||
userId: user.userId,
|
||||
username: user.username,
|
||||
nickname: user.nickname,
|
||||
} : null,
|
||||
};
|
||||
}
|
||||
|
||||
hashPassword(password: string) {
|
||||
|
||||
@@ -45,6 +45,6 @@ export class Blog {
|
||||
password_hash: string | null;
|
||||
|
||||
// 关系
|
||||
@OneToMany(() => BlogComment, (blog) => blog.id)
|
||||
@OneToMany(() => BlogComment, (comment) => comment.blog)
|
||||
comments: BlogComment[];
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ export function BlogCommentTool({ blogId, onInsertComment, replayTarget, handleC
|
||||
if ((error as { statusCode: number }).statusCode === 429) {
|
||||
return toast.error('操作太频繁了,稍后再试吧')
|
||||
}
|
||||
toast.error('发布失败')
|
||||
toast.error(`${(error as Error).message || '发布失败'}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ export default function Blog() {
|
||||
img: ({ src }) => (
|
||||
<PhotoProvider className="w-full">
|
||||
<PhotoView src={src as string}>
|
||||
<Image src={src as string} alt="加载失败" />
|
||||
<Image src={src as string} width={0} height={0} style={{ width: '100%', height: 'auto' }} unoptimized alt="加载失败" />
|
||||
</PhotoView>
|
||||
</PhotoProvider>
|
||||
),
|
||||
|
||||
@@ -15,6 +15,10 @@ const blogPermissions = [
|
||||
permission: BlogPermission.List,
|
||||
localText: '显示在列表中',
|
||||
},
|
||||
{
|
||||
permission: BlogPermission.AllowComments,
|
||||
localText: '允许评论',
|
||||
}
|
||||
] as const;
|
||||
|
||||
interface BlogPermissionCheckBoxsProps {
|
||||
|
||||
@@ -2,4 +2,5 @@ export enum BlogPermission {
|
||||
Public = 'Public',
|
||||
ByPassword = 'ByPassword',
|
||||
List = 'List',
|
||||
AllowComments = 'AllowComments',
|
||||
}
|
||||
Reference in New Issue
Block a user