Skip to content

Commit 7f6f240

Browse files
authored
Merge pull request #63 from Move-Log/develop
Merge develop to main
2 parents 5cf6211 + d348b30 commit 7f6f240

5 files changed

Lines changed: 167 additions & 26 deletions

File tree

src/main/java/com/movelog/domain/news/application/NewsService.java

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44
import com.movelog.domain.news.domain.repository.NewsRepository;
55
import com.movelog.domain.news.dto.request.CreateNewsReq;
66
import com.movelog.domain.news.dto.request.NewsHeadLineReq;
7-
import com.movelog.domain.news.dto.response.HeadLineRes;
8-
import com.movelog.domain.news.dto.response.RecentKeywordsRes;
9-
import com.movelog.domain.news.dto.response.RecentNewsRes;
7+
import com.movelog.domain.news.dto.response.*;
108
import com.movelog.domain.record.domain.Keyword;
119
import com.movelog.domain.record.domain.VerbType;
1210
import com.movelog.domain.record.exception.KeywordNotFoundException;
@@ -18,6 +16,7 @@
1816
import com.movelog.global.config.security.token.UserPrincipal;
1917
import com.movelog.global.util.S3Util;
2018
import lombok.RequiredArgsConstructor;
19+
import org.springframework.data.domain.Page;
2120
import org.springframework.data.domain.PageRequest;
2221
import org.springframework.data.domain.Pageable;
2322
import org.springframework.stereotype.Service;
@@ -85,7 +84,7 @@ public List<RecentKeywordsRes> getRecentKeywords(UserPrincipal userPrincipal) {
8584
.toList();
8685
}
8786

88-
public List<RecentNewsRes> getRecentNews(UserPrincipal userPrincipal, Integer page) {
87+
public Page<RecentNewsRes> getRecentNews(UserPrincipal userPrincipal, Integer page) {
8988
User user = validateUser(userPrincipal);
9089
// User user = userRepository.findById(5L).orElseThrow(UserNotFoundException::new);
9190

@@ -94,23 +93,68 @@ public List<RecentNewsRes> getRecentNews(UserPrincipal userPrincipal, Integer pa
9493

9594
// 최근 일주일간 생성한 뉴스 목록 조회
9695
LocalDateTime createdAt = LocalDateTime.now().minusDays(7);
97-
List<News> recentNews = newsRepository.findRecentNewsByUser(user, createdAt, pageable);
98-
99-
// 최신순 정렬
100-
recentNews.sort((n1, n2) -> n2.getCreatedAt().compareTo(n1.getCreatedAt()));
101-
102-
return recentNews.stream()
103-
.map(news -> RecentNewsRes.builder()
104-
.newsId(news.getNewsId())
105-
.newsImageUrl(news.getNewsUrl())
106-
.headLine(news.getHeadLine())
107-
.noun(news.getKeyword().getKeyword())
108-
.verb(VerbType.getStringVerbType(news.getKeyword().getVerbType()))
109-
.createdAt(news.getCreatedAt())
110-
.build())
111-
.toList();
96+
Page<News> recentNews = newsRepository.findRecentNewsByUser(user, createdAt, pageable);
97+
98+
return recentNews.map(news -> RecentNewsRes.builder()
99+
.newsId(news.getNewsId())
100+
.newsImageUrl(news.getNewsUrl())
101+
.headLine(news.getHeadLine())
102+
.noun(news.getKeyword().getKeyword())
103+
.verb(VerbType.getStringVerbType(news.getKeyword().getVerbType()))
104+
.createdAt(news.getCreatedAt())
105+
.build());
106+
}
107+
108+
public TodayNewsStatusRes getTodayNewsStatus(UserPrincipal userPrincipal) {
109+
User user = validateUser(userPrincipal);
110+
// User user = userRepository.findById(5L).orElseThrow(UserNotFoundException::new);
111+
112+
// 사용자가 생성한 모든 뉴스 개수 조회
113+
List<Keyword> keywords = user.getKeywords();
114+
long totalNewsCount = keywords.stream()
115+
.mapToLong(newsRepository::countByKeyword)
116+
.sum();
117+
118+
long newsStatus = totalNewsCount % 5;
119+
LocalDateTime today = LocalDateTime.now();
120+
121+
// 오늘 생성한 뉴스가 있으면 true, 없으면 false
122+
boolean isTodayNews = !newsRepository.findRecentNewsByUser(user, today, PageRequest.of(0, 1)).isEmpty();
123+
124+
int result;
125+
if(newsStatus == 0 && isTodayNews) {
126+
result = 5;
127+
}
128+
else if(newsStatus == 0) {
129+
result = 0;
130+
}
131+
else {
132+
result = (int) newsStatus;
133+
}
134+
135+
return TodayNewsStatusRes.builder()
136+
.newsStatus(result)
137+
.build();
112138
}
113139

140+
public Page<NewsCalendarRes> getNewsByDate(UserPrincipal userPrincipal, String date, int page) {
141+
User user = validateUser(userPrincipal);
142+
// User user = userRepository.findById(5L).orElseThrow(UserNotFoundException::new);
143+
144+
LocalDateTime start = LocalDateTime.parse(date + "T00:00:00");
145+
LocalDateTime end = LocalDateTime.parse(date + "T23:59:59");
146+
147+
Pageable pageable = PageRequest.of(0, 15); // 원하는 페이지와 크기를 지정
148+
Page<News> newsList = newsRepository.findNewsByUserAndCreatedAtBetween(user, start, end, pageable);
149+
150+
return newsList.map(news -> NewsCalendarRes.builder()
151+
.newsId(news.getNewsId())
152+
.newsImageUrl(news.getNewsUrl())
153+
.noun(news.getKeyword().getKeyword())
154+
.verb(VerbType.getStringVerbType(news.getKeyword().getVerbType()))
155+
.createdAt(news.getCreatedAt())
156+
.build());
157+
}
114158

115159
// User 정보 검증
116160
private User validateUser(UserPrincipal userPrincipal) {
Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
package com.movelog.domain.news.domain.repository;
22

33
import com.movelog.domain.news.domain.News;
4+
import com.movelog.domain.record.domain.Keyword;
45
import com.movelog.domain.user.domain.User;
6+
import org.springframework.data.domain.Page;
57
import org.springframework.data.domain.Pageable;
68
import org.springframework.data.jpa.repository.JpaRepository;
79
import org.springframework.data.jpa.repository.Query;
810
import org.springframework.data.repository.query.Param;
911
import org.springframework.stereotype.Repository;
1012

1113
import java.time.LocalDateTime;
12-
import java.util.List;
1314

1415
@Repository
1516
public interface NewsRepository extends JpaRepository<News, Long> {
@@ -18,10 +19,20 @@ public interface NewsRepository extends JpaRepository<News, Long> {
1819
"JOIN n.keyword k " +
1920
"WHERE k.user = :user " +
2021
"AND n.createdAt > :createdAt " +
21-
"ORDER BY n.createdAt DESC")
22-
List<News> findRecentNewsByUser(
22+
"ORDER BY n.createdAt ASC")
23+
Page<News> findRecentNewsByUser(
2324
@Param("user") User user,
2425
@Param("createdAt") LocalDateTime createdAt,
2526
Pageable pageable
2627
);
28+
29+
long countByKeyword(Keyword keyword);
30+
31+
@Query("SELECT n FROM News n " +
32+
"JOIN n.keyword k " +
33+
"WHERE k.user = :user " +
34+
"AND n.createdAt BETWEEN :start AND :end " +
35+
"ORDER BY n.createdAt ASC")
36+
Page<News> findNewsByUserAndCreatedAtBetween(User user, LocalDateTime start, LocalDateTime end, Pageable pageable);
37+
2738
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.movelog.domain.news.dto.response;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Getter;
7+
import lombok.NoArgsConstructor;
8+
9+
import java.time.LocalDateTime;
10+
11+
@Builder
12+
@AllArgsConstructor
13+
@NoArgsConstructor
14+
@Getter
15+
public class NewsCalendarRes {
16+
@Schema( type = "int", example ="1", description="뉴스 ID")
17+
private Long newsId;
18+
19+
@Schema( type = "String", example ="https://movelog.s3.ap-northeast-2.amazonaws.com/record/2021-08-01/1.jpg", description="뉴스 이미지 url")
20+
private String newsImageUrl;
21+
22+
@Schema( type = "String", example ="헬스", description="명사")
23+
private String noun;
24+
25+
@Schema( type = "String", example ="했어요", description="동사")
26+
private String verb;
27+
28+
@Schema( type = "LocalDateTime", example ="2025-08-01T00:00:00", description="뉴스 생성 시간")
29+
private LocalDateTime createdAt;
30+
31+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.movelog.domain.news.dto.response;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Getter;
7+
import lombok.NoArgsConstructor;
8+
9+
@Builder
10+
@AllArgsConstructor
11+
@NoArgsConstructor
12+
@Getter
13+
public class TodayNewsStatusRes {
14+
15+
@Schema( type = "int", example ="0 ~ 5", description = "오늘 기준 뉴스 현황입니다. 0~5 사이의 값입니다.")
16+
private int newsStatus;
17+
18+
}

src/main/java/com/movelog/domain/news/presentation/NewsController.java

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
import com.movelog.domain.news.application.NewsService;
44
import com.movelog.domain.news.dto.request.CreateNewsReq;
55
import com.movelog.domain.news.dto.request.NewsHeadLineReq;
6-
import com.movelog.domain.news.dto.response.HeadLineRes;
7-
import com.movelog.domain.news.dto.response.RecentKeywordsRes;
8-
import com.movelog.domain.news.dto.response.RecentNewsRes;
6+
import com.movelog.domain.news.dto.response.*;
97
import com.movelog.global.config.security.token.CurrentUser;
108
import com.movelog.global.config.security.token.UserPrincipal;
119
import com.movelog.global.payload.Message;
@@ -20,6 +18,7 @@
2018
import io.swagger.v3.oas.annotations.tags.Tag;
2119
import lombok.RequiredArgsConstructor;
2220
import lombok.extern.slf4j.Slf4j;
21+
import org.springframework.data.domain.Page;
2322
import org.springframework.http.ResponseEntity;
2423
import org.springframework.security.core.annotation.AuthenticationPrincipal;
2524
import org.springframework.web.ErrorResponse;
@@ -106,7 +105,45 @@ public ResponseEntity<?> getRecentNews(
106105
@Parameter(description = "뉴스 목록의 페이지 번호를 입력해주세요. **Page는 0부터 시작됩니다!**", required = true)
107106
@RequestParam(value = "page", required = false, defaultValue = "0") Integer page
108107
) {
109-
List<RecentNewsRes> response = newsService.getRecentNews(userPrincipal, page);
108+
Page<RecentNewsRes> response = newsService.getRecentNews(userPrincipal, page);
109+
return ResponseEntity.ok(ApiResponseUtil.success(response));
110+
}
111+
112+
113+
@Operation(summary = "뉴스 기록 현황 조회 API", description = "오늘 기준 사용자의 뉴스 기록 현황을 조회합니다. ")
114+
@ApiResponses(value = {
115+
@ApiResponse(responseCode = "200", description = "뉴스 기록 현황 조회 성공",
116+
content = @Content(mediaType = "application/json",
117+
schema = @Schema(type = "array", implementation = TodayNewsStatusRes.class))),
118+
@ApiResponse(responseCode = "400", description = "뉴스 기록 현황 조회 실패",
119+
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class)))
120+
})
121+
@GetMapping("/today")
122+
public ResponseEntity<?> getTodayNewsStatus(
123+
@Parameter(description = "Access Token을 입력해주세요.", required = true) @AuthenticationPrincipal UserPrincipal userPrincipal
124+
) {
125+
TodayNewsStatusRes response = newsService.getTodayNewsStatus(userPrincipal);
126+
return ResponseEntity.ok(ApiResponseUtil.success(response));
127+
}
128+
129+
130+
131+
@Operation(summary = "날짜별 뉴스 목록 조회 API", description = "특정 날짜의 뉴스 목록을 1페이지 당 15개씩 조회합니다.")
132+
@ApiResponses(value = {
133+
@ApiResponse(responseCode = "200", description = "날짜별 뉴스 목록 조회 성공",
134+
content = @Content(mediaType = "application/json",
135+
schema = @Schema(type = "array", implementation = NewsCalendarRes.class))),
136+
@ApiResponse(responseCode = "400", description = "날짜별 뉴스 목록 조회 실패",
137+
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class)))
138+
})
139+
@GetMapping("/calendar/{date}")
140+
public ResponseEntity<?> getNewsByDate(
141+
@Parameter(description = "Access Token을 입력해주세요.", required = true) @AuthenticationPrincipal UserPrincipal userPrincipal,
142+
@Parameter(description = "조회할 날짜를 입력해주세요. (yyyy-MM-dd 형식)", required = true) @PathVariable String date,
143+
@Parameter(description = "뉴스 목록의 페이지 번호를 입력해주세요. **Page는 0부터 시작됩니다!**", required = true)
144+
@RequestParam(value = "page", required = false, defaultValue = "0") Integer page
145+
) {
146+
Page<NewsCalendarRes> response = newsService.getNewsByDate(userPrincipal, date, page);
110147
return ResponseEntity.ok(ApiResponseUtil.success(response));
111148
}
112149

0 commit comments

Comments
 (0)