Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ public class Answer {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; // λ‹΅λ³€ ID

@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "post_id")
private Post post;

@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ public class Bookmark extends BaseEntity {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
@JsonIgnore
@JoinColumn(name = "public_service_id", nullable = false)
private PublicService publicService;

@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ public class Comment {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "post_id")
private Post post;

@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;

Expand Down
7 changes: 3 additions & 4 deletions src/main/java/com/hyetaekon/hyetaekon/post/entity/Post.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ public class Post {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; // κ²Œμ‹œκΈ€ ID

@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;

@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "public_service_id")
private PublicService publicService;

Expand Down Expand Up @@ -83,13 +83,12 @@ public class Post {
@Column(name = "suspend_at")
private LocalDateTime suspendAt;


@Builder.Default
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
private List<PostImage> postImages = new ArrayList<>(); // βœ… κ²Œμ‹œκΈ€ 이미지와 μ—°κ²°

@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
@Builder.Default
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Recommend> recommends = new ArrayList<>();

// 쑰회수 증가
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class PostImage {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "post_id")
private Post post;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

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

@Repository
Expand All @@ -24,7 +23,8 @@ public interface PostRepository extends JpaRepository<Post, Long> {
// ID둜 μ‚­μ œλ˜μ§€ μ•Šμ€ κ²Œμ‹œκΈ€ 쑰회
Optional<Post> findByIdAndDeletedAtIsNull(Long id);

boolean existsByUser_IdAndDeletedAtIsNull(Long userId);
// νŠΉμ • μ‚¬μš©μžκ°€ νŠΉμ • νƒ€μž…μ˜ κ²Œμ‹œκΈ€μ„ μž‘μ„±ν•œ 적이 μžˆλŠ”μ§€ 확인
boolean existsByUser_IdAndPostTypeAndDeletedAtIsNull(Long userId, PostType postType);

// νŠΉμ • μ‚¬μš©μžκ°€ μž‘μ„±ν•œ κ²Œμ‹œκΈ€ 쑰회
@EntityGraph(attributePaths = {"user"})
Expand All @@ -35,7 +35,6 @@ public interface PostRepository extends JpaRepository<Post, Long> {
Page<Post> findMyPostsOptimized(@Param("userId") Long userId, Pageable pageable);

// νŠΉμ • μ‚¬μš©μžκ°€ μΆ”μ²œν•œ κ²Œμ‹œκΈ€ 쑰회
@EntityGraph(attributePaths = {"user", "recommends"})
@Query("SELECT DISTINCT p FROM Post p " +
"JOIN p.recommends r " +
"WHERE r.user.id = :userId " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,26 @@ public PostDetailResponseDto createPost(PostCreateRequestDto requestDto, Long us
PostType postType = PostType.fromString(requestDto.getPostType());
log.info("Received postType: '{}'", requestDto.getPostType());

// 포인트 λΆ€μ—¬ λ‘œμ§μ„ κ²Œμ‹œκΈ€ μ €μž₯ 전에 μˆ˜ν–‰
boolean isFirstGreetingPost = false;
try {
if (postType == PostType.GREETING) {
// 첫 인사 κ²Œμ‹œκΈ€ μ—¬λΆ€ 확인 (κ²Œμ‹œκΈ€ μ €μž₯ 전에 체크)
isFirstGreetingPost = !postRepository.existsByUser_IdAndPostTypeAndDeletedAtIsNull(userId, PostType.GREETING);
log.info("인사 κ²Œμ‹œκΈ€ μž‘μ„± 체크 - μ‚¬μš©μž ID: {}, 첫 인사 κ²Œμ‹œκΈ€ μ—¬λΆ€: {}", userId, isFirstGreetingPost);
}
} catch (Exception e) {
log.error("포인트 λΆ€μ—¬ 체크 쀑 였λ₯˜ λ°œμƒ - μ‚¬μš©μž ID: {}", userId, e);
}

// κ²Œμ‹œκΈ€ μ €μž₯
Post post = postMapper.toEntity(requestDto);
post.setUser(user);
post.setPostType(postType);

Post savedPost = postRepository.save(post);

// 이미지 처리
if (requestDto.getImages() != null && !requestDto.getImages().isEmpty()) {
List<PostImage> postImages = processPostImages(requestDto.getImages(), savedPost);
if (!postImages.isEmpty()) {
Expand All @@ -144,9 +158,27 @@ public PostDetailResponseDto createPost(PostCreateRequestDto requestDto, Long us
}
}

// κ²Œμ‹œκΈ€ μž‘μ„± 포인트 λΆ€μ—¬
userPointService.addPointForAction(userId, PointActionType.POST_CREATION);
log.info("μ‚¬μš©μž {}μ—κ²Œ κ²Œμ‹œκΈ€ μž‘μ„± ν¬μΈνŠΈκ°€ λΆ€μ—¬λ˜μ—ˆμŠ΅λ‹ˆλ‹€.", userId);
// κ²Œμ‹œκΈ€ μ €μž₯ ν›„ 포인트 λΆ€μ—¬
try {
if (postType == PostType.GREETING) {
if (isFirstGreetingPost) {
// 첫 인사 κ²Œμ‹œκΈ€μΈ 경우 100점
userPointService.addPointForAction(userId, PointActionType.FIRST_GREETING_POST_CREATION);
log.info("첫 인사 κ²Œμ‹œκΈ€ μž‘μ„± μ™„λ£Œ - μ‚¬μš©μž ID: {}, λΆ€μ—¬ 포인트: 100점", userId);
} else {
// μΆ”κ°€ 인사 κ²Œμ‹œκΈ€μΈ 경우 20점
userPointService.addPointForAction(userId, PointActionType.POST_CREATION);
log.info("μΆ”κ°€ 인사 κ²Œμ‹œκΈ€ μž‘μ„± μ™„λ£Œ - μ‚¬μš©μž ID: {}, λΆ€μ—¬ 포인트: 20점", userId);
}
} else {
// 일반 κ²Œμ‹œκΈ€μΈ 경우 20점
userPointService.addPointForAction(userId, PointActionType.POST_CREATION);
log.info("일반 κ²Œμ‹œκΈ€ μž‘μ„± μ™„λ£Œ - μ‚¬μš©μž ID: {}, λΆ€μ—¬ 포인트: 20점", userId);
}
} catch (Exception e) {
log.error("포인트 λΆ€μ—¬ 쀑 였λ₯˜ λ°œμƒ - μ‚¬μš©μž ID: {}, κ²Œμ‹œκΈ€ ID: {}", userId, savedPost.getId(), e);
// 포인트 λΆ€μ—¬ μ‹€νŒ¨ν•΄λ„ κ²Œμ‹œκΈ€ 생성은 μ„±κ³΅μœΌλ‘œ 처리
}

return postMapper.toPostDetailDto(savedPost);
}
Expand Down Expand Up @@ -306,8 +338,6 @@ public Page<MyPostListResponseDto> getRecommendedPostsByUserId(Long userId, Page
return postRepository.findRecommendedPostsOptimized(userId, pageable)
.map(post -> {
MyPostListResponseDto dto = postMapper.toMyPostListDto(post);
// μΆ”μ²œ κ°œμˆ˜λŠ” 이미 λ‘œλ“œλœ λ°μ΄ν„°μ—μ„œ κ°€μ Έμ˜΄ (μΆ”κ°€ 쿼리 μ—†μŒ)
// post.getRecommends().size()λŠ” 이미 λ©”λͺ¨λ¦¬μ— 있음
return dto;
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ public class Recommend extends BaseEntity {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
@JsonIgnore
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "post_id", nullable = false)
private Post post;

@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,4 @@ public interface RecommendRepository extends JpaRepository<Recommend, Long> {

Optional<Recommend> findByUserIdAndPostId(Long userId, Long postId);

int countByPostId(Long postId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
@Getter
public enum PointActionType {
POST_CREATION(20), // κ²Œμ‹œκΈ€ μž‘μ„± (20점)
FIRST_POST_CREATION(100), // 첫 κ²Œμ‹œκΈ€ μž‘μ„± (100점)
FIRST_GREETING_POST_CREATION(100), // 인사 κ²Œμ‹œκΈ€ μž‘μ„± (100점)
ANSWER_CREATION(10), // λ‹΅λ³€ μž‘μ„± (10점)
ANSWER_ACCEPTED(50); // 닡변이 채택됨 (50점)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
@NoArgsConstructor
@AllArgsConstructor
public class User {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.hyetaekon.hyetaekon.user.entity.User;
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 org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
Expand All @@ -16,6 +17,10 @@ public interface UserRepository extends JpaRepository<User, Long> {
// user id둜 검색
Optional<User> findByIdAndDeletedAtIsNull(Long id);

@EntityGraph(attributePaths = {"interests"})
@Query("SELECT u FROM User u WHERE u.id = :id AND u.deletedAt IS NULL")
Optional<User> findByIdAndDeletedAtIsNullWithInterests(@Param("id") Long id);

// user realId둜 검색
Optional<User> findByRealIdAndDeletedAtIsNull(String realId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.hyetaekon.hyetaekon.common.exception.ErrorCode;
import com.hyetaekon.hyetaekon.common.exception.GlobalException;
import com.hyetaekon.hyetaekon.post.entity.PostType;
import com.hyetaekon.hyetaekon.post.repository.PostRepository;
import com.hyetaekon.hyetaekon.user.entity.PointActionType;
import com.hyetaekon.hyetaekon.user.entity.User;
Expand All @@ -17,7 +18,7 @@
public class UserPointService {
private final UserRepository userRepository;
private final UserLevelService userLevelService;
private final PostRepository postRepository; // κ²Œμ‹œκΈ€ μ €μž₯μ†Œ μΆ”κ°€ ν•„μš”
private final PostRepository postRepository;

@Transactional
public void addPointForAction(Long userId, PointActionType actionType) {
Expand All @@ -26,21 +27,20 @@ public void addPointForAction(Long userId, PointActionType actionType) {

int pointToAdd = actionType.getPoints();

// κ²Œμ‹œκΈ€ μž‘μ„±μΈ 경우 첫 κ²Œμ‹œκΈ€ μ—¬λΆ€ 확인
if (actionType == PointActionType.POST_CREATION) {
boolean isFirstPost = !postRepository.existsByUser_IdAndDeletedAtIsNull(userId);
if (isFirstPost) {
// 첫 κ²Œμ‹œκΈ€μΈ 경우 FIRST_POST_CREATION 포인트 적용
pointToAdd = PointActionType.FIRST_POST_CREATION.getPoints();
log.info("μ‚¬μš©μž {}의 첫 κ²Œμ‹œκΈ€ μž‘μ„±μœΌλ‘œ {}점 νšλ“", userId, pointToAdd);
}
}
// ν˜„μž¬ 포인트 λ‘œκΉ…
log.info("포인트 λΆ€μ—¬ μ „ - μ‚¬μš©μž ID: {}, ν˜„μž¬ 포인트: {}, λΆ€μ—¬ν•  포인트: {}",
userId, user.getPoint(), pointToAdd);

user.addPoint(pointToAdd);

// 레벨 체크 및 μ—…λ°μ΄νŠΈ
userLevelService.checkAndUpdateLevel(user);

userRepository.save(user);
User savedUser = userRepository.save(user);

// 포인트 λΆ€μ—¬ ν›„ λ‘œκΉ…
log.info("포인트 λΆ€μ—¬ ν›„ - μ‚¬μš©μž ID: {}, μ΅œμ’… 포인트: {}, 레벨: {}",
userId, savedUser.getPoint(), savedUser.getLevel().getName());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class UserInterest {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,5 @@ public interface UserInterestRepository extends JpaRepository<UserInterest, Long
*/
List<UserInterest> findByUserId(Long userId);

/**
* μ‚¬μš©μž ID둜 관심사 쑴재 μ—¬λΆ€ 확인
*/
boolean existsByUserId(Long userId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class UserInterestService {
// λͺ¨λ“  관심사 λͺ©λ‘κ³Ό μ‚¬μš©μž 선택 μ—¬λΆ€ ν•¨κ»˜ 쑰회
@Transactional(readOnly = true)
public CategorizedInterestsWithSelectionDto getUserInterestsWithSelection(Long userId) {
User user = userRepository.findByIdAndDeletedAtIsNull(userId)
User user = userRepository.findByIdAndDeletedAtIsNullWithInterests(userId)
.orElseThrow(() -> new GlobalException(ErrorCode.USER_NOT_FOUND_BY_ID));

// μ‚¬μš©μžκ°€ μ„ νƒν•œ 관심사 λͺ©λ‘
Expand Down