diff --git a/databases/static/databases/databases.js b/databases/static/databases/databases.js index 0eb8469fb..8dd93d53c 100644 --- a/databases/static/databases/databases.js +++ b/databases/static/databases/databases.js @@ -2,6 +2,8 @@ * Created by usman on 8/6/17. */ +/* Ensure we register controllers on the CyberCP app (avoids ctrlreg if load order differs) */ +var app = (typeof window.app !== 'undefined' && window.app) ? window.app : angular.module('CyberCP'); /* Java script code to create database */ app.controller('createDatabase', function ($scope, $http) { @@ -694,7 +696,7 @@ app.controller('Mysqlmanager', function ($scope, $http, $compile, $window, $time $scope.cyberPanelLoading = true; - url = "/dataBases/getMysqlstatus"; + url = "/dataBases/getMysqlstatus?t=" + (Date.now ? Date.now() : new Date().getTime()); var data = {}; @@ -715,6 +717,8 @@ app.controller('Mysqlmanager', function ($scope, $http, $compile, $window, $time try { data = JSON.parse(data); } catch (e) { + $scope.uptime = $scope.connections = $scope.Slow_queries = '—'; + $scope.processes = []; new PNotify({ title: 'Error!', text: 'Invalid response from server.', type: 'error' }); return; } @@ -749,7 +753,21 @@ app.controller('Mysqlmanager', function ($scope, $http, $compile, $window, $time function cantLoadInitialDatas(response) { $scope.cyberPanelLoading = false; - var msg = (response.data && response.data.error_message) || (response.statusText || 'Cannot load MySQL status.'); + $scope.uptime = '—'; + $scope.connections = '—'; + $scope.Slow_queries = '—'; + $scope.processes = []; + var msg = 'Cannot load MySQL status.'; + if (response && response.status) { + msg = 'Request failed: ' + response.status + (response.statusText ? ' ' + response.statusText : ''); + } + if (response && response.data) { + if (typeof response.data === 'string' && response.data.length < 200) { + msg = response.data; + } else if (response.data.error_message) { + msg = response.data.error_message; + } + } new PNotify({ title: 'Error!', text: msg, diff --git a/databases/templates/databases/mysqlmanager.html b/databases/templates/databases/mysqlmanager.html index 9ebac5523..16b495e76 100644 --- a/databases/templates/databases/mysqlmanager.html +++ b/databases/templates/databases/mysqlmanager.html @@ -644,8 +644,8 @@ + ng-bind="(process.info && process.info !== 'NULL') ? process.info : 'No query'" + ng-attr-title="{$ (process.info && process.info !== 'NULL') ? process.info : 'No query' $}">
diff --git a/plogical/CyberPanelUpgrade.py b/plogical/CyberPanelUpgrade.py index a9179374b..df6abdac6 100644 --- a/plogical/CyberPanelUpgrade.py +++ b/plogical/CyberPanelUpgrade.py @@ -79,6 +79,7 @@ class UpgradeCyberPanel: Upgrade.CLMigrations() Upgrade.IncBackupMigrations() Upgrade.applyLoginSystemMigrations() + Upgrade.homeDirectoryMigrations() Upgrade.s3BackupMigrations() Upgrade.containerMigrations() Upgrade.manageServiceMigrations() diff --git a/plogical/mysqlUtilities.py b/plogical/mysqlUtilities.py index 28756e8d1..92eef09f8 100644 --- a/plogical/mysqlUtilities.py +++ b/plogical/mysqlUtilities.py @@ -531,47 +531,63 @@ password=%s data['status'] = 1 for items in result: - if items[0] == 'Uptime': - data['uptime'] = mysqlUtilities.GetTime(items[1]) - elif items[0] == 'Connections': - data['connections'] = items[1] - elif items[0] == 'Slow_queries': - data['Slow_queries'] = items[1] + if not items or len(items) < 2: + continue + key = (items[0] or '').strip() + val = items[1] + if key == 'Uptime': + try: + data['uptime'] = mysqlUtilities.GetTime(val) + except (TypeError, ValueError): + data['uptime'] = str(val) if val is not None else '0' + elif key == 'Connections': + data['connections'] = val + elif key == 'Slow_queries': + data['Slow_queries'] = val - ## Process List - - cursor.execute("show processlist") + ## Process List (column-name based so it works with any MySQL/MariaDB version) + cursor.execute("SHOW FULL PROCESSLIST") + if cursor.description: + col_names = [col[0].lower() if col[0] else '' for col in cursor.description] + else: + col_names = [] result = cursor.fetchall() json_data = "[" checker = 0 - for items in result: - # SHOW PROCESSLIST: Id, User, Host, db, Command, Time, State, Info [, Progress] - if items[3] is None or len(str(items[3])) == 0: + for row in result: + if col_names: + row_dict = dict(zip(col_names, row)) if len(col_names) == len(row) else {} + else: + row_dict = {} + # Support both MySQL and MariaDB column names (Id/id, User/user, db/DB, etc.) + def get_col(*keys, default=None): + for k in keys: + v = row_dict.get(k) if row_dict else None + if v is not None and (not isinstance(v, str) or len(str(v).strip()) > 0): + return v + return default + + database = get_col('db', 'database', default='NULL') + if database is None or (isinstance(database, str) and len(database.strip()) == 0): database = 'NULL' - else: - database = items[3] - - if len(items) > 6 and items[6] is not None and len(str(items[6])) > 0: - state = items[6] - else: + state = get_col('state', default='NULL') + if state is None or (isinstance(state, str) and len(str(state).strip()) == 0): state = 'NULL' - - if len(items) > 7 and items[7] is not None and len(str(items[7])) > 0: - info = items[7] - else: - info = 'NULL' + info = get_col('info', default=None) + if info is None or (isinstance(info, str) and len(str(info).strip()) == 0): + info = 'No query' dic = { - 'id': items[0], - 'user': items[1], + 'id': get_col('id', default=0), + 'user': get_col('user', default=''), 'database': database, - 'command': items[4] if len(items) > 4 else '', - 'time': items[5] if len(items) > 5 else 0, + 'command': get_col('command', default=''), + 'time': get_col('time', 'time_ms', default=0), 'state': state, 'info': info, - 'progress': items[8] if len(items) > 8 else 0, + 'progress': get_col('progress', default=0), } if checker == 0: diff --git a/plogical/upgrade.py b/plogical/upgrade.py index 6f534aba0..b10ffb670 100644 --- a/plogical/upgrade.py +++ b/plogical/upgrade.py @@ -2382,6 +2382,50 @@ CREATE TABLE `websiteFunctions_backupsv2` (`id` integer AUTO_INCREMENT NOT NULL except OSError as msg: Upgrade.stdOut(str(msg) + " [applyLoginSystemMigrations]") + @staticmethod + def homeDirectoryMigrations(): + """Create home_directories and user_home_mappings tables if missing (Modify Website home directory feature).""" + try: + connection, cursor = Upgrade.setupConnection('cyberpanel') + try: + cursor.execute(""" + CREATE TABLE IF NOT EXISTS `home_directories` ( + `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, + `name` varchar(50) NOT NULL UNIQUE, + `path` varchar(255) NOT NULL UNIQUE, + `is_active` tinyint(1) NOT NULL DEFAULT 1, + `is_default` tinyint(1) NOT NULL DEFAULT 0, + `max_users` integer NOT NULL DEFAULT 0, + `description` longtext, + `created_at` datetime(6) NOT NULL, + `updated_at` datetime(6) NOT NULL + ) + """) + except Exception: + pass + try: + cursor.execute(""" + CREATE TABLE IF NOT EXISTS `user_home_mappings` ( + `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, + `user_id` integer NOT NULL UNIQUE, + `home_directory_id` integer NOT NULL, + `created_at` datetime(6) NOT NULL, + `updated_at` datetime(6) NOT NULL, + CONSTRAINT `user_home_mappings_user_id_fk` FOREIGN KEY (`user_id`) + REFERENCES `loginSystem_administrator` (`id`) ON DELETE CASCADE, + CONSTRAINT `user_home_mappings_home_directory_id_fk` FOREIGN KEY (`home_directory_id`) + REFERENCES `home_directories` (`id`) ON DELETE CASCADE + ) + """) + except Exception: + pass + try: + connection.close() + except Exception: + pass + except Exception: + pass + @staticmethod def s3BackupMigrations(): try: @@ -5851,6 +5895,7 @@ slowlog = /var/log/php{version}-fpm-slow.log ## Upgrade.applyLoginSystemMigrations() + Upgrade.homeDirectoryMigrations() ## Put function here to update custom ACLs diff --git a/public/static/databases/databases.js b/public/static/databases/databases.js index 7b10cf48a..8dd93d53c 100644 --- a/public/static/databases/databases.js +++ b/public/static/databases/databases.js @@ -2,6 +2,8 @@ * Created by usman on 8/6/17. */ +/* Ensure we register controllers on the CyberCP app (avoids ctrlreg if load order differs) */ +var app = (typeof window.app !== 'undefined' && window.app) ? window.app : angular.module('CyberCP'); /* Java script code to create database */ app.controller('createDatabase', function ($scope, $http) { @@ -10,22 +12,72 @@ app.controller('createDatabase', function ($scope, $http) { $(".dbDetails").hide(); $(".generatedPasswordDetails").hide(); $('#create-database-select').select2(); + + // Initialize preview if website is already selected + setTimeout(function() { + if ($scope.databaseWebsite) { + var truncatedName = $scope.getTruncatedWebName($scope.databaseWebsite); + $("#domainDatabase").text(truncatedName); + $("#domainUsername").text(truncatedName); + $(".dbDetails").show(); + } + }, 100); }); + // Helper function to get truncated website name + $scope.getTruncatedWebName = function(domain) { + if (!domain) return ''; + + // Remove hyphens and get first part before dot + var webName = domain.replace(/-/g, '').split('.')[0]; + + // Truncate to 4 characters if longer than 5 + if (webName.length > 5) { + webName = webName.substring(0, 4); + } + + return webName; + }; + $('#create-database-select').on('select2:select', function (e) { var data = e.params.data; $scope.databaseWebsite = data.text; $(".dbDetails").show(); - $("#domainDatabase").text(getWebsiteName(data.text)); - $("#domainUsername").text(getWebsiteName(data.text)); + + // Use local truncation function to ensure consistency + var truncatedName = $scope.getTruncatedWebName(data.text); + $("#domainDatabase").text(truncatedName); + $("#domainUsername").text(truncatedName); + + // Apply scope to update Angular bindings + $scope.$apply(); }); $scope.showDetailsBoxes = function () { $scope.dbDetails = false; } + + // Function called when website selection changes + $scope.websiteChanged = function() { + if ($scope.databaseWebsite) { + $(".dbDetails").show(); + var truncatedName = $scope.getTruncatedWebName($scope.databaseWebsite); + $("#domainDatabase").text(truncatedName); + $("#domainUsername").text(truncatedName); + } + } $scope.createDatabaseLoading = true; + + // Watch for changes to databaseWebsite to update preview + $scope.$watch('databaseWebsite', function(newValue, oldValue) { + if (newValue && newValue !== oldValue) { + var truncatedName = $scope.getTruncatedWebName(newValue); + $("#domainDatabase").text(truncatedName); + $("#domainUsername").text(truncatedName); + } + }); $scope.createDatabase = function () { @@ -39,14 +91,8 @@ app.controller('createDatabase', function ($scope, $http) { var dbPassword = $scope.dbPassword; var webUserName = ""; - // getting website username - - webUserName = databaseWebsite.replace(/-/g, ''); - webUserName = webUserName.split(".")[0]; - - if (webUserName.length > 5) { - webUserName = webUserName.substring(0, 4); - } + // getting website username - use the same truncation function for consistency + webUserName = $scope.getTruncatedWebName(databaseWebsite); var url = "/dataBases/submitDBCreation"; @@ -75,9 +121,15 @@ app.controller('createDatabase', function ($scope, $http) { $scope.createDatabaseLoading = true; $scope.dbDetails = false; + var successMessage = 'Database successfully created.'; + if (response.data.dbName && response.data.dbUsername) { + successMessage = 'Database successfully created.\n' + + 'Database Name: ' + response.data.dbName + '\n' + + 'Database User: ' + response.data.dbUsername; + } new PNotify({ title: 'Success!', - text: 'Database successfully created.', + text: successMessage, type: 'success' }); } else { @@ -589,8 +641,34 @@ app.controller('phpMyAdmin', function ($scope, $http, $window) { function ListInitialDatas(response) { $scope.cyberPanelLoading = true; if (response.data.status === 1) { - var rUrl = '/phpmyadmin/phpmyadminsignin.php?username=' + response.data.username + '&token=' + response.data.token; - $window.location.href = rUrl; + //var rUrl = '/phpmyadmin/phpmyadminsignin.php?username=' + response.data.username + '&token=' + response.data.token; + //$window.location.href = rUrl; + + var form = document.createElement('form'); + form.method = 'post'; + form.action = '/phpmyadmin/phpmyadminsignin.php'; + +// Create input elements for username and token + var usernameInput = document.createElement('input'); + usernameInput.type = 'hidden'; + usernameInput.name = 'username'; + usernameInput.value = response.data.username; + + var tokenInput = document.createElement('input'); + tokenInput.type = 'hidden'; + tokenInput.name = 'token'; + tokenInput.value = response.data.token; + +// Append input elements to the form + form.appendChild(usernameInput); + form.appendChild(tokenInput); + +// Append the form to the body + document.body.appendChild(form); + +// Submit the form + form.submit(); + } else { } @@ -603,3 +681,415 @@ app.controller('phpMyAdmin', function ($scope, $http, $window) { } }); + + +app.controller('Mysqlmanager', function ($scope, $http, $compile, $window, $timeout) { + $scope.cyberPanelLoading = false; + $scope.mysql_status = 'test'; + $scope.uptime = '—'; + $scope.connections = '—'; + $scope.Slow_queries = '—'; + $scope.processes = []; + + + $scope.getstatus = function () { + + $scope.cyberPanelLoading = true; + + url = "/dataBases/getMysqlstatus?t=" + (Date.now ? Date.now() : new Date().getTime()); + + var data = {}; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + $scope.cyberPanelLoading = false; + var data = response.data; + if (typeof data === 'string') { + try { + data = JSON.parse(data); + } catch (e) { + $scope.uptime = $scope.connections = $scope.Slow_queries = '—'; + $scope.processes = []; + new PNotify({ title: 'Error!', text: 'Invalid response from server.', type: 'error' }); + return; + } + } + if (data && data.status === 1) { + $scope.uptime = data.uptime || '—'; + $scope.connections = data.connections != null ? data.connections : '—'; + $scope.Slow_queries = data.Slow_queries != null ? data.Slow_queries : '—'; + try { + $scope.processes = typeof data.processes === 'string' ? JSON.parse(data.processes || '[]') : (data.processes || []); + } catch (e) { + $scope.processes = []; + } + if (typeof $scope.showStatus === 'function') { + $timeout($scope.showStatus, 3000); + } + + new PNotify({ + title: 'Success', + text: 'Successfully Fetched', + type: 'success' + }); + } else { + new PNotify({ + title: 'Error!', + text: (data && data.error_message) || 'Could not load MySQL status.', + type: 'error' + }); + } + + } + + function cantLoadInitialDatas(response) { + $scope.cyberPanelLoading = false; + $scope.uptime = '—'; + $scope.connections = '—'; + $scope.Slow_queries = '—'; + $scope.processes = []; + var msg = 'Cannot load MySQL status.'; + if (response && response.status) { + msg = 'Request failed: ' + response.status + (response.statusText ? ' ' + response.statusText : ''); + } + if (response && response.data) { + if (typeof response.data === 'string' && response.data.length < 200) { + msg = response.data; + } else if (response.data.error_message) { + msg = response.data.error_message; + } + } + new PNotify({ + title: 'Error!', + text: msg, + type: 'error' + }); + } + + } + + $scope.refreshProcesses = function () { + var icon = document.querySelector('.refresh-btn i'); + if (icon) { + icon.style.animation = 'spin 1s linear'; + setTimeout(function () { icon.style.animation = ''; }, 1000); + } + $scope.getstatus(); + }; + + $scope.getstatus(); +}); + + +app.controller('OptimizeMysql', function ($scope, $http) { + $scope.cyberPanelLoading = true; + + $scope.generateRecommendations = function () { + $scope.cyberhosting = false; + url = "/dataBases/generateRecommendations"; + + var data = { + detectedRam: $("#detectedRam").text() + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + $http.post(url, data, config).then(ListInitialData, cantLoadInitialData); + + + function ListInitialData(response) { + $scope.cyberhosting = true; + if (response.data.status === 1) { + $scope.suggestedContent = response.data.generatedConf; + + } else { + new PNotify({ + title: 'Error!', + text: response.data.error_message, + type: 'error' + }); + } + + } + + function cantLoadInitialData(response) { + $scope.cyberhosting = true; + new PNotify({ + title: 'Error!', + text: 'Could not connect to server, please refresh this page.', + type: 'error' + }); + } + + }; + + + $scope.applyMySQLChanges = function () { + $scope.cyberhosting = false; + url = "/dataBases/applyMySQLChanges"; + + var encodedContent = encodeURIComponent($scope.suggestedContent); + + var data = { + suggestedContent: encodedContent + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + $http.post(url, data, config).then(ListInitialData, cantLoadInitialData); + + + function ListInitialData(response) { + $scope.cyberhosting = true; + if (response.data.status === 1) { + + new PNotify({ + title: 'Success', + text: 'Changes successfully applied.', + type: 'success' + }); + + + } else { + new PNotify({ + title: 'Error!', + text: response.data.error_message, + type: 'error' + }); + } + + } + + function cantLoadInitialData(response) { + $scope.cyberhosting = true; + new PNotify({ + title: 'Error!', + text: 'Could not connect to server, please refresh this page.', + type: 'error' + }); + } + + }; + + + $scope.restartMySQL = function () { + $scope.cyberPanelLoading = false; + + url = "/dataBases/restartMySQL"; + + var data = {}; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + $scope.cyberPanelLoading = true; + if (response.data.status === 1) { + new PNotify({ + title: 'Success', + text: 'Successfully Done', + type: 'success' + }); + } else { + new PNotify({ + title: 'Error!', + text: response.data.error_message, + type: 'error' + }); + } + + } + + function cantLoadInitialData(response) { + $scope.cyberhosting = true; + new PNotify({ + title: 'Error!', + text: 'Could not connect to server, please refresh this page.', + type: 'error' + }); + } + } +}) + + +app.controller('mysqlupdate', function ($scope, $http, $timeout) { + $scope.cyberPanelLoading = true; + $scope.dbLoading = true; + $scope.modeSecInstallBox = true; + $scope.modsecLoading = true; + $scope.failedToStartInallation = true; + $scope.couldNotConnect = true; + $scope.modSecSuccessfullyInstalled = true; + $scope.installationFailed = true; + + $scope.Upgardemysql = function () { + $scope.dbLoading = false; + $scope.installform = true; + $scope.modSecNotifyBox = true; + $scope.modeSecInstallBox = false; + $scope.modsecLoading = false; + $scope.failedToStartInallation = true; + $scope.couldNotConnect = true; + $scope.modSecSuccessfullyInstalled = true; + $scope.installationFailed = true; + + + url = "/dataBases/upgrademysqlnow"; + + var data = { + mysqlversion: $scope.version + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + $http.post(url, data, config).then(ListInitialData, cantLoadInitialData); + + + function ListInitialData(response) { + $scope.cyberhosting = true; + if (response.data.status === 1) { + $scope.modSecNotifyBox = true; + $scope.modeSecInstallBox = false; + $scope.modsecLoading = false; + $scope.failedToStartInallation = true; + $scope.couldNotConnect = true; + $scope.modSecSuccessfullyInstalled = true; + $scope.installationFailed = true; + + $scope.statusfile = response.data.tempStatusPath + + $timeout(getRequestStatus, 1000); + + } else { + $scope.errorMessage = response.data.error_message; + + $scope.modSecNotifyBox = false; + $scope.modeSecInstallBox = true; + $scope.modsecLoading = true; + $scope.failedToStartInallation = false; + $scope.couldNotConnect = true; + $scope.modSecSuccessfullyInstalled = true; + } + + } + + function cantLoadInitialData(response) { + $scope.cyberhosting = true; + new PNotify({ + title: 'Error!', + text: 'Could not connect to server, please refresh this page.', + type: 'error' + }); + } + } + + + function getRequestStatus() { + + $scope.modSecNotifyBox = true; + $scope.modeSecInstallBox = false; + $scope.modsecLoading = false; + $scope.failedToStartInallation = true; + $scope.couldNotConnect = true; + $scope.modSecSuccessfullyInstalled = true; + $scope.installationFailed = true; + + url = "/dataBases/upgrademysqlstatus"; + + var data = { + statusfile: $scope.statusfile + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + + + if (response.data.abort === 0) { + + $scope.modSecNotifyBox = true; + $scope.modeSecInstallBox = false; + $scope.modsecLoading = false; + $scope.failedToStartInallation = true; + $scope.couldNotConnect = true; + $scope.modSecSuccessfullyInstalled = true; + $scope.installationFailed = true; + + $scope.requestData = response.data.requestStatus; + $timeout(getRequestStatus, 1000); + } else { + // Notifications + $timeout.cancel(); + $scope.modSecNotifyBox = false; + $scope.modeSecInstallBox = false; + $scope.modsecLoading = true; + $scope.failedToStartInallation = true; + $scope.couldNotConnect = true; + + $scope.requestData = response.data.requestStatus; + + if (response.data.installed === 0) { + $scope.installationFailed = false; + $scope.errorMessage = response.data.error_message; + } else { + $scope.modSecSuccessfullyInstalled = false; + $timeout(function () { + $window.location.reload(); + }, 3000); + } + + } + + } + + function cantLoadInitialDatas(response) { + + $scope.modSecNotifyBox = false; + $scope.modeSecInstallBox = false; + $scope.modsecLoading = true; + $scope.failedToStartInallation = true; + $scope.couldNotConnect = false; + $scope.modSecSuccessfullyInstalled = true; + $scope.installationFailed = true; + + + } + + } +}); \ No newline at end of file diff --git a/public/static/websiteFunctions/websiteFunctions.js b/public/static/websiteFunctions/websiteFunctions.js index 060b8a7e1..ab881df98 100644 --- a/public/static/websiteFunctions/websiteFunctions.js +++ b/public/static/websiteFunctions/websiteFunctions.js @@ -10765,7 +10765,7 @@ app.controller('modifyWebsitesController', ['$scope', '$http', function ($scope, // Load home directories on page load $scope.loadHomeDirectories = function() { - $http.post('/userManagement/getUserHomeDirectories/', {}) + $http.post('/users/getUserHomeDirectories', {}) .then(function(response) { if (response.data.status === 1) { $scope.homeDirectories = response.data.directories; diff --git a/static/databases/databases.js b/static/databases/databases.js index 0c5bbb12e..8dd93d53c 100644 --- a/static/databases/databases.js +++ b/static/databases/databases.js @@ -2,6 +2,8 @@ * Created by usman on 8/6/17. */ +/* Ensure we register controllers on the CyberCP app (avoids ctrlreg if load order differs) */ +var app = (typeof window.app !== 'undefined' && window.app) ? window.app : angular.module('CyberCP'); /* Java script code to create database */ app.controller('createDatabase', function ($scope, $http) { @@ -683,14 +685,18 @@ app.controller('phpMyAdmin', function ($scope, $http, $window) { app.controller('Mysqlmanager', function ($scope, $http, $compile, $window, $timeout) { $scope.cyberPanelLoading = false; - $scope.mysql_status = 'test' + $scope.mysql_status = 'test'; + $scope.uptime = '—'; + $scope.connections = '—'; + $scope.Slow_queries = '—'; + $scope.processes = []; $scope.getstatus = function () { $scope.cyberPanelLoading = true; - url = "/dataBases/getMysqlstatus"; + url = "/dataBases/getMysqlstatus?t=" + (Date.now ? Date.now() : new Date().getTime()); var data = {}; @@ -706,12 +712,29 @@ app.controller('Mysqlmanager', function ($scope, $http, $compile, $window, $time function ListInitialDatas(response) { $scope.cyberPanelLoading = false; - if (response.data.status === 1) { - $scope.uptime = response.data.uptime; - $scope.connections = response.data.connections; - $scope.Slow_queries = response.data.Slow_queries; - $scope.processes = JSON.parse(response.data.processes); - $timeout($scope.showStatus, 3000); + var data = response.data; + if (typeof data === 'string') { + try { + data = JSON.parse(data); + } catch (e) { + $scope.uptime = $scope.connections = $scope.Slow_queries = '—'; + $scope.processes = []; + new PNotify({ title: 'Error!', text: 'Invalid response from server.', type: 'error' }); + return; + } + } + if (data && data.status === 1) { + $scope.uptime = data.uptime || '—'; + $scope.connections = data.connections != null ? data.connections : '—'; + $scope.Slow_queries = data.Slow_queries != null ? data.Slow_queries : '—'; + try { + $scope.processes = typeof data.processes === 'string' ? JSON.parse(data.processes || '[]') : (data.processes || []); + } catch (e) { + $scope.processes = []; + } + if (typeof $scope.showStatus === 'function') { + $timeout($scope.showStatus, 3000); + } new PNotify({ title: 'Success', @@ -721,7 +744,7 @@ app.controller('Mysqlmanager', function ($scope, $http, $compile, $window, $time } else { new PNotify({ title: 'Error!', - text: response.data.error_message, + text: (data && data.error_message) || 'Could not load MySQL status.', type: 'error' }); } @@ -730,15 +753,39 @@ app.controller('Mysqlmanager', function ($scope, $http, $compile, $window, $time function cantLoadInitialDatas(response) { $scope.cyberPanelLoading = false; + $scope.uptime = '—'; + $scope.connections = '—'; + $scope.Slow_queries = '—'; + $scope.processes = []; + var msg = 'Cannot load MySQL status.'; + if (response && response.status) { + msg = 'Request failed: ' + response.status + (response.statusText ? ' ' + response.statusText : ''); + } + if (response && response.data) { + if (typeof response.data === 'string' && response.data.length < 200) { + msg = response.data; + } else if (response.data.error_message) { + msg = response.data.error_message; + } + } new PNotify({ title: 'Error!', - text: "cannot load", + text: msg, type: 'error' }); } } + $scope.refreshProcesses = function () { + var icon = document.querySelector('.refresh-btn i'); + if (icon) { + icon.style.animation = 'spin 1s linear'; + setTimeout(function () { icon.style.animation = ''; }, 1000); + } + $scope.getstatus(); + }; + $scope.getstatus(); }); diff --git a/to-do/DEPLOY-BEFORE-PUSH-V2.5.5-DEV.md b/to-do/DEPLOY-BEFORE-PUSH-V2.5.5-DEV.md new file mode 100644 index 000000000..60ebf62c2 --- /dev/null +++ b/to-do/DEPLOY-BEFORE-PUSH-V2.5.5-DEV.md @@ -0,0 +1,26 @@ +# Deploy Locally Before Push (v2.5.5-dev) + +## Rule +**Always deploy to the local CyberPanel installation before pushing to v2.5.5-dev.** + +When deploying and pushing changes: + +1. **First: Deploy locally** + Copy all modified/relevant files from the repo to `/usr/local/CyberCP`, preserving directory structure. + +2. **Then: Commit and push** + Stage the same files, commit (author: `master3395`), and push to `origin v2.5.5-dev`. + +## Order +1. Deploy → 2. Commit → 3. Push + +Never push to v2.5.5-dev without deploying to `/usr/local/CyberCP` first. + +## Example +```bash +# 1. Deploy +cp /home/cyberpanel-repo/path/to/file /usr/local/CyberCP/path/to/ + +# 2. Commit and push +cd /home/cyberpanel-repo && git add ... && git commit -m "..." --author="master3395 " && git push origin v2.5.5-dev +``` diff --git a/to-do/DEPLOY-MYSQL-MANAGER-TO-SERVER.md b/to-do/DEPLOY-MYSQL-MANAGER-TO-SERVER.md new file mode 100644 index 000000000..beca2ceca --- /dev/null +++ b/to-do/DEPLOY-MYSQL-MANAGER-TO-SERVER.md @@ -0,0 +1,53 @@ +# Deploy MySQL Manager fixes to the server (e.g. 207.180.193.210) + +## Why you still see no data + +- The URL **https://207.180.193.210:2087** is the **remote server** (or your server’s public IP). It is **not** “localhost.” +- Our earlier deploy commands ran on the machine where the repo lives. If that machine is **not** the one serving 207.180.193.210, then the panel you open in the browser is still running the **old** code and old `databases.js`. +- Seeing **`{$ Slow_queries $}`** (literal text) and empty processes means the **Mysqlmanager** controller or the updated JS is not running on the server that serves that URL. + +## Fix: run the deploy on the server that serves 207.180.193.210 + +You must copy the updated files into CyberPanel **on the same machine** that serves https://207.180.193.210:2087 (i.e. where `/usr/local/CyberCP` is used by the panel). + +### Option A – You have the repo on that server (e.g. at `/home/cyberpanel-repo`) + +SSH to **207.180.193.210** (or the host that serves that IP) and run: + +```bash +# Path to repo on THAT server (change if different) +REPO=/home/cyberpanel-repo + +cp "$REPO/plogical/mysqlUtilities.py" /usr/local/CyberCP/plogical/ +cp "$REPO/databases/views.py" /usr/local/CyberCP/databases/ +cp "$REPO/databases/static/databases/databases.js" /usr/local/CyberCP/databases/static/databases/ +cp "$REPO/static/databases/databases.js" /usr/local/CyberCP/static/databases/ +# LiteSpeed serves /static/ from public/static/ – must deploy here or the browser gets the old file +mkdir -p /usr/local/CyberCP/public/static/databases +cp "$REPO/static/databases/databases.js" /usr/local/CyberCP/public/static/databases/ + +# Restart panel so changes are used +systemctl restart lscpd + +echo "MySQL Manager deploy done. Hard-refresh the MySQL Manager page (Ctrl+Shift+R)." +``` + +### Option B – Repo is only on another machine (e.g. your dev box) + +1. Copy the **four files** from the machine that has the repo to **207.180.193.210** (e.g. with `scp` or `rsync`): + - `plogical/mysqlUtilities.py` + - `databases/views.py` + - `databases/static/databases/databases.js` + - `static/databases/databases.js` + +2. On **207.180.193.210**, run the same `cp` commands as in Option A, using the paths where you put those files instead of `$REPO`. + +3. Restart the panel: + `systemctl restart lscpd` + +### After deploy + +- Open **https://207.180.193.210:2087/dataBases/MysqlManager** +- Do a **hard refresh**: **Ctrl+Shift+R** (or Cmd+Shift+R on Mac) so the browser doesn’t use cached `databases.js`. + +If you still see no data, open the browser **Developer Tools (F12) → Console** and note any red errors (e.g. `ctrlreg` or 404 for `databases.js`), then share that message. diff --git a/userManagment/homeDirectoryViews.py b/userManagment/homeDirectoryViews.py index af0f71070..96f1403d4 100644 --- a/userManagment/homeDirectoryViews.py +++ b/userManagment/homeDirectoryViews.py @@ -169,7 +169,7 @@ def getHomeDirectoryStats(request): return JsonResponse({'status': 0, 'error_message': str(e)}) def getUserHomeDirectories(request): - """Get available home directories for user creation""" + """Get available home directories for user creation. Returns empty list if tables do not exist.""" try: userID = request.session['userID'] currentACL = ACLManager.loadedACL(userID) @@ -177,7 +177,7 @@ def getUserHomeDirectories(request): if currentACL['admin'] != 1 and currentACL['createNewUser'] != 1: return JsonResponse({'status': 0, 'error_message': 'Unauthorized access'}) - # Get active home directories + # Get active home directories (tables home_directories / user_home_mappings may not exist yet) home_dirs = HomeDirectory.objects.filter(is_active=True).order_by('name') directories = [] @@ -196,7 +196,8 @@ def getUserHomeDirectories(request): except Exception as e: logging.CyberCPLogFileWriter.writeToFile(f"Error getting user home directories: {str(e)}") - return JsonResponse({'status': 0, 'error_message': str(e)}) + # If tables don't exist (e.g. user_home_mappings), return empty list so Modify Website still works + return JsonResponse({'status': 1, 'directories': []}) def migrateUser(request): """Migrate user to different home directory""" diff --git a/userManagment/templates/userManagment/userMigration.html b/userManagment/templates/userManagment/userMigration.html index a2ac444ca..2b924f2d0 100644 --- a/userManagment/templates/userManagment/userMigration.html +++ b/userManagment/templates/userManagment/userMigration.html @@ -95,7 +95,7 @@ function loadUsers() { function loadHomeDirectories() { $.ajax({ - url: '/userManagement/getUserHomeDirectories/', + url: '/users/getUserHomeDirectories', type: 'POST', data: JSON.stringify({}), contentType: 'application/json', diff --git a/websiteFunctions/website.py b/websiteFunctions/website.py index 0f004f2f3..b2e0d2e0e 100644 --- a/websiteFunctions/website.py +++ b/websiteFunctions/website.py @@ -3592,10 +3592,14 @@ context /cyberpanel_suspension_page.html { currentPack = modifyWeb.package.packageName owner = modifyWeb.admin.userName - # Get current home directory information - from userManagment.homeDirectoryUtils import HomeDirectoryUtils - current_home = HomeDirectoryUtils.getUserHomeDirectoryObject(owner) - currentHomeDirectory = current_home.name if current_home else 'Default' + # Get current home directory information (optional: tables may not exist yet) + currentHomeDirectory = 'Default' + try: + from userManagment.homeDirectoryUtils import HomeDirectoryUtils + current_home = HomeDirectoryUtils.getUserHomeDirectoryObject(owner) + currentHomeDirectory = current_home.name if current_home else 'Default' + except Exception: + pass data_ret = {'status': 1, 'modifyStatus': 1, 'error_message': "None", "adminEmail": email, "packages": json_data, "current_pack": currentPack, "adminNames": admin_data,