diff --git a/src/docs/asciidoc/auth.adoc b/src/docs/asciidoc/auth.adoc index 04449d60..683a2657 100644 --- a/src/docs/asciidoc/auth.adoc +++ b/src/docs/asciidoc/auth.adoc @@ -10,3 +10,8 @@ operation::auth-controller-test/kakao-o-auth-sign-in[snippets='http-request,curl === `POST` 토큰 재발급 operation::auth-controller-test/reissue[snippets='http-request,curl-request,request-cookies,http-response,response-cookies,response-fields'] + +[[게스트-토큰-발급]] +=== `POST` 게스트 토큰 발급 + +operation::auth-controller-test/guest-token[snippets='http-request,curl-request,http-response,response-fields'] diff --git a/src/main/java/com/swyp8team2/auth/application/AuthService.java b/src/main/java/com/swyp8team2/auth/application/AuthService.java index 470816d7..bbce4488 100644 --- a/src/main/java/com/swyp8team2/auth/application/AuthService.java +++ b/src/main/java/com/swyp8team2/auth/application/AuthService.java @@ -13,8 +13,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.security.NoSuchAlgorithmException; - @Service @RequiredArgsConstructor public class AuthService { @@ -40,11 +38,13 @@ private SocialAccount createUser(OAuthUserInfo oAuthUserInfo) { return socialAccountRepository.save(SocialAccount.create(userId, oAuthUserInfo)); } + @Transactional public TokenPair reissue(String refreshToken) { return jwtService.reissue(refreshToken); } - public String guestLogin() { + @Transactional + public String createGuestToken() { Long guestId = userService.createGuest(); return cryptoService.encrypt(String.valueOf(guestId)); } diff --git a/src/main/java/com/swyp8team2/auth/application/oauth/OAuthService.java b/src/main/java/com/swyp8team2/auth/application/oauth/OAuthService.java index 826e77bc..dd6516a4 100644 --- a/src/main/java/com/swyp8team2/auth/application/oauth/OAuthService.java +++ b/src/main/java/com/swyp8team2/auth/application/oauth/OAuthService.java @@ -3,6 +3,7 @@ import com.swyp8team2.auth.application.oauth.dto.KakaoAuthResponse; import com.swyp8team2.auth.application.oauth.dto.OAuthUserInfo; import com.swyp8team2.common.config.KakaoOAuthConfig; +import com.swyp8team2.common.exception.BadRequestException; import com.swyp8team2.common.exception.ErrorCode; import com.swyp8team2.common.exception.InternalServerException; import lombok.RequiredArgsConstructor; @@ -29,8 +30,8 @@ public OAuthUserInfo getUserInfo(String code, String redirectUri) { .fetchUserInfo(BEARER + kakaoAuthResponse.accessToken()) .toOAuthUserInfo(); } catch (Exception e) { - log.error("소셜 로그인 실패", e); - throw new InternalServerException(ErrorCode.SOCIAL_AUTHENTICATION_FAILED); + log.debug("소셜 로그인 실패 {}", e.getMessage()); + throw new BadRequestException(ErrorCode.SOCIAL_AUTHENTICATION_FAILED); } } diff --git a/src/main/java/com/swyp8team2/auth/domain/SocialAccount.java b/src/main/java/com/swyp8team2/auth/domain/SocialAccount.java index 23f784e7..3675e6c4 100644 --- a/src/main/java/com/swyp8team2/auth/domain/SocialAccount.java +++ b/src/main/java/com/swyp8team2/auth/domain/SocialAccount.java @@ -2,6 +2,7 @@ import com.swyp8team2.auth.application.oauth.dto.OAuthUserInfo; import com.swyp8team2.common.domain.BaseEntity; +import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; @@ -25,6 +26,7 @@ public class SocialAccount extends BaseEntity { private Long userId; + @Column(nullable = false, unique = true) private String socialId; @Enumerated(EnumType.STRING) diff --git a/src/main/java/com/swyp8team2/auth/presentation/AuthController.java b/src/main/java/com/swyp8team2/auth/presentation/AuthController.java index b14bd9c2..2bbeaa44 100644 --- a/src/main/java/com/swyp8team2/auth/presentation/AuthController.java +++ b/src/main/java/com/swyp8team2/auth/presentation/AuthController.java @@ -56,8 +56,8 @@ public ResponseEntity reissue( } @PostMapping("/guest/token") - public ResponseEntity guestLogin() { - String guestToken = authService.guestLogin(); + public ResponseEntity guestToken() { + String guestToken = authService.createGuestToken(); return ResponseEntity.ok(new GuestTokenResponse(guestToken)); } } diff --git a/src/main/java/com/swyp8team2/comment/application/CommentService.java b/src/main/java/com/swyp8team2/comment/application/CommentService.java index ad46dd31..bfe61db3 100644 --- a/src/main/java/com/swyp8team2/comment/application/CommentService.java +++ b/src/main/java/com/swyp8team2/comment/application/CommentService.java @@ -10,6 +10,8 @@ import com.swyp8team2.common.exception.ErrorCode; import com.swyp8team2.user.domain.User; import com.swyp8team2.user.domain.UserRepository; +import com.swyp8team2.vote.domain.Vote; +import com.swyp8team2.vote.domain.VoteRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.PageRequest; @@ -25,6 +27,7 @@ public class CommentService { private final UserRepository userRepository; private final CommentRepository commentRepository; + private final VoteRepository voteRepository; @Transactional public void createComment(Long postId, CreateCommentRequest request, UserInfo userInfo) { @@ -32,14 +35,19 @@ public void createComment(Long postId, CreateCommentRequest request, UserInfo us commentRepository.save(comment); } - public CursorBasePaginatedResponse findComments(Long postId, Long cursor, int size) { - Slice commentSlice = commentRepository.findByPostId(postId, cursor, PageRequest.of(0, size)); - return CursorBasePaginatedResponse.of(commentSlice.map(this::createCommentResponse)); + public CursorBasePaginatedResponse findComments(Long userId, Long postId, Long cursor, int size) { + Slice commentSlice = commentRepository.findByPostId(postId, cursor, PageRequest.ofSize(size)); + return CursorBasePaginatedResponse.of( + commentSlice.map(comment -> createCommentResponse(comment, userId)) + ); } - private CommentResponse createCommentResponse(Comment comment) { - User user = userRepository.findById(comment.getUserNo()) + private CommentResponse createCommentResponse(Comment comment, Long userId) { + User author = userRepository.findById(comment.getUserNo()) .orElseThrow(() -> new BadRequestException(ErrorCode.USER_NOT_FOUND)); - return CommentResponse.of(comment, user); + Long voteImageId = voteRepository.findByUserIdAndPostId(userId, comment.getPostId()) + .map(Vote::getPostImageId) + .orElse(null); + return CommentResponse.of(comment, author, author.getId().equals(userId), voteImageId); } } diff --git a/src/main/java/com/swyp8team2/comment/presentation/CommentController.java b/src/main/java/com/swyp8team2/comment/presentation/CommentController.java index 9f21cba5..b727fb2b 100644 --- a/src/main/java/com/swyp8team2/comment/presentation/CommentController.java +++ b/src/main/java/com/swyp8team2/comment/presentation/CommentController.java @@ -22,6 +22,7 @@ import java.time.LocalDateTime; import java.util.List; +import java.util.Optional; @RestController @RequiredArgsConstructor @@ -47,8 +48,8 @@ public ResponseEntity> selectCommen @RequestParam(value = "size", required = false, defaultValue = "10") @Min(1) int size, @AuthenticationPrincipal UserInfo userInfo ) { - CursorBasePaginatedResponse response = commentService.findComments(postId, cursor, size); - return ResponseEntity.ok(response); + Long userId = Optional.ofNullable(userInfo).map(UserInfo::userId).orElse(null); + return ResponseEntity.ok(commentService.findComments(userId, postId, cursor, size)); } @DeleteMapping("/{commentId}") diff --git a/src/main/java/com/swyp8team2/comment/presentation/dto/CommentResponse.java b/src/main/java/com/swyp8team2/comment/presentation/dto/CommentResponse.java index ea3c6f67..89848202 100644 --- a/src/main/java/com/swyp8team2/comment/presentation/dto/CommentResponse.java +++ b/src/main/java/com/swyp8team2/comment/presentation/dto/CommentResponse.java @@ -12,7 +12,8 @@ public record CommentResponse( String content, AuthorDto author, Long voteImageId, - LocalDateTime createdAt + LocalDateTime createdAt, + boolean isAuthor ) implements CursorDto { @Override @@ -21,12 +22,13 @@ public long getId() { return commentId; } - public static CommentResponse of(Comment comment, User user) { + public static CommentResponse of(Comment comment, User user, boolean isAuthor, Long voteImageId) { return new CommentResponse(comment.getId(), - comment.getContent(), - new AuthorDto(user.getId(), user.getNickname(), user.getProfileUrl()), - null, - comment.getCreatedAt() - ); + comment.getContent(), + new AuthorDto(user.getId(), user.getNickname(), user.getProfileUrl()), + voteImageId, + comment.getCreatedAt(), + isAuthor + ); } } diff --git a/src/main/java/com/swyp8team2/common/dev/DataInitializer.java b/src/main/java/com/swyp8team2/common/dev/DataInitializer.java index 9665d462..644eff7a 100644 --- a/src/main/java/com/swyp8team2/common/dev/DataInitializer.java +++ b/src/main/java/com/swyp8team2/common/dev/DataInitializer.java @@ -39,6 +39,9 @@ public class DataInitializer { @Transactional public void init() { + if (userRepository.count() > 0) { + return; + } List adjectives = nicknameAdjectiveRepository.findAll(); User testUser = userRepository.save(User.create("nickname", "https://t1.kakaocdn.net/account_images/default_profile.jpeg")); TokenPair tokenPair = jwtService.createToken(testUser.getId()); diff --git a/src/test/java/com/swyp8team2/auth/presentation/AuthControllerTest.java b/src/test/java/com/swyp8team2/auth/presentation/AuthControllerTest.java index 676f8231..4fb50574 100644 --- a/src/test/java/com/swyp8team2/auth/presentation/AuthControllerTest.java +++ b/src/test/java/com/swyp8team2/auth/presentation/AuthControllerTest.java @@ -150,10 +150,10 @@ void reissue_refreshTokenMismatched() throws Exception { @Test @DisplayName("게스트 토큰 발급") - void guestLogin() throws Exception { + void guestToken() throws Exception { //given String guestToken = "guestToken"; - given(authService.guestLogin()) + given(authService.createGuestToken()) .willReturn(guestToken); //when then diff --git a/src/test/java/com/swyp8team2/comment/application/CommentServiceTest.java b/src/test/java/com/swyp8team2/comment/application/CommentServiceTest.java index 09d5e374..bd5b9844 100644 --- a/src/test/java/com/swyp8team2/comment/application/CommentServiceTest.java +++ b/src/test/java/com/swyp8team2/comment/application/CommentServiceTest.java @@ -11,6 +11,7 @@ import com.swyp8team2.user.domain.Role; import com.swyp8team2.user.domain.User; import com.swyp8team2.user.domain.UserRepository; +import com.swyp8team2.vote.domain.VoteRepository; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -43,6 +44,9 @@ class CommentServiceTest { @InjectMocks private CommentService commentService; + @Mock + private VoteRepository voteRepository; + @Test @DisplayName("댓글 생성") void createComment() { @@ -74,11 +78,12 @@ void findComments() { // Mock 설정 given(commentRepository.findByPostId(eq(postId), eq(cursor), any(PageRequest.class))).willReturn(commentSlice); + given(voteRepository.findByUserIdAndPostId(eq(user.getId()), eq(postId))).willReturn(Optional.empty()); // 각 댓글마다 user_no=100L 이므로, findById(100L)만 호출됨 given(userRepository.findById(100L)).willReturn(Optional.of(user)); // when - CursorBasePaginatedResponse response = commentService.findComments(postId, cursor, size); + CursorBasePaginatedResponse response = commentService.findComments(user.getId(), postId, cursor, size); // then assertThat(response.data()).hasSize(2); @@ -113,7 +118,7 @@ void findComments_userNotFound() { given(userRepository.findById(100L)).willReturn(Optional.empty()); // when & then - assertThatThrownBy(() -> commentService.findComments(postId, cursor, size)) + assertThatThrownBy(() -> commentService.findComments(1L, postId, cursor, size)) .isInstanceOf(BadRequestException.class) .hasMessage((ErrorCode.USER_NOT_FOUND.getMessage())); } diff --git a/src/test/java/com/swyp8team2/comment/presentation/CommentControllerTest.java b/src/test/java/com/swyp8team2/comment/presentation/CommentControllerTest.java index ab316900..da30223a 100644 --- a/src/test/java/com/swyp8team2/comment/presentation/CommentControllerTest.java +++ b/src/test/java/com/swyp8team2/comment/presentation/CommentControllerTest.java @@ -72,14 +72,15 @@ void findComments() throws Exception { "댓글 내용", new AuthorDto(100L, "닉네임", "http://example.com/profile.png"), null, - LocalDateTime.now() + LocalDateTime.now(), + false ); List commentList = Collections.singletonList(commentResponse); CursorBasePaginatedResponse response = new CursorBasePaginatedResponse<>(null, false, commentList); - when(commentService.findComments(eq(postId), eq(cursor), eq(size))).thenReturn(response); + when(commentService.findComments(eq(null), eq(postId), eq(cursor), eq(size))).thenReturn(response); //when mockMvc.perform(get("/posts/{postId}/comments", "1")) @@ -125,11 +126,14 @@ void findComments() throws Exception { .description("작성자가 투표한 이미지 Id (투표 없을 시 null)"), fieldWithPath("data[].createdAt") .type(JsonFieldType.STRING) - .description("댓글 작성일") + .description("댓글 작성일"), + fieldWithPath("data[].isAuthor") + .type(JsonFieldType.BOOLEAN) + .description("작성자 여부") ) )); - verify(commentService, times(1)).findComments(eq(postId), eq(cursor), eq(size)); + verify(commentService, times(1)).findComments(eq(null), eq(postId), eq(cursor), eq(size)); } @Test