Browse Source

Merge branch 'dev' into patches/linq-optimization

pull/1114/head
Christopher F GitHub 7 years ago
parent
commit
500f9f875d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 442 additions and 171 deletions
  1. +1
    -6
      README.md
  2. +6
    -1
      src/Discord.Net.Commands/Attributes/CommandAttribute.cs
  3. +1
    -1
      src/Discord.Net.Commands/Builders/ModuleBuilder.cs
  4. +13
    -11
      src/Discord.Net.Commands/Builders/ParameterBuilder.cs
  5. +2
    -2
      src/Discord.Net.Commands/Extensions/MessageExtensions.cs
  6. +4
    -1
      src/Discord.Net.Commands/Results/ParseResult.cs
  7. +4
    -1
      src/Discord.Net.Commands/Results/PreconditionGroupResult.cs
  8. +4
    -1
      src/Discord.Net.Commands/Results/PreconditionResult.cs
  9. +4
    -1
      src/Discord.Net.Commands/Results/SearchResult.cs
  10. +2
    -0
      src/Discord.Net.Commands/Results/TypeReaderResult.cs
  11. +2
    -2
      src/Discord.Net.Core/Entities/AuditLogs/IAuditLogEntry.cs
  12. +2
    -1
      src/Discord.Net.Core/Entities/Permissions/ChannelPermission.cs
  13. +9
    -2
      src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs
  14. +1
    -0
      src/Discord.Net.Core/Entities/Permissions/GuildPermission.cs
  15. +9
    -2
      src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs
  16. +11
    -0
      src/Discord.Net.Core/Entities/Roles/Color.cs
  17. +11
    -0
      src/Discord.Net.Core/Extensions/MessageExtensions.cs
  18. +46
    -0
      src/Discord.Net.Core/Utils/TokenUtils.cs
  19. +1
    -1
      src/Discord.Net.Rest/API/Common/AuditLogOptions.cs
  20. +17
    -2
      src/Discord.Net.Rest/BaseDiscordClient.cs
  21. +12
    -9
      src/Discord.Net.Rest/DiscordRestApiClient.cs
  22. +3
    -5
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelCreateAuditLogData.cs
  23. +3
    -3
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelDeleteAuditLogData.cs
  24. +8
    -8
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelUpdateAuditLogData.cs
  25. +1
    -1
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteCreateAuditLogData.cs
  26. +1
    -1
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteDeleteAuditLogData.cs
  27. +2
    -2
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteUpdateAuditLogData.cs
  28. +20
    -20
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/GuildUpdateAuditLogData.cs
  29. +7
    -7
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteCreateAuditLogData.cs
  30. +7
    -7
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteDeleteAuditLogData.cs
  31. +10
    -10
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteUpdateAuditLogData.cs
  32. +18
    -0
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberInfo.cs
  33. +1
    -1
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberRoleAuditLogData.cs
  34. +23
    -9
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberUpdateAuditLogData.cs
  35. +3
    -5
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteCreateAuditLogData.cs
  36. +5
    -7
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteDeleteAuditLogData.cs
  37. +6
    -6
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteUpdateAuditLogData.cs
  38. +5
    -5
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleCreateAuditLogData.cs
  39. +5
    -5
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleDeleteAuditLogData.cs
  40. +10
    -10
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleUpdateAuditLogData.cs
  41. +3
    -3
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookCreateAuditLogData.cs
  42. +4
    -4
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookDeleteAuditLogData.cs
  43. +7
    -7
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookUpdateAuditLogData.cs
  44. +4
    -1
      src/Discord.Net.Rest/Entities/AuditLogs/RestAuditLogEntry.cs
  45. +124
    -0
      test/Discord.Net.Tests/Tests.TokenUtils.cs

+ 1
- 6
README.md View File

@@ -16,13 +16,9 @@ Our stable builds available from NuGet through the Discord.Net metapackage:
The individual components may also be installed from NuGet: The individual components may also be installed from NuGet:
- [Discord.Net.Commands](https://www.nuget.org/packages/Discord.Net.Commands/) - [Discord.Net.Commands](https://www.nuget.org/packages/Discord.Net.Commands/)
- [Discord.Net.Rest](https://www.nuget.org/packages/Discord.Net.Rest/) - [Discord.Net.Rest](https://www.nuget.org/packages/Discord.Net.Rest/)
- [Discord.Net.Rpc](https://www.nuget.org/packages/Discord.Net.Rpc/)
- [Discord.Net.WebSocket](https://www.nuget.org/packages/Discord.Net.WebSocket/) - [Discord.Net.WebSocket](https://www.nuget.org/packages/Discord.Net.WebSocket/)
- [Discord.Net.Webhook](https://www.nuget.org/packages/Discord.Net.Webhook/) - [Discord.Net.Webhook](https://www.nuget.org/packages/Discord.Net.Webhook/)


The following provider is available for platforms not supporting .NET Standard 1.3:
- [Discord.Net.Providers.WS4Net](https://www.nuget.org/packages/Discord.Net.Providers.WS4Net/)

### Unstable (MyGet) ### Unstable (MyGet)
Nightly builds are available through our MyGet feed (`https://www.myget.org/F/discord-net/api/v3/index.json`). Nightly builds are available through our MyGet feed (`https://www.myget.org/F/discord-net/api/v3/index.json`).


@@ -41,5 +37,4 @@ The .NET Core workload must be selected during Visual Studio installation.
## Known Issues ## Known Issues


### WebSockets (Win7 and earlier) ### WebSockets (Win7 and earlier)
.NET Core 1.1 does not support WebSockets on Win7 and earlier. It's recommended to use the Discord.Net.Providers.WS4Net package until this is resolved.
Track the issue [here](https://github.com/dotnet/corefx/issues/9503).
.NET Core 1.1 does not support WebSockets on Win7 and earlier. This issue has been fixed since the release of .NET Core 2.1. It is recommended to target .NET Core 2.1 or above for your project if you wish to run your bot on legacy platforms; alternatively, you may choose to install the [Discord.Net.Providers.WS4Net](https://www.nuget.org/packages/Discord.Net.Providers.WS4Net/) package.

+ 6
- 1
src/Discord.Net.Commands/Attributes/CommandAttribute.cs View File

@@ -7,7 +7,7 @@ namespace Discord.Commands
{ {
public string Text { get; } public string Text { get; }
public RunMode RunMode { get; set; } = RunMode.Default; public RunMode RunMode { get; set; } = RunMode.Default;
public bool? IgnoreExtraArgs { get; set; }
public bool? IgnoreExtraArgs { get; }


public CommandAttribute() public CommandAttribute()
{ {
@@ -17,5 +17,10 @@ namespace Discord.Commands
{ {
Text = text; Text = text;
} }
public CommandAttribute(string text, bool ignoreExtraArgs)
{
Text = text;
IgnoreExtraArgs = ignoreExtraArgs;
}
} }
} }

+ 1
- 1
src/Discord.Net.Commands/Builders/ModuleBuilder.cs View File

@@ -120,7 +120,7 @@ namespace Discord.Commands.Builders
if (Name == null) if (Name == null)
Name = _aliases[0]; Name = _aliases[0];


if (TypeInfo != null)
if (TypeInfo != null && !TypeInfo.IsAbstract)
{ {
var moduleInstance = ReflectionUtils.CreateObject<IModuleBase>(TypeInfo, service, services); var moduleInstance = ReflectionUtils.CreateObject<IModuleBase>(TypeInfo, service, services);
moduleInstance.OnModuleBuilding(service, this); moduleInstance.OnModuleBuilding(service, this);


+ 13
- 11
src/Discord.Net.Commands/Builders/ParameterBuilder.cs View File

@@ -45,14 +45,7 @@ namespace Discord.Commands.Builders


internal void SetType(Type type) internal void SetType(Type type)
{ {
var readers = Command.Module.Service.GetTypeReaders(type);
if (readers != null)
TypeReader = readers.FirstOrDefault().Value;
else
TypeReader = Command.Module.Service.GetDefaultTypeReader(type);

if (TypeReader == null)
throw new InvalidOperationException($"{type} does not have a TypeReader registered for it. Parameter: {Name} in {Command.PrimaryAlias}");
TypeReader = GetReader(type);


if (type.GetTypeInfo().IsValueType) if (type.GetTypeInfo().IsValueType)
DefaultValue = Activator.CreateInstance(type); DefaultValue = Activator.CreateInstance(type);
@@ -60,7 +53,16 @@ namespace Discord.Commands.Builders
type = ParameterType.GetElementType(); type = ParameterType.GetElementType();
ParameterType = type; ParameterType = type;
} }

private TypeReader GetReader(Type type)
{
var readers = Command.Module.Service.GetTypeReaders(type);
if (readers != null)
return readers.FirstOrDefault().Value;
else
return Command.Module.Service.GetDefaultTypeReader(type);
}

public ParameterBuilder WithSummary(string summary) public ParameterBuilder WithSummary(string summary)
{ {
Summary = summary; Summary = summary;
@@ -100,10 +102,10 @@ namespace Discord.Commands.Builders


internal ParameterInfo Build(CommandInfo info) internal ParameterInfo Build(CommandInfo info)
{ {
if (TypeReader == null)
if ((TypeReader ?? (TypeReader = GetReader(ParameterType))) == null)
throw new InvalidOperationException($"No type reader found for type {ParameterType.Name}, one must be specified"); throw new InvalidOperationException($"No type reader found for type {ParameterType.Name}, one must be specified");


return new ParameterInfo(this, info, Command.Module.Service); return new ParameterInfo(this, info, Command.Module.Service);
} }
} }
}
}

+ 2
- 2
src/Discord.Net.Commands/Extensions/MessageExtensions.cs View File

@@ -1,4 +1,4 @@
using System;
using System;


namespace Discord.Commands namespace Discord.Commands
{ {
@@ -43,4 +43,4 @@ namespace Discord.Commands
return false; return false;
} }
} }
}
}

+ 4
- 1
src/Discord.Net.Commands/Results/ParseResult.cs View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;


namespace Discord.Commands namespace Discord.Commands
@@ -53,6 +54,8 @@ namespace Discord.Commands


public static ParseResult FromError(CommandError error, string reason) public static ParseResult FromError(CommandError error, string reason)
=> new ParseResult(null, null, error, reason); => new ParseResult(null, null, error, reason);
public static ParseResult FromError(Exception ex)
=> FromError(CommandError.Exception, ex.Message);
public static ParseResult FromError(IResult result) public static ParseResult FromError(IResult result)
=> new ParseResult(null, null, result.Error, result.ErrorReason); => new ParseResult(null, null, result.Error, result.ErrorReason);




+ 4
- 1
src/Discord.Net.Commands/Results/PreconditionGroupResult.cs View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;


namespace Discord.Commands namespace Discord.Commands
@@ -18,6 +19,8 @@ namespace Discord.Commands
=> new PreconditionGroupResult(null, null, null); => new PreconditionGroupResult(null, null, null);
public static PreconditionGroupResult FromError(string reason, ICollection<PreconditionResult> preconditions) public static PreconditionGroupResult FromError(string reason, ICollection<PreconditionResult> preconditions)
=> new PreconditionGroupResult(CommandError.UnmetPrecondition, reason, preconditions); => new PreconditionGroupResult(CommandError.UnmetPrecondition, reason, preconditions);
public static new PreconditionGroupResult FromError(Exception ex)
=> new PreconditionGroupResult(CommandError.Exception, ex.Message, null);
public static new PreconditionGroupResult FromError(IResult result) //needed? public static new PreconditionGroupResult FromError(IResult result) //needed?
=> new PreconditionGroupResult(result.Error, result.ErrorReason, null); => new PreconditionGroupResult(result.Error, result.ErrorReason, null);




+ 4
- 1
src/Discord.Net.Commands/Results/PreconditionResult.cs View File

@@ -1,4 +1,5 @@
using System.Diagnostics;
using System;
using System.Diagnostics;


namespace Discord.Commands namespace Discord.Commands
{ {
@@ -20,6 +21,8 @@ namespace Discord.Commands
=> new PreconditionResult(null, null); => new PreconditionResult(null, null);
public static PreconditionResult FromError(string reason) public static PreconditionResult FromError(string reason)
=> new PreconditionResult(CommandError.UnmetPrecondition, reason); => new PreconditionResult(CommandError.UnmetPrecondition, reason);
public static PreconditionResult FromError(Exception ex)
=> new PreconditionResult(CommandError.Exception, ex.Message);
public static PreconditionResult FromError(IResult result) public static PreconditionResult FromError(IResult result)
=> new PreconditionResult(result.Error, result.ErrorReason); => new PreconditionResult(result.Error, result.ErrorReason);




+ 4
- 1
src/Discord.Net.Commands/Results/SearchResult.cs View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;


namespace Discord.Commands namespace Discord.Commands
@@ -26,6 +27,8 @@ namespace Discord.Commands
=> new SearchResult(text, commands, null, null); => new SearchResult(text, commands, null, null);
public static SearchResult FromError(CommandError error, string reason) public static SearchResult FromError(CommandError error, string reason)
=> new SearchResult(null, null, error, reason); => new SearchResult(null, null, error, reason);
public static SearchResult FromError(Exception ex)
=> FromError(CommandError.Exception, ex.Message);
public static SearchResult FromError(IResult result) public static SearchResult FromError(IResult result)
=> new SearchResult(null, null, result.Error, result.ErrorReason); => new SearchResult(null, null, result.Error, result.ErrorReason);




+ 2
- 0
src/Discord.Net.Commands/Results/TypeReaderResult.cs View File

@@ -50,6 +50,8 @@ namespace Discord.Commands
=> new TypeReaderResult(values, null, null); => new TypeReaderResult(values, null, null);
public static TypeReaderResult FromError(CommandError error, string reason) public static TypeReaderResult FromError(CommandError error, string reason)
=> new TypeReaderResult(null, error, reason); => new TypeReaderResult(null, error, reason);
public static TypeReaderResult FromError(Exception ex)
=> FromError(CommandError.Exception, ex.Message);
public static TypeReaderResult FromError(IResult result) public static TypeReaderResult FromError(IResult result)
=> new TypeReaderResult(null, result.Error, result.ErrorReason); => new TypeReaderResult(null, result.Error, result.ErrorReason);




+ 2
- 2
src/Discord.Net.Core/Entities/AuditLogs/IAuditLogEntry.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@@ -9,7 +9,7 @@ namespace Discord
/// <summary> /// <summary>
/// Represents an entry in an audit log /// Represents an entry in an audit log
/// </summary> /// </summary>
public interface IAuditLogEntry : IEntity<ulong>
public interface IAuditLogEntry : ISnowflakeEntity
{ {
/// <summary> /// <summary>
/// The action which occured to create this entry /// The action which occured to create this entry


+ 2
- 1
src/Discord.Net.Core/Entities/Permissions/ChannelPermission.cs View File

@@ -1,4 +1,4 @@
using System;
using System;


namespace Discord namespace Discord
{ {
@@ -30,6 +30,7 @@ namespace Discord
DeafenMembers = 0x00_80_00_00, DeafenMembers = 0x00_80_00_00,
MoveMembers = 0x01_00_00_00, MoveMembers = 0x01_00_00_00,
UseVAD = 0x02_00_00_00, UseVAD = 0x02_00_00_00,
PrioritySpeaker = 0x00_00_01_00,


// More General // More General
ManageRoles = 0x10_00_00_00, ManageRoles = 0x10_00_00_00,


+ 9
- 2
src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs View File

@@ -12,7 +12,7 @@ namespace Discord
/// <summary> Gets a ChannelPermissions that grants all permissions for text channels. </summary> /// <summary> Gets a ChannelPermissions that grants all permissions for text channels. </summary>
public static readonly ChannelPermissions Text = new ChannelPermissions(0b01100_0000000_1111111110001_010001); public static readonly ChannelPermissions Text = new ChannelPermissions(0b01100_0000000_1111111110001_010001);
/// <summary> Gets a ChannelPermissions that grants all permissions for voice channels. </summary> /// <summary> Gets a ChannelPermissions that grants all permissions for voice channels. </summary>
public static readonly ChannelPermissions Voice = new ChannelPermissions(0b00100_1111110_0000000010000_010001);
public static readonly ChannelPermissions Voice = new ChannelPermissions(0b00100_1111110_0000000010100_010001);
/// <summary> Gets a ChannelPermissions that grants all permissions for category channels. </summary> /// <summary> Gets a ChannelPermissions that grants all permissions for category channels. </summary>
public static readonly ChannelPermissions Category = new ChannelPermissions(0b01100_1111110_1111111110001_010001); public static readonly ChannelPermissions Category = new ChannelPermissions(0b01100_1111110_1111111110001_010001);
/// <summary> Gets a ChannelPermissions that grants all permissions for direct message channels. </summary> /// <summary> Gets a ChannelPermissions that grants all permissions for direct message channels. </summary>
@@ -78,6 +78,8 @@ namespace Discord
public bool MoveMembers => Permissions.GetValue(RawValue, ChannelPermission.MoveMembers); public bool MoveMembers => Permissions.GetValue(RawValue, ChannelPermission.MoveMembers);
/// <summary> If True, a user may use voice-activity-detection rather than push-to-talk. </summary> /// <summary> If True, a user may use voice-activity-detection rather than push-to-talk. </summary>
public bool UseVAD => Permissions.GetValue(RawValue, ChannelPermission.UseVAD); public bool UseVAD => Permissions.GetValue(RawValue, ChannelPermission.UseVAD);
/// <summary> If True, a user may use priority speaker in a voice channel. </summary>
public bool PrioritySpeaker => Permissions.GetValue(RawValue, ChannelPermission.PrioritySpeaker);


/// <summary> If True, a user may adjust role permissions. This also implictly grants all other permissions. </summary> /// <summary> If True, a user may adjust role permissions. This also implictly grants all other permissions. </summary>
public bool ManageRoles => Permissions.GetValue(RawValue, ChannelPermission.ManageRoles); public bool ManageRoles => Permissions.GetValue(RawValue, ChannelPermission.ManageRoles);
@@ -106,6 +108,7 @@ namespace Discord
bool? deafenMembers = null, bool? deafenMembers = null,
bool? moveMembers = null, bool? moveMembers = null,
bool? useVoiceActivation = null, bool? useVoiceActivation = null,
bool? prioritySpeaker = null,
bool? manageRoles = null, bool? manageRoles = null,
bool? manageWebhooks = null) bool? manageWebhooks = null)
{ {
@@ -129,6 +132,7 @@ namespace Discord
Permissions.SetValue(ref value, deafenMembers, ChannelPermission.DeafenMembers); Permissions.SetValue(ref value, deafenMembers, ChannelPermission.DeafenMembers);
Permissions.SetValue(ref value, moveMembers, ChannelPermission.MoveMembers); Permissions.SetValue(ref value, moveMembers, ChannelPermission.MoveMembers);
Permissions.SetValue(ref value, useVoiceActivation, ChannelPermission.UseVAD); Permissions.SetValue(ref value, useVoiceActivation, ChannelPermission.UseVAD);
Permissions.SetValue(ref value, prioritySpeaker, ChannelPermission.PrioritySpeaker);
Permissions.SetValue(ref value, manageRoles, ChannelPermission.ManageRoles); Permissions.SetValue(ref value, manageRoles, ChannelPermission.ManageRoles);
Permissions.SetValue(ref value, manageWebhooks, ChannelPermission.ManageWebhooks); Permissions.SetValue(ref value, manageWebhooks, ChannelPermission.ManageWebhooks);


@@ -155,11 +159,12 @@ namespace Discord
bool deafenMembers = false, bool deafenMembers = false,
bool moveMembers = false, bool moveMembers = false,
bool useVoiceActivation = false, bool useVoiceActivation = false,
bool prioritySpeaker = false,
bool manageRoles = false, bool manageRoles = false,
bool manageWebhooks = false) bool manageWebhooks = false)
: this(0, createInstantInvite, manageChannel, addReactions, viewChannel, sendMessages, sendTTSMessages, manageMessages, : this(0, createInstantInvite, manageChannel, addReactions, viewChannel, sendMessages, sendTTSMessages, manageMessages,
embedLinks, attachFiles, readMessageHistory, mentionEveryone, useExternalEmojis, connect, embedLinks, attachFiles, readMessageHistory, mentionEveryone, useExternalEmojis, connect,
speak, muteMembers, deafenMembers, moveMembers, useVoiceActivation, manageRoles, manageWebhooks)
speak, muteMembers, deafenMembers, moveMembers, useVoiceActivation, prioritySpeaker, manageRoles, manageWebhooks)
{ } { }


/// <summary> Creates a new ChannelPermissions from this one, changing the provided non-null permissions. </summary> /// <summary> Creates a new ChannelPermissions from this one, changing the provided non-null permissions. </summary>
@@ -182,6 +187,7 @@ namespace Discord
bool? deafenMembers = null, bool? deafenMembers = null,
bool? moveMembers = null, bool? moveMembers = null,
bool? useVoiceActivation = null, bool? useVoiceActivation = null,
bool? prioritySpeaker = null,
bool? manageRoles = null, bool? manageRoles = null,
bool? manageWebhooks = null) bool? manageWebhooks = null)
=> new ChannelPermissions(RawValue, => new ChannelPermissions(RawValue,
@@ -203,6 +209,7 @@ namespace Discord
deafenMembers, deafenMembers,
moveMembers, moveMembers,
useVoiceActivation, useVoiceActivation,
prioritySpeaker,
manageRoles, manageRoles,
manageWebhooks); manageWebhooks);




+ 1
- 0
src/Discord.Net.Core/Entities/Permissions/GuildPermission.cs View File

@@ -35,6 +35,7 @@ namespace Discord
DeafenMembers = 0x00_80_00_00, DeafenMembers = 0x00_80_00_00,
MoveMembers = 0x01_00_00_00, MoveMembers = 0x01_00_00_00,
UseVAD = 0x02_00_00_00, UseVAD = 0x02_00_00_00,
PrioritySpeaker = 0x00_00_01_00,


// General 2 // General 2
ChangeNickname = 0x04_00_00_00, ChangeNickname = 0x04_00_00_00,


+ 9
- 2
src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs View File

@@ -12,7 +12,7 @@ namespace Discord
/// <summary> Gets a GuildPermissions that grants all guild permissions for webhook users. </summary> /// <summary> Gets a GuildPermissions that grants all guild permissions for webhook users. </summary>
public static readonly GuildPermissions Webhook = new GuildPermissions(0b00000_0000000_0001101100000_000000); public static readonly GuildPermissions Webhook = new GuildPermissions(0b00000_0000000_0001101100000_000000);
/// <summary> Gets a GuildPermissions that grants all guild permissions. </summary> /// <summary> Gets a GuildPermissions that grants all guild permissions. </summary>
public static readonly GuildPermissions All = new GuildPermissions(0b11111_1111110_1111111110011_111111);
public static readonly GuildPermissions All = new GuildPermissions(0b11111_1111110_1111111110111_111111);


/// <summary> Gets a packed value representing all the permissions in this GuildPermissions. </summary> /// <summary> Gets a packed value representing all the permissions in this GuildPermissions. </summary>
public ulong RawValue { get; } public ulong RawValue { get; }
@@ -69,6 +69,8 @@ namespace Discord
public bool MoveMembers => Permissions.GetValue(RawValue, GuildPermission.MoveMembers); public bool MoveMembers => Permissions.GetValue(RawValue, GuildPermission.MoveMembers);
/// <summary> If True, a user may use voice-activity-detection rather than push-to-talk. </summary> /// <summary> If True, a user may use voice-activity-detection rather than push-to-talk. </summary>
public bool UseVAD => Permissions.GetValue(RawValue, GuildPermission.UseVAD); public bool UseVAD => Permissions.GetValue(RawValue, GuildPermission.UseVAD);
/// <summary> If True, a user may use priority speaker in a voice channel. </summary>
public bool PrioritySpeaker => Permissions.GetValue(RawValue, ChannelPermission.PrioritySpeaker);


/// <summary> If True, a user may change their own nickname. </summary> /// <summary> If True, a user may change their own nickname. </summary>
public bool ChangeNickname => Permissions.GetValue(RawValue, GuildPermission.ChangeNickname); public bool ChangeNickname => Permissions.GetValue(RawValue, GuildPermission.ChangeNickname);
@@ -108,6 +110,7 @@ namespace Discord
bool? deafenMembers = null, bool? deafenMembers = null,
bool? moveMembers = null, bool? moveMembers = null,
bool? useVoiceActivation = null, bool? useVoiceActivation = null,
bool? prioritySpeaker = null,
bool? changeNickname = null, bool? changeNickname = null,
bool? manageNicknames = null, bool? manageNicknames = null,
bool? manageRoles = null, bool? manageRoles = null,
@@ -139,6 +142,7 @@ namespace Discord
Permissions.SetValue(ref value, deafenMembers, GuildPermission.DeafenMembers); Permissions.SetValue(ref value, deafenMembers, GuildPermission.DeafenMembers);
Permissions.SetValue(ref value, moveMembers, GuildPermission.MoveMembers); Permissions.SetValue(ref value, moveMembers, GuildPermission.MoveMembers);
Permissions.SetValue(ref value, useVoiceActivation, GuildPermission.UseVAD); Permissions.SetValue(ref value, useVoiceActivation, GuildPermission.UseVAD);
Permissions.SetValue(ref value, prioritySpeaker, GuildPermission.PrioritySpeaker);
Permissions.SetValue(ref value, changeNickname, GuildPermission.ChangeNickname); Permissions.SetValue(ref value, changeNickname, GuildPermission.ChangeNickname);
Permissions.SetValue(ref value, manageNicknames, GuildPermission.ManageNicknames); Permissions.SetValue(ref value, manageNicknames, GuildPermission.ManageNicknames);
Permissions.SetValue(ref value, manageRoles, GuildPermission.ManageRoles); Permissions.SetValue(ref value, manageRoles, GuildPermission.ManageRoles);
@@ -173,6 +177,7 @@ namespace Discord
bool deafenMembers = false, bool deafenMembers = false,
bool moveMembers = false, bool moveMembers = false,
bool useVoiceActivation = false, bool useVoiceActivation = false,
bool prioritySpeaker = false,
bool changeNickname = false, bool changeNickname = false,
bool manageNicknames = false, bool manageNicknames = false,
bool manageRoles = false, bool manageRoles = false,
@@ -203,6 +208,7 @@ namespace Discord
deafenMembers: deafenMembers, deafenMembers: deafenMembers,
moveMembers: moveMembers, moveMembers: moveMembers,
useVoiceActivation: useVoiceActivation, useVoiceActivation: useVoiceActivation,
prioritySpeaker: prioritySpeaker,
changeNickname: changeNickname, changeNickname: changeNickname,
manageNicknames: manageNicknames, manageNicknames: manageNicknames,
manageWebhooks: manageWebhooks, manageWebhooks: manageWebhooks,
@@ -234,6 +240,7 @@ namespace Discord
bool? deafenMembers = null, bool? deafenMembers = null,
bool? moveMembers = null, bool? moveMembers = null,
bool? useVoiceActivation = null, bool? useVoiceActivation = null,
bool? prioritySpeaker = null,
bool? changeNickname = null, bool? changeNickname = null,
bool? manageNicknames = null, bool? manageNicknames = null,
bool? manageRoles = null, bool? manageRoles = null,
@@ -242,7 +249,7 @@ namespace Discord
=> new GuildPermissions(RawValue, createInstantInvite, kickMembers, banMembers, administrator, manageChannels, manageGuild, addReactions, => new GuildPermissions(RawValue, createInstantInvite, kickMembers, banMembers, administrator, manageChannels, manageGuild, addReactions,
viewAuditLog, viewChannel, sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles, viewAuditLog, viewChannel, sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles,
readMessageHistory, mentionEveryone, useExternalEmojis, connect, speak, muteMembers, deafenMembers, moveMembers, readMessageHistory, mentionEveryone, useExternalEmojis, connect, speak, muteMembers, deafenMembers, moveMembers,
useVoiceActivation, changeNickname, manageNicknames, manageRoles, manageWebhooks, manageEmojis);
useVoiceActivation, prioritySpeaker, changeNickname, manageNicknames, manageRoles, manageWebhooks, manageEmojis);


public bool Has(GuildPermission permission) => Permissions.GetValue(RawValue, permission); public bool Has(GuildPermission permission) => Permissions.GetValue(RawValue, permission);




+ 11
- 0
src/Discord.Net.Core/Entities/Roles/Color.cs View File

@@ -100,6 +100,17 @@ namespace Discord
(uint)(b * 255.0f); (uint)(b * 255.0f);
} }


public static bool operator ==(Color lhs, Color rhs)
=> lhs.RawValue == rhs.RawValue;

public static bool operator !=(Color lhs, Color rhs)
=> lhs.RawValue != rhs.RawValue;

public override bool Equals(object obj)
=> (obj is Color c && RawValue == c.RawValue);

public override int GetHashCode() => RawValue.GetHashCode();

#if NETSTANDARD2_0 || NET45 #if NETSTANDARD2_0 || NET45
public static implicit operator StandardColor(Color color) => public static implicit operator StandardColor(Color color) =>
StandardColor.FromArgb((int)color.RawValue); StandardColor.FromArgb((int)color.RawValue);


+ 11
- 0
src/Discord.Net.Core/Extensions/MessageExtensions.cs View File

@@ -0,0 +1,11 @@
namespace Discord
{
public static class MessageExtensions
{
public static string GetJumpUrl(this IMessage msg)
{
var channel = msg.Channel;
return $"https://discordapp.com/channels/{(channel is IDMChannel ? "@me" : $"{(channel as ITextChannel).GuildId}")}/{channel.Id}/{msg.Id}";
}
}
}

+ 46
- 0
src/Discord.Net.Core/Utils/TokenUtils.cs View File

@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord
{
public static class TokenUtils
{
/// <summary>
/// Checks the validity of the supplied token of a specific type.
/// </summary>
/// <param name="tokenType"> The type of token to validate. </param>
/// <param name="token"> The token value to validate. </param>
/// <exception cref="ArgumentNullException"> Thrown when the supplied token string is null, empty, or contains only whitespace.</exception>
/// <exception cref="ArgumentException"> Thrown when the supplied TokenType or token value is invalid. </exception>
public static void ValidateToken(TokenType tokenType, string token)
{
// A Null or WhiteSpace token of any type is invalid.
if (string.IsNullOrWhiteSpace(token))
throw new ArgumentNullException("A token cannot be null, empty, or contain only whitespace.", nameof(token));

switch (tokenType)
{
case TokenType.Webhook:
// no validation is performed on Webhook tokens
break;
case TokenType.Bearer:
// no validation is performed on Bearer tokens
break;
case TokenType.Bot:
// bot tokens are assumed to be at least 59 characters in length
// this value was determined by referencing examples in the discord documentation, and by comparing with
// pre-existing tokens
if (token.Length < 59)
throw new ArgumentException("A Bot token must be at least 59 characters in length.", nameof(token));
break;
default:
// All unrecognized TokenTypes (including User tokens) are considered to be invalid.
throw new ArgumentException("Unrecognized TokenType.", nameof(token));
}
}

}
}

+ 1
- 1
src/Discord.Net.Rest/API/Common/AuditLogOptions.cs View File

@@ -20,7 +20,7 @@ namespace Discord.API
[JsonProperty("role_name")] [JsonProperty("role_name")]
public string OverwriteRoleName { get; set; } public string OverwriteRoleName { get; set; }
[JsonProperty("type")] [JsonProperty("type")]
public string OverwriteType { get; set; }
public PermissionTarget OverwriteType { get; set; }
[JsonProperty("id")] [JsonProperty("id")]
public ulong? OverwriteTargetId { get; set; } public ulong? OverwriteTargetId { get; set; }
} }


+ 17
- 2
src/Discord.Net.Rest/BaseDiscordClient.cs View File

@@ -55,11 +55,11 @@ namespace Discord.Rest
await _stateLock.WaitAsync().ConfigureAwait(false); await _stateLock.WaitAsync().ConfigureAwait(false);
try try
{ {
await LoginInternalAsync(tokenType, token).ConfigureAwait(false);
await LoginInternalAsync(tokenType, token, validateToken).ConfigureAwait(false);
} }
finally { _stateLock.Release(); } finally { _stateLock.Release(); }
} }
private async Task LoginInternalAsync(TokenType tokenType, string token)
private async Task LoginInternalAsync(TokenType tokenType, string token, bool validateToken)
{ {
if (_isFirstLogin) if (_isFirstLogin)
{ {
@@ -73,6 +73,21 @@ namespace Discord.Rest


try try
{ {
// If token validation is enabled, validate the token and let it throw any ArgumentExceptions
// that result from invalid parameters
if (validateToken)
{
try
{
TokenUtils.ValidateToken(tokenType, token);
}
catch (ArgumentException ex)
{
// log these ArgumentExceptions and allow for the client to attempt to log in anyways
await LogManager.WarningAsync("Discord", "A supplied token was invalid", ex).ConfigureAwait(false);
}
}

await ApiClient.LoginAsync(tokenType, token).ConfigureAwait(false); await ApiClient.LoginAsync(tokenType, token).ConfigureAwait(false);
await OnLoginAsync(tokenType, token).ConfigureAwait(false); await OnLoginAsync(tokenType, token).ConfigureAwait(false);
LoginState = LoginState.LoggedIn; LoginState = LoginState.LoggedIn;


+ 12
- 9
src/Discord.Net.Rest/DiscordRestApiClient.cs View File

@@ -43,9 +43,11 @@ namespace Discord.API
public TokenType AuthTokenType { get; private set; } public TokenType AuthTokenType { get; private set; }
internal string AuthToken { get; private set; } internal string AuthToken { get; private set; }
internal IRestClient RestClient { get; private set; } internal IRestClient RestClient { get; private set; }
internal ulong? CurrentUserId { get; set;}
internal ulong? CurrentUserId { get; set; }


public DiscordRestApiClient(RestClientProvider restClientProvider, string userAgent, RetryMode defaultRetryMode = RetryMode.AlwaysRetry,
internal JsonSerializer Serializer => _serializer;

public DiscordRestApiClient(RestClientProvider restClientProvider, string userAgent, RetryMode defaultRetryMode = RetryMode.AlwaysRetry,
JsonSerializer serializer = null) JsonSerializer serializer = null)
{ {
_restClientProvider = restClientProvider; _restClientProvider = restClientProvider;
@@ -235,7 +237,7 @@ namespace Discord.API
internal Task<TResponse> SendMultipartAsync<TResponse>(string method, Expression<Func<string>> endpointExpr, IReadOnlyDictionary<string, object> multipartArgs, BucketIds ids, internal Task<TResponse> SendMultipartAsync<TResponse>(string method, Expression<Func<string>> endpointExpr, IReadOnlyDictionary<string, object> multipartArgs, BucketIds ids,
ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null) ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null)
=> SendMultipartAsync<TResponse>(method, GetEndpoint(endpointExpr), multipartArgs, GetBucketId(ids, endpointExpr, AuthTokenType, funcName), clientBucket, options); => SendMultipartAsync<TResponse>(method, GetEndpoint(endpointExpr), multipartArgs, GetBucketId(ids, endpointExpr, AuthTokenType, funcName), clientBucket, options);
public async Task<TResponse> SendMultipartAsync<TResponse>(string method, string endpoint, IReadOnlyDictionary<string, object> multipartArgs,
public async Task<TResponse> SendMultipartAsync<TResponse>(string method, string endpoint, IReadOnlyDictionary<string, object> multipartArgs,
string bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null) string bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null)
{ {
options = options ?? new RequestOptions(); options = options ?? new RequestOptions();
@@ -414,7 +416,7 @@ namespace Discord.API
var ids = new BucketIds(guildId: guildId); var ids = new BucketIds(guildId: guildId);
await SendAsync("DELETE", () => $"guilds/{guildId}/members/{userId}/roles/{roleId}", ids, options: options); await SendAsync("DELETE", () => $"guilds/{guildId}/members/{userId}/roles/{roleId}", ids, options: options);
} }
//Channel Messages //Channel Messages
public async Task<Message> GetChannelMessageAsync(ulong channelId, ulong messageId, RequestOptions options = null) public async Task<Message> GetChannelMessageAsync(ulong channelId, ulong messageId, RequestOptions options = null)
{ {
@@ -490,7 +492,7 @@ namespace Discord.API
if (args.Content?.Length > DiscordConfig.MaxMessageSize) if (args.Content?.Length > DiscordConfig.MaxMessageSize)
throw new ArgumentException($"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", nameof(args.Content)); throw new ArgumentException($"Message content is too long, length must be less or equal to {DiscordConfig.MaxMessageSize}.", nameof(args.Content));
options = RequestOptions.CreateOrClone(options); options = RequestOptions.CreateOrClone(options);
return await SendJsonAsync<Message>("POST", () => $"webhooks/{webhookId}/{AuthToken}?wait=true", args, new BucketIds(), clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false); return await SendJsonAsync<Message>("POST", () => $"webhooks/{webhookId}/{AuthToken}?wait=true", args, new BucketIds(), clientBucket: ClientBucketType.SendEdit, options: options).ConfigureAwait(false);
} }
public async Task<Message> UploadFileAsync(ulong channelId, UploadFileParams args, RequestOptions options = null) public async Task<Message> UploadFileAsync(ulong channelId, UploadFileParams args, RequestOptions options = null)
@@ -737,7 +739,7 @@ namespace Discord.API
Preconditions.NotNullOrWhitespace(args.Name, nameof(args.Name)); Preconditions.NotNullOrWhitespace(args.Name, nameof(args.Name));
Preconditions.NotNullOrWhitespace(args.RegionId, nameof(args.RegionId)); Preconditions.NotNullOrWhitespace(args.RegionId, nameof(args.RegionId));
options = RequestOptions.CreateOrClone(options); options = RequestOptions.CreateOrClone(options);
return await SendJsonAsync<Guild>("POST", () => "guilds", args, new BucketIds(), options: options).ConfigureAwait(false); return await SendJsonAsync<Guild>("POST", () => "guilds", args, new BucketIds(), options: options).ConfigureAwait(false);
} }
public async Task<Guild> DeleteGuildAsync(ulong guildId, RequestOptions options = null) public async Task<Guild> DeleteGuildAsync(ulong guildId, RequestOptions options = null)
@@ -964,7 +966,7 @@ namespace Discord.API
{ {
Preconditions.NotNullOrEmpty(inviteId, nameof(inviteId)); Preconditions.NotNullOrEmpty(inviteId, nameof(inviteId));
options = RequestOptions.CreateOrClone(options); options = RequestOptions.CreateOrClone(options);
return await SendAsync<Invite>("DELETE", () => $"invites/{inviteId}", new BucketIds(), options: options).ConfigureAwait(false); return await SendAsync<Invite>("DELETE", () => $"invites/{inviteId}", new BucketIds(), options: options).ConfigureAwait(false);
} }


@@ -1163,7 +1165,7 @@ namespace Discord.API


int limit = args.Limit.GetValueOrDefault(int.MaxValue); int limit = args.Limit.GetValueOrDefault(int.MaxValue);
ulong afterGuildId = args.AfterGuildId.GetValueOrDefault(0); ulong afterGuildId = args.AfterGuildId.GetValueOrDefault(0);
return await SendAsync<IReadOnlyCollection<UserGuild>>("GET", () => $"users/@me/guilds?limit={limit}&after={afterGuildId}", new BucketIds(), options: options).ConfigureAwait(false); return await SendAsync<IReadOnlyCollection<UserGuild>>("GET", () => $"users/@me/guilds?limit={limit}&after={afterGuildId}", new BucketIds(), options: options).ConfigureAwait(false);
} }
public async Task<Application> GetMyApplicationAsync(RequestOptions options = null) public async Task<Application> GetMyApplicationAsync(RequestOptions options = null)
@@ -1263,7 +1265,7 @@ namespace Discord.API
Preconditions.NotNull(args, nameof(args)); Preconditions.NotNull(args, nameof(args));
Preconditions.NotNullOrEmpty(args.Name, nameof(args.Name)); Preconditions.NotNullOrEmpty(args.Name, nameof(args.Name));
options = RequestOptions.CreateOrClone(options); options = RequestOptions.CreateOrClone(options);
if (AuthTokenType == TokenType.Webhook) if (AuthTokenType == TokenType.Webhook)
return await SendJsonAsync<Webhook>("PATCH", () => $"webhooks/{webhookId}/{AuthToken}", args, new BucketIds(), options: options).ConfigureAwait(false); return await SendJsonAsync<Webhook>("PATCH", () => $"webhooks/{webhookId}/{AuthToken}", args, new BucketIds(), options: options).ConfigureAwait(false);
else else
@@ -1394,6 +1396,7 @@ namespace Discord.API
string fieldName = GetFieldName(methodArgs[argId + 1]); string fieldName = GetFieldName(methodArgs[argId + 1]);


var mappedId = BucketIds.GetIndex(fieldName); var mappedId = BucketIds.GetIndex(fieldName);

if(!mappedId.HasValue && rightIndex != endIndex && format.Length > rightIndex + 1 && format[rightIndex + 1] == '/') //Ignore the next slash if(!mappedId.HasValue && rightIndex != endIndex && format.Length > rightIndex + 1 && format[rightIndex + 1] == '/') //Ignore the next slash
rightIndex++; rightIndex++;




+ 3
- 5
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelCreateAuditLogData.cs View File

@@ -26,18 +26,16 @@ namespace Discord.Rest
var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type"); var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type");
var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name");


var type = typeModel.NewValue.ToObject<ChannelType>();
var name = nameModel.NewValue.ToObject<string>();
var type = typeModel.NewValue.ToObject<ChannelType>(discord.ApiClient.Serializer);
var name = nameModel.NewValue.ToObject<string>(discord.ApiClient.Serializer);


foreach (var overwrite in overwritesModel.NewValue) foreach (var overwrite in overwritesModel.NewValue)
{ {
var deny = overwrite.Value<ulong>("deny"); var deny = overwrite.Value<ulong>("deny");
var _type = overwrite.Value<string>("type");
var permType = overwrite.Value<PermissionTarget>("type");
var id = overwrite.Value<ulong>("id"); var id = overwrite.Value<ulong>("id");
var allow = overwrite.Value<ulong>("allow"); var allow = overwrite.Value<ulong>("allow");


PermissionTarget permType = _type == "member" ? PermissionTarget.User : PermissionTarget.Role;

overwrites.Add(new Overwrite(id, permType, new OverwritePermissions(allow, deny))); overwrites.Add(new Overwrite(id, permType, new OverwritePermissions(allow, deny)));
} }




+ 3
- 3
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelDeleteAuditLogData.cs View File

@@ -27,11 +27,11 @@ namespace Discord.Rest
var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type"); var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type");
var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name");


var overwrites = overwritesModel.OldValue.ToObject<API.Overwrite[]>()
var overwrites = overwritesModel.OldValue.ToObject<API.Overwrite[]>(discord.ApiClient.Serializer)
.Select(x => new Overwrite(x.TargetId, x.TargetType, new OverwritePermissions(x.Allow, x.Deny))) .Select(x => new Overwrite(x.TargetId, x.TargetType, new OverwritePermissions(x.Allow, x.Deny)))
.ToList(); .ToList();
var type = typeModel.OldValue.ToObject<ChannelType>();
var name = nameModel.OldValue.ToObject<string>();
var type = typeModel.OldValue.ToObject<ChannelType>(discord.ApiClient.Serializer);
var name = nameModel.OldValue.ToObject<string>(discord.ApiClient.Serializer);
var id = entry.TargetId.Value; var id = entry.TargetId.Value;


return new ChannelDeleteAuditLogData(id, name, type, overwrites.ToReadOnlyCollection()); return new ChannelDeleteAuditLogData(id, name, type, overwrites.ToReadOnlyCollection());


+ 8
- 8
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelUpdateAuditLogData.cs View File

@@ -23,14 +23,14 @@ namespace Discord.Rest
var bitrateModel = changes.FirstOrDefault(x => x.ChangedProperty == "bitrate"); var bitrateModel = changes.FirstOrDefault(x => x.ChangedProperty == "bitrate");
var userLimitModel = changes.FirstOrDefault(x => x.ChangedProperty == "user_limit"); var userLimitModel = changes.FirstOrDefault(x => x.ChangedProperty == "user_limit");


string oldName = nameModel?.OldValue?.ToObject<string>(),
newName = nameModel?.NewValue?.ToObject<string>();
string oldTopic = topicModel?.OldValue?.ToObject<string>(),
newTopic = topicModel?.NewValue?.ToObject<string>();
int? oldBitrate = bitrateModel?.OldValue?.ToObject<int>(),
newBitrate = bitrateModel?.NewValue?.ToObject<int>();
int? oldLimit = userLimitModel?.OldValue?.ToObject<int>(),
newLimit = userLimitModel?.NewValue?.ToObject<int>();
string oldName = nameModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer),
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? oldBitrate = bitrateModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer),
newBitrate = bitrateModel?.NewValue?.ToObject<int>(discord.ApiClient.Serializer);
int? oldLimit = userLimitModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer),
newLimit = userLimitModel?.NewValue?.ToObject<int>(discord.ApiClient.Serializer);


var before = new ChannelInfo(oldName, oldTopic, oldBitrate, oldLimit); var before = new ChannelInfo(oldName, oldTopic, oldBitrate, oldLimit);
var after = new ChannelInfo(newName, newTopic, newBitrate, newLimit); var after = new ChannelInfo(newName, newTopic, newBitrate, newLimit);


+ 1
- 1
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteCreateAuditLogData.cs View File

@@ -21,7 +21,7 @@ namespace Discord.Rest
{ {
var change = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name"); var change = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name");


var emoteName = change.NewValue?.ToObject<string>();
var emoteName = change.NewValue?.ToObject<string>(discord.ApiClient.Serializer);
return new EmoteCreateAuditLogData(entry.TargetId.Value, emoteName); return new EmoteCreateAuditLogData(entry.TargetId.Value, emoteName);
} }




+ 1
- 1
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteDeleteAuditLogData.cs View File

@@ -17,7 +17,7 @@ namespace Discord.Rest
{ {
var change = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name"); var change = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name");


var emoteName = change.OldValue?.ToObject<string>();
var emoteName = change.OldValue?.ToObject<string>(discord.ApiClient.Serializer);


return new EmoteDeleteAuditLogData(entry.TargetId.Value, emoteName); return new EmoteDeleteAuditLogData(entry.TargetId.Value, emoteName);
} }


+ 2
- 2
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/EmoteUpdateAuditLogData.cs View File

@@ -18,8 +18,8 @@ namespace Discord.Rest
{ {
var change = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name"); var change = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "name");


var newName = change.NewValue?.ToObject<string>();
var oldName = change.OldValue?.ToObject<string>();
var newName = change.NewValue?.ToObject<string>(discord.ApiClient.Serializer);
var oldName = change.OldValue?.ToObject<string>(discord.ApiClient.Serializer);


return new EmoteUpdateAuditLogData(entry.TargetId.Value, oldName, newName); return new EmoteUpdateAuditLogData(entry.TargetId.Value, oldName, newName);
} }


+ 20
- 20
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/GuildUpdateAuditLogData.cs View File

@@ -28,26 +28,26 @@ namespace Discord.Rest
var mfaLevelModel = changes.FirstOrDefault(x => x.ChangedProperty == "afk_timeout"); var mfaLevelModel = changes.FirstOrDefault(x => x.ChangedProperty == "afk_timeout");
var contentFilterModel = changes.FirstOrDefault(x => x.ChangedProperty == "afk_timeout"); var contentFilterModel = changes.FirstOrDefault(x => x.ChangedProperty == "afk_timeout");


int? oldAfkTimeout = afkTimeoutModel?.OldValue?.ToObject<int>(),
newAfkTimeout = afkTimeoutModel?.NewValue?.ToObject<int>();
DefaultMessageNotifications? oldDefaultMessageNotifications = defaultMessageNotificationsModel?.OldValue?.ToObject<DefaultMessageNotifications>(),
newDefaultMessageNotifications = defaultMessageNotificationsModel?.NewValue?.ToObject<DefaultMessageNotifications>();
ulong? oldAfkChannelId = afkChannelModel?.OldValue?.ToObject<ulong>(),
newAfkChannelId = afkChannelModel?.NewValue?.ToObject<ulong>();
string oldName = nameModel?.OldValue?.ToObject<string>(),
newName = nameModel?.NewValue?.ToObject<string>();
string oldRegionId = regionIdModel?.OldValue?.ToObject<string>(),
newRegionId = regionIdModel?.NewValue?.ToObject<string>();
string oldIconHash = iconHashModel?.OldValue?.ToObject<string>(),
newIconHash = iconHashModel?.NewValue?.ToObject<string>();
VerificationLevel? oldVerificationLevel = verificationLevelModel?.OldValue?.ToObject<VerificationLevel>(),
newVerificationLevel = verificationLevelModel?.NewValue?.ToObject<VerificationLevel>();
ulong? oldOwnerId = ownerIdModel?.OldValue?.ToObject<ulong>(),
newOwnerId = ownerIdModel?.NewValue?.ToObject<ulong>();
MfaLevel? oldMfaLevel = mfaLevelModel?.OldValue?.ToObject<MfaLevel>(),
newMfaLevel = mfaLevelModel?.NewValue?.ToObject<MfaLevel>();
int? oldContentFilter = contentFilterModel?.OldValue?.ToObject<int>(),
newContentFilter = contentFilterModel?.NewValue?.ToObject<int>();
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),
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);
int? oldContentFilter = contentFilterModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer),
newContentFilter = contentFilterModel?.NewValue?.ToObject<int>(discord.ApiClient.Serializer);


IUser oldOwner = null; IUser oldOwner = null;
if (oldOwnerId != null) if (oldOwnerId != null)


+ 7
- 7
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteCreateAuditLogData.cs View File

@@ -30,13 +30,13 @@ namespace Discord.Rest
var usesModel = changes.FirstOrDefault(x => x.ChangedProperty == "uses"); var usesModel = changes.FirstOrDefault(x => x.ChangedProperty == "uses");
var maxUsesModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_uses"); var maxUsesModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_uses");


var maxAge = maxAgeModel.NewValue.ToObject<int>();
var code = codeModel.NewValue.ToObject<string>();
var temporary = temporaryModel.NewValue.ToObject<bool>();
var inviterId = inviterIdModel.NewValue.ToObject<ulong>();
var channelId = channelIdModel.NewValue.ToObject<ulong>();
var uses = usesModel.NewValue.ToObject<int>();
var maxUses = maxUsesModel.NewValue.ToObject<int>();
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 inviterId = inviterIdModel.NewValue.ToObject<ulong>(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);


var inviterInfo = log.Users.FirstOrDefault(x => x.Id == inviterId); var inviterInfo = log.Users.FirstOrDefault(x => x.Id == inviterId);
var inviter = RestUser.Create(discord, inviterInfo); var inviter = RestUser.Create(discord, inviterInfo);


+ 7
- 7
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteDeleteAuditLogData.cs View File

@@ -30,13 +30,13 @@ namespace Discord.Rest
var usesModel = changes.FirstOrDefault(x => x.ChangedProperty == "uses"); var usesModel = changes.FirstOrDefault(x => x.ChangedProperty == "uses");
var maxUsesModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_uses"); var maxUsesModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_uses");


var maxAge = maxAgeModel.OldValue.ToObject<int>();
var code = codeModel.OldValue.ToObject<string>();
var temporary = temporaryModel.OldValue.ToObject<bool>();
var inviterId = inviterIdModel.OldValue.ToObject<ulong>();
var channelId = channelIdModel.OldValue.ToObject<ulong>();
var uses = usesModel.OldValue.ToObject<int>();
var maxUses = maxUsesModel.OldValue.ToObject<int>();
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 inviterId = inviterIdModel.OldValue.ToObject<ulong>(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);


var inviterInfo = log.Users.FirstOrDefault(x => x.Id == inviterId); var inviterInfo = log.Users.FirstOrDefault(x => x.Id == inviterId);
var inviter = RestUser.Create(discord, inviterInfo); var inviter = RestUser.Create(discord, inviterInfo);


+ 10
- 10
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/InviteUpdateAuditLogData.cs View File

@@ -23,16 +23,16 @@ namespace Discord.Rest
var channelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "channel_id"); var channelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "channel_id");
var maxUsesModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_uses"); var maxUsesModel = changes.FirstOrDefault(x => x.ChangedProperty == "max_uses");


int? oldMaxAge = maxAgeModel?.OldValue?.ToObject<int>(),
newMaxAge = maxAgeModel?.NewValue?.ToObject<int>();
string oldCode = codeModel?.OldValue?.ToObject<string>(),
newCode = codeModel?.NewValue?.ToObject<string>();
bool? oldTemporary = temporaryModel?.OldValue?.ToObject<bool>(),
newTemporary = temporaryModel?.NewValue?.ToObject<bool>();
ulong? oldChannelId = channelIdModel?.OldValue?.ToObject<ulong>(),
newChannelId = channelIdModel?.NewValue?.ToObject<ulong>();
int? oldMaxUses = maxUsesModel?.OldValue?.ToObject<int>(),
newMaxUses = maxUsesModel?.NewValue?.ToObject<int>();
int? oldMaxAge = maxAgeModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer),
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 before = new InviteInfo(oldMaxAge, oldCode, oldTemporary, oldChannelId, oldMaxUses);
var after = new InviteInfo(newMaxAge, newCode, newTemporary, newChannelId, newMaxUses); var after = new InviteInfo(newMaxAge, newCode, newTemporary, newChannelId, newMaxUses);


+ 18
- 0
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberInfo.cs View File

@@ -0,0 +1,18 @@
namespace Discord.Rest
{
public struct MemberInfo
{
internal MemberInfo(string nick, bool? deaf, bool? mute, string avatar_hash)
{
Nickname = nick;
Deaf = deaf;
Mute = mute;
AvatarHash = avatar_hash;
}

public string Nickname { get; }
public bool? Deaf { get; }
public bool? Mute { get; }
public string AvatarHash { get; }
}
}

+ 1
- 1
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberRoleAuditLogData.cs View File

@@ -19,7 +19,7 @@ namespace Discord.Rest
{ {
var changes = entry.Changes; var changes = entry.Changes;


var roleInfos = changes.SelectMany(x => x.NewValue.ToObject<API.Role[]>(),
var roleInfos = changes.SelectMany(x => x.NewValue.ToObject<API.Role[]>(discord.ApiClient.Serializer),
(model, role) => new { model.ChangedProperty, Role = role }) (model, role) => new { model.ChangedProperty, Role = role })
.Select(x => new MemberRoleEditInfo(x.Role.Name, x.Role.Id, x.ChangedProperty == "$add")) .Select(x => new MemberRoleEditInfo(x.Role.Name, x.Role.Id, x.ChangedProperty == "$add"))
.ToList(); .ToList();


+ 23
- 9
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberUpdateAuditLogData.cs View File

@@ -8,28 +8,42 @@ namespace Discord.Rest
{ {
public class MemberUpdateAuditLogData : IAuditLogData public class MemberUpdateAuditLogData : IAuditLogData
{ {
private MemberUpdateAuditLogData(IUser target, string newNick, string oldNick)
private MemberUpdateAuditLogData(IUser target, MemberInfo before, MemberInfo after)
{ {
Target = target; Target = target;
NewNick = newNick;
OldNick = oldNick;
Before = before;
After = after;
} }


internal static MemberUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry) internal static MemberUpdateAuditLogData Create(BaseDiscordClient discord, Model log, EntryModel entry)
{ {
var changes = entry.Changes.FirstOrDefault(x => x.ChangedProperty == "nick");
var changes = entry.Changes;


var newNick = changes.NewValue?.ToObject<string>();
var oldNick = changes.OldValue?.ToObject<string>();
var nickModel = changes.FirstOrDefault(x => x.ChangedProperty == "nick");
var deafModel = changes.FirstOrDefault(x => x.ChangedProperty == "deaf");
var muteModel = changes.FirstOrDefault(x => x.ChangedProperty == "mute");
var avatarModel = changes.FirstOrDefault(x => x.ChangedProperty == "avatar_hash");

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);
string oldAvatar = avatarModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer),
newAvatar = avatarModel?.NewValue?.ToObject<string>(discord.ApiClient.Serializer);


var targetInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId); var targetInfo = log.Users.FirstOrDefault(x => x.Id == entry.TargetId);
var user = RestUser.Create(discord, targetInfo); var user = RestUser.Create(discord, targetInfo);


return new MemberUpdateAuditLogData(user, newNick, oldNick);
var before = new MemberInfo(oldNick, oldDeaf, oldMute, oldAvatar);
var after = new MemberInfo(newNick, newDeaf, newMute, newAvatar);

return new MemberUpdateAuditLogData(user, before, after);
} }


public IUser Target { get; } public IUser Target { get; }
public string NewNick { get; }
public string OldNick { get; }
public MemberInfo Before { get; }
public MemberInfo After { get; }
} }
} }

+ 3
- 5
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteCreateAuditLogData.cs View File

@@ -19,17 +19,15 @@ namespace Discord.Rest
var denyModel = changes.FirstOrDefault(x => x.ChangedProperty == "deny"); var denyModel = changes.FirstOrDefault(x => x.ChangedProperty == "deny");
var allowModel = changes.FirstOrDefault(x => x.ChangedProperty == "allow"); var allowModel = changes.FirstOrDefault(x => x.ChangedProperty == "allow");


var deny = denyModel.NewValue.ToObject<ulong>();
var allow = allowModel.NewValue.ToObject<ulong>();
var deny = denyModel.NewValue.ToObject<ulong>(discord.ApiClient.Serializer);
var allow = allowModel.NewValue.ToObject<ulong>(discord.ApiClient.Serializer);


var permissions = new OverwritePermissions(allow, deny); var permissions = new OverwritePermissions(allow, deny);


var id = entry.Options.OverwriteTargetId.Value; var id = entry.Options.OverwriteTargetId.Value;
var type = entry.Options.OverwriteType; var type = entry.Options.OverwriteType;


PermissionTarget target = type == "member" ? PermissionTarget.User : PermissionTarget.Role;

return new OverwriteCreateAuditLogData(new Overwrite(id, target, permissions));
return new OverwriteCreateAuditLogData(new Overwrite(id, type, permissions));
} }


public Overwrite Overwrite { get; } public Overwrite Overwrite { get; }


+ 5
- 7
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteDeleteAuditLogData.cs View File

@@ -27,14 +27,12 @@ namespace Discord.Rest
var idModel = changes.FirstOrDefault(x => x.ChangedProperty == "id"); var idModel = changes.FirstOrDefault(x => x.ChangedProperty == "id");
var allowModel = changes.FirstOrDefault(x => x.ChangedProperty == "allow"); var allowModel = changes.FirstOrDefault(x => x.ChangedProperty == "allow");


var deny = denyModel.OldValue.ToObject<ulong>();
var type = typeModel.OldValue.ToObject<string>();
var id = idModel.OldValue.ToObject<ulong>();
var allow = allowModel.OldValue.ToObject<ulong>();
var deny = denyModel.OldValue.ToObject<ulong>(discord.ApiClient.Serializer);
var type = typeModel.OldValue.ToObject<PermissionTarget>(discord.ApiClient.Serializer);
var id = idModel.OldValue.ToObject<ulong>(discord.ApiClient.Serializer);
var allow = allowModel.OldValue.ToObject<ulong>(discord.ApiClient.Serializer);


PermissionTarget target = type == "member" ? PermissionTarget.User : PermissionTarget.Role;

return new OverwriteDeleteAuditLogData(new Overwrite(id, target, new OverwritePermissions(allow, deny)));
return new OverwriteDeleteAuditLogData(new Overwrite(id, type, new OverwritePermissions(allow, deny)));
} }


public Overwrite Overwrite { get; } public Overwrite Overwrite { get; }


+ 6
- 6
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteUpdateAuditLogData.cs View File

@@ -22,17 +22,17 @@ namespace Discord.Rest
var denyModel = changes.FirstOrDefault(x => x.ChangedProperty == "deny"); var denyModel = changes.FirstOrDefault(x => x.ChangedProperty == "deny");
var allowModel = changes.FirstOrDefault(x => x.ChangedProperty == "allow"); var allowModel = changes.FirstOrDefault(x => x.ChangedProperty == "allow");


var beforeAllow = allowModel?.OldValue?.ToObject<ulong>();
var afterAllow = allowModel?.NewValue?.ToObject<ulong>();
var beforeDeny = denyModel?.OldValue?.ToObject<ulong>();
var afterDeny = denyModel?.OldValue?.ToObject<ulong>();
var beforeAllow = allowModel?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer);
var afterAllow = allowModel?.NewValue?.ToObject<ulong>(discord.ApiClient.Serializer);
var beforeDeny = denyModel?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer);
var afterDeny = denyModel?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer);


var beforePermissions = new OverwritePermissions(beforeAllow ?? 0, beforeDeny ?? 0); var beforePermissions = new OverwritePermissions(beforeAllow ?? 0, beforeDeny ?? 0);
var afterPermissions = new OverwritePermissions(afterAllow ?? 0, afterDeny ?? 0); var afterPermissions = new OverwritePermissions(afterAllow ?? 0, afterDeny ?? 0);


PermissionTarget target = entry.Options.OverwriteType == "member" ? PermissionTarget.User : PermissionTarget.Role;
var type = entry.Options.OverwriteType;


return new OverwriteUpdateAuditLogData(beforePermissions, afterPermissions, entry.Options.OverwriteTargetId.Value, target);
return new OverwriteUpdateAuditLogData(beforePermissions, afterPermissions, entry.Options.OverwriteTargetId.Value, type);
} }


public OverwritePermissions OldPermissions { get; } public OverwritePermissions OldPermissions { get; }


+ 5
- 5
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleCreateAuditLogData.cs View File

@@ -23,11 +23,11 @@ namespace Discord.Rest
var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name");
var permissionsModel = changes.FirstOrDefault(x => x.ChangedProperty == "permissions"); var permissionsModel = changes.FirstOrDefault(x => x.ChangedProperty == "permissions");


uint? colorRaw = colorModel?.NewValue?.ToObject<uint>();
bool? mentionable = mentionableModel?.NewValue?.ToObject<bool>();
bool? hoist = hoistModel?.NewValue?.ToObject<bool>();
string name = nameModel?.NewValue?.ToObject<string>();
ulong? permissionsRaw = permissionsModel?.NewValue?.ToObject<ulong>();
uint? colorRaw = colorModel?.NewValue?.ToObject<uint>(discord.ApiClient.Serializer);
bool? mentionable = mentionableModel?.NewValue?.ToObject<bool>(discord.ApiClient.Serializer);
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; Color? color = null;
GuildPermissions? permissions = null; GuildPermissions? permissions = null;


+ 5
- 5
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleDeleteAuditLogData.cs View File

@@ -23,11 +23,11 @@ namespace Discord.Rest
var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name");
var permissionsModel = changes.FirstOrDefault(x => x.ChangedProperty == "permissions"); var permissionsModel = changes.FirstOrDefault(x => x.ChangedProperty == "permissions");


uint? colorRaw = colorModel?.OldValue?.ToObject<uint>();
bool? mentionable = mentionableModel?.OldValue?.ToObject<bool>();
bool? hoist = hoistModel?.OldValue?.ToObject<bool>();
string name = nameModel?.OldValue?.ToObject<string>();
ulong? permissionsRaw = permissionsModel?.OldValue?.ToObject<ulong>();
uint? colorRaw = colorModel?.OldValue?.ToObject<uint>(discord.ApiClient.Serializer);
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; Color? color = null;
GuildPermissions? permissions = null; GuildPermissions? permissions = null;


+ 10
- 10
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleUpdateAuditLogData.cs View File

@@ -24,16 +24,16 @@ namespace Discord.Rest
var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name");
var permissionsModel = changes.FirstOrDefault(x => x.ChangedProperty == "permissions"); var permissionsModel = changes.FirstOrDefault(x => x.ChangedProperty == "permissions");


uint? oldColorRaw = colorModel?.OldValue?.ToObject<uint>(),
newColorRaw = colorModel?.NewValue?.ToObject<uint>();
bool? oldMentionable = mentionableModel?.OldValue?.ToObject<bool>(),
newMentionable = mentionableModel?.NewValue?.ToObject<bool>();
bool? oldHoist = hoistModel?.OldValue?.ToObject<bool>(),
newHoist = hoistModel?.NewValue?.ToObject<bool>();
string oldName = nameModel?.OldValue?.ToObject<string>(),
newName = nameModel?.NewValue?.ToObject<string>();
ulong? oldPermissionsRaw = permissionsModel?.OldValue?.ToObject<ulong>(),
newPermissionsRaw = permissionsModel?.OldValue?.ToObject<ulong>();
uint? oldColorRaw = colorModel?.OldValue?.ToObject<uint>(discord.ApiClient.Serializer),
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?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer);


Color? oldColor = null, Color? oldColor = null,
newColor = null; newColor = null;


+ 3
- 3
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookCreateAuditLogData.cs View File

@@ -23,9 +23,9 @@ namespace Discord.Rest
var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type"); var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type");
var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name");


var channelId = channelIdModel.NewValue.ToObject<ulong>();
var type = typeModel.NewValue.ToObject<WebhookType>();
var name = nameModel.NewValue.ToObject<string>();
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 = RestWebhook.Create(discord, (IGuild)null, webhookInfo); var webhook = RestWebhook.Create(discord, (IGuild)null, webhookInfo);


+ 4
- 4
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookDeleteAuditLogData.cs View File

@@ -29,10 +29,10 @@ namespace Discord.Rest
var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name");
var avatarHashModel = changes.FirstOrDefault(x => x.ChangedProperty == "avatar_hash"); var avatarHashModel = changes.FirstOrDefault(x => x.ChangedProperty == "avatar_hash");


var channelId = channelIdModel.OldValue.ToObject<ulong>();
var type = typeModel.OldValue.ToObject<WebhookType>();
var name = nameModel.OldValue.ToObject<string>();
var avatarHash = avatarHashModel?.OldValue?.ToObject<string>();
var channelId = channelIdModel.OldValue.ToObject<ulong>(discord.ApiClient.Serializer);
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); return new WebhookDeleteAuditLogData(entry.TargetId.Value, channelId, type, name, avatarHash);
} }


+ 7
- 7
src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/WebhookUpdateAuditLogData.cs View File

@@ -26,18 +26,18 @@ namespace Discord.Rest
var channelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "channel_id"); var channelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "channel_id");
var avatarHashModel = changes.FirstOrDefault(x => x.ChangedProperty == "avatar_hash"); var avatarHashModel = changes.FirstOrDefault(x => x.ChangedProperty == "avatar_hash");


var oldName = nameModel?.OldValue?.ToObject<string>();
var oldChannelId = channelIdModel?.OldValue?.ToObject<ulong>();
var oldAvatar = avatarHashModel?.OldValue?.ToObject<string>();
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 before = new WebhookInfo(oldName, oldChannelId, oldAvatar);


var newName = nameModel?.NewValue?.ToObject<string>();
var newChannelId = channelIdModel?.NewValue?.ToObject<ulong>();
var newAvatar = avatarHashModel?.NewValue?.ToObject<string>();
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 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 = RestWebhook.Create(discord, (IGuild)null, webhookInfo);
var webhook = webhookInfo != null ? RestWebhook.Create(discord, (IGuild)null, webhookInfo) : null;


return new WebhookUpdateAuditLogData(webhook, before, after); return new WebhookUpdateAuditLogData(webhook, before, after);
} }


+ 4
- 1
src/Discord.Net.Rest/Entities/AuditLogs/RestAuditLogEntry.cs View File

@@ -1,4 +1,5 @@
using System.Linq;
using System;
using System.Linq;


using Model = Discord.API.AuditLog; using Model = Discord.API.AuditLog;
using EntryModel = Discord.API.AuditLogEntry; using EntryModel = Discord.API.AuditLogEntry;
@@ -26,6 +27,8 @@ namespace Discord.Rest
return new RestAuditLogEntry(discord, fullLog, model, user); return new RestAuditLogEntry(discord, fullLog, model, user);
} }


/// <inheritdoc/>
public DateTimeOffset CreatedAt => SnowflakeUtils.FromSnowflake(Id);
/// <inheritdoc/> /// <inheritdoc/>
public ActionType Action { get; } public ActionType Action { get; }
/// <inheritdoc/> /// <inheritdoc/>


+ 124
- 0
test/Discord.Net.Tests/Tests.TokenUtils.cs View File

@@ -0,0 +1,124 @@
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;

namespace Discord
{
public class TokenUtilsTests
{
/// <summary>
/// Tests the usage of <see cref="TokenUtils.ValidateToken(TokenType, string)"/>
/// to see that when a null, empty or whitespace-only string is passed as the token,
/// it will throw an ArgumentNullException.
/// </summary>
[Theory]
[InlineData(null)]
[InlineData("")] // string.Empty isn't a constant type
[InlineData(" ")]
[InlineData(" ")]
[InlineData("\t")]
public void TestNullOrWhitespaceToken(string token)
{
// an ArgumentNullException should be thrown, regardless of the TokenType
Assert.Throws<ArgumentNullException>(() => TokenUtils.ValidateToken(TokenType.Bearer, token));
Assert.Throws<ArgumentNullException>(() => TokenUtils.ValidateToken(TokenType.Bot, token));
Assert.Throws<ArgumentNullException>(() => TokenUtils.ValidateToken(TokenType.Webhook, token));
}
/// <summary>
/// Tests the behavior of <see cref="TokenUtils.ValidateToken(TokenType, string)"/>
/// to see that valid Webhook tokens do not throw Exceptions.
/// </summary>
/// <param name="token"></param>
[Theory]
[InlineData("123123123")]
// bot token
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")]
// bearer token taken from discord docs
[InlineData("6qrZcUqja7812RVdnEKjpzOL4CvHBFG")]
// client secret
[InlineData("937it3ow87i4ery69876wqire")]
public void TestWebhookTokenDoesNotThrowExceptions(string token)
{
TokenUtils.ValidateToken(TokenType.Webhook, token);
}

// No tests for invalid webhook token behavior, because there is nothing there yet.

/// <summary>
/// Tests the behavior of <see cref="TokenUtils.ValidateToken(TokenType, string)"/>
/// to see that valid Webhook tokens do not throw Exceptions.
/// </summary>
/// <param name="token"></param>
[Theory]
[InlineData("123123123")]
// bot token
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")]
// bearer token taken from discord docs
[InlineData("6qrZcUqja7812RVdnEKjpzOL4CvHBFG")]
// client secret
[InlineData("937it3ow87i4ery69876wqire")]
public void TestBearerTokenDoesNotThrowExceptions(string token)
{
TokenUtils.ValidateToken(TokenType.Bearer, token);
}

// No tests for invalid bearer token behavior, because there is nothing there yet.

/// <summary>
/// Tests the behavior of <see cref="TokenUtils.ValidateToken(TokenType, string)"/>
/// to see that valid Bot tokens do not throw Exceptions.
/// Valid Bot tokens can be strings of length 59 or above.
/// </summary>
[Theory]
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")]
[InlineData("This appears to be completely invalid, however the current validation rules are not very strict.")]
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWss")]
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWsMTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs")]
public void TestBotTokenDoesNotThrowExceptions(string token)
{
// This example token is pulled from the Discord Docs
// https://discordapp.com/developers/docs/reference#authentication-example-bot-token-authorization-header
// should not throw any exception
TokenUtils.ValidateToken(TokenType.Bot, token);
}

/// <summary>
/// Tests the usage of <see cref="TokenUtils.ValidateToken(TokenType, string)"/> with
/// a Bot token that is invalid.
/// </summary>
[Theory]
[InlineData("This is invalid")]
// missing a single character from the end
[InlineData("MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKW")]
// bearer token
[InlineData("6qrZcUqja7812RVdnEKjpzOL4CvHBFG")]
// client secret
[InlineData("937it3ow87i4ery69876wqire")]
public void TestBotTokenInvalidThrowsArgumentException(string token)
{
Assert.Throws<ArgumentException>(() => TokenUtils.ValidateToken(TokenType.Bot, token));
}

/// <summary>
/// Tests the behavior of <see cref="TokenUtils.ValidateToken(TokenType, string)"/>
/// to see that an <see cref="ArgumentException"/> is thrown when an invalid
/// <see cref="TokenType"/> is supplied as a parameter.
/// </summary>
/// <remarks>
/// The <see cref="TokenType.User"/> type is treated as an invalid <see cref="TokenType"/>.
/// </remarks>
[Theory]
// TokenType.User
[InlineData(0)]
// out of range TokenType
[InlineData(4)]
[InlineData(7)]
public void TestUnrecognizedTokenType(int type)
{
Assert.Throws<ArgumentException>(() =>
TokenUtils.ValidateToken((TokenType)type, "MTk4NjIyNDgzNDcxOTI1MjQ4.Cl2FMQ.ZnCjm1XVW7vRze4b7Cq4se7kKWs"));
}
}
}

Loading…
Cancel
Save