Skip to content
Open

697 #744

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 @@ -70,7 +70,7 @@ public CustomAuthenticationSuccessHandler(
this.sessionRepository = sessionRepository;
this.leaderboardRepository = leaderboardRepository;
this.discordClubRepository = discordClubRepository;
this.jdaClient = jdaClient.connect();
this.jdaClient = jdaClient;
this.userTagRepository = userTagRepository;
this.leetcodeClient = throttledLeetcodeClient;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ private Optional<UserWithScore> getUser(final List<UserWithScore> users, final i
*/
private void sendLeaderboardCompletedDiscordMessage(final DiscordClub club) {
log.info("Connecting to JDA client...");
jdaClient.connect();
try {
var latestLeaderboard = leaderboardRepository.getRecentLeaderboardMetadata();

Expand Down Expand Up @@ -143,7 +142,6 @@ private void sendLeaderboardCompletedDiscordMessage(final DiscordClub club) {

private void sendWeeklyLeaderboardUpdateDiscordMessage(final DiscordClub club) {
log.info("Connecting to JDA client...");
jdaClient.connect();
try {
var latestLeaderboard = leaderboardRepository.getRecentLeaderboardMetadata();

Expand Down Expand Up @@ -245,4 +243,93 @@ public void sendWeeklyLeaderboardUpdateDiscordMessageToAllClubs() {
var discordClubs = discordClubRepository.getAllActiveDiscordClubs();
discordClubs.forEach(this::sendWeeklyLeaderboardUpdateDiscordMessage);
}

public void sendWeeklyLeaderboardUpdateDiscordMessageForClub(String guildId) {
System.out.println("working");
DiscordClub club =
discordClubRepository.getDiscordClubByGuildId(guildId).get();
var latestLeaderboard = leaderboardRepository.getRecentLeaderboardMetadata();

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

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

Leaderboard currentLeaderboard = leaderboardRepository.getRecentLeaderboardMetadata();

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

Duration remaining = Duration.between(StandardizedLocalDateTime.now(), shouldExpireByTime);

long daysLeft = remaining.toDays();
long hoursLeft = remaining.toHours() % 24;
long minutesLeft = remaining.toMinutes() % 60;

String description = String.format(
"""
Dear %s users,

Here is a weekly update on the LeetCode leaderboard for our very own members!

🥇- <@%s> - %s pts
🥈- <@%s> - %s pts
🥉- <@%s> - %s pts

To view the rest of the members, visit the website or check out the image embedded in this message!

Just as a reminder, there's %d day(s), %d hour(s), and %d minute(s) left until the leaderboard closes, so keep grinding!

View the full leaderboard for %s users at https://codebloom.patinanetwork.org/leaderboard?%s=true


See you next week!

Beep boop,
Codebloom
<%s>
""",
club.getName(),
getUser(users, 0).map(UserWithScore::getDiscordId).orElse("N/A"),
getUser(users, 0)
.map(UserWithScore::getTotalScore)
.map(String::valueOf)
.orElse("N/A"),
getUser(users, 1).map(UserWithScore::getDiscordId).orElse("N/A"),
getUser(users, 1)
.map(UserWithScore::getTotalScore)
.map(String::valueOf)
.orElse("N/A"),
getUser(users, 2).map(UserWithScore::getDiscordId).orElse("N/A"),
getUser(users, 2)
.map(UserWithScore::getTotalScore)
.map(String::valueOf)
.orElse("N/A"),
daysLeft,
hoursLeft,
minutesLeft,
club.getName(),
club.getTag().name().toLowerCase(),
serverUrlUtils.getUrl());

var channelId = club.getDiscordClubMetadata().flatMap(DiscordClubMetadata::getLeaderboardChannelId);

if (guildId.isEmpty() || channelId.isEmpty()) {
log.error("club {} is skipped because of missing metadata", club.getName());
return;
}

jdaClient.sendEmbedWithImages(EmbeddedImagesMessageOptions.builder()
.guildId(Long.valueOf(guildId))
.channelId(Long.valueOf(channelId.get()))
.description(description)
.title("%s - Weekly Leaderboard Update for %s".formatted(currentLeaderboard.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))
.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.Optional;
import org.patinanetwork.codebloom.common.db.models.discord.DiscordClub;


public interface DiscordClubRepository {
/**
* Creates a new DiscordClub in the database.
Expand Down Expand Up @@ -36,4 +37,6 @@ public interface DiscordClubRepository {
boolean updateDiscordClubById(DiscordClub discordClub);

boolean deleteDiscordClubById(String id);

Optional<DiscordClub> getDiscordClubByGuildId(String guildId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -174,4 +174,32 @@ public List<DiscordClub> getAllActiveDiscordClubs() {
}
return result;
}

@Override
public Optional<DiscordClub> getDiscordClubByGuildId(String guildId) {
String sql = """
SELECT
dc.*
FROM
"DiscordClub" dc
INNER JOIN
"DiscordClubMetadata" dcm
ON
dc.id = dcm."discordClubId"
WHERE
dcm."guildId" = :guildId
""";
try (Connection conn = ds.getConnection();
NamedPreparedStatement stmt = new NamedPreparedStatement(conn, sql)) {
stmt.setObject("guildId", guildId);
try (ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
return Optional.of(parseResultSetTDiscordClub(rs));
}
}
} catch (SQLException e) {
throw new RuntimeException("Failed to get DiscordClub by guildId", e);
}
return Optional.empty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import net.dv8tion.jda.api.utils.MemberCachePolicy;
import org.patinanetwork.codebloom.jda.properties.JDAProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

/**
Expand All @@ -17,25 +16,23 @@
*/
@Component
@EnableConfigurationProperties(JDAProperties.class)
public class JDAInitializer {
public class JDAClientManager {

@Getter
private final JDAProperties jdaProperties;

private final JDAEventListener jdaEventListener;
@Getter
private final JDA client;

public JDAInitializer(final JDAProperties jdaProperties, final JDAEventListener jdaEventListener) {
public JDAClientManager(final JDAProperties jdaProperties) throws InterruptedException {
this.jdaProperties = jdaProperties;
this.jdaEventListener = jdaEventListener;
this.client = initializeJda();
}

@Bean
public JDA initializeJda() throws InterruptedException {
final JDA jda = JDABuilder.createDefault(jdaProperties.getToken())
.enableIntents(GatewayIntent.GUILD_MEMBERS)
.setChunkingFilter(ChunkingFilter.ALL)
.setMemberCachePolicy(MemberCachePolicy.ALL)
.addEventListeners(jdaEventListener)
.build();

jda.awaitReady();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,43 @@
package org.patinanetwork.codebloom.jda;

import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.events.session.ReadyEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.patinanetwork.codebloom.common.components.DiscordClubManager;
import org.springframework.stereotype.Component;

/** Do not remove this. JDA requires at least one listener in order to function. */
@Component
public class JDAEventListener extends ListenerAdapter {

private final DiscordClubManager discordClubManager;
private final JDA client;

public JDAEventListener(final DiscordClubManager discordClubManager, final JDAClientManager clientManager) {
this.discordClubManager = discordClubManager;
this.client = clientManager.getClient();
client.addEventListener(this);
}

public void say(final SlashCommandInteractionEvent event, final String content) {
event.reply(content).queue(); // This requires no permissions!
}

@Override
public void onReady(final ReadyEvent event) {
for (Guild guild : event.getJDA().getGuilds()) {
guild.upsertCommand("leaderboard", "Shows the current weekly leaderboard")
.queue();
}
}

@Override
public void onSlashCommandInteraction(final SlashCommandInteractionEvent event) {
if (event.getName().equals("leaderboard")) {
discordClubManager.sendWeeklyLeaderboardUpdateDiscordMessageForClub(
event.getGuild().getId());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.utils.FileUpload;
import org.patinanetwork.codebloom.jda.JDAInitializer;
import org.patinanetwork.codebloom.jda.JDAClientManager;
import org.patinanetwork.codebloom.jda.client.options.EmbeddedImagesMessageOptions;
import org.patinanetwork.codebloom.jda.client.options.EmbeddedMessageOptions;
import org.patinanetwork.codebloom.jda.properties.patina.JDAPatinaProperties;
Expand All @@ -32,8 +32,7 @@
})
public class JDAClient {

private final JDAInitializer jdaInitializer;
private JDA jda;
private final JDA jda;

@Getter
private final JDAPatinaProperties jdaPatinaProperties;
Expand All @@ -45,56 +44,29 @@ public class JDAClient {
private final JDALogReportingProperties jdaLogReportingProperties;

JDAClient(
final JDAInitializer jdaInitializer,
final JDAClientManager jdaClientManager,
final JDAPatinaProperties jdaPatinaProperties,
final JDAErrorReportingProperties jdaReportingProperties,
final JDALogReportingProperties jdaLogReportingProperties) {
this.jdaInitializer = jdaInitializer;
this.jda = jdaClientManager.getClient();
this.jdaPatinaProperties = jdaPatinaProperties;
this.jdaErrorReportingProperties = jdaReportingProperties;
this.jdaLogReportingProperties = jdaLogReportingProperties;
}

private void isJdaReadyOrThrow() {
if (jda == null) {
throw new RuntimeException("You must call connect() first.");
}

try {
jda.awaitReady();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("Something went wrong when awaiting JDA", e);
throw new RuntimeException("Something went wrong when awaiting JDA", e);
}
}

/** Initializes the JDAClient. Returns the client object on completion. */
public JDAClient connect() {
try {
jda = jdaInitializer.initializeJda();
return this;
} catch (InterruptedException e) {
throw new RuntimeException("Failed to initialize JDA client", e);
}
}

public List<Guild> getGuilds() {
isJdaReadyOrThrow();
return jda.getGuilds();
}

public Guild getGuildById(final long guildId) {
String guildIdString = String.valueOf(guildId);
isJdaReadyOrThrow();
return jda.getGuilds().stream()
.filter(g -> g.getId().equals(guildIdString))
.findFirst()
.orElse(null);
}

public List<Member> getMemberListByGuildId(final String guildId) {
isJdaReadyOrThrow();
List<Guild> guilds = jda.getGuilds();

Optional<Guild> optionalGuild =
Expand All @@ -113,7 +85,6 @@ public List<Member> getMemberListByGuildId(final String guildId) {
* <p>Check EmbeddedMessageOptions for details on what is supported.
*/
public void sendEmbedWithImage(final EmbeddedMessageOptions options) {
isJdaReadyOrThrow();
Guild guild = getGuildById(options.getGuildId());
if (guild == null) {
log.error("Guild does not exist.");
Expand Down Expand Up @@ -147,7 +118,6 @@ public void sendEmbedWithImage(final EmbeddedMessageOptions options) {
}

public void sendEmbedWithImages(final EmbeddedImagesMessageOptions options) {
isJdaReadyOrThrow();
Guild guild = getGuildById(options.getGuildId());
if (guild == null) {
log.error("Guild does not exist.");
Expand Down
Loading
Loading