-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathCalendarController.java
174 lines (137 loc) · 8.39 KB
/
CalendarController.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
package com.oing.controller;
import com.oing.domain.BannerImageType;
import com.oing.domain.Post;
import com.oing.dto.response.ArrayResponse;
import com.oing.dto.response.BannerResponse;
import com.oing.dto.response.CalendarResponse;
import com.oing.dto.response.FamilyMonthlyStatisticsResponse;
import com.oing.restapi.CalendarApi;
import com.oing.service.FamilyService;
import com.oing.service.MemberService;
import com.oing.service.PostService;
import com.oing.util.OptimizedImageUrlGenerator;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
@Controller
@RequiredArgsConstructor
public class CalendarController implements CalendarApi {
private final MemberService memberService;
private final PostService postService;
private final FamilyService familyService;
private final OptimizedImageUrlGenerator optimizedImageUrlGenerator;
@Override
public ArrayResponse<CalendarResponse> getMonthlyCalendar(String yearMonth, String familyId) {
if (yearMonth == null) yearMonth = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM"));
LocalDate startDate = LocalDate.parse(yearMonth + "-01"); // yyyy-MM-dd 패턴으로 파싱
LocalDate endDate = startDate.plusMonths(1);
List<Post> daysLatestPosts = postService.findLatestPostOfEveryday(startDate, endDate, familyId);
List<CalendarResponse> calendarResponses = convertToCalendarResponse(daysLatestPosts, familyId);
return new ArrayResponse<>(calendarResponses);
}
private List<CalendarResponse> convertToCalendarResponse(List<Post> daysLatestPosts, String familyId) {
List<CalendarResponse> calendarResponses = new ArrayList<>();
for (Post dayLatestPost : daysLatestPosts) {
LocalDate postDate = dayLatestPost.getCreatedAt().toLocalDate();
// 탈퇴한 회원을 제외하고 allFamilyMembersUploaded 기본값이 true이므로, 탈퇴한 회원이 allFamilyMembersUploaded 계산에 영향을 미치지 않음
// edge case: 글을 업로드하지 않은 회원이 탈퇴하면, 과거 날짜들의 allFamilyMembersUploaded이 true로 변함 -> 핸들링할 수 없는 케이스
List<String> familyMembersIds = memberService.findFamilyMembersIdsByFamilyJoinAtBefore(familyId, postDate.plusDays(1));
boolean allFamilyMembersUploaded = true;
for (String memberId : familyMembersIds) {
if (!postService.existsByMemberIdAndFamilyIdAndCreatedAt(memberId, familyId, postDate)) {
allFamilyMembersUploaded = false;
break;
}
}
calendarResponses.add(new CalendarResponse(
dayLatestPost.getCreatedAt().toLocalDate(),
dayLatestPost.getId(),
optimizedImageUrlGenerator.getThumbnailUrlGenerator(dayLatestPost.getPostImgUrl()),
allFamilyMembersUploaded
));
}
return calendarResponses;
}
@Override
public BannerResponse getBanner(String yearMonth, String familyId) {
/* 파라미터 정리 */
if (yearMonth == null) yearMonth = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM"));
LocalDate startDate = LocalDate.parse(yearMonth + "-01"); // yyyy-MM-dd 패턴으로 파싱
LocalDate endDate = startDate.plusMonths(1);
/* 배너를 위한 필드 조회 */
/* 정적 필드 조회 */
int familyTopPercentage = familyService.getFamilyTopPercentage(familyId, startDate);
List<Post> familyPosts = postService.findAllByFamilyIdAndCreatedAtBetween(familyId, startDate, endDate);
int familyPostsCount = familyPosts.size();
int familyInteractionCount = familyPosts.stream().mapToInt((memberPost -> memberPost.getCommentCnt() + memberPost.getReactionCnt() + memberPost.getRealEmojiCnt())).sum();
/* 다이나믹 필드 계산 */
int allFamilyMembersUploadedDays = 0;
int allFamilyMembersUploadedStreaks = 0;
boolean allFamilyMembersUploadedStreaked = true;
// 한 달 동안 '가족이 전부 업로드한 날'과 '전부 업로드한 날의 연속'을 계산하기 위해, 1일부터 마지막 날까지 순회한다.
while (startDate.isBefore(endDate)) {
boolean allFamilyMembersUploaded = true;
if (postService.existsByFamilyIdAndCreatedAt(familyId, startDate)) {
List<String> familyMembersIds = memberService.findFamilyMembersIdsByFamilyJoinAtBefore(familyId, startDate.plusDays(1));
for (String memberId : familyMembersIds) {
if (!postService.existsByMemberIdAndFamilyIdAndCreatedAt(memberId, familyId, startDate)) {
allFamilyMembersUploaded = false;
break;
}
}
} else {
// 게시글이 없다면, 계산에서 제외
// 해당 날짜에 가족과 게시물이 없는 경우, allFamilyMembersUploaded = true 가 되는 것을 방지
// edge case: 게시물을 하나라도 없로드 하고 글을 업로드하지 않은 회원이 탈퇴하면, allFamilyMembersUploaded이 true로 변함 -> 핸들링할 수 없는 케이스
allFamilyMembersUploaded = false;
}
// (가족 전부 업로드한 날의 수, 연속해서 업로드한 여부, 연속해서 업로드한 날의 수) 계산
if (allFamilyMembersUploaded) {
allFamilyMembersUploadedDays++;
if (allFamilyMembersUploadedStreaked)
allFamilyMembersUploadedStreaks++;
} else {
allFamilyMembersUploadedStreaked = false;
}
startDate = startDate.plusDays(1);
}
int familyLevel = getFamilyLevel(familyPostsCount, allFamilyMembersUploadedDays, familyInteractionCount, allFamilyMembersUploadedStreaked);
BannerImageType bannerImageType = getBannerImageType(familyLevel);
return new BannerResponse(familyTopPercentage, allFamilyMembersUploadedDays, familyLevel, bannerImageType);
}
private int getFamilyLevel(int familyPostsCount, int allFamilyMembersUploadedDays, int familyInteractionCount, boolean allFamilyMembersUploadedStreaked) {
int familyLevel = 1;
// [ Level 1 기저 조건 ] 업로드 된 글이 없으면, 무조건 Level 1
if (familyPostsCount == 0) familyLevel = 1;
// [ Level 4 ] 모두 업로드 20일 이상 or (업로드 사진 60개 이상 and 리액션 120개 이상)
else if (allFamilyMembersUploadedDays >= 20 || (familyPostsCount >= 60 && familyInteractionCount >= 120))
familyLevel = 4;
// [ Level 3 ] 이때까지 모두 업로드가 연속되면 OR (업로드 사진 10개이상 and 리액션 10개 이상)
else if (allFamilyMembersUploadedStreaked || (familyPostsCount >= 10 && familyInteractionCount >= 10))
familyLevel = 3;
// [ Level 2 ] 모두 업로드 한 날이 1일 이상 OR 업로드된 사진 2개 이상
else if (allFamilyMembersUploadedDays >= 1 || familyPostsCount >= 2) familyLevel = 2;
return familyLevel;
}
private BannerImageType getBannerImageType(int familyLevel) {
BannerImageType bannerImageType;
if (familyLevel == 1) bannerImageType = BannerImageType.SKULL_FLAG;
else if (familyLevel == 2) bannerImageType = BannerImageType.ALONE_WALKING;
else if (familyLevel == 3) bannerImageType = BannerImageType.WE_ARE_FRIENDS;
else if (familyLevel == 4) bannerImageType = BannerImageType.JEWELRY_TREASURE;
else bannerImageType = BannerImageType.SKULL_FLAG; // 예외 처리
return bannerImageType;
}
@Override
public FamilyMonthlyStatisticsResponse getSummary(String yearMonth, String loginMemberId) {
String[] yearMonthArray = yearMonth.split("-");
int year = Integer.parseInt(yearMonthArray[0]);
int month = Integer.parseInt(yearMonthArray[1]);
String familyId = memberService.findFamilyIdByMemberId(loginMemberId);
long monthlyPostCount = postService.countMonthlyPostByFamilyId(year, month, familyId);
return new FamilyMonthlyStatisticsResponse((int) monthlyPostCount);
}
}