From a9c613e71c19b15783404d164d7d519a0f08b115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maurice=20Preu=C3=9F=20=28envoyr=29?= Date: Wed, 7 Jun 2023 20:51:53 +0200 Subject: [PATCH] update backups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurice Preuß (envoyr) --- admin_backups.php | 86 +++++- install/updates/froxlor/update_2.1.inc.php | 8 +- lib/Froxlor/Api/Commands/BackupStorages.php | 256 ++++++++++++++++++ .../formfield.backup_storage_add.php | 90 ++++++ .../formfield.backup_storage_edit.php | 97 +++++++ .../admin/backup_storages/index.html | 0 .../admin/backups/formfield.backups_add.php | 2 +- .../backups/formfield.backups_restore.php | 2 +- .../admin/tablelisting.backup_storages.php | 129 +++++++++ .../admin/tablelisting.backups.php | 4 +- lib/tables.inc.php | 1 + 11 files changed, 666 insertions(+), 9 deletions(-) create mode 100644 lib/Froxlor/Api/Commands/BackupStorages.php create mode 100644 lib/formfields/admin/backup_storages/formfield.backup_storage_add.php create mode 100644 lib/formfields/admin/backup_storages/formfield.backup_storage_edit.php create mode 100644 lib/formfields/admin/backup_storages/index.html create mode 100644 lib/tablelisting/admin/tablelisting.backup_storages.php diff --git a/admin_backups.php b/admin_backups.php index d34933f0..8c7f29df 100644 --- a/admin_backups.php +++ b/admin_backups.php @@ -27,6 +27,7 @@ const AREA = 'admin'; require __DIR__ . '/lib/init.php'; use Froxlor\Api\Commands\Backups; +use Froxlor\Api\Commands\BackupStorages; use Froxlor\FroxlorLogger; use Froxlor\UI\Collection; use Froxlor\UI\Listing; @@ -36,7 +37,7 @@ use Froxlor\UI\Response; $id = (int)Request::any('id'); -if (($page == 'admins' || $page == 'overview') && $userinfo['change_serversettings'] == '1') { +if (($page == 'backups' || $page == 'overview') && $userinfo['change_serversettings'] == '1') { if ($action == '') { $log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "viewed admin_backups"); @@ -60,6 +61,12 @@ if (($page == 'admins' || $page == 'overview') && $userinfo['change_serversettin 'label' => lng('admin.backups_restore'), 'icon' => 'fa-solid fa-file-import', 'class' => 'btn-outline-secondary' + ], + [ + 'href' => $linker->getLink(['section' => 'backups', 'page' => 'storages']), + 'label' => lng('admin.backup_storages'), + 'icon' => 'fa-solid fa-hard-drive', + 'class' => 'btn-outline-secondary' ] ] ]); @@ -72,4 +79,81 @@ if (($page == 'admins' || $page == 'overview') && $userinfo['change_serversettin } elseif ($action == 'restore') { } +} else if ($page == 'storages' && $userinfo['change_serversettings'] == '1') { + if ($action == '') { + $log->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "viewed admin_backup_storage"); + + try { + $admin_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/admin/tablelisting.backup_storages.php'; + $collection = (new Collection(BackupStorages::class, $userinfo)) + ->withPagination($admin_list_data['backup_storages_list']['columns'], $admin_list_data['backup_storages_list']['default_sorting']); + } catch (Exception $e) { + Response::dynamicError($e->getMessage()); + } + + UI::view('user/table.html.twig', [ + 'listing' => Listing::format($collection, $admin_list_data, 'backup_storages_list'), + 'actions_links' => [ + [ + 'href' => $linker->getLink(['section' => 'backups', 'page' => 'backups']), + 'label' => lng('admin.backups'), + 'icon' => 'fa-solid fa-reply' + ], + [ + 'href' => $linker->getLink(['section' => 'backups', 'page' => $page, 'action' => 'add']), + 'label' => lng('admin.backup_storage_add') + ] + ] + ]); + } elseif ($action == 'delete' && $id != 0) { + + } elseif ($action == 'add') { + if (isset($_POST['send']) && $_POST['send'] == 'send') { + try { + BackupStorages::getLocal($userinfo, $_POST)->add(); + } catch (Exception $e) { + Response::dynamicError($e->getMessage()); + } + Response::redirectTo($filename, [ + 'page' => $page + ]); + } else { + $admin_add_data = include_once dirname(__FILE__) . '/lib/formfields/admin/backup_storages/formfield.backup_storage_add.php'; + + UI::view('user/form.html.twig', [ + 'formaction' => $linker->getLink(['section' => 'backups']), + 'formdata' => $admin_add_data['backup_storage_add'] + ]); + } + } elseif ($action == 'edit' && $id != 0) { + try { + $json_result = BackupStorages::getLocal($userinfo, [ + 'id' => $id + ])->get(); + } catch (Exception $e) { + Response::dynamicError($e->getMessage()); + } + $result = json_decode($json_result, true)['data']; + + if ($result['id'] != '') { + if (isset($_POST['send']) && $_POST['send'] == 'send') { + try { + BackupStorages::getLocal($userinfo, $_POST)->update(); + } catch (Exception $e) { + Response::dynamicError($e->getMessage()); + } + Response::redirectTo($filename, [ + 'page' => $page + ]); + } else { + $backup_storage_edit_data = include_once dirname(__FILE__) . '/lib/formfields/admin/backup_storages/formfield.backup_storage_edit.php'; + + UI::view('user/form.html.twig', [ + 'formaction' => $linker->getLink(['section' => 'backups', 'id' => $id]), + 'formdata' => $backup_storage_edit_data['backup_storage_edit'], + 'editid' => $id + ]); + } + } + } } diff --git a/install/updates/froxlor/update_2.1.inc.php b/install/updates/froxlor/update_2.1.inc.php index 6d304094..f19b2d7f 100644 --- a/install/updates/froxlor/update_2.1.inc.php +++ b/install/updates/froxlor/update_2.1.inc.php @@ -63,8 +63,8 @@ if (Froxlor::isDatabaseVersion('202304260')) { } Update::showUpdateStep("Creating new tables and fields for backups"); - Database::query("DROP TABLE IF EXISTS `panel_backup_storages`;"); - $sql = "CREATE TABLE `panel_backup_storages` ( + Database::query("DROP TABLE IF EXISTS `". TABLE_PANEL_BACKUP_STORAGES ."`;"); + $sql = "CREATE TABLE `". TABLE_PANEL_BACKUP_STORAGES ."` ( `id` int(11) NOT NULL AUTO_INCREMENT, `description` varchar(255) NOT NULL, `type` varchar(255) NOT NULL DEFAULT 'local', @@ -83,8 +83,8 @@ if (Froxlor::isDatabaseVersion('202304260')) { INSERT INTO `panel_backup_storages` (`id`, `description`, `destination_path`) VALUES (1, 'Local backup storage', '/var/customers/backups'); "); - Database::query("DROP TABLE IF EXISTS `panel_backups`;"); - $sql = "CREATE TABLE `panel_backups` ( + Database::query("DROP TABLE IF EXISTS `". TABLE_PANEL_BACKUPS ."`;"); + $sql = "CREATE TABLE `". TABLE_PANEL_BACKUPS ."` ( `id` int(11) NOT NULL AUTO_INCREMENT, `adminid` int(11) NOT NULL, `customerid` int(11) NOT NULL, diff --git a/lib/Froxlor/Api/Commands/BackupStorages.php b/lib/Froxlor/Api/Commands/BackupStorages.php new file mode 100644 index 00000000..6cb1ccb5 --- /dev/null +++ b/lib/Froxlor/Api/Commands/BackupStorages.php @@ -0,0 +1,256 @@ + + * @license https://files.froxlor.org/misc/COPYING.txt GPLv2 + */ + +namespace Froxlor\Api\Commands; + +use Exception; +use Froxlor\Api\ApiCommand; +use Froxlor\Api\ResourceEntity; +use Froxlor\Database\Database; +use Froxlor\FileDir; +use Froxlor\FroxlorLogger; +use Froxlor\UI\Response; +use Froxlor\Validate\Validate; +use PDO; + +/** + * @since 2.1.0 + */ +class BackupStorages extends ApiCommand implements ResourceEntity +{ + /** + * lists all backup storages entries + * + * @param array $sql_search + * optional array with index = fieldname, and value = array with 'op' => operator (one of <, > or =), + * LIKE is used if left empty and 'value' => searchvalue + * @param int $sql_limit + * optional specify number of results to be returned + * @param int $sql_offset + * optional specify offset for resultset + * @param array $sql_orderby + * optional array with index = fieldname and value = ASC|DESC to order the resultset by one or more + * fields + * + * @access admin + * @return string json-encoded array count|list + * @throws Exception + */ + public function listing() + { + if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) { + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] list backups"); + $query_fields = []; + $result_stmt = Database::prepare(" + SELECT * FROM `" . TABLE_PANEL_BACKUP_STORAGES . "` + "); + Database::pexecute($result_stmt, $query_fields, true, true); + $result = []; + while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) { + $result[] = $row; + } + return $this->response([ + 'count' => count($result), + 'list' => $result + ]); + } + throw new Exception("Not allowed to execute given command.", 403); + } + + /** + * returns the total number of backup storages + * + * @access admin + * @return string json-encoded response message + * @throws Exception + */ + public function listingCount() + { + if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) { + $result_stmt = Database::prepare(" + SELECT COUNT(*) as num_backup_storagess + FROM `" . TABLE_PANEL_BACKUP_STORAGES . "` + "); + $result = Database::pexecute_first($result_stmt, null, true, true); + if ($result) { + return $this->response($result['num_backup_storagess']); + } + $this->response(0); + } + throw new Exception("Not allowed to execute given command.", 403); + } + + /** + * create a backup storage by given id + * + * @param string $name + * + * @access admin + * @return string json-encoded array + * @throws Exception + */ + public function add() + { + if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) { + // + } + throw new Exception("Not allowed to execute given command.", 403); + } + + /** + * return an admin entry by id + * + * @param int $id + * optional, the backup-storage-id + * + * @access admin + * @return string json-encoded array + * @throws Exception + */ + public function get() + { + $id = $this->getParam('id'); + + if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) { + $result_stmt = Database::prepare(" + SELECT * FROM `" . TABLE_PANEL_BACKUP_STORAGES . "` + WHERE `id` = :id" + ); + $params = [ + 'id' => $id + ]; + $result = Database::pexecute_first($result_stmt, $params, true, true); + if ($result) { + $this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] get backup storage for '" . $result['id'] . "'"); + return $this->response($result); + } + throw new Exception("Backup storage with " . $id . " could not be found", 404); + } + throw new Exception("Not allowed to execute given command.", 403); + } + + /** + * update a backup storage by given id + * + * @param int $id + * required, the backup-storage-id + * + * @access admin + * @return string json-encoded array + * @throws Exception + */ + public function update() + { + $id = $this->getParam('id'); + + if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) { + // validation + $result = $this->apiCall('BackupStorages.get', [ + 'id' => $id + ]); + + // parameters + $description = $this->getParam('description', true, $result['description']); + $type = $this->getParam('type', true, $result['type']); + $region = $this->getParam('region', true, $result['region']); + $bucket = $this->getParam('bucket', true, $result['bucket']); + $destination_path = $this->getParam('destination_path', true, $result['destination_path']); + $hostname = $this->getParam('hostname', true, $result['hostname']); + $username = $this->getParam('username', true, $result['username']); + $password = $this->getParam('password', true, 'password'); + $pgp_public_key = $this->getParam('pgp_public_key', true, $result['pgp_public_key']); + $retention = $this->getParam('retention', true, $result['retention']); + + // validation + $destination_path = FileDir::makeCorrectDir(Validate::validate($destination_path, 'destination_path', Validate::REGEX_DIR, '', [], true)); + + // pgp public key validation + if (!empty($pgp_public_key)) { + // check if gnupg extension is loaded + if (!extension_loaded('gnupg')) { + Response::standardError('gnupgextensionnotavailable', '', true); + } + // check if the pgp public key is a valid key + putenv('GNUPGHOME='.sys_get_temp_dir()); + if (gnupg_import(gnupg_init(), $pgp_public_key) === false) { + Response::standardError('invalidpgppublickey', '', true); + } + } + + // update + $stmt = Database::prepare(" + UPDATE `" . TABLE_PANEL_BACKUP_STORAGES . "` + SET `description` = :description, + `type` = :type, + `region` = :region, + `bucket` = :bucket, + `destination_path` = :destination_path, + `hostname` = :hostname, + `username` = :username, + `password` = :password, + `pgp_public_key` = :pgp_public_key, + `retention` = :retention + WHERE `id` = :id + "); + $params = [ + "id" => $id, + "description" => $description, + "type" => $type, + "region" => $region, + "bucket" => $bucket, + "destination_path" => $destination_path, + "hostname" => $hostname, + "username" => $username, + "password" => $password, + "pgp_public_key" => $pgp_public_key, + "retention" => $retention, + ]; + Database::pexecute($stmt, $params, true, true); + $this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] edited backup storage for '" . $result['id'] . "'"); + + // return + $result = $this->apiCall('BackupStorages.get', [ + 'id' => $id + ]); + return $this->response($result); + } + throw new Exception("Not allowed to execute given command.", 403); + } + + /** + * delete a backup-storage entry by either id + * + * @param int $id + * required, the backup-storage-id + * + * @access admin + * @return string json-encoded array + * @throws Exception + */ + public function delete() + { + throw new Exception("Not allowed to execute given command.", 403); + } +} diff --git a/lib/formfields/admin/backup_storages/formfield.backup_storage_add.php b/lib/formfields/admin/backup_storages/formfield.backup_storage_add.php new file mode 100644 index 00000000..a9a51647 --- /dev/null +++ b/lib/formfields/admin/backup_storages/formfield.backup_storage_add.php @@ -0,0 +1,90 @@ + + * @license https://files.froxlor.org/misc/COPYING.txt GPLv2 + */ + +use Froxlor\Settings; + +return [ + 'backup_storage_add' => [ + 'title' => lng('backups.backup_storage_add'), + 'image' => 'fa-solid fa-file-archive', + 'self_overview' => ['section' => 'backups', 'page' => 'storages'], + 'sections' => [ + 'section_a' => [ + 'title' => lng('backup.backup_storage_create'), + 'fields' => [ + 'description' => [ + 'label' => lng('backup.backup_storage.description'), + 'type' => 'text' + ], + 'type' => [ + 'label' => lng('backup.backup_storage.type'), + 'type' => 'select', + 'selected' => 'local', + 'select_var' => [ + 'local' => lng('backup.backup_storage.type_local'), + 'ftp' => lng('backup.backup_storage.type_ftp'), + 'sftp' => lng('backup.backup_storage.type_sftp'), + 'rsync' => lng('backup.backup_storage.type_rsync'), + 's3' => lng('backup.backup_storage.type_s3'), + ] + ], + 'region' => [ + 'label' => lng('backup.backup_storage.region'), + 'type' => 'text' + ], + 'bucket' => [ + 'label' => lng('backup.backup_storage.bucket'), + 'type' => 'text' + ], + 'destination_path' => [ + 'label' => lng('backup.backup_storage.destination_path'), + 'type' => 'text' + ], + 'hostname' => [ + 'label' => lng('backup.backup_storage.hostname'), + 'type' => 'text' + ], + 'username' => [ + 'label' => lng('backup.backup_storage.username'), + 'type' => 'text' + ], + 'password' => [ + 'label' => lng('backup.backup_storage.password'), + 'type' => 'text' + ], + 'pgp_public_key' => [ + 'label' => lng('backup.backup_storage.pgp_public_key'), + 'type' => 'textarea', + ], + 'retention' => [ + 'label' => lng('backup.backup_storage.retention'), + 'type' => 'number', + 'min' => 0, + ] + ] + ] + ] + ], +]; diff --git a/lib/formfields/admin/backup_storages/formfield.backup_storage_edit.php b/lib/formfields/admin/backup_storages/formfield.backup_storage_edit.php new file mode 100644 index 00000000..ac283615 --- /dev/null +++ b/lib/formfields/admin/backup_storages/formfield.backup_storage_edit.php @@ -0,0 +1,97 @@ + + * @license https://files.froxlor.org/misc/COPYING.txt GPLv2 + */ + +return [ + 'backup_storage_edit' => [ + 'title' => lng('backups.backup_storage_edit'), + 'image' => 'fa-solid fa-file-archive', + 'self_overview' => ['section' => 'backups', 'page' => 'storages'], + 'sections' => [ + 'section_a' => [ + 'title' => lng('backup.backup_storage_edit'), + 'fields' => [ + 'description' => [ + 'label' => lng('backup.backup_storage.description'), + 'type' => 'text', + 'value' => $result['description'] + ], + 'type' => [ + 'label' => lng('backup.backup_storage.type'), + 'type' => 'select', + 'selected' => $result['type'], + 'select_var' => [ + 'local' => lng('backup.backup_storage.type_local'), + 'ftp' => lng('backup.backup_storage.type_ftp'), + 'sftp' => lng('backup.backup_storage.type_sftp'), + 'rsync' => lng('backup.backup_storage.type_rsync'), + 's3' => lng('backup.backup_storage.type_s3'), + ] + ], + 'region' => [ + 'label' => lng('backup.backup_storage.region'), + 'type' => 'text', + 'value' => $result['region'] + ], + 'bucket' => [ + 'label' => lng('backup.backup_storage.bucket'), + 'type' => 'text', + 'value' => $result['bucket'] + ], + 'destination_path' => [ + 'label' => lng('backup.backup_storage.destination_path'), + 'type' => 'text', + 'value' => $result['destination_path'] + ], + 'hostname' => [ + 'label' => lng('backup.backup_storage.hostname'), + 'type' => 'text', + 'value' => $result['hostname'] + ], + 'username' => [ + 'label' => lng('backup.backup_storage.username'), + 'type' => 'text', + 'value' => $result['username'] + ], + 'password' => [ + 'label' => lng('backup.backup_storage.password'), + 'type' => 'password', + 'autocomplete' => 'off' + ], + 'pgp_public_key' => [ + 'label' => lng('backup.backup_storage.pgp_public_key'), + 'type' => 'textarea', + 'value' => $result['pgp_public_key'] + ], + 'retention' => [ + 'label' => lng('backup.backup_storage.retention'), + 'type' => 'number', + 'min' => 0, + 'value' => $result['retention'] + ] + ] + ] + ] + ], +]; diff --git a/lib/formfields/admin/backup_storages/index.html b/lib/formfields/admin/backup_storages/index.html new file mode 100644 index 00000000..e69de29b diff --git a/lib/formfields/admin/backups/formfield.backups_add.php b/lib/formfields/admin/backups/formfield.backups_add.php index 2b2546ab..9aba2c5d 100644 --- a/lib/formfields/admin/backups/formfield.backups_add.php +++ b/lib/formfields/admin/backups/formfield.backups_add.php @@ -27,7 +27,7 @@ return [ 'backups_add' => [ 'title' => lng('backups.backups_add'), 'image' => 'fa-solid fa-file-archive', - 'self_overview' => ['section' => 'backups', 'page' => 'backups'], + 'self_overview' => ['section' => 'backups', 'page' => 'storages'], 'sections' => [] ], ]; diff --git a/lib/formfields/admin/backups/formfield.backups_restore.php b/lib/formfields/admin/backups/formfield.backups_restore.php index f146bdec..36b13fcf 100644 --- a/lib/formfields/admin/backups/formfield.backups_restore.php +++ b/lib/formfields/admin/backups/formfield.backups_restore.php @@ -27,7 +27,7 @@ return [ 'backups_restore' => [ 'title' => lng('backups.backups_restore'), 'image' => 'fa-solid fa-file-archive', - 'self_overview' => ['section' => 'backups', 'page' => 'backups'], + 'self_overview' => ['section' => 'backups', 'page' => 'storages'], 'sections' => [] ], ]; diff --git a/lib/tablelisting/admin/tablelisting.backup_storages.php b/lib/tablelisting/admin/tablelisting.backup_storages.php new file mode 100644 index 00000000..b0811ec8 --- /dev/null +++ b/lib/tablelisting/admin/tablelisting.backup_storages.php @@ -0,0 +1,129 @@ + + * @license https://files.froxlor.org/misc/COPYING.txt GPLv2 + */ + +use Froxlor\UI\Callbacks\Admin; +use Froxlor\UI\Callbacks\Customer; +use Froxlor\UI\Callbacks\Impersonate; +use Froxlor\UI\Callbacks\ProgressBar; +use Froxlor\UI\Callbacks\Style; +use Froxlor\UI\Callbacks\Text; +use Froxlor\UI\Listing; + +return [ + 'backup_storages_list' => [ + 'title' => lng('backup.backup_storages.list'), + 'icon' => 'fa-solid fa-file-archive', + 'self_overview' => ['section' => 'backups', 'page' => 'storages'], + 'default_sorting' => ['loginname' => 'asc'], + 'columns' => [ + 'id' => [ + 'label' => 'ID', + 'field' => 'id', + 'sortable' => true, + ], + 'description' => [ + 'label' => lng('description'), + 'field' => 'description', + 'sortable' => true, + ], + 'type' => [ + 'label' => lng('type'), + 'field' => 'type', + 'sortable' => true, + ], + 'region' => [ + 'label' => lng('region'), + 'field' => 'region', + 'sortable' => true, + ], + 'bucket' => [ + 'label' => lng('bucket'), + 'field' => 'bucket', + 'sortable' => true, + ], + 'destination_path' => [ + 'label' => lng('destination_path'), + 'field' => 'destination_path', + 'sortable' => true, + ], + 'hostname' => [ + 'label' => lng('hostname'), + 'field' => 'hostname', + 'sortable' => true, + ], + 'username' => [ + 'label' => lng('username'), + 'field' => 'username', + 'sortable' => true, + ], + 'retention' => [ + 'label' => lng('retention'), + 'field' => 'retention', + 'sortable' => true, + ], + ], + 'visible_columns' => Listing::getVisibleColumnsForListing('admin_list', [ + 'id', + 'description', + 'type', + 'retention', + ]), + 'actions' => [ + 'show' => [ + 'icon' => 'fa-solid fa-eye', + 'title' => lng('usersettings.custom_notes.title'), + 'modal' => [Text::class, 'customerNoteDetailModal'], + 'visible' => [Customer::class, 'hasNote'] + ], + 'edit' => [ + 'icon' => 'fa-solid fa-edit', + 'title' => lng('panel.edit'), + 'href' => [ + 'section' => 'backups', + 'page' => 'storages', + 'action' => 'edit', + 'id' => ':id' + ], + ], + 'delete' => [ + 'icon' => 'fa-solid fa-trash', + 'title' => lng('panel.delete'), + 'class' => 'btn-danger', + 'href' => [ + 'section' => 'backups', + 'page' => 'storages', + 'action' => 'delete', + 'id' => ':id' + ], + 'visible' => [Admin::class, 'isNotMe'] + ], + ], + 'format_callback' => [ + [Style::class, 'deactivated'], + [Style::class, 'diskspaceWarning'], + [Style::class, 'trafficWarning'] + ] + ] +]; diff --git a/lib/tablelisting/admin/tablelisting.backups.php b/lib/tablelisting/admin/tablelisting.backups.php index b5b2b20e..96db9d1d 100644 --- a/lib/tablelisting/admin/tablelisting.backups.php +++ b/lib/tablelisting/admin/tablelisting.backups.php @@ -95,7 +95,7 @@ return [ 'title' => lng('panel.edit'), 'href' => [ 'section' => 'backups', - 'page' => 'backups', + 'page' => 'storages', 'action' => 'edit', 'id' => ':id' ], @@ -106,7 +106,7 @@ return [ 'class' => 'btn-danger', 'href' => [ 'section' => 'backups', - 'page' => 'backups', + 'page' => 'storages', 'action' => 'delete', 'id' => ':id' ], diff --git a/lib/tables.inc.php b/lib/tables.inc.php index f385091d..2e8d1fa9 100644 --- a/lib/tables.inc.php +++ b/lib/tables.inc.php @@ -33,6 +33,7 @@ const TABLE_MAIL_VIRTUAL = 'mail_virtual'; const TABLE_PANEL_ACTIVATION = 'panel_activation'; const TABLE_PANEL_ADMINS = 'panel_admins'; const TABLE_PANEL_BACKUPS = 'panel_backups'; +const TABLE_PANEL_BACKUP_STORAGES = 'panel_backup_storages'; const TABLE_PANEL_CUSTOMERS = 'panel_customers'; const TABLE_PANEL_DATABASES = 'panel_databases'; const TABLE_PANEL_DOMAINS = 'panel_domains';