diff --git a/scripts/after-deploy.sh b/scripts/after-deploy.sh index f3b704d..40a8c4c 100755 --- a/scripts/after-deploy.sh +++ b/scripts/after-deploy.sh @@ -18,5 +18,7 @@ else sleep 5 fi +source ~/.bashrc + echo "> Deploy - $JAR_PATH " -nohup java -jar $JAR_PATH > /dev/null 2> /dev/null < /dev/null & \ No newline at end of file +nohup java -jar $JAR_PATH > commitato.log 2>&1 & \ No newline at end of file diff --git a/src/main/java/com/leets/commitatobe/domain/commit/domain/Commit.java b/src/main/java/com/leets/commitatobe/domain/commit/domain/Commit.java index 4e6adea..eab4431 100644 --- a/src/main/java/com/leets/commitatobe/domain/commit/domain/Commit.java +++ b/src/main/java/com/leets/commitatobe/domain/commit/domain/Commit.java @@ -8,6 +8,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; +import java.time.LocalDate; import java.time.LocalDateTime; import java.util.UUID; @@ -28,7 +29,7 @@ public class Commit extends BaseTimeEntity { private LocalDateTime commitDate; @ManyToOne - @JoinColumn(name="user_id") + @JoinColumn(name = "user_id") @JsonBackReference private User user; @@ -52,7 +53,23 @@ public Commit(LocalDateTime commitDate, Integer cnt, User user) { public void updateCnt(Integer cnt) { this.cnt = this.cnt + cnt; - this.isCalculated=false; + markAsUncalculated(); + } + + public void markAsCalculated() { + isCalculated = true; + } + + public void markAsUncalculated() { + isCalculated = false; + } + + public int calculateExp(int dailyBonusExp, int consecutiveDays, int bonusExpIncrease) { + int bonusExp = dailyBonusExp + consecutiveDays * bonusExpIncrease; + return this.cnt * 5 + bonusExp; + } + + public boolean commitDateIsToday() { + return this.commitDate.toLocalDate().isEqual(LocalDate.now()); } - public void updateStatusToCalculated(boolean calculated){isCalculated=calculated;}//isCalculated 필드 설정 } diff --git a/src/main/java/com/leets/commitatobe/domain/commit/domain/repository/CommitRepository.java b/src/main/java/com/leets/commitatobe/domain/commit/domain/repository/CommitRepository.java index 70eb16e..1489d3e 100644 --- a/src/main/java/com/leets/commitatobe/domain/commit/domain/repository/CommitRepository.java +++ b/src/main/java/com/leets/commitatobe/domain/commit/domain/repository/CommitRepository.java @@ -15,4 +15,4 @@ public interface CommitRepository extends JpaRepository { Optional findByCommitDateAndUser(LocalDateTime commitDate, User user); List findAllByUserOrderByCommitDateAsc(User user); -} \ No newline at end of file +} diff --git a/src/main/java/com/leets/commitatobe/domain/commit/presentation/CommitController.java b/src/main/java/com/leets/commitatobe/domain/commit/presentation/CommitController.java index a645cd0..960b330 100644 --- a/src/main/java/com/leets/commitatobe/domain/commit/presentation/CommitController.java +++ b/src/main/java/com/leets/commitatobe/domain/commit/presentation/CommitController.java @@ -28,9 +28,9 @@ public ApiResponse fetchCommits(HttpServletRequest request) { @Operation( summary = "커밋 기록 불러오기 (테스트)", - description = "commit/fetch가 정상적으로 실행이 될 동안 사용할 임시 API") + description = "테스트를 위해, 7월 1일부터 커밋 기록을 가져와 DB에 저장합니다.") @PostMapping("test/fetch") - public ApiResponse fetchCommits(HttpServletRequest request, @RequestHeader String accessToken) { - return ApiResponse.onSuccess(fetchCommitsTest.execute(request, accessToken)); + public ApiResponse fetchCommitsTest(HttpServletRequest request) { + return ApiResponse.onSuccess(fetchCommitsTest.execute(request)); } } diff --git a/src/main/java/com/leets/commitatobe/domain/commit/usecase/ExpService.java b/src/main/java/com/leets/commitatobe/domain/commit/usecase/ExpService.java index 33d73b1..86708e2 100644 --- a/src/main/java/com/leets/commitatobe/domain/commit/usecase/ExpService.java +++ b/src/main/java/com/leets/commitatobe/domain/commit/usecase/ExpService.java @@ -6,13 +6,14 @@ import com.leets.commitatobe.domain.tier.domain.repository.TierRepository; import com.leets.commitatobe.domain.user.domain.User; import com.leets.commitatobe.domain.user.domain.repository.UserRepository; +import com.leets.commitatobe.global.exception.ApiException; +import com.leets.commitatobe.global.response.code.status.ErrorStatus; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; -import java.time.LocalDate; import java.time.LocalDateTime; import java.util.Comparator; import java.util.List; @@ -25,46 +26,50 @@ public class ExpService { private final UserRepository userRepository; private final TierRepository tierRepository; - public void calculateAndSaveExp(String githubId){ - User user=userRepository.findByGithubId(githubId) - .orElseThrow(()->new UsernameNotFoundException("해당하는 깃허브 닉네임과 일치하는 유저를 찾을 수 없음: " +githubId)); - List commits=commitRepository.findAllByUserOrderByCommitDateAsc(user);//사용자의 모든 커밋을 날짜 오름차순으로 불러온다. + int DAILY_BONUS_EXP = 100; + int BONUS_EXP_INCREASE = 10; - int consecutiveDays=0;//연속 커밋 일수 - LocalDateTime lastCommitDate=null;//마지막 커밋 날짜 - int totalExp=user.getExp()!=null?user.getExp():0;//사용자의 현재 경험치, user.getExp()가 null인 경우 0으로 초기화 - int dailyBonusExp=100;//데일리 보너스 경험치 - int bonusExpIncrease=10;//보너스 경험치 증가량 - int totalCommitCount=0;//총 커밋 횟수 - int todayCommitCount=0;//오늘 커밋 횟수 + public void calculateAndSaveExp(String githubId) { + User user = userRepository.findByGithubId(githubId) + .orElseThrow(() -> new UsernameNotFoundException("해당하는 깃허브 닉네임과 일치하는 유저를 찾을 수 없음: " + githubId)); + List commits = commitRepository.findAllByUserOrderByCommitDateAsc(user); //사용자의 모든 커밋을 날짜 오름차순으로 불러온다. - LocalDate today=LocalDate.now();//오늘 날짜 + int consecutiveDays = user.getConsecutiveCommitDays(); //연속 커밋 일수 + LocalDateTime lastCommitDate = null; //마지막 커밋 날짜 + int totalExp = user.getExp(); //사용자의 현재 경험치 + int totalCommitCount = user.getTotalCommitCount(); //총 커밋 횟수 + int todayCommitCount = user.getTodayCommitCount(); //오늘 커밋 횟수 - for(Commit commit:commits){//각 커밋을 반복해서 계산 - if(commit.isCalculated()) continue;//이미 계산된 커밋 - LocalDateTime commitDate=commit.getCommitDate();//커밋날짜를 가져와 시간 설정 + for (Commit commit : commits) {//각 커밋을 반복해서 계산 + if (commit.isCalculated()) continue;//이미 계산된 커밋 + LocalDateTime commitDate = commit.getCommitDate();//커밋날짜를 가져와 시간 설정 - if(lastCommitDate != null && commitDate.isEqual(lastCommitDate.plusDays(1))){ + if (lastCommitDate != null && commitDate.isEqual(lastCommitDate.plusDays(1))) { // 마지막 커밋 날짜가 존재하고, 현재 커밋 날짜가 마지막 커밋 날짜의 다음 날과 같으면 연속 커밋으로 간주합니다. consecutiveDays++;//연속 커밋 일수 1 증가 + } else { + if (lastCommitDate == null) { // 연속 커밋 일수는 전날 커밋이 없을 경우에 초기화 + consecutiveDays = 0;//연속 커밋 일수 초기화 + } } - else{ - consecutiveDays=0;//연속 커밋 일수 초기화 - } - int commitExp=commit.getCnt()*5;//하루 커밋 경험치 - int bonusExp=dailyBonusExp+consecutiveDays*bonusExpIncrease;//보너스 경험치 계산 - totalExp+=commitExp+bonusExp;//총 경험치 업데이트 - totalCommitCount+=commit.getCnt();//총 커밋 횟수 - if(commitDate.toLocalDate().isEqual(today)){ - todayCommitCount=commit.getCnt();//오늘날짜의 커밋 개수 카운트 + totalExp += commit.calculateExp(DAILY_BONUS_EXP, consecutiveDays, BONUS_EXP_INCREASE);//총 경험치 업데이트 + totalCommitCount += commit.getCnt();//총 커밋 횟수 + + if (commit.commitDateIsToday()) { + todayCommitCount = commit.getCnt();//오늘날짜의 커밋 개수 카운트 } - commit.updateStatusToCalculated(true);//커밋 계산 여부를 true로 해서 다음 게산에서 제외 - lastCommitDate=commitDate;//마지막 커밋날짜를 현재 커밋날짜로 업데이트 + commit.markAsCalculated();//커밋 계산 여부를 true로 해서 다음 게산에서 제외 + lastCommitDate = commitDate;//마지막 커밋날짜를 현재 커밋날짜로 업데이트 + } + + if (lastCommitDate != null && lastCommitDate.isBefore(LocalDateTime.now().minusDays(1))) { + consecutiveDays = 0;//마지막 커밋날짜가 어제보다 이전이면 연속 커밋 일수 초기화 } + user.updateExp(totalExp);//사용자 경험치 업데이트 - Tier tier=determineTier(user.getExp());//경험치에 따른 티어 결정 + Tier tier = determineTier(user.getExp());//경험치에 따른 티어 결정 user.updateTier(tier); user.updateConsecutiveCommitDays(consecutiveDays); user.updateTotalCommitCount(totalCommitCount); @@ -85,11 +90,12 @@ public void calculateAndSaveExp(String githubId){ commitRepository.saveAll(commits);//변경된 커밋 정보 데이터베이스에 저장 userRepository.save(user);//변경된 사용자 정보 데이터베이스에 저장 } - private Tier determineTier(Integer exp){ + + private Tier determineTier(Integer exp) { return tierRepository.findAll() .stream() - .filter(tier->tier.getRequiredExp()!=null&&tier.getRequiredExp()<=exp) + .filter(tier -> tier.isValid(exp)) .max(Comparator.comparing(Tier::getRequiredExp)) - .orElseThrow(()->new RuntimeException("해당 경험치의 티어가 없음"+exp)); + .orElseThrow(() -> new ApiException(ErrorStatus._TIER_NOT_FOUND)); } } diff --git a/src/main/java/com/leets/commitatobe/domain/commit/usecase/FetchCommits.java b/src/main/java/com/leets/commitatobe/domain/commit/usecase/FetchCommits.java index 6c7d949..5ac7c7c 100644 --- a/src/main/java/com/leets/commitatobe/domain/commit/usecase/FetchCommits.java +++ b/src/main/java/com/leets/commitatobe/domain/commit/usecase/FetchCommits.java @@ -54,8 +54,7 @@ public CommitResponse execute(HttpServletRequest request) { // gitHubService.updateToken(loginCommandService.gitHubLogin(gitHubId)); //변경: DB에서 엑세스 토큰 불러오도록 방식 변경 - String gitHubaccessToken = userQueryService.getUserGitHubAccessToken(gitHubId); - gitHubService.updateToken(gitHubaccessToken); + gitHubService.updateToken(userQueryService.getUserGitHubAccessToken(gitHubId)); List repos = gitHubService.fetchRepos(gitHubId); ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); diff --git a/src/main/java/com/leets/commitatobe/domain/commit/usecase/FetchCommitsTest.java b/src/main/java/com/leets/commitatobe/domain/commit/usecase/FetchCommitsTest.java index d16f3ae..e8311fd 100644 --- a/src/main/java/com/leets/commitatobe/domain/commit/usecase/FetchCommitsTest.java +++ b/src/main/java/com/leets/commitatobe/domain/commit/usecase/FetchCommitsTest.java @@ -3,9 +3,11 @@ import com.leets.commitatobe.domain.commit.domain.Commit; import com.leets.commitatobe.domain.commit.domain.repository.CommitRepository; import com.leets.commitatobe.domain.commit.presentation.dto.response.CommitResponse; +import com.leets.commitatobe.domain.login.usecase.LoginCommandServiceImpl; import com.leets.commitatobe.domain.login.usecase.LoginQueryService; import com.leets.commitatobe.domain.user.domain.User; import com.leets.commitatobe.domain.user.domain.repository.UserRepository; +import com.leets.commitatobe.domain.user.usecase.UserQueryService; import com.leets.commitatobe.global.exception.ApiException; import com.leets.commitatobe.global.response.code.status.ErrorStatus; import com.leets.commitatobe.global.response.code.status.SuccessStatus; @@ -16,10 +18,7 @@ import java.io.IOException; import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -30,9 +29,12 @@ public class FetchCommitsTest { private final CommitRepository commitRepository; private final UserRepository userRepository; private final GitHubService gitHubService; // GitHub API 통신 + private final LoginCommandServiceImpl loginCommandService; private final LoginQueryService loginQueryService; + private final ExpService expService; + private final UserQueryService userQueryService; - public CommitResponse execute(HttpServletRequest request, String accessToken) { + public CommitResponse execute(HttpServletRequest request) { String gitHubId = loginQueryService.getGitHubId(request); User user = userRepository.findByGithubId(gitHubId) .orElseThrow(() -> new UsernameNotFoundException("해당하는 깃허브 닉네임과 일치하는 유저를 찾을 수 없음: " + gitHubId)); @@ -49,7 +51,7 @@ public CommitResponse execute(HttpServletRequest request, String accessToken) { try { // Github API Access Token 저장 - gitHubService.updateToken(accessToken); + gitHubService.updateToken(userQueryService.getUserGitHubAccessToken(gitHubId)); List repos = gitHubService.fetchRepos(gitHubId); ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); @@ -74,6 +76,8 @@ public CommitResponse execute(HttpServletRequest request, String accessToken) { saveCommits(user); + expService.calculateAndSaveExp(gitHubId);//커밋 가져온 후 경험치 계산 및 저장 + } catch (Exception e) { throw new RuntimeException(e); } diff --git a/src/main/java/com/leets/commitatobe/domain/commit/usecase/GitHubService.java b/src/main/java/com/leets/commitatobe/domain/commit/usecase/GitHubService.java index b7a2786..9aee329 100644 --- a/src/main/java/com/leets/commitatobe/domain/commit/usecase/GitHubService.java +++ b/src/main/java/com/leets/commitatobe/domain/commit/usecase/GitHubService.java @@ -31,7 +31,6 @@ public class GitHubService { private final Map commitsByDate = new HashMap<>(); @Value("${domain-uri}") private String DOMAIN_URI; - private String loginURL = DOMAIN_URI + "/login/github"; // GitHub repository 이름 저장 public List fetchRepos(String gitHubUsername) throws IOException { @@ -134,7 +133,7 @@ private HttpURLConnection getConnection(URL url) throws IOException { int responseCode = connection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) { // AUTH_TOKEN이 유효하지 않으면 리다이렉트 - URL loginUrl = new URL(loginURL); + URL loginUrl = new URL(DOMAIN_URI + "/login/github"); connection = (HttpURLConnection) loginUrl.openConnection(); connection.setInstanceFollowRedirects(true); connection.connect(); @@ -193,4 +192,4 @@ private String formatToISO8601(LocalDateTime dateTime) { public void updateToken(String accessToken) { this.AUTH_TOKEN = accessToken; } -} \ No newline at end of file +} diff --git a/src/main/java/com/leets/commitatobe/domain/login/domain/CustomUserDetails.java b/src/main/java/com/leets/commitatobe/domain/login/domain/CustomUserDetails.java index acd5cbb..a4b70e2 100644 --- a/src/main/java/com/leets/commitatobe/domain/login/domain/CustomUserDetails.java +++ b/src/main/java/com/leets/commitatobe/domain/login/domain/CustomUserDetails.java @@ -68,4 +68,3 @@ public GitHubDto getGitHubDto() { return new GitHubDto(this.githubId); } } - diff --git a/src/main/java/com/leets/commitatobe/domain/login/presentation/LoginController.java b/src/main/java/com/leets/commitatobe/domain/login/presentation/LoginController.java index eb92661..7b7ee1e 100644 --- a/src/main/java/com/leets/commitatobe/domain/login/presentation/LoginController.java +++ b/src/main/java/com/leets/commitatobe/domain/login/presentation/LoginController.java @@ -10,7 +10,6 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; @@ -74,5 +73,4 @@ public ApiResponse test(HttpServletRequest request) { log.info("깃허브 엑세스 토큰: {}", gitHubAccessToken); return ApiResponse.onSuccess(user); } - -} \ No newline at end of file +} diff --git a/src/main/java/com/leets/commitatobe/domain/login/usecase/CustomUserDetailsService.java b/src/main/java/com/leets/commitatobe/domain/login/usecase/CustomUserDetailsService.java index 2b77321..5a70c25 100644 --- a/src/main/java/com/leets/commitatobe/domain/login/usecase/CustomUserDetailsService.java +++ b/src/main/java/com/leets/commitatobe/domain/login/usecase/CustomUserDetailsService.java @@ -29,4 +29,3 @@ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundEx ); } } - diff --git a/src/main/java/com/leets/commitatobe/domain/login/usecase/LoginCommandServiceImpl.java b/src/main/java/com/leets/commitatobe/domain/login/usecase/LoginCommandServiceImpl.java index a1e4281..8c4e1e2 100644 --- a/src/main/java/com/leets/commitatobe/domain/login/usecase/LoginCommandServiceImpl.java +++ b/src/main/java/com/leets/commitatobe/domain/login/usecase/LoginCommandServiceImpl.java @@ -158,5 +158,3 @@ public String decrypt(String token) { return new String(decrypted, StandardCharsets.UTF_8); } } - - diff --git a/src/main/java/com/leets/commitatobe/domain/tier/domain/Tier.java b/src/main/java/com/leets/commitatobe/domain/tier/domain/Tier.java index 1ae858c..14c34fa 100644 --- a/src/main/java/com/leets/commitatobe/domain/tier/domain/Tier.java +++ b/src/main/java/com/leets/commitatobe/domain/tier/domain/Tier.java @@ -1,43 +1,28 @@ package com.leets.commitatobe.domain.tier.domain; -import com.leets.commitatobe.domain.user.domain.User; -import com.leets.commitatobe.global.shared.entity.BaseTimeEntity; import jakarta.persistence.*; -import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import java.util.List; import java.util.UUID; @Entity @Getter -@Builder @NoArgsConstructor -public class Tier extends BaseTimeEntity { +public class Tier { - @Id @GeneratedValue(strategy = GenerationType.UUID) + @Id + @GeneratedValue(strategy = GenerationType.UUID) @Column(name = "tier_id") private UUID id; private String tierName; private String characterUrl; - private String badgeUrl; @Column(nullable = false) private Integer requiredExp; - @OneToMany(mappedBy = "tier") - private List userList; - - public Tier(UUID id,String tierName, String characterUrl, String badgeUrl, Integer requiredExp, ListuserList){ - this.id=id; - this.tierName=tierName; - this.characterUrl=characterUrl; - this.badgeUrl=badgeUrl; - this.requiredExp=requiredExp; - this.userList=userList; + public boolean isValid(Integer exp) { + return this.getRequiredExp() != null && this.getRequiredExp() <= exp; } - } diff --git a/src/main/java/com/leets/commitatobe/domain/user/domain/User.java b/src/main/java/com/leets/commitatobe/domain/user/domain/User.java index 02170f6..99e7247 100644 --- a/src/main/java/com/leets/commitatobe/domain/user/domain/User.java +++ b/src/main/java/com/leets/commitatobe/domain/user/domain/User.java @@ -1,13 +1,10 @@ package com.leets.commitatobe.domain.user.domain; -import com.fasterxml.jackson.annotation.JsonManagedReference; -import com.leets.commitatobe.domain.commit.domain.Commit; import com.leets.commitatobe.domain.tier.domain.Tier; import com.leets.commitatobe.global.shared.entity.BaseTimeEntity; import jakarta.persistence.*; import lombok.*; -import java.util.List; import java.util.UUID; @Entity(name = "users") @@ -25,7 +22,7 @@ public class User extends BaseTimeEntity { @Column private String gitHubAccessToken; - @Column(nullable = true) + @Column private String username; @Column(nullable = false) @@ -38,48 +35,46 @@ public class User extends BaseTimeEntity { @Builder.Default private Integer exp = 0; - @Column - private Integer commitDays; - - @Column - private Integer consecutiveCommitDays; + @Column(nullable = false) + @Builder.Default + private Integer consecutiveCommitDays = 0; - @Column - private Integer totalCommitCount; + @Column(nullable = false) + @Builder.Default + private Integer totalCommitCount = 0; - @Column - private Integer todayCommitCount; + @Column(nullable = false) + @Builder.Default + private Integer todayCommitCount = 0; @Column private Integer ranking;// 랭킹 추가 - @OneToMany(mappedBy = "user") - @JsonManagedReference - private List commitList; - @ManyToOne - @JoinColumn(name="tier_id") + @JoinColumn(name = "tier_id") private Tier tier; - public void updateExp(Integer exp){ - this.exp=exp; + public void updateExp(Integer exp) { + this.exp = exp; } - public void updateTier(Tier tier){ - this.tier=tier; + public void updateTier(Tier tier) { + this.tier = tier; } - public void updateConsecutiveCommitDays(Integer consecutiveCommitDays){ - this.consecutiveCommitDays=consecutiveCommitDays; + public void updateConsecutiveCommitDays(Integer consecutiveCommitDays) { + this.consecutiveCommitDays = consecutiveCommitDays; } - public void updateTotalCommitCount(Integer totalCommitCount){ - this.totalCommitCount=totalCommitCount; + public void updateTotalCommitCount(Integer totalCommitCount) { + this.totalCommitCount = totalCommitCount; } - public void updateTodayCommitCount(Integer todayCommitCount){ - this.todayCommitCount=todayCommitCount; + public void updateTodayCommitCount(Integer todayCommitCount) { + this.todayCommitCount = todayCommitCount; } - public void updateRank(Integer ranking) { this.ranking = ranking; } + public void updateRank(Integer ranking) { + this.ranking = ranking; + } } diff --git a/src/main/java/com/leets/commitatobe/domain/user/domain/repository/UserRepository.java b/src/main/java/com/leets/commitatobe/domain/user/domain/repository/UserRepository.java index b688c95..ddaac92 100644 --- a/src/main/java/com/leets/commitatobe/domain/user/domain/repository/UserRepository.java +++ b/src/main/java/com/leets/commitatobe/domain/user/domain/repository/UserRepository.java @@ -2,7 +2,6 @@ import com.leets.commitatobe.domain.user.domain.User; -import java.util.List; import java.util.Optional; import org.springframework.data.domain.Page; @@ -17,4 +16,4 @@ public interface UserRepository extends JpaRepository { //경험치순으로 유저를 페이징하여 조회하는 메서드 Page findAllByOrderByExpDesc(Pageable pageable); -} \ No newline at end of file +} diff --git a/src/main/java/com/leets/commitatobe/domain/user/presentation/UserController.java b/src/main/java/com/leets/commitatobe/domain/user/presentation/UserController.java index 983a31b..f6e3e70 100644 --- a/src/main/java/com/leets/commitatobe/domain/user/presentation/UserController.java +++ b/src/main/java/com/leets/commitatobe/domain/user/presentation/UserController.java @@ -4,12 +4,9 @@ import com.leets.commitatobe.domain.user.presentation.dto.response.UserSearchResponse; import com.leets.commitatobe.domain.user.usecase.UserQueryService; import com.leets.commitatobe.global.response.ApiResponse; +import com.leets.commitatobe.global.response.CustomPageResponse; import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; -import org.springframework.data.web.PageableDefault; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -21,17 +18,23 @@ @RequestMapping("/user") public class UserController { private final UserQueryService userQueryService; + @Operation( summary = "유저 정보 검색", description = "깃허브 아이디로 검색합니다." ) @GetMapping("/search") - public ApiResponse searchUsers(@RequestParam("githubId")String githubId){ + public ApiResponse searchUsers(@RequestParam("githubId") String githubId) { return ApiResponse.onSuccess(userQueryService.searchUsersByGithubId(githubId)); } - @GetMapping("/ranking")//경험치 순으로 유저 정보 조회 엔드포인트 - public ApiResponse> getUsersByExp(@PageableDefault(size = 50,sort = "exp",direction = Sort.Direction.DESC) - Pageable pageable){//페이지네이션 설정(페이지:50, exp 내림차순) - return ApiResponse.onSuccess(userQueryService.getUsersByExp(pageable)); + + @Operation( + summary = "랭킹 조회", + description = "경험치 순으로 유저 정보를 조회합니다." + ) + @GetMapping("/ranking") + public ApiResponse> getUsersByExp(@RequestParam(name = "page") int page, + @RequestParam(name = "size") int size) { + return ApiResponse.onSuccess(userQueryService.getUsersOrderByExp(page, size)); } } diff --git a/src/main/java/com/leets/commitatobe/domain/user/presentation/dto/response/UserRankResponse.java b/src/main/java/com/leets/commitatobe/domain/user/presentation/dto/response/UserRankResponse.java index c84c79e..62f9792 100644 --- a/src/main/java/com/leets/commitatobe/domain/user/presentation/dto/response/UserRankResponse.java +++ b/src/main/java/com/leets/commitatobe/domain/user/presentation/dto/response/UserRankResponse.java @@ -1,7 +1,5 @@ package com.leets.commitatobe.domain.user.presentation.dto.response; -import java.util.UUID; - public record UserRankResponse( String username, Integer exp, diff --git a/src/main/java/com/leets/commitatobe/domain/user/presentation/dto/response/UserResponse.java b/src/main/java/com/leets/commitatobe/domain/user/presentation/dto/response/UserResponse.java index f8fa125..0228f60 100644 --- a/src/main/java/com/leets/commitatobe/domain/user/presentation/dto/response/UserResponse.java +++ b/src/main/java/com/leets/commitatobe/domain/user/presentation/dto/response/UserResponse.java @@ -12,4 +12,3 @@ public record GitHubAccessTokenResponse( String gitHubAccessToken ) {} } - diff --git a/src/main/java/com/leets/commitatobe/domain/user/presentation/dto/response/UserSearchResponse.java b/src/main/java/com/leets/commitatobe/domain/user/presentation/dto/response/UserSearchResponse.java index d5c5153..01bded6 100644 --- a/src/main/java/com/leets/commitatobe/domain/user/presentation/dto/response/UserSearchResponse.java +++ b/src/main/java/com/leets/commitatobe/domain/user/presentation/dto/response/UserSearchResponse.java @@ -5,9 +5,9 @@ public record UserSearchResponse( Integer exp, String tierName, String characterUrl, - String badgeUrl, Integer consecutiveCommitDays, Integer totalCommitCount, - Integer todayCommitCount + Integer todayCommitCount, + Integer ranking ) { } diff --git a/src/main/java/com/leets/commitatobe/domain/user/usecase/UserCommandService.java b/src/main/java/com/leets/commitatobe/domain/user/usecase/UserCommandService.java index eac0f51..904c243 100644 --- a/src/main/java/com/leets/commitatobe/domain/user/usecase/UserCommandService.java +++ b/src/main/java/com/leets/commitatobe/domain/user/usecase/UserCommandService.java @@ -1,4 +1,4 @@ package com.leets.commitatobe.domain.user.usecase; public interface UserCommandService { -} \ No newline at end of file +} diff --git a/src/main/java/com/leets/commitatobe/domain/user/usecase/UserCommandServiceImpl.java b/src/main/java/com/leets/commitatobe/domain/user/usecase/UserCommandServiceImpl.java index 24a9d42..a5e0f43 100644 --- a/src/main/java/com/leets/commitatobe/domain/user/usecase/UserCommandServiceImpl.java +++ b/src/main/java/com/leets/commitatobe/domain/user/usecase/UserCommandServiceImpl.java @@ -12,4 +12,4 @@ @Configuration public class UserCommandServiceImpl implements UserCommandService { -} \ No newline at end of file +} diff --git a/src/main/java/com/leets/commitatobe/domain/user/usecase/UserQueryService.java b/src/main/java/com/leets/commitatobe/domain/user/usecase/UserQueryService.java index b156883..774708f 100644 --- a/src/main/java/com/leets/commitatobe/domain/user/usecase/UserQueryService.java +++ b/src/main/java/com/leets/commitatobe/domain/user/usecase/UserQueryService.java @@ -3,11 +3,10 @@ import com.leets.commitatobe.domain.user.presentation.dto.response.UserRankResponse; import com.leets.commitatobe.domain.user.presentation.dto.response.UserSearchResponse; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; +import com.leets.commitatobe.global.response.CustomPageResponse; public interface UserQueryService { UserSearchResponse searchUsersByGithubId(String GithubId);//유저 이름으로 유저 정보를 검색하는 메서드 - Page getUsersByExp(Pageable pageable);//경험치 순으로 페이징된 유저 정보를 조회 + CustomPageResponse getUsersOrderByExp(int page, int size);//경험치 순으로 페이징된 유저 정보를 조회 String getUserGitHubAccessToken(String githubId); -} \ No newline at end of file +} diff --git a/src/main/java/com/leets/commitatobe/domain/user/usecase/UserQueryServiceImpl.java b/src/main/java/com/leets/commitatobe/domain/user/usecase/UserQueryServiceImpl.java index 76ece36..e750e60 100644 --- a/src/main/java/com/leets/commitatobe/domain/user/usecase/UserQueryServiceImpl.java +++ b/src/main/java/com/leets/commitatobe/domain/user/usecase/UserQueryServiceImpl.java @@ -1,6 +1,5 @@ package com.leets.commitatobe.domain.user.usecase; -import com.leets.commitatobe.domain.commit.usecase.ExpService; import com.leets.commitatobe.domain.login.usecase.LoginCommandService; import com.leets.commitatobe.domain.tier.domain.Tier; import com.leets.commitatobe.domain.user.domain.User; @@ -8,16 +7,15 @@ import com.leets.commitatobe.domain.user.presentation.dto.response.UserRankResponse; import com.leets.commitatobe.domain.user.presentation.dto.response.UserSearchResponse; import com.leets.commitatobe.global.exception.ApiException; +import com.leets.commitatobe.global.response.CustomPageResponse; import com.leets.commitatobe.global.response.code.status.ErrorStatus; -import com.leets.commitatobe.global.utils.JwtProvider; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Optional; - import static com.leets.commitatobe.global.response.code.status.ErrorStatus._USER_NOT_FOUND; @@ -26,36 +24,40 @@ @Transactional(readOnly = true) public class UserQueryServiceImpl implements UserQueryService { private final UserRepository userRepository; - private final ExpService expService; - private final JwtProvider jwtProvider; private final LoginCommandService loginCommandService; @Override @Transactional public UserSearchResponse searchUsersByGithubId(String githubId) {// 유저 이름으로 유저 정보 검색 - User user=userRepository.findByGithubId(githubId) - .orElseThrow(()->new ApiException(ErrorStatus._USER_NOT_FOUND)); - expService.calculateAndSaveExp(user.getGithubId()); - Tier tier=user.getTier(); + User user = userRepository.findByGithubId(githubId) + .orElseThrow(() -> new ApiException(ErrorStatus._USER_NOT_FOUND)); + + Tier tier = user.getTier(); + return new UserSearchResponse( user.getUsername(), user.getExp(), - tier!=null?tier.getTierName():"Unranked", - tier!=null?tier.getCharacterUrl():null, - tier!=null?tier.getBadgeUrl():null, + tier.getTierName(), + tier.getCharacterUrl(), user.getConsecutiveCommitDays(), user.getTotalCommitCount(), - user.getTodayCommitCount() + user.getTodayCommitCount(), + user.getRanking() ); } @Override - public Page getUsersByExp(Pageable pageable){//경험치 순으로 페이징된 유저 정보 조회 - Page userPage= userRepository.findAllByOrderByExpDesc(pageable); + public CustomPageResponse getUsersOrderByExp(int page, int size) {//경험치 순으로 페이징된 유저 정보 조회 + Pageable pageable = PageRequest.of(page, size); + Page userRankingPage = userRepository.findAllByOrderByExpDesc(pageable); + + if (userRankingPage.isEmpty()) { + return CustomPageResponse.from(Page.empty(pageable)); // 빈 페이지 반환 + } + + Page userRankResponses = userRankingPage.map(user -> { // 각 사용자의 경험치 최신화 및 UserRankResponse 변환 + Tier tier = user.getTier(); - return userPage.map(user->{// 각 사용자의 경험치 최신화 및 UserRankResponse 변환 - expService.calculateAndSaveExp(user.getGithubId());// 경험치 계산 및 저장 - Tier tier=user.getTier(); return new UserRankResponse( user.getUsername(), user.getExp(), @@ -63,19 +65,16 @@ public Page getUsersByExp(Pageable pageable){//경험치 순 tier!=null?tier.getTierName():"Unranked", user.getRanking());//랭킹 추가 }); + + return CustomPageResponse.from(userRankResponses); } @Override public String getUserGitHubAccessToken(String githubId) { - User user=userRepository.findByGithubId(githubId).orElseThrow(()->new ApiException(_USER_NOT_FOUND)); + User user = userRepository.findByGithubId(githubId).orElseThrow(() -> new ApiException(_USER_NOT_FOUND)); String gitHubAccessToken = user.getGitHubAccessToken(); - String decodedGitHubAccessToken = loginCommandService.decrypt(gitHubAccessToken); - - return decodedGitHubAccessToken; + return loginCommandService.decrypt(gitHubAccessToken); } - - - -} \ No newline at end of file +} diff --git a/src/main/java/com/leets/commitatobe/global/config/CustomOAuth2UserService.java b/src/main/java/com/leets/commitatobe/global/config/CustomOAuth2UserService.java index d6a78e3..2e30e56 100644 --- a/src/main/java/com/leets/commitatobe/global/config/CustomOAuth2UserService.java +++ b/src/main/java/com/leets/commitatobe/global/config/CustomOAuth2UserService.java @@ -106,11 +106,10 @@ public User createNewUser(OAuth2User oAuth2User, String refreshToken, String git .githubId(githubId) .username(username) .profileImage(profileImage) + .exp(0) .gitHubAccessToken(encryptedGitHubAccessToken) .build(); - User savedUser = userRepository.save(user); - - return savedUser; + return userRepository.save(user); } } \ No newline at end of file diff --git a/src/main/java/com/leets/commitatobe/global/config/SecurityConfig.java b/src/main/java/com/leets/commitatobe/global/config/SecurityConfig.java index 2b533ff..e5c5b82 100644 --- a/src/main/java/com/leets/commitatobe/global/config/SecurityConfig.java +++ b/src/main/java/com/leets/commitatobe/global/config/SecurityConfig.java @@ -3,6 +3,7 @@ import com.leets.commitatobe.global.filter.JwtAuthenticationFilter; import com.leets.commitatobe.global.utils.JwtProvider; import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -23,6 +24,8 @@ @EnableWebSecurity @RequiredArgsConstructor public class SecurityConfig { + @Value("${domain.uri}") + private String DOMAIN_URI; private final JwtProvider jwtProvider; @Bean @@ -56,7 +59,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { @Bean CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); - configuration.setAllowedOrigins(Arrays.asList("http://localhost:8080", "http://localhost:3000")); + configuration.setAllowedOrigins(Arrays.asList("http://localhost:8080", "http://localhost:3000", "http://localhost:5173", DOMAIN_URI)); configuration.setAllowedMethods(Arrays.asList("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS")); configuration.setAllowCredentials(true); configuration.setAllowedHeaders(List.of("*")); @@ -65,4 +68,4 @@ CorsConfigurationSource corsConfigurationSource() { source.registerCorsConfiguration("/**", configuration); return source; } -} \ No newline at end of file +} diff --git a/src/main/java/com/leets/commitatobe/global/response/CustomPageResponse.java b/src/main/java/com/leets/commitatobe/global/response/CustomPageResponse.java new file mode 100644 index 0000000..02ba894 --- /dev/null +++ b/src/main/java/com/leets/commitatobe/global/response/CustomPageResponse.java @@ -0,0 +1,30 @@ +package com.leets.commitatobe.global.response; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.springframework.data.domain.Page; + +import java.util.List; + +public record CustomPageResponse( + @JsonProperty("content") List content, + @JsonProperty("isFirst") boolean isFirst, + @JsonProperty("isLast") boolean isLast, + @JsonProperty("totalPage") int totalPage, + @JsonProperty("totalElements") long totalElements, + @JsonProperty("size") int size, + @JsonProperty("currPage") int currPage, + @JsonProperty("hasNext") boolean hasNext +) { + public static CustomPageResponse from(Page page) { + return new CustomPageResponse<>( + page.getContent(), + page.isFirst(), + page.isLast(), + page.getTotalPages(), + page.getTotalElements(), + page.getSize(), + page.getNumber(), + page.hasNext() + ); + } +} diff --git a/src/main/java/com/leets/commitatobe/global/response/code/status/ErrorStatus.java b/src/main/java/com/leets/commitatobe/global/response/code/status/ErrorStatus.java index db4b16b..eaf0e47 100644 --- a/src/main/java/com/leets/commitatobe/global/response/code/status/ErrorStatus.java +++ b/src/main/java/com/leets/commitatobe/global/response/code/status/ErrorStatus.java @@ -40,8 +40,11 @@ public enum ErrorStatus implements BaseErrorCode { // 디코딩 오류 _DECRYPT_ERROR(HttpStatus.BAD_REQUEST, "DECRYPT_001", "토큰 디코딩 과정에서 오류가 발생했습니다."), - //검색 기능 관련 - _USER_NOT_FOUND(HttpStatus.NOT_FOUND,"USER_001","해당 유저가 존재하지 않습니다"); + // 검색 기능 관련 + _USER_NOT_FOUND(HttpStatus.NOT_FOUND, "USER_001", "해당 유저가 존재하지 않습니다"), + + // 티어 관련 + _TIER_NOT_FOUND(HttpStatus.NOT_FOUND, "TIER_001", "해당 경험치에 맞는 티어를 찾을 수 없습니다."); private final HttpStatus httpStatus; private final String code; @@ -51,19 +54,19 @@ public enum ErrorStatus implements BaseErrorCode { @Override public ErrorReasonDto getReason() { return ErrorReasonDto.builder() - .isSuccess(false) - .code(code) - .message(message) - .build(); + .isSuccess(false) + .code(code) + .message(message) + .build(); } @Override public ErrorReasonDto getReasonHttpStatus() { return ErrorReasonDto.builder() - .httpStatus(httpStatus) - .isSuccess(false) - .code(code) - .message(message) - .build(); + .httpStatus(httpStatus) + .isSuccess(false) + .code(code) + .message(message) + .build(); } -} \ No newline at end of file +} diff --git a/src/main/resources/application-dev.yaml b/src/main/resources/application-dev.yaml index edf6901..e0a1b6c 100644 --- a/src/main/resources/application-dev.yaml +++ b/src/main/resources/application-dev.yaml @@ -10,12 +10,16 @@ spring: jpa: show-sql: true hibernate: - ddl-auto: create + ddl-auto: update database: mysql database-platform: org.hibernate.dialect.MySQLDialect properties: hibernate: format_sql: true + defer-datasource-initialization: true + sql: + init: + mode: always security: oauth2: client: diff --git a/src/main/resources/application-local.yaml b/src/main/resources/application-local.yaml index fac1624..3ebf795 100644 --- a/src/main/resources/application-local.yaml +++ b/src/main/resources/application-local.yaml @@ -7,12 +7,16 @@ spring: jpa: show-sql: true hibernate: - ddl-auto: update + ddl-auto: create-drop database: mysql database-platform: org.hibernate.dialect.MySQLDialect properties: hibernate: format_sql: true + defer-datasource-initialization: true + sql: + init: + mode: always security: oauth2: client: diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql new file mode 100644 index 0000000..0b80520 --- /dev/null +++ b/src/main/resources/data.sql @@ -0,0 +1,5 @@ +INSERT INTO tier (tier_id, tier_name, character_url, required_exp) +VALUES (UNHEX(REPLACE(UUID(), '-', '')), '바보 감자', 'https://d1ds22ndweg1nu.cloudfront.net/potato/stupidPotato.png', 0), + (UNHEX(REPLACE(UUID(), '-', '')), '말하는 감자', 'https://d1ds22ndweg1nu.cloudfront.net/potato/speakingPotato.png', 1000), + (UNHEX(REPLACE(UUID(), '-', '')), '개발자 감자', 'https://d1ds22ndweg1nu.cloudfront.net/potato/developerPotato.png', 15000), + (UNHEX(REPLACE(UUID(), '-', '')), 'CEO 감자', 'https://d1ds22ndweg1nu.cloudfront.net/potato/CEOPotato.png', 33000);