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
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public ResponseEntity<ApiResponse<CategoryResponseDTO>> createCategory(@Authenti
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "해당 카테고리를 찾을 수 없습니다."),
})
@GetMapping("/{id}")
public ResponseEntity<ApiResponse<CategoryResponseDTO>> getCategoryTitle(@RequestParam Long id) {
public ResponseEntity<ApiResponse<CategoryResponseDTO>> getCategoryTitle(@PathVariable Long id) {

CategoryResponseDTO response = categoryService.getCategoryTitle(id);
return ApiResponse.success(SuccessStatus.GET_CATEGORY_TITLE_SUCCESS, response);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ public ResponseEntity<ApiResponse<Void>> unfollow(@AuthenticationPrincipal UserD
@Operation(
summary = "팔로잉 사용자 목록 조회 API",
description = "내가 팔로우한 사용자(팔로잉)의 목록을 조회합니다." +
"<br>userId 쿼리파라미터가 없으면 본인, 있으면 해당 사용자의 정보를 조회합니다." +
"<br><br>[enum] myFollowStatus: 내가 해당 팔로워를 팔로우했는지 확인하는 필드:" +
"<br>- NONE: 팔로우 아님" +
"<br>- PENDING: 요청 대기중" +
Expand All @@ -319,14 +320,16 @@ public ResponseEntity<ApiResponse<Void>> unfollow(@AuthenticationPrincipal UserD
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "해당 사용자를 찾을 수 없습니다.")
})
@GetMapping("/following")
public ResponseEntity<ApiResponse<List<FollowResponseDTO>>> getFollowings(@AuthenticationPrincipal UserDetails userDetails){
List<FollowResponseDTO> response = followService.getFollowing(userDetails.getUsername());
public ResponseEntity<ApiResponse<List<FollowResponseDTO>>> getFollowings(@AuthenticationPrincipal UserDetails userDetails,
@RequestParam(required = false) Long userId){
List<FollowResponseDTO> response = followService.getFollowing(userDetails.getUsername(), userId);
return ApiResponse.success(SuccessStatus.GET_FOLLOWING_SUCCESS, response);
}

@Operation(
summary = "팔로워 사용자 목록 조회 API",
description = "나를 팔로잉한 사용자(팔로워)의 목록을 조회합니다." +
"<br>userId 쿼리파라미터가 없으면 본인, 있으면 해당 사용자의 정보를 조회합니다." +
"<br><br>[enum] myFollowStatus: 내가 해당 팔로워를 팔로우했는지 확인하는 필드:" +
"<br>- NONE: 팔로우 아님" +
"<br>- PENDING: 요청 대기중" +
Expand All @@ -337,8 +340,9 @@ public ResponseEntity<ApiResponse<List<FollowResponseDTO>>> getFollowings(@Authe
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "해당 사용자를 찾을 수 없습니다.")
})
@GetMapping("/follower")
public ResponseEntity<ApiResponse<List<FollowResponseDTO>>> getFollowers(@AuthenticationPrincipal UserDetails userDetails){
List<FollowResponseDTO> response = followService.getFollower(userDetails.getUsername());
public ResponseEntity<ApiResponse<List<FollowResponseDTO>>> getFollowers(@AuthenticationPrincipal UserDetails userDetails,
@RequestParam(required = false) Long userId){
List<FollowResponseDTO> response = followService.getFollower(userDetails.getUsername(), userId);
return ApiResponse.success(SuccessStatus.GET_FOLLOWER_SUCCESS, response);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,8 @@ public String getAuthorityKey() {
/**
* OAuth2 로그인 시 이름, 사진이 변경될 경우 Entity를 업데이트하는 메서드
*/
public Member update(String name, String picture) {
public Member update(String name) {
this.name = name;
this.profileImage = picture;
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.moongeul.backend.api.notification.repository.NotificationRepository;
import com.moongeul.backend.api.notification.service.NotificationTriggerService;
import com.moongeul.backend.common.exception.BadRequestException;
import com.moongeul.backend.common.exception.ForbiddenException;
import com.moongeul.backend.common.exception.NotFoundException;
import com.moongeul.backend.common.response.ErrorStatus;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -89,10 +90,11 @@ public void unfollow(Long followingId, String email) {

// 팔로잉 사용자 목록 조회
@Transactional(readOnly = true) // 생성, 수정, 삭제가 없는 메서드
public List<FollowResponseDTO> getFollowing(String email){
Member me = getMemberByEmail(email);
public List<FollowResponseDTO> getFollowing(String email, Long userId){
Member currentMember = getMemberByEmail(email);
Member targetMember = getTargetMember(currentMember, userId);

return followRepository.findByFollowings(me.getId())
return followRepository.findByFollowings(targetMember.getId())
.stream()
.map(follow -> {
Member following = follow.getFollowing();
Expand All @@ -109,15 +111,16 @@ public List<FollowResponseDTO> getFollowing(String email){

// 팔로워 사용자 목록 조회
@Transactional(readOnly = true) // 생성, 수정, 삭제가 없는 메서드
public List<FollowResponseDTO> getFollower(String email){
Member me = getMemberByEmail(email);
public List<FollowResponseDTO> getFollower(String email, Long userId){
Member currentMember = getMemberByEmail(email);
Member targetMember = getTargetMember(currentMember, userId);

// 나를 팔로우하는 사람들(Follower) 목록 조회 (상태: ACCEPTED만)
List<Follow> followers = followRepository.findByFollowers(me.getId());
List<Follow> followers = followRepository.findByFollowers(targetMember.getId());

// 내가 누구를 팔로우하고 있는지(PENDING, ACCEPTED) 전체 목록을 Map으로 만듦
// Map은 서비스 로직 안에서만 '검색용'으로 쓰임
Map<Long, FollowStatus> myFollowStatusMap = followRepository.findAllByFollowerId(me.getId())
Map<Long, FollowStatus> myFollowStatusMap = followRepository.findAllByFollowerId(targetMember.getId())
.stream()
.collect(Collectors.toMap(
follow -> follow.getFollowing().getId(), // Key: 상대방 ID
Expand Down Expand Up @@ -177,4 +180,40 @@ private Member getMemberByEmail(String email) {
return memberRepository.findByEmail(email)
.orElseThrow(() -> new NotFoundException(ErrorStatus.USER_NOTFOUND_EXCEPTION.getMessage()));
}

private Member getTargetMember(Member currentMember, Long userId) {
Member targetMember = (userId == null)
? currentMember
: memberRepository.findById(userId)
.orElseThrow(() -> new NotFoundException(ErrorStatus.USER_NOTFOUND_EXCEPTION.getMessage()));

validatePrivacyAccess(currentMember, targetMember);
return targetMember;
}

private void validatePrivacyAccess(Member currentMember, Member targetMember) {
if (currentMember.getId().equals(targetMember.getId())) {
return;
}

PrivacyLevel privacyLevel = targetMember.getPrivacyLevel();

if (privacyLevel == null || privacyLevel == PrivacyLevel.PUBLIC) {
return;
}

if (privacyLevel == PrivacyLevel.PRIVATE) {
throw new ForbiddenException(ErrorStatus.PRIVACY_FORBIDDEN_EXCEPTION.getMessage());
}

if (privacyLevel == PrivacyLevel.FOLLOWER_ONLY) {
FollowStatus status = followRepository.findByFollowingIdAndFollowerId(targetMember.getId(), currentMember.getId())
.map(Follow::getFollowStatus)
.orElse(FollowStatus.NONE);

if (status != FollowStatus.ACCEPTED) {
throw new ForbiddenException(ErrorStatus.PRIVACY_FORBIDDEN_EXCEPTION.getMessage());
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public LoginResponseDTO loginWithGoogle(String code, String type){

// 3. DB 처리 (회원가입 또는 로그인)
Member member = memberRepository.findBySocialId(socialId)
.map(entity -> entity.update(name, picture)) // 이미 있으면 정보 업데이트
.map(entity -> entity.update(name)) // 이미 있으면 정보 업데이트
.orElseGet(() -> signUp(socialId, email, name, picture, socialType)); // 없으면 신규 회원가입

// 4. 자체 JWT 토큰 생성 및 반환
Expand Down Expand Up @@ -129,7 +129,7 @@ public LoginResponseDTO loginWithKakao(String code, String type){

// 3. DB 처리 (회원가입 또는 로그인)
Member member = memberRepository.findBySocialId(socialId)
.map(entity -> entity.update(name, picture)) // 이미 있으면 정보 업데이트
.map(entity -> entity.update(name)) // 이미 있으면 정보 업데이트
.orElseGet(() -> signUp(socialId, email, name, picture, socialType)); // 없으면 신규 회원가입

// 4. 자체 JWT 토큰 생성 및 반환
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/com/moongeul/backend/api/post/dto/PostDTO.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.moongeul.backend.api.post.dto;

import com.moongeul.backend.api.post.entity.PostVisibility;
import com.moongeul.backend.api.readingTaste.entity.ReadingTasteType;
import lombok.AllArgsConstructor;
import lombok.Builder;
Expand All @@ -23,7 +24,11 @@ public class PostDTO {

private BookInfo bookInfo; // 책 정보

private PostVisibility postVisibility; // 공개여부
private Long categoryId; // 카테고리 id

private Double rating; // 별점
private Integer page; // 페이지 수
private String content; // 감상평
private LocalDate readDate; // 읽은날짜

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,11 @@ private PostDTO convertToPostDTO(Post post, PostDTO.MyLikesStatus myLikesStatus,
.pubdate(post.getBook().getPubdate())
.ratingAverage(post.getBook().getRatingAverage())
.build())
.postVisibility(post.getPostVisibility())
.categoryId(post.getCategory().getId())
.created(post.getCreatedAt())
.rating(post.getRating())
.page(post.getPage())
.content(post.getContent())
.readDate(post.getReadDate())
.quotesCnt(quoteDTOList.size())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ public StoryAllResponseDTO getALLStory(String email, PostVisibility postVisibili
Pageable pageable = PageRequest.of(page - 1, size);
Page<Story> storyPage;

// 현재 시간 기준 24시간 전 계산
LocalDateTime timeLimit = LocalDateTime.now().minusHours(24);
// 현재 시간 기준 24시간 전 계산 -> 한 달 임시 수정
LocalDateTime timeLimit = LocalDateTime.now().minusMonths(1);

boolean isAnonymous = (email == null || "anonymousUser".equals(email));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.requestMatchers("/v3/api-docs/**", "/api-doc/**", "/swagger-ui/**").permitAll()
.requestMatchers("/api/v2/member/google/login", "/api/v2/member/kakao/login", "/api/v2/member/reissue-token").permitAll()
.requestMatchers("/api/v2/reading-taste", "/api/v2/reading-taste/total-count").permitAll()
.requestMatchers("/api/v2/book/bestseller").permitAll()
.requestMatchers(HttpMethod.GET, "/api/v2/post/**").permitAll()
.anyRequest().authenticated()
);
Expand Down
Loading