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