update backup cron

Signed-off-by: Maurice Preuß (envoyr) <envoyr@froxlor.org>
This commit is contained in:
Maurice Preuß (envoyr)
2023-06-08 17:17:25 +02:00
parent 8a30bc07f5
commit 105213fd3f
9 changed files with 128 additions and 105 deletions

View File

@@ -38,7 +38,7 @@ use Froxlor\UI\Response;
$id = (int)Request::any('id'); $id = (int)Request::any('id');
if (($page == 'backups' || $page == 'overview') && $userinfo['change_serversettings'] == '1') { if (($page == 'backups' || $page == 'overview')) {
if ($action == '') { if ($action == '') {
$log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "viewed admin_backups"); $log->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "viewed admin_backups");
@@ -53,10 +53,6 @@ if (($page == 'backups' || $page == 'overview') && $userinfo['change_serversetti
UI::view('user/table.html.twig', [ UI::view('user/table.html.twig', [
'listing' => Listing::format($collection, $admin_list_data, 'backups_list'), 'listing' => Listing::format($collection, $admin_list_data, 'backups_list'),
'actions_links' => [ 'actions_links' => [
[
'href' => $linker->getLink(['section' => 'backups', 'page' => $page, 'action' => 'add']),
'label' => lng('admin.backups_add')
],
[ [
'href' => $linker->getLink(['section' => 'backups', 'page' => $page, 'action' => 'restore']), 'href' => $linker->getLink(['section' => 'backups', 'page' => $page, 'action' => 'restore']),
'label' => lng('admin.backups_restore'), 'label' => lng('admin.backups_restore'),
@@ -67,7 +63,8 @@ if (($page == 'backups' || $page == 'overview') && $userinfo['change_serversetti
'href' => $linker->getLink(['section' => 'backups', 'page' => 'storages']), 'href' => $linker->getLink(['section' => 'backups', 'page' => 'storages']),
'label' => lng('admin.backup_storages'), 'label' => lng('admin.backup_storages'),
'icon' => 'fa-solid fa-hard-drive', 'icon' => 'fa-solid fa-hard-drive',
'class' => 'btn-outline-secondary' 'class' => 'btn-outline-secondary',
'visible' => $userinfo['change_serversettings'] == '1'
] ]
] ]
]); ]);
@@ -181,4 +178,6 @@ if (($page == 'backups' || $page == 'overview') && $userinfo['change_serversetti
} }
} }
} }
} else {
Response::dynamicError('403');
} }

View File

@@ -63,24 +63,55 @@ class Backups extends ApiCommand implements ResourceEntity
*/ */
public function listing() public function listing()
{ {
if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) { if ($this->isAdmin()) {
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list backups"); // if we're an admin, list all backups of all the admins customers
$query_fields = []; // or optionally for one specific customer identified by id or loginname
$result_stmt = Database::prepare(" $customerid = $this->getParam('customerid', true, 0);
$loginname = $this->getParam('loginname', true, '');
if (!empty($customerid) || !empty($loginname)) {
$result = $this->apiCall('Customers.get', [
'id' => $customerid,
'loginname' => $loginname
]);
$custom_list_result = [
$result
];
} else {
$_custom_list_result = $this->apiCall('Customers.listing');
$custom_list_result = $_custom_list_result['list'];
}
$customer_ids = [];
foreach ($custom_list_result as $customer) {
$customer_ids[] = $customer['customerid'];
}
if (empty($customer_ids)) {
throw new Exception("Required resource unsatisfied.", 405);
}
} else {
$customer_ids = [
$this->getUserDetail('customerid')
];
}
$this->logger()->logAction(FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] list backups");
$query_fields = [];
$result_stmt = Database::prepare("
SELECT `b`.*, `a`.`loginname` as `adminname` SELECT `b`.*, `a`.`loginname` as `adminname`
FROM `" . TABLE_PANEL_BACKUPS . "` `b` FROM `" . TABLE_PANEL_BACKUPS . "` `b`
LEFT JOIN `" . TABLE_PANEL_ADMINS . "` `a` USING(`adminid`) LEFT JOIN `" . TABLE_PANEL_ADMINS . "` `a` USING(`adminid`)
WHERE `b`.`customerid` IN (" . implode(', ', $customer_ids) . ")
"); ");
Database::pexecute($result_stmt, $query_fields, true, true); Database::pexecute($result_stmt, $query_fields, true, true);
$result = []; $result = [];
while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) { while ($row = $result_stmt->fetch(PDO::FETCH_ASSOC)) {
$result[] = $row; $result[] = $row;
}
return $this->response([
'count' => count($result),
'list' => $result
]);
} }
return $this->response([
'count' => count($result),
'list' => $result
]);
throw new Exception("Not allowed to execute given command.", 403); throw new Exception("Not allowed to execute given command.", 403);
} }
@@ -93,7 +124,7 @@ class Backups extends ApiCommand implements ResourceEntity
*/ */
public function listingCount() public function listingCount()
{ {
if ($this->isAdmin() && $this->getUserDetail('change_serversettings') == 1) { if ($this->isAdmin()) {
$result_stmt = Database::prepare(" $result_stmt = Database::prepare("
SELECT COUNT(*) as num_backups SELECT COUNT(*) as num_backups
FROM `" . TABLE_PANEL_BACKUPS . "` FROM `" . TABLE_PANEL_BACKUPS . "`

View File

@@ -1059,17 +1059,19 @@ class SubDomains extends ApiCommand implements ResourceEntity
$this->getUserDetail('customerid') => $this->getUserDetail('standardsubdomain') $this->getUserDetail('customerid') => $this->getUserDetail('standardsubdomain')
]; ];
} }
// prepare select statement if (!empty($customer_ids)) {
$domains_stmt = Database::prepare(" // prepare select statement
SELECT COUNT(*) as num_subdom $domains_stmt = Database::prepare("
FROM `" . TABLE_PANEL_DOMAINS . "` `d` SELECT COUNT(*) as num_subdom
WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ") FROM `" . TABLE_PANEL_DOMAINS . "` `d`
AND `d`.`email_only` = '0' WHERE `d`.`customerid` IN (" . implode(', ', $customer_ids) . ")
AND `d`.`id` NOT IN (" . implode(', ', $customer_stdsubs) . ") AND `d`.`email_only` = '0'
"); AND `d`.`id` NOT IN (" . implode(', ', $customer_stdsubs) . ")
$result = Database::pexecute_first($domains_stmt, null, true, true); ");
if ($result) { $result = Database::pexecute_first($domains_stmt, null, true, true);
return $this->response($result['num_subdom']); if ($result) {
return $this->response($result['num_subdom']);
}
} }
return $this->response(0); return $this->response(0);
} }

View File

@@ -27,6 +27,10 @@ namespace Froxlor\Cron\Backup;
use Froxlor\Cron\Forkable; use Froxlor\Cron\Forkable;
use Froxlor\Cron\FroxlorCron; use Froxlor\Cron\FroxlorCron;
use Froxlor\Database\Database;
use Froxlor\FroxlorLogger;
use Froxlor\Settings;
use PDO;
class BackupCron extends FroxlorCron class BackupCron extends FroxlorCron
{ {
@@ -34,28 +38,45 @@ class BackupCron extends FroxlorCron
public static function run() public static function run()
{ {
$users = ['web1', 'web2', 'web3', 'web4', 'web5', 'web6', 'web7', 'web8', 'web9', 'web10']; if(!Settings::Get('backup.enabled')) {
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'BackupCron: disabled - exiting');
return -1;
}
self::runFork([self::class, 'handle'], [ $stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_BACKUP_STORAGES . "`");
[ Database::pexecute($stmt);
'user' => '1',
'data' => 'value1', $storages = [];
], while ($storage = $stmt->fetch(PDO::FETCH_ASSOC)) {
[ $storages[$storage['id']] = $storage;
'user' => '2', }
'data' => 'value2',
] $stmt = Database::prepare("SELECT
]); customerid,
loginname,
adminid,
backup,
guid,
documentroot
FROM `" . TABLE_PANEL_CUSTOMERS . "` WHERE `backup` > 0
");
Database::pexecute($stmt);
$customers = [];
while ($customer = $stmt->fetch(PDO::FETCH_ASSOC)) {
$customer['storage'] = $storages[$customer['backup']];
$customers[] = $customer;
}
self::runFork([self::class, 'handle'], $customers);
} }
private static function handle(array $userdata) private static function handle(array $userdata)
{ {
echo "BackupCron: started - creating customer backup for user " . $userdata['user'] . "\n"; echo "BackupCron: started - creating customer backup for user " . $userdata['loginname'] . "\n";
echo $userdata['data'] . "\n"; echo json_encode($userdata['storage']) . "\n";
sleep(rand(1, 3)); echo "BackupCron: finished - creating customer backup for user " . $userdata['loginname'] . "\n";
echo "BackupCron: finished - creating customer backup for user " . $userdata['user'] . "\n";
} }
} }

View File

@@ -244,7 +244,6 @@ return [
], ],
'server' => [ 'server' => [
'label' => lng('admin.server'), 'label' => lng('admin.server'),
'required_resources' => 'change_serversettings',
'icon' => 'fa-solid fa-server', 'icon' => 'fa-solid fa-server',
'elements' => [ 'elements' => [
[ [
@@ -265,14 +264,11 @@ return [
[ [
'url' => 'admin_backups.php?page=overview', 'url' => 'admin_backups.php?page=overview',
'label' => lng('admin.backups.backups'), 'label' => lng('admin.backups.backups'),
'required_resources' => 'change_serversettings',
'add_shortlink' => 'admin_backups.php?page=overview&action=add',
'show_element' => (Settings::Get('backup.enabled') == true) 'show_element' => (Settings::Get('backup.enabled') == true)
], ],
[ [
'url' => 'admin_logger.php?page=log', 'url' => 'admin_logger.php?page=log',
'label' => lng('menue.logger.logger'), 'label' => lng('menue.logger.logger'),
'required_resources' => 'change_serversettings',
'show_element' => (Settings::Get('logger.enabled') == true) 'show_element' => (Settings::Get('logger.enabled') == true)
], ],
[ [

View File

@@ -84,7 +84,7 @@ return [
'sortable' => true, 'sortable' => true,
], ],
], ],
'visible_columns' => Listing::getVisibleColumnsForListing('admin_list', [ 'visible_columns' => Listing::getVisibleColumnsForListing('backup_storages_list', [
'id', 'id',
'description', 'description',
'type', 'type',
@@ -94,8 +94,6 @@ return [
'show' => [ 'show' => [
'icon' => 'fa-solid fa-eye', 'icon' => 'fa-solid fa-eye',
'title' => lng('usersettings.custom_notes.title'), 'title' => lng('usersettings.custom_notes.title'),
'modal' => [Text::class, 'customerNoteDetailModal'],
'visible' => [Customer::class, 'hasNote']
], ],
'edit' => [ 'edit' => [
'icon' => 'fa-solid fa-edit', 'icon' => 'fa-solid fa-edit',
@@ -117,13 +115,7 @@ return [
'action' => 'delete', 'action' => 'delete',
'id' => ':id' 'id' => ':id'
], ],
'visible' => [Admin::class, 'isNotMe']
], ],
], ],
'format_callback' => [
[Style::class, 'deactivated'],
[Style::class, 'diskspaceWarning'],
[Style::class, 'trafficWarning']
]
] ]
]; ];

View File

@@ -24,6 +24,7 @@
*/ */
use Froxlor\UI\Callbacks\Admin; use Froxlor\UI\Callbacks\Admin;
use Froxlor\UI\Callbacks\Backup;
use Froxlor\UI\Callbacks\Customer; use Froxlor\UI\Callbacks\Customer;
use Froxlor\UI\Callbacks\Impersonate; use Froxlor\UI\Callbacks\Impersonate;
use Froxlor\UI\Callbacks\ProgressBar; use Froxlor\UI\Callbacks\ProgressBar;
@@ -63,20 +64,32 @@ return [
'label' => lng('admin.admin'), 'label' => lng('admin.admin'),
'field' => 'adminname', 'field' => 'adminname',
'callback' => [Impersonate::class, 'admin'], 'callback' => [Impersonate::class, 'admin'],
'sortable' => true,
], ],
'size' => [ 'size' => [
'label' => lng('backup.size'), 'label' => lng('backup.size'),
'field' => 'size', 'field' => 'size',
'sortable' => true, 'sortable' => true,
'callback' => [Text::class, 'size'],
],
'storage_id' => [
'label' => lng('backup.backup_storage.title'),
'field' => 'storage_id',
'class' => 'text-center',
'callback' => [Backup::class, 'backupStorageLink'],
],
'filename' => [
'label' => lng('backup.size'),
'field' => 'filename',
'sortable' => true,
], ],
'created_at' => [ 'created_at' => [
'label' => lng('backup.created_at'), 'label' => lng('backup.created_at'),
'field' => 'created_at', 'field' => 'created_at',
'sortable' => true, 'sortable' => true,
'callback' => [Text::class, 'timestamp'],
], ],
], ],
'visible_columns' => Listing::getVisibleColumnsForListing('admin_list', [ 'visible_columns' => Listing::getVisibleColumnsForListing('backups_list', [
'id', 'id',
'adminname', 'adminname',
'loginname', 'loginname',
@@ -84,22 +97,6 @@ return [
'created_at', 'created_at',
]), ]),
'actions' => [ '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' => [ 'delete' => [
'icon' => 'fa-solid fa-trash', 'icon' => 'fa-solid fa-trash',
'title' => lng('panel.delete'), 'title' => lng('panel.delete'),
@@ -110,13 +107,8 @@ return [
'action' => 'delete', 'action' => 'delete',
'id' => ':id' 'id' => ':id'
], ],
'visible' => [Admin::class, 'isNotMe'] 'visible' => [Admin::class, 'canChangeServerSettings'],
], ],
],
'format_callback' => [
[Style::class, 'deactivated'],
[Style::class, 'diskspaceWarning'],
[Style::class, 'trafficWarning']
] ]
] ]
]; ];

View File

@@ -31,18 +31,13 @@
<div> <div>
{% if actions_links is iterable %} {% if actions_links is iterable %}
{% for link in actions_links %} {% for link in actions_links %}
<a class="btn {{ link.class|default('btn-outline-primary') }}" href="{{ link.href|raw }}"> {% if link.visible is not defined or (link.visible is defined and link.visible == true) %}
<i class="{{ link.icon|default('fa-solid fa-plus-circle') }}"></i><span class="d-none d-lg-inline ms-lg-1">{{ link.label }}</span> <a class="btn {{ link.class|default('btn-outline-primary') }}" href="{{ link.href|raw }}">
</a> <i class="{{ link.icon|default('fa-solid fa-plus-circle') }}"></i><span class="d-none d-lg-inline ms-lg-1">{{ link.label }}</span>
</a>
{% endif %}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{# TODO: eventually not used anymore because of using a documentation link
{% if entity_info is defined and entity_info is not empty %}
<div class="alert alert-info" role="alert">
{{ entity_info|raw }}
</div>
{% endif %}
#}
</div> </div>
{% endif %} {% endif %}

View File

@@ -33,19 +33,14 @@
<div> <div>
{% if actions_links is iterable %} {% if actions_links is iterable %}
{% for link in actions_links %} {% for link in actions_links %}
<a class="btn {{ link.class|default('btn-outline-primary') }}" href="{{ link.href|raw }}"> {% if link.visible is not defined or (link.visible is defined and link.visible == true) %}
<i class="{{ link.icon|default('fa-solid fa-plus-circle') }}"></i> <a class="btn {{ link.class|default('btn-outline-primary') }}" href="{{ link.href|raw }}">
{% if link.label is defined and link.label is not empty %}<span class="d-none d-lg-inline ms-lg-1">{{ link.label }}</span>{% endif %} <i class="{{ link.icon|default('fa-solid fa-plus-circle') }}"></i>
</a> {% if link.label is defined and link.label is not empty %}<span class="d-none d-lg-inline ms-lg-1">{{ link.label }}</span>{% endif %}
</a>
{% endif %}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{# TODO: eventually not used anymore because of using a documentation link
{% if entity_info is defined and entity_info is not empty %}
<div class="alert alert-info" role="alert">
{{ entity_info|raw }}
</div>
{% endif %}
#}
</div> </div>
{% endif %} {% endif %}
{% endblock %} {% endblock %}