Skip to content

Commit

Permalink
v3.3.0
Browse files Browse the repository at this point in the history
Ports SecretClaire to ClaireBot. This was fairly straightforward as SecretClaire is based on BaseBot, which itself is based on ClaireBot. In other words, they share the same architecture.

Adds the option to get a user's server avatar instead of only their global avatar. Not sure when I did this, but I must've done it at some point.

Finally re-adds the Zerfas reaction from ClaireBot 2. This breaks backwards compatibility of config files and they will either need to be updated manually, or regenerated. You must also fill out these config parameters or the bot will generate many errors.
  • Loading branch information
Sidpatchy committed Apr 21, 2024
1 parent 773bf16 commit 3d66402
Show file tree
Hide file tree
Showing 16 changed files with 436 additions and 28 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jar {
}

group 'com.sidpatchy'
version '3.2.0'
version '3.3.0'

sourceCompatibility = 17
targetCompatibility = 17
Expand Down
Binary file added img/zerfas-emoji.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
package com.sidpatchy.clairebot.Embed.Commands.Regular;

import com.sidpatchy.clairebot.Main;
import org.javacord.api.entity.Icon;
import org.javacord.api.entity.message.embed.EmbedBuilder;
import org.javacord.api.entity.server.Server;
import org.javacord.api.entity.user.User;

public class AvatarEmbed {

public static EmbedBuilder getAvatar(User user, User author) {
public static EmbedBuilder getAvatar(Server server, User user, User author, boolean globalAvatar) {
if (user == null) { user = author; }

// Check whether we should display the user's global avatar, or server specific avatar.
Icon avatar;
if (!globalAvatar && server != null) {
avatar = user.getServerAvatar(server).orElse(user.getAvatar());
}
else {
avatar = user.getAvatar();
}

return new EmbedBuilder()
.setColor(Main.getColor(user.getIdAsString()))
.setTimestampToNow()
.setAuthor(user.getDiscriminatedName(), "", user.getAvatar())
.setImage(user.getAvatar().getUrl().toString().replace("?size=1024", "?size=4096"))
.setAuthor(user.getDiscriminatedName(), "", user.getAvatar()) // always display global avatar in author field.
.setImage(avatar.getUrl().toString().replace("?size=1024", "?size=4096"))
.setFooter(String.valueOf(user.getId()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class HelpEmbed {

private static final ParseCommands commands = new ParseCommands(Main.getCommandsFile());
public static EmbedBuilder getHelp(String commandName, String userID) throws FileNotFoundException {
List<String> regularCommandsList = Arrays.asList("8ball", "avatar", "help", "info", "leaderboard", "level", "poll", "quote", "request", "server", "user", "config");
List<String> regularCommandsList = Arrays.asList("8ball", "avatar", "help", "info", "leaderboard", "level", "poll", "quote", "request", "server", "user", "config", "santa");

// Create HashMaps for help command
HashMap<String, HashMap<String, String>> allCommands = new HashMap<String, HashMap<String, String>>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public static EmbedBuilder getInfo(User author) {
.addField("Add Me to a Server", "Adding me to a server is simple, all you have to do is click [here](https://invite.clairebot.net)", true)
.addField("GitHub", "ClaireBot is open source, that means you can view all of its code! Check out its [GitHub!](https://github.com/Sidpatchy/ClaireBot)", true)
.addField("Server Count", "I have enlightened **" + Main.getApi().getServers().size() + "** servers.", true)
.addField("Version", "I am running ClaireBot **v3.2.0**, released on **2024-04-08**", true)
.addField("Version", "I am running ClaireBot **v3.3.0**, released on **2024-04-21**", true)
.addField("Uptime", "Started on <t:" + Main.getStartMillis() / 1000 + ">" + "\n*" + timeSinceStart + "*", true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package com.sidpatchy.clairebot.Embed.Commands.Regular;

import com.sidpatchy.clairebot.Main;
import com.sidpatchy.clairebot.Util.SantaUtils;
import org.javacord.api.entity.message.MessageBuilder;
import org.javacord.api.entity.message.component.ActionRow;
import org.javacord.api.entity.message.component.Button;
import org.javacord.api.entity.message.embed.EmbedBuilder;
import org.javacord.api.entity.permission.Role;
import org.javacord.api.entity.server.Server;
import org.javacord.api.entity.user.User;

import java.util.*;

public class SantaEmbed {

public static EmbedBuilder getConfirmationEmbed(User author) {
return new EmbedBuilder()
.setColor(Main.getColor(author.getIdAsString()))
.setAuthor("SecretClaire", "", "https://github.com/Sidpatchy/ClaireBot/blob/main/img/ClaireBot-SantaHat.png?raw=true")
.setDescription("Confirmed! I've sent you a direct message. Please continue there.");
}

/**
* Method for constructing the message to send to the host of the exchange.
*
* @param role The group of users participating
* @param author Author of the command.
* @param rules Rules for the exchange, seperated by \n.
* @param theme Theme for the exchange.
* @return Message with components
*/
public static MessageBuilder getHostMessage(Role role, User author, String rules, String theme) {
Set<User> users = role.getUsers();
Server server = role.getServer();

MessageBuilder message = new MessageBuilder();

EmbedBuilder embed = new EmbedBuilder()
.setColor(Main.getColor(author.getIdAsString()))
.setAuthor("SecretClaire", "", "https://github.com/Sidpatchy/ClaireBot/blob/main/img/ClaireBot-SantaHat.png?raw=true")
.setFooter(SantaUtils.getSantaID(server.getIdAsString(), author.getIdAsString(), role.getIdAsString()), server.getIcon().orElse(null));

if (!theme.isEmpty()) {
embed.addField("Theme", theme, false);
}

if (!rules.isEmpty()) {
embed.addField("Rules", rules, false);
}

HashMap<User, User> santaList = assignSecretSanta(users);

for (Map.Entry<User, User> userPair : santaList.entrySet()) {
User giver = userPair.getKey();
User receiver = userPair.getValue();

embed.addField(giver.getIdAsString(), giver.getNicknameMentionTag() + " → " + receiver.getNicknameMentionTag(), false);
}

ActionRow actionRow = ActionRow.of(
Button.primary("rules", "Add rules"),
Button.primary("theme", "Add a theme"),
Button.danger("send", "Send messages"),
Button.success("test", "Send sample"),
Button.secondary("randomize", "Re-randomize"));

message.addEmbed(embed);
message.addComponents(actionRow);
return message;
}

public static MessageBuilder getSantaMessage(Server server, User author, User giver, User receiver, String rules, String theme) {

MessageBuilder message = new MessageBuilder();

EmbedBuilder embed = new EmbedBuilder()
.setColor(Main.getColor(author.getIdAsString()))
.setAuthor("SecretClaire", "", "https://github.com/Sidpatchy/ClaireBot/blob/main/img/ClaireBot-SantaHat.png?raw=true")
.setFooter("Sent by " + author.getName(), author.getAvatar());

if (!theme.isEmpty()) {
embed.addField("Theme", theme, false);
}

if (!rules.isEmpty()) {
embed.addField("Rules", rules, false);
}

embed.setDescription("Ho! Ho! Ho! You have received **" + receiver.getDisplayName(server) + "** in the " + server.getName() + " Secret Santa!");

message.addEmbed(embed);

return message;
}

/**
* Method implementing a simple selected-cycle approach for pairing users.
*
* @param participants the set of users participating in the exchange
* @return A shuffled hashmap of paired up users
*/
private static HashMap<User, User> assignSecretSanta(Set<User> participants) {
List<User> userList = new ArrayList<>(participants);

// Shuffle the list to ensure random assignment
Collections.shuffle(userList);

HashMap<User, User> users = new HashMap<>(); //giver, receiver

// Creating a directed cycle
for (int i = 0; i < userList.size(); i++) {
User giver = userList.get(i);
User receiver = userList.get((i + 1) % userList.size());

// Assign the receiver to the giver here
users.put(giver, receiver);
}

return users;
}
}
69 changes: 69 additions & 0 deletions src/main/java/com/sidpatchy/clairebot/Listener/ButtonClick.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.sidpatchy.clairebot.Listener;

import com.sidpatchy.clairebot.Embed.Commands.Regular.SantaEmbed;
import com.sidpatchy.clairebot.Main;
import com.sidpatchy.clairebot.MessageComponents.Regular.SantaModal;
import com.sidpatchy.clairebot.Util.SantaUtils;
import org.javacord.api.entity.message.Message;
import org.javacord.api.entity.message.embed.Embed;
import org.javacord.api.entity.message.embed.EmbedFooter;
import org.javacord.api.entity.permission.Role;
import org.javacord.api.entity.server.Server;
import org.javacord.api.entity.user.User;
import org.javacord.api.event.interaction.ButtonClickEvent;
import org.javacord.api.interaction.ButtonInteraction;
import org.javacord.api.listener.interaction.ButtonClickListener;

public class ButtonClick implements ButtonClickListener {
@Override
public void onButtonClick(ButtonClickEvent event) {
ButtonInteraction buttonInteraction = event.getButtonInteraction();

String buttonID = buttonInteraction.getCustomId().toLowerCase();
User buttonAuthor = buttonInteraction.getUser();
Message message = buttonInteraction.getMessage();

Embed embed = buttonInteraction.getMessage().getEmbeds().get(0);
EmbedFooter footer = embed.getFooter().orElse(null);

// Extract data from embed fields
SantaUtils.ExtractionResult extractionResult = SantaUtils.extractDataFromEmbed(embed, footer);

Server server = Main.getApi().getServerById(extractionResult.santaID.get("serverID")).orElse(null);
User author = Main.getApi().getUserById(extractionResult.santaID.get("authorID")).join();

switch (buttonID) {
case "rules":
buttonInteraction.respondWithModal("santa-rules-" + message.getIdAsString(), "Update Rules",
SantaModal.getRulesRow()
);

break;
case "theme":
buttonInteraction.respondWithModal("santa-theme-" + message.getIdAsString(), "Update Theme",
SantaModal.getThemeRow()
);

break;
case "send":
buttonInteraction.acknowledge();
for (int i = 0; i < extractionResult.givers.size(); i++) {
SantaEmbed.getSantaMessage(server, author, extractionResult.givers.get(i), extractionResult.receivers.get(i), extractionResult.rules, extractionResult.theme).send(extractionResult.givers.get(i));
}

break;
case "test":
buttonInteraction.acknowledge();
SantaEmbed.getSantaMessage(server, author, extractionResult.givers.get(0), extractionResult.receivers.get(0), extractionResult.rules, extractionResult.theme).send(buttonAuthor);

break;
case "randomize":
buttonInteraction.acknowledge();
Role role = Main.getApi().getRoleById(extractionResult.santaID.get("roleID")).orElse(null);
buttonInteraction.getMessage().delete();
SantaEmbed.getHostMessage(role, buttonAuthor, extractionResult.rules, extractionResult.theme).send(buttonAuthor);

break;
}
}
}
14 changes: 12 additions & 2 deletions src/main/java/com/sidpatchy/clairebot/Listener/MessageCreate.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
import com.sidpatchy.clairebot.API.APIUser;
import com.sidpatchy.clairebot.Main;
import com.sidpatchy.clairebot.Util.Leveling.LevelingTools;
import org.javacord.api.entity.emoji.Emoji;
import org.javacord.api.entity.message.Message;
import org.javacord.api.entity.message.MessageAuthor;
import org.javacord.api.entity.message.MessageBuilder;
import org.javacord.api.entity.message.mention.AllowedMentionsBuilder;
import org.javacord.api.entity.server.Server;
import org.javacord.api.entity.user.User;
import org.javacord.api.event.message.MessageCreateEvent;
import org.javacord.api.listener.message.MessageCreateListener;

Expand Down Expand Up @@ -42,7 +42,7 @@ public void onMessageCreate(MessageCreateEvent event) {
if (messageContent.toUpperCase().matches(regex)) {
Random random = new Random();
int rand = random.nextInt(onTopResponses.size());

// because apparently message.reply() doesn't allow disabling mentions.
new MessageBuilder()
.setContent(Main.getClaireBotOnTopResponses().get(rand))
Expand Down Expand Up @@ -75,6 +75,16 @@ public void onMessageCreate(MessageCreateEvent event) {
}
}

// Zerfas react
for (String trigger : Main.getZerfas()) {
String regex = ".*\\b" + Pattern.quote(trigger.toUpperCase()) + "\\b.*"; // match trigger led/followed by anything
if (messageContent.toUpperCase().matches(regex)) {
Server zerfasEmojiServer = event.getApi().getServerById(Main.getZerfasEmojiServerID()).orElse(null);
Emoji zerfasEmoji = zerfasEmojiServer.getCustomEmojiById(Main.getZerfasEmojiID()).orElse(null);
message.addReactions(zerfasEmoji);
}
}

// Grant between 0 and 8 points
if (server != null) {
Integer currentPoints = LevelingTools.getUserPoints(messageAuthor.getIdAsString(), "global");
Expand Down
46 changes: 44 additions & 2 deletions src/main/java/com/sidpatchy/clairebot/Listener/ModalSubmit.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
package com.sidpatchy.clairebot.Listener;

import com.sidpatchy.clairebot.Embed.Commands.Regular.SantaEmbed;
import com.sidpatchy.clairebot.Embed.Commands.Regular.UserPreferencesEmbed;
import com.sidpatchy.clairebot.Embed.Commands.Regular.VotingEmbed;
import com.sidpatchy.clairebot.Main;
import com.sidpatchy.clairebot.Util.ChannelUtils;
import com.sidpatchy.clairebot.Util.SantaUtils;
import org.javacord.api.entity.channel.ServerTextChannel;
import org.javacord.api.entity.message.Message;
import org.javacord.api.entity.message.MessageFlag;
import org.javacord.api.entity.message.embed.Embed;
import org.javacord.api.entity.message.embed.EmbedFooter;
import org.javacord.api.entity.permission.Role;
import org.javacord.api.entity.server.Server;
import org.javacord.api.entity.user.User;
import org.javacord.api.event.interaction.ModalSubmitEvent;
Expand All @@ -23,20 +29,46 @@ public void onModalSubmit(ModalSubmitEvent event) {

Main.getLogger().debug(modalID);

String voteType = "";
String voteType = ""; // Allows the Poll/Request feature to distinguish between the two

// Santa related vars
String santaMessageID = ""; // Allows the Secret Santa function to identify which message is being referenced.
SantaUtils.ExtractionResult extractionResult = null;
Message santaMessage = null;
if (modalID.equalsIgnoreCase("poll")) {
voteType = "POLL";
modalID = "request";
}
else if (modalID.equalsIgnoreCase("request")) {
voteType = "REQUEST";
}

else if (modalID.startsWith("santa")) {
if (modalID.startsWith("santa-rules")) {
santaMessageID = modalID.replace("santa-rules-", "");
modalID = "santa-rules";
}
else if (modalID.startsWith("santa-theme")) {
santaMessageID = modalID.replace("santa-theme-", "");
modalID = "santa-theme";
}

santaMessage = Main.getApi().getCachedMessageById(santaMessageID).orElse(null);
assert santaMessage != null;

Embed embed = santaMessage.getEmbeds().get(0);
EmbedFooter footer = embed.getFooter().orElse(null);

extractionResult = SantaUtils.extractDataFromEmbed(embed, footer);
}



switch (modalID) {
case "hex-entry-modal":
String hexColour = modalInteraction.getTextInputValueByCustomId("hex-entry-field").orElse("");

if (!hexColour.equals("")) {
if (!hexColour.isEmpty()) {
// Add "#" if not present
if (hexColour.length() == 6 || !hexColour.contains("#")) {
hexColour = "#" + hexColour;
Expand Down Expand Up @@ -76,6 +108,16 @@ else if (voteType.equalsIgnoreCase("poll")) {
}

break;
case "santa-rules", "santa-theme":
modalInteraction.createImmediateResponder().respond();
extractionResult.rules = modalInteraction.getTextInputValueByCustomId("rules-row").orElse(extractionResult.rules);
extractionResult.theme = modalInteraction.getTextInputValueByCustomId("theme-row").orElse(extractionResult.theme);

Role role = Main.getApi().getRoleById(extractionResult.santaID.get("roleID")).orElse(null);
assert role != null;

SantaEmbed.getHostMessage(role, user, extractionResult.rules, extractionResult.theme).send(user);
santaMessage.delete();
}
}
}
Loading

0 comments on commit 3d66402

Please sign in to comment.