1
0
mirror of https://github.com/bitwarden/server.git synced 2024-12-03 14:03:33 +01:00
bitwarden-server/src/Infrastructure.Dapper/Repositories/EventRepository.cs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

245 lines
10 KiB
C#
Raw Normal View History

using System.Data;
using Bit.Core.Entities;
2017-12-12 20:22:22 +01:00
using Bit.Core.Models.Data;
using Bit.Core.Repositories;
using Bit.Core.Settings;
using Bit.Core.Vault.Entities;
2017-12-19 05:15:16 +01:00
using Dapper;
using Microsoft.Data.SqlClient;
2017-12-12 20:22:22 +01:00
namespace Bit.Infrastructure.Dapper.Repositories;
2022-08-29 22:06:55 +02:00
public class EventRepository : Repository<Event, Guid>, IEventRepository
2017-12-12 20:22:22 +01:00
{
public EventRepository(GlobalSettings globalSettings)
: this(globalSettings.SqlServer.ConnectionString, globalSettings.SqlServer.ReadOnlyConnectionString)
2022-08-29 22:06:55 +02:00
{ }
2017-12-12 20:22:22 +01:00
public EventRepository(string connectionString, string readOnlyConnectionString)
2017-12-19 05:15:16 +01:00
: base(connectionString, readOnlyConnectionString)
2022-08-29 22:06:55 +02:00
{ }
2017-12-12 20:22:22 +01:00
public async Task<PagedResult<IEvent>> GetManyByUserAsync(Guid userId, DateTime startDate, DateTime endDate,
2017-12-15 21:50:50 +01:00
PageOptions pageOptions)
2017-12-12 20:22:22 +01:00
{
return await GetManyAsync($"[{Schema}].[Event_ReadPageByUserId]",
new Dictionary<string, object>
2022-08-29 22:06:55 +02:00
{
["@UserId"] = userId
}, startDate, endDate, pageOptions);
2017-12-12 20:22:22 +01:00
}
2017-12-19 05:15:16 +01:00
public async Task<PagedResult<IEvent>> GetManyByOrganizationAsync(Guid organizationId,
DateTime startDate, DateTime endDate, PageOptions pageOptions)
2022-08-29 22:06:55 +02:00
{
2017-12-19 05:15:16 +01:00
return await GetManyAsync($"[{Schema}].[Event_ReadPageByOrganizationId]",
new Dictionary<string, object>
2022-08-29 22:06:55 +02:00
{
2017-12-19 05:15:16 +01:00
["@OrganizationId"] = organizationId
}, startDate, endDate, pageOptions);
}
2017-12-15 21:50:50 +01:00
2017-12-19 05:15:16 +01:00
public async Task<PagedResult<IEvent>> GetManyByOrganizationActingUserAsync(Guid organizationId, Guid actingUserId,
DateTime startDate, DateTime endDate, PageOptions pageOptions)
2017-12-15 21:50:50 +01:00
{
2017-12-19 05:15:16 +01:00
return await GetManyAsync($"[{Schema}].[Event_ReadPageByOrganizationIdActingUserId]",
new Dictionary<string, object>
{
["@OrganizationId"] = organizationId,
2017-12-19 05:15:16 +01:00
["@ActingUserId"] = actingUserId
}, startDate, endDate, pageOptions);
2017-12-15 21:50:50 +01:00
}
public async Task<PagedResult<IEvent>> GetManyByProviderAsync(Guid providerId,
DateTime startDate, DateTime endDate, PageOptions pageOptions)
2022-08-29 20:53:16 +02:00
{
return await GetManyAsync($"[{Schema}].[Event_ReadPageByProviderId]",
new Dictionary<string, object>
2022-08-29 20:53:16 +02:00
{
["@ProviderId"] = providerId
}, startDate, endDate, pageOptions);
2022-08-29 20:53:16 +02:00
}
public async Task<PagedResult<IEvent>> GetManyByProviderActingUserAsync(Guid providerId, Guid actingUserId,
DateTime startDate, DateTime endDate, PageOptions pageOptions)
{
return await GetManyAsync($"[{Schema}].[Event_ReadPageByProviderIdActingUserId]",
new Dictionary<string, object>
{
["@ProviderId"] = providerId,
2017-12-19 05:15:16 +01:00
["@ActingUserId"] = actingUserId
}, startDate, endDate, pageOptions);
}
public async Task<PagedResult<IEvent>> GetManyByCipherAsync(Cipher cipher, DateTime startDate, DateTime endDate,
PageOptions pageOptions)
2022-08-29 22:06:55 +02:00
{
return await GetManyAsync($"[{Schema}].[Event_ReadPageByCipherId]",
new Dictionary<string, object>
2022-08-29 22:06:55 +02:00
{
["@OrganizationId"] = cipher.OrganizationId,
2017-12-19 05:15:16 +01:00
["@UserId"] = cipher.UserId,
["@CipherId"] = cipher.Id
}, startDate, endDate, pageOptions);
2022-08-29 22:06:55 +02:00
}
public async Task CreateAsync(IEvent e)
2022-08-29 22:06:55 +02:00
{
if (!(e is Event ev))
{
2017-12-19 05:15:16 +01:00
ev = new Event(e);
2022-08-29 20:53:16 +02:00
}
await base.CreateAsync(ev);
2022-08-29 22:06:55 +02:00
}
public async Task CreateManyAsync(IEnumerable<IEvent> entities)
2022-08-29 22:06:55 +02:00
{
if (!entities?.Any() ?? true)
{
return;
}
2017-12-19 05:15:16 +01:00
if (!entities.Skip(1).Any())
2017-12-15 21:50:50 +01:00
{
2017-12-19 05:15:16 +01:00
await CreateAsync(entities.First());
return;
2017-12-14 18:33:50 +01:00
}
2017-12-12 20:22:22 +01:00
using (var connection = new SqlConnection(ConnectionString))
{
2017-12-19 05:15:16 +01:00
connection.Open();
using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, null))
2017-12-12 20:22:22 +01:00
{
2017-12-19 05:15:16 +01:00
bulkCopy.DestinationTableName = "[dbo].[Event]";
2017-12-12 20:22:22 +01:00
var dataTable = BuildEventsTable(bulkCopy, entities.Select(e => e is Event ? e as Event : new Event(e)));
2017-12-19 05:15:16 +01:00
await bulkCopy.WriteToServerAsync(dataTable);
2017-12-12 20:22:22 +01:00
}
}
2022-08-29 22:06:55 +02:00
}
2017-12-12 20:22:22 +01:00
public async Task<PagedResult<IEvent>> GetManyByOrganizationServiceAccountAsync(Guid organizationId, Guid serviceAccountId,
DateTime startDate, DateTime endDate,
PageOptions pageOptions)
{
return await GetManyAsync($"[{Schema}].[Event_ReadPageByOrganizationIdServiceAccountId]",
new Dictionary<string, object>
{
["@OrganizationId"] = organizationId,
["@ServiceAccountId"] = serviceAccountId
}, startDate, endDate, pageOptions);
}
2017-12-19 05:15:16 +01:00
private async Task<PagedResult<IEvent>> GetManyAsync(string sprocName,
IDictionary<string, object> sprocParams, DateTime startDate, DateTime endDate, PageOptions pageOptions)
2022-08-29 22:06:55 +02:00
{
2017-12-12 20:22:22 +01:00
DateTime? beforeDate = null;
2017-12-19 05:15:16 +01:00
if (!string.IsNullOrWhiteSpace(pageOptions.ContinuationToken) &&
2017-12-12 20:22:22 +01:00
long.TryParse(pageOptions.ContinuationToken, out var binaryDate))
2022-08-29 20:53:16 +02:00
{
2017-12-19 05:15:16 +01:00
beforeDate = DateTime.SpecifyKind(DateTime.FromBinary(binaryDate), DateTimeKind.Utc);
}
2020-02-28 04:44:49 +01:00
var parameters = new DynamicParameters(sprocParams);
parameters.Add("@PageSize", pageOptions.PageSize, DbType.Int32);
// Explicitly use DbType.DateTime2 for proper precision.
// ref: https://github.com/StackExchange/Dapper/issues/229
parameters.Add("@StartDate", startDate.ToUniversalTime(), DbType.DateTime2, null, 7);
2017-12-12 20:22:22 +01:00
parameters.Add("@EndDate", endDate.ToUniversalTime(), DbType.DateTime2, null, 7);
parameters.Add("@BeforeDate", beforeDate, DbType.DateTime2, null, 7);
2017-12-12 20:22:22 +01:00
using (var connection = new SqlConnection(ConnectionString))
2022-08-29 22:06:55 +02:00
{
2017-12-12 20:22:22 +01:00
var events = (await connection.QueryAsync<Event>(sprocName, parameters,
2017-12-19 05:15:16 +01:00
commandType: CommandType.StoredProcedure)).ToList();
2017-12-12 20:22:22 +01:00
var result = new PagedResult<IEvent>();
if (events.Any() && events.Count >= pageOptions.PageSize)
{
2017-12-12 20:22:22 +01:00
result.ContinuationToken = events.Last().Date.ToBinary().ToString();
}
2017-12-19 05:15:16 +01:00
result.Data.AddRange(events);
return result;
2020-02-28 04:44:49 +01:00
}
2022-08-29 22:06:55 +02:00
}
2020-02-28 04:44:49 +01:00
2017-12-12 20:22:22 +01:00
private DataTable BuildEventsTable(SqlBulkCopy bulkCopy, IEnumerable<Event> events)
2022-08-29 22:06:55 +02:00
{
2017-12-12 20:22:22 +01:00
var e = events.FirstOrDefault();
if (e == null)
2022-08-29 20:53:16 +02:00
{
2017-12-12 20:22:22 +01:00
throw new ApplicationException("Must have some events to bulk import.");
}
2017-12-12 20:22:22 +01:00
var eventsTable = new DataTable("EventDataTable");
2022-08-29 22:06:55 +02:00
2017-12-12 20:22:22 +01:00
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 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);
2017-12-12 21:04:14 +01:00
var collectionIdColumn = new DataColumn(nameof(e.CollectionId), typeof(Guid));
2017-12-12 20:22:22 +01:00
eventsTable.Columns.Add(collectionIdColumn);
2017-12-12 21:04:14 +01:00
var policyIdColumn = new DataColumn(nameof(e.PolicyId), typeof(Guid));
2020-01-15 15:43:49 +01:00
eventsTable.Columns.Add(policyIdColumn);
2017-12-12 21:04:14 +01:00
var groupIdColumn = new DataColumn(nameof(e.GroupId), typeof(Guid));
eventsTable.Columns.Add(groupIdColumn);
var organizationUserIdColumn = new DataColumn(nameof(e.OrganizationUserId), typeof(Guid));
2017-12-12 20:22:22 +01:00
eventsTable.Columns.Add(organizationUserIdColumn);
2017-12-19 05:15:16 +01:00
var actingUserIdColumn = new DataColumn(nameof(e.ActingUserId), typeof(Guid));
eventsTable.Columns.Add(actingUserIdColumn);
var deviceTypeColumn = new DataColumn(nameof(e.DeviceType), typeof(int));
2017-12-12 21:04:14 +01:00
eventsTable.Columns.Add(deviceTypeColumn);
var ipAddressColumn = new DataColumn(nameof(e.IpAddress), typeof(string));
2017-12-19 05:15:16 +01:00
eventsTable.Columns.Add(ipAddressColumn);
2017-12-12 21:04:14 +01:00
var dateColumn = new DataColumn(nameof(e.Date), typeof(DateTime));
eventsTable.Columns.Add(dateColumn);
var secretIdColumn = new DataColumn(nameof(e.SecretId), typeof(Guid));
eventsTable.Columns.Add(secretIdColumn);
var serviceAccountIdColumn = new DataColumn(nameof(e.ServiceAccountId), typeof(Guid));
eventsTable.Columns.Add(serviceAccountIdColumn);
2022-08-29 22:06:55 +02:00
foreach (DataColumn col in eventsTable.Columns)
2022-08-29 22:06:55 +02:00
{
2017-12-12 21:04:14 +01:00
bulkCopy.ColumnMappings.Add(col.ColumnName, col.ColumnName);
2022-08-29 22:06:55 +02:00
}
2022-08-29 20:53:16 +02:00
2017-12-12 20:22:22 +01:00
var keys = new DataColumn[1];
2017-12-12 21:04:14 +01:00
keys[0] = idColumn;
eventsTable.PrimaryKey = keys;
foreach (var ev in events)
2022-08-29 22:06:55 +02:00
{
ev.SetNewId();
2022-08-29 22:06:55 +02:00
var row = eventsTable.NewRow();
2022-08-29 22:06:55 +02:00
2017-12-12 20:22:22 +01:00
row[idColumn] = ev.Id;
row[typeColumn] = (int)ev.Type;
2017-12-12 21:04:14 +01:00
row[userIdColumn] = ev.UserId.HasValue ? (object)ev.UserId.Value : DBNull.Value;
row[organizationIdColumn] = ev.OrganizationId.HasValue ? (object)ev.OrganizationId.Value : DBNull.Value;
row[cipherIdColumn] = ev.CipherId.HasValue ? (object)ev.CipherId.Value : DBNull.Value;
row[collectionIdColumn] = ev.CollectionId.HasValue ? (object)ev.CollectionId.Value : DBNull.Value;
2020-01-15 15:43:49 +01:00
row[policyIdColumn] = ev.PolicyId.HasValue ? (object)ev.PolicyId.Value : DBNull.Value;
2017-12-19 05:15:16 +01:00
row[groupIdColumn] = ev.GroupId.HasValue ? (object)ev.GroupId.Value : DBNull.Value;
2017-12-12 21:04:14 +01:00
row[organizationUserIdColumn] = ev.OrganizationUserId.HasValue ?
(object)ev.OrganizationUserId.Value : DBNull.Value;
2017-12-19 05:15:16 +01:00
row[actingUserIdColumn] = ev.ActingUserId.HasValue ? (object)ev.ActingUserId.Value : DBNull.Value;
row[deviceTypeColumn] = ev.DeviceType.HasValue ? (object)ev.DeviceType.Value : DBNull.Value;
row[ipAddressColumn] = ev.IpAddress != null ? (object)ev.IpAddress : DBNull.Value;
row[dateColumn] = ev.Date;
row[secretIdColumn] = ev.SecretId.HasValue ? ev.SecretId.Value : DBNull.Value;
row[serviceAccountIdColumn] = ev.ServiceAccountId.HasValue ? ev.ServiceAccountId.Value : DBNull.Value;
2022-08-29 22:06:55 +02:00
2017-12-12 21:04:14 +01:00
eventsTable.Rows.Add(row);
}
2022-08-29 22:06:55 +02:00
return eventsTable;
2017-12-12 20:22:22 +01:00
}
}