mirror of
https://github.com/bitwarden/server.git
synced 2025-01-10 20:07:56 +01:00
event sql table and repo
This commit is contained in:
parent
7b359053d6
commit
ce1680a009
@ -3,7 +3,7 @@ using Bit.Core.Enums;
|
|||||||
|
|
||||||
namespace Bit.Core.Models.Data
|
namespace Bit.Core.Models.Data
|
||||||
{
|
{
|
||||||
public class Event : IEvent
|
public class EventMessage : IEvent
|
||||||
{
|
{
|
||||||
public DateTime Date { get; set; }
|
public DateTime Date { get; set; }
|
||||||
public EventType Type { get; set; }
|
public EventType Type { get; set; }
|
@ -5,7 +5,6 @@ namespace Bit.Core.Models.Data
|
|||||||
{
|
{
|
||||||
public interface IEvent
|
public interface IEvent
|
||||||
{
|
{
|
||||||
DateTime Date { get; set; }
|
|
||||||
EventType Type { get; set; }
|
EventType Type { get; set; }
|
||||||
Guid? UserId { get; set; }
|
Guid? UserId { get; set; }
|
||||||
Guid? OrganizationId { get; set; }
|
Guid? OrganizationId { get; set; }
|
||||||
@ -14,5 +13,6 @@ namespace Bit.Core.Models.Data
|
|||||||
Guid? GroupId { get; set; }
|
Guid? GroupId { get; set; }
|
||||||
Guid? OrganizationUserId { get; set; }
|
Guid? OrganizationUserId { get; set; }
|
||||||
Guid? ActingUserId { get; set; }
|
Guid? ActingUserId { get; set; }
|
||||||
|
DateTime Date { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
41
src/Core/Models/Table/Event.cs
Normal file
41
src/Core/Models/Table/Event.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using Bit.Core.Enums;
|
||||||
|
using Bit.Core.Models.Data;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Table
|
||||||
|
{
|
||||||
|
public class Event : ITableObject<Guid>, IEvent
|
||||||
|
{
|
||||||
|
public Event() { }
|
||||||
|
|
||||||
|
public Event(IEvent e)
|
||||||
|
{
|
||||||
|
Date = e.Date;
|
||||||
|
Type = e.Type;
|
||||||
|
UserId = e.UserId;
|
||||||
|
OrganizationId = e.OrganizationId;
|
||||||
|
CipherId = e.CipherId;
|
||||||
|
CollectionId = e.CollectionId;
|
||||||
|
GroupId = e.GroupId;
|
||||||
|
OrganizationUserId = e.OrganizationUserId;
|
||||||
|
ActingUserId = e.ActingUserId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public DateTime Date { get; set; }
|
||||||
|
public EventType Type { get; set; }
|
||||||
|
public Guid? UserId { get; set; }
|
||||||
|
public Guid? OrganizationId { get; set; }
|
||||||
|
public Guid? CipherId { get; set; }
|
||||||
|
public Guid? CollectionId { get; set; }
|
||||||
|
public Guid? GroupId { get; set; }
|
||||||
|
public Guid? OrganizationUserId { get; set; }
|
||||||
|
public Guid? ActingUserId { get; set; }
|
||||||
|
|
||||||
|
public void SetNewId()
|
||||||
|
{
|
||||||
|
Id = CoreHelpers.GenerateComb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,7 @@ namespace Bit.Core.Repositories
|
|||||||
public interface IEventRepository
|
public interface IEventRepository
|
||||||
{
|
{
|
||||||
Task<ICollection<IEvent>> GetManyByUserAsync(Guid userId, DateTime startDate, DateTime endDate);
|
Task<ICollection<IEvent>> GetManyByUserAsync(Guid userId, DateTime startDate, DateTime endDate);
|
||||||
Task CreateAsync(IEvent entity);
|
Task CreateAsync(IEvent e);
|
||||||
Task CreateManyAsync(IList<IEvent> entities);
|
Task CreateManyAsync(IList<IEvent> e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -392,8 +392,7 @@ namespace Bit.Core.Repositories.SqlServer
|
|||||||
{
|
{
|
||||||
if(folders.Any())
|
if(folders.Any())
|
||||||
{
|
{
|
||||||
using(var bulkCopy = new SqlBulkCopy(connection,
|
using(var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, transaction))
|
||||||
SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.FireTriggers, transaction))
|
|
||||||
{
|
{
|
||||||
bulkCopy.DestinationTableName = "[dbo].[Folder]";
|
bulkCopy.DestinationTableName = "[dbo].[Folder]";
|
||||||
var dataTable = BuildFoldersTable(folders);
|
var dataTable = BuildFoldersTable(folders);
|
||||||
@ -401,8 +400,7 @@ namespace Bit.Core.Repositories.SqlServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
using(var bulkCopy = new SqlBulkCopy(connection,
|
using(var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, transaction))
|
||||||
SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.FireTriggers, transaction))
|
|
||||||
{
|
{
|
||||||
bulkCopy.DestinationTableName = "[dbo].[Cipher]";
|
bulkCopy.DestinationTableName = "[dbo].[Cipher]";
|
||||||
var dataTable = BuildCiphersTable(ciphers);
|
var dataTable = BuildCiphersTable(ciphers);
|
||||||
|
115
src/Core/Repositories/SqlServer/EventRepository.cs
Normal file
115
src/Core/Repositories/SqlServer/EventRepository.cs
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
using System;
|
||||||
|
using Bit.Core.Models.Table;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Bit.Core.Models.Data;
|
||||||
|
using System.Data.SqlClient;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Data;
|
||||||
|
|
||||||
|
namespace Bit.Core.Repositories.SqlServer
|
||||||
|
{
|
||||||
|
public class EventRepository : Repository<Event, Guid>, IEventRepository
|
||||||
|
{
|
||||||
|
public EventRepository(GlobalSettings globalSettings)
|
||||||
|
: this(globalSettings.SqlServer.ConnectionString)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public EventRepository(string connectionString)
|
||||||
|
: base(connectionString)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public Task<ICollection<IEvent>> GetManyByUserAsync(Guid userId, DateTime startDate, DateTime endDate)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CreateAsync(IEvent e)
|
||||||
|
{
|
||||||
|
if(!(e is Event ev))
|
||||||
|
{
|
||||||
|
ev = new Event(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
await base.CreateAsync(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CreateManyAsync(IList<IEvent> entities)
|
||||||
|
{
|
||||||
|
if(!entities.Any())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using(var connection = new SqlConnection(ConnectionString))
|
||||||
|
{
|
||||||
|
connection.Open();
|
||||||
|
using(var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, null))
|
||||||
|
{
|
||||||
|
bulkCopy.DestinationTableName = "[dbo].[Event]";
|
||||||
|
var dataTable = BuildEventsTable(entities.Select(e => e is Event ? e as Event : new Event(e)));
|
||||||
|
await bulkCopy.WriteToServerAsync(dataTable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataTable BuildEventsTable(IEnumerable<Event> events)
|
||||||
|
{
|
||||||
|
var e = events.FirstOrDefault();
|
||||||
|
if(e == null)
|
||||||
|
{
|
||||||
|
throw new ApplicationException("Must have some events to bulk import.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var eventsTable = new DataTable("EventDataTable");
|
||||||
|
|
||||||
|
var idColumn = new DataColumn(nameof(e.Id), e.Id.GetType());
|
||||||
|
eventsTable.Columns.Add(idColumn);
|
||||||
|
var typeColumn = new DataColumn(nameof(e.Type), typeof(int));
|
||||||
|
eventsTable.Columns.Add(typeColumn);
|
||||||
|
var dateColumn = new DataColumn(nameof(e.Date), e.Date.GetType());
|
||||||
|
eventsTable.Columns.Add(dateColumn);
|
||||||
|
var userIdColumn = new DataColumn(nameof(e.UserId), typeof(Guid));
|
||||||
|
eventsTable.Columns.Add(userIdColumn);
|
||||||
|
var organizationIdColumn = new DataColumn(nameof(e.OrganizationId), typeof(Guid));
|
||||||
|
eventsTable.Columns.Add(organizationIdColumn);
|
||||||
|
var cipherIdColumn = new DataColumn(nameof(e.CipherId), typeof(Guid));
|
||||||
|
eventsTable.Columns.Add(cipherIdColumn);
|
||||||
|
var groupIdColumn = new DataColumn(nameof(e.GroupId), typeof(Guid));
|
||||||
|
eventsTable.Columns.Add(groupIdColumn);
|
||||||
|
var collectionIdColumn = new DataColumn(nameof(e.CollectionId), typeof(Guid));
|
||||||
|
eventsTable.Columns.Add(collectionIdColumn);
|
||||||
|
var actingUserIdColumn = new DataColumn(nameof(e.ActingUserId), typeof(Guid));
|
||||||
|
eventsTable.Columns.Add(actingUserIdColumn);
|
||||||
|
var organizationUserIdColumn = new DataColumn(nameof(e.OrganizationUserId), typeof(Guid));
|
||||||
|
eventsTable.Columns.Add(organizationUserIdColumn);
|
||||||
|
|
||||||
|
var keys = new DataColumn[1];
|
||||||
|
keys[0] = idColumn;
|
||||||
|
eventsTable.PrimaryKey = keys;
|
||||||
|
|
||||||
|
foreach(var ev in events)
|
||||||
|
{
|
||||||
|
ev.SetNewId();
|
||||||
|
|
||||||
|
var row = eventsTable.NewRow();
|
||||||
|
|
||||||
|
row[idColumn] = ev.Id;
|
||||||
|
row[typeColumn] = ev.Type;
|
||||||
|
row[dateColumn] = ev.Date;
|
||||||
|
row[userIdColumn] = ev.UserId;
|
||||||
|
row[organizationIdColumn] = ev.OrganizationId;
|
||||||
|
row[cipherIdColumn] = ev.CipherId;
|
||||||
|
row[groupIdColumn] = ev.GroupId;
|
||||||
|
row[collectionIdColumn] = ev.CollectionId;
|
||||||
|
row[actingUserIdColumn] = ev.ActingUserId;
|
||||||
|
row[organizationUserIdColumn] = ev.OrganizationUserId;
|
||||||
|
|
||||||
|
eventsTable.Rows.Add(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
return eventsTable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -33,7 +33,7 @@ namespace Bit.Core.Services
|
|||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
var events = new List<IEvent>
|
var events = new List<IEvent>
|
||||||
{
|
{
|
||||||
new Event
|
new EventMessage
|
||||||
{
|
{
|
||||||
UserId = userId,
|
UserId = userId,
|
||||||
Type = type,
|
Type = type,
|
||||||
@ -44,7 +44,7 @@ namespace Bit.Core.Services
|
|||||||
IEnumerable<IEvent> orgEvents;
|
IEnumerable<IEvent> orgEvents;
|
||||||
if(_currentContext.UserId.HasValue)
|
if(_currentContext.UserId.HasValue)
|
||||||
{
|
{
|
||||||
orgEvents = _currentContext.Organizations.Select(o => new Event
|
orgEvents = _currentContext.Organizations.Select(o => new EventMessage
|
||||||
{
|
{
|
||||||
OrganizationId = o.Id,
|
OrganizationId = o.Id,
|
||||||
UserId = userId,
|
UserId = userId,
|
||||||
@ -56,7 +56,7 @@ namespace Bit.Core.Services
|
|||||||
{
|
{
|
||||||
var orgs = await _organizationUserRepository.GetManyByUserAsync(userId);
|
var orgs = await _organizationUserRepository.GetManyByUserAsync(userId);
|
||||||
orgEvents = orgs.Where(o => o.Status == OrganizationUserStatusType.Confirmed)
|
orgEvents = orgs.Where(o => o.Status == OrganizationUserStatusType.Confirmed)
|
||||||
.Select(o => new Event
|
.Select(o => new EventMessage
|
||||||
{
|
{
|
||||||
OrganizationId = o.Id,
|
OrganizationId = o.Id,
|
||||||
UserId = userId,
|
UserId = userId,
|
||||||
@ -83,7 +83,7 @@ namespace Bit.Core.Services
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var e = new Event
|
var e = new EventMessage
|
||||||
{
|
{
|
||||||
OrganizationId = cipher.OrganizationId,
|
OrganizationId = cipher.OrganizationId,
|
||||||
UserId = cipher.OrganizationId.HasValue ? null : cipher.UserId,
|
UserId = cipher.OrganizationId.HasValue ? null : cipher.UserId,
|
||||||
@ -97,7 +97,7 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
public async Task LogCollectionEventAsync(Collection collection, EventType type)
|
public async Task LogCollectionEventAsync(Collection collection, EventType type)
|
||||||
{
|
{
|
||||||
var e = new Event
|
var e = new EventMessage
|
||||||
{
|
{
|
||||||
OrganizationId = collection.OrganizationId,
|
OrganizationId = collection.OrganizationId,
|
||||||
CollectionId = collection.Id,
|
CollectionId = collection.Id,
|
||||||
@ -110,7 +110,7 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
public async Task LogGroupEventAsync(Group group, EventType type)
|
public async Task LogGroupEventAsync(Group group, EventType type)
|
||||||
{
|
{
|
||||||
var e = new Event
|
var e = new EventMessage
|
||||||
{
|
{
|
||||||
OrganizationId = group.OrganizationId,
|
OrganizationId = group.OrganizationId,
|
||||||
GroupId = group.Id,
|
GroupId = group.Id,
|
||||||
@ -123,7 +123,7 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
public async Task LogOrganizationUserEventAsync(OrganizationUser organizationUser, EventType type)
|
public async Task LogOrganizationUserEventAsync(OrganizationUser organizationUser, EventType type)
|
||||||
{
|
{
|
||||||
var e = new Event
|
var e = new EventMessage
|
||||||
{
|
{
|
||||||
OrganizationId = organizationUser.OrganizationId,
|
OrganizationId = organizationUser.OrganizationId,
|
||||||
UserId = organizationUser.UserId,
|
UserId = organizationUser.UserId,
|
||||||
@ -137,7 +137,7 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
public async Task LogOrganizationEventAsync(Organization organization, EventType type)
|
public async Task LogOrganizationEventAsync(Organization organization, EventType type)
|
||||||
{
|
{
|
||||||
var e = new Event
|
var e = new EventMessage
|
||||||
{
|
{
|
||||||
OrganizationId = organization.Id,
|
OrganizationId = organization.Id,
|
||||||
Type = type,
|
Type = type,
|
||||||
|
@ -44,7 +44,7 @@ namespace Bit.Core.Utilities
|
|||||||
|
|
||||||
if(globalSettings.SelfHosted)
|
if(globalSettings.SelfHosted)
|
||||||
{
|
{
|
||||||
// TODO: Sql server event repo
|
services.AddSingleton<IEventRepository, SqlServerRepos.EventRepository>();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -42,13 +42,13 @@ namespace Bit.EventsProcessor
|
|||||||
var token = JToken.Parse(message);
|
var token = JToken.Parse(message);
|
||||||
if(token is JArray)
|
if(token is JArray)
|
||||||
{
|
{
|
||||||
var events = token.ToObject<List<Event>>()
|
var events = token.ToObject<List<EventMessage>>()
|
||||||
.Select(e => new EventTableEntity(e) as IEvent).ToList();
|
.Select(e => new EventTableEntity(e) as IEvent).ToList();
|
||||||
await _eventWriteService.CreateManyAsync(events);
|
await _eventWriteService.CreateManyAsync(events);
|
||||||
}
|
}
|
||||||
else if(token is JObject)
|
else if(token is JObject)
|
||||||
{
|
{
|
||||||
var e = token.ToObject<Event>();
|
var e = token.ToObject<EventMessage>();
|
||||||
await _eventWriteService.CreateAsync(new EventTableEntity(e));
|
await _eventWriteService.CreateAsync(new EventTableEntity(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
39
src/Sql/dbo/Stored Procedures/Event_Create.sql
Normal file
39
src/Sql/dbo/Stored Procedures/Event_Create.sql
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
CREATE PROCEDURE [dbo].[Event_Create]
|
||||||
|
@Id UNIQUEIDENTIFIER,
|
||||||
|
@Type INT,
|
||||||
|
@UserId UNIQUEIDENTIFIER,
|
||||||
|
@OrganizationId UNIQUEIDENTIFIER,
|
||||||
|
@CipherId UNIQUEIDENTIFIER,
|
||||||
|
@CollectionId UNIQUEIDENTIFIER,
|
||||||
|
@GroupId UNIQUEIDENTIFIER,
|
||||||
|
@OrganizationUserId UNIQUEIDENTIFIER,
|
||||||
|
@Date DATETIME2(7)
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
INSERT INTO [dbo].[Event]
|
||||||
|
(
|
||||||
|
[Id],
|
||||||
|
[Type],
|
||||||
|
[UserId],
|
||||||
|
[OrganizationId],
|
||||||
|
[CipherId],
|
||||||
|
[CollectionId],
|
||||||
|
[GroupId],
|
||||||
|
[OrganizationUserId],
|
||||||
|
[Date]
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(
|
||||||
|
@Id,
|
||||||
|
@Type,
|
||||||
|
@UserId,
|
||||||
|
@OrganizationId,
|
||||||
|
@CipherId,
|
||||||
|
@CollectionId,
|
||||||
|
@GroupId,
|
||||||
|
@OrganizationUserId,
|
||||||
|
@Date
|
||||||
|
)
|
||||||
|
END
|
13
src/Sql/dbo/Tables/Event.sql
Normal file
13
src/Sql/dbo/Tables/Event.sql
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
CREATE TABLE [dbo].[Event] (
|
||||||
|
[Id] UNIQUEIDENTIFIER NOT NULL,
|
||||||
|
[Type] INT NOT NULL,
|
||||||
|
[UserId] UNIQUEIDENTIFIER NULL,
|
||||||
|
[OrganizationId] UNIQUEIDENTIFIER NULL,
|
||||||
|
[CipherId] UNIQUEIDENTIFIER NULL,
|
||||||
|
[CollectionId] UNIQUEIDENTIFIER NULL,
|
||||||
|
[GroupId] UNIQUEIDENTIFIER NULL,
|
||||||
|
[OrganizationUserId] UNIQUEIDENTIFIER NULL,
|
||||||
|
[Date] DATETIME2 (7) NOT NULL,
|
||||||
|
CONSTRAINT [PK_Event] PRIMARY KEY CLUSTERED ([Id] ASC)
|
||||||
|
);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user