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

apis for managing collection users

This commit is contained in:
Kyle Spearrin 2018-10-17 22:18:03 -04:00
parent 7db36e0005
commit 33bfd12b7d
11 changed files with 81 additions and 121 deletions

View File

@ -9,6 +9,7 @@ using Bit.Core.Exceptions;
using Bit.Core.Services;
using Bit.Core;
using Bit.Core.Models.Table;
using System.Collections.Generic;
namespace Bit.Api.Controllers
{
@ -95,13 +96,12 @@ namespace Bit.Api.Controllers
}
[HttpGet("{id}/users")]
public async Task<ListResponseModel<CollectionUserResponseModel>> GetUsers(string orgId, string id)
public async Task<ListResponseModel<SelectionReadOnlyResponseModel>> GetUsers(string orgId, string id)
{
var collection = await GetCollectionAsync(new Guid(id), new Guid(orgId));
var collectionUsers = await _collectionRepository.GetManyUserDetailsByIdAsync(collection.OrganizationId,
collection.Id);
var responses = collectionUsers.Select(c => new CollectionUserResponseModel(c));
return new ListResponseModel<CollectionUserResponseModel>(responses);
var collectionUsers = await _collectionRepository.GetManyUsersByIdAsync(collection.Id);
var responses = collectionUsers.Select(cu => new SelectionReadOnlyResponseModel(cu));
return new ListResponseModel<SelectionReadOnlyResponseModel>(responses);
}
[HttpPost("")]
@ -129,6 +129,13 @@ namespace Bit.Api.Controllers
return new CollectionResponseModel(collection);
}
[HttpPut("{id}/users")]
public async Task PutUsers(string orgId, string id, [FromBody]IEnumerable<SelectionReadOnlyRequestModel> model)
{
var collection = await GetCollectionAsync(new Guid(id), new Guid(orgId));
await _collectionRepository.UpdateUsersAsync(collection.Id, model?.Select(g => g.ToSelectionReadOnly()));
}
[HttpDelete("{id}")]
[HttpPost("{id}/delete")]
public async Task Delete(string orgId, string id)

View File

@ -1,34 +0,0 @@
using System;
using Bit.Core.Models.Data;
using Bit.Core.Enums;
namespace Bit.Core.Models.Api
{
public class CollectionUserResponseModel : ResponseModel
{
public CollectionUserResponseModel(CollectionUserDetails collectionUser)
: base("collectionUser")
{
if(collectionUser == null)
{
throw new ArgumentNullException(nameof(collectionUser));
}
OrganizationUserId = collectionUser.OrganizationUserId.ToString();
AccessAll = collectionUser.AccessAll;
Name = collectionUser.Name;
Email = collectionUser.Email;
Type = collectionUser.Type;
Status = collectionUser.Status;
ReadOnly = collectionUser.ReadOnly;
}
public string OrganizationUserId { get; set; }
public bool AccessAll { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public OrganizationUserType Type { get; set; }
public OrganizationUserStatusType Status { get; set; }
public bool ReadOnly { get; set; }
}
}

View File

@ -3,9 +3,10 @@ using Bit.Core.Models.Data;
namespace Bit.Core.Models.Api
{
public class SelectionReadOnlyResponseModel
public class SelectionReadOnlyResponseModel : ResponseModel
{
public SelectionReadOnlyResponseModel(SelectionReadOnly selection)
: base("selection")
{
if(selection == null)
{

View File

@ -1,15 +0,0 @@
using System;
namespace Bit.Core.Models.Data
{
public class CollectionUserDetails
{
public Guid OrganizationUserId { get; set; }
public bool AccessAll { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public Enums.OrganizationUserStatusType Status { get; set; }
public Enums.OrganizationUserType Type { get; set; }
public bool ReadOnly { get; set; }
}
}

View File

@ -14,10 +14,10 @@ namespace Bit.Core.Repositories
Task<ICollection<Collection>> GetManyByOrganizationIdAsync(Guid organizationId);
Task<CollectionDetails> GetByIdAsync(Guid id, Guid userId);
Task<ICollection<CollectionDetails>> GetManyByUserIdAsync(Guid userId);
Task<ICollection<CollectionUserDetails>> GetManyUserDetailsByIdAsync(Guid organizationId, Guid collectionId);
Task CreateAsync(Collection obj, IEnumerable<SelectionReadOnly> groups);
Task ReplaceAsync(Collection obj, IEnumerable<SelectionReadOnly> groups);
Task DeleteUserAsync(Guid collectionId, Guid organizationUserId);
Task UpdateUsersAsync(Guid id, IEnumerable<SelectionReadOnly> users);
Task<ICollection<SelectionReadOnly>> GetManyUsersByIdAsync(Guid id);
}
}

View File

@ -111,24 +111,6 @@ namespace Bit.Core.Repositories.SqlServer
}
}
public async Task<ICollection<CollectionUserDetails>> GetManyUserDetailsByIdAsync(Guid organizationId,
Guid collectionId)
{
using(var connection = new SqlConnection(ConnectionString))
{
var results = await connection.QueryAsync<CollectionUserDetails>(
$"[{Schema}].[CollectionUserDetails_ReadByCollectionId]",
new { OrganizationId = organizationId, CollectionId = collectionId },
commandType: CommandType.StoredProcedure);
// Return distinct Id results. If at least one of the grouped results is not ReadOnly, that we return it.
return results
.GroupBy(c => c.OrganizationUserId)
.Select(g => g.OrderBy(og => og.ReadOnly).First())
.ToList();
}
}
public async Task CreateAsync(Collection obj, IEnumerable<SelectionReadOnly> groups)
{
obj.SetNewId();
@ -185,12 +167,25 @@ namespace Bit.Core.Repositories.SqlServer
using(var connection = new SqlConnection(ConnectionString))
{
var results = await connection.ExecuteAsync(
$"[{Schema}].[Collection_UpdateUsers]",
$"[{Schema}].[CollectionUser_UpdateUsers]",
new { Id = id, Users = users.ToArrayTVP() },
commandType: CommandType.StoredProcedure);
}
}
public async Task<ICollection<SelectionReadOnly>> GetManyUsersByIdAsync(Guid id)
{
using(var connection = new SqlConnection(ConnectionString))
{
var results = await connection.QueryAsync<SelectionReadOnly>(
$"[{Schema}].[CollectionUser_ReadByCollectionId]",
new { CollectionId = id },
commandType: CommandType.StoredProcedure);
return results.ToList();
}
}
public class CollectionWithGroups : Collection
{
public DataTable Groups { get; set; }

View File

@ -160,7 +160,7 @@
<Build Include="dbo\Stored Procedures\User_ReadById.sql" />
<Build Include="dbo\Stored Procedures\CollectionUser_Delete.sql" />
<Build Include="dbo\Stored Procedures\User_Update.sql" />
<Build Include="dbo\Stored Procedures\CollectionUserDetails_ReadByCollectionId.sql" />
<Build Include="dbo\Stored Procedures\CollectionUser_ReadByCollectionId.sql" />
<Build Include="dbo\Stored Procedures\Group_Create.sql" />
<Build Include="dbo\Stored Procedures\Group_CreateWithCollections.sql" />
<Build Include="dbo\Stored Procedures\Group_DeleteById.sql" />
@ -236,6 +236,6 @@
<Build Include="dbo\Stored Procedures\Collection_ReadByIdUserId.sql" />
<Build Include="dbo\Stored Procedures\Collection_ReadWithGroupsByIdUserId.sql" />
<Build Include="dbo\Stored Procedures\Collection_CreateWithGroups.sql" />
<Build Include="dbo\Stored Procedures\Collection_UpdateUsers.sql" />
<Build Include="dbo\Stored Procedures\CollectionUser_UpdateUsers.sql" />
</ItemGroup>
</Project>

View File

@ -1,42 +0,0 @@
CREATE PROCEDURE [dbo].[CollectionUserDetails_ReadByCollectionId]
@CollectionId UNIQUEIDENTIFIER,
@OrganizationId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
SELECT
OU.[Id] AS [OrganizationUserId],
CASE
WHEN OU.[AccessAll] = 1 OR G.[AccessAll] = 1 THEN 1
ELSE 0
END [AccessAll],
U.[Name],
ISNULL(U.[Email], OU.[Email]) Email,
OU.[Status],
OU.[Type],
CASE
WHEN OU.[AccessAll] = 1 OR CU.[ReadOnly] = 0 OR G.[AccessAll] = 1 OR CG.[ReadOnly] = 0 THEN 0
ELSE 1
END [ReadOnly]
FROM
[dbo].[OrganizationUser] OU
LEFT JOIN
[dbo].[CollectionUser] CU ON OU.[AccessAll] = 0 AND CU.[OrganizationUserId] = OU.[Id] AND CU.[CollectionId] = @CollectionId
LEFT JOIN
[dbo].[GroupUser] GU ON CU.[CollectionId] IS NULL AND OU.[AccessAll] = 0 AND GU.[OrganizationUserId] = OU.[Id]
LEFT JOIN
[dbo].[Group] G ON G.[Id] = GU.[GroupId]
LEFT JOIN
[dbo].[CollectionGroup] CG ON G.[AccessAll] = 0 AND CG.[GroupId] = GU.[GroupId] AND CG.[CollectionId] = @CollectionId
LEFT JOIN
[dbo].[User] U ON U.[Id] = OU.[UserId]
WHERE
OU.[OrganizationId] = @OrganizationId
AND (
CU.[CollectionId] IS NOT NULL
OR CG.[CollectionId] IS NOT NULL
OR OU.[AccessAll] = 1
OR G.[AccessAll] = 1
)
END

View File

@ -0,0 +1,14 @@
CREATE PROCEDURE [dbo].[CollectionUser_ReadByCollectionId]
@CollectionId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
SELECT
[OrganizationUserId] [Id],
[ReadOnly]
FROM
[dbo].[CollectionUser]
WHERE
[CollectionId] = @CollectionId
END

View File

@ -1,4 +1,4 @@
CREATE PROCEDURE [dbo].[Collection_UpdateUsers]
CREATE PROCEDURE [dbo].[CollectionUser_UpdateUsers]
@Id UNIQUEIDENTIFIER,
@Users AS [dbo].[SelectionReadOnlyArray] READONLY
AS

View File

@ -117,7 +117,13 @@ BEGIN
END
GO
CREATE PROCEDURE [dbo].[Collection_UpdateUsers]
IF OBJECT_ID('[dbo].[CollectionUser_UpdateUsers]') IS NOT NULL
BEGIN
DROP PROCEDURE [dbo].[CollectionUser_UpdateUsers]
END
GO
CREATE PROCEDURE [dbo].[CollectionUser_UpdateUsers]
@Id UNIQUEIDENTIFIER,
@Users AS [dbo].[SelectionReadOnlyArray] READONLY
AS
@ -159,3 +165,31 @@ BEGIN
EXEC [dbo].[User_BumpAccountRevisionDateByCollectionId] @Id, @OrganizationId
END
GO
IF OBJECT_ID('[dbo].[CollectionUserDetails_ReadByCollectionId]') IS NOT NULL
BEGIN
DROP PROCEDURE [dbo].[CollectionUserDetails_ReadByCollectionId]
END
GO
IF OBJECT_ID('[dbo].[CollectionUser_ReadByCollectionId]') IS NOT NULL
BEGIN
DROP PROCEDURE [dbo].[CollectionUser_ReadByCollectionId]
END
GO
CREATE PROCEDURE [dbo].[CollectionUser_ReadByCollectionId]
@CollectionId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
SELECT
[OrganizationUserId] [Id],
[ReadOnly]
FROM
[dbo].[CollectionUser]
WHERE
[CollectionId] = @CollectionId
END
GO