1
0
mirror of https://github.com/bitwarden/server synced 2026-01-04 17:43:53 +00:00

[PM-23116/PM-23117] Remove deprecated feature flag MembersGetEndpointOptimization (#6179)

* Refactor OrganizationUserRepositoryTests: Swap GetManyByOrganizationWithClaimedDomainsAsync_vNext with GetManyByOrganizationWithClaimedDomainsAsync and remove outdated test

* Refactor GetOrganizationUsersClaimedStatusQuery: Remove unused IFeatureService dependency and simplify domain claimed status retrieval logic.

* Refactor OrganizationUserUserDetailsQuery: Remove unused IFeatureService dependency and streamline user details retrieval methods.

* Refactor OrganizationUserRepository: Remove deprecated GetManyByOrganizationWithClaimedDomainsAsync_vNext method and its implementation

* Remove deprecated feature flag MembersGetEndpointOptimization
This commit is contained in:
Rui Tomé
2025-08-15 10:14:38 +01:00
committed by GitHub
parent 4bad008085
commit 41f82bb357
7 changed files with 14 additions and 211 deletions

View File

@@ -8,16 +8,13 @@ public class GetOrganizationUsersClaimedStatusQuery : IGetOrganizationUsersClaim
{
private readonly IApplicationCacheService _applicationCacheService;
private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly IFeatureService _featureService;
public GetOrganizationUsersClaimedStatusQuery(
IApplicationCacheService applicationCacheService,
IOrganizationUserRepository organizationUserRepository,
IFeatureService featureService)
IOrganizationUserRepository organizationUserRepository)
{
_applicationCacheService = applicationCacheService;
_organizationUserRepository = organizationUserRepository;
_featureService = featureService;
}
public async Task<IDictionary<Guid, bool>> GetUsersOrganizationClaimedStatusAsync(Guid organizationId, IEnumerable<Guid> organizationUserIds)
@@ -30,9 +27,7 @@ public class GetOrganizationUsersClaimedStatusQuery : IGetOrganizationUsersClaim
if (organizationAbility is { Enabled: true, UseOrganizationDomains: true })
{
// Get all organization users with claimed domains by the organization
var organizationUsersWithClaimedDomain = _featureService.IsEnabled(FeatureFlagKeys.MembersGetEndpointOptimization)
? await _organizationUserRepository.GetManyByOrganizationWithClaimedDomainsAsync_vNext(organizationId)
: await _organizationUserRepository.GetManyByOrganizationWithClaimedDomainsAsync(organizationId);
var organizationUsersWithClaimedDomain = await _organizationUserRepository.GetManyByOrganizationWithClaimedDomainsAsync(organizationId);
// Create a dictionary with the OrganizationUserId and a boolean indicating if the user is claimed by the organization
return organizationUserIds.ToDictionary(ouId => ouId, ouId => organizationUsersWithClaimedDomain.Any(ou => ou.Id == ouId));

View File

@@ -1,10 +1,8 @@
using Bit.Core;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces;
using Bit.Core.Enums;
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Utilities;
using Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
using Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Requests;
@@ -15,19 +13,16 @@ public class OrganizationUserUserDetailsQuery : IOrganizationUserUserDetailsQuer
{
private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly ITwoFactorIsEnabledQuery _twoFactorIsEnabledQuery;
private readonly IFeatureService _featureService;
private readonly IGetOrganizationUsersClaimedStatusQuery _getOrganizationUsersClaimedStatusQuery;
public OrganizationUserUserDetailsQuery(
IOrganizationUserRepository organizationUserRepository,
ITwoFactorIsEnabledQuery twoFactorIsEnabledQuery,
IFeatureService featureService,
IGetOrganizationUsersClaimedStatusQuery getOrganizationUsersClaimedStatusQuery
)
{
_organizationUserRepository = organizationUserRepository;
_twoFactorIsEnabledQuery = twoFactorIsEnabledQuery;
_featureService = featureService;
_getOrganizationUsersClaimedStatusQuery = getOrganizationUsersClaimedStatusQuery;
}
@@ -62,47 +57,6 @@ public class OrganizationUserUserDetailsQuery : IOrganizationUserUserDetailsQuer
/// <param name="request">Request details for the query</param>
/// <returns>List of OrganizationUserUserDetails</returns>
public async Task<IEnumerable<(OrganizationUserUserDetails OrgUser, bool TwoFactorEnabled, bool ClaimedByOrganization)>> Get(OrganizationUserUserDetailsQueryRequest request)
{
if (_featureService.IsEnabled(FeatureFlagKeys.MembersGetEndpointOptimization))
{
return await Get_vNext(request);
}
var organizationUsers = await GetOrganizationUserUserDetails(request);
var organizationUsersTwoFactorEnabled = (await _twoFactorIsEnabledQuery.TwoFactorIsEnabledAsync(organizationUsers)).ToDictionary(u => u.user.Id);
var organizationUsersClaimedStatus = await _getOrganizationUsersClaimedStatusQuery.GetUsersOrganizationClaimedStatusAsync(request.OrganizationId, organizationUsers.Select(o => o.Id));
var responses = organizationUsers.Select(o => (o, organizationUsersTwoFactorEnabled[o.Id].twoFactorIsEnabled, organizationUsersClaimedStatus[o.Id]));
return responses;
}
/// <summary>
/// Get the organization users user details, two factor enabled status, and
/// claimed status for confirmed users that are enrolled in account recovery
/// </summary>
/// <param name="request">Request details for the query</param>
/// <returns>List of OrganizationUserUserDetails</returns>
public async Task<IEnumerable<(OrganizationUserUserDetails OrgUser, bool TwoFactorEnabled, bool ClaimedByOrganization)>> GetAccountRecoveryEnrolledUsers(OrganizationUserUserDetailsQueryRequest request)
{
if (_featureService.IsEnabled(FeatureFlagKeys.MembersGetEndpointOptimization))
{
return await GetAccountRecoveryEnrolledUsers_vNext(request);
}
var organizationUsers = (await GetOrganizationUserUserDetails(request))
.Where(o => o.Status.Equals(OrganizationUserStatusType.Confirmed) && o.UsesKeyConnector == false && !String.IsNullOrEmpty(o.ResetPasswordKey));
var organizationUsersTwoFactorEnabled = (await _twoFactorIsEnabledQuery.TwoFactorIsEnabledAsync(organizationUsers)).ToDictionary(u => u.user.Id);
var organizationUsersClaimedStatus = await _getOrganizationUsersClaimedStatusQuery.GetUsersOrganizationClaimedStatusAsync(request.OrganizationId, organizationUsers.Select(o => o.Id));
var responses = organizationUsers
.Select(o => (o, organizationUsersTwoFactorEnabled[o.Id].twoFactorIsEnabled, organizationUsersClaimedStatus[o.Id]));
return responses;
}
private async Task<IEnumerable<(OrganizationUserUserDetails OrgUser, bool TwoFactorEnabled, bool ClaimedByOrganization)>> Get_vNext(OrganizationUserUserDetailsQueryRequest request)
{
var organizationUsers = await _organizationUserRepository
.GetManyDetailsByOrganizationAsync_vNext(request.OrganizationId, request.IncludeGroups, request.IncludeCollections);
@@ -132,7 +86,13 @@ public class OrganizationUserUserDetailsQuery : IOrganizationUserUserDetailsQuer
return responses;
}
private async Task<IEnumerable<(OrganizationUserUserDetails OrgUser, bool TwoFactorEnabled, bool ClaimedByOrganization)>> GetAccountRecoveryEnrolledUsers_vNext(OrganizationUserUserDetailsQueryRequest request)
/// <summary>
/// Get the organization users user details, two factor enabled status, and
/// claimed status for confirmed users that are enrolled in account recovery
/// </summary>
/// <param name="request">Request details for the query</param>
/// <returns>List of OrganizationUserUserDetails</returns>
public async Task<IEnumerable<(OrganizationUserUserDetails OrgUser, bool TwoFactorEnabled, bool ClaimedByOrganization)>> GetAccountRecoveryEnrolledUsers(OrganizationUserUserDetailsQueryRequest request)
{
var organizationUsers = (await _organizationUserRepository
.GetManyDetailsByOrganizationAsync_vNext(request.OrganizationId, request.IncludeGroups, request.IncludeCollections))

View File

@@ -76,10 +76,6 @@ public interface IOrganizationUserRepository : IRepository<OrganizationUser, Gui
/// Returns a list of OrganizationUsers with email domains that match one of the Organization's claimed domains.
/// </summary>
Task<ICollection<OrganizationUser>> GetManyByOrganizationWithClaimedDomainsAsync(Guid organizationId);
/// <summary>
/// Optimized version of <see cref="GetManyByOrganizationWithClaimedDomainsAsync"/> with better performance.
/// </summary>
Task<ICollection<OrganizationUser>> GetManyByOrganizationWithClaimedDomainsAsync_vNext(Guid organizationId);
Task RevokeManyByIdAsync(IEnumerable<Guid> organizationUserIds);
/// <summary>

View File

@@ -115,7 +115,6 @@ public static class FeatureFlagKeys
public const string SeparateCustomRolePermissions = "pm-19917-separate-custom-role-permissions";
public const string ImportAsyncRefactor = "pm-22583-refactor-import-async";
public const string CreateDefaultLocation = "pm-19467-create-default-location";
public const string MembersGetEndpointOptimization = "pm-23113-optimize-get-members-endpoint";
public const string DirectoryConnectorPreventUserRemoval = "pm-24592-directory-connector-prevent-user-removal";
/* Auth Team */

View File

@@ -608,19 +608,6 @@ public class OrganizationUserRepository : Repository<OrganizationUser, Guid>, IO
}
public async Task<ICollection<OrganizationUser>> GetManyByOrganizationWithClaimedDomainsAsync(Guid organizationId)
{
using (var connection = new SqlConnection(ConnectionString))
{
var results = await connection.QueryAsync<OrganizationUser>(
$"[{Schema}].[OrganizationUser_ReadByOrganizationIdWithClaimedDomains]",
new { OrganizationId = organizationId },
commandType: CommandType.StoredProcedure);
return results.ToList();
}
}
public async Task<ICollection<OrganizationUser>> GetManyByOrganizationWithClaimedDomainsAsync_vNext(Guid organizationId)
{
using (var connection = new SqlConnection(ConnectionString))
{

View File

@@ -786,12 +786,6 @@ public class OrganizationUserRepository : Repository<Core.Entities.OrganizationU
}
}
public async Task<ICollection<Core.Entities.OrganizationUser>> GetManyByOrganizationWithClaimedDomainsAsync_vNext(Guid organizationId)
{
// No EF optimization is required for this query
return await GetManyByOrganizationWithClaimedDomainsAsync(organizationId);
}
public async Task RevokeManyByIdAsync(IEnumerable<Guid> organizationUserIds)
{
using var scope = ServiceScopeFactory.CreateScope();