1
0
mirror of https://github.com/bitwarden/server.git synced 2025-02-18 02:11:22 +01:00

Update emails

This commit is contained in:
Justin Baur 2021-11-15 14:34:12 -05:00
parent 85225790d6
commit afa53fcccd
19 changed files with 90 additions and 46 deletions

View File

@ -1,5 +0,0 @@
{{#>BasicTextLayout}}
{{OrganizationName}} has offered to sponsor a family organization for you with Bitwarden. To redeem please click the following link:
{{Url}}
{{/BasicTextLayout}}

View File

@ -2,15 +2,20 @@
<table width="100%" cellpadding="0" cellspacing="0" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
<tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
<td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none;" valign="top">
<b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{OrganizationName}}</b> has offered to sponsor a family organization for you with Bitwarden.
A Bitwarden account, {{SponsorEmail}}, has sponsored a free Families subscription for you! To activate your complimentary subscription, click the link below.
</td>
</tr>
<tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
<td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none; text-align: center;" valign="top" align="center">
<a href="{{{Url}}}" clicktracking=off target="_blank" style="color: #ffffff; text-decoration: none; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; background-color: #175DDC; border-color: #175DDC; border-style: solid; border-width: 10px 20px; margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
Redeem
Accept Sponsorship
</a>
</td>
</tr>
<tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
<td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none;" valign="top">
If you do not recognize this account, please ignore this message.
</td>
</tr>
</table>
{{/FullHtmlLayout}}
{{/FullHtmlLayout}}

View File

@ -0,0 +1,5 @@
{{#>BasicTextLayout}}
A Bitwarden account, {{SponsorEmail}}, has sponsored a free Families subscription for you! To activate your complimentary subscription, click the link below.
{{Url}}
{{/BasicTextLayout}}

View File

@ -0,0 +1,21 @@
{{#>FullHtmlLayout}}
<table width="100%" cellpadding="0" cellspacing="0" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
<tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
<td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none;" valign="top">
A Bitwarden account, {{SponsorEmail}}, has sponsored a free Families subscription for you! To activate your complimentary subscription, you will need to create an account. Click the link below.
</td>
</tr>
<tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
<td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none; text-align: center;" valign="top" align="center">
<a href="{{{Url}}}" clicktracking=off target="_blank" style="color: #ffffff; text-decoration: none; text-align: center; cursor: pointer; display: inline-block; border-radius: 5px; background-color: #175DDC; border-color: #175DDC; border-style: solid; border-width: 10px 20px; margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
Accept Sponsorship
</a>
</td>
</tr>
<tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
<td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none;" valign="top">
If you do not recognize this account, please ignore this message.
</td>
</tr>
</table>
{{/FullHtmlLayout}}

View File

@ -0,0 +1,5 @@
{{#>BasicTextLayout}}
A Bitwarden account, {{SponsorEmail}}, has sponsored a free Families subscription for you! To activate your complimentary subscription, you will need to create an account. Click the link below.
{{Url}}
{{/BasicTextLayout}}

View File

@ -2,8 +2,8 @@
<table width="100%" cellpadding="0" cellspacing="0" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
<tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
<td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none;" valign="top">
You have redeemed a family organization sponsorship from {{OrganizationName}}.
Your Families subscription has been successfully activated. Your subscription is free as long as the sponsoring member continues to have a qualifying Bitwarden subscription.
</td>
</tr>
</table>
{{/FullHtmlLayout}}
{{/FullHtmlLayout}}

View File

@ -1,3 +1,3 @@
{{#>BasicTextLayout}}
You have redeemed a family organization sponsorship from {{OrganizationName}}.
{{/BasicTextLayout}}
Your Families subscription has been successfully activated. Your subscription is free as long as the sponsoring member continues to have a qualifying Bitwarden subscription.
{{/BasicTextLayout}}

View File

@ -2,8 +2,8 @@
<table width="100%" cellpadding="0" cellspacing="0" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
<tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
<td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none;" valign="top">
You have redeemed a Families for Enterprise sponsorship from {{OrganizationName}}.
Your Families subscription has been successfully redeemed.
</td>
</tr>
</table>
{{/FullHtmlLayout}}
{{/FullHtmlLayout}}

View File

@ -1,3 +1,3 @@
{{#>BasicTextLayout}}
A user in your organization has redeemed a family invitation.
{{/BasicTextLayout}}
Your Families subscription has been successfully redeemed.
{{/BasicTextLayout}}

View File

@ -2,8 +2,8 @@
<table width="100%" cellpadding="0" cellspacing="0" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
<tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
<td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none;" valign="top">
Your Families for Enterprise sponsorship has ended and you will lose premium access at the end of the current billing cycle.
Your Families subscription is no longer sponsored and your subscription will expire in {{DaysLeft}} days. Please make sure you have a valid payment method to ensure there's no disruption to your account. Payment method can be updated under Settings → Subscription under your Families Organization.
</td>
</tr>
</table>
{{/FullHtmlLayout}}
{{/FullHtmlLayout}}

View File

@ -1,3 +1,3 @@
{{#>BasicTextLayout}}
Your Families for Enterprise sponsorship has ended and you will lose premium access at the end of the current billing cycle.
{{/BasicTextLayout}}
Your Families subscription is no longer sponsored and your subscription will expire in {{DaysLeft}} days. Please make sure you have a valid payment method to ensure there's no disruption to your account. Payment method can be updated under Settings → Subscription under your Families Organization.
{{/BasicTextLayout}}

View File

@ -2,6 +2,7 @@ namespace Bit.Core.Models.Mail.FamiliesForEnterprise
{
public class FamiliesForEnterpriseOfferViewModel : BaseMailModel
{
public string SponsorEmail { get; set; }
public string SponsorshipToken { get; set; }
public string Url => $"{WebVaultUrl}/sponsored/families-for-enterprise?token={SponsorshipToken}";
}

View File

@ -2,6 +2,6 @@ namespace Bit.Core.Models.Mail.FamiliesForEnterprise
{
public class FamiliesForEnterpriseRedeemedToOrgUserViewModel : BaseMailModel
{
public string OrganizationName { get; set; }
}
}

View File

@ -2,6 +2,6 @@ namespace Bit.Core.Models.Mail.FamiliesForEnterprise
{
public class FamiliesForEnterpriseSponsorshipEndingViewModel : BaseMailModel
{
public int DaysLeft { get; set; }
}
}

View File

@ -49,12 +49,11 @@ namespace Bit.Core.Services
Task SendProviderConfirmedEmailAsync(string providerName, string email);
Task SendProviderUserRemoved(string providerName, string email);
Task SendUpdatedTempPasswordEmailAsync(string email, string userName);
// TODO: Change signature to hold data needed for email
Task SendFamiliesForEnterpriseOfferEmailAsync(string email, string organizationName, string token);
Task SendFamiliesForEnterpriseRedeemedEmailsAsync(string familyUserEmail, string sponsorEmail, string sponsorOrgName);
Task SendFamiliesForEnterpriseOfferEmailAsync(string email, string sponsorEmail, bool existingAccount, string token);
Task SendFamiliesForEnterpriseRedeemedEmailsAsync(string familyUserEmail, string sponsorEmail);
Task SendFamiliesForEnterpriseReconfirmationRequiredEmailAsync(string email);
Task SendFamiliesForEnterpriseSponsorshipRevertingEmailAsync(string email, string familyOrgName);
Task SendFamiliesForEnterpriseSponsorshipEndingEmailAsync(string email);
Task SendFamiliesForEnterpriseSponsorshipEndingEmailAsync(string email, DateTime sponsorshipEndDate);
Task SendOTPEmailAsync(string email, string token);
}
}

View File

@ -757,35 +757,39 @@ namespace Bit.Core.Services
await _mailDeliveryService.SendEmailAsync(message);
}
public async Task SendFamiliesForEnterpriseOfferEmailAsync(string email, string organizationName, string token)
public async Task SendFamiliesForEnterpriseOfferEmailAsync(string email, string sponsorEmail, bool existingAccount, string token)
{
var message = CreateDefaultMessage("Free Bitwarden Family Plan Offer", email);
var message = CreateDefaultMessage("Finish Activation - Your Free Families Subscription", email);
var model = new FamiliesForEnterpriseOfferViewModel
{
SponsorEmail = sponsorEmail,
WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash,
SiteName = _globalSettings.SiteName,
SponsorshipToken = token,
};
await AddMessageContentAsync(message, "FamiliesForEnterprise.FamiliesForEnterpriseOffer", model);
await AddMessageContentAsync(message, existingAccount
? "FamiliesForEnterprise.FamiliesForEnterpriseOfferExistingAccount"
: "FamiliesForEnterprise.FamiliesForEnterpriseOfferNewAccount", model);
message.Category = "FamiliesForEnterpriseOffer";
await _mailDeliveryService.SendEmailAsync(message);
}
public async Task SendFamiliesForEnterpriseRedeemedEmailsAsync(string familyUserEmail, string sponsorEmail, string sponsorOrgName)
public async Task SendFamiliesForEnterpriseRedeemedEmailsAsync(string familyUserEmail, string sponsorEmail)
{
// Email family user
await SendFamiliesForEnterpriseInviteRedeemedToFamilyUserEmailAsync(familyUserEmail);
// Email enterprise org user
await SendFamiliesForEnterpriseInviteRedeemedToOrgUserEmailAsync(sponsorEmail, sponsorOrgName);
await SendFamiliesForEnterpriseInviteRedeemedToOrgUserEmailAsync(sponsorEmail);
}
private async Task SendFamiliesForEnterpriseInviteRedeemedToFamilyUserEmailAsync(string email)
{
// TODO: Complete emails
var message = CreateDefaultMessage("You Have Redeemed A Family Organization Sponsorship", email);
var message = CreateDefaultMessage("Success! Families Subscription Activated", email);
var model = new FamiliesForEnterpriseRedeemedToFamilyUserViewModel
{
@ -795,13 +799,13 @@ namespace Bit.Core.Services
await _mailDeliveryService.SendEmailAsync(message);
}
private async Task SendFamiliesForEnterpriseInviteRedeemedToOrgUserEmailAsync(string email, string organizationName)
private async Task SendFamiliesForEnterpriseInviteRedeemedToOrgUserEmailAsync(string email)
{
// TODO: Complete emails
var message = CreateDefaultMessage("A User Has Redeemeed Your Sponsorship", email);
var message = CreateDefaultMessage("Success! Families Subscription Activated", email);
var model = new FamiliesForEnterpriseRedeemedToOrgUserViewModel
{
OrganizationName = CoreHelpers.SanitizeForEmail(organizationName, false),
};
await AddMessageContentAsync(message, "FamiliesForEnterprise.FamiliesForEnterpriseRedeemedToOrgUser", model);
message.Category = "FamilyForEnterpriseRedeemedToOrgUser";
@ -814,7 +818,7 @@ namespace Bit.Core.Services
var message = CreateDefaultMessage("Your Sponsorship Requires Reconfirmation", email);
var model = new FamiliesForEnterpriseReconfirmationRequiredViewModel
{
};
await AddMessageContentAsync(message, "FamiliesForEnterprise.FamiliesForEnterpriseReconfirmationRequired", model);
message.Category = "FamiliesForEnterpriseReconfirmationRequired";
@ -823,7 +827,6 @@ namespace Bit.Core.Services
public async Task SendFamiliesForEnterpriseSponsorshipRevertingEmailAsync(string email, string familyOrgName)
{
// TODO: Complete emails
var message = CreateDefaultMessage($"{familyOrgName} Organization Sponsorship Is No Longer Valid", email);
var model = new FamiliesForEnterpriseSponsorshipRevertingViewModel
{
@ -834,13 +837,14 @@ namespace Bit.Core.Services
await _mailDeliveryService.SendEmailAsync(message);
}
public async Task SendFamiliesForEnterpriseSponsorshipEndingEmailAsync(string email)
public async Task SendFamiliesForEnterpriseSponsorshipEndingEmailAsync(string email, DateTime sponsorshipEndDate)
{
// TODO: Complete emails
var message = CreateDefaultMessage("A Family Organization Sponsorship Is Ending", email);
var endsInTime = DateTime.UtcNow - sponsorshipEndDate;
var message = CreateDefaultMessage("Action Required: Renew Families Subscription", email);
var model = new FamiliesForEnterpriseSponsorshipEndingViewModel
{
DaysLeft = (int)endsInTime.TotalDays,
};
await AddMessageContentAsync(message, "FamiliesForEnterprise.FamiliesForEnterpriseSponsorshipEnding", model);
message.Category = "FamiliesForEnterpriseSponsorshipEnding";

View File

@ -15,6 +15,7 @@ namespace Bit.Core.Services
private readonly IOrganizationSponsorshipRepository _organizationSponsorshipRepository;
private readonly IOrganizationRepository _organizationRepository;
private readonly IUserRepository _userRepository;
private readonly IPaymentService _paymentService;
private readonly IMailService _mailService;
@ -22,12 +23,14 @@ namespace Bit.Core.Services
public OrganizationSponsorshipService(IOrganizationSponsorshipRepository organizationSponsorshipRepository,
IOrganizationRepository organizationRepository,
IUserRepository userRepository,
IPaymentService paymentService,
IMailService mailService,
IDataProtectionProvider dataProtectionProvider)
{
_organizationSponsorshipRepository = organizationSponsorshipRepository;
_organizationRepository = organizationRepository;
_userRepository = userRepository;
_paymentService = paymentService;
_mailService = mailService;
_dataProtector = dataProtectionProvider.CreateProtector("OrganizationSponsorshipServiceDataProtector");
@ -105,8 +108,11 @@ namespace Bit.Core.Services
public async Task SendSponsorshipOfferAsync(Organization sponsoringOrg, OrganizationSponsorship sponsorship)
{
var user = await _userRepository.GetByEmailAsync(sponsorship.OfferedToEmail);
var isExistingAccount = user != null;
await _mailService.SendFamiliesForEnterpriseOfferEmailAsync(sponsorship.OfferedToEmail, sponsoringOrg.Name,
RedemptionToken(sponsorship.Id, sponsorship.PlanSponsorshipType.Value));
isExistingAccount, RedemptionToken(sponsorship.Id, sponsorship.PlanSponsorshipType.Value));
}
public async Task SetUpSponsorshipAsync(OrganizationSponsorship sponsorship, Organization sponsoredOrganization)

View File

@ -201,12 +201,12 @@ namespace Bit.Core.Services
return Task.FromResult(0);
}
public Task SendFamiliesForEnterpriseOfferEmailAsync(string email, string organizationName, string token)
public Task SendFamiliesForEnterpriseOfferEmailAsync(string email, string sponsorEmail, bool existingAccount, string token)
{
return Task.FromResult(0);
}
public Task SendFamiliesForEnterpriseRedeemedEmailsAsync(string familyUserEmail, string sponsorEmail, string sponsorOrgName)
public Task SendFamiliesForEnterpriseRedeemedEmailsAsync(string familyUserEmail, string sponsorEmail)
{
return Task.FromResult(0);
}
@ -221,7 +221,7 @@ namespace Bit.Core.Services
return Task.FromResult(0);
}
public Task SendFamiliesForEnterpriseSponsorshipEndingEmailAsync(string email)
public Task SendFamiliesForEnterpriseSponsorshipEndingEmailAsync(string email, DateTime sponsorshipEndDate)
{
return Task.FromResult(0);
}

View File

@ -35,7 +35,7 @@ namespace Bit.Core.Test.Services
);
}
[Fact(Skip = "Only for local development")]
[Fact]
public async Task SendAllEmails()
{
// This test is only opt in and is more for development purposes.
@ -112,6 +112,9 @@ namespace Bit.Core.Test.Services
ProviderId = Guid.NewGuid(),
Id = Guid.NewGuid(),
}},
{ ("familyUserEmail", typeof(string)), "test@bitwarden.com" },
{ ("sponsorEmail", typeof(string)), "test@bitwarden.com" },
{ ("familyOrgName", typeof(string)), "Test Org Name" },
};
var globalSettings = new GlobalSettings