From 6de26081ca21af1cc1460e373fb357aee9628b78 Mon Sep 17 00:00:00 2001 From: "2jin2.1031" <2jin2.1031@gmail.com> Date: Sun, 9 Nov 2025 17:48:47 +0900 Subject: [PATCH 01/26] =?UTF-8?q?feat:=20=EB=8F=84=EC=BB=A4=ED=8C=8C?= =?UTF-8?q?=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 --- Dockerfile | 9 +++++++++ src/main/resources/application.yml | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..4cc9fec --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM eclipse-temurin:17 + +WORKDIR /app + +COPY build/libs/*.jar app.jar + +EXPOSE 8080 + +ENTRYPOINT ["java", "-Dspring.profiles.active=dev", "-jar", "app.jar"] diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index e3c312c..713047c 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,4 +1,4 @@ spring: profiles: include: private - active: dev # prod (배포 환경) + active: local # prod (배포 환경) From d767c3ec2092287b3c72f56d4bfdb06ae64f5386 Mon Sep 17 00:00:00 2001 From: "2jin2.1031" <2jin2.1031@gmail.com> Date: Sun, 9 Nov 2025 18:16:10 +0900 Subject: [PATCH 02/26] =?UTF-8?q?tmp:=20dev=20cd=20=ED=8A=B8=EB=A6=AC?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/wooteco/wiki/WikiApplication.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/wooteco/wiki/WikiApplication.java b/src/main/java/com/wooteco/wiki/WikiApplication.java index 29c2808..ab35129 100644 --- a/src/main/java/com/wooteco/wiki/WikiApplication.java +++ b/src/main/java/com/wooteco/wiki/WikiApplication.java @@ -9,5 +9,4 @@ public class WikiApplication { public static void main(String[] args) { SpringApplication.run(WikiApplication.class, args); } - } From f847f66a6fb9292d6edc36e895f5dfcf8563448b Mon Sep 17 00:00:00 2001 From: "2jin2.1031" <2jin2.1031@gmail.com> Date: Sun, 9 Nov 2025 18:31:46 +0900 Subject: [PATCH 03/26] =?UTF-8?q?tmp:=20dev=20cd=20=ED=8A=B8=EB=A6=AC?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/wooteco/wiki/WikiApplication.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/wooteco/wiki/WikiApplication.java b/src/main/java/com/wooteco/wiki/WikiApplication.java index ab35129..29c2808 100644 --- a/src/main/java/com/wooteco/wiki/WikiApplication.java +++ b/src/main/java/com/wooteco/wiki/WikiApplication.java @@ -9,4 +9,5 @@ public class WikiApplication { public static void main(String[] args) { SpringApplication.run(WikiApplication.class, args); } + } From 4c26dd0dee5b5304b432c09474b406f6b623c2ca Mon Sep 17 00:00:00 2001 From: "2jin2.1031" <2jin2.1031@gmail.com> Date: Sun, 9 Nov 2025 19:33:15 +0900 Subject: [PATCH 04/26] =?UTF-8?q?tmp:=20dev=20cd=20=ED=8A=B8=EB=A6=AC?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/wooteco/wiki/WikiApplication.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/wooteco/wiki/WikiApplication.java b/src/main/java/com/wooteco/wiki/WikiApplication.java index 29c2808..ab35129 100644 --- a/src/main/java/com/wooteco/wiki/WikiApplication.java +++ b/src/main/java/com/wooteco/wiki/WikiApplication.java @@ -9,5 +9,4 @@ public class WikiApplication { public static void main(String[] args) { SpringApplication.run(WikiApplication.class, args); } - } From 5534cbf7bca3ea82c8089d0baee275c166bb0478 Mon Sep 17 00:00:00 2001 From: "2jin2.1031" <2jin2.1031@gmail.com> Date: Sun, 9 Nov 2025 19:40:44 +0900 Subject: [PATCH 05/26] =?UTF-8?q?tmp:=20dev=20cd=20=ED=8A=B8=EB=A6=AC?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/wooteco/wiki/WikiApplication.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/wooteco/wiki/WikiApplication.java b/src/main/java/com/wooteco/wiki/WikiApplication.java index ab35129..29c2808 100644 --- a/src/main/java/com/wooteco/wiki/WikiApplication.java +++ b/src/main/java/com/wooteco/wiki/WikiApplication.java @@ -9,4 +9,5 @@ public class WikiApplication { public static void main(String[] args) { SpringApplication.run(WikiApplication.class, args); } + } From 30beb53a922e04e78f7b0e2ba09cfb426ff6aee4 Mon Sep 17 00:00:00 2001 From: "2jin2.1031" <2jin2.1031@gmail.com> Date: Sun, 9 Nov 2025 19:51:52 +0900 Subject: [PATCH 06/26] =?UTF-8?q?tmp:=20dev=20cd=20=ED=8A=B8=EB=A6=AC?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/wooteco/wiki/WikiApplication.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/wooteco/wiki/WikiApplication.java b/src/main/java/com/wooteco/wiki/WikiApplication.java index 29c2808..ab35129 100644 --- a/src/main/java/com/wooteco/wiki/WikiApplication.java +++ b/src/main/java/com/wooteco/wiki/WikiApplication.java @@ -9,5 +9,4 @@ public class WikiApplication { public static void main(String[] args) { SpringApplication.run(WikiApplication.class, args); } - } From 94d39e6df1221b1ffc28e0e1a901e405b37e6a50 Mon Sep 17 00:00:00 2001 From: "2jin2.1031" <2jin2.1031@gmail.com> Date: Sun, 9 Nov 2025 20:18:41 +0900 Subject: [PATCH 07/26] =?UTF-8?q?chore:=20.gitignore=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- src/main/resources/application-dev.yml | 22 ++++++++++++++++++++++ src/main/resources/application-local.yml | 0 src/main/resources/application-private.yml | 17 +++++++++++++++++ 4 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/application-dev.yml create mode 100644 src/main/resources/application-local.yml create mode 100644 src/main/resources/application-private.yml diff --git a/.gitignore b/.gitignore index 2071836..fa99f61 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,4 @@ out/ ### VS Code ### .vscode/ -application-*.yml +application-prod.yml diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml new file mode 100644 index 0000000..773f800 --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,22 @@ +server: + port: 8080 + +spring: + datasource: + url: ${DEV_DB_URL} + username: ${DEV_DB_USERNAME} + password: ${DEV_DB_PASSWORD} + driver-class-name: com.mysql.cj.jdbc.Driver + + jpa: + hibernate: + ddl-auto: update + properties: + hibernate: + dialect: org.hibernate.dialect.MySQL8Dialect + +cors: + allowed-origins: http://localhost:3000, https://dev.crew-wiki.site, https://dev.api.crew-wiki.site + +swagger: + server-url: https://dev.api.crew-wiki.site diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/application-private.yml b/src/main/resources/application-private.yml new file mode 100644 index 0000000..fa7b38c --- /dev/null +++ b/src/main/resources/application-private.yml @@ -0,0 +1,17 @@ +security: + jwt: + token: + secret-key: ${JWT_SECRET_KEY} + expire-length: ${JWT_SECRET_EXPIRE_LENGTH} + +cloud: + aws: + credentials: + access-key: ${AWS_CREDENTIALS_ACCESS_KEY} + secret-key: ${AWS_CREDENTIALS_SECRET_KEY} + s3: + bucket: ${S3_BUCKET} + region: + static: ap-northeast-2 + stack: + auto: false From b81911597d7015ae43db731a3a617e5364aa4b99 Mon Sep 17 00:00:00 2001 From: "2jin2.1031" <2jin2.1031@gmail.com> Date: Sun, 9 Nov 2025 20:25:53 +0900 Subject: [PATCH 08/26] =?UTF-8?q?chore:=20.gitignore=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index fa99f61..2071836 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,4 @@ out/ ### VS Code ### .vscode/ -application-prod.yml +application-*.yml From cb69ae2739542bbaaf58941a0e56c5d7daeb1fb1 Mon Sep 17 00:00:00 2001 From: "2jin2.1031" <2jin2.1031@gmail.com> Date: Sun, 9 Nov 2025 20:44:09 +0900 Subject: [PATCH 09/26] =?UTF-8?q?tmp:=20dev=20cd=20=ED=8A=B8=EB=A6=AC?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/wooteco/wiki/WikiApplication.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/wooteco/wiki/WikiApplication.java b/src/main/java/com/wooteco/wiki/WikiApplication.java index ab35129..29c2808 100644 --- a/src/main/java/com/wooteco/wiki/WikiApplication.java +++ b/src/main/java/com/wooteco/wiki/WikiApplication.java @@ -9,4 +9,5 @@ public class WikiApplication { public static void main(String[] args) { SpringApplication.run(WikiApplication.class, args); } + } From 2aa974ec7ad50e3912319157f08ed2c5e966409c Mon Sep 17 00:00:00 2001 From: "2jin2.1031" <2jin2.1031@gmail.com> Date: Mon, 17 Nov 2025 16:14:39 +0900 Subject: [PATCH 10/26] =?UTF-8?q?feat:=20=EB=AC=B8=EC=84=9C=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EC=9A=94=EC=B2=AD=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(id=20->=20uuid)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wiki/admin/controller/AdminController.java | 9 +++++---- .../com/wooteco/wiki/admin/service/AdminService.java | 7 +++---- .../wiki/document/repository/DocumentRepository.java | 2 ++ .../wiki/document/service/DocumentService.java | 12 ++++++------ .../wiki/document/service/DocumentServiceTest.java | 8 ++++---- 5 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/wooteco/wiki/admin/controller/AdminController.java b/src/main/java/com/wooteco/wiki/admin/controller/AdminController.java index a6226b5..07ce2be 100644 --- a/src/main/java/com/wooteco/wiki/admin/controller/AdminController.java +++ b/src/main/java/com/wooteco/wiki/admin/controller/AdminController.java @@ -4,6 +4,7 @@ import com.wooteco.wiki.global.common.ApiResponse; import com.wooteco.wiki.global.common.ApiResponseGenerator; import io.swagger.v3.oas.annotations.Operation; +import java.util.UUID; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -20,10 +21,10 @@ public AdminController(AdminService adminService) { this.adminService = adminService; } - @Operation(summary = "문서 삭제", description = "문서 ID로 문서를 삭제합니다.") - @DeleteMapping("/documents/{documentId}") - public ApiResponse> deleteDocumentByDocumentId(@PathVariable Long documentId) { - adminService.deleteDocumentByDocumentId(documentId); + @Operation(summary = "문서 삭제", description = "문서 Uuid로 문서를 삭제합니다.") + @DeleteMapping("/documents/{documentUuid}") + public ApiResponse> deleteDocumentByDocumentId(@PathVariable UUID documentUuid) { + adminService.deleteDocumentByDocumentUuid(documentUuid); return ApiResponseGenerator.success(HttpStatus.NO_CONTENT); } } diff --git a/src/main/java/com/wooteco/wiki/admin/service/AdminService.java b/src/main/java/com/wooteco/wiki/admin/service/AdminService.java index e947a3a..53d27e3 100644 --- a/src/main/java/com/wooteco/wiki/admin/service/AdminService.java +++ b/src/main/java/com/wooteco/wiki/admin/service/AdminService.java @@ -1,8 +1,7 @@ package com.wooteco.wiki.admin.service; import com.wooteco.wiki.document.service.DocumentService; -import com.wooteco.wiki.global.exception.ErrorCode; -import com.wooteco.wiki.global.exception.WikiException; +import java.util.UUID; import org.springframework.stereotype.Service; @Service @@ -14,7 +13,7 @@ public AdminService(DocumentService documentService) { this.documentService = documentService; } - public void deleteDocumentByDocumentId(Long documentId) { - documentService.deleteById(documentId); + public void deleteDocumentByDocumentUuid(UUID documentUuid) { + documentService.deleteByUuid(documentUuid); } } diff --git a/src/main/java/com/wooteco/wiki/document/repository/DocumentRepository.java b/src/main/java/com/wooteco/wiki/document/repository/DocumentRepository.java index 628297b..d1e1e1a 100644 --- a/src/main/java/com/wooteco/wiki/document/repository/DocumentRepository.java +++ b/src/main/java/com/wooteco/wiki/document/repository/DocumentRepository.java @@ -26,4 +26,6 @@ public interface DocumentRepository extends JpaRepository { Optional findIdByUuid(@Param("uuid") UUID documentUuid); List findAllByUuidIn(Set uuids); + + void deleteByUuid(UUID documentUuid); } diff --git a/src/main/java/com/wooteco/wiki/document/service/DocumentService.java b/src/main/java/com/wooteco/wiki/document/service/DocumentService.java index d42c524..7344526 100644 --- a/src/main/java/com/wooteco/wiki/document/service/DocumentService.java +++ b/src/main/java/com/wooteco/wiki/document/service/DocumentService.java @@ -106,12 +106,6 @@ public DocumentResponse put(UUID uuid, DocumentUpdateRequest request) { return mapToResponse(document); } - public void deleteById(Long id) { - documentRepository.findById(id) - .orElseThrow(() -> new WikiException(ErrorCode.DOCUMENT_NOT_FOUND)); - documentRepository.deleteById(id); - } - public void flushViews(Map views) { List documents = documentRepository.findAllByUuidIn(views.keySet()); @@ -126,6 +120,12 @@ public void flushViews(Map views) { documentRepository.saveAll(documents); } + public void deleteByUuid(UUID documentUuid) { + documentRepository.findByUuid(documentUuid) + .orElseThrow(() -> new WikiException(ErrorCode.DOCUMENT_NOT_FOUND)); + documentRepository.deleteByUuid(documentUuid); + } + private DocumentResponse mapToResponse(Document document) { long latestVersion = historyService.findLatestVersionByDocument(document); List organizationDocumentResponses = diff --git a/src/test/java/com/wooteco/wiki/document/service/DocumentServiceTest.java b/src/test/java/com/wooteco/wiki/document/service/DocumentServiceTest.java index ac7502b..87cfd7c 100644 --- a/src/test/java/com/wooteco/wiki/document/service/DocumentServiceTest.java +++ b/src/test/java/com/wooteco/wiki/document/service/DocumentServiceTest.java @@ -246,8 +246,8 @@ void findAll_throwsException_byNegativeNumber() { } @Nested - @DisplayName("문서 id로 삭제 기능") - class deleteById { + @DisplayName("문서 uuid로 삭제 기능") + class deleteByUuid { @DisplayName("존재하는 문서 id일 경우 문서가 로그들과 함께 삭제된다") @Test @@ -262,7 +262,7 @@ void deleteById_success_byExistsId() { assertThat(historyRepository.findAll()).hasSize(1); // when - documentService.deleteById(documentResponse.getDocumentId()); + documentService.deleteByUuid(documentResponse.getDocumentUUID()); // after then assertThat(documentRepository.findAll()).hasSize(0); @@ -274,7 +274,7 @@ void deleteById_success_byExistsId() { void deleteById_throwsException_byNonExistsId() { // when & then WikiException ex = assertThrows(WikiException.class, - () -> documentService.deleteById(Long.MAX_VALUE)); + () -> documentService.deleteByUuid(UUID.randomUUID())); assertThat(ex.getErrorCode()).isEqualTo(DOCUMENT_NOT_FOUND); } } From 9ece70907c18a6b6fe8931a50a60733dee067e37 Mon Sep 17 00:00:00 2001 From: "2jin2.1031" <2jin2.1031@gmail.com> Date: Sun, 14 Dec 2025 16:50:36 +0900 Subject: [PATCH 11/26] =?UTF-8?q?feat:=20local=20yml=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-local.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index e69de29..100b669 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -0,0 +1,24 @@ +spring: + datasource: + url: jdbc:h2:mem:testdb;MODE=MySQL + driver-class-name: org.h2.Driver + + jpa: + hibernate: + ddl-auto: update + open-in-view: false + properties: + hibernate: + dialect: org.hibernate.dialect.H2Dialect + + h2: + console: + enabled: true + path: /h2-console + + +cors: + allowed-origins: http://localhost:3000, https://dev.crew-wiki.site, https://dev.api.crew-wiki.site + +swagger: + server-url: https://dev.api.crew-wiki.site From 5e1e391ad2da67c6046c2119139d4b59328b0bd8 Mon Sep 17 00:00:00 2001 From: "2jin2.1031" <2jin2.1031@gmail.com> Date: Sun, 14 Dec 2025 17:24:06 +0900 Subject: [PATCH 12/26] =?UTF-8?q?tmp:=20cd=20=ED=8A=B8=EB=A6=AC=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/wooteco/wiki/WikiApplication.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/wooteco/wiki/WikiApplication.java b/src/main/java/com/wooteco/wiki/WikiApplication.java index 29c2808..ab35129 100644 --- a/src/main/java/com/wooteco/wiki/WikiApplication.java +++ b/src/main/java/com/wooteco/wiki/WikiApplication.java @@ -9,5 +9,4 @@ public class WikiApplication { public static void main(String[] args) { SpringApplication.run(WikiApplication.class, args); } - } From 084513a3491a72537d6f0fc54128d8ae49d14ed0 Mon Sep 17 00:00:00 2001 From: "2jin2.1031" <2jin2.1031@gmail.com> Date: Sun, 14 Dec 2025 20:38:17 +0900 Subject: [PATCH 13/26] =?UTF-8?q?feat:=20Dockerfile=20=ED=99=98=EA=B2=BD?= =?UTF-8?q?=20=EB=B3=80=EC=88=98=20=EC=9D=BC=EB=B0=98=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 4cc9fec..c0aa37f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,4 +6,4 @@ COPY build/libs/*.jar app.jar EXPOSE 8080 -ENTRYPOINT ["java", "-Dspring.profiles.active=dev", "-jar", "app.jar"] +ENTRYPOINT ["java", "-Dspring.profiles.active=${SPRING_PROFILES_ACTIVE}", "-jar", "app.jar"] From 47ee6ee04d128c5b539a8d6885d7b82acd6c2e7e Mon Sep 17 00:00:00 2001 From: CheChe903 <137619133+CheChe903@users.noreply.github.com> Date: Sun, 28 Dec 2025 15:30:30 +0900 Subject: [PATCH 14/26] =?UTF-8?q?refactor:=20=EC=9E=90=EB=B0=94=20?= =?UTF-8?q?=EB=A7=88=EC=9D=B4=EA=B7=B8=EB=A0=88=EC=9D=B4=EC=85=98=20(#132)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 코틀린 파일 삭제 및 자바 파일 추가 * fix: 테스트 오류 수정 --- .../controller/DocumentController.java | 136 ++++++++++++++++++ .../document/controller/DocumentController.kt | 132 ----------------- .../document/domain/dto/DocumentResponse.java | 20 +++ .../document/domain/dto/DocumentResponse.kt | 17 --- .../domain/dto/DocumentSearchResponse.java | 12 ++ .../domain/dto/DocumentSearchResponse.kt | 10 -- .../domain/dto/DocumentUpdateRequest.java | 13 ++ .../domain/dto/DocumentUpdateRequest.kt | 12 -- .../document/domain/dto/ViewFlushRequest.java | 10 ++ .../document/domain/dto/ViewFlushRequest.kt | 7 - .../document/service/DocumentService.java | 10 +- .../wiki/global/config/RandomConfig.java | 15 ++ .../wiki/global/config/RandomConfig.kt | 12 -- .../service/DocumentSearchServiceTest.java | 4 +- .../document/service/DocumentServiceTest.java | 10 +- 15 files changed, 218 insertions(+), 202 deletions(-) create mode 100644 src/main/java/com/wooteco/wiki/document/controller/DocumentController.java delete mode 100644 src/main/java/com/wooteco/wiki/document/controller/DocumentController.kt create mode 100644 src/main/java/com/wooteco/wiki/document/domain/dto/DocumentResponse.java delete mode 100644 src/main/java/com/wooteco/wiki/document/domain/dto/DocumentResponse.kt create mode 100644 src/main/java/com/wooteco/wiki/document/domain/dto/DocumentSearchResponse.java delete mode 100644 src/main/java/com/wooteco/wiki/document/domain/dto/DocumentSearchResponse.kt create mode 100644 src/main/java/com/wooteco/wiki/document/domain/dto/DocumentUpdateRequest.java delete mode 100644 src/main/java/com/wooteco/wiki/document/domain/dto/DocumentUpdateRequest.kt create mode 100644 src/main/java/com/wooteco/wiki/document/domain/dto/ViewFlushRequest.java delete mode 100644 src/main/java/com/wooteco/wiki/document/domain/dto/ViewFlushRequest.kt create mode 100644 src/main/java/com/wooteco/wiki/global/config/RandomConfig.java delete mode 100644 src/main/java/com/wooteco/wiki/global/config/RandomConfig.kt diff --git a/src/main/java/com/wooteco/wiki/document/controller/DocumentController.java b/src/main/java/com/wooteco/wiki/document/controller/DocumentController.java new file mode 100644 index 0000000..ee56d24 --- /dev/null +++ b/src/main/java/com/wooteco/wiki/document/controller/DocumentController.java @@ -0,0 +1,136 @@ +package com.wooteco.wiki.document.controller; + +import com.wooteco.wiki.document.domain.Document; +import com.wooteco.wiki.document.domain.dto.*; +import com.wooteco.wiki.document.service.DocumentSearchService; +import com.wooteco.wiki.document.service.DocumentService; +import com.wooteco.wiki.document.service.DocumentServiceJava; +import com.wooteco.wiki.global.common.ApiResponse; +import com.wooteco.wiki.global.common.ApiResponse.SuccessBody; +import com.wooteco.wiki.global.common.ApiResponseGenerator; +import com.wooteco.wiki.global.common.PageRequestDto; +import com.wooteco.wiki.global.common.ResponseDto; +import com.wooteco.wiki.history.domain.dto.HistoryDetailResponse; +import com.wooteco.wiki.history.domain.dto.HistoryResponse; +import com.wooteco.wiki.history.service.HistoryService; +import com.wooteco.wiki.organizationdocument.dto.OrganizationDocumentSearchResponse; +import io.swagger.v3.oas.annotations.Operation; +import java.util.List; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/document") +@RequiredArgsConstructor +public class DocumentController { + + private final DocumentService documentService; + private final HistoryService historyService; + private final DocumentSearchService documentSearchService; + private final DocumentServiceJava documentServiceJava; + + @Operation(summary = "위키 글 작성", description = "위키 글을 작성합니다.") + @PostMapping + public ApiResponse> post(@RequestBody CrewDocumentCreateRequest crewDocumentCreateRequest) { + DocumentResponse response = documentService.postCrewDocument(crewDocumentCreateRequest); + return ApiResponseGenerator.success(response); + } + + @Operation(summary = "랜덤 위키 글 조회", description = "랜덤으로 위키 글을 조회합니다.") + @GetMapping("/random") + public ApiResponse> getRandom() { + DocumentResponse response = documentService.getRandom(); + return ApiResponseGenerator.success(response); + } + + @Operation(summary = "위키 글 전체 조회", description = "페이지네이션을 통해 모든 위키 글을 조회합니다.") + @GetMapping("") + public ApiResponse>>> findAll(@ModelAttribute PageRequestDto pageRequestDto) { + Page pageResponses = documentService.findAll(pageRequestDto); + return ApiResponseGenerator.success(convertToResponse(pageResponses)); + } + + @Operation(summary = "제목으로 위키 글 조회", description = "제목을 통해 위키 글을 조회합니다.") + @GetMapping("title/{title}") + public ApiResponse> get(@PathVariable String title) { + Object response = documentService.get(title); + return ApiResponseGenerator.success(response); + } + + @Operation(summary = "제목으로 UUID 조회", description = "제목을 통해 위키 글의 UUID를 조회합니다.") + @GetMapping("title/{title}/uuid") + public ApiResponse> getUuidByTitle(@PathVariable String title) { + Object response = documentService.getUuidByTitle(title); + return ApiResponseGenerator.success(response); + } + + @Operation(summary = "UUID로 위키 글 조회", description = "UUID를 통해 위키 글을 조회합니다.") + @GetMapping("uuid/{uuidText}") + public ApiResponse> getByUuid(@PathVariable String uuidText) { + UUID uuid = UUID.fromString(uuidText); + Object response = documentService.getByUuid(uuid); + return ApiResponseGenerator.success(response); + } + + @Operation(summary = "문서 로그 목록 조회", description = "문서 UUID로 해당 문서의 로그 목록을 페이지네이션을 통해 조회합니다.") + @GetMapping("uuid/{uuidText}/log") + public ApiResponse>>> getLogs( + @PathVariable String uuidText, + @ModelAttribute PageRequestDto pageRequestDto + ) { + UUID uuid = UUID.fromString(uuidText); + Page pageResponses = historyService.findAllByDocumentUuid(uuid, pageRequestDto); + return ApiResponseGenerator.success(convertToResponse(pageResponses)); + } + + @Operation(summary = "로그 상세 조회", description = "로그 ID로 로그 상세 정보를 조회합니다.") + @GetMapping("/log/{logId}") + public ApiResponse> getDocumentLogs(@PathVariable Long logId) { + HistoryDetailResponse logDetail = historyService.getLogDetail(logId); + return ApiResponseGenerator.success(logDetail); + } + + @Operation(summary = "위키 글 수정", description = "위키 글을 수정합니다.") + @PutMapping + public ApiResponse> put( + @RequestBody DocumentUpdateRequest documentUpdateRequest + ) { + DocumentResponse response = documentService.put(documentUpdateRequest.uuid(), documentUpdateRequest); + return ApiResponseGenerator.success(response); + } + + @Operation(summary = "키워드로 위키 글 검색", description = "키워드로 위키 글을 검색합니다.") + @GetMapping("/search") + public ApiResponse>> search(@RequestParam String keyWord) { + return ApiResponseGenerator.success(documentSearchService.search(keyWord)); + } + + @Operation(summary = "누적 조회수 수신 API", description = "프론트에서 누적된 조회수를 전달받아 DB에 반영합니다.") + @PostMapping("/views/flush") + public ApiResponse> flushViews( + @RequestBody ViewFlushRequest request + ) { + documentService.flushViews(request.views()); + return ApiResponseGenerator.success("조회수 누적 완료"); + } + + @Operation(summary = "특정 문서에 대한 조직 문서 조회 API", description = "특정 문서에 대한 조직 문서들을 조회합니다.") + @GetMapping("/{uuidText}/organization-documents") + public ApiResponse>> readOrganizationDocument( + @PathVariable String uuidText + ) { + UUID uuid = UUID.fromString(uuidText); + return ApiResponseGenerator.success(documentServiceJava.searchOrganizationDocument(uuid)); + } + + private ResponseDto> convertToResponse(Page pageResponses) { + return ResponseDto.of( + pageResponses.getNumber(), + pageResponses.getTotalPages(), + pageResponses.getContent() + ); + } +} + diff --git a/src/main/java/com/wooteco/wiki/document/controller/DocumentController.kt b/src/main/java/com/wooteco/wiki/document/controller/DocumentController.kt deleted file mode 100644 index b153d33..0000000 --- a/src/main/java/com/wooteco/wiki/document/controller/DocumentController.kt +++ /dev/null @@ -1,132 +0,0 @@ -package com.wooteco.wiki.document.controller - -import com.wooteco.wiki.document.domain.Document -import com.wooteco.wiki.document.domain.dto.* -import com.wooteco.wiki.document.service.DocumentSearchService -import com.wooteco.wiki.document.service.DocumentService -import com.wooteco.wiki.document.service.DocumentServiceJava -import com.wooteco.wiki.global.common.ApiResponse -import com.wooteco.wiki.global.common.ApiResponse.SuccessBody -import com.wooteco.wiki.global.common.ApiResponseGenerator -import com.wooteco.wiki.global.common.PageRequestDto -import com.wooteco.wiki.global.common.ResponseDto -import com.wooteco.wiki.history.domain.dto.HistoryDetailResponse -import com.wooteco.wiki.history.domain.dto.HistoryResponse -import com.wooteco.wiki.history.service.HistoryService -import com.wooteco.wiki.organizationdocument.dto.OrganizationDocumentSearchResponse -import io.swagger.v3.oas.annotations.Operation -import org.springframework.data.domain.Page -import org.springframework.web.bind.annotation.* -import java.util.* - -@RestController -@RequestMapping("/document") -class DocumentController( - private val documentService: DocumentService, - private val historyService: HistoryService, - private val documentSearchService: DocumentSearchService, - private val documentServiceJava: DocumentServiceJava -) { - - @Operation(summary = "위키 글 작성", description = "위키 글을 작성합니다.") - @PostMapping - fun post(@RequestBody crewDocumentCreateRequest: CrewDocumentCreateRequest): ApiResponse> { - val response = documentService.postCrewDocument(crewDocumentCreateRequest) - return ApiResponseGenerator.success(response) - } - - @Operation(summary = "랜덤 위키 글 조회", description = "랜덤으로 위키 글을 조회합니다.") - @GetMapping("/random") - fun getRandom(): ApiResponse> { - val response = documentService.getRandom() - return ApiResponseGenerator.success(response) - } - - @Operation(summary = "위키 글 전체 조회", description = "페이지네이션을 통해 모든 위키 글을 조회합니다.") - @GetMapping("") - fun findAll(@ModelAttribute pageRequestDto: PageRequestDto): ApiResponse>>> { - val pageResponses = documentService.findAll(pageRequestDto) - return ApiResponseGenerator.success(convertToResponse(pageResponses)) - } - - @Operation(summary = "제목으로 위키 글 조회", description = "제목을 통해 위키 글을 조회합니다.") - @GetMapping("title/{title}") - fun get(@PathVariable title: String): ApiResponse> { - val response = documentService.get(title) - return ApiResponseGenerator.success(response) - } - - @Operation(summary = "제목으로 UUID 조회", description = "제목을 통해 위키 글의 UUID를 조회합니다.") - @GetMapping("title/{title}/uuid") - fun getUuidByTitle(@PathVariable title: String): ApiResponse> { - val response = documentService.getUuidByTitle(title) - return ApiResponseGenerator.success(response) - } - - @Operation(summary = "UUID로 위키 글 조회", description = "UUID를 통해 위키 글을 조회합니다.") - @GetMapping("uuid/{uuidText}") - fun getByUuid(@PathVariable uuidText: String): ApiResponse> { - val uuid = UUID.fromString(uuidText) - val response = documentService.getByUuid(uuid) - return ApiResponseGenerator.success(response) - } - - @Operation(summary = "문서 로그 목록 조회", description = "문서 UUID로 해당 문서의 로그 목록을 페이지네이션을 통해 조회합니다.") - @GetMapping("uuid/{uuidText}/log") - fun getLogs( - @PathVariable uuidText: String, - @ModelAttribute pageRequestDto: PageRequestDto - ): ApiResponse>>> { - val uuid = UUID.fromString(uuidText) - val pageResponses = historyService.findAllByDocumentUuid(uuid, pageRequestDto) - return ApiResponseGenerator.success(convertToResponse(pageResponses)) - } - - @Operation(summary = "로그 상세 조회", description = "로그 ID로 로그 상세 정보를 조회합니다.") - @GetMapping("/log/{logId}") - fun getDocumentLogs(@PathVariable logId: Long): ApiResponse> { - val logDetail = historyService.getLogDetail(logId) - return ApiResponseGenerator.success(logDetail) - } - - @Operation(summary = "위키 글 수정", description = "위키 글을 수정합니다.") - @PutMapping - fun put( - @RequestBody documentUpdateRequest: DocumentUpdateRequest - ): ApiResponse> { - val response = documentService.put(documentUpdateRequest.uuid, documentUpdateRequest) - return ApiResponseGenerator.success(response) - } - - @Operation(summary = "키워드로 위키 글 검색", description = "키워드로 위키 글을 검색합니다.") - @GetMapping("/search") - fun search(@RequestParam keyWord: String): ApiResponse>> { - return ApiResponseGenerator.success(documentSearchService.search(keyWord)) - } - - @Operation(summary = "누적 조회수 수신 API", description = "프론트에서 누적된 조회수를 전달받아 DB에 반영합니다.") - @PostMapping("/views/flush") - fun flushViews( - @RequestBody request: ViewFlushRequest - ): ApiResponse> { - documentService.flushViews(request.views) - return ApiResponseGenerator.success("조회수 누적 완료") - } - - @Operation(summary = "특정 문서에 대한 조직 문서 조회 API", description = "특정 문서에 대한 조직 문서들을 조회합니다.") - @GetMapping("/{uuidText}/organization-documents") - fun readOrganizationDocument( - @PathVariable uuidText: String - ): ApiResponse>> { - val uuid = UUID.fromString(uuidText) - return ApiResponseGenerator.success(documentServiceJava.searchOrganizationDocument(uuid)) - } - - private fun convertToResponse(pageResponses: Page): ResponseDto> { - return ResponseDto.of( - pageResponses.number, - pageResponses.totalPages, - pageResponses.content - ) - } -} diff --git a/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentResponse.java b/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentResponse.java new file mode 100644 index 0000000..78b1469 --- /dev/null +++ b/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentResponse.java @@ -0,0 +1,20 @@ +package com.wooteco.wiki.document.domain.dto; + +import com.wooteco.wiki.organizationdocument.dto.response.OrganizationDocumentResponse; +import java.time.LocalDateTime; +import java.util.List; +import java.util.UUID; + +public record DocumentResponse( + Long documentId, + UUID documentUUID, + String title, + String contents, + String writer, + LocalDateTime generateTime, + Integer viewCount, + Long latestVersion, + List organizationDocumentResponses +) { +} + diff --git a/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentResponse.kt b/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentResponse.kt deleted file mode 100644 index cdc2db8..0000000 --- a/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentResponse.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.wooteco.wiki.document.domain.dto - -import com.wooteco.wiki.organizationdocument.dto.response.OrganizationDocumentResponse -import java.time.LocalDateTime -import java.util.* - -data class DocumentResponse( - val documentId: Long, - var documentUUID: UUID, - val title: String, - val contents: String, - val writer: String, - val generateTime: LocalDateTime, - val viewCount: Int, - val latestVersion: Long, - val organizationDocumentResponses : List -) diff --git a/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentSearchResponse.java b/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentSearchResponse.java new file mode 100644 index 0000000..ae114a8 --- /dev/null +++ b/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentSearchResponse.java @@ -0,0 +1,12 @@ +package com.wooteco.wiki.document.domain.dto; + +import com.wooteco.wiki.document.domain.DocumentType; +import java.util.UUID; + +public record DocumentSearchResponse( + String title, + UUID uuid, + DocumentType documentType +) { +} + diff --git a/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentSearchResponse.kt b/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentSearchResponse.kt deleted file mode 100644 index 79f6165..0000000 --- a/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentSearchResponse.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.wooteco.wiki.document.domain.dto - -import com.wooteco.wiki.document.domain.DocumentType -import java.util.* - -data class DocumentSearchResponse( - val title: String, - val uuid: UUID, - val documentType: DocumentType -) diff --git a/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentUpdateRequest.java b/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentUpdateRequest.java new file mode 100644 index 0000000..cbc7209 --- /dev/null +++ b/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentUpdateRequest.java @@ -0,0 +1,13 @@ +package com.wooteco.wiki.document.domain.dto; + +import java.util.UUID; + +public record DocumentUpdateRequest( + String title, + String contents, + String writer, + Long documentBytes, + UUID uuid +) { +} + diff --git a/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentUpdateRequest.kt b/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentUpdateRequest.kt deleted file mode 100644 index 2c0a6bb..0000000 --- a/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentUpdateRequest.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.wooteco.wiki.document.domain.dto - -import java.util.* - -data class DocumentUpdateRequest( - val title: String, - val contents: String, - val writer: String, - val documentBytes: Long, - val uuid: UUID -) - diff --git a/src/main/java/com/wooteco/wiki/document/domain/dto/ViewFlushRequest.java b/src/main/java/com/wooteco/wiki/document/domain/dto/ViewFlushRequest.java new file mode 100644 index 0000000..0e9d6fe --- /dev/null +++ b/src/main/java/com/wooteco/wiki/document/domain/dto/ViewFlushRequest.java @@ -0,0 +1,10 @@ +package com.wooteco.wiki.document.domain.dto; + +import java.util.Map; +import java.util.UUID; + +public record ViewFlushRequest( + Map views +) { +} + diff --git a/src/main/java/com/wooteco/wiki/document/domain/dto/ViewFlushRequest.kt b/src/main/java/com/wooteco/wiki/document/domain/dto/ViewFlushRequest.kt deleted file mode 100644 index 793ddee..0000000 --- a/src/main/java/com/wooteco/wiki/document/domain/dto/ViewFlushRequest.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.wooteco.wiki.document.domain.dto - -import java.util.UUID - -data class ViewFlushRequest( - val views: Map -) diff --git a/src/main/java/com/wooteco/wiki/document/service/DocumentService.java b/src/main/java/com/wooteco/wiki/document/service/DocumentService.java index 7344526..cc9dd7c 100644 --- a/src/main/java/com/wooteco/wiki/document/service/DocumentService.java +++ b/src/main/java/com/wooteco/wiki/document/service/DocumentService.java @@ -17,8 +17,8 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Random; import java.util.UUID; -import kotlin.random.Random; import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -93,10 +93,10 @@ public DocumentResponse getByUuid(UUID uuid) { } public DocumentResponse put(UUID uuid, DocumentUpdateRequest request) { - String title = request.getTitle(); - String contents = request.getContents(); - String writer = request.getWriter(); - Long documentBytes = request.getDocumentBytes(); + String title = request.title(); + String contents = request.contents(); + String writer = request.writer(); + Long documentBytes = request.documentBytes(); Document document = documentRepository.findByUuid(uuid) .orElseThrow(() -> new WikiException(ErrorCode.DOCUMENT_NOT_FOUND)); diff --git a/src/main/java/com/wooteco/wiki/global/config/RandomConfig.java b/src/main/java/com/wooteco/wiki/global/config/RandomConfig.java new file mode 100644 index 0000000..29e0b33 --- /dev/null +++ b/src/main/java/com/wooteco/wiki/global/config/RandomConfig.java @@ -0,0 +1,15 @@ +package com.wooteco.wiki.global.config; + +import java.util.Random; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class RandomConfig { + + @Bean + public Random random() { + return new Random(); + } +} + diff --git a/src/main/java/com/wooteco/wiki/global/config/RandomConfig.kt b/src/main/java/com/wooteco/wiki/global/config/RandomConfig.kt deleted file mode 100644 index 7bdc80c..0000000 --- a/src/main/java/com/wooteco/wiki/global/config/RandomConfig.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.wooteco.wiki.global.config - -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import kotlin.random.Random - -@Configuration -class RandomConfig { - - @Bean - fun random(): Random = Random.Default -} diff --git a/src/test/java/com/wooteco/wiki/document/service/DocumentSearchServiceTest.java b/src/test/java/com/wooteco/wiki/document/service/DocumentSearchServiceTest.java index 33c5f00..aaa0e60 100644 --- a/src/test/java/com/wooteco/wiki/document/service/DocumentSearchServiceTest.java +++ b/src/test/java/com/wooteco/wiki/document/service/DocumentSearchServiceTest.java @@ -75,8 +75,8 @@ void search_success_has_valid_type() { // then assertSoftly(softly -> { softly.assertThat(result).hasSize(2); - softly.assertThat(result.get(0).getDocumentType()).isEqualTo(DocumentType.CREW); - softly.assertThat(result.get(1).getDocumentType()).isEqualTo(DocumentType.ORGANIZATION); + softly.assertThat(result.get(0).documentType()).isEqualTo(DocumentType.CREW); + softly.assertThat(result.get(1).documentType()).isEqualTo(DocumentType.ORGANIZATION); }); } } diff --git a/src/test/java/com/wooteco/wiki/document/service/DocumentServiceTest.java b/src/test/java/com/wooteco/wiki/document/service/DocumentServiceTest.java index 87cfd7c..de4f079 100644 --- a/src/test/java/com/wooteco/wiki/document/service/DocumentServiceTest.java +++ b/src/test/java/com/wooteco/wiki/document/service/DocumentServiceTest.java @@ -61,14 +61,14 @@ void getDocumentLatestVersion_success_byExistsDocument() { historyRepository.save(history); // when - DocumentUpdateRequest documentUpdateRequest = new DocumentUpdateRequest("test", "test", "test", 150, + DocumentUpdateRequest documentUpdateRequest = new DocumentUpdateRequest("test", "test", "test", 150L, savedCrewDocument.getUuid()); documentService.put(savedCrewDocument.getUuid(), documentUpdateRequest); DocumentResponse documentResponse = documentService.getByUuid(savedCrewDocument.getUuid()); // then - assertThat(documentResponse.getLatestVersion()).isEqualTo(21L); + assertThat(documentResponse.latestVersion()).isEqualTo(21L); } } @@ -84,10 +84,10 @@ void getUuidByTitle_success_byExistsDocumentTitle() { DocumentFixture.createDocumentCreateRequestDefault()); // when - DocumentUuidResponse documentUuidResponse = documentService.getUuidByTitle(documentResponse.getTitle()); + DocumentUuidResponse documentUuidResponse = documentService.getUuidByTitle(documentResponse.title()); // then - assertThat(documentUuidResponse.uuid()).isEqualTo(documentResponse.getDocumentUUID()); + assertThat(documentUuidResponse.uuid()).isEqualTo(documentResponse.documentUUID()); } @DisplayName("존재하지 않는 문서 제목으로 조회할 경우 예외를 반환한다 : WikiException.DOCUMENT_NOT_FOUND") @@ -262,7 +262,7 @@ void deleteById_success_byExistsId() { assertThat(historyRepository.findAll()).hasSize(1); // when - documentService.deleteByUuid(documentResponse.getDocumentUUID()); + documentService.deleteByUuid(documentResponse.documentUUID()); // after then assertThat(documentRepository.findAll()).hasSize(0); From ab6b65be726e4d70081d7dbbbbef8283c25db719 Mon Sep 17 00:00:00 2001 From: Mint Date: Sun, 11 Jan 2026 18:57:14 +0900 Subject: [PATCH 15/26] =?UTF-8?q?test:=20=EB=AC=B8=EC=84=9C=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=ED=85=8C=EC=8A=A4=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 - 조직 문서와 크루 문서 모두가 조회되는지 확인한다. --- .../repository/DocumentRepositoryTest.java | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/test/java/com/wooteco/wiki/document/repository/DocumentRepositoryTest.java b/src/test/java/com/wooteco/wiki/document/repository/DocumentRepositoryTest.java index f1798d9..c7ff920 100644 --- a/src/test/java/com/wooteco/wiki/document/repository/DocumentRepositoryTest.java +++ b/src/test/java/com/wooteco/wiki/document/repository/DocumentRepositoryTest.java @@ -1,8 +1,13 @@ package com.wooteco.wiki.document.repository; +import static org.assertj.core.api.SoftAssertions.assertSoftly; + import com.wooteco.wiki.document.domain.CrewDocument; import com.wooteco.wiki.document.domain.Document; +import com.wooteco.wiki.document.domain.DocumentType; import com.wooteco.wiki.document.fixture.DocumentFixture; +import com.wooteco.wiki.organizationdocument.domain.OrganizationDocument; +import com.wooteco.wiki.organizationdocument.fixture.OrganizationDocumentFixture; import java.util.List; import java.util.Optional; import java.util.Set; @@ -54,6 +59,66 @@ void findUuidByTitle_success_byExistsDocument() { @DisplayName("문서 전체 조회 기능") class findAll { + @DisplayName("DocumentRepository로 조회 시 CrewDocument와 OrganizationDocument가 모두 조회된다") + @Test + void findAll_success_returnsBothCrewAndOrganizationDocuments() { + // given + CrewDocument crewDocument = documentRepository.save( + DocumentFixture.createCrewDocument("crew문서", "content1", "writer1", 10L, UUID.randomUUID())); + OrganizationDocument organizationDocument = documentRepository.save( + OrganizationDocumentFixture.create("org문서", "content2", "writer2", 15L, UUID.randomUUID())); + + // when + List result = documentRepository.findAll(); + + // then + assertSoftly(softly -> { + softly.assertThat(result).hasSize(2); + softly.assertThat(result).extracting(Document::type) + .containsExactlyInAnyOrder(DocumentType.CREW, DocumentType.ORGANIZATION); + softly.assertThat(result).extracting(Document::getTitle) + .containsExactlyInAnyOrder("crew문서", "org문서"); + }); + } + + @DisplayName("CrewDocument만 저장했을 때는 CrewDocument만 조회된다") + @Test + void findAll_success_returnsOnlyCrewDocuments() { + // given + documentRepository.save( + DocumentFixture.createCrewDocument("crew1", "content1", "writer1", 10L, UUID.randomUUID())); + documentRepository.save( + DocumentFixture.createCrewDocument("crew2", "content2", "writer2", 15L, UUID.randomUUID())); + + // when + List result = documentRepository.findAll(); + + // then + assertSoftly(softly -> { + softly.assertThat(result).hasSize(2); + softly.assertThat(result).allMatch(doc -> doc.type() == DocumentType.CREW); + }); + } + + @DisplayName("OrganizationDocument만 저장했을 때는 OrganizationDocument만 조회된다") + @Test + void findAll_success_returnsOnlyOrganizationDocuments() { + // given + documentRepository.save( + OrganizationDocumentFixture.create("org1", "content1", "writer1", 10L, UUID.randomUUID())); + documentRepository.save( + OrganizationDocumentFixture.create("org2", "content2", "writer2", 15L, UUID.randomUUID())); + + // when + List result = documentRepository.findAll(); + + // then + assertSoftly(softly -> { + softly.assertThat(result).hasSize(2); + softly.assertThat(result).allMatch(doc -> doc.type() == DocumentType.ORGANIZATION); + }); + } + @DisplayName("문서가 여러개 존재했을 때 List 형태로 반환한다") @Test void findAll_success_bySomeData() { From b76d2d29a6b7c113554178b51ed8d7e19b925359 Mon Sep 17 00:00:00 2001 From: Mint Date: Sun, 11 Jan 2026 19:53:55 +0900 Subject: [PATCH 16/26] =?UTF-8?q?test:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EC=9D=80=20=EB=B3=80=EC=88=98=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=9C=20=EC=84=A0=EC=96=B8=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wiki/document/repository/DocumentRepositoryTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/wooteco/wiki/document/repository/DocumentRepositoryTest.java b/src/test/java/com/wooteco/wiki/document/repository/DocumentRepositoryTest.java index c7ff920..7f138c0 100644 --- a/src/test/java/com/wooteco/wiki/document/repository/DocumentRepositoryTest.java +++ b/src/test/java/com/wooteco/wiki/document/repository/DocumentRepositoryTest.java @@ -63,9 +63,9 @@ class findAll { @Test void findAll_success_returnsBothCrewAndOrganizationDocuments() { // given - CrewDocument crewDocument = documentRepository.save( + documentRepository.save( DocumentFixture.createCrewDocument("crew문서", "content1", "writer1", 10L, UUID.randomUUID())); - OrganizationDocument organizationDocument = documentRepository.save( + documentRepository.save( OrganizationDocumentFixture.create("org문서", "content2", "writer2", 15L, UUID.randomUUID())); // when From 027304ce4032a2c8e2b72c65460a988e87ca7a4b Mon Sep 17 00:00:00 2001 From: CheChe903 <137619133+CheChe903@users.noreply.github.com> Date: Mon, 12 Jan 2026 17:06:30 +0900 Subject: [PATCH 17/26] =?UTF-8?q?feat:=20=EC=A1=B0=EC=A7=81=EB=AC=B8?= =?UTF-8?q?=EC=84=9C=20=EC=88=98=EC=A0=95=EC=8B=9C=20=ED=9E=88=EC=8A=A4?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EC=A0=80=EC=9E=A5=20(#134)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/OrganizationDocumentService.java | 3 +++ .../OrganizationCrewDocumentServiceTest.java | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/main/java/com/wooteco/wiki/organizationdocument/service/OrganizationDocumentService.java b/src/main/java/com/wooteco/wiki/organizationdocument/service/OrganizationDocumentService.java index 479de67..098296c 100644 --- a/src/main/java/com/wooteco/wiki/organizationdocument/service/OrganizationDocumentService.java +++ b/src/main/java/com/wooteco/wiki/organizationdocument/service/OrganizationDocumentService.java @@ -7,6 +7,7 @@ import com.wooteco.wiki.document.repository.DocumentRepository; import com.wooteco.wiki.global.exception.ErrorCode; import com.wooteco.wiki.global.exception.WikiException; +import com.wooteco.wiki.history.service.HistoryService; import com.wooteco.wiki.organizationdocument.domain.OrganizationDocument; import com.wooteco.wiki.organizationdocument.dto.request.OrganizationDocumentCreateRequest; import com.wooteco.wiki.organizationdocument.dto.request.OrganizationDocumentUpdateRequest; @@ -32,6 +33,7 @@ public class OrganizationDocumentService { private final DocumentRepository documentRepository; private final DocumentOrganizationLinkService documentOrganizationLinkService; private final CrewDocumentRepository crewDocumentRepository; + private final HistoryService historyService; public OrganizationDocumentResponse create(OrganizationDocumentCreateRequest organizationDocumentCreateRequest) { if (documentRepository.existsByTitle(organizationDocumentCreateRequest.title())) { @@ -56,6 +58,7 @@ public OrganizationDocumentResponse update(OrganizationDocumentUpdateRequest org organizationDocumentUpdateRequest.documentBytes(), LocalDateTime.now() ); + historyService.save(organizationDocument); return new OrganizationDocumentResponse(organizationDocument); } diff --git a/src/test/java/com/wooteco/wiki/organizationdocument/service/OrganizationCrewDocumentServiceTest.java b/src/test/java/com/wooteco/wiki/organizationdocument/service/OrganizationCrewDocumentServiceTest.java index db9cbee..5a397cd 100644 --- a/src/test/java/com/wooteco/wiki/organizationdocument/service/OrganizationCrewDocumentServiceTest.java +++ b/src/test/java/com/wooteco/wiki/organizationdocument/service/OrganizationCrewDocumentServiceTest.java @@ -5,6 +5,8 @@ import com.wooteco.wiki.global.exception.ErrorCode; import com.wooteco.wiki.global.exception.WikiException; +import com.wooteco.wiki.history.domain.History; +import com.wooteco.wiki.history.repository.HistoryRepository; import com.wooteco.wiki.organizationdocument.domain.OrganizationDocument; import com.wooteco.wiki.organizationdocument.dto.request.OrganizationDocumentCreateRequest; import com.wooteco.wiki.organizationdocument.dto.request.OrganizationDocumentUpdateRequest; @@ -14,6 +16,7 @@ import com.wooteco.wiki.organizationevent.domain.OrganizationEvent; import com.wooteco.wiki.organizationevent.fixture.OrganizationEventFixture; import com.wooteco.wiki.organizationevent.repository.OrganizationEventRepository; +import java.util.List; import java.util.UUID; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; @@ -21,6 +24,8 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.test.annotation.DirtiesContext; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE) @@ -36,6 +41,9 @@ class OrganizationCrewDocumentServiceTest { @Autowired private OrganizationEventRepository organizationEventRepository; + @Autowired + private HistoryRepository historyRepository; + @DisplayName("조직 문서를 수정할 때") @Nested class Update { @@ -61,11 +69,20 @@ void updateOrganizationDocument_success_byValidData() { organizationDocument.getUuid()).orElseThrow(); // then + Page histories = historyRepository.findAllByDocumentId(organizationDocument.getId(), Pageable.ofSize(1)); + assertSoftly(softly -> { softly.assertThat(foundOrganizationDocument.getTitle()).isEqualTo(updateTitle); softly.assertThat(foundOrganizationDocument.getContents()).isEqualTo(updateContents); softly.assertThat(foundOrganizationDocument.getWriter()).isEqualTo(updateWriter); softly.assertThat(foundOrganizationDocument.getDocumentBytes()).isEqualTo(updateDocumentBytes); + softly.assertThat(histories.hasContent()).isTrue(); + + History first = histories.getContent().get(0); + softly.assertThat(first.getTitle()).isEqualTo(updateTitle); + softly.assertThat(first.getContents()).isEqualTo(updateContents); + softly.assertThat(first.getWriter()).isEqualTo(updateWriter); + softly.assertThat(first.getDocumentBytes()).isEqualTo(updateDocumentBytes); }); } } From f1910ca2b8bf083916fb536d6098df376899817d Mon Sep 17 00:00:00 2001 From: "2jin2.1031" <2jin2.1031@gmail.com> Date: Mon, 2 Feb 2026 06:34:41 +0900 Subject: [PATCH 18/26] =?UTF-8?q?feat:=20=ED=8A=B9=EC=A0=95=20=EB=AC=B8?= =?UTF-8?q?=EC=84=9C=EC=97=90=20=EB=8C=80=ED=95=9C=20=EC=A1=B0=EC=A7=81=20?= =?UTF-8?q?=EB=AC=B8=EC=84=9C=20=EC=82=AD=EC=A0=9C=20API=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../document/controller/DocumentController.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/java/com/wooteco/wiki/document/controller/DocumentController.java b/src/main/java/com/wooteco/wiki/document/controller/DocumentController.java index ee56d24..050e423 100644 --- a/src/main/java/com/wooteco/wiki/document/controller/DocumentController.java +++ b/src/main/java/com/wooteco/wiki/document/controller/DocumentController.java @@ -19,6 +19,7 @@ import java.util.UUID; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; +import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; @RestController @@ -125,6 +126,18 @@ public ApiResponse>> readOr return ApiResponseGenerator.success(documentServiceJava.searchOrganizationDocument(uuid)); } + @Operation(summary = "특정 문서에 대한 조직 문서 삭제 API", description = "특정 문서에 대한 조직 문서를 제거합니다.") + @DeleteMapping("/{uuidText}/organization-documents/{organizationDocumentUuidText}") + public ApiResponse> deleteOrganizationDocument( + @PathVariable String uuidText, + @PathVariable String organizationDocumentUuidText + ) { + UUID documentUuid = UUID.fromString(uuidText); + UUID organizationDocumentUuid = UUID.fromString(organizationDocumentUuidText); + documentServiceJava.deleteOrganizationDocument(documentUuid, organizationDocumentUuid); + return ApiResponseGenerator.success(HttpStatus.NO_CONTENT); + } + private ResponseDto> convertToResponse(Page pageResponses) { return ResponseDto.of( pageResponses.getNumber(), From e1d1253f2608338c90e42c9a99cedac9b10b0974 Mon Sep 17 00:00:00 2001 From: CheChe903 <137619133+CheChe903@users.noreply.github.com> Date: Sat, 7 Feb 2026 20:47:13 +0900 Subject: [PATCH 19/26] =?UTF-8?q?feat:=20=EC=A1=B0=EC=A7=81=20=EB=AC=B8?= =?UTF-8?q?=EC=84=9C=20=EC=83=9D=EC=84=B1=20=EC=8B=9C=20=EC=B2=AB=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=20=EC=A0=80=EC=9E=A5=20(#140)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/OrganizationDocumentService.java | 7 ++-- .../OrganizationCrewDocumentServiceTest.java | 37 +++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/wooteco/wiki/organizationdocument/service/OrganizationDocumentService.java b/src/main/java/com/wooteco/wiki/organizationdocument/service/OrganizationDocumentService.java index 098296c..520c10e 100644 --- a/src/main/java/com/wooteco/wiki/organizationdocument/service/OrganizationDocumentService.java +++ b/src/main/java/com/wooteco/wiki/organizationdocument/service/OrganizationDocumentService.java @@ -41,9 +41,10 @@ public OrganizationDocumentResponse create(OrganizationDocumentCreateRequest org } CrewDocument crewDocument = getCrewDocument(organizationDocumentCreateRequest.crewDocumentUuid()); OrganizationDocument organizationDocument = organizationDocumentCreateRequest.toOrganizationDocument(); - organizationDocumentRepository.save(organizationDocument); - documentOrganizationLinkService.link(crewDocument, organizationDocument); - return new OrganizationDocumentResponse(organizationDocument); + OrganizationDocument savedOrganizationDocument = organizationDocumentRepository.save(organizationDocument); + historyService.save(savedOrganizationDocument); + documentOrganizationLinkService.link(crewDocument, savedOrganizationDocument); + return new OrganizationDocumentResponse(savedOrganizationDocument); } public OrganizationDocumentResponse update(OrganizationDocumentUpdateRequest organizationDocumentUpdateRequest) { diff --git a/src/test/java/com/wooteco/wiki/organizationdocument/service/OrganizationCrewDocumentServiceTest.java b/src/test/java/com/wooteco/wiki/organizationdocument/service/OrganizationCrewDocumentServiceTest.java index 5a397cd..d87d057 100644 --- a/src/test/java/com/wooteco/wiki/organizationdocument/service/OrganizationCrewDocumentServiceTest.java +++ b/src/test/java/com/wooteco/wiki/organizationdocument/service/OrganizationCrewDocumentServiceTest.java @@ -3,6 +3,9 @@ import static org.assertj.core.api.SoftAssertions.assertSoftly; import static org.junit.jupiter.api.Assertions.assertThrows; +import com.wooteco.wiki.document.domain.CrewDocument; +import com.wooteco.wiki.document.fixture.DocumentFixture; +import com.wooteco.wiki.document.repository.CrewDocumentRepository; import com.wooteco.wiki.global.exception.ErrorCode; import com.wooteco.wiki.global.exception.WikiException; import com.wooteco.wiki.history.domain.History; @@ -11,6 +14,7 @@ import com.wooteco.wiki.organizationdocument.dto.request.OrganizationDocumentCreateRequest; import com.wooteco.wiki.organizationdocument.dto.request.OrganizationDocumentUpdateRequest; import com.wooteco.wiki.organizationdocument.dto.response.OrganizationDocumentAndEventResponse; +import com.wooteco.wiki.organizationdocument.dto.response.OrganizationDocumentResponse; import com.wooteco.wiki.organizationdocument.fixture.OrganizationDocumentFixture; import com.wooteco.wiki.organizationdocument.repository.OrganizationDocumentRepository; import com.wooteco.wiki.organizationevent.domain.OrganizationEvent; @@ -44,6 +48,9 @@ class OrganizationCrewDocumentServiceTest { @Autowired private HistoryRepository historyRepository; + @Autowired + private CrewDocumentRepository crewDocumentRepository; + @DisplayName("조직 문서를 수정할 때") @Nested class Update { @@ -144,6 +151,36 @@ void create_success_byValidData() { Assertions.assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.DOCUMENT_DUPLICATE); } + @DisplayName("첫 번째 로그가 저장된다.") + @Test + void create_success_savesFirstHistory() { + // given + CrewDocument crewDocument = DocumentFixture.createDefaultCrewDocument(); + CrewDocument savedCrewDocument = crewDocumentRepository.save(crewDocument); + + OrganizationDocumentCreateRequest organizationDocumentCreateRequest = new OrganizationDocumentCreateRequest( + "newTitle", "newContents", "newWriter", 99L, savedCrewDocument.getUuid(), UUID.randomUUID()); + + // when + OrganizationDocumentResponse response = organizationDocumentService.create(organizationDocumentCreateRequest); + OrganizationDocument savedOrganizationDocument = organizationDocumentRepository.findByUuid( + response.organizationDocumentUuid()).orElseThrow(); + + // then + Page histories = historyRepository.findAllByDocumentId(savedOrganizationDocument.getId(), + Pageable.ofSize(1)); + + assertSoftly(softly -> { + softly.assertThat(histories.hasContent()).isTrue(); + History first = histories.getContent().get(0); + softly.assertThat(first.getVersion()).isEqualTo(1L); + softly.assertThat(first.getTitle()).isEqualTo("newTitle"); + softly.assertThat(first.getContents()).isEqualTo("newContents"); + softly.assertThat(first.getWriter()).isEqualTo("newWriter"); + softly.assertThat(first.getDocumentBytes()).isEqualTo(99L); + }); + } + // @DisplayName("존재하지 않는 특정 문서의 Uuid로 요청한다면 예외가 발생한다 : DOCUMENT_NOT_FOUND") // @Test // void addOrganizationDocument_error_byNonExistingDocumentUuid() { From 7731cbf2ad497021aefafd0c86cd390ad3cb992d Mon Sep 17 00:00:00 2001 From: CheChe903 <137619133+CheChe903@users.noreply.github.com> Date: Sat, 7 Feb 2026 20:47:23 +0900 Subject: [PATCH 20/26] =?UTF-8?q?feat:=20=EB=AC=B8=EC=84=9C=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=EC=8B=9C=20=EB=AC=B8=EC=84=9C=20=ED=83=80=EC=9E=85?= =?UTF-8?q?=EC=9D=84=20=EC=9D=91=EB=8B=B5=EC=97=90=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?(#142)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DocumentController.java | 6 ++-- .../wiki/document/domain/Document.java | 4 +++ .../domain/dto/DocumentListResponse.java | 32 +++++++++++++++++++ 3 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/wooteco/wiki/document/domain/dto/DocumentListResponse.java diff --git a/src/main/java/com/wooteco/wiki/document/controller/DocumentController.java b/src/main/java/com/wooteco/wiki/document/controller/DocumentController.java index 050e423..83b6dd9 100644 --- a/src/main/java/com/wooteco/wiki/document/controller/DocumentController.java +++ b/src/main/java/com/wooteco/wiki/document/controller/DocumentController.java @@ -48,9 +48,10 @@ public ApiResponse> getRandom() { @Operation(summary = "위키 글 전체 조회", description = "페이지네이션을 통해 모든 위키 글을 조회합니다.") @GetMapping("") - public ApiResponse>>> findAll(@ModelAttribute PageRequestDto pageRequestDto) { + public ApiResponse>>> findAll(@ModelAttribute PageRequestDto pageRequestDto) { Page pageResponses = documentService.findAll(pageRequestDto); - return ApiResponseGenerator.success(convertToResponse(pageResponses)); + Page responses = pageResponses.map(DocumentListResponse::from); + return ApiResponseGenerator.success(convertToResponse(responses)); } @Operation(summary = "제목으로 위키 글 조회", description = "제목을 통해 위키 글을 조회합니다.") @@ -146,4 +147,3 @@ private ResponseDto> convertToResponse(Page pageResponses) { ); } } - diff --git a/src/main/java/com/wooteco/wiki/document/domain/Document.java b/src/main/java/com/wooteco/wiki/document/domain/Document.java index 178dccf..3220ccc 100644 --- a/src/main/java/com/wooteco/wiki/document/domain/Document.java +++ b/src/main/java/com/wooteco/wiki/document/domain/Document.java @@ -87,6 +87,10 @@ public void changeViewCount(int viewCount) { this.viewCount = viewCount; } + public DocumentType getDocumentType() { + return type(); + } + public abstract DocumentType type(); @Override diff --git a/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentListResponse.java b/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentListResponse.java new file mode 100644 index 0000000..bc64652 --- /dev/null +++ b/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentListResponse.java @@ -0,0 +1,32 @@ +package com.wooteco.wiki.document.domain.dto; + +import com.wooteco.wiki.document.domain.Document; +import com.wooteco.wiki.document.domain.DocumentType; +import java.time.LocalDateTime; +import java.util.UUID; + +public record DocumentListResponse( + Long id, + String title, + String contents, + String writer, + Long documentBytes, + LocalDateTime generateTime, + UUID uuid, + Integer viewCount, + DocumentType documentType +) { + public static DocumentListResponse from(Document document) { + return new DocumentListResponse( + document.getId(), + document.getTitle(), + document.getContents(), + document.getWriter(), + document.getDocumentBytes(), + document.getGenerateTime(), + document.getUuid(), + document.getViewCount(), + document.type() + ); + } +} From 1ae401e256de87feb6f3523600c9a9cac3971723 Mon Sep 17 00:00:00 2001 From: "2jin2.1031" <2jin2.1031@gmail.com> Date: Mon, 23 Feb 2026 17:07:55 +0900 Subject: [PATCH 21/26] =?UTF-8?q?feat:=20=ED=81=AC=EB=A3=A8=EB=AC=B8?= =?UTF-8?q?=EC=84=9C=20=EC=82=AD=EC=A0=9C=20=EC=8B=9C,=20=EC=A1=B0?= =?UTF-8?q?=EC=A7=81=20=EB=AC=B8=EC=84=9C=20=EC=97=B0=EA=B2=B0=20=ED=95=B4?= =?UTF-8?q?=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wiki/admin/service/AdminService.java | 11 +- .../admin/service/CrewDocumentService.java | 116 ++++++++++++++++++ .../DocumentOrganizationLinkService.java | 4 + 3 files changed, 124 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/wooteco/wiki/admin/service/CrewDocumentService.java diff --git a/src/main/java/com/wooteco/wiki/admin/service/AdminService.java b/src/main/java/com/wooteco/wiki/admin/service/AdminService.java index 53d27e3..58b779b 100644 --- a/src/main/java/com/wooteco/wiki/admin/service/AdminService.java +++ b/src/main/java/com/wooteco/wiki/admin/service/AdminService.java @@ -1,19 +1,16 @@ package com.wooteco.wiki.admin.service; -import com.wooteco.wiki.document.service.DocumentService; import java.util.UUID; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +@RequiredArgsConstructor @Service public class AdminService { - private final DocumentService documentService; - - public AdminService(DocumentService documentService) { - this.documentService = documentService; - } + private final CrewDocumentService crewDocumentService; public void deleteDocumentByDocumentUuid(UUID documentUuid) { - documentService.deleteByUuid(documentUuid); + crewDocumentService.deleteByUuid(documentUuid); } } diff --git a/src/main/java/com/wooteco/wiki/admin/service/CrewDocumentService.java b/src/main/java/com/wooteco/wiki/admin/service/CrewDocumentService.java new file mode 100644 index 0000000..ce40f9a --- /dev/null +++ b/src/main/java/com/wooteco/wiki/admin/service/CrewDocumentService.java @@ -0,0 +1,116 @@ +package com.wooteco.wiki.admin.service; + +import com.wooteco.wiki.document.domain.CrewDocument; +import com.wooteco.wiki.document.domain.Document; +import com.wooteco.wiki.document.domain.dto.CrewDocumentCreateRequest; +import com.wooteco.wiki.document.domain.dto.DocumentResponse; +import com.wooteco.wiki.document.domain.dto.DocumentUpdateRequest; +import com.wooteco.wiki.document.repository.CrewDocumentRepository; +import com.wooteco.wiki.document.repository.DocumentRepository; +import com.wooteco.wiki.global.exception.ErrorCode; +import com.wooteco.wiki.global.exception.WikiException; +import com.wooteco.wiki.history.service.HistoryService; +import com.wooteco.wiki.organizationdocument.dto.response.OrganizationDocumentResponse; +import com.wooteco.wiki.organizationdocument.service.DocumentOrganizationLinkService; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Random; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class CrewDocumentService { + + private final DocumentOrganizationLinkService documentOrganizationLinkService; + private final CrewDocumentRepository crewDocumentRepository; + private final DocumentRepository documentRepository; + private final HistoryService historyService; + private final Random random; + + @Transactional + public void deleteByUuid(UUID documentUuid) { + CrewDocument crewDocument = crewDocumentRepository.findByUuid(documentUuid) + .orElseThrow(() -> new WikiException(ErrorCode.DOCUMENT_NOT_FOUND)); + + documentOrganizationLinkService.unlinkAll(crewDocument); + + documentRepository.deleteByUuid(documentUuid); + } + + @Transactional + public DocumentResponse create(CrewDocumentCreateRequest request) { + String title = request.title(); + if (documentRepository.existsByTitle(title)) { + throw new WikiException(ErrorCode.DOCUMENT_DUPLICATE); + } + + CrewDocument crewDocument = request.toCrewDocument(); + CrewDocument savedDocument = crewDocumentRepository.save(crewDocument); + historyService.save(savedDocument); + return mapToResponse(savedDocument); + } + + public DocumentResponse getByUuid(UUID uuid) { + CrewDocument crewDocument = crewDocumentRepository.findByUuid(uuid) + .orElseThrow(() -> new WikiException(ErrorCode.DOCUMENT_NOT_FOUND)); + return mapToResponse(crewDocument); + } + + public DocumentResponse getByTitle(String title) { + Document document = documentRepository.findByTitle(title) + .orElseThrow(() -> new WikiException(ErrorCode.DOCUMENT_NOT_FOUND)); + + if (!(document instanceof CrewDocument crewDocument)) { + throw new WikiException(ErrorCode.DOCUMENT_NOT_FOUND); + } + + return mapToResponse(crewDocument); + } + + public DocumentResponse getRandom() { + List documents = crewDocumentRepository.findAll(); + if (documents.isEmpty()) { + throw new WikiException(ErrorCode.DOCUMENT_NOT_FOUND); + } + CrewDocument document = documents.get(random.nextInt(documents.size())); + return mapToResponse(document); + } + + @Transactional + public DocumentResponse update(UUID uuid, DocumentUpdateRequest request) { + CrewDocument crewDocument = crewDocumentRepository.findByUuid(uuid) + .orElseThrow(() -> new WikiException(ErrorCode.DOCUMENT_NOT_FOUND)); + + Document updateData = crewDocument.update( + request.title(), + request.contents(), + request.writer(), + request.documentBytes(), + LocalDateTime.now() + ); + historyService.save(updateData); + return mapToResponse(crewDocument); + } + + private DocumentResponse mapToResponse(CrewDocument crewDocument) { + long latestVersion = historyService.findLatestVersionByDocument(crewDocument); + List organizationDocumentResponses = + documentOrganizationLinkService.findOrganizationDocumentResponsesByDocument(crewDocument); + + return new DocumentResponse( + crewDocument.getId(), + crewDocument.getUuid(), + crewDocument.getTitle(), + crewDocument.getContents(), + crewDocument.getWriter(), + crewDocument.getGenerateTime(), + crewDocument.getViewCount(), + latestVersion, + organizationDocumentResponses + ); + } +} diff --git a/src/main/java/com/wooteco/wiki/organizationdocument/service/DocumentOrganizationLinkService.java b/src/main/java/com/wooteco/wiki/organizationdocument/service/DocumentOrganizationLinkService.java index a219e1f..fcce58a 100644 --- a/src/main/java/com/wooteco/wiki/organizationdocument/service/DocumentOrganizationLinkService.java +++ b/src/main/java/com/wooteco/wiki/organizationdocument/service/DocumentOrganizationLinkService.java @@ -27,6 +27,10 @@ public void unlink(CrewDocument crewDocument, OrganizationDocument organizationD documentOrgDocLinkRepository.deleteByCrewDocumentAndOrganizationDocument(crewDocument, organizationDocument); } + public void unlinkAll(CrewDocument crewDocument) { + documentOrgDocLinkRepository.deleteAllByCrewDocument(crewDocument); + } + @Transactional(readOnly = true) public List findOrganizationDocumentResponsesByDocument(CrewDocument crewDocument) { List documentOrganizationLinks = documentOrgDocLinkRepository.findAllByCrewDocument( From 937a1890a4da0b99694596bda49b1bb80e7d29df Mon Sep 17 00:00:00 2001 From: "2jin2.1031" <2jin2.1031@gmail.com> Date: Mon, 23 Feb 2026 17:49:41 +0900 Subject: [PATCH 22/26] =?UTF-8?q?feat:=20DocumentService=EC=97=90=EC=84=9C?= =?UTF-8?q?=20CrewDocumentService=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/service/CrewDocumentService.java | 12 +- .../controller/DocumentController.java | 16 +- .../document/domain/dto/DocumentResponse.java | 35 +++- .../document/service/DocumentService.java | 117 +----------- .../DocumentOrganizationLinkRepository.java | 2 + .../service/CrewDocumentServiceTest.java | 98 ++++++++++ .../document/service/DocumentServiceTest.java | 170 ++++++------------ 7 files changed, 196 insertions(+), 254 deletions(-) create mode 100644 src/test/java/com/wooteco/wiki/document/service/CrewDocumentServiceTest.java diff --git a/src/main/java/com/wooteco/wiki/admin/service/CrewDocumentService.java b/src/main/java/com/wooteco/wiki/admin/service/CrewDocumentService.java index ce40f9a..1eea9eb 100644 --- a/src/main/java/com/wooteco/wiki/admin/service/CrewDocumentService.java +++ b/src/main/java/com/wooteco/wiki/admin/service/CrewDocumentService.java @@ -101,16 +101,6 @@ private DocumentResponse mapToResponse(CrewDocument crewDocument) { List organizationDocumentResponses = documentOrganizationLinkService.findOrganizationDocumentResponsesByDocument(crewDocument); - return new DocumentResponse( - crewDocument.getId(), - crewDocument.getUuid(), - crewDocument.getTitle(), - crewDocument.getContents(), - crewDocument.getWriter(), - crewDocument.getGenerateTime(), - crewDocument.getViewCount(), - latestVersion, - organizationDocumentResponses - ); + return DocumentResponse.toDocumentResponse(crewDocument, latestVersion, organizationDocumentResponses); } } diff --git a/src/main/java/com/wooteco/wiki/document/controller/DocumentController.java b/src/main/java/com/wooteco/wiki/document/controller/DocumentController.java index 83b6dd9..8773214 100644 --- a/src/main/java/com/wooteco/wiki/document/controller/DocumentController.java +++ b/src/main/java/com/wooteco/wiki/document/controller/DocumentController.java @@ -1,5 +1,6 @@ package com.wooteco.wiki.document.controller; +import com.wooteco.wiki.admin.service.CrewDocumentService; import com.wooteco.wiki.document.domain.Document; import com.wooteco.wiki.document.domain.dto.*; import com.wooteco.wiki.document.service.DocumentSearchService; @@ -27,6 +28,7 @@ @RequiredArgsConstructor public class DocumentController { + private final CrewDocumentService crewDocumentService; private final DocumentService documentService; private final HistoryService historyService; private final DocumentSearchService documentSearchService; @@ -35,14 +37,14 @@ public class DocumentController { @Operation(summary = "위키 글 작성", description = "위키 글을 작성합니다.") @PostMapping public ApiResponse> post(@RequestBody CrewDocumentCreateRequest crewDocumentCreateRequest) { - DocumentResponse response = documentService.postCrewDocument(crewDocumentCreateRequest); + DocumentResponse response = crewDocumentService.create(crewDocumentCreateRequest); return ApiResponseGenerator.success(response); } @Operation(summary = "랜덤 위키 글 조회", description = "랜덤으로 위키 글을 조회합니다.") @GetMapping("/random") public ApiResponse> getRandom() { - DocumentResponse response = documentService.getRandom(); + DocumentResponse response = crewDocumentService.getRandom(); return ApiResponseGenerator.success(response); } @@ -56,8 +58,8 @@ public ApiResponse>>> findAll @Operation(summary = "제목으로 위키 글 조회", description = "제목을 통해 위키 글을 조회합니다.") @GetMapping("title/{title}") - public ApiResponse> get(@PathVariable String title) { - Object response = documentService.get(title); + public ApiResponse> get(@PathVariable String title) { + DocumentResponse response = crewDocumentService.getByTitle(title); return ApiResponseGenerator.success(response); } @@ -70,9 +72,9 @@ public ApiResponse> getUuidByTitle(@PathVariable String titl @Operation(summary = "UUID로 위키 글 조회", description = "UUID를 통해 위키 글을 조회합니다.") @GetMapping("uuid/{uuidText}") - public ApiResponse> getByUuid(@PathVariable String uuidText) { + public ApiResponse> getByUuid(@PathVariable String uuidText) { UUID uuid = UUID.fromString(uuidText); - Object response = documentService.getByUuid(uuid); + DocumentResponse response = crewDocumentService.getByUuid(uuid); return ApiResponseGenerator.success(response); } @@ -99,7 +101,7 @@ public ApiResponse> getDocumentLogs(@PathVari public ApiResponse> put( @RequestBody DocumentUpdateRequest documentUpdateRequest ) { - DocumentResponse response = documentService.put(documentUpdateRequest.uuid(), documentUpdateRequest); + DocumentResponse response = crewDocumentService.update(documentUpdateRequest.uuid(), documentUpdateRequest); return ApiResponseGenerator.success(response); } diff --git a/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentResponse.java b/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentResponse.java index 78b1469..da1b8d5 100644 --- a/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentResponse.java +++ b/src/main/java/com/wooteco/wiki/document/domain/dto/DocumentResponse.java @@ -1,20 +1,39 @@ package com.wooteco.wiki.document.domain.dto; +import com.wooteco.wiki.document.domain.CrewDocument; import com.wooteco.wiki.organizationdocument.dto.response.OrganizationDocumentResponse; import java.time.LocalDateTime; import java.util.List; import java.util.UUID; public record DocumentResponse( - Long documentId, - UUID documentUUID, - String title, - String contents, - String writer, - LocalDateTime generateTime, - Integer viewCount, + Long documentId, + UUID documentUUID, + String title, + String contents, + String writer, + LocalDateTime generateTime, + Integer viewCount, + Long latestVersion, + List organizationDocumentResponses +) { + + public static DocumentResponse toDocumentResponse( + CrewDocument crewDocument, Long latestVersion, List organizationDocumentResponses -) { + ) { + return new DocumentResponse( + crewDocument.getId(), + crewDocument.getUuid(), + crewDocument.getTitle(), + crewDocument.getContents(), + crewDocument.getWriter(), + crewDocument.getGenerateTime(), + crewDocument.getViewCount(), + latestVersion, + organizationDocumentResponses + ); + } } diff --git a/src/main/java/com/wooteco/wiki/document/service/DocumentService.java b/src/main/java/com/wooteco/wiki/document/service/DocumentService.java index cc9dd7c..eea24ce 100644 --- a/src/main/java/com/wooteco/wiki/document/service/DocumentService.java +++ b/src/main/java/com/wooteco/wiki/document/service/DocumentService.java @@ -1,111 +1,37 @@ package com.wooteco.wiki.document.service; -import com.wooteco.wiki.document.domain.CrewDocument; import com.wooteco.wiki.document.domain.Document; -import com.wooteco.wiki.document.domain.dto.CrewDocumentCreateRequest; -import com.wooteco.wiki.document.domain.dto.DocumentResponse; -import com.wooteco.wiki.document.domain.dto.DocumentUpdateRequest; import com.wooteco.wiki.document.domain.dto.DocumentUuidResponse; import com.wooteco.wiki.document.repository.DocumentRepository; import com.wooteco.wiki.global.common.PageRequestDto; import com.wooteco.wiki.global.exception.ErrorCode; import com.wooteco.wiki.global.exception.WikiException; -import com.wooteco.wiki.history.service.HistoryService; -import com.wooteco.wiki.organizationdocument.dto.response.OrganizationDocumentResponse; -import com.wooteco.wiki.organizationdocument.service.DocumentOrganizationLinkService; -import java.time.LocalDateTime; -import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Random; import java.util.UUID; +import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +@RequiredArgsConstructor +@Transactional(readOnly = true) @Service -@Transactional public class DocumentService { private final DocumentRepository documentRepository; - private final DocumentOrganizationLinkService organizationDocumentLinkService; - private final HistoryService historyService; - private final Random random; - public DocumentService( - DocumentRepository documentRepository, - DocumentOrganizationLinkService organizationDocumentLinkService, - HistoryService historyService, - Random random - ) { - this.documentRepository = documentRepository; - this.organizationDocumentLinkService = organizationDocumentLinkService; - this.historyService = historyService; - this.random = random; - } - - public DocumentResponse postCrewDocument(CrewDocumentCreateRequest request) { - String title = request.title(); - if (documentRepository.existsByTitle(title)) { - throw new WikiException(ErrorCode.DOCUMENT_DUPLICATE); - } - - CrewDocument crewDocument = request.toCrewDocument(); - Document savedDocument = documentRepository.save(crewDocument); - historyService.save(savedDocument); - return mapToResponse(savedDocument); - } - - @Transactional(readOnly = true) - public DocumentResponse getRandom() { - List documents = documentRepository.findAll(); - if (documents.isEmpty()) { - throw new WikiException(ErrorCode.DOCUMENT_NOT_FOUND); - } - Document document = documents.get(random.nextInt(documents.size())); - return mapToResponse(document); - } - - @Transactional(readOnly = true) public Page findAll(PageRequestDto requestDto) { return documentRepository.findAll(requestDto.toPageable()); } - @Transactional(readOnly = true) - public DocumentResponse get(String title) { - Document document = documentRepository.findByTitle(title) - .orElseThrow(() -> new WikiException(ErrorCode.DOCUMENT_NOT_FOUND)); - return mapToResponse(document); - } - - @Transactional(readOnly = true) public DocumentUuidResponse getUuidByTitle(String title) { return documentRepository.findUuidByTitle(title) - .map(DocumentUuidResponse::new) - .orElseThrow(() -> new WikiException(ErrorCode.DOCUMENT_NOT_FOUND)); - } - - @Transactional(readOnly = true) - public DocumentResponse getByUuid(UUID uuid) { - Document document = documentRepository.findByUuid(uuid) - .orElseThrow(() -> new WikiException(ErrorCode.DOCUMENT_NOT_FOUND)); - return mapToResponse(document); - } - - public DocumentResponse put(UUID uuid, DocumentUpdateRequest request) { - String title = request.title(); - String contents = request.contents(); - String writer = request.writer(); - Long documentBytes = request.documentBytes(); - - Document document = documentRepository.findByUuid(uuid) - .orElseThrow(() -> new WikiException(ErrorCode.DOCUMENT_NOT_FOUND)); - - Document updateData = document.update(title, contents, writer, documentBytes, LocalDateTime.now()); - historyService.save(updateData); - return mapToResponse(document); + .map(DocumentUuidResponse::new) + .orElseThrow(() -> new WikiException(ErrorCode.DOCUMENT_NOT_FOUND)); } + @Transactional public void flushViews(Map views) { List documents = documentRepository.findAllByUuidIn(views.keySet()); @@ -119,36 +45,5 @@ public void flushViews(Map views) { documentRepository.saveAll(documents); } - - public void deleteByUuid(UUID documentUuid) { - documentRepository.findByUuid(documentUuid) - .orElseThrow(() -> new WikiException(ErrorCode.DOCUMENT_NOT_FOUND)); - documentRepository.deleteByUuid(documentUuid); - } - - private DocumentResponse mapToResponse(Document document) { - long latestVersion = historyService.findLatestVersionByDocument(document); - List organizationDocumentResponses = - (document instanceof CrewDocument crew) - ? organizationDocumentLinkService.findOrganizationDocumentResponsesByDocument(crew) - : Collections.emptyList(); - - return new DocumentResponse( - document.getId() != null ? document.getId() : - throwNotFound(), - document.getUuid(), - document.getTitle(), - document.getContents(), - document.getWriter(), - document.getGenerateTime(), - document.getViewCount(), - latestVersion, - organizationDocumentResponses - ); - } - - private Long throwNotFound() { - throw new WikiException(ErrorCode.DOCUMENT_NOT_FOUND); - } } diff --git a/src/main/java/com/wooteco/wiki/organizationdocument/repository/DocumentOrganizationLinkRepository.java b/src/main/java/com/wooteco/wiki/organizationdocument/repository/DocumentOrganizationLinkRepository.java index 50b350e..5d6b498 100644 --- a/src/main/java/com/wooteco/wiki/organizationdocument/repository/DocumentOrganizationLinkRepository.java +++ b/src/main/java/com/wooteco/wiki/organizationdocument/repository/DocumentOrganizationLinkRepository.java @@ -18,4 +18,6 @@ void deleteByCrewDocumentAndOrganizationDocument(CrewDocument crewDocument, OrganizationDocument organizationDocument); List findAllByCrewDocument(CrewDocument crewDocument); + + void deleteAllByCrewDocument(CrewDocument crewDocument); } diff --git a/src/test/java/com/wooteco/wiki/document/service/CrewDocumentServiceTest.java b/src/test/java/com/wooteco/wiki/document/service/CrewDocumentServiceTest.java new file mode 100644 index 0000000..30457c5 --- /dev/null +++ b/src/test/java/com/wooteco/wiki/document/service/CrewDocumentServiceTest.java @@ -0,0 +1,98 @@ +package com.wooteco.wiki.document.service; + +import static com.wooteco.wiki.global.exception.ErrorCode.DOCUMENT_NOT_FOUND; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import com.wooteco.wiki.admin.service.CrewDocumentService; +import com.wooteco.wiki.document.domain.CrewDocument; +import com.wooteco.wiki.document.domain.dto.DocumentResponse; +import com.wooteco.wiki.document.domain.dto.DocumentUpdateRequest; +import com.wooteco.wiki.document.fixture.DocumentFixture; +import com.wooteco.wiki.document.repository.DocumentRepository; +import com.wooteco.wiki.global.exception.WikiException; +import com.wooteco.wiki.history.domain.History; +import com.wooteco.wiki.history.fixture.HistoryFixture; +import com.wooteco.wiki.history.repository.HistoryRepository; +import java.time.LocalDateTime; +import java.util.UUID; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE) +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) +class CrewDocumentServiceTest { + + @Autowired + private CrewDocumentService crewDocumentService; + @Autowired + private DocumentRepository documentRepository; + @Autowired + private HistoryRepository historyRepository; + + @DisplayName("문서 조회 기능") + @Nested + class Find { + + @DisplayName("문서 조회시, 해당 문서의 마지막 로그 번호를 가져온다.") + @Test + void getDocumentLatestVersion_success_byExistsDocument() { + // given + CrewDocument crewDocument = DocumentFixture.createDefaultCrewDocument(); + CrewDocument savedCrewDocument = documentRepository.save(crewDocument); + + History history = HistoryFixture.create("test", "test", "tesst", 150, + LocalDateTime.of(2025, 7, 15, 10, 0, 0), + savedCrewDocument, 20L); + historyRepository.save(history); + + // when + DocumentUpdateRequest documentUpdateRequest = new DocumentUpdateRequest("test", "test", "test", 150L, + savedCrewDocument.getUuid()); + + crewDocumentService.update(savedCrewDocument.getUuid(), documentUpdateRequest); + DocumentResponse documentResponse = crewDocumentService.getByUuid(savedCrewDocument.getUuid()); + + // then + assertThat(documentResponse.latestVersion()).isEqualTo(21L); + } + } + + @Nested + @DisplayName("문서 uuid로 삭제 기능") + class deleteByUuid { + + @DisplayName("존재하는 문서 id일 경우 문서가 로그들과 함께 삭제된다") + @Test + void deleteById_success_byExistsId() { + // given + DocumentResponse documentResponse = crewDocumentService.create( + DocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, + UUID.randomUUID())); + + // before then + assertThat(documentRepository.findAll()).hasSize(1); + assertThat(historyRepository.findAll()).hasSize(1); + + // when + crewDocumentService.deleteByUuid(documentResponse.documentUUID()); + + // after then + assertThat(documentRepository.findAll()).hasSize(0); + assertThat(historyRepository.findAll()).hasSize(0); + } + + @DisplayName("존재하지 않는 문서의 id일 경우 예외가 발생한다 : WikiException.DOCUMENT_NOT_FOUND") + @Test + void deleteById_throwsException_byNonExistsId() { + // when & then + WikiException ex = assertThrows(WikiException.class, + () -> crewDocumentService.deleteByUuid(UUID.randomUUID())); + assertThat(ex.getErrorCode()).isEqualTo(DOCUMENT_NOT_FOUND); + } + } +} diff --git a/src/test/java/com/wooteco/wiki/document/service/DocumentServiceTest.java b/src/test/java/com/wooteco/wiki/document/service/DocumentServiceTest.java index de4f079..12f6666 100644 --- a/src/test/java/com/wooteco/wiki/document/service/DocumentServiceTest.java +++ b/src/test/java/com/wooteco/wiki/document/service/DocumentServiceTest.java @@ -4,27 +4,22 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; +import com.wooteco.wiki.admin.service.CrewDocumentService; import com.wooteco.wiki.document.domain.CrewDocument; import com.wooteco.wiki.document.domain.Document; import com.wooteco.wiki.document.domain.dto.CrewDocumentCreateRequest; import com.wooteco.wiki.document.domain.dto.DocumentResponse; -import com.wooteco.wiki.document.domain.dto.DocumentUpdateRequest; import com.wooteco.wiki.document.domain.dto.DocumentUuidResponse; import com.wooteco.wiki.document.fixture.DocumentFixture; import com.wooteco.wiki.document.repository.DocumentRepository; import com.wooteco.wiki.global.common.PageRequestDto; import com.wooteco.wiki.global.exception.ErrorCode; import com.wooteco.wiki.global.exception.WikiException; -import com.wooteco.wiki.history.domain.History; -import com.wooteco.wiki.history.fixture.HistoryFixture; -import com.wooteco.wiki.history.repository.HistoryRepository; -import java.time.LocalDateTime; import java.util.List; import java.util.Map; import java.util.UUID; import org.assertj.core.api.Assertions; import org.assertj.core.api.SoftAssertions; -import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -41,36 +36,9 @@ class DocumentServiceTest { @Autowired private DocumentService documentService; @Autowired - private DocumentRepository documentRepository; + private CrewDocumentService crewDocumentService; @Autowired - private HistoryRepository historyRepository; - - @DisplayName("문서 조회 기능") - @Nested - class Find { - - @DisplayName("문서 조회시, 해당 문서의 마지막 로그 번호를 가져온다.") - @Test - void getDocumentLatestVersion_success_byExistsDocument() { - // given - CrewDocument crewDocument = DocumentFixture.createDefaultCrewDocument(); - CrewDocument savedCrewDocument = documentRepository.save(crewDocument); - - History history = HistoryFixture.create("test", "test", "tesst", 150, LocalDateTime.of(2025, 7, 15, 10, 0, 0), - savedCrewDocument, 20L); - historyRepository.save(history); - - // when - DocumentUpdateRequest documentUpdateRequest = new DocumentUpdateRequest("test", "test", "test", 150L, - savedCrewDocument.getUuid()); - - documentService.put(savedCrewDocument.getUuid(), documentUpdateRequest); - DocumentResponse documentResponse = documentService.getByUuid(savedCrewDocument.getUuid()); - - // then - assertThat(documentResponse.latestVersion()).isEqualTo(21L); - } - } + private DocumentRepository documentRepository; @Nested @DisplayName("문서 제목으로 조회하면 UUID를 반환하는 기능") @@ -80,8 +48,8 @@ class getUuidByTitle { @Test void getUuidByTitle_success_byExistsDocumentTitle() { // given - DocumentResponse documentResponse = documentService.postCrewDocument( - DocumentFixture.createDocumentCreateRequestDefault()); + DocumentResponse documentResponse = crewDocumentService.create( + DocumentFixture.createDocumentCreateRequestDefault()); // when DocumentUuidResponse documentUuidResponse = documentService.getUuidByTitle(documentResponse.title()); @@ -96,7 +64,7 @@ void getUuidByTitle_success_byNonExistsDocumentTitle() { // when & then WikiException ex = assertThrows(WikiException.class, - () -> documentService.getUuidByTitle("nonExistsDocumentTitle")); + () -> documentService.getUuidByTitle("nonExistsDocumentTitle")); assertThat(ex.getErrorCode()).isEqualTo(DOCUMENT_NOT_FOUND); } } @@ -116,15 +84,15 @@ class findAll_data { void findAll_success_bySomeData() { // given List crewDocumentCreateRequests = List.of( - DocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title2", "content2", "writer2", 11L, - UUID.randomUUID()) + DocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title2", "content2", "writer2", 11L, + UUID.randomUUID()) ); // when for (CrewDocumentCreateRequest documentRequestDto : crewDocumentCreateRequests) { - documentService.postCrewDocument(documentRequestDto); + crewDocumentService.create(documentRequestDto); } // then @@ -148,34 +116,34 @@ class findAll_pageable { @BeforeEach public void beforeEach() { crewDocumentCreateRequests = List.of( - DocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title2", "content2", "writer2", 11L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title3", "content3", "writer3", 13L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title4", "content4", "writer4", 14L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title5", "content5", "writer5", 15L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title6", "content6", "writer6", 16L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title7", "content7", "writer7", 17L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title8", "content8", "writer8", 18L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title9", "content9", "writer9", 19L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title10", "content10", "writer10", 110L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title11", "content11", "writer11", 11L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title12", "content12", "writer12", 11L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title13", "content13", "writer13", 11L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title14", "content14", "writer14", 11L, - UUID.randomUUID()) + DocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title2", "content2", "writer2", 11L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title3", "content3", "writer3", 13L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title4", "content4", "writer4", 14L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title5", "content5", "writer5", 15L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title6", "content6", "writer6", 16L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title7", "content7", "writer7", 17L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title8", "content8", "writer8", 18L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title9", "content9", "writer9", 19L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title10", "content10", "writer10", 110L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title11", "content11", "writer11", 11L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title12", "content12", "writer12", 11L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title13", "content13", "writer13", 11L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title14", "content14", "writer14", 11L, + UUID.randomUUID()) ); } @@ -186,15 +154,16 @@ void findAll_success_byPageRequestDtoDefault() { PageRequestDto pageRequestDto = new PageRequestDto(); for (CrewDocumentCreateRequest documentRequestDto : crewDocumentCreateRequests) { - documentService.postCrewDocument(documentRequestDto); + crewDocumentService.create(documentRequestDto); } // when - Page<@NotNull Document> documentPages = documentService.findAll(pageRequestDto); + Page documentPages = documentService.findAll(pageRequestDto); // then SoftAssertions softAssertions = new SoftAssertions(); - softAssertions.assertThat(documentPages.getTotalElements()).isEqualTo(crewDocumentCreateRequests.size()); + softAssertions.assertThat(documentPages.getTotalElements()) + .isEqualTo(crewDocumentCreateRequests.size()); softAssertions.assertThat(documentPages.getNumber()).isEqualTo(0); softAssertions.assertThat(documentPages.getTotalPages()).isEqualTo(2); softAssertions.assertAll(); @@ -211,15 +180,16 @@ void findAll_success_byPageRequestDto() { pageRequestDto.setSortDirection("DESC"); for (CrewDocumentCreateRequest documentRequestDto : crewDocumentCreateRequests) { - documentService.postCrewDocument(documentRequestDto); + crewDocumentService.create(documentRequestDto); } // when - Page<@NotNull Document> documentPages = documentService.findAll(pageRequestDto); + Page documentPages = documentService.findAll(pageRequestDto); // then SoftAssertions softAssertions = new SoftAssertions(); - softAssertions.assertThat(documentPages.getTotalElements()).isEqualTo(crewDocumentCreateRequests.size()); + softAssertions.assertThat(documentPages.getTotalElements()) + .isEqualTo(crewDocumentCreateRequests.size()); softAssertions.assertThat(documentPages.getNumber()).isEqualTo(1); softAssertions.assertThat(documentPages.getTotalPages()).isEqualTo(3); softAssertions.assertAll(); @@ -234,51 +204,17 @@ void findAll_throwsException_byNegativeNumber() { pageRequestDto.setPageSize(5); for (CrewDocumentCreateRequest documentRequestDto : crewDocumentCreateRequests) { - documentService.postCrewDocument(documentRequestDto); + crewDocumentService.create(documentRequestDto); } // when & then WikiException ex = assertThrows(WikiException.class, - () -> documentService.findAll(pageRequestDto)); + () -> documentService.findAll(pageRequestDto)); assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.PAGE_BAD_REQUEST); } } } - @Nested - @DisplayName("문서 uuid로 삭제 기능") - class deleteByUuid { - - @DisplayName("존재하는 문서 id일 경우 문서가 로그들과 함께 삭제된다") - @Test - void deleteById_success_byExistsId() { - // given - DocumentResponse documentResponse = documentService.postCrewDocument( - DocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, - UUID.randomUUID())); - - // before then - assertThat(documentRepository.findAll()).hasSize(1); - assertThat(historyRepository.findAll()).hasSize(1); - - // when - documentService.deleteByUuid(documentResponse.documentUUID()); - - // after then - assertThat(documentRepository.findAll()).hasSize(0); - assertThat(historyRepository.findAll()).hasSize(0); - } - - @DisplayName("존재하지 않는 문서의 id일 경우 예외가 발생한다 : WikiException.DOCUMENT_NOT_FOUND") - @Test - void deleteById_throwsException_byNonExistsId() { - // when & then - WikiException ex = assertThrows(WikiException.class, - () -> documentService.deleteByUuid(UUID.randomUUID())); - assertThat(ex.getErrorCode()).isEqualTo(DOCUMENT_NOT_FOUND); - } - } - @Test @DisplayName("flushViews 호출 시 uuid별로 조회수가 증가된다") void flushViews_success() { @@ -286,13 +222,13 @@ void flushViews_success() { UUID uuid1 = UUID.randomUUID(); UUID uuid2 = UUID.randomUUID(); CrewDocument doc1 = documentRepository.save( - DocumentFixture.createCrewDocument("title1", "content1", "writer1", 10L, uuid1)); + DocumentFixture.createCrewDocument("title1", "content1", "writer1", 10L, uuid1)); CrewDocument doc2 = documentRepository.save( - DocumentFixture.createCrewDocument("title2", "content2", "writer2", 10L, uuid2)); + DocumentFixture.createCrewDocument("title2", "content2", "writer2", 10L, uuid2)); Map viewMap = Map.of( - uuid1, 5, - uuid2, 10 + uuid1, 5, + uuid2, 10 ); // when From 6021df7b4a2f011e2b06433aa5a7d7fbbfb8167e Mon Sep 17 00:00:00 2001 From: "2jin2.1031" <2jin2.1031@gmail.com> Date: Mon, 23 Feb 2026 17:57:43 +0900 Subject: [PATCH 23/26] =?UTF-8?q?test:=20=EB=B3=80=EA=B2=BD=EB=90=9C=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=EB=AA=85=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=ED=8C=8C=EC=9D=BC=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 --- .../wiki/document/service/DocumentSearchServiceTest.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/wooteco/wiki/document/service/DocumentSearchServiceTest.java b/src/test/java/com/wooteco/wiki/document/service/DocumentSearchServiceTest.java index aaa0e60..4cd7baf 100644 --- a/src/test/java/com/wooteco/wiki/document/service/DocumentSearchServiceTest.java +++ b/src/test/java/com/wooteco/wiki/document/service/DocumentSearchServiceTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.SoftAssertions.assertSoftly; +import com.wooteco.wiki.admin.service.CrewDocumentService; import com.wooteco.wiki.document.domain.DocumentType; import com.wooteco.wiki.document.domain.dto.DocumentSearchResponse; import com.wooteco.wiki.document.fixture.DocumentFixture; @@ -25,7 +26,7 @@ class DocumentSearchServiceTest { private DocumentSearchService documentSearchService; @Autowired - private DocumentService documentService; + private CrewDocumentService crewDocumentService; @Autowired private OrganizationDocumentRepository organizationDocumentRepository; @@ -34,9 +35,9 @@ class DocumentSearchServiceTest { @Test void search_success() { // given - documentService.postCrewDocument( + crewDocumentService.create( DocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, UUID.randomUUID())); - documentService.postCrewDocument( + crewDocumentService.create( DocumentFixture.createDocumentCreateRequest("title2", "content2", "writer2", 11L, UUID.randomUUID())); // when @@ -63,7 +64,7 @@ void search_empty() { @Test void search_success_has_valid_type() { // given - documentService.postCrewDocument( + crewDocumentService.create( DocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, UUID.randomUUID())); OrganizationDocument organizationDocument = OrganizationDocumentFixture.create("title2", "content", "writer", 15L, UUID.randomUUID()); From 55a8667d4fec2d082ee4ed4e519263744c52c714 Mon Sep 17 00:00:00 2001 From: CheChe903 <137619133+CheChe903@users.noreply.github.com> Date: Thu, 26 Feb 2026 15:26:08 +0900 Subject: [PATCH 24/26] =?UTF-8?q?[REFACTOR]:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=BB=A8=EB=B2=A4=EC=85=98=20=EC=A0=81=EC=9A=A9=20(#144)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: DTO 네이밍 및 공용 래퍼 정리 record 전환과 이름 규칙을 반영해 공용 요청/응답 DTO를 정리하고 관련 사용처를 갱신 * feat: 테스트 네이밍 규칙 적용 @Nested 클래스명과 테스트 메서드명을 규칙에 맞게 정리 * feat: 컨벤션 문서 추가 프로젝트 규칙을 한국어로 정리하고 예시를 추가 --- docs/CONVENTIONS.md | 160 +++++++++++ .../controller/DocumentController.java | 14 +- .../document/service/DocumentService.java | 4 +- .../wiki/global/auth/JwtTokenProvider.java | 6 +- .../global/auth/domain/dto/AuthTokens.java | 4 - .../auth/domain/dto/AuthTokensResponse.java | 4 + .../global/auth/domain/dto/TokenInfoDto.java | 11 - .../auth/domain/dto/TokenInfoResponse.java | 11 + .../wiki/global/auth/service/AuthService.java | 6 +- .../wiki/global/common/ApiResponse.java | 15 +- .../wiki/global/common/PagedResponse.java | 8 + ...PageRequestDto.java => PagingRequest.java} | 2 +- .../wiki/global/common/ResponseDto.java | 8 - .../wiki/history/service/HistoryService.java | 4 +- .../admin/controller/AdminControllerTest.java | 4 +- .../admin/repository/AdminRepositoryTest.java | 4 +- .../repository/DocumentRepositoryTest.java | 14 +- .../service/CrewDocumentServiceJavaTest.java | 10 +- .../service/DocumentSearchServiceTest.java | 6 +- .../document/service/DocumentServiceTest.java | 269 +++++++++--------- .../auth/controller/AuthControllerTest.java | 10 +- .../global/auth/service/AuthServiceTest.java | 16 +- .../history/service/HistoryServiceTest.java | 49 ++-- ...ewDocumentOrganizationLinkServiceTest.java | 6 +- .../OrganizationCrewDocumentServiceTest.java | 8 +- .../OrganizationEventControllerTest.java | 20 +- .../service/OrganizationEventServiceTest.java | 193 ++++++------- 27 files changed, 508 insertions(+), 358 deletions(-) create mode 100644 docs/CONVENTIONS.md delete mode 100644 src/main/java/com/wooteco/wiki/global/auth/domain/dto/AuthTokens.java create mode 100644 src/main/java/com/wooteco/wiki/global/auth/domain/dto/AuthTokensResponse.java delete mode 100644 src/main/java/com/wooteco/wiki/global/auth/domain/dto/TokenInfoDto.java create mode 100644 src/main/java/com/wooteco/wiki/global/auth/domain/dto/TokenInfoResponse.java create mode 100644 src/main/java/com/wooteco/wiki/global/common/PagedResponse.java rename src/main/java/com/wooteco/wiki/global/common/{PageRequestDto.java => PagingRequest.java} (97%) delete mode 100644 src/main/java/com/wooteco/wiki/global/common/ResponseDto.java diff --git a/docs/CONVENTIONS.md b/docs/CONVENTIONS.md new file mode 100644 index 0000000..f0f2eaf --- /dev/null +++ b/docs/CONVENTIONS.md @@ -0,0 +1,160 @@ +# CrewWiki Backend 컨벤션 + +## 1. 패키지 구조 +``` +├── post +│ ├── controller +│ ├── dto +│ ├── repository +│ └── service +└── user +│ ├── controller +│ ├── dto +│ ├── repository +│ └── service +├── common +│ ├── config +│ ├── entity +│ ├── exception +│ ├── infrastructure +│ ├── log +│ └── utils +``` + +## 2. 테스트 코드 +### 2.1 네이밍 +- `@Nested`는 프로덕션 **메서드명**을 기준으로 작성한다. +- `@Nested` 클래스명은 **UpperCamel**로 표기한다. +- 테스트 메서드명 형식: + - `프로덕션메서드_success_조건` + - `프로덕션메서드_fail_조건` + +예시 +```java +@Nested +@DisplayName("로그인 기능") +class Login { + @Test + @DisplayName("유효한 정보로 로그인 성공") + void login_success_byValidCredentials() { } + + @Test + @DisplayName("유효하지 않은 정보로 로그인 실패") + void login_fail_byInvalidCredentials() { } +} +``` + +### 2.2 BDD 패턴 +```java +// given (불필요하면 생략) +// when +// then +``` + +### 2.3 Fixture +- 정적 팩토리 메서드 사용 + +예시 +```java +CrewDocument doc = DocumentFixture.createDefaultCrewDocument(); +``` + +### 2.4 테스트 환경 및 전략 +- 인증/인가 필요 시 컨트롤러 테스트에서 `RestAssured` 사용 +- 서비스 테스트는 통합 테스트로 작성 (`@SpringBootTest(WebEnvironment.MOCK/NONE)`)하여 톰캣을 띄우지 않음 +- 필요 시 `assertSoftly`로 감싸기 +- 결과 검증은 **상태 검증 우선** +- 서비스 테스트는 필수, 컨트롤러 테스트는 필요 시 + +## 3. 네이밍 규칙 +- 메서드명: 동사로 시작, 엔티티명 미사용 + - 예: `memberService.findById(Long id)` +- Path Variable 명확화 + - 예: `/api/{documentId}` +- DTO: `Request`/`Response` 접미사 사용 + - 등록/수정은 `Register`/`Update` 가능 + - 예: `DocumentSearchResponse`, `DocumentUpdateRequest` + +## 4. 객체지향 생활체조 (최대한 지킴) +1. 한 메서드 한 indent +2. `else` 금지 +3. 원시값·문자열 포장 +4. 한 줄에 점 하나 +5. 축약 금지 +6. 작은 엔티티 +7. 인스턴스 변수 ≤ 2 +8. 일급 컬렉션 +9. Getter/Setter는 필요할 때만 사용 + +## 5. 예외 처리 +- 에러 코드를 포함해 반환 + +## 6. 어노테이션 순서 (권장) +1. 로깅 +2. 롬복 +3. 스프링 메타 +4. 스프링 컴포넌트 (가장 아래) + +예시 +```java +@Slf4j +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +@Builder +@EntityListeners(AuditingEntityListener.class) +@Entity +@Table(name = "...") +public class SampleEntity { + ... +} +``` + +## 7. 도메인 외부 노출 범위 +- 서비스 외부에는 DTO만 노출 + +예시 +```java +public ApiResponse> getByUuid(...) { } +``` + +## 8. API ↔ DTO +- 1:1 매핑 +- 어드민/일반 API가 다르면 DTO도 분리 + +예시 +- 어드민 문서 검색 → `AdminDocumentSearchResponse` +- 일반 문서 검색 → `DocumentSearchResponse` + +## 9. 코드 스타일 +- 클래스 선언 전 공백 한 줄 +- 메서드 파라미터 2개 이상이면 개행 +- 메서드 라인 수 제한 없음 (개행 규칙 우선) + +## 10. 검증 위치 +- 행동 검증: 서비스 +- 상태 검증: 도메인 +- 애매한 경우 개발 시 협의 + +## 11. import +- 와일드카드 금지 +- IntelliJ 컨벤션 적용 +- static import 허용 + +## 12. 기타 +- `final`은 필드/상수에 사용 가능 +- 정적 팩토리 메서드 사용 가능 +- VO 미사용 (필요 시 도입) +- 상수는 `UPPER_SNAKE_CASE` +- 접근자/메서드 정렬: `public` → `protected` → `private` + - 예외: getter는 맨 아래 + +## 13. DTO 정책 (업데이트) +- DTO는 `record`를 최대한 유지 +- 불가피한 경우에만 `class` 사용 (예: `@ModelAttribute` 바인딩 등) + +현재 적용된 공용 네이밍 +- `PagedResponse` +- `PagingRequest` +- `TokenInfoResponse` +- `AuthTokensResponse` diff --git a/src/main/java/com/wooteco/wiki/document/controller/DocumentController.java b/src/main/java/com/wooteco/wiki/document/controller/DocumentController.java index 83b6dd9..dd80411 100644 --- a/src/main/java/com/wooteco/wiki/document/controller/DocumentController.java +++ b/src/main/java/com/wooteco/wiki/document/controller/DocumentController.java @@ -8,8 +8,8 @@ import com.wooteco.wiki.global.common.ApiResponse; import com.wooteco.wiki.global.common.ApiResponse.SuccessBody; import com.wooteco.wiki.global.common.ApiResponseGenerator; -import com.wooteco.wiki.global.common.PageRequestDto; -import com.wooteco.wiki.global.common.ResponseDto; +import com.wooteco.wiki.global.common.PagingRequest; +import com.wooteco.wiki.global.common.PagedResponse; import com.wooteco.wiki.history.domain.dto.HistoryDetailResponse; import com.wooteco.wiki.history.domain.dto.HistoryResponse; import com.wooteco.wiki.history.service.HistoryService; @@ -48,7 +48,7 @@ public ApiResponse> getRandom() { @Operation(summary = "위키 글 전체 조회", description = "페이지네이션을 통해 모든 위키 글을 조회합니다.") @GetMapping("") - public ApiResponse>>> findAll(@ModelAttribute PageRequestDto pageRequestDto) { + public ApiResponse>>> findAll(@ModelAttribute PagingRequest pageRequestDto) { Page pageResponses = documentService.findAll(pageRequestDto); Page responses = pageResponses.map(DocumentListResponse::from); return ApiResponseGenerator.success(convertToResponse(responses)); @@ -78,9 +78,9 @@ public ApiResponse> getByUuid(@PathVariable String uuidText) @Operation(summary = "문서 로그 목록 조회", description = "문서 UUID로 해당 문서의 로그 목록을 페이지네이션을 통해 조회합니다.") @GetMapping("uuid/{uuidText}/log") - public ApiResponse>>> getLogs( + public ApiResponse>>> getLogs( @PathVariable String uuidText, - @ModelAttribute PageRequestDto pageRequestDto + @ModelAttribute PagingRequest pageRequestDto ) { UUID uuid = UUID.fromString(uuidText); Page pageResponses = historyService.findAllByDocumentUuid(uuid, pageRequestDto); @@ -139,8 +139,8 @@ public ApiResponse> deleteOrganizationDocument( return ApiResponseGenerator.success(HttpStatus.NO_CONTENT); } - private ResponseDto> convertToResponse(Page pageResponses) { - return ResponseDto.of( + private PagedResponse> convertToResponse(Page pageResponses) { + return PagedResponse.of( pageResponses.getNumber(), pageResponses.getTotalPages(), pageResponses.getContent() diff --git a/src/main/java/com/wooteco/wiki/document/service/DocumentService.java b/src/main/java/com/wooteco/wiki/document/service/DocumentService.java index cc9dd7c..8eb706b 100644 --- a/src/main/java/com/wooteco/wiki/document/service/DocumentService.java +++ b/src/main/java/com/wooteco/wiki/document/service/DocumentService.java @@ -7,7 +7,7 @@ import com.wooteco.wiki.document.domain.dto.DocumentUpdateRequest; import com.wooteco.wiki.document.domain.dto.DocumentUuidResponse; import com.wooteco.wiki.document.repository.DocumentRepository; -import com.wooteco.wiki.global.common.PageRequestDto; +import com.wooteco.wiki.global.common.PagingRequest; import com.wooteco.wiki.global.exception.ErrorCode; import com.wooteco.wiki.global.exception.WikiException; import com.wooteco.wiki.history.service.HistoryService; @@ -67,7 +67,7 @@ public DocumentResponse getRandom() { } @Transactional(readOnly = true) - public Page findAll(PageRequestDto requestDto) { + public Page findAll(PagingRequest requestDto) { return documentRepository.findAll(requestDto.toPageable()); } diff --git a/src/main/java/com/wooteco/wiki/global/auth/JwtTokenProvider.java b/src/main/java/com/wooteco/wiki/global/auth/JwtTokenProvider.java index d68c1fe..3aa667f 100644 --- a/src/main/java/com/wooteco/wiki/global/auth/JwtTokenProvider.java +++ b/src/main/java/com/wooteco/wiki/global/auth/JwtTokenProvider.java @@ -1,6 +1,6 @@ package com.wooteco.wiki.global.auth; -import com.wooteco.wiki.global.auth.domain.dto.TokenInfoDto; +import com.wooteco.wiki.global.auth.domain.dto.TokenInfoResponse; import com.wooteco.wiki.global.exception.ErrorCode; import com.wooteco.wiki.global.exception.WikiException; import io.jsonwebtoken.Claims; @@ -30,7 +30,7 @@ private void init() { this.secretKey = Keys.hmacShaKeyFor(strSecretKey.getBytes()); } - public String createToken(TokenInfoDto tokenInfoDto) { + public String createToken(TokenInfoResponse tokenInfoDto) { Map claims = getMyClaimMap(tokenInfoDto); @@ -49,7 +49,7 @@ public String createToken(TokenInfoDto tokenInfoDto) { } } - private Map getMyClaimMap(TokenInfoDto tokenInfoDto) { + private Map getMyClaimMap(TokenInfoResponse tokenInfoDto) { Map map = new HashMap<>(); map.put("id", tokenInfoDto.id()); map.put("role", tokenInfoDto.role()); diff --git a/src/main/java/com/wooteco/wiki/global/auth/domain/dto/AuthTokens.java b/src/main/java/com/wooteco/wiki/global/auth/domain/dto/AuthTokens.java deleted file mode 100644 index d41bc66..0000000 --- a/src/main/java/com/wooteco/wiki/global/auth/domain/dto/AuthTokens.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.wooteco.wiki.global.auth.domain.dto; - -public record AuthTokens(String accessToken, String refreshToken) { -} diff --git a/src/main/java/com/wooteco/wiki/global/auth/domain/dto/AuthTokensResponse.java b/src/main/java/com/wooteco/wiki/global/auth/domain/dto/AuthTokensResponse.java new file mode 100644 index 0000000..9bf42ae --- /dev/null +++ b/src/main/java/com/wooteco/wiki/global/auth/domain/dto/AuthTokensResponse.java @@ -0,0 +1,4 @@ +package com.wooteco.wiki.global.auth.domain.dto; + +public record AuthTokensResponse(String accessToken, String refreshToken) { +} diff --git a/src/main/java/com/wooteco/wiki/global/auth/domain/dto/TokenInfoDto.java b/src/main/java/com/wooteco/wiki/global/auth/domain/dto/TokenInfoDto.java deleted file mode 100644 index 95a1c2d..0000000 --- a/src/main/java/com/wooteco/wiki/global/auth/domain/dto/TokenInfoDto.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.wooteco.wiki.global.auth.domain.dto; - -import com.wooteco.wiki.admin.domain.Admin; -import com.wooteco.wiki.global.auth.Role; - -public record TokenInfoDto (Long id, Role role) { - - public static TokenInfoDto of(Admin admin, Role role) { - return new TokenInfoDto(admin.getId(), role); - } -} diff --git a/src/main/java/com/wooteco/wiki/global/auth/domain/dto/TokenInfoResponse.java b/src/main/java/com/wooteco/wiki/global/auth/domain/dto/TokenInfoResponse.java new file mode 100644 index 0000000..88a76e8 --- /dev/null +++ b/src/main/java/com/wooteco/wiki/global/auth/domain/dto/TokenInfoResponse.java @@ -0,0 +1,11 @@ +package com.wooteco.wiki.global.auth.domain.dto; + +import com.wooteco.wiki.admin.domain.Admin; +import com.wooteco.wiki.global.auth.Role; + +public record TokenInfoResponse (Long id, Role role) { + + public static TokenInfoResponse of(Admin admin, Role role) { + return new TokenInfoResponse(admin.getId(), role); + } +} diff --git a/src/main/java/com/wooteco/wiki/global/auth/service/AuthService.java b/src/main/java/com/wooteco/wiki/global/auth/service/AuthService.java index a6613f1..e1eac58 100644 --- a/src/main/java/com/wooteco/wiki/global/auth/service/AuthService.java +++ b/src/main/java/com/wooteco/wiki/global/auth/service/AuthService.java @@ -4,7 +4,7 @@ import com.wooteco.wiki.admin.domain.dto.AdminResponse; import com.wooteco.wiki.admin.domain.dto.LoginRequest; import com.wooteco.wiki.global.auth.Role; -import com.wooteco.wiki.global.auth.domain.dto.TokenInfoDto; +import com.wooteco.wiki.global.auth.domain.dto.TokenInfoResponse; import com.wooteco.wiki.global.auth.domain.dto.TokenResponse; import com.wooteco.wiki.global.exception.ErrorCode; import com.wooteco.wiki.global.exception.WikiException; @@ -26,10 +26,10 @@ public AuthService(JwtTokenProvider jwtTokenProvider, AdminRepository adminRepos public TokenResponse login(LoginRequest loginRequest) { Admin admin = adminRepository.findOneByLoginIdAndPassword(loginRequest.loginId(), loginRequest.password()) .orElseThrow(() -> new WikiException(ErrorCode.ADMIN_NOT_FOUND)); - return createToken(TokenInfoDto.of(admin, Role.ROLE_ADMIN)); + return createToken(TokenInfoResponse.of(admin, Role.ROLE_ADMIN)); } - public TokenResponse createToken(TokenInfoDto tokenInfoDto) { + public TokenResponse createToken(TokenInfoResponse tokenInfoDto) { String accessToken = jwtTokenProvider.createToken(tokenInfoDto); return new TokenResponse(accessToken); } diff --git a/src/main/java/com/wooteco/wiki/global/common/ApiResponse.java b/src/main/java/com/wooteco/wiki/global/common/ApiResponse.java index 02c56e5..f6f0772 100644 --- a/src/main/java/com/wooteco/wiki/global/common/ApiResponse.java +++ b/src/main/java/com/wooteco/wiki/global/common/ApiResponse.java @@ -2,29 +2,18 @@ import com.wooteco.wiki.global.exception.ErrorCode; import com.wooteco.wiki.global.exception.SuccessCode; -import lombok.AllArgsConstructor; -import lombok.Getter; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -@Getter public class ApiResponse extends ResponseEntity { public ApiResponse(B body, HttpStatus status) { super(body, status); } - @Getter - @AllArgsConstructor - public static class SuccessBody { - private D data; - private SuccessCode code; + public static record SuccessBody(D data, SuccessCode code) { } - @Getter - @AllArgsConstructor - public static class FailureBody { - private ErrorCode code; - private String message; + public static record FailureBody(ErrorCode code, String message) { } } diff --git a/src/main/java/com/wooteco/wiki/global/common/PagedResponse.java b/src/main/java/com/wooteco/wiki/global/common/PagedResponse.java new file mode 100644 index 0000000..3b835cf --- /dev/null +++ b/src/main/java/com/wooteco/wiki/global/common/PagedResponse.java @@ -0,0 +1,8 @@ +package com.wooteco.wiki.global.common; + +public record PagedResponse (int page, int totalPage, T data){ + + public static PagedResponse of(int page, int totalPage, T data) { + return new PagedResponse<>(page, totalPage, data); + } +} diff --git a/src/main/java/com/wooteco/wiki/global/common/PageRequestDto.java b/src/main/java/com/wooteco/wiki/global/common/PagingRequest.java similarity index 97% rename from src/main/java/com/wooteco/wiki/global/common/PageRequestDto.java rename to src/main/java/com/wooteco/wiki/global/common/PagingRequest.java index c7cfbd3..bdb377b 100644 --- a/src/main/java/com/wooteco/wiki/global/common/PageRequestDto.java +++ b/src/main/java/com/wooteco/wiki/global/common/PagingRequest.java @@ -12,7 +12,7 @@ @Getter @Setter -public class PageRequestDto { +public class PagingRequest { @Min(value = 0, message = "페이지 번호는 0 이상이어야 합니다.") private int pageNumber = 0; diff --git a/src/main/java/com/wooteco/wiki/global/common/ResponseDto.java b/src/main/java/com/wooteco/wiki/global/common/ResponseDto.java deleted file mode 100644 index 7f71d7f..0000000 --- a/src/main/java/com/wooteco/wiki/global/common/ResponseDto.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.wooteco.wiki.global.common; - -public record ResponseDto (int page, int totalPage, T data){ - - public static ResponseDto of(int page, int totalPage, T data) { - return new ResponseDto<>(page, totalPage, data); - } -} diff --git a/src/main/java/com/wooteco/wiki/history/service/HistoryService.java b/src/main/java/com/wooteco/wiki/history/service/HistoryService.java index 537a71b..4799e71 100644 --- a/src/main/java/com/wooteco/wiki/history/service/HistoryService.java +++ b/src/main/java/com/wooteco/wiki/history/service/HistoryService.java @@ -5,7 +5,7 @@ import com.wooteco.wiki.document.domain.Document; import com.wooteco.wiki.document.repository.DocumentRepository; -import com.wooteco.wiki.global.common.PageRequestDto; +import com.wooteco.wiki.global.common.PagingRequest; import com.wooteco.wiki.global.exception.WikiException; import com.wooteco.wiki.history.domain.History; import com.wooteco.wiki.history.domain.dto.HistoryDetailResponse; @@ -47,7 +47,7 @@ public HistoryDetailResponse getLogDetail(Long logId) { } @Transactional(readOnly = true) - public Page findAllByDocumentUuid(UUID documentUuid, PageRequestDto pageRequestDto) { + public Page findAllByDocumentUuid(UUID documentUuid, PagingRequest pageRequestDto) { Long documentId = documentRepository.findIdByUuid(documentUuid) .orElseThrow(() -> new WikiException(DOCUMENT_NOT_FOUND)); diff --git a/src/test/java/com/wooteco/wiki/admin/controller/AdminControllerTest.java b/src/test/java/com/wooteco/wiki/admin/controller/AdminControllerTest.java index a2e0a72..4771e2e 100644 --- a/src/test/java/com/wooteco/wiki/admin/controller/AdminControllerTest.java +++ b/src/test/java/com/wooteco/wiki/admin/controller/AdminControllerTest.java @@ -28,11 +28,11 @@ void setUp() { @Nested @DisplayName("adminController") - class adminController { + class DeleteDocumentByDocumentId { @DisplayName("/admin/** 은 token이 없을 시 예외 발생") @Test - void adminController_throwsException_byNonExistsToken() { + void deleteDocumentByDocumentId_fail_byMissingToken() { // then RestAssured .given().log().all() diff --git a/src/test/java/com/wooteco/wiki/admin/repository/AdminRepositoryTest.java b/src/test/java/com/wooteco/wiki/admin/repository/AdminRepositoryTest.java index 25b9cf8..8251c2e 100644 --- a/src/test/java/com/wooteco/wiki/admin/repository/AdminRepositoryTest.java +++ b/src/test/java/com/wooteco/wiki/admin/repository/AdminRepositoryTest.java @@ -19,7 +19,7 @@ class AdminRepositoryTest { @Nested @DisplayName("loginId와 password로 Admin을 찾는 기능") - class findOneByLoginIdAndPassword { + class FindOneByLoginIdAndPassword { @DisplayName("유효한 loginId와 password로 Admin을 반환한다.") @Test @@ -41,7 +41,7 @@ void findOneByLoginIdAndPassword_success_byValidLoginIdAndPassword() { @DisplayName("알맞지 않는 loginId와 password로 Optional.isEmpty를 반환한다.") @Test - void findOneByLoginIdAndPassword_isEmpty_byInValidLoginIdAndPassword() { + void findOneByLoginIdAndPassword_success_byInvalidCredentials() { // given adminRepository.save(new Admin("admin", "password")); diff --git a/src/test/java/com/wooteco/wiki/document/repository/DocumentRepositoryTest.java b/src/test/java/com/wooteco/wiki/document/repository/DocumentRepositoryTest.java index 7f138c0..3a8a1c1 100644 --- a/src/test/java/com/wooteco/wiki/document/repository/DocumentRepositoryTest.java +++ b/src/test/java/com/wooteco/wiki/document/repository/DocumentRepositoryTest.java @@ -28,7 +28,7 @@ public class DocumentRepositoryTest { @Nested @DisplayName("문서 제목으로 uuid를 조회하는 기능") - class findUuidByTitle { + class FindUuidByTitle { @DisplayName("존재하지 않는 문서 제목으로 조회했을 때 Optional.empty를 반환한다") @Test @@ -57,11 +57,11 @@ void findUuidByTitle_success_byExistsDocument() { @Nested @DisplayName("문서 전체 조회 기능") - class findAll { + class FindAll { @DisplayName("DocumentRepository로 조회 시 CrewDocument와 OrganizationDocument가 모두 조회된다") @Test - void findAll_success_returnsBothCrewAndOrganizationDocuments() { + void findAll_success_byMixedDocumentTypes() { // given documentRepository.save( DocumentFixture.createCrewDocument("crew문서", "content1", "writer1", 10L, UUID.randomUUID())); @@ -83,7 +83,7 @@ void findAll_success_returnsBothCrewAndOrganizationDocuments() { @DisplayName("CrewDocument만 저장했을 때는 CrewDocument만 조회된다") @Test - void findAll_success_returnsOnlyCrewDocuments() { + void findAll_success_byOnlyCrewDocuments() { // given documentRepository.save( DocumentFixture.createCrewDocument("crew1", "content1", "writer1", 10L, UUID.randomUUID())); @@ -102,7 +102,7 @@ void findAll_success_returnsOnlyCrewDocuments() { @DisplayName("OrganizationDocument만 저장했을 때는 OrganizationDocument만 조회된다") @Test - void findAll_success_returnsOnlyOrganizationDocuments() { + void findAll_success_byOnlyOrganizationDocuments() { // given documentRepository.save( OrganizationDocumentFixture.create("org1", "content1", "writer1", 10L, UUID.randomUUID())); @@ -148,7 +148,7 @@ void findAll_success_byNoData() { @Nested @DisplayName("uuid로 id 찾는 기능") - class findIdByUuid { + class FindIdByUuid { private UUID uuid; private CrewDocument savedCrewDocument; @@ -179,7 +179,7 @@ class FindAllByUuidIn { @DisplayName("UUID 리스트로 조회 시 해당 문서 리스트를 반환한다") @Test - void findAllByUuidIn_success() { + void findAllByUuidIn_success_byUuidSet() { // given CrewDocument doc1 = documentRepository.save( DocumentFixture.createCrewDocument("title1", "content1", "writer1", 10L, UUID.randomUUID())); diff --git a/src/test/java/com/wooteco/wiki/document/service/CrewDocumentServiceJavaTest.java b/src/test/java/com/wooteco/wiki/document/service/CrewDocumentServiceJavaTest.java index 8ad81c3..c3b4f58 100644 --- a/src/test/java/com/wooteco/wiki/document/service/CrewDocumentServiceJavaTest.java +++ b/src/test/java/com/wooteco/wiki/document/service/CrewDocumentServiceJavaTest.java @@ -54,7 +54,7 @@ void setUp() { @DisplayName("특정 문서에 대한 조직 문서 제목과 Uuid들을 조회할 때") @Nested - class searchOrganizationCrewDocument { + class SearchOrganizationDocument { @BeforeEach void setUp() { @@ -90,7 +90,7 @@ void searchOrganizationDocument_success_byExistingDocumentUuid() { @DisplayName("존재하지 않는 특정 문서의 Uuid로 요청한다면 예외가 발생한다 : DOCUMENT_NOT_FOUND") @Test - void searchOrganizationDocument_error_byNonExistingDocumentUuid() { + void searchOrganizationDocument_fail_byNonExistingDocumentUuid() { // when & then WikiException ex = assertThrows(WikiException.class, () -> documentService.searchOrganizationDocument(UUID.randomUUID())); @@ -100,7 +100,7 @@ void searchOrganizationDocument_error_byNonExistingDocumentUuid() { @DisplayName("특정 문서에 대해 조직 문서를 제거할 때에") @Nested - class deleteOrganizationCrewDocument { + class DeleteOrganizationDocument { private UUID savedOrganizationDocumentUuid; @@ -129,7 +129,7 @@ void deleteOrganizationDocument_success_byExistingDocumentUuid() { @DisplayName("존재하지 않는 특정 문서의 Uuid로 요청한다면 예외가 발생한다 : DOCUMENT_NOT_FOUND") @Test - void deleteOrganizationDocument_error_byNonExistingDocumentUuid() { + void deleteOrganizationDocument_fail_byNonExistingDocumentUuid() { // when & then WikiException ex = assertThrows(WikiException.class, () -> documentService.deleteOrganizationDocument(UUID.randomUUID(), savedOrganizationDocumentUuid)); @@ -138,7 +138,7 @@ void deleteOrganizationDocument_error_byNonExistingDocumentUuid() { @DisplayName("존재하지 않는 특정 조직 문서의 Uuid로 요청한다면 예외가 발생한다 : ORGANIZATION_DOCUMENT_NOT_FOUND") @Test - void deleteOrganizationDocument_error_byNonExistingOrganizationDocumentUuid() { + void deleteOrganizationDocument_fail_byNonExistingOrganizationDocumentUuid() { // when & then WikiException ex = assertThrows(WikiException.class, () -> documentService.deleteOrganizationDocument(savedDocumentUuid, UUID.randomUUID())); diff --git a/src/test/java/com/wooteco/wiki/document/service/DocumentSearchServiceTest.java b/src/test/java/com/wooteco/wiki/document/service/DocumentSearchServiceTest.java index aaa0e60..5ae680b 100644 --- a/src/test/java/com/wooteco/wiki/document/service/DocumentSearchServiceTest.java +++ b/src/test/java/com/wooteco/wiki/document/service/DocumentSearchServiceTest.java @@ -32,7 +32,7 @@ class DocumentSearchServiceTest { @DisplayName("검색어로 시작하는 문서들을 찾아 리스트로 반환한다.") @Test - void search_success() { + void search_success_byKeywordPrefix() { // given documentService.postCrewDocument( DocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, UUID.randomUUID())); @@ -48,7 +48,7 @@ void search_success() { @DisplayName("검색어와 일치하는 문서가 없으면 빈 리스트를 반환한다.") @Test - void search_empty() { + void search_success_byNoMatch() { // given String keyword = "존재하지않는문서"; @@ -61,7 +61,7 @@ void search_empty() { @DisplayName("조직 문서라면 타입이 조직문서로 나온다.") @Test - void search_success_has_valid_type() { + void search_success_byOrganizationDocumentType() { // given documentService.postCrewDocument( DocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, UUID.randomUUID())); diff --git a/src/test/java/com/wooteco/wiki/document/service/DocumentServiceTest.java b/src/test/java/com/wooteco/wiki/document/service/DocumentServiceTest.java index de4f079..5aec924 100644 --- a/src/test/java/com/wooteco/wiki/document/service/DocumentServiceTest.java +++ b/src/test/java/com/wooteco/wiki/document/service/DocumentServiceTest.java @@ -12,7 +12,7 @@ import com.wooteco.wiki.document.domain.dto.DocumentUuidResponse; import com.wooteco.wiki.document.fixture.DocumentFixture; import com.wooteco.wiki.document.repository.DocumentRepository; -import com.wooteco.wiki.global.common.PageRequestDto; +import com.wooteco.wiki.global.common.PagingRequest; import com.wooteco.wiki.global.exception.ErrorCode; import com.wooteco.wiki.global.exception.WikiException; import com.wooteco.wiki.history.domain.History; @@ -47,11 +47,11 @@ class DocumentServiceTest { @DisplayName("문서 조회 기능") @Nested - class Find { + class GetByUuid { @DisplayName("문서 조회시, 해당 문서의 마지막 로그 번호를 가져온다.") @Test - void getDocumentLatestVersion_success_byExistsDocument() { + void getByUuid_success_byLatestVersionFromHistory() { // given CrewDocument crewDocument = DocumentFixture.createDefaultCrewDocument(); CrewDocument savedCrewDocument = documentRepository.save(crewDocument); @@ -74,7 +74,7 @@ void getDocumentLatestVersion_success_byExistsDocument() { @Nested @DisplayName("문서 제목으로 조회하면 UUID를 반환하는 기능") - class getUuidByTitle { + class GetUuidByTitle { @DisplayName("존재하는 문서 제목으로 조회할 경우 UUID를 반환한다") @Test @@ -92,7 +92,7 @@ void getUuidByTitle_success_byExistsDocumentTitle() { @DisplayName("존재하지 않는 문서 제목으로 조회할 경우 예외를 반환한다 : WikiException.DOCUMENT_NOT_FOUND") @Test - void getUuidByTitle_success_byNonExistsDocumentTitle() { + void getUuidByTitle_fail_byNonExistsDocumentTitle() { // when & then WikiException ex = assertThrows(WikiException.class, @@ -103,155 +103,148 @@ void getUuidByTitle_success_byNonExistsDocumentTitle() { @Nested @DisplayName("문서 전체 조회 기능") - class findAll { - - @Nested - @DisplayName("문서 전체 조회 기능 : 데이터의 수") - class findAll_data { - - PageRequestDto pageRequestDto = new PageRequestDto(); - - @DisplayName("저장된 문서가 존재할 때 요청 시 List 형태로 반환한다") - @Test - void findAll_success_bySomeData() { - // given - List crewDocumentCreateRequests = List.of( - DocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title2", "content2", "writer2", 11L, - UUID.randomUUID()) - ); - - // when - for (CrewDocumentCreateRequest documentRequestDto : crewDocumentCreateRequests) { - documentService.postCrewDocument(documentRequestDto); - } - - // then - assertThat(documentService.findAll(pageRequestDto)).hasSize(crewDocumentCreateRequests.size()); - } + class FindAll { - @DisplayName("저장된 문서가 존재하지 않을 때 요청 시 예외 없이 빈 리스트를 반환한다") - @Test - void findAll_success_byNoData() { - // when & then - assertThat(documentService.findAll(pageRequestDto)).hasSize(0); - } + List crewDocumentCreateRequests; + + @BeforeEach + public void beforeEach() { + crewDocumentCreateRequests = List.of( + DocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title2", "content2", "writer2", 11L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title3", "content3", "writer3", 13L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title4", "content4", "writer4", 14L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title5", "content5", "writer5", 15L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title6", "content6", "writer6", 16L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title7", "content7", "writer7", 17L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title8", "content8", "writer8", 18L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title9", "content9", "writer9", 19L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title10", "content10", "writer10", 110L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title11", "content11", "writer11", 11L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title12", "content12", "writer12", 11L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title13", "content13", "writer13", 11L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title14", "content14", "writer14", 11L, + UUID.randomUUID()) + ); } - @Nested - @DisplayName("문서 전체 조회 기능 : Pageable") - class findAll_pageable { - - List crewDocumentCreateRequests; - - @BeforeEach - public void beforeEach() { - crewDocumentCreateRequests = List.of( - DocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title2", "content2", "writer2", 11L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title3", "content3", "writer3", 13L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title4", "content4", "writer4", 14L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title5", "content5", "writer5", 15L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title6", "content6", "writer6", 16L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title7", "content7", "writer7", 17L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title8", "content8", "writer8", 18L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title9", "content9", "writer9", 19L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title10", "content10", "writer10", 110L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title11", "content11", "writer11", 11L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title12", "content12", "writer12", 11L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title13", "content13", "writer13", 11L, - UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title14", "content14", "writer14", 11L, - UUID.randomUUID()) - ); + @DisplayName("저장된 문서가 존재할 때 요청 시 List 형태로 반환한다") + @Test + void findAll_success_bySomeData() { + // given + List requestDtos = List.of( + DocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, + UUID.randomUUID()), + DocumentFixture.createDocumentCreateRequest("title2", "content2", "writer2", 11L, + UUID.randomUUID()) + ); + + PagingRequest pageRequestDto = new PagingRequest(); + + // when + for (CrewDocumentCreateRequest documentRequestDto : requestDtos) { + documentService.postCrewDocument(documentRequestDto); } - @DisplayName("PageRequestDto의 default 값으로 동작하는 지 확인") - @Test - void findAll_success_byPageRequestDtoDefault() { - // given - PageRequestDto pageRequestDto = new PageRequestDto(); - - for (CrewDocumentCreateRequest documentRequestDto : crewDocumentCreateRequests) { - documentService.postCrewDocument(documentRequestDto); - } - - // when - Page<@NotNull Document> documentPages = documentService.findAll(pageRequestDto); - - // then - SoftAssertions softAssertions = new SoftAssertions(); - softAssertions.assertThat(documentPages.getTotalElements()).isEqualTo(crewDocumentCreateRequests.size()); - softAssertions.assertThat(documentPages.getNumber()).isEqualTo(0); - softAssertions.assertThat(documentPages.getTotalPages()).isEqualTo(2); - softAssertions.assertAll(); + // then + assertThat(documentService.findAll(pageRequestDto)).hasSize(requestDtos.size()); + } + + @DisplayName("저장된 문서가 존재하지 않을 때 요청 시 예외 없이 빈 리스트를 반환한다") + @Test + void findAll_success_byNoData() { + // given + PagingRequest pageRequestDto = new PagingRequest(); + + // when & then + assertThat(documentService.findAll(pageRequestDto)).hasSize(0); + } + + @DisplayName("PagingRequest의 default 값으로 동작하는 지 확인") + @Test + void findAll_success_byPagingRequestDefault() { + // given + PagingRequest pageRequestDto = new PagingRequest(); + + for (CrewDocumentCreateRequest documentRequestDto : crewDocumentCreateRequests) { + documentService.postCrewDocument(documentRequestDto); } - @DisplayName("PageRequestDto의 필드 값을 수정한 값으로 동작하는 지 확인") - @Test - void findAll_success_byPageRequestDto() { - // given - PageRequestDto pageRequestDto = new PageRequestDto(); - pageRequestDto.setPageNumber(1); - pageRequestDto.setPageSize(5); - pageRequestDto.setSort("uuid"); - pageRequestDto.setSortDirection("DESC"); - - for (CrewDocumentCreateRequest documentRequestDto : crewDocumentCreateRequests) { - documentService.postCrewDocument(documentRequestDto); - } - - // when - Page<@NotNull Document> documentPages = documentService.findAll(pageRequestDto); - - // then - SoftAssertions softAssertions = new SoftAssertions(); - softAssertions.assertThat(documentPages.getTotalElements()).isEqualTo(crewDocumentCreateRequests.size()); - softAssertions.assertThat(documentPages.getNumber()).isEqualTo(1); - softAssertions.assertThat(documentPages.getTotalPages()).isEqualTo(3); - softAssertions.assertAll(); + // when + Page<@NotNull Document> documentPages = documentService.findAll(pageRequestDto); + + // then + SoftAssertions softAssertions = new SoftAssertions(); + softAssertions.assertThat(documentPages.getTotalElements()).isEqualTo(crewDocumentCreateRequests.size()); + softAssertions.assertThat(documentPages.getNumber()).isEqualTo(0); + softAssertions.assertThat(documentPages.getTotalPages()).isEqualTo(2); + softAssertions.assertAll(); + } + + @DisplayName("PagingRequest의 필드 값을 수정한 값으로 동작하는 지 확인") + @Test + void findAll_success_byPagingRequest() { + // given + PagingRequest pageRequestDto = new PagingRequest(); + pageRequestDto.setPageNumber(1); + pageRequestDto.setPageSize(5); + pageRequestDto.setSort("uuid"); + pageRequestDto.setSortDirection("DESC"); + + for (CrewDocumentCreateRequest documentRequestDto : crewDocumentCreateRequests) { + documentService.postCrewDocument(documentRequestDto); } - @DisplayName("PageRequestDto 필드 중 pageNumber 와 pageSize는 음수가 불가능하도록 확인") - @Test - void findAll_throwsException_byNegativeNumber() { - // given - PageRequestDto pageRequestDto = new PageRequestDto(); - pageRequestDto.setPageNumber(-1); - pageRequestDto.setPageSize(5); - - for (CrewDocumentCreateRequest documentRequestDto : crewDocumentCreateRequests) { - documentService.postCrewDocument(documentRequestDto); - } - - // when & then - WikiException ex = assertThrows(WikiException.class, - () -> documentService.findAll(pageRequestDto)); - assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.PAGE_BAD_REQUEST); + // when + Page<@NotNull Document> documentPages = documentService.findAll(pageRequestDto); + + // then + SoftAssertions softAssertions = new SoftAssertions(); + softAssertions.assertThat(documentPages.getTotalElements()).isEqualTo(crewDocumentCreateRequests.size()); + softAssertions.assertThat(documentPages.getNumber()).isEqualTo(1); + softAssertions.assertThat(documentPages.getTotalPages()).isEqualTo(3); + softAssertions.assertAll(); + } + + @DisplayName("PagingRequest 필드 중 pageNumber 와 pageSize는 음수가 불가능하도록 확인") + @Test + void findAll_fail_byNegativePageNumber() { + // given + PagingRequest pageRequestDto = new PagingRequest(); + pageRequestDto.setPageNumber(-1); + pageRequestDto.setPageSize(5); + + for (CrewDocumentCreateRequest documentRequestDto : crewDocumentCreateRequests) { + documentService.postCrewDocument(documentRequestDto); } + + // when & then + WikiException ex = assertThrows(WikiException.class, + () -> documentService.findAll(pageRequestDto)); + assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.PAGE_BAD_REQUEST); } } @Nested @DisplayName("문서 uuid로 삭제 기능") - class deleteByUuid { + class DeleteByUuid { @DisplayName("존재하는 문서 id일 경우 문서가 로그들과 함께 삭제된다") @Test - void deleteById_success_byExistsId() { + void deleteByUuid_success_byExistingDocument() { // given DocumentResponse documentResponse = documentService.postCrewDocument( DocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, @@ -271,7 +264,7 @@ void deleteById_success_byExistsId() { @DisplayName("존재하지 않는 문서의 id일 경우 예외가 발생한다 : WikiException.DOCUMENT_NOT_FOUND") @Test - void deleteById_throwsException_byNonExistsId() { + void deleteByUuid_fail_byNonExistingDocument() { // when & then WikiException ex = assertThrows(WikiException.class, () -> documentService.deleteByUuid(UUID.randomUUID())); @@ -281,7 +274,7 @@ void deleteById_throwsException_byNonExistsId() { @Test @DisplayName("flushViews 호출 시 uuid별로 조회수가 증가된다") - void flushViews_success() { + void flushViews_success_byAccumulatedViewCount() { // given UUID uuid1 = UUID.randomUUID(); UUID uuid2 = UUID.randomUUID(); diff --git a/src/test/java/com/wooteco/wiki/global/auth/controller/AuthControllerTest.java b/src/test/java/com/wooteco/wiki/global/auth/controller/AuthControllerTest.java index 30284f1..e248b68 100644 --- a/src/test/java/com/wooteco/wiki/global/auth/controller/AuthControllerTest.java +++ b/src/test/java/com/wooteco/wiki/global/auth/controller/AuthControllerTest.java @@ -43,11 +43,11 @@ void setUp() { @Nested @DisplayName("로그인 기능") - class login { + class Login { @DisplayName("유효한 이메일과 비밀번호로 로그인을 성공한다.") @Test - void login_success() { + void login_success_byValidCredentials() { // given // when @@ -66,7 +66,7 @@ void login_success() { @DisplayName("유효하지 않는 이메일과 비밀번호로 로그인을 시도하여 실패: 상태 코드 404를 반환한다.") @Test - void login_throwException_byInvalidEmail() { + void login_fail_byInvalidCredentials() { // given // when LoginRequest requestDto = new LoginRequest("invalidLoginId", "invalidPassword"); @@ -85,11 +85,11 @@ void login_throwException_byInvalidEmail() { @Nested @DisplayName("토큰 기반 어드민 조회 API 테스트") - class checkAuth { + class CheckAuth { @DisplayName("토큰으로 어드민 조회 시 200 OK 반환") @Test - void checkAuth_success() { + void checkAuth_success_byValidToken() { // given String expectedLoginId = "loginIdCS"; Admin savedAdmin = adminRepository.save(new Admin(expectedLoginId, "password")); diff --git a/src/test/java/com/wooteco/wiki/global/auth/service/AuthServiceTest.java b/src/test/java/com/wooteco/wiki/global/auth/service/AuthServiceTest.java index 0423274..c557f15 100644 --- a/src/test/java/com/wooteco/wiki/global/auth/service/AuthServiceTest.java +++ b/src/test/java/com/wooteco/wiki/global/auth/service/AuthServiceTest.java @@ -8,7 +8,7 @@ import com.wooteco.wiki.admin.repository.AdminRepository; import com.wooteco.wiki.global.auth.JwtTokenProvider; import com.wooteco.wiki.global.auth.Role; -import com.wooteco.wiki.global.auth.domain.dto.TokenInfoDto; +import com.wooteco.wiki.global.auth.domain.dto.TokenInfoResponse; import com.wooteco.wiki.global.auth.domain.dto.TokenResponse; import com.wooteco.wiki.global.exception.ErrorCode; import com.wooteco.wiki.global.exception.WikiException; @@ -32,14 +32,14 @@ class AuthServiceTest { private AdminRepository adminRepository; @Nested - @DisplayName("TokenInfoDto로 Jwt 토큰 생성") - class createToken { + @DisplayName("TokenInfoResponse로 Jwt 토큰 생성") + class CreateToken { - @DisplayName("TokenInfoDto로 Jwt 토큰 생성된다.") + @DisplayName("TokenInfoResponse로 Jwt 토큰 생성된다.") @Test - void createToken_success() { + void createToken_success_byTokenInfoResponse() { // given - TokenInfoDto tokenInfoDto = new TokenInfoDto(1L, Role.ROLE_ADMIN); + TokenInfoResponse tokenInfoDto = new TokenInfoResponse(1L, Role.ROLE_ADMIN); // when TokenResponse tokenResponse = authService.createToken(tokenInfoDto); @@ -52,7 +52,7 @@ void createToken_success() { @Nested @DisplayName("loginRequest로 Jwt 토큰 생성") - class login { + class Login { @DisplayName("존재하는 어드민 정보로 요청했을 시 Jwt 토큰을 반환한다.") @Test @@ -71,7 +71,7 @@ void login_success_byExistingAdmin() { @DisplayName("존재하지 않는 어드민 정보로 요청했을 때 예외 발생한다. : WikiException.ADMIN_NOT_FOUND") @Test - void login_throwException_byInValidAdmin() { + void login_fail_byInvalidAdmin() { // given LoginRequest loginRequest = new LoginRequest("invalidLoginId", "invalidPassword"); diff --git a/src/test/java/com/wooteco/wiki/history/service/HistoryServiceTest.java b/src/test/java/com/wooteco/wiki/history/service/HistoryServiceTest.java index 4be778a..3651f21 100644 --- a/src/test/java/com/wooteco/wiki/history/service/HistoryServiceTest.java +++ b/src/test/java/com/wooteco/wiki/history/service/HistoryServiceTest.java @@ -7,7 +7,7 @@ import com.wooteco.wiki.document.domain.Document; import com.wooteco.wiki.document.fixture.DocumentFixture; import com.wooteco.wiki.document.repository.DocumentRepository; -import com.wooteco.wiki.global.common.PageRequestDto; +import com.wooteco.wiki.global.common.PagingRequest; import com.wooteco.wiki.global.exception.ErrorCode; import com.wooteco.wiki.global.exception.WikiException; import com.wooteco.wiki.history.domain.dto.HistoryResponse; @@ -39,25 +39,26 @@ public class HistoryServiceTest { @Autowired private HistoryRepository historyRepository; + private PagingRequest pageRequestDto; + private UUID documentUuid; + private CrewDocument savedCrewDocument; + + @BeforeEach + void setUp() { + pageRequestDto = new PagingRequest(); + savedCrewDocument = documentRepository.save( + DocumentFixture.createCrewDocument("title", "content", "writer", 100L, UUID.randomUUID())); + documentUuid = savedCrewDocument.getUuid(); + + historyRepository.save( + HistoryFixture.create("t1", "c1", "w1", 10L, LocalDateTime.now(), savedCrewDocument, 1L)); + historyRepository.save( + HistoryFixture.create("t1", "c2", "w2", 20L, LocalDateTime.now(), savedCrewDocument, 2L)); + } + @Nested @DisplayName("documentUuid로 요청 시 로그 리스트 반환하는 기능") - class findAllByCrewDocumentUuid { - - private PageRequestDto pageRequestDto = new PageRequestDto(); - private UUID documentUuid; - private CrewDocument savedCrewDocument; - - @BeforeEach - void setUp() { - savedCrewDocument = documentRepository.save( - DocumentFixture.createCrewDocument("title", "content", "writer", 100L, UUID.randomUUID())); - documentUuid = savedCrewDocument.getUuid(); - - historyRepository.save( - HistoryFixture.create("t1", "c1", "w1", 10L, LocalDateTime.now(), savedCrewDocument, 1L)); - historyRepository.save( - HistoryFixture.create("t1", "c2", "w2", 20L, LocalDateTime.now(), savedCrewDocument, 2L)); - } + class FindAllByDocumentUuid { @DisplayName("documentUuid에 해당하는 로그들이 반환된다") @Test @@ -76,7 +77,7 @@ void findAllByDocumentUuid_success_bySomeData() { @DisplayName("버전 번호가 순차적으로 부여된다") @Test - void findAllByDocumentUuid_versionsAreNumberedCorrectly() { + void findAllByDocumentUuid_success_bySequentialVersions() { // when Page actual = historyService.findAllByDocumentUuid(documentUuid, pageRequestDto); @@ -90,7 +91,7 @@ void findAllByDocumentUuid_versionsAreNumberedCorrectly() { @DisplayName("존재하지 않는 documentUuid로 요청 시 예외가 발생한다 : WikiException.DOCUMENT_NOT_FOUND") @Test - void findAllByDocumentUuid_throwsException_byNonExistsDocumentUuid() { + void findAllByDocumentUuid_fail_byNonExistsDocumentUuid() { // given UUID invalidUuid = UUID.randomUUID(); @@ -100,9 +101,15 @@ void findAllByDocumentUuid_throwsException_byNonExistsDocumentUuid() { assertThat(ex.getErrorCode()).isEqualTo(ErrorCode.DOCUMENT_NOT_FOUND); } + } + + @Nested + @DisplayName("로그 저장 기능") + class Save { + @DisplayName("로그 저장 시 최신 version을 제공한다.") @Test - void save_versionIsNumberedCorrectly() { + void save_success_byIncrementedVersion() { // when Document updatedDocument = savedCrewDocument.update("test_document_2", "contents", "writer1", 120L, LocalDateTime.now()); diff --git a/src/test/java/com/wooteco/wiki/organizationdocument/service/CrewDocumentOrganizationLinkServiceTest.java b/src/test/java/com/wooteco/wiki/organizationdocument/service/CrewDocumentOrganizationLinkServiceTest.java index 31c50b9..46301d1 100644 --- a/src/test/java/com/wooteco/wiki/organizationdocument/service/CrewDocumentOrganizationLinkServiceTest.java +++ b/src/test/java/com/wooteco/wiki/organizationdocument/service/CrewDocumentOrganizationLinkServiceTest.java @@ -54,7 +54,7 @@ void setUp() { @DisplayName("특정 문서와 특정 조직 문서로 둘을 연결한다.") @Test - void link_success_byDocumentAndOrganizationDocument() { + void link_success_byCrewAndOrganizationDocument() { // when documentOrgDocLinkService.link(savedCrewDocument, savedOrganizationDocument); @@ -73,7 +73,7 @@ void link_success_byDocumentAndOrganizationDocument() { @DisplayName("문서와 조직 문서 연결 해제 할 때에") @Nested - class UnLink { + class Unlink { private CrewDocument savedCrewDocument; private OrganizationDocument savedOrganizationDocument; @@ -91,7 +91,7 @@ void setUp() { @DisplayName("특정 문서와 특정 조직 문서의 연결을 해제한다") @Test - void unLink_success_byDocumentAndOrganizationDocument() { + void unlink_success_byCrewAndOrganizationDocument() { // when documentOrgDocLinkService.unlink(savedCrewDocument, savedOrganizationDocument); diff --git a/src/test/java/com/wooteco/wiki/organizationdocument/service/OrganizationCrewDocumentServiceTest.java b/src/test/java/com/wooteco/wiki/organizationdocument/service/OrganizationCrewDocumentServiceTest.java index d87d057..3071727 100644 --- a/src/test/java/com/wooteco/wiki/organizationdocument/service/OrganizationCrewDocumentServiceTest.java +++ b/src/test/java/com/wooteco/wiki/organizationdocument/service/OrganizationCrewDocumentServiceTest.java @@ -96,11 +96,11 @@ void updateOrganizationDocument_success_byValidData() { @DisplayName("조직 문서를 조회할 때") @Nested - class Find { + class FindByUuid { @DisplayName("올바른 값으로 조회된다.") @Test - void find_success_byValidData() { + void findByUuid_success_byValidData() { // given UUID uuid = UUID.randomUUID(); OrganizationDocument organizationDocument = OrganizationDocumentFixture @@ -133,7 +133,7 @@ class Create { @DisplayName("이미 있는 문서 이름이라면 예외가 발생한다.") @Test - void create_success_byValidData() { + void create_fail_byDuplicateTitle() { // given UUID uuid = UUID.randomUUID(); OrganizationDocument organizationDocument = OrganizationDocumentFixture @@ -153,7 +153,7 @@ void create_success_byValidData() { @DisplayName("첫 번째 로그가 저장된다.") @Test - void create_success_savesFirstHistory() { + void create_success_byFirstHistorySaved() { // given CrewDocument crewDocument = DocumentFixture.createDefaultCrewDocument(); CrewDocument savedCrewDocument = crewDocumentRepository.save(crewDocument); diff --git a/src/test/java/com/wooteco/wiki/organizationevent/controller/OrganizationEventControllerTest.java b/src/test/java/com/wooteco/wiki/organizationevent/controller/OrganizationEventControllerTest.java index 64a91d3..46b6acc 100644 --- a/src/test/java/com/wooteco/wiki/organizationevent/controller/OrganizationEventControllerTest.java +++ b/src/test/java/com/wooteco/wiki/organizationevent/controller/OrganizationEventControllerTest.java @@ -49,11 +49,11 @@ void setUp() { @Nested @DisplayName("조직 이벤트 생성 시") - class Create { + class Post { @Test @DisplayName("유효한 값이면 저장된다.") - void create_success() { + void post_success_byValidRequest() { Map body = Map.of( "title", "분기 워크숍", "contents", "OKR 점검", @@ -74,7 +74,7 @@ void create_success() { @Test @DisplayName("검증 실패시 400 예외가 발생한다.") - void create_fail_400_validation() { + void post_fail_byValidationError() { Map body = Map.of( "title", " ", "contents", "메모", @@ -94,7 +94,7 @@ void create_fail_400_validation() { @Test @DisplayName("존재하지 않은 조직 문서 uuid일 경우 404 예외가 발생한다.") - void create_fail_404_orgDocNotFound() { + void post_fail_byOrganizationDocumentNotFound() { Map body = Map.of( "title", "회의", "contents", "아젠다", @@ -115,11 +115,11 @@ void create_fail_404_orgDocNotFound() { @Nested @DisplayName("조직 문서를 수정 시") - class Update { + class Put { @Test @DisplayName("전달된 값으로 갱신된다.") - void update_success() { + void put_success_byUpdatedValues() { OrganizationEvent event = OrganizationEventFixture.createDefault(doc); organizationEventRepository.save(event); UUID eventUuid = event.getUuid(); @@ -145,7 +145,7 @@ void update_success() { @Test @DisplayName("이벤트가 존재하지 않을 경우 404 예외가 발생한다.") - void update_fail_404_eventNotFound() { + void put_fail_byEventNotFound() { Map body = Map.of( "title", "x", "contents", "y", @@ -164,7 +164,7 @@ void update_fail_404_eventNotFound() { @Test @DisplayName("검증이 실패할 경우 400 예외가 발생한다.") - void update_fail_400_validation() { + void put_fail_byValidationError() { OrganizationEvent event = OrganizationEventFixture.createDefault(doc); organizationEventRepository.save(event); UUID eventUuid = event.getUuid(); @@ -192,7 +192,7 @@ class Delete { @Test @DisplayName("정상적으로 삭제된다.") - void delete_success() { + void delete_success_byExistingEvent() { OrganizationEvent event = OrganizationEventFixture.createDefault(doc); organizationEventRepository.save(event); UUID eventUuid = event.getUuid(); @@ -206,7 +206,7 @@ void delete_success() { @Test @DisplayName("이벤트 없을 경우 404 예외가 발생한다.") - void delete_fail_404_eventNotFound() { + void delete_fail_byEventNotFound() { RestAssured.given().log().all() .when() .delete("/organization-events/{uuid}", UUID.randomUUID()) diff --git a/src/test/java/com/wooteco/wiki/organizationevent/service/OrganizationEventServiceTest.java b/src/test/java/com/wooteco/wiki/organizationevent/service/OrganizationEventServiceTest.java index 672d9a3..dc31943 100644 --- a/src/test/java/com/wooteco/wiki/organizationevent/service/OrganizationEventServiceTest.java +++ b/src/test/java/com/wooteco/wiki/organizationevent/service/OrganizationEventServiceTest.java @@ -38,11 +38,11 @@ class OrganizationEventServiceTest { @Nested @DisplayName("조직 이벤트 생성 시") - class Create { + class Post { @Test @DisplayName("유효한 값이면 저장되고 UUID가 반환된다.") - void create_success() { + void post_success_byValidRequest() { // given OrganizationDocument orgDoc = OrganizationDocumentFixture.createDefault(); organizationDocumentRepository.save(orgDoc); @@ -75,7 +75,7 @@ void create_success() { @Test @DisplayName("존재하지 않는 조직 문서 UUID면 404 예외가 발생한다.") - void create_fail_orgDocNotFound() { + void post_fail_byOrganizationDocumentNotFound() { // given OrganizationEventCreateRequest req = new OrganizationEventCreateRequest( "회의", @@ -91,101 +91,102 @@ void create_fail_orgDocNotFound() { .hasFieldOrPropertyWithValue("errorCode", ErrorCode.ORGANIZATION_DOCUMENT_NOT_FOUND); } - @Nested - @DisplayName("조직 이벤트 수정 시") - class Update { - - @Test - @DisplayName("전달된 값으로 갱신된다.") - void update_success() { - // given: 선행으로 문서 + 이벤트 하나 생성 - OrganizationDocument orgDoc = OrganizationDocumentFixture.createDefault(); - organizationDocumentRepository.save(orgDoc); - - OrganizationEventCreateRequest createReq = new OrganizationEventCreateRequest( - "분기 워크숍", - "OKR 점검", - "밍트", - LocalDate.now(), - orgDoc.getUuid() - ); - UUID eventUuid = organizationEventService.post(createReq).organizationEventUuid(); - - OrganizationEventUpdateRequest req = new OrganizationEventUpdateRequest( - "분기 워크숍(보강)", - "OKR + 액션아이템", - "밍트2", - LocalDate.now().plusDays(1) - ); - - // when - OrganizationEventUpdateResponse res = organizationEventService.put(eventUuid, req); - - // then - OrganizationEvent found = organizationEventRepository.findByUuid(eventUuid).orElseThrow(); - - assertSoftly(softly -> { - softly.assertThat(res.organizationEventUuid()).isEqualTo(eventUuid); - softly.assertThat(found.getTitle()).isEqualTo(req.title()); - softly.assertThat(found.getContents()).isEqualTo(req.contents()); - softly.assertThat(found.getWriter()).isEqualTo(req.writer()); - softly.assertThat(found.getOccurredAt()).isEqualTo(req.occurredAt()); - }); - } - - @Test - @DisplayName("존재하지 않는 이벤트 UUID면 404 예외가 발생한다.") - void update_fail_eventNotFound() { - // given - OrganizationEventUpdateRequest updateReq = new OrganizationEventUpdateRequest( - "x", "y", "z", LocalDate.now() - ); - - // then - assertThatThrownBy(() -> - organizationEventService.put(UUID.randomUUID(), updateReq)) - .isInstanceOf(WikiException.class) - .hasFieldOrPropertyWithValue("errorCode", ErrorCode.ORGANIZATION_EVENT_NOT_FOUND); - } + } + + @Nested + @DisplayName("조직 이벤트 수정 시") + class Put { + + @Test + @DisplayName("전달된 값으로 갱신된다.") + void put_success_byUpdatedValues() { + // given: 선행으로 문서 + 이벤트 하나 생성 + OrganizationDocument orgDoc = OrganizationDocumentFixture.createDefault(); + organizationDocumentRepository.save(orgDoc); + + OrganizationEventCreateRequest createReq = new OrganizationEventCreateRequest( + "분기 워크숍", + "OKR 점검", + "밍트", + LocalDate.now(), + orgDoc.getUuid() + ); + UUID eventUuid = organizationEventService.post(createReq).organizationEventUuid(); + + OrganizationEventUpdateRequest req = new OrganizationEventUpdateRequest( + "분기 워크숍(보강)", + "OKR + 액션아이템", + "밍트2", + LocalDate.now().plusDays(1) + ); + + // when + OrganizationEventUpdateResponse res = organizationEventService.put(eventUuid, req); + + // then + OrganizationEvent found = organizationEventRepository.findByUuid(eventUuid).orElseThrow(); + + assertSoftly(softly -> { + softly.assertThat(res.organizationEventUuid()).isEqualTo(eventUuid); + softly.assertThat(found.getTitle()).isEqualTo(req.title()); + softly.assertThat(found.getContents()).isEqualTo(req.contents()); + softly.assertThat(found.getWriter()).isEqualTo(req.writer()); + softly.assertThat(found.getOccurredAt()).isEqualTo(req.occurredAt()); + }); + } + + @Test + @DisplayName("존재하지 않는 이벤트 UUID면 404 예외가 발생한다.") + void put_fail_byEventNotFound() { + // given + OrganizationEventUpdateRequest updateReq = new OrganizationEventUpdateRequest( + "x", "y", "z", LocalDate.now() + ); + + // then + assertThatThrownBy(() -> + organizationEventService.put(UUID.randomUUID(), updateReq)) + .isInstanceOf(WikiException.class) + .hasFieldOrPropertyWithValue("errorCode", ErrorCode.ORGANIZATION_EVENT_NOT_FOUND); + } + } + + @Nested + @DisplayName("조직 이벤트 삭제 시") + class Delete { + + @Test + @DisplayName("정상적으로 삭제된다.") + void delete_success_byExistingEvent() { + // given + OrganizationDocument orgDoc = OrganizationDocumentFixture.createDefault(); + organizationDocumentRepository.save(orgDoc); + + OrganizationEventCreateRequest createReq = new OrganizationEventCreateRequest( + "분기 워크숍", + "OKR 점검", + "밍트", + LocalDate.now(), + orgDoc.getUuid() + ); + UUID eventUuid = organizationEventService.post(createReq).organizationEventUuid(); + + // when + organizationEventService.delete(eventUuid); + + // then + assertSoftly(softly -> { + softly.assertThat(organizationEventRepository.findByUuid(eventUuid)).isEmpty(); + }); } - @Nested - @DisplayName("조직 이벤트 삭제 시") - class Delete { - - @Test - @DisplayName("정상적으로 삭제된다.") - void delete_success() { - // given - OrganizationDocument orgDoc = OrganizationDocumentFixture.createDefault(); - organizationDocumentRepository.save(orgDoc); - - OrganizationEventCreateRequest createReq = new OrganizationEventCreateRequest( - "분기 워크숍", - "OKR 점검", - "밍트", - LocalDate.now(), - orgDoc.getUuid() - ); - UUID eventUuid = organizationEventService.post(createReq).organizationEventUuid(); - - // when - organizationEventService.delete(eventUuid); - - // then - assertSoftly(softly -> { - softly.assertThat(organizationEventRepository.findByUuid(eventUuid)).isEmpty(); - }); - } - - @Test - @DisplayName("존재하지 않는 이벤트 UUID면 404 예외가 발생한다.") - void delete_fail_eventNotFound() { - // then - assertThatThrownBy(() -> organizationEventService.delete(UUID.randomUUID())) - .isInstanceOf(WikiException.class) - .hasFieldOrPropertyWithValue("errorCode", ErrorCode.ORGANIZATION_EVENT_NOT_FOUND); - } + @Test + @DisplayName("존재하지 않는 이벤트 UUID면 404 예외가 발생한다.") + void delete_fail_byEventNotFound() { + // then + assertThatThrownBy(() -> organizationEventService.delete(UUID.randomUUID())) + .isInstanceOf(WikiException.class) + .hasFieldOrPropertyWithValue("errorCode", ErrorCode.ORGANIZATION_EVENT_NOT_FOUND); } } } From 315588658ae68b6e96535166f21bd85d75ffe883 Mon Sep 17 00:00:00 2001 From: "2jin2.1031" <2jin2.1031@gmail.com> Date: Tue, 3 Mar 2026 16:16:28 +0900 Subject: [PATCH 25/26] =?UTF-8?q?test:=20DocumentService=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=EB=A1=9C=20Crew/Organization=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...tFixture.java => CrewDocumentFixture.java} | 8 +- .../repository/DocumentRepositoryTest.java | 21 ++-- .../service/CrewDocumentServiceJavaTest.java | 4 +- .../service/CrewDocumentServiceTest.java | 67 +++++++++- .../service/DocumentSearchServiceTest.java | 8 +- .../document/service/DocumentServiceTest.java | 116 +++++------------- .../history/service/HistoryServiceTest.java | 4 +- ...ewDocumentOrganizationLinkServiceTest.java | 6 +- .../OrganizationCrewDocumentServiceTest.java | 5 +- 9 files changed, 116 insertions(+), 123 deletions(-) rename src/test/java/com/wooteco/wiki/document/fixture/{DocumentFixture.java => CrewDocumentFixture.java} (74%) diff --git a/src/test/java/com/wooteco/wiki/document/fixture/DocumentFixture.java b/src/test/java/com/wooteco/wiki/document/fixture/CrewDocumentFixture.java similarity index 74% rename from src/test/java/com/wooteco/wiki/document/fixture/DocumentFixture.java rename to src/test/java/com/wooteco/wiki/document/fixture/CrewDocumentFixture.java index aba4f2f..c80e1f4 100644 --- a/src/test/java/com/wooteco/wiki/document/fixture/DocumentFixture.java +++ b/src/test/java/com/wooteco/wiki/document/fixture/CrewDocumentFixture.java @@ -2,10 +2,9 @@ import com.wooteco.wiki.document.domain.CrewDocument; import com.wooteco.wiki.document.domain.dto.CrewDocumentCreateRequest; -import com.wooteco.wiki.document.domain.dto.DocumentUpdateRequest; import java.util.UUID; -public class DocumentFixture { +public class CrewDocumentFixture { public static CrewDocument createCrewDocument(String title, String content, String writer, Long documentBytes, UUID uuid) { @@ -24,9 +23,4 @@ public static CrewDocumentCreateRequest createDocumentCreateRequest(String title public static CrewDocumentCreateRequest createDocumentCreateRequestDefault() { return createDocumentCreateRequest("defaultTitle", "defaultContent", "defaultWriter", 10L, UUID.randomUUID()); } - - public static DocumentUpdateRequest createDocumentUpdateRequest(String title, String contents, String writer, - Long documentBytes) { - return new DocumentUpdateRequest(title, contents, writer, documentBytes, UUID.randomUUID()); - } } diff --git a/src/test/java/com/wooteco/wiki/document/repository/DocumentRepositoryTest.java b/src/test/java/com/wooteco/wiki/document/repository/DocumentRepositoryTest.java index 3a8a1c1..b47514e 100644 --- a/src/test/java/com/wooteco/wiki/document/repository/DocumentRepositoryTest.java +++ b/src/test/java/com/wooteco/wiki/document/repository/DocumentRepositoryTest.java @@ -5,8 +5,7 @@ import com.wooteco.wiki.document.domain.CrewDocument; import com.wooteco.wiki.document.domain.Document; import com.wooteco.wiki.document.domain.DocumentType; -import com.wooteco.wiki.document.fixture.DocumentFixture; -import com.wooteco.wiki.organizationdocument.domain.OrganizationDocument; +import com.wooteco.wiki.document.fixture.CrewDocumentFixture; import com.wooteco.wiki.organizationdocument.fixture.OrganizationDocumentFixture; import java.util.List; import java.util.Optional; @@ -45,7 +44,7 @@ void findUuidByTitle_success_byNonExistsDocument() { @Test void findUuidByTitle_success_byExistsDocument() { // given - CrewDocument savedCrewDocument = documentRepository.save(DocumentFixture.createDefaultCrewDocument()); + CrewDocument savedCrewDocument = documentRepository.save(CrewDocumentFixture.createDefaultCrewDocument()); // when Optional actual = documentRepository.findUuidByTitle(savedCrewDocument.getTitle()); @@ -64,7 +63,7 @@ class FindAll { void findAll_success_byMixedDocumentTypes() { // given documentRepository.save( - DocumentFixture.createCrewDocument("crew문서", "content1", "writer1", 10L, UUID.randomUUID())); + CrewDocumentFixture.createCrewDocument("crew문서", "content1", "writer1", 10L, UUID.randomUUID())); documentRepository.save( OrganizationDocumentFixture.create("org문서", "content2", "writer2", 15L, UUID.randomUUID())); @@ -86,9 +85,9 @@ void findAll_success_byMixedDocumentTypes() { void findAll_success_byOnlyCrewDocuments() { // given documentRepository.save( - DocumentFixture.createCrewDocument("crew1", "content1", "writer1", 10L, UUID.randomUUID())); + CrewDocumentFixture.createCrewDocument("crew1", "content1", "writer1", 10L, UUID.randomUUID())); documentRepository.save( - DocumentFixture.createCrewDocument("crew2", "content2", "writer2", 15L, UUID.randomUUID())); + CrewDocumentFixture.createCrewDocument("crew2", "content2", "writer2", 15L, UUID.randomUUID())); // when List result = documentRepository.findAll(); @@ -124,9 +123,9 @@ void findAll_success_byOnlyOrganizationDocuments() { void findAll_success_bySomeData() { // given documentRepository.save( - DocumentFixture.createCrewDocument("title1", "content1", "writer1", 10L, UUID.randomUUID())); + CrewDocumentFixture.createCrewDocument("title1", "content1", "writer1", 10L, UUID.randomUUID())); documentRepository.save( - DocumentFixture.createCrewDocument("title2", "content2", "writer2", 11L, UUID.randomUUID())); + CrewDocumentFixture.createCrewDocument("title2", "content2", "writer2", 11L, UUID.randomUUID())); // when List crewDocuments = documentRepository.findAll(); @@ -157,7 +156,7 @@ class FindIdByUuid { void setUp() { uuid = UUID.randomUUID(); - CrewDocument crewDocument = DocumentFixture.createCrewDocument("titl1", "content1", "writer1", 10L, uuid); + CrewDocument crewDocument = CrewDocumentFixture.createCrewDocument("titl1", "content1", "writer1", 10L, uuid); savedCrewDocument = documentRepository.save(crewDocument); } @@ -182,9 +181,9 @@ class FindAllByUuidIn { void findAllByUuidIn_success_byUuidSet() { // given CrewDocument doc1 = documentRepository.save( - DocumentFixture.createCrewDocument("title1", "content1", "writer1", 10L, UUID.randomUUID())); + CrewDocumentFixture.createCrewDocument("title1", "content1", "writer1", 10L, UUID.randomUUID())); CrewDocument doc2 = documentRepository.save( - DocumentFixture.createCrewDocument("title2", "content2", "writer2", 20L, UUID.randomUUID())); + CrewDocumentFixture.createCrewDocument("title2", "content2", "writer2", 20L, UUID.randomUUID())); Set uuids = Set.of(doc1.getUuid(), doc2.getUuid()); diff --git a/src/test/java/com/wooteco/wiki/document/service/CrewDocumentServiceJavaTest.java b/src/test/java/com/wooteco/wiki/document/service/CrewDocumentServiceJavaTest.java index c3b4f58..28e53a4 100644 --- a/src/test/java/com/wooteco/wiki/document/service/CrewDocumentServiceJavaTest.java +++ b/src/test/java/com/wooteco/wiki/document/service/CrewDocumentServiceJavaTest.java @@ -5,7 +5,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import com.wooteco.wiki.document.domain.CrewDocument; -import com.wooteco.wiki.document.fixture.DocumentFixture; +import com.wooteco.wiki.document.fixture.CrewDocumentFixture; import com.wooteco.wiki.document.repository.DocumentRepository; import com.wooteco.wiki.global.exception.ErrorCode; import com.wooteco.wiki.global.exception.WikiException; @@ -47,7 +47,7 @@ class CrewDocumentServiceJavaTest { @BeforeEach void setUp() { - CrewDocument crewDocument = DocumentFixture.createDefaultCrewDocument(); + CrewDocument crewDocument = CrewDocumentFixture.createDefaultCrewDocument(); savedCrewDocument = documentRepository.save(crewDocument); savedDocumentUuid = savedCrewDocument.getUuid(); } diff --git a/src/test/java/com/wooteco/wiki/document/service/CrewDocumentServiceTest.java b/src/test/java/com/wooteco/wiki/document/service/CrewDocumentServiceTest.java index 30457c5..422355c 100644 --- a/src/test/java/com/wooteco/wiki/document/service/CrewDocumentServiceTest.java +++ b/src/test/java/com/wooteco/wiki/document/service/CrewDocumentServiceTest.java @@ -8,7 +8,7 @@ import com.wooteco.wiki.document.domain.CrewDocument; import com.wooteco.wiki.document.domain.dto.DocumentResponse; import com.wooteco.wiki.document.domain.dto.DocumentUpdateRequest; -import com.wooteco.wiki.document.fixture.DocumentFixture; +import com.wooteco.wiki.document.fixture.CrewDocumentFixture; import com.wooteco.wiki.document.repository.DocumentRepository; import com.wooteco.wiki.global.exception.WikiException; import com.wooteco.wiki.history.domain.History; @@ -34,6 +34,33 @@ class CrewDocumentServiceTest { @Autowired private HistoryRepository historyRepository; + @DisplayName("문서 조회 기능") + @Nested + class GetByUuid { + + @DisplayName("문서 조회시, 해당 문서의 마지막 로그 번호를 가져온다.") + @Test + void getByUuid_success_byLatestVersionFromHistory() { + // given + CrewDocument crewDocument = CrewDocumentFixture.createDefaultCrewDocument(); + CrewDocument savedCrewDocument = documentRepository.save(crewDocument); + + History history = HistoryFixture.create("test", "test", "tesst", 150, LocalDateTime.of(2025, 7, 15, 10, 0, 0), + savedCrewDocument, 20L); + historyRepository.save(history); + + // when + DocumentUpdateRequest documentUpdateRequest = new DocumentUpdateRequest("test", "test", "test", 150L, + savedCrewDocument.getUuid()); + + crewDocumentService.update(savedCrewDocument.getUuid(), documentUpdateRequest); + DocumentResponse documentResponse = crewDocumentService.getByUuid(savedCrewDocument.getUuid()); + + // then + assertThat(documentResponse.latestVersion()).isEqualTo(21L); + } + } + @DisplayName("문서 조회 기능") @Nested class Find { @@ -42,7 +69,7 @@ class Find { @Test void getDocumentLatestVersion_success_byExistsDocument() { // given - CrewDocument crewDocument = DocumentFixture.createDefaultCrewDocument(); + CrewDocument crewDocument = CrewDocumentFixture.createDefaultCrewDocument(); CrewDocument savedCrewDocument = documentRepository.save(crewDocument); History history = HistoryFixture.create("test", "test", "tesst", 150, @@ -71,7 +98,7 @@ class deleteByUuid { void deleteById_success_byExistsId() { // given DocumentResponse documentResponse = crewDocumentService.create( - DocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, + CrewDocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, UUID.randomUUID())); // before then @@ -95,4 +122,38 @@ void deleteById_throwsException_byNonExistsId() { assertThat(ex.getErrorCode()).isEqualTo(DOCUMENT_NOT_FOUND); } } + + @Nested + @DisplayName("문서 uuid로 삭제 기능") + class DeleteByUuid { + + @DisplayName("존재하는 문서 id일 경우 문서가 로그들과 함께 삭제된다") + @Test + void deleteByUuid_success_byExistingDocument() { + // given + DocumentResponse documentResponse = crewDocumentService.create( + CrewDocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, + UUID.randomUUID())); + + // before then + assertThat(documentRepository.findAll()).hasSize(1); + assertThat(historyRepository.findAll()).hasSize(1); + + // when + crewDocumentService.deleteByUuid(documentResponse.documentUUID()); + + // after then + assertThat(documentRepository.findAll()).hasSize(0); + assertThat(historyRepository.findAll()).hasSize(0); + } + + @DisplayName("존재하지 않는 문서의 id일 경우 예외가 발생한다 : WikiException.DOCUMENT_NOT_FOUND") + @Test + void deleteByUuid_fail_byNonExistingDocument() { + // when & then + WikiException ex = assertThrows(WikiException.class, + () -> crewDocumentService.deleteByUuid(UUID.randomUUID())); + assertThat(ex.getErrorCode()).isEqualTo(DOCUMENT_NOT_FOUND); + } + } } diff --git a/src/test/java/com/wooteco/wiki/document/service/DocumentSearchServiceTest.java b/src/test/java/com/wooteco/wiki/document/service/DocumentSearchServiceTest.java index 0608e2a..7f5bcf7 100644 --- a/src/test/java/com/wooteco/wiki/document/service/DocumentSearchServiceTest.java +++ b/src/test/java/com/wooteco/wiki/document/service/DocumentSearchServiceTest.java @@ -5,7 +5,7 @@ import com.wooteco.wiki.admin.service.CrewDocumentService; import com.wooteco.wiki.document.domain.DocumentType; import com.wooteco.wiki.document.domain.dto.DocumentSearchResponse; -import com.wooteco.wiki.document.fixture.DocumentFixture; +import com.wooteco.wiki.document.fixture.CrewDocumentFixture; import com.wooteco.wiki.organizationdocument.domain.OrganizationDocument; import com.wooteco.wiki.organizationdocument.fixture.OrganizationDocumentFixture; import com.wooteco.wiki.organizationdocument.repository.OrganizationDocumentRepository; @@ -36,9 +36,9 @@ class DocumentSearchServiceTest { void search_success_byKeywordPrefix() { // given crewDocumentService.create( - DocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, UUID.randomUUID())); + CrewDocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, UUID.randomUUID())); crewDocumentService.create( - DocumentFixture.createDocumentCreateRequest("title2", "content2", "writer2", 11L, UUID.randomUUID())); + CrewDocumentFixture.createDocumentCreateRequest("title2", "content2", "writer2", 11L, UUID.randomUUID())); // when List result = documentSearchService.search("title"); @@ -65,7 +65,7 @@ void search_success_byNoMatch() { void search_success_byOrganizationDocumentType() { // given crewDocumentService.create( - DocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, UUID.randomUUID())); + CrewDocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, UUID.randomUUID())); OrganizationDocument organizationDocument = OrganizationDocumentFixture.create("title2", "content", "writer", 15L, UUID.randomUUID()); organizationDocumentRepository.save(organizationDocument); diff --git a/src/test/java/com/wooteco/wiki/document/service/DocumentServiceTest.java b/src/test/java/com/wooteco/wiki/document/service/DocumentServiceTest.java index 5aec924..45d252a 100644 --- a/src/test/java/com/wooteco/wiki/document/service/DocumentServiceTest.java +++ b/src/test/java/com/wooteco/wiki/document/service/DocumentServiceTest.java @@ -4,21 +4,18 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; +import com.wooteco.wiki.admin.service.CrewDocumentService; import com.wooteco.wiki.document.domain.CrewDocument; import com.wooteco.wiki.document.domain.Document; import com.wooteco.wiki.document.domain.dto.CrewDocumentCreateRequest; import com.wooteco.wiki.document.domain.dto.DocumentResponse; -import com.wooteco.wiki.document.domain.dto.DocumentUpdateRequest; import com.wooteco.wiki.document.domain.dto.DocumentUuidResponse; -import com.wooteco.wiki.document.fixture.DocumentFixture; +import com.wooteco.wiki.document.fixture.CrewDocumentFixture; import com.wooteco.wiki.document.repository.DocumentRepository; import com.wooteco.wiki.global.common.PagingRequest; import com.wooteco.wiki.global.exception.ErrorCode; import com.wooteco.wiki.global.exception.WikiException; -import com.wooteco.wiki.history.domain.History; -import com.wooteco.wiki.history.fixture.HistoryFixture; import com.wooteco.wiki.history.repository.HistoryRepository; -import java.time.LocalDateTime; import java.util.List; import java.util.Map; import java.util.UUID; @@ -41,36 +38,13 @@ class DocumentServiceTest { @Autowired private DocumentService documentService; @Autowired + private CrewDocumentService crewDocumentService; + @Autowired private DocumentRepository documentRepository; @Autowired private HistoryRepository historyRepository; - @DisplayName("문서 조회 기능") - @Nested - class GetByUuid { - - @DisplayName("문서 조회시, 해당 문서의 마지막 로그 번호를 가져온다.") - @Test - void getByUuid_success_byLatestVersionFromHistory() { - // given - CrewDocument crewDocument = DocumentFixture.createDefaultCrewDocument(); - CrewDocument savedCrewDocument = documentRepository.save(crewDocument); - - History history = HistoryFixture.create("test", "test", "tesst", 150, LocalDateTime.of(2025, 7, 15, 10, 0, 0), - savedCrewDocument, 20L); - historyRepository.save(history); - - // when - DocumentUpdateRequest documentUpdateRequest = new DocumentUpdateRequest("test", "test", "test", 150L, - savedCrewDocument.getUuid()); - documentService.put(savedCrewDocument.getUuid(), documentUpdateRequest); - DocumentResponse documentResponse = documentService.getByUuid(savedCrewDocument.getUuid()); - - // then - assertThat(documentResponse.latestVersion()).isEqualTo(21L); - } - } @Nested @DisplayName("문서 제목으로 조회하면 UUID를 반환하는 기능") @@ -80,8 +54,8 @@ class GetUuidByTitle { @Test void getUuidByTitle_success_byExistsDocumentTitle() { // given - DocumentResponse documentResponse = documentService.postCrewDocument( - DocumentFixture.createDocumentCreateRequestDefault()); + DocumentResponse documentResponse = crewDocumentService.create( + CrewDocumentFixture.createDocumentCreateRequestDefault()); // when DocumentUuidResponse documentUuidResponse = documentService.getUuidByTitle(documentResponse.title()); @@ -110,33 +84,33 @@ class FindAll { @BeforeEach public void beforeEach() { crewDocumentCreateRequests = List.of( - DocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, + CrewDocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title2", "content2", "writer2", 11L, + CrewDocumentFixture.createDocumentCreateRequest("title2", "content2", "writer2", 11L, UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title3", "content3", "writer3", 13L, + CrewDocumentFixture.createDocumentCreateRequest("title3", "content3", "writer3", 13L, UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title4", "content4", "writer4", 14L, + CrewDocumentFixture.createDocumentCreateRequest("title4", "content4", "writer4", 14L, UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title5", "content5", "writer5", 15L, + CrewDocumentFixture.createDocumentCreateRequest("title5", "content5", "writer5", 15L, UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title6", "content6", "writer6", 16L, + CrewDocumentFixture.createDocumentCreateRequest("title6", "content6", "writer6", 16L, UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title7", "content7", "writer7", 17L, + CrewDocumentFixture.createDocumentCreateRequest("title7", "content7", "writer7", 17L, UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title8", "content8", "writer8", 18L, + CrewDocumentFixture.createDocumentCreateRequest("title8", "content8", "writer8", 18L, UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title9", "content9", "writer9", 19L, + CrewDocumentFixture.createDocumentCreateRequest("title9", "content9", "writer9", 19L, UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title10", "content10", "writer10", 110L, + CrewDocumentFixture.createDocumentCreateRequest("title10", "content10", "writer10", 110L, UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title11", "content11", "writer11", 11L, + CrewDocumentFixture.createDocumentCreateRequest("title11", "content11", "writer11", 11L, UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title12", "content12", "writer12", 11L, + CrewDocumentFixture.createDocumentCreateRequest("title12", "content12", "writer12", 11L, UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title13", "content13", "writer13", 11L, + CrewDocumentFixture.createDocumentCreateRequest("title13", "content13", "writer13", 11L, UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title14", "content14", "writer14", 11L, + CrewDocumentFixture.createDocumentCreateRequest("title14", "content14", "writer14", 11L, UUID.randomUUID()) ); } @@ -146,9 +120,9 @@ public void beforeEach() { void findAll_success_bySomeData() { // given List requestDtos = List.of( - DocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, + CrewDocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, UUID.randomUUID()), - DocumentFixture.createDocumentCreateRequest("title2", "content2", "writer2", 11L, + CrewDocumentFixture.createDocumentCreateRequest("title2", "content2", "writer2", 11L, UUID.randomUUID()) ); @@ -156,7 +130,7 @@ void findAll_success_bySomeData() { // when for (CrewDocumentCreateRequest documentRequestDto : requestDtos) { - documentService.postCrewDocument(documentRequestDto); + crewDocumentService.create(documentRequestDto); } // then @@ -180,7 +154,7 @@ void findAll_success_byPagingRequestDefault() { PagingRequest pageRequestDto = new PagingRequest(); for (CrewDocumentCreateRequest documentRequestDto : crewDocumentCreateRequests) { - documentService.postCrewDocument(documentRequestDto); + crewDocumentService.create(documentRequestDto); } // when @@ -205,7 +179,7 @@ void findAll_success_byPagingRequest() { pageRequestDto.setSortDirection("DESC"); for (CrewDocumentCreateRequest documentRequestDto : crewDocumentCreateRequests) { - documentService.postCrewDocument(documentRequestDto); + crewDocumentService.create(documentRequestDto); } // when @@ -228,7 +202,7 @@ void findAll_fail_byNegativePageNumber() { pageRequestDto.setPageSize(5); for (CrewDocumentCreateRequest documentRequestDto : crewDocumentCreateRequests) { - documentService.postCrewDocument(documentRequestDto); + crewDocumentService.create(documentRequestDto); } // when & then @@ -238,40 +212,6 @@ void findAll_fail_byNegativePageNumber() { } } - @Nested - @DisplayName("문서 uuid로 삭제 기능") - class DeleteByUuid { - - @DisplayName("존재하는 문서 id일 경우 문서가 로그들과 함께 삭제된다") - @Test - void deleteByUuid_success_byExistingDocument() { - // given - DocumentResponse documentResponse = documentService.postCrewDocument( - DocumentFixture.createDocumentCreateRequest("title1", "content1", "writer1", 10L, - UUID.randomUUID())); - - // before then - assertThat(documentRepository.findAll()).hasSize(1); - assertThat(historyRepository.findAll()).hasSize(1); - - // when - documentService.deleteByUuid(documentResponse.documentUUID()); - - // after then - assertThat(documentRepository.findAll()).hasSize(0); - assertThat(historyRepository.findAll()).hasSize(0); - } - - @DisplayName("존재하지 않는 문서의 id일 경우 예외가 발생한다 : WikiException.DOCUMENT_NOT_FOUND") - @Test - void deleteByUuid_fail_byNonExistingDocument() { - // when & then - WikiException ex = assertThrows(WikiException.class, - () -> documentService.deleteByUuid(UUID.randomUUID())); - assertThat(ex.getErrorCode()).isEqualTo(DOCUMENT_NOT_FOUND); - } - } - @Test @DisplayName("flushViews 호출 시 uuid별로 조회수가 증가된다") void flushViews_success_byAccumulatedViewCount() { @@ -279,9 +219,9 @@ void flushViews_success_byAccumulatedViewCount() { UUID uuid1 = UUID.randomUUID(); UUID uuid2 = UUID.randomUUID(); CrewDocument doc1 = documentRepository.save( - DocumentFixture.createCrewDocument("title1", "content1", "writer1", 10L, uuid1)); + CrewDocumentFixture.createCrewDocument("title1", "content1", "writer1", 10L, uuid1)); CrewDocument doc2 = documentRepository.save( - DocumentFixture.createCrewDocument("title2", "content2", "writer2", 10L, uuid2)); + CrewDocumentFixture.createCrewDocument("title2", "content2", "writer2", 10L, uuid2)); Map viewMap = Map.of( uuid1, 5, diff --git a/src/test/java/com/wooteco/wiki/history/service/HistoryServiceTest.java b/src/test/java/com/wooteco/wiki/history/service/HistoryServiceTest.java index 3651f21..7bbf86c 100644 --- a/src/test/java/com/wooteco/wiki/history/service/HistoryServiceTest.java +++ b/src/test/java/com/wooteco/wiki/history/service/HistoryServiceTest.java @@ -5,7 +5,7 @@ import com.wooteco.wiki.document.domain.CrewDocument; import com.wooteco.wiki.document.domain.Document; -import com.wooteco.wiki.document.fixture.DocumentFixture; +import com.wooteco.wiki.document.fixture.CrewDocumentFixture; import com.wooteco.wiki.document.repository.DocumentRepository; import com.wooteco.wiki.global.common.PagingRequest; import com.wooteco.wiki.global.exception.ErrorCode; @@ -47,7 +47,7 @@ public class HistoryServiceTest { void setUp() { pageRequestDto = new PagingRequest(); savedCrewDocument = documentRepository.save( - DocumentFixture.createCrewDocument("title", "content", "writer", 100L, UUID.randomUUID())); + CrewDocumentFixture.createCrewDocument("title", "content", "writer", 100L, UUID.randomUUID())); documentUuid = savedCrewDocument.getUuid(); historyRepository.save( diff --git a/src/test/java/com/wooteco/wiki/organizationdocument/service/CrewDocumentOrganizationLinkServiceTest.java b/src/test/java/com/wooteco/wiki/organizationdocument/service/CrewDocumentOrganizationLinkServiceTest.java index 46301d1..fbe7613 100644 --- a/src/test/java/com/wooteco/wiki/organizationdocument/service/CrewDocumentOrganizationLinkServiceTest.java +++ b/src/test/java/com/wooteco/wiki/organizationdocument/service/CrewDocumentOrganizationLinkServiceTest.java @@ -4,7 +4,7 @@ import static org.assertj.core.api.SoftAssertions.assertSoftly; import com.wooteco.wiki.document.domain.CrewDocument; -import com.wooteco.wiki.document.fixture.DocumentFixture; +import com.wooteco.wiki.document.fixture.CrewDocumentFixture; import com.wooteco.wiki.document.repository.CrewDocumentRepository; import com.wooteco.wiki.organizationdocument.domain.DocumentOrganizationLink; import com.wooteco.wiki.organizationdocument.domain.OrganizationDocument; @@ -45,7 +45,7 @@ class Link { @BeforeEach void setUp() { - CrewDocument crewDocument = DocumentFixture.createDefaultCrewDocument(); + CrewDocument crewDocument = CrewDocumentFixture.createDefaultCrewDocument(); savedCrewDocument = crewDocumentRepository.save(crewDocument); OrganizationDocument organizationDocument = OrganizationDocumentFixture.createDefault(); @@ -80,7 +80,7 @@ class Unlink { @BeforeEach void setUp() { - CrewDocument crewDocument = DocumentFixture.createDefaultCrewDocument(); + CrewDocument crewDocument = CrewDocumentFixture.createDefaultCrewDocument(); savedCrewDocument = crewDocumentRepository.save(crewDocument); OrganizationDocument organizationDocument = OrganizationDocumentFixture.createDefault(); diff --git a/src/test/java/com/wooteco/wiki/organizationdocument/service/OrganizationCrewDocumentServiceTest.java b/src/test/java/com/wooteco/wiki/organizationdocument/service/OrganizationCrewDocumentServiceTest.java index 3071727..2cbd5ce 100644 --- a/src/test/java/com/wooteco/wiki/organizationdocument/service/OrganizationCrewDocumentServiceTest.java +++ b/src/test/java/com/wooteco/wiki/organizationdocument/service/OrganizationCrewDocumentServiceTest.java @@ -4,7 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import com.wooteco.wiki.document.domain.CrewDocument; -import com.wooteco.wiki.document.fixture.DocumentFixture; +import com.wooteco.wiki.document.fixture.CrewDocumentFixture; import com.wooteco.wiki.document.repository.CrewDocumentRepository; import com.wooteco.wiki.global.exception.ErrorCode; import com.wooteco.wiki.global.exception.WikiException; @@ -20,7 +20,6 @@ import com.wooteco.wiki.organizationevent.domain.OrganizationEvent; import com.wooteco.wiki.organizationevent.fixture.OrganizationEventFixture; import com.wooteco.wiki.organizationevent.repository.OrganizationEventRepository; -import java.util.List; import java.util.UUID; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; @@ -155,7 +154,7 @@ void create_fail_byDuplicateTitle() { @Test void create_success_byFirstHistorySaved() { // given - CrewDocument crewDocument = DocumentFixture.createDefaultCrewDocument(); + CrewDocument crewDocument = CrewDocumentFixture.createDefaultCrewDocument(); CrewDocument savedCrewDocument = crewDocumentRepository.save(crewDocument); OrganizationDocumentCreateRequest organizationDocumentCreateRequest = new OrganizationDocumentCreateRequest( From cc11cfa15600fcfb150f78be19e098a185c5fcfd Mon Sep 17 00:00:00 2001 From: "2jin2.1031" <2jin2.1031@gmail.com> Date: Thu, 5 Mar 2026 03:03:36 +0900 Subject: [PATCH 26/26] =?UTF-8?q?feat:=20=EA=B8=B0=EC=A1=B4=20=EC=A1=B0?= =?UTF-8?q?=EC=A7=81=20=EB=AC=B8=EC=84=9C=EB=A5=BC=20=ED=81=AC=EB=A3=A8=20?= =?UTF-8?q?=EB=AC=B8=EC=84=9C=EC=97=90=20=EC=97=B0=EA=B2=B0=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../OrganizationDocumentController.java | 11 ++ .../OrganizationDocumentLinkRequest.java | 9 ++ .../service/OrganizationDocumentService.java | 9 ++ .../OrganizationDocumentServiceTest.java | 108 ++++++++++++++++++ 4 files changed, 137 insertions(+) create mode 100644 src/main/java/com/wooteco/wiki/organizationdocument/dto/request/OrganizationDocumentLinkRequest.java create mode 100644 src/test/java/com/wooteco/wiki/organizationdocument/service/OrganizationDocumentServiceTest.java diff --git a/src/main/java/com/wooteco/wiki/organizationdocument/controller/OrganizationDocumentController.java b/src/main/java/com/wooteco/wiki/organizationdocument/controller/OrganizationDocumentController.java index 7e2f03f..580ad2f 100644 --- a/src/main/java/com/wooteco/wiki/organizationdocument/controller/OrganizationDocumentController.java +++ b/src/main/java/com/wooteco/wiki/organizationdocument/controller/OrganizationDocumentController.java @@ -4,6 +4,7 @@ import com.wooteco.wiki.global.common.ApiResponse.SuccessBody; import com.wooteco.wiki.global.common.ApiResponseGenerator; import com.wooteco.wiki.organizationdocument.dto.request.OrganizationDocumentCreateRequest; +import com.wooteco.wiki.organizationdocument.dto.request.OrganizationDocumentLinkRequest; import com.wooteco.wiki.organizationdocument.dto.request.OrganizationDocumentUpdateRequest; import com.wooteco.wiki.organizationdocument.dto.response.OrganizationDocumentAndEventResponse; import com.wooteco.wiki.organizationdocument.dto.response.OrganizationDocumentResponse; @@ -42,6 +43,16 @@ public ApiResponse> createOrganization return ApiResponseGenerator.success(organizationDocumentResponse); } + @Operation(summary = "기존 조직 문서를 크루 문서에 연결", description = "이미 존재하는 조직 문서를 크루 문서와 연결합니다.") + @PostMapping("/link") + public ApiResponse> linkOrganizationDocument( + @RequestBody OrganizationDocumentLinkRequest organizationDocumentLinkRequest) { + OrganizationDocumentResponse organizationDocumentResponse = organizationDocumentService.link( + organizationDocumentLinkRequest); + + return ApiResponseGenerator.success(organizationDocumentResponse); + } + @Operation(summary = "조직 위키 글 수정", description = "조직 위키 글을 수정합니다.") @PutMapping public ApiResponse> modifyOrganizationDocumentContents( diff --git a/src/main/java/com/wooteco/wiki/organizationdocument/dto/request/OrganizationDocumentLinkRequest.java b/src/main/java/com/wooteco/wiki/organizationdocument/dto/request/OrganizationDocumentLinkRequest.java new file mode 100644 index 0000000..722fff5 --- /dev/null +++ b/src/main/java/com/wooteco/wiki/organizationdocument/dto/request/OrganizationDocumentLinkRequest.java @@ -0,0 +1,9 @@ +package com.wooteco.wiki.organizationdocument.dto.request; + +import java.util.UUID; + +public record OrganizationDocumentLinkRequest( + UUID crewDocumentUuid, + UUID organizationDocumentUuid +) { +} \ No newline at end of file diff --git a/src/main/java/com/wooteco/wiki/organizationdocument/service/OrganizationDocumentService.java b/src/main/java/com/wooteco/wiki/organizationdocument/service/OrganizationDocumentService.java index 520c10e..7075111 100644 --- a/src/main/java/com/wooteco/wiki/organizationdocument/service/OrganizationDocumentService.java +++ b/src/main/java/com/wooteco/wiki/organizationdocument/service/OrganizationDocumentService.java @@ -10,6 +10,7 @@ import com.wooteco.wiki.history.service.HistoryService; import com.wooteco.wiki.organizationdocument.domain.OrganizationDocument; import com.wooteco.wiki.organizationdocument.dto.request.OrganizationDocumentCreateRequest; +import com.wooteco.wiki.organizationdocument.dto.request.OrganizationDocumentLinkRequest; import com.wooteco.wiki.organizationdocument.dto.request.OrganizationDocumentUpdateRequest; import com.wooteco.wiki.organizationdocument.dto.response.OrganizationDocumentAndEventResponse; import com.wooteco.wiki.organizationdocument.dto.response.OrganizationDocumentResponse; @@ -47,6 +48,14 @@ public OrganizationDocumentResponse create(OrganizationDocumentCreateRequest org return new OrganizationDocumentResponse(savedOrganizationDocument); } + public OrganizationDocumentResponse link(OrganizationDocumentLinkRequest organizationDocumentLinkRequest) { + CrewDocument crewDocument = getCrewDocument(organizationDocumentLinkRequest.crewDocumentUuid()); + OrganizationDocument organizationDocument = getOrganizationDocument( + organizationDocumentLinkRequest.organizationDocumentUuid()); + documentOrganizationLinkService.link(crewDocument, organizationDocument); + return new OrganizationDocumentResponse(organizationDocument); + } + public OrganizationDocumentResponse update(OrganizationDocumentUpdateRequest organizationDocumentUpdateRequest) { OrganizationDocument organizationDocument = organizationDocumentRepository.findByUuid( organizationDocumentUpdateRequest.uuid()) diff --git a/src/test/java/com/wooteco/wiki/organizationdocument/service/OrganizationDocumentServiceTest.java b/src/test/java/com/wooteco/wiki/organizationdocument/service/OrganizationDocumentServiceTest.java new file mode 100644 index 0000000..6715d6c --- /dev/null +++ b/src/test/java/com/wooteco/wiki/organizationdocument/service/OrganizationDocumentServiceTest.java @@ -0,0 +1,108 @@ +package com.wooteco.wiki.organizationdocument.service; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.SoftAssertions.assertSoftly; + +import com.wooteco.wiki.document.domain.CrewDocument; +import com.wooteco.wiki.document.fixture.CrewDocumentFixture; +import com.wooteco.wiki.document.repository.CrewDocumentRepository; +import com.wooteco.wiki.global.exception.WikiException; +import com.wooteco.wiki.organizationdocument.domain.DocumentOrganizationLink; +import com.wooteco.wiki.organizationdocument.domain.OrganizationDocument; +import com.wooteco.wiki.organizationdocument.dto.request.OrganizationDocumentLinkRequest; +import com.wooteco.wiki.organizationdocument.fixture.OrganizationDocumentFixture; +import com.wooteco.wiki.organizationdocument.repository.DocumentOrganizationLinkRepository; +import com.wooteco.wiki.organizationdocument.repository.OrganizationDocumentRepository; +import java.util.UUID; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE) +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) +class OrganizationDocumentServiceTest { + + @Autowired + private OrganizationDocumentService organizationDocumentService; + + @Autowired + private CrewDocumentRepository crewDocumentRepository; + + @Autowired + private OrganizationDocumentRepository organizationDocumentRepository; + + @Autowired + private DocumentOrganizationLinkRepository documentOrganizationLinkRepository; + + @DisplayName("기존 조직 문서를 크루 문서에 연결할 때") + @Nested + class LinkExistingOrganization { + + private CrewDocument savedCrewDocument; + private OrganizationDocument savedOrganizationDocument; + + @BeforeEach + void setUp() { + CrewDocument crewDocument = CrewDocumentFixture.createDefaultCrewDocument(); + savedCrewDocument = crewDocumentRepository.save(crewDocument); + + OrganizationDocument organizationDocument = OrganizationDocumentFixture.createDefault(); + savedOrganizationDocument = organizationDocumentRepository.save(organizationDocument); + } + + @DisplayName("성공적으로 기존 조직 문서를 크루 문서와 연결한다") + @Test + void link_success() { + // given + OrganizationDocumentLinkRequest request = new OrganizationDocumentLinkRequest( + savedCrewDocument.getUuid(), + savedOrganizationDocument.getUuid() + ); + + // when + organizationDocumentService.link(request); + + // then + DocumentOrganizationLink link = documentOrganizationLinkRepository + .findByCrewDocumentAndOrganizationDocument(savedCrewDocument, savedOrganizationDocument) + .orElseThrow(); + + assertSoftly(softly -> { + softly.assertThat(link.getCrewDocument().getId()).isEqualTo(savedCrewDocument.getId()); + softly.assertThat(link.getOrganizationDocument().getId()).isEqualTo(savedOrganizationDocument.getId()); + }); + } + + @DisplayName("존재하지 않는 크루 문서 UUID로 연결을 시도하면 예외가 발생한다") + @Test + void link_fail_crewDocumentNotFound() { + // given + OrganizationDocumentLinkRequest request = new OrganizationDocumentLinkRequest( + UUID.randomUUID(), + savedOrganizationDocument.getUuid() + ); + + // when & then + assertThatThrownBy(() -> organizationDocumentService.link(request)) + .isInstanceOf(WikiException.class); + } + + @DisplayName("존재하지 않는 조직 문서 UUID로 연결을 시도하면 예외가 발생한다") + @Test + void link_fail_organizationDocumentNotFound() { + // given + OrganizationDocumentLinkRequest request = new OrganizationDocumentLinkRequest( + savedCrewDocument.getUuid(), + UUID.randomUUID() + ); + + // when & then + assertThatThrownBy(() -> organizationDocumentService.link(request)) + .isInstanceOf(WikiException.class); + } + } +}