mirror of
https://github.com/bitwarden/server.git
synced 2025-07-01 16:12:49 -05:00
only update user groups if they are not the same
This commit is contained in:
11
src/Core/Models/Table/GroupUser.cs
Normal file
11
src/Core/Models/Table/GroupUser.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.Table
|
||||||
|
{
|
||||||
|
public class GroupUser
|
||||||
|
{
|
||||||
|
public Guid GroupId { get; set; }
|
||||||
|
public Guid OrganizationUserId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@ namespace Bit.Core.Repositories
|
|||||||
Task<ICollection<Group>> GetManyByOrganizationIdAsync(Guid organizationId);
|
Task<ICollection<Group>> GetManyByOrganizationIdAsync(Guid organizationId);
|
||||||
Task<ICollection<GroupUserDetails>> GetManyUserDetailsByIdAsync(Guid id);
|
Task<ICollection<GroupUserDetails>> GetManyUserDetailsByIdAsync(Guid id);
|
||||||
Task<ICollection<Guid>> GetManyIdsByUserIdAsync(Guid organizationUserId);
|
Task<ICollection<Guid>> GetManyIdsByUserIdAsync(Guid organizationUserId);
|
||||||
|
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);
|
||||||
Task DeleteUserAsync(Guid groupId, Guid organizationUserId);
|
Task DeleteUserAsync(Guid groupId, Guid organizationUserId);
|
||||||
|
@ -77,6 +77,19 @@ namespace Bit.Core.Repositories.SqlServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ICollection<GroupUser>> GetManyGroupUsersByOrganizationIdAsync(Guid organizationId)
|
||||||
|
{
|
||||||
|
using(var connection = new SqlConnection(ConnectionString))
|
||||||
|
{
|
||||||
|
var results = await connection.QueryAsync<GroupUser>(
|
||||||
|
$"[{Schema}].[GroupUser_ReadByOrganizationId]",
|
||||||
|
new { OrganizationId = organizationId },
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
|
|
||||||
|
return results.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task CreateAsync(Group obj, IEnumerable<SelectionReadOnly> collections)
|
public async Task CreateAsync(Group obj, IEnumerable<SelectionReadOnly> collections)
|
||||||
{
|
{
|
||||||
obj.SetNewId();
|
obj.SetNewId();
|
||||||
|
@ -916,27 +916,35 @@ namespace Bit.Core.Services
|
|||||||
var existingGroups = (await _groupRepository.GetManyByOrganizationIdAsync(organizationId)).ToList();
|
var existingGroups = (await _groupRepository.GetManyByOrganizationIdAsync(organizationId)).ToList();
|
||||||
var existingGroupsDict = existingGroups.ToDictionary(g => g.ExternalId);
|
var existingGroupsDict = existingGroups.ToDictionary(g => g.ExternalId);
|
||||||
|
|
||||||
var newGroups = groups.Where(g => !existingGroupsDict.ContainsKey(g.ExternalId));
|
if(groups?.Any() ?? false)
|
||||||
var updateGroups = existingGroups.Where(eg => groups.Any(g => g.ExternalId == eg.ExternalId && g.Name != eg.Name));
|
|
||||||
|
|
||||||
foreach(var group in newGroups)
|
|
||||||
{
|
{
|
||||||
group.CreationDate = group.RevisionDate = DateTime.UtcNow;
|
var newGroups = groups.Where(g => !existingGroupsDict.ContainsKey(g.ExternalId));
|
||||||
await _groupRepository.CreateAsync(group);
|
var updateGroups = existingGroups.Where(eg => groups.Any(g => g.ExternalId == eg.ExternalId && g.Name != eg.Name));
|
||||||
}
|
|
||||||
|
|
||||||
foreach(var group in updateGroups)
|
foreach(var group in newGroups)
|
||||||
{
|
{
|
||||||
group.RevisionDate = DateTime.UtcNow;
|
group.CreationDate = group.RevisionDate = DateTime.UtcNow;
|
||||||
group.Name = existingGroupsDict[group.ExternalId].Name;
|
await _groupRepository.CreateAsync(group);
|
||||||
await _groupRepository.ReplaceAsync(group);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Add the newly created groups to existing groups so that we have a complete list to reference below for users.
|
foreach(var group in updateGroups)
|
||||||
existingGroups.AddRange(newGroups);
|
{
|
||||||
existingGroupsDict = existingGroups.ToDictionary(g => g.ExternalId);
|
group.RevisionDate = DateTime.UtcNow;
|
||||||
|
group.Name = existingGroupsDict[group.ExternalId].Name;
|
||||||
|
await _groupRepository.ReplaceAsync(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the newly created groups to existing groups so that we have a complete list to reference below for users.
|
||||||
|
existingGroups.AddRange(newGroups);
|
||||||
|
existingGroupsDict = existingGroups.ToDictionary(g => g.ExternalId);
|
||||||
|
}
|
||||||
|
|
||||||
// Users
|
// Users
|
||||||
|
if(users?.Any() ?? false)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var existingUsers = await _organizationUserRepository.GetManyDetailsByOrganizationAsync(organizationId);
|
var existingUsers = await _organizationUserRepository.GetManyDetailsByOrganizationAsync(organizationId);
|
||||||
var existingUsersDict = existingUsers.ToDictionary(u => u.Email);
|
var existingUsersDict = existingUsers.ToDictionary(u => u.Email);
|
||||||
|
|
||||||
@ -975,6 +983,7 @@ namespace Bit.Core.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var existingGroupUsers = await _groupRepository.GetManyGroupUsersByOrganizationIdAsync(organizationId);
|
||||||
foreach(var user in updateUsers)
|
foreach(var user in updateUsers)
|
||||||
{
|
{
|
||||||
if(!existingUsersDict.ContainsKey(user.Key))
|
if(!existingUsersDict.ContainsKey(user.Key))
|
||||||
@ -983,11 +992,16 @@ namespace Bit.Core.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
var existingUser = existingUsersDict[user.Key];
|
var existingUser = existingUsersDict[user.Key];
|
||||||
var groupsIdsForUser = user.Value.Where(id => existingGroupsDict.ContainsKey(id))
|
var existingGroupIdsForUser = new HashSet<Guid>(existingGroupUsers
|
||||||
.Select(id => existingGroupsDict[id].Id).ToList();
|
.Where(gu => gu.OrganizationUserId == existingUser.Id)
|
||||||
if(groupsIdsForUser.Any())
|
.Select(gu => gu.GroupId));
|
||||||
|
var newGroupsIdsForUser = new HashSet<Guid>(user.Value
|
||||||
|
.Where(id => existingGroupsDict.ContainsKey(id))
|
||||||
|
.Select(id => existingGroupsDict[id].Id));
|
||||||
|
|
||||||
|
if(!existingGroupIdsForUser.SetEquals(newGroupsIdsForUser))
|
||||||
{
|
{
|
||||||
await _organizationUserRepository.UpdateGroupsAsync(existingUser.Id, groupsIdsForUser);
|
await _organizationUserRepository.UpdateGroupsAsync(existingUser.Id, newGroupsIdsForUser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,5 +189,6 @@
|
|||||||
<Build Include="dbo\Stored Procedures\OrganizationUser_CreateWithCollections.sql" />
|
<Build Include="dbo\Stored Procedures\OrganizationUser_CreateWithCollections.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\OrganizationUser_UpdateWithCollections.sql" />
|
<Build Include="dbo\Stored Procedures\OrganizationUser_UpdateWithCollections.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\CollectionUser_Delete.sql" />
|
<Build Include="dbo\Stored Procedures\CollectionUser_Delete.sql" />
|
||||||
|
<Build Include="dbo\Stored Procedures\GroupUser_ReadByOrganizationId.sql" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -0,0 +1,15 @@
|
|||||||
|
CREATE PROCEDURE [dbo].[GroupUser_ReadByOrganizationId]
|
||||||
|
@OrganizationId UNIQUEIDENTIFIER
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
GU.*
|
||||||
|
FROM
|
||||||
|
[dbo].[GroupUser] GU
|
||||||
|
INNER JOIN
|
||||||
|
[dbo].[Group] G ON G.[Id] = GU.[GroupId]
|
||||||
|
WHERE
|
||||||
|
G.[OrganizationId] = @OrganizationId
|
||||||
|
END
|
Reference in New Issue
Block a user