1
0
mirror of https://github.com/bitwarden/server.git synced 2024-11-22 12:15:36 +01:00

Bulk re-invite of org users (#1316)

* Add APIs for Bulk reinvinte

* Resolve review comments.
This commit is contained in:
Oscar Hinton 2021-05-12 11:18:25 +02:00 committed by GitHub
parent 69c2673f1f
commit e2f633dace
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 98 additions and 1 deletions

View File

@ -129,6 +129,19 @@ namespace Bit.Api.Controllers
var userId = _userService.GetProperUserId(User);
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")]
public async Task Reinvite(string orgId, string id)

View File

@ -1,4 +1,5 @@
using Bit.Core.Models.Data;
using System;
using Bit.Core.Models.Data;
using Bit.Core.Models.Table;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@ -89,4 +90,10 @@ namespace Bit.Core.Models.Api
{
public string ResetPasswordKey { get; set; }
}
public class OrganizationUserBulkReinviteRequestModel
{
[Required]
public IEnumerable<Guid> Ids { get; set; }
}
}

View File

@ -29,6 +29,7 @@ namespace Bit.Core.Repositories
Task CreateAsync(OrganizationUser obj, IEnumerable<SelectionReadOnly> collections);
Task ReplaceAsync(OrganizationUser obj, IEnumerable<SelectionReadOnly> collections);
Task<ICollection<OrganizationUser>> GetManyByManyUsersAsync(IEnumerable<Guid> userIds);
Task<ICollection<OrganizationUser>> GetManyAsync(IEnumerable<Guid> Ids);
Task<OrganizationUser> GetByOrganizationEmailAsync(Guid organizationId, string email);
}
}

View File

@ -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)
{
using (var connection = new SqlConnection(ConnectionString))

View File

@ -33,6 +33,7 @@ namespace Bit.Core.Services
Task<OrganizationUser> InviteUserAsync(Guid organizationId, Guid? invitingUserId, string email,
OrganizationUserType type, bool accessAll, string externalId, IEnumerable<SelectionReadOnly> collections);
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<OrganizationUser> AcceptUserAsync(Guid organizationUserId, User user, string token,
IUserService userService);

View File

@ -1076,6 +1076,25 @@ namespace Bit.Core.Services
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)
{
var orgUser = await _organizationUserRepository.GetByIdAsync(organizationUserId);

View File

@ -112,6 +112,7 @@
<Build Include="dbo\Stored Procedures\OrganizationUser_DeleteById.sql" />
<Build Include="dbo\Stored Procedures\Grant_Delete.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\Grant_ReadByKey.sql" />
<Build Include="dbo\Stored Procedures\Grant_Read.sql" />

View 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

View 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