diff --git a/CHANGELOG.md b/CHANGELOG.md index 9779874c..75fad669 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - Fix search criterion value on multiple dropdown fields being reset after a search, which emptied the criterion when sorting or paging results +- Fix Data Injection models mapping additional fields becoming inaccessible with a "You don't have permission" error ## [1.24.7] - 2026-10-28 diff --git a/templates/injection.class.tpl b/templates/injection.class.tpl index 9568df20..aff54e1d 100644 --- a/templates/injection.class.tpl +++ b/templates/injection.class.tpl @@ -21,6 +21,24 @@ class %%CLASSNAME%%Injection extends %%CLASSNAME%% implements PluginDatainjectio return $itemtype::getTypeName($nb) . " - " . $container_name; } + /** + * Injecting fields values means updating the parent item, so the same rules + * as the item form apply: update right on the itemtype and write right on the container. + * The update right on the targeted item itself is checked by CommonDBChild. + */ + static function canCreate(): bool { + $itemtype = %%ITEMTYPE%%; + return $itemtype::canUpdate() + && PluginFieldsProfile::getRightOnContainer( + (int) ($_SESSION['glpiactiveprofile']['id'] ?? 0), + (int) %%CONTAINER_ID%% + ) > READ; + } + + static function canUpdate(): bool { + return static::canCreate(); + } + /** * Tells datainjection if the type is a primary type or not * diff --git a/tests/Units/ContainerItemRightTest.php b/tests/Units/ContainerItemRightTest.php index 4a1bf888..e1daf276 100644 --- a/tests/Units/ContainerItemRightTest.php +++ b/tests/Units/ContainerItemRightTest.php @@ -86,6 +86,43 @@ public function testCanUpdateTargetItemFollowsRightOnItem(): void $this->assertFalse(PluginFieldsContainer::canUpdateTargetItem(Computer::class, $computer->getID())); } + public function testInjectionClassFollowsParentItemtypeUpdateRight(): void + { + if (!interface_exists('PluginDatainjectionInjectionInterface')) { + require_once __DIR__ . '/../fixtures/datainjection_stubs.php'; + } + + $entity_id = getItemByTypeName(Entity::class, '_test_root_entity', true); + $this->setEntity($entity_id, true); + + $container = $this->createFieldContainer([ + 'label' => 'Injection container ' . $this->getUniqueString(), + 'type' => 'dom', + 'itemtypes' => [Computer::class], + 'is_active' => 1, + 'entities_id' => $entity_id, + 'is_recursive' => 1, + ]); + $classname = PluginFieldsContainer::getClassname(Computer::class, $container->fields['name'], 'Injection'); + + // Datainjection requires these rights to display and run a model mapping the container + $this->assertTrue($classname::canCreate()); + $this->assertTrue($classname::canUpdate()); + + // A read-only container must not be writable through injection + PluginFieldsProfile::updateProfile([ + 'plugin_fields_containers_id' => $container->getID(), + 'rights' => [$_SESSION['glpiactiveprofile']['id'] => READ], + ]); + $this->assertFalse($classname::canCreate()); + $this->assertFalse($classname::canUpdate()); + + $this->login('post-only', 'postonly'); + + $this->assertFalse($classname::canCreate()); + $this->assertFalse($classname::canUpdate()); + } + public function testCanUpdateTargetItemRejectsInvalidItemtype(): void { $this->login(); diff --git a/tests/fixtures/datainjection_stubs.php b/tests/fixtures/datainjection_stubs.php new file mode 100644 index 00000000..94fedde7 --- /dev/null +++ b/tests/fixtures/datainjection_stubs.php @@ -0,0 +1,43 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2013-2023 by Fields plugin team. + * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html + * @link https://github.com/pluginsGLPI/fields + * ------------------------------------------------------------------------- + */ + +// Minimal stand-in for the Data Injection interface implemented by the generated `...Injection` classes, +// loaded only when the plugin is absent so their rights can be tested. +// It mirrors Data Injection 2.15: keep it in sync if the interface changes there. +interface PluginDatainjectionInjectionInterface +{ + public function isPrimaryType(); + + public function connectedTo(); + + public function getOptions($primary_type = ''); + + public function addOrUpdateObject($values = [], $options = []); +}