mirror of
https://github.com/bitwarden/server.git
synced 2025-02-13 01:21:29 +01:00
Organization User Accepted Invite Email Notifications (#1465)
This commit is contained in:
parent
7abb053914
commit
5ec37b96b4
@ -2,17 +2,23 @@
|
|||||||
<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;">
|
<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;">
|
<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">
|
<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">
|
||||||
This email is to notify you that {{UserEmail}} has accepted your invitation to join <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>.
|
{{UserIdentifier}} needs to be confirmed to {{OrganizationName}} before they can access the organization vault.
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</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;">
|
<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">
|
<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">
|
||||||
To confirm this user, log into the Bitwarden web vault, manage your organization "People", and confirm the user.
|
To confirm users into your organization:
|
||||||
|
<ol>
|
||||||
|
<li>Log in to your <a href="https://vault.bitwarden.com/#/organizations/{{{OrganizationId}}}/manage/people">Web Vault</a> and open your Organization.</li>
|
||||||
|
<li>Open the <b>Manage</b> tab and select <b>People</b> from the left-hand menu.</li>
|
||||||
|
<li>Hover over the <b>Accepted</b> user and select the gear dropdown.</li>
|
||||||
|
<li>Select <b>Confirm</b>.</li>
|
||||||
|
</ol>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</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;">
|
<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 last" 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; -webkit-text-size-adjust: none;" valign="top">
|
<td class="content-block last" 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; -webkit-text-size-adjust: none;" valign="top">
|
||||||
If you do not wish to confirm this user, you can also remove them from the organization on the same page.
|
For more information, please refer to the following help article: <a href="https://bitwarden.com/help/article/managing-users/#confirm">https://bitwarden.com/help/article/managing-users/#confirm</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
{{#>BasicTextLayout}}
|
{{#>BasicTextLayout}}
|
||||||
This email is to notify you that {{UserEmail}} has accepted your invitation to join {{OrganizationName}}.
|
{{UserIdentifier}} needs to be confirmed to {{OrganizationName}} before they can access the organization vault.
|
||||||
|
|
||||||
To confirm this user, log into the Bitwarden web vault, manage your organization "People" and confirm the user.
|
To confirm users into your organization:
|
||||||
|
1. Log in to your Web Vault and open your Organization.
|
||||||
|
2. Open the Manage tab and select People from the left-hand menu.
|
||||||
|
3. Hover over the Accepted user and select the grear dropdown.
|
||||||
|
4. Select Confirm.
|
||||||
|
|
||||||
If you do not wish to confirm this user, you can also remove them from the organization on the same page.
|
For more information, please refer to the following help article: https://bitwarden.com/help/article/managing-user/#confirm
|
||||||
{{/BasicTextLayout}}
|
{{/BasicTextLayout}}
|
@ -1,8 +1,11 @@
|
|||||||
namespace Bit.Core.Models.Mail
|
using System;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Mail
|
||||||
{
|
{
|
||||||
public class OrganizationUserAcceptedViewModel : BaseMailModel
|
public class OrganizationUserAcceptedViewModel : BaseMailModel
|
||||||
{
|
{
|
||||||
|
public Guid OrganizationId { get; set; }
|
||||||
public string OrganizationName { get; set; }
|
public string OrganizationName { get; set; }
|
||||||
public string UserEmail { get; set; }
|
public string UserIdentifier { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -389,5 +389,21 @@ namespace Bit.Core.Repositories.EntityFramework
|
|||||||
}
|
}
|
||||||
|
|
||||||
Task<ICollection<string>> IOrganizationUserRepository.SelectKnownEmailsAsync(Guid organizationId, IEnumerable<string> emails, bool onlyRegisteredUsers) => throw new NotImplementedException();
|
Task<ICollection<string>> IOrganizationUserRepository.SelectKnownEmailsAsync(Guid organizationId, IEnumerable<string> emails, bool onlyRegisteredUsers) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public async Task<IEnumerable<OrganizationUserUserDetails>> GetManyByMinimumRoleAsync(Guid organizationId, OrganizationUserType minRole)
|
||||||
|
{
|
||||||
|
using (var scope = ServiceScopeFactory.CreateScope())
|
||||||
|
{
|
||||||
|
var dbContext = GetDatabaseContext(scope);
|
||||||
|
var query = dbContext.OrganizationUsers
|
||||||
|
.Include(e => e.User)
|
||||||
|
.Where(e => e.OrganizationId.Equals(organizationId) && e.Type <= minRole)
|
||||||
|
.Select(e => new OrganizationUserUserDetails() {
|
||||||
|
Id = e.Id,
|
||||||
|
Email = e.Email ?? e.User.Email
|
||||||
|
});
|
||||||
|
return await query.ToListAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,5 +37,6 @@ namespace Bit.Core.Repositories
|
|||||||
Task DeleteManyAsync(IEnumerable<Guid> userIds);
|
Task DeleteManyAsync(IEnumerable<Guid> userIds);
|
||||||
Task<OrganizationUser> GetByOrganizationEmailAsync(Guid organizationId, string email);
|
Task<OrganizationUser> GetByOrganizationEmailAsync(Guid organizationId, string email);
|
||||||
Task<IEnumerable<OrganizationUserPublicKey>> GetManyPublicKeysByOrganizationUserAsync(Guid organizationId, IEnumerable<Guid> Ids);
|
Task<IEnumerable<OrganizationUserPublicKey>> GetManyPublicKeysByOrganizationUserAsync(Guid organizationId, IEnumerable<Guid> Ids);
|
||||||
|
Task<IEnumerable<OrganizationUserUserDetails>> GetManyByMinimumRoleAsync(Guid organizationId, OrganizationUserType minRole);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -391,5 +391,18 @@ namespace Bit.Core.Repositories.SqlServer
|
|||||||
return results.ToList();
|
return results.ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<OrganizationUserUserDetails>> GetManyByMinimumRoleAsync(Guid organizationId, OrganizationUserType minRole)
|
||||||
|
{
|
||||||
|
using (var connection = new SqlConnection(ConnectionString))
|
||||||
|
{
|
||||||
|
var results = await connection.QueryAsync<OrganizationUserUserDetails>(
|
||||||
|
"[dbo].[OrganizationUser_ReadByMinimumRole]",
|
||||||
|
new { OrganizationId = organizationId, MinRole = minRole },
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
|
|
||||||
|
return results.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ namespace Bit.Core.Services
|
|||||||
Task SendMasterPasswordHintEmailAsync(string email, string hint);
|
Task SendMasterPasswordHintEmailAsync(string email, string hint);
|
||||||
Task SendOrganizationInviteEmailAsync(string organizationName, OrganizationUser orgUser, string token);
|
Task SendOrganizationInviteEmailAsync(string organizationName, OrganizationUser orgUser, string token);
|
||||||
Task BulkSendOrganizationInviteEmailAsync(string organizationName, IEnumerable<(OrganizationUser orgUser, string token)> invites);
|
Task BulkSendOrganizationInviteEmailAsync(string organizationName, IEnumerable<(OrganizationUser orgUser, string token)> invites);
|
||||||
Task SendOrganizationAcceptedEmailAsync(string organizationName, string userEmail,
|
Task SendOrganizationAcceptedEmailAsync(Organization organization, string userIdentifier,
|
||||||
IEnumerable<string> adminEmails);
|
IEnumerable<string> adminEmails);
|
||||||
Task SendOrganizationConfirmedEmailAsync(string organizationName, string email);
|
Task SendOrganizationConfirmedEmailAsync(string organizationName, string email);
|
||||||
Task SendOrganizationUserRemovedForPolicyTwoStepEmailAsync(string organizationName, string email);
|
Task SendOrganizationUserRemovedForPolicyTwoStepEmailAsync(string organizationName, string email);
|
||||||
|
@ -143,14 +143,15 @@ namespace Bit.Core.Services
|
|||||||
await _mailDeliveryService.SendEmailAsync(message);
|
await _mailDeliveryService.SendEmailAsync(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SendOrganizationAcceptedEmailAsync(string organizationName, string userEmail,
|
public async Task SendOrganizationAcceptedEmailAsync(Organization organization, string userIdentifier,
|
||||||
IEnumerable<string> adminEmails)
|
IEnumerable<string> adminEmails)
|
||||||
{
|
{
|
||||||
var message = CreateDefaultMessage($"User {userEmail} Has Accepted Invite", adminEmails);
|
var message = CreateDefaultMessage($"Action Required: {userIdentifier} Needs to Be Confirmed", adminEmails);
|
||||||
var model = new OrganizationUserAcceptedViewModel
|
var model = new OrganizationUserAcceptedViewModel
|
||||||
{
|
{
|
||||||
OrganizationName = CoreHelpers.SanitizeForEmail(organizationName),
|
OrganizationId = organization.Id,
|
||||||
UserEmail = userEmail,
|
OrganizationName = CoreHelpers.SanitizeForEmail(organization.Name),
|
||||||
|
UserIdentifier = userIdentifier,
|
||||||
WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash,
|
WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash,
|
||||||
SiteName = _globalSettings.SiteName
|
SiteName = _globalSettings.SiteName
|
||||||
};
|
};
|
||||||
|
@ -1424,7 +1424,10 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
await _organizationUserRepository.ReplaceAsync(orgUser);
|
await _organizationUserRepository.ReplaceAsync(orgUser);
|
||||||
|
|
||||||
// TODO: send notification emails to org admins and accepting user?
|
await _mailService.SendOrganizationAcceptedEmailAsync(
|
||||||
|
(await _organizationRepository.GetByIdAsync(orgUser.OrganizationId)),
|
||||||
|
user.Email,
|
||||||
|
(await _organizationUserRepository.GetManyByMinimumRoleAsync(orgUser.OrganizationId, OrganizationUserType.Admin)).Select(a => a.Email).Distinct());
|
||||||
return orgUser;
|
return orgUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ namespace Bit.Core.Services
|
|||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SendOrganizationAcceptedEmailAsync(string organizationName, string userEmail, IEnumerable<string> adminEmails)
|
public Task SendOrganizationAcceptedEmailAsync(Organization organization, string userIdentifier, IEnumerable<string> adminEmails)
|
||||||
{
|
{
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
CREATE PROCEDURE [dbo].[OrganizationUser_ReadByMinimumRole]
|
||||||
|
@OrganizationId UNIQUEIDENTIFIER,
|
||||||
|
@MinRole TINYINT
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
[dbo].[OrganizationUserUserDetailsView]
|
||||||
|
WHERE
|
||||||
|
OrganizationId = @OrganizationId
|
||||||
|
AND [Type] <= @MinRole
|
||||||
|
END
|
@ -0,0 +1,21 @@
|
|||||||
|
IF OBJECT_ID('[dbo].[OrganizationUser_ReadByMinimumRole]') IS NOT NULL
|
||||||
|
BEGIN
|
||||||
|
DROP PROCEDURE [dbo].[OrganizationUser_ReadByMinimumRole]
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE PROCEDURE [dbo].[OrganizationUser_ReadByMinimumRole]
|
||||||
|
@OrganizationId UNIQUEIDENTIFIER,
|
||||||
|
@MinRole TINYINT
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
[dbo].[OrganizationUserUserDetailsView]
|
||||||
|
WHERE
|
||||||
|
OrganizationId = @OrganizationId
|
||||||
|
AND [Type] <= @MinRole
|
||||||
|
END
|
Loading…
Reference in New Issue
Block a user