You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

107 lines
3.6 KiB

2 days ago
<?php
namespace App\Console\Commands;
use App\Models\User;
use App\Support\VenueAdminCredentials;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
class ResetVenueAdminPasswordsCommand extends Command
{
protected $signature = 'venues:reset-admin-passwords
{--output= : 导出 xlsx 绝对或相对路径(默认 storage/app/exports/venue_admin_password_reset_时间戳.xlsx}
{--dry-run : 仅列出将重置的账号,不改密码、不失效 token、不导出}';
protected $description = '重置全部场馆管理员role=venue_admin密码为随机强密码作废其 Sanctum token并导出仅供运维发放的 Excel';
public function handle(): int
{
$users = User::query()
->where('role', 'venue_admin')
->orderBy('id')
->get(['id', 'username', 'name']);
if ($users->isEmpty()) {
$this->warn('没有 role=venue_admin 的账号。');
return self::SUCCESS;
}
$this->info('将处理 '.$users->count().' 个场馆管理员账号。');
$dryRun = (bool) $this->option('dry-run');
if ($dryRun) {
foreach ($users as $user) {
$this->line($user->id."\t".$user->username);
}
$this->warn('当前为 --dry-run未改密码、未失效 token、未导出。去掉 --dry-run 才会写入。');
return self::SUCCESS;
}
$rows = [];
DB::transaction(function () use ($users, &$rows) {
foreach ($users as $user) {
$plainPassword = VenueAdminCredentials::randomPassword();
$user->password = $plainPassword;
$user->save();
$user->tokens()->delete();
$rows[] = [
'id' => $user->id,
'name' => (string) $user->name,
'username' => (string) $user->username,
'password_plain' => $plainPassword,
];
}
});
$defaultDir = storage_path('app/exports');
if (! is_dir($defaultDir)) {
mkdir($defaultDir, 0755, true);
}
$outPath = $this->option('output');
if (! $outPath) {
$outPath = $defaultDir.'/venue_admin_password_reset_'.now()->format('Ymd_His').'.xlsx';
} elseif (! str_starts_with((string) $outPath, '/')) {
$outPath = base_path($outPath);
}
$this->writeXlsx((string) $outPath, $rows);
$this->info('已重置 '.$users->count().' 个场馆管理员密码,并作废其现有 token。');
$this->info('Excel 已生成(请安全交给运营,不要提交到 git'.$outPath);
return self::SUCCESS;
}
/**
* @param array<int, array{id:int, name:string, username:string, password_plain:string}> $rows
*/
private function writeXlsx(string $path, array $rows): void
{
$sheetRows = [
['用户ID', '姓名', '用户名', '新密码(明文)'],
];
foreach ($rows as $r) {
$sheetRows[] = [
$r['id'],
$r['name'],
$r['username'],
$r['password_plain'],
];
}
$spreadsheet = new Spreadsheet;
$sheet = $spreadsheet->getActiveSheet();
$sheet->setTitle('场馆管理员新密码');
$sheet->fromArray($sheetRows, null, 'A1');
$writer = new Xlsx($spreadsheet);
$writer->save($path);
}
}