mirror of
https://github.com/bitwarden/server.git
synced 2024-11-25 12:45:18 +01:00
app cache with org ability checks on events
This commit is contained in:
parent
d75ca51d75
commit
e9116f8c44
21
src/Core/Models/Data/OrganizationAbility.cs
Normal file
21
src/Core/Models/Data/OrganizationAbility.cs
Normal 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; }
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Models.Table;
|
||||
|
||||
namespace Bit.Core.Repositories
|
||||
@ -10,5 +11,6 @@ namespace Bit.Core.Repositories
|
||||
Task<ICollection<Organization>> GetManyByEnabledAsync();
|
||||
Task<ICollection<Organization>> GetManyByUserIdAsync(Guid userId);
|
||||
Task UpdateStorageAsync(Guid id);
|
||||
Task<ICollection<OrganizationAbility>> GetManyAbilitiesAsync();
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ using System.Data;
|
||||
using Dapper;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Bit.Core.Models.Data;
|
||||
|
||||
namespace Bit.Core.Repositories.SqlServer
|
||||
{
|
||||
@ -55,5 +56,17 @@ namespace Bit.Core.Repositories.SqlServer
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
15
src/Core/Services/IApplicationCacheService.cs
Normal file
15
src/Core/Services/IApplicationCacheService.cs
Normal 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);
|
||||
}
|
||||
}
|
@ -13,17 +13,20 @@ namespace Bit.Core.Services
|
||||
{
|
||||
private readonly IEventWriteService _eventWriteService;
|
||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||
private readonly IApplicationCacheService _applicationCacheService;
|
||||
private readonly CurrentContext _currentContext;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
|
||||
public EventService(
|
||||
IEventWriteService eventWriteService,
|
||||
IOrganizationUserRepository organizationUserRepository,
|
||||
IApplicationCacheService applicationCacheService,
|
||||
CurrentContext currentContext,
|
||||
GlobalSettings globalSettings)
|
||||
{
|
||||
_eventWriteService = eventWriteService;
|
||||
_organizationUserRepository = organizationUserRepository;
|
||||
_applicationCacheService = applicationCacheService;
|
||||
_currentContext = currentContext;
|
||||
_globalSettings = globalSettings;
|
||||
}
|
||||
@ -42,22 +45,26 @@ namespace Bit.Core.Services
|
||||
}
|
||||
};
|
||||
|
||||
var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
|
||||
IEnumerable<IEvent> orgEvents;
|
||||
if(_currentContext.UserId.HasValue)
|
||||
{
|
||||
orgEvents = _currentContext.Organizations.Select(o => new EventMessage(_currentContext)
|
||||
{
|
||||
OrganizationId = o.Id,
|
||||
UserId = userId,
|
||||
ActingUserId = userId,
|
||||
Type = type,
|
||||
Date = DateTime.UtcNow
|
||||
});
|
||||
orgEvents = _currentContext.Organizations
|
||||
.Where(o => CanUseEvents(orgAbilities, o.Id))
|
||||
.Select(o => new EventMessage(_currentContext)
|
||||
{
|
||||
OrganizationId = o.Id,
|
||||
UserId = userId,
|
||||
ActingUserId = userId,
|
||||
Type = type,
|
||||
Date = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
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)
|
||||
{
|
||||
OrganizationId = o.OrganizationId,
|
||||
@ -87,6 +94,15 @@ namespace Bit.Core.Services
|
||||
return;
|
||||
}
|
||||
|
||||
if(cipher.OrganizationId.HasValue)
|
||||
{
|
||||
var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
|
||||
if(!CanUseEvents(orgAbilities, cipher.OrganizationId.Value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var e = new EventMessage(_currentContext)
|
||||
{
|
||||
OrganizationId = cipher.OrganizationId,
|
||||
@ -101,6 +117,12 @@ namespace Bit.Core.Services
|
||||
|
||||
public async Task LogCollectionEventAsync(Collection collection, EventType type)
|
||||
{
|
||||
var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
|
||||
if(!CanUseEvents(orgAbilities, collection.OrganizationId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var e = new EventMessage(_currentContext)
|
||||
{
|
||||
OrganizationId = collection.OrganizationId,
|
||||
@ -114,6 +136,12 @@ namespace Bit.Core.Services
|
||||
|
||||
public async Task LogGroupEventAsync(Group group, EventType type)
|
||||
{
|
||||
var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
|
||||
if(!CanUseEvents(orgAbilities, group.OrganizationId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var e = new EventMessage(_currentContext)
|
||||
{
|
||||
OrganizationId = group.OrganizationId,
|
||||
@ -127,6 +155,12 @@ namespace Bit.Core.Services
|
||||
|
||||
public async Task LogOrganizationUserEventAsync(OrganizationUser organizationUser, EventType type)
|
||||
{
|
||||
var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
|
||||
if(!CanUseEvents(orgAbilities, organizationUser.OrganizationId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var e = new EventMessage(_currentContext)
|
||||
{
|
||||
OrganizationId = organizationUser.OrganizationId,
|
||||
@ -141,6 +175,11 @@ namespace Bit.Core.Services
|
||||
|
||||
public async Task LogOrganizationEventAsync(Organization organization, EventType type)
|
||||
{
|
||||
if(!organization.Enabled || !organization.UseEvents)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var e = new EventMessage(_currentContext)
|
||||
{
|
||||
OrganizationId = organization.Id,
|
||||
@ -150,5 +189,11 @@ namespace Bit.Core.Services
|
||||
};
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -31,6 +31,7 @@ namespace Bit.Core.Services
|
||||
private readonly ILicensingService _licensingService;
|
||||
private readonly IEventService _eventService;
|
||||
private readonly IInstallationRepository _installationRepository;
|
||||
private readonly IApplicationCacheService _applicationCacheService;
|
||||
private readonly StripePaymentService _stripePaymentService;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
|
||||
@ -48,6 +49,7 @@ namespace Bit.Core.Services
|
||||
ILicensingService licensingService,
|
||||
IEventService eventService,
|
||||
IInstallationRepository installationRepository,
|
||||
IApplicationCacheService applicationCacheService,
|
||||
GlobalSettings globalSettings)
|
||||
{
|
||||
_organizationRepository = organizationRepository;
|
||||
@ -63,13 +65,14 @@ namespace Bit.Core.Services
|
||||
_licensingService = licensingService;
|
||||
_eventService = eventService;
|
||||
_installationRepository = installationRepository;
|
||||
_applicationCacheService = applicationCacheService;
|
||||
_stripePaymentService = new StripePaymentService();
|
||||
_globalSettings = globalSettings;
|
||||
}
|
||||
|
||||
public async Task ReplacePaymentMethodAsync(Guid organizationId, string paymentToken)
|
||||
{
|
||||
var organization = await _organizationRepository.GetByIdAsync(organizationId);
|
||||
var organization = await GetOrgById(organizationId);
|
||||
if(organization == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
@ -78,13 +81,13 @@ namespace Bit.Core.Services
|
||||
var updated = await _stripePaymentService.UpdatePaymentMethodAsync(organization, paymentToken);
|
||||
if(updated)
|
||||
{
|
||||
await _organizationRepository.ReplaceAsync(organization);
|
||||
await ReplaceAndUpdateCache(organization);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CancelSubscriptionAsync(Guid organizationId, bool endOfPeriod = false)
|
||||
{
|
||||
var organization = await _organizationRepository.GetByIdAsync(organizationId);
|
||||
var organization = await GetOrgById(organizationId);
|
||||
if(organization == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
@ -95,7 +98,7 @@ namespace Bit.Core.Services
|
||||
|
||||
public async Task ReinstateSubscriptionAsync(Guid organizationId)
|
||||
{
|
||||
var organization = await _organizationRepository.GetByIdAsync(organizationId);
|
||||
var organization = await GetOrgById(organizationId);
|
||||
if(organization == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
@ -106,7 +109,7 @@ namespace Bit.Core.Services
|
||||
|
||||
public async Task UpgradePlanAsync(Guid organizationId, PlanType plan, int additionalSeats)
|
||||
{
|
||||
var organization = await _organizationRepository.GetByIdAsync(organizationId);
|
||||
var organization = await GetOrgById(organizationId);
|
||||
if(organization == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
@ -243,7 +246,7 @@ namespace Bit.Core.Services
|
||||
|
||||
public async Task AdjustStorageAsync(Guid organizationId, short storageAdjustmentGb)
|
||||
{
|
||||
var organization = await _organizationRepository.GetByIdAsync(organizationId);
|
||||
var organization = await GetOrgById(organizationId);
|
||||
if(organization == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
@ -262,12 +265,12 @@ namespace Bit.Core.Services
|
||||
|
||||
await BillingHelpers.AdjustStorageAsync(_stripePaymentService, organization, storageAdjustmentGb,
|
||||
plan.StripStoragePlanId);
|
||||
await _organizationRepository.ReplaceAsync(organization);
|
||||
await ReplaceAndUpdateCache(organization);
|
||||
}
|
||||
|
||||
public async Task AdjustSeatsAsync(Guid organizationId, int seatAdjustment)
|
||||
{
|
||||
var organization = await _organizationRepository.GetByIdAsync(organizationId);
|
||||
var organization = await GetOrgById(organizationId);
|
||||
if(organization == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
@ -361,12 +364,12 @@ namespace Bit.Core.Services
|
||||
}
|
||||
|
||||
organization.Seats = (short?)newSeatTotal;
|
||||
await _organizationRepository.ReplaceAsync(organization);
|
||||
await ReplaceAndUpdateCache(organization);
|
||||
}
|
||||
|
||||
public async Task VerifyBankAsync(Guid organizationId, int amount1, int amount2)
|
||||
{
|
||||
var organization = await _organizationRepository.GetByIdAsync(organizationId);
|
||||
var organization = await GetOrgById(organizationId);
|
||||
if(organization == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
@ -622,6 +625,7 @@ namespace Bit.Core.Services
|
||||
try
|
||||
{
|
||||
await _organizationRepository.CreateAsync(organization);
|
||||
await _applicationCacheService.UpsertOrganizationAbilityAsync(organization);
|
||||
|
||||
var orgUser = new OrganizationUser
|
||||
{
|
||||
@ -666,6 +670,7 @@ namespace Bit.Core.Services
|
||||
if(organization.Id != default(Guid))
|
||||
{
|
||||
await _organizationRepository.DeleteAsync(organization);
|
||||
await _applicationCacheService.DeleteOrganizationAbilityAsync(organization.Id);
|
||||
}
|
||||
|
||||
throw;
|
||||
@ -674,7 +679,7 @@ namespace Bit.Core.Services
|
||||
|
||||
public async Task UpdateLicenseAsync(Guid organizationId, OrganizationLicense license)
|
||||
{
|
||||
var organization = await _organizationRepository.GetByIdAsync(organizationId);
|
||||
var organization = await GetOrgById(organizationId);
|
||||
if(organization == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
@ -753,7 +758,7 @@ namespace Bit.Core.Services
|
||||
organization.ExpirationDate = license.Expires;
|
||||
organization.LicenseKey = license.LicenseKey;
|
||||
organization.RevisionDate = DateTime.UtcNow;
|
||||
await _organizationRepository.ReplaceAsync(organization);
|
||||
await ReplaceAndUpdateCache(organization);
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(Organization organization)
|
||||
@ -764,17 +769,18 @@ namespace Bit.Core.Services
|
||||
}
|
||||
|
||||
await _organizationRepository.DeleteAsync(organization);
|
||||
await _applicationCacheService.DeleteOrganizationAbilityAsync(organization.Id);
|
||||
}
|
||||
|
||||
public async Task DisableAsync(Guid organizationId, DateTime? expirationDate)
|
||||
{
|
||||
var org = await _organizationRepository.GetByIdAsync(organizationId);
|
||||
var org = await GetOrgById(organizationId);
|
||||
if(org != null && org.Enabled)
|
||||
{
|
||||
org.Enabled = false;
|
||||
org.ExpirationDate = expirationDate;
|
||||
org.RevisionDate = DateTime.UtcNow;
|
||||
await _organizationRepository.ReplaceAsync(org);
|
||||
await ReplaceAndUpdateCache(org);
|
||||
|
||||
// TODO: send email to owners?
|
||||
}
|
||||
@ -782,22 +788,22 @@ namespace Bit.Core.Services
|
||||
|
||||
public async Task UpdateExpirationDateAsync(Guid organizationId, DateTime? expirationDate)
|
||||
{
|
||||
var org = await _organizationRepository.GetByIdAsync(organizationId);
|
||||
var org = await GetOrgById(organizationId);
|
||||
if(org != null)
|
||||
{
|
||||
org.ExpirationDate = expirationDate;
|
||||
org.RevisionDate = DateTime.UtcNow;
|
||||
await _organizationRepository.ReplaceAsync(org);
|
||||
await ReplaceAndUpdateCache(org);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task EnableAsync(Guid organizationId)
|
||||
{
|
||||
var org = await _organizationRepository.GetByIdAsync(organizationId);
|
||||
var org = await GetOrgById(organizationId);
|
||||
if(org != null && !org.Enabled)
|
||||
{
|
||||
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.");
|
||||
}
|
||||
|
||||
await _organizationRepository.ReplaceAsync(organization);
|
||||
await _eventService.LogOrganizationEventAsync(organization, EventType.Organization_Updated);
|
||||
await ReplaceAndUpdateCache(organization, EventType.Organization_Updated);
|
||||
|
||||
if(updateBilling && !string.IsNullOrWhiteSpace(organization.GatewayCustomerId))
|
||||
{
|
||||
@ -834,7 +839,7 @@ namespace Bit.Core.Services
|
||||
IEnumerable<string> emails, OrganizationUserType type, bool accessAll, string externalId,
|
||||
IEnumerable<SelectionReadOnly> collections)
|
||||
{
|
||||
var organization = await _organizationRepository.GetByIdAsync(organizationId);
|
||||
var organization = await GetOrgById(organizationId);
|
||||
if(organization == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
@ -915,7 +920,7 @@ namespace Bit.Core.Services
|
||||
|
||||
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 token = _dataProtector.Protect(
|
||||
$"OrganizationUserInvite {orgUser.Id} {orgUser.Email} {nowMillis}");
|
||||
@ -937,7 +942,7 @@ namespace Bit.Core.Services
|
||||
|
||||
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)
|
||||
{
|
||||
var adminCount = await _organizationUserRepository.GetCountByFreeOrganizationAdminUserAsync(user.Id);
|
||||
@ -999,7 +1004,7 @@ namespace Bit.Core.Services
|
||||
throw new BadRequestException("User not valid.");
|
||||
}
|
||||
|
||||
var org = await _organizationRepository.GetByIdAsync(organizationId);
|
||||
var org = await GetOrgById(organizationId);
|
||||
if(org.PlanType == PlanType.Free &&
|
||||
(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)
|
||||
{
|
||||
var organization = await _organizationRepository.GetByIdAsync(organizationId);
|
||||
var organization = await GetOrgById(organizationId);
|
||||
return await GenerateLicenseAsync(organization, installationId);
|
||||
}
|
||||
|
||||
@ -1168,7 +1173,7 @@ namespace Bit.Core.Services
|
||||
IEnumerable<ImportedOrganizationUser> newUsers,
|
||||
IEnumerable<string> removeUserExternalIds)
|
||||
{
|
||||
var organization = await _organizationRepository.GetByIdAsync(organizationId);
|
||||
var organization = await GetOrgById(organizationId);
|
||||
if(organization == null)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
@ -1340,5 +1345,21 @@ namespace Bit.Core.Services
|
||||
var devices = await _deviceRepository.GetManyByUserIdAsync(userId);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,6 +67,7 @@ namespace Bit.Core.Utilities
|
||||
{
|
||||
services.AddSingleton<IMailService, BackupMailService>();
|
||||
services.AddSingleton<ILicensingService, LicensingService>();
|
||||
services.AddSingleton<IApplicationCacheService, InMemoryApplicationCacheService>();
|
||||
|
||||
if(CoreHelpers.SettingHasValue(globalSettings.Mail.SendGridApiKey))
|
||||
{
|
||||
|
@ -223,5 +223,6 @@
|
||||
<Build Include="dbo\Stored Procedures\Event_ReadPageByOrganizationId.sql" />
|
||||
<Build Include="dbo\Stored Procedures\Event_ReadPageByCipherId.sql" />
|
||||
<Build Include="dbo\Stored Procedures\Event_ReadPageByOrganizationIdActingUserId.sql" />
|
||||
<Build Include="dbo\Stored Procedures\Organization_ReadAbilities.sql" />
|
||||
</ItemGroup>
|
||||
</Project>
|
12
src/Sql/dbo/Stored Procedures/Organization_ReadAbilities.sql
Normal file
12
src/Sql/dbo/Stored Procedures/Organization_ReadAbilities.sql
Normal file
@ -0,0 +1,12 @@
|
||||
CREATE PROCEDURE [dbo].[Organization_ReadAbilities]
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
SELECT
|
||||
[Id],
|
||||
[UseEvents],
|
||||
[Enabled]
|
||||
FROM
|
||||
[dbo].[Organization]
|
||||
END
|
@ -202,6 +202,26 @@ BEGIN
|
||||
END
|
||||
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')
|
||||
BEGIN
|
||||
DROP VIEW [dbo].[OrganizationView]
|
||||
|
Loading…
Reference in New Issue
Block a user