diff --git a/front/computermodel.form.php b/front/computermodel.form.php new file mode 100644 index 00000000..5a3409cb --- /dev/null +++ b/front/computermodel.form.php @@ -0,0 +1,53 @@ +. + * + * ------------------------------------------------------------------------- + */ + +use Glpi\Exception\Http\NotFoundHttpException; +use GlpiPlugin\Carbon\ComputerModel; + +include(__DIR__ . '/../../../inc/includes.php'); + +if (!Plugin::isPluginActive('carbon')) { + throw new NotFoundHttpException(); +} + +Session::checkRight('config', UPDATE); + +$item = new ComputerModel(); + +if (isset($_POST['update'])) { + // Add a new Form + Session::checkRight('entity', UPDATE); + $item->update($_POST); + Html::back(); +} + +Html::back(); diff --git a/front/embodiedimpact.form.php b/front/embodiedimpact.form.php index b588851c..24a1ba6a 100644 --- a/front/embodiedimpact.form.php +++ b/front/embodiedimpact.form.php @@ -32,9 +32,7 @@ use Glpi\Event; use Glpi\Exception\Http\NotFoundHttpException; -use GlpiPlugin\Carbon\Config; use GlpiPlugin\Carbon\EmbodiedImpact; -use GlpiPlugin\Carbon\Impact\Embodied\AbstractEmbodiedImpact; use GlpiPlugin\Carbon\Impact\Embodied\Engine; include(__DIR__ . '/../../../inc/includes.php'); diff --git a/front/monitormodel.form.php b/front/monitormodel.form.php new file mode 100644 index 00000000..01ecccd8 --- /dev/null +++ b/front/monitormodel.form.php @@ -0,0 +1,54 @@ +. + * + * ------------------------------------------------------------------------- + */ + +use Glpi\Exception\Http\NotFoundHttpException; +use GlpiPlugin\Carbon\MonitorModel; + +include(__DIR__ . '/../../../inc/includes.php'); + +if (!Plugin::isPluginActive('carbon')) { + throw new NotFoundHttpException(); +} + + +Session::checkRight('config', UPDATE); + +$item = new MonitorModel(); + +if (isset($_POST['update'])) { + // Add a new Form + Session::checkRight('entity', UPDATE); + $item->update($_POST); + Html::back(); +} + +Html::back(); diff --git a/front/networkequipmentmodel.form.php b/front/networkequipmentmodel.form.php new file mode 100644 index 00000000..ff13a764 --- /dev/null +++ b/front/networkequipmentmodel.form.php @@ -0,0 +1,54 @@ +. + * + * ------------------------------------------------------------------------- + */ + +use Glpi\Exception\Http\NotFoundHttpException; +use GlpiPlugin\Carbon\NetworkEquipmentModel; + +include(__DIR__ . '/../../../inc/includes.php'); + +if (!Plugin::isPluginActive('carbon')) { + throw new NotFoundHttpException(); +} + + +Session::checkRight('config', UPDATE); + +$item = new NetworkEquipmentModel(); + +if (isset($_POST['update'])) { + // Add a new Form + Session::checkRight('entity', UPDATE); + $item->update($_POST); + Html::back(); +} + +Html::back(); diff --git a/install/mysql/plugin_carbon_empty.sql b/install/mysql/plugin_carbon_empty.sql index 31bc8fd9..da2f1360 100644 --- a/install/mysql/plugin_carbon_empty.sql +++ b/install/mysql/plugin_carbon_empty.sql @@ -89,6 +89,22 @@ CREATE TABLE IF NOT EXISTS `glpi_plugin_carbon_sources_zones` ( UNIQUE KEY `unicity` (`plugin_carbon_sources_id`, `plugin_carbon_zones_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +CREATE TABLE IF NOT EXISTS `glpi_plugin_carbon_computermodels` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `computermodels_id` int unsigned NOT NULL DEFAULT '0', + `gwp` int DEFAULT '0' COMMENT '(unit gCO2eq) Global warming potential', + `gwp_source` mediumtext DEFAULT NULL COMMENT 'any information to describe the source, URL preferred', + `gwp_quality` int DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `adp` int DEFAULT '0' COMMENT '(unit gSbEq) Abiotic depletion potential', + `adp_source` mediumtext DEFAULT NULL COMMENT 'any information to describe the source, URL preferred', + `adp_quality` int DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `pe` int DEFAULT '0' COMMENT '(unit J) Primary energy', + `pe_source` mediumtext DEFAULT NULL COMMENT 'any information to describe the source, URL preferred', + `pe_quality` int DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + PRIMARY KEY (`id`), + UNIQUE KEY `unicity` (`computermodels_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + CREATE TABLE IF NOT EXISTS `glpi_plugin_carbon_computertypes` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `computertypes_id` int unsigned NOT NULL DEFAULT '0', @@ -139,6 +155,22 @@ CREATE TABLE IF NOT EXISTS `glpi_plugin_carbon_environmentalimpacts` ( UNIQUE KEY `unicity` (`computers_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +CREATE TABLE IF NOT EXISTS `glpi_plugin_carbon_monitormodels` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `monitormodels_id` int unsigned NOT NULL DEFAULT '0', + `gwp` int DEFAULT '0' COMMENT '(unit gCO2eq) Global warming potential', + `gwp_source` mediumtext DEFAULT NULL COMMENT 'any information to describe the source, URL preferred', + `gwp_quality` int DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `adp` int DEFAULT '0' COMMENT '(unit gSbEq) Abiotic depletion potential', + `adp_source` mediumtext DEFAULT NULL COMMENT 'any information to describe the source, URL preferred', + `adp_quality` int DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `pe` int DEFAULT '0' COMMENT '(unit J) Primary energy', + `pe_source` mediumtext DEFAULT NULL COMMENT 'any information to describe the source, URL preferred', + `pe_quality` int DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + PRIMARY KEY (`id`), + UNIQUE KEY `unicity` (`monitormodels_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + CREATE TABLE IF NOT EXISTS `glpi_plugin_carbon_monitortypes` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `monitortypes_id` int unsigned NOT NULL DEFAULT '0', @@ -148,6 +180,22 @@ CREATE TABLE IF NOT EXISTS `glpi_plugin_carbon_monitortypes` ( UNIQUE KEY `unicity` (`monitortypes_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +CREATE TABLE IF NOT EXISTS `glpi_plugin_carbon_networkequipmentmodels` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `networkequipmentmodels_id` int unsigned NOT NULL DEFAULT '0', + `gwp` int DEFAULT '0' COMMENT '(unit gCO2eq) Global warming potential', + `gwp_source` mediumtext DEFAULT NULL COMMENT 'any information to describe the source, URL preferred', + `gwp_quality` int DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `adp` int DEFAULT '0' COMMENT '(unit gSbEq) Abiotic depletion potential', + `adp_source` mediumtext DEFAULT NULL COMMENT 'any information to describe the source, URL preferred', + `adp_quality` int DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `pe` int DEFAULT '0' COMMENT '(unit J) Primary energy', + `pe_source` mediumtext DEFAULT NULL COMMENT 'any information to describe the source, URL preferred', + `pe_quality` int DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + PRIMARY KEY (`id`), + UNIQUE KEY `unicity` (`networkequipmentmodels_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + CREATE TABLE IF NOT EXISTS `glpi_plugin_carbon_networkequipmenttypes` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `networkequipmenttypes_id` int unsigned NOT NULL DEFAULT '0', diff --git a/setup.php b/setup.php index 8bc52c66..3e421701 100644 --- a/setup.php +++ b/setup.php @@ -43,7 +43,7 @@ use GlpiPlugin\Carbon\Location; define('PLUGIN_CARBON_VERSION', '1.2.0-dev'); -define('PLUGIN_CARBON_SCHEMA_VERSION', '1.1.0'); +define('PLUGIN_CARBON_SCHEMA_VERSION', '1.2.0'); // Minimal GLPI version, inclusive define("PLUGIN_CARBON_MIN_GLPI_VERSION", "11.0.0-beta"); @@ -143,10 +143,15 @@ function plugin_carbon_registerClasses() Plugin::registerClass(Location::class, ['addtabon' => GlpiLocation::class]); foreach (PLUGIN_CARBON_TYPES as $itemtype) { - $item_type_class = 'GlpiPlugin\\Carbon\\' . $itemtype . 'Type'; $core_type_class = $itemtype . 'Type'; + $item_type_class = 'GlpiPlugin\\Carbon\\' . $core_type_class; Plugin::registerClass($item_type_class, ['addtabon' => $core_type_class]); + Plugin::registerClass(UsageInfo::class, ['addtabon' => $itemtype]); + + $core_model_class = $itemtype . 'Model'; + $item_model_class = 'GlpiPlugin\\Carbon\\' . $core_model_class; + Plugin::registerClass($item_model_class, ['addtabon' => $core_model_class]); } } diff --git a/src/AbstractModel.php b/src/AbstractModel.php new file mode 100644 index 00000000..950cf3ce --- /dev/null +++ b/src/AbstractModel.php @@ -0,0 +1,141 @@ +. + * + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Carbon; + +use CommonDBChild; +use CommonDBTM; +use CommonGLPI; +use Glpi\Application\View\TemplateRenderer; +use Session; + +class AbstractModel extends CommonDBChild +{ + public static $rightname = 'dropdown'; + + public static function getIcon(): string + { + return 'fa-solid fa-solar-panel'; + } + + public static function getTypeName($nb = 0) + { + return _n('Environmental impact', 'Environmental impact', $nb, 'carbon'); + } + + public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) + { + $tabName = ''; + if (!$withtemplate) { + if ($item->getType() == static::$itemtype) { + return self::createTabEntry(__('Carbon', 'carbon'), 0); + } + } + return $tabName; + } + + /** + * Undocumented function + * + * @param CommonGLPI $item + * @param integer $tabnum + * @param integer $withtemplate + * @return void + */ + public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) + { + /** @var CommonDBTM $item */ + if ($item->getType() !== static::$itemtype) { + return; + } + + $type = new static(); + $type->getOrCreate($item); + $type->showForItemType($type->getID()); + } + + /** + * Get the type for the item, creating it if it doesn't exist. + * + * @param CommonGLPI $item + * @return bool + */ + protected function getOrCreate(CommonGLPI $item): bool + { + /** @var CommonDBTM $item */ + $item_fk = $item->getForeignKeyField(); + $this->getFromDBByCrit([$item_fk => $item->getID()]); + if ($this->isNewItem()) { + $this->add([ + $item_fk => $item->getID() + ]); + } + return $this->isNewItem(); + } + + public function showForItemType($ID, $withtemplate = '') + { + // TODO: Design a rights system for the whole plugin + $canedit = Session::haveRight(Config::$rightname, UPDATE); + + $options = [ + 'candel' => false, + 'can_edit' => $canedit, + ]; + $this->initForm($this->getID(), $options); + + $criterias = [ + 'gwp' => [ + 'title' => __('Global warming potential', 'carbon'), + 'label' => __('Emissions of CO2 (KgCO2eq)', 'carbon'), + 'icon' => '', // 'fa-solid fa-temperature-three-quarters' + ], + 'adp' => [ + 'title' => __('Abiotic depletion potential', 'carbon'), + 'label' => __('Abiotic depletion potential (gSbEq)', 'carbon'), + 'icon' => '', // @todo : find an icon + ], + 'pe' => [ + 'title' => __('Primary energy', 'carbon'), + 'label' => __('Primary energy (J)', 'carbon'), + 'icon' => '', // @todo : find an icon + ], + ]; + + $template = strtolower(basename(str_replace('\\', '/', static::class))) . '.html.twig'; + TemplateRenderer::getInstance()->display('@carbon/' . $template, [ + 'params' => $options, + 'item' => $this, + 'criterias' => $criterias, + ]); + } +} diff --git a/src/AbstractType.php b/src/AbstractType.php index 06f09522..02e6bb8a 100644 --- a/src/AbstractType.php +++ b/src/AbstractType.php @@ -42,7 +42,6 @@ abstract class AbstractType extends CommonDBChild { public static $rightname = 'dropdown'; - public static function getIcon(): string { return 'fa-solid fa-solar-panel'; @@ -53,7 +52,7 @@ public static function getIcon(): string */ public static function getTypeName($nb = 0) { - return _n("Power", "Powers", $nb, 'carbon'); + return _n('Environmental impact', 'Environmental impacts', $nb, 'carbon'); } public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) diff --git a/src/ComputerModel.php b/src/ComputerModel.php new file mode 100644 index 00000000..f08fb727 --- /dev/null +++ b/src/ComputerModel.php @@ -0,0 +1,41 @@ +. + * + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Carbon; + +use ComputerModel as GlpiComputerModel; + +class ComputerModel extends AbstractModel +{ + public static $itemtype = GlpiComputerModel::class; + public static $items_id = 'computermodels_id'; +} diff --git a/src/CronTask.php b/src/CronTask.php index c56e7e1a..9d819164 100644 --- a/src/CronTask.php +++ b/src/CronTask.php @@ -37,6 +37,7 @@ use Geocoder\Geocoder; use GlpiPlugin\Carbon\DataSource\CarbonIntensity\ClientFactory; use GlpiPlugin\Carbon\DataSource\CarbonIntensity\ClientInterface; +use GlpiPlugin\Carbon\DataSource\RestApiClient; use GlpiPlugin\Carbon\Impact\Embodied\Engine as EmbodiedEngine; use GlpiPlugin\Carbon\Impact\Usage\UsageImpactInterface as UsageImpactInterface; use GlpiPlugin\Carbon\Impact\Usage\Engine as UsageEngine; @@ -122,10 +123,9 @@ public static function cronUsageImpact(GlpiCronTask $task): int } // Calculate other impacts - $usage_impacts = Toolbox::getUsageImpactClasses(); - foreach ($usage_impacts as $usage_impact_type) { + foreach (PLUGIN_CARBON_TYPES as $itemtype) { /** @ar UsageImpactInterface $usage_impact */ - $usage_impact = UsageEngine::getEngine($usage_impact_type); + $usage_impact = UsageEngine::getEngineFromItemtype($itemtype, new RestApiClient()); if ($usage_impact === null) { continue; } @@ -146,13 +146,12 @@ public static function cronUsageImpact(GlpiCronTask $task): int public static function cronEmbodiedImpact(GlpiCronTask $task): int { $count = 0; - $embodied_impacts = Toolbox::getEmbodiedImpactClasses(); $task->setVolume(0); // start with zero $remaining = $task->fields['param']; $limit_per_type = max(1, floor(($remaining) / count($embodied_impacts))); - foreach ($embodied_impacts as $embodied_impact_type) { - $embodied_impact = EmbodiedEngine::getEngine($embodied_impact_type); + foreach (PLUGIN_CARBON_TYPES as $itemtype) { + $embodied_impact = EmbodiedEngine::getEngineFromItemtype($itemtype, new RestApiClient()); if ($embodied_impact === null) { // An error occured while configuring the engine continue; diff --git a/src/DataSource/RestApiClient.php b/src/DataSource/RestApiClient.php index 6b68f45a..dd46c5d7 100644 --- a/src/DataSource/RestApiClient.php +++ b/src/DataSource/RestApiClient.php @@ -35,7 +35,6 @@ use GuzzleHttp\Client; use GuzzleHttp\Exception\RequestException; use GuzzleHttp\Psr7; -use Session; use Toolbox; class RestApiClient implements RestApiClientInterface diff --git a/src/DataTracking/AbstractTracked.php b/src/DataTracking/AbstractTracked.php index 5b9dd680..7e19117b 100644 --- a/src/DataTracking/AbstractTracked.php +++ b/src/DataTracking/AbstractTracked.php @@ -32,6 +32,7 @@ namespace GlpiPlugin\Carbon\DataTracking; +use Dropdown; use LogicException; /** @@ -64,6 +65,36 @@ public function __construct($source = null) $this->appendSource($source); } + /** + * Get name of data qualities + * + * @return array + */ + public static function getDataQualities(): array + { + return [ + self::DATA_QUALITY_UNSPECIFIED => __('Unspecified quality', 'carbon'), + self::DATA_QUALITY_MANUAL => __('Manual data', 'carbon'), + self::DATA_QUALITY_ESTIMATED => __('Estimated data', 'carbon'), + self::DATA_QUALITY_RAW_REAL_TIME_MEASUREMENT_DOWNSAMPLED => __('Downsampled data', 'carbon'), + self::DATA_QUALITY_RAW_REAL_TIME_MEASUREMENT => __('Measured data', 'carbon'), + ]; + } + + /** + * Show or return HTML code displaying a dropdown of data qualities + * @see constants DATA_QUALITY_* + * + * @param string $name + * @param array $options + * @return integer|string + */ + public static function dropdownQuality(string $name, array $options = []) + { + $items = self::getDataQualities(); + return Dropdown::showFromArray($name, $items, $options); + } + public function getSource(): array { return $this->sources; diff --git a/src/Impact/Embodied/Engine.php b/src/Impact/Embodied/Engine.php index b14a6a60..e562af1c 100644 --- a/src/Impact/Embodied/Engine.php +++ b/src/Impact/Embodied/Engine.php @@ -35,7 +35,8 @@ use CommonGLPI; use GlpiPlugin\Carbon\Config; use GlpiPlugin\Carbon\DataSource\Boaviztapi; -use GlpiPlugin\Carbon\DataSource\RestApiClient; +use GlpiPlugin\Carbon\Impact\Embodied\Boavizta\AbstractAsset; +use GlpiPlugin\Carbon\DataSource\RestApiClientInterface; class Engine extends CommonGLPI { @@ -55,54 +56,61 @@ public static function getAvailableBackends(): array * Returns null if no engine found * * @param string $itemtype itemtype of assets to analyze + * @param ?RestApiClientInterface $client * @return EmbodiedImpactInterface|null an instance if an embodied impact calculation object or null on error */ - public static function getEngineFromItemtype(string $itemtype): ?EmbodiedImpactInterface + public static function getEngineFromItemtype(string $itemtype, ?RestApiClientInterface $client = null): ?EmbodiedImpactInterface { $embodied_impact_namespace = Config::getEmbodiedImpactEngine(); $embodied_impact_class = $embodied_impact_namespace . '\\' . $itemtype; if (!class_exists($embodied_impact_class) || !is_subclass_of($embodied_impact_class, AbstractEmbodiedImpact::class)) { - return null; + return self::getInternalEngineFromItemtype($itemtype); } /** @var AbstractEmbodiedImpact $embodied_impact */ $embodied_impact = new $embodied_impact_class(); try { - return self::configureEngine($embodied_impact); + return self::configureEngine($embodied_impact, $client); } catch (\RuntimeException $e) { // If the engine cannot be configured, it is not usable return null; } } - public static function getEngine(string $engine_class): ?EmbodiedImpactInterface + /** + * Get an instance of the internal engine to calcilate impacts for the given itemtype + * This is a fallback engine + * + * @param string $itemtype + * @return ?EmbodiedImpactInterface + */ + public static function getInternalEngineFromItemtype(string $itemtype): ?EmbodiedImpactInterface { - if (!is_subclass_of($engine_class, EmbodiedImpactInterface::class)) { - return null; - } - $embodied_impact = new $engine_class(); - - try { - return self::configureEngine($embodied_impact); - } catch (\RuntimeException $e) { - // If the engine cannot be configured, it is not usable + $embodied_impact_class = 'GlpiPlugin\\Carbon\\Impact\\Embodied\Internal' . '\\' . $itemtype; + if (!class_exists($embodied_impact_class) || !is_subclass_of($embodied_impact_class, AbstractEmbodiedImpact::class)) { return null; } + $embodied_impact = new $embodied_impact_class(); + return $embodied_impact; } /** * Configure the engine depending on its specificities * * @param EmbodiedImpactInterface $engine the engine to configure + * @param ?RestApiClientInterface $client * @return EmbodiedImpactInterface the configured engine */ - protected static function configureEngine(EmbodiedImpactInterface $engine): EmbodiedImpactInterface + protected static function configureEngine(EmbodiedImpactInterface $engine, ?RestApiClientInterface $client = null): EmbodiedImpactInterface { $embodied_impact_namespace = explode('\\', get_class($engine)); switch (array_slice($embodied_impact_namespace, -2, 1)[0]) { case 'Boavizta': - /** @var Boavizta\AbstractAsset $engine */ - $engine->setClient(new Boaviztapi(new RestApiClient())); + if ($client === null) { + throw new \RuntimeException('A RestApiClientInterface instance is required to configure Boavizta embodied impact engine'); + } + /** @var AbstractAsset $engine */ + $engine->setClient(new Boaviztapi($client)); } return $engine; diff --git a/src/Impact/Embodied/Internal/AbstractAsset.php b/src/Impact/Embodied/Internal/AbstractAsset.php new file mode 100644 index 00000000..341f7939 --- /dev/null +++ b/src/Impact/Embodied/Internal/AbstractAsset.php @@ -0,0 +1,44 @@ +. + * + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Carbon\Impact\Embodied\Internal; + +use GlpiPlugin\Carbon\Impact\Embodied\AbstractEmbodiedImpact; + +abstract class AbstractAsset extends AbstractEmbodiedImpact +{ + /** @var string $engine Name of the calculation engine */ + protected string $engine = 'Internal'; + + /** @var string $engine_version Version of the calculation engine */ + protected string $engine_version = '1'; +} diff --git a/src/Impact/Embodied/Internal/Computer.php b/src/Impact/Embodied/Internal/Computer.php new file mode 100644 index 00000000..0c96194c --- /dev/null +++ b/src/Impact/Embodied/Internal/Computer.php @@ -0,0 +1,100 @@ +. + * + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Carbon\Impact\Embodied\Internal; + +use CommonDBTM; +use Computer as GlpiComputer; +use GlpiPlugin\Carbon\DataTracking\TrackedFloat; +use ComputerModel as GlpiComputerModel; +use GlpiPlugin\Carbon\Impact\Type; + +/** + * This embodied impact + */ +class Computer extends AbstractAsset +{ + protected static string $itemtype = GlpiComputer::class; + + protected function doEvaluation(CommonDBTM $item): ?array + { + if (GlpiComputerModel::isNewID($item->fields['networkequipmentmodels_id'])) { + return []; + } + + $model = new GlpiComputerModel(); + $model->getFromDBByCrit([ + 'networkequipmentmodels_id' => $item->fields['networkequipmentmodels_id'] + ]); + if ($model->isNewItem()) { + return []; + } + + $impacts = []; + $types = Type::getImpactTypes(); + foreach ($types as $type) { + switch ($type) { + case 'gwp': + if (!empty($model->fields['gwp'])) { + $impacts[Type::IMPACT_GWP] = new TrackedFloat( + $model->fields['gwp'] * 1000, // UI Field in KgCO2Eq, + null, + $model->fields['gwp_quality'] + ); + } + break; + + case 'adp': + if (!empty($model->fields['adp'])) { + $impacts[Type::IMPACT_ADP] = new TrackedFloat( + $model->fields['adp'], + null, + $model->fields['adp_quality'] + ); + } + break; + + case 'pe': + if (!empty($model->fields['pe'])) { + $impacts[Type::IMPACT_PE] = new TrackedFloat( + $model->fields['pe'], + null, + $model->fields['pe_quality'] + ); + } + break; + } + } + + return $impacts; + } +} diff --git a/src/Impact/Embodied/Internal/Monitor.php b/src/Impact/Embodied/Internal/Monitor.php new file mode 100644 index 00000000..caac7f6a --- /dev/null +++ b/src/Impact/Embodied/Internal/Monitor.php @@ -0,0 +1,100 @@ +. + * + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Carbon\Impact\Embodied\Internal; + +use CommonDBTM; +use Monitor as GlpiMonitor; +use GlpiPlugin\Carbon\DataTracking\TrackedFloat; +use MonitorModel as GlpiMonitorModel; +use GlpiPlugin\Carbon\Impact\Type; + +/** + * This embodied impact + */ +class Monitor extends AbstractAsset +{ + protected static string $itemtype = GlpiMonitor::class; + + protected function doEvaluation(CommonDBTM $item): ?array + { + if (GlpiMonitorModel::isNewID($item->fields['networkequipmentmodels_id'])) { + return []; + } + + $model = new GlpiMonitorModel(); + $model->getFromDBByCrit([ + 'networkequipmentmodels_id' => $item->fields['networkequipmentmodels_id'] + ]); + if ($model->isNewItem()) { + return []; + } + + $impacts = []; + $types = Type::getImpactTypes(); + foreach ($types as $type) { + switch ($type) { + case 'gwp': + if (!empty($model->fields['gwp'])) { + $impacts[Type::IMPACT_GWP] = new TrackedFloat( + $model->fields['gwp'] * 1000, // UI Field in KgCO2Eq + null, + $model->fields['gwp_quality'] + ); + } + break; + + case 'adp': + if (!empty($model->fields['adp'])) { + $impacts[Type::IMPACT_ADP] = new TrackedFloat( + $model->fields['adp'], + null, + $model->fields['adp_quality'] + ); + } + break; + + case 'pe': + if (!empty($model->fields['pe'])) { + $impacts[Type::IMPACT_PE] = new TrackedFloat( + $model->fields['pe'], + null, + $model->fields['pe_quality'] + ); + } + break; + } + } + + return $impacts; + } +} diff --git a/src/Impact/Embodied/Internal/NetworkEquipment.php b/src/Impact/Embodied/Internal/NetworkEquipment.php new file mode 100644 index 00000000..59b6904a --- /dev/null +++ b/src/Impact/Embodied/Internal/NetworkEquipment.php @@ -0,0 +1,101 @@ +. + * + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Carbon\Impact\Embodied\Internal; + +use CommonDBTM; +use GlpiPlugin\Carbon\DataTracking\TrackedFloat; +use NetworkEquipment as GlpiNetworkEquipment; +use NetworkEquipmentModel as GlpiNetworkEquipmentModel; +use GlpiPlugin\Carbon\Impact\Type; +use GlpiPlugin\Carbon\NetworkEquipmentModel; + +/** + * This embodied impact + */ +class NetworkEquipment extends AbstractAsset +{ + protected static string $itemtype = GlpiNetworkEquipment::class; + + protected function doEvaluation(CommonDBTM $item): ?array + { + if (GlpiNetworkEquipmentModel::isNewID($item->fields['networkequipmentmodels_id'])) { + return []; + } + + $model = new NetworkEquipmentModel(); + $success = $model->getFromDBByCrit([ + 'networkequipmentmodels_id' => $item->fields['networkequipmentmodels_id'] + ]); + if ($success === false) { + return []; + } + + $impacts = []; + $types = Type::getImpactTypes(); + foreach ($types as $type) { + switch ($type) { + case 'gwp': + if (!empty($model->fields['gwp'])) { + $impacts[Type::IMPACT_GWP] = new TrackedFloat( + $model->fields['gwp'] * 1000, // UI Field in KgCO2Eq + null, + $model->fields['gwp_quality'] + ); + } + break; + + case 'adp': + if (!empty($model->fields['adp'])) { + $impacts[Type::IMPACT_ADP] = new TrackedFloat( + $model->fields['adp'], + null, + $model->fields['adp_quality'] + ); + } + break; + + case 'pe': + if (!empty($model->fields['pe'])) { + $impacts[Type::IMPACT_PE] = new TrackedFloat( + $model->fields['pe'], + null, + $model->fields['pe_quality'] + ); + } + break; + } + } + + return $impacts; + } +} diff --git a/src/Impact/Usage/Engine.php b/src/Impact/Usage/Engine.php index b0429722..3b52d110 100644 --- a/src/Impact/Usage/Engine.php +++ b/src/Impact/Usage/Engine.php @@ -36,6 +36,7 @@ use GlpiPlugin\Carbon\Config; use GlpiPlugin\Carbon\DataSource\Boaviztapi; use GlpiPlugin\Carbon\DataSource\RestApiClient; +use GlpiPlugin\Carbon\DataSource\RestApiClientInterface; class Engine extends CommonGLPI { @@ -55,9 +56,10 @@ public static function getAvailableBackends(): array * Returns null if no engine found * * @param string $itemtype itemtype of assets to analyze + * @param ?RestApiClientInterface $client * @return AbstractUsageImpact|null an instance if an embodied impact calculation object or null on error */ - public static function getEngineFromItemtype(string $itemtype): ?AbstractUsageImpact + public static function getEngineFromItemtype(string $itemtype, ?RestApiClientInterface $client = null): ?AbstractUsageImpact { $usage_impact_namespace = Config::getUsageImpactEngine(); $usage_impact_class = $usage_impact_namespace . '\\' . $itemtype; @@ -68,23 +70,7 @@ public static function getEngineFromItemtype(string $itemtype): ?AbstractUsageIm /** @var AbstractUsageImpact $usage_impact */ $usage_impact = new $usage_impact_class(); try { - return self::configureEngine($usage_impact); - } catch (\RuntimeException $e) { - return null; - } - } - - public static function getEngine(string $engine_class): ?AbstractUsageImpact - { - if (!is_subclass_of($engine_class, AbstractUsageImpact::class)) { - return null; - } - - /** @var AbstractUsageImpact $usage_impact */ - $usage_impact = new $engine_class(); - - try { - return self::configureEngine($usage_impact); + return self::configureEngine($usage_impact, $client); } catch (\RuntimeException $e) { return null; } @@ -94,15 +80,16 @@ public static function getEngine(string $engine_class): ?AbstractUsageImpact * Configure the engine depending on its specificities * * @param AbstractUsageImpact $engine the engine to configure + * @param ?RestApiClientInterface $client * @return AbstractUsageImpact the configured engine */ - protected static function configureEngine(AbstractUsageImpact $engine): AbstractUsageImpact + protected static function configureEngine(AbstractUsageImpact $engine, ?RestApiClientInterface $client = null): AbstractUsageImpact { $embodied_impact_namespace = explode('\\', get_class($engine)); switch (array_slice($embodied_impact_namespace, -2, 1)[0]) { case 'Boavizta': /** @var Boavizta\AbstractAsset $engine */ - $engine->setClient(new Boaviztapi(new RestApiClient())); + $engine->setClient(new Boaviztapi($client)); } return $engine; diff --git a/src/MonitorModel.php b/src/MonitorModel.php new file mode 100644 index 00000000..d929e3d2 --- /dev/null +++ b/src/MonitorModel.php @@ -0,0 +1,41 @@ +. + * + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Carbon; + +use MonitorModel as GlpiMonitorModel; + +class MonitorModel extends AbstractModel +{ + public static $itemtype = GlpiMonitorModel::class; + public static $items_id = 'monitormodels_id'; +} diff --git a/src/NetworkEquipmentModel.php b/src/NetworkEquipmentModel.php new file mode 100644 index 00000000..70bde975 --- /dev/null +++ b/src/NetworkEquipmentModel.php @@ -0,0 +1,41 @@ +. + * + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Carbon; + +use NetworkEquipmentModel as GlpiNetworkEquipmentModel; + +class NetworkEquipmentModel extends AbstractModel +{ + public static $itemtype = GlpiNetworkEquipmentModel::class; + public static $items_id = 'networkequipmentmodels_id'; +} diff --git a/src/NetworkEquipmentType.php b/src/NetworkEquipmentType.php index e6021180..2d9bf942 100644 --- a/src/NetworkEquipmentType.php +++ b/src/NetworkEquipmentType.php @@ -57,7 +57,6 @@ public static function showMassiveActionsSubForm(MassiveAction $ma) return parent::showMassiveActionsSubForm($ma); } - public static function processMassiveActionsForOneItemtype(MassiveAction $ma, CommonDBTM $item, array $ids) { switch ($ma->getAction()) { diff --git a/templates/components/form/fields_macros.html.twig b/templates/components/form/fields_macros.html.twig index fb7953e3..10cf5d2e 100644 --- a/templates/components/form/fields_macros.html.twig +++ b/templates/components/form/fields_macros.html.twig @@ -97,3 +97,38 @@ {{ fields.field(name, field, label, options|merge({'id': 'dropdown_' ~ name ~ '_' ~ options.rand})) }} {% endif %} {% endmacro %} + +{% macro dropdownDataQuaity(name, value, label = '', options = {}) %} + {% import 'components/form/fields_macros.html.twig' as fields %} + + {% if options.multiple ?? false %} + {# Needed for empty value as the input wont be sent in this case... we need something to know the input was displayed AND empty #} + {% set defined_input_name = "_#{name}_defined" %} + + + {# Multiple values will be set, input need to be an array #} + {% set name = "#{name}[]" %} + {% endif %} + {% set options = { + 'rand': random(), + 'disabled': false, + }|merge(options) %} + {% if options.fields_template.isMandatoryField(name)|default(false) %} + {% set options = {'specific_tags': {'required': true}}|merge(options) %} + {% endif %} + + {% if options.disabled %} + {% set options = options|merge({specific_tags: {'disabled': 'disabled'}}) %} + {% endif %} + + {% set field %} + {% do call('GlpiPlugin\\Carbon\\DataTracking\\TrackedInt::dropdownQuality', [name, { + 'value': value, + 'rand': options.rand, + 'width': '100%', + }|merge(options)]) %} + {% endset %} + {% if field|trim is not empty %} + {{ fields.field(name, field, label, options|merge({'id': 'dropdown_' ~ name ~ '_' ~ options.rand})) }} + {% endif %} +{% endmacro %} diff --git a/templates/computermodel.html.twig b/templates/computermodel.html.twig new file mode 100644 index 00000000..23272f79 --- /dev/null +++ b/templates/computermodel.html.twig @@ -0,0 +1,60 @@ +{# + # ------------------------------------------------------------------------- + # Carbon plugin for GLPI + # + # @copyright Copyright (C) 2024-2025 Teclib' and contributors. + # @license https://www.gnu.org/licenses/gpl-3.0.txt GPLv3+ + # @license MIT https://opensource.org/licenses/mit-license.php + # @link https://github.com/pluginsGLPI/carbon + # + # ------------------------------------------------------------------------- + # + # LICENSE + # + # This file is part of Carbon plugin for GLPI. + # + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by + # the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU General Public License + # along with this program. If not, see . + # + # ------------------------------------------------------------------------- + #} + +{% extends "generic_show_form.html.twig" %} +{% import "components/form/fields_macros.html.twig" as fields %} +{% import "@carbon/components/form/fields_macros.html.twig" as carbonFields %} + +{% block form_fields %} + {% for key, field_description in criterias %} + {% set criteria = key %} + {% set criteria_source = key ~ '_source' %} + {% set criteria_quality = key ~ '_quality' %} + + {{ fields.smallTitle(field_description.title) }} + + {{ fields.numberField(criteria, + item.fields[criteria], + field_description.label, { + min: 0 + }) }} + + {{ fields.textfield(criteria_source, + item.fields[criteria_source], + __('Data source', 'carbon'), {}) }} + + {{ carbonFields.dropdownDataQuaity(criteria_quality, + item.fields[criteria_quality], + __('Data quality', 'carbon'), { + min: 0 + }) }} + {% endfor %} +{% endblock %} diff --git a/templates/monitormodel.html.twig b/templates/monitormodel.html.twig new file mode 100644 index 00000000..272e794c --- /dev/null +++ b/templates/monitormodel.html.twig @@ -0,0 +1,60 @@ +{# + # ------------------------------------------------------------------------- + # Carbon plugin for GLPI + # + # @copyright Copyright (C) 2024-2025 Teclib' and contributors. + # @license https://www.gnu.org/licenses/gpl-3.0.txt GPLv3+ + # @license MIT https://opensource.org/licenses/mit-license.php + # @link https://github.com/pluginsGLPI/carbon + # + # ------------------------------------------------------------------------- + # + # LICENSE + # + # This file is part of Carbon plugin for GLPI. + # + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by + # the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU General Public License + # along with this program. If not, see . + # + # ------------------------------------------------------------------------- + #} + +{% extends "generic_show_form.html.twig" %} +{% import "components/form/fields_macros.html.twig" as fields %} +{% import "@carbon/components/form/fields_macros.html.twig" as carbonFields %} + +{% block form_fields %} + {% for key, field_description in criterias %} + {% set criteria = key %} + {% set criteria_source = key ~ '_source' %} + {% set criteria_quality = key ~ '_quality' %} + + {{ fields.smallTitle(field_description.title, field_description.icon) }} + + {{ fields.numberField(criteria, + item.fields[criteria], + field_description.label, { + min: 0 + }) }} + + {{ fields.textfield(criteria_source, + item.fields[criteria_source], + __('Data source', 'carbon'), {}) }} + + {{ carbonFields.dropdownDataQuaity(criteria_quality, + item.fields[criteria_quality], + __('Data quality', 'carbon'), { + min: 0 + }) }} + {% endfor %} +{% endblock %} diff --git a/templates/networkequipmentmodel.html.twig b/templates/networkequipmentmodel.html.twig new file mode 100644 index 00000000..23272f79 --- /dev/null +++ b/templates/networkequipmentmodel.html.twig @@ -0,0 +1,60 @@ +{# + # ------------------------------------------------------------------------- + # Carbon plugin for GLPI + # + # @copyright Copyright (C) 2024-2025 Teclib' and contributors. + # @license https://www.gnu.org/licenses/gpl-3.0.txt GPLv3+ + # @license MIT https://opensource.org/licenses/mit-license.php + # @link https://github.com/pluginsGLPI/carbon + # + # ------------------------------------------------------------------------- + # + # LICENSE + # + # This file is part of Carbon plugin for GLPI. + # + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by + # the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU General Public License + # along with this program. If not, see . + # + # ------------------------------------------------------------------------- + #} + +{% extends "generic_show_form.html.twig" %} +{% import "components/form/fields_macros.html.twig" as fields %} +{% import "@carbon/components/form/fields_macros.html.twig" as carbonFields %} + +{% block form_fields %} + {% for key, field_description in criterias %} + {% set criteria = key %} + {% set criteria_source = key ~ '_source' %} + {% set criteria_quality = key ~ '_quality' %} + + {{ fields.smallTitle(field_description.title) }} + + {{ fields.numberField(criteria, + item.fields[criteria], + field_description.label, { + min: 0 + }) }} + + {{ fields.textfield(criteria_source, + item.fields[criteria_source], + __('Data source', 'carbon'), {}) }} + + {{ carbonFields.dropdownDataQuaity(criteria_quality, + item.fields[criteria_quality], + __('Data quality', 'carbon'), { + min: 0 + }) }} + {% endfor %} +{% endblock %} diff --git a/tests/install/PluginInstallTest.php b/tests/install/PluginInstallTest.php index b364c45f..3ba3f42f 100644 --- a/tests/install/PluginInstallTest.php +++ b/tests/install/PluginInstallTest.php @@ -32,6 +32,10 @@ namespace GlpiPlugin\Carbon\Tests; +use CommonGLPI; +use Computer; +use ComputerModel; +use ComputerType; use Session; use Config; use CronTask as GLPICronTask; @@ -49,14 +53,19 @@ use Glpi\Plugin\Hooks; use Glpi\System\Diagnostic\DatabaseSchemaIntegrityChecker; use GlpiPlugin\Carbon\CarbonIntensity; -use GlpiPlugin\Carbon\CarbonIntensitySource; -use GlpiPlugin\Carbon\CarbonIntensitySource_Zone; use GlpiPlugin\Carbon\Source; use GlpiPlugin\Carbon\Source_Zone; use GlpiPlugin\Carbon\Zone; use GlpiPlugin\Carbon\ComputerUsageProfile; use GlpiPlugin\Carbon\CronTask; use GlpiPlugin\Carbon\Report; +use Location; +use Monitor; +use MonitorModel; +use MonitorType; +use NetworkEquipment; +use NetworkEquipmentModel; +use NetworkEquipmentType; class PluginInstallTest extends CommonTestCase { @@ -137,6 +146,7 @@ public function testInstallPlugin() $this->checkDisplayPrefs(); $this->checkPredefinedUsageProfiles(); $this->checkSourceZoneRelation(); + $this->checkRegisteredClasses(); } public function testConfigurationExists() @@ -842,4 +852,55 @@ public function checkSourceZoneRelation() ]); $this->assertEquals(1, $iterator->count()); } + + public function checkRegisteredClasses() + { + $result = CommonGLPI::getOtherTabs(Config::class); + $expected = ['GlpiPlugin\Carbon\Config']; + $this->assertEquals($expected, $result); + + $result = CommonGLPI::getOtherTabs(Profile::class); + $expected = ['GlpiPlugin\Carbon\Profile']; + $this->assertEquals($expected, $result); + + $result = CommonGLPI::getOtherTabs(Location::class); + $expected = ['GlpiPlugin\Carbon\Location']; + $this->assertEquals($expected, $result); + + $result = CommonGLPI::getOtherTabs(Computer::class); + $expected = ['GlpiPlugin\Carbon\UsageInfo']; + $this->assertEquals($expected, $result); + + $result = CommonGLPI::getOtherTabs(Monitor::class); + $expected = ['GlpiPlugin\Carbon\UsageInfo']; + $this->assertEquals($expected, $result); + + $result = CommonGLPI::getOtherTabs(NetworkEquipment::class); + $expected = ['GlpiPlugin\Carbon\UsageInfo']; + $this->assertEquals($expected, $result); + + $result = CommonGLPI::getOtherTabs(ComputerType::class); + $expected = ['GlpiPlugin\Carbon\ComputerType']; + $this->assertEquals($expected, $result); + + $result = CommonGLPI::getOtherTabs(MonitorType::class); + $expected = ['GlpiPlugin\Carbon\MonitorType']; + $this->assertEquals($expected, $result); + + $result = CommonGLPI::getOtherTabs(NetworkEquipmentType::class); + $expected = ['GlpiPlugin\Carbon\NetworkEquipmentType']; + $this->assertEquals($expected, $result); + + $result = CommonGLPI::getOtherTabs(ComputerModel::class); + $expected = ['GlpiPlugin\Carbon\ComputerModel']; + $this->assertEquals($expected, $result); + + $result = CommonGLPI::getOtherTabs(MonitorModel::class); + $expected = ['GlpiPlugin\Carbon\MonitorModel']; + $this->assertEquals($expected, $result); + + $result = CommonGLPI::getOtherTabs(NetworkEquipmentModel::class); + $expected = ['GlpiPlugin\Carbon\NetworkEquipmentModel']; + $this->assertEquals($expected, $result); + } } diff --git a/tests/integration/SearchOptionTest.php b/tests/integration/SearchOptionTest.php index b5918e05..d77fff51 100644 --- a/tests/integration/SearchOptionTest.php +++ b/tests/integration/SearchOptionTest.php @@ -47,6 +47,9 @@ use CommonGLPI; use DBmysql; use DbUtils; +use GlpiPlugin\Carbon\ComputerModel; +use GlpiPlugin\Carbon\MonitorModel; +use GlpiPlugin\Carbon\NetworkEquipmentModel; use Plugin; use PHPUnit\Framework\Attributes\CoversMethod; @@ -68,6 +71,7 @@ class SearchOptionTest extends CommonTestCase ], ComputerType::class => [], MonitorType::class => [], + NetworkEquipmentType::class => [], UsageInfo::class => [], CarbonIntensity::class => [ 'data_quality' @@ -77,11 +81,13 @@ class SearchOptionTest extends CommonTestCase 'adp_quality', 'pe_quality', ], - NetworkEquipmentType::class => [], Location::class => [], Zone::class => [ 'entities_id', ], + ComputerModel::class => [], + MonitorModel::class => [], + NetworkEquipmentModel::class => [], ]; private array $mapping = [ diff --git a/tests/units/ComputerModelTest.php b/tests/units/ComputerModelTest.php new file mode 100644 index 00000000..3535c547 --- /dev/null +++ b/tests/units/ComputerModelTest.php @@ -0,0 +1,69 @@ +. + * + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Carbon\Tests; + +use ComputerModel as GlpiComputerModel; +use GlpiPlugin\Carbon\ComputerModel; +use Symfony\Component\DomCrawler\Crawler; + +class ComputerModelTest extends DbTestCase +{ + /** + * #CoversMethod GlpiPlugin\Carbon\AbstractType::showForItemType + */ + public function testShowForItemType() + { + $glpi_computer_model = $this->createItem(GlpiComputerModel::class); + $computer_model = $this->createItem(ComputerModel::class, [ + 'computermodels_id' => $glpi_computer_model->getID(), + ]); + $this->login('glpi', 'glpi'); + ob_start(); + $computer_model->showForItemType($glpi_computer_model); + $output = ob_get_clean(); + $crawler = new Crawler($output); + $gwp = $crawler->filter('input[name="gwp"]'); + $this->assertEquals(1, $gwp->count()); + $gwp->each(function (Crawler $node) { + $this->assertEquals(0, $node->attr('value')); + $this->assertEquals('number', $node->attr('type')); + }); + + $gwp_source = $crawler->filter('input[name="gwp_source"]'); + $gwp_source->each(function (Crawler $node) { + $this->assertEquals('', $node->attr('value')); + }); + + $gwp_quality = $crawler->filter('select[name="gwp_quality"]'); + } +} diff --git a/tests/units/ComputerTypeTest.php b/tests/units/ComputerTypeTest.php index 8941cd8e..58635176 100644 --- a/tests/units/ComputerTypeTest.php +++ b/tests/units/ComputerTypeTest.php @@ -43,8 +43,8 @@ class ComputerTypeTest extends DbTestCase { public function testGetTypeName() { - $this->assertEquals('Power', ComputerType::getTypeName(1)); - $this->assertEquals('Powers', ComputerType::getTypeName(Session::getPluralNumber())); + $this->assertEquals('Environmental impact', ComputerType::getTypeName(1)); + $this->assertEquals('Environmental impacts', ComputerType::getTypeName(Session::getPluralNumber())); } public function testGetTabNameForItem() diff --git a/tests/units/Impact/Embodied/EngineTest.php b/tests/units/Impact/Embodied/EngineTest.php new file mode 100644 index 00000000..23699565 --- /dev/null +++ b/tests/units/Impact/Embodied/EngineTest.php @@ -0,0 +1,73 @@ +. + * + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Carbon\Impact\Embodied\Tests; + +use Computer as GlpiComputer; +use Monitor as GlpiMonitor; +use NetworkEquipment as GlpiNetworkEquipment; +use Config as GlpiConfig; +use GlpiPlugin\Carbon\DataSource\RestApiClient; +use GlpiPlugin\Carbon\Tests\DbTestCase; +use GlpiPlugin\Carbon\Impact\Embodied\Boavizta\Computer; +use GlpiPlugin\Carbon\Impact\Embodied\Boavizta\Monitor; +use GlpiPlugin\Carbon\Impact\Embodied\Internal\NetworkEquipment; +use GlpiPlugin\Carbon\Impact\Embodied\Engine; + +class EngineTest extends DbTestCase +{ + public function testGetEngineFromItemtypeForBoavizta() + { + GlpiConfig::setConfigurationValues('plugin:carbon', [ + 'boaviztapi_base_url' => 'http://localhost:5000' + ]); + $version_response = [ + '1.3.11', + ]; + $client_stub = $this->getMockBuilder(RestApiClient::class) + ->getMock(); + $client_stub->method('request')->willReturn($version_response); + + $itemtype = GlpiComputer::class; + $result = Engine::getEngineFromItemtype($itemtype, $client_stub); + $this->assertTrue($result instanceof Computer); + + $itemtype = GlpiMonitor::class; + $result = Engine::getEngineFromItemtype($itemtype, $client_stub); + $this->assertTrue($result instanceof Monitor); + + // This case returns internal embodied impact engine, as Boavizta does not provide data + $itemtype = GlpiNetworkEquipment::class; + $result = Engine::getEngineFromItemtype($itemtype, $client_stub); + $this->assertTrue($result instanceof NetworkEquipment); + } +} diff --git a/tests/units/Impact/Usage/EngineTest.php b/tests/units/Impact/Usage/EngineTest.php new file mode 100644 index 00000000..6c8eb7e1 --- /dev/null +++ b/tests/units/Impact/Usage/EngineTest.php @@ -0,0 +1,72 @@ +. + * + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Carbon\Impact\Usage\Tests; + +use Computer as GlpiComputer; +use Monitor as GlpiMonitor; +use NetworkEquipment as GlpiNetworkEquipment; +use Config as GlpiConfig; +use GlpiPlugin\Carbon\DataSource\RestApiClient; +use GlpiPlugin\Carbon\Tests\DbTestCase; +use GlpiPlugin\Carbon\Impact\Usage\Boavizta\Computer; +use GlpiPlugin\Carbon\Impact\Usage\Boavizta\Monitor; +use GlpiPlugin\Carbon\Impact\Usage\Engine; + +class EngineTest extends DbTestCase +{ + public function testGetEngineFromItemtypeForBoavizta() + { + GlpiConfig::setConfigurationValues('plugin:carbon', [ + 'boaviztapi_base_url' => 'http://localhost:5000' + ]); + $version_response = [ + '1.3.11', + ]; + $client_stub = $this->getMockBuilder(RestApiClient::class) + ->getMock(); + $client_stub->method('request')->willReturn($version_response); + + $itemtype = GlpiComputer::class; + $result = Engine::getEngineFromItemtype($itemtype, $client_stub); + $this->assertTrue($result instanceof Computer); + + $itemtype = GlpiMonitor::class; + $result = Engine::getEngineFromItemtype($itemtype, $client_stub); + $this->assertTrue($result instanceof Monitor); + + // This case returns null, as Boavizta does not provide data + $itemtype = GlpiNetworkEquipment::class; + $result = Engine::getEngineFromItemtype($itemtype, $client_stub); + $this->assertNull($result); + } +} diff --git a/tests/units/MonitorModelTest.php b/tests/units/MonitorModelTest.php new file mode 100644 index 00000000..0390417e --- /dev/null +++ b/tests/units/MonitorModelTest.php @@ -0,0 +1,69 @@ +. + * + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Carbon\Tests; + +use MonitorModel as GlpiMonitorModel; +use GlpiPlugin\Carbon\MonitorModel; +use Symfony\Component\DomCrawler\Crawler; + +class MonitorModelTest extends DbTestCase +{ + /** + * #CoversMethod GlpiPlugin\Carbon\AbstractType::showForItemType + */ + public function testShowForItemType() + { + $glpi_monitor_model = $this->createItem(GlpiMonitorModel::class); + $monitor_model = $this->createItem(MonitorModel::class, [ + 'monitormodels_id' => $glpi_monitor_model->getID(), + ]); + $this->login('glpi', 'glpi'); + ob_start(); + $monitor_model->showForItemType($glpi_monitor_model); + $output = ob_get_clean(); + $crawler = new Crawler($output); + $gwp = $crawler->filter('input[name="gwp"]'); + $this->assertEquals(1, $gwp->count()); + $gwp->each(function (Crawler $node) { + $this->assertEquals(0, $node->attr('value')); + $this->assertEquals('number', $node->attr('type')); + }); + + $gwp_source = $crawler->filter('input[name="gwp_source"]'); + $gwp_source->each(function (Crawler $node) { + $this->assertEquals('', $node->attr('value')); + }); + + $gwp_quality = $crawler->filter('select[name="gwp_quality"]'); + } +} diff --git a/tests/units/MonitorTypeTest.php b/tests/units/MonitorTypeTest.php index 9ef57c9b..c9727a95 100644 --- a/tests/units/MonitorTypeTest.php +++ b/tests/units/MonitorTypeTest.php @@ -45,8 +45,8 @@ class MonitorTypeTest extends DbTestCase { public function testGetTypeName() { - $this->assertEquals('Power', MonitorType::getTypeName(1)); - $this->assertEquals('Powers', MonitorType::getTypeName(Session::getPluralNumber())); + $this->assertEquals('Environmental impact', MonitorType::getTypeName(1)); + $this->assertEquals('Environmental impacts', MonitorType::getTypeName(Session::getPluralNumber())); } public function testGetTabNameForItem() diff --git a/tests/units/NetworkEquipmentModelTest.php b/tests/units/NetworkEquipmentModelTest.php new file mode 100644 index 00000000..dc90e319 --- /dev/null +++ b/tests/units/NetworkEquipmentModelTest.php @@ -0,0 +1,69 @@ +. + * + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Carbon\Tests; + +use NetworkEquipmentModel as GlpiNetworkEquipmentModel; +use GlpiPlugin\Carbon\NetworkEquipmentModel; +use Symfony\Component\DomCrawler\Crawler; + +class NetworkEquipmentModelTest extends DbTestCase +{ + /** + * #CoversMethod GlpiPlugin\Carbon\AbstractType::showForItemType + */ + public function testShowForItemType() + { + $glpi_networkequipment_model = $this->createItem(GlpiNetworkEquipmentModel::class); + $networkequipment_model = $this->createItem(NetworkEquipmentModel::class, [ + 'networkequipmentmodels_id' => $glpi_networkequipment_model->getID(), + ]); + $this->login('glpi', 'glpi'); + ob_start(); + $networkequipment_model->showForItemType($glpi_networkequipment_model); + $output = ob_get_clean(); + $crawler = new Crawler($output); + $gwp = $crawler->filter('input[name="gwp"]'); + $this->assertEquals(1, $gwp->count()); + $gwp->each(function (Crawler $node) { + $this->assertEquals(0, $node->attr('value')); + $this->assertEquals('number', $node->attr('type')); + }); + + $gwp_source = $crawler->filter('input[name="gwp_source"]'); + $gwp_source->each(function (Crawler $node) { + $this->assertEquals('', $node->attr('value')); + }); + + $gwp_quality = $crawler->filter('select[name="gwp_quality"]'); + } +} diff --git a/tests/units/NetworkEquipmentTypeTest.php b/tests/units/NetworkEquipmentTypeTest.php index db334e17..4eb19426 100644 --- a/tests/units/NetworkEquipmentTypeTest.php +++ b/tests/units/NetworkEquipmentTypeTest.php @@ -36,7 +36,6 @@ use MassiveAction; use NetworkEquipmentType as GlpiNetworkEquipmentType; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\Attributes\CoversMethod; use Session; use Symfony\Component\DomCrawler\Crawler; @@ -46,8 +45,8 @@ class NetworkEquipmentTypeTest extends DbTestCase { public function testGetTypeName() { - $this->assertEquals('Power', NetworkEquipmentType::getTypeName(1)); - $this->assertEquals('Powers', NetworkEquipmentType::getTypeName(Session::getPluralNumber())); + $this->assertEquals('Environmental impact', NetworkEquipmentType::getTypeName(1)); + $this->assertEquals('Environmental impacts', NetworkEquipmentType::getTypeName(Session::getPluralNumber())); } public function testGetTabNameForItem()