diff --git a/src/Billing/Controllers/StripeController.cs b/src/Billing/Controllers/StripeController.cs index 1bdb406724..98073a06ab 100644 --- a/src/Billing/Controllers/StripeController.cs +++ b/src/Billing/Controllers/StripeController.cs @@ -1,5 +1,6 @@ using Bit.Core; using Bit.Core.Enums; +using Bit.Core.Models.Business; using Bit.Core.Models.Table; using Bit.Core.Repositories; using Bit.Core.Services; @@ -34,6 +35,7 @@ namespace Bit.Billing.Controllers private readonly IMailService _mailService; private readonly ILogger _logger; private readonly Braintree.BraintreeGateway _btGateway; + private readonly IReferenceEventService _referenceEventService; public StripeController( GlobalSettings globalSettings, @@ -45,6 +47,7 @@ namespace Bit.Billing.Controllers IUserService userService, IAppleIapService appleIapService, IMailService mailService, + IReferenceEventService referenceEventService, ILogger logger) { _billingSettings = billingSettings?.Value; @@ -55,6 +58,7 @@ namespace Bit.Billing.Controllers _userService = userService; _appleIapService = appleIapService; _mailService = mailService; + _referenceEventService = referenceEventService; _logger = logger; _btGateway = new Braintree.BraintreeGateway { @@ -382,6 +386,17 @@ namespace Bit.Billing.Controllers await _userService.EnablePremiumAsync(ids.Item2.Value, subscription.CurrentPeriodEnd); } } + if (ids.Item1.HasValue || ids.Item2.HasValue) + { + await _referenceEventService.RaiseEventAsync( + new ReferenceEvent(ReferenceEventType.Rebilled, null) + { + Id = ids.Item1 ?? ids.Item2 ?? default, + Source = ids.Item1.HasValue + ? ReferenceEventSource.Organization + : ReferenceEventSource.User, + }); + } } } } diff --git a/src/Core/Enums/ReferenceEventType.cs b/src/Core/Enums/ReferenceEventType.cs index abc7886c5c..25fb19a2df 100644 --- a/src/Core/Enums/ReferenceEventType.cs +++ b/src/Core/Enums/ReferenceEventType.cs @@ -18,5 +18,11 @@ namespace Bit.Core.Enums ReinstateSubscription, [EnumMember(Value = "delete-account")] DeleteAccount, + [EnumMember(Value = "confirm-email")] + ConfirmEmailAddress, + [EnumMember(Value = "invited-users")] + InvitedUsers, + [EnumMember(Value = "rebilled")] + Rebilled, } } diff --git a/src/Core/Models/Business/ReferenceEvent.cs b/src/Core/Models/Business/ReferenceEvent.cs index 5e430e36f0..83e44cc646 100644 --- a/src/Core/Models/Business/ReferenceEvent.cs +++ b/src/Core/Models/Business/ReferenceEvent.cs @@ -34,6 +34,8 @@ namespace Bit.Core.Models.Business public DateTime EventDate { get; set; } = DateTime.UtcNow; + public int? Users { get; set; } + public bool? EndOfPeriod { get; set; } public string PlanName { get; set; } diff --git a/src/Core/Services/Implementations/OrganizationService.cs b/src/Core/Services/Implementations/OrganizationService.cs index 4f5a06b9a4..749b4d6da6 100644 --- a/src/Core/Services/Implementations/OrganizationService.cs +++ b/src/Core/Services/Implementations/OrganizationService.cs @@ -949,6 +949,7 @@ namespace Bit.Core.Services } var orgUsers = new List(); + var orgUserInvitedCount = 0; foreach (var email in emails) { // Make sure user is not already invited @@ -982,10 +983,16 @@ namespace Bit.Core.Services await _organizationUserRepository.CreateAsync(orgUser); } - await SendInviteAsync(orgUser); + await SendInviteAsync(orgUser, organization); await _eventService.LogOrganizationUserEventAsync(orgUser, EventType.OrganizationUser_Invited); orgUsers.Add(orgUser); + orgUserInvitedCount++; } + await _referenceEventService.RaiseEventAsync( + new ReferenceEvent(ReferenceEventType.InvitedUsers, organization) + { + Users = orgUserInvitedCount + }); return orgUsers; } @@ -999,16 +1006,16 @@ namespace Bit.Core.Services throw new BadRequestException("User invalid."); } - await SendInviteAsync(orgUser); + var org = await GetOrgById(orgUser.OrganizationId); + await SendInviteAsync(orgUser, org); } - private async Task SendInviteAsync(OrganizationUser orgUser) + private async Task SendInviteAsync(OrganizationUser orgUser, Organization organization) { - var org = await GetOrgById(orgUser.OrganizationId); var nowMillis = CoreHelpers.ToEpocMilliseconds(DateTime.UtcNow); var token = _dataProtector.Protect( $"OrganizationUserInvite {orgUser.Id} {orgUser.Email} {nowMillis}"); - await _mailService.SendOrganizationInviteEmailAsync(org.Name, orgUser, token); + await _mailService.SendOrganizationInviteEmailAsync(organization.Name, orgUser, token); } public async Task AcceptUserAsync(Guid organizationUserId, User user, string token, diff --git a/src/Core/Services/Implementations/UserService.cs b/src/Core/Services/Implementations/UserService.cs index bcdf80da0f..06cd774f79 100644 --- a/src/Core/Services/Implementations/UserService.cs +++ b/src/Core/Services/Implementations/UserService.cs @@ -1135,5 +1135,16 @@ namespace Bit.Core.Services } } } + + public override async Task ConfirmEmailAsync(User user, string token) + { + var result = await base.ConfirmEmailAsync(user, token); + if (result.Succeeded) + { + await _referenceEventService.RaiseEventAsync( + new ReferenceEvent(ReferenceEventType.ConfirmEmailAddress, user)); + } + return result; + } } }