cleanup
All checks were successful
Deploy to Dokku / docker (ubuntu-latest) (push) Successful in 1m42s

This commit is contained in:
Lee
2024-12-27 13:04:57 +00:00
parent 5f099a97f0
commit b3a6284e40
185 changed files with 787 additions and 1341 deletions

View File

@ -0,0 +1,23 @@
package cc.fascinated.bat.autorole;
import cc.fascinated.bat.common.feature.Feature;
import cc.fascinated.bat.common.feature.FeatureProfile;
import cc.fascinated.bat.autorole.command.AutoRoleCommand;
import cc.fascinated.bat.service.CommandService;
import lombok.NonNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
/**
* @author Fascinated (fascinated7)
*/
@Component
public class AutoRoleFeature extends Feature {
@Autowired
public AutoRoleFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService) {
super("Auto Role", FeatureProfile.FeatureState.DISABLED, true);
registerCommand(commandService, context.getBean(AutoRoleCommand.class));
}
}

View File

@ -0,0 +1,59 @@
package cc.fascinated.bat.autorole;
import cc.fascinated.bat.event.EventListener;
import cc.fascinated.bat.autorole.profile.AutoRoleProfile;
import cc.fascinated.bat.common.model.BatGuild;
import cc.fascinated.bat.common.model.BatUser;
import cc.fascinated.bat.service.FeatureService;
import lombok.NonNull;
import lombok.extern.log4j.Log4j2;
import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* @author Fascinated (fascinated7)
*/
@Component
@Log4j2(topic = "AutoRole Listener")
public class AutoRoleListener implements EventListener {
private final FeatureService featureService;
@Autowired
public AutoRoleListener(@NonNull FeatureService featureService) {
this.featureService = featureService;
}
@Override
public void onGuildMemberJoin(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull GuildMemberJoinEvent event) {
AutoRoleFeature autoRoleFeature = featureService.getFeature(AutoRoleFeature.class);
if (!guild.getFeatureProfile().isFeatureEnabled(autoRoleFeature)) { // Check if the feature is enabled
return;
}
AutoRoleProfile profile = guild.getProfile(AutoRoleProfile.class);
if (profile.getRoles().isEmpty()) {
return;
}
List<String> toRemove = new ArrayList<>();
for (Role role : profile.getRoles()) {
if (event.getGuild().getRoleById(role.getId()) == null) {
toRemove.add(role.getId());
continue;
}
event.getGuild().addRoleToMember(event.getMember(), role).queue();
}
toRemove.forEach(profile::removeRole);
log.info("Gave user \"{}\" {} auto roles in guild \"{}\"{}",
user.getId(),
profile.getRoles().size(),
guild.getName(),
toRemove.isEmpty() ? "" : " and removed %s invalid roles from the profile".formatted(toRemove.size())
);
}
}

View File

@ -0,0 +1,80 @@
package cc.fascinated.bat.autorole.command;
import cc.fascinated.bat.common.command.BatCommand;
import cc.fascinated.bat.common.command.CommandInfo;
import cc.fascinated.bat.common.EmbedUtils;
import cc.fascinated.bat.common.RoleUtils;
import cc.fascinated.bat.autorole.profile.AutoRoleProfile;
import cc.fascinated.bat.common.model.BatGuild;
import cc.fascinated.bat.common.model.BatUser;
import lombok.NonNull;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author Fascinated (fascinated7)
*/
@Component("autoroles:add.sub")
@CommandInfo(name = "add", description = "Adds a role to the auto roles list")
public class AddSubCommand extends BatCommand {
@Autowired
public AddSubCommand() {
super.addOptions(new OptionData(OptionType.ROLE, "role", "The role to add", true));
}
@Override
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, Message commandMessage, String[] arguments, SlashCommandInteraction event) {
AutoRoleProfile profile = guild.getProfile(AutoRoleProfile.class);
// Check if the guild has reached the maximum auto roles count
int maxRoleSlots = AutoRoleProfile.getMaxRoleSlots(guild);
if (profile.getRoleSlotsInUse() >= maxRoleSlots) {
event.replyEmbeds(EmbedUtils.errorEmbed()
.setDescription("The guild can only have a maximum of %d auto roles"
.formatted(maxRoleSlots))
.build()).queue();
return;
}
OptionMapping option = event.getOption("role");
assert option != null;
Role role = option.getAsRole();
// Check if the role is already in the auto roles list
if (profile.hasRole(role.getId())) {
event.replyEmbeds(EmbedUtils.errorEmbed()
.setDescription("The role %s is already in the auto roles list".formatted(role.getAsMention()))
.build()).queue();
return;
}
// Check if the bot has permission to give the role
if (!RoleUtils.hasPermissionToGiveRole(guild, guild.getDiscordGuild().getSelfMember(), role)) {
event.replyEmbeds(EmbedUtils.errorEmbed()
.setDescription("I do not have permission to give the role %s".formatted(role.getAsMention()))
.build()).queue();
return;
}
// Check if the role is higher than the user adding the role
if (!RoleUtils.hasPermissionToGiveRole(guild, member, role)) {
event.replyEmbeds(EmbedUtils.errorEmbed()
.setDescription("You cannot add a role that is higher than you")
.build()).queue();
return;
}
// Add the role to the auto roles list
profile.addRole(role.getId());
event.replyEmbeds(EmbedUtils.successEmbed()
.setDescription("You have added %s to the auto roles list".formatted(role.getAsMention()))
.build()).queue();
}
}

View File

@ -0,0 +1,31 @@
package cc.fascinated.bat.autorole.command;
import cc.fascinated.bat.common.command.BatCommand;
import cc.fascinated.bat.common.command.Category;
import cc.fascinated.bat.common.command.CommandInfo;
import lombok.NonNull;
import net.dv8tion.jda.api.Permission;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
/**
* @author Fascinated (fascinated7)
*/
@Component("autoroles.command")
@CommandInfo(
name = "autorole",
description = "Set up the automatic role system for members on join",
requiredPermissions = Permission.MANAGE_SERVER,
category = Category.SERVER
)
public class AutoRoleCommand extends BatCommand {
public AutoRoleCommand(@NonNull ApplicationContext context) {
super.addSubCommands(
context.getBean(ListSubCommand.class),
context.getBean(AddSubCommand.class),
context.getBean(RemoveSubCommand.class),
context.getBean(ClearSubCommand.class),
context.getBean(SyncSubCommand.class)
);
}
}

View File

@ -0,0 +1,31 @@
package cc.fascinated.bat.autorole.command;
import cc.fascinated.bat.common.command.BatCommand;
import cc.fascinated.bat.common.command.CommandInfo;
import cc.fascinated.bat.common.EmbedUtils;
import cc.fascinated.bat.autorole.profile.AutoRoleProfile;
import cc.fascinated.bat.common.model.BatGuild;
import cc.fascinated.bat.common.model.BatUser;
import lombok.NonNull;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
import org.springframework.stereotype.Component;
/**
* @author Fascinated (fascinated7)
*/
@Component("autoroles:clear.sub")
@CommandInfo(name = "clear", description = "Clears all auto roles")
public class ClearSubCommand extends BatCommand {
@Override
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, Message commandMessage, String[] arguments, SlashCommandInteraction event) {
AutoRoleProfile profile = guild.getProfile(AutoRoleProfile.class);
profile.reset();
event.replyEmbeds(EmbedUtils.successEmbed()
.setDescription("Successfully cleared all auto roles")
.build()).queue();
}
}

View File

@ -0,0 +1,47 @@
package cc.fascinated.bat.autorole.command;
import cc.fascinated.bat.common.command.BatCommand;
import cc.fascinated.bat.common.command.CommandInfo;
import cc.fascinated.bat.common.EmbedUtils;
import cc.fascinated.bat.autorole.profile.AutoRoleProfile;
import cc.fascinated.bat.common.model.BatGuild;
import cc.fascinated.bat.common.model.BatUser;
import lombok.NonNull;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
import org.springframework.stereotype.Component;
/**
* @author Fascinated (fascinated7)
*/
@Component("autoroles:list.sub")
@CommandInfo(name = "list", description = "Lists all auto roles")
public class ListSubCommand extends BatCommand {
@Override
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, Message commandMessage, String[] arguments, SlashCommandInteraction event) {
AutoRoleProfile profile = guild.getProfile(AutoRoleProfile.class);
if (profile.getRoles().isEmpty()) {
event.replyEmbeds(EmbedUtils.errorEmbed()
.setDescription("There are no auto roles set")
.build()).queue();
return;
}
StringBuilder roles = new StringBuilder();
roles.append("There are %d/%d auto roles\n".formatted(
profile.getRoleSlotsInUse(),
AutoRoleProfile.getMaxRoleSlots(guild)
));
for (int i = 0; i < profile.getRoles().size(); i++) {
roles.append("%d. %s\n".formatted(i + 1, profile.getRoles().get(i).getAsMention()));
}
EmbedBuilder embed = EmbedUtils.genericEmbed();
embed.setAuthor("Auto Role List");
embed.setDescription(roles.toString());
event.replyEmbeds(embed.build()).queue();
}
}

View File

@ -0,0 +1,51 @@
package cc.fascinated.bat.autorole.command;
import cc.fascinated.bat.common.command.BatCommand;
import cc.fascinated.bat.common.command.CommandInfo;
import cc.fascinated.bat.common.EmbedUtils;
import cc.fascinated.bat.autorole.profile.AutoRoleProfile;
import cc.fascinated.bat.common.model.BatGuild;
import cc.fascinated.bat.common.model.BatUser;
import lombok.NonNull;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author Fascinated (fascinated7)
*/
@Component("autoroles:remove.sub")
@CommandInfo(name = "remove", description = "Removes a role from the auto roles list")
public class RemoveSubCommand extends BatCommand {
@Autowired
public RemoveSubCommand() {
super.addOptions(new OptionData(OptionType.ROLE, "role", "The role to remove", true));
}
@Override
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, Message commandMessage, String[] arguments, SlashCommandInteraction event) {
AutoRoleProfile profile = guild.getProfile(AutoRoleProfile.class);
OptionMapping option = event.getOption("role");
assert option != null;
Role role = option.getAsRole();
if (!profile.hasRole(role.getId())) {
event.replyEmbeds(EmbedUtils.errorEmbed()
.setDescription("The role %s is not in the auto roles list".formatted(role.getAsMention()))
.build()).queue();
return;
}
profile.removeRole(role.getId());
event.replyEmbeds(EmbedUtils.successEmbed()
.setDescription("Successfully removed the role %s from the auto roles list".formatted(role.getAsMention()))
.build()).queue();
}
}

View File

@ -0,0 +1,113 @@
package cc.fascinated.bat.autorole.command;
import cc.fascinated.bat.common.command.BatCommand;
import cc.fascinated.bat.common.command.CommandInfo;
import cc.fascinated.bat.common.DescriptionBuilder;
import cc.fascinated.bat.common.EmbedUtils;
import cc.fascinated.bat.autorole.profile.AutoRoleProfile;
import cc.fascinated.bat.common.model.BatGuild;
import cc.fascinated.bat.common.model.BatUser;
import lombok.NonNull;
import lombok.extern.log4j.Log4j2;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
/**
* @author Fascinated (fascinated7)
*/
@Log4j2(topic = "AutoRole Sync SubCommand")
@Component("autoroles:sync.sub")
@CommandInfo(name = "sync", description = "Gives everyone their missing auto roles")
public class SyncSubCommand extends BatCommand {
@Override
public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, Message commandMessage, String[] arguments, SlashCommandInteraction event) {
AutoRoleProfile profile = guild.getProfile(AutoRoleProfile.class);
if (profile.getRoles().isEmpty()) {
event.replyEmbeds(EmbedUtils.errorEmbed()
.setDescription("There are no auto roles set")
.build()).queue();
return;
}
Guild discordGuild = guild.getDiscordGuild();
event.replyEmbeds(EmbedUtils.genericEmbed()
.setDescription("Finding members that are missing auto roles...")
.build())
.queue(message -> {
log.info("Finding members that are missing auto roles in guild \"{}\"", discordGuild.getName());
List<Member> members = discordGuild.loadMembers().get();
Map<Role, Integer> rolesGiven = new HashMap<>();
// Find members that are missing the auto roles
members.removeIf(foundMember -> {
if (foundMember.getUser().isBot() || foundMember.getId().equals(discordGuild.getSelfMember().getId())) {
return true;
}
return new HashSet<>(foundMember.getRoles()).containsAll(profile.getRoles());
});
log.info("Found {} members that are missing auto roles in guild \"{}\"", members.size(), discordGuild.getName());
// No members were missing roles
if (members.isEmpty()) {
message.editOriginalEmbeds(EmbedUtils.successEmbed()
.setDescription("There are no members missing auto roles")
.build()).queue();
return;
}
int finished = 0;
for (Member foundMember : members) {
// Check if the user doesn't have the role, so we can
// show the incremented count when we're done
for (Role role : profile.getRoles()) {
if (foundMember.getRoles().contains(role)) {
continue;
}
rolesGiven.put(role, rolesGiven.getOrDefault(role, 0) + 1);
}
// Give the user the roles
discordGuild.modifyMemberRoles(foundMember, profile.getRoles(), null).queue();
finished++;
// Update the message every 10 members
if (finished % 10 == 0 || finished == 1) {
message.editOriginalEmbeds(EmbedUtils.genericEmbed()
.setDescription("""
Giving auto roles...
Completed: `%s`/`%s`
""".formatted(finished, members.size()))
.build()).queue();
}
// We're finished giving all the roles
if (finished == members.size()) {
DescriptionBuilder description = new DescriptionBuilder(
"Successfully gave auto roles to `%s` member%s".formatted(
members.size(),
members.size() == 1 ? "" : "s"
));
description.emptyLine();
description.appendLine("**Auto Roles Given:**", false);
for (Map.Entry<Role, Integer> entry : rolesGiven.entrySet()) {
description.appendLine("%s: %s member%s".formatted(
entry.getKey().getAsMention(),
entry.getValue(),
entry.getValue() == 1 ? "" : "s"
), true);
}
message.editOriginalEmbeds(EmbedUtils.successEmbed().setDescription(description.build()).build()).queue();
}
}
});
}
}

View File

@ -0,0 +1,125 @@
package cc.fascinated.bat.autorole.profile;
import cc.fascinated.bat.common.Serializable;
import cc.fascinated.bat.common.model.BatGuild;
import cc.fascinated.bat.service.DiscordService;
import com.google.gson.Gson;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import net.dv8tion.jda.api.entities.Role;
import org.bson.Document;
import java.util.ArrayList;
import java.util.List;
/**
* @author Fascinated (fascinated7)
*/
@Setter
@Getter
@NoArgsConstructor
public class AutoRoleProfile extends Serializable {
private static final int DEFAULT_MAX_ROLES = 10;
private static final int PREMIUM_MAX_ROLES = 25;
/**
* The roles to assign when a user joins
*/
private List<String> roleIds;
/**
* Gets the maximum amount of roles that can be set in the guild
*
* @param guild the guild to check
* @return the amount of role slots
*/
public static int getMaxRoleSlots(BatGuild guild) {
if (guild.getPremiumProfile().hasPremium()) {
return PREMIUM_MAX_ROLES;
}
return DEFAULT_MAX_ROLES;
}
/**
* Gets the amount of role slots in use
*
* @return the amount
*/
public int getRoleSlotsInUse() {
return getRoles().size();
}
/**
* Adds a role to assign when a user joins
*
* @param roleId the role ID to add
*/
public void addRole(String roleId) {
if (this.roleIds == null) {
this.roleIds = new ArrayList<>();
}
this.roleIds.add(roleId);
}
/**
* Removes a role from being assigned when a user joins
*
* @param roleId the role ID to remove
*/
public void removeRole(String roleId) {
if (this.roleIds == null) {
this.roleIds = new ArrayList<>();
}
this.roleIds.remove(roleId);
}
/**
* Checks if a role is set to be assigned when a user joins
*
* @param roleId the role ID to check
* @return whether the role is set
*/
public boolean hasRole(String roleId) {
if (this.roleIds == null) {
this.roleIds = new ArrayList<>();
}
return this.roleIds.contains(roleId);
}
/**
* Gets the roles to assign when a user joins
*
* @return the roles
*/
public List<Role> getRoles() {
if (this.roleIds == null) {
this.roleIds = new ArrayList<>();
}
List<Role> roles = new ArrayList<>();
for (String id : this.roleIds) {
Role role = DiscordService.JDA.getRoleById(id);
if (role != null) {
roles.add(role);
}
}
return roles;
}
@Override
public void reset() {
roleIds.clear();
}
@Override
public void load(Document document, Gson gson) {
roleIds = document.getList("roleIds", String.class);
}
@Override
public Document serialize(Gson gson) {
Document document = new Document();
document.put("roleIds", roleIds);
return document;
}
}