Repair: copy legacy joinDate into new user's created_at when creating users from legacy wallz
This commit is contained in:
@@ -11,7 +11,7 @@ use Illuminate\Support\Str;
|
||||
|
||||
class ImportLegacyUsers extends Command
|
||||
{
|
||||
protected $signature = 'skinbase:import-legacy-users {--chunk=200 : Chunk size for processing} {--force-reset-all : Force reset passwords for all imported users} {--dry-run : Preview which users would be skipped/deleted without making changes}';
|
||||
protected $signature = 'skinbase:import-legacy-users {--chunk=200 : Chunk size for processing} {--force-reset-all : Force reset passwords for all imported users} {--restore-temp-usernames : Restore legacy usernames for existing users still using tmpu12345-style placeholders} {--dry-run : Preview which users would be skipped/deleted without making changes}';
|
||||
protected $description = 'Import legacy users into the new auth schema per legacy_users_migration spec';
|
||||
|
||||
protected string $migrationLogPath;
|
||||
@@ -20,7 +20,7 @@ class ImportLegacyUsers extends Command
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$this->migrationLogPath = storage_path('logs/username_migration.log');
|
||||
$this->migrationLogPath = (string) storage_path('logs/username_migration.log');
|
||||
@file_put_contents($this->migrationLogPath, '['.now()."] Starting legacy username policy migration\n", FILE_APPEND);
|
||||
|
||||
// Build the set of legacy user IDs that have any meaningful activity.
|
||||
@@ -134,8 +134,14 @@ class ImportLegacyUsers extends Command
|
||||
{
|
||||
$legacyId = (int) $row->user_id;
|
||||
|
||||
// Use legacy username as-is (sanitized only, no numeric suffixing — was unique in old DB).
|
||||
$username = $this->sanitizeUsername((string) ($row->uname ?: ('user' . $legacyId)));
|
||||
// Use legacy username as-is by default. Placeholder tmp usernames can be
|
||||
// restored explicitly with --restore-temp-usernames using safe uniqueness rules.
|
||||
$existingUser = DB::table('users')
|
||||
->select(['id', 'username'])
|
||||
->where('id', $legacyId)
|
||||
->first();
|
||||
|
||||
$username = $this->resolveImportUsername($row, $legacyId, $existingUser?->username ?? null);
|
||||
|
||||
$normalizedLegacy = UsernamePolicy::normalize((string) ($row->uname ?? ''));
|
||||
if ($normalizedLegacy !== $username) {
|
||||
@@ -173,7 +179,12 @@ class ImportLegacyUsers extends Command
|
||||
|
||||
DB::transaction(function () use ($legacyId, $username, $email, $passwordHash, $row, $uploads, $downloads, $pageviews, $awards) {
|
||||
$now = now();
|
||||
$alreadyExists = DB::table('users')->where('id', $legacyId)->exists();
|
||||
$existingUser = DB::table('users')
|
||||
->select(['id', 'username'])
|
||||
->where('id', $legacyId)
|
||||
->first();
|
||||
$alreadyExists = $existingUser !== null;
|
||||
$previousUsername = (string) ($existingUser?->username ?? '');
|
||||
|
||||
// All fields synced from legacy on every run
|
||||
$sharedFields = [
|
||||
@@ -212,7 +223,7 @@ class ImportLegacyUsers extends Command
|
||||
'country_code' => $row->country_code ? substr($row->country_code, 0, 2) : null,
|
||||
'language' => $row->lang ?: null,
|
||||
'birthdate' => $row->birth ?: null,
|
||||
'gender' => $row->gender ?: 'X',
|
||||
'gender' => $this->normalizeLegacyGender($row->gender ?? null),
|
||||
'website' => $row->web ?: null,
|
||||
'updated_at' => $now,
|
||||
]
|
||||
@@ -232,7 +243,7 @@ class ImportLegacyUsers extends Command
|
||||
);
|
||||
|
||||
if (Schema::hasTable('username_redirects')) {
|
||||
$old = UsernamePolicy::normalize((string) ($row->uname ?? ''));
|
||||
$old = $this->usernameRedirectKey((string) ($row->uname ?? ''));
|
||||
if ($old !== '' && $old !== $username) {
|
||||
DB::table('username_redirects')->updateOrInsert(
|
||||
['old_username' => $old],
|
||||
@@ -244,10 +255,50 @@ class ImportLegacyUsers extends Command
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->shouldRestoreTemporaryUsername($previousUsername) && $previousUsername !== $username) {
|
||||
DB::table('username_redirects')->updateOrInsert(
|
||||
['old_username' => $this->usernameRedirectKey($previousUsername)],
|
||||
[
|
||||
'new_username' => $username,
|
||||
'user_id' => $legacyId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected function resolveImportUsername(object $row, int $legacyId, ?string $existingUsername = null): string
|
||||
{
|
||||
$legacyUsername = $this->sanitizeUsername((string) ($row->uname ?: ('user' . $legacyId)));
|
||||
|
||||
if (! $this->option('restore-temp-usernames')) {
|
||||
return $legacyUsername;
|
||||
}
|
||||
|
||||
if ($existingUsername === null || $existingUsername === '') {
|
||||
return $legacyUsername;
|
||||
}
|
||||
|
||||
if (! $this->shouldRestoreTemporaryUsername($existingUsername)) {
|
||||
return $existingUsername;
|
||||
}
|
||||
|
||||
return UsernamePolicy::uniqueCandidate((string) ($row->uname ?: ('user' . $legacyId)), $legacyId);
|
||||
}
|
||||
|
||||
protected function shouldRestoreTemporaryUsername(?string $username): bool
|
||||
{
|
||||
if (! is_string($username) || trim($username) === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return preg_match('/^tmpu\d+$/i', trim($username)) === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure statistic values are safe for unsigned DB columns.
|
||||
*/
|
||||
@@ -265,6 +316,24 @@ class ImportLegacyUsers extends Command
|
||||
return UsernamePolicy::sanitizeLegacy($username);
|
||||
}
|
||||
|
||||
protected function usernameRedirectKey(?string $username): string
|
||||
{
|
||||
$value = $this->sanitizeUsername((string) ($username ?? ''));
|
||||
|
||||
return $value === 'user' && trim((string) ($username ?? '')) === '' ? '' : $value;
|
||||
}
|
||||
|
||||
protected function normalizeLegacyGender(mixed $value): ?string
|
||||
{
|
||||
$normalized = strtoupper(trim((string) ($value ?? '')));
|
||||
|
||||
return match ($normalized) {
|
||||
'M', 'MALE', 'MAN', 'BOY' => 'M',
|
||||
'F', 'FEMALE', 'WOMAN', 'GIRL' => 'F',
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
|
||||
protected function sanitizeEmailLocal(string $value): string
|
||||
{
|
||||
$local = strtolower(trim($value));
|
||||
|
||||
Reference in New Issue
Block a user