Account info DTO

This commit is contained in:
Mikhail Shabanov committed 2020-09-30 19:30:36 +02:00
1 parent b343e36e0d
commit 5e0369511f
16 files changed
+557 -35

No files matched your search

@@ -0,0 +1,157 @@
using System;
using System.Collections.Generic;
namespace WotBlitzStatisticsPro.Common.Model
{
/// <summary>
/// Information about player
/// </summary>
public class AccountInfoResponse
{
///<summary>
/// Player account identifier
///</summary>
public long AccountId { get; set; }
///<summary>
/// Account creation date
///</summary>
public DateTime CreatedAt { get; set; }
///<summary>
/// Last battle time
///</summary>
public DateTime LastBattleTime { get; set; }
///<summary>
/// Player's nick
///</summary>
public string Nickname { get; set; }
///<summary>
/// Battles count
///</summary>
public long Battles { get; set; }
///<summary>
/// Capture points
///</summary>
public long CapturePoints { get; set; }
///<summary>
/// Total damage amount
///</summary>
public long DamageDealt { get; set; }
///<summary>
/// Total amount of received damage
///</summary>
public long DamageReceived { get; set; }
///<summary>
/// Dropped capture points
///</summary>
public long DroppedCapturePoints { get; set; }
///<summary>
/// Total amount of frags
///</summary>
public long Frags { get; set; }
///<summary>
/// Total amount of fras grater ten 8 lvl
///</summary>
public long Frags8P { get; set; }
///<summary>
/// Total amount of hits
///</summary>
public long Hits { get; set; }
///<summary>
/// Total amount of losses
///</summary>
public long Losses { get; set; }
///<summary>
/// Max frags per battle
///</summary>
public long MaxFrags { get; set; }
///<summary>
/// Tank id, which kills max frags per battle
///</summary>
public long MaxFragsTankId { get; set; }
///<summary>
/// Max experience per battle
///</summary>
public long MaxXp { get; set; }
///<summary>
/// Tank Id which created max experience per battle
///</summary>
public long MaxXpTankId { get; set; }
///<summary>
/// Total shots count
///</summary>
public long Shots { get; set; }
///<summary>
/// Total count of spotted vehicles
///</summary>
public long Spotted { get; set; }
///<summary>
/// Total count of survived battles
///</summary>
public long SurvivedBattles { get; set; }
///<summary>
/// Total count of survived and winned battles
///</summary>
public long WinAndSurvived { get; set; }
///<summary>
/// Total wins count
///</summary>
public long Wins { get; set; }
///<summary>
/// Total amount of experience
///</summary>
public long Xp { get; set; }
/// <summary>
/// Average tier
/// </summary>
public double AvgTier { get; set; }
/// <summary>
/// Wn7 coefficient
/// </summary>
public double Wn7 { get; set; }
/// <summary>
/// Player's win rate
/// </summary>
public decimal WinRate => Battles == 0 ? 0m : (decimal) 100 * Wins / Battles;
/// <summary>
/// Player's average damage
/// </summary>
public decimal AvgDamage => Battles == 0 ? 0m : (decimal)DamageDealt / Battles;
/// <summary>
/// Player's average XP
/// </summary>
public decimal AvgXp => Battles == 0 ? 0m : (decimal)Xp / Battles;
/// <summary>
/// All player's tanks
/// </summary>
public List<TankInfoResponse> Tanks { get; set; }
}
}
@@ -0,0 +1,186 @@
using System;
namespace WotBlitzStatisticsPro.Common.Model
{
/// <summary>
/// Information about player's tank
/// </summary>
public class TankInfoResponse
{
///<summary>
/// Player account identifier
///</summary>
public long AccountId { get; set; }
///<summary>
/// Tank identifier
///</summary>
public long TankId { get; set; }
/// <summary>
/// Total time in battle until tank killed
/// </summary>
public int BattleLifeTimeInSeconds { get; set; }
///<summary>
/// Last battle
///</summary>
public DateTime LastBattleTime { get; set; }
/// <summary>
/// Information is tank in garage or not. Information is not provided without Auth token
/// </summary>
public bool? InGarage { get; set; }
///<summary>
/// Mark of Mastery
///</summary>
public MarkOfMastery MarkOfMastery { get; set; }
///<summary>
/// Battles count
///</summary>
public long Battles { get; set; } = 1;
///<summary>
/// Base capture points
///</summary>
public long CapturePoints { get; set; }
///<summary>
/// Damage dealt
///</summary>
public long DamageDealt { get; set; }
///<summary>
/// Damage received
///</summary>
public long DamageReceived { get; set; }
///<summary>
/// Base dropped capture points
///</summary>
public long DroppedCapturePoints { get; set; }
///<summary>
/// Frags count
///</summary>
public long Frags { get; set; }
///<summary>
/// Frags count after 8 tier
///</summary>
public long Frags8P { get; set; }
///<summary>
/// Hits count
///</summary>
public long Hits { get; set; }
///<summary>
/// Losses count
///</summary>
public long Losses { get; set; }
///<summary>
/// Max frags per battle
///</summary>
public long MaxFrags { get; set; }
///<summary>
/// Max XP per battle
///</summary>
public long MaxXp { get; set; }
///<summary>
/// Shots count
///</summary>
public long Shots { get; set; }
///<summary>
/// Spotted vehicles count
///</summary>
public long Spotted { get; set; }
///<summary>
/// Amount of survived battles
///</summary>
public long SurvivedBattles { get; set; }
///<summary>
/// Amount of survived and wined battles
///</summary>
public long WinAndSurvived { get; set; }
///<summary>
/// Wins count
///</summary>
public long Wins { get; set; }
///<summary>
/// Total experience
///</summary>
public long Xp { get; set; }
/// <summary>
/// Wn7 coefficient
/// </summary>
public double Wn7 { get; set; }
/// <summary>
/// Average life time in battle until tank is killed.
/// </summary>
public decimal AvgBattleLifeTimeInMinutes => (decimal) BattleLifeTimeInSeconds / (60 * Battles);
/// <summary>
/// Tank's win rate
/// </summary>
public decimal WinRate => (decimal) 100 * Wins / Battles;
/// <summary>
/// Average tank's damage
/// </summary>
public decimal AvgDamage => (decimal) DamageDealt / Battles;
/// <summary>
/// Average XP
/// </summary>
public decimal AvgXp => (decimal) Xp / Battles;
/// <summary>
/// Tank name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Tank nation dictionary identifier
/// </summary>
public string TankNationId { get; set; }
/// <summary>
/// Localized tank nation name
/// </summary>
public string TankNation { get; set; }
/// <summary>
/// Tank tier
/// </summary>
public int Tier { get; set; }
/// <summary>
/// Tank type dictionary identifier
/// </summary>
public string TankTypeId { get; set; }
/// <summary>
/// Localized tank type name
/// </summary>
public string TankType { get; set; }
/// <summary>
/// Is it premium tank or not
/// </summary>
public bool IsPremium { get; set; }
}
}
@@ -4,6 +4,7 @@ using System.Threading.Tasks;
using MongoDB.Driver;
using WotBlitzStatisticsPro.Common;
using WotBlitzStatisticsPro.Common.Dictionaries;
using WotBlitzStatisticsPro.Common.Model;
using WotBlitzStatisticsPro.DataAccess.Model;
namespace WotBlitzStatisticsPro.DataAccess
@@ -101,5 +102,42 @@ namespace WotBlitzStatisticsPro.DataAccess
return collection.ToDictionary(k => k.TankId, v => v.Tier);
}
public async Task<Dictionary<long, IVehiclesDictionary>> GetVehicles(long[] tankIds)
{
var collection = await _database.GetCollection<VehiclesDictionary>(VehiclesCollectionName)
.Find(Builders<VehiclesDictionary>.Filter.In(v => v.TankId, tankIds))
.ToListAsync();
return collection.ToDictionary(k => k.TankId, v => v as IVehiclesDictionary);
}
public async Task<Dictionary<string, string>> GetNations(RequestLanguage language)
{
var collection = await _database.GetCollection<NationDictionary>(NationsCollectionName)
.Find(Builders<NationDictionary>.Filter.Empty)
.Project(n => new
{
nationId = n.NationId,
nationValue = n.NationNames.First(v => v.Language == language).Value
})
.ToListAsync();
return collection.ToDictionary(n => n.nationId, n => n.nationValue);
}
public async Task<Dictionary<string, string>> GetTankTypes(RequestLanguage language)
{
var collection = await _database.GetCollection<VehicleTypeDictionary>(VehicleTypesCollectionName)
.Find(Builders<VehicleTypeDictionary>.Filter.Empty)
.Project(n => new
{
typeId = n.VehicleTypeId,
typeValue = n.VehicleTypeNames.First(v => v.Language == language).Value
})
.ToListAsync();
return collection.ToDictionary(n => n.typeId, n => n.typeValue);
}
}
}
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using WotBlitzStatisticsPro.Common.Dictionaries;
using WotBlitzStatisticsPro.Common.Model;
namespace WotBlitzStatisticsPro.DataAccess
{
@@ -23,5 +24,11 @@ namespace WotBlitzStatisticsPro.DataAccess
Task<List<ILanguageDictionary>> ReadLanguages();
Task<Dictionary<long, int>> GetTankTires(long[] tankIds);
Task<Dictionary<long, IVehiclesDictionary>> GetVehicles(long[] tankIds);
Task<Dictionary<string, string>> GetNations(RequestLanguage language);
Task<Dictionary<string, string>> GetTankTypes(RequestLanguage language);
}
}
@@ -19,91 +19,90 @@
///<summary>
/// Battles count
///</summary>
public long? Battles { get; set; }
public long Battles { get; set; }
///<summary>
/// Base capture points
///</summary>
public long? CapturePoints { get; set; }
public long CapturePoints { get; set; }
///<summary>
/// Damage dealt
///</summary>
public long? DamageDealt { get; set; }
public long DamageDealt { get; set; }
///<summary>
/// Damage received
///</summary>
public long? DamageReceived { get; set; }
public long DamageReceived { get; set; }
///<summary>
/// Base dropped capture points
///</summary>
public long? DroppedCapturePoints { get; set; }
public long DroppedCapturePoints { get; set; }
///<summary>
/// Frags count
///</summary>
public long? Frags { get; set; }
public long Frags { get; set; }
///<summary>
/// Frags count after 8 tier
///</summary>
public long? Frags8P { get; set; }
public long Frags8P { get; set; }
///<summary>
/// Hits count
///</summary>
public long? Hits { get; set; }
public long Hits { get; set; }
///<summary>
/// Losses count
///</summary>
public long? Losses { get; set; }
public long Losses { get; set; }
///<summary>
/// Max frags per battle
///</summary>
public long? MaxFrags { get; set; }
public long MaxFrags { get; set; }
///<summary>
/// Max XP per battle
///</summary>
public long? MaxXp { get; set; }
public long MaxXp { get; set; }
///<summary>
/// Shots count
///</summary>
public long? Shots { get; set; }
public long Shots { get; set; }
///<summary>
/// Spotted vehicles count
///</summary>
public long? Spotted { get; set; }
public long Spotted { get; set; }
///<summary>
/// Amount of survived battles
///</summary>
public long? SurvivedBattles { get; set; }
public long SurvivedBattles { get; set; }
///<summary>
/// Amount of survived and wined battles
///</summary>
public long? WinAndSurvived { get; set; }
public long WinAndSurvived { get; set; }
///<summary>
/// Wins count
///</summary>
public long? Wins { get; set; }
public long Wins { get; set; }
///<summary>
/// Total experience
///</summary>
public long? Xp { get; set; }
public long Xp { get; set; }
/// <summary>
/// Wn7 coefficient
@@ -37,7 +37,7 @@ namespace WotBlitzStatisticsPro.GraphQl.Mutation
/// <param name="accountId">AccountId</param>
/// <param name="requestLanguage">Request language</param>
/// <returns></returns>
public Task<bool> GatherAccountInformation(RealmType realmType, long accountId, RequestLanguage requestLanguage)
public Task<AccountInfoResponse> GatherAccountInformation(RealmType realmType, long accountId, RequestLanguage requestLanguage)
{
return _wargamingAccounts.GatherAccountInformation(realmType, accountId, requestLanguage);
}
@@ -29,5 +29,7 @@ namespace WotBlitzStatisticsPro.Logic.AccountInformationPipeline
public Dictionary<long, TankInfoHistory> TanksHistory { get; set; }
public AccountInfoResponse Response { get; set; }
}
}
@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AutoMapper;
using WotBlitzStatisticsPro.Common.Dictionaries;
using WotBlitzStatisticsPro.Common.Model;
using WotBlitzStatisticsPro.DataAccess;
using WotBlitzStatisticsPro.DataAccess.Model;
using WotBlitzStatisticsPro.DataAccess.Model.Accounts;
using WotBlitzStatisticsPro.Logic.Pipeline;
namespace WotBlitzStatisticsPro.Logic.AccountInformationPipeline.Operations
{
public class BuildAccountInfoResponseOperation : IOperation<AccountInformationPipelineContext>
{
private readonly IMapper _mapper;
private readonly IDictionariesDataAccessor _dictionariesDataAccessor;
public BuildAccountInfoResponseOperation(IMapper mapper, IDictionariesDataAccessor dictionariesDataAccessor)
{
_mapper = mapper;
_dictionariesDataAccessor = dictionariesDataAccessor;
}
public async Task Invoke(AccountInformationPipelineContext context, Func<AccountInformationPipelineContext, Task> next)
{
context.Response = _mapper.Map<AccountInfo, AccountInfoResponse>(context.AccountInfo);
context.Response = _mapper.Map(context.AccountInfoHistory, context.Response);
var tankIds = context.Tanks.Select(t => t.TankId).ToArray();
var vehicles = await _dictionariesDataAccessor.GetVehicles(tankIds);
var nations = await _dictionariesDataAccessor.GetNations(context.RequestLanguage);
var tankTypes = await _dictionariesDataAccessor.GetTankTypes(context.RequestLanguage);
context.Response.Tanks = _mapper.Map<List<TankInfo>, List<TankInfoResponse>>(context.Tanks);
context.Response.Tanks.ForEach(t =>
{
t = _mapper.Map(context.TanksHistory[t.TankId], t);
var vehicle = vehicles.ContainsKey(t.TankId) ? vehicles[t.TankId] : CreateStubVehicle();
t = _mapper.Map(vehicle, t,
opt =>
{
opt.Items["language"] = context.RequestLanguage;
opt.AfterMap((src, dest) =>
{
dest.TankType = tankTypes.ContainsKey(dest.TankTypeId) ? tankTypes[dest.TankTypeId] : "-";
dest.TankNation = nations.ContainsKey(dest.TankNationId) ? nations[dest.TankNationId] : "-";
});
});
});
await next.Invoke(context);
}
private static IVehiclesDictionary CreateStubVehicle()
{
return new VehiclesDictionary
{
Name = new List<LocalizableString>()
{
new LocalizableString
{Language = RequestLanguage.En, Value = "[Vehicle is not provided in the dictionary]"},
new LocalizableString {Language = RequestLanguage.Ru, Value = "[Танк отсутствует в танкопедии]"},
new LocalizableString
{Language = RequestLanguage.De, Value = "[Tank ist nicht im Wörterbuch enthalten]"},
}
};
}
}
}
@@ -0,0 +1,17 @@
using System;
namespace WotBlitzStatisticsPro.Logic.Calculations
{
public static class DateTimeHelper
{
public static DateTime ToDateTime(this int unixTimeStamp)
{
// Unix timestamp is seconds past epoch
var dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
dtDateTime = dtDateTime.AddSeconds(unixTimeStamp).ToLocalTime();
return dtDateTime;
}
}
}
@@ -14,9 +14,9 @@ namespace WotBlitzStatisticsPro.Logic.Calculations
}
foreach (var tank in allTanks)
{
if (tankTires.ContainsKey(tank.TankId) && tank.Battles.HasValue && tank.Battles > 0)
if (tankTires.ContainsKey(tank.TankId) && tank.Battles > 0)
{
x += tankTires[tank.TankId] * tank.Battles.Value;
x += tankTires[tank.TankId] * tank.Battles;
}
}
if (account.Battles > 0)
@@ -26,17 +26,13 @@ namespace WotBlitzStatisticsPro.Logic.Calculations
public static void CalculateWn7(this TankInfoHistory tank, double tier)
{
if (!tank.Battles.HasValue)
{
return;
}
double avdFrags = tank.Frags.DoubleValue() / tank.Battles.DoubleValue();
double avgDamage = tank.DamageDealt.DoubleValue() / tank.Battles.DoubleValue();
double avgSpot = tank.Spotted.DoubleValue() / tank.Battles.DoubleValue();
double avgDef = tank.DroppedCapturePoints.DoubleValue() / tank.Battles.DoubleValue();
double winRate = (100d * tank.Wins.DoubleValue() / tank.Battles.DoubleValue()); // - 48;
double avdFrags = (double) tank.Frags / tank.Battles;
double avgDamage = (double)tank.DamageDealt / tank.Battles;
double avgSpot = (double)tank.Spotted / tank.Battles;
double avgDef = (double)tank.DroppedCapturePoints / tank.Battles;
double winRate = (100d * (double) tank.Wins / tank.Battles); // - 48;
tank.Wn7 = CalculateWn7(tank.Battles.Value, tier, avdFrags, avgDamage, avgSpot, avgDef, winRate);
tank.Wn7 = CalculateWn7(tank.Battles, tier, avdFrags, avgDamage, avgSpot, avgDef, winRate);
}
public static void CalculateWn7(this AccountInfoHistory account)
@@ -5,6 +5,6 @@ namespace WotBlitzStatisticsPro.Logic
{
public interface IWargamingAccounts
{
Task<bool> GatherAccountInformation(RealmType realm, long accountId, RequestLanguage requestLanguage);
Task<AccountInfoResponse> GatherAccountInformation(RealmType realm, long accountId, RequestLanguage requestLanguage);
}
}
@@ -0,0 +1,46 @@
using System.Linq;
using AutoMapper;
using WotBlitzStatisticsPro.Common.Dictionaries;
using WotBlitzStatisticsPro.Common.Model;
using WotBlitzStatisticsPro.DataAccess.Model;
using WotBlitzStatisticsPro.DataAccess.Model.Accounts;
using WotBlitzStatisticsPro.Logic.Calculations;
namespace WotBlitzStatisticsPro.Logic.Mappers
{
public class AccountDtoProfile: Profile
{
public AccountDtoProfile()
{
CreateMap<AccountInfo, AccountInfoResponse>()
.ForMember(dest => dest.CreatedAt,
o => o.MapFrom(s => s.CreatedAt.ToDateTime()))
.ForMember(dest => dest.LastBattleTime,
o => o.MapFrom(s => s.LastBattleTime.ToDateTime()));
CreateMap<AccountInfoHistory, AccountInfoResponse>()
.ForMember(d => d.LastBattleTime, o => o.Ignore())
.ForMember(d => d.Battles,
o => o.MapFrom(s => s.Battles ?? 0));
CreateMap<TankInfo, TankInfoResponse>()
.ForMember(dest => dest.LastBattleTime,
o => o.MapFrom(s => s.LastBattleTime.ToDateTime()));
CreateMap<TankInfoHistory, TankInfoResponse>()
.ForMember(d => d.LastBattleTime,
o => o.Ignore());
CreateMap<IVehiclesDictionary, TankInfoResponse>()
.ForMember(d => d.TankId, o => o.Ignore())
.ForMember(d => d.TankNationId,
o => o.MapFrom(s => string.IsNullOrEmpty(s.NationId) ? "-" : s.NationId))
.ForMember(d => d.TankTypeId,
o => o.MapFrom(s => string.IsNullOrEmpty(s.TypeId) ? "-" : s.TypeId))
.ForMember(d => d.Name,
o => o.MapFrom((src, dest, destMember, context) =>
src.Name.FirstOrDefault(l => l.Language == (RequestLanguage) context.Items["language"])?.Value));
}
}
}
@@ -15,7 +15,7 @@ namespace WotBlitzStatisticsPro.Logic
_operationFactory = operationFactory;
}
public async Task<bool> GatherAccountInformation(RealmType realm, long accountId, RequestLanguage requestLanguage)
public async Task<AccountInfoResponse> GatherAccountInformation(RealmType realm, long accountId, RequestLanguage requestLanguage)
{
var context = new AccountInformationPipelineContext(accountId, realm, requestLanguage);
var pipeline = new Pipeline<AccountInformationPipelineContext>(_operationFactory);
@@ -23,6 +23,7 @@ namespace WotBlitzStatisticsPro.Logic
pipeline.AddOperation<GetAccountInfoOperation>()
.AddOperation<GetTanksInfoOperation>()
.AddOperation<CalculateStatisticsOperation>()
.AddOperation<BuildAccountInfoResponseOperation>()
;
// ToDo: add other operations
@@ -32,7 +33,7 @@ namespace WotBlitzStatisticsPro.Logic
// ToDo: return context response
return true;
return context.Response;
}
}
}
@@ -62,6 +62,7 @@ namespace WotBlitzStatisticsPro.Logic
services.AddTransient<GetAccountInfoOperation>();
services.AddTransient<GetTanksInfoOperation>();
services.AddTransient<CalculateStatisticsOperation>();
services.AddTransient<BuildAccountInfoResponseOperation>();
services.AddTransient<IOperationFactory>(serviceProvider =>
new ServiceProviderOperationFactory(serviceProvider));
@@ -154,7 +154,7 @@ namespace WotBlitzStatisticsPro.WgApiClient
language,
"tanks/stats/",
$"account_id={accountId}").ConfigureAwait(false);
return tanks[accountId.ToString()];
return tanks[accountId.ToString()] ?? new List<WotAccountTanksStatistics>();
}
#endregion