asdasd
All checks were successful
Deploy / deploy-production (push) Has been skipped
Deploy / deploy-staging (push) Successful in 6s

This commit is contained in:
2026-04-11 02:40:45 +02:00
parent c15c90bf6d
commit bbd2e39f86
3 changed files with 33 additions and 82 deletions

View File

@@ -246,7 +246,13 @@
}); });
} }
if (!response.ok) { if (!response.ok) {
throw new Error(payload.error || 'API request failed'); const context = payload && payload.context && typeof payload.context === 'object' ? payload.context : null;
const detail = context
? [context.message, context.statement ? `SQL: ${String(context.statement).slice(0, 500)}` : null]
.filter(Boolean)
.join(' ')
: '';
throw new Error([payload.error || 'API request failed', detail].filter(Boolean).join(' '));
} }
if (payload && Object.prototype.hasOwnProperty.call(payload, 'data')) { if (payload && Object.prototype.hasOwnProperty.call(payload, 'data')) {
return payload.data; return payload.data;
@@ -1471,7 +1477,11 @@
? `Geloeschte Tabellen: ${result.dropped_tables.join(', ')}.` ? `Geloeschte Tabellen: ${result.dropped_tables.join(', ')}.`
: 'Keine Tabellen geloescht.') : 'Keine Tabellen geloescht.')
); );
await loadBootstrap(projectKey); try {
await loadBootstrap(projectKey);
} catch (bootstrapError) {
setError(`Schema wurde initialisiert, aber Bootstrap-Daten konnten nicht geladen werden: ${bootstrapError.message}`);
}
} catch (err) { } catch (err) {
setError(err.message); setError(err.message);
} finally { } finally {

View File

@@ -379,53 +379,7 @@ final class Router
private function simpleSchemaStatus(): array private function simpleSchemaStatus(): array
{ {
$requiredTables = [ return $this->schemaManager()->schemaStatus();
$this->config->tablePrefix() . 'projects',
$this->config->tablePrefix() . 'currencies',
$this->config->tablePrefix() . 'settings',
$this->config->tablePrefix() . 'cost_plans',
$this->config->tablePrefix() . 'measurements',
$this->config->tablePrefix() . 'fx_fetches',
$this->config->tablePrefix() . 'measurement_rates',
$this->config->tablePrefix() . 'payouts',
$this->config->tablePrefix() . 'targets',
$this->config->tablePrefix() . 'dashboard_definitions',
$this->config->tablePrefix() . 'miner_offers',
$this->config->tablePrefix() . 'purchased_miners',
];
$presentTables = $this->fetchTablesByPrefix($this->config->tablePrefix());
$presentRequired = array_values(array_intersect($requiredTables, $presentTables));
$missingTables = array_values(array_diff($requiredTables, $presentRequired));
$pendingUpgrades = [];
if (in_array($this->config->tablePrefix() . 'cost_plans', $presentRequired, true)) {
$columns = $this->fetchColumns($this->config->tablePrefix() . 'cost_plans');
foreach (['mining_speed_value', 'mining_speed_unit', 'bonus_speed_value', 'bonus_speed_unit'] as $column) {
if (!in_array($column, $columns, true)) {
$pendingUpgrades[] = 'cost_plan_speed_columns';
break;
}
}
}
if (
!in_array($this->config->tablePrefix() . 'fx_fetches', $presentTables, true) ||
!in_array($this->config->tablePrefix() . 'fx_rates', $presentTables, true)
) {
$pendingUpgrades[] = 'fx_rates_table';
}
return [
'required_tables' => $requiredTables,
'present_tables' => $presentRequired,
'missing_tables' => $missingTables,
'present_count' => count($presentRequired),
'missing_count' => count($missingTables),
'pending_upgrades' => array_values(array_unique($pendingUpgrades)),
'pending_upgrade_count' => count(array_unique($pendingUpgrades)),
'all_present' => $missingTables === [],
];
} }
private function rebuildPreservingCoreData(string $projectKey): array private function rebuildPreservingCoreData(string $projectKey): array
@@ -606,38 +560,6 @@ final class Router
} }
} }
private function fetchTablesByPrefix(string $prefix): array
{
$pdo = $this->pdo();
$driver = (string) $pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
if ($driver === 'pgsql') {
$sql = 'SELECT table_name FROM information_schema.tables WHERE table_schema = current_schema() AND table_name LIKE :prefix ORDER BY table_name';
} else {
$sql = 'SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name LIKE :prefix ORDER BY table_name';
}
$statement = $pdo->prepare($sql);
$statement->execute(['prefix' => $prefix . '%']);
return array_map('strval', $statement->fetchAll(PDO::FETCH_COLUMN) ?: []);
}
private function fetchColumns(string $tableName): array
{
$pdo = $this->pdo();
$driver = (string) $pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
if ($driver === 'pgsql') {
$sql = 'SELECT column_name FROM information_schema.columns WHERE table_schema = current_schema() AND table_name = :table_name ORDER BY ordinal_position';
} else {
$sql = 'SELECT column_name FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = :table_name ORDER BY ordinal_position';
}
$statement = $pdo->prepare($sql);
$statement->execute(['table_name' => $tableName]);
return array_map('strval', $statement->fetchAll(PDO::FETCH_COLUMN) ?: []);
}
private function refreshFxRates(array $input): array private function refreshFxRates(array $input): array
{ {
$base = strtoupper(trim((string) ($input['base'] ?? 'EUR'))); $base = strtoupper(trim((string) ($input['base'] ?? 'EUR')));

View File

@@ -379,20 +379,39 @@ final class SchemaManager
$sql = (string) file_get_contents($schemaFile); $sql = (string) file_get_contents($schemaFile);
$statements = preg_split('/;\s*(?:\R|$)/', $sql) ?: []; $statements = preg_split('/;\s*(?:\R|$)/', $sql) ?: [];
$currentStatement = null;
$useTransaction = $this->driver === 'pgsql' && !$this->pdo->inTransaction();
try { try {
if ($useTransaction) {
$this->pdo->beginTransaction();
}
foreach ($statements as $statement) { foreach ($statements as $statement) {
$trimmed = trim($statement); $trimmed = trim($statement);
if ($trimmed === '') { if ($trimmed === '') {
continue; continue;
} }
$currentStatement = $trimmed;
$this->pdo->exec($trimmed); $this->pdo->exec($trimmed);
} }
if ($useTransaction && $this->pdo->inTransaction()) {
$this->pdo->commit();
}
} catch (\Throwable $exception) { } catch (\Throwable $exception) {
if ($useTransaction && $this->pdo->inTransaction()) {
$this->pdo->rollBack();
}
throw new ApiException( throw new ApiException(
'Schema-Import fuer Mining-Checker fehlgeschlagen.', 'Schema-Import fuer Mining-Checker fehlgeschlagen.',
500, 500,
['message' => $exception->getMessage()] [
'message' => $exception->getMessage(),
'schema_file' => $schemaFile,
'statement' => $currentStatement !== null ? substr($currentStatement, 0, 1000) : null,
]
); );
} }
} }