|
|
|
@ -0,0 +1,360 @@
|
|
|
|
|
package net.pingex.discordbot;
|
|
|
|
|
|
|
|
|
|
import com.google.gson.Gson;
|
|
|
|
|
import com.google.gson.GsonBuilder;
|
|
|
|
|
import com.google.gson.reflect.TypeToken;
|
|
|
|
|
import net.pingex.discordbot.json.permissions.Guild;
|
|
|
|
|
import sx.blah.discord.api.IDiscordClient;
|
|
|
|
|
import sx.blah.discord.handle.impl.events.MessageReceivedEvent;
|
|
|
|
|
import sx.blah.discord.handle.obj.IGuild;
|
|
|
|
|
import sx.blah.discord.handle.obj.IRole;
|
|
|
|
|
import sx.blah.discord.handle.obj.IUser;
|
|
|
|
|
import sx.blah.discord.util.DiscordException;
|
|
|
|
|
import sx.blah.discord.util.HTTP429Exception;
|
|
|
|
|
import sx.blah.discord.util.MissingPermissionsException;
|
|
|
|
|
import java.io.*;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Permissions modules.
|
|
|
|
|
* @version 0.1-dev
|
|
|
|
|
* @author Raphael "Pingex" NAAS
|
|
|
|
|
*/
|
|
|
|
|
@Controllable(name="perm")
|
|
|
|
|
class PermissionsModule extends AbstractModule
|
|
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* Main permissions table
|
|
|
|
|
*/
|
|
|
|
|
private HashMap<String, Guild> permissions;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Gson instance for json (de)serialisation
|
|
|
|
|
*/
|
|
|
|
|
private static Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Current instance of this module, for easier access
|
|
|
|
|
*/
|
|
|
|
|
private static PermissionsModule INSTANCE = null;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the current instance of this module
|
|
|
|
|
* @return This instance
|
|
|
|
|
*/
|
|
|
|
|
public static PermissionsModule getInstance()
|
|
|
|
|
{
|
|
|
|
|
return INSTANCE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructor doing all the basic stuff, like registering as a Listener to Discord, getting a logger, etc.
|
|
|
|
|
* @param client Discord Client instance used to register self.
|
|
|
|
|
*/
|
|
|
|
|
public PermissionsModule(IDiscordClient client)
|
|
|
|
|
{
|
|
|
|
|
super(client);
|
|
|
|
|
INSTANCE = this;
|
|
|
|
|
|
|
|
|
|
if(!Configuration.exists("permissions", "file") || Configuration.getValue("permissions", "file").isEmpty())
|
|
|
|
|
{
|
|
|
|
|
logger.warning("Permissions file location not specified, defaulting to `permissions.json`");
|
|
|
|
|
Configuration.setValue("permissions", "file", "permissions.json");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reloadPermissions();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Gives the UID of the User passed as arguments
|
|
|
|
|
* @param name The current name of the user
|
|
|
|
|
* @param discriminator His discriminator
|
|
|
|
|
* @return The ID of the target user
|
|
|
|
|
*/
|
|
|
|
|
@Command
|
|
|
|
|
public String getUID(MessageReceivedEvent event, String name, String discriminator)
|
|
|
|
|
{
|
|
|
|
|
for(IUser i : event.getMessage().getGuild().getUsers())
|
|
|
|
|
if(i.getName().equals(name) && i.getDiscriminator().equals(discriminator))
|
|
|
|
|
return i.getID();
|
|
|
|
|
return "User not found";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Gets caller's UID
|
|
|
|
|
* @return Caller's UID
|
|
|
|
|
*/
|
|
|
|
|
@Command
|
|
|
|
|
public String getMyUID(MessageReceivedEvent event)
|
|
|
|
|
{
|
|
|
|
|
return event.getMessage().getAuthor().getID();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Give GID of the named role
|
|
|
|
|
* @param name The role current name
|
|
|
|
|
* @return The GID of the role
|
|
|
|
|
*/
|
|
|
|
|
@Command
|
|
|
|
|
public String getGID(MessageReceivedEvent event, String name)
|
|
|
|
|
{
|
|
|
|
|
for(IRole i : event.getMessage().getGuild().getRoles())
|
|
|
|
|
if(i.getName().equals(name))
|
|
|
|
|
return i.getID();
|
|
|
|
|
return "Role not found";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Dump all Roles and their GID
|
|
|
|
|
* Note: this commands answers the dump via PM to avoid spam and the @everyone role to be publicly displayed thus notify everyone in the guild.
|
|
|
|
|
* @return The whole dump, formatted as a displayable String
|
|
|
|
|
*/
|
|
|
|
|
@Command
|
|
|
|
|
public String dumpGID(MessageReceivedEvent event)
|
|
|
|
|
{
|
|
|
|
|
StringBuffer buffer = new StringBuffer("Dumping Roles for Guild ").append(event.getMessage().getGuild().getName()).append("\n");
|
|
|
|
|
for(IRole i : event.getMessage().getGuild().getRoles())
|
|
|
|
|
buffer.append(i.getName()).append("\t").append(i.getID()).append("\n");
|
|
|
|
|
|
|
|
|
|
// PM the IDs
|
|
|
|
|
// TODO: Remove when PM answers are implemented
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
client.getOrCreatePMChannel(event.getMessage().getAuthor()).sendMessage(buffer.toString());
|
|
|
|
|
} catch (MissingPermissionsException | HTTP429Exception | DiscordException e)
|
|
|
|
|
{
|
|
|
|
|
logger.warning("Fail to send the result");
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
return "Check your PM for the command result";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Dump all Users and their UID
|
|
|
|
|
* Note: this commands answers the dump via PM to avoid spam.
|
|
|
|
|
* @return The whole dump, formatted as a displayable String
|
|
|
|
|
*/
|
|
|
|
|
@Command
|
|
|
|
|
public String dumpUID(MessageReceivedEvent event)
|
|
|
|
|
{
|
|
|
|
|
StringBuffer buffer = new StringBuffer("Dumping all users for Guild ").append(event.getMessage().getGuild().getName()).append("\n");
|
|
|
|
|
for(IUser i : event.getMessage().getGuild().getUsers())
|
|
|
|
|
buffer.append(i.getName()).append("#").append(i.getDiscriminator()).append("\t").append(i.getID()).append("\n");
|
|
|
|
|
|
|
|
|
|
// PM the IDs
|
|
|
|
|
// TODO: Remove when PM answers are implemented
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
client.getOrCreatePMChannel(event.getMessage().getAuthor()).sendMessage(buffer.toString());
|
|
|
|
|
} catch (MissingPermissionsException | HTTP429Exception | DiscordException e)
|
|
|
|
|
{
|
|
|
|
|
logger.warning("Fail to send the result");
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
return "Check your PM for the command result";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Reload permissions from file
|
|
|
|
|
* @return Nothing
|
|
|
|
|
*/
|
|
|
|
|
@Command
|
|
|
|
|
public String reload(MessageReceivedEvent event)
|
|
|
|
|
{
|
|
|
|
|
reloadPermissions();
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Save permissions to file
|
|
|
|
|
* @return Nothing
|
|
|
|
|
*/
|
|
|
|
|
@Command
|
|
|
|
|
public String save(MessageReceivedEvent event)
|
|
|
|
|
{
|
|
|
|
|
writePermissions();
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets an user permission
|
|
|
|
|
* @param command The target *full* command, shorthands doesn't work
|
|
|
|
|
* @param user The user's UID
|
|
|
|
|
* @param target `true` to allow execution of the command, `false` to deny it, `null` to remove the rule
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
@Command
|
|
|
|
|
public String setUser(MessageReceivedEvent event, String command, String user, Boolean target)
|
|
|
|
|
{
|
|
|
|
|
if(!permissions.containsKey(event.getMessage().getGuild().getID()))
|
|
|
|
|
permissions.put(event.getMessage().getGuild().getID(), new Guild(new HashMap<>()));
|
|
|
|
|
Guild g = permissions.get(event.getMessage().getGuild().getID());
|
|
|
|
|
|
|
|
|
|
if(!g.commands.containsKey(command))
|
|
|
|
|
g.commands.put(command, new net.pingex.discordbot.json.permissions.Command(new HashMap<>(), new HashMap<>()));
|
|
|
|
|
net.pingex.discordbot.json.permissions.Command c = g.commands.get(command);
|
|
|
|
|
|
|
|
|
|
if(target == null) c.users.remove(user);
|
|
|
|
|
else c.users.put(user, target);
|
|
|
|
|
|
|
|
|
|
return "OK";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets a role permission
|
|
|
|
|
* @param command The target *full* command, shorthands doesn't work
|
|
|
|
|
* @param group The role's GID
|
|
|
|
|
* @param target `true` to allow execution of the command, `false` to deny it, `null` to remove the rule
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
@Command
|
|
|
|
|
public String setRole(MessageReceivedEvent event, String command, String group, Boolean target)
|
|
|
|
|
{
|
|
|
|
|
if(!permissions.containsKey(event.getMessage().getGuild().getID()))
|
|
|
|
|
permissions.put(event.getMessage().getGuild().getID(), new Guild(new HashMap<>()));
|
|
|
|
|
Guild g = permissions.get(event.getMessage().getGuild().getID());
|
|
|
|
|
|
|
|
|
|
if(!g.commands.containsKey(command))
|
|
|
|
|
g.commands.put(command, new net.pingex.discordbot.json.permissions.Command(new HashMap<>(), new HashMap<>()));
|
|
|
|
|
net.pingex.discordbot.json.permissions.Command c = g.commands.get(command);
|
|
|
|
|
|
|
|
|
|
if(target == null) c.roles.remove(group);
|
|
|
|
|
else c.roles.put(group, target);
|
|
|
|
|
|
|
|
|
|
return "OK";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Dump all permissions defined for the current guild
|
|
|
|
|
* @return Displayable String of the permissions
|
|
|
|
|
*/
|
|
|
|
|
@Command(shorthand = "dumpPerm")
|
|
|
|
|
public String dumpPermissions(MessageReceivedEvent event)
|
|
|
|
|
{
|
|
|
|
|
StringBuffer buffer = new StringBuffer("Dumping all permissions for Guild ").append(event.getMessage().getGuild().getName()).append("\n\n```");
|
|
|
|
|
|
|
|
|
|
if(!permissions.containsKey(event.getMessage().getGuild().getID()))
|
|
|
|
|
return "No permissions set for Guild";
|
|
|
|
|
Guild g = permissions.get(event.getMessage().getGuild().getID());
|
|
|
|
|
|
|
|
|
|
for(Map.Entry<String, net.pingex.discordbot.json.permissions.Command> i : g.commands.entrySet())
|
|
|
|
|
{
|
|
|
|
|
buffer.append("========== COMMAND ").append(i.getKey()).append(" ==========\n");
|
|
|
|
|
|
|
|
|
|
// USERS
|
|
|
|
|
buffer.append("----- Users -----\n");
|
|
|
|
|
for(Map.Entry<String, Boolean> j : i.getValue().users.entrySet())
|
|
|
|
|
{
|
|
|
|
|
buffer.append(j.getKey()).append("\t").append(j.getValue()).append("\n");
|
|
|
|
|
}
|
|
|
|
|
buffer.append("\n");
|
|
|
|
|
|
|
|
|
|
// GROUPS
|
|
|
|
|
buffer.append("----- Roles -----\n");
|
|
|
|
|
for(Map.Entry<String, Boolean> j : i.getValue().roles.entrySet())
|
|
|
|
|
{
|
|
|
|
|
buffer.append(j.getKey()).append("\t").append(j.getValue()).append("\n");
|
|
|
|
|
}
|
|
|
|
|
buffer.append("\n\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buffer.append("```");
|
|
|
|
|
return buffer.toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Says if the permissions overrider will allow the target user to run the target command
|
|
|
|
|
* @param user User name
|
|
|
|
|
* @param discriminator His discriminator
|
|
|
|
|
* @param command The target command
|
|
|
|
|
* @return `YES` if he can run it, `NO` if he can't, `N/A` if the decision relies to the default behavior
|
|
|
|
|
*/
|
|
|
|
|
@Command
|
|
|
|
|
public String canRun(MessageReceivedEvent event, String user, String discriminator, String command)
|
|
|
|
|
{
|
|
|
|
|
IUser target = null;
|
|
|
|
|
|
|
|
|
|
for(IUser i : event.getMessage().getGuild().getUsers())
|
|
|
|
|
if(i.getName().equals(user) && i.getDiscriminator().equals(discriminator))
|
|
|
|
|
{
|
|
|
|
|
target = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(target == null)
|
|
|
|
|
return "User not found in this Guild.";
|
|
|
|
|
|
|
|
|
|
Boolean toReturn = canRun(event.getMessage().getGuild(), target, command);
|
|
|
|
|
return toReturn == null ? "N/A" : (toReturn ? "YES" : "NO");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Says if the permissions overrider will allow the target user to run the target command. To be run internally
|
|
|
|
|
* @param guild The current guild
|
|
|
|
|
* @param user The target user
|
|
|
|
|
* @param command The target command
|
|
|
|
|
* @return `true` is he can run the command, `false` if he can't, `null` if the overrider has nothing to say
|
|
|
|
|
*/
|
|
|
|
|
public Boolean canRun(IGuild guild, IUser user, String command)
|
|
|
|
|
{
|
|
|
|
|
// Return null if command or guild aren't mentioned in the permissions file
|
|
|
|
|
if(!permissions.containsKey(guild.getID()) || !permissions.get(guild.getID()).commands.containsKey(command)) return null;
|
|
|
|
|
net.pingex.discordbot.json.permissions.Command c = permissions.get(guild.getID()).commands.get(command);
|
|
|
|
|
|
|
|
|
|
// User matching
|
|
|
|
|
if(c.users.containsKey(user.getID()))
|
|
|
|
|
return c.users.get(user.getID());
|
|
|
|
|
|
|
|
|
|
// Role matching
|
|
|
|
|
for(IRole i : user.getRolesForGuild(guild))
|
|
|
|
|
{
|
|
|
|
|
if(c.roles.containsKey(i.getID()))
|
|
|
|
|
return c.roles.get(i.getID());
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Reloads the permissions file. Discards the current permissions cache
|
|
|
|
|
*/
|
|
|
|
|
private void reloadPermissions()
|
|
|
|
|
{
|
|
|
|
|
logger.info("Reloading permissions");
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
FileReader reader = new FileReader(Configuration.getValue("permissions", "file"));
|
|
|
|
|
permissions = gson.fromJson(reader, new TypeToken<HashMap<String, Guild>>(){}.getType());
|
|
|
|
|
reader.close();
|
|
|
|
|
}
|
|
|
|
|
catch (FileNotFoundException e)
|
|
|
|
|
{
|
|
|
|
|
logger.info("File doesn't exist, using default permissions");
|
|
|
|
|
permissions = new HashMap<>();
|
|
|
|
|
}
|
|
|
|
|
catch (IOException e)
|
|
|
|
|
{
|
|
|
|
|
logger.severe("I/O error while reading permissions file");
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Write the current HashMap to file.
|
|
|
|
|
*/
|
|
|
|
|
private void writePermissions()
|
|
|
|
|
{
|
|
|
|
|
logger.info("Writing permissions");
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
FileWriter writer = new FileWriter(Configuration.getValue("permissions", "file"));
|
|
|
|
|
writer.write(gson.toJson(permissions));
|
|
|
|
|
writer.close();
|
|
|
|
|
}
|
|
|
|
|
catch (IOException e)
|
|
|
|
|
{
|
|
|
|
|
logger.severe("I/O error while writing permissions file");
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|