From 6f5e49de795e26b5c94366baf3a44df34dfba6bb Mon Sep 17 00:00:00 2001 From: Michael Kaufmann Date: Wed, 7 Jun 2023 20:57:58 +0200 Subject: [PATCH] integrate backup/access_backup fields into Customers Signed-off-by: Michael Kaufmann --- admin_customers.php | 41 ++++++++++++ install/froxlor.sql.php | 11 +-- lib/Froxlor/Api/Commands/Customers.php | 67 +++++++++++++++++-- lib/Froxlor/UI/Callbacks/Backup.php | 50 ++++++++++++++ .../admin/customer/formfield.customer_add.php | 17 ++++- .../customer/formfield.customer_edit.php | 17 ++++- lib/navigation/00.froxlor.main.php | 3 +- .../admin/tablelisting.customers.php | 15 +++++ 8 files changed, 205 insertions(+), 16 deletions(-) create mode 100644 lib/Froxlor/UI/Callbacks/Backup.php diff --git a/admin_customers.php b/admin_customers.php index 4a403a79..ae4f434a 100644 --- a/admin_customers.php +++ b/admin_customers.php @@ -27,6 +27,7 @@ const AREA = 'admin'; require __DIR__ . '/lib/init.php'; use Froxlor\Api\Commands\Admins; +use Froxlor\Api\Commands\BackupStorages; use Froxlor\Api\Commands\Customers; use Froxlor\Api\Commands\MysqlServer; use Froxlor\CurrentUser; @@ -224,6 +225,26 @@ if (($page == 'customers' || $page == 'overview') && $userinfo['customers'] != ' $hosting_plans[$row['id']] = $row['name']; } + // backup storages + $backup_storages = []; + if (Settings::Get('backup.enabled') == '1' && $userinfo['change_serversettings'] == '1') { + $backup_storages = [ + 0 => lng('backup.storage_none') + ]; + try { + $result_json = BackupStorages::getLocal($userinfo)->listing(); + $result_decoded = json_decode($result_json, true)['data']['list']; + foreach ($result_decoded as $storagedata) { + $backup_storages[] = [ + 'label' => $storagedata['description'] . '(' . $storagedata['type'] . ')', + 'value' => $storagedata['id'] + ]; + } + } catch (Exception $e) { + /* just none */ + } + } + $customer_add_data = include_once dirname(__FILE__) . '/lib/formfields/admin/customer/formfield.customer_add.php'; UI::view('user/form.html.twig', [ @@ -306,6 +327,26 @@ if (($page == 'customers' || $page == 'overview') && $userinfo['customers'] != ' $hosting_plans[$row['id']] = $row['name']; } + // backup storages + $backup_storages = []; + if (Settings::Get('backup.enabled') == '1' && $userinfo['change_serversettings'] == '1') { + $backup_storages = [ + 0 => lng('backup.storage_none') + ]; + try { + $result_json = BackupStorages::getLocal($userinfo)->listing(); + $result_decoded = json_decode($result_json, true)['data']['list']; + foreach ($result_decoded as $storagedata) { + $backup_storages[] = [ + 'label' => $storagedata['description'] . '(' . $storagedata['type'] . ')', + 'value' => $storagedata['id'] + ]; + } + } catch (Exception $e) { + /* just none */ + } + } + $available_admins_stmt = Database::prepare(" SELECT * FROM `" . TABLE_PANEL_ADMINS . "` WHERE (`customers` = '-1' OR `customers` > `customers_used`) diff --git a/install/froxlor.sql.php b/install/froxlor.sql.php index 1b5e4ea6..61b7a58f 100644 --- a/install/froxlor.sql.php +++ b/install/froxlor.sql.php @@ -703,15 +703,8 @@ opcache.validate_timestamps'), ('system', 'req_limit_per_interval', 60), ('system', 'req_limit_interval', 60), ('backup', 'enabled', 0), - ('backup', 'type', 'Local'), - ('backup', 'region', ''), - ('backup', 'bucket', ''), - ('backup', 'destination_path', '/srv/backups/'), - ('backup', 'hostname', ''), - ('backup', 'username', ''), - ('backup', 'password', ''), - ('backup', 'pgp_public_key', ''), - ('backup', 'retention', '3'), + ('backup', 'default_storage', '1'), + ('backup', 'default_customer_access', '1'), ('api', 'enabled', '0'), ('api', 'customer_default', '1'), ('2fa', 'enabled', '1'), diff --git a/lib/Froxlor/Api/Commands/Customers.php b/lib/Froxlor/Api/Commands/Customers.php index b6ac3c89..20105077 100644 --- a/lib/Froxlor/Api/Commands/Customers.php +++ b/lib/Froxlor/Api/Commands/Customers.php @@ -274,6 +274,13 @@ class Customers extends ApiCommand implements ResourceEntity * @param array $allowed_mysqlserver * optional, array of IDs of defined mysql-servers the customer is allowed to use, * default is to allow the default dbserver (id=0) + * @param int $backup + * optional, either 0 to disable backup for this customer or a backup-storage-id + * where backups are to be stored, requires change_serversettings permissions, + * default is system-setting backup.default_storage + * @param bool $access_backup + * optional, where the customer is allowed to view backups, default is system-setting + * default_customer_access * * @access admin * @return string json-encoded array @@ -360,6 +367,24 @@ class Customers extends ApiCommand implements ResourceEntity $p_allowed_mysqlserver = []; } + if ($this->getUserDetail('change_serversettings')) { + $backup = $this->getParam('backup', true, Settings::Get('backup.default_storage')); + if ($backup > 0) { + try { + $this->apiCall('BackupStorages.get', [ + 'id' => $backup + ]); + } catch (Exception $e) { + // not found or other issue, set default + $backup = Settings::Get('backup.default_storage'); + } + } + $access_backup = $this->getBoolParam('access_backup', true, Settings::Get('backup.default_customer_access')); + } else { + $backup = Settings::Get('backup.default_storage'); + $access_backup = Settings::Get('backup.default_customer_access'); + } + // validation $name = Validate::validate($name, 'name', Validate::REGEX_DESC_TEXT, '', [], true); $firstname = Validate::validate($firstname, 'first name', Validate::REGEX_DESC_TEXT, '', [], true); @@ -534,7 +559,9 @@ class Customers extends ApiCommand implements ResourceEntity 'theme' => $_theme, 'custom_notes' => $custom_notes, 'custom_notes_show' => $custom_notes_show, - 'allowed_mysqlserver' => empty($allowed_mysqlserver) ? "" : json_encode($allowed_mysqlserver) + 'allowed_mysqlserver' => empty($allowed_mysqlserver) ? "" : json_encode($allowed_mysqlserver), + 'backup' => $backup, + 'access_backup' => $access_backup ]; $ins_stmt = Database::prepare(" @@ -577,7 +604,9 @@ class Customers extends ApiCommand implements ResourceEntity `theme` = :theme, `custom_notes` = :custom_notes, `custom_notes_show` = :custom_notes_show, - `allowed_mysqlserver`= :allowed_mysqlserver + `allowed_mysqlserver`= :allowed_mysqlserver, + `backup` = :backup, + `access_backup` = :access_backup "); Database::pexecute($ins_stmt, $ins_data, true, true); @@ -1025,6 +1054,13 @@ class Customers extends ApiCommand implements ResourceEntity * @param array $allowed_mysqlserver * optional, array of IDs of defined mysql-servers the customer is allowed to use, * default is to allow the default dbserver (id=0) + * @param int $backup + * optional, either 0 to disable backup for this customer or a backup-storage-id + * where backups are to be stored, requires change_serversettings permissions, + * default is system-setting backup.default_storage + * @param bool $access_backup + * optional, where the customer is allowed to view backups, default is system-setting + * default_customer_access * * @access admin, customer * @return string json-encoded array @@ -1086,6 +1122,24 @@ class Customers extends ApiCommand implements ResourceEntity $deactivated = $this->getBoolParam('deactivated', true, $result['deactivated']); $theme = $this->getParam('theme', true, $result['theme']); $allowed_mysqlserver = $this->getParam('allowed_mysqlserver', true, json_decode($result['allowed_mysqlserver'], true)); + + if ($this->isAdmin() && $this->getUserDetail('change_serversettings')) { + $backup = $this->getParam('backup', true, $result['backup']); + if ($backup > 0) { + try { + $this->apiCall('BackupStorages.get', [ + 'id' => $backup + ]); + } catch (Exception $e) { + // not found or other issue, dont update + $backup = $result['backup']; + } + } + $access_backup = $this->getBoolParam('access_backup', true, Settings::Get('backup.default_customer_access')); + } else { + $backup = $result['backup']; + $access_backup = $result['access_backup']; + } } else { // allowed parameters $def_language = $this->getParam('def_language', true, $result['def_language']); @@ -1118,6 +1172,7 @@ class Customers extends ApiCommand implements ResourceEntity if (! empty($allowed_mysqlserver)) { $allowed_mysqlserver = array_map('intval', $allowed_mysqlserver); } + } $def_language = Validate::validate($def_language, 'default language', '', '', [], true); $theme = Validate::validate($theme, 'theme', '', '', [], true); @@ -1390,7 +1445,9 @@ class Customers extends ApiCommand implements ResourceEntity 'custom_notes' => $custom_notes, 'custom_notes_show' => $custom_notes_show, 'api_allowed' => $api_allowed, - 'allowed_mysqlserver' => empty($allowed_mysqlserver) ? "" : json_encode($allowed_mysqlserver) + 'allowed_mysqlserver' => empty($allowed_mysqlserver) ? "" : json_encode($allowed_mysqlserver), + 'backup' => $backup, + 'access_backup' => $access_backup ]; $upd_data += $admin_upd_data; } @@ -1433,7 +1490,9 @@ class Customers extends ApiCommand implements ResourceEntity `custom_notes` = :custom_notes, `custom_notes_show` = :custom_notes_show, `api_allowed` = :api_allowed, - `allowed_mysqlserver` = :allowed_mysqlserver"; + `allowed_mysqlserver` = :allowed_mysqlserver, + `backup`= :backup, + `access_backup` = :access_backup"; $upd_query .= $admin_upd_query; } $upd_query .= " WHERE `customerid` = :customerid"; diff --git a/lib/Froxlor/UI/Callbacks/Backup.php b/lib/Froxlor/UI/Callbacks/Backup.php new file mode 100644 index 00000000..035da2f5 --- /dev/null +++ b/lib/Froxlor/UI/Callbacks/Backup.php @@ -0,0 +1,50 @@ + + * @license https://files.froxlor.org/misc/COPYING.txt GPLv2 + */ + +namespace Froxlor\UI\Callbacks; + +use Froxlor\Database\Database; +use Froxlor\UI\Panel\UI; + +class Backup +{ + public static function backupStorageLink(array $attributes) + { + $sel_stmt = Database::prepare("SELECT `description` FROM `" . TABLE_PANEL_BACKUPSTORAGES . "` WHERE `id` = :id"); + $backupstorage = Database::pexecute_first($sel_stmt, ['id' => $attributes['data']]); + if ((int)UI::getCurrentUser()['adminsession'] == 1 && UI::getCurrentUser()['change_serversettings']) { + $linker = UI::getLinker(); + $result = '' . $backupstorage['description'] . ''; + } else { + $result = $backupstorage['description']; + } + return $result; + } +} diff --git a/lib/formfields/admin/customer/formfield.customer_add.php b/lib/formfields/admin/customer/formfield.customer_add.php index 53bb2c76..9afef260 100644 --- a/lib/formfields/admin/customer/formfield.customer_add.php +++ b/lib/formfields/admin/customer/formfield.customer_add.php @@ -89,7 +89,22 @@ return [ 'value' => '1', 'checked' => Settings::Get('api.enabled') == '1' && Settings::Get('api.customer_default'), 'visible' => Settings::Get('api.enabled') == '1' - ] + ], + 'backup' => [ + 'label' => lng('backup.backup_storage.title'), + 'desc' => lng('backup.backup_storage.description'), + 'type' => 'select', + 'select_var' => $backup_storages, + 'selected' => Settings::Get('backup.default_storage'), + 'visible' => Settings::Get('backup.enabled') == '1' && $userinfo['change_serversettings'] == '1' + ], + 'access_backup' => [ + 'label' => lng('backup.access_backup'), + 'type' => 'checkbox', + 'value' => '1', + 'checked' => Settings::Get('backup.enabled') == '1' && Settings::Get('backup.default_customer_access'), + 'visible' => Settings::Get('backup.enabled') == '1' && ($userinfo['change_serversettings'] == '1' || Settings::Get('backup.default_customer_access')) + ], ] ], 'section_b' => [ diff --git a/lib/formfields/admin/customer/formfield.customer_edit.php b/lib/formfields/admin/customer/formfield.customer_edit.php index 72d94408..0f95330f 100644 --- a/lib/formfields/admin/customer/formfield.customer_edit.php +++ b/lib/formfields/admin/customer/formfield.customer_edit.php @@ -87,7 +87,22 @@ return [ 'value' => '1', 'checked' => $result['api_allowed'], 'visible' => Settings::Get('api.enabled') == '1' - ] + ], + 'backup' => [ + 'label' => lng('backup.backup_storage.title'), + 'desc' => lng('backup.backup_storage.description'), + 'type' => 'select', + 'select_var' => $backup_storages, + 'selected' => $result['backup'], + 'visible' => Settings::Get('backup.enabled') == '1' && $userinfo['change_serversettings'] == '1' + ], + 'access_backup' => [ + 'label' => lng('backup.access_backup'), + 'type' => 'checkbox', + 'value' => '1', + 'checked' => $result['access_backup'], + 'visible' => Settings::Get('backup.enabled') == '1' && ($userinfo['change_serversettings'] == '1' || Settings::Get('backup.default_customer_access')) + ], ] ], 'section_b' => [ diff --git a/lib/navigation/00.froxlor.main.php b/lib/navigation/00.froxlor.main.php index e27c22b1..70066626 100644 --- a/lib/navigation/00.froxlor.main.php +++ b/lib/navigation/00.froxlor.main.php @@ -266,7 +266,8 @@ return [ 'url' => 'admin_backups.php?page=overview', 'label' => lng('admin.backups.backups'), 'required_resources' => 'change_serversettings', - 'add_shortlink' => 'admin_backups.php?page=overview&action=add' + 'add_shortlink' => 'admin_backups.php?page=overview&action=add', + 'show_element' => (Settings::Get('backup.enabled') == true) ], [ 'url' => 'admin_logger.php?page=log', diff --git a/lib/tablelisting/admin/tablelisting.customers.php b/lib/tablelisting/admin/tablelisting.customers.php index bfe663ce..a3ca05c3 100644 --- a/lib/tablelisting/admin/tablelisting.customers.php +++ b/lib/tablelisting/admin/tablelisting.customers.php @@ -23,6 +23,7 @@ * @license https://files.froxlor.org/misc/COPYING.txt GPLv2 */ +use Froxlor\UI\Callbacks\Backup; use Froxlor\UI\Callbacks\Customer; use Froxlor\UI\Callbacks\Impersonate; use Froxlor\UI\Callbacks\ProgressBar; @@ -149,6 +150,20 @@ return [ 'class' => 'text-center', 'callback' => [Text::class, 'boolean'], ], + 'c.backup' => [ + 'label' => lng('backup.backup_storage.title'), + 'field' => 'backup', + 'class' => 'text-center', + 'callback' => [Backup::class, 'backupStorageLink'], + 'visible' => (bool)Settings::Get('backup.enabled'), + ], + 'c.access_backup' => [ + 'label' => lng('backup.access_backup'), + 'field' => 'access_backup', + 'class' => 'text-center', + 'callback' => [Text::class, 'boolean'], + 'visible' => (bool)Settings::Get('backup.enabled'), + ], ], 'visible_columns' => Listing::getVisibleColumnsForListing('customer_list', [ 'c.name',