Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 90f056ea6c | |||
| 3c05ab394a | |||
| e24d7938d0 | |||
| f140031266 | |||
| 503695b28c | |||
| b75765a6d8 | |||
| 5fdd69acb8 | |||
| 80ee6798b7 | |||
| aa43136946 | |||
| cb4f5907e5 |
@@ -71,7 +71,13 @@ export class BlogController {
|
|||||||
const blog = await this.blogService.findById(id);
|
const blog = await this.blogService.findById(id);
|
||||||
if (!blog) throw new BadRequestException('文章不存在');
|
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合法性
|
// 该接口允许匿名评论,但仍需验证userId合法性
|
||||||
@@ -87,6 +93,10 @@ export class BlogController {
|
|||||||
const blog = await this.blogService.findById(id);
|
const blog = await this.blogService.findById(id);
|
||||||
if (!blog) throw new BadRequestException('文章不存在');
|
if (!blog) throw new BadRequestException('文章不存在');
|
||||||
|
|
||||||
|
if (!blog.permissions.includes(BlogPermission.AllowComments)) {
|
||||||
|
throw new BadRequestException('作者关闭了该文章的评论功能');
|
||||||
|
}
|
||||||
|
|
||||||
const user = userId ? await this.userService.findById(userId) : null;
|
const user = userId ? await this.userService.findById(userId) : null;
|
||||||
|
|
||||||
const ip = req.headers['x-forwarded-for'] || req.ip;
|
const ip = req.headers['x-forwarded-for'] || req.ip;
|
||||||
|
|||||||
@@ -2,4 +2,5 @@ export enum BlogPermission {
|
|||||||
Public = 'Public',
|
Public = 'Public',
|
||||||
ByPassword = 'ByPassword',
|
ByPassword = 'ByPassword',
|
||||||
List = 'List',
|
List = 'List',
|
||||||
|
AllowComments = 'AllowComments',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,24 +95,40 @@ export class BlogService {
|
|||||||
await this.blogRepository.increment({ id }, 'viewCount', 1);
|
await this.blogRepository.increment({ id }, 'viewCount', 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getComments(blogId: string) {
|
async getComments(blog: Blog) {
|
||||||
const blog = await this.findById(blogId);
|
const comments = await this.blogCommentRepository.find({
|
||||||
if (!blog) {
|
where: { blog: { id: blog.id } },
|
||||||
throw new Error('文章不存在');
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.blogCommentRepository.find({
|
|
||||||
where: { blog },
|
|
||||||
relations: ['user'],
|
relations: ['user'],
|
||||||
order: {
|
order: {
|
||||||
createdAt: 'DESC',
|
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>) {
|
async createComment(comment: Partial<BlogComment>) {
|
||||||
const newComment = this.blogCommentRepository.create(comment);
|
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) {
|
hashPassword(password: string) {
|
||||||
|
|||||||
@@ -45,6 +45,6 @@ export class Blog {
|
|||||||
password_hash: string | null;
|
password_hash: string | null;
|
||||||
|
|
||||||
// 关系
|
// 关系
|
||||||
@OneToMany(() => BlogComment, (blog) => blog.id)
|
@OneToMany(() => BlogComment, (comment) => comment.blog)
|
||||||
comments: BlogComment[];
|
comments: BlogComment[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export function BlogCommentTool({ blogId, onInsertComment, replayTarget, handleC
|
|||||||
if ((error as { statusCode: number }).statusCode === 429) {
|
if ((error as { statusCode: number }).statusCode === 429) {
|
||||||
return toast.error('操作太频繁了,稍后再试吧')
|
return toast.error('操作太频繁了,稍后再试吧')
|
||||||
}
|
}
|
||||||
toast.error('发布失败')
|
toast.error(`${(error as Error).message || '发布失败'}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export default function Blog() {
|
|||||||
img: ({ src }) => (
|
img: ({ src }) => (
|
||||||
<PhotoProvider className="w-full">
|
<PhotoProvider className="w-full">
|
||||||
<PhotoView src={src as string}>
|
<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>
|
</PhotoView>
|
||||||
</PhotoProvider>
|
</PhotoProvider>
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ const blogPermissions = [
|
|||||||
permission: BlogPermission.List,
|
permission: BlogPermission.List,
|
||||||
localText: '显示在列表中',
|
localText: '显示在列表中',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
permission: BlogPermission.AllowComments,
|
||||||
|
localText: '允许评论',
|
||||||
|
}
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
interface BlogPermissionCheckBoxsProps {
|
interface BlogPermissionCheckBoxsProps {
|
||||||
|
|||||||
@@ -2,4 +2,5 @@ export enum BlogPermission {
|
|||||||
Public = 'Public',
|
Public = 'Public',
|
||||||
ByPassword = 'ByPassword',
|
ByPassword = 'ByPassword',
|
||||||
List = 'List',
|
List = 'List',
|
||||||
|
AllowComments = 'AllowComments',
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user