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 @@ -17,6 +17,7 @@
import org.clokey.global.paging.SortDirection;
import org.clokey.response.BaseResponse;
import org.clokey.response.SliceResponse;
import org.springframework.beans.TypeMismatchException;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

Expand Down Expand Up @@ -155,13 +156,23 @@ public BaseResponse<Void> toggleCoordinateLike(@PathVariable Long coordinateId)
return BaseResponse.onSuccess(GlobalBaseSuccessCode.NO_CONTENT, null);
}

@GetMapping("/my-favorites")
@GetMapping("/favorites")
@Operation(
operationId = "Coordinate_getFavoriteCoordinates",
summary = "나의 최애 코디 조회",
description = "나의 최애 코디를 조회하는 API입니다.")
public BaseResponse<List<FavoriteCoordinateResponse>> getFavoriteCoordinates() {
List<FavoriteCoordinateResponse> response = coordinateService.getFavoriteCoordinates();
summary = "최애 코디 조회",
description = "최애 코디를 조회하는 API입니다.")
public BaseResponse<List<FavoriteCoordinateResponse>> getFavoriteCoordinates(
@RequestParam(required = false) String memberId) {
Long parsedMemberId = null;
if (memberId != null && !memberId.isBlank()) {
try {
parsedMemberId = Long.valueOf(memberId);
} catch (NumberFormatException e) {
throw new TypeMismatchException(memberId, Long.class, e);
}
}
List<FavoriteCoordinateResponse> response =
coordinateService.getFavoriteCoordinates(parsedMemberId);
return BaseResponse.onSuccess(GlobalBaseSuccessCode.OK, response);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ SliceResponse<DailyCoordinateListResponse> getDailyCoordinates(

void toggleCoordinateLike(Long coordinateId);

List<FavoriteCoordinateResponse> getFavoriteCoordinates();
List<FavoriteCoordinateResponse> getFavoriteCoordinates(Long memberId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,15 @@
import org.clokey.domain.image.event.ImageDeleteEvent;
import org.clokey.domain.lookbook.exception.LookBookErrorCode;
import org.clokey.domain.lookbook.repository.LookBookRepository;
import org.clokey.domain.member.exception.MemberErrorCode;
import org.clokey.domain.member.repository.BlockRepository;
import org.clokey.domain.member.repository.MemberRepository;
import org.clokey.exception.BaseCustomException;
import org.clokey.global.paging.SortDirection;
import org.clokey.global.util.MemberUtil;
import org.clokey.lookbook.entity.LookBook;
import org.clokey.member.entity.Member;
import org.clokey.member.enums.Visibility;
import org.clokey.response.SliceResponse;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Slice;
Expand All @@ -46,6 +50,8 @@ public class CoordinateServiceImpl implements CoordinateService {
private final CoordinateRepository coordinateRepository;
private final ClothRepository clothRepository;
private final LookBookRepository lookBookRepository;
private final MemberRepository memberRepository;
private final BlockRepository blockRepository;
private final CoordinateClothRepository coordinateClothRepository;
private final RedisTemplate<String, String> redisTemplate;

Expand Down Expand Up @@ -373,11 +379,13 @@ public void toggleCoordinateLike(Long coordinateId) {
}

@Override
public List<FavoriteCoordinateResponse> getFavoriteCoordinates() {
public List<FavoriteCoordinateResponse> getFavoriteCoordinates(Long memberId) {
final Member currentMember = memberUtil.getCurrentMember();
final Long targetMemberId =
resolveFavoriteCoordinateTargetMemberId(currentMember, memberId);

List<Coordinate> favoriteCoordinates =
coordinateRepository.findLikedCoordinatesByMemberId(currentMember.getId());
coordinateRepository.findLikedCoordinatesByMemberId(targetMemberId);

if (favoriteCoordinates.isEmpty()) {
return List.of();
Expand All @@ -386,6 +394,23 @@ public List<FavoriteCoordinateResponse> getFavoriteCoordinates() {
return favoriteCoordinates.stream().map(FavoriteCoordinateResponse::from).toList();
}

private Long resolveFavoriteCoordinateTargetMemberId(Member currentMember, Long memberId) {
if (memberId == null || memberId.equals(currentMember.getId())) {
return currentMember.getId();
}

Member targetMember =
memberRepository
.findById(memberId)
.orElseThrow(
() -> new BaseCustomException(MemberErrorCode.MEMBER_NOT_FOUND));

validatePublicMember(targetMember);
validateNotBlocked(currentMember.getId(), targetMember.getId());

return targetMember.getId();
}

private void validateAllClothesExist(List<Long> clothIds, Map<Long, Cloth> clothMap) {
boolean hasMissing = clothIds.stream().anyMatch(clothId -> !clothMap.containsKey(clothId));

Expand Down Expand Up @@ -469,6 +494,19 @@ private void validateCoordinateLikeLimit(Long memberId, Coordinate coordinate) {
}
}

private void validatePublicMember(Member member) {
if (member.getVisibility().equals(Visibility.PRIVATE)) {
throw new BaseCustomException(MemberErrorCode.PRIVATE_MEMBER_ACCESS_DENIED);
}
}

private void validateNotBlocked(Long currentMemberId, Long targetMemberId) {
if (blockRepository.existsByBlockerIdAndBlockedIdOrBlockerIdAndBlockedId(
currentMemberId, targetMemberId, targetMemberId, currentMemberId)) {
throw new BaseCustomException(MemberErrorCode.BLOCKED_MEMBER_ACCESS_DENIED);
}
}

private LookBook getLookBookById(Long lookBookId) {
return lookBookRepository
.findById(lookBookId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ public MemberInfoResponse getMemberInfo(Long memberId) {
Member currentMember = memberUtil.getCurrentMember();
Member targetMember = getMemberById(memberId);

if (!currentMember.getId().equals(targetMember.getId())) {
validateBlockedMutual(currentMember.getId(), targetMember.getId());
}

return memberRepository.findMemberInfoById(currentMember.getId(), memberId);
}

Expand Down Expand Up @@ -250,6 +254,13 @@ private void validateBlocked(Member currentMember, Member targetMember) {
}
}

private void validateBlockedMutual(Long currentMemberId, Long targetMemberId) {
if (blockRepository.existsByBlockerIdAndBlockedIdOrBlockerIdAndBlockedId(
currentMemberId, targetMemberId, targetMemberId, currentMemberId)) {
throw new BaseCustomException(MemberErrorCode.BLOCKED_MEMBER_ACCESS_DENIED);
}
}

private void validateFollowMyself(Member followFrom, Member followTo) {
if (followFrom.getId().equals(followTo.getId())) {
throw new BaseCustomException(MemberErrorCode.CANNOT_FOLLOW_MYSELF);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1650,10 +1650,10 @@ class 최애_코디_조회_요청_시 {
new FavoriteCoordinateResponse(
2L, "testImageUrl2", "testCoordinateName2"));

given(coordinateService.getFavoriteCoordinates()).willReturn(response);
given(coordinateService.getFavoriteCoordinates(null)).willReturn(response);

// when & then
ResultActions perform = mockMvc.perform(get("/coordinate/my-favorites"));
ResultActions perform = mockMvc.perform(get("/coordinate/favorites"));

perform.andExpect(status().isOk())
.andExpect(jsonPath("$.isSuccess").value(true))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,14 @@
import org.clokey.domain.image.event.ImageDeleteEvent;
import org.clokey.domain.lookbook.exception.LookBookErrorCode;
import org.clokey.domain.lookbook.repository.LookBookRepository;
import org.clokey.domain.member.exception.MemberErrorCode;
import org.clokey.domain.member.repository.BlockRepository;
import org.clokey.domain.member.repository.MemberRepository;
import org.clokey.exception.BaseCustomException;
import org.clokey.global.paging.SortDirection;
import org.clokey.global.util.MemberUtil;
import org.clokey.lookbook.entity.LookBook;
import org.clokey.member.entity.Block;
import org.clokey.member.entity.Member;
import org.clokey.member.entity.OauthInfo;
import org.clokey.member.enums.OauthProvider;
Expand All @@ -56,6 +59,7 @@ class CoordinateServiceImplTest extends IntegrationTest {

@Autowired private CoordinateRepository coordinateRepository;
@Autowired private MemberRepository memberRepository;
@Autowired private BlockRepository blockRepository;
@Autowired private CoordinateClothRepository coordinateClothRepository;
@Autowired private CategoryRepository categoryRepository;
@Autowired private ClothRepository clothRepository;
Expand Down Expand Up @@ -1944,7 +1948,8 @@ void setUp() {
@Test
void 유효한_요청이면_좋아요한_코디를_반환한다() {
// when
List<FavoriteCoordinateResponse> responses = coordinateService.getFavoriteCoordinates();
List<FavoriteCoordinateResponse> responses =
coordinateService.getFavoriteCoordinates(null);

// then
assertThat(responses)
Expand All @@ -1960,11 +1965,51 @@ void setUp() {
given(memberUtil.getCurrentMember()).willReturn(member);

// when
List<FavoriteCoordinateResponse> responses = coordinateService.getFavoriteCoordinates();
List<FavoriteCoordinateResponse> responses =
coordinateService.getFavoriteCoordinates(null);

// then
assertThat(responses).isEmpty();
}

@Test
void memberId를_전달하면_해당_회원의_좋아요한_코디를_반환한다() {
// when
List<FavoriteCoordinateResponse> responses =
coordinateService.getFavoriteCoordinates(1L);

// then
assertThat(responses)
.extracting("coordinateId", "imageUrl", "coordinateName")
.containsExactly(
tuple(1L, "testUrl1", "testName1"), tuple(2L, "testUrl2", "testName2"));
}

@Test
void 비공개_계정의_memberId로_조회하면_예외가_발생한다() {
// given
Member member = memberRepository.findById(2L).orElseThrow();
member.changeVisibility();
memberRepository.saveAndFlush(member);

// when & then
assertThatThrownBy(() -> coordinateService.getFavoriteCoordinates(2L))
.isInstanceOf(BaseCustomException.class)
.hasMessage(MemberErrorCode.PRIVATE_MEMBER_ACCESS_DENIED.getMessage());
}

@Test
void 차단_관계의_memberId로_조회하면_예외가_발생한다() {
// given
Member currentMember = memberRepository.findById(1L).orElseThrow();
Member targetMember = memberRepository.findById(2L).orElseThrow();
blockRepository.save(Block.createBlock(currentMember, targetMember));

// when & then
assertThatThrownBy(() -> coordinateService.getFavoriteCoordinates(2L))
.isInstanceOf(BaseCustomException.class)
.hasMessage(MemberErrorCode.BLOCKED_MEMBER_ACCESS_DENIED.getMessage());
}
}

@Nested
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,27 @@ void setUp() {
.isInstanceOf(BaseCustomException.class)
.hasMessage(MemberErrorCode.MEMBER_NOT_FOUND.getMessage());
}

@Test
void 내가_차단한_회원의_정보를_조회하면_예외가_발생한다() {
// when & then
assertThatThrownBy(() -> memberService.getMemberInfo(3L))
.isInstanceOf(BaseCustomException.class)
.hasMessage(MemberErrorCode.BLOCKED_MEMBER_ACCESS_DENIED.getMessage());
}

@Test
void 나를_차단한_회원의_정보를_조회하면_예외가_발생한다() {
// given
Member currentMember = memberRepository.findById(1L).orElseThrow();
Member targetMember = memberRepository.findById(2L).orElseThrow();
blockRepository.save(Block.createBlock(targetMember, currentMember));

// when & then
assertThatThrownBy(() -> memberService.getMemberInfo(2L))
.isInstanceOf(BaseCustomException.class)
.hasMessage(MemberErrorCode.BLOCKED_MEMBER_ACCESS_DENIED.getMessage());
}
}

@Nested
Expand Down