Skip to content

Commit 1493e75

Browse files
mingeun.kimmingeun0507
authored andcommitted
feat: 그플리 추가 API 구현
1 parent c617092 commit 1493e75

File tree

7 files changed

+108
-7
lines changed

7 files changed

+108
-7
lines changed

src/main/java/com/guttery/madii/domain/achievement/application/service/AchievementServiceHelper.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import lombok.AccessLevel;
1111
import lombok.NoArgsConstructor;
1212

13+
import java.time.LocalDate;
14+
1315
@NoArgsConstructor(access = AccessLevel.PRIVATE)
1416
public class AchievementServiceHelper {
1517
public static Achievement findExistingAchievement(final AchievementRepository achievementRepository, final Long achievementId) {
@@ -35,4 +37,10 @@ public static void validateUnfinishedJoyAchievementNotInPlaylist(final Achieveme
3537
throw CustomException.of(ErrorDetails.UNFINISHED_JOY_ALREADY_EXISTS_IN_PLAYLIST);
3638
}
3739
}
40+
41+
public static void validateUnfinishedJoyAchievementNotInPlaylistForDate(final AchievementRepository achievementRepository, final Joy joy, final User achiever, final LocalDate date) {
42+
if (achievementRepository.checkJoyAlreadyInPlaylistForDate(joy, achiever, date)) {
43+
throw CustomException.of(ErrorDetails.UNFINISHED_JOY_ALREADY_EXISTS_IN_PLAYLIST);
44+
}
45+
}
3846
}

src/main/java/com/guttery/madii/domain/achievement/application/service/JoyPlaylistService.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.guttery.madii.domain.achievement.application.service;
22

33
import com.guttery.madii.domain.achievement.application.dto.AddAchievementRequest;
4+
import com.guttery.madii.domain.achievement.application.dto.AddAchievementRequestV2;
45
import com.guttery.madii.domain.achievement.application.dto.DateSpecificPlaylistResponse;
56
import com.guttery.madii.domain.achievement.application.dto.DateSpecificPlaylistResponseV2;
67
import com.guttery.madii.domain.achievement.application.dto.JoyPlaylistResponse;
@@ -41,6 +42,24 @@ public void addAchievementInPlaylist(final AddAchievementRequest addAchievementR
4142
achievementRepository.save(newAchievement);
4243
}
4344

45+
@Transactional
46+
public DateSpecificPlaylistResponseV2 addAchievementInPlaylistV2(final AddAchievementRequestV2 addAchievementRequestV2, final UserPrincipal userPrincipal) {
47+
final User user = UserServiceHelper.findExistingUser(userRepository, userPrincipal);
48+
final Joy joy = JoyServiceHelper.findExistingJoy(joyRepository, addAchievementRequestV2.joyId());
49+
50+
// 특정 날짜에 해당 소확행이 이미 있는지 확인
51+
AchievementServiceHelper.validateUnfinishedJoyAchievementNotInPlaylistForDate(achievementRepository, joy, user, addAchievementRequestV2.date());
52+
53+
// 특정 날짜에 실천 추가
54+
final Achievement newAchievement = Achievement.createForDate(user, joy, FinishInfo.createNotFinished(), addAchievementRequestV2.date());
55+
log.info("Creating achievement for date: {}, joyId: {}, userId: {}", addAchievementRequestV2.date(), addAchievementRequestV2.joyId(), user.getUserId());
56+
achievementRepository.save(newAchievement);
57+
log.info("Achievement saved with createdDate: {}", newAchievement.getCreatedDate());
58+
59+
// 해당 날짜의 플레이리스트 조회하여 반환
60+
return achievementRepository.getAchievementsInPlaylistByDateV2(user.getUserId(), addAchievementRequestV2.date(), null);
61+
}
62+
4463
@Transactional(readOnly = true)
4564
public JoyPlaylistResponse getAchievementsInPlaylist(final UserPrincipal userPrincipal) {
4665
final User user = UserServiceHelper.findExistingUser(userRepository, userPrincipal);

src/main/java/com/guttery/madii/domain/achievement/application/service/UpdateAchievementStatusService.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import com.guttery.madii.domain.achievement.application.dto.CancelAchievementRequest;
44
import com.guttery.madii.domain.achievement.application.dto.FinishAchievementRequest;
5+
import com.guttery.madii.domain.achievement.application.dto.FinishAchievementRequestV2;
56
import com.guttery.madii.domain.achievement.application.dto.RateAchievementRequest;
7+
import com.guttery.madii.domain.achievement.application.dto.DateSpecificPlaylistResponseV2;
68
import com.guttery.madii.domain.achievement.domain.model.Achievement;
79
import com.guttery.madii.domain.achievement.domain.repository.AchievementRepository;
810
import com.guttery.madii.domain.user.domain.model.UserPrincipal;
@@ -41,4 +43,15 @@ public void cancelAchievement(final CancelAchievementRequest cancelAchievementRe
4143

4244
achievementRepository.save(foundAchievement);
4345
}
46+
47+
@Transactional
48+
public DateSpecificPlaylistResponseV2 finishAchievementV2(final FinishAchievementRequestV2 finishAchievementRequestV2, final UserPrincipal userPrincipal) {
49+
final Achievement foundAchievement = AchievementServiceHelper.findValidAchievement(achievementRepository, finishAchievementRequestV2.achievementId(), userPrincipal);
50+
foundAchievement.finish(finishAchievementRequestV2.satisfaction());
51+
52+
achievementRepository.save(foundAchievement);
53+
54+
// 해당 날짜의 플레이리스트 조회하여 반환
55+
return achievementRepository.getAchievementsInPlaylistByDateV2(userPrincipal.id(), finishAchievementRequestV2.date(), null);
56+
}
4457
}

src/main/java/com/guttery/madii/domain/achievement/domain/model/Achievement.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
import lombok.AccessLevel;
88
import lombok.Getter;
99
import lombok.NoArgsConstructor;
10-
import org.hibernate.annotations.CreationTimestamp;
11-
1210
import java.time.LocalDate;
1311

1412
@Getter
@@ -26,18 +24,29 @@ public class Achievement extends BaseTimeEntity {
2624
private Joy joy;
2725
@Embedded
2826
private FinishInfo finishInfo;
29-
@CreationTimestamp
3027
private LocalDate createdDate;
3128

3229
public Achievement(User achiever, Joy joy, FinishInfo finishInfo) {
3330
this.achiever = achiever;
3431
this.joy = joy;
3532
this.finishInfo = finishInfo;
33+
this.createdDate = LocalDate.now();
34+
}
35+
36+
public Achievement(User achiever, Joy joy, FinishInfo finishInfo, LocalDate createdDate) {
37+
this.achiever = achiever;
38+
this.joy = joy;
39+
this.finishInfo = finishInfo;
40+
this.createdDate = createdDate;
3641
}
3742

3843
public static Achievement create(User user, Joy joy, FinishInfo finishInfo) {
3944
return new Achievement(user, joy, finishInfo);
4045
}
46+
47+
public static Achievement createForDate(User user, Joy joy, FinishInfo finishInfo, LocalDate date) {
48+
return new Achievement(user, joy, finishInfo, date);
49+
}
4150

4251
public void finish(final Satisfaction satisfaction) {
4352
if (satisfaction != null) {

src/main/java/com/guttery/madii/domain/achievement/domain/repository/AchievementQueryDslRepository.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,6 @@ public interface AchievementQueryDslRepository {
2323
CalenderDailyJoyAchievementResponse getDailyJoyAchievementInfos(Long userId, LocalDate date);
2424

2525
boolean checkJoyAlreadyInPlaylist(Joy joy, User achiever);
26+
27+
boolean checkJoyAlreadyInPlaylistForDate(Joy joy, User achiever, LocalDate date);
2628
}

src/main/java/com/guttery/madii/domain/achievement/infrastructure/AchievementRepositoryImpl.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.querydsl.core.types.dsl.StringExpression;
2222
import com.querydsl.jpa.impl.JPAQuery;
2323
import com.querydsl.jpa.impl.JPAQueryFactory;
24+
import lombok.extern.slf4j.Slf4j;
2425
import org.springframework.stereotype.Repository;
2526

2627
import java.time.LocalDate;
@@ -35,6 +36,7 @@
3536
import static com.querydsl.core.types.dsl.Expressions.stringTemplate;
3637

3738

39+
@Slf4j
3840
@Repository
3941
public class AchievementRepositoryImpl extends BaseQueryDslRepository<AchievementRepository> implements AchievementQueryDslRepository {
4042
private static final int MAX_COLOR_NUM = 6;
@@ -135,14 +137,13 @@ public DateSpecificPlaylistResponse getAchievementsInPlaylistByDate(final Long u
135137

136138
@Override
137139
public DateSpecificPlaylistResponseV2 getAchievementsInPlaylistByDateV2(final Long userId, final LocalDate date, final Boolean isFinished) {
138-
final LocalDateTime startOfDay = date.atStartOfDay().plusHours(TODAY_PLAYLIST_TIME_OFFSET);
139-
final LocalDateTime endOfDay = date.atStartOfDay().plusDays(1).plusHours(TODAY_PLAYLIST_TIME_OFFSET).minusSeconds(1);
140-
140+
log.info("Querying achievements for userId: {}, date: {}", userId, date);
141+
141142
JPAQuery<JoyAchievementInfoV2> query = select(JoyAchievementInfoV2.class, joy.joyId, achievement.achievementId, joy.joyIconNum, joy.contents, achievement.finishInfo.isFinished)
142143
.from(achievement)
143144
.join(achievement.joy, joy)
144145
.join(achievement.achiever, user)
145-
.where(achievement.achiever.userId.eq(userId), achievement.createdAt.between(startOfDay, endOfDay));
146+
.where(achievement.achiever.userId.eq(userId), achievement.createdDate.eq(date));
146147

147148
if (isFinished != null) {
148149
query = query.where(achievement.finishInfo.isFinished.eq(isFinished));
@@ -152,6 +153,7 @@ public DateSpecificPlaylistResponseV2 getAchievementsInPlaylistByDateV2(final Lo
152153
.orderBy(achievement.finishInfo.isFinished.asc(), achievement.finishInfo.finishedAt.asc(), achievement.createdAt.desc())
153154
.fetch();
154155

156+
log.info("Found {} achievements for date: {}", joyAchievementInfos.size(), date);
155157
return new DateSpecificPlaylistResponseV2(date, joyAchievementInfos);
156158
}
157159

@@ -183,4 +185,16 @@ public boolean checkJoyAlreadyInPlaylist(final Joy addedJoy, final User achiever
183185
.where(achievement.achiever.eq(achiever), joy.eq(addedJoy), achievement.finishInfo.isFinished.isFalse(), achievement.createdAt.between(date.atStartOfDay().plusHours(TODAY_PLAYLIST_TIME_OFFSET), date.atStartOfDay().plusDays(1).minusSeconds(1).plusHours(TODAY_PLAYLIST_TIME_OFFSET)))
184186
.fetchFirst() != null;
185187
}
188+
189+
@Override
190+
public boolean checkJoyAlreadyInPlaylistForDate(final Joy addedJoy, final User achiever, final LocalDate date) {
191+
return select(achievement)
192+
.from(achievement)
193+
.join(achievement.joy, joy)
194+
.fetchJoin()
195+
.join(achievement.achiever, user)
196+
.fetchJoin()
197+
.where(achievement.achiever.eq(achiever), joy.eq(addedJoy), achievement.finishInfo.isFinished.isFalse(), achievement.createdDate.eq(date))
198+
.fetchFirst() != null;
199+
}
186200
}

src/main/java/com/guttery/madii/domain/achievement/presentation/AchievementController.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,24 @@ public JoyPlaylistResponse addAchievementInPlaylist(
9191
return joyPlaylistService.getAchievementsInPlaylist(userPrincipal);
9292
}
9393

94+
@PostMapping("/v2/achievements")
95+
@ApiResponses(
96+
value = {
97+
@ApiResponse(
98+
responseCode = "200",
99+
description = "플레이리스트 추가 성공",
100+
useReturnTypeSchema = true
101+
)
102+
}
103+
)
104+
@Operation(summary = "특정 날짜 플레이리스트 추가 API", description = "특정 날짜에 실천을 추가하는 API입니다.")
105+
public DateSpecificPlaylistResponseV2 addAchievementInPlaylistV2(
106+
@Valid @RequestBody final AddAchievementRequestV2 addAchievementRequestV2,
107+
@NotNull @AuthenticationPrincipal final UserPrincipal userPrincipal
108+
) {
109+
return joyPlaylistService.addAchievementInPlaylistV2(addAchievementRequestV2, userPrincipal);
110+
}
111+
94112
@DeleteMapping("/v1/achievements")
95113
@ApiResponses(
96114
value = {
@@ -131,6 +149,24 @@ public JoyPlaylistResponse finishAchievement(
131149
return joyPlaylistService.getAchievementsInPlaylist(userPrincipal);
132150
}
133151

152+
@PutMapping("/v2/achievements/finish")
153+
@ApiResponses(
154+
value = {
155+
@ApiResponse(
156+
responseCode = "200",
157+
description = "실천 완료 성공",
158+
useReturnTypeSchema = true
159+
)
160+
}
161+
)
162+
@Operation(summary = "특정 날짜 실천 완료 API", description = "특정 날짜의 실천을 완료하는 API입니다. 만족도는 nullable합니다.")
163+
public DateSpecificPlaylistResponseV2 finishAchievementV2(
164+
@Valid @RequestBody final FinishAchievementRequestV2 finishAchievementRequestV2,
165+
@NotNull @AuthenticationPrincipal final UserPrincipal userPrincipal
166+
) {
167+
return updateAchievementStatusService.finishAchievementV2(finishAchievementRequestV2, userPrincipal);
168+
}
169+
134170
@PutMapping("/v1/achievements/rate")
135171
@ApiResponses(
136172
value = {

0 commit comments

Comments
 (0)