| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- import { DataSource, Repository, In } from 'typeorm';
- import debug from 'debug';
- import { z } from '@hono/zod-openapi';
- import { PostEntity as Post } from './post.entity';
- import { FollowEntity } from '../follows/follow.entity';
- import { UserEntity as User } from '../users/user.entity';
- import { UserService } from '../users/user.service';
- import type { CreatePostDto, UpdatePostDto } from './post.entity';
- import { HTTPException } from 'hono/http-exception';
- import { DeleteStatus } from '@/share/types';
- const logger = debug('backend:posts:service');
- export class PostService {
- private postRepository: Repository<Post>;
- private userRepository: Repository<User>;
- private userService: UserService;
- constructor(dataSource: DataSource) {
- this.postRepository = dataSource.getRepository(Post);
- this.userRepository = dataSource.getRepository(User);
- this.userService = new UserService(dataSource);
- }
- /**
- * 创建帖子
- */
- async createPost(userId: number, data: z.infer<typeof CreatePostDto>): Promise<Post> {
- // 验证用户是否存在
- const user = await this.userRepository.findOneBy({ id: userId });
- if (!user) {
- throw new Error('用户不存在');
- }
- 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 Error('帖子不存在或没有权限');
- }
- 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表存在且有关联
- logger('Building following feed query for followerId: %d, page: %d, pageSize: %d', followerId, page, pageSize);
-
- // 创建主查询用于获取分页数据
- 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 countQuery = 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 });
- // 记录生成的SQL和参数
- const sql = query.getSql();
- const parameters = query.getParameters();
- logger('Following feed query: %s', sql);
- logger('Query parameters: %o', parameters);
-
- const [posts, total] = await Promise.all([
- query.getRawMany(),
- countQuery.getCount()
- ]);
-
- logger('Following feed results: %d posts, total: %d', posts.length, total);
- 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 Error('帖子不存在');
- }
- 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 Error('帖子不存在');
- }
- if (post.likesCount > 0) {
- post.likesCount -= 1;
- return this.postRepository.save(post);
- }
- return post;
- }
- /**
- * 根据用户ID列表获取帖子
- */
- async getPostsByUserIds(userIds: number[], page: number = 1, pageSize: number = 10): Promise<[Post[], number]> {
- const skip = (page - 1) * pageSize;
-
- const [posts, total] = await this.postRepository.findAndCount({
- where: {
- userId: In(userIds),
- isDeleted: DeleteStatus.NOT_DELETED
- },
- relations: ['user'],
- skip,
- take: pageSize,
- order: { createdAt: 'DESC' }
- });
- return [posts, total];
- }
- /**
- * 获取推荐用户的帖子
- */
- async getRecommendedPosts(currentUserId: number, page: number = 1, pageSize: number = 10): Promise<[Post[], number]> {
- // 获取推荐用户
- const recommendedUsers = await this.userService.getRecommendedUsers(currentUserId);
- const recommendedUserIds = recommendedUsers.map(u => u.id);
-
- if (recommendedUserIds.length > 0) {
- return this.getPostsByUserIds(recommendedUserIds, page, pageSize);
- }
-
- return [[], 0];
- }
- /**
- * 获取热门帖子(按点赞数和创建时间排序)
- */
- async getPopularPosts(page: number = 1, pageSize: number = 10): Promise<[Post[], number]> {
- const skip = (page - 1) * pageSize;
-
- const [posts, total] = await this.postRepository.findAndCount({
- where: { isDeleted: DeleteStatus.NOT_DELETED },
- relations: ['user'],
- skip,
- take: pageSize,
- order: {
- likesCount: 'DESC',
- createdAt: 'DESC'
- }
- });
- return [posts, total];
- }
- }
|