mirror of
https://github.com/bitwarden/server.git
synced 2025-06-27 22:26:13 -05:00
clean up
This commit is contained in:
parent
3a1ed0d81b
commit
e309c3cc2f
@ -20,20 +20,20 @@ public class OrganizationController : Controller
|
|||||||
private readonly IOrganizationService _organizationService;
|
private readonly IOrganizationService _organizationService;
|
||||||
private readonly ICurrentContext _currentContext;
|
private readonly ICurrentContext _currentContext;
|
||||||
private readonly GlobalSettings _globalSettings;
|
private readonly GlobalSettings _globalSettings;
|
||||||
private readonly IImportOrganizationUserCommand _importOrganizationUserCommand;
|
private readonly IImportOrganizationUsersAndGroupsCommand _importOrganizationUsersAndGroupsCommand;
|
||||||
private readonly IFeatureService _featureService;
|
private readonly IFeatureService _featureService;
|
||||||
|
|
||||||
public OrganizationController(
|
public OrganizationController(
|
||||||
IOrganizationService organizationService,
|
IOrganizationService organizationService,
|
||||||
ICurrentContext currentContext,
|
ICurrentContext currentContext,
|
||||||
GlobalSettings globalSettings,
|
GlobalSettings globalSettings,
|
||||||
IImportOrganizationUserCommand importOrganizationUserCommand,
|
IImportOrganizationUsersAndGroupsCommand importOrganizationUsersAndGroupsCommand,
|
||||||
IFeatureService featureService)
|
IFeatureService featureService)
|
||||||
{
|
{
|
||||||
_organizationService = organizationService;
|
_organizationService = organizationService;
|
||||||
_currentContext = currentContext;
|
_currentContext = currentContext;
|
||||||
_globalSettings = globalSettings;
|
_globalSettings = globalSettings;
|
||||||
_importOrganizationUserCommand = importOrganizationUserCommand;
|
_importOrganizationUsersAndGroupsCommand = importOrganizationUsersAndGroupsCommand;
|
||||||
_featureService = featureService;
|
_featureService = featureService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ public class OrganizationController : Controller
|
|||||||
|
|
||||||
if (_featureService.IsEnabled(FeatureFlagKeys.ScimInviteUserOptimization))
|
if (_featureService.IsEnabled(FeatureFlagKeys.ScimInviteUserOptimization))
|
||||||
{
|
{
|
||||||
await _importOrganizationUserCommand.ImportAsync(
|
await _importOrganizationUsersAndGroupsCommand.ImportAsync(
|
||||||
_currentContext.OrganizationId.Value,
|
_currentContext.OrganizationId.Value,
|
||||||
model.Groups.Select(g => g.ToImportedGroup(_currentContext.OrganizationId.Value)),
|
model.Groups.Select(g => g.ToImportedGroup(_currentContext.OrganizationId.Value)),
|
||||||
model.Members.Where(u => !u.Deleted).Select(u => u.ToImportedOrganizationUser()),
|
model.Members.Where(u => !u.Deleted).Select(u => u.ToImportedOrganizationUser()),
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
using Bit.Core.AdminConsole.Models.Business;
|
#nullable enable
|
||||||
|
|
||||||
|
using Bit.Core.AdminConsole.Models.Business;
|
||||||
using Bit.Core.Models.Business;
|
using Bit.Core.Models.Business;
|
||||||
|
|
||||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||||
|
|
||||||
public interface IImportOrganizationUserCommand
|
public interface IImportOrganizationUsersAndGroupsCommand
|
||||||
{
|
{
|
||||||
Task ImportAsync(Guid organizationId,
|
Task ImportAsync(Guid organizationId,
|
||||||
IEnumerable<ImportedGroup> groups,
|
IEnumerable<ImportedGroup> groups,
|
@ -1,4 +1,6 @@
|
|||||||
using Bit.Core.AdminConsole.Entities;
|
#nullable enable
|
||||||
|
|
||||||
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.AdminConsole.Models.Business;
|
using Bit.Core.AdminConsole.Models.Business;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers;
|
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers;
|
||||||
@ -16,11 +18,9 @@ using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
|||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
|
|
||||||
#nullable enable
|
|
||||||
|
|
||||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers;
|
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers;
|
||||||
|
|
||||||
public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
public class ImportOrganizationUsersAndGroupsCommand : IImportOrganizationUsersAndGroupsCommand
|
||||||
{
|
{
|
||||||
private readonly IOrganizationRepository _organizationRepository;
|
private readonly IOrganizationRepository _organizationRepository;
|
||||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||||
@ -34,7 +34,7 @@ public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
|||||||
|
|
||||||
private readonly EventSystemUser _EventSystemUser = EventSystemUser.PublicApi;
|
private readonly EventSystemUser _EventSystemUser = EventSystemUser.PublicApi;
|
||||||
|
|
||||||
public ImportOrganizationUserCommand(IOrganizationRepository organizationRepository,
|
public ImportOrganizationUsersAndGroupsCommand(IOrganizationRepository organizationRepository,
|
||||||
IOrganizationUserRepository organizationUserRepository,
|
IOrganizationUserRepository organizationUserRepository,
|
||||||
IPaymentService paymentService,
|
IPaymentService paymentService,
|
||||||
IGroupRepository groupRepository,
|
IGroupRepository groupRepository,
|
||||||
@ -95,7 +95,7 @@ public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
|||||||
await OverwriteExisting(events, importUserData);
|
await OverwriteExisting(events, importUserData);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Update(importedUsers, importUserData);
|
await UpdateExistingUsers(importedUsers, importUserData);
|
||||||
|
|
||||||
await AddNewUsers(organization, importedUsers, importUserData);
|
await AddNewUsers(organization, importedUsers, importUserData);
|
||||||
|
|
||||||
@ -144,7 +144,7 @@ public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="importedUsers">List of imported organization users.</param>
|
/// <param name="importedUsers">List of imported organization users.</param>
|
||||||
/// <param name="importUserData">Data containing existing and imported users, along with mapping dictionaries.</param>
|
/// <param name="importUserData">Data containing existing and imported users, along with mapping dictionaries.</param>
|
||||||
private async Task Update(IEnumerable<ImportedOrganizationUser> importedUsers, OrganizationUserImportData importUserData)
|
private async Task UpdateExistingUsers(IEnumerable<ImportedOrganizationUser> importedUsers, OrganizationUserImportData importUserData)
|
||||||
{
|
{
|
||||||
if (!importedUsers.Any())
|
if (!importedUsers.Any())
|
||||||
{
|
{
|
||||||
@ -160,27 +160,24 @@ public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
|||||||
var importedUsersEmailsDict = importedUsers.ToDictionary(u => u.Email);
|
var importedUsersEmailsDict = importedUsers.ToDictionary(u => u.Email);
|
||||||
|
|
||||||
// Determine which users to update.
|
// Determine which users to update.
|
||||||
var userDetailsToUpdate = existingUsersEmailsDict.Keys.Intersect(importedUsersEmailsDict.Keys).ToList();
|
var userEmailsToUpdate = existingUsersEmailsDict.Keys.Intersect(importedUsersEmailsDict.Keys).ToList();
|
||||||
var userIdsToUpdate = importUserData.ExistingUsers
|
var userIdsToUpdate = userEmailsToUpdate.Select(e => existingUsersEmailsDict[e].Id).ToList();
|
||||||
.Where(u => userDetailsToUpdate.Contains(u.Email))
|
|
||||||
.Select(u => u.Id)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var organizationUsers = (await _organizationUserRepository.GetManyAsync(userIdsToUpdate)).ToDictionary(u => u.Id);
|
var organizationUsers = (await _organizationUserRepository.GetManyAsync(userIdsToUpdate)).ToDictionary(u => u.Id);
|
||||||
|
|
||||||
foreach (var userEmail in userDetailsToUpdate)
|
foreach (var userEmail in userEmailsToUpdate)
|
||||||
{
|
{
|
||||||
// verify userEmail has an associated OrganizationUser
|
// verify userEmail has an associated OrganizationUser
|
||||||
existingUsersEmailsDict.TryGetValue(userEmail, out var existingUser);
|
existingUsersEmailsDict.TryGetValue(userEmail, out var existingUser);
|
||||||
organizationUsers.TryGetValue(existingUser!.Id, out var organizationUser);
|
organizationUsers.TryGetValue(existingUser!.Id, out var organizationUser);
|
||||||
importedUsersEmailsDict.TryGetValue(userEmail, out var user);
|
importedUsersEmailsDict.TryGetValue(userEmail, out var importedUser);
|
||||||
|
|
||||||
if (organizationUser is null || user is null)
|
if (organizationUser is null || importedUser is null)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
organizationUser.ExternalId = user.ExternalId;
|
organizationUser.ExternalId = importedUser.ExternalId;
|
||||||
updateUsers.Add(organizationUser);
|
updateUsers.Add(organizationUser);
|
||||||
importUserData.ExistingExternalUsersIdDict.Add(organizationUser.ExternalId, organizationUser.Id);
|
importUserData.ExistingExternalUsersIdDict.Add(organizationUser.ExternalId, organizationUser.Id);
|
||||||
}
|
}
|
||||||
@ -302,11 +299,8 @@ public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
|||||||
/// <param name="organization">The organization into which groups are being imported.</param>
|
/// <param name="organization">The organization into which groups are being imported.</param>
|
||||||
/// <param name="importedGroups">A collection of groups to be imported.</param>
|
/// <param name="importedGroups">A collection of groups to be imported.</param>
|
||||||
/// <param name="importUserData">Data containing information about existing and imported users.</param>
|
/// <param name="importUserData">Data containing information about existing and imported users.</param>
|
||||||
private async Task ImportGroups(Organization organization,
|
private async Task ImportGroups(Organization organization, IEnumerable<ImportedGroup> importedGroups, OrganizationUserImportData importUserData)
|
||||||
IEnumerable<ImportedGroup> importedGroups,
|
|
||||||
OrganizationUserImportData importUserData)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!importedGroups.Any())
|
if (!importedGroups.Any())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -314,7 +308,7 @@ public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
|||||||
|
|
||||||
if (!organization.UseGroups)
|
if (!organization.UseGroups)
|
||||||
{
|
{
|
||||||
throw new BadRequestException("Organization cannot use importedGroups.");
|
throw new BadRequestException("Organization cannot use groups.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var existingGroups = await _groupRepository.GetManyByOrganizationIdAsync(organization.Id);
|
var existingGroups = await _groupRepository.GetManyByOrganizationIdAsync(organization.Id);
|
||||||
@ -332,9 +326,11 @@ public class ImportOrganizationUserCommand : IImportOrganizationUserCommand
|
|||||||
/// <param name="importUserData">Data containing information about existing and imported users.</param>
|
/// <param name="importUserData">Data containing information about existing and imported users.</param>
|
||||||
private async Task SaveNewGroups(OrganizationGroupImportData importGroupData, OrganizationUserImportData importUserData)
|
private async Task SaveNewGroups(OrganizationGroupImportData importGroupData, OrganizationUserImportData importUserData)
|
||||||
{
|
{
|
||||||
|
var existingExternalGroupsDict = importGroupData.ExistingExternalGroups.ToDictionary(g => g.ExternalId!);
|
||||||
var newGroups = importGroupData.Groups
|
var newGroups = importGroupData.Groups
|
||||||
.Where(g => !importGroupData.ExistingExternalGroups.ToDictionary(g => g.ExternalId!).ContainsKey(g.Group.ExternalId!))
|
.Where(g => !existingExternalGroupsDict.ContainsKey(g.Group.ExternalId!))
|
||||||
.Select(g => g.Group).ToList()!;
|
.Select(g => g.Group)
|
||||||
|
.ToList()!;
|
||||||
|
|
||||||
var savedGroups = new List<Group>();
|
var savedGroups = new List<Group>();
|
||||||
foreach (var group in newGroups)
|
foreach (var group in newGroups)
|
@ -1,19 +1,40 @@
|
|||||||
using Bit.Core.AdminConsole.Entities;
|
#nullable enable
|
||||||
|
|
||||||
|
using Bit.Core.AdminConsole.Entities;
|
||||||
using Bit.Core.AdminConsole.Models.Business;
|
using Bit.Core.AdminConsole.Models.Business;
|
||||||
|
|
||||||
namespace Bit.Core.Models.Data.Organizations;
|
namespace Bit.Core.Models.Data.Organizations;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the data required to import organization groups,
|
||||||
|
/// including newly imported groups and existing groups within the organization.
|
||||||
|
/// </summary>
|
||||||
public class OrganizationGroupImportData
|
public class OrganizationGroupImportData
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The collection of groups that are being imported.
|
||||||
|
/// </summary>
|
||||||
public readonly IEnumerable<ImportedGroup> Groups;
|
public readonly IEnumerable<ImportedGroup> Groups;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Collection of groups that already exist in the organization.
|
||||||
|
/// </summary>
|
||||||
public readonly ICollection<Group> ExistingGroups;
|
public readonly ICollection<Group> ExistingGroups;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Existing groups with ExternalId set.
|
||||||
|
/// </summary>
|
||||||
public readonly IEnumerable<Group> ExistingExternalGroups;
|
public readonly IEnumerable<Group> ExistingExternalGroups;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mapping of imported groups keyed by their ExternalId.
|
||||||
|
/// </summary>
|
||||||
public readonly IDictionary<string, ImportedGroup> GroupsDict;
|
public readonly IDictionary<string, ImportedGroup> GroupsDict;
|
||||||
|
|
||||||
public OrganizationGroupImportData(IEnumerable<ImportedGroup> groups, ICollection<Group> existingGroups)
|
public OrganizationGroupImportData(IEnumerable<ImportedGroup> groups, ICollection<Group> existingGroups)
|
||||||
{
|
{
|
||||||
Groups = groups;
|
Groups = groups;
|
||||||
GroupsDict = groups.ToDictionary(g => g.Group.ExternalId);
|
GroupsDict = groups.ToDictionary(g => g.Group.ExternalId!);
|
||||||
ExistingGroups = existingGroups;
|
ExistingGroups = existingGroups;
|
||||||
ExistingExternalGroups = existingGroups.Where(u => !string.IsNullOrWhiteSpace(u.ExternalId)).ToList();
|
ExistingExternalGroups = existingGroups.Where(u => !string.IsNullOrWhiteSpace(u.ExternalId)).ToList();
|
||||||
}
|
}
|
@ -1,4 +1,6 @@
|
|||||||
using Bit.Core.Models.Business;
|
#nullable enable
|
||||||
|
|
||||||
|
using Bit.Core.Models.Business;
|
||||||
namespace Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
namespace Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||||
|
|
||||||
public class OrganizationUserImportData
|
public class OrganizationUserImportData
|
||||||
@ -8,11 +10,11 @@ public class OrganizationUserImportData
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly HashSet<string> ImportedExternalIds;
|
public readonly HashSet<string> ImportedExternalIds;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Exising organization users details
|
/// All existing OrganizationUsers for the organization
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly ICollection<OrganizationUserUserDetails> ExistingUsers;
|
public readonly ICollection<OrganizationUserUserDetails> ExistingUsers;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// List of ExternalIds belonging to existing organization Users
|
/// Existing OrganizationUsers with ExternalIds set.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly IEnumerable<OrganizationUserUserDetails> ExistingExternalUsers;
|
public readonly IEnumerable<OrganizationUserUserDetails> ExistingExternalUsers;
|
||||||
/// <summary>
|
/// <summary>
|
@ -1,5 +1,4 @@
|
|||||||
using Bit.Core.AdminConsole.Models.Business;
|
using Bit.Core.AdminConsole.Models.Business;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers;
|
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers;
|
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models;
|
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models;
|
||||||
using Bit.Core.AdminConsole.Utilities.Commands;
|
using Bit.Core.AdminConsole.Utilities.Commands;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user