[Feature] Audit Log Created gateway event support (#2627)

* add event to socket client

* make `AuditLog` param optional

* Some WIP audit log changes

* api models

* moar models

* complete models

* modelsss

* forgot to push

* oh lol forgot this too

* api & rest guild method

* revert VS being VS & formatting to file scoped namespace

* socket entities

* some work eh

* moar stuff

- switched to d.net's attribute for audit log deserialization

* working socket guild updated event + reworked rest GuildInfo creation

* a bit of refactoring + new models

* +channel created

* channel updated & channel deleted

* refactor rest channel updated log + some nullable fixes

* rest channel created + deleted logs

* user banned socket log

* kick + unban

* moar log modelsssss

* fixes & 4 more log types

* overwrite logs

* role logs

* invite logs

* webhook logs

* switch to `ISocketAuditLogData` for socket log data

* emote logs

* move stuff around

* move more stuff around

* audit logs cache

* scheduled event logs

* thread logs

* command permission update audit log

* fetch scheduled event data from log

* integration audit logs

* sticker audit log data

* stage instance audit logs

* auto mod rule audit logs

* fix

* forgot couple props

* command perm updated data from options

* final automod ones

* debugging goes away :(

* merge cringe

* ...

* yup

* fix xml doc

* onboarding audit logs

* changes

---------

Co-authored-by: cat <lumitydev@gmail.com>
This commit is contained in:
Misha133
2023-04-15 02:13:02 +03:00
committed by GitHub
parent 3a8f76c4b1
commit dff6a57a92
181 changed files with 8992 additions and 2805 deletions

View File

@@ -205,6 +205,50 @@ namespace Discord
/// <summary> /// <summary>
/// A thread was deleted. /// A thread was deleted.
/// </summary> /// </summary>
ThreadDelete = 112 ThreadDelete = 112,
/// <summary>
/// Permissions were updated for a command.
/// </summary>
ApplicationCommandPermissionUpdate = 121,
/// <summary>
/// Auto Moderation rule was created.
/// </summary>
AutoModerationRuleCreate = 140,
/// <summary>
/// Auto Moderation rule was updated.
/// </summary>
AutoModerationRuleUpdate = 141,
/// <summary>
/// Auto Moderation rule was deleted.
/// </summary>
AutoModerationRuleDelete = 142,
/// <summary>
/// Message was blocked by Auto Moderation.
/// </summary>
AutoModerationBlockMessage = 143,
/// <summary>
/// Message was flagged by Auto Moderation.
/// </summary>
AutoModerationFlagToChannel = 144,
/// <summary>
/// Member was timed out by Auto Moderation.
/// </summary>
AutoModerationUserCommunicationDisabled = 145,
/// <summary>
/// Guild Onboarding Question was created.
/// </summary>
OnboardingQuestionCreated = 163,
/// <summary>
/// Guild Onboarding Question was updated.
/// </summary>
OnboardingQuestionUpdated = 164,
/// <summary>
/// Guild Onboarding was updated.
/// </summary>
OnboardingUpdated = 167
} }
} }

View File

@@ -0,0 +1,6 @@
namespace Discord;
public interface IAuditLogInfoModel
{
}

View File

@@ -17,17 +17,11 @@ namespace Discord
/// <summary> /// <summary>
/// Three days (4320 minutes). /// Three days (4320 minutes).
/// <remarks>
/// This option is explicitly available to nitro users.
/// </remarks>
/// </summary> /// </summary>
ThreeDays = 4320, ThreeDays = 4320,
/// <summary> /// <summary>
/// One week (10080 minutes). /// One week (10080 minutes).
/// <remarks>
/// This option is explicitly available to nitro users.
/// </remarks>
/// </summary> /// </summary>
OneWeek = 10080 OneWeek = 10080
} }

View File

@@ -7,6 +7,8 @@ using System.Threading.Tasks;
namespace Discord namespace Discord
{ {
// when adding properties to guilds please check if they are returned in audit log events and add them to the
// 'GuildInfo.cs' file for socket and rest audit logs.
/// <summary> /// <summary>
/// Represents a generic guild/server. /// Represents a generic guild/server.
/// </summary> /// </summary>

View File

@@ -0,0 +1,30 @@
using Discord.Rest;
namespace Discord.API.AuditLogs;
internal class AutoModRuleInfoAuditLogModel : IAuditLogInfoModel
{
[JsonField("name")]
public string Name { get; set; }
[JsonField("event_type")]
public AutoModEventType EventType { get; set; }
[JsonField("trigger_type")]
public AutoModTriggerType TriggerType { get; set; }
[JsonField("trigger_metadata")]
public TriggerMetadata TriggerMetadata { get; set; }
[JsonField("actions")]
public AutoModAction[] Actions { get; set; }
[JsonField("enabled")]
public bool Enabled { get; set; }
[JsonField("exempt_roles")]
public ulong[] ExemptRoles { get; set; }
[JsonField("exempt_channels")]
public ulong[] ExemptChannels { get; set; }
}

View File

@@ -0,0 +1,57 @@
using Discord.Rest;
namespace Discord.API.AuditLogs;
internal class ChannelInfoAuditLogModel : IAuditLogInfoModel
{
[JsonField("name")]
public string Name { get; set; }
[JsonField("type")]
public ChannelType? Type { get; set; }
[JsonField("permission_overwrites")]
public Overwrite[] Overwrites { get; set; }
[JsonField("flags")]
public ChannelFlags? Flags { get; set; }
[JsonField("default_thread_rate_limit_per_user")]
public int? DefaultThreadRateLimitPerUser { get; set; }
[JsonField("default_auto_archive_duration")]
public ThreadArchiveDuration? DefaultArchiveDuration { get; set; }
[JsonField("rate_limit_per_user")]
public int? RateLimitPerUser { get; set; }
[JsonField("auto_archive_duration")]
public ThreadArchiveDuration? AutoArchiveDuration { get; set; }
[JsonField("nsfw")]
public bool? IsNsfw { get; set; }
[JsonField("topic")]
public string Topic { get; set; }
// Forum channels
[JsonField("available_tags")]
public ForumTag[] AvailableTags { get; set; }
[JsonField("default_reaction_emoji")]
public ForumReactionEmoji DefaultEmoji { get; set; }
// Voice channels
[JsonField("user_limit")]
public int? UserLimit { get; set; }
[JsonField("rtc_region")]
public string Region { get; set; }
[JsonField("video_quality_mode")]
public VideoQualityMode? VideoQualityMode { get; set; }
[JsonField("bitrate")]
public int? Bitrate { get; set; }
}

View File

@@ -0,0 +1,82 @@
using Discord.Rest;
namespace Discord.API.AuditLogs;
public class GuildInfoAuditLogModel : IAuditLogInfoModel
{
[JsonField("name")]
public string Name { get; set; }
[JsonField("afk_timeout")]
public int? AfkTimeout { get; set; }
[JsonField("widget_enabled")]
public bool? IsEmbeddable { get; set; }
[JsonField("default_message_notifications")]
public DefaultMessageNotifications? DefaultMessageNotifications { get; set; }
[JsonField("mfa_level")]
public MfaLevel? MfaLevel { get; set; }
[JsonField("verification_level")]
public VerificationLevel? VerificationLevel { get; set; }
[JsonField("explicit_content_filter")]
public ExplicitContentFilterLevel? ExplicitContentFilterLevel { get; set; }
[JsonField("icon_hash")]
public string IconHash { get; set; }
[JsonField("discovery_splash")]
public string DiscoverySplash { get; set; }
[JsonField("splash")]
public string Splash { get; set; }
[JsonField("afk_channel_id")]
public ulong? AfkChannelId { get; set; }
[JsonField("widget_channel_id")]
public ulong? EmbeddedChannelId { get; set; }
[JsonField("system_channel_id")]
public ulong? SystemChannelId { get; set; }
[JsonField("rules_channel_id")]
public ulong? RulesChannelId { get; set; }
[JsonField("public_updates_channel_id")]
public ulong? PublicUpdatesChannelId { get; set; }
[JsonField("owner_id")]
public ulong? OwnerId { get; set; }
[JsonField("application_id")]
public ulong? ApplicationId { get; set; }
[JsonField("region")]
public string RegionId { get; set; }
[JsonField("banner")]
public string Banner { get; set; }
[JsonField("vanity_url_code")]
public string VanityUrl { get; set; }
[JsonField("system_channel_flags")]
public SystemChannelMessageDeny? SystemChannelFlags { get; set; }
[JsonField("description")]
public string Description { get; set; }
[JsonField("preferred_locale")]
public string PreferredLocale { get; set; }
[JsonField("nsfw_level")]
public NsfwLevel? NsfwLevel { get; set; }
[JsonField("premium_progress_bar_enabled")]
public bool? ProgressBarEnabled { get; set; }
}

View File

@@ -0,0 +1,33 @@
using Discord.Rest;
namespace Discord.API.AuditLogs;
internal class IntegrationInfoAuditLogModel : IAuditLogInfoModel
{
[JsonField("name")]
public string Name { get; set; }
[JsonField("type")]
public string Type { get; set; }
[JsonField("enabled")]
public bool? Enabled { get; set; }
[JsonField("syncing")]
public bool? Syncing { get; set; }
[JsonField("role_id")]
public ulong? RoleId { get; set; }
[JsonField("enable_emoticons")]
public bool? EnableEmojis { get; set; }
[JsonField("expire_behavior")]
public IntegrationExpireBehavior? ExpireBehavior { get; set; }
[JsonField("expire_grace_period")]
public int? ExpireGracePeriod { get; set; }
[JsonField("scopes")]
public string[] Scopes { get; set; }
}

View File

@@ -0,0 +1,27 @@
using Discord.Rest;
namespace Discord.API.AuditLogs;
internal class InviteInfoAuditLogModel : IAuditLogInfoModel
{
[JsonField("code")]
public string Code { get; set; }
[JsonField("channel_id")]
public ulong? ChannelId { get; set; }
[JsonField("inviter_id")]
public ulong? InviterId { get; set; }
[JsonField("uses")]
public int? Uses { get; set; }
[JsonField("max_uses")]
public int? MaxUses { get; set; }
[JsonField("max_age")]
public int? MaxAge { get; set; }
[JsonField("temporary")]
public bool? Temporary { get; set; }
}

View File

@@ -0,0 +1,19 @@
using Discord.Rest;
using System;
namespace Discord.API.AuditLogs;
internal class MemberInfoAuditLogModel : IAuditLogInfoModel
{
[JsonField("nick")]
public string Nickname { get; set; }
[JsonField("mute")]
public bool? IsMuted { get; set; }
[JsonField("deaf")]
public bool? IsDeafened { get; set; }
[JsonField("communication_disabled_until")]
public DateTimeOffset? TimeOutUntil { get; set; }
}

View File

@@ -0,0 +1,15 @@
using Discord.Rest;
namespace Discord.API.AuditLogs;
internal class OnboardingAuditLogModel : IAuditLogInfoModel
{
[JsonField("default_channel_ids")]
public ulong[] DefaultChannelIds { get; set; }
[JsonField("prompts")]
public GuildOnboardingPrompt[] Prompts { get; set; }
[JsonField("enabled")]
public bool? Enabled { get; set; }
}

View File

@@ -0,0 +1,27 @@
using Discord.Rest;
namespace Discord.API.AuditLogs;
internal class OnboardingPromptAuditLogModel : IAuditLogInfoModel
{
[JsonField("id")]
public ulong? Id { get; set; }
[JsonField("title")]
public string Title { get; set; }
[JsonField("options")]
public GuildOnboardingPromptOption[] Options { get; set; }
[JsonField("single_select")]
public bool? IsSingleSelect { get; set; }
[JsonField("required")]
public bool? IsRequired { get; set; }
[JsonField("in_onboarding")]
public bool? IsInOnboarding { get; set; }
[JsonField("type")]
public GuildOnboardingPromptType? Type { get; set; }
}

View File

@@ -0,0 +1,24 @@
using Discord.Rest;
namespace Discord.API.AuditLogs;
internal class RoleInfoAuditLogModel : IAuditLogInfoModel
{
[JsonField("name")]
public string Name { get; set; }
[JsonField("color")]
public uint? Color { get; set; }
[JsonField("hoist")]
public bool? Hoist { get; set; }
[JsonField("permissions")]
public ulong? Permissions { get; set; }
[JsonField("mentionable")]
public bool? IsMentionable { get; set; }
[JsonField("icon_hash")]
public string IconHash { get; set; }
}

View File

@@ -0,0 +1,43 @@
using Discord.Rest;
using System;
namespace Discord.API.AuditLogs;
internal class ScheduledEventInfoAuditLogModel : IAuditLogInfoModel
{
[JsonField("channel_id")]
public ulong? ChannelId { get; set; }
[JsonField("name")]
public string Name { get; set; }
[JsonField("description")]
public string Description { get; set; }
[JsonField("scheduled_start_time")]
public DateTimeOffset? StartTime { get; set; }
[JsonField("scheduled_end_time")]
public DateTimeOffset? EndTime { get; set; }
[JsonField("privacy_level")]
public GuildScheduledEventPrivacyLevel? PrivacyLevel { get; set; }
[JsonField("status")]
public GuildScheduledEventStatus? EventStatus { get; set; }
[JsonField("entity_type")]
public GuildScheduledEventType? EventType { get; set; }
[JsonField("entity_id")]
public ulong? EntityId { get; set; }
[JsonField("user_count")]
public int? UserCount { get; set; }
[JsonField("location")]
public string Location { get; set; }
[JsonField("image")]
public string Image { get; set; }
}

View File

@@ -0,0 +1,15 @@
using Discord.Rest;
namespace Discord.API.AuditLogs;
internal class StickerInfoAuditLogModel : IAuditLogInfoModel
{
[JsonField("name")]
public string Name { get; set; }
[JsonField("tags")]
public string Tags { get; set; }
[JsonField("description")]
public string Description { get; set; }
}

View File

@@ -0,0 +1,30 @@
using Discord.Rest;
namespace Discord.API.AuditLogs;
internal class ThreadInfoAuditLogModel : IAuditLogInfoModel
{
[JsonField("name")]
public string Name { get; set; }
[JsonField("type")]
public ThreadType Type { get; set; }
[JsonField("archived")]
public bool? IsArchived { get; set; }
[JsonField("locked")]
public bool? IsLocked { get; set;}
[JsonField("auto_archive_duration")]
public ThreadArchiveDuration? ArchiveDuration { get; set; }
[JsonField("rate_limit_per_user")]
public int? SlowModeInterval { get; set; }
[JsonField("flags")]
public ChannelFlags? ChannelFlags { get; set; }
[JsonField("applied_tags")]
public ulong[] AppliedTags { get; set; }
}

View File

@@ -0,0 +1,18 @@
using Discord.Rest;
namespace Discord.API.AuditLogs;
internal class WebhookInfoAuditLogModel : IAuditLogInfoModel
{
[JsonField("channel_id")]
public ulong? ChannelId { get; set; }
[JsonField("name")]
public string Name { get; set; }
[JsonField("type")]
public WebhookType? Type { get; set; }
[JsonField("avatar_hash")]
public string AvatarHash { get; set; }
}

View File

@@ -14,6 +14,9 @@ namespace Discord.API
[JsonProperty("application_id")] [JsonProperty("application_id")]
public ulong ApplicationId { get; set; } public ulong ApplicationId { get; set; }
[JsonProperty("guild_id")]
public Optional<ulong> GuildId { get; set; }
[JsonProperty("name")] [JsonProperty("name")]
public string Name { get; set; } public string Name { get; set; }

View File

@@ -18,5 +18,14 @@ namespace Discord.API
[JsonProperty("audit_log_entries")] [JsonProperty("audit_log_entries")]
public AuditLogEntry[] Entries { get; set; } public AuditLogEntry[] Entries { get; set; }
[JsonProperty("application_commands")]
public ApplicationCommand[] Commands { get; set; }
[JsonProperty("auto_moderation_rules")]
public AutoModerationRule[] AutoModerationRules { get; set;}
[JsonProperty("guild_scheduled_events")]
public GuildScheduledEvent[] GuildScheduledEvents { get; set; }
} }
} }

View File

@@ -1,9 +1,9 @@
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Discord.API namespace Discord.API;
internal class AuditLogOptions
{ {
internal class AuditLogOptions
{
[JsonProperty("count")] [JsonProperty("count")]
public int? Count { get; set; } public int? Count { get; set; }
[JsonProperty("channel_id")] [JsonProperty("channel_id")]
@@ -24,5 +24,16 @@ namespace Discord.API
public PermissionTarget OverwriteType { get; set; } public PermissionTarget OverwriteType { get; set; }
[JsonProperty("id")] [JsonProperty("id")]
public ulong? OverwriteTargetId { get; set; } public ulong? OverwriteTargetId { get; set; }
}
// App command perm update
[JsonProperty("application_id")]
public ulong? ApplicationId { get; set; }
// Automod
[JsonProperty("auto_moderation_rule_name")]
public string AutoModRuleName { get; set; }
[JsonProperty("auto_moderation_rule_trigger_type")]
public AutoModTriggerType? AutoModRuleTriggerType { get; set; }
} }

View File

@@ -72,7 +72,7 @@ namespace Discord.API
//ForumChannel //ForumChannel
[JsonProperty("available_tags")] [JsonProperty("available_tags")]
public Optional<ForumTags[]> ForumTags { get; set; } public Optional<ForumTag[]> ForumTags { get; set; }
[JsonProperty("applied_tags")] [JsonProperty("applied_tags")]
public Optional<ulong[]> AppliedTags { get; set; } public Optional<ulong[]> AppliedTags { get; set; }

View File

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
namespace Discord.API namespace Discord.API
{ {
internal class ForumTags internal class ForumTag
{ {
[JsonProperty("id")] [JsonProperty("id")]
public ulong Id { get; set; } public ulong Id { get; set; }

View File

@@ -1,17 +1,19 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using AuditLogChange = Discord.API.AuditLogChange;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
{
internal static class AuditLogHelper
{
private static readonly Dictionary<ActionType, Func<BaseDiscordClient, Model, EntryModel, IAuditLogData>> CreateMapping
= new Dictionary<ActionType, Func<BaseDiscordClient, Model, EntryModel, IAuditLogData>>()
{
[ActionType.GuildUpdated] = GuildUpdateAuditLogData.Create,
internal static class AuditLogHelper
{
private static readonly Dictionary<ActionType, Func<BaseDiscordClient, EntryModel, Model, IAuditLogData>> CreateMapping
= new ()
{
[ActionType.GuildUpdated] = GuildUpdateAuditLogData.Create, // log
[ActionType.ChannelCreated] = ChannelCreateAuditLogData.Create, [ActionType.ChannelCreated] = ChannelCreateAuditLogData.Create,
[ActionType.ChannelUpdated] = ChannelUpdateAuditLogData.Create, [ActionType.ChannelUpdated] = ChannelUpdateAuditLogData.Create,
[ActionType.ChannelDeleted] = ChannelDeleteAuditLogData.Create, [ActionType.ChannelDeleted] = ChannelDeleteAuditLogData.Create,
@@ -58,14 +60,63 @@ namespace Discord.Rest
[ActionType.ThreadCreate] = ThreadCreateAuditLogData.Create, [ActionType.ThreadCreate] = ThreadCreateAuditLogData.Create,
[ActionType.ThreadUpdate] = ThreadUpdateAuditLogData.Create, [ActionType.ThreadUpdate] = ThreadUpdateAuditLogData.Create,
[ActionType.ThreadDelete] = ThreadDeleteAuditLogData.Create, [ActionType.ThreadDelete] = ThreadDeleteAuditLogData.Create,
[ActionType.ApplicationCommandPermissionUpdate] = CommandPermissionUpdateAuditLogData.Create,
[ActionType.IntegrationCreated] = IntegrationCreatedAuditLogData.Create,
[ActionType.IntegrationUpdated] = IntegrationUpdatedAuditLogData.Create,
[ActionType.IntegrationDeleted] = IntegrationDeletedAuditLogData.Create,
[ActionType.StageInstanceCreated] = StageInstanceCreateAuditLogData.Create,
[ActionType.StageInstanceUpdated] = StageInstanceUpdatedAuditLogData.Create,
[ActionType.StageInstanceDeleted] = StageInstanceDeleteAuditLogData.Create,
[ActionType.StickerCreated] = StickerCreatedAuditLogData.Create,
[ActionType.StickerUpdated] = StickerUpdatedAuditLogData.Create,
[ActionType.StickerDeleted] = StickerDeletedAuditLogData.Create,
[ActionType.AutoModerationRuleCreate] = AutoModRuleCreatedAuditLogData.Create,
[ActionType.AutoModerationRuleUpdate] = AutoModRuleUpdatedAuditLogData.Create,
[ActionType.AutoModerationRuleDelete] = AutoModRuleDeletedAuditLogData.Create,
[ActionType.AutoModerationBlockMessage] = AutoModBlockedMessageAuditLogData.Create,
[ActionType.AutoModerationFlagToChannel] = AutoModFlaggedMessageAuditLogData.Create,
[ActionType.AutoModerationUserCommunicationDisabled] = AutoModTimeoutUserAuditLogData.Create,
[ActionType.OnboardingQuestionCreated] = OnboardingPromptCreatedAuditLogData.Create,
[ActionType.OnboardingQuestionUpdated] = OnboardingPromptUpdatedAuditLogData.Create,
[ActionType.OnboardingUpdated] = OnboardingUpdatedAuditLogData.Create,
}; };
public static IAuditLogData CreateData(BaseDiscordClient discord, Model log, EntryModel entry) public static IAuditLogData CreateData(BaseDiscordClient discord, EntryModel entry, Model log = null)
{ {
if (CreateMapping.TryGetValue(entry.Action, out var func)) if (CreateMapping.TryGetValue(entry.Action, out var func))
return func(discord, log, entry); return func(discord, entry, log);
return null; return null;
} }
internal static (T, T) CreateAuditLogEntityInfo<T>(AuditLogChange[] changes, BaseDiscordClient discord) where T : IAuditLogInfoModel
{
var oldModel = (T)Activator.CreateInstance(typeof(T))!;
var newModel = (T)Activator.CreateInstance(typeof(T))!;
var props = typeof(T).GetProperties();
foreach (var property in props)
{
if (property.GetCustomAttributes(typeof(JsonFieldAttribute), true).FirstOrDefault() is not JsonFieldAttribute jsonAttr)
continue;
var change = changes.FirstOrDefault(x => x.ChangedProperty == jsonAttr.FieldName);
if (change is null)
continue;
property.SetValue(oldModel, change.OldValue?.ToObject(property.PropertyType, discord.ApiClient.Serializer));
property.SetValue(newModel, change.NewValue?.ToObject(property.PropertyType, discord.ApiClient.Serializer));
}
return (oldModel, newModel);
} }
} }

View File

@@ -0,0 +1,38 @@
using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog;
namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to message getting blocked by automod.
/// </summary>
public class AutoModBlockedMessageAuditLogData : IAuditLogData
{
internal AutoModBlockedMessageAuditLogData(ulong channelId, string autoModRuleName, AutoModTriggerType autoModRuleTriggerType)
{
ChannelId = channelId;
AutoModRuleName = autoModRuleName;
AutoModRuleTriggerType = autoModRuleTriggerType;
}
internal static AutoModBlockedMessageAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{
return new(entry.Options.ChannelId!.Value, entry.Options.AutoModRuleName,
entry.Options.AutoModRuleTriggerType!.Value);
}
/// <summary>
/// Gets the channel the message was sent in.
/// </summary>
public ulong ChannelId { get; set; }
/// <summary>
/// Gets the name of the auto moderation rule that got triggered.
/// </summary>
public string AutoModRuleName { get; set; }
/// <summary>
/// Gets the trigger type of the auto moderation rule that got triggered.
/// </summary>
public AutoModTriggerType AutoModRuleTriggerType { get; set; }
}

View File

@@ -0,0 +1,38 @@
using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog;
namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to message getting flagged by automod.
/// </summary>
public class AutoModFlaggedMessageAuditLogData : IAuditLogData
{
internal AutoModFlaggedMessageAuditLogData(ulong channelId, string autoModRuleName, AutoModTriggerType autoModRuleTriggerType)
{
ChannelId = channelId;
AutoModRuleName = autoModRuleName;
AutoModRuleTriggerType = autoModRuleTriggerType;
}
internal static AutoModFlaggedMessageAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{
return new(entry.Options.ChannelId!.Value, entry.Options.AutoModRuleName,
entry.Options.AutoModRuleTriggerType!.Value);
}
/// <summary>
/// Gets the channel the message was sent in.
/// </summary>
public ulong ChannelId { get; set; }
/// <summary>
/// Gets the name of the auto moderation rule that got triggered.
/// </summary>
public string AutoModRuleName { get; set; }
/// <summary>
/// Gets the trigger type of the auto moderation rule that got triggered.
/// </summary>
public AutoModTriggerType AutoModRuleTriggerType { get; set; }
}

View File

@@ -0,0 +1,31 @@
using Discord.API.AuditLogs;
using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog;
namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to an auto moderation rule creation.
/// </summary>
public class AutoModRuleCreatedAuditLogData : IAuditLogData
{
private AutoModRuleCreatedAuditLogData(AutoModRuleInfo data)
{
Data = data;
}
internal static AutoModRuleCreatedAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{
var changes = entry.Changes;
var (_, data) = AuditLogHelper.CreateAuditLogEntityInfo<AutoModRuleInfoAuditLogModel>(changes, discord);
return new AutoModRuleCreatedAuditLogData(new (data));
}
/// <summary>
/// Gets the auto moderation rule information after the changes.
/// </summary>
public AutoModRuleInfo Data { get; }
}

View File

@@ -0,0 +1,31 @@
using Discord.API.AuditLogs;
using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog;
namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to an auto moderation rule removal.
/// </summary>
public class AutoModRuleDeletedAuditLogData : IAuditLogData
{
private AutoModRuleDeletedAuditLogData(AutoModRuleInfo data)
{
Data = data;
}
internal static AutoModRuleDeletedAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{
var changes = entry.Changes;
var (data, _) = AuditLogHelper.CreateAuditLogEntityInfo<AutoModRuleInfoAuditLogModel>(changes, discord);
return new AutoModRuleDeletedAuditLogData(new (data));
}
/// <summary>
/// Gets the auto moderation rule information before the changes.
/// </summary>
public AutoModRuleInfo Data { get; }
}

View File

@@ -0,0 +1,113 @@
using Discord.API.AuditLogs;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
namespace Discord.Rest;
/// <summary>
/// Represents information for an auto moderation rule.
/// </summary>
public class AutoModRuleInfo
{
internal AutoModRuleInfo(AutoModRuleInfoAuditLogModel model)
{
Actions = model.Actions?.Select(x => new AutoModRuleAction(
x.Type,
x.Metadata.GetValueOrDefault()?.ChannelId.ToNullable(),
x.Metadata.GetValueOrDefault()?.DurationSeconds.ToNullable(),
x.Metadata.IsSpecified
? x.Metadata.Value.CustomMessage.IsSpecified
? x.Metadata.Value.CustomMessage.Value
: null
: null
)).ToImmutableArray();
KeywordFilter = model.TriggerMetadata?.KeywordFilter.GetValueOrDefault(Array.Empty<string>())?.ToImmutableArray();
Presets = model.TriggerMetadata?.Presets.GetValueOrDefault(Array.Empty<KeywordPresetTypes>())?.ToImmutableArray();
RegexPatterns = model.TriggerMetadata?.RegexPatterns.GetValueOrDefault(Array.Empty<string>())?.ToImmutableArray();
AllowList = model.TriggerMetadata?.AllowList.GetValueOrDefault(Array.Empty<string>())?.ToImmutableArray();
MentionTotalLimit = model.TriggerMetadata?.MentionLimit.IsSpecified ?? false
? model.TriggerMetadata?.MentionLimit.Value
: null;
Name = model.Name;
Enabled = model.Enabled;
ExemptRoles = model.ExemptRoles?.ToImmutableArray();
ExemptChannels = model.ExemptChannels?.ToImmutableArray();
TriggerType = model.TriggerType;
EventType = model.EventType;
}
/// <inheritdoc cref="IAutoModRule.Name"/>
/// <remarks>
/// <see langword="null"/> if this property is not mentioned in this entry.
/// </remarks>
public string Name { get; set; }
/// <inheritdoc cref="IAutoModRule.EventType"/>
/// <remarks>
/// <see langword="null"/> if this property is not mentioned in this entry.
/// </remarks>
public AutoModEventType? EventType { get; set; }
/// <inheritdoc cref="IAutoModRule.TriggerType"/>
/// <remarks>
/// <see langword="null"/> if this property is not mentioned in this entry.
/// </remarks>
public AutoModTriggerType? TriggerType { get; set; }
/// <inheritdoc cref="IAutoModRule.Enabled"/>
/// <remarks>
/// <see langword="null"/> if this property is not mentioned in this entry.
/// </remarks>
public bool? Enabled { get; set; }
/// <inheritdoc cref="IAutoModRule.ExemptRoles"/>
/// <remarks>
/// <see langword="null"/> if this property is not mentioned in this entry.
/// </remarks>
public IReadOnlyCollection<ulong> ExemptRoles { get; set; }
/// <inheritdoc cref="IAutoModRule.ExemptChannels"/>
/// <remarks>
/// <see langword="null"/> if this property is not mentioned in this entry.
/// </remarks>
public IReadOnlyCollection<ulong> ExemptChannels { get; set; }
/// <inheritdoc cref="IAutoModRule.KeywordFilter"/>
/// <remarks>
/// <see langword="null"/> if this property is not mentioned in this entry.
/// </remarks>
public IReadOnlyCollection<string> KeywordFilter { get; }
/// <inheritdoc cref="IAutoModRule.RegexPatterns"/>
/// <remarks>
/// <see langword="null"/> if this property is not mentioned in this entry.
/// </remarks>
public IReadOnlyCollection<string> RegexPatterns { get; }
/// <inheritdoc cref="IAutoModRule.AllowList"/>
/// <remarks>
/// <see langword="null"/> if this property is not mentioned in this entry.
/// </remarks>
public IReadOnlyCollection<string> AllowList { get; }
/// <inheritdoc cref="IAutoModRule.Presets"/>
/// <remarks>
/// <see langword="null"/> if this property is not mentioned in this entry.
/// </remarks>
public IReadOnlyCollection<KeywordPresetTypes> Presets { get; }
/// <inheritdoc cref="IAutoModRule.MentionTotalLimit"/>
/// <remarks>
/// <see langword="null"/> if this property is not mentioned in this entry.
/// </remarks>
public int? MentionTotalLimit { get; }
/// <inheritdoc cref="IAutoModRule.Actions"/>
/// <remarks>
/// <see langword="null"/> if this property is not mentioned in this entry.
/// </remarks>
public IReadOnlyCollection<AutoModRuleAction> Actions { get; private set; }
}

View File

@@ -0,0 +1,45 @@
using Discord.API.AuditLogs;
using System.Linq;
using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog;
namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to an auto moderation rule update.
/// </summary>
public class AutoModRuleUpdatedAuditLogData : IAuditLogData
{
private AutoModRuleUpdatedAuditLogData(AutoModRuleInfo before, AutoModRuleInfo after, IAutoModRule rule)
{
Before = before;
After = after;
Rule = rule;
}
internal static AutoModRuleUpdatedAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{
var changes = entry.Changes;
var (before, after) = AuditLogHelper.CreateAuditLogEntityInfo<AutoModRuleInfoAuditLogModel>(changes, discord);
var rule = RestAutoModRule.Create(discord, log.AutoModerationRules.FirstOrDefault(x => x.Id == entry.TargetId));
return new AutoModRuleUpdatedAuditLogData(new (before), new(after), rule);
}
/// <summary>
/// Gets the auto moderation rule the changes correspond to.
/// </summary>
public IAutoModRule Rule { get; }
/// <summary>
/// Gets the auto moderation rule information before the changes.
/// </summary>
public AutoModRuleInfo Before { get; }
/// <summary>
/// Gets the auto moderation rule information after the changes.
/// </summary>
public AutoModRuleInfo After { get; }
}

View File

@@ -0,0 +1,38 @@
using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog;
namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to user getting in timeout by automod.
/// </summary>
public class AutoModTimeoutUserAuditLogData : IAuditLogData
{
internal AutoModTimeoutUserAuditLogData(ulong channelId, string autoModRuleName, AutoModTriggerType autoModRuleTriggerType)
{
ChannelId = channelId;
AutoModRuleName = autoModRuleName;
AutoModRuleTriggerType = autoModRuleTriggerType;
}
internal static AutoModTimeoutUserAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{
return new(entry.Options.ChannelId!.Value, entry.Options.AutoModRuleName,
entry.Options.AutoModRuleTriggerType!.Value);
}
/// <summary>
/// Gets the channel the message was sent in.
/// </summary>
public ulong ChannelId { get; set; }
/// <summary>
/// Gets the name of the auto moderation rule that got triggered.
/// </summary>
public string AutoModRuleName { get; set; }
/// <summary>
/// Gets the trigger type of the auto moderation rule that got triggered.
/// </summary>
public AutoModTriggerType AutoModRuleTriggerType { get; set; }
}

View File

@@ -2,19 +2,19 @@ using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a ban.
/// </summary>
public class BanAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to a ban.
/// </summary>
public class BanAuditLogData : IAuditLogData
{
private BanAuditLogData(IUser user) private BanAuditLogData(IUser user)
{ {
Target = user; Target = user;
} }
internal static BanAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static BanAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log = null)
{ {
var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId); var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId);
return new BanAuditLogData((userInfo != null) ? RestUser.Create(discord, userInfo) : null); return new BanAuditLogData((userInfo != null) ? RestUser.Create(discord, userInfo) : null);
@@ -30,5 +30,4 @@ namespace Discord.Rest
/// A user object representing the banned user. /// A user object representing the banned user.
/// </returns> /// </returns>
public IUser Target { get; } public IUser Target { get; }
}
} }

View File

@@ -2,19 +2,19 @@ using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a adding a bot to a guild.
/// </summary>
public class BotAddAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to a adding a bot to a guild.
/// </summary>
public class BotAddAuditLogData : IAuditLogData
{
private BotAddAuditLogData(IUser bot) private BotAddAuditLogData(IUser bot)
{ {
Target = bot; Target = bot;
} }
internal static BotAddAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static BotAddAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId); var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId);
return new BotAddAuditLogData((userInfo != null) ? RestUser.Create(discord, userInfo) : null); return new BotAddAuditLogData((userInfo != null) ? RestUser.Create(discord, userInfo) : null);
@@ -30,5 +30,4 @@ namespace Discord.Rest
/// A user object representing the bot. /// A user object representing the bot.
/// </returns> /// </returns>
public IUser Target { get; } public IUser Target { get; }
}
} }

View File

@@ -1,48 +1,65 @@
using Discord.API.AuditLogs;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq; using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a channel creation.
/// </summary>
public class ChannelCreateAuditLogData : IAuditLogData
{ {
/// <summary> private ChannelCreateAuditLogData(ChannelInfoAuditLogModel model, EntryModel entry)
/// Contains a piece of audit log data related to a channel creation.
/// </summary>
public class ChannelCreateAuditLogData : IAuditLogData
{ {
private ChannelCreateAuditLogData(ulong id, string name, ChannelType type, int? rateLimit, bool? nsfw, int? bitrate, IReadOnlyCollection<Overwrite> overwrites) ChannelId = entry.TargetId!.Value;
ChannelName = model.Name;
ChannelType = model.Type!.Value;
SlowModeInterval = model.RateLimitPerUser;
IsNsfw = model.IsNsfw;
Bitrate = model.Bitrate;
Topic = model.Topic;
AutoArchiveDuration = model.AutoArchiveDuration;
DefaultSlowModeInterval = model.DefaultThreadRateLimitPerUser;
DefaultAutoArchiveDuration = model.DefaultArchiveDuration;
AvailableTags = model.AvailableTags?.Select(x => new ForumTag(x.Id,
x.Name,
x.EmojiId.GetValueOrDefault(null),
x.EmojiName.GetValueOrDefault(null),
x.Moderated)).ToImmutableArray();
if (model.DefaultEmoji is not null)
{ {
ChannelId = id; if (model.DefaultEmoji.EmojiId.HasValue && model.DefaultEmoji.EmojiId.Value != 0)
ChannelName = name; DefaultReactionEmoji = new Emote(model.DefaultEmoji.EmojiId.GetValueOrDefault(), null, false);
ChannelType = type; else if (model.DefaultEmoji.EmojiName.IsSpecified)
SlowModeInterval = rateLimit; DefaultReactionEmoji = new Emoji(model.DefaultEmoji.EmojiName.Value);
IsNsfw = nsfw; else
Bitrate = bitrate; DefaultReactionEmoji = null;
Overwrites = overwrites; }
else
DefaultReactionEmoji = null;
VideoQualityMode = model.VideoQualityMode;
RtcRegion = model.Region;
Flags = model.Flags;
UserLimit = model.UserLimit;
Overwrites = model.Overwrites?.Select(x => new Overwrite(x.TargetId, x.TargetType, new OverwritePermissions(x.Allow, x.Deny)))
.ToImmutableArray();
} }
internal static ChannelCreateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static ChannelCreateAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log = null)
{ {
var changes = entry.Changes; var changes = entry.Changes;
var overwritesModel = changes.FirstOrDefault(x => x.ChangedProperty == "permission_overwrites"); var (_, data) = AuditLogHelper.CreateAuditLogEntityInfo<ChannelInfoAuditLogModel>(changes, discord);
var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type");
var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name");
var rateLimitPerUserModel = changes.FirstOrDefault(x => x.ChangedProperty == "rate_limit_per_user");
var nsfwModel = changes.FirstOrDefault(x => x.ChangedProperty == "nsfw");
var bitrateModel = changes.FirstOrDefault(x => x.ChangedProperty == "bitrate");
var overwrites = overwritesModel.NewValue.ToObject<API.Overwrite[]>(discord.ApiClient.Serializer) return new ChannelCreateAuditLogData(data, entry);
.Select(x => new Overwrite(x.TargetId, x.TargetType, new OverwritePermissions(x.Allow, x.Deny)))
.ToList();
var type = typeModel.NewValue.ToObject<ChannelType>(discord.ApiClient.Serializer);
var name = nameModel.NewValue.ToObject<string>(discord.ApiClient.Serializer);
int? rateLimitPerUser = rateLimitPerUserModel?.NewValue?.ToObject<int>(discord.ApiClient.Serializer);
bool? nsfw = nsfwModel?.NewValue?.ToObject<bool>(discord.ApiClient.Serializer);
int? bitrate = bitrateModel?.NewValue?.ToObject<int>(discord.ApiClient.Serializer);
var id = entry.TargetId.Value;
return new ChannelCreateAuditLogData(id, name, type, rateLimitPerUser, nsfw, bitrate, overwrites.ToReadOnlyCollection());
} }
/// <summary> /// <summary>
@@ -52,6 +69,7 @@ namespace Discord.Rest
/// A <see cref="ulong"/> representing the snowflake identifier for the created channel. /// A <see cref="ulong"/> representing the snowflake identifier for the created channel.
/// </returns> /// </returns>
public ulong ChannelId { get; } public ulong ChannelId { get; }
/// <summary> /// <summary>
/// Gets the name of the created channel. /// Gets the name of the created channel.
/// </summary> /// </summary>
@@ -59,6 +77,7 @@ namespace Discord.Rest
/// A string containing the name of the created channel. /// A string containing the name of the created channel.
/// </returns> /// </returns>
public string ChannelName { get; } public string ChannelName { get; }
/// <summary> /// <summary>
/// Gets the type of the created channel. /// Gets the type of the created channel.
/// </summary> /// </summary>
@@ -66,6 +85,7 @@ namespace Discord.Rest
/// The type of channel that was created. /// The type of channel that was created.
/// </returns> /// </returns>
public ChannelType ChannelType { get; } public ChannelType ChannelType { get; }
/// <summary> /// <summary>
/// Gets the current slow-mode delay of the created channel. /// Gets the current slow-mode delay of the created channel.
/// </summary> /// </summary>
@@ -75,6 +95,7 @@ namespace Discord.Rest
/// <c>null</c> if this is not mentioned in this entry. /// <c>null</c> if this is not mentioned in this entry.
/// </returns> /// </returns>
public int? SlowModeInterval { get; } public int? SlowModeInterval { get; }
/// <summary> /// <summary>
/// Gets the value that indicates whether the created channel is NSFW. /// Gets the value that indicates whether the created channel is NSFW.
/// </summary> /// </summary>
@@ -83,6 +104,7 @@ namespace Discord.Rest
/// <c>null</c> if this is not mentioned in this entry. /// <c>null</c> if this is not mentioned in this entry.
/// </returns> /// </returns>
public bool? IsNsfw { get; } public bool? IsNsfw { get; }
/// <summary> /// <summary>
/// Gets the bit-rate that the clients in the created voice channel are requested to use. /// Gets the bit-rate that the clients in the created voice channel are requested to use.
/// </summary> /// </summary>
@@ -92,6 +114,7 @@ namespace Discord.Rest
/// <c>null</c> if this is not mentioned in this entry. /// <c>null</c> if this is not mentioned in this entry.
/// </returns> /// </returns>
public int? Bitrate { get; } public int? Bitrate { get; }
/// <summary> /// <summary>
/// Gets a collection of permission overwrites that was assigned to the created channel. /// Gets a collection of permission overwrites that was assigned to the created channel.
/// </summary> /// </summary>
@@ -100,5 +123,54 @@ namespace Discord.Rest
/// assigned to the created channel. /// assigned to the created channel.
/// </returns> /// </returns>
public IReadOnlyCollection<Overwrite> Overwrites { get; } public IReadOnlyCollection<Overwrite> Overwrites { get; }
}
/// <summary>
/// Gets the thread archive duration that was set in the created channel.
/// </summary>
public ThreadArchiveDuration? AutoArchiveDuration { get; }
/// <summary>
/// Gets the default thread archive duration that was set in the created channel.
/// </summary>
public ThreadArchiveDuration? DefaultAutoArchiveDuration { get; }
/// <summary>
/// Gets the default slow mode interval that will be set in child threads in the channel.
/// </summary>
public int? DefaultSlowModeInterval { get; }
/// <summary>
/// Gets the topic that was set in the created channel.
/// </summary>
public string Topic { get; }
/// <summary>
/// Gets tags available in the created forum channel.
/// </summary>
public IReadOnlyCollection<ForumTag> AvailableTags { get; }
/// <summary>
/// Gets the default reaction added to posts in the created forum channel.
/// </summary>
public IEmote DefaultReactionEmoji { get; }
/// <summary>
/// Gets the user limit configured in the created voice channel.
/// </summary>
public int? UserLimit { get; }
/// <summary>
/// Gets the video quality mode configured in the created voice channel.
/// </summary>
public VideoQualityMode? VideoQualityMode { get; }
/// <summary>
/// Gets the region configured in the created voice channel.
/// </summary>
public string RtcRegion { get; }
/// <summary>
/// Gets channel flags configured for the created channel.
/// </summary>
public ChannelFlags? Flags { get; }
} }

View File

@@ -1,48 +1,69 @@
using Discord.API.AuditLogs;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq; using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a channel deletion.
/// </summary>
public class ChannelDeleteAuditLogData : IAuditLogData
{ {
/// <summary> private ChannelDeleteAuditLogData(ChannelInfoAuditLogModel model, EntryModel entry)
/// Contains a piece of audit log data related to a channel deletion.
/// </summary>
public class ChannelDeleteAuditLogData : IAuditLogData
{ {
private ChannelDeleteAuditLogData(ulong id, string name, ChannelType type, int? rateLimit, bool? nsfw, int? bitrate, IReadOnlyCollection<Overwrite> overwrites) ChannelId = entry.TargetId!.Value;
ChannelType = model.Type!.Value;
ChannelName = model.Name;
Topic = model.Topic;
IsNsfw = model.IsNsfw;
Bitrate = model.Bitrate;
DefaultArchiveDuration = model.DefaultArchiveDuration;
SlowModeInterval = model.RateLimitPerUser;
ForumTags = model.AvailableTags?.Select(
x => new ForumTag(x.Id,
x.Name,
x.EmojiId.GetValueOrDefault(null),
x.EmojiName.GetValueOrDefault(null),
x.Moderated)).ToImmutableArray();
if (model.DefaultEmoji is not null)
{ {
ChannelId = id; if (model.DefaultEmoji.EmojiId.HasValue && model.DefaultEmoji.EmojiId.Value != 0)
ChannelName = name; DefaultReactionEmoji = new Emote(model.DefaultEmoji.EmojiId.GetValueOrDefault(), null, false);
ChannelType = type; else if (model.DefaultEmoji.EmojiName.IsSpecified)
SlowModeInterval = rateLimit; DefaultReactionEmoji = new Emoji(model.DefaultEmoji.EmojiName.Value);
IsNsfw = nsfw; else
Bitrate = bitrate; DefaultReactionEmoji = null;
Overwrites = overwrites; }
else
DefaultReactionEmoji = null;
AutoArchiveDuration = model.AutoArchiveDuration;
DefaultSlowModeInterval = model.DefaultThreadRateLimitPerUser;
VideoQualityMode = model.VideoQualityMode;
RtcRegion = model.Region;
Flags = model.Flags;
UserLimit = model.UserLimit;
Overwrites = model.Overwrites?.Select(x
=> new Overwrite(x.TargetId,
x.TargetType,
new OverwritePermissions(x.Allow, x.Deny))).ToImmutableArray();
} }
internal static ChannelDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static ChannelDeleteAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log = null)
{ {
var changes = entry.Changes; var changes = entry.Changes;
var overwritesModel = changes.FirstOrDefault(x => x.ChangedProperty == "permission_overwrites"); var (data, _) = AuditLogHelper.CreateAuditLogEntityInfo<ChannelInfoAuditLogModel>(changes, discord);
var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type");
var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name");
var rateLimitPerUserModel = changes.FirstOrDefault(x => x.ChangedProperty == "rate_limit_per_user");
var nsfwModel = changes.FirstOrDefault(x => x.ChangedProperty == "nsfw");
var bitrateModel = changes.FirstOrDefault(x => x.ChangedProperty == "bitrate");
var overwrites = overwritesModel.OldValue.ToObject<API.Overwrite[]>(discord.ApiClient.Serializer) return new ChannelDeleteAuditLogData(data, entry);
.Select(x => new Overwrite(x.TargetId, x.TargetType, new OverwritePermissions(x.Allow, x.Deny)))
.ToList();
var type = typeModel.OldValue.ToObject<ChannelType>(discord.ApiClient.Serializer);
var name = nameModel.OldValue.ToObject<string>(discord.ApiClient.Serializer);
int? rateLimitPerUser = rateLimitPerUserModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer);
bool? nsfw = nsfwModel?.OldValue?.ToObject<bool>(discord.ApiClient.Serializer);
int? bitrate = bitrateModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer);
var id = entry.TargetId.Value;
return new ChannelDeleteAuditLogData(id, name, type, rateLimitPerUser, nsfw, bitrate, overwrites.ToReadOnlyCollection());
} }
/// <summary> /// <summary>
@@ -98,5 +119,57 @@ namespace Discord.Rest
/// A collection of permission <see cref="Overwrite"/>. /// A collection of permission <see cref="Overwrite"/>.
/// </returns> /// </returns>
public IReadOnlyCollection<Overwrite> Overwrites { get; } public IReadOnlyCollection<Overwrite> Overwrites { get; }
} /// <summary>
/// Gets the user limit configured in the created voice channel.
/// </summary>
public int? UserLimit { get; }
/// <summary>
/// Gets the video quality mode configured in the created voice channel.
/// </summary>
public VideoQualityMode? VideoQualityMode { get; }
/// <summary>
/// Gets the region configured in the created voice channel.
/// </summary>
public string RtcRegion { get; }
/// <summary>
/// Gets channel flags configured for the created channel.
/// </summary>
public ChannelFlags? Flags { get; }
/// <summary>
/// Gets the thread archive duration that was configured for the created channel.
/// </summary>
public ThreadArchiveDuration? AutoArchiveDuration { get; }
/// <summary>
/// Gets the default slow mode interval that was configured for the channel.
/// </summary>
public int? DefaultSlowModeInterval { get; }
/// <inheritdoc cref="ITextChannel.DefaultArchiveDuration"/>
/// <remarks>
/// <see langword="null" /> if the value was not specified in this entry..
/// </remarks>
public ThreadArchiveDuration? DefaultArchiveDuration { get; }
/// <inheritdoc cref="IForumChannel.Tags"/>
/// <remarks>
/// <see langword="null" /> if the value was not specified in this entry..
/// </remarks>
public IReadOnlyCollection<ForumTag> ForumTags { get; }
/// <inheritdoc cref="ITextChannel.Topic"/>
/// <remarks>
/// <see langword="null" /> if the value was not specified in this entry..
/// </remarks>
public string Topic { get; }
/// <inheritdoc cref="IForumChannel.DefaultReactionEmoji"/>
/// <remarks>
/// <see langword="null" /> if the value was not specified in this entry..
/// </remarks>
public IEmote DefaultReactionEmoji { get; }
} }

View File

@@ -1,3 +1,8 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Model = Discord.API.AuditLogs.ChannelInfoAuditLogModel;
namespace Discord.Rest namespace Discord.Rest
{ {
/// <summary> /// <summary>
@@ -5,14 +10,41 @@ namespace Discord.Rest
/// </summary> /// </summary>
public struct ChannelInfo public struct ChannelInfo
{ {
internal ChannelInfo(string name, string topic, int? rateLimit, bool? nsfw, int? bitrate, ChannelType? type) internal ChannelInfo(Model model)
{ {
Name = name; Name = model.Name;
Topic = topic; Topic = model.Topic;
SlowModeInterval = rateLimit; IsNsfw = model.IsNsfw;
IsNsfw = nsfw; Bitrate = model.Bitrate;
Bitrate = bitrate; DefaultArchiveDuration = model.DefaultArchiveDuration;
ChannelType = type; ChannelType = model.Type;
SlowModeInterval = model.RateLimitPerUser;
ForumTags = model.AvailableTags?.Select(
x => new ForumTag(x.Id,
x.Name,
x.EmojiId.GetValueOrDefault(null),
x.EmojiName.GetValueOrDefault(null),
x.Moderated)).ToImmutableArray();
if (model.DefaultEmoji is not null)
{
if (model.DefaultEmoji.EmojiId.HasValue && model.DefaultEmoji.EmojiId.Value != 0)
DefaultReactionEmoji = new Emote(model.DefaultEmoji.EmojiId.GetValueOrDefault(), null, false);
else if (model.DefaultEmoji.EmojiName.IsSpecified)
DefaultReactionEmoji = new Emoji(model.DefaultEmoji.EmojiName.Value);
else
DefaultReactionEmoji = null;
}
else
DefaultReactionEmoji = null;
AutoArchiveDuration = model.AutoArchiveDuration;
DefaultSlowModeInterval = model.DefaultThreadRateLimitPerUser;
VideoQualityMode = model.VideoQualityMode;
RtcRegion = model.Region;
Flags = model.Flags;
UserLimit = model.UserLimit;
} }
/// <summary> /// <summary>
@@ -61,5 +93,53 @@ namespace Discord.Rest
/// The channel type of this channel; <c>null</c> if not applicable. /// The channel type of this channel; <c>null</c> if not applicable.
/// </returns> /// </returns>
public ChannelType? ChannelType { get; } public ChannelType? ChannelType { get; }
/// <inheritdoc cref="ITextChannel.DefaultArchiveDuration"/>
/// <remarks>
/// <see langword="null" /> if the value was not updated in this entry.
/// </remarks>
public ThreadArchiveDuration? DefaultArchiveDuration { get; }
/// <inheritdoc cref="IForumChannel.Tags"/>
/// <remarks>
/// <see langword="null" /> if the value was not updated in this entry.
/// </remarks>
public IReadOnlyCollection<ForumTag> ForumTags { get; }
/// <inheritdoc cref="IForumChannel.DefaultReactionEmoji"/>
/// <remarks>
/// <see langword="null" /> if the value was not updated in this entry.
/// </remarks>
public IEmote DefaultReactionEmoji { get; }
/// <summary>
/// Gets the user limit configured in the created voice channel.
/// </summary>
public int? UserLimit { get; }
/// <summary>
/// Gets the video quality mode configured in the created voice channel.
/// </summary>
public VideoQualityMode? VideoQualityMode { get; }
/// <summary>
/// Gets the region configured in the created voice channel.
/// </summary>
public string RtcRegion { get; }
/// <summary>
/// Gets channel flags configured for the created channel.
/// </summary>
public ChannelFlags? Flags { get; }
/// <summary>
/// Gets the thread archive duration that was set in the created channel.
/// </summary>
public ThreadArchiveDuration? AutoArchiveDuration { get; }
/// <summary>
/// Gets the default slow mode interval that will be set in child threads in the channel.
/// </summary>
public int? DefaultSlowModeInterval { get; }
} }
} }

View File

@@ -1,3 +1,4 @@
using Discord.API.AuditLogs;
using System.Linq; using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
@@ -16,34 +17,13 @@ namespace Discord.Rest
After = after; After = after;
} }
internal static ChannelUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static ChannelUpdateAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log = null)
{ {
var changes = entry.Changes; var changes = entry.Changes;
var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); var (before, after) = AuditLogHelper.CreateAuditLogEntityInfo<ChannelInfoAuditLogModel>(changes, discord);
var topicModel = changes.FirstOrDefault(x => x.ChangedProperty == "topic");
var rateLimitPerUserModel = changes.FirstOrDefault(x => x.ChangedProperty == "rate_limit_per_user");
var nsfwModel = changes.FirstOrDefault(x => x.ChangedProperty == "nsfw");
var bitrateModel = changes.FirstOrDefault(x => x.ChangedProperty == "bitrate");
var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type");
string oldName = nameModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer), return new ChannelUpdateAuditLogData(entry.TargetId!.Value, new ChannelInfo(before), new ChannelInfo(after));
newName = nameModel?.NewValue?.ToObject<string>(discord.ApiClient.Serializer);
string oldTopic = topicModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer),
newTopic = topicModel?.NewValue?.ToObject<string>(discord.ApiClient.Serializer);
int? oldRateLimitPerUser = rateLimitPerUserModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer),
newRateLimitPerUser = rateLimitPerUserModel?.NewValue?.ToObject<int>(discord.ApiClient.Serializer);
bool? oldNsfw = nsfwModel?.OldValue?.ToObject<bool>(discord.ApiClient.Serializer),
newNsfw = nsfwModel?.NewValue?.ToObject<bool>(discord.ApiClient.Serializer);
int? oldBitrate = bitrateModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer),
newBitrate = bitrateModel?.NewValue?.ToObject<int>(discord.ApiClient.Serializer);
ChannelType? oldType = typeModel?.OldValue?.ToObject<ChannelType>(discord.ApiClient.Serializer),
newType = typeModel?.NewValue?.ToObject<ChannelType>(discord.ApiClient.Serializer);
var before = new ChannelInfo(oldName, oldTopic, oldRateLimitPerUser, oldNsfw, oldBitrate, oldType);
var after = new ChannelInfo(newName, newTopic, newRateLimitPerUser, newNsfw, newBitrate, newType);
return new ChannelUpdateAuditLogData(entry.TargetId.Value, before, after);
} }
/// <summary> /// <summary>

View File

@@ -0,0 +1,69 @@
using Discord.API;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog;
namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to an application command permission update.
/// </summary>
public class CommandPermissionUpdateAuditLogData : IAuditLogData
{
internal CommandPermissionUpdateAuditLogData(IReadOnlyCollection<ApplicationCommandPermission> before, IReadOnlyCollection<ApplicationCommandPermission> after,
IApplicationCommand command, ulong appId)
{
Before = before;
After = after;
ApplicationCommand = command;
ApplicationId = appId;
}
internal static CommandPermissionUpdateAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{
var changes = entry.Changes;
var before = new List<ApplicationCommandPermission>();
var after = new List<ApplicationCommandPermission>();
foreach (var change in changes)
{
var oldValue = change.OldValue?.ToObject<API.ApplicationCommandPermissions>();
var newValue = change.NewValue?.ToObject<API.ApplicationCommandPermissions>();
if (oldValue is not null)
before.Add(new ApplicationCommandPermission(oldValue.Id, oldValue.Type, oldValue.Permission));
if (newValue is not null)
after.Add(new ApplicationCommandPermission(newValue.Id, newValue.Type, newValue.Permission));
}
var command = log.Commands.FirstOrDefault(x => x.Id == entry.TargetId);
var appCommand = RestApplicationCommand.Create(discord, command, command?.GuildId.IsSpecified ?? false ? command.GuildId.Value : null);
return new(before.ToImmutableArray(), after.ToImmutableArray(), appCommand, entry.Options.ApplicationId!.Value);
}
/// <summary>
/// Gets the ID of the app whose permissions were targeted.
/// </summary>
public ulong ApplicationId { get; set; }
/// <summary>
/// Gets the application command which permissions were updated.
/// </summary>
public IApplicationCommand ApplicationCommand { get; }
/// <summary>
/// Gets values of the permissions before the change if available.
/// </summary>
public IReadOnlyCollection<ApplicationCommandPermission> Before { get; }
/// <summary>
/// Gets values of the permissions after the change if available.
/// </summary>
public IReadOnlyCollection<ApplicationCommandPermission> After { get; }
}

View File

@@ -1,21 +1,22 @@
using System.Linq; using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to an emoji creation.
/// </summary>
public class EmoteCreateAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to an emoji creation.
/// </summary>
public class EmoteCreateAuditLogData : IAuditLogData
{
private EmoteCreateAuditLogData(ulong id, string name) private EmoteCreateAuditLogData(ulong id, string name)
{ {
EmoteId = id; EmoteId = id;
Name = name; Name = name;
} }
internal static EmoteCreateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static EmoteCreateAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var change = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name"); var change = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name");
@@ -27,9 +28,10 @@ namespace Discord.Rest
/// Gets the snowflake ID of the created emoji. /// Gets the snowflake ID of the created emoji.
/// </summary> /// </summary>
/// <returns> /// <returns>
/// A <see cref="System.UInt64"/> representing the snowflake identifier for the created emoji. /// A <see cref="ulong"/> representing the snowflake identifier for the created emoji.
/// </returns> /// </returns>
public ulong EmoteId { get; } public ulong EmoteId { get; }
/// <summary> /// <summary>
/// Gets the name of the created emoji. /// Gets the name of the created emoji.
/// </summary> /// </summary>
@@ -37,5 +39,4 @@ namespace Discord.Rest
/// A string containing the name of the created emoji. /// A string containing the name of the created emoji.
/// </returns> /// </returns>
public string Name { get; } public string Name { get; }
}
} }

View File

@@ -2,20 +2,20 @@ using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to an emoji deletion.
/// </summary>
public class EmoteDeleteAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to an emoji deletion.
/// </summary>
public class EmoteDeleteAuditLogData : IAuditLogData
{
private EmoteDeleteAuditLogData(ulong id, string name) private EmoteDeleteAuditLogData(ulong id, string name)
{ {
EmoteId = id; EmoteId = id;
Name = name; Name = name;
} }
internal static EmoteDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static EmoteDeleteAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var change = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name"); var change = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name");
@@ -28,9 +28,10 @@ namespace Discord.Rest
/// Gets the snowflake ID of the deleted emoji. /// Gets the snowflake ID of the deleted emoji.
/// </summary> /// </summary>
/// <returns> /// <returns>
/// A <see cref="System.UInt64"/> representing the snowflake identifier for the deleted emoji. /// A <see cref="ulong"/> representing the snowflake identifier for the deleted emoji.
/// </returns> /// </returns>
public ulong EmoteId { get; } public ulong EmoteId { get; }
/// <summary> /// <summary>
/// Gets the name of the deleted emoji. /// Gets the name of the deleted emoji.
/// </summary> /// </summary>
@@ -38,5 +39,4 @@ namespace Discord.Rest
/// A string containing the name of the deleted emoji. /// A string containing the name of the deleted emoji.
/// </returns> /// </returns>
public string Name { get; } public string Name { get; }
}
} }

View File

@@ -1,14 +1,15 @@
using System.Linq; using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to an emoji update.
/// </summary>
public class EmoteUpdateAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to an emoji update.
/// </summary>
public class EmoteUpdateAuditLogData : IAuditLogData
{
private EmoteUpdateAuditLogData(ulong id, string oldName, string newName) private EmoteUpdateAuditLogData(ulong id, string oldName, string newName)
{ {
EmoteId = id; EmoteId = id;
@@ -16,7 +17,7 @@ namespace Discord.Rest
NewName = newName; NewName = newName;
} }
internal static EmoteUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static EmoteUpdateAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var change = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name"); var change = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name");
@@ -33,6 +34,7 @@ namespace Discord.Rest
/// A <see cref="ulong"/> representing the snowflake identifier of the updated emoji. /// A <see cref="ulong"/> representing the snowflake identifier of the updated emoji.
/// </returns> /// </returns>
public ulong EmoteId { get; } public ulong EmoteId { get; }
/// <summary> /// <summary>
/// Gets the new name of the updated emoji. /// Gets the new name of the updated emoji.
/// </summary> /// </summary>
@@ -40,6 +42,7 @@ namespace Discord.Rest
/// A string containing the new name of the updated emoji. /// A string containing the new name of the updated emoji.
/// </returns> /// </returns>
public string NewName { get; } public string NewName { get; }
/// <summary> /// <summary>
/// Gets the old name of the updated emoji. /// Gets the old name of the updated emoji.
/// </summary> /// </summary>
@@ -47,5 +50,4 @@ namespace Discord.Rest
/// A string containing the old name of the updated emoji. /// A string containing the old name of the updated emoji.
/// </returns> /// </returns>
public string OldName { get; } public string OldName { get; }
}
} }

View File

@@ -1,30 +1,121 @@
namespace Discord.Rest using Model = Discord.API.AuditLogs.GuildInfoAuditLogModel;
namespace Discord.Rest;
/// <summary>
/// Represents information for a guild.
/// </summary>
public struct GuildInfo
{ {
/// <summary> internal GuildInfo(Model model, IUser owner)
/// Represents information for a guild.
/// </summary>
public struct GuildInfo
{ {
internal GuildInfo(int? afkTimeout, DefaultMessageNotifications? defaultNotifs,
ulong? afkChannel, string name, string region, string icon,
VerificationLevel? verification, IUser owner, MfaLevel? mfa, ExplicitContentFilterLevel? filter,
ulong? systemChannel, ulong? widgetChannel, bool? widget)
{
AfkTimeout = afkTimeout;
DefaultMessageNotifications = defaultNotifs;
AfkChannelId = afkChannel;
Name = name;
RegionId = region;
IconHash = icon;
VerificationLevel = verification;
Owner = owner; Owner = owner;
MfaLevel = mfa;
ExplicitContentFilter = filter; Name = model.Name;
SystemChannelId = systemChannel; AfkTimeout = model.AfkTimeout.GetValueOrDefault();
EmbedChannelId = widgetChannel; IsEmbeddable = model.IsEmbeddable;
IsEmbeddable = widget; DefaultMessageNotifications = model.DefaultMessageNotifications;
MfaLevel = model.MfaLevel;
Description = model.Description;
PreferredLocale = model.PreferredLocale;
IconHash = model.IconHash;
OwnerId = model.OwnerId;
AfkChannelId = model.AfkChannelId;
ApplicationId = model.ApplicationId;
BannerId = model.Banner;
DiscoverySplashId = model.DiscoverySplash;
EmbedChannelId = model.EmbeddedChannelId;
ExplicitContentFilter = model.ExplicitContentFilterLevel;
IsBoostProgressBarEnabled = model.ProgressBarEnabled;
NsfwLevel = model.NsfwLevel;
PublicUpdatesChannelId = model.PublicUpdatesChannelId;
RegionId = model.RegionId;
RulesChannelId = model.RulesChannelId;
SplashId = model.Splash;
SystemChannelFlags = model.SystemChannelFlags;
SystemChannelId = model.SystemChannelId;
VanityURLCode = model.VanityUrl;
VerificationLevel = model.VerificationLevel;
} }
/// <inheritdoc cref="IGuild.DiscoverySplashId"/>
/// <remarks>
/// <see langword="null" /> if the value was not updated in this entry.
/// </remarks>
public string DiscoverySplashId { get; }
/// <inheritdoc cref="IGuild.SplashId"/>
/// <remarks>
/// <see langword="null" /> if the value was not updated in this entry.
/// </remarks>
public string SplashId { get; }
/// <inheritdoc cref="IGuild.RulesChannelId"/>
/// <remarks>
/// <see langword="null" /> if the value was not updated in this entry.
/// </remarks>
public ulong? RulesChannelId { get; }
/// <inheritdoc cref="IGuild.PublicUpdatesChannelId"/>
/// <remarks>
/// <see langword="null" /> if the value was not updated in this entry.
/// </remarks>
public ulong? PublicUpdatesChannelId { get; }
/// <inheritdoc cref="IGuild.OwnerId"/>
/// <remarks>
/// <see langword="null" /> if the value was not updated in this entry.
/// </remarks>
public ulong? OwnerId { get; }
/// <inheritdoc cref="IGuild.ApplicationId"/>
/// <remarks>
/// <see langword="null" /> if the value was not updated in this entry.
/// </remarks>
public ulong? ApplicationId { get; }
/// <inheritdoc cref="IGuild.BannerId"/>
/// <remarks>
/// <see langword="null" /> if the value was not updated in this entry.
/// </remarks>
public string BannerId { get; }
/// <inheritdoc cref="IGuild.VanityURLCode"/>
/// <remarks>
/// <see langword="null" /> if the value was not updated in this entry.
/// </remarks>
public string VanityURLCode { get; }
/// <inheritdoc cref="IGuild.SystemChannelFlags"/>
/// <remarks>
/// <see langword="null" /> if the value was not updated in this entry.
/// </remarks>
public SystemChannelMessageDeny? SystemChannelFlags { get; }
/// <inheritdoc cref="IGuild.Description"/>
/// <remarks>
/// <see langword="null" /> if the value was not updated in this entry.
/// </remarks>
public string Description { get; }
/// <inheritdoc cref="IGuild.PreferredLocale"/>
/// <remarks>
/// <see langword="null" /> if the value was not updated in this entry.
/// </remarks>
public string PreferredLocale { get; }
/// <inheritdoc cref="IGuild.NsfwLevel"/>
/// <remarks>
/// <see langword="null" /> if the value was not updated in this entry.
/// </remarks>
public NsfwLevel? NsfwLevel { get; }
/// <inheritdoc cref="IGuild.IsBoostProgressBarEnabled"/>
/// <remarks>
/// <see langword="null" /> if the value was not updated in this entry.
/// </remarks>
public bool? IsBoostProgressBarEnabled { get; }
/// <summary> /// <summary>
/// Gets the amount of time (in seconds) a user must be inactive in a voice channel for until they are /// Gets the amount of time (in seconds) a user must be inactive in a voice channel for until they are
/// automatically moved to the AFK voice channel. /// automatically moved to the AFK voice channel.
@@ -124,5 +215,4 @@ namespace Discord.Rest
/// <c>null</c> if this is not mentioned in this entry. /// <c>null</c> if this is not mentioned in this entry.
/// </returns> /// </returns>
public bool? IsEmbeddable { get; } public bool? IsEmbeddable { get; }
}
} }

View File

@@ -1,3 +1,4 @@
using Discord.API.AuditLogs;
using System.Linq; using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
@@ -15,50 +16,14 @@ namespace Discord.Rest
After = after; After = after;
} }
internal static GuildUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static GuildUpdateAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log = null)
{ {
var changes = entry.Changes; var changes = entry.Changes;
var afkTimeoutModel = changes.FirstOrDefault(x => x.ChangedProperty == "afk_timeout");
var defaultMessageNotificationsModel = changes.FirstOrDefault(x => x.ChangedProperty == "default_message_notifications");
var afkChannelModel = changes.FirstOrDefault(x => x.ChangedProperty == "afk_channel_id");
var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name");
var regionIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "region");
var iconHashModel = changes.FirstOrDefault(x => x.ChangedProperty == "icon_hash");
var verificationLevelModel = changes.FirstOrDefault(x => x.ChangedProperty == "verification_level");
var ownerIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "owner_id"); var ownerIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "owner_id");
var mfaLevelModel = changes.FirstOrDefault(x => x.ChangedProperty == "mfa_level");
var contentFilterModel = changes.FirstOrDefault(x => x.ChangedProperty == "explicit_content_filter");
var systemChannelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "system_channel_id");
var widgetChannelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "widget_channel_id");
var widgetEnabledModel = changes.FirstOrDefault(x => x.ChangedProperty == "widget_enabled");
int? oldAfkTimeout = afkTimeoutModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer),
newAfkTimeout = afkTimeoutModel?.NewValue?.ToObject<int>(discord.ApiClient.Serializer);
DefaultMessageNotifications? oldDefaultMessageNotifications = defaultMessageNotificationsModel?.OldValue?.ToObject<DefaultMessageNotifications>(discord.ApiClient.Serializer),
newDefaultMessageNotifications = defaultMessageNotificationsModel?.NewValue?.ToObject<DefaultMessageNotifications>(discord.ApiClient.Serializer);
ulong? oldAfkChannelId = afkChannelModel?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer),
newAfkChannelId = afkChannelModel?.NewValue?.ToObject<ulong>(discord.ApiClient.Serializer);
string oldName = nameModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer),
newName = nameModel?.NewValue?.ToObject<string>(discord.ApiClient.Serializer);
string oldRegionId = regionIdModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer),
newRegionId = regionIdModel?.NewValue?.ToObject<string>(discord.ApiClient.Serializer);
string oldIconHash = iconHashModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer),
newIconHash = iconHashModel?.NewValue?.ToObject<string>(discord.ApiClient.Serializer);
VerificationLevel? oldVerificationLevel = verificationLevelModel?.OldValue?.ToObject<VerificationLevel>(discord.ApiClient.Serializer),
newVerificationLevel = verificationLevelModel?.NewValue?.ToObject<VerificationLevel>(discord.ApiClient.Serializer);
ulong? oldOwnerId = ownerIdModel?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer), ulong? oldOwnerId = ownerIdModel?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer),
newOwnerId = ownerIdModel?.NewValue?.ToObject<ulong>(discord.ApiClient.Serializer); newOwnerId = ownerIdModel?.NewValue?.ToObject<ulong>(discord.ApiClient.Serializer);
MfaLevel? oldMfaLevel = mfaLevelModel?.OldValue?.ToObject<MfaLevel>(discord.ApiClient.Serializer),
newMfaLevel = mfaLevelModel?.NewValue?.ToObject<MfaLevel>(discord.ApiClient.Serializer);
ExplicitContentFilterLevel? oldContentFilter = contentFilterModel?.OldValue?.ToObject<ExplicitContentFilterLevel>(discord.ApiClient.Serializer),
newContentFilter = contentFilterModel?.NewValue?.ToObject<ExplicitContentFilterLevel>(discord.ApiClient.Serializer);
ulong? oldSystemChannelId = systemChannelIdModel?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer),
newSystemChannelId = systemChannelIdModel?.NewValue?.ToObject<ulong>(discord.ApiClient.Serializer);
ulong? oldWidgetChannelId = widgetChannelIdModel?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer),
newWidgetChannelId = widgetChannelIdModel?.NewValue?.ToObject<ulong>(discord.ApiClient.Serializer);
bool? oldWidgetEnabled = widgetEnabledModel?.OldValue?.ToObject<bool>(discord.ApiClient.Serializer),
newWidgetEnabled = widgetEnabledModel?.NewValue?.ToObject<bool>(discord.ApiClient.Serializer);
IUser oldOwner = null; IUser oldOwner = null;
if (oldOwnerId != null) if (oldOwnerId != null)
@@ -74,14 +39,9 @@ namespace Discord.Rest
newOwner = RestUser.Create(discord, newOwnerInfo); newOwner = RestUser.Create(discord, newOwnerInfo);
} }
var before = new GuildInfo(oldAfkTimeout, oldDefaultMessageNotifications, var (before, after) = AuditLogHelper.CreateAuditLogEntityInfo<GuildInfoAuditLogModel>(changes, discord);
oldAfkChannelId, oldName, oldRegionId, oldIconHash, oldVerificationLevel, oldOwner,
oldMfaLevel, oldContentFilter, oldSystemChannelId, oldWidgetChannelId, oldWidgetEnabled);
var after = new GuildInfo(newAfkTimeout, newDefaultMessageNotifications,
newAfkChannelId, newName, newRegionId, newIconHash, newVerificationLevel, newOwner,
newMfaLevel, newContentFilter, newSystemChannelId, newWidgetChannelId, newWidgetEnabled);
return new GuildUpdateAuditLogData(before, after); return new GuildUpdateAuditLogData(new(before, oldOwner), new(after, newOwner));
} }
/// <summary> /// <summary>

View File

@@ -0,0 +1,39 @@
using Discord.API.AuditLogs;
using System.Linq;
using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog;
namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to an integration authorization.
/// </summary>
public class IntegrationCreatedAuditLogData : IAuditLogData
{
internal IntegrationCreatedAuditLogData(IntegrationInfo info, IIntegration integration)
{
Integration = integration;
Data = info;
}
internal static IntegrationCreatedAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{
var changes = entry.Changes;
var (_, data) = AuditLogHelper.CreateAuditLogEntityInfo<IntegrationInfoAuditLogModel>(changes, discord);
var integration = RestIntegration.Create(discord, null, log.Integrations.FirstOrDefault(x => x.Id == entry.TargetId));
return new(new IntegrationInfo(data), integration);
}
/// <summary>
/// Gets the partial integration the changes correspond to.
/// </summary>
public IIntegration Integration { get; }
/// <summary>
/// Gets the integration information after the changes.
/// </summary>
public IntegrationInfo Data { get; }
}

View File

@@ -0,0 +1,31 @@
using Discord.API.AuditLogs;
using System.Linq;
using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog;
namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to an integration removal.
/// </summary>
public class IntegrationDeletedAuditLogData : IAuditLogData
{
internal IntegrationDeletedAuditLogData(IntegrationInfo info)
{
Data = info;
}
internal static IntegrationDeletedAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{
var changes = entry.Changes;
var (data, _) = AuditLogHelper.CreateAuditLogEntityInfo<IntegrationInfoAuditLogModel>(changes, discord);
return new(new IntegrationInfo(data));
}
/// <summary>
/// Gets the integration information before the changes.
/// </summary>
public IntegrationInfo Data { get; }
}

View File

@@ -0,0 +1,69 @@
using Discord.API.AuditLogs;
using System.Collections.Generic;
using System.Collections.Immutable;
namespace Discord.Rest;
/// <summary>
/// Represents information for an integration.
/// </summary>
public class IntegrationInfo
{
internal IntegrationInfo(IntegrationInfoAuditLogModel model)
{
Name = model.Name;
Type = model.Type;
EnableEmojis = model.EnableEmojis;
Enabled = model.Enabled;
Scopes = model.Scopes?.ToImmutableArray();
ExpireBehavior = model.ExpireBehavior;
ExpireGracePeriod = model.ExpireGracePeriod;
Syncing = model.Syncing;
RoleId = model.RoleId;
}
/// <summary>
/// Gets the name of the integration. <see landword="null"/> if the property was not mentioned in this audit log.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets the type of the integration. <see landword="null"/> if the property was not mentioned in this audit log.
/// </summary>
public string Type { get; set; }
/// <summary>
/// Gets if the integration is enabled. <see landword="null"/> if the property was not mentioned in this audit log.
/// </summary>
public bool? Enabled { get; set; }
/// <summary>
/// Gets if syncing is enabled for this integration. <see landword="null"/> if the property was not mentioned in this audit log.
/// </summary>
public bool? Syncing { get; set; }
/// <summary>
/// Gets the id of the role that this integration uses for subscribers. <see landword="null"/> if the property was not mentioned in this audit log.
/// </summary>
public ulong? RoleId { get; set; }
/// <summary>
/// Gets whether emoticons should be synced for this integration. <see landword="null"/> if the property was not mentioned in this audit log.
/// </summary>
public bool? EnableEmojis { get; set; }
/// <summary>
/// Gets the behavior of expiring subscribers. <see landword="null"/> if the property was not mentioned in this audit log.
/// </summary>
public IntegrationExpireBehavior? ExpireBehavior { get; set; }
/// <summary>
/// Gets the grace period (in days) before expiring subscribers. <see landword="null"/> if the property was not mentioned in this audit log.
/// </summary>
public int? ExpireGracePeriod { get; set; }
/// <summary>
/// Gets the scopes the application has been authorized for. <see landword="null"/> if the property was not mentioned in this audit log.
/// </summary>
public IReadOnlyCollection<string> Scopes { get; set; }
}

View File

@@ -0,0 +1,45 @@
using Discord.API.AuditLogs;
using System.Linq;
using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog;
namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to an integration update.
/// </summary>
public class IntegrationUpdatedAuditLogData : IAuditLogData
{
internal IntegrationUpdatedAuditLogData(IntegrationInfo before, IntegrationInfo after, IIntegration integration)
{
Before = before;
After = after;
Integration = integration;
}
internal static IntegrationUpdatedAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{
var changes = entry.Changes;
var (before, after) = AuditLogHelper.CreateAuditLogEntityInfo<IntegrationInfoAuditLogModel>(changes, discord);
var integration = RestIntegration.Create(discord, null, log.Integrations.FirstOrDefault(x => x.Id == entry.TargetId));
return new(new IntegrationInfo(before), new IntegrationInfo(after), integration);
}
/// <summary>
/// Gets the partial integration the changes correspond to.
/// </summary>
public IIntegration Integration { get; }
/// <summary>
/// Gets the integration information before the changes.
/// </summary>
public IntegrationInfo Before { get; }
/// <summary>
/// Gets the integration information after the changes.
/// </summary>
public IntegrationInfo After { get; }
}

View File

@@ -1,53 +1,42 @@
using Discord.API.AuditLogs;
using System.Linq; using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to an invite creation.
/// </summary>
public class InviteCreateAuditLogData : IAuditLogData
{ {
/// <summary> private InviteCreateAuditLogData(InviteInfoAuditLogModel model, IUser inviter)
/// Contains a piece of audit log data related to an invite creation.
/// </summary>
public class InviteCreateAuditLogData : IAuditLogData
{ {
private InviteCreateAuditLogData(int maxAge, string code, bool temporary, IUser inviter, ulong channelId, int uses, int maxUses) MaxAge = model.MaxAge!.Value;
{ Code = model.Code;
MaxAge = maxAge; Temporary = model.Temporary!.Value;
Code = code;
Temporary = temporary;
Creator = inviter; Creator = inviter;
ChannelId = channelId; ChannelId = model.ChannelId!.Value;
Uses = uses; Uses = model.Uses!.Value;
MaxUses = maxUses; MaxUses = model.MaxUses!.Value;
} }
internal static InviteCreateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static InviteCreateAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var changes = entry.Changes; var changes = entry.Changes;
var maxAgeModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_age"); var (_, data) = AuditLogHelper.CreateAuditLogEntityInfo<InviteInfoAuditLogModel>(changes, discord);
var codeModel = changes.FirstOrDefault(x => x.ChangedProperty == "code");
var temporaryModel = changes.FirstOrDefault(x => x.ChangedProperty == "temporary");
var inviterIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "inviter_id");
var channelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "channel_id");
var usesModel = changes.FirstOrDefault(x => x.ChangedProperty == "uses");
var maxUsesModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_uses");
var maxAge = maxAgeModel.NewValue.ToObject<int>(discord.ApiClient.Serializer);
var code = codeModel.NewValue.ToObject<string>(discord.ApiClient.Serializer);
var temporary = temporaryModel.NewValue.ToObject<bool>(discord.ApiClient.Serializer);
var channelId = channelIdModel.NewValue.ToObject<ulong>(discord.ApiClient.Serializer);
var uses = usesModel.NewValue.ToObject<int>(discord.ApiClient.Serializer);
var maxUses = maxUsesModel.NewValue.ToObject<int>(discord.ApiClient.Serializer);
RestUser inviter = null; RestUser inviter = null;
if (inviterIdModel != null)
if (data.InviterId is not null)
{ {
var inviterId = inviterIdModel.NewValue.ToObject<ulong>(discord.ApiClient.Serializer); var inviterInfo = log.Users.FirstOrDefault(x => x.Id == data.InviterId);
var inviterInfo = log.Users.FirstOrDefault(x => x.Id == inviterId);
inviter = (inviterInfo != null) ? RestUser.Create(discord, inviterInfo) : null; inviter = (inviterInfo != null) ? RestUser.Create(discord, inviterInfo) : null;
} }
return new InviteCreateAuditLogData(maxAge, code, temporary, inviter, channelId, uses, maxUses); return new InviteCreateAuditLogData(data, inviter);
} }
/// <summary> /// <summary>
@@ -57,6 +46,7 @@ namespace Discord.Rest
/// An <see cref="int"/> representing the time in seconds until this invite expires. /// An <see cref="int"/> representing the time in seconds until this invite expires.
/// </returns> /// </returns>
public int MaxAge { get; } public int MaxAge { get; }
/// <summary> /// <summary>
/// Gets the unique identifier for this invite. /// Gets the unique identifier for this invite.
/// </summary> /// </summary>
@@ -64,6 +54,7 @@ namespace Discord.Rest
/// A string containing the invite code (e.g. <c>FTqNnyS</c>). /// A string containing the invite code (e.g. <c>FTqNnyS</c>).
/// </returns> /// </returns>
public string Code { get; } public string Code { get; }
/// <summary> /// <summary>
/// Gets a value that determines whether the invite is a temporary one. /// Gets a value that determines whether the invite is a temporary one.
/// </summary> /// </summary>
@@ -72,6 +63,7 @@ namespace Discord.Rest
/// <c>false</c>. /// <c>false</c>.
/// </returns> /// </returns>
public bool Temporary { get; } public bool Temporary { get; }
/// <summary> /// <summary>
/// Gets the user that created this invite if available. /// Gets the user that created this invite if available.
/// </summary> /// </summary>
@@ -82,6 +74,7 @@ namespace Discord.Rest
/// A user that created this invite or <see langword="null"/>. /// A user that created this invite or <see langword="null"/>.
/// </returns> /// </returns>
public IUser Creator { get; } public IUser Creator { get; }
/// <summary> /// <summary>
/// Gets the ID of the channel this invite is linked to. /// Gets the ID of the channel this invite is linked to.
/// </summary> /// </summary>
@@ -89,6 +82,7 @@ namespace Discord.Rest
/// A <see cref="ulong"/> representing the channel snowflake identifier that the invite points to. /// A <see cref="ulong"/> representing the channel snowflake identifier that the invite points to.
/// </returns> /// </returns>
public ulong ChannelId { get; } public ulong ChannelId { get; }
/// <summary> /// <summary>
/// Gets the number of times this invite has been used. /// Gets the number of times this invite has been used.
/// </summary> /// </summary>
@@ -96,6 +90,7 @@ namespace Discord.Rest
/// An <see cref="int"/> representing the number of times this invite was used. /// An <see cref="int"/> representing the number of times this invite was used.
/// </returns> /// </returns>
public int Uses { get; } public int Uses { get; }
/// <summary> /// <summary>
/// Gets the max number of uses this invite may have. /// Gets the max number of uses this invite may have.
/// </summary> /// </summary>
@@ -104,5 +99,4 @@ namespace Discord.Rest
/// from the guild; <c>null</c> if none is set. /// from the guild; <c>null</c> if none is set.
/// </returns> /// </returns>
public int MaxUses { get; } public int MaxUses { get; }
}
} }

View File

@@ -1,53 +1,42 @@
using Discord.API.AuditLogs;
using System.Linq; using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to an invite removal.
/// </summary>
public class InviteDeleteAuditLogData : IAuditLogData
{ {
/// <summary> private InviteDeleteAuditLogData(InviteInfoAuditLogModel model, IUser inviter)
/// Contains a piece of audit log data related to an invite removal.
/// </summary>
public class InviteDeleteAuditLogData : IAuditLogData
{ {
private InviteDeleteAuditLogData(int maxAge, string code, bool temporary, IUser inviter, ulong channelId, int uses, int maxUses) MaxAge = model.MaxAge!.Value;
{ Code = model.Code;
MaxAge = maxAge; Temporary = model.Temporary!.Value;
Code = code;
Temporary = temporary;
Creator = inviter; Creator = inviter;
ChannelId = channelId; ChannelId = model.ChannelId!.Value;
Uses = uses; Uses = model.Uses!.Value;
MaxUses = maxUses; MaxUses = model.MaxUses!.Value;
} }
internal static InviteDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static InviteDeleteAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var changes = entry.Changes; var changes = entry.Changes;
var maxAgeModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_age"); var (data, _) = AuditLogHelper.CreateAuditLogEntityInfo<InviteInfoAuditLogModel>(changes, discord);
var codeModel = changes.FirstOrDefault(x => x.ChangedProperty == "code");
var temporaryModel = changes.FirstOrDefault(x => x.ChangedProperty == "temporary");
var inviterIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "inviter_id");
var channelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "channel_id");
var usesModel = changes.FirstOrDefault(x => x.ChangedProperty == "uses");
var maxUsesModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_uses");
var maxAge = maxAgeModel.OldValue.ToObject<int>(discord.ApiClient.Serializer);
var code = codeModel.OldValue.ToObject<string>(discord.ApiClient.Serializer);
var temporary = temporaryModel.OldValue.ToObject<bool>(discord.ApiClient.Serializer);
var channelId = channelIdModel.OldValue.ToObject<ulong>(discord.ApiClient.Serializer);
var uses = usesModel.OldValue.ToObject<int>(discord.ApiClient.Serializer);
var maxUses = maxUsesModel.OldValue.ToObject<int>(discord.ApiClient.Serializer);
RestUser inviter = null; RestUser inviter = null;
if (inviterIdModel != null)
if (data.InviterId != null)
{ {
var inviterId = inviterIdModel.OldValue.ToObject<ulong>(discord.ApiClient.Serializer); var inviterInfo = log.Users.FirstOrDefault(x => x.Id == data.InviterId);
var inviterInfo = log.Users.FirstOrDefault(x => x.Id == inviterId);
inviter = (inviterInfo != null) ? RestUser.Create(discord, inviterInfo) : null; inviter = (inviterInfo != null) ? RestUser.Create(discord, inviterInfo) : null;
} }
return new InviteDeleteAuditLogData(maxAge, code, temporary, inviter, channelId, uses, maxUses); return new InviteDeleteAuditLogData(data, inviter);
} }
/// <summary> /// <summary>
@@ -57,6 +46,7 @@ namespace Discord.Rest
/// An <see cref="int"/> representing the time in seconds until this invite expires. /// An <see cref="int"/> representing the time in seconds until this invite expires.
/// </returns> /// </returns>
public int MaxAge { get; } public int MaxAge { get; }
/// <summary> /// <summary>
/// Gets the unique identifier for this invite. /// Gets the unique identifier for this invite.
/// </summary> /// </summary>
@@ -64,6 +54,7 @@ namespace Discord.Rest
/// A string containing the invite code (e.g. <c>FTqNnyS</c>). /// A string containing the invite code (e.g. <c>FTqNnyS</c>).
/// </returns> /// </returns>
public string Code { get; } public string Code { get; }
/// <summary> /// <summary>
/// Gets a value that indicates whether the invite is a temporary one. /// Gets a value that indicates whether the invite is a temporary one.
/// </summary> /// </summary>
@@ -72,6 +63,7 @@ namespace Discord.Rest
/// <c>false</c>. /// <c>false</c>.
/// </returns> /// </returns>
public bool Temporary { get; } public bool Temporary { get; }
/// <summary> /// <summary>
/// Gets the user that created this invite if available. /// Gets the user that created this invite if available.
/// </summary> /// </summary>
@@ -82,6 +74,7 @@ namespace Discord.Rest
/// A user that created this invite or <see langword="null"/>. /// A user that created this invite or <see langword="null"/>.
/// </returns> /// </returns>
public IUser Creator { get; } public IUser Creator { get; }
/// <summary> /// <summary>
/// Gets the ID of the channel this invite is linked to. /// Gets the ID of the channel this invite is linked to.
/// </summary> /// </summary>
@@ -89,6 +82,7 @@ namespace Discord.Rest
/// A <see cref="ulong"/> representing the channel snowflake identifier that the invite points to. /// A <see cref="ulong"/> representing the channel snowflake identifier that the invite points to.
/// </returns> /// </returns>
public ulong ChannelId { get; } public ulong ChannelId { get; }
/// <summary> /// <summary>
/// Gets the number of times this invite has been used. /// Gets the number of times this invite has been used.
/// </summary> /// </summary>
@@ -96,6 +90,7 @@ namespace Discord.Rest
/// An <see cref="int"/> representing the number of times this invite has been used. /// An <see cref="int"/> representing the number of times this invite has been used.
/// </returns> /// </returns>
public int Uses { get; } public int Uses { get; }
/// <summary> /// <summary>
/// Gets the max number of uses this invite may have. /// Gets the max number of uses this invite may have.
/// </summary> /// </summary>
@@ -104,5 +99,4 @@ namespace Discord.Rest
/// from the guild; <c>null</c> if none is set. /// from the guild; <c>null</c> if none is set.
/// </returns> /// </returns>
public int MaxUses { get; } public int MaxUses { get; }
}
} }

View File

@@ -1,17 +1,20 @@
namespace Discord.Rest using Model = Discord.API.AuditLogs.InviteInfoAuditLogModel;
namespace Discord.Rest;
/// <summary>
/// Represents information for an invite.
/// </summary>
public struct InviteInfo
{ {
/// <summary> internal InviteInfo(Model model)
/// Represents information for an invite.
/// </summary>
public struct InviteInfo
{ {
internal InviteInfo(int? maxAge, string code, bool? temporary, ulong? channelId, int? maxUses) MaxAge = model.MaxAge;
{ Code = model.Code;
MaxAge = maxAge; Temporary = model.Temporary;
Code = code; ChannelId = model.ChannelId;
Temporary = temporary; MaxUses = model.MaxUses;
ChannelId = channelId; CreatorId = model.InviterId;
MaxUses = maxUses;
} }
/// <summary> /// <summary>
@@ -22,6 +25,7 @@ namespace Discord.Rest
/// invite never expires or not specified. /// invite never expires or not specified.
/// </returns> /// </returns>
public int? MaxAge { get; } public int? MaxAge { get; }
/// <summary> /// <summary>
/// Gets the unique identifier for this invite. /// Gets the unique identifier for this invite.
/// </summary> /// </summary>
@@ -29,6 +33,7 @@ namespace Discord.Rest
/// A string containing the invite code (e.g. <c>FTqNnyS</c>). /// A string containing the invite code (e.g. <c>FTqNnyS</c>).
/// </returns> /// </returns>
public string Code { get; } public string Code { get; }
/// <summary> /// <summary>
/// Gets a value that indicates whether the invite is a temporary one. /// Gets a value that indicates whether the invite is a temporary one.
/// </summary> /// </summary>
@@ -37,6 +42,7 @@ namespace Discord.Rest
/// <c>false</c> if not; <c>null</c> if not specified. /// <c>false</c> if not; <c>null</c> if not specified.
/// </returns> /// </returns>
public bool? Temporary { get; } public bool? Temporary { get; }
/// <summary> /// <summary>
/// Gets the ID of the channel this invite is linked to. /// Gets the ID of the channel this invite is linked to.
/// </summary> /// </summary>
@@ -45,6 +51,7 @@ namespace Discord.Rest
/// <c>null</c> if not specified. /// <c>null</c> if not specified.
/// </returns> /// </returns>
public ulong? ChannelId { get; } public ulong? ChannelId { get; }
/// <summary> /// <summary>
/// Gets the max number of uses this invite may have. /// Gets the max number of uses this invite may have.
/// </summary> /// </summary>
@@ -53,5 +60,9 @@ namespace Discord.Rest
/// from the guild; <c>null</c> if none is specified. /// from the guild; <c>null</c> if none is specified.
/// </returns> /// </returns>
public int? MaxUses { get; } public int? MaxUses { get; }
}
/// <summary>
/// Gets the id of the user created this invite.
/// </summary>
public ulong? CreatorId { get; }
} }

View File

@@ -1,45 +1,29 @@
using Discord.API.AuditLogs;
using System.Linq; using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data relating to an invite update.
/// </summary>
public class InviteUpdateAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data relating to an invite update.
/// </summary>
public class InviteUpdateAuditLogData : IAuditLogData
{
private InviteUpdateAuditLogData(InviteInfo before, InviteInfo after) private InviteUpdateAuditLogData(InviteInfo before, InviteInfo after)
{ {
Before = before; Before = before;
After = after; After = after;
} }
internal static InviteUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static InviteUpdateAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var changes = entry.Changes; var changes = entry.Changes;
var maxAgeModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_age"); var (before, after) = AuditLogHelper.CreateAuditLogEntityInfo<InviteInfoAuditLogModel>(changes, discord);
var codeModel = changes.FirstOrDefault(x => x.ChangedProperty == "code");
var temporaryModel = changes.FirstOrDefault(x => x.ChangedProperty == "temporary");
var channelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "channel_id");
var maxUsesModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_uses");
int? oldMaxAge = maxAgeModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer), return new InviteUpdateAuditLogData(new(before), new(after));
newMaxAge = maxAgeModel?.NewValue?.ToObject<int>(discord.ApiClient.Serializer);
string oldCode = codeModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer),
newCode = codeModel?.NewValue?.ToObject<string>(discord.ApiClient.Serializer);
bool? oldTemporary = temporaryModel?.OldValue?.ToObject<bool>(discord.ApiClient.Serializer),
newTemporary = temporaryModel?.NewValue?.ToObject<bool>(discord.ApiClient.Serializer);
ulong? oldChannelId = channelIdModel?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer),
newChannelId = channelIdModel?.NewValue?.ToObject<ulong>(discord.ApiClient.Serializer);
int? oldMaxUses = maxUsesModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer),
newMaxUses = maxUsesModel?.NewValue?.ToObject<int>(discord.ApiClient.Serializer);
var before = new InviteInfo(oldMaxAge, oldCode, oldTemporary, oldChannelId, oldMaxUses);
var after = new InviteInfo(newMaxAge, newCode, newTemporary, newChannelId, newMaxUses);
return new InviteUpdateAuditLogData(before, after);
} }
/// <summary> /// <summary>
@@ -49,6 +33,7 @@ namespace Discord.Rest
/// An information object containing the original invite information before the changes were made. /// An information object containing the original invite information before the changes were made.
/// </returns> /// </returns>
public InviteInfo Before { get; } public InviteInfo Before { get; }
/// <summary> /// <summary>
/// Gets the invite information after the changes. /// Gets the invite information after the changes.
/// </summary> /// </summary>
@@ -56,5 +41,4 @@ namespace Discord.Rest
/// An information object containing the invite information after the changes were made. /// An information object containing the invite information after the changes were made.
/// </returns> /// </returns>
public InviteInfo After { get; } public InviteInfo After { get; }
}
} }

View File

@@ -2,19 +2,19 @@ using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a kick.
/// </summary>
public class KickAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to a kick.
/// </summary>
public class KickAuditLogData : IAuditLogData
{
private KickAuditLogData(RestUser user) private KickAuditLogData(RestUser user)
{ {
Target = user; Target = user;
} }
internal static KickAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static KickAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log = null)
{ {
var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId); var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId);
return new KickAuditLogData((userInfo != null) ? RestUser.Create(discord, userInfo) : null); return new KickAuditLogData((userInfo != null) ? RestUser.Create(discord, userInfo) : null);
@@ -30,5 +30,4 @@ namespace Discord.Rest
/// A user object representing the kicked user. /// A user object representing the kicked user.
/// </returns> /// </returns>
public IUser Target { get; } public IUser Target { get; }
}
} }

View File

@@ -1,19 +1,19 @@
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to disconnecting members from voice channels.
/// </summary>
public class MemberDisconnectAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to disconnecting members from voice channels.
/// </summary>
public class MemberDisconnectAuditLogData : IAuditLogData
{
private MemberDisconnectAuditLogData(int count) private MemberDisconnectAuditLogData(int count)
{ {
MemberCount = count; MemberCount = count;
} }
internal static MemberDisconnectAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static MemberDisconnectAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
return new MemberDisconnectAuditLogData(entry.Options.Count.Value); return new MemberDisconnectAuditLogData(entry.Options.Count.Value);
} }
@@ -25,5 +25,4 @@ namespace Discord.Rest
/// An <see cref="int"/> representing the number of members that were disconnected from a voice channel. /// An <see cref="int"/> representing the number of members that were disconnected from a voice channel.
/// </returns> /// </returns>
public int MemberCount { get; } public int MemberCount { get; }
}
} }

View File

@@ -1,41 +1,57 @@
namespace Discord.Rest using Discord.API.AuditLogs;
using System;
namespace Discord.Rest;
/// <summary>
/// Represents information for a member.
/// </summary>
public struct MemberInfo
{ {
/// <summary> internal MemberInfo(MemberInfoAuditLogModel model)
/// Represents information for a member.
/// </summary>
public struct MemberInfo
{ {
internal MemberInfo(string nick, bool? deaf, bool? mute) Nickname = model.Nickname;
{ Deaf = model.IsDeafened;
Nickname = nick; Mute = model.IsMuted;
Deaf = deaf; TimedOutUntil = model.TimeOutUntil;
Mute = mute;
} }
/// <summary> /// <summary>
/// Gets the nickname of the updated member. /// Gets the nickname of the updated member.
/// </summary> /// </summary>
/// <returns> /// <returns>
/// A string representing the nickname of the updated member; <c>null</c> if none is set. /// A string representing the nickname of the updated member; <see langword="null"/> if none is set.
/// </returns> /// </returns>
public string Nickname { get; } public string Nickname { get; }
/// <summary> /// <summary>
/// Gets a value that indicates whether the updated member is deafened by the guild. /// Gets a value that indicates whether the updated member is deafened by the guild.
/// </summary> /// </summary>
/// <returns> /// <returns>
/// <c>true</c> if the updated member is deafened (i.e. not permitted to listen to or speak to others) by the guild; /// <see langword="true"/> if the updated member is deafened (i.e. not permitted to listen to or speak to others) by the guild;
/// otherwise <c>false</c>. /// otherwise <see langword="false"/>.
/// <c>null</c> if this is not mentioned in this entry. /// <see langword="null"/> if this is not mentioned in this entry.
/// </returns> /// </returns>
public bool? Deaf { get; } public bool? Deaf { get; }
/// <summary> /// <summary>
/// Gets a value that indicates whether the updated member is muted (i.e. not permitted to speak via voice) by the /// Gets a value that indicates whether the updated member is muted (i.e. not permitted to speak via voice) by the
/// guild. /// guild.
/// </summary> /// </summary>
/// <returns> /// <returns>
/// <c>true</c> if the updated member is muted by the guild; otherwise <c>false</c>. /// <see langword="true"/> if the updated member is muted by the guild; otherwise <see langword="false"/>.
/// <c>null</c> if this is not mentioned in this entry. /// <see langword="null"/> if this is not mentioned in this entry.
/// </returns> /// </returns>
public bool? Mute { get; } public bool? Mute { get; }
}
/// <summary>
/// Gets the date and time that indicates if and for how long the updated user has been timed out.
/// </summary>
/// <remarks>
/// <see langword="null"/> or a timestamp in the past if the user is not timed out.
/// </remarks>
/// <returns>
/// A <see cref="DateTimeOffset"/> indicating how long the user will be timed out for.
/// </returns>
public DateTimeOffset? TimedOutUntil { get; }
} }

View File

@@ -1,20 +1,20 @@
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to moving members between voice channels.
/// </summary>
public class MemberMoveAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to moving members between voice channels.
/// </summary>
public class MemberMoveAuditLogData : IAuditLogData
{
private MemberMoveAuditLogData(ulong channelId, int count) private MemberMoveAuditLogData(ulong channelId, int count)
{ {
ChannelId = channelId; ChannelId = channelId;
MemberCount = count; MemberCount = count;
} }
internal static MemberMoveAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static MemberMoveAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log = null)
{ {
return new MemberMoveAuditLogData(entry.Options.ChannelId.Value, entry.Options.Count.Value); return new MemberMoveAuditLogData(entry.Options.ChannelId.Value, entry.Options.Count.Value);
} }
@@ -33,5 +33,4 @@ namespace Discord.Rest
/// An <see cref="int"/> representing the number of members that were moved to another voice channel. /// An <see cref="int"/> representing the number of members that were moved to another voice channel.
/// </returns> /// </returns>
public int MemberCount { get; } public int MemberCount { get; }
}
} }

View File

@@ -3,20 +3,20 @@ using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a change in a guild member's roles.
/// </summary>
public class MemberRoleAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to a change in a guild member's roles.
/// </summary>
public class MemberRoleAuditLogData : IAuditLogData
{
private MemberRoleAuditLogData(IReadOnlyCollection<MemberRoleEditInfo> roles, IUser target) private MemberRoleAuditLogData(IReadOnlyCollection<MemberRoleEditInfo> roles, IUser target)
{ {
Roles = roles; Roles = roles;
Target = target; Target = target;
} }
internal static MemberRoleAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static MemberRoleAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log = null)
{ {
var changes = entry.Changes; var changes = entry.Changes;
@@ -39,6 +39,7 @@ namespace Discord.Rest
/// the member. /// the member.
/// </returns> /// </returns>
public IReadOnlyCollection<MemberRoleEditInfo> Roles { get; } public IReadOnlyCollection<MemberRoleEditInfo> Roles { get; }
/// <summary> /// <summary>
/// Gets the user that the roles changes were performed on. /// Gets the user that the roles changes were performed on.
/// </summary> /// </summary>
@@ -46,5 +47,4 @@ namespace Discord.Rest
/// A user object representing the user that the role changes were performed on. /// A user object representing the user that the role changes were performed on.
/// </returns> /// </returns>
public IUser Target { get; } public IUser Target { get; }
}
} }

View File

@@ -1,10 +1,10 @@
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// An information object representing a change in one of a guild member's roles.
/// </summary>
public struct MemberRoleEditInfo
{ {
/// <summary>
/// An information object representing a change in one of a guild member's roles.
/// </summary>
public struct MemberRoleEditInfo
{
internal MemberRoleEditInfo(string name, ulong roleId, bool added) internal MemberRoleEditInfo(string name, ulong roleId, bool added)
{ {
Name = name; Name = name;
@@ -19,6 +19,7 @@ namespace Discord.Rest
/// A string containing the name of the role that was changed. /// A string containing the name of the role that was changed.
/// </returns> /// </returns>
public string Name { get; } public string Name { get; }
/// <summary> /// <summary>
/// Gets the ID of the role that was changed. /// Gets the ID of the role that was changed.
/// </summary> /// </summary>
@@ -26,6 +27,7 @@ namespace Discord.Rest
/// A <see cref="ulong"/> representing the snowflake identifier of the role that was changed. /// A <see cref="ulong"/> representing the snowflake identifier of the role that was changed.
/// </returns> /// </returns>
public ulong RoleId { get; } public ulong RoleId { get; }
/// <summary> /// <summary>
/// Gets a value that indicates whether the role was added to the user. /// Gets a value that indicates whether the role was added to the user.
/// </summary> /// </summary>
@@ -33,5 +35,4 @@ namespace Discord.Rest
/// <c>true</c> if the role was added to the user; otherwise <c>false</c>. /// <c>true</c> if the role was added to the user; otherwise <c>false</c>.
/// </returns> /// </returns>
public bool Added { get; } public bool Added { get; }
}
} }

View File

@@ -1,14 +1,15 @@
using Discord.API.AuditLogs;
using System.Linq; using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a change in a guild member.
/// </summary>
public class MemberUpdateAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to a change in a guild member.
/// </summary>
public class MemberUpdateAuditLogData : IAuditLogData
{
private MemberUpdateAuditLogData(IUser target, MemberInfo before, MemberInfo after) private MemberUpdateAuditLogData(IUser target, MemberInfo before, MemberInfo after)
{ {
Target = target; Target = target;
@@ -16,28 +17,16 @@ namespace Discord.Rest
After = after; After = after;
} }
internal static MemberUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static MemberUpdateAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log = null)
{ {
var changes = entry.Changes; var changes = entry.Changes;
var nickModel = changes.FirstOrDefault(x => x.ChangedProperty == "nick"); var (before, after) = AuditLogHelper.CreateAuditLogEntityInfo<MemberInfoAuditLogModel>(changes, discord);
var deafModel = changes.FirstOrDefault(x => x.ChangedProperty == "deaf");
var muteModel = changes.FirstOrDefault(x => x.ChangedProperty == "mute");
string oldNick = nickModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer),
newNick = nickModel?.NewValue?.ToObject<string>(discord.ApiClient.Serializer);
bool? oldDeaf = deafModel?.OldValue?.ToObject<bool>(discord.ApiClient.Serializer),
newDeaf = deafModel?.NewValue?.ToObject<bool>(discord.ApiClient.Serializer);
bool? oldMute = muteModel?.OldValue?.ToObject<bool>(discord.ApiClient.Serializer),
newMute = muteModel?.NewValue?.ToObject<bool>(discord.ApiClient.Serializer);
var targetInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId); var targetInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId);
RestUser user = (targetInfo != null) ? RestUser.Create(discord, targetInfo) : null; RestUser user = (targetInfo != null) ? RestUser.Create(discord, targetInfo) : null;
var before = new MemberInfo(oldNick, oldDeaf, oldMute); return new MemberUpdateAuditLogData(user, new MemberInfo(before), new MemberInfo(after));
var after = new MemberInfo(newNick, newDeaf, newMute);
return new MemberUpdateAuditLogData(user, before, after);
} }
/// <summary> /// <summary>
@@ -64,5 +53,4 @@ namespace Discord.Rest
/// An information object containing the member information after the changes were made. /// An information object containing the member information after the changes were made.
/// </returns> /// </returns>
public MemberInfo After { get; } public MemberInfo After { get; }
}
} }

View File

@@ -1,20 +1,20 @@
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to message deletion(s).
/// </summary>
public class MessageBulkDeleteAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to message deletion(s).
/// </summary>
public class MessageBulkDeleteAuditLogData : IAuditLogData
{
private MessageBulkDeleteAuditLogData(ulong channelId, int count) private MessageBulkDeleteAuditLogData(ulong channelId, int count)
{ {
ChannelId = channelId; ChannelId = channelId;
MessageCount = count; MessageCount = count;
} }
internal static MessageBulkDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static MessageBulkDeleteAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
return new MessageBulkDeleteAuditLogData(entry.TargetId.Value, entry.Options.Count.Value); return new MessageBulkDeleteAuditLogData(entry.TargetId.Value, entry.Options.Count.Value);
} }
@@ -34,5 +34,4 @@ namespace Discord.Rest
/// An <see cref="int"/> representing the number of messages that were deleted from the channel. /// An <see cref="int"/> representing the number of messages that were deleted from the channel.
/// </returns> /// </returns>
public int MessageCount { get; } public int MessageCount { get; }
}
} }

View File

@@ -3,13 +3,13 @@ using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to message deletion(s).
/// </summary>
public class MessageDeleteAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to message deletion(s).
/// </summary>
public class MessageDeleteAuditLogData : IAuditLogData
{
private MessageDeleteAuditLogData(ulong channelId, int count, IUser user) private MessageDeleteAuditLogData(ulong channelId, int count, IUser user)
{ {
ChannelId = channelId; ChannelId = channelId;
@@ -17,7 +17,7 @@ namespace Discord.Rest
Target = user; Target = user;
} }
internal static MessageDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static MessageDeleteAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId); var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId);
return new MessageDeleteAuditLogData(entry.Options.ChannelId.Value, entry.Options.Count.Value, userInfo != null ? RestUser.Create(discord, userInfo) : null); return new MessageDeleteAuditLogData(entry.Options.ChannelId.Value, entry.Options.Count.Value, userInfo != null ? RestUser.Create(discord, userInfo) : null);
@@ -48,5 +48,4 @@ namespace Discord.Rest
/// A user object representing the user that created the deleted messages. /// A user object representing the user that created the deleted messages.
/// </returns> /// </returns>
public IUser Target { get; } public IUser Target { get; }
}
} }

View File

@@ -2,13 +2,13 @@ using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a pinned message.
/// </summary>
public class MessagePinAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to a pinned message.
/// </summary>
public class MessagePinAuditLogData : IAuditLogData
{
private MessagePinAuditLogData(ulong messageId, ulong channelId, IUser user) private MessagePinAuditLogData(ulong messageId, ulong channelId, IUser user)
{ {
MessageId = messageId; MessageId = messageId;
@@ -16,7 +16,7 @@ namespace Discord.Rest
Target = user; Target = user;
} }
internal static MessagePinAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static MessagePinAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
RestUser user = null; RestUser user = null;
if (entry.TargetId.HasValue) if (entry.TargetId.HasValue)
@@ -25,7 +25,7 @@ namespace Discord.Rest
user = (userInfo != null) ? RestUser.Create(discord, userInfo) : null; user = (userInfo != null) ? RestUser.Create(discord, userInfo) : null;
} }
return new MessagePinAuditLogData(entry.Options.MessageId.Value, entry.Options.ChannelId.Value, user); return new MessagePinAuditLogData(entry.Options.MessageId!.Value, entry.Options.ChannelId!.Value, user);
} }
/// <summary> /// <summary>
@@ -35,6 +35,7 @@ namespace Discord.Rest
/// A <see cref="ulong"/> representing the snowflake identifier for the messages that was pinned. /// A <see cref="ulong"/> representing the snowflake identifier for the messages that was pinned.
/// </returns> /// </returns>
public ulong MessageId { get; } public ulong MessageId { get; }
/// <summary> /// <summary>
/// Gets the ID of the channel that the message was pinned from. /// Gets the ID of the channel that the message was pinned from.
/// </summary> /// </summary>
@@ -42,6 +43,7 @@ namespace Discord.Rest
/// A <see cref="ulong"/> representing the snowflake identifier for the channel that the message was pinned from. /// A <see cref="ulong"/> representing the snowflake identifier for the channel that the message was pinned from.
/// </returns> /// </returns>
public ulong ChannelId { get; } public ulong ChannelId { get; }
/// <summary> /// <summary>
/// Gets the user of the message that was pinned if available. /// Gets the user of the message that was pinned if available.
/// </summary> /// </summary>
@@ -52,5 +54,4 @@ namespace Discord.Rest
/// A user object representing the user that created the pinned message or <see langword="null"/>. /// A user object representing the user that created the pinned message or <see langword="null"/>.
/// </returns> /// </returns>
public IUser Target { get; } public IUser Target { get; }
}
} }

View File

@@ -2,13 +2,13 @@ using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to an unpinned message.
/// </summary>
public class MessageUnpinAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to an unpinned message.
/// </summary>
public class MessageUnpinAuditLogData : IAuditLogData
{
private MessageUnpinAuditLogData(ulong messageId, ulong channelId, IUser user) private MessageUnpinAuditLogData(ulong messageId, ulong channelId, IUser user)
{ {
MessageId = messageId; MessageId = messageId;
@@ -16,7 +16,7 @@ namespace Discord.Rest
Target = user; Target = user;
} }
internal static MessageUnpinAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static MessageUnpinAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
RestUser user = null; RestUser user = null;
if (entry.TargetId.HasValue) if (entry.TargetId.HasValue)
@@ -52,5 +52,4 @@ namespace Discord.Rest
/// A user object representing the user that created the unpinned message or <see langword="null"/>. /// A user object representing the user that created the unpinned message or <see langword="null"/>.
/// </returns> /// </returns>
public IUser Target { get; } public IUser Target { get; }
}
} }

View File

@@ -0,0 +1,34 @@
using Discord.API.AuditLogs;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
namespace Discord.Rest;
public class OnboardingInfo
{
internal OnboardingInfo(OnboardingAuditLogModel model, BaseDiscordClient discord)
{
Prompts = model.Prompts?.Select(x => new RestGuildOnboardingPrompt(discord, x.Id, x)).ToImmutableArray();
DefaultChannelIds = model.DefaultChannelIds;
IsEnabled = model.Enabled;
}
/// <inheritdoc cref="IGuildOnboarding.Prompts"/>
/// <remarks>
/// <see langword="null"/> if this property is not mentioned in this entry.
/// </remarks>
IReadOnlyCollection<IGuildOnboardingPrompt> Prompts { get; }
/// <inheritdoc cref="IGuildOnboarding.DefaultChannelIds"/>
/// <remarks>
/// <see langword="null"/> if this property is not mentioned in this entry.
/// </remarks>
IReadOnlyCollection<ulong> DefaultChannelIds { get; }
/// <inheritdoc cref="IGuildOnboarding.IsEnabled"/>
/// <remarks>
/// <see langword="null"/> if this property is not mentioned in this entry.
/// </remarks>
bool? IsEnabled { get; }
}

View File

@@ -0,0 +1,31 @@
using Discord.API.AuditLogs;
using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog;
namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to an onboarding prompt creation.
/// </summary>
public class OnboardingPromptCreatedAuditLogData : IAuditLogData
{
internal OnboardingPromptCreatedAuditLogData(OnboardingPromptInfo data)
{
Data = data;
}
internal static OnboardingPromptCreatedAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log = null)
{
var changes = entry.Changes;
var (_, data) = AuditLogHelper.CreateAuditLogEntityInfo<OnboardingPromptAuditLogModel>(changes, discord);
return new OnboardingPromptCreatedAuditLogData(new(data, discord));
}
/// <summary>
/// Gets the onboarding prompt information after the changes.
/// </summary>
OnboardingPromptInfo Data { get; set; }
}

View File

@@ -0,0 +1,56 @@
using Discord.API.AuditLogs;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
namespace Discord.Rest;
public class OnboardingPromptInfo
{
internal OnboardingPromptInfo(OnboardingPromptAuditLogModel model, BaseDiscordClient discord)
{
Title = model.Title;
IsSingleSelect = model.IsSingleSelect;
IsRequired = model.IsRequired;
IsInOnboarding = model.IsInOnboarding;
Type = model.Type;
Options = model.Options?.Select(x => new RestGuildOnboardingPromptOption(discord, x.Id, x)).ToImmutableArray();
}
/// <inheritdoc cref="IGuildOnboardingPrompt.Title"/>
/// <remarks>
/// <see langword="null"/> if this property is not mentioned in this entry.
/// </remarks>
string Title { get; }
/// <inheritdoc cref="IGuildOnboardingPrompt.IsSingleSelect"/>
/// <remarks>
/// <see langword="null"/> if this property is not mentioned in this entry.
/// </remarks>
bool? IsSingleSelect { get; }
/// <inheritdoc cref="IGuildOnboardingPrompt.IsRequired"/>
/// <remarks>
/// <see langword="null"/> if this property is not mentioned in this entry.
/// </remarks>
bool? IsRequired { get; }
/// <inheritdoc cref="IGuildOnboardingPrompt.IsInOnboarding"/>
/// <remarks>
/// <see langword="null"/> if this property is not mentioned in this entry.
/// </remarks>
bool? IsInOnboarding { get; }
/// <inheritdoc cref="IGuildOnboardingPrompt.Type"/>
/// <remarks>
/// <see langword="null"/> if this property is not mentioned in this entry.
/// </remarks>
GuildOnboardingPromptType? Type { get; }
/// <inheritdoc cref="IGuildOnboardingPrompt.Options"/>
/// <remarks>
/// <see langword="null"/> if this property is not mentioned in this entry.
/// </remarks>
IReadOnlyCollection<IGuildOnboardingPromptOption> Options { get; }
}

View File

@@ -0,0 +1,38 @@
using Discord.API.AuditLogs;
using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog;
namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to an onboarding prompt update.
/// </summary>
public class OnboardingPromptUpdatedAuditLogData : IAuditLogData
{
internal OnboardingPromptUpdatedAuditLogData(OnboardingPromptInfo before, OnboardingPromptInfo after)
{
Before = before;
After = after;
}
internal static OnboardingPromptUpdatedAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log = null)
{
var changes = entry.Changes;
var (before, after) = AuditLogHelper.CreateAuditLogEntityInfo<OnboardingPromptAuditLogModel>(changes, discord);
return new OnboardingPromptUpdatedAuditLogData(new(before, discord), new(after, discord));
}
/// <summary>
/// Gets the onboarding prompt information after the changes.
/// </summary>
OnboardingPromptInfo After { get; set; }
/// <summary>
/// Gets the onboarding prompt information before the changes.
/// </summary>
OnboardingPromptInfo Before { get; set; }
}

View File

@@ -0,0 +1,38 @@
using Discord.API.AuditLogs;
using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog;
namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a guild update.
/// </summary>
public class OnboardingUpdatedAuditLogData : IAuditLogData
{
internal OnboardingUpdatedAuditLogData(OnboardingInfo before, OnboardingInfo after)
{
Before = before;
After = after;
}
internal static OnboardingUpdatedAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log = null)
{
var changes = entry.Changes;
var (before, after) = AuditLogHelper.CreateAuditLogEntityInfo<OnboardingAuditLogModel>(changes, discord);
return new OnboardingUpdatedAuditLogData(new(before, discord), new(after, discord));
}
/// <summary>
/// Gets the onboarding information after the changes.
/// </summary>
OnboardingInfo After { get; set; }
/// <summary>
/// Gets the onboarding information before the changes.
/// </summary>
OnboardingInfo Before { get; set; }
}

View File

@@ -1,21 +1,22 @@
using System.Linq; using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data for a permissions overwrite creation.
/// </summary>
public class OverwriteCreateAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data for a permissions overwrite creation.
/// </summary>
public class OverwriteCreateAuditLogData : IAuditLogData
{
private OverwriteCreateAuditLogData(ulong channelId, Overwrite overwrite) private OverwriteCreateAuditLogData(ulong channelId, Overwrite overwrite)
{ {
ChannelId = channelId; ChannelId = channelId;
Overwrite = overwrite; Overwrite = overwrite;
} }
internal static OverwriteCreateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static OverwriteCreateAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log = null)
{ {
var changes = entry.Changes; var changes = entry.Changes;
@@ -48,5 +49,4 @@ namespace Discord.Rest
/// An <see cref="Overwrite"/> object representing the overwrite that was created. /// An <see cref="Overwrite"/> object representing the overwrite that was created.
/// </returns> /// </returns>
public Overwrite Overwrite { get; } public Overwrite Overwrite { get; }
}
} }

View File

@@ -2,20 +2,20 @@ using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to the deletion of a permission overwrite.
/// </summary>
public class OverwriteDeleteAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to the deletion of a permission overwrite.
/// </summary>
public class OverwriteDeleteAuditLogData : IAuditLogData
{
private OverwriteDeleteAuditLogData(ulong channelId, Overwrite deletedOverwrite) private OverwriteDeleteAuditLogData(ulong channelId, Overwrite deletedOverwrite)
{ {
ChannelId = channelId; ChannelId = channelId;
Overwrite = deletedOverwrite; Overwrite = deletedOverwrite;
} }
internal static OverwriteDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static OverwriteDeleteAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log = null)
{ {
var changes = entry.Changes; var changes = entry.Changes;
@@ -48,5 +48,4 @@ namespace Discord.Rest
/// An <see cref="Overwrite"/> object representing the overwrite that was deleted. /// An <see cref="Overwrite"/> object representing the overwrite that was deleted.
/// </returns> /// </returns>
public Overwrite Overwrite { get; } public Overwrite Overwrite { get; }
}
} }

View File

@@ -1,14 +1,15 @@
using System.Linq; using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to the update of a permission overwrite.
/// </summary>
public class OverwriteUpdateAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to the update of a permission overwrite.
/// </summary>
public class OverwriteUpdateAuditLogData : IAuditLogData
{
private OverwriteUpdateAuditLogData(ulong channelId, OverwritePermissions before, OverwritePermissions after, ulong targetId, PermissionTarget targetType) private OverwriteUpdateAuditLogData(ulong channelId, OverwritePermissions before, OverwritePermissions after, ulong targetId, PermissionTarget targetType)
{ {
ChannelId = channelId; ChannelId = channelId;
@@ -18,7 +19,7 @@ namespace Discord.Rest
OverwriteType = targetType; OverwriteType = targetType;
} }
internal static OverwriteUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static OverwriteUpdateAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log = null)
{ {
var changes = entry.Changes; var changes = entry.Changes;
@@ -76,5 +77,4 @@ namespace Discord.Rest
/// The target of the updated permission overwrite. /// The target of the updated permission overwrite.
/// </returns> /// </returns>
public PermissionTarget OverwriteType { get; } public PermissionTarget OverwriteType { get; }
}
} }

View File

@@ -1,20 +1,20 @@
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a guild prune.
/// </summary>
public class PruneAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to a guild prune.
/// </summary>
public class PruneAuditLogData : IAuditLogData
{
private PruneAuditLogData(int pruneDays, int membersRemoved) private PruneAuditLogData(int pruneDays, int membersRemoved)
{ {
PruneDays = pruneDays; PruneDays = pruneDays;
MembersRemoved = membersRemoved; MembersRemoved = membersRemoved;
} }
internal static PruneAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static PruneAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log = null)
{ {
return new PruneAuditLogData(entry.Options.PruneDeleteMemberDays.Value, entry.Options.PruneMembersRemoved.Value); return new PruneAuditLogData(entry.Options.PruneDeleteMemberDays.Value, entry.Options.PruneMembersRemoved.Value);
} }
@@ -28,6 +28,7 @@ namespace Discord.Rest
/// kicked from the server) /// kicked from the server)
/// </returns> /// </returns>
public int PruneDays { get; } public int PruneDays { get; }
/// <summary> /// <summary>
/// Gets the number of members that were kicked during the purge. /// Gets the number of members that were kicked during the purge.
/// </summary> /// </summary>
@@ -36,5 +37,4 @@ namespace Discord.Rest
/// not been seen within <paramref cref="PruneDays"/>. /// not been seen within <paramref cref="PruneDays"/>.
/// </returns> /// </returns>
public int MembersRemoved { get; } public int MembersRemoved { get; }
}
} }

View File

@@ -1,46 +1,31 @@
using Discord.API.AuditLogs;
using System.Linq; using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a role creation.
/// </summary>
public class RoleCreateAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to a role creation.
/// </summary>
public class RoleCreateAuditLogData : IAuditLogData
{
private RoleCreateAuditLogData(ulong id, RoleEditInfo props) private RoleCreateAuditLogData(ulong id, RoleEditInfo props)
{ {
RoleId = id; RoleId = id;
Properties = props; Properties = props;
} }
internal static RoleCreateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static RoleCreateAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var changes = entry.Changes; var changes = entry.Changes;
var colorModel = changes.FirstOrDefault(x => x.ChangedProperty == "color"); var (_, data) = AuditLogHelper.CreateAuditLogEntityInfo<RoleInfoAuditLogModel>(changes, discord);
var mentionableModel = changes.FirstOrDefault(x => x.ChangedProperty == "mentionable");
var hoistModel = changes.FirstOrDefault(x => x.ChangedProperty == "hoist");
var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name");
var permissionsModel = changes.FirstOrDefault(x => x.ChangedProperty == "permissions");
uint? colorRaw = colorModel?.NewValue?.ToObject<uint>(discord.ApiClient.Serializer); return new RoleCreateAuditLogData(entry.TargetId!.Value,
bool? mentionable = mentionableModel?.NewValue?.ToObject<bool>(discord.ApiClient.Serializer); new RoleEditInfo(data));
bool? hoist = hoistModel?.NewValue?.ToObject<bool>(discord.ApiClient.Serializer);
string name = nameModel?.NewValue?.ToObject<string>(discord.ApiClient.Serializer);
ulong? permissionsRaw = permissionsModel?.NewValue?.ToObject<ulong>(discord.ApiClient.Serializer);
Color? color = null;
GuildPermissions? permissions = null;
if (colorRaw.HasValue)
color = new Color(colorRaw.Value);
if (permissionsRaw.HasValue)
permissions = new GuildPermissions(permissionsRaw.Value);
return new RoleCreateAuditLogData(entry.TargetId.Value,
new RoleEditInfo(color, mentionable, hoist, name, permissions));
} }
/// <summary> /// <summary>
@@ -50,6 +35,7 @@ namespace Discord.Rest
/// A <see cref="ulong"/> representing the snowflake identifier to the role that was created. /// A <see cref="ulong"/> representing the snowflake identifier to the role that was created.
/// </return> /// </return>
public ulong RoleId { get; } public ulong RoleId { get; }
/// <summary> /// <summary>
/// Gets the role information that was created. /// Gets the role information that was created.
/// </summary> /// </summary>
@@ -57,5 +43,4 @@ namespace Discord.Rest
/// An information object representing the properties of the role that was created. /// An information object representing the properties of the role that was created.
/// </return> /// </return>
public RoleEditInfo Properties { get; } public RoleEditInfo Properties { get; }
}
} }

View File

@@ -1,46 +1,28 @@
using System.Linq; using Discord.API.AuditLogs;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data relating to a role deletion.
/// </summary>
public class RoleDeleteAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data relating to a role deletion.
/// </summary>
public class RoleDeleteAuditLogData : IAuditLogData
{
private RoleDeleteAuditLogData(ulong id, RoleEditInfo props) private RoleDeleteAuditLogData(ulong id, RoleEditInfo props)
{ {
RoleId = id; RoleId = id;
Properties = props; Properties = props;
} }
internal static RoleDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static RoleDeleteAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var changes = entry.Changes; var changes = entry.Changes;
var colorModel = changes.FirstOrDefault(x => x.ChangedProperty == "color"); var (data, _) = AuditLogHelper.CreateAuditLogEntityInfo<RoleInfoAuditLogModel>(changes, discord);
var mentionableModel = changes.FirstOrDefault(x => x.ChangedProperty == "mentionable");
var hoistModel = changes.FirstOrDefault(x => x.ChangedProperty == "hoist");
var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name");
var permissionsModel = changes.FirstOrDefault(x => x.ChangedProperty == "permissions");
uint? colorRaw = colorModel?.OldValue?.ToObject<uint>(discord.ApiClient.Serializer); return new RoleDeleteAuditLogData(entry.TargetId!.Value, new RoleEditInfo(data));
bool? mentionable = mentionableModel?.OldValue?.ToObject<bool>(discord.ApiClient.Serializer);
bool? hoist = hoistModel?.OldValue?.ToObject<bool>(discord.ApiClient.Serializer);
string name = nameModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer);
ulong? permissionsRaw = permissionsModel?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer);
Color? color = null;
GuildPermissions? permissions = null;
if (colorRaw.HasValue)
color = new Color(colorRaw.Value);
if (permissionsRaw.HasValue)
permissions = new GuildPermissions(permissionsRaw.Value);
return new RoleDeleteAuditLogData(entry.TargetId.Value,
new RoleEditInfo(color, mentionable, hoist, name, permissions));
} }
/// <summary> /// <summary>
@@ -50,6 +32,7 @@ namespace Discord.Rest
/// A <see cref="ulong"/> representing the snowflake identifier to the role that was deleted. /// A <see cref="ulong"/> representing the snowflake identifier to the role that was deleted.
/// </return> /// </return>
public ulong RoleId { get; } public ulong RoleId { get; }
/// <summary> /// <summary>
/// Gets the role information that was deleted. /// Gets the role information that was deleted.
/// </summary> /// </summary>
@@ -57,5 +40,4 @@ namespace Discord.Rest
/// An information object representing the properties of the role that was deleted. /// An information object representing the properties of the role that was deleted.
/// </return> /// </return>
public RoleEditInfo Properties { get; } public RoleEditInfo Properties { get; }
}
} }

View File

@@ -1,18 +1,29 @@
namespace Discord.Rest using Model = Discord.API.AuditLogs.RoleInfoAuditLogModel;
namespace Discord.Rest;
/// <summary>
/// Represents information for a role edit.
/// </summary>
public struct RoleEditInfo
{ {
/// <summary> internal RoleEditInfo(Model model)
/// Represents information for a role edit.
/// </summary>
public struct RoleEditInfo
{ {
internal RoleEditInfo(Color? color, bool? mentionable, bool? hoist, string name, if (model.Color is not null)
GuildPermissions? permissions) Color = new Color(model.Color.Value);
{ else
Color = color; Color = null;
Mentionable = mentionable;
Hoist = hoist; Mentionable = model.IsMentionable;
Name = name; Hoist = model.Hoist;
Permissions = permissions; Name = model.Name;
if (model.Permissions is not null)
Permissions = new GuildPermissions(model.Permissions.Value);
else
Permissions = null;
IconId = model.IconHash;
} }
/// <summary> /// <summary>
@@ -23,6 +34,7 @@ namespace Discord.Rest
/// color. /// color.
/// </returns> /// </returns>
public Color? Color { get; } public Color? Color { get; }
/// <summary> /// <summary>
/// Gets a value that indicates whether this role is mentionable. /// Gets a value that indicates whether this role is mentionable.
/// </summary> /// </summary>
@@ -31,6 +43,7 @@ namespace Discord.Rest
/// <c>null</c> if this is not mentioned in this entry. /// <c>null</c> if this is not mentioned in this entry.
/// </returns> /// </returns>
public bool? Mentionable { get; } public bool? Mentionable { get; }
/// <summary> /// <summary>
/// Gets a value that indicates whether this role is hoisted (i.e. its members will appear in a separate /// Gets a value that indicates whether this role is hoisted (i.e. its members will appear in a separate
/// section on the user list). /// section on the user list).
@@ -40,6 +53,7 @@ namespace Discord.Rest
/// <c>false</c>; <c>null</c> if this is not mentioned in this entry. /// <c>false</c>; <c>null</c> if this is not mentioned in this entry.
/// </returns> /// </returns>
public bool? Hoist { get; } public bool? Hoist { get; }
/// <summary> /// <summary>
/// Gets the name of this role. /// Gets the name of this role.
/// </summary> /// </summary>
@@ -47,6 +61,7 @@ namespace Discord.Rest
/// A string containing the name of this role. /// A string containing the name of this role.
/// </returns> /// </returns>
public string Name { get; } public string Name { get; }
/// <summary> /// <summary>
/// Gets the permissions assigned to this role. /// Gets the permissions assigned to this role.
/// </summary> /// </summary>
@@ -55,5 +70,10 @@ namespace Discord.Rest
/// if no permissions have been assigned. /// if no permissions have been assigned.
/// </returns> /// </returns>
public GuildPermissions? Permissions { get; } public GuildPermissions? Permissions { get; }
}
/// <inheritdoc cref="IRole.Icon"/>
/// <remarks>
/// <see langword="null" /> if the value was not updated in this entry.
/// </remarks>
public string IconId { get; }
} }

View File

@@ -1,14 +1,15 @@
using System.Linq; using Discord.API.AuditLogs;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a role update.
/// </summary>
public class RoleUpdateAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to a role update.
/// </summary>
public class RoleUpdateAuditLogData : IAuditLogData
{
private RoleUpdateAuditLogData(ulong id, RoleEditInfo oldProps, RoleEditInfo newProps) private RoleUpdateAuditLogData(ulong id, RoleEditInfo oldProps, RoleEditInfo newProps)
{ {
RoleId = id; RoleId = id;
@@ -16,45 +17,13 @@ namespace Discord.Rest
After = newProps; After = newProps;
} }
internal static RoleUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static RoleUpdateAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var changes = entry.Changes; var changes = entry.Changes;
var colorModel = changes.FirstOrDefault(x => x.ChangedProperty == "color"); var (before, after) = AuditLogHelper.CreateAuditLogEntityInfo<RoleInfoAuditLogModel>(changes, discord);
var mentionableModel = changes.FirstOrDefault(x => x.ChangedProperty == "mentionable");
var hoistModel = changes.FirstOrDefault(x => x.ChangedProperty == "hoist");
var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name");
var permissionsModel = changes.FirstOrDefault(x => x.ChangedProperty == "permissions");
uint? oldColorRaw = colorModel?.OldValue?.ToObject<uint>(discord.ApiClient.Serializer), return new RoleUpdateAuditLogData(entry.TargetId!.Value, new(before), new(after));
newColorRaw = colorModel?.NewValue?.ToObject<uint>(discord.ApiClient.Serializer);
bool? oldMentionable = mentionableModel?.OldValue?.ToObject<bool>(discord.ApiClient.Serializer),
newMentionable = mentionableModel?.NewValue?.ToObject<bool>(discord.ApiClient.Serializer);
bool? oldHoist = hoistModel?.OldValue?.ToObject<bool>(discord.ApiClient.Serializer),
newHoist = hoistModel?.NewValue?.ToObject<bool>(discord.ApiClient.Serializer);
string oldName = nameModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer),
newName = nameModel?.NewValue?.ToObject<string>(discord.ApiClient.Serializer);
ulong? oldPermissionsRaw = permissionsModel?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer),
newPermissionsRaw = permissionsModel?.NewValue?.ToObject<ulong>(discord.ApiClient.Serializer);
Color? oldColor = null,
newColor = null;
GuildPermissions? oldPermissions = null,
newPermissions = null;
if (oldColorRaw.HasValue)
oldColor = new Color(oldColorRaw.Value);
if (newColorRaw.HasValue)
newColor = new Color(newColorRaw.Value);
if (oldPermissionsRaw.HasValue)
oldPermissions = new GuildPermissions(oldPermissionsRaw.Value);
if (newPermissionsRaw.HasValue)
newPermissions = new GuildPermissions(newPermissionsRaw.Value);
var oldProps = new RoleEditInfo(oldColor, oldMentionable, oldHoist, oldName, oldPermissions);
var newProps = new RoleEditInfo(newColor, newMentionable, newHoist, newName, newPermissions);
return new RoleUpdateAuditLogData(entry.TargetId.Value, oldProps, newProps);
} }
/// <summary> /// <summary>
@@ -64,6 +33,7 @@ namespace Discord.Rest
/// A <see cref="ulong"/> representing the snowflake identifier of the role that was changed. /// A <see cref="ulong"/> representing the snowflake identifier of the role that was changed.
/// </returns> /// </returns>
public ulong RoleId { get; } public ulong RoleId { get; }
/// <summary> /// <summary>
/// Gets the role information before the changes. /// Gets the role information before the changes.
/// </summary> /// </summary>
@@ -71,6 +41,7 @@ namespace Discord.Rest
/// A role information object containing the role information before the changes were made. /// A role information object containing the role information before the changes were made.
/// </returns> /// </returns>
public RoleEditInfo Before { get; } public RoleEditInfo Before { get; }
/// <summary> /// <summary>
/// Gets the role information after the changes. /// Gets the role information after the changes.
/// </summary> /// </summary>
@@ -78,5 +49,4 @@ namespace Discord.Rest
/// A role information object containing the role information after the changes were made. /// A role information object containing the role information after the changes were made.
/// </returns> /// </returns>
public RoleEditInfo After { get; } public RoleEditInfo After { get; }
}
} }

View File

@@ -1,83 +1,49 @@
using Discord.API; using Discord.API.AuditLogs;
using System; using System;
using System.Linq; using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a scheduled event creation.
/// </summary>
public class ScheduledEventCreateAuditLogData : IAuditLogData
{ {
/// <summary> private ScheduledEventCreateAuditLogData(ulong id, ScheduledEventInfoAuditLogModel model, IGuildScheduledEvent scheduledEvent)
/// Contains a piece of audit log data related to a scheduled event creation.
/// </summary>
public class ScheduledEventCreateAuditLogData : IAuditLogData
{
private ScheduledEventCreateAuditLogData(ulong id, ulong guildId, ulong? channelId, ulong? creatorId, string name, string description, DateTimeOffset scheduledStartTime, DateTimeOffset? scheduledEndTime, GuildScheduledEventPrivacyLevel privacyLevel, GuildScheduledEventStatus status, GuildScheduledEventType entityType, ulong? entityId, string location, RestUser creator, int userCount, string image)
{ {
Id = id; Id = id;
GuildId = guildId; ChannelId = model.ChannelId;
ChannelId = channelId; Name = model.Name;
CreatorId = creatorId; Description = model.Description;
Name = name; ScheduledStartTime = model.StartTime;
Description = description; ScheduledEndTime = model.EndTime;
ScheduledStartTime = scheduledStartTime; PrivacyLevel = model.PrivacyLevel!.Value;
ScheduledEndTime = scheduledEndTime; Status = model.EventStatus!.Value;
PrivacyLevel = privacyLevel; EntityType = model.EventType!.Value;
Status = status; EntityId = model.EntityId;
EntityType = entityType; Location = model.Location;
EntityId = entityId; Image = model.Image;
Location = location; ScheduledEvent = scheduledEvent;
Creator = creator;
UserCount = userCount;
Image = image;
} }
internal static ScheduledEventCreateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static ScheduledEventCreateAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var changes = entry.Changes; var changes = entry.Changes;
var id = entry.TargetId.Value; var (_, data) = AuditLogHelper.CreateAuditLogEntityInfo<ScheduledEventInfoAuditLogModel>(changes, discord);
var guildId = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "guild_id") var scheduledEvent = log.GuildScheduledEvents.FirstOrDefault(x => x.Id == entry.TargetId);
.NewValue.ToObject<ulong>(discord.ApiClient.Serializer);
var channelId = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "channel_id")
.NewValue.ToObject<ulong?>(discord.ApiClient.Serializer);
var creatorId = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "channel_id")
.NewValue.ToObject<Optional<ulong?>>(discord.ApiClient.Serializer)
.GetValueOrDefault();
var name = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name")
.NewValue.ToObject<string>(discord.ApiClient.Serializer);
var description = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "description")
.NewValue.ToObject<Optional<string>>(discord.ApiClient.Serializer)
.GetValueOrDefault();
var scheduledStartTime = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "scheduled_start_time")
.NewValue.ToObject<DateTimeOffset>(discord.ApiClient.Serializer);
var scheduledEndTime = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "scheduled_end_time")
.NewValue.ToObject<DateTimeOffset?>(discord.ApiClient.Serializer);
var privacyLevel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "privacy_level")
.NewValue.ToObject<GuildScheduledEventPrivacyLevel>(discord.ApiClient.Serializer);
var status = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "status")
.NewValue.ToObject<GuildScheduledEventStatus>(discord.ApiClient.Serializer);
var entityType = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "entity_type")
.NewValue.ToObject<GuildScheduledEventType>(discord.ApiClient.Serializer);
var entityId = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "entity_id")
.NewValue.ToObject<ulong?>(discord.ApiClient.Serializer);
var entityMetadata = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "entity_metadata")
.NewValue.ToObject<GuildScheduledEventEntityMetadata>(discord.ApiClient.Serializer);
var creator = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "creator")
.NewValue.ToObject<Optional<User>>(discord.ApiClient.Serializer)
.GetValueOrDefault();
var userCount = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "user_count")
.NewValue.ToObject<Optional<int>>(discord.ApiClient.Serializer)
.GetValueOrDefault();
var image = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "image")
.NewValue.ToObject<Optional<string>>(discord.ApiClient.Serializer)
.GetValueOrDefault();
var creatorUser = creator == null ? null : RestUser.Create(discord, creator); return new ScheduledEventCreateAuditLogData(entry.TargetId!.Value, data, RestGuildEvent.Create(discord, null, scheduledEvent));
return new ScheduledEventCreateAuditLogData(id, guildId, channelId, creatorId, name, description, scheduledStartTime, scheduledEndTime, privacyLevel, status, entityType, entityId, entityMetadata.Location.GetValueOrDefault(), creatorUser, userCount, image);
} }
/// <summary>
/// Gets the scheduled event this log corresponds to.
/// </summary>
public IGuildScheduledEvent ScheduledEvent { get; }
// Doc Note: Corresponds to the *current* data // Doc Note: Corresponds to the *current* data
/// <summary> /// <summary>
@@ -85,18 +51,10 @@ namespace Discord.Rest
/// </summary> /// </summary>
public ulong Id { get; } public ulong Id { get; }
/// <summary> /// <summary>
/// Gets the snowflake id of the guild the event is associated with.
/// </summary>
public ulong GuildId { get; }
/// <summary>
/// Gets the snowflake id of the channel the event is associated with. /// Gets the snowflake id of the channel the event is associated with.
/// </summary> /// </summary>
public ulong? ChannelId { get; } public ulong? ChannelId { get; }
/// <summary> /// <summary>
/// Gets the snowflake id of the original creator of the event.
/// </summary>
public ulong? CreatorId { get; }
/// <summary>
/// Gets name of the event. /// Gets name of the event.
/// </summary> /// </summary>
public string Name { get; } public string Name { get; }
@@ -107,7 +65,7 @@ namespace Discord.Rest
/// <summary> /// <summary>
/// Gets the time the event was scheduled for. /// Gets the time the event was scheduled for.
/// </summary> /// </summary>
public DateTimeOffset ScheduledStartTime { get; } public DateTimeOffset? ScheduledStartTime { get; }
/// <summary> /// <summary>
/// Gets the time the event was scheduled to end. /// Gets the time the event was scheduled to end.
/// </summary> /// </summary>
@@ -133,16 +91,7 @@ namespace Discord.Rest
/// </summary> /// </summary>
public string Location { get; } public string Location { get; }
/// <summary> /// <summary>
/// Gets the user that originally created the event.
/// </summary>
public RestUser Creator { get; }
/// <summary>
/// Gets the count of users interested in this event.
/// </summary>
public int UserCount { get; }
/// <summary>
/// Gets the image hash of the image that was attached to the event. Null if not set. /// Gets the image hash of the image that was attached to the event. Null if not set.
/// </summary> /// </summary>
public string Image { get; } public string Image { get; }
}
} }

View File

@@ -1,33 +1,97 @@
using Discord.API; using Discord.API.AuditLogs;
using System; using System;
using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a scheduled event deletion.
/// </summary>
public class ScheduledEventDeleteAuditLogData : IAuditLogData
{ {
/// <summary> private ScheduledEventDeleteAuditLogData(ulong id, ScheduledEventInfoAuditLogModel model)
/// Contains a piece of audit log data related to a scheduled event deletion.
/// </summary>
public class ScheduledEventDeleteAuditLogData : IAuditLogData
{
private ScheduledEventDeleteAuditLogData(ulong id)
{ {
Id = id; Id = id;
ChannelId = model.ChannelId;
Name = model.Name;
Description = model.Description;
ScheduledStartTime = model.StartTime;
ScheduledEndTime = model.EndTime;
PrivacyLevel = model.PrivacyLevel;
Status = model.EventStatus;
EntityType = model.EventType;
EntityId = model.EntityId;
Location = model.Location;
Image = model.Image;
} }
internal static ScheduledEventDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static ScheduledEventDeleteAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var id = entry.TargetId.Value; var changes = entry.Changes;
return new ScheduledEventDeleteAuditLogData(id); var (data, _) = AuditLogHelper.CreateAuditLogEntityInfo<ScheduledEventInfoAuditLogModel>(changes, discord);
return new ScheduledEventDeleteAuditLogData(entry.TargetId!.Value, data);
} }
// Doc Note: Corresponds to the *current* data
/// <summary> /// <summary>
/// Gets the snowflake id of the event. /// Gets the snowflake id of the event.
/// </summary> /// </summary>
public ulong Id { get; } public ulong Id { get; }
}
/// <summary>
/// Gets the snowflake id of the channel the event is associated with.
/// </summary>
public ulong? ChannelId { get; }
/// <summary>
/// Gets name of the event.
/// </summary>
public string Name { get; }
/// <summary>
/// Gets the description of the event. null if none is set.
/// </summary>
public string Description { get; }
/// <summary>
/// Gets the time the event was scheduled for.
/// </summary>
public DateTimeOffset? ScheduledStartTime { get; }
/// <summary>
/// Gets the time the event was scheduled to end.
/// </summary>
public DateTimeOffset? ScheduledEndTime { get; }
/// <summary>
/// Gets the privacy level of the event.
/// </summary>
public GuildScheduledEventPrivacyLevel? PrivacyLevel { get; }
/// <summary>
/// Gets the status of the event.
/// </summary>
public GuildScheduledEventStatus? Status { get; }
/// <summary>
/// Gets the type of the entity associated with the event (stage / void / external).
/// </summary>
public GuildScheduledEventType? EntityType { get; }
/// <summary>
/// Gets the snowflake id of the entity associated with the event (stage / void / external).
/// </summary>
public ulong? EntityId { get; }
/// <summary>
/// Gets the metadata for the entity associated with the event.
/// </summary>
public string Location { get; }
/// <summary>
/// Gets the image hash of the image that was attached to the event. Null if not set.
/// </summary>
public string Image { get; }
} }

View File

@@ -1,80 +1,81 @@
using Discord.API.AuditLogs;
using System; using System;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Represents information for a scheduled event.
/// </summary>
public class ScheduledEventInfo
{ {
/// <summary> /// <summary>
/// Represents information for a scheduled event. /// Gets the snowflake id of the channel the event is associated with.
/// </summary>
public class ScheduledEventInfo
{
/// <summary>
/// Gets the snowflake id of the guild the event is associated with.
/// </summary>
public ulong? GuildId { get; }
/// <summary>
/// Gets the snowflake id of the channel the event is associated with. 0 for events with external location.
/// </summary> /// </summary>
public ulong? ChannelId { get; } public ulong? ChannelId { get; }
/// <summary> /// <summary>
/// Gets name of the event. /// Gets name of the event.
/// </summary> /// </summary>
public string Name { get; } public string Name { get; }
/// <summary> /// <summary>
/// Gets the description of the event. null if none is set. /// Gets the description of the event. null if none is set.
/// </summary> /// </summary>
public string Description { get; } public string Description { get; }
/// <summary> /// <summary>
/// Gets the time the event was scheduled for. /// Gets the time the event was scheduled for.
/// </summary> /// </summary>
public DateTimeOffset? ScheduledStartTime { get; } public DateTimeOffset? ScheduledStartTime { get; }
/// <summary> /// <summary>
/// Gets the time the event was scheduled to end. /// Gets the time the event was scheduled to end.
/// </summary> /// </summary>
public DateTimeOffset? ScheduledEndTime { get; } public DateTimeOffset? ScheduledEndTime { get; }
/// <summary> /// <summary>
/// Gets the privacy level of the event. /// Gets the privacy level of the event.
/// </summary> /// </summary>
public GuildScheduledEventPrivacyLevel? PrivacyLevel { get; } public GuildScheduledEventPrivacyLevel? PrivacyLevel { get; }
/// <summary> /// <summary>
/// Gets the status of the event. /// Gets the status of the event.
/// </summary> /// </summary>
public GuildScheduledEventStatus? Status { get; } public GuildScheduledEventStatus? Status { get; }
/// <summary> /// <summary>
/// Gets the type of the entity associated with the event (stage / void / external). /// Gets the type of the entity associated with the event (stage / void / external).
/// </summary> /// </summary>
public GuildScheduledEventType? EntityType { get; } public GuildScheduledEventType? EntityType { get; }
/// <summary> /// <summary>
/// Gets the snowflake id of the entity associated with the event (stage / void / external). /// Gets the snowflake id of the entity associated with the event (stage / void / external).
/// </summary> /// </summary>
public ulong? EntityId { get; } public ulong? EntityId { get; }
/// <summary> /// <summary>
/// Gets the metadata for the entity associated with the event. <see cref="Optional{T}.Unspecified"/> if there was no change. /// Gets the metadata for the entity associated with the event.
/// </summary> /// </summary>
public Optional<string> Location { get; } public string Location { get; }
/// <summary>
/// Gets the count of users interested in this event.
/// </summary>
public int? UserCount { get; }
/// <summary> /// <summary>
/// Gets the image hash of the image that was attached to the event. Null if not set. /// Gets the image hash of the image that was attached to the event. Null if not set.
/// </summary> /// </summary>
public string Image { get; } public string Image { get; }
internal ScheduledEventInfo(ulong? guildId, ulong? channelId, string name, string description, DateTimeOffset? scheduledStartTime, DateTimeOffset? scheduledEndTime, GuildScheduledEventPrivacyLevel? privacyLevel, GuildScheduledEventStatus? status, GuildScheduledEventType? entityType, ulong? entityId, Optional<string> location, int? userCount, string image) internal ScheduledEventInfo(ScheduledEventInfoAuditLogModel model)
{ {
GuildId = guildId; ChannelId = model.ChannelId;
ChannelId = channelId; Name = model.Name;
Name = name; Description = model.Description;
Description = description; ScheduledStartTime = model.StartTime;
ScheduledStartTime = scheduledStartTime; ScheduledEndTime = model.EndTime;
ScheduledEndTime = scheduledEndTime; PrivacyLevel = model.PrivacyLevel;
PrivacyLevel = privacyLevel; Status = model.EventStatus;
Status = status; EntityType = model.EventType;
EntityType = entityType; EntityId = model.EntityId;
EntityId = entityId; Location = model.Location;
Location = location; Image = model.Image;
UserCount = userCount;
Image = image;
}
} }
} }

View File

@@ -1,95 +1,54 @@
using System; using Discord.API.AuditLogs;
using System.Linq; using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a scheduled event updates.
/// </summary>
public class ScheduledEventUpdateAuditLogData : IAuditLogData
{ {
/// <summary> private ScheduledEventUpdateAuditLogData(ulong id, ScheduledEventInfo before, ScheduledEventInfo after, IGuildScheduledEvent scheduledEvent)
/// Contains a piece of audit log data related to a scheduled event updates.
/// </summary>
public class ScheduledEventUpdateAuditLogData : IAuditLogData
{
private ScheduledEventUpdateAuditLogData(ulong id, ScheduledEventInfo before, ScheduledEventInfo after)
{ {
Id = id; Id = id;
Before = before; Before = before;
After = after; After = after;
ScheduledEvent = scheduledEvent;
} }
internal static ScheduledEventUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static ScheduledEventUpdateAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var changes = entry.Changes; var changes = entry.Changes;
var id = entry.TargetId.Value; var (before, after) = AuditLogHelper.CreateAuditLogEntityInfo<ScheduledEventInfoAuditLogModel>(changes, discord);
var guildId = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "guild_id"); var scheduledEvent = log.GuildScheduledEvents.FirstOrDefault(x => x.Id == entry.TargetId);
var channelId = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "channel_id");
var name = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name");
var description = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "description");
var scheduledStartTime = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "scheduled_start_time");
var scheduledEndTime = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "scheduled_end_time");
var privacyLevel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "privacy_level");
var status = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "status");
var entityType = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "entity_type");
var entityId = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "entity_id");
var location = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "location");
var userCount = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "user_count");
var image = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "image");
var before = new ScheduledEventInfo( return new ScheduledEventUpdateAuditLogData(entry.TargetId!.Value, new(before), new(after), RestGuildEvent.Create(discord, null, scheduledEvent));
guildId?.OldValue.ToObject<ulong>(discord.ApiClient.Serializer),
channelId == null ? null : channelId.OldValue?.ToObject<ulong?>(discord.ApiClient.Serializer) ?? 0,
name?.OldValue.ToObject<string>(discord.ApiClient.Serializer),
description?.OldValue.ToObject<Optional<string>>(discord.ApiClient.Serializer)
.GetValueOrDefault(),
scheduledStartTime?.OldValue.ToObject<DateTimeOffset>(discord.ApiClient.Serializer),
scheduledEndTime?.OldValue.ToObject<DateTimeOffset?>(discord.ApiClient.Serializer),
privacyLevel?.OldValue.ToObject<GuildScheduledEventPrivacyLevel>(discord.ApiClient.Serializer),
status?.OldValue.ToObject<GuildScheduledEventStatus>(discord.ApiClient.Serializer),
entityType?.OldValue.ToObject<GuildScheduledEventType>(discord.ApiClient.Serializer),
entityId?.OldValue.ToObject<ulong?>(discord.ApiClient.Serializer),
location == null ? Optional<string>.Unspecified : new Optional<string>(location.OldValue?.ToObject<string>(discord.ApiClient.Serializer)),
userCount?.OldValue.ToObject<Optional<int>>(discord.ApiClient.Serializer)
.GetValueOrDefault(),
image?.OldValue.ToObject<Optional<string>>(discord.ApiClient.Serializer)
.GetValueOrDefault()
);
var after = new ScheduledEventInfo(
guildId?.NewValue.ToObject<ulong>(discord.ApiClient.Serializer),
channelId == null ? null : channelId.NewValue?.ToObject<ulong?>(discord.ApiClient.Serializer) ?? 0,
name?.NewValue.ToObject<string>(discord.ApiClient.Serializer),
description?.NewValue.ToObject<Optional<string>>(discord.ApiClient.Serializer)
.GetValueOrDefault(),
scheduledStartTime?.NewValue.ToObject<DateTimeOffset>(discord.ApiClient.Serializer),
scheduledEndTime?.NewValue.ToObject<DateTimeOffset?>(discord.ApiClient.Serializer),
privacyLevel?.NewValue.ToObject<GuildScheduledEventPrivacyLevel>(discord.ApiClient.Serializer),
status?.NewValue.ToObject<GuildScheduledEventStatus>(discord.ApiClient.Serializer),
entityType?.NewValue.ToObject<GuildScheduledEventType>(discord.ApiClient.Serializer),
entityId?.NewValue.ToObject<ulong?>(discord.ApiClient.Serializer),
location == null ? Optional<string>.Unspecified : new Optional<string>(location.NewValue?.ToObject<string>(discord.ApiClient.Serializer)),
userCount?.NewValue.ToObject<Optional<int>>(discord.ApiClient.Serializer)
.GetValueOrDefault(),
image?.NewValue.ToObject<Optional<string>>(discord.ApiClient.Serializer)
.GetValueOrDefault()
);
return new ScheduledEventUpdateAuditLogData(id, before, after);
} }
/// <summary>
/// Gets the scheduled event this log corresponds to.
/// </summary>
public IGuildScheduledEvent ScheduledEvent { get; }
// Doc Note: Corresponds to the *current* data // Doc Note: Corresponds to the *current* data
/// <summary> /// <summary>
/// Gets the snowflake id of the event. /// Gets the snowflake id of the event.
/// </summary> /// </summary>
public ulong Id { get; } public ulong Id { get; }
/// <summary> /// <summary>
/// Gets the state before the change. /// Gets the state before the change.
/// </summary> /// </summary>
public ScheduledEventInfo Before { get; } public ScheduledEventInfo Before { get; }
/// <summary> /// <summary>
/// Gets the state after the change. /// Gets the state after the change.
/// </summary> /// </summary>
public ScheduledEventInfo After { get; } public ScheduledEventInfo After { get; }
}
} }

View File

@@ -2,13 +2,13 @@ using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a stage going live.
/// </summary>
public class StageInstanceCreateAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to a stage going live.
/// </summary>
public class StageInstanceCreateAuditLogData : IAuditLogData
{
/// <summary> /// <summary>
/// Gets the topic of the stage channel. /// Gets the topic of the stage channel.
/// </summary> /// </summary>
@@ -37,7 +37,7 @@ namespace Discord.Rest
StageChannelId = channelId; StageChannelId = channelId;
} }
internal static StageInstanceCreateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static StageInstanceCreateAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var topic = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "topic").NewValue.ToObject<string>(discord.ApiClient.Serializer); var topic = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "topic").NewValue.ToObject<string>(discord.ApiClient.Serializer);
var privacyLevel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "privacy_level").NewValue.ToObject<StagePrivacyLevel>(discord.ApiClient.Serializer); var privacyLevel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "privacy_level").NewValue.ToObject<StagePrivacyLevel>(discord.ApiClient.Serializer);
@@ -46,5 +46,4 @@ namespace Discord.Rest
return new StageInstanceCreateAuditLogData(topic, privacyLevel, RestUser.Create(discord, user), channelId ?? 0); return new StageInstanceCreateAuditLogData(topic, privacyLevel, RestUser.Create(discord, user), channelId ?? 0);
} }
}
} }

View File

@@ -2,13 +2,13 @@ using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a stage instance deleted.
/// </summary>
public class StageInstanceDeleteAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to a stage instance deleted.
/// </summary>
public class StageInstanceDeleteAuditLogData
{
/// <summary> /// <summary>
/// Gets the topic of the stage channel. /// Gets the topic of the stage channel.
/// </summary> /// </summary>
@@ -37,7 +37,7 @@ namespace Discord.Rest
StageChannelId = channelId; StageChannelId = channelId;
} }
internal static StageInstanceDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static StageInstanceDeleteAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var topic = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "topic").OldValue.ToObject<string>(discord.ApiClient.Serializer); var topic = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "topic").OldValue.ToObject<string>(discord.ApiClient.Serializer);
var privacyLevel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "privacy_level").OldValue.ToObject<StagePrivacyLevel>(discord.ApiClient.Serializer); var privacyLevel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "privacy_level").OldValue.ToObject<StagePrivacyLevel>(discord.ApiClient.Serializer);
@@ -46,5 +46,4 @@ namespace Discord.Rest
return new StageInstanceDeleteAuditLogData(topic, privacyLevel, RestUser.Create(discord, user), channelId ?? 0); return new StageInstanceDeleteAuditLogData(topic, privacyLevel, RestUser.Create(discord, user), channelId ?? 0);
} }
}
} }

View File

@@ -2,13 +2,13 @@ using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a stage instance update.
/// </summary>
public class StageInstanceUpdatedAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to a stage instance update.
/// </summary>
public class StageInstanceUpdatedAuditLogData
{
/// <summary> /// <summary>
/// Gets the Id of the stage channel. /// Gets the Id of the stage channel.
/// </summary> /// </summary>
@@ -31,7 +31,7 @@ namespace Discord.Rest
After = after; After = after;
} }
internal static StageInstanceUpdatedAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static StageInstanceUpdatedAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var channelId = entry.Options.ChannelId.Value; var channelId = entry.Options.ChannelId.Value;
@@ -47,5 +47,4 @@ namespace Discord.Rest
return new StageInstanceUpdatedAuditLogData(channelId, new StageInfo(user, oldPrivacy, oldTopic), new StageInfo(user, newPrivacy, newTopic)); return new StageInstanceUpdatedAuditLogData(channelId, new StageInfo(user, oldPrivacy, oldTopic), new StageInfo(user, newPrivacy, newTopic));
} }
}
} }

View File

@@ -0,0 +1,29 @@
using Discord.API.AuditLogs;
using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog;
namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a sticker creation.
/// </summary>
public class StickerCreatedAuditLogData : IAuditLogData
{
internal StickerCreatedAuditLogData(StickerInfo data)
{
Data = data;
}
internal static StickerCreatedAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log = null)
{
var changes = entry.Changes;
var (_, data) = AuditLogHelper.CreateAuditLogEntityInfo<StickerInfoAuditLogModel>(changes, discord);
return new StickerCreatedAuditLogData(new(data));
}
/// <summary>
/// Gets the sticker information after the changes.
/// </summary>
public StickerInfo Data { get; }
}

View File

@@ -0,0 +1,29 @@
using Discord.API.AuditLogs;
using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog;
namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a sticker removal.
/// </summary>
public class StickerDeletedAuditLogData : IAuditLogData
{
internal StickerDeletedAuditLogData(StickerInfo data)
{
Data = data;
}
internal static StickerDeletedAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log = null)
{
var changes = entry.Changes;
var (data, _) = AuditLogHelper.CreateAuditLogEntityInfo<StickerInfoAuditLogModel>(changes, discord);
return new StickerDeletedAuditLogData(new(data));
}
/// <summary>
/// Gets the sticker information before the changes.
/// </summary>
public StickerInfo Data { get; }
}

View File

@@ -0,0 +1,31 @@
using Discord.API.AuditLogs;
namespace Discord.Rest;
/// <summary>
/// Represents information for a guild.
/// </summary>
public class StickerInfo
{
internal StickerInfo(StickerInfoAuditLogModel model)
{
Name = model.Name;
Tags = model.Tags;
Description = model.Description;
}
/// <summary>
/// Gets the name of the sticker. <see langword="null" /> if the value was not updated in this entry.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets tags of the sticker. <see langword="null" /> if the value was not updated in this entry.
/// </summary>
public string Tags { get; set; }
/// <summary>
/// Gets the description of the sticker. <see langword="null" /> if the value was not updated in this entry.
/// </summary>
public string Description { get; set; }
}

View File

@@ -0,0 +1,35 @@
using Discord.API.AuditLogs;
using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog;
namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a sticker update.
/// </summary>
public class StickerUpdatedAuditLogData : IAuditLogData
{
internal StickerUpdatedAuditLogData(StickerInfo before, StickerInfo after)
{
Before = before;
After = after;
}
internal static StickerUpdatedAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log = null)
{
var changes = entry.Changes;
var (before, after) = AuditLogHelper.CreateAuditLogEntityInfo<StickerInfoAuditLogModel>(changes, discord);
return new StickerUpdatedAuditLogData(new(before), new (after));
}
/// <summary>
/// Gets the sticker information before the changes.
/// </summary>
public StickerInfo Before { get; }
/// <summary>
/// Gets the sticker information after the changes.
/// </summary>
public StickerInfo After { get; }
}

View File

@@ -1,57 +1,44 @@
using Discord.API.AuditLogs;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a thread creation.
/// </summary>
public class ThreadCreateAuditLogData : IAuditLogData
{ {
/// <summary> private ThreadCreateAuditLogData(IThreadChannel thread, ulong id, ThreadInfoAuditLogModel model)
/// Contains a piece of audit log data related to a thread creation.
/// </summary>
public class ThreadCreateAuditLogData : IAuditLogData
{
private ThreadCreateAuditLogData(IThreadChannel thread, ulong id, string name, ThreadType type, bool archived,
ThreadArchiveDuration autoArchiveDuration, bool locked, int? rateLimit)
{ {
Thread = thread; Thread = thread;
ThreadId = id; ThreadId = id;
ThreadName = name;
ThreadType = type; ThreadName = model.Name;
IsArchived = archived; IsArchived = model.IsArchived!.Value;
AutoArchiveDuration = autoArchiveDuration; AutoArchiveDuration = model.ArchiveDuration!.Value;
IsLocked = locked; IsLocked = model.IsLocked!.Value;
SlowModeInterval = rateLimit; SlowModeInterval = model.SlowModeInterval;
AppliedTags = model.AppliedTags;
Flags = model.ChannelFlags;
ThreadType = model.Type;
} }
internal static ThreadCreateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static ThreadCreateAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var changes = entry.Changes; var changes = entry.Changes;
var id = entry.TargetId.Value; var (_, data) = AuditLogHelper.CreateAuditLogEntityInfo<ThreadInfoAuditLogModel>(changes, discord);
var nameModel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name"); var threadInfo = log.Threads.FirstOrDefault(x => x.Id == entry.TargetId!.Value);
var typeModel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "type");
var archivedModel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "archived");
var autoArchiveDurationModel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "auto_archive_duration");
var lockedModel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "locked");
var rateLimitPerUserModel = changes.FirstOrDefault(x => x.ChangedProperty == "rate_limit_per_user");
var name = nameModel.NewValue.ToObject<string>(discord.ApiClient.Serializer);
var type = typeModel.NewValue.ToObject<ThreadType>(discord.ApiClient.Serializer);
var archived = archivedModel.NewValue.ToObject<bool>(discord.ApiClient.Serializer);
var autoArchiveDuration = autoArchiveDurationModel.NewValue.ToObject<ThreadArchiveDuration>(discord.ApiClient.Serializer);
var locked = lockedModel.NewValue.ToObject<bool>(discord.ApiClient.Serializer);
var rateLimit = rateLimitPerUserModel?.NewValue?.ToObject<int>(discord.ApiClient.Serializer);
var threadInfo = log.Threads.FirstOrDefault(x => x.Id == id);
var threadChannel = threadInfo == null ? null : RestThreadChannel.Create(discord, (IGuild)null, threadInfo); var threadChannel = threadInfo == null ? null : RestThreadChannel.Create(discord, (IGuild)null, threadInfo);
return new ThreadCreateAuditLogData(threadChannel, id, name, type, archived, autoArchiveDuration, locked, rateLimit); return new ThreadCreateAuditLogData(threadChannel, entry.TargetId!.Value, data);
} }
// Doc Note: Corresponds to the *current* data
/// <summary> /// <summary>
/// Gets the thread that was created if it still exists. /// Gets the thread that was created if it still exists.
/// </summary> /// </summary>
@@ -59,6 +46,7 @@ namespace Discord.Rest
/// A thread object representing the thread that was created if it still exists, otherwise returns <c>null</c>. /// A thread object representing the thread that was created if it still exists, otherwise returns <c>null</c>.
/// </returns> /// </returns>
public IThreadChannel Thread { get; } public IThreadChannel Thread { get; }
/// <summary> /// <summary>
/// Gets the snowflake ID of the thread. /// Gets the snowflake ID of the thread.
/// </summary> /// </summary>
@@ -66,6 +54,7 @@ namespace Discord.Rest
/// A <see cref="ulong"/> representing the snowflake identifier for the thread. /// A <see cref="ulong"/> representing the snowflake identifier for the thread.
/// </returns> /// </returns>
public ulong ThreadId { get; } public ulong ThreadId { get; }
/// <summary> /// <summary>
/// Gets the name of the thread. /// Gets the name of the thread.
/// </summary> /// </summary>
@@ -73,6 +62,7 @@ namespace Discord.Rest
/// A string containing the name of the thread. /// A string containing the name of the thread.
/// </returns> /// </returns>
public string ThreadName { get; } public string ThreadName { get; }
/// <summary> /// <summary>
/// Gets the type of the thread. /// Gets the type of the thread.
/// </summary> /// </summary>
@@ -80,6 +70,7 @@ namespace Discord.Rest
/// The type of thread. /// The type of thread.
/// </returns> /// </returns>
public ThreadType ThreadType { get; } public ThreadType ThreadType { get; }
/// <summary> /// <summary>
/// Gets the value that indicates whether the thread is archived. /// Gets the value that indicates whether the thread is archived.
/// </summary> /// </summary>
@@ -87,6 +78,7 @@ namespace Discord.Rest
/// <c>true</c> if this thread has the Archived flag enabled; otherwise <c>false</c>. /// <c>true</c> if this thread has the Archived flag enabled; otherwise <c>false</c>.
/// </returns> /// </returns>
public bool IsArchived { get; } public bool IsArchived { get; }
/// <summary> /// <summary>
/// Gets the auto archive duration of the thread. /// Gets the auto archive duration of the thread.
/// </summary> /// </summary>
@@ -94,6 +86,7 @@ namespace Discord.Rest
/// The thread auto archive duration of the thread. /// The thread auto archive duration of the thread.
/// </returns> /// </returns>
public ThreadArchiveDuration AutoArchiveDuration { get; } public ThreadArchiveDuration AutoArchiveDuration { get; }
/// <summary> /// <summary>
/// Gets the value that indicates whether the thread is locked. /// Gets the value that indicates whether the thread is locked.
/// </summary> /// </summary>
@@ -101,6 +94,7 @@ namespace Discord.Rest
/// <c>true</c> if this thread has the Locked flag enabled; otherwise <c>false</c>. /// <c>true</c> if this thread has the Locked flag enabled; otherwise <c>false</c>.
/// </returns> /// </returns>
public bool IsLocked { get; } public bool IsLocked { get; }
/// <summary> /// <summary>
/// Gets the slow-mode delay of the thread. /// Gets the slow-mode delay of the thread.
/// </summary> /// </summary>
@@ -110,5 +104,20 @@ namespace Discord.Rest
/// <c>null</c> if this is not mentioned in this entry. /// <c>null</c> if this is not mentioned in this entry.
/// </returns> /// </returns>
public int? SlowModeInterval { get; } public int? SlowModeInterval { get; }
}
/// <summary>
/// Gets the applied tags of this thread.
/// </summary>
/// <remarks>
/// <see langword="null"/> if the property was not updated.
/// </remarks>
public IReadOnlyCollection<ulong> AppliedTags { get; }
/// <summary>
/// Gets the flags of the thread channel.
/// </summary>
/// <remarks>
/// <see langword="null"/> if the property was not updated.
/// </remarks>
public ChannelFlags? Flags { get; }
} }

View File

@@ -1,50 +1,36 @@
using System.Linq; using Discord.API.AuditLogs;
using System.Collections.Generic;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a thread deletion.
/// </summary>
public class ThreadDeleteAuditLogData : IAuditLogData
{ {
/// <summary> private ThreadDeleteAuditLogData(ulong id, ThreadInfoAuditLogModel model)
/// Contains a piece of audit log data related to a thread deletion.
/// </summary>
public class ThreadDeleteAuditLogData : IAuditLogData
{
private ThreadDeleteAuditLogData(ulong id, string name, ThreadType type, bool archived,
ThreadArchiveDuration autoArchiveDuration, bool locked, int? rateLimit)
{ {
ThreadId = id; ThreadId = id;
ThreadName = name;
ThreadType = type; ThreadName = model.Name;
IsArchived = archived; IsArchived = model.IsArchived!.Value;
AutoArchiveDuration = autoArchiveDuration; AutoArchiveDuration = model.ArchiveDuration!.Value;
IsLocked = locked; IsLocked = model.IsLocked!.Value;
SlowModeInterval = rateLimit; SlowModeInterval = model.SlowModeInterval;
AppliedTags = model.AppliedTags;
Flags = model.ChannelFlags;
ThreadType = model.Type;
} }
internal static ThreadDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static ThreadDeleteAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var changes = entry.Changes; var changes = entry.Changes;
var id = entry.TargetId.Value; var (data, _) = AuditLogHelper.CreateAuditLogEntityInfo<ThreadInfoAuditLogModel>(changes, discord);
var thread = log.Threads.FirstOrDefault(x => x.Id == id);
var nameModel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name"); return new ThreadDeleteAuditLogData(entry.TargetId!.Value, data);
var typeModel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "type");
var archivedModel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "archived");
var autoArchiveDurationModel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "auto_archive_duration");
var lockedModel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "locked");
var rateLimitPerUserModel = changes.FirstOrDefault(x => x.ChangedProperty == "rate_limit_per_user");
var name = nameModel.OldValue.ToObject<string>(discord.ApiClient.Serializer);
var type = typeModel.OldValue.ToObject<ThreadType>(discord.ApiClient.Serializer);
var archived = archivedModel.OldValue.ToObject<bool>(discord.ApiClient.Serializer);
var autoArchiveDuration = autoArchiveDurationModel.OldValue.ToObject<ThreadArchiveDuration>(discord.ApiClient.Serializer);
var locked = lockedModel.OldValue.ToObject<bool>(discord.ApiClient.Serializer);
var rateLimit = rateLimitPerUserModel?.NewValue?.ToObject<int>(discord.ApiClient.Serializer);
return new ThreadDeleteAuditLogData(id, name, type, archived, autoArchiveDuration, locked, rateLimit);
} }
/// <summary> /// <summary>
@@ -52,15 +38,19 @@ namespace Discord.Rest
/// </summary> /// </summary>
/// <returns> /// <returns>
/// A <see cref="ulong"/> representing the snowflake identifier for the deleted thread. /// A <see cref="ulong"/> representing the snowflake identifier for the deleted thread.
///
/// </returns> /// </returns>
public ulong ThreadId { get; } public ulong ThreadId { get; }
/// <summary> /// <summary>
/// Gets the name of the deleted thread. /// Gets the name of the deleted thread.
/// </summary> /// </summary>
/// <returns> /// <returns>
/// A string containing the name of the deleted thread. /// A string containing the name of the deleted thread.
///
/// </returns> /// </returns>
public string ThreadName { get; } public string ThreadName { get; }
/// <summary> /// <summary>
/// Gets the type of the deleted thread. /// Gets the type of the deleted thread.
/// </summary> /// </summary>
@@ -68,6 +58,7 @@ namespace Discord.Rest
/// The type of thread that was deleted. /// The type of thread that was deleted.
/// </returns> /// </returns>
public ThreadType ThreadType { get; } public ThreadType ThreadType { get; }
/// <summary> /// <summary>
/// Gets the value that indicates whether the deleted thread was archived. /// Gets the value that indicates whether the deleted thread was archived.
/// </summary> /// </summary>
@@ -75,6 +66,7 @@ namespace Discord.Rest
/// <c>true</c> if this thread had the Archived flag enabled; otherwise <c>false</c>. /// <c>true</c> if this thread had the Archived flag enabled; otherwise <c>false</c>.
/// </returns> /// </returns>
public bool IsArchived { get; } public bool IsArchived { get; }
/// <summary> /// <summary>
/// Gets the thread auto archive duration of the deleted thread. /// Gets the thread auto archive duration of the deleted thread.
/// </summary> /// </summary>
@@ -82,6 +74,7 @@ namespace Discord.Rest
/// The thread auto archive duration of the thread that was deleted. /// The thread auto archive duration of the thread that was deleted.
/// </returns> /// </returns>
public ThreadArchiveDuration AutoArchiveDuration { get; } public ThreadArchiveDuration AutoArchiveDuration { get; }
/// <summary> /// <summary>
/// Gets the value that indicates whether the deleted thread was locked. /// Gets the value that indicates whether the deleted thread was locked.
/// </summary> /// </summary>
@@ -89,6 +82,7 @@ namespace Discord.Rest
/// <c>true</c> if this thread had the Locked flag enabled; otherwise <c>false</c>. /// <c>true</c> if this thread had the Locked flag enabled; otherwise <c>false</c>.
/// </returns> /// </returns>
public bool IsLocked { get; } public bool IsLocked { get; }
/// <summary> /// <summary>
/// Gets the slow-mode delay of the deleted thread. /// Gets the slow-mode delay of the deleted thread.
/// </summary> /// </summary>
@@ -98,5 +92,20 @@ namespace Discord.Rest
/// <c>null</c> if this is not mentioned in this entry. /// <c>null</c> if this is not mentioned in this entry.
/// </returns> /// </returns>
public int? SlowModeInterval { get; } public int? SlowModeInterval { get; }
}
/// <summary>
/// Gets the applied tags of this thread.
/// </summary>
/// <remarks>
/// <see langword="null"/> if this is not mentioned in this entry.
/// </remarks>
public IReadOnlyCollection<ulong> AppliedTags { get; }
/// <summary>
/// Gets the flags of the thread channel.
/// </summary>
/// <remarks>
/// <see langword="null"/> if this is not mentioned in this entry.
/// </remarks>
public ChannelFlags? Flags { get; }
} }

View File

@@ -1,39 +1,84 @@
namespace Discord.Rest using Discord.API.AuditLogs;
using System;
using System.Collections.Generic;
namespace Discord.Rest;
/// <summary>
/// Represents information for a thread.
/// </summary>
public class ThreadInfo
{ {
/// <summary>
/// Represents information for a thread.
/// </summary>
public class ThreadInfo
{
/// <summary> /// <summary>
/// Gets the name of the thread. /// Gets the name of the thread.
/// </summary> /// </summary>
public string Name { get; } public string Name { get; }
/// <summary> /// <summary>
/// Gets the value that indicates whether the thread is archived. /// Gets the value that indicates whether the thread is archived.
/// </summary> /// </summary>
public bool IsArchived { get; } /// <remarks>
/// <see langword="null"/> if the property was not updated.
/// </remarks>
public bool? IsArchived { get; }
/// <summary> /// <summary>
/// Gets the auto archive duration of thread. /// Gets the auto archive duration of thread.
/// </summary> /// </summary>
public ThreadArchiveDuration AutoArchiveDuration { get; } /// <remarks>
/// <see langword="null"/> if the property was not updated.
/// </remarks>
public ThreadArchiveDuration? AutoArchiveDuration { get; }
/// <summary> /// <summary>
/// Gets the value that indicates whether the thread is locked. /// Gets the value that indicates whether the thread is locked.
/// </summary> /// </summary>
public bool IsLocked { get; } /// <remarks>
/// <see langword="null"/> if the property was not updated.
/// </remarks>
public bool? IsLocked { get; }
/// <summary> /// <summary>
/// Gets the slow-mode delay of the ´thread. /// Gets the slow-mode delay of the thread.
/// </summary> /// </summary>
/// <remarks>
/// <see langword="null"/> if the property was not updated.
/// </remarks>
public int? SlowModeInterval { get; } public int? SlowModeInterval { get; }
internal ThreadInfo(string name, bool archived, ThreadArchiveDuration autoArchiveDuration, bool locked, int? rateLimit) /// <summary>
/// Gets the applied tags of this thread.
/// </summary>
/// <remarks>
/// <see langword="null"/> if the property was not updated.
/// </remarks>
public IReadOnlyCollection<ulong> AppliedTags { get; }
/// <summary>
/// Gets the flags of the thread channel.
/// </summary>
/// <remarks>
/// <see langword="null"/> if the property was not updated.
/// </remarks>
public ChannelFlags? Flags { get; }
/// <summary>
/// Gets the type of the thread.
/// </summary>
/// <remarks>
/// <see langword="null"/> if the property was not updated.
/// </remarks>
public ThreadType Type { get; }
internal ThreadInfo(ThreadInfoAuditLogModel model)
{ {
Name = name; Name = model.Name;
IsArchived = archived; IsArchived = model.IsArchived;
AutoArchiveDuration = autoArchiveDuration; AutoArchiveDuration = model.ArchiveDuration;
IsLocked = locked; IsLocked = model.IsLocked;
SlowModeInterval = rateLimit; SlowModeInterval = model.SlowModeInterval;
} AppliedTags = model.AppliedTags;
Flags = model.ChannelFlags;
Type = model.Type;
} }
} }

View File

@@ -1,14 +1,16 @@
using Discord.API.AuditLogs;
using System.Linq; using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a thread update.
/// </summary>
public class ThreadUpdateAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to a thread update.
/// </summary>
public class ThreadUpdateAuditLogData : IAuditLogData
{
private ThreadUpdateAuditLogData(IThreadChannel thread, ThreadType type, ThreadInfo before, ThreadInfo after) private ThreadUpdateAuditLogData(IThreadChannel thread, ThreadType type, ThreadInfo before, ThreadInfo after)
{ {
Thread = thread; Thread = thread;
@@ -17,40 +19,16 @@ namespace Discord.Rest
After = after; After = after;
} }
internal static ThreadUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static ThreadUpdateAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var changes = entry.Changes; var changes = entry.Changes;
var id = entry.TargetId.Value; var (before, after) = AuditLogHelper.CreateAuditLogEntityInfo<ThreadInfoAuditLogModel>(changes, discord);
var nameModel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name"); var threadInfo = log.Threads.FirstOrDefault(x => x.Id == entry.TargetId!.Value);
var typeModel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "type");
var archivedModel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "archived");
var autoArchiveDurationModel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "auto_archive_duration");
var lockedModel = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "locked");
var rateLimitPerUserModel = changes.FirstOrDefault(x => x.ChangedProperty == "rate_limit_per_user");
var type = typeModel.OldValue.ToObject<ThreadType>(discord.ApiClient.Serializer);
var oldName = nameModel.OldValue.ToObject<string>(discord.ApiClient.Serializer);
var oldArchived = archivedModel.OldValue.ToObject<bool>(discord.ApiClient.Serializer);
var oldAutoArchiveDuration = autoArchiveDurationModel.OldValue.ToObject<ThreadArchiveDuration>(discord.ApiClient.Serializer);
var oldLocked = lockedModel.OldValue.ToObject<bool>(discord.ApiClient.Serializer);
var oldRateLimit = rateLimitPerUserModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer);
var before = new ThreadInfo(oldName, oldArchived, oldAutoArchiveDuration, oldLocked, oldRateLimit);
var newName = nameModel.NewValue.ToObject<string>(discord.ApiClient.Serializer);
var newArchived = archivedModel.NewValue.ToObject<bool>(discord.ApiClient.Serializer);
var newAutoArchiveDuration = autoArchiveDurationModel.NewValue.ToObject<ThreadArchiveDuration>(discord.ApiClient.Serializer);
var newLocked = lockedModel.NewValue.ToObject<bool>(discord.ApiClient.Serializer);
var newRateLimit = rateLimitPerUserModel?.NewValue?.ToObject<int>(discord.ApiClient.Serializer);
var after = new ThreadInfo(newName, newArchived, newAutoArchiveDuration, newLocked, newRateLimit);
var threadInfo = log.Threads.FirstOrDefault(x => x.Id == id);
var threadChannel = threadInfo == null ? null : RestThreadChannel.Create(discord, (IGuild)null, threadInfo); var threadChannel = threadInfo == null ? null : RestThreadChannel.Create(discord, (IGuild)null, threadInfo);
return new ThreadUpdateAuditLogData(threadChannel, type, before, after); return new ThreadUpdateAuditLogData(threadChannel, before.Type, new(before), new (after));
} }
// Doc Note: Corresponds to the *current* data // Doc Note: Corresponds to the *current* data
@@ -62,6 +40,7 @@ namespace Discord.Rest
/// A thread object representing the thread that was created if it still exists, otherwise returns <c>null</c>. /// A thread object representing the thread that was created if it still exists, otherwise returns <c>null</c>.
/// </returns> /// </returns>
public IThreadChannel Thread { get; } public IThreadChannel Thread { get; }
/// <summary> /// <summary>
/// Gets the type of the thread. /// Gets the type of the thread.
/// </summary> /// </summary>
@@ -69,6 +48,7 @@ namespace Discord.Rest
/// The type of thread. /// The type of thread.
/// </returns> /// </returns>
public ThreadType ThreadType { get; } public ThreadType ThreadType { get; }
/// <summary> /// <summary>
/// Gets the thread information before the changes. /// Gets the thread information before the changes.
/// </summary> /// </summary>
@@ -76,6 +56,7 @@ namespace Discord.Rest
/// A thread information object representing the thread before the changes were made. /// A thread information object representing the thread before the changes were made.
/// </returns> /// </returns>
public ThreadInfo Before { get; } public ThreadInfo Before { get; }
/// <summary> /// <summary>
/// Gets the thread information after the changes. /// Gets the thread information after the changes.
/// </summary> /// </summary>
@@ -83,5 +64,4 @@ namespace Discord.Rest
/// A thread information object representing the thread after the changes were made. /// A thread information object representing the thread after the changes were made.
/// </returns> /// </returns>
public ThreadInfo After { get; } public ThreadInfo After { get; }
}
} }

View File

@@ -2,19 +2,19 @@ using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to an unban.
/// </summary>
public class UnbanAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to an unban.
/// </summary>
public class UnbanAuditLogData : IAuditLogData
{
private UnbanAuditLogData(IUser user) private UnbanAuditLogData(IUser user)
{ {
Target = user; Target = user;
} }
internal static UnbanAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static UnbanAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log = null)
{ {
var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId); var userInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId);
return new UnbanAuditLogData((userInfo != null) ? RestUser.Create(discord, userInfo) : null); return new UnbanAuditLogData((userInfo != null) ? RestUser.Create(discord, userInfo) : null);
@@ -27,5 +27,4 @@ namespace Discord.Rest
/// A user object representing the user that was unbanned. /// A user object representing the user that was unbanned.
/// </returns> /// </returns>
public IUser Target { get; } public IUser Target { get; }
}
} }

View File

@@ -1,39 +1,36 @@
using Discord.API.AuditLogs;
using System.Linq; using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a webhook creation.
/// </summary>
public class WebhookCreateAuditLogData : IAuditLogData
{ {
/// <summary> private WebhookCreateAuditLogData(IWebhook webhook, ulong webhookId, WebhookInfoAuditLogModel model)
/// Contains a piece of audit log data related to a webhook creation.
/// </summary>
public class WebhookCreateAuditLogData : IAuditLogData
{
private WebhookCreateAuditLogData(IWebhook webhook, ulong webhookId, WebhookType type, string name, ulong channelId)
{ {
Webhook = webhook; Webhook = webhook;
WebhookId = webhookId; WebhookId = webhookId;
Name = name; Name = model.Name;
Type = type; Type = model.Type!.Value;
ChannelId = channelId; ChannelId = model.ChannelId!.Value;
Avatar = model.AvatarHash;
} }
internal static WebhookCreateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static WebhookCreateAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var changes = entry.Changes; var changes = entry.Changes;
var channelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "channel_id"); var (_, data) = AuditLogHelper.CreateAuditLogEntityInfo<WebhookInfoAuditLogModel>(changes, discord);
var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type");
var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name");
var channelId = channelIdModel.NewValue.ToObject<ulong>(discord.ApiClient.Serializer);
var type = typeModel.NewValue.ToObject<WebhookType>(discord.ApiClient.Serializer);
var name = nameModel.NewValue.ToObject<string>(discord.ApiClient.Serializer);
var webhookInfo = log.Webhooks?.FirstOrDefault(x => x.Id == entry.TargetId); var webhookInfo = log.Webhooks?.FirstOrDefault(x => x.Id == entry.TargetId);
var webhook = webhookInfo == null ? null : RestWebhook.Create(discord, (IGuild)null, webhookInfo); var webhook = webhookInfo == null ? null : RestWebhook.Create(discord, (IGuild)null, webhookInfo);
return new WebhookCreateAuditLogData(webhook, entry.TargetId.Value, type, name, channelId); return new WebhookCreateAuditLogData(webhook, entry.TargetId!.Value, data);
} }
// Doc Note: Corresponds to the *current* data // Doc Note: Corresponds to the *current* data
@@ -79,5 +76,12 @@ namespace Discord.Rest
/// to. /// to.
/// </returns> /// </returns>
public ulong ChannelId { get; } public ulong ChannelId { get; }
}
/// <summary>
/// Gets the hash value of the webhook's avatar.
/// </summary>
/// <returns>
/// A string containing the hash of the webhook's avatar.
/// </returns>
public string Avatar { get; }
} }

View File

@@ -1,38 +1,31 @@
using System.Linq; using Discord.API.AuditLogs;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a webhook deletion.
/// </summary>
public class WebhookDeleteAuditLogData : IAuditLogData
{ {
/// <summary> private WebhookDeleteAuditLogData(ulong id, WebhookInfoAuditLogModel model)
/// Contains a piece of audit log data related to a webhook deletion.
/// </summary>
public class WebhookDeleteAuditLogData : IAuditLogData
{
private WebhookDeleteAuditLogData(ulong id, ulong channel, WebhookType type, string name, string avatar)
{ {
WebhookId = id; WebhookId = id;
ChannelId = channel; ChannelId = model.ChannelId!.Value;
Name = name; Name = model.Name;
Type = type; Type = model.Type!.Value;
Avatar = avatar; Avatar = model.AvatarHash;
} }
internal static WebhookDeleteAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static WebhookDeleteAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var changes = entry.Changes; var changes = entry.Changes;
var channelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "channel_id"); var (data, _) = AuditLogHelper.CreateAuditLogEntityInfo<WebhookInfoAuditLogModel>(changes, discord);
var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type");
var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name");
var avatarHashModel = changes.FirstOrDefault(x => x.ChangedProperty == "avatar_hash");
var channelId = channelIdModel.OldValue.ToObject<ulong>(discord.ApiClient.Serializer); return new WebhookDeleteAuditLogData(entry.TargetId!.Value, data);
var type = typeModel.OldValue.ToObject<WebhookType>(discord.ApiClient.Serializer);
var name = nameModel.OldValue.ToObject<string>(discord.ApiClient.Serializer);
var avatarHash = avatarHashModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer);
return new WebhookDeleteAuditLogData(entry.TargetId.Value, channelId, type, name, avatarHash);
} }
/// <summary> /// <summary>
@@ -42,6 +35,7 @@ namespace Discord.Rest
/// A <see cref="ulong"/> representing the snowflake identifier of the webhook that was deleted. /// A <see cref="ulong"/> representing the snowflake identifier of the webhook that was deleted.
/// </returns> /// </returns>
public ulong WebhookId { get; } public ulong WebhookId { get; }
/// <summary> /// <summary>
/// Gets the ID of the channel that the webhook could send to. /// Gets the ID of the channel that the webhook could send to.
/// </summary> /// </summary>
@@ -50,6 +44,7 @@ namespace Discord.Rest
/// to. /// to.
/// </returns> /// </returns>
public ulong ChannelId { get; } public ulong ChannelId { get; }
/// <summary> /// <summary>
/// Gets the type of the webhook that was deleted. /// Gets the type of the webhook that was deleted.
/// </summary> /// </summary>
@@ -57,6 +52,7 @@ namespace Discord.Rest
/// The type of webhook that was deleted. /// The type of webhook that was deleted.
/// </returns> /// </returns>
public WebhookType Type { get; } public WebhookType Type { get; }
/// <summary> /// <summary>
/// Gets the name of the webhook that was deleted. /// Gets the name of the webhook that was deleted.
/// </summary> /// </summary>
@@ -64,6 +60,7 @@ namespace Discord.Rest
/// A string containing the name of the webhook that was deleted. /// A string containing the name of the webhook that was deleted.
/// </returns> /// </returns>
public string Name { get; } public string Name { get; }
/// <summary> /// <summary>
/// Gets the hash value of the webhook's avatar. /// Gets the hash value of the webhook's avatar.
/// </summary> /// </summary>
@@ -71,5 +68,4 @@ namespace Discord.Rest
/// A string containing the hash of the webhook's avatar. /// A string containing the hash of the webhook's avatar.
/// </returns> /// </returns>
public string Avatar { get; } public string Avatar { get; }
}
} }

View File

@@ -1,15 +1,17 @@
namespace Discord.Rest using Model = Discord.API.AuditLogs.WebhookInfoAuditLogModel;
namespace Discord.Rest;
/// <summary>
/// Represents information for a webhook.
/// </summary>
public struct WebhookInfo
{ {
/// <summary> internal WebhookInfo(Model model)
/// Represents information for a webhook.
/// </summary>
public struct WebhookInfo
{ {
internal WebhookInfo(string name, ulong? channelId, string avatar) Name = model.Name;
{ ChannelId = model.ChannelId;
Name = name; Avatar = model.AvatarHash;
ChannelId = channelId;
Avatar = avatar;
} }
/// <summary> /// <summary>
@@ -19,6 +21,7 @@ namespace Discord.Rest
/// A string containing the name of this webhook. /// A string containing the name of this webhook.
/// </returns> /// </returns>
public string Name { get; } public string Name { get; }
/// <summary> /// <summary>
/// Gets the ID of the channel that this webhook sends to. /// Gets the ID of the channel that this webhook sends to.
/// </summary> /// </summary>
@@ -27,6 +30,7 @@ namespace Discord.Rest
/// to. /// to.
/// </returns> /// </returns>
public ulong? ChannelId { get; } public ulong? ChannelId { get; }
/// <summary> /// <summary>
/// Gets the hash value of this webhook's avatar. /// Gets the hash value of this webhook's avatar.
/// </summary> /// </summary>
@@ -34,5 +38,4 @@ namespace Discord.Rest
/// A string containing the hash of this webhook's avatar. /// A string containing the hash of this webhook's avatar.
/// </returns> /// </returns>
public string Avatar { get; } public string Avatar { get; }
}
} }

View File

@@ -1,14 +1,15 @@
using Discord.API.AuditLogs;
using System.Linq; using System.Linq;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
namespace Discord.Rest namespace Discord.Rest;
/// <summary>
/// Contains a piece of audit log data related to a webhook update.
/// </summary>
public class WebhookUpdateAuditLogData : IAuditLogData
{ {
/// <summary>
/// Contains a piece of audit log data related to a webhook update.
/// </summary>
public class WebhookUpdateAuditLogData : IAuditLogData
{
private WebhookUpdateAuditLogData(IWebhook webhook, WebhookInfo before, WebhookInfo after) private WebhookUpdateAuditLogData(IWebhook webhook, WebhookInfo before, WebhookInfo after)
{ {
Webhook = webhook; Webhook = webhook;
@@ -16,28 +17,16 @@ namespace Discord.Rest
After = after; After = after;
} }
internal static WebhookUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static WebhookUpdateAuditLogData Create(BaseDiscordClient discord, EntryModel entry, Model log)
{ {
var changes = entry.Changes; var changes = entry.Changes;
var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); var (before, after) = AuditLogHelper.CreateAuditLogEntityInfo<WebhookInfoAuditLogModel>(changes, discord);
var channelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "channel_id");
var avatarHashModel = changes.FirstOrDefault(x => x.ChangedProperty == "avatar_hash");
var oldName = nameModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer);
var oldChannelId = channelIdModel?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer);
var oldAvatar = avatarHashModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer);
var before = new WebhookInfo(oldName, oldChannelId, oldAvatar);
var newName = nameModel?.NewValue?.ToObject<string>(discord.ApiClient.Serializer);
var newChannelId = channelIdModel?.NewValue?.ToObject<ulong>(discord.ApiClient.Serializer);
var newAvatar = avatarHashModel?.NewValue?.ToObject<string>(discord.ApiClient.Serializer);
var after = new WebhookInfo(newName, newChannelId, newAvatar);
var webhookInfo = log.Webhooks?.FirstOrDefault(x => x.Id == entry.TargetId); var webhookInfo = log.Webhooks?.FirstOrDefault(x => x.Id == entry.TargetId);
var webhook = webhookInfo != null ? RestWebhook.Create(discord, (IGuild)null, webhookInfo) : null; var webhook = webhookInfo != null ? RestWebhook.Create(discord, (IGuild)null, webhookInfo) : null;
return new WebhookUpdateAuditLogData(webhook, before, after); return new WebhookUpdateAuditLogData(webhook, new(before), new(after));
} }
/// <summary> /// <summary>
@@ -63,5 +52,4 @@ namespace Discord.Rest
/// A webhook information object representing the webhook after the changes were made. /// A webhook information object representing the webhook after the changes were made.
/// </returns> /// </returns>
public WebhookInfo After { get; } public WebhookInfo After { get; }
}
} }

View File

@@ -0,0 +1,14 @@
using System;
namespace Discord.Rest;
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
internal class JsonFieldAttribute : Attribute
{
public string FieldName { get; }
public JsonFieldAttribute(string fieldName)
{
FieldName = fieldName;
}
}

View File

@@ -14,7 +14,7 @@ namespace Discord.Rest
: base(discord, model.Id) : base(discord, model.Id)
{ {
Action = model.Action; Action = model.Action;
Data = AuditLogHelper.CreateData(discord, fullLog, model); Data = AuditLogHelper.CreateData(discord, model, fullLog);
User = user; User = user;
Reason = model.Reason; Reason = model.Reason;
} }

View File

@@ -75,7 +75,7 @@ namespace Discord.Rest
DefaultSortOrder = model.DefaultSortOrder.GetValueOrDefault(); DefaultSortOrder = model.DefaultSortOrder.GetValueOrDefault();
Tags = model.ForumTags.GetValueOrDefault(Array.Empty<API.ForumTags>()).Select( Tags = model.ForumTags.GetValueOrDefault(Array.Empty<API.ForumTag>()).Select(
x => new ForumTag(x.Id, x.Name, x.EmojiId.GetValueOrDefault(null), x.EmojiName.GetValueOrDefault(), x.Moderated) x => new ForumTag(x.Id, x.Name, x.EmojiId.GetValueOrDefault(null), x.EmojiName.GetValueOrDefault(), x.Moderated)
).ToImmutableArray(); ).ToImmutableArray();

View File

@@ -4,7 +4,5 @@ namespace Discord.API.Gateway
{ {
internal class ApplicationCommandCreatedUpdatedEvent : ApplicationCommand internal class ApplicationCommandCreatedUpdatedEvent : ApplicationCommand
{ {
[JsonProperty("guild_id")]
public Optional<ulong> GuildId { get; set; }
} }
} }

View File

@@ -0,0 +1,9 @@
using Newtonsoft.Json;
namespace Discord.API.Gateway;
internal class AuditLogCreatedEvent : AuditLogEntry
{
[JsonProperty("guild_id")]
public ulong GuildId { get; set; }
}

View File

@@ -893,6 +893,21 @@ namespace Discord.WebSocket
#endregion #endregion
#region Audit Logs
/// <summary>
/// Fired when a guild audit log entry is created.
/// </summary>
public event Func<SocketAuditLogEntry, SocketGuild, Task> AuditLogCreated
{
add { _auditLogCreated.Add(value); }
remove { _auditLogCreated.Remove(value); }
}
internal readonly AsyncEvent<Func<SocketAuditLogEntry, SocketGuild, Task>> _auditLogCreated = new();
#endregion
#region AutoModeration #region AutoModeration
/// <summary> /// <summary>

Some files were not shown because too many files have changed in this diff Show More