-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[REFACT] 유저의 이력 처리, 업적의 달성 체크, 업적 달성 알림에 대한 이벤트 구독 처리 핸들러 리팩토링
- Loading branch information
Showing
3 changed files
with
319 additions
and
0 deletions.
There are no files selected for viewing
121 changes: 121 additions & 0 deletions
121
src/main/java/io/oeid/mogakgo/common/event/handler/AchievementCheckListener.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
package io.oeid.mogakgo.common.event.handler; | ||
|
||
import static io.oeid.mogakgo.exception.code.ErrorCode400.NON_ACHIEVED_USER_ACHIEVEMENT; | ||
|
||
import io.oeid.mogakgo.common.event.AchievementCompletionEvent; | ||
import io.oeid.mogakgo.domain.achievement.application.AchievementFacadeService; | ||
import io.oeid.mogakgo.domain.achievement.application.AchievementProgressService; | ||
import io.oeid.mogakgo.domain.achievement.domain.entity.Achievement; | ||
import io.oeid.mogakgo.domain.achievement.domain.entity.AchievementMessage; | ||
import io.oeid.mogakgo.domain.achievement.domain.entity.UserAchievement; | ||
import io.oeid.mogakgo.domain.achievement.domain.entity.UserActivity; | ||
import io.oeid.mogakgo.domain.achievement.domain.entity.enums.RequirementType; | ||
import io.oeid.mogakgo.domain.achievement.exception.UserAchievementException; | ||
import io.oeid.mogakgo.domain.achievement.infrastructure.UserAchievementJpaRepository; | ||
import io.oeid.mogakgo.domain.achievement.infrastructure.UserActivityJpaRepository; | ||
import io.oeid.mogakgo.domain.user.application.UserCommonService; | ||
import io.oeid.mogakgo.domain.user.domain.User; | ||
import java.util.List; | ||
import java.util.Objects; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.messaging.simp.SimpMessagingTemplate; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
import org.springframework.transaction.event.TransactionalEventListener; | ||
|
||
@Slf4j | ||
@Service | ||
@Transactional(readOnly = true) | ||
@RequiredArgsConstructor | ||
public class AchievementCheckListener { | ||
|
||
private static final String SUBSCRIBE_DESTINATIONN = "/topic/achievement/"; | ||
|
||
private final UserCommonService userCommonService; | ||
private final AchievementFacadeService achievementFacadeService; | ||
private final UserAchievementJpaRepository userAchievementRepository; | ||
private final UserActivityJpaRepository userActivityRepository; | ||
private final AchievementProgressService achievementProgressService; | ||
private final SimpMessagingTemplate messagingTemplate; | ||
|
||
@TransactionalEventListener | ||
public void executeEvent(final AchievementCompletionEvent event) { | ||
|
||
Long achievementId = achievementFacadeService | ||
.getAvailableAchievementId(event.getUserId(), event.getActivityType()); | ||
|
||
if (achievementId != null) { | ||
|
||
User user = userCommonService.getUserById(event.getUserId()); | ||
UserAchievement userAchievement = getByUserAndAchievement(event.getUserId(), achievementId); | ||
|
||
Boolean isExist = achievementFacadeService | ||
.validateAchivementAlreadyInProgress(event.getUserId(), achievementId); | ||
|
||
// -- 업적에 대한 진행도가 존재하지 않을 경우 | ||
if (isExist.equals(Boolean.FALSE)) { | ||
userAchievementRepository.save( | ||
UserAchievement.builder() | ||
.user(user) | ||
.achievement(userAchievement.getAchievement()) | ||
.completed(Boolean.FALSE) | ||
.build() | ||
); | ||
} | ||
|
||
Object progressCount = event.getTarget() == null | ||
? getProgressCountForAchievement(event.getUserId(), userAchievement.getAchievement()) + 1 | ||
: event.getTarget(); | ||
|
||
// -- 업적이 달성 가능한 조건을 만족했을 경우 | ||
if (validateAvailabilityToAchieve(progressCount, userAchievement.getAchievement())) { | ||
userAchievement.updateCompleted(); | ||
|
||
// -- 해당 업적이 연속적으로 달성 가능한 업적인 경우 | ||
if (userAchievement.getAchievement().getRequirementType() | ||
.equals(RequirementType.SEQUENCE)) { | ||
List<UserActivity> history = userActivityRepository.getActivityHistoryByActivityType( | ||
event.getUserId(), userAchievement.getAchievement().getActivityType(), | ||
userAchievement.getAchievement().getRequirementValue()); | ||
history.forEach(UserActivity::delete); | ||
} | ||
|
||
// -- 업적 달성에 대한 STOMP 통신 | ||
messagingTemplate.convertAndSend(SUBSCRIBE_DESTINATIONN + event.getUserId(), | ||
AchievementMessage.builder() | ||
.userId(event.getUserId()) | ||
.achievementId(achievementId) | ||
.progressCount(userAchievement.getAchievement().getRequirementValue()) | ||
.requirementValue(userAchievement.getAchievement().getRequirementValue()) | ||
.completed(Boolean.TRUE) | ||
.build() | ||
); | ||
} | ||
} | ||
} | ||
|
||
private UserAchievement getByUserAndAchievement(Long userId, Long achievementId) { | ||
return userAchievementRepository.findByUserAndAchievementId(userId, achievementId) | ||
.orElseThrow(() -> new UserAchievementException(NON_ACHIEVED_USER_ACHIEVEMENT)); | ||
} | ||
|
||
private Integer getProgressCountForAchievement(Long userId, Achievement achievement) { | ||
if (achievement.getRequirementType().equals(RequirementType.ACCUMULATE)) { | ||
return achievementProgressService.getAccumulatedProgressCount(userId, achievement.getActivityType()); | ||
} | ||
return achievementProgressService.getProgressCountMap(userId, | ||
List.of(achievement.getActivityType())).get(achievement.getActivityType()); | ||
} | ||
|
||
private boolean validateAvailabilityToAchieve(Object target, Achievement achievement) { | ||
if (target instanceof Integer) { | ||
return Objects.equals(achievement.getRequirementValue(), target); | ||
} else if (target instanceof Double) { | ||
return achievement.getRequirementValue() <= (Double) target; | ||
} else { | ||
throw new IllegalArgumentException("Unsupported target type"); | ||
} | ||
} | ||
|
||
} |
91 changes: 91 additions & 0 deletions
91
src/main/java/io/oeid/mogakgo/common/event/handler/NotificationListener.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package io.oeid.mogakgo.common.event.handler; | ||
|
||
import static io.oeid.mogakgo.exception.code.ErrorCode400.NON_ACHIEVED_USER_ACHIEVEMENT; | ||
|
||
import io.oeid.mogakgo.common.event.AchievementNotificationEvent; | ||
import io.oeid.mogakgo.domain.achievement.application.AchievementFacadeService; | ||
import io.oeid.mogakgo.domain.achievement.application.AchievementProgressService; | ||
import io.oeid.mogakgo.domain.achievement.domain.entity.Achievement; | ||
import io.oeid.mogakgo.domain.achievement.domain.entity.AchievementMessage; | ||
import io.oeid.mogakgo.domain.achievement.domain.entity.UserAchievement; | ||
import io.oeid.mogakgo.domain.achievement.domain.entity.enums.RequirementType; | ||
import io.oeid.mogakgo.domain.achievement.exception.UserAchievementException; | ||
import io.oeid.mogakgo.domain.achievement.infrastructure.AchievementJpaRepository; | ||
import io.oeid.mogakgo.domain.achievement.infrastructure.UserAchievementJpaRepository; | ||
import java.util.List; | ||
import java.util.Objects; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.messaging.simp.SimpMessagingTemplate; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
import org.springframework.transaction.event.TransactionalEventListener; | ||
|
||
@Slf4j | ||
@Service | ||
@Transactional(readOnly = true) | ||
@RequiredArgsConstructor | ||
public class NotificationListener { | ||
|
||
private static final String SUBSCRIBE_DESTINATIONN = "/topic/achievement/"; | ||
|
||
private final SimpMessagingTemplate messagingTemplate; | ||
private final AchievementJpaRepository achievementRepository; | ||
private final UserAchievementJpaRepository userAchievementRepository; | ||
private final AchievementProgressService achievementProgressService; | ||
private final AchievementFacadeService achievementFacadeService; | ||
|
||
@TransactionalEventListener | ||
public void executeEvent(final AchievementNotificationEvent event) { | ||
|
||
// 사용자가 현재 달성할 수 있는 업적 ID | ||
Long achievementId = achievementFacadeService | ||
.getAvailableAchievementId(event.getUserId(), event.getActivityType()); | ||
|
||
if (achievementId != null) { | ||
|
||
UserAchievement userAchievement = getByUserAndAchievement(event.getUserId(), achievementId); | ||
Object progressCount = event.getTarget() == null | ||
? getProgressCountForAchievement(event.getUserId(), userAchievement.getAchievement()) + 1 | ||
: event.getTarget(); | ||
|
||
// -- 업적이 달성 가능한 조건을 만족했을 경우 | ||
if (validateAvailabilityToAchieve(progressCount, userAchievement.getAchievement())) { | ||
userAchievement.updateCompleted(); | ||
|
||
messagingTemplate.convertAndSend(SUBSCRIBE_DESTINATIONN + event.getUserId(), | ||
AchievementMessage.builder() | ||
.userId(event.getUserId()) | ||
.achievementId(achievementId) | ||
.progressCount((Integer) progressCount) | ||
.requirementValue(userAchievement.getAchievement().getRequirementValue()) | ||
.build() | ||
); | ||
} | ||
} | ||
} | ||
|
||
private UserAchievement getByUserAndAchievement(Long userId, Long achievementId) { | ||
return userAchievementRepository.findByUserAndAchievementId(userId, achievementId) | ||
.orElseThrow(() -> new UserAchievementException(NON_ACHIEVED_USER_ACHIEVEMENT)); | ||
} | ||
|
||
private Integer getProgressCountForAchievement(Long userId, Achievement achievement) { | ||
if (achievement.getRequirementType().equals(RequirementType.ACCUMULATE)) { | ||
return achievementProgressService.getAccumulatedProgressCount(userId, achievement.getActivityType()); | ||
} | ||
return achievementProgressService.getProgressCountMap(userId, | ||
List.of(achievement.getActivityType())).get(achievement.getActivityType()); | ||
} | ||
|
||
private boolean validateAvailabilityToAchieve(Object target, Achievement achievement) { | ||
if (target instanceof Integer) { | ||
return Objects.equals(achievement.getRequirementValue(), (Integer) target + 1); | ||
} else if (target instanceof Double) { | ||
return achievement.getRequirementValue() <= (Double) target; | ||
} else { | ||
throw new IllegalArgumentException("Unsupported target type"); | ||
} | ||
} | ||
|
||
} |
107 changes: 107 additions & 0 deletions
107
src/main/java/io/oeid/mogakgo/common/event/handler/UserActivityListener.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package io.oeid.mogakgo.common.event.handler; | ||
|
||
import io.oeid.mogakgo.common.event.UserActivityEvents; | ||
import io.oeid.mogakgo.domain.achievement.application.AchievementFacadeService; | ||
import io.oeid.mogakgo.domain.achievement.application.AchievementProgressService; | ||
import io.oeid.mogakgo.domain.achievement.domain.entity.Achievement; | ||
import io.oeid.mogakgo.domain.achievement.domain.entity.AchievementMessage; | ||
import io.oeid.mogakgo.domain.achievement.domain.entity.UserActivity; | ||
import io.oeid.mogakgo.domain.achievement.domain.entity.enums.ActivityType; | ||
import io.oeid.mogakgo.domain.achievement.domain.entity.enums.RequirementType; | ||
import io.oeid.mogakgo.domain.achievement.infrastructure.AchievementJpaRepository; | ||
import io.oeid.mogakgo.domain.achievement.infrastructure.UserActivityJpaRepository; | ||
import io.oeid.mogakgo.domain.user.application.UserCommonService; | ||
import io.oeid.mogakgo.domain.user.domain.User; | ||
import java.util.List; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.messaging.simp.SimpMessagingTemplate; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
import org.springframework.transaction.event.TransactionalEventListener; | ||
|
||
@Slf4j | ||
@Service | ||
@Transactional(readOnly = true) | ||
@RequiredArgsConstructor | ||
public class UserActivityListener { | ||
|
||
private static final Integer MIN_PROGRESS_SIZE = 1; | ||
private static final String SUBSCRIBE_DESTINATIONN = "/topic/achievement/"; | ||
|
||
private final UserCommonService userCommonService; | ||
private final AchievementJpaRepository achievementRepository; | ||
private final UserActivityJpaRepository userActivityRepository; | ||
private final AchievementFacadeService achievementFacadeService; | ||
private final AchievementProgressService achievementProgressService; | ||
private final SimpMessagingTemplate messagingTemplate; | ||
|
||
@TransactionalEventListener | ||
public void executeEvent(final UserActivityEvents event) { | ||
|
||
// 사용자가 현재 달성할 수 있는 업적 ID | ||
Long achievementId = achievementFacadeService | ||
.getAvailableAchievementId(event.getUserId(), event.getActivityType()); | ||
|
||
if (achievementId != null) { | ||
|
||
// -- 업적이 연속적으로 달성 가능한 업적인 경우 | ||
Achievement achievement = achievementFacadeService.getById(achievementId); | ||
if (achievement.getRequirementType().equals(RequirementType.SEQUENCE)) { | ||
|
||
// -- 당일에 연속적으로 달성 가능한 업적에 대한 이벤트를 발행한 적이 없는 경우 | ||
if (achievementFacadeService.validateActivityDuplicate(event.getUserId(), event.getActivityType())) { | ||
saveActivity(event); | ||
} | ||
} else { | ||
saveActivity(event); | ||
} | ||
|
||
// 업적이 진행중이거나 한 번에 달성 가능한 업적이 아닌 경우 | ||
Integer progressCount = getProgressCountForAchievement(event.getUserId(), achievement); | ||
if (!isAvailableToAchieve(progressCount, achievement) || !isAvailableToAchieveOnce(event.getActivityType())) { | ||
|
||
// 업적 진행에 대한 STOMP 통신 | ||
messagingTemplate.convertAndSend(SUBSCRIBE_DESTINATIONN + event.getUserId(), | ||
AchievementMessage.builder() | ||
.userId(event.getUserId()) | ||
.achievementId(achievementId) | ||
.progressCount(progressCount) | ||
.requirementValue(achievement.getRequirementValue()) | ||
.build() | ||
); | ||
} | ||
} | ||
} | ||
|
||
private void saveActivity(final UserActivityEvents event) { | ||
User user = userCommonService.getUserById(event.getUserId()); | ||
userActivityRepository.save( | ||
UserActivity.builder() | ||
.user(user) | ||
.activityType(event.getActivityType()) | ||
.build() | ||
); | ||
} | ||
|
||
private Integer getProgressCountForAchievement(Long userId, Achievement achievement) { | ||
if (achievement.getRequirementType().equals(RequirementType.ACCUMULATE)) { | ||
return achievementProgressService.getAccumulatedProgressCount(userId, achievement.getActivityType()); | ||
} | ||
return achievementProgressService.getProgressCountMap(userId, | ||
List.of(achievement.getActivityType())).get(achievement.getActivityType()); | ||
} | ||
|
||
private boolean isAvailableToAchieve(Integer progressCount, Achievement achievement) { | ||
return achievement.getRequirementValue().equals(progressCount); | ||
} | ||
|
||
private boolean isAvailableToAchieveOnce(ActivityType activityType) { | ||
return getProgressLevelSize(activityType).equals(MIN_PROGRESS_SIZE); | ||
} | ||
|
||
private Integer getProgressLevelSize(ActivityType activityType) { | ||
return achievementRepository.findByActivityType(activityType).size(); | ||
} | ||
|
||
} |