Update D4J and some bugfixes

The update fixes the numerous errors about a missing status constant
Remove test check (#114)
Improvements and checking for admin permission (#115)
It also checks for channel perms now
This commit is contained in:
Norbi Peti 2019-11-28 00:16:58 +01:00
parent 19463963e3
commit 3a94b6191b
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
7 changed files with 65 additions and 45 deletions

View file

@ -183,7 +183,7 @@
<dependency> <dependency>
<groupId>com.discord4j</groupId> <groupId>com.discord4j</groupId>
<artifactId>discord4j-core</artifactId> <artifactId>discord4j-core</artifactId>
<version>3.0.10</version> <version>3.0.11</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-jdk14 --> <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-jdk14 -->
<dependency> <dependency>

View file

@ -157,12 +157,27 @@ public final class DPUtils {
return false; return false;
} }
/**
* Send a response in the form of "@User, message". Use Mono.empty() if you don't have a channel object.
*
* @param original The original message to reply to
* @param channel The channel to send the message in, defaults to the original
* @param message The message to send
* @return A mono to send the message
*/
public static Mono<Message> reply(Message original, @Nullable MessageChannel channel, String message) { public static Mono<Message> reply(Message original, @Nullable MessageChannel channel, String message) {
Mono<MessageChannel> ch; Mono<MessageChannel> ch;
if (channel == null) if (channel == null)
ch = original.getChannel(); ch = original.getChannel();
else else
ch = Mono.just(channel); ch = Mono.just(channel);
return reply(original, ch, message);
}
/**
* @see #reply(Message, MessageChannel, String)
*/
public static Mono<Message> reply(Message original, Mono<MessageChannel> ch, String message) {
return ch.flatMap(chan -> chan.createMessage((original.getAuthor().isPresent() return ch.flatMap(chan -> chan.createMessage((original.getAuthor().isPresent()
? original.getAuthor().get().getMention() + ", " : "") + message)); ? original.getAuthor().get().getMention() + ", " : "") + message));
} }

View file

@ -44,7 +44,6 @@ import java.awt.*;
import java.io.File; import java.io.File;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -196,14 +195,6 @@ public class DiscordPlugin extends ButtonPlugin {
getConfig().set("serverup", true); getConfig().set("serverup", true);
saveConfig(); saveConfig();
if (TBMCCoreAPI.IsTestServer() && !Objects.requireNonNull(dc.getSelf().block()).getUsername().toLowerCase().contains("test")) {
TBMCCoreAPI.SendException(
"Won't load because we're in testing mode and not using a separate account.",
new Exception(
"The plugin refuses to load until you change the token to a testing account. (The account needs to have \"test\" in its name.)"
+ "\nYou can disable test mode in ChromaCore config."));
Bukkit.getPluginManager().disablePlugin(this);
}
TBMCCoreAPI.SendUnsentExceptions(); TBMCCoreAPI.SendUnsentExceptions();
TBMCCoreAPI.SendUnsentDebugMessages(); TBMCCoreAPI.SendUnsentDebugMessages();

View file

@ -96,7 +96,7 @@ public class FunModule extends Component<DiscordPlugin> implements Listener {
} }
if (msglowercased.equals("list") && Bukkit.getOnlinePlayers().size() == lastlistp && ListC++ > 2) // Lowered already if (msglowercased.equals("list") && Bukkit.getOnlinePlayers().size() == lastlistp && ListC++ > 2) // Lowered already
{ {
DPUtils.reply(message, null, "Stop it. You know the answer.").subscribe(); DPUtils.reply(message, Mono.empty(), "stop it. You know the answer.").subscribe();
lastlist = 0; lastlist = 0;
lastlistp = (short) Bukkit.getOnlinePlayers().size(); lastlistp = (short) Bukkit.getOnlinePlayers().size();
return true; //Handled return true; //Handled
@ -108,7 +108,7 @@ public class FunModule extends Component<DiscordPlugin> implements Listener {
if (usableServerReadyStrings.size() == 0) if (usableServerReadyStrings.size() == 0)
fm.createUsableServerReadyStrings(); fm.createUsableServerReadyStrings();
next = usableServerReadyStrings.remove(serverReadyRandom.nextInt(usableServerReadyStrings.size())); next = usableServerReadyStrings.remove(serverReadyRandom.nextInt(usableServerReadyStrings.size()));
DPUtils.reply(message, null, fm.serverReadyAnswers().get().get(next)).subscribe(); DPUtils.reply(message, Mono.empty(), fm.serverReadyAnswers().get().get(next)).subscribe();
return false; //Still process it as a command/mcchat if needed return false; //Still process it as a command/mcchat if needed
} }
return false; return false;

View file

@ -62,7 +62,7 @@ public class CommandListener {
try { try {
timings.printElapsed("F"); timings.printElapsed("F");
if (!DiscordPlugin.plugin.getManager().handleCommand(new Command2DCSender(message), cmdwithargsString)) if (!DiscordPlugin.plugin.getManager().handleCommand(new Command2DCSender(message), cmdwithargsString))
return DPUtils.reply(message, channel, "Unknown command. Do " + DiscordPlugin.getPrefix() + "help for help.\n" + cmdwithargsString) return DPUtils.reply(message, channel, "unknown command. Do " + DiscordPlugin.getPrefix() + "help for help.\n" + cmdwithargsString)
.map(m -> false); .map(m -> false);
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("Failed to process Discord command: " + cmdwithargsString, e); TBMCCoreAPI.SendException("Failed to process Discord command: " + cmdwithargsString, e);

View file

@ -9,12 +9,17 @@ import buttondevteam.lib.TBMCSystemChatEvent;
import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.Command2;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayer;
import discord4j.core.object.entity.GuildChannel;
import discord4j.core.object.entity.Message; import discord4j.core.object.entity.Message;
import discord4j.core.object.entity.MessageChannel;
import discord4j.core.object.entity.User;
import discord4j.core.object.util.Permission; import discord4j.core.object.util.Permission;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.val; import lombok.val;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import reactor.core.publisher.Mono;
import javax.annotation.Nullable;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
@ -22,6 +27,7 @@ import java.util.Objects;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@SuppressWarnings("SimplifyOptionalCallChains") //Java 11
@CommandClass(helpText = {"Channel connect", // @CommandClass(helpText = {"Channel connect", //
"This command allows you to connect a Minecraft channel to a Discord channel (just like how the global chat is connected to #minecraft-chat).", // "This command allows you to connect a Minecraft channel to a Discord channel (just like how the global chat is connected to #minecraft-chat).", //
"You need to have access to the MC channel and have manage permissions on the Discord channel.", // "You need to have access to the MC channel and have manage permissions on the Discord channel.", //
@ -36,28 +42,29 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor @RequiredArgsConstructor
public class ChannelconCommand extends ICommand2DC { public class ChannelconCommand extends ICommand2DC {
private final MinecraftChatModule module; private final MinecraftChatModule module;
@Command2.Subcommand @Command2.Subcommand
public boolean remove(Command2DCSender sender) { public boolean remove(Command2DCSender sender) {
val message = sender.getMessage(); val message = sender.getMessage();
if (checkPerms(message)) return true; if (checkPerms(message, null)) return true;
if (MCChatCustom.removeCustomChat(message.getChannelId())) if (MCChatCustom.removeCustomChat(message.getChannelId()))
DPUtils.reply(message, null, "channel connection removed.").subscribe(); DPUtils.reply(message, Mono.empty(), "channel connection removed.").subscribe();
else else
DPUtils.reply(message, null, "this channel isn't connected.").subscribe(); DPUtils.reply(message, Mono.empty(), "this channel isn't connected.").subscribe();
return true; return true;
} }
@Command2.Subcommand @Command2.Subcommand
public boolean toggle(Command2DCSender sender, @Command2.OptionalArg String toggle) { public boolean toggle(Command2DCSender sender, @Command2.OptionalArg String toggle) {
val message = sender.getMessage(); val message = sender.getMessage();
if (checkPerms(message)) return true; if (checkPerms(message, null)) return true;
val cc = MCChatCustom.getCustomChat(message.getChannelId()); val cc = MCChatCustom.getCustomChat(message.getChannelId());
if (cc == null) if (cc == null)
return respond(sender, "this channel isn't connected."); return respond(sender, "this channel isn't connected.");
Supplier<String> togglesString = () -> Arrays.stream(ChannelconBroadcast.values()).map(t -> t.toString().toLowerCase() + ": " + ((cc.toggles & t.flag) == 0 ? "disabled" : "enabled")).collect(Collectors.joining("\n")) Supplier<String> togglesString = () -> Arrays.stream(ChannelconBroadcast.values()).map(t -> t.toString().toLowerCase() + ": " + ((cc.toggles & t.flag) == 0 ? "disabled" : "enabled")).collect(Collectors.joining("\n"))
+ "\n\n" + TBMCSystemChatEvent.BroadcastTarget.stream().map(target -> target.getName() + ": " + (cc.brtoggles.contains(target) ? "enabled" : "disabled")).collect(Collectors.joining("\n")); + "\n\n" + TBMCSystemChatEvent.BroadcastTarget.stream().map(target -> target.getName() + ": " + (cc.brtoggles.contains(target) ? "enabled" : "disabled")).collect(Collectors.joining("\n"));
if (toggle == null) { if (toggle == null) {
DPUtils.reply(message, null, "toggles:\n" + togglesString.get()).subscribe(); DPUtils.reply(message, Mono.empty(), "toggles:\n" + togglesString.get()).subscribe();
return true; return true;
} }
String arg = toggle.toUpperCase(); String arg = toggle.toUpperCase();
@ -65,7 +72,7 @@ public class ChannelconCommand extends ICommand2DC {
if (!b.isPresent()) { if (!b.isPresent()) {
val bt = TBMCSystemChatEvent.BroadcastTarget.get(arg); val bt = TBMCSystemChatEvent.BroadcastTarget.get(arg);
if (bt == null) { if (bt == null) {
DPUtils.reply(message, null, "cannot find toggle. Toggles:\n" + togglesString.get()).subscribe(); DPUtils.reply(message, Mono.empty(), "cannot find toggle. Toggles:\n" + togglesString.get()).subscribe();
return true; return true;
} }
final boolean add; final boolean add;
@ -83,7 +90,7 @@ public class ChannelconCommand extends ICommand2DC {
//1 1 | 0 //1 1 | 0
// XOR // XOR
cc.toggles ^= b.get().flag; cc.toggles ^= b.get().flag;
DPUtils.reply(message, null, "'" + b.get().toString().toLowerCase() + "' " + ((cc.toggles & b.get().flag) == 0 ? "disabled" : "enabled")).subscribe(); DPUtils.reply(message, Mono.empty(), "'" + b.get().toString().toLowerCase() + "' " + ((cc.toggles & b.get().flag) == 0 ? "disabled" : "enabled")).subscribe();
return true; return true;
} }
@ -94,12 +101,13 @@ public class ChannelconCommand extends ICommand2DC {
sender.sendMessage("channel connection is not allowed on this Minecraft server."); sender.sendMessage("channel connection is not allowed on this Minecraft server.");
return true; return true;
} }
if (checkPerms(message)) return true; val channel = message.getChannel().block();
if (checkPerms(message, channel)) return true;
if (MCChatCustom.hasCustomChat(message.getChannelId())) if (MCChatCustom.hasCustomChat(message.getChannelId()))
return respond(sender, "this channel is already connected to a Minecraft channel. Use `@ChromaBot channelcon remove` to remove it."); return respond(sender, "this channel is already connected to a Minecraft channel. Use `@ChromaBot channelcon remove` to remove it.");
val chan = Channel.getChannels().filter(ch -> ch.ID.equalsIgnoreCase(channelID) || (Arrays.stream(ch.IDs().get()).anyMatch(cid -> cid.equalsIgnoreCase(channelID)))).findAny(); val chan = Channel.getChannels().filter(ch -> ch.ID.equalsIgnoreCase(channelID) || (Arrays.stream(ch.IDs().get()).anyMatch(cid -> cid.equalsIgnoreCase(channelID)))).findAny();
if (!chan.isPresent()) { //TODO: Red embed that disappears over time (kinda like the highlight messages in OW) if (!chan.isPresent()) { //TODO: Red embed that disappears over time (kinda like the highlight messages in OW)
DPUtils.reply(message, null, "MC channel with ID '" + channelID + "' not found! The ID is the command for it without the /.").subscribe(); DPUtils.reply(message, channel, "MC channel with ID '" + channelID + "' not found! The ID is the command for it without the /.").subscribe();
return true; return true;
} }
if (!message.getAuthor().isPresent()) return true; if (!message.getAuthor().isPresent()) return true;
@ -107,19 +115,18 @@ public class ChannelconCommand extends ICommand2DC {
val dp = DiscordPlayer.getUser(author.getId().asString(), DiscordPlayer.class); val dp = DiscordPlayer.getUser(author.getId().asString(), DiscordPlayer.class);
val chp = dp.getAs(TBMCPlayer.class); val chp = dp.getAs(TBMCPlayer.class);
if (chp == null) { if (chp == null) {
DPUtils.reply(message, null, "you need to connect your Minecraft account. On our server in " + DPUtils.botmention() + " do " + DiscordPlugin.getPrefix() + "connect <MCname>").subscribe(); DPUtils.reply(message, channel, "you need to connect your Minecraft account. On the main server in " + DPUtils.botmention() + " do " + DiscordPlugin.getPrefix() + "connect <MCname>").subscribe();
return true; return true;
} }
val channel = message.getChannel().block();
DiscordConnectedPlayer dcp = DiscordConnectedPlayer.create(message.getAuthor().get(), channel, chp.getUUID(), Bukkit.getOfflinePlayer(chp.getUUID()).getName(), module); DiscordConnectedPlayer dcp = DiscordConnectedPlayer.create(message.getAuthor().get(), channel, chp.getUUID(), Bukkit.getOfflinePlayer(chp.getUUID()).getName(), module);
//Using a fake player with no login/logout, should be fine for this event //Using a fake player with no login/logout, should be fine for this event
String groupid = chan.get().getGroupID(dcp); String groupid = chan.get().getGroupID(dcp);
if (groupid == null && !(chan.get() instanceof ChatRoom)) { //ChatRooms don't allow it unless the user joins, which happens later if (groupid == null && !(chan.get() instanceof ChatRoom)) { //ChatRooms don't allow it unless the user joins, which happens later
DPUtils.reply(message, null, "sorry, you cannot use that Minecraft channel.").subscribe(); DPUtils.reply(message, channel, "sorry, you cannot use that Minecraft channel.").subscribe();
return true; return true;
} }
if (chan.get() instanceof ChatRoom) { //ChatRooms don't work well if (chan.get() instanceof ChatRoom) { //ChatRooms don't work well
DPUtils.reply(message, null, "chat rooms are not supported yet.").subscribe(); DPUtils.reply(message, channel, "chat rooms are not supported yet.").subscribe();
return true; return true;
} }
/*if (MCChatListener.getCustomChats().stream().anyMatch(cc -> cc.groupID.equals(groupid) && cc.mcchannel.ID.equals(chan.get().ID))) { /*if (MCChatListener.getCustomChats().stream().anyMatch(cc -> cc.groupID.equals(groupid) && cc.mcchannel.ID.equals(chan.get().ID))) {
@ -128,16 +135,23 @@ public class ChannelconCommand extends ICommand2DC {
}*/ //TODO: "Channel admins" that can connect channels? }*/ //TODO: "Channel admins" that can connect channels?
MCChatCustom.addCustomChat(channel, groupid, chan.get(), author, dcp, 0, new HashSet<>()); MCChatCustom.addCustomChat(channel, groupid, chan.get(), author, dcp, 0, new HashSet<>());
if (chan.get() instanceof ChatRoom) if (chan.get() instanceof ChatRoom)
DPUtils.reply(message, null, "alright, connection made to the room!").subscribe(); DPUtils.reply(message, channel, "alright, connection made to the room!").subscribe();
else else
DPUtils.reply(message, null, "alright, connection made to group `" + groupid + "`!").subscribe(); DPUtils.reply(message, channel, "alright, connection made to group `" + groupid + "`!").subscribe();
return true; return true;
} }
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
private boolean checkPerms(Message message) { private boolean checkPerms(Message message, @Nullable MessageChannel channel) {
if (!message.getAuthorAsMember().block().getBasePermissions().block().contains(Permission.MANAGE_CHANNELS)) { if (channel == null)
DPUtils.reply(message, null, "you need to have manage permissions for this channel!").subscribe(); channel = message.getChannel().block();
if (!(channel instanceof GuildChannel)) {
DPUtils.reply(message, channel, "you can only use this command in a server!").subscribe();
return true;
}
var perms = ((GuildChannel) channel).getEffectivePermissions(message.getAuthor().map(User::getId).get()).block();
if (!perms.contains(Permission.ADMINISTRATOR) && !perms.contains(Permission.MANAGE_CHANNELS)) {
DPUtils.reply(message, channel, "you need to have manage permissions for this channel!").subscribe();
return true; return true;
} }
return false; return false;
@ -145,17 +159,17 @@ public class ChannelconCommand extends ICommand2DC {
@Override @Override
public String[] getHelpText(Method method, Command2.Subcommand ann) { public String[] getHelpText(Method method, Command2.Subcommand ann) {
return new String[]{ // return new String[]{ //
"Channel connect", // "Channel connect", //
"This command allows you to connect a Minecraft channel to a Discord channel (just like how the global chat is connected to #minecraft-chat).", // "This command allows you to connect a Minecraft channel to a Discord channel (just like how the global chat is connected to #minecraft-chat).", //
"You need to have access to the MC channel and have manage permissions on the Discord channel.", // "You need to have access to the MC channel and have manage permissions on the Discord channel.", //
"You also need to have your Minecraft account connected. In " + DPUtils.botmention() + " use " + DiscordPlugin.getPrefix() + "connect <mcname>.", // "You also need to have your Minecraft account connected. In " + DPUtils.botmention() + " use " + DiscordPlugin.getPrefix() + "connect <mcname>.", //
"Call this command from the channel you want to use.", // "Call this command from the channel you want to use.", //
"Usage: " + Objects.requireNonNull(DiscordPlugin.dc.getSelf().block()).getMention() + " channelcon <mcchannel>", // "Usage: " + Objects.requireNonNull(DiscordPlugin.dc.getSelf().block()).getMention() + " channelcon <mcchannel>", //
"Use the ID (command) of the channel, for example `g` for the global chat.", // "Use the ID (command) of the channel, for example `g` for the global chat.", //
"To remove a connection use @ChromaBot channelcon remove in the channel.", // "To remove a connection use @ChromaBot channelcon remove in the channel.", //
"Mentioning the bot is needed in this case because the " + DiscordPlugin.getPrefix() + " prefix only works in " + DPUtils.botmention() + ".", // "Mentioning the bot is needed in this case because the " + DiscordPlugin.getPrefix() + " prefix only works in " + DPUtils.botmention() + ".", //
"Invite link: <https://discordapp.com/oauth2/authorize?client_id=" + DiscordPlugin.dc.getApplicationInfo().map(info -> info.getId().asString()).blockOptional().orElse("Unknown") + "&scope=bot&permissions=268509264>" "Invite link: <https://discordapp.com/oauth2/authorize?client_id=" + DiscordPlugin.dc.getApplicationInfo().map(info -> info.getId().asString()).blockOptional().orElse("Unknown") + "&scope=bot&permissions=268509264>"
}; };
} }
} }

View file

@ -33,13 +33,13 @@ public class MCChatCommand extends ICommand2DC {
val channel = message.getChannel().block(); val channel = message.getChannel().block();
@SuppressWarnings("OptionalGetWithoutIsPresent") val author = message.getAuthor().get(); @SuppressWarnings("OptionalGetWithoutIsPresent") val author = message.getAuthor().get();
if (!(channel instanceof PrivateChannel)) { if (!(channel instanceof PrivateChannel)) {
DPUtils.reply(message, null, "this command can only be issued in a direct message with the bot.").subscribe(); DPUtils.reply(message, channel, "this command can only be issued in a direct message with the bot.").subscribe();
return true; return true;
} }
try (final DiscordPlayer user = DiscordPlayer.getUser(author.getId().asString(), DiscordPlayer.class)) { try (final DiscordPlayer user = DiscordPlayer.getUser(author.getId().asString(), DiscordPlayer.class)) {
boolean mcchat = !user.isMinecraftChatEnabled(); boolean mcchat = !user.isMinecraftChatEnabled();
MCChatPrivate.privateMCChat(channel, mcchat, author, user); MCChatPrivate.privateMCChat(channel, mcchat, author, user);
DPUtils.reply(message, null, "Minecraft chat " + (mcchat // DPUtils.reply(message, channel, "Minecraft chat " + (mcchat //
? "enabled. Use '" + DiscordPlugin.getPrefix() + "mcchat' again to turn it off." // ? "enabled. Use '" + DiscordPlugin.getPrefix() + "mcchat' again to turn it off." //
: "disabled.")).subscribe(); : "disabled.")).subscribe();
} catch (Exception e) { } catch (Exception e) {