Skip to content

Commit

Permalink
Merge pull request #205 from Gamegoo-repo/feat/201
Browse files Browse the repository at this point in the history
[Feat/201] 친구 검색 기능 구현 및 친구 목록 조회 페이징 추가
  • Loading branch information
Eunjin3395 authored Sep 5, 2024
2 parents 3f95e7a + b76c722 commit 8282fca
Show file tree
Hide file tree
Showing 12 changed files with 279 additions and 95 deletions.
53 changes: 28 additions & 25 deletions src/main/java/com/gamegoo/apiPayload/code/status/ErrorStatus.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public enum ErrorStatus implements BaseErrorCode {

// 페이징 관련 에러
PAGE_INVALID(HttpStatus.BAD_REQUEST, "PAGE401", "페이지 값은 1 이상이어야 합니다."),
CURSOR_INVALID(HttpStatus.BAD_REQUEST, "PAGE402", "커서 값은 1 이상이어야 합니다."),

// Member 관련 에러
PASSWORD_INVALID(HttpStatus.BAD_REQUEST, "MEMBER400", "비밀번호가 불일치합니다."),
Expand Down Expand Up @@ -58,14 +59,14 @@ public enum ErrorStatus implements BaseErrorCode {
// Riot 관련 에러
RIOT_NOT_FOUND(HttpStatus.NOT_FOUND, "RIOT404", "해당 Riot 계정이 존재하지 않습니다."),
RIOT_MATCH_NOT_FOUND(HttpStatus.NOT_FOUND, "RIOTMATCH404",
"해당 Riot 계정의 매칭을 불러오는 도중 에러가 발생했습니다. 최근 100판 이내 이벤트 매칭 제외, 일반 매칭(일반게임,랭크게임,칼바람)을 많이 한 계정으로 다시 시도하세요."),
"해당 Riot 계정의 매칭을 불러오는 도중 에러가 발생했습니다. 최근 100판 이내 이벤트 매칭 제외, 일반 매칭(일반게임,랭크게임,칼바람)을 많이 한 계정으로 다시 시도하세요."),
RIOT_PREFER_CHAMPION_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "RIOTCHAMPION500",
"선호 챔피언을 연동하는 도중 에러가 발생했습니다"),
"선호 챔피언을 연동하는 도중 에러가 발생했습니다"),
CHAMPION_NOT_FOUND(HttpStatus.NOT_FOUND, "CHAMPION404", "해당 챔피언이 존재하지 않습니다."),
RIOT_MEMBER_CONFLICT(HttpStatus.CONFLICT, "RIOT409", "해당 이메일 계정은 이미 다른 RIOT 계정과 연동되었습니다."),
RIOT_ACCOUNT_CONFLICT(HttpStatus.CONFLICT, "RIOT409", "해당 RIOT 계정은 이미 다른 이메일과 연동되어있습니다."),
RIOT_INSUFFICIENT_MATCHES(HttpStatus.NOT_FOUND, "RIOT404",
"해당 RIOT 계정은 최근 100판 이내에 솔로랭크, 자유랭크, 일반게임, 칼바람을 플레이한 적이 없기 때문에 선호하는 챔피언 3명을 정할 수 없습니다."),
"해당 RIOT 계정은 최근 100판 이내에 솔로랭크, 자유랭크, 일반게임, 칼바람을 플레이한 적이 없기 때문에 선호하는 챔피언 3명을 정할 수 없습니다."),
RIOT_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "RIOT500", "RIOT API 연동 중 에러가 발생했습니다."),

// 차단 관련 에러
Expand All @@ -80,7 +81,7 @@ public enum ErrorStatus implements BaseErrorCode {

// 게시판 글 작성 관련 에러
BOARD_GAME_STYLE_BAD_REQUEST(HttpStatus.BAD_REQUEST, "BOARD400",
"게임 스타일 선택 개수(최대 3개)를 초과했습니다."),
"게임 스타일 선택 개수(최대 3개)를 초과했습니다."),
GAME_MODE_INVALID(HttpStatus.BAD_REQUEST, "BOARD401", "게임모드 값은 1~4만 가능합니다."),
MAIN_POSITION_INVALID(HttpStatus.BAD_REQUEST, "BOARD401", "주포지션 값은 0~5만 가능합니다."),
SUB_POSITION_INVALID(HttpStatus.BAD_REQUEST, "BOARD401", "부포지션 값은 0~5만 가능합니다."),
Expand All @@ -96,11 +97,11 @@ public enum ErrorStatus implements BaseErrorCode {
// 매너평가 관련 에러
MANNER_TARGET_MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "MANNER401", "매너 평가 대상 회원을 찾을 수 없습니다."),
BAD_MANNER_TARGET_MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "MANNER401",
"비매너 평가 대상 회원을 찾을 수 없습니다."),
"비매너 평가 대상 회원을 찾을 수 없습니다."),
MANNER_UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "MANNER401", "매너평가 작성자만 수정 가능합니다."),
MANNER_KEYWORD_TYPE_INVALID(HttpStatus.BAD_REQUEST, "MANNER401", "매너 키워드 유형은 1~6만 가능합니다."),
BAD_MANNER_KEYWORD_TYPE_INVALID(HttpStatus.BAD_REQUEST, "MANNER401",
"비매너 키워드 유형은 7~12만 가능합니다."),
"비매너 키워드 유형은 7~12만 가능합니다."),
MANNER_KEYWORD_NOT_FOUND(HttpStatus.NOT_FOUND, "MANNER404", "해당 매너 키워드를 찾을 수 없습니다."),
MANNER_NOT_FOUND(HttpStatus.NOT_FOUND, "MANNER404", "해당 매너평가를 찾을 수 없습니다."),
BAD_MANNER_NOT_FOUND(HttpStatus.NOT_FOUND, "MANNER404", "해당 비매너평가를 찾을 수 없습니다."),
Expand All @@ -114,43 +115,45 @@ public enum ErrorStatus implements BaseErrorCode {
CHATROOM_ACCESS_DENIED(HttpStatus.BAD_REQUEST, "CHAT403", "접근할 수 없는 채팅방 입니다."),
CHAT_MESSAGE_NOT_FOUND(HttpStatus.NOT_FOUND, "CHAT404", "해당 메시지를 찾을 수 없습니다"),
CHAT_TARGET_IS_BLOCKED_CHAT_START_FAILED(HttpStatus.FORBIDDEN, "CHAT405",
"채팅 상대 회원을 차단한 상태입니다. 채팅 시작이 불가능합니다."),
"채팅 상대 회원을 차단한 상태입니다. 채팅 시작이 불가능합니다."),
BLOCKED_BY_CHAT_TARGET_CHAT_START_FAILED(HttpStatus.FORBIDDEN, "CHAT406",
"채팅 상대 회원이 나를 차단했습니다. 채팅 시작이 불가능합니다."),
"채팅 상대 회원이 나를 차단했습니다. 채팅 시작이 불가능합니다."),
CHAT_TARGET_IS_BLOCKED_SEND_CHAT_FAILED(HttpStatus.FORBIDDEN, "CHAT407",
"채팅 상대 회원을 차단한 상태입니다. 채팅 메시지 전송이 불가능합니다."),
"채팅 상대 회원을 차단한 상태입니다. 채팅 메시지 전송이 불가능합니다."),
BLOCKED_BY_CHAT_TARGET_SEND_CHAT_FAILED(HttpStatus.FORBIDDEN, "CHAT408",
"채팅 상대 회원이 나를 차단했습니다. 채팅 메시지 전송이 불가능합니다."),
"채팅 상대 회원이 나를 차단했습니다. 채팅 메시지 전송이 불가능합니다."),
CHAT_TARGET_MEMBER_ID_INVALID(HttpStatus.BAD_REQUEST, "CHAT409", "채팅방 시작 대상 회원 id 값이 잘못되었습니다."),

// 친구 관련 에러
FRIEND_BAD_REQUEST(HttpStatus.BAD_REQUEST, "FRIEND401", "잘못된 친구 요청입니다."),
FRIEND_TARGET_IS_BLOCKED(HttpStatus.BAD_REQUEST, "FRIEND402",
"내가 차단한 회원입니다. 친구 요청을 보낼 수 없습니다."),
"내가 차단한 회원입니다. 친구 요청을 보낼 수 없습니다."),
BLOCKED_BY_FRIEND_TARGET(HttpStatus.BAD_REQUEST, "FRIEND403",
"나를 차단한 회원입니다. 친구 요청을 보낼 수 없습니다."),
"나를 차단한 회원입니다. 친구 요청을 보낼 수 없습니다."),
MY_PENDING_FRIEND_REQUEST_EXIST(HttpStatus.BAD_REQUEST, "FRIEND404",
"해당 회원에게 보낸 수락 대기 중인 친구 요청이 존재합니다. 친구 요청을 보낼 수 없습니다."),
"해당 회원에게 보낸 수락 대기 중인 친구 요청이 존재합니다. 친구 요청을 보낼 수 없습니다."),
TARGET_PENDING_FRIEND_REQUEST_EXIST(HttpStatus.BAD_REQUEST, "FRIEND405",
"해당 회원이 나에게 보낸 친구 요청이 수락 대기 중 입니다. 해당 요청을 수락 해주세요."),
"해당 회원이 나에게 보낸 친구 요청이 수락 대기 중 입니다. 해당 요청을 수락 해주세요."),
ALREADY_FRIEND(HttpStatus.BAD_REQUEST, "FRIEND406",
"두 회원은 이미 친구 관계 입니다. 친구 요청을 보낼 수 없습니다."),
PENDING_FRIEND_REQUEST_NOT_EXIST(HttpStatus.NOT_FOUND, "FRIEND407",
"취소/수락/거절할 친구 요청이 존재하지 않습니다."),
MEMBERS_NOT_FRIEND(HttpStatus.BAD_REQUEST, "FRIEND408", "두 회원은 친구 관계가 아닙니다."),
ALREADY_STAR_FRIEND(HttpStatus.BAD_REQUEST, "FRIEND409", "이미 즐겨찾기 되어 있는 친구입니다."),
NOT_STAR_FRIEND(HttpStatus.BAD_REQUEST, "FRIEND410", "즐겨찾기 되어 있는 친구가 아닙니다."),
FRIEND_SEARCH_QUERY_BAD_REQUEST(HttpStatus.BAD_REQUEST, "FRIEND411",
"친구 검색 쿼리는 100자 이하여야 합니다."),

// 알림 관련 에러
NOTIFICATION_TYPE_NOT_FOUND(HttpStatus.NOT_FOUND, "NOTI401", "해당 알림 타입 데이터를 찾을 수 없습니다."),
NOTIFICATION_METHOD_BAD_REQUEST(HttpStatus.BAD_REQUEST, "NOTI402", "알림 생성 메소드 호출이 잘못되었습니다."),
INVALID_NOTIFICATION_TYPE(HttpStatus.BAD_REQUEST, "NOTI403",
"잘못된 알림 조회 타입입니다. general과 friend 중 하나를 입력하세요."),
"잘못된 알림 조회 타입입니다. general과 friend 중 하나를 입력하세요."),
NOTIFICATION_NOT_FOUND(HttpStatus.NOT_FOUND, "NOTI404", "해당 알림 내역을 찾을 수 없습니다."),

// SOCKET 서버 API 호출 에러
SOCKET_API_RESPONSE_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "SOCKET501",
"socket서버 api 요청에 실패했습니다.");
"socket서버 api 요청에 실패했습니다.");

private final HttpStatus httpStatus;
private final String code;
Expand All @@ -159,19 +162,19 @@ public enum ErrorStatus implements BaseErrorCode {
@Override
public ErrorReasonDTO getReason() {
return ErrorReasonDTO.builder()
.message(message)
.code(code)
.isSuccess(false)
.build();
.message(message)
.code(code)
.isSuccess(false)
.build();
}

@Override
public ErrorReasonDTO getReasonHttpStatus() {
return ErrorReasonDTO.builder()
.message(message)
.code(code)
.isSuccess(false)
.httpStatus(httpStatus)
.build();
.message(message)
.code(code)
.isSuccess(false)
.httpStatus(httpStatus)
.build();
}
}
36 changes: 29 additions & 7 deletions src/main/java/com/gamegoo/controller/member/FriendController.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.gamegoo.converter.MemberConverter;
import com.gamegoo.domain.friend.Friend;
import com.gamegoo.dto.member.MemberResponse;
import com.gamegoo.dto.member.MemberResponse.friendInfoDTO;
import com.gamegoo.dto.member.MemberResponse.friendRequestResultDTO;
import com.gamegoo.dto.member.MemberResponse.starFriendResultDTO;
import com.gamegoo.service.member.FriendService;
Expand All @@ -15,12 +16,14 @@
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Slice;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
Expand All @@ -32,18 +35,37 @@ public class FriendController {

private final FriendService friendService;

@Operation(summary = "친구 목록 조회 API", description = "해당 회원의 친구 목록을 조회하는 API 입니다. 이름 오름차순으로 정렬해 제공합니다.")
@Operation(summary = "친구 목록 조회 API", description =
"해당 회원의 친구 목록을 조회하는 API 입니다. 이름 오름차순(한글-영문-숫자 순)으로 정렬해 제공합니다.\n\n"
+ "cursor를 보내지 않으면 상위 10개 친구 목록을 조회합니다.")
@Parameter(name = "cursor", description = "페이징을 위한 커서, 이전 친구 목록 조회에서 응답받은 next_cursor를 보내주세요.")
@GetMapping
public ApiResponse<List<MemberResponse.friendInfoDTO>> getFriendList() {
public ApiResponse<MemberResponse.friendListDTO> getFriendList(
@RequestParam(name = "cursor", required = false) Long cursorId
) {
Long memberId = JWTUtil.getCurrentUserId();
List<Friend> friends = friendService.getFriends(memberId);

List<MemberResponse.friendInfoDTO> friendInfoDTOList = friends.stream()
.map(MemberConverter::toFriendInfoDto).collect(
Collectors.toList());
Slice<Friend> friends = friendService.getFriends(memberId, cursorId);

return ApiResponse.onSuccess(friendInfoDTOList);
return ApiResponse.onSuccess(MemberConverter.toFriendListDTO(friends));

}

@Operation(summary = "소환사명으로 친구 검색 API", description =
"해당 회원의 친구 중, query string으로 시작하는 소환사명을 가진 모든 친구 목록을 조회합니다.")
@Parameter(name = "query", description = "친구 목록 검색을 위한 소환사명 string으로, 100자 이하여야 합니다.")
@GetMapping("/search")
public ApiResponse<List<friendInfoDTO>> searchFriend(
@RequestParam(name = "query") String query
) {
Long memberId = JWTUtil.getCurrentUserId();

List<Friend> friends = friendService.searchFriendByQueryString(memberId, query);

List<friendInfoDTO> friendInfoDTOList = friends.stream()
.map(MemberConverter::toFriendInfoDto).collect(Collectors.toList());

return ApiResponse.onSuccess(friendInfoDTOList);
}

@Operation(summary = "모든 친구 id 조회 API", description = "해당 회원의 모든 친구 id 목록을 조회하는 API 입니다.\n\n"
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/com/gamegoo/converter/MemberConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
import com.gamegoo.domain.friend.Friend;
import com.gamegoo.domain.member.Member;
import com.gamegoo.dto.member.MemberResponse;
import com.gamegoo.dto.member.MemberResponse.friendInfoDTO;
import com.gamegoo.util.MemberUtils;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Slice;

public class MemberConverter {

Expand Down Expand Up @@ -124,12 +126,27 @@ public static MemberResponse.memberProfileDTO toMemberProfileDTO(Member member,

}

public static MemberResponse.friendListDTO toFriendListDTO(Slice<Friend> friends) {
List<friendInfoDTO> friendInfoDTOList = friends.stream()
.map(MemberConverter::toFriendInfoDto).collect(Collectors.toList());
return MemberResponse.friendListDTO.builder()
.friendInfoDTOList(friendInfoDTOList)
.list_size(friendInfoDTOList.size())
.has_next(friends.hasNext())
.next_cursor(
friends.hasNext() ? friends.getContent().get(friendInfoDTOList.size() - 1)
.getToMember().getId()
: null)
.build();
}

public static MemberResponse.friendInfoDTO toFriendInfoDto(Friend friend) {
return MemberResponse.friendInfoDTO.builder()
.memberId(friend.getToMember().getId())
.name(friend.getToMember().getGameName())
.memberProfileImg(friend.getToMember().getProfileImage())
.isLiked(friend.getIsLiked())
.isBlind(friend.getToMember().getBlind())
.build();
}

Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/gamegoo/dto/chat/ChatResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ public static class ChatroomViewDTO {
Long targetMemberId;
Integer targetMemberImg;
String targetMemberName;
boolean friend;
boolean blocked;
Boolean friend;
Boolean blocked;
Long friendRequestMemberId;
String lastMsg;
String lastMsgAt;
Expand Down
15 changes: 14 additions & 1 deletion src/main/java/com/gamegoo/dto/member/MemberResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,18 @@ public static class memberProfileDTO {
List<ChampionResponseDTO> championResponseDTOList;
}

@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public static class friendListDTO {

List<friendInfoDTO> friendInfoDTOList;
Integer list_size;
Boolean has_next;
Long next_cursor;
}

@Builder
@Getter
@NoArgsConstructor
Expand All @@ -142,7 +154,8 @@ public static class friendInfoDTO {
Long memberId;
String name;
Integer memberProfileImg;
boolean isLiked;
Boolean isLiked;
Boolean isBlind;
}

@Builder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public static class notificationDTO {
int notificationType;
String content;
String pageUrl;
boolean read;
Boolean read;
LocalDateTime createdAt;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
package com.gamegoo.repository.friend;

import com.gamegoo.domain.member.Member;
import com.gamegoo.domain.friend.Friend;

import com.gamegoo.domain.member.Member;
import java.util.List;
import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface FriendRepository extends JpaRepository<Friend, Long> {
public interface FriendRepository extends JpaRepository<Friend, Long>, FriendRepositoryCustom {

List<Friend> findAllByFromMemberId(Long memberId);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.gamegoo.repository.friend;

import com.gamegoo.domain.friend.Friend;
import java.util.List;
import org.springframework.data.domain.Slice;

interface FriendRepositoryCustom {

Slice<Friend> findFriendsByCursorAndOrdered(Long cursor, Long memberId, Integer pageSize);

List<Friend> findFriendsByQueryStringAndOrdered(String queryString, Long memberId);
}
Loading

0 comments on commit 8282fca

Please sign in to comment.