From df545cfef25edd11134672e255b359f38cdcb29f Mon Sep 17 00:00:00 2001 From: usmannasir Date: Wed, 23 Apr 2025 23:12:24 +0500 Subject: [PATCH 01/16] bug fix: child domain launcher --- .../websiteFunctions/websiteFunctions.js | 935 +++++++++++++++++- 1 file changed, 934 insertions(+), 1 deletion(-) diff --git a/websiteFunctions/static/websiteFunctions/websiteFunctions.js b/websiteFunctions/static/websiteFunctions/websiteFunctions.js index 143947cb5..ecf1752a9 100755 --- a/websiteFunctions/static/websiteFunctions/websiteFunctions.js +++ b/websiteFunctions/static/websiteFunctions/websiteFunctions.js @@ -16904,4 +16904,937 @@ app.controller('BuyAddons', function ($scope, $http) { } -}) \ No newline at end of file +}) + +app.controller('launchChild', function ($scope, $http) { + + $scope.logFileLoading = true; + $scope.logsFeteched = true; + $scope.couldNotFetchLogs = true; + $scope.couldNotConnect = true; + $scope.fetchedData = true; + $scope.hideLogs = true; + $scope.hideErrorLogs = true; + + $scope.hidelogsbtn = function () { + $scope.hideLogs = true; + }; + + $scope.hideErrorLogsbtn = function () { + $scope.hideLogs = true; + }; + + $scope.fileManagerURL = "/filemanager/" + $("#domainNamePage").text(); + $scope.previewUrl = "/preview/" + $("#childDomain").text() + "/"; + $scope.wordPressInstallURL = "/websites/" + $("#childDomain").text() + "/wordpressInstall"; + $scope.joomlaInstallURL = "/websites/" + $("#childDomain").text() + "/joomlaInstall"; + $scope.setupGit = "/websites/" + $("#childDomain").text() + "/setupGit"; + $scope.installPrestaURL = "/websites/" + $("#childDomain").text() + "/installPrestaShop"; + $scope.installMagentoURL = "/websites/" + $("#childDomain").text() + "/installMagento"; + + var logType = 0; + $scope.pageNumber = 1; + + $scope.fetchLogs = function (type) { + + var pageNumber = $scope.pageNumber; + + + if (type == 3) { + pageNumber = $scope.pageNumber + 1; + $scope.pageNumber = pageNumber; + } else if (type == 4) { + pageNumber = $scope.pageNumber - 1; + $scope.pageNumber = pageNumber; + } else { + logType = type; + } + + + $scope.logFileLoading = false; + $scope.logsFeteched = true; + $scope.couldNotFetchLogs = true; + $scope.couldNotConnect = true; + $scope.fetchedData = false; + $scope.hideErrorLogs = true; + + + url = "/websites/getDataFromLogFile"; + + var domainNamePage = $("#domainNamePage").text(); + + + var data = { + logType: logType, + virtualHost: domainNamePage, + page: pageNumber, + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + + if (response.data.logstatus === 1) { + + + $scope.logFileLoading = true; + $scope.logsFeteched = false; + $scope.couldNotFetchLogs = true; + $scope.couldNotConnect = true; + $scope.fetchedData = false; + $scope.hideLogs = false; + + + $scope.records = JSON.parse(response.data.data); + + } else { + + $scope.logFileLoading = true; + $scope.logsFeteched = true; + $scope.couldNotFetchLogs = false; + $scope.couldNotConnect = true; + $scope.fetchedData = true; + $scope.hideLogs = false; + + + $scope.errorMessage = response.data.error_message; + console.log(domainNamePage) + + } + + + } + + function cantLoadInitialDatas(response) { + + $scope.logFileLoading = true; + $scope.logsFeteched = true; + $scope.couldNotFetchLogs = true; + $scope.couldNotConnect = false; + $scope.fetchedData = true; + $scope.hideLogs = false; + + } + + + }; + + $scope.errorPageNumber = 1; + + + $scope.fetchErrorLogs = function (type) { + + var errorPageNumber = $scope.errorPageNumber; + + + if (type === 3) { + errorPageNumber = $scope.errorPageNumber + 1; + $scope.errorPageNumber = errorPageNumber; + } else if (type === 4) { + errorPageNumber = $scope.errorPageNumber - 1; + $scope.errorPageNumber = errorPageNumber; + } else { + logType = type; + } + + // notifications + + $scope.logFileLoading = false; + $scope.logsFeteched = true; + $scope.couldNotFetchLogs = true; + $scope.couldNotConnect = true; + $scope.fetchedData = true; + $scope.hideErrorLogs = true; + $scope.hideLogs = false; + + + url = "/websites/fetchErrorLogs"; + + var domainNamePage = $("#domainNamePage").text(); + + + var data = { + virtualHost: domainNamePage, + page: errorPageNumber, + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + + if (response.data.logstatus === 1) { + + + // notifications + + $scope.logFileLoading = true; + $scope.logsFeteched = false; + $scope.couldNotFetchLogs = true; + $scope.couldNotConnect = true; + $scope.fetchedData = true; + $scope.hideLogs = false; + $scope.hideErrorLogs = false; + + + $scope.errorLogsData = response.data.data; + + } else { + + // notifications + + $scope.logFileLoading = true; + $scope.logsFeteched = true; + $scope.couldNotFetchLogs = false; + $scope.couldNotConnect = true; + $scope.fetchedData = true; + $scope.hideLogs = true; + $scope.hideErrorLogs = true; + + + $scope.errorMessage = response.data.error_message; + + } + + + } + + function cantLoadInitialDatas(response) { + + // notifications + + $scope.logFileLoading = true; + $scope.logsFeteched = true; + $scope.couldNotFetchLogs = true; + $scope.couldNotConnect = false; + $scope.fetchedData = true; + $scope.hideLogs = true; + $scope.hideErrorLogs = true; + + } + + + }; + + ///////// Configurations Part + + $scope.configurationsBox = true; + $scope.configsFetched = true; + $scope.couldNotFetchConfigs = true; + $scope.couldNotConnect = true; + $scope.fetchedConfigsData = true; + $scope.configFileLoading = true; + $scope.configSaved = true; + $scope.couldNotSaveConfigurations = true; + + $scope.hideconfigbtn = function () { + + $scope.configurationsBox = true; + }; + + $scope.fetchConfigurations = function () { + + + $scope.hidsslconfigs = true; + $scope.configurationsBoxRewrite = true; + $scope.changePHPView = true; + + + //Rewrite rules + $scope.configurationsBoxRewrite = true; + $scope.rewriteRulesFetched = true; + $scope.couldNotFetchRewriteRules = true; + $scope.rewriteRulesSaved = true; + $scope.couldNotSaveRewriteRules = true; + $scope.fetchedRewriteRules = true; + $scope.saveRewriteRulesBTN = true; + + /// + + $scope.configFileLoading = false; + + + url = "/websites/getDataFromConfigFile"; + + var virtualHost = $("#childDomain").text(); + + + var data = { + virtualHost: virtualHost, + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + + if (response.data.configstatus === 1) { + + //Rewrite rules + + $scope.configurationsBoxRewrite = true; + $scope.rewriteRulesFetched = true; + $scope.couldNotFetchRewriteRules = true; + $scope.rewriteRulesSaved = true; + $scope.couldNotSaveRewriteRules = true; + $scope.fetchedRewriteRules = true; + $scope.saveRewriteRulesBTN = true; + + /// + + $scope.configurationsBox = false; + $scope.configsFetched = false; + $scope.couldNotFetchConfigs = true; + $scope.couldNotConnect = true; + $scope.fetchedConfigsData = false; + $scope.configFileLoading = true; + $scope.configSaved = true; + $scope.couldNotSaveConfigurations = true; + $scope.saveConfigBtn = false; + + + $scope.configData = response.data.configData; + + } else { + + //Rewrite rules + $scope.configurationsBoxRewrite = true; + $scope.rewriteRulesFetched = true; + $scope.couldNotFetchRewriteRules = true; + $scope.rewriteRulesSaved = true; + $scope.couldNotSaveRewriteRules = true; + $scope.fetchedRewriteRules = true; + $scope.saveRewriteRulesBTN = true; + + /// + $scope.configurationsBox = false; + $scope.configsFetched = true; + $scope.couldNotFetchConfigs = false; + $scope.couldNotConnect = true; + $scope.fetchedConfigsData = true; + $scope.configFileLoading = true; + $scope.configSaved = true; + $scope.couldNotSaveConfigurations = true; + + + $scope.errorMessage = response.data.error_message; + + } + + + } + + function cantLoadInitialDatas(response) { + + //Rewrite rules + $scope.configurationsBoxRewrite = true; + $scope.rewriteRulesFetched = true; + $scope.couldNotFetchRewriteRules = true; + $scope.rewriteRulesSaved = true; + $scope.couldNotSaveRewriteRules = true; + $scope.fetchedRewriteRules = true; + $scope.saveRewriteRulesBTN = true; + /// + + $scope.configurationsBox = false; + $scope.configsFetched = true; + $scope.couldNotFetchConfigs = true; + $scope.couldNotConnect = false; + $scope.fetchedConfigsData = true; + $scope.configFileLoading = true; + $scope.configSaved = true; + $scope.couldNotSaveConfigurations = true; + + + } + + + }; + + $scope.saveCongiruations = function () { + + $scope.configFileLoading = false; + + + url = "/websites/saveConfigsToFile"; + + var virtualHost = $("#childDomain").text(); + var configData = $scope.configData; + + + var data = { + virtualHost: virtualHost, + configData: configData, + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + + if (response.data.configstatus == 1) { + + $scope.configurationsBox = false; + $scope.configsFetched = true; + $scope.couldNotFetchConfigs = true; + $scope.couldNotConnect = true; + $scope.fetchedConfigsData = true; + $scope.configFileLoading = true; + $scope.configSaved = false; + $scope.couldNotSaveConfigurations = true; + $scope.saveConfigBtn = true; + + + } else { + $scope.configurationsBox = false; + $scope.configsFetched = true; + $scope.couldNotFetchConfigs = true; + $scope.couldNotConnect = true; + $scope.fetchedConfigsData = false; + $scope.configFileLoading = true; + $scope.configSaved = true; + $scope.couldNotSaveConfigurations = false; + + + $scope.errorMessage = response.data.error_message; + + } + + + } + + function cantLoadInitialDatas(response) { + + $scope.configurationsBox = false; + $scope.configsFetched = true; + $scope.couldNotFetchConfigs = true; + $scope.couldNotConnect = false; + $scope.fetchedConfigsData = true; + $scope.configFileLoading = true; + $scope.configSaved = true; + $scope.couldNotSaveConfigurations = true; + + + } + + + }; + + + ///////// Rewrite Rules + + $scope.configurationsBoxRewrite = true; + $scope.rewriteRulesFetched = true; + $scope.couldNotFetchRewriteRules = true; + $scope.rewriteRulesSaved = true; + $scope.couldNotSaveRewriteRules = true; + $scope.fetchedRewriteRules = true; + $scope.saveRewriteRulesBTN = true; + + $scope.hideRewriteRulesbtn = function () { + $scope.configurationsBoxRewrite = true; + }; + + + $scope.fetchRewriteFules = function () { + + $scope.hidsslconfigs = true; + $scope.configurationsBox = true; + $scope.changePHPView = true; + + + $scope.configurationsBox = true; + $scope.configsFetched = true; + $scope.couldNotFetchConfigs = true; + $scope.couldNotConnect = true; + $scope.fetchedConfigsData = true; + $scope.configFileLoading = true; + $scope.configSaved = true; + $scope.couldNotSaveConfigurations = true; + $scope.saveConfigBtn = true; + + $scope.configFileLoading = false; + + + url = "/websites/getRewriteRules"; + + var virtualHost = $("#childDomain").text(); + + + var data = { + virtualHost: virtualHost, + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + + if (response.data.rewriteStatus == 1) { + + + // from main + + $scope.configurationsBox = true; + $scope.configsFetched = true; + $scope.couldNotFetchConfigs = true; + $scope.fetchedConfigsData = true; + $scope.configSaved = true; + $scope.couldNotSaveConfigurations = true; + $scope.saveConfigBtn = true; + + // main ends + + $scope.configFileLoading = true; + + // + + + $scope.configurationsBoxRewrite = false; + $scope.rewriteRulesFetched = false; + $scope.couldNotFetchRewriteRules = true; + $scope.rewriteRulesSaved = true; + $scope.couldNotSaveRewriteRules = true; + $scope.fetchedRewriteRules = false; + $scope.saveRewriteRulesBTN = false; + $scope.couldNotConnect = true; + + + $scope.rewriteRules = response.data.rewriteRules; + + } else { + // from main + $scope.configurationsBox = true; + $scope.configsFetched = true; + $scope.couldNotFetchConfigs = true; + $scope.fetchedConfigsData = true; + $scope.configFileLoading = true; + $scope.configSaved = true; + $scope.couldNotSaveConfigurations = true; + $scope.saveConfigBtn = true; + // from main + + $scope.configFileLoading = true; + + /// + + $scope.configurationsBoxRewrite = true; + $scope.rewriteRulesFetched = true; + $scope.couldNotFetchRewriteRules = false; + $scope.rewriteRulesSaved = true; + $scope.couldNotSaveRewriteRules = true; + $scope.fetchedRewriteRules = true; + $scope.saveRewriteRulesBTN = true; + $scope.couldNotConnect = true; + + + $scope.errorMessage = response.data.error_message; + + } + + + } + + function cantLoadInitialDatas(response) { + // from main + + $scope.configurationsBox = true; + $scope.configsFetched = true; + $scope.couldNotFetchConfigs = true; + $scope.fetchedConfigsData = true; + $scope.configFileLoading = true; + $scope.configSaved = true; + $scope.couldNotSaveConfigurations = true; + $scope.saveConfigBtn = true; + + // from main + + $scope.configFileLoading = true; + + /// + + $scope.configurationsBoxRewrite = true; + $scope.rewriteRulesFetched = true; + $scope.couldNotFetchRewriteRules = true; + $scope.rewriteRulesSaved = true; + $scope.couldNotSaveRewriteRules = true; + $scope.fetchedRewriteRules = true; + $scope.saveRewriteRulesBTN = true; + + $scope.couldNotConnect = false; + + + } + + + }; + + $scope.saveRewriteRules = function () { + + $scope.configFileLoading = false; + + + url = "/websites/saveRewriteRules"; + + var virtualHost = $("#childDomain").text(); + var rewriteRules = $scope.rewriteRules; + + + var data = { + virtualHost: virtualHost, + rewriteRules: rewriteRules, + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + + if (response.data.rewriteStatus == 1) { + + $scope.configurationsBoxRewrite = false; + $scope.rewriteRulesFetched = true; + $scope.couldNotFetchRewriteRules = true; + $scope.rewriteRulesSaved = false; + $scope.couldNotSaveRewriteRules = true; + $scope.fetchedRewriteRules = true; + $scope.saveRewriteRulesBTN = true; + $scope.configFileLoading = true; + + + } else { + $scope.configurationsBoxRewrite = false; + $scope.rewriteRulesFetched = false; + $scope.couldNotFetchRewriteRules = true; + $scope.rewriteRulesSaved = true; + $scope.couldNotSaveRewriteRules = false; + $scope.fetchedRewriteRules = true; + $scope.saveRewriteRulesBTN = false; + + $scope.configFileLoading = true; + + + $scope.errorMessage = response.data.error_message; + + } + + + } + + function cantLoadInitialDatas(response) { + + $scope.configurationsBoxRewrite = false; + $scope.rewriteRulesFetched = false; + $scope.couldNotFetchRewriteRules = true; + $scope.rewriteRulesSaved = true; + $scope.couldNotSaveRewriteRules = true; + $scope.fetchedRewriteRules = true; + $scope.saveRewriteRulesBTN = false; + + $scope.configFileLoading = true; + + $scope.couldNotConnect = false; + + + } + + + }; + + + //////// SSL Part + + $scope.sslSaved = true; + $scope.couldNotSaveSSL = true; + $scope.hidsslconfigs = true; + $scope.couldNotConnect = true; + + + $scope.hidesslbtn = function () { + $scope.hidsslconfigs = true; + }; + + $scope.addSSL = function () { + $scope.hidsslconfigs = false; + $scope.configurationsBox = true; + $scope.configurationsBoxRewrite = true; + $scope.changePHPView = true; + }; + + + $scope.saveSSL = function () { + + + $scope.configFileLoading = false; + + url = "/websites/saveSSL"; + + var virtualHost = $("#childDomain").text(); + var cert = $scope.cert; + var key = $scope.key; + + + var data = { + virtualHost: virtualHost, + cert: cert, + key: key, + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + + if (response.data.sslStatus === 1) { + + $scope.sslSaved = false; + $scope.couldNotSaveSSL = true; + $scope.couldNotConnect = true; + $scope.configFileLoading = true; + + + } else { + + $scope.sslSaved = true; + $scope.couldNotSaveSSL = false; + $scope.couldNotConnect = true; + $scope.configFileLoading = true; + + $scope.errorMessage = response.data.error_message; + + } + + + } + + function cantLoadInitialDatas(response) { + + $scope.sslSaved = true; + $scope.couldNotSaveSSL = true; + $scope.couldNotConnect = false; + $scope.configFileLoading = true; + + + } + + }; + + + //// Change PHP Master + + $scope.failedToChangePHPMaster = true; + $scope.phpChangedMaster = true; + $scope.couldNotConnect = true; + + $scope.changePHPView = true; + + + $scope.hideChangePHPMaster = function () { + $scope.changePHPView = true; + }; + + $scope.changePHPMaster = function () { + $scope.hidsslconfigs = true; + $scope.configurationsBox = true; + $scope.configurationsBoxRewrite = true; + $scope.changePHPView = false; + }; + + + $scope.changePHPVersionMaster = function (childDomain, phpSelection) { + + // notifcations + + $scope.configFileLoading = false; + + var url = "/websites/changePHP"; + + var data = { + childDomain: $("#childDomain").text(), + phpSelection: $scope.phpSelectionMaster, + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + + + if (response.data.changePHP === 1) { + + $scope.configFileLoading = true; + $scope.websiteDomain = $("#childDomain").text(); + + + // notifcations + + $scope.failedToChangePHPMaster = true; + $scope.phpChangedMaster = false; + $scope.couldNotConnect = true; + + + } else { + + $scope.configFileLoading = true; + $scope.errorMessage = response.data.error_message; + + // notifcations + + $scope.failedToChangePHPMaster = false; + $scope.phpChangedMaster = true; + $scope.couldNotConnect = true; + + } + + + } + + function cantLoadInitialDatas(response) { + + $scope.configFileLoading = true; + + // notifcations + + $scope.failedToChangePHPMaster = true; + $scope.phpChangedMaster = true; + $scope.couldNotConnect = false; + + } + + }; + + + /// Open_basedir protection + + $scope.baseDirLoading = true; + $scope.operationFailed = true; + $scope.operationSuccessfull = true; + $scope.couldNotConnect = true; + $scope.openBaseDirBox = true; + + + $scope.openBaseDirView = function () { + $scope.openBaseDirBox = false; + }; + + $scope.hideOpenBasedir = function () { + $scope.openBaseDirBox = true; + }; + + $scope.applyOpenBasedirChanges = function (childDomain, phpSelection) { + + // notifcations + + $scope.baseDirLoading = false; + $scope.operationFailed = true; + $scope.operationSuccessfull = true; + $scope.couldNotConnect = true; + $scope.openBaseDirBox = false; + + + var url = "/websites/changeOpenBasedir"; + + var data = { + domainName: $("#childDomain").text(), + openBasedirValue: $scope.openBasedirValue + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + + + if (response.data.changeOpenBasedir === 1) { + + $scope.baseDirLoading = true; + $scope.operationFailed = true; + $scope.operationSuccessfull = false; + $scope.couldNotConnect = true; + $scope.openBaseDirBox = false; + + } else { + + $scope.baseDirLoading = true; + $scope.operationFailed = false; + $scope.operationSuccessfull = true; + $scope.couldNotConnect = true; + $scope.openBaseDirBox = false; + + $scope.errorMessage = response.data.error_message; + + } + + + } + + function cantLoadInitialDatas(response) { + + $scope.baseDirLoading = true; + $scope.operationFailed = true; + $scope.operationSuccessfull = true; + $scope.couldNotConnect = false; + $scope.openBaseDirBox = false; + + + } + + } + +}); + From a2e4e4eca54ed10fe591d3737cd67fae3496c40c Mon Sep 17 00:00:00 2001 From: usmannasir Date: Thu, 24 Apr 2025 14:08:07 +0500 Subject: [PATCH 02/16] bug fix: decidedistro check --- plogical/processUtilities.py | 42 ++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/plogical/processUtilities.py b/plogical/processUtilities.py index 52a0c65ea..46cd51473 100755 --- a/plogical/processUtilities.py +++ b/plogical/processUtilities.py @@ -169,27 +169,31 @@ class ProcessUtilities(multi.Thread): distroPath = '/etc/lsb-release' distroPathAlma = '/etc/redhat-release' - if os.path.exists(distroPath): - - ## this is check only - if open(distroPath, 'r').read().find('22.04') > -1: - ProcessUtilities.ubuntu22Check = 1 + # First check if we're on Ubuntu + if os.path.exists('/etc/os-release'): + with open('/etc/os-release', 'r') as f: + content = f.read() + if 'Ubuntu' in content: + if '22.04' in content: + ProcessUtilities.ubuntu22Check = 1 + return ProcessUtilities.ubuntu20 + elif '20.04' in content: + return ProcessUtilities.ubuntu20 + return ProcessUtilities.ubuntu - if open(distroPath, 'r').read().find('20.04') > -1 or open(distroPath, 'r').read().find('22.04'): - return ProcessUtilities.ubuntu20 - return ProcessUtilities.ubuntu - else: - if open('/etc/redhat-release', 'r').read().find('CentOS Linux release 8') > -1 or open('/etc/redhat-release', 'r').read().find('AlmaLinux release 8') > -1 \ - or open('/etc/redhat-release', 'r').read().find('Rocky Linux release 8') > -1 \ - or open('/etc/redhat-release', 'r').read().find('Rocky Linux release 9') > -1 or open('/etc/redhat-release', 'r').read().find('AlmaLinux release 9') > -1 or \ - open('/etc/redhat-release', 'r').read().find('CloudLinux release 9') > -1 or open('/etc/redhat-release', 'r').read().find('CloudLinux release 8') > -1: - ## this is check only - if open(distroPathAlma, 'r').read().find('AlmaLinux release 9') > -1 or open(distroPathAlma, 'r').read().find('Rocky Linux release 9') > -1: - ProcessUtilities.alma9check = 1 - - return ProcessUtilities.cent8 - return ProcessUtilities.centos + # Check for RedHat-based distributions + if os.path.exists(distroPathAlma): + with open(distroPathAlma, 'r') as f: + content = f.read() + if any(x in content for x in ['CentOS Linux release 8', 'AlmaLinux release 8', 'Rocky Linux release 8', + 'Rocky Linux release 9', 'AlmaLinux release 9', 'CloudLinux release 9', + 'CloudLinux release 8']): + if any(x in content for x in ['AlmaLinux release 9', 'Rocky Linux release 9']): + ProcessUtilities.alma9check = 1 + return ProcessUtilities.cent8 + # Default to Ubuntu if no other distribution is detected + return ProcessUtilities.ubuntu @staticmethod def containerCheck(): From 031a8e785184bb4e4ecab49b6b72ee52f2b4cff6 Mon Sep 17 00:00:00 2001 From: usmannasir Date: Sun, 27 Apr 2025 15:28:50 +0500 Subject: [PATCH 03/16] bug fix: to wp install, improved file manager and custom ssl implementation --- .../static/filemanager/css/fileManager.css | 206 ++-- install/install.py | 18 + manageSSL/static/manageSSL/manageSSL.js | 106 +- manageSSL/templates/manageSSL/manageSSL.html | 24 +- .../templates/manageSSL/v2ManageSSL.html | 25 +- manageSSL/urls.py | 1 + manageSSL/views.py | 70 ++ plogical/customAcme.py | 934 ++++++++++++++++++ plogical/renew.py | 209 ++-- plogical/sslUtilities.py | 424 ++++---- plogical/upgrade.py | 20 + 11 files changed, 1578 insertions(+), 459 deletions(-) create mode 100644 plogical/customAcme.py diff --git a/filemanager/static/filemanager/css/fileManager.css b/filemanager/static/filemanager/css/fileManager.css index b69fd4538..2c07d5f34 100755 --- a/filemanager/static/filemanager/css/fileManager.css +++ b/filemanager/static/filemanager/css/fileManager.css @@ -1,5 +1,6 @@ -#logo{ - width: 25%; +#logo { + width: 200px; + height: auto; } /*#navBar{ @@ -8,23 +9,24 @@ background: -o-linear-gradient(#a4dbf5, #8cc5e0); }*/ #navBar { - background: #0daeff; /* Old browsers */ - background: -moz-linear-gradient(-45deg, #0daeff 0%,#3939ad 30%); /* FF3.6-15 */ - background: -webkit-linear-gradient(-45deg, #0daeff 0%,#3939ad 30%); /* Chrome10-25,Safari5.1-6 */ - background: linear-gradient(-45deg, #0daeff 0%,#3939ad 30%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#3939ad', endColorstr='#0daeff',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */ + background: linear-gradient(135deg, #4158D0 0%, #C850C0 46%, #FFCC70 100%); + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + padding: 0.5rem 0; } .navbar-brand { - margin: 0 1rem 0 1rem; + margin: 0 1rem; + color: #fff !important; + font-weight: 500; } -#mainRow{ - margin: 1%; +#mainRow { + margin: 2rem 1.5rem; } -#tableHead{ - background: -moz-linear-gradient(#a4dbf5, #8cc5e0); - background: -webkit-linear-gradient(#a4dbf5, #8cc5e0); - background: -o-linear-gradient(#a4dbf5, #8cc5e0); +#tableHead { + background: #f8f9fa; + color: #2c3e50; + font-weight: 500; + border-radius: 8px 8px 0 0; } #uploadBoxLabel,#htmlEditorLable{ @@ -34,12 +36,23 @@ } .my-drop-zone { - border: dotted 3px lightgray; + border: 2px dashed #cbd5e0; + border-radius: 8px; + padding: 2rem; + background: #f7fafc; + transition: all 0.3s ease; margin-bottom: 2%; } -#queueProg{ +.my-drop-zone:hover { + border-color: #4158D0; + background: #f0f5ff; +} + +#queueProg { margin-bottom: 2%; + height: 6px; + border-radius: 3px; } #htmlEditorContent{ @@ -98,10 +111,14 @@ } a.nav-link { - color: #add8e6; + color: rgba(255,255,255,0.9) !important; + font-weight: 500; + padding: 0.5rem 1rem; + transition: all 0.2s ease; } a.nav-link:hover { - color: #E4F2F7; + color: #ffffff !important; + transform: translateY(-1px); } .point-events { @@ -115,62 +132,141 @@ a.nav-link:hover { border-bottom: none; } .form-control { - padding: 0 .5rem; - border: 1px solid #eeeeee; - color: #777; - font-size: .95em; + padding: 0.5rem 1rem; + border: 1px solid #e2e8f0; + border-radius: 6px; + color: #4a5568; + font-size: 0.95rem; + transition: all 0.3s ease; } - .form-control[readonly] { - background-color: transparent; +.form-control:focus { + border-color: #4158D0; + box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.15); +} +.form-control[readonly] { + background-color: #f8f9fa; } a { - color: #6C6CA4; - text-decoration: none; - background-color: transparent; - -webkit-text-decoration-skip: objects; + color: #4158D0; + transition: color 0.2s ease; } a:hover { - color: #8989B6; - text-decoration: none; - background-color: transparent; - -webkit-text-decoration-skip: objects; + color: #C850C0; } -#tableHead { - background: #8989B6; - color: #E1E1EC; +.table { + background: white; + border-radius: 8px; + box-shadow: 0 0 20px rgba(0,0,0,0.05); + margin-bottom: 2rem; } .table td, .table th { - padding: .15em; - vertical-align: top; - border-top: 1px solid #e9ecef; + padding: .75rem; + vertical-align: middle; + border-top: 1px solid #edf2f7; } .table thead th { - vertical-align: bottom; - border-bottom: 1px solid #e9ecef; - font-weight: 400; + border-bottom: 2px solid #edf2f7; + font-weight: 600; + font-size: 0.875rem; + text-transform: uppercase; + letter-spacing: 0.5px; } .table td { - font-size: 14px; - color: #666666; + font-size: 0.9rem; + color: #4a5568; } .list-group-item { - padding: .2em 1.25rem; + padding: 0.75rem 1.25rem; + border: 1px solid #edf2f7; + margin-bottom: -1px; + background-color: white; + transition: all 0.2s ease; +} +.list-group-item:hover { + background-color: #f7fafc; } -i.fa.fa-file { - color: #6C6CA4 !important; -} -i.fa.fa-minus { - color: #6C6CA4 !important; -} +i.fa.fa-file, +i.fa.fa-minus, i.fa.fa-plus { - color: #6C6CA4 !important; -} -.list-group-item { - background-color: transparent; + color: #4158D0 !important; } .bg-lightgray { - background: #F9F9FA; + background: #f8f9fa; + border-radius: 8px; +} + +.progress-bar { + background: linear-gradient(135deg, #4158D0 0%, #C850C0 100%); +} + +/* Card styles */ +.card { + border: none; + border-radius: 8px; + box-shadow: 0 0 20px rgba(0,0,0,0.05); +} + +.card-header { + background: #f8f9fa; + border-bottom: 1px solid #edf2f7; + padding: 1rem 1.25rem; + font-weight: 500; + border-radius: 8px 8px 0 0; +} + +/* Navigation link styles */ +a.nav-link { + color: rgba(255,255,255,0.9) !important; + font-weight: 500; + padding: 0.5rem 1rem; + transition: all 0.2s ease; +} + +a.nav-link:hover { + color: #ffffff !important; + transform: translateY(-1px); +} + +/* Utility classes */ +.bg-lightgray { + background: #f8f9fa; + border-radius: 8px; +} + +/* Custom scrollbar */ +::-webkit-scrollbar { + width: 8px; +} + +::-webkit-scrollbar-track { + background: #f1f1f1; +} + +::-webkit-scrollbar-thumb { + background: #c8c8c8; + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: #a8a8a8; +} + +.btn { + padding: 0.5rem 1rem; + border-radius: 6px; + font-weight: 500; + transition: all 0.3s ease; +} + +.btn-primary { + background: linear-gradient(135deg, #4158D0 0%, #C850C0 100%); + border: none; +} + +.btn-primary:hover { + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(65, 88, 208, 0.15); } diff --git a/install/install.py b/install/install.py index dec901953..42603eb43 100755 --- a/install/install.py +++ b/install/install.py @@ -2329,8 +2329,26 @@ milter_default_action = accept command = "chmod +x /usr/local/CyberCP/cli/cyberPanel.py" preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + def setupPHPSymlink(self): + try: + # Remove existing PHP symlink if it exists + if os.path.exists('/usr/bin/php'): + os.remove('/usr/bin/php') + + # Create symlink to PHP 8.0 + command = 'ln -s /usr/local/lsws/lsphp80/bin/php /usr/bin/php' + preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + + logging.InstallLog.writeToFile("[setupPHPSymlink] PHP symlink created successfully.") + + except OSError as msg: + logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [setupPHPSymlink]") + return 0 + def setupPHPAndComposer(self): try: + # First setup the PHP symlink + self.setupPHPSymlink() if self.distro == ubuntu: if not os.access('/usr/local/lsws/lsphp70/bin/php', os.R_OK): diff --git a/manageSSL/static/manageSSL/manageSSL.js b/manageSSL/static/manageSSL/manageSSL.js index 0a4e406d2..0f3de8365 100755 --- a/manageSSL/static/manageSSL/manageSSL.js +++ b/manageSSL/static/manageSSL/manageSSL.js @@ -12,21 +12,54 @@ app.controller('sslIssueCtrl', function ($scope, $http) { $scope.canNotIssue = true; $scope.sslIssued = true; $scope.couldNotConnect = true; + $scope.sslDetails = null; $scope.showbtn = function () { $scope.issueSSLBtn = false; + $scope.fetchSSLDetails(); + }; + + $scope.fetchSSLDetails = function() { + if (!$scope.virtualHost) return; + + var url = "/manageSSL/getSSLDetails"; + var data = { + virtualHost: $scope.virtualHost + }; + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + $http.post(url, data, config).then(function(response) { + if (response.data.status === 1) { + $scope.sslDetails = response.data; + } else { + $scope.sslDetails = null; + new PNotify({ + title: 'Error', + text: response.data.error_message, + type: 'error' + }); + } + }, function(response) { + $scope.sslDetails = null; + new PNotify({ + title: 'Error', + text: 'Could not fetch SSL details', + type: 'error' + }); + }); }; $scope.issueSSL = function () { $scope.manageSSLLoading = false; var url = "/manageSSL/issueSSL"; - - var data = { virtualHost: $scope.virtualHost, }; - var config = { headers: { 'X-CSRFToken': getCookie('csrftoken') @@ -35,22 +68,16 @@ app.controller('sslIssueCtrl', function ($scope, $http) { $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); - function ListInitialDatas(response) { - - if (response.data.SSL == 1) { - $scope.sslIssueCtrl = true; $scope.manageSSLLoading = true; $scope.issueSSLBtn = false; $scope.canNotIssue = true; $scope.sslIssued = false; $scope.couldNotConnect = true; - $scope.sslDomain = $scope.virtualHost; - - + $scope.fetchSSLDetails(); // Refresh SSL details after issuing } else { $scope.sslIssueCtrl = true; $scope.manageSSLLoading = true; @@ -59,10 +86,7 @@ app.controller('sslIssueCtrl', function ($scope, $http) { $scope.sslIssued = true; $scope.couldNotConnect = true; $scope.errorMessage = response.data.error_message; - } - - } function cantLoadInitialDatas(response) { @@ -72,10 +96,7 @@ app.controller('sslIssueCtrl', function ($scope, $http) { $scope.canNotIssue = true; $scope.sslIssued = true; $scope.couldNotConnect = false; - } - - }; }); @@ -85,21 +106,54 @@ app.controller('sslIssueCtrl', function ($scope, $http) { app.controller('sslIssueCtrlV2', function ($scope, $http) { $scope.manageSSLLoading = true; + $scope.sslDetails = null; $scope.showbtn = function () { $scope.issueSSLBtn = false; + $scope.fetchSSLDetails(); + }; + + $scope.fetchSSLDetails = function() { + if (!$scope.virtualHost) return; + + var url = "/manageSSL/getSSLDetails"; + var data = { + virtualHost: $scope.virtualHost + }; + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + $http.post(url, data, config).then(function(response) { + if (response.data.status === 1) { + $scope.sslDetails = response.data; + } else { + $scope.sslDetails = null; + new PNotify({ + title: 'Error', + text: response.data.error_message, + type: 'error' + }); + } + }, function(response) { + $scope.sslDetails = null; + new PNotify({ + title: 'Error', + text: 'Could not fetch SSL details', + type: 'error' + }); + }); }; $scope.issueSSL = function () { $scope.manageSSLLoading = false; var url = "/manageSSL/v2IssueSSL"; - - var data = { virtualHost: $scope.virtualHost, }; - var config = { headers: { 'X-CSRFToken': getCookie('csrftoken') @@ -108,24 +162,16 @@ app.controller('sslIssueCtrlV2', function ($scope, $http) { $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); - function ListInitialDatas(response) { - $scope.manageSSLLoading = true; - - if (response.data.SSL === 1) { - $scope.sslStatus = 'Issued.'; $scope.sslLogs = response.data.sslLogs; - + $scope.fetchSSLDetails(); // Refresh SSL details after issuing } else { $scope.sslStatus = 'Failed.'; $scope.sslLogs = response.data.sslLogs; - } - - } function cantLoadInitialDatas(response) { @@ -135,12 +181,8 @@ app.controller('sslIssueCtrlV2', function ($scope, $http) { $scope.canNotIssue = true; $scope.sslIssued = true; $scope.couldNotConnect = false; - } - - }; - }); /* Java script code to issue SSL V2 ends here */ diff --git a/manageSSL/templates/manageSSL/manageSSL.html b/manageSSL/templates/manageSSL/manageSSL.html index 2b3f41e78..8efaf8311 100755 --- a/manageSSL/templates/manageSSL/manageSSL.html +++ b/manageSSL/templates/manageSSL/manageSSL.html @@ -14,7 +14,7 @@ style="height: 23px;line-height: 21px;" class="btn btn-border btn-alt border-red btn-link font-red" title="">{% trans "SSL Docs" %} -

{% trans "This page can be used to issue Let’s Encrypt SSL for existing websites on server." %}

+

{% trans "This page can be used to issue Let's Encrypt SSL for existing websites on server." %}

@@ -39,6 +39,28 @@
+
+
+
+
+

SSL Details

+
+
+
+

Status: Active

+

Issued By: {$ sslDetails.authority $}

+

Expiry Date: {$ sslDetails.expiryDate $}

+

Days Remaining: {$ sslDetails.days $}

+
+
+

Status: No SSL Certificate

+

Error: {$ sslDetails.error_message $}

+
+
+
+
+
+
diff --git a/manageSSL/templates/manageSSL/v2ManageSSL.html b/manageSSL/templates/manageSSL/v2ManageSSL.html index 36440c3f4..182432207 100755 --- a/manageSSL/templates/manageSSL/v2ManageSSL.html +++ b/manageSSL/templates/manageSSL/v2ManageSSL.html @@ -66,7 +66,7 @@
+
+
+ +
- {% trans "Clone/Staging" %} - {% trans "Set up SSH/SFTP Access" %} - {% trans "Stress Test" %} - +
+ + +
-
-
+ +
+ + + + + + + + + + + + + + + + + + + +
TypeIP AddressTimeResourceSize
+
+
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{% trans "Resource" %}{% trans "Usage" %}{% trans "Allowed" %}
{% trans "FTP" %}{{ ftpUsed }}{{ ftpTotal }}
{% trans "Databases" %}{{ databasesUsed }}{{ databasesTotal }}
{% trans "Disk Usage" %}{{ diskInMB }} (MB){{ diskInMBTotal }} (MB)
{% trans "Bandwidth Usage" %}{{ bwInMB }} (MB){{ bwInMBTotal }} (MB)
-
-
-
-
- {% if viewSSL == 1 %} -
-
-

{{ authority }}

-

Your SSL will expire in {{ days }} days.

-
-
- {% endif %} -
-

- {% trans "Disk Usage" %} -

-
-
-
-
{{ diskUsage }}%
-
-
-

- {% trans "Bandwidth Usage" %} -

-
-
-
-
{{ bwUsage }}%
-
-
+
+ +
+ +
+ +
+ + +
+ + +
+ +
+
+ +
+
+
+
+
+ +
+
+

+ {% trans "Domains" %} +

+
+
+ + + + + + + + + + +
+
+ +
+ +
+ +
+
+ +

+
+
+
+ +
+ +
+ +
+
{% trans "Invalid Domain (Note: You don't need to add 'http' or 'https')" %}
+
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
-
+ +
+ +
+ + +
+
+ +
+ +
+ +
+

{$ currentStatus $}

+
+ +
+
+ 70% Complete +
+
+ +
+

{% trans "Error message:" %} {$ errorMessage $}

+
+ +
+

{% trans "Website succesfully created." %}

+
+ + +
+

{% trans "Could not connect to server. Please refresh this page." %}

+
+ + +
+
+ +
+ +
+ +
+
+ + +
-
-
-
+ -
-
-

- {% trans "Logs" %} -

+ -
-
- - +
-
-
-
-

{% trans "Logs Fetched" %}

-
-
-

{% trans "Could not fetch logs, see the logs file through command line. Error message:" %} - {$ errorMessage $}

-
-
-

{% trans "Could not connect to server. Please refresh this page." %}

-
-
-
- -
-
- -
+ -
- - -
- -
- - - - - - - - - - - - - - - - - - - -
TypeIP AddressTimeResourceSize
-
+
+

{% trans "PHP Version Changed to:" %} {$ changedPHPVersion $}

+
+ +
+

{% trans "Deleted:" %} {$ deletedDomain $}

+
+ +
+

{% trans "SSL Issued:" %} {$ sslDomainIssued $}

+
+ +
+

{% trans "Changes applied successfully." %}

+
+ + +
+

{$ errorMessage $}

+
+ + +
+

{% trans "Could not connect to server. Please refresh this page." %}

+
+ + +
+ +
+
- -
- -
- -
- -
- - -
- - -
- -
-
- -
-
-
-
-
- -
-
-

- {% trans "Domains" %} -

-
-
- - - - - - - - - - -
-
- -
- -
- -
-
- -

-
-
-
- -
- -
- -
-
{% trans "Invalid Domain (Note: You don't need to add 'http' or 'https')" %}
-
- -
- -
- -
-
- -
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
- -
- -
- - -
-
- -
- -
- -
-

{$ currentStatus $}

-
- -
-
- 70% Complete -
-
- -
-

{% trans "Error message:" %} {$ errorMessage $}

-
- -
-

{% trans "Website succesfully created." %}

-
- - -
-

{% trans "Could not connect to server. Please refresh this page." %}

-
- - -
-
- -
- -
- -
-
- - -
-
- - - - - -
- -
- - -
-

{% trans "PHP Version Changed to:" %} {$ changedPHPVersion $}

-
- -
-

{% trans "Deleted:" %} {$ deletedDomain $}

-
- -
-

{% trans "SSL Issued:" %} {$ sslDomainIssued $}

-
- -
-

{% trans "Changes applied successfully." %}

-
- - -
-

{$ errorMessage $}

-
- - -
-

{% trans "Could not connect to server. Please refresh this page." %}

-
- - -
- -
+
+
-
-
-

- {% trans "Configurations" %} -

-
-
- +
+
+

+ {% trans "Configurations" %} +

+
+
+ - + - + - + - + - + -
+
-
+ -
-

{% trans "SSL Saved" %}

+
+

{% trans "SSL Saved" %}

+
+ + +
+

{% trans "Could not save SSL. Error message:" %} {$ errorMessage $}

+
+ + +
+

{% trans "Could not connect to server. Please refresh this page." %}

+
+ + +
+
+
- - -
-

{% trans "Could not save SSL. Error message:" %} {$ errorMessage $}

+
+
- - -
-

{% trans "Could not connect to server. Please refresh this page." %}

+
+
+
- -
-
- -
-
- -
-
- -
+
+ +
+
+
+ +
-
- -
- -
+ + + + + + +
+
+
+

{% trans "Current configuration in the file fetched." %}

+
+ +
+

{% trans "Could not fetch current configuration. Error message:" %} {$ + errorMessage $}

+
+ +
+

{% trans "Could not connect to server. Please refresh this page." %}

+
+ +
+

{% trans "Configurations saved." %}

+
+ +
+

{% trans "Could not fetch current configuration. Error message:" %} {$ + errorMessage $}

+
+ +
+
+
- -
- - - - - - - -
-
-
-

{% trans "Current configuration in the file fetched." %}

+
+
+
-
-

{% trans "Could not fetch current configuration. Error message:" %} {$ - errorMessage $}

+
+ +
+
+
+ +
-
-

{% trans "Could not connect to server. Please refresh this page." %}

-
+ -
-

{% trans "Configurations saved." %}

-
+
+
+
+

{% trans "It is not required to modify rules if you are using OpenLiteSpeed." %} + Click + to read more about whats changed in rewrite + rules from v1.8 onwards.

+
-
-

{% trans "Could not fetch current configuration. Error message:" %} {$ - errorMessage $}

-
- -
-
- -
-
- -
-
- -
- -
- -
-
-
-
- - - -
-
-
-

{% trans "It is not required to modify rules if you are using OpenLiteSpeed." %} - Click - to read more about whats changed in rewrite - rules from v1.8 onwards.

-
- - - -
- -
- -
-
- -
- -
-

{% trans "Could not fetch current rewrite rules. Error message:" %} {$ - errorMessage $}

-
- -
-

{% trans "Could not connect to server. Please refresh this page." %}

-
- -
-

{% trans "Configurations saved." %}

-
- -
-

{% trans "Could not save rewrite rules. Error message:" %} {$ errorMessage - $}

-
+
-
- -
-
- -
-
- -
- -
- -
-
- -
- -
- - - -
- -
- - -
- +
- + + + +
- -
-

-
- -
- - -
- -
- -
-
- - -
- - -
-
-

{% trans "Failed to change PHP version. Error message:" %} {$ - errorMessage $}

-
- -
-

{% trans "PHP successfully changed for: " %} {$ websiteDomain - $}

-
- -
-

{% trans "Could not connect to server. Please refresh this page." %}

-
-
-
+ +
+

{% trans "Could not fetch current rewrite rules. Error message:" %} {$ + errorMessage $}

+
+ +
+

{% trans "Could not connect to server. Please refresh this page." %}

+
+ +
+

{% trans "Configurations saved." %}

+
+ +
+

{% trans "Could not save rewrite rules. Error message:" %} {$ errorMessage + $}

+
+ +
+
+ +
+
+ +
+
+ +
+ +
+ +
+
+ +
+ + + +
+ +
+ + +
+ +
+ +
+ +
+

+
+ +
+ + +
+ +
+ +
+
+ + +
+ + +
+
+

{% trans "Failed to change PHP version. Error message:" %} {$ + errorMessage $}

+
+ +
+

{% trans "PHP successfully changed for: " %} {$ websiteDomain + $}

+
+ +
+

{% trans "Could not connect to server. Please refresh this page." %}

+
+
+
+ +
+
+
+
-
-
-

- {% trans "Files" %} -

-
-
+
+
+

+ {% trans "Files" %} +

+
+
+ + + + + + {% if ftp %} + + {% endif %} - {% if ftp %} + -
- - - - - {% trans "Create FTP Acct" %} - +
+
+
+ +
+ +
+ +
+ +
+ +
+ +
-
- - - - - {% trans "Delete FTP Acct" %} - + +
+ +
+ +
+
+
+ + +
+
+

{% trans "Error message:" %} {$ errorMessage $}

+
+ +
+

{% trans "Changes successfully saved." %}

+
+ +
+

{% trans "Could not connect to server. Please refresh this page." %}

+
+
+
- {% endif %} - - - -
- -
- -
- -
- -
- -
- -
- -
-
- - -
- -
- -
-
-
- - -
-
-

{% trans "Error message:" %} {$ errorMessage $}

-
- -
-

{% trans "Changes successfully saved." %}

-
- -
-

{% trans "Could not connect to server. Please refresh this page." %}

-
-
- -
- - - -
- - - +
+ + + +
+
- {% if email %} + {% if email %} - {% if marketingStatus %} + {% if marketingStatus %} -
-
-

- {% trans "Email Marketing" %} -

- -
-
- - - - - - - - - + {% endif %} -
-
-

- {% trans "Application Installer" %} +
+

+ {% trans "Application Installer" %} -

+

- {% else %} From c97791b3df2abb5f6b287301538ade40793c2340 Mon Sep 17 00:00:00 2001 From: usmannasir Date: Fri, 2 May 2025 12:40:09 +0500 Subject: [PATCH 09/16] bug fix: with website search and wpsites --- plogical/acl.py | 32 +++++++++++++--- .../websiteFunctions/listWebsites.html | 2 +- websiteFunctions/website.py | 38 +++++++++++++------ 3 files changed, 53 insertions(+), 19 deletions(-) diff --git a/plogical/acl.py b/plogical/acl.py index f0aee9150..a9788791b 100644 --- a/plogical/acl.py +++ b/plogical/acl.py @@ -14,7 +14,7 @@ django.setup() from loginSystem.models import Administrator, ACL from django.shortcuts import HttpResponse from packages.models import Package -from websiteFunctions.models import Websites, ChildDomains, aliasDomains, DockerSites +from websiteFunctions.models import Websites, ChildDomains, aliasDomains, DockerSites, WPSites import json from subprocess import call, CalledProcessError from shlex import split @@ -582,24 +582,44 @@ class ACLManager: @staticmethod def searchWebsiteObjects(currentACL, userID, searchTerm): - if currentACL['admin'] == 1: - return Websites.objects.filter(domain__istartswith=searchTerm) + # Get websites that match the search term + websites = Websites.objects.filter(domain__istartswith=searchTerm) + # Get WordPress sites that match the search term + wp_sites = WPSites.objects.filter(title__icontains=searchTerm) + # Add WordPress sites' parent websites to the results + for wp in wp_sites: + if wp.owner not in websites: + websites = websites | Websites.objects.filter(pk=wp.owner.pk) + return websites else: websiteList = [] admin = Administrator.objects.get(pk=userID) + # Get websites that match the search term websites = admin.websites_set.filter(domain__istartswith=searchTerm) - for items in websites: websiteList.append(items) - admins = Administrator.objects.filter(owner=admin.pk) + # Get WordPress sites that match the search term + wp_sites = WPSites.objects.filter(title__icontains=searchTerm) + for wp in wp_sites: + if wp.owner.admin == admin and wp.owner not in websiteList: + websiteList.append(wp.owner) + admins = Administrator.objects.filter(owner=admin.pk) for items in admins: + # Get websites that match the search term webs = items.websites_set.filter(domain__istartswith=searchTerm) for web in webs: - websiteList.append(web) + if web not in websiteList: + websiteList.append(web) + + # Get WordPress sites that match the search term + wp_sites = WPSites.objects.filter(title__icontains=searchTerm) + for wp in wp_sites: + if wp.owner.admin == items and wp.owner not in websiteList: + websiteList.append(wp.owner) return websiteList diff --git a/websiteFunctions/templates/websiteFunctions/listWebsites.html b/websiteFunctions/templates/websiteFunctions/listWebsites.html index 44fbaf468..4e09feade 100755 --- a/websiteFunctions/templates/websiteFunctions/listWebsites.html +++ b/websiteFunctions/templates/websiteFunctions/listWebsites.html @@ -66,7 +66,7 @@
-
diff --git a/websiteFunctions/website.py b/websiteFunctions/website.py index ab607dac1..a57cff62b 100755 --- a/websiteFunctions/website.py +++ b/websiteFunctions/website.py @@ -4566,8 +4566,7 @@ StrictHostKeyChecking no websites = ACLManager.searchWebsiteObjects(currentlACL, userID, searchTerm) - json_data = "[" - checker = 0 + json_data = [] try: ipFile = "/etc/cyberpanel/machineIP" @@ -4598,19 +4597,34 @@ StrictHostKeyChecking no PHPVersionActual = 'PHP 8.1' diskUsed = "%sMB" % str(DiskUsage) - dic = {'domain': items.domain, 'adminEmail': items.adminEmail, 'ipAddress': ipAddress, - 'admin': items.admin.userName, 'package': items.package.packageName, 'state': state, - 'diskUsed': diskUsed, 'phpVersion': PHPVersionActual} - if checker == 0: - json_data = json_data + json.dumps(dic) - checker = 1 - else: - json_data = json_data + ',' + json.dumps(dic) + # Get WordPress sites for this website + wp_sites = [] + try: + wp_sites = WPSites.objects.filter(owner=items) + wp_sites = [{ + 'id': wp.id, + 'title': wp.title, + 'url': wp.FinalURL, + 'version': wp.version if hasattr(wp, 'version') else 'Unknown', + 'phpVersion': wp.phpVersion if hasattr(wp, 'phpVersion') else 'Unknown' + } for wp in wp_sites] + except: + pass - json_data = json_data + ']' + json_data.append({ + 'domain': items.domain, + 'adminEmail': items.adminEmail, + 'ipAddress': ipAddress, + 'admin': items.admin.userName, + 'package': items.package.packageName, + 'state': state, + 'diskUsed': diskUsed, + 'phpVersion': PHPVersionActual, + 'wp_sites': wp_sites + }) - return json_data + return json.dumps(json_data) def findWebsitesJson(self, currentACL, userID, pageNumber): finalPageNumber = ((pageNumber * 10)) - 10 From 4e70b379c233fc2c997709d2db4faa4685a276b8 Mon Sep 17 00:00:00 2001 From: usmannasir Date: Fri, 2 May 2025 15:33:20 +0500 Subject: [PATCH 10/16] bug fix: wp scan button --- .../websiteFunctions/WPsitesList.html | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/websiteFunctions/templates/websiteFunctions/WPsitesList.html b/websiteFunctions/templates/websiteFunctions/WPsitesList.html index 14298a370..0a8f4f7fc 100644 --- a/websiteFunctions/templates/websiteFunctions/WPsitesList.html +++ b/websiteFunctions/templates/websiteFunctions/WPsitesList.html @@ -87,6 +87,42 @@ } }; + $scope.ScanWordpressSite = function () { + $('#cyberPanelLoading').show(); + var url = "{% url 'ScanWordpressSite' %}"; + var data = {}; + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + $http.post(url, data, config).then(function(response) { + $('#cyberPanelLoading').hide(); + if (response.data.status === 1) { + new PNotify({ + title: 'Success!', + text: 'WordPress sites scanned successfully!', + type: 'success' + }); + location.reload(); + } else { + new PNotify({ + title: 'Operation Failed!', + text: response.data.error_message, + type: 'error' + }); + } + }, function(response) { + $('#cyberPanelLoading').hide(); + new PNotify({ + title: 'Operation Failed!', + text: response.data.error_message, + type: 'error' + }); + }); + }; + $scope.updateSetting = function(site, setting) { var settingMap = { 'search-indexing': 'searchIndex', @@ -355,6 +391,7 @@

{% trans "WordPress Sites" %}

+ Install WordPress
@@ -602,6 +639,4 @@ margin-left: 4px; } -{% endblock content %} - - +{% endblock content %} \ No newline at end of file From 12ba18bac0edbd7097263f41b4b02ea4d8d5c942 Mon Sep 17 00:00:00 2001 From: usmannasir Date: Fri, 2 May 2025 15:44:36 +0500 Subject: [PATCH 11/16] resource usage graphs --- websiteFunctions/resource_monitoring.py | 52 ++++++ .../static/js/resource-monitoring.js | 143 ++++++++++++++++ .../static/js/websiteFunctions.js | 162 ++++++++++++++++++ .../templates/websiteFunctions/website.html | 32 +++- websiteFunctions/urls.py | 2 + websiteFunctions/views.py | 44 ++++- 6 files changed, 432 insertions(+), 3 deletions(-) create mode 100644 websiteFunctions/resource_monitoring.py create mode 100644 websiteFunctions/static/js/resource-monitoring.js create mode 100644 websiteFunctions/static/js/websiteFunctions.js diff --git a/websiteFunctions/resource_monitoring.py b/websiteFunctions/resource_monitoring.py new file mode 100644 index 000000000..243dbc805 --- /dev/null +++ b/websiteFunctions/resource_monitoring.py @@ -0,0 +1,52 @@ +import psutil +import os +from plogical.processUtilities import ProcessUtilities +from plogical.acl import ACLManager +import plogical.CyberCPLogFileWriter as logging + +def get_website_resource_usage(externalApp): + try: + user = externalApp + if not user: + return {'status': 0, 'error_message': 'User not found'} + + # Get CPU and Memory usage using ps command + command = f"ps -u {user} -o pcpu,pmem | grep -v CPU | awk '{{cpu += $1; mem += $2}} END {{print cpu, mem}}'" + result = ProcessUtilities.outputExecutioner(command) + + try: + cpu_percent, memory_percent = map(float, result.split()) + except: + cpu_percent = 0 + memory_percent = 0 + + # Get disk usage using du command + website_path = f"/home/{user}/public_html" + if os.path.exists(website_path): + # Get disk usage in MB + command = f"du -sm {website_path} | cut -f1" + disk_used = float(ProcessUtilities.outputExecutioner(command)) + + # Get total disk space + command = f"df -m {website_path} | tail -1 | awk '{{print $2}}'" + disk_total = float(ProcessUtilities.outputExecutioner(command)) + + # Calculate percentage + disk_percent = (disk_used / disk_total) * 100 if disk_total > 0 else 0 + else: + disk_used = 0 + disk_total = 0 + disk_percent = 0 + + return { + 'status': 1, + 'cpu_usage': round(cpu_percent, 2), + 'memory_usage': round(memory_percent, 2), + 'disk_used': round(disk_used, 2), + 'disk_total': round(disk_total, 2), + 'disk_percent': round(disk_percent, 2) + } + + except BaseException as msg: + logging.CyberCPLogFileWriter.writeToFile(f'Error in get_website_resource_usage: {str(msg)}') + return {'status': 0, 'error_message': str(msg)} \ No newline at end of file diff --git a/websiteFunctions/static/js/resource-monitoring.js b/websiteFunctions/static/js/resource-monitoring.js new file mode 100644 index 000000000..6b0f3ed87 --- /dev/null +++ b/websiteFunctions/static/js/resource-monitoring.js @@ -0,0 +1,143 @@ +// Resource Monitoring +let cpuChart, memoryChart, diskChart; +let cpuData = [], memoryData = [], diskData = []; +const maxDataPoints = 30; + +function initializeCharts() { + const chartOptions = { + responsive: true, + maintainAspectRatio: false, + scales: { + y: { + beginAtZero: true, + max: 100, + ticks: { + callback: function(value) { + return value + '%'; + } + } + } + }, + animation: { + duration: 750 + } + }; + + // CPU Chart + const cpuCtx = document.getElementById('cpuChart').getContext('2d'); + cpuChart = new Chart(cpuCtx, { + type: 'line', + data: { + labels: [], + datasets: [{ + label: 'CPU Usage (%)', + data: [], + borderColor: '#2563eb', + backgroundColor: 'rgba(37, 99, 235, 0.1)', + borderWidth: 2, + fill: true, + tension: 0.4 + }] + }, + options: chartOptions + }); + + // Memory Chart + const memoryCtx = document.getElementById('memoryChart').getContext('2d'); + memoryChart = new Chart(memoryCtx, { + type: 'line', + data: { + labels: [], + datasets: [{ + label: 'Memory Usage (%)', + data: [], + borderColor: '#00b894', + backgroundColor: 'rgba(0, 184, 148, 0.1)', + borderWidth: 2, + fill: true, + tension: 0.4 + }] + }, + options: chartOptions + }); + + // Disk Chart + const diskCtx = document.getElementById('diskChart').getContext('2d'); + diskChart = new Chart(diskCtx, { + type: 'line', + data: { + labels: [], + datasets: [{ + label: 'Disk Usage (%)', + data: [], + borderColor: '#ff9800', + backgroundColor: 'rgba(255, 152, 0, 0.1)', + borderWidth: 2, + fill: true, + tension: 0.4 + }] + }, + options: chartOptions + }); +} + +function updateCharts(data) { + const now = new Date(); + const timeLabel = now.toLocaleTimeString(); + + // Update CPU Chart + cpuData.push(data.cpu_usage); + if (cpuData.length > maxDataPoints) cpuData.shift(); + cpuChart.data.labels.push(timeLabel); + if (cpuChart.data.labels.length > maxDataPoints) cpuChart.data.labels.shift(); + cpuChart.data.datasets[0].data = cpuData; + cpuChart.update('none'); // Use 'none' mode for better performance + + // Update Memory Chart + memoryData.push(data.memory_usage); + if (memoryData.length > maxDataPoints) memoryData.shift(); + memoryChart.data.labels.push(timeLabel); + if (memoryChart.data.labels.length > maxDataPoints) memoryChart.data.labels.shift(); + memoryChart.data.datasets[0].data = memoryData; + memoryChart.update('none'); + + // Update Disk Chart + diskData.push(data.disk_percent); + if (diskData.length > maxDataPoints) diskData.shift(); + diskChart.data.labels.push(timeLabel); + if (diskChart.data.labels.length > maxDataPoints) diskChart.data.labels.shift(); + diskChart.data.datasets[0].data = diskData; + diskChart.update('none'); +} + +function fetchResourceUsage() { + $.ajax({ + url: '/websites/get_website_resources/', + type: 'POST', + data: JSON.stringify({ + 'domain': $('#domainNamePage').text().trim() + }), + contentType: 'application/json', + success: function(data) { + if (data.status === 1) { + updateCharts(data); + } else { + console.error('Error fetching resource data:', data.error_message); + } + }, + error: function(xhr, status, error) { + console.error('Failed to fetch resource usage:', error); + } + }); +} + +// Initialize charts when the page loads +$(document).ready(function() { + if (document.getElementById('cpuChart')) { + initializeCharts(); + // Fetch resource usage every 5 seconds + setInterval(fetchResourceUsage, 5000); + // Initial fetch + fetchResourceUsage(); + } +}); \ No newline at end of file diff --git a/websiteFunctions/static/js/websiteFunctions.js b/websiteFunctions/static/js/websiteFunctions.js new file mode 100644 index 000000000..c7c4eca13 --- /dev/null +++ b/websiteFunctions/static/js/websiteFunctions.js @@ -0,0 +1,162 @@ +// Resource Monitoring +let cpuChart, memoryChart, diskChart; +let cpuData = [], memoryData = [], diskData = []; +const maxDataPoints = 30; + +function initializeCharts() { + // CPU Chart + const cpuCtx = document.getElementById('cpuChart').getContext('2d'); + cpuChart = new Chart(cpuCtx, { + type: 'line', + data: { + labels: [], + datasets: [{ + label: 'CPU Usage (%)', + data: [], + borderColor: '#2563eb', + backgroundColor: 'rgba(37, 99, 235, 0.1)', + borderWidth: 2, + fill: true, + tension: 0.4 + }] + }, + options: { + responsive: true, + maintainAspectRatio: false, + scales: { + y: { + beginAtZero: true, + max: 100, + ticks: { + callback: function(value) { + return value + '%'; + } + } + } + } + } + }); + + // Memory Chart + const memoryCtx = document.getElementById('memoryChart').getContext('2d'); + memoryChart = new Chart(memoryCtx, { + type: 'line', + data: { + labels: [], + datasets: [{ + label: 'Memory Usage (%)', + data: [], + borderColor: '#00b894', + backgroundColor: 'rgba(0, 184, 148, 0.1)', + borderWidth: 2, + fill: true, + tension: 0.4 + }] + }, + options: { + responsive: true, + maintainAspectRatio: false, + scales: { + y: { + beginAtZero: true, + max: 100, + ticks: { + callback: function(value) { + return value + '%'; + } + } + } + } + } + }); + + // Disk Chart + const diskCtx = document.getElementById('diskChart').getContext('2d'); + diskChart = new Chart(diskCtx, { + type: 'line', + data: { + labels: [], + datasets: [{ + label: 'Disk Usage (%)', + data: [], + borderColor: '#ff9800', + backgroundColor: 'rgba(255, 152, 0, 0.1)', + borderWidth: 2, + fill: true, + tension: 0.4 + }] + }, + options: { + responsive: true, + maintainAspectRatio: false, + scales: { + y: { + beginAtZero: true, + max: 100, + ticks: { + callback: function(value) { + return value + '%'; + } + } + } + } + } + }); +} + +function updateCharts(data) { + const now = new Date(); + const timeLabel = now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds(); + + // Update CPU Chart + cpuData.push(data.cpu_usage); + if (cpuData.length > maxDataPoints) cpuData.shift(); + cpuChart.data.labels.push(timeLabel); + if (cpuChart.data.labels.length > maxDataPoints) cpuChart.data.labels.shift(); + cpuChart.data.datasets[0].data = cpuData; + cpuChart.update(); + + // Update Memory Chart + memoryData.push(data.memory_usage); + if (memoryData.length > maxDataPoints) memoryData.shift(); + memoryChart.data.labels.push(timeLabel); + if (memoryChart.data.labels.length > maxDataPoints) memoryChart.data.labels.shift(); + memoryChart.data.datasets[0].data = memoryData; + memoryChart.update(); + + // Update Disk Chart + diskData.push(data.disk_percent); + if (diskData.length > maxDataPoints) diskData.shift(); + diskChart.data.labels.push(timeLabel); + if (diskChart.data.labels.length > maxDataPoints) diskChart.data.labels.shift(); + diskChart.data.datasets[0].data = diskData; + diskChart.update(); +} + +function fetchResourceUsage() { + $.ajax({ + url: '/website/get_website_resources/', + type: 'POST', + data: JSON.stringify({ + 'domain': $('#domainNamePage').text() + }), + contentType: 'application/json', + success: function(data) { + if (data.status === 1) { + updateCharts(data); + } + }, + error: function() { + console.error('Error fetching resource usage data'); + } + }); +} + +// Initialize charts when the page loads +$(document).ready(function() { + initializeCharts(); + // Fetch resource usage every 5 seconds + setInterval(fetchResourceUsage, 5000); + // Initial fetch + fetchResourceUsage(); +}); \ No newline at end of file diff --git a/websiteFunctions/templates/websiteFunctions/website.html b/websiteFunctions/templates/websiteFunctions/website.html index 1cff43688..ff1cc0f51 100755 --- a/websiteFunctions/templates/websiteFunctions/website.html +++ b/websiteFunctions/templates/websiteFunctions/website.html @@ -1,9 +1,9 @@ {% extends "baseTemplate/index.html" %} {% load i18n %} +{% load static %} {% block title %}{{ domain }} - CyberPanel{% endblock %} {% block content %} - {% load static %} {% get_current_language as LANGUAGE_CODE %} @@ -222,6 +222,29 @@
+ +
+
+ + + + {% trans "Real-time Resource Usage" %} +
+
+
+ +
+
+ +
+
+
+
+ +
+
+
+

@@ -1196,3 +1219,10 @@ {% endblock %} + +{% block footer_scripts %} +{{ block.super }} + + + +{% endblock %} diff --git a/websiteFunctions/urls.py b/websiteFunctions/urls.py index 263492a83..9b68b8712 100755 --- a/websiteFunctions/urls.py +++ b/websiteFunctions/urls.py @@ -200,4 +200,6 @@ urlpatterns = [ # Catch all for domains path('/', views.launchChild, name='launchChild'), path('', views.domain, name='domain'), + + path('get_website_resources/', views.get_website_resources, name='get_website_resources'), ] diff --git a/websiteFunctions/views.py b/websiteFunctions/views.py index ddfe3276e..a1cad4436 100755 --- a/websiteFunctions/views.py +++ b/websiteFunctions/views.py @@ -2,11 +2,12 @@ from django.shortcuts import redirect -from django.http import HttpResponse +from django.http import HttpResponse, JsonResponse from loginSystem.models import Administrator from loginSystem.views import loadLoginPage import json import plogical.CyberCPLogFileWriter as logging +from plogical.acl import ACLManager from plogical.httpProc import httpProc @@ -17,6 +18,7 @@ from django.views.decorators.csrf import csrf_exempt from .dockerviews import startContainer as docker_startContainer from .dockerviews import stopContainer as docker_stopContainer from .dockerviews import restartContainer as docker_restartContainer +from .resource_monitoring import get_website_resource_usage def loadWebsitesHome(request): val = request.session['userID'] @@ -1882,4 +1884,42 @@ def restartContainer(request): return docker_restartContainer(request) return HttpResponse('Not allowed') except KeyError: - return redirect(loadLoginPage) \ No newline at end of file + return redirect(loadLoginPage) + +@csrf_exempt +def get_website_resources(request): + try: + data = json.loads(request.body) + domain = data['domain'] + + # Get userID from session + try: + userID = request.session['userID'] + admin = Administrator.objects.get(pk=userID) + except: + return JsonResponse({'status': 0, 'error_message': 'Unauthorized access'}) + + # Verify domain ownership + currentACL = ACLManager.loadedACL(userID) + + from websiteFunctions.models import Websites + try: + website = Websites.objects.get(domain=domain) + except Websites.DoesNotExist: + return JsonResponse({'status': 0, 'error_message': 'Website not found'}) + + if ACLManager.checkOwnership(domain, admin, currentACL) == 1: + pass + else: + return ACLManager.loadError() + + # Get resource usage data using externalApp + resource_data = get_website_resource_usage(website.externalApp) + if resource_data['status'] == 0: + return JsonResponse(resource_data) + + return JsonResponse(resource_data) + + except BaseException as msg: + logging.CyberCPLogFileWriter.writeToFile(f'Error in get_website_resources: {str(msg)}') + return JsonResponse({'status': 0, 'error_message': str(msg)}) \ No newline at end of file From 1df56caee736e58d46ead7c720565946079cd5a8 Mon Sep 17 00:00:00 2001 From: usmannasir Date: Fri, 2 May 2025 16:17:17 +0500 Subject: [PATCH 12/16] resource usage graphs --- .../js/resource-monitoring.js | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 static/websiteFunctions/js/resource-monitoring.js diff --git a/static/websiteFunctions/js/resource-monitoring.js b/static/websiteFunctions/js/resource-monitoring.js new file mode 100644 index 000000000..6b0f3ed87 --- /dev/null +++ b/static/websiteFunctions/js/resource-monitoring.js @@ -0,0 +1,143 @@ +// Resource Monitoring +let cpuChart, memoryChart, diskChart; +let cpuData = [], memoryData = [], diskData = []; +const maxDataPoints = 30; + +function initializeCharts() { + const chartOptions = { + responsive: true, + maintainAspectRatio: false, + scales: { + y: { + beginAtZero: true, + max: 100, + ticks: { + callback: function(value) { + return value + '%'; + } + } + } + }, + animation: { + duration: 750 + } + }; + + // CPU Chart + const cpuCtx = document.getElementById('cpuChart').getContext('2d'); + cpuChart = new Chart(cpuCtx, { + type: 'line', + data: { + labels: [], + datasets: [{ + label: 'CPU Usage (%)', + data: [], + borderColor: '#2563eb', + backgroundColor: 'rgba(37, 99, 235, 0.1)', + borderWidth: 2, + fill: true, + tension: 0.4 + }] + }, + options: chartOptions + }); + + // Memory Chart + const memoryCtx = document.getElementById('memoryChart').getContext('2d'); + memoryChart = new Chart(memoryCtx, { + type: 'line', + data: { + labels: [], + datasets: [{ + label: 'Memory Usage (%)', + data: [], + borderColor: '#00b894', + backgroundColor: 'rgba(0, 184, 148, 0.1)', + borderWidth: 2, + fill: true, + tension: 0.4 + }] + }, + options: chartOptions + }); + + // Disk Chart + const diskCtx = document.getElementById('diskChart').getContext('2d'); + diskChart = new Chart(diskCtx, { + type: 'line', + data: { + labels: [], + datasets: [{ + label: 'Disk Usage (%)', + data: [], + borderColor: '#ff9800', + backgroundColor: 'rgba(255, 152, 0, 0.1)', + borderWidth: 2, + fill: true, + tension: 0.4 + }] + }, + options: chartOptions + }); +} + +function updateCharts(data) { + const now = new Date(); + const timeLabel = now.toLocaleTimeString(); + + // Update CPU Chart + cpuData.push(data.cpu_usage); + if (cpuData.length > maxDataPoints) cpuData.shift(); + cpuChart.data.labels.push(timeLabel); + if (cpuChart.data.labels.length > maxDataPoints) cpuChart.data.labels.shift(); + cpuChart.data.datasets[0].data = cpuData; + cpuChart.update('none'); // Use 'none' mode for better performance + + // Update Memory Chart + memoryData.push(data.memory_usage); + if (memoryData.length > maxDataPoints) memoryData.shift(); + memoryChart.data.labels.push(timeLabel); + if (memoryChart.data.labels.length > maxDataPoints) memoryChart.data.labels.shift(); + memoryChart.data.datasets[0].data = memoryData; + memoryChart.update('none'); + + // Update Disk Chart + diskData.push(data.disk_percent); + if (diskData.length > maxDataPoints) diskData.shift(); + diskChart.data.labels.push(timeLabel); + if (diskChart.data.labels.length > maxDataPoints) diskChart.data.labels.shift(); + diskChart.data.datasets[0].data = diskData; + diskChart.update('none'); +} + +function fetchResourceUsage() { + $.ajax({ + url: '/websites/get_website_resources/', + type: 'POST', + data: JSON.stringify({ + 'domain': $('#domainNamePage').text().trim() + }), + contentType: 'application/json', + success: function(data) { + if (data.status === 1) { + updateCharts(data); + } else { + console.error('Error fetching resource data:', data.error_message); + } + }, + error: function(xhr, status, error) { + console.error('Failed to fetch resource usage:', error); + } + }); +} + +// Initialize charts when the page loads +$(document).ready(function() { + if (document.getElementById('cpuChart')) { + initializeCharts(); + // Fetch resource usage every 5 seconds + setInterval(fetchResourceUsage, 5000); + // Initial fetch + fetchResourceUsage(); + } +}); \ No newline at end of file From e685efa8117fc2d35f0dc5110c0716ed5737d520 Mon Sep 17 00:00:00 2001 From: usmannasir Date: Fri, 2 May 2025 16:28:05 +0500 Subject: [PATCH 13/16] resource usage graphs --- .../js/resource-monitoring.js | 143 ++++++++++++++++ .../websiteFunctions/js/websiteFunctions.js | 162 ++++++++++++++++++ 2 files changed, 305 insertions(+) create mode 100644 websiteFunctions/static/websiteFunctions/js/resource-monitoring.js create mode 100644 websiteFunctions/static/websiteFunctions/js/websiteFunctions.js diff --git a/websiteFunctions/static/websiteFunctions/js/resource-monitoring.js b/websiteFunctions/static/websiteFunctions/js/resource-monitoring.js new file mode 100644 index 000000000..6b0f3ed87 --- /dev/null +++ b/websiteFunctions/static/websiteFunctions/js/resource-monitoring.js @@ -0,0 +1,143 @@ +// Resource Monitoring +let cpuChart, memoryChart, diskChart; +let cpuData = [], memoryData = [], diskData = []; +const maxDataPoints = 30; + +function initializeCharts() { + const chartOptions = { + responsive: true, + maintainAspectRatio: false, + scales: { + y: { + beginAtZero: true, + max: 100, + ticks: { + callback: function(value) { + return value + '%'; + } + } + } + }, + animation: { + duration: 750 + } + }; + + // CPU Chart + const cpuCtx = document.getElementById('cpuChart').getContext('2d'); + cpuChart = new Chart(cpuCtx, { + type: 'line', + data: { + labels: [], + datasets: [{ + label: 'CPU Usage (%)', + data: [], + borderColor: '#2563eb', + backgroundColor: 'rgba(37, 99, 235, 0.1)', + borderWidth: 2, + fill: true, + tension: 0.4 + }] + }, + options: chartOptions + }); + + // Memory Chart + const memoryCtx = document.getElementById('memoryChart').getContext('2d'); + memoryChart = new Chart(memoryCtx, { + type: 'line', + data: { + labels: [], + datasets: [{ + label: 'Memory Usage (%)', + data: [], + borderColor: '#00b894', + backgroundColor: 'rgba(0, 184, 148, 0.1)', + borderWidth: 2, + fill: true, + tension: 0.4 + }] + }, + options: chartOptions + }); + + // Disk Chart + const diskCtx = document.getElementById('diskChart').getContext('2d'); + diskChart = new Chart(diskCtx, { + type: 'line', + data: { + labels: [], + datasets: [{ + label: 'Disk Usage (%)', + data: [], + borderColor: '#ff9800', + backgroundColor: 'rgba(255, 152, 0, 0.1)', + borderWidth: 2, + fill: true, + tension: 0.4 + }] + }, + options: chartOptions + }); +} + +function updateCharts(data) { + const now = new Date(); + const timeLabel = now.toLocaleTimeString(); + + // Update CPU Chart + cpuData.push(data.cpu_usage); + if (cpuData.length > maxDataPoints) cpuData.shift(); + cpuChart.data.labels.push(timeLabel); + if (cpuChart.data.labels.length > maxDataPoints) cpuChart.data.labels.shift(); + cpuChart.data.datasets[0].data = cpuData; + cpuChart.update('none'); // Use 'none' mode for better performance + + // Update Memory Chart + memoryData.push(data.memory_usage); + if (memoryData.length > maxDataPoints) memoryData.shift(); + memoryChart.data.labels.push(timeLabel); + if (memoryChart.data.labels.length > maxDataPoints) memoryChart.data.labels.shift(); + memoryChart.data.datasets[0].data = memoryData; + memoryChart.update('none'); + + // Update Disk Chart + diskData.push(data.disk_percent); + if (diskData.length > maxDataPoints) diskData.shift(); + diskChart.data.labels.push(timeLabel); + if (diskChart.data.labels.length > maxDataPoints) diskChart.data.labels.shift(); + diskChart.data.datasets[0].data = diskData; + diskChart.update('none'); +} + +function fetchResourceUsage() { + $.ajax({ + url: '/websites/get_website_resources/', + type: 'POST', + data: JSON.stringify({ + 'domain': $('#domainNamePage').text().trim() + }), + contentType: 'application/json', + success: function(data) { + if (data.status === 1) { + updateCharts(data); + } else { + console.error('Error fetching resource data:', data.error_message); + } + }, + error: function(xhr, status, error) { + console.error('Failed to fetch resource usage:', error); + } + }); +} + +// Initialize charts when the page loads +$(document).ready(function() { + if (document.getElementById('cpuChart')) { + initializeCharts(); + // Fetch resource usage every 5 seconds + setInterval(fetchResourceUsage, 5000); + // Initial fetch + fetchResourceUsage(); + } +}); \ No newline at end of file diff --git a/websiteFunctions/static/websiteFunctions/js/websiteFunctions.js b/websiteFunctions/static/websiteFunctions/js/websiteFunctions.js new file mode 100644 index 000000000..c7c4eca13 --- /dev/null +++ b/websiteFunctions/static/websiteFunctions/js/websiteFunctions.js @@ -0,0 +1,162 @@ +// Resource Monitoring +let cpuChart, memoryChart, diskChart; +let cpuData = [], memoryData = [], diskData = []; +const maxDataPoints = 30; + +function initializeCharts() { + // CPU Chart + const cpuCtx = document.getElementById('cpuChart').getContext('2d'); + cpuChart = new Chart(cpuCtx, { + type: 'line', + data: { + labels: [], + datasets: [{ + label: 'CPU Usage (%)', + data: [], + borderColor: '#2563eb', + backgroundColor: 'rgba(37, 99, 235, 0.1)', + borderWidth: 2, + fill: true, + tension: 0.4 + }] + }, + options: { + responsive: true, + maintainAspectRatio: false, + scales: { + y: { + beginAtZero: true, + max: 100, + ticks: { + callback: function(value) { + return value + '%'; + } + } + } + } + } + }); + + // Memory Chart + const memoryCtx = document.getElementById('memoryChart').getContext('2d'); + memoryChart = new Chart(memoryCtx, { + type: 'line', + data: { + labels: [], + datasets: [{ + label: 'Memory Usage (%)', + data: [], + borderColor: '#00b894', + backgroundColor: 'rgba(0, 184, 148, 0.1)', + borderWidth: 2, + fill: true, + tension: 0.4 + }] + }, + options: { + responsive: true, + maintainAspectRatio: false, + scales: { + y: { + beginAtZero: true, + max: 100, + ticks: { + callback: function(value) { + return value + '%'; + } + } + } + } + } + }); + + // Disk Chart + const diskCtx = document.getElementById('diskChart').getContext('2d'); + diskChart = new Chart(diskCtx, { + type: 'line', + data: { + labels: [], + datasets: [{ + label: 'Disk Usage (%)', + data: [], + borderColor: '#ff9800', + backgroundColor: 'rgba(255, 152, 0, 0.1)', + borderWidth: 2, + fill: true, + tension: 0.4 + }] + }, + options: { + responsive: true, + maintainAspectRatio: false, + scales: { + y: { + beginAtZero: true, + max: 100, + ticks: { + callback: function(value) { + return value + '%'; + } + } + } + } + } + }); +} + +function updateCharts(data) { + const now = new Date(); + const timeLabel = now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds(); + + // Update CPU Chart + cpuData.push(data.cpu_usage); + if (cpuData.length > maxDataPoints) cpuData.shift(); + cpuChart.data.labels.push(timeLabel); + if (cpuChart.data.labels.length > maxDataPoints) cpuChart.data.labels.shift(); + cpuChart.data.datasets[0].data = cpuData; + cpuChart.update(); + + // Update Memory Chart + memoryData.push(data.memory_usage); + if (memoryData.length > maxDataPoints) memoryData.shift(); + memoryChart.data.labels.push(timeLabel); + if (memoryChart.data.labels.length > maxDataPoints) memoryChart.data.labels.shift(); + memoryChart.data.datasets[0].data = memoryData; + memoryChart.update(); + + // Update Disk Chart + diskData.push(data.disk_percent); + if (diskData.length > maxDataPoints) diskData.shift(); + diskChart.data.labels.push(timeLabel); + if (diskChart.data.labels.length > maxDataPoints) diskChart.data.labels.shift(); + diskChart.data.datasets[0].data = diskData; + diskChart.update(); +} + +function fetchResourceUsage() { + $.ajax({ + url: '/website/get_website_resources/', + type: 'POST', + data: JSON.stringify({ + 'domain': $('#domainNamePage').text() + }), + contentType: 'application/json', + success: function(data) { + if (data.status === 1) { + updateCharts(data); + } + }, + error: function() { + console.error('Error fetching resource usage data'); + } + }); +} + +// Initialize charts when the page loads +$(document).ready(function() { + initializeCharts(); + // Fetch resource usage every 5 seconds + setInterval(fetchResourceUsage, 5000); + // Initial fetch + fetchResourceUsage(); +}); \ No newline at end of file From b160c1b8f84682bea4c67d8277635d92d47f4bf5 Mon Sep 17 00:00:00 2001 From: usmannasir Date: Fri, 2 May 2025 16:33:00 +0500 Subject: [PATCH 14/16] resource usage graphs --- plogical/upgrade.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plogical/upgrade.py b/plogical/upgrade.py index 6543f9c96..424096663 100755 --- a/plogical/upgrade.py +++ b/plogical/upgrade.py @@ -2207,6 +2207,10 @@ CREATE TABLE `websiteFunctions_backupsv2` (`id` integer AUTO_INCREMENT NOT NULL if not Upgrade.executioner(command, command, 1): return 0, 'Failed to execute %s' % (command) + command = 'git clean -f' + if not Upgrade.executioner(command, command, 1): + return 0, 'Failed to execute %s' % (command) + command = 'git pull' if not Upgrade.executioner(command, command, 1): return 0, 'Failed to execute %s' % (command) From 83a36675001614d47027de9a2645ad276e473789 Mon Sep 17 00:00:00 2001 From: usmannasir Date: Thu, 15 May 2025 12:46:54 +0500 Subject: [PATCH 15/16] bug fix: site id in wp manager --- websiteFunctions/website.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/websiteFunctions/website.py b/websiteFunctions/website.py index a57cff62b..5fa495375 100755 --- a/websiteFunctions/website.py +++ b/websiteFunctions/website.py @@ -1959,7 +1959,9 @@ class WebsiteManager: currentACL = ACLManager.loadedACL(userID) admin = Administrator.objects.get(pk=userID) - siteId = data['siteId'] + siteId = data.get('siteId') or data.get('WPid') + if not siteId: + return JsonResponse({'status': 0, 'error_message': 'Missing siteId or WPid'}) setting = data['setting'] value = data['value'] From fc6a9c6800571a258a2d3c2349daf2aff4863143 Mon Sep 17 00:00:00 2001 From: usmannasir Date: Thu, 15 May 2025 13:08:54 +0500 Subject: [PATCH 16/16] bug fix: site id in wp manager --- websiteFunctions/website.py | 114 ++++++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 44 deletions(-) diff --git a/websiteFunctions/website.py b/websiteFunctions/website.py index 5fa495375..89605423b 100755 --- a/websiteFunctions/website.py +++ b/websiteFunctions/website.py @@ -1955,21 +1955,43 @@ class WebsiteManager: return HttpResponse(json_data) def UpdateWPSettings(self, userID=None, data=None): + # Map old setting names to new ones + setting_map = { + 'PasswordProtection': 'password-protection', + 'searchIndex': 'search-indexing', + 'debugging': 'debugging', + 'maintenanceMode': 'maintenance-mode', + 'lscache': 'lscache', + 'Wpcron': 'wpcron', + # Add more mappings as needed + } + + siteId = data.get('siteId') or data.get('WPid') + if not siteId: + resp = {'status': 0, 'error_message': 'Missing siteId or WPid'} + return JsonResponse(resp) + + # Accept both new and old setting names + setting = data.get('setting') + if not setting: + for old_key in setting_map: + if old_key in data: + setting = old_key + data['settingValue'] = data[old_key] + break + + # Map to new setting name if needed + setting = setting_map.get(setting, setting) + value = data.get('value') or data.get('settingValue') + try: currentACL = ACLManager.loadedACL(userID) admin = Administrator.objects.get(pk=userID) - - siteId = data.get('siteId') or data.get('WPid') - if not siteId: - return JsonResponse({'status': 0, 'error_message': 'Missing siteId or WPid'}) - setting = data['setting'] - value = data['value'] - wpsite = WPSites.objects.get(pk=siteId) - + if ACLManager.checkOwnership(wpsite.owner.domain, admin, currentACL) != 1: return ACLManager.loadError() - + # Get PHP version and path Webobj = Websites.objects.get(pk=wpsite.owner_id) Vhuser = Webobj.externalApp @@ -1979,10 +2001,8 @@ class WebsiteManager: # Update the appropriate setting based on the setting type if setting == 'search-indexing': - # Update search engine indexing command = f'sudo -u {Vhuser} {FinalPHPPath} -d error_reporting=0 /usr/bin/wp option update blog_public {value} --skip-plugins --skip-themes --path={wpsite.path}' elif setting == 'debugging': - # Update debugging in wp-config.php if value: command = f'sudo -u {Vhuser} {FinalPHPPath} -d error_reporting=0 /usr/bin/wp config set WP_DEBUG true --raw --skip-plugins --skip-themes --path={wpsite.path}' else: @@ -1992,76 +2012,84 @@ class WebsiteManager: vhostPassDir = f'/home/{vhostName}' path = f'{vhostPassDir}/{siteId}' if value: - # Enable password protection tempPath = f'/home/cyberpanel/{str(randint(1000, 9999))}' os.makedirs(tempPath) - - # Create temporary .htpasswd file htpasswd = f'{tempPath}/.htpasswd' htaccess = f'{tempPath}/.htaccess' password = randomPassword.generate_pass(12) - - # Create .htpasswd file command = f"htpasswd -cb {htpasswd} admin {password}" ProcessUtilities.executioner(command) - - # Create .htaccess file content htaccess_content = f""" AuthType Basic AuthName "Restricted Access" AuthUserFile {path}/.htpasswd Require valid-user """ - with open(htaccess, 'w') as f: f.write(htaccess_content) - - # Create final directory and move files command = f"mkdir -p {path}" ProcessUtilities.executioner(command, wpsite.owner.externalApp) - - # Move files to final location command = f"mv {htpasswd} {path}/.htpasswd" ProcessUtilities.executioner(command, wpsite.owner.externalApp) - - command = f"mv {htaccess} {wpsite.path}/.htaccess" + command = f"mv {htaccess} {wpsite.path}/.htaccess" ProcessUtilities.executioner(command, wpsite.owner.externalApp) - - # Cleanup temp directory command = f"rm -rf {tempPath}" ProcessUtilities.executioner(command) - else: - # Disable password protection if os.path.exists(path): command = f"rm -rf {path}" ProcessUtilities.executioner(command, wpsite.owner.externalApp) - htaccess = f'{wpsite.path}/.htaccess' if os.path.exists(htaccess): command = f"rm -f {htaccess}" ProcessUtilities.executioner(command, wpsite.owner.externalApp) - - return JsonResponse({'status': 1, 'error_message': 'None'}) + resp = {'status': 1, 'error_message': 'None'} + if data.get('legacy_response'): + import json + return HttpResponse(json.dumps(resp)) + else: + return JsonResponse(resp) elif setting == 'maintenance-mode': if value: command = f'sudo -u {Vhuser} {FinalPHPPath} -d error_reporting=0 /usr/bin/wp maintenance-mode activate --skip-plugins --skip-themes --path={wpsite.path}' else: command = f'sudo -u {Vhuser} {FinalPHPPath} -d error_reporting=0 /usr/bin/wp maintenance-mode deactivate --skip-plugins --skip-themes --path={wpsite.path}' + elif setting == 'lscache': + if value: + command = f'sudo -u {Vhuser} {FinalPHPPath} -d error_reporting=0 /usr/bin/wp plugin activate litespeed-cache --skip-plugins --skip-themes --path={wpsite.path}' + else: + command = f'sudo -u {Vhuser} {FinalPHPPath} -d error_reporting=0 /usr/bin/wp plugin deactivate litespeed-cache --skip-plugins --skip-themes --path={wpsite.path}' else: - return JsonResponse({'status': 0, 'error_message': 'Invalid setting type'}) - + resp = {'status': 0, 'error_message': 'Invalid setting type'} + if data.get('legacy_response'): + import json + return HttpResponse(json.dumps(resp)) + else: + return JsonResponse(resp) + result = ProcessUtilities.outputExecutioner(command) if result.find('Error:') > -1: - return JsonResponse({'status': 0, 'error_message': result}) - - return JsonResponse({'status': 1, 'error_message': 'None'}) + resp = {'status': 0, 'error_message': result} + if data.get('legacy_response'): + import json + return HttpResponse(json.dumps(resp)) + else: + return JsonResponse(resp) + + resp = {'status': 1, 'error_message': 'None'} + if data.get('legacy_response'): + import json + return HttpResponse(json.dumps(resp)) + else: + return JsonResponse(resp) except BaseException as msg: - return JsonResponse({'status': 0, 'error_message': str(msg)}) - - - + resp = {'status': 0, 'error_message': str(msg)} + if data and data.get('legacy_response'): + import json + return HttpResponse(json.dumps(resp)) + else: + return JsonResponse(resp) def submitWorpressCreation(self, userID=None, data=None): try: @@ -4789,7 +4817,6 @@ StrictHostKeyChecking no return ACLManager.loadErrorJson() tempStatusPath = "/home/cyberpanel/" + str(randint(1000, 9999)) - execPath = "/usr/local/CyberCP/bin/python " + virtualHostUtilities.cyberPanel + "/plogical/virtualHostUtilities.py" execPath = execPath + " switchServer --phpVersion '" + phpVersion + "' --server " + str( server) + " --virtualHostName " + domainName + " --tempStatusPath " + tempStatusPath @@ -7231,5 +7258,4 @@ StrictHostKeyChecking no except BaseException as msg: data_ret = {'status': 0, 'fetchStatus': 0, 'error_message': str(msg)} json_data = json.dumps(data_ret) - return HttpResponse(json_data) - + return HttpResponse(json_data) \ No newline at end of file