Updated everything, added a check for if someone leaves the discord so it auto unlinks them if they do, and added auto bans/unbans based on litebans bans/unbans

This commit is contained in:
Teriuihi 2021-12-27 05:00:51 +01:00
parent 5236b11241
commit e26a3c23c6
13 changed files with 264 additions and 72 deletions

View File

@ -37,9 +37,10 @@ dependencies {
compileOnly("com.velocitypowered:velocity-api:1.1.5")
annotationProcessor("com.velocitypowered:velocity-api:1.1.5")
// JDA
implementation("net.dv8tion:JDA:4.3.0_283") {
implementation("net.dv8tion:JDA:5.0.0-alpha.3") {
exclude("opus-java") // exclude audio
}
compileOnly("com.gitlab.ruany:LitebansAPI:0.3.5")
// LuckPerms
compileOnly("net.luckperms:api:5.3")
// MySQL

View File

@ -4,12 +4,13 @@ dependencyResolutionManagement {
repositories {
mavenCentral()
// Altitude
maven {
name = "maven"
url = uri("http://leo:8081/")
isAllowInsecureProtocol = true
//credentials(PasswordCredentials::class)
}
// maven {
// name = "maven"
// url = uri("http://leo:8081/")
// isAllowInsecureProtocol = true
// //credentials(PasswordCredentials::class)
// }
maven("https://jitpack.io")
// Velocity
maven("https://nexus.velocitypowered.com/repository/maven-public/")
// JDA

View File

@ -6,6 +6,7 @@ import com.alttd.proxydiscordlink.config.BotConfig;
import com.alttd.proxydiscordlink.config.Config;
import com.alttd.proxydiscordlink.database.Database;
import com.alttd.proxydiscordlink.database.DatabaseConnection;
import com.alttd.proxydiscordlink.minecraft.listeners.LiteBansBanListener;
import com.alttd.proxydiscordlink.minecraft.listeners.LuckpermsEvents;
import com.alttd.proxydiscordlink.minecraft.listeners.PlayerLeave;
import com.alttd.proxydiscordlink.minecraft.listeners.WhitelistKick;
@ -65,6 +66,7 @@ public class DiscordLink {
loadCommands();
loadEvents();
loadBot();
new LiteBansBanListener().registerEvents();
}
public void reloadConfig() {

View File

@ -3,18 +3,20 @@ package com.alttd.proxydiscordlink.bot;
import com.alttd.proxydiscordlink.bot.listeners.DiscordMessageListener;
import com.alttd.proxydiscordlink.bot.listeners.DiscordRoleListener;
import com.alttd.proxydiscordlink.config.BotConfig;
import com.alttd.proxydiscordlink.objects.DiscordLinkPlayer;
import com.alttd.proxydiscordlink.util.ALogger;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
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.Role;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.exceptions.HierarchyException;
import net.dv8tion.jda.api.exceptions.InsufficientPermissionException;
import net.dv8tion.jda.api.requests.GatewayIntent;
import net.dv8tion.jda.api.utils.MemberCachePolicy;
import org.jetbrains.annotations.Nullable;
import javax.security.auth.login.LoginException;
import java.util.concurrent.TimeUnit;
@ -77,20 +79,36 @@ public class Bot {
public void sendEmbedToDiscord(long channelid, EmbedBuilder embedBuilder, long secondsTillDelete) {
//sendMessageToDiscord(client.getTextChannelById(channel), message, blocking);
TextChannel channel = jda.getTextChannelById(channelid);
if (jda == null) return;
if (jda == null) {
ALogger.warn("JDA is NULL");
return;
}
if (channel == null) return;
if (channel == null) {
ALogger.warn("Can't send message to NULL channel (" + channelid + ")");
return;
}
if (embedBuilder == null) return;
if (embedBuilder == null) {
ALogger.warn("Tried to send a NULL embed");
return;
}
if (!embedBuilder.isValidLength()) return;
if (!embedBuilder.isValidLength()) {
ALogger.warn("Tried to send an invalid embed");
return;
}
if (embedBuilder.isEmpty()) {
ALogger.warn("Tried to send an empty embed");
return;
}
if (embedBuilder.isEmpty()) return;
try {
if (secondsTillDelete < 0) {
channel.sendMessage(embedBuilder.build()).queue();
channel.sendMessageEmbeds(embedBuilder.build()).queue();
} else {
channel.sendMessage(embedBuilder.build()).queue(message -> message.delete().queueAfter(secondsTillDelete, TimeUnit.SECONDS));
channel.sendMessageEmbeds(embedBuilder.build()).queue(message -> message.delete().queueAfter(secondsTillDelete, TimeUnit.SECONDS));
}
} catch (Exception e) {
ALogger.error("caught some exception, " + e);
@ -166,4 +184,40 @@ public class Bot {
}
return true;
}
public void discordUnban(long guildId, long userId) {
Guild guild = jda.getGuildById(guildId);
if (guild == null)
return;
if (!guild.getSelfMember().getPermissions().contains(Permission.BAN_MEMBERS)) {
ALogger.warn("I can't unban members in " + guild.getName() + ".");
return;
}
guild.retrieveBanList().queue(bans -> bans.stream()
.filter(ban -> ban.getUser().getIdLong() == userId)
.findFirst()
.ifPresent(bans::remove));
}
public void discordBan(long guildId, long userId, @Nullable String optionalReason) {
Guild guild = jda.getGuildById(guildId);
if (guild == null)
return;
if (!guild.getSelfMember().getPermissions().contains(Permission.BAN_MEMBERS)) {
ALogger.warn("I can't ban members in " + guild.getName() + ".");
return;
}
Member member = guild.getMemberById(userId);
if (member == null)
return;
try {
if (optionalReason == null)
member.ban(0).queue();
else
member.ban(0, optionalReason).queue();
} catch (InsufficientPermissionException exception) {
ALogger.warn("Unable to ban " + userId + " from Discord they might be above me.");
}
}
}

View File

@ -57,6 +57,7 @@ public class DiscordLinkCommand extends DiscordCommand {
getUsername(uuid),
member.getUser().getName(),
false,
true,
discordRoles.stream()
.map(DiscordRole::getInternalName)
.collect(Collectors.toList()));

View File

@ -1,16 +1,10 @@
package com.alttd.proxydiscordlink.bot.commands;
import com.alttd.proxydiscordlink.DiscordLink;
import com.alttd.proxydiscordlink.bot.DiscordCommand;
import com.alttd.proxydiscordlink.bot.objects.DiscordRole;
import com.alttd.proxydiscordlink.database.Database;
import com.alttd.proxydiscordlink.objects.DiscordLinkPlayer;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
public class DiscordUnlink extends DiscordCommand {
@Override
public String getCommand() {
@ -35,26 +29,15 @@ public class DiscordUnlink extends DiscordCommand {
@Override
public void handleCommand(Message message, String sender, String command, String[] args) {
Member member = message.getMember();
if (member == null)
return;
Database database = DiscordLink.getPlugin().getDatabase();
DiscordLinkPlayer discordLinkPlayer = DiscordLinkPlayer.getDiscordLinkPlayer(member.getIdLong());
if (discordLinkPlayer == null) {
message.getChannel().sendMessage("Your accounts aren't linked.").queue();
return;
}
database.removeLinkedAccount(discordLinkPlayer);
discordLinkPlayer.updateDiscord(
DiscordRole.getDiscordRoles().stream()
.filter(role -> discordLinkPlayer.getRoles().contains(role.getInternalName()))
.collect(Collectors.toList()),
false);
discordLinkPlayer.updateMinecraft(
DiscordRole.getDiscordRoles().stream()
.filter(role -> discordLinkPlayer.getRoles().contains(role.getInternalName()))
.collect(Collectors.toList()),
false);
discordLinkPlayer.linkedRole(false);
discordLinkPlayer.unlinkDiscordLinkPlayer();
message.getChannel().sendMessage("Your Discord and Minecraft accounts have been unlinked.").queue();
}
}

View File

@ -0,0 +1,19 @@
package com.alttd.proxydiscordlink.bot.listeners;
import com.alttd.proxydiscordlink.DiscordLink;
import com.alttd.proxydiscordlink.database.Database;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.events.guild.member.GuildMemberRemoveEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
public class DiscordLeaveListener extends ListenerAdapter {
@Override
public void onGuildMemberRemove(GuildMemberRemoveEvent event) {
User user = event.getUser();
Database database = DiscordLink.getPlugin().getDatabase();
if (DiscordLink.getPlugin().getDatabase().playerIsLinked(user.getIdLong())) {
}
}
}

View File

@ -4,15 +4,14 @@ import com.alttd.proxydiscordlink.DiscordLink;
import com.alttd.proxydiscordlink.bot.Bot;
import com.alttd.proxydiscordlink.bot.DiscordCommand;
import com.alttd.proxydiscordlink.config.BotConfig;
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import java.util.Arrays;
import java.util.Optional;
public class DiscordMessageListener extends ListenerAdapter {
private DiscordLink plugin;
private final DiscordLink plugin;
private final Bot bot;
public DiscordMessageListener() {
@ -21,13 +20,13 @@ public class DiscordMessageListener extends ListenerAdapter {
}
@Override
public void onGuildMessageReceived(GuildMessageReceivedEvent event) {
if (event.getAuthor() == event.getJDA().getSelfUser()) {
public void onMessageReceived(MessageReceivedEvent event) {
if (!event.isFromGuild())
return;
}
if (event.isWebhookMessage()) {
if (event.getAuthor() == event.getJDA().getSelfUser())
return;
if (event.isWebhookMessage())
return;
}
if (event.getMessage().getChannel().getIdLong() == BotConfig.COMMAND_CHANNEL) {
String content = event.getMessage().getContentRaw();
if (content.startsWith(BotConfig.prefixMap.get(event.getGuild().getIdLong())) && content.length() > 1) {
@ -35,9 +34,8 @@ public class DiscordMessageListener extends ListenerAdapter {
String cmd = split[0].substring(1).toLowerCase();
String[] args = Arrays.copyOfRange(split, 1, split.length);
for(DiscordCommand command : DiscordCommand.getCommands()) {
if(!command.getCommand().equalsIgnoreCase(cmd)) {
if(!command.getCommand().equalsIgnoreCase(cmd))
continue;
}
if(command.getPermission() != null) {
// TODO permission check? do we need this?
}
@ -49,12 +47,11 @@ public class DiscordMessageListener extends ListenerAdapter {
String[] split = content.split(" ");
String cmd = split[0].substring(1).toLowerCase();
String[] args = Arrays.copyOfRange(split, 1, split.length);
if (cmd.equalsIgnoreCase("link")) {
Optional<DiscordCommand> link = DiscordCommand.getCommands().stream().filter(discordCommand -> discordCommand.getCommand().equals("link")).findFirst();
if (!link.isEmpty()) {
link.get().handleCommand(event.getMessage(), event.getAuthor().getName(), cmd, args);
}
}
if (cmd.equalsIgnoreCase("link"))
DiscordCommand.getCommands().stream()
.filter(discordCommand -> discordCommand.getCommand().equals("link"))
.findFirst()
.ifPresent(discordCommand -> discordCommand.handleCommand(event.getMessage(), event.getAuthor().getName(), cmd, args));
}
}

View File

@ -170,6 +170,7 @@ public class BotConfig {
public static long COMMAND_CHANNEL = -1;
public static long LINK_CHANNEL = -1;
public static long GUILD_ID = -1;
public static long EVIDENCE_CHANNEL_ID = -1;
public static long LINKED_ROLE_ID = -1;
private static void settings() {
@ -177,6 +178,7 @@ public class BotConfig {
COMMAND_CHANNEL = getLong("settings.command-channel", COMMAND_CHANNEL);
LINK_CHANNEL = getLong("settings.link-channel", LINK_CHANNEL);
GUILD_ID = getLong("settings.guild-id", GUILD_ID);
EVIDENCE_CHANNEL_ID = getLong("settings.evidence-channel-id", EVIDENCE_CHANNEL_ID);
LINKED_ROLE_ID = getLong("settings.linked-role-id", LINKED_ROLE_ID);
}

View File

@ -19,6 +19,7 @@ public class Database {
"`discord_username` VARCHAR(256) NOT NULL, " +
"`discord_id` BIGINT NOT NULL, " +
"`nickname` BIT DEFAULT b'0', " +
"`active` BIT DEFAULT b'1', " +
"UNIQUE(discord_id), " +
"PRIMARY KEY(player_uuid)" +
");";
@ -37,15 +38,14 @@ public class Database {
}
public void syncPlayer(DiscordLinkPlayer player) {
//Remove any accounts with the players uuid/id
removeLinkedAccount(player);
try {
String sql = "INSERT INTO linked_accounts " +
"VALUES (?, ?, ?, ?, ?) " +
"VALUES (?, ?, ?, ?, ?, ?) " +
"ON DUPLICATE KEY UPDATE " +
"player_uuid = ?, " +
"player_name = ?, " +
"discord_username = ?, " +
"discord_id = ?, " +
"nickname = ? ";
"discord_id = ?";
PreparedStatement statement = DatabaseConnection.getConnection().prepareStatement(sql);
@ -55,12 +55,10 @@ public class Database {
statement.setString(3, player.getDiscordUsername());
statement.setLong(4, player.getUserId());
statement.setInt(5, player.hasNick() ? 1 : 0);
statement.setInt(6, player.isActive() ? 1 : 0);
//Update
statement.setString(6, player.getUuid().toString());
statement.setString(7, player.getUsername());
statement.setString(8, player.getDiscordUsername());
statement.setLong(9, player.getUserId());
statement.setInt(10, player.hasNick() ? 1 : 0);
statement.setString(7, player.getUuid().toString());
statement.setLong(8, player.getUserId());
statement.execute();
} catch (SQLException exception) {
@ -108,7 +106,26 @@ public class Database {
public boolean playerIsLinked(Player player) { //TODO maybe this can be using the discord api instead? (or a cache idk)
try {
PreparedStatement statement = DatabaseConnection.getConnection()
.prepareStatement("SELECT * FROM linked_accounts WHERE player_uuid = '" + player.getUniqueId().toString() + "'");
.prepareStatement("SELECT * FROM linked_accounts WHERE player_uuid = ?");
statement.setString(1, player.getUniqueId().toString());
ResultSet resultSet = statement.executeQuery();
if (resultSet.next()) {
return true;
}
} catch (SQLException exception) {
exception.printStackTrace();
}
return false;
}
public boolean playerIsLinked(long id) { //TODO maybe this can be using the discord api instead? (or a cache idk)
try {
PreparedStatement statement = DatabaseConnection.getConnection()
.prepareStatement("SELECT * FROM linked_accounts WHERE discord_id = ?");
statement.setLong(1, id);
ResultSet resultSet = statement.executeQuery();
if (resultSet.next()) {
@ -125,14 +142,10 @@ public class Database {
public void removeLinkedAccount(DiscordLinkPlayer player) {
try {
PreparedStatement statement = DatabaseConnection.getConnection()
.prepareStatement("DELETE FROM linked_accounts WHERE discord_id = ?");
.prepareStatement("DELETE FROM linked_accounts WHERE discord_id = ? OR uuid = ?");
statement.setLong(1, player.getUserId());
statement.setString(2, player.getUuid().toString());
statement.executeUpdate();
PreparedStatement statement2 = DatabaseConnection.getConnection()
.prepareStatement("DELETE FROM account_roles WHERE uuid = ?");
statement2.setString(1, player.getUuid().toString());
statement2.executeUpdate();
} catch (SQLException var2) {
var2.printStackTrace();
}
@ -218,6 +231,7 @@ public class Database {
resultSet.getString("player_name"),
resultSet.getString("discord_username"),
resultSet.getInt("nickname") == 1,
resultSet.getInt("active") == 1,
new ArrayList<>()
);
addRoles(discordLinkPlayer);
@ -242,4 +256,14 @@ public class Database {
exception.printStackTrace();
}
}
public void setActive(UUID uuid, boolean active) {
String sql = "UPDATE linked_accounts SET active = ? WHERE player_uuid = ?";
try {
PreparedStatement statement = DatabaseConnection.getConnection().prepareStatement(sql);
statement.setInt(1, active ? 1 : 0);
} catch (SQLException exception) {
exception.printStackTrace();
}
}
}

View File

@ -59,8 +59,8 @@ public class Unlink implements SubCommand {
}
DiscordLinkPlayer discordLinkPlayer = DiscordLinkPlayer.getDiscordLinkPlayer(player.getUniqueId());
database.removeLinkedAccount(discordLinkPlayer);
discordLinkPlayer.setActive(false);
discordLinkPlayer.updateDiscord(
DiscordRole.getDiscordRoles().stream()
.filter(role -> discordLinkPlayer.getRoles().contains(role.getInternalName()))

View File

@ -0,0 +1,77 @@
package com.alttd.proxydiscordlink.minecraft.listeners;
import com.alttd.proxydiscordlink.DiscordLink;
import com.alttd.proxydiscordlink.config.BotConfig;
import com.alttd.proxydiscordlink.objects.DiscordLinkPlayer;
import com.velocitypowered.api.proxy.Player;
import litebans.api.Entry;
import litebans.api.Events;
import net.dv8tion.jda.api.EmbedBuilder;
import java.awt.*;
import java.util.Optional;
import java.util.UUID;
public class LiteBansBanListener {
public void registerEvents() {
Events.get().register(new Events.Listener() {
@Override
public void entryAdded(Entry entry) {
if (entry.getType().equals("ban"))
onBan(entry);
}
@Override
public void entryRemoved(Entry entry) {
if (entry.getType().equals("ban"))
onUnBan(entry);
}
});
}
private void onBan(Entry entry) {
if (!entry.isPermanent())
return;
String stringUuid = entry.getUuid();
if (stringUuid == null)
return;
UUID uuid = UUID.fromString(stringUuid);
DiscordLinkPlayer discordLinkPlayer = DiscordLinkPlayer.getDiscordLinkPlayer(uuid);
discordLinkPlayer.setActive(false);
DiscordLink.getPlugin().getBot().discordBan(BotConfig.GUILD_ID, discordLinkPlayer.getUserId(), "Auto ban due to Minecraft ban");
Optional<Player> player = DiscordLink.getPlugin().getProxy().getPlayer(uuid);
String username = stringUuid;
if (player.isPresent())
username = player.get().getUsername();
DiscordLink.getPlugin().getBot().sendEmbedToDiscord(BotConfig.EVIDENCE_CHANNEL_ID,
new EmbedBuilder()
.setColor(Color.RED)
.setAuthor(username, null, "https://crafatar.com/avatars/" + stringUuid + "?overlay")
.setTitle("Auto Discord ban")
.addField("Ban info",
"**Discord username**: `" + discordLinkPlayer.getDiscordUsername() + "`" +
"\n**Discord id**: `" + discordLinkPlayer.getUserId() + "`" +
"\n**Banned by**: `" + entry.getExecutorName() + "`" +
"\n**For**: ```" + (entry.getReason().length() < 800 ? entry.getReason() : entry.getReason().substring(0, 797) + "...") + "```",
false),
-1);
}
private void onUnBan(Entry entry) {
if (!entry.isPermanent())
return;
String uuid = entry.getUuid();
if (uuid == null)
return;
DiscordLinkPlayer discordLinkPlayer = DiscordLinkPlayer.getDiscordLinkPlayer(UUID.fromString(uuid));
DiscordLink.getPlugin().getBot().discordUnban(BotConfig.GUILD_ID, discordLinkPlayer.getUserId());
}
}

View File

@ -11,6 +11,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
public class DiscordLinkPlayer {
private final long userId;
@ -18,15 +19,17 @@ public class DiscordLinkPlayer {
private String username;
private String discordUsername;
private boolean nick;
private boolean active;
private final List<String> roleNames;
public DiscordLinkPlayer(long userId, UUID uuid, String username, String discordUsername, boolean nick, List<String> roleNames) {
public DiscordLinkPlayer(long userId, UUID uuid, String username, String discordUsername, boolean nick, boolean active, List<String> roleNames) {
this.userId = userId;
this.uuid = uuid;
this.username = username;
this.roleNames = roleNames;
this.discordUsername = discordUsername;
this.nick = nick;
this.active = active;
}
public long getUserId() {
@ -74,6 +77,16 @@ public class DiscordLinkPlayer {
this.nick = nick;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
DiscordLink.getPlugin().getDatabase().setActive(getUuid(), active);
this.active = active;
}
public void updateDiscord(List<DiscordRole> roles, boolean added) {
if (added)
roles.stream().filter(DiscordRole::isUpdateToDiscord).forEach(role -> DiscordLink.getPlugin().getBot().addRole(userId, role.getId(), BotConfig.GUILD_ID));
@ -103,6 +116,22 @@ public class DiscordLinkPlayer {
DiscordLink.getPlugin().getBot().removeRole(userId, BotConfig.LINKED_ROLE_ID, BotConfig.GUILD_ID);
}
public void unlinkDiscordLinkPlayer() {
setActive(false);
updateDiscord(
DiscordRole.getDiscordRoles().stream()
.filter(role -> getRoles().contains(role.getInternalName()))
.collect(Collectors.toList()),
false);
updateMinecraft(
DiscordRole.getDiscordRoles().stream()
.filter(role -> getRoles().contains(role.getInternalName()))
.collect(Collectors.toList()),
false);
linkedRole(false);
}
//Static stuff
private static final List<DiscordLinkPlayer> discordLinkPlayers = new ArrayList<>();
@ -122,7 +151,8 @@ public class DiscordLinkPlayer {
.findFirst()
.orElseGet(() -> {
DiscordLinkPlayer player = DiscordLink.getPlugin().getDatabase().getPlayer(userId);
DiscordLinkPlayer.addDiscordLinkPlayer(player);
if (player != null)
DiscordLinkPlayer.addDiscordLinkPlayer(player);
return player;
});
}
@ -133,7 +163,8 @@ public class DiscordLinkPlayer {
.findFirst()
.orElseGet(() -> {
DiscordLinkPlayer player = DiscordLink.getPlugin().getDatabase().getPlayer(uuid);
DiscordLinkPlayer.addDiscordLinkPlayer(player);
if (player != null)
DiscordLinkPlayer.addDiscordLinkPlayer(player);
return player;
});
}