diff --git a/build.gradle b/build.gradle index 84e87bba..d0a82dc1 100644 --- a/build.gradle +++ b/build.gradle @@ -33,6 +33,7 @@ dependencies { compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.4.2' // JPA & Database implementation 'org.springframework.boot:spring-boot-starter-data-jpa' diff --git a/src/main/java/com/yello/server/ServerApplication.java b/src/main/java/com/yello/server/ServerApplication.java index 05d0d699..925d86c1 100644 --- a/src/main/java/com/yello/server/ServerApplication.java +++ b/src/main/java/com/yello/server/ServerApplication.java @@ -8,6 +8,7 @@ @EnableJpaAuditing @SpringBootApplication public class ServerApplication { + public static void main(String[] args) { SpringApplication.run(ServerApplication.class, args); } diff --git a/src/main/java/com/yello/server/domain/authorization/JwtTokenProvider.java b/src/main/java/com/yello/server/domain/authorization/JwtTokenProvider.java index f2eaf803..a2e965b0 100644 --- a/src/main/java/com/yello/server/domain/authorization/JwtTokenProvider.java +++ b/src/main/java/com/yello/server/domain/authorization/JwtTokenProvider.java @@ -12,7 +12,6 @@ import io.jsonwebtoken.MalformedJwtException; import io.jsonwebtoken.security.SignatureException; import java.util.Date; -import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import lombok.val; import org.springframework.beans.factory.annotation.Value; @@ -20,7 +19,6 @@ @Log4j2 @Component -@RequiredArgsConstructor public class JwtTokenProvider { public static final String ACCESS_TOKEN = "accessToken"; @@ -29,11 +27,15 @@ public class JwtTokenProvider { private static final Long ACCESS_TOKEN_VALID_TIME = ofSeconds(30).toMillis(); private static final Long REFRESH_TOKEN_VALID_TIME = ofDays(14).toMillis(); - @Value("${spring.jwt.secret}") - private String secretKey; + public String secretKey; + + public JwtTokenProvider(@Value("${spring.jwt.secret}") String secretKey) { + this.secretKey = secretKey; + } public Long getUserId(String token) - throws ExpiredJwtException, MalformedJwtException, SignatureException, IllegalArgumentException { + throws ExpiredJwtException, MalformedJwtException, SignatureException, + IllegalArgumentException { JwtParser parser = Jwts.parserBuilder() .setSigningKey(secretKey) @@ -47,7 +49,8 @@ public Long getUserId(String token) } public String getUserUuid(String token) - throws ExpiredJwtException, MalformedJwtException, SignatureException, IllegalArgumentException { + throws ExpiredJwtException, MalformedJwtException, SignatureException, + IllegalArgumentException { return Jwts.parserBuilder() .setSigningKey(secretKey) .build() @@ -120,7 +123,8 @@ public String createJwt(Long userId, String uuid, Long tokenValidTime, String to } public void tryParse(String token) - throws ExpiredJwtException, MalformedJwtException, SignatureException, IllegalArgumentException { + throws ExpiredJwtException, MalformedJwtException, SignatureException, + IllegalArgumentException { JwtParser parser = Jwts.parserBuilder() .setSigningKey(secretKey) .build(); diff --git a/src/main/java/com/yello/server/domain/authorization/configuration/SecurityConfiguration.java b/src/main/java/com/yello/server/domain/authorization/configuration/SecurityConfiguration.java index 5a6be771..8db9be1e 100644 --- a/src/main/java/com/yello/server/domain/authorization/configuration/SecurityConfiguration.java +++ b/src/main/java/com/yello/server/domain/authorization/configuration/SecurityConfiguration.java @@ -44,7 +44,8 @@ public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws .exceptionHandling() .authenticationEntryPoint(customAuthenticationEntryPoint) .and() - .addFilterBefore(new JwtFilter(userRepository), UsernamePasswordAuthenticationFilter.class) + .addFilterBefore(new JwtFilter(userRepository), + UsernamePasswordAuthenticationFilter.class) .addFilterBefore(new JwtExceptionFilter(jwtTokenProvider), JwtFilter.class) .addFilterBefore(new ExceptionHandlerFilter(), JwtExceptionFilter.class) .build(); diff --git a/src/main/java/com/yello/server/domain/authorization/dto/request/OnBoardingFriendRequest.java b/src/main/java/com/yello/server/domain/authorization/dto/request/OnBoardingFriendRequest.java index 94976591..1c2bfacc 100644 --- a/src/main/java/com/yello/server/domain/authorization/dto/request/OnBoardingFriendRequest.java +++ b/src/main/java/com/yello/server/domain/authorization/dto/request/OnBoardingFriendRequest.java @@ -2,10 +2,11 @@ import java.util.List; import javax.validation.constraints.NotNull; +import lombok.Builder; +@Builder public record OnBoardingFriendRequest( - @NotNull List friendKakaoId, - @NotNull Long groupId + @NotNull List friendKakaoId ) { } diff --git a/src/main/java/com/yello/server/domain/authorization/dto/response/OnBoardingFriend.java b/src/main/java/com/yello/server/domain/authorization/dto/response/OnBoardingFriend.java index 2a77327b..4cd4ee39 100644 --- a/src/main/java/com/yello/server/domain/authorization/dto/response/OnBoardingFriend.java +++ b/src/main/java/com/yello/server/domain/authorization/dto/response/OnBoardingFriend.java @@ -15,7 +15,7 @@ public record OnBoardingFriend( public static OnBoardingFriend of(User user) { return OnBoardingFriend.builder() - .group(user.getSocial()==Social.KAKAO ? "KAKAO" : "SCHOOL") + .group(user.getSocial() == Social.KAKAO ? "KAKAO" : "SCHOOL") .id(user.getId()) .name(user.getName()) .profileImage(user.getProfileImage()) diff --git a/src/main/java/com/yello/server/domain/authorization/exception/AuthBadRequestException.java b/src/main/java/com/yello/server/domain/authorization/exception/AuthBadRequestException.java index 0b49bc36..d4be31f2 100644 --- a/src/main/java/com/yello/server/domain/authorization/exception/AuthBadRequestException.java +++ b/src/main/java/com/yello/server/domain/authorization/exception/AuthBadRequestException.java @@ -4,6 +4,7 @@ import com.yello.server.global.exception.CustomException; public class AuthBadRequestException extends CustomException { + public AuthBadRequestException(ErrorCode error) { super(error, "[AuthBadRequestException] " + error.getMessage()); } diff --git a/src/main/java/com/yello/server/domain/authorization/exception/AuthNotFoundException.java b/src/main/java/com/yello/server/domain/authorization/exception/AuthNotFoundException.java index cafbc248..1046d48a 100644 --- a/src/main/java/com/yello/server/domain/authorization/exception/AuthNotFoundException.java +++ b/src/main/java/com/yello/server/domain/authorization/exception/AuthNotFoundException.java @@ -4,6 +4,7 @@ import com.yello.server.global.exception.CustomException; public class AuthNotFoundException extends CustomException { + public AuthNotFoundException(ErrorCode error) { super(error, "[AuthNotFoundException] " + error.getMessage()); } diff --git a/src/main/java/com/yello/server/domain/authorization/exception/CustomAuthenticationEntryPoint.java b/src/main/java/com/yello/server/domain/authorization/exception/CustomAuthenticationEntryPoint.java index dd723104..1b2c73b0 100644 --- a/src/main/java/com/yello/server/domain/authorization/exception/CustomAuthenticationEntryPoint.java +++ b/src/main/java/com/yello/server/domain/authorization/exception/CustomAuthenticationEntryPoint.java @@ -25,7 +25,8 @@ public void commence(HttpServletRequest request, HttpServletResponse response, ObjectMapper objectMapper = new ObjectMapper(); log.error("인증에 실패했습니다."); - CustomAuthenticationException exception = new CustomAuthenticationException(AUTHENTICATION_ERROR); + CustomAuthenticationException exception = + new CustomAuthenticationException(AUTHENTICATION_ERROR); response.setStatus(exception.getHttpStatus()); response.setContentType(APPLICATION_JSON_VALUE); response.setCharacterEncoding("UTF-8"); diff --git a/src/main/java/com/yello/server/domain/authorization/filter/JwtExceptionFilter.java b/src/main/java/com/yello/server/domain/authorization/filter/JwtExceptionFilter.java index 9ae91edc..8174bdd4 100644 --- a/src/main/java/com/yello/server/domain/authorization/filter/JwtExceptionFilter.java +++ b/src/main/java/com/yello/server/domain/authorization/filter/JwtExceptionFilter.java @@ -51,7 +51,7 @@ protected void doFilterInternal( val accessHeader = request.getHeader(AUTHORIZATION); log.info("Authorization : {}", accessHeader); - if (accessHeader==null || !accessHeader.startsWith(BEARER)) { + if (accessHeader == null || !accessHeader.startsWith(BEARER)) { throw new CustomAuthenticationException(AUTHENTICATION_ERROR); } diff --git a/src/main/java/com/yello/server/domain/authorization/filter/JwtFilter.java b/src/main/java/com/yello/server/domain/authorization/filter/JwtFilter.java index 32633d52..1dc63784 100644 --- a/src/main/java/com/yello/server/domain/authorization/filter/JwtFilter.java +++ b/src/main/java/com/yello/server/domain/authorization/filter/JwtFilter.java @@ -27,7 +27,8 @@ public class JwtFilter extends OncePerRequestFilter { private final UserRepository userRepository; @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, + FilterChain filterChain) throws ServletException, IOException { final String requestPath = request.getServletPath(); diff --git a/src/main/java/com/yello/server/domain/authorization/service/AuthService.java b/src/main/java/com/yello/server/domain/authorization/service/AuthService.java index 830c953a..8079fb79 100644 --- a/src/main/java/com/yello/server/domain/authorization/service/AuthService.java +++ b/src/main/java/com/yello/server/domain/authorization/service/AuthService.java @@ -34,40 +34,55 @@ import com.yello.server.domain.user.entity.User; import com.yello.server.domain.user.exception.UserConflictException; import com.yello.server.domain.user.repository.UserRepository; +import com.yello.server.global.common.factory.ListFactory; import com.yello.server.global.common.factory.PaginationFactory; import com.yello.server.global.common.util.RestUtil; -import java.util.ArrayList; +import com.yello.server.infrastructure.redis.repository.TokenRepository; import java.util.Comparator; import java.util.List; import java.util.Objects; import java.util.Optional; import javax.validation.constraints.NotNull; +import lombok.Builder; import lombok.RequiredArgsConstructor; import lombok.val; import org.springframework.data.domain.Pageable; -import org.springframework.data.redis.core.ValueOperations; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; + +@Builder @Service @RequiredArgsConstructor -@Transactional(readOnly = true) public class AuthService { - private final UserRepository userRepository; private final SchoolRepository schoolRepository; private final FriendRepository friendRepository; private final CooldownRepository cooldownRepository; private final JwtTokenProvider jwtTokenProvider; - private final ValueOperations tokenValueOperations; + private final TokenRepository tokenValueOperations; - @Transactional + // TODO softDelete 우아하게 처리하는 방법으로 바꾸기 + public void renewUserInformation(User currentUser) { + currentUser.renew(); + + friendRepository.findAllByUserIdNotFiltered(currentUser.getId()) + .forEach(Friend::renew); + friendRepository.findAllByTargetIdNotFiltered(currentUser.getId()) + .forEach(Friend::renew); + cooldownRepository.findByUserIdNotFiltered(currentUser.getId()) + .ifPresent(Cooldown::renew); + } + + // TODO 응답을 주입 받을 수 있도록 설계 + // TODO 테스트 코드 작성 public OAuthResponse oauthLogin(OAuthRequest oAuthRequest) { - final ResponseEntity response = RestUtil.getKakaoTokenInfo(oAuthRequest.accessToken()); + final ResponseEntity response = RestUtil.getKakaoTokenInfo( + oAuthRequest.accessToken()); - if (response.getStatusCode()==BAD_REQUEST || response.getStatusCode()==UNAUTHORIZED) { + if (response.getStatusCode() == BAD_REQUEST || response.getStatusCode() == UNAUTHORIZED) { throw new OAuthException(OAUTH_TOKEN_EXCEPTION); } @@ -76,24 +91,11 @@ public OAuthResponse oauthLogin(OAuthRequest oAuthRequest) { throw new NotSignedInException(NOT_SIGNIN_USER_EXCEPTION); } - final User user = target.get(); - final ServiceTokenVO serviceTokenVO = jwtTokenProvider.createServiceToken( - user.getId(), - user.getUuid() - ); + final User currentUser = target.get(); + final ServiceTokenVO serviceTokenVO = + this.registerToken(currentUser.getId(), currentUser.getUuid()); - tokenValueOperations.set( - user.getId(), - serviceTokenVO - ); - - user.renew(); - friendRepository.findAllByUserIdNotFiltered(user.getId()) - .forEach(Friend::renew); - friendRepository.findAllByTargetIdNotFiltered(user.getId()) - .forEach(Friend::renew); - cooldownRepository.findByUserIdNotFiltered(user.getId()) - .ifPresent(Cooldown::renew); + this.renewUserInformation(currentUser); return OAuthResponse.of(serviceTokenVO); } @@ -103,67 +105,81 @@ public Boolean isYelloIdDuplicated(String yelloId) { throw new AuthBadRequestException(YELLOID_REQUIRED_EXCEPTION); } - userRepository.getByYelloId(yelloId); - return true; + return userRepository.findByYelloId(yelloId).isPresent(); } @Transactional public SignUpResponse signUp(SignUpRequest signUpRequest) { + final User signUpUser = this.signUpUser(signUpRequest); + this.recommendUser(signUpRequest.recommendId()); + final ServiceTokenVO signUpToken = this.registerToken(signUpUser.getId(), signUpUser.getUuid()); + this.makeFriend(signUpUser, signUpRequest.friends()); + + return SignUpResponse.of(signUpUser.getYelloId(), signUpToken); + } + + public User signUpUser(SignUpRequest signUpRequest) { // exception - final Optional userByUUID = userRepository.findByUuid(signUpRequest.uuid()); - if (userByUUID.isPresent()) { - throw new UserConflictException(UUID_CONFLICT_USER_EXCEPTION); - } + userRepository.findByUuid(signUpRequest.uuid()) + .ifPresent(action -> { + throw new UserConflictException(UUID_CONFLICT_USER_EXCEPTION); + }); - final Optional userByYelloId = userRepository.findByYelloId(signUpRequest.yelloId()); - if (userByYelloId.isPresent()) { - throw new UserConflictException(YELLOID_CONFLICT_USER_EXCEPTION); - } + userRepository.findByYelloId(signUpRequest.yelloId()) + .ifPresent(action -> { + throw new UserConflictException(YELLOID_CONFLICT_USER_EXCEPTION); + }); - School group = schoolRepository.findById(signUpRequest.groupId()); + School group = schoolRepository.getById(signUpRequest.groupId()); - final User newSignInUser = userRepository.save(User.of(signUpRequest, signUpRequest.uuid(), group)); - ServiceTokenVO newUserTokens = jwtTokenProvider.createServiceToken( - newSignInUser.getId(), - newSignInUser.getUuid() - ); + final User newSignInUser = userRepository.save(User.of(signUpRequest, group)); + return newSignInUser; + } - if (signUpRequest.recommendId()!=null && !"".equals(signUpRequest.recommendId())) { - final User recommendedUser = userRepository.getByYelloId(signUpRequest.recommendId()); + public void recommendUser(String recommendYelloId) { + if (recommendYelloId != null && !recommendYelloId.isEmpty()) { + User recommendedUser = userRepository.getByYelloId(recommendYelloId); recommendedUser.increaseRecommendCount(); - final Optional cooldown = cooldownRepository.findByUserId(recommendedUser.getId()); + final Optional cooldown = + cooldownRepository.findByUserId(recommendedUser.getId()); cooldown.ifPresent(cooldownRepository::delete); } + } + + public ServiceTokenVO registerToken(Long id, String uuid) { + ServiceTokenVO newUserTokens = jwtTokenProvider.createServiceToken( + id, + uuid + ); + tokenValueOperations.set(id, newUserTokens); - signUpRequest.friends() + return newUserTokens; + } + + public void makeFriend(User user, List friendIds) { + friendIds .stream() - .map(userRepository::getById) + .map(userRepository::findById) .forEach(friend -> { - friendRepository.save(Friend.createFriend(newSignInUser, friend)); - friendRepository.save(Friend.createFriend(friend, newSignInUser)); + if (friend.isPresent()) { + friendRepository.save(Friend.createFriend(user, friend.get())); + friendRepository.save(Friend.createFriend(friend.get(), user)); + } }); - - tokenValueOperations.set(newSignInUser.getId(), newUserTokens); - return SignUpResponse.of(newSignInUser.getYelloId(), newUserTokens); } - public OnBoardingFriendResponse findOnBoardingFriends(OnBoardingFriendRequest friendRequest, Pageable pageable) { - List totalList = new ArrayList<>(); + public OnBoardingFriendResponse findOnBoardingFriends(OnBoardingFriendRequest friendRequest, + Pageable pageable) { - schoolRepository.findById(friendRequest.groupId()); - - final List groupFriends = userRepository.findAllByGroupId(friendRequest.groupId()); - final List kakaoFriends = friendRequest.friendKakaoId() + final List kakaoFriends = ListFactory.toNonNullableList(friendRequest.friendKakaoId() .stream() .map(String::valueOf) - .map(userRepository::getByUuid) - .toList(); + .map(userRepository::findByUuid) + .toList()); - totalList.addAll(groupFriends); - totalList.addAll(kakaoFriends); - - totalList = totalList.stream() + final List totalList = kakaoFriends + .stream() .distinct() .sorted(Comparator.comparing(User::getName)) .toList(); @@ -177,13 +193,16 @@ public OnBoardingFriendResponse findOnBoardingFriends(OnBoardingFriendRequest fr public GroupNameSearchResponse findSchoolsBySearch(String keyword, Pageable pageable) { int totalCount = schoolRepository.countDistinctSchoolNameContaining(keyword); - final List nameList = schoolRepository.findDistinctSchoolNameContaining(keyword, pageable); + final List nameList = schoolRepository.findDistinctSchoolNameContaining(keyword, + pageable); return GroupNameSearchResponse.of(totalCount, nameList); } - public DepartmentSearchResponse findDepartmentsBySearch(String schoolName, String keyword, Pageable pageable) { + public DepartmentSearchResponse findDepartmentsBySearch(String schoolName, String keyword, + Pageable pageable) { int totalCount = schoolRepository.countAllBySchoolNameContaining(schoolName, keyword); - final List schoolResult = schoolRepository.findAllBySchoolNameContaining(schoolName, keyword, pageable); + final List schoolResult = schoolRepository.findAllBySchoolNameContaining(schoolName, + keyword, pageable); return DepartmentSearchResponse.of(totalCount, schoolResult); } diff --git a/src/main/java/com/yello/server/domain/cooldown/entity/Cooldown.java b/src/main/java/com/yello/server/domain/cooldown/entity/Cooldown.java index fcc8a68d..10e538c4 100644 --- a/src/main/java/com/yello/server/domain/cooldown/entity/Cooldown.java +++ b/src/main/java/com/yello/server/domain/cooldown/entity/Cooldown.java @@ -1,16 +1,26 @@ package com.yello.server.domain.cooldown.entity; +import static com.yello.server.global.common.factory.TimeFactory.getSecondsBetween; +import static com.yello.server.global.common.util.ConstantUtil.TIMER_TIME; + import com.yello.server.domain.user.entity.User; -import lombok.*; +import java.time.LocalDateTime; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.OneToOne; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; import org.hibernate.annotations.Where; import org.springframework.data.annotation.CreatedDate; -import javax.persistence.*; -import java.time.LocalDateTime; - -import static com.yello.server.global.common.factory.TimeFactory.getSecondsBetween; -import static com.yello.server.global.common.util.ConstantUtil.TIMER_TIME; - @Getter @Entity @Builder @@ -36,9 +46,9 @@ public class Cooldown { public static Cooldown of(User user, LocalDateTime createdAt) { return Cooldown.builder() - .user(user) - .createdAt(createdAt) - .build(); + .user(user) + .createdAt(createdAt) + .build(); } public Boolean isPossible() { diff --git a/src/main/java/com/yello/server/domain/cooldown/exception/CooldownNotFoundException.java b/src/main/java/com/yello/server/domain/cooldown/exception/CooldownNotFoundException.java new file mode 100644 index 00000000..4971bc0d --- /dev/null +++ b/src/main/java/com/yello/server/domain/cooldown/exception/CooldownNotFoundException.java @@ -0,0 +1,11 @@ +package com.yello.server.domain.cooldown.exception; + +import com.yello.server.global.common.ErrorCode; +import com.yello.server.global.exception.CustomException; + +public class CooldownNotFoundException extends CustomException { + + public CooldownNotFoundException(ErrorCode error) { + super(error, "[CooldownNotFoundException] " + error.getMessage()); + } +} diff --git a/src/main/java/com/yello/server/domain/cooldown/repository/CooldownRepository.java b/src/main/java/com/yello/server/domain/cooldown/repository/CooldownRepository.java index ca86a563..8e93ae71 100644 --- a/src/main/java/com/yello/server/domain/cooldown/repository/CooldownRepository.java +++ b/src/main/java/com/yello/server/domain/cooldown/repository/CooldownRepository.java @@ -5,8 +5,10 @@ public interface CooldownRepository { - void save(Cooldown cooldown); + Cooldown save(Cooldown cooldown); + Cooldown getByUserid(Long userId); + Optional findByUserId(Long userId); boolean existsByUserId(Long userId); diff --git a/src/main/java/com/yello/server/domain/cooldown/repository/CooldownRepositoryImpl.java b/src/main/java/com/yello/server/domain/cooldown/repository/CooldownRepositoryImpl.java index a14f6cf8..4363a2a2 100644 --- a/src/main/java/com/yello/server/domain/cooldown/repository/CooldownRepositoryImpl.java +++ b/src/main/java/com/yello/server/domain/cooldown/repository/CooldownRepositoryImpl.java @@ -1,6 +1,9 @@ package com.yello.server.domain.cooldown.repository; +import static com.yello.server.global.common.ErrorCode.ID_NOT_FOUND_COOLDOWN_EXCEPTION; + import com.yello.server.domain.cooldown.entity.Cooldown; +import com.yello.server.domain.cooldown.exception.CooldownNotFoundException; import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; @@ -14,8 +17,14 @@ public class CooldownRepositoryImpl implements CooldownRepository { private final CooldownJpaRepository cooldownJpaRepository; @Override - public void save(Cooldown cooldown) { - cooldownJpaRepository.save(cooldown); + public Cooldown save(Cooldown cooldown) { + return cooldownJpaRepository.save(cooldown); + } + + @Override + public Cooldown getByUserid(Long userId) { + return cooldownJpaRepository.findByUserId(userId) + .orElseThrow(() -> new CooldownNotFoundException(ID_NOT_FOUND_COOLDOWN_EXCEPTION)); } @Override diff --git a/src/main/java/com/yello/server/domain/friend/controller/FriendController.java b/src/main/java/com/yello/server/domain/friend/controller/FriendController.java index 98d5b98d..03a3f646 100644 --- a/src/main/java/com/yello/server/domain/friend/controller/FriendController.java +++ b/src/main/java/com/yello/server/domain/friend/controller/FriendController.java @@ -97,7 +97,8 @@ public BaseResponse recommendSchoolFriend( @Valid @RequestParam Integer page, @AccessTokenUser User user ) { - val data = friendService.findAllRecommendSchoolFriends(createPageableByNameSort(page), user.getId()); + val data = friendService.findAllRecommendSchoolFriends(createPageableByNameSort(page), + user.getId()); return BaseResponse.success(SuccessCode.READ_FRIEND_SUCCESS, data); } @@ -112,7 +113,9 @@ public BaseResponse recommendKakaoFriend( @Valid @RequestParam Integer page, @AccessTokenUser User user ) { - val data = friendService.findAllRecommendKakaoFriends(createPageableByNameSort(page), user.getId(), request); + val data = + friendService.findAllRecommendKakaoFriends(createPageableByNameSort(page), user.getId(), + request); return BaseResponse.success(READ_FRIEND_SUCCESS, data); } diff --git a/src/main/java/com/yello/server/domain/friend/dto/request/KakaoRecommendRequest.java b/src/main/java/com/yello/server/domain/friend/dto/request/KakaoRecommendRequest.java index 722f2934..17576962 100644 --- a/src/main/java/com/yello/server/domain/friend/dto/request/KakaoRecommendRequest.java +++ b/src/main/java/com/yello/server/domain/friend/dto/request/KakaoRecommendRequest.java @@ -1,5 +1,8 @@ package com.yello.server.domain.friend.dto.request; +import lombok.Builder; + +@Builder public record KakaoRecommendRequest( String[] friendKakaoId ) { diff --git a/src/main/java/com/yello/server/domain/friend/dto/response/FriendResponse.java b/src/main/java/com/yello/server/domain/friend/dto/response/FriendResponse.java index 826dac8b..f769c847 100644 --- a/src/main/java/com/yello/server/domain/friend/dto/response/FriendResponse.java +++ b/src/main/java/com/yello/server/domain/friend/dto/response/FriendResponse.java @@ -5,18 +5,18 @@ @Builder public record FriendResponse( - Long id, - String name, - String group, - String profileImage + Long id, + String name, + String group, + String profileImage ) { public static FriendResponse of(User user) { return FriendResponse.builder() - .id(user.getId()) - .name(user.getName()) - .group(user.groupString()) - .profileImage(user.getProfileImage()) - .build(); + .id(user.getId()) + .name(user.getName()) + .group(user.groupString()) + .profileImage(user.getProfileImage()) + .build(); } } diff --git a/src/main/java/com/yello/server/domain/friend/dto/response/KakaoFriendResponse.java b/src/main/java/com/yello/server/domain/friend/dto/response/KakaoFriendResponse.java index cc99d060..2c1d3488 100644 --- a/src/main/java/com/yello/server/domain/friend/dto/response/KakaoFriendResponse.java +++ b/src/main/java/com/yello/server/domain/friend/dto/response/KakaoFriendResponse.java @@ -2,13 +2,12 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; - import java.util.List; @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public record KakaoFriendResponse( - List elements, - Integer total_count + List elements, + Integer total_count ) { } diff --git a/src/main/java/com/yello/server/domain/friend/repository/FriendJpaRepository.java b/src/main/java/com/yello/server/domain/friend/repository/FriendJpaRepository.java index 9cc80b35..d816374f 100644 --- a/src/main/java/com/yello/server/domain/friend/repository/FriendJpaRepository.java +++ b/src/main/java/com/yello/server/domain/friend/repository/FriendJpaRepository.java @@ -6,10 +6,8 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import org.springframework.transaction.annotation.Transactional; public interface FriendJpaRepository extends JpaRepository { @@ -25,7 +23,8 @@ public interface FriendJpaRepository extends JpaRepository { "and f.user.deletedAt is null " + "and f.target.deletedAt is null " + "and f.deletedAt is null") - Optional findByUserAndTarget(@Param("userId") Long userId, @Param("targetId") Long targetId); + Optional findByUserAndTarget(@Param("userId") Long userId, + @Param("targetId") Long targetId); @Query("select case when count(f) > 0 then true else false end from Friend f " + "where f.target.id = :targetId " + @@ -60,11 +59,4 @@ public interface FriendJpaRepository extends JpaRepository { @Query("select f from Friend f " + "where f.target.id = :targetId") List findAllByTargetIdNotFiltered(Long targetId); - - @Transactional - @Modifying(clearAutomatically = true) - @Query("delete from Friend f " + - "where f.target.id = :targetId " + - "and f.user.id = :userId") - void deleteByUserAndTarget(@Param("userId") Long userId, @Param("targetId") Long targetId); } diff --git a/src/main/java/com/yello/server/domain/friend/repository/FriendRepository.java b/src/main/java/com/yello/server/domain/friend/repository/FriendRepository.java index 0fcafacd..242f6e09 100644 --- a/src/main/java/com/yello/server/domain/friend/repository/FriendRepository.java +++ b/src/main/java/com/yello/server/domain/friend/repository/FriendRepository.java @@ -27,6 +27,4 @@ public interface FriendRepository { List findAllByUserIdNotFiltered(Long userId); List findAllByTargetIdNotFiltered(Long targetId); - - void deleteByUserAndTarget(Long userId, Long targetId); } diff --git a/src/main/java/com/yello/server/domain/friend/repository/FriendRepositoryImpl.java b/src/main/java/com/yello/server/domain/friend/repository/FriendRepositoryImpl.java index 42578825..b24b68d1 100644 --- a/src/main/java/com/yello/server/domain/friend/repository/FriendRepositoryImpl.java +++ b/src/main/java/com/yello/server/domain/friend/repository/FriendRepositoryImpl.java @@ -70,11 +70,4 @@ public List findAllByUserIdNotFiltered(Long userId) { public List findAllByTargetIdNotFiltered(Long targetId) { return friendJpaRepository.findAllByTargetIdNotFiltered(targetId); } - - @Transactional - @Override - public void deleteByUserAndTarget(Long userId, Long targetId) { - friendJpaRepository.deleteByUserAndTarget(userId, targetId); - friendJpaRepository.deleteByUserAndTarget(targetId, userId); - } } diff --git a/src/main/java/com/yello/server/domain/friend/service/FriendService.java b/src/main/java/com/yello/server/domain/friend/service/FriendService.java index 49c27eb2..da60f593 100644 --- a/src/main/java/com/yello/server/domain/friend/service/FriendService.java +++ b/src/main/java/com/yello/server/domain/friend/service/FriendService.java @@ -17,10 +17,12 @@ import com.yello.server.domain.user.repository.UserRepository; import com.yello.server.domain.vote.repository.VoteRepository; import com.yello.server.global.common.factory.PaginationFactory; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Optional; +import lombok.Builder; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -28,6 +30,7 @@ import org.springframework.transaction.annotation.Transactional; @Service +@Builder @RequiredArgsConstructor @Transactional(readOnly = true) public class FriendService { @@ -68,7 +71,7 @@ public void addFriend(Long userId, Long targetId) { public List findShuffledFriend(Long userId) { final User user = userRepository.getById(userId); - final List allFriends = friendRepository.findAllByUserId(user.getId()); + final List allFriends = new ArrayList<>(friendRepository.findAllByUserId(user.getId())); if (allFriends.size() < RANDOM_COUNT) { throw new FriendException(LACK_USER_EXCEPTION); @@ -104,10 +107,8 @@ public void deleteFriend(Long userId, Long targetId) { final User target = userRepository.getById(targetId); final User user = userRepository.getById(userId); - friendRepository.findByUserAndTarget(userId, targetId); - friendRepository.findByUserAndTarget(targetId, userId); - - friendRepository.deleteByUserAndTarget(user.getId(), target.getId()); + friendRepository.getByUserAndTarget(userId, targetId).delete(); + friendRepository.getByUserAndTarget(targetId, userId).delete(); } public RecommendFriendResponse findAllRecommendKakaoFriends(Pageable pageable, Long userId, diff --git a/src/main/java/com/yello/server/domain/group/entity/School.java b/src/main/java/com/yello/server/domain/group/entity/School.java index 4cb36511..eee58d4e 100644 --- a/src/main/java/com/yello/server/domain/group/entity/School.java +++ b/src/main/java/com/yello/server/domain/group/entity/School.java @@ -1,11 +1,20 @@ package com.yello.server.domain.group.entity; -import lombok.*; - -import javax.persistence.*; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Index; +import javax.persistence.Table; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; @Table(indexes = { - @Index(name = "idx__school_name", columnList = "schoolName") + @Index(name = "idx__school_name", columnList = "schoolName") }) @Getter @Entity @@ -26,9 +35,9 @@ public class School { public static School of(String schoolName, String departmentName) { return School.builder() - .schoolName(schoolName) - .departmentName(departmentName) - .build(); + .schoolName(schoolName) + .departmentName(departmentName) + .build(); } @Override diff --git a/src/main/java/com/yello/server/domain/group/repository/SchoolJpaRepository.java b/src/main/java/com/yello/server/domain/group/repository/SchoolJpaRepository.java index 75ace23b..c452881a 100644 --- a/src/main/java/com/yello/server/domain/group/repository/SchoolJpaRepository.java +++ b/src/main/java/com/yello/server/domain/group/repository/SchoolJpaRepository.java @@ -1,34 +1,33 @@ package com.yello.server.domain.group.repository; import com.yello.server.domain.group.entity.School; +import java.util.List; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import java.util.List; - public interface SchoolJpaRepository extends JpaRepository { @Query("select count (DISTINCT s.schoolName)from School s " + - "where s.schoolName " + - "like CONCAT('%',:schoolName,'%')") + "where s.schoolName " + + "like CONCAT('%',:schoolName,'%')") Integer countDistinctSchoolNameContaining(@Param("schoolName") String schoolName); @Query("select distinct(s.schoolName) from School s " + - "where s.schoolName " + - "like CONCAT('%',:schoolName,'%')") + "where s.schoolName " + + "like CONCAT('%',:schoolName,'%')") List findDistinctSchoolNameContaining(@Param("schoolName") String schoolName, Pageable pageable); @Query("select count(s) from School s " + - "where s.schoolName = :schoolName and s.departmentName " + - "like CONCAT('%',:departmentName,'%')") + "where s.schoolName = :schoolName and s.departmentName " + + "like CONCAT('%',:departmentName,'%')") Integer countAllBySchoolNameContaining(@Param("schoolName") String schoolName, - @Param("departmentName") String departmentName); + @Param("departmentName") String departmentName); @Query("select s from School s " + - "where s.schoolName = :schoolName and s.departmentName " + - "like CONCAT('%',:departmentName,'%')") + "where s.schoolName = :schoolName and s.departmentName " + + "like CONCAT('%',:departmentName,'%')") List findAllBySchoolNameContaining(@Param("schoolName") String schoolName, - @Param("departmentName") String departmentName, Pageable pageable); + @Param("departmentName") String departmentName, Pageable pageable); } diff --git a/src/main/java/com/yello/server/domain/group/repository/SchoolRepository.java b/src/main/java/com/yello/server/domain/group/repository/SchoolRepository.java index cded5cd9..20ca4034 100644 --- a/src/main/java/com/yello/server/domain/group/repository/SchoolRepository.java +++ b/src/main/java/com/yello/server/domain/group/repository/SchoolRepository.java @@ -1,13 +1,17 @@ package com.yello.server.domain.group.repository; import com.yello.server.domain.group.entity.School; - -import org.springframework.data.domain.Pageable; import java.util.List; +import java.util.Optional; +import org.springframework.data.domain.Pageable; public interface SchoolRepository { - School findById(Long id); + School save(School school); + + School getById(Long id); + + Optional findById(Long id); Integer countDistinctSchoolNameContaining(String schoolName); @@ -15,5 +19,6 @@ public interface SchoolRepository { Integer countAllBySchoolNameContaining(String schoolName, String departmentName); - List findAllBySchoolNameContaining(String schoolName, String departmentName, Pageable pageable); + List findAllBySchoolNameContaining(String schoolName, String departmentName, + Pageable pageable); } diff --git a/src/main/java/com/yello/server/domain/group/repository/SchoolRepositoryImpl.java b/src/main/java/com/yello/server/domain/group/repository/SchoolRepositoryImpl.java index 18c8b0dd..1e35bd8e 100644 --- a/src/main/java/com/yello/server/domain/group/repository/SchoolRepositoryImpl.java +++ b/src/main/java/com/yello/server/domain/group/repository/SchoolRepositoryImpl.java @@ -1,16 +1,16 @@ package com.yello.server.domain.group.repository; +import static com.yello.server.global.common.ErrorCode.GROUPID_NOT_FOUND_GROUP_EXCEPTION; + import com.yello.server.domain.group.entity.School; import com.yello.server.domain.group.exception.GroupNotFoundException; +import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; -import java.util.List; - -import static com.yello.server.global.common.ErrorCode.GROUPID_NOT_FOUND_GROUP_EXCEPTION; - @Repository @RequiredArgsConstructor @Transactional(readOnly = true) @@ -20,9 +20,19 @@ public class SchoolRepositoryImpl implements SchoolRepository { @Override - public School findById(Long id) { + public School save(School school) { + return schoolJpaRepository.save(school); + } + + @Override + public School getById(Long id) { return schoolJpaRepository.findById(id) - .orElseThrow(() -> new GroupNotFoundException(GROUPID_NOT_FOUND_GROUP_EXCEPTION)); + .orElseThrow(() -> new GroupNotFoundException(GROUPID_NOT_FOUND_GROUP_EXCEPTION)); + } + + @Override + public Optional findById(Long id) { + return schoolJpaRepository.findById(id); } @Override @@ -41,7 +51,8 @@ public Integer countAllBySchoolNameContaining(String schoolName, String departme } @Override - public List findAllBySchoolNameContaining(String schoolName, String departmentName, Pageable pageable) { + public List findAllBySchoolNameContaining(String schoolName, String departmentName, + Pageable pageable) { return schoolJpaRepository.findAllBySchoolNameContaining(schoolName, departmentName, pageable); } } diff --git a/src/main/java/com/yello/server/domain/keyword/dto/response/KeywordCheckResponse.java b/src/main/java/com/yello/server/domain/keyword/dto/response/KeywordCheckResponse.java index 894100ee..29578773 100644 --- a/src/main/java/com/yello/server/domain/keyword/dto/response/KeywordCheckResponse.java +++ b/src/main/java/com/yello/server/domain/keyword/dto/response/KeywordCheckResponse.java @@ -5,13 +5,13 @@ @Builder public record KeywordCheckResponse( - String answer + String answer ) { public static KeywordCheckResponse of(Vote vote) { return KeywordCheckResponse.builder() - .answer(vote.getAnswer()) - .build(); + .answer(vote.getAnswer()) + .build(); } } diff --git a/src/main/java/com/yello/server/domain/keyword/dto/response/KeywordVO.java b/src/main/java/com/yello/server/domain/keyword/dto/response/KeywordVO.java index ebb19032..2522dcd9 100644 --- a/src/main/java/com/yello/server/domain/keyword/dto/response/KeywordVO.java +++ b/src/main/java/com/yello/server/domain/keyword/dto/response/KeywordVO.java @@ -5,12 +5,12 @@ @Builder public record KeywordVO( - String keywordName + String keywordName ) { public static KeywordVO of(Keyword keyword) { return KeywordVO.builder() - .keywordName(keyword.getKeywordName()) - .build(); + .keywordName(keyword.getKeywordName()) + .build(); } } diff --git a/src/main/java/com/yello/server/domain/keyword/entity/Keyword.java b/src/main/java/com/yello/server/domain/keyword/entity/Keyword.java index 3585e310..83941cd4 100644 --- a/src/main/java/com/yello/server/domain/keyword/entity/Keyword.java +++ b/src/main/java/com/yello/server/domain/keyword/entity/Keyword.java @@ -1,9 +1,19 @@ package com.yello.server.domain.keyword.entity; import com.yello.server.domain.question.entity.Question; -import lombok.*; - -import javax.persistence.*; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; @Getter @Entity @@ -25,8 +35,8 @@ public class Keyword { public static Keyword of(String keywordName, Question question) { return Keyword.builder() - .keywordName(keywordName) - .question(question) - .build(); + .keywordName(keywordName) + .question(question) + .build(); } } diff --git a/src/main/java/com/yello/server/domain/keyword/repository/KeywordRepository.java b/src/main/java/com/yello/server/domain/keyword/repository/KeywordRepository.java index e9f3f94d..d5ac6588 100644 --- a/src/main/java/com/yello/server/domain/keyword/repository/KeywordRepository.java +++ b/src/main/java/com/yello/server/domain/keyword/repository/KeywordRepository.java @@ -1,5 +1,12 @@ package com.yello.server.domain.keyword.repository; +import com.yello.server.domain.keyword.entity.Keyword; +import java.util.List; + public interface KeywordRepository { + Keyword save(Keyword keyword); + + List findAll(); + } diff --git a/src/main/java/com/yello/server/domain/keyword/repository/KeywordRepositoryImpl.java b/src/main/java/com/yello/server/domain/keyword/repository/KeywordRepositoryImpl.java index 7acac31a..d7299b12 100644 --- a/src/main/java/com/yello/server/domain/keyword/repository/KeywordRepositoryImpl.java +++ b/src/main/java/com/yello/server/domain/keyword/repository/KeywordRepositoryImpl.java @@ -1,5 +1,7 @@ package com.yello.server.domain.keyword.repository; +import com.yello.server.domain.keyword.entity.Keyword; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; @@ -7,5 +9,15 @@ @RequiredArgsConstructor public class KeywordRepositoryImpl implements KeywordRepository { - private final KeywordJpaRepository keywordJpaRepository; + private final KeywordJpaRepository keywordJpaRepository; + + @Override + public Keyword save(Keyword keyword) { + return keywordJpaRepository.save(keyword); + } + + @Override + public List findAll() { + return keywordJpaRepository.findAll(); + } } diff --git a/src/main/java/com/yello/server/domain/pay/controller/PayController.java b/src/main/java/com/yello/server/domain/pay/controller/PayController.java index 0f2a2e87..8c90de49 100644 --- a/src/main/java/com/yello/server/domain/pay/controller/PayController.java +++ b/src/main/java/com/yello/server/domain/pay/controller/PayController.java @@ -23,18 +23,18 @@ @RequiredArgsConstructor public class PayController { - private final PayService payService; + private final PayService payService; - @Operation(summary = "결제 전환율 체크 API", responses = { - @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/json")) - }) - @PostMapping - public BaseResponse postPayCount( - @AccessTokenUser User user, - @RequestBody PayCountRequest request) { - payService.postPayCount(user.getId(), request.index()); - return BaseResponse.success(CREATE_PAY_COUNT); - } + @Operation(summary = "결제 전환율 체크 API", responses = { + @ApiResponse( + responseCode = "200", + content = @Content(mediaType = "application/json")) + }) + @PostMapping + public BaseResponse postPayCount( + @AccessTokenUser User user, + @RequestBody PayCountRequest request) { + payService.postPayCount(user.getId(), request.index()); + return BaseResponse.success(CREATE_PAY_COUNT); + } } diff --git a/src/main/java/com/yello/server/domain/pay/entity/Pay.java b/src/main/java/com/yello/server/domain/pay/entity/Pay.java index eb9ca15c..a1d73a58 100644 --- a/src/main/java/com/yello/server/domain/pay/entity/Pay.java +++ b/src/main/java/com/yello/server/domain/pay/entity/Pay.java @@ -1,9 +1,18 @@ package com.yello.server.domain.pay.entity; import com.yello.server.domain.user.entity.User; -import lombok.*; - -import javax.persistence.*; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; @Entity @Getter @@ -24,9 +33,9 @@ public class Pay { public static Pay of(Integer optionIndex, User user) { return Pay.builder() - .optionIndex(optionIndex) - .user(user) - .build(); + .optionIndex(optionIndex) + .user(user) + .build(); } public static Pay createPay(Integer optionIndex, User user) { diff --git a/src/main/java/com/yello/server/domain/pay/repository/PayJpaRepository.java b/src/main/java/com/yello/server/domain/pay/repository/PayJpaRepository.java index 4f64c863..7b32874d 100644 --- a/src/main/java/com/yello/server/domain/pay/repository/PayJpaRepository.java +++ b/src/main/java/com/yello/server/domain/pay/repository/PayJpaRepository.java @@ -7,5 +7,5 @@ public interface PayJpaRepository extends JpaRepository { - List findAllByUserAndOptionIndex(User user, Integer optionIndex); + List findAllByUserAndOptionIndex(User user, Integer optionIndex); } diff --git a/src/main/java/com/yello/server/domain/pay/repository/PayRepository.java b/src/main/java/com/yello/server/domain/pay/repository/PayRepository.java index 65a0ebd6..778aec1e 100644 --- a/src/main/java/com/yello/server/domain/pay/repository/PayRepository.java +++ b/src/main/java/com/yello/server/domain/pay/repository/PayRepository.java @@ -6,7 +6,7 @@ public interface PayRepository { - Pay save(Pay pay); + Pay save(Pay pay); - List findAllByUserAndOptionIndex(User user, Integer optionIndex); + List findAllByUserAndOptionIndex(User user, Integer optionIndex); } diff --git a/src/main/java/com/yello/server/domain/pay/repository/PayRepositoryImpl.java b/src/main/java/com/yello/server/domain/pay/repository/PayRepositoryImpl.java index effb4596..457d21a3 100644 --- a/src/main/java/com/yello/server/domain/pay/repository/PayRepositoryImpl.java +++ b/src/main/java/com/yello/server/domain/pay/repository/PayRepositoryImpl.java @@ -10,15 +10,15 @@ @RequiredArgsConstructor public class PayRepositoryImpl implements PayRepository { - private final PayJpaRepository payJpaRepository; + private final PayJpaRepository payJpaRepository; - @Override - public Pay save(Pay pay) { - return payJpaRepository.save(pay); - } + @Override + public Pay save(Pay pay) { + return payJpaRepository.save(pay); + } - @Override - public List findAllByUserAndOptionIndex(User user, Integer optionIndex) { - return payJpaRepository.findAllByUserAndOptionIndex(user, optionIndex); - } + @Override + public List findAllByUserAndOptionIndex(User user, Integer optionIndex) { + return payJpaRepository.findAllByUserAndOptionIndex(user, optionIndex); + } } diff --git a/src/main/java/com/yello/server/domain/question/dto/response/QuestionForVoteResponse.java b/src/main/java/com/yello/server/domain/question/dto/response/QuestionForVoteResponse.java index 55a99453..201cf701 100644 --- a/src/main/java/com/yello/server/domain/question/dto/response/QuestionForVoteResponse.java +++ b/src/main/java/com/yello/server/domain/question/dto/response/QuestionForVoteResponse.java @@ -1,15 +1,15 @@ package com.yello.server.domain.question.dto.response; import com.yello.server.domain.friend.dto.response.FriendShuffleResponse; -import lombok.Builder; - import java.util.List; +import lombok.Builder; @Builder public record QuestionForVoteResponse( - QuestionVO question, - List friendList, - List keywordList, - Integer questionPoint + QuestionVO question, + List friendList, + List keywordList, + Integer questionPoint ) { + } diff --git a/src/main/java/com/yello/server/domain/question/dto/response/QuestionVO.java b/src/main/java/com/yello/server/domain/question/dto/response/QuestionVO.java index 7bd267f3..67e11a4c 100644 --- a/src/main/java/com/yello/server/domain/question/dto/response/QuestionVO.java +++ b/src/main/java/com/yello/server/domain/question/dto/response/QuestionVO.java @@ -2,35 +2,34 @@ import com.yello.server.domain.question.entity.Question; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; - import java.util.Objects; +import lombok.Builder; @Builder public record QuestionVO( - @Schema(description = "투표 질문 id", example = "1") - Long questionId, + @Schema(description = "투표 질문 id", example = "1") + Long questionId, - @Schema(description = "투표 내용 중 이름 앞 부분", example = "나는") - String nameHead, + @Schema(description = "투표 내용 중 이름 앞 부분", example = "나는") + String nameHead, - @Schema(description = "투표 내용 중 이름 뒷 부분", example = "랑") - String nameFoot, + @Schema(description = "투표 내용 중 이름 뒷 부분", example = "랑") + String nameFoot, - @Schema(description = "투표 내용 중 키워드 앞 부분", example = "한강에서") - String keywordHead, + @Schema(description = "투표 내용 중 키워드 앞 부분", example = "한강에서") + String keywordHead, - @Schema(description = "투표 내용 중 키워드 뒷 부분", example = "하고 싶어") - String keywordFoot + @Schema(description = "투표 내용 중 키워드 뒷 부분", example = "하고 싶어") + String keywordFoot ) { public static QuestionVO of(Question question) { return QuestionVO.builder() - .questionId(Objects.isNull(question.getId()) ? null : question.getId()) - .nameHead(Objects.isNull(question.getNameHead()) ? null : question.getNameHead()) - .nameFoot(Objects.isNull(question.getNameFoot()) ? null : question.getNameFoot()) - .keywordHead(Objects.isNull(question.getKeywordHead()) ? null : question.getKeywordHead()) - .keywordFoot(Objects.isNull(question.getKeywordFoot()) ? null : question.getKeywordFoot()) - .build(); + .questionId(Objects.isNull(question.getId()) ? null : question.getId()) + .nameHead(Objects.isNull(question.getNameHead()) ? null : question.getNameHead()) + .nameFoot(Objects.isNull(question.getNameFoot()) ? null : question.getNameFoot()) + .keywordHead(Objects.isNull(question.getKeywordHead()) ? null : question.getKeywordHead()) + .keywordFoot(Objects.isNull(question.getKeywordFoot()) ? null : question.getKeywordFoot()) + .build(); } } diff --git a/src/main/java/com/yello/server/domain/question/entity/Question.java b/src/main/java/com/yello/server/domain/question/entity/Question.java index 0827612d..94faeb5f 100644 --- a/src/main/java/com/yello/server/domain/question/entity/Question.java +++ b/src/main/java/com/yello/server/domain/question/entity/Question.java @@ -1,19 +1,28 @@ package com.yello.server.domain.question.entity; import com.yello.server.domain.keyword.entity.Keyword; +import java.util.ArrayList; +import java.util.List; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.OneToMany; import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import javax.persistence.*; -import java.util.ArrayList; -import java.util.List; - @Entity @Getter +@Builder +@AllArgsConstructor @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Question { + @OneToMany(mappedBy = "question", cascade = CascadeType.ALL) private final List keywordList = new ArrayList<>(); @Id @@ -35,4 +44,10 @@ public Question(String nameHead, String nameFoot, String keywordHead, String key this.keywordHead = keywordHead; this.keywordFoot = keywordFoot; } + + + public void addKeyword(Keyword keyword) { + this.keywordList.add(keyword); + } + } diff --git a/src/main/java/com/yello/server/domain/question/repository/QuestionRepository.java b/src/main/java/com/yello/server/domain/question/repository/QuestionRepository.java index 8547e90c..41105510 100644 --- a/src/main/java/com/yello/server/domain/question/repository/QuestionRepository.java +++ b/src/main/java/com/yello/server/domain/question/repository/QuestionRepository.java @@ -5,7 +5,9 @@ public interface QuestionRepository { - List findAll(); + List findAll(); - Question findById(Long id); + Question findById(Long id); + + Question save(Question question); } diff --git a/src/main/java/com/yello/server/domain/question/repository/QuestionRepositoryImpl.java b/src/main/java/com/yello/server/domain/question/repository/QuestionRepositoryImpl.java index ac7da7c1..57c5a849 100644 --- a/src/main/java/com/yello/server/domain/question/repository/QuestionRepositoryImpl.java +++ b/src/main/java/com/yello/server/domain/question/repository/QuestionRepositoryImpl.java @@ -7,21 +7,28 @@ import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; @Repository @RequiredArgsConstructor public class QuestionRepositoryImpl implements QuestionRepository { - private final QuestionJpaRepository questionJpaRepository; + private final QuestionJpaRepository questionJpaRepository; - @Override - public List findAll() { - return questionJpaRepository.findAll(); - } + @Override + public List findAll() { + return questionJpaRepository.findAll(); + } - @Override - public Question findById(Long id) { - return questionJpaRepository.findById(id) - .orElseThrow(() -> new QuestionException(NOT_FOUND_QUESTION_EXCEPTION)); - } + @Override + public Question findById(Long id) { + return questionJpaRepository.findById(id) + .orElseThrow(() -> new QuestionException(NOT_FOUND_QUESTION_EXCEPTION)); + } + + @Transactional + @Override + public Question save(Question question) { + return questionJpaRepository.save(question); + } } diff --git a/src/main/java/com/yello/server/domain/user/dto/response/UserDetailResponse.java b/src/main/java/com/yello/server/domain/user/dto/response/UserDetailResponse.java index fd3a67d9..ddb3d6e4 100644 --- a/src/main/java/com/yello/server/domain/user/dto/response/UserDetailResponse.java +++ b/src/main/java/com/yello/server/domain/user/dto/response/UserDetailResponse.java @@ -5,26 +5,26 @@ @Builder public record UserDetailResponse( - Long userId, - String name, - String profileImageUrl, - String group, - String yelloId, - Integer yelloCount, - Integer friendCount, - Integer point + Long userId, + String name, + String profileImageUrl, + String group, + String yelloId, + Integer yelloCount, + Integer friendCount, + Integer point ) { public static UserDetailResponse of(User user, Integer yelloCount, Integer friendCount) { return UserDetailResponse.builder() - .userId(user.getId()) - .name(user.getName()) - .group(user.groupString()) - .profileImageUrl(user.getProfileImage()) - .yelloId(user.getYelloId()) - .yelloCount(yelloCount) - .friendCount(friendCount) - .point(user.getPoint()) - .build(); + .userId(user.getId()) + .name(user.getName()) + .group(user.groupString()) + .profileImageUrl(user.getProfileImage()) + .yelloId(user.getYelloId()) + .yelloCount(yelloCount) + .friendCount(friendCount) + .point(user.getPoint()) + .build(); } } diff --git a/src/main/java/com/yello/server/domain/user/dto/response/UserResponse.java b/src/main/java/com/yello/server/domain/user/dto/response/UserResponse.java index bafc7ff2..6a8794e7 100644 --- a/src/main/java/com/yello/server/domain/user/dto/response/UserResponse.java +++ b/src/main/java/com/yello/server/domain/user/dto/response/UserResponse.java @@ -5,24 +5,24 @@ @Builder public record UserResponse( - Long userId, - String name, - String profileImageUrl, - String group, - String yelloId, - Integer yelloCount, - Integer friendCount + Long userId, + String name, + String profileImageUrl, + String group, + String yelloId, + Integer yelloCount, + Integer friendCount ) { public static UserResponse of(User user, Integer yelloCount, Integer friendCount) { return UserResponse.builder() - .userId(user.getId()) - .name(user.getName()) - .group(user.groupString()) - .profileImageUrl(user.getProfileImage()) - .yelloId(user.getYelloId()) - .yelloCount(yelloCount) - .friendCount(friendCount) - .build(); + .userId(user.getId()) + .name(user.getName()) + .group(user.groupString()) + .profileImageUrl(user.getProfileImage()) + .yelloId(user.getYelloId()) + .yelloCount(yelloCount) + .friendCount(friendCount) + .build(); } } diff --git a/src/main/java/com/yello/server/domain/user/entity/Gender.java b/src/main/java/com/yello/server/domain/user/entity/Gender.java index 4de8cf7a..5b17ac33 100644 --- a/src/main/java/com/yello/server/domain/user/entity/Gender.java +++ b/src/main/java/com/yello/server/domain/user/entity/Gender.java @@ -17,9 +17,10 @@ public static Gender fromCode(String dbData) { return Arrays.stream(Gender.values()) .filter(v -> v.getIntial().equals(dbData)) .findAny() - .orElseThrow(() -> new IllegalArgumentException(MessageFormat.format("존재하지 않는 성별입니다. {0}", dbData))); + .orElseThrow(() -> new IllegalArgumentException( + MessageFormat.format("존재하지 않는 성별입니다. {0}", dbData))); } - + public String intial() { return intial; } diff --git a/src/main/java/com/yello/server/domain/user/entity/GenderConverter.java b/src/main/java/com/yello/server/domain/user/entity/GenderConverter.java index 68c4b4b4..1c0b2b63 100644 --- a/src/main/java/com/yello/server/domain/user/entity/GenderConverter.java +++ b/src/main/java/com/yello/server/domain/user/entity/GenderConverter.java @@ -10,7 +10,7 @@ public class GenderConverter implements AttributeConverter { @Override public String convertToDatabaseColumn(Gender gender) { - if (gender==null) { + if (gender == null) { return null; } return gender.getIntial(); @@ -18,7 +18,7 @@ public String convertToDatabaseColumn(Gender gender) { @Override public Gender convertToEntityAttribute(String dbData) { - if (dbData==null) { + if (dbData == null) { return null; } try { diff --git a/src/main/java/com/yello/server/domain/user/entity/Social.java b/src/main/java/com/yello/server/domain/user/entity/Social.java index bff5adcb..709574f6 100644 --- a/src/main/java/com/yello/server/domain/user/entity/Social.java +++ b/src/main/java/com/yello/server/domain/user/entity/Social.java @@ -17,7 +17,8 @@ public static Social fromCode(String dbData) { return Arrays.stream(Social.values()) .filter(v -> v.getIntial().equals(dbData)) .findAny() - .orElseThrow(() -> new IllegalArgumentException(MessageFormat.format("존재하지 않는 소셜입니다. {0}", dbData))); + .orElseThrow(() -> new IllegalArgumentException( + MessageFormat.format("존재하지 않는 소셜입니다. {0}", dbData))); } public String intial() { diff --git a/src/main/java/com/yello/server/domain/user/entity/SocialConverter.java b/src/main/java/com/yello/server/domain/user/entity/SocialConverter.java index 6fcc8ca4..d1671424 100644 --- a/src/main/java/com/yello/server/domain/user/entity/SocialConverter.java +++ b/src/main/java/com/yello/server/domain/user/entity/SocialConverter.java @@ -10,7 +10,7 @@ public class SocialConverter implements AttributeConverter { @Override public String convertToDatabaseColumn(Social social) { - if (social==null) { + if (social == null) { return null; } return social.getIntial(); @@ -18,7 +18,7 @@ public String convertToDatabaseColumn(Social social) { @Override public Social convertToEntityAttribute(String dbData) { - if (dbData==null) { + if (dbData == null) { return null; } try { diff --git a/src/main/java/com/yello/server/domain/user/entity/User.java b/src/main/java/com/yello/server/domain/user/entity/User.java index f6048e1c..05a4de9b 100644 --- a/src/main/java/com/yello/server/domain/user/entity/User.java +++ b/src/main/java/com/yello/server/domain/user/entity/User.java @@ -74,7 +74,7 @@ public class User extends AuditingTimeEntity { @Column(nullable = false) private String email; - public static User of(SignUpRequest signUpRequest, String uuid, School group) { + public static User of(SignUpRequest signUpRequest, School group) { return User.builder() .recommendCount(0L) .name(signUpRequest.name()) @@ -83,7 +83,7 @@ public static User of(SignUpRequest signUpRequest, String uuid, School group) { .point(200) .social(signUpRequest.social()) .profileImage(signUpRequest.profileImage()) - .uuid(uuid) + .uuid(signUpRequest.uuid()) .deletedAt(null) .group(group) .groupAdmissionYear(signUpRequest.groupAdmissionYear()) diff --git a/src/main/java/com/yello/server/domain/vote/dto/request/CreateVoteRequest.java b/src/main/java/com/yello/server/domain/vote/dto/request/CreateVoteRequest.java index bc90e825..61f125ac 100644 --- a/src/main/java/com/yello/server/domain/vote/dto/request/CreateVoteRequest.java +++ b/src/main/java/com/yello/server/domain/vote/dto/request/CreateVoteRequest.java @@ -1,10 +1,12 @@ package com.yello.server.domain.vote.dto.request; import java.util.List; +import lombok.Builder; +@Builder public record CreateVoteRequest( - List voteAnswerList, - Integer totalPoint + List voteAnswerList, + Integer totalPoint ) { } diff --git a/src/main/java/com/yello/server/domain/vote/dto/request/VoteAnswer.java b/src/main/java/com/yello/server/domain/vote/dto/request/VoteAnswer.java index fbaba1c9..d5d1a12c 100644 --- a/src/main/java/com/yello/server/domain/vote/dto/request/VoteAnswer.java +++ b/src/main/java/com/yello/server/domain/vote/dto/request/VoteAnswer.java @@ -1,10 +1,13 @@ package com.yello.server.domain.vote.dto.request; +import lombok.Builder; + +@Builder public record VoteAnswer( - Long friendId, - Long questionId, - String keywordName, - Integer colorIndex + Long friendId, + Long questionId, + String keywordName, + Integer colorIndex ) { } diff --git a/src/main/java/com/yello/server/domain/vote/dto/response/RevealNameResponse.java b/src/main/java/com/yello/server/domain/vote/dto/response/RevealNameResponse.java index a3aabefe..06891933 100644 --- a/src/main/java/com/yello/server/domain/vote/dto/response/RevealNameResponse.java +++ b/src/main/java/com/yello/server/domain/vote/dto/response/RevealNameResponse.java @@ -5,13 +5,14 @@ @Builder public record RevealNameResponse( - char name, - Integer nameIndex + char name, + Integer nameIndex ) { + public static RevealNameResponse of(User sender, int randomIndex) { return RevealNameResponse.builder() - .name(sender.getName().charAt(randomIndex)) - .nameIndex(randomIndex) - .build(); + .name(sender.getName().charAt(randomIndex)) + .nameIndex(randomIndex) + .build(); } } diff --git a/src/main/java/com/yello/server/domain/vote/dto/response/VoteAvailableResponse.java b/src/main/java/com/yello/server/domain/vote/dto/response/VoteAvailableResponse.java index 7ba347be..d0b5335a 100644 --- a/src/main/java/com/yello/server/domain/vote/dto/response/VoteAvailableResponse.java +++ b/src/main/java/com/yello/server/domain/vote/dto/response/VoteAvailableResponse.java @@ -1,41 +1,41 @@ package com.yello.server.domain.vote.dto.response; +import static com.yello.server.global.common.factory.TimeFactory.plusTime; +import static com.yello.server.global.common.factory.TimeFactory.toDateFormattedString; +import static com.yello.server.global.common.util.ConstantUtil.TIMER_MAX_TIME; + import com.yello.server.domain.cooldown.entity.Cooldown; import com.yello.server.domain.user.entity.User; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Builder; - import java.time.LocalDateTime; - -import static com.yello.server.global.common.factory.TimeFactory.plusTime; -import static com.yello.server.global.common.factory.TimeFactory.toDateFormattedString; -import static com.yello.server.global.common.util.ConstantUtil.TIMER_MAX_TIME; +import lombok.Builder; @Builder public record VoteAvailableResponse( - @Schema(description = "투표 가능 여부 (true=가능, false=불가능)", example = "false") - Boolean isPossible, + @Schema(description = "투표 가능 여부 (true=가능, false=불가능)", example = "false") + Boolean isPossible, - @Schema(description = "현재 보유중인 포인트", example = "200") - Integer point, + @Schema(description = "현재 보유중인 포인트", example = "200") + Integer point, - @Schema(description = "마지막 투표 시점") - String createdAt + @Schema(description = "마지막 투표 시점") + String createdAt ) { public static VoteAvailableResponse of(User user, Cooldown cooldown) { return VoteAvailableResponse.builder() - .isPossible(cooldown.isPossible()) - .point(user.getPoint()) - .createdAt(toDateFormattedString(cooldown.getCreatedAt())) - .build(); + .isPossible(cooldown.isPossible()) + .point(user.getPoint()) + .createdAt(toDateFormattedString(cooldown.getCreatedAt())) + .build(); } - public static VoteAvailableResponse of(User user, Boolean isPossible, LocalDateTime localDateTime) { + public static VoteAvailableResponse of(User user, Boolean isPossible, + LocalDateTime localDateTime) { return VoteAvailableResponse.builder() - .isPossible(isPossible) - .point(user.getPoint()) - .createdAt(toDateFormattedString(plusTime(localDateTime, TIMER_MAX_TIME))) - .build(); + .isPossible(isPossible) + .point(user.getPoint()) + .createdAt(toDateFormattedString(plusTime(localDateTime, TIMER_MAX_TIME))) + .build(); } } diff --git a/src/main/java/com/yello/server/domain/vote/dto/response/VoteContentVO.java b/src/main/java/com/yello/server/domain/vote/dto/response/VoteContentVO.java index b585ecc3..aa11ff36 100644 --- a/src/main/java/com/yello/server/domain/vote/dto/response/VoteContentVO.java +++ b/src/main/java/com/yello/server/domain/vote/dto/response/VoteContentVO.java @@ -7,30 +7,30 @@ @Builder public record VoteContentVO( - @Schema(description = "투표 내용 중 이름 앞 부분", example = "나는") - String nameHead, + @Schema(description = "투표 내용 중 이름 앞 부분", example = "나는") + String nameHead, - @Schema(description = "투표 내용 중 이름 뒷 부분", example = "랑") - String nameFoot, + @Schema(description = "투표 내용 중 이름 뒷 부분", example = "랑") + String nameFoot, - @Schema(description = "투표 내용 중 키워드 앞 부분", example = "한강에서") - String keywordHead, + @Schema(description = "투표 내용 중 키워드 앞 부분", example = "한강에서") + String keywordHead, - @Schema(description = "투표 내용 중 키워드 키워드 부분", example = "수영") - String keyword, - - @Schema(description = "투표 내용 중 키워드 뒷 부분", example = "하고 싶어") - String keywordFoot + @Schema(description = "투표 내용 중 키워드 키워드 부분", example = "수영") + String keyword, + + @Schema(description = "투표 내용 중 키워드 뒷 부분", example = "하고 싶어") + String keywordFoot ) { static VoteContentVO of(Vote vote) { return VoteContentVO.builder() - .nameHead(vote.getQuestion().getNameHead()) - .nameFoot(deleteBracket(vote.getQuestion().getNameFoot())) - .keywordHead(vote.getQuestion().getKeywordHead()) - .keyword(vote.getAnswer()) - .keywordFoot(vote.getQuestion().getKeywordFoot()) - .build(); + .nameHead(vote.getQuestion().getNameHead()) + .nameFoot(deleteBracket(vote.getQuestion().getNameFoot())) + .keywordHead(vote.getQuestion().getKeywordHead()) + .keyword(vote.getAnswer()) + .keywordFoot(vote.getQuestion().getKeywordFoot()) + .build(); } private static String deleteBracket(String target) { diff --git a/src/main/java/com/yello/server/domain/vote/dto/response/VoteCreateResponse.java b/src/main/java/com/yello/server/domain/vote/dto/response/VoteCreateResponse.java index 651e3497..662d525d 100644 --- a/src/main/java/com/yello/server/domain/vote/dto/response/VoteCreateResponse.java +++ b/src/main/java/com/yello/server/domain/vote/dto/response/VoteCreateResponse.java @@ -4,12 +4,12 @@ @Builder public record VoteCreateResponse( - Integer point + Integer point ) { public static VoteCreateResponse of(Integer point) { return VoteCreateResponse.builder() - .point(point) - .build(); + .point(point) + .build(); } } diff --git a/src/main/java/com/yello/server/domain/vote/dto/response/VoteDetailResponse.java b/src/main/java/com/yello/server/domain/vote/dto/response/VoteDetailResponse.java index ecf270ae..3c83e4ea 100644 --- a/src/main/java/com/yello/server/domain/vote/dto/response/VoteDetailResponse.java +++ b/src/main/java/com/yello/server/domain/vote/dto/response/VoteDetailResponse.java @@ -6,41 +6,41 @@ @Builder public record VoteDetailResponse( - @Schema(description = "투표 컬러 인덱스") - Integer colorIndex, + @Schema(description = "투표 컬러 인덱스") + Integer colorIndex, - @Schema(description = "현재 보유중인 포인트") - Integer currentPoint, + @Schema(description = "현재 보유중인 포인트") + Integer currentPoint, - @Schema(description = "이름 힌트 인덱스" - + "-1 → 이름 힌트가 아직 밝혀지지 않음" - + "0 → 첫번째 위치에 이름 힌트가 밝혀짐" - + "1 → 두번째 위치에 이름 힌트가 밝혀짐") - Integer nameHint, + @Schema(description = "이름 힌트 인덱스" + + "-1 → 이름 힌트가 아직 밝혀지지 않음" + + "0 → 첫번째 위치에 이름 힌트가 밝혀짐" + + "1 → 두번째 위치에 이름 힌트가 밝혀짐") + Integer nameHint, - @Schema(description = "키워드 공개 여부") - Boolean isAnswerRevealed, + @Schema(description = "키워드 공개 여부") + Boolean isAnswerRevealed, - @Schema(description = "투표를 작성한 유저의 이름") - String senderName, + @Schema(description = "투표를 작성한 유저의 이름") + String senderName, - @Schema(description = "투표를 보낸 유저의 성별", example = "MALE") - String senderGender, + @Schema(description = "투표를 보낸 유저의 성별", example = "MALE") + String senderGender, - @Schema(description = "투표 내용") - VoteContentVO vote + @Schema(description = "투표 내용") + VoteContentVO vote ) { public static VoteDetailResponse of(Vote vote) { return VoteDetailResponse.builder() - .colorIndex(vote.getColorIndex()) - .currentPoint(vote.getReceiver().getPoint()) - .nameHint(vote.getNameHint()) - .isAnswerRevealed(vote.getIsAnswerRevealed()) - .senderName(vote.getSender().getName()) - .senderGender(vote.getSender().getGender().name()) - .vote(VoteContentVO.of(vote)) - .build(); + .colorIndex(vote.getColorIndex()) + .currentPoint(vote.getReceiver().getPoint()) + .nameHint(vote.getNameHint()) + .isAnswerRevealed(vote.getIsAnswerRevealed()) + .senderName(vote.getSender().getName()) + .senderGender(vote.getSender().getGender().name()) + .vote(VoteContentVO.of(vote)) + .build(); } } diff --git a/src/main/java/com/yello/server/domain/vote/dto/response/VoteFriendResponse.java b/src/main/java/com/yello/server/domain/vote/dto/response/VoteFriendResponse.java index ba5fc7a7..6157897a 100644 --- a/src/main/java/com/yello/server/domain/vote/dto/response/VoteFriendResponse.java +++ b/src/main/java/com/yello/server/domain/vote/dto/response/VoteFriendResponse.java @@ -1,41 +1,41 @@ package com.yello.server.domain.vote.dto.response; +import static com.yello.server.global.common.factory.TimeFactory.toFormattedString; + import com.yello.server.domain.vote.entity.Vote; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; -import static com.yello.server.global.common.factory.TimeFactory.toFormattedString; - @Builder public record VoteFriendResponse( - @Schema(description = "투표 고유 Id 값") - Long id, + @Schema(description = "투표 고유 Id 값") + Long id, - @Schema(description = "투표를 받은 유저의 이름", example = "권세훈") - String receiverName, + @Schema(description = "투표를 받은 유저의 이름", example = "권세훈") + String receiverName, - @Schema(description = "투표를 보낸 유저의 성별", example = "MALE") - String senderGender, + @Schema(description = "투표를 보낸 유저의 성별", example = "MALE") + String senderGender, - @Schema(description = "투표의 전체 문장", example = "나는 너랑 한강에서 ??? 하고 싶어") - VoteContentVO vote, + @Schema(description = "투표의 전체 문장", example = "나는 너랑 한강에서 ??? 하고 싶어") + VoteContentVO vote, - @Schema(description = "힌트 사용 여부") - Boolean isHintUsed, + @Schema(description = "힌트 사용 여부") + Boolean isHintUsed, - @Schema(description = "투표 생성 일자", example = "1시간 전") - String createdAt + @Schema(description = "투표 생성 일자", example = "1시간 전") + String createdAt ) { public static VoteFriendResponse of(Vote vote) { return VoteFriendResponse.builder() - .id(vote.getId()) - .receiverName(vote.getReceiver().getName()) - .senderGender(vote.getSender().getGender().name()) - .vote(VoteContentVO.of(vote)) - .isHintUsed(vote.getIsAnswerRevealed()) - .createdAt(toFormattedString(vote.getCreatedAt())) - .build(); + .id(vote.getId()) + .receiverName(vote.getReceiver().getName()) + .senderGender(vote.getSender().getGender().name()) + .vote(VoteContentVO.of(vote)) + .isHintUsed(vote.getIsAnswerRevealed()) + .createdAt(toFormattedString(vote.getCreatedAt())) + .build(); } } diff --git a/src/main/java/com/yello/server/domain/vote/dto/response/VoteListResponse.java b/src/main/java/com/yello/server/domain/vote/dto/response/VoteListResponse.java index 4adec7f7..83ce1a48 100644 --- a/src/main/java/com/yello/server/domain/vote/dto/response/VoteListResponse.java +++ b/src/main/java/com/yello/server/domain/vote/dto/response/VoteListResponse.java @@ -1,19 +1,18 @@ package com.yello.server.domain.vote.dto.response; -import lombok.Builder; - import java.util.List; +import lombok.Builder; @Builder public record VoteListResponse( - Integer totalCount, - List votes + Integer totalCount, + List votes ) { public static VoteListResponse of(Integer totalCount, List votes) { return VoteListResponse.builder() - .totalCount(totalCount) - .votes(votes) - .build(); + .totalCount(totalCount) + .votes(votes) + .build(); } } diff --git a/src/main/java/com/yello/server/domain/vote/dto/response/VoteResponse.java b/src/main/java/com/yello/server/domain/vote/dto/response/VoteResponse.java index cae91952..4ab04676 100644 --- a/src/main/java/com/yello/server/domain/vote/dto/response/VoteResponse.java +++ b/src/main/java/com/yello/server/domain/vote/dto/response/VoteResponse.java @@ -1,48 +1,48 @@ package com.yello.server.domain.vote.dto.response; +import static com.yello.server.global.common.factory.TimeFactory.toFormattedString; + import com.yello.server.domain.vote.entity.Vote; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; -import static com.yello.server.global.common.factory.TimeFactory.toFormattedString; - @Builder public record VoteResponse( - @Schema(description = "투표 고유 Id 값") - Long id, + @Schema(description = "투표 고유 Id 값") + Long id, - @Schema(description = "투표를 보낸 유저의 성별", example = "MALE") - String senderGender, + @Schema(description = "투표를 보낸 유저의 성별", example = "MALE") + String senderGender, - @Schema(description = "투표를 보낸 유저의 이름", example = "권세훈") - String senderName, + @Schema(description = "투표를 보낸 유저의 이름", example = "권세훈") + String senderName, - @Schema(description = "이름 힌트 인덱스", example = "-1") - Integer nameHint, + @Schema(description = "이름 힌트 인덱스", example = "-1") + Integer nameHint, - @Schema(description = "투표 내용") - VoteContentVO vote, + @Schema(description = "투표 내용") + VoteContentVO vote, - @Schema(description = "힌트 사용 여부") - Boolean isHintUsed, + @Schema(description = "힌트 사용 여부") + Boolean isHintUsed, - @Schema(description = "투표 읽음 여부") - Boolean isRead, + @Schema(description = "투표 읽음 여부") + Boolean isRead, - @Schema(description = "투표 생성 일자", example = "1시간 전") - String createdAt + @Schema(description = "투표 생성 일자", example = "1시간 전") + String createdAt ) { public static VoteResponse of(Vote vote) { return VoteResponse.builder() - .id(vote.getId()) - .senderGender(vote.getSender().getGender().name()) - .senderName(vote.getSender().getName()) - .nameHint(vote.getNameHint()) - .vote(VoteContentVO.of(vote)) - .isHintUsed(vote.getIsAnswerRevealed()) - .isRead(vote.getIsRead()) - .createdAt(toFormattedString(vote.getCreatedAt())) - .build(); + .id(vote.getId()) + .senderGender(vote.getSender().getGender().name()) + .senderName(vote.getSender().getName()) + .nameHint(vote.getNameHint()) + .vote(VoteContentVO.of(vote)) + .isHintUsed(vote.getIsAnswerRevealed()) + .isRead(vote.getIsRead()) + .createdAt(toFormattedString(vote.getCreatedAt())) + .build(); } } diff --git a/src/main/java/com/yello/server/domain/vote/entity/Vote.java b/src/main/java/com/yello/server/domain/vote/entity/Vote.java index 9deebfb5..a8b3b265 100644 --- a/src/main/java/com/yello/server/domain/vote/entity/Vote.java +++ b/src/main/java/com/yello/server/domain/vote/entity/Vote.java @@ -13,15 +13,15 @@ import javax.persistence.ManyToOne; import lombok.AccessLevel; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; import org.hibernate.annotations.ColumnDefault; import org.hibernate.annotations.DynamicInsert; @Entity @Getter -@Builder +@SuperBuilder @DynamicInsert @AllArgsConstructor @NoArgsConstructor(access = AccessLevel.PROTECTED) @@ -61,7 +61,8 @@ public class Vote extends AuditingTimeEntity { @Column(nullable = false) private Integer colorIndex; - public static Vote of(String answer, User sender, User receiver, Question question, Integer colorIndex) { + public static Vote of(String answer, User sender, User receiver, Question question, + Integer colorIndex) { return Vote.builder() .answer(answer) .sender(sender) @@ -71,7 +72,8 @@ public static Vote of(String answer, User sender, User receiver, Question questi .build(); } - public static Vote createVote(String answer, User sender, User receiver, Question question, Integer colorIndex) { + public static Vote createVote(String answer, User sender, User receiver, Question question, + Integer colorIndex) { return Vote.of(answer, sender, receiver, question, colorIndex); } diff --git a/src/main/java/com/yello/server/domain/vote/repository/VoteRepository.java b/src/main/java/com/yello/server/domain/vote/repository/VoteRepository.java index 6bcce4a2..6d62f671 100644 --- a/src/main/java/com/yello/server/domain/vote/repository/VoteRepository.java +++ b/src/main/java/com/yello/server/domain/vote/repository/VoteRepository.java @@ -2,13 +2,16 @@ import com.yello.server.domain.vote.entity.Vote; import java.util.List; +import java.util.Optional; import org.springframework.data.domain.Pageable; public interface VoteRepository { Vote save(Vote vote); - Vote findById(Long id); + Vote getById(Long id); + + Optional findById(Long id); Integer countAllByReceiverUserId(Long userId); diff --git a/src/main/java/com/yello/server/domain/vote/repository/VoteRepositoryImpl.java b/src/main/java/com/yello/server/domain/vote/repository/VoteRepositoryImpl.java index 8c0f5200..e143847b 100644 --- a/src/main/java/com/yello/server/domain/vote/repository/VoteRepositoryImpl.java +++ b/src/main/java/com/yello/server/domain/vote/repository/VoteRepositoryImpl.java @@ -5,6 +5,7 @@ import com.yello.server.domain.vote.entity.Vote; import com.yello.server.domain.vote.exception.VoteNotFoundException; import java.util.List; +import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Repository; @@ -24,11 +25,16 @@ public Vote save(Vote vote) { } @Override - public Vote findById(Long id) { + public Vote getById(Long id) { return voteJpaRepository.findById(id) .orElseThrow(() -> new VoteNotFoundException(NOT_FOUND_VOTE_EXCEPTION)); } + @Override + public Optional findById(Long id) { + return voteJpaRepository.findById(id); + } + @Override public Integer countAllByReceiverUserId(Long userId) { return voteJpaRepository.countAllByReceiverUserId(userId); diff --git a/src/main/java/com/yello/server/domain/vote/service/VoteService.java b/src/main/java/com/yello/server/domain/vote/service/VoteService.java index 787b45e1..86669f83 100644 --- a/src/main/java/com/yello/server/domain/vote/service/VoteService.java +++ b/src/main/java/com/yello/server/domain/vote/service/VoteService.java @@ -21,6 +21,7 @@ import com.yello.server.domain.friend.repository.FriendRepository; import com.yello.server.domain.keyword.dto.response.KeywordCheckResponse; import com.yello.server.domain.keyword.entity.Keyword; +import com.yello.server.domain.keyword.repository.KeywordRepository; import com.yello.server.domain.question.dto.response.QuestionForVoteResponse; import com.yello.server.domain.question.dto.response.QuestionVO; import com.yello.server.domain.question.entity.Question; @@ -41,16 +42,19 @@ import com.yello.server.domain.vote.exception.VoteNotFoundException; import com.yello.server.domain.vote.repository.VoteRepository; import java.time.LocalDateTime; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.stream.IntStream; +import lombok.Builder; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service +@Builder @RequiredArgsConstructor @Transactional(readOnly = true) public class VoteService { @@ -60,6 +64,7 @@ public class VoteService { private final QuestionRepository questionRepository; private final CooldownRepository cooldownRepository; private final VoteRepository voteRepository; + private final KeywordRepository keywordRepository; public VoteListResponse findAllVotes(Long userId, Pageable pageable) { final Integer count = voteRepository.countAllByReceiverUserId(userId); @@ -71,8 +76,8 @@ public VoteListResponse findAllVotes(Long userId, Pageable pageable) { } @Transactional - public VoteDetailResponse findVoteById(Long id) { - final Vote vote = voteRepository.findById(id); + public VoteDetailResponse findVoteById(Long voteId) { + final Vote vote = voteRepository.getById(voteId); vote.read(); return VoteDetailResponse.of(vote); } @@ -86,7 +91,7 @@ public List findAllFriendVotes(Long userId, Pageable pageabl @Transactional public KeywordCheckResponse checkKeyword(Long userId, Long voteId) { - final Vote vote = voteRepository.findById(voteId); + final Vote vote = voteRepository.getById(voteId); final User user = userRepository.getById(userId); vote.checkKeyword(); @@ -108,7 +113,7 @@ public List findVoteQuestionList(Long userId) { } final List questions = questionRepository.findAll(); - Collections.shuffle(questions); + Collections.shuffle(Arrays.asList(questions)); final List questionList = questions.stream() .limit(VOTE_COUNT) @@ -140,7 +145,7 @@ public VoteCreateResponse createVote(Long userId, CreateVoteRequest request) { final List voteAnswerList = request.voteAnswerList(); IntStream.range(0, voteAnswerList.size()) .forEach(index -> { - if (index > 0 && voteAnswerList.get(index - 1).questionId()==voteAnswerList.get(index) + if (index > 0 && voteAnswerList.get(index - 1).questionId() == voteAnswerList.get(index) .questionId()) { throw new VoteForbiddenException(DUPLICATE_VOTE_EXCEPTION); } @@ -171,8 +176,8 @@ public RevealNameResponse revealNameHint(Long userId, Long voteId) { throw new VoteForbiddenException(LACK_POINT_EXCEPTION); } - final Vote vote = voteRepository.findById(voteId); - if (vote.getNameHint()!=NAME_HINT_DEFAULT) { + final Vote vote = voteRepository.getById(voteId); + if (vote.getNameHint() != NAME_HINT_DEFAULT) { throw new VoteNotFoundException(INVALID_VOTE_EXCEPTION); } @@ -185,7 +190,7 @@ public RevealNameResponse revealNameHint(Long userId, Long voteId) { private QuestionForVoteResponse generateVoteQuestion(User user, Question question) { final List keywordList = question.getKeywordList(); - Collections.shuffle(keywordList); + Collections.shuffle(Arrays.asList(keywordList)); return QuestionForVoteResponse.builder() .friendList(getShuffledFriends(user)) @@ -197,7 +202,7 @@ private QuestionForVoteResponse generateVoteQuestion(User user, Question questio private List getShuffledFriends(User user) { final List allFriend = friendRepository.findAllByUserId(user.getId()); - Collections.shuffle(allFriend); + Collections.shuffle(Arrays.asList(allFriend)); return allFriend.stream() .map(FriendShuffleResponse::of) diff --git a/src/main/java/com/yello/server/global/common/ErrorCode.java b/src/main/java/com/yello/server/global/common/ErrorCode.java index 4a882e05..cf2eed99 100644 --- a/src/main/java/com/yello/server/global/common/ErrorCode.java +++ b/src/main/java/com/yello/server/global/common/ErrorCode.java @@ -1,13 +1,17 @@ package com.yello.server.global.common; +import static org.springframework.http.HttpStatus.BAD_REQUEST; +import static org.springframework.http.HttpStatus.CONFLICT; +import static org.springframework.http.HttpStatus.FORBIDDEN; +import static org.springframework.http.HttpStatus.NOT_FOUND; +import static org.springframework.http.HttpStatus.UNAUTHORIZED; + import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import org.springframework.http.HttpStatus; -import static org.springframework.http.HttpStatus.*; - @Getter @AllArgsConstructor(access = AccessLevel.PRIVATE) public enum ErrorCode { @@ -45,7 +49,7 @@ public enum ErrorCode { TOKEN_NOT_EXPIRED_AUTH_EXCEPTION(FORBIDDEN, "토큰이 모두 유효합니다."), TOKEN_ALL_EXPIRED_AUTH_EXCEPTION(FORBIDDEN, "토큰이 모두 만료됐습니다."), TOKEN_INFO_NOT_SAME_AUTH_EXCEPTION(FORBIDDEN, "동일하지 않은 액세스 토큰과 리프레시 토큰입니다."), - DUPLICATE_VOTE_EXCEPTION(FORBIDDEN,"중복된 투표가 전달되었습니다."), + DUPLICATE_VOTE_EXCEPTION(FORBIDDEN, "중복된 투표가 전달되었습니다."), /** * 404 NOT FOUND @@ -54,6 +58,7 @@ public enum ErrorCode { AUTH_NOT_FOUND_USER_EXCEPTION(NOT_FOUND, "토큰 정보에 해당하는 유저가 존재하지 않습니다."), AUTH_UUID_NOT_FOUND_USER_EXCEPTION(NOT_FOUND, "토큰 uuid에 해당하는 유저가 존재하지 않습니다."), GROUPID_NOT_FOUND_GROUP_EXCEPTION(NOT_FOUND, "해당 그룹 id의 그룹이 존재하지 않습니다."), + ID_NOT_FOUND_COOLDOWN_EXCEPTION(NOT_FOUND, "해당 id의 cooldown이 존재하지 않습니다."), USERID_NOT_FOUND_USER_EXCEPTION(NOT_FOUND, "탈퇴했거나 존재하지 않는 유저의 id 입니다."), TOKEN_TIME_EXPIRED_EXCEPTION(UNAUTHORIZED, "인증되지 않은 유저입니다."), NOT_FOUND_VOTE_EXCEPTION(NOT_FOUND, "존재하지 않는 투표입니다."), diff --git a/src/main/java/com/yello/server/global/common/annotation/AccessTokenUserResolver.java b/src/main/java/com/yello/server/global/common/annotation/AccessTokenUserResolver.java index 38460544..37168647 100644 --- a/src/main/java/com/yello/server/global/common/annotation/AccessTokenUserResolver.java +++ b/src/main/java/com/yello/server/global/common/annotation/AccessTokenUserResolver.java @@ -22,9 +22,9 @@ public boolean supportsParameter(MethodParameter parameter) { @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, - NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { + NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { return SecurityContextHolder.getContext() - .getAuthentication() - .getDetails(); + .getAuthentication() + .getDetails(); } } diff --git a/src/main/java/com/yello/server/global/common/annotation/ServiceTokenResolver.java b/src/main/java/com/yello/server/global/common/annotation/ServiceTokenResolver.java index 953fd122..1041d66a 100644 --- a/src/main/java/com/yello/server/global/common/annotation/ServiceTokenResolver.java +++ b/src/main/java/com/yello/server/global/common/annotation/ServiceTokenResolver.java @@ -18,7 +18,8 @@ public class ServiceTokenResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { boolean hasServiceToken = parameter.hasParameterAnnotation(ServiceToken.class); - boolean isServiceTokenVOType = ServiceTokenVO.class.isAssignableFrom(parameter.getParameterType()); + boolean isServiceTokenVOType = + ServiceTokenVO.class.isAssignableFrom(parameter.getParameterType()); return hasServiceToken && isServiceTokenVOType; } @@ -27,8 +28,8 @@ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer m NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { String accessTokenHeader = webRequest.getHeader("X-ACCESS-AUTH"); String refreshTokenHeader = webRequest.getHeader("X-REFRESH-AUTH"); - - if (accessTokenHeader==null || refreshTokenHeader==null + + if (accessTokenHeader == null || refreshTokenHeader == null || !refreshTokenHeader.startsWith(BEARER) || !accessTokenHeader.startsWith(BEARER)) { throw new CustomAuthenticationException(AUTHENTICATION_ERROR); diff --git a/src/main/java/com/yello/server/global/common/dto/AuditingTimeEntity.java b/src/main/java/com/yello/server/global/common/dto/AuditingTimeEntity.java index 02c0dc2d..6fbc28bd 100644 --- a/src/main/java/com/yello/server/global/common/dto/AuditingTimeEntity.java +++ b/src/main/java/com/yello/server/global/common/dto/AuditingTimeEntity.java @@ -1,22 +1,28 @@ package com.yello.server.global.common.dto; +import java.time.LocalDateTime; +import javax.persistence.EntityListeners; +import javax.persistence.MappedSuperclass; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import javax.persistence.EntityListeners; -import javax.persistence.MappedSuperclass; -import java.time.LocalDateTime; - @Getter @MappedSuperclass +@SuperBuilder +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) @EntityListeners(AuditingEntityListener.class) public abstract class AuditingTimeEntity { @CreatedDate - private LocalDateTime createdAt; + protected LocalDateTime createdAt; @LastModifiedDate - private LocalDateTime updatedAt; + protected LocalDateTime updatedAt; } diff --git a/src/main/java/com/yello/server/global/common/dto/BaseResponse.java b/src/main/java/com/yello/server/global/common/dto/BaseResponse.java index 79d06c38..9a106848 100644 --- a/src/main/java/com/yello/server/global/common/dto/BaseResponse.java +++ b/src/main/java/com/yello/server/global/common/dto/BaseResponse.java @@ -41,7 +41,8 @@ public static BaseResponse error(ErrorCode error, @Nullable String messag return new BaseResponse<>(error.getHttpStatusCode(), message); } - public static BaseResponse error(ErrorCode error, @Nullable String message, @Nullable T data) { + public static BaseResponse error(ErrorCode error, @Nullable String message, + @Nullable T data) { return new BaseResponse<>(error.getHttpStatusCode(), message, data); } } \ No newline at end of file diff --git a/src/main/java/com/yello/server/global/common/factory/TimeFactory.java b/src/main/java/com/yello/server/global/common/factory/TimeFactory.java index 0c5ed7e1..f4230836 100644 --- a/src/main/java/com/yello/server/global/common/factory/TimeFactory.java +++ b/src/main/java/com/yello/server/global/common/factory/TimeFactory.java @@ -30,7 +30,8 @@ public static String toFormattedString(LocalDateTime localDateTime) { return (seconds / HOUR) + "일 전"; } - public static long getSecondsBetween(LocalDateTime currentDateTime, LocalDateTime localDateTime) { + public static long getSecondsBetween(LocalDateTime currentDateTime, + LocalDateTime localDateTime) { Duration duration = Duration.between(localDateTime, currentDateTime); return duration.getSeconds(); } diff --git a/src/main/java/com/yello/server/global/common/util/RestUtil.java b/src/main/java/com/yello/server/global/common/util/RestUtil.java index 2e28281b..a5b90271 100644 --- a/src/main/java/com/yello/server/global/common/util/RestUtil.java +++ b/src/main/java/com/yello/server/global/common/util/RestUtil.java @@ -10,8 +10,10 @@ public class RestUtil { - private static final String KAKAO_TOKEN_INFO_URL = "https://kapi.kakao.com/v1/user/access_token_info"; - private static final String KAKAO_FRIEND_LIST_URL = "https://kapi.kakao.com/v1/api/talk/friends"; + private static final String KAKAO_TOKEN_INFO_URL = + "https://kapi.kakao.com/v1/user/access_token_info"; + private static final String KAKAO_FRIEND_LIST_URL = + "https://kapi.kakao.com/v1/api/talk/friends"; private RestUtil() { throw new IllegalStateException(); @@ -29,19 +31,20 @@ public static ResponseEntity getKakaoTokenInfo(String kakaoAcces .block(); } - public static ResponseEntity getKakaoFriendList(String kakaoAccessToken, String friendOrder, + public static ResponseEntity getKakaoFriendList(String kakaoAccessToken, + String friendOrder, Integer offset, Integer limit, String order) { String baseUrl = KAKAO_FRIEND_LIST_URL + "?"; - if (friendOrder!=null) { + if (friendOrder != null) { baseUrl += "friendOrder=" + friendOrder; } - if (offset!=null) { + if (offset != null) { baseUrl += "offset=" + offset; } - if (limit!=null) { + if (limit != null) { baseUrl += "limit=" + limit; } - if (order!=null) { + if (order != null) { baseUrl += "order=" + order; } if (baseUrl.equals(KAKAO_FRIEND_LIST_URL + "?")) { diff --git a/src/main/java/com/yello/server/global/exception/ControllerExceptionAdvice.java b/src/main/java/com/yello/server/global/exception/ControllerExceptionAdvice.java index b6888130..f83e632c 100644 --- a/src/main/java/com/yello/server/global/exception/ControllerExceptionAdvice.java +++ b/src/main/java/com/yello/server/global/exception/ControllerExceptionAdvice.java @@ -1,6 +1,22 @@ package com.yello.server.global.exception; -import com.yello.server.domain.authorization.exception.*; +import static com.yello.server.global.common.ErrorCode.FIELD_REQUIRED_EXCEPTION; +import static com.yello.server.global.common.ErrorCode.QUERY_STRING_REQUIRED_EXCEPTION; +import static org.springframework.http.HttpStatus.BAD_REQUEST; +import static org.springframework.http.HttpStatus.CONFLICT; +import static org.springframework.http.HttpStatus.FORBIDDEN; +import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; +import static org.springframework.http.HttpStatus.NOT_FOUND; +import static org.springframework.http.HttpStatus.UNAUTHORIZED; + +import com.yello.server.domain.authorization.exception.AuthBadRequestException; +import com.yello.server.domain.authorization.exception.CustomAuthenticationException; +import com.yello.server.domain.authorization.exception.ExpiredTokenException; +import com.yello.server.domain.authorization.exception.InvalidTokenException; +import com.yello.server.domain.authorization.exception.NotExpiredTokenForbiddenException; +import com.yello.server.domain.authorization.exception.NotSignedInException; +import com.yello.server.domain.authorization.exception.NotValidTokenForbiddenException; +import com.yello.server.domain.authorization.exception.OAuthException; import com.yello.server.domain.friend.exception.FriendException; import com.yello.server.domain.friend.exception.FriendNotFoundException; import com.yello.server.domain.group.exception.GroupNotFoundException; @@ -22,10 +38,6 @@ import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; -import static com.yello.server.global.common.ErrorCode.FIELD_REQUIRED_EXCEPTION; -import static com.yello.server.global.common.ErrorCode.QUERY_STRING_REQUIRED_EXCEPTION; -import static org.springframework.http.HttpStatus.*; - @RestControllerAdvice public class ControllerExceptionAdvice { @@ -33,105 +45,107 @@ public class ControllerExceptionAdvice { * 400 BAD REQUEST */ @ExceptionHandler({ - FriendException.class, - UserException.class, - AuthBadRequestException.class, - UserBadRequestException.class + FriendException.class, + UserException.class, + AuthBadRequestException.class, + UserBadRequestException.class }) public ResponseEntity BadRequestException(CustomException exception) { return ResponseEntity.status(BAD_REQUEST) - .body(BaseResponse.error(exception.getError(), exception.getMessage())); + .body(BaseResponse.error(exception.getError(), exception.getMessage())); } @ExceptionHandler({ - // @Valid 오류 Catch - MethodArgumentNotValidException.class + // @Valid 오류 Catch + MethodArgumentNotValidException.class }) public ResponseEntity BadRequestException(BindException exception) { return ResponseEntity.status(BAD_REQUEST) - .body(BaseResponse.error(FIELD_REQUIRED_EXCEPTION, FIELD_REQUIRED_EXCEPTION.getMessage())); + .body(BaseResponse.error(FIELD_REQUIRED_EXCEPTION, FIELD_REQUIRED_EXCEPTION.getMessage())); } @ExceptionHandler({ - // Post인데 @RequestBody 없을 때 - HttpMessageNotReadableException.class + // Post인데 @RequestBody 없을 때 + HttpMessageNotReadableException.class }) - public ResponseEntity BadRequestException(HttpMessageConversionException exception) { + public ResponseEntity BadRequestException( + HttpMessageConversionException exception) { return ResponseEntity.status(BAD_REQUEST) - .body(BaseResponse.error(FIELD_REQUIRED_EXCEPTION, FIELD_REQUIRED_EXCEPTION.getMessage())); + .body(BaseResponse.error(FIELD_REQUIRED_EXCEPTION, FIELD_REQUIRED_EXCEPTION.getMessage())); } @ExceptionHandler({ - // @RequestParam 이 없을 때 - MissingServletRequestParameterException.class + // @RequestParam 이 없을 때 + MissingServletRequestParameterException.class }) - public ResponseEntity BadRequestException(MissingServletRequestParameterException exception) { + public ResponseEntity BadRequestException( + MissingServletRequestParameterException exception) { return ResponseEntity.status(BAD_REQUEST) - .body(BaseResponse.error(QUERY_STRING_REQUIRED_EXCEPTION, QUERY_STRING_REQUIRED_EXCEPTION.getMessage())); + .body(BaseResponse.error(QUERY_STRING_REQUIRED_EXCEPTION, QUERY_STRING_REQUIRED_EXCEPTION.getMessage())); } /** * 401 UNAUTHORIZED */ @ExceptionHandler({ - CustomAuthenticationException.class, - ExpiredTokenException.class, - InvalidTokenException.class, - OAuthException.class + CustomAuthenticationException.class, + ExpiredTokenException.class, + InvalidTokenException.class, + OAuthException.class }) public ResponseEntity UnauthorizedException(CustomException exception) { return ResponseEntity.status(UNAUTHORIZED) - .body(BaseResponse.error(exception.getError(), exception.getMessage())); + .body(BaseResponse.error(exception.getError(), exception.getMessage())); } /** * 403 FORBIDDEN */ @ExceptionHandler({ - VoteForbiddenException.class, - NotSignedInException.class, - NotExpiredTokenForbiddenException.class, - NotValidTokenForbiddenException.class + VoteForbiddenException.class, + NotSignedInException.class, + NotExpiredTokenForbiddenException.class, + NotValidTokenForbiddenException.class }) public ResponseEntity ForbiddenException(CustomException exception) { return ResponseEntity.status(FORBIDDEN) - .body(BaseResponse.error(exception.getError(), exception.getMessage())); + .body(BaseResponse.error(exception.getError(), exception.getMessage())); } /** * 404 NOT FOUND */ @ExceptionHandler({ - UserNotFoundException.class, - VoteNotFoundException.class, - GroupNotFoundException.class, - FriendNotFoundException.class, - QuestionNotFoundException.class + UserNotFoundException.class, + VoteNotFoundException.class, + GroupNotFoundException.class, + FriendNotFoundException.class, + QuestionNotFoundException.class }) public ResponseEntity NotFoundException(CustomException exception) { return ResponseEntity.status(NOT_FOUND) - .body(BaseResponse.error(exception.getError(), exception.getMessage())); + .body(BaseResponse.error(exception.getError(), exception.getMessage())); } /** * 409 CONFLICT */ @ExceptionHandler({ - UserConflictException.class + UserConflictException.class }) public ResponseEntity ConflictException(CustomException exception) { return ResponseEntity.status(CONFLICT) - .body(BaseResponse.error(exception.getError(), exception.getMessage())); + .body(BaseResponse.error(exception.getError(), exception.getMessage())); } /** * 500 INTERNAL SERVER ERROR */ @ExceptionHandler({ - RedisException.class, + RedisException.class, }) public ResponseEntity InternalServerException(CustomException exception) { return ResponseEntity.status(INTERNAL_SERVER_ERROR) - .body(BaseResponse.error(exception.getError(), exception.getMessage())); + .body(BaseResponse.error(exception.getError(), exception.getMessage())); } } diff --git a/src/main/java/com/yello/server/global/exception/ExceptionHandlerFilter.java b/src/main/java/com/yello/server/global/exception/ExceptionHandlerFilter.java index 9dac5649..7ea06309 100644 --- a/src/main/java/com/yello/server/global/exception/ExceptionHandlerFilter.java +++ b/src/main/java/com/yello/server/global/exception/ExceptionHandlerFilter.java @@ -1,26 +1,25 @@ package com.yello.server.global.exception; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + import com.fasterxml.jackson.core.json.JsonWriteFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.yello.server.global.common.ErrorCode; import com.yello.server.global.common.dto.BaseResponse; -import org.springframework.web.filter.OncePerRequestFilter; - +import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import org.springframework.web.filter.OncePerRequestFilter; public class ExceptionHandlerFilter extends OncePerRequestFilter { @Override protected void doFilterInternal( - HttpServletRequest request, - HttpServletResponse response, - FilterChain filterChain + HttpServletRequest request, + HttpServletResponse response, + FilterChain filterChain ) throws ServletException, IOException { try { filterChain.doFilter(request, response); @@ -30,8 +29,8 @@ protected void doFilterInternal( } private void setErrorResponse( - HttpServletResponse response, - ErrorCode errorCode + HttpServletResponse response, + ErrorCode errorCode ) { ObjectMapper objectMapper = new ObjectMapper(); response.setStatus(errorCode.getHttpStatusCode()); @@ -39,8 +38,8 @@ private void setErrorResponse( BaseResponse baseResponse = BaseResponse.error(errorCode); try { response.getWriter() - .write(objectMapper.configure(JsonWriteFeature.ESCAPE_NON_ASCII.mappedFeature(), true) - .writeValueAsString(baseResponse)); + .write(objectMapper.configure(JsonWriteFeature.ESCAPE_NON_ASCII.mappedFeature(), true) + .writeValueAsString(baseResponse)); } catch (IOException exception) { exception.printStackTrace(); } diff --git a/src/main/java/com/yello/server/infrastructure/redis/repository/TokenRepository.java b/src/main/java/com/yello/server/infrastructure/redis/repository/TokenRepository.java new file mode 100644 index 00000000..a76ca430 --- /dev/null +++ b/src/main/java/com/yello/server/infrastructure/redis/repository/TokenRepository.java @@ -0,0 +1,19 @@ +package com.yello.server.infrastructure.redis.repository; + +import com.yello.server.domain.authorization.dto.ServiceTokenVO; + +public interface TokenRepository { + + void set(Long key, ServiceTokenVO value); + + void setDeviceToken(String uuid, String deviceToken); + + ServiceTokenVO get(Long key); + + String getDeviceToken(String uuid); + + void deleteDeviceToken(String uuid); + + Boolean hasKey(String uuid); + +} diff --git a/src/main/java/com/yello/server/infrastructure/redis/repository/TokenRepositoryImpl.java b/src/main/java/com/yello/server/infrastructure/redis/repository/TokenRepositoryImpl.java new file mode 100644 index 00000000..3cd02e8b --- /dev/null +++ b/src/main/java/com/yello/server/infrastructure/redis/repository/TokenRepositoryImpl.java @@ -0,0 +1,47 @@ +package com.yello.server.infrastructure.redis.repository; + +import com.yello.server.domain.authorization.dto.ServiceTokenVO; +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class TokenRepositoryImpl implements TokenRepository { + + private final ValueOperations redisTokenRepository; + private final StringRedisTemplate redisDeviceTokenRepository; + + @Override + public void set(Long key, ServiceTokenVO value) { + redisTokenRepository.set(key, value); + } + + @Override + public void setDeviceToken(String uuid, String deviceToken) { + redisDeviceTokenRepository.opsForValue() + .set(uuid, deviceToken); + } + + @Override + public ServiceTokenVO get(Long key) { + return redisTokenRepository.get(key); + } + + @Override + public String getDeviceToken(String uuid) { + return redisDeviceTokenRepository.opsForValue() + .get(uuid); + } + + @Override + public void deleteDeviceToken(String uuid) { + redisDeviceTokenRepository.delete(uuid); + } + + @Override + public Boolean hasKey(String uuid) { + return redisDeviceTokenRepository.hasKey(uuid); + } +} diff --git a/src/test/java/com/yello/server/ServerApplicationTests.java b/src/test/java/com/yello/server/ServerApplicationTests.java index d1ce0fde..0e120911 100644 --- a/src/test/java/com/yello/server/ServerApplicationTests.java +++ b/src/test/java/com/yello/server/ServerApplicationTests.java @@ -6,8 +6,8 @@ @SpringBootTest class ServerApplicationTests { - @Test - void contextLoads() { - } + @Test + void contextLoads() { + } } diff --git a/src/test/java/com/yello/server/small/authorization/AuthServiceTest.java b/src/test/java/com/yello/server/small/authorization/AuthServiceTest.java new file mode 100644 index 00000000..c60c9570 --- /dev/null +++ b/src/test/java/com/yello/server/small/authorization/AuthServiceTest.java @@ -0,0 +1,406 @@ +package com.yello.server.small.authorization; + +import static com.yello.server.global.common.ErrorCode.GROUPID_NOT_FOUND_GROUP_EXCEPTION; +import static com.yello.server.global.common.ErrorCode.UUID_CONFLICT_USER_EXCEPTION; +import static com.yello.server.global.common.ErrorCode.YELLOID_CONFLICT_USER_EXCEPTION; +import static com.yello.server.global.common.ErrorCode.YELLOID_REQUIRED_EXCEPTION; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.yello.server.domain.authorization.JwtTokenProvider; +import com.yello.server.domain.authorization.dto.ServiceTokenVO; +import com.yello.server.domain.authorization.dto.request.OnBoardingFriendRequest; +import com.yello.server.domain.authorization.dto.request.SignUpRequest; +import com.yello.server.domain.authorization.dto.response.OnBoardingFriend; +import com.yello.server.domain.authorization.dto.response.OnBoardingFriendResponse; +import com.yello.server.domain.authorization.exception.AuthBadRequestException; +import com.yello.server.domain.authorization.service.AuthService; +import com.yello.server.domain.cooldown.entity.Cooldown; +import com.yello.server.domain.cooldown.repository.CooldownRepository; +import com.yello.server.domain.friend.repository.FriendRepository; +import com.yello.server.domain.group.entity.School; +import com.yello.server.domain.group.exception.GroupNotFoundException; +import com.yello.server.domain.group.repository.SchoolRepository; +import com.yello.server.domain.user.entity.Gender; +import com.yello.server.domain.user.entity.Social; +import com.yello.server.domain.user.entity.User; +import com.yello.server.domain.user.exception.UserConflictException; +import com.yello.server.domain.user.repository.UserRepository; +import com.yello.server.global.common.factory.PaginationFactory; +import com.yello.server.infrastructure.redis.repository.TokenRepository; +import com.yello.server.small.cooldown.FakeCooldownRepository; +import com.yello.server.small.friend.FakeFriendRepository; +import com.yello.server.small.global.redis.FakeTokenRepository; +import com.yello.server.small.group.FakeSchoolRepository; +import com.yello.server.small.user.FakeUserRepository; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.data.domain.Pageable; + +public class AuthServiceTest { + + private final String secretKey = Base64.getEncoder().encodeToString( + "keyForTestkeyForTestkeyForTestkeyForTestkeyForTestkeyForTestkeyForTestkeyForTestkeyForTest".getBytes()); + private final UserRepository userRepository = new FakeUserRepository(); + private final SchoolRepository schoolRepository = new FakeSchoolRepository(); + private final FriendRepository friendRepository = new FakeFriendRepository(); + private final CooldownRepository cooldownRepository = new FakeCooldownRepository(); + private final JwtTokenProvider jwtTokenProvider = new JwtTokenProvider(secretKey); + private final TokenRepository tokenRepository = new FakeTokenRepository(); + private AuthService authService; + + @BeforeEach + void init() { + this.authService = AuthService.builder() + .userRepository(userRepository) + .schoolRepository(schoolRepository) + .friendRepository(friendRepository) + .cooldownRepository(cooldownRepository) + .jwtTokenProvider(jwtTokenProvider) + .tokenValueOperations(tokenRepository) + .build(); + + School school = School.builder() + .id(1L) + .schoolName("옐로대학교") + .departmentName("국정원학과") + .build(); + + schoolRepository.save(school); + + // soft-deleted User + userRepository.save(User.builder() + .id(0L) + .recommendCount(0L).name("잉강밍") + .yelloId("gm").gender(Gender.FEMALE) + .point(200).social(Social.KAKAO) + .profileImage("NO_IMAGE").uuid("123") + .deletedAt(LocalDateTime.now()).group(school) + .groupAdmissionYear(23).email("gm@yello.com") + .build()); + + userRepository.save(User.builder() + .id(1L) + .recommendCount(0L).name("방형정") + .yelloId("hj_p__").gender(Gender.FEMALE) + .point(200).social(Social.KAKAO) + .profileImage("NO_IMAGE").uuid("1234") + .deletedAt(null).group(school) + .groupAdmissionYear(23).email("hj_p__@yello.com") + .build()); + + userRepository.save(User.builder() + .id(2L) + .recommendCount(0L).name("궝셍훙") + .yelloId("sh").gender(Gender.FEMALE) + .point(200).social(Social.KAKAO) + .profileImage("NO_IMAGE").uuid("12345") + .deletedAt(null).group(school) + .groupAdmissionYear(23).email("sh@yello.com") + .build()); + + userRepository.save(User.builder() + .id(3L) + .recommendCount(0L).name("잉응젱") + .yelloId("ej").gender(Gender.FEMALE) + .point(200).social(Social.KAKAO) + .profileImage("NO_IMAGE").uuid("123456") + .deletedAt(null).group(school) + .groupAdmissionYear(23).email("ej@yello.com") + .build()); + } + + @Test + void 유저_삭제정보_초기화에_성공합니다() { + // given + Long userId = 0L; + + // when + final User softDeletedUser = userRepository.getById(userId); + authService.renewUserInformation(softDeletedUser); + + final List targetIds = + friendRepository.findAllByUserIdNotFiltered(softDeletedUser.getId()) + .stream() + .map((friend) -> friend.getTarget().getDeletedAt()) + .toList(); + final List userIds = + friendRepository.findAllByTargetIdNotFiltered(softDeletedUser.getId()) + .stream() + .map((friend) -> friend.getUser().getDeletedAt()) + .toList(); + final Optional cooldown = cooldownRepository.findByUserId(userId); + + // then + assertThat(softDeletedUser.getDeletedAt()).isNull(); + targetIds.forEach((deletedTime) -> assertThat(deletedTime).isNull()); + userIds.forEach((deletedTime) -> assertThat(deletedTime).isNull()); + cooldown.ifPresent((cooldown1) -> assertThat(cooldown1.getDeletedAt()).isNull()); + } + + @Test + void Yello_Id_중복_조회에_성공합니다_중복임() { + // given + String yelloId = "hj_p__"; + + // when + Boolean isDuplicated = authService.isYelloIdDuplicated(yelloId); + + // then + assertThat(isDuplicated).isEqualTo(true); + } + + @Test + void Yello_Id_중복_조회에_성공합니다_중복아님() { + // given + String yelloId = "hj_p__123123"; + + // when + Boolean isDuplicated = authService.isYelloIdDuplicated(yelloId); + + // then + assertThat(isDuplicated).isEqualTo(false); + } + + @Test + void Yello_Id가_NULL일시_AuthBadRequestException이_발생합니다() { + // given + + // when + + // then + assertThatThrownBy(() -> authService.isYelloIdDuplicated(null)) + .isInstanceOf(AuthBadRequestException.class) + .hasMessageContaining(YELLOID_REQUIRED_EXCEPTION.getMessage()); + } + + @Test + void 회원가입_신규_유저_등록에_성공합니다() { + // given + final SignUpRequest request = SignUpRequest.builder() + .social(Social.KAKAO) + .uuid("123456789") + .email("agenda511@kakao.com") + .profileImage("NO_IMAGE") + .groupId(1L) + .groupAdmissionYear(19) + .name("이의제") + .yelloId("agenda511") + .gender(Gender.MALE) + .friends(new ArrayList<>()) + .recommendId("") + .build(); + + // when + final User signUpUser = authService.signUpUser(request); + final User expectedUser = userRepository.getById(signUpUser.getId()); + + // then + assertThat(signUpUser).isEqualTo(expectedUser); + } + + @Test + void 회원가입_신규_유저_등록에_실패합니다_uuid_충돌() { + // given + final SignUpRequest request = SignUpRequest.builder() + .social(Social.KAKAO) + .uuid("1234") + .email("agenda511@kakao.com") + .profileImage("NO_IMAGE") + .groupId(1L) + .groupAdmissionYear(19) + .name("이의제") + .yelloId("agenda511") + .gender(Gender.MALE) + .friends(new ArrayList<>()) + .recommendId("") + .build(); + + // when + + // then + assertThatThrownBy(() -> authService.signUpUser(request)) + .isInstanceOf(UserConflictException.class) + .hasMessageContaining(UUID_CONFLICT_USER_EXCEPTION.getMessage()); + } + + @Test + void 회원가입_신규_유저_등록에_실패합니다_yelloId_충돌() { + // given + final SignUpRequest request = SignUpRequest.builder() + .social(Social.KAKAO) + .uuid("12345678") + .email("agenda511@kakao.com") + .profileImage("NO_IMAGE") + .groupId(1L) + .groupAdmissionYear(19) + .name("이의제") + .yelloId("hj_p__") + .gender(Gender.MALE) + .friends(new ArrayList<>()) + .recommendId("") + .build(); + + // when + + // then + assertThatThrownBy(() -> authService.signUpUser(request)) + .isInstanceOf(UserConflictException.class) + .hasMessageContaining(YELLOID_CONFLICT_USER_EXCEPTION.getMessage()); + } + + @Test + void 회원가입_신규_유저_등록에_실패합니다_존재하지_않는_group() { + // given + final SignUpRequest request = SignUpRequest.builder() + .social(Social.KAKAO) + .uuid("12345678") + .email("agenda511@kakao.com") + .profileImage("NO_IMAGE") + .groupId(2L) + .groupAdmissionYear(19) + .name("이의제") + .yelloId("_euije") + .gender(Gender.MALE) + .friends(new ArrayList<>()) + .recommendId("") + .build(); + + // when + + // then + assertThatThrownBy(() -> authService.signUpUser(request)) + .isInstanceOf(GroupNotFoundException.class) + .hasMessageContaining(GROUPID_NOT_FOUND_GROUP_EXCEPTION.getMessage()); + } + + @Test + void 회원가입_친구_추천에_성공합니다_추천수() { + // given + String recommendYelloId = "hj_p__"; + + // when + final Long before = userRepository.getByYelloId(recommendYelloId).getRecommendCount(); + authService.recommendUser(recommendYelloId); + final User after = userRepository.getByYelloId(recommendYelloId); + + // then + assertThat(after.getRecommendCount()).isEqualTo(before + 1L); + } + + @Test + void 회원가입_친구_추천에_성공합니다_쿨다운삭제() { + // given + String recommendYelloId = "hj_p__"; + final User before = userRepository.getByYelloId(recommendYelloId); + cooldownRepository.save(Cooldown.builder() + .user(before) + .build()); + + // when + authService.recommendUser(recommendYelloId); + final User after = userRepository.getByYelloId(recommendYelloId); + final Optional cooldown = cooldownRepository.findByUserId(after.getId()); + + // then + assertThat(cooldown.isEmpty()).isEqualTo(true); + } + + @Test + void 회원가입_토큰_등록에_성공합니다() { + // given + Long id = 1L; + String uuid = "1234"; + + // when + final ServiceTokenVO token = authService.registerToken(id, uuid); + final ServiceTokenVO registeredToken = tokenRepository.get(id); + + // then +// assertThat(jwtTokenProvider.getUserId(token.accessToken())).isEqualTo(id); +// assertThat(jwtTokenProvider.getUserId(token.refreshToken())).isEqualTo(id); +// assertThat(jwtTokenProvider.getUserUuid(token.accessToken())).isEqualTo(uuid); +// assertThat(jwtTokenProvider.getUserUuid(token.refreshToken())).isEqualTo(uuid); + assertThat(registeredToken).isEqualTo(token); + } + + @Test + void 회원가입_친구_등록에_성공합니다() { + // given + Long id = 1L; + List friendList = new ArrayList<>(); + friendList.add(2L); + friendList.add(3L); + + // when + final User user = userRepository.getById(id); + authService.makeFriend(user, friendList); + + final List targetId = friendRepository.findAllByUserId(user.getId()) + .stream() + .map((friend) -> friend.getTarget().getId()) + .toList(); + final List userId = friendRepository.findAllByTargetId(user.getId()) + .stream() + .map((friend) -> friend.getUser().getId()) + .toList(); + + // then + assertThat(friendList).isSubsetOf(targetId); + assertThat(friendList).isSubsetOf(userId); + } + + @Test + void 회원가입_친구_등록에_실패합니다() { + // given + + /** + * NOTE - 실패 케이스가 없습니다. + */ + + // when + + // then + } + + @Test + void 회원가입_추천친구목록_조회에_성공합니다() { + // given + List kakaoFriendList = new ArrayList<>(); + kakaoFriendList.add("123"); // soft-deleted user + kakaoFriendList.add("1234"); + kakaoFriendList.add("12345"); + kakaoFriendList.add("123456"); + + final List expectedList = Stream.of("123", "1234", "12345", "123456") + .map(userRepository::getByUuid) + .map(User::getId) + .toList(); + + final OnBoardingFriendRequest request = OnBoardingFriendRequest.builder() + .friendKakaoId(kakaoFriendList) + .build(); + final Pageable pageable = PaginationFactory.createPageable(0); + + // when + final OnBoardingFriendResponse response = + authService.findOnBoardingFriends(request, pageable); + + // then + assertThat(response.totalCount() - 1).isEqualTo(3); + assertThat(expectedList.stream() + .sorted() + .toList()) + .isEqualTo(response.friendList() + .stream() + .map(OnBoardingFriend::id) + .sorted() + .toList()); + } +} diff --git a/src/test/java/com/yello/server/small/cooldown/FakeCooldownRepository.java b/src/test/java/com/yello/server/small/cooldown/FakeCooldownRepository.java index 2e851760..3b84417f 100644 --- a/src/test/java/com/yello/server/small/cooldown/FakeCooldownRepository.java +++ b/src/test/java/com/yello/server/small/cooldown/FakeCooldownRepository.java @@ -1,19 +1,49 @@ package com.yello.server.small.cooldown; +import static com.yello.server.global.common.ErrorCode.ID_NOT_FOUND_COOLDOWN_EXCEPTION; + import com.yello.server.domain.cooldown.entity.Cooldown; +import com.yello.server.domain.cooldown.exception.CooldownNotFoundException; import com.yello.server.domain.cooldown.repository.CooldownRepository; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; public class FakeCooldownRepository implements CooldownRepository { + private final List data = new ArrayList<>(); + private Long id = 0L; + @Override - public void save(Cooldown cooldown) { + public Cooldown save(Cooldown cooldown) { + if (cooldown.getId() != null && cooldown.getId() > id) { + id = cooldown.getId(); + } + + Cooldown newCooldown = Cooldown.builder() + .id(cooldown.getId() == null ? ++id : cooldown.getId()) + .user(cooldown.getUser()) + .createdAt(cooldown.getCreatedAt()) + .deletedAt(null) + .build(); + + data.add(newCooldown); + return newCooldown; + } + @Override + public Cooldown getByUserid(Long userId) { + return data.stream() + .filter(user -> user.getId().equals(id)) + .findFirst() + .orElseThrow(() -> new CooldownNotFoundException(ID_NOT_FOUND_COOLDOWN_EXCEPTION)); } @Override public Optional findByUserId(Long userId) { - return Optional.empty(); + return data.stream() + .filter(user -> user.getId().equals(id)) + .findFirst(); } @Override @@ -28,6 +58,6 @@ public Optional findByUserIdNotFiltered(Long userId) { @Override public void delete(Cooldown cooldown) { - + data.remove(cooldown); } } diff --git a/src/test/java/com/yello/server/small/friend/FakeFriendRepository.java b/src/test/java/com/yello/server/small/friend/FakeFriendRepository.java index ef6fcbaf..c2e6941b 100644 --- a/src/test/java/com/yello/server/small/friend/FakeFriendRepository.java +++ b/src/test/java/com/yello/server/small/friend/FakeFriendRepository.java @@ -14,13 +14,17 @@ public class FakeFriendRepository implements FriendRepository { - private final List data = new ArrayList<>(); + private List data = new ArrayList<>(); private Long id = 0L; @Override public Friend save(Friend friend) { + if (friend.getId() != null && friend.getId() > id) { + id = friend.getId(); + } + Friend newFriend = Friend.builder() - .id(id++) + .id(friend.getId() == null ? ++id : friend.getId()) .user(friend.getUser()) .target(friend.getTarget()) .deletedAt(null) @@ -33,7 +37,7 @@ public Friend save(Friend friend) { @Override public Integer countAllByUserId(Long userId) { return data.stream() - .filter(friend -> friend.getUser().getId().equals(userId) && friend.getDeletedAt()==null) + .filter(friend -> friend.getUser().getId().equals(userId) && friend.getDeletedAt() == null) .toList() .size(); } @@ -49,8 +53,9 @@ public Optional findByUserAndTarget(Long userId, Long targetId) { @Override public Friend getByUserAndTarget(Long userId, Long targetId) { return data.stream() - .filter(friend -> friend.getUser().getId().equals(userId) && friend.getTarget().getId().equals(targetId) - && friend.getDeletedAt()==null) + .filter(friend -> friend.getUser().getId().equals(userId) && + friend.getTarget().getId().equals(targetId) + && friend.getDeletedAt() == null) .findFirst() .orElseThrow(() -> new FriendNotFoundException(NOT_FOUND_FRIEND_EXCEPTION)); } @@ -58,14 +63,15 @@ public Friend getByUserAndTarget(Long userId, Long targetId) { @Override public boolean existsByUserAndTarget(Long userId, Long targetId) { return data.stream() - .anyMatch(friend -> friend.getUser().getId().equals(userId) && friend.getTarget().getId().equals(targetId) - && friend.getDeletedAt()==null); + .anyMatch(friend -> friend.getUser().getId().equals(userId) && + friend.getTarget().getId().equals(targetId) + && friend.getDeletedAt() == null); } @Override public Page findAllFriendsByUserId(Pageable pageable, Long userId) { final List friends = data.stream() - .filter(friend -> friend.getUser().getId().equals(userId) && friend.getDeletedAt()==null) + .filter(friend -> friend.getUser().getId().equals(userId) && friend.getDeletedAt() == null) .toList(); final int start = (int) pageable.getOffset(); @@ -76,14 +82,15 @@ public Page findAllFriendsByUserId(Pageable pageable, Long userId) { @Override public List findAllByUserId(Long userId) { return data.stream() - .filter(friend -> friend.getUser().getId().equals(userId) && friend.getDeletedAt()==null) + .filter(friend -> friend.getUser().getId().equals(userId) && friend.getDeletedAt() == null) .toList(); } @Override public List findAllByTargetId(Long targetId) { return data.stream() - .filter(friend -> friend.getTarget().getId().equals(targetId) && friend.getDeletedAt()==null) + .filter( + friend -> friend.getTarget().getId().equals(targetId) && friend.getDeletedAt() == null) .toList(); } @@ -100,9 +107,4 @@ public List findAllByTargetIdNotFiltered(Long targetId) { .filter(friend -> friend.getTarget().getId().equals(targetId)) .toList(); } - - @Override - public void deleteByUserAndTarget(Long userId, Long targetId) { - //do something - } } diff --git a/src/test/java/com/yello/server/small/friend/FriendServiceTest.java b/src/test/java/com/yello/server/small/friend/FriendServiceTest.java new file mode 100644 index 00000000..539a24c6 --- /dev/null +++ b/src/test/java/com/yello/server/small/friend/FriendServiceTest.java @@ -0,0 +1,280 @@ +package com.yello.server.small.friend; + +import static com.yello.server.global.common.factory.PaginationFactory.createPageable; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.yello.server.domain.friend.dto.request.KakaoRecommendRequest; +import com.yello.server.domain.friend.dto.response.FriendShuffleResponse; +import com.yello.server.domain.friend.dto.response.FriendsResponse; +import com.yello.server.domain.friend.dto.response.RecommendFriendResponse; +import com.yello.server.domain.friend.entity.Friend; +import com.yello.server.domain.friend.exception.FriendException; +import com.yello.server.domain.friend.exception.FriendNotFoundException; +import com.yello.server.domain.friend.repository.FriendRepository; +import com.yello.server.domain.friend.service.FriendService; +import com.yello.server.domain.group.entity.School; +import com.yello.server.domain.user.entity.Gender; +import com.yello.server.domain.user.entity.Social; +import com.yello.server.domain.user.entity.User; +import com.yello.server.domain.user.exception.UserNotFoundException; +import com.yello.server.domain.user.repository.UserRepository; +import com.yello.server.domain.vote.repository.VoteRepository; +import com.yello.server.small.user.FakeUserRepository; +import com.yello.server.small.vote.FakeVoteRepository; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.data.domain.Pageable; + +class FriendServiceTest { + + private final UserRepository userRepository = new FakeUserRepository(); + private final FriendRepository friendRepository = new FakeFriendRepository(); + private final VoteRepository voteRepository = new FakeVoteRepository(); + private FriendService friendService; + private User user1; + private User user2; + private User user3; + private User user4; + private User user5; + + @BeforeEach + void init() { + this.friendService = FriendService.builder() + .userRepository(userRepository) + .friendRepository(friendRepository) + .voteRepository(voteRepository) + .build(); + School school = School.builder() + .id(1L) + .schoolName("Test School") + .departmentName("Testing") + .build(); + user1 = userRepository.save(User.builder() + .id(1L) + .recommendCount(0L).name("test") + .yelloId("yelloworld").gender(Gender.MALE) + .point(200).social(Social.KAKAO) + .profileImage("test image").uuid("1234") + .deletedAt(null).group(school) + .groupAdmissionYear(20).email("test@test.com") + .build()); + user2 = userRepository.save(User.builder() + .id(2L) + .recommendCount(0L).name("hello") + .yelloId("helloworld").gender(Gender.MALE) + .point(200).social(Social.KAKAO) + .profileImage("test image 2").uuid("5678") + .deletedAt(null).group(school) + .groupAdmissionYear(17).email("hello@test.com") + .build()); + user3 = userRepository.save(User.builder() + .id(3L) + .recommendCount(0L).name("yello") + .yelloId("yelloworld").gender(Gender.MALE) + .point(200).social(Social.KAKAO) + .profileImage("test image 3").uuid("91011") + .deletedAt(null).group(school) + .groupAdmissionYear(19).email("yello@test.com") + .build()); + user4 = userRepository.save(User.builder() + .id(4L) + .recommendCount(0L).name("aaa") + .yelloId("aaa").gender(Gender.MALE) + .point(200).social(Social.KAKAO) + .profileImage("test image 4").uuid("aaa") + .deletedAt(null).group(school) + .groupAdmissionYear(19).email("aaa@test.com") + .build()); + user5 = userRepository.save(User.builder() + .id(5L) + .recommendCount(0L).name("bbb") + .yelloId("aaa").gender(Gender.MALE) + .point(200).social(Social.KAKAO) + .profileImage("test image 5").uuid("bbb") + .deletedAt(null).group(school) + .groupAdmissionYear(19).email("bbb@test.com") + .build()); + friendRepository.save(Friend.createFriend(user1, user2)); + friendRepository.save(Friend.createFriend(user2, user1)); + } + + @Test + void 친구_전체_조회에_성공합니다() { + // given + final Long userId = 1L; + final Integer page = 0; + final Pageable pageable = createPageable(page); + + // when + final FriendsResponse friends = friendService.findAllFriends(pageable, userId); + + // then + assertThat(friends.totalCount()).isEqualTo(1); + assertThat(friends.friends().get(0).name()).isEqualTo("hello"); + } + + @Test + void 친구_추가에_성공합니다() { + // given + final Long userId = 1L; + final Long targetId = 3L; + + // when + friendService.addFriend(userId, targetId); + final Friend friend = friendRepository.getByUserAndTarget(userId, targetId); + + // then + assertThat(friend.getUser().getName()).isEqualTo("test"); + assertThat(friend.getTarget().getName()).isEqualTo("yello"); + } + + @Test + void 친구_추가_시_존재하지_않는_유저_id인_경우에_UserNotFoundException이_발생합니다() { + // given + final Long userId = 1L; + final Long targetId = 999L; + + // when + // then + assertThatThrownBy(() -> friendService.addFriend(userId, targetId)) + .isInstanceOf(UserNotFoundException.class) + .hasMessageContaining("[UserNotFoundException] 탈퇴했거나 존재하지 않는 유저의 id 입니다."); + } + + @Test + void 친구_추가_시_이미_친구인_경우에_FriendException이_발생합니다() { + // given + final Long userId = 1L; + final Long targetId = 2L; + + // when + // then + assertThatThrownBy(() -> friendService.addFriend(userId, targetId)) + .isInstanceOf(FriendException.class) + .hasMessageContaining("[FriendException] 이미 존재하는 친구입니다."); + } + + @Test + void 친구_셔플에_성공합니다() { + // given + final Long userId = 1L; + + // when + friendRepository.save(Friend.createFriend(user1, user3)); + friendRepository.save(Friend.createFriend(user1, user4)); + friendRepository.save(Friend.createFriend(user1, user5)); + + List firstShuffledList = friendService.findShuffledFriend(userId); + List secoundShuffledList = friendService.findShuffledFriend(userId); + + // then + assertThat(firstShuffledList.size()).isEqualTo(4); + assertThat(secoundShuffledList.size()).isEqualTo(4); + assertThat(secoundShuffledList).isNotEqualTo(firstShuffledList); + } + + @Test + void 친구_셔플_시_존재하지_않는_유저_id인_경우에_UserNotFoundException이_발생합니다() { + // given + final Long userId = 999L; + + // when + // then + assertThatThrownBy(() -> friendService.findShuffledFriend(userId)) + .isInstanceOf(UserNotFoundException.class) + .hasMessageContaining("[UserNotFoundException] 탈퇴했거나 존재하지 않는 유저의 id 입니다."); + } + + @Test + void 친구_셔플_시_친구_수가_부족한_경우에_FriendException이_발생합니다() { + // given + final Long userId = 1L; + + // when + // then + assertThatThrownBy(() -> friendService.findShuffledFriend(userId)) + .isInstanceOf(FriendException.class) + .hasMessageContaining("[FriendException] 친구가 4명 이하입니다."); + } + + @Test + void 학교_추천_친구_조회에_성공합니다() { + // given + final Long userId = 1L; + final Integer page = 0; + final Pageable pageable = createPageable(page); + + // when + final RecommendFriendResponse recommendSchoolFriends = friendService.findAllRecommendSchoolFriends( + pageable, + userId + ); + + // then + assertThat(recommendSchoolFriends.totalCount()).isEqualTo(3); + } + + @Test + void 친구_끊기에_성공합니다() { + // given + final Long userId = 1L; + final Long targetId = 2L; + + // when + friendService.deleteFriend(userId, targetId); + final List friends = friendRepository.findAllByUserIdNotFiltered(userId); + + // then + assertThat(friends.get(0).getDeletedAt()).isNotNull(); + } + + @Test + void 존재하지_않는_유저_친구_끊기_시_UserNotFoundException이_발생합니다() { + // given + final Long userId = 1L; + final Long targetId = 999L; + + // when + // then + assertThatThrownBy(() -> friendService.deleteFriend(userId, targetId)) + .isInstanceOf(UserNotFoundException.class) + .hasMessageContaining("[UserNotFoundException] 탈퇴했거나 존재하지 않는 유저의 id 입니다."); + } + + @Test + void 친구_끊기_시_친구가_아니라면_FriendNotFoundException이_발생합니다() { + // given + final Long userId = 1L; + final Long targetId = 4L; + + // when + // then + assertThatThrownBy(() -> friendService.deleteFriend(userId, targetId)) + .isInstanceOf(FriendNotFoundException.class) + .hasMessageContaining("[FriendNotFoundException] 존재하지 않는 친구이거나 친구 관계가 아닙니다."); + } + + @Test + void 카카오_추천_친구_조회에_성공합니다() { + // given + final Long userId = 1L; + final Integer page = 0; + final Pageable pageable = createPageable(page); + final String[] friendKakaoId = {"5678", "91011", "aaa", "bbb"}; + final KakaoRecommendRequest request = KakaoRecommendRequest.builder() + .friendKakaoId(friendKakaoId) + .build(); + + // when + final RecommendFriendResponse allRecommendKakaoFriends = friendService.findAllRecommendKakaoFriends( + pageable, + userId, + request + ); + + // then + assertThat(allRecommendKakaoFriends.totalCount()).isEqualTo(3); + } +} \ No newline at end of file diff --git a/src/test/java/com/yello/server/small/global/redis/FakeTokenRepository.java b/src/test/java/com/yello/server/small/global/redis/FakeTokenRepository.java new file mode 100644 index 00000000..12aff26b --- /dev/null +++ b/src/test/java/com/yello/server/small/global/redis/FakeTokenRepository.java @@ -0,0 +1,40 @@ +package com.yello.server.small.global.redis; + +import com.yello.server.domain.authorization.dto.ServiceTokenVO; +import com.yello.server.infrastructure.redis.repository.TokenRepository; +import java.util.HashMap; + +public class FakeTokenRepository implements TokenRepository { + + private final HashMap data = new HashMap<>(); + + @Override + public void set(Long key, ServiceTokenVO value) { + data.put(key, value); + } + + @Override + public void setDeviceToken(String uuid, String deviceToken) { + + } + + @Override + public ServiceTokenVO get(Long key) { + return data.get(Long.parseLong(key.toString())); + } + + @Override + public String getDeviceToken(String uuid) { + return null; + } + + @Override + public void deleteDeviceToken(String uuid) { + + } + + @Override + public Boolean hasKey(String uuid) { + return null; + } +} diff --git a/src/test/java/com/yello/server/small/group/FakeSchoolRepository.java b/src/test/java/com/yello/server/small/group/FakeSchoolRepository.java new file mode 100644 index 00000000..cf0181a3 --- /dev/null +++ b/src/test/java/com/yello/server/small/group/FakeSchoolRepository.java @@ -0,0 +1,69 @@ +package com.yello.server.small.group; + +import static com.yello.server.global.common.ErrorCode.GROUPID_NOT_FOUND_GROUP_EXCEPTION; + +import com.yello.server.domain.group.entity.School; +import com.yello.server.domain.group.exception.GroupNotFoundException; +import com.yello.server.domain.group.repository.SchoolRepository; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import org.springframework.data.domain.Pageable; + +public class FakeSchoolRepository implements SchoolRepository { + + private final List data = new ArrayList<>(); + private Long id = 0L; + + @Override + public School save(School school) { + if (school.getId() != null && school.getId() > id) { + id = school.getId(); + } + + School newSchool = School.builder() + .id(school.getId() == null ? ++id : school.getId()) + .schoolName(school.getSchoolName()) + .departmentName(school.getDepartmentName()) + .build(); + + data.add(newSchool); + return newSchool; + } + + @Override + public School getById(Long id) { + return data.stream() + .filter(school -> school.getId().equals(id)) + .findFirst() + .orElseThrow(() -> new GroupNotFoundException(GROUPID_NOT_FOUND_GROUP_EXCEPTION)); + } + + @Override + public Optional findById(Long id) { + return data.stream() + .filter(school -> school.getId().equals(id)) + .findFirst(); + } + + @Override + public Integer countDistinctSchoolNameContaining(String schoolName) { + return null; + } + + @Override + public List findDistinctSchoolNameContaining(String schoolName, Pageable pageable) { + return null; + } + + @Override + public Integer countAllBySchoolNameContaining(String schoolName, String departmentName) { + return null; + } + + @Override + public List findAllBySchoolNameContaining(String schoolName, String departmentName, + Pageable pageable) { + return null; + } +} diff --git a/src/test/java/com/yello/server/small/keyword/FakeKeywordRepository.java b/src/test/java/com/yello/server/small/keyword/FakeKeywordRepository.java new file mode 100644 index 00000000..a71ca5fb --- /dev/null +++ b/src/test/java/com/yello/server/small/keyword/FakeKeywordRepository.java @@ -0,0 +1,28 @@ +package com.yello.server.small.keyword; + +import com.yello.server.domain.keyword.entity.Keyword; +import com.yello.server.domain.keyword.repository.KeywordRepository; +import java.util.ArrayList; +import java.util.List; + +public class FakeKeywordRepository implements KeywordRepository { + + private final List data = new ArrayList<>(); + private Long id = 0L; + + @Override + public Keyword save(Keyword keyword) { + Keyword newKeyword = Keyword.builder() + .id(keyword.getId() == null ? id++ : keyword.getId()) + .keywordName(keyword.getKeywordName()) + .question(keyword.getQuestion()) + .build(); + data.add(newKeyword); + return newKeyword; + } + + @Override + public List findAll() { + return data.stream().toList(); + } +} diff --git a/src/test/java/com/yello/server/small/question/FakeQuestionRepository.java b/src/test/java/com/yello/server/small/question/FakeQuestionRepository.java new file mode 100644 index 00000000..de95f398 --- /dev/null +++ b/src/test/java/com/yello/server/small/question/FakeQuestionRepository.java @@ -0,0 +1,58 @@ +package com.yello.server.small.question; + +import static com.yello.server.global.common.ErrorCode.NOT_FOUND_QUESTION_EXCEPTION; + +import com.yello.server.domain.keyword.entity.Keyword; +import com.yello.server.domain.keyword.repository.KeywordRepository; +import com.yello.server.domain.question.entity.Question; +import com.yello.server.domain.question.exception.QuestionNotFoundException; +import com.yello.server.domain.question.repository.QuestionRepository; +import com.yello.server.small.keyword.FakeKeywordRepository; +import java.util.ArrayList; +import java.util.List; + +public class FakeQuestionRepository implements QuestionRepository { + + private final KeywordRepository keywordRepository = new FakeKeywordRepository(); + private final List data = new ArrayList<>(); + private Long id = 0L; + + + @Override + public List findAll() { + return data.stream() + .toList(); + } + + @Override + public Question findById(Long questionId) { + return data.stream() + .filter(question -> question.getId().equals(questionId)) + .findFirst() + .orElseThrow(() -> new QuestionNotFoundException(NOT_FOUND_QUESTION_EXCEPTION)); + } + + @Override + public Question save(Question question) { + Question newQuestion = Question.builder() + .id(question.getId() == null ? id++ : question.getId()) + .nameHead(question.getNameHead()) + .nameFoot(question.getNameFoot()) + .keywordFoot(question.getKeywordFoot()) + .keywordHead(question.getKeywordHead()) + .build(); + + Keyword keyword1 = keywordRepository.save(Keyword.of("keyword", newQuestion)); + Keyword keyword2 = keywordRepository.save(Keyword.of("keyword", newQuestion)); + Keyword keyword3 = keywordRepository.save(Keyword.of("keyword", newQuestion)); + Keyword keyword4 = keywordRepository.save(Keyword.of("keyword", newQuestion)); + + newQuestion.addKeyword(keyword1); + newQuestion.addKeyword(keyword2); + newQuestion.addKeyword(keyword3); + newQuestion.addKeyword(keyword4); + + data.add(newQuestion); + return newQuestion; + } +} diff --git a/src/test/java/com/yello/server/small/user/FakeUserRepository.java b/src/test/java/com/yello/server/small/user/FakeUserRepository.java index 83be8915..37206453 100644 --- a/src/test/java/com/yello/server/small/user/FakeUserRepository.java +++ b/src/test/java/com/yello/server/small/user/FakeUserRepository.java @@ -18,13 +18,17 @@ public class FakeUserRepository implements UserRepository { @Override public User save(User user) { + if (user.getId() != null && user.getId() > id) { + id = user.getId(); + } + User newUser = User.builder() - .id(user.getId()==null ? id++ : user.getId()) + .id(user.getId() == null ? ++id : user.getId()) .recommendCount(0L) .name(user.getName()) .yelloId(user.getYelloId()) .gender(user.getGender()) - .point(200) + .point(2000) .social(user.getSocial()) .profileImage(user.getProfileImage()) .uuid(user.getUuid()) @@ -35,7 +39,7 @@ public User save(User user) { .build(); data.add(newUser); - return user; + return newUser; } @Override diff --git a/src/test/java/com/yello/server/small/vote/FakeVoteRepository.java b/src/test/java/com/yello/server/small/vote/FakeVoteRepository.java index 998e89f2..65f0e721 100644 --- a/src/test/java/com/yello/server/small/vote/FakeVoteRepository.java +++ b/src/test/java/com/yello/server/small/vote/FakeVoteRepository.java @@ -7,6 +7,7 @@ import com.yello.server.domain.vote.repository.VoteRepository; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import org.springframework.data.domain.Pageable; public class FakeVoteRepository implements VoteRepository { @@ -17,7 +18,7 @@ public class FakeVoteRepository implements VoteRepository { @Override public Vote save(Vote vote) { Vote newVote = Vote.builder() - .id(id++) + .id(vote.getId() == null ? id++ : vote.getId()) .answer(vote.getAnswer()) .nameHint(vote.getNameHint()) .isAnswerRevealed(vote.getIsAnswerRevealed()) @@ -26,19 +27,27 @@ public Vote save(Vote vote) { .receiver(vote.getReceiver()) .question(vote.getQuestion()) .colorIndex(vote.getColorIndex()) + .createdAt(vote.getCreatedAt()) .build(); data.add(newVote); return newVote; } @Override - public Vote findById(Long id) { + public Vote getById(Long id) { return data.stream() .filter(vote -> vote.getId().equals(id)) .findFirst() .orElseThrow(() -> new VoteNotFoundException(NOT_FOUND_VOTE_EXCEPTION)); } + @Override + public Optional findById(Long id) { + return data.stream() + .filter(vote -> vote.getId().equals(id)) + .findFirst(); + } + @Override public Integer countAllByReceiverUserId(Long userId) { return data.stream() diff --git a/src/test/java/com/yello/server/small/vote/VoteServiceTest.java b/src/test/java/com/yello/server/small/vote/VoteServiceTest.java new file mode 100644 index 00000000..20ccc12d --- /dev/null +++ b/src/test/java/com/yello/server/small/vote/VoteServiceTest.java @@ -0,0 +1,348 @@ +package com.yello.server.small.vote; + +import static com.yello.server.global.common.factory.PaginationFactory.createPageable; +import static org.assertj.core.api.Assertions.assertThat; + +import com.yello.server.domain.cooldown.repository.CooldownRepository; +import com.yello.server.domain.friend.entity.Friend; +import com.yello.server.domain.friend.repository.FriendRepository; +import com.yello.server.domain.group.entity.School; +import com.yello.server.domain.keyword.dto.response.KeywordCheckResponse; +import com.yello.server.domain.keyword.repository.KeywordRepository; +import com.yello.server.domain.question.dto.response.QuestionForVoteResponse; +import com.yello.server.domain.question.entity.Question; +import com.yello.server.domain.question.repository.QuestionRepository; +import com.yello.server.domain.user.entity.Gender; +import com.yello.server.domain.user.entity.Social; +import com.yello.server.domain.user.entity.User; +import com.yello.server.domain.user.repository.UserRepository; +import com.yello.server.domain.vote.dto.request.CreateVoteRequest; +import com.yello.server.domain.vote.dto.request.VoteAnswer; +import com.yello.server.domain.vote.dto.response.RevealNameResponse; +import com.yello.server.domain.vote.dto.response.VoteAvailableResponse; +import com.yello.server.domain.vote.dto.response.VoteCreateResponse; +import com.yello.server.domain.vote.dto.response.VoteDetailResponse; +import com.yello.server.domain.vote.dto.response.VoteFriendResponse; +import com.yello.server.domain.vote.dto.response.VoteListResponse; +import com.yello.server.domain.vote.entity.Vote; +import com.yello.server.domain.vote.repository.VoteRepository; +import com.yello.server.domain.vote.service.VoteService; +import com.yello.server.small.cooldown.FakeCooldownRepository; +import com.yello.server.small.friend.FakeFriendRepository; +import com.yello.server.small.keyword.FakeKeywordRepository; +import com.yello.server.small.question.FakeQuestionRepository; +import com.yello.server.small.user.FakeUserRepository; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.data.domain.Pageable; + +public class VoteServiceTest { + + private final UserRepository userRepository = new FakeUserRepository(); + private final FriendRepository friendRepository = new FakeFriendRepository(); + private final VoteRepository voteRepository = new FakeVoteRepository(); + private final CooldownRepository cooldownRepository = new FakeCooldownRepository(); + private final QuestionRepository questionRepository = new FakeQuestionRepository(); + private final KeywordRepository keywordRepository = new FakeKeywordRepository(); + private VoteService voteService; + private Question question1; + private Question question2; + private Question question3; + private Question question4; + private Question question5; + private Question question6; + private Question question7; + private Question question8; + private Question question9; + private Question question10; + + + @BeforeEach + void init() { + this.voteService = VoteService.builder() + .voteRepository(voteRepository) + .friendRepository(friendRepository) + .cooldownRepository(cooldownRepository) + .userRepository(userRepository) + .questionRepository(questionRepository) + .keywordRepository(keywordRepository) + .build(); + + School school = School.builder() + .schoolName("Yello School") + .departmentName("Yello") + .build(); + question1 = Question.builder() + .id(1L) + .nameHead(null).nameFoot("와") + .keywordHead("멋진").keywordFoot("에서 놀고싶어") + .build(); + question2 = Question.builder() + .id(2L) + .nameHead(null).nameFoot("와") + .keywordHead("이쁜").keywordFoot("닮아보여") + .build(); + question3 = Question.builder() + .id(3L) + .nameHead(null).nameFoot("와") + .keywordHead(null).keywordFoot("을 가고싶어") + .build(); + question4 = Question.builder() + .id(4L) + .nameHead(null).nameFoot("와") + .keywordHead(null).keywordFoot("을 가고싶어") + .build(); + question5 = Question.builder() + .id(5L) + .nameHead(null).nameFoot("와") + .keywordHead(null).keywordFoot("을 가고싶어") + .build(); + question6 = Question.builder() + .id(6L) + .nameHead(null).nameFoot("와") + .keywordHead(null).keywordFoot("을 가고싶어") + .build(); + question7 = Question.builder() + .id(7L) + .nameHead(null).nameFoot("와") + .keywordHead(null).keywordFoot("을 가고싶어") + .build(); + question8 = Question.builder() + .id(8L) + .nameHead(null).nameFoot("와") + .keywordHead(null).keywordFoot("을 가고싶어") + .build(); + + questionRepository.save(question1); + questionRepository.save(question2); + questionRepository.save(question3); + questionRepository.save(question4); + questionRepository.save(question5); + questionRepository.save(question6); + questionRepository.save(question7); + questionRepository.save(question8); + + User user1 = userRepository.save(User.builder() + .id(1L) + .recommendCount(0L).name("yello") + .yelloId("yelloId").gender(Gender.FEMALE) + .social(Social.KAKAO) + .profileImage("yello image").group(school) + .deletedAt(null).uuid("123") + .groupAdmissionYear(20).email("yello@gmail.com") + .build()); + User user2 = userRepository.save(User.builder() + .id(2L) + .recommendCount(0L).name("yello2") + .yelloId("yelloId2").gender(Gender.FEMALE) + .social(Social.KAKAO) + .profileImage("yello image2").group(school) + .deletedAt(null).uuid("456") + .groupAdmissionYear(20).email("yello2@gmail.com") + .build()); + User user3 = userRepository.save(User.builder() + .id(3L) + .recommendCount(0L).name("yello3") + .yelloId("yelloId3").gender(Gender.FEMALE) + .social(Social.KAKAO) + .profileImage("yello image3").group(school) + .deletedAt(null).uuid("4567") + .groupAdmissionYear(20).email("yello3@gmail.com") + .build()); + User user4 = userRepository.save(User.builder() + .id(4L) + .recommendCount(0L).name("yello4") + .yelloId("yelloId4").gender(Gender.FEMALE) + .social(Social.KAKAO) + .profileImage("yello image4").group(school) + .deletedAt(null).uuid("45678") + .groupAdmissionYear(20).email("yello4@gmail.com") + .build()); + User user5 = userRepository.save(User.builder() + .id(5L) + .recommendCount(0L).name("yello5") + .yelloId("yelloId5").gender(Gender.FEMALE) + .social(Social.KAKAO) + .profileImage("yello image5").group(school) + .deletedAt(null).uuid("456789") + .groupAdmissionYear(20).email("yello5@gmail.com") + .build()); + + friendRepository.save(Friend.createFriend(user2, user1)); + friendRepository.save(Friend.createFriend(user1, user2)); + friendRepository.save(Friend.createFriend(user1, user3)); + friendRepository.save(Friend.createFriend(user1, user4)); + friendRepository.save(Friend.createFriend(user1, user5)); + + voteRepository.save(Vote.builder() + .id(1L) + .colorIndex(0).answer("test") + .isRead(false).nameHint(-1).isAnswerRevealed(false) + .sender(userRepository.getById(2L)) + .receiver(userRepository.getById(1L)) + .question(question1).createdAt(LocalDateTime.now()) + .build()); + voteRepository.save(Vote.builder() + .id(2L) + .colorIndex(0).answer("test2") + .isRead(false).nameHint(-1).isAnswerRevealed(false) + .sender(userRepository.getById(2L)) + .receiver(userRepository.getById(1L)) + .question(question2).createdAt(LocalDateTime.now().minusMinutes(1)) + .build()); + voteRepository.save(Vote.builder() + .id(3L) + .colorIndex(0).answer("test3") + .isRead(false).nameHint(-1).isAnswerRevealed(false) + .sender(userRepository.getById(2L)) + .receiver(userRepository.getById(1L)) + .question(question3).createdAt(LocalDateTime.now().minusMinutes(2)) + .build()); + voteRepository.save(Vote.builder() + .id(3L) + .colorIndex(0).answer("test3") + .isRead(false).nameHint(-1).isAnswerRevealed(false) + .sender(userRepository.getById(2L)) + .receiver(userRepository.getById(1L)) + .question(question3).createdAt(LocalDateTime.now().minusMinutes(2)) + .build()); + + + } + + @Test + void 내가_받은_투표_전체_조회에_성공합니다() { + // given + final Long userId = 1L; + final Integer page = 0; + final Pageable pageable = createPageable(page); + + // when + VoteListResponse result = voteService.findAllVotes(userId, pageable); + + // then + assertThat(result.totalCount()).isEqualTo(4); + assertThat(result.votes().get(0).id()).isEqualTo(1L); + + } + + @Test + void 상세_투표_조회에_성공합니다() { + // given + final Long voteId = 1L; + final Vote vote = voteRepository.getById(voteId); + + // when + final VoteDetailResponse result = voteService.findVoteById(voteId); + + // then + assertThat(result.senderName()).isEqualTo("yello2"); + assertThat(vote.getIsRead()).isEqualTo(true); + + } + + @Test + void 친구들이_받은_투표_조회에_성공합니다() { + // given + final Long userId = 1L; + final Pageable pageable = createPageable(0); + + // when + List result = + voteService.findAllFriendVotes(userId, pageable); // 다시 확인 !! + + // then + assertThat(result.size()).isEqualTo(4); + assertThat(result.get(0).id()).isEqualTo(1L); + + } + + @Test + void 특정_투표에_대한_키워드_확인에_성공합니다() { + // given + final Long userId = 1L; + final Long voteId = 1L; + final Vote vote = voteRepository.getById(voteId); + final User user = userRepository.getById(userId); + final Integer beforePoint = user.getPoint(); + + // when + final KeywordCheckResponse result = voteService.checkKeyword(userId, voteId); + + // then + assertThat(vote.getIsAnswerRevealed()).isEqualTo(true); + assertThat(user.getPoint()).isEqualTo(beforePoint - 100); + assertThat(result.answer()).isEqualTo("test"); + } + + @Test + void 투표하기_시_투표_10개_조회에_성공합니다() { + // given + final Long userId = 1L; + + // when + List result = voteService.findVoteQuestionList(userId); + + // then + assertThat(result.size()).isEqualTo(8); + + } + + @Test + void 투표_가능_여부_조회에_성공합니다() { + // given + final Long userId = 1L; + + // when + VoteAvailableResponse result = voteService.checkVoteAvailable(userId); + + // then + assertThat(result.isPossible()).isEqualTo(true); + + } + + @Test + void 투표_생성에_성공합니다() { + // given + final Long userId = 1L; + final List voteAnswerList = new ArrayList<>(); + VoteAnswer answer1 = VoteAnswer.builder() + .friendId(1L) + .questionId(1L) + .keywordName("test") + .colorIndex(0) + .build(); + voteAnswerList.add(answer1); + + CreateVoteRequest request = CreateVoteRequest.builder() + .voteAnswerList(voteAnswerList) + .totalPoint(3) + .build(); + + // when + VoteCreateResponse result = voteService.createVote(userId, request); + + // then + assertThat(result.point()).isEqualTo(2003); + + } + + @Test + void 투표_이름_힌트_조회에_성공합니다() { + // given + final Long userId = 1L; + final Long voteId = 1L; + final User user = userRepository.getById(userId); + + // when + RevealNameResponse result = voteService.revealNameHint(userId, voteId); + + // then + assertThat(result.name()).isIn('t', 'e'); + assertThat(result.nameIndex()).isLessThan(2); + + } +}