From a0ac7242b6f6da8200d7998caf09bb16fc764472 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Sat, 13 May 2017 14:14:20 -0400 Subject: [PATCH] only update user groups if they are not the same --- src/Core/Models/Table/GroupUser.cs | 11 ++++ src/Core/Repositories/IGroupRepository.cs | 1 + .../Repositories/SqlServer/GroupRepository.cs | 13 +++++ .../Implementations/OrganizationService.cs | 54 ++++++++++++------- src/Sql/Sql.sqlproj | 1 + .../GroupUser_ReadByOrganizationId.sql | 15 ++++++ 6 files changed, 75 insertions(+), 20 deletions(-) create mode 100644 src/Core/Models/Table/GroupUser.cs create mode 100644 src/Sql/dbo/Stored Procedures/GroupUser_ReadByOrganizationId.sql diff --git a/src/Core/Models/Table/GroupUser.cs b/src/Core/Models/Table/GroupUser.cs new file mode 100644 index 000000000..524fedd36 --- /dev/null +++ b/src/Core/Models/Table/GroupUser.cs @@ -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; } + } +} diff --git a/src/Core/Repositories/IGroupRepository.cs b/src/Core/Repositories/IGroupRepository.cs index 56065b7cf..837c4522d 100644 --- a/src/Core/Repositories/IGroupRepository.cs +++ b/src/Core/Repositories/IGroupRepository.cs @@ -12,6 +12,7 @@ namespace Bit.Core.Repositories Task> GetManyByOrganizationIdAsync(Guid organizationId); Task> GetManyUserDetailsByIdAsync(Guid id); Task> GetManyIdsByUserIdAsync(Guid organizationUserId); + Task> GetManyGroupUsersByOrganizationIdAsync(Guid organizationId); Task CreateAsync(Group obj, IEnumerable collections); Task ReplaceAsync(Group obj, IEnumerable collections); Task DeleteUserAsync(Guid groupId, Guid organizationUserId); diff --git a/src/Core/Repositories/SqlServer/GroupRepository.cs b/src/Core/Repositories/SqlServer/GroupRepository.cs index 4ef8e87f2..73e65871d 100644 --- a/src/Core/Repositories/SqlServer/GroupRepository.cs +++ b/src/Core/Repositories/SqlServer/GroupRepository.cs @@ -77,6 +77,19 @@ namespace Bit.Core.Repositories.SqlServer } } + public async Task> GetManyGroupUsersByOrganizationIdAsync(Guid organizationId) + { + using(var connection = new SqlConnection(ConnectionString)) + { + var results = await connection.QueryAsync( + $"[{Schema}].[GroupUser_ReadByOrganizationId]", + new { OrganizationId = organizationId }, + commandType: CommandType.StoredProcedure); + + return results.ToList(); + } + } + public async Task CreateAsync(Group obj, IEnumerable collections) { obj.SetNewId(); diff --git a/src/Core/Services/Implementations/OrganizationService.cs b/src/Core/Services/Implementations/OrganizationService.cs index ac0044196..6425c48c6 100644 --- a/src/Core/Services/Implementations/OrganizationService.cs +++ b/src/Core/Services/Implementations/OrganizationService.cs @@ -916,27 +916,35 @@ namespace Bit.Core.Services var existingGroups = (await _groupRepository.GetManyByOrganizationIdAsync(organizationId)).ToList(); var existingGroupsDict = existingGroups.ToDictionary(g => g.ExternalId); - var newGroups = groups.Where(g => !existingGroupsDict.ContainsKey(g.ExternalId)); - var updateGroups = existingGroups.Where(eg => groups.Any(g => g.ExternalId == eg.ExternalId && g.Name != eg.Name)); - - foreach(var group in newGroups) + if(groups?.Any() ?? false) { - group.CreationDate = group.RevisionDate = DateTime.UtcNow; - await _groupRepository.CreateAsync(group); - } + var newGroups = groups.Where(g => !existingGroupsDict.ContainsKey(g.ExternalId)); + var updateGroups = existingGroups.Where(eg => groups.Any(g => g.ExternalId == eg.ExternalId && g.Name != eg.Name)); - foreach(var group in updateGroups) - { - group.RevisionDate = DateTime.UtcNow; - group.Name = existingGroupsDict[group.ExternalId].Name; - await _groupRepository.ReplaceAsync(group); - } + foreach(var group in newGroups) + { + group.CreationDate = group.RevisionDate = DateTime.UtcNow; + await _groupRepository.CreateAsync(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); + foreach(var group in updateGroups) + { + 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 + if(users?.Any() ?? false) + { + return; + } + var existingUsers = await _organizationUserRepository.GetManyDetailsByOrganizationAsync(organizationId); 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) { if(!existingUsersDict.ContainsKey(user.Key)) @@ -983,11 +992,16 @@ namespace Bit.Core.Services } var existingUser = existingUsersDict[user.Key]; - var groupsIdsForUser = user.Value.Where(id => existingGroupsDict.ContainsKey(id)) - .Select(id => existingGroupsDict[id].Id).ToList(); - if(groupsIdsForUser.Any()) + var existingGroupIdsForUser = new HashSet(existingGroupUsers + .Where(gu => gu.OrganizationUserId == existingUser.Id) + .Select(gu => gu.GroupId)); + var newGroupsIdsForUser = new HashSet(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); } } } diff --git a/src/Sql/Sql.sqlproj b/src/Sql/Sql.sqlproj index 5f33d0eb0..becbb1c1d 100644 --- a/src/Sql/Sql.sqlproj +++ b/src/Sql/Sql.sqlproj @@ -189,5 +189,6 @@ + \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/GroupUser_ReadByOrganizationId.sql b/src/Sql/dbo/Stored Procedures/GroupUser_ReadByOrganizationId.sql new file mode 100644 index 000000000..87d263213 --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/GroupUser_ReadByOrganizationId.sql @@ -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 \ No newline at end of file