Added the Moderation module V1

This commit is contained in:
Mathias Wagner 2022-09-06 16:28:48 +02:00
parent c5f1a281a0
commit be825e7281
18 changed files with 685 additions and 0 deletions

View File

@ -0,0 +1,3 @@
# Project exclude paths
/target/
/.idea

View File

@ -0,0 +1,2 @@
# SheepstarModule-Moderation
The official sheepstar moderation module

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>xyz.sheepstar</groupId>
<artifactId>SheepstarModule-Moderation</artifactId>
<version>pre1.0.0</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>xyz.sheepstar</groupId>
<artifactId>SheepstarCore</artifactId>
<version>beta1.0.2</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,38 @@
package xyz.sheepstar.moderation.action;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.User;
import xyz.sheepstar.moderation.api.models.TempBanManager;
import xyz.sheepstar.util.action.RepeatedAction;
import java.time.LocalDateTime;
public class AutomaticUnbanAction extends RepeatedAction {
private final TempBanManager tempBanManager = (TempBanManager) api.getDatabase().getTableFactory().getTable(TempBanManager.class);
@Override
public long time() {
return 3;
}
@Override
public void execute() {
tempBanManager.getEntries().forEach(entry -> {
LocalDateTime unbanDate = (LocalDateTime) entry.get("unban_date");
if (unbanDate.compareTo(LocalDateTime.now()) <= 0) {
Guild guild = api.getJDA().getGuildById((String) entry.get("guildID"));
User user = api.getJDA().retrieveUserById((String) entry.get("userID")).complete();
try {
guild.unban(user).complete();
} catch (Exception ignored) {
}
tempBanManager.unban(user, guild);
}
});
}
}

View File

@ -0,0 +1,26 @@
package xyz.sheepstar.moderation.api;
import net.dv8tion.jda.api.Permission;
import xyz.sheepstar.util.bot.command.GuildCommand;
import xyz.sheepstar.util.bot.command.GuildEventController;
public abstract class ModerationCommand extends GuildCommand {
/**
* Checks if a user is authorized (an administrator or a moderation)
*
* @param event The {@link GuildEventController} from the listener
* @return <code>true</code> if the user is authorized, otherwise <code>false</code>
*/
@Override
public boolean isAuthorized(GuildEventController event) {
if (event.getMember().hasPermission(Permission.ADMINISTRATOR)) return true;
String moderationRole = api.getBotManager().getSettingsManager().getSetting(event.getGuild(), "moderation", "moderation_role").toString();
if (moderationRole.isEmpty()) return false;
return event.getMember().getRoles().contains(jda.getRoleById(moderationRole));
}
}

View File

@ -0,0 +1,79 @@
package xyz.sheepstar.moderation.api.entities;
import net.dv8tion.jda.api.entities.Member;
import java.sql.Timestamp;
public class Infraction {
private Member member;
private String reason;
private Timestamp timestamp;
/**
* Basic constructor of the {@link Infraction}
*
* @param member The member of the infraction
* @param reason The reason why the member has been warned
* @param timestamp The time when the user has been warned
*/
public Infraction(Member member, String reason, Timestamp timestamp) {
this.member = member;
this.reason = reason;
this.timestamp = timestamp;
}
/**
* Gets the member of the infraction
*
* @return the member of the infraction
*/
public Member getMember() {
return member;
}
/**
* Sets the member of the infraction
*
* @param member The new member of the infraction
*/
public void setMember(Member member) {
this.member = member;
}
/**
* Gets the reason why the user has been warned
*
* @return the reason of the infraction
*/
public String getReason() {
return reason;
}
/**
* Sets the reason of the infraction
*
* @param reason The reason of the infraction
*/
public void setReason(String reason) {
this.reason = reason;
}
/**
* Gets the timestamp of the infraction
*
* @return the timestamp of the infraction
*/
public Timestamp getTimestamp() {
return timestamp;
}
/**
* Sets the timestamp of the infraction
*
* @param timestamp The new timestamp of the infraction
*/
public void setTimestamp(Timestamp timestamp) {
this.timestamp = timestamp;
}
}

View File

@ -0,0 +1,67 @@
package xyz.sheepstar.moderation.api.models;
import de.gnmyt.sqltoolkit.types.SQLType;
import net.dv8tion.jda.api.entities.Member;
import xyz.sheepstar.moderation.api.entities.Infraction;
import xyz.sheepstar.util.sql.SheepManager;
import java.sql.Timestamp;
import java.util.ArrayList;
public class InfractionsManager extends SheepManager {
@Override
protected String tableName() {
return "moderation_infractions";
}
@Override
protected void tableFields() {
custom("guildID").add();
custom("clientID").add();
custom("reason").add();
custom("added").length(6).type(SQLType.TIMESTAMP).extras(new String[]{"DEFAULT CURRENT_TIMESTAMP(6)"}).add();
}
/**
* Warns a member in a guild
*
* @param member The member you want to warn
* @param reason The reason why you want to warn the member
*/
public void warn(Member member, String reason) {
insert().value("guildID", member.getGuild().getId()).value("clientID", member.getId()).value("reason", reason).execute();
}
/**
* Warns a member in a guild without a reason
*
* @param member The member you want to warn
*/
public void warn(Member member) {
warn(member, "No reason provided");
}
/**
* Clears all warnings of a member
*
* @param member The member from which you want to remove all warnings
*/
public void clearWarnings(Member member) {
delete().where("guildID", member.getGuild().getId()).where("clientID", member.getId()).execute();
}
/**
* Gets all infractions of a member
* @param member The member you want to get the infractions from
* @return all infractions of the member
*/
public ArrayList<Infraction> getInfractions(Member member) {
ArrayList<Infraction> infractions = new ArrayList<>();
select().where("guildID", member.getGuild().getId()).where("clientID", member.getId()).getResult().getList().forEach(entry ->
infractions.add(new Infraction(member, (String) entry.get("reason"), (Timestamp) entry.get("added"))));
return infractions;
}
}

View File

@ -0,0 +1,68 @@
package xyz.sheepstar.moderation.api.models;
import de.gnmyt.sqltoolkit.types.SQLType;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.User;
import xyz.sheepstar.util.sql.SheepManager;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
public class TempBanManager extends SheepManager {
@Override
protected String tableName() {
return "moderation_temp_bans";
}
@Override
protected void tableFields() {
custom("userID").add();
custom("guildID").add();
custom("unban_date").type(SQLType.DATETIME).add();
}
/**
* Checks if a specific user is temp-banned on a specific guild
*
* @param user The user you want to check
* @param guild The guild you want to check
* @return <code>true</code> if the specific user is temp-banned, otherwise <code>false</code>
*/
public boolean isBanned(User user, Guild guild) {
return select().where("userID", user.getId()).where("guildID", guild.getId()).getResult().exists();
}
/**
* Temp-bans a specific user / adds the specific user to the table
* @param user The user you want to temp-ban
* @param guild The guild on which the user should be banned
* @param date The date when the user should be unbanned
*/
public void ban(User user, Guild guild, Date date) {
if (isBanned(user, guild)) return;
insert().value("userID", user.getId()).value("guildID", guild.getId()).value("unban_date", date).execute();
}
/**
* Unbans a user / deletes a temp-ban from the table
*
* @param user The user you want to unban
* @param guild The guild on which the user should be unbanned
*/
public void unban(User user, Guild guild) {
if (!isBanned(user, guild)) return;
delete().where("userID", user.getId()).where("guildID", guild.getId()).execute();
}
/**
* Gets all current banned users
*
* @return gets all entries from the table
*/
public ArrayList<HashMap<String, Object>> getEntries() {
return select().getResult().getList();
}
}

View File

@ -0,0 +1,31 @@
package xyz.sheepstar.moderation.commands;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import xyz.sheepstar.moderation.api.ModerationCommand;
import xyz.sheepstar.util.bot.command.Arguments;
import xyz.sheepstar.util.bot.command.GuildEventController;
import xyz.sheepstar.util.bot.command.annotations.CommandMeta;
@CommandMeta(aliases = {"ban", "banuser"}, description = "Bans a member")
public class BanCommand extends ModerationCommand {
@Override
public void usage() {
usage(OptionType.USER, "member", "The member you want to ban").required(true).add();
usage("reason", "The reason why the member should be banned").add();
usage(OptionType.INTEGER, "days", "Deletes messages from the past days").add();
}
@Override
public void execute(GuildEventController event, Arguments args) throws Exception {
User member = args.retrieveUser("member");
String reason = (args.exists("reason") ? args.getString("reason") : "No reason provided") + " (Banned by " + event.getAuthor().getAsTag() + ")";
int days = args.exists("days") ? args.getInteger("days") : 0;
event.getGuild().ban(member, days, reason).complete();
event.success("moderation.user_banned", member.getAsTag(), reason, days);
}
}

View File

@ -0,0 +1,32 @@
package xyz.sheepstar.moderation.commands;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import xyz.sheepstar.moderation.api.ModerationCommand;
import xyz.sheepstar.util.bot.command.Arguments;
import xyz.sheepstar.util.bot.command.GuildEventController;
import xyz.sheepstar.util.bot.command.annotations.CommandMeta;
import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;
@CommandMeta(aliases = "clear", description = "Clears a specific amount of messages in this chat")
public class ClearCommand extends ModerationCommand {
@Override
public void usage() {
usage(OptionType.INTEGER, "amount", "The amount of messages to delete").required(true).add();
}
@Override
public void execute(GuildEventController event, Arguments args) throws Exception {
int amount = Math.min(args.getInteger("amount"), 100);
event.getChannel().getHistory().retrievePast(amount).queue(messages -> {
messages.removeIf(message -> message.getTimeCreated().isBefore(OffsetDateTime.now().minus(2, ChronoUnit.WEEKS)));
if (!messages.isEmpty()) event.getChannel().deleteMessages(messages).queue();
event.success("moderation.messages_cleared", amount, event.getChannel().getAsMention());
});
}
}

View File

@ -0,0 +1,31 @@
package xyz.sheepstar.moderation.commands;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import xyz.sheepstar.moderation.api.ModerationCommand;
import xyz.sheepstar.util.bot.command.Arguments;
import xyz.sheepstar.util.bot.command.GuildEventController;
import xyz.sheepstar.util.bot.command.annotations.CommandMeta;
@CommandMeta(aliases = {"kick", "kickuser"}, description = "Kicks a user from the server")
public class KickCommand extends ModerationCommand {
@Override
public void usage() {
usage(OptionType.USER, "member", "The member you want to kick").required(true).add();
usage("reason", "The reason why you want to kick the member").add();
}
@Override
public void execute(GuildEventController event, Arguments args) throws Exception {
Member member = event.getGuild().retrieveMemberById(args.getString("member")).complete();
String reason = args.exists("reason") ? args.getString("reason") : "No reason provided";
event.getGuild().kick(member, reason).complete();
event.success("moderation.user_kicked", member.getUser().getAsTag(), reason);
}
}

View File

@ -0,0 +1,42 @@
package xyz.sheepstar.moderation.commands;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import xyz.sheepstar.moderation.api.ModerationCommand;
import xyz.sheepstar.moderation.api.models.TempBanManager;
import xyz.sheepstar.util.bot.command.Arguments;
import xyz.sheepstar.util.bot.command.GuildEventController;
import xyz.sheepstar.util.bot.command.annotations.CommandMeta;
import java.util.Date;
@CommandMeta(aliases = {"tempban", "bantemp"}, description = "Bans a user for a specific amount of days")
public class TempBanCommand extends ModerationCommand {
private final TempBanManager tempBanManager = (TempBanManager) table(TempBanManager.class);
@Override
public void usage() {
usage(OptionType.USER, "member", "The member you want to ban").required(true).add();
usage("time", "The amount of time the user should be banned (ex. 3d2h5m)").required(true).add();
usage("reason", "The reason why the member should be banned").add();
usage(OptionType.INTEGER, "days", "Deletes messages from the past days").add();
}
@Override
public void execute(GuildEventController event, Arguments args) throws Exception {
User member = args.retrieveUser("member");
int days = args.exists("days") ? args.getInteger("days") : 0;
Date date = getTimeFromString(args.getString("time"));
String reason = (args.exists("reason") ? args.getString("reason") : "No reason provided")
+ " (Temp-banned by " + event.getAuthor().getAsTag() + ", automatically unbans at " + date + ")";
tempBanManager.ban(member, event.getGuild(), date);
event.getGuild().ban(member, days, reason).complete();
event.success("moderation.user_temp_banned", member.getAsTag(), reason, days, date);
}
}

View File

@ -0,0 +1,26 @@
package xyz.sheepstar.moderation.commands;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import xyz.sheepstar.moderation.api.ModerationCommand;
import xyz.sheepstar.util.bot.command.Arguments;
import xyz.sheepstar.util.bot.command.GuildEventController;
import xyz.sheepstar.util.bot.command.annotations.CommandMeta;
@CommandMeta(aliases = "unban", description = "Unbans a user")
public class UnbanCommand extends ModerationCommand {
@Override
public void usage() {
usage(OptionType.USER, "member", "The member you want to unban").required(true).add();
}
@Override
public void execute(GuildEventController event, Arguments args) throws Exception {
User member = args.retrieveUser("member");
event.getGuild().unban(member).complete();
event.success("moderation.user_unbanned", member.getAsTag());
}
}

View File

@ -0,0 +1,69 @@
package xyz.sheepstar.moderation.commands;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import xyz.sheepstar.moderation.api.ModerationCommand;
import xyz.sheepstar.util.bot.builder.message.DefaultEmbedBuilder;
import xyz.sheepstar.util.bot.builder.message.MessageType;
import xyz.sheepstar.util.bot.command.Arguments;
import xyz.sheepstar.util.bot.command.GuildEventController;
import xyz.sheepstar.util.bot.command.annotations.CommandMeta;
import xyz.sheepstar.util.bot.emote.INTERN_EMOTE;
import java.time.OffsetDateTime;
@CommandMeta(aliases = "userinfo", description = "Shows the information of an user")
public class UserInfoCommand extends ModerationCommand {
@Override
public void usage() {
usage(OptionType.USER, "member", "The member you want the info from").required(true).add();
}
@Override
public void execute(GuildEventController event, Arguments args) throws Exception {
Member target = event.getGuild().retrieveMemberById(args.getString("member")).complete();
String boostedTime = target.getTimeBoosted() == null ? ":x: Not boosting" : toUnix(target.getTimeBoosted());
DefaultEmbedBuilder builder = new DefaultEmbedBuilder(MessageType.PRIMARY)
.setTitle(":information_source: " + translate("moderation.userinfo", event.getGuild()))
.addField(":id: " + translate("moderation.client_id", event.getGuild()), target.getId(), true)
.addField(":pencil: " + translate("moderation.username", event.getGuild()), target.getUser().getAsTag(), true)
.addField(getEmoteString(INTERN_EMOTE.NITRO) + " " + translate("moderation.boosting_since", event.getGuild()), boostedTime, true)
.addField(String.format(":open_file_folder: %s (%s)", translate("moderation.roles", event.getGuild()), target.getRoles().size()),
getRoleText(target), true)
.addField(":date: " + translate("moderation.joined_date", event.getGuild()), toUnix(target.getTimeJoined()), true)
.addField(":date: " + translate("moderation.creation_date", event.getGuild()), toUnix(target.getTimeCreated()), true)
.setColor(target.getColor())
.setThumbnail(target.getUser().getAvatarUrl());
event.reply(builder.toMessage());
}
/**
* Converts the provided timestamp to a valid discord unix timestamp
*
* @param time The timestamp you want to view
* @return the created discord unix timestamp
*/
public String toUnix(OffsetDateTime time) {
return String.format("<t:%s:R>", (time.toInstant().toEpochMilli() / 1000));
}
/**
* Gets the text of the role
*
* @param target The member you want to get
* @return the roles as a string
*/
public String getRoleText(Member target) {
StringBuilder roleText = new StringBuilder();
target.getRoles().forEach(role -> {
if (!roleText.toString().isEmpty()) roleText.append(", ");
roleText.append(role.getAsMention());
});
return roleText.toString();
}
}

View File

@ -0,0 +1,33 @@
package xyz.sheepstar.moderation.commands.infractions;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import xyz.sheepstar.moderation.api.ModerationCommand;
import xyz.sheepstar.moderation.api.models.InfractionsManager;
import xyz.sheepstar.util.bot.command.Arguments;
import xyz.sheepstar.util.bot.command.GuildEventController;
import xyz.sheepstar.util.bot.command.annotations.CommandMeta;
@CommandMeta(aliases = {"warn", "warnuser"}, description = "Warns a user")
public class WarnCommand extends ModerationCommand {
private InfractionsManager infractionsManager = (InfractionsManager) table(InfractionsManager.class);
@Override
public void usage() {
usage(OptionType.USER, "member", "The member you want to warn").required(true).add();
usage("reason", "The reason why you want to warn the user").add();
}
@Override
public void execute(GuildEventController event, Arguments args) throws Exception {
Member member = event.getGuild().retrieveMemberById(args.getString("member")).complete();
String reason = args.exists("reason") ? args.getString("reason") : "No reason provided";
infractionsManager.warn(member, reason);
event.success("moderation.user_warned", member.getUser().getAsTag(), reason);
}
}

View File

@ -0,0 +1,57 @@
package xyz.sheepstar.moderation.commands.infractions;
import net.dv8tion.jda.api.entities.Emoji;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.components.ButtonStyle;
import xyz.sheepstar.moderation.api.ModerationCommand;
import xyz.sheepstar.moderation.api.models.InfractionsManager;
import xyz.sheepstar.util.bot.builder.message.MessageType;
import xyz.sheepstar.util.bot.command.Arguments;
import xyz.sheepstar.util.bot.command.GuildEventController;
import xyz.sheepstar.util.bot.command.annotations.CommandMeta;
@CommandMeta(aliases = {"warnings", "listwarns", "listwarnings"}, description = "Shows you all infractions/warnings of a user")
public class WarningsCommand extends ModerationCommand {
private InfractionsManager infractionsManager = (InfractionsManager) table(InfractionsManager.class);
@Override
public void usage() {
usage(OptionType.USER, "member", "The member you want to get the infractions from").required(true).add();
}
@Override
public void execute(GuildEventController event, Arguments args) throws Exception {
Member member = event.getGuild().retrieveMemberById(args.getString("member")).complete();
StringBuilder infractions = new StringBuilder();
infractionsManager.getInfractions(member).forEach(infraction -> {
if (!infractions.toString().isEmpty()) infractions.append("\n");
infractions.append("`").append(infraction.getReason()).append("`").append(" *").
append(String.format("<t:%s:R>", infraction.getTimestamp().getTime() / 1000)).append("*");
});
if (infractions.toString().isEmpty())
infractions.append(":no_entry_sign: The member currently has no warnings");
event.custom(MessageType.PRIMARY)
.withTitle(translate("moderation.infractions", event.getLanguage(), member.getUser().getName()))
.withDescription(infractions.toString())
.addButton(ButtonStyle.DANGER, "clear#" + args.getString("member"), "Clear all", Emoji.fromUnicode("\uD83D\uDDD1"))
.send();
}
@Override
public void buttonClick(GuildEventController event, String id) throws Exception {
if (!id.startsWith("clear#")) return;
Member member = event.getGuild().retrieveMemberById(id.split("#")[1]).complete();
infractionsManager.clearWarnings(member);
event.success("moderation.cleared_warnings", member.getUser().getAsTag());
}
}

View File

@ -0,0 +1,54 @@
package xyz.sheepstar.moderation.core;
import xyz.sheepstar.moderation.action.AutomaticUnbanAction;
import xyz.sheepstar.moderation.api.models.InfractionsManager;
import xyz.sheepstar.moderation.commands.*;
import xyz.sheepstar.moderation.api.models.TempBanManager;
import xyz.sheepstar.moderation.commands.infractions.WarningsCommand;
import xyz.sheepstar.moderation.commands.infractions.WarnCommand;
import xyz.sheepstar.util.bot.manager.ImportManager;
import xyz.sheepstar.util.module.SheepstarModule;
public class ModerationCore extends SheepstarModule {
private ImportManager importManager;
@Override
public void onEnable() {
importManager = new ImportManager(getAPI(), "moderation");
registerManagers();
registerCommands();
registerActions();
}
/**
* Registers all commands of the moderation module
*/
public void registerCommands() {
importManager.registerCommand(new BanCommand());
importManager.registerCommand(new UnbanCommand());
importManager.registerCommand(new TempBanCommand());
importManager.registerCommand(new KickCommand());
importManager.registerCommand(new UserInfoCommand());
importManager.registerCommand(new WarnCommand());
importManager.registerCommand(new WarningsCommand());
importManager.registerCommands(new ClearCommand());
}
/**
* Registers all managers of this module
*/
public void registerManagers() {
registerTable(new TempBanManager());
registerTable(new InfractionsManager());
}
/**
* Registers all actions of this module
*/
public void registerActions() {
new AutomaticUnbanAction().start();
}
}

View File

@ -0,0 +1,3 @@
main: xyz.sheepstar.moderation.core.ModerationCore
name: moderation
author: Mathias Wagner