mirror of
				https://github.com/usmannasir/cyberpanel.git
				synced 2025-10-31 02:15:55 +01:00 
			
		
		
		
	Update PHP version references and improve AlmaLinux 9 compatibility
- Changed PHP symlink from version 8.0 to 8.3 in various scripts to ensure compatibility with the latest PHP version. - Updated documentation links in the FAQ to point to the new community support page. - Added checks and fixes for MariaDB installation issues specific to AlmaLinux 9. - Enhanced the installation script to support additional PHP versions and improve overall installation reliability.
This commit is contained in:
		| @@ -39,9 +39,9 @@ CyberPanel supports a wide range of PHP versions across different operating syst | |||||||
|  |  | ||||||
| ### ☑️ **Currently Supported PHP Versions** | ### ☑️ **Currently Supported PHP Versions** | ||||||
|  |  | ||||||
| - **PHP 8.5** - Latest stable version (EOL: Dec 2028) | - **PHP 8.5** - Latest stable version (EOL: Dec 2028) ⭐ **NEW!** | ||||||
| - **PHP 8.4** - Stable version (EOL: Dec 2027) | - **PHP 8.4** - Stable version (EOL: Dec 2027) | ||||||
| - **PHP 8.3** - Stable version (EOL: Dec 2027) | - **PHP 8.3** - **Default version** - Stable version (EOL: Dec 2027) 🎯 | ||||||
| - **PHP 8.2** - Stable version (EOL: Dec 2026) | - **PHP 8.2** - Stable version (EOL: Dec 2026) | ||||||
| - **PHP 8.1** - Stable version (EOL: Dec 2025) | - **PHP 8.1** - Stable version (EOL: Dec 2025) | ||||||
| - **PHP 8.0** - Legacy support (EOL: Nov 2023) | - **PHP 8.0** - Legacy support (EOL: Nov 2023) | ||||||
|   | |||||||
| @@ -2278,7 +2278,7 @@ echo "echo \$@ > /etc/cyberpanel/adminPass" >> /usr/bin/adminPass | |||||||
| chmod 700 /usr/bin/adminPass | chmod 700 /usr/bin/adminPass | ||||||
|  |  | ||||||
| rm -f /usr/bin/php | rm -f /usr/bin/php | ||||||
| ln -s /usr/local/lsws/lsphp80/bin/php /usr/bin/php | ln -s /usr/local/lsws/lsphp83/bin/php /usr/bin/php | ||||||
|  |  | ||||||
| if [[ "$Server_OS" = "CentOS" ]] ; then | if [[ "$Server_OS" = "CentOS" ]] ; then | ||||||
| #all centos 7/8 post change goes here | #all centos 7/8 post change goes here | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								faq.sh
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								faq.sh
									
									
									
									
									
								
							| @@ -28,7 +28,7 @@ ${BLUE}------------------------------------------------------------${NC} | |||||||
|  |  | ||||||
| ${PURPLE}3.${NC} How to access LiteSpeed webadmin console ? | ${PURPLE}3.${NC} How to access LiteSpeed webadmin console ? | ||||||
|  |  | ||||||
| Please check this post: ${GREEN}https://forums.cyberpanel.net/discussion/87/tutorial-how-to-setup-and-login-to-openlitespeed-webadmin-console/p1${NC} | Please check this post: ${GREEN}https://community.cyberpanel.net/c/support/55${NC} | ||||||
|  |  | ||||||
| ${BLUE}------------------------------------------------------------${NC} | ${BLUE}------------------------------------------------------------${NC} | ||||||
|  |  | ||||||
| @@ -52,9 +52,9 @@ ${BLUE}------------------------------------------------------------${NC} | |||||||
|  |  | ||||||
| ${PURPLE}6.${NC} How to raise upload limit for cyberpanel's phpMyAdmin and File Manager? | ${PURPLE}6.${NC} How to raise upload limit for cyberpanel's phpMyAdmin and File Manager? | ||||||
|  |  | ||||||
| edit file ${RED}/usr/local/lsws/lsphp73/etc/php.ini${NC} for CentOS or openEuler | edit file ${RED}/usr/local/lsws/lsphp83/etc/php.ini${NC} for CentOS or openEuler | ||||||
|  |  | ||||||
| ${RED}/usr/local/lsws/lsphp73/etc/php/7.3/litespeed/php.ini${NC} for Ubbuntu | ${RED}/usr/local/lsws/lsphp83/etc/php/8.3/litespeed/php.ini${NC} for Ubuntu | ||||||
|  |  | ||||||
| find 2 configurations: | find 2 configurations: | ||||||
|  |  | ||||||
| @@ -66,9 +66,9 @@ ${BLUE}------------------------------------------------------------${NC} | |||||||
|  |  | ||||||
| ${PURPLE}7.${NC} How to add more IPs to my website(s) ? | ${PURPLE}7.${NC} How to add more IPs to my website(s) ? | ||||||
|  |  | ||||||
| For OpenLiteSpeed, please check this post: ${GREEN}https://forums.cyberpanel.net/discussion/126/tutorial-how-to-add-2nd-ip-for-websites/p1${NC} | For OpenLiteSpeed, please check this post: ${GREEN}https://community.cyberpanel.net/c/support/55${NC} | ||||||
|  |  | ||||||
| For LiteSpeed Enterprise, please check this post: ${GREEN}https://forums.cyberpanel.net/discussion/3745/tutorial-how-to-add-2nd-ip-for-litespeed-enterprise/p1${NC} | For LiteSpeed Enterprise, please check this post: ${GREEN}https://community.cyberpanel.net/c/support/55${NC} | ||||||
|  |  | ||||||
| ${BLUE}------------------------------------------------------------${NC} | ${BLUE}------------------------------------------------------------${NC} | ||||||
|  |  | ||||||
| @@ -80,7 +80,7 @@ ${BLUE}------------------------------------------------------------${NC} | |||||||
|  |  | ||||||
| ${PURPLE}9.${NC} How to enable Auto-Index for my site ? | ${PURPLE}9.${NC} How to enable Auto-Index for my site ? | ||||||
|  |  | ||||||
| Please check this post ${GREEN}https://forums.cyberpanel.net/discussion/3850/tutorial-how-to-enable-auto-index-on-openlitespeed-and-litespeed-enterprise${NC} | Please check this post ${GREEN}https://community.cyberpanel.net/c/support/55${NC} | ||||||
|  |  | ||||||
| ${BLUE}------------------------------------------------------------${NC} | ${BLUE}------------------------------------------------------------${NC} | ||||||
|  |  | ||||||
| @@ -111,5 +111,5 @@ ${BLUE}------------------------------------------------------------${NC} | |||||||
|  |  | ||||||
| ${PURPLE}13.${NC} How to enable PHP error log ? | ${PURPLE}13.${NC} How to enable PHP error log ? | ||||||
|  |  | ||||||
| Please check this post ${GREEN}https://forums.cyberpanel.net/discussion/3977/tutorial-how-to-enable-php-error-log/p1${NC} | Please check this post ${GREEN}https://community.cyberpanel.net/c/support/55${NC} | ||||||
| " | " | ||||||
| @@ -1,190 +0,0 @@ | |||||||
| import os |  | ||||||
| import shutil |  | ||||||
| import pathlib |  | ||||||
| import stat |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def mkdir_p(path, exist_ok=True): |  | ||||||
|     """ |  | ||||||
|     Creates the directory and paths leading up to it like unix mkdir -p . |  | ||||||
|     Defaults to exist_ok so if it exists were not throwing fatal errors |  | ||||||
|     https://docs.python.org/3.7/library/os.html#os.makedirs |  | ||||||
|     """ |  | ||||||
|     if not os.path.exists(path): |  | ||||||
|         print('creating directory: ' + path) |  | ||||||
|         os.makedirs(path, exist_ok) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def chmod_digit(file_path, perms): |  | ||||||
|     """ |  | ||||||
|     Helper function to chmod like you would in unix without having to preface 0o or converting to octal yourself. |  | ||||||
|     Credits: https://stackoverflow.com/a/60052847/1621381 |  | ||||||
|     """ |  | ||||||
|     try: |  | ||||||
|         os.chmod(file_path, int(str(perms), base=8)) |  | ||||||
|     except: |  | ||||||
|         print(f'Could not chmod : {file_path} to {perms}') |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def touch(filepath: str, exist_ok=True): |  | ||||||
|     """ |  | ||||||
|     Touches a file like unix `touch somefile` would. |  | ||||||
|     """ |  | ||||||
|     try: |  | ||||||
|         pathlib.Path(filepath).touch(exist_ok) |  | ||||||
|     except FileExistsError: |  | ||||||
|         print('Could touch : ' + filepath) |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def symlink(src, dst): |  | ||||||
|     """ |  | ||||||
|     Symlink a path to another if the src exists. |  | ||||||
|     """ |  | ||||||
|     try: |  | ||||||
|         if os.access(src, os.R_OK): |  | ||||||
|             os.symlink(src, dst) |  | ||||||
|     except: |  | ||||||
|         print(f'Could not symlink Source: {src} > Destination: {dst}') |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def chown(path, user, group=-1): |  | ||||||
|     """ |  | ||||||
|     Chown file/path to user/group provided. Passing -1 to user or group will leave it unchanged. |  | ||||||
|     Useful if just changing user or group vs both. |  | ||||||
|     """ |  | ||||||
|     try: |  | ||||||
|         shutil.chown(path, user, group) |  | ||||||
|     except PermissionError: |  | ||||||
|         print(f'Could not change permissions for: {path} to {user}:{group}') |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def recursive_chown(path, owner, group=-1): |  | ||||||
|     """ |  | ||||||
|     Recursively chown a path and contents to owner. |  | ||||||
|     https://docs.python.org/3/library/shutil.html |  | ||||||
|     """ |  | ||||||
|     for dirpath, dirnames, filenames in os.walk(path): |  | ||||||
|         try: |  | ||||||
|             shutil.chown(dirpath, owner, group) |  | ||||||
|         except PermissionError: |  | ||||||
|             print('Could not change permissions for: ' + dirpath + ' to: ' + owner) |  | ||||||
|             pass |  | ||||||
|         for filename in filenames: |  | ||||||
|             try: |  | ||||||
|                 shutil.chown(os.path.join(dirpath, filename), owner, group) |  | ||||||
|             except PermissionError: |  | ||||||
|                 print('Could not change permissions for: ' + os.path.join(dirpath, filename) + ' to: ' + owner) |  | ||||||
|                 pass |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def recursive_permissions(path, dir_mode=755, file_mode=644, topdir=True): |  | ||||||
|     """ |  | ||||||
|     Recursively chmod a path and contents to mode. |  | ||||||
|     Defaults to chmod top level directory but can be optionally |  | ||||||
|     toggled off when you want to chmod only contents of like a user's homedir vs homedir itself |  | ||||||
|     https://docs.python.org/3.6/library/os.html#os.walk |  | ||||||
|     """ |  | ||||||
|  |  | ||||||
|     # Here we are converting the integers to string and then to octal. |  | ||||||
|     # so this function doesn't need to be called with 0o prefixed for the file and dir mode |  | ||||||
|     dir_mode = int(str(dir_mode), base=8) |  | ||||||
|     file_mode = int(str(file_mode), base=8) |  | ||||||
|  |  | ||||||
|     if topdir: |  | ||||||
|         # Set chmod on top level path |  | ||||||
|         try: |  | ||||||
|             os.chmod(path, dir_mode) |  | ||||||
|         except: |  | ||||||
|             print('Could not chmod :' + path + ' to ' + str(dir_mode)) |  | ||||||
|     for root, dirs, files in os.walk(path): |  | ||||||
|         for d in dirs: |  | ||||||
|             try: |  | ||||||
|                 os.chmod(os.path.join(root, d), dir_mode) |  | ||||||
|             except: |  | ||||||
|                 print('Could not chmod :' + os.path.join(root, d) + ' to ' + str(dir_mode)) |  | ||||||
|                 pass |  | ||||||
|         for f in files: |  | ||||||
|             try: |  | ||||||
|                 os.chmod(os.path.join(root, f), file_mode) |  | ||||||
|             except: |  | ||||||
|                 print('Could not chmod :' + path + ' to ' + str(file_mode)) |  | ||||||
|                 pass |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Left intentionally here for reference. |  | ||||||
| # Set recursive chown for a path |  | ||||||
| # recursive_chown(my_path, 'root', 'root') |  | ||||||
| # for changing group recursively without affecting user |  | ||||||
| # recursive_chown('/usr/local/lscp/cyberpanel/rainloop/data', -1, 'lscpd') |  | ||||||
|  |  | ||||||
| # explicitly set permissions for directories/folders to 0755 and files to 0644 |  | ||||||
| # recursive_permissions(my_path, 755, 644) |  | ||||||
|  |  | ||||||
| # Fix permissions and use default values |  | ||||||
| # recursive_permissions(my_path) |  | ||||||
| # ========================================================= |  | ||||||
| # Below is a helper class for getting and working with permissions |  | ||||||
| # Original credits to : https://github.com/keysemble/perfm |  | ||||||
|  |  | ||||||
| def perm_octal_digit(rwx): |  | ||||||
|     digit = 0 |  | ||||||
|     if rwx[0] == 'r': |  | ||||||
|         digit += 4 |  | ||||||
|     if rwx[1] == 'w': |  | ||||||
|         digit += 2 |  | ||||||
|     if rwx[2] == 'x': |  | ||||||
|         digit += 1 |  | ||||||
|     return digit |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class FilePerm: |  | ||||||
|     def __init__(self, filepath): |  | ||||||
|         filemode = stat.filemode(os.stat(filepath).st_mode) |  | ||||||
|         permissions = [filemode[-9:][i:i + 3] for i in range(0, len(filemode[-9:]), 3)] |  | ||||||
|         self.filepath = filepath |  | ||||||
|         self.access_dict = dict(zip(['user', 'group', 'other'], [list(perm) for perm in permissions])) |  | ||||||
|  |  | ||||||
|     def mode(self): |  | ||||||
|         mode = 0 |  | ||||||
|         for shift, digit in enumerate(self.octal()[::-1]): |  | ||||||
|             mode += digit << (shift * 3) |  | ||||||
|         return mode |  | ||||||
|  |  | ||||||
|     def digits(self): |  | ||||||
|         """Get the octal chmod equivalent value 755 in single string""" |  | ||||||
|         return "".join(map(str, self.octal())) |  | ||||||
|  |  | ||||||
|     def octal(self): |  | ||||||
|         """Get the octal value in a list [7, 5, 5]""" |  | ||||||
|         return [perm_octal_digit(p) for p in self.access_dict.values()] |  | ||||||
|  |  | ||||||
|     def access_bits(self, access): |  | ||||||
|         if access in self.access_dict.keys(): |  | ||||||
|             r, w, x = self.access_dict[access] |  | ||||||
|             return [r == 'r', w == 'w', x == 'x'] |  | ||||||
|  |  | ||||||
|     def update_bitwise(self, settings): |  | ||||||
|         def perm_list(read=False, write=False, execute=False): |  | ||||||
|             pl = ['-', '-', '-'] |  | ||||||
|             if read: |  | ||||||
|                 pl[0] = 'r' |  | ||||||
|             if write: |  | ||||||
|                 pl[1] = 'w' |  | ||||||
|             if execute: |  | ||||||
|                 pl[2] = 'x' |  | ||||||
|             return pl |  | ||||||
|  |  | ||||||
|         self.access_dict = dict( |  | ||||||
|             [(access, perm_list(read=r, write=w, execute=x)) for access, [r, w, x] in settings.items()]) |  | ||||||
|         os.chmod(self.filepath, self.mode()) |  | ||||||
|  |  | ||||||
| # project_directory = os.path.abspath(os.path.dirname(sys.argv[0])) |  | ||||||
| # home_directory = os.path.expanduser('~') |  | ||||||
| # print(f'Path: {home_directory}  Mode: {FilePerm(home_directory).mode()}  Octal: {FilePerm(home_directory).octal()} ' |  | ||||||
| #      f'Digits: {FilePerm(home_directory).digits()}') |  | ||||||
| # Example: Output |  | ||||||
| # Path: /home/cooluser  Mode: 493  Octal: [7, 5, 5] Digits: 755 |  | ||||||
| @@ -2969,7 +2969,7 @@ echo $oConfig->Save() ? 'Done' : 'Error'; | |||||||
|         writeToFile.write(content) |         writeToFile.write(content) | ||||||
|         writeToFile.close() |         writeToFile.close() | ||||||
|  |  | ||||||
|         command = '/usr/local/lsws/lsphp72/bin/php /usr/local/CyberCP/public/snappymail.php' |         command = '/usr/local/lsws/lsphp83/bin/php /usr/local/CyberCP/public/snappymail.php' | ||||||
|         subprocess.call(shlex.split(command)) |         subprocess.call(shlex.split(command)) | ||||||
|  |  | ||||||
|         command = "chown -R lscpd:lscpd /usr/local/lscp/cyberpanel/snappymail/data" |         command = "chown -R lscpd:lscpd /usr/local/lscp/cyberpanel/snappymail/data" | ||||||
|   | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -44,6 +44,62 @@ FetchCloudLinuxAlmaVersionVersion = install_utils.FetchCloudLinuxAlmaVersionVers | |||||||
| class InstallCyberPanel: | class InstallCyberPanel: | ||||||
|     mysql_Root_password = "" |     mysql_Root_password = "" | ||||||
|     mysqlPassword = "" |     mysqlPassword = "" | ||||||
|  |      | ||||||
|  |     def is_almalinux9(self): | ||||||
|  |         """Check if running on AlmaLinux 9""" | ||||||
|  |         if os.path.exists('/etc/almalinux-release'): | ||||||
|  |             try: | ||||||
|  |                 with open('/etc/almalinux-release', 'r') as f: | ||||||
|  |                     content = f.read() | ||||||
|  |                     return 'release 9' in content | ||||||
|  |             except: | ||||||
|  |                 return False | ||||||
|  |         return False | ||||||
|  |      | ||||||
|  |     def fix_almalinux9_mariadb(self): | ||||||
|  |         """Fix AlmaLinux 9 MariaDB installation issues""" | ||||||
|  |         if not self.is_almalinux9(): | ||||||
|  |             return | ||||||
|  |          | ||||||
|  |         self.stdOut("Applying AlmaLinux 9 MariaDB fixes...", 1) | ||||||
|  |          | ||||||
|  |         try: | ||||||
|  |             # Disable problematic MariaDB MaxScale repository | ||||||
|  |             self.stdOut("Disabling problematic MariaDB MaxScale repository...", 1) | ||||||
|  |             command = "dnf config-manager --disable mariadb-maxscale 2>/dev/null || true" | ||||||
|  |             install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) | ||||||
|  |              | ||||||
|  |             # Remove problematic repository files | ||||||
|  |             self.stdOut("Removing problematic repository files...", 1) | ||||||
|  |             problematic_repos = [ | ||||||
|  |                 '/etc/yum.repos.d/mariadb-maxscale.repo', | ||||||
|  |                 '/etc/yum.repos.d/mariadb-maxscale.repo.rpmnew' | ||||||
|  |             ] | ||||||
|  |             for repo_file in problematic_repos: | ||||||
|  |                 if os.path.exists(repo_file): | ||||||
|  |                     os.remove(repo_file) | ||||||
|  |                     self.stdOut(f"Removed {repo_file}", 1) | ||||||
|  |              | ||||||
|  |             # Clean DNF cache | ||||||
|  |             self.stdOut("Cleaning DNF cache...", 1) | ||||||
|  |             command = "dnf clean all" | ||||||
|  |             install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) | ||||||
|  |              | ||||||
|  |             # Install MariaDB from official repository | ||||||
|  |             self.stdOut("Setting up official MariaDB repository...", 1) | ||||||
|  |             command = "curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | bash -s -- --mariadb-server-version='10.11'" | ||||||
|  |             install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) | ||||||
|  |              | ||||||
|  |             # Install MariaDB packages | ||||||
|  |             self.stdOut("Installing MariaDB packages...", 1) | ||||||
|  |             mariadb_packages = "MariaDB-server MariaDB-client MariaDB-backup MariaDB-devel" | ||||||
|  |             command = f"dnf install -y {mariadb_packages}" | ||||||
|  |             install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) | ||||||
|  |              | ||||||
|  |             self.stdOut("AlmaLinux 9 MariaDB fixes completed", 1) | ||||||
|  |              | ||||||
|  |         except Exception as e: | ||||||
|  |             self.stdOut(f"Error applying AlmaLinux 9 MariaDB fixes: {str(e)}", 0) | ||||||
|     CloudLinux8 = 0 |     CloudLinux8 = 0 | ||||||
|  |  | ||||||
|     def install_package(self, package_name, options=""): |     def install_package(self, package_name, options=""): | ||||||
| @@ -335,7 +391,7 @@ class InstallCyberPanel: | |||||||
|         return self.reStartLiteSpeed() |         return self.reStartLiteSpeed() | ||||||
|  |  | ||||||
|     def installAllPHPVersions(self): |     def installAllPHPVersions(self): | ||||||
|         php_versions = ['71', '72', '73', '74', '80', '81', '82', '83'] |         php_versions = ['71', '72', '73', '74', '80', '81', '82', '83', '84', '85'] | ||||||
|          |          | ||||||
|         if self.distro == ubuntu: |         if self.distro == ubuntu: | ||||||
|             # Install base PHP 7.x packages |             # Install base PHP 7.x packages | ||||||
| @@ -563,6 +619,12 @@ gpgcheck=1 | |||||||
|  |  | ||||||
|         if self.remotemysql == 'OFF': |         if self.remotemysql == 'OFF': | ||||||
|             ############## Start mariadb ###################### |             ############## Start mariadb ###################### | ||||||
|  |              | ||||||
|  |             # Check if AlmaLinux 9 and apply fixes | ||||||
|  |             if self.is_almalinux9(): | ||||||
|  |                 self.stdOut("AlmaLinux 9 detected - applying MariaDB fixes", 1) | ||||||
|  |                 self.fix_almalinux9_mariadb() | ||||||
|  |              | ||||||
|             self.manage_service('mariadb', 'start') |             self.manage_service('mariadb', 'start') | ||||||
|  |  | ||||||
|             ############## Enable mariadb at system startup ###################### |             ############## Enable mariadb at system startup ###################### | ||||||
|   | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,121 +0,0 @@ | |||||||
| {% extends "baseTemplate/index.html" %} |  | ||||||
| {% load i18n %} |  | ||||||
| {% block title %}{% trans "Mail Functions - CyberPanel" %}{% endblock %} |  | ||||||
| {% block content %} |  | ||||||
|  |  | ||||||
|     {% load static %} |  | ||||||
|     {% get_current_language as LANGUAGE_CODE %} |  | ||||||
|     <!-- Current language: {{ LANGUAGE_CODE }} --> |  | ||||||
|  |  | ||||||
|     <div class="container"> |  | ||||||
|         <div id="page-title"> |  | ||||||
|             <h2>{% trans "Mail Functions" %}</h2> |  | ||||||
|             <p>{% trans "Manage email accounts on this page." %}</p> |  | ||||||
|         </div> |  | ||||||
|  |  | ||||||
|         <div class="panel col-md-12"> |  | ||||||
|             <div class="panel-body"> |  | ||||||
|                 <h3 class="content-box-header"> |  | ||||||
|                     {% trans "Available Functions" %} |  | ||||||
|                 </h3> |  | ||||||
|  |  | ||||||
|                 <div class="example-box-wrapper"> |  | ||||||
|                     <div class="row"> |  | ||||||
|                         <div class="col-md-3 btn-min-width"> |  | ||||||
|                             <a href="{% url 'createEmailAccount' %}" title="{% trans 'Create Email' %}" |  | ||||||
|                                class="tile-box tile-box-shortcut btn-primary"> |  | ||||||
|                                 <div class="tile-header"> |  | ||||||
|                                     {% trans "Create Email" %} |  | ||||||
|                                 </div> |  | ||||||
|                                 <div class="tile-content-wrapper"> |  | ||||||
|                                     <i class="fa fa-plus-square"></i> |  | ||||||
|                                 </div> |  | ||||||
|                             </a> |  | ||||||
|                         </div> |  | ||||||
|                          |  | ||||||
|                         <div class="col-md-3 btn-min-width"> |  | ||||||
|                             <a href="{% url 'listEmails' %}" title="{% trans 'List Emails' %}" |  | ||||||
|                                class="tile-box tile-box-shortcut btn-primary"> |  | ||||||
|                                 <div class="tile-header"> |  | ||||||
|                                     {% trans "List Emails" %} |  | ||||||
|                                 </div> |  | ||||||
|                                 <div class="tile-content-wrapper"> |  | ||||||
|                                     <i class="fa fa-plus-square"></i> |  | ||||||
|                                 </div> |  | ||||||
|                             </a> |  | ||||||
|                         </div> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|                         <div class="col-md-3 btn-min-width"> |  | ||||||
|                             <a href="{% url 'deleteEmailAccount' %}" title="{% trans 'Delete Email' %}" |  | ||||||
|                                class="tile-box tile-box-shortcut btn-primary"> |  | ||||||
|                                 <div class="tile-header"> |  | ||||||
|                                     {% trans "Delete Email" %} |  | ||||||
|                                 </div> |  | ||||||
|                                 <div class="tile-content-wrapper"> |  | ||||||
|                                     <i class="fa fa-trash"></i> |  | ||||||
|                                 </div> |  | ||||||
|                             </a> |  | ||||||
|                         </div> |  | ||||||
|                          |  | ||||||
|                         <div class="col-md-3 btn-min-width"> |  | ||||||
|                             <a href="{% url 'emailForwarding' %}" title="{% trans 'Email Forwarding' %}" |  | ||||||
|                                class="tile-box tile-box-shortcut btn-primary"> |  | ||||||
|                                 <div class="tile-header"> |  | ||||||
|                                     {% trans "Email Forwarding" %} |  | ||||||
|                                 </div> |  | ||||||
|                                 <div class="tile-content-wrapper"> |  | ||||||
|                                     <i class="fa fa-plus-square"></i> |  | ||||||
|                                 </div> |  | ||||||
|                             </a> |  | ||||||
|                         </div> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|                         <div class="col-md-3 btn-min-width"> |  | ||||||
|                             <a href="{% url 'changeEmailAccountPassword' %}" title="{% trans 'Change Password' %}" |  | ||||||
|                                class="tile-box tile-box-shortcut btn-primary"> |  | ||||||
|                                 <div class="tile-header"> |  | ||||||
|                                     {% trans "Change Password" %} |  | ||||||
|                                 </div> |  | ||||||
|                                 <div class="tile-content-wrapper"> |  | ||||||
|                                     <i class="fa fa-key"></i> |  | ||||||
|                                 </div> |  | ||||||
|                             </a> |  | ||||||
|                         </div> |  | ||||||
|                          |  | ||||||
|                         <div class="col-md-3 btn-min-width"> |  | ||||||
|                             <a href="{% url 'dkimManager' %}" title="{% trans 'DKIM Manager' %}" |  | ||||||
|                                class="tile-box tile-box-shortcut btn-primary"> |  | ||||||
|                                 <div class="tile-header"> |  | ||||||
|                                     {% trans "DKIM Manager" %} |  | ||||||
|                                 </div> |  | ||||||
|                                 <div class="tile-content-wrapper"> |  | ||||||
|                                     <i class="fa fa-key"></i> |  | ||||||
|                                 </div> |  | ||||||
|                             </a> |  | ||||||
|                         </div> |  | ||||||
|                          |  | ||||||
|                         <div class="col-md-3 btn-min-width"> |  | ||||||
|                             <a href="/snappymail/index.php" title="{% trans 'Access Webmail' %}" |  | ||||||
|                                class="tile-box tile-box-shortcut btn-primary"> |  | ||||||
|                                 <div class="tile-header"> |  | ||||||
|                                     {% trans "Access Webmail" %} |  | ||||||
|                                 </div> |  | ||||||
|                                 <div class="tile-content-wrapper"> |  | ||||||
|                                     <i class="fa fa-key"></i> |  | ||||||
|                                 </div> |  | ||||||
|                             </a> |  | ||||||
|                         </div> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|                     </div> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|                 </div> |  | ||||||
|             </div> |  | ||||||
|         </div> |  | ||||||
|  |  | ||||||
|     </div> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| {% endblock %} |  | ||||||
| @@ -1372,7 +1372,7 @@ echo $oConfig->Save() ? 'Done' : 'Error'; | |||||||
|             command = 'chmod 640 /usr/local/lscp/cyberpanel/logs/access.log' |             command = 'chmod 640 /usr/local/lscp/cyberpanel/logs/access.log' | ||||||
|             ProcessUtilities.executioner(command, 'root', True) |             ProcessUtilities.executioner(command, 'root', True) | ||||||
|  |  | ||||||
|             command = '/usr/local/lsws/lsphp72/bin/php /usr/local/CyberCP/public/snappymail.php' |             command = '/usr/local/lsws/lsphp83/bin/php /usr/local/CyberCP/public/snappymail.php' | ||||||
|             ProcessUtilities.executioner(command, 'root', True) |             ProcessUtilities.executioner(command, 'root', True) | ||||||
|  |  | ||||||
|             command = 'chmod 600 /usr/local/CyberCP/public/snappymail.php' |             command = 'chmod 600 /usr/local/CyberCP/public/snappymail.php' | ||||||
|   | |||||||
| @@ -1,190 +0,0 @@ | |||||||
| import os |  | ||||||
| import shutil |  | ||||||
| import pathlib |  | ||||||
| import stat |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def mkdir_p(path, exist_ok=True): |  | ||||||
|     """ |  | ||||||
|     Creates the directory and paths leading up to it like unix mkdir -p . |  | ||||||
|     Defaults to exist_ok so if it exists were not throwing fatal errors |  | ||||||
|     https://docs.python.org/3.7/library/os.html#os.makedirs |  | ||||||
|     """ |  | ||||||
|     if not os.path.exists(path): |  | ||||||
|         print('creating directory: ' + path) |  | ||||||
|         os.makedirs(path, exist_ok) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def chmod_digit(file_path, perms): |  | ||||||
|     """ |  | ||||||
|     Helper function to chmod like you would in unix without having to preface 0o or converting to octal yourself. |  | ||||||
|     Credits: https://stackoverflow.com/a/60052847/1621381 |  | ||||||
|     """ |  | ||||||
|     try: |  | ||||||
|         os.chmod(file_path, int(str(perms), base=8)) |  | ||||||
|     except: |  | ||||||
|         print(f'Could not chmod : {file_path} to {perms}') |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def touch(filepath: str, exist_ok=True): |  | ||||||
|     """ |  | ||||||
|     Touches a file like unix `touch somefile` would. |  | ||||||
|     """ |  | ||||||
|     try: |  | ||||||
|         pathlib.Path(filepath).touch(exist_ok) |  | ||||||
|     except FileExistsError: |  | ||||||
|         print('Could touch : ' + filepath) |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def symlink(src, dst): |  | ||||||
|     """ |  | ||||||
|     Symlink a path to another if the src exists. |  | ||||||
|     """ |  | ||||||
|     try: |  | ||||||
|         if os.access(src, os.R_OK): |  | ||||||
|             os.symlink(src, dst) |  | ||||||
|     except: |  | ||||||
|         print(f'Could not symlink Source: {src} > Destination: {dst}') |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def chown(path, user, group=-1): |  | ||||||
|     """ |  | ||||||
|     Chown file/path to user/group provided. Passing -1 to user or group will leave it unchanged. |  | ||||||
|     Useful if just changing user or group vs both. |  | ||||||
|     """ |  | ||||||
|     try: |  | ||||||
|         shutil.chown(path, user, group) |  | ||||||
|     except PermissionError: |  | ||||||
|         print(f'Could not change permissions for: {path} to {user}:{group}') |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def recursive_chown(path, owner, group=-1): |  | ||||||
|     """ |  | ||||||
|     Recursively chown a path and contents to owner. |  | ||||||
|     https://docs.python.org/3/library/shutil.html |  | ||||||
|     """ |  | ||||||
|     for dirpath, dirnames, filenames in os.walk(path): |  | ||||||
|         try: |  | ||||||
|             shutil.chown(dirpath, owner, group) |  | ||||||
|         except PermissionError: |  | ||||||
|             print('Could not change permissions for: ' + dirpath + ' to: ' + owner) |  | ||||||
|             pass |  | ||||||
|         for filename in filenames: |  | ||||||
|             try: |  | ||||||
|                 shutil.chown(os.path.join(dirpath, filename), owner, group) |  | ||||||
|             except PermissionError: |  | ||||||
|                 print('Could not change permissions for: ' + os.path.join(dirpath, filename) + ' to: ' + owner) |  | ||||||
|                 pass |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def recursive_permissions(path, dir_mode=755, file_mode=644, topdir=True): |  | ||||||
|     """ |  | ||||||
|     Recursively chmod a path and contents to mode. |  | ||||||
|     Defaults to chmod top level directory but can be optionally |  | ||||||
|     toggled off when you want to chmod only contents of like a user's homedir vs homedir itself |  | ||||||
|     https://docs.python.org/3.6/library/os.html#os.walk |  | ||||||
|     """ |  | ||||||
|  |  | ||||||
|     # Here we are converting the integers to string and then to octal. |  | ||||||
|     # so this function doesn't need to be called with 0o prefixed for the file and dir mode |  | ||||||
|     dir_mode = int(str(dir_mode), base=8) |  | ||||||
|     file_mode = int(str(file_mode), base=8) |  | ||||||
|  |  | ||||||
|     if topdir: |  | ||||||
|         # Set chmod on top level path |  | ||||||
|         try: |  | ||||||
|             os.chmod(path, dir_mode) |  | ||||||
|         except: |  | ||||||
|             print('Could not chmod :' + path + ' to ' + str(dir_mode)) |  | ||||||
|     for root, dirs, files in os.walk(path): |  | ||||||
|         for d in dirs: |  | ||||||
|             try: |  | ||||||
|                 os.chmod(os.path.join(root, d), dir_mode) |  | ||||||
|             except: |  | ||||||
|                 print('Could not chmod :' + os.path.join(root, d) + ' to ' + str(dir_mode)) |  | ||||||
|                 pass |  | ||||||
|         for f in files: |  | ||||||
|             try: |  | ||||||
|                 os.chmod(os.path.join(root, f), file_mode) |  | ||||||
|             except: |  | ||||||
|                 print('Could not chmod :' + path + ' to ' + str(file_mode)) |  | ||||||
|                 pass |  | ||||||
|  |  | ||||||
|  |  | ||||||
| # Left intentionally here for reference. |  | ||||||
| # Set recursive chown for a path |  | ||||||
| # recursive_chown(my_path, 'root', 'root') |  | ||||||
| # for changing group recursively without affecting user |  | ||||||
| # recursive_chown('/usr/local/lscp/cyberpanel/rainloop/data', -1, 'lscpd') |  | ||||||
|  |  | ||||||
| # explicitly set permissions for directories/folders to 0755 and files to 0644 |  | ||||||
| # recursive_permissions(my_path, 755, 644) |  | ||||||
|  |  | ||||||
| # Fix permissions and use default values |  | ||||||
| # recursive_permissions(my_path) |  | ||||||
| # ========================================================= |  | ||||||
| # Below is a helper class for getting and working with permissions |  | ||||||
| # Original credits to : https://github.com/keysemble/perfm |  | ||||||
|  |  | ||||||
| def perm_octal_digit(rwx): |  | ||||||
|     digit = 0 |  | ||||||
|     if rwx[0] == 'r': |  | ||||||
|         digit += 4 |  | ||||||
|     if rwx[1] == 'w': |  | ||||||
|         digit += 2 |  | ||||||
|     if rwx[2] == 'x': |  | ||||||
|         digit += 1 |  | ||||||
|     return digit |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class FilePerm: |  | ||||||
|     def __init__(self, filepath): |  | ||||||
|         filemode = stat.filemode(os.stat(filepath).st_mode) |  | ||||||
|         permissions = [filemode[-9:][i:i + 3] for i in range(0, len(filemode[-9:]), 3)] |  | ||||||
|         self.filepath = filepath |  | ||||||
|         self.access_dict = dict(zip(['user', 'group', 'other'], [list(perm) for perm in permissions])) |  | ||||||
|  |  | ||||||
|     def mode(self): |  | ||||||
|         mode = 0 |  | ||||||
|         for shift, digit in enumerate(self.octal()[::-1]): |  | ||||||
|             mode += digit << (shift * 3) |  | ||||||
|         return mode |  | ||||||
|  |  | ||||||
|     def digits(self): |  | ||||||
|         """Get the octal chmod equivalent value 755 in single string""" |  | ||||||
|         return "".join(map(str, self.octal())) |  | ||||||
|  |  | ||||||
|     def octal(self): |  | ||||||
|         """Get the octal value in a list [7, 5, 5]""" |  | ||||||
|         return [perm_octal_digit(p) for p in self.access_dict.values()] |  | ||||||
|  |  | ||||||
|     def access_bits(self, access): |  | ||||||
|         if access in self.access_dict.keys(): |  | ||||||
|             r, w, x = self.access_dict[access] |  | ||||||
|             return [r == 'r', w == 'w', x == 'x'] |  | ||||||
|  |  | ||||||
|     def update_bitwise(self, settings): |  | ||||||
|         def perm_list(read=False, write=False, execute=False): |  | ||||||
|             pl = ['-', '-', '-'] |  | ||||||
|             if read: |  | ||||||
|                 pl[0] = 'r' |  | ||||||
|             if write: |  | ||||||
|                 pl[1] = 'w' |  | ||||||
|             if execute: |  | ||||||
|                 pl[2] = 'x' |  | ||||||
|             return pl |  | ||||||
|  |  | ||||||
|         self.access_dict = dict( |  | ||||||
|             [(access, perm_list(read=r, write=w, execute=x)) for access, [r, w, x] in settings.items()]) |  | ||||||
|         os.chmod(self.filepath, self.mode()) |  | ||||||
|  |  | ||||||
| # project_directory = os.path.abspath(os.path.dirname(sys.argv[0])) |  | ||||||
| # home_directory = os.path.expanduser('~') |  | ||||||
| # print(f'Path: {home_directory}  Mode: {FilePerm(home_directory).mode()}  Octal: {FilePerm(home_directory).octal()} ' |  | ||||||
| #      f'Digits: {FilePerm(home_directory).digits()}') |  | ||||||
| # Example: Output |  | ||||||
| # Path: /home/cooluser  Mode: 493  Octal: [7, 5, 5] Digits: 755 |  | ||||||
| @@ -861,7 +861,7 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; | |||||||
|             command = f'wget -q -O /usr/local/CyberCP/snappymail_cyberpanel.php  https://raw.githubusercontent.com/the-djmaze/snappymail/master/integrations/cyberpanel/install.php' |             command = f'wget -q -O /usr/local/CyberCP/snappymail_cyberpanel.php  https://raw.githubusercontent.com/the-djmaze/snappymail/master/integrations/cyberpanel/install.php' | ||||||
|             Upgrade.executioner_silent(command, 'verify certificate', 0) |             Upgrade.executioner_silent(command, 'verify certificate', 0) | ||||||
|  |  | ||||||
|             command = f'/usr/local/lsws/lsphp80/bin/php /usr/local/CyberCP/snappymail_cyberpanel.php' |             command = f'/usr/local/lsws/lsphp83/bin/php /usr/local/CyberCP/snappymail_cyberpanel.php' | ||||||
|             Upgrade.executioner_silent(command, 'verify certificate', 0) |             Upgrade.executioner_silent(command, 'verify certificate', 0) | ||||||
|  |  | ||||||
|             # labsPath = '/usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/configs/application.ini' |             # labsPath = '/usr/local/lscp/cyberpanel/rainloop/data/_data_/_default_/configs/application.ini' | ||||||
| @@ -3121,7 +3121,7 @@ echo $oConfig->Save() ? 'Done' : 'Error'; | |||||||
|             command = 'chmod 640 /usr/local/lscp/cyberpanel/logs/access.log' |             command = 'chmod 640 /usr/local/lscp/cyberpanel/logs/access.log' | ||||||
|             Upgrade.executioner(command, 0) |             Upgrade.executioner(command, 0) | ||||||
|  |  | ||||||
|             command = '/usr/local/lsws/lsphp72/bin/php /usr/local/CyberCP/public/snappymail.php' |             command = '/usr/local/lsws/lsphp83/bin/php /usr/local/CyberCP/public/snappymail.php' | ||||||
|             Upgrade.executioner_silent(command, 'Configure SnappyMail') |             Upgrade.executioner_silent(command, 'Configure SnappyMail') | ||||||
|  |  | ||||||
|             command = 'chmod 600 /usr/local/CyberCP/public/snappymail.php' |             command = 'chmod 600 /usr/local/CyberCP/public/snappymail.php' | ||||||
| @@ -3182,44 +3182,221 @@ echo $oConfig->Save() ? 'Done' : 'Error'; | |||||||
|         command = '/root/.acme.sh/acme.sh --set-default-ca  --server  letsencrypt' |         command = '/root/.acme.sh/acme.sh --set-default-ca  --server  letsencrypt' | ||||||
|         Upgrade.executioner(command, command, 0) |         Upgrade.executioner(command, command, 0) | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def check_package_availability(package_name): | ||||||
|  |         """Check if a package is available in the repositories""" | ||||||
|  |         try: | ||||||
|  |             # Try to search for the package without installing | ||||||
|  |             if os.path.exists('/etc/yum.repos.d/') or os.path.exists('/etc/dnf/dnf.conf'): | ||||||
|  |                 # RHEL-based systems | ||||||
|  |                 command = f"dnf search --quiet {package_name} 2>/dev/null | grep -q '^Last metadata expiration' || yum search --quiet {package_name} 2>/dev/null | head -1" | ||||||
|  |                 result = subprocess.run(command, shell=True, capture_output=True, text=True) | ||||||
|  |                 return result.returncode == 0 | ||||||
|  |             else: | ||||||
|  |                 # Ubuntu/Debian systems | ||||||
|  |                 command = f"apt-cache search {package_name} 2>/dev/null | head -1" | ||||||
|  |                 result = subprocess.run(command, shell=True, capture_output=True, text=True) | ||||||
|  |                 return result.returncode == 0 and result.stdout.strip() != "" | ||||||
|  |         except Exception as e: | ||||||
|  |             Upgrade.stdOut(f"Error checking package availability for {package_name}: {str(e)}", 0) | ||||||
|  |             return False | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def is_almalinux9(): | ||||||
|  |         """Check if running on AlmaLinux 9""" | ||||||
|  |         if os.path.exists('/etc/almalinux-release'): | ||||||
|  |             try: | ||||||
|  |                 with open('/etc/almalinux-release', 'r') as f: | ||||||
|  |                     content = f.read() | ||||||
|  |                     return 'release 9' in content | ||||||
|  |             except: | ||||||
|  |                 return False | ||||||
|  |         return False | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def fix_almalinux9_mariadb(): | ||||||
|  |         """Fix AlmaLinux 9 MariaDB installation issues""" | ||||||
|  |         if not Upgrade.is_almalinux9(): | ||||||
|  |             return | ||||||
|  |          | ||||||
|  |         Upgrade.stdOut("Applying AlmaLinux 9 MariaDB fixes...", 1) | ||||||
|  |          | ||||||
|  |         try: | ||||||
|  |             # Disable problematic MariaDB MaxScale repository | ||||||
|  |             Upgrade.stdOut("Disabling problematic MariaDB MaxScale repository...", 1) | ||||||
|  |             command = "dnf config-manager --disable mariadb-maxscale 2>/dev/null || true" | ||||||
|  |             subprocess.run(command, shell=True, capture_output=True) | ||||||
|  |              | ||||||
|  |             # Remove problematic repository files | ||||||
|  |             Upgrade.stdOut("Removing problematic repository files...", 1) | ||||||
|  |             problematic_repos = [ | ||||||
|  |                 '/etc/yum.repos.d/mariadb-maxscale.repo', | ||||||
|  |                 '/etc/yum.repos.d/mariadb-maxscale.repo.rpmnew' | ||||||
|  |             ] | ||||||
|  |             for repo_file in problematic_repos: | ||||||
|  |                 if os.path.exists(repo_file): | ||||||
|  |                     os.remove(repo_file) | ||||||
|  |                     Upgrade.stdOut(f"Removed {repo_file}", 1) | ||||||
|  |              | ||||||
|  |             # Clean DNF cache | ||||||
|  |             Upgrade.stdOut("Cleaning DNF cache...", 1) | ||||||
|  |             command = "dnf clean all" | ||||||
|  |             subprocess.run(command, shell=True, capture_output=True) | ||||||
|  |              | ||||||
|  |             # Install MariaDB from official repository | ||||||
|  |             Upgrade.stdOut("Setting up official MariaDB repository...", 1) | ||||||
|  |             command = "curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | bash -s -- --mariadb-server-version='10.11'" | ||||||
|  |             result = subprocess.run(command, shell=True, capture_output=True, text=True) | ||||||
|  |             if result.returncode != 0: | ||||||
|  |                 Upgrade.stdOut(f"Warning: MariaDB repo setup failed: {result.stderr}", 0) | ||||||
|  |              | ||||||
|  |             # Install MariaDB packages | ||||||
|  |             Upgrade.stdOut("Installing MariaDB packages...", 1) | ||||||
|  |             mariadb_packages = "MariaDB-server MariaDB-client MariaDB-backup MariaDB-devel" | ||||||
|  |             command = f"dnf install -y {mariadb_packages}" | ||||||
|  |             result = subprocess.run(command, shell=True, capture_output=True, text=True) | ||||||
|  |             if result.returncode != 0: | ||||||
|  |                 Upgrade.stdOut(f"Warning: MariaDB installation issues: {result.stderr}", 0) | ||||||
|  |              | ||||||
|  |             # Start and enable MariaDB service | ||||||
|  |             Upgrade.stdOut("Starting MariaDB service...", 1) | ||||||
|  |             services = ['mariadb', 'mysql', 'mysqld'] | ||||||
|  |             for service in services: | ||||||
|  |                 try: | ||||||
|  |                     command = f"systemctl start {service}" | ||||||
|  |                     result = subprocess.run(command, shell=True, capture_output=True) | ||||||
|  |                     if result.returncode == 0: | ||||||
|  |                         command = f"systemctl enable {service}" | ||||||
|  |                         subprocess.run(command, shell=True, capture_output=True) | ||||||
|  |                         Upgrade.stdOut(f"MariaDB service started as {service}", 1) | ||||||
|  |                         break | ||||||
|  |                 except: | ||||||
|  |                     continue | ||||||
|  |              | ||||||
|  |             Upgrade.stdOut("AlmaLinux 9 MariaDB fixes completed", 1) | ||||||
|  |              | ||||||
|  |         except Exception as e: | ||||||
|  |             Upgrade.stdOut(f"Error applying AlmaLinux 9 MariaDB fixes: {str(e)}", 0) | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def get_available_php_versions(): | ||||||
|  |         """Get list of available PHP versions based on OS""" | ||||||
|  |         # Check for AlmaLinux 9+ first | ||||||
|  |         if os.path.exists('/etc/almalinux-release'): | ||||||
|  |             try: | ||||||
|  |                 with open('/etc/almalinux-release', 'r') as f: | ||||||
|  |                     content = f.read() | ||||||
|  |                     if 'release 9' in content or 'release 10' in content: | ||||||
|  |                         Upgrade.stdOut("AlmaLinux 9+ detected - checking available PHP versions", 1) | ||||||
|  |                         # AlmaLinux 9+ doesn't have PHP 7.1, 7.2, 7.3 | ||||||
|  |                         php_versions = ['74', '80', '81', '82', '83', '84', '85'] | ||||||
|  |                     else: | ||||||
|  |                         php_versions = ['71', '72', '73', '74', '80', '81', '82', '83', '84', '85'] | ||||||
|  |             except: | ||||||
|  |                 php_versions = ['71', '72', '73', '74', '80', '81', '82', '83', '84', '85'] | ||||||
|  |         else: | ||||||
|  |             # Check other OS versions | ||||||
|  |             os_info = Upgrade.findOperatingSytem() | ||||||
|  |             if os_info in [Ubuntu24, CENTOS8]: | ||||||
|  |                 php_versions = ['74', '80', '81', '82', '83', '84', '85'] | ||||||
|  |             else: | ||||||
|  |                 php_versions = ['71', '72', '73', '74', '80', '81', '82', '83', '84', '85'] | ||||||
|  |          | ||||||
|  |         # Check availability of each version | ||||||
|  |         available_versions = [] | ||||||
|  |         for version in php_versions: | ||||||
|  |             if Upgrade.check_package_availability(f'lsphp{version}'): | ||||||
|  |                 available_versions.append(version) | ||||||
|  |             else: | ||||||
|  |                 Upgrade.stdOut(f"PHP {version} not available on this OS", 0) | ||||||
|  |          | ||||||
|  |         return available_versions | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def fixLiteSpeedConfig(): | ||||||
|  |         """Fix LiteSpeed configuration issues by creating missing files""" | ||||||
|  |         try: | ||||||
|  |             Upgrade.stdOut("Checking and fixing LiteSpeed configuration...", 1) | ||||||
|  |              | ||||||
|  |             # Check if LiteSpeed is installed | ||||||
|  |             if not os.path.exists('/usr/local/lsws'): | ||||||
|  |                 Upgrade.stdOut("LiteSpeed not found at /usr/local/lsws", 0) | ||||||
|  |                 return | ||||||
|  |              | ||||||
|  |             # Create missing configuration files | ||||||
|  |             config_files = [ | ||||||
|  |                 "/usr/local/lsws/conf/httpd_config.xml", | ||||||
|  |                 "/usr/local/lsws/conf/httpd.conf", | ||||||
|  |                 "/usr/local/lsws/conf/modsec.conf" | ||||||
|  |             ] | ||||||
|  |              | ||||||
|  |             for config_file in config_files: | ||||||
|  |                 if not os.path.exists(config_file): | ||||||
|  |                     Upgrade.stdOut(f"Missing LiteSpeed config: {config_file}", 0) | ||||||
|  |                      | ||||||
|  |                     # Create directory if it doesn't exist | ||||||
|  |                     os.makedirs(os.path.dirname(config_file), exist_ok=True) | ||||||
|  |                      | ||||||
|  |                     # Create minimal config file | ||||||
|  |                     if config_file.endswith('httpd_config.xml'): | ||||||
|  |                         with open(config_file, 'w') as f: | ||||||
|  |                             f.write('<?xml version="1.0" encoding="UTF-8"?>\n') | ||||||
|  |                             f.write('<httpServerConfig>\n') | ||||||
|  |                             f.write('    <!-- Minimal LiteSpeed configuration -->\n') | ||||||
|  |                             f.write('    <listener>\n') | ||||||
|  |                             f.write('        <name>Default</name>\n') | ||||||
|  |                             f.write('        <address>*:8088</address>\n') | ||||||
|  |                             f.write('    </listener>\n') | ||||||
|  |                             f.write('</httpServerConfig>\n') | ||||||
|  |                     elif config_file.endswith('httpd.conf'): | ||||||
|  |                         with open(config_file, 'w') as f: | ||||||
|  |                             f.write('# Minimal LiteSpeed HTTP configuration\n') | ||||||
|  |                             f.write('# This file will be updated by CyberPanel\n') | ||||||
|  |                     elif config_file.endswith('modsec.conf'): | ||||||
|  |                         with open(config_file, 'w') as f: | ||||||
|  |                             f.write('# ModSecurity configuration\n') | ||||||
|  |                             f.write('# This file will be updated by CyberPanel\n') | ||||||
|  |                      | ||||||
|  |                     Upgrade.stdOut(f"Created minimal config: {config_file}", 1) | ||||||
|  |                 else: | ||||||
|  |                     Upgrade.stdOut(f"LiteSpeed config exists: {config_file}", 1) | ||||||
|  |                      | ||||||
|  |         except Exception as e: | ||||||
|  |             Upgrade.stdOut(f"Error fixing LiteSpeed config: {str(e)}", 0) | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def installPHP73(): |     def installPHP73(): | ||||||
|         try: |         try: | ||||||
|             if Upgrade.installedOutput.find('lsphp73') == -1: |             Upgrade.stdOut("Installing PHP versions based on OS compatibility...", 1) | ||||||
|                 command = 'yum install -y lsphp73 lsphp73-json lsphp73-xmlrpc lsphp73-xml lsphp73-tidy lsphp73-soap lsphp73-snmp ' \ |  | ||||||
|                           'lsphp73-recode lsphp73-pspell lsphp73-process lsphp73-pgsql lsphp73-pear lsphp73-pdo lsphp73-opcache ' \ |  | ||||||
|                           'lsphp73-odbc lsphp73-mysqlnd lsphp73-mcrypt lsphp73-mbstring lsphp73-ldap lsphp73-intl lsphp73-imap ' \ |  | ||||||
|                           'lsphp73-gmp lsphp73-gd lsphp73-enchant lsphp73-dba  lsphp73-common  lsphp73-bcmath' |  | ||||||
|                 Upgrade.executioner(command, 'Install PHP 73, 0') |  | ||||||
|              |              | ||||||
|             if Upgrade.installedOutput.find('lsphp74') == -1: |             # Get available PHP versions | ||||||
|                 command = 'yum install -y lsphp74 lsphp74-json lsphp74-xmlrpc lsphp74-xml lsphp74-tidy lsphp74-soap lsphp74-snmp ' \ |             available_versions = Upgrade.get_available_php_versions() | ||||||
|                           'lsphp74-recode lsphp74-pspell lsphp74-process lsphp74-pgsql lsphp74-pear lsphp74-pdo lsphp74-opcache ' \ |  | ||||||
|                           'lsphp74-odbc lsphp74-mysqlnd lsphp74-mcrypt lsphp74-mbstring lsphp74-ldap lsphp74-intl lsphp74-imap ' \ |  | ||||||
|                           'lsphp74-gmp lsphp74-gd lsphp74-enchant lsphp74-dba lsphp74-common  lsphp74-bcmath' |  | ||||||
|              |              | ||||||
|                 Upgrade.executioner(command, 'Install PHP 74, 0') |             if not available_versions: | ||||||
|  |                 Upgrade.stdOut("No PHP versions available for installation", 0) | ||||||
|  |                 return | ||||||
|              |              | ||||||
|             if Upgrade.installedOutput.find('lsphp80') == -1: |             Upgrade.stdOut(f"Installing available PHP versions: {', '.join(available_versions)}", 1) | ||||||
|                 command = 'yum install lsphp80* -y' |              | ||||||
|  |             for version in available_versions: | ||||||
|  |                 try: | ||||||
|  |                     if version in ['71', '72', '73', '74']: | ||||||
|  |                         # PHP 7.x versions with specific extensions | ||||||
|  |                         if Upgrade.installedOutput.find(f'lsphp{version}') == -1: | ||||||
|  |                             extensions = ['json', 'xmlrpc', 'xml', 'tidy', 'soap', 'snmp', 'recode', 'pspell', 'process', 'pgsql', 'pear', 'pdo', 'opcache', 'odbc', 'mysqlnd', 'mcrypt', 'mbstring', 'ldap', 'intl', 'imap', 'gmp', 'gd', 'enchant', 'dba', 'common', 'bcmath'] | ||||||
|  |                             package_list = f"lsphp{version} " + " ".join([f"lsphp{version}-{ext}" for ext in extensions]) | ||||||
|  |                             command = f"yum install -y {package_list}" | ||||||
|  |                             Upgrade.executioner(command, f'Install PHP {version}', 0) | ||||||
|  |                     else: | ||||||
|  |                         # PHP 8.x versions | ||||||
|  |                         if Upgrade.installedOutput.find(f'lsphp{version}') == -1: | ||||||
|  |                             command = f"yum install lsphp{version}* -y" | ||||||
|             subprocess.call(command, shell=True) |             subprocess.call(command, shell=True) | ||||||
|  |                             Upgrade.stdOut(f"Installed PHP {version}", 1) | ||||||
|                          |                          | ||||||
|             if Upgrade.installedOutput.find('lsphp81') == -1: |                 except Exception as e: | ||||||
|                 command = 'yum install lsphp81* -y' |                     Upgrade.stdOut(f"Error installing PHP {version}: {str(e)}", 0) | ||||||
|                 subprocess.call(command, shell=True) |                     continue | ||||||
|  |  | ||||||
|             if Upgrade.installedOutput.find('lsphp82') == -1: |  | ||||||
|                 command = 'yum install lsphp82* -y' |  | ||||||
|                 subprocess.call(command, shell=True) |  | ||||||
|  |  | ||||||
|             command = 'yum install lsphp83* -y' |  | ||||||
|             subprocess.call(command, shell=True) |  | ||||||
|  |  | ||||||
|             command = 'yum install lsphp84* -y' |  | ||||||
|             subprocess.call(command, shell=True) |  | ||||||
|  |  | ||||||
|             command = 'yum install lsphp85* -y' |  | ||||||
|             subprocess.call(command, shell=True) |  | ||||||
|  |  | ||||||
|         except: |         except: | ||||||
|             command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install ' \ |             command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install ' \ | ||||||
| @@ -3997,9 +4174,20 @@ pm.max_spare_servers = 3 | |||||||
|     @staticmethod |     @staticmethod | ||||||
|     def setupPHPSymlink(): |     def setupPHPSymlink(): | ||||||
|         try: |         try: | ||||||
|             # Check if PHP 8.3 exists |             # Try to find available PHP version (prioritize modern stable versions) | ||||||
|             if not os.path.exists('/usr/local/lsws/lsphp83/bin/php'): |             # Priority: 8.3 (recommended), 8.2, 8.4, 8.5, 8.1, 8.0, then older versions | ||||||
|                 Upgrade.stdOut("PHP 8.3 not found, installing it first...") |             php_versions = ['83', '82', '84', '85', '81', '80', '74', '73', '72', '71'] | ||||||
|  |             selected_php = None | ||||||
|  |              | ||||||
|  |             for version in php_versions: | ||||||
|  |                 if os.path.exists(f'/usr/local/lsws/lsphp{version}/bin/php'): | ||||||
|  |                     selected_php = version | ||||||
|  |                     Upgrade.stdOut(f"Found PHP {version}, using as default", 1) | ||||||
|  |                     break | ||||||
|  |              | ||||||
|  |             if not selected_php: | ||||||
|  |                 # Try to install PHP 8.3 as fallback (modern stable version) | ||||||
|  |                 Upgrade.stdOut("No PHP found, installing PHP 8.3 as fallback...") | ||||||
|                  |                  | ||||||
|                 # Install PHP 8.3 based on OS |                 # Install PHP 8.3 based on OS | ||||||
|                 if os.path.exists(Upgrade.CentOSPath) or os.path.exists(Upgrade.openEulerPath): |                 if os.path.exists(Upgrade.CentOSPath) or os.path.exists(Upgrade.openEulerPath): | ||||||
| @@ -4013,16 +4201,17 @@ pm.max_spare_servers = 3 | |||||||
|                 if not os.path.exists('/usr/local/lsws/lsphp83/bin/php'): |                 if not os.path.exists('/usr/local/lsws/lsphp83/bin/php'): | ||||||
|                     Upgrade.stdOut('[ERROR] Failed to install PHP 8.3') |                     Upgrade.stdOut('[ERROR] Failed to install PHP 8.3') | ||||||
|                     return 0 |                     return 0 | ||||||
|  |                 selected_php = '83' | ||||||
|              |              | ||||||
|             # Remove existing PHP symlink if it exists |             # Remove existing PHP symlink if it exists | ||||||
|             if os.path.exists('/usr/bin/php'): |             if os.path.exists('/usr/bin/php'): | ||||||
|                 os.remove('/usr/bin/php') |                 os.remove('/usr/bin/php') | ||||||
|  |  | ||||||
|             # Create symlink to PHP 8.3 |             # Create symlink to selected PHP version | ||||||
|             command = 'ln -s /usr/local/lsws/lsphp83/bin/php /usr/bin/php' |             command = f'ln -s /usr/local/lsws/lsphp{selected_php}/bin/php /usr/bin/php' | ||||||
|             Upgrade.executioner(command, 'Setup PHP Symlink to 8.3', 0) |             Upgrade.executioner(command, f'Setup PHP Symlink to {selected_php}', 0) | ||||||
|  |  | ||||||
|             Upgrade.stdOut("PHP symlink updated to PHP 8.3 successfully.") |             Upgrade.stdOut(f"PHP symlink updated to PHP {selected_php} successfully.") | ||||||
|  |  | ||||||
|         except BaseException as msg: |         except BaseException as msg: | ||||||
|             Upgrade.stdOut('[ERROR] ' + str(msg) + " [setupPHPSymlink]") |             Upgrade.stdOut('[ERROR] ' + str(msg) + " [setupPHPSymlink]") | ||||||
| @@ -4150,6 +4339,9 @@ pm.max_spare_servers = 3 | |||||||
|         Upgrade.manageServiceMigrations() |         Upgrade.manageServiceMigrations() | ||||||
|         Upgrade.enableServices() |         Upgrade.enableServices() | ||||||
|  |  | ||||||
|  |         # Apply AlmaLinux 9 fixes before other installations | ||||||
|  |         Upgrade.fix_almalinux9_mariadb() | ||||||
|  |  | ||||||
|         Upgrade.installPHP73() |         Upgrade.installPHP73() | ||||||
|         Upgrade.setupCLI() |         Upgrade.setupCLI() | ||||||
|         Upgrade.someDirectories() |         Upgrade.someDirectories() | ||||||
| @@ -4159,6 +4351,9 @@ pm.max_spare_servers = 3 | |||||||
|         ## Fix Apache configuration issues after upgrade |         ## Fix Apache configuration issues after upgrade | ||||||
|         Upgrade.fixApacheConfiguration() |         Upgrade.fixApacheConfiguration() | ||||||
|          |          | ||||||
|  |         # Fix LiteSpeed configuration files if missing | ||||||
|  |         Upgrade.fixLiteSpeedConfig() | ||||||
|  |  | ||||||
|         ### General migrations are not needed any more |         ### General migrations are not needed any more | ||||||
|  |  | ||||||
|         # Upgrade.GeneralMigrations() |         # Upgrade.GeneralMigrations() | ||||||
| @@ -4191,8 +4386,32 @@ pm.max_spare_servers = 3 | |||||||
|         except: |         except: | ||||||
|             pass |             pass | ||||||
|  |  | ||||||
|         command = 'cp /usr/local/lsws/lsphp80/bin/lsphp %s' % (phpPath) |         # Try to find available PHP binary in order of preference (modern stable first) | ||||||
|  |         php_versions = ['83', '82', '84', '85', '81', '80', '74', '73', '72', '71'] | ||||||
|  |         php_binary_found = False | ||||||
|  |          | ||||||
|  |         for version in php_versions: | ||||||
|  |             php_binary = f'/usr/local/lsws/lsphp{version}/bin/lsphp' | ||||||
|  |             if os.path.exists(php_binary): | ||||||
|  |                 command = f'cp {php_binary} {phpPath}' | ||||||
|         Upgrade.executioner(command, 0) |         Upgrade.executioner(command, 0) | ||||||
|  |                 Upgrade.stdOut(f"Using PHP {version} for LSCPD", 1) | ||||||
|  |                 php_binary_found = True | ||||||
|  |                 break | ||||||
|  |          | ||||||
|  |         if not php_binary_found: | ||||||
|  |             Upgrade.stdOut("Warning: No PHP binary found for LSCPD", 0) | ||||||
|  |             # Try to create a symlink to any available PHP | ||||||
|  |             try: | ||||||
|  |                 command = 'find /usr/local/lsws -name "lsphp" -type f 2>/dev/null | head -1' | ||||||
|  |                 result = subprocess.run(command, shell=True, capture_output=True, text=True) | ||||||
|  |                 if result.stdout.strip(): | ||||||
|  |                     php_binary = result.stdout.strip() | ||||||
|  |                     command = f'cp {php_binary} {phpPath}' | ||||||
|  |                     Upgrade.executioner(command, 0) | ||||||
|  |                     Upgrade.stdOut(f"Using found PHP binary: {php_binary}", 1) | ||||||
|  |             except: | ||||||
|  |                 pass | ||||||
|  |  | ||||||
|         if Upgrade.SoftUpgrade == 0: |         if Upgrade.SoftUpgrade == 0: | ||||||
|             try: |             try: | ||||||
| @@ -4201,6 +4420,42 @@ pm.max_spare_servers = 3 | |||||||
|             except: |             except: | ||||||
|                 pass |                 pass | ||||||
|              |              | ||||||
|  |             # Try to start other services if they exist | ||||||
|  |             # Enhanced service startup with AlmaLinux 9 support | ||||||
|  |             services_to_start = ['fastapi_ssh_server', 'cyberpanel'] | ||||||
|  |              | ||||||
|  |             # Special handling for AlmaLinux 9 MariaDB service | ||||||
|  |             if Upgrade.is_almalinux9(): | ||||||
|  |                 Upgrade.stdOut("AlmaLinux 9 detected - applying enhanced service management", 1) | ||||||
|  |                 mariadb_services = ['mariadb', 'mysql', 'mysqld'] | ||||||
|  |                 for service in mariadb_services: | ||||||
|  |                     try: | ||||||
|  |                         check_command = f"systemctl list-unit-files | grep -q {service}" | ||||||
|  |                         result = subprocess.run(check_command, shell=True, capture_output=True) | ||||||
|  |                         if result.returncode == 0: | ||||||
|  |                             command = f"systemctl restart {service}" | ||||||
|  |                             Upgrade.executioner(command, f'Restart {service} for AlmaLinux 9', 0) | ||||||
|  |                             command = f"systemctl enable {service}" | ||||||
|  |                             Upgrade.executioner(command, f'Enable {service} for AlmaLinux 9', 0) | ||||||
|  |                             Upgrade.stdOut(f"MariaDB service managed as {service} on AlmaLinux 9", 1) | ||||||
|  |                             break | ||||||
|  |                     except Exception as e: | ||||||
|  |                         Upgrade.stdOut(f"Could not manage MariaDB service {service}: {str(e)}", 0) | ||||||
|  |                         continue | ||||||
|  |              | ||||||
|  |             for service in services_to_start: | ||||||
|  |                 try: | ||||||
|  |                     # Check if service exists | ||||||
|  |                     check_command = f"systemctl list-unit-files | grep -q {service}" | ||||||
|  |                     result = subprocess.run(check_command, shell=True, capture_output=True) | ||||||
|  |                     if result.returncode == 0: | ||||||
|  |                         command = f"systemctl start {service}" | ||||||
|  |                         Upgrade.executioner(command, f'Start {service}', 0) | ||||||
|  |                     else: | ||||||
|  |                         Upgrade.stdOut(f"Service {service} not found, skipping", 0) | ||||||
|  |                 except Exception as e: | ||||||
|  |                     Upgrade.stdOut(f"Could not start {service}: {str(e)}", 0) | ||||||
|  |  | ||||||
|         # Remove CSF if installed and restore firewalld (CSF is being discontinued on August 31, 2025) |         # Remove CSF if installed and restore firewalld (CSF is being discontinued on August 31, 2025) | ||||||
|         if os.path.exists('/etc/csf'): |         if os.path.exists('/etc/csf'): | ||||||
|             print("CSF detected - removing CSF and restoring firewalld...") |             print("CSF detected - removing CSF and restoring firewalld...") | ||||||
|   | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Reference in New Issue
	
	Block a user