From b534e7e306db76ad1033c5ec8365bb68480f6459 Mon Sep 17 00:00:00 2001 From: Myron Blair Date: Sat, 20 Jun 2026 05:46:31 +0000 Subject: [PATCH] fix: nested transaction crash and favicon 404 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - accounts.php: remove outer beginTransaction() — AccountManager already wraps in its own transaction; nested transactions fail in SQLite with 'already an active transaction' - accounts.php: on AccountManager failure, manually delete the inserted user row instead - admin/reseller/user index.php: fix favicon href from /assets/img/favicon.svg to nova-favicon.svg Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_01LP9Q4kfCAYAjJnsbHBrViZ --- panel/admin/index.php | 2 +- panel/api/endpoints/accounts.php | 33 ++++++++++++++++---------------- panel/reseller/index.php | 2 +- panel/user/index.php | 2 +- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/panel/admin/index.php b/panel/admin/index.php index 202bf99..2582926 100644 --- a/panel/admin/index.php +++ b/panel/admin/index.php @@ -8,7 +8,7 @@ NovaCPX Admin - + diff --git a/panel/api/endpoints/accounts.php b/panel/api/endpoints/accounts.php index 1dfcfa6..c5843fc 100644 --- a/panel/api/endpoints/accounts.php +++ b/panel/api/endpoints/accounts.php @@ -73,26 +73,25 @@ match ($action) { if ($db->fetchOne("SELECT id FROM users WHERE email = ?", [$body['email']])) Response::error("Email already in use by another account"); if ($db->fetchOne("SELECT id FROM users WHERE username = ?", [$body['username']])) Response::error("Username already taken"); - // Wrap user creation + account provisioning in a single transaction - $db->beginTransaction(); - try { - $userId = (int)$db->insert( - "INSERT INTO users (username, password, email, role, status, reseller_id) VALUES (?,?,?,?,?,?)", - [ - $body['username'], - password_hash($body['password'], PASSWORD_BCRYPT), - $body['email'], - 'user', - 'active', - $user['role'] === 'reseller' ? $user['uid'] : null, - ] - ); - $body['user_id'] = $userId; + // Insert user first — AccountManager::create() wraps everything else in its own transaction + $userId = (int)$db->insert( + "INSERT INTO users (username, password, email, role, status, reseller_id) VALUES (?,?,?,?,?,?)", + [ + $body['username'], + password_hash($body['password'], PASSWORD_BCRYPT), + $body['email'], + 'user', + 'active', + $user['role'] === 'reseller' ? $user['uid'] : null, + ] + ); + $body['user_id'] = $userId; + try { $result = AccountManager::create($body); - $db->commit(); } catch (Throwable $e) { - $db->rollBack(); + // Roll back the user insert if account provisioning failed + $db->execute("DELETE FROM users WHERE id = ?", [$userId]); throw $e; } diff --git a/panel/reseller/index.php b/panel/reseller/index.php index e6d2b05..26a1fb0 100644 --- a/panel/reseller/index.php +++ b/panel/reseller/index.php @@ -15,7 +15,7 @@ $_pname = novacpx_panel_name('NovaCPX'); <?= $_pname ?> — Reseller - + diff --git a/panel/user/index.php b/panel/user/index.php index 475a786..0bd6cf4 100644 --- a/panel/user/index.php +++ b/panel/user/index.php @@ -15,7 +15,7 @@ $_pname = novacpx_panel_name('NovaCPX'); <?= $_pname ?> — My Hosting - +