Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] #15 아카이브 비즈니스 로직 및 API 개발 #16

Merged
merged 9 commits into from
May 13, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package kusitms.duduk.apiserver.archive.presentation;

import kusitms.duduk.apiserver.security.infrastructure.CustomUserDetails;
import kusitms.duduk.core.archive.dto.response.ArchiveResponse;
import kusitms.duduk.core.archive.port.input.RetrieveArchiveUseCase;
import kusitms.duduk.domain.global.Category;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequiredArgsConstructor
@RestController
@RequestMapping("/api/archies")
public class ArchiveController implements ArchiveControllerDocs {

private final RetrieveArchiveUseCase retrieveArchiveUseCase;

@GetMapping("/newsletters/{category}")
public ResponseEntity<ArchiveResponse> retrieveArchivedNewsLetters(
@AuthenticationPrincipal final CustomUserDetails customUserDetails,
@PathVariable(name = "category") String category) {

return new ResponseEntity<>(
retrieveArchiveUseCase.retrieveNewsLetters(customUserDetails.getEmail(),
Category.from(category)), HttpStatus.OK);
}

@GetMapping("/terms")
public ResponseEntity<ArchiveResponse> retrieveArchivedTerms(
@AuthenticationPrincipal CustomUserDetails customUserDetails) {
return new ResponseEntity<>(
retrieveArchiveUseCase.retrieveTerms(customUserDetails.getEmail()),
HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package kusitms.duduk.apiserver.archive.presentation;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import kusitms.duduk.apiserver.security.infrastructure.CustomUserDetails;
import kusitms.duduk.common.exception.ErrorResponse;
import kusitms.duduk.core.archive.dto.response.ArchiveResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.PathVariable;

@Tag(name = "Archive", description = "아카이브 API")
public interface ArchiveControllerDocs {

@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "400", description = "BAD REQUEST",
content = {@Content(schema = @Schema(implementation = ErrorResponse.class))}),
@ApiResponse(responseCode = "500", description = "INTERNAL SERVER ERROR",
content = {@Content(schema = @Schema(implementation = ErrorResponse.class))})
})
@Operation(summary = "아카이브 뉴스레터 조회", description = "아카이브에 저장되어 있는 뉴스레터를 조회합니다.")
ResponseEntity<ArchiveResponse> retrieveArchivedNewsLetters(
@AuthenticationPrincipal final CustomUserDetails customUserDetails,
@PathVariable final String category
);

@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "400", description = "BAD REQUEST",
content = {@Content(schema = @Schema(implementation = ErrorResponse.class))}),
@ApiResponse(responseCode = "500", description = "INTERNAL SERVER ERROR",
content = {@Content(schema = @Schema(implementation = ErrorResponse.class))})
})
@Operation(summary = "아카이브 단어 조회", description = "아카이브에 저장되어 있는 단어를 조회합니다.")
ResponseEntity<ArchiveResponse> retrieveArchivedTerms(
@AuthenticationPrincipal final CustomUserDetails customUserDetails);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import kusitms.duduk.common.exception.ErrorResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;

@Tag(name = "HealthCheck", description = "헬스체크 API")
public interface HealthCheckControllerDocs {

@GetMapping("/api/healthcheck")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package kusitms.duduk.apiserver.newsletter.presentation;

import io.swagger.v3.oas.annotations.tags.Tag;

@Tag(name = "NewsLetter", description = "뉴스레터 API")
public interface NewsLetterControllerDocs {

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@
import java.time.LocalDateTime;
import java.util.List;
import kusitms.duduk.apiserver.security.infrastructure.CustomUserDetails;
import kusitms.duduk.core.newsletter.dto.response.ArchiveNewsLetterResponse;
import kusitms.duduk.core.newsletter.dto.response.NewsLetterThumbnailResponse;
import kusitms.duduk.core.newsletter.port.input.ArchiveNewsLetterUseCase;
import kusitms.duduk.core.term.dto.response.ArchiveTermResponse;
import kusitms.duduk.core.term.dto.response.RetrieveTermResponse;
import kusitms.duduk.core.term.port.input.ArchiveTermUseCase;
import kusitms.duduk.core.user.dto.request.CreateUserRequest;
import kusitms.duduk.core.user.dto.request.ValidateUserEmailRequest;
import kusitms.duduk.core.user.dto.request.ValidateUserNicknameRequest;
import kusitms.duduk.core.user.dto.response.RetrieveHomeResponse;
import kusitms.duduk.core.user.dto.response.RetrieveMypageResponse;
import kusitms.duduk.core.user.dto.response.UserResponse;
import kusitms.duduk.core.user.port.input.RegisterUserUseCase;
import kusitms.duduk.core.user.port.input.RetrieveUserQuery;
Expand All @@ -18,6 +23,7 @@
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -31,6 +37,8 @@ public class UserController implements UserControllerDocs {
private final RegisterUserUseCase registerUserUseCase;
private final RetrieveUserQuery retrieveUserQuery;
private final ValidateDuplicatedUserQuery validateDuplicatedUserQuery;
private final ArchiveNewsLetterUseCase archiveNewsLetterUseCase;
private final ArchiveTermUseCase archiveTermUseCase;

@PostMapping
public ResponseEntity<UserResponse> register(@RequestBody CreateUserRequest createUserRequest) {
Expand All @@ -54,87 +62,113 @@ public ResponseEntity<Void> validateNickname(@RequestBody ValidateUserNicknameRe
public ResponseEntity<RetrieveHomeResponse> home(CustomUserDetails customUserDetails) {
RetrieveHomeResponse response = RetrieveHomeResponse.builder()
.todayNewsLetter(NewsLetterThumbnailResponse.builder()
.id(1L)
.title("오늘의 주목할 뉴스")
.type("editor")
.keywords("테슬라, 주가 변동, 시장 분석")
.thumbnail("https://image.shutterstock.com/image-photo/latest-stock-market-charts.jpg")
.isScrapped(false)
.createdAt(LocalDateTime.now())
.build())
.id(1L)
.title("오늘의 주목할 뉴스")
.type("editor")
.keywords("테슬라, 주가 변동, 시장 분석")
.thumbnail(
"https://image.shutterstock.com/image-photo/latest-stock-market-charts.jpg")
.isScrapped(false)
.createdAt(LocalDateTime.now())
.build())
.realtimeTrendNewsLetters(List.of(
NewsLetterThumbnailResponse.builder()
.id(2L)
.title("기술 섹터 동향")
.type("analysis")
.keywords("애플, 삼성, 최신 기술")
.thumbnail("https://image.shutterstock.com/image-photo/technology-trends.jpg")
.isScrapped(true)
.createdAt(LocalDateTime.now().minusHours(3))
.build(),
NewsLetterThumbnailResponse.builder()
.id(3L)
.title("유럽 시장 개요")
.type("global")
.keywords("유로존, 경제 성장")
.thumbnail("https://image.shutterstock.com/image-photo/european-markets.jpg")
.isScrapped(false)
.createdAt(LocalDateTime.now().minusHours(2))
.build(),
NewsLetterThumbnailResponse.builder()
.id(4L)
.title("투자 조언: 금융 포트폴리오 관리")
.type("financial")
.keywords("투자, 자산 관리")
.thumbnail("https://image.shutterstock.com/image-photo/financial-management.jpg")
.isScrapped(true)
.createdAt(LocalDateTime.now().minusHours(1))
.build()
NewsLetterThumbnailResponse.builder()
.id(2L)
.title("기술 섹터 동향")
.type("analysis")
.keywords("애플, 삼성, 최신 기술")
.thumbnail("https://image.shutterstock.com/image-photo/technology-trends.jpg")
.isScrapped(true)
.createdAt(LocalDateTime.now().minusHours(3))
.build(),
NewsLetterThumbnailResponse.builder()
.id(3L)
.title("유럽 시장 개요")
.type("global")
.keywords("유로존, 경제 성장")
.thumbnail("https://image.shutterstock.com/image-photo/european-markets.jpg")
.isScrapped(false)
.createdAt(LocalDateTime.now().minusHours(2))
.build(),
NewsLetterThumbnailResponse.builder()
.id(4L)
.title("투자 조언: 금융 포트폴리오 관리")
.type("financial")
.keywords("투자, 자산 관리")
.thumbnail(
"https://image.shutterstock.com/image-photo/financial-management.jpg")
.isScrapped(true)
.createdAt(LocalDateTime.now().minusHours(1))
.build()
))
.customizeNewsLetters(List.of(
NewsLetterThumbnailResponse.builder()
.id(5L)
.title("지속 가능한 투자 동향")
.type("sustainable")
.keywords("그린 에너지, 친환경 정책")
.thumbnail("https://image.shutterstock.com/image-photo/sustainable-investments.jpg")
.isScrapped(false)
.createdAt(LocalDateTime.now().minusDays(1))
.build(),
NewsLetterThumbnailResponse.builder()
.id(6L)
.title("신흥 시장 뉴스 업데이트")
.type("emerging")
.keywords("신흥 시장, 경제 발전")
.thumbnail("https://image.shutterstock.com/image-photo/emerging-markets.jpg")
.isScrapped(true)
.createdAt(LocalDateTime.now().minusDays(1).minusHours(2))
.build(),
NewsLetterThumbnailResponse.builder()
.id(7L)
.title("실리콘 밸리 최신 소식")
.type("tech")
.keywords("스타트업, 혁신, 기술")
.thumbnail("https://image.shutterstock.com/image-photo/silicon-valley.jpg")
.isScrapped(false)
.createdAt(LocalDateTime.now().minusDays(1).minusHours(4))
.build()
NewsLetterThumbnailResponse.builder()
.id(5L)
.title("지속 가능한 투자 동향")
.type("sustainable")
.keywords("그린 에너지, 친환경 정책")
.thumbnail(
"https://image.shutterstock.com/image-photo/sustainable-investments.jpg")
.isScrapped(false)
.createdAt(LocalDateTime.now().minusDays(1))
.build(),
NewsLetterThumbnailResponse.builder()
.id(6L)
.title("신흥 시장 뉴스 업데이트")
.type("emerging")
.keywords("신흥 시장, 경제 발전")
.thumbnail("https://image.shutterstock.com/image-photo/emerging-markets.jpg")
.isScrapped(true)
.createdAt(LocalDateTime.now().minusDays(1).minusHours(2))
.build(),
NewsLetterThumbnailResponse.builder()
.id(7L)
.title("실리콘 밸리 최신 소식")
.type("tech")
.keywords("스타트업, 혁신, 기술")
.thumbnail("https://image.shutterstock.com/image-photo/silicon-valley.jpg")
.isScrapped(false)
.createdAt(LocalDateTime.now().minusDays(1).minusHours(4))
.build()
))
.todayTerm(RetrieveTermResponse.builder()
.termId(1L)
.koreanName("지속 가능성")
.englishName("Sustainability")
.description("지속 가능성은 환경적, 경제적, 사회적 측면에서 장기적으로 견딜 수 있는 발전을 의미합니다.")
.category("ENVIRONMENT")
.isScrapped(true)
.build())
.termId(1L)
.koreanName("지속 가능성")
.englishName("Sustainability")
.description("지속 가능성은 환경적, 경제적, 사회적 측면에서 장기적으로 견딜 수 있는 발전을 의미합니다.")
.category("ENVIRONMENT")
.isScrapped(true)
.build())
.build();

return new ResponseEntity<>(response, HttpStatus.OK);
// return new ResponseEntity<>(retrieveUserQuery.home(customUserDetails.getEmail()),
// HttpStatus.OK);
}

@GetMapping("/mypage")
public ResponseEntity<RetrieveMypageResponse> mypage(CustomUserDetails customUserDetails) {
return new ResponseEntity<>(retrieveUserQuery.mypage(customUserDetails.getEmail()),
HttpStatus.OK);
}

@GetMapping("/archive/{newsLetterId}")
public ResponseEntity<ArchiveNewsLetterResponse> archiveNewsLetter(
@AuthenticationPrincipal CustomUserDetails customUserDetails,
@PathVariable(name = "newsLetterId") Long newsLetterId) {
return new ResponseEntity<>(
archiveNewsLetterUseCase.archive(customUserDetails.getEmail(), newsLetterId),
HttpStatus.OK);
}

@GetMapping("/archive/{termId}")
public ResponseEntity<ArchiveTermResponse> archiveTerm(
@AuthenticationPrincipal CustomUserDetails customUserDetails,
@PathVariable(name = "termId") Long termId) {
return new ResponseEntity<>(
archiveTermUseCase.archive(customUserDetails.getEmail(), termId), HttpStatus.OK);
}

@GetMapping("/test")
public ResponseEntity<String> test(@AuthenticationPrincipal
CustomUserDetails customUserDetails) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@
import io.swagger.v3.oas.annotations.tags.Tag;
import kusitms.duduk.apiserver.security.infrastructure.CustomUserDetails;
import kusitms.duduk.common.exception.ErrorResponse;
import kusitms.duduk.core.newsletter.dto.response.ArchiveNewsLetterResponse;
import kusitms.duduk.core.term.dto.response.ArchiveTermResponse;
import kusitms.duduk.core.user.dto.request.CreateUserRequest;
import kusitms.duduk.core.user.dto.request.ValidateUserEmailRequest;
import kusitms.duduk.core.user.dto.request.ValidateUserNicknameRequest;
import kusitms.duduk.core.user.dto.response.RetrieveHomeResponse;
import kusitms.duduk.core.user.dto.response.UserResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;

@Tag(name = "User", description = "유저 API")
Expand Down Expand Up @@ -75,4 +78,30 @@ ResponseEntity<Void> validateNickname(
ResponseEntity<RetrieveHomeResponse> home(
@AuthenticationPrincipal final CustomUserDetails customUserDetails
);

@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "400", description = "BAD REQUEST",
content = {@Content(schema = @Schema(implementation = ErrorResponse.class))}),
@ApiResponse(responseCode = "500", description = "INTERNAL SERVER ERROR",
content = {@Content(schema = @Schema(implementation = ErrorResponse.class))})
})
@Operation(summary = "뉴스레터 아카이브", description = "뉴스레터를 아카이브에 저장합니다.")
ResponseEntity<ArchiveNewsLetterResponse> archiveNewsLetter(
@AuthenticationPrincipal final CustomUserDetails customUserDetails,
@PathVariable final Long newsLetterId
);

@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "400", description = "BAD REQUEST",
content = {@Content(schema = @Schema(implementation = ErrorResponse.class))}),
@ApiResponse(responseCode = "500", description = "INTERNAL SERVER ERROR",
content = {@Content(schema = @Schema(implementation = ErrorResponse.class))})
})
@Operation(summary = "단어 아카이브", description = "단어를 아카이브에 저장합니다.")
ResponseEntity<ArchiveTermResponse> archiveTerm(
@AuthenticationPrincipal final CustomUserDetails customUserDetails,
@PathVariable final Long termId
);
}
Loading
Loading