Skip to content

Commit

Permalink
feat: 친구 관련 API 처리 (#71)
Browse files Browse the repository at this point in the history
* feat: 친구 신청 목록 조회 API 작성 #68

* feat: 친구 신청 수락, 거절 API 작성 #68

* feat: 유저 검색 API 작성 #68
  • Loading branch information
sanbonai06 authored Oct 19, 2023
1 parent 5b7ddef commit c102d63
Show file tree
Hide file tree
Showing 24 changed files with 495 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,19 @@
import org.springframework.data.web.PageableDefault;
import org.springframework.web.bind.annotation.*;
import tify.server.api.common.slice.SliceResponse;
import tify.server.api.user.model.dto.request.CreateNeighborUseCase;
import tify.server.api.user.model.dto.request.PatchNeighborsOrdersRequest;
import tify.server.api.user.model.dto.request.PutUserProfileRequest;
import tify.server.api.user.model.dto.request.UserOnBoardingRequest;
import tify.server.api.user.model.dto.response.OnBoardingStatusResponse;
import tify.server.api.user.service.*;
import tify.server.api.user.service.CreateNeighborUseCase;
import tify.server.domain.common.vo.UserFavorVo;
import tify.server.domain.common.vo.UserInfoVo;
import tify.server.domain.common.vo.UserProfileVo;
import tify.server.domain.common.vo.UserTagVo;
import tify.server.domain.domains.user.domain.LargeCategory;
import tify.server.domain.domains.user.dto.condition.UserCondition;
import tify.server.domain.domains.user.dto.model.RetrieveNeighborApplicationDTO;
import tify.server.domain.domains.user.dto.model.RetrieveNeighborDTO;

@SecurityRequirement(name = "access-token")
Expand All @@ -42,6 +44,10 @@ public class UserController {
private final UpdateNeighborUseCase updateNeighborUseCase;
private final CreateNeighborUseCase createNeighborUseCase;
private final RetrieveBirthdayNeighborUseCase retrieveBirthdayNeighborUseCase;
private final RetrieveNeighborApplicationUseCase retrieveNeighborApplicationUseCase;
private final AcceptanceNeighborApplicationUseCase acceptanceNeighborApplicationUseCase;
private final RejectNeighborApplicationUseCase rejectNeighborApplicationUseCase;
private final RetrieveUserListUseCase retrieveUserListUseCase;

// userId를 pathvariable로 받아서 그 해당 유저의 profile 정보를 리턴하기.
@Operation(summary = "유저 정보 조회")
Expand Down Expand Up @@ -76,7 +82,7 @@ public void putUserProfile(@RequestBody @Valid PutUserProfileRequest body) {
}

@Operation(summary = "유저 정보 조회 (토큰)")
@GetMapping
@GetMapping("/me")
public UserInfoVo getUserProfileInfoByToken() {
return userInfoUseCase.executeByToken();
}
Expand Down Expand Up @@ -140,4 +146,31 @@ public SliceResponse<RetrieveNeighborDTO> getBirthdayNeighbor(
@ParameterObject @PageableDefault Pageable pageable) {
return retrieveBirthdayNeighborUseCase.execute(pageable);
}

@Operation(summary = "친구 신청 목록을 조회합니다.")
@GetMapping("/neighbors/applications")
public SliceResponse<RetrieveNeighborApplicationDTO> getNeighborApplications(
@ParameterObject @PageableDefault Pageable pageable) {
return SliceResponse.of(retrieveNeighborApplicationUseCase.execute(pageable));
}

@Operation(summary = "친구 신청을 수락합니다.")
@PatchMapping("/neighbors/applications/{neighborApplicationId}/accept")
public void patchNeighborApplicationAccept(@PathVariable Long neighborApplicationId) {
acceptanceNeighborApplicationUseCase.execute(neighborApplicationId);
}

@Operation(summary = "친구 신청을 거절합니다.")
@PatchMapping("/neighbors/applications/{neighborApplicationId}/reject")
public void patchNeighborApplicationReject(@PathVariable Long neighborApplicationId) {
rejectNeighborApplicationUseCase.execute(neighborApplicationId);
}

@Operation(summary = "유저를 검색합니다.")
@GetMapping
public SliceResponse<UserInfoVo> getUsers(
@ParameterObject @PageableDefault Pageable pageable,
@ParameterObject UserCondition condition) {
return SliceResponse.of(retrieveUserListUseCase.execute(pageable, condition));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package tify.server.api.user.service;


import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;
import tify.server.api.config.security.SecurityUtils;
import tify.server.core.annotation.UseCase;
import tify.server.domain.domains.user.adaptor.NeighborAdaptor;
import tify.server.domain.domains.user.domain.Neighbor;
import tify.server.domain.domains.user.domain.NeighborApplication;
import tify.server.domain.domains.user.exception.AlreadyExistNeighborRelationshipException;
import tify.server.domain.domains.user.validator.NeighborValidator;

@UseCase
@RequiredArgsConstructor
@Transactional
public class AcceptanceNeighborApplicationUseCase {

private final NeighborAdaptor neighborAdaptor;
private final NeighborValidator neighborValidator;

public void execute(Long neighborApplicationId) {

// 나 (친구 신청을 받은 사람)
Long currentUserId = SecurityUtils.getCurrentUserId();
NeighborApplication neighborApplication =
neighborAdaptor.queryNeighborApplication(neighborApplicationId);

neighborValidator.userIdAndNeighborApplicationValidate(neighborApplication, currentUserId);

neighborApplication.accept();

// 상대방 (친구 신청을 보낸 사람)
Long toUserId = neighborApplication.getFromUserId();

// 친구 맺기 (toUserId, fromUserId inversion)
if (neighborAdaptor.existsNeighbor(currentUserId, toUserId)) {
throw AlreadyExistNeighborRelationshipException.EXCEPTION;
}

List<Neighbor> neighbors = neighborAdaptor.queryAllByFromUserId(currentUserId);

neighborAdaptor.save(
Neighbor.builder()
.fromUserId(currentUserId)
.toUserId(toUserId)
.isView(true)
.order((long) neighbors.size() + 1L)
.build());
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package tify.server.api.user.model.dto.request;
package tify.server.api.user.service;


import java.util.List;
Expand All @@ -9,6 +9,7 @@
import tify.server.domain.domains.user.adaptor.NeighborAdaptor;
import tify.server.domain.domains.user.adaptor.UserAdaptor;
import tify.server.domain.domains.user.domain.Neighbor;
import tify.server.domain.domains.user.domain.NeighborApplication;
import tify.server.domain.domains.user.domain.User;
import tify.server.domain.domains.user.exception.AlreadyExistNeighborRelationshipException;
import tify.server.domain.domains.user.exception.SelfNeighborException;
Expand Down Expand Up @@ -41,5 +42,16 @@ public void execute(Long toUserId) {
.isView(true)
.order((long) neighbors.size() + 1L)
.build());

// 반대편에서 이미 친구가 되어있다면 신청을 보내지 않음
if (!neighborAdaptor
.queryByFromUserIdAndToUserId(toUser.getId(), currentUserId)
.isPresent()) {
neighborAdaptor.saveNeighborApplication(
NeighborApplication.builder()
.fromUserId(SecurityUtils.getCurrentUserId())
.toUserId(toUserId)
.build());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package tify.server.api.user.service;


import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;
import tify.server.api.config.security.SecurityUtils;
import tify.server.core.annotation.UseCase;
import tify.server.domain.domains.user.adaptor.NeighborAdaptor;
import tify.server.domain.domains.user.domain.NeighborApplication;
import tify.server.domain.domains.user.validator.NeighborValidator;

@UseCase
@RequiredArgsConstructor
@Transactional
public class RejectNeighborApplicationUseCase {

private final NeighborAdaptor neighborAdaptor;
private final NeighborValidator neighborValidator;

public void execute(Long neighborApplicationId) {
Long currentUserId = SecurityUtils.getCurrentUserId();
NeighborApplication neighborApplication =
neighborAdaptor.queryNeighborApplication(neighborApplicationId);

neighborValidator.userIdAndNeighborApplicationValidate(neighborApplication, currentUserId);

neighborApplication.reject();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package tify.server.api.user.service;


import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.transaction.annotation.Transactional;
import tify.server.api.config.security.SecurityUtils;
import tify.server.core.annotation.UseCase;
import tify.server.domain.domains.user.adaptor.NeighborAdaptor;
import tify.server.domain.domains.user.dto.model.RetrieveNeighborApplicationDTO;

@UseCase
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class RetrieveNeighborApplicationUseCase {

private final NeighborAdaptor neighborAdaptor;

public Slice<RetrieveNeighborApplicationDTO> execute(Pageable pageable) {
Long toUserId = SecurityUtils.getCurrentUserId();
return neighborAdaptor.searchNeighborApplications(pageable, toUserId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package tify.server.api.user.service;


import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.transaction.annotation.Transactional;
import tify.server.core.annotation.UseCase;
import tify.server.domain.common.vo.UserInfoVo;
import tify.server.domain.domains.user.adaptor.UserAdaptor;
import tify.server.domain.domains.user.dto.condition.UserCondition;

@UseCase
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class RetrieveUserListUseCase {

private final UserAdaptor userAdaptor;

public Slice<UserInfoVo> execute(Pageable pageable, UserCondition condition) {
return userAdaptor.searchUsers(pageable, condition).map(UserInfoVo::from);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
public class UserInfoVo {

// 유저 프로필 사진, 이름, 생년월일, 직업 조회
private final Long userId;
private final Long id;

private final String userName;

private final String userId;

private final String imageUrl;

private final String birth;
Expand All @@ -30,8 +32,9 @@ public class UserInfoVo {

public static UserInfoVo from(User user) {
return UserInfoVo.builder()
.userId(user.getId())
.id(user.getId())
.userName(user.getProfile().getUserName())
.userId(user.getUserId())
.imageUrl(user.getProfile().getThumbNail())
.birth(user.getProfile().getBirth())
.job(user.getProfile().getJob())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ public List<FavorAnswerVo> getFavorAnswerBySmallCategory(
favorQuestionCategory.smallCategory,
favorAnswer.answerContent))
.from(favorAnswer)
.join(favorQuestion)
.on(favorAnswer.favorQuestion.id.eq(favorQuestion.id))
.innerJoin(favorAnswer.favorQuestion, favorQuestion)
.fetchJoin()
.join(favorQuestionCategory)
.on(favorQuestion.favorQuestionCategory.id.eq(favorQuestionCategory.id))
.where(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,25 @@
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import tify.server.core.annotation.Adaptor;
import tify.server.domain.domains.user.domain.Neighbor;
import tify.server.domain.domains.user.domain.NeighborApplication;
import tify.server.domain.domains.user.dto.condition.NeighborCondition;
import tify.server.domain.domains.user.dto.model.RetrieveNeighborApplicationDTO;
import tify.server.domain.domains.user.dto.model.RetrieveNeighborDTO;
import tify.server.domain.domains.user.exception.NeighborApplicationNotFoundException;
import tify.server.domain.domains.user.exception.NeighborNotFoundException;
import tify.server.domain.domains.user.repository.NeighborApplicationRepository;
import tify.server.domain.domains.user.repository.NeighborRepository;

@Adaptor
@RequiredArgsConstructor
public class NeighborAdaptor {

private final NeighborRepository neighborRepository;
private final NeighborApplicationRepository neighborApplicationRepository;

public Neighbor query(Long neighborId) {
return neighborRepository
Expand Down Expand Up @@ -53,4 +59,20 @@ public void save(Neighbor neighbor) {
public Slice<RetrieveNeighborDTO> searchBirthdayNeighbors(NeighborCondition neighborCondition) {
return neighborRepository.searchBirthToPage(neighborCondition);
}

public void saveNeighborApplication(NeighborApplication neighborApplication) {
neighborApplicationRepository.save(neighborApplication);
}

public NeighborApplication queryNeighborApplication(Long neighborApplicationId) {
return neighborApplicationRepository
.findById(neighborApplicationId)
.orElseThrow(() -> NeighborApplicationNotFoundException.EXCEPTION);
}

public Slice<RetrieveNeighborApplicationDTO> searchNeighborApplications(
Pageable pageable, Long toUserId) {
return neighborApplicationRepository.searchAllNeighborApplicationByFromUserId(
pageable, toUserId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import tify.server.core.annotation.Adaptor;
import tify.server.core.exception.BaseException;
import tify.server.domain.domains.user.domain.OauthInfo;
import tify.server.domain.domains.user.domain.User;
import tify.server.domain.domains.user.domain.UserOnBoardingStatus;
import tify.server.domain.domains.user.dto.condition.UserCondition;
import tify.server.domain.domains.user.exception.UserNotFoundException;
import tify.server.domain.domains.user.repository.UserOnBoardingStatusRepository;
import tify.server.domain.domains.user.repository.UserRepository;
Expand Down Expand Up @@ -48,4 +51,8 @@ public UserOnBoardingStatus queryOnBoardingStatusByName(String name) {
public List<UserOnBoardingStatusInfoVo> searchByKeyword(String keyword) {
return userOnBoardingStatusRepository.searchByKeyword(keyword);
}

public Slice<User> searchUsers(Pageable pageable, UserCondition condition) {
return userRepository.searchUsers(pageable, condition);
}
}
Loading

0 comments on commit c102d63

Please sign in to comment.