Пример #1
0
        public async Task HandleAsync(MessageDeletedEventArgs args)
        {
            if (!(args.Channel is CachedTextChannel channel) ||
                !args.Message.HasValue || args.Message.Value.Author.IsBot) // TODO: What to do when message doesn't have value, other than ignore
            {
                return;
            }

            using var ctx = new AdminDatabaseContext(_provider);
            var guild = await ctx.GetOrCreateGuildAsync(channel.Guild.Id);

            if (!(await ctx.GetLoggingChannelAsync(channel.Guild.Id, LogType.MessageDelete) is { } logChannel))
            {
                return;
            }

            var builder = new LocalEmbedBuilder()
                          .WithErrorColor()
                          .WithTitle(_localization.Localize(guild.Language, "logging_message_delete", channel.Tag))
                          .WithDescription(args.Message.Value.Author.Format(false))
                          .AddField(_localization.Localize(guild.Language, "info_id"), args.Message.Id)
                          .WithTimestamp(DateTimeOffset.UtcNow);

            if (!string.IsNullOrWhiteSpace(args.Message.Value.Content))
            {
                builder.AddField(_localization.Localize(guild.Language, "info_content"),
                                 args.Message.Value.Content.TrimTo(1024, true));
            }

            if (channel.Guild.CurrentMember.Permissions.ViewAuditLog)
            {
                await Task.Delay(TimeSpan.FromSeconds(1));

                var logs = await channel.Guild.GetAuditLogsAsync <RestMessagesDeletedAuditLog>(10);

                if (logs.FirstOrDefault(x =>
                                        x.TargetId == args.Message.Value.Author.Id && x.ChannelId == args.Channel.Id) is { } log)
                {
                    var moderator = await args.Client.GetOrDownloadUserAsync(log.ResponsibleUserId);

                    builder.WithTitle(_localization.Localize(guild.Language, "logging_message_delete_moderator", moderator.Tag, channel.Tag));
                }
            }

            if (_temporaryImages.Remove(args.Message.Id, out var attachment))
            {
                using (attachment)
                {
                    await logChannel.SendMessageAsync(attachment,
                                                      embed : builder
                                                      .WithImageUrl($"attachment://{attachment.FileName}")
                                                      .Build());
                }

                return;
            }

            await logChannel.SendMessageAsync(embed : builder.Build());
        }
Пример #2
0
        public static bool TryParseEmbed(string json, out LocalEmbedBuilder embed)
        {
            embed = new LocalEmbedBuilder();
            try
            {
                var embedDeserialized = JsonConvert.DeserializeObject <JsonEmbed>(json);

                var author      = embedDeserialized.Author;
                var title       = embedDeserialized.Title;
                var description = embedDeserialized.Description;

                var colorString = embedDeserialized.Color;
                var thumbnail   = embedDeserialized.Thumbnail;
                var image       = embedDeserialized.Image;
                var fields      = embedDeserialized.Fields;
                var footer      = embedDeserialized.Footer;
                var timestamp   = embedDeserialized.Timestamp;

                if (author != null)
                {
                    embed.WithAuthor(author);
                }

                if (!string.IsNullOrEmpty(title))
                {
                    embed.WithTitle(title);
                }

                if (!string.IsNullOrEmpty(description))
                {
                    embed.WithDescription(description);
                }

                if (!string.IsNullOrEmpty(colorString))
                {
                    embed.WithColor(HexToInt(colorString) ?? 0xFFFFFF);
                }

                if (!string.IsNullOrEmpty(thumbnail))
                {
                    embed.WithThumbnailUrl(thumbnail);
                }
                if (!string.IsNullOrEmpty(image))
                {
                    embed.WithImageUrl(image);
                }

                if (fields != null)
                {
                    foreach (var field in fields)
                    {
                        var fieldName   = field.Name;
                        var fieldValue  = field.Value;
                        var fieldInline = field.IsInline;

                        if (!string.IsNullOrEmpty(fieldName) && !string.IsNullOrEmpty(fieldValue))
                        {
                            embed.AddField(fieldName, fieldValue, fieldInline);
                        }
                    }
                }

                if (footer != null)
                {
                    embed.WithFooter(footer);
                }

                if (timestamp.HasValue)
                {
                    embed.WithTimestamp(timestamp.Value);
                }
                else if (embedDeserialized.WithCurrentTimestamp)
                {
                    embed.WithCurrentTimestamp();
                }

                return(true);
            }
            catch
            {
                return(false);
            }
        }
        private async Task SendTargetEmbedAsync(Punishment punishment, IUser target, Punishment additionalPunishment, LocalizedLanguage language)
        {
            var typeName = punishment.GetType().Name.ToLower();
            var builder  = new LocalEmbedBuilder().WithErrorColor()
                           .WithTitle(_localization.Localize(language, $"punishment_{typeName}") +
                                      $" - {_localization.Localize(language, "punishment_case", punishment.Id)}")
                           .AddField(_localization.Localize(language, "title_reason"),
                                     punishment.Reason ?? _localization.Localize(language, "punishment_noreason"))
                           .WithTimestamp(punishment.CreatedAt);

            if (!(additionalPunishment is null))
            {
                builder.AddField(FormatAdditionalPunishment(additionalPunishment, language));
            }

            if (punishment is Warning)
            {
                using var ctx = new AdminDatabaseContext(_provider);

                var warningCount = await ctx.Punishments.OfType <Warning>().CountAsync(x =>
                                                                                       x.TargetId == target.Id && x.GuildId == punishment.GuildId && !x.RevokedAt.HasValue);

                builder.WithDescription(_localization.Localize(language, "punishment_warning_description",
                                                               Markdown.Bold(_client.GetGuild(punishment.GuildId).Name.Sanitize()),
                                                               Markdown.Bold(warningCount.ToOrdinalWords(language.Culture))));
            }
            else
            {
                builder.WithDescription(_localization.Localize(language, $"punishment_{typeName}_description",
                                                               _client.GetGuild(punishment.GuildId).Name));
            }

            if (punishment is RevocablePunishment revocable)
            {
                var field = new LocalEmbedFieldBuilder()
                            .WithName(_localization.Localize(language, "punishment_appeal"));

                switch (revocable)
                {
                case Ban ban:
                    field.WithValue(!ban.Duration.HasValue || ban.Duration.Value > TimeSpan.FromDays(1)
                            ? GetAppealInstructions()
                            : _localization.Localize(language, "punishment_tooshort",
                                                     ban.Duration.Value.Humanize(minUnit: TimeUnit.Minute, culture: language.Culture)));
                    break;

                case Mute mute:
                    field.WithValue(!mute.Duration.HasValue || mute.Duration.Value > TimeSpan.FromDays(1)
                            ? GetAppealInstructions()
                            : _localization.Localize(language, "punishment_tooshort",
                                                     mute.Duration.Value.Humanize(minUnit: TimeUnit.Minute, culture: language.Culture)));
                    break;

                default:
                    field = null;
                    break;
                }

                if (!(field is null))
                {
                    builder.AddField(field);
                }

                string GetAppealInstructions()
                {
                    return(_localization.Localize(language, "punishment_appeal_instructions",
                                                  Markdown.Code(punishment.Id.ToString()),
                                                  Markdown.Code($"{_config.DefaultPrefix}appeal {punishment.Id} [{_localization.Localize(language, "title_reason").ToLower()}]")));
                }
            }

            if (punishment is Mute channelMute && channelMute.ChannelId.HasValue)
            {
                builder.AddField(_localization.Localize(language, "punishment_mute_channel"),
                                 _client.GetGuild(punishment.GuildId).GetTextChannel(channelMute.ChannelId.Value).Mention);
            }

            if (punishment.Format != ImageFormat.Default)
            {
                builder.WithImageUrl($"attachment://attachment.{punishment.Format.ToString().ToLower()}");
                _ = target.SendMessageAsync(new LocalAttachment(punishment.Image,
                                                                $"attachment.{punishment.Format.ToString().ToLower()}"), embed: builder.Build());

                return;
            }

            _ = target.SendMessageAsync(embed: builder.Build());
        }
Пример #4
0
        public async ValueTask <AdminCommandResult> CreateSuggestionAsync([Remainder] string text)
        {
            if (!(await Context.Database.GetLoggingChannelAsync(Context.Guild.Id,
                                                                LogType.Suggestion) is { } suggestionChannel))
            {
                return(CommandErrorLocalized("suggestion_nochannel"));
            }

            var image  = new MemoryStream();
            var format = ImageFormat.Default;

            if (Context.Message.Attachments.FirstOrDefault() is { } attachment&&
                attachment.FileName.HasImageExtension(out format))
            {
                await using var stream = await Http.GetStreamAsync(attachment.Url);

                await stream.CopyToAsync(image);

                image.Seek(0, SeekOrigin.Begin);
            }

            if (format == ImageFormat.Default)
            {
                var match = StringExtensions.LazyImageLinkRegex.Match(text);
                if (match.Success && match.Value.HasImageExtension(out format))
                {
                    try
                    {
                        await using var stream = await Http.GetStreamAsync(match.Value);

                        await stream.CopyToAsync(image);

                        image.Seek(0, SeekOrigin.Begin);
                    }
                    catch { /* ignored */ }
                }
            }

            var suggestion = Context.Database.Suggestions.Add(new Suggestion(Context.Guild.Id, Context.User.Id, text, image, format))
                             .Entity;
            await Context.Database.SaveChangesAsync();

            var builder = new LocalEmbedBuilder()
                          .WithSuccessColor()
                          .WithAuthor(Context.User)
                          .WithDescription(text)
                          .WithFooter(Context.Localize("suggestion_id", suggestion.Id));

            RestUserMessage message;

            if (format != ImageFormat.Default)
            {
                message = await suggestionChannel.SendMessageAsync(new LocalAttachment(image, $"attachment.{format.ToString().ToLower()}"),
                                                                   embed : builder.WithImageUrl($"attachment://attachment.{format.ToString().ToLower()}").Build());
            }
            else
            {
                message = await suggestionChannel.SendMessageAsync(embed : builder.Build());
            }

            var upvote = (await Context.Database.SpecialEmojis.FindAsync(Context.Guild.Id.RawValue, EmojiType.Upvote))?.Emoji ??
                         EmojiTools.Upvote;
            var downvote = (await Context.Database.SpecialEmojis.FindAsync(Context.Guild.Id.RawValue, EmojiType.Downvote))?.Emoji ??
                           EmojiTools.Downvote;

            await message.AddReactionAsync(upvote);

            await message.AddReactionAsync(downvote);

            suggestion.SetMessageId(message.Id);
            Context.Database.Suggestions.Update(suggestion);
            await Context.Database.SaveChangesAsync();

            _ = Context.Message.DeleteAsync();
            return(CommandSuccessLocalized("suggestion_successful", args: suggestion.Id));
        }
Пример #5
0
        public async ValueTask <AdminCommandResult> ModifySuggestionAsync(int id, [Remainder] string reason = null)
        {
            var suggestion = await Context.Database.Suggestions.FindAsync(id);

            if (suggestion?.GuildId != Context.Guild.Id)
            {
                return(CommandErrorLocalized("suggestion_notfound"));
            }

            if (!(await Context.Database.GetLoggingChannelAsync(Context.Guild.Id, LogType.SuggestionArchive) is { }
                  archiveChannel))
            {
                return(CommandErrorLocalized("suggestion_noarchive"));
            }

            IUserMessage message = null;
            int          upvotes = 0, downvotes = 0;

            if (await Context.Database.GetLoggingChannelAsync(Context.Guild.Id, LogType.Suggestion) is { }
                suggestionChannel)
            {
                try
                {
                    message = (IUserMessage)await suggestionChannel.GetMessageAsync(suggestion.MessageId);

                    var upvote = (await Context.Database.SpecialEmojis.FindAsync(Context.Guild.Id.RawValue, EmojiType.Upvote))?.Emoji ??
                                 EmojiTools.Upvote;
                    var downvote = (await Context.Database.SpecialEmojis.FindAsync(Context.Guild.Id.RawValue, EmojiType.Downvote))?.Emoji ??
                                   EmojiTools.Downvote;

                    upvotes   = Math.Max((await message.GetReactionsAsync(upvote, int.MaxValue)).Count - 1, 0);
                    downvotes = Math.Max((await message.GetReactionsAsync(downvote, int.MaxValue)).Count - 1, 0);
                }
                catch { /* ignored */ }
            }

            var author = await Context.Client.GetOrDownloadUserAsync(suggestion.UserId);

            var builder = new LocalEmbedBuilder()
                          .WithAuthor(Context.Localize(Context.Alias.Equals("approve")
                        ? "suggestion_approved_title"
                        : "suggestion_denied_title", suggestion.Id, author.Tag, upvotes, downvotes),
                                      author.GetAvatarUrl())
                          .WithDescription(suggestion.Text)
                          .WithFooter(Context.Localize(Context.Alias.Equals("approve")
                        ? "suggestion_approved_footer"
                        : "suggestion_denied_footer", Context.User.Tag),
                                      Context.User.GetAvatarUrl());

            if (Context.Alias.Equals("approve"))
            {
                builder.WithSuccessColor();
            }
            else
            {
                builder.WithErrorColor();
            }

            if (!string.IsNullOrWhiteSpace(reason))
            {
                builder.AddField(Context.Localize("title_reason"), reason);
            }

            if (suggestion.Format != ImageFormat.Default)
            {
                await archiveChannel.SendMessageAsync(new LocalAttachment(suggestion.Image, $"attachment.{suggestion.Format.ToString().ToLower()}"),
                                                      embed : builder.WithImageUrl($"attachment://attachment.{suggestion.Format.ToString().ToLower()}").Build());
            }
            else
            {
                await archiveChannel.SendMessageAsync(embed : builder.Build());
            }

            _ = message?.DeleteAsync();

            Context.Database.Suggestions.Remove(suggestion);
            await Context.Database.SaveChangesAsync();

            return(CommandSuccessLocalized(Context.Alias.Equals("approve")
                ? "suggestion_approved"
                : "suggestion_denied"));
        }
 public LocalizedEmbedBuilder WithImageUrl(string imageUrl)
 {
     _builder.WithImageUrl(imageUrl);
     return(this);
 }
Пример #7
0
            public async ValueTask <AdminCommandResult> ShowPunishmentAsync([MustBe(Operator.GreaterThan, 0)] int id)
            {
                var punishment =
                    await Context.Database.Punishments.FirstOrDefaultAsync(x =>
                                                                           x.GuildId == Context.Guild.Id && x.Id == id);

                if (punishment is null)
                {
                    return(CommandErrorLocalized("punishment_notfound_id"));
                }


                var target = await Context.Client.GetOrDownloadUserAsync(punishment.TargetId);

                var moderator = await Context.Client.GetOrDownloadUserAsync(punishment.ModeratorId);

                var builder = new LocalEmbedBuilder()
                              .WithSuccessColor()
                              .WithTitle(Context.Localize($"punishment_{punishment.GetType().Name.ToLower()}") +
                                         $" - {Context.Localize("punishment_case", punishment.Id)}")
                              .AddField(Context.Localize("punishment_target_title"), target?.Format(false) ?? "???", true)
                              .AddField(Context.Localize("punishment_moderator_title"), moderator?.Format(false) ?? "???", true)
                              .AddField(Context.Localize("punishment_timestamp_title"),
                                        punishment.CreatedAt.ToString("g", Context.Language.Culture), true)
                              .AddField(Context.Localize("title_reason"),
                                        punishment.Reason ?? Context.Localize("punishment_noreason"));

                switch (punishment)
                {
                case Ban ban:
                    builder.AddField(Context.Localize("punishment_duration"),
                                     ban.Duration.HasValue
                                ? ban.Duration.Value.HumanizeFormatted(Localization, Context.Language, TimeUnit.Second)
                                : Context.Localize("punishment_permanent"));
                    break;

                case Mute mute:
                    if (mute.ChannelId.HasValue)
                    {
                        builder.AddField(Context.Localize("punishment_mute_channel"),
                                         Context.Guild.GetTextChannel(mute.ChannelId.Value)?.Mention ?? "???");
                    }
                    builder.AddField(Context.Localize("punishment_duration"),
                                     mute.Duration.HasValue
                                ? mute.Duration.Value.HumanizeFormatted(Localization, Context.Language, TimeUnit.Second)
                                : Context.Localize("punishment_permanent"));
                    break;

                case Warning warning when warning.SecondaryPunishmentId.HasValue:
                    var secondary = await Context.Database.Punishments.FindAsync(warning.SecondaryPunishmentId.Value);

                    builder.AddField(Punishments.FormatAdditionalPunishment(secondary, Context.Language));
                    break;
                }

                if (punishment is RevocablePunishment revocable)
                {
                    if (revocable.IsAppealable)
                    {
                        builder.AddField(Context.Localize("punishment_appealed"), revocable.AppealedAt.HasValue
                            ? $"✅ {revocable.AppealedAt.Value.ToString("g", Context.Language.Culture)} - {revocable.AppealReason.TrimTo(950)}"
                            : "❌");
                    }

                    var revoker = revocable.RevokedAt.HasValue
                        ? await Context.Client.GetOrDownloadUserAsync(revocable.RevokerId)
                        : default;

                    builder.AddField(Context.Localize("punishment_revoked"), revocable.RevokedAt.HasValue
                        ? "✅ " + revocable.RevokedAt.Value.ToString("g", Context.Language.Culture) + $" - {Markdown.Bold(revoker?.Tag ?? "???")} - " +
                                     (revocable.RevocationReason?.TrimTo(920) ?? Context.Localize("punishment_noreason"))
                        : "❌");
                }

                if (punishment.Format != ImageFormat.Default)
                {
                    builder.WithImageUrl($"attachment://attachment.{punishment.Format.ToString().ToLower()}");
                    return(CommandSuccess(embed: builder.Build(), attachment: new LocalAttachment(punishment.Image,
                                                                                                  $"attachment.{punishment.Format.ToString().ToLower()}")));
                }

                return(CommandSuccess(embed: builder.Build()));
            }