From d389c0ec4a59786f5594cc2ac53deea5cd019bd7 Mon Sep 17 00:00:00 2001 From: wlsh44 Date: Sat, 1 Mar 2025 03:05:33 +0900 Subject: [PATCH 1/5] =?UTF-8?q?chore:=20base62=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 +- .../swyp8team2/crypto/application/Base62.java | 34 -------------- .../post/domain/{State.java => Status.java} | 0 .../crypto/application/Base62Test.java | 45 ------------------- 4 files changed, 1 insertion(+), 80 deletions(-) delete mode 100644 src/main/java/com/swyp8team2/crypto/application/Base62.java rename src/main/java/com/swyp8team2/post/domain/{State.java => Status.java} (100%) delete mode 100644 src/test/java/com/swyp8team2/crypto/application/Base62Test.java diff --git a/build.gradle b/build.gradle index 23e36c35..42219f6a 100644 --- a/build.gradle +++ b/build.gradle @@ -46,7 +46,7 @@ dependencies { implementation 'com.google.code.gson:gson:2.8.6' // base64 - implementation 'commons-codec:commons-codec:1.15' + implementation 'io.seruco.encoding:base62:0.1.3' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' diff --git a/src/main/java/com/swyp8team2/crypto/application/Base62.java b/src/main/java/com/swyp8team2/crypto/application/Base62.java deleted file mode 100644 index e83ae4c0..00000000 --- a/src/main/java/com/swyp8team2/crypto/application/Base62.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.swyp8team2.crypto.application; - -import java.math.BigInteger; - -public class Base62 { - - private static final String BASE62_ALPHABET = - "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - private static final int BASE = 62; - - public static String encode(byte[] bytes) { - BigInteger value = new BigInteger(1, bytes); - StringBuilder encoded = new StringBuilder(); - - while (value.compareTo(BigInteger.ZERO) > 0) { - BigInteger[] divRem = value.divideAndRemainder(BigInteger.valueOf(BASE)); - value = divRem[0]; - encoded.insert(0, BASE62_ALPHABET.charAt(divRem[1].intValue())); - } - - return encoded.toString(); - } - - public static byte[] decode(String encoded) { - BigInteger value = BigInteger.ZERO; - - for (char c : encoded.toCharArray()) { - value = value.multiply(BigInteger.valueOf(BASE)) - .add(BigInteger.valueOf(BASE62_ALPHABET.indexOf(c))); - } - - return value.toByteArray(); - } -} diff --git a/src/main/java/com/swyp8team2/post/domain/State.java b/src/main/java/com/swyp8team2/post/domain/Status.java similarity index 100% rename from src/main/java/com/swyp8team2/post/domain/State.java rename to src/main/java/com/swyp8team2/post/domain/Status.java diff --git a/src/test/java/com/swyp8team2/crypto/application/Base62Test.java b/src/test/java/com/swyp8team2/crypto/application/Base62Test.java deleted file mode 100644 index bd0c180e..00000000 --- a/src/test/java/com/swyp8team2/crypto/application/Base62Test.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.swyp8team2.crypto.application; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import java.nio.charset.StandardCharsets; - -import static org.assertj.core.api.Assertions.*; - -class Base62Test { - - @Test - @DisplayName("인코딩 디코딩") - void encodingAndDecoding() throws Exception { - //given - String plainText = "Hello, World!"; - byte[] bytes = plainText.getBytes(StandardCharsets.UTF_8); - - //when - String encode = Base62.encode(bytes); - byte[] decode = Base62.decode(encode); - - String decodeText = new String(decode, StandardCharsets.UTF_8); - - //then - assertThat(decodeText).isEqualTo(plainText); - } - - @Test - @DisplayName("인코딩 디코딩 - 다른 문자열") - void encodingAndDecoding_differentText() throws Exception { - //given - String plainText = "Hello, World!"; - byte[] bytes = plainText.getBytes(StandardCharsets.UTF_8); - - //when - String encode = Base62.encode(bytes); - byte[] decode = Base62.decode("different"); - - String decodeText = new String(decode, StandardCharsets.UTF_8); - - //then - assertThat(decodeText).isNotEqualTo(plainText); - } -} From 984ae512da3b619bf802799ca8d2f9f9be13a7fc Mon Sep 17 00:00:00 2001 From: wlsh44 Date: Sat, 1 Mar 2025 03:05:42 +0900 Subject: [PATCH 2/5] =?UTF-8?q?chore:=20=EC=84=A4=EC=A0=95=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EA=B0=B1=EC=8B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server-config b/server-config index 68ef107f..764ff3f7 160000 --- a/server-config +++ b/server-config @@ -1 +1 @@ -Subproject commit 68ef107fc0155483439e02560e94159e61241b0b +Subproject commit 764ff3f77cbac588a188c20df89dcfe9f5010c26 From 7d6d27327aca0404fca7a179c323bfb04fa3da4c Mon Sep 17 00:00:00 2001 From: wlsh44 Date: Sat, 1 Mar 2025 03:06:54 +0900 Subject: [PATCH 3/5] =?UTF-8?q?refactor:=20guest-id=20=ED=97=A4=EB=8D=94?= =?UTF-8?q?=20guest-token=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../swyp8team2/auth/presentation/filter/GuestAuthFilter.java | 5 +---- .../com/swyp8team2/common/presentation/CustomHeader.java | 2 +- .../com/swyp8team2/crypto/application/CryptoService.java | 5 +++-- .../com/swyp8team2/vote/presentation/VoteController.java | 2 +- src/test/java/com/swyp8team2/support/RestDocsTest.java | 2 +- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/swyp8team2/auth/presentation/filter/GuestAuthFilter.java b/src/main/java/com/swyp8team2/auth/presentation/filter/GuestAuthFilter.java index 91de4d43..f1286b03 100644 --- a/src/main/java/com/swyp8team2/auth/presentation/filter/GuestAuthFilter.java +++ b/src/main/java/com/swyp8team2/auth/presentation/filter/GuestAuthFilter.java @@ -12,13 +12,10 @@ import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; import org.springframework.util.AntPathMatcher; import org.springframework.web.filter.OncePerRequestFilter; @@ -44,7 +41,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse if (!matcher.match("/posts/{postId}/votes/guest", request.getRequestURI())) { return; } - String token = request.getHeader(CustomHeader.GUEST_ID); + String token = request.getHeader(CustomHeader.GUEST_TOKEN); if (Objects.isNull(token)) { throw new BadRequestException(ErrorCode.INVALID_GUEST_HEADER); } diff --git a/src/main/java/com/swyp8team2/common/presentation/CustomHeader.java b/src/main/java/com/swyp8team2/common/presentation/CustomHeader.java index 903322ea..147385f9 100644 --- a/src/main/java/com/swyp8team2/common/presentation/CustomHeader.java +++ b/src/main/java/com/swyp8team2/common/presentation/CustomHeader.java @@ -2,7 +2,7 @@ public abstract class CustomHeader { - public static final String GUEST_ID = "Guest-Id"; + public static final String GUEST_TOKEN = "Guest-Token"; public static final String AUTHORIZATION_REFRESH = "Authorization-Refresh"; public static class CustomCookie{ diff --git a/src/main/java/com/swyp8team2/crypto/application/CryptoService.java b/src/main/java/com/swyp8team2/crypto/application/CryptoService.java index c3ecd7e0..9803147d 100644 --- a/src/main/java/com/swyp8team2/crypto/application/CryptoService.java +++ b/src/main/java/com/swyp8team2/crypto/application/CryptoService.java @@ -3,6 +3,7 @@ import com.swyp8team2.common.exception.BadRequestException; import com.swyp8team2.common.exception.ErrorCode; import com.swyp8team2.common.exception.InternalServerException; +import io.seruco.encoding.base62.Base62; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.security.crypto.encrypt.AesBytesEncryptor; @@ -18,7 +19,7 @@ public class CryptoService { public String encrypt(String data) { try { byte[] encrypt = encryptor.encrypt(data.getBytes(StandardCharsets.UTF_8)); - return Base62.encode(encrypt); + return new String(Base62.createInstance().encode(encrypt), StandardCharsets.UTF_8); } catch (Exception e) { log.debug("encrypt error {}", e.getMessage()); throw new BadRequestException(ErrorCode.INVALID_TOKEN); @@ -27,7 +28,7 @@ public String encrypt(String data) { public String decrypt(String encryptedData) { try { - byte[] decryptBytes = Base62.decode(encryptedData); + byte[] decryptBytes = Base62.createInstance().decode(encryptedData.getBytes(StandardCharsets.UTF_8)); byte[] decrypt = encryptor.decrypt(decryptBytes); return new String(decrypt, StandardCharsets.UTF_8); } catch (Exception e) { diff --git a/src/main/java/com/swyp8team2/vote/presentation/VoteController.java b/src/main/java/com/swyp8team2/vote/presentation/VoteController.java index 51d0caea..6f97d68f 100644 --- a/src/main/java/com/swyp8team2/vote/presentation/VoteController.java +++ b/src/main/java/com/swyp8team2/vote/presentation/VoteController.java @@ -56,7 +56,7 @@ public ResponseEntity changeVote( @PatchMapping("/guest") public ResponseEntity changeGuestVote( @PathVariable("postId") Long postId, - @RequestHeader(CustomHeader.GUEST_ID) String guestId, + @RequestHeader(CustomHeader.GUEST_TOKEN) String guestId, @Valid @RequestBody ChangeVoteRequest request ) { return ResponseEntity.ok().build(); diff --git a/src/test/java/com/swyp8team2/support/RestDocsTest.java b/src/test/java/com/swyp8team2/support/RestDocsTest.java index f8bd6e39..8e72a1e0 100644 --- a/src/test/java/com/swyp8team2/support/RestDocsTest.java +++ b/src/test/java/com/swyp8team2/support/RestDocsTest.java @@ -34,7 +34,7 @@ protected static HeaderDescriptor authorizationHeader() { } protected static HeaderDescriptor guestHeader() { - return headerWithName(CustomHeader.GUEST_ID).description("게스트 Id (UUID 형식)"); + return headerWithName(CustomHeader.GUEST_TOKEN).description("게스트 토큰"); } protected static ParameterDescriptor[] cursorQueryParams() { From 3977fa9146f2a1ef2618b985cb39f553b87cb5e7 Mon Sep 17 00:00:00 2001 From: wlsh44 Date: Sat, 1 Mar 2025 03:09:27 +0900 Subject: [PATCH 4/5] =?UTF-8?q?refactor:=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../post/application/PostService.java | 5 ++-- .../java/com/swyp8team2/post/domain/Post.java | 14 +++++------ .../com/swyp8team2/post/domain/Status.java | 2 +- .../post/presentation/PostController.java | 2 +- .../presentation/dto/CreatePostResponse.java | 2 +- .../post/presentation/dto/PostResponse.java | 3 +++ .../crypto/application/CryptoServiceTest.java | 5 ++-- .../post/application/PostServiceTest.java | 23 +++++++++++++++---- .../com/swyp8team2/post/domain/PostTest.java | 10 ++++---- .../post/presentation/PostControllerTest.java | 14 ++++++++--- .../com/swyp8team2/support/WebUnitTest.java | 4 ++++ .../vote/application/VoteServiceTest.java | 6 ++--- .../vote/presentation/VoteControllerTest.java | 9 ++------ 13 files changed, 63 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/swyp8team2/post/application/PostService.java b/src/main/java/com/swyp8team2/post/application/PostService.java index 1e97d25d..72ff11fa 100644 --- a/src/main/java/com/swyp8team2/post/application/PostService.java +++ b/src/main/java/com/swyp8team2/post/application/PostService.java @@ -12,6 +12,7 @@ import com.swyp8team2.post.domain.PostImage; import com.swyp8team2.post.domain.PostRepository; import com.swyp8team2.post.presentation.dto.CreatePostRequest; +import com.swyp8team2.post.presentation.dto.CreatePostResponse; import com.swyp8team2.post.presentation.dto.PostResponse; import com.swyp8team2.post.presentation.dto.PostImageVoteStatusResponse; import com.swyp8team2.post.presentation.dto.SimplePostResponse; @@ -57,12 +58,12 @@ public PostService( } @Transactional - public Long create(Long userId, CreatePostRequest request) { + public CreatePostResponse create(Long userId, CreatePostRequest request) { List postImages = createPostImages(request); Post post = Post.create(userId, request.description(), postImages); Post save = postRepository.save(post); save.setShareUrl(shareUrlCryptoService.encrypt(String.valueOf(save.getId()))); - return save.getId(); + return new CreatePostResponse(save.getId(), save.getShareUrl()); } private List createPostImages(CreatePostRequest request) { diff --git a/src/main/java/com/swyp8team2/post/domain/Post.java b/src/main/java/com/swyp8team2/post/domain/Post.java index 5d8d2bb2..6105b2b9 100644 --- a/src/main/java/com/swyp8team2/post/domain/Post.java +++ b/src/main/java/com/swyp8team2/post/domain/Post.java @@ -37,20 +37,20 @@ public class Post extends BaseEntity { private Long userId; @Enumerated(EnumType.STRING) - private State state; + private Status status; @OneToMany(mappedBy = "post", orphanRemoval = true, cascade = CascadeType.ALL) private List images = new ArrayList<>(); private String shareUrl; - public Post(Long id, Long userId, String description, State state, List images, String shareUrl) { + public Post(Long id, Long userId, String description, Status status, List images, String shareUrl) { validateDescription(description); validatePostImages(images); this.id = id; this.description = description; this.userId = userId; - this.state = state; + this.status = status; this.images = images; images.forEach(image -> image.setPost(this)); this.shareUrl = shareUrl; @@ -69,7 +69,7 @@ private void validateDescription(String description) { } public static Post create(Long userId, String description, List images) { - return new Post(null, userId, description, State.PROGRESS, images, null); + return new Post(null, userId, description, Status.PROGRESS, images, null); } public PostImage getBestPickedImage() { @@ -96,10 +96,10 @@ public void cancelVote(Long imageId) { public void close(Long userId) { validateOwner(userId); - if (state == State.CLOSED) { + if (status == Status.CLOSED) { throw new BadRequestException(ErrorCode.POST_ALREADY_CLOSED); } - this.state = State.CLOSED; + this.status = Status.CLOSED; } public void validateOwner(Long userId) { @@ -109,7 +109,7 @@ public void validateOwner(Long userId) { } public void validateProgress() { - if (!this.state.equals(State.PROGRESS)) { + if (!this.status.equals(Status.PROGRESS)) { throw new BadRequestException(ErrorCode.POST_ALREADY_CLOSED); } } diff --git a/src/main/java/com/swyp8team2/post/domain/Status.java b/src/main/java/com/swyp8team2/post/domain/Status.java index cfdafbdd..bda22f18 100644 --- a/src/main/java/com/swyp8team2/post/domain/Status.java +++ b/src/main/java/com/swyp8team2/post/domain/Status.java @@ -1,5 +1,5 @@ package com.swyp8team2.post.domain; -public enum State { +public enum Status { PROGRESS, CLOSED } diff --git a/src/main/java/com/swyp8team2/post/presentation/PostController.java b/src/main/java/com/swyp8team2/post/presentation/PostController.java index c07264d7..52c1cb81 100644 --- a/src/main/java/com/swyp8team2/post/presentation/PostController.java +++ b/src/main/java/com/swyp8team2/post/presentation/PostController.java @@ -38,7 +38,7 @@ public ResponseEntity createPost( @AuthenticationPrincipal UserInfo userInfo ) { - return ResponseEntity.ok(new CreatePostResponse(postService.create(userInfo.userId(), request))); + return ResponseEntity.ok(postService.create(userInfo.userId(), request)); } @GetMapping("/{postId}") diff --git a/src/main/java/com/swyp8team2/post/presentation/dto/CreatePostResponse.java b/src/main/java/com/swyp8team2/post/presentation/dto/CreatePostResponse.java index f6629c64..172d42b3 100644 --- a/src/main/java/com/swyp8team2/post/presentation/dto/CreatePostResponse.java +++ b/src/main/java/com/swyp8team2/post/presentation/dto/CreatePostResponse.java @@ -1,4 +1,4 @@ package com.swyp8team2.post.presentation.dto; -public record CreatePostResponse(Long postId) { +public record CreatePostResponse(Long postId, String shareUrl) { } diff --git a/src/main/java/com/swyp8team2/post/presentation/dto/PostResponse.java b/src/main/java/com/swyp8team2/post/presentation/dto/PostResponse.java index 6f082117..b41421eb 100644 --- a/src/main/java/com/swyp8team2/post/presentation/dto/PostResponse.java +++ b/src/main/java/com/swyp8team2/post/presentation/dto/PostResponse.java @@ -1,6 +1,7 @@ package com.swyp8team2.post.presentation.dto; import com.swyp8team2.post.domain.Post; +import com.swyp8team2.post.domain.Status; import com.swyp8team2.user.domain.User; import java.time.LocalDateTime; @@ -13,6 +14,7 @@ public record PostResponse( List images, String shareUrl, boolean isAuthor, + Status status, LocalDateTime createdAt ) { public static PostResponse of(Post post, User user, List images, boolean isAuthor) { @@ -23,6 +25,7 @@ public static PostResponse of(Post post, User user, List imag images, post.getShareUrl(), isAuthor, + post.getStatus(), post.getCreatedAt() ); } diff --git a/src/test/java/com/swyp8team2/crypto/application/CryptoServiceTest.java b/src/test/java/com/swyp8team2/crypto/application/CryptoServiceTest.java index 801b4151..90e26e0d 100644 --- a/src/test/java/com/swyp8team2/crypto/application/CryptoServiceTest.java +++ b/src/test/java/com/swyp8team2/crypto/application/CryptoServiceTest.java @@ -17,17 +17,18 @@ class CryptoServiceTest { @BeforeEach void setUp() throws Exception { - cryptoService = new CryptoService(new AesBytesEncryptor("test", "123456")); + cryptoService = new CryptoService(new AesBytesEncryptor("asdfd", "1541235432")); } @Test @DisplayName("암호화 및 복호화") void encryptAndDecrypt() { // given - String plainText = "Hello, World!"; + String plainText = "15411"; // when String encryptedText = cryptoService.encrypt(plainText); + System.out.println("encryptedText = " + encryptedText); String decryptedText = cryptoService.decrypt(encryptedText); // then diff --git a/src/test/java/com/swyp8team2/post/application/PostServiceTest.java b/src/test/java/com/swyp8team2/post/application/PostServiceTest.java index dde9b629..4d06c2f3 100644 --- a/src/test/java/com/swyp8team2/post/application/PostServiceTest.java +++ b/src/test/java/com/swyp8team2/post/application/PostServiceTest.java @@ -1,14 +1,17 @@ package com.swyp8team2.post.application; +import com.swyp8team2.common.annotation.ShareUrlCryptoService; import com.swyp8team2.common.exception.BadRequestException; import com.swyp8team2.common.exception.ErrorCode; +import com.swyp8team2.crypto.application.CryptoService; import com.swyp8team2.image.domain.ImageFile; import com.swyp8team2.image.domain.ImageFileRepository; import com.swyp8team2.post.domain.Post; import com.swyp8team2.post.domain.PostImage; import com.swyp8team2.post.domain.PostRepository; -import com.swyp8team2.post.domain.State; +import com.swyp8team2.post.domain.Status; import com.swyp8team2.post.presentation.dto.CreatePostRequest; +import com.swyp8team2.post.presentation.dto.CreatePostResponse; import com.swyp8team2.post.presentation.dto.PostResponse; import com.swyp8team2.post.presentation.dto.PostImageRequestDto; import com.swyp8team2.post.presentation.dto.PostImageResponse; @@ -21,6 +24,8 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.springframework.test.context.bean.override.mockito.MockitoSpyBean; import java.util.ArrayList; import java.util.List; @@ -31,6 +36,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; class PostServiceTest extends IntegrationTest { @@ -52,6 +59,10 @@ class PostServiceTest extends IntegrationTest { @Autowired VoteService voteService; + @MockitoBean + @ShareUrlCryptoService + CryptoService shareUrlCryptoService; + @Test @DisplayName("게시글 작성") void create() throws Exception { @@ -61,16 +72,20 @@ void create() throws Exception { new PostImageRequestDto(1L), new PostImageRequestDto(2L) )); + String shareUrl = "shareUrl"; + given(shareUrlCryptoService.encrypt(any())) + .willReturn(shareUrl); //when - Long postId = postService.create(userId, request); + CreatePostResponse response = postService.create(userId, request); //then - Post post = postRepository.findById(postId).get(); + Post post = postRepository.findById(response.postId()).get(); List images = post.getImages(); assertAll( () -> assertThat(post.getDescription()).isEqualTo("description"), () -> assertThat(post.getUserId()).isEqualTo(userId), + () -> assertThat(post.getShareUrl()).isEqualTo(shareUrl), () -> assertThat(images).hasSize(2), () -> assertThat(images.get(0).getImageFileId()).isEqualTo(1L), () -> assertThat(images.get(0).getName()).isEqualTo("뽀또 A"), @@ -253,7 +268,7 @@ void close() throws Exception { //then postRepository.findById(post.getId()).get(); - assertThat(post.getState()).isEqualTo(State.CLOSED); + assertThat(post.getStatus()).isEqualTo(Status.CLOSED); } @Test diff --git a/src/test/java/com/swyp8team2/post/domain/PostTest.java b/src/test/java/com/swyp8team2/post/domain/PostTest.java index c0908cf2..a41a2609 100644 --- a/src/test/java/com/swyp8team2/post/domain/PostTest.java +++ b/src/test/java/com/swyp8team2/post/domain/PostTest.java @@ -32,7 +32,7 @@ void create() throws Exception { assertAll( () -> assertThat(post.getUserId()).isEqualTo(userId), () -> assertThat(post.getDescription()).isEqualTo(description), - () -> assertThat(post.getState()).isEqualTo(State.PROGRESS), + () -> assertThat(post.getStatus()).isEqualTo(Status.PROGRESS), () -> assertThat(images).hasSize(2), () -> assertThat(images.get(0).getName()).isEqualTo("뽀또A"), () -> assertThat(images.get(0).getImageFileId()).isEqualTo(1L), @@ -82,13 +82,13 @@ void close() throws Exception { PostImage.create("뽀또A", 1L), PostImage.create("뽀또B", 2L) ); - Post post = new Post(null, userId, "description", State.PROGRESS, postImages, "shareUrl"); + Post post = new Post(null, userId, "description", Status.PROGRESS, postImages, "shareUrl"); //when post.close(userId); //then - assertThat(post.getState()).isEqualTo(State.CLOSED); + assertThat(post.getStatus()).isEqualTo(Status.CLOSED); } @Test @@ -100,7 +100,7 @@ void close_alreadyClosed() throws Exception { PostImage.create("뽀또A", 1L), PostImage.create("뽀또B", 2L) ); - Post post = new Post(null, userId, "description", State.CLOSED, postImages, "shareUrl"); + Post post = new Post(null, userId, "description", Status.CLOSED, postImages, "shareUrl"); //when then assertThatThrownBy(() -> post.close(userId)) @@ -117,7 +117,7 @@ void close_notPostAuthor() throws Exception { PostImage.create("뽀또A", 1L), PostImage.create("뽀또B", 2L) ); - Post post = new Post(null, userId, "description", State.PROGRESS, postImages, "shareUrl"); + Post post = new Post(null, userId, "description", Status.PROGRESS, postImages, "shareUrl"); //when then assertThatThrownBy(() -> post.close(2L)) diff --git a/src/test/java/com/swyp8team2/post/presentation/PostControllerTest.java b/src/test/java/com/swyp8team2/post/presentation/PostControllerTest.java index 9d70892f..aff536f4 100644 --- a/src/test/java/com/swyp8team2/post/presentation/PostControllerTest.java +++ b/src/test/java/com/swyp8team2/post/presentation/PostControllerTest.java @@ -1,6 +1,7 @@ package com.swyp8team2.post.presentation; import com.swyp8team2.common.dto.CursorBasePaginatedResponse; +import com.swyp8team2.post.domain.Status; import com.swyp8team2.post.presentation.dto.AuthorDto; import com.swyp8team2.post.presentation.dto.CreatePostRequest; import com.swyp8team2.post.presentation.dto.CreatePostResponse; @@ -49,9 +50,9 @@ void createPost() throws Exception { "제목", List.of(new PostImageRequestDto(1L), new PostImageRequestDto(2L)) ); + CreatePostResponse response = new CreatePostResponse(1L, "shareUrl"); given(postService.create(any(), any())) - .willReturn(1L); - CreatePostResponse response = new CreatePostResponse(1L); + .willReturn(response); //when then mockMvc.perform(post("/posts") @@ -78,7 +79,10 @@ void createPost() throws Exception { responseFields( fieldWithPath("postId") .type(JsonFieldType.NUMBER) - .description("게시글 Id") + .description("게시글 Id"), + fieldWithPath("shareUrl") + .type(JsonFieldType.STRING) + .description("게시글 공유 url") ) )); } @@ -102,6 +106,7 @@ void findPost() throws Exception { ), "https://photopic.site/shareurl", true, + Status.PROGRESS, LocalDateTime.of(2025, 2, 13, 12, 0) ); given(postService.findById(any(), any())) @@ -130,6 +135,7 @@ void findPost() throws Exception { fieldWithPath("images[].voted").type(JsonFieldType.BOOLEAN).description("투표 여부"), fieldWithPath("shareUrl").type(JsonFieldType.STRING).description("게시글 공유 URL"), fieldWithPath("createdAt").type(JsonFieldType.STRING).description("게시글 생성 시간"), + fieldWithPath("status").type(JsonFieldType.STRING).description("게시글 마감 여부 (PROGRESS, CLOSED)"), fieldWithPath("isAuthor").type(JsonFieldType.BOOLEAN).description("게시글 작성자 여부") ) )); @@ -154,6 +160,7 @@ void findPost_shareUrl() throws Exception { ), "https://photopic.site/shareurl", true, + Status.PROGRESS, LocalDateTime.of(2025, 2, 13, 12, 0) ); given(postService.findByShareUrl(any(), any())) @@ -182,6 +189,7 @@ void findPost_shareUrl() throws Exception { fieldWithPath("images[].voted").type(JsonFieldType.BOOLEAN).description("투표 여부"), fieldWithPath("shareUrl").type(JsonFieldType.STRING).description("게시글 공유 URL"), fieldWithPath("createdAt").type(JsonFieldType.STRING).description("게시글 생성 시간"), + fieldWithPath("status").type(JsonFieldType.STRING).description("게시글 마감 여부 (PROGRESS, CLOSED)"), fieldWithPath("isAuthor").type(JsonFieldType.BOOLEAN).description("게시글 작성자 여부") ) )); diff --git a/src/test/java/com/swyp8team2/support/WebUnitTest.java b/src/test/java/com/swyp8team2/support/WebUnitTest.java index ebd1b17c..aa1f1395 100644 --- a/src/test/java/com/swyp8team2/support/WebUnitTest.java +++ b/src/test/java/com/swyp8team2/support/WebUnitTest.java @@ -4,6 +4,7 @@ import com.swyp8team2.auth.application.AuthService; import com.swyp8team2.auth.presentation.RefreshTokenCookieGenerator; import com.swyp8team2.comment.application.CommentService; +import com.swyp8team2.common.exception.DiscordMessageSender; import com.swyp8team2.image.application.ImageService; import com.swyp8team2.post.application.PostService; import com.swyp8team2.user.application.UserService; @@ -44,4 +45,7 @@ public abstract class WebUnitTest { @MockitoBean protected UserService userService; + + @MockitoBean + protected DiscordMessageSender discordMessageSender; } diff --git a/src/test/java/com/swyp8team2/vote/application/VoteServiceTest.java b/src/test/java/com/swyp8team2/vote/application/VoteServiceTest.java index adf54852..fff0993c 100644 --- a/src/test/java/com/swyp8team2/vote/application/VoteServiceTest.java +++ b/src/test/java/com/swyp8team2/vote/application/VoteServiceTest.java @@ -7,7 +7,7 @@ import com.swyp8team2.post.domain.Post; import com.swyp8team2.post.domain.PostImage; import com.swyp8team2.post.domain.PostRepository; -import com.swyp8team2.post.domain.State; +import com.swyp8team2.post.domain.Status; import com.swyp8team2.support.IntegrationTest; import com.swyp8team2.user.domain.User; import com.swyp8team2.user.domain.UserRepository; @@ -102,7 +102,7 @@ void vote_alreadyClosed() { null, user.getId(), "description", - State.CLOSED, + Status.CLOSED, List.of( PostImage.create("뽀또A", imageFile1.getId()), PostImage.create("뽀또B", imageFile2.getId()) @@ -178,7 +178,7 @@ void guestVote_alreadyClosed() { null, user.getId(), "description", - State.CLOSED, + Status.CLOSED, List.of( PostImage.create("뽀또A", imageFile1.getId()), PostImage.create("뽀또B", imageFile2.getId()) diff --git a/src/test/java/com/swyp8team2/vote/presentation/VoteControllerTest.java b/src/test/java/com/swyp8team2/vote/presentation/VoteControllerTest.java index 129d98d2..c1c9d502 100644 --- a/src/test/java/com/swyp8team2/vote/presentation/VoteControllerTest.java +++ b/src/test/java/com/swyp8team2/vote/presentation/VoteControllerTest.java @@ -11,13 +11,8 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.restdocs.payload.JsonFieldType; -import org.springframework.security.test.context.support.WithAnonymousUser; - -import java.util.UUID; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders; @@ -69,7 +64,7 @@ void guestVote() throws Exception { mockMvc.perform(post("/posts/{postId}/votes/guest", "1") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request)) - .header(CustomHeader.GUEST_ID, "guestToken")) + .header(CustomHeader.GUEST_TOKEN, "guestToken")) .andExpect(status().isOk()) .andDo(restDocs.document( requestHeaders(guestHeader()), @@ -122,7 +117,7 @@ void guestChangeVote() throws Exception { mockMvc.perform(patch("/posts/{postId}/votes/guest", "1") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request)) - .header(CustomHeader.GUEST_ID, "guestToken")) + .header(CustomHeader.GUEST_TOKEN, "guestToken")) .andExpect(status().isOk()) .andDo(restDocs.document( requestHeaders(guestHeader()), From 7910fdba3f1f26b8df19e6fc6323c1e17b16d1fa Mon Sep 17 00:00:00 2001 From: wlsh44 Date: Sat, 1 Mar 2025 03:09:50 +0900 Subject: [PATCH 5/5] =?UTF-8?q?fix:=20webp=20=EC=9D=B4=EB=AF=B8=EC=A7=80?= =?UTF-8?q?=20=EC=97=85=EB=A1=9C=EB=93=9C=20=EC=B6=94=EA=B0=80=20(?= =?UTF-8?q?=EB=A6=AC=EC=82=AC=EC=9D=B4=EC=A6=88=20=EC=A0=9C=EC=99=B8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 ++ .../annotation/ShareUrlCryptoService.java | 2 +- .../swyp8team2/common/dev/DataInitConfig.java | 2 +- .../common/exception/ErrorCode.java | 1 + .../image/application/R2Storage.java | 22 +++++++++++++++++-- 5 files changed, 25 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 42219f6a..f036af26 100644 --- a/build.gradle +++ b/build.gradle @@ -41,6 +41,8 @@ dependencies { // image implementation 'software.amazon.awssdk:s3:2.30.18' implementation 'org.imgscalr:imgscalr-lib:4.2' + implementation 'com.sksamuel.scrimage:scrimage-core:4.3.0' + implementation 'com.sksamuel.scrimage:scrimage-webp:4.3.0' // gson implementation 'com.google.code.gson:gson:2.8.6' diff --git a/src/main/java/com/swyp8team2/common/annotation/ShareUrlCryptoService.java b/src/main/java/com/swyp8team2/common/annotation/ShareUrlCryptoService.java index 2ea4c9f4..82be1bc7 100644 --- a/src/main/java/com/swyp8team2/common/annotation/ShareUrlCryptoService.java +++ b/src/main/java/com/swyp8team2/common/annotation/ShareUrlCryptoService.java @@ -9,7 +9,7 @@ @Qualifier(ShareUrlCryptoService.QUALIFIER) @Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.PARAMETER, ElementType.METHOD}) +@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD}) public @interface ShareUrlCryptoService { String QUALIFIER = "shareUrlCryptoService"; diff --git a/src/main/java/com/swyp8team2/common/dev/DataInitConfig.java b/src/main/java/com/swyp8team2/common/dev/DataInitConfig.java index 561a4c99..59bd22d8 100644 --- a/src/main/java/com/swyp8team2/common/dev/DataInitConfig.java +++ b/src/main/java/com/swyp8team2/common/dev/DataInitConfig.java @@ -12,7 +12,7 @@ public class DataInitConfig { private final DataInitializer dataInitializer; - @PostConstruct +// @PostConstruct public void init() { dataInitializer.init(); } diff --git a/src/main/java/com/swyp8team2/common/exception/ErrorCode.java b/src/main/java/com/swyp8team2/common/exception/ErrorCode.java index e717db55..6ee4f4b3 100644 --- a/src/main/java/com/swyp8team2/common/exception/ErrorCode.java +++ b/src/main/java/com/swyp8team2/common/exception/ErrorCode.java @@ -21,6 +21,7 @@ public enum ErrorCode { NOT_POST_AUTHOR("게시글 작성자가 아님"), POST_ALREADY_CLOSED("이미 마감된 게시글"), INVALID_GUEST_HEADER("잘못된 게스트 토큰 헤더"), + FILE_NAME_TOO_LONG("파일 이름이 너무 김"), //401 EXPIRED_TOKEN("토큰 만료"), diff --git a/src/main/java/com/swyp8team2/image/application/R2Storage.java b/src/main/java/com/swyp8team2/image/application/R2Storage.java index f735799e..8222f2b0 100644 --- a/src/main/java/com/swyp8team2/image/application/R2Storage.java +++ b/src/main/java/com/swyp8team2/image/application/R2Storage.java @@ -1,5 +1,7 @@ package com.swyp8team2.image.application; +import com.sksamuel.scrimage.ImmutableImage; +import com.swyp8team2.common.exception.BadRequestException; import com.swyp8team2.common.exception.ErrorCode; import com.swyp8team2.common.exception.ServiceUnavailableException; import com.swyp8team2.common.util.DateTime; @@ -13,6 +15,7 @@ import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.PutObjectRequest; +import software.amazon.awssdk.services.s3.model.PutObjectResponse; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; @@ -22,6 +25,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; @Component @Slf4j @@ -52,6 +56,9 @@ public List uploadImageFile(MultipartFile... files) { for (int i = 0; i < files.length; i++) { MultipartFile file = files[i]; String originFileName = file.getOriginalFilename(); + if (originFileName.length() > 100) { + throw new BadRequestException(ErrorCode.FILE_NAME_TOO_LONG); + } String realFileName = getRealFileName(originFileName, filePath, i); File tempFile = File.createTempFile("upload_", "_" + originFileName); file.transferTo(tempFile); @@ -81,7 +88,18 @@ public List uploadImageFile(MultipartFile... files) { private String resizeImage(File file, String realFileName, int targetHeight) { try { - BufferedImage srcImage = ImageIO.read(file); + String ext = Optional.of(realFileName) + .filter(name -> name.contains(".")) + .map(name -> name.substring(name.lastIndexOf('.') + 1)) + .orElseThrow(() -> new BadRequestException(ErrorCode.MISSING_FILE_EXTENSION)) + .toLowerCase(); + + BufferedImage srcImage; + if ("webp".equals(ext)) { + srcImage = ImmutableImage.loader().fromFile(file).awt(); + } else { + srcImage = ImageIO.read(file); + } BufferedImage resizedImage = highQualityResize(srcImage, targetHeight); int splitIndex = realFileName.lastIndexOf("/") + 1; @@ -120,7 +138,7 @@ private File s3PutObject(File file, String realFileName, String imageType) { .key(realFileName) .build(); - s3Client.putObject(objectRequest, RequestBody.fromFile(file)); + PutObjectResponse putObjectResponse = s3Client.putObject(objectRequest, RequestBody.fromFile(file)); return file; }