Add setup auth schema repair and login diagnostics
This commit is contained in:
parent
498b46952f
commit
503a090dbe
|
|
@ -228,6 +228,7 @@ $routes->post('setup/db-tools/generate', 'Setup::generateMigrations');
|
|||
$routes->post('setup/db-tools/export-master-schema', 'Setup::exportMasterSchema');
|
||||
$routes->post('setup/db-tools/schema-sync', 'Setup::schemaSync');
|
||||
$routes->post('setup/db-tools/schema-sync-step', 'Setup::schemaSyncStep');
|
||||
$routes->post('setup/db-tools/repair-auth-schema', 'Setup::repairAuthSchema');
|
||||
$routes->post('setup/db-tools/prepare-filesystem', 'Setup::prepareFilesystem');
|
||||
$routes->post('setup/db-tools/ensure-admin', 'Setup::ensureAdminLogin');
|
||||
$routes->post('setup/db-tools/complete', 'Setup::complete');
|
||||
|
|
|
|||
|
|
@ -329,6 +329,12 @@ class Setup extends BaseController
|
|||
return $deny;
|
||||
}
|
||||
|
||||
$repair = $this->repairAuthSchemaInternal();
|
||||
if (!empty($repair['errors'])) {
|
||||
session()->setFlashdata('setup_msg', 'Auth schema repair failed before admin setup: ' . implode(' | ', (array) $repair['errors']));
|
||||
return redirect()->to($this->dbToolsUrlWithKey());
|
||||
}
|
||||
|
||||
$username = trim((string) env('setup.admin.username', 'admin'));
|
||||
$email = trim((string) env('setup.admin.email', 'admin@example.com'));
|
||||
$password = (string) env('setup.admin.password', 'Admin@12345');
|
||||
|
|
@ -392,7 +398,12 @@ class Setup extends BaseController
|
|||
$user->addGroup($group);
|
||||
}
|
||||
|
||||
session()->setFlashdata('setup_msg', 'Admin login ' . $action . ': username=' . $username . ', email=' . $email . ', group=' . $group . '.');
|
||||
$repairMsg = '';
|
||||
if (!empty($repair['applied'])) {
|
||||
$repairMsg = ' Auth schema repaired: ' . implode(', ', (array) $repair['applied']) . '.';
|
||||
}
|
||||
|
||||
session()->setFlashdata('setup_msg', 'Admin login ' . $action . ': username=' . $username . ', email=' . $email . ', group=' . $group . '.' . $repairMsg);
|
||||
} catch (\Throwable $e) {
|
||||
session()->setFlashdata('setup_msg', 'Admin login setup failed: ' . $e->getMessage());
|
||||
}
|
||||
|
|
@ -400,6 +411,31 @@ class Setup extends BaseController
|
|||
return redirect()->to($this->dbToolsUrlWithKey());
|
||||
}
|
||||
|
||||
public function repairAuthSchema()
|
||||
{
|
||||
if ($deny = $this->ensureSetupAccess()) {
|
||||
return $deny;
|
||||
}
|
||||
|
||||
$result = $this->repairAuthSchemaInternal();
|
||||
$parts = [];
|
||||
$parts[] = 'Auth schema check finished.';
|
||||
$parts[] = 'Applied: ' . count((array) ($result['applied'] ?? [])) . '.';
|
||||
|
||||
if (!empty($result['applied'])) {
|
||||
$parts[] = 'Changes: ' . implode(', ', (array) $result['applied']) . '.';
|
||||
}
|
||||
if (!empty($result['warnings'])) {
|
||||
$parts[] = 'Warnings: ' . implode(' | ', (array) $result['warnings']) . '.';
|
||||
}
|
||||
if (!empty($result['errors'])) {
|
||||
$parts[] = 'Errors: ' . implode(' | ', (array) $result['errors']) . '.';
|
||||
}
|
||||
|
||||
session()->setFlashdata('setup_msg', implode(' ', $parts));
|
||||
return redirect()->to($this->dbToolsUrlWithKey());
|
||||
}
|
||||
|
||||
public function prepareFilesystem()
|
||||
{
|
||||
if ($deny = $this->ensureSetupAccess()) {
|
||||
|
|
@ -508,6 +544,18 @@ class Setup extends BaseController
|
|||
$errors[] = 'Database error: ' . $dbError;
|
||||
}
|
||||
|
||||
$authSchema = $this->checkAuthSchemaHealth();
|
||||
if (!empty($authSchema['errors'])) {
|
||||
foreach ((array) $authSchema['errors'] as $authErr) {
|
||||
$errors[] = (string) $authErr;
|
||||
}
|
||||
}
|
||||
if (!empty($authSchema['warnings'])) {
|
||||
foreach ((array) $authSchema['warnings'] as $authWarn) {
|
||||
$warnings[] = (string) $authWarn;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->requiredWritablePaths() as $path) {
|
||||
$relative = $this->relativeProjectPath($path);
|
||||
if (!is_dir($path)) {
|
||||
|
|
@ -1247,4 +1295,120 @@ class Setup extends BaseController
|
|||
|
||||
return $absolutePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{applied:array<int,string>,warnings:array<int,string>,errors:array<int,string>}
|
||||
*/
|
||||
private function repairAuthSchemaInternal(): array
|
||||
{
|
||||
$applied = [];
|
||||
$warnings = [];
|
||||
$errors = [];
|
||||
|
||||
try {
|
||||
$tables = config('Auth')->tables;
|
||||
$usersTable = (string) ($tables['users'] ?? 'users');
|
||||
|
||||
if (!$this->tableExists($usersTable)) {
|
||||
$errors[] = 'Auth users table not found: ' . $usersTable . '. Run schema sync first.';
|
||||
return ['applied' => $applied, 'warnings' => $warnings, 'errors' => $errors];
|
||||
}
|
||||
|
||||
$requiredColumns = [
|
||||
'deleted_at' => 'ALTER TABLE `' . $usersTable . '` ADD COLUMN `deleted_at` DATETIME NULL DEFAULT NULL AFTER `updated_at`',
|
||||
'updated_at' => 'ALTER TABLE `' . $usersTable . '` ADD COLUMN `updated_at` DATETIME NULL DEFAULT NULL AFTER `created_at`',
|
||||
'created_at' => 'ALTER TABLE `' . $usersTable . '` ADD COLUMN `created_at` DATETIME NULL DEFAULT NULL AFTER `last_active`',
|
||||
'last_active' => 'ALTER TABLE `' . $usersTable . '` ADD COLUMN `last_active` DATETIME NULL DEFAULT NULL AFTER `active`',
|
||||
'active' => 'ALTER TABLE `' . $usersTable . '` ADD COLUMN `active` TINYINT(1) NOT NULL DEFAULT 0 AFTER `status_message`',
|
||||
'status_message' => 'ALTER TABLE `' . $usersTable . '` ADD COLUMN `status_message` VARCHAR(255) NULL DEFAULT NULL AFTER `status`',
|
||||
'status' => 'ALTER TABLE `' . $usersTable . '` ADD COLUMN `status` VARCHAR(255) NULL DEFAULT NULL AFTER `username`',
|
||||
'username' => 'ALTER TABLE `' . $usersTable . '` ADD COLUMN `username` VARCHAR(30) NULL DEFAULT NULL AFTER `id`',
|
||||
];
|
||||
|
||||
foreach ($requiredColumns as $column => $sql) {
|
||||
if ($this->columnExists($usersTable, $column)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->db->query($sql);
|
||||
$applied[] = $usersTable . '.' . $column;
|
||||
} catch (\Throwable $e) {
|
||||
$errors[] = 'Failed to add ' . $usersTable . '.' . $column . ': ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->columnExists($usersTable, 'deleted_at')) {
|
||||
$errors[] = 'Column still missing after repair: ' . $usersTable . '.deleted_at';
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$errors[] = 'Auth schema repair exception: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
return ['applied' => $applied, 'warnings' => $warnings, 'errors' => $errors];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{warnings:array<int,string>,errors:array<int,string>}
|
||||
*/
|
||||
private function checkAuthSchemaHealth(): array
|
||||
{
|
||||
$warnings = [];
|
||||
$errors = [];
|
||||
|
||||
try {
|
||||
$tables = config('Auth')->tables;
|
||||
$usersTable = (string) ($tables['users'] ?? 'users');
|
||||
|
||||
if (!$this->tableExists($usersTable)) {
|
||||
$errors[] = 'Auth users table missing: ' . $usersTable . '.';
|
||||
return ['warnings' => $warnings, 'errors' => $errors];
|
||||
}
|
||||
|
||||
if (!$this->columnExists($usersTable, 'deleted_at')) {
|
||||
$errors[] = 'Missing required auth column: ' . $usersTable . '.deleted_at (causes login failure).';
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$warnings[] = 'Auth schema diagnostics skipped: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
return ['warnings' => $warnings, 'errors' => $errors];
|
||||
}
|
||||
|
||||
private function tableExists(string $tableName): bool
|
||||
{
|
||||
$tableName = trim($tableName);
|
||||
if ($tableName === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$tables = $this->db->listTables();
|
||||
return in_array($tableName, $tables, true);
|
||||
} catch (\Throwable $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function columnExists(string $tableName, string $columnName): bool
|
||||
{
|
||||
$tableName = trim($tableName);
|
||||
$columnName = trim($columnName);
|
||||
if ($tableName === '' || $columnName === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$safeTable = preg_replace('/[^a-zA-Z0-9_]/', '', $tableName) ?? '';
|
||||
$safeColumn = preg_replace('/[^a-zA-Z0-9_]/', '', $columnName) ?? '';
|
||||
if ($safeTable === '' || $safeColumn === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$row = $this->db->query("SHOW COLUMNS FROM `{$safeTable}` LIKE '{$safeColumn}'")->getRowArray();
|
||||
return !empty($row);
|
||||
} catch (\Throwable $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -159,6 +159,15 @@
|
|||
|
||||
<hr>
|
||||
|
||||
<form method="post" action="<?= base_url('setup/db-tools/repair-auth-schema') ?>" onsubmit="return confirm('Check and repair auth schema now? This will add missing columns like users.deleted_at if needed.');" style="margin-bottom:10px;">
|
||||
<?= csrf_field() ?>
|
||||
<?php if (!empty($setup_key ?? '')) : ?>
|
||||
<input type="hidden" name="key" value="<?= esc($setup_key) ?>">
|
||||
<?php endif; ?>
|
||||
<button type="submit" class="btn btn-default">Repair Auth Schema (Login Fix)</button>
|
||||
<span class="text-muted" style="margin-left:10px;">Fixes Shield auth schema mismatches such as missing <code>users.deleted_at</code>.</span>
|
||||
</form>
|
||||
|
||||
<form method="post" action="<?= base_url('setup/db-tools/ensure-admin') ?>" onsubmit="return confirm('Create or update admin login for this client database?');" style="margin-bottom:10px;">
|
||||
<?= csrf_field() ?>
|
||||
<?php if (!empty($setup_key ?? '')) : ?>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user