Skip to content
Open
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 @@ -98,12 +98,13 @@ public ResponseEntity<ApiResponder<Empty>> createLeaderboard(
// BE VERY CAREFUL WITH THIS ROUTE. IT WILL DEACTIVATE THE PREVIOUS LEADERBOARD
// (however, it should be in a recoverable state, as it just gets toggled to be
// deactivated, not deleted).
Leaderboard currentLeaderboard = leaderboardRepository.getRecentLeaderboardMetadata();
if (currentLeaderboard != null) {
Optional<Leaderboard> currentLeaderboard = leaderboardRepository.getRecentLeaderboardMetadata();

currentLeaderboard.ifPresent(lb -> {
discordClubManager.sendLeaderboardCompletedDiscordMessageToAllClubs();
leaderboardManager.generateAchievementsForAllWinners();
leaderboardRepository.disableLeaderboardById(currentLeaderboard.getId());
}
leaderboardRepository.disableLeaderboardById(lb.getId());
});

OffsetDateTime shouldExpireBy = StandardizedOffsetDateTime.normalize(newLeaderboardBody.getShouldExpireBy());

Expand All @@ -117,8 +118,8 @@ public ResponseEntity<ApiResponder<Empty>> createLeaderboard(

Leaderboard newLeaderboard = Leaderboard.builder()
.name(name)
.shouldExpireBy(shouldExpireBy != null ? shouldExpireBy.toLocalDateTime() : null)
.syntaxHighlightingLanguage(newLeaderboardBody.getSyntaxHighlightingLanguage())
.shouldExpireBy(Optional.ofNullable(shouldExpireBy).map(d -> d.toLocalDateTime()))
.syntaxHighlightingLanguage(Optional.ofNullable(newLeaderboardBody.getSyntaxHighlightingLanguage()))
.build();

leaderboardRepository.addNewLeaderboard(newLeaderboard);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import net.dv8tion.jda.api.entities.Member;
import org.patinanetwork.codebloom.common.db.models.Session;
import org.patinanetwork.codebloom.common.db.models.discord.DiscordClubMetadata;
import org.patinanetwork.codebloom.common.db.models.leaderboard.Leaderboard;
import org.patinanetwork.codebloom.common.db.models.user.User;
import org.patinanetwork.codebloom.common.db.models.usertag.UserTag;
import org.patinanetwork.codebloom.common.db.repos.discord.club.DiscordClubRepository;
Expand Down Expand Up @@ -111,8 +110,9 @@ public void onAuthenticationSuccess(
.discordName(discordName)
.build();
userRepository.createUser(newUser);
Leaderboard leaderboard = leaderboardRepository.getRecentLeaderboardMetadata();
leaderboardRepository.addUserToLeaderboard(newUser.getId(), leaderboard.getId());
leaderboardRepository
.getRecentLeaderboardMetadata()
.ifPresent(lb -> leaderboardRepository.addUserToLeaderboard(newUser.getId(), lb.getId()));
existingUser = newUser;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Optional;
import org.patinanetwork.codebloom.common.components.LeaderboardManager;
import org.patinanetwork.codebloom.common.db.models.leaderboard.Leaderboard;
import org.patinanetwork.codebloom.common.db.models.user.UserWithScore;
Expand Down Expand Up @@ -72,15 +73,15 @@ public ResponseEntity<ApiResponder<LeaderboardDto>> getLeaderboardMetadataByLead
final @PathVariable String leaderboardId, final HttpServletRequest request) {
FakeLag.sleep(650);

Leaderboard leaderboardData = leaderboardManager.getLeaderboardMetadata(leaderboardId);
Optional<Leaderboard> leaderboardData = leaderboardManager.getLeaderboardMetadata(leaderboardId);

if (leaderboardData == null) {
if (leaderboardData.isEmpty()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Leaderboard cannot be found or does not exist.");
}

return ResponseEntity.ok()
.body(ApiResponder.success(
"Leaderboard metadata found!", LeaderboardDto.fromLeaderboard(leaderboardData)));
"Leaderboard metadata found!", LeaderboardDto.fromLeaderboard(leaderboardData.get())));
}

@GetMapping("/{leaderboardId}/user/all")
Expand Down Expand Up @@ -177,11 +178,19 @@ public ResponseEntity<ApiResponder<LeaderboardDto>> getCurrentLeaderboardMetadat
final HttpServletRequest request) {
FakeLag.sleep(650);

Leaderboard leaderboardData = leaderboardManager.getLeaderboardMetadata(
leaderboardRepository.getRecentLeaderboardMetadata().getId());
var current = leaderboardRepository
.getRecentLeaderboardMetadata()
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No active leaderboard found."));

Optional<Leaderboard> leaderboardData = leaderboardManager.getLeaderboardMetadata(current.getId());

if (leaderboardData.isEmpty()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Leaderboard cannot be found or does not exist.");
}

return ResponseEntity.ok()
.body(ApiResponder.success("All leaderboards found!", LeaderboardDto.fromLeaderboard(leaderboardData)));
.body(ApiResponder.success(
"All leaderboards found!", LeaderboardDto.fromLeaderboard(leaderboardData.get())));
}

@GetMapping("/current/user/all")
Expand Down Expand Up @@ -256,8 +265,10 @@ public ResponseEntity<ApiResponder<Page<Indexed<UserWithScoreDto>>>> getCurrentL
.mhcplusplus(mhcplusplus)
.build();

String currentLeaderboardId =
leaderboardRepository.getRecentLeaderboardMetadata().getId();
String currentLeaderboardId = leaderboardRepository
.getRecentLeaderboardMetadata()
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "No active leaderboard found."))
.getId();
Page<Indexed<UserWithScoreDto>> createdPage =
leaderboardManager.getLeaderboardUsers(currentLeaderboardId, options, globalIndex);

Expand All @@ -278,11 +289,17 @@ public ResponseEntity<ApiResponder<UserWithScoreDto>> getUserCurrentLeaderboardF
final HttpServletRequest request, @PathVariable final String userId) {
FakeLag.sleep(650);

Leaderboard leaderboardData = leaderboardRepository.getRecentLeaderboardMetadata();
Optional<Leaderboard> leaderboardData = leaderboardRepository.getRecentLeaderboardMetadata();

if (leaderboardData.isEmpty()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Active leaderboard could not be found.");
}

// we do not support point of time in this endpoint currently
UserWithScore user = userRepository.getUserWithScoreByIdAndLeaderboardId(
userId, leaderboardData.getId(), UserFilterOptions.builder().build());
userId,
leaderboardData.get().getId(),
UserFilterOptions.builder().build());

// if (user == null) {
// return
Expand Down Expand Up @@ -336,17 +353,20 @@ public ResponseEntity<ApiResponder<Indexed<UserWithScoreDto>>> getUserCurrentLea
AuthenticationObject authenticationObject = protector.validateSession(request);
String userId = authenticationObject.getUser().getId();

Leaderboard leaderboardData = leaderboardRepository.getRecentLeaderboardMetadata();
Optional<Leaderboard> leaderboardData = leaderboardRepository.getRecentLeaderboardMetadata();

if (leaderboardData == null) {
if (leaderboardData.isEmpty()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "No active leaderboard found.");
}

Indexed<UserWithScore> userWithRank;

if (!patina && !hunter && !nyu && !baruch && !rpi && !gwc && !sbu && !ccny && !columbia && !cornell && !bmcc) {
// Use global ranking when no filters are applied
userWithRank = leaderboardRepository.getGlobalRankedUserById(leaderboardData.getId(), userId);
userWithRank = leaderboardRepository
.getGlobalRankedUserById(leaderboardData.get().getId(), userId)
.orElseThrow(() -> new ResponseStatusException(
HttpStatus.NOT_FOUND, "User not found on the current leaderboard."));
} else {
// Use filtered ranking when filters are applied
LeaderboardFilterOptions options = LeaderboardFilterOptions.builder()
Expand All @@ -362,13 +382,11 @@ public ResponseEntity<ApiResponder<Indexed<UserWithScoreDto>>> getUserCurrentLea
.cornell(cornell)
.bmcc(bmcc)
.build();
userWithRank = leaderboardRepository.getFilteredRankedUserById(leaderboardData.getId(), userId, options);
}

if (userWithRank == null) {
throw new ResponseStatusException(
HttpStatus.NOT_FOUND,
"User not found on the current leaderboard or does not match the specified filters.");
userWithRank = leaderboardRepository
.getFilteredRankedUserById(leaderboardData.get().getId(), userId, options)
.orElseThrow(() -> new ResponseStatusException(
HttpStatus.NOT_FOUND,
"User not found on the current leaderboard or does not match the specified filters."));
}

Indexed<UserWithScoreDto> indexedUserWithScoreDto =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,20 @@ private String buildTopUsersSection(final List<UserWithScore> users, final boole
*/
private void sendLeaderboardCompletedDiscordMessage(final DiscordClub club) {
try {
Leaderboard currentLeaderboard = leaderboardRepository.getRecentLeaderboardMetadata();
Optional<Leaderboard> currentLeaderboard = leaderboardRepository.getRecentLeaderboardMetadata();

if (currentLeaderboard.isEmpty()) {
return;
}

LeaderboardFilterOptions options = LeaderboardFilterGenerator.builderWithTag(club.getTag())
.page(1)
.pageSize(5)
.build();

List<UserWithScore> users = LeaderboardUtils.filterUsersWithPoints(
leaderboardRepository.getLeaderboardUsersById(currentLeaderboard.getId(), options));
List<UserWithScore> users =
LeaderboardUtils.filterUsersWithPoints(leaderboardRepository.getLeaderboardUsersById(
currentLeaderboard.get().getId(), options));

String topUsersSection = buildTopUsersSection(users, true);
String headerText = users.isEmpty()
Expand Down Expand Up @@ -115,7 +120,7 @@ private void sendLeaderboardCompletedDiscordMessage(final DiscordClub club) {
topUsersSection,
club.getName(),
serverUrlUtils.getUrl(),
currentLeaderboard.getId(),
currentLeaderboard.get().getId(),
club.getTag().name().toLowerCase(),
serverUrlUtils.getUrl());

Expand All @@ -132,7 +137,7 @@ private void sendLeaderboardCompletedDiscordMessage(final DiscordClub club) {
.channelId(Long.valueOf(channelId.get()))
.description(description)
.title("🏆🏆🏆 %s - Final Leaderboard Score for %s"
.formatted(currentLeaderboard.getName(), club.getName()))
.formatted(currentLeaderboard.get().getName(), club.getName()))
.footerText("Codebloom - LeetCode Leaderboard for %s".formatted(club.getName()))
.footerIcon("%s/favicon.ico".formatted(serverUrlUtils.getUrl()))
.color(new Color(69, 129, 103))
Expand Down Expand Up @@ -204,24 +209,33 @@ public MessageCreateData buildLeaderboardMessageForClub(String guildId, boolean
DiscordClub club =
discordClubRepository.getDiscordClubByGuildId(guildId).orElseThrow();

Leaderboard currentLeaderboard = leaderboardRepository.getRecentLeaderboardMetadata();
Optional<Leaderboard> currentLeaderboard = leaderboardRepository.getRecentLeaderboardMetadata();

if (currentLeaderboard.isEmpty()) {
throw new RuntimeException("No recent leaderboard found.");
}

LeaderboardFilterOptions options = LeaderboardFilterGenerator.builderWithTag(club.getTag())
.page(1)
.pageSize(5)
.build();

List<UserWithScore> users = LeaderboardUtils.filterUsersWithPoints(
leaderboardRepository.getLeaderboardUsersById(currentLeaderboard.getId(), options));
List<UserWithScore> users =
LeaderboardUtils.filterUsersWithPoints(leaderboardRepository.getLeaderboardUsersById(
currentLeaderboard.get().getId(), options));

LocalDateTime shouldExpireByTime =
Optional.ofNullable(currentLeaderboard.getShouldExpireBy()).orElse(StandardizedLocalDateTime.now());
Optional<LocalDateTime> shouldExpireByTime = currentLeaderboard.get().getShouldExpireBy();

Duration remaining = Duration.between(StandardizedLocalDateTime.now(), shouldExpireByTime);
long daysLeft = 0;
long hoursLeft = 0;
long minutesLeft = 0;

long daysLeft = remaining.toDays();
long hoursLeft = remaining.toHours() % 24;
long minutesLeft = remaining.toMinutes() % 60;
if (shouldExpireByTime.isPresent()) {
Duration remaining = Duration.between(StandardizedLocalDateTime.now(), shouldExpireByTime.get());
daysLeft = remaining.toDays();
hoursLeft = remaining.toHours() % 24;
minutesLeft = remaining.toMinutes() % 60;
}

String topUsersSection = buildTopUsersSection(users, false);
String headerText = "Here is %s on the LeetCode leaderboard for our very own members!"
Expand Down Expand Up @@ -259,7 +273,7 @@ public MessageCreateData buildLeaderboardMessageForClub(String guildId, boolean

MessageEmbed embed = new EmbedBuilder()
.setTitle("%s - %s Leaderboard Update for %s"
.formatted(currentLeaderboard.getName(), isWeekly ? "Weekly" : "", club.getName()))
.formatted(currentLeaderboard.get().getName(), isWeekly ? "Weekly" : "", club.getName()))
.setDescription(description)
.setFooter(
"Codebloom - LeetCode Leaderboard for %s".formatted(club.getName()),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.patinanetwork.codebloom.common.components;

import java.util.List;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.patinanetwork.codebloom.common.db.models.achievements.Achievement;
import org.patinanetwork.codebloom.common.db.models.achievements.AchievementPlaceEnum;
Expand Down Expand Up @@ -49,9 +50,9 @@ private String calculatePlaceString(final int place) {

public void generateAchievementsForAllWinners() {
log.info("generating achievements for all winners...");
Leaderboard currentLeaderboard = leaderboardRepository.getRecentLeaderboardMetadata();
Optional<Leaderboard> currentLeaderboard = leaderboardRepository.getRecentLeaderboardMetadata();

if (currentLeaderboard == null) {
if (currentLeaderboard.isEmpty()) {
return;
}

Expand All @@ -61,7 +62,7 @@ public void generateAchievementsForAllWinners() {
for (var pair : filterOptsAndTags) {
log.info("on leaderboard for {}", pair.getRight().getResolvedName());
List<Indexed<UserWithScore>> users = leaderboardRepository.getRankedIndexedLeaderboardUsersById(
currentLeaderboard.getId(), pair.getLeft());
currentLeaderboard.get().getId(), pair.getLeft());
List<UserWithScore> usersWithPoints = LeaderboardUtils.filterUsersWithPoints(
users.stream().map(Indexed::getItem).toList());
List<UserWithScore> winners = usersWithPoints.subList(0, maxWinners(usersWithPoints.size()));
Expand All @@ -77,35 +78,41 @@ public void generateAchievementsForAllWinners() {
.leaderboard(pair.getRight())
.title(String.format(
"%s - %s - %s Place",
currentLeaderboard.getName(), pair.getRight().getResolvedName(), placeString))
currentLeaderboard.get().getName(),
pair.getRight().getResolvedName(),
placeString))
.build();
achievementRepository.createAchievement(achievement);
}
}

// handle global leaderboard
List<Indexed<UserWithScore>> users = leaderboardRepository.getGlobalRankedIndexedLeaderboardUsersById(
currentLeaderboard.getId(), LeaderboardFilterOptions.DEFAULT);
currentLeaderboard.get().getId(), LeaderboardFilterOptions.DEFAULT);
List<UserWithScore> usersWithPoints = LeaderboardUtils.filterUsersWithPoints(
users.stream().map(Indexed::getItem).toList());
List<UserWithScore> winners = usersWithPoints.subList(0, maxWinners(usersWithPoints.size()));

for (int i = 0; i < winners.size(); i++) {
int place = i + 1;
log.info("on leaderboard for {} for global winner #{}", currentLeaderboard.getName(), place);
log.info(
"on leaderboard for {} for global winner #{}",
currentLeaderboard.get().getName(),
place);
String placeString = calculatePlaceString(place);
UserWithScore user = winners.get(i);
Achievement achievement = Achievement.builder()
.userId(user.getId())
.place(AchievementPlaceEnum.fromInteger(place))
.leaderboard(null)
.title(String.format("%s - %s Place", currentLeaderboard.getName(), placeString))
.title(String.format(
"%s - %s Place", currentLeaderboard.get().getName(), placeString))
.build();
achievementRepository.createAchievement(achievement);
}
}

public Leaderboard getLeaderboardMetadata(final String id) {
public Optional<Leaderboard> getLeaderboardMetadata(final String id) {
return leaderboardRepository.getLeaderboardMetadataById(id);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package org.patinanetwork.codebloom.common.db.models.leaderboard;

import java.time.LocalDateTime;
import java.util.Optional;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.SuperBuilder;
import org.patinanetwork.codebloom.common.db.helper.annotations.NotNullColumn;
import org.patinanetwork.codebloom.common.db.helper.annotations.NullColumn;

@Getter
@Setter
Expand All @@ -16,21 +16,18 @@
@ToString
public class Leaderboard {

@NotNullColumn
private String id;

@NotNullColumn
private String name;

@NotNullColumn
private LocalDateTime createdAt;

@NullColumn
private LocalDateTime deletedAt;
@Builder.Default
private Optional<LocalDateTime> deletedAt = Optional.empty();

@NullColumn
private LocalDateTime shouldExpireBy;
@Builder.Default
private Optional<LocalDateTime> shouldExpireBy = Optional.empty();

@NullColumn
private String syntaxHighlightingLanguage;
@Builder.Default
private Optional<String> syntaxHighlightingLanguage = Optional.empty();
}
Loading
Loading