1
0
mirror of https://github.com/bitwarden/server.git synced 2025-05-20 19:14:32 -05:00

manager group user apis

This commit is contained in:
Kyle Spearrin 2018-10-18 08:38:22 -04:00
parent 33bfd12b7d
commit 45a77c8903
13 changed files with 102 additions and 106 deletions

View File

@ -96,12 +96,12 @@ namespace Bit.Api.Controllers
} }
[HttpGet("{id}/users")] [HttpGet("{id}/users")]
public async Task<ListResponseModel<SelectionReadOnlyResponseModel>> GetUsers(string orgId, string id) public async Task<IEnumerable<SelectionReadOnlyResponseModel>> GetUsers(string orgId, string id)
{ {
var collection = await GetCollectionAsync(new Guid(id), new Guid(orgId)); var collection = await GetCollectionAsync(new Guid(id), new Guid(orgId));
var collectionUsers = await _collectionRepository.GetManyUsersByIdAsync(collection.Id); var collectionUsers = await _collectionRepository.GetManyUsersByIdAsync(collection.Id);
var responses = collectionUsers.Select(cu => new SelectionReadOnlyResponseModel(cu)); var responses = collectionUsers.Select(cu => new SelectionReadOnlyResponseModel(cu));
return new ListResponseModel<SelectionReadOnlyResponseModel>(responses); return responses;
} }
[HttpPost("")] [HttpPost("")]

View File

@ -8,6 +8,7 @@ using Bit.Core.Models.Api;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Services; using Bit.Core.Services;
using Bit.Core; using Bit.Core;
using System.Collections.Generic;
namespace Bit.Api.Controllers namespace Bit.Api.Controllers
{ {
@ -68,7 +69,7 @@ namespace Bit.Api.Controllers
} }
[HttpGet("{id}/users")] [HttpGet("{id}/users")]
public async Task<ListResponseModel<GroupUserResponseModel>> GetUsers(string orgId, string id) public async Task<IEnumerable<Guid>> GetUsers(string orgId, string id)
{ {
var idGuid = new Guid(id); var idGuid = new Guid(id);
var group = await _groupRepository.GetByIdAsync(idGuid); var group = await _groupRepository.GetByIdAsync(idGuid);
@ -77,9 +78,8 @@ namespace Bit.Api.Controllers
throw new NotFoundException(); throw new NotFoundException();
} }
var groups = await _groupRepository.GetManyUserDetailsByIdAsync(idGuid); var groupIds = await _groupRepository.GetManyUserIdsByIdAsync(idGuid);
var responses = groups.Select(g => new GroupUserResponseModel(g)); return groupIds;
return new ListResponseModel<GroupUserResponseModel>(responses);
} }
[HttpPost("")] [HttpPost("")]
@ -110,6 +110,17 @@ namespace Bit.Api.Controllers
return new GroupResponseModel(group); return new GroupResponseModel(group);
} }
[HttpPut("{id}/users")]
public async Task PutUsers(string orgId, string id, [FromBody]IEnumerable<Guid> model)
{
var group = await _groupRepository.GetByIdAsync(new Guid(id));
if(group == null || !_currentContext.OrganizationAdmin(group.OrganizationId))
{
throw new NotFoundException();
}
await _groupRepository.UpdateUsersAsync(group.Id, model);
}
[HttpDelete("{id}")] [HttpDelete("{id}")]
[HttpPost("{id}/delete")] [HttpPost("{id}/delete")]
public async Task Delete(string orgId, string id) public async Task Delete(string orgId, string id)

View File

@ -1,32 +0,0 @@
using System;
using Bit.Core.Models.Data;
using Bit.Core.Enums;
namespace Bit.Core.Models.Api
{
public class GroupUserResponseModel : ResponseModel
{
public GroupUserResponseModel(GroupUserDetails groupUser)
: base("groupUser")
{
if(groupUser == null)
{
throw new ArgumentNullException(nameof(groupUser));
}
OrganizationUserId = groupUser.OrganizationUserId.ToString();
AccessAll = groupUser.AccessAll;
Name = groupUser.Name;
Email = groupUser.Email;
Type = groupUser.Type;
Status = groupUser.Status;
}
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; }
}
}

View File

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

View File

@ -1,14 +0,0 @@
using System;
namespace Bit.Core.Models.Data
{
public class GroupUserDetails
{
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; }
}
}

View File

@ -10,8 +10,8 @@ namespace Bit.Core.Repositories
{ {
Task<Tuple<Group, ICollection<SelectionReadOnly>>> GetByIdWithCollectionsAsync(Guid id); Task<Tuple<Group, ICollection<SelectionReadOnly>>> GetByIdWithCollectionsAsync(Guid id);
Task<ICollection<Group>> GetManyByOrganizationIdAsync(Guid organizationId); Task<ICollection<Group>> GetManyByOrganizationIdAsync(Guid organizationId);
Task<ICollection<GroupUserDetails>> GetManyUserDetailsByIdAsync(Guid id);
Task<ICollection<Guid>> GetManyIdsByUserIdAsync(Guid organizationUserId); Task<ICollection<Guid>> GetManyIdsByUserIdAsync(Guid organizationUserId);
Task<ICollection<Guid>> GetManyUserIdsByIdAsync(Guid id);
Task<ICollection<GroupUser>> GetManyGroupUsersByOrganizationIdAsync(Guid organizationId); Task<ICollection<GroupUser>> GetManyGroupUsersByOrganizationIdAsync(Guid organizationId);
Task CreateAsync(Group obj, IEnumerable<SelectionReadOnly> collections); Task CreateAsync(Group obj, IEnumerable<SelectionReadOnly> collections);
Task ReplaceAsync(Group obj, IEnumerable<SelectionReadOnly> collections); Task ReplaceAsync(Group obj, IEnumerable<SelectionReadOnly> collections);

View File

@ -168,7 +168,7 @@ namespace Bit.Core.Repositories.SqlServer
{ {
var results = await connection.ExecuteAsync( var results = await connection.ExecuteAsync(
$"[{Schema}].[CollectionUser_UpdateUsers]", $"[{Schema}].[CollectionUser_UpdateUsers]",
new { Id = id, Users = users.ToArrayTVP() }, new { CollectionId = id, Users = users.ToArrayTVP() },
commandType: CommandType.StoredProcedure); commandType: CommandType.StoredProcedure);
} }
} }

View File

@ -51,19 +51,6 @@ namespace Bit.Core.Repositories.SqlServer
} }
} }
public async Task<ICollection<GroupUserDetails>> GetManyUserDetailsByIdAsync(Guid id)
{
using(var connection = new SqlConnection(ConnectionString))
{
var results = await connection.QueryAsync<GroupUserDetails>(
$"[{Schema}].[GroupUserDetails_ReadByGroupId]",
new { GroupId = id },
commandType: CommandType.StoredProcedure);
return results.ToList();
}
}
public async Task<ICollection<Guid>> GetManyIdsByUserIdAsync(Guid organizationUserId) public async Task<ICollection<Guid>> GetManyIdsByUserIdAsync(Guid organizationUserId)
{ {
using(var connection = new SqlConnection(ConnectionString)) using(var connection = new SqlConnection(ConnectionString))
@ -77,6 +64,19 @@ namespace Bit.Core.Repositories.SqlServer
} }
} }
public async Task<ICollection<Guid>> GetManyUserIdsByIdAsync(Guid id)
{
using(var connection = new SqlConnection(ConnectionString))
{
var results = await connection.QueryAsync<Guid>(
$"[{Schema}].[GroupUser_ReadOrganizationUserIdsByGroupId]",
new { GroupId = id },
commandType: CommandType.StoredProcedure);
return results.ToList();
}
}
public async Task<ICollection<GroupUser>> GetManyGroupUsersByOrganizationIdAsync(Guid organizationId) public async Task<ICollection<GroupUser>> GetManyGroupUsersByOrganizationIdAsync(Guid organizationId)
{ {
using(var connection = new SqlConnection(ConnectionString)) using(var connection = new SqlConnection(ConnectionString))

View File

@ -174,7 +174,6 @@
<Build Include="dbo\Stored Procedures\GroupUser_ReadGroupIdsByOrganizationUserId.sql" /> <Build Include="dbo\Stored Procedures\GroupUser_ReadGroupIdsByOrganizationUserId.sql" />
<Build Include="dbo\Stored Procedures\GroupUser_UpdateGroups.sql" /> <Build Include="dbo\Stored Procedures\GroupUser_UpdateGroups.sql" />
<Build Include="dbo\Stored Procedures\GroupUser_UpdateUsers.sql" /> <Build Include="dbo\Stored Procedures\GroupUser_UpdateUsers.sql" />
<Build Include="dbo\Stored Procedures\GroupUserDetails_ReadByGroupId.sql" />
<Build Include="dbo\Stored Procedures\OrganizationUser_CreateWithCollections.sql" /> <Build Include="dbo\Stored Procedures\OrganizationUser_CreateWithCollections.sql" />
<Build Include="dbo\Stored Procedures\OrganizationUser_ReadWithCollectionsById.sql" /> <Build Include="dbo\Stored Procedures\OrganizationUser_ReadWithCollectionsById.sql" />
<Build Include="dbo\Stored Procedures\OrganizationUser_UpdateWithCollections.sql" /> <Build Include="dbo\Stored Procedures\OrganizationUser_UpdateWithCollections.sql" />
@ -237,5 +236,6 @@
<Build Include="dbo\Stored Procedures\Collection_ReadWithGroupsByIdUserId.sql" /> <Build Include="dbo\Stored Procedures\Collection_ReadWithGroupsByIdUserId.sql" />
<Build Include="dbo\Stored Procedures\Collection_CreateWithGroups.sql" /> <Build Include="dbo\Stored Procedures\Collection_CreateWithGroups.sql" />
<Build Include="dbo\Stored Procedures\CollectionUser_UpdateUsers.sql" /> <Build Include="dbo\Stored Procedures\CollectionUser_UpdateUsers.sql" />
<Build Include="dbo\Stored Procedures\GroupUser_ReadOrganizationUserIdsByGroupId.sql" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,11 +1,18 @@
CREATE PROCEDURE [dbo].[CollectionUser_UpdateUsers] CREATE PROCEDURE [dbo].[CollectionUser_UpdateUsers]
@Id UNIQUEIDENTIFIER, @CollectionId UNIQUEIDENTIFIER,
@Users AS [dbo].[SelectionReadOnlyArray] READONLY @Users AS [dbo].[SelectionReadOnlyArray] READONLY
AS AS
BEGIN BEGIN
SET NOCOUNT ON SET NOCOUNT ON
DECLARE @OrganizationId UNIQUEIDENTIFIER = (SELECT [OrganizationId] FROM [dbo].[Collection] WHERE [Id] = @Id) DECLARE @OrgId UNIQUEIDENTIFIER = (
SELECT TOP 1
[OrganizationId]
FROM
[dbo].[Collection]
WHERE
[Id] = @CollectionId
)
;WITH [AvailableUsersCTE] AS( ;WITH [AvailableUsersCTE] AS(
SELECT SELECT
@ -13,29 +20,29 @@ BEGIN
FROM FROM
[dbo].[OrganizationUser] [dbo].[OrganizationUser]
WHERE WHERE
OrganizationId = @OrganizationId OrganizationId = @OrgId
) )
MERGE MERGE
[dbo].[CollectionUser] AS [Target] [dbo].[CollectionUser] AS [Target]
USING USING
@Users AS [Source] @Users AS [Source]
ON ON
[Target].[CollectionId] = @Id [Target].[CollectionId] = @CollectionId
AND [Target].[OrganizationUserId] = [Source].[Id] AND [Target].[OrganizationUserId] = [Source].[Id]
WHEN NOT MATCHED BY TARGET WHEN NOT MATCHED BY TARGET
AND [Source].[Id] IN (SELECT [Id] FROM [AvailableUsersCTE]) THEN AND [Source].[Id] IN (SELECT [Id] FROM [AvailableUsersCTE]) THEN
INSERT VALUES INSERT VALUES
( (
@Id, @CollectionId,
[Source].[Id], [Source].[Id],
[Source].[ReadOnly] [Source].[ReadOnly]
) )
WHEN MATCHED AND [Target].[ReadOnly] != [Source].[ReadOnly] THEN WHEN MATCHED AND [Target].[ReadOnly] != [Source].[ReadOnly] THEN
UPDATE SET [Target].[ReadOnly] = [Source].[ReadOnly] UPDATE SET [Target].[ReadOnly] = [Source].[ReadOnly]
WHEN NOT MATCHED BY SOURCE WHEN NOT MATCHED BY SOURCE
AND [Target].[CollectionId] = @Id THEN AND [Target].[CollectionId] = @CollectionId THEN
DELETE DELETE
; ;
EXEC [dbo].[User_BumpAccountRevisionDateByCollectionId] @Id, @OrganizationId EXEC [dbo].[User_BumpAccountRevisionDateByCollectionId] @CollectionId, @OrgId
END END

View File

@ -1,22 +0,0 @@
CREATE PROCEDURE [dbo].[GroupUserDetails_ReadByGroupId]
@GroupId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
SELECT
OU.[Id] AS [OrganizationUserId],
OU.[AccessAll],
U.[Name],
ISNULL(U.[Email], OU.[Email]) Email,
OU.[Status],
OU.[Type]
FROM
[dbo].[OrganizationUser] OU
INNER JOIN
[dbo].[GroupUser] GU ON GU.[OrganizationUserId] = OU.[Id]
LEFT JOIN
[dbo].[User] U ON U.[Id] = OU.[UserId]
WHERE
GU.[GroupId] = @GroupId
END

View File

@ -0,0 +1,13 @@
CREATE PROCEDURE [dbo].[GroupUser_ReadOrganizationUserIdsByGroupId]
@GroupId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
SELECT
[OrganizationUserId]
FROM
[dbo].[GroupUser]
WHERE
[GroupId] = @GroupId
END

View File

@ -124,13 +124,20 @@ END
GO GO
CREATE PROCEDURE [dbo].[CollectionUser_UpdateUsers] CREATE PROCEDURE [dbo].[CollectionUser_UpdateUsers]
@Id UNIQUEIDENTIFIER, @CollectionId UNIQUEIDENTIFIER,
@Users AS [dbo].[SelectionReadOnlyArray] READONLY @Users AS [dbo].[SelectionReadOnlyArray] READONLY
AS AS
BEGIN BEGIN
SET NOCOUNT ON SET NOCOUNT ON
DECLARE @OrganizationId UNIQUEIDENTIFIER = (SELECT [OrganizationId] FROM [dbo].[Collection] WHERE [Id] = @Id) DECLARE @OrgId UNIQUEIDENTIFIER = (
SELECT TOP 1
[OrganizationId]
FROM
[dbo].[Collection]
WHERE
[Id] = @CollectionId
)
;WITH [AvailableUsersCTE] AS( ;WITH [AvailableUsersCTE] AS(
SELECT SELECT
@ -138,31 +145,31 @@ BEGIN
FROM FROM
[dbo].[OrganizationUser] [dbo].[OrganizationUser]
WHERE WHERE
OrganizationId = @OrganizationId OrganizationId = @OrgId
) )
MERGE MERGE
[dbo].[CollectionUser] AS [Target] [dbo].[CollectionUser] AS [Target]
USING USING
@Users AS [Source] @Users AS [Source]
ON ON
[Target].[CollectionId] = @Id [Target].[CollectionId] = @CollectionId
AND [Target].[OrganizationUserId] = [Source].[Id] AND [Target].[OrganizationUserId] = [Source].[Id]
WHEN NOT MATCHED BY TARGET WHEN NOT MATCHED BY TARGET
AND [Source].[Id] IN (SELECT [Id] FROM [AvailableUsersCTE]) THEN AND [Source].[Id] IN (SELECT [Id] FROM [AvailableUsersCTE]) THEN
INSERT VALUES INSERT VALUES
( (
@Id, @CollectionId,
[Source].[Id], [Source].[Id],
[Source].[ReadOnly] [Source].[ReadOnly]
) )
WHEN MATCHED AND [Target].[ReadOnly] != [Source].[ReadOnly] THEN WHEN MATCHED AND [Target].[ReadOnly] != [Source].[ReadOnly] THEN
UPDATE SET [Target].[ReadOnly] = [Source].[ReadOnly] UPDATE SET [Target].[ReadOnly] = [Source].[ReadOnly]
WHEN NOT MATCHED BY SOURCE WHEN NOT MATCHED BY SOURCE
AND [Target].[CollectionId] = @Id THEN AND [Target].[CollectionId] = @CollectionId THEN
DELETE DELETE
; ;
EXEC [dbo].[User_BumpAccountRevisionDateByCollectionId] @Id, @OrganizationId EXEC [dbo].[User_BumpAccountRevisionDateByCollectionId] @CollectionId, @OrgId
END END
GO GO
@ -193,3 +200,30 @@ BEGIN
[CollectionId] = @CollectionId [CollectionId] = @CollectionId
END END
GO GO
IF OBJECT_ID('[dbo].[GroupUserDetails_ReadByGroupId]') IS NOT NULL
BEGIN
DROP PROCEDURE [dbo].[GroupUserDetails_ReadByGroupId]
END
GO
IF OBJECT_ID('[dbo].[GroupUser_ReadOrganizationUserIdsByGroupId]') IS NOT NULL
BEGIN
DROP PROCEDURE [dbo].[GroupUser_ReadOrganizationUserIdsByGroupId]
END
GO
CREATE PROCEDURE [dbo].[GroupUser_ReadOrganizationUserIdsByGroupId]
@GroupId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
SELECT
[OrganizationUserId]
FROM
[dbo].[GroupUser]
WHERE
[GroupId] = @GroupId
END
GO