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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?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);
}
}