From 506526524ebaa5b3089d3aea19f4ed940bb7419a Mon Sep 17 00:00:00 2001 From: Dan Jagnow Date: Tue, 24 Nov 2020 16:51:23 -0600 Subject: [PATCH] Added support for the Character Soulbinds API Added support for the Character Soulbinds API. Added an ICharacterSoulbindsApi interface to describe the capabilities of the API. The IWarcraftClient interface implements this interface via the IProfileApi interface. --- .../ServiceCollectionExtensions.cs | 1 + .../ProfileApi/CharacterSoulbindsApi.cs | 20 +++++ .../ProfileApi/ICharacterSoulbindsApi.cs | 34 ++++++++ .../Interfaces/ProfileApi/IProfileApi.cs | 1 + .../GameDataApi/Covenant/ConduitReference.cs | 28 +++++++ .../GameDataApi/Covenant/CovenantReference.cs | 28 +++++++ .../GameDataApi/Covenant/SoulbindReference.cs | 28 +++++++ .../TechTalent/TechTalentReference.cs | 28 +++++++ .../CharacterSoulbinds/CharacterSoulbinds.cs | 40 ++++++++++ .../CharacterSoulbinds/ConduitRank.cs | 22 ++++++ .../CharacterSoulbinds/ConduitSocketTrait.cs | 22 ++++++ .../CharacterSoulbinds/SoulbindSelection.cs | 28 +++++++ .../CharacterSoulbinds/SoulbindTrait.cs | 34 ++++++++ .../ProfileApi/CharacterSoulbindsApiTests.cs | 16 ++++ .../ProfileApi/CharacterSoulbindsApiTests.cs | 20 +++++ .../Properties/Resources.Designer.cs | 26 +++++++ .../Properties/Resources.resx | 77 +++++++++++++++++++ 17 files changed, 453 insertions(+) create mode 100644 src/ArgentPonyWarcraftClient/Client/ProfileApi/CharacterSoulbindsApi.cs create mode 100644 src/ArgentPonyWarcraftClient/Interfaces/ProfileApi/ICharacterSoulbindsApi.cs create mode 100644 src/ArgentPonyWarcraftClient/Models/GameDataApi/Covenant/ConduitReference.cs create mode 100644 src/ArgentPonyWarcraftClient/Models/GameDataApi/Covenant/CovenantReference.cs create mode 100644 src/ArgentPonyWarcraftClient/Models/GameDataApi/Covenant/SoulbindReference.cs create mode 100644 src/ArgentPonyWarcraftClient/Models/GameDataApi/TechTalent/TechTalentReference.cs create mode 100644 src/ArgentPonyWarcraftClient/Models/ProfileApi/CharacterSoulbinds/CharacterSoulbinds.cs create mode 100644 src/ArgentPonyWarcraftClient/Models/ProfileApi/CharacterSoulbinds/ConduitRank.cs create mode 100644 src/ArgentPonyWarcraftClient/Models/ProfileApi/CharacterSoulbinds/ConduitSocketTrait.cs create mode 100644 src/ArgentPonyWarcraftClient/Models/ProfileApi/CharacterSoulbinds/SoulbindSelection.cs create mode 100644 src/ArgentPonyWarcraftClient/Models/ProfileApi/CharacterSoulbinds/SoulbindTrait.cs create mode 100644 tests/ArgentPonyWarcraftClient.Integration.Tests/ProfileApi/CharacterSoulbindsApiTests.cs create mode 100644 tests/ArgentPonyWarcraftClient.Tests/ProfileApi/CharacterSoulbindsApiTests.cs diff --git a/src/ArgentPonyWarcraftClient.Extensions.DependencyInjection/ServiceCollectionExtensions.cs b/src/ArgentPonyWarcraftClient.Extensions.DependencyInjection/ServiceCollectionExtensions.cs index 673160b6..06803313 100644 --- a/src/ArgentPonyWarcraftClient.Extensions.DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/ArgentPonyWarcraftClient.Extensions.DependencyInjection/ServiceCollectionExtensions.cs @@ -90,6 +90,7 @@ private static IServiceCollection AddProfileApiServices(this IServiceCollection .AddTransientUsingServiceProvider() .AddTransientUsingServiceProvider() .AddTransientUsingServiceProvider() + .AddTransientUsingServiceProvider() .AddTransientUsingServiceProvider() .AddTransientUsingServiceProvider() .AddTransientUsingServiceProvider() diff --git a/src/ArgentPonyWarcraftClient/Client/ProfileApi/CharacterSoulbindsApi.cs b/src/ArgentPonyWarcraftClient/Client/ProfileApi/CharacterSoulbindsApi.cs new file mode 100644 index 00000000..15d0e715 --- /dev/null +++ b/src/ArgentPonyWarcraftClient/Client/ProfileApi/CharacterSoulbindsApi.cs @@ -0,0 +1,20 @@ +using System.Threading.Tasks; + +namespace ArgentPonyWarcraftClient +{ + public partial class WarcraftClient + { + /// + public async Task> GetCharacterSoulbindsAsync(string realmSlug, string characterName, string @namespace) + { + return await GetCharacterSoulbindsAsync(realmSlug, characterName, @namespace, _region, _locale); + } + + /// + public async Task> GetCharacterSoulbindsAsync(string realmSlug, string characterName, string @namespace, Region region, Locale locale) + { + string host = GetHost(region); + return await GetAsync($"{host}/profile/wow/character/{realmSlug}/{characterName?.ToLowerInvariant()}/soulbinds?namespace={@namespace}&locale={locale}"); + } + } +} diff --git a/src/ArgentPonyWarcraftClient/Interfaces/ProfileApi/ICharacterSoulbindsApi.cs b/src/ArgentPonyWarcraftClient/Interfaces/ProfileApi/ICharacterSoulbindsApi.cs new file mode 100644 index 00000000..d7da81fd --- /dev/null +++ b/src/ArgentPonyWarcraftClient/Interfaces/ProfileApi/ICharacterSoulbindsApi.cs @@ -0,0 +1,34 @@ +using System.Threading.Tasks; + +namespace ArgentPonyWarcraftClient +{ + /// + /// A client for the World of Warcraft Character Soulbinds API. + /// + public interface ICharacterSoulbindsApi + { + /// + /// Get a character's soulbinds. + /// + /// The slug of the realm. + /// The name of the character. + /// The namespace to use to locate this document. + /// + /// A character's soulbinds. + /// + Task> GetCharacterSoulbindsAsync(string realmSlug, string characterName, string @namespace); + + /// + /// Get a character's soulbinds. + /// + /// The slug of the realm. + /// The name of the character. + /// The namespace to use to locate this document. + /// Specifies the region that the API will retrieve its data from. + /// Specifies the language that the result will be in. + /// + /// A character's soulbinds. + /// + Task> GetCharacterSoulbindsAsync(string realmSlug, string characterName, string @namespace, Region region, Locale locale); + } +} diff --git a/src/ArgentPonyWarcraftClient/Interfaces/ProfileApi/IProfileApi.cs b/src/ArgentPonyWarcraftClient/Interfaces/ProfileApi/IProfileApi.cs index 649028d9..faeaf40e 100644 --- a/src/ArgentPonyWarcraftClient/Interfaces/ProfileApi/IProfileApi.cs +++ b/src/ArgentPonyWarcraftClient/Interfaces/ProfileApi/IProfileApi.cs @@ -18,6 +18,7 @@ public interface IProfileApi : ICharacterPvpApi, ICharacterQuestsApi, ICharacterReputationsApi, + ICharacterSoulbindsApi, ICharacterSpecializationsApi, ICharacterStatisticsApi, ICharacterTitlesApi, diff --git a/src/ArgentPonyWarcraftClient/Models/GameDataApi/Covenant/ConduitReference.cs b/src/ArgentPonyWarcraftClient/Models/GameDataApi/Covenant/ConduitReference.cs new file mode 100644 index 00000000..8d11c35c --- /dev/null +++ b/src/ArgentPonyWarcraftClient/Models/GameDataApi/Covenant/ConduitReference.cs @@ -0,0 +1,28 @@ +using System.Text.Json.Serialization; + +namespace ArgentPonyWarcraftClient +{ + /// + /// A reference to a conduit. + /// + public class ConduitReference + { + /// + /// Gets the key for the conduit. + /// + [JsonPropertyName("key")] + public Self Key { get; set; } + + /// + /// Gets the name of the conduit. + /// + [JsonPropertyName("name")] + public string Name { get; set; } + + /// + /// Gets the ID of the conduit. + /// + [JsonPropertyName("id")] + public int Id { get; set; } + } +} diff --git a/src/ArgentPonyWarcraftClient/Models/GameDataApi/Covenant/CovenantReference.cs b/src/ArgentPonyWarcraftClient/Models/GameDataApi/Covenant/CovenantReference.cs new file mode 100644 index 00000000..66fceac4 --- /dev/null +++ b/src/ArgentPonyWarcraftClient/Models/GameDataApi/Covenant/CovenantReference.cs @@ -0,0 +1,28 @@ +using System.Text.Json.Serialization; + +namespace ArgentPonyWarcraftClient +{ + /// + /// A reference to a covenant. + /// + public class CovenantReference + { + /// + /// Gets the key for the covenant. + /// + [JsonPropertyName("key")] + public Self Key { get; set; } + + /// + /// Gets the name of the covenant. + /// + [JsonPropertyName("name")] + public string Name { get; set; } + + /// + /// Gets the ID of the covenant. + /// + [JsonPropertyName("id")] + public int Id { get; set; } + } +} diff --git a/src/ArgentPonyWarcraftClient/Models/GameDataApi/Covenant/SoulbindReference.cs b/src/ArgentPonyWarcraftClient/Models/GameDataApi/Covenant/SoulbindReference.cs new file mode 100644 index 00000000..70de1583 --- /dev/null +++ b/src/ArgentPonyWarcraftClient/Models/GameDataApi/Covenant/SoulbindReference.cs @@ -0,0 +1,28 @@ +using System.Text.Json.Serialization; + +namespace ArgentPonyWarcraftClient +{ + /// + /// A reference to a soulbind. + /// + public class SoulbindReference + { + /// + /// Gets the key for the soulbind. + /// + [JsonPropertyName("key")] + public Self Key { get; set; } + + /// + /// Gets the name of the soulbind. + /// + [JsonPropertyName("name")] + public string Name { get; set; } + + /// + /// Gets the ID of the soulbind. + /// + [JsonPropertyName("id")] + public int Id { get; set; } + } +} diff --git a/src/ArgentPonyWarcraftClient/Models/GameDataApi/TechTalent/TechTalentReference.cs b/src/ArgentPonyWarcraftClient/Models/GameDataApi/TechTalent/TechTalentReference.cs new file mode 100644 index 00000000..e2a1675f --- /dev/null +++ b/src/ArgentPonyWarcraftClient/Models/GameDataApi/TechTalent/TechTalentReference.cs @@ -0,0 +1,28 @@ +using System.Text.Json.Serialization; + +namespace ArgentPonyWarcraftClient +{ + /// + /// A reference to a tech talent. + /// + public class TechTalentReference + { + /// + /// Gets the key for the tech talent. + /// + [JsonPropertyName("key")] + public Self Key { get; set; } + + /// + /// Gets the name of the tech talent. + /// + [JsonPropertyName("name")] + public string Name { get; set; } + + /// + /// Gets the ID of the tech talent. + /// + [JsonPropertyName("id")] + public int Id { get; set; } + } +} diff --git a/src/ArgentPonyWarcraftClient/Models/ProfileApi/CharacterSoulbinds/CharacterSoulbinds.cs b/src/ArgentPonyWarcraftClient/Models/ProfileApi/CharacterSoulbinds/CharacterSoulbinds.cs new file mode 100644 index 00000000..8ef71bf4 --- /dev/null +++ b/src/ArgentPonyWarcraftClient/Models/ProfileApi/CharacterSoulbinds/CharacterSoulbinds.cs @@ -0,0 +1,40 @@ +using System.Text.Json.Serialization; + +namespace ArgentPonyWarcraftClient +{ + /// + /// A character's soulbinds. + /// + public class CharacterSoulbinds + { + /// + /// Gets links for the character's soulbinds. + /// + [JsonPropertyName("_links")] + public Links Links { get; set; } + + /// + /// Gets a reference to the character. + /// + [JsonPropertyName("character")] + public CharacterReference Character { get; set; } + + /// + /// Gets a reference to the character's chosen covenant. + /// + [JsonPropertyName("chosen_covenant")] + public CovenantReference ChosenCovenant { get; set; } + + /// + /// Gets the renown level for the character with the chosen covenant. + /// + [JsonPropertyName("renown_level")] + public long RenownLevel { get; set; } + + /// + /// Gets the soulbinds for the character. + /// + [JsonPropertyName("soulbinds")] + public SoulbindSelection[] Soulbinds { get; set; } + } +} diff --git a/src/ArgentPonyWarcraftClient/Models/ProfileApi/CharacterSoulbinds/ConduitRank.cs b/src/ArgentPonyWarcraftClient/Models/ProfileApi/CharacterSoulbinds/ConduitRank.cs new file mode 100644 index 00000000..9124fdf0 --- /dev/null +++ b/src/ArgentPonyWarcraftClient/Models/ProfileApi/CharacterSoulbinds/ConduitRank.cs @@ -0,0 +1,22 @@ +using System.Text.Json.Serialization; + +namespace ArgentPonyWarcraftClient +{ + /// + /// Rank details for a conduit socket. + /// + public class ConduitRank + { + /// + /// Gets a reference to the conduit. + /// + [JsonPropertyName("conduit")] + public ConduitReference Conduit { get; set; } + + /// + /// Gets the rank of the socket. + /// + [JsonPropertyName("rank")] + public long Rank { get; set; } + } +} diff --git a/src/ArgentPonyWarcraftClient/Models/ProfileApi/CharacterSoulbinds/ConduitSocketTrait.cs b/src/ArgentPonyWarcraftClient/Models/ProfileApi/CharacterSoulbinds/ConduitSocketTrait.cs new file mode 100644 index 00000000..09062bc2 --- /dev/null +++ b/src/ArgentPonyWarcraftClient/Models/ProfileApi/CharacterSoulbinds/ConduitSocketTrait.cs @@ -0,0 +1,22 @@ +using System.Text.Json.Serialization; + +namespace ArgentPonyWarcraftClient +{ + /// + /// A conduit socket trait for a character. + /// + public class ConduitSocketTrait + { + /// + /// Gets the type of conduit socket. + /// + [JsonPropertyName("type")] + public EnumType Type { get; set; } + + /// + /// Gets the socket details for the conduit. + /// + [JsonPropertyName("socket")] + public ConduitRank Socket { get; set; } + } +} diff --git a/src/ArgentPonyWarcraftClient/Models/ProfileApi/CharacterSoulbinds/SoulbindSelection.cs b/src/ArgentPonyWarcraftClient/Models/ProfileApi/CharacterSoulbinds/SoulbindSelection.cs new file mode 100644 index 00000000..15b00f43 --- /dev/null +++ b/src/ArgentPonyWarcraftClient/Models/ProfileApi/CharacterSoulbinds/SoulbindSelection.cs @@ -0,0 +1,28 @@ +using System.Text.Json.Serialization; + +namespace ArgentPonyWarcraftClient +{ + /// + /// A soulbind selection for a character. + /// + public class SoulbindSelection + { + /// + /// Gets a reference to the soulbind. + /// + [JsonPropertyName("soulbind")] + public SoulbindReference Soulbind { get; set; } + + /// + /// Gets the soulbinds and associated traits for the character. + /// + [JsonPropertyName("traits")] + public SoulbindTrait[] Traits { get; set; } + + /// + /// Gets a value indicating whether the soulbind is active for this character. + /// + [JsonPropertyName("is_active")] + public bool IsActive { get; set; } + } +} diff --git a/src/ArgentPonyWarcraftClient/Models/ProfileApi/CharacterSoulbinds/SoulbindTrait.cs b/src/ArgentPonyWarcraftClient/Models/ProfileApi/CharacterSoulbinds/SoulbindTrait.cs new file mode 100644 index 00000000..93051385 --- /dev/null +++ b/src/ArgentPonyWarcraftClient/Models/ProfileApi/CharacterSoulbinds/SoulbindTrait.cs @@ -0,0 +1,34 @@ +using System.Text.Json.Serialization; + +namespace ArgentPonyWarcraftClient +{ + /// + /// Character traits associated with a soulbind. + /// + public class SoulbindTrait + { + /// + /// Gets a reference to a tech talent selected as a trait for this character. + /// + [JsonPropertyName("trait")] + public TechTalentReference Trait { get; set; } + + /// + /// Gets the tier for this trait. + /// + [JsonPropertyName("tier")] + public long Tier { get; set; } + + /// + /// Gets the display order of this trait. + /// + [JsonPropertyName("display_order")] + public long DisplayOrder { get; set; } + + /// + /// Gets a conduit socket for this character. + /// + [JsonPropertyName("conduit_socket")] + public ConduitSocketTrait ConduitSocket { get; set; } + } +} diff --git a/tests/ArgentPonyWarcraftClient.Integration.Tests/ProfileApi/CharacterSoulbindsApiTests.cs b/tests/ArgentPonyWarcraftClient.Integration.Tests/ProfileApi/CharacterSoulbindsApiTests.cs new file mode 100644 index 00000000..677ec38c --- /dev/null +++ b/tests/ArgentPonyWarcraftClient.Integration.Tests/ProfileApi/CharacterSoulbindsApiTests.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Xunit; + +namespace ArgentPonyWarcraftClient.Integration.Tests.ProfileApi +{ + public class CharacterSoulbindsApiTests + { + [ResilientFact] + public async Task GetCharacterSoulbindsAsync_Gets_CharacterSoulbinds() + { + ICharacterSoulbindsApi warcraftClient = ClientFactory.BuildClient(); + RequestResult result = await warcraftClient.GetCharacterSoulbindsAsync("ravencrest", "drizzy", "profile-us"); + Assert.NotNull(result.Value); + } + } +} diff --git a/tests/ArgentPonyWarcraftClient.Tests/ProfileApi/CharacterSoulbindsApiTests.cs b/tests/ArgentPonyWarcraftClient.Tests/ProfileApi/CharacterSoulbindsApiTests.cs new file mode 100644 index 00000000..882575c5 --- /dev/null +++ b/tests/ArgentPonyWarcraftClient.Tests/ProfileApi/CharacterSoulbindsApiTests.cs @@ -0,0 +1,20 @@ +using System.Threading.Tasks; +using ArgentPonyWarcraftClient.Tests.Properties; +using Xunit; + +namespace ArgentPonyWarcraftClient.Tests.ProfileApi +{ + public class CharacterSoulbindsApiTests + { + [Fact] + public async Task GetCharacterSoulbindsAsync_Gets_CharacterSoulbinds() + { + ICharacterSoulbindsApi warcraftClient = ClientFactory.BuildMockClient( + requestUri: "https://us.api.blizzard.com/profile/wow/character/ravencrest/drizzy/soulbinds?namespace=profile-us&locale=en_US", + responseContent: Resources.CharacterSoulbindsResponse); + + RequestResult result = await warcraftClient.GetCharacterSoulbindsAsync("ravencrest", "drizzy", "profile-us"); + Assert.NotNull(result.Value); + } + } +} diff --git a/tests/ArgentPonyWarcraftClient.Tests/Properties/Resources.Designer.cs b/tests/ArgentPonyWarcraftClient.Tests/Properties/Resources.Designer.cs index ef0cc4aa..462cb236 100644 --- a/tests/ArgentPonyWarcraftClient.Tests/Properties/Resources.Designer.cs +++ b/tests/ArgentPonyWarcraftClient.Tests/Properties/Resources.Designer.cs @@ -952,6 +952,32 @@ internal static string CharacterReputationsSummaryResponse { } } + /// + /// Looks up a localized string similar to { + /// "_links": { + /// "self": { + /// "href": "https://us.api.blizzard.com/profile/wow/character/ravencrest/drizzy/soulbinds?namespace=profile-us" + /// } + /// }, + /// "character": { + /// "key": { + /// "href": "https://us.api.blizzard.com/profile/wow/character/ravencrest/drizzy?namespace=profile-us" + /// }, + /// "name": "Drizzy", + /// "id": 215331728, + /// "realm": { + /// "key": { + /// "href": "https://us.api.blizzard.com/data/wow/realm/1072?namespace=dynamic-us" + /// }, + /// "name": "Ravencrest", + /// [rest of string was truncated]";. + /// + internal static string CharacterSoulbindsResponse { + get { + return ResourceManager.GetString("CharacterSoulbindsResponse", resourceCulture); + } + } + /// /// Looks up a localized string similar to { /// "_links": { diff --git a/tests/ArgentPonyWarcraftClient.Tests/Properties/Resources.resx b/tests/ArgentPonyWarcraftClient.Tests/Properties/Resources.resx index 43f70241..20fbf112 100644 --- a/tests/ArgentPonyWarcraftClient.Tests/Properties/Resources.resx +++ b/tests/ArgentPonyWarcraftClient.Tests/Properties/Resources.resx @@ -73738,6 +73738,83 @@ "id": 46 } ] +} + + + { + "_links": { + "self": { + "href": "https://us.api.blizzard.com/profile/wow/character/ravencrest/drizzy/soulbinds?namespace=profile-us" + } + }, + "character": { + "key": { + "href": "https://us.api.blizzard.com/profile/wow/character/ravencrest/drizzy?namespace=profile-us" + }, + "name": "Drizzy", + "id": 215331728, + "realm": { + "key": { + "href": "https://us.api.blizzard.com/data/wow/realm/1072?namespace=dynamic-us" + }, + "name": "Ravencrest", + "id": 1072, + "slug": "ravencrest" + } + }, + "chosen_covenant": { + "key": { + "href": "https://us.api.blizzard.com/data/wow/covenant/1?namespace=static-9.0.2_36532-us" + }, + "name": "Kyrian", + "id": 1 + }, + "renown_level": 2, + "soulbinds": [ + { + "soulbind": { + "key": { + "href": "https://us.api.blizzard.com/data/wow/covenant/soulbind/7?namespace=static-9.0.2_36532-us" + }, + "name": "Pelagos", + "id": 7 + }, + "traits": [ + { + "trait": { + "key": { + "href": "https://us.api.blizzard.com/data/wow/tech-talent/1316?namespace=static-9.0.2_36532-us" + }, + "name": "Combat Meditation", + "id": 1316 + }, + "tier": 0, + "display_order": 1 + }, + { + "conduit_socket": { + "type": { + "type": "POTENCY", + "name": "Potency Conduit Slot" + }, + "socket": { + "conduit": { + "key": { + "href": "https://us.api.blizzard.com/data/wow/covenant/conduit/59?namespace=static-9.0.2_36532-us" + }, + "name": "Strike with Clarity", + "id": 59 + }, + "rank": 1 + } + }, + "tier": 1, + "display_order": 0 + } + ], + "is_active": true + } + ] } \ No newline at end of file