Skip to content

Commit

Permalink
Administration system information page (#1035)
Browse files Browse the repository at this point in the history
* feat: admin sysinfo

* fix: ConfigControllerTest::testBeforeFilter

* feat: api info from endpoint, if available

* chore fix: phpcs + tests

* chore fix: better coverage

* chore fix: rename keys

* chore feat: notice about API

* chore fix: notice style

* refactor: rename to SystemInfo

* fix: SystemInfoControllerTest

* fix: SystemInfoControllerTest

* fix: use admin sysinfo endpoint
  • Loading branch information
didoda authored Aug 2, 2023
1 parent e69c39d commit 874aa50
Show file tree
Hide file tree
Showing 9 changed files with 297 additions and 4 deletions.
17 changes: 15 additions & 2 deletions config/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,21 @@

// Admin.
$routes->prefix('admin', ['_namePrefix' => 'admin:'], function (RouteBuilder $routes) {

foreach (['appearance', 'applications', 'async_jobs', 'config', 'endpoints', 'roles', 'roles_modules', 'endpoint_permissions', 'objects_history', 'user_accesses'] as $controller) {
$adminRoutes = [
'appearance',
'applications',
'async_jobs',
'config',
'endpoints',
'roles',
'roles_modules',
'endpoint_permissions',
'objects_history',
'user_accesses',
'system_info',
];

foreach ($adminRoutes as $controller) {
// Routes connected here are prefixed with '/admin'
$name = Inflector::camelize($controller);
$routes->get(
Expand Down
1 change: 1 addition & 0 deletions resources/js/app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ const _vueInstance = new Vue({
Permissions:() => import(/* webpackChunkName: "permissions" */'app/components/permissions/permissions'),
PaginationNavigation:() => import(/* webpackChunkName: "pagination-navigation" */'app/components/pagination-navigation/pagination-navigation'),
ObjectsHistory:() => import(/* webpackChunkName: "objects-history" */'app/components/objects-history/objects-history'),
SystemInfo:() => import(/* webpackChunkName: "system-info" */'app/components/system-info/system-info'),
UserAccesses:() => import(/* webpackChunkName: "user-accesses" */'app/components/user-accesses/user-accesses'),
Icon,
},
Expand Down
45 changes: 45 additions & 0 deletions resources/js/app/components/system-info/system-info.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<template>
<div>
<p v-for="item,key of infos">
<span class="key">{{ key }}</span>:
<span class="version">{{ item }}</span>
</p>
</div>
</template>
<script>
import Vue from 'vue';
export default {
name: 'SystemInfo',
props: {
data: {
type: String,
default: '',
},
},
data() {
return {
infos: {},
}
},
mounted() {
this.$nextTick(() => {
this.infos = JSON.parse(this.data) || {};
if (this.infos['Vuejs'] !== undefined) {
this.infos['Vuejs'] = Vue.version;
}
});
},
}
</script>
<style>
span.key {
font-style: italic;
color: yellow;
}
span.version {
font-family: 'Courier New', Courier, monospace;
}
</style>
82 changes: 82 additions & 0 deletions src/Controller/Admin/SystemInfoController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php
/**
* BEdita, API-first content management framework
* Copyright 2023 Atlas Srl, Chialab Srl
*
* This file is part of BEdita: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* See LICENSE.LGPL or <http://gnu.org/licenses/lgpl-3.0.html> for more details.
*/
namespace App\Controller\Admin;

use BEdita\SDK\BEditaClientException;
use Cake\Core\Configure;
use Cake\Http\Response;
use Cake\Utility\Hash;
use Twig\Environment;

/**
* System info Controller
*/
class SystemInfoController extends AdministrationBaseController
{
/**
* @inheritDoc
*/
public function index(): ?Response
{
$this->set('system_info', $this->getSystemInfo());
$this->set('api_info', $this->getApiInfo());

return null;
}

/**
* Get system info.
*
* @return array
*/
public function getSystemInfo(): array
{
return [
'Version' => Configure::read('Manager.version'),
'CakePHP' => Configure::version(),
'PHP' => phpversion(),
'Twig' => Environment::VERSION,
'Vuejs' => '',
'Operating System' => php_uname(),
'PHP Server API' => php_sapi_name(),
'Extensions' => get_loaded_extensions(),
'Extensions info' => get_loaded_extensions(true),
'Memory limit' => ini_get('memory_limit'),
'Post max size' => sprintf('%dM', intVal(substr(ini_get('post_max_size'), 0, -1))),
'Upload max size' => sprintf('%dM', intVal(substr(ini_get('upload_max_filesize'), 0, -1))),
];
}

/**
* Get api info from API server.
*
* @return array
*/
public function getApiInfo(): array
{
$info = [
'Url' => Configure::read('API.apiBaseUrl'),
'Version' => Hash::get((array)$this->viewBuilder()->getVar('project'), 'version'),
];
try {
$info = (array)Hash::get(
$this->apiClient->get('/admin/sysinfo'),
'meta.info'
);
} catch (BEditaClientException $e) {
$this->log($e->getMessage(), 'error');
}

return $info;
}
}
1 change: 1 addition & 0 deletions src/View/Helper/LayoutHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ protected function commandLinkClass(): string
'EndpointPermissions' => 'has-background-black',
'Tags' => 'has-background-module-tags',
'ObjectsHistory' => 'has-background-black',
'SystemInfo' => 'has-background-black',
'UserAccesses' => 'has-background-black',
];

Expand Down
14 changes: 13 additions & 1 deletion templates/Element/Admin/sidebar.twig
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
{# Append urls to sidebar #}
{% set actions = ['appearance', 'applications', 'endpoints', 'endpoint_permissions', 'roles', 'roles_modules', 'config', 'async_jobs', 'objects_history', 'user_accesses'] %}
{% set actions = [
'appearance',
'applications',
'endpoints',
'endpoint_permissions',
'roles',
'roles_modules',
'config',
'async_jobs',
'objects_history',
'user_accesses',
'system_info',
] %}
{% set controllerAction = _view.request.getparam('controller')|default('') %}
{% for action in actions %}
{% if action == controllerAction|underscore %}
Expand Down
19 changes: 19 additions & 0 deletions templates/Pages/Admin/SystemInfo/index.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{{ element('Admin/sidebar') }}

{% do _view.assign('title', __('Administration') ~ ' ' ~ __('System information')) %}
{% do _view.assign('bodyViewClass', 'view-module view-admin') %}

<h2>BEdita Manager</h2>

<system-info data="{{system_info|json_encode}}">
</system-info>

<h2 class="mt-15">API</h2>

<p class="mb-1">
<Icon icon="carbon:information"></Icon>
{{ __('API could be distributed in multiple nodes. The following data refers to a single node') }}
</p>

<system-info data="{{api_info|json_encode}}">
</system-info>
2 changes: 1 addition & 1 deletion tests/TestCase/Controller/Admin/ConfigControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,6 @@ public function testBeforeFilter(): void
$event = $this->CfgController->dispatchEvent('Controller.beforeFilter');
$this->CfgController->beforeFilter($event);
$viewVars = (array)$this->CfgController->viewBuilder()->getVars();
static::assertEquals(['' => __('No application'), 1 => 'default-app', 2 => 'manager'], $viewVars['applications']);
static::assertContains('manager', $viewVars['applications']);
}
}
120 changes: 120 additions & 0 deletions tests/TestCase/Controller/Admin/SystemInfoControllerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?php
namespace App\Test\TestCase\Controller\Admin;

use App\Controller\Admin\SystemInfoController;
use BEdita\WebTools\ApiClientProvider;
use Cake\Http\ServerRequest;
use Cake\TestSuite\TestCase;

/**
* {@see \App\Controller\Admin\SystemInfoController} Test Case
*
* @coversDefaultClass \App\Controller\Admin\SystemInfoController
*/
class SystemInfoControllerTest extends TestCase
{
public $SystemInfoController;

/**
* Test request config
*
* @var array
*/
public $defaultRequestConfig = [
'environment' => [
'REQUEST_METHOD' => 'GET',
],
'params' => [
'resource_type' => 'applications',
],
];

/**
* API client
*
* @var \BEdita\SDK\BEditaClient
*/
protected $client;

/**
* @inheritDoc
*/
public function setUp(): void
{
parent::setUp();

$config = array_merge($this->defaultRequestConfig, []);
$request = new ServerRequest($config);
$this->SystemInfoController = new SystemInfoController($request);
$this->client = ApiClientProvider::getApiClient();
$adminUser = getenv('BEDITA_ADMIN_USR');
$adminPassword = getenv('BEDITA_ADMIN_PWD');
$response = $this->client->authenticate($adminUser, $adminPassword);
$this->client->setupTokens($response['meta']);
}

/**
* Test `index` method
*
* @return void
* @covers ::index()
*/
public function testIndex(): void
{
$this->SystemInfoController->index();
$keys = [
'system_info',
'api_info',
];
$viewVars = (array)$this->SystemInfoController->viewBuilder()->getVars();
foreach ($keys as $expectedKey) {
static::assertArrayHasKey($expectedKey, $viewVars);
}
}

/**
* Test `getSystemInfo` method
*
* @return void
* @covers ::getSystemInfo()
*/
public function testGetSystemInfo(): void
{
$expectedKeys = [
'Version',
'CakePHP',
'PHP',
'Twig',
'Vuejs',
'Operating System',
'PHP Server API',
'Extensions',
'Extensions info',
'Memory limit',
'Post max size',
'Upload max size',
];
$actual = $this->SystemInfoController->getSystemInfo();
foreach ($expectedKeys as $expectedKey) {
static::assertArrayHasKey($expectedKey, $actual);
}
}

/**
* Test `getApiInfo` method
*
* @return void
* @covers ::getApiInfo()
*/
public function testGetApiInfo(): void
{
$expectedKeys = [
'Url',
'Version',
];
$actual = $this->SystemInfoController->getApiInfo();
foreach ($expectedKeys as $expectedKey) {
static::assertArrayHasKey($expectedKey, $actual);
}
}
}

0 comments on commit 874aa50

Please sign in to comment.