diff --git a/WotBlitzStatisticsPro.Common/Model/AccountAchievementsResponse.cs b/WotBlitzStatisticsPro.Common/Model/AccountAchievementsResponse.cs
new file mode 100644
index 0000000..f1155cd
--- /dev/null
+++ b/WotBlitzStatisticsPro.Common/Model/AccountAchievementsResponse.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using WotBlitzStatisticsPro.Common.Model.Achievements;
+
+namespace WotBlitzStatisticsPro.Common.Model
+{
+ ///
+ /// Represents information about player's achievements
+ ///
+ public class AccountAchievementsResponse
+ {
+ ///
+ /// Player Id
+ ///
+ public long AccountId { get; set; }
+
+ ///
+ /// Player Achievements by sections
+ ///
+ public List? AchievementSections { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Common/Model/Achievements/Achievement.cs b/WotBlitzStatisticsPro.Common/Model/Achievements/Achievement.cs
new file mode 100644
index 0000000..9ee7b5b
--- /dev/null
+++ b/WotBlitzStatisticsPro.Common/Model/Achievements/Achievement.cs
@@ -0,0 +1,64 @@
+namespace WotBlitzStatisticsPro.Common.Model.Achievements
+{
+ ///
+ /// Player's achievement information
+ ///
+ public class Achievement
+ {
+ ///
+ /// Achievement Id
+ ///
+ public string Id { get; set; } = string.Empty;
+
+ ///
+ /// Achievement value
+ ///
+ public int AchievementValue { get; set; }
+
+ ///
+ /// Achievement max series value
+ ///
+ public int? MaxSeriesValue { get; set; }
+
+ ///
+ /// Achievement condition
+ ///
+ public string? Condition { get; set; }
+
+ ///
+ /// Achievement description
+ ///
+ public string? Description { get; set; }
+
+ ///
+ /// Achievement normal sized image
+ ///
+ public string? Image { get; set; }
+
+ ///
+ /// Achievement big image
+ ///
+ public string? ImageBig { get; set; }
+
+ ///
+ /// Achievement name
+ ///
+ public string? Name { get; set; }
+
+ ///
+ /// Order
+ ///
+ public long? Order { get; set; }
+
+ ///
+ /// Section Id
+ ///
+ public string SectionId { get; set; } = string.Empty;
+
+ ///
+ /// Achievement type
+ ///
+ public string Type { get; set; } = string.Empty;
+
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Common/Model/Achievements/AchievementSection.cs b/WotBlitzStatisticsPro.Common/Model/Achievements/AchievementSection.cs
new file mode 100644
index 0000000..4a0dd66
--- /dev/null
+++ b/WotBlitzStatisticsPro.Common/Model/Achievements/AchievementSection.cs
@@ -0,0 +1,30 @@
+using System.Collections.Generic;
+
+namespace WotBlitzStatisticsPro.Common.Model.Achievements
+{
+ ///
+ /// Represents achievement section info and it's achievements list
+ ///
+ public class AchievementSection
+ {
+ ///
+ /// Section Identifier
+ ///
+ public string SectionId { get; set; } = string.Empty;
+
+ ///
+ /// Section order
+ ///
+ public int Order { get; set; }
+
+ ///
+ /// Section Name
+ ///
+ public string Name { get; set; } = string.Empty;
+
+ ///
+ /// Achievements in the section
+ ///
+ public List? Achievements { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Common/Model/ClanInfoResponse.cs b/WotBlitzStatisticsPro.Common/Model/ClanInfoResponse.cs
index d1b8cc6..89e9a18 100644
--- a/WotBlitzStatisticsPro.Common/Model/ClanInfoResponse.cs
+++ b/WotBlitzStatisticsPro.Common/Model/ClanInfoResponse.cs
@@ -18,10 +18,15 @@ namespace WotBlitzStatisticsPro.Common.Model
public DateTime JoinedAt { get; set; } = new DateTime(1970, 1, 1);
///
- /// Player clan role
+ /// Player clan role ID
///
public string? Role { get; set; }
+ ///
+ /// Player clan role
+ ///
+ public string RoleLocalized { get; set; }
+
///
/// Clan name
diff --git a/WotBlitzStatisticsPro.DataAccess/DictionariesDataAccessor.cs b/WotBlitzStatisticsPro.DataAccess/DictionariesDataAccessor.cs
index 77d6969..7bb9703 100644
--- a/WotBlitzStatisticsPro.DataAccess/DictionariesDataAccessor.cs
+++ b/WotBlitzStatisticsPro.DataAccess/DictionariesDataAccessor.cs
@@ -153,5 +153,21 @@ namespace WotBlitzStatisticsPro.DataAccess
return collection.ToDictionary(n => n.ClanRoleId, n => n.ClanRoleValueValue);
}
+
+ public async Task> GetAchievementSections()
+ {
+ var collection = await _database.GetCollection(AchievementsSectionsCollectionName)
+ .FindAsync(Builders.Filter.Empty);
+ return collection.ToList();
+ }
+
+ public async Task> GetAchievements(string[] achievementIds)
+ {
+ var collection = await _database.GetCollection(AchievementsCollectionName)
+ .Find(Builders.Filter.In(v => v.AchievementId, achievementIds))
+ .ToListAsync();
+
+ return collection.ToDictionary(a => a.AchievementId, a => a);
+ }
}
}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.DataAccess/IDictionariesDataAccessor.cs b/WotBlitzStatisticsPro.DataAccess/IDictionariesDataAccessor.cs
index 0f4a5c9..c4dd52d 100644
--- a/WotBlitzStatisticsPro.DataAccess/IDictionariesDataAccessor.cs
+++ b/WotBlitzStatisticsPro.DataAccess/IDictionariesDataAccessor.cs
@@ -2,6 +2,7 @@
using System.Threading.Tasks;
using WotBlitzStatisticsPro.Common.Dictionaries;
using WotBlitzStatisticsPro.Common.Model;
+using WotBlitzStatisticsPro.DataAccess.Model;
namespace WotBlitzStatisticsPro.DataAccess
{
@@ -32,5 +33,9 @@ namespace WotBlitzStatisticsPro.DataAccess
Task> GetTankTypes(RequestLanguage language);
Task> GetClanRoles(RequestLanguage language);
+
+ Task> GetAchievementSections();
+
+ Task> GetAchievements(string[] achievementIds);
}
}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.GraphQl/Query/WotBlitzAchievementsQuery.cs b/WotBlitzStatisticsPro.GraphQl/Query/WotBlitzAchievementsQuery.cs
new file mode 100644
index 0000000..b666794
--- /dev/null
+++ b/WotBlitzStatisticsPro.GraphQl/Query/WotBlitzAchievementsQuery.cs
@@ -0,0 +1,49 @@
+using System.Threading.Tasks;
+using HotChocolate.Types;
+using WotBlitzStatisticsPro.Common.Model;
+using WotBlitzStatisticsPro.Logic;
+
+namespace WotBlitzStatisticsPro.GraphQl.Query
+{
+ [ExtendObjectType(Name = "Query")]
+ public class WotBlitzAchievementsQuery
+ {
+ private readonly IWargamingAchievements _achievementsService;
+
+ public WotBlitzAchievementsQuery(IWargamingAchievements achievementsService)
+ {
+ _achievementsService = achievementsService;
+ }
+
+ ///
+ /// Returns information about player's achievements
+ ///
+ /// Account region
+ /// AccountId
+ /// Request language
+ public Task GetAccountAchievements(
+ long accountId,
+ RealmType? realmType,
+ RequestLanguage? requestLanguage)
+ {
+ return _achievementsService.GetAccountAchievements(realmType ?? RealmType.Ru, accountId, requestLanguage ?? RequestLanguage.En);
+ }
+
+ ///
+ /// Returns information about player's tank achievements
+ ///
+ /// Account tank Id
+ /// Account region
+ /// AccountId
+ /// Request language
+ public Task GetTankAchievements(
+ long accountId,
+ long tankId,
+ RealmType? realmType,
+ RequestLanguage? requestLanguage)
+ {
+ return _achievementsService.GetTankAchievements(realmType ?? RealmType.Ru, accountId, tankId, requestLanguage ?? RequestLanguage.En);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.GraphQl/Startup.cs b/WotBlitzStatisticsPro.GraphQl/Startup.cs
index 42a37b7..548748d 100644
--- a/WotBlitzStatisticsPro.GraphQl/Startup.cs
+++ b/WotBlitzStatisticsPro.GraphQl/Startup.cs
@@ -45,6 +45,7 @@ namespace WotBlitzStatisticsPro.GraphQl
.AddQueryType(d => d.Name("Query"))
.AddType()
.AddType()
+ .AddType()
.AddMutationType()
.AddType()
.AddType()
diff --git a/WotBlitzStatisticsPro.Logic/IWargamingAchievements.cs b/WotBlitzStatisticsPro.Logic/IWargamingAchievements.cs
new file mode 100644
index 0000000..126ac99
--- /dev/null
+++ b/WotBlitzStatisticsPro.Logic/IWargamingAchievements.cs
@@ -0,0 +1,15 @@
+using System.Threading.Tasks;
+using WotBlitzStatisticsPro.Common.Model;
+
+namespace WotBlitzStatisticsPro.Logic
+{
+ public interface IWargamingAchievements
+ {
+ Task GetAccountAchievements(RealmType realm, long accountId,
+ RequestLanguage requestLanguage);
+
+ Task GetTankAchievements(RealmType realm, long accountId,
+ long tankId,
+ RequestLanguage requestLanguage);
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/Mappers/AchievementDictionaryProfile.cs b/WotBlitzStatisticsPro.Logic/Mappers/AchievementDictionaryProfile.cs
deleted file mode 100644
index 6ac64bd..0000000
--- a/WotBlitzStatisticsPro.Logic/Mappers/AchievementDictionaryProfile.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using System.Collections.Generic;
-using AutoMapper;
-using WotBlitzStatisticsPro.Common.Dictionaries;
-using WotBlitzStatisticsPro.DataAccess.Model;
-using WotBlitzStatisticsPro.WgApiClient.Model;
-
-namespace WotBlitzStatisticsPro.Logic.Mappers
-{
- public class AchievementDictionaryProfile : Profile
- {
- public AchievementDictionaryProfile()
- {
- CreateMap()
- .ForMember(d => d.Name, o => o.MapFrom(_ => new List()))
- .ForMember(d => d.Condition, o => o.MapFrom(_ => new List()))
- .ForMember(d => d.Description, o => o.MapFrom(_ => new List()))
- .ForMember(d => d.HeroInfo, o => o.MapFrom(_ => new List()))
- .ForMember(d => d.SectionId, o => o.MapFrom(s => s.Section))
- .ForMember(d => d.Options, o => o.Ignore());
-
- }
- }
-}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/Mappers/AchievementOptionProfile.cs b/WotBlitzStatisticsPro.Logic/Mappers/AchievementOptionProfile.cs
deleted file mode 100644
index 12f2235..0000000
--- a/WotBlitzStatisticsPro.Logic/Mappers/AchievementOptionProfile.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System.Collections.Generic;
-using AutoMapper;
-using WotBlitzStatisticsPro.Common.Dictionaries;
-using WotBlitzStatisticsPro.WgApiClient.Model;
-
-namespace WotBlitzStatisticsPro.Logic.Mappers
-{
- public class AchievementOptionProfile : Profile
- {
- public AchievementOptionProfile()
- {
- CreateMap()
- .ForMember(d => d.Name, o => o.MapFrom(_ => new List()))
- .ForMember(d => d.Description, o => o.MapFrom(_ => new List()));
- }
- }
-}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/Mappers/AchievementsProfile.cs b/WotBlitzStatisticsPro.Logic/Mappers/AchievementsProfile.cs
new file mode 100644
index 0000000..6844a6d
--- /dev/null
+++ b/WotBlitzStatisticsPro.Logic/Mappers/AchievementsProfile.cs
@@ -0,0 +1,60 @@
+using System.Collections.Generic;
+using System.Linq;
+using AutoMapper;
+using WotBlitzStatisticsPro.Common.Dictionaries;
+using WotBlitzStatisticsPro.Common.Model;
+using WotBlitzStatisticsPro.Common.Model.Achievements;
+using WotBlitzStatisticsPro.DataAccess.Model;
+using WotBlitzStatisticsPro.WgApiClient.Model;
+
+namespace WotBlitzStatisticsPro.Logic.Mappers
+{
+ public class AchievementsProfile: Profile
+ {
+ public AchievementsProfile()
+ {
+ CreateMap()
+ .ForMember(d => d.Name, o => o.MapFrom(_ => new List()))
+ .ForMember(d => d.Description, o => o.MapFrom(_ => new List()));
+
+
+ CreateMap()
+ .ForMember(d => d.Name, o => o.MapFrom(_ => new List()))
+ .ForMember(d => d.Condition, o => o.MapFrom(_ => new List()))
+ .ForMember(d => d.Description, o => o.MapFrom(_ => new List()))
+ .ForMember(d => d.HeroInfo, o => o.MapFrom(_ => new List()))
+ .ForMember(d => d.SectionId, o => o.MapFrom(s => s.Section))
+ .ForMember(d => d.Options, o => o.Ignore());
+
+ CreateMap()
+ .ForMember(s => s.SectionId,
+ o => o.MapFrom(d => d.AchievementSectionId))
+ .ForMember(d => d.Name,
+ o => o.MapFrom((src, dest, destMember, context) =>
+ src.AchievementSectionNames
+ .FirstOrDefault(l => l.Language == (RequestLanguage) context.Items["language"])?.Value));
+
+ CreateMap, Achievement>()
+ .ForMember(d => d.Id, o => o.MapFrom(s => s.Key))
+ .ForMember(d => d.AchievementValue, o => o.MapFrom(s => s.Value));
+
+ CreateMap()
+ .ForMember(d => d.Condition,
+ o => o.MapFrom((src, dest, destMember, context) =>
+ src.Condition
+ .FirstOrDefault(l => l.Language == (RequestLanguage) context.Items["language"])?.Value))
+ .ForMember(d => d.Description,
+ o => o.MapFrom((src, dest, destMember, context) =>
+ src.Description
+ .FirstOrDefault(l => l.Language == (RequestLanguage) context.Items["language"])?.Value))
+ .ForMember(d => d.Name,
+ o => o.MapFrom((src, dest, destMember, context) =>
+ src.Name
+ .FirstOrDefault(l => l.Language == (RequestLanguage) context.Items["language"])?.Value))
+ .ForMember(d => d.Id, o => o.Ignore())
+ .ForMember(d => d.AchievementValue, o => o.Ignore())
+ .ForMember(d => d.MaxSeriesValue, s => s.Ignore())
+ ;
+ }
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/Mappers/ClansProfile.cs b/WotBlitzStatisticsPro.Logic/Mappers/ClansProfile.cs
index 7602c25..c145690 100644
--- a/WotBlitzStatisticsPro.Logic/Mappers/ClansProfile.cs
+++ b/WotBlitzStatisticsPro.Logic/Mappers/ClansProfile.cs
@@ -1,10 +1,7 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using AutoMapper;
-using WotBlitzStatisticsPro.Common.Dictionaries;
using WotBlitzStatisticsPro.Common.Model;
-using WotBlitzStatisticsPro.DataAccess.Model;
using WotBlitzStatisticsPro.WgApiClient.Model;
using WotBlitzStatisticsPro.Logic.Calculations;
@@ -18,7 +15,7 @@ namespace WotBlitzStatisticsPro.Logic.Mappers
CreateMap()
.ForMember(d => d.JoinedAt,
o => o.MapFrom(s => s.JoinedAt.HasValue ? s.JoinedAt.Value.ToDateTime() : new DateTime(1970, 1, 1)))
- .ForMember(d => d.Role,
+ .ForMember(d => d.RoleLocalized,
o => o.MapFrom((src, dest, destMember, context) =>
{
var dictionary = context.Items["roles"] as Dictionary;
diff --git a/WotBlitzStatisticsPro.Logic/WargamingAchievements.cs b/WotBlitzStatisticsPro.Logic/WargamingAchievements.cs
new file mode 100644
index 0000000..a92883b
--- /dev/null
+++ b/WotBlitzStatisticsPro.Logic/WargamingAchievements.cs
@@ -0,0 +1,149 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using AutoMapper;
+using Microsoft.Extensions.Logging;
+using WotBlitzStatisticsPro.Common.Model;
+using WotBlitzStatisticsPro.Common.Model.Achievements;
+using WotBlitzStatisticsPro.DataAccess;
+using WotBlitzStatisticsPro.DataAccess.Model;
+using WotBlitzStatisticsPro.WgApiClient;
+using WotBlitzStatisticsPro.WgApiClient.Model;
+
+namespace WotBlitzStatisticsPro.Logic
+{
+ public class WargamingAchievements: IWargamingAchievements
+ {
+ private readonly IDictionariesDataAccessor _dictionariesDataAccessor;
+ private readonly IWargamingAchievementsApiClient _wargamingAchievementsService;
+ private readonly IMapper _mapper;
+ private readonly ILogger _logger;
+
+ public WargamingAchievements(
+ IDictionariesDataAccessor dictionariesDataAccessor,
+ IWargamingAchievementsApiClient wargamingAchievementsService,
+ IMapper mapper,
+ ILogger logger)
+ {
+ _dictionariesDataAccessor = dictionariesDataAccessor;
+ _wargamingAchievementsService = wargamingAchievementsService;
+ _mapper = mapper;
+ _logger = logger;
+ }
+
+ public async Task GetAccountAchievements(RealmType realm, long accountId, RequestLanguage requestLanguage)
+ {
+ try
+ {
+ // Get account achievements from WG API
+ var wgAchievements =
+ await _wargamingAchievementsService.GetAccountAchievements(accountId, realm, requestLanguage);
+
+ return await FillAchievements(accountId, wgAchievements, requestLanguage);
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, "GetAccountAchievements error");
+
+ throw;
+ }
+ }
+
+ public async Task GetTankAchievements(RealmType realm, long accountId, long tankId, RequestLanguage requestLanguage)
+ {
+ try
+ {
+ // Get account achievements from WG API
+ var wgAchievements =
+ await _wargamingAchievementsService.GetTankAchievements(accountId, tankId, realm, requestLanguage);
+
+ return await FillAchievements(accountId, wgAchievements, requestLanguage);
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, "GetTankAchievements error");
+
+ throw;
+ }
+ }
+
+ private async Task FillAchievements(long accountId, WotAccountAchievementResponse? wgAchievements,
+ RequestLanguage requestLanguage)
+ {
+ // Read achievement sections from DB
+ var sectionsDictionary = await _dictionariesDataAccessor.GetAchievementSections();
+ var sections =
+ _mapper.Map, List>(sectionsDictionary,
+ context => context.Items["language"] = requestLanguage);
+
+ var response = new AccountAchievementsResponse
+ {
+ AccountId = accountId,
+ AchievementSections = sections
+ };
+
+ if (wgAchievements?.Achievements == null)
+ {
+ return response;
+ }
+
+ // Map ID And value
+ var achievements = _mapper.Map, List>(wgAchievements.Achievements);
+
+ // Add Max series
+ if (wgAchievements.MaxSeries != null)
+ {
+ foreach (var achievementsMaxSeries in wgAchievements.MaxSeries)
+ {
+ if (achievementsMaxSeries.Value == 0)
+ {
+ continue;
+ }
+ var existing = achievements.FirstOrDefault(a => a.Id == achievementsMaxSeries.Key);
+ if (existing == null)
+ {
+ achievements.Add(new Achievement
+ { Id = achievementsMaxSeries.Key, MaxSeriesValue = achievementsMaxSeries.Value });
+ }
+ else
+ {
+ existing.MaxSeriesValue = achievementsMaxSeries.Value;
+ }
+ }
+ }
+
+ // Read achievements dictionaries from DB
+ var achievementDictionaries =
+ await _dictionariesDataAccessor.GetAchievements(achievements.Select(a => a.Id).ToArray());
+
+ // Map achievements dictionaries
+ foreach (var achievement in achievements)
+ {
+ _mapper.Map(achievementDictionaries[achievement.Id], achievement,
+ context => context.Items["language"] = requestLanguage);
+
+ // Map achievement option if exists
+ if (achievementDictionaries[achievement.Id].Options.Count > 0)
+ {
+ if (achievement.AchievementValue < achievementDictionaries[achievement.Id].Options.Count)
+ {
+ achievement.Image = achievementDictionaries[achievement.Id]
+ .Options[achievement.AchievementValue - 1].Image;
+ achievement.ImageBig = achievementDictionaries[achievement.Id]
+ .Options[achievement.AchievementValue - 1].ImageBig;
+ }
+ }
+ }
+
+ // Sort achievements by sections
+ foreach (var section in response.AchievementSections)
+ {
+ section.Achievements = achievements.Where(a => a.SectionId == section.SectionId).ToList();
+ }
+
+ return response;
+ }
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/WotBlitzStatisticsLogicInstaller.cs b/WotBlitzStatisticsPro.Logic/WotBlitzStatisticsLogicInstaller.cs
index 8b0df9c..915eefb 100644
--- a/WotBlitzStatisticsPro.Logic/WotBlitzStatisticsLogicInstaller.cs
+++ b/WotBlitzStatisticsPro.Logic/WotBlitzStatisticsLogicInstaller.cs
@@ -26,10 +26,12 @@ namespace WotBlitzStatisticsPro.Logic
services.AddHttpClient();
services.AddHttpClient();
services.AddHttpClient();
+ services.AddHttpClient();
services.AddTransient();
services.AddTransient();
services.AddTransient();
services.AddTransient();
+ services.AddTransient();
}
private static void ConfigureDictionariesFactory(IServiceCollection services)
diff --git a/WotBlitzStatisticsPro.WgApiClient/IWargamingAchievementsApiClient.cs b/WotBlitzStatisticsPro.WgApiClient/IWargamingAchievementsApiClient.cs
new file mode 100644
index 0000000..9d08b88
--- /dev/null
+++ b/WotBlitzStatisticsPro.WgApiClient/IWargamingAchievementsApiClient.cs
@@ -0,0 +1,20 @@
+using System.Threading.Tasks;
+using WotBlitzStatisticsPro.Common.Model;
+using WotBlitzStatisticsPro.WgApiClient.Model;
+
+namespace WotBlitzStatisticsPro.WgApiClient
+{
+ public interface IWargamingAchievementsApiClient
+ {
+ Task GetAccountAchievements(
+ long accountId,
+ RealmType realmType = RealmType.Ru,
+ RequestLanguage language = RequestLanguage.En);
+
+ Task GetTankAchievements(
+ long accountId,
+ long tankId,
+ RealmType realmType = RealmType.Ru,
+ RequestLanguage language = RequestLanguage.En);
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.WgApiClient/Model/WotAccountAchievementResponse.cs b/WotBlitzStatisticsPro.WgApiClient/Model/WotAccountAchievementResponse.cs
new file mode 100644
index 0000000..26d03b1
--- /dev/null
+++ b/WotBlitzStatisticsPro.WgApiClient/Model/WotAccountAchievementResponse.cs
@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+namespace WotBlitzStatisticsPro.WgApiClient.Model
+{
+ public class WotAccountAchievementResponse
+ {
+ ///
+ /// Achievements
+ ///
+ [JsonProperty("achievements")]
+ public Dictionary? Achievements { get; set; }
+
+ ///
+ /// Max values if series achievements
+ ///
+ [JsonProperty("max_series")]
+ public Dictionary? MaxSeries { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.WgApiClient/WargamingAchievementsApiClient.cs b/WotBlitzStatisticsPro.WgApiClient/WargamingAchievementsApiClient.cs
new file mode 100644
index 0000000..11caa26
--- /dev/null
+++ b/WotBlitzStatisticsPro.WgApiClient/WargamingAchievementsApiClient.cs
@@ -0,0 +1,46 @@
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Threading.Tasks;
+using WotBlitzStatisticsPro.Common;
+using WotBlitzStatisticsPro.Common.Model;
+using WotBlitzStatisticsPro.WgApiClient.Model;
+
+namespace WotBlitzStatisticsPro.WgApiClient
+{
+ public class WargamingAchievementsApiClient: WagramingApiClientBase,
+ IWargamingAchievementsApiClient
+ {
+ public WargamingAchievementsApiClient(HttpClient httpClient, IWargamingApiSettings wargamingApiSettings) : base(httpClient, wargamingApiSettings)
+ {
+ }
+
+ public async Task GetAccountAchievements(long accountId, RealmType realmType = RealmType.Ru,
+ RequestLanguage language = RequestLanguage.En)
+ {
+ var accountAchievements = await GetFromBlitzApi>(
+ realmType,
+ language,
+ "account/achievements/",
+ $"account_id={accountId}").ConfigureAwait(false);
+ return accountAchievements?[accountId.ToString()];
+ }
+
+ public async Task GetTankAchievements(long accountId, long tankId, RealmType realmType = RealmType.Ru,
+ RequestLanguage language = RequestLanguage.En)
+ {
+ var accountAchievements = await GetFromBlitzApi>(
+ realmType,
+ language,
+ "tanks/achievements/",
+ $"account_id={accountId}",
+ $"tank_id={tankId}").ConfigureAwait(false);
+ if (accountAchievements?[accountId.ToString()] != null &&
+ accountAchievements?[accountId.ToString()].Length == 1)
+ {
+ return accountAchievements?[accountId.ToString()][0];
+ }
+
+ return null;
+ }
+ }
+}
\ No newline at end of file