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

org user subvaults apis

This commit is contained in:
Kyle Spearrin 2017-03-11 22:42:27 -05:00
parent 4a9206b992
commit cfb4d1453c
13 changed files with 124 additions and 54 deletions

View File

@ -58,7 +58,8 @@ namespace Bit.Api.Controllers
public async Task Invite(string orgId, [FromBody]OrganizationUserInviteRequestModel model)
{
var user = await _userService.GetUserByPrincipalAsync(User);
var result = await _organizationService.InviteUserAsync(new Guid(orgId), model.Email);
var result = await _organizationService.InviteUserAsync(new Guid(orgId), model.Email,
model.Subvaults.Select(s => s.ToSubvaultUser()));
}
[HttpPut("{id}/accept")]

View File

@ -7,6 +7,7 @@ namespace Bit.Core.Models.Api
public class OrganizationUserInviteRequestModel
{
public string Email { get; set; }
public IEnumerable<OrganizationUserSubvaultRequestModel> Subvaults { get; set; }
}
public class OrganizationUserAcceptRequestModel
@ -22,31 +23,35 @@ namespace Bit.Core.Models.Api
public class OrganizationUserUpdateRequestModel
{
public Enums.OrganizationUserType Type { get; set; }
public IEnumerable<Subvault> Subvaults { get; set; }
public IEnumerable<OrganizationUserSubvaultRequestModel> Subvaults { get; set; }
}
public class Subvault
public class OrganizationUserSubvaultRequestModel
{
public string Id { get; set; }
public string SubvaultId { get; set; }
public bool Admin { get; set; }
public bool ReadOnly { get; set; }
public SubvaultUser ToSubvaultUser()
{
public string Id { get; set; }
public string SubvaultId { get; set; }
public bool Admin { get; set; }
public bool ReadOnly { get; set; }
public SubvaultUser ToSubvaultUser()
var subvault = new SubvaultUser
{
var user = new SubvaultUser
{
SubvaultId = new Guid(SubvaultId),
Admin = Admin,
ReadOnly = ReadOnly
};
Admin = Admin,
ReadOnly = ReadOnly
};
if(string.IsNullOrWhiteSpace(Id))
{
user.Id = new Guid(Id);
}
return user;
if(!string.IsNullOrWhiteSpace(SubvaultId))
{
subvault.SubvaultId = new Guid(SubvaultId);
}
if(!string.IsNullOrWhiteSpace(Id))
{
subvault.Id = new Guid(Id);
}
return subvault;
}
}
}

View File

@ -2,7 +2,6 @@
using Bit.Core.Enums;
using Bit.Core.Models.Data;
using System.Collections.Generic;
using Bit.Core.Models.Table;
using System.Linq;
namespace Bit.Core.Models.Api
@ -36,12 +35,13 @@ namespace Bit.Core.Models.Api
public class OrganizationUserDetailsResponseModel : OrganizationUserResponseModel
{
public OrganizationUserDetailsResponseModel(OrganizationUserUserDetails organizationUser,
IEnumerable<Subvault> subvaults)
IEnumerable<SubvaultUserDetails> subvaults)
: base(organizationUser, "organizationUserDetails")
{
Subvaults = new ListResponseModel<SubvaultResponseModel>(subvaults.Select(s => new SubvaultResponseModel(s)));
Subvaults = new ListResponseModel<OrganizationUserSubvaultResponseModel>(
subvaults.Select(s => new OrganizationUserSubvaultResponseModel(s)));
}
public ListResponseModel<SubvaultResponseModel> Subvaults { get; set; }
public ListResponseModel<OrganizationUserSubvaultResponseModel> Subvaults { get; set; }
}
}

View File

@ -0,0 +1,30 @@
using System;
using Bit.Core.Models.Data;
namespace Bit.Core.Models.Api
{
public class OrganizationUserSubvaultResponseModel : ResponseModel
{
public OrganizationUserSubvaultResponseModel(SubvaultUserDetails details,
string obj = "organizationUserSubvault")
: base(obj)
{
if(details == null)
{
throw new ArgumentNullException(nameof(details));
}
Id = details.Id.ToString();
Name = details.Name;
SubvaultId = details.SubvaultId.ToString();
ReadOnly = details.ReadOnly;
Admin = details.Admin;
}
public string Id { get; set; }
public string Name { get; set; }
public string SubvaultId { get; set; }
public bool ReadOnly { get; set; }
public bool Admin { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using System;
namespace Bit.Core.Models.Data
{
public class SubvaultUserDetails
{
public Guid Id { get; set; }
public Guid OrganizationUserId { get; set; }
public string Name { get; set; }
public Guid SubvaultId { get; set; }
public bool ReadOnly { get; set; }
public bool Admin { get; set; }
}
}

View File

@ -9,7 +9,7 @@ namespace Bit.Core.Repositories
public interface IOrganizationUserRepository : IRepository<OrganizationUser, Guid>
{
Task<OrganizationUser> GetByOrganizationAsync(Guid organizationId, Guid userId);
Task<Tuple<OrganizationUserUserDetails, ICollection<Subvault>>> GetDetailsByIdAsync(Guid id);
Task<Tuple<OrganizationUserUserDetails, ICollection<SubvaultUserDetails>>> GetDetailsByIdAsync(Guid id);
Task<ICollection<OrganizationUserUserDetails>> GetManyDetailsByOrganizationAsync(Guid organizationId);
Task<ICollection<OrganizationUserOrganizationDetails>> GetManyDetailsByUserAsync(Guid userId);
}

View File

@ -33,7 +33,7 @@ namespace Bit.Core.Repositories.SqlServer
}
}
public async Task<Tuple<OrganizationUserUserDetails, ICollection<Subvault>>> GetDetailsByIdAsync(Guid id)
public async Task<Tuple<OrganizationUserUserDetails, ICollection<SubvaultUserDetails>>> GetDetailsByIdAsync(Guid id)
{
using(var connection = new SqlConnection(ConnectionString))
{
@ -43,8 +43,8 @@ namespace Bit.Core.Repositories.SqlServer
commandType: CommandType.StoredProcedure);
var user = (await results.ReadAsync<OrganizationUserUserDetails>()).SingleOrDefault();
var subvaults = (await results.ReadAsync<Subvault>()).ToList();
return new Tuple<OrganizationUserUserDetails, ICollection<Subvault>>(user, subvaults);
var subvaults = (await results.ReadAsync<SubvaultUserDetails>()).ToList();
return new Tuple<OrganizationUserUserDetails, ICollection<SubvaultUserDetails>>(user, subvaults);
}
}

View File

@ -9,9 +9,9 @@ namespace Bit.Core.Services
public interface IOrganizationService
{
Task<Tuple<Organization, OrganizationUser>> SignUpAsync(OrganizationSignup organizationSignup);
Task<OrganizationUser> InviteUserAsync(Guid organizationId, string email);
Task<OrganizationUser> InviteUserAsync(Guid organizationId, string email, IEnumerable<SubvaultUser> subvaults);
Task<OrganizationUser> AcceptUserAsync(Guid organizationUserId, User user, string token);
Task<OrganizationUser> ConfirmUserAsync(Guid organizationUserId, string key);
Task<OrganizationUser> SaveUserAsync(OrganizationUser user, IEnumerable<SubvaultUser> subvaults);
Task SaveUserAsync(OrganizationUser user, IEnumerable<SubvaultUser> subvaults);
}
}

View File

@ -90,7 +90,8 @@ namespace Bit.Core.Services
}
}
public async Task<OrganizationUser> InviteUserAsync(Guid organizationId, string email)
public async Task<OrganizationUser> InviteUserAsync(Guid organizationId, string email,
IEnumerable<SubvaultUser> subvaults)
{
var orgUser = new OrganizationUser
{
@ -105,6 +106,7 @@ namespace Bit.Core.Services
};
await _organizationUserRepository.CreateAsync(orgUser);
await SaveUserSubvaultsAsync(orgUser, subvaults, true);
// TODO: send email
@ -149,7 +151,7 @@ namespace Bit.Core.Services
return orgUser;
}
public async Task<OrganizationUser> SaveUserAsync(OrganizationUser user, IEnumerable<SubvaultUser> subvaults)
public async Task SaveUserAsync(OrganizationUser user, IEnumerable<SubvaultUser> subvaults)
{
if(user.Id.Equals(default(Guid)))
{
@ -157,28 +159,36 @@ namespace Bit.Core.Services
}
await _organizationUserRepository.ReplaceAsync(user);
await SaveUserSubvaultsAsync(user, subvaults, false);
}
private async Task SaveUserSubvaultsAsync(OrganizationUser user, IEnumerable<SubvaultUser> subvaults, bool newUser)
{
var orgSubvaults = await _subvaultRepository.GetManyByOrganizationIdAsync(user.OrganizationId);
var currentUserSubvaults = await _subvaultUserRepository.GetManyByOrganizationUserIdAsync(user.Id);
var currentUserSubvaults = newUser ? null : await _subvaultUserRepository.GetManyByOrganizationUserIdAsync(user.Id);
// Let's make sure all these belong to this user and organization.
var filteredSubvaults = subvaults.Where(s =>
orgSubvaults.Any(os => os.Id == s.SubvaultId) &&
(s.Id == default(Guid) || currentUserSubvaults.Any(cs => cs.Id == s.Id)));
var subvaultsToDelete = currentUserSubvaults.Where(cs => !subvaults.Any(s => s.Id == cs.Id));
var filteredSubvaults = subvaults.Where(s => orgSubvaults.Any(os => os.Id == s.SubvaultId));
if(!newUser)
{
filteredSubvaults = filteredSubvaults.Where(s =>
s.Id == default(Guid) || currentUserSubvaults.Any(cs => cs.Id == s.Id));
}
foreach(var subvault in filteredSubvaults)
{
subvault.OrganizationUserId = user.Id;
await _subvaultUserRepository.UpsertAsync(subvault);
}
foreach(var subvault in subvaultsToDelete)
if(!newUser)
{
await _subvaultUserRepository.DeleteAsync(subvault);
var subvaultsToDelete = currentUserSubvaults.Where(cs => !subvaults.Any(s => s.Id == cs.Id));
foreach(var subvault in subvaultsToDelete)
{
await _subvaultUserRepository.DeleteAsync(subvault);
}
}
return user;
}
}
}

View File

@ -156,7 +156,8 @@
<Build Include="dbo\Stored Procedures\OrganizationUserUserDetails_ReadById.sql" />
<Build Include="dbo\Stored Procedures\OrganizationUserUserDetails_ReadByOrganizationId.sql" />
<Build Include="dbo\Stored Procedures\Subvault_ReadByIdAdminUserId.sql" />
<Build Include="dbo\Stored Procedures\Subvault_ReadByUserId.sql" />
<Build Include="dbo\Stored Procedures\SubvaultUserDetails_ReadByUserId.sql" />
<Build Include="dbo\Stored Procedures\Subvault_ReadByOrganizationIdAdminUserId.sql" />
<Build Include="dbo\Views\SubvaultUserDetailsView.sql" />
</ItemGroup>
</Project>

View File

@ -12,11 +12,9 @@ BEGIN
[Id] = @Id
SELECT
S.*
*
FROM
[dbo].[SubvaultView] S
INNER JOIN
[dbo].[SubvaultUser] SU ON SU.[SubvaultId] = S.[Id]
[dbo].[SubvaultUserDetailsView]
WHERE
SU.[OrganizationUserId] = @Id
[OrganizationUserId] = @Id
END

View File

@ -1,15 +1,13 @@
CREATE PROCEDURE [dbo].[Subvault_ReadByUserId]
CREATE PROCEDURE [dbo].[SubvaultUserDetails_ReadByUserId]
@UserId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
SELECT
S.*
SU.*
FROM
[dbo].[SubvaultView] S
INNER JOIN
[SubvaultUser] SU ON SU.[SubvaultId] = S.[Id]
[dbo].[SubvaultUserDetailsView] SU
INNER JOIN
[OrganizationUser] OU ON SU.[OrganizationUserId] = OU.[Id]
WHERE

View File

@ -0,0 +1,13 @@
CREATE VIEW [dbo].[SubvaultUserDetailsView]
AS
SELECT
SU.[Id],
SU.[OrganizationUserId],
S.[Name],
S.[Id] SubvaultId,
SU.[ReadOnly],
SU.[Admin]
FROM
[dbo].[SubvaultUser] SU
INNER JOIN
[dbo].[Subvault] S ON S.[Id] = SU.[SubvaultId]