mirror of
https://github.com/bitwarden/server.git
synced 2025-04-07 05:58:13 -05:00
Reference event service implementation (#811)
* Reference event service implementation * Fix IReferenceable implementation of Id * add structure to event body
This commit is contained in:
parent
b4524fbcb6
commit
7af50172e0
12
src/Core/Enums/ReferenceEventSource.cs
Normal file
12
src/Core/Enums/ReferenceEventSource.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
namespace Bit.Core.Enums
|
||||||
|
{
|
||||||
|
public enum ReferenceEventSource
|
||||||
|
{
|
||||||
|
[EnumMember(Value = "organization")]
|
||||||
|
Organization,
|
||||||
|
[EnumMember(Value = "user")]
|
||||||
|
User,
|
||||||
|
}
|
||||||
|
}
|
22
src/Core/Enums/ReferenceEventType.cs
Normal file
22
src/Core/Enums/ReferenceEventType.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
namespace Bit.Core.Enums
|
||||||
|
{
|
||||||
|
public enum ReferenceEventType
|
||||||
|
{
|
||||||
|
[EnumMember(Value = "signup")]
|
||||||
|
Signup,
|
||||||
|
[EnumMember(Value = "upgrade-plan")]
|
||||||
|
UpgradePlan,
|
||||||
|
[EnumMember(Value = "adjust-storage")]
|
||||||
|
AdjustStorage,
|
||||||
|
[EnumMember(Value = "adjust-seats")]
|
||||||
|
AdjustSeats,
|
||||||
|
[EnumMember(Value = "cancel-subscription")]
|
||||||
|
CancelSubscription,
|
||||||
|
[EnumMember(Value = "reinstate-subscription")]
|
||||||
|
ReinstateSubscription,
|
||||||
|
[EnumMember(Value = "delete-account")]
|
||||||
|
DeleteAccount,
|
||||||
|
}
|
||||||
|
}
|
47
src/Core/Models/Business/ReferenceEvent.cs
Normal file
47
src/Core/Models/Business/ReferenceEvent.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
using Bit.Core.Enums;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
using Newtonsoft.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Business
|
||||||
|
{
|
||||||
|
[JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))]
|
||||||
|
public class ReferenceEvent
|
||||||
|
{
|
||||||
|
public ReferenceEvent() { }
|
||||||
|
|
||||||
|
public ReferenceEvent(ReferenceEventType type, IReferenceable source)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
if (source != null)
|
||||||
|
{
|
||||||
|
Source = source.IsUser() ? ReferenceEventSource.User : ReferenceEventSource.Organization;
|
||||||
|
Id = source.Id;
|
||||||
|
ReferenceId = source.ReferenceId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
|
public ReferenceEventType Type { get; set; }
|
||||||
|
|
||||||
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
|
public ReferenceEventSource Source { get; set; }
|
||||||
|
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
|
public string ReferenceId { get; set; }
|
||||||
|
|
||||||
|
public DateTime EventDate { get; set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
|
public bool? EndOfPeriod { get; set; }
|
||||||
|
|
||||||
|
public string PlanName { get; set; }
|
||||||
|
|
||||||
|
public PlanType? PlanType { get; set; }
|
||||||
|
|
||||||
|
public short? Seats { get; set; }
|
||||||
|
|
||||||
|
public short? Storage { get; set; }
|
||||||
|
}
|
||||||
|
}
|
11
src/Core/Models/Table/IReferenceable.cs
Normal file
11
src/Core/Models/Table/IReferenceable.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models
|
||||||
|
{
|
||||||
|
public interface IReferenceable
|
||||||
|
{
|
||||||
|
Guid Id { get; set; }
|
||||||
|
string ReferenceId { get; set; }
|
||||||
|
bool IsUser();
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,7 @@ using System.Linq;
|
|||||||
|
|
||||||
namespace Bit.Core.Models.Table
|
namespace Bit.Core.Models.Table
|
||||||
{
|
{
|
||||||
public class Organization : ITableObject<Guid>, ISubscriber, IStorable, IStorableSubscriber, IRevisable
|
public class Organization : ITableObject<Guid>, ISubscriber, IStorable, IStorableSubscriber, IRevisable, IReferenceable
|
||||||
{
|
{
|
||||||
private Dictionary<TwoFactorProviderType, TwoFactorProvider> _twoFactorProviders;
|
private Dictionary<TwoFactorProviderType, TwoFactorProvider> _twoFactorProviders;
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ using Microsoft.AspNetCore.Identity;
|
|||||||
|
|
||||||
namespace Bit.Core.Models.Table
|
namespace Bit.Core.Models.Table
|
||||||
{
|
{
|
||||||
public class User : ITableObject<Guid>, ISubscriber, IStorable, IStorableSubscriber, IRevisable, ITwoFactorProvidersUser
|
public class User : ITableObject<Guid>, ISubscriber, IStorable, IStorableSubscriber, IRevisable, ITwoFactorProvidersUser, IReferenceable
|
||||||
{
|
{
|
||||||
private Dictionary<TwoFactorProviderType, TwoFactorProvider> _twoFactorProviders;
|
private Dictionary<TwoFactorProviderType, TwoFactorProvider> _twoFactorProviders;
|
||||||
|
|
||||||
|
10
src/Core/Services/IReferenceEventService.cs
Normal file
10
src/Core/Services/IReferenceEventService.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.Core.Models.Business;
|
||||||
|
|
||||||
|
namespace Bit.Core.Services
|
||||||
|
{
|
||||||
|
public interface IReferenceEventService
|
||||||
|
{
|
||||||
|
Task RaiseEventAsync(ReferenceEvent referenceEvent);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Azure.Storage.Queues;
|
||||||
|
using Bit.Core.Models.Business;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Bit.Core.Services
|
||||||
|
{
|
||||||
|
public class AzureQueueReferenceEventService : IReferenceEventService
|
||||||
|
{
|
||||||
|
private const string _queueName = "reference-events";
|
||||||
|
|
||||||
|
private readonly QueueClient _queueClient;
|
||||||
|
private readonly GlobalSettings _globalSettings;
|
||||||
|
private readonly JsonSerializerSettings _jsonSerializerSettings = new JsonSerializerSettings
|
||||||
|
{
|
||||||
|
NullValueHandling = NullValueHandling.Ignore,
|
||||||
|
};
|
||||||
|
|
||||||
|
public AzureQueueReferenceEventService (
|
||||||
|
GlobalSettings globalSettings)
|
||||||
|
{
|
||||||
|
_queueClient = new QueueClient(globalSettings.Storage.ConnectionString, _queueName);
|
||||||
|
_globalSettings = globalSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RaiseEventAsync(ReferenceEvent referenceEvent)
|
||||||
|
{
|
||||||
|
await SendMessageAsync(referenceEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SendMessageAsync(ReferenceEvent referenceEvent)
|
||||||
|
{
|
||||||
|
if (_globalSettings.SelfHosted || string.IsNullOrWhiteSpace(referenceEvent.ReferenceId))
|
||||||
|
{
|
||||||
|
// Ignore for self-hosted, OR, where there is no ReferenceId
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var message = JsonConvert.SerializeObject(referenceEvent, _jsonSerializerSettings);
|
||||||
|
await _queueClient.SendMessageAsync(message);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Ignore failure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -34,6 +34,7 @@ namespace Bit.Core.Services
|
|||||||
private readonly IApplicationCacheService _applicationCacheService;
|
private readonly IApplicationCacheService _applicationCacheService;
|
||||||
private readonly IPaymentService _paymentService;
|
private readonly IPaymentService _paymentService;
|
||||||
private readonly IPolicyRepository _policyRepository;
|
private readonly IPolicyRepository _policyRepository;
|
||||||
|
private readonly IReferenceEventService _referenceEventService;
|
||||||
private readonly GlobalSettings _globalSettings;
|
private readonly GlobalSettings _globalSettings;
|
||||||
|
|
||||||
public OrganizationService(
|
public OrganizationService(
|
||||||
@ -53,6 +54,7 @@ namespace Bit.Core.Services
|
|||||||
IApplicationCacheService applicationCacheService,
|
IApplicationCacheService applicationCacheService,
|
||||||
IPaymentService paymentService,
|
IPaymentService paymentService,
|
||||||
IPolicyRepository policyRepository,
|
IPolicyRepository policyRepository,
|
||||||
|
IReferenceEventService referenceEventService,
|
||||||
GlobalSettings globalSettings)
|
GlobalSettings globalSettings)
|
||||||
{
|
{
|
||||||
_organizationRepository = organizationRepository;
|
_organizationRepository = organizationRepository;
|
||||||
@ -71,6 +73,7 @@ namespace Bit.Core.Services
|
|||||||
_applicationCacheService = applicationCacheService;
|
_applicationCacheService = applicationCacheService;
|
||||||
_paymentService = paymentService;
|
_paymentService = paymentService;
|
||||||
_policyRepository = policyRepository;
|
_policyRepository = policyRepository;
|
||||||
|
_referenceEventService = referenceEventService;
|
||||||
_globalSettings = globalSettings;
|
_globalSettings = globalSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,6 +111,11 @@ namespace Bit.Core.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
await _paymentService.CancelSubscriptionAsync(organization, eop);
|
await _paymentService.CancelSubscriptionAsync(organization, eop);
|
||||||
|
await _referenceEventService.RaiseEventAsync(
|
||||||
|
new ReferenceEvent(ReferenceEventType.CancelSubscription, organization)
|
||||||
|
{
|
||||||
|
EndOfPeriod = endOfPeriod,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ReinstateSubscriptionAsync(Guid organizationId)
|
public async Task ReinstateSubscriptionAsync(Guid organizationId)
|
||||||
@ -119,6 +127,8 @@ namespace Bit.Core.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
await _paymentService.ReinstateSubscriptionAsync(organization);
|
await _paymentService.ReinstateSubscriptionAsync(organization);
|
||||||
|
await _referenceEventService.RaiseEventAsync(
|
||||||
|
new ReferenceEvent(ReferenceEventType.ReinstateSubscription, organization));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Tuple<bool, string>> UpgradePlanAsync(Guid organizationId, OrganizationUpgrade upgrade)
|
public async Task<Tuple<bool, string>> UpgradePlanAsync(Guid organizationId, OrganizationUpgrade upgrade)
|
||||||
@ -240,6 +250,17 @@ namespace Bit.Core.Services
|
|||||||
organization.Plan = newPlan.Name;
|
organization.Plan = newPlan.Name;
|
||||||
organization.Enabled = success;
|
organization.Enabled = success;
|
||||||
await ReplaceAndUpdateCache(organization);
|
await ReplaceAndUpdateCache(organization);
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
await _referenceEventService.RaiseEventAsync(
|
||||||
|
new ReferenceEvent(ReferenceEventType.UpgradePlan, organization)
|
||||||
|
{
|
||||||
|
PlanName = newPlan.Name,
|
||||||
|
PlanType = newPlan.Type,
|
||||||
|
Seats = organization.Seats,
|
||||||
|
Storage = organization.MaxStorageGb,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return new Tuple<bool, string>(success, paymentIntentClientSecret);
|
return new Tuple<bool, string>(success, paymentIntentClientSecret);
|
||||||
}
|
}
|
||||||
@ -265,6 +286,13 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
var secret = await BillingHelpers.AdjustStorageAsync(_paymentService, organization, storageAdjustmentGb,
|
var secret = await BillingHelpers.AdjustStorageAsync(_paymentService, organization, storageAdjustmentGb,
|
||||||
plan.StripeStoragePlanId);
|
plan.StripeStoragePlanId);
|
||||||
|
await _referenceEventService.RaiseEventAsync(
|
||||||
|
new ReferenceEvent(ReferenceEventType.AdjustStorage, organization)
|
||||||
|
{
|
||||||
|
PlanName = plan.Name,
|
||||||
|
PlanType = plan.Type,
|
||||||
|
Storage = storageAdjustmentGb,
|
||||||
|
});
|
||||||
await ReplaceAndUpdateCache(organization);
|
await ReplaceAndUpdateCache(organization);
|
||||||
return secret;
|
return secret;
|
||||||
}
|
}
|
||||||
@ -399,6 +427,13 @@ namespace Bit.Core.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
organization.Seats = (short?)newSeatTotal;
|
organization.Seats = (short?)newSeatTotal;
|
||||||
|
await _referenceEventService.RaiseEventAsync(
|
||||||
|
new ReferenceEvent(ReferenceEventType.AdjustSeats, organization)
|
||||||
|
{
|
||||||
|
PlanName = plan.Name,
|
||||||
|
PlanType = plan.Type,
|
||||||
|
Seats = organization.Seats,
|
||||||
|
});
|
||||||
await ReplaceAndUpdateCache(organization);
|
await ReplaceAndUpdateCache(organization);
|
||||||
return paymentIntentClientSecret;
|
return paymentIntentClientSecret;
|
||||||
}
|
}
|
||||||
@ -503,7 +538,16 @@ namespace Bit.Core.Services
|
|||||||
signup.PremiumAccessAddon, signup.TaxInfo);
|
signup.PremiumAccessAddon, signup.TaxInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
return await SignUpAsync(organization, signup.Owner.Id, signup.OwnerKey, signup.CollectionName, true);
|
var returnValue = await SignUpAsync(organization, signup.Owner.Id, signup.OwnerKey, signup.CollectionName, true);
|
||||||
|
await _referenceEventService.RaiseEventAsync(
|
||||||
|
new ReferenceEvent(ReferenceEventType.Signup, organization)
|
||||||
|
{
|
||||||
|
PlanName = plan.Name,
|
||||||
|
PlanType = plan.Type,
|
||||||
|
Seats = returnValue.Item1.Seats,
|
||||||
|
Storage = returnValue.Item1.MaxStorageGb,
|
||||||
|
});
|
||||||
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Tuple<Organization, OrganizationUser>> SignUpAsync(
|
public async Task<Tuple<Organization, OrganizationUser>> SignUpAsync(
|
||||||
@ -741,6 +785,8 @@ namespace Bit.Core.Services
|
|||||||
var eop = !organization.ExpirationDate.HasValue ||
|
var eop = !organization.ExpirationDate.HasValue ||
|
||||||
organization.ExpirationDate.Value >= DateTime.UtcNow;
|
organization.ExpirationDate.Value >= DateTime.UtcNow;
|
||||||
await _paymentService.CancelSubscriptionAsync(organization, eop);
|
await _paymentService.CancelSubscriptionAsync(organization, eop);
|
||||||
|
await _referenceEventService.RaiseEventAsync(
|
||||||
|
new ReferenceEvent(ReferenceEventType.DeleteAccount, organization));
|
||||||
}
|
}
|
||||||
catch (GatewayException) { }
|
catch (GatewayException) { }
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,7 @@ namespace Bit.Core.Services
|
|||||||
private readonly IPaymentService _paymentService;
|
private readonly IPaymentService _paymentService;
|
||||||
private readonly IPolicyRepository _policyRepository;
|
private readonly IPolicyRepository _policyRepository;
|
||||||
private readonly IDataProtector _organizationServiceDataProtector;
|
private readonly IDataProtector _organizationServiceDataProtector;
|
||||||
|
private readonly IReferenceEventService _referenceEventService;
|
||||||
private readonly CurrentContext _currentContext;
|
private readonly CurrentContext _currentContext;
|
||||||
private readonly GlobalSettings _globalSettings;
|
private readonly GlobalSettings _globalSettings;
|
||||||
|
|
||||||
@ -71,6 +72,7 @@ namespace Bit.Core.Services
|
|||||||
IDataProtectionProvider dataProtectionProvider,
|
IDataProtectionProvider dataProtectionProvider,
|
||||||
IPaymentService paymentService,
|
IPaymentService paymentService,
|
||||||
IPolicyRepository policyRepository,
|
IPolicyRepository policyRepository,
|
||||||
|
IReferenceEventService referenceEventService,
|
||||||
CurrentContext currentContext,
|
CurrentContext currentContext,
|
||||||
GlobalSettings globalSettings)
|
GlobalSettings globalSettings)
|
||||||
: base(
|
: base(
|
||||||
@ -102,6 +104,7 @@ namespace Bit.Core.Services
|
|||||||
_policyRepository = policyRepository;
|
_policyRepository = policyRepository;
|
||||||
_organizationServiceDataProtector = dataProtectionProvider.CreateProtector(
|
_organizationServiceDataProtector = dataProtectionProvider.CreateProtector(
|
||||||
"OrganizationServiceDataProtector");
|
"OrganizationServiceDataProtector");
|
||||||
|
_referenceEventService = referenceEventService;
|
||||||
_currentContext = currentContext;
|
_currentContext = currentContext;
|
||||||
_globalSettings = globalSettings;
|
_globalSettings = globalSettings;
|
||||||
}
|
}
|
||||||
@ -219,6 +222,8 @@ namespace Bit.Core.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
await _userRepository.DeleteAsync(user);
|
await _userRepository.DeleteAsync(user);
|
||||||
|
await _referenceEventService.RaiseEventAsync(
|
||||||
|
new ReferenceEvent(ReferenceEventType.DeleteAccount, user));
|
||||||
await _pushService.PushLogOutAsync(user.Id);
|
await _pushService.PushLogOutAsync(user.Id);
|
||||||
return IdentityResult.Success;
|
return IdentityResult.Success;
|
||||||
}
|
}
|
||||||
@ -288,6 +293,8 @@ namespace Bit.Core.Services
|
|||||||
if (result == IdentityResult.Success)
|
if (result == IdentityResult.Success)
|
||||||
{
|
{
|
||||||
await _mailService.SendWelcomeEmailAsync(user);
|
await _mailService.SendWelcomeEmailAsync(user);
|
||||||
|
await _referenceEventService.RaiseEventAsync(
|
||||||
|
new ReferenceEvent(ReferenceEventType.Signup, user));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -765,6 +772,12 @@ namespace Bit.Core.Services
|
|||||||
{
|
{
|
||||||
await SaveUserAsync(user);
|
await SaveUserAsync(user);
|
||||||
await _pushService.PushSyncVaultAsync(user.Id);
|
await _pushService.PushSyncVaultAsync(user.Id);
|
||||||
|
await _referenceEventService.RaiseEventAsync(
|
||||||
|
new ReferenceEvent(ReferenceEventType.UpgradePlan, user)
|
||||||
|
{
|
||||||
|
Storage = user.MaxStorageGb,
|
||||||
|
PlanName = PremiumPlanId,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
catch when(!_globalSettings.SelfHosted)
|
catch when(!_globalSettings.SelfHosted)
|
||||||
{
|
{
|
||||||
@ -841,6 +854,12 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
var secret = await BillingHelpers.AdjustStorageAsync(_paymentService, user, storageAdjustmentGb,
|
var secret = await BillingHelpers.AdjustStorageAsync(_paymentService, user, storageAdjustmentGb,
|
||||||
StoragePlanId);
|
StoragePlanId);
|
||||||
|
await _referenceEventService.RaiseEventAsync(
|
||||||
|
new ReferenceEvent(ReferenceEventType.AdjustStorage, user)
|
||||||
|
{
|
||||||
|
Storage = storageAdjustmentGb,
|
||||||
|
PlanName = StoragePlanId,
|
||||||
|
});
|
||||||
await SaveUserAsync(user);
|
await SaveUserAsync(user);
|
||||||
return secret;
|
return secret;
|
||||||
}
|
}
|
||||||
@ -868,11 +887,18 @@ namespace Bit.Core.Services
|
|||||||
eop = false;
|
eop = false;
|
||||||
}
|
}
|
||||||
await _paymentService.CancelSubscriptionAsync(user, eop, accountDelete);
|
await _paymentService.CancelSubscriptionAsync(user, eop, accountDelete);
|
||||||
|
await _referenceEventService.RaiseEventAsync(
|
||||||
|
new ReferenceEvent(ReferenceEventType.CancelSubscription, user)
|
||||||
|
{
|
||||||
|
EndOfPeriod = eop,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ReinstatePremiumAsync(User user)
|
public async Task ReinstatePremiumAsync(User user)
|
||||||
{
|
{
|
||||||
await _paymentService.ReinstateSubscriptionAsync(user);
|
await _paymentService.ReinstateSubscriptionAsync(user);
|
||||||
|
await _referenceEventService.RaiseEventAsync(
|
||||||
|
new ReferenceEvent(ReferenceEventType.ReinstateSubscription, user));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task EnablePremiumAsync(Guid userId, DateTime? expirationDate)
|
public async Task EnablePremiumAsync(Guid userId, DateTime? expirationDate)
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.Core.Models.Business;
|
||||||
|
|
||||||
|
namespace Bit.Core.Services
|
||||||
|
{
|
||||||
|
public class NoopReferenceEventService : IReferenceEventService
|
||||||
|
{
|
||||||
|
public Task RaiseEventAsync(ReferenceEvent referenceEvent)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -196,6 +196,15 @@ namespace Bit.Core.Utilities
|
|||||||
{
|
{
|
||||||
services.AddSingleton<IAttachmentStorageService, NoopAttachmentStorageService>();
|
services.AddSingleton<IAttachmentStorageService, NoopAttachmentStorageService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (globalSettings.SelfHosted)
|
||||||
|
{
|
||||||
|
services.AddSingleton<IReferenceEventService, NoopReferenceEventService>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
services.AddSingleton<IReferenceEventService, AzureQueueReferenceEventService>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddNoopServices(this IServiceCollection services)
|
public static void AddNoopServices(this IServiceCollection services)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user