using System.Data; using System.Text.Json; using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Models.Data; using Bit.Core.AdminConsole.Repositories; using Bit.Core.Entities; using Bit.Core.Models.Data; using Bit.Core.Settings; using Bit.Infrastructure.Dapper.Repositories; using Dapper; using Microsoft.Data.SqlClient; #nullable enable namespace Bit.Infrastructure.Dapper.AdminConsole.Repositories; public class GroupRepository : Repository, IGroupRepository { public GroupRepository(GlobalSettings globalSettings) : this(globalSettings.SqlServer.ConnectionString, globalSettings.SqlServer.ReadOnlyConnectionString) { } public GroupRepository(string connectionString, string readOnlyConnectionString) : base(connectionString, readOnlyConnectionString) { } public async Task>> GetByIdWithCollectionsAsync(Guid id) { using (var connection = new SqlConnection(ConnectionString)) { var results = await connection.QueryMultipleAsync( $"[{Schema}].[Group_ReadWithCollectionsById]", new { Id = id }, commandType: CommandType.StoredProcedure); var group = await results.ReadFirstOrDefaultAsync(); var colletions = (await results.ReadAsync()).ToList(); return new Tuple>(group, colletions); } } public async Task> GetManyByOrganizationIdAsync(Guid organizationId) { using (var connection = new SqlConnection(ConnectionString)) { var results = await connection.QueryAsync( $"[{Schema}].[Group_ReadByOrganizationId]", new { OrganizationId = organizationId }, commandType: CommandType.StoredProcedure); return results.ToList(); } } public async Task>>> GetManyWithCollectionsByOrganizationIdAsync(Guid organizationId) { using (var connection = new SqlConnection(ConnectionString)) { var results = await connection.QueryMultipleAsync( $"[{Schema}].[Group_ReadWithCollectionsByOrganizationId]", new { OrganizationId = organizationId }, commandType: CommandType.StoredProcedure); var groups = (await results.ReadAsync()).ToList(); var collections = (await results.ReadAsync()) .GroupBy(c => c.GroupId) .ToList(); return groups.Select(group => new Tuple>( group, collections.FirstOrDefault(c => c.Key == group.Id)? .Select(c => new CollectionAccessSelection { Id = c.CollectionId, HidePasswords = c.HidePasswords, ReadOnly = c.ReadOnly, Manage = c.Manage } ).ToList() ?? new List()) ).ToList(); } } public async Task> GetManyByManyIds(IEnumerable groupIds) { using (var connection = new SqlConnection(ConnectionString)) { var results = await connection.QueryAsync( $"[{Schema}].[Group_ReadByIds]", new { Ids = groupIds.ToGuidIdArrayTVP() }, commandType: CommandType.StoredProcedure); return results.ToList(); } } public async Task> GetManyIdsByUserIdAsync(Guid organizationUserId) { using (var connection = new SqlConnection(ConnectionString)) { var results = await connection.QueryAsync( $"[{Schema}].[GroupUser_ReadGroupIdsByOrganizationUserId]", new { OrganizationUserId = organizationUserId }, commandType: CommandType.StoredProcedure); return results.ToList(); } } public async Task> GetManyUserIdsByIdAsync(Guid id) { using (var connection = new SqlConnection(ConnectionString)) { var results = await connection.QueryAsync( $"[{Schema}].[GroupUser_ReadOrganizationUserIdsByGroupId]", new { GroupId = id }, commandType: CommandType.StoredProcedure); return results.ToList(); } } 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(); var objWithCollections = JsonSerializer.Deserialize(JsonSerializer.Serialize(obj))!; objWithCollections.Collections = collections.ToArrayTVP(); using (var connection = new SqlConnection(ConnectionString)) { var results = await connection.ExecuteAsync( $"[{Schema}].[Group_CreateWithCollections]", objWithCollections, commandType: CommandType.StoredProcedure); } } public async Task ReplaceAsync(Group obj, IEnumerable collections) { var objWithCollections = JsonSerializer.Deserialize(JsonSerializer.Serialize(obj))!; objWithCollections.Collections = collections.ToArrayTVP(); using (var connection = new SqlConnection(ConnectionString)) { var results = await connection.ExecuteAsync( $"[{Schema}].[Group_UpdateWithCollections]", objWithCollections, commandType: CommandType.StoredProcedure); } } public async Task DeleteUserAsync(Guid groupId, Guid organizationUserId) { using (var connection = new SqlConnection(ConnectionString)) { var results = await connection.ExecuteAsync( $"[{Schema}].[GroupUser_Delete]", new { GroupId = groupId, OrganizationUserId = organizationUserId }, commandType: CommandType.StoredProcedure); } } public async Task UpdateUsersAsync(Guid groupId, IEnumerable organizationUserIds) { using (var connection = new SqlConnection(ConnectionString)) { var results = await connection.ExecuteAsync( "[dbo].[GroupUser_UpdateUsers]", new { GroupId = groupId, OrganizationUserIds = organizationUserIds.ToGuidIdArrayTVP() }, commandType: CommandType.StoredProcedure); } } public async Task DeleteManyAsync(IEnumerable groupIds) { using (var connection = new SqlConnection(ConnectionString)) { await connection.ExecuteAsync("[dbo].[Group_DeleteByIds]", new { Ids = groupIds.ToGuidIdArrayTVP() }, commandType: CommandType.StoredProcedure); } } }