cyberpanel/baseTemplate/static/baseTemplate/custom-js/system-status.js

1780 lines
61 KiB
JavaScript

/**
* Created by usman on 7/24/17.
*/
/* Utilities */
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
function randomPassword(length) {
var chars = "abcdefghijklmnopqrstuvwxyz!@#%^*-+ABCDEFGHIJKLMNOP1234567890";
var pass = "";
for (var x = 0; x < length; x++) {
var i = Math.floor(Math.random() * chars.length);
pass += chars.charAt(i);
}
return pass;
}
/* Utilities ends here */
/* Java script code to monitor system status */
var app = angular.module('CyberCP', []);
var globalScope;
function GlobalRespSuccess(response) {
globalScope.cyberPanelLoading = true;
if (response.data.status === 1) {
new PNotify({
title: 'Success',
text: 'Successfully executed.',
type: 'success'
});
} else {
new PNotify({
title: 'Operation Failed!',
text: response.data.error_message,
type: 'error'
});
}
}
function GlobalRespFailed(response) {
globalScope.cyberPanelLoading = true;
new PNotify({
title: 'Operation Failed!',
text: 'Could not connect to server, please refresh this page',
type: 'error'
});
}
function GLobalAjaxCall(http, url, data, successCallBack, failureCallBack) {
var config = {
headers: {
'X-CSRFToken': getCookie('csrftoken')
}
};
http.post(url, data, config).then(successCallBack, failureCallBack);
}
app.config(['$interpolateProvider', function ($interpolateProvider) {
$interpolateProvider.startSymbol('{$');
$interpolateProvider.endSymbol('$}');
}]);
app.filter('getwebsitename', function () {
return function (domain, uppercase) {
if (domain !== undefined) {
domain = domain.replace(/-/g, '');
var domainName = domain.split(".");
var finalDomainName = domainName[0];
if (finalDomainName.length > 5) {
finalDomainName = finalDomainName.substring(0, 4);
}
return finalDomainName;
}
};
});
function getWebsiteName(domain) {
if (domain !== undefined) {
domain = domain.replace(/-/g, '');
var domainName = domain.split(".");
var finalDomainName = domainName[0];
if (finalDomainName.length > 5) {
finalDomainName = finalDomainName.substring(0, 4);
}
return finalDomainName;
}
}
app.controller('systemStatusInfo', function ($scope, $http, $timeout) {
$scope.uptimeLoaded = false;
$scope.uptime = 'Loading...';
getStuff();
$scope.getSystemStatus = function() {
getStuff();
};
function getStuff() {
url = "/base/getSystemStatus";
$http.get(url).then(ListInitialData, cantLoadInitialData);
function ListInitialData(response) {
$scope.cpuUsage = response.data.cpuUsage;
$scope.ramUsage = response.data.ramUsage;
$scope.diskUsage = response.data.diskUsage;
// Total system information
$scope.cpuCores = response.data.cpuCores;
$scope.ramTotalMB = response.data.ramTotalMB;
$scope.diskTotalGB = response.data.diskTotalGB;
$scope.diskFreeGB = response.data.diskFreeGB;
// Get uptime if available
if (response.data.uptime) {
$scope.uptime = response.data.uptime;
$scope.uptimeLoaded = true;
} else {
// Fallback: try to get uptime separately
$http.get("/base/getUptime").then(function(uptimeResponse) {
if (uptimeResponse.data.uptime) {
$scope.uptime = uptimeResponse.data.uptime;
$scope.uptimeLoaded = true;
}
});
}
}
function cantLoadInitialData(response) {
$scope.uptime = 'Unavailable';
$scope.uptimeLoaded = true;
}
$timeout(getStuff, 60000); // Update every minute
}
});
/* Admin status */
app.controller('adminController', function ($scope, $http, $timeout) {
url = "/base/getAdminStatus";
$http.get(url).then(ListInitialData, cantLoadInitialData);
function ListInitialData(response) {
$scope.currentAdmin = response.data.adminName;
$scope.admin_type = response.data.admin_type;
$("#serverIPAddress").text(response.data.serverIPAddress);
if (response.data.admin === 0) {
$('.serverACL').hide();
if (!Boolean(response.data.versionManagement)) {
$('.versionManagement').hide();
}
// User Management
if (!Boolean(response.data.createNewUser)) {
$('.createNewUser').hide();
}
if (!Boolean(response.data.listUsers)) {
$('.listUsers').hide();
}
if (!Boolean(response.data.resellerCenter)) {
$('.resellerCenter').hide();
}
if (!Boolean(response.data.deleteUser)) {
$('.deleteUser').hide();
}
if (!Boolean(response.data.changeUserACL)) {
$('.changeUserACL').hide();
}
// Website Management
if (!Boolean(response.data.createWebsite)) {
$('.createWebsite').hide();
}
if (!Boolean(response.data.modifyWebsite)) {
$('.modifyWebsite').hide();
}
if (!Boolean(response.data.suspendWebsite)) {
$('.suspendWebsite').hide();
}
if (!Boolean(response.data.deleteWebsite)) {
$('.deleteWebsite').hide();
}
// Package Management
if (!Boolean(response.data.createPackage)) {
$('.createPackage').hide();
}
if (!Boolean(response.data.listPackages)) {
$('.listPackages').hide();
}
if (!Boolean(response.data.deletePackage)) {
$('.deletePackage').hide();
}
if (!Boolean(response.data.modifyPackage)) {
$('.modifyPackage').hide();
}
// Database Management
if (!Boolean(response.data.createDatabase)) {
$('.createDatabase').hide();
}
if (!Boolean(response.data.deleteDatabase)) {
$('.deleteDatabase').hide();
}
if (!Boolean(response.data.listDatabases)) {
$('.listDatabases').hide();
}
// DNS Management
if (!Boolean(response.data.dnsAsWhole)) {
$('.dnsAsWhole').hide();
}
if (!Boolean(response.data.createNameServer)) {
$('.createNameServer').hide();
}
if (!Boolean(response.data.createDNSZone)) {
$('.createDNSZone').hide();
}
if (!Boolean(response.data.deleteZone)) {
$('.addDeleteRecords').hide();
}
if (!Boolean(response.data.addDeleteRecords)) {
$('.deleteDatabase').hide();
}
// Email Management
if (!Boolean(response.data.emailAsWhole)) {
$('.emailAsWhole').hide();
}
if (!Boolean(response.data.listEmails)) {
$('.listEmails').hide();
}
if (!Boolean(response.data.createEmail)) {
$('.createEmail').hide();
}
if (!Boolean(response.data.deleteEmail)) {
$('.deleteEmail').hide();
}
if (!Boolean(response.data.emailForwarding)) {
$('.emailForwarding').hide();
}
if (!Boolean(response.data.changeEmailPassword)) {
$('.changeEmailPassword').hide();
}
if (!Boolean(response.data.dkimManager)) {
$('.dkimManager').hide();
}
// FTP Management
if (!Boolean(response.data.ftpAsWhole)) {
$('.ftpAsWhole').hide();
}
if (!Boolean(response.data.createFTPAccount)) {
$('.createFTPAccount').hide();
}
if (!Boolean(response.data.deleteFTPAccount)) {
$('.deleteFTPAccount').hide();
}
if (!Boolean(response.data.listFTPAccounts)) {
$('.listFTPAccounts').hide();
}
// Backup Management
if (!Boolean(response.data.createBackup)) {
$('.createBackup').hide();
}
if (!Boolean(response.data.restoreBackup)) {
$('.restoreBackup').hide();
}
if (!Boolean(response.data.addDeleteDestinations)) {
$('.addDeleteDestinations').hide();
}
if (!Boolean(response.data.scheduleBackups)) {
$('.scheduleBackups').hide();
}
if (!Boolean(response.data.remoteBackups)) {
$('.remoteBackups').hide();
}
// SSL Management
if (!Boolean(response.data.manageSSL)) {
$('.manageSSL').hide();
}
if (!Boolean(response.data.hostnameSSL)) {
$('.hostnameSSL').hide();
}
if (!Boolean(response.data.mailServerSSL)) {
$('.mailServerSSL').hide();
}
} else {
if (!Boolean(response.data.emailAsWhole)) {
$('.emailAsWhole').hide();
}
if (!Boolean(response.data.ftpAsWhole)) {
$('.ftpAsWhole').hide();
}
if (!Boolean(response.data.dnsAsWhole)) {
$('.dnsAsWhole').hide();
}
}
}
function cantLoadInitialData(response) {
}
});
/* Load average */
app.controller('loadAvg', function ($scope, $http, $timeout) {
getLoadAvg();
function getLoadAvg() {
url = "/base/getLoadAverage";
$http.get(url).then(ListLoadAvgData, cantGetLoadAvgData);
function ListLoadAvgData(response) {
$scope.one = response.data.one;
$scope.two = response.data.two;
$scope.three = response.data.three;
}
function cantGetLoadAvgData(response) {
console.log("Can't get load average data");
}
//$timeout(getStuff, 2000);
}
});
/// home page system status
app.controller('homePageStatus', function ($scope, $http, $timeout) {
getStuff();
getLoadAvg();
function getStuff() {
url = "/base/getSystemStatus";
$http.get(url).then(ListInitialData, cantLoadInitialData);
function ListInitialData(response) {
console.log(response.data);
$("#redcircle").removeClass();
$("#greencircle").removeClass();
$("#pinkcircle").removeClass();
$scope.cpuUsage = response.data.cpuUsage;
$scope.ramUsage = response.data.ramUsage;
$scope.diskUsage = response.data.diskUsage;
$scope.RequestProcessing = response.data.RequestProcessing;
$scope.TotalRequests = response.data.TotalRequests;
$scope.MAXCONN = response.data.MAXCONN;
$scope.MAXSSL = response.data.MAXSSL;
$scope.Avail = response.data.Avail;
$scope.AvailSSL = response.data.AvailSSL;
$("#redcircle").addClass("c100");
$("#redcircle").addClass("p" + $scope.cpuUsage);
$("#redcircle").addClass("red");
$("#greencircle").addClass("c100");
$("#greencircle").addClass("p" + $scope.ramUsage);
$("#greencircle").addClass("green");
$("#pinkcircle").addClass("c100");
$("#pinkcircle").addClass("p" + $scope.diskUsage);
$("#pinkcircle").addClass("red");
// home page cpu,ram and disk update.
var rotationMultiplier = 3.6;
// For each div that its id ends with "circle", do the following.
$("div[id$='circle']").each(function () {
// Save all of its classes in an array.
var classList = $(this).attr('class').split(/\s+/);
// Iterate over the array
for (var i = 0; i < classList.length; i++) {
/* If there's about a percentage class, take the actual percentage and apply the
css transformations in all occurences of the specified percentage class,
even for the divs without an id ending with "circle" */
if (classList[i].match("^p" + $scope.cpuUsage)) {
var rotationPercentage = $scope.cpuUsage;
var rotationDegrees = rotationMultiplier * rotationPercentage;
$('.c100.p' + rotationPercentage + ' .bar').css({
'-webkit-transform': 'rotate(' + rotationDegrees + 'deg)',
'-moz-transform': 'rotate(' + rotationDegrees + 'deg)',
'-ms-transform': 'rotate(' + rotationDegrees + 'deg)',
'-o-transform': 'rotate(' + rotationDegrees + 'deg)',
'transform': 'rotate(' + rotationDegrees + 'deg)'
});
} else if (classList[i].match("^p" + $scope.ramUsage)) {
var rotationPercentage = response.data.ramUsage;
;
var rotationDegrees = rotationMultiplier * rotationPercentage;
$('.c100.p' + rotationPercentage + ' .bar').css({
'-webkit-transform': 'rotate(' + rotationDegrees + 'deg)',
'-moz-transform': 'rotate(' + rotationDegrees + 'deg)',
'-ms-transform': 'rotate(' + rotationDegrees + 'deg)',
'-o-transform': 'rotate(' + rotationDegrees + 'deg)',
'transform': 'rotate(' + rotationDegrees + 'deg)'
});
} else if (classList[i].match("^p" + $scope.diskUsage)) {
var rotationPercentage = response.data.diskUsage;
;
var rotationDegrees = rotationMultiplier * rotationPercentage;
$('.c100.p' + rotationPercentage + ' .bar').css({
'-webkit-transform': 'rotate(' + rotationDegrees + 'deg)',
'-moz-transform': 'rotate(' + rotationDegrees + 'deg)',
'-ms-transform': 'rotate(' + rotationDegrees + 'deg)',
'-o-transform': 'rotate(' + rotationDegrees + 'deg)',
'transform': 'rotate(' + rotationDegrees + 'deg)'
});
}
}
});
}
function cantLoadInitialData(response) {
console.log("not good");
}
$timeout(getStuff, 2000);
}
function getLoadAvg() {
url = "/base/getLoadAverage";
$http.get(url).then(ListLoadAvgData, cantGetLoadAvgData);
function ListLoadAvgData(response) {
$scope.one = response.data.one;
$scope.two = response.data.two;
$scope.three = response.data.three;
//document.getElementById("load1").innerHTML = $scope.one;
//document.getElementById("load2").innerHTML = $scope.two;
//document.getElementById("load3").innerHTML = $scope.three;
}
function cantGetLoadAvgData(response) {
console.log("Can't get load average data");
}
$timeout(getLoadAvg, 2000);
}
});
////////////
function increment() {
$('.box').hide();
setTimeout(function () {
$('.box').show();
}, 100);
}
increment();
////////////
app.controller('versionManagment', function ($scope, $http, $timeout) {
$scope.upgradeLoading = true;
$scope.upgradelogBox = true;
$scope.updateError = true;
$scope.updateStarted = true;
$scope.updateFinish = true;
$scope.couldNotConnect = true;
$scope.upgrade = function () {
$scope.upgradeLoading = false;
$scope.updateError = true;
$scope.updateStarted = true;
$scope.updateFinish = true;
$scope.couldNotConnect = true;
var data = {
branchSelect: document.getElementById("branchSelect").value,
};
var config = {
headers: {
'X-CSRFToken': getCookie('csrftoken')
}
};
url = "/base/upgrade";
$http.post(url, data, config).then(ListInitialData, cantLoadInitialData);
function ListInitialData(response) {
if (response.data.upgrade == 1) {
$scope.upgradeLoading = true;
$scope.updateError = true;
$scope.updateStarted = false;
$scope.updateFinish = true;
$scope.couldNotConnect = true;
getUpgradeStatus();
} else {
$scope.updateError = false;
$scope.updateStarted = true;
$scope.updateFinish = true;
$scope.couldNotConnect = true;
$scope.errorMessage = response.data.error_message;
}
}
function cantLoadInitialData(response) {
$scope.updateError = true;
$scope.updateStarted = true;
$scope.updateFinish = true;
$scope.couldNotConnect = false;
}
}
function getUpgradeStatus() {
$scope.upgradeLoading = false;
url = "/base/UpgradeStatus";
var data = {};
var config = {
headers: {
'X-CSRFToken': getCookie('csrftoken')
}
};
$http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
function ListInitialDatas(response) {
console.log(response.data.upgradeLog);
if (response.data.upgradeStatus === 1) {
if (response.data.finished === 1) {
$timeout.cancel();
$scope.upgradelogBox = false;
$scope.upgradeLog = response.data.upgradeLog;
$scope.upgradeLoading = true;
$scope.updateError = true;
$scope.updateStarted = true;
$scope.updateFinish = false;
$scope.couldNotConnect = true;
} else {
$scope.upgradelogBox = false;
$scope.upgradeLog = response.data.upgradeLog;
timeout(getUpgradeStatus, 2000);
}
}
}
function cantLoadInitialDatas(response) {
$scope.updateError = true;
$scope.updateStarted = true;
$scope.updateFinish = true;
$scope.couldNotConnect = false;
}
};
});
app.controller('designtheme', function ($scope, $http, $timeout) {
$scope.themeloading = true;
$scope.getthemedata = function () {
$scope.themeloading = false;
url = "/base/getthemedata";
var data = {
package: "helo world",
Themename: $('#stheme').val(),
};
var config = {
headers: {
'X-CSRFToken': getCookie('csrftoken')
}
};
$http.post(url, data, config).then(Listgetthemedata, cantgetthemedata);
function Listgetthemedata(response) {
$scope.themeloading = true;
if (response.data.status === 1) {
document.getElementById('appendthemedata').innerHTML = "";
$("#appendthemedata").val(response.data.csscontent)
} else {
alert(response.data.error_message)
}
}
function cantgetthemedata(response) {
$scope.themeloading = true;
console.log(response);
}
//$timeout(getStuff, 2000);
};
});
app.controller('OnboardingCP', function ($scope, $http, $timeout, $window) {
$scope.cyberpanelLoading = true;
$scope.ExecutionStatus = true;
$scope.ReportStatus = true;
$scope.OnboardineDone = true;
var statusTimer = null;
function statusFunc() {
$scope.cyberpanelLoading = false;
$scope.ExecutionStatus = false;
var url = "/emailPremium/statusFunc";
var data = {
statusFile: statusFile
};
var config = {
headers: {
'X-CSRFToken': getCookie('csrftoken')
}
};
$http.post(url, data, config).then(ListInitialData, cantLoadInitialData);
function ListInitialData(response) {
if (response.data.status === 1) {
if (response.data.abort === 1) {
$scope.functionProgress = {"width": "100%"};
$scope.functionStatus = response.data.currentStatus;
$scope.cyberpanelLoading = true;
$scope.OnboardineDone = false;
if (statusTimer) {
$timeout.cancel(statusTimer);
statusTimer = null;
}
} else {
$scope.functionProgress = {"width": response.data.installationProgress + "%"};
$scope.functionStatus = response.data.currentStatus;
statusTimer = $timeout(statusFunc, 3000);
}
} else {
$scope.cyberpanelLoading = true;
$scope.functionStatus = response.data.error_message;
$scope.functionProgress = {"width": response.data.installationProgress + "%"};
if (statusTimer) {
$timeout.cancel(statusTimer);
statusTimer = null;
}
}
}
function cantLoadInitialData(response) {
$scope.functionProgress = {"width": response.data.installationProgress + "%"};
$scope.functionStatus = 'Could not connect to server, please refresh this page.';
$timeout.cancel();
}
}
$scope.RunOnboarding = function () {
$scope.cyberpanelLoading = false;
$scope.OnboardineDone = true;
var url = "/base/runonboarding";
var data = {
hostname: $scope.hostname,
rDNSCheck: $scope.rDNSCheck
};
var config = {
headers: {
'X-CSRFToken': getCookie('csrftoken')
}
};
$http.post(url, data, config).then(ListInitialData, cantLoadInitialData);
function ListInitialData(response) {
$scope.cyberpanelLoading = true;
if (response.data.status === 1) {
statusFile = response.data.tempStatusPath;
statusFunc();
} else {
new PNotify({
title: 'Operation Failed!',
text: response.data.error_message,
type: 'error'
});
}
}
function cantLoadInitialData(response) {
$scope.cyberpanelLoading = true;
new PNotify({
title: 'Error',
text: 'Could not connect to server, please refresh this page.',
type: 'error'
});
}
};
$scope.RestartCyberPanel = function () {
$scope.cyberpanelLoading = false;
var url = "/base/RestartCyberPanel";
var data = {
};
var config = {
headers: {
'X-CSRFToken': getCookie('csrftoken')
}
};
$http.post(url, data, config).then(ListInitialData, cantLoadInitialData);
$scope.cyberpanelLoading = true;
new PNotify({
title: 'Success',
text: 'Refresh your browser after 3 seconds to fetch new SSL.',
type: 'success'
});
function ListInitialData(response) {
$scope.cyberpanelLoading = true;
if (response.data.status === 1) {
} else {
new PNotify({
title: 'Operation Failed!',
text: response.data.error_message,
type: 'error'
});
}
}
function cantLoadInitialData(response) {
$scope.cyberpanelLoading = true;
new PNotify({
title: 'Error',
text: 'Could not connect to server, please refresh this page.',
type: 'error'
});
}
};
});
app.controller('dashboardStatsController', function ($scope, $http, $timeout) {
// Card values
$scope.totalUsers = 0;
$scope.totalSites = 0;
$scope.totalWPSites = 0;
$scope.totalDBs = 0;
$scope.totalEmails = 0;
$scope.totalFTPUsers = 0;
// Hide system charts for non-admin users
$scope.hideSystemCharts = false;
// Top Processes
$scope.topProcesses = [];
$scope.loadingTopProcesses = true;
$scope.errorTopProcesses = '';
$scope.refreshTopProcesses = function() {
$scope.loadingTopProcesses = true;
$http.get('/base/getTopProcesses').then(function (response) {
$scope.loadingTopProcesses = false;
if (response.data && response.data.status === 1 && response.data.processes) {
$scope.topProcesses = response.data.processes;
} else {
$scope.topProcesses = [];
}
}, function (err) {
$scope.loadingTopProcesses = false;
$scope.errorTopProcesses = 'Failed to load top processes.';
});
};
// SSH Logins
$scope.sshLogins = [];
$scope.sshLoginsPaginated = [];
$scope.sshLoginsCurrentPage = 1;
$scope.sshLoginsPerPage = 10;
$scope.sshLoginsGoToPage = 1;
$scope.loadingSSHLogins = true;
$scope.errorSSHLogins = '';
$scope.getSSHLoginsTotalPages = function() {
return Math.ceil($scope.sshLogins.length / $scope.sshLoginsPerPage);
};
$scope.getSSHLoginsStart = function() {
if (!$scope.sshLogins || $scope.sshLogins.length === 0) {
return 0;
}
return ($scope.sshLoginsCurrentPage - 1) * $scope.sshLoginsPerPage + 1;
};
$scope.getSSHLoginsEnd = function() {
if (!$scope.sshLogins || $scope.sshLogins.length === 0) {
return 0;
}
var end = $scope.sshLoginsCurrentPage * $scope.sshLoginsPerPage;
return Math.min(end, $scope.sshLogins.length);
};
$scope.updateSSHLoginsPaginated = function() {
if (!$scope.sshLogins || $scope.sshLogins.length === 0) {
$scope.sshLoginsPaginated = [];
console.log('updateSSHLoginsPaginated: No data, cleared paginated array');
return;
}
var start = ($scope.sshLoginsCurrentPage - 1) * $scope.sshLoginsPerPage;
var end = start + $scope.sshLoginsPerPage;
$scope.sshLoginsPaginated = $scope.sshLogins.slice(start, end);
console.log('updateSSHLoginsPaginated: start=', start, 'end=', end, 'total=', $scope.sshLogins.length, 'paginated=', $scope.sshLoginsPaginated.length);
};
$scope.sshLoginsPrevPage = function() {
if ($scope.sshLoginsCurrentPage > 1) {
$scope.sshLoginsCurrentPage--;
$scope.updateSSHLoginsPaginated();
}
};
$scope.sshLoginsNextPage = function() {
if ($scope.sshLoginsCurrentPage < $scope.getSSHLoginsTotalPages()) {
$scope.sshLoginsCurrentPage++;
$scope.updateSSHLoginsPaginated();
}
};
$scope.sshLoginsGoToPageNumber = function() {
var page = parseInt($scope.sshLoginsGoToPage);
var totalPages = $scope.getSSHLoginsTotalPages();
if (page >= 1 && page <= totalPages) {
$scope.sshLoginsCurrentPage = page;
$scope.updateSSHLoginsPaginated();
} else {
$scope.sshLoginsGoToPage = $scope.sshLoginsCurrentPage;
}
};
$scope.refreshSSHLogins = function() {
$scope.loadingSSHLogins = true;
$http.get('/base/getRecentSSHLogins').then(function (response) {
$scope.loadingSSHLogins = false;
console.log('SSH Logins response:', response.data);
if (response.data && response.data.logins && Array.isArray(response.data.logins)) {
$scope.sshLogins = response.data.logins;
$scope.sshLoginsCurrentPage = 1;
$scope.sshLoginsGoToPage = 1;
console.log('SSH Logins loaded:', $scope.sshLogins.length, 'items');
$scope.updateSSHLoginsPaginated();
console.log('SSH Logins paginated:', $scope.sshLoginsPaginated.length, 'items');
} else {
console.warn('SSH Logins: No data or invalid format', response.data);
$scope.sshLogins = [];
$scope.sshLoginsPaginated = [];
}
}, function (err) {
$scope.loadingSSHLogins = false;
console.error('SSH Logins error:', err);
$scope.errorSSHLogins = 'Failed to load SSH logins.';
$scope.sshLogins = [];
$scope.sshLoginsPaginated = [];
});
};
// SSH Logs
$scope.sshLogs = [];
$scope.sshLogsPaginated = [];
$scope.sshLogsCurrentPage = 1;
$scope.sshLogsPerPage = 10;
$scope.sshLogsGoToPage = 1;
$scope.loadingSSHLogs = true;
$scope.errorSSHLogs = '';
$scope.securityAlerts = [];
$scope.loadingSecurityAnalysis = false;
$scope.getSSHLogsTotalPages = function() {
return Math.ceil($scope.sshLogs.length / $scope.sshLogsPerPage);
};
$scope.getSSHLogsStart = function() {
if (!$scope.sshLogs || $scope.sshLogs.length === 0) {
return 0;
}
return ($scope.sshLogsCurrentPage - 1) * $scope.sshLogsPerPage + 1;
};
$scope.getSSHLogsEnd = function() {
if (!$scope.sshLogs || $scope.sshLogs.length === 0) {
return 0;
}
var end = $scope.sshLogsCurrentPage * $scope.sshLogsPerPage;
return Math.min(end, $scope.sshLogs.length);
};
$scope.updateSSHLogsPaginated = function() {
if (!$scope.sshLogs || $scope.sshLogs.length === 0) {
$scope.sshLogsPaginated = [];
console.log('updateSSHLogsPaginated: No data, cleared paginated array');
return;
}
var start = ($scope.sshLogsCurrentPage - 1) * $scope.sshLogsPerPage;
var end = start + $scope.sshLogsPerPage;
$scope.sshLogsPaginated = $scope.sshLogs.slice(start, end);
console.log('updateSSHLogsPaginated: start=', start, 'end=', end, 'total=', $scope.sshLogs.length, 'paginated=', $scope.sshLogsPaginated.length);
};
$scope.sshLogsPrevPage = function() {
if ($scope.sshLogsCurrentPage > 1) {
$scope.sshLogsCurrentPage--;
$scope.updateSSHLogsPaginated();
}
};
$scope.sshLogsNextPage = function() {
if ($scope.sshLogsCurrentPage < $scope.getSSHLogsTotalPages()) {
$scope.sshLogsCurrentPage++;
$scope.updateSSHLogsPaginated();
}
};
$scope.sshLogsGoToPageNumber = function() {
var page = parseInt($scope.sshLogsGoToPage);
var totalPages = $scope.getSSHLogsTotalPages();
if (page >= 1 && page <= totalPages) {
$scope.sshLogsCurrentPage = page;
$scope.updateSSHLogsPaginated();
} else {
$scope.sshLogsGoToPage = $scope.sshLogsCurrentPage;
}
};
$scope.refreshSSHLogs = function() {
$scope.loadingSSHLogs = true;
$http.get('/base/getRecentSSHLogs').then(function (response) {
$scope.loadingSSHLogs = false;
console.log('SSH Logs response:', response.data);
if (response.data && response.data.logs && Array.isArray(response.data.logs)) {
$scope.sshLogs = response.data.logs;
$scope.sshLogsCurrentPage = 1;
$scope.sshLogsGoToPage = 1;
console.log('SSH Logs loaded:', $scope.sshLogs.length, 'items');
$scope.updateSSHLogsPaginated();
console.log('SSH Logs paginated:', $scope.sshLogsPaginated.length, 'items');
// Analyze logs for security issues
$scope.analyzeSSHSecurity();
} else {
console.warn('SSH Logs: No data or invalid format', response.data);
$scope.sshLogs = [];
$scope.sshLogsPaginated = [];
}
}, function (err) {
$scope.loadingSSHLogs = false;
console.error('SSH Logs error:', err);
$scope.errorSSHLogs = 'Failed to load SSH logs.';
$scope.sshLogs = [];
$scope.sshLogsPaginated = [];
});
};
// Security Analysis
$scope.showAddonRequired = false;
$scope.addonInfo = {};
$scope.analyzeSSHSecurity = function() {
$scope.loadingSecurityAnalysis = true;
$scope.showAddonRequired = false;
$http.post('/base/analyzeSSHSecurity', {}).then(function (response) {
$scope.loadingSecurityAnalysis = false;
if (response.data) {
if (response.data.addon_required) {
$scope.showAddonRequired = true;
$scope.addonInfo = response.data;
$scope.securityAlerts = [];
} else if (response.data.status === 1) {
$scope.securityAlerts = response.data.alerts;
$scope.showAddonRequired = false;
}
}
}, function (err) {
$scope.loadingSecurityAnalysis = false;
});
};
// Initial fetch
$scope.refreshTopProcesses();
$scope.refreshSSHLogins();
$scope.refreshSSHLogs();
// Chart.js chart objects
var trafficChart, diskIOChart, cpuChart;
// Data arrays for live graphs
var trafficLabels = [], rxData = [], txData = [];
var diskLabels = [], readData = [], writeData = [];
var cpuLabels = [], cpuUsageData = [];
// For rate calculation
var lastRx = null, lastTx = null, lastDiskRead = null, lastDiskWrite = null, lastCPU = null;
var lastCPUTimes = null;
var pollInterval = 2000; // ms
var maxPoints = 30;
function pollDashboardStats() {
$http.get('/base/getDashboardStats').then(function(response) {
if (response.data.status === 1) {
$scope.totalUsers = response.data.total_users;
$scope.totalSites = response.data.total_sites;
$scope.totalWPSites = response.data.total_wp_sites;
$scope.totalDBs = response.data.total_dbs;
$scope.totalEmails = response.data.total_emails;
$scope.totalFTPUsers = response.data.total_ftp_users;
}
});
}
function pollTraffic() {
console.log('pollTraffic called');
$http.get('/base/getTrafficStats').then(function(response) {
if (response.data.admin_only) {
// Hide chart for non-admin users
$scope.hideSystemCharts = true;
return;
}
if (response.data.status === 1) {
var now = new Date();
var rx = response.data.rx_bytes;
var tx = response.data.tx_bytes;
if (lastRx !== null && lastTx !== null) {
var rxRate = (rx - lastRx) / (pollInterval / 1000); // bytes/sec
var txRate = (tx - lastTx) / (pollInterval / 1000);
trafficLabels.push(now.toLocaleTimeString());
rxData.push(rxRate);
txData.push(txRate);
if (trafficLabels.length > maxPoints) {
trafficLabels.shift(); rxData.shift(); txData.shift();
}
if (trafficChart) {
trafficChart.data.labels = trafficLabels.slice();
trafficChart.data.datasets[0].data = rxData.slice();
trafficChart.data.datasets[1].data = txData.slice();
trafficChart.update();
console.log('trafficChart updated:', trafficChart.data.labels, trafficChart.data.datasets[0].data, trafficChart.data.datasets[1].data);
}
} else {
// First poll, push zero data point
trafficLabels.push(now.toLocaleTimeString());
rxData.push(0);
txData.push(0);
if (trafficChart) {
trafficChart.data.labels = trafficLabels.slice();
trafficChart.data.datasets[0].data = rxData.slice();
trafficChart.data.datasets[1].data = txData.slice();
trafficChart.update();
console.log('trafficChart first update:', trafficChart.data.labels, trafficChart.data.datasets[0].data, trafficChart.data.datasets[1].data);
setTimeout(function() {
if (window.trafficChart) {
window.trafficChart.resize();
window.trafficChart.update();
console.log('trafficChart forced resize/update after first poll.');
}
}, 1000);
}
}
lastRx = rx; lastTx = tx;
} else {
console.log('pollTraffic error or no data:', response);
}
});
}
function pollDiskIO() {
$http.get('/base/getDiskIOStats').then(function(response) {
if (response.data.admin_only) {
// Hide chart for non-admin users
$scope.hideSystemCharts = true;
return;
}
if (response.data.status === 1) {
var now = new Date();
var read = response.data.read_bytes;
var write = response.data.write_bytes;
if (lastDiskRead !== null && lastDiskWrite !== null) {
var readRate = (read - lastDiskRead) / (pollInterval / 1000); // bytes/sec
var writeRate = (write - lastDiskWrite) / (pollInterval / 1000);
diskLabels.push(now.toLocaleTimeString());
readData.push(readRate);
writeData.push(writeRate);
if (diskLabels.length > maxPoints) {
diskLabels.shift(); readData.shift(); writeData.shift();
}
if (diskIOChart) {
diskIOChart.data.labels = diskLabels.slice();
diskIOChart.data.datasets[0].data = readData.slice();
diskIOChart.data.datasets[1].data = writeData.slice();
diskIOChart.update();
}
} else {
// First poll, push zero data point
diskLabels.push(now.toLocaleTimeString());
readData.push(0);
writeData.push(0);
if (diskIOChart) {
diskIOChart.data.labels = diskLabels.slice();
diskIOChart.data.datasets[0].data = readData.slice();
diskIOChart.data.datasets[1].data = writeData.slice();
diskIOChart.update();
}
}
lastDiskRead = read; lastDiskWrite = write;
}
});
}
function pollCPU() {
$http.get('/base/getCPULoadGraph').then(function(response) {
if (response.data.admin_only) {
// Hide chart for non-admin users
$scope.hideSystemCharts = true;
return;
}
if (response.data.status === 1 && response.data.cpu_times && response.data.cpu_times.length >= 4) {
var now = new Date();
var cpuTimes = response.data.cpu_times;
if (lastCPUTimes) {
var idle = cpuTimes[3];
var total = cpuTimes.reduce(function(a, b) { return a + b; }, 0);
var lastIdle = lastCPUTimes[3];
var lastTotal = lastCPUTimes.reduce(function(a, b) { return a + b; }, 0);
var idleDiff = idle - lastIdle;
var totalDiff = total - lastTotal;
var usage = totalDiff > 0 ? (100 * (1 - idleDiff / totalDiff)) : 0;
cpuLabels.push(now.toLocaleTimeString());
cpuUsageData.push(usage);
if (cpuLabels.length > maxPoints) {
cpuLabels.shift(); cpuUsageData.shift();
}
if (cpuChart) {
cpuChart.data.labels = cpuLabels.slice();
cpuChart.data.datasets[0].data = cpuUsageData.slice();
cpuChart.update();
}
} else {
// First poll, push zero data point
cpuLabels.push(now.toLocaleTimeString());
cpuUsageData.push(0);
if (cpuChart) {
cpuChart.data.labels = cpuLabels.slice();
cpuChart.data.datasets[0].data = cpuUsageData.slice();
cpuChart.update();
}
}
lastCPUTimes = cpuTimes;
}
});
}
function setupCharts() {
console.log('setupCharts called, initializing charts...');
var trafficCtx = document.getElementById('trafficChart').getContext('2d');
trafficChart = new Chart(trafficCtx, {
type: 'line',
data: {
labels: [],
datasets: [
{
label: 'Download',
data: [],
borderColor: '#5b5fcf',
backgroundColor: 'rgba(91,95,207,0.1)',
pointBackgroundColor: '#5b5fcf',
pointBorderColor: '#5b5fcf',
pointRadius: 3,
pointHoverRadius: 5,
borderWidth: 2,
tension: 0.4,
fill: true
},
{
label: 'Upload',
data: [],
borderColor: '#4a90e2',
backgroundColor: 'rgba(74,144,226,0.1)',
pointBackgroundColor: '#4a90e2',
pointBorderColor: '#4a90e2',
pointRadius: 3,
pointHoverRadius: 5,
borderWidth: 2,
tension: 0.4,
fill: true
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
animation: { duration: 0 },
plugins: {
legend: {
display: true,
position: 'top',
labels: {
font: { size: 12, weight: '600' },
color: '#64748b',
usePointStyle: true,
padding: 20
}
},
title: { display: false },
tooltip: {
enabled: true,
mode: 'index',
intersect: false,
backgroundColor: 'rgba(255,255,255,0.95)',
titleColor: '#2f3640',
bodyColor: '#64748b',
borderColor: '#e8e9ff',
borderWidth: 1,
cornerRadius: 8,
padding: 12
}
},
interaction: { mode: 'nearest', axis: 'x', intersect: false },
scales: {
x: {
grid: { color: '#f0f0ff', drawBorder: false },
ticks: {
font: { size: 11 },
color: '#94a3b8',
maxTicksLimit: 8
}
},
y: {
beginAtZero: true,
grid: { color: '#f0f0ff', drawBorder: false },
ticks: {
font: { size: 11 },
color: '#94a3b8'
}
}
},
layout: { padding: { top: 10, bottom: 10, left: 10, right: 10 } }
}
});
window.trafficChart = trafficChart;
setTimeout(function() {
if (window.trafficChart) {
window.trafficChart.resize();
window.trafficChart.update();
console.log('trafficChart resized and updated after setup.');
}
}, 500);
var diskCtx = document.getElementById('diskIOChart').getContext('2d');
diskIOChart = new Chart(diskCtx, {
type: 'line',
data: {
labels: [],
datasets: [
{
label: 'Read',
data: [],
borderColor: '#5b5fcf',
backgroundColor: 'rgba(91,95,207,0.1)',
pointBackgroundColor: '#5b5fcf',
pointBorderColor: '#5b5fcf',
pointRadius: 3,
pointHoverRadius: 5,
borderWidth: 2,
tension: 0.4,
fill: true
},
{
label: 'Write',
data: [],
borderColor: '#e74c3c',
backgroundColor: 'rgba(231,76,60,0.1)',
pointBackgroundColor: '#e74c3c',
pointBorderColor: '#e74c3c',
pointRadius: 3,
pointHoverRadius: 5,
borderWidth: 2,
tension: 0.4,
fill: true
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
animation: { duration: 0 },
plugins: {
legend: {
display: true,
position: 'top',
labels: {
font: { size: 12, weight: '600' },
color: '#64748b',
usePointStyle: true,
padding: 20
}
},
title: { display: false },
tooltip: {
enabled: true,
mode: 'index',
intersect: false,
backgroundColor: 'rgba(255,255,255,0.95)',
titleColor: '#2f3640',
bodyColor: '#64748b',
borderColor: '#e8e9ff',
borderWidth: 1,
cornerRadius: 8,
padding: 12
}
},
interaction: { mode: 'nearest', axis: 'x', intersect: false },
scales: {
x: {
grid: { color: '#f0f0ff', drawBorder: false },
ticks: {
font: { size: 11 },
color: '#94a3b8',
maxTicksLimit: 8
}
},
y: {
beginAtZero: true,
grid: { color: '#f0f0ff', drawBorder: false },
ticks: {
font: { size: 11 },
color: '#94a3b8'
}
}
},
layout: { padding: { top: 10, bottom: 10, left: 10, right: 10 } }
}
});
var cpuCtx = document.getElementById('cpuChart').getContext('2d');
cpuChart = new Chart(cpuCtx, {
type: 'line',
data: {
labels: [],
datasets: [
{
label: 'CPU Usage (%)',
data: [],
borderColor: '#5b5fcf',
backgroundColor: 'rgba(91,95,207,0.1)',
pointBackgroundColor: '#5b5fcf',
pointBorderColor: '#5b5fcf',
pointRadius: 3,
pointHoverRadius: 5,
borderWidth: 2,
tension: 0.4,
fill: true
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
animation: { duration: 0 },
plugins: {
legend: {
display: true,
position: 'top',
labels: {
font: { size: 12, weight: '600' },
color: '#64748b',
usePointStyle: true,
padding: 20
}
},
title: { display: false },
tooltip: {
enabled: true,
mode: 'index',
intersect: false,
backgroundColor: 'rgba(255,255,255,0.95)',
titleColor: '#2f3640',
bodyColor: '#64748b',
borderColor: '#e8e9ff',
borderWidth: 1,
cornerRadius: 8,
padding: 12
}
},
interaction: { mode: 'nearest', axis: 'x', intersect: false },
scales: {
x: {
grid: { color: '#f0f0ff', drawBorder: false },
ticks: {
font: { size: 11 },
color: '#94a3b8',
maxTicksLimit: 8
}
},
y: {
beginAtZero: true,
max: 100,
grid: { color: '#f0f0ff', drawBorder: false },
ticks: {
font: { size: 11 },
color: '#94a3b8'
}
}
},
layout: { padding: { top: 10, bottom: 10, left: 10, right: 10 } }
}
});
// Redraw charts on tab shown
$("a[data-toggle='tab']").on('shown.bs.tab', function (e) {
setTimeout(function() {
if (trafficChart) trafficChart.resize();
if (diskIOChart) diskIOChart.resize();
if (cpuChart) cpuChart.resize();
}, 100);
});
// Also handle custom tab switching
document.addEventListener('DOMContentLoaded', function() {
var tabs = document.querySelectorAll('a[data-toggle="tab"]');
tabs.forEach(function(tab) {
tab.addEventListener('click', function(e) {
setTimeout(function() {
if (trafficChart) trafficChart.resize();
if (diskIOChart) diskIOChart.resize();
if (cpuChart) cpuChart.resize();
}, 200);
});
});
});
}
// Initial setup
$timeout(function() {
// Check if user is admin before setting up charts
$http.get('/base/getAdminStatus').then(function(response) {
if (response.data && response.data.admin === 1) {
setupCharts();
} else {
$scope.hideSystemCharts = true;
}
}).catch(function() {
// If error, assume non-admin and hide charts
$scope.hideSystemCharts = true;
});
// Immediately poll once so stats are updated on first load
pollDashboardStats();
pollTraffic();
pollDiskIO();
pollCPU();
// Start polling
function pollAll() {
pollDashboardStats();
pollTraffic();
pollDiskIO();
pollCPU();
$scope.refreshTopProcesses();
$timeout(pollAll, pollInterval);
}
pollAll();
}, 500);
// SSH User Activity Modal
$scope.showSSHActivityModal = false;
$scope.sshActivity = { processes: [], w: [] };
$scope.sshActivityUser = '';
$scope.loadingSSHActivity = false;
$scope.errorSSHActivity = '';
$scope.viewSSHActivity = function(login) {
$scope.showSSHActivityModal = true;
$scope.sshActivity = { processes: [], w: [] };
$scope.sshActivityUser = login.user;
$scope.loadingSSHActivity = true;
$scope.errorSSHActivity = '';
var tty = '';
// Try to extract tty from login.raw or login.session if available
if (login.raw) {
var match = login.raw.match(/(pts\/[0-9]+)/);
if (match) tty = match[1];
}
console.log('Fetching SSH activity for user:', login.user, 'IP:', login.ip, 'TTY:', tty);
$http.post('/base/getSSHUserActivity', { user: login.user, tty: tty, ip: login.ip || '' }, {
timeout: 30000
}).then(function(response) {
console.log('SSH Activity response received:', response);
$scope.loadingSSHActivity = false;
if (response.data && response.data.error) {
console.error('SSH Activity error:', response.data.error);
$scope.errorSSHActivity = response.data.error;
$scope.sshActivity = { processes: [], w: [], shell_history: [], geoip: {}, disk_usage: '' };
} else if (response.data) {
console.log('SSH Activity data:', response.data);
$scope.sshActivity = response.data;
$scope.errorSSHActivity = '';
} else {
console.warn('SSH Activity: No data in response');
$scope.sshActivity = { processes: [], w: [], shell_history: [], geoip: {}, disk_usage: '' };
$scope.errorSSHActivity = 'No data received from server.';
}
}, function(err) {
$scope.loadingSSHActivity = false;
console.error('Error fetching SSH activity:', err);
console.error('Error status:', err.status);
console.error('Error data:', err.data);
if (err.status === 0) {
$scope.errorSSHActivity = 'Network error: Unable to connect to server. Please check your connection.';
} else if (err.status === -1) {
$scope.errorSSHActivity = 'Request timeout. The server took too long to respond.';
} else if (err.data && err.data.error) {
$scope.errorSSHActivity = err.data.error;
} else if (err.data && err.data.errorMessage) {
$scope.errorSSHActivity = err.data.errorMessage;
} else if (err.status === 403) {
$scope.errorSSHActivity = 'Access denied. Admin privileges required.';
} else if (err.status === 400) {
$scope.errorSSHActivity = 'Invalid request. Please try again.';
} else if (err.status === 500) {
$scope.errorSSHActivity = 'Server error. Please try again later.';
} else {
$scope.errorSSHActivity = 'Failed to fetch activity. Status: ' + (err.status || 'Unknown') + '. Please check your connection and try again.';
}
$scope.sshActivity = { processes: [], w: [], shell_history: [], geoip: {}, disk_usage: '' };
});
};
$scope.closeSSHActivityModal = function() {
$scope.showSSHActivityModal = false;
$scope.sshActivity = { processes: [], w: [] };
$scope.sshActivityUser = '';
$scope.loadingSSHActivity = false;
$scope.errorSSHActivity = '';
};
// Close modal when clicking backdrop
$scope.closeModalOnBackdrop = function(event) {
if (event.target === event.currentTarget) {
$scope.closeSSHActivityModal();
}
};
// Kill a specific process
$scope.killProcess = function(pid, user) {
if (!confirm('Are you sure you want to kill process ' + pid + '? This action cannot be undone.')) {
return;
}
console.log('Killing process:', pid, 'for user:', user);
$http.post('/base/killSSHProcess', { pid: pid, user: user }, { timeout: 10000 }).then(function(response) {
if (response.data && response.data.success) {
alert('Process ' + pid + ' killed successfully.');
// Reload activity data
if ($scope.sshActivityUser) {
var login = { user: $scope.sshActivityUser, ip: '', tty: '' };
$scope.viewSSHActivity(login);
}
} else if (response.data && response.data.error) {
alert('Error: ' + response.data.error);
} else {
alert('Unknown error occurred.');
}
}, function(err) {
console.error('Error killing process:', err);
var errorMsg = 'Failed to kill process. ';
if (err.data && err.data.error) {
errorMsg += err.data.error;
} else if (err.status === 403) {
errorMsg += 'Access denied.';
} else if (err.status === 404) {
errorMsg += 'Process not found.';
} else {
errorMsg += 'Please try again.';
}
alert(errorMsg);
});
};
// Kill all sessions for a user
$scope.killSession = function(user) {
if (!confirm('WARNING: This will force close ALL active sessions for user "' + user + '". This action cannot be undone.\n\nAre you sure you want to continue?')) {
return;
}
if (!confirm('Final confirmation: Kill all sessions for user "' + user + '"?')) {
return;
}
console.log('Killing session for user:', user);
$http.post('/base/killSSHSession', { user: user }, { timeout: 10000 }).then(function(response) {
if (response.data && response.data.success) {
alert('All sessions for user ' + user + ' have been terminated successfully.');
// Close modal and refresh SSH logins
$scope.closeSSHActivityModal();
// Refresh SSH logins list
if (typeof $scope.loadSSHLogins === 'function') {
$scope.loadSSHLogins();
}
} else if (response.data && response.data.error) {
alert('Error: ' + response.data.error);
} else {
alert('Unknown error occurred.');
}
}, function(err) {
console.error('Error killing session:', err);
var errorMsg = 'Failed to kill session. ';
if (err.data && err.data.error) {
errorMsg += err.data.error;
} else if (err.status === 403) {
errorMsg += 'Access denied.';
} else {
errorMsg += 'Please try again.';
}
alert(errorMsg);
});
};
});