big renaming of CustomerBackup to DataDump / export for the real backup-feature to shine :P

Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
This commit is contained in:
Michael Kaufmann 2023-06-07 11:37:00 +02:00
parent 5181602921
commit e958cfed84
No known key found for this signature in database
GPG Key ID: C121F97338D7A352
20 changed files with 257 additions and 261 deletions

View File

@ -265,7 +265,7 @@ return [
'extras.directoryprotection' => lng('menue.extras.extras') . " / " . lng('menue.extras.directoryprotection'),
'extras.pathoptions' => lng('menue.extras.extras') . " / " . lng('menue.extras.pathoptions'),
'extras.logger' => lng('menue.extras.extras') . " / " . lng('menue.logger.logger'),
'extras.backup' => lng('menue.extras.extras') . " / " . lng('menue.extras.backup'),
'extras.export' => lng('menue.extras.extras') . " / " . lng('menue.extras.export'),
'traffic' => lng('menue.traffic.traffic'),
'traffic.http' => lng('menue.traffic.traffic') . " / HTTP",
'traffic.ftp' => lng('menue.traffic.traffic') . " / FTP",

View File

@ -230,10 +230,10 @@ return [
'onlyif' => 1
]
],
'system_backupenabled' => [
'label' => lng('serversettings.backupenabled'),
'system_exportenabled' => [
'label' => lng('serversettings.exportenabled'),
'settinggroup' => 'system',
'varname' => 'backupenabled',
'varname' => 'exportenabled',
'type' => 'checkbox',
'default' => false,
'cronmodule' => 'froxlor/export',

View File

@ -26,7 +26,7 @@
const AREA = 'customer';
require __DIR__ . '/lib/init.php';
use Froxlor\Api\Commands\CustomerBackups as CustomerBackups;
use Froxlor\Api\Commands\DataDump as DataDump;
use Froxlor\Api\Commands\DirOptions as DirOptions;
use Froxlor\Api\Commands\DirProtections as DirProtections;
use Froxlor\Customer\Customer;
@ -282,18 +282,18 @@ if ($page == 'overview' || $page == 'htpasswds') {
}
}
}
} elseif ($page == 'backup') {
} elseif ($page == 'export') {
// redirect if this customer sub-page is hidden via settings
if (Settings::IsInList('panel.customer_hide_options', 'extras.backup')) {
if (Settings::IsInList('panel.customer_hide_options', 'extras.export')) {
Response::redirectTo('customer_index.php');
}
if (Settings::Get('system.backupenabled') == 1) {
if (Settings::Get('system.exportenabled') == 1) {
if ($action == 'abort') {
if (isset($_POST['send']) && $_POST['send'] == 'send') {
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "customer_extras::backup - aborted scheduled backupjob");
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "customer_extras::export - aborted scheduled data export job");
try {
CustomerBackups::getLocal($userinfo, $_POST)->delete();
DataDump::getLocal($userinfo, $_POST)->delete();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
@ -302,43 +302,43 @@ if ($page == 'overview' || $page == 'htpasswds') {
'action' => ''
]);
} else {
HTML::askYesNo('extras_reallydelete_backup', $filename, [
'backup_job_entry' => $id,
HTML::askYesNo('extras_reallydelete_export', $filename, [
'job_entry' => $id,
'section' => 'extras',
'page' => $page,
'action' => $action
]);
}
} elseif ($action == '') {
$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed customer_extras::backup");
$log->logAction(FroxlorLogger::USR_ACTION, LOG_INFO, "viewed customer_extras::export");
// check whether there is a backup-job for this customer
try {
$backup_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/customer/tablelisting.backups.php';
$collection = (new Collection(CustomerBackups::class, $userinfo));
$export_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/customer/tablelisting.export.php';
$collection = (new Collection(DataDump::class, $userinfo));
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
if (isset($_POST['send']) && $_POST['send'] == 'send') {
try {
CustomerBackups::getLocal($userinfo, $_POST)->add();
DataDump::getLocal($userinfo, $_POST)->add();
} catch (Exception $e) {
Response::dynamicError($e->getMessage());
}
Response::standardSuccess('backupscheduled');
Response::standardSuccess('exportscheduled');
} else {
$pathSelect = FileDir::makePathfield($userinfo['documentroot'], $userinfo['guid'], $userinfo['guid']);
$backup_data = include_once dirname(__FILE__) . '/lib/formfields/customer/extras/formfield.backup.php';
$export_data = include_once dirname(__FILE__) . '/lib/formfields/customer/extras/formfield.export.php';
UI::view('user/form-datatable.html.twig', [
'formaction' => $linker->getLink(['section' => 'extras']),
'formdata' => $backup_data['backup'],
'tabledata' => Listing::format($collection, $backup_list_data, 'backup_list'),
'formdata' => $export_data['export'],
'tabledata' => Listing::format($collection, $export_list_data, 'export_list'),
]);
}
}
} else {
Response::standardError('backupfunctionnotenabled');
Response::standardError('exportfunctionnotenabled');
}
}

View File

@ -646,7 +646,7 @@ opcache.validate_timestamps'),
('system', 'letsencryptreuseold', 0),
('system', 'leenabled', '0'),
('system', 'leapiversion', '2'),
('system', 'backupenabled', '0'),
('system', 'exportenabled', '0'),
('system', 'dnsenabled', '0'),
('system', 'dns_server', 'Bind'),
('system', 'apacheglobaldiropt', ''),
@ -1071,4 +1071,15 @@ CREATE TABLE `panel_loginlinks` (
`allowed_from` text NOT NULL,
UNIQUE KEY `loginname` (`loginname`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
DROP TABLE IF EXISTS `panel_backups`;
CREATE TABLE `panel_backups` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`adminid` int(11) NOT NULL,
`customerid` int(11) NOT NULL,
`loginname` varchar(255) NOT NULL,
`size` bigint(20) NOT NULL,
`created_at` int(15) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
FROXLORSQL;

View File

@ -571,5 +571,12 @@ if (Froxlor::isDatabaseVersion('202304260')) {
");
Update::lastStepStatus(0);
Update::showUpdateStep("Adjusting system for data-export function");
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "`SET `varname` = 'exportenabled' WHERE `settinggroup`= 'system' AND `varname`= 'backupenabled");
Database::query("UPDATE `" . TABLE_PANEL_SETTINGS . "`SET `value` = REPLACE(`value`, 'extras.backup', 'extras.export') WHERE `settinggroup` = 'panel' AND `varname` = 'customer_hide_options'");
Database::query("DELETE FROM `" . TABLE_PANEL_USERCOLUMNS . "` WHERE `section` = 'backup_list'");
Database::query("DELETE FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = '20'");
Update::lastStepStatus(0);
Froxlor::updateToDbVersion('202305240');
}

View File

@ -41,22 +41,22 @@ use PDO;
/**
* @since 0.10.0
*/
class CustomerBackups extends ApiCommand implements ResourceEntity
class DataDump extends ApiCommand implements ResourceEntity
{
/**
* add a new customer backup job
* add a new data dump job
*
* @param string $path
* path to store the backup to
* path to store the dumped data to
* @param string $pgp_public_key
* optional pgp public key to encrypt the backup, default is empty
* @param bool $backup_dbs
* optional whether to backup databases, default is 0 (false)
* @param bool $backup_mail
* optional whether to backup mail-data, default is 0 (false)
* @param bool $backup_web
* optional whether to backup web-data, default is 0 (false)
* optional pgp public key to encrypt the archive, default is empty
* @param bool $dump_dbs
* optional whether to include databases, default is 0 (false)
* @param bool $dump_mail
* optional whether to include mail-data, default is 0 (false)
* @param bool $dump_web
* optional whether to incoude web-data, default is 0 (false)
* @param int $customerid
* optional, required when called as admin (if $loginname is not specified)
* @param string $loginname
@ -75,9 +75,9 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
// parameter
$pgp_public_key = $this->getParam('pgp_public_key', true, '');
$backup_dbs = $this->getBoolParam('backup_dbs', true, 0);
$backup_mail = $this->getBoolParam('backup_mail', true, 0);
$backup_web = $this->getBoolParam('backup_web', true, 0);
$dump_dbs = $this->getBoolParam('dump_dbs', true, 0);
$dump_mail = $this->getBoolParam('dump_mail', true, 0);
$dump_web = $this->getBoolParam('dump_web', true, 0);
// get customer data
$customer = $this->getCustomerData();
@ -89,7 +89,7 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
// path cannot be the customers docroot
if ($path == FileDir::makeCorrectDir($customer['documentroot'])) {
Response::standardError('backupfoldercannotbedocroot', '', true);
Response::standardError('dumpfoldercannotbedocroot', '', true);
}
// pgp public key validation
@ -105,16 +105,16 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
}
}
if ($backup_dbs != '1') {
$backup_dbs = '0';
if ($dump_dbs != '1') {
$dump_dbs = '0';
}
if ($backup_mail != '1') {
$backup_mail = '0';
if ($dump_mail != '1') {
$dump_mail = '0';
}
if ($backup_web != '1') {
$backup_web = '0';
if ($dump_web != '1') {
$dump_web = '0';
}
$task_data = [
@ -124,62 +124,62 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
'loginname' => $customer['loginname'],
'destdir' => $path,
'pgp_public_key' => $pgp_public_key,
'backup_dbs' => $backup_dbs,
'backup_mail' => $backup_mail,
'backup_web' => $backup_web
'dump_dbs' => $dump_dbs,
'dump_mail' => $dump_mail,
'dump_web' => $dump_web
];
// schedule backup job
Cronjob::inserttask(TaskId::CREATE_CUSTOMER_BACKUP, $task_data);
// schedule export job
Cronjob::inserttask(TaskId::CREATE_CUSTOMER_DATADUMP, $task_data);
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added customer-backup job for '" . $customer['loginname'] . "'. Target directory: " . $userpath);
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added customer data-dump job for '" . $customer['loginname'] . "'. Target directory: " . $userpath);
return $this->response($task_data);
}
/**
* check whether backup is enabled systemwide and if accessible for customer (hide_options)
* check whether data dump is enabled systemwide and if accessible for customer (hide_options)
*
* @throws Exception
*/
private function validateAccess()
{
if (Settings::Get('system.backupenabled') != 1) {
if (Settings::Get('system.exportenabled') != 1) {
throw new Exception("You cannot access this resource", 405);
}
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'extras')) {
throw new Exception("You cannot access this resource", 405);
}
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'extras.backup')) {
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'extras.export')) {
throw new Exception("You cannot access this resource", 405);
}
}
/**
* You cannot get a planned backup.
* Try CustomerBackups.listing()
* You cannot get a planned data export.
* Try DataDump.listing()
*/
public function get()
{
throw new Exception('You cannot get a planned backup. Try CustomerBackups.listing()', 303);
throw new Exception('You cannot get a planned data export. Try DataDump.listing()', 303);
}
/**
* You cannot update a planned backup.
* You cannot update a planned data export.
* You need to delete it and re-add it.
*/
public function update()
{
throw new Exception('You cannot update a planned backup. You need to delete it and re-add it.', 303);
throw new Exception('You cannot update a planned data export. You need to delete it and re-add it.', 303);
}
/**
* list all planned backup-jobs, if called from an admin, list all planned backup-jobs of all customers you are
* list all planned data export jobs, if called from an admin, list all planned data export jobs of all customers you are
* allowed to view, or specify id or loginname for one specific customer
*
* @param int $customerid
* optional, admin-only, select backup-jobs of a specific customer by id
* optional, admin-only, select data export jobs of a specific customer by id
* @param string $loginname
* optional, admin-only, select backup-jobs of a specific customer by loginname
* optional, admin-only, select data export jobs of a specific customer by loginname
* @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
@ -199,9 +199,9 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
{
$this->validateAccess();
$customer_ids = $this->getAllowedCustomerIds('extras.backup');
$customer_ids = $this->getAllowedCustomerIds('extras.export');
// check whether there is a backup-job for this customer
// check whether there is a data export job for this customer
$query_fields = [];
$sel_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = '20'" . $this->getSearchWhere($query_fields, true) . $this->getOrderBy() . $this->getLimit());
Database::pexecute($sel_stmt, $query_fields, true, true);
@ -212,7 +212,7 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
$result[] = $entry;
}
}
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list customer-backups");
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_INFO, "[API] list customer data dump jobs");
return $this->response([
'count' => count($result),
'list' => $result
@ -220,12 +220,12 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
}
/**
* returns the total number of planned backups
* returns the total number of planned data exports
*
* @param int $customerid
* optional, admin-only, select backup-jobs of a specific customer by id
* optional, admin-only, select data export jobs of a specific customer by id
* @param string $loginname
* optional, admin-only, select backup-jobs of a specific customer by loginname
* optional, admin-only, select data export jobs of a specific customer by loginname
*
* @access admin, customer
* @return string json-encoded response message
@ -235,9 +235,9 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
{
$this->validateAccess();
$customer_ids = $this->getAllowedCustomerIds('extras.backup');
$customer_ids = $this->getAllowedCustomerIds('extras.export');
// check whether there is a backup-job for this customer
// check whether there is a data export job for this customer
$result_count = 0;
$sel_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = '20'");
Database::pexecute($sel_stmt, null, true, true);
@ -251,10 +251,10 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
}
/**
* delete a planned backup-jobs by id, if called from an admin you need to specify the customerid/loginname
* delete a planned data export jobs by id, if called from an admin you need to specify the customerid/loginname
*
* @param int $backup_job_entry
* id of backup job
* @param int $job_entry
* id of data export job
* @param int $customerid
* optional, required when called as admin (if $loginname is not specified)
* @param string $loginname
@ -266,26 +266,26 @@ class CustomerBackups extends ApiCommand implements ResourceEntity
*/
public function delete()
{
// get planned backups
$result = $this->apiCall('CustomerBackups.listing', $this->getParamList());
// get planned exports
$result = $this->apiCall('DataDump.listing', $this->getParamList());
$entry = $this->getParam('backup_job_entry');
$customer_ids = $this->getAllowedCustomerIds('extras.backup');
$entry = $this->getParam('job_entry');
$customer_ids = $this->getAllowedCustomerIds('extras.export');
if ($result['count'] > 0 && $entry > 0) {
// prepare statement
$del_stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_TASKS . "` WHERE `id` = :tid");
// check for the correct job
foreach ($result['list'] as $backupjob) {
if ($backupjob['id'] == $entry && in_array($backupjob['data']['customerid'], $customer_ids)) {
foreach ($result['list'] as $exportjob) {
if ($exportjob['id'] == $entry && in_array($exportjob['data']['customerid'], $customer_ids)) {
Database::pexecute($del_stmt, [
'tid' => $entry
], true, true);
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] deleted planned customer-backup #" . $entry);
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] deleted planned customer data export job #" . $entry);
return $this->response(true);
}
}
}
throw new Exception('Backup job with id #' . $entry . ' could not be found', 404);
throw new Exception('Data export job with id #' . $entry . ' could not be found', 404);
}
}

View File

@ -23,19 +23,18 @@ trait Forkable
} elseif ($pid == 0) {
// re-create db
Database::needRoot(false);
$closure(...$closureAttributes);
$closure($closureAttributes);
exit();
} else {
$childrenPids[] = $pid;
while (count($childrenPids) >= $concurrentChildren) {
foreach ($childrenPids as $key => $pid) {
$res = pcntl_waitpid($pid, $status, WNOHANG);
// If the process has already exited
if($res == -1 || $res > 0)
if ($res == -1 || $res > 0) {
unset($childrenPids[$key]);
}
}
sleep(1);
}
}
@ -51,7 +50,7 @@ trait Forkable
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, $msg . " Not forking " . self::class . ", this may take a long time!");
}
foreach ($attributes as $closureAttributes) {
$closure(...$closureAttributes);
$closure($closureAttributes);
}
}
}

View File

@ -39,7 +39,7 @@ class ExportCron extends FroxlorCron
public static function run()
{
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'BackupCron: started - creating customer backup');
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'ExportCron: started - creating customer data export');
$result_tasks_stmt = Database::query("
SELECT * FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` = '20' ORDER BY `id` ASC
@ -65,11 +65,11 @@ class ExportCron extends FroxlorCron
// create folder if not exists
if (!file_exists($row['data']['destdir']) && $row['data']['destdir'] != '/' && $row['data']['destdir'] != Settings::Get('system.documentroot_prefix') && $row['data']['destdir'] != $customerdocroot) {
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'Creating backup-destination path for customer: ' . escapeshellarg($row['data']['destdir']));
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating data export destination path for customer: ' . escapeshellarg($row['data']['destdir']));
FileDir::safe_exec('mkdir -p ' . escapeshellarg($row['data']['destdir']));
}
self::createCustomerBackup($row['data'], $customerdocroot, $cronlog);
self::createCustomerExport($row['data'], $customerdocroot, $cronlog);
}
}
@ -80,7 +80,7 @@ class ExportCron extends FroxlorCron
}
/**
* depending on the give choice, the customers web-data, email-data and databases are being backup'ed
* depending on the give choice, the customers web-data, email-data and databases are being exported
*
* @param array $data
*
@ -88,19 +88,19 @@ class ExportCron extends FroxlorCron
*
* @throws Exception
*/
private static function createCustomerBackup($data = null, $customerdocroot = null, &$cronlog = null)
private static function createCustomerExport($data = null, $customerdocroot = null, &$cronlog = null)
{
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Creating Backup for user "' . $data['loginname'] . '"');
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'Creating data export for user "' . $data['loginname'] . '"');
// create tmp folder
$tmpdir = FileDir::makeCorrectDir($data['destdir'] . '/.tmp/');
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating tmp-folder "' . $tmpdir . '"');
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> mkdir -p ' . escapeshellarg($tmpdir));
FileDir::safe_exec('mkdir -p ' . escapeshellarg($tmpdir));
$create_backup_tar_data = "";
$create_export_tar_data = "";
// MySQL databases
if ($data['backup_dbs'] == 1) {
if ($data['dump_dbs'] == 1) {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating mysql-folder "' . FileDir::makeCorrectDir($tmpdir . '/mysql') . '"');
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/mysql')));
FileDir::safe_exec('mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/mysql')));
@ -140,7 +140,7 @@ class ExportCron extends FroxlorCron
}
if ($has_dbs) {
$create_backup_tar_data .= './mysql ';
$create_export_tar_data .= './mysql ';
}
if (file_exists($mysqlcnf_file)) {
@ -151,7 +151,7 @@ class ExportCron extends FroxlorCron
}
// E-mail data
if ($data['backup_mail'] == 1) {
if ($data['dump_mail'] == 1) {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating mail-folder "' . FileDir::makeCorrectDir($tmpdir . '/mail') . '"');
FileDir::safe_exec('mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/mail')));
@ -171,41 +171,41 @@ class ExportCron extends FroxlorCron
if (!empty($tar_file_list)) {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> tar cfvz ' . escapeshellarg(FileDir::makeCorrectFile($tmpdir . '/mail/' . $data['loginname'] . '-mail.tar.gz')) . ' -C ' . escapeshellarg($mail_homedir) . ' ' . trim($tar_file_list));
FileDir::safe_exec('tar cfz ' . escapeshellarg(FileDir::makeCorrectFile($tmpdir . '/mail/' . $data['loginname'] . '-mail.tar.gz')) . ' -C ' . escapeshellarg($mail_homedir) . ' ' . trim($tar_file_list));
$create_backup_tar_data .= './mail ';
$create_export_tar_data .= './mail ';
}
}
// Web data
if ($data['backup_web'] == 1) {
if ($data['dump_web'] == 1) {
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'Creating web-folder "' . FileDir::makeCorrectDir($tmpdir . '/web') . '"');
FileDir::safe_exec('mkdir -p ' . escapeshellarg(FileDir::makeCorrectDir($tmpdir . '/web')));
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> tar cfz ' . escapeshellarg(FileDir::makeCorrectFile($tmpdir . '/web/' . $data['loginname'] . '-web.tar.gz')) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", FileDir::makeCorrectFile($tmpdir . '/*'))) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", substr(FileDir::makeCorrectDir($tmpdir), 0, -1))) . ' -C ' . escapeshellarg($customerdocroot) . ' .');
FileDir::safe_exec('tar cfz ' . escapeshellarg(FileDir::makeCorrectFile($tmpdir . '/web/' . $data['loginname'] . '-web.tar.gz')) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", FileDir::makeCorrectFile($tmpdir . '/*'))) . ' --exclude=' . escapeshellarg(str_replace($customerdocroot, "./", substr(FileDir::makeCorrectFile($tmpdir), 0, -1))) . ' -C ' . escapeshellarg($customerdocroot) . ' .');
$create_backup_tar_data .= './web ';
$create_export_tar_data .= './web ';
}
if (!empty($create_backup_tar_data)) {
if (!empty($create_export_tar_data)) {
// set owner to customer
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> chown -R ' . (int)$data['uid'] . ':' . (int)$data['gid'] . ' ' . escapeshellarg($tmpdir));
FileDir::safe_exec('chown -R ' . (int)$data['uid'] . ':' . (int)$data['gid'] . ' ' . escapeshellarg($tmpdir));
// create tar-file
$backup_file = FileDir::makeCorrectFile($tmpdir . '/' . $data['loginname'] . '-backup_' . date('YmdHi', time()) . '.tar.gz' . (!empty($data['pgp_public_key']) ? '.gpg' : ''));
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Creating backup-file "' . $backup_file . '"');
$export_file = FileDir::makeCorrectFile($tmpdir . '/' . $data['loginname'] . '-export_' . date('YmdHi', time()) . '.tar.gz' . (!empty($data['pgp_public_key']) ? '.gpg' : ''));
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Creating export-file "' . $export_file . '"');
if (!empty($data['pgp_public_key'])) {
// pack all archives in tmp-dir to one archive and encrypt it with gpg
$recipient_file = FileDir::makeCorrectFile($tmpdir . '/' . $data['loginname'] . '-recipients.gpg');
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'Creating recipient-file "' . $recipient_file . '"');
file_put_contents($recipient_file, $data['pgp_public_key']);
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> tar cfz - -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_backup_tar_data) . ' | gpg --encrypt --recipient-file ' . escapeshellarg($recipient_file) . ' --output ' . escapeshellarg($backup_file) . ' --trust-model always --batch --yes');
FileDir::safe_exec('tar cfz - -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_backup_tar_data) . ' | gpg --encrypt --recipient-file ' . escapeshellarg($recipient_file) . ' --output ' . escapeshellarg($backup_file) . ' --trust-model always --batch --yes', $return_value, ['|']);
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> tar cfz - -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_export_tar_data) . ' | gpg --encrypt --recipient-file ' . escapeshellarg($recipient_file) . ' --output ' . escapeshellarg($export_file) . ' --trust-model always --batch --yes');
FileDir::safe_exec('tar cfz - -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_export_tar_data) . ' | gpg --encrypt --recipient-file ' . escapeshellarg($recipient_file) . ' --output ' . escapeshellarg($export_file) . ' --trust-model always --batch --yes', $return_value, ['|']);
} else {
// pack all archives in tmp-dir to one archive
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> tar cfz ' . escapeshellarg($backup_file) . ' -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_backup_tar_data));
FileDir::safe_exec('tar cfz ' . escapeshellarg($backup_file) . ' -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_backup_tar_data));
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> tar cfz ' . escapeshellarg($export_file) . ' -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_export_tar_data));
FileDir::safe_exec('tar cfz ' . escapeshellarg($export_file) . ' -C ' . escapeshellarg($tmpdir) . ' ' . trim($create_export_tar_data));
}
// move to destination directory
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> mv ' . escapeshellarg($backup_file) . ' ' . escapeshellarg($data['destdir']));
FileDir::safe_exec('mv ' . escapeshellarg($backup_file) . ' ' . escapeshellarg($data['destdir']));
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> mv ' . escapeshellarg($export_file) . ' ' . escapeshellarg($data['destdir']));
FileDir::safe_exec('mv ' . escapeshellarg($export_file) . ' ' . escapeshellarg($data['destdir']));
// remove tmp-files
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_DEBUG, 'shell> rm -rf ' . escapeshellarg($tmpdir));
FileDir::safe_exec('rm -rf ' . escapeshellarg($tmpdir));

View File

@ -46,7 +46,7 @@ class TasksCron extends FroxlorCron
* LOOK INTO TASKS TABLE TO SEE IF THERE ARE ANY UNDONE JOBS
*/
self::$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "TasksCron: Searching for tasks to do");
// no type 99 (regenerate cron.d-file) and no type 20 (customer backup)
// no type 99 (regenerate cron.d-file) and no type 20 (customer data export)
// order by type descending to re-create bind and then webserver at the end
$result_tasks_stmt = Database::query("
SELECT `id`, `type`, `data` FROM `" . TABLE_PANEL_TASKS . "` WHERE `type` <> '99' AND `type` <> '20' ORDER BY `type` DESC, `id` ASC

View File

@ -82,9 +82,9 @@ final class TaskId
const DELETE_DOMAIN_SSL = 12;
/**
* TYPE=20 COSTUMERBACKUP
* TYPE=20 CUSTUMER DATA DUMP
*/
const CREATE_CUSTOMER_BACKUP = 20;
const CREATE_CUSTOMER_DATADUMP = 20;
/**
* TYPE=99 REGENERATE CRON

View File

@ -211,10 +211,10 @@ class Cronjob
'type' => TaskId::DELETE_DOMAIN_SSL,
'data' => $data
]);
} elseif ($type == TaskId::CREATE_CUSTOMER_BACKUP && isset($params[0]) && is_array($params[0])) {
} elseif ($type == TaskId::CREATE_CUSTOMER_DATADUMP && isset($params[0]) && is_array($params[0])) {
$data = json_encode($params[0]);
Database::pexecute($ins_stmt, [
'type' => TaskId::CREATE_CUSTOMER_BACKUP,
'type' => TaskId::CREATE_CUSTOMER_DATADUMP,
'data' => $data
]);
}

View File

@ -18,17 +18,16 @@
use Froxlor\Settings;
return [
'backup' => [
'title' => lng('extras.backup'),
'export' => [
'title' => lng('extras.export'),
'image' => 'fa-solid fa-server',
'sections' => [
'section_a' => [
'title' => lng('extras.backup'),
'image' => 'icons/backup_big.png',
'title' => lng('extras.export'),
'fields' => [
'path' => [
'label' => lng('panel.backuppath.title'),
'desc' => lng('panel.backuppath.description') . '<br>' . (Settings::Get('panel.pathedit') != 'Dropdown' ? lng('panel.pathDescription') : null),
'label' => lng('panel.exportpath.title'),
'desc' => lng('panel.exportpath.description') . '<br>' . (Settings::Get('panel.pathedit') != 'Dropdown' ? lng('panel.pathDescription') : null),
'type' => $pathSelect['type'],
'select_var' => $pathSelect['select_var'] ?? '',
'selected' => $pathSelect['value'],
@ -36,8 +35,8 @@ return [
'note' => $pathSelect['note'] ?? '',
],
'pgp_public_key' => [
'label' => lng('panel.backup_pgp_public_key.title'),
'desc' => lng('panel.backup_pgp_public_key.description'),
'label' => lng('panel.export_pgp_public_key.title'),
'desc' => lng('panel.export_pgp_public_key.description'),
'type' => 'textarea',
],
'path_protection_info' => [
@ -46,20 +45,20 @@ return [
'value' => lng('extras.path_protection_info'),
'classes' => 'fw-bold text-danger'
],
'backup_web' => [
'label' => lng('extras.backup_web'),
'dump_web' => [
'label' => lng('extras.dump_web'),
'type' => 'checkbox',
'value' => '1',
'checked' => true
],
'backup_mail' => [
'label' => lng('extras.backup_mail'),
'dump_mail' => [
'label' => lng('extras.dump_mail'),
'type' => 'checkbox',
'value' => '1',
'checked' => true
],
'backup_dbs' => [
'label' => lng('extras.backup_dbs'),
'dump_dbs' => [
'label' => lng('extras.dump_dbs'),
'type' => 'checkbox',
'value' => '1',
'checked' => true

View File

@ -133,9 +133,9 @@ return [
'show_element' => (Settings::Get('logger.enabled') == true) && (!Settings::IsInList('panel.customer_hide_options', 'extras.logger'))
],
[
'url' => 'customer_extras.php?page=backup',
'label' => lng('menue.extras.backup'),
'show_element' => (Settings::Get('system.backupenabled') == true) && (!Settings::IsInList('panel.customer_hide_options', 'extras.backup'))
'url' => 'customer_extras.php?page=export',
'label' => lng('menue.extras.export'),
'show_element' => (Settings::Get('system.exportenabled') == true) && (!Settings::IsInList('panel.customer_hide_options', 'extras.export'))
]
]
],

View File

@ -28,10 +28,10 @@ use Froxlor\UI\Callbacks\Text;
use Froxlor\UI\Listing;
return [
'backup_list' => [
'title' => lng('error.customerhasongoingbackupjob'),
'export_list' => [
'title' => lng('error.customerhasongoingexportjob'),
'icon' => 'fa-solid fa-server',
'self_overview' => ['section' => 'extras', 'page' => 'backup'],
'self_overview' => ['section' => 'extras', 'page' => 'export'],
'default_sorting' => ['destdir' => 'asc'],
'columns' => [
'destdir' => [
@ -44,28 +44,28 @@ return [
'field' => 'data.pgp_public_key',
'callback' => [Text::class, 'boolean']
],
'backup_web' => [
'label' => lng('extras.backup_web'),
'field' => 'data.backup_web',
'dump_web' => [
'label' => lng('extras.dump_web'),
'field' => 'data.dump_web',
'callback' => [Text::class, 'boolean'],
],
'backup_mail' => [
'label' => lng('extras.backup_mail'),
'field' => 'data.backup_mail',
'dump_mail' => [
'label' => lng('extras.dump_mail'),
'field' => 'data.dump_mail',
'callback' => [Text::class, 'boolean'],
],
'backup_dbs' => [
'label' => lng('extras.backup_dbs'),
'field' => 'data.backup_dbs',
'dump_dbs' => [
'label' => lng('extras.dump_dbs'),
'field' => 'data.dump_dbs',
'callback' => [Text::class, 'boolean'],
]
],
'visible_columns' => Listing::getVisibleColumnsForListing('backup_list', [
'visible_columns' => Listing::getVisibleColumnsForListing('export_list', [
'destdir',
'pgp_public_key',
'backup_web',
'backup_mail',
'backup_dbs'
'dump_web',
'dump_mail',
'dump_dbs'
]),
'actions' => [
'delete' => [

View File

@ -456,10 +456,6 @@ return [
'directory_browsing' => 'Procházení obsahu adresáře',
'pathoptions_edit' => 'Upravit možnosti cesty',
'execute_perl' => 'Spustit perl/CGI',
'backup' => 'Vytvořit zálohu',
'backup_web' => 'Zálohovat web-data',
'backup_mail' => 'Zálohovat mail-data',
'backup_dbs' => 'Zálohovat databáze',
],
'ftp' => [
'description' => 'Zde můžeš tvořit a upravovat tvé FTP-účty.<br />Změny jsou uskutečněny okamžitě a účty mohou být použity ihned.',
@ -549,7 +545,6 @@ return [
'extras' => 'Extra',
'directoryprotection' => 'Ochrana adresáře',
'pathoptions' => 'Možnosti cesty',
'backup' => 'Záloha',
],
'traffic' => [
'traffic' => 'Provoz',
@ -815,9 +810,6 @@ return [
'caa_entry' => [
'title' => 'Generovat CAA DNS záznamy',
],
'backupenabled' => [
'title' => 'Povolit zálohy pro zákazníky',
],
'mail_smtp_passwd' => 'SMTP heslo',
],
'success' => [

View File

@ -527,7 +527,8 @@ return [
'cron_usage_report' => 'Webspace- und Trafficreport',
'cron_mailboxsize' => 'Berechnung der Mailbox-Größen',
'cron_letsencrypt' => 'Aktualisierung der Let\'s Encrypt Zertifikate',
'cron_backup' => 'Ausstehende Sicherungen erstellen',
'cron_export' => 'Ausstehende Datenexporte erstellen',
'cron_backup' => 'System- und Kunden-Sicherungen erstellen',
],
'cronjob' => [
'cronjobsettings' => 'Cronjob-Einstellungen',
@ -775,7 +776,7 @@ return [
'destinationalreadyexistasmail' => 'Die Weiterleitung zu "%s" existiert bereits als aktive E-Mail-Adresse.',
'destinationalreadyexist' => 'Es existiert bereits eine Weiterleitung nach "%s".',
'destinationiswrong' => 'Die Weiterleitungsadresse "%s" enthält ungültige Zeichen oder ist nicht vollständig.',
'backupfoldercannotbedocroot' => 'Der Ordner für Backups darf nicht das Heimatverzeichnis sein, wählen Sie einen Ordner unterhalb des Heimatverzeichnisses, z.B. /backups',
'dumpfoldercannotbedocroot' => 'Der Ordner für Daten-Export darf nicht das Heimatverzeichnis sein, wählen Sie einen Ordner unterhalb des Heimatverzeichnisses, z.B. /dumps',
'templatelanguagecombodefined' => 'Die gewählte Kombination aus Sprache und Vorlage ist bereits definiert.',
'templatelanguageinvalid' => 'Die gewählte Sprache existiert nicht',
'ipstillhasdomains' => 'Die IP/Port-Kombination, die Sie löschen wollen, ist noch bei einer oder mehreren Domains eingetragen. Bitte ändern Sie die Domains vorher auf eine andere IP/Port-Kombination, um diese löschen zu können.',
@ -892,8 +893,8 @@ return [
'autoupdate_10' => 'Minimum unterstützte Version von PHP ist 7.4.0',
'autoupdate_11' => 'Webupdate ist deaktiviert',
'mailaccistobedeleted' => 'Ein vorheriges Konto mit dem gleichen Namen (%s) wird aktuell noch gelöscht und kann daher derzeit nicht angelegt werden',
'customerhasongoingbackupjob' => 'Es gibt noch einen austehenden Backup-Job. Bitte haben Sie etwas Geduld.',
'backupfunctionnotenabled' => 'Die Sicherungs-Funktion is nicht aktiviert',
'customerhasongoingexportjob' => 'Es gibt noch einen austehenden Daten-Export. Bitte haben Sie etwas Geduld.',
'exportfunctionnotenabled' => 'Die Datenexport-Funktion is nicht aktiviert',
'dns_domain_nodns' => 'DNS ist für diese Domain nicht aktiviert',
'dns_content_empty' => 'Keinen Inhalt angegeben',
'dns_content_invalid' => 'DNS Eintrag ungültig',
@ -950,10 +951,10 @@ return [
'execute_perl' => 'Perl/CGI ausführen',
'htpasswdauthname' => 'Grund der Authentifizierung (AuthName)',
'directoryprotection_edit' => 'Verzeichnisschutz bearbeiten',
'backup' => 'Sicherung erstellen',
'backup_web' => 'Web-Daten sichern',
'backup_mail' => 'E-Mail Daten sichern',
'backup_dbs' => 'Datenbanken sichern',
'export' => 'Datenexport erstellen',
'dump_web' => 'Web-Daten hinzufügen',
'dump_mail' => 'E-Mail Daten hinzufügen',
'dump_dbs' => 'Datenbanken hinzufügen',
'path_protection_label' => '<strong class="text-danger">Wichtig</strong>',
'path_protection_info' => 'Wir raten dringend dazu den angegebenen Pfad zu schützen, siehe "Extras" -> "Verzeichnisschutz"',
],
@ -1102,7 +1103,7 @@ Vielen Dank, Ihr Administrator',
'extras' => 'Extras',
'directoryprotection' => 'Verzeichnisschutz',
'pathoptions' => 'Pfadoptionen',
'backup' => 'Sicherung',
'export' => 'Datenexport',
],
'traffic' => [
'traffic' => 'Traffic',
@ -1198,13 +1199,13 @@ Vielen Dank, Ihr Administrator',
'ftpdesc' => 'FTP-Beschreibung',
'letsencrypt' => 'Benutzt Let\'s encrypt',
'set' => 'Setzen',
'backuppath' => [
'title' => 'Pfad zur Ablage der Backups',
'description' => 'In diesem Ordner werden die Backups abgelegt. Wenn das Sichern von Web-Daten aktiviert ist, werden alle Dateien aus dem Heimatverzeichnis gesichert, exklusive des hier angegebenen Backup-Ordners.',
'exportpath' => [
'title' => 'Pfad zur Ablage des Exports',
'description' => 'In diesem Ordner werden die Export-Archive abgelegt. Wenn Web-Daten exportiert werden, werden alle Dateien aus dem Heimatverzeichnis gesichert, exklusive des hier angegebenen Ordners.',
],
'backup_pgp_public_key' => [
'export_pgp_public_key' => [
'title' => 'Öffentlicher PGP-Schlüssel',
'description' => 'Der öffentliche PGP-Schlüssel, mit dem die Backups verschlüsselt werden sollen. Wenn kein Schlüssel angegeben ist, werden die Backups nicht verschlüsselt.',
'description' => 'Der öffentliche PGP-Schlüssel, mit dem die Exporte verschlüsselt werden sollen. Wenn kein Schlüssel angegeben ist, werden die Exporte nicht verschlüsselt.',
],
'pgp_public_key' => 'Öffentlicher PGP-Schlüssel',
'none_value' => 'Keine',
@ -1273,7 +1274,7 @@ Vielen Dank, Ihr Administrator',
'email_reallydelete_forwarder' => 'Wollen Sie die Weiterleitung "%s" wirklich löschen?',
'extras_reallydelete' => 'Wollen Sie den Verzeichnisschutz für "%s" wirklich löschen?',
'extras_reallydelete_pathoptions' => 'Wollen Sie die Optionen für den Pfad "%s" wirklich löschen?',
'extras_reallydelete_backup' => 'Wollen Sie die geplante Sicherung wirklich löschen?',
'extras_reallydelete_export' => 'Wollen Sie den geplanten Daten-Export wirklich löschen?',
'ftp_reallydelete' => 'Wollen Sie das FTP-Benutzerkonto "%s" wirklich löschen?',
'mysql_reallydelete' => 'Wollen Sie die Datenbank "%s" wirklich löschen?<br />ACHTUNG! Alle Daten gehen unwiderruflich verloren!',
'admin_configs_reallyrebuild' => 'Wollen Sie wirklich alle Konfigurationsdateien neu erstellen lassen?',
@ -1925,9 +1926,9 @@ Vielen Dank, Ihr Administrator',
'title' => 'Zusätzliche CAA DNS Einträge',
'description' => 'DNS Certification Authority Authorization (CAA) verwendet das Domain Name System, um dem Besitzer einer Domain die Möglichkeit zu bieten, gewisse Zertifizierungsstellen (CAs) dazu zu berechtigen,<br>ein Zertifikat für die betroffene Domain auszustellen. CAA Records sollen verhindern, dass Zertifikate fälschlicherweise für eine Domain ausgestellt werden.<br><br>Der Inhalt dieses Feldes wird direkt in die DNS Zone übernommen (eine Zeile pro CAA Record). Wenn Let\'s Encrypt für eine Domain aktiviert wurde und die obige Option aktiviert wurde, wird immer automatisch dieser Eintrag angefügt und muss nicht selber angegeben werden:<br><code>0 issue "letsencrypt.org"</code> (Wenn wildcard aktiviert ist, wird statdessen issuewild benutzt).<br>Um Incident Reporting per Mail zu aktivieren, muss eine <code>iodef</code> Zeile angefügt werden. Ein Beispiel für einen Report an <code>me@example.com</code> wäre:<br><code>0 iodef "mailto:me@example.com"</code><br><br><strong>ACHTUNG:</strong> Der Code wird nicht auf Fehler geprüft. Etwaige Fehler werden also auch übernommen. Die CAA finalen Einträge könnten daher falsch sein!',
],
'backupenabled' => [
'title' => 'Backup für Kunden aktivieren',
'description' => 'Wenn dies aktiviert ist, kann der Kunde Sicherungen planen (cron-backup) welche ein Archiv in sein Heimatverzeichnis ablegt (Unterordner vom Kunden wählbar)',
'exportenabled' => [
'title' => 'Daten-Export für Kunden aktivieren',
'description' => 'Wenn dies aktiviert ist, kann der Kunde Daten-Exporte planen (cron-export) welche ein Archiv in sein Heimatverzeichnis ablegen (Unterordner vom Kunden wählbar)',
],
'dnseditorenable' => [
'title' => 'DNS Editor aktivieren',
@ -2097,8 +2098,8 @@ Vielen Dank, Ihr Administrator',
'settingssaved' => 'Die Einstellungen wurden erfolgreich gespeichert.',
'rebuildingconfigs' => 'Task für Neuerstellung der Konfigurationen wurde erfolgreich eingetragen',
'domain_import_successfully' => 'Erfolgreich %s Domains importiert.',
'backupscheduled' => 'Ihre Sicherung wurde erfolgreich geplant. Bitte warten Sie nun, bis diese abgearbeitet wurde.',
'backupaborted' => 'Die geplante Sicherung wurde abgebrochen',
'exportscheduled' => 'Ihr Daten-Export wurde erfolgreich geplant. Bitte warten Sie nun, bis dieser bearbeitet wurde.',
'exportaborted' => 'Der geplante Daten-Export wurde abgebrochen',
'dns_record_added' => 'Eintrag erfolgreich hinzugefügt',
'dns_record_deleted' => 'Eintrag erfolgreich entfernt',
'testmailsent' => 'Test E-Mail erfolgreich gesendet',
@ -2117,7 +2118,7 @@ Vielen Dank, Ihr Administrator',
'DELETE_EMAIL_DATA' => 'E-Mail-Dateien des Kunden löschen',
'DELETE_FTP_DATA' => 'Kunden FTP-Konto Dateien löschen',
'REBUILD_CRON' => 'Neuerstellung der cron.d-Datei',
'CREATE_CUSTOMER_BACKUP' => 'Datensicherung für Kunde %s',
'CREATE_CUSTOMER_DATADUMP' => 'Daten-Export für Kunde %s',
'DELETE_DOMAIN_PDNS' => 'Lösche Domain %s von PowerDNS Datenbank',
'DELETE_DOMAIN_SSL' => 'Lösche SSL Dateien von Domain %s',
],

View File

@ -573,7 +573,8 @@ return [
'cron_usage_report' => 'Web- and traffic-reports',
'cron_mailboxsize' => 'Mailbox-size calculation',
'cron_letsencrypt' => 'Let\'s Encrypt certificate updates',
'cron_backup' => 'Process backup jobs',
'cron_export' => 'Process data-export jobs',
'cron_backup' => 'Process system- and customer backup jobs',
],
'cronjob' => [
'cronjobsettings' => 'Cronjob settings',
@ -844,7 +845,7 @@ return [
'destinationalreadyexistasmail' => 'The forwarder to %s already exists as active email-address.',
'destinationalreadyexist' => 'You have already defined a forwarder to "%s"',
'destinationiswrong' => 'The forwarder %s contains invalid character(s) or is incomplete.',
'backupfoldercannotbedocroot' => 'The folder for backups cannot be your homedir, please chose a folder within your homedir, e.g. /backups',
'dumpfoldercannotbedocroot' => 'The folder for data-dumps cannot be your homedir, please chose a folder within your homedir, e.g. /dumps',
'templatelanguagecombodefined' => 'The selected language/template combination has already been defined.',
'templatelanguageinvalid' => 'The selected language does not exist',
'ipstillhasdomains' => 'The IP/Port combination you want to delete still has domains assigned to it, please reassign those to other IP/Port combinations before deleting this IP/Port combination.',
@ -964,8 +965,8 @@ return [
'autoupdate_10' => 'Minimum supported version of PHP is 7.4.0',
'autoupdate_11' => 'Webupdate is disabled',
'mailaccistobedeleted' => 'Another account with the same name (%s) is currently being deleted and can therefore not be added at this moment.',
'customerhasongoingbackupjob' => 'There is already a backup job waiting to be processed, please be patient.',
'backupfunctionnotenabled' => 'The backup function is not enabled',
'customerhasongoingexportjob' => 'There is already a data export job waiting to be processed, please be patient.',
'exportfunctionnotenabled' => 'The export function is not enabled',
'dns_domain_nodns' => 'DNS is not enabled for this domain',
'dns_content_empty' => 'No content given',
'dns_content_invalid' => 'DNS content invalid',
@ -1022,10 +1023,10 @@ return [
'execute_perl' => 'Execute perl/CGI',
'htpasswdauthname' => 'Authentication reason (AuthName)',
'directoryprotection_edit' => 'Edit directory protection',
'backup' => 'Create backup',
'backup_web' => 'Backup web-data',
'backup_mail' => 'Backup mail-data',
'backup_dbs' => 'Backup databases',
'export' => 'Create data dump',
'dump_web' => 'Include web-data',
'dump_mail' => 'Include mail-data',
'dump_dbs' => 'Include databases',
'path_protection_label' => '<strong class="text-danger">Important</strong>',
'path_protection_info' => 'We strongly recommend protecting the given path, see "Extras" -> "Directory protection"',
],
@ -1174,7 +1175,7 @@ Yours sincerely, your administrator',
'extras' => 'Extras',
'directoryprotection' => 'Directory protection',
'pathoptions' => 'Path options',
'backup' => 'Backup',
'export' => 'Data export',
],
'traffic' => [
'traffic' => 'Traffic',
@ -1313,13 +1314,13 @@ Yours sincerely, your administrator',
'letsencrypt' => 'Using Let\'s encrypt',
'set' => 'Apply',
'shell' => 'Shell',
'backuppath' => [
'title' => 'Destination path for the backup',
'description' => 'This is the path where the backups will be stored. If backup of web-data is selected, all files from the homedir are stored excluding the backup-folder specified here.',
'exportpath' => [
'title' => 'Destination path for the exported data',
'description' => 'This is the path where the export-archive will be stored. If web-data is being included, all files from the homedir are stored excluding the folder specified here.',
],
'backup_pgp_public_key' => [
'export_pgp_public_key' => [
'title' => 'Public PGP key for encryption',
'description' => 'This is the public PGP key which will be used to encrypt the backup. If you leave this field empty, the backup will not be encrypted.',
'description' => 'This is the public PGP key which will be used to encrypt the export. If you leave this field empty, the export will not be encrypted.',
],
'pgp_public_key' => 'Public PGP key',
'none_value' => 'None',
@ -1388,7 +1389,7 @@ Yours sincerely, your administrator',
'email_reallydelete_forwarder' => 'Do you really want to delete the forwarder %s?',
'extras_reallydelete' => 'Do you really want to delete the directory protection for %s?',
'extras_reallydelete_pathoptions' => 'Do you really want to delete the path options for %s?',
'extras_reallydelete_backup' => 'Do you really want to abort the planned backup job?',
'extras_reallydelete_export' => 'Do you really want to abort the planned export job?',
'ftp_reallydelete' => 'Do you really want to delete the FTP-account %s?',
'mysql_reallydelete' => 'Do you really want to delete the database %s? This cannot be undone!',
'admin_configs_reallyrebuild' => 'Do you really want to rebuild all config files?',
@ -2047,9 +2048,9 @@ Yours sincerely, your administrator',
'title' => 'Additional CAA DNS records',
'description' => 'DNS Certification Authority Authorization (CAA) is an Internet security policy mechanism which allows domain name holders to indicate to certificate authorities<br>whether they are authorized to issue digital certificates for a particular domain name. It does this by means of a new "CAA" Domain Name System (DNS) resource record.<br><br>The content of this field will be included into the DNS zone directly (each line results in a CAA record).<br>If Let\'s Encrypt is enabled for this domain, this entry will always be added automatically and does not need to be added manually:<br><code>0 issue "letsencrypt.org"</code> (If domain is a wildcard domain, issuewild will be used instead).<br>To enable Incident Reporting, you can add an <code>iodef</code> record. An example for sending such report to <code>me@example.com</code> would be:<br><code>0 iodef "mailto:me@example.com"</code><br><br><strong>Attention:</strong> The code won\'t be checked for any errors. If it contains errors, your CAA records might not work!',
],
'backupenabled' => [
'title' => 'Enable backup for customers',
'description' => 'If activated, the customer will be able to schedule backup jobs (cron-backup) which generates an archive within his docroot (subdirectory chosable by customer)',
'exportenabled' => [
'title' => 'Enable data export for customers',
'description' => 'If activated, the customer will be able to schedule data export jobs (cron-export) which generates an archive within his docroot (subdirectory chosable by customer)',
],
'dnseditorenable' => [
'title' => 'Enable DNS editor',
@ -2230,8 +2231,8 @@ Yours sincerely, your administrator',
'settingssaved' => 'The settings have been successfully saved.',
'rebuildingconfigs' => 'Successfully inserted tasks for rebuild configfiles',
'domain_import_successfully' => 'Successfully imported %s domains.',
'backupscheduled' => 'Your backup job has been scheduled. Please wait for it to be processed',
'backupaborted' => 'Your scheduled backup has been cancelled',
'exportscheduled' => 'Your export job has been scheduled. Please wait for it to be processed',
'exportaborted' => 'Your scheduled export has been cancelled',
'dns_record_added' => 'Record added successfully',
'dns_record_deleted' => 'Record deleted successfully',
'testmailsent' => 'Test mail sent successfully',
@ -2250,7 +2251,7 @@ Yours sincerely, your administrator',
'DELETE_EMAIL_DATA' => 'Delete customer e-mail data.',
'DELETE_FTP_DATA' => 'Delete customer ftp-account data.',
'REBUILD_CRON' => 'Rebuilding the cron.d-file',
'CREATE_CUSTOMER_BACKUP' => 'Backup job for customer %s',
'CREATE_CUSTOMER_DATADUMP' => 'Data export job for customer %s',
'DELETE_DOMAIN_PDNS' => 'Delete domain %s from PowerDNS database',
'DELETE_DOMAIN_SSL' => 'Delete ssl files of domain %s',
],

View File

@ -837,7 +837,6 @@ return [
'destinationalreadyexistasmail' => 'El remitente a %s ya existe como dirección de correo electrónico activa.',
'destinationalreadyexist' => 'Ya ha definido un reenviador para "%s".',
'destinationiswrong' => 'La %s la redirección contiene caracteres no válidos o está incompleta.',
'backupfoldercannotbedocroot' => 'La carpeta para las copias de seguridad no puede ser su carpeta de inicio, elija una carpeta dentro de su carpeta de inicio, por ejemplo, /backups.',
'templatelanguagecombodefined' => 'La combinación idioma/plantilla seleccionada ya ha sido definida.',
'templatelanguageinvalid' => 'El idioma seleccionado no existe.',
'ipstillhasdomains' => 'La combinación IP/Puerto que desea eliminar todavía tiene dominios asignados, por favor reasígnelos a otras combinaciones IP/Puerto antes de eliminar esta combinación IP/Puerto.',
@ -958,7 +957,6 @@ return [
'autoupdate_11' => 'Webupdate está desactivado',
'mailaccistobedeleted' => 'Otra cuenta con el mismo nombre (%s) está siendo eliminada y por lo tanto no puede ser añadida en este momento.',
'customerhasongoingbackupjob' => 'Ya hay un trabajo de copia de seguridad esperando a ser procesado, por favor sea paciente.',
'backupfunctionnotenabled' => 'La función de copia de seguridad no está habilitada',
'dns_domain_nodns' => 'DNS no está habilitado para este dominio',
'dns_content_empty' => 'No hay contenido',
'dns_content_invalid' => 'El contenido DNS no es válido',
@ -1010,10 +1008,6 @@ return [
'execute_perl' => 'Ejecutar perl/CGI',
'htpasswdauthname' => 'Razón de autenticación (AuthName)',
'directoryprotection_edit' => 'Editar protección de directorio',
'backup' => 'Crear copia de seguridad',
'backup_web' => 'Copia de seguridad de datos web',
'backup_mail' => 'Copia de seguridad de los datos de correo',
'backup_dbs' => 'Copia de seguridad de bases de datos',
'path_protection_label' => '<strong class="text-danger">Importante</strong>',
'path_protection_info' => 'Le recomendamos encarecidamente que proteja la ruta indicada, consulte "Extras" -> "Protección de directorios".'
],
@ -1162,7 +1156,7 @@ Atentamente, su administrador'
'extras' => 'Extras',
'directoryprotection' => 'Protección de directorios',
'pathoptions' => 'Opciones de ruta',
'backup' => 'Copia de seguridad'
'export' => 'Exportación de datos'
],
'traffic' => [
'traffic' => 'Tráfico',
@ -1371,7 +1365,6 @@ Atentamente, su administrador'
'email_reallydelete_forwarder' => '¿Realmente quieres borrar el forwarder %s?',
'extras_reallydelete' => '¿Realmente quieres borrar la protección de directorio de %s?',
'extras_reallydelete_pathoptions' => '¿Realmente quieres borrar las opciones de ruta de %s?',
'extras_reallydelete_backup' => '¿Realmente quieres abortar el trabajo de copia de seguridad planificado?',
'ftp_reallydelete' => '¿Realmente quieres borrar la cuenta FTP %s?',
'mysql_reallydelete' => '¿Realmente quieres borrar la base de datos %s? Esto no se puede deshacer.',
'admin_configs_reallyrebuild' => '¿Realmente quieres reconstruir todos los archivos de configuración?',
@ -2030,10 +2023,6 @@ Atentamente, su administrador'
'title' => 'Registros DNS CAA adicionales',
'description' => 'DNS Certification Authority Authorization (CAA) es un mecanismo de política de seguridad en Internet que permite a los titulares de nombres de dominio indicar a las autoridades de certificación<br/>si están autorizadas a emitir certificados digitales para un nombre de dominio concreto. Lo hace mediante un nuevo registro de recursos del Sistema de Nombres de Dominio (DNS) "CAA".<br/><br/>El contenido de este campo se incluirá en la zona DNS directamente (cada línea da lugar a un registro CAA).<br/>Si Let\'s Encrypt está habilitado para este dominio, esta entrada siempre se añadirá automáticamente y no es necesario añadirla manualmente:<br/> 0<code>issue "letsencrypt.org"</code> (Si el dominio es un dominio comodín, se utilizará issuewild en su lugar).<br/>Para habilitar el informe de incidentes, puede añadir un registro <code>iodef</code>. Un ejemplo para enviar dicho informe a <code>me@example.com</code> sería:<br/> 0<code>iodef "mailto:me@example.com"</code><br/><br/><strong>Atención:</strong> No se comprobará si el código contiene errores. Si contiene errores, ¡es posible que sus registros CAA no funcionen!'
],
'backupenabled' => [
'title' => 'Activar copia de seguridad para clientes',
'description' => 'Si se activa, el cliente podrá programar trabajos de copia de seguridad (cron-backup) que generan un archivo dentro de su docroot (subdirectorio a elección del cliente)'
],
'dnseditorenable' => [
'title' => 'Habilitar editor DNS',
'description' => 'Permite a los administradores y a los clientes gestionar las entradas DNS del dominio'
@ -2209,8 +2198,6 @@ Atentamente, su administrador'
'settingssaved' => 'La configuración se ha guardado correctamente.',
'rebuildingconfigs' => 'Tareas insertadas con éxito para reconstruir archivos de configuración',
'domain_import_successfully' => 'Se han importado correctamente los dominios %s.',
'backupscheduled' => 'Se ha programado su tarea de copia de seguridad. Espere a que se procese.',
'backupaborted' => 'Su copia de seguridad programada ha sido cancelada',
'dns_record_added' => 'Registro añadido correctamente',
'dns_record_deleted' => 'Registro eliminado correctamente',
'testmailsent' => 'Correo de prueba enviado correctamente',
@ -2229,7 +2216,6 @@ Atentamente, su administrador'
'DELETE_EMAIL_DATA' => 'Borrar datos de e-mail del cliente.',
'DELETE_FTP_DATA' => 'Borrar los datos de la cuenta ftp del cliente.',
'REBUILD_CRON' => 'Reconstruir el archivo cron.d',
'CREATE_CUSTOMER_BACKUP' => 'Trabajo de copia de seguridad para el cliente %s',
'DELETE_DOMAIN_PDNS' => 'Borrar dominio %s de la base de datos PowerDNS',
'DELETE_DOMAIN_SSL' => 'Borrar archivos ssl de dominio %s'
],

View File

@ -4,22 +4,22 @@ use PHPUnit\Framework\TestCase;
use Froxlor\Settings;
use Froxlor\Database\Database;
use Froxlor\Api\Commands\Customers;
use Froxlor\Api\Commands\CustomerBackups;
use Froxlor\Api\Commands\DataDump;
/**
*
* @covers \Froxlor\Api\ApiCommand
* @covers \Froxlor\Api\ApiParameter
* @covers \Froxlor\Api\Commands\CustomerBackups
* @covers \Froxlor\Api\Commands\DataDump
*/
class CustomerBackupsTest extends TestCase
class DataDumpTest extends TestCase
{
public function testAdminCustomerBackupsNotEnabled()
public function testAdminDataDumpNotEnabled()
{
global $admin_userdata;
Settings::Set('system.backupenabled', 0, true);
Settings::Set('system.exportenabled', 0, true);
// get customer
$json_result = Customers::getLocal($admin_userdata, array(
@ -28,18 +28,18 @@ class CustomerBackupsTest extends TestCase
$customer_userdata = json_decode($json_result, true)['data'];
$this->expectExceptionCode(405);
$this->expectExceptionMessage("You cannot access this resource");
CustomerBackups::getLocal($customer_userdata)->add();
DataDump::getLocal($customer_userdata)->add();
}
/**
*
* @depends testAdminCustomerBackupsNotEnabled
* @depends testAdminDataDumpNotEnabled
*/
public function testAdminCustomerBackupsExtrasHidden()
public function testAdminDataDumpExtrasHidden()
{
global $admin_userdata;
Settings::Set('system.backupenabled', 1, true);
Settings::Set('system.exportenabled', 1, true);
Settings::Set('panel.customer_hide_options', 'extras', true);
// get customer
@ -49,18 +49,18 @@ class CustomerBackupsTest extends TestCase
$customer_userdata = json_decode($json_result, true)['data'];
$this->expectExceptionCode(405);
$this->expectExceptionMessage("You cannot access this resource");
CustomerBackups::getLocal($customer_userdata)->add();
DataDump::getLocal($customer_userdata)->add();
}
/**
*
* @depends testAdminCustomerBackupsExtrasHidden
* @depends testAdminDataDumpExtrasHidden
*/
public function testAdminCustomerBackupsExtrasBackupHidden()
public function testAdminDataDumpExtrasExportHidden()
{
global $admin_userdata;
Settings::Set('panel.customer_hide_options', 'extras.backup', true);
Settings::Set('panel.customer_hide_options', 'extras.export', true);
// get customer
$json_result = Customers::getLocal($admin_userdata, array(
@ -69,14 +69,14 @@ class CustomerBackupsTest extends TestCase
$customer_userdata = json_decode($json_result, true)['data'];
$this->expectExceptionCode(405);
$this->expectExceptionMessage("You cannot access this resource");
CustomerBackups::getLocal($customer_userdata)->add();
DataDump::getLocal($customer_userdata)->add();
}
/**
*
* @depends testAdminCustomerBackupsExtrasBackupHidden
* @depends testAdminDataDumpExtrasExportHidden
*/
public function testCustomerCustomerBackupsAdd()
public function testCustomerDataDumpAdd()
{
global $admin_userdata;
@ -90,24 +90,24 @@ class CustomerBackupsTest extends TestCase
$customer_userdata = json_decode($json_result, true)['data'];
$data = [
'path' => '/my-backup',
'backup_dbs' => 2,
'backup_mail' => 3,
'backup_web' => 4
'path' => '/my-dump',
'dump_dbs' => 2,
'dump_mail' => 3,
'dump_web' => 4
];
$json_result = CustomerBackups::getLocal($customer_userdata, $data)->add();
$json_result = DataDump::getLocal($customer_userdata, $data)->add();
$result = json_decode($json_result, true)['data'];
$this->assertEquals($customer_userdata['documentroot'] . 'my-backup/', $result['destdir']);
$this->assertEquals('1', $result['backup_dbs']);
$this->assertEquals('1', $result['backup_mail']);
$this->assertEquals('1', $result['backup_web']);
$this->assertEquals($customer_userdata['documentroot'] . 'my-dump/', $result['destdir']);
$this->assertEquals('1', $result['dump_dbs']);
$this->assertEquals('1', $result['dump_mail']);
$this->assertEquals('1', $result['dump_web']);
}
/**
*
* @depends testCustomerCustomerBackupsAdd
* @depends testCustomerDataDumpAdd
*/
public function testCustomerCustomerBackupsAddPathNotDocroot()
public function testCustomerDataDumpAddPathNotDocroot()
{
global $admin_userdata;
@ -122,49 +122,49 @@ class CustomerBackupsTest extends TestCase
];
$this->expectExceptionCode(400);
$this->expectExceptionMessage('The folder for backups cannot be your homedir, please chose a folder within your homedir, e.g. /backups');
$json_result = CustomerBackups::getLocal($customer_userdata, $data)->add();
$this->expectExceptionMessage('The folder for data-dumps cannot be your homedir, please chose a folder within your homedir, e.g. /dumps');
$json_result = DataDump::getLocal($customer_userdata, $data)->add();
}
public function testAdminCustomerBackupsGet()
public function testAdminDataDumpGet()
{
global $admin_userdata;
$this->expectExceptionCode(303);
CustomerBackups::getLocal($admin_userdata)->get();
DataDump::getLocal($admin_userdata)->get();
}
public function testAdminCustomerBackupsUpdate()
public function testAdminDataDumpUpdate()
{
global $admin_userdata;
$this->expectExceptionCode(303);
CustomerBackups::getLocal($admin_userdata)->update();
DataDump::getLocal($admin_userdata)->update();
}
/**
*
* @depends testCustomerCustomerBackupsAdd
* @depends testCustomerDataDumpAdd
*/
public function testAdminCustomerBackupsListing()
public function testAdminDataDumpListing()
{
global $admin_userdata;
$json_result = CustomerBackups::getLocal($admin_userdata)->listing();
$json_result = DataDump::getLocal($admin_userdata)->listing();
$result = json_decode($json_result, true)['data'];
$this->assertEquals(1, $result['count']);
$this->assertEquals('1', $result['list'][0]['data']['backup_dbs']);
$this->assertEquals('1', $result['list'][0]['data']['backup_mail']);
$this->assertEquals('1', $result['list'][0]['data']['backup_web']);
$this->assertEquals('1', $result['list'][0]['data']['dump_dbs']);
$this->assertEquals('1', $result['list'][0]['data']['dump_mail']);
$this->assertEquals('1', $result['list'][0]['data']['dump_web']);
$json_result = CustomerBackups::getLocal($admin_userdata)->listingCount();
$json_result = DataDump::getLocal($admin_userdata)->listingCount();
$result = json_decode($json_result, true)['data'];
$this->assertEquals(1, $result);
}
/**
*
* @depends testCustomerCustomerBackupsAdd
* @depends testCustomerDataDumpAdd
*/
public function testCustomerCustomerBackupsDelete()
public function testCustomerDataDumpDelete()
{
global $admin_userdata;
@ -175,18 +175,18 @@ class CustomerBackupsTest extends TestCase
$customer_userdata = json_decode($json_result, true)['data'];
$data = [
'backup_job_entry' => 1
'job_entry' => 1
];
$json_result = CustomerBackups::getLocal($customer_userdata, $data)->delete();
$json_result = DataDump::getLocal($customer_userdata, $data)->delete();
$result = json_decode($json_result, true)['data'];
$this->assertTrue($result);
}
/**
*
* @depends testAdminCustomerBackupsListing
* @depends testAdminDataDumpListing
*/
public function testCustomerCustomerBackupsDeleteNotFound()
public function testCustomerDataDumpDeleteNotFound()
{
global $admin_userdata;
@ -200,7 +200,7 @@ class CustomerBackupsTest extends TestCase
'backup_job_entry' => 1337
];
$this->expectExceptionCode(404);
$this->expectExceptionMessage('Backup job with id #1337 could not be found');
CustomerBackups::getLocal($customer_userdata, $data)->delete();
$this->expectExceptionMessage('Data export job with id #1337 could not be found');
DataDump::getLocal($customer_userdata, $data)->delete();
}
}

View File

@ -30,7 +30,7 @@ class TaskIDTest extends TestCase
'DELETE_DOMAIN_SSL' => 12,
'CREATE_CUSTOMER_BACKUP' => 20,
'CREATE_CUSTOMER_DATADUMP' => 20,
'REBUILD_CRON' => 99,
);