@@ -1,4 +1,5 @@ | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text.RegularExpressions; | |||
@@ -12,6 +13,8 @@ namespace Discord | |||
{ | |||
private string _name; | |||
private string _description; | |||
private IDictionary<string, string> _nameLocalizations = new Dictionary<string, string>(); | |||
private IDictionary<string, string> _descriptionLocalizations = new Dictionary<string, string>(); | |||
/// <summary> | |||
/// Gets or sets the name of this option. | |||
@@ -21,18 +24,7 @@ namespace Discord | |||
get => _name; | |||
set | |||
{ | |||
if (value == null) | |||
throw new ArgumentNullException(nameof(value), $"{nameof(Name)} cannot be null."); | |||
if (value.Length > 32) | |||
throw new ArgumentOutOfRangeException(nameof(value), "Name length must be less than or equal to 32."); | |||
if (!Regex.IsMatch(value, @"^[\w-]{1,32}$")) | |||
throw new FormatException($"{nameof(value)} must match the regex ^[\\w-]{{1,32}}$"); | |||
if (value.Any(x => char.IsUpper(x))) | |||
throw new FormatException("Name cannot contain any uppercase characters."); | |||
EnsureValidOptionName(value); | |||
_name = value; | |||
} | |||
} | |||
@@ -43,12 +35,11 @@ namespace Discord | |||
public string Description | |||
{ | |||
get => _description; | |||
set => _description = value?.Length switch | |||
set | |||
{ | |||
> 100 => throw new ArgumentOutOfRangeException(nameof(value), "Description length must be less than or equal to 100."), | |||
0 => throw new ArgumentOutOfRangeException(nameof(value), "Description length must be at least 1."), | |||
_ => value | |||
}; | |||
EnsureValidOptionDescription(value); | |||
_description = value; | |||
} | |||
} | |||
/// <summary> | |||
@@ -95,5 +86,73 @@ namespace Discord | |||
/// Gets or sets the allowed channel types for this option. | |||
/// </summary> | |||
public List<ChannelType> ChannelTypes { get; set; } | |||
public IDictionary<string, string> NameLocalizations | |||
{ | |||
get => _nameLocalizations; | |||
set | |||
{ | |||
foreach (var (locale, name) in value) | |||
{ | |||
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) | |||
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); | |||
EnsureValidOptionName(name); | |||
} | |||
_nameLocalizations = value; | |||
} | |||
} | |||
public IDictionary<string, string> DescriptionLocalizations | |||
{ | |||
get => _descriptionLocalizations; | |||
set | |||
{ | |||
foreach (var (locale, description) in value) | |||
{ | |||
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) | |||
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); | |||
EnsureValidOptionDescription(description); | |||
} | |||
_nameLocalizations = value; | |||
} | |||
} | |||
private static void EnsureValidOptionName(string name) | |||
{ | |||
if (name == null) | |||
throw new ArgumentNullException(nameof(name), $"{nameof(Name)} cannot be null."); | |||
if (name.Length > 32) | |||
throw new ArgumentOutOfRangeException(nameof(name), "Name length must be less than or equal to 32."); | |||
if (!Regex.IsMatch(name, @"^[\w-]{1,32}$")) | |||
throw new FormatException($"{nameof(name)} must match the regex ^[\\w-]{{1,32}}$"); | |||
if (name.Any(x => char.IsUpper(x))) | |||
throw new FormatException("Name cannot contain any uppercase characters."); | |||
} | |||
private static void EnsureValidOptionDescription(string description) | |||
{ | |||
switch (description.Length) | |||
{ | |||
case > 100: | |||
throw new ArgumentOutOfRangeException(nameof(description), | |||
"Description length must be less than or equal to 100."); | |||
case 0: | |||
throw new ArgumentOutOfRangeException(nameof(description), "Description length must at least 1."); | |||
} | |||
} | |||
} | |||
public static class Test | |||
{ | |||
public static void Deconstruct<T1, T2>(this KeyValuePair<T1, T2> kvp, out T1 key, out T2 value) | |||
{ | |||
key = kvp.Key; | |||
value = kvp.Value; | |||
} | |||
} | |||
} |
@@ -1,4 +1,8 @@ | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text.RegularExpressions; | |||
namespace Discord | |||
{ | |||
@@ -9,6 +13,7 @@ namespace Discord | |||
{ | |||
private string _name; | |||
private object _value; | |||
private IDictionary<string, string> _nameLocalizations = new Dictionary<string, string>(); | |||
/// <summary> | |||
/// Gets or sets the name of this choice. | |||
@@ -40,5 +45,29 @@ namespace Discord | |||
_value = value; | |||
} | |||
} | |||
public IDictionary<string, string> NameLocalizations | |||
{ | |||
get => _nameLocalizations; | |||
set | |||
{ | |||
foreach (var (locale, name) in value) | |||
{ | |||
if (!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) | |||
throw new ArgumentException("Key values of the dictionary must be valid language codes."); | |||
switch (name.Length) | |||
{ | |||
case > 100: | |||
throw new ArgumentOutOfRangeException(nameof(value), | |||
"Name length must be less than or equal to 100."); | |||
case 0: | |||
throw new ArgumentOutOfRangeException(nameof(value), "Name length must at least 1."); | |||
} | |||
} | |||
_nameLocalizations = value; | |||
} | |||
} | |||
} | |||
} |
@@ -1,3 +1,6 @@ | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
namespace Discord | |||
{ | |||
/// <summary> | |||
@@ -17,6 +20,10 @@ namespace Discord | |||
/// </summary> | |||
public Optional<bool> IsDefaultPermission { get; set; } | |||
public Optional<IDictionary<string, string>> NameLocalizations { get; set; } | |||
public Optional<IDictionary<string, string>> DescriptionLocalizations { get; set; } | |||
internal ApplicationCommandProperties() { } | |||
} | |||
} |
@@ -39,6 +39,14 @@ namespace Discord | |||
/// </summary> | |||
IReadOnlyCollection<IApplicationCommandOption> Options { get; } | |||
IReadOnlyDictionary<string, string>? NameLocalizations { get; } | |||
IReadOnlyDictionary<string, string>? DescriptionLocalizations { get; } | |||
string? NameLocalized { get; } | |||
string? DescriptionLocalized { get; } | |||
/// <summary> | |||
/// Modifies the current application command. | |||
/// </summary> | |||
@@ -61,5 +61,13 @@ namespace Discord | |||
/// Gets the allowed channel types for this option. | |||
/// </summary> | |||
IReadOnlyCollection<ChannelType> ChannelTypes { get; } | |||
IReadOnlyDictionary<string, string>? NameLocalizations { get; } | |||
IReadOnlyDictionary<string, string>? DescriptionLocalizations { get; } | |||
string? NameLocalized { get; } | |||
string? DescriptionLocalized { get; } | |||
} | |||
} |
@@ -1,3 +1,5 @@ | |||
using System.Collections.Generic; | |||
namespace Discord | |||
{ | |||
/// <summary> | |||
@@ -14,5 +16,9 @@ namespace Discord | |||
/// Gets the value of the choice. | |||
/// </summary> | |||
object Value { get; } | |||
IReadOnlyDictionary<string, string>? NameLocalizations { get; } | |||
string? NameLocalized { get; } | |||
} | |||
} |
@@ -1,6 +1,9 @@ | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
using System.Collections.Immutable; | |||
using System.Linq; | |||
using System.Net.Sockets; | |||
using System.Text.RegularExpressions; | |||
namespace Discord | |||
@@ -76,6 +79,10 @@ namespace Discord | |||
} | |||
} | |||
public IReadOnlyDictionary<string, string> NameLocalizations => _nameLocalizations; | |||
public IReadOnlyDictionary<string, string> DescriptionLocalizations => _descriptionLocalizations; | |||
/// <summary> | |||
/// Gets or sets whether the command is enabled by default when the app is added to a guild | |||
/// </summary> | |||
@@ -83,6 +90,8 @@ namespace Discord | |||
private string _name; | |||
private string _description; | |||
private Dictionary<string, string> _nameLocalizations; | |||
private Dictionary<string, string> _descriptionLocalizations; | |||
private List<SlashCommandOptionBuilder> _options; | |||
/// <summary> | |||
@@ -96,6 +105,8 @@ namespace Discord | |||
Name = Name, | |||
Description = Description, | |||
IsDefaultPermission = IsDefaultPermission, | |||
NameLocalizations = _nameLocalizations, | |||
DescriptionLocalizations = _descriptionLocalizations, | |||
}; | |||
if (Options != null && Options.Any()) | |||
@@ -162,7 +173,8 @@ namespace Discord | |||
/// <returns>The current builder.</returns> | |||
public SlashCommandBuilder AddOption(string name, ApplicationCommandOptionType type, | |||
string description, bool? isRequired = null, bool? isDefault = null, bool isAutocomplete = false, double? minValue = null, double? maxValue = null, | |||
List<SlashCommandOptionBuilder> options = null, List<ChannelType> channelTypes = null, params ApplicationCommandOptionChoiceProperties[] choices) | |||
List<SlashCommandOptionBuilder> options = null, List<ChannelType> channelTypes = null, IDictionary<string, string> nameLocalizations = null, | |||
IDictionary<string, string> descriptionLocalizations = null, params ApplicationCommandOptionChoiceProperties[] choices) | |||
{ | |||
// Make sure the name matches the requirements from discord | |||
Preconditions.NotNullOrEmpty(name, nameof(name)); | |||
@@ -195,9 +207,15 @@ namespace Discord | |||
Choices = (choices ?? Array.Empty<ApplicationCommandOptionChoiceProperties>()).ToList(), | |||
ChannelTypes = channelTypes, | |||
MinValue = minValue, | |||
MaxValue = maxValue, | |||
MaxValue = maxValue | |||
}; | |||
if (nameLocalizations is not null) | |||
option.WithNameLocalizations(nameLocalizations); | |||
if (descriptionLocalizations is not null) | |||
option.WithDescriptionLocalizations(descriptionLocalizations); | |||
return AddOption(option); | |||
} | |||
@@ -239,6 +257,74 @@ namespace Discord | |||
Options.AddRange(options); | |||
return this; | |||
} | |||
public SlashCommandBuilder WithNameLocalizations(IDictionary<string, string> nameLocalizations) | |||
{ | |||
if (nameLocalizations is null) | |||
throw new ArgumentNullException(nameof(nameLocalizations)); | |||
foreach (var (locale, name) in nameLocalizations) | |||
{ | |||
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) | |||
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); | |||
Preconditions.AtLeast(name.Length, 1, nameof(name)); | |||
Preconditions.AtMost(name.Length, SlashCommandBuilder.MaxNameLength, nameof(name)); | |||
if (!Regex.IsMatch(name, @"^[\w-]{1,32}$")) | |||
throw new ArgumentException("Option name cannot contain any special characters or whitespaces!", nameof(name)); | |||
} | |||
_nameLocalizations = new Dictionary<string, string>(nameLocalizations); | |||
return this; | |||
} | |||
public SlashCommandBuilder WithDescriptionLocalizations(IDictionary<string, string> descriptionLocalizations) | |||
{ | |||
if (descriptionLocalizations is null) | |||
throw new ArgumentNullException(nameof(descriptionLocalizations)); | |||
foreach (var (locale, description) in _descriptionLocalizations) | |||
{ | |||
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) | |||
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); | |||
Preconditions.AtLeast(description.Length, 1, nameof(description)); | |||
Preconditions.AtMost(description.Length, SlashCommandBuilder.MaxDescriptionLength, nameof(description)); | |||
} | |||
_descriptionLocalizations = new Dictionary<string, string>(descriptionLocalizations); | |||
return this; | |||
} | |||
public SlashCommandBuilder AddNameLocalization(string locale, string name) | |||
{ | |||
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) | |||
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); | |||
Preconditions.AtLeast(name.Length, 1, nameof(name)); | |||
Preconditions.AtMost(name.Length, SlashCommandBuilder.MaxNameLength, nameof(name)); | |||
if (!Regex.IsMatch(name, @"^[\w-]{1,32}$")) | |||
throw new ArgumentException("Option name cannot contain any special characters or whitespaces!", nameof(name)); | |||
_descriptionLocalizations ??= new(); | |||
_nameLocalizations.Add(locale, name); | |||
return this; | |||
} | |||
public SlashCommandBuilder AddDescriptionLocalization(string locale, string description) | |||
{ | |||
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) | |||
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); | |||
Preconditions.AtLeast(description.Length, 1, nameof(description)); | |||
Preconditions.AtMost(description.Length, SlashCommandBuilder.MaxDescriptionLength, nameof(description)); | |||
_descriptionLocalizations ??= new(); | |||
_descriptionLocalizations.Add(locale, description); | |||
return this; | |||
} | |||
} | |||
/// <summary> | |||
@@ -258,6 +344,8 @@ namespace Discord | |||
private string _name; | |||
private string _description; | |||
private Dictionary<string, string> _nameLocalizations; | |||
private Dictionary<string, string> _descriptionLocalizations; | |||
/// <summary> | |||
/// Gets or sets the name of this option. | |||
@@ -342,6 +430,10 @@ namespace Discord | |||
/// </summary> | |||
public List<ChannelType> ChannelTypes { get; set; } | |||
public IReadOnlyDictionary<string, string> NameLocalizations => _nameLocalizations; | |||
public IReadOnlyDictionary<string, string> DescriptionLocalizations => _descriptionLocalizations; | |||
/// <summary> | |||
/// Builds the current option. | |||
/// </summary> | |||
@@ -377,7 +469,9 @@ namespace Discord | |||
IsAutocomplete = IsAutocomplete, | |||
ChannelTypes = ChannelTypes, | |||
MinValue = MinValue, | |||
MaxValue = MaxValue | |||
MaxValue = MaxValue, | |||
NameLocalizations = _nameLocalizations, | |||
DescriptionLocalizations = _descriptionLocalizations | |||
}; | |||
} | |||
@@ -398,7 +492,8 @@ namespace Discord | |||
/// <returns>The current builder.</returns> | |||
public SlashCommandOptionBuilder AddOption(string name, ApplicationCommandOptionType type, | |||
string description, bool? isRequired = null, bool isDefault = false, bool isAutocomplete = false, double? minValue = null, double? maxValue = null, | |||
List<SlashCommandOptionBuilder> options = null, List<ChannelType> channelTypes = null, params ApplicationCommandOptionChoiceProperties[] choices) | |||
List<SlashCommandOptionBuilder> options = null, List<ChannelType> channelTypes = null, IDictionary<string, string> nameLocalizations = null, | |||
IDictionary<string, string> descriptionLocalizations = null, params ApplicationCommandOptionChoiceProperties[] choices) | |||
{ | |||
// Make sure the name matches the requirements from discord | |||
Preconditions.NotNullOrEmpty(name, nameof(name)); | |||
@@ -431,9 +526,15 @@ namespace Discord | |||
Options = options, | |||
Type = type, | |||
Choices = (choices ?? Array.Empty<ApplicationCommandOptionChoiceProperties>()).ToList(), | |||
ChannelTypes = channelTypes | |||
ChannelTypes = channelTypes, | |||
}; | |||
if(nameLocalizations is not null) | |||
option.WithNameLocalizations(nameLocalizations); | |||
if(descriptionLocalizations is not null) | |||
option.WithDescriptionLocalizations(descriptionLocalizations); | |||
return AddOption(option); | |||
} | |||
/// <summary> | |||
@@ -460,9 +561,9 @@ namespace Discord | |||
/// <param name="name">The name of the choice.</param> | |||
/// <param name="value">The value of the choice.</param> | |||
/// <returns>The current builder.</returns> | |||
public SlashCommandOptionBuilder AddChoice(string name, int value) | |||
public SlashCommandOptionBuilder AddChoice(string name, int value, IDictionary<string, string> nameLocalizations = null) | |||
{ | |||
return AddChoiceInternal(name, value); | |||
return AddChoiceInternal(name, value, nameLocalizations); | |||
} | |||
/// <summary> | |||
@@ -471,9 +572,9 @@ namespace Discord | |||
/// <param name="name">The name of the choice.</param> | |||
/// <param name="value">The value of the choice.</param> | |||
/// <returns>The current builder.</returns> | |||
public SlashCommandOptionBuilder AddChoice(string name, string value) | |||
public SlashCommandOptionBuilder AddChoice(string name, string value, IDictionary<string, string> nameLocalizations = null) | |||
{ | |||
return AddChoiceInternal(name, value); | |||
return AddChoiceInternal(name, value, nameLocalizations); | |||
} | |||
/// <summary> | |||
@@ -482,9 +583,9 @@ namespace Discord | |||
/// <param name="name">The name of the choice.</param> | |||
/// <param name="value">The value of the choice.</param> | |||
/// <returns>The current builder.</returns> | |||
public SlashCommandOptionBuilder AddChoice(string name, double value) | |||
public SlashCommandOptionBuilder AddChoice(string name, double value, IDictionary<string, string> nameLocalizations = null) | |||
{ | |||
return AddChoiceInternal(name, value); | |||
return AddChoiceInternal(name, value, nameLocalizations); | |||
} | |||
/// <summary> | |||
@@ -493,9 +594,9 @@ namespace Discord | |||
/// <param name="name">The name of the choice.</param> | |||
/// <param name="value">The value of the choice.</param> | |||
/// <returns>The current builder.</returns> | |||
public SlashCommandOptionBuilder AddChoice(string name, float value) | |||
public SlashCommandOptionBuilder AddChoice(string name, float value, IDictionary<string, string> nameLocalizations = null) | |||
{ | |||
return AddChoiceInternal(name, value); | |||
return AddChoiceInternal(name, value, nameLocalizations); | |||
} | |||
/// <summary> | |||
@@ -504,12 +605,12 @@ namespace Discord | |||
/// <param name="name">The name of the choice.</param> | |||
/// <param name="value">The value of the choice.</param> | |||
/// <returns>The current builder.</returns> | |||
public SlashCommandOptionBuilder AddChoice(string name, long value) | |||
public SlashCommandOptionBuilder AddChoice(string name, long value, IDictionary<string, string> nameLocalizations = null) | |||
{ | |||
return AddChoiceInternal(name, value); | |||
return AddChoiceInternal(name, value, nameLocalizations); | |||
} | |||
private SlashCommandOptionBuilder AddChoiceInternal(string name, object value) | |||
private SlashCommandOptionBuilder AddChoiceInternal(string name, object value, IDictionary<string, string> nameLocalizations = null) | |||
{ | |||
Choices ??= new List<ApplicationCommandOptionChoiceProperties>(); | |||
@@ -531,7 +632,8 @@ namespace Discord | |||
Choices.Add(new ApplicationCommandOptionChoiceProperties | |||
{ | |||
Name = name, | |||
Value = value | |||
Value = value, | |||
NameLocalizations = nameLocalizations | |||
}); | |||
return this; | |||
@@ -617,7 +719,7 @@ namespace Discord | |||
MinValue = value; | |||
return this; | |||
} | |||
/// <summary> | |||
/// Sets the current builders max value field. | |||
/// </summary> | |||
@@ -639,5 +741,73 @@ namespace Discord | |||
Type = type; | |||
return this; | |||
} | |||
public SlashCommandOptionBuilder WithNameLocalizations(IDictionary<string, string> nameLocalizations) | |||
{ | |||
if (nameLocalizations is null) | |||
throw new ArgumentNullException(nameof(nameLocalizations)); | |||
foreach (var (locale, name) in nameLocalizations) | |||
{ | |||
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) | |||
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); | |||
Preconditions.AtLeast(name.Length, 1, nameof(name)); | |||
Preconditions.AtMost(name.Length, SlashCommandBuilder.MaxNameLength, nameof(name)); | |||
if (!Regex.IsMatch(name, @"^[\w-]{1,32}$")) | |||
throw new ArgumentException("Option name cannot contain any special characters or whitespaces!", nameof(name)); | |||
} | |||
_nameLocalizations = new Dictionary<string, string>(nameLocalizations); | |||
return this; | |||
} | |||
public SlashCommandOptionBuilder WithDescriptionLocalizations(IDictionary<string, string> descriptionLocalizations) | |||
{ | |||
if (descriptionLocalizations is null) | |||
throw new ArgumentNullException(nameof(descriptionLocalizations)); | |||
foreach (var (locale, description) in _descriptionLocalizations) | |||
{ | |||
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) | |||
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); | |||
Preconditions.AtLeast(description.Length, 1, nameof(description)); | |||
Preconditions.AtMost(description.Length, SlashCommandBuilder.MaxDescriptionLength, nameof(description)); | |||
} | |||
_descriptionLocalizations = new Dictionary<string, string>(descriptionLocalizations); | |||
return this; | |||
} | |||
public SlashCommandOptionBuilder AddNameLocalization(string locale, string name) | |||
{ | |||
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) | |||
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); | |||
Preconditions.AtLeast(name.Length, 1, nameof(name)); | |||
Preconditions.AtMost(name.Length, SlashCommandBuilder.MaxNameLength, nameof(name)); | |||
if (!Regex.IsMatch(name, @"^[\w-]{1,32}$")) | |||
throw new ArgumentException("Option name cannot contain any special characters or whitespaces!", nameof(name)); | |||
_descriptionLocalizations ??= new(); | |||
_nameLocalizations.Add(locale, name); | |||
return this; | |||
} | |||
public SlashCommandOptionBuilder AddDescriptionLocalization(string locale, string description) | |||
{ | |||
if(!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) | |||
throw new ArgumentException($"Invalid locale: {locale}", nameof(locale)); | |||
Preconditions.AtLeast(description.Length, 1, nameof(description)); | |||
Preconditions.AtMost(description.Length, SlashCommandBuilder.MaxDescriptionLength, nameof(description)); | |||
_descriptionLocalizations ??= new(); | |||
_descriptionLocalizations.Add(locale, description); | |||
return this; | |||
} | |||
} | |||
} |
@@ -55,7 +55,7 @@ namespace Discord | |||
if (obj.Value == null) throw CreateNotNullException(name, msg); | |||
if (obj.Value.Trim().Length == 0) throw CreateNotEmptyException(name, msg); | |||
} | |||
} | |||
} | |||
private static ArgumentException CreateNotEmptyException(string name, string msg) | |||
=> new ArgumentException(message: msg ?? "Argument cannot be blank.", paramName: name); | |||
@@ -129,7 +129,7 @@ namespace Discord | |||
private static ArgumentException CreateNotEqualException<T>(string name, string msg, T value) | |||
=> new ArgumentException(message: msg ?? $"Value may not be equal to {value}.", paramName: name); | |||
/// <exception cref="ArgumentException">Value must be at least <paramref name="value"/>.</exception> | |||
public static void AtLeast(sbyte obj, sbyte value, string name, string msg = null) { if (obj < value) throw CreateAtLeastException(name, msg, value); } | |||
/// <exception cref="ArgumentException">Value must be at least <paramref name="value"/>.</exception> | |||
@@ -165,7 +165,7 @@ namespace Discord | |||
private static ArgumentException CreateAtLeastException<T>(string name, string msg, T value) | |||
=> new ArgumentException(message: msg ?? $"Value must be at least {value}.", paramName: name); | |||
/// <exception cref="ArgumentException">Value must be greater than <paramref name="value"/>.</exception> | |||
public static void GreaterThan(sbyte obj, sbyte value, string name, string msg = null) { if (obj <= value) throw CreateGreaterThanException(name, msg, value); } | |||
/// <exception cref="ArgumentException">Value must be greater than <paramref name="value"/>.</exception> | |||
@@ -201,7 +201,7 @@ namespace Discord | |||
private static ArgumentException CreateGreaterThanException<T>(string name, string msg, T value) | |||
=> new ArgumentException(message: msg ?? $"Value must be greater than {value}.", paramName: name); | |||
/// <exception cref="ArgumentException">Value must be at most <paramref name="value"/>.</exception> | |||
public static void AtMost(sbyte obj, sbyte value, string name, string msg = null) { if (obj > value) throw CreateAtMostException(name, msg, value); } | |||
/// <exception cref="ArgumentException">Value must be at most <paramref name="value"/>.</exception> | |||
@@ -237,7 +237,7 @@ namespace Discord | |||
private static ArgumentException CreateAtMostException<T>(string name, string msg, T value) | |||
=> new ArgumentException(message: msg ?? $"Value must be at most {value}.", paramName: name); | |||
/// <exception cref="ArgumentException">Value must be less than <paramref name="value"/>.</exception> | |||
public static void LessThan(sbyte obj, sbyte value, string name, string msg = null) { if (obj >= value) throw CreateLessThanException(name, msg, value); } | |||
/// <exception cref="ArgumentException">Value must be less than <paramref name="value"/>.</exception> | |||
@@ -1,4 +1,5 @@ | |||
using Newtonsoft.Json; | |||
using System.Collections.Generic; | |||
namespace Discord.API | |||
{ | |||
@@ -24,5 +25,17 @@ namespace Discord.API | |||
[JsonProperty("default_permission")] | |||
public Optional<bool> DefaultPermissions { get; set; } | |||
[JsonProperty("name_localizations")] | |||
public Optional<Dictionary<string, string>?> NameLocalizations { get; set; } | |||
[JsonProperty("description_localizations")] | |||
public Optional<Dictionary<string, string>?> DescriptionLocalizations { get; set; } | |||
[JsonProperty("name_localized")] | |||
public Optional<string?> NameLocalized { get; set; } | |||
[JsonProperty("description_localized")] | |||
public Optional<string?> DescriptionLocalized { get; set; } | |||
} | |||
} |
@@ -1,4 +1,5 @@ | |||
using Newtonsoft.Json; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
namespace Discord.API | |||
@@ -38,6 +39,18 @@ namespace Discord.API | |||
[JsonProperty("channel_types")] | |||
public Optional<ChannelType[]> ChannelTypes { get; set; } | |||
[JsonProperty("name_localizations")] | |||
public Optional<Dictionary<string, string>?> NameLocalizations { get; set; } | |||
[JsonProperty("description_localizations")] | |||
public Optional<Dictionary<string, string>?> DescriptionLocalizations { get; set; } | |||
[JsonProperty("name_localized")] | |||
public Optional<string?> NameLocalized { get; set; } | |||
[JsonProperty("description_localized")] | |||
public Optional<string?> DescriptionLocalized { get; set; } | |||
public ApplicationCommandOption() { } | |||
public ApplicationCommandOption(IApplicationCommandOption cmd) | |||
@@ -61,6 +74,11 @@ namespace Discord.API | |||
Name = cmd.Name; | |||
Type = cmd.Type; | |||
Description = cmd.Description; | |||
NameLocalizations = cmd.NameLocalizations?.ToDictionary(x => x.Key, x => x.Value) ?? Optional<Dictionary<string, string>>.Unspecified; | |||
DescriptionLocalizations = cmd.DescriptionLocalizations?.ToDictionary(x => x.Key, x => x.Value) ?? Optional<Dictionary<string, string>>.Unspecified; | |||
NameLocalized = cmd.NameLocalized; | |||
DescriptionLocalized = cmd.DescriptionLocalized; | |||
} | |||
public ApplicationCommandOption(ApplicationCommandOptionProperties option) | |||
{ | |||
@@ -1,4 +1,5 @@ | |||
using Newtonsoft.Json; | |||
using System.Collections.Generic; | |||
namespace Discord.API | |||
{ | |||
@@ -9,5 +10,11 @@ namespace Discord.API | |||
[JsonProperty("value")] | |||
public object Value { get; set; } | |||
[JsonProperty("name_localizations")] | |||
public Optional<Dictionary<string, string>?> NameLocalizations { get; set; } | |||
[JsonProperty("name_localized")] | |||
public Optional<string?> NameLocalized { get; set; } | |||
} | |||
} |
@@ -32,6 +32,14 @@ namespace Discord.Rest | |||
/// </summary> | |||
public IReadOnlyCollection<RestApplicationCommandOption> Options { get; private set; } | |||
public IReadOnlyDictionary<string, string>? NameLocalizations { get; private set; } | |||
public IReadOnlyDictionary<string, string>? DescriptionLocalizations { get; private set; } | |||
public string? NameLocalized { get; private set; } | |||
public string? DescriptionLocalized { get; private set; } | |||
/// <inheritdoc/> | |||
public DateTimeOffset CreatedAt | |||
=> SnowflakeUtils.FromSnowflake(Id); | |||
@@ -57,6 +65,15 @@ namespace Discord.Rest | |||
Options = model.Options.IsSpecified | |||
? model.Options.Value.Select(RestApplicationCommandOption.Create).ToImmutableArray() | |||
: ImmutableArray.Create<RestApplicationCommandOption>(); | |||
NameLocalizations = model.NameLocalizations.GetValueOrDefault(null)?.ToImmutableDictionary() ?? | |||
ImmutableDictionary<string, string>.Empty; | |||
DescriptionLocalizations = model.DescriptionLocalizations.GetValueOrDefault(null)?.ToImmutableDictionary() ?? | |||
ImmutableDictionary<string, string>.Empty; | |||
NameLocalized = model.NameLocalized.GetValueOrDefault(); | |||
DescriptionLocalized = model.DescriptionLocalized.GetValueOrDefault(); | |||
} | |||
/// <inheritdoc/> | |||
@@ -1,3 +1,5 @@ | |||
using System.Collections.Generic; | |||
using System.Collections.Immutable; | |||
using Model = Discord.API.ApplicationCommandOptionChoice; | |||
namespace Discord.Rest | |||
@@ -13,10 +15,16 @@ namespace Discord.Rest | |||
/// <inheritdoc/> | |||
public object Value { get; } | |||
public IReadOnlyDictionary<string, string>? NameLocalizations { get; } | |||
public string? NameLocalized { get; } | |||
internal RestApplicationCommandChoice(Model model) | |||
{ | |||
Name = model.Name; | |||
Value = model.Value; | |||
NameLocalizations = model.NameLocalizations.GetValueOrDefault(null)?.ToImmutableDictionary(); | |||
NameLocalized = model.NameLocalized.GetValueOrDefault(null); | |||
} | |||
} | |||
} |
@@ -27,7 +27,7 @@ namespace Discord.Rest | |||
public bool? IsRequired { get; private set; } | |||
/// <inheritdoc/> | |||
public bool? IsAutocomplete { get; private set; } | |||
public bool? IsAutocomplete { get; private set; } | |||
/// <inheritdoc/> | |||
public double? MinValue { get; private set; } | |||
@@ -48,6 +48,14 @@ namespace Discord.Rest | |||
/// <inheritdoc/> | |||
public IReadOnlyCollection<ChannelType> ChannelTypes { get; private set; } | |||
public IReadOnlyDictionary<string, string>? NameLocalizations { get; private set; } | |||
public IReadOnlyDictionary<string, string>? DescriptionLocalizations { get; private set; } | |||
public string? NameLocalized { get; private set; } | |||
public string? DescriptionLocalized { get; private set; } | |||
internal RestApplicationCommandOption() { } | |||
internal static RestApplicationCommandOption Create(Model model) | |||
@@ -89,6 +97,15 @@ namespace Discord.Rest | |||
ChannelTypes = model.ChannelTypes.IsSpecified | |||
? model.ChannelTypes.Value.ToImmutableArray() | |||
: ImmutableArray.Create<ChannelType>(); | |||
NameLocalizations = model.NameLocalizations.GetValueOrDefault(null)?.ToImmutableDictionary() ?? | |||
ImmutableDictionary<string, string>.Empty; | |||
DescriptionLocalizations = model.DescriptionLocalizations.GetValueOrDefault(null)?.ToImmutableDictionary() ?? | |||
ImmutableDictionary<string, string>.Empty; | |||
NameLocalized = model.NameLocalized.GetValueOrDefault(); | |||
DescriptionLocalized = model.DescriptionLocalized.GetValueOrDefault(); | |||
} | |||
#endregion | |||
@@ -44,6 +44,14 @@ namespace Discord.WebSocket | |||
/// </remarks> | |||
public IReadOnlyCollection<SocketApplicationCommandOption> Options { get; private set; } | |||
public IReadOnlyDictionary<string, string>? NameLocalizations { get; private set; } | |||
public IReadOnlyDictionary<string, string>? DescriptionLocalizations { get; private set; } | |||
public string? NameLocalized { get; private set; } | |||
public string? DescriptionLocalized { get; private set; } | |||
/// <inheritdoc/> | |||
public DateTimeOffset CreatedAt | |||
=> SnowflakeUtils.FromSnowflake(Id); | |||
@@ -86,6 +94,15 @@ namespace Discord.WebSocket | |||
Options = model.Options.IsSpecified | |||
? model.Options.Value.Select(SocketApplicationCommandOption.Create).ToImmutableArray() | |||
: ImmutableArray.Create<SocketApplicationCommandOption>(); | |||
NameLocalizations = model.NameLocalizations.GetValueOrDefault(null)?.ToImmutableDictionary() ?? | |||
ImmutableDictionary<string, string>.Empty; | |||
DescriptionLocalizations = model.DescriptionLocalizations.GetValueOrDefault(null)?.ToImmutableDictionary() ?? | |||
ImmutableDictionary<string, string>.Empty; | |||
NameLocalized = model.NameLocalized.GetValueOrDefault(); | |||
DescriptionLocalized = model.DescriptionLocalized.GetValueOrDefault(); | |||
} | |||
/// <inheritdoc/> | |||
@@ -1,3 +1,5 @@ | |||
using System.Collections.Generic; | |||
using System.Collections.Immutable; | |||
using Model = Discord.API.ApplicationCommandOptionChoice; | |||
namespace Discord.WebSocket | |||
@@ -13,6 +15,10 @@ namespace Discord.WebSocket | |||
/// <inheritdoc/> | |||
public object Value { get; private set; } | |||
public IReadOnlyDictionary<string, string>? NameLocalizations { get; private set; } | |||
public string? NameLocalized { get; private set; } | |||
internal SocketApplicationCommandChoice() { } | |||
internal static SocketApplicationCommandChoice Create(Model model) | |||
{ | |||
@@ -24,6 +30,8 @@ namespace Discord.WebSocket | |||
{ | |||
Name = model.Name; | |||
Value = model.Value; | |||
NameLocalizations = model.NameLocalizations.GetValueOrDefault(null)?.ToImmutableDictionary(); | |||
NameLocalized = model.NameLocalized.GetValueOrDefault(null); | |||
} | |||
} | |||
} |
@@ -48,6 +48,14 @@ namespace Discord.WebSocket | |||
/// </summary> | |||
public IReadOnlyCollection<ChannelType> ChannelTypes { get; private set; } | |||
public IReadOnlyDictionary<string, string>? NameLocalizations { get; private set; } | |||
public IReadOnlyDictionary<string, string>? DescriptionLocalizations { get; private set; } | |||
public string? NameLocalized { get; private set; } | |||
public string? DescriptionLocalized { get; private set; } | |||
internal SocketApplicationCommandOption() { } | |||
internal static SocketApplicationCommandOption Create(Model model) | |||
{ | |||
@@ -83,6 +91,15 @@ namespace Discord.WebSocket | |||
ChannelTypes = model.ChannelTypes.IsSpecified | |||
? model.ChannelTypes.Value.ToImmutableArray() | |||
: ImmutableArray.Create<ChannelType>(); | |||
NameLocalizations = model.NameLocalizations.GetValueOrDefault(null)?.ToImmutableDictionary() ?? | |||
ImmutableDictionary<string, string>.Empty; | |||
DescriptionLocalizations = model.DescriptionLocalizations.GetValueOrDefault(null)?.ToImmutableDictionary() ?? | |||
ImmutableDictionary<string, string>.Empty; | |||
NameLocalized = model.NameLocalized.GetValueOrDefault(); | |||
DescriptionLocalized = model.DescriptionLocalized.GetValueOrDefault(); | |||
} | |||
IReadOnlyCollection<IApplicationCommandOptionChoice> IApplicationCommandOption.Choices => Choices; | |||