From 28efa90222325b257e600793264acd5d01b300f5 Mon Sep 17 00:00:00 2001 From: master3395 Date: Mon, 19 Jan 2026 20:55:08 +0100 Subject: [PATCH] Add automatic rainloop to snappymail data migration for 2.4.4 -> 2.5.5-dev upgrades - Added migrateRainloopToSnappymail() function to automatically migrate email data - Migrates from /usr/local/lscp/cyberpanel/rainloop/data to /usr/local/lscp/cyberpanel/snappymail/data - Uses rsync to preserve permissions and ownership - Updates include.php files to use new snappymail path - Includes safety checks to prevent data overwriting - Added migration logic to cyberpanel_upgrade.sh - Updated default paths from rainloop to snappymail - Deprecates rainloop folder in 2.5.5-dev --- cyberpanel_upgrade.sh | 46 +++++++++++++-- plogical/upgrade.py | 128 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 166 insertions(+), 8 deletions(-) diff --git a/cyberpanel_upgrade.sh b/cyberpanel_upgrade.sh index 050f3838c..4d5952302 100644 --- a/cyberpanel_upgrade.sh +++ b/cyberpanel_upgrade.sh @@ -1453,12 +1453,46 @@ fi # Fix SnappyMail directory permissions for Ubuntu 24.04 and other systems echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Checking SnappyMail directories..." | tee -a /var/log/cyberpanel_upgrade_debug.log -# Create SnappyMail data directories if they don't exist -mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/configs/ -mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/domains/ -mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/storage/ -mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/temp/ -mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/cache/ +# Migrate data from old rainloop folder to new snappymail folder (2.4.4 -> 2.5.5 upgrade) +if [ -d "/usr/local/lscp/cyberpanel/rainloop/data" ] && [ "$(ls -A /usr/local/lscp/cyberpanel/rainloop/data 2>/dev/null)" ]; then + echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Migrating rainloop data to snappymail..." | tee -a /var/log/cyberpanel_upgrade_debug.log + + # Check if snappymail data already exists with content + if [ -d "/usr/local/lscp/cyberpanel/snappymail/data" ] && [ -d "/usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/configs" ]; then + echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] SnappyMail data already exists, skipping migration" | tee -a /var/log/cyberpanel_upgrade_debug.log + else + # Create SnappyMail data directories if they don't exist + mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/configs/ + mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/domains/ + mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/storage/ + mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/temp/ + mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/cache/ + + # Migrate data using rsync (preserves permissions and ownership) + rsync -av --ignore-existing /usr/local/lscp/cyberpanel/rainloop/data/ /usr/local/lscp/cyberpanel/snappymail/data/ 2>&1 | tee -a /var/log/cyberpanel_upgrade_debug.log + + if [ $? -eq 0 ]; then + echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Successfully migrated rainloop data to snappymail" | tee -a /var/log/cyberpanel_upgrade_debug.log + + # Update include.php to use snappymail path + if [ -f "/usr/local/CyberCP/public/snappymail/include.php" ]; then + sed -i 's|/usr/local/lscp/cyberpanel/rainloop/data|/usr/local/lscp/cyberpanel/snappymail/data|g' /usr/local/CyberCP/public/snappymail/include.php + echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] Updated include.php to use snappymail data path" | tee -a /var/log/cyberpanel_upgrade_debug.log + fi + else + echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] WARNING: Data migration completed with errors" | tee -a /var/log/cyberpanel_upgrade_debug.log + fi + fi +else + echo -e "[$(date +"%Y-%m-%d %H:%M:%S")] No old rainloop data found, creating new SnappyMail directories..." | tee -a /var/log/cyberpanel_upgrade_debug.log + + # Create SnappyMail data directories if they don't exist + mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/configs/ + mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/domains/ + mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/storage/ + mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/temp/ + mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/cache/ +fi # Ensure proper ownership for SnappyMail data directories if id -u lscpd >/dev/null 2>&1; then diff --git a/plogical/upgrade.py b/plogical/upgrade.py index 7523bf319..17e83fe70 100644 --- a/plogical/upgrade.py +++ b/plogical/upgrade.py @@ -1427,13 +1427,14 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; for items in data: if items.find("$sCustomDataPath = '';") > -1: writeToFile.writelines( - " $sCustomDataPath = '/usr/local/lscp/cyberpanel/rainloop/data';\n") + " $sCustomDataPath = '/usr/local/lscp/cyberpanel/snappymail/data';\n") else: writeToFile.writelines(items) writeToFile.close() - command = "mkdir -p /usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/configs/" + # Create snappymail data directories (rainloop is deprecated in 2.5.5) + command = "mkdir -p /usr/local/lscp/cyberpanel/snappymail/data/_data_/_default_/configs/" Upgrade.executioner_silent(command, 'mkdir snappymail configs', 0) command = f'wget -q -O /usr/local/CyberCP/snappymail_cyberpanel.php https://raw.githubusercontent.com/the-djmaze/snappymail/master/integrations/cyberpanel/install.php' @@ -1563,6 +1564,9 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; os.chdir(cwd) + # Migrate data from old rainloop folder to new snappymail folder (2.4.4 -> 2.5.5 upgrade) + Upgrade.migrateRainloopToSnappymail() + Upgrade.stdOut("SnappyMail installation completed.", 0) except Exception as e: @@ -3197,6 +3201,126 @@ class Migration(migrations.Migration): Upgrade.stdOut("Error fixing baseTemplate migrations: " + str(e)) @staticmethod + def migrateRainloopToSnappymail(): + """ + Migrate data from old rainloop folder to new snappymail folder + This migration is for upgrading from CyberPanel 2.4.4 to 2.5.5-dev + """ + try: + old_data_path = '/usr/local/lscp/cyberpanel/rainloop/data' + new_data_path = '/usr/local/lscp/cyberpanel/snappymail/data' + + # Check if old rainloop data exists + if not os.path.exists(old_data_path): + Upgrade.stdOut("No old rainloop data found, skipping migration.", 0) + return 0 + + # Check if old data directory has actual content + try: + old_data_contents = os.listdir(old_data_path) + if not old_data_contents or old_data_contents == []: + Upgrade.stdOut("Old rainloop data directory is empty, skipping migration.", 0) + return 0 + except: + Upgrade.stdOut("Could not read old rainloop data directory, skipping migration.", 0) + return 0 + + # Check if new snappymail data already exists and has content + if os.path.exists(new_data_path): + try: + new_data_contents = os.listdir(new_data_path) + # If new directory has content (more than just empty subdirs), don't migrate + if new_data_contents and len(new_data_contents) > 0: + # Check if _data_ directory exists and has content + data_dir = os.path.join(new_data_path, '_data_') + if os.path.exists(data_dir): + default_dir = os.path.join(data_dir, '_default_') + if os.path.exists(default_dir): + default_contents = os.listdir(default_dir) + # If configs, domains, or storage exist, assume migration already done + if any(item in default_contents for item in ['configs', 'domains', 'storage']): + Upgrade.stdOut("SnappyMail data already exists, skipping migration.", 0) + return 0 + except: + pass + + Upgrade.stdOut("Migrating rainloop data to snappymail...", 0) + + # Ensure new data directory structure exists + os.makedirs(new_data_path, exist_ok=True) + os.makedirs(os.path.join(new_data_path, '_data_', '_default_'), exist_ok=True) + + # Use rsync to copy data (preserves permissions, ownership, and handles large files) + import subprocess + import shlex + + # Copy all data from old to new location + command = f'rsync -av --ignore-existing {old_data_path}/ {new_data_path}/' + cmd = shlex.split(command) + result = subprocess.call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + + if result == 0: + # Set proper ownership for migrated data + command = "chown -R lscpd:lscpd " + new_data_path + Upgrade.executioner_silent(command, 'Set ownership for migrated data', 0) + + # Set proper permissions + command = "chmod -R 775 " + new_data_path + Upgrade.executioner_silent(command, 'Set permissions for migrated data', 0) + + Upgrade.stdOut("Successfully migrated rainloop data to snappymail.", 0) + + # Update include.php to use new snappymail path + include_file = '/usr/local/CyberCP/public/snappymail/include.php' + if os.path.exists(include_file): + try: + with open(include_file, 'r') as f: + content = f.read() + + # Replace rainloop path with snappymail path + content = content.replace( + '/usr/local/lscp/cyberpanel/rainloop/data', + '/usr/local/lscp/cyberpanel/snappymail/data' + ) + + with open(include_file, 'w') as f: + f.write(content) + + Upgrade.stdOut("Updated include.php to use snappymail data path.", 0) + except Exception as e: + Upgrade.stdOut(f"Warning: Could not update include.php: {str(e)}", 0) + + # Also update the version-specific include.php if it exists + try: + iPath = os.listdir('/usr/local/CyberCP/public/snappymail/snappymail/v/') + if iPath: + version_include = f"/usr/local/CyberCP/public/snappymail/snappymail/v/{iPath[0]}/include.php" + if os.path.exists(version_include): + with open(version_include, 'r') as f: + content = f.read() + + # Replace rainloop path with snappymail path + content = content.replace( + '/usr/local/lscp/cyberpanel/rainloop/data', + '/usr/local/lscp/cyberpanel/snappymail/data' + ) + + with open(version_include, 'w') as f: + f.write(content) + + Upgrade.stdOut("Updated version-specific include.php to use snappymail data path.", 0) + except: + pass + + return 1 + else: + Upgrade.stdOut("Warning: Data migration completed with errors. Please verify manually.", 0) + return 0 + + except Exception as e: + Upgrade.stdOut(f"Error during rainloop to snappymail migration: {str(e)}", 0) + return 0 + def IncBackupMigrations(): try: connection, cursor = Upgrade.setupConnection('cyberpanel')