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