This commit is contained in:
Tyler Murphy 2022-08-30 16:05:54 -04:00
parent f65981e4b4
commit 2839f973c3
9 changed files with 260 additions and 16 deletions

View file

@ -99,6 +99,8 @@ public class Ken {
public Role getRoleById(long id) { return api.getRoleById(id); }
public User getUserByName(String username, String discriminator) { return api.getUserByTag(username, discriminator); }
public EmbedBuilder getDefaultEmbed() {
EmbedBuilder builder = new EmbedBuilder();
builder.setColor(new Color(

View file

@ -17,6 +17,7 @@ import net.dv8tion.jda.api.interactions.components.ActionRow;
import net.dv8tion.jda.api.interactions.components.LayoutComponent;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import net.dv8tion.jda.api.interactions.components.selections.SelectMenu;
import net.dv8tion.jda.api.requests.restaction.WebhookMessageCreateAction;
import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction;
import net.dv8tion.jda.api.utils.FileUpload;
import net.tylermurphy.ken.Ken;
@ -144,9 +145,10 @@ public class Responder extends ListenerAdapter {
// Invoke Method and Respond to User
try {
event.deferReply().queue();
Object temp = method.invoke(register.getHandle(method.getDeclaringClass().getName()), parameters);
Response response = (Response)temp;
reply(response, event);
reply(response, event.getHook());
} catch (Exception e) {
EmbedBuilder builder = Ken.getInstance().getDefaultEmbed()
.setColor(Color.RED)
@ -191,9 +193,9 @@ public class Responder extends ListenerAdapter {
// Invoke Method and Respond to User
try {
event.deferEdit().queue();
Object temp = method.invoke(register.getHandle(method.getDeclaringClass().getName()), parameters);
Response response = (Response) temp;
event.deferEdit().queue();
edit(response, event.getHook());
} catch (Exception e) {
EmbedBuilder builder = Ken.getInstance().getDefaultEmbed()
@ -239,9 +241,10 @@ public class Responder extends ListenerAdapter {
// Invoke Method and Respond to User
try {
event.deferReply().queue();
Object temp = method.invoke(register.getHandle(method.getDeclaringClass().getName()), parameters);
Response response = (Response) temp;
reply(response, event);
reply(response, event.getHook());
} catch (Exception e) {
EmbedBuilder builder = Ken.getInstance().getDefaultEmbed()
.setColor(Color.RED)
@ -252,18 +255,18 @@ public class Responder extends ListenerAdapter {
}
private void reply(Response response, IReplyCallback event){
private void reply(Response response, InteractionHook hook){
if(response.isError()) {
EmbedBuilder builder = Ken.getInstance().getDefaultEmbed()
.setColor(Color.RED)
.setDescription(response.getMessage());
event.replyEmbeds(builder.build()).setEphemeral(true).queue();
hook.sendMessageEmbeds(builder.build()).setEphemeral(true).queue();
} else {
ReplyCallbackAction message;
WebhookMessageCreateAction<Message> message;
if(response.hasEmbed()) {
message = event.replyEmbeds(response.getEmbeds());
message = hook.sendMessageEmbeds(response.getEmbeds());
} else {
message = event.reply(response.getMessage());
message = hook.sendMessage(response.getMessage());
}
if(response.hasButtons()) message = message.addActionRow(response.getButtons());
if(response.hasSelectMenu()) message = message.addActionRow(response.getSelectMenu());

View file

@ -27,7 +27,7 @@ public class Ban {
@Command(name="ban", description="Perm ban a user and delete all messages in past 24h")
@Option(name="member", description="Member to ban", type=OptionType.USER, required=true)
@Option(name="reason", description="Reason to ban", type=OptionType.STRING, required=true)
@Option(name="deletemessages", description="Delete messages from past 24h", type=OptionType.BOOLEAN, required=true)
@Option(name="delete_messages", description="Delete messages from past 24h", type=OptionType.BOOLEAN, required=true)
@Requirement(Permission.BAN_MEMBERS)
public Response execute(Member sender, List<Object> args, Guild guild){
Member target = (Member) args.get(0);
@ -45,6 +45,9 @@ public class Ban {
if(!Checks.getRolePermission(self, low)){
return Response.error("I need a higher role than the target");
}
if(guild.getOwner() == target){
return Response.error("You cannot to this to the server owner");
}
try {
guild.retrieveBan(target).complete();
@ -67,6 +70,8 @@ public class Ban {
table.setData(guild.getIdLong(), target.getUser().getIdLong(), json.toString());
Ken.getInstance().getDatabase().getUserTable().setData(target.getIdLong(), target.getUser().getName(), Integer.parseInt(target.getUser().getDiscriminator()));
PrivateChannel channel = target.getUser().openPrivateChannel().complete();
if(channel != null){
EmbedBuilder builder = Ken.getInstance().getDefaultEmbed()
@ -79,7 +84,7 @@ public class Ban {
}
guild.ban(target,purge ? 1 : 0,reason).queue();
EmbedBuilder builder = Ken.getInstance().getDefaultEmbed()
.appendDescription(String.format("Permanently banned %s for %s", target.getEffectiveName(), reason));
.appendDescription(String.format("Permanently banned %s for %s", target, reason));
return Response.success(builder.build());
}

View file

@ -1,4 +1,76 @@
package net.tylermurphy.ken.command.moderation;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.tylermurphy.ken.Ken;
import net.tylermurphy.ken.command.Response;
import net.tylermurphy.ken.command.annotation.Command;
import net.tylermurphy.ken.command.annotation.Option;
import net.tylermurphy.ken.command.annotation.Requirement;
import net.tylermurphy.ken.database.ModerationTable;
import org.json.JSONArray;
import org.json.JSONObject;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
public class History {
@Command(name="history", description="Get moderation history of a user")
@Option(name="username", description="The username of the target not including after the #", type= OptionType.STRING, required=true)
@Option(name="discriminator", description="Last for digits after #", type=OptionType.INTEGER, required=true)
@Requirement(Permission.BAN_MEMBERS)
public Response execute(List<Object> args, Guild guild){
String username = (String) args.get(0);
String discriminator = String.valueOf(args.get(1));
if(discriminator.length() != 4) {
return Response.error("Invalid discriminator");
}
long target = Ken.getInstance().getDatabase().getUserTable().getData(username, (int)args.get(1));
if(target == 0L) {
return Response.error("Unable to find this user");
}
ModerationTable table = Ken.getInstance().getDatabase().getModerationTable();
String data = table.getData(guild.getIdLong(), target);
JSONObject json = table.updateData(data);
JSONObject status = json.getJSONObject("status");
JSONArray history = json.getJSONArray("history");
StringBuilder historyString = new StringBuilder();
history.forEach(audit -> historyString.append(parseStatus((JSONObject) audit)));
EmbedBuilder builder = Ken.getInstance().getDefaultEmbed()
.setAuthor("Moderation History")
.addField("Status", parseStatus(status), false)
.addField("History", historyString.toString(), false);
return Response.success(builder.build());
}
private String parseStatus(JSONObject status){
String type = status.getString("type");
String reason = "Reason: " + status.getString("reason");
if(type.equals("None")) return "User currently has no moderation actions against them";
String name = switch (type){
case "ban" -> "Banned";
case "temp-ban" -> "Temp banned";
case "unban" -> "Unbanned";
case "kick" -> "Kicked";
default -> throw new RuntimeException("Unknown value: " + type);
};
SimpleDateFormat format = new SimpleDateFormat("MMM d, y ha zz");
String date = status.has("until") ?
"Until: " + format.format(new Date(status.getLong("until"))) :
"Date: " + format.format(new Date(status.getLong("date")));
return "**" + name + "**\n" + reason + "\n" + date + "\n";
}
}

View file

@ -1,4 +1,89 @@
package net.tylermurphy.ken.command.moderation;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.PrivateChannel;
import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.exceptions.ErrorResponseException;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.tylermurphy.ken.Ken;
import net.tylermurphy.ken.command.Response;
import net.tylermurphy.ken.command.annotation.Command;
import net.tylermurphy.ken.command.annotation.Option;
import net.tylermurphy.ken.command.annotation.Requirement;
import net.tylermurphy.ken.database.ModerationTable;
import net.tylermurphy.ken.util.Checks;
import org.json.JSONArray;
import org.json.JSONObject;
import java.awt.*;
import java.util.Date;
import java.util.List;
public class Kick {
@Command(name="kick", description="Kick a user")
@Option(name="member", description="Member to kick", type= OptionType.USER, required=true)
@Option(name="reason", description="Reason to kick", type=OptionType.STRING, required=true)
@Requirement(Permission.BAN_MEMBERS)
public Response execute(Member sender, List<Object> args, Guild guild){
Member target = (Member) args.get(0);
String reason = (String) args.get(1);
if(target == sender){
return Response.error("You are not allowed to do this to yourself");
}
Role low = Checks.getHighestRole(target);
Role high = Checks.getHighestRole(sender);
if(!Checks.getRolePermission(high, low)){
return Response.error("You need a higher role than the target");
}
Role self = Checks.getHighestRole(guild.getSelfMember());
if(!Checks.getRolePermission(self, low)){
return Response.error("I need a higher role than the target");
}
if(guild.getOwner() == target){
return Response.error("You cannot to this to the server owner");
}
try {
guild.retrieveBan(target).complete();
return Response.error("User is currently banned and cannot be kicked");
} catch (ErrorResponseException ignored) {}
ModerationTable table = Ken.getInstance().getDatabase().getModerationTable();
String data = table.getData(guild.getIdLong(), target.getUser().getIdLong());
JSONObject json = table.updateData(data);
JSONObject status = json.getJSONObject("status");
status.put("type", "None");
status.put("reason", "");
status.put("until", 0L);
json.put("status", status);
JSONArray history = json.getJSONArray("history");
history.put(new JSONObject().put("type", "kick").put("reason", reason).put("date",new Date().getTime()));
json.put("history", history);
table.setData(guild.getIdLong(), target.getUser().getIdLong(), json.toString());
Ken.getInstance().getDatabase().getUserTable().setData(target.getIdLong(), target.getUser().getName(), Integer.parseInt(target.getUser().getDiscriminator()));
PrivateChannel channel = target.getUser().openPrivateChannel().complete();
if(channel != null){
EmbedBuilder builder = Ken.getInstance().getDefaultEmbed()
.setColor(Color.red)
.setTitle("**Kicked**")
.appendDescription("You have been kicked from "+guild.getName()+"\n")
.appendDescription("`By:` " + sender.getEffectiveName()+"\n")
.appendDescription("`Reason:` " + reason);
channel.sendMessageEmbeds(builder.build()).queue();
}
guild.kick(target, reason).queue();
EmbedBuilder builder = Ken.getInstance().getDefaultEmbed()
.appendDescription(String.format("Kicked %s for %s", target, reason));
return Response.success(builder.build());
}
}

View file

@ -31,7 +31,7 @@ public class TempBan {
@Option(name="days", description="Days for temp ban", type= OptionType.INTEGER, required=true)
@Option(name="hours", description="Hours for temp ban", type= OptionType.INTEGER, required=true)
@Option(name="reason", description="Reason to temp-ban", type=OptionType.STRING, required=true)
@Option(name="deletemessages", description="Delete messages from past 24h", type=OptionType.BOOLEAN, required=true)
@Option(name="delete_messages", description="Delete messages from past 24h", type=OptionType.BOOLEAN, required=true)
@Requirement(Permission.BAN_MEMBERS)
public Response execute(Member sender, List<Object> args, Guild guild){
Member target = (Member) args.get(0);
@ -51,6 +51,9 @@ public class TempBan {
if(!Checks.getRolePermission(self, low)){
return Response.error("I need a higher role than the target");
}
if(guild.getOwner() == target){
return Response.error("You cannot to this to the server owner");
}
if(hours < 0){
return Response.error("Hours must be 0 or greater");
}
@ -70,7 +73,7 @@ public class TempBan {
cal.setTime(new Date());
cal.add(Calendar.DATE, days);
cal.add(Calendar.HOUR, hours);
SimpleDateFormat format = new SimpleDateFormat("L d, y ha zz");
SimpleDateFormat format = new SimpleDateFormat("MMM d, y ha zz");
String date = format.format(cal.getTime());
ModerationTable table = Ken.getInstance().getDatabase().getModerationTable();
@ -89,6 +92,8 @@ public class TempBan {
table.setData(guild.getIdLong(), target.getUser().getIdLong(), json.toString());
Ken.getInstance().getDatabase().getUserTable().setData(target.getIdLong(), target.getUser().getName(), Integer.parseInt(target.getUser().getDiscriminator()));
PrivateChannel channel = target.getUser().openPrivateChannel().complete();
if(channel != null){
EmbedBuilder builder = Ken.getInstance().getDefaultEmbed()
@ -96,13 +101,13 @@ public class TempBan {
.setTitle("**Temp Banned**")
.appendDescription("You have been temporarily banned from "+guild.getName()+"\n")
.appendDescription("`By:` " + sender.getEffectiveName()+"\n")
.appendDescription("`Reason:` " + reason)
.appendDescription("`Reason:` " + reason+"\n")
.appendDescription("`Until:` " + date);
channel.sendMessageEmbeds(builder.build()).queue();
}
guild.ban(target,purge ? 1 : 0,reason).queue();
EmbedBuilder builder = Ken.getInstance().getDefaultEmbed()
.appendDescription(String.format("Temporarily banned %s for %s until %s", target.getEffectiveName(), reason, date));
.appendDescription(String.format("Temporarily banned %s for %s until %s", target, reason, date));
return Response.success(builder.build());
}

View file

@ -21,13 +21,18 @@ import java.util.List;
public class UnBan {
@Command(name="unban", description="Unban a user")
@Option(name="username", description="Username", type= OptionType.STRING, required=true)
@Option(name="discriminator", description="Discriminator", type=OptionType.INTEGER, required=true)
@Option(name="username", description="The username of the target not including after the #", type= OptionType.STRING, required=true)
@Option(name="discriminator", description="Last for digits after #", type=OptionType.INTEGER, required=true)
@Option(name="reason", description="Reason to unban", type=OptionType.STRING, required=true)
@Requirement(Permission.BAN_MEMBERS)
public Response execute(Member sender, Guild guild, List<Object> args){
String username = (String) args.get(0);
String discriminator = String.valueOf(args.get(1));
if(discriminator.length() != 4) {
return Response.error("Invalid discriminator");
}
String reason = (String) args.get(2);
User target = null;
@ -69,6 +74,8 @@ public class UnBan {
table.setData(guild.getIdLong(), target.getIdLong(), json.toString());
Ken.getInstance().getDatabase().getUserTable().setData(target.getIdLong(), target.getName(), Integer.parseInt(target.getDiscriminator()));
PrivateChannel channel = target.openPrivateChannel().complete();
if(channel != null){
EmbedBuilder builder = Ken.getInstance().getDefaultEmbed()

View file

@ -14,6 +14,7 @@ public class Database {
private final SelfRoleTable selfRoleTable;
private final EconomyTable economyTable;
private final ModerationTable moderationTable;
private final UserTable userTable;
public Database(){
if(Ken.getInstance().getConfig().getBoolean("database.sqlite")) {
@ -24,6 +25,7 @@ public class Database {
selfRoleTable = new SelfRoleTable(this);
economyTable = new EconomyTable(this);
moderationTable = new ModerationTable(this);
userTable = new UserTable(this);
}
public SelfRoleTable getSelfRoleData(){
@ -36,6 +38,8 @@ public class Database {
public ModerationTable getModerationTable() { return moderationTable; }
public UserTable getUserTable() { return userTable; }
protected Connection connect() throws SQLException {
return connection.connect();
}

View file

@ -0,0 +1,61 @@
package net.tylermurphy.ken.database;
import net.dv8tion.jda.api.entities.User;
import net.tylermurphy.ken.Ken;
import org.json.JSONObject;
import java.sql.*;
public class UserTable {
private final Database database;
public UserTable(Database database){
String sql = """
CREATE TABLE IF NOT EXISTS user_data (
user_id BIGINT NOT NULL,
username VARCHAR(64) NOT NULL,
discriminator INT NOT NULL,
PRIMARY KEY (user_id)
);""";
try(Connection connection = database.connect(); Statement statement = connection.createStatement()) {
statement.executeUpdate(sql);
} catch (SQLException e) {
Ken.getInstance().getLogger().error("SQL Error: " + e.getMessage());
}
this.database = database;
}
public long getData(String username, int discriminator){
User cache = Ken.getInstance().getUserByName(username, String.valueOf(discriminator));
if(cache != null) return cache.getIdLong();
String sql = "SELECT * FROM user_data WHERE username=? AND discriminator=?";
try(Connection connection = database.connect(); PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setString(1, username);
statement.setInt(2, discriminator);
ResultSet rs = statement.executeQuery();
if(rs.next()) return rs.getLong("user_id");
else return 0L;
} catch (SQLException e) {
Ken.getInstance().getLogger().error("SQL Error: " + e.getMessage());
return 0L;
}
}
public boolean setData(long userId, String username, int discriminator) {
String sql = "INSERT OR REPLACE INTO user_data (user_id, username, discriminator) VALUES(?,?,?)";
try(Connection connection = database.connect(); PreparedStatement statement = connection.prepareStatement(sql)) {
statement.setLong(1, userId);
statement.setString(2, username);
statement.setInt(3, discriminator);
return statement.executeUpdate() != 0;
} catch (SQLException e) {
Ken.getInstance().getLogger().error("SQL Error: " + e.getMessage());
return false;
}
}
}