11package com .spring .monew .article .controller ;
22
33import com .spring .monew .article .controller .dto .response .ArticleDto ;
4+ import com .spring .monew .article .controller .dto .response .ArticleRestoreResultDto ;
45import com .spring .monew .article .controller .dto .response .CursorPageResponseArticleDto ;
56import com .spring .monew .article .service .ArticleService ;
6- import com .spring .monew .auth .config .HeaderUserAuthentication ;
77import com .spring .monew .common .util .RequestUserExtractor ;
88import io .swagger .v3 .oas .annotations .Operation ;
99import io .swagger .v3 .oas .annotations .Parameter ;
1717import java .util .List ;
1818import java .util .UUID ;
1919import lombok .RequiredArgsConstructor ;
20+ import org .springframework .format .annotation .DateTimeFormat ;
21+ import org .springframework .http .HttpStatus ;
22+ import org .springframework .http .ResponseEntity ;
2023import org .springframework .validation .annotation .Validated ;
24+ import org .springframework .web .bind .annotation .DeleteMapping ;
2125import org .springframework .web .bind .annotation .GetMapping ;
2226import org .springframework .web .bind .annotation .PathVariable ;
2327import org .springframework .web .bind .annotation .RequestMapping ;
2428import org .springframework .web .bind .annotation .RequestParam ;
29+ import org .springframework .web .bind .annotation .ResponseStatus ;
2530import org .springframework .web .bind .annotation .RestController ;
2631
2732@ RestController
@@ -38,9 +43,9 @@ public class ArticleController {
3843 @ GetMapping
3944 @ Operation (summary = "뉴스 기사 목록 조회" , description = "조건에 맞는 뉴스 기사 목록을 조회합니다." )
4045 @ ApiResponses ({
41- @ ApiResponse (responseCode = "200" , description = "조회 성공" ),
42- @ ApiResponse (responseCode = "400" , description = "잘못된 요청 (정렬 기준 오류, 페이지네이션 파라미터 오류 등)" ),
43- @ ApiResponse (responseCode = "500" , description = "서버 내부 오류" )
46+ @ ApiResponse (responseCode = "200" , description = "조회 성공" ),
47+ @ ApiResponse (responseCode = "400" , description = "잘못된 요청 (정렬 기준 오류, 페이지네이션 파라미터 오류 등)" ),
48+ @ ApiResponse (responseCode = "500" , description = "서버 내부 오류" )
4449 })
4550 public CursorPageResponseArticleDto articleList (
4651 @ Parameter (description = "검색어(제목, 요약)" )
@@ -96,12 +101,12 @@ public CursorPageResponseArticleDto articleList(
96101 @ GetMapping ("/{articleId}" )
97102 @ Operation (
98103 summary = "뉴스 기사 단건 조회" ,
99- description = "뉴스 기사 ID로 뉴스 기사 단건을 조회합니다."
104+ description = "뉴스 기사 ID로 뉴스 기사 단건을 조회합니다."
100105 )
101106 @ ApiResponses ({
102- @ ApiResponse (responseCode = "200" , description = "조회 성공" ),
103- @ ApiResponse (responseCode = "404" , description = "뉴스 기사 정보 없음" ),
104- @ ApiResponse (responseCode = "500" , description = "서버 내부 오류" )
107+ @ ApiResponse (responseCode = "200" , description = "조회 성공" ),
108+ @ ApiResponse (responseCode = "404" , description = "뉴스 기사 정보 없음" ),
109+ @ ApiResponse (responseCode = "500" , description = "서버 내부 오류" )
105110 })
106111 public ArticleDto articleDetails (
107112 @ Parameter (description = "뉴스 기사 ID" , required = true )
@@ -116,10 +121,53 @@ public ArticleDto articleDetails(
116121 @ GetMapping ("/sources" )
117122 @ Operation (summary = "출처 목록 조회" , description = "출처 목록을 조회합니다." )
118123 @ ApiResponses ({
119- @ ApiResponse (responseCode = "200" , description = "조회 성공" ),
120- @ ApiResponse (responseCode = "500" , description = "서버 내부 오류" )
124+ @ ApiResponse (responseCode = "200" , description = "조회 성공" ),
125+ @ ApiResponse (responseCode = "500" , description = "서버 내부 오류" )
121126 })
122127 public List <String > articleSourceList () {
123128 return articleService .getSources ();
124129 }
125- }
130+
131+ @ DeleteMapping ("/{articleId}" )
132+ @ ResponseStatus (HttpStatus .NO_CONTENT )
133+ @ Operation (summary = "뉴스 기사 삭제" , description = "특정 기사를 소프트 삭제합니다 (논리 삭제)" )
134+ public void softDeleteArticle (
135+ @ Parameter (description = "뉴스 기사 ID" , required = true )
136+ @ PathVariable UUID articleId ,
137+ Principal principal
138+ ) {
139+ UUID userId = userExtractor .extractUserId (principal );
140+ articleService .softDeleteArticle (articleId , userId );
141+ }
142+
143+ @ DeleteMapping ("/{articleId}/hard" )
144+ @ ResponseStatus (HttpStatus .NO_CONTENT )
145+ @ Operation (summary = "뉴스 기사 영구 삭제" , description = "특정 기사 및 관련된 모든 데이터(댓글, 좋아요, 조회수)를 데이터베이스에서 완전히 삭제합니다" )
146+ public void hardDeleteArticle (
147+ @ Parameter (description = "뉴스 기사 ID" , required = true )
148+ @ PathVariable UUID articleId ,
149+ Principal principal
150+ ) {
151+ UUID userId = userExtractor .extractUserId (principal );
152+ articleService .hardDeleteArticle (articleId , userId );
153+ }
154+
155+ @ GetMapping ("/restore" )
156+ @ Operation (
157+ summary = "백업에서 기사 복원" ,
158+ description = "S3 백업에서 지정된 날짜 범위의 누락된 기사를 복원합니다. 최대 31일 범위까지 가능합니다."
159+ )
160+ public ResponseEntity <ArticleRestoreResultDto > restoreArticles (
161+ @ Parameter (description = "시작 날짜" , required = true )
162+ @ RequestParam @ DateTimeFormat (iso = DateTimeFormat .ISO .DATE_TIME ) Instant from ,
163+
164+ @ Parameter (description = "종료 날짜" , required = true )
165+ @ RequestParam @ DateTimeFormat (iso = DateTimeFormat .ISO .DATE_TIME ) Instant to ,
166+
167+ Principal principal
168+ ) {
169+ UUID userId = userExtractor .extractUserId (principal );
170+ ArticleRestoreResultDto result = articleService .restoreArticlesFromBackup (from , to , userId );
171+ return ResponseEntity .ok (result );
172+ }
173+ }
0 commit comments