diff --git a/src/main/java/com/fab/banggabgo/controller/MyContentController.java b/src/main/java/com/fab/banggabgo/controller/MyContentController.java index 895f4df..bbf70dd 100644 --- a/src/main/java/com/fab/banggabgo/controller/MyContentController.java +++ b/src/main/java/com/fab/banggabgo/controller/MyContentController.java @@ -12,11 +12,13 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; 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.RequestParam; import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; @@ -25,6 +27,7 @@ @RequiredArgsConstructor @RequestMapping("api/my") @PermitAll +@Validated public class MyContentController { private final MyContentService myContentService; @@ -70,4 +73,19 @@ public ResponseEntity postMyInfoImage(@AuthenticationPrincipal User user, return ApiResponse.builder().code(ResponseCode.RESPONSE_SUCCESS).data(result).toEntity(); } + @GetMapping("/from-applicants") + public ResponseEntity getMyFromApplicant(@AuthenticationPrincipal User user, + @RequestParam(defaultValue = "1") Integer page, + @RequestParam(defaultValue = "10") Integer size) { + var result = myContentService.getMyFromApplicantList(user, page, size); + return ApiResponse.builder().code(ResponseCode.RESPONSE_SUCCESS).data(result).toEntity(); + } + + @GetMapping("/to-applicants") + public ResponseEntity getMyToApplicantList(@AuthenticationPrincipal User user, + @RequestParam(defaultValue = "1") Integer page, + @RequestParam(defaultValue = "10") Integer size) { + var result = myContentService.getMyToApplicantList(user, page, size); + return ApiResponse.builder().code(ResponseCode.RESPONSE_SUCCESS).data(result).toEntity(); + } } diff --git a/src/main/java/com/fab/banggabgo/dto/apply/ApplyListResultDto.java b/src/main/java/com/fab/banggabgo/dto/apply/ApplyListResultDto.java new file mode 100644 index 0000000..934765c --- /dev/null +++ b/src/main/java/com/fab/banggabgo/dto/apply/ApplyListResultDto.java @@ -0,0 +1,56 @@ +package com.fab.banggabgo.dto.apply; + +import com.fab.banggabgo.entity.Apply; +import java.util.List; +import java.util.stream.Collectors; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ApplyListResultDto { + + Integer applyId; + Integer articleId; + String articleTitle; + Integer otherUserId; + String otherUserName; + String matchStatus; + + public static List toFromApplicantDtoList(List applyPage) { + return applyPage.stream().map(ApplyListResultDto::toFromApplicantDto) + .collect(Collectors.toList()); + } + + public static ApplyListResultDto toFromApplicantDto(Apply apply) { + return ApplyListResultDto.builder() + .applyId(apply.getId()) + .articleId(apply.getArticle().getId()) + .articleTitle(apply.getArticle().getTitle()) + .otherUserId(apply.getApplicantUser().getId()) + .otherUserName(apply.getApplicantUser().getNickname()) + .matchStatus(apply.getApproveStatus().getValue()) + .build(); + } + public static List toToApplicantDtoList(List applyPage) { + return applyPage.stream().map(ApplyListResultDto::toToApplicantDto) + .collect(Collectors.toList()); + } + + public static ApplyListResultDto toToApplicantDto(Apply apply) { + return ApplyListResultDto.builder() + .applyId(apply.getId()) + .articleId(apply.getArticle().getId()) + .articleTitle(apply.getArticle().getTitle()) + .otherUserId(apply.getArticle().getUser().getId()) + .otherUserName(apply.getArticle().getUser().getNickname()) + .matchStatus(apply.getApproveStatus().getValue()) + .build(); + } +} diff --git a/src/main/java/com/fab/banggabgo/repository/ApplyRepository.java b/src/main/java/com/fab/banggabgo/repository/ApplyRepository.java index fad4179..f21eb50 100644 --- a/src/main/java/com/fab/banggabgo/repository/ApplyRepository.java +++ b/src/main/java/com/fab/banggabgo/repository/ApplyRepository.java @@ -5,7 +5,7 @@ import org.springframework.stereotype.Repository; @Repository -public interface ApplyRepository extends JpaRepository { +public interface ApplyRepository extends JpaRepository, ApplyRepositoryCustom { boolean existsByApplicantUserIdAndArticleId(Integer applicantUserId, Integer articleId); } diff --git a/src/main/java/com/fab/banggabgo/repository/ApplyRepositoryCustom.java b/src/main/java/com/fab/banggabgo/repository/ApplyRepositoryCustom.java new file mode 100644 index 0000000..ac31195 --- /dev/null +++ b/src/main/java/com/fab/banggabgo/repository/ApplyRepositoryCustom.java @@ -0,0 +1,11 @@ +package com.fab.banggabgo.repository; + +import com.fab.banggabgo.entity.Apply; +import java.util.List; +import org.springframework.data.domain.Pageable; + +public interface ApplyRepositoryCustom { + + List getMyApplicant(Pageable pageable, Integer userId); + List getMyToApplicant(Pageable pageable, Integer userId); +} diff --git a/src/main/java/com/fab/banggabgo/repository/impl/ApplyRepositoryImpl.java b/src/main/java/com/fab/banggabgo/repository/impl/ApplyRepositoryImpl.java new file mode 100644 index 0000000..b3e275a --- /dev/null +++ b/src/main/java/com/fab/banggabgo/repository/impl/ApplyRepositoryImpl.java @@ -0,0 +1,45 @@ +package com.fab.banggabgo.repository.impl; + +import com.fab.banggabgo.entity.Apply; +import com.fab.banggabgo.entity.QApply; +import com.fab.banggabgo.repository.ApplyRepositoryCustom; +import com.querydsl.jpa.impl.JPAQueryFactory; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; + +@RequiredArgsConstructor +public class ApplyRepositoryImpl implements ApplyRepositoryCustom { + + private final JPAQueryFactory jpaQueryFactory; + + QApply qApply = QApply.apply; + + @Override + public List getMyApplicant(Pageable pageable, Integer userId) { + var pageQuery = jpaQueryFactory.selectFrom(qApply) + .leftJoin(qApply.applicantUser) + .fetchJoin() + .leftJoin(qApply.article) + .fetchJoin() + .where(qApply.article.user.id.eq(userId)) + .orderBy(qApply.lastModifiedDate.desc()) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()); + + return pageQuery.fetch(); + } + @Override + public List getMyToApplicant(Pageable pageable, Integer userId) { + var pageQuery = jpaQueryFactory.selectFrom(qApply) + .leftJoin(qApply.article) + .fetchJoin() + .leftJoin(qApply.article.user) + .where(qApply.applicantUser.id.eq(userId)) + .orderBy(qApply.lastModifiedDate.desc()) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()); + + return pageQuery.fetch(); + } +} diff --git a/src/main/java/com/fab/banggabgo/service/MyContentService.java b/src/main/java/com/fab/banggabgo/service/MyContentService.java index b2e7723..79426ce 100644 --- a/src/main/java/com/fab/banggabgo/service/MyContentService.java +++ b/src/main/java/com/fab/banggabgo/service/MyContentService.java @@ -1,9 +1,11 @@ package com.fab.banggabgo.service; import com.fab.banggabgo.common.exception.CustomException; +import com.fab.banggabgo.dto.apply.ApplyListResultDto; import com.fab.banggabgo.dto.mycontent.FavoriteArticleDto; import com.fab.banggabgo.dto.mycontent.MyArticleDto; import com.fab.banggabgo.dto.mycontent.MyInfoDto; +import com.fab.banggabgo.dto.mycontent.PatchMyInfoDto; import com.fab.banggabgo.dto.mycontent.PatchMyInfoRequestDto; import com.fab.banggabgo.dto.mycontent.PatchMyInfoResultDto; import com.fab.banggabgo.dto.mycontent.PatchMyNicknameRequestDto; @@ -29,4 +31,9 @@ PostMyInfoImageResultDto postMyInfoImage(User user, PostMyInfoImageRequestDto dt throws IOException; PatchMyInfoResultDto patchMyInfo(User user, PatchMyInfoRequestDto form); + PatchMyInfoResultDto patchMyInfo(User user, PatchMyInfoDto form); + + List getMyFromApplicantList(User user, Integer page, Integer size); + + List getMyToApplicantList(User user, Integer page, Integer size); } diff --git a/src/main/java/com/fab/banggabgo/service/impl/MyContentServiceImpl.java b/src/main/java/com/fab/banggabgo/service/impl/MyContentServiceImpl.java index 7b5911b..e13bc07 100644 --- a/src/main/java/com/fab/banggabgo/service/impl/MyContentServiceImpl.java +++ b/src/main/java/com/fab/banggabgo/service/impl/MyContentServiceImpl.java @@ -2,6 +2,7 @@ import com.fab.banggabgo.common.exception.CustomException; import com.fab.banggabgo.common.exception.ErrorCode; +import com.fab.banggabgo.dto.apply.ApplyListResultDto; import com.fab.banggabgo.dto.mycontent.FavoriteArticleDto; import com.fab.banggabgo.dto.mycontent.MyArticleDto; import com.fab.banggabgo.dto.mycontent.MyInfoDto; @@ -12,6 +13,7 @@ import com.fab.banggabgo.dto.mycontent.PostMyInfoImageRequestDto; import com.fab.banggabgo.dto.mycontent.PostMyInfoImageResultDto; import com.fab.banggabgo.entity.User; +import com.fab.banggabgo.repository.ApplyRepository; import com.fab.banggabgo.repository.ArticleRepository; import com.fab.banggabgo.repository.UserRepository; import com.fab.banggabgo.service.MyContentService; @@ -25,6 +27,8 @@ import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; @Service @@ -33,6 +37,7 @@ public class MyContentServiceImpl implements MyContentService { private final ArticleRepository articleRepository; private final UserRepository userRepository; + private final ApplyRepository applyRepository; private final S3Service s3Service; @Override @@ -98,9 +103,25 @@ public User convertUserData(User user, PatchMyInfoRequestDto dto) { changed_user.setActivityTime(ActivityTime.fromValue(dto.getActivityTime())); changed_user.setTag(new HashSet<>(dto.getTags())); changed_user.setDetail(dto.getDetail()); - }catch (Exception e){ + } catch (Exception e) { throw new CustomException(ErrorCode.PATCH_MY_INFO_CONVERT_FAIL); } return changed_user; } + + public List getMyFromApplicantList(User user, Integer page, Integer size) { + page = page > 0 ? page - 1 : 0; + + Pageable pageable = PageRequest.of(page, size); + return ApplyListResultDto.toFromApplicantDtoList( + applyRepository.getMyApplicant(pageable, user.getId())); + } + + public List getMyToApplicantList(User user, Integer page, Integer size) { + page = page > 0 ? page - 1 : 0; + + Pageable pageable = PageRequest.of(page, size); + return ApplyListResultDto.toToApplicantDtoList( + applyRepository.getMyToApplicant(pageable, user.getId())); + } } diff --git a/src/test/java/com/fab/banggabgo/controller/MyContentControllerTest.java b/src/test/java/com/fab/banggabgo/controller/MyContentControllerTest.java index 5d12950..55e69df 100644 --- a/src/test/java/com/fab/banggabgo/controller/MyContentControllerTest.java +++ b/src/test/java/com/fab/banggabgo/controller/MyContentControllerTest.java @@ -136,6 +136,78 @@ void patchMyInfo() throws Exception { //then } + @Nested + @DisplayName("내가받은 신청자리스트") + class applicantList { + + @Test + @DisplayName("신청자리스트 - 성공") + @WithMockUser + void successGetApplicantList() throws Exception{ + mockMvc.perform(get("/api/my/from-applicants?page=1&size=4") + .with(SecurityMockMvcRequestPostProcessors.csrf())) + .andExpect(status().isOk()); + } + @Test + @DisplayName("신청자리스트 - 성공 페이지 누락") + @WithMockUser + void successLostPageGetApplicantList() throws Exception{ + mockMvc.perform(get("/api/my/from-applicants?size=4") + .with(SecurityMockMvcRequestPostProcessors.csrf())) + .andExpect(status().isOk()); + } + @Test + @DisplayName("신청자리스트 - 성공 사이즈 누락") + @WithMockUser + void successLostSizeGetApplicantList() throws Exception{ + mockMvc.perform(get("/api/my/from-applicants?page=1") + .with(SecurityMockMvcRequestPostProcessors.csrf())) + .andExpect(status().isOk()); + } + @Test + @DisplayName("신청자리스트 - 실패 계정 누락") + void FailNonAuthGetApplicantList() throws Exception{ + mockMvc.perform(get("/api/my/from-applicants?page=1&size=4") + .with(SecurityMockMvcRequestPostProcessors.csrf())) + .andExpect(status().isUnauthorized()); + } + } + @Nested + @DisplayName("내가신청한 신청자리스트") + class toApplicantList { + + @Test + @DisplayName("신청한리스트 - 성공") + @WithMockUser + void successGetApplicantList() throws Exception{ + mockMvc.perform(get("/api/my/to-applicants?page=1&size=4") + .with(SecurityMockMvcRequestPostProcessors.csrf())) + .andExpect(status().isOk()); + } + @Test + @DisplayName("신청한리스트 - 성공 페이지 누락") + @WithMockUser + void successLostPageGetApplicantList() throws Exception{ + mockMvc.perform(get("/api/my/to-applicants?size=4") + .with(SecurityMockMvcRequestPostProcessors.csrf())) + .andExpect(status().isOk()); + } + @Test + @DisplayName("신청한리스트 - 성공 사이즈 누락") + @WithMockUser + void successLostSizeGetApplicantList() throws Exception{ + mockMvc.perform(get("/api/my/to-applicants?page=1") + .with(SecurityMockMvcRequestPostProcessors.csrf())) + .andExpect(status().isOk()); + } + @Test + @DisplayName("신청한리스트 - 실패 계정 누락") + void FailNonAuthGetApplicantList() throws Exception{ + mockMvc.perform(get("/api/my/to-applicants?page=1&size=4") + .with(SecurityMockMvcRequestPostProcessors.csrf())) + .andExpect(status().isUnauthorized()); + } + @Test @DisplayName("이미지 변경 테스트") @WithMockUser diff --git a/src/test/java/com/fab/banggabgo/service/impl/MyContentServiceImplTest.java b/src/test/java/com/fab/banggabgo/service/impl/MyContentServiceImplTest.java index d2d9fa2..04a29f9 100644 --- a/src/test/java/com/fab/banggabgo/service/impl/MyContentServiceImplTest.java +++ b/src/test/java/com/fab/banggabgo/service/impl/MyContentServiceImplTest.java @@ -3,6 +3,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -14,13 +15,26 @@ import com.fab.banggabgo.dto.mycontent.MyArticleDto; import com.fab.banggabgo.dto.mycontent.PatchMyInfoForm; import com.fab.banggabgo.dto.mycontent.PatchMyNicknameForm; +import com.fab.banggabgo.entity.Apply; +import com.fab.banggabgo.entity.Article; import com.fab.banggabgo.dto.mycontent.PostMyInfoImageRequestDto; import com.fab.banggabgo.entity.User; +import com.fab.banggabgo.repository.ApplyRepository; import com.fab.banggabgo.repository.ArticleRepository; import com.fab.banggabgo.repository.UserRepository; +import com.fab.banggabgo.type.ActivityTime; +import com.fab.banggabgo.type.ApproveStatus; +import com.fab.banggabgo.type.Gender; +import com.fab.banggabgo.type.MatchStatus; +import com.fab.banggabgo.type.Mbti; +import com.fab.banggabgo.type.Period; +import com.fab.banggabgo.type.Seoul; +import com.fab.banggabgo.type.UserRole; +import com.fab.banggabgo.type.UserType; import com.fab.banggabgo.service.S3Service; import java.io.IOException; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; @@ -32,10 +46,12 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.data.domain.Pageable; import org.springframework.mock.web.MockMultipartFile; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.test.context.support.WithMockUser; @ExtendWith(MockitoExtension.class) class MyContentServiceImplTest { @@ -44,6 +60,8 @@ class MyContentServiceImplTest { private ArticleRepository articleRepository; @Mock private UserRepository userRepository; + @Mock + private ApplyRepository applyRepository; @InjectMocks private MyContentServiceImpl myContentService; @Mock @@ -194,7 +212,87 @@ void patch_my_info_missedValue_form() { assertThrows(CustomException.class, () -> myContentService.patchMyInfo(stub_user, PatchMyInfoForm.toDto(form))); } + } + + @Nested + @DisplayName("신청자 목록 불러오기") + class fromApplicant { + + private final User loginUser = User.builder() + .id(1) + .email("test@email.com") + .password("abcd1234") + .nickname("테스트") + .userType(UserType.NORMAL) + .image("http://image_uri") + .matchStatus(MatchStatus.ACTIVITY) + .isSmoker(true) + .activityTime(ActivityTime.MORNING) + .gender(Gender.MALE) + .region(Seoul.DOBONG) + .mbti(Mbti.ENFP) + .minAge(20) + .maxAge(30) + .myAge(25) + .tag(new HashSet<>()) + .detail("abcdef") + .roles(List.of(UserRole.USER_ROLE)) + .build(); + + private final User appliedUser = User.builder() + .id(2) + .email("test2@email.com") + .password("abcdf12345") + .nickname("테스트2") + .userType(UserType.NORMAL) + .image("http://image_uri2") + .matchStatus(MatchStatus.ACTIVITY) + .isSmoker(true) + .activityTime(ActivityTime.MORNING) + .gender(Gender.MALE) + .region(Seoul.DOBONG) + .mbti(Mbti.ENFP) + .minAge(22) + .maxAge(28) + .myAge(26) + .tag(new HashSet<>()) + .detail("abcdeffdaa") + .roles(List.of(UserRole.USER_ROLE)) + .build(); + + private Article article = Article.builder() + .id(1) + .user(loginUser) + .title("테스트 게시글") + .content("test test test") + .region(Seoul.DOBONG) + .period(Period.ONETOTHREE) + .price(10000000) + .gender(Gender.MALE) + .isRecruiting(true) + .isDeleted(false) + .build(); + @Test + @DisplayName("신청자 목록 - 성공") + @WithMockUser + void getApplicantsSuccess() { + + when(applyRepository.getMyApplicant(any(), anyInt())).thenReturn(List.of(Apply.builder() + .approveStatus(ApproveStatus.WAIT) + .article(article) + .applicantUser(appliedUser) + .approveStatus(ApproveStatus.WAIT) + .build())); + var result = myContentService.getMyFromApplicantList(loginUser, 4, 1); + + verify(applyRepository, times(1)).getMyApplicant(any(Pageable.class), any(Integer.class)); + assertEquals(result.get(0).getMatchStatus(), ApproveStatus.WAIT.getValue()); + assertEquals(result.get(0).getArticleTitle(), article.getTitle()); + assertEquals(result.get(0).getArticleId(), article.getId()); + assertEquals(result.get(0).getOtherUserName(), appliedUser.getNickname()); + assertEquals(result.get(0).getOtherUserId(), appliedUser.getId()); + @Test @DisplayName("이미지 업로드하기") void postImage() throws IOException { @@ -223,7 +321,85 @@ void postImage() throws IOException { } + } + + @Nested + @DisplayName("신청한 목록 불러오기") + class toApplicant { + private final User loginUser = User.builder() + .id(1) + .email("test@email.com") + .password("abcd1234") + .nickname("테스트") + .userType(UserType.NORMAL) + .image("http://image_uri") + .matchStatus(MatchStatus.ACTIVITY) + .isSmoker(true) + .activityTime(ActivityTime.MORNING) + .gender(Gender.MALE) + .region(Seoul.DOBONG) + .mbti(Mbti.ENFP) + .minAge(20) + .maxAge(30) + .myAge(25) + .tag(new HashSet<>()) + .detail("abcdef") + .roles(List.of(UserRole.USER_ROLE)) + .build(); + + private final User appliedUser = User.builder() + .id(2) + .email("test2@email.com") + .password("abcdf12345") + .nickname("테스트2") + .userType(UserType.NORMAL) + .image("http://image_uri2") + .matchStatus(MatchStatus.ACTIVITY) + .isSmoker(true) + .activityTime(ActivityTime.MORNING) + .gender(Gender.MALE) + .region(Seoul.DOBONG) + .mbti(Mbti.ENFP) + .minAge(22) + .maxAge(28) + .myAge(26) + .tag(new HashSet<>()) + .detail("abcdeffdaa") + .roles(List.of(UserRole.USER_ROLE)) + .build(); + + private Article article = Article.builder() + .id(1) + .user(appliedUser) + .title("테스트 게시글") + .content("test test test") + .region(Seoul.DOBONG) + .period(Period.ONETOTHREE) + .price(10000000) + .gender(Gender.MALE) + .isRecruiting(true) + .isDeleted(false) + .build(); + @Test + @DisplayName("신청한 목록 - 성공") + @WithMockUser + void getApplicantsSuccess() { + when(applyRepository.getMyToApplicant(any(), anyInt())).thenReturn(List.of(Apply.builder() + .approveStatus(ApproveStatus.WAIT) + .article(article) + .applicantUser(loginUser) + .approveStatus(ApproveStatus.WAIT) + .build())); + + var result = myContentService.getMyToApplicantList(loginUser, 4, 1); + verify(applyRepository, times(1)).getMyToApplicant(any(Pageable.class), any(Integer.class)); + assertEquals(result.get(0).getMatchStatus(), ApproveStatus.WAIT.getValue()); + assertEquals(result.get(0).getArticleTitle(), article.getTitle()); + assertEquals(result.get(0).getArticleId(), article.getId()); + assertEquals(result.get(0).getOtherUserName(), appliedUser.getNickname()); + assertEquals(result.get(0).getOtherUserId(), appliedUser.getId()); + } } } \ No newline at end of file