diff --git a/src/Discord.Net.Core/Entities/ApplicationRoleConnection/RoleConnectionMetadata.cs b/src/Discord.Net.Core/Entities/ApplicationRoleConnection/RoleConnectionMetadata.cs index c13264d97..26ac3065d 100644 --- a/src/Discord.Net.Core/Entities/ApplicationRoleConnection/RoleConnectionMetadata.cs +++ b/src/Discord.Net.Core/Entities/ApplicationRoleConnection/RoleConnectionMetadata.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -5,26 +6,58 @@ namespace Discord; public class RoleConnectionMetadata { + /// + /// Gets the of metadata value. + /// public RoleConnectionMetadataType Type { get; } + /// + /// Gets the dictionary key for the metadata field. + /// public string Key { get; } - public string Name{ get; } - - public Optional> NameLocalizations { get; } + /// + /// Gets the name of the metadata field. + /// + public string Name { get; } + /// + /// Gets the description of the metadata field. + /// public string Description { get; } - public Optional> DescriptionLocalizations { get; } + /// + /// Gets translations of the name. if not set. + /// + public IReadOnlyDictionary NameLocalizations { get; } + + /// + /// Gets translations of the description. if not set. + /// + public IReadOnlyDictionary DescriptionLocalizations { get; } internal RoleConnectionMetadata(RoleConnectionMetadataType type, string key, string name, string description, - Dictionary nameLocalizations = null, Dictionary descriptionLocalizations = null) + IDictionary nameLocalizations = null, IDictionary descriptionLocalizations = null) { Type = type; Key = key; Name = name; Description = description; - NameLocalizations = nameLocalizations.ToImmutableDictionary(); - DescriptionLocalizations = descriptionLocalizations.ToImmutableDictionary(); + NameLocalizations = nameLocalizations?.ToImmutableDictionary(); + DescriptionLocalizations = descriptionLocalizations?.ToImmutableDictionary(); } + + /// + /// Initializes a new with the data from this object. + /// + public RoleConnectionMetadataProperties ToRoleConnectionMetadataProperties() + => new() + { + Name = Name, + Description = Description, + Type = Type, + Key = Key, + NameLocalizations = NameLocalizations, + DescriptionLocalizations = DescriptionLocalizations + }; } diff --git a/src/Discord.Net.Core/Entities/ApplicationRoleConnection/RoleConnectionMetadataProperties.cs b/src/Discord.Net.Core/Entities/ApplicationRoleConnection/RoleConnectionMetadataProperties.cs new file mode 100644 index 000000000..9c4fb87b6 --- /dev/null +++ b/src/Discord.Net.Core/Entities/ApplicationRoleConnection/RoleConnectionMetadataProperties.cs @@ -0,0 +1,121 @@ +using System.Collections.Generic; +using System; +using System.Collections.Immutable; + +namespace Discord; + +public class RoleConnectionMetadataProperties +{ + private const int MaxKeyLength = 50; + private const int MaxNameLength = 100; + private const int MaxDescriptionLength = 200; + + private string _key; + private string _name; + private string _description; + + private IReadOnlyDictionary _nameLocalizations; + private IReadOnlyDictionary _descriptionLocalizations; + + /// + /// Gets or sets the of metadata value. + /// + public RoleConnectionMetadataType Type { get; set; } + + /// + /// Gets or sets the dictionary key for the metadata field. + /// + public string Key + { + get => _key; + set + { + Preconditions.AtMost(value.Length, MaxKeyLength, nameof(Key), $"Key length must be less than or equal to {MaxKeyLength}"); + _key = value; + } + } + + /// + /// Gets or sets the name of the metadata field. + /// + public string Name + { + get => _name; + set + { + Preconditions.AtMost(value.Length, MaxNameLength, nameof(Name), $"Name length must be less than or equal to {MaxNameLength}"); + _name = value; + } + } + + /// + /// Gets or sets the description of the metadata field. + /// + public string Description + { + get => _description; + set + { + Preconditions.AtMost(value.Length, MaxDescriptionLength, nameof(Description), $"Description length must be less than or equal to {MaxDescriptionLength}"); + _description = value; + } + } + + /// + /// Gets or sets translations of the name. if not set. + /// + public IReadOnlyDictionary NameLocalizations + { + get => _nameLocalizations; + set + { + if (value is not null) + foreach (var localization in value) + if (localization.Value.Length > MaxNameLength) + throw new ArgumentException($"Name localization length must be less than or equal to {MaxNameLength}. Locale '{localization}'"); + _nameLocalizations = value; + } + } + + /// + /// Gets or sets translations of the description. if not set. + /// + public IReadOnlyDictionary DescriptionLocalizations + { + get => _descriptionLocalizations; + set + { + if (value is not null) + foreach (var localization in value) + if (localization.Value.Length > MaxDescriptionLength) + throw new ArgumentException($"Description localization length must be less than or equal to {MaxDescriptionLength}. Locale '{localization}'"); + _descriptionLocalizations = value; + } + } + + /// + /// Initializes a new instance of . + /// + /// The type of the metadata value. + /// The dictionary key for the metadata field. Max 50 characters. + /// The name of the metadata visible in user profile. Max 100 characters. + /// The description of the metadata visible in user profile. Max 200 characters. + /// Translations for the name. + /// Translations for the description. + public RoleConnectionMetadataProperties(RoleConnectionMetadataType type, string key, string name, string description, + IDictionary nameLocalizations = null, IDictionary descriptionLocalizations = null) + { + Type = type; + Key = key; + Name = name; + Description = description; + NameLocalizations = nameLocalizations?.ToImmutableDictionary(); + DescriptionLocalizations = descriptionLocalizations?.ToImmutableDictionary(); + } + + /// + /// Initializes a new instance of . + /// + public RoleConnectionMetadataProperties() { } +} + diff --git a/src/Discord.Net.Rest/API/Common/RoleConnectionMetadata.cs b/src/Discord.Net.Rest/API/Common/RoleConnectionMetadata.cs index 472c14e62..9ce36a05d 100644 --- a/src/Discord.Net.Rest/API/Common/RoleConnectionMetadata.cs +++ b/src/Discord.Net.Rest/API/Common/RoleConnectionMetadata.cs @@ -18,8 +18,8 @@ public class RoleConnectionMetadata public string Description { get; set; } [JsonProperty("name_localizations")] - public Optional>> NameLocalizations { get; set; } + public Optional> NameLocalizations { get; set; } [JsonProperty("description_localizations")] - public Optional>> DescriptionLocalizations { get; set; } + public Optional> DescriptionLocalizations { get; set; } } diff --git a/src/Discord.Net.Rest/ClientHelper.cs b/src/Discord.Net.Rest/ClientHelper.cs index 0c8f8c42f..b1bd0c544 100644 --- a/src/Discord.Net.Rest/ClientHelper.cs +++ b/src/Discord.Net.Rest/ClientHelper.cs @@ -264,5 +264,50 @@ namespace Discord.Rest public static Task RemoveRoleAsync(BaseDiscordClient client, ulong guildId, ulong userId, ulong roleId, RequestOptions options = null) => client.ApiClient.RemoveRoleAsync(guildId, userId, roleId, options); #endregion + + #region Role Subscription Metadata + + public static async Task> GetRoleConnectionMetadataRecordsAsync(BaseDiscordClient client, RequestOptions options = null) + => (await client.ApiClient.GetApplicationRoleConnectionMetadataRecordsAsync(options)) + .Select(model + => new RoleConnectionMetadata( + model.Type, + model.Key, + model.Name, + model.Description, + model.NameLocalizations.IsSpecified + ? model.NameLocalizations.Value?.ToImmutableDictionary() + : null, + model.DescriptionLocalizations.IsSpecified + ? model.DescriptionLocalizations.Value?.ToImmutableDictionary() + : null)) + .ToImmutableArray(); + + public static async Task> ModifyRoleConnectionMetadataRecordsAsync(ICollection metadata, BaseDiscordClient client, RequestOptions options = null) + => (await client.ApiClient.UpdateApplicationRoleConnectionMetadataRecordsAsync(metadata + .Select(x => new API.RoleConnectionMetadata + { + Name = x.Name, + Description = x.Description, + Key = x.Key, + Type = x.Type, + NameLocalizations = x.NameLocalizations?.ToDictionary(), + DescriptionLocalizations = x.DescriptionLocalizations?.ToDictionary() + }).ToArray())) + .Select(model + => new RoleConnectionMetadata( + model.Type, + model.Key, + model.Name, + model.Description, + model.NameLocalizations.IsSpecified + ? model.NameLocalizations.Value?.ToImmutableDictionary() + : null, + model.DescriptionLocalizations.IsSpecified + ? model.DescriptionLocalizations.Value?.ToImmutableDictionary() + : null)) + .ToImmutableArray(); + + #endregion } } diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs index 12656be88..4ff6668ab 100644 --- a/src/Discord.Net.Rest/DiscordRestApiClient.cs +++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs @@ -4,7 +4,9 @@ using Discord.Net; using Discord.Net.Converters; using Discord.Net.Queue; using Discord.Net.Rest; + using Newtonsoft.Json; + using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -2480,25 +2482,17 @@ namespace Discord.API #region Application Role Connections Metadata - public async Task> GetApplicationRoleConnectionMetadataRecordsAsync(RequestOptions options = null) - { - return await SendAsync>("GET", $"/applications/{CurrentApplicationId}/role-connections/metadata", options: options).ConfigureAwait(false); - } + public async Task GetApplicationRoleConnectionMetadataRecordsAsync(RequestOptions options = null) + => await SendAsync("GET", () => $"applications/{CurrentApplicationId}/role-connections/metadata", new BucketIds(), options: options).ConfigureAwait(false); - public async Task> UpdateApplicationRoleConnectionMetadataRecordsAsync(IEnumerable roleConnections, RequestOptions options = null) - { - return await SendJsonAsync>("PUT", $"/applications/{CurrentApplicationId}/role-connections/metadata", roleConnections, options: options).ConfigureAwait(false); - } + public async Task UpdateApplicationRoleConnectionMetadataRecordsAsync(RoleConnectionMetadata[] roleConnections, RequestOptions options = null) + => await SendJsonAsync ("PUT", () => $"applications/{CurrentApplicationId}/role-connections/metadata", roleConnections, new BucketIds(), options: options).ConfigureAwait(false); public async Task GetUserApplicationRoleConnection(RequestOptions options = null) - { - return await SendAsync("GET", $"/users/@me/applications/{CurrentApplicationId}/role-connection", options: options); - } + => await SendAsync("GET", () => $"users/@me/applications/{CurrentApplicationId}/role-connection", new BucketIds(), options: options); public async Task GetUserApplicationRoleConnection(RoleConnection connection, RequestOptions options = null) - { - return await SendJsonAsync("PUT", $"/users/@me/applications/{CurrentApplicationId}/role-connection", connection, options: options); - } + => await SendJsonAsync("PUT", () => $"users/@me/applications/{CurrentApplicationId}/role-connection", connection, new BucketIds(), options: options); #endregion } diff --git a/src/Discord.Net.Rest/DiscordRestClient.cs b/src/Discord.Net.Rest/DiscordRestClient.cs index ddd38c5be..774738b57 100644 --- a/src/Discord.Net.Rest/DiscordRestClient.cs +++ b/src/Discord.Net.Rest/DiscordRestClient.cs @@ -231,7 +231,17 @@ namespace Discord.Rest => MessageHelper.RemoveAllReactionsAsync(channelId, messageId, this, options); public Task RemoveAllReactionsForEmoteAsync(ulong channelId, ulong messageId, IEmote emote, RequestOptions options = null) => MessageHelper.RemoveAllReactionsForEmoteAsync(channelId, messageId, emote, this, options); -#endregion + + public Task> GetRoleConnectionMetadataRecordsAsync(RequestOptions options = null) + => ClientHelper.GetRoleConnectionMetadataRecordsAsync(this, options); + + public Task> ModifyRoleConnectionMetadataRecordsAsync(ICollection metadata, RequestOptions options = null) + { + Preconditions.AtMost(metadata.Count, 5, nameof(metadata), "An application can have a maximum of 5 metadata records."); + return ClientHelper.ModifyRoleConnectionMetadataRecordsAsync(metadata, this, options); + } + + #endregion #region IDiscordClient ///