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 @@ -11,17 +11,21 @@
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.patinanetwork.codebloom.api.admin.body.CreateAnnouncementBody;
import org.patinanetwork.codebloom.api.admin.body.DeleteAnnouncementBody;
import org.patinanetwork.codebloom.api.admin.body.NewLeaderboardBody;
import org.patinanetwork.codebloom.api.admin.body.UpdateAdminBody;
import org.patinanetwork.codebloom.api.admin.body.jda.DeleteMessageBody;
import org.patinanetwork.codebloom.common.components.DiscordClubManager;
import org.patinanetwork.codebloom.common.components.LeaderboardManager;
import org.patinanetwork.codebloom.common.db.models.announcement.Announcement;
import org.patinanetwork.codebloom.common.db.models.discord.DiscordClub;
import org.patinanetwork.codebloom.common.db.models.leaderboard.Leaderboard;
import org.patinanetwork.codebloom.common.db.models.question.QuestionWithUser;
import org.patinanetwork.codebloom.common.db.models.user.User;
import org.patinanetwork.codebloom.common.db.repos.announcement.AnnouncementRepository;
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.question.QuestionRepository;
import org.patinanetwork.codebloom.common.db.repos.user.UserRepository;
Expand Down Expand Up @@ -54,6 +58,7 @@ public class AdminController {
private final Protector protector;
private final DiscordClubManager discordClubManager;
private final LeaderboardManager leaderboardManager;
private final DiscordClubRepository discordClubRepository;

public AdminController(
final LeaderboardRepository leaderboardRepository,
Expand All @@ -62,14 +67,16 @@ public AdminController(
final AnnouncementRepository announcementRepository,
final QuestionRepository questionRepository,
final DiscordClubManager discordClubManager,
final LeaderboardManager leaderboardManager) {
final LeaderboardManager leaderboardManager,
final DiscordClubRepository discordClubRepository) {
this.leaderboardRepository = leaderboardRepository;
this.protector = protector;
this.userRepository = userRepository;
this.announcementRepository = announcementRepository;
this.questionRepository = questionRepository;
this.discordClubManager = discordClubManager;
this.leaderboardManager = leaderboardManager;
this.discordClubRepository = discordClubRepository;
}

@Operation(summary = "Drops current leaderboard and add new one", description = """
Expand Down Expand Up @@ -257,4 +264,52 @@ public ResponseEntity<ApiResponder<List<QuestionWithUserDto>>> getIncompleteQues
return ResponseEntity.ok(ApiResponder.success(
"Retrieved " + incompleteQuestionsDto.size() + " incomplete questions.", incompleteQuestionsDto));
}

@Operation(
summary = "Send a message to a club's discord",
description = """
Sends an embedded message to the leaderboard channel of the guild associated with their club, provided its clubId. Only accessible to admins.
""",
responses = {
@ApiResponse(responseCode = "200", description = "Message was sent successfully"),
@ApiResponse(
responseCode = "404",
description = "Something went wrong",
content = @Content(schema = @Schema(implementation = UnsafeGenericFailureResponse.class))),
})
@PostMapping("/discord/message/test")
public ResponseEntity<ApiResponder<Empty>> sendDiscordMessage(
@RequestBody final String clubId, final HttpServletRequest request) {
protector.validateAdminSession(request);

Optional<DiscordClub> clubOpt = discordClubRepository.getDiscordClubById(clubId);
if (clubOpt.isEmpty()) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ApiResponder.failure("Club not found."));
}
DiscordClub club = clubOpt.get();

boolean sentMessage = discordClubManager.sendTestEmbedMessageToClub(club);

if (!sentMessage) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(ApiResponder.failure("Hmm, something went wrong."));
}
return ResponseEntity.ok(ApiResponder.success("Message successfully sent!", Empty.of()));
}

@PostMapping("/discord/message/delete")
public ResponseEntity<ApiResponder<Empty>> deleteDiscordMessage(
@RequestBody final DeleteMessageBody deleteMessageBody, HttpServletRequest request) {
protector.validateAdminSession(request);

boolean isDeleted = discordClubManager.deleteMessageById(
deleteMessageBody.getChannelId(), deleteMessageBody.getMessageId());

if (!isDeleted) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(ApiResponder.failure("Hmm, something went wrong."));
}

return ResponseEntity.ok(ApiResponder.success("Discord Message successfully deleted", Empty.of()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.patinanetwork.codebloom.api.admin.body.jda;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Builder
@AllArgsConstructor
public class DeleteMessageBody {

@NotBlank
private Long channelId;

@NotNull
private Long messageId;
}
Original file line number Diff line number Diff line change
Expand Up @@ -269,4 +269,33 @@ public MessageCreateData buildLeaderboardMessageForClub(String guildId, boolean

return MessageCreateData.fromEmbeds(embed);
}

public boolean sendTestEmbedMessageToClub(DiscordClub club) {
try {
String description = String.format("""
This is a test message ensuring that the integration is working as expected. Please ignore.
""", club.getName());

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

jdaClient.sendEmbedWithImages(EmbeddedImagesMessageOptions.builder()
.guildId(Long.valueOf(guildId.get()))
.channelId(Long.valueOf(channelId.get()))
.description(description)
.title("Message for %s".formatted(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());
return true;
} catch (Exception e) {
log.error("Error in DiscordClubManager when sending test message", e);
return false;
}
}

public boolean deleteMessageById(Long channelId, Long messageId) {
return jdaClient.deleteMessageById(channelId, messageId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.exceptions.ErrorResponseException;
import net.dv8tion.jda.api.utils.FileUpload;
import org.patinanetwork.codebloom.jda.JDAClientManager;
import org.patinanetwork.codebloom.jda.client.options.EmbeddedImagesMessageOptions;
Expand Down Expand Up @@ -43,7 +44,7 @@ public class JDAClient {
@Getter
private final JDALogReportingProperties jdaLogReportingProperties;

JDAClient(
public JDAClient(
final JDAClientManager jdaClientManager,
final JDAPatinaProperties jdaPatinaProperties,
final JDAErrorReportingProperties jdaReportingProperties,
Expand Down Expand Up @@ -170,4 +171,20 @@ public void sendEmbedWithImages(final EmbeddedImagesMessageOptions options) {

messageCreationAction.queue();
}

public boolean deleteMessageById(long channelId, long messageId) {
TextChannel channel = jda.getTextChannelById(channelId);

if (channel == null) {
return false;
}

try {
channel.deleteMessageById(messageId).complete();
return true;
} catch (ErrorResponseException e) {
log.error("Failed to delete message.", e);
return false;
}
}
}
Loading