Exemplo n.º 1
0
        private async Task OnCommandExecutedAsync(Optional <CommandInfo> optionalCommand, ICommandContext context, IResult result)
        {
            // We have access to the information of the command executed,
            // the context of the command, and the result returned from the
            // execution in this event.

            // command is unspecified when there was a search failure (command not found)
            if (!optionalCommand.IsSpecified)
            {
                await _logService.LogAsync(new LogMessage(LogSeverity.Info, "Command", $"Unknown command: \"{context.Message.Content}\", sent by {context.User} in {context.Display()}"));

                return;
            }
            var command = optionalCommand.Value;

            if (command.Module.Name != Constants.DevelopmentModuleName)
            {
                // Update the command stats
                lock (_cmdStatsLock)
                {
                    var stats = DatabaseConfig.CommandStats;
                    if (stats.ContainsKey(command.Name))
                    {
                        stats[command.Name]++;
                    }
                    else
                    {
                        stats.Add(command.Name, 1);
                    }
                    DatabaseConfig.Update(x => x.CommandStats = stats);
                }
            }

            // the command was successful, we don't care about this result, unless we want to log that a command succeeded.
            if (result.IsSuccess)
            {
                return;
            }

            double ignoreTime = Constants.DefaultIgnoreTime;

            switch (result.Error)
            {
            //case CommandError.UnknownCommand:
            //    await SendEmbedAsync(context.Message, string.Format(LocalizationService.Locate("CommandNotFound", context.Message), GetPrefix(context.Channel)));
            //    break;
            case CommandError.BadArgCount:
            case CommandError.ParseFailed:
                string language = GuildUtils.GetLanguage(context.Channel);
                string prefix   = GuildUtils.GetPrefix(context.Channel);
                await SendEmbedAsync(context.Message, command.ToHelpEmbed(language, prefix), _services);

                break;

            case CommandError.UnmetPrecondition when command.Module.Name != Constants.DevelopmentModuleName:
                ChannelPermissions permissions;
                if (context.Guild == null)
                {
                    permissions = ChannelPermissions.All(context.Channel);
                }
                else
                {
                    var guildUser = await context.Guild.GetCurrentUserAsync().ConfigureAwait(false);

                    permissions = guildUser.GetPermissions((IGuildChannel)context.Channel);
                }

                if (!permissions.Has(Constants.MinimumRequiredPermissions))
                {
                    var builder = new EmbedBuilder()
                                  .WithDescription($"\u26a0 {result.ErrorReason}")
                                  .WithColor(FergunClient.Config.EmbedColor);
                    try
                    {
                        await context.User.SendMessageAsync(embed : builder.Build());
                    }
                    catch (HttpException e) when(e.DiscordCode == 50007)
                    {
                        await _logService.LogAsync(new LogMessage(LogSeverity.Warning, "Command", "Unable to send a DM about the minimum required permissions to the user."));
                    }
                }
                else
                {
                    if (result.ErrorReason.StartsWith("(Cooldown)", StringComparison.OrdinalIgnoreCase))
                    {
                        ignoreTime = Constants.CooldownIgnoreTime;
                    }
                    await SendEmbedAsync(context.Message, $"\u26a0 {GuildUtils.Locate(result.ErrorReason, context.Channel)}", _services);
                }
                break;

            case CommandError.ObjectNotFound:
                // reason: The error reason (User not found., Role not found., etc)
                string reason = result.ErrorReason;
                // Delete the last char (.)
                reason = reason.Substring(0, result.ErrorReason.Length - 1);
                // Convert to title case (User Not Found)
                reason = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(reason);
                // Remove spaces (UserNotFound)
                reason = reason.Replace(" ", string.Empty, StringComparison.OrdinalIgnoreCase);
                // Locate the string to the current language of the guild
                reason = GuildUtils.Locate(reason, context.Channel);
                await SendEmbedAsync(context.Message, $"\u26a0 {reason}", _services);

                break;

            case CommandError.MultipleMatches:
                await SendEmbedAsync(context.Message, $"\u26a0 {GuildUtils.Locate("MultipleMatches", context.Channel)}", _services);

                break;

            case CommandError.Unsuccessful:
                await SendEmbedAsync(context.Message, $"\u26a0 {result.ErrorReason}".Truncate(EmbedBuilder.MaxDescriptionLength), _services);

                break;

            case CommandError.Exception when result is ExecuteResult execResult:
                var exception = execResult.Exception;

                if (exception is HttpException httpException && httpException.HttpCode >= HttpStatusCode.InternalServerError)
                {
                    await Task.Delay(2000);

                    var builder = new EmbedBuilder()
                                  .WithTitle(GuildUtils.Locate("DiscordServerError", context.Channel))
                                  .WithDescription($"\u26a0 {GuildUtils.Locate("DiscordServerErrorInfo", context.Channel)}")
                                  .AddField(GuildUtils.Locate("ErrorDetails", context.Channel),
                                            Format.Code($"Code: {(int)httpException.HttpCode}, Reason: {httpException.Reason}", "md"))
                                  .WithColor(FergunClient.Config.EmbedColor);

                    try
                    {
                        await SendEmbedAsync(context.Message, builder.Build(), _services);
                    }
                    catch (HttpException) { }
                    break;
                }

                var builder2 = new EmbedBuilder()
                               .WithTitle($"\u274c {GuildUtils.Locate("FailedExecution", context.Channel)} {Format.Code(command.Name)}")
                               .AddField(GuildUtils.Locate("ErrorType", context.Channel), Format.Code(exception.GetType().Name, "cs"))
                               .AddField(GuildUtils.Locate("ErrorMessage", context.Channel), Format.Code(exception.Message, "cs"))
                               .WithColor(FergunClient.Config.EmbedColor);

                var owner = (await context.Client.GetApplicationInfoAsync()).Owner;

                if (context.User.Id != owner.Id)
                {
                    builder2.WithFooter(GuildUtils.Locate("ErrorSentToOwner", context.Channel));
                }

                await SendEmbedAsync(context.Message, builder2.Build(), _services);

                if (context.User.Id == owner.Id)
                {
                    break;
                }
                // if the user that executed the command isn't the bot owner, send the full stack trace to the errors channel

                var channel = await context.Client.GetChannelAsync(FergunClient.Config.LogChannel);

                if (!(channel is IMessageChannel messageChannel))
                {
                    await _logService.LogAsync(new LogMessage(LogSeverity.Warning, "Command", $"Invalid log channel Id ({FergunClient.Config.LogChannel}). Not possible to send the embed with the error info."));

                    break;
                }

                var builder3 = new EmbedBuilder()
                               .WithTitle($"\u274c Failed to execute {Format.Code(command.Name)} in {context.Display()}".Truncate(EmbedBuilder.MaxTitleLength))
                               .AddField(GuildUtils.Locate("ErrorType", messageChannel), Format.Code(exception.GetType().Name, "cs"))
                               .AddField(GuildUtils.Locate("ErrorMessage", messageChannel), Format.Code(exception.ToString().Truncate(EmbedFieldBuilder.MaxFieldValueLength - 10), "cs"))
                               .AddField("Jump url", context.Message.GetJumpUrl())
                               .AddField("Command", context.Message.Content.Truncate(EmbedFieldBuilder.MaxFieldValueLength))
                               .WithColor(FergunClient.Config.EmbedColor);

                try
                {
                    await messageChannel.SendMessageAsync(embed : builder3.Build());
                }
                catch (HttpException e)
                {
                    await _logService.LogAsync(new LogMessage(LogSeverity.Warning, "Command", "Error while sending the embed in the log channel", e));
                }
                break;
            }

            _ = IgnoreUserAsync(context.User.Id, TimeSpan.FromSeconds(ignoreTime));
            await _logService.LogAsync(new LogMessage(LogSeverity.Info, "Command", $"Failed to execute \"{command.Name}\" for {context.User} in {context.Display()}, with error type: {result.Error} and reason: {result.ErrorReason}"));
        }