MySQL Manager: fix status/processes load, Query Info 'No query', MariaDB-safe parsing, deploy docs

- databases.js: app ref for ctrlreg, cache-buster, error handling, public/static sync
- mysqlUtilities: column-name process list (MariaDB), SHOW GLOBAL STATUS safe parse, Query Info 'No query'
- mysqlmanager.html: Query Info fallback for NULL
- Deploy docs: DEPLOY-BEFORE-PUSH, DEPLOY-MYSQL-MANAGER-TO-SERVER (public/static)
- Other: CyberPanelUpgrade, upgrade, websiteFunctions, userManagment, website
This commit is contained in:
master3395
2026-02-16 19:24:39 +01:00
parent faf6f8fff6
commit d8c8af72bf
13 changed files with 765 additions and 64 deletions

View File

@@ -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,

View File

@@ -644,8 +644,8 @@
</td>
<td>
<span class="info-text"
ng-bind="process.info || 'No query'"
ng-attr-title="{$ process.info $}"></span>
ng-bind="(process.info && process.info !== 'NULL') ? process.info : 'No query'"
ng-attr-title="{$ (process.info && process.info !== 'NULL') ? process.info : 'No query' $}"></span>
</td>
<td>
<div class="progress-bar">

View File

@@ -79,6 +79,7 @@ class UpgradeCyberPanel:
Upgrade.CLMigrations()
Upgrade.IncBackupMigrations()
Upgrade.applyLoginSystemMigrations()
Upgrade.homeDirectoryMigrations()
Upgrade.s3BackupMigrations()
Upgrade.containerMigrations()
Upgrade.manageServiceMigrations()

View File

@@ -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:

View File

@@ -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

View File

@@ -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;
}
}
});

View File

@@ -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;

View File

@@ -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();
});

View File

@@ -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 <master3395@users.noreply.github.com>" && git push origin v2.5.5-dev
```

View File

@@ -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 servers 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 doesnt 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.

View File

@@ -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"""

View File

@@ -95,7 +95,7 @@ function loadUsers() {
function loadHomeDirectories() {
$.ajax({
url: '/userManagement/getUserHomeDirectories/',
url: '/users/getUserHomeDirectories',
type: 'POST',
data: JSON.stringify({}),
contentType: 'application/json',

View File

@@ -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,