Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions src/main/java/com/example/FixLog/controller/FollowController.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import com.example.FixLog.service.FollowService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;

import java.util.List;
Expand All @@ -23,8 +25,9 @@ public class FollowController {
@PostMapping
public ResponseEntity<Response<FollowResponseDto>> follow(
@RequestBody FollowRequestDto followRequestDto,
@RequestParam String requesterEmail // jwt 구현 전까지 임시 사용 -> 이후 AuthenticationPrincipal 사용 예정
@AuthenticationPrincipal UserDetails userDetails // jwt 구현 전까지 임시 사용 -> 이후 AuthenticationPrincipal 사용 예정
){
String requesterEmail = userDetails.getUsername();
FollowResponseDto result = followService.follow(requesterEmail, followRequestDto.getTargetMemberId());
return ResponseEntity.ok(Response.success("팔로우 완료", result));
}
Expand All @@ -33,26 +36,29 @@ public ResponseEntity<Response<FollowResponseDto>> follow(
@PostMapping("/unfollow")
public ResponseEntity<Response<Void>> unfollow(
@RequestBody UnfollowRequestDto requestDto,
@RequestParam String requesterEmail) {

@AuthenticationPrincipal UserDetails userDetails
) {
String requesterEmail = userDetails.getUsername();
followService.unfollow(requesterEmail, requestDto.getTargetMemberId());
return ResponseEntity.ok(Response.success("언팔로우 완료", null));
}

// 나를 팔로우하는 목록 조회
@GetMapping("/followers")
public ResponseEntity<Response<List<FollowerListResponseDto>>> getMyFollowers(
@RequestParam String requesterEmail) {

@AuthenticationPrincipal UserDetails userDetails
) {
String requesterEmail = userDetails.getUsername();
List<FollowerListResponseDto> followers = followService.getMyFollowers(requesterEmail);
return ResponseEntity.ok(Response.success("나를 팔로우하는 목록 조회 성공", followers));
}

// 내가 팔로우하는 목록 조회
@GetMapping("/followings")
public ResponseEntity<Response<List<FollowingListResponseDto>>> getMyFollowings(
@RequestParam String requesterEmail) {

@AuthenticationPrincipal UserDetails userDetails
) {
String requesterEmail = userDetails.getUsername();
List<FollowingListResponseDto> followings = followService.getMyFollowings(requesterEmail);
return ResponseEntity.ok(Response.success("내가 팔로우 중인 목록 조회 성공", followings));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.example.FixLog.controller;

import com.example.FixLog.dto.PageResponseDto;
import com.example.FixLog.dto.Response;
import com.example.FixLog.dto.post.MyPostPageResponseDto;
import com.example.FixLog.service.MypagePostService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/mypage")
public class MypagePostController {

private final MypagePostService mypagePostService;

// 내가 쓴 글 보기
@GetMapping("/posts")
public ResponseEntity<Response<PageResponseDto<MyPostPageResponseDto>>> getMyPosts(
@AuthenticationPrincipal UserDetails userDetails,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "4") int size,
@RequestParam(defaultValue = "0") int sort
) {
String email = userDetails.getUsername();
PageResponseDto<MyPostPageResponseDto> data = mypagePostService.getMyPosts(email, page, sort, size);
return ResponseEntity.ok(Response.success("내가 작성한 글 보기 성공", data));
}

}
6 changes: 3 additions & 3 deletions src/main/java/com/example/FixLog/domain/post/Post.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
import com.example.FixLog.domain.like.PostLike;
import com.example.FixLog.domain.member.Member;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.*;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Entity
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Post {

Expand Down
35 changes: 35 additions & 0 deletions src/main/java/com/example/FixLog/dto/PageResponseDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.example.FixLog.dto;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Getter;
import org.springframework.data.domain.Page;

import java.util.List;
import java.util.function.Function;

@Getter
@JsonInclude(JsonInclude.Include.NON_NULL)
public class PageResponseDto<T> {

private final List<T> content;
private final int page;
private final int size;
private final long totalElements;

@JsonInclude(JsonInclude.Include.NON_NULL)
private final Integer totalPages;

private PageResponseDto(Page<T> page) {
this.content = page.getContent();
this.page = page.getNumber() + 1; // 1부터 시작
this.size = page.getSize();
this.totalElements = page.getTotalElements();
this.totalPages = page.getTotalPages() == 0 ? null : page.getTotalPages();
}

public static <T, R> PageResponseDto<R> from(Page<T> page, Function<T, R> mapper) {
Page<R> mapped = page.map(mapper);
return new PageResponseDto<>(mapped);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.example.FixLog.dto.post;

import com.example.FixLog.domain.post.Post;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.List;

@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class MyPostPageResponseDto {
private Long postId;
private String postTitle;
private String postSummary;
private String imageUrl;
private List<String> tags;
private LocalDateTime createdAt;
private int likeCount;
private int forkCount;

public static MyPostPageResponseDto from(Post post, int forkCount) {
return MyPostPageResponseDto.builder()
.postId(post.getPostId())
.postTitle(post.getPostTitle())
.postSummary(generateSummary(post.getProblem()))
.imageUrl(post.getCoverImage())
.tags(post.getPostTags().stream().map(tag -> tag.getTagId().getTagName()).toList())
.createdAt(post.getCreatedAt())
.likeCount(post.getPostLikes().size())
.forkCount(forkCount)
.build();
}

private static String generateSummary(String content) {
if (content == null) return "";
return content.length() > 200 ? content.substring(0, 200) + "..." : content;
}
}
85 changes: 85 additions & 0 deletions src/main/java/com/example/FixLog/mock/PostTestDataInitializer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package com.example.FixLog.mock;

import com.example.FixLog.domain.bookmark.Bookmark;
import com.example.FixLog.domain.like.PostLike;
import com.example.FixLog.domain.post.Post;
import com.example.FixLog.domain.post.PostTag;
import com.example.FixLog.domain.tag.Tag;
import com.example.FixLog.repository.MemberRepository;
import com.example.FixLog.repository.bookmark.BookmarkFolderRepository;
import com.example.FixLog.repository.bookmark.BookmarkRepository;
import com.example.FixLog.repository.like.PostLikeRepository;
import com.example.FixLog.repository.post.PostRepository;
import com.example.FixLog.repository.post.PostTagRepository;
import com.example.FixLog.repository.tag.TagRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.List;

@Component
@Order(4) // Member, Tag, BookmarkFolder 이후에 실행
@RequiredArgsConstructor
public class PostTestDataInitializer implements CommandLineRunner {

private final MemberRepository memberRepository;
private final PostRepository postRepository;
private final TagRepository tagRepository;
private final PostTagRepository postTagRepository;
private final PostLikeRepository postLikeRepository;
private final BookmarkRepository bookmarkRepository;
private final BookmarkFolderRepository bookmarkFolderRepository;

@Override
public void run(String... args) {
if (postRepository.count() == 0) {
memberRepository.findByEmail("[email protected]").ifPresentOrElse(member -> {

// 1. 게시글 생성
Post post = Post.builder()
.userId(member)
.postTitle("개발을 하다 보면 많은 에러를 만난다")
.coverImage("https://cdn.example.com/images/test1.jpg")
.problem("만나고 싶지 않다")
.errorMessage("에러메세지 ~~ ")
.environment("스프링부트")
.reproduceCode("여긴 뭘까요")
.solutionCode("해결 !!")
.causeAnalysis("이유를 모름")
.referenceLink("no_error@@.com")
.extraContent("추가 설명입니다.")
.createdAt(LocalDateTime.now())
.editedAt(LocalDateTime.now())
.build();
postRepository.save(post);

// 2. 태그 연결
List<Tag> tags = tagRepository.findAll();
if (!tags.isEmpty()) {
List<PostTag> postTags = tags.subList(0, Math.min(2, tags.size())).stream()
.map(tag -> new PostTag(post, tag))
.toList();
postTagRepository.saveAll(postTags);
}

// 3. 좋아요 추가
PostLike postLike = new PostLike(member, post);
postLikeRepository.save(postLike);

// 4. 북마크 추가 (기본 폴더 사용)
bookmarkFolderRepository.findFirstByUserId(member).ifPresent(folder -> {
Bookmark bookmark = new Bookmark(folder, post);
bookmarkRepository.save(bookmark);
});

System.out.println("테스트용 게시글 1개, 태그/좋아요/북마크까지 생성 완료");

}, () -> {
System.out.println("[email protected] 사용자가 없어 게시글 생성 생략됨");
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.example.FixLog.repository.tag.TagRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.List;
Expand All @@ -12,6 +13,7 @@

@Component
@RequiredArgsConstructor
@Order(3)
public class TagTestDataInitializer implements CommandLineRunner {

private final TagRepository tagRepository;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;
import java.util.Optional;


public interface BookmarkFolderRepository extends JpaRepository<BookmarkFolder, Long> {
Page<BookmarkFolder> findAllByUserId(Member userId, Pageable pageable);
BookmarkFolder findByUserId(Member userId);
Optional<BookmarkFolder> findFirstByUserId(Member userId); // 첫 번째 폴더만 가져올 때 Optional
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.example.FixLog.repository.fork;

import com.example.FixLog.domain.fork.Fork;
import com.example.FixLog.domain.post.Post;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

public interface ForkRepository extends JpaRepository<Fork, Long> {
@Query("""
SELECT f.originalPostId.postId, COUNT(f)
FROM Fork f
WHERE f.originalPostId IN :posts
GROUP BY f.originalPostId.postId
""")
List<Object[]> countForksByOriginalPosts(@Param("posts") List<Post> posts); // 원본글 기반 포크 수
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.example.FixLog.repository.post;

import com.example.FixLog.domain.member.Member;
import com.example.FixLog.domain.post.Post;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;
Expand All @@ -12,4 +14,7 @@ public interface PostRepository extends JpaRepository<Post, Long> {
List<Post> findTop12ByOrderByPostLikesDesc();
Page<Post> findAllByOrderByCreatedAtDesc(Pageable pageable);
Page<Post> findAllByOrderByPostLikesDesc(Pageable pageable);

@EntityGraph(attributePaths = {"postLikes"})
Page<Post> findByUserId(Member userId, Pageable pageable);
}
Loading