Skip to content

Commit e0ff4c2

Browse files
authored
Merge pull request #164 from DevKor-github/develop
#163까지 반영해 배포
2 parents dbf5d8b + 3ff7cc4 commit e0ff4c2

13 files changed

Lines changed: 119 additions & 10 deletions

File tree

src/main/java/com/devkor/ifive/nadab/domain/dailyreport/api/DailyReportController.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public class DailyReportController {
7777
description = """
7878
- ErrorCode: DAILY_QUESTION_MISMATCH - 요청한 질문이 사용자에게 할당된 오늘의 질문과 일치하지 않음
7979
- ErrorCode: IMAGE_INVALID_KEY - 유효하지 않은 이미지 키
80+
- ErrorCode: IMAGE_WEBP_KEY_REQUIRED - objectKey는 존재하지만 webpKey가 누락됨
8081
""",
8182
content = @Content
8283
),

src/main/java/com/devkor/ifive/nadab/domain/dailyreport/application/DailyReportService.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,12 @@ public CreateDailyReportResponse generateDailyReport(Long userId, DailyReportReq
6161
DailyQuestion question = dailyQuestionRepository.findByIdWithInterest(request.questionId())
6262
.orElseThrow(() -> new NotFoundException(ErrorCode.QUESTION_NOT_FOUND));
6363

64-
// webpKey 존재 시 검증
65-
if(!isBlank(request.webpKey())) {
66-
validateWebpKey(request.webpKey(), userId);
64+
// objectKey, webpKey 존재 시 검증
65+
if(!isBlank(request.objectKey())) {
66+
if(isBlank(request.webpKey())) {
67+
throw new BadRequestException(ErrorCode.IMAGE_WEBP_KEY_REQUIRED);
68+
}
69+
validateWebpKey(request.webpKey(), userId);
6770
}
6871

6972
LocalDate today = TodayDateTimeProvider.getTodayDate();

src/main/java/com/devkor/ifive/nadab/domain/stats/application/MonthlyStatsService.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,15 @@ public MonthlyStatsViewModel getMonthlyStatsLast5Months() {
5959
Map<YearMonth, Long> completedDailyMap = aggregateByMonth(
6060
repo.findCompletedDailyReportCountsByDateBetween(startDate, endDateInclusive)
6161
);
62+
Map<YearMonth, Long> mauMap = aggregateByMonth(
63+
repo.findMonthlyActiveUserCountsByDateBetween(startDate, endDateInclusive)
64+
);
6265

6366
List<Long> signupCounts = months.stream().map(m -> signupMap.getOrDefault(m, 0L)).toList();
6467
List<Long> assignedCounts = months.stream().map(m -> assignedMap.getOrDefault(m, 0L)).toList();
6568
List<Long> completedDailyCounts = months.stream().map(m -> completedDailyMap.getOrDefault(m, 0L)).toList();
6669
List<Long> completedCounts = months.stream().map(m -> completedMap.getOrDefault(m, 0L)).toList();
70+
List<Long> mauCounts = months.stream().map(m -> mauMap.getOrDefault(m, 0L)).toList();
6771

6872
long inProgressNow = repo.countInProgressMonthlyReportsNow();
6973

@@ -73,6 +77,7 @@ public MonthlyStatsViewModel getMonthlyStatsLast5Months() {
7377
assignedCounts,
7478
completedDailyCounts,
7579
completedCounts,
80+
mauCounts,
7681
inProgressNow,
7782
OffsetDateTime.now(SEOUL).format(FMT)
7883
);

src/main/java/com/devkor/ifive/nadab/domain/stats/application/WeeklyStatsService.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,15 @@ public WeeklyStatsViewModel getWeeklyStatsLast7Weeks() {
5858
Map<LocalDate, Long> completedDailyMap = aggregateByWeekStart(
5959
repo.findCompletedDailyReportCountsByDateBetween(startWeekStart, endDateInclusive)
6060
);
61+
Map<LocalDate, Long> wauMap = toMapByDate(
62+
repo.findWeeklyActiveUserCountsByDateBetween(startWeekStart, endDateInclusive)
63+
);
6164

6265
List<Long> signupCounts = weekStarts.stream().map(d -> signupMap.getOrDefault(d, 0L)).toList();
6366
List<Long> assignedCounts = weekStarts.stream().map(d -> assignedMap.getOrDefault(d, 0L)).toList();
6467
List<Long> completedDailyCounts = weekStarts.stream().map(d -> completedDailyMap.getOrDefault(d, 0L)).toList();
6568
List<Long> completedCounts = weekStarts.stream().map(d -> completedMap.getOrDefault(d, 0L)).toList();
69+
List<Long> wauCounts = weekStarts.stream().map(d -> wauMap.getOrDefault(d, 0L)).toList();
6670

6771
long inProgressNow = repo.countInProgressWeeklyReportsNow();
6872

@@ -72,6 +76,7 @@ public WeeklyStatsViewModel getWeeklyStatsLast7Weeks() {
7276
assignedCounts,
7377
completedDailyCounts,
7478
completedCounts,
79+
wauCounts,
7580
inProgressNow,
7681
OffsetDateTime.now(SEOUL).format(FMT)
7782
);
@@ -85,4 +90,12 @@ private Map<LocalDate, Long> aggregateByWeekStart(List<DateCountDto> dailyCounts
8590
}
8691
return map;
8792
}
93+
94+
private Map<LocalDate, Long> toMapByDate(List<DateCountDto> counts) {
95+
Map<LocalDate, Long> map = new HashMap<>();
96+
for (DateCountDto dto : counts) {
97+
map.put(dto.date(), dto.count());
98+
}
99+
return map;
100+
}
88101
}

src/main/java/com/devkor/ifive/nadab/domain/stats/core/dto/monthly/MonthlyStatsViewModel.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ public record MonthlyStatsViewModel(
88
List<Long> assignedQuestionCounts,
99
List<Long> completedDailyReportCounts,
1010
List<Long> completedMonthlyReportCounts,
11+
List<Long> mauCounts,
1112
long inProgressMonthlyReportCount,
1213
String refreshedAt
1314
) {}

src/main/java/com/devkor/ifive/nadab/domain/stats/core/dto/weekly/WeeklyStatsViewModel.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ public record WeeklyStatsViewModel(
88
List<Long> assignedQuestionCounts,
99
List<Long> completedDailyReportCounts,
1010
List<Long> completedWeeklyReportCounts,
11+
List<Long> wauCounts,
1112
long inProgressWeeklyReportCount,
1213
String refreshedAt
1314
) {}

src/main/java/com/devkor/ifive/nadab/domain/stats/core/repository/DailyStatsRepository.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,7 @@ public List<Object[]> findSignupCountsLast7Days(LocalDate startDate, LocalDate e
3131
return em.createQuery("""
3232
select function('date', u.registeredAt), count(u.id)
3333
from User u
34-
where u.deletedAt is null
35-
and u.signupStatus = com.devkor.ifive.nadab.domain.user.core.entity.SignupStatusType.COMPLETED
34+
where u.signupStatus = com.devkor.ifive.nadab.domain.user.core.entity.SignupStatusType.COMPLETED
3635
and u.registeredAt is not null
3736
and u.registeredAt >= :start
3837
and u.registeredAt < :endExclusive

src/main/java/com/devkor/ifive/nadab/domain/stats/core/repository/MonthlyStatsRepository.java

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import org.springframework.stereotype.Repository;
77

88
import java.sql.Date;
9+
import java.sql.Timestamp;
910
import java.time.LocalDate;
1011
import java.time.OffsetDateTime;
1112
import java.time.ZoneId;
@@ -25,8 +26,7 @@ public List<DateCountDto> findSignupCountsByDateBetween(LocalDate startDate, Loc
2526
List<Object[]> rows = em.createQuery("""
2627
select function('date', u.registeredAt), count(u.id)
2728
from User u
28-
where u.deletedAt is null
29-
and u.signupStatus = com.devkor.ifive.nadab.domain.user.core.entity.SignupStatusType.COMPLETED
29+
where u.signupStatus = com.devkor.ifive.nadab.domain.user.core.entity.SignupStatusType.COMPLETED
3030
and u.registeredAt is not null
3131
and u.registeredAt >= :start
3232
and u.registeredAt < :endExclusive
@@ -92,9 +92,40 @@ select count(mr.id)
9292
.getSingleResult();
9393
}
9494

95+
public List<DateCountDto> findMonthlyActiveUserCountsByDateBetween(LocalDate startDate, LocalDate endDateInclusive) {
96+
List<Object[]> rows = em.createQuery("""
97+
select function('date_trunc', 'month', dr.date), count(distinct dr.answerEntry.user.id)
98+
from DailyReport dr
99+
where dr.date between :startDate and :endDate
100+
and dr.status = com.devkor.ifive.nadab.domain.dailyreport.core.entity.DailyReportStatus.COMPLETED
101+
group by function('date_trunc', 'month', dr.date)
102+
order by function('date_trunc', 'month', dr.date)
103+
""", Object[].class)
104+
.setParameter("startDate", startDate)
105+
.setParameter("endDate", endDateInclusive)
106+
.getResultList();
107+
108+
return rows.stream()
109+
.map(MonthlyStatsRepository::toDateCountDtoFromDateTrunc)
110+
.toList();
111+
}
112+
95113
private static DateCountDto toDateCountDto(Object[] row) {
96114
LocalDate date = ((Date) row[0]).toLocalDate();
97115
long count = (Long) row[1];
98116
return new DateCountDto(date, count);
99117
}
118+
119+
private static DateCountDto toDateCountDtoFromDateTrunc(Object[] row) {
120+
LocalDate date;
121+
if (row[0] instanceof Timestamp timestamp) {
122+
date = timestamp.toLocalDateTime().toLocalDate();
123+
} else if (row[0] instanceof Date sqlDate) {
124+
date = sqlDate.toLocalDate();
125+
} else {
126+
date = LocalDate.parse(row[0].toString().substring(0, 10));
127+
}
128+
long count = (Long) row[1];
129+
return new DateCountDto(date, count);
130+
}
100131
}

src/main/java/com/devkor/ifive/nadab/domain/stats/core/repository/WeeklyStatsRepository.java

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import org.springframework.stereotype.Repository;
77

88
import java.sql.Date;
9+
import java.sql.Timestamp;
910
import java.time.LocalDate;
1011
import java.time.OffsetDateTime;
1112
import java.time.ZoneId;
@@ -25,8 +26,7 @@ public List<DateCountDto> findSignupCountsByDateBetween(LocalDate startDate, Loc
2526
List<Object[]> rows = em.createQuery("""
2627
select function('date', u.registeredAt), count(u.id)
2728
from User u
28-
where u.deletedAt is null
29-
and u.signupStatus = com.devkor.ifive.nadab.domain.user.core.entity.SignupStatusType.COMPLETED
29+
where u.signupStatus = com.devkor.ifive.nadab.domain.user.core.entity.SignupStatusType.COMPLETED
3030
and u.registeredAt is not null
3131
and u.registeredAt >= :start
3232
and u.registeredAt < :endExclusive
@@ -98,9 +98,40 @@ select count(wr.id)
9898
.getSingleResult();
9999
}
100100

101+
public List<DateCountDto> findWeeklyActiveUserCountsByDateBetween(LocalDate startDate, LocalDate endDateInclusive) {
102+
List<Object[]> rows = em.createQuery("""
103+
select function('date_trunc', 'week', dr.date), count(distinct dr.answerEntry.user.id)
104+
from DailyReport dr
105+
where dr.date between :startDate and :endDate
106+
and dr.status = com.devkor.ifive.nadab.domain.dailyreport.core.entity.DailyReportStatus.COMPLETED
107+
group by function('date_trunc', 'week', dr.date)
108+
order by function('date_trunc', 'week', dr.date)
109+
""", Object[].class)
110+
.setParameter("startDate", startDate)
111+
.setParameter("endDate", endDateInclusive)
112+
.getResultList();
113+
114+
return rows.stream()
115+
.map(WeeklyStatsRepository::toDateCountDtoFromDateTrunc)
116+
.toList();
117+
}
118+
101119
private static DateCountDto toDateCountDto(Object[] row) {
102120
LocalDate date = ((Date) row[0]).toLocalDate();
103121
long count = (Long) row[1];
104122
return new DateCountDto(date, count);
105123
}
124+
125+
private static DateCountDto toDateCountDtoFromDateTrunc(Object[] row) {
126+
LocalDate date;
127+
if (row[0] instanceof Timestamp timestamp) {
128+
date = timestamp.toLocalDateTime().toLocalDate();
129+
} else if (row[0] instanceof Date sqlDate) {
130+
date = sqlDate.toLocalDate();
131+
} else {
132+
date = LocalDate.parse(row[0].toString().substring(0, 10));
133+
}
134+
long count = (Long) row[1];
135+
return new DateCountDto(date, count);
136+
}
106137
}

src/main/java/com/devkor/ifive/nadab/global/core/response/ErrorCode.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ public enum ErrorCode {
9393
IMAGE_SIZE_EXCEEDED(HttpStatus.BAD_REQUEST, "이미지 크기가 제한을 초과했습니다 (최대 5MB)"),
9494
IMAGE_METADATA_INVALID(HttpStatus.BAD_REQUEST, "파일 메타데이터를 읽을 수 없습니다. 다시 시도해주세요."),
9595
IMAGE_INVALID_KEY(HttpStatus.BAD_REQUEST, "잘못된 이미지 key입니다."),
96+
IMAGE_WEBP_KEY_REQUIRED(HttpStatus.BAD_REQUEST, "objectKey가 존재할 때 webpKey도 함께 제공되어야 합니다"),
9697

9798
// ==================== QUESTION (질문) ====================
9899
// 400 Bad Request

0 commit comments

Comments
 (0)