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()); }
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()); }
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)); }
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); }
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())); }