1
0
mirror of https://github.com/bitwarden/server.git synced 2025-04-08 14:38:15 -05:00

app cache with org ability checks on events

This commit is contained in:
Kyle Spearrin 2017-12-19 16:02:39 -05:00
parent d75ca51d75
commit e9116f8c44
11 changed files with 252 additions and 35 deletions

View File

@ -0,0 +1,21 @@
using System;
using Bit.Core.Models.Table;
namespace Bit.Core.Models.Data
{
public class OrganizationAbility
{
public OrganizationAbility() { }
public OrganizationAbility(Organization organization)
{
Id = organization.Id;
UseEvents = organization.UseEvents;
Enabled = organization.Enabled;
}
public Guid Id { get; set; }
public bool UseEvents { get; set; }
public bool Enabled { get; set; }
}
}

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Bit.Core.Models.Data;
using Bit.Core.Models.Table; using Bit.Core.Models.Table;
namespace Bit.Core.Repositories namespace Bit.Core.Repositories
@ -10,5 +11,6 @@ namespace Bit.Core.Repositories
Task<ICollection<Organization>> GetManyByEnabledAsync(); Task<ICollection<Organization>> GetManyByEnabledAsync();
Task<ICollection<Organization>> GetManyByUserIdAsync(Guid userId); Task<ICollection<Organization>> GetManyByUserIdAsync(Guid userId);
Task UpdateStorageAsync(Guid id); Task UpdateStorageAsync(Guid id);
Task<ICollection<OrganizationAbility>> GetManyAbilitiesAsync();
} }
} }

View File

@ -6,6 +6,7 @@ using System.Data;
using Dapper; using Dapper;
using System.Linq; using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using Bit.Core.Models.Data;
namespace Bit.Core.Repositories.SqlServer namespace Bit.Core.Repositories.SqlServer
{ {
@ -55,5 +56,17 @@ namespace Bit.Core.Repositories.SqlServer
commandTimeout: 180); commandTimeout: 180);
} }
} }
public async Task<ICollection<OrganizationAbility>> GetManyAbilitiesAsync()
{
using(var connection = new SqlConnection(ConnectionString))
{
var results = await connection.QueryAsync<OrganizationAbility>(
"[dbo].[Organization_ReadAbilities]",
commandType: CommandType.StoredProcedure);
return results.ToList();
}
}
} }
} }

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.Core.Models.Data;
using Bit.Core.Models.Table;
namespace Bit.Core.Services
{
public interface IApplicationCacheService
{
Task<IDictionary<Guid, OrganizationAbility>> GetOrganizationAbilitiesAsync();
Task UpsertOrganizationAbilityAsync(Organization organization);
Task DeleteOrganizationAbilityAsync(Guid organizationId);
}
}

View File

@ -13,17 +13,20 @@ namespace Bit.Core.Services
{ {
private readonly IEventWriteService _eventWriteService; private readonly IEventWriteService _eventWriteService;
private readonly IOrganizationUserRepository _organizationUserRepository; private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly IApplicationCacheService _applicationCacheService;
private readonly CurrentContext _currentContext; private readonly CurrentContext _currentContext;
private readonly GlobalSettings _globalSettings; private readonly GlobalSettings _globalSettings;
public EventService( public EventService(
IEventWriteService eventWriteService, IEventWriteService eventWriteService,
IOrganizationUserRepository organizationUserRepository, IOrganizationUserRepository organizationUserRepository,
IApplicationCacheService applicationCacheService,
CurrentContext currentContext, CurrentContext currentContext,
GlobalSettings globalSettings) GlobalSettings globalSettings)
{ {
_eventWriteService = eventWriteService; _eventWriteService = eventWriteService;
_organizationUserRepository = organizationUserRepository; _organizationUserRepository = organizationUserRepository;
_applicationCacheService = applicationCacheService;
_currentContext = currentContext; _currentContext = currentContext;
_globalSettings = globalSettings; _globalSettings = globalSettings;
} }
@ -42,22 +45,26 @@ namespace Bit.Core.Services
} }
}; };
var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
IEnumerable<IEvent> orgEvents; IEnumerable<IEvent> orgEvents;
if(_currentContext.UserId.HasValue) if(_currentContext.UserId.HasValue)
{ {
orgEvents = _currentContext.Organizations.Select(o => new EventMessage(_currentContext) orgEvents = _currentContext.Organizations
{ .Where(o => CanUseEvents(orgAbilities, o.Id))
OrganizationId = o.Id, .Select(o => new EventMessage(_currentContext)
UserId = userId, {
ActingUserId = userId, OrganizationId = o.Id,
Type = type, UserId = userId,
Date = DateTime.UtcNow ActingUserId = userId,
}); Type = type,
Date = DateTime.UtcNow
});
} }
else else
{ {
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 && CanUseEvents(orgAbilities, o.Id))
.Select(o => new EventMessage(_currentContext) .Select(o => new EventMessage(_currentContext)
{ {
OrganizationId = o.OrganizationId, OrganizationId = o.OrganizationId,
@ -87,6 +94,15 @@ namespace Bit.Core.Services
return; return;
} }
if(cipher.OrganizationId.HasValue)
{
var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
if(!CanUseEvents(orgAbilities, cipher.OrganizationId.Value))
{
return;
}
}
var e = new EventMessage(_currentContext) var e = new EventMessage(_currentContext)
{ {
OrganizationId = cipher.OrganizationId, OrganizationId = cipher.OrganizationId,
@ -101,6 +117,12 @@ namespace Bit.Core.Services
public async Task LogCollectionEventAsync(Collection collection, EventType type) public async Task LogCollectionEventAsync(Collection collection, EventType type)
{ {
var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
if(!CanUseEvents(orgAbilities, collection.OrganizationId))
{
return;
}
var e = new EventMessage(_currentContext) var e = new EventMessage(_currentContext)
{ {
OrganizationId = collection.OrganizationId, OrganizationId = collection.OrganizationId,
@ -114,6 +136,12 @@ namespace Bit.Core.Services
public async Task LogGroupEventAsync(Group group, EventType type) public async Task LogGroupEventAsync(Group group, EventType type)
{ {
var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
if(!CanUseEvents(orgAbilities, group.OrganizationId))
{
return;
}
var e = new EventMessage(_currentContext) var e = new EventMessage(_currentContext)
{ {
OrganizationId = group.OrganizationId, OrganizationId = group.OrganizationId,
@ -127,6 +155,12 @@ namespace Bit.Core.Services
public async Task LogOrganizationUserEventAsync(OrganizationUser organizationUser, EventType type) public async Task LogOrganizationUserEventAsync(OrganizationUser organizationUser, EventType type)
{ {
var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
if(!CanUseEvents(orgAbilities, organizationUser.OrganizationId))
{
return;
}
var e = new EventMessage(_currentContext) var e = new EventMessage(_currentContext)
{ {
OrganizationId = organizationUser.OrganizationId, OrganizationId = organizationUser.OrganizationId,
@ -141,6 +175,11 @@ namespace Bit.Core.Services
public async Task LogOrganizationEventAsync(Organization organization, EventType type) public async Task LogOrganizationEventAsync(Organization organization, EventType type)
{ {
if(!organization.Enabled || !organization.UseEvents)
{
return;
}
var e = new EventMessage(_currentContext) var e = new EventMessage(_currentContext)
{ {
OrganizationId = organization.Id, OrganizationId = organization.Id,
@ -150,5 +189,11 @@ namespace Bit.Core.Services
}; };
await _eventWriteService.CreateAsync(e); await _eventWriteService.CreateAsync(e);
} }
private bool CanUseEvents(IDictionary<Guid, OrganizationAbility> orgAbilities, Guid orgId)
{
return orgAbilities != null && orgAbilities.ContainsKey(orgId) &&
orgAbilities[orgId].Enabled && orgAbilities[orgId].UseEvents;
}
} }
} }

View File

@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Bit.Core.Models.Data;
using Bit.Core.Models.Table;
using Bit.Core.Repositories;
namespace Bit.Core.Services
{
public class InMemoryApplicationCacheService : IApplicationCacheService
{
private readonly IOrganizationRepository _organizationRepository;
private DateTime _lastOrgAbilityRefresh = DateTime.MinValue;
private IDictionary<Guid, OrganizationAbility> _orgAbilities;
private TimeSpan _orgAbilitiesRefreshInterval = TimeSpan.FromMinutes(10);
public InMemoryApplicationCacheService(
IOrganizationRepository organizationRepository)
{
_organizationRepository = organizationRepository;
}
public async Task<IDictionary<Guid, OrganizationAbility>> GetOrganizationAbilitiesAsync()
{
await InitOrganizationAbilitiesAsync();
return _orgAbilities;
}
public async Task UpsertOrganizationAbilityAsync(Organization organization)
{
await InitOrganizationAbilitiesAsync();
var newAbility = new OrganizationAbility(organization);
if(_orgAbilities.ContainsKey(organization.Id))
{
_orgAbilities[organization.Id] = newAbility;
}
else
{
_orgAbilities.Add(organization.Id, newAbility);
}
}
public Task DeleteOrganizationAbilityAsync(Guid organizationId)
{
if(_orgAbilities != null && _orgAbilities.ContainsKey(organizationId))
{
_orgAbilities.Remove(organizationId);
}
return Task.FromResult(0);
}
private async Task InitOrganizationAbilitiesAsync()
{
var now = DateTime.UtcNow;
if(_orgAbilities == null || (now - _lastOrgAbilityRefresh) > _orgAbilitiesRefreshInterval)
{
var abilities = await _organizationRepository.GetManyAbilitiesAsync();
_orgAbilities = abilities.ToDictionary(a => a.Id);
_lastOrgAbilityRefresh = now;
}
}
}
}

View File

@ -31,6 +31,7 @@ namespace Bit.Core.Services
private readonly ILicensingService _licensingService; private readonly ILicensingService _licensingService;
private readonly IEventService _eventService; private readonly IEventService _eventService;
private readonly IInstallationRepository _installationRepository; private readonly IInstallationRepository _installationRepository;
private readonly IApplicationCacheService _applicationCacheService;
private readonly StripePaymentService _stripePaymentService; private readonly StripePaymentService _stripePaymentService;
private readonly GlobalSettings _globalSettings; private readonly GlobalSettings _globalSettings;
@ -48,6 +49,7 @@ namespace Bit.Core.Services
ILicensingService licensingService, ILicensingService licensingService,
IEventService eventService, IEventService eventService,
IInstallationRepository installationRepository, IInstallationRepository installationRepository,
IApplicationCacheService applicationCacheService,
GlobalSettings globalSettings) GlobalSettings globalSettings)
{ {
_organizationRepository = organizationRepository; _organizationRepository = organizationRepository;
@ -63,13 +65,14 @@ namespace Bit.Core.Services
_licensingService = licensingService; _licensingService = licensingService;
_eventService = eventService; _eventService = eventService;
_installationRepository = installationRepository; _installationRepository = installationRepository;
_applicationCacheService = applicationCacheService;
_stripePaymentService = new StripePaymentService(); _stripePaymentService = new StripePaymentService();
_globalSettings = globalSettings; _globalSettings = globalSettings;
} }
public async Task ReplacePaymentMethodAsync(Guid organizationId, string paymentToken) public async Task ReplacePaymentMethodAsync(Guid organizationId, string paymentToken)
{ {
var organization = await _organizationRepository.GetByIdAsync(organizationId); var organization = await GetOrgById(organizationId);
if(organization == null) if(organization == null)
{ {
throw new NotFoundException(); throw new NotFoundException();
@ -78,13 +81,13 @@ namespace Bit.Core.Services
var updated = await _stripePaymentService.UpdatePaymentMethodAsync(organization, paymentToken); var updated = await _stripePaymentService.UpdatePaymentMethodAsync(organization, paymentToken);
if(updated) if(updated)
{ {
await _organizationRepository.ReplaceAsync(organization); await ReplaceAndUpdateCache(organization);
} }
} }
public async Task CancelSubscriptionAsync(Guid organizationId, bool endOfPeriod = false) public async Task CancelSubscriptionAsync(Guid organizationId, bool endOfPeriod = false)
{ {
var organization = await _organizationRepository.GetByIdAsync(organizationId); var organization = await GetOrgById(organizationId);
if(organization == null) if(organization == null)
{ {
throw new NotFoundException(); throw new NotFoundException();
@ -95,7 +98,7 @@ namespace Bit.Core.Services
public async Task ReinstateSubscriptionAsync(Guid organizationId) public async Task ReinstateSubscriptionAsync(Guid organizationId)
{ {
var organization = await _organizationRepository.GetByIdAsync(organizationId); var organization = await GetOrgById(organizationId);
if(organization == null) if(organization == null)
{ {
throw new NotFoundException(); throw new NotFoundException();
@ -106,7 +109,7 @@ namespace Bit.Core.Services
public async Task UpgradePlanAsync(Guid organizationId, PlanType plan, int additionalSeats) public async Task UpgradePlanAsync(Guid organizationId, PlanType plan, int additionalSeats)
{ {
var organization = await _organizationRepository.GetByIdAsync(organizationId); var organization = await GetOrgById(organizationId);
if(organization == null) if(organization == null)
{ {
throw new NotFoundException(); throw new NotFoundException();
@ -243,7 +246,7 @@ namespace Bit.Core.Services
public async Task AdjustStorageAsync(Guid organizationId, short storageAdjustmentGb) public async Task AdjustStorageAsync(Guid organizationId, short storageAdjustmentGb)
{ {
var organization = await _organizationRepository.GetByIdAsync(organizationId); var organization = await GetOrgById(organizationId);
if(organization == null) if(organization == null)
{ {
throw new NotFoundException(); throw new NotFoundException();
@ -262,12 +265,12 @@ namespace Bit.Core.Services
await BillingHelpers.AdjustStorageAsync(_stripePaymentService, organization, storageAdjustmentGb, await BillingHelpers.AdjustStorageAsync(_stripePaymentService, organization, storageAdjustmentGb,
plan.StripStoragePlanId); plan.StripStoragePlanId);
await _organizationRepository.ReplaceAsync(organization); await ReplaceAndUpdateCache(organization);
} }
public async Task AdjustSeatsAsync(Guid organizationId, int seatAdjustment) public async Task AdjustSeatsAsync(Guid organizationId, int seatAdjustment)
{ {
var organization = await _organizationRepository.GetByIdAsync(organizationId); var organization = await GetOrgById(organizationId);
if(organization == null) if(organization == null)
{ {
throw new NotFoundException(); throw new NotFoundException();
@ -361,12 +364,12 @@ namespace Bit.Core.Services
} }
organization.Seats = (short?)newSeatTotal; organization.Seats = (short?)newSeatTotal;
await _organizationRepository.ReplaceAsync(organization); await ReplaceAndUpdateCache(organization);
} }
public async Task VerifyBankAsync(Guid organizationId, int amount1, int amount2) public async Task VerifyBankAsync(Guid organizationId, int amount1, int amount2)
{ {
var organization = await _organizationRepository.GetByIdAsync(organizationId); var organization = await GetOrgById(organizationId);
if(organization == null) if(organization == null)
{ {
throw new NotFoundException(); throw new NotFoundException();
@ -622,6 +625,7 @@ namespace Bit.Core.Services
try try
{ {
await _organizationRepository.CreateAsync(organization); await _organizationRepository.CreateAsync(organization);
await _applicationCacheService.UpsertOrganizationAbilityAsync(organization);
var orgUser = new OrganizationUser var orgUser = new OrganizationUser
{ {
@ -666,6 +670,7 @@ namespace Bit.Core.Services
if(organization.Id != default(Guid)) if(organization.Id != default(Guid))
{ {
await _organizationRepository.DeleteAsync(organization); await _organizationRepository.DeleteAsync(organization);
await _applicationCacheService.DeleteOrganizationAbilityAsync(organization.Id);
} }
throw; throw;
@ -674,7 +679,7 @@ namespace Bit.Core.Services
public async Task UpdateLicenseAsync(Guid organizationId, OrganizationLicense license) public async Task UpdateLicenseAsync(Guid organizationId, OrganizationLicense license)
{ {
var organization = await _organizationRepository.GetByIdAsync(organizationId); var organization = await GetOrgById(organizationId);
if(organization == null) if(organization == null)
{ {
throw new NotFoundException(); throw new NotFoundException();
@ -753,7 +758,7 @@ namespace Bit.Core.Services
organization.ExpirationDate = license.Expires; organization.ExpirationDate = license.Expires;
organization.LicenseKey = license.LicenseKey; organization.LicenseKey = license.LicenseKey;
organization.RevisionDate = DateTime.UtcNow; organization.RevisionDate = DateTime.UtcNow;
await _organizationRepository.ReplaceAsync(organization); await ReplaceAndUpdateCache(organization);
} }
public async Task DeleteAsync(Organization organization) public async Task DeleteAsync(Organization organization)
@ -764,17 +769,18 @@ namespace Bit.Core.Services
} }
await _organizationRepository.DeleteAsync(organization); await _organizationRepository.DeleteAsync(organization);
await _applicationCacheService.DeleteOrganizationAbilityAsync(organization.Id);
} }
public async Task DisableAsync(Guid organizationId, DateTime? expirationDate) public async Task DisableAsync(Guid organizationId, DateTime? expirationDate)
{ {
var org = await _organizationRepository.GetByIdAsync(organizationId); var org = await GetOrgById(organizationId);
if(org != null && org.Enabled) if(org != null && org.Enabled)
{ {
org.Enabled = false; org.Enabled = false;
org.ExpirationDate = expirationDate; org.ExpirationDate = expirationDate;
org.RevisionDate = DateTime.UtcNow; org.RevisionDate = DateTime.UtcNow;
await _organizationRepository.ReplaceAsync(org); await ReplaceAndUpdateCache(org);
// TODO: send email to owners? // TODO: send email to owners?
} }
@ -782,22 +788,22 @@ namespace Bit.Core.Services
public async Task UpdateExpirationDateAsync(Guid organizationId, DateTime? expirationDate) public async Task UpdateExpirationDateAsync(Guid organizationId, DateTime? expirationDate)
{ {
var org = await _organizationRepository.GetByIdAsync(organizationId); var org = await GetOrgById(organizationId);
if(org != null) if(org != null)
{ {
org.ExpirationDate = expirationDate; org.ExpirationDate = expirationDate;
org.RevisionDate = DateTime.UtcNow; org.RevisionDate = DateTime.UtcNow;
await _organizationRepository.ReplaceAsync(org); await ReplaceAndUpdateCache(org);
} }
} }
public async Task EnableAsync(Guid organizationId) public async Task EnableAsync(Guid organizationId)
{ {
var org = await _organizationRepository.GetByIdAsync(organizationId); var org = await GetOrgById(organizationId);
if(org != null && !org.Enabled) if(org != null && !org.Enabled)
{ {
org.Enabled = true; org.Enabled = true;
await _organizationRepository.ReplaceAsync(org); await ReplaceAndUpdateCache(org);
} }
} }
@ -808,8 +814,7 @@ namespace Bit.Core.Services
throw new ApplicationException("Cannot create org this way. Call SignUpAsync."); throw new ApplicationException("Cannot create org this way. Call SignUpAsync.");
} }
await _organizationRepository.ReplaceAsync(organization); await ReplaceAndUpdateCache(organization, EventType.Organization_Updated);
await _eventService.LogOrganizationEventAsync(organization, EventType.Organization_Updated);
if(updateBilling && !string.IsNullOrWhiteSpace(organization.GatewayCustomerId)) if(updateBilling && !string.IsNullOrWhiteSpace(organization.GatewayCustomerId))
{ {
@ -834,7 +839,7 @@ namespace Bit.Core.Services
IEnumerable<string> emails, OrganizationUserType type, bool accessAll, string externalId, IEnumerable<string> emails, OrganizationUserType type, bool accessAll, string externalId,
IEnumerable<SelectionReadOnly> collections) IEnumerable<SelectionReadOnly> collections)
{ {
var organization = await _organizationRepository.GetByIdAsync(organizationId); var organization = await GetOrgById(organizationId);
if(organization == null) if(organization == null)
{ {
throw new NotFoundException(); throw new NotFoundException();
@ -915,7 +920,7 @@ namespace Bit.Core.Services
private async Task SendInviteAsync(OrganizationUser orgUser) private async Task SendInviteAsync(OrganizationUser orgUser)
{ {
var org = await _organizationRepository.GetByIdAsync(orgUser.OrganizationId); var org = await GetOrgById(orgUser.OrganizationId);
var nowMillis = CoreHelpers.ToEpocMilliseconds(DateTime.UtcNow); var nowMillis = CoreHelpers.ToEpocMilliseconds(DateTime.UtcNow);
var token = _dataProtector.Protect( var token = _dataProtector.Protect(
$"OrganizationUserInvite {orgUser.Id} {orgUser.Email} {nowMillis}"); $"OrganizationUserInvite {orgUser.Id} {orgUser.Email} {nowMillis}");
@ -937,7 +942,7 @@ namespace Bit.Core.Services
if(orgUser.Type == OrganizationUserType.Owner || orgUser.Type == OrganizationUserType.Admin) if(orgUser.Type == OrganizationUserType.Owner || orgUser.Type == OrganizationUserType.Admin)
{ {
var org = await _organizationRepository.GetByIdAsync(orgUser.OrganizationId); var org = await GetOrgById(orgUser.OrganizationId);
if(org.PlanType == PlanType.Free) if(org.PlanType == PlanType.Free)
{ {
var adminCount = await _organizationUserRepository.GetCountByFreeOrganizationAdminUserAsync(user.Id); var adminCount = await _organizationUserRepository.GetCountByFreeOrganizationAdminUserAsync(user.Id);
@ -999,7 +1004,7 @@ namespace Bit.Core.Services
throw new BadRequestException("User not valid."); throw new BadRequestException("User not valid.");
} }
var org = await _organizationRepository.GetByIdAsync(organizationId); var org = await GetOrgById(organizationId);
if(org.PlanType == PlanType.Free && if(org.PlanType == PlanType.Free &&
(orgUser.Type == OrganizationUserType.Admin || orgUser.Type == OrganizationUserType.Owner)) (orgUser.Type == OrganizationUserType.Admin || orgUser.Type == OrganizationUserType.Owner))
{ {
@ -1140,7 +1145,7 @@ namespace Bit.Core.Services
public async Task<OrganizationLicense> GenerateLicenseAsync(Guid organizationId, Guid installationId) public async Task<OrganizationLicense> GenerateLicenseAsync(Guid organizationId, Guid installationId)
{ {
var organization = await _organizationRepository.GetByIdAsync(organizationId); var organization = await GetOrgById(organizationId);
return await GenerateLicenseAsync(organization, installationId); return await GenerateLicenseAsync(organization, installationId);
} }
@ -1168,7 +1173,7 @@ namespace Bit.Core.Services
IEnumerable<ImportedOrganizationUser> newUsers, IEnumerable<ImportedOrganizationUser> newUsers,
IEnumerable<string> removeUserExternalIds) IEnumerable<string> removeUserExternalIds)
{ {
var organization = await _organizationRepository.GetByIdAsync(organizationId); var organization = await GetOrgById(organizationId);
if(organization == null) if(organization == null)
{ {
throw new NotFoundException(); throw new NotFoundException();
@ -1340,5 +1345,21 @@ namespace Bit.Core.Services
var devices = await _deviceRepository.GetManyByUserIdAsync(userId); var devices = await _deviceRepository.GetManyByUserIdAsync(userId);
return devices.Where(d => !string.IsNullOrWhiteSpace(d.PushToken)).Select(d => d.Id.ToString()); return devices.Where(d => !string.IsNullOrWhiteSpace(d.PushToken)).Select(d => d.Id.ToString());
} }
private async Task ReplaceAndUpdateCache(Organization org, EventType? orgEvent = null)
{
await _organizationRepository.ReplaceAsync(org);
await _applicationCacheService.UpsertOrganizationAbilityAsync(org);
if(orgEvent.HasValue)
{
await _eventService.LogOrganizationEventAsync(org, orgEvent.Value);
}
}
private async Task<Organization> GetOrgById(Guid id)
{
return await _organizationRepository.GetByIdAsync(id);
}
} }
} }

View File

@ -67,6 +67,7 @@ namespace Bit.Core.Utilities
{ {
services.AddSingleton<IMailService, BackupMailService>(); services.AddSingleton<IMailService, BackupMailService>();
services.AddSingleton<ILicensingService, LicensingService>(); services.AddSingleton<ILicensingService, LicensingService>();
services.AddSingleton<IApplicationCacheService, InMemoryApplicationCacheService>();
if(CoreHelpers.SettingHasValue(globalSettings.Mail.SendGridApiKey)) if(CoreHelpers.SettingHasValue(globalSettings.Mail.SendGridApiKey))
{ {

View File

@ -223,5 +223,6 @@
<Build Include="dbo\Stored Procedures\Event_ReadPageByOrganizationId.sql" /> <Build Include="dbo\Stored Procedures\Event_ReadPageByOrganizationId.sql" />
<Build Include="dbo\Stored Procedures\Event_ReadPageByCipherId.sql" /> <Build Include="dbo\Stored Procedures\Event_ReadPageByCipherId.sql" />
<Build Include="dbo\Stored Procedures\Event_ReadPageByOrganizationIdActingUserId.sql" /> <Build Include="dbo\Stored Procedures\Event_ReadPageByOrganizationIdActingUserId.sql" />
<Build Include="dbo\Stored Procedures\Organization_ReadAbilities.sql" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,12 @@
CREATE PROCEDURE [dbo].[Organization_ReadAbilities]
AS
BEGIN
SET NOCOUNT ON
SELECT
[Id],
[UseEvents],
[Enabled]
FROM
[dbo].[Organization]
END

View File

@ -202,6 +202,26 @@ BEGIN
END END
GO GO
IF OBJECT_ID('[dbo].[Organization_ReadAbilities]') IS NULL
BEGIN
EXEC('CREATE PROCEDURE [dbo].[Organization_ReadAbilities] AS BEGIN SET NOCOUNT ON; END')
END
GO
ALTER PROCEDURE [dbo].[Organization_ReadAbilities]
AS
BEGIN
SET NOCOUNT ON
SELECT
[Id],
[UseEvents],
[Enabled]
FROM
[dbo].[Organization]
END
GO
IF EXISTS(SELECT * FROM sys.views WHERE [Name] = 'OrganizationView') IF EXISTS(SELECT * FROM sys.views WHERE [Name] = 'OrganizationView')
BEGIN BEGIN
DROP VIEW [dbo].[OrganizationView] DROP VIEW [dbo].[OrganizationView]