|
|
@@ -0,0 +1,157 @@
|
|
|
+import { DataSource, Repository } from 'typeorm';
|
|
|
+import { z } from '@hono/zod-openapi';
|
|
|
+import { PostEntity as Post } from './post.entity';
|
|
|
+import { UserEntity as User } from '../users/user.entity';
|
|
|
+import type { CreatePostDto, UpdatePostDto } from './post.entity';
|
|
|
+import { HTTPException } from 'hono/http-exception';
|
|
|
+import { DeleteStatus } from '@/share/types';
|
|
|
+
|
|
|
+export class PostService {
|
|
|
+ private postRepository: Repository<Post>;
|
|
|
+ private userRepository: Repository<User>;
|
|
|
+
|
|
|
+ constructor(dataSource: DataSource) {
|
|
|
+ this.postRepository = dataSource.getRepository(Post);
|
|
|
+ this.userRepository = dataSource.getRepository(User);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建帖子
|
|
|
+ */
|
|
|
+ async createPost(userId: number, data: z.infer<typeof CreatePostDto>): Promise<Post> {
|
|
|
+ // 验证用户是否存在
|
|
|
+ const user = await this.userRepository.findOneBy({ id: userId });
|
|
|
+ if (!user) {
|
|
|
+ throw new HTTPException(404, { message: '用户不存在' });
|
|
|
+ }
|
|
|
+
|
|
|
+ const post = this.postRepository.create({
|
|
|
+ userId,
|
|
|
+ ...data,
|
|
|
+ likesCount: 0,
|
|
|
+ commentsCount: 0
|
|
|
+ });
|
|
|
+
|
|
|
+ const savedPost = await this.postRepository.save(post);
|
|
|
+ return savedPost as unknown as Post;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取帖子详情
|
|
|
+ */
|
|
|
+ async getPostById(id: number): Promise<Post | null> {
|
|
|
+ const post = await this.postRepository.findOne({
|
|
|
+ where: { id, isDeleted: DeleteStatus.NOT_DELETED },
|
|
|
+ relations: ['user']
|
|
|
+ });
|
|
|
+
|
|
|
+ return post;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新帖子
|
|
|
+ */
|
|
|
+ async updatePost(postId: number, userId: number, data: z.infer<typeof UpdatePostDto>): Promise<Post | null> {
|
|
|
+ // 验证帖子是否存在且属于当前用户
|
|
|
+ const post = await this.postRepository.findOneBy({
|
|
|
+ id: postId,
|
|
|
+ userId,
|
|
|
+ isDeleted: DeleteStatus.NOT_DELETED
|
|
|
+ });
|
|
|
+
|
|
|
+ if (!post) {
|
|
|
+ throw new HTTPException(404, { message: '帖子不存在或没有权限' });
|
|
|
+ }
|
|
|
+
|
|
|
+ Object.assign(post, data);
|
|
|
+ return this.postRepository.save(post);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 删除帖子(软删除)
|
|
|
+ */
|
|
|
+ async deletePost(postId: number, userId: number): Promise<boolean> {
|
|
|
+ const result = await this.postRepository.update(
|
|
|
+ { id: postId, userId, isDeleted: DeleteStatus.NOT_DELETED },
|
|
|
+ { isDeleted: DeleteStatus.DELETED }
|
|
|
+ );
|
|
|
+
|
|
|
+ return (result.affected || 0) > 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取用户帖子列表
|
|
|
+ */
|
|
|
+ async getUserPosts(userId: number, page: number = 1, pageSize: number = 10): Promise<[Post[], number]> {
|
|
|
+ const skip = (page - 1) * pageSize;
|
|
|
+
|
|
|
+ const [posts, total] = await this.postRepository.findAndCount({
|
|
|
+ where: { userId, isDeleted: DeleteStatus.NOT_DELETED },
|
|
|
+ relations: ['user'],
|
|
|
+ skip,
|
|
|
+ take: pageSize,
|
|
|
+ order: { createdAt: 'DESC' }
|
|
|
+ });
|
|
|
+
|
|
|
+ return [posts, total];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取关注用户的帖子流
|
|
|
+ */
|
|
|
+ async getFollowingFeed(followerId: number, page: number = 1, pageSize: number = 10): Promise<[Post[], number]> {
|
|
|
+ const skip = (page - 1) * pageSize;
|
|
|
+
|
|
|
+ // 直接查询关注用户的帖子,假设follow表存在且有关联
|
|
|
+ const query = this.postRepository
|
|
|
+ .createQueryBuilder('post')
|
|
|
+ .leftJoin('follows', 'f', 'f.following_id = post.user_id')
|
|
|
+ .where('f.follower_id = :followerId', { followerId })
|
|
|
+ .andWhere('post.is_deleted = :notDeleted', { notDeleted: DeleteStatus.NOT_DELETED })
|
|
|
+ .leftJoinAndSelect('post.user', 'user')
|
|
|
+ .orderBy('post.created_at', 'DESC')
|
|
|
+ .skip(skip)
|
|
|
+ .take(pageSize);
|
|
|
+
|
|
|
+ const [posts, total] = await query.getManyAndCount();
|
|
|
+ return [posts, total];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 点赞帖子
|
|
|
+ */
|
|
|
+ async likePost(postId: number): Promise<Post | null> {
|
|
|
+ const post = await this.postRepository.findOneBy({
|
|
|
+ id: postId,
|
|
|
+ isDeleted: DeleteStatus.NOT_DELETED
|
|
|
+ });
|
|
|
+
|
|
|
+ if (!post) {
|
|
|
+ throw new HTTPException(404, { message: '帖子不存在' });
|
|
|
+ }
|
|
|
+
|
|
|
+ post.likesCount += 1;
|
|
|
+ return this.postRepository.save(post);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 取消点赞帖子
|
|
|
+ */
|
|
|
+ async unlikePost(postId: number): Promise<Post | null> {
|
|
|
+ const post = await this.postRepository.findOneBy({
|
|
|
+ id: postId,
|
|
|
+ isDeleted: DeleteStatus.NOT_DELETED
|
|
|
+ });
|
|
|
+
|
|
|
+ if (!post) {
|
|
|
+ throw new HTTPException(404, { message: '帖子不存在' });
|
|
|
+ }
|
|
|
+
|
|
|
+ if (post.likesCount > 0) {
|
|
|
+ post.likesCount -= 1;
|
|
|
+ return this.postRepository.save(post);
|
|
|
+ }
|
|
|
+
|
|
|
+ return post;
|
|
|
+ }
|
|
|
+}
|