Skip to content

Commit a3099d2

Browse files
committed
Added command privilege stuff.
1 parent 589bae5 commit a3099d2

40 files changed

Lines changed: 417 additions & 369 deletions

‎README.md‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,25 @@ The file must contain a Discord Bot Token and a MongoDB Connection String.
1313
token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1414
mongologin=mongodb+srv\://<USER>\:<PASSWORD>@<CLUSTERURL>
1515
```
16+
17+
# Commands
18+
Commands are defined in this bot using a `commands.yaml` configuration file. The data in this file is transformed at startup time into an array of `com.javadiscord.javabot.properties.command.CommandConfig` objects using JSON deserialization.
19+
20+
These commands are then used by `com.javadiscord.javabot.SlashCommands#registerSlashCommands(Guild)` to register the defined commands as Discord slash commands which become available to users in guilds and private messages with the bot.
21+
22+
**Each command MUST define a `handler` property, whose name is the fully-qualified class name of a `SlashCommandHandler`.** When registering commands, the bot will look for such a class, and attempt to create a new instance of it using a no-args constructor. Therefore, make sure that your handler class has a no-args constructor.
23+
24+
## Privileges
25+
To specify that a command should only be allowed to be executed by certain people, you can specify a list of privileges. For example:
26+
```yaml
27+
- name: jam-admin
28+
description: Administrator actions for configuring the Java Jam.
29+
handler: com.javadiscord.javabot.jam.JamAdminCommandHandler
30+
enabledByDefault: false
31+
privileges:
32+
- type: ROLE
33+
id: jam_admin_rid
34+
- type: USER
35+
id: 235439851263098880
36+
```
37+
In this example, we define that the `jam-admin` command is first of all, *not enabled by default*, and also we say that anyone from the `jam_admin_rid` role (as found using `new Database().getConfigRole(guild, "roles." + this.id);` from the MongoDB). Additionally, we also say that the user whose id is `235439851263098880` is allowed to use this command.

‎src/main/java/com/javadiscord/javabot/SlashCommands.java‎

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.google.gson.JsonParser;
55
import com.javadiscord.javabot.commands.SlashCommandHandler;
66
import com.javadiscord.javabot.other.Constants;
7+
import com.javadiscord.javabot.other.Database;
78
import com.javadiscord.javabot.properties.command.CommandConfig;
89
import com.javadiscord.javabot.properties.command.CommandDataConfig;
910
import com.mongodb.BasicDBObject;
@@ -14,12 +15,17 @@
1415
import net.dv8tion.jda.api.entities.Guild;
1516
import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
1617
import net.dv8tion.jda.api.hooks.ListenerAdapter;
18+
import net.dv8tion.jda.api.interactions.commands.Command;
1719
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
20+
import net.dv8tion.jda.api.interactions.commands.privileges.CommandPrivilege;
1821
import net.dv8tion.jda.api.requests.restaction.CommandListUpdateAction;
1922
import org.bson.Document;
23+
import org.slf4j.Logger;
24+
import org.slf4j.LoggerFactory;
2025

21-
import java.util.HashMap;
22-
import java.util.Map;
26+
import java.util.*;
27+
import java.util.concurrent.ExecutionException;
28+
import java.util.concurrent.Executors;
2329

2430
import static com.javadiscord.javabot.events.Startup.mongoClient;
2531
import static com.mongodb.client.model.Filters.eq;
@@ -34,6 +40,8 @@
3440
* </p>
3541
*/
3642
public class SlashCommands extends ListenerAdapter {
43+
private static final Logger log = LoggerFactory.getLogger(SlashCommands.class);
44+
3745
/**
3846
* Maps every command name and alias to an instance of the command, for
3947
* constant-time lookup.
@@ -84,9 +92,24 @@ public void onSlashCommand(SlashCommandEvent event) {
8492
* @param guild The guild to update commands for.
8593
*/
8694
public void registerSlashCommands(Guild guild) {
87-
CommandListUpdateAction commands = guild.updateCommands();
88-
8995
CommandConfig[] commandConfigs = CommandDataConfig.load();
96+
var commandUpdateAction = this.updateCommands(commandConfigs, guild);
97+
this.updateCustomCommands(commandUpdateAction, guild);
98+
99+
// Add privileges to the commands, after the commands have been registered.
100+
commandUpdateAction.queue(commands -> Executors.newSingleThreadExecutor().submit(() ->{
101+
try {
102+
this.addCommandPrivileges(commands, commandConfigs, guild);
103+
} catch (InterruptedException | ExecutionException e) {
104+
log.error("Could not add command privileges.", e);
105+
}
106+
}));
107+
}
108+
109+
private CommandListUpdateAction updateCommands(CommandConfig[] commandConfigs, Guild guild) {
110+
log.info("Registering slash commands.");
111+
if (commandConfigs.length > 100) throw new IllegalArgumentException("Cannot add more than 100 commands.");
112+
CommandListUpdateAction commandUpdateAction = guild.updateCommands();
90113
for (CommandConfig config : commandConfigs) {
91114
if (config.getHandler() != null && !config.getHandler().isEmpty()) {
92115
try {
@@ -96,25 +119,51 @@ public void registerSlashCommands(Guild guild) {
96119
e.printStackTrace();
97120
}
98121
} else {
99-
System.err.println("Warning: Command \"" + config.getName() + "\" does not have an associated handler class. It will be ignored.");
122+
log.warn("Command \"{}\" does not have an associated handler class. It will be ignored.", config.getName());
100123
}
101-
commands.addCommands(config.toData());
124+
commandUpdateAction.addCommands(config.toData());
102125
}
126+
return commandUpdateAction;
127+
}
103128

129+
private void updateCustomCommands(CommandListUpdateAction commandUpdateAction, Guild guild) {
130+
log.info("Registering custom commands.");
104131
MongoDatabase database = mongoClient.getDatabase("other");
105132
MongoCollection<Document> collection = database.getCollection("customcommands");
106133
MongoCursor<Document> it = collection.find(eq("guild_id", guild.getId())).iterator();
107134

108135
while (it.hasNext()) {
109-
110136
JsonObject Root = JsonParser.parseString(it.next().toJson()).getAsJsonObject();
111137
String commandName = Root.get("commandname").getAsString();
112138
String value = Root.get("value").getAsString();
113-
114139
if (value.length() > 100) value = value.substring(0, 97) + "...";
115-
commands.addCommands(new CommandData(commandName, value));
140+
commandUpdateAction.addCommands(new CommandData(commandName, value));
116141
}
142+
}
117143

118-
commands.queue();
144+
private void addCommandPrivileges(List<Command> commands, CommandConfig[] commandConfigs, Guild guild) throws ExecutionException, InterruptedException {
145+
log.info("Adding command privileges.");
146+
var db = new Database();
147+
for (var config : commandConfigs) {
148+
Long commandId = null;
149+
for (Command command : commands) {
150+
if (command.getName().equals(config.getName())) {
151+
commandId = command.getIdLong();
152+
break;
153+
}
154+
}
155+
if (commandId == null) throw new IllegalStateException("Could not find id for command " + config.getName());
156+
final long cid = commandId;
157+
if (config.getPrivileges() != null) {
158+
List<CommandPrivilege> p = new ArrayList<>();
159+
for (var privilegeConfig : config.getPrivileges()) {
160+
p.add(privilegeConfig.toData(guild, db).get());
161+
log.info("Registering privilege for command {}: {}", config.getName(), Objects.toString(privilegeConfig));
162+
}
163+
guild.updateCommandPrivilegesById(cid, p).queue(commandPrivileges -> {
164+
log.info("Privilege update successful for command {}", config.getName());
165+
});
166+
}
167+
}
119168
}
120169
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.javadiscord.javabot.commands;
2+
3+
import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
4+
5+
import java.util.Map;
6+
7+
/**
8+
* Abstract command handler which is useful for commands which consist of lots
9+
* of subcommands. A child class will supply a map of subcommand handlers, so
10+
* that this parent handler can do the logic of finding the right subcommand to
11+
* invoke depending on the event received.
12+
*/
13+
public class DelegatingCommandHandler implements SlashCommandHandler {
14+
private final Map<String, SlashCommandHandler> subcommandHandlers;
15+
16+
public DelegatingCommandHandler(Map<String, SlashCommandHandler> subcommandHandlers) {
17+
this.subcommandHandlers = subcommandHandlers;
18+
}
19+
20+
@Override
21+
public void handle(SlashCommandEvent event) {
22+
if (event.getSubcommandName() == null) {
23+
this.handleNonSubcommand(event);
24+
} else {
25+
SlashCommandHandler handler = this.subcommandHandlers.get(event.getSubcommandName());
26+
if (handler != null) {
27+
handler.handle(event);
28+
} else {
29+
event.getHook().setEphemeral(true);
30+
event.getHook().sendMessage("Unknown subcommand.").queue();
31+
}
32+
}
33+
}
34+
35+
protected void handleNonSubcommand(SlashCommandEvent event) {
36+
event.getHook().setEphemeral(true);
37+
event.getHook().sendMessage("Please specify a subcommand.").queue();
38+
}
39+
}

‎src/main/java/com/javadiscord/javabot/commands/jam/JamCommandHandler.java‎

Lines changed: 0 additions & 73 deletions
This file was deleted.

‎src/main/java/com/javadiscord/javabot/commands/jam/model/JamSubmissionVote.java‎

Lines changed: 0 additions & 4 deletions
This file was deleted.

‎src/main/java/com/javadiscord/javabot/commands/jam/model/JamThemeVote.java‎

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.javadiscord.javabot.jam;
2+
3+
import com.javadiscord.javabot.commands.DelegatingCommandHandler;
4+
import com.javadiscord.javabot.jam.subcommands.admin.*;
5+
6+
import java.util.Map;
7+
8+
public class JamAdminCommandHandler extends DelegatingCommandHandler {
9+
public JamAdminCommandHandler() {
10+
super(Map.of(
11+
"plan-new-jam", new PlanNewJamSubcommand(),
12+
"add-theme", new AddThemeSubcommand(),
13+
"list-themes", new ListThemesSubcommand(),
14+
"remove-theme", new RemoveThemeSubcommand(),
15+
"next-phase", new NextPhaseSubcommand(),
16+
"list-submissions", new ListSubmissionsSubcommand(),
17+
"remove-submissions", new RemoveSubmissionsSubcommand(),
18+
"cancel", new CancelSubcommand()
19+
));
20+
}
21+
}

src/main/java/com/javadiscord/javabot/commands/jam/JamChannelManager.java renamed to src/main/java/com/javadiscord/javabot/jam/JamChannelManager.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
package com.javadiscord.javabot.commands.jam;
1+
package com.javadiscord.javabot.jam;
22

33
import com.javadiscord.javabot.Bot;
4-
import com.javadiscord.javabot.commands.jam.model.Jam;
5-
import com.javadiscord.javabot.commands.jam.model.JamSubmission;
6-
import com.javadiscord.javabot.commands.jam.model.JamTheme;
4+
import com.javadiscord.javabot.jam.model.Jam;
5+
import com.javadiscord.javabot.jam.model.JamSubmission;
6+
import com.javadiscord.javabot.jam.model.JamTheme;
77
import com.javadiscord.javabot.other.Colors;
88
import com.javadiscord.javabot.other.Database;
99
import net.dv8tion.jda.api.EmbedBuilder;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.javadiscord.javabot.jam;
2+
3+
import com.javadiscord.javabot.commands.DelegatingCommandHandler;
4+
import com.javadiscord.javabot.jam.subcommands.JamInfoSubcommand;
5+
import com.javadiscord.javabot.jam.subcommands.JamSubmitSubcommand;
6+
7+
import java.util.Map;
8+
9+
/**
10+
* Main command handler for Jam commands.
11+
*/
12+
public class JamCommandHandler extends DelegatingCommandHandler {
13+
public JamCommandHandler() {
14+
super(Map.of(
15+
"info", new JamInfoSubcommand(),
16+
"submit", new JamSubmitSubcommand()
17+
));
18+
}
19+
}

src/main/java/com/javadiscord/javabot/commands/jam/JamPhaseManager.java renamed to src/main/java/com/javadiscord/javabot/jam/JamPhaseManager.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
package com.javadiscord.javabot.commands.jam;
1+
package com.javadiscord.javabot.jam;
22

33
import com.javadiscord.javabot.Bot;
4-
import com.javadiscord.javabot.commands.jam.model.Jam;
5-
import com.javadiscord.javabot.commands.jam.model.JamPhase;
6-
import com.javadiscord.javabot.commands.jam.phase_transitions.*;
4+
import com.javadiscord.javabot.jam.model.Jam;
5+
import com.javadiscord.javabot.jam.model.JamPhase;
6+
import com.javadiscord.javabot.jam.phase_transitions.*;
77
import com.javadiscord.javabot.other.Database;
88
import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
99
import org.slf4j.Logger;

0 commit comments

Comments
 (0)