diff --git a/src/Discord.Net.Commands.Net45/Discord.Net.Commands.csproj b/src/Discord.Net.Commands.Net45/Discord.Net.Commands.csproj
index 3a77ea6ed..b2c6076de 100644
--- a/src/Discord.Net.Commands.Net45/Discord.Net.Commands.csproj
+++ b/src/Discord.Net.Commands.Net45/Discord.Net.Commands.csproj
@@ -61,6 +61,39 @@
CommandServiceConfig.cs
+
+ Permissions\IPermissionChecker.cs
+
+
+ Permissions\Levels\PermissionLevelChecker.cs
+
+
+ Permissions\Levels\PermissionLevelExtensions.cs
+
+
+ Permissions\Levels\PermissionLevelService.cs
+
+
+ Permissions\Userlist\BlacklistChecker.cs
+
+
+ Permissions\Userlist\BlacklistExtensions.cs
+
+
+ Permissions\Userlist\BlacklistService.cs
+
+
+ Permissions\Userlist\UserlistService.cs
+
+
+ Permissions\Userlist\WhitelistChecker.cs
+
+
+ Permissions\Userlist\WhitelistExtensions.cs
+
+
+ Permissions\Userlist\WhitelistService.cs
+
diff --git a/src/Discord.Net.Commands/Command.cs b/src/Discord.Net.Commands/Command.cs
index 548ef2bc9..a91251f88 100644
--- a/src/Discord.Net.Commands/Command.cs
+++ b/src/Discord.Net.Commands/Command.cs
@@ -1,4 +1,5 @@
-using System;
+using Discord.Commands.Permissions;
+using System;
using System.Collections.Generic;
using System.Threading.Tasks;
@@ -41,8 +42,9 @@ namespace Discord.Commands
public IEnumerable Parameters => _parameters;
internal CommandParameter[] _parameters;
-
- private Func _handler;
+
+ private IPermissionChecker[] _checks;
+ private Func _runFunc;
internal Command(string text)
{
@@ -56,7 +58,6 @@ namespace Discord.Commands
{
_aliases = aliases;
}
-
internal void SetParameters(CommandParameter[] parameters)
{
_parameters = parameters;
@@ -89,24 +90,32 @@ namespace Discord.Commands
}
}
}
-
- internal void SetHandler(Func func)
- {
- _handler = func;
- }
- internal void SetHandler(Action func)
+ internal void SetChecks(IPermissionChecker[] checks)
{
- _handler = e => { func(e); return TaskHelper.CompletedTask; };
+ _checks = checks;
}
internal bool CanRun(User user, Channel channel)
{
+ for (int i = 0; i < _checks.Length; i++)
+ {
+ if (!_checks[i].CanRun(this, user, channel))
+ return false;
+ }
return true;
}
+ internal void SetRunFunc(Func func)
+ {
+ _runFunc = func;
+ }
+ internal void SetRunFunc(Action func)
+ {
+ _runFunc = e => { func(e); return TaskHelper.CompletedTask; };
+ }
internal Task Run(CommandEventArgs args)
{
- var task = _handler(args);
+ var task = _runFunc(args);
if (task != null)
return task;
else
diff --git a/src/Discord.Net.Commands/CommandBuilder.cs b/src/Discord.Net.Commands/CommandBuilder.cs
index 67f7e0c1a..6f11e3f26 100644
--- a/src/Discord.Net.Commands/CommandBuilder.cs
+++ b/src/Discord.Net.Commands/CommandBuilder.cs
@@ -1,4 +1,5 @@
-using System;
+using Discord.Commands.Permissions;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@@ -9,19 +10,27 @@ namespace Discord.Commands
{
private readonly CommandService _service;
private readonly Command _command;
- private List _params;
- private bool _allowRequired, _isClosed;
- private string _prefix;
+ private readonly List _params;
+ private readonly List _checks;
+ private readonly string _prefix;
+ private bool _allowRequiredParams, _areParamsClosed;
+
+ public CommandService Service => _service;
- internal CommandBuilder(CommandService service, Command command, string prefix, string category)
+ internal CommandBuilder(CommandService service, Command command, string prefix = "", string category = "", IEnumerable initialChecks = null)
{
_service = service;
_command = command;
_command.Category = category;
_params = new List();
+ if (initialChecks != null)
+ _checks = new List(initialChecks);
+ else
+ _checks = new List();
_prefix = prefix;
- _allowRequired = true;
- _isClosed = false;
+
+ _allowRequiredParams = true;
+ _areParamsClosed = false;
}
public CommandBuilder Alias(params string[] aliases)
@@ -35,24 +44,24 @@ namespace Discord.Commands
_command.Category = category;
return this;
}*/
- public CommandBuilder Info(string description)
+ public CommandBuilder Description(string description)
{
_command.Description = description;
return this;
}
public CommandBuilder Parameter(string name, ParameterType type = ParameterType.Required)
{
- if (_isClosed)
+ if (_areParamsClosed)
throw new Exception($"No parameters may be added after a {nameof(ParameterType.Multiple)} or {nameof(ParameterType.Unparsed)} parameter.");
- if (!_allowRequired && type == ParameterType.Required)
+ if (!_allowRequiredParams && type == ParameterType.Required)
throw new Exception($"{nameof(ParameterType.Required)} parameters may not be added after an optional one");
_params.Add(new CommandParameter(name, type));
if (type == ParameterType.Optional)
- _allowRequired = false;
+ _allowRequiredParams = false;
if (type == ParameterType.Multiple || type == ParameterType.Unparsed)
- _isClosed = true;
+ _areParamsClosed = true;
return this;
}
public CommandBuilder Hide()
@@ -60,20 +69,26 @@ namespace Discord.Commands
_command.IsHidden = true;
return this;
}
+ public CommandBuilder AddCheck(IPermissionChecker check)
+ {
+ _checks.Add(check);
+ return this;
+ }
public void Do(Func func)
{
- _command.SetHandler(func);
+ _command.SetRunFunc(func);
Build();
}
public void Do(Action func)
{
- _command.SetHandler(func);
+ _command.SetRunFunc(func);
Build();
}
private void Build()
{
_command.SetParameters(_params.ToArray());
+ _command.SetChecks(_checks.ToArray());
_service.AddCommand(_command);
}
@@ -97,14 +112,21 @@ namespace Discord.Commands
}
public sealed class CommandGroupBuilder
{
- internal readonly CommandService _service;
+ private readonly CommandService _service;
private readonly string _prefix;
+ private readonly List _checks;
private string _category;
- internal CommandGroupBuilder(CommandService service, string prefix)
+ public CommandService Service => _service;
+
+ internal CommandGroupBuilder(CommandService service, string prefix, IEnumerable initialChecks = null)
{
_service = service;
_prefix = prefix;
+ if (initialChecks != null)
+ _checks = new List(initialChecks);
+ else
+ _checks = new List();
}
public CommandGroupBuilder Category(string category)
@@ -112,10 +134,14 @@ namespace Discord.Commands
_category = category;
return this;
}
+ public void AddCheck(IPermissionChecker check)
+ {
+ _checks.Add(check);
+ }
public CommandGroupBuilder CreateGroup(string cmd, Action config = null)
- {
- config(new CommandGroupBuilder(_service, _prefix + ' ' + cmd));
+ {
+ config(new CommandGroupBuilder(_service, CommandBuilder.AppendPrefix(_prefix, cmd), _checks));
return this;
}
public CommandBuilder CreateCommand()
@@ -123,7 +149,7 @@ namespace Discord.Commands
public CommandBuilder CreateCommand(string cmd)
{
var command = new Command(CommandBuilder.AppendPrefix(_prefix, cmd));
- return new CommandBuilder(_service, command, _prefix, _category);
+ return new CommandBuilder(_service, command, _prefix, _category, _checks);
}
}
}
diff --git a/src/Discord.Net.Commands/CommandMap.cs b/src/Discord.Net.Commands/CommandMap.cs
index cceff23f9..4343cdd86 100644
--- a/src/Discord.Net.Commands/CommandMap.cs
+++ b/src/Discord.Net.Commands/CommandMap.cs
@@ -7,24 +7,26 @@ namespace Discord.Commands
internal class CommandMap
{
private readonly CommandMap _parent;
- private readonly string _text;
+ private readonly string _name, _fullName;
private Command _command;
private readonly Dictionary _items;
private bool _isHidden;
- public string Text => _text;
+ public string Name => _name;
+ public string FullName => _fullName;
public bool IsHidden => _isHidden;
public Command Command => _command;
public IEnumerable SubGroups => _items.Values;
/*public IEnumerable SubCommands => _items.Select(x => x.Value._command).Where(x => x != null);
public IEnumerable SubGroups => _items.Select(x => x.Value).Where(x => x._items.Count > 0);*/
- public CommandMap(CommandMap parent, string text)
+ public CommandMap(CommandMap parent, string name, string fullName)
{
_parent = parent;
- _text = text;
- _items = new Dictionary();
+ _name = name;
+ _fullName = fullName;
+ _items = new Dictionary();
_isHidden = true;
}
@@ -82,19 +84,20 @@ namespace Discord.Commands
{
AddCommand(0, text.Split(' '), command);
}
- public void AddCommand(int index, string[] parts, Command command)
+ private void AddCommand(int index, string[] parts, Command command)
{
if (!command.IsHidden && _isHidden)
_isHidden = false;
if (index != parts.Length)
{
- string nextPart = parts[index];
CommandMap nextGroup;
- if (!_items.TryGetValue(nextPart, out nextGroup))
+ string name = parts[index];
+ string fullName = string.Join(" ", parts, 0, index + 1);
+ if (!_items.TryGetValue(name, out nextGroup))
{
- nextGroup = new CommandMap(this, nextPart);
- _items.Add(nextPart, nextGroup);
+ nextGroup = new CommandMap(this, name, fullName);
+ _items.Add(name, nextGroup);
}
nextGroup.AddCommand(index + 1, parts, command);
}
diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs
index 24d475b79..7a3d984c7 100644
--- a/src/Discord.Net.Commands/CommandService.cs
+++ b/src/Discord.Net.Commands/CommandService.cs
@@ -9,8 +9,12 @@ namespace Discord.Commands
/// A Discord.Net client with extensions for handling common bot operations like text commands.
public partial class CommandService : IService
{
+ private readonly CommandServiceConfig _config;
+ private readonly CommandGroupBuilder _root;
private DiscordClient _client;
- public CommandServiceConfig Config { get; }
+
+ public DiscordClient Client => _client;
+ public CommandGroupBuilder Root => _root;
//AllCommands store a flattened collection of all commands
public IEnumerable AllCommands => _allCommands;
@@ -23,40 +27,47 @@ namespace Discord.Commands
internal IEnumerable Categories => _categories.Values;
private readonly Dictionary _categories;
-
public CommandService(CommandServiceConfig config)
{
- Config = config;
+ _config = config;
_allCommands = new List();
- _map = new CommandMap(null, null);
+ _map = new CommandMap(null, "", "");
_categories = new Dictionary();
- }
+ _root = new CommandGroupBuilder(this, "", null);
+ }
void IService.Install(DiscordClient client)
{
_client = client;
- Config.Lock();
+ _config.Lock();
- if (Config.HelpMode != HelpMode.Disable)
+ if (_config.HelpMode != HelpMode.Disable)
{
- CreateCommand("help")
+ CreateCommand("help")
.Parameter("command", ParameterType.Multiple)
.Hide()
- .Info("Returns information about commands.")
- .Do(async e =>
+ .Description("Returns information about commands.")
+ .Do((Func)(async e =>
{
- Channel channel = Config.HelpMode == HelpMode.Public ? e.Channel : await client.CreatePMChannel(e.User);
+ Channel replyChannel = _config.HelpMode == HelpMode.Public ? e.Channel : await client.CreatePMChannel(e.User);
if (e.Args.Length > 0) //Show command help
{
var map = _map.GetItem(string.Join(" ", e.Args));
if (map != null)
- await ShowHelp(map, e.User, channel);
+ await ShowCommandHelp(map, e.User, e.Channel, replyChannel);
else
- await client.SendMessage(channel, "Unable to display help: Unknown command.");
+ await client.SendMessage(replyChannel, "Unable to display help: Unknown command.");
}
else //Show general help
- await ShowHelp(e.User, channel);
- });
+
+/* Unmerged change from project 'Discord.Net.Commands'
+Before:
+ await ShowHelp(e.User, e.Channel, replyChannel);
+After:
+ await this.ShowHelp((User)e.User, e.Channel, replyChannel);
+*/
+ await this.ShowGeneralHelp(e.User, (Channel)e.Channel, (Channel)replyChannel);
+ }));
}
client.MessageReceived += async (s, e) =>
@@ -68,7 +79,7 @@ namespace Discord.Commands
if (msg.Length == 0) return;
//Check for command char if one is provided
- var chars = Config.CommandChars;
+ var chars = _config.CommandChars;
if (chars.Length > 0)
{
if (!chars.Contains(msg[0]))
@@ -121,7 +132,7 @@ namespace Discord.Commands
};
}
- public Task ShowHelp(User user, Channel channel)
+ public Task ShowGeneralHelp(User user, Channel channel, Channel replyChannel = null)
{
StringBuilder output = new StringBuilder();
/*output.AppendLine("These are the commands you can use:");
@@ -163,7 +174,7 @@ namespace Discord.Commands
else
output.Append(", ");
output.Append('`');
- output.Append(group.Text);
+ output.Append(group.Name);
if (group.SubGroups.Any())
output.Append("*");
output.Append('`');
@@ -177,7 +188,7 @@ namespace Discord.Commands
{
output.Append("\n\n");
- var chars = Config.CommandChars;
+ var chars = _config.CommandChars;
if (chars.Length > 0)
{
if (chars.Length == 1)
@@ -190,20 +201,20 @@ namespace Discord.Commands
output.AppendLine($"`help ` can tell you more about how to use a command.");
}
- return _client.SendMessage(channel, output.ToString());
+ return _client.SendMessage(replyChannel ?? channel, output.ToString());
}
- private Task ShowHelp(CommandMap map, User user, Channel channel)
+ private Task ShowCommandHelp(CommandMap map, User user, Channel channel, Channel replyChannel = null)
{
StringBuilder output = new StringBuilder();
Command cmd = map.Command;
if (cmd != null)
- ShowHelpInternal(cmd, user, channel, output);
+ ShowCommandHelpInternal(cmd, user, channel, output);
else
{
output.Append('`');
- output.Append(map.Text);
+ output.Append(map.FullName);
output.Append("`\n");
}
@@ -218,21 +229,21 @@ namespace Discord.Commands
else
output.Append(", ");
output.Append('`');
- output.Append(subCmd.Text);
+ output.Append(subCmd.Name);
if (subCmd.SubGroups.Any())
output.Append("*");
output.Append('`');
}
- return _client.SendMessage(channel, output.ToString());
+ return _client.SendMessage(replyChannel ?? channel, output.ToString());
}
- public Task ShowHelp(Command command, User user, Channel channel)
+ public Task ShowCommandHelp(Command command, User user, Channel channel, Channel replyChannel = null)
{
StringBuilder output = new StringBuilder();
- ShowHelpInternal(command, user, channel, output);
- return _client.SendMessage(channel, output.ToString());
+ ShowCommandHelpInternal(command, user, channel, output);
+ return _client.SendMessage(replyChannel ?? channel, output.ToString());
}
- private void ShowHelpInternal(Command command, User user, Channel channel, StringBuilder output)
+ private void ShowCommandHelpInternal(Command command, User user, Channel channel, StringBuilder output)
{
output.Append('`');
output.Append(command.Text);
@@ -261,17 +272,8 @@ namespace Discord.Commands
output.AppendLine($"Aliases: `" + string.Join("`, `", command.Aliases) + '`');
}
- public void CreateGroup(string cmd, Action config = null)
- {
- var builder = new CommandGroupBuilder(this, cmd);
- if (config != null)
- config(builder);
- }
- public CommandBuilder CreateCommand(string cmd)
- {
- var command = new Command(cmd);
- return new CommandBuilder(this, command, "", "");
- }
+ public void CreateGroup(string cmd, Action config = null) => _root.CreateGroup(cmd, config);
+ public CommandBuilder CreateCommand(string cmd) => _root.CreateCommand(cmd);
internal void AddCommand(Command command)
{
@@ -282,7 +284,7 @@ namespace Discord.Commands
string categoryName = command.Category ?? "";
if (!_categories.TryGetValue(categoryName, out category))
{
- category = new CommandMap(null, "");
+ category = new CommandMap(null, "", "");
_categories.Add(categoryName, category);
}
diff --git a/src/Discord.Net.Commands/CommandServiceConfig.cs b/src/Discord.Net.Commands/CommandServiceConfig.cs
index 70752f7ca..6d9e51926 100644
--- a/src/Discord.Net.Commands/CommandServiceConfig.cs
+++ b/src/Discord.Net.Commands/CommandServiceConfig.cs
@@ -1,4 +1,5 @@
-using System;
+using Discord.Commands.Permissions;
+using System;
namespace Discord.Commands
{
@@ -13,9 +14,6 @@ namespace Discord.Commands
}
public class CommandServiceConfig
{
- /*public Func PermissionResolver { get { return _permissionsResolver; } set { SetValue(ref _permissionsResolver, value); } }
- private Func _permissionsResolver;*/
-
public char? CommandChar
{
get
diff --git a/src/Discord.Net.Commands/Discord.Net.Commands.xproj b/src/Discord.Net.Commands/Discord.Net.Commands.xproj
index 1c104ae22..6c0d0ca91 100644
--- a/src/Discord.Net.Commands/Discord.Net.Commands.xproj
+++ b/src/Discord.Net.Commands/Discord.Net.Commands.xproj
@@ -7,7 +7,7 @@
19793545-ef89-48f4-8100-3ebaad0a9141
- Discord
+ Discord.Commands
..\..\artifacts\obj\$(MSBuildProjectName)
..\..\artifacts\bin\$(MSBuildProjectName)\
diff --git a/src/Discord.Net.Commands/Permissions/IPermissionChecker.cs b/src/Discord.Net.Commands/Permissions/IPermissionChecker.cs
new file mode 100644
index 000000000..6df6c6ea0
--- /dev/null
+++ b/src/Discord.Net.Commands/Permissions/IPermissionChecker.cs
@@ -0,0 +1,7 @@
+namespace Discord.Commands.Permissions
+{
+ public interface IPermissionChecker
+ {
+ bool CanRun(Command command, User user, Channel channel);
+ }
+}
diff --git a/src/Discord.Net.Commands/Permissions/Levels/PermissionLevelChecker.cs b/src/Discord.Net.Commands/Permissions/Levels/PermissionLevelChecker.cs
new file mode 100644
index 000000000..4d5d33dd4
--- /dev/null
+++ b/src/Discord.Net.Commands/Permissions/Levels/PermissionLevelChecker.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace Discord.Commands.Permissions.Levels
+{
+ public class PermissionLevelChecker : IPermissionChecker
+ {
+ private readonly PermissionLevelService _service;
+ private readonly int _minPermissions;
+
+ public PermissionLevelService Service => _service;
+ public int MinPermissions => _minPermissions;
+
+ internal PermissionLevelChecker(DiscordClient client, int minPermissions)
+ {
+ _service = client.GetService();
+ _minPermissions = minPermissions;
+ if (_service == null)
+ throw new InvalidOperationException($"{nameof(PermissionLevelService)} must be added to {nameof(DiscordClient)} before this function is called.");
+ }
+
+ public bool CanRun(Command command, User user, Channel channel)
+ {
+ int permissions = _service.GetPermissionLevel(user, channel);
+ return permissions >= _minPermissions;
+ }
+ }
+}
diff --git a/src/Discord.Net.Commands/Permissions/Levels/PermissionLevelExtensions.cs b/src/Discord.Net.Commands/Permissions/Levels/PermissionLevelExtensions.cs
new file mode 100644
index 000000000..e2169ec7b
--- /dev/null
+++ b/src/Discord.Net.Commands/Permissions/Levels/PermissionLevelExtensions.cs
@@ -0,0 +1,21 @@
+namespace Discord.Commands.Permissions.Levels
+{
+ public static class PermissionLevelExtensions
+ {
+ public static CommandBuilder MinPermissions(this CommandBuilder builder, int minPermissions)
+ {
+ builder.AddCheck(new PermissionLevelChecker(builder.Service.Client, minPermissions));
+ return builder;
+ }
+ public static CommandGroupBuilder MinPermissions(this CommandGroupBuilder builder, int minPermissions)
+ {
+ builder.AddCheck(new PermissionLevelChecker(builder.Service.Client, minPermissions));
+ return builder;
+ }
+ public static CommandService MinPermissions(this CommandService service, int minPermissions)
+ {
+ service.Root.AddCheck(new PermissionLevelChecker(service.Client, minPermissions));
+ return service;
+ }
+ }
+}
diff --git a/src/Discord.Net.Commands/Permissions/Levels/PermissionLevelService.cs b/src/Discord.Net.Commands/Permissions/Levels/PermissionLevelService.cs
new file mode 100644
index 000000000..6bab13b97
--- /dev/null
+++ b/src/Discord.Net.Commands/Permissions/Levels/PermissionLevelService.cs
@@ -0,0 +1,23 @@
+using System;
+
+namespace Discord.Commands.Permissions.Levels
+{
+ public class PermissionLevelService : IService
+ {
+ private readonly Func _getPermissionsFunc;
+
+ private DiscordClient _client;
+ public DiscordClient Client => _client;
+
+ public PermissionLevelService(Func getPermissionsFunc)
+ {
+ _getPermissionsFunc = getPermissionsFunc;
+ }
+
+ public void Install(DiscordClient client)
+ {
+ _client = client;
+ }
+ public int GetPermissionLevel(User user, Channel channel) => _getPermissionsFunc(user, channel);
+ }
+}
diff --git a/src/Discord.Net.Commands/Permissions/Userlist/BlacklistChecker.cs b/src/Discord.Net.Commands/Permissions/Userlist/BlacklistChecker.cs
new file mode 100644
index 000000000..c038af68b
--- /dev/null
+++ b/src/Discord.Net.Commands/Permissions/Userlist/BlacklistChecker.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Discord.Commands.Permissions.Userlist
+{
+ public class BlacklistChecker : IPermissionChecker
+ {
+ private readonly BlacklistService _service;
+
+ internal BlacklistChecker(DiscordClient client)
+ {
+ _service = client.GetService();
+ if (_service == null)
+ throw new InvalidOperationException($"{nameof(BlacklistService)} must be added to {nameof(DiscordClient)} before this function is called.");
+ }
+
+ public bool CanRun(Command command, User user, Channel channel)
+ {
+ return _service.CanRun(user);
+ }
+ }
+}
diff --git a/src/Discord.Net.Commands/Permissions/Userlist/BlacklistExtensions.cs b/src/Discord.Net.Commands/Permissions/Userlist/BlacklistExtensions.cs
new file mode 100644
index 000000000..6d6ee01c3
--- /dev/null
+++ b/src/Discord.Net.Commands/Permissions/Userlist/BlacklistExtensions.cs
@@ -0,0 +1,21 @@
+namespace Discord.Commands.Permissions.Userlist
+{
+ public static class BlacklistExtensions
+ {
+ public static CommandBuilder UseGlobalBlacklist(this CommandBuilder builder)
+ {
+ builder.AddCheck(new BlacklistChecker(builder.Service.Client));
+ return builder;
+ }
+ public static CommandGroupBuilder UseGlobalBlacklist(this CommandGroupBuilder builder)
+ {
+ builder.AddCheck(new BlacklistChecker(builder.Service.Client));
+ return builder;
+ }
+ public static CommandService UseGlobalBlacklist(this CommandService service)
+ {
+ service.Root.AddCheck(new BlacklistChecker(service.Client));
+ return service;
+ }
+ }
+}
diff --git a/src/Discord.Net.Commands/Permissions/Userlist/BlacklistService.cs b/src/Discord.Net.Commands/Permissions/Userlist/BlacklistService.cs
new file mode 100644
index 000000000..8e91ef8b6
--- /dev/null
+++ b/src/Discord.Net.Commands/Permissions/Userlist/BlacklistService.cs
@@ -0,0 +1,17 @@
+using System.Collections.Generic;
+
+namespace Discord.Commands.Permissions.Userlist
+{
+ public class BlacklistService : UserlistService
+ {
+ public BlacklistService(IEnumerable initialList = null)
+ : base(initialList)
+ {
+ }
+
+ public bool CanRun(User user)
+ {
+ return !_userList.ContainsKey(user.Id);
+ }
+ }
+}
diff --git a/src/Discord.Net.Commands/Permissions/Userlist/UserlistService.cs b/src/Discord.Net.Commands/Permissions/Userlist/UserlistService.cs
new file mode 100644
index 000000000..3c6e8bf6e
--- /dev/null
+++ b/src/Discord.Net.Commands/Permissions/Userlist/UserlistService.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Discord.Commands.Permissions.Userlist
+{
+ public class UserlistService : IService
+ {
+ protected readonly ConcurrentDictionary _userList;
+ private DiscordClient _client;
+
+ public DiscordClient Client => _client;
+ public IEnumerable UserIds => _userList.Select(x => x.Key);
+
+ public UserlistService(IEnumerable initialList = null)
+ {
+ if (initialList != null)
+ _userList = new ConcurrentDictionary(initialList.Select(x => new KeyValuePair(x, true)));
+ else
+ _userList = new ConcurrentDictionary();
+ }
+
+ public void Add(User user)
+ {
+ if (user == null) throw new ArgumentNullException(nameof(user));
+ _userList[user.Id] = true;
+ }
+ public void Add(string userId)
+ {
+ if (userId == null) throw new ArgumentNullException(nameof(userId));
+ _userList[userId] = true;
+ }
+ public bool Remove(User user)
+ {
+ if (user == null) throw new ArgumentNullException(nameof(user));
+ bool ignored;
+ return _userList.TryRemove(user.Id, out ignored);
+ }
+ public bool Remove(string userId)
+ {
+ if (userId == null) throw new ArgumentNullException(nameof(userId));
+ bool ignored;
+ return _userList.TryRemove(userId, out ignored);
+ }
+
+ public void Install(DiscordClient client)
+ {
+ _client = client;
+ }
+ }
+}
diff --git a/src/Discord.Net.Commands/Permissions/Userlist/WhitelistChecker.cs b/src/Discord.Net.Commands/Permissions/Userlist/WhitelistChecker.cs
new file mode 100644
index 000000000..781ea30e3
--- /dev/null
+++ b/src/Discord.Net.Commands/Permissions/Userlist/WhitelistChecker.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Discord.Commands.Permissions.Userlist
+{
+ public class WhitelistChecker : IPermissionChecker
+ {
+ private readonly WhitelistService _service;
+
+ internal WhitelistChecker(DiscordClient client)
+ {
+ _service = client.GetService();
+ if (_service == null)
+ throw new InvalidOperationException($"{nameof(WhitelistService)} must be added to {nameof(DiscordClient)} before this function is called.");
+ }
+
+ public bool CanRun(Command command, User user, Channel channel)
+ {
+ return _service.CanRun(user);
+ }
+ }
+}
diff --git a/src/Discord.Net.Commands/Permissions/Userlist/WhitelistExtensions.cs b/src/Discord.Net.Commands/Permissions/Userlist/WhitelistExtensions.cs
new file mode 100644
index 000000000..9076179c2
--- /dev/null
+++ b/src/Discord.Net.Commands/Permissions/Userlist/WhitelistExtensions.cs
@@ -0,0 +1,21 @@
+namespace Discord.Commands.Permissions.Userlist
+{
+ public static class WhitelistExtensions
+ {
+ public static CommandBuilder UseGlobalWhitelist(this CommandBuilder builder)
+ {
+ builder.AddCheck(new WhitelistChecker(builder.Service.Client));
+ return builder;
+ }
+ public static CommandGroupBuilder UseGlobalWhitelist(this CommandGroupBuilder builder)
+ {
+ builder.AddCheck(new WhitelistChecker(builder.Service.Client));
+ return builder;
+ }
+ public static CommandService UseGlobalWhitelist(this CommandService service)
+ {
+ service.Root.AddCheck(new BlacklistChecker(service.Client));
+ return service;
+ }
+ }
+}
diff --git a/src/Discord.Net.Commands/Permissions/Userlist/WhitelistService.cs b/src/Discord.Net.Commands/Permissions/Userlist/WhitelistService.cs
new file mode 100644
index 000000000..4719ee004
--- /dev/null
+++ b/src/Discord.Net.Commands/Permissions/Userlist/WhitelistService.cs
@@ -0,0 +1,17 @@
+using System.Collections.Generic;
+
+namespace Discord.Commands.Permissions.Userlist
+{
+ public class WhitelistService : UserlistService
+ {
+ public WhitelistService(IEnumerable initialList = null)
+ : base(initialList)
+ {
+ }
+
+ public bool CanRun(User user)
+ {
+ return _userList.ContainsKey(user.Id);
+ }
+ }
+}
diff --git a/src/Discord.Net.Modules.Net45/Discord.Net.Modules.csproj b/src/Discord.Net.Modules.Net45/Discord.Net.Modules.csproj
index fd825930f..68d3404f3 100644
--- a/src/Discord.Net.Modules.Net45/Discord.Net.Modules.csproj
+++ b/src/Discord.Net.Modules.Net45/Discord.Net.Modules.csproj
@@ -7,7 +7,7 @@
{3091164F-66AE-4543-A63D-167C1116241D}
Library
Properties
- Discord
+ Discord.Modules
Discord.Net.Commands
512
v4.5
@@ -40,6 +40,9 @@
IModule.cs
+
+ ModuleChecker.cs
+
ModuleExtensions.cs
diff --git a/src/Discord.Net.Modules/Discord.Net.Modules.xproj b/src/Discord.Net.Modules/Discord.Net.Modules.xproj
index f6db54ed1..77112cd5d 100644
--- a/src/Discord.Net.Modules/Discord.Net.Modules.xproj
+++ b/src/Discord.Net.Modules/Discord.Net.Modules.xproj
@@ -7,7 +7,7 @@
01584e8a-78da-486f-9ef9-a894e435841b
- Discord
+ Discord.Modules
..\..\artifacts\obj\$(MSBuildProjectName)
..\..\artifacts\bin\$(MSBuildProjectName)\
diff --git a/src/Discord.Net.Modules/ModuleChecker.cs b/src/Discord.Net.Modules/ModuleChecker.cs
new file mode 100644
index 000000000..efa37690b
--- /dev/null
+++ b/src/Discord.Net.Modules/ModuleChecker.cs
@@ -0,0 +1,20 @@
+using Discord.Commands;
+using Discord.Commands.Permissions;
+
+namespace Discord.Modules
+{
+ public class ModuleChecker : IPermissionChecker
+ {
+ private readonly ModuleManager _manager;
+
+ internal ModuleChecker(ModuleManager manager)
+ {
+ _manager = manager;
+ }
+
+ public bool CanRun(Command command, User user, Channel channel)
+ {
+ return _manager.FilterType.HasFlag(FilterType.Unrestricted) || _manager.HasChannel(channel);
+ }
+ }
+}
diff --git a/src/Discord.Net.Modules/ModuleManager.cs b/src/Discord.Net.Modules/ModuleManager.cs
index 2697b5bcb..43a5350fa 100644
--- a/src/Discord.Net.Modules/ModuleManager.cs
+++ b/src/Discord.Net.Modules/ModuleManager.cs
@@ -64,8 +64,8 @@ namespace Discord.Modules
_name = name;
_id = name.ToLowerInvariant();
_filterType = filterType;
- _allowServerWhitelist = filterType.HasFlag(FilterType.Server);
- _allowChannelWhitelist = filterType.HasFlag(FilterType.Channel);
+ _allowServerWhitelist = filterType.HasFlag(FilterType.ServerWhitelist);
+ _allowChannelWhitelist = filterType.HasFlag(FilterType.ChannelWhitelist);
_allowPrivate = filterType.HasFlag(FilterType.AllowPrivate);
_enabledServers = new ConcurrentDictionary();
@@ -115,6 +115,7 @@ namespace Discord.Modules
commandService.CreateGroup(prefix, x =>
{
x.Category(_name);
+ x.AddCheck(new ModuleChecker(this));
config(x);
});
@@ -244,12 +245,12 @@ namespace Discord.Modules
DisableAllChannels();
}
- private bool HasServer(Server server) =>
+ internal bool HasServer(Server server) =>
_allowServerWhitelist && _enabledServers.ContainsKey(server.Id);
- private bool HasIndirectServer(Server server) =>
+ internal bool HasIndirectServer(Server server) =>
(_allowServerWhitelist && _enabledServers.ContainsKey(server.Id)) ||
(_allowChannelWhitelist && _indirectServers.ContainsKey(server.Id));
- private bool HasChannel(Channel channel)
+ internal bool HasChannel(Channel channel)
{
if (channel.IsPrivate) return _allowPrivate;
diff --git a/src/Discord.Net.Modules/ModuleType.cs b/src/Discord.Net.Modules/ModuleType.cs
index bb0743a61..215debab6 100644
--- a/src/Discord.Net.Modules/ModuleType.cs
+++ b/src/Discord.Net.Modules/ModuleType.cs
@@ -5,12 +5,12 @@ namespace Discord.Modules
[Flags]
public enum FilterType
{
- /// Disables the event filter.
- Disabled = 0x0,
- /// Uses the server whitelist to filter events.
- Server = 0x1,
- /// Uses the channel whitelist to filter events.
- Channel = 0x2,
+ /// Disables the event and command filtesr.
+ Unrestricted = 0x0,
+ /// Uses the server whitelist to filter events and commands.
+ ServerWhitelist = 0x1,
+ /// Uses the channel whitelist to filter events and commands.
+ ChannelWhitelist = 0x2,
/// Enables this module in all private messages.
AllowPrivate = 0x4
}