diff --git a/CPScripts/ensure_ftp_users_quota_columns.py b/CPScripts/ensure_ftp_users_quota_columns.py new file mode 100644 index 000000000..7685e9739 --- /dev/null +++ b/CPScripts/ensure_ftp_users_quota_columns.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Idempotent schema repair: add custom_quota_enabled and custom_quota_size to the +Django ftp.Users table (Meta.db_table = 'users') if missing. + +Fixes MySQL 1054: Unknown column 'custom_quota_enabled' in 'INSERT INTO' +when creating FTP accounts after upgrading CyberPanel without a matching migration. + +Usage: + CP_DIR=/usr/local/CyberCP python3 ensure_ftp_users_quota_columns.py + python3 ensure_ftp_users_quota_columns.py /usr/local/CyberCP +""" +from __future__ import annotations + +import os +import sys + + +def main() -> int: + try: + if len(sys.argv) > 1 and sys.argv[1].strip(): + cp_dir = os.path.abspath(sys.argv[1].strip()) + else: + cp_dir = os.path.abspath(os.environ.get("CP_DIR", "/usr/local/CyberCP")) + + if not os.path.isdir(cp_dir): + sys.stderr.write("ensure_ftp_users_quota_columns: CP directory not found: %s\n" % cp_dir) + return 1 + + sys.path.insert(0, cp_dir) + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "CyberCP.settings") + + import django + + django.setup() + + from django.db import connection + + table = "users" + alters = ( + ("custom_quota_enabled", "TINYINT(1) NOT NULL DEFAULT 0"), + ("custom_quota_size", "INT NOT NULL DEFAULT 0"), + ) + + with connection.cursor() as cursor: + cursor.execute("SELECT DATABASE()") + row = cursor.fetchone() + dbname = row[0] if row else None + if not dbname: + sys.stderr.write( + "ensure_ftp_users_quota_columns: could not resolve current database name.\n" + ) + return 1 + + for col, definition in alters: + cursor.execute( + """ + SELECT COUNT(*) FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = %s AND TABLE_NAME = %s AND COLUMN_NAME = %s + """, + [dbname, table, col], + ) + exists = cursor.fetchone()[0] > 0 + if exists: + print("ensure_ftp_users_quota_columns: column %s already on %s; skipped." % (col, table)) + continue + # identifiers are fixed literals; definition is controlled (no user input) + cursor.execute( + "ALTER TABLE `%s` ADD COLUMN `%s` %s" % (table, col, definition) + ) + print("ensure_ftp_users_quota_columns: added column %s to %s." % (col, table)) + + print("ensure_ftp_users_quota_columns: done.") + return 0 + except Exception as exc: + sys.stderr.write("ensure_ftp_users_quota_columns: error: %s\n" % (exc,)) + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/deploy-ftp-users-custom-quota-columns.sh b/deploy-ftp-users-custom-quota-columns.sh new file mode 100755 index 000000000..0b5b9d9ad --- /dev/null +++ b/deploy-ftp-users-custom-quota-columns.sh @@ -0,0 +1,66 @@ +#!/bin/bash +# Add missing custom_quota_enabled / custom_quota_size columns to ftp Users table (users). +# Fixes: (1054, "Unknown column 'custom_quota_enabled' in 'INSERT INTO'") on FTP account creation. +# +# Usage: +# sudo bash /home/cyberpanel-repo/deploy-ftp-users-custom-quota-columns.sh +# sudo bash deploy-ftp-users-custom-quota-columns.sh [REPO_DIR] [CP_DIR] + +set -e + +log() { echo "[$(date +%Y-%m-%d\ %H:%M:%S)] $*"; } +err() { log "ERROR: $*" >&2; } + +# Resolve REPO_DIR +if [[ -n "$1" && -f "$1/CPScripts/ensure_ftp_users_quota_columns.py" ]]; then + REPO_DIR="$1" + shift +elif [[ -f "$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)/CPScripts/ensure_ftp_users_quota_columns.py" ]]; then + REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +elif [[ -f "/home/cyberpanel-repo/CPScripts/ensure_ftp_users_quota_columns.py" ]]; then + REPO_DIR="/home/cyberpanel-repo" +elif [[ -f "./CPScripts/ensure_ftp_users_quota_columns.py" ]]; then + REPO_DIR="$(pwd)" +else + err "CPScripts/ensure_ftp_users_quota_columns.py not found." + exit 1 +fi + +CP_DIR="${1:-/usr/local/CyberCP}" +RESTART_LSCPD="${RESTART_LSCPD:-1}" + +if [[ ! -d "$CP_DIR" ]]; then + err "CyberPanel directory not found: $CP_DIR" + exit 1 +fi + +log "REPO_DIR=$REPO_DIR" +log "CP_DIR=$CP_DIR" + +mkdir -p "$CP_DIR/CPScripts" +cp -f "$REPO_DIR/CPScripts/ensure_ftp_users_quota_columns.py" "$CP_DIR/CPScripts/ensure_ftp_users_quota_columns.py" +chmod 644 "$CP_DIR/CPScripts/ensure_ftp_users_quota_columns.py" +log "Copied ensure_ftp_users_quota_columns.py to $CP_DIR/CPScripts/" + +log "Ensuring FTP users table has custom quota columns..." +export CP_DIR +PY="$CP_DIR/bin/python" +if [[ -x "$PY" ]]; then + "$PY" "$CP_DIR/CPScripts/ensure_ftp_users_quota_columns.py" "$CP_DIR" || { err "Python repair failed"; exit 1; } +else + python3 "$CP_DIR/CPScripts/ensure_ftp_users_quota_columns.py" "$CP_DIR" || { err "Python repair failed"; exit 1; } +fi + +if [[ "$RESTART_LSCPD" =~ ^(1|yes|true)$ ]]; then + if systemctl is-active --quiet lscpd 2>/dev/null; then + log "Restarting lscpd..." + systemctl restart lscpd || { err "lscpd restart failed"; exit 1; } + log "lscpd restarted." + else + log "lscpd not running or not a systemd service; skip restart." + fi +else + log "Skipping restart (set RESTART_LSCPD=1 to restart lscpd)." +fi + +log "Deploy complete. Test: Websites → FTP → Create FTP Account." diff --git a/upgrade_modules/10_post_tweak.sh b/upgrade_modules/10_post_tweak.sh index 3b9a38c94..85cf57c29 100644 --- a/upgrade_modules/10_post_tweak.sh +++ b/upgrade_modules/10_post_tweak.sh @@ -368,6 +368,18 @@ if [ -f /usr/local/CyberCP/public/phpmyadmin/phpmyadminsignin.php ]; then grep -q "127.0.0.1" /usr/local/CyberCP/public/phpmyadmin/phpmyadminsignin.php && echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] phpMyAdmin signon default host set to 127.0.0.1" | tee -a /var/log/cyberpanel_upgrade_debug.log fi +# FTP users table: custom quota columns (fixes 1054 on Create FTP Account if schema predates model fields) +if [[ -f /usr/local/CyberCP/CPScripts/ensure_ftp_users_quota_columns.py ]]; then + if [[ -x /usr/local/CyberCP/bin/python ]]; then + CP_DIR=/usr/local/CyberCP /usr/local/CyberCP/bin/python /usr/local/CyberCP/CPScripts/ensure_ftp_users_quota_columns.py /usr/local/CyberCP 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log || true + else + CP_DIR=/usr/local/CyberCP python3 /usr/local/CyberCP/CPScripts/ensure_ftp_users_quota_columns.py /usr/local/CyberCP 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log || true + fi + echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Ran ensure_ftp_users_quota_columns (FTP users table custom quota columns)" | tee -a /var/log/cyberpanel_upgrade_debug.log +else + echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] INFO: ensure_ftp_users_quota_columns.py not in CyberCP yet; run deploy-ftp-users-custom-quota-columns.sh after sync" | tee -a /var/log/cyberpanel_upgrade_debug.log +fi + systemctl restart lscpd }