Пример #1
0
        public static async Task MessageTextReactionEventHandlerAsync(FreudShard shard, MessageCreateEventArgs e)
        {
            if (e.Author.IsBot || e.Channel.IsPrivate || string.IsNullOrWhiteSpace(e.Message?.Content))
            {
                return;
            }
            if (e.Message.Content.StartsWith(shard.SharedData.GetGuildPrefix(e.Guild.Id)))
            {
                return;
            }
            if (shard.SharedData.BlockedChannels.Contains(e.Channel.Id) || shard.SharedData.BlockedUsers.Contains(e.Author.Id))
            {
                return;
            }
            if (!e.Channel.PermissionsFor(e.Guild.CurrentMember).HasFlag(Permissions.SendMessages))
            {
                return;
            }
            if (!shard.SharedData.TextReactions.TryGetValue(e.Guild.Id, out var treactions))
            {
                return;
            }

            var tr = treactions?.FirstOrDefault(r => r.IsMatch(e.Message.Content));

            if (!tr?.IsCooldownActive() ?? false)
            {
                await e.Channel.SendMessageAsync(tr.Response.Replace("%user%", e.Author.Mention));
            }
        }
Пример #2
0
        public static async Task MessageCreateEventHandlerAsync(FreudShard shard, MessageCreateEventArgs e)
        {
            if (e.Author.IsBot || e.Channel.IsPrivate)
            {
                return;
            }
            if (shard.SharedData.BlockedChannels.Contains(e.Channel.Id) || shard.SharedData.BlockedUsers.Contains(e.Author.Id))
            {
                return;
            }
            if (!e.Channel.PermissionsFor(e.Guild.CurrentMember).HasFlag(Permissions.SendMessages))
            {
                return;
            }
            if (!string.IsNullOrWhiteSpace(e.Message?.Content) && !e.Message.Content.StartsWith(shard.SharedData.GetGuildPrefix(e.Guild.Id)))
            {
                short rank = shard.SharedData.IncrementMessageCountForUser(e.Author.Id);
                if (rank != 0)
                {
                    DatabaseGuildRank rankInfo;
                    using (var dc = shard.Database.CreateContext())
                        rankInfo = dc.GuildRanks.SingleOrDefault(r => r.GuildId == e.Guild.Id && r.Rank == rank);

                    await e.Channel.EmbedAsync($"GG {e.Author.Mention}! You have advanced to level {Formatter.Bold(rank.ToString())} {(rankInfo is null ? "" : $": {Formatter.Italic(rankInfo.Name)}")} !", StaticDiscordEmoji.Medal);
                }
            }
        }
Пример #3
0
        public static async Task MessageFilterEventHandlerAsync(FreudShard shard, MessageCreateEventArgs e)
        {
            if (e.Author.IsBot || e.Channel.IsPrivate || string.IsNullOrWhiteSpace(e.Message?.Content))
            {
                return;
            }
            if (shard.SharedData.BlockedChannels.Contains(e.Channel.Id))
            {
                return;
            }

            var gcfg = shard.SharedData.GetGuildConfiguration(e.Guild.Id);

            if (gcfg.LinkfilterSettings.Enabled)
            {
                if (await shard.CNext.Services.GetService <LinkfilterService>().HandleNewMessageAsync(e, gcfg.LinkfilterSettings))
                {
                    return;
                }
            }

            if (!shard.SharedData.MessageContainsFilter(e.Guild.Id, e.Message.Content))
            {
                return;
            }
            if (!e.Channel.PermissionsFor(e.Guild.CurrentMember).HasFlag(Permissions.ManageMessages))
            {
                return;
            }

            await e.Message.DeleteAsync("bot: Filter hit");

            await e.Channel.SendMessageAsync($"{e.Author.Mention} said: {FormatterExtensions.Spoiler(Formatter.BlockCode(FormatterExtensions.StripMarkdown(e.Message.Content)))}");
        }
Пример #4
0
 public AntispamService(FreudShard shard)
     : base(shard)
 {
     this.guildExempts  = new ConcurrentDictionary <ulong, ConcurrentHashSet <ExemptedEntity> >();
     this.guildSpamInfo = new ConcurrentDictionary <ulong, ConcurrentDictionary <ulong, UserSpamInfo> >();
     this.refreshTimer  = new Timer(RefreshCallback, this, TimeSpan.FromMinutes(3), TimeSpan.FromMinutes(3));
     this.reason        = "bot: Antispam";
 }
Пример #5
0
 public RatelimitService(FreudShard shard)
     : base(shard)
 {
     this.guildExempts       = new ConcurrentDictionary <ulong, ConcurrentHashSet <ExemptedEntity> >();
     this.guildRatelimitInfo = new ConcurrentDictionary <ulong, ConcurrentDictionary <ulong, UserRatelimitInfo> >();
     this.refreshTimer       = new Timer(RefreshCallback, this, TimeSpan.FromSeconds(20), TimeSpan.FromSeconds(20));
     this.reason             = "bot: Ratelimit hit";
 }
Пример #6
0
        public static async Task MessageUpdateEventHandlerAsync(FreudShard shard, MessageUpdateEventArgs e)
        {
            if (e.Author is null || e.Author.IsBot || e.Channel is null || e.Channel.IsPrivate || e.Message is null)
            {
                return;
            }
            if (shard.SharedData.BlockedChannels.Contains(e.Channel.Id))
            {
                return;
            }
            if (e.Message.Author == e.Client.CurrentUser && shard.SharedData.IsEventRunningInChannel(e.Channel.Id))
            {
                return;
            }
            if (!(e.Message.Content is null) && shard.SharedData.MessageContainsFilter(e.Guild.Id, e.Message.Content))
            {
                try
                {
                    await e.Message.DeleteAsync("bot: Filter hit after update");

                    await e.Channel.SendMessageAsync($"{e.Author.Mention} said: {FormatterExtensions.Spoiler(Formatter.BlockCode(FormatterExtensions.StripMarkdown(e.Message.Content)))}");
                } catch
                {
                    // swallow
                }
            }

            var logchn = shard.SharedData.GetLogChannelForGuild(shard.Client, e.Guild);

            if (logchn is null || !e.Message.IsEdited || e.Channel.IsExempted(shard))
            {
                return;
            }

            var member = await e.Guild.GetMemberAsync(e.Author.Id);

            if (member.IsExempted(shard))
            {
                return;
            }

            string pcontent = string.IsNullOrWhiteSpace(e.MessageBefore?.Content) ? "" : e.MessageBefore.Content.Truncate(700);
            string acontent = string.IsNullOrWhiteSpace(e.Message?.Content) ? "" : e.Message.Content.Truncate(700);
            string ctime    = e.Message.CreationTimestamp == null ? _unknown : e.Message.CreationTimestamp.ToUtcTimestamp();
            string etime    = e.Message.EditedTimestamp is null ? _unknown : e.Message.EditedTimestamp.Value.ToUtcTimestamp();
            string bextra   = $"Embeds: {e.MessageBefore?.Embeds?.Count ?? 0}, Reactions: {e.MessageBefore?.Reactions?.Count ?? 0}, Attachments: {e.MessageBefore.Attachments?.Count ?? 0}";
            string aextra   = $"Embeds: {e.Message.Embeds.Count}, Reactions: {e.Message.Reactions.Count}, Attachments: {e.Message.Attachments.Count}";

            var emb = FormEmbedBuilder(EventOrigin.Message, "Message updated");

            emb.WithDescription(Formatter.MaskedUrl("Jump to message", e.Message.JumpLink));
            emb.AddField("Location", e.Channel.Mention, inline: true);
            emb.AddField("Author", e.Message.Author?.Mention ?? _unknown, inline: true);
            emb.AddField("Before update", $"Created {ctime}\n{bextra}\nContent:{Formatter.BlockCode(FormatterExtensions.StripMarkdown(pcontent))}");
            emb.AddField("After update", $"Edited {etime}\n{aextra}\nContent:{Formatter.BlockCode(FormatterExtensions.StripMarkdown(acontent))}");

            await logchn.SendMessageAsync(embed : emb.Build());
        }
Пример #7
0
        public static Task CommandExecutionEventHandler(FreudShard shard, CommandExecutionEventArgs e)
        {
            shard.LogMany(LogLevel.Info,
                          $"Executed: {e.Command?.QualifiedName ?? "<unknown command>"}",
                          $"{e.Context.User.ToString()}",
                          $"{e.Context.Guild.ToString()}; {e.Context.Channel.ToString()}");

            return(Task.CompletedTask);
        }
Пример #8
0
        public static Task GuildAvailableEventHandlerAsync(FreudShard shard, GuildCreateEventArgs e)
        {
            shard.Log(LogLevel.Debug, $"Guild available: {e.Guild.ToString()}");
            if (shard.SharedData.GuildConfigurations.ContainsKey(e.Guild.Id))
            {
                return(Task.CompletedTask);
            }

            return(RegisterGuildAsync(shard.SharedData, shard.Database, e.Guild.Id));
        }
Пример #9
0
        public static bool IsExempted(this DiscordChannel channel, FreudShard shard)
        {
            using (var dc = shard.Database.CreateContext())
            {
                if (dc.LoggingExempts.Any(ee => ee.GuildId == channel.GuildId && ee.Type == ExemptedEntityType.Channel && (ee.Id == channel.Id || ee.Id == channel.Parent.Id)))
                {
                    return(true);
                }
            }

            return(false);
        }
Пример #10
0
            public Task DeleteAsync(CommandContext ctx, [RemainingText, Description("Command to remove")] string command)
            {
                Command cmd = ctx.CommandsNext.FindCommand(command, out _);

                if (cmd is null)
                {
                    throw new CommandFailedException("Cannot find that command.");
                }
                ctx.CommandsNext.UnregisterCommands(cmd);
                FreudShard.UpdateCommandList(ctx.CommandsNext);

                return(this.InformAsync(ctx, $"Removed command {Formatter.Bold(cmd.QualifiedName)}.", important: false));
            }
Пример #11
0
        public static async Task MemberJoinEventHandlerAsync(FreudShard shard, GuildMemberAddEventArgs e)
        {
            var gcfg = e.Guild.GetGuildSettings(shard.Database);
            await Task.Delay(TimeSpan.FromSeconds(gcfg.AntiInstantLeaveSettings.Cooldown + 1));

            if (e.Member.Guild is null)
            {
                return;
            }

            var whcn = e.Guild.GetChannel(gcfg.WelcomeChannelId);

            if (!(whcn is null))
            {
                if (string.IsNullOrWhiteSpace(gcfg.WelcomeMessage))
                {
                    await whcn.EmbedAsync($"Welcome to {Formatter.Bold(e.Guild.Name)}, {e.Member.Mention}!", StaticDiscordEmoji.Wave);
                }
                else
                {
                    await whcn.EmbedAsync(gcfg.WelcomeMessage.Replace("%user%", e.Member.Mention), StaticDiscordEmoji.Wave);
                }
            }
            try
            {
                using (var dc = shard.Database.CreateContext())
                {
                    var rids = dc.AutoAssignableRoles.Where(dbr => dbr.GuildId == e.Guild.Id).Select(dbr => dbr.RoleId);
                    foreach (ulong rid in rids.ToList())
                    {
                        try
                        {
                            var role = e.Guild.GetRole(rid);
                            if (!(role is null))
                            {
                                await e.Member.GrantRoleAsync(role);
                            }
                            else
                            {
                                dc.AutoAssignableRoles.Remove(dc.AutoAssignableRoles.Single(r => r.GuildId == e.Guild.Id && r.RoleId == rid));
                            }
                        } catch (Exception exc)
                        {
                            shard.Log(LogLevel.Debug,
                                      $"| Failed to assign an automatic role to a new member!\n" +
                                      $"| {e.Guild.ToString()}\n" +
                                      $"| Exception: {exc.GetType()}" +
                                      $"| Message: {exc.Message}"
                                      );
                        }
                    }
Пример #12
0
        public static async Task ChannelCreateEventHandlerAsync(FreudShard shard, ChannelCreateEventArgs e)
        {
            var logchn = shard.SharedData.GetLogChannelForGuild(shard.Client, e.Guild);

            if (logchn is null)
            {
                return;
            }

            var emb   = FormEmbedBuilder(EventOrigin.Channel, "Channel created", e.Channel.ToString());
            var entry = await e.Guild.GetLatestAuditLogEntryAsync(AuditLogActionType.ChannelCreate);

            if (entry is null || !(entry is DiscordAuditLogChannelEntry centry))
            {
                emb.AddField("Error", "Failed to read audit log information. Please check my permissions");
            }
Пример #13
0
        public static async Task BulkDeleteEventHandlerAsync(FreudShard shard, MessageBulkDeleteEventArgs e)
        {
            if (e.Channel.IsPrivate)
            {
                return;
            }

            var logchn = shard.SharedData.GetLogChannelForGuild(shard.Client, e.Channel.Guild);

            if (logchn is null || e.Channel.IsExempted(shard))
            {
                return;
            }

            var emb = FormEmbedBuilder(EventOrigin.Message, $"Bulk message deletiong occured ({e.Messages.Count} total)", $"In channel {e.Channel.Mention}");
            await logchn.SendMessageAsync(embed : emb.Build());
        }
Пример #14
0
        public static async Task GuildBanEventHandlerAsync(FreudShard shard, GuildBanAddEventArgs e)
        {
            var logchn = shard.SharedData.GetLogChannelForGuild(shard.Client, e.Guild);

            if (logchn is null)
            {
                return;
            }

            var emb   = FormEmbedBuilder(EventOrigin.KickOrBan, "User BANNED");
            var entry = await e.Guild.GetLatestAuditLogEntryAsync(AuditLogActionType.Ban);

            if (entry is null || !(entry is DiscordAuditLogBanEntry bentry))
            {
                emb.WithDescription(e.Member?.ToString() ?? _unknown);
                emb.AddField("Error", "Failed to read audit log information. Please check my permissions");
            }
Пример #15
0
        public static void RegisterEventListeners(DiscordClient client, FreudShard shard)
        {
            ListenerMethods =
                from types in Assembly.GetExecutingAssembly().GetTypes()
                from methods in types.GetMethods()
                let attribute = methods.GetCustomAttribute(typeof(AsyncEventListenerAttribute), inherit: true)
                                where !(attribute is null)
                                select new ListenerMethod
            {
                Method    = methods,
                Attribute = attribute as AsyncEventListenerAttribute
            };

            foreach (ListenerMethod lm in ListenerMethods)
            {
                lm.Attribute.Register(shard, client, lm.Method);
            }
        }
Пример #16
0
        public static async Task GuildCreatedEventhandlerAsync(FreudShard shard, GuildCreateEventArgs e)
        {
            shard.Log(LogLevel.Info, $"Joined guild: {e.Guild.ToString()}");
            await RegisterGuildAsync(shard.SharedData, shard.Database, e.Guild.Id);

            var defChannel = e.Guild.GetDefaultChannel();

            if (!defChannel.PermissionsFor(e.Guild.CurrentMember).HasPermission(Permissions.SendMessages))
            {
                return;
            }
            await defChannel.EmbedAsync(
                $"{Formatter.Bold("Thank you for adding me to your discord!")}\n\n" +
                $"{StaticDiscordEmoji.SmallBlueDiamond} The default prefix for my command is {Formatter.Bold(shard.SharedData.BotConfiguration.DefaultPrefix)}, but it can be changed using {Formatter.Bold("prefix")} command.\n" +
                $"{StaticDiscordEmoji.SmallBlueDiamond} I advise you to run the configuration wizard for this guild in order to quickly configure functions like logging and notifications. The wizard can be invoked using {Formatter.Bold("guild configuration setup")} command.\n" +
                $"{StaticDiscordEmoji.SmallBlueDiamond} You can use the {Formatter.Bold("help")} command as a guide, though it is recommended to read the command list provided in the source \n" +
                $"{StaticDiscordEmoji.SmallBlueDiamond} If you have any questions or issues, use the {Formatter.Bold("report")} command in order to send a message to the bot owner ({e.Client.CurrentApplication.Team}#{e.Client.CurrentApplication.Description})." + StaticDiscordEmoji.Wave
                );
        }
Пример #17
0
        public static bool IsExempted(this DiscordMember member, FreudShard shard)
        {
            if (member is null)
            {
                return(false);
            }

            using (var dc = shard.Database.CreateContext())
            {
                if (dc.LoggingExempts.Any(ee => ee.Type == ExemptedEntityType.Member && ee.Id == member.Id))
                {
                    return(true);
                }
                if (member.Roles.Any(r => dc.LoggingExempts.Any(ee => ee.Type == ExemptedEntityType.Role && ee.Id == r.Id)))
                {
                    return(true);
                }
            }

            return(false);
        }
Пример #18
0
        public static async Task MessageCreateProtectionHandlerAsync(FreudShard shard, MessageCreateEventArgs e)
        {
            if (e.Author.IsBot || e.Channel.IsPrivate || string.IsNullOrWhiteSpace(e.Message?.Content))
            {
                return;
            }
            if (shard.SharedData.BlockedChannels.Contains(e.Channel.Id))
            {
                return;
            }

            var gcfg = shard.SharedData.GetGuildConfiguration(e.Guild.Id);

            if (gcfg.RatelimitSettings.Enabled)
            {
                await shard.CNext.Services.GetService <RatelimitService>().HandleNewMessageAsync(e, gcfg.RatelimitSettings);
            }
            if (gcfg.AntispamSettings.Enabled)
            {
                await shard.CNext.Services.GetService <AntispamService>().HandleNewMessageAsync(e, gcfg.AntispamSettings);
            }
        }
Пример #19
0
        public static async Task MessageEmojiReactionEventHandlerAsync(FreudShard shard, MessageCreateEventArgs e)
        {
            if (e.Author.IsBot || e.Channel.IsPrivate || string.IsNullOrWhiteSpace(e.Message?.Content))
            {
                return;
            }
            if (shard.SharedData.BlockedChannels.Contains(e.Channel.Id) || shard.SharedData.BlockedUsers.Contains(e.Author.Id))
            {
                return;
            }
            if (!e.Channel.PermissionsFor(e.Guild.CurrentMember).HasFlag(Permissions.AddReactions))
            {
                return;
            }
            if (!shard.SharedData.EmojiReactions.TryGetValue(e.Guild.Id, out var ereactions))
            {
                return;
            }

            var ereaction = ereactions?.Where(er => er.IsMatch(e.Message?.Content ?? "")).Shuffle().FirstOrDefault();

            if (!(ereaction is null))
            {
                try
                {
                    var emoji = DiscordEmoji.FromName(shard.Client, ereaction.Response);

                    await e.Message.CreateReactionAsync(emoji);
                } catch
                {
                    using (var dc = shard.Database.CreateContext())
                    {
                        dc.EmojiReactions.RemoveRange(dc.EmojiReactions.Where(er => er.GuildId == e.Guild.Id && er.Reaction == ereaction.Response));

                        await dc.SaveChangesAsync();
                    }
                }
            }
        }
Пример #20
0
        public static Task ClientErrorEventHandlerAsync(FreudShard shard, ClientErrorEventArgs e)
        {
            var ex = e.Exception;

            while (ex is AggregateException)
            {
                ex = ex.InnerException;
            }

            if (ex.InnerException is null)
            {
                shard.LogMany(LogLevel.Critical, $"Client errored with exception: {ex.GetType()}", $"Message: {ex.Message}");
            }
            else
            {
                shard.LogMany(LogLevel.Critical,
                              $"Client errored with exception: {ex.GetType()}",
                              $"Message: {ex.Message}",
                              $"Inner exception: {ex.InnerException.GetType()}",
                              $"Inner exception message: {ex.InnerException.Message}");
            };

            return(Task.CompletedTask);
        }
Пример #21
0
 protected ProtectionService(FreudShard shard)
 {
     this.shard = shard;
 }
Пример #22
0
        public static Task GuildDownloadCompletedEventHandlerAsync(FreudShard shard, GuildDownloadCompletedEventArgs e)
        {
            shard.Log(LogLevel.Info, $"All guilds are now available.");

            return(Task.CompletedTask);
        }
Пример #23
0
        public static async Task CommandErrorEventHandlerAsync(FreudShard shard, CommandErrorEventArgs e)
        {
            if (e.Exception is null)
            {
                return;
            }

            var ex = e.Exception;

            while (ex is AggregateException)
            {
                ex = ex.InnerException;
            }

            if (ex is ChecksFailedException chke && chke.FailedChecks.Any(c => c is NotBlockedAttribute))
            {
                await e.Context.Message.CreateReactionAsync(StaticDiscordEmoji.X);

                return;
            }

            shard.LogMany(LogLevel.Info,
                          $"Tried executing: {e.Command?.QualifiedName ?? "<unknown command>"}",
                          $"{e.Context.User.ToString()}",
                          $"{e.Context.Guild.ToString()}; {e.Context.Channel.ToString()}",
                          $"Exception: {ex.GetType()}",
                          $"Message: {ex.Message ?? "<no message provided>"}",
                          ex.InnerException is null ? "" : $"Inner exception: {ex.InnerException.GetType()}",
                          ex.InnerException is null ? "" : $"Inner exception message: {ex.InnerException.Message}");

            var emb = new DiscordEmbedBuilder {
                Color = DiscordColor.Red
            };
            var sb = new StringBuilder(StaticDiscordEmoji.NoEntry).Append(" ");

            switch (ex)
            {
            case CommandNotFoundException cne:
                if (!shard.SharedData.GetGuildConfiguration(e.Context.Guild.Id).SuggestionsEnabled)
                {
                    await e.Context.Message.CreateReactionAsync(StaticDiscordEmoji.Question);

                    return;
                }

                sb.Clear();
                sb.AppendLine(Formatter.Bold($"Command {Formatter.InlineCode(cne.CommandName)} not found. Did you mean..."));
                var ordered = FreudShard.Commands
                              .OrderBy(tup => cne.CommandName.LevenshteinDistance(tup.Name)).Take(3);
                foreach ((string alias, var cmd) in ordered)
                {
                    emb.AddField($"{alias} ({cmd.QualifiedName})", cmd.Description);
                }
                break;

            case InvalidCommandUsageException _:
                sb.Append("Invalid command usage! ");
                sb.AppendLine(ex.Message);
                emb.WithFooter($"Type \"{shard.SharedData.GetGuildPrefix(e.Context.Guild.Id)}help {e.Command.QualifiedName}\" for a command manual.");
                break;

            case ArgumentException _:
                string fcmdStr = $"help {e.Command.QualifiedName}";
                var    command = shard.CNext.FindCommand(fcmdStr, out string args);
                var    fctx    = shard.CNext.CreateFakeContext(e.Context.User, e.Context.Channel, fcmdStr, e.Context.Prefix, command, args);
                await shard.CNext.ExecuteCommandAsync(fctx);

                return;

            case BadRequestException brex:
                sb.Append($"Bad request! Details: {brex.JsonMessage}");
                break;

            case NotFoundException nfe:
                sb.Append($"404: Not found! Details: {nfe.JsonMessage}");
                break;

            case CommandFailedException _:
                sb.Append($"{ex.Message} {ex.InnerException?.Message}");
                break;

            case NpgsqlException dbex:
                sb.Append($"Database operation failed. Details: {dbex.Message}");
                shard.SharedData.LogProvider.Log(LogLevel.Error, ex);
                break;

            case ChecksFailedException cfex:
                switch (cfex.FailedChecks.First())
                {
                case CooldownAttribute _:
                    return;

                case UsageInteractivityAttribute _:
                    sb.Append($"I am waiting for your answer and you cannot execute commands until you either answer, or the timeout is reached.");
                    break;

                default:
                    sb.AppendLine($"Command {Formatter.Bold(e.Command.QualifiedName)} cannot be executed because:").AppendLine();
                    foreach (var attr in cfex.FailedChecks)
                    {
                        switch (attr)
                        {
                        case RequirePermissionsAttribute perms:
                            sb.AppendLine($"- One of us does not have the required permissions ({perms.Permissions.ToPermissionString()})!");
                            break;

                        case RequireUserPermissionsAttribute uperms:
                            sb.AppendLine($"- You do not have sufficient permissions ({uperms.Permissions.ToPermissionString()})!");
                            break;

                        case RequireOwnerOrPermissionsAttribute operms:
                            sb.AppendLine($"- You do not have sufficient permissions ({operms.Permissions.ToPermissionString()})!");
                            break;

                        case RequireBotPermissionsAttribute bperms:
                            sb.AppendLine($"- I do not have sufficient permissions ({bperms.Permissions.ToPermissionString()})!");
                            break;

                        case RequirePrivilegedUserAttribute _:
                            sb.AppendLine($"- That command is reserved for my owner and privileged users!");
                            break;

                        case RequireOwnerAttribute _:
                            sb.AppendLine($"- That command is reserved only for my owner!");
                            break;

                        case RequireNsfwAttribute _:
                            sb.AppendLine($"- That command is allowed only in the NSFW channels!");
                            break;

                        case RequirePrefixesAttribute pattr:
                            sb.AppendLine($"- That command can only be invoked only with the following prefixes: {string.Join(" ", pattr.Prefixes)}!");
                            break;

                        default:
                            sb.AppendLine($"{attr} was not met! (this should not happen, please report this)");
                            break;
                        }
                    }
                    break;
                }
                break;

            case ConcurrentOperationException _:
                sb.Append($"A concurrency error occured - please report this. Details: {ex.Message}");
                shard.SharedData.LogProvider.Log(LogLevel.Error, ex);
                break;

            case UnauthorizedException _:
                sb.Append("I am unauthorized to do that");
                break;

            case DbUpdateException _:
                sb.Append("A database update error has occured, possibly due to large amount of update request. Please try again later.");
                shard.SharedData.LogProvider.Log(LogLevel.Error, ex);
                break;

            case TargetInvocationException _:
                sb.Append($"{ex.InnerException?.Message ?? "Target invocation error occured. Please check the arguments provided and try again."}");
                break;

            case TaskCanceledException _:
                return;

            default:
                sb.AppendLine($"Command {Formatter.Bold(e.Command.QualifiedName)} errored!").AppendLine();
                sb.AppendLine($"Exception: {Formatter.InlineCode(ex.GetType().ToString())}");
                sb.AppendLine($"Details: {Formatter.Italic(ex.Message)}");

                if (!(ex.InnerException is null))
                {
                    sb.AppendLine($"Inner exception: {Formatter.InlineCode(ex.InnerException.GetType().ToString())}");
                    sb.AppendLine($"Details: {Formatter.Italic(ex.InnerException.Message ?? "No details provided")}");
                }

                shard.SharedData.LogProvider.Log(LogLevel.Error, ex);
                break;
            }

            emb.Description = sb.ToString();

            await e.Context.RespondAsync(embed : emb.Build());
        }
        public void Register(FreudShard shard, DiscordClient client, MethodInfo info)
        {
            Task OnEventWithArgs(object e)
            {
                if (!shard.IsListening)
                {
                    return(Task.CompletedTask);
                }

                _ = Task.Run(async() =>
                {
                    try
                    {
                        await(Task) info.Invoke(null, new object[] { shard, e });
                    } catch (Exception ex)
                    {
                        shard.SharedData.LogProvider.Log(LogLevel.Error, ex);
                    }
                });

                return(Task.CompletedTask);
            }

            Task OnEventVoid()
            {
                if (!shard.IsListening)
                {
                    return(Task.CompletedTask);
                }

                _ = Task.Run(async() =>
                {
                    try
                    {
                        await(Task) info.Invoke(null, new object[] { shard });
                    } catch (Exception ex)
                    {
                        shard.SharedData.LogProvider.Log(LogLevel.Error, ex);
                    }
                });

                return(Task.CompletedTask);
            }

            #region START_SWITCH_STATEMENT

            switch (this.Target)
            {
            case DiscordEventType.ClientErrored:
                client.ClientErrored += OnEventWithArgs;
                break;

            case DiscordEventType.SocketErrored:
                client.SocketErrored += OnEventWithArgs;
                break;

            case DiscordEventType.SocketOpened:
                client.SocketOpened += OnEventVoid;
                break;

            case DiscordEventType.SocketClosed:
                client.SocketClosed += OnEventWithArgs;
                break;

            case DiscordEventType.Ready:
                client.Ready += OnEventWithArgs;
                break;

            case DiscordEventType.Resumed:
                client.Resumed += OnEventWithArgs;
                break;

            case DiscordEventType.ChannelCreated:
                client.ChannelCreated += OnEventWithArgs;
                break;

            case DiscordEventType.DmChannelCreated:
                client.DmChannelCreated += OnEventWithArgs;
                break;

            case DiscordEventType.ChannelUpdated:
                client.ChannelUpdated += OnEventWithArgs;
                break;

            case DiscordEventType.ChannelDeleted:
                client.ChannelDeleted += OnEventWithArgs;
                break;

            case DiscordEventType.DmChannelDeleted:
                client.DmChannelDeleted += OnEventWithArgs;
                break;

            case DiscordEventType.ChannelPinsUpdated:
                client.ChannelPinsUpdated += OnEventWithArgs;
                break;

            case DiscordEventType.GuildCreated:
                client.GuildCreated += OnEventWithArgs;
                break;

            case DiscordEventType.GuildAvailable:
                client.GuildAvailable += OnEventWithArgs;
                break;

            case DiscordEventType.GuildUpdated:
                client.GuildUpdated += OnEventWithArgs;
                break;

            case DiscordEventType.GuildDeleted:
                client.GuildDeleted += OnEventWithArgs;
                break;

            case DiscordEventType.GuildUnavailable:
                client.GuildUnavailable += OnEventWithArgs;
                break;

            case DiscordEventType.MessageCreated:
                client.MessageCreated += OnEventWithArgs;
                break;

            case DiscordEventType.PresenceUpdated:
                client.PresenceUpdated += OnEventWithArgs;
                break;

            case DiscordEventType.GuildBanAdded:
                client.GuildBanAdded += OnEventWithArgs;
                break;

            case DiscordEventType.GuildBanRemoved:
                client.GuildBanRemoved += OnEventWithArgs;
                break;

            case DiscordEventType.GuildEmojisUpdated:
                client.GuildEmojisUpdated += OnEventWithArgs;
                break;

            case DiscordEventType.GuildIntegrationsUpdated:
                client.GuildIntegrationsUpdated += OnEventWithArgs;
                break;

            case DiscordEventType.GuildMemberAdded:
                client.GuildMemberAdded += OnEventWithArgs;
                break;

            case DiscordEventType.GuildMemberRemoved:
                client.GuildMemberRemoved += OnEventWithArgs;
                break;

            case DiscordEventType.GuildMemberUpdated:
                client.GuildMemberUpdated += OnEventWithArgs;
                break;

            case DiscordEventType.GuildRoleCreated:
                client.GuildRoleCreated += OnEventWithArgs;
                break;

            case DiscordEventType.GuildRoleUpdated:
                client.GuildRoleUpdated += OnEventWithArgs;
                break;

            case DiscordEventType.GuildRoleDeleted:
                client.GuildRoleDeleted += OnEventWithArgs;
                break;

            case DiscordEventType.MessageAcknowledged:
                client.MessageAcknowledged += OnEventWithArgs;
                break;

            case DiscordEventType.MessageUpdated:
                client.MessageUpdated += OnEventWithArgs;
                break;

            case DiscordEventType.MessageDeleted:
                client.MessageDeleted += OnEventWithArgs;
                break;

            case DiscordEventType.MessagesBulkDeleted:
                client.MessagesBulkDeleted += OnEventWithArgs;
                break;

            case DiscordEventType.TypingStarted:
                client.TypingStarted += OnEventWithArgs;
                break;

            case DiscordEventType.UserSettingsUpdated:
                client.UserSettingsUpdated += OnEventWithArgs;
                break;

            case DiscordEventType.UserUpdated:
                client.UserUpdated += OnEventWithArgs;
                break;

            case DiscordEventType.VoiceStateUpdated:
                client.VoiceStateUpdated += OnEventWithArgs;
                break;

            case DiscordEventType.VoiceServerUpdated:
                client.VoiceServerUpdated += OnEventWithArgs;
                break;

            case DiscordEventType.GuildMembersChunked:
                client.GuildMembersChunked += OnEventWithArgs;
                break;

            case DiscordEventType.UnknownEvent:
                client.UnknownEvent += OnEventWithArgs;
                break;

            case DiscordEventType.MessageReactionAdded:
                client.MessageReactionAdded += OnEventWithArgs;
                break;

            case DiscordEventType.MessageReactionRemoved:
                client.MessageReactionRemoved += OnEventWithArgs;
                break;

            case DiscordEventType.MessageReactionsCleared:
                client.MessageReactionsCleared += OnEventWithArgs;
                break;

            case DiscordEventType.WebhooksUpdated:
                client.WebhooksUpdated += OnEventWithArgs;
                break;

            case DiscordEventType.Heartbeated:
                client.Heartbeated += OnEventWithArgs;
                break;

            case DiscordEventType.CommandExecuted:
                shard.CNext.CommandExecuted += OnEventWithArgs;
                break;

            case DiscordEventType.CommandErrored:
                shard.CNext.CommandErrored += OnEventWithArgs;
                break;

                #endregion START_SWITCH_STATEMENT
            }
        }
Пример #25
0
            public Task AddAsync(CommandContext ctx,
                                 [RemainingText, Description("Code to evaluate.")] string code)
            {
                if (string.IsNullOrWhiteSpace(code))
                {
                    throw new InvalidCommandUsageException("Code missing.");
                }

                int cs1 = code.IndexOf("```") + 3;
                int cs2 = code.LastIndexOf("```");

                if (cs1 == -1 || cs2 == -1)
                {
                    throw new InvalidCommandUsageException("You need to wrap the code into a code block.");
                }

                code = $@"
[ModuleLifespan(ModuleLifespan.Transient)]
public sealed class DynamicCommands : FreudModule
{{
    public Dynamic Commands(SharedData shared, DatabaseContextBuilder dcb) : base(shard, dcb)
    {{
        this.ModuleColor = DiscordColor.NotQuiteBlack;
    }}

    {code.Substring(cs1, cs2 - cs1)}
}}";

                string type       = $"DynamicCommands{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}";
                Type   moduleType = null;

                try
                {
                    var refs = AppDomain.CurrentDomain.GetAssemblies()
                               .Where(xa => !xa.IsDynamic && !string.IsNullOrWhiteSpace(xa.Location))
                               .Select(x => MetadataReference.CreateFromFile(x.Location));

                    var ast  = SyntaxFactory.ParseSyntaxTree(code, new CSharpParseOptions().WithKind(SourceCodeKind.Script).WithLanguageVersion(LanguageVersion.Latest));
                    var opts = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary,
                                                            scriptClassName: type, usings: new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text",
                                                                                                   "System.Threading.Tasks", "DSharpPlus", "DSharpPlus.Entities", "DSharpPlus.CommandsNext",
                                                                                                   "DSharpPlus.CommandsNext.Attributes", "DSharpPlus.Interactivity" },
                                                            optimizationLevel: OptimizationLevel.Release, allowUnsafe: true, platform: Platform.X64);

                    var compilation = CSharpCompilation.CreateScriptCompilation(type, ast, refs, opts, returnType: typeof(object));

                    Assembly assembly = null;
                    using (var ms = new MemoryStream())
                    {
                        var result = compilation.Emit(ms);
                        ms.Position = 0;
                        assembly    = Assembly.Load(ms.ToArray());
                    }

                    var outType = assembly.ExportedTypes.FirstOrDefault(x => x.Name == type);
                    moduleType = outType.GetNestedTypes().FirstOrDefault(x => x.BaseType == typeof(BaseCommandModule));

                    ctx.CommandsNext.RegisterCommands(moduleType);
                    FreudShard.UpdateCommandList(ctx.CommandsNext);

                    return(this.InformAsync(ctx, StaticDiscordEmoji.Information, "Compilation successful! Command(s) successfully added!", important: false));
                } catch (Exception ex)
                {
                    return(this.InformOfFailureAsync(ctx, $"Compilation failed!\n\n{Formatter.Bold(ex.GetType().ToString())}: {ex.Message}"));
                }
            }
Пример #26
0
 public LinkfilterService(FreudShard shard)
     : base(shard)
 {
     this.reason = "bot: Linkfilter";
 }
Пример #27
0
        public static async Task MessageDeleteEventHandlerAsync(FreudShard shard, MessageDeleteEventArgs e)
        {
            if (e.Channel.IsPrivate || e.Message is null)
            {
                return;
            }

            var logchn = shard.SharedData.GetLogChannelForGuild(shard.Client, e.Guild);

            if (logchn is null || e.Channel.IsExempted(shard))
            {
                return;
            }
            if (e.Message.Author == e.Client.CurrentUser && shard.SharedData.IsEventRunningInChannel(e.Channel.Id))
            {
                return;
            }

            var emb = FormEmbedBuilder(EventOrigin.Message, "Message deleted");

            emb.AddField("Location", e.Channel.Mention, inline: true);
            emb.AddField("Author", e.Message.Author?.Mention ?? _unknown, inline: true);

            var entry = await e.Guild.GetLatestAuditLogEntryAsync(AuditLogActionType.MessageDelete);

            if (!(entry is null) && entry is DiscordAuditLogMessageEntry mentry)
            {
                var member = await e.Guild.GetMemberAsync(mentry.UserResponsible.Id);

                if (member.IsExempted(shard))
                {
                    return;
                }

                emb.AddField("User responsible", mentry.UserResponsible.Mention, inline: true);

                if (!string.IsNullOrWhiteSpace(mentry.Reason))
                {
                    emb.AddField("Reason", mentry.Reason);
                }
                emb.WithFooter(mentry.CreationTimestamp.ToUtcTimestamp(), mentry.UserResponsible.AvatarUrl);
            }

            if (!string.IsNullOrWhiteSpace(e.Message.Content))
            {
                emb.AddField("Content", $"{Formatter.BlockCode(string.IsNullOrWhiteSpace(e.Message.Content) ? "<empty content>" : FormatterExtensions.StripMarkdown(e.Message.Content.Truncate(1000)))}");

                if (shard.SharedData.MessageContainsFilter(e.Guild.Id, e.Message.Content))
                {
                    emb.WithDescription(Formatter.Italic("Message contained a filter."));
                }
            }

            if (e.Message.Embeds.Any())
            {
                emb.AddField("Embeds", e.Message.Embeds.Count.ToString(), inline: true);
            }
            if (e.Message.Reactions.Any())
            {
                emb.AddField("Reactions", string.Join(" ", e.Message.Reactions.Select(r => r.Emoji.GetDiscordName())), inline: true);
            }
            if (e.Message.Attachments.Any())
            {
                emb.AddField("Attachments", string.Join("\n", e.Message.Attachments.Select(a => a.FileName)), inline: true);
            }
            if (e.Message.CreationTimestamp != null)
            {
                emb.AddField("Message creation time", e.Message.CreationTimestamp.ToUtcTimestamp(), inline: true);
            }

            await logchn.SendMessageAsync(embed : emb.Build());
        }
Пример #28
0
 public AntifloodService(FreudShard shard)
     : base(shard)
 {
     this.guildFloodUsers = new ConcurrentDictionary <ulong, ConcurrentHashSet <DiscordMember> >();
     this.reason          = "bot: Flooding";
 }
Пример #29
0
 public AntiInstantLeaveService(FreudShard shard)
     : base(shard)
 {
     this.newGuildMembers = new ConcurrentDictionary <ulong, ConcurrentHashSet <DiscordMember> >();
     this.reason          = "bot: Instant leave";
 }