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 @@ -12,11 +12,16 @@
import org.patinanetwork.codebloom.common.db.models.discord.DiscordClub;
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.user.UserWithScore;
import org.patinanetwork.codebloom.common.db.repos.discord.club.DiscordClubRepository;
import org.patinanetwork.codebloom.common.db.repos.leaderboard.LeaderboardRepository;
import org.patinanetwork.codebloom.common.db.repos.leaderboard.options.LeaderboardFilterGenerator;
import org.patinanetwork.codebloom.common.db.repos.leaderboard.options.LeaderboardFilterOptions;
import org.patinanetwork.codebloom.common.db.repos.user.UserRepository;
import org.patinanetwork.codebloom.common.db.repos.user.options.UserFilterOptions;
import org.patinanetwork.codebloom.common.dto.refresh.RefreshResultDto;
import org.patinanetwork.codebloom.common.page.Indexed;
import org.patinanetwork.codebloom.common.time.StandardizedLocalDateTime;
import org.patinanetwork.codebloom.common.url.ServerUrlUtils;
import org.patinanetwork.codebloom.common.utils.leaderboard.LeaderboardUtils;
Expand All @@ -31,17 +36,23 @@ public class DiscordClubManager {
private final JDAClient jdaClient;
private final LeaderboardRepository leaderboardRepository;
private final DiscordClubRepository discordClubRepository;
private final UserRepository userRepository;
private final ServerUrlUtils serverUrlUtils;
private final LeaderboardManager leaderboardManager;

public DiscordClubManager(
final ServerUrlUtils serverUrlUtils,
final JDAClient jdaClient,
final LeaderboardRepository leaderboardRepository,
final DiscordClubRepository discordClubRepository) {
final DiscordClubRepository discordClubRepository,
final UserRepository userRepository,
final LeaderboardManager leaderboardManager) {
this.serverUrlUtils = serverUrlUtils;
this.jdaClient = jdaClient;
this.leaderboardRepository = leaderboardRepository;
this.discordClubRepository = discordClubRepository;
this.userRepository = userRepository;
this.leaderboardManager = leaderboardManager;
}

private static final String[] MEDAL_EMOJIS = {"🥇", "🥈", "🥉"};
Expand Down Expand Up @@ -270,6 +281,37 @@ public MessageCreateData buildLeaderboardMessageForClub(String guildId, boolean
return MessageCreateData.fromEmbeds(embed);
}

public RefreshResultDto refreshSubmissions(String guildId, String discordId) throws LeaderboardException {
DiscordClub club = discordClubRepository
.getDiscordClubByGuildId(guildId)
.orElseThrow(() -> new LeaderboardException("Club does not exist", "This club does not exist!"));

User user = leaderboardManager.refreshUserSubmissions(discordId);
Leaderboard currentLeaderboard = leaderboardRepository.getRecentLeaderboardMetadata();

LeaderboardFilterOptions options =
LeaderboardFilterGenerator.builderWithTag(club.getTag()).build();

String userId = user.getId();

UserWithScore scoredUser = userRepository.getUserWithScoreByIdAndLeaderboardId(
userId, currentLeaderboard.getId(), UserFilterOptions.DEFAULT);

int score = scoredUser.getTotalScore();
Indexed<UserWithScore> globalIndex =
leaderboardRepository.getGlobalRankedUserById(currentLeaderboard.getId(), userId);
Indexed<UserWithScore> clubIndex =
leaderboardRepository.getFilteredRankedUserById(currentLeaderboard.getId(), userId, options);

return RefreshResultDto.builder()
.score(score)
.globalRank(globalIndex.getIndex())
.clubRank(clubIndex.getIndex())
.leaderboardName(currentLeaderboard.getName())
.clubName(club.getName())
.build();
}

public boolean sendTestEmbedMessageToClub(DiscordClub club) {
try {
String description = """
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.patinanetwork.codebloom.common.components;

import lombok.Getter;

@Getter
public class LeaderboardException extends Exception {
private final String title;
private final String description;

public LeaderboardException(Throwable t) {
this("Something went wrong!", t.getMessage());
}

public LeaderboardException(String title, String description) {
this.title = title;
this.description = description;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,20 @@
import org.patinanetwork.codebloom.common.db.models.achievements.Achievement;
import org.patinanetwork.codebloom.common.db.models.achievements.AchievementPlaceEnum;
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.user.UserWithScore;
import org.patinanetwork.codebloom.common.db.models.usertag.Tag;
import org.patinanetwork.codebloom.common.db.repos.achievements.AchievementRepository;
import org.patinanetwork.codebloom.common.db.repos.leaderboard.LeaderboardRepository;
import org.patinanetwork.codebloom.common.db.repos.leaderboard.options.LeaderboardFilterGenerator;
import org.patinanetwork.codebloom.common.db.repos.leaderboard.options.LeaderboardFilterOptions;
import org.patinanetwork.codebloom.common.db.repos.user.UserRepository;
import org.patinanetwork.codebloom.common.dto.user.UserWithScoreDto;
import org.patinanetwork.codebloom.common.leetcode.LeetcodeClient;
import org.patinanetwork.codebloom.common.leetcode.models.LeetcodeSubmission;
import org.patinanetwork.codebloom.common.page.Indexed;
import org.patinanetwork.codebloom.common.page.Page;
import org.patinanetwork.codebloom.common.submissions.SubmissionsHandler;
import org.patinanetwork.codebloom.common.utils.leaderboard.LeaderboardUtils;
import org.patinanetwork.codebloom.common.utils.pair.Pair;
import org.springframework.stereotype.Component;
Expand All @@ -24,11 +29,21 @@ public class LeaderboardManager {

private final LeaderboardRepository leaderboardRepository;
private final AchievementRepository achievementRepository;
private final UserRepository userRepository;
private final LeetcodeClient leetcodeClient;
private final SubmissionsHandler submissionsHandler;

public LeaderboardManager(
final LeaderboardRepository leaderboardRepository, final AchievementRepository achievementRepository) {
final LeaderboardRepository leaderboardRepository,
final AchievementRepository achievementRepository,
final UserRepository userRepository,
final LeetcodeClient leetcodeClient,
final SubmissionsHandler submissionsHandler) {
this.leaderboardRepository = leaderboardRepository;
this.achievementRepository = achievementRepository;
this.userRepository = userRepository;
this.leetcodeClient = leetcodeClient;
this.submissionsHandler = submissionsHandler;
}

public static final int MIN_POSSIBLE_WINNERS = 0;
Expand Down Expand Up @@ -151,4 +166,33 @@ public Page<Indexed<UserWithScoreDto>> getLeaderboardUsers(
new Page<>(hasNextPage, indexedUserWithScoreDtos, totalPages, parsedPageSize);
return createdPage;
}

public User refreshUserSubmissions(final String discordId) throws LeaderboardException {
User user = userRepository.getUserByDiscordId(discordId);

if (user == null) {
throw new LeaderboardException(
"Cannot refresh submissions",
"Please link your account by [logging in to Codebloom](https://codebloom.patinanetwork.org/login) and completing onboarding.");
}

if (user.getLeetcodeUsername() == null) {
throw new LeaderboardException(
"Cannot refresh submissions", "Your Discord Account is not linked to a LeetCode username.");
}
try {
log.info("Fetching recent LeetCode submissions for user: {}", user.getLeetcodeUsername());
List<LeetcodeSubmission> leetcodeSubmissions =
leetcodeClient.findSubmissionsByUsername(user.getLeetcodeUsername(), 20);

submissionsHandler.handleSubmissions(leetcodeSubmissions, user, true);
} catch (Exception e) {
log.error("Failed to fetch or process submissions for user {}", user.getLeetcodeUsername(), e);
throw new LeaderboardException(
"Cannot refresh submissions",
"Failed to fetch or process submissions from LeetCode. Please try again later.");
}

return user;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.patinanetwork.codebloom.common.dto.refresh;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.jackson.Jacksonized;

@Getter
@Builder
@Jacksonized
@ToString
@EqualsAndHashCode
public class RefreshResultDto {

@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
private int score;

@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
private int globalRank;

@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
private int clubRank;

@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
private String leaderboardName;

@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
private String clubName;
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
@ToString
@EqualsAndHashCode
public class Indexed<T> {

@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
private final int index;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
@AllArgsConstructor
@ToString
public enum JDASlashCommand {
LEADERBOARD("leaderboard", "Shows the current weekly leaderboard");
LEADERBOARD("leaderboard", "Shows the current weekly leaderboard"),
REFRESH("refresh", "Refresh submissions manually");

private final String command;
private final String description;
Expand Down
Loading
Loading