mirror of
https://github.com/bitwarden/server.git
synced 2025-05-30 15:50:33 -05:00
Bulk re-invite of org users (#1316)
* Add APIs for Bulk reinvinte * Resolve review comments.
This commit is contained in:
parent
69c2673f1f
commit
e2f633dace
@ -130,6 +130,19 @@ namespace Bit.Api.Controllers
|
|||||||
var result = await _organizationService.InviteUserAsync(orgGuidId, userId.Value, null, new OrganizationUserInvite(model));
|
var result = await _organizationService.InviteUserAsync(orgGuidId, userId.Value, null, new OrganizationUserInvite(model));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost("reinvite")]
|
||||||
|
public async Task BulkReinvite(string orgId, [FromBody]OrganizationUserBulkReinviteRequestModel model)
|
||||||
|
{
|
||||||
|
var orgGuidId = new Guid(orgId);
|
||||||
|
if (!_currentContext.ManageUsers(orgGuidId))
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
var userId = _userService.GetProperUserId(User);
|
||||||
|
await _organizationService.ResendInvitesAsync(orgGuidId, userId.Value, model.Ids);
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost("{id}/reinvite")]
|
[HttpPost("{id}/reinvite")]
|
||||||
public async Task Reinvite(string orgId, string id)
|
public async Task Reinvite(string orgId, string id)
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Bit.Core.Models.Data;
|
using System;
|
||||||
|
using Bit.Core.Models.Data;
|
||||||
using Bit.Core.Models.Table;
|
using Bit.Core.Models.Table;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
@ -89,4 +90,10 @@ namespace Bit.Core.Models.Api
|
|||||||
{
|
{
|
||||||
public string ResetPasswordKey { get; set; }
|
public string ResetPasswordKey { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class OrganizationUserBulkReinviteRequestModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public IEnumerable<Guid> Ids { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ namespace Bit.Core.Repositories
|
|||||||
Task CreateAsync(OrganizationUser obj, IEnumerable<SelectionReadOnly> collections);
|
Task CreateAsync(OrganizationUser obj, IEnumerable<SelectionReadOnly> collections);
|
||||||
Task ReplaceAsync(OrganizationUser obj, IEnumerable<SelectionReadOnly> collections);
|
Task ReplaceAsync(OrganizationUser obj, IEnumerable<SelectionReadOnly> collections);
|
||||||
Task<ICollection<OrganizationUser>> GetManyByManyUsersAsync(IEnumerable<Guid> userIds);
|
Task<ICollection<OrganizationUser>> GetManyByManyUsersAsync(IEnumerable<Guid> userIds);
|
||||||
|
Task<ICollection<OrganizationUser>> GetManyAsync(IEnumerable<Guid> Ids);
|
||||||
Task<OrganizationUser> GetByOrganizationEmailAsync(Guid organizationId, string email);
|
Task<OrganizationUser> GetByOrganizationEmailAsync(Guid organizationId, string email);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -260,6 +260,19 @@ namespace Bit.Core.Repositories.SqlServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ICollection<OrganizationUser>> GetManyAsync(IEnumerable<Guid> Ids)
|
||||||
|
{
|
||||||
|
using (var connection = new SqlConnection(ConnectionString))
|
||||||
|
{
|
||||||
|
var results = await connection.QueryAsync<OrganizationUser>(
|
||||||
|
"[dbo].[OrganizationUser_ReadByIds]",
|
||||||
|
new { Ids = Ids.ToGuidIdArrayTVP() },
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
|
|
||||||
|
return results.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<OrganizationUser> GetByOrganizationEmailAsync(Guid organizationId, string email)
|
public async Task<OrganizationUser> GetByOrganizationEmailAsync(Guid organizationId, string email)
|
||||||
{
|
{
|
||||||
using (var connection = new SqlConnection(ConnectionString))
|
using (var connection = new SqlConnection(ConnectionString))
|
||||||
|
@ -33,6 +33,7 @@ namespace Bit.Core.Services
|
|||||||
Task<OrganizationUser> InviteUserAsync(Guid organizationId, Guid? invitingUserId, string email,
|
Task<OrganizationUser> InviteUserAsync(Guid organizationId, Guid? invitingUserId, string email,
|
||||||
OrganizationUserType type, bool accessAll, string externalId, IEnumerable<SelectionReadOnly> collections);
|
OrganizationUserType type, bool accessAll, string externalId, IEnumerable<SelectionReadOnly> collections);
|
||||||
Task<List<OrganizationUser>> InviteUserAsync(Guid organizationId, Guid? invitingUserId, string externalId, OrganizationUserInvite orgUserInvite);
|
Task<List<OrganizationUser>> InviteUserAsync(Guid organizationId, Guid? invitingUserId, string externalId, OrganizationUserInvite orgUserInvite);
|
||||||
|
Task ResendInvitesAsync(Guid organizationId, Guid? invitingUserId, IEnumerable<Guid> organizationUsersId);
|
||||||
Task ResendInviteAsync(Guid organizationId, Guid? invitingUserId, Guid organizationUserId);
|
Task ResendInviteAsync(Guid organizationId, Guid? invitingUserId, Guid organizationUserId);
|
||||||
Task<OrganizationUser> AcceptUserAsync(Guid organizationUserId, User user, string token,
|
Task<OrganizationUser> AcceptUserAsync(Guid organizationUserId, User user, string token,
|
||||||
IUserService userService);
|
IUserService userService);
|
||||||
|
@ -1076,6 +1076,25 @@ namespace Bit.Core.Services
|
|||||||
return orgUsers;
|
return orgUsers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task ResendInvitesAsync(Guid organizationId, Guid? invitingUserId,
|
||||||
|
IEnumerable<Guid> organizationUsersId)
|
||||||
|
{
|
||||||
|
var orgUsers = await _organizationUserRepository.GetManyAsync(organizationUsersId);
|
||||||
|
var filteredUsers = orgUsers
|
||||||
|
.Where(u => u.Status == OrganizationUserStatusType.Invited && u.OrganizationId == organizationId);
|
||||||
|
|
||||||
|
if (!filteredUsers.Any())
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Users invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var org = await GetOrgById(organizationId);
|
||||||
|
foreach (var orgUser in filteredUsers)
|
||||||
|
{
|
||||||
|
await SendInviteAsync(orgUser, org);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task ResendInviteAsync(Guid organizationId, Guid? invitingUserId, Guid organizationUserId)
|
public async Task ResendInviteAsync(Guid organizationId, Guid? invitingUserId, Guid organizationUserId)
|
||||||
{
|
{
|
||||||
var orgUser = await _organizationUserRepository.GetByIdAsync(organizationUserId);
|
var orgUser = await _organizationUserRepository.GetByIdAsync(organizationUserId);
|
||||||
|
@ -112,6 +112,7 @@
|
|||||||
<Build Include="dbo\Stored Procedures\OrganizationUser_DeleteById.sql" />
|
<Build Include="dbo\Stored Procedures\OrganizationUser_DeleteById.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\Grant_Delete.sql" />
|
<Build Include="dbo\Stored Procedures\Grant_Delete.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\OrganizationUser_ReadById.sql" />
|
<Build Include="dbo\Stored Procedures\OrganizationUser_ReadById.sql" />
|
||||||
|
<Build Include="dbo\Stored Procedures\OrganizationUser_ReadByIds.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\OrganizationUser_ReadByOrganizationId.sql" />
|
<Build Include="dbo\Stored Procedures\OrganizationUser_ReadByOrganizationId.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\Grant_ReadByKey.sql" />
|
<Build Include="dbo\Stored Procedures\Grant_ReadByKey.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\Grant_Read.sql" />
|
<Build Include="dbo\Stored Procedures\Grant_Read.sql" />
|
||||||
|
18
src/Sql/dbo/Stored Procedures/OrganizationUser_ReadByIds.sql
Normal file
18
src/Sql/dbo/Stored Procedures/OrganizationUser_ReadByIds.sql
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
CREATE PROCEDURE [dbo].[OrganizationUser_ReadByIds]
|
||||||
|
@Ids AS [dbo].[GuidIdArray] READONLY
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
IF (SELECT COUNT(1) FROM @Ids) < 1
|
||||||
|
BEGIN
|
||||||
|
RETURN(-1)
|
||||||
|
END
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
[dbo].[OrganizationUserView]
|
||||||
|
WHERE
|
||||||
|
[Id] IN (SELECT [Id] FROM @Ids)
|
||||||
|
END
|
24
util/Migrator/DbScripts/2021-05-11_00_BulkReinvite.sql
Normal file
24
util/Migrator/DbScripts/2021-05-11_00_BulkReinvite.sql
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
IF OBJECT_ID('[dbo].[OrganizationUser_ReadByIds]') IS NOT NULL
|
||||||
|
BEGIN
|
||||||
|
DROP FUNCTION [dbo].[OrganizationUser_ReadByIds]
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE PROCEDURE [dbo].[OrganizationUser_ReadByIds]
|
||||||
|
@Ids AS [dbo].[GuidIdArray] READONLY
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
IF (SELECT COUNT(1) FROM @Ids) < 1
|
||||||
|
BEGIN
|
||||||
|
RETURN(-1)
|
||||||
|
END
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
[dbo].[OrganizationUserView]
|
||||||
|
WHERE
|
||||||
|
[Id] IN (SELECT [Id] FROM @Ids)
|
||||||
|
END
|
Loading…
x
Reference in New Issue
Block a user