Feature/crontaskid (#1005)

* Add \Froxlor\Cron\TaskId for fixed task id naming

* Replace Cronjob::inserttask numbers with \Froxlor\Cron\TaskId constants

* Use TaskId in Froxlor\Cron\System\TasksCron

* Use TaskId in Froxlor\System\Cronjob,
simplify getOutstandingTasks.
Rename lng['tasks'] cronjob task description.
WARNING: DELETE_DOMAIN_PDNS, DELETE_DOMAIN_SSL now use %domain%

* Remove Froxlor\System\Cronjob type 3 check
This commit is contained in:
Oskar Eisemuth
2022-01-21 10:03:45 +01:00
committed by GitHub
parent bcb95e9b7d
commit 4a912e3902
30 changed files with 368 additions and 208 deletions

View File

@@ -323,7 +323,7 @@ class Certificates extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou
));
// trigger removing of certificate from acme.sh if let's encrypt
if ($chk['letsencrypt'] == '1') {
\Froxlor\System\Cronjob::inserttask('12', $chk['domain']);
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::DELETE_DOMAIN_SSL, $chk['domain']);
}
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_INFO, "[API] removed ssl-certificate for '" . $chk['domain'] . "'");
return $this->response(200, "successful", $result);
@@ -421,7 +421,7 @@ class Certificates extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou
);
Database::pexecute($stmt, $params, true, true);
// insert task to re-generate webserver-configs (#1260)
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
return true;
}
}

View File

@@ -114,7 +114,7 @@ class Cronjobs extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceE
), true, true);
// insert task to re-generate the cron.d-file
\Froxlor\System\Cronjob::inserttask('99');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_CRON);
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] cronjob with description '" . $result['module'] . '/' . $result['cronfile'] . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
$result = $this->apiCall('Cronjobs.get', array(
'id' => $id

View File

@@ -108,7 +108,7 @@ class CustomerBackups extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Re
'backup_web' => $backup_web
);
// schedule backup job
\Froxlor\System\Cronjob::inserttask('20', $task_data);
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::CREATE_CUSTOMER_BACKUP, $task_data);
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] added customer-backup job for '" . $customer['loginname'] . "'. Target directory: " . $userpath);
return $this->response(200, "successful", $task_data);

View File

@@ -645,10 +645,10 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
unset($ins_data);
// insert task to create homedir etc.
\Froxlor\System\Cronjob::inserttask('2', $loginname, $guid, $guid, $store_defaultindex);
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::CREATE_HOME, $loginname, $guid, $guid, $store_defaultindex);
// Using filesystem - quota, insert a task which cleans the filesystem - quota
\Froxlor\System\Cronjob::inserttask('10');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::CREATE_QUOTA);
// Add htpasswd for the stats-pages
$htpasswdPassword = \Froxlor\System\Crypt::makeCryptPassword($password, true);
@@ -674,7 +674,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] automatically added " . $stats_folder . " htpasswd for user '" . $loginname . "'");
Database::pexecute($ins_stmt, $ins_data, true, true);
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
// add default FTP-User
// also, add froxlor-local user to ftp-group (if exists!) to
@@ -739,7 +739,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
'customerid' => $customerid
), true, true);
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] automatically added standardsubdomain for user '" . $loginname . "'");
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
}
}
@@ -1088,7 +1088,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
'customerid' => $result['customerid']
), true, true);
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] automatically added standardsubdomain for user '" . $result['loginname'] . "'");
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
}
}
@@ -1102,11 +1102,11 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_ERR, "[API] Unable to delete standard-subdomain: " . $e->getMessage());
}
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "[API] automatically deleted standardsubdomain for user '" . $result['loginname'] . "'");
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
}
if ($phpenabled != $result['phpenabled'] || $perlenabled != $result['perlenabled'] || $email != $result['email']) {
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
}
// activate/deactivate customer services
@@ -1192,7 +1192,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
), true, true);
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] " . ($deactivated ? 'deactivated' : 'reactivated') . " user '" . $result['loginname'] . "'");
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
}
// Disable or enable POP3 Login for customers Mail Accounts
@@ -1304,7 +1304,7 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
if ($this->isAdmin()) {
// Using filesystem - quota, insert a task which cleans the filesystem - quota
\Froxlor\System\Cronjob::inserttask('10');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::CREATE_QUOTA);
$admin_update_query = "UPDATE `" . TABLE_PANEL_ADMINS . "` SET `customers_used` = `customers_used` ";
@@ -1512,9 +1512,9 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
'did' => $row['id']
), true, true);
// remove domains DNS from powerDNS if used, #581
\Froxlor\System\Cronjob::inserttask('11', $row['domain']);
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::DELETE_DOMAIN_PDNS, $row['domain']);
// remove domain from acme.sh / lets encrypt if used
\Froxlor\System\Cronjob::inserttask('12', $row['domain']);
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::DELETE_DOMAIN_SSL, $row['domain']);
}
// remove customer domains
$stmt = Database::prepare("DELETE FROM `" . TABLE_PANEL_DOMAINS . "` WHERE `customerid` = :id");
@@ -1643,18 +1643,18 @@ class Customers extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resource
}
// rebuild configs
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
// Using nameserver, insert a task which rebuilds the server config
\Froxlor\System\Cronjob::inserttask('4');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_DNS);
if ($delete_userfiles == 1) {
// insert task to remove the customers files from the filesystem
\Froxlor\System\Cronjob::inserttask('6', $result['loginname']);
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::DELETE_CUSTOMER_FILES, $result['loginname']);
}
// Using filesystem - quota, insert a task which cleans the filesystem - quota
\Froxlor\System\Cronjob::inserttask('10');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::CREATE_QUOTA);
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] deleted customer '" . $result['loginname'] . "'");
return $this->response(200, "successful", $result);

View File

@@ -123,7 +123,7 @@ class DirOptions extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
Database::pexecute($stmt, $params, true, true);
$id = Database::lastInsertId();
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added directory-option for '" . $userpath . "'");
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
$result = $this->apiCall('DirOptions.get', array(
'id' => $id
@@ -248,7 +248,7 @@ class DirOptions extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
}
if (($options_indexes != $result['options_indexes']) || ($error404path != $result['error404path']) || ($error403path != $result['error403path']) || ($error500path != $result['error500path']) || ($options_cgi != $result['options_cgi'])) {
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
$stmt = Database::prepare("
UPDATE `" . TABLE_PANEL_HTACCESS . "`
SET `options_indexes` = :options_indexes,
@@ -413,7 +413,7 @@ class DirOptions extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
"id" => $id
), true, true);
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted directory-option for '" . str_replace($customer_data['documentroot'], '/', $result['path']) . "'");
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
return $this->response(200, "successful", $result);
}

View File

@@ -106,7 +106,7 @@ class DirProtections extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Res
Database::pexecute($stmt, $params, true, true);
$id = Database::lastInsertId();
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added directory-protection for '" . $username . " (" . $path . ")'");
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
$result = $this->apiCall('DirProtections.get', array(
'id' => $id
@@ -251,7 +251,7 @@ class DirProtections extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Res
UPDATE `" . TABLE_PANEL_HTPASSWDS . "` SET " . $upd_query . " WHERE `id` = :id AND `customerid`= :cid
");
Database::pexecute($upd_stmt, $upd_params, true, true);
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
}
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_INFO, "[API] updated directory-protection '" . $result['username'] . " (" . $result['path'] . ")'");
@@ -385,7 +385,7 @@ class DirProtections extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Res
));
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_INFO, "[API] deleted htpasswd for '" . $result['username'] . " (" . $result['path'] . ")'");
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
return $this->response(200, "successful", $result);
}
}

View File

@@ -336,7 +336,7 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
$dom_entries[] = $new_entry;
// re-generate bind configs
\Froxlor\System\Cronjob::inserttask('4');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_DNS);
$result = $this->apiCall('DomainZones.get', array(
'id' => $id
@@ -542,7 +542,7 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
), true, true);
if ($del_stmt->rowCount() > 0) {
// re-generate bind configs
\Froxlor\System\Cronjob::inserttask('4');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_DNS);
return $this->response(200, "successful", true);
}
return $this->response(304, "successful", true);

View File

@@ -857,9 +857,9 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
\Froxlor\Domain\Domain::triggerLetsEncryptCSRForAliasDestinationDomain($aliasdomain, $this->logger());
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
// Using nameserver, insert a task which rebuilds the server config
\Froxlor\System\Cronjob::inserttask('4');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_DNS);
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] added domain '" . $domain . "'");
@@ -1465,7 +1465,7 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
$iswildcarddomain = ($serveraliasoption == '0') ? '1' : '0';
if ($documentroot != $result['documentroot'] || $ssl_redirect != $result['ssl_redirect'] || $wwwserveralias != $result['wwwserveralias'] || $iswildcarddomain != $result['iswildcarddomain'] || $phpenabled != $result['phpenabled'] || $openbasedir != $result['openbasedir'] || $phpsettingid != $result['phpsettingid'] || $mod_fcgid_starter != $result['mod_fcgid_starter'] || $mod_fcgid_maxrequests != $result['mod_fcgid_maxrequests'] || $specialsettings != $result['specialsettings'] || $ssl_specialsettings != $result['ssl_specialsettings'] || $notryfiles != $result['notryfiles'] || $writeaccesslog != $result['writeaccesslog'] || $writeerrorlog != $result['writeerrorlog'] || $aliasdomain != $result['aliasdomain'] || $issubof != $result['ismainbutsubto'] || $email_only != $result['email_only'] || ($speciallogfile != $result['speciallogfile'] && $speciallogverified == '1') || $letsencrypt != $result['letsencrypt'] || $http2 != $result['http2'] || $hsts_maxage != $result['hsts'] || $hsts_sub != $result['hsts_sub'] || $hsts_preload != $result['hsts_preload'] || $ocsp_stapling != $result['ocsp_stapling']) {
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
}
if ($speciallogfile != $result['speciallogfile'] && $speciallogverified != '1') {
@@ -1473,11 +1473,11 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
}
if ($isbinddomain != $result['isbinddomain'] || $zonefile != $result['zonefile'] || $dkim != $result['dkim'] || $isemaildomain != $result['isemaildomain']) {
\Froxlor\System\Cronjob::inserttask('4');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_DNS);
}
// check whether nameserver has been disabled, #581
if ($isbinddomain != $result['isbinddomain'] && $isbinddomain == 0) {
\Froxlor\System\Cronjob::inserttask('11', $result['domain']);
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::DELETE_DOMAIN_PDNS, $result['domain']);
}
if ($isemaildomain == '0' && $result['isemaildomain'] == '1') {
@@ -1506,7 +1506,7 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
'id' => $id
), true, true);
// remove domain from acme.sh / lets encrypt if used
\Froxlor\System\Cronjob::inserttask('12', $result['domain']);
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::DELETE_DOMAIN_SSL, $result['domain']);
}
$updatechildren = '';
@@ -1984,16 +1984,16 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
\Froxlor\Domain\Domain::triggerLetsEncryptCSRForAliasDestinationDomain($result['aliasdomain'], $this->logger());
// remove domains DNS from powerDNS if used, #581
\Froxlor\System\Cronjob::inserttask('11', $result['domain']);
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::DELETE_DOMAIN_PDNS, $result['domain']);
// remove domain from acme.sh / lets encrypt if used
\Froxlor\System\Cronjob::inserttask('12', $result['domain']);
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::DELETE_DOMAIN_SSL, $result['domain']);
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] deleted domain/subdomains (#" . $result['id'] . ")");
\Froxlor\User::updateCounters();
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
// Using nameserver, insert a task which rebuilds the server config
\Froxlor\System\Cronjob::inserttask('4');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_DNS);
return $this->response(200, "successful", $result);
}
throw new \Exception("Not allowed to execute given command.", 403);

View File

@@ -499,7 +499,7 @@ class EmailAccounts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Reso
}
if ($delete_userfiles) {
\Froxlor\System\Cronjob::inserttask('7', $customer['loginname'], $result['email_full']);
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::DELETE_EMAIL_DATA, $customer['loginname'], $result['email_full']);
}
// decrease usage for customer

View File

@@ -229,7 +229,7 @@ class FpmDaemons extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
Database::pexecute($ins_stmt, $ins_data);
$id = Database::lastInsertId();
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] fpm-daemon with description '" . $description . "' has been created by '" . $this->getUserDetail('loginname') . "'");
$result = $this->apiCall('FpmDaemons.get', array(
'id' => $id
@@ -351,7 +351,7 @@ class FpmDaemons extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
);
Database::pexecute($upd_stmt, $upd_data, true, true);
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] fpm-daemon with description '" . $description . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
$result = $this->apiCall('FpmDaemons.get', array(
'id' => $id
@@ -400,7 +400,7 @@ class FpmDaemons extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
'id' => $id
), true, true);
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] fpm-daemon setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'");
return $this->response(200, "successful", $result);
}

View File

@@ -123,12 +123,12 @@ class Froxlor extends \Froxlor\Api\ApiCommand
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "User " . $this->getUserDetail('loginname') . " imported settings");
try {
\Froxlor\SImExporter::import($json_str);
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask('10');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::CREATE_QUOTA);
// Using nameserver, insert a task which rebuilds the server config
\Froxlor\System\Cronjob::inserttask('4');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_DNS);
// cron.d file
\Froxlor\System\Cronjob::inserttask('99');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_CRON);
return $this->response(200, "successful", true);
} catch (\Exception $e) {
throw new \Exception($e->getMessage(), 406);

View File

@@ -234,7 +234,7 @@ class Ftps extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEntit
}
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_INFO, "[API] added ftp-account '" . $username . " (" . $path . ")'");
\Froxlor\System\Cronjob::inserttask(5);
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::CREATE_FTP);
if ($sendinfomail == 1) {
$replace_arr = array(
@@ -450,7 +450,7 @@ class Ftps extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEntit
}
// it's the task for "new ftp" but that will
// create all directories and correct their permissions
\Froxlor\System\Cronjob::inserttask(5);
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::CREATE_FTP);
$stmt = Database::prepare("
UPDATE `" . TABLE_FTP_USERS . "`
@@ -628,11 +628,11 @@ class Ftps extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEntit
// refs #293
if ($delete_userfiles == 1) {
\Froxlor\System\Cronjob::inserttask('8', $customer_data['loginname'], $result['homedir']);
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::DELETE_FTP_DATA, $customer_data['loginname'], $result['homedir']);
} else {
if (Settings::Get('system.nssextrausers') == 1) {
// this is used so that the libnss-extrausers cron is fired
\Froxlor\System\Cronjob::inserttask(5);
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::CREATE_FTP);
}
}

View File

@@ -298,9 +298,9 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
Database::pexecute($ins_stmt, $ins_data);
$ins_data['id'] = Database::lastInsertId();
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
// Using nameserver, insert a task which rebuilds the server config
\Froxlor\System\Cronjob::inserttask('4');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_DNS);
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$ip = '[' . $ip . ']';
@@ -511,9 +511,9 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
);
Database::pexecute($upd_stmt, $upd_data);
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
// Using nameserver, insert a task which rebuilds the server config
\Froxlor\System\Cronjob::inserttask('4');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_DNS);
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] changed IP/port from '" . $result['ip'] . ":" . $result['port'] . "' to '" . $ip . ":" . $port . "'");
@@ -584,9 +584,9 @@ class IpsAndPorts extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
'id' => $id
), true, true);
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
// Using nameserver, insert a task which rebuilds the server config
\Froxlor\System\Cronjob::inserttask('4');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_DNS);
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_WARNING, "[API] deleted IP/port '" . $result['ip'] . ":" . $result['port'] . "'");
return $this->response(200, "successful", $result);

View File

@@ -364,7 +364,7 @@ class PhpSettings extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
Database::pexecute($ins_stmt, $ins_data, true, true);
$ins_data['id'] = Database::lastInsertId();
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] php setting with description '" . $description . "' has been created by '" . $this->getUserDetail('loginname') . "'");
$result = $this->apiCall('PhpSettings.get', array(
@@ -565,7 +565,7 @@ class PhpSettings extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
);
Database::pexecute($upd_stmt, $upd_data, true, true);
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] php setting with description '" . $description . "' has been updated by '" . $this->getUserDetail('loginname') . "'");
$result = $this->apiCall('PhpSettings.get', array(
@@ -622,7 +622,7 @@ class PhpSettings extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
'id' => $id
), true, true);
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
$this->logger()->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_INFO, "[API] php setting '" . $result['description'] . "' has been deleted by '" . $this->getUserDetail('loginname') . "'");
return $this->response(200, "successful", $result);
}

View File

@@ -359,9 +359,9 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
\Froxlor\Domain\Domain::addRedirectToDomain($subdomain_id, $redirectcode);
}
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
// Using nameserver, insert a task which rebuilds the server config
\Froxlor\System\Cronjob::inserttask('4');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_DNS);
Customers::increaseUsage($customer['customerid'], 'subdomains_used');
@@ -733,11 +733,11 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
'id' => $id
), true, true);
// remove domain from acme.sh / lets encrypt if used
\Froxlor\System\Cronjob::inserttask('12', $result['domain']);
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::DELETE_DOMAIN_SSL, $result['domain']);
}
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask('4');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_DNS);
$idna_convert = new \Froxlor\Idna\IdnaWrapper();
$this->logger()->logAction($this->isAdmin() ? \Froxlor\FroxlorLogger::ADM_ACTION : \Froxlor\FroxlorLogger::USR_ACTION, LOG_INFO, "[API] edited domain '" . $idna_convert->decode($result['domain']) . "'");
}
@@ -1019,13 +1019,13 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
'domainid' => $id
), true, true);
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
// Using nameserver, insert a task which rebuilds the server config
\Froxlor\System\Cronjob::inserttask('4');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_DNS);
// remove domains DNS from powerDNS if used, #581
\Froxlor\System\Cronjob::inserttask('11', $result['domain']);
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::DELETE_DOMAIN_PDNS, $result['domain']);
// remove domain from acme.sh / lets encrypt if used
\Froxlor\System\Cronjob::inserttask('12', $result['domain']);
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::DELETE_DOMAIN_SSL, $result['domain']);
// reduce subdomain-usage-counter
Customers::decreaseUsage($customer['customerid'], 'subdomains_used');

View File

@@ -63,13 +63,13 @@ class MasterCron extends \Froxlor\Cron\FroxlorCron
if (strtolower($argv[$x]) == '--force') {
// really force re-generating of config-files by
// inserting task 1
\Froxlor\System\Cronjob::inserttask('1');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_VHOST);
// bind (if enabled, \Froxlor\System\Cronjob::inserttask() checks this)
\Froxlor\System\Cronjob::inserttask('4');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_DNS);
// set quotas (if enabled)
\Froxlor\System\Cronjob::inserttask('10');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::CREATE_QUOTA);
// also regenerate cron.d-file
\Froxlor\System\Cronjob::inserttask('99');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_CRON);
array_push($jobs_to_run, 'tasks');
define('CRON_IS_FORCED', 1);
} elseif (strtolower($argv[$x]) == '--debug') {

View File

@@ -4,6 +4,8 @@ namespace Froxlor\Cron\System;
use Froxlor\Database\Database;
use Froxlor\Settings;
use Froxlor\Cron\TaskId;
/**
* This file is part of the Froxlor project.
* Copyright (c) 2003-2009 the SysCP Team (see authors).
@@ -45,55 +47,55 @@ class TasksCron extends \Froxlor\Cron\FroxlorCron
$row['data'] = json_decode($row['data'], true);
}
if ($row['type'] == '1') {
if ($row['type'] == TaskId::REBUILD_VHOST) {
/**
* TYPE=1 MEANS TO REBUILD APACHE VHOSTS.CONF
*/
self::rebuildWebserverConfigs();
} elseif ($row['type'] == '2') {
} elseif ($row['type'] == TaskId::CREATE_HOME) {
/**
* TYPE=2 MEANS TO CREATE A NEW HOME AND CHOWN
*/
self::createNewHome($row);
} elseif ($row['type'] == '4' && (int) Settings::Get('system.bind_enable') != 0) {
} elseif ($row['type'] == TaskId::REBUILD_DNS && (int) Settings::Get('system.bind_enable') != 0) {
/**
* TYPE=4 MEANS THAT SOMETHING IN THE BIND CONFIG HAS CHANGED.
* REBUILD froxlor_bind.conf IF BIND IS ENABLED
*/
self::rebuildDnsConfigs();
} elseif ($row['type'] == '5') {
} elseif ($row['type'] == TaskId::CREATE_FTP) {
/**
* TYPE=5 MEANS THAT A NEW FTP-ACCOUNT HAS BEEN CREATED, CREATE THE DIRECTORY
*/
self::createNewFtpHome($row);
} elseif ($row['type'] == '6') {
} elseif ($row['type'] == TaskId::DELETE_CUSTOMER_FILES) {
/**
* TYPE=6 MEANS THAT A CUSTOMER HAS BEEN DELETED AND THAT WE HAVE TO REMOVE ITS FILES
*/
self::deleteCustomerData($row);
} elseif ($row['type'] == '7') {
} elseif ($row['type'] == TaskId::DELETE_EMAIL_DATA) {
/**
* TYPE=7 Customer deleted an email account and wants the data to be deleted on the filesystem
*/
self::deleteEmailData($row);
} elseif ($row['type'] == '8') {
} elseif ($row['type'] == TaskId::DELETE_FTP_DATA) {
/**
* TYPE=8 Customer deleted a ftp account and wants the homedir to be deleted on the filesystem
* refs #293
*/
self::deleteFtpData($row);
} elseif ($row['type'] == '10' && (int) Settings::Get('system.diskquota_enabled') != 0) {
} elseif ($row['type'] == TaskId::CREATE_QUOTA && (int) Settings::Get('system.diskquota_enabled') != 0) {
/**
* TYPE=10 Set the filesystem - quota
*/
self::setFilesystemQuota();
} elseif ($row['type'] == '11' && Settings::Get('system.dns_server') == 'PowerDNS') {
} elseif ($row['type'] == TaskId::DELETE_DOMAIN_PDNS && Settings::Get('system.dns_server') == 'PowerDNS') {
/**
* TYPE=11 domain has been deleted, remove from pdns database if used
*/
\Froxlor\FroxlorLogger::getInstanceOf()->logAction(\Froxlor\FroxlorLogger::CRON_ACTION, LOG_NOTICE, "Removing PowerDNS entries for domain " . $row['data']['domain']);
\Froxlor\Dns\PowerDNS::cleanDomainZone($row['data']['domain']);
} elseif ($row['type'] == '12') {
} elseif ($row['type'] == TaskId::DELETE_DOMAIN_SSL) {
/**
* TYPE=12 domain has been deleted, remove from acme.sh/let's encrypt directory if used
*/

105
lib/Froxlor/Cron/TaskId.php Normal file
View File

@@ -0,0 +1,105 @@
<?php
namespace Froxlor\Cron;
class TaskId {
/**
* TYPE=1 MEANS TO REBUILD APACHE VHOSTS.CONF
*/
const REBUILD_VHOST = 1;
/**
* TYPE=2 MEANS TO CREATE A NEW HOME AND CHOWN
*/
const CREATE_HOME = 2;
/**
* TYPE=4 MEANS THAT SOMETHING IN THE DNS CONFIG HAS CHANGED.
* REBUILD froxlor_bind.conf IF BIND IS ENABLED, UPDATE DKIM KEYS
*/
const REBUILD_DNS = 4;
/**
* TYPE=5 MEANS THAT A NEW FTP-ACCOUNT HAS BEEN CREATED, CREATE THE DIRECTORY
*/
const CREATE_FTP = 5;
/**
* TYPE=6 MEANS THAT A CUSTOMER HAS BEEN DELETED AND THAT WE HAVE TO REMOVE ITS FILES
*/
const DELETE_CUSTOMER_FILES = 6;
/**
* TYPE=7 Customer deleted an email account and wants the data to be deleted on the filesystem
*/
const DELETE_EMAIL_DATA = 7;
/**
* TYPE=8 Customer deleted a ftp account and wants the homedir to be deleted on the filesystem
* refs #293
*/
const DELETE_FTP_DATA = 8;
/**
* TYPE=10 Set the filesystem - quota
*/
const CREATE_QUOTA = 10;
/**
* TYPE=11 domain has been deleted, remove from pdns database if used
*/
const DELETE_DOMAIN_PDNS = 11;
/**
* TYPE=12 domain has been deleted, remove from acme.sh/let's encrypt directory if used
*/
const DELETE_DOMAIN_SSL = 12;
/**
* TYPE=20 COSTUMERBACKUP
*/
const CREATE_CUSTOMER_BACKUP = 20;
/**
* TYPE=99 REGENERATE CRON
*/
const REBUILD_CRON = 99;
/**
* Return if a cron task id is valid
* @param int|string $id cron task id (legacy string support)
* @return boolean
*/
public static function isValid($id) {
static $reflContants;
if (!is_numeric($id)) {
return false;
}
$numericid = (int)$id;
if (!is_array($reflContants)) {
$reflClass = new \ReflectionClass(get_called_class());
$reflContants = $reflClass->getConstants();
}
return in_array($numericid, $reflContants, true);
}
/**
* Get constant name by id
* @param int|string $id cron task id (legacy string support)
* @return string|false constant name or false if not found
*/
public static function convertToConstant($id) {
static $reflContants;
if (!is_numeric($id)) {
return false;
}
$numericid = (int)$id;
if (!is_array($reflContants)) {
$reflClass = new \ReflectionClass(get_called_class());
$reflContants = $reflClass->getConstants();
}
return array_search($numericid, $reflContants, true);
}
}

View File

@@ -174,7 +174,7 @@ class Store
$returnvalue = self::storeSettingField($fieldname, $fielddata, $newfieldvalue);
if ($returnvalue !== false) {
\Froxlor\System\Cronjob::inserttask('4');
\Froxlor\System\Cronjob::inserttask(\Froxlor\Cron\TaskId::REBUILD_DNS);
}
return $returnvalue;
}

View File

@@ -4,6 +4,8 @@ namespace Froxlor\System;
use Froxlor\Settings;
use Froxlor\Database\Database;
use Froxlor\Cron\TaskId;
class Cronjob
{
@@ -109,13 +111,13 @@ class Cronjob
INSERT INTO `" . TABLE_PANEL_TASKS . "` SET `type` = :type, `data` = :data
");
if ($type == '1' || $type == '3' || $type == '4' || $type == '5' || $type == '10' || $type == '99') {
if ($type == TaskId::REBUILD_VHOST || $type == TaskId::REBUILD_DNS || $type == TaskId::CREATE_FTP || $type == TaskId::CREATE_QUOTA || $type == TaskId::REBUILD_CRON) {
// 4 = bind -> if bind disabled -> no task
if ($type == '4' && Settings::Get('system.bind_enable') == '0') {
if ($type == TaskId::REBUILD_DNS && Settings::Get('system.bind_enable') == '0') {
return;
}
// 10 = quota -> if quota disabled -> no task
if ($type == '10' && Settings::Get('system.diskquota_enabled') == '0') {
if ($type == TaskId::CREATE_QUOTA && Settings::Get('system.diskquota_enabled') == '0') {
return;
}
@@ -132,7 +134,7 @@ class Cronjob
'type' => $type,
'data' => ''
));
} elseif ($type == '2' && $param1 != '' && $param2 != '' && $param3 != '' && ($param4 == 0 || $param4 == 1)) {
} elseif ($type == TaskId::CREATE_HOME && $param1 != '' && $param2 != '' && $param3 != '' && ($param4 == 0 || $param4 == 1)) {
$data = array();
$data['loginname'] = $param1;
$data['uid'] = $param2;
@@ -140,56 +142,56 @@ class Cronjob
$data['store_defaultindex'] = $param4;
$data = json_encode($data);
Database::pexecute($ins_stmt, array(
'type' => '2',
'type' => TaskId::CREATE_HOME,
'data' => $data
));
} elseif ($type == '6' && $param1 != '') {
} elseif ($type == TaskId::DELETE_CUSTOMER_FILES && $param1 != '') {
$data = array();
$data['loginname'] = $param1;
$data = json_encode($data);
Database::pexecute($ins_stmt, array(
'type' => '6',
'type' => TaskId::DELETE_CUSTOMER_FILES,
'data' => $data
));
} elseif ($type == '7' && $param1 != '' && $param2 != '') {
} elseif ($type == TaskId::DELETE_EMAIL_DATA && $param1 != '' && $param2 != '') {
$data = array();
$data['loginname'] = $param1;
$data['email'] = $param2;
$data = json_encode($data);
Database::pexecute($ins_stmt, array(
'type' => '7',
'type' => TaskId::DELETE_EMAIL_DATA,
'data' => $data
));
} elseif ($type == '8' && $param1 != '' && $param2 != '') {
} elseif ($type == TaskId::DELETE_FTP_DATA && $param1 != '' && $param2 != '') {
$data = array();
$data['loginname'] = $param1;
$data['homedir'] = $param2;
$data = json_encode($data);
Database::pexecute($ins_stmt, array(
'type' => '8',
'type' => TaskId::DELETE_FTP_DATA,
'data' => $data
));
} elseif ($type == '11' && $param1 != '' && Settings::Get('system.bind_enable') == '1' && Settings::Get('system.dns_server') == 'PowerDNS') {
} elseif ($type == TaskId::DELETE_DOMAIN_PDNS && $param1 != '' && Settings::Get('system.bind_enable') == '1' && Settings::Get('system.dns_server') == 'PowerDNS') {
// -> if bind disabled or dns-server not PowerDNS -> no task
$data = array();
$data['domain'] = $param1;
$data = json_encode($data);
Database::pexecute($ins_stmt, array(
'type' => '11',
'type' => TaskId::DELETE_DOMAIN_PDNS,
'data' => $data
));
} elseif ($type == '12' && $param1 != '') {
} elseif ($type == TaskId::DELETE_DOMAIN_SSL && $param1 != '') {
$data = array();
$data['domain'] = $param1;
$data = json_encode($data);
Database::pexecute($ins_stmt, array(
'type' => '12',
'type' => TaskId::DELETE_DOMAIN_SSL,
'data' => $data
));
} elseif ($type == '20' && is_array($param1)) {
} elseif ($type == TaskId::CREATE_CUSTOMER_BACKUP && is_array($param1)) {
$data = json_encode($param1);
Database::pexecute($ins_stmt, array(
'type' => '20',
'type' => TaskId::CREATE_CUSTOMER_BACKUP,
'data' => $data
));
}
@@ -248,57 +250,23 @@ class Cronjob
$row['data'] = json_decode($row['data'], true);
}
// rebuilding webserver-configuration
if ($row['type'] == '1') {
$task_desc = $lng['tasks']['rebuild_webserverconfig'];
} elseif ($row['type'] == '2') {
// adding new user/
$loginname = '';
$task_id = $row['type'];
if (\Froxlor\Cron\TaskId::isValid($task_id)) {
$task_constname = \Froxlor\Cron\TaskId::convertToConstant($task_id);
$task_desc = isset($lng['tasks'][$task_constname]) ? $lng['tasks'][$task_constname] : $task_constname;
if (is_array($row['data'])) {
$loginname = $row['data']['loginname'];
// task includes loginname
if (isset($row['data']['loginname'])) {
$loginname = $row['data']['loginname'];
$task_desc = str_replace('%loginname%', $loginname, $task_desc);
}
// task includes domain data
if (isset($row['data']['domain'])) {
$domain = $row['data']['domain'];
$task_desc = str_replace('%domain%', $domain, $task_desc);
}
}
$task_desc = $lng['tasks']['adding_customer'];
$task_desc = str_replace('%loginname%', $loginname, $task_desc);
} elseif ($row['type'] == '4') {
// rebuilding bind-configuration
$task_desc = $lng['tasks']['rebuild_bindconfig'];
} elseif ($row['type'] == '5') {
// creating ftp-user directory
$task_desc = $lng['tasks']['creating_ftpdir'];
} elseif ($row['type'] == '6') {
// deleting user-files
$loginname = '';
if (is_array($row['data'])) {
$loginname = $row['data']['loginname'];
}
$task_desc = $lng['tasks']['deleting_customerfiles'];
$task_desc = str_replace('%loginname%', $loginname, $task_desc);
} elseif ($row['type'] == '7') {
// deleting email-account
$task_desc = $lng['tasks']['remove_emailacc_files'];
} elseif ($row['type'] == '8') {
// deleting ftp-account
$task_desc = $lng['tasks']['remove_ftpacc_files'];
} elseif ($row['type'] == '10') {
// Set FS - quota
$task_desc = $lng['tasks']['diskspace_set_quota'];
} elseif ($row['type'] == '11') {
// remove domain from pdns database if used
$task_desc = sprintf($lng['tasks']['remove_pdns_domain'], $row['data']['domain']);
} elseif ($row['type'] == '12') {
// remove domains ssl files
$task_desc = sprintf($lng['tasks']['remove_ssl_domain'], $row['data']['domain']);
} elseif ($row['type'] == '20') {
// deleting user-files
$loginname = '';
if (is_array($row['data'])) {
$loginname = $row['data']['loginname'];
}
$task_desc = $lng['tasks']['backup_customerfiles'];
$task_desc = str_replace('%loginname%', $loginname, $task_desc);
} elseif ($row['type'] == '99') {
// re-generating of cron.d-file
$task_desc = $lng['tasks']['regenerating_crond'];
} else {
// unknown
$task_desc = "ERROR: Unknown task type '" . $row['type'] . "'";