Prefix stuff almost complete, and i just realized permissions are getting screwed because of this

This commit is contained in:
Master Kwoth 2017-05-30 06:54:59 +02:00
parent 7704569c36
commit 6dd002002d
29 changed files with 1887 additions and 132 deletions

View File

@ -1,4 +1,5 @@
using Discord.Commands;
using NadekoBot.Services;
using NadekoBot.Services.CustomReactions;
using System.Linq;
using System.Threading.Tasks;
@ -8,18 +9,22 @@ namespace NadekoBot.TypeReaders
public class CommandTypeReader : TypeReader
{
private readonly CommandService _cmds;
private readonly CommandHandler _cmdHandler;
public CommandTypeReader(CommandService cmds)
public CommandTypeReader(CommandService cmds, CommandHandler cmdHandler)
{
_cmds = cmds;
_cmdHandler = cmdHandler;
}
public override Task<TypeReaderResult> Read(ICommandContext context, string input)
{
input = input.ToUpperInvariant();
if (!input.StartsWith(NadekoBot.Prefix.ToUpperInvariant()))
var prefix = _cmdHandler.GetPrefix(context.Guild);
if (!input.StartsWith(prefix.ToUpperInvariant()))
return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "No such command found."));
input = input.Substring(NadekoBot.Prefix.Length);
input = input.Substring(prefix.Length);
var cmd = _cmds.Commands.FirstOrDefault(c =>
c.Aliases.Select(a => a.ToUpperInvariant()).Contains(input));
@ -34,7 +39,7 @@ namespace NadekoBot.TypeReaders
{
private readonly CustomReactionsService _crs;
public CommandOrCrTypeReader(CustomReactionsService crs, CommandService cmds) : base(cmds)
public CommandOrCrTypeReader(CustomReactionsService crs, CommandService cmds, CommandHandler cmdHandler) : base(cmds, cmdHandler)
{
_crs = crs;
}
@ -62,7 +67,7 @@ namespace NadekoBot.TypeReaders
var cmd = await base.Read(context, input);
if (cmd.IsSuccess)
{
return TypeReaderResult.FromSuccess(new CommandOrCrInfo(((CommandInfo)cmd.Values.First().Value).Aliases.First()));
return TypeReaderResult.FromSuccess(new CommandOrCrInfo(((CommandInfo)cmd.Values.First().Value).Name));
}
return TypeReaderResult.FromError(CommandError.ParseFailed, "No such command or cr found.");
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations
{
public partial class guildprefixes : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Prefix",
table: "GuildConfigs",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "DefaultPrefix",
table: "BotConfig",
nullable: true,
defaultValue: ".");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Prefix",
table: "GuildConfigs");
migrationBuilder.DropColumn(
name: "DefaultPrefix",
table: "BotConfig");
}
}
}

View File

@ -2,7 +2,9 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using NadekoBot.Services.Database;
using NadekoBot.Services.Database.Models;
namespace NadekoBot.Migrations
{
@ -149,6 +151,8 @@ namespace NadekoBot.Migrations
b.Property<DateTime?>("DateAdded");
b.Property<string>("DefaultPrefix");
b.Property<string>("ErrorColor");
b.Property<bool>("ForwardMessages");
@ -568,6 +572,8 @@ namespace NadekoBot.Migrations
b.Property<string>("PermissionRole");
b.Property<string>("Prefix");
b.Property<int?>("RootPermissionId");
b.Property<bool>("SendChannelByeMessage");

View File

@ -0,0 +1,55 @@
using Discord;
using Discord.Commands;
using NadekoBot.Attributes;
using NadekoBot.Services;
using NadekoBot.Services.Administration;
using System.Threading.Tasks;
namespace NadekoBot.Modules.Administration
{
public partial class Administration
{
[Group]
public class PrefixCommands : NadekoSubmodule
{
[NadekoCommand, Usage, Description, Aliases]
[Priority(0)]
public new async Task Prefix()
{
await ReplyConfirmLocalized("prefix_current", Format.Code(_cmdHandler.GetPrefix(Context.Guild))).ConfigureAwait(false);
return;
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[RequireUserPermission(GuildPermission.Administrator)]
[Priority(1)]
public new async Task Prefix([Remainder]string prefix)
{
if (string.IsNullOrWhiteSpace(prefix))
return;
var oldPrefix = base.Prefix;
var newPrefix = _cmdHandler.SetPrefix(Context.Guild, prefix);
await ReplyConfirmLocalized("prefix_new", Format.Code(oldPrefix), Format.Code(newPrefix)).ConfigureAwait(false);
}
[NadekoCommand, Usage, Description, Aliases]
[OwnerOnly]
public async Task DefPrefix([Remainder]string prefix)
{
if (string.IsNullOrWhiteSpace(prefix))
{
await ReplyConfirmLocalized("defprefix_current", _cmdHandler.DefaultPrefix).ConfigureAwait(false);
return;
}
var oldPrefix = _cmdHandler.DefaultPrefix;
var newPrefix = _cmdHandler.SetDefaultPrefix(prefix);
await ReplyConfirmLocalized("defprefix_new", Format.Code(oldPrefix), Format.Code(newPrefix)).ConfigureAwait(false);
}
}
}
}

View File

@ -22,14 +22,16 @@ namespace NadekoBot.Modules.Games.Models
private readonly List<ulong> finishedUserIds;
private readonly DiscordShardedClient _client;
private readonly GamesService _games;
private readonly string _prefix;
private Logger _log { get; }
public TypingGame(GamesService games, DiscordShardedClient client, ITextChannel channel)
public TypingGame(GamesService games, DiscordShardedClient client, ITextChannel channel, string prefix) //kek@prefix
{
_log = LogManager.GetCurrentClassLogger();
_games = games;
_client = client;
_prefix = prefix;
this.Channel = channel;
IsActive = false;
@ -96,7 +98,7 @@ namespace NadekoBot.Modules.Games.Models
if (_games.TypingArticles.Any())
return _games.TypingArticles[new NadekoRandom().Next(0, _games.TypingArticles.Count)].Text;
else
return $"No typing articles found. Use {NadekoBot.Prefix}typeadd command to add a new article for typing.";
return $"No typing articles found. Use {_prefix}typeadd command to add a new article for typing.";
}

View File

@ -34,7 +34,7 @@ namespace NadekoBot.Modules.Games
{
var channel = (ITextChannel)Context.Channel;
var game = RunningContests.GetOrAdd(channel.Guild.Id, id => new TypingGame(_games, _client, channel));
var game = RunningContests.GetOrAdd(channel.Guild.Id, id => new TypingGame(_games, _client, channel, Prefix));
if (game.IsActive)
{

View File

@ -10,6 +10,7 @@ using System.IO;
using System.Text;
using System.Collections.Generic;
using NadekoBot.Services.Database.Models;
using NadekoBot.Services.Permissions;
namespace NadekoBot.Modules.Help
{
@ -20,15 +21,17 @@ namespace NadekoBot.Modules.Help
private readonly IBotCredentials _creds;
private readonly BotConfig _config;
private readonly CommandService _cmds;
private readonly GlobalPermissionService _perms;
public string HelpString => String.Format(_config.HelpString, _creds.ClientId, NadekoBot.Prefix);
public string HelpString => String.Format(_config.HelpString, _creds.ClientId, Prefix);
public string DMHelpString => _config.DMHelpString;
public Help(IBotCredentials creds, BotConfig config, CommandService cmds)
public Help(IBotCredentials creds, GlobalPermissionService perms, BotConfig config, CommandService cmds)
{
_creds = creds;
_config = config;
_cmds = cmds;
_perms = perms;
}
[NadekoCommand, Usage, Description, Aliases]
@ -39,8 +42,7 @@ namespace NadekoBot.Modules.Help
.WithTitle(GetText("list_of_modules"))
.WithDescription(string.Join("\n",
_cmds.Modules.GroupBy(m => m.GetTopLevelModule())
//todo perms
//.Where(m => !Permissions.Permissions.GlobalPermissionCommands.BlockedModules.Contains(m.Key.Name.ToLowerInvariant()))
.Where(m => !_perms.BlockedModules.Contains(m.Key.Name.ToLowerInvariant()))
.Select(m => "• " + m.Key.Name)
.OrderBy(s => s)));
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
@ -55,8 +57,7 @@ namespace NadekoBot.Modules.Help
if (string.IsNullOrWhiteSpace(module))
return;
var cmds = _cmds.Commands.Where(c => c.Module.GetTopLevelModule().Name.ToUpperInvariant().StartsWith(module))
//todo perms
//.Where(c => !Permissions.Permissions.GlobalPermissionCommands.BlockedCommands.Contains(c.Aliases.First().ToLowerInvariant()))
.Where(c => !_perms.BlockedCommands.Contains(c.Aliases.First().ToLowerInvariant()))
.OrderBy(c => c.Aliases.First())
.Distinct(new CommandTextEqualityComparer())
.AsEnumerable();
@ -154,8 +155,8 @@ namespace NadekoBot.Modules.Help
lastModule = module.Name;
}
helpstr.AppendLine($"{string.Join(" ", com.Aliases.Select(a => "`" + a + "`"))} |" +
$" {string.Format(com.Summary, NadekoBot.Prefix)} {GetCommandRequirements(com)} |" +
$" {string.Format(com.Remarks, NadekoBot.Prefix)}");
$" {string.Format(com.Summary, Prefix)} {GetCommandRequirements(com)} |" +
$" {string.Format(com.Remarks, Prefix)}");
}
File.WriteAllText("../../docs/Commands List.md", helpstr.ToString());
await ReplyConfirmLocalized("commandlist_regen").ConfigureAwait(false);

View File

@ -2,6 +2,7 @@
using Discord.Commands;
using NadekoBot.Extensions;
using NadekoBot.Services;
using NadekoBot.Services.Administration;
using NLog;
using System.Globalization;
using System.Threading.Tasks;
@ -12,19 +13,21 @@ namespace NadekoBot.Modules
{
protected readonly Logger _log;
protected CultureInfo _cultureInfo;
public readonly string Prefix;
public readonly string ModuleTypeName;
public readonly string LowerModuleTypeName;
public NadekoStrings _strings { get; set; }
public CommandHandler _cmdHandler { get; set; }
public ILocalization _localization { get; set; }
public string Prefix => _cmdHandler.GetPrefix(Context.Guild);
protected NadekoTopLevelModule(bool isTopLevelModule = true)
{
//if it's top level module
ModuleTypeName = isTopLevelModule ? this.GetType().Name : this.GetType().DeclaringType.Name;
LowerModuleTypeName = ModuleTypeName.ToLowerInvariant();
Prefix = NadekoBot.Prefix;
_log = LogManager.GetCurrentClassLogger();
}

View File

@ -13,11 +13,11 @@ namespace NadekoBot.Modules.Permissions.Commands
[Group]
public class ResetPermissionsCommands : NadekoSubmodule
{
private readonly PermissionsService _service;
private readonly PermissionService _service;
private readonly DbService _db;
private readonly GlobalPermissionService _globalPerms;
public ResetPermissionsCommands(PermissionsService service, GlobalPermissionService globalPerms, DbService db)
public ResetPermissionsCommands(PermissionService service, GlobalPermissionService globalPerms, DbService db)
{
_service = service;
_db = db;

View File

@ -16,9 +16,9 @@ namespace NadekoBot.Modules.Permissions
public partial class Permissions : NadekoTopLevelModule
{
private readonly DbService _db;
private readonly PermissionsService _service;
private readonly PermissionService _service;
public Permissions(PermissionsService service, DbService db)
public Permissions(PermissionService service, DbService db)
{
_db = db;
_service = service;

View File

@ -29,7 +29,7 @@ namespace NadekoBot.Modules.Searches
[NadekoCommand, Usage, Description, Aliases]
public async Task Placelist()
{
await Context.Channel.SendConfirmAsync(GetText("list_of_place_tags", NadekoBot.Prefix),
await Context.Channel.SendConfirmAsync(GetText("list_of_place_tags", Prefix),
typesStr)
.ConfigureAwait(false);
}

View File

@ -65,7 +65,7 @@ namespace NadekoBot.Modules.Utility
return;
}
var rem = (_patreon.Interval - (DateTime.UtcNow - _patreon.LastUpdate));
var helpcmd = Format.Code(NadekoBot.Prefix + "donate");
var helpcmd = Format.Code(Prefix + "donate");
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
.WithDescription(GetText("clpa_fail"))
.AddField(efb => efb.WithName(GetText("clpa_fail_already_title")).WithValue(GetText("clpa_fail_already")))

View File

@ -41,9 +41,6 @@ namespace NadekoBot
public static Color OkColor { get; private set; }
public static Color ErrorColor { get; private set; }
//todo placeholder, will be guild-based
public static string Prefix { get; } = ".";
public ImmutableArray<GuildConfig> AllGuildConfigs { get; }
public BotConfig BotConfig { get; }
public DbService Db { get; }
@ -97,7 +94,7 @@ namespace NadekoBot
var soundcloudApiService = new SoundCloudApiService(Credentials);
var localization = new Localization(BotConfig.Locale, AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.Locale), Db);
var strings = new NadekoStrings(localization);
var commandHandler = new CommandHandler(Client, CommandService, Credentials, this);
var commandHandler = new CommandHandler(Client, Db, BotConfig, AllGuildConfigs, CommandService, Credentials, this);
var stats = new StatsService(Client, commandHandler, Credentials);
var images = new ImagesService();
var currencyHandler = new CurrencyService(BotConfig, Db);
@ -112,6 +109,14 @@ namespace NadekoBot
var commandMapService = new CommandMapService(AllGuildConfigs);
#endregion
#region permissions
var permissionsService = new PermissionService(Db, BotConfig);
var blacklistService = new BlacklistService(BotConfig);
var cmdcdsService = new CmdCdService(AllGuildConfigs);
var filterService = new FilterService(Client, AllGuildConfigs);
var globalPermsService = new GlobalPermissionService(BotConfig);
#endregion
#region Searches
var searchesService = new SearchesService(Client, googleApiService, Db);
var streamNotificationService = new StreamNotificationService(Db, Client, strings);
@ -119,12 +124,12 @@ namespace NadekoBot
var clashService = new ClashOfClansService(Client, Db, localization, strings);
var musicService = new MusicService(googleApiService, strings, localization, Db, soundcloudApiService, Credentials, AllGuildConfigs);
var crService = new CustomReactionsService(Db, Client);
var crService = new CustomReactionsService(permissionsService, Db, Client);
var helpService = new HelpService(BotConfig);
#region Games
var gamesService = new GamesService(Client, BotConfig, AllGuildConfigs, strings, images);
var chatterBotService = new ChatterBotService(Client, AllGuildConfigs);
var gamesService = new GamesService(Client, BotConfig, AllGuildConfigs, strings, images, commandHandler);
var chatterBotService = new ChatterBotService(Client, permissionsService, AllGuildConfigs);
var pollService = new PollService(Client, strings);
#endregion
@ -140,13 +145,9 @@ namespace NadekoBot
var playingRotateService = new PlayingRotateService(Client, BotConfig, musicService);
var gameVcService = new GameVoiceChannelService(Client, Db, AllGuildConfigs);
var autoAssignRoleService = new AutoAssignRoleService(Client, AllGuildConfigs);
var permissionsService = new PermissionsService(Db, BotConfig);
var blacklistService = new BlacklistService(BotConfig);
var cmdcdsService = new CmdCdService(AllGuildConfigs);
var filterService = new FilterService(Client, AllGuildConfigs);
var globalPermsService = new GlobalPermissionService(BotConfig);
#endregion
//initialize Services
Services = new NServiceProvider.ServiceProviderBuilder()
.Add<ILocalization>(localization)
@ -188,7 +189,7 @@ namespace NadekoBot
.Add(gameVcService)
.Add(autoAssignRoleService)
.Add(protectionService)
.Add<PermissionsService>(permissionsService)
.Add<PermissionService>(permissionsService)
.Add(blacklistService)
.Add(cmdcdsService)
.Add(filterService)
@ -199,8 +200,8 @@ namespace NadekoBot
//setup typereaders
CommandService.AddTypeReader<PermissionAction>(new PermissionActionTypeReader());
CommandService.AddTypeReader<CommandInfo>(new CommandTypeReader(CommandService));
CommandService.AddTypeReader<CommandOrCrInfo>(new CommandOrCrTypeReader(crService, CommandService));
CommandService.AddTypeReader<CommandInfo>(new CommandTypeReader(CommandService, commandHandler));
CommandService.AddTypeReader<CommandOrCrInfo>(new CommandOrCrTypeReader(crService, CommandService, commandHandler));
CommandService.AddTypeReader<ModuleInfo>(new ModuleTypeReader(CommandService));
CommandService.AddTypeReader<ModuleOrCrInfo>(new ModuleOrCrTypeReader(CommandService));
CommandService.AddTypeReader<IGuild>(new GuildTypeReader(Client));

View File

@ -41,6 +41,7 @@
<Compile Include="Modules\Administration\Commands\Migration\MigrationException.cs" />
<Compile Include="Modules\Administration\Commands\MuteCommands.cs" />
<Compile Include="Modules\Administration\Commands\PlayingRotateCommands.cs" />
<Compile Include="Modules\Administration\Commands\PrefixCommands.cs" />
<Compile Include="Modules\Administration\Commands\ProtectionCommands.cs" />
<Compile Include="Modules\Administration\Commands\RatelimitCommand.cs" />
<Compile Include="Modules\Administration\Commands\SelfAssignedRolesCommand.cs" />

View File

@ -3474,4 +3474,22 @@
<data name="resetglobalpermissions_usage" xml:space="preserve">
<value>`{0}resetglobalperms`</value>
</data>
<data name="prefix_cmd" xml:space="preserve">
<value>prefix</value>
</data>
<data name="prefix_usage" xml:space="preserve">
<value>`{0}prefix +`</value>
</data>
<data name="prefix_desc" xml:space="preserve">
<value>Sets this server's prefix for all bot commands. Provide no arguments to see the current server prefix.</value>
</data>
<data name="defprefix_cmd" xml:space="preserve">
<value>defprefix</value>
</data>
<data name="defprefix_usage" xml:space="preserve">
<value>`{0}defprefix +`</value>
</data>
<data name="defprefix_desc" xml:space="preserve">
<value>Sets bot's default prefix for all bot commands. Provide no arguments to see the current default prefix. This will not change this server's current prefix.</value>
</data>
</root>

View File

@ -1,6 +1,7 @@
using Discord;
using Discord.WebSocket;
using Microsoft.EntityFrameworkCore;
using NadekoBot.Extensions;
using NadekoBot.Services.Database.Models;
using NLog;
using System;
@ -33,9 +34,10 @@ namespace NadekoBot.Services.Administration
_client = client;
_db = db;
GuildMuteRoles = new ConcurrentDictionary<ulong, string>(gcs
GuildMuteRoles = gcs
.Where(c => !string.IsNullOrWhiteSpace(c.MuteRoleName))
.ToDictionary(c => c.GuildId, c => c.MuteRoleName));
.ToDictionary(c => c.GuildId, c => c.MuteRoleName)
.ToConcurrent();
MutedUsers = new ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>>(gcs.ToDictionary(
k => k.GuildId,

View File

@ -12,6 +12,8 @@ using System.Threading;
using NadekoBot.DataStructures;
using System.Collections.Immutable;
using NadekoBot.DataStructures.ModuleBehaviors;
using NadekoBot.Services.Database.Models;
using NadekoBot.Services;
namespace NadekoBot.Services
{
@ -31,6 +33,8 @@ namespace NadekoBot.Services
private readonly IBotCredentials _creds;
private readonly NadekoBot _bot;
private INServiceProvider _services;
public string DefaultPrefix { get; private set; }
private ConcurrentDictionary<ulong, string> _prefixes { get; } = new ConcurrentDictionary<ulong, string>();
private ImmutableArray<AsyncLazy<IDMChannel>> ownerChannels { get; set; } = new ImmutableArray<AsyncLazy<IDMChannel>>();
@ -42,12 +46,13 @@ namespace NadekoBot.Services
public ConcurrentHashSet<ulong> UsersOnShortCooldown { get; } = new ConcurrentHashSet<ulong>();
private readonly Timer _clearUsersOnShortCooldown;
public CommandHandler(DiscordShardedClient client, CommandService commandService, IBotCredentials credentials, NadekoBot bot)
public CommandHandler(DiscordShardedClient client, DbService db, BotConfig bc, IEnumerable<GuildConfig> gcs, CommandService commandService, IBotCredentials credentials, NadekoBot bot)
{
_client = client;
_commandService = commandService;
_creds = credentials;
_bot = bot;
_db = db;
_log = LogManager.GetCurrentClassLogger();
@ -55,8 +60,60 @@ namespace NadekoBot.Services
{
UsersOnShortCooldown.Clear();
}, null, GlobalCommandsCooldown, GlobalCommandsCooldown);
DefaultPrefix = bc.DefaultPrefix;
_prefixes = gcs
.Where(x => x.Prefix != null)
.ToDictionary(x => x.GuildId, x => x.Prefix)
.ToConcurrent();
}
public string GetPrefix(IGuild guild) => GetPrefix(guild?.Id);
public string GetPrefix(ulong? id)
{
if (id == null || !_prefixes.TryGetValue(id.Value, out var prefix))
return DefaultPrefix;
return prefix;
}
public string SetDefaultPrefix(string prefix)
{
if (string.IsNullOrWhiteSpace(prefix))
throw new ArgumentNullException(nameof(prefix));
prefix = prefix.ToLowerInvariant();
using (var uow = _db.UnitOfWork)
{
uow.BotConfig.GetOrCreate(set => set).DefaultPrefix = prefix;
uow.Complete();
}
return DefaultPrefix = prefix;
}
public string SetPrefix(IGuild guild, string prefix)
{
if (string.IsNullOrWhiteSpace(prefix))
throw new ArgumentNullException(nameof(prefix));
if (guild == null)
throw new ArgumentNullException(nameof(guild));
prefix = prefix.ToLowerInvariant();
using (var uow = _db.UnitOfWork)
{
var gc = uow.GuildConfigs.For(guild.Id, set => set);
gc.Prefix = prefix;
uow.Complete();
}
_prefixes.AddOrUpdate(guild.Id, prefix, (key, old) => prefix);
return prefix;
}
public void AddServices(INServiceProvider services)
{
_services = services;
@ -87,13 +144,14 @@ namespace NadekoBot.Services
public Task StartHandling()
{
_client.MessageReceived += MessageReceivedHandler;
_client.MessageReceived += (msg) => { var _ = Task.Run(() => MessageReceivedHandler(msg)); return Task.CompletedTask; };
return Task.CompletedTask;
}
private const float _oneThousandth = 1.0f / 1000;
private readonly DbService _db;
private Task LogSuccessfulExecution(IUserMessage usrMsg, bool exec, ITextChannel channel, params int[] execPoints)
private Task LogSuccessfulExecution(IUserMessage usrMsg, ITextChannel channel, params int[] execPoints)
{
_log.Info("Command Executed after " + string.Join("/", execPoints.Select(x => x * _oneThousandth)) + "s\n\t" +
"User: {0}\n\t" +
@ -108,7 +166,7 @@ namespace NadekoBot.Services
return Task.CompletedTask;
}
private void LogErroredExecution(IUserMessage usrMsg, bool exec, ITextChannel channel, params int[] execPoints)
private void LogErroredExecution(string errorMessage, IUserMessage usrMsg, ITextChannel channel, params int[] execPoints)
{
_log.Warn("Command Errored after " + string.Join("/", execPoints.Select(x => x * _oneThousandth)) + "s\n\t" +
"User: {0}\n\t" +
@ -120,7 +178,7 @@ namespace NadekoBot.Services
(channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
(channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
usrMsg.Content,// {3}
exec
errorMessage
//exec.Result.ErrorReason // {4}
);
}
@ -199,33 +257,25 @@ namespace NadekoBot.Services
break;
}
}
var prefix = GetPrefix(guild.Id);
// execute the command and measure the time it took
if (messageContent.StartsWith(NadekoBot.Prefix))
if (messageContent.StartsWith(prefix))
{
var exec = await Task.Run(() => ExecuteCommandAsync(new CommandContext(_client, usrMsg), messageContent, NadekoBot.Prefix.Length, _services, MultiMatchHandling.Best)).ConfigureAwait(false);
var result = await ExecuteCommandAsync(new CommandContext(_client, usrMsg), messageContent, prefix.Length, _services, MultiMatchHandling.Best);
execTime = Environment.TickCount - execTime;
////todo commandHandler
if (exec)
if (result.Success)
{
// await CommandExecuted(usrMsg, exec.CommandInfo).ConfigureAwait(false);
await LogSuccessfulExecution(usrMsg, exec, channel as ITextChannel, exec2, exec3, execTime).ConfigureAwait(false);
await LogSuccessfulExecution(usrMsg, channel as ITextChannel, exec2, exec3, execTime).ConfigureAwait(false);
return;
}
//else if (!exec.Result.IsSuccess && exec.Result.Error != CommandError.UnknownCommand)
//{
// LogErroredExecution(usrMsg, exec, channel, exec2, exec3, execTime);
// if (guild != null && exec.CommandInfo != null && exec.Result.Error == CommandError.Exception)
// {
// if (exec.PermissionCache != null && exec.PermissionCache.Verbose)
// try { await usrMsg.Channel.SendMessageAsync("⚠️ " + exec.Result.ErrorReason).ConfigureAwait(false); } catch { }
// }
// return;
//}
if (exec)
return;
else if (result.Error != null)
{
//todo 80 should have log levels and it should return some kind of result,
// instead of tuple with the type of thing that went wrong, like before
LogErroredExecution(result.Error, usrMsg, channel as ITextChannel, exec2, exec3, execTime);
}
}
@ -239,15 +289,15 @@ namespace NadekoBot.Services
}
public Task<bool> ExecuteCommandAsync(CommandContext context, string input, int argPos, IServiceProvider serviceProvider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
public Task<(bool Success, string Error)> ExecuteCommandAsync(CommandContext context, string input, int argPos, IServiceProvider serviceProvider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
=> ExecuteCommand(context, input.Substring(argPos), serviceProvider, multiMatchHandling);
public async Task<bool> ExecuteCommand(CommandContext context, string input, IServiceProvider serviceProvider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
public async Task<(bool Success, string Error)> ExecuteCommand(CommandContext context, string input, IServiceProvider serviceProvider, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
{
var searchResult = _commandService.Search(context, input);
if (!searchResult.IsSuccess)
return false;
return (false, null);
var commands = searchResult.Commands;
for (int i = commands.Count - 1; i >= 0; i--)
@ -256,7 +306,7 @@ namespace NadekoBot.Services
if (!preconditionResult.IsSuccess)
{
if (commands.Count == 1)
return false;
return (false, null);
else
continue;
}
@ -280,33 +330,18 @@ namespace NadekoBot.Services
if (!parseResult.IsSuccess)
{
if (commands.Count == 1)
return false;
return (false, null);
else
continue;
}
}
var cmd = commands[i].Command;
var resetCommand = cmd.Name == "resetperms";
var module = cmd.Module.GetTopLevelModule();
if (context.Guild != null)
{
//////future
////int price;
////if (Permissions.CommandCostCommands.CommandCosts.TryGetValue(cmd.Aliases.First().Trim().ToLowerInvariant(), out price) && price > 0)
////{
//// var success = await _cs.RemoveCurrencyAsync(context.User.Id, $"Running {cmd.Name} command.", price).ConfigureAwait(false);
//// if (!success)
//// {
//// return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, $"Insufficient funds. You need {price}{NadekoBot.BotConfig.CurrencySign} to run this command."));
//// }
////}
}
// Bot will ignore commands which are ran more often than what specified by
// GlobalCommandsCooldown constant (miliseconds)
if (!UsersOnShortCooldown.Add(context.Message.Author.Id))
return false;
return (false, null);
//return SearchResult.FromError(CommandError.Exception, "You are on a global cooldown.");
var commandName = cmd.Aliases.First();
@ -316,15 +351,17 @@ namespace NadekoBot.Services
await exec.TryBlockLate(_client, context.Message, context.Guild, context.Channel, context.User, cmd.Module.GetTopLevelModule().Name, commandName).ConfigureAwait(false))
{
_log.Info("Late blocking User [{0}] Command: [{1}] in [{2}]", context.User, commandName, svc.GetType().Name);
return false;
return (false, null);
}
}
await commands[i].ExecuteAsync(context, parseResult, serviceProvider);
return true;
var execResult = await commands[i].ExecuteAsync(context, parseResult, serviceProvider);
if (execResult.Exception != null) //todo temp, to not be blind
_log.Warn(execResult.Exception);
return (true, null);
}
return false;
return (false, null);
//return new ExecuteCommandResult(null, null, SearchResult.FromError(CommandError.UnknownCommand, "This input does not match any overload."));
}
}

View File

@ -9,6 +9,7 @@ using System.Linq;
using System;
using System.Threading.Tasks;
using NadekoBot.Services.Permissions;
using NadekoBot.Extensions;
namespace NadekoBot.Services.CustomReactions
{
@ -22,9 +23,9 @@ namespace NadekoBot.Services.CustomReactions
private readonly Logger _log;
private readonly DbService _db;
private readonly DiscordShardedClient _client;
private readonly PermissionsService _perms;
private readonly PermissionService _perms;
public CustomReactionsService(PermissionsService perms, DbService db, DiscordShardedClient client)
public CustomReactionsService(PermissionService perms, DbService db, DiscordShardedClient client)
{
_log = LogManager.GetCurrentClassLogger();
_db = db;
@ -100,16 +101,18 @@ namespace NadekoBot.Services.CustomReactions
{
try
{
//todo permissions
if (guild is SocketGuild sg)
{
PermissionCache pc = _perms.GetCache(guild.Id);
var pc = _perms.GetCache(guild.Id);
if (!pc.Permissions.CheckPermissions(msg, cr.Trigger, "ActualCustomReactions",
out int index))
{
if (pc.Verbose)
{
var returnMsg = $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(sg)}** is preventing this action.";
try { await msg.Channel.SendErrorAsync(returnMsg).ConfigureAwait(false); } catch { }
_log.Info(returnMsg);
}
return true;
}
}

View File

@ -65,6 +65,7 @@ Nadeko Support Server: https://discord.gg/nadekobot";
public HashSet<BlockedCmdOrMdl> BlockedCommands { get; set; }
public HashSet<BlockedCmdOrMdl> BlockedModules { get; set; }
public int PermissionVersion { get; set; } = 1;
public string DefaultPrefix { get; set; } = ".";
}
public class BlockedCmdOrMdl : DbEntity

View File

@ -6,6 +6,9 @@ namespace NadekoBot.Services.Database.Models
public class GuildConfig : DbEntity
{
public ulong GuildId { get; set; }
public string Prefix { get; set; } = null;
public bool DeleteMessageOnCommand { get; set; }
public ulong AutoAssignRoleId { get; set; }
//greet stuff

View File

@ -3,6 +3,7 @@ using Discord.WebSocket;
using NadekoBot.DataStructures.ModuleBehaviors;
using NadekoBot.Extensions;
using NadekoBot.Services.Database.Models;
using NadekoBot.Services.Permissions;
using NLog;
using System;
using System.Collections.Concurrent;
@ -16,13 +17,15 @@ namespace NadekoBot.Services.Games
{
private readonly DiscordShardedClient _client;
private readonly Logger _log;
private readonly PermissionService _perms;
public ConcurrentDictionary<ulong, Lazy<ChatterBotSession>> ChatterBotGuilds { get; }
public ChatterBotService(DiscordShardedClient client, IEnumerable<GuildConfig> gcs)
public ChatterBotService(DiscordShardedClient client, PermissionService perms, IEnumerable<GuildConfig> gcs)
{
_client = client;
_log = LogManager.GetCurrentClassLogger();
_perms = perms;
ChatterBotGuilds = new ConcurrentDictionary<ulong, Lazy<ChatterBotSession>>(
gcs.Where(gc => gc.CleverbotEnabled)
@ -80,7 +83,7 @@ namespace NadekoBot.Services.Games
public async Task<bool> TryExecuteEarly(DiscordShardedClient client, IGuild guild, IUserMessage usrMsg)
{
if (guild == null)
if (!(guild is SocketGuild sg))
return false;
try
{
@ -88,19 +91,21 @@ namespace NadekoBot.Services.Games
if (message == null || cbs == null)
return false;
//todo permissions
//PermissionCache pc = Permissions.GetCache(guild.Id);
//if (!pc.Permissions.CheckPermissions(usrMsg,
// NadekoBot.Prefix + "cleverbot",
// "Games".ToLowerInvariant(),
// out int index))
//{
// //todo 46 print in guild actually
// var returnMsg =
// $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(guild)}** is preventing this action.";
// _log.Info(returnMsg);
// return true;
//}
var pc = _perms.GetCache(guild.Id);
if (!pc.Permissions.CheckPermissions(usrMsg,
"cleverbot",
"Games".ToLowerInvariant(),
out int index))
{
if (pc.Verbose)
{
//todo move this to permissions, prefix is always "." as a placeholder, fix that when you move it
var returnMsg = $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(sg)}** is preventing this action.";
try { await usrMsg.Channel.SendErrorAsync(returnMsg).ConfigureAwait(false); } catch { }
_log.Info(returnMsg);
}
return true;
}
var cleverbotExecuted = await TryAsk(cbs, (ITextChannel)usrMsg.Channel, message).ConfigureAwait(false);
if (cleverbotExecuted)

View File

@ -29,15 +29,18 @@ namespace NadekoBot.Services.Games
private readonly Logger _log;
public readonly string TypingArticlesPath = "data/typing_articles2.json";
private readonly CommandHandler _cmdHandler;
public List<TypingArticle> TypingArticles { get; } = new List<TypingArticle>();
public GamesService(DiscordShardedClient client, BotConfig bc, IEnumerable<GuildConfig> gcs,
NadekoStrings strings, IImagesService images)
NadekoStrings strings, IImagesService images, CommandHandler cmdHandler)
{
_bc = bc;
_client = client;
_strings = strings;
_images = images;
_cmdHandler = cmdHandler;
_log = LogManager.GetCurrentClassLogger();
//8ball
@ -123,7 +126,7 @@ namespace NadekoBot.Services.Games
if (dropAmount > 0)
{
var msgs = new IUserMessage[dropAmount];
var prefix = NadekoBot.Prefix;
var prefix = _cmdHandler.GetPrefix(channel.Guild.Id);
var toSend = dropAmount == 1
? GetText(channel, "curgen_sn", _bc.CurrencySign)
+ " " + GetText(channel, "pick_sn", prefix)

View File

@ -90,7 +90,7 @@ namespace NadekoBot.Services.Music
case MusicType.Radio:
return "https://cdn.discordapp.com/attachments/155726317222887425/261850925063340032/1482522097_radio.png"; //test links
case MusicType.Normal:
//todo have videoid in songinfo from the start
//todo 50 have videoid in songinfo from the start
var videoId = Regex.Match(SongInfo.Query, "<=v=[a-zA-Z0-9-]+(?=&)|(?<=[0-9])[^&\n]+|(?<=v=)[^&\n]+");
return $"https://img.youtube.com/vi/{ videoId }/0.jpg";
case MusicType.Local:

View File

@ -116,7 +116,7 @@ namespace NadekoBot.Services.Permissions
break;
}
return NadekoBot.Prefix + com;
return "." + com;
}
public static IEnumerable<Permission> AsEnumerable(this Permission perm)

View File

@ -9,10 +9,11 @@ using System.Linq;
using System.Threading.Tasks;
using Discord;
using Discord.WebSocket;
using NadekoBot.Extensions;
namespace NadekoBot.Services.Permissions
{
public class PermissionsService : ILateBlocker
public class PermissionService : ILateBlocker
{
private readonly DbService _db;
private readonly Logger _log;
@ -21,7 +22,7 @@ namespace NadekoBot.Services.Permissions
public ConcurrentDictionary<ulong, PermissionCache> Cache { get; } =
new ConcurrentDictionary<ulong, PermissionCache>();
public PermissionsService(DbService db, BotConfig bc)
public PermissionService(DbService db, BotConfig bc)
{
_log = LogManager.GetCurrentClassLogger();
_db = db;
@ -177,6 +178,8 @@ namespace NadekoBot.Services.Permissions
if (!resetCommand && !pc.Permissions.CheckPermissions(msg, commandName, moduleName, out int index))
{
var returnMsg = $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand((SocketGuild)guild)}** is preventing this action.";
if (pc.Verbose)
try { await channel.SendErrorAsync(returnMsg).ConfigureAwait(false); } catch { }
return true;
//return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, returnMsg));
}
@ -187,6 +190,9 @@ namespace NadekoBot.Services.Permissions
var roles = (user as SocketGuildUser)?.Roles ?? ((IGuildUser)user).RoleIds.Select(x => guild.GetRole(x)).Where(x => x != null);
if (!roles.Any(r => r.Name.Trim().ToLowerInvariant() == pc.PermRole.Trim().ToLowerInvariant()) && user.Id != ((IGuildUser)user).Guild.OwnerId)
{
var returnMsg = $"You need the **{pc.PermRole}** role in order to use permission commands.";
if (pc.Verbose)
try { await channel.SendErrorAsync(returnMsg).ConfigureAwait(false); } catch { }
return true;
//return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, $"You need the **{pc.PermRole}** role in order to use permission commands."));
}

View File

@ -36,7 +36,6 @@ namespace NadekoBot.Services.Utility
if (guild == null || string.IsNullOrWhiteSpace(input))
return input;
//todo alias mapping
if (guild != null)
{
input = input.ToLowerInvariant();

View File

@ -18,6 +18,9 @@ namespace NadekoBot.Extensions
{
public static class Extensions
{
public static ConcurrentDictionary<TKey, TValue> ToConcurrent<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, TValue>> dict)
=> new ConcurrentDictionary<TKey, TValue>(dict);
public static bool IsAuthor(this IMessage msg, IDiscordClient client) =>
msg.Author?.Id == client.CurrentUser.Id;

View File

@ -165,14 +165,14 @@
"administration_rc": "Color of {0} role has been changed.",
"administration_rc_not_exist": "That role does not exist.",
"administration_rc_params": "The parameters specified are invalid.",
"administration_rc_perms": "Error occured due to invalid color or insufficient permissions.",
"administration_rc_perms": "Error occurred due to invalid color or insufficient permissions.",
"administration_remrole": "Successfully removed role {0} from user {1}",
"administration_remrole_err": "Failed to remove role. I have insufficient permissions.",
"administration_renrole": "Role renamed.",
"administration_renrole_err": "Failed to rename role. I have insufficient permissions.",
"administration_renrole_perms": "You can't edit roles higher than your highest role.",
"administration_reprm": "Removed the playing message: {0}",
"administration_role_added": "Role {0} as been added to the list.",
"administration_role_added": "Role {0} has been added to the list.",
"administration_role_clean": "{0} not found.Cleaned up.",
"administration_role_in_list": "Role {0} is already in the list.",
"administration_ropl_added": "Added.",
@ -236,7 +236,7 @@
"administration_vt_enabled": "Enabled voice + text feature.",
"administration_vt_exit": "I don't have **manage roles** and/or **manage channels** permission, so I cannot run `voice+text` on {0} server.",
"administration_vt_no_admin": "You are enabling/disabling this feature and **I do not have ADMINISTRATOR permissions**. This may cause some issues, and you will have to clean up text channels yourself afterwards.",
"administration_vt_perms": "I require atleast **manage roles** and **manage channels** permissions to enable this feature. (preffered Administration permission)",
"administration_vt_perms": "I require at least **manage roles** and **manage channels** permissions to enable this feature. (preferred Administration permission)",
"administration_xmuted_text": "User {0} from text chat",
"administration_xmuted_text_and_voice": "User {0} from text and voice chat",
"administration_xmuted_voice": "User {0} from voice chat",
@ -519,7 +519,7 @@
"searches_define": "Define:",
"searches_dropped": "Dropped",
"searches_episodes": "Episodes",
"searches_error_occured": "Error occured.",
"searches_error_occured": "Error occurred.",
"searches_example": "Example",
"searches_failed_finding_anime": "Failed finding that animu.",
"searches_failed_finding_manga": "Failed finding that mango.",
@ -605,9 +605,9 @@
"utility_convert_not_found": "Cannot convert {0} to {1}: units not found",
"utility_convert_type_error": "Cannot convert {0} to {1}: types of unit are not equal",
"utility_created_at": "Created at",
"utility_chc_join": "Joined cross server channel.",
"utility_chc_leave": "Left cross server channel.",
"utility_chc_token": "This is your CSC token",
"utility_csc_join": "Joined cross server channel.",
"utility_csc_leave": "Left cross server channel.",
"utility_csc_token": "This is your CSC token",
"utility_custom_emojis": "Custom emojis",
"utility_error": "Error",
"utility_features": "Features",
@ -638,7 +638,7 @@
"utility_presence_txt": "{0} Servers\n{1} Text Channels\n{2} Voice Channels",
"utility_quotes_deleted": "Deleted all quotes with {0} keyword.",
"utility_quotes_page": "Page {0} of quotes",
"utility_quotes_page_none": "No quotes found matching the quote ID specified.",
"utility_quotes_page_none": "No quotes found on that page.",
"utility_quotes_remove_none": "No quotes found which you can remove.",
"utility_quote_added": "Quote Added",
"utility_quote_deleted": "Quote #{0} deleted.",
@ -779,5 +779,12 @@
"permissions_gcmd_remove": "Command {0} has been enabled on all servers.",
"permissions_gmod_add": "Module {0} has been disabled on all servers.",
"permissions_gmod_remove": "Module {0} has been enabled on all servers.",
"permissions_lgp_none": "No blocked commands or modules."
"permissions_lgp_none": "No blocked commands or modules.",
"gambling_animal_race_no_race": "This Animal Race is full!",
"utility_cant_read_or_send": "You can't read from or send messages to that channel.",
"utility_quotes_notfound": "No quotes found matching the quote ID specified.",
"administration_prefix_current": "Prefix on this server is {0}",
"administration_prefix_new": "Changed prefix on this server from {0} to {1}",
"administration_defprefix_current": "Default bot prefix is {0}",
"administration_defprefix_new": "Changed Default bot prefix from {0} to {1}"
}