diff --git a/README.md b/README.md
index 7b63678..4ad9c1f 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,74 @@ Detailed player & tank statistics and history for [World of Tanks: Blitz](ht
- Frontent - Blazor WebAssembly (coming soon)
### Local MongoDB Installation for debugging ([Docker desktop for Windows](https://www.docker.com/products/docker-desktop))
-(Coming soon)
+For the developing and debugging purposes, you have to istall MongoDB locally on your dev machine and run it as a service. Alternatively, if you have istalled [Docker desktop for Windows](https://www.docker.com/products/docker-desktop), you can deploy MongoDB inside the container. To do so, create an empty folder and make 2 files there: ```docker-compose.yml``` and ```.env```. Second one will contain sensitive data.
+
+
+ Example for docker-compose.yml with mongo-express shell:
+
+```yml
+version: "3"
+services:
+ mongo:
+ image: mongo
+ restart: always
+ container_name: "mein-mongo"
+ ports:
+ - "27017:27017"
+ environment:
+ MONGO_INITDB_ROOT_USERNAME: "${DB_USERNAME}"
+ MONGO_INITDB_ROOT_PASSWORD: "${DB_PASSWORD}"
+ volumes:
+ - "mongodblvolume:/data/db"
+ mongo-express:
+ image: mongo-express
+ container_name: "mein-mongo-express"
+ restart: always
+ ports:
+ - 8081:8081
+ environment:
+ ME_CONFIG_MONGODB_ADMINUSERNAME: "${DB_USERNAME}"
+ ME_CONFIG_MONGODB_ADMINPASSWORD: "${DB_PASSWORD}"
+volumes:
+ mongodblvolume:
+```
+
+
+
+Example of .env file
+
+```
+DB_USERNAME=root
+DB_PASSWORD=P@SSW0RT!
+```
+
+
+To install docker, use shell command:
+
+```bash
+docker-compose up -d
+```
+
+That's all. You can use mongo shell like this:
+
+```bash
+docker exec -it mein-mongo bash
+mongo --username root --password --authenticationDatabase admin
+use your_database_name
+db.someSampleCollection.insert({})
+```
+
+Or you can use mongo-express by this address: http://localhost:8081/
+
+To use this mongo instance in application, use this connection string in ```appsettings.json```:
+
+```json
+{
+ "Mongo": {
+ "ConnectionString": "mongodb://root:P@SSW0RT!@localhost:27017/?authSource=admin"
+ }
+}
+```
### Hosting solution (k8s)
(Coming soon)
diff --git a/WotBlitzStatisticsPro.DataAccess/IWargamingAccountDataAccessor.cs b/WotBlitzStatisticsPro.DataAccess/IWargamingAccountDataAccessor.cs
new file mode 100644
index 0000000..0af5d0f
--- /dev/null
+++ b/WotBlitzStatisticsPro.DataAccess/IWargamingAccountDataAccessor.cs
@@ -0,0 +1,7 @@
+namespace WotBlitzStatisticsPro.DataAccess
+{
+ public interface IWargamingAccountDataAccessor
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.DataAccess/Model/Accounts/AccountInfo.cs b/WotBlitzStatisticsPro.DataAccess/Model/Accounts/AccountInfo.cs
new file mode 100644
index 0000000..f1ff745
--- /dev/null
+++ b/WotBlitzStatisticsPro.DataAccess/Model/Accounts/AccountInfo.cs
@@ -0,0 +1,42 @@
+using MongoDB.Bson.Serialization.Attributes;
+using WotBlitzStatisticsPro.Common.Model;
+
+namespace WotBlitzStatisticsPro.DataAccess.Model.Accounts
+{
+ ///
+ /// Account information
+ ///
+ public class AccountInfo
+ {
+ ///
+ /// Player account identifier
+ ///
+ [BsonId]
+ public long AccountId { get; set; }
+
+ ///
+ /// Player region
+ ///
+ public RealmType Realm { get; set; }
+
+ ///
+ /// Account creation date
+ ///
+ public int CreatedAt { get; set; }
+
+ ///
+ /// Last battle time
+ ///
+ public int LastBattleTime { get; set; }
+
+ ///
+ /// Player's nick
+ ///
+ public string Nickname { get; set; }
+
+ ///
+ /// Player information update date
+ ///
+ public int? UpdatedAt { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.DataAccess/WargamingAccountDataAccessor.cs b/WotBlitzStatisticsPro.DataAccess/WargamingAccountDataAccessor.cs
new file mode 100644
index 0000000..dfea248
--- /dev/null
+++ b/WotBlitzStatisticsPro.DataAccess/WargamingAccountDataAccessor.cs
@@ -0,0 +1,44 @@
+using System.Runtime.Serialization.Formatters;
+using MongoDB.Driver;
+using WotBlitzStatisticsPro.Common;
+using WotBlitzStatisticsPro.DataAccess.Model.Accounts;
+
+namespace WotBlitzStatisticsPro.DataAccess
+{
+ public class WargamingAccountDataAccessor : IWargamingAccountDataAccessor
+ {
+ private const string AccountInfoCollectionName = "account-info";
+
+
+ private readonly IMongoDatabase _database;
+
+ public WargamingAccountDataAccessor(IMongoSettings mongoSettings)
+ {
+ var client = new MongoClient(mongoSettings.ConnectionString);
+ _database = client.GetDatabase(mongoSettings.DatabaseName);
+
+ CreateAccountIndexesIfNotExists();
+ }
+
+ private void CreateAccountIndexesIfNotExists()
+ {
+ var accountInfoBuilder = Builders.IndexKeys;
+ var accountInfoRealmIndexModel = new CreateIndexModel(accountInfoBuilder.Ascending(a => a.Realm));
+ var accountInfoLastBattleTimeIndexModel = new CreateIndexModel(accountInfoBuilder.Descending(a => a.LastBattleTime));
+ _database.GetCollection(AccountInfoCollectionName).Indexes
+ .CreateMany(new[] {accountInfoRealmIndexModel, accountInfoLastBattleTimeIndexModel});
+
+
+ /*
+
+// Multiple keys
+var indexDefinition = Builders.IndexKeys.Combine(
+Builders.IndexKeys.Ascending(f => f.Key1),
+Builders.IndexKeys.Ascending(f => f.Key2));
+
+await collection.Indexes.CreateOneAsync(indexDefinition);
+ */
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.DataAccess/WotBlitzStatisticsDataAccessInstaller.cs b/WotBlitzStatisticsPro.DataAccess/WotBlitzStatisticsDataAccessInstaller.cs
index e7a8b7d..568f636 100644
--- a/WotBlitzStatisticsPro.DataAccess/WotBlitzStatisticsDataAccessInstaller.cs
+++ b/WotBlitzStatisticsPro.DataAccess/WotBlitzStatisticsDataAccessInstaller.cs
@@ -7,6 +7,7 @@ namespace WotBlitzStatisticsPro.DataAccess
public static void ConfigureServices(IServiceCollection services)
{
services.AddTransient();
+ services.AddTransient();
}
}
diff --git a/WotBlitzStatisticsPro.GraphQl/Mutation/WotBlitzStatisticsMutation.cs b/WotBlitzStatisticsPro.GraphQl/Mutation/WotBlitzStatisticsMutation.cs
index a386599..5d0f19e 100644
--- a/WotBlitzStatisticsPro.GraphQl/Mutation/WotBlitzStatisticsMutation.cs
+++ b/WotBlitzStatisticsPro.GraphQl/Mutation/WotBlitzStatisticsMutation.cs
@@ -10,10 +10,13 @@ namespace WotBlitzStatisticsPro.GraphQl.Mutation
public class WotBlitzStatisticsMutation
{
private readonly IWargamingDictionaries _wargamingDictionaries;
+ private readonly IWargamingAccounts _wargamingAccounts;
- public WotBlitzStatisticsMutation(IWargamingDictionaries wargamingDictionaries)
+ public WotBlitzStatisticsMutation(IWargamingDictionaries wargamingDictionaries,
+ IWargamingAccounts wargamingAccounts)
{
_wargamingDictionaries = wargamingDictionaries;
+ _wargamingAccounts = wargamingAccounts;
}
///
@@ -26,5 +29,17 @@ namespace WotBlitzStatisticsPro.GraphQl.Mutation
{
return _wargamingDictionaries.UpdateDictionaries(updateDictionariesRequest);
}
+
+ ///
+ /// Gathers all account information
+ ///
+ /// Account region
+ /// AccountId
+ /// Request language
+ ///
+ public Task GatherAccountInformation(RealmType realmType, long accountId, RequestLanguage requestLanguage)
+ {
+ return _wargamingAccounts.GatherAccountInformation(realmType, accountId, requestLanguage);
+ }
}
}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/AccountInformationPipelineContext.cs b/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/AccountInformationPipelineContext.cs
new file mode 100644
index 0000000..5a111ad
--- /dev/null
+++ b/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/AccountInformationPipelineContext.cs
@@ -0,0 +1,23 @@
+using WotBlitzStatisticsPro.Common.Model;
+
+namespace WotBlitzStatisticsPro.Logic.AccountInformationPipeline
+{
+ public class AccountInformationPipelineContext
+ {
+ public AccountInformationPipelineContext(
+ long accountId,
+ RealmType realmType,
+ RequestLanguage requestLanguage)
+ {
+ AccountId = accountId;
+ RealmType = realmType;
+ RequestLanguage = requestLanguage;
+ }
+
+
+ public long AccountId { get; }
+ public RealmType RealmType { get; }
+ public RequestLanguage RequestLanguage { get; }
+
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/Operations/GetAccountInfoOperation.cs b/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/Operations/GetAccountInfoOperation.cs
new file mode 100644
index 0000000..56dfc2b
--- /dev/null
+++ b/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/Operations/GetAccountInfoOperation.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Threading.Tasks;
+using WotBlitzStatisticsPro.Logic.Pipeline;
+
+namespace WotBlitzStatisticsPro.Logic.AccountInformationPipeline.Operations
+{
+ public class GetAccountInfoOperation: IOperation
+ {
+ public Task Invoke(AccountInformationPipelineContext context, Func next)
+ {
+ return next.Invoke(context);
+ }
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/Operations/GetTanksInfoOperation.cs b/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/Operations/GetTanksInfoOperation.cs
new file mode 100644
index 0000000..2f3dbd6
--- /dev/null
+++ b/WotBlitzStatisticsPro.Logic/AccountInformationPipeline/Operations/GetTanksInfoOperation.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Threading.Tasks;
+using WotBlitzStatisticsPro.Logic.Pipeline;
+
+namespace WotBlitzStatisticsPro.Logic.AccountInformationPipeline.Operations
+{
+ public class GetTanksInfoOperation: IOperation
+ {
+ public Task Invoke(AccountInformationPipelineContext context, Func next)
+ {
+ return next.Invoke(context);
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/IWargamingAccounts.cs b/WotBlitzStatisticsPro.Logic/IWargamingAccounts.cs
new file mode 100644
index 0000000..8c80730
--- /dev/null
+++ b/WotBlitzStatisticsPro.Logic/IWargamingAccounts.cs
@@ -0,0 +1,10 @@
+using System.Threading.Tasks;
+using WotBlitzStatisticsPro.Common.Model;
+
+namespace WotBlitzStatisticsPro.Logic
+{
+ public interface IWargamingAccounts
+ {
+ Task GatherAccountInformation(RealmType realm, long accountId, RequestLanguage requestLanguage);
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/Pipeline/IOperation.cs b/WotBlitzStatisticsPro.Logic/Pipeline/IOperation.cs
new file mode 100644
index 0000000..a820266
--- /dev/null
+++ b/WotBlitzStatisticsPro.Logic/Pipeline/IOperation.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Threading.Tasks;
+
+namespace WotBlitzStatisticsPro.Logic.Pipeline
+{
+ ///
+ /// Represents pipeline single operation
+ ///
+ public interface IOperation
+ {
+ ///
+ /// Invokes the pipeline operation
+ ///
+ /// Pipeline context
+ /// Next operation
+ Task Invoke(TContext context, Func next);
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/Pipeline/IOperationFactory.cs b/WotBlitzStatisticsPro.Logic/Pipeline/IOperationFactory.cs
new file mode 100644
index 0000000..d52c285
--- /dev/null
+++ b/WotBlitzStatisticsPro.Logic/Pipeline/IOperationFactory.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace WotBlitzStatisticsPro.Logic.Pipeline
+{
+ ///
+ /// Factory creates the operation instances.
+ ///
+ public interface IOperationFactory
+ {
+ ///
+ /// Creates new operation instance
+ ///
+ ///
+ ///
+ ///
+ IOperation Create(Type operationType);
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/Pipeline/IPipeline.cs b/WotBlitzStatisticsPro.Logic/Pipeline/IPipeline.cs
new file mode 100644
index 0000000..af8885c
--- /dev/null
+++ b/WotBlitzStatisticsPro.Logic/Pipeline/IPipeline.cs
@@ -0,0 +1,21 @@
+namespace WotBlitzStatisticsPro.Logic.Pipeline
+{
+ ///
+ /// Represents operation pipeline
+ ///
+ public interface IPipeline
+ {
+ ///
+ /// Builds the pipeline.
+ ///
+ /// First operation in pipeline.
+ IOperation Build();
+
+ ///
+ /// Adds operation type to the pipeline
+ ///
+ /// Operation type
+ /// Pipeline instance
+ IPipeline AddOperation() where TOperation : IOperation;
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/Pipeline/OperationMediator.cs b/WotBlitzStatisticsPro.Logic/Pipeline/OperationMediator.cs
new file mode 100644
index 0000000..2ca2fab
--- /dev/null
+++ b/WotBlitzStatisticsPro.Logic/Pipeline/OperationMediator.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Threading.Tasks;
+
+namespace WotBlitzStatisticsPro.Logic.Pipeline
+{
+ public class OperationMediator: IOperation
+ {
+ private readonly IOperation _current;
+ private readonly IOperation _next;
+
+ public OperationMediator(IOperation current, IOperation next)
+ {
+ _current = current ?? throw new ArgumentNullException(nameof(current));
+ _next = next;
+ }
+
+ public Task Invoke(TContext context, Func next)
+ {
+ return _current.Invoke(context, c => _next == null ? Task.CompletedTask : _next.Invoke(c, null));
+ }
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/Pipeline/Pipeline.cs b/WotBlitzStatisticsPro.Logic/Pipeline/Pipeline.cs
new file mode 100644
index 0000000..14ecd48
--- /dev/null
+++ b/WotBlitzStatisticsPro.Logic/Pipeline/Pipeline.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace WotBlitzStatisticsPro.Logic.Pipeline
+{
+ public class Pipeline: IPipeline
+ {
+ private readonly IOperationFactory _operationFactory;
+ private readonly List _operations = new List();
+
+ public Pipeline(IOperationFactory operationFactory)
+ {
+ _operationFactory = operationFactory;
+ }
+
+ public IOperation Build()
+ {
+ var allOperationTypes = _operations.ToArray();
+ var lastOperationType = allOperationTypes.LastOrDefault();
+ if (lastOperationType == null)
+ {
+ return null;
+ }
+ var nextOperation = new OperationMediator(_operationFactory.Create(lastOperationType), null);
+
+ for (int i = allOperationTypes.Length - 2; i >= 0; i--)
+ {
+ nextOperation = new OperationMediator(_operationFactory.Create(allOperationTypes[i]), nextOperation);
+ }
+
+ return nextOperation;
+ }
+
+ public IPipeline AddOperation() where TOperation : IOperation
+ {
+ _operations.Add(typeof(TOperation));
+ return this;
+ }
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/Pipeline/ServiceProviderOperationFactory.cs b/WotBlitzStatisticsPro.Logic/Pipeline/ServiceProviderOperationFactory.cs
new file mode 100644
index 0000000..f68513b
--- /dev/null
+++ b/WotBlitzStatisticsPro.Logic/Pipeline/ServiceProviderOperationFactory.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace WotBlitzStatisticsPro.Logic.Pipeline
+{
+ public class ServiceProviderOperationFactory: IOperationFactory
+ {
+ private readonly IServiceProvider _serviceProvider;
+
+ public ServiceProviderOperationFactory(IServiceProvider serviceProvider)
+ {
+ _serviceProvider = serviceProvider;
+ }
+
+ public IOperation Create(Type operationType)
+ {
+ return _serviceProvider.GetService(operationType) as IOperation;
+ }
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/WargamingAccounts.cs b/WotBlitzStatisticsPro.Logic/WargamingAccounts.cs
new file mode 100644
index 0000000..47c8081
--- /dev/null
+++ b/WotBlitzStatisticsPro.Logic/WargamingAccounts.cs
@@ -0,0 +1,37 @@
+using System.Threading.Tasks;
+using WotBlitzStatisticsPro.Common.Model;
+using WotBlitzStatisticsPro.Logic.AccountInformationPipeline;
+using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.Operations;
+using WotBlitzStatisticsPro.Logic.Pipeline;
+
+namespace WotBlitzStatisticsPro.Logic
+{
+ public class WargamingAccounts: IWargamingAccounts
+ {
+ private readonly IOperationFactory _operationFactory;
+
+ public WargamingAccounts(IOperationFactory operationFactory)
+ {
+ _operationFactory = operationFactory;
+ }
+
+ public async Task GatherAccountInformation(RealmType realm, long accountId, RequestLanguage requestLanguage)
+ {
+ var context = new AccountInformationPipelineContext(accountId, realm, requestLanguage);
+ var pipeline = new Pipeline(_operationFactory);
+
+ pipeline.AddOperation()
+ .AddOperation()
+ ;
+ // ToDo: add other operations
+
+ await pipeline.Build()
+ .Invoke(context, null)
+ .ConfigureAwait(false);
+
+ // ToDo: return context response
+
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Logic/WotBlitzStatisticsLogicInstaller.cs b/WotBlitzStatisticsPro.Logic/WotBlitzStatisticsLogicInstaller.cs
index a9a652b..4a1b96e 100644
--- a/WotBlitzStatisticsPro.Logic/WotBlitzStatisticsLogicInstaller.cs
+++ b/WotBlitzStatisticsPro.Logic/WotBlitzStatisticsLogicInstaller.cs
@@ -4,7 +4,9 @@ using AutoMapper;
using Microsoft.Extensions.DependencyInjection;
using WotBlitzStatisticsPro.Common.Model;
using WotBlitzStatisticsPro.DataAccess;
+using WotBlitzStatisticsPro.Logic.AccountInformationPipeline.Operations;
using WotBlitzStatisticsPro.Logic.Dictionaries;
+using WotBlitzStatisticsPro.Logic.Pipeline;
using WotBlitzStatisticsPro.WgApiClient;
[assembly: InternalsVisibleTo("WotBlitzStatisticsPro.Tests")]
@@ -17,12 +19,14 @@ namespace WotBlitzStatisticsPro.Logic
public static void ConfigureServices(IServiceCollection services)
{
ConfigureDictionariesFactory(services);
+ ConfigureOperationsFactory(services);
WotBlitzStatisticsDataAccessInstaller.ConfigureServices(services);
services.AddAutoMapper(typeof(WotBlitzStatisticsLogicInstaller));
services.AddHttpClient();
services.AddHttpClient();
services.AddTransient();
services.AddTransient();
+ services.AddTransient();
}
private static void ConfigureDictionariesFactory(IServiceCollection services)
@@ -31,10 +35,10 @@ namespace WotBlitzStatisticsPro.Logic
services.AddTransient();
services.AddTransient();
- RegisterFactoryMethod(services);
+ RegisterDictionariesFactoryMethod(services);
}
- internal static void RegisterFactoryMethod(IServiceCollection services)
+ internal static void RegisterDictionariesFactoryMethod(IServiceCollection services)
{
services.AddTransient(serviceProvider => dictionaryType =>
{
@@ -51,5 +55,14 @@ namespace WotBlitzStatisticsPro.Logic
}
});
}
+
+ private static void ConfigureOperationsFactory(IServiceCollection services)
+ {
+ services.AddTransient();
+ services.AddTransient();
+
+ services.AddTransient(serviceProvider =>
+ new ServiceProviderOperationFactory(serviceProvider));
+ }
}
}
\ No newline at end of file
diff --git a/WotBlitzStatisticsPro.Tests/DictionariesTests/DictionariesServiceTests.cs b/WotBlitzStatisticsPro.Tests/DictionariesTests/DictionariesServiceTests.cs
index a07c04b..e42cd09 100644
--- a/WotBlitzStatisticsPro.Tests/DictionariesTests/DictionariesServiceTests.cs
+++ b/WotBlitzStatisticsPro.Tests/DictionariesTests/DictionariesServiceTests.cs
@@ -36,7 +36,7 @@ namespace WotBlitzStatisticsPro.Tests.DictionariesTests
serviceProvider.AddSingleton(_achievementsDictionaryUpdaterMock.Object);
serviceProvider.AddSingleton(_vehiclesDictionaryUpdaterMock.Object);
- WotBlitzStatisticsLogicInstaller.RegisterFactoryMethod(serviceProvider);
+ WotBlitzStatisticsLogicInstaller.RegisterDictionariesFactoryMethod(serviceProvider);
var services = serviceProvider.BuildServiceProvider();