From a02d699518cc64fc973e3c89fea07f62d7cbab81 Mon Sep 17 00:00:00 2001 From: Paulo Date: Sun, 30 May 2021 23:45:40 -0300 Subject: [PATCH] Audit log models --- Directory.Build.targets | 3 +- Discord.Net.sln | 34 +++++-- src/Models/AuditLog/AuditEntryInfo.cs | 58 +++++++++++ src/Models/AuditLog/AuditEntryInfoType.cs | 17 ++++ src/Models/AuditLog/AuditLog.cs | 34 +++++++ src/Models/AuditLog/AuditLogChange.cs | 28 ++++++ src/Models/AuditLog/AuditLogEntry.cs | 52 ++++++++++ src/Models/AuditLog/AuditLogEvent.cs | 153 ++++++++++++++++++++++++++++++ src/Models/Discord.Net.Models.csproj | 4 + src/Models/Optional.cs | 98 +++++++++++++++++++ src/Models/Snowflake.cs | 76 +++++++++++++++ 11 files changed, 548 insertions(+), 9 deletions(-) create mode 100644 src/Models/AuditLog/AuditEntryInfo.cs create mode 100644 src/Models/AuditLog/AuditEntryInfoType.cs create mode 100644 src/Models/AuditLog/AuditLog.cs create mode 100644 src/Models/AuditLog/AuditLogChange.cs create mode 100644 src/Models/AuditLog/AuditLogEntry.cs create mode 100644 src/Models/AuditLog/AuditLogEvent.cs create mode 100644 src/Models/Optional.cs create mode 100644 src/Models/Snowflake.cs diff --git a/Directory.Build.targets b/Directory.Build.targets index f1715a487..50fad7775 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -29,7 +29,8 @@ - + + diff --git a/Discord.Net.sln b/Discord.Net.sln index 3b0ea5400..8635159e4 100644 --- a/Discord.Net.sln +++ b/Discord.Net.sln @@ -1,19 +1,21 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26124.0 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31229.75 MinimumVisualStudioVersion = 15.0.26124.0 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{CD5CFA4B-143E-4495-8BFD-AF419226CBE5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Gateway", "src\Gateway\Discord.Net.Gateway.csproj", "{DAF502E3-CFE6-4243-8049-9A6157F42111}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Gateway", "src\Gateway\Discord.Net.Gateway.csproj", "{DAF502E3-CFE6-4243-8049-9A6157F42111}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{6D7B7A29-83FE-44F2-85E1-7D44B061EA27}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PingPong", "samples\PingPong\PingPong.csproj", "{54A6E396-5186-4D79-893B-6EFD1CF658CB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PingPong", "samples\PingPong\PingPong.csproj", "{54A6E396-5186-4D79-893B-6EFD1CF658CB}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{A47FC28E-1835-46C3-AFD5-7C048A43C157}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Gateway.UnitTests", "test\Gateway\Discord.Net.Gateway.UnitTests.csproj", "{7EC53EB6-6C15-4FD7-9B83-95F96025C14D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Gateway.UnitTests", "test\Gateway\Discord.Net.Gateway.UnitTests.csproj", "{7EC53EB6-6C15-4FD7-9B83-95F96025C14D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discord.Net.Models", "src\Models\Discord.Net.Models.csproj", "{564A2E82-CE92-42F6-9D4E-8CC09C5CDF17}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -24,9 +26,6 @@ Global Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {DAF502E3-CFE6-4243-8049-9A6157F42111}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DAF502E3-CFE6-4243-8049-9A6157F42111}.Debug|Any CPU.Build.0 = Debug|Any CPU @@ -64,10 +63,29 @@ Global {7EC53EB6-6C15-4FD7-9B83-95F96025C14D}.Release|x64.Build.0 = Release|Any CPU {7EC53EB6-6C15-4FD7-9B83-95F96025C14D}.Release|x86.ActiveCfg = Release|Any CPU {7EC53EB6-6C15-4FD7-9B83-95F96025C14D}.Release|x86.Build.0 = Release|Any CPU + {564A2E82-CE92-42F6-9D4E-8CC09C5CDF17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {564A2E82-CE92-42F6-9D4E-8CC09C5CDF17}.Debug|Any CPU.Build.0 = Debug|Any CPU + {564A2E82-CE92-42F6-9D4E-8CC09C5CDF17}.Debug|x64.ActiveCfg = Debug|Any CPU + {564A2E82-CE92-42F6-9D4E-8CC09C5CDF17}.Debug|x64.Build.0 = Debug|Any CPU + {564A2E82-CE92-42F6-9D4E-8CC09C5CDF17}.Debug|x86.ActiveCfg = Debug|Any CPU + {564A2E82-CE92-42F6-9D4E-8CC09C5CDF17}.Debug|x86.Build.0 = Debug|Any CPU + {564A2E82-CE92-42F6-9D4E-8CC09C5CDF17}.Release|Any CPU.ActiveCfg = Release|Any CPU + {564A2E82-CE92-42F6-9D4E-8CC09C5CDF17}.Release|Any CPU.Build.0 = Release|Any CPU + {564A2E82-CE92-42F6-9D4E-8CC09C5CDF17}.Release|x64.ActiveCfg = Release|Any CPU + {564A2E82-CE92-42F6-9D4E-8CC09C5CDF17}.Release|x64.Build.0 = Release|Any CPU + {564A2E82-CE92-42F6-9D4E-8CC09C5CDF17}.Release|x86.ActiveCfg = Release|Any CPU + {564A2E82-CE92-42F6-9D4E-8CC09C5CDF17}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {DAF502E3-CFE6-4243-8049-9A6157F42111} = {CD5CFA4B-143E-4495-8BFD-AF419226CBE5} {54A6E396-5186-4D79-893B-6EFD1CF658CB} = {6D7B7A29-83FE-44F2-85E1-7D44B061EA27} {7EC53EB6-6C15-4FD7-9B83-95F96025C14D} = {A47FC28E-1835-46C3-AFD5-7C048A43C157} + {564A2E82-CE92-42F6-9D4E-8CC09C5CDF17} = {CD5CFA4B-143E-4495-8BFD-AF419226CBE5} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {36B0BFC9-AF79-4D25-89D4-2EE3C961612B} EndGlobalSection EndGlobal diff --git a/src/Models/AuditLog/AuditEntryInfo.cs b/src/Models/AuditLog/AuditEntryInfo.cs new file mode 100644 index 000000000..cea53bfeb --- /dev/null +++ b/src/Models/AuditLog/AuditEntryInfo.cs @@ -0,0 +1,58 @@ +using System.Text.Json.Serialization; + +namespace Discord.Net.Models +{ + /// + /// Represents an audit entry info object. + /// + public record AuditEntryInfo + { + /// + /// Number of days after which inactive members were kicked. + /// + [JsonPropertyName("delete_member_days")] + public Optional DeleteMemberDays { get; init; } // actually sent as Optional + + /// + /// Number of members removed by the prune. + /// + [JsonPropertyName("members_removed")] + public Optional MembersRemoved { get; init; } // actually sent as Optional + + /// + /// Channel in which the entities were targeted. + /// + [JsonPropertyName("channel_id")] + public Optional ChannelId { get; init; } + + /// + /// Id of the message that was targeted. + /// + [JsonPropertyName("message_id")] + public Optional MessageId { get; init; } + + /// + /// Number of entities that were targeted. + /// + [JsonPropertyName("count")] + public Optional Count { get; init; } // actually sent as Optional + + /// + /// Id of the overwritten entity. + /// + [JsonPropertyName("id")] + public Optional Id { get; init; } + + /// + /// Type of overwritten entity - "0" for "role" or "1" for "member". + /// + [JsonPropertyName("type")] + public Optional Type { get; init; } // actually sent as Optional + + /// + /// Name of the role if type is "0" (not present if type is "1"). + /// + [JsonPropertyName("role_name")] + public Optional RoleName { get; init; } + } +} diff --git a/src/Models/AuditLog/AuditEntryInfoType.cs b/src/Models/AuditLog/AuditEntryInfoType.cs new file mode 100644 index 000000000..e92f94314 --- /dev/null +++ b/src/Models/AuditLog/AuditEntryInfoType.cs @@ -0,0 +1,17 @@ +namespace Discord.Net.Models +{ + /// + /// Represents type of the overwritten entity for an audit entry info. + /// + public enum AuditEntryInfoType + { + /// + /// The type of the overwritten entity is a role. + /// + Role = 0, + /// + /// The type of the overwritten entity is a member. + /// + Member = 1, + } +} diff --git a/src/Models/AuditLog/AuditLog.cs b/src/Models/AuditLog/AuditLog.cs new file mode 100644 index 000000000..54fd26bad --- /dev/null +++ b/src/Models/AuditLog/AuditLog.cs @@ -0,0 +1,34 @@ +using System.Text.Json.Serialization; + +namespace Discord.Net.Models +{ + /// + /// Represents a discord audit log object. + /// + public record AuditLog + { + /// + /// Gets an array of s. + /// + /*[JsonPropertyName("webhooks")] + public Optional Webhooks { get; init; }*/ //TODO Add Webhook + + /// + /// Gets an array of s. + /// + /*[JsonPropertyName("users")] + public Optional Users { get; init; }*/ //TODO Add User + + /// + /// Gets an array of s. + /// + [JsonPropertyName("audit_log_entries")] + public Optional AuditLogEntries { get; init; } + + /// + /// Gets an array of s. + /// + /*[JsonPropertyName("integrations")] + public Optional Integrations { get; init; }*/ //TODO Add Integration + } +} diff --git a/src/Models/AuditLog/AuditLogChange.cs b/src/Models/AuditLog/AuditLogChange.cs new file mode 100644 index 000000000..32317aa1f --- /dev/null +++ b/src/Models/AuditLog/AuditLogChange.cs @@ -0,0 +1,28 @@ +using System.Text.Json.Serialization; + +namespace Discord.Net.Models +{ + /// + /// Represents an audit log change object. + /// + public record AuditLogChange + { + /// + /// New value of the key. + /// + [JsonPropertyName("new_value")] + public Optional NewValue { get; init; } + + /// + /// Old value of the key. + /// + [JsonPropertyName("old_value")] + public Optional OldValue { get; init; } + + /// + /// Name of the audit log change key. + /// + [JsonPropertyName("key")] + public string? Key { get; init; } + } +} diff --git a/src/Models/AuditLog/AuditLogEntry.cs b/src/Models/AuditLog/AuditLogEntry.cs new file mode 100644 index 000000000..bc0a83923 --- /dev/null +++ b/src/Models/AuditLog/AuditLogEntry.cs @@ -0,0 +1,52 @@ +using System.Text.Json.Serialization; + +namespace Discord.Net.Models +{ + /// + /// Represents an audit log entry object. + /// + public record AuditLogEntry + { + /// + /// Id of the affected entity (webhook, user, role, etc.). + /// + [JsonPropertyName("target_id")] + public Snowflake? TargetId { get; init; } + + /// + /// Changes made to the . + /// + [JsonPropertyName("changes")] + public Optional Changes { get; init; } + + /// + /// The user who made the changes. + /// + [JsonPropertyName("user_id")] + public Snowflake? UserId { get; init; } + + /// + /// Id of the entry. + /// + [JsonPropertyName("id")] + public Snowflake Id { get; init; } + + /// + /// Type of action that occurred. + /// + [JsonPropertyName("action_type")] + public AuditLogEvent ActionType { get; init; } + + /// + /// Additional info for certain action types. + /// + [JsonPropertyName("options")] + public Optional Options { get; init; } + + /// + /// The reason for the change (0-512 characters). + /// + [JsonPropertyName("reason")] + public Optional Reason { get; init; } + } +} diff --git a/src/Models/AuditLog/AuditLogEvent.cs b/src/Models/AuditLog/AuditLogEvent.cs new file mode 100644 index 000000000..f3dc94c59 --- /dev/null +++ b/src/Models/AuditLog/AuditLogEvent.cs @@ -0,0 +1,153 @@ +namespace Discord.Net.Models +{ + /// + /// Specifies the type of audit log event. + /// + public enum AuditLogEvent : int + { + /// + /// Default value of this type. + /// + None = 0, + /// + /// The guild was updated. + /// + GuildUpdate = 1, + /// + /// A channel was created. + /// + ChannelCreate = 10, + /// + /// A channel was updated. + /// + ChannelUpdate = 11, + /// + /// A channel was deleted. + /// + ChannelDelete = 12, + /// + /// A channel overwrite was created. + /// + ChannelOverwriteCreate = 13, + /// + /// A channel overwrite was updated. + /// + ChannelOverwriteUpdate = 14, + /// + /// A channel overwrite was deleted. + /// + ChannelOverwriteDelete = 15, + /// + /// A guild member was kicked. + /// + MemberKick = 20, + /// + /// A guild member was pruned. + /// + MemberPrune = 21, + /// + /// A guild member was banned. + /// + MemberBanAdd = 22, + /// + /// A guild member was unbanned. + /// + MemberBanRemove = 23, + /// + /// A guild member was updated. + /// + MemberUpdate = 24, + /// + /// A guild role was updated. + /// + MemberRoleUpdate = 25, + /// + /// A guild member was moved. + /// + MemberMove = 26, + /// + /// A guild member was disconnected. + /// + MemberDisconnect = 27, + /// + /// A bot was added. + /// + BotAdd = 28, + /// + /// A role was created. + /// + RoleCreate = 30, + /// + /// A role was updated. + /// + RoleUpdate = 31, + /// + /// A role was deleted. + /// + RoleDelete = 32, + /// + /// An invite was created. + /// + InviteCreate = 40, + /// + /// An invite was updated. + /// + InviteUpdate = 41, + /// + /// An invite was deleted. + /// + InviteDelete = 42, + /// + /// A webhook was created. + /// + WebhookCreate = 50, + /// + /// A webhook was updated. + /// + WebhookUpdate = 51, + /// + /// A webhook was deleted. + /// + WebhookDelete = 52, + /// + /// An emoji was created. + /// + EmojiCreate = 60, + /// + /// An emoji was updated. + /// + EmojiUpdate = 61, + /// + /// An emoji was deleted. + /// + EmojiDelete = 62, + /// + /// A message was deleted. + /// + MessageDelete = 72, + /// + /// Message were deleted in bulk. + /// + MessageBulkDelete = 73, + /// + /// A message was pinned. + /// + MessagePin = 74, + /// + /// A message was unpinned. + /// + MessageUnpin = 75, + /// + /// An integration was created. + /// + IntegrationCreate = 80, + /// + /// An integration was updated. + /// + IntegrationUpdate = 81, + /// + /// An integration was deleted. + /// + IntegrationDelete = 82, + } +} diff --git a/src/Models/Discord.Net.Models.csproj b/src/Models/Discord.Net.Models.csproj index 2f01002cb..b01c93952 100644 --- a/src/Models/Discord.Net.Models.csproj +++ b/src/Models/Discord.Net.Models.csproj @@ -8,5 +8,9 @@ Shared models between the Discord REST API and Gateway. + + + + diff --git a/src/Models/Optional.cs b/src/Models/Optional.cs new file mode 100644 index 000000000..ba31cb061 --- /dev/null +++ b/src/Models/Optional.cs @@ -0,0 +1,98 @@ +using System; + +namespace Discord.Net +{ + /// + /// Container to keep a type that might not be present. + /// + /// Inner type + public struct Optional + { + private readonly T _value; + + /// + /// Gets the inner value of this if present. + /// + /// The value inside this . + /// This has no inner value. + public T Value => !IsSpecified ? throw new InvalidOperationException("This property has no value set.") : _value; + + /// + /// Gets if this has an inner value. + /// + /// A boolean that determines if this has a . + public bool IsSpecified { get; } + + private Optional(T value) + { + _value = value; + IsSpecified = true; + } + + /// + /// Creates a new unspecified . + /// + /// An unspecified . + public static Optional Create() + => default; + + /// + /// Creates a new with the specified . + /// + /// Value that will be specified for this . + /// A specified with the provided value inside. + public static Optional Create(T value) + => new(value); + + /// + /// Gets the or their value. + /// + /// The value inside this or their value. + public T GetValueOrDefault() + => _value; + + /// + /// Gets the or the default value provided. + /// + /// The value inside this or default value provided. + public T GetValueOrDefault(T defaultValue) + => IsSpecified ? _value : defaultValue; + + /// + public override bool Equals(object? other) + { + if (!IsSpecified) + return other == null; + if (other == null || _value == null) + return false; + return _value.Equals(other); + } + + /// + public override int GetHashCode() + => IsSpecified ? _value?.GetHashCode() ?? default : default; + + /// + /// Returns the inner value ToString value or this type fully qualified name. + /// + /// The inner value string value or this type fully qualified name. + public override string? ToString() + => IsSpecified ? _value?.ToString() : default; + + /// + /// Creates a new with the specified . + /// + /// Value to convert + /// A new with the specified + public static implicit operator Optional(T value) + => new(value); + + /// + /// Gets the inner value. + /// + /// Value to convert + /// The inner value + public static explicit operator T(Optional value) + => value.Value; + } +} diff --git a/src/Models/Snowflake.cs b/src/Models/Snowflake.cs new file mode 100644 index 000000000..08bb4d6a9 --- /dev/null +++ b/src/Models/Snowflake.cs @@ -0,0 +1,76 @@ +using System; + +namespace Discord.Net +{ + /// + /// Represents a discord snowflake. + /// + public struct Snowflake + { + private const ulong DiscordEpoch = 1420070400000UL; + + /// + /// Gets the raw value of this snowflake. + /// + /// A with the rae value. + public ulong RawValue { get; } + + /// + /// Creates a based on the provided. + /// + /// Raw value of the snowflake. + public Snowflake(ulong value) + { + RawValue = value; + } + + /// + /// Creates a based on the provided. + /// + /// DateTimeOffset of this snowflake. + public Snowflake(DateTimeOffset dateTimeOffset) + { + RawValue = ((ulong)dateTimeOffset.ToUniversalTime().ToUnixTimeMilliseconds() - DiscordEpoch) << 22; + } + + /// + /// Creates a based on the provided. + /// + /// DateTime of this snowflake. + public Snowflake(DateTime dateTime) + : this(new DateTimeOffset(dateTime)) { } + + /// + /// Converts this to a . + /// + /// A of this snowflake. + public DateTimeOffset ToDateTimeOffset() => DateTimeOffset.FromUnixTimeMilliseconds((long)((RawValue >> 22) + DiscordEpoch)); + + /// + /// Converts this to a . + /// + /// A of this snowflake. + public DateTimeOffset ToDateTime() => ToDateTimeOffset().UtcDateTime; + + /// + /// Converts this to a . + /// + /// Value that will be converted + /// A with the raw value. + public static implicit operator ulong(Snowflake snowflake) => snowflake.RawValue; + + /// + /// Converts this to a . + /// + /// Value that will be converted + /// A with as the raw value. + public static implicit operator Snowflake(ulong value) => new Snowflake(value); + + /// + /// Returns the raw value as . + /// + /// A that is the raw value. + public override string ToString() + => RawValue.ToString(); + } +}