Repair: copy legacy joinDate into new user's created_at when creating users from legacy wallz
This commit is contained in:
135
app/Console/Commands/RepairTemporaryUsernamesCommand.php
Normal file
135
app/Console/Commands/RepairTemporaryUsernamesCommand.php
Normal file
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Support\UsernamePolicy;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class RepairTemporaryUsernamesCommand extends Command
|
||||
{
|
||||
protected $signature = 'skinbase:repair-temp-usernames
|
||||
{--chunk=500 : Number of users to process per batch}
|
||||
{--dry-run : Preview username changes without writing them}';
|
||||
|
||||
protected $description = 'Replace current users.username values like tmpu% using the users.name field';
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$chunk = max(1, (int) $this->option('chunk'));
|
||||
$dryRun = (bool) $this->option('dry-run');
|
||||
|
||||
if ($dryRun) {
|
||||
$this->warn('[DRY RUN] No changes will be written.');
|
||||
}
|
||||
|
||||
$total = (int) DB::table('users')
|
||||
->where('username', 'like', 'tmpu%')
|
||||
->count();
|
||||
|
||||
if ($total === 0) {
|
||||
$this->info('No users with temporary tmpu% usernames were found.');
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
$this->info("Found {$total} users with temporary tmpu% usernames.");
|
||||
|
||||
$processed = 0;
|
||||
$updated = 0;
|
||||
$skipped = 0;
|
||||
|
||||
DB::table('users')
|
||||
->select(['id', 'name', 'username'])
|
||||
->where('username', 'like', 'tmpu%')
|
||||
->chunkById($chunk, function ($rows) use (&$processed, &$updated, &$skipped, $dryRun) {
|
||||
foreach ($rows as $row) {
|
||||
$processed++;
|
||||
|
||||
$sourceName = trim((string) ($row->name ?? ''));
|
||||
if ($sourceName === '') {
|
||||
$skipped++;
|
||||
$this->warn("Skipping user id={$row->id}: name is empty.");
|
||||
continue;
|
||||
}
|
||||
|
||||
$candidate = $this->resolveCandidate($sourceName, (int) $row->id);
|
||||
|
||||
if ($candidate === null || strcasecmp($candidate, (string) $row->username) === 0) {
|
||||
$skipped++;
|
||||
$this->warn("Skipping user id={$row->id}: unable to resolve a better username from name='{$sourceName}'.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($dryRun) {
|
||||
$this->line("[dry] Would update user id={$row->id} username '{$row->username}' => '{$candidate}'");
|
||||
$updated++;
|
||||
continue;
|
||||
}
|
||||
|
||||
$affected = DB::table('users')
|
||||
->where('id', (int) $row->id)
|
||||
->where('username', 'like', 'tmpu%')
|
||||
->update([
|
||||
'username' => $candidate,
|
||||
'username_changed_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
if ($affected > 0) {
|
||||
$updated += $affected;
|
||||
$this->line("[update] user id={$row->id} username '{$row->username}' => '{$candidate}'");
|
||||
}
|
||||
}
|
||||
}, 'id');
|
||||
|
||||
$this->info(sprintf('Finished. processed=%d updated=%d skipped=%d', $processed, $updated, $skipped));
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
private function resolveCandidate(string $sourceName, int $userId): ?string
|
||||
{
|
||||
$base = UsernamePolicy::sanitizeLegacy($sourceName);
|
||||
$min = UsernamePolicy::min();
|
||||
$max = UsernamePolicy::max();
|
||||
|
||||
if ($base === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (preg_match('/^tmpu\d+$/i', $base) === 1) {
|
||||
$base = 'user' . $userId;
|
||||
}
|
||||
|
||||
if (strlen($base) < $min) {
|
||||
$base = substr($base . $userId, 0, $max);
|
||||
}
|
||||
|
||||
if ($base === '' || $base === 'user') {
|
||||
$base = 'user' . $userId;
|
||||
}
|
||||
|
||||
$candidate = substr($base, 0, $max);
|
||||
$suffix = 1;
|
||||
|
||||
while ($this->usernameExists($candidate, $userId) || UsernamePolicy::isReserved($candidate)) {
|
||||
$suffixValue = (string) $suffix;
|
||||
$prefixLen = max(1, $max - strlen($suffixValue));
|
||||
$candidate = substr($base, 0, $prefixLen) . $suffixValue;
|
||||
$suffix++;
|
||||
}
|
||||
|
||||
return $candidate;
|
||||
}
|
||||
|
||||
private function usernameExists(string $username, int $ignoreUserId): bool
|
||||
{
|
||||
return DB::table('users')
|
||||
->whereRaw('LOWER(username) = ?', [strtolower($username)])
|
||||
->where('id', '!=', $ignoreUserId)
|
||||
->exists();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user