diff --git a/src/main/java/UMC/campusNote/friend/controller/FriendController.java b/src/main/java/UMC/campusNote/friend/controller/FriendController.java index 3c95172..8d2483f 100644 --- a/src/main/java/UMC/campusNote/friend/controller/FriendController.java +++ b/src/main/java/UMC/campusNote/friend/controller/FriendController.java @@ -1,27 +1,54 @@ package UMC.campusNote.friend.controller; +import UMC.campusNote.auth.jwt.JwtProvider; import UMC.campusNote.common.ApiResponse; import UMC.campusNote.friend.dto.FriendRequestDTO; +import UMC.campusNote.friend.dto.FriendResponseDTO; import UMC.campusNote.friend.service.FriendService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + +import java.util.List; @RestController @RequiredArgsConstructor -@RequestMapping("/api/v1/friend") +@RequestMapping("/api/v1/friends") public class FriendController { private final FriendService friendService; + @PostMapping + @Operation(summary = "친구 추가 기능 API", description = "친구 관계를 추가하는 API입니다.") private ApiResponse addFriend(@Valid @RequestBody FriendRequestDTO.AddFriendReqDTO addFriendReqDto){ friendService.addFriend(addFriendReqDto); return ApiResponse.onSuccess(null); } + + + @GetMapping("/{userId}") + @Operation(summary = "친구 조회 기능 API", description = "유저의 친구를 조회하는 API입니다.") + @Parameters({ + @Parameter(name = "userId", description = "유저 id 입니다.") + }) + private ApiResponse> friendList(@PathVariable("userId") Long userId){ + List friendList = friendService.findFriendList(userId); + + return ApiResponse.onSuccess(friendList); + } + + @DeleteMapping("/{userId}/{friendId}") + @Operation(summary = "친구 삭제 기능 API", description = "") + private ApiResponse deleteFriend(@PathVariable("userId") Long userId, @PathVariable("friendId") Long friendId){ + friendService.deleteFriend(userId, friendId); + + return ApiResponse.onSuccess(null); + } } diff --git a/src/main/java/UMC/campusNote/friend/converter/FriendConverter.java b/src/main/java/UMC/campusNote/friend/converter/FriendConverter.java index 9d4ae3a..278b003 100644 --- a/src/main/java/UMC/campusNote/friend/converter/FriendConverter.java +++ b/src/main/java/UMC/campusNote/friend/converter/FriendConverter.java @@ -1,5 +1,6 @@ package UMC.campusNote.friend.converter; +import UMC.campusNote.friend.dto.FriendResponseDTO; import UMC.campusNote.friend.entity.Friend; import UMC.campusNote.user.entity.User; @@ -10,4 +11,12 @@ public static Friend fromEntity(User user1, User user2){ .user2(user2) .build(); } + + public static FriendResponseDTO.friendListDTO toFriendListDTO(User user){ + return FriendResponseDTO.friendListDTO.builder() + .friendId(user.getId()) + .img(user.getImg()) + .name(user.getName()) + .build(); + } } diff --git a/src/main/java/UMC/campusNote/friend/dto/AddFriendReqDto.java b/src/main/java/UMC/campusNote/friend/dto/AddFriendReqDto.java deleted file mode 100644 index bd0de42..0000000 --- a/src/main/java/UMC/campusNote/friend/dto/AddFriendReqDto.java +++ /dev/null @@ -1,17 +0,0 @@ -package UMC.campusNote.friend.dto; - -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import lombok.*; - -@AllArgsConstructor -@NoArgsConstructor -@Getter -@Setter -@Builder -public class AddFriendReqDto { - @NotNull - private Long inviterUserId; - @NotNull - private Long invitedUserId; -} diff --git a/src/main/java/UMC/campusNote/friend/dto/FriendResponseDTO.java b/src/main/java/UMC/campusNote/friend/dto/FriendResponseDTO.java new file mode 100644 index 0000000..37fca64 --- /dev/null +++ b/src/main/java/UMC/campusNote/friend/dto/FriendResponseDTO.java @@ -0,0 +1,17 @@ +package UMC.campusNote.friend.dto; + +import lombok.*; + +public class FriendResponseDTO { + @AllArgsConstructor + @NoArgsConstructor + @Getter + @Setter + @Builder + public static class friendListDTO{ + private Long friendId; + private String name; + private String img; + } + +} diff --git a/src/main/java/UMC/campusNote/friend/repository/FriendRepository.java b/src/main/java/UMC/campusNote/friend/repository/FriendRepository.java index 6624b6e..26daf6a 100644 --- a/src/main/java/UMC/campusNote/friend/repository/FriendRepository.java +++ b/src/main/java/UMC/campusNote/friend/repository/FriendRepository.java @@ -4,9 +4,12 @@ import UMC.campusNote.user.entity.User; import io.lettuce.core.dynamic.annotation.Param; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; +import java.util.List; import java.util.Optional; @Repository @@ -15,4 +18,10 @@ public interface FriendRepository extends JpaRepository { @Query("SELECT f FROM Friend f WHERE (f.user1=:user1 AND f.user2=:user2) OR (f.user1=:user2 AND f.user2=:user1)") Optional findByUser1AndUser2(@Param("user1") User user1, @Param("user2") User user2); + @Query("SELECT f FROM Friend f WHERE f.user1=:user OR f.user2=:user") + List findAllByUser1(@Param("user1") User user); + + @Modifying + @Query("DELETE FROM Friend f WHERE (f.user1=:user1 AND f.user2=:user2) OR (f.user1=:user2 AND f.user2=:user1)") + void deleteByUser1AndUser2(@Param("user1") User user1, @Param("user2") User user2); } diff --git a/src/main/java/UMC/campusNote/friend/service/FriendService.java b/src/main/java/UMC/campusNote/friend/service/FriendService.java index f878872..c8a6145 100644 --- a/src/main/java/UMC/campusNote/friend/service/FriendService.java +++ b/src/main/java/UMC/campusNote/friend/service/FriendService.java @@ -4,12 +4,16 @@ import UMC.campusNote.friend.converter.FriendConverter; import UMC.campusNote.friend.dto.FriendRequestDTO; +import UMC.campusNote.friend.dto.FriendResponseDTO; import UMC.campusNote.friend.entity.Friend; import UMC.campusNote.friend.repository.FriendRepository; import UMC.campusNote.user.entity.User; import UMC.campusNote.user.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; import static UMC.campusNote.common.code.status.ErrorStatus.*; @@ -27,10 +31,8 @@ public void addFriend(FriendRequestDTO.AddFriendReqDTO addFriendReqDto) { if (invitedId.equals(inviterId)) throw new GeneralException(FRIEND_NOT_MYSELF); - User inviter = userRepository.findById(inviterId) - .orElseThrow(() -> new GeneralException(USER_NOT_FOUND)); - User invited = userRepository.findById(invitedId) - .orElseThrow(() -> new GeneralException(USER_NOT_FOUND)); + User inviter = findUser(inviterId); + User invited = findUser(invitedId); friendRepository.findByUser1AndUser2(inviter, invited) .ifPresent(friend1 -> { @@ -41,4 +43,33 @@ public void addFriend(FriendRequestDTO.AddFriendReqDTO addFriendReqDto) { friendRepository.save(friend); } + + public List findFriendList(Long userId){ + User user = findUser(userId); + + List friends = friendRepository.findAllByUser1(user); + + List friendList = friends.stream() + .map((friend) -> { + if (friend.getUser1().equals(user)) return FriendConverter.toFriendListDTO(friend.getUser2()); + else return FriendConverter.toFriendListDTO(friend.getUser1()); + }) + .toList(); + + return friendList; + } + + @Transactional + public void deleteFriend(Long userId, Long friendId){ + User user = findUser(userId); + User friend = findUser(friendId); + + friendRepository.deleteByUser1AndUser2(user, friend); + } + + private User findUser(Long userId){ + return userRepository.findById(userId) + .orElseThrow(() -> new GeneralException(USER_NOT_FOUND)); + } + } diff --git a/src/test/java/UMC/campusNote/friend/controller/FriendControllerTest.java b/src/test/java/UMC/campusNote/friend/controller/FriendControllerTest.java deleted file mode 100644 index e6553f8..0000000 --- a/src/test/java/UMC/campusNote/friend/controller/FriendControllerTest.java +++ /dev/null @@ -1,42 +0,0 @@ -//package UMC.campusNote.friend.controller; -// -//import UMC.campusNote.friend.dto.AddFriendReqDto; -//import UMC.campusNote.friend.service.FriendService; -//import com.fasterxml.jackson.databind.ObjectMapper; -//import org.junit.jupiter.api.DisplayName; -//import org.junit.jupiter.api.Test; -//import org.springframework.beans.factory.annotation.Autowired; -//import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -//import org.springframework.boot.test.mock.mockito.MockBean; -//import org.springframework.http.MediaType; -//import org.springframework.test.web.servlet.MockMvc; -// -//import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -//import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -//import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -// -//@WebMvcTest(FriendControllerTest.class) -//public class FriendControllerTest { -// -// @Autowired -// private MockMvc mockMvc; -// -// @MockBean -// FriendService friendService; -// -// @Test -// @DisplayName("AddFriendDto 유효성 테스트") -// void validAddFriendDto() throws Exception{ -// AddFriendReqDto reqDto1 = AddFriendReqDto.builder().build(); -// -// String req1 = new ObjectMapper().writeValueAsString(reqDto1); -// -// mockMvc.perform( -// post("/api/v1/friend") -// .content(req1) -// .contentType(MediaType.APPLICATION_JSON)) -// .andExpect(status().isBadRequest()) -// .andDo(print()); -// -// } -//} diff --git a/src/test/java/UMC/campusNote/friend/service/FriendServiceTest.java b/src/test/java/UMC/campusNote/friend/service/FriendServiceTest.java index 61bf101..1be2bc3 100644 --- a/src/test/java/UMC/campusNote/friend/service/FriendServiceTest.java +++ b/src/test/java/UMC/campusNote/friend/service/FriendServiceTest.java @@ -1,13 +1,16 @@ package UMC.campusNote.friend.service; import UMC.campusNote.common.exception.GeneralException; +import UMC.campusNote.friend.converter.FriendConverter; import UMC.campusNote.friend.dto.FriendRequestDTO; +import UMC.campusNote.friend.dto.FriendResponseDTO; import UMC.campusNote.friend.entity.Friend; import UMC.campusNote.friend.repository.FriendRepository; import UMC.campusNote.user.entity.User; import UMC.campusNote.user.repository.UserRepository; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -16,6 +19,8 @@ import org.mockito.junit.jupiter.MockitoExtension; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import static org.mockito.Mockito.*; @@ -30,10 +35,9 @@ public class FriendServiceTest { @InjectMocks FriendService friendService; -// @BeforeEach -// public void setUp(){ -// -// } + //@BeforeEach + //public void setUp(){ + //} @Test @DisplayName("[addFriend service 성공] Add friend test") @@ -97,4 +101,60 @@ public void addFriendTest_FRIEND_ALREADY_EXIST(){ // friendRepository.save() 메서드가 호출되지 않았는지 검증 verify(friendRepository, never()).save(any(Friend.class)); } + + @Test + @DisplayName("[findFriendList service 성공] find friendList test") + void findFriendListTest() { + // Mock 데이터 설정 + Long userId=1L; + User user1 = User.builder() + .id(userId) + .build(); + User user2 = User.builder() + .id(2L) + .build(); + User user3 = User.builder() + .id(3L) + .build(); + + Friend friend1 = Friend.builder() + .user1(user1) + .user2(user2) + .build(); + Friend friend2 = Friend.builder() + .user1(user3) + .user2(user1) + .build(); + + List friends = new ArrayList<>(); + friends.add(friend1); + friends.add(friend2); + + List expectedFriendList = new ArrayList<>(); + expectedFriendList.add(FriendConverter.toFriendListDTO(friend1.getUser2())); + expectedFriendList.add(FriendConverter.toFriendListDTO(friend2.getUser1())); + + // userRepository의 findById 메소드 Mock 설정 + when(userRepository.findById(userId)).thenReturn(Optional.of(user1)); + + // friendRepository의 findAllByUser1 메소드 Mock 설정 + when(friendRepository.findAllByUser1(user1)).thenReturn(friends); + + // 테스트 대상 메소드 호출 + List actualFriendList = friendService.findFriendList(userId); + + // 결과 검증 + Assertions.assertEquals(expectedFriendList.size(), actualFriendList.size()); + for (int i = 0; i < expectedFriendList.size(); i++) { + FriendResponseDTO.friendListDTO expectedFriend = expectedFriendList.get(i); + FriendResponseDTO.friendListDTO actualFriend = actualFriendList.get(i); + Assertions.assertEquals(expectedFriend.getFriendId(), actualFriend.getFriendId()); + // 다른 필드에 대한 추가 검증 로직 작성 + } + + // userRepository의 findById 메소드가 정확히 1번 호출되었는지 검증 + verify(userRepository, times(1)).findById(userId); + // friendRepository의 findAllByUser1 메소드가 정확히 1번 호출되었는지 검증 + verify(friendRepository, times(1)).findAllByUser1(user1); + } }