From 75bfac055c3c0fc78fe307d229a1e8accfd775e2 Mon Sep 17 00:00:00 2001 From: seongjunkim Date: Sun, 8 Dec 2024 16:50:21 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=ED=8F=AC=ED=8A=B8=ED=8F=B4?= =?UTF-8?q?=EB=A6=AC=EC=98=A4=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 --- .../gaeme/controller/PortfolioController.java | 8 ++++++++ .../com/bigant/gaeme/dto/PortfolioDto.java | 3 +++ .../gaeme/repository/entity/Portfolio.java | 2 ++ .../bigant/gaeme/service/PortfolioService.java | 18 ++++++++++++++++++ 4 files changed, 31 insertions(+) diff --git a/src/main/java/com/bigant/gaeme/controller/PortfolioController.java b/src/main/java/com/bigant/gaeme/controller/PortfolioController.java index b9f625a..42971ac 100644 --- a/src/main/java/com/bigant/gaeme/controller/PortfolioController.java +++ b/src/main/java/com/bigant/gaeme/controller/PortfolioController.java @@ -33,4 +33,12 @@ public List getMine(@RequestHeader(HttpHeaders.AUTHORIZATION) Stri return portfolioService.getMine(jwtBuilder.decryptJwt(token)); } + @DeleteMapping + public PortfolioDto delete( + @RequestHeader(HttpHeaders.AUTHORIZATION) String token, + @RequestParam Long id + ) { + return portfolioService.delete(jwtBuilder.decryptJwt(token), id); + } + } diff --git a/src/main/java/com/bigant/gaeme/dto/PortfolioDto.java b/src/main/java/com/bigant/gaeme/dto/PortfolioDto.java index 9190937..c5cde81 100644 --- a/src/main/java/com/bigant/gaeme/dto/PortfolioDto.java +++ b/src/main/java/com/bigant/gaeme/dto/PortfolioDto.java @@ -16,6 +16,9 @@ public class PortfolioDto { private List stocks; + @Builder.Default + private boolean isDeleted = false; + @Data @AllArgsConstructor @NoArgsConstructor diff --git a/src/main/java/com/bigant/gaeme/repository/entity/Portfolio.java b/src/main/java/com/bigant/gaeme/repository/entity/Portfolio.java index c908f9f..d69ded4 100644 --- a/src/main/java/com/bigant/gaeme/repository/entity/Portfolio.java +++ b/src/main/java/com/bigant/gaeme/repository/entity/Portfolio.java @@ -19,6 +19,8 @@ public class Portfolio { private String name; + private Boolean isDeleted; + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id") private User user; diff --git a/src/main/java/com/bigant/gaeme/service/PortfolioService.java b/src/main/java/com/bigant/gaeme/service/PortfolioService.java index 37da28b..b4b507e 100644 --- a/src/main/java/com/bigant/gaeme/service/PortfolioService.java +++ b/src/main/java/com/bigant/gaeme/service/PortfolioService.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -129,4 +130,21 @@ public List getMine(Long requestId) { return portfolioStocksByPortfolio.entrySet().stream().map(convertDto).toList(); } + + @Transactional + public PortfolioDto delete(Long requestId, Long portfolioId) { + User user = userRepository.findById(requestId).orElseThrow(); + Portfolio portfolio = portfolioRepository.findById(portfolioId).orElseThrow(); + + if (!Objects.equals(portfolio.getUser().getId(), user.getId())) { + throw new IllegalStateException("리소스를 삭제할 권한이 없습니다"); + } + + portfolio.setIsDeleted(true); + return PortfolioDto.builder() + .name(portfolio.getName()) + .stocks(List.of()) + .isDeleted(true) + .build(); + } } From 39e140b4000b74bdcd0aa2d5914afd7a221f3f66 Mon Sep 17 00:00:00 2001 From: seongjunkim Date: Sun, 8 Dec 2024 16:58:08 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=ED=8F=AC=ED=8A=B8=ED=8F=B4?= =?UTF-8?q?=EB=A6=AC=EC=98=A4=20=EC=82=AD=EC=A0=9C=20API=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/docs/asciidoc/portfolio.adoc | 3 ++ .../controller/PortfolioControllerTest.java | 32 +++++++++++++++++++ .../gaeme/service/PortfolioServiceTest.java | 29 +++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/src/docs/asciidoc/portfolio.adoc b/src/docs/asciidoc/portfolio.adoc index e10341e..9872f0f 100644 --- a/src/docs/asciidoc/portfolio.adoc +++ b/src/docs/asciidoc/portfolio.adoc @@ -3,6 +3,9 @@ === 포트폴리오 생성 operation::portfolio/post[snippets="http-request,http-response,request-fields"] +=== 포트폴리오 삭제 +operation::portfolio/delete[snippetes="http-request,http-response"] + === 내 포트폴리오 조회 operation::my-portfolio/get[snippets="http-request,http-response"] diff --git a/src/test/java/com/bigant/gaeme/controller/PortfolioControllerTest.java b/src/test/java/com/bigant/gaeme/controller/PortfolioControllerTest.java index 5562ce5..69eecc4 100644 --- a/src/test/java/com/bigant/gaeme/controller/PortfolioControllerTest.java +++ b/src/test/java/com/bigant/gaeme/controller/PortfolioControllerTest.java @@ -171,6 +171,7 @@ RestDocumentationResultHandler getBacktestGetResultHandler() { requestFields(fieldWithPath("portfolio").type(JsonFieldType.OBJECT).description("포트폴리오"), fieldWithPath("portfolio.name").type(JsonFieldType.STRING).description("포트폴리오 이름"), fieldWithPath("portfolio.stocks").type(JsonFieldType.ARRAY).description("보유 주식"), + fieldWithPath("portfolio.deleted").type(JsonFieldType.BOOLEAN).description("삭제 여부"), fieldWithPath("portfolio.stocks.[].symbol").type(JsonFieldType.STRING).description("주식 심볼"), fieldWithPath("portfolio.stocks.[].rate").type(JsonFieldType.NUMBER).description("주식 비중"), fieldWithPath("startDate").type(JsonFieldType.STRING).description("시작 날짜"), @@ -218,4 +219,35 @@ RestDocumentationResultHandler getMyPortfolioGetHandler() { ); } + @Test + void delete() throws Exception { + //given + BDDMockito.given(portfolioService.delete(BDDMockito.any(), BDDMockito.any())).willReturn( + PortfolioDto.builder() + .name("test-portfolio") + .stocks(List.of()) + .isDeleted(true) + .build() + ); + + //when + mockMvc.perform(RestDocumentationRequestBuilders.delete("/v1/portfolio?id=1") + .contentType(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, "Bearer token") + .characterEncoding(StandardCharsets.UTF_8)) + .andDo(print()) + .andExpect(status().isOk()) + .andDo(getPortfolioDeleteHandler()); + + //then + BDDMockito.then(portfolioService).should().delete(BDDMockito.any(), BDDMockito.any()); + } + + RestDocumentationResultHandler getPortfolioDeleteHandler() { + return document("portfolio/delete", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()) + ); + } + } diff --git a/src/test/java/com/bigant/gaeme/service/PortfolioServiceTest.java b/src/test/java/com/bigant/gaeme/service/PortfolioServiceTest.java index 37638dc..78ed428 100644 --- a/src/test/java/com/bigant/gaeme/service/PortfolioServiceTest.java +++ b/src/test/java/com/bigant/gaeme/service/PortfolioServiceTest.java @@ -227,4 +227,33 @@ public PortfolioServiceTest( ), result); } + @Test + void 포트폴리오_삭제_성공() { + //given + User user = TestFixture.getTestUser(); + Portfolio portfolio = TestFixture.getTestPortfolio(user); + Stock stock = TestFixture.getTestStock(); + + userRepository.save(user); + portfolioRepository.save(portfolio); + stockRepository.save(stock); + portfolioStockRepository.save(PortfolioStock.builder() + .rate(100) + .portfolio(portfolio) + .stock(stock) + .build()); + + //when + PortfolioDto result = portfolioService.delete(user.getId(), portfolio.getId()); + + //then + Assertions.assertEquals( + PortfolioDto.builder() + .name("test-portfolio") + .stocks(List.of()) + .isDeleted(true) + .build(), result + ); + } + }