Added an page to view infos about the server (Part-DB, PHP and DB config

This commit is contained in:
Jan Böhmer 2022-11-06 01:07:10 +01:00
parent 78d1dff40f
commit 34fbcec00f
10 changed files with 1287 additions and 1018 deletions

View file

@ -206,6 +206,8 @@ perms: # Here comes a list with all Permission names (they have a perm_[name] co
delete_logs:
label: "perm.delete_logs"
alsoSet: 'show_logs'
server_infos:
label: "perm.server_infos"
attachments:
label: "perm.part.attachments"

View file

@ -2,6 +2,9 @@
namespace App\Controller;
use App\Services\GitVersionInfo;
use App\Services\Misc\DBInfoHelper;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
@ -20,4 +23,47 @@ class ToolsController extends AbstractController
return $this->render('Tools/ReelCalculator/main.html.twig');
}
/**
* @Route("/server_infos", name="tools_server_infos")
*/
public function systemInfos(GitVersionInfo $versionInfo, DBInfoHelper $DBInfoHelper): Response
{
$this->denyAccessUnlessGranted('@system.server_infos');
return $this->render('Tools/ServerInfos/main.html.twig', [
//Part-DB section
'git_branch' => $versionInfo->getGitBranchName(),
'git_commit' => $versionInfo->getGitCommitHash(),
'default_locale' => $this->getParameter('partdb.locale'),
'default_timezone' => $this->getParameter('partdb.timezone'),
'default_currency' => $this->getParameter('partdb.default_currency'),
'default_theme' => $this->getParameter('partdb.global_theme'),
'enabled_locales' => $this->getParameter('partdb.locale_menu'),
'demo_mode' => $this->getParameter('partdb.demo_mode'),
'gpdr_compliance' => $this->getParameter('partdb.gpdr_compliance'),
'use_gravatar' => $this->getParameter('partdb.users.use_gravatar'),
'email_password_reset' => $this->getParameter('partdb.users.email_pw_reset'),
'enviroment' => $this->getParameter('kernel.environment'),
'is_debug' => $this->getParameter('kernel.debug'),
'email_sender' => $this->getParameter('partdb.mail.sender_email'),
'email_sender_name' => $this->getParameter('partdb.mail.sender_name'),
'allow_attachments_downloads' => $this->getParameter('partdb.attachments.allow_downloads'),
'detailed_error_pages' => $this->getParameter('partdb.error_pages.show_help'),
'error_page_admin_email' => $this->getParameter('partdb.error_pages.admin_email'),
//PHP section
'php_version' => PHP_VERSION,
'php_uname' => php_uname('a'),
'php_sapi' => PHP_SAPI,
'php_extensions' => array_merge(get_loaded_extensions(), get_loaded_extensions(true)),
'php_opcache_enabled' => ini_get('opcache.enable'),
'php_upload_max_filesize' => ini_get('upload_max_filesize'),
'php_post_max_size' => ini_get('post_max_size'),
//DB section
'db_type' => $DBInfoHelper->getDatabaseType() ?? 'Unknown',
'db_version' => $DBInfoHelper->getDatabaseVersion() ?? 'Unknown',
]);
}
}

View file

@ -0,0 +1,58 @@
<?php
namespace App\Services\Misc;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Platforms\AbstractMySQLPlatform;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\ORM\EntityManagerInterface;
/**
* This service provides db independent information about the database.
*/
class DBInfoHelper
{
protected Connection $connection;
protected EntityManagerInterface $entityManager;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
$this->connection = $entityManager->getConnection();
}
/**
* Returns the database type of the used database.
* @return string|null Returns 'mysql' for MySQL/MariaDB and 'sqlite' for SQLite. Returns null if unknown type
*/
public function getDatabaseType(): ?string
{
if ($this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform) {
return 'mysql';
}
if ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) {
return 'sqlite';
}
return null;
}
/**
* Returns the database version of the used database.
* @return string|null
* @throws \Doctrine\DBAL\Exception
*/
public function getDatabaseVersion(): ?string
{
if ($this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform) {
return $this->connection->fetchOne('SELECT VERSION()');
}
if ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) {
return $this->connection->fetchOne('SELECT sqlite_version()');
}
return null;
}
}

View file

@ -291,6 +291,13 @@ class ToolsTreeBuilder
))->setIcon('fa-fw fa-treeview fa-solid fa-binoculars');
}
if ($this->security->isGranted('@system.server_infos')) {
$nodes[] = (new TreeViewNode(
$this->translator->trans('tools.server_infos.title'),
$this->urlGenerator->generate('tools_server_infos')
))->setIcon('fa-fw fa-treeview fa-solid fa-database');
}
return $nodes;
}
}

View file

@ -0,0 +1,13 @@
{% import "helper.twig" as helper %}
<table class="table table-sm table-striped table-hover table-bordered">
<tbody>
<tr>
<td>Database type</td>
<td>{{ db_type }}</td>
</tr>
<tr>
<td>Database Server Version</td>
<td>{{ db_version }}</td>
</tr>
</tbody>
</table>

View file

@ -0,0 +1,66 @@
{% import "helper.twig" as helper %}
<table class="table table-sm table-striped table-hover table-bordered">
<tbody>
<tr>
<td>Part-DB Version</td>
<td>{{ shivas_app_version }} {% if git_branch is not empty or git_commit is not empty %}({{ git_branch ?? '' }}/{{ git_commit ?? '' }}){% endif %}</td>
</tr>
<tr>
<td>Symfony environment</td>
<td>{{ enviroment }} (Debug: {{ helper.boolean_badge(is_debug) }})</td>
</tr>
<tr>
<td>Part-DB Instance name</td>
<td>{{ partdb_title }}</td>
</tr>
<tr>
<td>Default locale</td>
<td>{{ default_locale | locale_name }} ({{ default_locale }})</td>
</tr>
<tr>
<td>Default timezone</td>
<td>{{ default_timezone }}</td>
</tr>
<tr>
<td>Default Currency</td>
<td>{{ default_currency | currency_name }} ({{ default_currency }}, {{ default_currency | currency_symbol }})</td>
</tr>
<tr>
<td>Default theme</td>
<td>{{ default_theme | default('bootstrap') }}</td>
</tr>
<tr>
<td>Enabled locales</td>
<td>{{ helper.array_to_tags(enabled_locales | map(l => "#{l|locale_name} (#{l})")) }}</td>
</tr>
<tr>
<td>Demo Mode</td>
<td>{{ helper.boolean_badge(demo_mode) }}</td>
</tr>
<tr>
<td>GPDR Compliance Mode</td>
<td>{{ helper.boolean_badge(gpdr_compliance) }}</td>
</tr>
<tr>
<td>Use Gravatar</td>
<td>{{ helper.boolean_badge(use_gravatar) }}</td>
</tr>
<tr>
<td>Password Reset via Email enabled</td>
<td>{{ helper.boolean_badge(email_password_reset) }}</td>
</tr>
<tr>
<td>Configured E-Mail sender</td>
<td>{{ email_sender }} ({{ email_sender_name }})</td>
</tr>
<tr>
<td>Allow server-side download of attachments</td>
<td>{{ helper.boolean_badge(allow_attachments_downloads) }}</td>
</tr>
<tr>
<td>Detailed error pages enabled</td>
<td>{{ helper.boolean_badge(detailed_error_pages) }} (Admin Contact email: {{ error_page_admin_email }})</td>
</tr>
</tbody>
</table>

View file

@ -0,0 +1,25 @@
{% import "helper.twig" as helper %}
<table class="table table-sm table-striped table-hover table-bordered">
<tbody>
<tr>
<td>PHP version</td>
<td>{{ php_version }} (SAPI: {{ php_sapi }})</td>
</tr>
<tr>
<td>Server Operating System</td>
<td>{{ php_uname }}</td>
</tr>
<tr>
<td>Opcache enabled</td>
<td>{{ helper.boolean_badge(php_opcache_enabled) }}</td>
</tr>
<tr>
<td>Maximum upload sizee (upload_max_filesize / post_max_size)</td>
<td>{{ php_upload_max_filesize }} / {{ php_post_max_size }}</td>
</tr>
<tr>
<td>PHP extensions</td>
<td>{{ helper.array_to_tags(php_extensions) }}</td>
</tr>
</tbody>
</table>

View file

@ -0,0 +1,30 @@
{% extends "main_card.html.twig" %}
{% block title %}{% trans %}tools.server_infos.title{% endtrans %}{% endblock %}
{% block card_title %}
<i class="fas fa-database"></i> {% trans %}tools.server_infos.title{% endtrans %}
{% endblock %}
{% block card_content %}
<nav>
<div class="nav nav-tabs" id="nav-tab" role="tablist">
<button class="nav-link active" id="server_infos-partdb-tab" data-bs-toggle="tab" data-bs-target="#server_infos-partdb" type="button" role="tab" aria-controls="server_infos-partdb" aria-selected="true">Part-DB</button>
<button class="nav-link" id="server_infos-php-tab" data-bs-toggle="tab" data-bs-target="#server_infos-php" type="button" role="tab" aria-controls="server_infos-php" aria-selected="false">PHP</button>
<button class="nav-link" id="server_infos-database-tab" data-bs-toggle="tab" data-bs-target="#server_infos-db" type="button" role="tab" aria-controls="server_infos-db" aria-selected="false">Database</button>
</div>
</nav>
<div class="tab-content" id="nav-tabContent">
<div class="tab-pane fade show active" id="server_infos-partdb" role="tabpanel" aria-labelledby="server_infos-partdb-tab">
{% include "Tools/ServerInfos/_partdb.html.twig" %}
</div>
<div class="tab-pane fade" id="server_infos-php" role="tabpanel" aria-labelledby="server_infos-php-tab">
{% include "Tools/ServerInfos/_php.html.twig" %}
</div>
<div class="tab-pane fade" id="server_infos-db" role="tabpanel" aria-labelledby="server_infos-database-tab">
{% include "Tools/ServerInfos/_db.html.twig" %}
</div>
</div>
<p>Run <code>php bin/console partdb:check-requirements</code> in a terminal in your Part-DB folder to check if there are any recommendations for your system configuration.</p>
{% endblock %}

View file

@ -6,6 +6,30 @@
{% endif %}
{% endmacro %}
{% macro array_to_tags(tags, class="badge bg-primary") %}
{% for tag in tags %}
<span class="{{ class }}">{{ tag | trim }}</span>
{% endfor %}
{% endmacro %}
{% macro bool_icon(bool) %}
{% if bool %}
<i class="fas fa-check-circle fa-fw" title="{% trans %}Yes{% endtrans %}"></i>
{% else %}
<i class="fas fa-times-circle fa-fw" title="{% trans %}No{% endtrans %}"></i>
{% endif %}
{% endmacro %}
{% macro boolean_badge(value, class="badge") %}
{% if value %}
{% set class = class ~ ' bg-success' %}
{% else %}
{% set class = class ~ ' bg-danger' %}
{% endif %}
<span class="{{ class }}">{{ _self.bool_icon(value) }} {{ _self.boolean(value) }}</span>
{% endmacro %}
{% macro string_to_tags(string, class="badge bg-info") %}
{% for tag in string|split(',') %}
<a href="{{ path('part_list_tags', {'tag': tag | trim | url_encode}) }}" class="{{ class }}" >{{ tag | trim }}</a>
@ -106,14 +130,6 @@
</nav>
{% endmacro %}
{% macro bool_icon(bool) %}
{% if bool %}
<i class="fas fa-check-circle fa-fw" title="{% trans %}Yes{% endtrans %}"></i>
{% else %}
<i class="fas fa-times-circle fa-fw" title="{% trans %}No{% endtrans %}"></i>
{% endif %}
{% endmacro %}
{% macro date_user_combination(entity, lastModified, datetime_format = "short") %}
{% if lastModified == true %}
{{ entity.lastModified | format_datetime(datetime_format) }}

File diff suppressed because it is too large Load diff