diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index a279c098..0728b59e 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -20,7 +20,7 @@ jobs: name: "Generate CI matrix" uses: "glpi-project/plugin-ci-workflows/.github/workflows/generate-ci-matrix.yml@v1" with: - glpi-version: "11.0.x" + glpi-version: "12.0.x" ci: name: "GLPI ${{ matrix.glpi-version }} - php:${{ matrix.php-version }} - ${{ matrix.db-image }}" needs: "generate-ci-matrix" diff --git a/CHANGELOG.md b/CHANGELOG.md index 619e4b38..8cebe3b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [UNRELEASED] +### Added + +- GLPI 12 compatibility + ### Fixed - Fix various minor bugs in the import/export workflow diff --git a/composer.json b/composer.json index 8b1e015d..278f52a5 100644 --- a/composer.json +++ b/composer.json @@ -2,9 +2,6 @@ "require": { "php": ">=8.2" }, - "require-dev": { - "glpi-project/tools": "^0.8" - }, "config": { "optimize-autoloader": true, "platform": { @@ -14,7 +11,9 @@ }, "autoload-dev": { "psr-4": { - "Glpi\\Tools\\": "../../tools/src/" + "Glpi\\Tools\\": "../../tools/src/", + "GlpiPlugin\\Datainjection\\Tests\\": "tests/", + "GlpiPlugin\\Datainjection\\Tests\\Unit\\": "tests/unit/" } } } diff --git a/composer.lock b/composer.lock index 1adb59c7..e798ec87 100644 --- a/composer.lock +++ b/composer.lock @@ -4,881 +4,9 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0bb7734a8837cdd118f20d259d3613e7", + "content-hash": "4cacb822b12bf0d2a0dbcf952b20ef7b", "packages": [], - "packages-dev": [ - { - "name": "glpi-project/tools", - "version": "0.8.3", - "source": { - "type": "git", - "url": "https://github.com/glpi-project/tools.git", - "reference": "8ea2a7d4702a858f4b0360ba7d4f1841a5e77026" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/glpi-project/tools/zipball/8ea2a7d4702a858f4b0360ba7d4f1841a5e77026", - "reference": "8ea2a7d4702a858f4b0360ba7d4f1841a5e77026", - "shasum": "" - }, - "require": { - "symfony/console": "^5.4 || ^6.0", - "twig/twig": "^3.3" - }, - "require-dev": { - "nikic/php-parser": "^4.13", - "phpstan/phpstan-src": "^1.10" - }, - "bin": [ - "bin/extract-locales", - "bin/licence-headers-check", - "tools/plugin-release" - ], - "type": "library", - "autoload": { - "psr-4": { - "GlpiProject\\Tools\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-3.0-or-later" - ], - "authors": [ - { - "name": "Teclib'", - "email": "glpi@teclib.com", - "homepage": "http://teclib-group.com" - } - ], - "description": "Various tools for GLPI and its plugins", - "keywords": [ - "glpi", - "plugins", - "tools" - ], - "support": { - "issues": "https://github.com/glpi-project/tools/issues", - "source": "https://github.com/glpi-project/tools" - }, - "time": "2025-10-14T10:26:06+00:00" - }, - { - "name": "psr/container", - "version": "2.0.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", - "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", - "shasum": "" - }, - "require": { - "php": ">=7.4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Container\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", - "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" - ], - "support": { - "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/2.0.2" - }, - "time": "2021-11-05T16:47:00+00:00" - }, - { - "name": "symfony/console", - "version": "v6.4.43", - "source": { - "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "3b643aa587acbc42f967a429af088a56ed8f046d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/3b643aa587acbc42f967a429af088a56ed8f046d", - "reference": "3b643aa587acbc42f967a429af088a56ed8f046d", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-mbstring": "~1.0", - "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^5.4|^6.0|^7.0" - }, - "conflict": { - "symfony/dependency-injection": "<5.4", - "symfony/dotenv": "<5.4", - "symfony/event-dispatcher": "<5.4", - "symfony/lock": "<5.4", - "symfony/process": "<5.4" - }, - "provide": { - "psr/log-implementation": "1.0|2.0|3.0" - }, - "require-dev": { - "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/lock": "^5.4|^6.0|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.0|^7.0", - "symfony/stopwatch": "^5.4|^6.0|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Console\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Eases the creation of beautiful and testable command line interfaces", - "homepage": "https://symfony.com", - "keywords": [ - "cli", - "command-line", - "console", - "terminal" - ], - "support": { - "source": "https://github.com/symfony/console/tree/v6.4.43" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-07-26T14:44:19+00:00" - }, - { - "name": "symfony/deprecation-contracts", - "version": "v3.7.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/f3202fa1b5097b0af062dc978b32ecf63404e31d", - "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.7-dev" - } - }, - "autoload": { - "files": [ - "function.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "A generic function and convention to trigger deprecation notices", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.1" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-06-05T06:23:12+00:00" - }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.37.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "141046a8f9477948ff284fa65be2095baafb94f2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/141046a8f9477948ff284fa65be2095baafb94f2", - "reference": "141046a8f9477948ff284fa65be2095baafb94f2", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "provide": { - "ext-ctype": "*" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], - "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.37.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-04-10T16:19:22+00:00" - }, - { - "name": "symfony/polyfill-intl-grapheme", - "version": "v1.41.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "bb899c1db0aa8127dc3afe8cda4a67eb24915f8d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/bb899c1db0aa8127dc3afe8cda4a67eb24915f8d", - "reference": "bb899c1db0aa8127dc3afe8cda4a67eb24915f8d", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Intl\\Grapheme\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for intl's grapheme_* functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "grapheme", - "intl", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.41.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-07-28T08:25:59+00:00" - }, - { - "name": "symfony/polyfill-intl-normalizer", - "version": "v1.38.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/2d446c214bdbe5b71bde5011b060a05fece3ae6b", - "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for intl's Normalizer class and related functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "intl", - "normalizer", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.38.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-05-25T13:48:31+00:00" - }, - { - "name": "symfony/polyfill-mbstring", - "version": "v1.38.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6", - "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6", - "shasum": "" - }, - "require": { - "ext-iconv": "*", - "php": ">=7.2" - }, - "provide": { - "ext-mbstring": "*" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.2" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-05-27T06:59:30+00:00" - }, - { - "name": "symfony/service-contracts", - "version": "v3.7.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/service-contracts.git", - "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/c0a284bab1ed8aa0417e3d69250ab437739563a0", - "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "psr/container": "^1.1|^2.0", - "symfony/deprecation-contracts": "^2.5|^3" - }, - "conflict": { - "ext-psr": "<1.1|>=2" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.7-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\Service\\": "" - }, - "exclude-from-classmap": [ - "/Test/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to writing services", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.7.1" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-06-16T09:55:08+00:00" - }, - { - "name": "symfony/string", - "version": "v7.4.15", - "source": { - "type": "git", - "url": "https://github.com/symfony/string.git", - "reference": "e394af32256bf9e7bf80849d95e589167c10097b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/e394af32256bf9e7bf80849d95e589167c10097b", - "reference": "e394af32256bf9e7bf80849d95e589167c10097b", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3.0", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.33", - "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0" - }, - "conflict": { - "symfony/translation-contracts": "<2.5" - }, - "require-dev": { - "symfony/emoji": "^7.1|^8.0", - "symfony/http-client": "^6.4|^7.0|^8.0", - "symfony/intl": "^6.4|^7.0|^8.0", - "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.4|^7.0|^8.0" - }, - "type": "library", - "autoload": { - "files": [ - "Resources/functions.php" - ], - "psr-4": { - "Symfony\\Component\\String\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", - "homepage": "https://symfony.com", - "keywords": [ - "grapheme", - "i18n", - "string", - "unicode", - "utf-8", - "utf8" - ], - "support": { - "source": "https://github.com/symfony/string/tree/v7.4.15" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-07-28T07:33:02+00:00" - }, - { - "name": "twig/twig", - "version": "v3.28.0", - "source": { - "type": "git", - "url": "https://github.com/twigphp/Twig.git", - "reference": "597c12ed286fb9d1701a36684ce6e0cbe28ebc8b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/597c12ed286fb9d1701a36684ce6e0cbe28ebc8b", - "reference": "597c12ed286fb9d1701a36684ce6e0cbe28ebc8b", - "shasum": "" - }, - "require": { - "php": ">=8.1.0", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-ctype": "^1.8", - "symfony/polyfill-mbstring": "^1.3" - }, - "require-dev": { - "php-cs-fixer/shim": "^3.0@stable", - "phpstan/phpstan": "^2.0@stable", - "psr/container": "^1.0|^2.0", - "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" - }, - "type": "library", - "autoload": { - "files": [ - "src/Resources/core.php", - "src/Resources/debug.php", - "src/Resources/escaper.php", - "src/Resources/string_loader.php" - ], - "psr-4": { - "Twig\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com", - "homepage": "http://fabien.potencier.org", - "role": "Lead Developer" - }, - { - "name": "Twig Team", - "role": "Contributors" - }, - { - "name": "Armin Ronacher", - "email": "armin.ronacher@active-4.com", - "role": "Project Founder" - } - ], - "description": "Twig, the flexible, fast, and secure template language for PHP", - "homepage": "https://twig.symfony.com", - "keywords": [ - "templating" - ], - "support": { - "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.28.0" - }, - "funding": [ - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/twig/twig", - "type": "tidelift" - } - ], - "time": "2026-07-03T20:44:34+00:00" - } - ], + "packages-dev": [], "aliases": [], "minimum-stability": "stable", "stability-flags": {}, diff --git a/front/clientinjection.form.php b/front/clientinjection.form.php index 4610c796..32161117 100644 --- a/front/clientinjection.form.php +++ b/front/clientinjection.form.php @@ -28,7 +28,7 @@ * ------------------------------------------------------------------------- */ -Session::checkRight("plugin_datainjection_use", READ); +Session::checkRight(PluginDatainjectionClientInjection::$rightname, READ); Html::header( __('Data injection', 'datainjection'), @@ -61,6 +61,8 @@ && !$_FILES['filename']['error'] && $_FILES['filename']['size'] ) { + $uploaded_filename = $_FILES['filename']['name']; + //Read file using automatic encoding detection, and do not delete file once readed $options = [ 'file_encoding' => $_POST['file_encoding'], @@ -72,7 +74,7 @@ if ($response) { //File uploaded successfully and matches the given model : switch to the import tab - $_SESSION['datainjection']['file_name'] = $_FILES['filename']['name']; + $_SESSION['datainjection']['file_name'] = $uploaded_filename; $_SESSION['datainjection']['step'] = PluginDatainjectionClientInjection::STEP_PROCESS; //Store model in session for injection $_SESSION['datainjection']['currentmodel'] = serialize($model); diff --git a/front/mapping.form.php b/front/mapping.form.php index 8e99af94..ee79a02e 100644 --- a/front/mapping.form.php +++ b/front/mapping.form.php @@ -28,7 +28,7 @@ * ------------------------------------------------------------------------- */ -Session::checkRight('plugin_datainjection_model', UPDATE); +Session::checkRight(PluginDatainjectionModel::$rightname, UPDATE); /* Update mappings */ if (isset($_POST["update"])) { diff --git a/hook.php b/hook.php index 05a0a021..3d163db7 100644 --- a/hook.php +++ b/hook.php @@ -236,7 +236,7 @@ function plugin_datainjection_migration_2158_2159(Migration $migration) // Fix remaining legacy data (old schema stored private models with `entities_id = -1`). // Must run *before* the changeField() below: the column is converted to // `unsigned`, which would mangle the `-1` values before this cleanup could match them. - if (countElementsInTable("glpi_plugin_datainjection_models", ['entities_id' => -1])) { + if (countElementsInTable("glpi_plugin_datainjection_models", ['entities_id' => -1]) !== 0) { $migration->addPreQuery( "UPDATE `glpi_plugin_datainjection_models` SET `is_private` = '1', `entities_id` = '0', `is_recursive` = '1' @@ -1916,7 +1916,7 @@ function plugin_datainjection_update220_230() /** @var DBmysql $DB */ global $DB; - if (countElementsInTable("glpi_plugin_datainjection_models", ['entities_id' => -1])) { + if (countElementsInTable("glpi_plugin_datainjection_models", ['entities_id' => -1]) !== 0) { $query = "UPDATE `glpi_plugin_datainjection_models` SET `is_private` = '1', `entities_id` = '0', diff --git a/inc/clientinjection.class.php b/inc/clientinjection.class.php index cf244faf..1a6e9a5e 100644 --- a/inc/clientinjection.class.php +++ b/inc/clientinjection.class.php @@ -44,7 +44,7 @@ class PluginDatainjectionClientInjection { - public static $rightname = "plugin_datainjection_use"; + public static string $rightname = "plugin_datainjection_use"; public const STEP_UPLOAD = 0; @@ -87,7 +87,7 @@ public function showForm($ID, $options = []) TemplateRenderer::getInstance()->display('@datainjection/clientinjection.html.twig', [ 'form_action' => Toolbox::getItemTypeFormURL(self::class), 'models' => PluginDatainjectionModel::getModels(Session::getLoginUserID(), 'name', $_SESSION['glpiactive_entity'], false), - 'can_create_model' => Session::haveRight('plugin_datainjection_model', CREATE), + 'can_create_model' => Session::haveRight(PluginDatainjectionModel::$rightname, CREATE), 'model_type_name' => PluginDatainjectionModel::getTypeName(), 'models_id' => PluginDatainjectionSession::getParam('models_id'), 'step' => PluginDatainjectionSession::getParam('step'), diff --git a/inc/commoninjectionlib.class.php b/inc/commoninjectionlib.class.php index d0b75ea6..197d678d 100644 --- a/inc/commoninjectionlib.class.php +++ b/inc/commoninjectionlib.class.php @@ -642,7 +642,7 @@ private function getFieldValue( 'entities_id' => $this->entity, ]; - if ($item->getType() == 'Entity') { + if ($item::class == 'Entity') { // Blocks entity creation. The findID method only searches for direct sub-entities of the root, not deeper levels. $crit = 'name'; if (strpos($input['completename'], '>')) { @@ -661,7 +661,7 @@ private function getFieldValue( } $sons = getSonsOf('glpi_entities', $input['entities_id']); - if ($result === false && !empty($sons)) { + if ($result === false && $sons !== []) { foreach ($sons as $son_id) { $result = $entity->getFromDBByCrit( [ @@ -1831,7 +1831,7 @@ private function effectiveAddOrUpdate($injectionClass, $item, $values, $add = tr && !empty($option) && isset($option['table']) && $option['table'] === getTableForItemType(Group::class) - && Toolbox::hasTrait($item->getType(), AssignableItem::class) + && Toolbox::hasTrait($item::class, AssignableItem::class) ) { $normalized_value = $toinject[$key]; $group_type = null; diff --git a/inc/devicecaseinjection.class.php b/inc/devicecaseinjection.class.php index 35ba7328..8814ad56 100644 --- a/inc/devicecaseinjection.class.php +++ b/inc/devicecaseinjection.class.php @@ -98,14 +98,14 @@ public function processAfterInsertOrUpdate($values, $add = true, $rights = []) $foreign = getForeignKeyFieldForTable(getTableForItemType(get_parent_class($this))); if ( - !countElementsInTable( + countElementsInTable( $item->getTable(), [ $foreign => $values[get_parent_class($this)]['id'], 'itemtype' => 'Computer', 'items_id' => $values['Computer']['id'], ], - ) + ) === 0 ) { $tmp[$foreign] = $values[get_parent_class($this)]['id']; $tmp['items_id'] = $values['Computer']['id']; diff --git a/inc/devicecontrolinjection.class.php b/inc/devicecontrolinjection.class.php index a6992267..503d6bd5 100644 --- a/inc/devicecontrolinjection.class.php +++ b/inc/devicecontrolinjection.class.php @@ -99,14 +99,14 @@ public function processAfterInsertOrUpdate($values, $add = true, $rights = []) $foreign = getForeignKeyFieldForTable(getTableForItemType(get_parent_class($this))); if ( - !countElementsInTable( + countElementsInTable( $item->getTable(), [ $foreign => $values[get_parent_class($this)]['id'], 'itemtype' => 'Computer', 'items_id' => $values['Computer']['id'], ], - ) + ) === 0 ) { $tmp[$foreign] = $values[get_parent_class($this)]['id']; $tmp['items_id'] = $values['Computer']['id']; diff --git a/inc/devicedriveinjection.class.php b/inc/devicedriveinjection.class.php index 83789b35..668e7af0 100644 --- a/inc/devicedriveinjection.class.php +++ b/inc/devicedriveinjection.class.php @@ -99,14 +99,14 @@ public function processAfterInsertOrUpdate($values, $add = true, $rights = []) $foreign = getForeignKeyFieldForTable(getTableForItemType(get_parent_class($this))); if ( - !countElementsInTable( + countElementsInTable( $item->getTable(), [ $foreign => $values[get_parent_class($this)]['id'], 'itemtype' => 'Computer', 'items_id' => $values['Computer']['id'], ], - ) + ) === 0 ) { $tmp[$foreign] = $values[get_parent_class($this)]['id']; $tmp['items_id'] = $values['Computer']['id']; diff --git a/inc/deviceharddriveinjection.class.php b/inc/deviceharddriveinjection.class.php index 74d6ba83..240b3df5 100644 --- a/inc/deviceharddriveinjection.class.php +++ b/inc/deviceharddriveinjection.class.php @@ -100,14 +100,14 @@ public function processAfterInsertOrUpdate($values, $add = true, $rights = []) $foreign = getForeignKeyFieldForTable(getTableForItemType(get_parent_class($this))); if ( - !countElementsInTable( + countElementsInTable( $item->getTable(), [ $foreign => $values[get_parent_class($this)]['id'], 'itemtype' => 'Computer', 'items_id' => $values['Computer']['id'], ], - ) + ) === 0 ) { $tmp[$foreign] = $values[get_parent_class($this)]['id']; $tmp['items_id'] = $values['Computer']['id']; diff --git a/inc/devicememoryinjection.class.php b/inc/devicememoryinjection.class.php index 0d2cdfa8..d6ab5daa 100644 --- a/inc/devicememoryinjection.class.php +++ b/inc/devicememoryinjection.class.php @@ -105,7 +105,7 @@ public function processAfterInsertOrUpdate($values, $add = true, $rights = []) 'items_id' => $values['Computer']['id'], ]; - if (!countElementsInTable($item->getTable(), $where)) { + if (countElementsInTable($item->getTable(), $where) === 0) { if ( isset($values[get_parent_class($this)]['size_default']) && ($values[get_parent_class($this)]['size_default'] > 0) diff --git a/inc/devicemotherboardinjection.class.php b/inc/devicemotherboardinjection.class.php index a5276073..d508ffb0 100644 --- a/inc/devicemotherboardinjection.class.php +++ b/inc/devicemotherboardinjection.class.php @@ -100,14 +100,14 @@ public function processAfterInsertOrUpdate($values, $add = true, $rights = []) $foreign = getForeignKeyFieldForTable(getTableForItemType(get_parent_class($this))); if ( - !countElementsInTable( + countElementsInTable( $item->getTable(), [ $foreign => $values[get_parent_class($this)]['id'], 'itemtype' => 'Computer', 'items_id' => $values['Computer']['id'], ], - ) + ) === 0 ) { $tmp[$foreign] = $values[get_parent_class($this)]['id']; $tmp['items_id'] = $values['Computer']['id']; diff --git a/inc/devicenetworkcardinjection.class.php b/inc/devicenetworkcardinjection.class.php index 1b1f089b..5aa5c71a 100644 --- a/inc/devicenetworkcardinjection.class.php +++ b/inc/devicenetworkcardinjection.class.php @@ -98,14 +98,14 @@ public function processAfterInsertOrUpdate($values, $add = true, $rights = []) $foreign = getForeignKeyFieldForTable(getTableForItemType(get_parent_class($this))); if ( - !countElementsInTable( + countElementsInTable( $item->getTable(), [ $foreign => $values[get_parent_class($this)]['id'], 'itemtype' => 'Computer', 'items_id' => $values['Computer']['id'], ], - ) + ) === 0 ) { $tmp[$foreign] = $values[get_parent_class($this)]['id']; $tmp['items_id'] = $values['Computer']['id']; diff --git a/inc/deviceprocessorinjection.class.php b/inc/deviceprocessorinjection.class.php index 75f0fdb9..9a65ac45 100644 --- a/inc/deviceprocessorinjection.class.php +++ b/inc/deviceprocessorinjection.class.php @@ -105,7 +105,7 @@ public function processAfterInsertOrUpdate($values, $add = true, $rights = []) 'items_id' => $values['Computer']['id'], ]; - if (!countElementsInTable($item->getTable(), $where)) { + if (countElementsInTable($item->getTable(), $where) === 0) { //try first frequency, then default_frequency if ( isset($values[get_parent_class($this)]['frequency']) diff --git a/inc/entityinjection.class.php b/inc/entityinjection.class.php index 34421311..3834521d 100644 --- a/inc/entityinjection.class.php +++ b/inc/entityinjection.class.php @@ -190,7 +190,7 @@ public function importEntity($input) ); // Entity doesn't exists => create it - if (empty($results)) { + if ($results === []) { $parent = $em->import($tmp); } else { // Entity already exists, use the ID as parent @@ -233,7 +233,7 @@ public function customDataAlreadyInDB($injectionClass, $values, $options) ['completename' => $values['completename']], ); - if (empty($results)) { + if ($results === []) { return false; } diff --git a/inc/info.class.php b/inc/info.class.php index 82758ef6..e553d885 100644 --- a/inc/info.class.php +++ b/inc/info.class.php @@ -35,7 +35,7 @@ class PluginDatainjectionInfo extends CommonDBTM { - public static $rightname = "plugin_datainjection_model"; + public static string $rightname = "plugin_datainjection_model"; public function getEmpty() { @@ -156,7 +156,7 @@ public static function showFormInfos(PluginDatainjectionModel $model) $sel = "checked"; } - echo "", $sel); + echo "", $sel); echo ""; } @@ -476,13 +476,16 @@ public static function dropdownTemplates($name, $table) $values = [0 => Dropdown::EMPTY_VALUE]; - $sql = "SELECT `id`, `template_name` - FROM `" . $table . "` - WHERE `is_template`=1 " . - getEntitiesRestrictRequest(' AND ', $table) . - "ORDER BY `template_name`"; + $result = $DB->request([ + 'SELECT' => ['id', 'template_name'], + 'FROM' => $table, + 'WHERE' => [ + 'is_template' => 1, + ] + getEntitiesRestrictCriteria($table), + 'ORDER' => 'template_name', + ]); - foreach ($DB->doQuery($sql) as $data) { + foreach ($result as $data) { $values[$data['id']] = $data['template_name']; } diff --git a/inc/injectiontype.class.php b/inc/injectiontype.class.php index ee8eca2a..8da2105e 100644 --- a/inc/injectiontype.class.php +++ b/inc/injectiontype.class.php @@ -350,7 +350,7 @@ public static function showMandatoryCheckbox($options = []) && !in_array($options['value'], self::NON_MANDATORY_FIELDS) ) ) { - echo "", $checked); + echo "", $checked); } } diff --git a/inc/knowbaseitemcategoryinjection.class.php b/inc/knowbaseitemcategoryinjection.class.php deleted file mode 100644 index bee2b550..00000000 --- a/inc/knowbaseitemcategoryinjection.class.php +++ /dev/null @@ -1,91 +0,0 @@ -. - * ------------------------------------------------------------------------- - * @copyright Copyright (C) 2007-2023 by DataInjection plugin team. - * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html - * @link https://github.com/pluginsGLPI/datainjection - * ------------------------------------------------------------------------- - */ - - - -class PluginDatainjectionKnowbaseItemCategoryInjection extends KnowbaseItemCategory implements PluginDatainjectionInjectionInterface -{ - public static function getTable($classname = null) - { - - $parenttype = get_parent_class(self::class); - return $parenttype::getTable(); - } - - - public function isPrimaryType() - { - - return true; - } - - - public function connectedTo() - { - - return []; - } - - public function isNullable($field) - { - return true; // By default, all fields can be null - } - - - /** - * @see plugins/datainjection/inc/PluginDatainjectionInjectionInterface::getOptions() - **/ - public function getOptions($primary_type = '') - { - - $tab = Search::getOptions(get_parent_class($this)); - - //Remove some options because some fields cannot be imported - $blacklist = PluginDatainjectionCommonInjectionLib::getBlacklistedOptions(get_parent_class($this)); - $notimportable = [14]; - - $options['ignore_fields'] = array_merge($blacklist, $notimportable); - $options['displaytype'] = ["multiline_text" => [16]]; - - return PluginDatainjectionCommonInjectionLib::addToSearchOptions($tab, $options, $this); - } - - - /** - * @see plugins/datainjection/inc/PluginDatainjectionInjectionInterface::addOrUpdateObject() - **/ - public function addOrUpdateObject($values = [], $options = []) - { - - $lib = new PluginDatainjectionCommonInjectionLib($this, $values, $options); - $lib->processAddOrUpdate(); - return $lib->getInjectionResults(); - } -} diff --git a/inc/mapping.class.php b/inc/mapping.class.php index d9a3b495..20dfa36e 100644 --- a/inc/mapping.class.php +++ b/inc/mapping.class.php @@ -35,7 +35,7 @@ class PluginDatainjectionMapping extends CommonDBTM { - public static $rightname = "plugin_datainjection_model"; + public static string $rightname = "plugin_datainjection_model"; /** * @param string $field diff --git a/inc/menu.class.php b/inc/menu.class.php index 6d304cee..4c9d7146 100644 --- a/inc/menu.class.php +++ b/inc/menu.class.php @@ -30,7 +30,7 @@ class PluginDatainjectionMenu extends CommonGLPI { - public static $rightname = 'plugin_datainjection_use'; + public static string $rightname = 'plugin_datainjection_use'; public static function getMenuName() { @@ -73,14 +73,14 @@ public static function getMenuContent() $model_name = PluginDatainjectionModel::getTypeName(Session::getPluralNumber()); $image_model = "", $model_name, $model_name); - if (Session::haveRight('plugin_datainjection_model', READ)) { + if (Session::haveRight(PluginDatainjectionModel::$rightname, READ)) { $menu['options']['model']['title'] = $model_name; $menu['options']['model']['page'] = Toolbox::getItemTypeSearchUrl('PluginDatainjectionModel', false); $menu['options']['model']['links']['search'] = Toolbox::getItemTypeSearchUrl('PluginDatainjectionModel', false); $menu['options']['client']['links'][$image_model] = Toolbox::getItemTypeSearchUrl('PluginDatainjectionModel', false); } - if (Session::haveRight('plugin_datainjection_model', UPDATE) || Session::haveRight('plugin_datainjection_model', CREATE)) { + if (Session::haveRight(PluginDatainjectionModel::$rightname, UPDATE) || Session::haveRight(PluginDatainjectionModel::$rightname, CREATE)) { $menu['options']['model']['links']['add'] = Toolbox::getItemTypeFormUrl('PluginDatainjectionModel', false); $menu['options']['client']['links'][$image_model] = Toolbox::getItemTypeSearchUrl('PluginDatainjectionModel', false); } diff --git a/inc/model.class.php b/inc/model.class.php index 8fbbfd0e..a4fbdc28 100644 --- a/inc/model.class.php +++ b/inc/model.class.php @@ -64,7 +64,7 @@ class PluginDatainjectionModel extends CommonDBTM { - public static $rightname = "plugin_datainjection_model"; + public static string $rightname = "plugin_datainjection_model"; //Store mappings informations private $mappings; @@ -76,7 +76,7 @@ class PluginDatainjectionModel extends CommonDBTM protected $infos; //Do history (CommonDBTM) - public $dohistory = true; + public bool $dohistory = true; //Store specific backend parameters public $specific_model; @@ -459,7 +459,7 @@ public function rawSearchOptions() 'field' => 'name', 'name' => __('Name'), 'datatype' => 'itemlink', - 'itemlink_type' => $this->getType(), + 'itemlink_type' => static::class, 'autocomplete' => true, ], [ 'id' => 2, @@ -740,20 +740,20 @@ public function defineTabs($options = []) public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) { - $canedit = Session::haveRight('plugin_datainjection_model', UPDATE); + $canedit = Session::haveRight(self::$rightname, UPDATE); if (!$withtemplate && $item instanceof self) { - $tabs[1] = self::createTabEntry(__('Model'), 0, $item::getType(), self::getIcon()); + $tabs[1] = self::createTabEntry(__('Model'), 0, $item::class, self::getIcon()); if (!$this->isNewID($item->fields['id'])) { if ($canedit) { - $tabs[3] = self::createTabEntry(__('File to inject', 'datainjection'), 0, $item::getType(), 'ti ti-file-download'); + $tabs[3] = self::createTabEntry(__('File to inject', 'datainjection'), 0, $item::class, 'ti ti-file-download'); } - $tabs[4] = self::createTabEntry(__('Mappings', 'datainjection'), 0, $item::getType(), 'ti ti-columns'); + $tabs[4] = self::createTabEntry(__('Mappings', 'datainjection'), 0, $item::class, 'ti ti-columns'); if ($item->fields['step'] > self::MAPPING_STEP) { - $tabs[5] = self::createTabEntry(__('Additional Information', 'datainjection'), 0, $item::getType(), 'ti ti-code-variable-plus'); + $tabs[5] = self::createTabEntry(__('Additional Information', 'datainjection'), 0, $item::class, 'ti ti-code-variable-plus'); if ($canedit && $item->fields['step'] != self::READY_TO_USE_STEP) { - $tabs[6] = self::createTabEntry(__('Validation'), 0, $item::getType(), 'ti ti-checklist'); + $tabs[6] = self::createTabEntry(__('Validation'), 0, $item::class, 'ti ti-checklist'); } } } diff --git a/inc/modelcsv.class.php b/inc/modelcsv.class.php index c643bf00..6a49d4c5 100644 --- a/inc/modelcsv.class.php +++ b/inc/modelcsv.class.php @@ -60,17 +60,16 @@ class PluginDatainjectionModelcsv extends CommonDBChild { - public static $rightname = "plugin_datainjection_model"; + public static string $rightname = "plugin_datainjection_model"; - public $specific_fields; + public array $specific_fields; // From CommonDBChild - public static $itemtype = 'PluginDatainjectionModel'; + public static string $itemtype = 'PluginDatainjectionModel'; - public static $items_id = 'models_id'; - - public $dohistory = true; + public static string $items_id = 'models_id'; + public bool $dohistory = true; public function getEmpty() { diff --git a/inc/profile.class.php b/inc/profile.class.php index bd657c27..ac57751b 100644 --- a/inc/profile.class.php +++ b/inc/profile.class.php @@ -30,7 +30,7 @@ class PluginDatainjectionProfile extends Profile { - public static $rightname = "profile"; + public static string $rightname = "profile"; public static function getAllRights() { @@ -68,7 +68,7 @@ public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) if ($item instanceof Profile) { if ($item->fields['interface'] == 'central') { - return self::createTabEntry(__('Data injection', 'datainjection'), 0, $item::getType(), 'ti ti-download'); + return self::createTabEntry(__('Data injection', 'datainjection'), 0, $item::class, 'ti ti-download'); } return ''; @@ -105,10 +105,10 @@ public static function addDefaultProfileInfos($profiles_id, $rights) $profileRight = new ProfileRight(); foreach ($rights as $right => $value) { if ( - !countElementsInTable( + countElementsInTable( 'glpi_profilerights', ['profiles_id' => $profiles_id, 'name' => $right], - ) + ) === 0 ) { $myright['profiles_id'] = $profiles_id; $myright['name'] = $right; diff --git a/inc/softwarelicenseinjection.class.php b/inc/softwarelicenseinjection.class.php index ae1791e0..eb425251 100644 --- a/inc/softwarelicenseinjection.class.php +++ b/inc/softwarelicenseinjection.class.php @@ -157,16 +157,17 @@ public function getValueForAdditionalMandatoryFields($fields_toinject = []) return $fields_toinject; } - $where = ['name' => $fields_toinject['SoftwareLicense']['softwares_id']] + getEntitiesRestrictCriteria( - "glpi_softwares", - "entities_id", - $fields_toinject['SoftwareLicense']['entities_id'], - true, - ); $result = $DB->request([ - 'SELECT' => 'id', + 'SELECT' => ['id'], 'FROM' => 'glpi_softwares', - 'WHERE' => $where, + 'WHERE' => [ + 'name' => $fields_toinject['SoftwareLicense']['softwares_id'], + ] + getEntitiesRestrictCriteria( + 'glpi_softwares', + 'entities_id', + $fields_toinject['SoftwareLicense']['entities_id'], + true, + ), ]); if (count($result) > 0) { diff --git a/inc/softwareversioninjection.class.php b/inc/softwareversioninjection.class.php index 202d2029..d6289920 100644 --- a/inc/softwareversioninjection.class.php +++ b/inc/softwareversioninjection.class.php @@ -152,16 +152,17 @@ public function getValueForAdditionalMandatoryFields($fields_toinject = []) return $fields_toinject; } - $where = ['name' => $fields_toinject['SoftwareVersion']['softwares_id']] + getEntitiesRestrictCriteria( - "glpi_softwares", - "entities_id", - $fields_toinject['SoftwareVersion']['entities_id'], - true, - ); $result = $DB->request([ - 'SELECT' => 'id', + 'SELECT' => ['id'], 'FROM' => 'glpi_softwares', - 'WHERE' => $where, + 'WHERE' => [ + 'name' => $fields_toinject['SoftwareVersion']['softwares_id'], + ] + getEntitiesRestrictCriteria( + 'glpi_softwares', + 'entities_id', + $fields_toinject['SoftwareVersion']['entities_id'], + true, + ), ]); if (count($result) > 0) { diff --git a/inc/userinjection.class.php b/inc/userinjection.class.php index f215a18c..5177d759 100644 --- a/inc/userinjection.class.php +++ b/inc/userinjection.class.php @@ -186,7 +186,7 @@ public function processAfterInsertOrUpdate($values, $add = true, $rights = []) global $DB; //Manage user emails - if (isset($values['User']['useremails_id']) && $rights['add_dropdown'] && Session::haveRight('user', UPDATE)) { + if (isset($values['User']['useremails_id']) && $rights['add_dropdown'] && Session::haveRight(User::$rightname, UPDATE)) { $emails = preg_split('/[\s,;]+/', $values['User']['useremails_id'], -1, PREG_SPLIT_NO_EMPTY); foreach ($emails as $email) { $email = trim((string) $email); @@ -204,7 +204,7 @@ public function processAfterInsertOrUpdate($values, $add = true, $rights = []) 'is_default' => 0, ]; // If user has no emails, set this one as default - if (!countElementsInTable("glpi_useremails", ['users_id' => $values['User']['id']])) { + if (countElementsInTable("glpi_useremails", ['users_id' => $values['User']['id']]) === 0) { $tmp['is_default'] = 1; } diff --git a/setup.php b/setup.php index 99293671..fb437324 100644 --- a/setup.php +++ b/setup.php @@ -34,9 +34,9 @@ define('PLUGIN_DATAINJECTION_VERSION', '2.15.10'); // Minimal GLPI version, inclusive -define("PLUGIN_DATAINJECTION_MIN_GLPI", "11.0.5"); +define("PLUGIN_DATAINJECTION_MIN_GLPI", "12.0.0"); // Maximum GLPI version, exclusive -define("PLUGIN_DATAINJECTION_MAX_GLPI", "11.0.99"); +define("PLUGIN_DATAINJECTION_MAX_GLPI", "12.0.99"); if (!defined("PLUGIN_DATAINJECTION_UPLOAD_DIR")) { define("PLUGIN_DATAINJECTION_UPLOAD_DIR", GLPI_PLUGIN_DOC_DIR . "/datainjection/"); @@ -69,7 +69,7 @@ function plugin_init_datainjection() - if (Session::haveRight('plugin_datainjection_use', READ)) { + if (Session::haveRight(PluginDatainjectionClientInjection::$rightname, READ)) { $PLUGIN_HOOKS["menu_toadd"]['datainjection'] = ['tools' => 'PluginDatainjectionMenu']; } @@ -160,7 +160,6 @@ function getTypesToInject(): void 'PluginDatainjectionNetworkport_VlanInjection' => 'datainjection', 'PluginDatainjectionNetworkNameInjection' => 'datainjection', 'PluginDatainjectionNetpointInjection' => 'datainjection', - 'PluginDatainjectionKnowbaseItemCategoryInjection' => 'datainjection', 'PluginDatainjectionKnowbaseItemInjection' => 'datainjection', 'PluginDatainjectionITILFollowupTemplateInjection' => 'datainjection', 'PluginDatainjectionITILCategoryInjection' => 'datainjection', diff --git a/templates/clientinjection.html.twig b/templates/clientinjection.html.twig index 590b9cae..4790fe89 100644 --- a/templates/clientinjection.html.twig +++ b/templates/clientinjection.html.twig @@ -27,12 +27,10 @@ #} {% import 'components/form/fields_macros.html.twig' as fields %} -{% import 'components/alerts_macros.html.twig' as alerts %} {% set rand = random() %}
-
@@ -57,7 +55,12 @@ {% if can_create_model %} {% set text = text ~ '. ' ~ __('You can start the model creation by hitting the button', 'datainjection') ~ ': ' ~ model_type_name %} {% endif %} - {{ alerts.alert_info(text) }} + {{ component('Alert', { + color: 'info', + heading: __('No model available', 'datainjection'), + content: text, + icon: 'ti ti-info-circle', + }) }} {% endif %}
diff --git a/templates/clientinjection_result.html.twig b/templates/clientinjection_result.html.twig index 15ca3f22..34e6b161 100644 --- a/templates/clientinjection_result.html.twig +++ b/templates/clientinjection_result.html.twig @@ -26,13 +26,14 @@ # ------------------------------------------------------------------------- #} - - +{% import 'components/form/basic_inputs_macros.html.twig' as inputs %} + +
{{ __("Injection's results", 'datainjection') }}
-
+
{% if ok %} {{ __('Injection successful', 'datainjection') }} @@ -42,7 +43,7 @@ {% endif %}
-
+ \ No newline at end of file diff --git a/templates/clientinjection_upload_file.html.twig b/templates/clientinjection_upload_file.html.twig index 43ffaa20..8e749462 100644 --- a/templates/clientinjection_upload_file.html.twig +++ b/templates/clientinjection_upload_file.html.twig @@ -27,25 +27,24 @@ #} {% import 'components/form/fields_macros.html.twig' as fields %} +{% import 'components/form/basic_inputs_macros.html.twig' as inputs %} {% if add_form %}
- {% endif %}
{{ __('File to inject', 'datainjection') }}
- + {{ inputs.hidden('id', models_id) }} - {{ fields.htmlField( + {{ fields.fileField( 'filename', - '', + '', __('Choose a file', 'datainjection'), { - 'add_field_class' : 'col-sm-12', - 'label_class' : 'col-5 col-sm-5', + 'simple' : true, 'input_class' : 'col-6 col-sm-6', } ) }} @@ -55,10 +54,7 @@ file_encoding_values, __('File encoding', 'datainjection'), { - 'add_field_class' : 'col-sm-12', - 'label_class' : 'col-5 col-sm-5', 'input_class' : 'col-6 col-sm-6', - 'width': '325px', } ) }} @@ -69,12 +65,12 @@ {% else %} {% set message = __("Watch out, you're about to inject data into GLPI. Are you sure you want to do it ?", 'datainjection') %} {% endif %} - + {{ inputs.submit('upload', submit_label, submit_label, {'additional_attributes': {'onclick': "return window.confirm('" ~ message|e('js') ~ "');"}}) }} {% else %} - + {{ inputs.submit('upload', submit_label, submit_label) }} {% endif %}    - + {{ inputs.submit('cancel', _x('button', 'Cancel'), _x('button', 'Cancel'), {'class': 'btn btn-outline-danger'}) }}
{% if add_form %} diff --git a/templates/mappings_form.html.twig b/templates/mappings_form.html.twig index 1063f0e0..13a4cf93 100644 --- a/templates/mappings_form.html.twig +++ b/templates/mappings_form.html.twig @@ -25,45 +25,45 @@ # @link https://github.com/pluginsGLPI/datainjection # ------------------------------------------------------------------------- #} +{% import 'components/form/basic_inputs_macros.html.twig' as inputs %}
- {% if show_preview %} - - - - -
- - {{ __('See the file', 'datainjection') }} - -
+
{% endif %} - - - - - - - - - {% for mapping in mappings %} - - - - - - - {% endfor %} - - {% if canedit %} +
{{ __('Header of the file', 'datainjection') }}{{ __('Tables', 'datainjection') }}{{ _n('Field', 'Fields', 2) }}{{ __('Link field', 'datainjection') }}
{{ mapping.name }}{{ mapping.dropdown_html|raw }}
+ - + + + + + + + {% for mapping in mappings %} + + + + + + + {% endfor %} + + {% if canedit %} + + + + + {% endif %}
- - - {{ __('Header of the file', 'datainjection') }}{{ __('Tables', 'datainjection') }}{{ _n('Field', 'Fields', 2) }}{{ __('Link field', 'datainjection') }}
{{ mapping.name }}{{ mapping.dropdown_html|raw }}
+ {{ inputs.hidden('models_id', model_id) }} + {{ inputs.submit('update', __('Save'), __('Save')) }} +
diff --git a/templates/model_validation_form.html.twig b/templates/model_validation_form.html.twig index 18a92093..e7957468 100644 --- a/templates/model_validation_form.html.twig +++ b/templates/model_validation_form.html.twig @@ -25,17 +25,15 @@ # @link https://github.com/pluginsGLPI/datainjection # ------------------------------------------------------------------------- #} +{% import 'components/form/basic_inputs_macros.html.twig' as inputs %}
-
{{ __('Validation', 'datainjection') }}
-
-
- - -
+
+ {{ inputs.hidden('id', id) }} + {{ inputs.submit('validate', _x('button', 'Validate the model', 'datainjection'), _x('button', 'Validate the model', 'datainjection')) }}
\ No newline at end of file diff --git a/tests/AbstractDataInjectionTestCase.php b/tests/AbstractDataInjectionTestCase.php new file mode 100644 index 00000000..03b17a4a --- /dev/null +++ b/tests/AbstractDataInjectionTestCase.php @@ -0,0 +1,64 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2007-2023 by DataInjection plugin team. + * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html + * @link https://github.com/pluginsGLPI/datainjection + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Datainjection\Tests; + +use Glpi\Tests\DbTestCase; +use Plugin; + +abstract class AbstractDataInjectionTestCase extends DbTestCase +{ + public function setUp(): void + { + parent::setUp(); + $this->login(); + + // Functions defined in hook.php (migration steps, needUpdateOrInstall(), ...) + // are only required when the plugin is actually (re)loaded, which + // Plugin::activate() skips once it is already active. Load explicitly so + // tests can call those functions directly. + Plugin::load('datainjection', true); + } + + /** + * Run DDL (CREATE/DROP/ALTER TABLE) outside of the transaction that wraps each test. + */ + protected function withoutTransaction(callable $callback): mixed + { + global $DB; + $DB->commit(); + try { + return $callback(); + } finally { + $DB->clearSchemaCache(); + $DB->beginTransaction(); + } + } +} diff --git a/tests/unit/ClientInjectionEscapeCsvFormulaTest.php b/tests/unit/ClientInjectionEscapeCsvFormulaTest.php index 03ebaed3..b2ea0ee0 100644 --- a/tests/unit/ClientInjectionEscapeCsvFormulaTest.php +++ b/tests/unit/ClientInjectionEscapeCsvFormulaTest.php @@ -31,6 +31,7 @@ namespace GlpiPlugin\Datainjection\Tests\Unit; use Glpi\Tests\DbTestCase; +use PHPUnit\Framework\Attributes\DataProvider; use PluginDatainjectionClientInjection; use ReflectionMethod; @@ -56,9 +57,7 @@ public static function escapeCsvFormulaProvider(): array ]; } - /** - * @dataProvider escapeCsvFormulaProvider - */ + #[DataProvider('escapeCsvFormulaProvider')] public function testEscapeCsvFormula(mixed $value, mixed $expected): void { $escape_csv_formula = new ReflectionMethod( diff --git a/tests/unit/CommonInjectionLibDateTimeTest.php b/tests/unit/CommonInjectionLibDateTimeTest.php index 2cc8e5fe..412b100f 100644 --- a/tests/unit/CommonInjectionLibDateTimeTest.php +++ b/tests/unit/CommonInjectionLibDateTimeTest.php @@ -32,6 +32,7 @@ use Glpi\Tests\DbTestCase; use Computer; +use PHPUnit\Framework\Attributes\DataProvider; use PluginDatainjectionComputerInjection; use PluginDatainjectionCommonInjectionLib; use ReflectionMethod; @@ -84,9 +85,7 @@ public static function reformatDateTimeProvider(): array ]; } - /** - * @dataProvider reformatDateTimeProvider - */ + #[DataProvider('reformatDateTimeProvider')] public function testReformatDateTime(string $original, string $date_format, string $expected): void { $lib = new PluginDatainjectionCommonInjectionLib( diff --git a/tests/unit/CommonInjectionLibFloatDetectionTest.php b/tests/unit/CommonInjectionLibFloatDetectionTest.php index e694d218..c3842b53 100644 --- a/tests/unit/CommonInjectionLibFloatDetectionTest.php +++ b/tests/unit/CommonInjectionLibFloatDetectionTest.php @@ -31,6 +31,7 @@ namespace GlpiPlugin\Datainjection\Tests\Unit; use Glpi\Tests\DbTestCase; +use PHPUnit\Framework\Attributes\DataProvider; use PluginDatainjectionCommonInjectionLib; use PluginDatainjectionComputerInjection; @@ -88,9 +89,7 @@ public static function floatDetectionProvider(): array ]; } - /** - * @dataProvider floatDetectionProvider - */ + #[DataProvider('floatDetectionProvider')] public function testFloatDetectionRegex(string $value, bool $expected_match): void { $regex = $this->getFloatDetectionRegex(); diff --git a/tests/unit/EngineInjectLineTest.php b/tests/unit/EngineInjectLineTest.php new file mode 100644 index 00000000..12e48add --- /dev/null +++ b/tests/unit/EngineInjectLineTest.php @@ -0,0 +1,145 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2007-2023 by DataInjection plugin team. + * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html + * @link https://github.com/pluginsGLPI/datainjection + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Datainjection\Tests\Unit; + +use Computer; +use GlpiPlugin\Datainjection\Tests\AbstractDataInjectionTestCase; +use PluginDatainjectionCommonInjectionLib; +use PluginDatainjectionEngine; +use PluginDatainjectionMapping; +use PluginDatainjectionModel; +use Session; + +final class EngineInjectLineTest extends AbstractDataInjectionTestCase +{ + private function createModelWithMappings(array $model_overrides = []): PluginDatainjectionModel + { + $model = $this->createItem(PluginDatainjectionModel::class, array_merge([ + 'name' => 'Test_Engine_Model_' . uniqid(), + 'itemtype' => Computer::class, + 'entities_id' => 0, + 'is_private' => 0, + 'users_id' => Session::getLoginUserID(), + 'behavior_add' => 1, + 'behavior_update' => 1, + ], $model_overrides)); + + $this->createItem(PluginDatainjectionMapping::class, [ + 'models_id' => $model->getID(), + 'itemtype' => Computer::class, + 'rank' => 0, + 'name' => 'Name', + 'value' => 'name', + 'is_mandatory' => 1, + ]); + + $this->createItem(PluginDatainjectionMapping::class, [ + 'models_id' => $model->getID(), + 'itemtype' => Computer::class, + 'rank' => 1, + 'name' => 'Serial', + 'value' => 'serial', + 'is_mandatory' => 0, + ]); + + return $model; + } + + public function testInjectLineCreatesItemFromMappedCsvRow(): void + { + $model = $this->createModelWithMappings(); + + $engine = new PluginDatainjectionEngine($model, [], $model->fields['entities_id']); + $results = $engine->injectLine(['Test_Engine_Computer', 'ABC123'], 1); + + self::assertSame(PluginDatainjectionCommonInjectionLib::SUCCESS, $results['status']); + self::assertSame(PluginDatainjectionCommonInjectionLib::IMPORT_ADD, $results['type']); + self::assertEmpty($engine->getLinesInError()); + + $computer = new Computer(); + self::assertTrue($computer->getFromDB($results['Computer'])); + self::assertSame('Test_Engine_Computer', $computer->fields['name']); + self::assertSame('ABC123', $computer->fields['serial']); + } + + public function testInjectLineUpdatesExistingItemFromMappedCsvRow(): void + { + $model = $this->createModelWithMappings(); + + $computer = $this->createItem(Computer::class, [ + 'name' => 'Test_Engine_Computer_Update', + 'entities_id' => 0, + 'serial' => 'OLD_SERIAL', + ]); + + $engine = new PluginDatainjectionEngine($model, [], $model->fields['entities_id']); + $results = $engine->injectLine(['Test_Engine_Computer_Update', 'NEW_SERIAL'], 1); + + self::assertSame(PluginDatainjectionCommonInjectionLib::SUCCESS, $results['status']); + self::assertSame(PluginDatainjectionCommonInjectionLib::IMPORT_UPDATE, $results['type']); + + $computer->getFromDB($computer->getID()); + self::assertSame('NEW_SERIAL', $computer->fields['serial']); + } + + public function testInjectLineRejectsNewItemWhenModelDisallowsAdd(): void + { + $model = $this->createModelWithMappings(['behavior_add' => 0]); + + $engine = new PluginDatainjectionEngine($model, [], $model->fields['entities_id']); + $results = $engine->injectLine(['Test_Engine_Computer_NoAdd', 'XYZ'], 1); + + self::assertSame(PluginDatainjectionCommonInjectionLib::ERROR_CANNOT_IMPORT, $results['status']); + self::assertNotEmpty($engine->getLinesInError()); + + $computer = new Computer(); + self::assertFalse($computer->getFromDBbyCrit(['name' => 'Test_Engine_Computer_NoAdd'])); + } + + public function testInjectLineRejectsUpdateWhenModelDisallowsUpdate(): void + { + $model = $this->createModelWithMappings(['behavior_update' => 0]); + + $computer = $this->createItem(Computer::class, [ + 'name' => 'Test_Engine_Computer_NoUpdate', + 'entities_id' => 0, + 'serial' => 'ORIGINAL', + ]); + + $engine = new PluginDatainjectionEngine($model, [], $model->fields['entities_id']); + $results = $engine->injectLine(['Test_Engine_Computer_NoUpdate', 'CHANGED'], 1); + + self::assertSame(PluginDatainjectionCommonInjectionLib::ERROR_CANNOT_UPDATE, $results['status']); + + $computer->getFromDB($computer->getID()); + self::assertSame('ORIGINAL', $computer->fields['serial']); + } +} diff --git a/tests/unit/GroupInjectionTest.php b/tests/unit/GroupInjectionTest.php index 693bb25f..010b6b3e 100644 --- a/tests/unit/GroupInjectionTest.php +++ b/tests/unit/GroupInjectionTest.php @@ -30,6 +30,7 @@ namespace GlpiPlugin\Datainjection\Tests\Unit; +use PHPUnit\Framework\Attributes\DataProvider; use PluginDatainjectionComputerInjection; use PluginDatainjectionITILCategoryInjection; use Glpi\Tests\DbTestCase; @@ -78,10 +79,7 @@ public static function assignGroupToInjectedAssignableItemProvider(): array ]; } - /** - * - * @dataProvider assignGroupToInjectedAssignableItemProvider - */ + #[DataProvider('assignGroupToInjectedAssignableItemProvider')] public function testAssigneGroupToInjectedAssignableItem( string $group_field, array $injected_data, @@ -163,10 +161,7 @@ public static function groupIsAssignedToInjectedNonAssignableItemProvider(): arr ]; } - /** - * - * @dataProvider groupIsAssignedToInjectedNonAssignableItemProvider - */ + #[DataProvider('groupIsAssignedToInjectedNonAssignableItemProvider')] public function testGroupIsAssignedToInjectedNonAssignableItem( array $injected_data, array $mandatory_fields, @@ -250,8 +245,8 @@ public static function groupIsUpdatedOnExistingAssignableItemProvider(): array * Updating an existing AssignableItem (Computer) via injection must route the group through * the AssignableItem normalisation path and persist it in Group_Item. * - * @dataProvider groupIsUpdatedOnExistingAssignableItemProvider */ + #[DataProvider('groupIsUpdatedOnExistingAssignableItemProvider')] public function testGroupIsUpdatedOnExistingAssignableItem( string $group_field, array $injected_data, diff --git a/tests/unit/MigrationTest.php b/tests/unit/MigrationTest.php new file mode 100644 index 00000000..c5f34dbb --- /dev/null +++ b/tests/unit/MigrationTest.php @@ -0,0 +1,106 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2007-2023 by DataInjection plugin team. + * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html + * @link https://github.com/pluginsGLPI/datainjection + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Datainjection\Tests\Unit; + +use DBmysql; +use GlpiPlugin\Datainjection\Tests\AbstractDataInjectionTestCase; +use Migration; +use Psr\Log\LogLevel; +use Session; + +final class MigrationTest extends AbstractDataInjectionTestCase +{ + public function testMigration2158To2159FixesLegacyNegativeEntityId(): void + { + /** @var DBmysql $DB */ + global $DB; + + $table = 'glpi_plugin_datainjection_models'; + + // Recreate the pre-2158 column shape: signed, defaulting to -1, + // exactly as described in the migration's own comments. + $this->withoutTransaction(static function () use ($DB, $table): void { + $DB->doQuery(sprintf("ALTER TABLE `%s` CHANGE `entities_id` `entities_id` int NOT NULL default '-1'", $table)); + }); + // GLPI itself warns on signed keys; expected here since we are + // deliberately recreating the legacy (pre-migration) column shape. + $this->hasPhpLogRecordThatContains( + 'Usage of signed integers in primary or foreign keys is discouraged', + LogLevel::WARNING, + ); + + $id = null; + + try { + $DB->insert($table, [ + 'name' => 'Test_Migration_Legacy_Private_Model', + 'itemtype' => 'Computer', + 'entities_id' => -1, + 'is_private' => 1, + 'is_recursive' => 0, + 'users_id' => Session::getLoginUserID(), + 'behavior_add' => 1, + ]); + $id = $DB->insertId(); + + $this->withoutTransaction(static function (): void { + plugin_datainjection_migration_2158_2159(new Migration(PLUGIN_DATAINJECTION_VERSION)); + }); + + $row = $DB->request(['FROM' => $table, 'WHERE' => ['id' => $id]])->current(); + + self::assertSame(0, (int) $row['entities_id']); + self::assertSame(1, (int) $row['is_private']); + self::assertSame(1, (int) $row['is_recursive']); + + $column = null; + foreach ($DB->listFields($table) as $field) { + if ($field['Field'] === 'entities_id') { + $column = $field; + } + } + + self::assertNotNull($column); + self::assertStringContainsString('unsigned', $column['Type']); + } finally { + if ($id !== null) { + $DB->delete($table, ['id' => $id]); + } + + // Guarantee the column ends up unsigned regardless of whether the + // assertions above passed, matching the schema every other test + // in this suite relies on. + $this->withoutTransaction(static function () use ($DB, $table): void { + $DB->doQuery(sprintf("ALTER TABLE `%s` CHANGE `entities_id` `entities_id` int unsigned NOT NULL default '0'", $table)); + }); + } + } +} diff --git a/tests/unit/ModelCrudTest.php b/tests/unit/ModelCrudTest.php new file mode 100644 index 00000000..4c325fa1 --- /dev/null +++ b/tests/unit/ModelCrudTest.php @@ -0,0 +1,120 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2007-2023 by DataInjection plugin team. + * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html + * @link https://github.com/pluginsGLPI/datainjection + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Datainjection\Tests\Unit; + +use Computer; +use GlpiPlugin\Datainjection\Tests\AbstractDataInjectionTestCase; +use PluginDatainjectionMapping; +use PluginDatainjectionModel; +use Session; + +final class ModelCrudTest extends AbstractDataInjectionTestCase +{ + public function testAddRefusesModelWithoutAName(): void + { + $model = new PluginDatainjectionModel(); + $id = $model->add([ + 'name' => '', + 'itemtype' => Computer::class, + 'entities_id' => 0, + 'users_id' => Session::getLoginUserID(), + 'behavior_add' => 1, + 'behavior_update' => 0, + ]); + + self::assertFalse($id); + $this->hasSessionMessages(ERROR, ['Please enter a name for the model']); + } + + public function testAddRefusesModelWithNeitherAddNorUpdateBehavior(): void + { + $model = new PluginDatainjectionModel(); + $id = $model->add([ + 'name' => 'Test_Model_Crud_NoBehavior', + 'itemtype' => Computer::class, + 'entities_id' => 0, + 'users_id' => Session::getLoginUserID(), + 'behavior_add' => 0, + 'behavior_update' => 0, + ]); + + self::assertFalse($id); + $this->hasSessionMessages(ERROR, ['Your model should allow import and/or update of data']); + } + + public function testUpdateRefusesChangingOwnerOfAPrivateModel(): void + { + $model = $this->createItem(PluginDatainjectionModel::class, [ + 'name' => 'Test_Model_Crud_Private', + 'itemtype' => Computer::class, + 'entities_id' => 0, + 'is_private' => PluginDatainjectionModel::MODEL_PRIVATE, + 'users_id' => Session::getLoginUserID(), + 'behavior_add' => 1, + 'behavior_update' => 0, + ]); + + $success = $model->update([ + 'id' => $model->getID(), + 'is_private' => 1, + 'users_id' => Session::getLoginUserID() + 1, + ]); + + self::assertFalse($success); + $this->hasSessionMessages(ERROR, ['You are not the initial creator of this model']); + } + + public function testPurgingAModelDeletesItsMappings(): void + { + $model = $this->createItem(PluginDatainjectionModel::class, [ + 'name' => 'Test_Model_Crud_Purge', + 'itemtype' => Computer::class, + 'entities_id' => 0, + 'users_id' => Session::getLoginUserID(), + 'behavior_add' => 1, + 'behavior_update' => 0, + ]); + + $mapping = $this->createItem(PluginDatainjectionMapping::class, [ + 'models_id' => $model->getID(), + 'itemtype' => Computer::class, + 'rank' => 0, + 'name' => 'Name', + 'value' => 'name', + 'is_mandatory' => 1, + ]); + + $this->deleteItem(PluginDatainjectionModel::class, $model->getID(), true); + + $reloaded_mapping = new PluginDatainjectionMapping(); + self::assertFalse($reloaded_mapping->getFromDB($mapping->getID())); + } +} diff --git a/tests/unit/ModelRightsTest.php b/tests/unit/ModelRightsTest.php new file mode 100644 index 00000000..9f4d0a5d --- /dev/null +++ b/tests/unit/ModelRightsTest.php @@ -0,0 +1,122 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2007-2023 by DataInjection plugin team. + * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html + * @link https://github.com/pluginsGLPI/datainjection + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Datainjection\Tests\Unit; + +use Computer; +use Entity; +use GlpiPlugin\Datainjection\Tests\AbstractDataInjectionTestCase; +use PluginDatainjectionModel; +use Session; +use User; + +final class ModelRightsTest extends AbstractDataInjectionTestCase +{ + /** + * The default test user's active session is scoped to a fixed set of + * entities that does not include the root entity, so models under test + * need a real entity from that set, not entities_id => 0. + */ + private function createAccessibleEntityId(): int + { + return (int) $this->createItem(Entity::class, [ + 'name' => 'Test_Model_Rights_Entity_' . uniqid(), + 'entities_id' => 0, + ])->getID(); + } + + private function createModel(array $overrides = []): PluginDatainjectionModel + { + return $this->createItem(PluginDatainjectionModel::class, array_merge([ + 'name' => 'Test_Model_Rights_' . uniqid(), + 'itemtype' => Computer::class, + 'entities_id' => $this->createAccessibleEntityId(), + 'is_private' => PluginDatainjectionModel::MODEL_PUBLIC, + 'users_id' => Session::getLoginUserID(), + 'behavior_add' => 1, + 'behavior_update' => 1, + ], $overrides)); + } + + public function testCanCreateItemIsDeniedWhenNativeItemtypeRightIsRemoved(): void + { + $model = $this->createModel(); + + self::assertTrue($model->canCreateItem()); + + $_SESSION['glpiactiveprofile']['computer'] = 0; + self::assertFalse($model->canCreateItem()); + } + + public function testCanCreateItemIsAllowedWhenNativeItemtypeRightIsPresent(): void + { + $model = $this->createModel(); + + $_SESSION['glpiactiveprofile']['computer'] = ALLSTANDARDRIGHT; + self::assertTrue($model->canCreateItem()); + } + + public function testCanViewItemHidesPrivateModelOwnedByAnotherUser(): void + { + $model = $this->createModel([ + 'is_private' => PluginDatainjectionModel::MODEL_PRIVATE, + 'users_id' => getItemByTypeName(User::class, 'tech', true), + ]); + + self::assertFalse($model->canViewItem()); + } + + public function testCanViewItemAllowsPrivateModelOwnedBySelf(): void + { + $model = $this->createModel([ + 'is_private' => PluginDatainjectionModel::MODEL_PRIVATE, + ]); + + self::assertTrue($model->canViewItem()); + } + + public function testCanViewItemRespectsEntityRestriction(): void + { + $entity = $this->createItem(Entity::class, [ + 'name' => 'Test_Model_Rights_Entity', + 'entities_id' => 0, + ]); + + $model = $this->createModel([ + 'entities_id' => $entity->getID(), + 'is_recursive' => 0, + ]); + + self::assertTrue($model->canViewItem()); + + $_SESSION['glpiactiveentities'] = [0]; + self::assertFalse($model->canViewItem()); + } +} diff --git a/tests/unit/PluginLifecycleTest.php b/tests/unit/PluginLifecycleTest.php new file mode 100644 index 00000000..61ef2b85 --- /dev/null +++ b/tests/unit/PluginLifecycleTest.php @@ -0,0 +1,57 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2007-2023 by DataInjection plugin team. + * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html + * @link https://github.com/pluginsGLPI/datainjection + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Datainjection\Tests\Unit; + +use GlpiPlugin\Datainjection\Tests\AbstractDataInjectionTestCase; +use Plugin; + +final class PluginLifecycleTest extends AbstractDataInjectionTestCase +{ + private function getPlugin(): Plugin + { + $plugin = new Plugin(); + $plugin->getFromDBbyDir('datainjection'); + + return $plugin; + } + + public function testPluginIsInstalledAndActivatedByDefault(): void + { + $plugin = $this->getPlugin(); + + self::assertSame(Plugin::ACTIVATED, (int) $plugin->fields['state']); + } + + public function testNeedUpdateOrInstallReportsUpToDateWhenFullyInstalled(): void + { + self::assertSame(-1, plugin_datainjection_needUpdateOrInstall()); + } +}