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

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

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

@@ -180,7 +180,7 @@ namespace Discord.Commands
return ParseResult.FromError(CommandError.ParseFailed, "Input text may not end on an incomplete escape.");
if (curPart == ParserPart.QuotedParameter)
return ParseResult.FromError(CommandError.ParseFailed, "A quoted parameter is incomplete.");
//Add missing optionals
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.");
argList.Add(TypeReaderResult.FromSuccess(param.DefaultValue));
}
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/>
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/>
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;
ParamValues = paramValues;
Error = error;
ErrorReason = errorReason;
ErrorParameter = errorParamInfo;
}
public static ParseResult FromSuccess(IReadOnlyList<TypeReaderResult> argValues, IReadOnlyList<TypeReaderResult> paramValues)
{
for (int i = 0; i < argValues.Count; i++)
{
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++)
{
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)
{
@@ -55,15 +65,19 @@ namespace Discord.Commands
for (int i = 0; i < paramValues.Count; 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)
=> 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)
=> FromError(CommandError.Exception, ex.Message);
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}";
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>
UseVAD = 0x02_00_00_00,
PrioritySpeaker = 0x00_00_01_00,
/// <summary>
/// Allows video streaming in a voice channel.
/// </summary>
Stream = 0x00_00_02_00,

// More General
/// <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>
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>
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>
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>
@@ -82,6 +82,8 @@ namespace Discord
public bool UseVAD => Permissions.GetValue(RawValue, ChannelPermission.UseVAD);
/// <summary> If <c>true</c>, a user may use priority speaker in a voice channel. </summary>
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>
public bool ManageRoles => Permissions.GetValue(RawValue, ChannelPermission.ManageRoles);
@@ -111,6 +113,7 @@ namespace Discord
bool? moveMembers = null,
bool? useVoiceActivation = null,
bool? prioritySpeaker = null,
bool? stream = null,
bool? manageRoles = null,
bool? manageWebhooks = null)
{
@@ -135,6 +138,7 @@ namespace Discord
Permissions.SetValue(ref value, moveMembers, ChannelPermission.MoveMembers);
Permissions.SetValue(ref value, useVoiceActivation, ChannelPermission.UseVAD);
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, manageWebhooks, ChannelPermission.ManageWebhooks);

@@ -162,11 +166,12 @@ namespace Discord
bool moveMembers = false,
bool useVoiceActivation = false,
bool prioritySpeaker = false,
bool stream = false,
bool manageRoles = false,
bool manageWebhooks = false)
: this(0, createInstantInvite, manageChannel, addReactions, viewChannel, sendMessages, sendTTSMessages, manageMessages,
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>
@@ -190,6 +195,7 @@ namespace Discord
bool? moveMembers = null,
bool? useVoiceActivation = null,
bool? prioritySpeaker = null,
bool? stream = null,
bool? manageRoles = null,
bool? manageWebhooks = null)
=> new ChannelPermissions(RawValue,
@@ -212,6 +218,7 @@ namespace Discord
moveMembers,
useVoiceActivation,
prioritySpeaker,
stream,
manageRoles,
manageWebhooks);



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

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

// General 2
/// <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>
public static readonly GuildPermissions Webhook = new GuildPermissions(0b00000_0000000_0001101100000_000000);
/// <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>
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>
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);
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>
public bool ChangeNickname => Permissions.GetValue(RawValue, GuildPermission.ChangeNickname);
@@ -111,6 +113,7 @@ namespace Discord
bool? moveMembers = null,
bool? useVoiceActivation = null,
bool? prioritySpeaker = null,
bool? stream = null,
bool? changeNickname = null,
bool? manageNicknames = null,
bool? manageRoles = null,
@@ -143,6 +146,7 @@ namespace Discord
Permissions.SetValue(ref value, moveMembers, GuildPermission.MoveMembers);
Permissions.SetValue(ref value, useVoiceActivation, GuildPermission.UseVAD);
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, manageNicknames, GuildPermission.ManageNicknames);
Permissions.SetValue(ref value, manageRoles, GuildPermission.ManageRoles);
@@ -178,6 +182,7 @@ namespace Discord
bool moveMembers = false,
bool useVoiceActivation = false,
bool prioritySpeaker = false,
bool stream = false,
bool changeNickname = false,
bool manageNicknames = false,
bool manageRoles = false,
@@ -209,6 +214,7 @@ namespace Discord
moveMembers: moveMembers,
useVoiceActivation: useVoiceActivation,
prioritySpeaker: prioritySpeaker,
stream: stream,
changeNickname: changeNickname,
manageNicknames: manageNicknames,
manageWebhooks: manageWebhooks,
@@ -241,6 +247,7 @@ namespace Discord
bool? moveMembers = null,
bool? useVoiceActivation = null,
bool? prioritySpeaker = null,
bool? stream = null,
bool? changeNickname = null,
bool? manageNicknames = null,
bool? manageRoles = null,
@@ -249,7 +256,7 @@ namespace Discord
=> new GuildPermissions(RawValue, createInstantInvite, kickMembers, banMembers, administrator, manageChannels, manageGuild, addReactions,
viewAuditLog, viewChannel, sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles,
readMessageHistory, mentionEveryone, useExternalEmojis, connect, speak, muteMembers, deafenMembers, moveMembers,
useVoiceActivation, prioritySpeaker, changeNickname, manageNicknames, manageRoles, manageWebhooks, manageEmojis);
useVoiceActivation, prioritySpeaker, stream, changeNickname, manageNicknames, manageRoles, manageWebhooks, manageEmojis);

/// <summary>
/// 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.Globalization;
using System.Text;

namespace Discord
@@ -76,7 +77,7 @@ namespace Discord
var bytes = Convert.FromBase64String(encoded);
var idStr = Encoding.UTF8.GetString(bytes);
// 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;
}
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);
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]);

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>
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;
ChannelName = name;
ChannelType = type;
SlowModeInterval = rateLimit;
IsNsfw = nsfw;
Bitrate = bitrate;
Overwrites = overwrites;
}

@@ -27,9 +30,15 @@ namespace Discord.Rest
var overwritesModel = changes.FirstOrDefault(x => x.ChangedProperty == "permission_overwrites");
var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type");
var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name");
var rateLimitPerUserModel = changes.FirstOrDefault(x => x.ChangedProperty == "rate_limit_per_user");
var nsfwModel = changes.FirstOrDefault(x => x.ChangedProperty == "nsfw");
var bitrateModel = changes.FirstOrDefault(x => x.ChangedProperty == "bitrate");

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

foreach (var overwrite in overwritesModel.NewValue)
{
@@ -41,7 +50,7 @@ namespace Discord.Rest
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>
@@ -66,6 +75,32 @@ namespace Discord.Rest
/// </returns>
public ChannelType ChannelType { get; }
/// <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.
/// </summary>
/// <returns>


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

@@ -11,11 +11,14 @@ namespace Discord.Rest
/// </summary>
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;
ChannelName = name;
ChannelType = type;
SlowModeInterval = rateLimit;
IsNsfw = nsfw;
Bitrate = bitrate;
Overwrites = overwrites;
}

@@ -26,15 +29,21 @@ namespace Discord.Rest
var overwritesModel = changes.FirstOrDefault(x => x.ChangedProperty == "permission_overwrites");
var typeModel = changes.FirstOrDefault(x => x.ChangedProperty == "type");
var nameModel = changes.FirstOrDefault(x => x.ChangedProperty == "name");
var rateLimitPerUserModel = changes.FirstOrDefault(x => x.ChangedProperty == "rate_limit_per_user");
var nsfwModel = changes.FirstOrDefault(x => x.ChangedProperty == "nsfw");
var bitrateModel = changes.FirstOrDefault(x => x.ChangedProperty == "bitrate");

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

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

/// <summary>
@@ -59,6 +68,31 @@ namespace Discord.Rest
/// </returns>
public ChannelType ChannelType { get; }
/// <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.
/// </summary>
/// <returns>


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

@@ -5,12 +5,13 @@ namespace Discord.Rest
/// </summary>
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;
Topic = topic;
SlowModeInterval = rateLimit;
IsNsfw = nsfw;
Bitrate = bitrate;
UserLimit = limit;
}

/// <summary>
@@ -28,20 +29,29 @@ namespace Discord.Rest
/// </returns>
public string Topic { get; }
/// <summary>
/// Gets the bit-rate of this channel if applicable.
/// Gets the current slow-mode delay of this channel.
/// </summary>
/// <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>
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>
/// Gets the number of users allowed to be in this channel if applicable.
/// Gets the bit-rate of this channel if applicable.
/// </summary>
/// <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>
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 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 userLimitModel = changes.FirstOrDefault(x => x.ChangedProperty == "user_limit");

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? oldRateLimitPerUser = rateLimitPerUserModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer),
newRateLimitPerUser = rateLimitPerUserModel?.NewValue?.ToObject<int>(discord.ApiClient.Serializer);
bool? oldNsfw = nsfwModel?.OldValue?.ToObject<bool>(discord.ApiClient.Serializer),
newNsfw = nsfwModel?.NewValue?.ToObject<bool>(discord.ApiClient.Serializer);
int? oldBitrate = bitrateModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer),
newBitrate = bitrateModel?.NewValue?.ToObject<int>(discord.ApiClient.Serializer);
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);
}


+ 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,
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;
DefaultMessageNotifications = defaultNotifs;
@@ -18,7 +19,10 @@ namespace Discord.Rest
VerificationLevel = verification;
Owner = owner;
MfaLevel = mfa;
ContentFilterLevel = filter;
ExplicitContentFilter = filter;
SystemChannelId = systemChannel;
EmbedChannelId = widgetChannel;
IsEmbeddable = widget;
}

/// <summary>
@@ -28,11 +32,16 @@ namespace Discord.Rest
/// <returns>
/// 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.
/// <c>null</c> if this is not mentioned in this entry.
/// </returns>
public int? AfkTimeout { get; }
/// <summary>
/// Gets the default message notifications for users who haven't explicitly set their notification settings.
/// </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; }
/// <summary>
/// Gets the ID of the AFK voice channel for this guild.
@@ -65,6 +74,7 @@ namespace Discord.Rest
/// </summary>
/// <returns>
/// The level of requirements.
/// <c>null</c> if this is not mentioned in this entry.
/// </returns>
public VerificationLevel? VerificationLevel { get; }
/// <summary>
@@ -80,8 +90,39 @@ namespace Discord.Rest
/// </summary>
/// <returns>
/// The level of MFA requirement.
/// <c>null</c> if this is not mentioned in this entry.
/// </returns>
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 mfaLevelModel = changes.FirstOrDefault(x => x.ChangedProperty == "mfa_level");
var contentFilterModel = changes.FirstOrDefault(x => x.ChangedProperty == "explicit_content_filter");
var systemChannelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "system_channel_id");
var widgetChannelIdModel = changes.FirstOrDefault(x => x.ChangedProperty == "widget_channel_id");
var widgetEnabledModel = changes.FirstOrDefault(x => x.ChangedProperty == "widget_enabled");

int? oldAfkTimeout = afkTimeoutModel?.OldValue?.ToObject<int>(discord.ApiClient.Serializer),
newAfkTimeout = afkTimeoutModel?.NewValue?.ToObject<int>(discord.ApiClient.Serializer);
@@ -49,8 +52,14 @@ namespace Discord.Rest
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);
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;
if (oldOwnerId != null)
@@ -68,10 +77,10 @@ namespace Discord.Rest

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

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
{
/// <summary>
/// Represents information for a member.
/// </summary>
public struct MemberInfo
{
internal MemberInfo(string nick, bool? deaf, bool? mute, string avatar_hash)
internal MemberInfo(string nick, bool? deaf, bool? mute)
{
Nickname = nick;
Deaf = deaf;
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; }
/// <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; }
/// <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 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 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);
@@ -32,14 +31,12 @@ namespace Discord.Rest
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 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);
}
@@ -51,7 +48,19 @@ namespace Discord.Rest
/// A user object representing the user who the changes were performed on.
/// </returns>
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; }
/// <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; }
}
}

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

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

@@ -30,10 +31,18 @@ namespace Discord.Rest
var id = entry.Options.OverwriteTargetId.Value;
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>
/// 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.
/// </summary>
/// <returns>


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

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

@@ -29,10 +30,18 @@ namespace Discord.Rest
var id = idModel.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>
/// 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.
/// </summary>
/// <returns>


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

@@ -10,8 +10,9 @@ namespace Discord.Rest
/// </summary>
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;
NewPermissions = after;
OverwriteTargetId = targetId;
@@ -28,17 +29,25 @@ namespace Discord.Rest
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 afterDeny = denyModel?.NewValue?.ToObject<ulong>(discord.ApiClient.Serializer);

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

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>
/// 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.
/// </summary>
/// <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),
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);
newPermissionsRaw = permissionsModel?.NewValue?.ToObject<ulong>(discord.ApiClient.Serializer);

Color? oldColor = null,
newColor = null;


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

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

@@ -57,7 +58,7 @@ namespace Discord.Rest
if (model.Avatar.IsSpecified)
AvatarId = model.Avatar.Value;
if (model.Discriminator.IsSpecified)
DiscriminatorValue = ushort.Parse(model.Discriminator.Value);
DiscriminatorValue = ushort.Parse(model.Discriminator.Value, NumberStyles.None, CultureInfo.InvariantCulture);
if (model.Bot.IsSpecified)
IsBot = model.Bot.Value;
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 System;
using System.Globalization;

namespace Discord.Net.Converters
{
@@ -23,7 +24,7 @@ namespace Discord.Net.Converters
{
case JsonToken.String:
case JsonToken.Integer:
return new EntityOrId<T>(ulong.Parse(reader.ReadAsString()));
return new EntityOrId<T>(ulong.Parse(reader.ReadAsString(), NumberStyles.None, CultureInfo.InvariantCulture));
default:
T obj;
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? RetryAfter { get; }
public DateTimeOffset? Reset { get; }
public TimeSpan? ResetAfter { get; }
public TimeSpan? ResetAfter { get; }
public TimeSpan? Lag { get; }

internal RateLimitInfo(Dictionary<string, string> headers)
@@ -19,17 +19,17 @@ namespace Discord.Net
IsGlobal = headers.TryGetValue("X-RateLimit-Global", out string temp) &&
bool.TryParse(temp, out var isGlobal) && isGlobal;
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) &&
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) &&
double.TryParse(temp, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var reset) ? DateTimeOffset.FromUnixTimeMilliseconds((long)(reset * 1000)) : (DateTimeOffset?)null;
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) &&
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.Immutable;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Discord.Rest;
@@ -60,10 +61,10 @@ namespace Discord.WebSocket
}
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)
{
DiscriminatorValue = ushort.Parse(model.Discriminator.Value);
DiscriminatorValue = ushort.Parse(model.Discriminator.Value, NumberStyles.None, CultureInfo.InvariantCulture);
hasChanges = true;
}
}


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

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
@@ -132,7 +133,7 @@ namespace Discord.Webhook
{
// ensure that the first group is a ulong, set the _webhookId
// 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.");

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(useVoiceActivation: true), ChannelPermission.UseVAD);
AssertFlag(() => new ChannelPermissions(prioritySpeaker: true), ChannelPermission.PrioritySpeaker);
AssertFlag(() => new ChannelPermissions(stream: true), ChannelPermission.Stream);
AssertFlag(() => new ChannelPermissions(manageRoles: true), ChannelPermission.ManageRoles);
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.ManageWebhooks, x => x.ManageWebhooks, (p, enable) => p.Modify(manageWebhooks: 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>


+ 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(useVoiceActivation: true), GuildPermission.UseVAD);
AssertFlag(() => new GuildPermissions(prioritySpeaker: true), GuildPermission.PrioritySpeaker);
AssertFlag(() => new GuildPermissions(stream: true), GuildPermission.Stream);
AssertFlag(() => new GuildPermissions(changeNickname: true), GuildPermission.ChangeNickname);
AssertFlag(() => new GuildPermissions(manageNicknames: true), GuildPermission.ManageNicknames);
AssertFlag(() => new GuildPermissions(manageRoles: true), GuildPermission.ManageRoles);


Loading…
Cancel
Save