diff --git a/config/routes.php b/config/routes.php index f7580c944..d5433e051 100644 --- a/config/routes.php +++ b/config/routes.php @@ -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( diff --git a/resources/js/app/app.js b/resources/js/app/app.js index b9e8c8874..4ec2b2e56 100644 --- a/resources/js/app/app.js +++ b/resources/js/app/app.js @@ -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, }, diff --git a/resources/js/app/components/system-info/system-info.vue b/resources/js/app/components/system-info/system-info.vue new file mode 100644 index 000000000..3f59052b7 --- /dev/null +++ b/resources/js/app/components/system-info/system-info.vue @@ -0,0 +1,45 @@ + + + diff --git a/src/Controller/Admin/SystemInfoController.php b/src/Controller/Admin/SystemInfoController.php new file mode 100644 index 000000000..74069e358 --- /dev/null +++ b/src/Controller/Admin/SystemInfoController.php @@ -0,0 +1,82 @@ + 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; + } +} diff --git a/src/View/Helper/LayoutHelper.php b/src/View/Helper/LayoutHelper.php index 531f9a2f5..b1ce4dbee 100644 --- a/src/View/Helper/LayoutHelper.php +++ b/src/View/Helper/LayoutHelper.php @@ -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', ]; diff --git a/templates/Element/Admin/sidebar.twig b/templates/Element/Admin/sidebar.twig index 8a40f23a1..f5f2ddf99 100644 --- a/templates/Element/Admin/sidebar.twig +++ b/templates/Element/Admin/sidebar.twig @@ -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 %} diff --git a/templates/Pages/Admin/SystemInfo/index.twig b/templates/Pages/Admin/SystemInfo/index.twig new file mode 100644 index 000000000..b7b6b5fa7 --- /dev/null +++ b/templates/Pages/Admin/SystemInfo/index.twig @@ -0,0 +1,19 @@ +{{ element('Admin/sidebar') }} + +{% do _view.assign('title', __('Administration') ~ ' ' ~ __('System information')) %} +{% do _view.assign('bodyViewClass', 'view-module view-admin') %} + +

BEdita Manager

+ + + + +

API

+ +

+ + {{ __('API could be distributed in multiple nodes. The following data refers to a single node') }} +

+ + + diff --git a/tests/TestCase/Controller/Admin/ConfigControllerTest.php b/tests/TestCase/Controller/Admin/ConfigControllerTest.php index a3287c24f..e7d5473cf 100644 --- a/tests/TestCase/Controller/Admin/ConfigControllerTest.php +++ b/tests/TestCase/Controller/Admin/ConfigControllerTest.php @@ -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']); } } diff --git a/tests/TestCase/Controller/Admin/SystemInfoControllerTest.php b/tests/TestCase/Controller/Admin/SystemInfoControllerTest.php new file mode 100644 index 000000000..7fccfa40b --- /dev/null +++ b/tests/TestCase/Controller/Admin/SystemInfoControllerTest.php @@ -0,0 +1,120 @@ + [ + '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); + } + } +}