diff --git a/ajax/fieldValueInput.php b/ajax/fieldValueInput.php new file mode 100644 index 0000000..434e8b2 --- /dev/null +++ b/ajax/fieldValueInput.php @@ -0,0 +1,138 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2015-2026 by Teclib'. + * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html + * @link https://github.com/pluginsGLPI/uninstall + * ------------------------------------------------------------------------- + */ + +header("Content-Type: text/html; charset=UTF-8"); +Html::header_nocache(); + +Session::checkRightsOr('uninstall:profile', [READ, PluginUninstallProfile::RIGHT_REPLACE]); +switch ($_POST['action']) { + case PluginUninstallModelcontainerfield::ACTION_NONE: + case PluginUninstallModelcontainerfield::ACTION_RAZ: + echo ""; + break; + + case PluginUninstallModelcontainerfield::ACTION_NEW_VALUE: + if (isset($_POST['id']) && $_POST['id']) { + $rand = mt_rand(); + if (isset($_POST['rand']) && $_POST['rand']) { + $rand = $_POST['rand']; + } + + $pluginUninstallField = new PluginUninstallModelcontainerfield(); + $pluginUninstallField->getFromDB($_POST['id']); + + $pluginFieldsField = new PluginFieldsField(); + $pluginFieldsField->getFromDB($pluginUninstallField->fields['plugin_fields_fields_id']); + + $type = $pluginFieldsField->fields['type']; + + if ($type === 'glpi_item') { + // TODO handling this case + // Display "allowed values" field + echo __('Allowed values', 'fields') . ' :'; + + $allowed_itemtypes = !empty($pluginFieldsField->fields['allowed_values']) + ? json_decode($pluginFieldsField->fields['allowed_values']) + : []; + echo implode( + ', ', + array_map( + function ($itemtype) { + return is_a($itemtype, CommonDBTM::class, true) + ? $itemtype::getTypeName(Session::getPluralNumber()) + : $itemtype; + }, + $allowed_itemtypes + ) + ); + } else { + $dropdown_matches = []; + $is_dropdown = $type == 'dropdown' || preg_match( + '/^dropdown-(?.+)$/', + $type, + $dropdown_matches + ) === 1; + + if (in_array($type, ['date', 'datetime'])) { + echo ''; + } + + if ($is_dropdown) { + $multiple = (bool)$pluginFieldsField->fields['multiple']; + + echo '
'; + + $itemtype = $type == 'dropdown' + ? PluginFieldsDropdown::getClassname($pluginFieldsField->fields['name']) + : $dropdown_matches['class']; + $default_value = $multiple ? json_decode( + $pluginUninstallField->fields['new_value'] ?? $pluginFieldsField->fields['default_value'] + ) : $pluginUninstallField->fields['new_value'] ?? $pluginFieldsField->fields['default_value']; + Dropdown::show( + $itemtype, + [ + 'name' => 'new_value' . ($multiple ? '[]' : ''), + 'value' => $default_value, + 'entity_restrict' => -1, + 'multiple' => $multiple, + 'rand' => $rand + ] + ); + + echo '
'; + } else if ($type === 'yesno') { + $value = 0; + if ($pluginUninstallField->fields['new_value'] === 1 || $pluginUninstallField->fields['new_value'] === '1') { + $value = 1; + } else if ($pluginFieldsField->fields['default_value']) { + $value = $pluginFieldsField->fields['default_value']; + } + Dropdown::showYesNo( + 'new_value', + $value, + -1, + ['rand' => $rand] + ); + } else { + $id = 'new_value' . $rand; + echo Html::input( + 'new_value', + [ + 'value' => $pluginUninstallField->fields['new_value'] ?? $pluginFieldsField->fields['default_value'], + 'id' => $id + ] + ); + } + } + } + break; +} \ No newline at end of file diff --git a/ajax/saveField.php b/ajax/saveField.php new file mode 100644 index 0000000..de6bfe7 --- /dev/null +++ b/ajax/saveField.php @@ -0,0 +1,45 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2015-2026 by Teclib'. + * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html + * @link https://github.com/pluginsGLPI/uninstall + * ------------------------------------------------------------------------- + */ + +header("Content-Type: text/html; charset=UTF-8"); +Html::header_nocache(); + +Session::checkRightsOr('uninstall:profile', [READ, PluginUninstallProfile::RIGHT_REPLACE]); + +if (isset($_POST['id']) && $_POST['id']) { + $field = new PluginUninstallModelcontainerfield(); + $field->check($_POST['id'], UPDATE); + if ($field->update($_POST)) { + Session::addMessageAfterRedirect(__('Field updated', 'uninstall')); + } else { + Session::addMessageAfterRedirect(__('An error has occured'), ERROR); + } + echo ""; +} \ No newline at end of file diff --git a/front/model.form.php b/front/model.form.php index 5417965..7bbd48d 100644 --- a/front/model.form.php +++ b/front/model.form.php @@ -48,16 +48,47 @@ if (isset($_POST["add"])) { $model->check(-1, UPDATE, $_POST); - $model->add($_POST); + if ($id = $model->add($_POST)) { + $relationsCreated = false; + if (isset($_POST['action_plugin_fields_uninstall'])) { + if ($_POST['action_plugin_fields_uninstall'] == PluginUninstallModel::PLUGIN_FIELDS_ACTION_ADVANCED) { + $model->createPluginFieldsRelations($id); + $relationsCreated = true; + } + } + // possible that the relations were created in previous if for replace then uninstall model types + if (isset($_POST['action_plugin_fields_replace']) && !$relationsCreated) { + if ($_POST['action_plugin_fields_replace'] == PluginUninstallModel::PLUGIN_FIELDS_ACTION_ADVANCED) { + $model->createPluginFieldsRelations($id); + } + } + } Html::back(); } elseif (isset($_POST["update"])) { $model->check($_POST['id'], UPDATE); - $model->update($_POST); + if ($model->update($_POST)) { + $relationsCreated = false; + if (isset($_POST['action_plugin_fields_uninstall'])) { + if ($_POST['action_plugin_fields_uninstall'] == PluginUninstallModel::PLUGIN_FIELDS_ACTION_ADVANCED) { + $model->createPluginFieldsRelations($id); + $relationsCreated = true; + } + } + if (isset($_POST['action_plugin_fields_replace']) && !$relationsCreated) { + if ($_POST['action_plugin_fields_replace'] == PluginUninstallModel::PLUGIN_FIELDS_ACTION_ADVANCED) { + $model->createPluginFieldsRelations($id); + } + } + } Html::back(); } elseif (isset($_POST['purge'])) { $model->check($_POST['id'], DELETE); $model->delete($_POST); $model->redirectToList(); +} else if (isset($_GET["load_fields"])) { + $model->check($id, UPDATE); + $model->createPluginFieldsRelations($id); + Html::back(); } else { Html::header( PluginUninstallModel::getTypeName(), diff --git a/front/modelcontainer.form.php b/front/modelcontainer.form.php new file mode 100644 index 0000000..48ff544 --- /dev/null +++ b/front/modelcontainer.form.php @@ -0,0 +1,49 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2015-2026 by Teclib'. + * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html + * @link https://github.com/pluginsGLPI/uninstall + * ------------------------------------------------------------------------- + */ + +Session::checkRightsOr('uninstall:profile', [READ, PluginUninstallProfile::RIGHT_REPLACE]); + +$container = new PluginUninstallModelcontainer(); +if (isset($_POST["update"])) { + $container->check($_POST['id'], UPDATE); + $container->update($_POST); + Html::back(); +} else { + Html::header( + PluginUninstallModelContainer::getTypeName(), + $_SERVER['PHP_SELF'], + "admin", + "PluginUninstallModel", + "model" + ); + $container->display(['id' => $_GET['id']]); + + Html::footer(); +} \ No newline at end of file diff --git a/front/modelcontainerfield.form.php b/front/modelcontainerfield.form.php new file mode 100644 index 0000000..24352bc --- /dev/null +++ b/front/modelcontainerfield.form.php @@ -0,0 +1,56 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2015-2026 by Teclib'. + * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html + * @link https://github.com/pluginsGLPI/uninstall + * ------------------------------------------------------------------------- + */ + +Session::checkRightsOr('uninstall:profile', [READ, PluginUninstallProfile::RIGHT_REPLACE]); + +$field = new PluginUninstallModelcontainerfield(); + +if (isset($_POST["update"])) { + // TODO handling of mandatory when action = SET_VALUE + $field->check($_POST['id'], UPDATE); + $field->update($_POST); + Html::back(); +} else { + Html::header( + PluginUninstallModelcontainerfield::getTypeName(), + $_SERVER['PHP_SELF'], + "admin", + "PluginUninstallModel", + "model" + ); + + if (isset($_GET["id"])) { + PluginUninstallModelcontainerfield::displayFullPageForItem($_GET['id']); + } else { + } + + + Html::footer(); +} \ No newline at end of file diff --git a/hook.php b/hook.php index af4e28f..3f4d20b 100644 --- a/hook.php +++ b/hook.php @@ -53,6 +53,10 @@ function plugin_uninstall_addDefaultWhere($itemtype) { if ($itemtype === 'PluginUninstallModel' && !PluginUninstallModel::canReplace()) { return "`glpi_plugin_uninstall_models`.`types_id` = '1'"; + } elseif ($itemtype === 'PluginUninstallModelcontainer' && isset($_GET['id'])) { + return "`glpi_plugin_uninstall_modelcontainers`.`plugin_uninstall_models_id` = '" . $_GET['id'] . "'"; + } elseif ($itemtype === 'PluginUninstallModelcontainerfield' && isset($_GET['id'])) { + return "`glpi_plugin_uninstall_modelcontainerfields`.`plugin_uninstall_modelcontainers_id` = '" . $_GET['id'] . "'"; } return null; @@ -74,11 +78,15 @@ function plugin_uninstall_install() require_once($dir . "/inc/model.class.php"); require_once($dir . "/inc/replace.class.php"); require_once($dir . "/inc/config.class.php"); + require_once($dir . "/inc/modelcontainer.class.php"); + require_once($dir . "/inc/modelcontainerfield.class.php"); PluginUninstallProfile::install($migration); PluginUninstallModel::install($migration); PluginUninstallPreference::install($migration); PluginUninstallConfig::install($migration); + PluginUninstallModelcontainer::install($migration); + PluginUninstallModelcontainerfield::install($migration); $migration->executeMigration(); @@ -96,10 +104,99 @@ function plugin_uninstall_uninstall() require_once($dir . "/inc/model.class.php"); require_once($dir . "/inc/replace.class.php"); require_once($dir . "/inc/config.class.php"); + require_once($dir . "/inc/modelcontainer.class.php"); + require_once($dir . "/inc/modelcontainerfield.class.php"); PluginUninstallProfile::uninstall(); PluginUninstallModel::uninstall(); PluginUninstallPreference::uninstall(); PluginUninstallConfig::uninstall(); + PluginUninstallModelcontainer::uninstall(); + PluginUninstallModelcontainerfield::uninstall(); return true; } + +function plugin_uninstall_hook_add_container($item) +{ + global $UNINSTALL_TYPES; + if (!($item instanceof PluginFieldsContainer)) { + return; + } + $types = json_decode($item->fields['itemtypes']); + // only create matching elements for containers concerning item types used by the plugin + if (!empty(array_intersect($types, $UNINSTALL_TYPES))) { + $containerId = $item->getID(); + $uninstallContainer = new PluginUninstallModelcontainer(); + $model = new PluginUninstallModel(); + $models = $model->find(); + foreach ($models as $mod) { + $uninstallContainer->add([ + 'plugin_uninstall_models_id' => $mod['id'], + 'plugin_fields_containers_id' => $containerId + ]); + } + } +} + +function plugin_uninstall_hook_add_field($item) +{ + if (!($item instanceof PluginFieldsField)) { + return; + } + $fieldId = $item->getID(); + $uninstallContainer = new PluginUninstallModelcontainer(); + $uninstallContainers = $uninstallContainer->find( + ['plugin_fields_containers_id' => $item->fields['plugin_fields_containers_id']] + ); + $uninstallField = new PluginUninstallModelcontainerfield(); + foreach ($uninstallContainers as $container) { + $uninstallField->add([ + 'plugin_uninstall_modelcontainers_id' => $container['id'], + 'plugin_fields_fields_id' => $fieldId + ]); + } +} + +function plugin_uninstall_hook_purge_container($item) +{ + if (!($item instanceof PluginFieldsContainer)) { + return; + } + global $DB; + $containerId = $item->getID(); + // all uninstall containers associated with the purged item + $pluginUninstallContainers = $DB->request([ + 'FROM' => PluginUninstallModelcontainer::getTable(), + 'SELECT' => 'id', + 'WHERE' => ['plugin_fields_containers_id' => $containerId] + ]); + $ids = []; + foreach ($pluginUninstallContainers as $cont) { + $ids[] = $cont['id']; + } + // delete all uninstall fields associated with one of the previously fetched uninstall container + if (count($ids)) { + $DB->delete( + PluginUninstallModelcontainerfield::getTable(), + ['plugin_uninstall_modelcontainers_id' => $ids] + ); + } + // delete all uninstall containers associated with the purged item + $DB->delete( + PluginUninstallModelcontainer::getTable(), + ['plugin_fields_containers_id' => $containerId] + ); +} + +function plugin_uninstall_hook_purge_field($item) +{ + if (!($item instanceof PluginFieldsField)) { + return; + } + global $DB; + $fieldId = $item->getID(); + $DB->delete( + PluginUninstallModelcontainerfield::getTable(), + ['plugin_fields_fields_id' => $fieldId] + ); +} diff --git a/inc/model.class.php b/inc/model.class.php index 61a0221..98c5c93 100644 --- a/inc/model.class.php +++ b/inc/model.class.php @@ -46,6 +46,17 @@ class PluginUninstallModel extends CommonDBTM public const TYPE_MODEL_REPLACEMENT_UNINSTALL = 3; + // do nothing + const PLUGIN_FIELDS_ACTION_NONE = 0; + // delete values, uninstall only + const PLUGIN_FIELDS_ACTION_RAZ = 1; + // copy values, replace only + const PLUGIN_FIELDS_ACTION_COPY = 2; + // choose action for each container individually + const PLUGIN_FIELDS_ACTION_ADVANCED = 3; + + + public static function getTypeName($nb = 0) { return _sn("Template", "Templates", $nb); @@ -202,7 +213,12 @@ public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) return PluginUninstallUninstall::getTypeName(1); case self::class: - return [1 => self::createTabEntry(self::getTypeName(1), 0, $item::getType(), self::getIcon()), 2 => self::createTabEntry(__s('Replacing data', 'uninstall'), 0, $item::getType(), PluginUninstallReplace::getIcon())]; + $tab = [1 => self::createTabEntry(self::getTypeName(1), 0, $item::getType(), self::getIcon()), 2 => self::createTabEntry(__s('Replacing data', 'uninstall'), 0, $item::getType(), PluginUninstallReplace::getIcon())]; + $plugin = new Plugin(); + if ($plugin->isActivated('fields')) { + $tab[3] = __('Additional fields options', 'uninstall'); + } + return $tab; } return ''; @@ -221,6 +237,9 @@ public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $ case 2: $item->showFormAction($item); break; + case 3: + $item->showFormPluginFields($item); + break; } } @@ -458,6 +477,33 @@ public function showPartFormUninstall() -1, ); echo ""; + + if ((new Plugin())->isActivated('fields')) { + echo ""; + echo "" . __('Uninstallation', 'uninstall') . ' - ' . __("Additionnal fields", "fields") . + ""; + + echo ""; + echo "" . __('Fields plugin informations', 'uninstall') . ""; + echo ""; + $choices = [ + self::PLUGIN_FIELDS_ACTION_NONE => __('Do nothing'), + self::PLUGIN_FIELDS_ACTION_RAZ => __('Blank'), + self::PLUGIN_FIELDS_ACTION_ADVANCED => __('Advanced options', 'uninstall') + ]; + Dropdown::showFromArray( + "action_plugin_fields_uninstall", + $choices, + [ + 'value' => isset($this->fields["action_plugin_fields_uninstall"]) ? + $this->fields["action_plugin_fields_uninstall"] : self::PLUGIN_FIELDS_ACTION_RAZ, + 'width' => '100%' + ] + ); + echo ""; + echo ""; + echo ""; + } } public function showPartFormRemplacement() @@ -472,6 +518,12 @@ public function showPartFormRemplacement() 'replace_method' => $this->fields["replace_method"] ?? 0, 'methods_list' => $methods, 'pdf_activated' => $plug->isActivated('PDF'), + 'plugin_fields_activate' => (new Plugin())->isActivated('fields'), + 'fields_action_list' => [ + self::PLUGIN_FIELDS_ACTION_NONE => __('Do nothing'), + self::PLUGIN_FIELDS_ACTION_COPY => __('Copy'), + self::PLUGIN_FIELDS_ACTION_ADVANCED => __('Advanced options', 'uninstall') + ], ]); } @@ -563,24 +615,24 @@ public function showFormAction($item) echo ""; } - if ($plug->isActivated('fields')) { - echo ""; - echo "" . __s("Additionnal fields", "fields") - . ""; - - echo ""; - echo "" . __s('Delete Fields plugin informations', 'uninstall') . ""; - echo ""; - Dropdown::showYesNo( - "raz_plugin_fields", - ($this->fields["raz_plugin_fields"] ?? 1), - -1, - ['width' => '100%'], - ); - echo ""; - echo ""; - echo ""; - } +// if ($plug->isActivated('fields')) { +// echo ""; +// echo "" . __s("Additionnal fields", "fields") +// . ""; +// +// echo ""; +// echo "" . __s('Delete Fields plugin informations', 'uninstall') . ""; +// echo ""; +// Dropdown::showYesNo( +// "raz_plugin_fields", +// ($this->fields["raz_plugin_fields"] ?? 1), +// -1, +// ['width' => '100%'], +// ); +// echo ""; +// echo ""; +// echo ""; +// } if ($canedit) { echo ""; @@ -598,6 +650,60 @@ public function showFormAction($item) return true; } + /** + * @param $item + **/ + public function showFormPluginFields($item) + { + $plugin = new Plugin(); + if ($plugin->isActivated('fields')) { + $separator = false; + + echo '

' . __('Plugin additionnal fields blocks', 'uninstall') . '

'; + + if ($item->fields["types_id"] != self::TYPE_MODEL_UNINSTALL) { + if ($item->fields['action_plugin_fields_replace'] === self::PLUGIN_FIELDS_ACTION_ADVANCED) { + $separator = true; + PluginUninstallModelcontainer::showListsForType($item->getID(), self::TYPE_MODEL_REPLACEMENT); + } else { + switch ($item->fields['action_plugin_fields_replace']) { + case self::PLUGIN_FIELDS_ACTION_NONE: + $action = __('Do nothing'); + break; + case self::PLUGIN_FIELDS_ACTION_COPY: + $action = __('Copy'); + break; + } + + echo "

" . __('Action for ', 'uninstall') . __('Replacement', 'uninstall') . ' : ' . $action . "

"; + } + } + + echo "
"; + + if ($item->fields["types_id"] != self::TYPE_MODEL_REPLACEMENT) { + if ($item->fields['action_plugin_fields_uninstall'] === self::PLUGIN_FIELDS_ACTION_ADVANCED) { + PluginUninstallModelcontainer::showListsForType($item->getID(), self::TYPE_MODEL_UNINSTALL); + } else { + switch ($item->fields['action_plugin_fields_uninstall']) { + case self::PLUGIN_FIELDS_ACTION_NONE: + $action = __('Do nothing'); + break; + case self::PLUGIN_FIELDS_ACTION_RAZ: + $action = __('Blank'); + break; + } + + echo "

" . __('Action for ', 'uninstall') . __('Uninstallation', 'uninstall') . ' : ' . $action . "

"; + } + } + } else { + echo "" . __("Activate the plugin 'fields' to access this tab.") . ""; + return false; + } + return true; + } + /** * @param $model_id @@ -1173,6 +1279,47 @@ public static function install($migration) $migration->addField($table, 'raz_glpiinventory', "integer"); } + // 2.10.4 + if (!$DB->fieldExists($table, 'action_plugin_fields_replace')) { + $migration->addField($table, 'action_plugin_fields_replace', "int NOT NULL DEFAULT '" . self::PLUGIN_FIELDS_ACTION_NONE . "'"); + $migration->addField($table, 'action_plugin_fields_uninstall', "int NOT NULL DEFAULT '" . self::PLUGIN_FIELDS_ACTION_NONE . "'"); + $migration->addPostQuery( + // uninstall with no raz + $DB->buildUpdate( + $table, + ['action_plugin_fields_uninstall' => '0'], + [ + 'raz_plugin_fields' => '0', + 'types_id' => '1' + ] + ) + ); + $migration->addPostQuery( + // uninstall with raz + $DB->buildUpdate( + $table, + ['action_plugin_fields_uninstall' => '1'], + [ + 'raz_plugin_fields' => '1', + 'types_id' => '1' + ] + ) + ); + $migration->addPostQuery( + // replace default value + $DB->buildUpdate( + $table, + ['action_plugin_fields_replace' => '0'], + ['types_id' => '2'] + ) + ); + + if ($DB->fieldExists($table, 'raz_plugin_fields')) { + $migration->deleteField($table, 'raz_plugin_fields', "bool"); + } + + } + $migration->migrationOneTable($table); $self = new self(); @@ -1223,7 +1370,8 @@ public static function install($migration) `replace_method` int NOT NULL DEFAULT '2', `raz_glpiinventory` int NOT NULL DEFAULT '1', `raz_fusioninventory` int NOT NULL DEFAULT '1', - `raz_plugin_fields` tinyint NOT NULL DEFAULT '1', + `action_plugin_fields_uninstall` int NOT NULL DEFAULT '0', + `action_plugin_fields_replace` int NOT NULL DEFAULT '0', `replace_contact` tinyint NOT NULL DEFAULT '0', `replace_contact_num` tinyint NOT NULL DEFAULT '0', PRIMARY KEY (`id`) @@ -1289,7 +1437,8 @@ public static function createTransferModel($name = 'Uninstall') $tmp['raz_ocs_registrykeys'] = 1; $tmp['raz_glpiinventory'] = 1; $tmp['raz_fusioninventory'] = 1; - $tmp['raz_plugin_fields'] = 1; + $tmp['action_plugin_fields_uninstall'] = 0; + $tmp['action_plugin_fields_replace'] = 0; $tmp['comment'] = ''; $tmp['groups_action'] = 'set'; $tmp['groups_id'] = 0; @@ -1382,4 +1531,43 @@ public static function getIcon() { return "ti ti-template"; } + + /** + * Create all non-existing relations between plugin fields containers and a model + * @param $modelId int + */ + public function createPluginFieldsRelations($modelId) + { + global $DB, $UNINSTALL_TYPES; + if ($DB->tableExists('glpi_plugin_fields_containers')) { + $uninstallContainer = new PluginUninstallModelcontainer(); + $uninstallContainers = $uninstallContainer->find(['plugin_uninstall_models_id' => $modelId]); + $existingContainersIds = array_map(fn($e) => $e['plugin_fields_containers_id'], $uninstallContainers); + $existingContainersIds = array_unique($existingContainersIds); + + $fieldsContainers = PluginUninstallModelcontainer::getContainerForItemtypes($existingContainersIds); + + $fieldsField = new PluginFieldsField(); + $uninstallField = new PluginUninstallModelcontainerfield(); + + foreach ($fieldsContainers as $container) { + $types = json_decode($container['itemtypes']); + // only create matching elements for containers concerning item types used by the plugin + if (!empty(array_intersect($types, $UNINSTALL_TYPES))) { + $newId = $uninstallContainer->add([ + 'plugin_uninstall_models_id' => $modelId, + 'plugin_fields_containers_id' => $container['id'] + ]); + + $fieldsFields = $fieldsField->find(['plugin_fields_containers_id' => $container['id']]); + foreach ($fieldsFields as $field) { + $uninstallField->add([ + 'plugin_fields_fields_id' => $field['id'], + 'plugin_uninstall_modelcontainers_id' => $newId + ]); + } + } + } + } + } } diff --git a/inc/modelcontainer.class.php b/inc/modelcontainer.class.php new file mode 100644 index 0000000..8fde697 --- /dev/null +++ b/inc/modelcontainer.class.php @@ -0,0 +1,563 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2015-2026 by Teclib'. + * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html + * @link https://github.com/pluginsGLPI/uninstall + * ------------------------------------------------------------------------- + */ + +class PluginUninstallModelcontainer extends CommonDBChild +{ + public $dohistory = true; + + public static $rightname = "uninstall:profile"; + + // do nothing + const ACTION_NONE = 0; + // delete values, uninstall only + const ACTION_RAZ = 1; + // copy values, replace only + const ACTION_COPY = 2; + // choose action for each field individually + const ACTION_CUSTOM = 3; + + public static $itemtype = 'PluginUninstallModel'; + public static $items_id = 'plugin_uninstall_models_id'; + protected $displaylist = true; + + + public static function getTypeName($nb = 0) + { + return __("Block", "fields"); + } + + /** + * Get the list of actions available for an instance, or all available actions + * @param $type int|null + * @return array value => label + */ + public static function getActions($type = null) + { + if ($type) { + $values = [ + self::ACTION_NONE => __('Do nothing'), + ]; + if ($type == PluginUninstallModel::TYPE_MODEL_UNINSTALL) { + $values[self::ACTION_RAZ] = __('Blank'); + } else { + $values[self::ACTION_COPY] = __('Copy'); + } + $values[self::ACTION_CUSTOM] = __('Per field action', 'uninstall'); + return $values; + } + return [ + self::ACTION_NONE => __('Do nothing'), + self::ACTION_RAZ => __('Blank'), + self::ACTION_COPY => __('Copy'), + self::ACTION_CUSTOM => __('Per field action', 'uninstall') + ]; + } + + public static function getIcon() + { + return "ti ti-layout-grid"; + } + + public function defineTabs($options = []) + { + $ong = []; + $this->addStandardTab(__CLASS__, $ong, $options); + $this->addStandardTab('Log', $ong, $options); + return $ong; + } + + public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) + { + switch ($item->getType()) { + case __CLASS__: + switch ($tabnum) { + case 1: + $item->showForm($item->getID()); + break; + case 2: + $item->showFields($item); + break; + } + } + return true; + } + + public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) + { + switch ($item->getType()) { + case __CLASS__: + $tab = []; + $tab[1] = self::getTypeName(1); + $model = new PluginUninstallModel(); + $model->getFromDB($item->fields['plugin_uninstall_models_id']); + if ( + ($model->fields['types_id'] != $model::TYPE_MODEL_UNINSTALL && $item->fields['action_replace'] == self::ACTION_CUSTOM) || + ($model->fields['types_id'] != $model::TYPE_MODEL_REPLACEMENT && $item->fields['action_uninstall'] == self::ACTION_CUSTOM) + ) { + $tab[2] = __('Fields'); + } + return $tab; + } + return ''; + } + + public function getName($options = []) + { + $container = new PluginFieldsContainer(); + $container->getFromDB($this->fields['plugin_fields_containers_id']); + return $container->getFriendlyName(); + } + + /** + * Copy from PluginFieldsContainer + * @param $field_id_or_search_options + * @param $name + * @param $values + * @param $options + * @return mixed + */ + public function getValueToSelect($field_id_or_search_options, $name = '', $values = '', $options = []) + { + switch ($field_id_or_search_options['table'] . '.' . $field_id_or_search_options['field']) { + case $this->getTable() . '.itemtypes': + $options['display'] = false; + return Dropdown::showFromArray($name, self::getItemtypes(false), $options); + } + + return parent::getValueToSelect($field_id_or_search_options, $name, $values, $options); + } + + public function showForm($ID, $options = []) + { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + + $this->initForm($ID, $options); + $this->showFormHeader($options); + + $model = new PluginUninstallModel(); + $model->getFromDB($this->fields['plugin_uninstall_models_id']); + + $pluginFieldsContainer = new PluginFieldsContainer(); + if ($pluginFieldsContainer->getFromDB($this->fields['plugin_fields_containers_id'])) { + + + // associated model name + $types = json_decode($pluginFieldsContainer->fields['itemtypes']); + $obj = ''; + $count = count($types); + $i = 1; + foreach ($types as $type) { + // prevent usage of plugin class if not loaded + if (!class_exists($type)) { + continue; + } + + $name_type = getItemForItemtype($type); + $obj .= $name_type->getTypeName(2); + if ($count > $i) { + $obj .= ", "; + } + $i++; + } + + + // actual form data + $titleColspan = 4; + $actionColspan = 3; + if ($model->fields['types_id'] == $model::TYPE_MODEL_REPLACEMENT_UNINSTALL) { + $titleColspan = 2; + $actionColspan = 1; + } + + $dropdown = ''; + if ($model->fields['types_id'] != $model::TYPE_MODEL_UNINSTALL) { + if ($model->fields['action_plugin_fields_replace'] == $model::PLUGIN_FIELDS_ACTION_ADVANCED) { + $dropdown = [ + 'values' => self::getActions($model::TYPE_MODEL_REPLACEMENT), + 'value' => ($this->fields["action_replace"] ?? $this::ACTION_NONE), + 'width' => '100%', + ]; + } + } + + if ($model->fields['types_id'] != $model::TYPE_MODEL_REPLACEMENT) { + if ($model->fields['action_plugin_fields_uninstall'] == $model::PLUGIN_FIELDS_ACTION_ADVANCED) { + $dropdown = [ + 'values' => self::getActions($model::TYPE_MODEL_UNINSTALL), + 'value' => ($this->fields["action_uninstall"] ?? $this::ACTION_NONE), + 'width' => '100%', + ]; + } + } + + TemplateRenderer::getInstance()->display('@uninstall/modelcontainer_showForm.html.twig',[ + 'modelValues'=> $model->fields, + 'pluginFieldsContainer' => [ + 'typeName' => $pluginFieldsContainer->getTypeName(), + 'formUrlWithId' => $pluginFieldsContainer->getFormURLWithID($pluginFieldsContainer->getID()), + 'values' => $pluginFieldsContainer->fields, + ], + 'itemObjet' => $obj, + 'collspan' => ['title' => $titleColspan, 'action' => $actionColspan], + 'rand' => mt_rand(), + 'dropdown' => $dropdown, + ]); + + $this->showFormButtons($options); + } + + return true; + } + + /** + * @param $modelId int PluginUninstallModel id + * @param $type int const TYPE_MODEL from PluginUninstallModel + * @return void + */ + public static function showListsForType($modelId, $type) + { + $typeTitle = $type === PluginUninstallModel::TYPE_MODEL_UNINSTALL ? __('Uninstallation', 'uninstall') : __( + 'Replacement', + 'uninstall' + ); + echo "

" . $typeTitle . '

'; + $self = new self(); + $uninstallContainers = $self->find([ + 'plugin_uninstall_models_id' => $modelId + ]); + $fieldContainer = new PluginFieldsContainer(); + if (count($uninstallContainers)) { + + $actionProperty = $type === PluginUninstallModel::TYPE_MODEL_UNINSTALL ? 'action_uninstall' : 'action_replace'; + foreach ($uninstallContainers as $uninstallContainer) { + $uninstallContainers[$uninstallContainer['id']]['hasfieldcontainer'] = false; + if ($fieldContainer->getFromDB($uninstallContainer['plugin_fields_containers_id'])) { + $uninstallContainers[$uninstallContainer['id']]['hasFieldContainer'] = true; + $uninstallContainers[$uninstallContainer['id']]['link'] = PluginUninstallModelContainer::getFormURLWithID($uninstallContainer['id']); + $uninstallContainers[$uninstallContainer['id']]['fieldContainerValues'] = $fieldContainer->fields; + $uninstallContainers[$uninstallContainer['id']]['action'] = self::getActions()[$uninstallContainer[$actionProperty]]; + + $types = json_decode($fieldContainer->fields['itemtypes']); + $obj = ''; + $count = count($types); + $i = 1; + foreach ($types as $type) { + if (!class_exists($type)) { + continue; + } + $name_type = getItemForItemtype($type); + $obj .= $name_type->getTypeName(2); + if ($count > $i) { + $obj .= ", "; + } + $i++; + } + $uninstallContainers[$uninstallContainer['id']]['obj'] = $obj; + } + } + + TemplateRenderer::getInstance()->display('@uninstall/modelcontainer_showList.html.twig',[ + 'uninstallContainers' => $uninstallContainers + ]); + } else { + if (count(self::getContainerForItemtypes())) { + $link = PluginUninstallModel::getFormURLWithID($modelId) . "&load_fields=1"; + echo "" . __('Load plugin data', 'uninstall') . ""; + } + } + } + + /** + * Get all containers from the plugin fields which are associated with an itemtype used by uninstall + * @param $ids array list of plugin fields container ids to exclude from the request + * @return array + */ + public static function getContainerForItemtypes($ids = []) + { + global $DB, $UNINSTALL_TYPES; + $query = "SELECT * FROM " . PluginFieldsContainer::getTable() . " WHERE "; + if (count($ids)) { + $query .= 'id NOT IN (' . implode(',', $ids) . ') AND ('; + } + foreach ($UNINSTALL_TYPES as $index => $type) { + $query .= 'itemtypes LIKE \'%"' . $type . '"%\' '; + if ($index != count($UNINSTALL_TYPES) - 1) { + $query .= 'OR '; + } + } + if (count($ids)) { + $query .= ')'; + } + $return = []; + if ($result = $DB->doQuery($query)) { + if ($DB->numrows($result) > 0) { + while ($data = $DB->fetchAssoc($result)) { + $return[] = $data; + } + } + } + return $return; + } + + /** + * Display list + * @param $item + * @return void + */ + public function showFields($item) + { + $model = new PluginUninstallModel(); + $model->getFromDB($item->fields['plugin_uninstall_models_id']); + + echo "

" . __('Plugin additionnal fields field', 'uninstall') . "

"; + + echo "

" . __('Model') . " : " . "" . $model->fields['name'] . "" . "

"; + + $actionFields = ['action_replace', 'action_uninstall']; + foreach ($actionFields as $field) { + if ( + ($field === 'action_uninstall' && $model->fields['types_id'] != $model::TYPE_MODEL_REPLACEMENT) + || ($field === 'action_replace' && $model->fields['types_id'] != $model::TYPE_MODEL_UNINSTALL) + ) { + switch ($field) { + case 'action_uninstall': + $typeTitle = __('Uninstallation', 'uninstall'); + $modelProperty = 'action_plugin_fields_uninstall'; + break; + case 'action_replace': + $typeTitle = __('Replacement', 'uninstall'); + $modelProperty = 'action_plugin_fields_replace'; + break; + } + $actionTitle = __('Action for ', 'uninstall') . $typeTitle . ' : '; + if ($model->fields[$modelProperty] != $model::PLUGIN_FIELDS_ACTION_ADVANCED) { + switch ($model->fields[$modelProperty]) { + case $model::PLUGIN_FIELDS_ACTION_NONE: + $action = __('Do nothing'); + break; + case $model::PLUGIN_FIELDS_ACTION_RAZ: + $action = __('Blank'); + break; + case $model::PLUGIN_FIELDS_ACTION_COPY: + $action = __('Copy'); + break; + } + + $actionTitle .= $action . " (" . __('set by model', 'uninstall') . ")"; + } else { + $actionTitle .= self::getActions()[$item->fields[$field]]; + if ($item->fields[$field] != self::ACTION_CUSTOM) { + $actionTitle .= " (" . __('set by bloc', 'uninstall') . ')'; + } + } + echo "

" . $actionTitle . "

"; + if ($item->fields[$field] == self::ACTION_CUSTOM) { + $uninstallField = new PluginUninstallModelcontainerfield(); + $fields = $uninstallField->find([ + 'plugin_uninstall_modelcontainers_id' => $item->getID() + ]); + if (count($fields)) { + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + + $fieldsField = new PluginFieldsField(); + $types = $fieldsField->getTypes(true); + foreach ($fields as $fieldData) { + if ( + $fieldsField->getFromDB($fieldData['plugin_fields_fields_id']) + && $uninstallField->getFromDB($fieldData['id']) + ) { + echo ""; + $link = PluginUninstallModelcontainerfield::getFormURLWithID($fieldData['id']); + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + } + } + echo ""; + echo "
" . __('Field') . "" . __("Type") . "" . __("Action") . "
"; + echo "" . $fieldsField->fields['label'] . ""; + echo "" . $types[$fieldsField->fields['type']] . "
"; + $options = [ + $uninstallField::ACTION_NONE => __('Do nothing'), + ]; + if ($field == 'action_uninstall') { + $options[$uninstallField::ACTION_RAZ] = __('Blank'); + if ($fieldsField->fields['type'] !== 'glpi_item') { + $options[$uninstallField::ACTION_NEW_VALUE] = __('Set value', 'uninstall'); + } + } else { + $options[$uninstallField::ACTION_COPY] = __('Copy'); + } + $rand = mt_rand(); + echo "
"; + Dropdown::showFromArray( + $field, + $options, + [ + 'value' => (isset($uninstallField->fields[$field]) + ? $uninstallField->fields[$field] : $uninstallField::ACTION_NONE), + 'width' => '100%', + 'rand' => $rand + ] + ); + echo "
"; + $id = $uninstallField->getID(); + if ($field == 'action_uninstall') { + echo "
"; + echo "
"; + if ($fieldsField->fields['type'] === 'glpi_item') { + echo __('Action set value is not available for this field type', 'uninstall'); + } + echo "
"; + echo "
"; + $url = Plugin::getWebDir('uninstall') . "/ajax/fieldValueInput.php"; + echo " + + "; + } + echo "
"; + echo "
"; + echo "
"; + $saveUrl = Plugin::getWebDir('uninstall') . "/ajax/saveField.php"; + echo " + + "; + echo "
"; + } + } + } + } + } + + public static function install($migration) + { + /** @var DBmysql $DB */ + global $DB; + + $default_charset = DBConnection::getDefaultCharset(); + $default_collation = DBConnection::getDefaultCollation(); + $default_key_sign = DBConnection::getDefaultPrimaryKeySignOption(); + + // first version with this feature + if (!$DB->tableExists(getTableForItemType(__CLASS__))) { + $query = "CREATE TABLE IF NOT EXISTS `" . getTableForItemType(__CLASS__) . "` ( + `id` int {$default_key_sign} NOT NULL AUTO_INCREMENT, + `plugin_uninstall_models_id` int {$default_key_sign} DEFAULT '0', + `plugin_fields_containers_id` tinyint NOT NULL DEFAULT '0', + `action_uninstall` int NOT NULL DEFAULT '0', + `action_replace` int NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) + ) ENGINE=InnoDB DEFAULT CHARSET={$default_charset} COLLATE={$default_collation} ROW_FORMAT=DYNAMIC;"; + + $DB->doQuery($query); + } + return true; + } + + public static function uninstall() + { + /** @var DBmysql $DB */ + global $DB; + + $DB->doQuery("DROP TABLE IF EXISTS `" . getTableForItemType(__CLASS__) . "`"); + + $DB->doQuery("DELETE FROM `glpi_displaypreferences` WHERE `itemtype` = '" . self::class . "';"); + + //Delete history + $log = new Log(); + $log->dohistory = false; + $log->deleteByCriteria(['itemtype' => __CLASS__]); + } +} \ No newline at end of file diff --git a/inc/modelcontainerfield.class.php b/inc/modelcontainerfield.class.php new file mode 100644 index 0000000..1593326 --- /dev/null +++ b/inc/modelcontainerfield.class.php @@ -0,0 +1,191 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2015-2026 by Teclib'. + * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html + * @link https://github.com/pluginsGLPI/uninstall + * ------------------------------------------------------------------------- + */ + +class PluginUninstallModelcontainerfield extends CommonDBChild +{ + public $dohistory = true; + + protected $displaylist = true; + + public static $rightname = "uninstall:profile"; + // do nothing + const ACTION_NONE = 0; + // delete value, uninstall only + const ACTION_RAZ = 1; + // set value to new_value, uninstall only + const ACTION_NEW_VALUE = 2; + // copy value, replace only + const ACTION_COPY = 3; + + public static $itemtype = 'PluginUninstallModelcontainer'; + public static $items_id = 'plugin_uninstall_modelcontainers_id'; + + public static function getTypeName($nb = 0) + { + return __("Field"); + } + + public function getName($options = []) + { + $field = new PluginFieldsField(); + $field->getFromDB($this->fields['plugin_fields_fields_id']); + return $field->fields['label']; + } + + public function showForm($ID, $options = []) + { + /** @var array $CFG_GLPI */ + global $CFG_GLPI; + + $this->initForm($ID, $options); + $this->showFormHeader($options); + + $uninstallContainer = new PluginUninstallModelcontainer(); + $uninstallContainer->getFromDB($this->fields['plugin_uninstall_modelcontainers_id']); + + $fieldsContainer = new PluginFieldsContainer(); + $fieldsContainer->getFromDB($uninstallContainer->fields['plugin_fields_containers_id']); + + $model = new PluginUninstallModel(); + $model->getFromDB($uninstallContainer->fields['plugin_uninstall_models_id']); + + $pluginFieldsField = new PluginFieldsField(); + if ($pluginFieldsField->getFromDB($this->fields['plugin_fields_fields_id'])) { + + + $actionFields = ['action_replace', 'action_uninstall']; + foreach ($actionFields as $field) { + $undertitle[$field] = $uninstallContainer::getActions()[$uninstallContainer->fields[$field]]; + } + + TemplateRenderer::getInstance()->display('@uninstall/modelcontainerfield_showForm.html.twig',[ + 'modelValues'=> $model->fields, + 'fieldContainer' => $fieldsContainer->fields, + 'itemValues'=> $this->fields, + 'pluginFieldsField' => $pluginFieldsField->fields, + 'uninstallContainer' => $uninstallContainer->fields, + 'rand' => mt_rand(), + 'link' => [ + 'model' => $model->getFormUrlWithID($model->getID()), + 'container' => $model->getFormUrlWithID($model->getID()), + 'ajax' => $CFG_GLPI['root_doc'] . "/plugins/uninstall/ajax/fieldValueInput.php", + ], + 'idItem' => $ID, + 'pluginFieldsFieldType' => PluginFieldsField::getTypes(true)[$pluginFieldsField->fields['type']], + 'undertitle' => $undertitle, + ]); + + $this->showFormButtons($options); + } + + return true; + } + + /** + * Check whether a PluginFieldsField's value can be considered not empty + * @param array $field row of glpi_plugin_fields_fields + * @param array $values row of table used by plugin fields to save item data + * @return bool + */ + public static function fieldHasValue(array $field, array $values): bool + { + if (str_starts_with($field['type'], 'dropdown')) { + if ($field['type'] == 'dropdown') { + $property = 'plugin_fields_' . $field['name'] . 'dropdowns_id'; + } else { // for dropdown-$itemtype type + $property = $field['name']; + } + + if ($field['multiple']) { // not null and not [] + return $values[$property] && $values[$property] != '[]'; + } + + return $values[$property]; // not 0 + } + + if (in_array($field['type'], ['text', 'textarea', 'richtext', 'number'])) { // numbers also stored as varchar + return trim($values[$field['name']]) || trim($values[$field['name']]) === '0'; // not null or empty string + } + + if ($field['type'] == 'glpi_item') { + return $values['items_id_' . $field['name']]; + } + + return $values[$field['name']]; + } + + public static function install($migration) + { + /** @var DBmysql $DB */ + global $DB; + + $default_charset = DBConnection::getDefaultCharset(); + $default_collation = DBConnection::getDefaultCollation(); + $default_key_sign = DBConnection::getDefaultPrimaryKeySignOption(); + + // first version with this feature + if (!$DB->tableExists(getTableForItemType(__CLASS__))) { + $query = "CREATE TABLE IF NOT EXISTS `" . getTableForItemType(__CLASS__) . "` ( + `id` int {$default_key_sign} NOT NULL AUTO_INCREMENT, + `plugin_uninstall_modelcontainers_id` int {$default_key_sign} DEFAULT '0', + `plugin_fields_fields_id` tinyint NOT NULL DEFAULT '0', + `action_uninstall` int NOT NULL DEFAULT '0', + `action_replace` int NOT NULL DEFAULT '0', + `new_value` varchar(255), + PRIMARY KEY (`id`) + ) ENGINE=InnoDB DEFAULT CHARSET={$default_charset} COLLATE={$default_collation} ROW_FORMAT=DYNAMIC;"; + + $DB->doQuery($query); + } + return true; + } + + public static function uninstall() + { + /** @var DBmysql $DB */ + global $DB; + + $DB->doQuery("DROP TABLE IF EXISTS `" . getTableForItemType(__CLASS__) . "`"); + + $DB->doQuery("DELETE FROM `glpi_displaypreferences` WHERE `itemtype` = '" . self::class . "';"); + + //Delete history + $log = new Log(); + $log->dohistory = false; + $log->deleteByCriteria(['itemtype' => __CLASS__]); + } + + public static function getIcon() + { + return "ti ti-input-search"; + } +} \ No newline at end of file diff --git a/inc/replace.class.php b/inc/replace.class.php index d81d363..ea899b1 100644 --- a/inc/replace.class.php +++ b/inc/replace.class.php @@ -139,6 +139,33 @@ public static function replace($type, $model_id, $tab_ids, $location) ); } + if ($plug->isActivated('fields')) { + $pluginFieldsContainer = new PluginFieldsContainer(); + // copy all + if ($model->fields['action_plugin_fields_replace'] == PluginUninstallModel::PLUGIN_FIELDS_ACTION_COPY) { + $containers = $pluginFieldsContainer->find(['itemtypes' => ['LIKE', "%\"$type\"%"]]); + foreach ($containers as $container) { + self::handlePluginFieldsContainerValues($overwrite, $container, $olditem, $newitem, $type); + } + } + // case by case for containers + if ($model->fields['action_plugin_fields_replace'] == PluginUninstallModel::PLUGIN_FIELDS_ACTION_ADVANCED) { + $pluginUninstallContainer = new PluginUninstallModelcontainer(); + $containers = $pluginFieldsContainer->find(['itemtypes' => ['LIKE', "%\"$type\"%"]]); + foreach ($containers as $container) { + $pluginUninstallContainer->getFromDBByCrit([ + 'plugin_fields_containers_id' => $container['id'], + 'plugin_uninstall_models_id' => $model->getID() + ]); + if ($pluginUninstallContainer->fields['action_replace'] == $pluginUninstallContainer::ACTION_COPY) { + self::handlePluginFieldsContainerValues($overwrite, $container, $olditem, $newitem, $type); + } else if ($pluginUninstallContainer->fields['action_replace'] == $pluginUninstallContainer::ACTION_CUSTOM) { + self::handlePluginFieldsContainerValues($overwrite, $container, $olditem, $newitem, $type, $pluginUninstallContainer); + } + } + } + } + // METHOD REPLACEMENT 1 : Archive if ($model->fields['replace_method'] == self::METHOD_PURGE) { $name_out = str_shuffle(Toolbox::getRandomString(5) . time()); @@ -1166,4 +1193,101 @@ public static function getIcon() { return "ti ti-recycle"; } + + /** + * Handle copy of values from the plugin fields + * @param $overwrite bool if true copy will replace values from newitem by those of olditem + * @param $container array data of PluginFieldsContainer + * @param $olditem CommonDBTM + * @param $newitem CommonDBTM + * @param $type string + * @param $pluginUninstallContainer PluginUninstallModelcontainer if not null, will see if it must do a case by case when handling the fields copies + * @return void + */ + public static function handlePluginFieldsContainerValues($overwrite, $container, $olditem, $newitem, $type, $pluginUninstallContainer = null) + { + global $DB; + $pluginFieldsField = new PluginFieldsField(); + $pluginUninstallField = new PluginUninstallModelcontainerfield(); + $table = 'glpi_plugin_fields_' . strtolower($type) . $container['name'] . 's'; + $oldItemValues = $DB->request([ + 'FROM' => $table, + 'WHERE' => [ + 'items_id' => $olditem->getID(), + 'itemtype' => $type, + 'plugin_fields_containers_id' => $container['id'] + ] + ]); + $newItemValues = $DB->request([ + 'FROM' => $table, + 'WHERE' => [ + 'items_id' => $newitem->getID(), + 'itemtype' => $type, + 'plugin_fields_containers_id' => $container['id'] + ] + ]); + if ($oldItemValues->count()) { + $fields = $pluginFieldsField->find(['plugin_fields_containers_id' => $container['id']]); + $parameters = []; + foreach ($fields as $field) { + switch ($field['type']) { + case 'dropdown': + $property = 'plugin_fields_' . $field['name'] . 'dropdowns_id'; + break; + case 'glpi_item': + $property = 'items_id_' . $field['name']; + $itemtype = 'itemtype_' . $field['name']; + break; + default: + $property = $field['name']; + break; + } + + if ($pluginUninstallContainer && $pluginUninstallContainer->fields['action_replace'] == $pluginUninstallContainer::ACTION_CUSTOM) { + if ( + $pluginUninstallField->getFromDBByCrit([ + 'plugin_uninstall_modelcontainers_id' => $pluginUninstallContainer->getID(), + 'plugin_fields_fields_id' => $field['id'] + ]) + ) { + if ($pluginUninstallField->fields['action_replace'] == $pluginUninstallField::ACTION_COPY) { + if ( + $overwrite // template setting say to overwrite + || !$newItemValues->current() // no plugin field data for new item + || !$pluginUninstallField::fieldHasValue($field, $newItemValues->current()) // new item has no value for the field + ) { + $parameters[$property] = $oldItemValues->current()[$property]; + if ($field['type'] == 'glpi_item') { + $parameters[$itemtype] = $oldItemValues->current()[$itemtype]; + } + } + } + } + } else { + if ( + $overwrite + || !$newItemValues->current() + || !$pluginUninstallField::fieldHasValue($field, $newItemValues->current()) + ) { + $parameters[$property] = $oldItemValues->current()[$property]; + if ($field['type'] == 'glpi_item') { + $parameters[$itemtype] = $oldItemValues->current()[$itemtype]; + } + } + } + } + + if (count($parameters)) { + $DB->updateOrInsert( + $table, + $parameters, + [ + 'items_id' => $newitem->getID(), + 'itemtype' => $type, + 'plugin_fields_containers_id' => $container['id'] + ] + ); + } + } + } } diff --git a/inc/uninstall.class.php b/inc/uninstall.class.php index cac884c..1283d19 100644 --- a/inc/uninstall.class.php +++ b/inc/uninstall.class.php @@ -341,10 +341,15 @@ private static function doOneUninstall(PluginUninstallModel $model, Transfer $tr self::deleteFusionInventoryLink($type, $id); } - if ($plug->isActivated('fields') && $model->fields['raz_plugin_fields'] == 1) { + if ($plug->isActivated('fields') && + $model->fields['action_plugin_fields_uninstall'] == PluginUninstallModel::PLUGIN_FIELDS_ACTION_RAZ) { self::deletePluginFieldsLink($type, $id); } + if ($model->fields['action_plugin_fields_uninstall'] == PluginUninstallModel::PLUGIN_FIELDS_ACTION_ADVANCED) { + self::handlePluginFieldsValues($type, $id, $model); + } + //Plugin hook after uninstall Plugin::doHook("plugin_uninstall_after", $item); } @@ -543,6 +548,110 @@ public static function deletePluginFieldsLink($itemtype, $items_id) } } + /** + * Update information related to the Fields plugin + * + * @param $itemtype the asset type + * @param $items_id the asset's ID in GLPI + * @param $model PluginUninstallModel + * + */ + public static function handlePluginFieldsValues($itemtype, $items_id, $model) + { + global $DB; + $item = new $itemtype(); + $item->getFromDB($items_id); + + $pluginFieldsContainer = new PluginFieldsContainer(); + $pluginFieldsField = new PluginFieldsField(); + + $pluginUninstallContainer = new PluginUninstallModelcontainer(); + $pluginUninstallField = new PluginUninstallModelcontainerfield(); + + // first level foreach & condition of first level if are copied from PluginFieldsContainer::preItemPurge + $existingFieldsContainers = $pluginFieldsContainer->find(); + foreach ($existingFieldsContainers as $fieldsContainer) { + $itemtypes = json_decode($fieldsContainer['itemtypes']); + if (in_array($itemtype, $itemtypes)) { + if ( + $pluginUninstallContainer->getFromDBByCrit([ + 'plugin_uninstall_models_id' => $model->getID(), + 'plugin_fields_containers_id' => $fieldsContainer['id'] + ]) + ) { + if ($pluginUninstallContainer->fields['action_uninstall'] != PluginUninstallModelcontainer::ACTION_NONE) { + $classname = 'PluginFields' . $itemtype . getSingular($fieldsContainer['name']); + $obj = new $classname(); + if ($pluginUninstallContainer->fields['action_uninstall'] == PluginUninstallModelcontainer::ACTION_RAZ) { + // same as PluginFieldsContainer::preItemPurge + $obj->deleteByCriteria(['items_id' => $item->fields['id']], true); + } else if ( + $pluginUninstallContainer->fields['action_uninstall'] == PluginUninstallModelcontainer::ACTION_CUSTOM + && $obj->getFromDBByCrit(['items_id' => $items_id]) + ) { + $uninstallFields = $pluginUninstallField->find([ + 'plugin_uninstall_modelcontainers_id' => $pluginUninstallContainer->getID() + ]); + $fieldsFields = $pluginFieldsField->find([ + 'plugin_fields_containers_id' => $fieldsContainer['id'] + ]); + + $update = []; + foreach ($uninstallFields as $setting) { + $field = array_filter($fieldsFields, fn($e) => $e['id'] == $setting['plugin_fields_fields_id']); + $field = reset($field); + + switch ($field['type']) { + case 'dropdown': + $property = 'plugin_fields_' . $field['name'] . 'dropdowns_id'; + break; + case 'glpi_item': + $property = 'items_id_' . $field['name']; + $itemtype = 'itemtype_' . $field['name']; + break; + default: + $property = $field['name']; + break; + } + + switch ($setting['action_uninstall']) { + case PluginUninstallModelcontainerfield::ACTION_RAZ: + $razValue = null; + // field types which doesn't accept NULL values + if ( + str_starts_with($field['type'], 'dropdown') + || $field['type'] == 'glpi_item' + || $field['type'] == 'yesno' + ) { + $razValue = 0; + if ($field['multiple']) { + $razValue = '[]'; + } + } + $update[$property] = $razValue; + if ($field['type'] == 'glpi_item') { + $update[$itemtype] = null; + } + break; + case PluginUninstallModelcontainerfield::ACTION_NEW_VALUE: + $update[$property] = $setting['new_value']; + break; + } + } + if ($update) { + $DB->update( + $obj->getTable(), + $update, + ['items_id' => $items_id] + ); + } + } + } + } + } + } + } + /** * Function to remove FusionInventory information for an asset * diff --git a/setup.php b/setup.php index 2b5c90d..4d32f3c 100644 --- a/setup.php +++ b/setup.php @@ -32,7 +32,7 @@ use function Safe\define; -define('PLUGIN_UNINSTALL_VERSION', '2.10.3'); +define('PLUGIN_UNINSTALL_VERSION', '2.10.4'); define("PLUGIN_UNINSTALL_MIN_GLPI", "11.0.0"); define("PLUGIN_UNINSTALL_MAX_GLPI", "11.0.99"); @@ -110,6 +110,17 @@ function plugin_init_uninstall() } $PLUGIN_HOOKS[Hooks::POST_INIT]['uninstall'] = 'plugin_uninstall_postinit'; + + if ($plugin->isActivated('fields')) { + $PLUGIN_HOOKS[Hooks::ITEM_ADD]['uninstall'] = [ + PluginFieldsContainer::class => 'plugin_uninstall_hook_add_container', + PluginFieldsField::class => 'plugin_uninstall_hook_add_field', + ]; + $PLUGIN_HOOKS[Hooks::ITEM_PURGE]['uninstall'] = [ + PluginFieldsContainer::class => 'plugin_uninstall_hook_purge_container', + PluginFieldsField::class => 'plugin_uninstall_hook_purge_field', + ]; + } } } diff --git a/templates/model_config.html.twig b/templates/model_config.html.twig index 706e414..39dc3e4 100644 --- a/templates/model_config.html.twig +++ b/templates/model_config.html.twig @@ -195,4 +195,13 @@ __('%1$s %2$s')|format(__('Copy'), __('Alternate username number')), field_options ) }} + {% if plugin_fields_activate %} + {{ fields.dropdownArrayField( + 'action_plugin_fields_replace', + item.fields.action_plugin_fields_replace ?? constant('PluginUninstallModel::PLUGIN_FIELDS_ACTION_NONE'), + fields_action_list, + __('Fields plugin informations', 'uninstall'), + field_options + ) }} + {% endif %} \ No newline at end of file diff --git a/templates/modelcontainer_showForm.html.twig b/templates/modelcontainer_showForm.html.twig new file mode 100644 index 0000000..1f6b47b --- /dev/null +++ b/templates/modelcontainer_showForm.html.twig @@ -0,0 +1,104 @@ +{# +# ------------------------------------------------------------------------- +# Uninstall plugin for GLPI +# ------------------------------------------------------------------------- +# +# LICENSE +# +# This file is part of Uninstall. +# +# Uninstall 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 2 of the License, or +# (at your option) any later version. +# +# Uninstall 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 Uninstall. If not, see . +# ------------------------------------------------------------------------- +# @copyright Copyright (C) 2015-2026 by Teclib'. +# @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html +# @link https://github.com/pluginsGLPI/uninstall +# ------------------------------------------------------------------------- +#} + +{% import 'components/form/fields_macros.html.twig' as fields %} + +

{{ __('Model') }} {{ modelValues['name'] }}

+ + {{ __('Block informations', 'uninstall') }} + + + {{ pluginFieldsContainer['typeName'] }} + {{ pluginFieldsContainer['values']['label'] }} + {{ __("Associated item type") }} : + {{ itemObjet }} + + + {% if modelValues['types_id'] != constant('PluginUninstallModel::TYPE_MODEL_UNINSTALL') %} + {{ __('Action for ', 'uninstall') }} {{ __('Replacement', 'uninstall') }} + {% endif %} + + {% if modelValues['types_id'] != constant('PluginUninstallModel::TYPE_MODEL_REPLACEMENT') %} + {{ __('Action for ', 'uninstall') }} {{ __('Uninstallation', 'uninstall') }} + {% endif %} + + + {% if modelValues['types_id'] != constant('PluginUninstallModel::TYPE_MODEL_UNINSTALL') %} + {{ __('Action') }} + + {% if modelValues['action_plugin_fields_replace'] == constant('PluginUninstallModel::PLUGIN_FIELDS_ACTION_ADVANCED') %} + {{ fields.dropdownArrayField( + 'action_replace', + dropdown['value'], + dropdown['values'], + '', + { + 'rand': rand, + 'width': dropdown['width'], + } + ) }} + {% else %} + + {% if modelValues['action_plugin_fields_replace'] == constant('PluginUninstallModel::PLUGIN_FIELDS_ACTION_NONE') %} + {{ __('Do nothing') }} + {% elseif modelValues['action_plugin_fields_replace'] == constant('PluginUninstallModel::PLUGIN_FIELDS_ACTION_COPY') %} + {{ __('Copy') }} + {% endif %} + ({{ __('inherit from model', 'uninstall') }}) + {% endif %} + + {% endif %} + + {% if modelValues['types_id'] != constant('PluginUninstallModel::TYPE_MODEL_REPLACEMENT') %} + {{ __('Action') }} + + {% if modelValues['action_plugin_fields_uninstall'] == constant('PluginUninstallModel::PLUGIN_FIELDS_ACTION_ADVANCED') %} + {{ fields.dropdownArrayField( + 'action_uninstall', + dropdown['value'], + dropdown['values'], + '', + { + 'rand': rand, + 'width': dropdown['width'], + } + ) }} + {% else %} + + {% if modelValues['action_plugin_fields_uninstall'] == constant('PluginUninstallModel::PLUGIN_FIELDS_ACTION_NONE') %} + {{ __('Do nothing') }} + {% elseif modelValues['action_plugin_fields_uninstall'] == constant('PluginUninstallModel::PLUGIN_FIELDS_ACTION_COPY') %} + {{ __('Copy') }} + {% endif %} + ({{ __('inherit from model', 'uninstall') }}) + {% endif %} + + {% endif %} + + + diff --git a/templates/modelcontainer_showList.html.twig b/templates/modelcontainer_showList.html.twig new file mode 100644 index 0000000..dd49fbc --- /dev/null +++ b/templates/modelcontainer_showList.html.twig @@ -0,0 +1,58 @@ +{# +# ------------------------------------------------------------------------- +# Uninstall plugin for GLPI +# ------------------------------------------------------------------------- +# +# LICENSE +# +# This file is part of Uninstall. +# +# Uninstall 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 2 of the License, or +# (at your option) any later version. +# +# Uninstall 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 Uninstall. If not, see . +# ------------------------------------------------------------------------- +# @copyright Copyright (C) 2015-2026 by Teclib'. +# @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html +# @link https://github.com/pluginsGLPI/uninstall +# ------------------------------------------------------------------------- +#} + + + + + + + + + + + + {% for uninstallContainer in uninstallContainers %} + {% if uninstallContainer['hasFieldContainer'] == true %} + + + + + + {% endif %} + {% endfor %} + + +
{{ __('Block', 'fields') }}{{ __("Action") }}{{ __("Associated item type") }}
+ {{ uninstallContainer['fieldContainerValues']['label'] }} + + + {{ uninstallContainer['action'] }} + + + {{ uninstallContainer['obj'] }} +
diff --git a/templates/modelcontainerfield_showForm.html.twig b/templates/modelcontainerfield_showForm.html.twig new file mode 100644 index 0000000..bbd21a4 --- /dev/null +++ b/templates/modelcontainerfield_showForm.html.twig @@ -0,0 +1,213 @@ +{# +# ------------------------------------------------------------------------- +# Uninstall plugin for GLPI +# ------------------------------------------------------------------------- +# +# LICENSE +# +# This file is part of Uninstall. +# +# Uninstall 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 2 of the License, or +# (at your option) any later version. +# +# Uninstall 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 Uninstall. If not, see . +# ------------------------------------------------------------------------- +# @copyright Copyright (C) 2015-2026 by Teclib'. +# @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html +# @link https://github.com/pluginsGLPI/uninstall +# ------------------------------------------------------------------------- +#} + +{% import 'components/form/fields_macros.html.twig' as fields %} + + + {{ __('Parents', 'uninstall') }} + + + {{ __('Model') }} : + {{ model['name'] }} + {{ __('Bloc') }} + {{ fieldsContainer['name'] }} + + + {{ __('Field informations', 'uninstall') }} + + + {{ __("Label") }} : + {{ pluginFieldsField['label'] }} + {{ __("Type") }} : + {{ pluginFieldsFieldType }} + + + {{ __('Active') }} : + + {% if pluginFieldsField['is_active'] %} + {{ __('Yes') }} + {% else %} + {{ __('No') }} + {% endif %} + + {{ __("Mandatory field") }} : + + {% if pluginFieldsField['mandatory'] %} + {{ __('Yes') }} + {% else %} + {{ __('No') }} + {% endif %} + + + + + + {% set actionFields = ['action_replace', 'action_uninstall'] %} + + {% for field in actionFields %} + + {% if + (field == 'action_uninstall' and modelValues['types_id'] != constant('PluginUninstallModel::TYPE_MODEL_REPLACEMENT')) + or + (field == 'action_replace' and modelValues['types_id'] != constant('PluginUninstallModel::TYPE_MODEL_UNINSTALL')) + %} + + {% if field == 'action_uninstall' %} + {% set typeTitle = __('Uninstallation', 'uninstall') %} + {% set modelProperty = 'action_plugin_fields_uninstall' %} + {% elseif field == 'action_replace' %} + {% set typeTitle = __('Replacement', 'uninstall') %} + {% set modelProperty = 'action_plugin_fields_replace' %} + {% endif %} + + + + {{ __('Action for ', 'uninstall') ~ typeTitle }} + + + + + + + {% if + modelValues[modelProperty] == constant('PluginUninstallModel::PLUGIN_FIELDS_ACTION_ADVANCED') + and uninstallContainer[field] == constant('PluginUninstallModelcontainer::ACTION_CUSTOM') + %} + + {{ __('Action') }} : + + {% set colspan = field == 'action_uninstall' ? 1 : 3 %} + + + {% set rand = random() %} + + {% set options = { + constant('PluginUninstallModelcontainerfield::ACTION_NONE'): __('Do nothing') + } %} + + {% if field == 'action_uninstall' %} + {% set options = options|merge({ + (constant('PluginUninstallModelcontainerfield::ACTION_RAZ')): __('Blank') + }) %} + + {% if pluginFieldsField['type'] != 'glpi_item' %} + {% set options = options|merge({ + (constant('PluginUninstallModelcontainerfield::ACTION_NEW_VALUE')): __('Set value', 'uninstall') + }) %} + {% endif %} + {% else %} + {% set options = options|merge({ + (constant('PluginUninstallModelcontainerfield::ACTION_COPY')): __('Copy') + }) %} + {% endif %} + + + {{ fields.dropdownArrayField( + field, + itemValues[field] ?? constant('PluginUninstallModelcontainerfield::ACTION_NONE'), + options, + '', + { + 'rand': rand, + 'width': '100%', + } + ) }} + + + {% if field == 'action_uninstall' %} + + + + + + {% if pluginFieldsField['type'] == 'glpi_item' %} + {{ __('Action set value is not available for this field type', 'uninstall') }} + {% endif %} + + + + + {% endif %} + + {% else %} + + {% if modelValues[modelProperty] == constant('PluginUninstallModel::PLUGIN_FIELDS_ACTION_ADVANCED') %} + + {{ undertitle[field] }} + ({{ __('set by bloc', 'uninstall') }}) + + + {% else %} + + {% if modelValues[modelProperty] == constant('PluginUninstallModel::PLUGIN_FIELDS_ACTION_NONE') %} + {% set action = __('Do nothing') %} + {% elseif modelValues[modelProperty] == constant('PluginUninstallModel::PLUGIN_FIELDS_ACTION_RAZ') %} + {% set action = __('Blank') %} + {% elseif modelValues[modelProperty] == constant('PluginUninstallModel::PLUGIN_FIELDS_ACTION_COPY') %} + {% set action = __('Copy') %} + {% endif %} + + + {{ action }} + ({{ __('set by model', 'uninstall') }}) + + + {% endif %} + {% endif %} + + + + {% endif %} +{% endfor %} + + + +