Skip to content

Commit 2eac9c1

Browse files
committed
feat(Dashboard): import dashboard command
useful to recreate a damaged reporting dashboard
1 parent f7e1ad7 commit 2eac9c1

4 files changed

Lines changed: 246 additions & 1 deletion

File tree

‎setup.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ function plugin_carbon_setupHooks()
119119
$PLUGIN_HOOKS[Hooks::DASHBOARD_CARDS]['carbon'] = [Grid::class, 'getDashboardCards'];
120120
$PLUGIN_HOOKS[Hooks::DASHBOARD_TYPES]['carbon'] = [Widget::class, 'WidgetTypes'];
121121
// @phpstan-ignore-next-line
122-
if (version_compare(GLPI_VERSION, '11.0.8', '>')) {
122+
if (version_compare(GLPI_VERSION, '11.0.8', '>=')) {
123123
$PLUGIN_HOOKS[Hooks::DASHBOARD_DEFAULTS]['carbon'] = [Grid::class, 'getDefaults'];
124124
}
125125

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
/**
4+
* -------------------------------------------------------------------------
5+
* Carbon plugin for GLPI
6+
*
7+
* @copyright Copyright (C) 2024-2025 Teclib' and contributors.
8+
* @license https://www.gnu.org/licenses/gpl-3.0.txt GPLv3+
9+
* @link https://github.com/pluginsGLPI/carbon
10+
*
11+
* -------------------------------------------------------------------------
12+
*
13+
* LICENSE
14+
*
15+
* This file is part of Carbon plugin for GLPI.
16+
*
17+
* This program is free software: you can redistribute it and/or modify
18+
* it under the terms of the GNU General Public License as published by
19+
* the Free Software Foundation, either version 3 of the License, or
20+
* (at your option) any later version.
21+
*
22+
* This program is distributed in the hope that it will be useful,
23+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
24+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25+
* GNU General Public License for more details.
26+
*
27+
* You should have received a copy of the GNU General Public License
28+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
29+
*
30+
* -------------------------------------------------------------------------
31+
*/
32+
33+
namespace GlpiPlugin\Carbon\Command;
34+
35+
use Glpi\Dashboard\Dashboard as GlpiDashboard;
36+
use Override;
37+
use Symfony\Component\Console\Command\Command;
38+
use Symfony\Component\Console\Input\InputInterface;
39+
use Symfony\Component\Console\Output\OutputInterface;
40+
41+
class ImportDashboardCommand extends Command
42+
{
43+
private OutputInterface $output;
44+
45+
#[Override]
46+
protected function configure()
47+
{
48+
$this
49+
->setName('plugins:carbon:import_report_dashboard')
50+
->setDescription('imports the report dashboard description')
51+
->setHelp('This command imports the report dashboard description from a JSON file');
52+
}
53+
54+
#[Override]
55+
protected function execute(InputInterface $input, OutputInterface $output)
56+
{
57+
$this->output = $output;
58+
59+
$dashboard_key = 'plugin_carbon_board';
60+
$this->deleteDashboard($dashboard_key);
61+
$dashboard = new GlpiDashboard();
62+
$dashboard->add([
63+
'key' => $dashboard_key,
64+
'name' => __('Environmental impact', 'carbon'),
65+
'context' => 'mini_core',
66+
]);
67+
if (!$dashboard->resetToDefault($dashboard_key)) {
68+
$this->output->writeln("<error>Failed to reset the dashboard to default</error>");
69+
return Command::FAILURE;
70+
}
71+
72+
return Command::SUCCESS;
73+
}
74+
75+
private function deleteDashboard(string $dashboard_key)
76+
{
77+
$dashboard = new GlpiDashboard();
78+
$dashboard->getFromDB($dashboard_key);
79+
if ($dashboard->isNewItem()) {
80+
return;
81+
}
82+
$dashboard->delete($dashboard->fields);
83+
}
84+
}

‎src/Dashboard/Dashboard.php‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@
3636

3737
class Dashboard
3838
{
39+
/**
40+
* Key of the dashboard used by the plugin in its reporting page
41+
* @var string
42+
*/
43+
public const REPORTING_DASHBOARD_KEY = 'plugin_carbon_board';
44+
3945
/**
4046
* Returns total usage carbon emission per computer type.
4147
*
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
<?php
2+
3+
/**
4+
* -------------------------------------------------------------------------
5+
* Carbon plugin for GLPI
6+
*
7+
* @copyright Copyright (C) 2024-2025 Teclib' and contributors.
8+
* @license https://www.gnu.org/licenses/gpl-3.0.txt GPLv3+
9+
* @link https://github.com/pluginsGLPI/carbon
10+
*
11+
* -------------------------------------------------------------------------
12+
*
13+
* LICENSE
14+
*
15+
* This file is part of Carbon plugin for GLPI.
16+
*
17+
* This program is free software: you can redistribute it and/or modify
18+
* it under the terms of the GNU General Public License as published by
19+
* the Free Software Foundation, either version 3 of the License, or
20+
* (at your option) any later version.
21+
*
22+
* This program is distributed in the hope that it will be useful,
23+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
24+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25+
* GNU General Public License for more details.
26+
*
27+
* You should have received a copy of the GNU General Public License
28+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
29+
*
30+
* -------------------------------------------------------------------------
31+
*/
32+
33+
namespace GlpiPlugin\Carbon\Dashboard\Tests;
34+
35+
use DBmysql;
36+
use Glpi\Dashboard\Dashboard as GlpiDashboard;
37+
use Glpi\Dashboard\Item;
38+
use GlpiPlugin\Carbon\Command\ImportDashboardCommand;
39+
use GlpiPlugin\Carbon\Dashboard\Dashboard;
40+
use GlpiPlugin\Carbon\Tests\DbTestCase;
41+
use PHPUnit\Framework\Attributes\CoversClass;
42+
use Symfony\Component\Console\Input\ArrayInput;
43+
use Symfony\Component\Console\Output\NullOutput;
44+
45+
#[CoversClass(ImportDashboardCommand::class)]
46+
class ImportDashboardCommandTest extends DbTestCase
47+
{
48+
public function test_import_dashboard_command()
49+
{
50+
/**
51+
* @var DBmysql $DB
52+
*/
53+
global $DB;
54+
55+
$initial_dashboard = new GlpiDashboard(Dashboard::REPORTING_DASHBOARD_KEY);
56+
$initial_dashboard->load();
57+
$this->assertFalse($initial_dashboard->isNewItem());
58+
59+
$item_table = getTableForItemType(Item::class);
60+
$dashboard_table = getTableForItemType(GlpiDashboard::class);
61+
$result = $DB->request([
62+
'SELECT' => [
63+
$item_table => 'id',
64+
],
65+
'FROM' => $item_table,
66+
'INNER JOIN' => [
67+
$dashboard_table => [
68+
'ON' => [
69+
$dashboard_table => 'id',
70+
$item_table => 'dashboards_dashboards_id',
71+
],
72+
],
73+
],
74+
'WHERE' => [
75+
GlpiDashboard::getTableField('key') => Dashboard::REPORTING_DASHBOARD_KEY,
76+
],
77+
]);
78+
79+
// Traverse all items of the dashboard and arbitrary alter some of them
80+
foreach ($result as $row) {
81+
$item = Item::getById($row['id']);
82+
if ($item === false) {
83+
$this->fail("Failed to get dashboard item with id {$row['id']}");
84+
}
85+
switch ($row['id'] % 3) {
86+
case 0:
87+
// Drop the card options
88+
$item->update($item->fields + ['card_options' => '']);
89+
break;
90+
case 1:
91+
// Move the item to a different position and size, no matter there is collisions
92+
$item->update($item->fields + ['x' => '128', 'y' => '128', 'width' => '1', 'height' => '1']);
93+
break;
94+
case 2:
95+
// Do nothing
96+
break;
97+
}
98+
}
99+
100+
// Now import the dashboard again, it should reset all items to their default state
101+
$command = new ImportDashboardCommand();
102+
$command->run(new ArrayInput([]), new NullOutput());
103+
104+
// Initial dashboard has been deleted, the new one should have a different ID
105+
$new_dashboard = new GlpiDashboard(Dashboard::REPORTING_DASHBOARD_KEY);
106+
$new_dashboard->load();
107+
$this->assertFalse($initial_dashboard->isNewItem());
108+
$this->assertNotEquals($initial_dashboard->fields['id'], $new_dashboard->fields['id']);
109+
110+
// Compare the items against the JSON definition of the dashboard, they should be identical
111+
$dashboard_json_path = __DIR__ . '/../../../install/data/report_dashboard.json';
112+
$dashboard_json = json_decode(file_get_contents($dashboard_json_path), true);
113+
$result = $DB->request([
114+
'SELECT' => [
115+
$item_table => 'id',
116+
],
117+
'FROM' => $item_table,
118+
'INNER JOIN' => [
119+
$dashboard_table => [
120+
'ON' => [
121+
$dashboard_table => 'id',
122+
$item_table => 'dashboards_dashboards_id',
123+
],
124+
],
125+
],
126+
'WHERE' => [
127+
GlpiDashboard::getTableField('key') => Dashboard::REPORTING_DASHBOARD_KEY,
128+
],
129+
]);
130+
foreach ($result as $row) {
131+
$item = Item::getById($row['id']);
132+
if ($item === false) {
133+
$this->fail("Failed to get dashboard item with id {$row['id']}");
134+
}
135+
$item_fields = array_filter($item->fields, function ($key) {
136+
return !in_array($key, ['id', 'dashboards_dashboards_id']);
137+
}, ARRAY_FILTER_USE_KEY);
138+
$item_fields['card_options'] = json_decode($item_fields['card_options'], true);
139+
$found = false;
140+
foreach ($dashboard_json as $json_item) {
141+
if ($json_item['card_id'] === $item_fields['card_id']) {
142+
$found = true;
143+
$this->assertEqualsCanonicalizing($json_item, $item_fields);
144+
break;
145+
}
146+
}
147+
if (!$found) {
148+
$this->fail("Dashboard item with card_id {$item_fields['card_id']} not found in JSON definition");
149+
}
150+
}
151+
152+
// Assert counts of items match
153+
$this->assertEquals(count($dashboard_json), count($result));
154+
}
155+
}

0 commit comments

Comments
 (0)