mirror of
https://github.com/bitwarden/server.git
synced 2025-07-09 20:03:47 -05:00
[AC-2972] AC Team ownership: Events (#4647)
* Move Event domain under AC Team ownership
This commit is contained in:
65
src/Core/AdminConsole/Entities/Event.cs
Normal file
65
src/Core/AdminConsole/Entities/Event.cs
Normal file
@ -0,0 +1,65 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Core.Entities;
|
||||
|
||||
public class Event : ITableObject<Guid>, IEvent
|
||||
{
|
||||
public Event() { }
|
||||
|
||||
public Event(IEvent e)
|
||||
{
|
||||
Date = e.Date;
|
||||
Type = e.Type;
|
||||
UserId = e.UserId;
|
||||
OrganizationId = e.OrganizationId;
|
||||
ProviderId = e.ProviderId;
|
||||
CipherId = e.CipherId;
|
||||
CollectionId = e.CollectionId;
|
||||
PolicyId = e.PolicyId;
|
||||
GroupId = e.GroupId;
|
||||
OrganizationUserId = e.OrganizationUserId;
|
||||
InstallationId = e.InstallationId;
|
||||
ProviderUserId = e.ProviderUserId;
|
||||
ProviderOrganizationId = e.ProviderOrganizationId;
|
||||
DeviceType = e.DeviceType;
|
||||
IpAddress = e.IpAddress;
|
||||
ActingUserId = e.ActingUserId;
|
||||
SystemUser = e.SystemUser;
|
||||
DomainName = e.DomainName;
|
||||
SecretId = e.SecretId;
|
||||
ServiceAccountId = e.ServiceAccountId;
|
||||
}
|
||||
|
||||
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? InstallationId { get; set; }
|
||||
public Guid? ProviderId { get; set; }
|
||||
public Guid? CipherId { get; set; }
|
||||
public Guid? CollectionId { get; set; }
|
||||
public Guid? PolicyId { get; set; }
|
||||
public Guid? GroupId { get; set; }
|
||||
public Guid? OrganizationUserId { get; set; }
|
||||
public Guid? ProviderUserId { get; set; }
|
||||
public Guid? ProviderOrganizationId { get; set; }
|
||||
public DeviceType? DeviceType { get; set; }
|
||||
[MaxLength(50)]
|
||||
public string? IpAddress { get; set; }
|
||||
public Guid? ActingUserId { get; set; }
|
||||
public EventSystemUser? SystemUser { get; set; }
|
||||
public string? DomainName { get; set; }
|
||||
public Guid? SecretId { get; set; }
|
||||
public Guid? ServiceAccountId { get; set; }
|
||||
|
||||
public void SetNewId()
|
||||
{
|
||||
Id = CoreHelpers.GenerateComb();
|
||||
}
|
||||
}
|
7
src/Core/AdminConsole/Enums/EventSystemUser.cs
Normal file
7
src/Core/AdminConsole/Enums/EventSystemUser.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace Bit.Core.Enums;
|
||||
|
||||
public enum EventSystemUser : byte
|
||||
{
|
||||
SCIM = 1,
|
||||
DomainVerification = 2
|
||||
}
|
91
src/Core/AdminConsole/Enums/EventType.cs
Normal file
91
src/Core/AdminConsole/Enums/EventType.cs
Normal file
@ -0,0 +1,91 @@
|
||||
namespace Bit.Core.Enums;
|
||||
|
||||
// Increment by 100 for each new set of events
|
||||
public enum EventType : int
|
||||
{
|
||||
User_LoggedIn = 1000,
|
||||
User_ChangedPassword = 1001,
|
||||
User_Updated2fa = 1002,
|
||||
User_Disabled2fa = 1003,
|
||||
User_Recovered2fa = 1004,
|
||||
User_FailedLogIn = 1005,
|
||||
User_FailedLogIn2fa = 1006,
|
||||
User_ClientExportedVault = 1007,
|
||||
User_UpdatedTempPassword = 1008,
|
||||
User_MigratedKeyToKeyConnector = 1009,
|
||||
User_RequestedDeviceApproval = 1010,
|
||||
User_TdeOffboardingPasswordSet = 1011,
|
||||
|
||||
Cipher_Created = 1100,
|
||||
Cipher_Updated = 1101,
|
||||
Cipher_Deleted = 1102,
|
||||
Cipher_AttachmentCreated = 1103,
|
||||
Cipher_AttachmentDeleted = 1104,
|
||||
Cipher_Shared = 1105,
|
||||
Cipher_UpdatedCollections = 1106,
|
||||
Cipher_ClientViewed = 1107,
|
||||
Cipher_ClientToggledPasswordVisible = 1108,
|
||||
Cipher_ClientToggledHiddenFieldVisible = 1109,
|
||||
Cipher_ClientToggledCardCodeVisible = 1110,
|
||||
Cipher_ClientCopiedPassword = 1111,
|
||||
Cipher_ClientCopiedHiddenField = 1112,
|
||||
Cipher_ClientCopiedCardCode = 1113,
|
||||
Cipher_ClientAutofilled = 1114,
|
||||
Cipher_SoftDeleted = 1115,
|
||||
Cipher_Restored = 1116,
|
||||
Cipher_ClientToggledCardNumberVisible = 1117,
|
||||
|
||||
Collection_Created = 1300,
|
||||
Collection_Updated = 1301,
|
||||
Collection_Deleted = 1302,
|
||||
|
||||
Group_Created = 1400,
|
||||
Group_Updated = 1401,
|
||||
Group_Deleted = 1402,
|
||||
|
||||
OrganizationUser_Invited = 1500,
|
||||
OrganizationUser_Confirmed = 1501,
|
||||
OrganizationUser_Updated = 1502,
|
||||
OrganizationUser_Removed = 1503,
|
||||
OrganizationUser_UpdatedGroups = 1504,
|
||||
OrganizationUser_UnlinkedSso = 1505,
|
||||
OrganizationUser_ResetPassword_Enroll = 1506,
|
||||
OrganizationUser_ResetPassword_Withdraw = 1507,
|
||||
OrganizationUser_AdminResetPassword = 1508,
|
||||
OrganizationUser_ResetSsoLink = 1509,
|
||||
OrganizationUser_FirstSsoLogin = 1510,
|
||||
OrganizationUser_Revoked = 1511,
|
||||
OrganizationUser_Restored = 1512,
|
||||
OrganizationUser_ApprovedAuthRequest = 1513,
|
||||
OrganizationUser_RejectedAuthRequest = 1514,
|
||||
|
||||
Organization_Updated = 1600,
|
||||
Organization_PurgedVault = 1601,
|
||||
Organization_ClientExportedVault = 1602,
|
||||
Organization_VaultAccessed = 1603,
|
||||
Organization_EnabledSso = 1604,
|
||||
Organization_DisabledSso = 1605,
|
||||
Organization_EnabledKeyConnector = 1606,
|
||||
Organization_DisabledKeyConnector = 1607,
|
||||
Organization_SponsorshipsSynced = 1608,
|
||||
Organization_CollectionManagement_Updated = 1609,
|
||||
|
||||
Policy_Updated = 1700,
|
||||
|
||||
ProviderUser_Invited = 1800,
|
||||
ProviderUser_Confirmed = 1801,
|
||||
ProviderUser_Updated = 1802,
|
||||
ProviderUser_Removed = 1803,
|
||||
|
||||
ProviderOrganization_Created = 1900,
|
||||
ProviderOrganization_Added = 1901,
|
||||
ProviderOrganization_Removed = 1902,
|
||||
ProviderOrganization_VaultAccessed = 1903,
|
||||
|
||||
OrganizationDomain_Added = 2000,
|
||||
OrganizationDomain_Removed = 2001,
|
||||
OrganizationDomain_Verified = 2002,
|
||||
OrganizationDomain_NotVerified = 2003,
|
||||
|
||||
Secret_Retrieved = 2100,
|
||||
}
|
38
src/Core/AdminConsole/Models/Data/EventMessage.cs
Normal file
38
src/Core/AdminConsole/Models/Data/EventMessage.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.Models.Data;
|
||||
|
||||
public class EventMessage : IEvent
|
||||
{
|
||||
public EventMessage() { }
|
||||
|
||||
public EventMessage(ICurrentContext currentContext)
|
||||
: base()
|
||||
{
|
||||
IpAddress = currentContext.IpAddress;
|
||||
DeviceType = currentContext.DeviceType;
|
||||
}
|
||||
|
||||
public DateTime Date { get; set; }
|
||||
public EventType Type { get; set; }
|
||||
public Guid? UserId { get; set; }
|
||||
public Guid? OrganizationId { get; set; }
|
||||
public Guid? InstallationId { get; set; }
|
||||
public Guid? ProviderId { get; set; }
|
||||
public Guid? CipherId { get; set; }
|
||||
public Guid? CollectionId { get; set; }
|
||||
public Guid? GroupId { get; set; }
|
||||
public Guid? PolicyId { get; set; }
|
||||
public Guid? OrganizationUserId { get; set; }
|
||||
public Guid? ProviderUserId { get; set; }
|
||||
public Guid? ProviderOrganizationId { get; set; }
|
||||
public Guid? ActingUserId { get; set; }
|
||||
public DeviceType? DeviceType { get; set; }
|
||||
public string IpAddress { get; set; }
|
||||
public Guid? IdempotencyId { get; private set; } = Guid.NewGuid();
|
||||
public EventSystemUser? SystemUser { get; set; }
|
||||
public string DomainName { get; set; }
|
||||
public Guid? SecretId { get; set; }
|
||||
public Guid? ServiceAccountId { get; set; }
|
||||
}
|
235
src/Core/AdminConsole/Models/Data/EventTableEntity.cs
Normal file
235
src/Core/AdminConsole/Models/Data/EventTableEntity.cs
Normal file
@ -0,0 +1,235 @@
|
||||
using Azure;
|
||||
using Azure.Data.Tables;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.Core.Models.Data;
|
||||
|
||||
// used solely for interaction with Azure Table Storage
|
||||
public class AzureEvent : ITableEntity
|
||||
{
|
||||
public string PartitionKey { get; set; }
|
||||
public string RowKey { get; set; }
|
||||
public DateTimeOffset? Timestamp { get; set; }
|
||||
public ETag ETag { get; set; }
|
||||
|
||||
public DateTime Date { get; set; }
|
||||
public int Type { get; set; }
|
||||
public Guid? UserId { get; set; }
|
||||
public Guid? OrganizationId { get; set; }
|
||||
public Guid? InstallationId { get; set; }
|
||||
public Guid? ProviderId { get; set; }
|
||||
public Guid? CipherId { get; set; }
|
||||
public Guid? CollectionId { get; set; }
|
||||
public Guid? PolicyId { get; set; }
|
||||
public Guid? GroupId { get; set; }
|
||||
public Guid? OrganizationUserId { get; set; }
|
||||
public Guid? ProviderUserId { get; set; }
|
||||
public Guid? ProviderOrganizationId { get; set; }
|
||||
public int? DeviceType { get; set; }
|
||||
public string IpAddress { get; set; }
|
||||
public Guid? ActingUserId { get; set; }
|
||||
public int? SystemUser { get; set; }
|
||||
public string DomainName { get; set; }
|
||||
public Guid? SecretId { get; set; }
|
||||
public Guid? ServiceAccountId { get; set; }
|
||||
|
||||
public EventTableEntity ToEventTableEntity()
|
||||
{
|
||||
return new EventTableEntity
|
||||
{
|
||||
PartitionKey = PartitionKey,
|
||||
RowKey = RowKey,
|
||||
Timestamp = Timestamp,
|
||||
ETag = ETag,
|
||||
|
||||
Date = Date,
|
||||
Type = (EventType)Type,
|
||||
UserId = UserId,
|
||||
OrganizationId = OrganizationId,
|
||||
InstallationId = InstallationId,
|
||||
ProviderId = ProviderId,
|
||||
CipherId = CipherId,
|
||||
CollectionId = CollectionId,
|
||||
PolicyId = PolicyId,
|
||||
GroupId = GroupId,
|
||||
OrganizationUserId = OrganizationUserId,
|
||||
ProviderUserId = ProviderUserId,
|
||||
ProviderOrganizationId = ProviderOrganizationId,
|
||||
DeviceType = DeviceType.HasValue ? (DeviceType)DeviceType.Value : null,
|
||||
IpAddress = IpAddress,
|
||||
ActingUserId = ActingUserId,
|
||||
SystemUser = SystemUser.HasValue ? (EventSystemUser)SystemUser.Value : null,
|
||||
DomainName = DomainName,
|
||||
SecretId = SecretId,
|
||||
ServiceAccountId = ServiceAccountId
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class EventTableEntity : IEvent
|
||||
{
|
||||
public EventTableEntity() { }
|
||||
|
||||
private EventTableEntity(IEvent e)
|
||||
{
|
||||
Date = e.Date;
|
||||
Type = e.Type;
|
||||
UserId = e.UserId;
|
||||
OrganizationId = e.OrganizationId;
|
||||
InstallationId = e.InstallationId;
|
||||
ProviderId = e.ProviderId;
|
||||
CipherId = e.CipherId;
|
||||
CollectionId = e.CollectionId;
|
||||
PolicyId = e.PolicyId;
|
||||
GroupId = e.GroupId;
|
||||
OrganizationUserId = e.OrganizationUserId;
|
||||
ProviderUserId = e.ProviderUserId;
|
||||
ProviderOrganizationId = e.ProviderOrganizationId;
|
||||
DeviceType = e.DeviceType;
|
||||
IpAddress = e.IpAddress;
|
||||
ActingUserId = e.ActingUserId;
|
||||
SystemUser = e.SystemUser;
|
||||
DomainName = e.DomainName;
|
||||
SecretId = e.SecretId;
|
||||
ServiceAccountId = e.ServiceAccountId;
|
||||
}
|
||||
|
||||
public string PartitionKey { get; set; }
|
||||
public string RowKey { get; set; }
|
||||
public DateTimeOffset? Timestamp { get; set; }
|
||||
public ETag ETag { get; set; }
|
||||
|
||||
public DateTime Date { get; set; }
|
||||
public EventType Type { get; set; }
|
||||
public Guid? UserId { get; set; }
|
||||
public Guid? OrganizationId { get; set; }
|
||||
public Guid? InstallationId { get; set; }
|
||||
public Guid? ProviderId { get; set; }
|
||||
public Guid? CipherId { get; set; }
|
||||
public Guid? CollectionId { get; set; }
|
||||
public Guid? PolicyId { get; set; }
|
||||
public Guid? GroupId { get; set; }
|
||||
public Guid? OrganizationUserId { get; set; }
|
||||
public Guid? ProviderUserId { get; set; }
|
||||
public Guid? ProviderOrganizationId { get; set; }
|
||||
public DeviceType? DeviceType { get; set; }
|
||||
public string IpAddress { get; set; }
|
||||
public Guid? ActingUserId { get; set; }
|
||||
public EventSystemUser? SystemUser { get; set; }
|
||||
public string DomainName { get; set; }
|
||||
public Guid? SecretId { get; set; }
|
||||
public Guid? ServiceAccountId { get; set; }
|
||||
|
||||
public AzureEvent ToAzureEvent()
|
||||
{
|
||||
return new AzureEvent
|
||||
{
|
||||
PartitionKey = PartitionKey,
|
||||
RowKey = RowKey,
|
||||
Timestamp = Timestamp,
|
||||
ETag = ETag,
|
||||
|
||||
Date = Date,
|
||||
Type = (int)Type,
|
||||
UserId = UserId,
|
||||
OrganizationId = OrganizationId,
|
||||
InstallationId = InstallationId,
|
||||
ProviderId = ProviderId,
|
||||
CipherId = CipherId,
|
||||
CollectionId = CollectionId,
|
||||
PolicyId = PolicyId,
|
||||
GroupId = GroupId,
|
||||
OrganizationUserId = OrganizationUserId,
|
||||
ProviderUserId = ProviderUserId,
|
||||
ProviderOrganizationId = ProviderOrganizationId,
|
||||
DeviceType = DeviceType.HasValue ? (int)DeviceType.Value : null,
|
||||
IpAddress = IpAddress,
|
||||
ActingUserId = ActingUserId,
|
||||
SystemUser = SystemUser.HasValue ? (int)SystemUser.Value : null,
|
||||
DomainName = DomainName,
|
||||
SecretId = SecretId,
|
||||
ServiceAccountId = ServiceAccountId
|
||||
};
|
||||
}
|
||||
|
||||
public static List<EventTableEntity> IndexEvent(EventMessage e)
|
||||
{
|
||||
var uniquifier = e.IdempotencyId.GetValueOrDefault(Guid.NewGuid());
|
||||
|
||||
var pKey = GetPartitionKey(e);
|
||||
|
||||
var dateKey = CoreHelpers.DateTimeToTableStorageKey(e.Date);
|
||||
|
||||
var entities = new List<EventTableEntity>
|
||||
{
|
||||
new EventTableEntity(e)
|
||||
{
|
||||
PartitionKey = pKey,
|
||||
RowKey = $"Date={dateKey}__Uniquifier={uniquifier}"
|
||||
}
|
||||
};
|
||||
|
||||
if (e.OrganizationId.HasValue && e.ActingUserId.HasValue)
|
||||
{
|
||||
entities.Add(new EventTableEntity(e)
|
||||
{
|
||||
PartitionKey = pKey,
|
||||
RowKey = $"ActingUserId={e.ActingUserId}__Date={dateKey}__Uniquifier={uniquifier}"
|
||||
});
|
||||
}
|
||||
|
||||
if (!e.OrganizationId.HasValue && e.ProviderId.HasValue && e.ActingUserId.HasValue)
|
||||
{
|
||||
entities.Add(new EventTableEntity(e)
|
||||
{
|
||||
PartitionKey = pKey,
|
||||
RowKey = $"ActingUserId={e.ActingUserId}__Date={dateKey}__Uniquifier={uniquifier}"
|
||||
});
|
||||
}
|
||||
|
||||
if (e.CipherId.HasValue)
|
||||
{
|
||||
entities.Add(new EventTableEntity(e)
|
||||
{
|
||||
PartitionKey = pKey,
|
||||
RowKey = $"CipherId={e.CipherId}__Date={dateKey}__Uniquifier={uniquifier}"
|
||||
});
|
||||
}
|
||||
|
||||
if (e.OrganizationId.HasValue && e.ServiceAccountId.HasValue)
|
||||
{
|
||||
entities.Add(new EventTableEntity(e)
|
||||
{
|
||||
PartitionKey = pKey,
|
||||
RowKey = $"ServiceAccountId={e.ServiceAccountId}__Date={dateKey}__Uniquifier={uniquifier}"
|
||||
});
|
||||
}
|
||||
|
||||
if (e.SecretId.HasValue)
|
||||
{
|
||||
entities.Add(new EventTableEntity(e)
|
||||
{
|
||||
PartitionKey = pKey,
|
||||
RowKey = $"SecretId={e.CipherId}__Date={dateKey}__Uniquifier={uniquifier}"
|
||||
});
|
||||
}
|
||||
|
||||
return entities;
|
||||
}
|
||||
|
||||
private static string GetPartitionKey(EventMessage e)
|
||||
{
|
||||
if (e.OrganizationId.HasValue)
|
||||
{
|
||||
return $"OrganizationId={e.OrganizationId}";
|
||||
}
|
||||
|
||||
if (e.ProviderId.HasValue)
|
||||
{
|
||||
return $"ProviderId={e.ProviderId}";
|
||||
}
|
||||
|
||||
return $"UserId={e.UserId}";
|
||||
}
|
||||
}
|
27
src/Core/AdminConsole/Models/Data/IEvent.cs
Normal file
27
src/Core/AdminConsole/Models/Data/IEvent.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using Bit.Core.Enums;
|
||||
|
||||
namespace Bit.Core.Models.Data;
|
||||
|
||||
public interface IEvent
|
||||
{
|
||||
EventType Type { get; set; }
|
||||
Guid? UserId { get; set; }
|
||||
Guid? OrganizationId { get; set; }
|
||||
Guid? InstallationId { get; set; }
|
||||
Guid? ProviderId { get; set; }
|
||||
Guid? CipherId { get; set; }
|
||||
Guid? CollectionId { get; set; }
|
||||
Guid? GroupId { get; set; }
|
||||
Guid? PolicyId { get; set; }
|
||||
Guid? OrganizationUserId { get; set; }
|
||||
Guid? ProviderUserId { get; set; }
|
||||
Guid? ProviderOrganizationId { get; set; }
|
||||
Guid? ActingUserId { get; set; }
|
||||
DeviceType? DeviceType { get; set; }
|
||||
string IpAddress { get; set; }
|
||||
DateTime Date { get; set; }
|
||||
EventSystemUser? SystemUser { get; set; }
|
||||
string DomainName { get; set; }
|
||||
Guid? SecretId { get; set; }
|
||||
Guid? ServiceAccountId { get; set; }
|
||||
}
|
26
src/Core/AdminConsole/Repositories/IEventRepository.cs
Normal file
26
src/Core/AdminConsole/Repositories/IEventRepository.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Vault.Entities;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Core.Repositories;
|
||||
|
||||
public interface IEventRepository
|
||||
{
|
||||
Task<PagedResult<IEvent>> GetManyByUserAsync(Guid userId, DateTime startDate, DateTime endDate,
|
||||
PageOptions pageOptions);
|
||||
Task<PagedResult<IEvent>> GetManyByOrganizationAsync(Guid organizationId, DateTime startDate, DateTime endDate,
|
||||
PageOptions pageOptions);
|
||||
Task<PagedResult<IEvent>> GetManyByOrganizationActingUserAsync(Guid organizationId, Guid actingUserId,
|
||||
DateTime startDate, DateTime endDate, PageOptions pageOptions);
|
||||
Task<PagedResult<IEvent>> GetManyByProviderAsync(Guid providerId, DateTime startDate, DateTime endDate,
|
||||
PageOptions pageOptions);
|
||||
Task<PagedResult<IEvent>> GetManyByProviderActingUserAsync(Guid providerId, Guid actingUserId,
|
||||
DateTime startDate, DateTime endDate, PageOptions pageOptions);
|
||||
Task<PagedResult<IEvent>> GetManyByCipherAsync(Cipher cipher, DateTime startDate, DateTime endDate,
|
||||
PageOptions pageOptions);
|
||||
Task CreateAsync(IEvent e);
|
||||
Task CreateManyAsync(IEnumerable<IEvent> e);
|
||||
Task<PagedResult<IEvent>> GetManyByOrganizationServiceAccountAsync(Guid organizationId, Guid serviceAccountId,
|
||||
DateTime startDate, DateTime endDate, PageOptions pageOptions);
|
||||
}
|
@ -0,0 +1,160 @@
|
||||
using Azure.Data.Tables;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Core.Vault.Entities;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.Core.Repositories.TableStorage;
|
||||
|
||||
public class EventRepository : IEventRepository
|
||||
{
|
||||
private readonly TableClient _tableClient;
|
||||
|
||||
public EventRepository(GlobalSettings globalSettings)
|
||||
: this(globalSettings.Events.ConnectionString)
|
||||
{ }
|
||||
|
||||
public EventRepository(string storageConnectionString)
|
||||
{
|
||||
var tableClient = new TableServiceClient(storageConnectionString);
|
||||
_tableClient = tableClient.GetTableClient("event");
|
||||
}
|
||||
|
||||
public async Task<PagedResult<IEvent>> GetManyByUserAsync(Guid userId, DateTime startDate, DateTime endDate,
|
||||
PageOptions pageOptions)
|
||||
{
|
||||
return await GetManyAsync($"UserId={userId}", "Date={{0}}", startDate, endDate, pageOptions);
|
||||
}
|
||||
|
||||
public async Task<PagedResult<IEvent>> GetManyByOrganizationAsync(Guid organizationId,
|
||||
DateTime startDate, DateTime endDate, PageOptions pageOptions)
|
||||
{
|
||||
return await GetManyAsync($"OrganizationId={organizationId}", "Date={0}", startDate, endDate, pageOptions);
|
||||
}
|
||||
|
||||
public async Task<PagedResult<IEvent>> GetManyByOrganizationActingUserAsync(Guid organizationId, Guid actingUserId,
|
||||
DateTime startDate, DateTime endDate, PageOptions pageOptions)
|
||||
{
|
||||
return await GetManyAsync($"OrganizationId={organizationId}",
|
||||
$"ActingUserId={actingUserId}__Date={{0}}", startDate, endDate, pageOptions);
|
||||
}
|
||||
|
||||
public async Task<PagedResult<IEvent>> GetManyByProviderAsync(Guid providerId,
|
||||
DateTime startDate, DateTime endDate, PageOptions pageOptions)
|
||||
{
|
||||
return await GetManyAsync($"ProviderId={providerId}", "Date={0}", startDate, endDate, pageOptions);
|
||||
}
|
||||
|
||||
public async Task<PagedResult<IEvent>> GetManyByProviderActingUserAsync(Guid providerId, Guid actingUserId,
|
||||
DateTime startDate, DateTime endDate, PageOptions pageOptions)
|
||||
{
|
||||
return await GetManyAsync($"ProviderId={providerId}",
|
||||
$"ActingUserId={actingUserId}__Date={{0}}", startDate, endDate, pageOptions);
|
||||
}
|
||||
|
||||
public async Task<PagedResult<IEvent>> GetManyByCipherAsync(Cipher cipher, DateTime startDate, DateTime endDate,
|
||||
PageOptions pageOptions)
|
||||
{
|
||||
var partitionKey = cipher.OrganizationId.HasValue ?
|
||||
$"OrganizationId={cipher.OrganizationId}" : $"UserId={cipher.UserId}";
|
||||
return await GetManyAsync(partitionKey, $"CipherId={cipher.Id}__Date={{0}}", startDate, endDate, pageOptions);
|
||||
}
|
||||
|
||||
public async Task<PagedResult<IEvent>> GetManyByOrganizationServiceAccountAsync(Guid organizationId,
|
||||
Guid serviceAccountId, DateTime startDate, DateTime endDate, PageOptions pageOptions)
|
||||
{
|
||||
|
||||
return await GetManyAsync($"OrganizationId={organizationId}",
|
||||
$"ServiceAccountId={serviceAccountId}__Date={{0}}", startDate, endDate, pageOptions);
|
||||
}
|
||||
|
||||
public async Task CreateAsync(IEvent e)
|
||||
{
|
||||
if (!(e is EventTableEntity entity))
|
||||
{
|
||||
throw new ArgumentException(nameof(e));
|
||||
}
|
||||
|
||||
await CreateEventAsync(entity);
|
||||
}
|
||||
|
||||
public async Task CreateManyAsync(IEnumerable<IEvent>? e)
|
||||
{
|
||||
if (e is null || !e.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!e.Skip(1).Any())
|
||||
{
|
||||
await CreateAsync(e.First());
|
||||
return;
|
||||
}
|
||||
|
||||
var entities = e.OfType<EventTableEntity>();
|
||||
var entityGroups = entities.GroupBy(ent => ent.PartitionKey);
|
||||
foreach (var group in entityGroups)
|
||||
{
|
||||
var groupEntities = group.ToList();
|
||||
if (groupEntities.Count == 1)
|
||||
{
|
||||
await CreateEventAsync(groupEntities.First());
|
||||
continue;
|
||||
}
|
||||
|
||||
// A batch insert can only contain 100 entities at a time
|
||||
var iterations = groupEntities.Count / 100;
|
||||
for (var i = 0; i <= iterations; i++)
|
||||
{
|
||||
var batch = new List<TableTransactionAction>();
|
||||
var batchEntities = groupEntities.Skip(i * 100).Take(100);
|
||||
if (!batchEntities.Any())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (var entity in batchEntities)
|
||||
{
|
||||
batch.Add(new TableTransactionAction(TableTransactionActionType.Add,
|
||||
entity.ToAzureEvent()));
|
||||
}
|
||||
|
||||
await _tableClient.SubmitTransactionAsync(batch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<PagedResult<IEvent>> GetManyAsync(string partitionKey, string rowKey,
|
||||
DateTime startDate, DateTime endDate, PageOptions pageOptions)
|
||||
{
|
||||
var start = CoreHelpers.DateTimeToTableStorageKey(startDate);
|
||||
var end = CoreHelpers.DateTimeToTableStorageKey(endDate);
|
||||
var filter = MakeFilter(partitionKey, string.Format(rowKey, start), string.Format(rowKey, end));
|
||||
|
||||
var result = new PagedResult<IEvent>();
|
||||
var query = _tableClient.QueryAsync<AzureEvent>(filter, pageOptions.PageSize);
|
||||
|
||||
await using (var enumerator = query.AsPages(pageOptions.ContinuationToken,
|
||||
pageOptions.PageSize).GetAsyncEnumerator())
|
||||
{
|
||||
await enumerator.MoveNextAsync();
|
||||
|
||||
result.ContinuationToken = enumerator.Current.ContinuationToken;
|
||||
result.Data.AddRange(enumerator.Current.Values.Select(e => e.ToEventTableEntity()));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task CreateEventAsync(EventTableEntity entity)
|
||||
{
|
||||
await _tableClient.UpsertEntityAsync(entity.ToAzureEvent());
|
||||
}
|
||||
|
||||
private string MakeFilter(string partitionKey, string rowStart, string rowEnd)
|
||||
{
|
||||
return $"PartitionKey eq '{partitionKey}' and RowKey le '{rowStart}' and RowKey ge '{rowEnd}'";
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user