diff --git a/BuildRevisionCounter.Contract/BuildRevisionCounter.Protocol.csproj b/BuildRevisionCounter.Contract/BuildRevisionCounter.Protocol.csproj
new file mode 100644
index 0000000..d794d81
--- /dev/null
+++ b/BuildRevisionCounter.Contract/BuildRevisionCounter.Protocol.csproj
@@ -0,0 +1,54 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {667844E5-6D11-474D-A18F-BC4784626F34}
+ Library
+ Properties
+ BuildRevisionCounter.Protocol
+ BuildRevisionCounter.Protocol
+ v4.5
+ 512
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/BuildRevisionCounter.Contract/Properties/AssemblyInfo.cs b/BuildRevisionCounter.Contract/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..9f8219b
--- /dev/null
+++ b/BuildRevisionCounter.Contract/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("BuildRevisionCounter.Contract")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("BuildRevisionCounter.Contract")]
+[assembly: AssemblyCopyright("Copyright © 2015")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("91410165-4321-4bb2-9665-c1c0e36dc1d4")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/BuildRevisionCounter.Contract/Revision.cs b/BuildRevisionCounter.Contract/Revision.cs
new file mode 100644
index 0000000..bf84c7a
--- /dev/null
+++ b/BuildRevisionCounter.Contract/Revision.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace BuildRevisionCounter.Protocol
+{
+ public class Revision
+ {
+ public string Id { get; set; }
+
+ public DateTime Created { get; set; }
+
+ public DateTime Updated { get; set; }
+
+ public long CurrentNumber { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/BuildRevisionCounter.Contract/User.cs b/BuildRevisionCounter.Contract/User.cs
new file mode 100644
index 0000000..3ba213f
--- /dev/null
+++ b/BuildRevisionCounter.Contract/User.cs
@@ -0,0 +1,11 @@
+namespace BuildRevisionCounter.Protocol
+{
+ public class User
+ {
+ public string Name { get; set; }
+
+ public string Password { get; set; }
+
+ public string[] Roles { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/BuildRevisionCounter.Core/BuildRevisionCounter.Core.csproj b/BuildRevisionCounter.Core/BuildRevisionCounter.Core.csproj
new file mode 100644
index 0000000..99d5b9e
--- /dev/null
+++ b/BuildRevisionCounter.Core/BuildRevisionCounter.Core.csproj
@@ -0,0 +1,92 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {DDF51396-4EE1-45AF-B134-CA1C56B0CD9F}
+ Library
+ Properties
+ BuildRevisionCounter.Core
+ BuildRevisionCounter.Core
+ v4.5.1
+ 512
+
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\packages\MongoDB.Bson.2.0.0\lib\net45\MongoDB.Bson.dll
+ True
+
+
+ ..\packages\MongoDB.Driver.2.0.0\lib\net45\MongoDB.Driver.dll
+ True
+
+
+ ..\packages\MongoDB.Driver.Core.2.0.0\lib\net45\MongoDB.Driver.Core.dll
+ True
+
+
+ ..\packages\mongocsharpdriver.2.0.0\lib\net45\MongoDB.Driver.Legacy.dll
+ True
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {667844e5-6d11-474d-a18f-bc4784626f34}
+ BuildRevisionCounter.Protocol
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/BuildRevisionCounter.Core/Converters/IRevisionConverter.cs b/BuildRevisionCounter.Core/Converters/IRevisionConverter.cs
new file mode 100644
index 0000000..e10d86b
--- /dev/null
+++ b/BuildRevisionCounter.Core/Converters/IRevisionConverter.cs
@@ -0,0 +1,11 @@
+using BuildRevisionCounter.Core.DomainObjects;
+
+namespace BuildRevisionCounter.Core.Converters
+{
+ internal interface IRevisionConverter
+ {
+ Protocol.Revision ToProtocol(Revision revision);
+
+ Revision ToDomain(Protocol.Revision revision);
+ }
+}
\ No newline at end of file
diff --git a/BuildRevisionCounter.Core/Converters/IUserConverter.cs b/BuildRevisionCounter.Core/Converters/IUserConverter.cs
new file mode 100644
index 0000000..3f74753
--- /dev/null
+++ b/BuildRevisionCounter.Core/Converters/IUserConverter.cs
@@ -0,0 +1,11 @@
+using BuildRevisionCounter.Core.DomainObjects;
+
+namespace BuildRevisionCounter.Core.Converters
+{
+ internal interface IUserConverter
+ {
+ Protocol.User ToProtocol(User user);
+
+ User ToDomain(Protocol.User user);
+ }
+}
\ No newline at end of file
diff --git a/BuildRevisionCounter.Core/Converters/Impl/RevisionConverter.cs b/BuildRevisionCounter.Core/Converters/Impl/RevisionConverter.cs
new file mode 100644
index 0000000..b45cd2c
--- /dev/null
+++ b/BuildRevisionCounter.Core/Converters/Impl/RevisionConverter.cs
@@ -0,0 +1,33 @@
+using BuildRevisionCounter.Core.DomainObjects;
+
+namespace BuildRevisionCounter.Core.Converters.Impl
+{
+ internal class RevisionConverter : IRevisionConverter
+ {
+ public Protocol.Revision ToProtocol(Revision revision)
+ {
+ var revisionProtocol = new Protocol.Revision
+ {
+ Id = revision.Id,
+ CurrentNumber = revision.CurrentNumber,
+ Updated = revision.Updated,
+ Created = revision.Created
+ };
+
+ return revisionProtocol;
+ }
+
+ public Revision ToDomain(Protocol.Revision revision)
+ {
+ var revisionDomain = new Revision
+ {
+ Id = revision.Id,
+ CurrentNumber = revision.CurrentNumber,
+ Updated = revision.Updated,
+ Created = revision.Created
+ };
+
+ return revisionDomain;
+ }
+ }
+}
\ No newline at end of file
diff --git a/BuildRevisionCounter.Core/Converters/Impl/UserConverter.cs b/BuildRevisionCounter.Core/Converters/Impl/UserConverter.cs
new file mode 100644
index 0000000..60247a9
--- /dev/null
+++ b/BuildRevisionCounter.Core/Converters/Impl/UserConverter.cs
@@ -0,0 +1,21 @@
+using BuildRevisionCounter.Core.DomainObjects;
+
+namespace BuildRevisionCounter.Core.Converters.Impl
+{
+ internal class UserConverter : IUserConverter
+ {
+ public Protocol.User ToProtocol(User user)
+ {
+ var userProtocol = new Protocol.User { Name = user.Name, Password = user.Password, Roles = user.Roles };
+
+ return userProtocol;
+ }
+
+ public User ToDomain(Protocol.User user)
+ {
+ var userDomain = new User { Name = user.Name, Password = user.Password, Roles = user.Roles };
+
+ return userDomain;
+ }
+ }
+}
\ No newline at end of file
diff --git a/BuildRevisionCounter.Core/DomainObjects/Revision.cs b/BuildRevisionCounter.Core/DomainObjects/Revision.cs
new file mode 100644
index 0000000..07ad49b
--- /dev/null
+++ b/BuildRevisionCounter.Core/DomainObjects/Revision.cs
@@ -0,0 +1,20 @@
+using System;
+using MongoDB.Bson.Serialization.Attributes;
+
+namespace BuildRevisionCounter.Core.DomainObjects
+{
+ internal class Revision
+ {
+ [BsonId]
+ public string Id;
+
+ [BsonElement("created"), BsonDateTimeOptions(Kind = DateTimeKind.Utc)]
+ public DateTime Created;
+
+ [BsonElement("updated"), BsonDateTimeOptions(Kind = DateTimeKind.Utc)]
+ public DateTime Updated;
+
+ [BsonElement("currentNumber")]
+ public long CurrentNumber;
+ }
+}
\ No newline at end of file
diff --git a/BuildRevisionCounter/Model/UserModel.cs b/BuildRevisionCounter.Core/DomainObjects/User.cs
similarity index 76%
rename from BuildRevisionCounter/Model/UserModel.cs
rename to BuildRevisionCounter.Core/DomainObjects/User.cs
index 8506596..2b280c0 100644
--- a/BuildRevisionCounter/Model/UserModel.cs
+++ b/BuildRevisionCounter.Core/DomainObjects/User.cs
@@ -1,8 +1,8 @@
using MongoDB.Bson.Serialization.Attributes;
-namespace BuildRevisionCounter.Model
+namespace BuildRevisionCounter.Core.DomainObjects
{
- public class UserModel
+ internal class User
{
[BsonId]
public string Name { get; set; }
diff --git a/BuildRevisionCounter.Core/MongoDBStorage.cs b/BuildRevisionCounter.Core/MongoDBStorage.cs
new file mode 100644
index 0000000..5827f24
--- /dev/null
+++ b/BuildRevisionCounter.Core/MongoDBStorage.cs
@@ -0,0 +1,119 @@
+using System;
+using System.Configuration;
+using System.Threading.Tasks;
+using BuildRevisionCounter.Core.DomainObjects;
+using MongoDB.Driver;
+
+namespace BuildRevisionCounter.Core
+{
+ public class MongoContext : IRepository
+ {
+ public static readonly string AdminName = "admin";
+ public static readonly string AdminPassword = "admin";
+ public static readonly string[] AdminRoles = { "admin", "buildserver", "editor" };
+
+ private static readonly Object SLock = new Object();
+ private static volatile MongoContext _instance = null;
+
+ private readonly IMongoClient _client;
+ internal IMongoClient Client
+ {
+ get { return _client; }
+ }
+
+ private readonly IMongoDatabase _database;
+ internal IMongoDatabase Database
+ {
+ get { return _database; }
+ }
+
+ private MongoContext()
+ {
+ string connectionString = ConfigurationManager.ConnectionStrings["MongoDBStorage"].ConnectionString;
+ var url = new MongoUrl(connectionString);
+
+ _client = new MongoClient(url);
+ _database = _client.GetDatabase(url.DatabaseName);
+
+ CreateAdmin();
+ }
+
+ public static MongoContext Instance
+ {
+ get
+ {
+ if (_instance == null)
+ {
+ lock (SLock)
+ {
+ if (_instance == null)
+ _instance = new MongoContext();
+ }
+ }
+ return _instance;
+ }
+ }
+
+ public async Task SetUpAsync()
+ {
+ await Users.Indexes.CreateOneAsync(
+ Builders.IndexKeys.Ascending(u => u.Name),
+ new CreateIndexOptions { Unique = true });
+
+ await EnsureAdminUser();
+ }
+
+ public async Task DropDatabaseAsync()
+ {
+ await Client.DropDatabaseAsync(Database.DatabaseNamespace.DatabaseName);
+ }
+
+ public async Task EnsureAdminUser()
+ {
+ var repository = RepositoryFactory.Instance.GetUserRepository();
+
+ if (await repository.CountAsync() == 0)
+ {
+ await repository.CreateUserAsync(new Protocol.User
+ {
+ Name = AdminName,
+ Password = AdminPassword,
+ Roles = AdminRoles
+ });
+ }
+ }
+
+ internal IMongoCollection Revisions
+ {
+ get { return _database.GetCollection("revisions"); }
+ }
+
+ internal IMongoCollection Users
+ {
+ get { return _database.GetCollection("users"); }
+ }
+
+ private void CreateAdmin()
+ {
+ var anyUser = Users.Find(l => true).FirstOrDefaultAsync();
+ anyUser.Wait();
+
+ if (anyUser.Result == null)
+ {
+ Users.InsertOneAsync(new User
+ {
+ Name = "admin",
+ Password = "admin",
+ Roles = new[] { "admin", "buildserver", "editor" }
+ });
+ }
+ }
+ }
+
+ public interface IRepository
+ {
+ Task SetUpAsync();
+
+ Task DropDatabaseAsync();
+ }
+}
\ No newline at end of file
diff --git a/BuildRevisionCounter.Core/Properties/AssemblyInfo.cs b/BuildRevisionCounter.Core/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..5118d0a
--- /dev/null
+++ b/BuildRevisionCounter.Core/Properties/AssemblyInfo.cs
@@ -0,0 +1,37 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("BuildRevisionCounter.Core")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("BuildRevisionCounter.Core")]
+[assembly: AssemblyCopyright("Copyright © 2015")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("b1d43c9f-761a-420c-b9a9-c4beaa5f47f8")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: InternalsVisibleTo("BuildRevisionCounter.Tests")]
diff --git a/BuildRevisionCounter.Core/Repositories/IRevisionRepository.cs b/BuildRevisionCounter.Core/Repositories/IRevisionRepository.cs
new file mode 100644
index 0000000..f974a21
--- /dev/null
+++ b/BuildRevisionCounter.Core/Repositories/IRevisionRepository.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace BuildRevisionCounter.Core.Repositories
+{
+ public interface IRevisionRepository
+ {
+ Task GetRevisionByIdAsync(string revisionId);
+
+ Task IncrementRevisionAsync(string revisionId);
+
+ Task AddRevisionAsync(Protocol.Revision revision);
+
+ Task ClearRevisionCollectionAsync();
+
+ Task> GetAllRevisionAsync(Int32 pageSize = 20, Int32 pageNumber = 1);
+ }
+}
diff --git a/BuildRevisionCounter.Core/Repositories/IUserRepository.cs b/BuildRevisionCounter.Core/Repositories/IUserRepository.cs
new file mode 100644
index 0000000..3af44c2
--- /dev/null
+++ b/BuildRevisionCounter.Core/Repositories/IUserRepository.cs
@@ -0,0 +1,13 @@
+using System.Threading.Tasks;
+
+namespace BuildRevisionCounter.Core.Repositories
+{
+ public interface IUserRepository
+ {
+ Task GetUserByNameAsync(string userName);
+
+ Task CreateUserAsync(Protocol.User user);
+
+ Task CountAsync();
+ }
+}
\ No newline at end of file
diff --git a/BuildRevisionCounter.Core/Repositories/Impl/RevisionRepository.cs b/BuildRevisionCounter.Core/Repositories/Impl/RevisionRepository.cs
new file mode 100644
index 0000000..00757b8
--- /dev/null
+++ b/BuildRevisionCounter.Core/Repositories/Impl/RevisionRepository.cs
@@ -0,0 +1,154 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using BuildRevisionCounter.Core.Converters;
+using BuildRevisionCounter.Core.DomainObjects;
+using MongoDB.Driver;
+
+
+namespace BuildRevisionCounter.Core.Repositories.Impl
+{
+ internal class RevisionRepository : IRevisionRepository
+ {
+ private readonly MongoContext _storage;
+ private readonly IRevisionConverter _revisionConverter;
+
+ public RevisionRepository(IRevisionConverter revisionConverter)
+ {
+ _storage = MongoContext.Instance;
+ _revisionConverter = revisionConverter;
+ }
+
+ private void CheckRevisionId(string revisionId)
+ {
+ if (String.IsNullOrEmpty(revisionId)) throw new ArgumentException("revisionId can't be null or empty", "revisionId");
+ }
+
+ #region IRevisionRepository
+
+ public async Task GetRevisionByIdAsync(string revisionId)
+ {
+ var domainRevision = await GetDomainRevisionByIdAsync(revisionId);
+ if (domainRevision == null) return null;
+ return _revisionConverter.ToProtocol(domainRevision);
+ }
+
+ public async Task IncrementRevisionAsync(string revisionId)
+ {
+ var domainRevision = await IncrementDomainRevisionAsync(revisionId);
+
+ return _revisionConverter.ToProtocol(domainRevision);
+ }
+
+ public async Task AddRevisionAsync(Protocol.Revision revision)
+ {
+ var domainRevision = _revisionConverter.ToDomain(revision);
+ await AddDomainRevisionAsync(domainRevision);
+ }
+
+ public async Task ClearRevisionCollectionAsync()
+ {
+ await _storage.Revisions.DeleteManyAsync(l => true);
+ }
+
+ public async Task> GetAllRevisionAsync(Int32 pageSize = 20, Int32 pageNumber = 1)
+ {
+ var domainRevisions = await GetAllDomainRevisionAsync(pageSize, pageNumber);
+
+ if (domainRevisions == null) return null;
+ var protocolRevisions = domainRevisions.Select(l => _revisionConverter.ToProtocol(l)).ToList();
+ return protocolRevisions;
+ }
+
+ #endregion
+
+ internal async Task> GetAllDomainRevisionAsync(Int32 pageSize = 20, Int32 pageNumber = 1)
+ {
+ var revisions = await _storage.Revisions
+ .Find(r => true)
+ .Skip(pageSize * (pageNumber - 1))
+ .Limit(pageSize)
+ .ToListAsync();
+
+ return revisions;
+ }
+
+ internal async Task GetDomainRevisionByIdAsync(string revisionId)
+ {
+ CheckRevisionId(revisionId);
+
+ var revision = await _storage.Revisions
+ .Find(_ => _.Id == revisionId)
+ .SingleOrDefaultAsync();
+
+ return revision;
+ }
+
+ internal async Task IncrementDomainRevisionAsync(string revisionId)
+ {
+ CheckRevisionId(revisionId);
+
+ // попробуем обновить документ
+ var result = await FindOneAndUpdateRevisionAsync(revisionId);
+ if (result != null) return result;
+
+ // если не получилось, значит документ еще не был создан
+ // создадим его с начальным значением 0
+ try
+ {
+ await _storage.Revisions
+ .InsertOneAsync(new Revision
+ {
+ Id = revisionId,
+ CurrentNumber = 0,
+ Created = DateTime.UtcNow
+ });
+
+ result = await GetDomainRevisionByIdAsync(revisionId);
+ return result;
+ }
+ catch (MongoWriteException ex)
+ {
+ if (ex.WriteError.Category != ServerErrorCategory.DuplicateKey)
+ throw;
+ }
+
+ // если при вставке произошла ошибка значит мы не успели и запись там уже есть
+ // и теперь попытка обновления должна пройти без ошибок
+ result = await FindOneAndUpdateRevisionAsync(revisionId);
+
+ return result;
+ }
+
+ ///
+ /// Инкриментит каунтер в БД
+ ///
+ ///
+ ///
+ internal async Task FindOneAndUpdateRevisionAsync(string revisionName)
+ {
+ var result = await _storage.Revisions
+ .FindOneAndUpdateAsync(
+ r => r.Id == revisionName,
+ Builders.Update
+ .Inc(r => r.CurrentNumber, 1)
+ .SetOnInsert(r => r.Created, DateTime.UtcNow)
+ .Set(r => r.Updated, DateTime.UtcNow),
+ new FindOneAndUpdateOptions
+ {
+ IsUpsert = false,
+ ReturnDocument = ReturnDocument.After
+ });
+
+ return result;
+ }
+
+ internal async Task AddDomainRevisionAsync(Revision revision)
+ {
+ await _storage.Revisions.InsertOneAsync(revision);
+ }
+
+
+ }
+}
diff --git a/BuildRevisionCounter.Core/Repositories/Impl/UserRepository.cs b/BuildRevisionCounter.Core/Repositories/Impl/UserRepository.cs
new file mode 100644
index 0000000..22b7da1
--- /dev/null
+++ b/BuildRevisionCounter.Core/Repositories/Impl/UserRepository.cs
@@ -0,0 +1,59 @@
+using System.Threading.Tasks;
+using BuildRevisionCounter.Core.Converters;
+using BuildRevisionCounter.Core.DomainObjects;
+using MongoDB.Driver;
+
+
+namespace BuildRevisionCounter.Core.Repositories.Impl
+{
+ internal class UserRepository : IUserRepository
+ {
+ private readonly MongoContext _storage;
+ private readonly IUserConverter _userConverter;
+
+ public UserRepository(IUserConverter userConverter)
+ {
+ _storage = MongoContext.Instance;
+ _userConverter = userConverter;
+ }
+
+ #region IUserRepository
+
+ public async Task GetUserByNameAsync(string userName)
+ {
+ var domainUser = await GetDomainUserByNameAsync(userName);
+
+ if (domainUser == null) return null;
+ return _userConverter.ToProtocol(domainUser);
+ }
+
+ public async Task CreateUserAsync(Protocol.User user)
+ {
+ var domainUser = _userConverter.ToDomain(user);
+
+ await CreateDomainUserAsync(domainUser);
+ }
+
+ public async Task CountAsync()
+ {
+ return await _storage.Users.CountAsync(_ => true);
+ }
+
+ #endregion
+
+ internal async Task GetDomainUserByNameAsync(string userName)
+ {
+ var user = await _storage.Users
+ .Find(u => u.Name == userName)
+ .FirstOrDefaultAsync();
+
+ return user;
+ }
+
+ internal async Task CreateDomainUserAsync(User domainUser)
+ {
+ await _storage.Users.InsertOneAsync(domainUser);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/BuildRevisionCounter.Core/RepositoryFactory.cs b/BuildRevisionCounter.Core/RepositoryFactory.cs
new file mode 100644
index 0000000..31c39c4
--- /dev/null
+++ b/BuildRevisionCounter.Core/RepositoryFactory.cs
@@ -0,0 +1,47 @@
+using System;
+using BuildRevisionCounter.Core.Converters.Impl;
+using BuildRevisionCounter.Core.Repositories;
+using BuildRevisionCounter.Core.Repositories.Impl;
+
+namespace BuildRevisionCounter.Core
+{
+ public class RepositoryFactory
+ {
+ private static readonly Object SLock = new Object();
+ private static volatile RepositoryFactory _instance = null;
+
+ private RepositoryFactory()
+ { }
+
+ public static RepositoryFactory Instance
+ {
+ get
+ {
+ if (_instance == null)
+ {
+ lock (SLock)
+ {
+ if (_instance == null)
+ _instance = new RepositoryFactory();
+ }
+ }
+ return _instance;
+ }
+ }
+
+ public IRevisionRepository GetRevisionRepository()
+ {
+ return new RevisionRepository(new RevisionConverter());
+ }
+
+ public IUserRepository GetUserRepository()
+ {
+ return new UserRepository(new UserConverter());
+ }
+
+ public IRepository GetRepository()
+ {
+ return MongoContext.Instance;
+ }
+ }
+}
\ No newline at end of file
diff --git a/BuildRevisionCounter.Core/packages.config b/BuildRevisionCounter.Core/packages.config
new file mode 100644
index 0000000..c276a7f
--- /dev/null
+++ b/BuildRevisionCounter.Core/packages.config
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/BuildRevisionCounter.Tests/App.config b/BuildRevisionCounter.Tests/App.config
index 1613985..948da8e 100644
--- a/BuildRevisionCounter.Tests/App.config
+++ b/BuildRevisionCounter.Tests/App.config
@@ -1,7 +1,7 @@
-
+
diff --git a/BuildRevisionCounter.Tests/BuildRevisionCounter.Tests.csproj b/BuildRevisionCounter.Tests/BuildRevisionCounter.Tests.csproj
index 8ce0b45..9be19ea 100644
--- a/BuildRevisionCounter.Tests/BuildRevisionCounter.Tests.csproj
+++ b/BuildRevisionCounter.Tests/BuildRevisionCounter.Tests.csproj
@@ -92,15 +92,22 @@
-
-
+
-
+
+ {667844e5-6d11-474d-a18f-bc4784626f34}
+ BuildRevisionCounter.Protocol
+
+
+ {ddf51396-4ee1-45af-b134-ca1c56b0cd9f}
+ BuildRevisionCounter.Core
+
+
{64eeea30-fce1-4aa6-a375-ebd721914708}
- BuildRevisionCounter
+ BuildRevisionCounter.WebApi
diff --git a/BuildRevisionCounter.Tests/Controllers/CounterControllerTest.cs b/BuildRevisionCounter.Tests/Controllers/CounterControllerTest.cs
index c4bfe67..7682be8 100644
--- a/BuildRevisionCounter.Tests/Controllers/CounterControllerTest.cs
+++ b/BuildRevisionCounter.Tests/Controllers/CounterControllerTest.cs
@@ -2,6 +2,7 @@
using System.Threading.Tasks;
using System.Web.Http;
using BuildRevisionCounter.Controllers;
+using BuildRevisionCounter.Core;
using NUnit.Framework;
namespace BuildRevisionCounter.Tests.Controllers
@@ -10,13 +11,21 @@ namespace BuildRevisionCounter.Tests.Controllers
public class CounterControllerTest
{
private CounterController _controller;
+ private IRepository _repository;
[TestFixtureSetUp]
public void SetUp()
{
- MongoDBStorageUtils.SetUpAsync().Wait();
+ SetUpAsync().Wait();
+ }
+
+ public async Task SetUpAsync()
+ {
+ _repository = RepositoryFactory.Instance.GetRepository();
+ await _repository.DropDatabaseAsync();
+ await _repository.SetUpAsync();
- _controller = new CounterController(MongoDBStorageFactory.DefaultInstance);
+ _controller = new CounterController();
}
[Test]
diff --git a/BuildRevisionCounter.Tests/IntegrationTest/IntegrationTest.cs b/BuildRevisionCounter.Tests/IntegrationTest/IntegrationTest.cs
index 08658a6..e3ba98b 100644
--- a/BuildRevisionCounter.Tests/IntegrationTest/IntegrationTest.cs
+++ b/BuildRevisionCounter.Tests/IntegrationTest/IntegrationTest.cs
@@ -6,6 +6,7 @@
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
+using BuildRevisionCounter.Core;
using Microsoft.Owin.Hosting;
using NUnit.Framework;
@@ -27,7 +28,15 @@ public void Setup()
_uri = string.Format("http://localhost:{0}", port);
_application = WebApp.Start(_uri);
- MongoDBStorageUtils.SetUpAsync().Wait();
+ SetUpAsync().Wait();
+ }
+
+ public async Task SetUpAsync()
+ {
+ await MongoContext.Instance.Client.DropDatabaseAsync(
+ MongoContext.Instance.Database.DatabaseNamespace.DatabaseName);
+
+ await MongoContext.Instance.SetUpAsync();
}
diff --git a/BuildRevisionCounter.Tests/MongoDBStorageTest.cs b/BuildRevisionCounter.Tests/MongoDBStorageTest.cs
index c498db1..e4deb6e 100644
--- a/BuildRevisionCounter.Tests/MongoDBStorageTest.cs
+++ b/BuildRevisionCounter.Tests/MongoDBStorageTest.cs
@@ -1,4 +1,8 @@
using System.Threading.Tasks;
+using BuildRevisionCounter.Core;
+using BuildRevisionCounter.Core.Converters.Impl;
+using BuildRevisionCounter.Core.Repositories.Impl;
+using BuildRevisionCounter.Protocol;
using MongoDB.Driver;
using NUnit.Framework;
@@ -7,73 +11,82 @@ namespace BuildRevisionCounter.Tests
[TestFixture]
public class MongoDBStorageTest
{
- private MongoDBStorage _storage;
+ private UserRepository _userRepository;
[TestFixtureSetUp]
public void SetUp()
{
+ _userRepository = new UserRepository(new UserConverter());
SetUpAsync().Wait();
}
public async Task SetUpAsync()
{
- _storage = MongoDBStorageFactory.DefaultInstance;
+ await MongoContext.Instance.Client.DropDatabaseAsync(
+ MongoContext.Instance.Database.DatabaseNamespace.DatabaseName);
- await _storage.Revisions.Database.Client.DropDatabaseAsync(
- _storage.Revisions.Database.DatabaseNamespace.DatabaseName);
-
- await _storage.SetUp();
+ await MongoContext.Instance.SetUpAsync();
}
[Test]
public async Task EnsureAdminUserCreated()
{
- var user = await _storage.FindUser(MongoDBStorage.AdminName);
- Assert.AreEqual(MongoDBStorage.AdminName, user.Name);
+ var user = await _userRepository.GetUserByNameAsync(MongoContext.AdminName);
+ Assert.AreEqual(MongoContext.AdminName, user.Name);
}
[Test]
public async Task CreateUser()
{
- await _storage.CreateUser("test", "test", new[] {"testRole"});
+ await _userRepository.CreateUserAsync(new User { Name = "test", Password = "test", Roles = new[] { "testRole" } });
}
[Test]
public async Task FindUserReturnsNullIfNoUserFound()
{
- var user = await _storage.FindUser("FindUserReturnsNullIfNoUserFound");
+ var user = await _userRepository.GetUserByNameAsync("FindUserReturnsNullIfNoUserFound");
Assert.IsNull(user);
}
[Test]
public async Task FindUserReturnsCreatedUser()
{
- await _storage.CreateUser("FindUserReturnsCreatedUser", "FindUserReturnsCreatedUser", new[] {"testRole"});
- var user = await _storage.FindUser("FindUserReturnsCreatedUser");
+ await
+ _userRepository.CreateUserAsync(new User
+ {
+ Name = "FindUserReturnsCreatedUser",
+ Password = "FindUserReturnsCreatedUser",
+ Roles = new[] { "testRole" }
+ });
+ var user = await _userRepository.GetUserByNameAsync("FindUserReturnsCreatedUser");
Assert.AreEqual("FindUserReturnsCreatedUser", user.Name);
}
[Test]
public async Task EnsureAdminUserMayBeInvokedMultipleTimes()
{
- await _storage.EnsureAdminUser();
- await _storage.EnsureAdminUser();
+ await MongoContext.Instance.EnsureAdminUser();
+ await MongoContext.Instance.EnsureAdminUser();
}
[Test]
public async Task CreateUserMustThrowExceptionIfUserExists()
{
- await _storage.CreateUser(
- "CreateUserMustThrowExceptionIfUserExists",
- "CreateUserMustThrowExceptionIfUserExists",
- new[] {"testRole"});
+ await _userRepository.CreateUserAsync(new User
+ {
+ Name = "CreateUserMustThrowExceptionIfUserExists",
+ Password = "CreateUserMustThrowExceptionIfUserExists",
+ Roles = new[] { "testRole" }
+ });
try
{
- await _storage.CreateUser(
- "CreateUserMustThrowExceptionIfUserExists",
- "CreateUserMustThrowExceptionIfUserExists",
- new[] {"testRole"});
+ await _userRepository.CreateUserAsync(new User
+ {
+ Name = "CreateUserMustThrowExceptionIfUserExists",
+ Password = "CreateUserMustThrowExceptionIfUserExists",
+ Roles = new[] { "testRole" }
+ });
Assert.Fail();
}
catch (MongoWriteException ex)
diff --git a/BuildRevisionCounter.Tests/Repositories/RevisionRepositoryTest.cs b/BuildRevisionCounter.Tests/Repositories/RevisionRepositoryTest.cs
new file mode 100644
index 0000000..c780008
--- /dev/null
+++ b/BuildRevisionCounter.Tests/Repositories/RevisionRepositoryTest.cs
@@ -0,0 +1,73 @@
+using System.Threading.Tasks;
+using BuildRevisionCounter.Core.Converters.Impl;
+using BuildRevisionCounter.Core.DomainObjects;
+using BuildRevisionCounter.Core.Repositories.Impl;
+using NUnit.Framework;
+
+namespace BuildRevisionCounter.Tests.Repositories
+{
+ [TestFixture]
+ public class RevisionRepositoryTest
+ {
+ private RevisionRepository _repository;
+
+ [TestFixtureSetUp]
+ public void ClassSetUp()
+ {
+ _repository = new RevisionRepository(new RevisionConverter());
+ }
+
+ [SetUp]
+ public void TestSetUp()
+ {
+ _repository.ClearRevisionCollectionAsync().Wait();
+ }
+
+ [Test]
+ public async Task GetDomainRevisionByIdAsync_WhenIdNotExists_ReturnNull()
+ {
+ var revision = await _repository.GetDomainRevisionByIdAsync("unknownRev");
+
+ Assert.IsNull(revision);
+ }
+
+ [Test]
+ public async Task GetDomainRevisionByIdAsync_WhenIdExists_ReturnRevision()
+ {
+ const string expectedRevId = "testRev";
+ var expectedRev = new Revision {Id = expectedRevId};
+ await _repository.AddDomainRevisionAsync(expectedRev);
+
+ var actualRev = await _repository.GetDomainRevisionByIdAsync(expectedRevId);
+ var actualRevId = actualRev.Id;
+
+ Assert.AreEqual(expectedRevId, actualRevId);
+ }
+
+ [Test]
+ public async Task IncrementDomainRevisionAsync_WhenNotExist_CreateWithNumberZero()
+ {
+ const int expectedNextNumber = 0;
+ const string revId = "testRev";
+
+ var newRevision = await _repository.IncrementDomainRevisionAsync(revId);
+ var actualNextNumber = newRevision.CurrentNumber;
+
+ Assert.AreEqual(expectedNextNumber, actualNextNumber);
+ }
+
+ [Test]
+ public async Task IncrementDomainRevisionAsync_WhenExist_IncrementNumber()
+ {
+ const string revId = "testRev";
+ const int expectedNextNumber = 4;
+ var expectedRev = new Revision {Id = revId, CurrentNumber = expectedNextNumber - 1};
+ await _repository.AddDomainRevisionAsync(expectedRev);
+
+ var actualRev = await _repository.IncrementDomainRevisionAsync(revId);
+ var actualNextNumber = actualRev.CurrentNumber;
+
+ Assert.AreEqual(expectedNextNumber, actualNextNumber);
+ }
+ }
+}
diff --git a/BuildRevisionCounter.sln b/BuildRevisionCounter.sln
index e504ccf..298ec45 100644
--- a/BuildRevisionCounter.sln
+++ b/BuildRevisionCounter.sln
@@ -3,10 +3,14 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.31101.0
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildRevisionCounter", "BuildRevisionCounter\BuildRevisionCounter.csproj", "{64EEEA30-FCE1-4AA6-A375-EBD721914708}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildRevisionCounter.WebApi", "BuildRevisionCounter\BuildRevisionCounter.WebApi.csproj", "{64EEEA30-FCE1-4AA6-A375-EBD721914708}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildRevisionCounter.Tests", "BuildRevisionCounter.Tests\BuildRevisionCounter.Tests.csproj", "{837D9E7D-D0CC-4924-85B5-916FC5D931BA}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildRevisionCounter.Protocol", "BuildRevisionCounter.Contract\BuildRevisionCounter.Protocol.csproj", "{667844E5-6D11-474D-A18F-BC4784626F34}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildRevisionCounter.Core", "BuildRevisionCounter.Core\BuildRevisionCounter.Core.csproj", "{DDF51396-4EE1-45AF-B134-CA1C56B0CD9F}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -21,6 +25,14 @@ Global
{837D9E7D-D0CC-4924-85B5-916FC5D931BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{837D9E7D-D0CC-4924-85B5-916FC5D931BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{837D9E7D-D0CC-4924-85B5-916FC5D931BA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {667844E5-6D11-474D-A18F-BC4784626F34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {667844E5-6D11-474D-A18F-BC4784626F34}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {667844E5-6D11-474D-A18F-BC4784626F34}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {667844E5-6D11-474D-A18F-BC4784626F34}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DDF51396-4EE1-45AF-B134-CA1C56B0CD9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DDF51396-4EE1-45AF-B134-CA1C56B0CD9F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DDF51396-4EE1-45AF-B134-CA1C56B0CD9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DDF51396-4EE1-45AF-B134-CA1C56B0CD9F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/BuildRevisionCounter/BuildRevisionCounter.csproj b/BuildRevisionCounter/BuildRevisionCounter.WebApi.csproj
similarity index 92%
rename from BuildRevisionCounter/BuildRevisionCounter.csproj
rename to BuildRevisionCounter/BuildRevisionCounter.WebApi.csproj
index 596f9ab..76352fa 100644
--- a/BuildRevisionCounter/BuildRevisionCounter.csproj
+++ b/BuildRevisionCounter/BuildRevisionCounter.WebApi.csproj
@@ -120,10 +120,6 @@
-
-
-
-
@@ -136,6 +132,19 @@
Designer
+
+
+ {667844e5-6d11-474d-a18f-bc4784626f34}
+ BuildRevisionCounter.Protocol
+
+
+ {ddf51396-4ee1-45af-b134-ca1c56b0cd9f}
+ BuildRevisionCounter.Core
+
+
+
+
+
10.0
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
diff --git a/BuildRevisionCounter/Controllers/CounterController.cs b/BuildRevisionCounter/Controllers/CounterController.cs
index ae9e355..8ed764a 100644
--- a/BuildRevisionCounter/Controllers/CounterController.cs
+++ b/BuildRevisionCounter/Controllers/CounterController.cs
@@ -3,10 +3,9 @@
using System.Net;
using System.Threading.Tasks;
using System.Web.Http;
-using BuildRevisionCounter.Interfaces;
-using BuildRevisionCounter.Model;
+using BuildRevisionCounter.Core;
+using BuildRevisionCounter.Protocol;
using BuildRevisionCounter.Security;
-using MongoDB.Driver;
namespace BuildRevisionCounter.Controllers
{
@@ -14,33 +13,16 @@ namespace BuildRevisionCounter.Controllers
[BasicAuthentication]
public class CounterController : ApiController
{
- private readonly IMongoDBStorage _mongoDbStorage;
-
- ///
- /// Конструктор контроллера номеров ревизий.
- ///
- /// Объект для получения данных из БД Монго.
- public CounterController(IMongoDBStorage mongoDbStorage)
- {
- if (mongoDbStorage == null)
- throw new ArgumentNullException("mongoDbStorage");
-
- _mongoDbStorage = mongoDbStorage;
- }
-
[HttpGet]
[Route("")]
[Authorize(Roles = "admin, editor, anonymous")]
- public async Task> GetAllRevision([FromUri] Int32 pageSize = 20, [FromUri] Int32 pageNumber = 1)
+ public async Task> GetAllRevision([FromUri] Int32 pageSize = 20, [FromUri] Int32 pageNumber = 1)
{
if (pageSize < 1 || pageNumber < 1)
throw new HttpResponseException(HttpStatusCode.BadRequest);
- var revisions = await _mongoDbStorage.Revisions
- .Find(r => true)
- .Skip(pageSize * (pageNumber - 1))
- .Limit(pageSize)
- .ToListAsync();
+ var repository = RepositoryFactory.Instance.GetRevisionRepository();
+ var revisions = await repository.GetAllRevisionAsync(pageSize, pageNumber);
if (revisions == null)
throw new HttpResponseException(HttpStatusCode.NotFound);
@@ -53,9 +35,8 @@ public async Task> GetAllRevision([FromUri] I
[Authorize(Roles = "admin, editor, anonymous")]
public async Task Current([FromUri] string revisionName)
{
- var revision = await _mongoDbStorage.Revisions
- .Find(r => r.Id == revisionName)
- .SingleOrDefaultAsync();
+ var repository = RepositoryFactory.Instance.GetRevisionRepository();
+ var revision = await repository.GetRevisionByIdAsync(revisionName);
if (revision == null)
throw new HttpResponseException(HttpStatusCode.NotFound);
@@ -68,58 +49,13 @@ public async Task Current([FromUri] string revisionName)
[Authorize(Roles = "buildserver")]
public async Task Bumping([FromUri] string revisionName)
{
- // попробуем обновить документ
- var result = await FindOneAndUpdateRevisionModelAsync(revisionName);
- if (result != null)
- return result.CurrentNumber;
-
- // если не получилось, значит документ еще не был создан
- // создадим его с начальным значением 0
- try
- {
- await _mongoDbStorage.Revisions
- .InsertOneAsync(new RevisionModel
- {
- Id = revisionName,
- CurrentNumber = 0,
- Created = DateTime.UtcNow
- });
- return 0;
- }
- catch (MongoWriteException ex)
- {
- if (ex.WriteError.Category != ServerErrorCategory.DuplicateKey)
- throw;
- }
-
- // если при вставке произошла ошибка значит мы не успели и запись там уже есть
- // и теперь попытка обновления должна пройти без ошибок
- result = await FindOneAndUpdateRevisionModelAsync(revisionName);
+ var repository = RepositoryFactory.Instance.GetRevisionRepository();
+ var revision = await repository.IncrementRevisionAsync(revisionName);
- return result.CurrentNumber;
- }
-
- ///
- /// Инкриментит каунтер в БД
- ///
- ///
- ///
- private async Task FindOneAndUpdateRevisionModelAsync(string revisionName)
- {
- var result = await _mongoDbStorage.Revisions
- .FindOneAndUpdateAsync(
- r => r.Id == revisionName,
- Builders.Update
- .Inc(r => r.CurrentNumber, 1)
- .SetOnInsert(r => r.Created, DateTime.UtcNow)
- .Set(r => r.Updated, DateTime.UtcNow),
- new FindOneAndUpdateOptions
- {
- IsUpsert = false,
- ReturnDocument = ReturnDocument.After
- });
+ if (revision == null)
+ throw new HttpResponseException(HttpStatusCode.NotFound);
- return result;
+ return revision.CurrentNumber;
}
}
}
\ No newline at end of file
diff --git a/BuildRevisionCounter/Interfaces/IMongoDBStorage.cs b/BuildRevisionCounter/Interfaces/IMongoDBStorage.cs
deleted file mode 100644
index c75dc23..0000000
--- a/BuildRevisionCounter/Interfaces/IMongoDBStorage.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using BuildRevisionCounter.Model;
-using MongoDB.Driver;
-
-namespace BuildRevisionCounter.Interfaces
-{
- ///
- /// Интерфейс для получения данных из БД Монго.
- ///
- public interface IMongoDBStorage
- {
- ///
- /// MongoDB-коллекция ревизий.
- ///
- IMongoCollection Revisions { get; }
-
- ///
- /// MongoDB-коллекция пользователей.
- ///
- IMongoCollection Users { get; }
- }
-}
\ No newline at end of file
diff --git a/BuildRevisionCounter/Model/RevisionModel.cs b/BuildRevisionCounter/Model/RevisionModel.cs
deleted file mode 100644
index 96adbbd..0000000
--- a/BuildRevisionCounter/Model/RevisionModel.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using MongoDB.Bson.Serialization.Attributes;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Web;
-
-namespace BuildRevisionCounter.Model
-{
- public class RevisionModel
- {
- [BsonId]
- public string Id;
-
- [BsonElement("created"), BsonDateTimeOptions(Kind=DateTimeKind.Utc)]
- public DateTime Created;
-
- [BsonElement("updated"), BsonDateTimeOptions(Kind = DateTimeKind.Utc)]
- public DateTime Updated;
-
- [BsonElement("currentNumber")]
- public long CurrentNumber;
-
- }
-}
\ No newline at end of file
diff --git a/BuildRevisionCounter/MongoDBStorage.cs b/BuildRevisionCounter/MongoDBStorage.cs
deleted file mode 100644
index f5d9c84..0000000
--- a/BuildRevisionCounter/MongoDBStorage.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-using System.Threading.Tasks;
-using BuildRevisionCounter.Interfaces;
-using BuildRevisionCounter.Model;
-using MongoDB.Driver;
-
-namespace BuildRevisionCounter
-{
- public class MongoDBStorage : IMongoDBStorage
- {
- public static readonly string AdminName = "admin";
- public static readonly string AdminPassword = "admin";
- public static readonly string[] AdminRoles = {"admin", "buildserver", "editor"};
-
- public IMongoCollection Revisions { get; private set; }
- public IMongoCollection Users { get; private set; }
-
- public MongoDBStorage(IMongoDatabase database)
- {
- Revisions = database.GetCollection("revisions");
- Users = database.GetCollection("users");
-
- Task.Run(() => SetUp()).Wait();
- }
-
- public async Task SetUp()
- {
- await EnsureUsersIndex();
- await EnsureAdminUser();
- }
-
- public async Task EnsureUsersIndex()
- {
- await Users.Indexes.CreateOneAsync(
- Builders.IndexKeys.Ascending(u => u.Name),
- new CreateIndexOptions { Unique = true, });
- }
-
- public async Task EnsureAdminUser()
- {
- if (await Users.CountAsync(_ => true) == 0)
- {
- await CreateUser(AdminName, AdminPassword, AdminRoles);
- }
- }
-
- public async Task FindUser(string name)
- {
- return await Users.Find(u => u.Name == name).SingleOrDefaultAsync();
- }
-
- public Task CreateUser(string name, string password, string[] roles)
- {
- return Users
- .InsertOneAsync(
- new UserModel
- {
- Name = name,
- Password = password,
- Roles = roles
- });
- }
- }
-}
\ No newline at end of file
diff --git a/BuildRevisionCounter/Properties/PublishProfiles/ToFileSystem.pubxml b/BuildRevisionCounter/Properties/PublishProfiles/ToFileSystem.pubxml
index e872f41..d1195c2 100644
--- a/BuildRevisionCounter/Properties/PublishProfiles/ToFileSystem.pubxml
+++ b/BuildRevisionCounter/Properties/PublishProfiles/ToFileSystem.pubxml
@@ -5,13 +5,13 @@ by editing this MSBuild file. In order to learn more about this please visit htt
-->
- FileSystem
- Release
- Any CPU
-
- True
- True
- $(MSBuildThisFileDirectory)..\..\..\publish
- True
+FileSystem
+Release
+Any CPU
+
+True
+True
+$(MSBuildThisFileDirectory)..\..\..\publish
+True
\ No newline at end of file
diff --git a/BuildRevisionCounter/Security/BasicAuthenticationFilter.cs b/BuildRevisionCounter/Security/BasicAuthenticationFilter.cs
index e8a5228..0b4e977 100644
--- a/BuildRevisionCounter/Security/BasicAuthenticationFilter.cs
+++ b/BuildRevisionCounter/Security/BasicAuthenticationFilter.cs
@@ -6,9 +6,7 @@
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Filters;
-using BuildRevisionCounter.Interfaces;
-using BuildRevisionCounter.Model;
-using MongoDB.Driver;
+using BuildRevisionCounter.Core;
namespace BuildRevisionCounter.Security
{
@@ -28,21 +26,7 @@ public class BasicAuthenticationFilter : IAuthenticationFilter
Encoding.ASCII.CodePage,
EncoderFallback.ExceptionFallback,
DecoderFallback.ExceptionFallback);
-
- private readonly IMongoDBStorage _mongoDbStorage;
-
- ///
- /// Конструктор фильтра.
- ///
- /// Объект для получения данных из БД Монго.
- public BasicAuthenticationFilter(IMongoDBStorage mongoDbStorage)
- {
- if (mongoDbStorage == null)
- throw new ArgumentNullException("mongoDbStorage");
-
- _mongoDbStorage = mongoDbStorage;
- }
-
+
public string Realm { get; set; }
#region IAuthenticationFilter Members
@@ -88,11 +72,10 @@ public Task ChallengeAsync(HttpAuthenticationChallengeContext context, Cancellat
private async Task Authenticate(string userName, string password)
{
+ var repository = RepositoryFactory.Instance.GetUserRepository();
+
IPrincipal principal = null;
- var user =
- await
- _mongoDbStorage.Users.Find(Builders.Filter.Where(u => u.Name == userName))
- .SingleOrDefaultAsync();
+ var user = await repository.GetUserByNameAsync(userName);
if (user != null && user.Password == password)
{
principal = new GenericPrincipal(new GenericIdentity(userName), user.Roles);
diff --git a/BuildRevisionCounter/Startup.cs b/BuildRevisionCounter/Startup.cs
index fc77cfa..2240f31 100644
--- a/BuildRevisionCounter/Startup.cs
+++ b/BuildRevisionCounter/Startup.cs
@@ -1,8 +1,6 @@
-using System.Configuration;
-using System.Web.Http.Filters;
+using System.Web.Http.Filters;
using BuildRevisionCounter.Security;
using Microsoft.Owin;
-using MongoDB.Driver;
using Ninject;
using Ninject.Web.Common.OwinHost;
using Ninject.Web.WebApi.FilterBindingSyntax;
@@ -11,7 +9,6 @@
using BuildRevisionCounter;
using System.Web.Http;
using System.Net.Http.Formatting;
-using BuildRevisionCounter.Interfaces;
[assembly: OwinStartup(typeof(Startup))]
@@ -58,16 +55,7 @@ private static IKernel CreateKernel()
/// Ядро Ninject.
private static void RegisterServices(IKernel kernel)
{
- kernel.Bind().ToMethod(c => GetMongoDbStorage()).InSingletonScope();
kernel.BindHttpFilter(FilterScope.Controller).WhenControllerHas();
}
-
- private static MongoDBStorage GetMongoDbStorage(string connectionStringName = "MongoDBStorage")
- {
- var connectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;
- var mongoUrl = MongoUrl.Create(connectionString);
- var database = new MongoClient(mongoUrl).GetDatabase(mongoUrl.DatabaseName);
- return new MongoDBStorage(database);
- }
}
}
diff --git a/BuildRevisionCounter/Web.config b/BuildRevisionCounter/Web.config
index 210bf89..f6375ed 100644
--- a/BuildRevisionCounter/Web.config
+++ b/BuildRevisionCounter/Web.config
@@ -1,26 +1,26 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file