| @@ -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()); | ||||
| } | } | ||||
| } | } | ||||
| @@ -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}"; | ||||
| @@ -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> | ||||
| @@ -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); | ||||
| @@ -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> | ||||
| @@ -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 | ||||
| @@ -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) | ||||
| @@ -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); | ||||
| @@ -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> | ||||
| @@ -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> | ||||
| @@ -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; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -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); | ||||
| } | } | ||||
| @@ -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; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -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); | ||||
| } | } | ||||
| @@ -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; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -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; } | ||||
| } | } | ||||
| } | } | ||||
| @@ -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,9 +31,17 @@ 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> | |||||
| /// 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> | /// <summary> | ||||
| /// Gets the permission overwrite object that was created. | /// Gets the permission overwrite object that was created. | ||||
| /// </summary> | /// </summary> | ||||
| @@ -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,9 +30,17 @@ 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> | |||||
| /// 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> | /// <summary> | ||||
| /// Gets the permission overwrite object that was deleted. | /// Gets the permission overwrite object that was deleted. | ||||
| /// </summary> | /// </summary> | ||||
| @@ -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,16 +29,24 @@ 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> | |||||
| /// 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> | /// <summary> | ||||
| /// Gets the overwrite permissions before the changes. | /// Gets the overwrite permissions before the changes. | ||||
| /// </summary> | /// </summary> | ||||
| @@ -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; | ||||
| @@ -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) | ||||
| @@ -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) | ||||
| @@ -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; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -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; | ||||
| } | } | ||||
| } | } | ||||
| @@ -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) | ||||
| @@ -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> | ||||
| @@ -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); | ||||