Exemplo n.º 1
0
        private async Task ChannelUpdated(DiscordClient sender, ChannelUpdateEventArgs e)
        {
            _newEntry = await GetNewEntryAsync();

            _entryBuilder = new DiscordEmbedBuilder();

            string commonType  = e.ChannelAfter.Type.ToRusCommon();
            string channelName = e.ChannelAfter.Name;


            var  entryType         = _newEntry?.ActionType;
            bool checkForSameEntry = false;

            switch (entryType)
            {
            case (AuditLogActionType.ChannelUpdate):
            {
                checkForSameEntry = true;        //Important because in second case we have defense by ow == null, and if any small updates happen don't wanna send same channel update entries
                var cuEntry = _newEntry as DiscordAuditLogChannelEntry;
                _entryBuilder = EmbedBuilderExtensions.CreateForAudit(cuEntry,
                                                                      $"Обновление параметров {commonType}",
                                                                      $"Обновлены параметры у {commonType} {channelName}");

                _entryBuilder.AddNamePropertyChange(cuEntry.NameChange);

                _entryBuilder.AddPropertyChange("Битрейт", cuEntry.BitrateChange);
                _entryBuilder.AddPropertyChange("NSFW", cuEntry.NsfwChange);
                _entryBuilder.AddPropertyChange("Слоумод", cuEntry.PerUserRateLimitChange);
                _entryBuilder.AddPropertyChange("Тема", cuEntry.TopicChange);
                break;
            }

            default:     // case if overwrite entry
            {
                var owsBefore = e.ChannelBefore.PermissionOverwrites;
                var owsAfter  = e.ChannelAfter.PermissionOverwrites;
                OverwriteUpdateInformation owUpdInfo = new OverwriteUpdateInformation(owsBefore, owsAfter);
                if (_newEntry != null)
                {
                    _entryBuilder = EmbedBuilderExtensions.CreateForAudit(_newEntry);
                    _entryBuilder.AddField("Изменённые оверврайты", string.Join("\n", owUpdInfo.Changes));
                }

                var ow = owUpdInfo.GetAffectedOverwrite();
                if (ow == null)
                {
                    return;                     //If we don't have overwriteupdates at all
                }
                _entryBuilder.SetTitle($"{owUpdInfo.Action} оверврайтов");

                string subj = ow.Type == OverwriteType.Role ?
                              "роли " + ow.GetRoleAsync().Result.Name :
                              "пользователя " + ow.GetMemberAsync().Result.Username;

                _entryBuilder.SetDescription($"{owUpdInfo.Action} оверврайтов для {subj} у {e.ChannelAfter.Type.ToRusCommon()} {channelName} ");
            }
            break;
            }
            await SendMessageToAuditAsync(checkForSameEntry, embed : _entryBuilder); //Don't set true on defense from same entry,
        }
 private static DiscordEmbedBuilder.EmbedAuthor AuditAuthor(DiscordAuditLogEntry entry)
 {
     return(new DiscordEmbedBuilder.EmbedAuthor()
     {
         IconUrl = entry.UserResponsible.AvatarUrl,
         Name = entry.UserResponsible.Username
     });
 }
Exemplo n.º 3
0
        /// <summary>
        /// Works only when audit type mdisconnect or mmove
        /// </summary>
        /// <param name="currentEntry"></param>
        /// <param name="otherEntry"></param>
        /// <returns></returns>

        /*   public static DiscordUser FindRemovedUser(this DiscordChannel channelBefore, DiscordChannel channelAfter)
         * {
         *     foreach (var u in channelBefore.Users)
         *     {
         *         if (!channelAfter.Users.Any((x) => x.Id == u.Id))
         *         {
         *             return u;
         *         }
         *     }
         *     return null;
         *
         * }*/
        public void AddToLastEntries(DiscordAuditLogEntry e)
        {
            lastMemberEntries.Enqueue(e);
            if (lastMemberEntries.Count == MAX_SIZE)
            {
                lastMemberEntries.Dequeue();
            }
        }
Exemplo n.º 4
0
 private async Task SendMessageToAuditAsync(bool checkForSameEntry = false, string content = null, DiscordEmbedBuilder embed = null)
 {
     if (_auditChannel == null || (checkForSameEntry && _newEntry.Id == _lastHandledEntry?.Id))
     {
         return;
     }
     _lastHandledEntry = _newEntry;
     await _auditChannel.SendMessageAsync(embed : embed, content : content);
 }
Exemplo n.º 5
0
        public static async Task MemberUpdateEventHandlerAsync(TheGodfatherShard shard, GuildMemberUpdateEventArgs e)
        {
            DiscordChannel logchn = shard.SharedData.GetLogChannelForGuild(shard.Client, e.Guild);

            if (logchn == null)
            {
                return;
            }

            DiscordEmbedBuilder emb = FormEmbedBuilder(EventOrigin.Member, "Member updated", e.Member.ToString());

            emb.WithThumbnailUrl(e.Member.AvatarUrl);

            DiscordAuditLogEntry entry = null;

            if (e.RolesBefore.Count == e.RolesAfter.Count)
            {
                entry = await e.Guild.GetFirstAuditLogEntryAsync(AuditLogActionType.MemberUpdate);
            }
            else
            {
                entry = await e.Guild.GetFirstAuditLogEntryAsync(AuditLogActionType.MemberRoleUpdate);
            }
            if (entry != null && entry is DiscordAuditLogMemberUpdateEntry mentry)
            {
                emb.AddField("User responsible", mentry.UserResponsible.Mention, inline: true);
                if (mentry.NicknameChange != null)
                {
                    emb.AddField("Nickname change", $"{mentry.NicknameChange.Before} -> {mentry.NicknameChange.After}", inline: true);
                }
                if (mentry.AddedRoles != null && mentry.AddedRoles.Any())
                {
                    emb.AddField("Added roles", string.Join(",", mentry.AddedRoles.Select(r => r.Name)), inline: true);
                }
                if (mentry.RemovedRoles != null && mentry.RemovedRoles.Any())
                {
                    emb.AddField("Removed roles", string.Join(",", mentry.RemovedRoles.Select(r => r.Name)), inline: true);
                }
                if (!string.IsNullOrWhiteSpace(mentry.Reason))
                {
                    emb.AddField("Reason", mentry.Reason);
                }
                emb.WithFooter(mentry.CreationTimestamp.ToUtcTimestamp(), mentry.UserResponsible.AvatarUrl);
            }
            else
            {
                emb.AddField("Error", "Failed to read audit log information. Please check my permissions");
                emb.AddField("Name before", e.NicknameBefore ?? _unknown, inline: true);
                emb.AddField("Name after", e.NicknameAfter ?? _unknown, inline: true);
                emb.AddField("Roles before", e.RolesBefore?.Count.ToString() ?? _unknown, inline: true);
                emb.AddField("Roles after", e.RolesAfter?.Count.ToString() ?? _unknown, inline: true);
            }

            await logchn.SendMessageAsync(embed : emb.Build());
        }
 public static DiscordEmbedBuilder CreateForAudit(DiscordAuditLogEntry entry, string title = null, string description = null, DiscordColor color = default)
 {
     return(new DiscordEmbedBuilder
     {
         Author = AuditAuthor(entry),
         Title = title,
         Description = description,
         Footer = AuditFooter(entry),
         Color = color
     });
 }
 public static async Task <DiscordAuditLogEntry> GetLatestAuditLogEntryAsync(this DiscordGuild guild, AuditLogActionType type)
 {
     try {
         DiscordAuditLogEntry entry = (await guild.GetAuditLogsAsync(1, action_type: type))
                                      ?.FirstOrDefault();
         if (entry is null || DateTime.UtcNow - entry.CreationTimestamp.ToUniversalTime() > TimeSpan.FromSeconds(5))
         {
             return(null);
         }
         return(entry);
     } catch {
     }
     return(null);
 }
Exemplo n.º 8
0
        private async Task <DiscordAuditLogEntry> GetNewEntryAsync()
        {
            try
            {
                var audit = await DefaultGuild.GetAuditLogsAsync(1);

                _newEntry = audit.First();
                return(_newEntry);
            }
            catch
            {
                _newEntry = null;
                return(_newEntry);
            }
        }
Exemplo n.º 9
0
        public static async Task ChannelCreateEventHandlerAsync(TheGodfatherShard shard, ChannelCreateEventArgs e)
        {
            DiscordChannel logchn = shard.SharedData.GetLogChannelForGuild(shard.Client, e.Guild);

            if (logchn is null)
            {
                return;
            }

            DiscordEmbedBuilder emb = FormEmbedBuilder(EventOrigin.Channel, "Channel created", e.Channel.ToString());

            DiscordAuditLogEntry 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");
            }
Exemplo n.º 10
0
        public static async Task GuildBanEventHandlerAsync(TheGodfatherShard shard, GuildBanAddEventArgs e)
        {
            DiscordChannel logchn = shard.SharedData.GetLogChannelForGuild(shard.Client, e.Guild);

            if (logchn is null)
            {
                return;
            }

            DiscordEmbedBuilder emb = FormEmbedBuilder(EventOrigin.KickOrBan, "User BANNED");

            DiscordAuditLogEntry 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");
            }
Exemplo n.º 11
0
        private async Task VoiceStateUpdated(DiscordClient sender, VoiceStateUpdateEventArgs e)
        {
            _newEntry = await GetNewEntryAsync();

            if (_newEntry.ActionType == AuditLogActionType.MemberUpdate)
            {
                var muEntry = _newEntry as DiscordAuditLogMemberUpdateEntry;
                _entryBuilder = EmbedBuilderExtensions.CreateForAudit(_newEntry);
                _entryBuilder.SetTitle("Обновление пользователя");
                _entryBuilder.AddPropertyChange("Мут", muEntry.MuteChange);
                _entryBuilder.AddPropertyChange("Заглушение", muEntry.DeafenChange);
            }
            else
            {
                return;
            }
            await SendMessageToAuditAsync(true, embed : _entryBuilder);
        }
Exemplo n.º 12
0
        private async Task ChannelDeleted(DiscordClient sender, ChannelDeleteEventArgs e)
        {
            _newEntry = await GetNewEntryAsync();

            var cdEntry = _newEntry as DiscordAuditLogChannelEntry;

            if (cdEntry == null)
            {
                return;                  // Defense from cases when we delete category with channels under it
            }
            var cType = cdEntry.Target.Type;

            _entryBuilder = EmbedBuilderExtensions.CreateForAudit(cdEntry, "Удаление " + cType.ToRusCommon());
            var shortDesc = $"Удаление {cType.ToRusCommon()} {cdEntry.Target.Name}";
            var desc      = cType == ChannelType.Category ? shortDesc : shortDesc + $", тип канала: {cType.ToRusString()}";

            _entryBuilder.SetDescription(desc);
            await SendMessageToAuditAsync(true, embed : _entryBuilder);
        }
Exemplo n.º 13
0
        public static async Task ChannelUpdateEventHandlerAsync(TheGodfatherShard shard, ChannelUpdateEventArgs e)
        {
            if (e.ChannelBefore.Position != e.ChannelAfter.Position)
            {
                return;
            }

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

            if (logchn == null)
            {
                return;
            }

            if (await shard.DatabaseService.IsExemptedAsync(e.Guild.Id, e.ChannelAfter.Id, EntityType.Channel))
            {
                return;
            }

            DiscordEmbedBuilder  emb   = FormEmbedBuilder(EventOrigin.Channel, "Channel updated");
            DiscordAuditLogEntry entry = await e.Guild.GetFirstAuditLogEntryAsync(AuditLogActionType.ChannelUpdate);

            if (entry != null && entry is DiscordAuditLogChannelEntry centry)       // Regular update
            {
                emb.WithDescription(centry.Target.ToString());
                emb.AddField("User responsible", centry.UserResponsible?.Mention ?? _unknown, inline: true);
                if (centry.BitrateChange != null)
                {
                    emb.AddField("Bitrate changed to", centry.BitrateChange.After.ToString(), inline: true);
                }
                if (centry.NameChange != null)
                {
                    emb.AddField("Name changed to", centry.NameChange.After, inline: true);
                }
                if (centry.NsfwChange != null)
                {
                    emb.AddField("NSFW flag changed to", centry.NsfwChange.After.Value.ToString(), inline: true);
                }
                if (centry.OverwriteChange != null)
                {
                    emb.AddField("Permissions overwrites changed", $"{centry.OverwriteChange.After.Count} overwrites after changes");
                }
                if (centry.TopicChange != null)
                {
                    string ptopic = Formatter.BlockCode(Formatter.Sanitize(string.IsNullOrWhiteSpace(centry.TopicChange.Before) ? " " : centry.TopicChange.Before));
                    string ctopic = Formatter.BlockCode(Formatter.Sanitize(string.IsNullOrWhiteSpace(centry.TopicChange.After) ? " " : centry.TopicChange.After));
                    emb.AddField("Topic changed", $"From:{ptopic}\nTo:{ctopic}");
                }
                if (centry.TypeChange != null)
                {
                    emb.AddField("Type changed to", centry.TypeChange.After.Value.ToString());
                }
                if (!string.IsNullOrWhiteSpace(centry.Reason))
                {
                    emb.AddField("Reason", centry.Reason);
                }
                emb.WithFooter($"At {centry.CreationTimestamp.ToUniversalTime().ToString()} UTC", centry.UserResponsible.AvatarUrl);
            }
            else        // Overwrite update
            {
                AuditLogActionType type;
                if (e.ChannelBefore.PermissionOverwrites.Count > e.ChannelAfter.PermissionOverwrites.Count)
                {
                    type  = AuditLogActionType.OverwriteCreate;
                    entry = await e.Guild.GetFirstAuditLogEntryAsync(AuditLogActionType.OverwriteCreate);
                }
                else if (e.ChannelBefore.PermissionOverwrites.Count < e.ChannelAfter.PermissionOverwrites.Count)
                {
                    type  = AuditLogActionType.OverwriteDelete;
                    entry = await e.Guild.GetFirstAuditLogEntryAsync(AuditLogActionType.OverwriteDelete);
                }
                else
                {
                    if (e.ChannelBefore.PermissionOverwrites.Zip(e.ChannelAfter.PermissionOverwrites, (o1, o2) => o1.Allowed != o1.Allowed && o2.Denied != o2.Denied).Any())
                    {
                        type  = AuditLogActionType.OverwriteUpdate;
                        entry = await e.Guild.GetFirstAuditLogEntryAsync(AuditLogActionType.OverwriteUpdate);
                    }
                    else
                    {
                        type  = AuditLogActionType.ChannelUpdate;
                        entry = await e.Guild.GetFirstAuditLogEntryAsync(AuditLogActionType.ChannelUpdate);
                    }
                }

                if (entry != null && entry is DiscordAuditLogOverwriteEntry owentry)
                {
                    emb.WithDescription($"{owentry.Channel.ToString()} ({type})");
                    emb.AddField("User responsible", owentry.UserResponsible?.Mention ?? _unknown, inline: true);

                    DiscordUser member = null;
                    DiscordRole role   = null;

                    try {
                        bool isMemberUpdated = owentry.Target.Type.HasFlag(OverwriteType.Member);
                        if (isMemberUpdated)
                        {
                            member = await e.Client.GetUserAsync(owentry.Target.Id);
                        }
                        else
                        {
                            role = e.Guild.GetRole(owentry.Target.Id);
                        }
                        emb.AddField("Target", isMemberUpdated ? member.ToString() : role.ToString(), inline: true);
                        if (owentry.AllowChange != null)
                        {
                            emb.AddField("Allowed", $"{owentry.Target.Allowed.ToPermissionString() ?? _unknown}", inline: true);
                        }
                        if (owentry.DenyChange != null)
                        {
                            emb.AddField("Denied", $"{owentry.Target.Denied.ToPermissionString() ?? _unknown}", inline: true);
                        }
                    } catch {
                        emb.AddField("Target ID", owentry.Target.Id.ToString(), inline: true);
                    }

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

            await logchn.SendMessageAsync(embed : emb.Build());
        }
 private static DiscordEmbedBuilder.EmbedFooter AuditFooter(DiscordAuditLogEntry newEntry)
 {
     return(new DiscordEmbedBuilder.EmbedFooter {
         Text = $"ID: {newEntry.Id}  Время действия: {newEntry.CreationTimestamp.LocalDateTime}"
     });
 }
Exemplo n.º 15
0
        private async Task UpdateAuditLogs(AuditLogActionType type, DiscordGuild guild)
        {
            DiscordAuditLogEntry entryLatest = (await guild.GetAuditLogsAsync(limit: 1, action_type: type))[0];
            DiscordEmbedBuilder  builder     = new DiscordEmbedBuilder();
            DiscordUser          responsible = entryLatest.UserResponsible;

            builder.WithAuthor(responsible.Username, null, responsible.AvatarUrl);

            switch (entryLatest.ActionCategory)
            {
            case AuditLogActionCategory.Create:
                builder.Color = DiscordColor.Green;
                break;

            case AuditLogActionCategory.Update:
                builder.Color = DiscordColor.Yellow;
                break;

            case AuditLogActionCategory.Delete:
                builder.Color = DiscordColor.Red;
                break;

            case AuditLogActionCategory.Other:
                builder.Color = DiscordColor.White;
                break;

            default:
                break;
            }

            switch (entryLatest.ActionType)
            {
            case AuditLogActionType.GuildUpdate:
                builder.WithTitle("Guild updated");
                break;

            case AuditLogActionType.ChannelCreate:
                builder.WithTitle("Channel created");
                break;

            case AuditLogActionType.ChannelUpdate:
                builder.WithTitle("Channel updated");
                break;

            case AuditLogActionType.ChannelDelete:
                builder.WithTitle("Channel deleted");
                break;

            case AuditLogActionType.OverwriteCreate:
                builder.WithTitle("Permission override for channel created");
                break;

            case AuditLogActionType.OverwriteUpdate:
                builder.WithTitle("Permission override for channel updated");
                break;

            case AuditLogActionType.OverwriteDelete:
                builder.WithTitle("Permission override for channel deleted");
                break;

            case AuditLogActionType.Kick:
                builder.WithTitle("User kicked");
                break;

            case AuditLogActionType.Prune:
                builder.WithTitle("Users pruned");
                break;

            case AuditLogActionType.Ban:
                builder.WithTitle("User banned");
                break;

            case AuditLogActionType.Unban:
                builder.WithTitle("User unbanned");
                break;

            case AuditLogActionType.MemberUpdate:
                builder.WithTitle("Member updated");
                break;

            case AuditLogActionType.MemberRoleUpdate:
                builder.WithTitle("Member role updated");
                break;

            case AuditLogActionType.RoleCreate:
                builder.WithTitle("Role created");
                break;

            case AuditLogActionType.RoleUpdate:
                builder.WithTitle("Role updated");
                break;

            case AuditLogActionType.RoleDelete:
                builder.WithTitle("Role deleted");
                break;

            case AuditLogActionType.InviteCreate:
                builder.WithTitle("Invite created");
                break;

            case AuditLogActionType.InviteUpdate:
                builder.WithTitle("Invite updated");
                break;

            case AuditLogActionType.InviteDelete:
                builder.WithTitle("Invite deleted");
                break;

            case AuditLogActionType.WebhookCreate:
                builder.WithTitle("Webhook created");
                break;

            case AuditLogActionType.WebhookUpdate:
                builder.WithTitle("Webhook updated");
                break;

            case AuditLogActionType.WebhookDelete:
                builder.WithTitle("Webhook deleted");
                break;

            case AuditLogActionType.EmojiCreate:
                builder.WithTitle("Emoji created");
                break;

            case AuditLogActionType.EmojiUpdate:
                builder.WithTitle("Emoji updated");
                break;

            case AuditLogActionType.EmojiDelete:
                builder.WithTitle("Emoji deleted");
                break;

            case AuditLogActionType.MessageDelete:
                builder.WithTitle("Message deleted (See logs channel for more info)");
                break;

            default:
                builder.WithTitle("Unknown event");
                break;
            }

            Type entryType = entryLatest.GetType();

            PropertyInfo[] properties = entryType.GetProperties();

            foreach (PropertyInfo prop in properties)
            {
                if (typeof(PropertyChange <>).IsAssignableFrom(prop.PropertyType))
                {
                    Type changeType = prop.PropertyType.GetGenericArguments()[0];
                }
                else
                {
                }
            }
        }
Exemplo n.º 16
0
        public static async Task MessageDeleteEventHandlerAsync(KioskAppShard shard, MessageDeleteEventArgs e)
        {
            if (e.Channel.IsPrivate || e.Message is null)
            {
                return;
            }

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

            if (logchn is null)
            {
                return;
            }

            using (DatabaseContext db = shard.Database.CreateContext())
                if (db.LoggingExempts.Any(ee => ee.Type == ExemptedEntityType.Channel && ee.Id == e.Channel.Id))
                {
                    return;
                }

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

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

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

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

                using (DatabaseContext db = shard.Database.CreateContext())
                {
                    if (db.LoggingExempts.Any(ee => ee.Type == ExemptedEntityType.Member && ee.Id == mentry.UserResponsible.Id))
                    {
                        return;
                    }
                    if (member?.Roles.Any(r => db.LoggingExempts.Any(ee => ee.Type == ExemptedEntityType.Role && ee.Id == r.Id)) ?? false)
                    {
                        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>" : Formatter.Strip(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());
        }
Exemplo n.º 17
0
        public static async Task GuildEmojisUpdateEventHandlerAsync(TheGodfatherShard shard, GuildEmojisUpdateEventArgs e)
        {
            DiscordChannel logchn = shard.SharedData.GetLogChannelForGuild(shard.Client, e.Guild);

            if (logchn == null)
            {
                return;
            }

            DiscordEmbedBuilder emb = FormEmbedBuilder(EventOrigin.Emoji, "Guild emojis updated");

            AuditLogActionType action;

            if (e.EmojisAfter.Count > e.EmojisBefore.Count)
            {
                action = AuditLogActionType.EmojiCreate;
            }
            else if (e.EmojisAfter.Count < e.EmojisBefore.Count)
            {
                action = AuditLogActionType.EmojiDelete;
            }
            else
            {
                action = AuditLogActionType.EmojiUpdate;
            }
            DiscordAuditLogEntry entry = await e.Guild.GetFirstAuditLogEntryAsync(action);

            emb.WithTitle($"Guild emoji action occured: {action.ToString()}");
            if (entry == null || !(entry is DiscordAuditLogEmojiEntry eentry))
            {
                emb.AddField("Error", "Failed to read audit log information. Please check my permissions");
                emb.AddField("Emojis before", e.EmojisBefore?.Count.ToString() ?? _unknown, inline: true);
                emb.AddField("Emojis after", e.EmojisAfter?.Count.ToString() ?? _unknown, inline: true);
            }
            else
            {
                switch (action)
                {
                case AuditLogActionType.EmojiCreate:
                    emb.WithDescription(eentry.Target.Name ?? _unknown);
                    emb.WithThumbnailUrl(eentry.Target.Url);
                    break;

                case AuditLogActionType.EmojiDelete:
                    emb.WithDescription(eentry.NameChange.Before ?? _unknown);
                    break;

                case AuditLogActionType.EmojiUpdate:
                    emb.WithDescription(eentry.Target.Name ?? _unknown);
                    if (eentry.NameChange != null)
                    {
                        emb.AddField("Name changes", $"{Formatter.InlineCode(eentry.NameChange.Before ?? "None")} -> {Formatter.InlineCode(eentry.NameChange.After ?? "None")}", inline: true);
                    }
                    break;

                default:
                    break;
                }
                emb.AddField("User responsible", eentry.UserResponsible.Mention, inline: true);
                if (!string.IsNullOrWhiteSpace(eentry.Reason))
                {
                    emb.AddField("Reason", eentry.Reason);
                }
                emb.WithFooter(eentry.CreationTimestamp.ToUtcTimestamp(), eentry.UserResponsible.AvatarUrl);
            }

            await logchn.SendMessageAsync(embed : emb.Build());
        }