Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Expand Up @@ -7,6 +7,9 @@
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;

@RestController
@RequiredArgsConstructor
public class TotalCommitController {
Expand All @@ -16,4 +19,41 @@ public class TotalCommitController {
public TotalCommitResponseDto getTotalCommits(@PathVariable String username) {
return totalCommitService.getTotalCommitCount(username);
}

// 봄 시즌(3/1 - 5/31)
@GetMapping("/api/commits/{username}/spring")
public TotalCommitResponseDto getSpringSeasonCommits(@PathVariable String username) {
int currentYear = LocalDateTime.now().getYear(); // 현재는 테스트용으로 2024 대입
LocalDateTime since = LocalDateTime.of(2024, 3, 1, 0, 0);
LocalDateTime until = LocalDateTime.of(2024, 5, 31, 23, 59, 59);
return totalCommitService.getSeasonCommits(username, since, until);
}

// 여름 시즌(6/1 - 8/31)
@GetMapping("/api/commits/{username}/summer")
public TotalCommitResponseDto getSummerSeasonCommits(@PathVariable String username) {
int currentYear = LocalDateTime.now().getYear(); // 현재는 테스트용으로 2024 대입
LocalDateTime since = LocalDateTime.of(2024, 6, 1, 0, 0);
LocalDateTime until = LocalDateTime.of(2024, 8, 31, 23, 59, 59);
return totalCommitService.getSeasonCommits(username, since, until);
}

// 가을 시즌(9/1 - 11/30)
@GetMapping("/api/commits/{username}/fall")
public TotalCommitResponseDto getFallSeasonCommits(@PathVariable String username) {
int currentYear = LocalDateTime.now().getYear(); // 현재는 테스트용으로 2024 대입
LocalDateTime since = LocalDateTime.of(2024, 9, 1, 0, 0);
LocalDateTime until = LocalDateTime.of(2024, 11, 30, 23, 59, 59);
return totalCommitService.getSeasonCommits(username, since, until);
}

// 겨울 시즌(이전 년도 12/1 - 다음 년도 2/28)
@GetMapping("/api/commits/{username}/winter")
public TotalCommitResponseDto getWinterSeasonCommits(@PathVariable String username) {
int currentYear = LocalDateTime.now().getYear(); // 현재는 테스트용으로 2024 대입
LocalDateTime since = LocalDateTime.of(2024 - 1, 12, 1, 0, 0);
LocalDateTime until = LocalDateTime.of(2024, 2, 1, 23, 59, 59)
.with(TemporalAdjusters.lastDayOfMonth());
return totalCommitService.getSeasonCommits(username, since, until);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.List;

/*
응답구조 토대로 구현
{
Expand Down Expand Up @@ -37,7 +39,28 @@ public static class CommitUser {
@Getter
@NoArgsConstructor
public static class ContributionsCollection {
private long totalCommitContributions;
private long restrictedContributionsCount;
private long totalCommitContributions; // 공개 레포 커밋
private long restrictedContributionsCount; // 비공개 레포 커밋
private ContributionCalendar contributionCalendar;
}

@Getter
@NoArgsConstructor
public static class ContributionCalendar {
private int totalContributions;
private List<Week> weeks;
}

@Getter
@NoArgsConstructor
public static class Week {
private List<ContributionDay> contributionDays;
}

@Getter
@NoArgsConstructor
public static class ContributionDay {
private int contributionCount;
private String date;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,21 @@

@Getter
@NoArgsConstructor
@AllArgsConstructor
public class TotalCommitResponseDto {
private long totalCommitContributions;
private long restrictedContributionsCount;
private int currentStreakDays;
private int maxStreakDays;

public TotalCommitResponseDto(long totalCommitContributions, long restrictedContributionsCount, int currentStreakDays, int maxStreakDays) {
this.totalCommitContributions = totalCommitContributions;
this.restrictedContributionsCount = restrictedContributionsCount;
this.currentStreakDays = currentStreakDays;
this.maxStreakDays = maxStreakDays;
}

public TotalCommitResponseDto(long totalCommitContributions, long restrictedContributionsCount) {
this.totalCommitContributions = totalCommitContributions;
this.restrictedContributionsCount = restrictedContributionsCount;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;


Expand All @@ -23,14 +29,11 @@ public class TotalCommitService {

private final WebClient webClient = WebClient.builder()
.baseUrl(BASE_URL)
.defaultHeader(HttpHeaders.CONTENT_TYPE , MediaType.APPLICATION_JSON_VALUE)
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();

// 기존 메서드
public TotalCommitResponseDto getTotalCommitCount(String username) {
// String query = String.format("""
// {"query": "query { user(login: \\\"%s\\\") { contributionsCollection { totalCommitContributions restrictedContributionsCount } } }"}
// """, username);
// GraphQL 쿼리를 Map으로 구성
Map<String, String> requestBody = Map.of(
"query", String.format(
"query { user(login: \"%s\") { contributionsCollection { totalCommitContributions restrictedContributionsCount } } }",
Expand All @@ -45,11 +48,110 @@ public TotalCommitResponseDto getTotalCommitCount(String username) {
.bodyToMono(TotalCommitGraphQLResponse.class)
.block();

TotalCommitGraphQLResponse.ContributionsCollection contributions = response.getData().getUser().getContributionsCollection();
TotalCommitGraphQLResponse.ContributionsCollection contributions =
response.getData().getUser().getContributionsCollection();

return new TotalCommitResponseDto(
contributions.getTotalCommitContributions(),
contributions.getRestrictedContributionsCount()
);
}

// 시즌별 커밋 분석
public TotalCommitResponseDto getSeasonCommits(String username, LocalDateTime since, LocalDateTime until) {
String query = String.format("""
query {
user(login: "%s") {
contributionsCollection(from: "%s", to: "%s") {
totalCommitContributions
restrictedContributionsCount
contributionCalendar {
totalContributions
weeks {
contributionDays {
contributionCount
date
}
}
}
}
}
}
""", username, since.format(DateTimeFormatter.ISO_DATE_TIME), until.format(DateTimeFormatter.ISO_DATE_TIME));

Map<String, String> requestBody = Map.of("query", query);

TotalCommitGraphQLResponse response = webClient.post()
.header("Authorization", "bearer " + PAT)
.bodyValue(requestBody)
.retrieve()
.bodyToMono(TotalCommitGraphQLResponse.class)
.block();

if (response == null || response.getData() == null || response.getData().getUser() == null) {
throw new RuntimeException("Failed to fetch GitHub data");
}

TotalCommitGraphQLResponse.ContributionsCollection contributions =
response.getData().getUser().getContributionsCollection();

List<LocalDate> commitDates = extractCommitDates(contributions.getContributionCalendar());
StreakResult streaks = calculateStreaks(commitDates);

return new TotalCommitResponseDto(
contributions.getTotalCommitContributions(),
contributions.getRestrictedContributionsCount(),
streaks.currentStreak,
streaks.maxStreak
);
}

private List<LocalDate> extractCommitDates(TotalCommitGraphQLResponse.ContributionCalendar calendar) {
List<LocalDate> dates = new ArrayList<>();
calendar.getWeeks().forEach(week ->
week.getContributionDays().forEach(day -> {
if (day.getContributionCount() > 0) {
dates.add(LocalDate.parse(day.getDate()));
}
})
);
return dates;
}

@RequiredArgsConstructor
private static class StreakResult {
final int currentStreak;
final int maxStreak;
}

private StreakResult calculateStreaks(List<LocalDate> commitDates) {
if (commitDates.isEmpty()) {
return new StreakResult(0, 0);
}

Collections.sort(commitDates);
int currentStreak = 0;
int maxStreak = 0;
int tempStreak = 0;
LocalDate previousDate = null;

for (LocalDate date : commitDates) {
if (previousDate == null || date.minusDays(1).equals(previousDate)) {
tempStreak++;
} else {
tempStreak = 1;
}
maxStreak = Math.max(maxStreak, tempStreak);
previousDate = date;
}

// 현재 스트릭 계산 (마지막 커밋이 오늘 또는 어제인 경우)
LocalDate today = LocalDate.now();
LocalDate lastCommitDate = commitDates.get(commitDates.size() - 1);
if (lastCommitDate.equals(today) || lastCommitDate.equals(today.minusDays(1))) {
currentStreak = tempStreak;
}

return new StreakResult(currentStreak, maxStreak);
}
}