diff --git a/IncBackups/models.py b/IncBackups/models.py index 9e87e6aec..04a8f50c3 100644 --- a/IncBackups/models.py +++ b/IncBackups/models.py @@ -1,5 +1,6 @@ from django.db import models from websiteFunctions.models import Websites +from loginSystem.models import Administrator from datetime import datetime @@ -27,3 +28,19 @@ class BackupJob(models.Model): class JobSites(models.Model): job = models.ForeignKey(BackupJob, on_delete=models.CASCADE) website = models.CharField(max_length=300) + + +class OneClickBackups(models.Model): + owner = models.ForeignKey(Administrator, on_delete=models.PROTECT) + planName = models.CharField(max_length=100) + months = models.CharField(max_length=100) + price = models.CharField(max_length=100) + customer = models.CharField(max_length=300) + subscription = models.CharField(max_length=300, unique=True) + sftpUser = models.CharField(max_length=100) + config = models.TextField(default='{}') + date = models.DateTimeField(default=datetime.now, blank=True) + state = models.IntegerField(default=0) + + + diff --git a/backup/backupManager.py b/backup/backupManager.py index 13a85be36..38f82d796 100755 --- a/backup/backupManager.py +++ b/backup/backupManager.py @@ -2,8 +2,12 @@ import os import os.path import sys -import django +from io import StringIO +import django +import paramiko + +from plogical.applicationInstaller import ApplicationInstaller from plogical.httpProc import httpProc sys.path.append('/usr/local/CyberCP') @@ -1912,4 +1916,405 @@ class BackupManager: except BaseException as msg: data_ret = {'abort': 0, 'installStatus': 0, 'installationProgress': "0", 'error_message': str(msg)} json_data = json.dumps(data_ret) - return HttpResponse(json_data) \ No newline at end of file + return HttpResponse(json_data) + + def OneClickBackups(self, request=None, userID=None, data=None): + user = Administrator.objects.get(pk=userID) + + data = {} + + import requests + try: + if request.GET.get('status', 'none') == 'success': + plan_name = request.GET.get('planName') + months = request.GET.get('months') + monthly_price = request.GET.get('monthlyPrice') + yearly_price = request.GET.get('yearlyPrice') + customer = request.GET.get('customer') + subscription = request.GET.get('subscription') + + from IncBackups.models import OneClickBackups + + if months == '1': + price = monthly_price + else: + price = yearly_price + + try: + + backup_plan = OneClickBackups( + owner=user, + planName=plan_name, + months=months, + price=price, + customer=customer, + subscription=subscription, + sftpUser=f'{user.userName}{str(randint(1000, 9999))}', + ) + backup_plan.save() + + #### + + import requests + import json + + + # Define the URL of the endpoint + url = 'http://platform.cyberpersons.com/Billing/CreateSFTPAccount' # Replace with your actual endpoint URL + + # Define the payload to send in the POST request + payload = { + 'sub': subscription, + 'key': ProcessUtilities.outputExecutioner(f'cat /root/.ssh/cyberpanel.pub'), # Replace with the actual SSH public key + 'sftpUser': backup_plan.sftpUser, + 'serverIP': ACLManager.fetchIP(), # Replace with the actual server IP, + 'planName': plan_name + } + + # Convert the payload to JSON format + headers = {'Content-Type': 'application/json'} + dataRet = json.dumps(payload) + + # Make the POST request + response = requests.post(url, headers=headers, data=dataRet) + + # Handle the response + if response.status_code == 200: + response_data = response.json() + if response_data.get('status') == 1: + + ocbkup = OneClickBackups.objects.get(owner=user,subscription=subscription) + ocbkup.state = 1 + ocbkup.save() + + finalDic = {} + + finalDic['IPAddress'] = response_data.get('ipAddress') + finalDic['password'] = 'NOT-NEEDED' + finalDic['backupSSHPort'] = '22' + finalDic['userName'] = backup_plan.sftpUser + finalDic['type'] = 'SFTP' + finalDic['path'] = 'cpbackups' + finalDic['name'] = backup_plan.sftpUser + + wm = BackupManager() + response_inner = wm.submitDestinationCreation(userID, finalDic) + + response_data_inner = json.loads(response_inner.content.decode('utf-8')) + + # Extract the value of 'status' + if response_data_inner.get('status') == 0: + data['status'] = 0 + data[ + 'message'] = f"[2109] Failed to create sftp account {response_data_inner.get('error_message')}" + print("Failed to create SFTP account:", response_data_inner.get('error_message')) + else: + data['status'] = 1 + + else: + data['status'] = 0 + data['message'] = f"[1985] Failed to create sftp account {response_data.get('error_message')}" + print("Failed to create SFTP account:", response_data.get('error_message')) + else: + print("Failed to connect to the server. Status code:", response.status_code) + print("Response:", response.text) + data['status'] = 0 + data['message'] = f"[1991] Failed to create sftp account {response.text}" + + #### + + except BaseException as msg: + data['status'] = 4 + data['message'] = str(msg) + + elif request.GET.get('status', 'none') == 'cancelled': + data['status'] = 0 + else: + data['status'] = 2 + except BaseException as msg: + data['status'] = 0 + data['message'] = f"[2038] Unkown error occured in purchase process. Error message: {str(msg)}" + + + url = 'https://platform.cyberpersons.com/Billing/FetchBackupPlans' + + try: + response = requests.get(url) + response.raise_for_status() # Check if the request was successful + data['plans'] = response.json() # Convert the response to a Python dictionary + except requests.exceptions.HTTPError as http_err: + print(f'HTTP error occurred: {http_err}') + except Exception as err: + print(f'Other error occurred: {err}') + + data['bPlans'] = user.oneclickbackups_set.all() + + proc = httpProc(request, 'backup/oneClickBackups.html', data, 'addDeleteDestinations') + return proc.render() + + def ManageOCBackups(self, request=None, userID=None, data=None): + userID = request.session['userID'] + currentACL = ACLManager.loadedACL(userID) + admin = Administrator.objects.get(pk=userID) + from IncBackups.models import OneClickBackups + ocb = OneClickBackups.objects.get(pk = request.GET.get('id'), owner=admin) + destinations = [NormalBackupDests.objects.get(name=ocb.sftpUser)] + dests = [] + for dest in destinations: + dests.append(dest.name) + + websitesName = ACLManager.findAllSites(currentACL, userID) + + proc = httpProc(request, 'backup/OneClickBackupSchedule.html', {'destination': NormalBackupDests.objects.get(name=ocb.sftpUser).name, 'websites': websitesName}, + 'scheduleBackups') + return proc.render() + + def RestoreOCBackups(self, request=None, userID=None, data=None): + userID = request.session['userID'] + currentACL = ACLManager.loadedACL(userID) + admin = Administrator.objects.get(pk=userID) + from IncBackups.models import OneClickBackups + ocb = OneClickBackups.objects.get(pk = request.GET.get('id'), owner=admin) + + # Load the private key + + nbd = NormalBackupDests.objects.get(name=ocb.sftpUser) + ip = json.loads(nbd.config)['ip'] + + # Connect to the remote server using the private key + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + # Read the private key content + private_key_path = '/root/.ssh/cyberpanel' + key_content = ProcessUtilities.outputExecutioner(f'cat {private_key_path}').rstrip('\n') + + # Load the private key from the content + key_file = StringIO(key_content) + key = paramiko.RSAKey.from_private_key(key_file) + # Connect to the server using the private key + ssh.connect(ip, username=ocb.sftpUser, pkey=key) + # Command to list directories under the specified path + command = f"ls -d cpbackups/*/" + + # Execute the command + stdin, stdout, stderr = ssh.exec_command(command) + + # Read the results + directories = stdout.read().decode().splitlines() + + finalDirs = [] + + # Print directories + for directory in directories: + finalDirs.append(directory.split('/')[1]) + + proc = httpProc(request, 'backup/restoreOCBackups.html', {'directories': finalDirs}, + 'scheduleBackups') + return proc.render() + + def fetchOCSites(self, request=None, userID=None, data=None): + try: + userID = request.session['userID'] + currentACL = ACLManager.loadedACL(userID) + + data = json.loads(request.body) + id = data['idValue'] + folder = data['folder'] + + admin = Administrator.objects.get(pk=userID) + from IncBackups.models import OneClickBackups + ocb = OneClickBackups.objects.get(pk = id, owner=admin) + + # Load the private key + + nbd = NormalBackupDests.objects.get(name=ocb.sftpUser) + ip = json.loads(nbd.config)['ip'] + + # Connect to the remote server using the private key + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + # Read the private key content + private_key_path = '/root/.ssh/cyberpanel' + key_content = ProcessUtilities.outputExecutioner(f'cat {private_key_path}').rstrip('\n') + + # Load the private key from the content + key_file = StringIO(key_content) + key = paramiko.RSAKey.from_private_key(key_file) + # Connect to the server using the private key + ssh.connect(ip, username=ocb.sftpUser, pkey=key) + # Command to list directories under the specified path + command = f"ls -d cpbackups/{folder}/*" + + # Execute the command + stdin, stdout, stderr = ssh.exec_command(command) + + # Read the results + directories = stdout.read().decode().splitlines() + + finalDirs = [] + + # Print directories + for directory in directories: + finalDirs.append(directory.split('/')[2]) + + data_ret = {'status': 1, 'finalDirs': finalDirs} + json_data = json.dumps(data_ret) + return HttpResponse(json_data) + except BaseException as msg: + data_ret = {'status': 0, 'error_message': str(msg)} + json_data = json.dumps(data_ret) + return HttpResponse(json_data) + + def StartOCRestore(self, request=None, userID=None, data=None): + try: + userID = request.session['userID'] + currentACL = ACLManager.loadedACL(userID) + + data = json.loads(request.body) + id = data['idValue'] + folder = data['folder'] + backupfile = data['backupfile'] + + + extraArgs = {} + extraArgs['id'] = id + extraArgs['folder'] = folder + extraArgs['backupfile'] = backupfile + extraArgs['userID'] = userID + extraArgs['tempStatusPath'] = "/home/cyberpanel/" + str(randint(1000, 9999)) + + statusFile = open(extraArgs['tempStatusPath'], 'w') + statusFile.writelines("Restore started..") + statusFile.close() + + background = ApplicationInstaller('StartOCRestore', extraArgs) + background.start() + + data_ret = {'status': 1, 'installStatus': 1, 'error_message': 'None', + 'tempStatusPath': extraArgs['tempStatusPath']} + json_data = json.dumps(data_ret) + return HttpResponse(json_data) + except BaseException as msg: + data_ret = {'status': 0, 'error_message': str(msg)} + json_data = json.dumps(data_ret) + return HttpResponse(json_data) + + def DeployAccount(self, request=None, userID=None, data=None): + user = Administrator.objects.get(pk=userID) + + userID = request.session['userID'] + currentACL = ACLManager.loadedACL(userID) + import json + + data = json.loads(request.body) + id = data['id'] + + from IncBackups.models import OneClickBackups + ocb = OneClickBackups.objects.get(pk=id, owner=user) + + data = {} + + #### + + import requests + import json + + # Define the URL of the endpoint + url = 'http://platform.cyberpersons.com/Billing/CreateSFTPAccount' # Replace with your actual endpoint URL + + # Define the payload to send in the POST request + payload = { + 'sub': ocb.subscription, + 'key': ProcessUtilities.outputExecutioner(f'cat /root/.ssh/cyberpanel.pub'), + # Replace with the actual SSH public key + 'sftpUser': ocb.sftpUser, + 'serverIP': ACLManager.fetchIP(), # Replace with the actual server IP + 'planName': ocb.planName + } + + # Convert the payload to JSON format + headers = {'Content-Type': 'application/json'} + dataRet = json.dumps(payload) + + # Make the POST request + response = requests.post(url, headers=headers, data=dataRet) + + # Handle the response + # Handle the response + if response.status_code == 200: + response_data = response.json() + if response_data.get('status') == 1: + + ocb.state = 1 + ocb.save() + + print("SFTP account created successfully.") + + finalDic = {} + + finalDic['IPAddress'] = response_data.get('ipAddress') + finalDic['password'] = 'NOT-NEEDED' + finalDic['backupSSHPort'] = '22' + finalDic['userName'] = ocb.sftpUser + finalDic['type'] = 'SFTP' + finalDic['path'] = 'cpbackups' + finalDic['name'] = ocb.sftpUser + + wm = BackupManager() + response_inner = wm.submitDestinationCreation(userID, finalDic) + + response_data_inner = json.loads(response_inner.content.decode('utf-8')) + + # Extract the value of 'status' + if response_data_inner.get('status') == 0: + data_ret = {'status': 1, 'error_message': response_data_inner.get('error_message')} + json_data = json.dumps(data_ret) + return HttpResponse(json_data) + else: + data_ret = {'status': 1,} + json_data = json.dumps(data_ret) + return HttpResponse(json_data) + + else: + + if response_data.get('error_message') == "Already deployed.": + ocb.state = 1 + ocb.save() + + print("SFTP account created successfully.") + + finalDic = {} + + finalDic['IPAddress'] = response_data.get('ipAddress') + finalDic['password'] = 'NOT-NEEDED' + finalDic['backupSSHPort'] = '22' + finalDic['userName'] = ocb.sftpUser + finalDic['type'] = 'SFTP' + finalDic['path'] = 'cpbackups' + finalDic['name'] = ocb.sftpUser + + wm = BackupManager() + response_inner = wm.submitDestinationCreation(userID, finalDic) + + response_data_inner = json.loads(response_inner.content.decode('utf-8')) + + # Extract the value of 'status' + if response_data_inner.get('status') == 0: + data_ret = {'status': 1, 'error_message': response_data_inner.get('error_message')} + json_data = json.dumps(data_ret) + return HttpResponse(json_data) + else: + data_ret = {'status': 1, } + json_data = json.dumps(data_ret) + return HttpResponse(json_data) + + data_ret = {'status': 0, 'error_message': response_data.get('error_message')} + json_data = json.dumps(data_ret) + return HttpResponse(json_data) + else: + data['message'] = f"[1991] Failed to create sftp account {response.text}" + data_ret = {'status': 0, 'error_message': response.text} + json_data = json.dumps(data_ret) + return HttpResponse(json_data) + + diff --git a/backup/static/backup/backup.js b/backup/static/backup/backup.js index 17e62f6ad..a0d8ebb03 100755 --- a/backup/static/backup/backup.js +++ b/backup/static/backup/backup.js @@ -97,8 +97,7 @@ app.controller('backupWebsiteControl', function ($scope, $http, $timeout) { $scope.status = response.data.status; populateCurrentRecords(); return; - } - else { + } else { $scope.destination = true; $scope.backupButton = true; $scope.runningBackup = false; @@ -109,8 +108,7 @@ app.controller('backupWebsiteControl', function ($scope, $http, $timeout) { $timeout(getBackupStatus, 2000); } - } - else { + } else { $timeout.cancel(); $scope.backupLoadingBottom = true; $scope.backupLoading = true; @@ -230,8 +228,7 @@ app.controller('backupWebsiteControl', function ($scope, $http, $timeout) { populateCurrentRecords(); - } - else { + } else { } @@ -308,8 +305,7 @@ app.controller('restoreWebsiteControl', function ($scope, $http, $timeout) { $scope.restoreFinished = true; $timeout.cancel(); return; - } - else { + } else { $scope.running = response.data.running; $scope.fileName = $scope.backupFile; $scope.restoreLoading = false; @@ -364,18 +360,17 @@ app.controller('restoreWebsiteControl', function ($scope, $http, $timeout) { getRestoreStatus(); restoreBackupButton.disabled = false; - } - else { + } else { $scope.backupError = false; $scope.errorMessage = response.data.error_message; - restoreBackupButton.disabled = false; + restoreBackupButton.disabled = false; } } function cantLoadInitialDatas(response) { $scope.couldNotConnect = false; - restoreBackupButton.disabled = false; + restoreBackupButton.disabled = false; } }; @@ -404,14 +399,12 @@ app.controller('restoreWebsiteControl', function ($scope, $http, $timeout) { if (response.data.createWebSiteStatus == 1) { getRestoreStatus(); - } - else if (response.data.existsStatus == 1) { + } else if (response.data.existsStatus == 1) { $scope.backupError = false; $scope.errorMessage = response.data.error_message; $scope.restoreButton = true; $scope.runningRestore = true; - } - else { + } else { $scope.websiteDomain = domainName; $scope.backupError = false; $scope.errorMessage = response.data.error_message; @@ -484,8 +477,7 @@ app.controller('remoteBackupControl', function ($scope, $http, $timeout) { websitesToBeBacked.push(website); } - } - else { + } else { var tempArray = []; @@ -504,8 +496,7 @@ app.controller('remoteBackupControl', function ($scope, $http, $timeout) { websitesToBeBacked = websitesToBeBackedTemp; $scope.webSiteStatus = true; - } - else { + } else { websitesToBeBacked = []; $scope.webSiteStatus = false; } @@ -568,8 +559,7 @@ app.controller('remoteBackupControl', function ($scope, $http, $timeout) { $scope.backupCancelled = true; - } - else { + } else { $scope.error_message = response.data.error_message; $scope.backupLoading = true; @@ -667,8 +657,7 @@ app.controller('remoteBackupControl', function ($scope, $http, $timeout) { getBackupStatus(); - } - else { + } else { $scope.error_message = response.data.error_message; $scope.backupLoading = true; @@ -730,8 +719,7 @@ app.controller('remoteBackupControl', function ($scope, $http, $timeout) { $scope.backupStatus = false; $scope.requestData = response.data.status; $timeout(getBackupStatus, 2000); - } - else { + } else { $scope.requestData = response.data.status; $timeout.cancel(); @@ -739,8 +727,7 @@ app.controller('remoteBackupControl', function ($scope, $http, $timeout) { remoteBackupRestore(); } - } - else { + } else { $scope.error_message = response.data.error_message; $scope.backupLoading = true; @@ -832,15 +819,13 @@ app.controller('remoteBackupControl', function ($scope, $http, $timeout) { $scope.backupStatus = false; $scope.restoreData = response.data.status; $timeout(localRestoreStatus, 2000); - } - else { + } else { $scope.restoreData = response.data.status; $timeout.cancel(); $scope.backupLoading = true; $scope.startTransferbtn = false; } - } - else { + } else { $scope.error_message = response.data.error_message; $scope.backupLoading = true; @@ -895,8 +880,7 @@ app.controller('remoteBackupControl', function ($scope, $http, $timeout) { $scope.backupStatus = false; $scope.requestData = response.data.status; $timeout(getBackupStatus, 2000); - } - else { + } else { $timeout.cancel(); } } @@ -980,8 +964,7 @@ app.controller('remoteBackupControl', function ($scope, $http, $timeout) { $scope.fetchAccountsBtn = false; - } - else { + } else { $scope.error_message = response.data.error_message; $scope.backupLoading = true; @@ -1067,6 +1050,7 @@ app.controller('backupLogsScheduled', function ($scope, $http, $timeout) { }); } } + function cantLoadInitialData(response) { $scope.cyberpanelLoading = true; new PNotify({ @@ -1085,15 +1069,12 @@ app.controller('backupLogsScheduled', function ($scope, $http, $timeout) { ///** Backup site ends **/// - - - app.controller('googleDrive', function ($scope, $http) { $scope.cyberPanelLoading = true; $scope.driveHidden = true; - $scope.setupAccount = function(){ + $scope.setupAccount = function () { window.open("https://platform.cyberpersons.com/gDrive?name=" + $scope.accountName + '&server=' + window.location.href + 'Setup'); }; @@ -1252,7 +1233,7 @@ app.controller('googleDrive', function ($scope, $http) { $scope.changeRetention = function () { $scope.cyberPanelLoading = false; - var config = { + var config = { headers: { 'X-CSRFToken': getCookie('csrftoken') } @@ -1268,24 +1249,25 @@ app.controller('googleDrive', function ($scope, $http) { $http.post(dataurl, data, config).then(fileretention, cantLoadInitialData); - function fileretention(response) { - $scope.cyberPanelLoading = true; - if (response.data.status === 1) { - new PNotify({ - title: 'Success', - text: 'Changes successfully applied', - type: 'success' - }); - $scope.fetchWebsites(); - } else { - new PNotify({ - title: 'Operation Failed!', - text: response.data.error_message, - type: 'error' - }); - } + function fileretention(response) { + $scope.cyberPanelLoading = true; + if (response.data.status === 1) { + new PNotify({ + title: 'Success', + text: 'Changes successfully applied', + type: 'success' + }); + $scope.fetchWebsites(); + } else { + new PNotify({ + title: 'Operation Failed!', + text: response.data.error_message, + type: 'error' + }); } - function cantLoadInitialData(response) { + } + + function cantLoadInitialData(response) { $scope.cyberPanelLoading = true; new PNotify({ title: 'Operation Failed!', @@ -2062,3 +2044,654 @@ app.controller('scheduleBackup', function ($scope, $http, $window) { }; }); + +app.controller('backupPlanNowOneClick', function ($scope, $http, $window) { + $scope.cyberpanelLoading = true; + $scope.sftpHide = true; + $scope.localHide = true; + + $scope.BuyNowBackupP = function (planName, monthlyPrice, yearlyPrice, months) { + + const baseURL = 'https://platform.cyberpersons.com/Billing/CreateOrderforBackupPlans'; + // Get the current URL + var currentURL = window.location.href; + +// Find the position of the question mark + const queryStringIndex = currentURL.indexOf('?'); + +// Check if there is a query string + currentURL = queryStringIndex !== -1 ? currentURL.substring(0, queryStringIndex) : currentURL; + + + // Encode parameters to make them URL-safe + const params = new URLSearchParams({ + planName: planName, + monthlyPrice: monthlyPrice, + yearlyPrice: yearlyPrice, + returnURL: currentURL, // Add the current URL as a query parameter + months: months + }); + + + // Build the complete URL with query string + const fullURL = `${baseURL}?${params.toString()}`; + + // Redirect to the constructed URL + + window.location.href = fullURL; + + } + + + $scope.fetchDetails = function () { + + if ($scope.destinationType === 'SFTP') { + $scope.sftpHide = false; + $scope.localHide = true; + $scope.populateCurrentRecords(); + } else { + $scope.sftpHide = true; + $scope.localHide = false; + $scope.populateCurrentRecords(); + } + }; + + $scope.populateCurrentRecords = function () { + + $scope.cyberpanelLoading = false; + + url = "/backup/getCurrentBackupDestinations"; + + var type = 'SFTP'; + if ($scope.destinationType === 'SFTP') { + type = 'SFTP'; + } else { + type = 'local'; + } + + var data = { + type: type + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + $scope.cyberpanelLoading = true; + if (response.data.status === 1) { + $scope.records = JSON.parse(response.data.data); + } else { + new PNotify({ + title: 'Operation Failed!', + text: response.data.error_message, + type: 'error' + }); + } + + } + + function cantLoadInitialDatas(response) { + $scope.cyberpanelLoading = true; + new PNotify({ + title: 'Operation Failed!', + text: 'Could not connect to server, please refresh this page', + type: 'error' + }); + } + + }; + + $scope.addDestination = function (type) { + $scope.cyberpanelLoading = false; + + url = "/backup/submitDestinationCreation"; + + if (type === 'SFTP') { + var data = { + type: type, + name: $scope.name, + IPAddress: $scope.IPAddress, + userName: $scope.userName, + password: $scope.password, + backupSSHPort: $scope.backupSSHPort, + path: $scope.path + }; + } else { + var data = { + type: type, + path: $scope.localPath, + name: $scope.name + }; + } + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + $scope.cyberpanelLoading = true; + $scope.populateCurrentRecords(); + if (response.data.status === 1) { + new PNotify({ + title: 'Success!', + text: 'Destination successfully added.', + type: 'success' + }); + } else { + new PNotify({ + title: 'Operation Failed!', + text: response.data.error_message, + type: 'error' + }); + } + + } + + function cantLoadInitialDatas(response) { + $scope.cyberpanelLoading = true; + new PNotify({ + title: 'Operation Failed!', + text: 'Could not connect to server, please refresh this page', + type: 'error' + }); + } + + }; + + $scope.removeDestination = function (type, nameOrPath) { + $scope.cyberpanelLoading = false; + + + url = "/backup/deleteDestination"; + + var data = { + type: type, + nameOrPath: nameOrPath, + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + $scope.cyberpanelLoading = true; + $scope.populateCurrentRecords(); + if (response.data.status === 1) { + new PNotify({ + title: 'Success!', + text: 'Destination successfully removed.', + type: 'success' + }); + } else { + new PNotify({ + title: 'Operation Failed!', + text: response.data.error_message, + type: 'error' + }); + } + + } + + function cantLoadInitialDatas(response) { + $scope.cyberpanelLoading = true; + new PNotify({ + title: 'Operation Failed!', + text: 'Could not connect to server, please refresh this page', + type: 'error' + }); + } + + }; + + $scope.DeployAccount = function (id) { + $scope.cyberpanelLoading = false; + + url = "/backup/DeployAccount"; + + var data = { + id:id + + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + function ListInitialDatas(response) { + + $scope.cyberpanelLoading = true; + if (response.data.status === 1) { + new PNotify({ + title: 'Success', + text: 'Successfully deployed.', + type: 'success' + }); + $window.location.reload(); + + + } else { + new PNotify({ + title: 'Operation Failed!', + text: response.data.error_message, + type: 'error' + }); + } + + } + + function cantLoadInitialDatas(response) { + $scope.couldNotConnect = false; + restoreBackupButton.disabled = false; + } + + }; + + +}); + + +app.controller('OneClickrestoreWebsiteControl', function ($scope, $http, $timeout) { + + $scope.restoreLoading = true; + $scope.runningRestore = true; + $scope.restoreButton = true; + $scope.restoreFinished = false; + $scope.couldNotConnect = true; + $scope.backupError = true; + $scope.siteExists = true; + $scope.installationProgress = true; + + // check to start time of status function + + var check = 1; + + + $scope.fetchDetails = function () { + $scope.restoreLoading = false; + getRestoreStatus(); + }; + + + function getRestoreStatus() { + + var backupFile = $scope.backupFile; + + url = "/backup/restoreStatus"; + + var data = { + backupFile: backupFile, + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + + + if (response.data.restoreStatus === 1) { + + if (response.data.abort === 1) { + $scope.running = response.data.running; + $scope.fileName = $scope.backupFile; + $scope.restoreLoading = true; + $scope.status = response.data.status; + $scope.runningRestore = false; + $scope.restoreButton = false; + $scope.restoreFinished = true; + $timeout.cancel(); + return; + } else { + $scope.running = response.data.running; + $scope.fileName = $scope.backupFile; + $scope.restoreLoading = false; + $scope.status = response.data.status; + $scope.runningRestore = false; + $scope.restoreButton = true; + $timeout(getRestoreStatus, 2000); + } + } + + } + + function cantLoadInitialDatas(response) { + $scope.couldNotConnect = false; + + + } + + }; + + + $scope.restoreBackup = function () { + var restoreBackupButton = document.getElementById("restoreBackup"); + restoreBackupButton.disabled = true; + var backupFile = $scope.backupFile; + $scope.running = "Lets start.." + + url = "/backup/submitRestore"; + + var data = { + backupFile: backupFile, + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + + $scope.restoreLoading = true; + if (response.data.restoreStatus == 1) { + $scope.runningRestore = false; + $scope.running = "Running"; + $scope.fileName = $scope.backupFile; + $scope.status = "Just Started.."; + + getRestoreStatus(); + restoreBackupButton.disabled = false; + } else { + $scope.backupError = false; + $scope.errorMessage = response.data.error_message; + restoreBackupButton.disabled = false; + } + + } + + function cantLoadInitialDatas(response) { + $scope.couldNotConnect = false; + restoreBackupButton.disabled = false; + } + + }; + + function createWebsite() { + + var backupFile = $scope.backupFile; + + url = "/websites/CreateWebsiteFromBackup"; + + var data = { + backupFile: backupFile, + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + + if (response.data.createWebSiteStatus == 1) { + getRestoreStatus(); + } else if (response.data.existsStatus == 1) { + $scope.backupError = false; + $scope.errorMessage = response.data.error_message; + $scope.restoreButton = true; + $scope.runningRestore = true; + } else { + $scope.websiteDomain = domainName; + $scope.backupError = false; + $scope.errorMessage = response.data.error_message; + } + + + } + + function cantLoadInitialDatas(response) { + $scope.couldNotConnect = false; + } + + + }; + + $scope.FetchOCSites = function () { + $scope.restoreLoading = false; + + // Current URL + const currentURL = window.location.href; + +// Create a URL object + const urlN = new URL(currentURL); + +// Get the value of the 'id' parameter + const idValue = urlN.searchParams.get('id'); + + + url = "/backup/fetchOCSites"; + + var data = { + idValue: idValue, + folder: $scope.ocFolder + + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + + $scope.restoreLoading = true; + if (response.data.status === 1) { + + $scope.backups = response.data.finalDirs; + + } else { + + } + + } + + function cantLoadInitialDatas(response) { + $scope.couldNotConnect = false; + restoreBackupButton.disabled = false; + } + + }; + + $scope.StartOCRestore = function () { + + $scope.restoreLoading = false; + $scope.installationDetailsForm = true; + $scope.installationProgress = false; + $scope.errorMessageBox = true; + $scope.success = true; + $scope.couldNotConnect = true; + $scope.goBackDisable = true; + $scope.restoreLoading = false; + + + $scope.currentStatus = "Starting creation.."; + + + // Current URL + const currentURL = window.location.href; + +// Create a URL object + const urlN = new URL(currentURL); + +// Get the value of the 'id' parameter + const idValue = urlN.searchParams.get('id'); + + + //alert(domainNameCreate); + var data = { + + idValue: idValue, + folder: $scope.ocFolder, + backupfile: $scope.ocFile + } + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + var url = "/backup/StartOCRestore"; + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + $scope.restoreLoading = true; + if (response.data.status === 1) { + statusFile = response.data.tempStatusPath; + getCreationStatus(); + + } else { + $scope.goBackDisable = false; + new PNotify({ + title: 'Operation Failed!', + text: response.data.error_message, + type: 'error' + }); + } + + } + + function cantLoadInitialDatas(response) { + + alert("Error..." + response) + + } + + }; + $scope.goBack = function () { + $scope.webSiteCreationLoading = true; + $scope.installationDetailsForm = false; + $scope.installationProgress = true; + $scope.errorMessageBox = true; + $scope.success = true; + $scope.couldNotConnect = true; + $scope.goBackDisable = true; + $("#installProgress").css("width", "0%"); + }; + + function getCreationStatus() { + + url = "/websites/installWordpressStatus"; + + var data = { + statusFile: statusFile + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + + if (response.data.abort === 1) { + + if (response.data.installStatus === 1) { + + $scope.restoreLoading = true; + $scope.installationDetailsForm = true; + $scope.installationProgress = false; + $scope.errorMessageBox = true; + $scope.success = false; + $scope.couldNotConnect = true; + $scope.goBackDisable = false; + + $("#installProgress").css("width", "100%"); + $scope.installPercentage = "100"; + $scope.currentStatus = response.data.currentStatus ; + $timeout.cancel(); + + } else { + + $scope.restoreLoading = true; + $scope.installationDetailsForm = true; + $scope.installationProgress = false; + $scope.errorMessageBox = false; + $scope.success = true; + $scope.couldNotConnect = true; + $scope.goBackDisable = false; + + $scope.errorMessage = response.data.error_message; + + $("#installProgress").css("width", "0%"); + $scope.installPercentage = "0"; + $scope.goBackDisable = false; + + } + + } else { + $scope.restoreLoading = false; + $("#installProgress").css("width", response.data.installationProgress + "%"); + $scope.installPercentage = response.data.installationProgress; + $scope.currentStatus = response.data.currentStatus; + $timeout(getCreationStatus, 1000); + } + + } + + function cantLoadInitialDatas(response) { + + $scope.restoreLoading = true; + $scope.installationDetailsForm = true; + $scope.installationProgress = false; + $scope.errorMessageBox = true; + $scope.success = true; + $scope.couldNotConnect = false; + $scope.goBackDisable = false; + + } + + + } + + +}); diff --git a/backup/templates/backup/OneClickBackupSchedule.html b/backup/templates/backup/OneClickBackupSchedule.html new file mode 100755 index 000000000..65e5cad33 --- /dev/null +++ b/backup/templates/backup/OneClickBackupSchedule.html @@ -0,0 +1,309 @@ +{% extends "baseTemplate/index.html" %} +{% load i18n %} +{% block title %}{% trans "Schedule Backup - CyberPanel" %}{% endblock %} +{% block content %} + + {% load static %} + + + {% get_current_language as LANGUAGE_CODE %} + + +
+
+

{% trans "Schedule Backup" %} - {% trans "Remote Backups" %} +

+

{% trans "On this page you can schedule Backups to localhost or remote server (If you have added one)" %}

+
+ +
+
+

+ {% trans "Create New Backup Schedule" %} cyberPanelLoading +

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

+ {% trans "Manage Existing Backup Schedules" %} cyberPanelLoading +

+
+ + +
+ +
+ +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ + +
+ +
+
+ + + + + + + + + + + + + + + + + + + +
Last RunAll SitesFrequency ({$ currently $})Retention ({$ currently $})Current Status
{$ lastRun $}{$ allSites $} + + {$ currentStatus $}
+
+
+ +
+
+
+ + +
+
+
+
+
+ +
+
+
+ + + + + + + + + + + + + + +
SitesAction
+ +
+ +
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+ + +
+
+
+ + +
+ + +{% endblock %} diff --git a/backup/templates/backup/backup.html b/backup/templates/backup/backup.html index e90e97ab0..8d8bd6777 100755 --- a/backup/templates/backup/backup.html +++ b/backup/templates/backup/backup.html @@ -1,155 +1,167 @@ - {% extends "baseTemplate/index.html" %} {% load i18n %} {% block title %}{% trans "Backup Website" %}{% endblock %} {% block content %} -{% load static %} - -{% get_current_language as LANGUAGE_CODE %} - - -
-
-

{% trans "Backup Website" %} - {% trans "Backup Docs" %}

-

{% trans "This page can be used to Backup your websites" %}

-
- -
-
-

- {% trans "Backup Website" %} -

-
- -
- - -
- -
- -
-
- -
- -
- -
-
- - - - -
- -
- - - - - - - - - - - - - - - - -
{% trans "File Name" %}{% trans "Status" %}
{% trans "Running" %}{$ fileName $}{$ status $}
-
-
- - - - -
- -
- -
-
- -
- -
- -
-
- - - - -
- -
- - - - - - - - - - - - - - - - - - - - - - -
{% trans "ID" %}{% trans "File" %}{% trans "Date" %}{% trans "Size" %}{% trans "Status" %}{% trans "Delete" %}
-
-
- - - - -
- -
-
-

{% trans "Cannot delete website, Error message: " %}{$ errorMessage $}

-
- -
-

Website {$ deletedWebsite $} {% trans "Successfully Deleted" %}

-
-
- - - -
- - -
- + {% load static %} + {% get_current_language as LANGUAGE_CODE %} + +
+
+

{% trans "Backup Website" %} - {% trans "Backup Docs" %}

+

{% trans "This page can be used to Backup your websites" %}

+ +
+
+

+ {% trans "Backup Website" %} +

+
+

Configure automatic backups to our secure servers in 60 seconds. Set-up now.

+
+
+ +
+ + +
+ +
+ +
+
+ +
+ +
+ +
+
+ + + + +
+ +
+ + + + + + + + + + + + + + + + +
{% trans "File Name" %}{% trans "Status" %}
{% trans "Running" %}{$ fileName $}{$ status $}
+
+
+ + + + +
+ +
+ +
+
+ +
+ +
+ +
+
+ + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
{% trans "ID" %}{% trans "File" %}{% trans "Date" %}{% trans "Size" %}{% trans "Status" %}{% trans "Delete" %}
+
+
+ + + + +
+ +
+
+

{% trans "Cannot delete website, Error message: " %}{$ errorMessage $}

+
+ +
+

Website {$ deletedWebsite $} {% trans "Successfully Deleted" %} +

+
+
+ + +
+ + +
+ + +
+
+
+ +
-
- - -
{% endblock %} \ No newline at end of file diff --git a/backup/templates/backup/backupDestinations.html b/backup/templates/backup/backupDestinations.html index 6d8bd87be..8dcb8184c 100755 --- a/backup/templates/backup/backupDestinations.html +++ b/backup/templates/backup/backupDestinations.html @@ -12,10 +12,10 @@

{% trans "Set up Backup Destinations" %} - {% trans "Remote Backups" %} + href="https://cyberpanel.net/KnowledgeBase/home/add-destination-scheduled-local-sftp-remote-backups/" + style="height: 23px;line-height: 21px;" + class="btn btn-border btn-alt border-red btn-link font-red" + title="">{% trans "Remote Backups" %}

{% trans "On this page you can set up your Backup destinations. (SFTP)" %}

@@ -24,8 +24,12 @@

{% trans "Set up Backup Destinations." %} + src="{% static 'images/loading.gif' %}">

+
+

Configure automatic backups to our secure servers in 60 seconds. Set-up now.

+
@@ -82,7 +86,8 @@
- +
@@ -122,7 +127,8 @@ - + @@ -164,8 +170,6 @@ - -
@@ -184,7 +188,8 @@ - + diff --git a/backup/templates/backup/oneClickBackups.html b/backup/templates/backup/oneClickBackups.html new file mode 100755 index 000000000..e7aa97afa --- /dev/null +++ b/backup/templates/backup/oneClickBackups.html @@ -0,0 +1,172 @@ +{% extends "baseTemplate/index.html" %} +{% load i18n %} +{% block title %}{% trans "One-click Backups" %}{% endblock %} +{% block content %} + + {% load static %} + + + {% get_current_language as LANGUAGE_CODE %} + + +
+
+

{% trans "One-click Backups" %} - {% trans "Remote Backups" %} +

+

{% trans "On this page you purchase and manage one-click backups." %}

+
+ +
+
+

+ {% trans "Set up Backup Destinations." %} +

+
+ + {% if status == 1 %} +
+

You have successfully purchased a backup plan.

+
+ {% elif status == 0 %} + +
+

Your purchase was not successful.

{{ message }} +
+ {% elif status == 4 %} + +
+ {{ message }} +
+ {% endif %} + +
+ +

With CyberPanel's one-click backups, you can easily back up your website to our secure + servers in just 60 seconds. It's simple, fast, and reliable.

+ + + + +
+ +
+ + + + + + + + + + + + + + {% for plan in bPlans %} + + + + + {% if plan.months == '1' %} + + {% else %} + + {% endif %} + + + + + {% endfor %} + +
{% trans "Account" %}{% trans "Plan Name" %}{% trans "Subscription" %}{% trans "Billing Cycle" %}{% trans "Purchase Date" %}{% trans "Actions" %}
{{ plan.sftpUser }}{{ plan.planName }}{{ plan.subscription }}${{ plan.price }}/month${{ plan.price }}/year{{ plan.date }} + {% if plan.state == 1 %} + + + + + + + {% else %} + + {% endif %} + +
+
+ +
+ + + + + + +

+ {% trans "Subscribe to one-click backup plans." %} +

+ +
+ +
+ + + + + + + + + + + + {% for plan in plans %} + + + + + + + + {% endfor %} + +
{% trans "Plan Name" %}{% trans "Monthly Price" %}{% trans "Yearly Price" %}{% trans "Actions" %}
{{ plan.name }}${{ plan.monthlyPrice }}${{ plan.yearlyPrice }} + + +
+
+ +
+ + + + + + + +
+ + +
+
+
+ + +
+ + +{% endblock %} \ No newline at end of file diff --git a/backup/templates/backup/restoreOCBackups.html b/backup/templates/backup/restoreOCBackups.html new file mode 100755 index 000000000..c244abe79 --- /dev/null +++ b/backup/templates/backup/restoreOCBackups.html @@ -0,0 +1,114 @@ +{% extends "baseTemplate/index.html" %} +{% load i18n %} +{% block title %}{% trans "Restore Website - CyberPanel" %}{% endblock %} +{% block content %} + + {% load static %} + + {% get_current_language as LANGUAGE_CODE %} + + + +
+
+

{% trans "Restore Website" %} - {% trans "Backup Docs" %} +

+

{% trans "This page can be used to restore your websites, Backup should be generated from CyberPanel Backup generation tool, it will detect all Backups under /home/backup." %}

+
+ +
+
+

+ {% trans "Restore Website" %} +

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

{$ currentStatus $}

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

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

+
+ +
+

{% trans "Backup restored successfully." %}

+
+ + +
+

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

+
+ + +
+
+ +
+ +
+ +
+
+ + +
+ + +
+
+
+ + +
+ + +{% endblock %} \ No newline at end of file diff --git a/backup/urls.py b/backup/urls.py index 38cabfde6..d31bc8929 100755 --- a/backup/urls.py +++ b/backup/urls.py @@ -4,6 +4,13 @@ from . import views urlpatterns = [ url(r'^$', views.loadBackupHome, name='loadBackupHome'), url(r'^getCurrentBackups', views.getCurrentBackups, name='getCurrentBackups'), + url(r'^OneClickBackups', views.OneClickBackups, name='OneClickBackups'), + url(r'^ManageOCBackups', views.ManageOCBackups, name='ManageOCBackups'), + url(r'^RestoreOCBackups', views.RestoreOCBackups, name='RestoreOCBackups'), + url(r'^fetchOCSites', views.fetchOCSites, name='fetchOCSites'), + url(r'^StartOCRestore', views.StartOCRestore, name='StartOCRestore'), + url(r'^DeployAccount', views.DeployAccount, name='DeployAccount'), + url(r'^backupSite', views.backupSite, name='backupSite'), url(r'^restoreSite', views.restoreSite, name='restoreSite'), url(r'^gDrive$', views.gDrive, name='gDrive'), @@ -16,7 +23,6 @@ urlpatterns = [ url(r'^deleteSitegDrive$', views.deleteSitegDrive, name='deleteSitegDrive'), url(r'^fetchDriveLogs$', views.fetchDriveLogs, name='fetchDriveLogs'), - url(r'^submitBackupCreation', views.submitBackupCreation, name='submitBackupCreation'), url(r'^cancelBackupCreation', views.cancelBackupCreation, name='cancelBackupCreation'), url(r'^backupStatus', views.backupStatus, name='backupStatus'), @@ -42,10 +48,8 @@ urlpatterns = [ url(r'^submitBackupSchedule', views.submitBackupSchedule, name='submitBackupSchedule'), - url(r'^scheduleDelete', views.scheduleDelete, name='scheduleDelete'), - url(r'^remoteBackups', views.remoteBackups, name='remoteBackups'), url(r'^submitRemoteBackups', views.submitRemoteBackups, name='submitRemoteBackups'), url(r'^getRemoteTransferStatus', views.getRemoteTransferStatus, name='getRemoteTransferStatus'), @@ -67,4 +71,4 @@ urlpatterns = [ url(r'^deleteAccountNormal$', views.deleteAccountNormal, name='deleteAccountNormal'), url(r'^fetchNormalLogs$', views.fetchNormalLogs, name='fetchNormalLogs'), -] \ No newline at end of file +] diff --git a/backup/views.py b/backup/views.py index b20cfaa9d..7f0317f39 100755 --- a/backup/views.py +++ b/backup/views.py @@ -481,5 +481,56 @@ def fetchNormalLogs(request): userID = request.session['userID'] wm = BackupManager() return wm.fetchNormalLogs(request, userID) + except KeyError: + return redirect(loadLoginPage) + + +def OneClickBackups(request): + try: + userID = request.session['userID'] + bm = BackupManager() + return bm.OneClickBackups(request, userID) + except KeyError: + + return redirect(loadLoginPage) + +def ManageOCBackups(request): + try: + userID = request.session['userID'] + bm = BackupManager() + return bm.ManageOCBackups(request, userID) + except KeyError: + + return redirect(loadLoginPage) + +def RestoreOCBackups(request): + try: + userID = request.session['userID'] + bm = BackupManager() + return bm.RestoreOCBackups(request, userID) + except KeyError: + return redirect(loadLoginPage) + +def fetchOCSites(request): + try: + userID = request.session['userID'] + bm = BackupManager() + return bm.fetchOCSites(request, userID) + except KeyError: + return redirect(loadLoginPage) + +def StartOCRestore(request): + try: + userID = request.session['userID'] + bm = BackupManager() + return bm.StartOCRestore(request, userID) + except KeyError: + return redirect(loadLoginPage) + +def DeployAccount(request): + try: + userID = request.session['userID'] + bm = BackupManager() + return bm.DeployAccount(request, userID) except KeyError: return redirect(loadLoginPage) \ No newline at end of file diff --git a/baseTemplate/templates/baseTemplate/index.html b/baseTemplate/templates/baseTemplate/index.html index fc877f430..c677f2fae 100755 --- a/baseTemplate/templates/baseTemplate/index.html +++ b/baseTemplate/templates/baseTemplate/index.html @@ -77,7 +77,7 @@ - {% with version="2.3.5.4" %} + {% with version="2.3.5.6" %} @@ -690,6 +690,11 @@ @@ -1149,6 +1154,12 @@ href="/base/onboarding">Setup Wizard.

{% endif %} + {% if backupDisplay == 1 %} +
+

Looks like your websites are not secured with automatic backups. Configure now.

+
+ {% endif %} {% block content %} {% endblock %} diff --git a/plogical/IncScheduler.py b/plogical/IncScheduler.py index 0866f1e39..21d25655f 100644 --- a/plogical/IncScheduler.py +++ b/plogical/IncScheduler.py @@ -652,8 +652,18 @@ Automatic backup failed for %s on %s. except BaseException as msg: NormalBackupJobLogs(owner=backupjob, status=backupSchedule.INFO, message=f'Failed to make sftp connection {str(msg)}').save() + print(str(msg)) continue + + try: + + command = f'find cpbackups -type f -mtime +{destinationConfig["retention"]} -exec rm -f {{}} \\;' + ssh.exec_command(command) + logging.writeToFile(command) + except: + pass + # Execute the command to create the remote directory command = f'mkdir -p {finalPath}' stdin, stdout, stderr = ssh.exec_command(command) diff --git a/plogical/applicationInstaller.py b/plogical/applicationInstaller.py index 0c62e1b46..ce02cbb7d 100755 --- a/plogical/applicationInstaller.py +++ b/plogical/applicationInstaller.py @@ -1,8 +1,12 @@ #!/usr/local/CyberCP/bin/python import argparse +import json import os, sys import shutil import time +from io import StringIO + +import paramiko from ApachController.ApacheVhosts import ApacheVhost from loginSystem.models import Administrator @@ -18,7 +22,7 @@ import threading as multi from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging import subprocess from websiteFunctions.models import ChildDomains, Websites, WPSites, WPStaging, wpplugins, WPSitesBackup, \ - RemoteBackupConfig + RemoteBackupConfig, NormalBackupDests from plogical import randomPassword from plogical.mysqlUtilities import mysqlUtilities from databases.models import Databases @@ -86,6 +90,8 @@ class ApplicationInstaller(multi.Thread): self.RestoreWPbackupNow() elif self.installApp == 'UpgradeCP': self.UpgradeCP() + elif self.installApp == 'StartOCRestore': + self.StartOCRestore() except BaseException as msg: logging.writeToFile(str(msg) + ' [ApplicationInstaller.run]') @@ -6358,6 +6364,99 @@ class ApplicationInstaller(multi.Thread): logging.statusWriter(self.tempStatusPath, str(msg)) return 0, str(msg) + def StartOCRestore(self): + try: + + id = self.extraArgs['id'] + folder = self.extraArgs['folder'] + backupfile = self.extraArgs['backupfile'] + tempStatusPath = self.extraArgs['tempStatusPath'] + userID = self.extraArgs['userID'] + self.tempStatusPath = tempStatusPath + + statusFile = open(tempStatusPath, 'w') + statusFile.writelines("Download started..,30") + statusFile.close() + + from IncBackups.models import OneClickBackups + ocb = OneClickBackups.objects.get(pk=id) + + # Load the private key + + nbd = NormalBackupDests.objects.get(name=ocb.sftpUser) + ip = json.loads(nbd.config)['ip'] + + # Connect to the remote server using the private key + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + # Read the private key content + private_key_path = '/root/.ssh/cyberpanel' + key_content = ProcessUtilities.outputExecutioner(f'cat {private_key_path}').rstrip('\n') + + # Load the private key from the content + key_file = StringIO(key_content) + key = paramiko.RSAKey.from_private_key(key_file) + # Connect to the server using the private key + ssh.connect(ip, username=ocb.sftpUser, pkey=key) + sftp = ssh.open_sftp() + + sftp.get(f'cpbackups/{folder}/{backupfile}', f'/home/cyberpanel/{backupfile}') + + if not os.path.exists('/home/backup'): + command = 'mkdir /home/backup' + ProcessUtilities.executioner(command) + + command = f'mv /home/cyberpanel/{backupfile} /home/backup/{backupfile}' + ProcessUtilities.executioner(command) + + from backup.backupManager import BackupManager + wm = BackupManager() + resp = wm.submitRestore({'backupFile': backupfile}, userID) + + if json.loads(resp.content)['restoreStatus'] == 0: + statusFile = open(tempStatusPath, 'w') + statusFile.writelines(f"Failed to restore backup. Error {json.loads(resp.content)['error_message']}. [404]") + statusFile.close() + + command = f'rm -f /home/backup/{backupfile}' + ProcessUtilities.executioner(command) + + return 0 + + while True: + resp = wm.restoreStatus({'backupFile': backupfile}) + resp = json.loads(resp.content) + + if resp['abort'] == 1 and resp['running'] == 'Completed': + statusFile = open(tempStatusPath, 'w') + statusFile.writelines("Successfully Installed. [200]") + statusFile.close() + command = f'rm -f /home/backup/{backupfile}' + ProcessUtilities.executioner(command) + return 0 + elif resp['abort'] == 1 and resp['running'] == 'Error': + statusFile = open(tempStatusPath, 'w') + statusFile.writelines( + f"Failed to restore backup. Error {resp['status']}. [404]") + statusFile.close() + command = f'rm -f /home/backup/{backupfile}' + ProcessUtilities.executioner(command) + break + else: + statusFile = open(tempStatusPath, 'w') + statusFile.writelines(f"{resp['status']},60") + statusFile.close() + command = f'rm -f /home/backup/{backupfile}' + ProcessUtilities.executioner(command) + time.sleep(3) + + except BaseException as msg: + + statusFile = open(self.tempStatusPath, 'w') + statusFile.writelines(str(msg) + " [404]") + statusFile.close() + return 0 + def main(): parser = argparse.ArgumentParser(description='CyberPanel Application Installer') diff --git a/plogical/backupUtilities.py b/plogical/backupUtilities.py index 1a880937d..625a15ff4 100755 --- a/plogical/backupUtilities.py +++ b/plogical/backupUtilities.py @@ -1,3 +1,4 @@ +import json import os import sys @@ -41,7 +42,7 @@ from random import randint from plogical.processUtilities import ProcessUtilities try: - from websiteFunctions.models import Websites, ChildDomains, Backups + from websiteFunctions.models import Websites, ChildDomains, Backups, NormalBackupDests from databases.models import Databases from loginSystem.models import Administrator from plogical.dnsUtilities import DNS @@ -1329,35 +1330,48 @@ class backupUtilities: try: ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - ssh.connect(IPAddress, port=int(port), username=user, password=password) + if password != 'NOT-NEEDED': - commands = [ - "mkdir -p .ssh", - "rm -f .ssh/temp", - "rm -f .ssh/authorized_temp", - "cp .ssh/authorized_keys .ssh/temp", - "chmod 700 .ssh", - "chmod g-w ~", - ] + ssh.connect(IPAddress, port=int(port), username=user, password=password) + commands = [ + "mkdir -p .ssh", + "rm -f .ssh/temp", + "rm -f .ssh/authorized_temp", + "cp .ssh/authorized_keys .ssh/temp", + "chmod 700 .ssh", + "chmod g-w ~", + ] - for command in commands: - try: - ssh.exec_command(command) - except BaseException as msg: - logging.CyberCPLogFileWriter.writeToFile(f'Error executing remote command {command}. Error {str(msg)}') + for command in commands: + try: + ssh.exec_command(command) + except BaseException as msg: + logging.CyberCPLogFileWriter.writeToFile( + f'Error executing remote command {command}. Error {str(msg)}') - ssh.close() + ssh.close() - sendKey = backupUtilities.sendKey(IPAddress, password, port, user) + sendKey = backupUtilities.sendKey(IPAddress, password, port, user) - if sendKey[0] == 1: - command = 'chmod 644 %s' % ('/root/.ssh/cyberpanel.pub') - ProcessUtilities.executioner(command) - return [1, "None"] + if sendKey[0] == 1: + command = 'chmod 644 %s' % ('/root/.ssh/cyberpanel.pub') + ProcessUtilities.executioner(command) + return [1, "None"] + else: + command = 'chmod 644 %s' % ('/root/.ssh/cyberpanel.pub') + ProcessUtilities.executioner(command) + return [0, sendKey[1]] else: - command = 'chmod 644 %s' % ('/root/.ssh/cyberpanel.pub') - ProcessUtilities.executioner(command) - return [0, sendKey[1]] + # Load the private key + private_key_path = '/root/.ssh/cyberpanel' + keyPrivate = paramiko.RSAKey(filename=private_key_path) + + # Connect to the remote server using the private key + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + ssh.connect(IPAddress, username=user, pkey=keyPrivate) + + return [1, "None"] except paramiko.AuthenticationException: return [0, 'Authentication failed. [setupSSHKeys]'] @@ -2345,6 +2359,37 @@ def getConnectionStatus(ipAddress): except BaseException as msg: print(str(msg)) +def FetchOCBackupsFolders(id, owner): + # Load the private key + private_key_path = '/root/.ssh/cyberpanel' + keyPrivate = paramiko.RSAKey(filename=private_key_path) + + from IncBackups.models import OneClickBackups + admin = Administrator.objects.get(userName=owner) + ocb = OneClickBackups.objects.get(pk=id, owner=admin) + + nbd = NormalBackupDests.objects.get(name=ocb.sftpUser) + ip = json.loads(nbd.config)['ip'] + + # Connect to the remote server using the private key + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + ssh.connect(ip, username=ocb.sftpUser, pkey=keyPrivate) + + # Command to list directories under the specified path + command = f"ls -d cpbackups/*/" + + # Execute the command + stdin, stdout, stderr = ssh.exec_command(command) + + # Read the results + directories = stdout.read().decode().splitlines() + + # Print directories + for directory in directories: + print(directory) + + def main(): parser = argparse.ArgumentParser(description='CyberPanel Backup Generator') @@ -2391,6 +2436,10 @@ def main(): parser.add_argument('--CPHomeStorage', help='') + ### id + + parser.add_argument('--id', help='') + args = parser.parse_args() @@ -2439,5 +2488,8 @@ def main(): bu = backupUtilities(extraArgs) bu.SubmitS3BackupRestore() + elif args.function == 'FetchOCBackupsFolders': + FetchOCBackupsFolders(args.id, args.user) + if __name__ == "__main__": main() \ No newline at end of file diff --git a/plogical/httpProc.py b/plogical/httpProc.py index 82a6f3de6..6c95041c9 100755 --- a/plogical/httpProc.py +++ b/plogical/httpProc.py @@ -77,6 +77,13 @@ Please launch the set-up wizard to get maximum ou except: pass + from IncBackups.models import OneClickBackups + if OneClickBackups.objects.filter(owner=admin).count() == 0: + self.data['backupDisplay'] = 1 + else: + self.data['backupDisplay'] = 0 + + ACLManager.GetServiceStatus(self.data) self.data.update(currentACL)