diff --git a/src/Api/Startup.cs b/src/Api/Startup.cs index 08f8ff988e..7f77bcaeb4 100644 --- a/src/Api/Startup.cs +++ b/src/Api/Startup.cs @@ -58,7 +58,7 @@ namespace Bit.Api StripeConfiguration.SetApiKey(globalSettings.StripeApiKey); // Repositories - services.AddSqlServerRepositories(); + services.AddSqlServerRepositories(globalSettings); // Context services.AddScoped(); diff --git a/src/Billing/Startup.cs b/src/Billing/Startup.cs index 5f34658fac..36a3e8b164 100644 --- a/src/Billing/Startup.cs +++ b/src/Billing/Startup.cs @@ -36,7 +36,7 @@ namespace Bit.Billing StripeConfiguration.SetApiKey(globalSettings.StripeApiKey); // Repositories - services.AddSqlServerRepositories(); + services.AddSqlServerRepositories(globalSettings); // Context services.AddScoped(); diff --git a/src/Core/Models/Data/CipherEvent.cs b/src/Core/Models/Data/CipherEvent.cs new file mode 100644 index 0000000000..5726127a83 --- /dev/null +++ b/src/Core/Models/Data/CipherEvent.cs @@ -0,0 +1,29 @@ +using Bit.Core.Enums; +using Bit.Core.Models.Table; +using Bit.Core.Utilities; + +namespace Bit.Core.Models.Data +{ + public class CipherEvent : EventTableEntity + { + public CipherEvent(Cipher cipher, EventType type) + { + if(cipher.OrganizationId.HasValue) + { + PartitionKey = $"OrganizationId={cipher.OrganizationId.Value}"; + } + else + { + PartitionKey = $"UserId={cipher.UserId.Value}"; + } + + RowKey = string.Format("Date={0}__CipherId={1}__Type={2}", + CoreHelpers.DateTimeToTableStorageKey(), cipher.Id, type); + + OrganizationId = cipher.OrganizationId; + UserId = cipher.UserId; + CipherId = cipher.Id; + Type = type; + } + } +} diff --git a/src/Core/Models/Data/EventTableEntity.cs b/src/Core/Models/Data/EventTableEntity.cs new file mode 100644 index 0000000000..398b16bd2a --- /dev/null +++ b/src/Core/Models/Data/EventTableEntity.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using Bit.Core.Enums; +using Microsoft.WindowsAzure.Storage.Table; + +namespace Bit.Core.Models.Data +{ + public class EventTableEntity : TableEntity + { + public EventType Type { get; set; } + public Guid? UserId { get; set; } + public Guid? OrganizationId { get; set; } + public Guid? CipherId { get; set; } + public ICollection CipherIds { get; set; } + } +} diff --git a/src/Core/Models/Data/OrganizationEvent.cs b/src/Core/Models/Data/OrganizationEvent.cs new file mode 100644 index 0000000000..05efcf7aef --- /dev/null +++ b/src/Core/Models/Data/OrganizationEvent.cs @@ -0,0 +1,30 @@ +using System; +using Bit.Core.Enums; +using Bit.Core.Utilities; + +namespace Bit.Core.Models.Data +{ + public class OrganizationEvent : EventTableEntity + { + public OrganizationEvent(Guid organizationId, EventType type) + { + PartitionKey = $"OrganizationId={organizationId}"; + RowKey = string.Format("Date={0}__Type={1}", + CoreHelpers.DateTimeToTableStorageKey(), type); + + OrganizationId = organizationId; + Type = type; + } + + public OrganizationEvent(Guid organizationId, Guid userId, EventType type) + { + PartitionKey = $"OrganizationId={organizationId}"; + RowKey = string.Format("Date={0}__UserId={1}__Type={2}", + CoreHelpers.DateTimeToTableStorageKey(), userId, type); + + OrganizationId = organizationId; + UserId = userId; + Type = type; + } + } +} diff --git a/src/Core/Models/Data/UserEvent.cs b/src/Core/Models/Data/UserEvent.cs new file mode 100644 index 0000000000..1ced8bf2b4 --- /dev/null +++ b/src/Core/Models/Data/UserEvent.cs @@ -0,0 +1,30 @@ +using System; +using Bit.Core.Enums; +using Bit.Core.Utilities; + +namespace Bit.Core.Models.Data +{ + public class UserEvent : EventTableEntity + { + public UserEvent(Guid userId, EventType type) + { + PartitionKey = $"UserId={userId}"; + RowKey = string.Format("Date={0}__Type={1}", + CoreHelpers.DateTimeToTableStorageKey(), type); + + UserId = userId; + Type = type; + } + + public UserEvent(Guid userId, Guid organizationId, EventType type) + { + PartitionKey = $"OrganizationId={organizationId}"; + RowKey = string.Format("Date={0}__UserId={1}__Type={2}", + CoreHelpers.DateTimeToTableStorageKey(), userId, type); + + OrganizationId = organizationId; + UserId = userId; + Type = type; + } + } +} diff --git a/src/Core/Repositories/IEventRepository.cs b/src/Core/Repositories/IEventRepository.cs new file mode 100644 index 0000000000..e9ae09a970 --- /dev/null +++ b/src/Core/Repositories/IEventRepository.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Bit.Core.Models.Data; +using Microsoft.WindowsAzure.Storage.Table; + +namespace Bit.Core.Repositories +{ + public interface IEventRepository + { + Task> GetManyByUserAsync(Guid userId, DateTime startDate, DateTime endDate); + Task CreateAsync(ITableEntity entity); + Task CreateManyAsync(IEnumerable entities); + } +} diff --git a/src/Core/Repositories/TableStorage/EventRepository.cs b/src/Core/Repositories/TableStorage/EventRepository.cs index 14bf74ba37..81fd0b0420 100644 --- a/src/Core/Repositories/TableStorage/EventRepository.cs +++ b/src/Core/Repositories/TableStorage/EventRepository.cs @@ -2,15 +2,14 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Bit.Core.Enums; -using Bit.Core.Models.Table; +using Bit.Core.Models.Data; using Bit.Core.Utilities; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Table; namespace Bit.Core.Repositories.TableStorage { - public class EventRepository + public class EventRepository : IEventRepository { public EventRepository(GlobalSettings globalSettings) { @@ -21,7 +20,7 @@ namespace Bit.Core.Repositories.TableStorage protected CloudTable Table { get; set; } - public async Task> GetManyByUserAsync(Guid userId, + public async Task> GetManyByUserAsync(Guid userId, DateTime startDate, DateTime endDate) { var start = CoreHelpers.DateTimeToTableStorageKey(startDate); @@ -37,8 +36,8 @@ namespace Bit.Core.Repositories.TableStorage TableOperators.And, rowFilter); - var query = new TableQuery().Where(filter); - var results = new List(); + var query = new TableQuery().Where(filter); + var results = new List(); TableContinuationToken continuationToken = null; do { @@ -82,84 +81,4 @@ namespace Bit.Core.Repositories.TableStorage } } } - - public class UserEvent : EventTableEntiity - { - public UserEvent(Guid userId, EventType type) - { - PartitionKey = $"UserId={userId}"; - RowKey = string.Format("Date={0}__Type={1}", - CoreHelpers.DateTimeToTableStorageKey(), type); - - UserId = userId; - Type = type; - } - - public UserEvent(Guid userId, Guid organizationId, EventType type) - { - PartitionKey = $"OrganizationId={organizationId}"; - RowKey = string.Format("Date={0}__UserId={1}__Type={2}", - CoreHelpers.DateTimeToTableStorageKey(), userId, type); - - OrganizationId = organizationId; - UserId = userId; - Type = type; - } - } - - public class CipherEvent : EventTableEntiity - { - public CipherEvent(Cipher cipher, EventType type) - { - if(cipher.OrganizationId.HasValue) - { - PartitionKey = $"OrganizationId={cipher.OrganizationId.Value}"; - } - else - { - PartitionKey = $"UserId={cipher.UserId.Value}"; - } - - RowKey = string.Format("Date={0}__CipherId={1}__Type={2}", - CoreHelpers.DateTimeToTableStorageKey(), cipher.Id, type); - - OrganizationId = cipher.OrganizationId; - UserId = cipher.UserId; - CipherId = cipher.Id; - Type = type; - } - } - - public class OrganizationEvent : EventTableEntiity - { - public OrganizationEvent(Guid organizationId, EventType type) - { - PartitionKey = $"OrganizationId={organizationId}"; - RowKey = string.Format("Date={0}__Type={1}", - CoreHelpers.DateTimeToTableStorageKey(), type); - - OrganizationId = organizationId; - Type = type; - } - - public OrganizationEvent(Guid organizationId, Guid userId, EventType type) - { - PartitionKey = $"OrganizationId={organizationId}"; - RowKey = string.Format("Date={0}__UserId={1}__Type={2}", - CoreHelpers.DateTimeToTableStorageKey(), userId, type); - - OrganizationId = organizationId; - UserId = userId; - Type = type; - } - } - - public class EventTableEntiity : TableEntity - { - public EventType Type { get; set; } - public Guid? UserId { get; set; } - public Guid? OrganizationId { get; set; } - public Guid? CipherId { get; set; } - public ICollection CipherIds { get; set; } - } } diff --git a/src/Core/Services/IEventService.cs b/src/Core/Services/IEventService.cs new file mode 100644 index 0000000000..6a5e6a97df --- /dev/null +++ b/src/Core/Services/IEventService.cs @@ -0,0 +1,11 @@ +using System; +using System.Threading.Tasks; +using Bit.Core.Enums; + +namespace Bit.Core.Services +{ + public interface IEventService + { + Task LogUserEventAsync(Guid userId, EventType type); + } +} diff --git a/src/Core/Services/Implementations/EventService.cs b/src/Core/Services/Implementations/EventService.cs new file mode 100644 index 0000000000..eb1637f3d3 --- /dev/null +++ b/src/Core/Services/Implementations/EventService.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; +using System; +using Bit.Core.Enums; +using Bit.Core.Repositories; +using Bit.Core.Models.Data; + +namespace Bit.Core.Services +{ + public class EventService : IEventService + { + private readonly IEventRepository _eventRepository; + private readonly GlobalSettings _globalSettings; + + public EventService( + IEventRepository eventRepository, + GlobalSettings globalSettings) + { + _eventRepository = eventRepository; + _globalSettings = globalSettings; + } + + public async Task LogUserEventAsync(Guid userId, EventType type) + { + var userEvent = new UserEvent(userId, type); + await _eventRepository.CreateAsync(userEvent); + } + } +} diff --git a/src/Core/Services/NoopImplementations/NoopEventService.cs b/src/Core/Services/NoopImplementations/NoopEventService.cs new file mode 100644 index 0000000000..729f3e1af9 --- /dev/null +++ b/src/Core/Services/NoopImplementations/NoopEventService.cs @@ -0,0 +1,14 @@ +using System; +using System.Threading.Tasks; +using Bit.Core.Enums; + +namespace Bit.Core.Services +{ + public class NoopEventService : IEventService + { + public Task LogUserEventAsync(Guid userId, EventType type) + { + return Task.FromResult(0); + } + } +} diff --git a/src/Core/Utilities/ServiceCollectionExtensions.cs b/src/Core/Utilities/ServiceCollectionExtensions.cs index fbb184c9f1..e9cd87faab 100644 --- a/src/Core/Utilities/ServiceCollectionExtensions.cs +++ b/src/Core/Utilities/ServiceCollectionExtensions.cs @@ -20,13 +20,14 @@ using Microsoft.WindowsAzure.Storage; using System; using System.IO; using SqlServerRepos = Bit.Core.Repositories.SqlServer; +using TableStorageRepos = Bit.Core.Repositories.TableStorage; using System.Threading.Tasks; namespace Bit.Core.Utilities { public static class ServiceCollectionExtensions { - public static void AddSqlServerRepositories(this IServiceCollection services) + public static void AddSqlServerRepositories(this IServiceCollection services, GlobalSettings globalSettings) { services.AddSingleton(); services.AddSingleton(); @@ -40,6 +41,15 @@ namespace Bit.Core.Utilities services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + + if(globalSettings.SelfHosted) + { + // TODO: Sql server repo + } + else + { + services.AddSingleton(); + } } public static void AddBaseServices(this IServiceCollection services) @@ -50,6 +60,7 @@ namespace Bit.Core.Utilities services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); } public static void AddDefaultServices(this IServiceCollection services, GlobalSettings globalSettings) diff --git a/src/Identity/Startup.cs b/src/Identity/Startup.cs index 054ee21781..e74e0df05a 100644 --- a/src/Identity/Startup.cs +++ b/src/Identity/Startup.cs @@ -39,7 +39,7 @@ namespace Bit.Identity services.AddCustomDataProtectionServices(Environment, globalSettings); // Repositories - services.AddSqlServerRepositories(); + services.AddSqlServerRepositories(globalSettings); // Context services.AddScoped(); diff --git a/src/Jobs/Startup.cs b/src/Jobs/Startup.cs index 2f10f9a3bc..6d5fcd5908 100644 --- a/src/Jobs/Startup.cs +++ b/src/Jobs/Startup.cs @@ -45,7 +45,7 @@ namespace Bit.Jobs services.AddCustomDataProtectionServices(Environment, globalSettings); // Repositories - services.AddSqlServerRepositories(); + services.AddSqlServerRepositories(globalSettings); // Context services.AddScoped();