diff --git a/CHANGELOG.md b/CHANGELOG.md index 1421c94..1802957 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added +- Display GLPI 11 Custom Assets in the location tree + +### Fixed + +- Prevent custom assets from other asset definitions from appearing in the same location - Add Transifex translations link to README ## [1.21.0] - 2026-09-07 diff --git a/composer.json b/composer.json index 8136bf0..31aedaa 100644 --- a/composer.json +++ b/composer.json @@ -3,6 +3,7 @@ "php": ">=8.2" }, "config": { + "autoloader-suffix": "PluginTreeview", "optimize-autoloader": true, "autoloader-suffix": "PluginTreeview", "platform": { diff --git a/inc/config.class.php b/inc/config.class.php index 6e024da..5c46dad 100644 --- a/inc/config.class.php +++ b/inc/config.class.php @@ -27,14 +27,17 @@ * @link https://github.com/pluginsGLPI/treeview * ------------------------------------------------------------------------- */ + use Glpi\Application\View\TemplateRenderer; +use Glpi\Asset\Asset; +use Glpi\Asset\AssetDefinitionManager; use Glpi\DBAL\QueryExpression; use function Safe\json_encode; /** * Contains the display configuration of the treeview -**/ + **/ class PluginTreeviewConfig extends CommonDBTM { public static $types = [ @@ -52,10 +55,10 @@ class PluginTreeviewConfig extends CommonDBTM ]; /** - * Display name of itemtype - * - * @return string - **/ + * Display name of itemtype + * + * @return string + **/ public static function getTypeName($nb = 0) { return __s('Tree view', 'treeview'); @@ -128,6 +131,11 @@ public static function getTypes($all = false) // Only allowed types $types = self::$types; + $types = array_merge( + $types, + AssetDefinitionManager::getInstance()->getCustomObjectClassNames(), + ); + foreach ($types as $key => $type) { if (!class_exists($type) || !is_a($type, CommonDBTM::class, true)) { continue; @@ -336,6 +344,10 @@ public function getNodesFromDb() 'ORDER' => [$itemtable . '.name'], ]; + if (is_a($type, Asset::class, true)) { + $criteria['WHERE']['assets_assetdefinitions_id'] = $type::getDefinition()->fields['id']; + } + if ($item->maybeTemplate()) { $criteria['WHERE']['is_template'] = 0; } @@ -367,7 +379,9 @@ public function getNodesFromDb() $value = $r['id']; $getParam = sprintf('?is_deleted=0&criteria[0][field]=%d&criteria[0][searchtype]=equals&criteria[0][value]=%s&search=Rechercher&start=0', $field_num, $value); - $searchUrl = Toolbox::getItemTypeSearchURL($type) . $getParam; + $searchUrl = is_a($type, Asset::class, true) + ? $type::getSearchURL() . '&' . ltrim($getParam, '?') + : Toolbox::getItemTypeSearchURL($type) . $getParam; $params = ['itemtype' => $type, 'locations_id' => $value, @@ -413,7 +427,8 @@ public function getNodesFromDb() } } - $url = Toolbox::getItemTypeFormURL($type) . '?id=' . $r_1['id']; + $url = $type::getFormURLWithID($r_1['id']); + $pic = 'ti ti-chevrons-right'; $name = strtr($i_name, $trans); $opt = ['url' => $url, diff --git a/tests/Units/ConfigTest.php b/tests/Units/ConfigTest.php index d6b673f..eb31b8d 100644 --- a/tests/Units/ConfigTest.php +++ b/tests/Units/ConfigTest.php @@ -32,8 +32,10 @@ use Computer; use Entity; +use Glpi\Asset\AssetDefinitionManager; use GlpiPlugin\Treeview\Tests\TreeviewTestCase; use Location; +use PluginTreeviewConfig; use Session; final class ConfigTest extends TreeviewTestCase @@ -132,8 +134,13 @@ public function testGetNodesFromDbHidesItemtypeWithoutViewRight(): void 'locations_id' => $location->getID(), ]); - // remove all rights to view computers - $this->removeRightFromProfile('Super-Admin', Computer::$rightname, READ + READ_ASSIGNED + READ_OWNED); + // Remove all rights to view computers. + $this->removeRightFromProfile( + 'Super-Admin', + Computer::$rightname, + READ + READ_ASSIGNED + READ_OWNED, + ); + try { $this->login('glpi'); $this->setEntity($entity_id, false); @@ -141,7 +148,74 @@ public function testGetNodesFromDbHidesItemtypeWithoutViewRight(): void $this->assertStringNotContainsString($computer->fields['name'], $output); } finally { - $this->addRightToProfile('Super-Admin', Computer::$rightname, READ + READ_ASSIGNED + READ_OWNED); + $this->addRightToProfile( + 'Super-Admin', + Computer::$rightname, + READ + READ_ASSIGNED + READ_OWNED, + ); } } + + public function testGetNodesFromDbDoesNotMixAssetDefinitions(): void + { + $this->login(); + $entity_id = $this->getTestRootEntity(true); + $profile_id = $_SESSION['glpiactiveprofile']['id']; + + $location = $this->createItem(Location::class, [ + 'name' => 'treeview_asset_loc_' . $this->getUniqueString(), + 'entities_id' => $entity_id, + ]); + + $definition_a = $this->initAssetDefinition( + 'treeview_a_' . $this->getUniqueString(), + profiles: [$profile_id => READ], + ); + $definition_b = $this->initAssetDefinition( + 'treeview_b_' . $this->getUniqueString(), + profiles: [$profile_id => READ], + ); + + $asset_a = $this->createItem($definition_a->getAssetClassName(), [ + 'name' => 'treeview_asset_a_' . $this->getUniqueString(), + 'entities_id' => $entity_id, + 'locations_id' => $location->getID(), + ]); + $asset_b = $this->createItem($definition_b->getAssetClassName(), [ + 'name' => 'treeview_asset_b_' . $this->getUniqueString(), + 'entities_id' => $entity_id, + 'locations_id' => $location->getID(), + ]); + + // Refresh the definition manager so that the newly created + // definitions are available to TreeView. + $manager = AssetDefinitionManager::getInstance(); + $manager->clearDefinitionsCache(); + $manager->bootDefinitions(); + + // Definition creation stores rights in the database. Reload the + // current profile so that canView() sees these new rights in session. + Session::changeProfile($profile_id); + $this->setEntity($entity_id, false); + + $this->assertTrue($asset_a::canView()); + $this->assertTrue($asset_b::canView()); + $this->assertContains($definition_a->getAssetClassName(), PluginTreeviewConfig::getTypes()); + $this->assertContains($definition_b->getAssetClassName(), PluginTreeviewConfig::getTypes()); + + $output = $this->getTreeOutput($location->getID()); + + // Both assets share the same database table. Each asset must only + // appear in the tree group corresponding to its own definition. + // Without the assets_assetdefinitions_id filter, each asset would + // appear twice. + $this->assertSame( + 1, + substr_count($output, $asset_a->fields['name']), + ); + $this->assertSame( + 1, + substr_count($output, $asset_b->fields['name']), + ); + } }