@@ -31,52 +31,46 @@ public sealed class PlatformAdminBootstrapper(
|
||||
ArgumentNullException.ThrowIfNull(options);
|
||||
var email = options.Email.Trim();
|
||||
if (email.Length == 0)
|
||||
{
|
||||
throw new ArgumentException("Platform administrator email is required.", nameof(options));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(options.TemporaryPassword))
|
||||
{
|
||||
throw new ArgumentException("Platform administrator temporary password is required.", nameof(options));
|
||||
}
|
||||
|
||||
IDbContextTransaction? transaction = null;
|
||||
if (dbContext.Database.IsRelational())
|
||||
{
|
||||
transaction = await dbContext.Database.BeginTransactionAsync(IsolationLevel.Serializable, cancellationToken);
|
||||
}
|
||||
transaction =
|
||||
await dbContext.Database.BeginTransactionAsync(IsolationLevel.Serializable, cancellationToken);
|
||||
|
||||
await using (transaction)
|
||||
{
|
||||
var existingAdministrator = await (
|
||||
from binding in dbContext.PlatformBackendUserRoles.AsNoTracking()
|
||||
join boundRole in dbContext.PlatformBackendRoles.AsNoTracking() on binding.RoleId equals boundRole.Id
|
||||
join boundUser in dbContext.Users.AsNoTracking() on binding.UserId equals boundUser.Id
|
||||
where boundRole.Status == BackendRoleStatus.Active && boundUser.Status == UserStatus.Active
|
||||
select boundUser.Id)
|
||||
from binding in dbContext.PlatformBackendUserRoles.AsNoTracking()
|
||||
join boundRole in dbContext.PlatformBackendRoles.AsNoTracking() on binding.RoleId equals boundRole
|
||||
.Id
|
||||
join boundUser in dbContext.Users.AsNoTracking() on binding.UserId equals boundUser.Id
|
||||
where boundRole.Status == BackendRoleStatus.Active && boundUser.Status == UserStatus.Active
|
||||
select boundUser.Id)
|
||||
.AnyAsync(cancellationToken);
|
||||
if (existingAdministrator)
|
||||
{
|
||||
throw new PlatformAdminBootstrapException(
|
||||
"A platform administrator already exists. Bootstrap is a one-time operation.",
|
||||
"platform_admin_already_exists");
|
||||
}
|
||||
|
||||
var normalizedEmail = userManager.NormalizeEmail(email);
|
||||
if (await dbContext.Users.AsNoTracking().AnyAsync(
|
||||
user => user.NormalizedEmail == normalizedEmail || user.NormalizedUserName == normalizedEmail,
|
||||
cancellationToken))
|
||||
{
|
||||
throw new PlatformAdminBootstrapException(
|
||||
"The bootstrap email is already assigned to a user.",
|
||||
"bootstrap_user_already_exists");
|
||||
}
|
||||
|
||||
var user = new User
|
||||
{
|
||||
Email = email,
|
||||
UserName = email,
|
||||
Name = string.IsNullOrWhiteSpace(options.DisplayName) ? "Platform Administrator" : options.DisplayName.Trim(),
|
||||
Name = string.IsNullOrWhiteSpace(options.DisplayName)
|
||||
? "Platform Administrator"
|
||||
: options.DisplayName.Trim(),
|
||||
EmailConfirmed = true,
|
||||
Status = UserStatus.Active,
|
||||
ForcePasswordChange = true
|
||||
@@ -84,7 +78,8 @@ public sealed class PlatformAdminBootstrapper(
|
||||
var createResult = await userManager.CreateAsync(user, options.TemporaryPassword);
|
||||
if (!createResult.Succeeded)
|
||||
{
|
||||
var errors = string.Join(", ", createResult.Errors.Select(error => $"{error.Code}: {error.Description}"));
|
||||
var errors = string.Join(", ",
|
||||
createResult.Errors.Select(error => $"{error.Code}: {error.Description}"));
|
||||
throw new PlatformAdminBootstrapException(
|
||||
$"Platform administrator could not be created: {errors}",
|
||||
"bootstrap_user_invalid");
|
||||
@@ -121,8 +116,8 @@ public sealed class PlatformAdminBootstrapper(
|
||||
.Where(permission => platformPermissionCodes.Contains(permission.Code))
|
||||
.Select(permission => permission.Code)
|
||||
.ToHashSetAsync(StringComparer.Ordinal, cancellationToken);
|
||||
foreach (var permissionCode in platformPermissionCodes.Where(code => !existingPermissionCodes.Contains(code)))
|
||||
{
|
||||
foreach (var permissionCode in
|
||||
platformPermissionCodes.Where(code => !existingPermissionCodes.Contains(code)))
|
||||
dbContext.BackendPermissions.Add(new BackendPermission
|
||||
{
|
||||
Code = permissionCode,
|
||||
@@ -132,7 +127,6 @@ public sealed class PlatformAdminBootstrapper(
|
||||
Description = "Built-in platform permission.",
|
||||
IsSystem = true
|
||||
});
|
||||
}
|
||||
|
||||
dbContext.PlatformBackendRolePermissions.AddRange(
|
||||
platformPermissionCodes.Select(permissionCode => new PlatformBackendRolePermission
|
||||
@@ -161,10 +155,7 @@ public sealed class PlatformAdminBootstrapper(
|
||||
});
|
||||
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
if (transaction is not null)
|
||||
{
|
||||
await transaction.CommitAsync(cancellationToken);
|
||||
}
|
||||
if (transaction is not null) await transaction.CommitAsync(cancellationToken);
|
||||
|
||||
return new PlatformAdminBootstrapResult(user.Id, role.Id, email);
|
||||
}
|
||||
@@ -174,4 +165,4 @@ public sealed class PlatformAdminBootstrapper(
|
||||
public sealed class PlatformAdminBootstrapException(string message, string code) : InvalidOperationException(message)
|
||||
{
|
||||
public string Code { get; } = code;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user