HEX
Server: LiteSpeed
System: Linux php-prod-1.spaceapp.ru 5.15.0-157-generic #167-Ubuntu SMP Wed Sep 17 21:35:53 UTC 2025 x86_64
User: xnsbb3110 (1041)
PHP: 8.1.33
Disabled: NONE
Upload Files
File: //usr/local/CyberCP/plogical/Backupsv2.py
import argparse
import json
import os
import sys
import time

import paramiko
import requests
import json
import configparser
from django.http import HttpResponse

sys.path.append('/usr/local/CyberCP')
import django
import plogical.CyberCPLogFileWriter as logging

import plogical.mysqlUtilities as mysqlUtilities

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "CyberCP.settings")
try:
    django.setup()
except:
    pass

from plogical.processUtilities import ProcessUtilities
from plogical.processUtilities import ProcessUtilities as pu

import threading as multi


class CPBackupsV2(multi.Thread):
    PENDING_START = 0
    RUNNING = 1
    COMPLETED = 2
    FAILED = 3

    ### RCLONE BACKEND TYPES
    SFTP = 1
    LOCAL = 2
    GDrive = 3

    RUSTIC_PATH = '/usr/bin/rustic'
    RCLONE_CONFIG = '/root/.config/rclone/rclone.conf'
    command = 'rclone obscure hosting'

    def __init__(self, data):
        multi.Thread.__init__(self)
        self.data = data
        try:
            self.function = data['function']
        except:
            pass

        statusRes, message = self.InstallRustic()

        ### set self.website as it is needed in many functions
        from websiteFunctions.models import Websites
        self.website = Websites.objects.get(domain=self.data['domain'])

        # Resresh gdive access_token code
        try:
            self.LocalRclonePath = f'/home/{self.website.domain}/.config/rclone'
            self.ConfigFilePath = f'{self.LocalRclonePath}/rclone.conf'

            reponame =  self.data['BackendName']

            try:
                ### refresh token if gdrie
                command = f"rclone config dump"
                token = json.loads(ProcessUtilities.outputExecutioner(command, self.website.externalApp, True).rstrip('\n'))

                refreshToken = json.loads(token[reponame]['token'])['refresh_token']

                logging.CyberCPLogFileWriter.writeToFile(f"Refresh Token: {refreshToken}")

                new_Acess_token = self.refresh_V2Gdive_token(refreshToken)

                command = f"""rclone config update '{reponame}' token '{{"access_token":"{new_Acess_token}","token_type":"Bearer","refresh_token":"{refreshToken}","expiry":"2024-04-08T21:53:00.123456789Z"}}' --non-interactive"""
                result = ProcessUtilities.outputExecutioner(command, self.website.externalApp, True)

                if os.path.exists(ProcessUtilities.debugPath):
                    logging.CyberCPLogFileWriter.writeToFile(result)


            except BaseException as msg:
                logging.CyberCPLogFileWriter.writeToFile(f"Token Not upadate inside. Error: {str(msg)}")
                pass

            # command = 'cat %s' % (path)
            # CurrentContent = pu.outputExecutioner(command)


            # if CurrentContent.find(reponame) > -1:
            #     config = configparser.ConfigParser()
            #     config.read_string(CurrentContent)
            #
            #     token_str = config.get(reponame, 'token')
            #     token_dict = json.loads(token_str)
            #     refresh_token = token_dict['refresh_token']
            #
            #     new_Acess_token = self.refresh_V2Gdive_token(refresh_token)
            #
            #     old_access_token = token_dict['access_token']
            #
            #     new_content = CurrentContent.replace(str(old_access_token), new_Acess_token)
            #
            #     command = f"cat /dev/null > {self.ConfigFilePath}"
            #     pu.executioner(command, self.website.externalApp, True)
            #
            #     command = f"echo '{new_content}' >> {self.ConfigFilePath}"
            #     ProcessUtilities.executioner(command, self.website.externalApp, True)
            #
            #     command = f"chmod 600 {self.ConfigFilePath}"
            #     ProcessUtilities.executioner(command, self.website.externalApp)
            # else:
            #     logging.CyberCPLogFileWriter.writeToFile("Token Not upadate..........")
        except BaseException as msg:
            logging.CyberCPLogFileWriter.writeToFile("Error update token............%s"%msg)



        ## Set up the repo name to be used

        if self.data['BackendName'] != 'local':
            self.repo = f"rclone:'{self.data['BackendName']}':{self.data['domain']}"
        else:
            self.repo = f"rclone:'{self.data['BackendName']}':/home/{self.data['domain']}/incrementalbackups"

        ### This will contain list of all snapshots id generated and it will be merged

        self.snapshots = []

        ##

        self.StatusFile = f'/home/cyberpanel/{self.website.domain}_rustic_backup_log'
        self.StatusFile_Restore = f'/home/cyberpanel/{self.website.domain}_rustic_backup_log_Restore'

        ## restore or backup?

        self.restore = 0

        if os.path.exists(self.StatusFile):
            os.remove(self.StatusFile)


        #### i want to keep a merge flag, if not delete all snapshots in case of backup fail

        self.MergeSnapshotFlag = 1

        # ### delete repo function
        # try:
        #     self.repo = data['BackendName']
        # except:
        #     pass

    def run(self):
        try:
            if self.function == 'InitiateBackup':
                self.InitiateBackup()
            elif self.function == 'InitiateRestore':
                self.InitiateRestore()
        except BaseException as msg:
            logging.CyberCPLogFileWriter.writeToFile(str(msg) + ' [CPBackupsV2.run]')

    def FetchSnapShots(self):
        try:
            command = f'rustic -r {self.repo} snapshots --password "" --json 2>/dev/null'
            # SLSkjoSCczb6wxTMCBPmBMGq/UDSpp28-u cyber5986 rustic -r rclone:None:cyberpanel.net snapshots --password "" --json 2>/dev/null
            result = json.loads(
                ProcessUtilities.outputExecutioner(command, self.website.externalApp, True).rstrip('\n'))
            return 1, result
        except BaseException as msg:
            return 0, str(msg)

    def SetupRcloneBackend(self, type, config):
        try:
            self.LocalRclonePath = f'/home/{self.website.domain}/.config/rclone'
            self.ConfigFilePath = f'{self.LocalRclonePath}/rclone.conf'

            command = f'mkdir -p {self.LocalRclonePath}'
            ProcessUtilities.executioner(command, self.website.externalApp)


            if type == CPBackupsV2.SFTP:
                ## config = {"name":, "host":, "user":, "port":, "path":, "password":,}


                ### first check sftp credentails details

                # Connect to the remote server using the private key
                ssh = paramiko.SSHClient()
                ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

                try:
                    # Connect to the server using the private key
                    ssh.connect(config["host"], username=config["user"], password=config["password"], port=config["sshPort"])
                    ssh.close()
                    if os.path.exists(ProcessUtilities.debugPath):
                        logging.CyberCPLogFileWriter.writeToFile(f'Successfully connected to {config["host"]} through user {config["user"]}')
                except BaseException as msg:
                    return 0, str(msg)



                command = f'rclone obscure {config["password"]}'
                ObsecurePassword = ProcessUtilities.outputExecutioner(command).rstrip('\n')

                content = f'''
                
[{config["Repo_Name"]}]
type = sftp
host = {config["host"]}
user = {config["user"]}
pass = {ObsecurePassword}
port = {config["sshPort"]}
'''

                command = f"echo '{content}' >> {self.ConfigFilePath}"
                ProcessUtilities.executioner(command, self.website.externalApp, True)

                command = f"chmod 600 {self.ConfigFilePath}"
                ProcessUtilities.executioner(command, self.website.externalApp)
                return 1, None
            elif type == CPBackupsV2.GDrive:
                token = """{"access_token":"%s","token_type":"Bearer","refresh_token":"%s", "expiry":"2024-04-08T21:53:00.123456789Z"}""" % (
                config["token"], config["refresh_token"])

                if config["client_id"] == 'undefined':
                    config["client_id"] = ''
                    config["client_secret"] = ''

                content = f'''
[{config["accountname"]}]
type = drive
scope = drive
client_id={config["client_id"]}
client_secret={config["client_secret"]}
token = {token}
team_drive =
'''
                command = f"echo '{content}' >> {self.ConfigFilePath}"
                ProcessUtilities.executioner(command, self.website.externalApp, True)

                command = f"chmod 600 {self.ConfigFilePath}"
                ProcessUtilities.executioner(command, self.website.externalApp)
                return 1, None
        except BaseException as msg:
            logging.CyberCPLogFileWriter.writeToFile(str(msg) + ' [Configure.run]')
            return 0, str(msg)

    @staticmethod
    def FetchCurrentTimeStamp():
        import time
        return str(time.time())

    def UpdateStatus(self, message, status):

        if status == CPBackupsV2.FAILED:
            self.website.BackupLock = 0
            self.website.save()
            ### delete leftover dbs if backup fails

            command = f'rm -f {self.FinalPathRuctic}/*.sql'
            ProcessUtilities.executioner(command, None, True)

            file = open(self.StatusFile, 'a')
            file.writelines("[" + time.strftime(
                "%m.%d.%Y_%H-%M-%S") + ":FAILED] " + message + "[404]" + "\n")
            file.close()

            ### if backup failed, we need to prune snapshots as they are not needed.

            snapshots = ''
            for snapshot in self.snapshots:
                snapshots = f'{snapshots} {snapshot}'

            command = f'rustic -r {self.repo} forget {snapshots}  --password ""'
            result = ProcessUtilities.outputExecutioner(command, self.website.externalApp, True)

            if os.path.exists(ProcessUtilities.debugPath):
                logging.CyberCPLogFileWriter.writeToFile(result)

        elif status == CPBackupsV2.COMPLETED:
            self.website.BackupLock = 0
            self.website.save()
            file = open(self.StatusFile, 'a')
            file.writelines("[" + time.strftime(
                "%m.%d.%Y_%H-%M-%S") + ":COMPLETED] " + message + "[200]" + "\n")
            file.close()
        else:
            file = open(self.StatusFile, 'a')
            file.writelines("[" + time.strftime(
                "%m.%d.%Y_%H-%M-%S") + ":INFO] " + message + "\n")
            file.close()

    ## parent is used to link this snapshot with master snapshot
    def BackupConfig(self):
        ### Backup config file to rustic

        command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}'
        ProcessUtilities.executioner(command)

        command = f'rustic init -r {self.repo} --password ""'
        ProcessUtilities.executioner(command, self.website.externalApp)

        # command = f'chown cyberpanel:cyberpanel {self.FinalPathRuctic}'
        # ProcessUtilities.executioner(command)

        command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}/config.json'
        ProcessUtilities.executioner(command)

        command = f'rustic -r {self.repo} backup {self.FinalPathRuctic}/config.json --json --password "" 2>/dev/null'
        status, result = ProcessUtilities.outputExecutioner(command, self.website.externalApp, True, None, True)

        if os.path.exists(ProcessUtilities.debugPath):
            logging.CyberCPLogFileWriter.writeToFile(f'Status {str(status)}')

        if status:

            result = json.loads(result.rstrip('\n'))

            try:
                SnapShotID = result['id']  ## snapshot id that we need to store in db
                files_new = result['summary']['files_new']  ## basically new files in backup
                total_duration = result['summary']['total_duration']  ## time taken

                self.snapshots.append(SnapShotID)

            except BaseException as msg:
                self.UpdateStatus(f'Backup failed as no snapshot id found, error: {str(msg)}', CPBackupsV2.FAILED)
                return 0

            command = f'chown cyberpanel:cyberpanel {self.FinalPathRuctic}/config.json'
            ProcessUtilities.executioner(command)

            return 1
        else:
            self.UpdateStatus(f'Backup failed , error: {str(result)}', CPBackupsV2.FAILED)
            return 0

    def MergeSnapshots(self):
        snapshots = ''
        for snapshot in self.snapshots:
            snapshots = f'{snapshots} {snapshot}'

        if self.MergeSnapshotFlag:
            command = f'rustic -r {self.repo} merge {snapshots}  --password "" --json'
            result = ProcessUtilities.outputExecutioner(command, self.website.externalApp, True)

            if os.path.exists(ProcessUtilities.debugPath):
                logging.CyberCPLogFileWriter.writeToFile(result)

        command = f'rustic -r {self.repo} forget {snapshots}  --password ""'
        result = ProcessUtilities.outputExecutioner(command, self.website.externalApp, True)

        if os.path.exists(ProcessUtilities.debugPath):
            logging.CyberCPLogFileWriter.writeToFile(result)

    def InitiateBackup(self):
        logging.CyberCPLogFileWriter.writeToFile("[Create Backup start]")
        from websiteFunctions.models import Websites, Backupsv2
        from django.forms.models import model_to_dict
        from plogical.mysqlUtilities import mysqlUtilities
        self.website = Websites.objects.get(domain=self.data['domain'])

        ## Base path is basically the path set by user where all the backups will be housed

        if not os.path.exists(self.data['BasePath']):
            command = f"mkdir -p {self.data['BasePath']}"
            ProcessUtilities.executioner(command)

            #command = f"chmod 711 {self.data['BasePath']}"
            #ProcessUtilities.executioner(command)

        self.StartingTimeStamp = CPBackupsV2.FetchCurrentTimeStamp()

        ### Init rustic repo in main func so dont need to do again and again

        while (1):

            self.website = Websites.objects.get(domain=self.data['domain'])

            if self.website.BackupLock == 0:

                Disk1 = f"du -sm /home/{self.website.domain}/"
                Disk2 = "2>/dev/null | awk '{print $1}'"

                self.WebsiteDiskUsage = int(
                    ProcessUtilities.outputExecutioner(f"{Disk1} {Disk2}", 'root', True).rstrip('\n'))

                self.CurrentFreeSpaceOnDisk = int(
                    ProcessUtilities.outputExecutioner("df -m / | awk 'NR==2 {print $4}'", 'root', True).rstrip('\n'))

                if self.WebsiteDiskUsage > self.CurrentFreeSpaceOnDisk:
                    self.UpdateStatus(f'Not enough disk space on the server to backup this website.',
                                      CPBackupsV2.FAILED)
                    return 0

                self.UpdateStatus('Checking if backup modules installed,0', CPBackupsV2.RUNNING)

                ### Before doing anything install rustic

                statusRes, message = self.InstallRustic()

                if statusRes == 0:
                    self.UpdateStatus(f'Failed to install Rustic, error: {message}', CPBackupsV2.FAILED)
                    return 0

                # = Backupsv2(website=self.website, fileName='backup-' + self.data['domain'] + "-" + time.strftime("%m.%d.%Y_%H-%M-%S"), status=CPBackupsV2.RUNNING, BasePath=self.data['BasePath'])
                # self.buv2.save()

                # self.FinalPath = f"{self.data['BasePath']}/{self.buv2.fileName}"

                ### Rustic backup final path

                self.FinalPathRuctic = f"{self.data['BasePath']}/{self.website.domain}"

                # command = f"mkdir -p {self.FinalPath}"
                # ProcessUtilities.executioner(command)

                # command = f"chown {website.externalApp}:{website.externalApp} {self.FinalPath}"
                # ProcessUtilities.executioner(command)

                # command = f'chown cyberpanel:cyberpanel {self.FinalPath}'
                # ProcessUtilities.executioner(command)

                # command = f"chmod 711 {self.FinalPath}"
                # ProcessUtilities.executioner(command)

                command = f"mkdir -p {self.FinalPathRuctic}"
                ProcessUtilities.executioner(command)

                command = f'chown cyberpanel:cyberpanel {self.FinalPathRuctic}'
                ProcessUtilities.executioner(command)

                command = f"chmod 711 {self.FinalPathRuctic}"
                ProcessUtilities.executioner(command)

                try:

                    self.UpdateStatus('Creating backup config,0', CPBackupsV2.RUNNING)

                    Config = {'MainWebsite': model_to_dict(self.website,
                                                           fields=['domain', 'adminEmail', 'phpSelection', 'state',
                                                                   'config'])}
                    Config['admin'] = model_to_dict(self.website.admin,
                                                    fields=['userName', 'password', 'firstName', 'lastName',
                                                            'email', 'type', 'owner', 'token', 'api', 'securityLevel',
                                                            'state', 'initself.websitesLimit', 'twoFA', 'secretKey',
                                                            'config'])
                    Config['acl'] = model_to_dict(self.website.admin.acl)

                    ### Child domains to config

                    ChildsList = []

                    for childDomains in self.website.childdomains_set.all():
                        print(childDomains.domain)
                        ChildsList.append(model_to_dict(childDomains))

                    Config['ChildDomains'] = ChildsList

                    # print(str(Config))

                    ### Databases

                    connection, cursor = mysqlUtilities.setupConnection()

                    if connection == 0:
                        return 0

                    dataBases = self.website.databases_set.all()
                    DBSList = []

                    for db in dataBases:

                        query = f"SELECT host,user FROM mysql.db WHERE db='{db.dbName}';"
                        cursor.execute(query)
                        DBUsers = cursor.fetchall()

                        UserList = []

                        for databaseUser in DBUsers:
                            query = f"SELECT password FROM `mysql`.`user` WHERE `Host`='{databaseUser[0]}' AND `User`='{databaseUser[1]}';"
                            cursor.execute(query)
                            resp = cursor.fetchall()
                            print(resp)
                            UserList.append({'user': databaseUser[1], 'host': databaseUser[0], 'password': resp[0][0]})

                        DBSList.append({db.dbName: UserList})

                    Config['databases'] = DBSList

                    WPSitesList = []

                    for wpsite in self.website.wpsites_set.all():
                        WPSitesList.append(model_to_dict(wpsite, fields=['title', 'path', 'FinalURL', 'AutoUpdates',
                                                                         'PluginUpdates', 'ThemeUpdates',
                                                                         'WPLockState']))

                    Config['WPSites'] = WPSitesList
                    self.config = Config

                    ### DNS Records

                    try:
                        from dns.models import Domains

                        self.dnsDomain = Domains.objects.get(name=self.website.domain)

                        DNSRecords = []

                        for record in self.dnsDomain.records_set.all():
                            DNSRecords.append(model_to_dict(record))

                        Config['MainDNSDomain'] = model_to_dict(self.dnsDomain)
                        Config['DNSRecords'] = DNSRecords
                    except:
                        pass

                    ### Email accounts

                    try:
                        from mailServer.models import Domains

                        self.emailDomain = Domains.objects.get(domain=self.website.domain)

                        EmailAddrList = []

                        for record in self.emailDomain.eusers_set.all():
                            EmailAddrList.append(model_to_dict(record))

                        Config['MainEmailDomain'] = model_to_dict(self.emailDomain)
                        Config['EmailAddresses'] = EmailAddrList
                    except:
                        pass

                    # command = f"echo '{json.dumps(Config)}' > {self.FinalPath}/config.json"
                    # ProcessUtilities.executioner(command, self.website.externalApp, True)

                    command = f'chown cyberpanel:cyberpanel {self.FinalPathRuctic}/config.json'
                    ProcessUtilities.executioner(command)

                    WriteToFile = open(f'{self.FinalPathRuctic}/config.json', 'w')
                    WriteToFile.write(json.dumps(Config))
                    WriteToFile.close()

                    command = f"chmod 600 {self.FinalPathRuctic}/config.json"
                    ProcessUtilities.executioner(command)

                    if self.BackupConfig() == 0:
                        return 0

                    self.UpdateStatus('Backup config created,5', CPBackupsV2.RUNNING)
                except BaseException as msg:
                    self.UpdateStatus(f'Failed during config generation, Error: {str(msg)}', CPBackupsV2.FAILED)
                    return 0

                try:
                    if self.data['BackupDatabase']:
                        self.UpdateStatus('Backing up databases..,10', CPBackupsV2.RUNNING)
                        if self.BackupDataBasesRustic() == 0:
                            self.UpdateStatus(f'Failed to create backup for databases.', CPBackupsV2.FAILED)
                            self.MergeSnapshotFlag = 0
                            #return 0
                        else:
                            self.UpdateStatus('Database backups completed successfully..,25', CPBackupsV2.RUNNING)

                    if self.data['BackupData'] and self.MergeSnapshotFlag:
                        self.UpdateStatus('Backing up website data..,30', CPBackupsV2.RUNNING)
                        if self.BackupRustic() == 0:
                            self.UpdateStatus(f'Failed to create backup for data..', CPBackupsV2.FAILED)
                            self.MergeSnapshotFlag = 0
                            # return 0
                        else:
                            self.UpdateStatus('Website data backup completed successfully..,70', CPBackupsV2.RUNNING)

                    if self.data['BackupEmails'] and self.MergeSnapshotFlag:
                        self.UpdateStatus('Backing up emails..,75', CPBackupsV2.RUNNING)
                        if self.BackupEmailsRustic() == 0:
                            self.UpdateStatus(f'Failed to create backup for emails..', CPBackupsV2.FAILED)
                            self.MergeSnapshotFlag = 0
                        else:
                            self.UpdateStatus('Emails backup completed successfully..,85', CPBackupsV2.RUNNING)

                    ### Finally change the backup rustic folder to the website user owner

                    command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}'
                    ProcessUtilities.executioner(command)

                    if os.path.exists(ProcessUtilities.debugPath):
                        logging.CyberCPLogFileWriter.writeToFile(f'Snapshots to be merged {str(self.snapshots)}')

                    self.MergeSnapshots()

                    self.UpdateStatus('Completed', CPBackupsV2.COMPLETED)
                    return 1

                    break
                except BaseException as msg:
                    self.UpdateStatus(f'Failed, Error: {str(msg)}', CPBackupsV2.FAILED)
                    return 0
            else:
                time.sleep(5)

                ### If website lock is there for more then 20 minutes it means old backup is stucked or backup job failed, thus continue backup

                if float(CPBackupsV2.FetchCurrentTimeStamp()) > (float(self.StartingTimeStamp) + 1200):
                    self.website = Websites.objects.get(domain=self.data['domain'])
                    self.website.BackupLock = 0
                    self.website.save()

    def BackupDataBasesRustic(self):

        ### This function will backup databases of the website, also need to take care of database that we need to exclude
        ### excluded databases are in a list self.data['ExcludedDatabases'] only backup databases if backupdatabase check is on
        ## For example if self.data['BackupDatabase'] is one then only run this function otherwise not

        # command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}'
        # ProcessUtilities.executioner(command)

        command = f'rustic init -r {self.repo} --password ""'
        ProcessUtilities.executioner(command, self.website.externalApp)

        command = f'chown cyberpanel:cyberpanel {self.FinalPathRuctic}'
        ProcessUtilities.executioner(command)

        from plogical.mysqlUtilities import mysqlUtilities

        for dbs in self.config['databases']:

            ### Pending: Need to only backup database present in the list of databases that need backing up

            for key, value in dbs.items():
                print(f'DB {key}')

                CurrentDBPath = f"{self.FinalPathRuctic}/{key}.sql"

                DBResult, SnapID = mysqlUtilities.createDatabaseBackup(key, self.FinalPathRuctic, 1, self.repo,
                                                                       self.website.externalApp)

                if DBResult == 1:
                    self.snapshots.append(SnapID)

                    # command = f'chown {self.website.externalApp}:{self.website.externalApp} {CurrentDBPath}'
                    # ProcessUtilities.executioner(command)

                    ## Now pack config into same thing

                    # command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}/config.json'
                    # ProcessUtilities.executioner(command)

                    # command = f'rustic -r {self.repo} backup {CurrentDBPath} --password "" --json 2>/dev/null'
                    # print(f'db command rustic: {command}')
                    # result = json.loads(
                    #     ProcessUtilities.outputExecutioner(command, self.website.externalApp, True).rstrip('\n'))
                    #
                    # try:
                    #     SnapShotID = result['id']  ## snapshot id that we need to store in db
                    #     files_new = result['summary']['files_new']  ## basically new files in backup
                    #     total_duration = result['summary']['total_duration']  ## time taken
                    #
                    #     self.snapshots.append(SnapShotID)
                    #
                    #     ### Config is saved with each database, snapshot of config is attached to db snapshot with parent
                    #
                    #     #self.BackupConfig(SnapShotID)
                    #
                    #     command = f'chown cyberpanel:cyberpanel {self.FinalPathRuctic}'
                    #     ProcessUtilities.executioner(command)
                    #
                    # except BaseException as msg:
                    #     self.UpdateStatus(f'Backup failed as no snapshot id found, error: {str(msg)}',
                    #                       CPBackupsV2.FAILED)
                    #     return 0
                    #
                    #
                    # for dbUsers in value:
                    #     print(f'User: {dbUsers["user"]}, Host: {dbUsers["host"]}, Pass: {dbUsers["password"]}')
                    #
                    # command = f'rm -f {CurrentDBPath}'
                    # ProcessUtilities.executioner(command)

                else:
                    command = f'rm -f {CurrentDBPath}'
                    ProcessUtilities.executioner(command)
                    self.UpdateStatus(f'Failed to create backup for database {key}.', CPBackupsV2.FAILED)
                    return 0

        return 1

    def BackupRustic(self):

        ### This function will backup data of the website, also need to take care of directories that we need to exclude
        ### excluded directories are in a list self.data['ExcludedDirectories'] only backup data if backupdata check is on
        ## For example if self.data['BackupData'] is one then only run this function otherwise not

        # command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}'
        # ProcessUtilities.executioner(command)

        command = f'rustic init -r {self.repo} --password ""'
        ProcessUtilities.executioner(command, self.website.externalApp)

        source = f'/home/{self.website.domain}'

        # command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}/config.json'
        # ProcessUtilities.executioner(command)

        ## Pending add user provided folders in the exclude list

        exclude = f' --glob !{source}/logs '

        command = f'rustic -r {self.repo} backup {source} --password "" {exclude} --json 2>/dev/null'
        status, result = ProcessUtilities.outputExecutioner(command, self.website.externalApp, True, None, True)

        if os.path.exists(ProcessUtilities.debugPath):
            logging.CyberCPLogFileWriter.writeToFile(f'Status code {status}')

        if status:
            result = json.loads(result.rstrip('\n'))

            try:
                SnapShotID = result['id']  ## snapshot id that we need to store in db
                files_new = result['summary']['files_new']  ## basically new files in backup
                total_duration = result['summary']['total_duration']  ## time taken

                self.snapshots.append(SnapShotID)

                ### Config is saved with each backup, snapshot of config is attached to data snapshot with parent

                # self.BackupConfig(SnapShotID)
            except BaseException as msg:
                self.UpdateStatus(f'Backup failed as no snapshot id found, error: {str(msg)}', CPBackupsV2.FAILED)
                return 0

            # self.UpdateStatus(f'Rustic command result id: {SnapShotID}, files new {files_new}, total_duration {total_duration}', CPBackupsV2.RUNNING)

            return 1
        else:
            self.UpdateStatus(f'Backup failed, error: {str(result)}', CPBackupsV2.FAILED)
            return 0

    def BackupEmailsRustic(self):

        ### This function will backup emails of the website, also need to take care of emails that we need to exclude
        ### excluded emails are in a list self.data['ExcludedEmails'] only backup data if backupemail check is on
        ## For example if self.data['BackupEmails'] is one then only run this function otherwise not

        # command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}'
        # ProcessUtilities.executioner(command)

        command = f'rustic init -r {self.repo} --password ""'
        ProcessUtilities.executioner(command, self.website.externalApp)

        # command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}/config.json'
        # ProcessUtilities.executioner(command)

        source = f'/home/vmail/{self.website.domain}'

        if os.path.exists(source):
            ## Pending add user provided folders in the exclude list

            exclude = f' --exclude-if-present rusticbackup  --exclude-if-present logs '

            command = f'export RCLONE_CONFIG=/home/{self.website.domain}/.config/rclone/rclone.conf && rustic -r {self.repo} backup {source} --password "" {exclude} --json 2>/dev/null'

            result = json.loads(ProcessUtilities.outputExecutioner(command, None, True).rstrip('\n'))

            try:
                SnapShotID = result['id']  ## snapshot id that we need to store in db
                files_new = result['summary']['files_new']  ## basically new files in backup
                total_duration = result['summary']['total_duration']  ## time taken

                self.snapshots.append(SnapShotID)

                ### Config is saved with each email backup, snapshot of config is attached to email snapshot with parent

                # self.BackupConfig(SnapShotID)

            except BaseException as msg:
                self.UpdateStatus(f'Backup failed as no snapshot id found, error: {str(msg)}', CPBackupsV2.FAILED)
                return 0

        return 1

    #### Resote Functions

    def RestoreConfig(self):
        try:

            self.UpdateStatus(f'Restoring config..,10',
                              CPBackupsV2.RUNNING)
            ConfigPath = f'/home/backup/{self.website.domain}/config.json'
            RestoreConfigPath = f'/home/{self.website.domain}/'

            command = f'rustic -r {self.repo} restore {self.data["snapshotid"]}:{ConfigPath} {RestoreConfigPath} --password ""  2>/dev/null'
            result = ProcessUtilities.outputExecutioner(command, self.website.externalApp, True)

            ConfigContent = json.loads(ProcessUtilities.outputExecutioner(f'cat {RestoreConfigPath}/config.json').rstrip('\n'))

            ### ACL Creation code

            # ### First check if the acl exists
            # from loginSystem.models import ACL, Administrator
            # from django.http import HttpRequest
            # requestNew = HttpRequest()
            # try:
            #     if os.path.exists(ProcessUtilities.debugPath):
            #         logging.CyberCPLogFileWriter.writeToFile(f'ACL in config: {ConfigContent["acl"]}')
            #     acl = ACL.objects.get(name=ConfigContent['acl']['name'])
            # except:
            #     if os.path.exists(ProcessUtilities.debugPath):
            #         logging.CyberCPLogFileWriter.writeToFile('ACL Already existed.')
            #     requestNew.session['userID'] = Administrator.objects.get(userName='admin').id
            #     from userManagment.views import createACLFunc
            #     dataToPass = ConfigContent['acl']
            #     dataToPass['makeAdmin'] = ConfigContent['acl']['adminStatus']
            #     requestNew._body = json.dumps(dataToPass)
            #
            #     if os.path.exists(ProcessUtilities.debugPath):
            #         logging.CyberCPLogFileWriter.writeToFile(f'Passed content to Create ACL Func: {json.dumps(dataToPass)}')
            #
            #     resp = createACLFunc(requestNew)
            #     if os.path.exists(ProcessUtilities.debugPath):
            #         logging.CyberCPLogFileWriter.writeToFile(f'CreateACLFunc stats: {str(resp.content)}')

            ### Create DNS Records

            try:
                from dns.models import Domains
                zone = Domains.objects.get(name=self.website.domain)
                from plogical.dnsUtilities import DNS

                for record in ConfigContent['DNSRecords']:
                    DNS.createDNSRecord(zone, record['name'], record['type'], record['content'], 0, record['ttl'])
            except BaseException as msg:
                self.UpdateStatus(f'Error in RestoreConfig while restoring dns config. Error: {str(msg)}',
                                      CPBackupsV2.RUNNING)


            ### Create Emails Accounts


            #logging.statusWriter(statusPath, "Restoring email accounts!", 1)

            try:

                from plogical.mailUtilities import mailUtilities
                for emailAccount in ConfigContent['EmailAddresses']:

                    email = emailAccount['email']
                    username = email.split("@")[0]
                    password = emailAccount['password']

                    result = mailUtilities.createEmailAccount(self.website.domain, username, password)
                    if result[0] == 0:
                        # #logging.statusWriter(statusPath,
                        #                      'Email existed, updating password according to last snapshot. %s' % (
                        #                          email))
                        if mailUtilities.changeEmailPassword(email, password, 1)[0] == 0:
                            # logging.statusWriter(statusPath,
                            #                      'Failed changing password for: %s' % (
                            #                          email))
                            pass
                        else:
                            pass
                            # logging.statusWriter(statusPath,
                            #                      'Password changed for: %s' % (
                            #                          email))

                    else:
                        pass
                        # logging.statusWriter(statusPath,
                        #                      'Email created: %s' % (
                        #                          email))
            except BaseException as msg:
                self.UpdateStatus(f'Error in RestoreConfig while restoring email config. Error: {str(msg)}',
                                          CPBackupsV2.RUNNING)


            ### Restoring DBs

            try:

                from databases.models import Databases, DatabasesUsers

                for database in ConfigContent['databases']:

                    dbName = list(database.keys())[0]

                    if os.path.exists(ProcessUtilities.debugPath):
                        logging.CyberCPLogFileWriter.writeToFile(f'Databasename: {dbName}')

                    first = 1

                    databaseUsers = database[dbName]

                    for databaseUser in databaseUsers:

                        dbUser = databaseUser['user']
                        dbHost = databaseUser['host']
                        password = databaseUser['password']

                        if os.path.exists(ProcessUtilities.debugPath):
                            logging.CyberCPLogFileWriter.writeToFile('Database user: %s' % (dbUser))
                            logging.CyberCPLogFileWriter.writeToFile('Database host: %s' % (dbHost))
                            logging.CyberCPLogFileWriter.writeToFile('Database password: %s' % (password))

                        if first:

                            first = 0

                            try:
                                dbExist = Databases.objects.get(dbName=dbName)
                                logging.CyberCPLogFileWriter.writeToFile('Database exists, changing Database password.. %s' % (dbName))

                                if mysqlUtilities.mysqlUtilities.changePassword(dbUser, password, 1, dbHost) == 0:
                                    logging.CyberCPLogFileWriter.writeToFile('Failed changing password for database: %s' % (dbName))
                                else:
                                    logging.CyberCPLogFileWriter.writeToFile('Password successfully changed for database: %s.' % (dbName))

                            except:

                                logging.CyberCPLogFileWriter.writeToFile('Database did not exist, creating new.. %s' % (dbName))

                                if mysqlUtilities.mysqlUtilities.createDatabase(dbName, dbUser, "cyberpanel") == 0:
                                    logging.CyberCPLogFileWriter.writeToFile('Failed the creation of database: %s' % (dbName))
                                else:
                                    logging.CyberCPLogFileWriter.writeToFile('Database: %s successfully created.' % (dbName))

                                mysqlUtilities.mysqlUtilities.changePassword(dbUser, password, 1)

                                if mysqlUtilities.mysqlUtilities.changePassword(dbUser, password, 1) == 0:
                                    logging.CyberCPLogFileWriter.writeToFile('Failed changing password for database: %s' % (dbName))
                                else:
                                    logging.CyberCPLogFileWriter.writeToFile(
                                                         'Password successfully changed for database: %s.' % (dbName))

                                try:
                                    newDB = Databases(website=self.website, dbName=dbName, dbUser=dbUser)
                                    newDB.save()
                                except:
                                    pass

                        ## This function will not create database, only database user is created as third value is 0 for createDB

                        mysqlUtilities.mysqlUtilities.createDatabase(dbName, dbUser, password, 0, dbHost)
                        mysqlUtilities.mysqlUtilities.changePassword(dbUser, password, 1, dbHost)
            except BaseException as msg:
                self.UpdateStatus(f'Error in RestoreConfig while restoring database config. Error: {str(msg)}', CPBackupsV2.RUNNING)

            return 1, None

        except BaseException as msg:
            return 0, str(msg)

    def InitiateRestore(self):

        ### if restore then status file should be restore status file

        self.restore = 1
        # self.StatusFile = self.StatusFile_Restore

        from websiteFunctions.models import Websites
        from plogical.mysqlUtilities import mysqlUtilities
        self.website = Websites.objects.get(domain=self.data['domain'])

        self.UpdateStatus('Started restoring,20', CPBackupsV2.RUNNING)

        ## Base path is basically the path set by user where all the backups will be housed

        if not os.path.exists(self.data['BasePath']):
            command = f"mkdir -p {self.data['BasePath']}"
            ProcessUtilities.executioner(command)

            #command = f"chmod 711 {self.data['BasePath']}"
            #ProcessUtilities.executioner(command)

        self.StartingTimeStamp = CPBackupsV2.FetchCurrentTimeStamp()

        ### Init rustic repo in main func so dont need to do again and again

        while (1):

            self.website = Websites.objects.get(domain=self.data['domain'])

            if self.website.BackupLock == 0:

                Disk1 = f"du -sm /home/{self.website.domain}/"
                Disk2 = "2>/dev/null | awk '{print $1}'"

                self.WebsiteDiskUsage = int(
                    ProcessUtilities.outputExecutioner(f"{Disk1} {Disk2}", 'root', True).rstrip('\n'))

                self.CurrentFreeSpaceOnDisk = int(
                    ProcessUtilities.outputExecutioner("df -m / | awk 'NR==2 {print $4}'", 'root', True).rstrip('\n'))

                if self.WebsiteDiskUsage > self.CurrentFreeSpaceOnDisk:
                    self.UpdateStatus(f'Not enough disk space on the server to restore this website.',
                                      CPBackupsV2.FAILED)
                    return 0

                ### Rustic backup final path

                self.FinalPathRuctic = f"{self.data['BasePath']}/{self.website.domain}"

                command = f"mkdir -p {self.FinalPathRuctic}"
                ProcessUtilities.executioner(command)

                command = f'chown cyberpanel:cyberpanel {self.FinalPathRuctic}'
                ProcessUtilities.executioner(command)

                command = f"chmod 711 {self.FinalPathRuctic}"
                ProcessUtilities.executioner(command)

                ### Find Restore path first, if path is db, only then restore it to cp

                status, message = self.RestoreConfig()
                if status == 0:
                    self.UpdateStatus(f'Failed to restore config, Error {message}',
                                      CPBackupsV2.FAILED)
                    return 0

                if self.data["path"].find('.sql') > -1:
                    mysqlUtilities.restoreDatabaseBackup(self.data["path"].rstrip('.sql'), None, None, None, None, 1,
                                                         self.repo, self.website.externalApp, self.data["snapshotid"])

                else:

                    if self.data["path"].find('/home/vmail') > -1:
                        externalApp = None
                        InitialCommand = f'export RCLONE_CONFIG=/home/{self.website.domain}/.config/rclone/rclone.conf && '
                    else:
                        externalApp = self.website.externalApp
                        InitialCommand = ''

                    command = f'{InitialCommand}rustic -r {self.repo} restore {self.data["snapshotid"]}:{self.data["path"]} {self.data["path"]} --password ""  2>/dev/null'
                    result = ProcessUtilities.outputExecutioner(command, externalApp, True)

                    if os.path.exists(ProcessUtilities.debugPath):
                        logging.CyberCPLogFileWriter.writeToFile(result)

                self.UpdateStatus('Completed', CPBackupsV2.COMPLETED)

                return 1


            else:
                time.sleep(5)

                ### If website lock is there for more then 20 minutes it means old backup is stucked or backup job failed, thus continue backup

                if float(CPBackupsV2.FetchCurrentTimeStamp()) > (float(self.StartingTimeStamp) + 1200):
                    self.website = Websites.objects.get(domain=self.data['domain'])
                    self.website.BackupLock = 0
                    self.website.save()

    ### Delete Snapshots

    def DeleteSnapshots(self, deleteString):

        ### if restore then status file should be restore status file

        from websiteFunctions.models import Websites
        self.website = Websites.objects.get(domain=self.data['domain'])

        command = f'rustic -r {self.repo} forget {deleteString} --prune --password ""  2>/dev/null'
        result = ProcessUtilities.outputExecutioner(command, self.website.externalApp, True)

        if os.path.exists(ProcessUtilities.debugPath):
            logging.CyberCPLogFileWriter.writeToFile(result)

    @staticmethod
    def FetchCurrentSchedules(website):
        try:
            finalConfigPath = f'/home/cyberpanel/v2backups/{website}'

            if os.path.exists(finalConfigPath):
                command = f'cat {finalConfigPath}'
                RetResult = ProcessUtilities.outputExecutioner(command)
                print(repr(RetResult))
                BackupConfig = json.loads(ProcessUtilities.outputExecutioner(command).rstrip('\n'))

                schedules = []
                for value in BackupConfig['schedules']:

                    schedules.append({
                                      'repo': value['repo'],
                                      'frequency': value['frequency'],
                                      'websiteData': value['websiteData'],
                                      'websiteEmails': value['websiteEmails'],
                                      'websiteDatabases': value['websiteDatabases'],
                                      'lastRun': value['lastRun'],
                                      'retention': value['retention'],
                                      'domain': website
                                      })

                return 1, schedules
            else:
                return 1, []

        except BaseException as msg:
            return 0, str(msg)

    @staticmethod
    def refresh_V2Gdive_token(refresh_token):
        try:
            # refresh_token = "1//09pPJHjUgyp09CgYIARAAGAkSNgF-L9IrZ0FLMhuKVfPEwmv_6neFto3JJ-B9uXBYu1kPPdsPhSk1OJXDBA3ZvC3v_AH9S1rTIQ"

            if os.path.exists(ProcessUtilities.debugPath):
                logging.CyberCPLogFileWriter.writeToFile('Current Token: ' + refresh_token )

            finalData = json.dumps({'refresh_token': refresh_token})
            r = requests.post("https://platform.cyberpersons.com/refreshToken", data=finalData
                              )
            newtoken = json.loads(r.text)['access_token']

            if os.path.exists(ProcessUtilities.debugPath):
                logging.CyberCPLogFileWriter.writeToFile('newtoken: ' + newtoken )
                logging.CyberCPLogFileWriter.writeToFile(r.text)

            return newtoken
        except BaseException as msg:
            logging.CyberCPLogFileWriter.writeToFile(f'Error in tkupdate: {str(msg)}')
            print("Error Update token:%s" % msg)
            return None

    @staticmethod
    def DeleteSchedule(website, repo, frequency, websiteData, websiteDatabases, websiteEmails):
        try:
            finalConfigPath = f'/home/cyberpanel/v2backups/{website}'

            if os.path.exists(finalConfigPath):
                command = f'cat {finalConfigPath}'
                RetResult = ProcessUtilities.outputExecutioner(command)
                print(repr(RetResult))
                BackupConfig = json.loads(ProcessUtilities.outputExecutioner(command).rstrip('\n'))
                counter = 0

                for value in BackupConfig['schedules']:

                    if value['repo'] == repo and value['frequency'] == frequency and value['websiteData'] == websiteData and \
                            value['websiteEmails'] == websiteEmails and value['websiteDatabases'] == websiteDatabases:
                        del BackupConfig['schedules'][counter]
                        break
                    else:
                        counter = counter  + 1

                FinalContent = json.dumps(BackupConfig)
                WriteToFile = open(finalConfigPath, 'w')
                WriteToFile.write(FinalContent)
                WriteToFile.close()

                return 1, BackupConfig
            else:
                return 1, []

        except BaseException as msg:
            return 0, str(msg)

    @staticmethod
    def CreateScheduleV2(website, repo, frequency, websiteData, websiteDatabases, websiteEmails, retention):
        try:

            finalConfigPath = f'/home/cyberpanel/v2backups/{website}'

            if not os.path.exists('/home/cyberpanel/v2backups/'):

                command = 'mkdir -p /home/cyberpanel/v2backups/'
                ProcessUtilities.executioner(command, 'cyberpanel')


            if os.path.exists(finalConfigPath):

                command = f'cat {finalConfigPath}'
                RetResult = ProcessUtilities.outputExecutioner(command)
                print(repr(RetResult))
                BackupConfig = json.loads(ProcessUtilities.outputExecutioner(command).rstrip('\n'))

                try:
                    BackupConfig['schedules'].append({"repo": repo, "retention": retention, "frequency": frequency, "websiteData": websiteData,
                                      "websiteEmails": websiteEmails, "websiteDatabases": websiteDatabases,
                                      "lastRun": ""})
                except:
                    BackupConfig['schedules'] = [{"repo": repo, "retention": retention, "frequency": frequency, "websiteData": websiteData,
                                      "websiteEmails": websiteEmails, "websiteDatabases": websiteDatabases,
                                      "lastRun": ""}]

                # BackupConfig['schedules'] = {"retention": "7", "frequency": frequency, "websiteData": websiteData,
                #                       "websiteEmails": websiteEmails, "websiteDatabases": websiteDatabases,
                #                       "lastRun": ""}

                FinalContent = json.dumps(BackupConfig)
                WriteToFile = open(finalConfigPath, 'w')
                WriteToFile.write(FinalContent)
                WriteToFile.close()
                return 1, BackupConfig
            else:
                BackupConfig = {'site': website,
                                'schedules':
                                    [{"repo": repo, "retention": retention, "frequency": frequency,
                                      "websiteData": websiteData,
                                      "websiteEmails": websiteEmails, "websiteDatabases": websiteDatabases,
                                      "lastRun": ""}]}

                FinalContent = json.dumps(BackupConfig)
                WriteToFile = open(finalConfigPath, 'w')
                WriteToFile.write(FinalContent)
                WriteToFile.close()

                return 1, BackupConfig

        except BaseException as msg:
            return 0, str(msg)



    @staticmethod
    def DeleteRepoScheduleV2(website, repo, eu):
        try:
            finalConfigPath = f'/home/{website}/.config/rclone/rclone.conf'

            if os.path.exists(finalConfigPath):
                command = f"sed -i '/\[{repo}\]/,/^$/d' {finalConfigPath}"
                ProcessUtilities.outputExecutioner(command, eu, True)


                return 1, 'Done'
            else:
                return 0, "Repo not found!"
        except BaseException as msg:
            return 0, str(msg)
    # def BackupEmails(self):
    #
    #     ### This function will backup emails of the website, also need to take care of emails that we need to exclude
    #     ### excluded emails are in a list self.data['ExcludedEmails'] only backup data if backupemail check is on
    #     ## For example if self.data['BackupEmails'] is one then only run this function otherwise not
    #
    #     destination = f'{self.FinalPath}/emails'
    #     source = f'/home/vmail/{self.website.domain}'
    #
    #     ## Pending add user provided folders in the exclude list
    #
    #     exclude = f'--exclude=.cache --exclude=.cache --exclude=.cache --exclude=.wp-cli ' \
    #               f'--exclude=backup --exclude=incbackup --exclude=incbackup --exclude=logs --exclude=lscache'
    #
    #     command = f'mkdir -p {destination}'
    #     ProcessUtilities.executioner(command, 'cyberpanel')
    #
    #     command = f'chown vmail:vmail {destination}'
    #     ProcessUtilities.executioner(command)
    #
    #     command = f'rsync -av  {source}/ {destination}/'
    #     ProcessUtilities.executioner(command, 'vmail')
    #
    #     return 1

    # def BackupDataBases(self):
    #
    #     ### This function will backup databases of the website, also need to take care of database that we need to exclude
    #     ### excluded databases are in a list self.data['ExcludedDatabases'] only backup databases if backupdatabase check is on
    #     ## For example if self.data['BackupDatabase'] is one then only run this function otherwise not
    #
    #     command = f'chown {self.website.externalApp}:{self.website.externalApp} {self.FinalPathRuctic}'
    #     ProcessUtilities.executioner(command)
    #
    #     command = f'rustic init -r {self.FinalPathRuctic} --password ""'
    #     ProcessUtilities.executioner(command, self.website.externalApp)
    #
    #     command = f'chown cyberpanel:cyberpanel {self.FinalPathRuctic}'
    #     ProcessUtilities.executioner(command)
    #
    #     from plogical.mysqlUtilities import mysqlUtilities
    #
    #     for dbs in self.config['databases']:
    #
    #         ### Pending: Need to only backup database present in the list of databases that need backing up
    #
    #         for key, value in dbs.items():
    #             print(f'DB {key}')
    #
    #             if mysqlUtilities.createDatabaseBackup(key, self.FinalPath) == 0:
    #                 self.UpdateStatus(f'Failed to create backup for database {key}.', CPBackupsV2.RUNNING)
    #                 return 0
    #
    #             for dbUsers in value:
    #                 print(f'User: {dbUsers["user"]}, Host: {dbUsers["host"]}, Pass: {dbUsers["password"]}')
    #
    #
    #
    #     return 1

    # def BackupData(self):
    #
    #     ### This function will backup data of the website, also need to take care of directories that we need to exclude
    #     ### excluded directories are in a list self.data['ExcludedDirectories'] only backup data if backupdata check is on
    #     ## For example if self.data['BackupData'] is one then only run this function otherwise not
    #
    #     destination = f'{self.FinalPath}/data'
    #     source = f'/home/{self.website.domain}'
    #
    #     ## Pending add user provided folders in the exclude list
    #
    #     exclude = f'--exclude=.cache --exclude=.cache --exclude=.cache --exclude=.wp-cli ' \
    #               f'--exclude=backup --exclude=incbackup --exclude=incbackup --exclude=logs --exclude=lscache'
    #
    #     command = f'mkdir -p {destination}'
    #     ProcessUtilities.executioner(command, 'cyberpanel')
    #
    #     command = f'chown {self.website.externalApp}:{self.website.externalApp} {destination}'
    #     ProcessUtilities.executioner(command)
    #
    #     command = f'rsync -av {exclude}  {source}/ {destination}/'
    #     ProcessUtilities.executioner(command, self.website.externalApp)
    #
    #     return 1

    def InstallRustic(self):
        try:

            if not os.path.exists(CPBackupsV2.RUSTIC_PATH):

                ### also install rclone

                command = 'curl https://rclone.org/install.sh | sudo bash'
                ProcessUtilities.executioner(command, None, True)



                url = "https://api.github.com/repos/rustic-rs/rustic/releases/latest"
                response = requests.get(url)

                if response.status_code == 200:
                    data = response.json()
                    version = data['tag_name']
                    name = data['name']
                else:
                    return 0, str(response.content)

                # sudo mv filename /usr/bin/
                from plogical.acl import ACLManager

                if ACLManager.ISARM():
                    command = 'wget -P /home/rustic https://github.com/rustic-rs/rustic/releases/download/%s/rustic-%s-aarch64-unknown-linux-gnu.tar.gz' % (
                        version, version)
                    ProcessUtilities.executioner(command)

                    command = 'tar xzf /home/rustic/rustic-%s-aarch64-unknown-linux-gnu.tar.gz -C /home/rustic//' % (
                        version)
                    ProcessUtilities.executioner(command)

                else:
                    command = 'wget -P /home/rustic https://github.com/rustic-rs/rustic/releases/download/%s/rustic-%s-x86_64-unknown-linux-musl.tar.gz' % (
                version, version)
                    ProcessUtilities.executioner(command)

                    command = 'tar xzf /home/rustic/rustic-%s-x86_64-unknown-linux-musl.tar.gz -C /home/rustic//' % (
                        version)
                    ProcessUtilities.executioner(command)

                command = 'sudo mv /home/rustic/rustic /usr/bin/'
                ProcessUtilities.executioner(command)

                command = 'rm -rf /home/rustic'
                ProcessUtilities.executioner(command)

            return 1, None

        except BaseException as msg:
            print('Error: %s' % msg)
            return 0, str(msg)


if __name__ == "__main__":
    try:
        parser = argparse.ArgumentParser(description='CyberPanel Backup Generator')
        parser.add_argument('function', help='Specify a function to call!')
        parser.add_argument('--path', help='')

        args = parser.parse_args()

        if args.function == "BackupDataBases":
            cpbuv2 = CPBackupsV2({'finalPath': args.path})
            # cpbuv2.BackupDataBases()

    except:
        cpbuv2 = CPBackupsV2(
            {'function': 'InitiateRestore', 'domain': 'cyberpanel.net', 'BasePath': '/home/backup', 'SnapShotID': 1,
             'BackendName': 'usman'})
        cpbuv2.InitiateRestore()