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 }); }
/// <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(); } }
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); }
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); }
private async Task <DiscordAuditLogEntry> GetNewEntryAsync() { try { var audit = await DefaultGuild.GetAuditLogsAsync(1); _newEntry = audit.First(); return(_newEntry); } catch { _newEntry = null; return(_newEntry); } }
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"); }
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"); }
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); }
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); }
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}" }); }
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 { } } }
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()); }
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()); }