Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
090cfc26f2 | ||
|
|
529890b5d2 | ||
|
|
d4a6ab146d | ||
|
|
e3f02879cf | ||
|
|
b52d6df777 | ||
|
|
9e671100ae | ||
|
|
7e801ea502 | ||
|
|
b68522f7d5 | ||
|
|
86852942e0 | ||
|
|
ec05c84f4d | ||
|
|
9e13c077e9 | ||
|
|
da8d315e77 | ||
|
|
cb67e3ae63 | ||
|
|
82d15c4dc2 | ||
|
|
6d048e2cee | ||
|
|
87bd80eea1 |
@@ -35,6 +35,7 @@ use Froxlor\Cli\UpdateCommand;
|
||||
use Froxlor\Cli\InstallCommand;
|
||||
use Froxlor\Cli\MasterCron;
|
||||
use Froxlor\Cli\UserCommand;
|
||||
use Froxlor\Cli\ValidateAcmeWebroot;
|
||||
use Froxlor\Froxlor;
|
||||
|
||||
// validate correct php version
|
||||
@@ -59,4 +60,5 @@ $application->add(new UpdateCommand());
|
||||
$application->add(new InstallCommand());
|
||||
$application->add(new MasterCron());
|
||||
$application->add(new UserCommand());
|
||||
$application->add(new ValidateAcmeWebroot());
|
||||
$application->run();
|
||||
|
||||
@@ -40,7 +40,7 @@ use Froxlor\UI\Response;
|
||||
use Froxlor\CurrentUser;
|
||||
|
||||
// redirect if this customer page is hidden via settings
|
||||
if (Settings::IsInList('panel.customer_hide_options', 'ftp') || $userinfo['ftps'] == 0) {
|
||||
if (Settings::IsInList('panel.customer_hide_options', 'ftp')) {
|
||||
Response::redirectTo('customer_index.php');
|
||||
}
|
||||
|
||||
|
||||
@@ -115,10 +115,14 @@ if ($page == 'overview') {
|
||||
|
||||
if ($usages) {
|
||||
$userinfo['diskspace_bytes_used'] = $usages['webspace'] * 1024;
|
||||
$userinfo['mailspace_used'] = $usages['mail'] * 1024;
|
||||
$userinfo['dbspace_used'] = $usages['mysql'] * 1024;
|
||||
$userinfo['total_bytes_used'] = ($usages['webspace'] + $usages['mail'] + $usages['mysql']) * 1024;
|
||||
} else {
|
||||
$userinfo['diskspace_bytes_used'] = 0;
|
||||
$userinfo['total_bytes_used'] = 0;
|
||||
$userinfo['mailspace_used'] = 0;
|
||||
$userinfo['dbspace_used'] = 0;
|
||||
}
|
||||
|
||||
UI::twig()->addGlobal('userinfo', $userinfo);
|
||||
|
||||
@@ -642,7 +642,7 @@ opcache.validate_timestamps'),
|
||||
('system', 'leprivatekey', 'unset'),
|
||||
('system', 'lepublickey', 'unset'),
|
||||
('system', 'letsencryptca', 'letsencrypt'),
|
||||
('system', 'letsencryptchallengepath', '/var/www/froxlor'),
|
||||
('system', 'letsencryptchallengepath', '/var/www/html/froxlor'),
|
||||
('system', 'letsencryptkeysize', '4096'),
|
||||
('system', 'letsencryptreuseold', 0),
|
||||
('system', 'leenabled', '0'),
|
||||
@@ -696,7 +696,7 @@ opcache.validate_timestamps'),
|
||||
('system', 'distribution', ''),
|
||||
('system', 'update_channel', 'stable'),
|
||||
('system', 'updatecheck_data', ''),
|
||||
('system', 'update_notify_last', '2.0.7'),
|
||||
('system', 'update_notify_last', '2.0.8'),
|
||||
('system', 'traffictool', 'goaccess'),
|
||||
('api', 'enabled', '0'),
|
||||
('2fa', 'enabled', '1'),
|
||||
@@ -740,8 +740,8 @@ opcache.validate_timestamps'),
|
||||
('panel', 'logo_overridetheme', '0'),
|
||||
('panel', 'logo_overridecustom', '0'),
|
||||
('panel', 'settings_mode', '0'),
|
||||
('panel', 'version', '2.0.7'),
|
||||
('panel', 'db_version', '202212060');
|
||||
('panel', 'version', '2.0.8'),
|
||||
('panel', 'db_version', '202301120');
|
||||
|
||||
|
||||
DROP TABLE IF EXISTS `panel_tasks`;
|
||||
|
||||
@@ -38,10 +38,9 @@ if (!defined('_CRON_UPDATE')) {
|
||||
|
||||
// last 0.10.x release
|
||||
if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
||||
|
||||
$update_to = '2.0.0-beta1';
|
||||
|
||||
Update::showUpdateStep("Updating from 0.10.38.3 to ".$update_to, false);
|
||||
Update::showUpdateStep("Updating from 0.10.38.3 to " . $update_to, false);
|
||||
|
||||
Update::showUpdateStep("Removing unused table");
|
||||
Database::query("DROP TABLE IF EXISTS `panel_sessions`;");
|
||||
@@ -146,7 +145,7 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
||||
}
|
||||
|
||||
Update::showUpdateStep("Adding new settings");
|
||||
$panel_settings_mode = isset($_POST['panel_settings_mode']) ? (int) $_POST['panel_settings_mode'] : 0;
|
||||
$panel_settings_mode = isset($_POST['panel_settings_mode']) ? (int)$_POST['panel_settings_mode'] : 0;
|
||||
Settings::AddNew("panel.settings_mode", $panel_settings_mode);
|
||||
$system_distribution = isset($_POST['system_distribution']) ? $_POST['system_distribution'] : '';
|
||||
Settings::AddNew("system.distribution", $system_distribution);
|
||||
@@ -193,7 +192,6 @@ if (Froxlor::isFroxlorVersion('0.10.38.3')) {
|
||||
}
|
||||
|
||||
if (Froxlor::isDatabaseVersion('202112310')) {
|
||||
|
||||
Update::showUpdateStep("Adjusting traffic tool settings");
|
||||
$traffic_tool = Settings::Get('system.awstats_enabled') == 1 ? 'awstats' : 'webalizer';
|
||||
Settings::AddNew("system.traffictool", $traffic_tool);
|
||||
@@ -204,20 +202,30 @@ if (Froxlor::isDatabaseVersion('202112310')) {
|
||||
}
|
||||
|
||||
if (Froxlor::isDatabaseVersion('202211030')) {
|
||||
|
||||
Update::showUpdateStep("Creating backward compatibility for cronjob");
|
||||
$complete_filedir = Froxlor::getInstallDir() . '/scripts';
|
||||
mkdir($complete_filedir, 0750, true);
|
||||
$newCronBin = Froxlor::getInstallDir().'/bin/froxlor-cli';
|
||||
$compCron = <<<EOF
|
||||
$disabled = explode(',', ini_get('disable_functions'));
|
||||
$exec_allowed = !in_array('exec', $disabled);
|
||||
// check whether old files could be deleted in previous updates and if not,
|
||||
// user should run cron to regenerate cron.d-file manually as he will run
|
||||
// the other commands manually only after the update so this file would be deleted too
|
||||
if ($exec_allowed) {
|
||||
$complete_filedir = Froxlor::getInstallDir() . '/scripts';
|
||||
mkdir($complete_filedir, 0750, true);
|
||||
$newCronBin = Froxlor::getInstallDir() . '/bin/froxlor-cli';
|
||||
$compCron = <<<EOF
|
||||
<?php
|
||||
chmod('$newCronBin', 0755);
|
||||
// re-create cron.d configuration file
|
||||
exec('$newCronBin froxlor:cron -r 99');
|
||||
exit;
|
||||
EOF;
|
||||
file_put_contents($complete_filedir.'/froxlor_master_cronjob.php', $compCron);
|
||||
Update::lastStepStatus(0);
|
||||
file_put_contents($complete_filedir . '/froxlor_master_cronjob.php', $compCron);
|
||||
Update::lastStepStatus(0);
|
||||
} else {
|
||||
$cron_run_cmd = 'chmod +x ' . FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . PHO_EOL;
|
||||
$cron_run_cmd .= FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . ' froxlor:cron -r 99';
|
||||
Update::lastStepStatus(1, 'manual commands needed', 'Please run the following commands manually:<br><pre>' . $cron_run_cmd . '</pre>');
|
||||
}
|
||||
|
||||
Froxlor::updateToDbVersion('202212060');
|
||||
}
|
||||
@@ -257,20 +265,27 @@ if (Froxlor::isFroxlorVersion('2.0.3')) {
|
||||
|
||||
$complete_filedir = Froxlor::getInstallDir() . '/scripts';
|
||||
// check if compat. cronjob still exists (most likely didn't run successfully b/c of error from former 2.0 release)
|
||||
if (@file_exists($complete_filedir.'/froxlor_master_cronjob.php')) {
|
||||
if (@file_exists($complete_filedir . '/froxlor_master_cronjob.php')) {
|
||||
Update::showUpdateStep("Adjusting backward compatibility for cronjob");
|
||||
$newCronBin = Froxlor::getInstallDir() . '/bin/froxlor-cli';
|
||||
$compCron = <<<EOF
|
||||
$disabled = explode(',', ini_get('disable_functions'));
|
||||
$exec_allowed = !in_array('exec', $disabled);
|
||||
if ($exec_allowed) {
|
||||
$newCronBin = Froxlor::getInstallDir() . '/bin/froxlor-cli';
|
||||
$compCron = <<<EOF
|
||||
<?php
|
||||
chmod('$newCronBin', 0755);
|
||||
// re-create cron.d configuration file
|
||||
exec('$newCronBin froxlor:cron -r 99');
|
||||
exit;
|
||||
EOF;
|
||||
file_put_contents($complete_filedir . '/froxlor_master_cronjob.php', $compCron);
|
||||
Update::lastStepStatus(0);
|
||||
file_put_contents($complete_filedir . '/froxlor_master_cronjob.php', $compCron);
|
||||
Update::lastStepStatus(0);
|
||||
} else {
|
||||
$cron_run_cmd = 'chmod +x ' . FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . PHO_EOL;
|
||||
$cron_run_cmd .= FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . ' froxlor:cron -r 99';
|
||||
Update::lastStepStatus(1, 'manual commands needed', 'Please run the following commands manually:<br><pre>' . $cron_run_cmd . '</pre>');
|
||||
}
|
||||
}
|
||||
|
||||
Froxlor::updateToVersion('2.0.4');
|
||||
}
|
||||
|
||||
@@ -301,3 +316,31 @@ if (Froxlor::isFroxlorVersion('2.0.6')) {
|
||||
|
||||
Froxlor::updateToVersion('2.0.7');
|
||||
}
|
||||
|
||||
if (Froxlor::isDatabaseVersion('202212060')) {
|
||||
Update::showUpdateStep("Validating acme.sh challenge path");
|
||||
$acmesh_challenge_dir = Settings::Get('system.letsencryptchallengepath');
|
||||
$system_letsencryptchallengepath_upd = isset($_POST['system_letsencryptchallengepath_upd']) ? $_POST['system_letsencryptchallengepath_upd'] : $acmesh_challenge_dir;
|
||||
if ($acmesh_challenge_dir != $system_letsencryptchallengepath_upd) {
|
||||
Settings::Set('system.letsencryptchallengepath', $system_letsencryptchallengepath_upd);
|
||||
Update::lastStepStatus(1, 'manual commands needed', 'Please reconfigure webserver service using <pre>bin/froxlor-cli froxlor:config-services</pre> or adjust the path manually in <pre>' . Settings::Get('system.letsencryptacmeconf') . '</pre>');
|
||||
} else {
|
||||
Update::lastStepStatus(0);
|
||||
}
|
||||
|
||||
Froxlor::updateToDbVersion('202301120');
|
||||
}
|
||||
|
||||
if (Froxlor::isFroxlorVersion('2.0.7')) {
|
||||
Update::showUpdateStep("Updating from 2.0.7 to 2.0.8", false);
|
||||
|
||||
// adjust file-logging to be set to froxlor/logs/
|
||||
$logtypes = explode(',', Settings::Get('logger.logtypes'));
|
||||
if (in_array('file', $logtypes)) {
|
||||
Update::showUpdateStep("Adjusting froxlor logfile for system-logging to be stored in logs/froxlor.log");
|
||||
Settings::Set('logger.logfile', 'froxlor.log');
|
||||
Update::lastStepStatus(0);
|
||||
}
|
||||
|
||||
Froxlor::updateToVersion('2.0.8');
|
||||
}
|
||||
|
||||
@@ -34,9 +34,14 @@ $return = [];
|
||||
if (Update::versionInUpdate($current_db_version, '202004140')) {
|
||||
$has_preconfig = true;
|
||||
$description = 'Froxlor can now optionally validate the dns entries of domains that request Lets Encrypt certificates to reduce dns-related problems (e.g. freshly registered domain or updated a-record).';
|
||||
$return['system_le_domain_dnscheck_note'] = ['type' => 'infotext', 'value' => $description];
|
||||
$question = '<strong>Validate DNS of domains when using Lets Encrypt ';
|
||||
$return['system_le_domain_dnscheck'] = ['type' => 'checkbox', 'value' => 1, 'checked' => 1, 'label' => $question];
|
||||
$return['system_le_domain_dnscheck'] = [
|
||||
'type' => 'checkbox',
|
||||
'value' => 1,
|
||||
'checked' => 1,
|
||||
'label' => $question,
|
||||
'prior_infotext' => $description
|
||||
];
|
||||
}
|
||||
|
||||
$preconfig['fields'] = $return;
|
||||
|
||||
@@ -27,6 +27,7 @@ use Froxlor\Froxlor;
|
||||
use Froxlor\FileDir;
|
||||
use Froxlor\Config\ConfigParser;
|
||||
use Froxlor\Install\Update;
|
||||
use Froxlor\Settings;
|
||||
|
||||
$preconfig = [
|
||||
'title' => '2.x updates',
|
||||
@@ -36,7 +37,6 @@ $return = [];
|
||||
|
||||
if (Update::versionInUpdate($current_version, '2.0.0-beta1')) {
|
||||
$description = 'We have rearranged the settings and split them into basic and advanced categories. This makes it easier for users who do not need all the detailed or very specific settings and options and gives a better overview of the basic/mostly used settings.';
|
||||
$return['panel_settings_mode_note'] = ['type' => 'infotext', 'value' => $description];
|
||||
$question = '<strong>Chose settings mode (you can change that at any time)</strong>';
|
||||
$return['panel_settings_mode'] = [
|
||||
'type' => 'select',
|
||||
@@ -45,11 +45,11 @@ if (Update::versionInUpdate($current_version, '2.0.0-beta1')) {
|
||||
1 => 'Advanced'
|
||||
],
|
||||
'selected' => 1,
|
||||
'label' => $question
|
||||
'label' => $question,
|
||||
'prior_infotext' => $description
|
||||
];
|
||||
|
||||
$description = 'The configuration page now can preselect a distribution, please select your current distribution';
|
||||
$return['system_distribution_note'] = ['type' => 'infotext', 'value' => $description];
|
||||
$question = '<strong>Select distribution</strong>';
|
||||
$config_dir = FileDir::makeCorrectDir(Froxlor::getInstallDir() . '/lib/configfiles/');
|
||||
// show list of available distro's
|
||||
@@ -68,9 +68,26 @@ if (Update::versionInUpdate($current_version, '2.0.0-beta1')) {
|
||||
'type' => 'select',
|
||||
'select_var' => $distributions_select,
|
||||
'selected' => '',
|
||||
'label' => $question
|
||||
'label' => $question,
|
||||
'prior_infotext' => $description
|
||||
];
|
||||
}
|
||||
|
||||
if (Update::versionInUpdate($current_db_version, '202301120')) {
|
||||
$acmesh_challenge_dir = Settings::Get('system.letsencryptchallengepath');
|
||||
if ($acmesh_challenge_dir != Froxlor::getInstallDir()) {
|
||||
$has_preconfig = true;
|
||||
$description = 'ACME challenge docroot from settings differs from the current installation directory.';
|
||||
$question = '<strong>Validate Let\'s Encrypt challenge path ';
|
||||
$return['system_letsencryptchallengepath_upd'] = [
|
||||
'type' => 'text',
|
||||
'value' => $acmesh_challenge_dir,
|
||||
'placeholder' => Froxlor::getInstallDir(),
|
||||
'label' => $question,
|
||||
'prior_infotext' => $description
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$preconfig['fields'] = $return;
|
||||
return $preconfig;
|
||||
|
||||
@@ -73,12 +73,12 @@ class Mysqls extends ApiCommand implements ResourceEntity
|
||||
$password = $this->getParam('mysql_password');
|
||||
|
||||
// parameters
|
||||
$dbserver = $this->getParam('mysql_server', true, 0);
|
||||
$databasedescription = $this->getParam('description', true, '');
|
||||
$databasename = $this->getParam('custom_suffix', true, '');
|
||||
$sendinfomail = $this->getBoolParam('sendinfomail', true, 0);
|
||||
// get needed customer info to reduce the mysql-usage-counter by one
|
||||
$customer = $this->getCustomerData('mysqls');
|
||||
$dbserver = $this->getParam('mysql_server', true, $this->getDefaultMySqlServer($customer));
|
||||
|
||||
// validation
|
||||
$password = Validate::validate($password, 'password', '', '', [], true);
|
||||
@@ -558,4 +558,13 @@ class Mysqls extends ApiCommand implements ResourceEntity
|
||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_WARNING, "[API] deleted database '" . $result['databasename'] . "'");
|
||||
return $this->response($result);
|
||||
}
|
||||
|
||||
private function getDefaultMySqlServer(array $customer) {
|
||||
$allowed_mysqlservers = json_decode($customer['allowed_mysqlserver'] ?? '[]', true);
|
||||
asort($allowed_mysqlservers, SORT_NUMERIC);
|
||||
if (count($allowed_mysqlservers) == 1 && $allowed_mysqlservers[0] != 0) {
|
||||
return (int) $allowed_mysqlservers[0];
|
||||
}
|
||||
return (int) array_shift($allowed_mysqlservers);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||
class CliCommand extends Command
|
||||
{
|
||||
|
||||
protected function validateRequirements(InputInterface $input, OutputInterface $output): int
|
||||
protected function validateRequirements(InputInterface $input, OutputInterface $output, bool $ignore_has_updates = false): int
|
||||
{
|
||||
if (!file_exists(Froxlor::getInstallDir() . '/lib/userdata.inc.php')) {
|
||||
$output->writeln("<error>Could not find froxlor's userdata.inc.php file. You should use this script only with an installed froxlor system.</>");
|
||||
@@ -51,7 +51,7 @@ class CliCommand extends Command
|
||||
$output->writeln("<error>" . $e->getMessage() . "</>");
|
||||
return self::INVALID;
|
||||
}
|
||||
if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) {
|
||||
if (!$ignore_has_updates && (Froxlor::hasUpdates() || Froxlor::hasDbUpdates())) {
|
||||
if ((int)Settings::Get('system.cron_allowautoupdate') == 1) {
|
||||
return $this->runUpdate($output);
|
||||
} else {
|
||||
|
||||
154
lib/Froxlor/Cli/ValidateAcmeWebroot.php
Normal file
154
lib/Froxlor/Cli/ValidateAcmeWebroot.php
Normal file
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Froxlor project.
|
||||
* Copyright (c) 2010 the Froxlor Team (see authors).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you can also view it online at
|
||||
* https://files.froxlor.org/misc/COPYING.txt
|
||||
*
|
||||
* @copyright the authors
|
||||
* @author Froxlor team <team@froxlor.org>
|
||||
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||
*/
|
||||
|
||||
namespace Froxlor\Cli;
|
||||
|
||||
use Froxlor\Cron\TaskId;
|
||||
use Froxlor\Database\Database;
|
||||
use Froxlor\FileDir;
|
||||
use Froxlor\Froxlor;
|
||||
use Froxlor\Settings;
|
||||
use Froxlor\System\Cronjob;
|
||||
use PDO;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
final class ValidateAcmeWebroot extends CliCommand
|
||||
{
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('froxlor:validate-acme-webroot');
|
||||
$this->setDescription('Validates the Le_Webroot value is correct for froxlor managed domains with Let\s Encrypt certificate.');
|
||||
$this->addOption('yes-to-all', 'A', InputOption::VALUE_NONE, 'Do not ask for confirmation, update files if necessary');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$result = self::SUCCESS;
|
||||
|
||||
$result = $this->validateRequirements($input, $output, true);
|
||||
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
if ((int) Settings::Get('system.leenabled') == 0) {
|
||||
$io->info("Let's Encrypt not activated in froxlor settings.");
|
||||
$result = self::INVALID;
|
||||
}
|
||||
|
||||
if ($result == self::SUCCESS) {
|
||||
$yestoall = $input->getOption('yes-to-all') !== false;
|
||||
$helper = $this->getHelper('question');
|
||||
$count_changes = 0;
|
||||
// get all Let's Encrypt enabled domains
|
||||
$sel_stmt = Database::prepare("SELECT id, domain FROM panel_domains WHERE `letsencrypt` = '1' AND aliasdomain IS NULL ORDER BY id ASC");
|
||||
Database::pexecute($sel_stmt);
|
||||
$domains = $sel_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$upd_stmt = Database::prepare("UPDATE domain_ssl_settings SET expirationdate=NULL WHERE `domainid` = :did");
|
||||
$acmesh_dir = dirname(Settings::Get('system.acmeshpath'));
|
||||
$acmesh_challenge_dir = Settings::Get('system.letsencryptchallengepath');
|
||||
|
||||
if ($acmesh_challenge_dir != Froxlor::getInstallDir()) {
|
||||
$io->warning([
|
||||
"ACME challenge docroot from settings differs from the current installation directory.",
|
||||
"Settings: '" . $acmesh_challenge_dir . "'",
|
||||
"Default/recommended value: '" . Froxlor::getInstallDir() . "'",
|
||||
]);
|
||||
$question = new ConfirmationQuestion('Fix ACME challenge docroot setting? [yes] ', true, '/^(y|j)/i');
|
||||
if ($yestoall || $helper->ask($input, $output, $question)) {
|
||||
Settings::Set('system.letsencryptchallengepath', Froxlor::getInstallDir());
|
||||
$former_value = $acmesh_challenge_dir;
|
||||
$acmesh_challenge_dir = Froxlor::getInstallDir();
|
||||
// need to update the corresponding acme-alias config-file
|
||||
$acme_alias_file = Settings::Get('system.letsencryptacmeconf');
|
||||
$sed_params = "s@".$former_value."@" . $acmesh_challenge_dir . "@";
|
||||
FileDir::safe_exec('sed -i -e "' . $sed_params . '" ' . escapeshellarg($acme_alias_file));
|
||||
$count_changes++;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($domains as $domain_arr) {
|
||||
$domain = $domain_arr['domain'];
|
||||
$acme_domain_conf = FileDir::makeCorrectFile($acmesh_dir . '/' . $domain . '/' . $domain . '.conf');
|
||||
if (file_exists($acme_domain_conf)) {
|
||||
$io->text("Getting info from " . $acme_domain_conf);
|
||||
$conf_content = file_get_contents($acme_domain_conf);
|
||||
} else {
|
||||
$acme_domain_conf = FileDir::makeCorrectFile($acmesh_dir . '/' . $domain . '_ecc/' . $domain . '.conf');
|
||||
if (file_exists($acme_domain_conf)) {
|
||||
$io->text("Getting info from " . $acme_domain_conf);
|
||||
$conf_content = file_get_contents($acme_domain_conf);
|
||||
} else {
|
||||
$io->info("No domain configuration file found in '" . $acmesh_dir . "'");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!empty($conf_content)) {
|
||||
$lines = explode("\n", $conf_content);
|
||||
foreach ($lines as $line) {
|
||||
$val_key = explode("=", $line);
|
||||
if ($val_key[0] == 'Le_Webroot') {
|
||||
$domain_webroot = trim(trim($val_key[1], "'"), '"');
|
||||
if ($domain_webroot != $acmesh_challenge_dir) {
|
||||
$io->warning("Domain '" . $domain . "' has old/wrong Le_Webroot setting: '" . $domain_webroot . ' <> ' . $acmesh_challenge_dir . "'");
|
||||
$question = new ConfirmationQuestion('Fix Le_Webroot? [yes] ', true, '/^(y|j)/i');
|
||||
if ($yestoall || $helper->ask($input, $output, $question)) {
|
||||
$sed_params = "s@Le_Webroot=.*@Le_Webroot='" . $acmesh_challenge_dir . "'@";
|
||||
FileDir::safe_exec('sed -i -e "' . $sed_params . '" ' . escapeshellarg($acme_domain_conf));
|
||||
Database::pexecute($upd_stmt, ['did' => $domain_arr['id']]);
|
||||
$io->success("Correction of Le_Webroot successful");
|
||||
$count_changes++;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
$io->info("Domain '" . $domain . "' Le_Webroot value is correct");
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($count_changes > 0) {
|
||||
if (Froxlor::hasUpdates() || Froxlor::hasDbUpdates()) {
|
||||
Cronjob::inserttask(TaskId::REBUILD_VHOST);
|
||||
} else {
|
||||
$question = new ConfirmationQuestion('Changes detected. Force cronjob to refresh certificates? [yes] ', true, '/^(y|j)/i');
|
||||
if ($yestoall || $helper->ask($input, $output, $question)) {
|
||||
passthru(FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/bin/froxlor-cli') . ' froxlor:cron -f -d');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,10 +31,10 @@ final class Froxlor
|
||||
{
|
||||
|
||||
// Main version variable
|
||||
const VERSION = '2.0.7';
|
||||
const VERSION = '2.0.8';
|
||||
|
||||
// Database version (YYYYMMDDC where C is a daily counter)
|
||||
const DBVERSION = '202212060';
|
||||
const DBVERSION = '202301120';
|
||||
|
||||
// Distribution branding-tag (used for Debian etc.)
|
||||
const BRANDING = '';
|
||||
|
||||
@@ -100,11 +100,17 @@ class FroxlorLogger
|
||||
self::$ml->pushHandler(new SyslogHandler('froxlor', LOG_USER, Logger::DEBUG));
|
||||
break;
|
||||
case 'file':
|
||||
$logger_logfile = Settings::Get('logger.logfile');
|
||||
$logger_logfile = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/logs/' . Settings::Get('logger.logfile'));
|
||||
// is_writable needs an existing file to check if it's actually writable
|
||||
@touch($logger_logfile);
|
||||
if (empty($logger_logfile) || !is_writable($logger_logfile)) {
|
||||
Settings::Set('logger.logfile', '/tmp/froxlor.log');
|
||||
Settings::Set('logger.logfile', 'froxlor.log');
|
||||
$logger_logfile = FileDir::makeCorrectFile(Froxlor::getInstallDir() . '/logs/froxlor.log');
|
||||
@touch($logger_logfile);
|
||||
if (empty($logger_logfile) || !is_writable($logger_logfile)) {
|
||||
// not writable in our own directory? Skip
|
||||
break;
|
||||
}
|
||||
}
|
||||
self::$ml->pushHandler(new StreamHandler($logger_logfile, Logger::DEBUG));
|
||||
break;
|
||||
|
||||
@@ -3458,11 +3458,7 @@ ssl_key = <<SSL_KEY_FILE>
|
||||
# auth_ssl_username_from_cert=yes.
|
||||
#ssl_cert_username_field = commonName
|
||||
|
||||
# SSL DH parameters
|
||||
# Generate new params with `openssl dhparam -out /etc/dovecot/dh.pem 4096`
|
||||
# Or migrate from old ssl-parameters.dat file with the command dovecot
|
||||
# gives on startup when ssl_dh is unset.
|
||||
ssl_dh = </usr/share/dovecot/dh.pem
|
||||
ssl_dh_parameters_length = 2048
|
||||
|
||||
# SSL protocols to use
|
||||
#ssl_protocols = !SSLv3
|
||||
|
||||
@@ -30,6 +30,7 @@ return [
|
||||
'title' => lng('admin.domain_add'),
|
||||
'image' => 'fa-solid fa-globe',
|
||||
'self_overview' => ['section' => 'domains', 'page' => 'domains'],
|
||||
'id' => 'domain_add',
|
||||
'sections' => [
|
||||
'section_a' => [
|
||||
'title' => lng('domains.domainsettings'),
|
||||
|
||||
@@ -30,6 +30,7 @@ return [
|
||||
'title' => lng('admin.domain_edit'),
|
||||
'image' => 'fa-solid fa-globe',
|
||||
'self_overview' => ['section' => 'domains', 'page' => 'domains'],
|
||||
'id' => 'domain_edit',
|
||||
'sections' => [
|
||||
'section_a' => [
|
||||
'title' => lng('domains.domainsettings'),
|
||||
|
||||
@@ -1494,7 +1494,10 @@ Vielen Dank, Ihr Administrator',
|
||||
'title' => 'Log-Art(en)',
|
||||
'description' => 'Wählen Sie hier die gewünschten Logtypen. Für Mehrfachauswahl, halten Sie während der Auswahl STRG gedrückt<br />Mögliche Logtypen sind: syslog, file, mysql',
|
||||
],
|
||||
'logfile' => 'Log-Datei Pfad inklusive Dateinamen',
|
||||
'logfile' => [
|
||||
'title' => 'Dateiname der Logdatei',
|
||||
'description' => 'Wird nur verwendet, wenn die Log-Art "file" ausgewählt ist. Diese Datei wird unter froxlor/logs/ geschrieben. Dieser Ordner ist vor Webzugriff geschützt.',
|
||||
],
|
||||
'logcron' => 'Logge Cronjobs',
|
||||
'logcronoption' => [
|
||||
'never' => 'Nie',
|
||||
@@ -2124,17 +2127,31 @@ Vielen Dank, Ihr Administrator',
|
||||
],
|
||||
'mb' => 'Traffic',
|
||||
'day' => 'Tag',
|
||||
'distribution' => '<span color="#019522">FTP</span> | <span color="#0000FF">HTTP</span> | <span color="#800000">Mail</span>',
|
||||
'sumhttp' => 'Gesamt HTTP-Traffic',
|
||||
'sumftp' => 'Gesamt FTP-Traffic',
|
||||
'summail' => 'Gesamt Mail-Traffic',
|
||||
'sumtotal' => 'Gesamt Traffic',
|
||||
'sumhttp' => 'HTTP-Traffic',
|
||||
'sumftp' => 'FTP-Traffic',
|
||||
'summail' => 'Mail-Traffic',
|
||||
'customer' => 'Kunde',
|
||||
'trafficoverview' => 'Übersicht Traffic je',
|
||||
'trafficoverview' => 'Übersicht Traffic',
|
||||
'bycustomers' => 'Traffic nach Kunden',
|
||||
'details' => 'Details',
|
||||
'http' => 'HTTP',
|
||||
'ftp' => 'FTP',
|
||||
'mail' => 'Mail',
|
||||
'nocustomers' => 'Es wird mindestens ein Kunde benötigt um die Traffic Statistiken anzuzeigen.',
|
||||
'top5customers' => 'Top 5 Kunden',
|
||||
'nodata' => 'Keine Daten im angegebenen Zeitraum.',
|
||||
'ranges' => [
|
||||
'last24h' => 'die letzten 24 Std',
|
||||
'last7d' => 'die letzten 7 Tage',
|
||||
'last30d' => 'die letzten 30 Tage',
|
||||
'cm' => 'Aktueller Monat',
|
||||
'last3m' => 'die letzten 3 Monate',
|
||||
'last6m' => 'die letzten 6 Monate',
|
||||
'last12m' => 'die letzten 12 Monate',
|
||||
'cy' => 'Aktuelles Jahr',
|
||||
],
|
||||
'byrange' => 'Nach angegebenem Zeitraum',
|
||||
],
|
||||
'translator' => '',
|
||||
'update' => [
|
||||
|
||||
@@ -1613,7 +1613,10 @@ Yours sincerely, your administrator',
|
||||
'title' => 'Log-type(s)',
|
||||
'description' => 'Specify logtypes. To select multiple types, hold down CTRL while selecting.<br />Available logtypes are: syslog, file, mysql',
|
||||
],
|
||||
'logfile' => 'Logfile path including filename',
|
||||
'logfile' => [
|
||||
'title' => 'Filename for log',
|
||||
'description' => 'Only used if log-type includes "file". This file will be created in froxlor/logs/. This folder is protected against public access.',
|
||||
],
|
||||
'logcron' => 'Log cronjobs',
|
||||
'logcronoption' => [
|
||||
'never' => 'Never',
|
||||
@@ -2254,18 +2257,32 @@ Yours sincerely, your administrator',
|
||||
'total' => 'Total',
|
||||
],
|
||||
'mb' => 'Traffic',
|
||||
'distribution' => '<font color="#019522">FTP</font> | <font color="#0000FF">HTTP</font> | <font color="#800000">Mail</font>',
|
||||
'sumhttp' => 'Total HTTP-Traffic',
|
||||
'sumftp' => 'Total FTP-Traffic',
|
||||
'summail' => 'Total Mail-Traffic',
|
||||
'sumtotal' => 'Total traffic',
|
||||
'sumhttp' => 'HTTP traffic',
|
||||
'sumftp' => 'FTP traffic',
|
||||
'summail' => 'Mail traffic',
|
||||
'customer' => 'Customer',
|
||||
'domain' => 'Domain',
|
||||
'trafficoverview' => 'Traffic summary by',
|
||||
'trafficoverview' => 'Traffic summary',
|
||||
'bycustomers' => 'Traffic by customers',
|
||||
'details' => 'Details',
|
||||
'http' => 'HTTP',
|
||||
'ftp' => 'FTP',
|
||||
'mail' => 'Mail',
|
||||
'nocustomers' => 'You need at least one customer to view the traffic reports.',
|
||||
'top5customers' => 'Top 5 customers',
|
||||
'nodata' => 'No data for given range found.',
|
||||
'ranges' => [
|
||||
'last24h' => 'last 24 hours',
|
||||
'last7d' => 'last 7 days',
|
||||
'last30d' => 'last 30 days',
|
||||
'cm' => 'Current month',
|
||||
'last3m' => 'last 3 months',
|
||||
'last6m' => 'last 6 months',
|
||||
'last12m' => 'last 12 months',
|
||||
'cy' => 'Current year',
|
||||
],
|
||||
'byrange' => 'Specified by range',
|
||||
],
|
||||
'translator' => '',
|
||||
'update' => [
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
</form>
|
||||
|
||||
{# add translation for custom validations #}
|
||||
{% if form_data.id is defined and form_data.id in ['customer_add', 'customer_edit'] %}
|
||||
{% if form_data.id is defined and form_data.id in ['customer_add', 'customer_edit', 'domain_add', 'domain_edit'] %}
|
||||
<script>$(function() { $.extend($.validator.messages, {required: "{{ lng('error.requiredfield') }}"}) });</script>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
{% if field.visible is not defined or (field.visible is defined and field.visible) or nohide == true %}
|
||||
{% if norow == false and (field.type != 'hidden' or (field.type == 'hidden' and field.display is defined and field.display is not empty)) %}
|
||||
<div class="row g-0 formfield d-flex align-items-center">
|
||||
{% if field.prior_infotext is defined and field.prior_infotext|length > 0 %}
|
||||
<h5>{{ field.prior_infotext }}</h5>
|
||||
{% endif %}
|
||||
{% if field.label is iterable %}
|
||||
<label for="{{ id }}" class="col-sm-6 col-form-label pe-3">
|
||||
{% if em %}
|
||||
@@ -165,7 +168,7 @@
|
||||
|
||||
{% macro image(id, field) %}
|
||||
{% if field.value is not empty %}
|
||||
<img src="/{{ field.value }}" alt="Current Image" class="field-image-preview"><br>
|
||||
<img src="{{ field.value }}" alt="Current Image" class="field-image-preview"><br>
|
||||
<div class="form-check form-switch mb-2">
|
||||
<input type="checkbox" value="1" name="{{ id }}_delete" class="form-check-input">
|
||||
<label class="form-check-label">
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
$(document).ready(function() {
|
||||
$('#customer_add,#customer_edit').each(function(){
|
||||
$(document).ready(function () {
|
||||
$('#customer_add,#customer_edit').each(function () {
|
||||
$(this).validate({
|
||||
rules:{
|
||||
'name':{
|
||||
required:function(){
|
||||
rules: {
|
||||
'name': {
|
||||
required: function () {
|
||||
return $('#company').val().length === 0 || $('#firstname').val().length > 0;
|
||||
}
|
||||
},
|
||||
'firstname':{
|
||||
required:function(){
|
||||
'firstname': {
|
||||
required: function () {
|
||||
return $('#company').val().length === 0 || $('#name').val().length > 0;
|
||||
}
|
||||
},
|
||||
'company':{
|
||||
required:function(){
|
||||
'company': {
|
||||
required: function () {
|
||||
return $('#name').val().length === 0
|
||||
&& $('#firstname').val().length === 0;
|
||||
}
|
||||
@@ -21,4 +21,17 @@ $(document).ready(function() {
|
||||
},
|
||||
});
|
||||
});
|
||||
$('#domain_add,#domain_edit').each(function () {
|
||||
$(this).validate({
|
||||
rules: {
|
||||
'ipandport[]': {
|
||||
required: true,
|
||||
minlength: 1
|
||||
}
|
||||
},
|
||||
errorPlacement: function(error, element) {
|
||||
$(error).prependTo($(element).parent().parent());
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
@import "~@fortawesome/fontawesome-free/css/all";
|
||||
|
||||
// Generic
|
||||
.header-logo {
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.form-control-plaintext {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% macro ditem(lngstr, available, used, assigned = null, formatbytes = false) %}
|
||||
{% macro ditem(lngstr, available, used, assigned = null, formatbytes = false, byte_usage = null) %}
|
||||
<div class="col border-end border-bottom p-3">
|
||||
<div class="row mb-1">
|
||||
<div class="col text-truncate">{{ lng(lngstr) }}</div>
|
||||
<div class="col text-truncate">{{ lng(lngstr) }}{% if byte_usage %} <small>({{ byte_usage|formatBytes }})</small>{% endif %}</div>
|
||||
<div class="col-auto">
|
||||
<small>{% if formatbytes %}{{ used|formatBytes }}{% else %}{{ used }}{% endif %}/{% if available < 0 %}{{ lng('panel.unlimited') }}{% else %}{% if formatbytes %}{{ available|formatBytes }}{% else %}{{ available }}{% endif %}{% endif %}</small>
|
||||
</div>
|
||||
|
||||
@@ -33,12 +33,13 @@
|
||||
{% else %}
|
||||
{# customer-resources #}
|
||||
<div class="row row-cols-1 row-cols-sm-2 row-cols-xl-4 g-0">
|
||||
{{ dashboard.ditem('customer.total_diskspace', userinfo.diskspace_bytes, userinfo.total_bytes_used, null, true) }}
|
||||
{{ dashboard.ditem('customer.diskspace', userinfo.diskspace_bytes, userinfo.diskspace_bytes_used, null, true) }}
|
||||
{{ dashboard.ditem('customer.traffic', userinfo.traffic_bytes, userinfo.traffic_bytes_used, null, true) }}
|
||||
{{ dashboard.ditem('customer.subdomains', userinfo.subdomains, userinfo.subdomains_used) }}
|
||||
{{ dashboard.ditem('customer.mysqls', userinfo.mysqls, userinfo.mysqls_used) }}
|
||||
{{ dashboard.ditem('customer.mysqls', userinfo.mysqls, userinfo.mysqls_used, null, false, userinfo.dbspace_used) }}
|
||||
{{ dashboard.ditem('customer.emails', userinfo.emails, userinfo.emails_used) }}
|
||||
{{ dashboard.ditem('customer.accounts', userinfo.email_accounts, userinfo.email_accounts_used) }}
|
||||
{{ dashboard.ditem('customer.accounts', userinfo.email_accounts, userinfo.email_accounts_used, null, false, userinfo.mailspace_used) }}
|
||||
{{ dashboard.ditem('customer.forwarders', userinfo.email_forwarders, userinfo.email_forwarders_used) }}
|
||||
{{ dashboard.ditem('customer.ftps', userinfo.ftps, userinfo.ftps_used) }}
|
||||
</div>
|
||||
|
||||
@@ -18,14 +18,14 @@
|
||||
<!-- TODO: set url on change. e.g.: ?param=days:7 -->
|
||||
<div class="d-flex justify-content-center justify-content-md-end">
|
||||
<select class="form-select mb-3 mb-md-4 w-auto mt-md-n4" aria-label="select the traffic range" name="range" data-baseref="{{ linker({'section':'traffic'}) }}">
|
||||
<option value="hours:24" {% if range == 'hours:24' %}selected{% endif %}>last 24 hours</option>
|
||||
<option value="days:7" {% if range == 'days:7' %}selected{% endif %}>last 7 days</option>
|
||||
<option value="days:30" {% if range == 'days:30' %}selected{% endif %}>last 30 days</option>
|
||||
<option value="currentmonth" {% if range == 'currentmonth' %}selected{% endif %}>current month</option>
|
||||
<option value="months:3" {% if range == 'months:3' %}selected{% endif %}>last 3 months</option>
|
||||
<option value="months:6" {% if range == 'months:6' %}selected{% endif %}>last 6 months</option>
|
||||
<option value="months:12" {% if range == 'months:12' %}selected{% endif %}>last 12 months</option>
|
||||
<option value="currentyear" {% if range == 'currentyear' %}selected{% endif %}>current year</option>
|
||||
<option value="hours:24" {% if range == 'hours:24' %}selected{% endif %}>{{ lng('traffic.ranges.last24h') }}</option>
|
||||
<option value="days:7" {% if range == 'days:7' %}selected{% endif %}>{{ lng('traffic.ranges.last7d') }}</option>
|
||||
<option value="days:30" {% if range == 'days:30' %}selected{% endif %}>{{ lng('traffic.ranges.last30d') }}</option>
|
||||
<option value="currentmonth" {% if range == 'currentmonth' %}selected{% endif %}>{{ lng('traffic.ranges.cm') }}</option>
|
||||
<option value="months:3" {% if range == 'months:3' %}selected{% endif %}>{{ lng('traffic.ranges.last3m') }}</option>
|
||||
<option value="months:6" {% if range == 'months:6' %}selected{% endif %}>{{ lng('traffic.ranges.last6m') }}</option>
|
||||
<option value="months:12" {% if range == 'months:12' %}selected{% endif %}>{{ lng('traffic.ranges.last12m') }}</option>
|
||||
<option value="currentyear" {% if range == 'currentyear' %}selected{% endif %}>{{ lng('traffic.ranges.cy') }}</option>
|
||||
{% for yd in years_avail %}
|
||||
{% if yd.year != "now"|date('Y') %}
|
||||
<option value="year:{{ yd.year }}" {% if range == 'year:' ~ yd.year %}selected{% endif %}>{{ yd.year }}</option>
|
||||
@@ -50,37 +50,36 @@
|
||||
<div class="row row-cols-2 row-cols-md-4 g-0">
|
||||
<div class="col p-3 border-end">
|
||||
<h3>{{ metrics.total|formatBytes }}</h3>
|
||||
<span>Total</span>
|
||||
<span>{{ lng('traffic.months.total') }}</span>
|
||||
</div>
|
||||
<div class="col p-3 border-end">
|
||||
<h3>{{ metrics.http|formatBytes }}</h3>
|
||||
<span>HTTP</span>
|
||||
<span>{{ lng('traffic.http') }}</span>
|
||||
</div>
|
||||
<div class="col p-3 border-end">
|
||||
<h3>{{ metrics.ftp|formatBytes }}</h3>
|
||||
<span>FTP</span>
|
||||
<span>{{ lng('traffic.ftp') }}</span>
|
||||
</div>
|
||||
<div class="col p-3 border-end">
|
||||
<h3>{{ metrics.mail|formatBytes }}</h3>
|
||||
<span>Mail</span>
|
||||
<span>{{ lng('traffic.mail') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if userinfo.adminsession == 1 %}
|
||||
<!-- Overview for given range by user -->
|
||||
<h4 class="page-header">Traffic by customers</h4>
|
||||
<h4 class="page-header">{{ lng('traffic.bycustomers') }}</h4>
|
||||
{% if users is not empty %}
|
||||
<div class="card table-responsive">
|
||||
<table class="table table-borderless table-striped align-middle mb-0 px-3">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">{{ lng('login.username') }}</th>
|
||||
<th scope="col">Total</th>
|
||||
<th scope="col">HTTP</th>
|
||||
<th scope="col">FTP</th>
|
||||
<th scope="col">Mail
|
||||
</th>
|
||||
<th scope="col">{{ lng('traffic.months.total') }}</th>
|
||||
<th scope="col">{{ lng('traffic.http') }}</th>
|
||||
<th scope="col">{{ lng('traffic.ftp') }}</th>
|
||||
<th scope="col">{{ lng('traffic.mail') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -101,19 +100,19 @@
|
||||
{% else %}
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<p>No data for given range found.</p>
|
||||
<p>{{ lng('traffic.nodata') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<script>
|
||||
const labelsS = ['HTTP', 'FTP', 'Mail'];
|
||||
const labelsS = ['{{ lng('traffic.http') }}', '{{ lng('traffic.ftp') }}', '{{ lng('traffic.mail') }}'];
|
||||
|
||||
const dataS = {
|
||||
labels: labelsS,
|
||||
datasets: [{
|
||||
label: 'Traffic summary',
|
||||
label: '{{ lng('traffic.trafficoverview') }}',
|
||||
backgroundColor: ['rgb(255, 99, 132)', 'rgb(200, 199, 132)', 'rgb(255, 99, 0)'],
|
||||
data: [{value: '{{ metrics.http|default(0) }}', formatted: '{{ metrics.http|formatBytes }}'}, {value: '{{ metrics.ftp|default(0) }}', formatted: '{{ metrics.ftp|formatBytes }}'}, {value: '{{ metrics.mail|default(0) }}', formatted: '{{ metrics.mail|formatBytes }}'}]
|
||||
}]
|
||||
@@ -130,7 +129,7 @@
|
||||
plugins: {
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Total traffic'
|
||||
text: '{{ lng('traffic.sumtotal') }}'
|
||||
},
|
||||
legend: {
|
||||
position: 'right'
|
||||
@@ -161,7 +160,7 @@
|
||||
const dataC = {
|
||||
labels: labelsC,
|
||||
datasets: [{
|
||||
label: 'Top 5 customers',
|
||||
label: '{{ lng('traffic.top5customers') }}',
|
||||
backgroundColor: ['rgb(255, 99, 132)', 'rgb(200, 199, 132)', 'rgb(255, 99, 0)', 'rgb(100, 100, 132)', 'rgb(240, 150, 232)'],
|
||||
data: dataValues
|
||||
}]
|
||||
@@ -178,7 +177,7 @@
|
||||
plugins: {
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Top 5 customers'
|
||||
text: '{{ lng('traffic.top5customers') }}'
|
||||
},
|
||||
legend: {
|
||||
position: 'right'
|
||||
@@ -220,7 +219,7 @@
|
||||
labels: labelsC,
|
||||
datasets: [
|
||||
{
|
||||
label: 'HTTP traffic',
|
||||
label: '{{ lng('traffic.sumhttp') }}',
|
||||
backgroundColor: 'rgb(255, 99, 132)',
|
||||
{% if range starts with 'days' or range == 'currentmonth' %}
|
||||
data: [{% for d,dd in days %}{value: '{{ dd.http|default(0) }}', formatted: '{{ dd.http|formatBytes }}', axisv: '{{ d }}'},{% endfor %}],
|
||||
@@ -234,7 +233,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'FTP traffic',
|
||||
label: '{{ lng('traffic.sumftp') }}',
|
||||
backgroundColor: 'rgb(200, 199, 132)',
|
||||
{% if range starts with 'days' or range == 'currentmonth' %}
|
||||
data: [{% for d,dd in days %}{value: '{{ dd.ftp|default(0) }}', formatted: '{{ dd.ftp|formatBytes }}', axisv: '{{ d }}'},{% endfor %}],
|
||||
@@ -248,7 +247,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Mail traffic',
|
||||
label: '{{ lng('traffic.summail') }}',
|
||||
backgroundColor: 'rgb(255, 99, 0)',
|
||||
{% if range starts with 'days' or range == 'currentmonth' %}
|
||||
data: [{% for d,dd in days %}{value: '{{ dd.mail|default(0) }}', formatted: '{{ dd.mail|formatBytes }}', axisv: '{{ d }}'},{% endfor %}],
|
||||
@@ -283,7 +282,7 @@
|
||||
plugins: {
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Specified by range'
|
||||
text: '{{ lng('traffic.byrange') }}'
|
||||
},
|
||||
tooltip: {
|
||||
enabled: true,
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
</button>
|
||||
</div>
|
||||
<a class="navbar-brand me-0 {% if block('heading') %}shadow-sm{% endif %}" href="{{ linker({'section': 'index'}) }}">
|
||||
<img src="{{ header_logo }}" alt="" width="auto" height="24" class="d-inline-block align-text-top ms-md-3">
|
||||
<img src="{{ header_logo }}" alt="logo" class="header-logo d-inline-block align-text-top ms-md-3">
|
||||
</a>
|
||||
<div class="order-0 order-md-1 d-flex flex-grow-0 flex-md-grow-1" id="navbar">
|
||||
<ul class="navbar-nav ms-md-auto me-3 me-lg-5">
|
||||
|
||||
Reference in New Issue
Block a user