Skip to content

Commit 5cf784e

Browse files
refactor(application-server): remove Kotlin Support / Conversion back to Java (#509)
Co-authored-by: Felix T.J. Dietrich <felix_dietrich@gmx.de>
1 parent 0baa563 commit 5cf784e

16 files changed

Lines changed: 809 additions & 789 deletions

server/application-server/pom.xml

Lines changed: 0 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@
3030
</scm>
3131
<properties>
3232
<java.version>21</java.version>
33-
<!-- Kotlin Support -->
34-
<kotlin.version>1.9.25</kotlin.version>
3533
<app.profiles>local,dev</app.profiles>
3634

3735
<!-- Test Configuration -->
@@ -322,21 +320,6 @@
322320
<artifactId>langfuse-java</artifactId>
323321
<version>0.0.6</version>
324322
</dependency>
325-
<!-- Kotlin Dependencies -->
326-
<dependency>
327-
<groupId>org.jetbrains.kotlin</groupId>
328-
<artifactId>kotlin-stdlib-jdk8</artifactId>
329-
<version>${kotlin.version}</version>
330-
</dependency>
331-
<dependency>
332-
<groupId>org.jetbrains.kotlin</groupId>
333-
<artifactId>kotlin-reflect</artifactId>
334-
<version>${kotlin.version}</version>
335-
</dependency>
336-
<dependency>
337-
<groupId>com.fasterxml.jackson.module</groupId>
338-
<artifactId>jackson-module-kotlin</artifactId>
339-
</dependency>
340323
</dependencies>
341324
<dependencyManagement>
342325
<dependencies>
@@ -548,56 +531,6 @@
548531
</dependency>
549532
</dependencies>
550533
</plugin>
551-
552-
<!-- Kotlin Support -->
553-
<plugin>
554-
<groupId>org.jetbrains.kotlin</groupId>
555-
<artifactId>kotlin-maven-plugin</artifactId>
556-
<version>${kotlin.version}</version>
557-
<configuration>
558-
<jvmTarget>${java.version}</jvmTarget>
559-
<args>
560-
<arg>-Xjsr305=strict</arg>
561-
</args>
562-
<compilerPlugins>
563-
<plugin>spring</plugin>
564-
<plugin>jpa</plugin>
565-
<plugin>lombok</plugin>
566-
</compilerPlugins>
567-
</configuration>
568-
<dependencies>
569-
<dependency>
570-
<groupId>org.jetbrains.kotlin</groupId>
571-
<artifactId>kotlin-maven-allopen</artifactId>
572-
<version>${kotlin.version}</version>
573-
</dependency>
574-
<dependency>
575-
<groupId>org.jetbrains.kotlin</groupId>
576-
<artifactId>kotlin-maven-noarg</artifactId>
577-
<version>${kotlin.version}</version>
578-
</dependency>
579-
<dependency>
580-
<groupId>org.jetbrains.kotlin</groupId>
581-
<artifactId>kotlin-maven-lombok</artifactId>
582-
<version>${kotlin.version}</version>
583-
</dependency>
584-
</dependencies>
585-
<executions>
586-
<execution>
587-
<id>compile</id>
588-
<phase>process-sources</phase>
589-
<goals>
590-
<goal>compile</goal>
591-
</goals>
592-
</execution>
593-
<execution>
594-
<id>test-compile</id>
595-
<goals>
596-
<goal>test-compile</goal>
597-
</goals>
598-
</execution>
599-
</executions>
600-
</plugin>
601534
</plugins>
602535
</build>
603536
</project>
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package de.tum.in.www1.hephaestus.leaderboard;
2+
3+
import de.tum.in.www1.hephaestus.gitprovider.pullrequest.PullRequest;
4+
import de.tum.in.www1.hephaestus.gitprovider.user.User;
5+
import java.time.Instant;
6+
import java.util.Objects;
7+
import org.slf4j.Logger;
8+
import org.slf4j.LoggerFactory;
9+
import org.springframework.context.annotation.Primary;
10+
import org.springframework.stereotype.Service;
11+
12+
@Service
13+
@Primary
14+
public class DefaultLeaguePointsCalculationService implements LeaguePointsCalculationService {
15+
16+
private static final Logger logger = LoggerFactory.getLogger(DefaultLeaguePointsCalculationService.class);
17+
18+
private static final int DEFAULT_POINTS = LeaguePointsCalculationService.POINTS_DEFAULT;
19+
private static final int POINTS_THRESHOLD_HIGH = LeaguePointsCalculationService.POINTS_THRESHOLD_HIGH;
20+
private static final int POINTS_THRESHOLD_LOW = LeaguePointsCalculationService.POINTS_THRESHOLD_LOW;
21+
private static final int DECAY_MINIMUM = LeaguePointsCalculationService.DECAY_MINIMUM;
22+
private static final double DECAY_FACTOR = LeaguePointsCalculationService.DECAY_FACTOR;
23+
private static final double K_FACTOR_NEW_PLAYER = LeaguePointsCalculationService.K_FACTOR_NEW_PLAYER;
24+
private static final double K_FACTOR_LOW_POINTS = LeaguePointsCalculationService.K_FACTOR_LOW_POINTS;
25+
private static final double K_FACTOR_MEDIUM_POINTS = LeaguePointsCalculationService.K_FACTOR_MEDIUM_POINTS;
26+
private static final double K_FACTOR_HIGH_POINTS = LeaguePointsCalculationService.K_FACTOR_HIGH_POINTS;
27+
28+
@Override
29+
public int calculateNewPoints(User user, LeaderboardEntryDTO entry) {
30+
Objects.requireNonNull(user, "user must not be null");
31+
Objects.requireNonNull(entry, "entry must not be null");
32+
33+
int storedPoints = user.getLeaguePoints();
34+
int effectivePoints = storedPoints == 0 ? DEFAULT_POINTS : storedPoints;
35+
double kFactor = getKFactor(user, effectivePoints);
36+
int decay = calculateDecay(effectivePoints);
37+
int performanceBonus = calculatePerformanceBonus(entry.score());
38+
int placementBonus = calculatePlacementBonus(entry.rank());
39+
int pointChange = (int) (kFactor * (performanceBonus + placementBonus - decay));
40+
int newPoints = Math.max(1, effectivePoints + pointChange);
41+
42+
logger.info(
43+
"Points calculation: old={}, k={}, decay={}, performanceBonus={}, placement={}, pointchange={}, new={}",
44+
effectivePoints,
45+
kFactor,
46+
decay,
47+
performanceBonus,
48+
placementBonus,
49+
pointChange,
50+
newPoints
51+
);
52+
53+
return newPoints;
54+
}
55+
56+
private double getKFactor(User user, int currentPoints) {
57+
if (isNewPlayer(user)) {
58+
return K_FACTOR_NEW_PLAYER;
59+
}
60+
if (currentPoints < POINTS_THRESHOLD_LOW) {
61+
return K_FACTOR_LOW_POINTS;
62+
}
63+
if (currentPoints < POINTS_THRESHOLD_HIGH) {
64+
return K_FACTOR_MEDIUM_POINTS;
65+
}
66+
return K_FACTOR_HIGH_POINTS;
67+
}
68+
69+
private boolean isNewPlayer(User user) {
70+
Instant thirtyDaysAgo = Instant.now().minusSeconds(30L * 24 * 60 * 60);
71+
return user.getMergedPullRequests()
72+
.stream()
73+
.filter(Objects::nonNull)
74+
.filter(PullRequest::isMerged)
75+
.map(PullRequest::getMergedAt)
76+
.filter(Objects::nonNull)
77+
.noneMatch(mergedAt -> mergedAt.isBefore(thirtyDaysAgo));
78+
}
79+
80+
private int calculateDecay(int currentPoints) {
81+
if (currentPoints > 0) {
82+
return Math.max(DECAY_MINIMUM, (int) (currentPoints * DECAY_FACTOR));
83+
}
84+
return 0;
85+
}
86+
87+
private int calculatePerformanceBonus(int score) {
88+
return (int) (Math.sqrt((double) score) * 10);
89+
}
90+
91+
private int calculatePlacementBonus(int placement) {
92+
if (placement <= 3) {
93+
return 20 * (4 - placement);
94+
}
95+
return 0;
96+
}
97+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package de.tum.in.www1.hephaestus.leaderboard;
2+
3+
import io.swagger.v3.oas.annotations.Parameter;
4+
import jakarta.validation.constraints.NotBlank;
5+
import org.slf4j.Logger;
6+
import org.slf4j.LoggerFactory;
7+
import org.springframework.format.annotation.DateTimeFormat;
8+
import org.springframework.http.ResponseEntity;
9+
import org.springframework.web.bind.annotation.*;
10+
11+
import java.time.Instant;
12+
import java.util.List;
13+
14+
@RestController
15+
@RequestMapping("/leaderboard")
16+
public class LeaderboardController {
17+
18+
private static final Logger logger = LoggerFactory.getLogger(LeaderboardController.class);
19+
20+
private final LeaderboardService leaderboardService;
21+
22+
public LeaderboardController(LeaderboardService leaderboardService) {
23+
this.leaderboardService = leaderboardService;
24+
}
25+
26+
@GetMapping
27+
public ResponseEntity<List<LeaderboardEntryDTO>> getLeaderboard(
28+
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) Instant after,
29+
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) Instant before,
30+
@Parameter(description = "Team filter to apply in INDIVIDUAL mode; ignored when mode is TEAM.")
31+
@RequestParam @NotBlank String team,
32+
@Parameter(description = "Determines the ranking metric. In TEAM mode SCORE uses summed contribution scores; LEAGUE_POINTS uses total league points.")
33+
@RequestParam LeaderboardSortType sort,
34+
@RequestParam LeaderboardMode mode
35+
) {
36+
return ResponseEntity.ok(leaderboardService.createLeaderboard(after, before, team, sort, mode));
37+
}
38+
39+
@PostMapping
40+
public ResponseEntity<LeagueChangeDTO> getUserLeagueStats(
41+
@RequestParam String login,
42+
@RequestBody LeaderboardEntryDTO entry
43+
) {
44+
return ResponseEntity.ok(leaderboardService.getUserLeagueStats(login, entry));
45+
}
46+
}

server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/LeaderboardController.kt

Lines changed: 0 additions & 40 deletions
This file was deleted.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package de.tum.in.www1.hephaestus.leaderboard;
2+
3+
import com.fasterxml.jackson.annotation.JsonInclude;
4+
import de.tum.in.www1.hephaestus.gitprovider.pullrequest.PullRequestInfoDTO;
5+
import de.tum.in.www1.hephaestus.gitprovider.team.TeamInfoDTO;
6+
import de.tum.in.www1.hephaestus.gitprovider.user.UserInfoDTO;
7+
import io.swagger.v3.oas.annotations.media.Schema;
8+
import java.util.List;
9+
import org.springframework.lang.NonNull;
10+
11+
@JsonInclude(JsonInclude.Include.NON_NULL)
12+
public record LeaderboardEntryDTO(
13+
@NonNull Integer rank,
14+
@NonNull Integer score,
15+
UserInfoDTO user,
16+
TeamInfoDTO team,
17+
@NonNull List<PullRequestInfoDTO> reviewedPullRequests,
18+
@NonNull Integer numberOfReviewedPRs,
19+
@NonNull Integer numberOfApprovals,
20+
@NonNull Integer numberOfChangeRequests,
21+
@NonNull Integer numberOfComments,
22+
@NonNull Integer numberOfUnknowns,
23+
@NonNull Integer numberOfCodeComments
24+
) {}

server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/LeaderboardEntryDTO.kt

Lines changed: 0 additions & 21 deletions
This file was deleted.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package de.tum.in.www1.hephaestus.leaderboard;
2+
3+
public enum LeaderboardMode {
4+
INDIVIDUAL,
5+
TEAM,
6+
}

server/application-server/src/main/java/de/tum/in/www1/hephaestus/leaderboard/LeaderboardMode.kt

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)