1
0
mirror of https://github.com/bitwarden/server synced 2026-02-01 01:03:25 +00:00

Add default collection name to call stack for restore user command

This commit is contained in:
Jared McCannon
2026-01-13 10:29:10 -06:00
parent 7fb2822e05
commit 0dd4112d7b
4 changed files with 40 additions and 12 deletions

View File

@@ -695,9 +695,9 @@ public class OrganizationUsersController : BaseAdminConsoleController
[HttpPut("{id}/restore")]
[Authorize<ManageUsersRequirement>]
public async Task RestoreAsync(Guid orgId, Guid id)
public async Task RestoreAsync(Guid orgId, Guid id, string defaultUserCollectionName = null)
{
await RestoreOrRevokeUserAsync(orgId, id, (orgUser, userId) => _restoreOrganizationUserCommand.RestoreUserAsync(orgUser, userId));
await RestoreOrRevokeUserAsync(orgId, id, (orgUser, userId) => _restoreOrganizationUserCommand.RestoreUserAsync(orgUser, userId, defaultUserCollectionName));
}
[HttpPatch("{id}/restore")]
@@ -712,7 +712,9 @@ public class OrganizationUsersController : BaseAdminConsoleController
[Authorize<ManageUsersRequirement>]
public async Task<ListResponseModel<OrganizationUserBulkResponseModel>> BulkRestoreAsync(Guid orgId, [FromBody] OrganizationUserBulkRequestModel model)
{
return await RestoreOrRevokeUsersAsync(orgId, model, (orgId, orgUserIds, restoringUserId) => _restoreOrganizationUserCommand.RestoreUsersAsync(orgId, orgUserIds, restoringUserId, _userService));
return await RestoreOrRevokeUsersAsync(orgId, model,
(orgId, orgUserIds, restoringUserId) => _restoreOrganizationUserCommand.RestoreUsersAsync(orgId, orgUserIds,
restoringUserId, _userService, model.DefaultUserCollectionName));
}
[HttpPatch("restore")]

View File

@@ -116,12 +116,14 @@ public class OrganizationUserResetPasswordEnrollmentRequestModel
public string ResetPasswordKey { get; set; }
public string MasterPasswordHash { get; set; }
}
#nullable enable
public class OrganizationUserBulkRequestModel
{
[Required, MinLength(1)]
public IEnumerable<Guid> Ids { get; set; }
public IEnumerable<Guid> Ids { get; set; } = new List<Guid>();
public string? DefaultUserCollectionName { get; set; }
}
#nullable disable
public class ResetPasswordWithOrgIdRequestModel : OrganizationUserResetPasswordEnrollmentRequestModel
{

View File

@@ -20,7 +20,7 @@ public interface IRestoreOrganizationUserCommand
/// </summary>
/// <param name="organizationUser">Revoked user to be restored.</param>
/// <param name="restoringUserId">UserId of the user performing the action.</param>
Task RestoreUserAsync(OrganizationUser organizationUser, Guid? restoringUserId);
Task RestoreUserAsync(OrganizationUser organizationUser, Guid? restoringUserId, string? defaultCollectionName);
/// <summary>
/// Validates that the requesting user can perform the action. There is also a check done to ensure the organization
@@ -50,5 +50,5 @@ public interface IRestoreOrganizationUserCommand
/// <param name="userService">Passed in from caller to avoid circular dependency</param>
/// <returns>List of organization user Ids and strings. A successful restoration will have an empty string.
/// If an error occurs, the error message will be provided.</returns>
Task<List<Tuple<OrganizationUser, string>>> RestoreUsersAsync(Guid organizationId, IEnumerable<Guid> organizationUserIds, Guid? restoringUserId, IUserService userService);
Task<List<Tuple<OrganizationUser, string>>> RestoreUsersAsync(Guid organizationId, IEnumerable<Guid> organizationUserIds, Guid? restoringUserId, IUserService userService, string? defaultCollectionName);
}

View File

@@ -31,9 +31,10 @@ public class RestoreOrganizationUserCommand(
IOrganizationService organizationService,
IFeatureService featureService,
IPolicyRequirementQuery policyRequirementQuery,
ICollectionRepository collectionRepository,
IAutomaticUserConfirmationPolicyEnforcementValidator automaticUserConfirmationPolicyEnforcementValidator) : IRestoreOrganizationUserCommand
{
public async Task RestoreUserAsync(OrganizationUser organizationUser, Guid? restoringUserId)
public async Task RestoreUserAsync(OrganizationUser organizationUser, Guid? restoringUserId, string defaultCollectionName)
{
if (restoringUserId.HasValue && organizationUser.UserId == restoringUserId.Value)
{
@@ -46,7 +47,7 @@ public class RestoreOrganizationUserCommand(
throw new BadRequestException("Only owners can restore other owners.");
}
await RepositoryRestoreUserAsync(organizationUser);
await RepositoryRestoreUserAsync(organizationUser, defaultCollectionName);
await eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Restored);
if (organizationUser.UserId.HasValue)
@@ -57,7 +58,7 @@ public class RestoreOrganizationUserCommand(
public async Task RestoreUserAsync(OrganizationUser organizationUser, EventSystemUser systemUser)
{
await RepositoryRestoreUserAsync(organizationUser);
await RepositoryRestoreUserAsync(organizationUser, ""); // TODO fix this
await eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Restored,
systemUser);
@@ -67,7 +68,7 @@ public class RestoreOrganizationUserCommand(
}
}
private async Task RepositoryRestoreUserAsync(OrganizationUser organizationUser)
private async Task RepositoryRestoreUserAsync(OrganizationUser organizationUser, string defaultCollectionName)
{
if (organizationUser.Status != OrganizationUserStatusType.Revoked)
{
@@ -104,6 +105,17 @@ public class RestoreOrganizationUserCommand(
await organizationUserRepository.RestoreAsync(organizationUser.Id, status);
if (organizationUser.UserId.HasValue
&& (await policyRequirementQuery.GetAsync<OrganizationDataOwnershipPolicyRequirement>(organizationUser.UserId
.Value)).State == OrganizationDataOwnershipState.Enabled
&& organizationUser.Status == OrganizationUserStatusType.Confirmed
&& !string.IsNullOrWhiteSpace(defaultCollectionName))
{
await collectionRepository.CreateDefaultCollectionsAsync(organizationUser.OrganizationId,
[organizationUser.Id],
defaultCollectionName);
}
organizationUser.Status = status;
}
@@ -156,7 +168,8 @@ public class RestoreOrganizationUserCommand(
}
public async Task<List<Tuple<OrganizationUser, string>>> RestoreUsersAsync(Guid organizationId,
IEnumerable<Guid> organizationUserIds, Guid? restoringUserId, IUserService userService)
IEnumerable<Guid> organizationUserIds, Guid? restoringUserId, IUserService userService,
string defaultCollectionName)
{
var orgUsers = await organizationUserRepository.GetManyAsync(organizationUserIds);
var filteredUsers = orgUsers.Where(u => u.OrganizationId == organizationId)
@@ -224,9 +237,20 @@ public class RestoreOrganizationUserCommand(
await organizationUserRepository.RestoreAsync(organizationUser.Id, status);
organizationUser.Status = status;
await eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Restored);
if (organizationUser.UserId.HasValue)
{
if ((await policyRequirementQuery.GetAsync<OrganizationDataOwnershipPolicyRequirement>(organizationUser.UserId
.Value)).State == OrganizationDataOwnershipState.Enabled
&& organizationUser.Status == OrganizationUserStatusType.Confirmed
&& !string.IsNullOrWhiteSpace(defaultCollectionName))
{
await collectionRepository.CreateDefaultCollectionsAsync(organizationUser.OrganizationId,
[organizationUser.Id],
defaultCollectionName);
}
await pushNotificationService.PushSyncOrgKeysAsync(organizationUser.UserId.Value);
}