From 545e7d9cab754e029b5eef8f2a52ea2a89627892 Mon Sep 17 00:00:00 2001 From: btry Date: Tue, 1 Sep 2026 14:40:51 +0200 Subject: [PATCH 01/15] feat: glpi 12 compatibility --- .github/workflows/continuous-integration.yml | 2 +- composer.json | 2 +- package-lock.json | 4 +- package.json | 2 +- setup.php | 11 +- src/AbstractChildDropdown.php | 2 +- src/AbstractImpact.php | 6 +- .../View/Extension/DataHelpersExtension.php | 303 ------------------ src/CarbonEmission.php | 4 +- src/CarbonIntensity.php | 2 +- src/Command/CollectCarbonIntensityCommand.php | 2 +- .../CreateFakeCarbonIntensityCommand.php | 2 +- src/Command/CreateTestInventoryCommand.php | 2 +- src/Command/ExportDashboardCommand.php | 2 +- src/ComputerModel.php | 4 +- src/ComputerType.php | 4 +- .../ElectricityMaps/Client.php | 6 +- src/DataSource/CarbonIntensity/Rte/Client.php | 6 +- src/Location.php | 4 +- src/MonitorModel.php | 4 +- src/MonitorType.php | 4 +- src/NetworkEquipmentModel.php | 4 +- src/NetworkEquipmentType.php | 4 +- src/Report.php | 4 +- src/Source_Zone.php | 12 +- src/UsageInfo.php | 6 +- tests/install/PluginInstallTest.php | 2 - tests/units/HookTest.php | 2 +- 28 files changed, 50 insertions(+), 362 deletions(-) delete mode 100644 src/Application/View/Extension/DataHelpersExtension.php diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index dc3f4f9a..6530865b 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -22,7 +22,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/composer.json b/composer.json index e9a9a0b1..a0241e08 100644 --- a/composer.json +++ b/composer.json @@ -35,5 +35,5 @@ "license-headers": "vendor/bin/licence-headers-check --ansi --no-interaction", "build-schema": "tools/build-db-schema.php carbon | plantuml -p -tpng > docs/db-schema.png" }, - "version": "1.3.0-dev" + "version": "1.4.0-dev" } diff --git a/package-lock.json b/package-lock.json index be53cdf3..3cb71d8f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "carbon", - "version": "1.3.0-dev", + "version": "1.4.0-dev", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "carbon", - "version": "1.3.0-dev", + "version": "1.4.0-dev", "hasInstallScript": true, "license": "GPL-3.0-or-later", "dependencies": { diff --git a/package.json b/package.json index 831cb333..dcf9a0ed 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "carbon", "description": "Measurement of carbon emissions of GLPI devices", "license": "GPL-3.0-or-later", - "version": "1.3.0-dev", + "version": "1.4.0-dev", "engines": { "node": ">= 18.12.0" }, diff --git a/setup.php b/setup.php index f2aedb35..80e3e807 100644 --- a/setup.php +++ b/setup.php @@ -47,9 +47,9 @@ use Profile as GlpiProfile; // Version of the plugin (major.minor.bugfix) -define('PLUGIN_CARBON_VERSION', '1.3.0-dev'); +define('PLUGIN_CARBON_VERSION', '1.4.0-dev'); // Schema version of this version (major.minor.bugfix) -define('PLUGIN_CARBON_SCHEMA_VERSION', '1.3.0'); +define('PLUGIN_CARBON_SCHEMA_VERSION', '1.4.0'); // Version compatibility check -- from GLPI developer documentation // > A bug in GLPI prior to 11.0.7 caused plugin routes with method constraints other than GET to never match. @@ -63,9 +63,9 @@ // Watch it when adding new controllers. // Minimal GLPI version, inclusive -define('PLUGIN_CARBON_MIN_GLPI_VERSION', '11.0.0'); +define('PLUGIN_CARBON_MIN_GLPI_VERSION', '12.0.0'); // Maximum GLPI version, exclusive -define('PLUGIN_CARBON_MAX_GLPI_VERSION', '12.0.0'); +define('PLUGIN_CARBON_MAX_GLPI_VERSION', '13.0.0'); define('PLUGIN_CARBON_DECIMALS', 3); define('EMBER_DATASET_DATE', '2025-07-30'); @@ -223,8 +223,9 @@ function plugin_carbon_check_prerequisites() $prerequisitesSuccess = true; + // In case GLPI is so old that the modern version checker is not implemented /** @phpstan-ignore if.alwaysFalse */ - if (version_compare(GLPI_VERSION, PLUGIN_CARBON_MIN_GLPI_VERSION, 'lt')) { + if (version_compare(GLPI_VERSION, "10.0.0", 'lt')) { echo "This plugin requires GLPI >= " . PLUGIN_CARBON_MIN_GLPI_VERSION . " and GLPI < " . PLUGIN_CARBON_MAX_GLPI_VERSION . "
"; $prerequisitesSuccess = false; } diff --git a/src/AbstractChildDropdown.php b/src/AbstractChildDropdown.php index 64675fb5..54994398 100644 --- a/src/AbstractChildDropdown.php +++ b/src/AbstractChildDropdown.php @@ -41,7 +41,7 @@ abstract class AbstractChildDropdown extends CommonDBChild { - public static $rightname = 'dropdown'; + public static string $rightname = 'dropdown'; #[Override] public static function getIcon(): string diff --git a/src/AbstractImpact.php b/src/AbstractImpact.php index 103ddc09..f5c4a4fc 100644 --- a/src/AbstractImpact.php +++ b/src/AbstractImpact.php @@ -44,10 +44,10 @@ abstract class AbstractImpact extends CommonDBChild { - public static $itemtype = 'itemtype'; - public static $items_id = 'items_id'; + public static string $itemtype = 'itemtype'; + public static string $items_id = 'items_id'; - public static $rightname = 'carbon:report'; + public static string $rightname = 'carbon:report'; #[Override] public function canEdit($ID): bool diff --git a/src/Application/View/Extension/DataHelpersExtension.php b/src/Application/View/Extension/DataHelpersExtension.php deleted file mode 100644 index 2ccec211..00000000 --- a/src/Application/View/Extension/DataHelpersExtension.php +++ /dev/null @@ -1,303 +0,0 @@ -. - * - * ------------------------------------------------------------------------- - */ - -namespace GlpiPlugin\Carbon\Application\View\Extension; - -use Glpi\RichText\RichText; -use Glpi\Toolbox\Sanitizer; -use Html; -use Override; -use Toolbox; -use Twig\Extension\AbstractExtension; -use Twig\TwigFilter; - -/** - * @since 10.0.0 - */ -class DataHelpersExtension extends AbstractExtension -{ - #[Override] - public function getFilters(): array - { - return [ - new TwigFilter('formatted_datetime', [$this, 'getFormattedDatetime']), - new TwigFilter('formatted_date', [$this, 'getFormattedDate']), - new TwigFilter('formatted_duration', [$this, 'getFormattedDuration']), - new TwigFilter('formatted_integer', [$this, 'getFormattedInteger']), - new TwigFilter('formatted_number', [$this, 'getFormattedNumber']), - new TwigFilter('formatted_size', [$this, 'getFormattedSize']), - new TwigFilter('html_to_text', [$this, 'getTextFromHtml']), - new TwigFilter('long2ip', 'long2ip'), - new TwigFilter('picture_url', [$this, 'getPictureUrl']), - new TwigFilter('relative_datetime', [$this, 'getRelativeDatetime']), - new TwigFilter('safe_html', [$this, 'getSafeHtml'], ['is_safe' => ['html']]), - new TwigFilter('verbatim_value', [$this, 'getVerbatimValue']), - new TwigFilter('shortcut', [$this, 'underlineShortcutLetter'], ['is_safe' => ['html']]), - new TwigFilter('enhanced_html', [$this, 'getEnhancedHtml'], ['is_safe' => ['html']]), - new TwigFilter('truncate_left', [$this, 'truncateLeft']), - ]; - } - - /** - * Return date formatted to user preferred format. - * - * @param mixed $datetime - * @param bool $with_seconds - * - * @return string|null - */ - public function getFormattedDatetime($datetime, bool $with_seconds = false): ?string - { - if (!is_string($datetime)) { - return null; - } - return Html::convDateTime($datetime, null, $with_seconds); - } - - /** - * Return date formatted to user preferred format. - * - * @param mixed $date - * - * @return string|null - */ - public function getFormattedDate($date): ?string - { - if (!is_string($date)) { - return null; - } - return Html::convDate($date); - } - - /** - * Return relative representation of given date. - * - * @param mixed $datetime - * - * @return string|null - */ - public function getRelativeDatetime($datetime): ?string - { - if (!is_string($datetime)) { - return null; - } - return Html::timestampToRelativeStr($datetime); - } - - /** - * Return human readable duration. - * - * @param mixed $duration - * @param bool $display_seconds (default: true) - * - * @return string|null - */ - public function getFormattedDuration( - $duration, - bool $display_seconds = true - ): ?string { - if (!is_numeric($duration)) { - return null; - } - return Html::timestampToString($duration, $display_seconds); - } - - /** - * Return integer formatted to user preferred format. - * - * @param mixed $number Number to display - * - * @return string - */ - public function getFormattedInteger($number): string - { - return Html::formatNumber($number, false, 0); - } - - /** - * Return number formatted to user preferred format. - * - * @param mixed $number Number to display - * - * @return string - */ - public function getFormattedNumber($number): string - { - return Html::formatNumber($number); - } - - /** - * Return size formatted in a compact way (mo, ko, etc). - * - * @param mixed $number - * - * @return string - */ - public function getFormattedSize($number): string - { - if (!is_numeric($number)) { - return ''; - } - return Toolbox::getSize($number); - } - - /** - * Return URL for given picture. - * - * @param mixed $path - * - * @return null|string - */ - public function getPictureUrl($path): ?string - { - if (!is_string($path)) { - return null; - } - - return Toolbox::getPictureUrl($path, true); - } - - /** - * Return string having its shortcut letter underlined. - * - * @param string $string - * @param string $shortcut_letter - * - * @return string - */ - public function underlineShortcutLetter(string $string, string $shortcut_letter): string - { - if (empty($shortcut_letter)) { - return $string; - } - return Toolbox::shortcut($string, $shortcut_letter); - } - - /** - * Return plain text from HTML (rich text). - * - * @param mixed $string HTML string to be made safe - * @param bool $keep_presentation Indicates whether the presentation elements have to be replaced by plaintext equivalents - * @param bool $compact Indicates whether the output should be compact (limited line length, no links URL, ...) - * - * @return mixed - */ - public function getTextFromHtml($string, bool $keep_presentation = true, bool $compact = false) - { - if (!is_string($string)) { - return $string; - } - - return RichText::getTextFromHtml($string, $keep_presentation, $compact); - } - - /** - * Return safe HTML (rich text). - * Value will be made safe, whenever it has been sanitize (value fetched from DB), - * or not (value computed during runtime). - * Result will not be escaped, to prevent having to use `|raw` filter. - * - * @param mixed $string - * - * @return mixed - */ - public function getSafeHtml($string) - { - if (!is_string($string)) { - return $string; - } - - return RichText::getSafeHtml($string); - } - - /** - * Return enhanced HTML (rich text). - * Value will be made safe, whenever it has been sanitize (value fetched from DB), - * or not (value computed during runtime). - * Result will not be escaped, to prevent having to use `|raw` filter. - * - * @param mixed $string - * - * @return mixed - */ - public function getEnhancedHtml($string, array $params = []) - { - if (!is_string($string)) { - return $string; - } - - return RichText::getEnhancedHtml($string, $params); - } - - /** - * Return verbatim value for an itemtype field. - * Returned value will be unsanitized if it has been transformed by GLPI sanitizing process (value fetched from DB). - * Twig autoescaping system will then ensure that value is correctly escaped in rendered HTML. - * - * @param mixed $string - * - * @return mixed - * - * @deprecated 11.0 - */ - public function getVerbatimValue($string) - { - Toolbox::deprecated(); - - if (!is_string($string)) { - return $string; - } - - return Sanitizer::unsanitize($string); - } - - - /** - * return the provided string truncated on the left and prepend a prefix separator if length is reached - * - * @param string $string the string to left truncate - * @param int $length number of char to preserve - * @param string $separator prefix to prepend to the string - * - * @return string truncated string - */ - public function truncateLeft(string $string = "", int $length = 30, string $separator = "...") - { - if (mb_strlen($string) <= $length) { - return $string; - } - - return $separator . mb_substr($string, -$length); - } -} diff --git a/src/CarbonEmission.php b/src/CarbonEmission.php index 95619e15..bc2dea3d 100644 --- a/src/CarbonEmission.php +++ b/src/CarbonEmission.php @@ -44,8 +44,8 @@ class CarbonEmission extends CommonDBChild { - public static $itemtype = 'itemtype'; - public static $items_id = 'items_id'; + public static string $itemtype = 'itemtype'; + public static string $items_id = 'items_id'; #[Override] public static function getTypeName($nb = 0) diff --git a/src/CarbonIntensity.php b/src/CarbonIntensity.php index 4c9fc7ec..99d3a7b3 100644 --- a/src/CarbonIntensity.php +++ b/src/CarbonIntensity.php @@ -59,7 +59,7 @@ class CarbonIntensity extends CommonDropdown { private const MIN_HISTORY_LENGTH = '13 months ago'; - public static $rightname = 'carbon:report'; + public static string $rightname = 'carbon:report'; #[Override] public static function getTypeName($nb = 0) diff --git a/src/Command/CollectCarbonIntensityCommand.php b/src/Command/CollectCarbonIntensityCommand.php index 09941081..90cdfab2 100644 --- a/src/Command/CollectCarbonIntensityCommand.php +++ b/src/Command/CollectCarbonIntensityCommand.php @@ -117,7 +117,7 @@ protected function interact(InputInterface $input, OutputInterface $output) } #[Override] - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { if (count($this->zones) > 1 && $input->getArgument('zone') === null) { // Null is not a valid key if there are several zones available for the source diff --git a/src/Command/CreateFakeCarbonIntensityCommand.php b/src/Command/CreateFakeCarbonIntensityCommand.php index 516b9d1e..afb5855e 100644 --- a/src/Command/CreateFakeCarbonIntensityCommand.php +++ b/src/Command/CreateFakeCarbonIntensityCommand.php @@ -63,7 +63,7 @@ protected function configure() } #[Override] - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $this->output = $output; diff --git a/src/Command/CreateTestInventoryCommand.php b/src/Command/CreateTestInventoryCommand.php index 1ea9c7cf..882f4d50 100644 --- a/src/Command/CreateTestInventoryCommand.php +++ b/src/Command/CreateTestInventoryCommand.php @@ -141,7 +141,7 @@ protected function configure() } #[Override] - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { $this->output = $output; diff --git a/src/Command/ExportDashboardCommand.php b/src/Command/ExportDashboardCommand.php index 9c36d94b..988250bb 100644 --- a/src/Command/ExportDashboardCommand.php +++ b/src/Command/ExportDashboardCommand.php @@ -60,7 +60,7 @@ protected function configure() } #[Override] - protected function execute(InputInterface $input, OutputInterface $output) + protected function execute(InputInterface $input, OutputInterface $output): int { /** @var DBmysql $DB */ global $DB; diff --git a/src/ComputerModel.php b/src/ComputerModel.php index f08fb727..85ce4795 100644 --- a/src/ComputerModel.php +++ b/src/ComputerModel.php @@ -36,6 +36,6 @@ class ComputerModel extends AbstractModel { - public static $itemtype = GlpiComputerModel::class; - public static $items_id = 'computermodels_id'; + public static string $itemtype = GlpiComputerModel::class; + public static string $items_id = 'computermodels_id'; } diff --git a/src/ComputerType.php b/src/ComputerType.php index c20955d7..2ef95b35 100644 --- a/src/ComputerType.php +++ b/src/ComputerType.php @@ -41,8 +41,8 @@ class ComputerType extends AbstractChildDropdown { - public static $itemtype = GlpiComputerType::class; - public static $items_id = 'computertypes_id'; + public static string $itemtype = GlpiComputerType::class; + public static string $items_id = 'computertypes_id'; public const CATEGORY_UNDEFINED = 0; public const CATEGORY_DESKTOP = 1; diff --git a/src/DataSource/CarbonIntensity/ElectricityMaps/Client.php b/src/DataSource/CarbonIntensity/ElectricityMaps/Client.php index 1c9a6c08..16d5ae6e 100644 --- a/src/DataSource/CarbonIntensity/ElectricityMaps/Client.php +++ b/src/DataSource/CarbonIntensity/ElectricityMaps/Client.php @@ -37,7 +37,6 @@ use DateTimeImmutable; use DateTimeInterface; use DateTimeZone; -use DBmysql; use GLPIKey; use GlpiPlugin\Carbon\CarbonIntensity; use GlpiPlugin\Carbon\DataSource\CarbonIntensity\AbortException; @@ -412,11 +411,8 @@ protected function formatOutput(array $response, int $step): array */ protected function shiftToLocalTimezone(array $response): array { - /** @var DBmysql $DB */ - global $DB; - $shifted_response = []; - $local_timezone = new DateTimeZone($DB->guessTimezone()); + $local_timezone = new DateTimeZone(date_default_timezone_get()); array_walk($response, function ($item, $key) use (&$shifted_response, $local_timezone) { $shifted_date_object = DateTime::createFromFormat('Y-m-d\TH:i:s.vp', $item['datetime']) ->setTimezone($local_timezone); diff --git a/src/DataSource/CarbonIntensity/Rte/Client.php b/src/DataSource/CarbonIntensity/Rte/Client.php index ec7b66c7..8b16ff62 100644 --- a/src/DataSource/CarbonIntensity/Rte/Client.php +++ b/src/DataSource/CarbonIntensity/Rte/Client.php @@ -37,7 +37,6 @@ use DateTimeImmutable; use DateTimeInterface; use DateTimeZone; -use DBmysql; use GlpiPlugin\Carbon\DataSource\CarbonIntensity\AbstractClient; use GlpiPlugin\Carbon\DataSource\RestApiClientInterface; use GlpiPlugin\Carbon\DataTracking\AbstractTracked; @@ -387,11 +386,8 @@ protected function formatOutput(array $response, int $step): array */ protected function shiftToLocalTimezone(array $response): array { - /** @var DBmysql $DB */ - global $DB; - $shifted_response = []; - $local_timezone = new DateTimeZone($DB->guessTimezone()); + $local_timezone = new DateTimeZone(date_default_timezone_get()); array_walk($response, function ($item, $key) use (&$shifted_response, $local_timezone) { $shifted_date_object = DateTime::createFromFormat('Y-m-d\TH:i:sP', $item['date_heure']) ->setTimezone($local_timezone); diff --git a/src/Location.php b/src/Location.php index 8306426a..f08870de 100644 --- a/src/Location.php +++ b/src/Location.php @@ -60,8 +60,8 @@ class Location extends CommonDBChild { // From CommonDBRelation - public static $itemtype = GlpiLocation::class; - public static $items_id = 'locations_id'; + public static string $itemtype = GlpiLocation::class; + public static string $items_id = 'locations_id'; #[Override] public static function getIcon() diff --git a/src/MonitorModel.php b/src/MonitorModel.php index d929e3d2..f144bb5f 100644 --- a/src/MonitorModel.php +++ b/src/MonitorModel.php @@ -36,6 +36,6 @@ class MonitorModel extends AbstractModel { - public static $itemtype = GlpiMonitorModel::class; - public static $items_id = 'monitormodels_id'; + public static string $itemtype = GlpiMonitorModel::class; + public static string $items_id = 'monitormodels_id'; } diff --git a/src/MonitorType.php b/src/MonitorType.php index 9d104059..e4e994bb 100644 --- a/src/MonitorType.php +++ b/src/MonitorType.php @@ -40,8 +40,8 @@ class MonitorType extends AbstractChildDropdown { - public static $itemtype = GlpiMonitorType::class; - public static $items_id = 'monitortypes_id'; + public static string $itemtype = GlpiMonitorType::class; + public static string $items_id = 'monitortypes_id'; #[Override] public static function showMassiveActionsSubForm(MassiveAction $ma) diff --git a/src/NetworkEquipmentModel.php b/src/NetworkEquipmentModel.php index 70bde975..1ed55dfe 100644 --- a/src/NetworkEquipmentModel.php +++ b/src/NetworkEquipmentModel.php @@ -36,6 +36,6 @@ class NetworkEquipmentModel extends AbstractModel { - public static $itemtype = GlpiNetworkEquipmentModel::class; - public static $items_id = 'networkequipmentmodels_id'; + public static string $itemtype = GlpiNetworkEquipmentModel::class; + public static string $items_id = 'networkequipmentmodels_id'; } diff --git a/src/NetworkEquipmentType.php b/src/NetworkEquipmentType.php index 64e0cb3e..c49e9d33 100644 --- a/src/NetworkEquipmentType.php +++ b/src/NetworkEquipmentType.php @@ -40,8 +40,8 @@ class NetworkEquipmentType extends AbstractChildDropdown { - public static $itemtype = GlpiNetworkEquipmentType::class; - public static $items_id = 'networkequipmenttypes_id'; + public static string $itemtype = GlpiNetworkEquipmentType::class; + public static string $items_id = 'networkequipmenttypes_id'; #[Override] public static function showMassiveActionsSubForm(MassiveAction $ma) diff --git a/src/Report.php b/src/Report.php index c0511dfa..46ccf202 100644 --- a/src/Report.php +++ b/src/Report.php @@ -42,8 +42,8 @@ class Report extends CommonDBTM { - public static $rightname = 'carbon:report'; - protected static $notable = true; + public static string $rightname = 'carbon:report'; + protected static bool $notable = true; #[Override] public static function getTypeName($nb = 0) diff --git a/src/Source_Zone.php b/src/Source_Zone.php index c485486f..61fc3bb9 100644 --- a/src/Source_Zone.php +++ b/src/Source_Zone.php @@ -46,13 +46,13 @@ class Source_Zone extends CommonDBRelation { - public static $itemtype_1 = Source::class; // Type ref or field name (must start with itemtype) - public static $items_id_1 = 'plugin_carbon_sources_id'; // Field name - public static $checkItem_1_Rights = self::HAVE_SAME_RIGHT_ON_ITEM; + public static ?string $itemtype_1 = Source::class; // Type ref or field name (must start with itemtype) + public static ?string $items_id_1 = 'plugin_carbon_sources_id'; // Field name + public static int $checkItem_1_Rights = self::HAVE_SAME_RIGHT_ON_ITEM; - public static $itemtype_2 = Zone::class; // Type ref or field name (must start with itemtype) - public static $items_id_2 = 'plugin_carbon_zones_id'; // Field name - public static $checkItem_2_Rights = self::HAVE_SAME_RIGHT_ON_ITEM; + public static ?string $itemtype_2 = Zone::class; // Type ref or field name (must start with itemtype) + public static ?string $items_id_2 = 'plugin_carbon_zones_id'; // Field name + public static int $checkItem_2_Rights = self::HAVE_SAME_RIGHT_ON_ITEM; #[Override] public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) diff --git a/src/UsageInfo.php b/src/UsageInfo.php index 06274f96..f0736434 100644 --- a/src/UsageInfo.php +++ b/src/UsageInfo.php @@ -53,10 +53,10 @@ */ class UsageInfo extends CommonDBChild { - public static $itemtype = 'itemtype'; - public static $items_id = 'items_id'; + public static string $itemtype = 'itemtype'; + public static string $items_id = 'items_id'; - public static $rightname = 'carbon:report'; + public static string $rightname = 'carbon:report'; #[Override] public static function getTypeName($nb = 0) diff --git a/tests/install/PluginInstallTest.php b/tests/install/PluginInstallTest.php index c6a40cea..b9159b45 100644 --- a/tests/install/PluginInstallTest.php +++ b/tests/install/PluginInstallTest.php @@ -170,7 +170,6 @@ public function testInstallPlugin() $this->checkRegisteredClasses(); } - #[CoversNothing()] public function testConfigurationExists() { $config = Config::getConfigurationValues(TEST_PLUGIN_NAME); @@ -181,7 +180,6 @@ public function testConfigurationExists() return $config; } - #[CoversNothing()] private function checkSchema( string $version, bool $strict = true, diff --git a/tests/units/HookTest.php b/tests/units/HookTest.php index cb5b2ffd..ae6e5877 100644 --- a/tests/units/HookTest.php +++ b/tests/units/HookTest.php @@ -103,7 +103,7 @@ public function testCarbonAssetTypeIsPurgedOnAssetTypePurge() 'computertypes_id' => $computer_type->getID(), ]); - $computer_type->delete($computer_type->fields, 1); + $computer_type->delete($computer_type->fields, true); $count = (new DbUtils())->countElementsInTable($carbon_computer_type::getTable(), [ 'computertypes_id' => $computer_type->getID(), ]); From 9853fd735a9fd43515d073ddad1f8c66ddd79115 Mon Sep 17 00:00:00 2001 From: btry Date: Thu, 3 Sep 2026 09:35:50 +0200 Subject: [PATCH 02/15] feat: drop deprecated CSRF token --- src/Config.php | 1 - templates/config.html.twig | 5 ++--- templates/environmentalimpact-item.html.twig | 8 ++++---- tests/units/ConfigTest.php | 2 -- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/Config.php b/src/Config.php index e9b38b9e..35aca4ca 100644 --- a/src/Config.php +++ b/src/Config.php @@ -123,7 +123,6 @@ public function showForm($ID, $options = []) $current_config = array_diff_key($current_config, array_flip($secured_config)); $reset_args = json_encode([ - '_glpi_csrf_token' => Session::getNewCSRFToken(), 'reset_all' => '', ]); $usage_impact_action_url = 'submitGetLink("' . $CFG_GLPI['root_doc'] . '/plugins/carbon/front/usageimpact.form.php", ' . $reset_args . ')'; diff --git a/templates/config.html.twig b/templates/config.html.twig index 3f688a71..d199f31d 100644 --- a/templates/config.html.twig +++ b/templates/config.html.twig @@ -35,7 +35,6 @@
- {{ fields.largeTitle( __('Impact engine', 'carbon'), @@ -79,7 +78,7 @@ {{ __('Reset usage impacts. This will delete all calculated usage impacts for all assets.', 'carbon') }} - {% set reset_args = "{_glpi_csrf_token: '" ~ csrf_token() ~ "', reset_all: ''}" %} + {% set reset_args = "{reset_all: ''}" %} {{ _x('button', 'Reset usage impacts') }} @@ -89,7 +88,7 @@ {{ __('Reset embodied impacts. This will delete all calculated embodied impacts for all assets.', 'carbon') }} - {% set reset_args = "{_glpi_csrf_token: '" ~ csrf_token() ~ "', reset_all: ''}" %} + {% set reset_args = "{reset_all: ''}" %} {{ _x('button', 'Reset embodied impacts') }} diff --git a/templates/environmentalimpact-item.html.twig b/templates/environmentalimpact-item.html.twig index a499c1ec..436e6525 100644 --- a/templates/environmentalimpact-item.html.twig +++ b/templates/environmentalimpact-item.html.twig @@ -61,10 +61,10 @@
{% if not usage_impact.isNewItem() or usage_carbon_emission_count > 0 %} - {% set reset_args = "{_glpi_csrf_token: '" ~ csrf_token() ~ "', reset: '', itemtype: '" ~ asset.getType() ~ "', items_id: '" ~ asset.getID() ~ "'}" %} + {% set reset_args = "{reset: '', itemtype: '" ~ asset.getType() ~ "', items_id: '" ~ asset.getID() ~ "'}" %} {{ __('Reset data', 'carbon') }} {% endif %} - {% set calculate_args = "{_glpi_csrf_token: '" ~ csrf_token() ~ "', calculate: '', itemtype: '" ~ asset.getType() ~ "', items_id: '" ~ asset.getID() ~ "'}" %} + {% set calculate_args = "{calculate: '', itemtype: '" ~ asset.getType() ~ "', items_id: '" ~ asset.getID() ~ "'}" %} {{ __('Calculate data', 'carbon') }}
@@ -96,10 +96,10 @@
{% if not embodied_impact.isNewItem() %} - {% set reset_args = "{_glpi_csrf_token: '" ~ csrf_token() ~ "', reset: '', id: '" ~ embodied_impact.getID() ~ "'}" %} + {% set reset_args = "{reset: '', id: '" ~ embodied_impact.getID() ~ "'}" %} {{ __('Reset data', 'carbon') }} {% endif %} - {% set calculate_args = "{_glpi_csrf_token: '" ~ csrf_token() ~ "', calculate: '', itemtype: '" ~ asset.getType() ~ "', items_id: '" ~ asset.getID() ~ "'}" %} + {% set calculate_args = "{calculate: '', itemtype: '" ~ asset.getType() ~ "', items_id: '" ~ asset.getID() ~ "'}" %} {{ __('Calculate data', 'carbon') }}
diff --git a/tests/units/ConfigTest.php b/tests/units/ConfigTest.php index 5f0c5d25..c13a76e6 100644 --- a/tests/units/ConfigTest.php +++ b/tests/units/ConfigTest.php @@ -99,10 +99,8 @@ public function testShowForm() $crawler = new Crawler($output); $config_class = $crawler->filter('input[type="hidden"][name="config_class"]'); $config_context = $crawler->filter('input[type="hidden"][name="config_context"]'); - $csrf = $crawler->filter('input[type="hidden"][name="_glpi_csrf_token"]'); $this->assertEquals(1, $config_class->count()); $this->assertEquals(1, $config_context->count()); - $this->assertEquals(1, $csrf->count()); $electricitymaps_api = $crawler->filter('input[name="electricitymap_api_key"]'); $impact_engine = $crawler->filter('select[name="impact_engine"]'); $this->assertEquals(1, $electricitymaps_api->count()); From 603dd88f81a513b7950c6ea36ac2e4d6eb47ac2a Mon Sep 17 00:00:00 2001 From: btry Date: Thu, 3 Sep 2026 10:02:11 +0200 Subject: [PATCH 03/15] fix: truncate table with bad WHERE clause --- src/AbstractImpact.php | 2 +- src/CarbonEmission.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AbstractImpact.php b/src/AbstractImpact.php index f5c4a4fc..95a9fa71 100644 --- a/src/AbstractImpact.php +++ b/src/AbstractImpact.php @@ -255,6 +255,6 @@ public function truncate(): bool return false; } - return $DB->delete(static::getTable(), [1]); + return $DB->delete(static::getTable(), ['NOT' => ['id' => null]]); } } diff --git a/src/CarbonEmission.php b/src/CarbonEmission.php index bc2dea3d..5c717a49 100644 --- a/src/CarbonEmission.php +++ b/src/CarbonEmission.php @@ -229,6 +229,6 @@ public function truncate(): bool return false; } - return $DB->delete(static::getTable(), [1]); + return $DB->delete(static::getTable(), ['NOT' => ['id' => null]]); } } From a8d96226df40d2bc225e03f85b8c0456155c08f6 Mon Sep 17 00:00:00 2001 From: btry Date: Thu, 3 Sep 2026 10:15:38 +0200 Subject: [PATCH 04/15] feat: disable useless DB version check --- setup.php | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/setup.php b/setup.php index 80e3e807..7f8f48c5 100644 --- a/setup.php +++ b/setup.php @@ -240,22 +240,23 @@ function plugin_carbon_check_prerequisites() $prerequisitesSuccess = false; } - if (getenv('CI') === false) { - // only when not under test - $version_string = $DB->getVersion(); - - $server = preg_match('/-MariaDB/', $version_string) ? 'MariaDB' : 'MySQL'; - $version = preg_replace('/^((\d+\.?)+).*$/', '$1', $version_string); - if ($server === 'MySQL' && version_compare($version, '8.0.0', '<')) { - echo 'This plugin requires MySQL >= 8.0 or MariaDB >= 10.2
'; - $prerequisitesSuccess = false; - } - - if ($server === 'MariaDB' && version_compare($version, '10.2.0', '<')) { - echo 'This plugin requires MySQL >= 8.0 or MariaDB >= 10.2
'; - $prerequisitesSuccess = false; - } - } + // GLPI 12 requires MySQL >= 8.0 or MariaDB >= 10.2, then the check below can be disabled + // if (getenv('CI') === false) { + // // only when not under test + // $version_string = $DB->getVersion(); + + // $server = preg_match('/-MariaDB/', $version_string) ? 'MariaDB' : 'MySQL'; + // $version = preg_replace('/^((\d+\.?)+).*$/', '$1', $version_string); + // if ($server === 'MySQL' && version_compare($version, '8.0.0', '<')) { + // echo 'This plugin requires MySQL >= 8.0 or MariaDB >= 10.2
'; + // $prerequisitesSuccess = false; + // } + + // if ($server === 'MariaDB' && version_compare($version, '10.2.0', '<')) { + // echo 'This plugin requires MySQL >= 8.0 or MariaDB >= 10.2
'; + // $prerequisitesSuccess = false; + // } + // } return $prerequisitesSuccess; } From 9655603593dcb4eda00fc2e0974a9b92eca89971 Mon Sep 17 00:00:00 2001 From: btry Date: Thu, 3 Sep 2026 10:24:58 +0200 Subject: [PATCH 05/15] docs(security): update --- SECURITY.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SECURITY.md b/SECURITY.md index 0484177c..32d96350 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -19,6 +19,8 @@ Thank you for improving the security of glpi-agent. | Version | Supported | | ------- | ------------------ | -| 1.0.x | :heavy_check_mark: | +| 1.0.x | :x: | | 1.2.x | :x: | | 1.3.x | :heavy_check_mark: | +| 1.3.x | :heavy_check_mark: | +| 1.4.x | :heavy_check_mark: | From 5ef0924640abde0b1586e00e37cabd7b54ccddea Mon Sep 17 00:00:00 2001 From: btry Date: Thu, 3 Sep 2026 11:09:48 +0200 Subject: [PATCH 06/15] test: remove useless attributes --- tests/install/PluginInstallTest.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/install/PluginInstallTest.php b/tests/install/PluginInstallTest.php index b9159b45..f0bc92c0 100644 --- a/tests/install/PluginInstallTest.php +++ b/tests/install/PluginInstallTest.php @@ -67,7 +67,6 @@ use NetworkEquipmentModel; use NetworkEquipmentType; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\Attributes\CoversNothing; use PHPUnit\Framework\Attributes\Depends; use Plugin; use Profile; @@ -937,7 +936,6 @@ public function checkRegisteredClasses() $this->assertEquals($expected, $result); } - #[CoversNothing()] #[Depends('testInstallPlugin')] public function test_version_is_consistent_across_files() { @@ -980,7 +978,6 @@ public function test_version_is_consistent_across_files() $this->assertStringContainsString($setup_version, $supported_versions_table, "Current version '$setup_version' not found in Supported Versions table in SECURITY.md"); } - #[CoversNothing()] #[Depends('testInstallPlugin')] public function test_tagged_version_is_declared_in_plugin_xml() { From adfe55c382c0f6942a90015bfcbcab5e4bf26fd0 Mon Sep 17 00:00:00 2001 From: btry Date: Thu, 3 Sep 2026 11:10:13 +0200 Subject: [PATCH 07/15] test: fix wrong function name --- tests/units/CarbonEmissionTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/units/CarbonEmissionTest.php b/tests/units/CarbonEmissionTest.php index 84ad9d3c..50369df5 100644 --- a/tests/units/CarbonEmissionTest.php +++ b/tests/units/CarbonEmissionTest.php @@ -209,7 +209,7 @@ public function test_truncate_fails_when_not_logged_in() $this->assertEquals(1, countElementsInTable($table)); } - public function test_truncate_fails_when_user_has_all_required_rights() + public function test_truncate_succeeds_when_user_has_all_required_rights() { /** @var DBmysql $DB */ global $DB; From 9f646f41ccd2441d816b8b3a9de7e4c32feb32c9 Mon Sep 17 00:00:00 2001 From: btry Date: Thu, 3 Sep 2026 11:19:05 +0200 Subject: [PATCH 08/15] docs(test): document array --- tests/install/PluginInstallTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/install/PluginInstallTest.php b/tests/install/PluginInstallTest.php index f0bc92c0..3d4a0401 100644 --- a/tests/install/PluginInstallTest.php +++ b/tests/install/PluginInstallTest.php @@ -607,6 +607,10 @@ public function test_dashboard_is_configured() } } + /** + * Summary of zones + * @var array + */ private $zones = [ 'Afghanistan', 'Albania', From b4ea8c1cc6bd82b7f829fc109f92b8e413d528b0 Mon Sep 17 00:00:00 2001 From: btry Date: Thu, 3 Sep 2026 12:04:09 +0200 Subject: [PATCH 09/15] feat(Config): compatibility with GLPI 12 --- src/Config.php | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/Config.php b/src/Config.php index 35aca4ca..03e728d6 100644 --- a/src/Config.php +++ b/src/Config.php @@ -147,6 +147,32 @@ public function showForm($ID, $options = []) return true; } + /** + * Set config values : create or update entry + * + * @param string $context context to get values (default for glpi is core) + * @param array $values config names to set + * + * @return void + */ + public static function setConfigurationValues($context, array $values = []) + { + GlpiConfig::setConfigurationValues($context, $values); + } + + /** + * Get config value + * + * @param $context string context to get values (default for glpi is core) + * @param $name string config name + * + * @return mixed + */ + public static function getConfigurationValue(string $context, string $name) + { + return GlpiConfig::getConfigurationValue($context, $name); + } + /** * Prepare input for configuration update * From 09e9f9e16efb328c2c16847c27f70a33b3a48461 Mon Sep 17 00:00:00 2001 From: btry Date: Fri, 4 Sep 2026 10:05:19 +0200 Subject: [PATCH 10/15] fix(SearchOptions): use subquery objext instead of raw SQL requred to properly pass parameters for prepared queries --- src/SearchOptions.php | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/SearchOptions.php b/src/SearchOptions.php index 738952e7..774204f4 100644 --- a/src/SearchOptions.php +++ b/src/SearchOptions.php @@ -220,18 +220,22 @@ public static function getCoreSearchOptions(string $itemtype): array $fallback_carbon_intensity_subquery = Location::getCarbonIntensityDataSourceRequest([ Location::getTableField('id') => new QueryExpression('glpi_plugin_carbon_locations_3d6da7fccf9233a3f1a4e41183391a41.id'), ]); - $fallback_carbon_intensity_subquery = (new QuerySubQuery($fallback_carbon_intensity_subquery))->getQuery(); - $computation = "IF(`glpi_computers_id_963cd5e903dddc7ab00a3b70933369df`.`is_deleted` = 0 - AND `glpi_computers_id_963cd5e903dddc7ab00a3b70933369df`.`is_template` = 0 - AND `glpi_plugin_carbon_locations_3d6da7fccf9233a3f1a4e41183391a41`.`plugin_carbon_sources_zones_id` > 0 - AND `glpi_plugin_carbon_computerusageprofiles_09f8403aa14af64cd70f350288a0331b`.`id` > 0" - // Do not check if an asset is ignored - // . "AND COALESCE(`glpi_plugin_carbon_computertypes_a643ab3ffd70abf99533ed214da87d60`.`is_ignore`, 0) = 0" - . " AND ( - `glpi_plugin_carbon_computertypes_a643ab3ffd70abf99533ed214da87d60`.`power_consumption` > 0 - OR `glpi_computermodels`.`power_consumption` > 0 - ) - AND ($fallback_carbon_intensity_subquery) > 0, 1, 0)"; + $fallback_carbon_intensity_subquery = (new QuerySubQuery($fallback_carbon_intensity_subquery)); + $computation = new QueryExpression( + "IF(`glpi_computers_id_963cd5e903dddc7ab00a3b70933369df`.`is_deleted` = 0 + AND `glpi_computers_id_963cd5e903dddc7ab00a3b70933369df`.`is_template` = 0 + AND `glpi_plugin_carbon_locations_3d6da7fccf9233a3f1a4e41183391a41`.`plugin_carbon_sources_zones_id` > 0 + AND `glpi_plugin_carbon_computerusageprofiles_09f8403aa14af64cd70f350288a0331b`.`id` > 0" + // Do not check if an asset is ignored + // . "AND COALESCE(`glpi_plugin_carbon_computertypes_a643ab3ffd70abf99533ed214da87d60`.`is_ignore`, 0) = 0" + . " AND ( + `glpi_plugin_carbon_computertypes_a643ab3ffd70abf99533ed214da87d60`.`power_consumption` > 0 + OR `glpi_computermodels`.`power_consumption` > 0 + ) + AND ($fallback_carbon_intensity_subquery) > 0, 1, 0)", + null, + $fallback_carbon_intensity_subquery->getParams() + ); $sopt[] = [ 'id' => SearchOptions::IS_HISTORIZABLE, 'table' => getTableForItemType($itemtype), From ba669e28f592f6a50ab0fbed0326a856389212b8 Mon Sep 17 00:00:00 2001 From: btry Date: Fri, 4 Sep 2026 10:44:34 +0200 Subject: [PATCH 11/15] chore(dependencies): update dependencies --- composer.json | 2 +- composer.lock | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/composer.json b/composer.json index a0241e08..364efb73 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,7 @@ "php-http/message-factory": "^1.1" }, "require-dev": { - "glpi-project/tools": "^0.8.1", + "glpi-project/tools": "^0.8", "marcocesarato/php-conventional-changelog": "^1.17" }, "config": { diff --git a/composer.lock b/composer.lock index 3a534dbe..f5b53d20 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "a821ef4c2ae32d2c6dce28a1a3b4ceb9", + "content-hash": "21e2edb08d5c5905a3ed659864e7682c", "packages": [ { "name": "clue/stream-filter", @@ -826,16 +826,16 @@ }, { "name": "symfony/console", - "version": "v6.4.44", + "version": "v6.4.45", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "60e3944c4859c487aa6ea2f0f7754917f70f7524" + "reference": "3b8473e0d14157f2d22b0a0d7259ad23483d1e6d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/60e3944c4859c487aa6ea2f0f7754917f70f7524", - "reference": "60e3944c4859c487aa6ea2f0f7754917f70f7524", + "url": "https://api.github.com/repos/symfony/console/zipball/3b8473e0d14157f2d22b0a0d7259ad23483d1e6d", + "reference": "3b8473e0d14157f2d22b0a0d7259ad23483d1e6d", "shasum": "" }, "require": { @@ -900,7 +900,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.44" + "source": "https://github.com/symfony/console/tree/v6.4.45" }, "funding": [ { @@ -920,7 +920,7 @@ "type": "tidelift" } ], - "time": "2026-08-21T07:42:12+00:00" + "time": "2026-08-25T13:08:31+00:00" }, { "name": "symfony/deprecation-contracts", @@ -1330,16 +1330,16 @@ }, { "name": "symfony/service-contracts", - "version": "v3.7.1", + "version": "v3.7.3", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0" + "reference": "15e6a07ec2a2c75ceb1b21dd98105ee8456d2257" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/c0a284bab1ed8aa0417e3d69250ab437739563a0", - "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/15e6a07ec2a2c75ceb1b21dd98105ee8456d2257", + "reference": "15e6a07ec2a2c75ceb1b21dd98105ee8456d2257", "shasum": "" }, "require": { @@ -1393,7 +1393,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.7.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.7.3" }, "funding": [ { @@ -1413,7 +1413,7 @@ "type": "tidelift" } ], - "time": "2026-06-16T09:55:08+00:00" + "time": "2026-07-27T15:39:01+00:00" }, { "name": "symfony/string", From 22f3e933d9fe08c9f4d5cbd4970e4bd4a0f273ef Mon Sep 17 00:00:00 2001 From: btry Date: Fri, 4 Sep 2026 13:53:54 +0200 Subject: [PATCH 12/15] test: fix phpunit notices replace mocks with stubs in many places, because no expectations defined for these objects --- tests/units/CarbonIntensityTest.php | 12 ++++------- tests/units/ComputerTypeTest.php | 20 +++++-------------- tests/units/ComputerUsageProfileTest.php | 4 +--- .../CarbonIntensity/AbstractClientTest.php | 4 ++-- tests/units/Impact/Usage/EngineTest.php | 3 +-- tests/units/LocationTest.php | 6 ++---- tests/units/MonitorTypeTest.php | 12 +++-------- tests/units/NetworkEquipmentTypeTest.php | 12 +++-------- 8 files changed, 21 insertions(+), 52 deletions(-) diff --git a/tests/units/CarbonIntensityTest.php b/tests/units/CarbonIntensityTest.php index 932014d5..859df289 100644 --- a/tests/units/CarbonIntensityTest.php +++ b/tests/units/CarbonIntensityTest.php @@ -299,9 +299,7 @@ public function testGetDownloadStartDate() { $instance = new CarbonIntensity(); - $data_source = $this->getMockBuilder(AbstractClient::class) - ->getMock(); - $result = $instance->getDownloadStartDate('foo', $data_source); + $result = $instance->getDownloadStartDate(); $expected = (new DateTime('13 months ago'))->setTime(0, 0, 0); // CarbonIntensity::MIN_HISTORY_LENGTH $this->assertEquals($expected, $result); @@ -312,7 +310,7 @@ public function testGetDownloadStartDate() 'buy_date' => '2022-02-01', ]); - $result = $instance->getDownloadStartDate('foo', $data_source); + $result = $instance->getDownloadStartDate(); $expected = (new DateTime('2022-02-01'))->setTime(0, 0, 0); // CarbonIntensity::MIN_HISTORY_LENGTH $this->assertEquals($expected, $result); } @@ -366,8 +364,7 @@ public function testDownloadOneZone() $zone::getForeignKeyField() => $zone->getID(), ]); - $data_source = $this->getMockBuilder(AbstractClient::class) - ->getMock(); + $data_source = $this->createStub(AbstractClient::class); $hours = null; $data_source->method('fullDownload')->willReturnCallback( function ($zone_name, $gap_start, $gap_end, $carbon_intensity, $limit, $progress_bar) use (&$hours) { @@ -379,8 +376,7 @@ function ($zone_name, $gap_start, $gap_end, $carbon_intensity, $limit, $progress $data_source->method('getHardStartDate')->willReturn( DateTimeImmutable::createFromFormat(DateTimeInterface::ATOM, '2021-01-01T00:00:00+00:00'), ); - $output = $this->getMockBuilder(Output::class) - ->getMock(); + $output = $this->createStub(Output::class); $progress_bar = new ProgressBar($output); $instance = new CarbonIntensity(); diff --git a/tests/units/ComputerTypeTest.php b/tests/units/ComputerTypeTest.php index 89db56c3..d44560af 100644 --- a/tests/units/ComputerTypeTest.php +++ b/tests/units/ComputerTypeTest.php @@ -124,9 +124,7 @@ public function testUpdateCategory() public function testShowMassiveActionsSubForm() { // Test power consumption update form - $massive_action = $this->getMockBuilder(MassiveAction::class) - ->disableOriginalConstructor() - ->getMock(); + $massive_action = $this->createStub(MassiveAction::class); $massive_action->method('getAction')->willReturn('MassUpdatePower'); $massive_action->method('getItems')->willReturn([ ComputerType::class => $this->createItem(GlpiComputerType::class), @@ -153,9 +151,7 @@ public function testShowMassiveActionsSubForm() $this->assertTrue($result); // Test category update form - $massive_action = $this->getMockBuilder(MassiveAction::class) - ->disableOriginalConstructor() - ->getMock(); + $massive_action = $this->createStub(MassiveAction::class); $massive_action->method('getAction')->willReturn('MassUpdateCategory'); $massive_action->method('getItems')->willReturn([ ComputerType::class => $this->createItem(GlpiComputerType::class), @@ -181,9 +177,7 @@ public function testShowMassiveActionsSubForm() $this->assertTrue($result); // Test invalid action - $massive_action = $this->getMockBuilder(MassiveAction::class) - ->disableOriginalConstructor() - ->getMock(); + $massive_action = $this->createStub(MassiveAction::class); $massive_action->method('getAction')->willReturn(''); $massive_action->method('getItems')->willReturn([ ComputerType::class => $this->createItem(GlpiComputerType::class), @@ -200,9 +194,7 @@ public function testShowMassiveActionsSubForm() public function testProcessMassiveActionForOneItemtype() { // Test create power consumption - $massive_action = $this->getMockBuilder(MassiveAction::class) - ->disableOriginalConstructor() - ->getMock(); + $massive_action = $this->createStub(MassiveAction::class); $massive_action->method('getAction')->willReturn('MassUpdatePower'); $glpi_computer_type = $this->createItem(GlpiComputerType::class); $massive_action->POST = [ @@ -222,9 +214,7 @@ public function testProcessMassiveActionForOneItemtype() $this->assertEquals(25, $computer_type->fields['power_consumption']); // Test update category - $massive_action = $this->getMockBuilder(MassiveAction::class) - ->disableOriginalConstructor() - ->getMock(); + $massive_action = $this->createStub(MassiveAction::class); $massive_action->method('getAction')->willReturn('MassUpdateCategory'); $glpi_computer_type = $this->createItem(GlpiComputerType::class); $massive_action->POST = [ diff --git a/tests/units/ComputerUsageProfileTest.php b/tests/units/ComputerUsageProfileTest.php index b63e38a4..cd4a7503 100644 --- a/tests/units/ComputerUsageProfileTest.php +++ b/tests/units/ComputerUsageProfileTest.php @@ -180,9 +180,7 @@ public function testAssignToItem() public function testShowMassiveActionsSubForm() { // Test power consumption update form - $massive_action = $this->getMockBuilder(MassiveAction::class) - ->disableOriginalConstructor() - ->getMock(); + $massive_action = $this->createStub(MassiveAction::class); $massive_action->method('getAction')->willReturn('MassAssociateItems'); $massive_action->method('getItems')->willReturn([ GlpiComputer::class => $this->createItem(GlpiComputer::class), diff --git a/tests/units/DataSource/CarbonIntensity/AbstractClientTest.php b/tests/units/DataSource/CarbonIntensity/AbstractClientTest.php index 2ffe9ca7..aa8d7719 100644 --- a/tests/units/DataSource/CarbonIntensity/AbstractClientTest.php +++ b/tests/units/DataSource/CarbonIntensity/AbstractClientTest.php @@ -126,7 +126,7 @@ public function testSliceDateRangeByMonth() { foreach ($this->sliceDateRangeByMonthProvider() as $data) { [$start, $stop, $expected] = $data; - $stub = $this->getMockBuilder(AbstractClient::class)->getMock(); + $stub = $this->createStub(AbstractClient::class); $output = $this->callPrivateMethod($stub, 'sliceDateRangeByMonth', $start, $stop); if (count($expected) === 0) { @@ -175,7 +175,7 @@ public function testSliceDateRangeByDay() { foreach ($this->sliceDateRangeByDayProvider() as $data) { [$start, $stop, $expected] = $data; - $stub = $this->getMockBuilder(AbstractClient::class)->getMock(); + $stub = $this->createStub(AbstractClient::class); $output = $this->callPrivateMethod($stub, 'sliceDateRangeByDay', $start, $stop); if (count($expected) === 0) { diff --git a/tests/units/Impact/Usage/EngineTest.php b/tests/units/Impact/Usage/EngineTest.php index 69ba8e39..adbc725b 100644 --- a/tests/units/Impact/Usage/EngineTest.php +++ b/tests/units/Impact/Usage/EngineTest.php @@ -54,8 +54,7 @@ public function testGetEngineFromItemtypeForBoavizta() $version_response = [ '1.3.11', ]; - $client_stub = $this->getMockBuilder(RestApiClient::class) - ->getMock(); + $client_stub = $this->createStub(RestApiClient::class); $client_stub->method('request')->willReturn($version_response); $item = $this->createItem(GlpiComputer::class); diff --git a/tests/units/LocationTest.php b/tests/units/LocationTest.php index 7596a3af..0895cf2c 100644 --- a/tests/units/LocationTest.php +++ b/tests/units/LocationTest.php @@ -120,8 +120,7 @@ public function testOnGlpiLocationAdd() $this->assertEquals('FRA', $location->fields['boavizta_zone']); // Test the geocoding feature - $geocoder = $this->getMockBuilder(Geocoder::class) - ->getMock(); + $geocoder = $this->createStub(Geocoder::class); $geocoder->method('geocodeQuery')->willReturn( new AddressCollection([ new NominatimAddress( @@ -177,8 +176,7 @@ public function testOnGlpiLocationPreUpdate() $this->assertEquals('FRA', $location->fields['boavizta_zone']); // Test the geocoding feature - $geocoder = $this->getMockBuilder(Geocoder::class) - ->getMock(); + $geocoder = $this->createStub(Geocoder::class); $geocoder->method('geocodeQuery')->willReturn( new AddressCollection([ new NominatimAddress( diff --git a/tests/units/MonitorTypeTest.php b/tests/units/MonitorTypeTest.php index 49010bfc..ccd4fa83 100644 --- a/tests/units/MonitorTypeTest.php +++ b/tests/units/MonitorTypeTest.php @@ -78,9 +78,7 @@ public function testUpdatePowerConsumption() public function testShowMassiveActionsSubForm() { - $massive_action = $this->getMockBuilder(MassiveAction::class) - ->disableOriginalConstructor() - ->getMock(); + $massive_action = $this->createStub(MassiveAction::class); $massive_action->method('getAction')->willReturn('MassUpdatePower'); $massive_action->method('getItems')->willReturn([ MonitorType::class => $this->createItem(GlpiMonitorType::class), @@ -106,9 +104,7 @@ public function testShowMassiveActionsSubForm() }); $this->assertTrue($result); - $massive_action = $this->getMockBuilder(MassiveAction::class) - ->disableOriginalConstructor() - ->getMock(); + $massive_action = $this->createStub(MassiveAction::class); $massive_action->method('getAction')->willReturn(''); $massive_action->method('getItems')->willReturn([ MonitorType::class => $this->createItem(GlpiMonitorType::class), @@ -125,9 +121,7 @@ public function testShowMassiveActionsSubForm() public function testProcessMassiveActionForOneItemtype() { // Test update power consumption - $massive_action = $this->getMockBuilder(MassiveAction::class) - ->disableOriginalConstructor() - ->getMock(); + $massive_action = $this->createStub(MassiveAction::class); $massive_action->method('getAction')->willReturn('MassUpdatePower'); $glpi_monitor_type = $this->createItem(GlpiMonitorType::class); $massive_action->POST = [ diff --git a/tests/units/NetworkEquipmentTypeTest.php b/tests/units/NetworkEquipmentTypeTest.php index c502edee..782dbf6d 100644 --- a/tests/units/NetworkEquipmentTypeTest.php +++ b/tests/units/NetworkEquipmentTypeTest.php @@ -78,9 +78,7 @@ public function testUpdatePowerConsumption() public function testShowMassiveActionsSubForm() { - $massive_action = $this->getMockBuilder(MassiveAction::class) - ->disableOriginalConstructor() - ->getMock(); + $massive_action = $this->createStub(MassiveAction::class); $massive_action->method('getAction')->willReturn('MassUpdatePower'); $massive_action->method('getItems')->willReturn([ NetworkEquipmentType::class => $this->createItem(GlpiNetworkEquipmentType::class), @@ -106,9 +104,7 @@ public function testShowMassiveActionsSubForm() }); $this->assertTrue($result); - $massive_action = $this->getMockBuilder(MassiveAction::class) - ->disableOriginalConstructor() - ->getMock(); + $massive_action = $this->createStub(MassiveAction::class); $massive_action->method('getAction')->willReturn(''); $massive_action->method('getItems')->willReturn([ NetworkEquipmentType::class => $this->createItem(GlpiNetworkEquipmentType::class), @@ -125,9 +121,7 @@ public function testShowMassiveActionsSubForm() public function testProcessMassiveActionForOneItemtype() { // Test update power consumption - $massive_action = $this->getMockBuilder(MassiveAction::class) - ->disableOriginalConstructor() - ->getMock(); + $massive_action = $this->createStub(MassiveAction::class); $massive_action->method('getAction')->willReturn('MassUpdatePower'); $glpi_networkequipment_type = $this->createItem(GlpiNetworkEquipmentType::class); $networkequipment_type = $this->createItem(NetworkEquipmentType::class, [ From 5277030f2c2d0d76e6c3582b563f8d679c37e14c Mon Sep 17 00:00:00 2001 From: btry Date: Fri, 4 Sep 2026 14:08:01 +0200 Subject: [PATCH 13/15] test: remove deprecated attributes fir phpunit --- tests/migration/migration_to_1_2_0_Test.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/migration/migration_to_1_2_0_Test.php b/tests/migration/migration_to_1_2_0_Test.php index b2af6b9f..ab29691d 100644 --- a/tests/migration/migration_to_1_2_0_Test.php +++ b/tests/migration/migration_to_1_2_0_Test.php @@ -38,7 +38,6 @@ use GlpiPlugin\Carbon\Uninstall; use Location as GlpiLocation; use Migration; -use PHPUnit\Framework\Attributes\CoversNothing; use Plugin; class migration_to_1_2_0_Test extends CommonTestCase @@ -60,7 +59,6 @@ public function setUp(): void $success = $DB->runFile(realpath($sql_file)); } - #[CoversNothing] public function testUpdateCountryLocationZoneRelation() { /** @var DBmysql $DB */ @@ -110,7 +108,6 @@ public function testUpdateCountryLocationZoneRelation() $this->assertEquals($expected, $result->current()); } - #[CoversNothing] public function testUpdateStateLocationZoneRelation() { /** @var DBmysql $DB */ @@ -159,7 +156,6 @@ public function testUpdateStateLocationZoneRelation() $this->assertEquals($expected, $result->current()); } - #[CoversNothing] public function testTimeformatInUsageProfile() { global $DB; From db80f3b3b7b0b12b4fa1e16efdeee11032d724de Mon Sep 17 00:00:00 2001 From: btry Date: Fri, 4 Sep 2026 13:19:12 +0000 Subject: [PATCH 14/15] fix(install): newline after completing fallback data installation --- install/install/init_datasources.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/install/install/init_datasources.php b/install/install/init_datasources.php index a195c0fa..b70935e7 100644 --- a/install/install/init_datasources.php +++ b/install/install/init_datasources.php @@ -125,7 +125,9 @@ $progress_bar->setProgress($rows_count); } $file = null; // close the file - + if (isset($output)) { + $output->writeln(""); + } Config::setPluginConfigurationValues(['ember_dataset_date' => EMBER_DATASET_DATE]); } From a077afce580867532edc7c927426ad4e945e0a3d Mon Sep 17 00:00:00 2001 From: btry Date: Fri, 4 Sep 2026 15:26:45 +0200 Subject: [PATCH 15/15] chore: remove obsolete dependency --- composer.json | 1 - composer.lock | 184 +++++++------------------------------------------- 2 files changed, 24 insertions(+), 161 deletions(-) diff --git a/composer.json b/composer.json index 364efb73..8cba91a4 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,6 @@ "php-http/message-factory": "^1.1" }, "require-dev": { - "glpi-project/tools": "^0.8", "marcocesarato/php-conventional-changelog": "^1.17" }, "config": { diff --git a/composer.lock b/composer.lock index f5b53d20..547f38e4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "21e2edb08d5c5905a3ed659864e7682c", + "content-hash": "108f5d181fd03cee818d694c22fa7d8b", "packages": [ { "name": "clue/stream-filter", @@ -637,62 +637,6 @@ } ], "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": "marcocesarato/php-conventional-changelog", "version": "1.17.3", @@ -826,47 +770,47 @@ }, { "name": "symfony/console", - "version": "v6.4.45", + "version": "v7.4.18", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "3b8473e0d14157f2d22b0a0d7259ad23483d1e6d" + "reference": "23d6f88a29f6d0eac45bd77d70307adf83ba7ab0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/3b8473e0d14157f2d22b0a0d7259ad23483d1e6d", - "reference": "3b8473e0d14157f2d22b0a0d7259ad23483d1e6d", + "url": "https://api.github.com/repos/symfony/console/zipball/23d6f88a29f6d0eac45bd77d70307adf83ba7ab0", + "reference": "23d6f88a29f6d0eac45bd77d70307adf83ba7ab0", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "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" + "symfony/string": "^7.2|^8.0" }, "conflict": { - "symfony/dependency-injection": "<5.4", - "symfony/dotenv": "<5.4", - "symfony/event-dispatcher": "<5.4", - "symfony/lock": "<5.4", - "symfony/process": "<5.4" + "symfony/dependency-injection": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/lock": "<6.4", + "symfony/process": "<6.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" + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/lock": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -900,7 +844,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.45" + "source": "https://github.com/symfony/console/tree/v7.4.18" }, "funding": [ { @@ -920,7 +864,7 @@ "type": "tidelift" } ], - "time": "2026-08-25T13:08:31+00:00" + "time": "2026-08-25T14:18:37+00:00" }, { "name": "symfony/deprecation-contracts", @@ -1505,86 +1449,6 @@ } ], "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" } ], "aliases": [],