diff --git a/admin_admins.php b/admin_admins.php index ae9ce4ee..b22b7c21 100644 --- a/admin_admins.php +++ b/admin_admins.php @@ -32,78 +32,19 @@ if ($page == 'admins' && $userinfo['change_serversettings'] == '1') { if ($action == '') { $log->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "viewed admin_admins"); - $admin_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/admin/tablelisting.admin.php'; + $admin_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/admin/tablelisting.admins.php'; try { - // get collection - $collection = new \Froxlor\UI\Collection(\Froxlor\Api\Commands\Admins::class, $userinfo); - // initialize pagination and filtering - $paging = new \Froxlor\UI\Pagination($userinfo, $admin_list_data['admin_list']['columns'], $collection->count()); - // get filtered collection - $collection = new \Froxlor\UI\Collection(\Froxlor\Api\Commands\Admins::class, $userinfo, $paging->getApiCommandParams()); + // get filtered collection + $list = (new \Froxlor\UI\Collection(\Froxlor\Api\Commands\Admins::class, $userinfo)) + ->withPagination($admin_list_data['admin_list']['columns']) + ->getList(); } catch (Exception $e) { \Froxlor\UI\Response::dynamic_error($e->getMessage()); } - /* - $result = json_decode($json_result, true)['data']; - - $admins = ''; - $sortcode = $paging->getHtmlSortCode($lng, true); - $arrowcode = $paging->getHtmlArrowCode($filename . '?page=' . $page . '&s=' . $s); - $searchcode = $paging->getHtmlSearchCode($lng); - $pagingcode = $paging->getHtmlPagingCode($filename . '?page=' . $page . '&s=' . $s); - $count = 0; - - $dec_places = Settings::Get('panel.decimal_places'); - - foreach ($result['list'] as $row) { - - $row['traffic_used'] = round($row['traffic_used'] / (1024 * 1024), $dec_places); - $row['traffic'] = round($row['traffic'] / (1024 * 1024), $dec_places); - $row['diskspace_used'] = round($row['diskspace_used'] / 1024, $dec_places); - $row['diskspace'] = round($row['diskspace'] / 1024, $dec_places); - - // percent-values for progressbar - // For Disk usage - if ($row['diskspace'] > 0) { - $disk_percent = round(($row['diskspace_used'] * 100) / $row['diskspace'], 0); - $disk_doublepercent = round($disk_percent * 2, 2); - } else { - $disk_percent = 0; - $disk_doublepercent = 0; - } - // For Traffic usage - if ($row['traffic'] > 0) { - $traffic_percent = round(($row['traffic_used'] * 100) / $row['traffic'], 0); - $traffic_doublepercent = round($traffic_percent * 2, 2); - } else { - $traffic_percent = 0; - $traffic_doublepercent = 0; - } - - // fix progress-bars if value is >100% - if ($disk_percent > 100) { - $disk_percent = 100; - } - if ($traffic_percent > 100) { - $traffic_percent = 100; - } - - $row = \Froxlor\PhpHelper::strReplaceArray('-1', 'UL', $row, 'customers domains diskspace traffic mysqls emails email_accounts email_forwarders email_quota ftps subdomains'); - $row = \Froxlor\PhpHelper::htmlentitiesArray($row); - - $row['custom_notes'] = ($row['custom_notes'] != '') ? nl2br($row['custom_notes']) : ''; - - eval("\$admins.=\"" . \Froxlor\UI\Template::getTemplate("admins/admins_admin") . "\";"); - $count ++; - } - - $admincount = $result['count'] . " / " . $paging->getEntries(); - eval("echo \"" . \Froxlor\UI\Template::getTemplate("admins/admins") . "\";"); - */ UI::twigBuffer('user/table.html.twig', [ - 'listing' => \Froxlor\UI\Listing::format($collection, $admin_list_data['admin_list']), + 'listing' => \Froxlor\UI\Listing::format($list, $admin_list_data['admin_list']), ]); UI::twigOutputBuffer(); } elseif ($action == 'su') { diff --git a/admin_customers.php b/admin_customers.php index dddbc7be..a7b43f19 100644 --- a/admin_customers.php +++ b/admin_customers.php @@ -31,22 +31,19 @@ $id = (int) Request::get('id'); if ($page == 'customers' && $userinfo['customers'] != '0') { if ($action == '') { $log->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "viewed admin_customers"); - $customer_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/admin/tablelisting.customer.php'; try { - // get collection - $collection = new \Froxlor\UI\Collection(\Froxlor\Api\Commands\Customers::class, $userinfo); - // initialize pagination and filtering - $paging = new \Froxlor\UI\Pagination($userinfo, $customer_list_data['customer_list']['columns'], $collection->count()); - // get filtered collection - $collection = new \Froxlor\UI\Collection(\Froxlor\Api\Commands\Customers::class, $userinfo, array_merge($paging->getApiCommandParams(), ['show_usages' => true])); - $collection->has('admin', \Froxlor\Api\Commands\Admins::class, 'adminid', 'adminid'); - } catch (Exception $e) { - \Froxlor\UI\Response::dynamic_error($e->getMessage()); - } + $customer_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/admin/tablelisting.customers.php'; + $list = (new \Froxlor\UI\Collection(\Froxlor\Api\Commands\Customers::class, $userinfo)) + ->has('admin', \Froxlor\Api\Commands\Admins::class, 'adminid', 'adminid') + ->withPagination($customer_list_data['customer_list']['columns']) + ->getList(); + } catch (Exception $e) { + \Froxlor\UI\Response::dynamic_error($e->getMessage()); + } UI::twigBuffer('user/table.html.twig', [ - 'listing' => \Froxlor\UI\Listing::format($collection, $customer_list_data['customer_list']), + 'listing' => \Froxlor\UI\Listing::format($list, $customer_list_data['customer_list']), ]); UI::twigOutputBuffer(); } elseif ($action == 'su' && $id != 0) { diff --git a/admin_domains.php b/admin_domains.php index 25dc65d7..e8d32190 100644 --- a/admin_domains.php +++ b/admin_domains.php @@ -30,28 +30,21 @@ use Froxlor\UI\Request; $id = (int) Request::get('id'); if ($page == 'domains' || $page == 'overview') { - // Let's see how many customers we have - $json_result = Customers::getLocal($userinfo)->listingCount(); - $countcustomers = json_decode($json_result, true)['data']; - if ($action == '') { $log->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "viewed admin_domains"); - $domain_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/admin/tablelisting.domain.php'; try { - // get collection - $collection = new \Froxlor\UI\Collection(\Froxlor\Api\Commands\Domains::class, $userinfo); - // initialize pagination and filtering - $paging = new \Froxlor\UI\Pagination($userinfo, $domain_list_data['domain_list']['columns'], $collection->count()); - // get filtered collection - $collection = new \Froxlor\UI\Collection(\Froxlor\Api\Commands\Domains::class, $userinfo, $paging->getApiCommandParams()); - $collection->has('customer', \Froxlor\Api\Commands\Customers::class, 'customerid', 'customerid'); + $domain_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/admin/tablelisting.domains.php'; + $list = (new \Froxlor\UI\Collection(\Froxlor\Api\Commands\Domains::class, $userinfo)) + ->has('customer', \Froxlor\Api\Commands\Customers::class, 'customerid', 'customerid') + ->withPagination($domain_list_data['domain_list']['columns']) + ->getList(); } catch (Exception $e) { \Froxlor\UI\Response::dynamic_error($e->getMessage()); } UI::twigBuffer('user/table.html.twig', [ - 'listing' => \Froxlor\UI\Listing::format($collection, $domain_list_data['domain_list']), + 'listing' => \Froxlor\UI\Listing::format($list, $domain_list_data['domain_list']), ]); UI::twigOutputBuffer(); } elseif ($action == 'delete' && $id != 0) { diff --git a/admin_ipsandports.php b/admin_ipsandports.php index 0c928f71..172806c6 100644 --- a/admin_ipsandports.php +++ b/admin_ipsandports.php @@ -28,32 +28,22 @@ use Froxlor\UI\Request; $id = (int) Request::get('id'); if ($page == 'ipsandports' || $page == 'overview') { - // Do not display attributes that are not used by the current webserver - $websrv = Settings::Get('system.webserver'); - $is_nginx = ($websrv == 'nginx'); - $is_apache = ($websrv == 'apache2'); - $is_apache24 = $is_apache && (Settings::Get('system.apache24') === '1'); - if ($action == '') { - $log->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "viewed admin_ipsandports"); - $ipsandports_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/admin/tablelisting.ipsandports.php'; try { - // get collection - $collection = new \Froxlor\UI\Collection(\Froxlor\Api\Commands\IpsAndPorts::class, $userinfo); - // initialize pagination and filtering - $paging = new \Froxlor\UI\Pagination($userinfo, $ipsandports_list_data['ipsandports_list']['columns'], $collection->count()); - // get filtered collection - $collection = new \Froxlor\UI\Collection(\Froxlor\Api\Commands\IpsAndPorts::class, $userinfo, $paging->getApiCommandParams()); - } catch (Exception $e) { + $ipsandports_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/admin/tablelisting.ipsandports.php'; + $list = (new \Froxlor\UI\Collection(\Froxlor\Api\Commands\IpsAndPorts::class, $userinfo)) + ->withPagination($ipsandports_list_data['ipsandports_list']['columns']) + ->getList(); + } catch (Exception $e) { \Froxlor\UI\Response::dynamic_error($e->getMessage()); } - UI::twigBuffer('user/table.html.twig', [ - 'listing' => \Froxlor\UI\Listing::format($collection, $ipsandports_list_data['ipsandports_list']), - ]); - UI::twigOutputBuffer(); + UI::twigBuffer('user/table.html.twig', [ + 'listing' => \Froxlor\UI\Listing::format($list, $ipsandports_list_data['ipsandports_list']), + ]); + UI::twigOutputBuffer(); } elseif ($action == 'delete' && $id != 0) { try { $json_result = IpsAndPorts::getLocal($userinfo, array( diff --git a/admin_plans.php b/admin_plans.php index adbb822f..c856766e 100644 --- a/admin_plans.php +++ b/admin_plans.php @@ -31,40 +31,20 @@ if ($page == '' || $page == 'overview') { if ($action == '') { $log->logAction(\Froxlor\FroxlorLogger::ADM_ACTION, LOG_NOTICE, "viewed admin_plans"); - $fields = array( - 'p.name' => $lng['admin']['plans']['name'], - 'p.description' => $lng['admin']['plans']['description'], - 'adminname' => $lng['admin']['admin'], - 'p.ts' => $lng['admin']['plans']['last_update'] - ); + try { - // get total count - $json_result = HostingPlans::getLocal($userinfo)->listingCount(); - $result = json_decode($json_result, true)['data']; - // initialize pagination and filtering - $paging = new \Froxlor\UI\Pagination($userinfo, $fields, $result); - // get list - $json_result = HostingPlans::getLocal($userinfo, $paging->getApiCommandParams())->listing(); + $plan_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/admin/tablelisting.plans.php'; + $list = (new \Froxlor\UI\Collection(\Froxlor\Api\Commands\HostingPlans::class, $userinfo)) + ->withPagination($plan_list_data['plan_list']['columns']) + ->getList(); } catch (Exception $e) { \Froxlor\UI\Response::dynamic_error($e->getMessage()); } - $result = json_decode($json_result, true)['data']; - $plans = ''; - $sortcode = $paging->getHtmlSortCode($lng); - $arrowcode = $paging->getHtmlArrowCode($filename . '?page=' . $page . '&s=' . $s); - $searchcode = $paging->getHtmlSearchCode($lng); - $pagingcode = $paging->getHtmlPagingCode($filename . '?page=' . $page . '&s=' . $s); - $count = 0; - - foreach ($result['list'] as $row) { - $row = \Froxlor\PhpHelper::htmlentitiesArray($row); - $row['ts_format'] = date("d.m.Y H:i", $row['ts']); - eval("\$plans.=\"" . \Froxlor\UI\Template::getTemplate("plans/plans_plan") . "\";"); - $count++; - } - - eval("echo \"" . \Froxlor\UI\Template::getTemplate("plans/plans") . "\";"); + UI::twigBuffer('user/table.html.twig', [ + 'listing' => \Froxlor\UI\Listing::format($list, $plan_list_data['plan_list']), + ]); + UI::twigOutputBuffer(); } elseif ($action == 'delete' && $id != 0) { try { diff --git a/lib/Froxlor/Api/Commands/Certificates.php b/lib/Froxlor/Api/Commands/Certificates.php index 960a1a02..c3052343 100644 --- a/lib/Froxlor/Api/Commands/Certificates.php +++ b/lib/Froxlor/Api/Commands/Certificates.php @@ -220,6 +220,29 @@ class Certificates extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resou $cert['letsencrypt'] = Settings::Get('system.le_froxlor_enabled'); $cert['loginname'] = 'froxlor.panel'; } + + // Set data from certificate + $cert_data = openssl_x509_parse($cert['ssl_cert_file']); + if ($cert_data) { + $cert['validfromdate'] = date('Y-m-d H:i:s', $cert_data['validFrom_time_t']); + $cert['validtodate'] = date('Y-m-d H:i:s', $cert_data['validTo_time_t']); + $cert['isvalid'] = (bool) $cert_data['validTo_time_t'] > time(); + $cert['issuer'] = $cert_data['issuer']['O'] ?? null; + } + + // Set subject alt names from certificate + $cert['san'] = null; + if (isset($cert_data['extensions']['subjectAltName']) && ! empty($cert_data['extensions']['subjectAltName'])) { + $SANs = explode(",", $cert_data['extensions']['subjectAltName']); + $SANs = array_map('trim', $SANs); + foreach ($SANs as $san) { + $san = str_replace("DNS:", "", $san); + if ($san != $cert_data['subject']['CN'] && strpos($san, "othername:") === false) { + $cert['san'][] = $san; + } + } + } + $result[] = $cert; } return $this->response(array( diff --git a/lib/Froxlor/UI/Callbacks/Impersonate.php b/lib/Froxlor/UI/Callbacks/Impersonate.php new file mode 100644 index 00000000..c9b508f1 --- /dev/null +++ b/lib/Froxlor/UI/Callbacks/Impersonate.php @@ -0,0 +1,58 @@ + (2010-) + * @author Maurice Preuß + * @license GPLv2 http://files.froxlor.org/misc/COPYING.txt + * @package Listing + * + */ + +class Impersonate +{ + public static function admin(string $data, array $attributes): array + { + $linker = UI::getLinker(); + return [ + 'type' => 'link', + 'data' => [ + 'text' => $data, + 'href' => $linker->getLink([ + 'section' => 'admins', + 'page' => 'admins', + 'action' => 'su', + 'id' => $attributes['adminid'], + ]), + ] + ]; + } + + public static function customer(string $data, array $attributes): array + { + $linker = UI::getLinker(); + return [ + 'type' => 'link', + 'data' => [ + 'text' => $data, + 'href' => $linker->getLink([ + 'section' => 'customers', + 'page' => 'customers', + 'action' => 'su', + 'sort' => $attributes['loginname'], + 'id' => $attributes['customerid'], + ]), + ] + ]; + } +} diff --git a/lib/Froxlor/UI/Callbacks/Text.php b/lib/Froxlor/UI/Callbacks/Text.php index 0f6310f0..04d9b4e0 100644 --- a/lib/Froxlor/UI/Callbacks/Text.php +++ b/lib/Froxlor/UI/Callbacks/Text.php @@ -18,11 +18,22 @@ namespace Froxlor\UI\Callbacks; */ class Text { - public static function boolean(string $data): array + public static function boolean(?string $data): array { return [ 'type' => 'boolean', 'data' => (bool) $data ]; } -} \ No newline at end of file + + public static function domainWithSan(string $data, array $attributes): array + { + return [ + 'type' => 'domainWithSan', + 'data' => [ + 'domain' => $data, + 'san' => implode(', ', $attributes['san'] ?? []), + ] + ]; + } +} diff --git a/lib/Froxlor/UI/Collection.php b/lib/Froxlor/UI/Collection.php index cf9417ad..82f216c8 100644 --- a/lib/Froxlor/UI/Collection.php +++ b/lib/Froxlor/UI/Collection.php @@ -19,59 +19,85 @@ namespace Froxlor\UI; */ class Collection { - private array $items; - private array $userInfo; - private array $params; private string $class; + private array $has = []; + private array $params; + private array $userinfo; public function __construct(string $class, array $userInfo, array $params = []) { $this->class = $class; $this->params = $params; - $this->userInfo = $userInfo; - - $this->items = $this->getListing($this->class, $this->params); + $this->userinfo = $userInfo; } - private function getListing($class, $params) + private function getListing($class, $params): array { - return json_decode($class::getLocal($this->userInfo, $params)->listing(), true); + return json_decode($class::getLocal($this->userinfo, $params)->listing(), true); } - public function count() + public function count(): int { - return json_decode($this->class::getLocal($this->userInfo, $this->params)->listingCount(), true); + return json_decode($this->class::getLocal($this->userinfo, $this->params)->listingCount(), true)['data']; } - public function get() + public function get(): array { - return $this->items; - } + $result = $this->getListing($this->class, $this->params); - public function getData() - { - return $this->get()['data']; - } - - public function getJson() - { - return json_encode($this->get()); - } - - public function has($column, $class, $parentKey = 'id', $childKey = 'id', $params = []): Collection - { // check if the api result contains any items (not the overall listingCount as we might be in a search-resultset) - if (count($this->items) > 0) { - $attributes = $this->getListing($class, $params); + if (count($result)) { + foreach ($this->has as $has) { + $attributes = $this->getListing($has['class'], $has['params']); - foreach ($this->items['data']['list'] as $key => $item) { - foreach ($attributes['data']['list'] as $list) { - if ($item[$parentKey] == $list[$childKey]) { - $this->items['data']['list'][$key][$column] = $list; + foreach ($result['data']['list'] as $key => $item) { + foreach ($attributes['data']['list'] as $list) { + if ($item[$has['parentKey']] == $list[$has['childKey']]) { + $result['data']['list'][$key][$has['column']] = $list; + } } } } } + + return $result; + } + + public function getData(): array + { + return $this->get()['data']; + } + + public function getList(): array + { + return $this->getData()['list']; + } + + public function getJson(): string + { + return json_encode($this->get()); + } + + public function has(string $column, string $class, string $parentKey = 'id', string $childKey = 'id', array $params = []): Collection + { + $this->has[] = [ + 'column' => $column, + 'class' => $class, + 'parentKey' => $parentKey, + 'childKey' => $childKey, + 'params' => $params + ]; + + return $this; + } + + public function withPagination(array $columns): Collection + { + // TODO: handle 'sortable' => true in $columns + + $pagination = new Pagination($this->userinfo, $columns, $this->count()); + $this->params = array_merge($this->params, $pagination->getApiCommandParams()); + return $this; } } diff --git a/lib/Froxlor/UI/Listing.php b/lib/Froxlor/UI/Listing.php index 3f411724..a6d3b200 100644 --- a/lib/Froxlor/UI/Listing.php +++ b/lib/Froxlor/UI/Listing.php @@ -20,14 +20,14 @@ use Froxlor\UI\Panel\UI; */ class Listing { - public static function format(Collection $collection, array $tabellisting): array + public static function format(array $list, array $tabellisting): array { return [ 'title' => $tabellisting['title'], 'icon' => $tabellisting['icon'], 'table' => [ 'th' => self::generateTableHeadings($tabellisting), - 'tr' => self::generateTableRows($collection, $tabellisting), + 'tr' => self::generateTableRows($list, $tabellisting), ], 'pagination' => null, // TODO: write some logic ]; @@ -43,26 +43,31 @@ class Listing continue; } - $heading[] = $tabellisting['columns'][$visible_column]['label']; + $heading[] = [ + 'text' => $tabellisting['columns'][$visible_column]['label'], + 'class' => $tabellisting['columns'][$visible_column]['class'] ?? null, + ]; } // Table headings for actions if (isset($tabellisting['actions'])) { - $heading[] = UI::getLng('panel.options'); + $heading[] = [ + 'text' => UI::getLng('panel.options'), + 'class' => 'text-end', + ]; } return $heading; } - private static function generateTableRows(Collection $collection, array $tabellisting): array + private static function generateTableRows(array $list, array $tabellisting): array { $rows = []; - $items = $collection->getData()['list']; // Create new row from item - foreach ($items as $key => $item) { + foreach ($list as $row => $item) { // Generate columns from item - foreach ($tabellisting['visible_columns'] as $visible_column) { + foreach ($tabellisting['visible_columns'] as $col => $visible_column) { if (isset($tabellisting['columns'][$visible_column]['visible']) && !$tabellisting['columns'][$visible_column]['visible']) { continue; } @@ -71,22 +76,30 @@ class Listing $column = $tabellisting['columns'][$visible_column]['column']; $data = self::getMultiArrayFromString($item, $column); - // TODO: contextual_class ... - if ($format_callback) { - $rows[$key][] = call_user_func($format_callback, $data, $item); + $rows[$row]['td'][$col]['data'] = call_user_func($format_callback, $data, $item); } else { - $rows[$key][] = $data; + $rows[$row]['td'][$col]['data'] = $data; } + + $rows[$row]['td'][$col]['class'] = $tabellisting['columns'][$visible_column]['class'] ?? null; } + // TODO: contextual_class ... + //if (...) { + // $rows[$key]['class'] = '...'; + //} + // Set all actions for row if (isset($tabellisting['actions'])) { $actions = self::setLinks($tabellisting['actions'], $item); - $rows[$key]['action'] = [ - 'type' => 'actions', - 'data' => $actions + $rows[$row]['td'][] = [ + 'class' => 'text-end', + 'data' => [ + 'type' => 'actions', + 'data' => $actions + ] ]; } } @@ -94,7 +107,7 @@ class Listing return $rows; } - private static function setLinks($actions, array $item) + private static function setLinks(array $actions, array $item): array { $linker = UI::getLinker(); @@ -119,7 +132,7 @@ class Listing return $actions; } - public static function getVisibleColumnsForListing($listing, $default_columns) + public static function getVisibleColumnsForListing(string $listing, array $default_columns): array { // Hier käme dann die Logik, die das aus der DB zieht ... // alternativ nimmt er die $default_columns, wenn kein Eintrag @@ -128,7 +141,7 @@ class Listing return $default_columns; } - public static function getMultiArrayFromString($arr, $str) + public static function getMultiArrayFromString(array $arr, string $str) { foreach (explode('.', $str) as $key) { if (!array_key_exists($key, $arr)) { diff --git a/lib/tablelisting/admin/tablelisting.admin.php b/lib/tablelisting/admin/tablelisting.admins.php similarity index 77% rename from lib/tablelisting/admin/tablelisting.admin.php rename to lib/tablelisting/admin/tablelisting.admins.php index 0e737b31..18091a84 100644 --- a/lib/tablelisting/admin/tablelisting.admin.php +++ b/lib/tablelisting/admin/tablelisting.admins.php @@ -16,6 +16,10 @@ * */ +use Froxlor\UI\Callbacks\ProgressBar; +use Froxlor\UI\Callbacks\Text; +use Froxlor\UI\Listing; + return [ 'admin_list' => [ 'title' => $lng['admin']['admin'], @@ -37,25 +41,27 @@ return [ ], 'customers_used' => [ 'label' => $lng['admin']['customers'], - 'column' => 'customers_used' + 'column' => 'customers_used', + 'class' => 'text-center', ], 'diskspace' => [ 'label' => $lng['customer']['diskspace'], 'column' => 'diskspace', - 'format_callback' => [\Froxlor\UI\Callbacks\ProgressBar::class, 'diskspace'], + 'format_callback' => [ProgressBar::class, 'diskspace'], ], 'traffic' => [ 'label' => $lng['customer']['traffic'], 'column' => 'traffic', - 'format_callback' => [\Froxlor\UI\Callbacks\ProgressBar::class, 'traffic'], + 'format_callback' => [ProgressBar::class, 'traffic'], ], 'deactivated' => [ 'label' => $lng['admin']['deactivated'], 'column' => 'deactivated', - 'format_callback' => [\Froxlor\UI\Callbacks\Text::class, 'boolean'], + 'class' => 'text-center', + 'format_callback' => [Text::class, 'boolean'], ], ], - 'visible_columns' => \Froxlor\UI\Listing::getVisibleColumnsForListing('admin_list', [ + 'visible_columns' => Listing::getVisibleColumnsForListing('admin_list', [ 'loginname', 'name', 'customers_used', @@ -64,24 +70,25 @@ return [ 'deactivated', ]), 'actions' => [ - 'delete' => [ - 'icon' => 'fa fa-trash', - 'href' => [ - 'section' => 'admins', - 'page' => 'admins', - 'action' => 'delete', - 'id' => ':adminid' - ], - ], 'edit' => [ - 'text' => 'Edit', + 'icon' => 'fa fa-edit', 'href' => [ 'section' => 'admins', 'page' => 'admins', 'action' => 'edit', 'id' => ':adminid' ], - ] + ], + 'delete' => [ + 'icon' => 'fa fa-trash', + 'class' => 'text-danger', + 'href' => [ + 'section' => 'admins', + 'page' => 'admins', + 'action' => 'delete', + 'id' => ':adminid' + ], + ], ], 'contextual_class' => [ 'deactivated' => [ diff --git a/lib/tablelisting/admin/tablelisting.customer.php b/lib/tablelisting/admin/tablelisting.customers.php similarity index 82% rename from lib/tablelisting/admin/tablelisting.customer.php rename to lib/tablelisting/admin/tablelisting.customers.php index cd949337..629bf7a4 100644 --- a/lib/tablelisting/admin/tablelisting.customer.php +++ b/lib/tablelisting/admin/tablelisting.customers.php @@ -16,6 +16,10 @@ * */ +use Froxlor\UI\Callbacks\Impersonate; +use Froxlor\UI\Callbacks\ProgressBar; +use Froxlor\UI\Listing; + return [ 'customer_list' => [ 'title' => $lng['admin']['customers'], @@ -24,10 +28,12 @@ return [ 'c.loginname' => [ 'label' => $lng['login']['username'], 'column' => 'loginname', + 'format_callback' => [Impersonate::class, 'customer'], ], 'a.loginname' => [ 'label' => $lng['admin']['admin'], 'column' => 'admin.loginname', + 'format_callback' => [Impersonate::class, 'admin'], ], 'c.name' => [ 'label' => $lng['customer']['name'], @@ -48,15 +54,15 @@ return [ 'c.diskspace' => [ 'label' => $lng['customer']['diskspace'], 'column' => 'diskspace', - 'format_callback' => [\Froxlor\UI\Callbacks\ProgressBar::class, 'diskspace'], + 'format_callback' => [ProgressBar::class, 'diskspace'], ], 'c.traffic' => [ 'label' => $lng['customer']['traffic'], 'column' => 'traffic', - 'format_callback' => [\Froxlor\UI\Callbacks\ProgressBar::class, 'traffic'], + 'format_callback' => [ProgressBar::class, 'traffic'], ], ], - 'visible_columns' => \Froxlor\UI\Listing::getVisibleColumnsForListing('customer_list', [ + 'visible_columns' => Listing::getVisibleColumnsForListing('customer_list', [ 'c.loginname', 'a.loginname', 'c.email', @@ -66,8 +72,18 @@ return [ 'c.traffic', ]), 'actions' => [ + 'edit' => [ + 'icon' => 'fa fa-edit', + 'href' => [ + 'section' => 'customers', + 'page' => 'customers', + 'action' => 'edit', + 'id' => ':customerid' + ], + ], 'delete' => [ 'icon' => 'fa fa-trash', + 'class' => 'text-danger', 'href' => [ 'section' => 'customers', 'page' => 'customers', @@ -75,15 +91,6 @@ return [ 'id' => ':customerid' ], ], - 'edit' => [ - 'text' => 'Edit', - 'href' => [ - 'section' => 'customers', - 'page' => 'customers', - 'action' => 'edit', - 'id' => ':customerid' - ], - ] ], ] ]; diff --git a/lib/tablelisting/admin/tablelisting.domain.php b/lib/tablelisting/admin/tablelisting.domains.php similarity index 90% rename from lib/tablelisting/admin/tablelisting.domain.php rename to lib/tablelisting/admin/tablelisting.domains.php index 079f44aa..fb54fdcc 100644 --- a/lib/tablelisting/admin/tablelisting.domain.php +++ b/lib/tablelisting/admin/tablelisting.domains.php @@ -16,6 +16,9 @@ * */ +use Froxlor\UI\Callbacks\Impersonate; +use Froxlor\UI\Listing; + return [ 'domain_list' => [ 'title' => $lng['admin']['domains'], @@ -40,13 +43,14 @@ return [ 'c.loginname' => [ 'label' => $lng['login']['username'], 'column' => 'customer.loginname', + 'format_callback' => [Impersonate::class, 'customer'], ], 'd.aliasdomain' => [ 'label' => $lng['domains']['aliasdomain'], 'column' => 'aliasdomain', ], ], - 'visible_columns' => \Froxlor\UI\Listing::getVisibleColumnsForListing('domain_list', [ + 'visible_columns' => Listing::getVisibleColumnsForListing('domain_list', [ 'd.domain_ace', 'c.name', 'c.firstname', @@ -55,17 +59,8 @@ return [ 'd.aliasdomain', ]), 'actions' => [ - 'delete' => [ - 'icon' => 'fa fa-trash', - 'href' => [ - 'section' => 'domains', - 'page' => 'domains', - 'action' => 'delete', - 'id' => ':id' - ], - ], 'edit' => [ - 'text' => 'Edit', + 'icon' => 'fa fa-edit', 'href' => [ 'section' => 'domains', 'page' => 'domains', @@ -88,7 +83,17 @@ return [ 'page' => 'domaindnseditor', 'domain_id' => ':id' ], - ] + ], + 'delete' => [ + 'icon' => 'fa fa-trash', + 'class' => 'text-danger', + 'href' => [ + 'section' => 'domains', + 'page' => 'domains', + 'action' => 'delete', + 'id' => ':id' + ], + ], ] ] ]; diff --git a/lib/tablelisting/admin/tablelisting.ipsandports.php b/lib/tablelisting/admin/tablelisting.ipsandports.php index 8ebf4abd..66a1b117 100644 --- a/lib/tablelisting/admin/tablelisting.ipsandports.php +++ b/lib/tablelisting/admin/tablelisting.ipsandports.php @@ -16,6 +16,10 @@ * */ +use Froxlor\Settings; +use Froxlor\UI\Callbacks\Text; +use Froxlor\UI\Listing; + return [ 'ipsandports_list' => [ 'title' => $lng['admin']['ipsandports']['ipsandports'], @@ -28,42 +32,49 @@ return [ 'port' => [ 'label' => $lng['admin']['ipsandports']['port'], 'column' => 'port', + 'class' => 'text-center', ], 'listen' => [ 'label' => 'Listen', 'column' => 'listen_statement', - 'format_callback' => [\Froxlor\UI\Callbacks\Text::class, 'boolean'], - 'visible' => \Froxlor\Settings::Get('system.webserver') != 'nginx' + 'class' => 'text-center', + 'format_callback' => [Text::class, 'boolean'], + 'visible' => Settings::Get('system.webserver') != 'nginx' ], 'namevirtualhost' => [ 'label' => 'NameVirtualHost', 'column' => 'namevirtualhost_statement', - 'format_callback' => [\Froxlor\UI\Callbacks\Text::class, 'boolean'], - 'visible' => \Froxlor\Settings::Get('system.webserver') == 'apache2' && (int) \Froxlor\Settings::Get('system.apache24') == 0 + 'class' => 'text-center', + 'format_callback' => [Text::class, 'boolean'], + 'visible' => Settings::Get('system.webserver') == 'apache2' && (int) Settings::Get('system.apache24') == 0 ], 'vhostcontainer' => [ 'label' => 'vHost-Container', 'column' => 'vhostcontainer', - 'format_callback' => [\Froxlor\UI\Callbacks\Text::class, 'boolean'] + 'class' => 'text-center', + 'format_callback' => [Text::class, 'boolean'] ], 'specialsettings' => [ 'label' => 'Specialsettings', 'column' => 'specialsettings', - 'format_callback' => [\Froxlor\UI\Callbacks\Text::class, 'boolean'] + 'class' => 'text-center', + 'format_callback' => [Text::class, 'boolean'] ], 'servername' => [ 'label' => 'ServerName', 'column' => 'vhostcontainer_servername_statement', - 'format_callback' => [\Froxlor\UI\Callbacks\Text::class, 'boolean'], - 'visible' => \Froxlor\Settings::Get('system.webserver') == 'apache2' + 'class' => 'text-center', + 'format_callback' => [Text::class, 'boolean'], + 'visible' => Settings::Get('system.webserver') == 'apache2' ], 'ssl' => [ 'label' => 'SSL', 'column' => 'ssl', - 'format_callback' => [\Froxlor\UI\Callbacks\Text::class, 'boolean'] + 'class' => 'text-center', + 'format_callback' => [Text::class, 'boolean'] ], ], - 'visible_columns' => \Froxlor\UI\Listing::getVisibleColumnsForListing('ipsandports_list', [ + 'visible_columns' => Listing::getVisibleColumnsForListing('ipsandports_list', [ 'ip', 'port', 'listen', @@ -73,5 +84,26 @@ return [ 'servername', 'ssl' ]), + 'actions' => [ + 'edit' => [ + 'icon' => 'fa fa-edit', + 'href' => [ + 'section' => 'ipsandports', + 'page' => 'ipsandports', + 'action' => 'edit', + 'id' => ':id' + ], + ], + 'delete' => [ + 'icon' => 'fa fa-trash', + 'class' => 'text-danger', + 'href' => [ + 'section' => 'ipsandports', + 'page' => 'ipsandports', + 'action' => 'delete', + 'id' => ':id' + ], + ], + ] ] ]; diff --git a/lib/tablelisting/admin/tablelisting.plans.php b/lib/tablelisting/admin/tablelisting.plans.php new file mode 100644 index 00000000..88d5a7c4 --- /dev/null +++ b/lib/tablelisting/admin/tablelisting.plans.php @@ -0,0 +1,72 @@ + (2010-) + * @author Maurice Preuß + * @license GPLv2 http://files.froxlor.org/misc/COPYING.txt + * @package Tabellisting + * + */ + +use Froxlor\Settings; +use Froxlor\UI\Listing; + +return [ + 'plan_list' => [ + 'title' => $lng['domains']['ssl_certificates'], + 'icon' => 'fa-solid fa-user', + 'columns' => [ + 'p.name' => [ + 'label' => $lng['admin']['plans']['name'], + 'column' => 'name', + ], + 'p.description' => [ + 'label' => $lng['admin']['plans']['description'], + 'column' => 'description', + ], + 'p.adminname' => [ + 'label' => $lng['admin']['admin'], + 'column' => 'adminname', + ], + 'p.ts' => [ + 'label' => $lng['admin']['plans']['last_update'], + 'column' => 'ts', + ], + ], + 'visible_columns' => Listing::getVisibleColumnsForListing('sslcertificates_list', [ + 'p.name', + 'p.description', + 'p.adminname', + 'p.ts', + ]), + 'actions' => [ + 'edit' => [ + 'icon' => 'fa fa-edit', + 'href' => [ + 'section' => 'plans', + 'page' => 'overview', + 'action' => 'edit', + 'id' => ':id' + ], + ], + 'delete' => [ + 'icon' => 'fa fa-trash', + 'class' => 'text-danger', + 'href' => [ + 'section' => 'plans', + 'page' => 'overview', + 'action' => 'delete', + 'id' => ':id' + ], + ], + ] + ] +]; diff --git a/lib/tablelisting/admin/tablelisting.sslcertificates.php b/lib/tablelisting/admin/tablelisting.sslcertificates.php new file mode 100644 index 00000000..a685e64a --- /dev/null +++ b/lib/tablelisting/admin/tablelisting.sslcertificates.php @@ -0,0 +1,78 @@ + (2010-) + * @author Maurice Preuß + * @license GPLv2 http://files.froxlor.org/misc/COPYING.txt + * @package Tabellisting + * + */ + +use Froxlor\Settings; +use Froxlor\UI\Callbacks\Text; +use Froxlor\UI\Listing; + +return [ + 'sslcertificates_list' => [ + 'title' => $lng['domains']['ssl_certificates'], + 'icon' => 'fa-solid fa-user', + 'columns' => [ + 'd.domain' => [ + 'label' => $lng['domains']['domainname'], + 'column' => 'domain', + ], + 'c.domain' => [ + 'label' => $lng['ssl_certificates']['certificate_for'], + 'column' => 'domain', + 'format_callback' => [Text::class, 'domainWithSan'], + ], + 'c.issuer' => [ + 'label' => $lng['ssl_certificates']['issuer'], + 'column' => 'issuer', + ], + 'c.validfromdate' => [ + 'label' => $lng['ssl_certificates']['valid_from'], + 'column' => 'validfromdate', + ], + 'c.validtodate' => [ + 'label' => $lng['ssl_certificates']['valid_until'], + 'column' => 'validtodate', + ], + 'c.letsencrypt' => [ + 'label' => $lng['panel']['letsencrypt'], + 'column' => 'letsencrypt', + 'class' => 'text-center', + 'format_callback' => [Text::class, 'boolean'], + 'visible' => Settings::Get('system.le_froxlor_enabled'), + ], + ], + 'visible_columns' => Listing::getVisibleColumnsForListing('sslcertificates_list', [ + 'd.domain', + 'c.domain', + 'c.issuer', + 'c.validfromdate', + 'c.validtodate', + 'c.letsencrypt', + ]), + 'actions' => [ + 'delete' => [ + 'icon' => 'fa fa-trash', + 'class' => 'text-danger', + 'href' => [ + 'section' => 'domains', + 'page' => 'sslcertificates', + 'action' => 'delete', + 'id' => ':id' + ], + ], + ] + ] +]; diff --git a/lng/english.lng.php b/lng/english.lng.php index 09d44e87..71eed37c 100644 --- a/lng/english.lng.php +++ b/lng/english.lng.php @@ -2142,3 +2142,7 @@ $lng['serversettings']['acmeshpath']['description'] = 'Set this to where acme.sh $lng['panel']['usage_statistics'] = 'Resource usage'; $lng['panel']['security_question'] = 'Security question'; +$lng['ssl_certificates']['certificate_for'] = 'Certificate for'; +$lng['ssl_certificates']['valid_from'] = 'Valid from'; +$lng['ssl_certificates']['valid_until'] = 'Valid until'; +$lng['ssl_certificates']['issuer'] = 'Issuer'; diff --git a/ssl_certificates.php b/ssl_certificates.php index cdc0b67d..62864a9f 100644 --- a/ssl_certificates.php +++ b/ssl_certificates.php @@ -16,11 +16,16 @@ if (! defined('AREA')) { * @author Froxlor team (2016-) * @license GPLv2 http://files.froxlor.org/misc/COPYING.txt * @package Panel - * + * */ -use Froxlor\Settings; -use Froxlor\Api\Commands\Certificates as Certificates; +use Froxlor\FroxlorLogger; +use Froxlor\Api\Commands\Certificates; +use Froxlor\UI\Collection; +use Froxlor\UI\Listing; +use Froxlor\UI\Pagination; +use Froxlor\UI\Panel\UI; +use Froxlor\UI\Response; // This file is being included in admin_domains and customer_domains // and therefore does not need to require lib/init.php @@ -32,115 +37,28 @@ if ($action == 'delete') { $id = isset($_GET['id']) ? (int) $_GET['id'] : 0; if ($id > 0) { try { - $json_result = Certificates::getLocal($userinfo, array( + $json_result = Certificates::getLocal($userinfo, [ 'id' => $id - ))->delete(); + ])->delete(); $success_message = sprintf($lng['domains']['ssl_certificate_removed'], $id); } catch (Exception $e) { - \Froxlor\UI\Response::dynamic_error($e->getMessage()); + Response::dynamic_error($e->getMessage()); } } } -$log->logAction(\Froxlor\FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed domains::ssl_certificates"); -$fields = array( - 'd.domain' => $lng['domains']['domainname'] -); +$log->logAction(FroxlorLogger::USR_ACTION, LOG_NOTICE, "viewed domains::ssl_certificates"); + try { - // get total count - $json_result = Certificates::getLocal($userinfo)->listingCount(); - $result = json_decode($json_result, true)['data']; - // initialize pagination and filtering - $paging = new \Froxlor\UI\Pagination($userinfo, $fields, $result); - // get list - $json_result = Certificates::getLocal($userinfo, $paging->getApiCommandParams())->listing(); + $certificates_list_data = include_once dirname(__FILE__) . '/lib/tablelisting/admin/tablelisting.sslcertificates.php'; + $list = (new Collection(Certificates::class, $userinfo)) + ->withPagination($certificates_list_data['sslcertificates_list']['columns']) + ->getList(); } catch (Exception $e) { - \Froxlor\UI\Response::dynamic_error($e->getMessage()); + Response::dynamic_error($e->getMessage()); } -$result = json_decode($json_result, true)['data']; -$all_certs = $result['list']; -$certificates = ""; - -if (count($all_certs) == 0) { - $message = $lng['domains']['no_ssl_certificates']; - $sortcode = ""; - $arrowcode = array( - 'd.domain' => '' - ); - // keep searching code if something was searched and no results were returned - $searchcode = $paging->getHtmlSearchCode($lng); - $pagingcode = ""; - eval("\$certificates.=\"" . \Froxlor\UI\Template::getTemplate("ssl_certificates/certs_error", true) . "\";"); -} else { - $sortcode = $paging->getHtmlSortCode($lng); - $arrowcode = $paging->getHtmlArrowCode($filename . '?page=' . $page . '&s=' . $s); - $searchcode = $paging->getHtmlSearchCode($lng); - $pagingcode = $paging->getHtmlPagingCode($filename . '?page=' . $page . '&s=' . $s); - - foreach ($all_certs as $idx => $cert) { - // respect froxlor-hostname - if ($cert['domainid'] == 0) { - $cert['domain'] = Settings::Get('system.hostname'); - $cert['letsencrypt'] = Settings::Get('system.le_froxlor_enabled'); - $cert['loginname'] = 'froxlor.panel'; - } - - if (empty($cert['domain']) || empty($cert['ssl_cert_file'])) { - // no domain found to the entry or empty entry - safely delete it from the DB - try { - Certificates::getLocal($userinfo, array( - 'id' => $cert['id'] - ))->delete(); - } catch (Exception $e) { - // do nothing - } - continue; - } - - $cert_data = openssl_x509_parse($cert['ssl_cert_file']); - - $cert['domain'] = $idna_convert->decode($cert['domain']); - - $adminCustomerLink = ""; - if (AREA == 'admin' && $cert['domainid'] > 0) { - if (! empty($cert['loginname'])) { - $adminCustomerLink = ' (' . $cert['loginname'] . ')'; - } - } - - if ($cert_data) { - $validFrom = date('d.m.Y H:i:s', $cert_data['validFrom_time_t']); - $validTo = date('d.m.Y H:i:s', $cert_data['validTo_time_t']); - - $isValid = true; - if ($cert_data['validTo_time_t'] < time()) { - $isValid = false; - } - - $san_list = ""; - if (isset($cert_data['extensions']['subjectAltName']) && ! empty($cert_data['extensions']['subjectAltName'])) { - $SANs = explode(",", $cert_data['extensions']['subjectAltName']); - $SANs = array_map('trim', $SANs); - foreach ($SANs as $san) { - $san = str_replace("DNS:", "", $san); - if ($san != $cert_data['subject']['CN'] && strpos($san, "othername:") === false) { - $san_list .= $san . "
"; - } - } - } - - $row = \Froxlor\PhpHelper::htmlentitiesArray($cert); - eval("\$certificates.=\"" . \Froxlor\UI\Template::getTemplate("ssl_certificates/certs_cert", true) . "\";"); - } else { - $message = sprintf($lng['domains']['ssl_certificate_error'], $cert['domain']); - eval("\$certificates.=\"" . \Froxlor\UI\Template::getTemplate("ssl_certificates/certs_error", true) . "\";"); - } - } -} -eval("echo \"" . \Froxlor\UI\Template::getTemplate("ssl_certificates/certs_list", true) . "\";"); +UI::twigBuffer('user/table.html.twig', [ + 'listing' => Listing::format($list, $certificates_list_data['sslcertificates_list']), +]); +UI::twigOutputBuffer(); diff --git a/templates/Froxlor/table/callbacks.html.twig b/templates/Froxlor/table/callbacks.html.twig index 7c4f3e8e..0258ad1d 100644 --- a/templates/Froxlor/table/callbacks.html.twig +++ b/templates/Froxlor/table/callbacks.html.twig @@ -18,19 +18,30 @@ {% endif %} {% endmacro %} +{% macro link(data) %} + {% apply spaceless %} + + {% if data.icon is defined %} + + {% endif %} + {% if data.text is defined %} + {{ data.text }} + {% endif %} + + {% endapply %} +{% endmacro %} + +{% macro domainWithSan(data) %} + {{ data.domain }} + {% if data.san is not empty %} +
SAN: {{ data.san }} + {% endif %} +{% endmacro %} + {% macro actions(data) %} {% for action in data %} {% if action.visible is not defined or action.visible is defined and action.visible %} - {% apply spaceless %} - - {% if action.icon is defined %} - - {% endif %} - {% if action.text is defined %} - {{ action.text }} - {% endif %} - - {% endapply %} + {{ _self.link(action) }} {% endif %} {% endfor %} {% endmacro %} diff --git a/templates/Froxlor/table/table.html.twig b/templates/Froxlor/table/table.html.twig index 60df5418..157ee887 100644 --- a/templates/Froxlor/table/table.html.twig +++ b/templates/Froxlor/table/table.html.twig @@ -13,31 +13,35 @@ {% endif %}
- +
- {% for column in listing.table.th %} - + {% for th in listing.table.th %} + {% endfor %} - {% for td in listing.table.tr %} - - {% for value in td %} - + {% for td in tr.td %} + {% endfor %} @@ -45,9 +49,11 @@ {% endfor %}
{{ column }}{{ th.text }}
- {% if value is iterable %} - {% if value.type == 'progressbar' %} - {{ callbacks.progressbar(value.data) }} - {% elseif value.type == 'boolean' %} - {{ callbacks.boolean(value.data) }} - {% elseif value.type == 'actions' %} - {{ callbacks.actions(value.data) }} + {% for tr in listing.table.tr %} +
+ {% if td.data is iterable %} + {% if td.data.type == 'progressbar' %} + {{ callbacks.progressbar(td.data.data) }} + {% elseif td.data.type == 'boolean' %} + {{ callbacks.boolean(td.data.data) }} + {% elseif td.data.type == 'link' %} + {{ callbacks.link(td.data.data) }} + {% elseif td.data.type == 'domainWithSan' %} + {{ callbacks.domainWithSan(td.data.data) }} + {% elseif td.data.type == 'actions' %} + {{ callbacks.actions(td.data.data) }} {% else %} - Callback '{{ value|json_encode }}' is not implemented! + Callback '{{ td|json_encode }}' is not implemented! {% endif %} {% else %} - {{ value|raw }} + {{ td.data|raw }} {% endif %}
- + {% if listing.pagination is not empty %} + + {% endif %}