Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

♻️ refactor: update user level batch refactoring #454

Merged
merged 5 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.depromeet.domains.level.service;

import com.depromeet.domains.level.data.LevelPolicy;
import com.depromeet.level.data.LevelPolicy;
import com.depromeet.domains.level.dto.LevelPolicyDataDto;
import com.depromeet.domains.level.dto.LevelPolicyResponseDto;
import lombok.RequiredArgsConstructor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@
import com.depromeet.common.error.dto.CommonErrorCode;
import com.depromeet.common.error.exception.internal.NotFoundException;
import com.depromeet.domains.item.repository.ItemRepository;
import com.depromeet.domains.level.data.LevelPolicy;
import com.depromeet.domains.user.dto.response.UserLevelProgressDto;
import com.depromeet.domains.user.dto.response.UserLevelResponseDto;
import com.depromeet.domains.user.repository.UserLevelRepository;
import com.depromeet.level.data.LevelPolicy;
import com.depromeet.user.User;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;

import static com.depromeet.domains.level.data.LevelPolicy.getNextLevel;
import static com.depromeet.level.data.LevelPolicy.getNextLevel;


@RequiredArgsConstructor
@Service
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.depromeet.domains.item.dto;

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
@Getter
public class UserItemCount {
private Long userId;
private Long itemCount;
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
package com.depromeet.domains.item.repository;

import com.depromeet.domains.user.UserItemDto;
import com.depromeet.domains.item.dto.UserItemCount;
import com.depromeet.item.Item;
import com.depromeet.user.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.List;

@Repository
public interface ItemRepository extends JpaRepository<Item, Long> {

@Query("SELECT new com.depromeet.domains.user.UserItemDto(i.user.id, CAST(COUNT(i.id) AS int)) FROM Item i WHERE i.user.id IN :userIds GROUP BY i.user.id")
List<UserItemDto> countItemsByUserIdIn(@Param("userIds") List<Long> userIds);
@Query("SELECT new com.depromeet.domains.item.dto.UserItemCount(i.user.id, CAST(COUNT(i.id) AS long)) FROM Item i WHERE i.user.id IN :userIds GROUP BY i.user.id")
List<UserItemCount> countItemsByUserIdIn(@Param("userIds") List<Long> userIds);

@Query("SELECT i.user FROM Item AS i WHERE i.createdAt > :createdAt")
List<User> findAllItemUpdateUser(@Param("createdAt") LocalDateTime createdAt);

seonghun-dev marked this conversation as resolved.
Show resolved Hide resolved
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.depromeet.domains.level;

import com.depromeet.level.data.LevelPolicy;
import lombok.AllArgsConstructor;

import java.util.Arrays;

@AllArgsConstructor
public class LevelUpdater {
public static LevelPolicy getUpdateLevel(Long dropCount) {
return Arrays.stream(LevelPolicy.values())
.filter(policy -> dropCount >= policy.getDropCountStart() && dropCount < policy.getDropCountEnd())
.findFirst()
.orElse(LevelPolicy.LEVEL_1);
}
siyeonSon marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.depromeet.popup.Popup;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface PopupRepository extends JpaRepository<Popup, Long> {
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,9 @@ public void createLevelUpPopup(User user, long newLevel) {
Popup popup = new Popup(user.getId(), "LEVEL_" + newLevel);
popupRepository.save(popup);
}

public void createGuidePopup(User user) {
Popup popup = new Popup(user.getId(), "GUIDE_1");
popupRepository.save(popup);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.depromeet.domains.user.jobs;

import com.depromeet.domains.user.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class UserGuideJob {
private final UserService userService;

public void run() {
userService.createGuidePopup();
}

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package com.depromeet.domains.user.repository;

import com.depromeet.user.User;
import com.depromeet.user.UserLevel;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.List;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {

List<User> findAllByCreatedAtBefore(LocalDateTime createdAt);
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
package com.depromeet.domains.user.scheduler;

import com.depromeet.domains.user.jobs.UserGuideJob;
import com.depromeet.domains.user.jobs.UserLevelJob;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class UserLevelBatchScheduler {
private final UserLevelJob userLevelJob;
private final UserGuideJob userGuideJob;

@Scheduled(cron = "0 0/30 * * * *")
public void runUserLevelJob() {
userLevelJob.run();
}

@Scheduled(cron = "0 0/30 * * * *")
public void runUserGuideJob() {
userGuideJob.run();
}
}
Original file line number Diff line number Diff line change
@@ -1,84 +1,61 @@
package com.depromeet.domains.user.service;

import com.depromeet.domains.item.dto.UserItemCount;
import com.depromeet.domains.item.repository.ItemRepository;
import com.depromeet.domains.level.LevelUpdatePolicy;
import com.depromeet.domains.level.LevelUpdatePolicyImpl;
import com.depromeet.domains.level.LevelUpdater;
import com.depromeet.domains.popup.service.PopupService;
import com.depromeet.domains.user.UserItemDto;
import com.depromeet.domains.user.repository.UserLevelRepository;
import com.depromeet.domains.user.repository.UserRepository;
import com.depromeet.level.data.LevelPolicy;
import com.depromeet.user.User;
import com.depromeet.user.UserLevel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class UserService {

public static final int LEVEL_ONE = 1;
public static final int LEVEL_TWO = 2;
public static final int LEVEL_THREE = 3;

private final UserRepository userRepository;
private final UserLevelRepository userLevelRepository;
private final ItemRepository itemRepository;
private final Map<Integer, LevelUpdatePolicy> levelUpdatePolicies;
private final PopupService popupService;

public UserService(UserRepository userRepository, UserLevelRepository userLevelRepository, ItemRepository itemRepository, PopupService popupService) {
this.userRepository = userRepository;
this.userLevelRepository = userLevelRepository;
this.itemRepository = itemRepository;
levelUpdatePolicies = createLevelUpdatePolicies();
this.popupService = popupService;
}

private Map<Integer, LevelUpdatePolicy> createLevelUpdatePolicies() {
Map<Integer, LevelUpdatePolicy> policies = new HashMap<>();
policies.put(LEVEL_ONE, new LevelUpdatePolicyImpl(0, 4, getUserLevelById(1L)));
policies.put(LEVEL_TWO, new LevelUpdatePolicyImpl(5, 24, getUserLevelById(2L)));
policies.put(LEVEL_THREE, new LevelUpdatePolicyImpl(25, 55, getUserLevelById(3L)));
return policies;
}

private UserLevel getUserLevelById(long userLevelId) {
return userLevelRepository.findUserLevelById(userLevelId);
@Transactional
public void createGuidePopup() {
var signUpUsers = userRepository.findAllByCreatedAtBefore(LocalDateTime.now().minusMinutes(30));
signUpUsers.forEach(popupService::createGuidePopup);
}

@Transactional
public void updateLevel() {
List<User> usersToUpdateLevel = new ArrayList<>();
var allUsers = userRepository.findAll();
var userIds = allUsers.stream().map(User::getId).collect(Collectors.toList());
var userItemDtoList = itemRepository.countItemsByUserIdIn(userIds);

Map<Long, Integer> itemCountMap = userItemDtoList.stream()
.collect(Collectors.toMap(UserItemDto::getUserId, UserItemDto::getItemCount));

allUsers.forEach(user -> {
var itemCount = itemCountMap.getOrDefault(user.getId(), 0);
updateUserLevel(user, itemCount, usersToUpdateLevel);
});
userRepository.saveAll(usersToUpdateLevel);
}

private void updateUserLevel(User user, Integer itemCount, List<User> usersToUpdateLevel) {
for (Map.Entry<Integer, LevelUpdatePolicy> entry : levelUpdatePolicies.entrySet()) {
LevelUpdatePolicy policy = entry.getValue();
if (policy.isAcceptable(itemCount)) {
user.changeLevel(policy.getNewLevel().getId());
popupService.createLevelUpPopup(user, policy.getNewLevel().getId());
usersToUpdateLevel.add(user);
break;
}
}
var itemUpdateUsers = itemRepository.findAllItemUpdateUser(LocalDateTime.now().minusMinutes(30)).stream().distinct().toList();
siyeonSon marked this conversation as resolved.
Show resolved Hide resolved

var userIds = itemUpdateUsers.stream().map(User::getId).toList();
List<UserItemCount> userItemDtoMap = itemRepository.countItemsByUserIdIn(userIds);


itemUpdateUsers.forEach(
user -> {
var userId = user.getId();
var itemCount = userItemDtoMap.stream()
.filter(dto -> dto.getUserId().equals(userId))
.map(UserItemCount::getItemCount)
.findFirst()
.orElse(null);
siyeonSon marked this conversation as resolved.
Show resolved Hide resolved

LevelPolicy newLevel = LevelUpdater.getUpdateLevel(itemCount);
if (newLevel.getLevel() > user.getUserLevel().getId()) {
user.changeLevel(newLevel.getLevel());
popupService.createLevelUpPopup(user, newLevel.getLevel());
}
}
);

userRepository.saveAll(itemUpdateUsers);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.depromeet.domains.level.data;
package com.depromeet.level.data;

import lombok.AllArgsConstructor;
import lombok.Getter;
Expand Down
Loading