From 7c22f51540873463d97504f6686081636aee3893 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EA=B6=8C=EC=A3=BC=EC=84=B1?=
<99165624+JoosungKwon@users.noreply.github.com>
Date: Fri, 11 Aug 2023 18:06:01 +0900
Subject: [PATCH 1/9] =?UTF-8?q?README.md=EC=97=90=20Architecture=20?=
=?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index df6f76ca..51520355 100644
--- a/README.md
+++ b/README.md
@@ -46,15 +46,24 @@
+
+## Architecture ๐ฐ
+
+
+![image](https://github.com/Clover-Habiters/backend/assets/99165624/c1fa8ad2-546e-46e9-b6c1-c912d0ee5873)
+
+
## API Spec ๐ฝ
### [Habiters API ๋ฌธ์](https://api.habiters.store/docs/index.html)
-
+
+
## ERD ๐พ
-
+
+
## ํ๋ก์ ํธ ์คํ ๋ฐฉ๋ฒ โ
ํ๋ก์ ํธ ์คํ ์ ์๋ ํญ๋ชฉ์ ํ์ธํด์ฃผ์ธ์
From 155c6a1f39bf6995c692f9bdae43e4572bd2be92 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EA=B6=8C=EC=A3=BC=EC=84=B1?=
<99165624+JoosungKwon@users.noreply.github.com>
Date: Mon, 14 Aug 2023 18:58:13 +0900
Subject: [PATCH 2/9] =?UTF-8?q?CI/CD=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20?=
=?UTF-8?q?=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/README.md b/README.md
index 51520355..7f83305f 100644
--- a/README.md
+++ b/README.md
@@ -53,6 +53,14 @@
![image](https://github.com/Clover-Habiters/backend/assets/99165624/c1fa8ad2-546e-46e9-b6c1-c912d0ee5873)
+
+## CI/CD ๐
+
+
+![image](https://github.com/Clover-Habiters/backend/assets/99165624/159c8032-5460-4b1f-a0a6-3161ad0ae1e8)
+
+
+
## API Spec ๐ฝ
### [Habiters API ๋ฌธ์](https://api.habiters.store/docs/index.html)
From e7cc9e1990e4ec5be39232139e19bc9abb49de8a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EA=B6=8C=EC=A3=BC=EC=84=B1?=
<99165624+JoosungKwon@users.noreply.github.com>
Date: Mon, 14 Aug 2023 19:00:48 +0900
Subject: [PATCH 3/9] =?UTF-8?q?API=20=EB=AC=B8=EC=84=9C=20=EC=8D=B8?=
=?UTF-8?q?=EB=84=A4=EC=9D=BC=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/README.md b/README.md
index 7f83305f..8a135f7d 100644
--- a/README.md
+++ b/README.md
@@ -64,6 +64,9 @@
## API Spec ๐ฝ
### [Habiters API ๋ฌธ์](https://api.habiters.store/docs/index.html)
+
+
+![image](https://github.com/Clover-Habiters/backend/assets/99165624/4c31c232-e689-41dc-9470-1faa45b0c93a)
From c6ec60f3734d9925d6e61f89d9f294471f7b5e25 Mon Sep 17 00:00:00 2001
From: gombasan
Date: Mon, 14 Aug 2023 23:42:20 +0900
Subject: [PATCH 4/9] =?UTF-8?q?feat=20:=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20?=
=?UTF-8?q?=EC=97=85=EB=A1=9C=EB=93=9C=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?=
=?UTF-8?q?=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- NCP ๋ด์ ObjectStorage ๋ก ์ด๋ฏธ์ง๋ฅผ ์ ์ฅํ ํ์ ์ด๋ฏธ์ง์ url ์ ๋ฐํํ๋๋ก ์ค์ ํ์์ต๋๋ค.
- ์ด๋ฏธ์ง๋ฅผ ์์ ๊ฒฝ๋ก์ธ tmp ํ์ผ์ ์ ์ฅํด ๋ ํ์ ์คํ ๋ฆฌ์ง ์๋ฒ์ ์
๋ก๋ ํ ์ญ์ ํฉ๋๋ค.
---
.../infra/storage/ObjectStorageService.java | 68 -------------------
.../storage/api/ObjectStorageController.java | 29 ++++++++
.../storage/service/ObjectStorageService.java | 40 +++++++++++
.../habbittracker/global/util/ImageUtil.java | 40 +++++++++++
4 files changed, 109 insertions(+), 68 deletions(-)
delete mode 100644 src/main/java/com/clover/habbittracker/global/infra/storage/ObjectStorageService.java
create mode 100644 src/main/java/com/clover/habbittracker/global/infra/storage/api/ObjectStorageController.java
create mode 100644 src/main/java/com/clover/habbittracker/global/infra/storage/service/ObjectStorageService.java
create mode 100644 src/main/java/com/clover/habbittracker/global/util/ImageUtil.java
diff --git a/src/main/java/com/clover/habbittracker/global/infra/storage/ObjectStorageService.java b/src/main/java/com/clover/habbittracker/global/infra/storage/ObjectStorageService.java
deleted file mode 100644
index 44645c5b..00000000
--- a/src/main/java/com/clover/habbittracker/global/infra/storage/ObjectStorageService.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.clover.habbittracker.global.infra.storage;
-
-import java.io.File;
-import java.util.UUID;
-
-import org.springframework.stereotype.Service;
-import org.springframework.web.multipart.MultipartFile;
-
-import com.amazonaws.services.s3.AmazonS3;
-import com.amazonaws.services.s3.model.CannedAccessControlList;
-import com.amazonaws.services.s3.model.PutObjectRequest;
-
-import lombok.extern.slf4j.Slf4j;
-
-/* 2023/05/30 ํ๋กํ ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ์ง ์๊ธฐ๋๋ฌธ์ ํด๋น ์๋น์ค๋ ๋ฏธ์ฌ์ฉ
- ** ์ถํ ๋ค์ ์ฌ์ฉ ํ ์ ์์ **
- */
-@Service
-@Slf4j
-public class ObjectStorageService {
-
- private final AmazonS3 objectStorage;
- private final String imgPath;
-
- public ObjectStorageService(AmazonS3 objectStorage) {
- this.objectStorage = objectStorage;
- this.imgPath = System.getProperty("user.dir") + "/tmp";
- }
-
- public String profileImgSave(MultipartFile file) {
- if (file == null)
- return null;
-
- String buketName = "user-profile-image";
- String fileName = tempFileSave(file);
- PutObjectRequest request = new PutObjectRequest(buketName, fileName, new File(imgPath, fileName));
- request.withCannedAcl(CannedAccessControlList.PublicRead);
- objectStorage.putObject(request);
-
- if (!tempFileDelete(fileName)) {
- log.error("Failed to delete file. The administrator should check it out");
- }
-
- return objectStorage.getUrl(buketName, fileName).toString();
- }
-
- protected boolean tempFileDelete(String fileName) {
- File tempFile = new File(imgPath, fileName);
- if (tempFile.exists()) {
- return tempFile.delete();
- }
- return false;
- }
-
- protected String tempFileSave(MultipartFile file) {
- String uuid = UUID.randomUUID().toString().substring(0, 8);
-
- String imgName = uuid + "_" + file.getOriginalFilename();
- File imgFile = new File(imgPath, imgName);
- try {
- file.transferTo(imgFile);
- } catch (Exception e) {
- System.out.println(e.getMessage());
- }
-
- return imgName;
- }
-}
diff --git a/src/main/java/com/clover/habbittracker/global/infra/storage/api/ObjectStorageController.java b/src/main/java/com/clover/habbittracker/global/infra/storage/api/ObjectStorageController.java
new file mode 100644
index 00000000..c5e95152
--- /dev/null
+++ b/src/main/java/com/clover/habbittracker/global/infra/storage/api/ObjectStorageController.java
@@ -0,0 +1,29 @@
+package com.clover.habbittracker.global.infra.storage.api;
+
+import static org.springframework.http.MediaType.*;
+
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import com.clover.habbittracker.global.base.dto.ApiResponse;
+import com.clover.habbittracker.global.infra.storage.service.ObjectStorageService;
+
+import lombok.RequiredArgsConstructor;
+
+@RestController
+@RequestMapping("/image")
+@RequiredArgsConstructor
+public class ObjectStorageController {
+ private final ObjectStorageService objectStorageService;
+
+ @PostMapping(value = "/upload", consumes = MULTIPART_FORM_DATA_VALUE)
+ ApiResponse postImageUpload(
+ @RequestPart("file") MultipartFile imageFile
+ ) {
+ String imgUrl = objectStorageService.imgSave(imageFile);
+ return ApiResponse.success(imgUrl);
+ }
+}
diff --git a/src/main/java/com/clover/habbittracker/global/infra/storage/service/ObjectStorageService.java b/src/main/java/com/clover/habbittracker/global/infra/storage/service/ObjectStorageService.java
new file mode 100644
index 00000000..a294f59d
--- /dev/null
+++ b/src/main/java/com/clover/habbittracker/global/infra/storage/service/ObjectStorageService.java
@@ -0,0 +1,40 @@
+package com.clover.habbittracker.global.infra.storage.service;
+
+import static com.clover.habbittracker.global.util.ImageUtil.*;
+
+import java.io.File;
+import java.util.Optional;
+
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import com.amazonaws.services.s3.AmazonS3;
+import com.amazonaws.services.s3.model.CannedAccessControlList;
+import com.amazonaws.services.s3.model.PutObjectRequest;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class ObjectStorageService {
+
+ private final AmazonS3 objectStorage;
+ private final String BUCKET_NAME = "post-images";
+
+ public String imgSave(MultipartFile file) {
+ Optional.ofNullable(file).orElseThrow(IllegalArgumentException::new);
+ File tempFile = tempFileSave(file);
+ String imgUrl = objectStorageFileSave(tempFile);
+ tempFileDelete(tempFile);
+ return imgUrl;
+ }
+
+ private String objectStorageFileSave(File tempFile) {
+ PutObjectRequest request = new PutObjectRequest(BUCKET_NAME, tempFile.getName(), tempFile);
+ request.withCannedAcl(CannedAccessControlList.PublicRead);
+ objectStorage.putObject(request);
+ return objectStorage.getUrl(BUCKET_NAME, tempFile.getName()).toString();
+ }
+}
diff --git a/src/main/java/com/clover/habbittracker/global/util/ImageUtil.java b/src/main/java/com/clover/habbittracker/global/util/ImageUtil.java
new file mode 100644
index 00000000..aae7db17
--- /dev/null
+++ b/src/main/java/com/clover/habbittracker/global/util/ImageUtil.java
@@ -0,0 +1,40 @@
+package com.clover.habbittracker.global.util;
+
+import static lombok.AccessLevel.*;
+
+import java.io.File;
+import java.util.UUID;
+
+import org.springframework.web.multipart.MultipartFile;
+
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@NoArgsConstructor(access = PRIVATE)
+public class ImageUtil {
+ private static final String IMG_PATH = System.getProperty("user.dir") + "/tmp";
+
+ public static void tempFileDelete(File tempFile) {
+ if (tempFile.delete()) {
+ log.error("์์ ํ์ผ ์ญ์ ๋ฅผ ์คํจํ์์ต๋๋ค. ํด๋น ์์ํ์ผ์ ๊ด๋ฆฌ์๊ฐ ์ง์ ์ญ์ ํด์ผ ํฉ๋๋ค. FileName = {}", tempFile.getName());
+ }
+ }
+
+ public static File tempFileSave(MultipartFile file) {
+ File imgFile = getImgFile(file);
+ try {
+ file.transferTo(imgFile);
+ } catch (Exception e) {
+ log.error("Failed to transfer file: {}", e.getMessage());
+ }
+ return imgFile;
+ }
+
+ private static File getImgFile(MultipartFile file) {
+ String uuid = UUID.randomUUID().toString().substring(0, 8);
+
+ String imgName = uuid + "_" + file.getOriginalFilename();
+ return new File(IMG_PATH, imgName);
+ }
+}
From 6aee0ba27b7d8bde43d09624f3afd22dca79d36b Mon Sep 17 00:00:00 2001
From: gombasan
Date: Mon, 14 Aug 2023 23:44:25 +0900
Subject: [PATCH 5/9] =?UTF-8?q?feat(Test)=20:=20=EC=9D=B4=EB=AF=B8?=
=?UTF-8?q?=EC=A7=80=20=EC=97=85=EB=A1=9C=EB=93=9C=20=ED=85=8C=EC=8A=A4?=
=?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Mock ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ Url ์ ์ ์์ ์ผ๋ก ๋ฐํ ํ๋์ง ํ์ธํ๋ ํ
์คํธ์ฝ๋์
๋๋ค.
- ๋ง์ฝ ์ด๋ฏธ์ง ํ์ผ์ด null ๋ก ์ค๊ฒ ๋๋ค๋ฉด, IllegalArgumentException ์์ธ๋ฅผ ๋ฐ์์ํต๋๋ค.
- RestDocs ๋ก ๋ฌธ์ํ ๋ด์ฉ์ ์ถ๊ฐํ์์ต๋๋ค.
---
.../api/ObjectStorageControllerTest.java | 50 +++++++++++++++++++
.../service}/ObjectStorageServiceTest.java | 17 +++----
.../restdocs/templates/request-parts.snippet | 13 +++++
3 files changed, 71 insertions(+), 9 deletions(-)
create mode 100644 src/test/java/com/clover/habbittracker/global/infra/storage/api/ObjectStorageControllerTest.java
rename src/test/java/com/clover/habbittracker/global/infra/{ => storage/service}/ObjectStorageServiceTest.java (75%)
create mode 100644 src/test/resources/org/springframework/restdocs/templates/request-parts.snippet
diff --git a/src/test/java/com/clover/habbittracker/global/infra/storage/api/ObjectStorageControllerTest.java b/src/test/java/com/clover/habbittracker/global/infra/storage/api/ObjectStorageControllerTest.java
new file mode 100644
index 00000000..61db48a7
--- /dev/null
+++ b/src/test/java/com/clover/habbittracker/global/infra/storage/api/ObjectStorageControllerTest.java
@@ -0,0 +1,50 @@
+package com.clover.habbittracker.global.infra.storage.api;
+
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+import static org.springframework.restdocs.payload.PayloadDocumentation.*;
+import static org.springframework.restdocs.request.RequestDocumentation.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockitoAnnotations;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.web.multipart.MultipartFile;
+
+import com.clover.habbittracker.base.RestDocsSupport;
+import com.clover.habbittracker.global.infra.storage.service.ObjectStorageService;
+
+public class ObjectStorageControllerTest extends RestDocsSupport {
+
+ @MockBean
+ private ObjectStorageService objectStorageService;
+
+ @BeforeEach
+ void setUp() {
+ MockitoAnnotations.openMocks(this);
+ when(objectStorageService.imgSave(any(MultipartFile.class))).thenReturn("/sucess/url");
+ }
+
+ @Test
+ @DisplayName("์ฌ์ง์ ์์ฒญํ์ฌ ์ ์ฅํ ์ ์๋ค.")
+ void imageUploadTest() throws Exception {
+ MockMultipartFile file = new MockMultipartFile("file", "test.jpg", "image/jpeg", new byte[0]);
+ mockMvc.perform(multipart("/image/upload")
+ .file(file))
+ .andExpect(status().isOk())
+ .andDo(restDocs.document(
+ requestParts(
+ partWithName("file").description("์ด๋ฏธ์ง ํ์ผ")
+ ),
+ responseFields(
+ fieldWithPath("code").description("๊ฒฐ๊ณผ ์ฝ๋"),
+ fieldWithPath("message").description("๊ฒฐ๊ณผ ๋ฉ์ธ์ง"),
+ fieldWithPath("data").description("์ด๋ฏธ์ง url")
+ )
+ ));
+ }
+}
diff --git a/src/test/java/com/clover/habbittracker/global/infra/ObjectStorageServiceTest.java b/src/test/java/com/clover/habbittracker/global/infra/storage/service/ObjectStorageServiceTest.java
similarity index 75%
rename from src/test/java/com/clover/habbittracker/global/infra/ObjectStorageServiceTest.java
rename to src/test/java/com/clover/habbittracker/global/infra/storage/service/ObjectStorageServiceTest.java
index 2767a38b..6f845c4e 100644
--- a/src/test/java/com/clover/habbittracker/global/infra/ObjectStorageServiceTest.java
+++ b/src/test/java/com/clover/habbittracker/global/infra/storage/service/ObjectStorageServiceTest.java
@@ -1,11 +1,12 @@
-package com.clover.habbittracker.global.infra;
+package com.clover.habbittracker.global.infra.storage.service;
+import static org.assertj.core.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.io.IOException;
import java.net.URL;
-import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@@ -16,7 +17,6 @@
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.PutObjectRequest;
-import com.clover.habbittracker.global.infra.storage.ObjectStorageService;
public class ObjectStorageServiceTest {
private ObjectStorageService objectStorageService;
@@ -35,21 +35,21 @@ public void setup() {
public void naverCloudProfileImgSaveTest() throws IOException {
//given
MultipartFile mockFile = new MockMultipartFile("test.jpg", "test.jpg", "image/jpeg", new byte[0]);
- String expectedBucketName = "user-profile-image";
+ String expectedBucketName = "post-images";
String mockUrl = "http://simple.url";
//when
when(mockStorage.putObject(any(PutObjectRequest.class))).thenReturn(null);
when(mockStorage.getUrl(anyString(), anyString())).thenReturn(new URL(mockUrl));
- String result = objectStorageService.profileImgSave(mockFile);
+ String result = objectStorageService.imgSave(mockFile);
//then
- Assertions.assertThat(result).isEqualTo(mockUrl);
+ assertThat(result).isEqualTo(mockUrl);
verify(mockStorage).getUrl(eq(expectedBucketName), anyString());
}
@Test
- @DisplayName("multipartForm ๋ฐ์ดํฐ๊ฐ ์๋ค๋ฉด ์์ธ์ฒ๋ฆฌ๋ ๋ฐ๋ก ํ์ง์๊ณ , null์ ๋ฐํํ๋ค.")
+ @DisplayName("multipartForm ๋ฐ์ดํฐ๊ฐ ์๋ค๋ฉด IllegalArgumentException ์์ธ๋ก ์ฒ๋ฆฌํ๋ค.")
public void failedProfileImgSaveTest() throws IOException {
//given
String mockUrl = "http://simple.url";
@@ -57,9 +57,8 @@ public void failedProfileImgSaveTest() throws IOException {
//when
when(mockStorage.putObject(any(PutObjectRequest.class))).thenReturn(null);
when(mockStorage.getUrl(anyString(), anyString())).thenReturn(new URL(mockUrl));
- String result = objectStorageService.profileImgSave(null);
//then
- Assertions.assertThat(result).isEqualTo(null);
+ assertThrows(IllegalArgumentException.class, () -> objectStorageService.imgSave(null));
}
}
diff --git a/src/test/resources/org/springframework/restdocs/templates/request-parts.snippet b/src/test/resources/org/springframework/restdocs/templates/request-parts.snippet
new file mode 100644
index 00000000..14a2b6ae
--- /dev/null
+++ b/src/test/resources/org/springframework/restdocs/templates/request-parts.snippet
@@ -0,0 +1,13 @@
+===== Request Parts
+
+|===
+|ํ์ผ๋ช
|ํ์๊ฐ|์ค๋ช
+{{#fields}}
+ |{{#tableCellContent}}`+{{path}}+`{{/tableCellContent}}
+ |{{#tableCellContent}}
+ {{^optional}}true{{/optional}}
+ {{#optional}}false{{/optional}}
+ {{/tableCellContent}}
+ |{{#tableCellContent}}{{description}}{{/tableCellContent}}
+{{/fields}}
+|===
\ No newline at end of file
From 9c8152c0fe5e167aa4f98e15f49436d2816ad10d Mon Sep 17 00:00:00 2001
From: gombasan
Date: Tue, 15 Aug 2023 00:28:04 +0900
Subject: [PATCH 6/9] =?UTF-8?q?docs=20:=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20ap?=
=?UTF-8?q?i=20=EB=AC=B8=EC=84=9C=ED=99=94=20=EB=82=B4=EC=9A=A9=20?=
=?UTF-8?q?=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- ์ด๋ฏธ์ง api.adoc ํ์ผ ์ถ๊ฐํ์์ต๋๋ค.
- index ๋ด์ ๋งํฌ๋ฅผ ์ถ๊ฐํ์์ต๋๋ค.
---
src/docs/asciidoc/api/Image-API.adoc | 29 +++++++++++++++++++
src/docs/asciidoc/index.adoc | 4 ++-
.../restdocs/templates/request-parts.snippet | 13 ---------
3 files changed, 32 insertions(+), 14 deletions(-)
create mode 100644 src/docs/asciidoc/api/Image-API.adoc
delete mode 100644 src/test/resources/org/springframework/restdocs/templates/request-parts.snippet
diff --git a/src/docs/asciidoc/api/Image-API.adoc b/src/docs/asciidoc/api/Image-API.adoc
new file mode 100644
index 00000000..61fb25f5
--- /dev/null
+++ b/src/docs/asciidoc/api/Image-API.adoc
@@ -0,0 +1,29 @@
+:doctype: book
+:icons: font
+:source-highlighter: highlightjs
+:toc: left
+:toclevels: 2
+:sectlinks:
+
+[[Image-API]]
+== ์ด๋ฏธ์ง API
+
+---
+
+=== ์ด๋ฏธ์ง ๋ฑ๋ก
+
+==== Request
+
+include::{snippets}/object-storage-controller-test/image-upload-test/request-parts.adoc[]
+
+===== Request HTTP Example
+
+include::{snippets}/object-storage-controller-test/image-upload-test/http-request.adoc[]
+
+==== Response
+
+include::{snippets}/object-storage-controller-test/image-upload-test/response-fields.adoc[]
+
+===== Response HTTP Example
+
+include::{snippets}/object-storage-controller-test/image-upload-test/http-response.adoc[]
diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc
index 5c8a15b3..bbab93c3 100644
--- a/src/docs/asciidoc/index.adoc
+++ b/src/docs/asciidoc/index.adoc
@@ -29,4 +29,6 @@
=== link:api/Bookmark-API.html[๋ถ๋งํฌ API, window= _blank]
-=== link:api/Emoji-API.html[์ด๋ชจ์ง API, window= _blank]
\ No newline at end of file
+=== link:api/Emoji-API.html[์ด๋ชจ์ง API, window= _blank]
+
+=== link:api/Image-API.html[์ด๋ฏธ์ง API, window= _blank]
\ No newline at end of file
diff --git a/src/test/resources/org/springframework/restdocs/templates/request-parts.snippet b/src/test/resources/org/springframework/restdocs/templates/request-parts.snippet
deleted file mode 100644
index 14a2b6ae..00000000
--- a/src/test/resources/org/springframework/restdocs/templates/request-parts.snippet
+++ /dev/null
@@ -1,13 +0,0 @@
-===== Request Parts
-
-|===
-|ํ์ผ๋ช
|ํ์๊ฐ|์ค๋ช
-{{#fields}}
- |{{#tableCellContent}}`+{{path}}+`{{/tableCellContent}}
- |{{#tableCellContent}}
- {{^optional}}true{{/optional}}
- {{#optional}}false{{/optional}}
- {{/tableCellContent}}
- |{{#tableCellContent}}{{description}}{{/tableCellContent}}
-{{/fields}}
-|===
\ No newline at end of file
From 248be3fa77a01897f60ff51e76c25fdc32df0e81 Mon Sep 17 00:00:00 2001
From: gombasan
Date: Tue, 15 Aug 2023 00:29:50 +0900
Subject: [PATCH 7/9] =?UTF-8?q?feat=20:=20=EC=8D=B8=EB=84=A4=EC=9D=BC=20?=
=?UTF-8?q?=EB=82=B4=EC=9A=A9=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- ๊ฒ์๊ธ์ ์กฐํ ํ ๊ฒฝ์ฐ ์ธ๋ค์ผ ์ด๋ฏธ์ง์ url ์ ๋ณด๋ฅผ ์ถ๊ฐํ์์ต๋๋ค.
- ๊ฒ์๊ธ์ ๋ฑ๋ก ํ ๊ฒฝ์ฐ ์ธ๋ค์ผ ์ด๋ฏธ์ง์ url ์ ๊ฐ์ด ์์ฒญ๋ฐ์ ๋ฑ๋กํ๋๋ก ํ์์ต๋๋ค.
- ์ธ๋ค์ผ ์ด๋ฏธ์ง url ์ ์ต์
๊ฐ์ผ๋ก ํ์๊ฐ์ ์๋๋๋ค.
---
.../clover/habbittracker/domain/post/dto/PostRequest.java | 1 +
.../clover/habbittracker/domain/post/dto/PostResponse.java | 1 +
.../com/clover/habbittracker/domain/post/entity/Post.java | 5 ++++-
src/main/resources/schema.sql | 1 +
4 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/main/java/com/clover/habbittracker/domain/post/dto/PostRequest.java b/src/main/java/com/clover/habbittracker/domain/post/dto/PostRequest.java
index 334cdc25..a8eb980b 100644
--- a/src/main/java/com/clover/habbittracker/domain/post/dto/PostRequest.java
+++ b/src/main/java/com/clover/habbittracker/domain/post/dto/PostRequest.java
@@ -5,6 +5,7 @@
public record PostRequest(
String title,
String content,
+ String thumbnail,
Post.Category category
) {
diff --git a/src/main/java/com/clover/habbittracker/domain/post/dto/PostResponse.java b/src/main/java/com/clover/habbittracker/domain/post/dto/PostResponse.java
index ac3827b8..16b8607e 100644
--- a/src/main/java/com/clover/habbittracker/domain/post/dto/PostResponse.java
+++ b/src/main/java/com/clover/habbittracker/domain/post/dto/PostResponse.java
@@ -11,6 +11,7 @@ public record PostResponse(
Long id,
String title,
String content,
+ String thumbnail,
Post.Category category,
Long views,
Integer numOfComments,
diff --git a/src/main/java/com/clover/habbittracker/domain/post/entity/Post.java b/src/main/java/com/clover/habbittracker/domain/post/entity/Post.java
index 99643188..56c0d0b6 100644
--- a/src/main/java/com/clover/habbittracker/domain/post/entity/Post.java
+++ b/src/main/java/com/clover/habbittracker/domain/post/entity/Post.java
@@ -56,15 +56,17 @@ public class Post extends BaseEntity {
private String content;
private Category category;
private Long views;
+ private String thumbnail;
@ManyToOne
@JoinColumn(name = "memberId")
private Member member;
@Builder
- public Post(String title, String content, Category category, Member member) {
+ public Post(String title, String content, Category category, String thumbnail, Member member) {
this.title = title;
this.content = content;
this.category = category;
+ this.thumbnail = thumbnail;
this.member = member;
this.views = 0L;
}
@@ -72,6 +74,7 @@ public Post(String title, String content, Category category, Member member) {
public void updatePost(PostRequest postRequest) {
this.title = postRequest.title();
this.content = postRequest.content();
+ this.thumbnail = postRequest.thumbnail();
this.category = postRequest.category();
}
diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql
index 90386f44..de4bee80 100644
--- a/src/main/resources/schema.sql
+++ b/src/main/resources/schema.sql
@@ -68,6 +68,7 @@ create table post
id bigint auto_increment primary key,
title varchar(255) not null,
content varchar(255) not null,
+ thumbnail varchar(255) null,
category varchar(255) not null,
views bigint not null default 0,
member_id bigint null,
From 2fa44252f63dc3dbb7f793287996b76f5faa73cb Mon Sep 17 00:00:00 2001
From: gombasan
Date: Tue, 15 Aug 2023 00:31:46 +0900
Subject: [PATCH 8/9] =?UTF-8?q?feat(Test)=20:=20=EC=8D=B8=EB=84=A4?=
=?UTF-8?q?=EC=9D=BC=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20?=
=?UTF-8?q?=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- ๊ฒ์๊ธ ๋ฑ๋ก, ๋ฆฌ์คํธ ์กฐํ ์ ์ธ๋ค์ผ ์ด๋ฏธ์ง๊ฐ ์ ์์ ์ผ๋ก ๋ฑ๋ก,์กฐํ ํ
์คํธ ์ฝ๋๋ฅผ ์ถ๊ฐํ์์ต๋๋ค.
- ์ธ๋ค์ผ์ restDocs ๋ฌธ์ํ ๋ด์ฉ์ ์ถ๊ฐํ์์ต๋๋ค.
- PostProvider ์์ PostRequest ๋ฅผ ์์ฑ ํ ๊ฒฝ์ฐ ๊ธฐ๋ณธ ์ธ๋ค์ผ ๊ฐ์ ์ถ๊ฐํ์ฌ ์์ฑํ๋๋ก ๋ณ๊ฒฝํ์์ต๋๋ค.
---
.../domain/post/api/PostControllerTest.java | 10 +++--
.../domain/post/service/PostServiceTest.java | 38 ++++++++++---------
.../habbittracker/util/PostProvider.java | 5 ++-
3 files changed, 32 insertions(+), 21 deletions(-)
diff --git a/src/test/java/com/clover/habbittracker/domain/post/api/PostControllerTest.java b/src/test/java/com/clover/habbittracker/domain/post/api/PostControllerTest.java
index c189eff8..ab175314 100644
--- a/src/test/java/com/clover/habbittracker/domain/post/api/PostControllerTest.java
+++ b/src/test/java/com/clover/habbittracker/domain/post/api/PostControllerTest.java
@@ -21,6 +21,8 @@
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
import com.clover.habbittracker.base.RestDocsSupport;
import com.clover.habbittracker.domain.post.dto.PostRequest;
@@ -28,8 +30,6 @@
import com.clover.habbittracker.domain.post.entity.Post;
import com.clover.habbittracker.domain.post.repository.PostRepository;
import com.clover.habbittracker.util.CustomTransaction;
-import org.springframework.transaction.annotation.Propagation;
-import org.springframework.transaction.annotation.Transactional;
@Transactional(propagation = Propagation.REQUIRED)
class PostControllerTest extends RestDocsSupport {
@@ -72,6 +72,7 @@ void createPostTest() throws Exception {
requestFields(
fieldWithPath("title").description("๊ฒ์๊ธ ์ ๋ชฉ").attributes(field("constraints", "์์ง ๋ฏธ์ ")),
fieldWithPath("content").description("๊ฒ์๊ธ ๋ณธ๋ฌธ").attributes(field("constraints", "์์ง ๋ฏธ์ ")),
+ fieldWithPath("thumbnail").description("์ธ๋ค์ผ ์ด๋ฏธ์ง url").optional(),
fieldWithPath("category").description(generateLinkCode(DocUrl.CATEGORY))
),
responseHeaders(
@@ -103,6 +104,7 @@ void getPostListTest() throws Exception {
fieldWithPath("id").type(NUMBER).description("๊ฒ์๊ธ id"),
fieldWithPath("title").type(STRING).description("๊ฒ์๊ธ ์ ๋ชฉ"),
fieldWithPath("content").type(STRING).description("๊ฒ์๊ธ ๋ณธ๋ฌธ"),
+ fieldWithPath("thumbnail").description("๊ฒ์๊ธ ์ธ๋ค์ผ url"),
fieldWithPath("category").type(STRING).description(generateLinkCode(DocUrl.CATEGORY)),
fieldWithPath("views").type(NUMBER).description("์กฐํ์"),
fieldWithPath("numOfComments").type(NUMBER).description("๋๊ธ ์"),
@@ -184,6 +186,7 @@ void searchPostTest() throws Exception {
fieldWithPath("content[].id").type(NUMBER).description("๊ฒ์๊ธ id"),
fieldWithPath("content[].title").type(STRING).description("๊ฒ์๊ธ ์ ๋ชฉ"),
fieldWithPath("content[].content").type(STRING).description("๊ฒ์๊ธ ๋ณธ๋ฌธ"),
+ fieldWithPath("content[].thumbnail").description("๊ฒ์๊ธ ์ธ๋ค์ผ url"),
fieldWithPath("content[].category").type(STRING).description(generateLinkCode(DocUrl.CATEGORY)),
fieldWithPath("content[].views").type(NUMBER).description("์กฐํ์"),
fieldWithPath("content[].numOfComments").type(NUMBER).description("๋๊ธ ์"),
@@ -200,7 +203,7 @@ void searchPostTest() throws Exception {
@DisplayName("๊ฒ์๊ธ ์์ฑ์๋ ๊ฒ์๊ธ์ ์์ ํ ์ ์๋ค.")
void updatePostTest() throws Exception {
//given
- PostRequest postRequest = new PostRequest("updateTitle", "updateContent", Post.Category.STUDY);
+ PostRequest postRequest = new PostRequest("updateTitle", "updateContent", "/thumbnail", Post.Category.STUDY);
String request = objectMapper.writeValueAsString(postRequest);
//when then
@@ -220,6 +223,7 @@ void updatePostTest() throws Exception {
requestFields(
fieldWithPath("title").description("์์ ํ ๊ฒ์๊ธ ์ ๋ชฉ").attributes(field("constraints", "์์ง ๋ฏธ์ ")),
fieldWithPath("content").description("์์ ํ ๊ฒ์๊ธ ๋ณธ๋ฌธ").attributes(field("constraints", "์์ง ๋ฏธ์ ")),
+ fieldWithPath("thumbnail").description("์์ ํ ์ธ๋ค์ผ ์ด๋ฏธ์ง url").optional(),
fieldWithPath("category").description(generateLinkCode(DocUrl.CATEGORY))
),
responseHeaders(
diff --git a/src/test/java/com/clover/habbittracker/domain/post/service/PostServiceTest.java b/src/test/java/com/clover/habbittracker/domain/post/service/PostServiceTest.java
index 6f61bfb0..ed7a9c4a 100644
--- a/src/test/java/com/clover/habbittracker/domain/post/service/PostServiceTest.java
+++ b/src/test/java/com/clover/habbittracker/domain/post/service/PostServiceTest.java
@@ -1,14 +1,13 @@
package com.clover.habbittracker.domain.post.service;
-import com.clover.habbittracker.domain.member.entity.Member;
-import com.clover.habbittracker.domain.member.repository.MemberRepository;
-import com.clover.habbittracker.domain.post.dto.PostDetailResponse;
-import com.clover.habbittracker.domain.post.dto.PostRequest;
-import com.clover.habbittracker.domain.post.dto.PostResponse;
-import com.clover.habbittracker.domain.post.dto.PostSearchCondition;
-import com.clover.habbittracker.domain.post.entity.Post;
-import com.clover.habbittracker.domain.post.repository.PostRepository;
-import com.clover.habbittracker.util.CustomTransaction;
+import static com.clover.habbittracker.util.MemberProvider.*;
+import static com.clover.habbittracker.util.PostProvider.*;
+import static org.assertj.core.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.List;
+import java.util.Optional;
+
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
@@ -24,14 +23,15 @@
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
-import java.util.List;
-import java.util.Optional;
-
-import static com.clover.habbittracker.util.MemberProvider.createTestMember;
-import static com.clover.habbittracker.util.PostProvider.createPostRequest;
-import static com.clover.habbittracker.util.PostProvider.createTestPost;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertAll;
+import com.clover.habbittracker.domain.member.entity.Member;
+import com.clover.habbittracker.domain.member.repository.MemberRepository;
+import com.clover.habbittracker.domain.post.dto.PostDetailResponse;
+import com.clover.habbittracker.domain.post.dto.PostRequest;
+import com.clover.habbittracker.domain.post.dto.PostResponse;
+import com.clover.habbittracker.domain.post.dto.PostSearchCondition;
+import com.clover.habbittracker.domain.post.entity.Post;
+import com.clover.habbittracker.domain.post.repository.PostRepository;
+import com.clover.habbittracker.util.CustomTransaction;
@SpringBootTest
@Transactional
@@ -85,6 +85,7 @@ void updatePostTest() {
assertThat(updatedPost).isPresent();
assertThat(updatedPost.get().getTitle()).isEqualTo(updateRequest.title());
assertThat(updatedPost.get().getContent()).isEqualTo(updateRequest.content());
+ assertThat(updatedPost.get().getThumbnail()).isEqualTo(updateRequest.thumbnail());
assertThat(updatedPost.get().getCategory()).isEqualTo(updateRequest.category());
});
}
@@ -144,6 +145,7 @@ void categoryTest() {
assertThat(categoryFilterPost.size()).isEqualTo(1);
assertThat(categoryFilterPost.get(0).title()).isEqualTo(savedPost.getTitle());
assertThat(categoryFilterPost.get(0).content()).isEqualTo(savedPost.getContent());
+ assertThat(categoryFilterPost.get(0).thumbnail()).isEqualTo(savedPost.getThumbnail());
assertThat(categoryFilterPost.get(0).category()).isEqualTo(savedPost.getCategory());
});
@@ -166,6 +168,7 @@ void titleTest() {
assertThat(postList.size()).isEqualTo(1);
assertThat(postList.get(0).title()).isEqualTo(savedPost.getTitle());
assertThat(postList.get(0).content()).isEqualTo(savedPost.getContent());
+ assertThat(postList.get(0).thumbnail()).isEqualTo(savedPost.getThumbnail());
assertThat(postList.get(0).category()).isEqualTo(savedPost.getCategory());
});
}
@@ -187,6 +190,7 @@ void contentTest() {
assertThat(postList.size()).isEqualTo(1);
assertThat(postList.get(0).title()).isEqualTo(savedPost.getTitle());
assertThat(postList.get(0).content()).isEqualTo(savedPost.getContent());
+ assertThat(postList.get(0).thumbnail()).isEqualTo(savedPost.getThumbnail());
assertThat(postList.get(0).category()).isEqualTo(savedPost.getCategory());
});
}
diff --git a/src/test/java/com/clover/habbittracker/util/PostProvider.java b/src/test/java/com/clover/habbittracker/util/PostProvider.java
index be611770..731d8ce8 100644
--- a/src/test/java/com/clover/habbittracker/util/PostProvider.java
+++ b/src/test/java/com/clover/habbittracker/util/PostProvider.java
@@ -10,6 +10,7 @@ public class PostProvider {
private static final String DEFAULT_CONTENT = "testContent";
private static final String REQUEST_TITLE = "requestTitle";
private static final String REQUEST_CONTENT = "requestContent";
+ private static final String DEFAULT_THUMBNAIL = "/thumbnail";
private static final Post.Category DEFAULT_CATEGORY = Post.Category.DAILY;
private PostProvider() {
@@ -33,6 +34,7 @@ public static Post createTestPost(Member member, Post.Category category) {
.member(member)
.build();
}
+
public static Post createTestPost(Member member, String title) {
return Post.builder()
.title(title)
@@ -41,6 +43,7 @@ public static Post createTestPost(Member member, String title) {
.member(member)
.build();
}
+
public static Post createTestPost(Member member, String title, String content) {
return Post.builder()
.title(title)
@@ -51,6 +54,6 @@ public static Post createTestPost(Member member, String title, String content) {
}
public static PostRequest createPostRequest() {
- return new PostRequest(REQUEST_TITLE, REQUEST_CONTENT, DEFAULT_CATEGORY);
+ return new PostRequest(REQUEST_TITLE, REQUEST_CONTENT, DEFAULT_THUMBNAIL, DEFAULT_CATEGORY);
}
}
From 608b9877e6774f34d3574fca0ec646bb22f0ef62 Mon Sep 17 00:00:00 2001
From: kwonjoosung
Date: Tue, 15 Aug 2023 19:41:05 +0900
Subject: [PATCH 9/9] =?UTF-8?q?fix:=20=EC=98=A4=ED=83=80=20=EC=88=98?=
=?UTF-8?q?=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../global/infra/storage/api/ObjectStorageControllerTest.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/test/java/com/clover/habbittracker/global/infra/storage/api/ObjectStorageControllerTest.java b/src/test/java/com/clover/habbittracker/global/infra/storage/api/ObjectStorageControllerTest.java
index 61db48a7..9322d139 100644
--- a/src/test/java/com/clover/habbittracker/global/infra/storage/api/ObjectStorageControllerTest.java
+++ b/src/test/java/com/clover/habbittracker/global/infra/storage/api/ObjectStorageControllerTest.java
@@ -26,7 +26,7 @@ public class ObjectStorageControllerTest extends RestDocsSupport {
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
- when(objectStorageService.imgSave(any(MultipartFile.class))).thenReturn("/sucess/url");
+ when(objectStorageService.imgSave(any(MultipartFile.class))).thenReturn("/success/url");
}
@Test