Browse Source

Merge branch 'dev' into feature/reset-fater

feature/reset-fater
Christopher F GitHub 5 years ago
parent
commit
0924f43db0
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 311 additions and 76 deletions
  1. +6
    -6
      src/Discord.Net.Commands/CommandParser.cs
  2. +22
    -8
      src/Discord.Net.Commands/Results/ParseResult.cs
  3. +4
    -0
      src/Discord.Net.Core/Entities/Permissions/ChannelPermission.cs
  4. +9
    -2
      src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs
  5. +4
    -0
      src/Discord.Net.Core/Entities/Permissions/GuildPermission.cs
  6. +10
    -3
      src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs
  7. +2
    -1
      src/Discord.Net.Core/Utils/TokenUtils.cs
  8. +1
    -1
      src/Discord.Net.Rest/DiscordRestApiClient.cs
  9. +37
    -2
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelCreateAuditLogData.cs
  10. +36
    -2
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelDeleteAuditLogData.cs
  11. +20
    -10
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelInfo.cs
  12. +8
    -5
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/ChannelUpdateAuditLogData.cs
  13. +44
    -3
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/GuildInfo.cs
  14. +13
    -4
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/GuildUpdateAuditLogData.cs
  15. +26
    -3
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberInfo.cs
  16. +14
    -5
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/MemberUpdateAuditLogData.cs
  17. +11
    -2
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteCreateAuditLogData.cs
  18. +11
    -2
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteDeleteAuditLogData.cs
  19. +12
    -3
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/OverwriteUpdateAuditLogData.cs
  20. +1
    -1
      src/Discord.Net.Rest/Entities/AuditLogs/DataTypes/RoleUpdateAuditLogData.cs
  21. +2
    -1
      src/Discord.Net.Rest/Entities/Users/RestUser.cs
  22. +3
    -2
      src/Discord.Net.Rest/Net/Converters/UInt64EntityOrIdConverter.cs
  23. +7
    -7
      src/Discord.Net.Rest/Net/RateLimitInfo.cs
  24. +3
    -2
      src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs
  25. +2
    -1
      src/Discord.Net.Webhook/DiscordWebhookClient.cs
  26. +2
    -0
      test/Discord.Net.Tests.Unit/ChannelPermissionsTests.cs
  27. +1
    -0
      test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs

+ 6
- 6
src/Discord.Net.Commands/CommandParser.cs View File

@@ -103,7 +103,7 @@ namespace Discord.Commands
argBuilder.Append(c); argBuilder.Append(c);
continue; continue;
} }
if (IsOpenQuote(aliasMap, c)) if (IsOpenQuote(aliasMap, c))
{ {
curPart = ParserPart.QuotedParameter; curPart = ParserPart.QuotedParameter;
@@ -136,7 +136,7 @@ namespace Discord.Commands
else else
argBuilder.Append(c); argBuilder.Append(c);
} }
if (argString != null) if (argString != null)
{ {
if (curParam == null) if (curParam == null)
@@ -149,7 +149,7 @@ namespace Discord.Commands


var typeReaderResult = await curParam.ParseAsync(context, argString, services).ConfigureAwait(false); var typeReaderResult = await curParam.ParseAsync(context, argString, services).ConfigureAwait(false);
if (!typeReaderResult.IsSuccess && typeReaderResult.Error != CommandError.MultipleMatches) if (!typeReaderResult.IsSuccess && typeReaderResult.Error != CommandError.MultipleMatches)
return ParseResult.FromError(typeReaderResult);
return ParseResult.FromError(typeReaderResult, curParam);


if (curParam.IsMultiple) if (curParam.IsMultiple)
{ {
@@ -172,7 +172,7 @@ namespace Discord.Commands
{ {
var typeReaderResult = await curParam.ParseAsync(context, argBuilder.ToString(), services).ConfigureAwait(false); var typeReaderResult = await curParam.ParseAsync(context, argBuilder.ToString(), services).ConfigureAwait(false);
if (!typeReaderResult.IsSuccess) if (!typeReaderResult.IsSuccess)
return ParseResult.FromError(typeReaderResult);
return ParseResult.FromError(typeReaderResult, curParam);
argList.Add(typeReaderResult); argList.Add(typeReaderResult);
} }


@@ -180,7 +180,7 @@ namespace Discord.Commands
return ParseResult.FromError(CommandError.ParseFailed, "Input text may not end on an incomplete escape."); return ParseResult.FromError(CommandError.ParseFailed, "Input text may not end on an incomplete escape.");
if (curPart == ParserPart.QuotedParameter) if (curPart == ParserPart.QuotedParameter)
return ParseResult.FromError(CommandError.ParseFailed, "A quoted parameter is incomplete."); return ParseResult.FromError(CommandError.ParseFailed, "A quoted parameter is incomplete.");
//Add missing optionals //Add missing optionals
for (int i = argList.Count; i < command.Parameters.Count; i++) for (int i = argList.Count; i < command.Parameters.Count; i++)
{ {
@@ -191,7 +191,7 @@ namespace Discord.Commands
return ParseResult.FromError(CommandError.BadArgCount, "The input text has too few parameters."); return ParseResult.FromError(CommandError.BadArgCount, "The input text has too few parameters.");
argList.Add(TypeReaderResult.FromSuccess(param.DefaultValue)); argList.Add(TypeReaderResult.FromSuccess(param.DefaultValue));
} }
return ParseResult.FromSuccess(argList.ToImmutable(), paramList.ToImmutable()); return ParseResult.FromSuccess(argList.ToImmutable(), paramList.ToImmutable());
} }
} }


+ 22
- 8
src/Discord.Net.Commands/Results/ParseResult.cs View File

@@ -18,30 +18,40 @@ namespace Discord.Commands
/// <inheritdoc/> /// <inheritdoc/>
public string ErrorReason { get; } public string ErrorReason { get; }


/// <summary>
/// Provides information about the parameter that caused the parsing error.
/// </summary>
/// <returns>
/// A <see cref="ParameterInfo" /> indicating the parameter info of the error that may have occurred during parsing;
/// <c>null</c> if the parsing was successful or the parsing error is not specific to a single parameter.
/// </returns>
public ParameterInfo ErrorParameter { get; }

/// <inheritdoc/> /// <inheritdoc/>
public bool IsSuccess => !Error.HasValue; public bool IsSuccess => !Error.HasValue;


private ParseResult(IReadOnlyList<TypeReaderResult> argValues, IReadOnlyList<TypeReaderResult> paramValues, CommandError? error, string errorReason)
private ParseResult(IReadOnlyList<TypeReaderResult> argValues, IReadOnlyList<TypeReaderResult> paramValues, CommandError? error, string errorReason, ParameterInfo errorParamInfo)
{ {
ArgValues = argValues; ArgValues = argValues;
ParamValues = paramValues; ParamValues = paramValues;
Error = error; Error = error;
ErrorReason = errorReason; ErrorReason = errorReason;
ErrorParameter = errorParamInfo;
} }
public static ParseResult FromSuccess(IReadOnlyList<TypeReaderResult> argValues, IReadOnlyList<TypeReaderResult> paramValues) public static ParseResult FromSuccess(IReadOnlyList<TypeReaderResult> argValues, IReadOnlyList<TypeReaderResult> paramValues)
{ {
for (int i = 0; i < argValues.Count; i++) for (int i = 0; i < argValues.Count; i++)
{ {
if (argValues[i].Values.Count > 1) if (argValues[i].Values.Count > 1)
return new ParseResult(argValues, paramValues, CommandError.MultipleMatches, "Multiple matches found.");
return new ParseResult(argValues, paramValues, CommandError.MultipleMatches, "Multiple matches found.", null);
} }
for (int i = 0; i < paramValues.Count; i++) for (int i = 0; i < paramValues.Count; i++)
{ {
if (paramValues[i].Values.Count > 1) if (paramValues[i].Values.Count > 1)
return new ParseResult(argValues, paramValues, CommandError.MultipleMatches, "Multiple matches found.");
return new ParseResult(argValues, paramValues, CommandError.MultipleMatches, "Multiple matches found.", null);
} }
return new ParseResult(argValues, paramValues, null, null);
return new ParseResult(argValues, paramValues, null, null, null);
} }
public static ParseResult FromSuccess(IReadOnlyList<TypeReaderValue> argValues, IReadOnlyList<TypeReaderValue> paramValues) public static ParseResult FromSuccess(IReadOnlyList<TypeReaderValue> argValues, IReadOnlyList<TypeReaderValue> paramValues)
{ {
@@ -55,15 +65,19 @@ namespace Discord.Commands
for (int i = 0; i < paramValues.Count; i++) for (int i = 0; i < paramValues.Count; i++)
paramList[i] = TypeReaderResult.FromSuccess(paramValues[i]); paramList[i] = TypeReaderResult.FromSuccess(paramValues[i]);
} }
return new ParseResult(argList, paramList, null, null);
return new ParseResult(argList, paramList, null, null, null);
} }


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, null);
public static ParseResult FromError(CommandError error, string reason, ParameterInfo parameterInfo)
=> new ParseResult(null, null, error, reason, parameterInfo);
public static ParseResult FromError(Exception ex) public static ParseResult FromError(Exception ex)
=> FromError(CommandError.Exception, ex.Message); => 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, null);
public static ParseResult FromError(IResult result, ParameterInfo parameterInfo)
=> new ParseResult(null, null, result.Error, result.ErrorReason, parameterInfo);


public override string ToString() => IsSuccess ? "Success" : $"{Error}: {ErrorReason}"; public override string ToString() => IsSuccess ? "Success" : $"{Error}: {ErrorReason}";
private string DebuggerDisplay => IsSuccess ? $"Success ({ArgValues.Count}{(ParamValues.Count > 0 ? $" +{ParamValues.Count} Values" : "")})" : $"{Error}: {ErrorReason}"; private string DebuggerDisplay => IsSuccess ? $"Success ({ArgValues.Count}{(ParamValues.Count > 0 ? $" +{ParamValues.Count} Values" : "")})" : $"{Error}: {ErrorReason}";


+ 4
- 0
src/Discord.Net.Core/Entities/Permissions/ChannelPermission.cs View File

@@ -90,6 +90,10 @@ namespace Discord
/// </summary> /// </summary>
UseVAD = 0x02_00_00_00, UseVAD = 0x02_00_00_00,
PrioritySpeaker = 0x00_00_01_00, PrioritySpeaker = 0x00_00_01_00,
/// <summary>
/// Allows video streaming in a voice channel.
/// </summary>
Stream = 0x00_00_02_00,


// More General // More General
/// <summary> /// <summary>


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

@@ -13,7 +13,7 @@ namespace Discord
/// <summary> Gets a <see cref="ChannelPermissions"/> that grants all permissions for text channels. </summary> /// <summary> Gets a <see cref="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 <see cref="ChannelPermissions"/> that grants all permissions for voice channels. </summary> /// <summary> Gets a <see cref="ChannelPermissions"/> that grants all permissions for voice channels. </summary>
public static readonly ChannelPermissions Voice = new ChannelPermissions(0b00100_1111110_0000000010100_010001);
public static readonly ChannelPermissions Voice = new ChannelPermissions(0b00100_1111110_0000000011100_010001);
/// <summary> Gets a <see cref="ChannelPermissions"/> that grants all permissions for category channels. </summary> /// <summary> Gets a <see cref="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 <see cref="ChannelPermissions"/> that grants all permissions for direct message channels. </summary> /// <summary> Gets a <see cref="ChannelPermissions"/> that grants all permissions for direct message channels. </summary>
@@ -82,6 +82,8 @@ namespace Discord
public bool UseVAD => Permissions.GetValue(RawValue, ChannelPermission.UseVAD); public bool UseVAD => Permissions.GetValue(RawValue, ChannelPermission.UseVAD);
/// <summary> If <c>true</c>, a user may use priority speaker in a voice channel. </summary> /// <summary> If <c>true</c>, a user may use priority speaker in a voice channel. </summary>
public bool PrioritySpeaker => Permissions.GetValue(RawValue, ChannelPermission.PrioritySpeaker); public bool PrioritySpeaker => Permissions.GetValue(RawValue, ChannelPermission.PrioritySpeaker);
/// <summary> If <c>true</c>, a user may stream video in a voice channel. </summary>
public bool Stream => Permissions.GetValue(RawValue, ChannelPermission.Stream);


/// <summary> If <c>true</c>, a user may adjust role permissions. This also implictly grants all other permissions. </summary> /// <summary> If <c>true</c>, 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);
@@ -111,6 +113,7 @@ namespace Discord
bool? moveMembers = null, bool? moveMembers = null,
bool? useVoiceActivation = null, bool? useVoiceActivation = null,
bool? prioritySpeaker = null, bool? prioritySpeaker = null,
bool? stream = null,
bool? manageRoles = null, bool? manageRoles = null,
bool? manageWebhooks = null) bool? manageWebhooks = null)
{ {
@@ -135,6 +138,7 @@ namespace Discord
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, prioritySpeaker, ChannelPermission.PrioritySpeaker);
Permissions.SetValue(ref value, stream, ChannelPermission.Stream);
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);


@@ -162,11 +166,12 @@ namespace Discord
bool moveMembers = false, bool moveMembers = false,
bool useVoiceActivation = false, bool useVoiceActivation = false,
bool prioritySpeaker = false, bool prioritySpeaker = false,
bool stream = 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, prioritySpeaker, manageRoles, manageWebhooks)
speak, muteMembers, deafenMembers, moveMembers, useVoiceActivation, prioritySpeaker, stream, manageRoles, manageWebhooks)
{ } { }


/// <summary> Creates a new <see cref="ChannelPermissions"/> from this one, changing the provided non-null permissions. </summary> /// <summary> Creates a new <see cref="ChannelPermissions"/> from this one, changing the provided non-null permissions. </summary>
@@ -190,6 +195,7 @@ namespace Discord
bool? moveMembers = null, bool? moveMembers = null,
bool? useVoiceActivation = null, bool? useVoiceActivation = null,
bool? prioritySpeaker = null, bool? prioritySpeaker = null,
bool? stream = null,
bool? manageRoles = null, bool? manageRoles = null,
bool? manageWebhooks = null) bool? manageWebhooks = null)
=> new ChannelPermissions(RawValue, => new ChannelPermissions(RawValue,
@@ -212,6 +218,7 @@ namespace Discord
moveMembers, moveMembers,
useVoiceActivation, useVoiceActivation,
prioritySpeaker, prioritySpeaker,
stream,
manageRoles, manageRoles,
manageWebhooks); manageWebhooks);




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

@@ -126,6 +126,10 @@ namespace Discord
/// </summary> /// </summary>
UseVAD = 0x02_00_00_00, UseVAD = 0x02_00_00_00,
PrioritySpeaker = 0x00_00_01_00, PrioritySpeaker = 0x00_00_01_00,
/// <summary>
/// Allows video streaming in a voice channel.
/// </summary>
Stream = 0x00_00_02_00,


// General 2 // General 2
/// <summary> /// <summary>


+ 10
- 3
src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs View File

@@ -12,7 +12,7 @@ namespace Discord
/// <summary> Gets a <see cref="GuildPermissions"/> that grants all guild permissions for webhook users. </summary> /// <summary> Gets a <see cref="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 <see cref="GuildPermissions"/> that grants all guild permissions. </summary> /// <summary> Gets a <see cref="GuildPermissions"/> that grants all guild permissions. </summary>
public static readonly GuildPermissions All = new GuildPermissions(0b11111_1111110_1111111110111_111111);
public static readonly GuildPermissions All = new GuildPermissions(0b11111_1111110_1111111111111_111111);


/// <summary> Gets a packed value representing all the permissions in this <see cref="GuildPermissions"/>. </summary> /// <summary> Gets a packed value representing all the permissions in this <see cref="GuildPermissions"/>. </summary>
public ulong RawValue { get; } public ulong RawValue { get; }
@@ -70,7 +70,9 @@ namespace Discord
/// <summary> If <c>true</c>, a user may use voice-activity-detection rather than push-to-talk. </summary> /// <summary> If <c>true</c>, 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> /// <summary> If True, a user may use priority speaker in a voice channel. </summary>
public bool PrioritySpeaker => Permissions.GetValue(RawValue, ChannelPermission.PrioritySpeaker);
public bool PrioritySpeaker => Permissions.GetValue(RawValue, GuildPermission.PrioritySpeaker);
/// <summary> If True, a user may stream video in a voice channel. </summary>
public bool Stream => Permissions.GetValue(RawValue, GuildPermission.Stream);


/// <summary> If <c>true</c>, a user may change their own nickname. </summary> /// <summary> If <c>true</c>, a user may change their own nickname. </summary>
public bool ChangeNickname => Permissions.GetValue(RawValue, GuildPermission.ChangeNickname); public bool ChangeNickname => Permissions.GetValue(RawValue, GuildPermission.ChangeNickname);
@@ -111,6 +113,7 @@ namespace Discord
bool? moveMembers = null, bool? moveMembers = null,
bool? useVoiceActivation = null, bool? useVoiceActivation = null,
bool? prioritySpeaker = null, bool? prioritySpeaker = null,
bool? stream = null,
bool? changeNickname = null, bool? changeNickname = null,
bool? manageNicknames = null, bool? manageNicknames = null,
bool? manageRoles = null, bool? manageRoles = null,
@@ -143,6 +146,7 @@ namespace Discord
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, prioritySpeaker, GuildPermission.PrioritySpeaker);
Permissions.SetValue(ref value, stream, GuildPermission.Stream);
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);
@@ -178,6 +182,7 @@ namespace Discord
bool moveMembers = false, bool moveMembers = false,
bool useVoiceActivation = false, bool useVoiceActivation = false,
bool prioritySpeaker = false, bool prioritySpeaker = false,
bool stream = false,
bool changeNickname = false, bool changeNickname = false,
bool manageNicknames = false, bool manageNicknames = false,
bool manageRoles = false, bool manageRoles = false,
@@ -209,6 +214,7 @@ namespace Discord
moveMembers: moveMembers, moveMembers: moveMembers,
useVoiceActivation: useVoiceActivation, useVoiceActivation: useVoiceActivation,
prioritySpeaker: prioritySpeaker, prioritySpeaker: prioritySpeaker,
stream: stream,
changeNickname: changeNickname, changeNickname: changeNickname,
manageNicknames: manageNicknames, manageNicknames: manageNicknames,
manageWebhooks: manageWebhooks, manageWebhooks: manageWebhooks,
@@ -241,6 +247,7 @@ namespace Discord
bool? moveMembers = null, bool? moveMembers = null,
bool? useVoiceActivation = null, bool? useVoiceActivation = null,
bool? prioritySpeaker = null, bool? prioritySpeaker = null,
bool? stream = null,
bool? changeNickname = null, bool? changeNickname = null,
bool? manageNicknames = null, bool? manageNicknames = null,
bool? manageRoles = null, bool? manageRoles = null,
@@ -249,7 +256,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, prioritySpeaker, changeNickname, manageNicknames, manageRoles, manageWebhooks, manageEmojis);
useVoiceActivation, prioritySpeaker, stream, changeNickname, manageNicknames, manageRoles, manageWebhooks, manageEmojis);


/// <summary> /// <summary>
/// Returns a value that indicates if a specific <see cref="GuildPermission"/> is enabled /// Returns a value that indicates if a specific <see cref="GuildPermission"/> is enabled


+ 2
- 1
src/Discord.Net.Core/Utils/TokenUtils.cs View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Globalization;
using System.Text; using System.Text;


namespace Discord namespace Discord
@@ -76,7 +77,7 @@ namespace Discord
var bytes = Convert.FromBase64String(encoded); var bytes = Convert.FromBase64String(encoded);
var idStr = Encoding.UTF8.GetString(bytes); var idStr = Encoding.UTF8.GetString(bytes);
// try to parse a ulong from the resulting string // try to parse a ulong from the resulting string
if (ulong.TryParse(idStr, out var id))
if (ulong.TryParse(idStr, NumberStyles.None, CultureInfo.InvariantCulture, out var id))
return id; return id;
} }
catch (DecoderFallbackException) catch (DecoderFallbackException)


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

@@ -1492,7 +1492,7 @@ namespace Discord.API
builder.Append(format, lastIndex, leftIndex - lastIndex); builder.Append(format, lastIndex, leftIndex - lastIndex);
int rightIndex = format.IndexOf("}", leftIndex); int rightIndex = format.IndexOf("}", leftIndex);


int argId = int.Parse(format.Substring(leftIndex + 1, rightIndex - leftIndex - 1));
int argId = int.Parse(format.Substring(leftIndex + 1, rightIndex - leftIndex - 1), NumberStyles.None, CultureInfo.InvariantCulture);
string fieldName = GetFieldName(methodArgs[argId + 1]); string fieldName = GetFieldName(methodArgs[argId + 1]);


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


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

@@ -11,11 +11,14 @@ namespace Discord.Rest
/// </summary> /// </summary>
public class ChannelCreateAuditLogData : IAuditLogData public class ChannelCreateAuditLogData : IAuditLogData
{ {
private ChannelCreateAuditLogData(ulong id, string name, ChannelType type, IReadOnlyCollection<Overwrite> overwrites)
private ChannelCreateAuditLogData(ulong id, string name, ChannelType type, int? rateLimit, bool? nsfw, int? bitrate, IReadOnlyCollection<Overwrite> overwrites)
{ {
ChannelId = id; ChannelId = id;
ChannelName = name; ChannelName = name;
ChannelType = type; ChannelType = type;
SlowModeInterval = rateLimit;
IsNsfw = nsfw;
Bitrate = bitrate;
Overwrites = overwrites; Overwrites = overwrites;
} }


@@ -27,9 +30,15 @@ namespace Discord.Rest
var overwritesModel = changes.FirstOrDefault(x => x.ChangedProperty == "permission_overwrites"); var overwritesModel = changes.FirstOrDefault(x => x.ChangedProperty == "permission_overwrites");
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 rateLimitPerUserModel = changes.FirstOrDefault(x => x.ChangedProperty == "rate_limit_per_user");
var nsfwModel = changes.FirstOrDefault(x => x.ChangedProperty == "nsfw");
var bitrateModel = changes.FirstOrDefault(x => x.ChangedProperty == "bitrate");


var type = typeModel.NewValue.ToObject<ChannelType>(discord.ApiClient.Serializer); var type = typeModel.NewValue.ToObject<ChannelType>(discord.ApiClient.Serializer);
var name = nameModel.NewValue.ToObject<string>(discord.ApiClient.Serializer); var name = nameModel.NewValue.ToObject<string>(discord.ApiClient.Serializer);
int? rateLimitPerUser = rateLimitPerUserModel?.NewValue?.ToObject<int>(discord.ApiClient.Serializer);
bool? nsfw = nsfwModel?.NewValue?.ToObject<bool>(discord.ApiClient.Serializer);
int? bitrate = bitrateModel?.NewValue?.ToObject<int>(discord.ApiClient.Serializer);


foreach (var overwrite in overwritesModel.NewValue) foreach (var overwrite in overwritesModel.NewValue)
{ {
@@ -41,7 +50,7 @@ namespace Discord.Rest
overwrites.Add(new Overwrite(id, permType, new OverwritePermissions(allow, deny))); overwrites.Add(new Overwrite(id, permType, new OverwritePermissions(allow, deny)));
} }


return new ChannelCreateAuditLogData(entry.TargetId.Value, name, type, overwrites.ToReadOnlyCollection());
return new ChannelCreateAuditLogData(entry.TargetId.Value, name, type, rateLimitPerUser, nsfw, bitrate, overwrites.ToReadOnlyCollection());
} }


/// <summary> /// <summary>
@@ -66,6 +75,32 @@ namespace Discord.Rest
/// </returns> /// </returns>
public ChannelType ChannelType { get; } public ChannelType ChannelType { get; }
/// <summary> /// <summary>
/// Gets the current slow-mode delay of the created channel.
/// </summary>
/// <returns>
/// An <see cref="Int32"/> representing the time in seconds required before the user can send another
/// message; <c>0</c> if disabled.
/// <c>null</c> if this is not mentioned in this entry.
/// </returns>
public int? SlowModeInterval { get; }
/// <summary>
/// Gets the value that indicates whether the created channel is NSFW.
/// </summary>
/// <returns>
/// <c>true</c> if the created channel has the NSFW flag enabled; otherwise <c>false</c>.
/// <c>null</c> if this is not mentioned in this entry.
/// </returns>
public bool? IsNsfw { get; }
/// <summary>
/// Gets the bit-rate that the clients in the created voice channel are requested to use.
/// </summary>
/// <returns>
/// An <see cref="Int32"/> representing the bit-rate (bps) that the created voice channel defines and requests the
/// client(s) to use.
/// <c>null</c> if this is not mentioned in this entry.
/// </returns>
public int? Bitrate { get; }
/// <summary>
/// Gets a collection of permission overwrites that was assigned to the created channel. /// Gets a collection of permission overwrites that was assigned to the created channel.
/// </summary> /// </summary>
/// <returns> /// <returns>


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

@@ -11,11 +11,14 @@ namespace Discord.Rest
/// </summary> /// </summary>
public class ChannelDeleteAuditLogData : IAuditLogData public class ChannelDeleteAuditLogData : IAuditLogData
{ {
private ChannelDeleteAuditLogData(ulong id, string name, ChannelType type, IReadOnlyCollection<Overwrite> overwrites)
private ChannelDeleteAuditLogData(ulong id, string name, ChannelType type, int? rateLimit, bool? nsfw, int? bitrate, IReadOnlyCollection<Overwrite> overwrites)
{ {
ChannelId = id; ChannelId = id;
ChannelName = name; ChannelName = name;
ChannelType = type; ChannelType = type;
SlowModeInterval = rateLimit;
IsNsfw = nsfw;
Bitrate = bitrate;
Overwrites = overwrites; Overwrites = overwrites;
} }


@@ -26,15 +29,21 @@ namespace Discord.Rest
var overwritesModel = changes.FirstOrDefault(x => x.ChangedProperty == "permission_overwrites"); var overwritesModel = changes.FirstOrDefault(x => x.ChangedProperty == "permission_overwrites");
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 rateLimitPerUserModel = changes.FirstOrDefault(x => x.ChangedProperty == "rate_limit_per_user");
var nsfwModel = changes.FirstOrDefault(x => x.ChangedProperty == "nsfw");
var bitrateModel = changes.FirstOrDefault(x => x.ChangedProperty == "bitrate");


var overwrites = overwritesModel.OldValue.ToObject<API.Overwrite[]>(discord.ApiClient.Serializer) 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>(discord.ApiClient.Serializer); var type = typeModel.OldValue.ToObject<ChannelType>(discord.ApiClient.Serializer);
var name = nameModel.OldValue.ToObject<string>(discord.ApiClient.Serializer); var name = nameModel.OldValue.ToObject<string>(discord.ApiClient.Serializer);
int? rateLimitPerUser = rateLimitPerUserModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer);
bool? nsfw = nsfwModel?.OldValue?.ToObject<bool>(discord.ApiClient.Serializer);
int? bitrate = bitrateModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer);
var id = entry.TargetId.Value; var id = entry.TargetId.Value;


return new ChannelDeleteAuditLogData(id, name, type, overwrites.ToReadOnlyCollection());
return new ChannelDeleteAuditLogData(id, name, type, rateLimitPerUser, nsfw, bitrate, overwrites.ToReadOnlyCollection());
} }


/// <summary> /// <summary>
@@ -59,6 +68,31 @@ namespace Discord.Rest
/// </returns> /// </returns>
public ChannelType ChannelType { get; } public ChannelType ChannelType { get; }
/// <summary> /// <summary>
/// Gets the slow-mode delay of the deleted channel.
/// </summary>
/// <returns>
/// An <see cref="Int32"/> representing the time in seconds required before the user can send another
/// message; <c>0</c> if disabled.
/// <c>null</c> if this is not mentioned in this entry.
/// </returns>
public int? SlowModeInterval { get; }
/// <summary>
/// Gets the value that indicates whether the deleted channel was NSFW.
/// </summary>
/// <returns>
/// <c>true</c> if this channel had the NSFW flag enabled; otherwise <c>false</c>.
/// <c>null</c> if this is not mentioned in this entry.
/// </returns>
public bool? IsNsfw { get; }
/// <summary>
/// Gets the bit-rate of this channel if applicable.
/// </summary>
/// <returns>
/// An <see cref="Int32"/> representing the bit-rate set of the voice channel.
/// <c>null</c> if this is not mentioned in this entry.
/// </returns>
public int? Bitrate { get; }
/// <summary>
/// Gets a collection of permission overwrites that was assigned to the deleted channel. /// Gets a collection of permission overwrites that was assigned to the deleted channel.
/// </summary> /// </summary>
/// <returns> /// <returns>


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

@@ -5,12 +5,13 @@ namespace Discord.Rest
/// </summary> /// </summary>
public struct ChannelInfo public struct ChannelInfo
{ {
internal ChannelInfo(string name, string topic, int? bitrate, int? limit)
internal ChannelInfo(string name, string topic, int? rateLimit, bool? nsfw, int? bitrate)
{ {
Name = name; Name = name;
Topic = topic; Topic = topic;
SlowModeInterval = rateLimit;
IsNsfw = nsfw;
Bitrate = bitrate; Bitrate = bitrate;
UserLimit = limit;
} }


/// <summary> /// <summary>
@@ -28,20 +29,29 @@ namespace Discord.Rest
/// </returns> /// </returns>
public string Topic { get; } public string Topic { get; }
/// <summary> /// <summary>
/// Gets the bit-rate of this channel if applicable.
/// Gets the current slow-mode delay of this channel.
/// </summary> /// </summary>
/// <returns> /// <returns>
/// An <see cref="System.Int32"/> representing the bit-rate set for the voice channel; <c>null</c> if not
/// applicable.
/// An <see cref="Int32"/> representing the time in seconds required before the user can send another
/// message; <c>0</c> if disabled.
/// <c>null</c> if this is not mentioned in this entry.
/// </returns> /// </returns>
public int? Bitrate { get; }
public int? SlowModeInterval { get; }
/// <summary>
/// Gets the value that indicates whether this channel is NSFW.
/// </summary>
/// <returns>
/// <c>true</c> if this channel has the NSFW flag enabled; otherwise <c>false</c>.
/// <c>null</c> if this is not mentioned in this entry.
/// </returns>
public bool? IsNsfw { get; }
/// <summary> /// <summary>
/// Gets the number of users allowed to be in this channel if applicable.
/// Gets the bit-rate of this channel if applicable.
/// </summary> /// </summary>
/// <returns> /// <returns>
/// An <see cref="System.Int32" /> representing the number of users allowed to be in this voice channel;
/// <c>null</c> if not applicable.
/// An <see cref="Int32"/> representing the bit-rate set for the voice channel;
/// <c>null</c> if this is not mentioned in this entry.
/// </returns> /// </returns>
public int? UserLimit { get; }
public int? Bitrate { get; }
} }
} }

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

@@ -23,20 +23,23 @@ namespace Discord.Rest


var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name"); var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name");
var topicModel = changes.FirstOrDefault(x => x.ChangedProperty == "topic"); var topicModel = changes.FirstOrDefault(x => x.ChangedProperty == "topic");
var rateLimitPerUserModel = changes.FirstOrDefault(x => x.ChangedProperty == "rate_limit_per_user");
var nsfwModel = changes.FirstOrDefault(x => x.ChangedProperty == "nsfw");
var bitrateModel = changes.FirstOrDefault(x => x.ChangedProperty == "bitrate"); var bitrateModel = changes.FirstOrDefault(x => x.ChangedProperty == "bitrate");
var userLimitModel = changes.FirstOrDefault(x => x.ChangedProperty == "user_limit");


string oldName = nameModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer), string oldName = nameModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer),
newName = nameModel?.NewValue?.ToObject<string>(discord.ApiClient.Serializer); newName = nameModel?.NewValue?.ToObject<string>(discord.ApiClient.Serializer);
string oldTopic = topicModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer), string oldTopic = topicModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer),
newTopic = topicModel?.NewValue?.ToObject<string>(discord.ApiClient.Serializer); newTopic = topicModel?.NewValue?.ToObject<string>(discord.ApiClient.Serializer);
int? oldRateLimitPerUser = rateLimitPerUserModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer),
newRateLimitPerUser = rateLimitPerUserModel?.NewValue?.ToObject<int>(discord.ApiClient.Serializer);
bool? oldNsfw = nsfwModel?.OldValue?.ToObject<bool>(discord.ApiClient.Serializer),
newNsfw = nsfwModel?.NewValue?.ToObject<bool>(discord.ApiClient.Serializer);
int? oldBitrate = bitrateModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer), int? oldBitrate = bitrateModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer),
newBitrate = bitrateModel?.NewValue?.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 after = new ChannelInfo(newName, newTopic, newBitrate, newLimit);
var before = new ChannelInfo(oldName, oldTopic, oldRateLimitPerUser, oldNsfw, oldBitrate);
var after = new ChannelInfo(newName, newTopic, newRateLimitPerUser, newNsfw, newBitrate);


return new ChannelUpdateAuditLogData(entry.TargetId.Value, before, after); return new ChannelUpdateAuditLogData(entry.TargetId.Value, before, after);
} }


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

@@ -7,7 +7,8 @@ namespace Discord.Rest
{ {
internal GuildInfo(int? afkTimeout, DefaultMessageNotifications? defaultNotifs, internal GuildInfo(int? afkTimeout, DefaultMessageNotifications? defaultNotifs,
ulong? afkChannel, string name, string region, string icon, ulong? afkChannel, string name, string region, string icon,
VerificationLevel? verification, IUser owner, MfaLevel? mfa, int? filter)
VerificationLevel? verification, IUser owner, MfaLevel? mfa, ExplicitContentFilterLevel? filter,
ulong? systemChannel, ulong? widgetChannel, bool? widget)
{ {
AfkTimeout = afkTimeout; AfkTimeout = afkTimeout;
DefaultMessageNotifications = defaultNotifs; DefaultMessageNotifications = defaultNotifs;
@@ -18,7 +19,10 @@ namespace Discord.Rest
VerificationLevel = verification; VerificationLevel = verification;
Owner = owner; Owner = owner;
MfaLevel = mfa; MfaLevel = mfa;
ContentFilterLevel = filter;
ExplicitContentFilter = filter;
SystemChannelId = systemChannel;
EmbedChannelId = widgetChannel;
IsEmbeddable = widget;
} }


/// <summary> /// <summary>
@@ -28,11 +32,16 @@ namespace Discord.Rest
/// <returns> /// <returns>
/// An <see cref="int"/> representing the amount of time in seconds for a user to be marked as inactive /// An <see cref="int"/> representing the amount of time in seconds for a user to be marked as inactive
/// and moved into the AFK voice channel. /// and moved into the AFK voice channel.
/// <c>null</c> if this is not mentioned in this entry.
/// </returns> /// </returns>
public int? AfkTimeout { get; } public int? AfkTimeout { get; }
/// <summary> /// <summary>
/// Gets the default message notifications for users who haven't explicitly set their notification settings. /// Gets the default message notifications for users who haven't explicitly set their notification settings.
/// </summary> /// </summary>
/// <returns>
/// The default message notifications setting of this guild.
/// <c>null</c> if this is not mentioned in this entry.
/// </returns>
public DefaultMessageNotifications? DefaultMessageNotifications { get; } public DefaultMessageNotifications? DefaultMessageNotifications { get; }
/// <summary> /// <summary>
/// Gets the ID of the AFK voice channel for this guild. /// Gets the ID of the AFK voice channel for this guild.
@@ -65,6 +74,7 @@ namespace Discord.Rest
/// </summary> /// </summary>
/// <returns> /// <returns>
/// The level of requirements. /// The level of requirements.
/// <c>null</c> if this is not mentioned in this entry.
/// </returns> /// </returns>
public VerificationLevel? VerificationLevel { get; } public VerificationLevel? VerificationLevel { get; }
/// <summary> /// <summary>
@@ -80,8 +90,39 @@ namespace Discord.Rest
/// </summary> /// </summary>
/// <returns> /// <returns>
/// The level of MFA requirement. /// The level of MFA requirement.
/// <c>null</c> if this is not mentioned in this entry.
/// </returns> /// </returns>
public MfaLevel? MfaLevel { get; } public MfaLevel? MfaLevel { get; }
public int? ContentFilterLevel { get; }
/// <summary>
/// Gets the level of content filtering applied to user's content in a Guild.
/// </summary>
/// <returns>
/// The level of explicit content filtering.
/// </returns>
public ExplicitContentFilterLevel? ExplicitContentFilter { get; }
/// <summary>
/// Gets the ID of the channel where system messages are sent.
/// </summary>
/// <returns>
/// A <see cref="ulong"/> representing the snowflake identifier of the channel where system
/// messages are sent; <c>null</c> if none is set.
/// </returns>
public ulong? SystemChannelId { get; }
/// <summary>
/// Gets the ID of the widget embed channel of this guild.
/// </summary>
/// <returns>
/// A <see cref="ulong"/> representing the snowflake identifier of the embedded channel found within the
/// widget settings of this guild; <c>null</c> if none is set.
/// </returns>
public ulong? EmbedChannelId { get; }
/// <summary>
/// Gets a value that indicates whether this guild is embeddable (i.e. can use widget).
/// </summary>
/// <returns>
/// <c>true</c> if this guild can be embedded via widgets; otherwise <c>false</c>.
/// <c>null</c> if this is not mentioned in this entry.
/// </returns>
public bool? IsEmbeddable { get; }
} }
} }

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

@@ -30,6 +30,9 @@ namespace Discord.Rest
var ownerIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "owner_id"); var ownerIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "owner_id");
var mfaLevelModel = changes.FirstOrDefault(x => x.ChangedProperty == "mfa_level"); var mfaLevelModel = changes.FirstOrDefault(x => x.ChangedProperty == "mfa_level");
var contentFilterModel = changes.FirstOrDefault(x => x.ChangedProperty == "explicit_content_filter"); var contentFilterModel = changes.FirstOrDefault(x => x.ChangedProperty == "explicit_content_filter");
var systemChannelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "system_channel_id");
var widgetChannelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "widget_channel_id");
var widgetEnabledModel = changes.FirstOrDefault(x => x.ChangedProperty == "widget_enabled");


int? oldAfkTimeout = afkTimeoutModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer), int? oldAfkTimeout = afkTimeoutModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer),
newAfkTimeout = afkTimeoutModel?.NewValue?.ToObject<int>(discord.ApiClient.Serializer); newAfkTimeout = afkTimeoutModel?.NewValue?.ToObject<int>(discord.ApiClient.Serializer);
@@ -49,8 +52,14 @@ namespace Discord.Rest
newOwnerId = ownerIdModel?.NewValue?.ToObject<ulong>(discord.ApiClient.Serializer); newOwnerId = ownerIdModel?.NewValue?.ToObject<ulong>(discord.ApiClient.Serializer);
MfaLevel? oldMfaLevel = mfaLevelModel?.OldValue?.ToObject<MfaLevel>(discord.ApiClient.Serializer), MfaLevel? oldMfaLevel = mfaLevelModel?.OldValue?.ToObject<MfaLevel>(discord.ApiClient.Serializer),
newMfaLevel = mfaLevelModel?.NewValue?.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);
ExplicitContentFilterLevel? oldContentFilter = contentFilterModel?.OldValue?.ToObject<ExplicitContentFilterLevel>(discord.ApiClient.Serializer),
newContentFilter = contentFilterModel?.NewValue?.ToObject<ExplicitContentFilterLevel>(discord.ApiClient.Serializer);
ulong? oldSystemChannelId = systemChannelIdModel?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer),
newSystemChannelId = systemChannelIdModel?.NewValue?.ToObject<ulong>(discord.ApiClient.Serializer);
ulong? oldWidgetChannelId = widgetChannelIdModel?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer),
newWidgetChannelId = widgetChannelIdModel?.NewValue?.ToObject<ulong>(discord.ApiClient.Serializer);
bool? oldWidgetEnabled = widgetEnabledModel?.OldValue?.ToObject<bool>(discord.ApiClient.Serializer),
newWidgetEnabled = widgetEnabledModel?.NewValue?.ToObject<bool>(discord.ApiClient.Serializer);


IUser oldOwner = null; IUser oldOwner = null;
if (oldOwnerId != null) if (oldOwnerId != null)
@@ -68,10 +77,10 @@ namespace Discord.Rest


var before = new GuildInfo(oldAfkTimeout, oldDefaultMessageNotifications, var before = new GuildInfo(oldAfkTimeout, oldDefaultMessageNotifications,
oldAfkChannelId, oldName, oldRegionId, oldIconHash, oldVerificationLevel, oldOwner, oldAfkChannelId, oldName, oldRegionId, oldIconHash, oldVerificationLevel, oldOwner,
oldMfaLevel, oldContentFilter);
oldMfaLevel, oldContentFilter, oldSystemChannelId, oldWidgetChannelId, oldWidgetEnabled);
var after = new GuildInfo(newAfkTimeout, newDefaultMessageNotifications, var after = new GuildInfo(newAfkTimeout, newDefaultMessageNotifications,
newAfkChannelId, newName, newRegionId, newIconHash, newVerificationLevel, newOwner, newAfkChannelId, newName, newRegionId, newIconHash, newVerificationLevel, newOwner,
newMfaLevel, newContentFilter);
newMfaLevel, newContentFilter, newSystemChannelId, newWidgetChannelId, newWidgetEnabled);


return new GuildUpdateAuditLogData(before, after); return new GuildUpdateAuditLogData(before, after);
} }


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

@@ -1,18 +1,41 @@
namespace Discord.Rest namespace Discord.Rest
{ {
/// <summary>
/// Represents information for a member.
/// </summary>
public struct MemberInfo public struct MemberInfo
{ {
internal MemberInfo(string nick, bool? deaf, bool? mute, string avatar_hash)
internal MemberInfo(string nick, bool? deaf, bool? mute)
{ {
Nickname = nick; Nickname = nick;
Deaf = deaf; Deaf = deaf;
Mute = mute; Mute = mute;
AvatarHash = avatar_hash;
} }


/// <summary>
/// Gets the nickname of the updated member.
/// </summary>
/// <returns>
/// A string representing the nickname of the updated member; <c>null</c> if none is set.
/// </returns>
public string Nickname { get; } public string Nickname { get; }
/// <summary>
/// Gets a value that indicates whether the updated member is deafened by the guild.
/// </summary>
/// <returns>
/// <c>true</c> if the updated member is deafened (i.e. not permitted to listen to or speak to others) by the guild;
/// otherwise <c>false</c>.
/// <c>null</c> if this is not mentioned in this entry.
/// </returns>
public bool? Deaf { get; } public bool? Deaf { get; }
/// <summary>
/// Gets a value that indicates whether the updated member is muted (i.e. not permitted to speak via voice) by the
/// guild.
/// </summary>
/// <returns>
/// <c>true</c> if the updated member is muted by the guild; otherwise <c>false</c>.
/// <c>null</c> if this is not mentioned in this entry.
/// </returns>
public bool? Mute { get; } public bool? Mute { get; }
public string AvatarHash { get; }
} }
} }

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

@@ -24,7 +24,6 @@ namespace Discord.Rest
var nickModel = changes.FirstOrDefault(x => x.ChangedProperty == "nick"); var nickModel = changes.FirstOrDefault(x => x.ChangedProperty == "nick");
var deafModel = changes.FirstOrDefault(x => x.ChangedProperty == "deaf"); var deafModel = changes.FirstOrDefault(x => x.ChangedProperty == "deaf");
var muteModel = changes.FirstOrDefault(x => x.ChangedProperty == "mute"); 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), string oldNick = nickModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer),
newNick = nickModel?.NewValue?.ToObject<string>(discord.ApiClient.Serializer); newNick = nickModel?.NewValue?.ToObject<string>(discord.ApiClient.Serializer);
@@ -32,14 +31,12 @@ namespace Discord.Rest
newDeaf = deafModel?.NewValue?.ToObject<bool>(discord.ApiClient.Serializer); newDeaf = deafModel?.NewValue?.ToObject<bool>(discord.ApiClient.Serializer);
bool? oldMute = muteModel?.OldValue?.ToObject<bool>(discord.ApiClient.Serializer), bool? oldMute = muteModel?.OldValue?.ToObject<bool>(discord.ApiClient.Serializer),
newMute = muteModel?.NewValue?.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);


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


return new MemberUpdateAuditLogData(user, before, after); return new MemberUpdateAuditLogData(user, before, after);
} }
@@ -51,7 +48,19 @@ namespace Discord.Rest
/// A user object representing the user who the changes were performed on. /// A user object representing the user who the changes were performed on.
/// </returns> /// </returns>
public IUser Target { get; } public IUser Target { get; }
/// <summary>
/// Gets the member information before the changes.
/// </summary>
/// <returns>
/// An information object containing the original member information before the changes were made.
/// </returns>
public MemberInfo Before { get; } public MemberInfo Before { get; }
/// <summary>
/// Gets the member information after the changes.
/// </summary>
/// <returns>
/// An information object containing the member information after the changes were made.
/// </returns>
public MemberInfo After { get; } public MemberInfo After { get; }
} }
} }

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

@@ -10,8 +10,9 @@ namespace Discord.Rest
/// </summary> /// </summary>
public class OverwriteCreateAuditLogData : IAuditLogData public class OverwriteCreateAuditLogData : IAuditLogData
{ {
private OverwriteCreateAuditLogData(Overwrite overwrite)
private OverwriteCreateAuditLogData(ulong channelId, Overwrite overwrite)
{ {
ChannelId = channelId;
Overwrite = overwrite; Overwrite = overwrite;
} }


@@ -30,10 +31,18 @@ namespace Discord.Rest
var id = entry.Options.OverwriteTargetId.Value; var id = entry.Options.OverwriteTargetId.Value;
var type = entry.Options.OverwriteType; var type = entry.Options.OverwriteType;


return new OverwriteCreateAuditLogData(new Overwrite(id, type, permissions));
return new OverwriteCreateAuditLogData(entry.TargetId.Value, new Overwrite(id, type, permissions));
} }


/// <summary> /// <summary>
/// Gets the ID of the channel that the overwrite was created from.
/// </summary>
/// <returns>
/// A <see cref="ulong"/> representing the snowflake identifier for the channel that the overwrite was
/// created from.
/// </returns>
public ulong ChannelId { get; }
/// <summary>
/// Gets the permission overwrite object that was created. /// Gets the permission overwrite object that was created.
/// </summary> /// </summary>
/// <returns> /// <returns>


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

@@ -10,8 +10,9 @@ namespace Discord.Rest
/// </summary> /// </summary>
public class OverwriteDeleteAuditLogData : IAuditLogData public class OverwriteDeleteAuditLogData : IAuditLogData
{ {
private OverwriteDeleteAuditLogData(Overwrite deletedOverwrite)
private OverwriteDeleteAuditLogData(ulong channelId, Overwrite deletedOverwrite)
{ {
ChannelId = channelId;
Overwrite = deletedOverwrite; Overwrite = deletedOverwrite;
} }


@@ -29,10 +30,18 @@ namespace Discord.Rest
var id = idModel.OldValue.ToObject<ulong>(discord.ApiClient.Serializer); var id = idModel.OldValue.ToObject<ulong>(discord.ApiClient.Serializer);
var allow = allowModel.OldValue.ToObject<ulong>(discord.ApiClient.Serializer); var allow = allowModel.OldValue.ToObject<ulong>(discord.ApiClient.Serializer);


return new OverwriteDeleteAuditLogData(new Overwrite(id, type, new OverwritePermissions(allow, deny)));
return new OverwriteDeleteAuditLogData(entry.TargetId.Value, new Overwrite(id, type, new OverwritePermissions(allow, deny)));
} }


/// <summary> /// <summary>
/// Gets the ID of the channel that the overwrite was deleted from.
/// </summary>
/// <returns>
/// A <see cref="ulong"/> representing the snowflake identifier for the channel that the overwrite was
/// deleted from.
/// </returns>
public ulong ChannelId { get; }
/// <summary>
/// Gets the permission overwrite object that was deleted. /// Gets the permission overwrite object that was deleted.
/// </summary> /// </summary>
/// <returns> /// <returns>


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

@@ -10,8 +10,9 @@ namespace Discord.Rest
/// </summary> /// </summary>
public class OverwriteUpdateAuditLogData : IAuditLogData public class OverwriteUpdateAuditLogData : IAuditLogData
{ {
private OverwriteUpdateAuditLogData(OverwritePermissions before, OverwritePermissions after, ulong targetId, PermissionTarget targetType)
private OverwriteUpdateAuditLogData(ulong channelId, OverwritePermissions before, OverwritePermissions after, ulong targetId, PermissionTarget targetType)
{ {
ChannelId = channelId;
OldPermissions = before; OldPermissions = before;
NewPermissions = after; NewPermissions = after;
OverwriteTargetId = targetId; OverwriteTargetId = targetId;
@@ -28,17 +29,25 @@ namespace Discord.Rest
var beforeAllow = allowModel?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer); var beforeAllow = allowModel?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer);
var afterAllow = allowModel?.NewValue?.ToObject<ulong>(discord.ApiClient.Serializer); var afterAllow = allowModel?.NewValue?.ToObject<ulong>(discord.ApiClient.Serializer);
var beforeDeny = denyModel?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer); var beforeDeny = denyModel?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer);
var afterDeny = denyModel?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer);
var afterDeny = denyModel?.NewValue?.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);


var type = entry.Options.OverwriteType; var type = entry.Options.OverwriteType;


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


/// <summary> /// <summary>
/// Gets the ID of the channel that the overwrite was updated from.
/// </summary>
/// <returns>
/// A <see cref="ulong"/> representing the snowflake identifier for the channel that the overwrite was
/// updated from.
/// </returns>
public ulong ChannelId { get; }
/// <summary>
/// Gets the overwrite permissions before the changes. /// Gets the overwrite permissions before the changes.
/// </summary> /// </summary>
/// <returns> /// <returns>


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

@@ -36,7 +36,7 @@ namespace Discord.Rest
string oldName = nameModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer), string oldName = nameModel?.OldValue?.ToObject<string>(discord.ApiClient.Serializer),
newName = nameModel?.NewValue?.ToObject<string>(discord.ApiClient.Serializer); newName = nameModel?.NewValue?.ToObject<string>(discord.ApiClient.Serializer);
ulong? oldPermissionsRaw = permissionsModel?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer), ulong? oldPermissionsRaw = permissionsModel?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer),
newPermissionsRaw = permissionsModel?.OldValue?.ToObject<ulong>(discord.ApiClient.Serializer);
newPermissionsRaw = permissionsModel?.NewValue?.ToObject<ulong>(discord.ApiClient.Serializer);


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


+ 2
- 1
src/Discord.Net.Rest/Entities/Users/RestUser.cs View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization;
using System.Threading.Tasks; using System.Threading.Tasks;
using Model = Discord.API.User; using Model = Discord.API.User;


@@ -57,7 +58,7 @@ namespace Discord.Rest
if (model.Avatar.IsSpecified) if (model.Avatar.IsSpecified)
AvatarId = model.Avatar.Value; AvatarId = model.Avatar.Value;
if (model.Discriminator.IsSpecified) if (model.Discriminator.IsSpecified)
DiscriminatorValue = ushort.Parse(model.Discriminator.Value);
DiscriminatorValue = ushort.Parse(model.Discriminator.Value, NumberStyles.None, CultureInfo.InvariantCulture);
if (model.Bot.IsSpecified) if (model.Bot.IsSpecified)
IsBot = model.Bot.Value; IsBot = model.Bot.Value;
if (model.Username.IsSpecified) if (model.Username.IsSpecified)


+ 3
- 2
src/Discord.Net.Rest/Net/Converters/UInt64EntityOrIdConverter.cs View File

@@ -1,6 +1,7 @@
using Discord.API;
using Discord.API;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.Globalization;


namespace Discord.Net.Converters namespace Discord.Net.Converters
{ {
@@ -23,7 +24,7 @@ namespace Discord.Net.Converters
{ {
case JsonToken.String: case JsonToken.String:
case JsonToken.Integer: case JsonToken.Integer:
return new EntityOrId<T>(ulong.Parse(reader.ReadAsString()));
return new EntityOrId<T>(ulong.Parse(reader.ReadAsString(), NumberStyles.None, CultureInfo.InvariantCulture));
default: default:
T obj; T obj;
if (_innerConverter != null) if (_innerConverter != null)


+ 7
- 7
src/Discord.Net.Rest/Net/RateLimitInfo.cs View File

@@ -11,7 +11,7 @@ namespace Discord.Net
public int? Remaining { get; } public int? Remaining { get; }
public int? RetryAfter { get; } public int? RetryAfter { get; }
public DateTimeOffset? Reset { get; } public DateTimeOffset? Reset { get; }
public TimeSpan? ResetAfter { get; }
public TimeSpan? ResetAfter { get; }
public TimeSpan? Lag { get; } public TimeSpan? Lag { get; }


internal RateLimitInfo(Dictionary<string, string> headers) internal RateLimitInfo(Dictionary<string, string> headers)
@@ -19,17 +19,17 @@ namespace Discord.Net
IsGlobal = headers.TryGetValue("X-RateLimit-Global", out string temp) && IsGlobal = headers.TryGetValue("X-RateLimit-Global", out string temp) &&
bool.TryParse(temp, out var isGlobal) && isGlobal; bool.TryParse(temp, out var isGlobal) && isGlobal;
Limit = headers.TryGetValue("X-RateLimit-Limit", out temp) && Limit = headers.TryGetValue("X-RateLimit-Limit", out temp) &&
int.TryParse(temp, out var limit) ? limit : (int?)null;
int.TryParse(temp, NumberStyles.None, CultureInfo.InvariantCulture, out var limit) ? limit : (int?)null;
Remaining = headers.TryGetValue("X-RateLimit-Remaining", out temp) && Remaining = headers.TryGetValue("X-RateLimit-Remaining", out temp) &&
int.TryParse(temp, out var remaining) ? remaining : (int?)null;
int.TryParse(temp, NumberStyles.None, CultureInfo.InvariantCulture, out var remaining) ? remaining : (int?)null;
Reset = headers.TryGetValue("X-RateLimit-Reset", out temp) && Reset = headers.TryGetValue("X-RateLimit-Reset", out temp) &&
double.TryParse(temp, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var reset) ? DateTimeOffset.FromUnixTimeMilliseconds((long)(reset * 1000)) : (DateTimeOffset?)null; double.TryParse(temp, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var reset) ? DateTimeOffset.FromUnixTimeMilliseconds((long)(reset * 1000)) : (DateTimeOffset?)null;
RetryAfter = headers.TryGetValue("Retry-After", out temp) && RetryAfter = headers.TryGetValue("Retry-After", out temp) &&
int.TryParse(temp, out var retryAfter) ? retryAfter : (int?)null;
ResetAfter = headers.TryGetValue("X-RateLimit-Reset-After", out temp) &&
float.TryParse(temp, out var resetAfter) ? TimeSpan.FromMilliseconds((long)(resetAfter * 1000)) : (TimeSpan?)null;
int.TryParse(temp, NumberStyles.None, CultureInfo.InvariantCulture, out var retryAfter) ? retryAfter : (int?)null;
ResetAfter = headers.TryGetValue("X-RateLimit-Reset-After", out temp) &&
float.TryParse(temp, out var resetAfter) ? TimeSpan.FromMilliseconds((long)(resetAfter * 1000)) : (TimeSpan?)null;
Lag = headers.TryGetValue("Date", out temp) && Lag = headers.TryGetValue("Date", out temp) &&
DateTimeOffset.TryParse(temp, out var date) ? DateTimeOffset.UtcNow - date : (TimeSpan?)null;
DateTimeOffset.TryParse(temp, CultureInfo.InvariantCulture, DateTimeStyles.None, out var date) ? DateTimeOffset.UtcNow - date : (TimeSpan?)null;
} }
} }
} }

+ 3
- 2
src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Discord.Rest; using Discord.Rest;
@@ -60,10 +61,10 @@ namespace Discord.WebSocket
} }
if (model.Discriminator.IsSpecified) if (model.Discriminator.IsSpecified)
{ {
var newVal = ushort.Parse(model.Discriminator.Value);
var newVal = ushort.Parse(model.Discriminator.Value, NumberStyles.None, CultureInfo.InvariantCulture);
if (newVal != DiscriminatorValue) if (newVal != DiscriminatorValue)
{ {
DiscriminatorValue = ushort.Parse(model.Discriminator.Value);
DiscriminatorValue = ushort.Parse(model.Discriminator.Value, NumberStyles.None, CultureInfo.InvariantCulture);
hasChanges = true; hasChanges = true;
} }
} }


+ 2
- 1
src/Discord.Net.Webhook/DiscordWebhookClient.cs View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -132,7 +133,7 @@ namespace Discord.Webhook
{ {
// ensure that the first group is a ulong, set the _webhookId // ensure that the first group is a ulong, set the _webhookId
// 0th group is always the entire match, so start at index 1 // 0th group is always the entire match, so start at index 1
if (!(match.Groups[1].Success && ulong.TryParse(match.Groups[1].Value, out webhookId)))
if (!(match.Groups[1].Success && ulong.TryParse(match.Groups[1].Value, NumberStyles.None, CultureInfo.InvariantCulture, out webhookId)))
throw ex("The webhook Id could not be parsed."); throw ex("The webhook Id could not be parsed.");


if (!match.Groups[2].Success) if (!match.Groups[2].Success)


+ 2
- 0
test/Discord.Net.Tests.Unit/ChannelPermissionsTests.cs View File

@@ -82,6 +82,7 @@ namespace Discord
AssertFlag(() => new ChannelPermissions(moveMembers: true), ChannelPermission.MoveMembers); AssertFlag(() => new ChannelPermissions(moveMembers: true), ChannelPermission.MoveMembers);
AssertFlag(() => new ChannelPermissions(useVoiceActivation: true), ChannelPermission.UseVAD); AssertFlag(() => new ChannelPermissions(useVoiceActivation: true), ChannelPermission.UseVAD);
AssertFlag(() => new ChannelPermissions(prioritySpeaker: true), ChannelPermission.PrioritySpeaker); AssertFlag(() => new ChannelPermissions(prioritySpeaker: true), ChannelPermission.PrioritySpeaker);
AssertFlag(() => new ChannelPermissions(stream: true), ChannelPermission.Stream);
AssertFlag(() => new ChannelPermissions(manageRoles: true), ChannelPermission.ManageRoles); AssertFlag(() => new ChannelPermissions(manageRoles: true), ChannelPermission.ManageRoles);
AssertFlag(() => new ChannelPermissions(manageWebhooks: true), ChannelPermission.ManageWebhooks); AssertFlag(() => new ChannelPermissions(manageWebhooks: true), ChannelPermission.ManageWebhooks);
} }
@@ -147,6 +148,7 @@ namespace Discord
AssertUtil(ChannelPermission.ManageRoles, x => x.ManageRoles, (p, enable) => p.Modify(manageRoles: enable)); AssertUtil(ChannelPermission.ManageRoles, x => x.ManageRoles, (p, enable) => p.Modify(manageRoles: enable));
AssertUtil(ChannelPermission.ManageWebhooks, x => x.ManageWebhooks, (p, enable) => p.Modify(manageWebhooks: enable)); AssertUtil(ChannelPermission.ManageWebhooks, x => x.ManageWebhooks, (p, enable) => p.Modify(manageWebhooks: enable));
AssertUtil(ChannelPermission.PrioritySpeaker, x => x.PrioritySpeaker, (p, enable) => p.Modify(prioritySpeaker: enable)); AssertUtil(ChannelPermission.PrioritySpeaker, x => x.PrioritySpeaker, (p, enable) => p.Modify(prioritySpeaker: enable));
AssertUtil(ChannelPermission.Stream, x => x.Stream, (p, enable) => p.Modify(stream: enable));
} }


/// <summary> /// <summary>


+ 1
- 0
test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs View File

@@ -85,6 +85,7 @@ namespace Discord
AssertFlag(() => new GuildPermissions(moveMembers: true), GuildPermission.MoveMembers); AssertFlag(() => new GuildPermissions(moveMembers: true), GuildPermission.MoveMembers);
AssertFlag(() => new GuildPermissions(useVoiceActivation: true), GuildPermission.UseVAD); AssertFlag(() => new GuildPermissions(useVoiceActivation: true), GuildPermission.UseVAD);
AssertFlag(() => new GuildPermissions(prioritySpeaker: true), GuildPermission.PrioritySpeaker); AssertFlag(() => new GuildPermissions(prioritySpeaker: true), GuildPermission.PrioritySpeaker);
AssertFlag(() => new GuildPermissions(stream: true), GuildPermission.Stream);
AssertFlag(() => new GuildPermissions(changeNickname: true), GuildPermission.ChangeNickname); AssertFlag(() => new GuildPermissions(changeNickname: true), GuildPermission.ChangeNickname);
AssertFlag(() => new GuildPermissions(manageNicknames: true), GuildPermission.ManageNicknames); AssertFlag(() => new GuildPermissions(manageNicknames: true), GuildPermission.ManageNicknames);
AssertFlag(() => new GuildPermissions(manageRoles: true), GuildPermission.ManageRoles); AssertFlag(() => new GuildPermissions(manageRoles: true), GuildPermission.ManageRoles);


Loading…
Cancel
Save