fix(seeder): patch existing admin username/password on every boot
CI/CD / CI · API (dotnet build + test) (push) Has been cancelled
CI/CD / CI · Admin API (dotnet build) (push) Has been cancelled
CI/CD / CI · Dashboard (tsc) (push) Has been cancelled
CI/CD / CI · Admin Web (tsc) (push) Has been cancelled
CI/CD / CI · Website (tsc) (push) Has been cancelled
CI/CD / CI · Koja (tsc) (push) Has been cancelled
CI/CD / Deploy · all services (push) Has been cancelled
CI/CD / CI · API (dotnet build + test) (push) Has been cancelled
CI/CD / CI · Admin API (dotnet build) (push) Has been cancelled
CI/CD / CI · Dashboard (tsc) (push) Has been cancelled
CI/CD / CI · Admin Web (tsc) (push) Has been cancelled
CI/CD / CI · Website (tsc) (push) Has been cancelled
CI/CD / CI · Koja (tsc) (push) Has been cancelled
CI/CD / Deploy · all services (push) Has been cancelled
EnsureOwnerAdminAsync now sets Username='admin' (configurable via Seed:SystemAdminUsername) on any existing admin that has no username, and hashes Seed:SystemAdminPassword if provided and no hash is stored. Covers fresh deploys and existing prod admins created before credentials were added. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -54,9 +54,11 @@ public static class PlatformDataSeeder
|
||||
private static async Task EnsureOwnerAdminAsync(AppDbContext db, IConfiguration config, ILogger logger)
|
||||
{
|
||||
const string DefaultOwnerPhone = "09190345606";
|
||||
var configured = config["Seed:SystemAdminPhone"];
|
||||
const string DefaultAdminUsername = "admin";
|
||||
|
||||
var configuredPhone = config["Seed:SystemAdminPhone"];
|
||||
var phone = PhoneNormalizer.Normalize(
|
||||
string.IsNullOrWhiteSpace(configured) ? DefaultOwnerPhone : configured);
|
||||
string.IsNullOrWhiteSpace(configuredPhone) ? DefaultOwnerPhone : configuredPhone);
|
||||
|
||||
if (!PhoneNormalizer.IsValidIranMobile(phone))
|
||||
{
|
||||
@@ -64,28 +66,54 @@ public static class PlatformDataSeeder
|
||||
return;
|
||||
}
|
||||
|
||||
if (await db.SystemAdmins.AnyAsync(a => a.Phone == phone))
|
||||
return;
|
||||
var configuredUsername = config["Seed:SystemAdminUsername"];
|
||||
var username = string.IsNullOrWhiteSpace(configuredUsername) ? DefaultAdminUsername : configuredUsername.Trim().ToLowerInvariant();
|
||||
var defaultPassword = config["Seed:SystemAdminPassword"]; // optional — only set if provided
|
||||
|
||||
db.SystemAdmins.Add(new SystemAdmin
|
||||
var existing = await db.SystemAdmins.FirstOrDefaultAsync(a => a.Phone == phone);
|
||||
|
||||
if (existing is null)
|
||||
{
|
||||
var admin = new SystemAdmin
|
||||
{
|
||||
Id = "sysadmin_owner",
|
||||
Name = "مدیر سامانه",
|
||||
Phone = phone,
|
||||
IsActive = true
|
||||
});
|
||||
IsActive = true,
|
||||
Username = username,
|
||||
PasswordHash = string.IsNullOrWhiteSpace(defaultPassword) ? null : PasswordHasher.Hash(defaultPassword)
|
||||
};
|
||||
db.SystemAdmins.Add(admin);
|
||||
|
||||
try
|
||||
{
|
||||
await db.SaveChangesAsync();
|
||||
logger.LogInformation("Seeded owner system admin with phone {Phone}", phone);
|
||||
logger.LogInformation("Seeded owner system admin with phone {Phone}, username '{Username}'", phone, username);
|
||||
}
|
||||
catch (DbUpdateException)
|
||||
{
|
||||
// api + admin-api boot concurrently against the same DB; another instance
|
||||
// already inserted this admin. Safe to ignore.
|
||||
logger.LogInformation("Owner system admin already seeded by another instance");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Patch existing admin: fill in missing username / password without overwriting set values
|
||||
var patched = false;
|
||||
if (string.IsNullOrWhiteSpace(existing.Username))
|
||||
{
|
||||
existing.Username = username;
|
||||
patched = true;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(existing.PasswordHash) && !string.IsNullOrWhiteSpace(defaultPassword))
|
||||
{
|
||||
existing.PasswordHash = PasswordHasher.Hash(defaultPassword);
|
||||
patched = true;
|
||||
}
|
||||
if (patched)
|
||||
{
|
||||
await db.SaveChangesAsync();
|
||||
logger.LogInformation("Patched owner system admin credentials (username/password)");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Idempotent plan/feature upgrades for all environments (including production).</summary>
|
||||
|
||||
Reference in New Issue
Block a user