using System.Diagnostics; using Bit.Core.AdminConsole.Enums.Provider; using Bit.Core.Auth.Enums; using Bit.Core.Enums; using Bit.Infrastructure.EntityFramework.Repositories.Queries; using Microsoft.EntityFrameworkCore; #nullable enable namespace Bit.Infrastructure.EntityFramework.Repositories; public static class DatabaseContextExtensions { public static async Task UserBumpAccountRevisionDateAsync(this DatabaseContext context, Guid userId) { var user = await context.Users.FindAsync(userId); Debug.Assert(user is not null, "The user id is expected to be validated as a true-in database user before making this call."); user.AccountRevisionDate = DateTime.UtcNow; } public static async Task UserBumpManyAccountRevisionDatesAsync(this DatabaseContext context, ICollection userIds) { var users = context.Users.Where(u => userIds.Contains(u.Id)); var currentTime = DateTime.UtcNow; await users.ForEachAsync(u => { context.Attach(u); u.AccountRevisionDate = currentTime; }); } public static async Task UserBumpAccountRevisionDateByOrganizationIdAsync(this DatabaseContext context, Guid organizationId) { var users = await (from u in context.Users join ou in context.OrganizationUsers on u.Id equals ou.UserId where ou.OrganizationId == organizationId && ou.Status == OrganizationUserStatusType.Confirmed select u).ToListAsync(); UpdateUserRevisionDate(users); } public static async Task UserBumpAccountRevisionDateByCipherIdAsync(this DatabaseContext context, Guid cipherId, Guid organizationId) { var query = new UserBumpAccountRevisionDateByCipherIdQuery(cipherId, organizationId); var users = await query.Run(context).ToListAsync(); UpdateUserRevisionDate(users); } public static async Task UserBumpAccountRevisionDateByCollectionIdAsync(this DatabaseContext context, Guid collectionId, Guid organizationId) { var query = from u in context.Users join ou in context.OrganizationUsers on u.Id equals ou.UserId join cu in context.CollectionUsers on new { OrganizationUserId = ou.Id, CollectionId = collectionId } equals new { cu.OrganizationUserId, cu.CollectionId } into cu_g from cu in cu_g.DefaultIfEmpty() join gu in context.GroupUsers on new { CollectionId = (Guid?)cu.CollectionId, OrganizationUserId = ou.Id } equals new { CollectionId = (Guid?)null, gu.OrganizationUserId } into gu_g from gu in gu_g.DefaultIfEmpty() join g in context.Groups on gu.GroupId equals g.Id into g_g from g in g_g.DefaultIfEmpty() join cg in context.CollectionGroups on new { gu.GroupId, CollectionId = collectionId } equals new { cg.GroupId, cg.CollectionId } into cg_g from cg in cg_g.DefaultIfEmpty() where ou.OrganizationId == organizationId && ou.Status == OrganizationUserStatusType.Confirmed && ((cu == null ? (Guid?)null : cu.CollectionId) != null || (cg == null ? (Guid?)null : cg.CollectionId) != null) select u; var users = await query.ToListAsync(); UpdateUserRevisionDate(users); } public static async Task UserBumpAccountRevisionDateByCollectionIdsAsync(this DatabaseContext context, IEnumerable collectionIds, Guid organizationId) { var query = from u in context.Users from c in context.Collections join ou in context.OrganizationUsers on u.Id equals ou.UserId join cu in context.CollectionUsers on new { OrganizationUserId = ou.Id, CollectionId = c.Id } equals new { cu.OrganizationUserId, cu.CollectionId } into cu_g from cu in cu_g.DefaultIfEmpty() join gu in context.GroupUsers on new { CollectionId = (Guid?)cu.CollectionId, OrganizationUserId = ou.Id } equals new { CollectionId = (Guid?)null, gu.OrganizationUserId } into gu_g from gu in gu_g.DefaultIfEmpty() join g in context.Groups on gu.GroupId equals g.Id into g_g from g in g_g.DefaultIfEmpty() join cg in context.CollectionGroups on new { gu.GroupId, CollectionId = c.Id } equals new { cg.GroupId, cg.CollectionId } into cg_g from cg in cg_g.DefaultIfEmpty() where ou.OrganizationId == organizationId && collectionIds.Contains(c.Id) && ou.Status == OrganizationUserStatusType.Confirmed && ((cu == null ? (Guid?)null : cu.CollectionId) != null || (cg == null ? (Guid?)null : cg.CollectionId) != null) select u; var users = await query.ToListAsync(); UpdateUserRevisionDate(users); } public static async Task UserBumpAccountRevisionDateByOrganizationUserIdAsync(this DatabaseContext context, Guid organizationUserId) { var query = from u in context.Users join ou in context.OrganizationUsers on u.Id equals ou.UserId where ou.Id == organizationUserId && ou.Status == OrganizationUserStatusType.Confirmed select u; var users = await query.ToListAsync(); UpdateUserRevisionDate(users); } public static async Task UserBumpAccountRevisionDateByOrganizationUserIdsAsync(this DatabaseContext context, IEnumerable organizationUserIds) { foreach (var organizationUserId in organizationUserIds) { await context.UserBumpAccountRevisionDateByOrganizationUserIdAsync(organizationUserId); } } public static async Task UserBumpAccountRevisionDateByEmergencyAccessGranteeIdAsync(this DatabaseContext context, Guid emergencyAccessId) { var query = from u in context.Users join ea in context.EmergencyAccesses on u.Id equals ea.GranteeId where ea.Id == emergencyAccessId && ea.Status == EmergencyAccessStatusType.Confirmed select u; var users = await query.ToListAsync(); UpdateUserRevisionDate(users); } public static async Task UserBumpAccountRevisionDateByProviderIdAsync(this DatabaseContext context, Guid providerId) { var query = from u in context.Users join pu in context.ProviderUsers on u.Id equals pu.UserId where pu.ProviderId == providerId && pu.Status == ProviderUserStatusType.Confirmed select u; var users = await query.ToListAsync(); UpdateUserRevisionDate(users); } public static async Task UserBumpAccountRevisionDateByProviderUserIdAsync(this DatabaseContext context, Guid providerUserId) { var query = from u in context.Users join pu in context.ProviderUsers on u.Id equals pu.UserId where pu.ProviderId == providerUserId && pu.Status == ProviderUserStatusType.Confirmed select u; var users = await query.ToListAsync(); UpdateUserRevisionDate(users); } private static void UpdateUserRevisionDate(List users) { var time = DateTime.UtcNow; foreach (var user in users) { user.AccountRevisionDate = time; } } }