-
Notifications
You must be signed in to change notification settings - Fork 1.5k
[PM-27882] Add SendOrganizationConfirmationCommand #6743
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
8f26c52
c363d80
f9ed23f
98812dd
f8e7a3b
00c806a
2a12770
9435748
d8282e1
342c197
94b29ab
20da464
945576c
7494800
d93d100
c86f5ef
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| ๏ปฟusing Bit.Core.Platform.Mail.Mailer; | ||
|
|
||
| namespace Bit.Core.AdminConsole.Models.Mail.Mailer.OrganizationConfirmation; | ||
|
|
||
| public abstract class OrganizationConfirmationBaseView : BaseMailView | ||
| { | ||
| public required string OrganizationName { get; set; } | ||
| public required string TitleFirst { get; set; } | ||
| public required string TitleSecondBold { get; set; } | ||
| public required string TitleThird { get; set; } | ||
| public required string WebVaultUrl { get; set; } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| ๏ปฟusing Bit.Core.Platform.Mail.Mailer; | ||
|
|
||
| namespace Bit.Core.AdminConsole.Models.Mail.Mailer.OrganizationConfirmation; | ||
|
|
||
| public class OrganizationConfirmationEnterpriseTeamsView : OrganizationConfirmationBaseView | ||
| { | ||
| } | ||
|
|
||
| public class OrganizationConfirmationEnterpriseTeams : BaseMail<OrganizationConfirmationEnterpriseTeamsView> | ||
| { | ||
| public override required string Subject { get; set; } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| ๏ปฟusing Bit.Core.Platform.Mail.Mailer; | ||
|
|
||
| namespace Bit.Core.AdminConsole.Models.Mail.Mailer.OrganizationConfirmation; | ||
|
|
||
| public class OrganizationConfirmationFamilyFreeView : OrganizationConfirmationBaseView | ||
| { | ||
| } | ||
|
|
||
| public class OrganizationConfirmationFamilyFree : BaseMail<OrganizationConfirmationFamilyFreeView> | ||
| { | ||
| public override required string Subject { get; set; } | ||
| } |
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The ViewModel names need to match the templates. Our templates use kebab-case (MJML), while the ViewModels use PascalCase. We should standardize these conventions, but this is outside the AC teamโs scope. The owner of the mailer and MJML should decide this. I donโt recommend creating a script to map one naming convention to another. That adds complexity and could introduce more issues over time. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| ๏ปฟusing Bit.Core.AdminConsole.Entities; | ||
|
|
||
| namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.OrganizationConfirmation; | ||
|
|
||
| public interface ISendOrganizationConfirmationCommand | ||
| { | ||
| /// <summary> | ||
| /// Sends an organization confirmation email to the specified user. | ||
| /// </summary> | ||
| /// <param name="organization">The organization to send the confirmation email for.</param> | ||
| /// <param name="userEmail">The email address of the user to send the confirmation to.</param> | ||
| /// <param name="accessSecretsManager">Whether the user has access to Secrets Manager.</param> | ||
| Task SendConfirmationAsync(Organization organization, string userEmail, bool accessSecretsManager); | ||
|
|
||
| /// <summary> | ||
| /// Sends organization confirmation emails to multiple users. | ||
| /// </summary> | ||
| /// <param name="organization">The organization to send the confirmation emails for.</param> | ||
| /// <param name="userEmails">The email addresses of the users to send confirmations to.</param> | ||
| /// <param name="accessSecretsManager">Whether the users have access to Secrets Manager.</param> | ||
| Task SendConfirmationsAsync(Organization organization, IEnumerable<string> userEmails, bool accessSecretsManager); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| ๏ปฟusing System.Net; | ||
| using Bit.Core.AdminConsole.Entities; | ||
| using Bit.Core.AdminConsole.Models.Mail.Mailer.OrganizationConfirmation; | ||
| using Bit.Core.Billing.Enums; | ||
| using Bit.Core.Platform.Mail.Mailer; | ||
| using Bit.Core.Settings; | ||
|
|
||
| namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.OrganizationConfirmation; | ||
|
|
||
| public class SendOrganizationConfirmationCommand(IMailer mailer, GlobalSettings globalSettings) : ISendOrganizationConfirmationCommand | ||
| { | ||
| private const string _titleFirst = "You're confirmed as a member of "; | ||
| private const string _titleThird = "!"; | ||
|
|
||
| private static string GetConfirmationSubject(string organizationName) => | ||
| $"You Have Been Confirmed To {organizationName}"; | ||
| private string GetWebVaultUrl(bool accessSecretsManager) => accessSecretsManager | ||
| ? globalSettings.BaseServiceUri.VaultWithHashAndSecretManagerProduct | ||
| : globalSettings.BaseServiceUri.VaultWithHash; | ||
|
|
||
| public async Task SendConfirmationAsync(Organization organization, string userEmail, bool accessSecretsManager = false) | ||
| { | ||
| await SendConfirmationsAsync(organization, [userEmail], accessSecretsManager); | ||
| } | ||
|
|
||
| public async Task SendConfirmationsAsync(Organization organization, IEnumerable<string> userEmails, bool accessSecretsManager = false) | ||
| { | ||
| var userEmailsList = userEmails.ToList(); | ||
|
|
||
| if (userEmailsList.Count == 0) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| var organizationName = WebUtility.HtmlDecode(organization.Name); | ||
|
|
||
| if (IsEnterpriseOrTeamsPlan(organization.PlanType)) | ||
| { | ||
| await SendEnterpriseTeamsEmailsAsync(userEmailsList, organizationName, accessSecretsManager); | ||
| return; | ||
| } | ||
|
|
||
| await SendFamilyFreeConfirmEmailsAsync(userEmailsList, organizationName, accessSecretsManager); | ||
| } | ||
|
|
||
| private async Task SendEnterpriseTeamsEmailsAsync(List<string> userEmailsList, string organizationName, bool accessSecretsManager) | ||
| { | ||
| var mail = new OrganizationConfirmationEnterpriseTeams | ||
| { | ||
| ToEmails = userEmailsList, | ||
| Subject = GetConfirmationSubject(organizationName), | ||
| View = new OrganizationConfirmationEnterpriseTeamsView | ||
| { | ||
| OrganizationName = organizationName, | ||
| TitleFirst = _titleFirst, | ||
| TitleSecondBold = organizationName, | ||
| TitleThird = _titleThird, | ||
| WebVaultUrl = GetWebVaultUrl(accessSecretsManager) | ||
| } | ||
| }; | ||
|
|
||
| await mailer.SendEmail(mail); | ||
| } | ||
|
|
||
| private async Task SendFamilyFreeConfirmEmailsAsync(List<string> userEmailsList, string organizationName, bool accessSecretsManager) | ||
| { | ||
| var mail = new OrganizationConfirmationFamilyFree | ||
| { | ||
| ToEmails = userEmailsList, | ||
| Subject = GetConfirmationSubject(organizationName), | ||
| View = new OrganizationConfirmationFamilyFreeView | ||
| { | ||
| OrganizationName = organizationName, | ||
| TitleFirst = _titleFirst, | ||
| TitleSecondBold = organizationName, | ||
| TitleThird = _titleThird, | ||
| WebVaultUrl = GetWebVaultUrl(accessSecretsManager) | ||
| } | ||
| }; | ||
|
|
||
| await mailer.SendEmail(mail); | ||
| } | ||
|
|
||
|
|
||
| private static bool IsEnterpriseOrTeamsPlan(PlanType planType) | ||
| { | ||
| return planType switch | ||
| { | ||
| PlanType.TeamsMonthly2019 or | ||
| PlanType.TeamsAnnually2019 or | ||
| PlanType.TeamsMonthly2020 or | ||
| PlanType.TeamsAnnually2020 or | ||
| PlanType.TeamsMonthly2023 or | ||
| PlanType.TeamsAnnually2023 or | ||
| PlanType.TeamsStarter2023 or | ||
| PlanType.TeamsMonthly or | ||
| PlanType.TeamsAnnually or | ||
| PlanType.TeamsStarter or | ||
| PlanType.EnterpriseMonthly2019 or | ||
| PlanType.EnterpriseAnnually2019 or | ||
| PlanType.EnterpriseMonthly2020 or | ||
| PlanType.EnterpriseAnnually2020 or | ||
| PlanType.EnterpriseMonthly2023 or | ||
| PlanType.EnterpriseAnnually2023 or | ||
| PlanType.EnterpriseMonthly or | ||
| PlanType.EnterpriseAnnually => true, | ||
| _ => false | ||
| }; | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.