fix: ensure phpMyAdmin signin bridge + auto plugin migrations + PMA tmp dir

- Add plogical/phpmyadmin_utils.ensure_phpmyadmin_signin_bridge: restore
  phpmyadminsignin.php and tmp/ if missing (fixes 404 on /phpmyadmin/phpmyadminsignin.php).
- Call from databases phpMyAdmin page, fetchDetailsPHPMYAdmin, install, and upgrade PMA paths.
- install/upgrade: use makedirs(..., exist_ok=True) for phpmyadmin/tmp instead of mkdir.
- pluginInstaller: run migrate when migrations/ contains modules OR enable_migrations;
  use CyberCP venv python; --noinput for migrate; log non-zero exits.
This commit is contained in:
master3395
2026-03-27 01:15:33 +01:00
parent 2b23826948
commit 80ea96cc91
6 changed files with 131 additions and 18 deletions

View File

@@ -31,6 +31,11 @@ class DatabaseManager:
return proc.render()
def phpMyAdmin(self, request = None, userID = None):
try:
from plogical.phpmyadmin_utils import ensure_phpmyadmin_signin_bridge
ensure_phpmyadmin_signin_bridge()
except BaseException:
pass
template = 'databases/phpMyAdmin.html'
proc = httpProc(request, template, None, 'createDatabase')
return proc.render()

View File

@@ -257,6 +257,11 @@ def generateAccess(request):
@csrf_exempt
def fetchDetailsPHPMYAdmin(request):
try:
try:
from plogical.phpmyadmin_utils import ensure_phpmyadmin_signin_bridge
ensure_phpmyadmin_signin_bridge()
except BaseException:
pass
userID = request.session['userID']
admin = Administrator.objects.get(id=userID)

View File

@@ -3986,7 +3986,7 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout';
writeToFile.close()
os.mkdir('/usr/local/CyberCP/public/phpmyadmin/tmp')
os.makedirs('/usr/local/CyberCP/public/phpmyadmin/tmp', exist_ok=True)
command = 'chown -R lscpd:lscpd /usr/local/CyberCP/public/phpmyadmin'
preFlightsChecks.call(command, self.distro, '[chown -R lscpd:lscpd /usr/local/CyberCP/public/phpmyadmin]',

View File

@@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
"""
Ensure phpMyAdmin single-sign-on bridge files exist under public/phpmyadmin/.
Fixes 404 on /phpmyadmin/phpmyadminsignin.php when the file was lost after a partial install or manual change.
"""
from __future__ import annotations
import os
import shutil
from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging
PMA_DIR = '/usr/local/CyberCP/public/phpmyadmin'
SIGNIN_SRC = '/usr/local/CyberCP/plogical/phpmyadminsignin.php'
SIGNIN_NAME = 'phpmyadminsignin.php'
def ensure_phpmyadmin_signin_bridge() -> bool:
"""
Copy plogical/phpmyadminsignin.php into the public phpMyAdmin tree if missing,
ensure tmp/ exists, and fix ownership for lscpd.
Returns True if the sign-in file is present afterward.
"""
dst = os.path.join(PMA_DIR, SIGNIN_NAME)
try:
if not os.path.isdir(PMA_DIR):
return False
if not os.path.isfile(SIGNIN_SRC):
logging.writeToFile('phpmyadmin_utils: source signin missing at ' + SIGNIN_SRC)
return os.path.isfile(dst)
need_copy = (not os.path.isfile(dst)) or os.path.getsize(dst) < 32
if need_copy:
shutil.copy2(SIGNIN_SRC, dst)
tmp_dir = os.path.join(PMA_DIR, 'tmp')
os.makedirs(tmp_dir, exist_ok=True)
try:
from plogical.processUtilities import ProcessUtilities
ProcessUtilities.executioner('chown -R lscpd:lscpd ' + PMA_DIR)
except Exception as ch_ex:
logging.writeToFile('phpmyadmin_utils: chown skipped or failed (non-fatal): ' + str(ch_ex))
return os.path.isfile(dst)
except Exception as ex:
logging.writeToFile('phpmyadmin_utils: ensure_phpmyadmin_signin_bridge failed: ' + str(ex))
return os.path.isfile(dst)

View File

@@ -1388,7 +1388,7 @@ $cfg['Servers'][$i]['port'] = '3306';
writeToFile.writelines("$cfg['TempDir'] = '/usr/local/CyberCP/public/phpmyadmin/tmp';\n")
writeToFile.close()
os.mkdir('/usr/local/CyberCP/public/phpmyadmin/tmp')
os.makedirs('/usr/local/CyberCP/public/phpmyadmin/tmp', exist_ok=True)
if saved_signon and os.path.isfile(tmp_signon):
shutil.copy2(tmp_signon, os.path.join(pma_dir, 'phpmyadminsignin.php'))
@@ -1417,6 +1417,12 @@ $cfg['Servers'][$i]['port'] = '3306';
command = 'chown -R lscpd:lscpd /usr/local/CyberCP/public/phpmyadmin/tmp'
Upgrade.executioner_silent(command, 'chown phpMyAdmin tmp')
try:
from plogical.phpmyadmin_utils import ensure_phpmyadmin_signin_bridge
ensure_phpmyadmin_signin_bridge()
except Exception:
pass
os.chdir(cwd)
except Exception as e:

View File

@@ -58,6 +58,35 @@ class pluginInstaller:
pluginHome = '/usr/local/CyberCP/' + pluginName
return os.path.exists(pluginHome + '/enable_migrations')
@staticmethod
def shouldApplyPluginDatabaseMigrations(pluginName: str) -> bool:
"""
Run Django migrations when the plugin opts in (enable_migrations file)
or when a migrations/ package with real migration modules is shipped.
"""
if pluginInstaller.migrationsEnabled(pluginName):
return True
mig_dir = '/usr/local/CyberCP/' + pluginName + '/migrations'
if not os.path.isdir(mig_dir):
return False
try:
for fn in os.listdir(mig_dir):
if fn.endswith('.py') and fn != '__init__.py':
return True
except OSError:
return False
return False
@staticmethod
def _manage_python_executable():
for candidate in ('/usr/local/CyberCP/bin/python', '/usr/local/CyberCP/bin/python3'):
try:
if os.path.isfile(candidate) and os.access(candidate, os.X_OK):
return candidate
except OSError:
continue
return 'python3'
@staticmethod
def _write_lines_to_protected_file(target_path, lines):
"""
@@ -338,12 +367,31 @@ class pluginInstaller:
@staticmethod
def installMigrations(pluginName):
currentDir = os.getcwd()
os.chdir('/usr/local/CyberCP')
command = "python3 /usr/local/CyberCP/manage.py makemigrations %s" % pluginName
subprocess.call(shlex.split(command))
command = "python3 /usr/local/CyberCP/manage.py migrate %s" % pluginName
subprocess.call(shlex.split(command))
os.chdir(currentDir)
manage_py = '/usr/local/CyberCP/manage.py'
py = pluginInstaller._manage_python_executable()
try:
os.chdir('/usr/local/CyberCP')
mk = subprocess.call(
[py, manage_py, 'makemigrations', pluginName],
stdin=subprocess.DEVNULL,
)
if mk != 0:
pluginInstaller.stdOut(
'makemigrations %s exited %s (ok if no model changes)' % (pluginName, mk)
)
mig = subprocess.call(
[py, manage_py, 'migrate', pluginName, '--noinput'],
stdin=subprocess.DEVNULL,
)
if mig != 0:
pluginInstaller.stdOut(
'migrate %s exited %s — check CyberPanel logs and DB permissions' % (pluginName, mig)
)
finally:
try:
os.chdir(currentDir)
except OSError:
pass
@staticmethod
@@ -427,12 +475,14 @@ class pluginInstaller:
##
if pluginInstaller.migrationsEnabled(pluginName):
pluginInstaller.stdOut('Running Migrations..')
if pluginInstaller.shouldApplyPluginDatabaseMigrations(pluginName):
pluginInstaller.stdOut('Running database migrations for %s..' % pluginName)
pluginInstaller.installMigrations(pluginName)
pluginInstaller.stdOut('Migrations Completed..')
pluginInstaller.stdOut('Database migrations step finished for %s.' % pluginName)
else:
pluginInstaller.stdOut('Migrations not enabled, add file \'enable_migrations\' to plugin to enable')
pluginInstaller.stdOut(
'No plugin migrations to apply (no migrations/ package and no enable_migrations marker).'
)
##
@@ -625,8 +675,11 @@ class pluginInstaller:
def removeMigrations(pluginName):
currentDir = os.getcwd()
os.chdir('/usr/local/CyberCP')
command = "python3 /usr/local/CyberCP/manage.py migrate %s zero" % pluginName
subprocess.call(shlex.split(command))
py = pluginInstaller._manage_python_executable()
subprocess.call(
[py, '/usr/local/CyberCP/manage.py', 'migrate', pluginName, 'zero', '--noinput'],
stdin=subprocess.DEVNULL,
)
os.chdir(currentDir)
@staticmethod
@@ -640,12 +693,12 @@ class pluginInstaller:
##
if pluginInstaller.migrationsEnabled(pluginName):
pluginInstaller.stdOut('Removing migrations..')
if pluginInstaller.shouldApplyPluginDatabaseMigrations(pluginName):
pluginInstaller.stdOut('Reverting database migrations for %s..' % pluginName)
pluginInstaller.removeMigrations(pluginName)
pluginInstaller.stdOut('Migrations removed..')
pluginInstaller.stdOut('Database migrations reverted for %s.' % pluginName)
else:
pluginInstaller.stdOut('Migrations not enabled, add file \'enable_migrations\' to plugin to enable')
pluginInstaller.stdOut('Skipping migrate zero (no migrations package / marker).')
##