Implement profile page and related backend APIs

This commit is contained in:
Tim
2025-07-09 13:40:54 +08:00
parent d9322307fe
commit 37d1f2ab70
8 changed files with 198 additions and 106 deletions

View File

@@ -95,6 +95,26 @@ public class UserController {
.collect(java.util.stream.Collectors.toList());
}
@GetMapping("/{username}/hot-posts")
public java.util.List<PostMetaDto> hotPosts(@PathVariable String username,
@RequestParam(value = "limit", required = false) Integer limit) {
int l = limit != null ? limit : 10;
java.util.List<Long> ids = reactionService.topPostIds(username, l);
return postService.getPostsByIds(ids).stream()
.map(this::toMetaDto)
.collect(java.util.stream.Collectors.toList());
}
@GetMapping("/{username}/hot-replies")
public java.util.List<CommentInfoDto> hotReplies(@PathVariable String username,
@RequestParam(value = "limit", required = false) Integer limit) {
int l = limit != null ? limit : 10;
java.util.List<Long> ids = reactionService.topCommentIds(username, l);
return commentService.getCommentsByIds(ids).stream()
.map(this::toCommentInfoDto)
.collect(java.util.stream.Collectors.toList());
}
@GetMapping("/{username}/following")
public java.util.List<UserDto> following(@PathVariable String username) {
return subscriptionService.getSubscribedUsers(username).stream()
@@ -139,6 +159,9 @@ public class UserController {
dto.setIntroduction(user.getIntroduction());
dto.setFollowers(subscriptionService.countSubscribers(user.getUsername()));
dto.setFollowing(subscriptionService.countSubscribed(user.getUsername()));
dto.setCreatedAt(user.getCreatedAt());
dto.setLastPostTime(postService.getLastPostTime(user.getUsername()));
dto.setTotalViews(postService.getTotalViews(user.getUsername()));
return dto;
}
@@ -171,6 +194,9 @@ public class UserController {
private String introduction;
private long followers;
private long following;
private java.time.LocalDateTime createdAt;
private java.time.LocalDateTime lastPostTime;
private long totalViews;
}
@Data

View File

@@ -4,6 +4,7 @@ import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.time.LocalDateTime;
import com.openisle.model.Role;
@@ -43,4 +44,12 @@ public class User {
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private Role role = Role.USER;
@Column(nullable = false)
private LocalDateTime createdAt;
@PrePersist
protected void onCreate() {
this.createdAt = LocalDateTime.now();
}
}

View File

@@ -9,6 +9,9 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
import java.time.LocalDateTime;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface PostRepository extends JpaRepository<Post, Long> {
List<Post> findByStatus(PostStatus status);
@@ -21,4 +24,10 @@ public interface PostRepository extends JpaRepository<Post, Long> {
List<Post> findByTitleContainingIgnoreCaseOrContentContainingIgnoreCaseAndStatus(String titleKeyword, String contentKeyword, PostStatus status);
List<Post> findByContentContainingIgnoreCaseAndStatus(String keyword, PostStatus status);
List<Post> findByTitleContainingIgnoreCaseAndStatus(String keyword, PostStatus status);
@Query("SELECT MAX(p.createdAt) FROM Post p WHERE p.author.username = :username AND p.status = com.openisle.model.PostStatus.PUBLISHED")
LocalDateTime findLastPostTime(@Param("username") String username);
@Query("SELECT SUM(p.views) FROM Post p WHERE p.author.username = :username AND p.status = com.openisle.model.PostStatus.PUBLISHED")
Long sumViews(@Param("username") String username);
}

View File

@@ -5,6 +5,9 @@ import com.openisle.model.Post;
import com.openisle.model.Reaction;
import com.openisle.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.data.domain.Pageable;
import java.util.List;
import java.util.Optional;
@@ -14,4 +17,10 @@ public interface ReactionRepository extends JpaRepository<Reaction, Long> {
Optional<Reaction> findByUserAndComment(User user, Comment comment);
List<Reaction> findByPost(Post post);
List<Reaction> findByComment(Comment comment);
@Query("SELECT r.post.id FROM Reaction r WHERE r.post IS NOT NULL AND r.post.author.username = :username AND r.type = com.openisle.model.ReactionType.LIKE GROUP BY r.post.id ORDER BY COUNT(r.id) DESC")
List<Long> findTopPostIds(@Param("username") String username, Pageable pageable);
@Query("SELECT r.comment.id FROM Reaction r WHERE r.comment IS NOT NULL AND r.comment.author.username = :username AND r.type = com.openisle.model.ReactionType.LIKE GROUP BY r.comment.id ORDER BY COUNT(r.id) DESC")
List<Long> findTopCommentIds(@Param("username") String username, Pageable pageable);
}

View File

@@ -101,4 +101,8 @@ public class CommentService {
Pageable pageable = PageRequest.of(0, limit);
return commentRepository.findByAuthorOrderByCreatedAtDesc(user, pageable);
}
public java.util.List<Comment> getCommentsByIds(java.util.List<Long> ids) {
return commentRepository.findAllById(ids);
}
}

View File

@@ -136,6 +136,15 @@ public class PostService {
return postRepository.findByAuthorAndStatusOrderByCreatedAtDesc(user, PostStatus.PUBLISHED, pageable);
}
public java.time.LocalDateTime getLastPostTime(String username) {
return postRepository.findLastPostTime(username);
}
public long getTotalViews(String username) {
Long v = postRepository.sumViews(username);
return v != null ? v : 0;
}
public List<Post> listPostsByTags(java.util.List<Long> tagIds,
Integer page,
Integer pageSize) {
@@ -180,4 +189,8 @@ public class PostService {
notificationService.createNotification(post.getAuthor(), NotificationType.POST_REVIEWED, post, null, false);
return post;
}
public java.util.List<Post> getPostsByIds(java.util.List<Long> ids) {
return postRepository.findAllById(ids);
}
}

View File

@@ -69,4 +69,12 @@ public class ReactionService {
.orElseThrow(() -> new IllegalArgumentException("Comment not found"));
return reactionRepository.findByComment(comment);
}
public java.util.List<Long> topPostIds(String username, int limit) {
return reactionRepository.findTopPostIds(username, org.springframework.data.domain.PageRequest.of(0, limit));
}
public java.util.List<Long> topCommentIds(String username, int limit) {
return reactionRepository.findTopCommentIds(username, org.springframework.data.domain.PageRequest.of(0, limit));
}
}