Browse Source

add localization fields to rest and websocket application command entity implementations

pull/2211/head
Cenngo 3 years ago
parent
commit
95c4893af1
17 changed files with 450 additions and 41 deletions
  1. +76
    -17
      src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOption.cs
  2. +29
    -0
      src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOptionChoice.cs
  3. +7
    -0
      src/Discord.Net.Core/Entities/Interactions/ApplicationCommandProperties.cs
  4. +8
    -0
      src/Discord.Net.Core/Entities/Interactions/IApplicationCommand.cs
  5. +8
    -0
      src/Discord.Net.Core/Entities/Interactions/IApplicationCommandOption.cs
  6. +6
    -0
      src/Discord.Net.Core/Entities/Interactions/IApplicationCommandOptionChoice.cs
  7. +188
    -18
      src/Discord.Net.Core/Entities/Interactions/SlashCommands/SlashCommandBuilder.cs
  8. +5
    -5
      src/Discord.Net.Core/Utils/Preconditions.cs
  9. +13
    -0
      src/Discord.Net.Rest/API/Common/ApplicationCommand.cs
  10. +18
    -0
      src/Discord.Net.Rest/API/Common/ApplicationCommandOption.cs
  11. +7
    -0
      src/Discord.Net.Rest/API/Common/ApplicationCommandOptionChoice.cs
  12. +17
    -0
      src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommand.cs
  13. +8
    -0
      src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommandChoice.cs
  14. +18
    -1
      src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommandOption.cs
  15. +17
    -0
      src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketApplicationCommand.cs
  16. +8
    -0
      src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketApplicationCommandChoice.cs
  17. +17
    -0
      src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketApplicationCommandOption.cs

+ 76
- 17
src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOption.cs View File

@@ -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;
}
}
}

+ 29
- 0
src/Discord.Net.Core/Entities/Interactions/ApplicationCommandOptionChoice.cs View File

@@ -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;
}
}
}
}

+ 7
- 0
src/Discord.Net.Core/Entities/Interactions/ApplicationCommandProperties.cs View File

@@ -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() { }
}
}

+ 8
- 0
src/Discord.Net.Core/Entities/Interactions/IApplicationCommand.cs View File

@@ -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>


+ 8
- 0
src/Discord.Net.Core/Entities/Interactions/IApplicationCommandOption.cs View File

@@ -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; }
}
}

+ 6
- 0
src/Discord.Net.Core/Entities/Interactions/IApplicationCommandOptionChoice.cs View File

@@ -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; }
}
}

+ 188
- 18
src/Discord.Net.Core/Entities/Interactions/SlashCommands/SlashCommandBuilder.cs View File

@@ -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;
}
}
}

+ 5
- 5
src/Discord.Net.Core/Utils/Preconditions.cs View File

@@ -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>


+ 13
- 0
src/Discord.Net.Rest/API/Common/ApplicationCommand.cs View File

@@ -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; }
}
}

+ 18
- 0
src/Discord.Net.Rest/API/Common/ApplicationCommandOption.cs View File

@@ -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)
{


+ 7
- 0
src/Discord.Net.Rest/API/Common/ApplicationCommandOptionChoice.cs View File

@@ -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; }
}
}

+ 17
- 0
src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommand.cs View File

@@ -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/>


+ 8
- 0
src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommandChoice.cs View File

@@ -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);
}
}
}

+ 18
- 1
src/Discord.Net.Rest/Entities/Interactions/RestApplicationCommandOption.cs View File

@@ -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



+ 17
- 0
src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketApplicationCommand.cs View File

@@ -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/>


+ 8
- 0
src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketApplicationCommandChoice.cs View File

@@ -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);
}
}
}

+ 17
- 0
src/Discord.Net.WebSocket/Entities/Interaction/SocketBaseCommand/SocketApplicationCommandOption.cs View File

@@ -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;


Loading…
Cancel
Save