diff --git a/ajax/fieldValueInput.php b/ajax/fieldValueInput.php new file mode 100644 index 0000000..6a2a6e2 --- /dev/null +++ b/ajax/fieldValueInput.php @@ -0,0 +1,139 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2015-2023 by Teclib'. + * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html + * @link https://github.com/pluginsGLPI/uninstall + * ------------------------------------------------------------------------- + */ + +include('../../../inc/includes.php'); +header("Content-Type: text/html; charset=UTF-8"); +Html::header_nocache(); + +Session::checkLoginUser(); +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; +} diff --git a/ajax/saveField.php b/ajax/saveField.php new file mode 100644 index 0000000..e5814e8 --- /dev/null +++ b/ajax/saveField.php @@ -0,0 +1,46 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2015-2023 by Teclib'. + * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html + * @link https://github.com/pluginsGLPI/uninstall + * ------------------------------------------------------------------------- + */ + +include('../../../inc/includes.php'); +header("Content-Type: text/html; charset=UTF-8"); +Html::header_nocache(); + +Session::checkLoginUser(); + +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 ""; +} diff --git a/front/model.form.php b/front/model.form.php index 1505f90..b802f85 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(); } else if (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(); } else if (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..3fb42c9 --- /dev/null +++ b/front/modelcontainer.form.php @@ -0,0 +1,51 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2015-2023 by Teclib'. + * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html + * @link https://github.com/pluginsGLPI/uninstall + * ------------------------------------------------------------------------- + */ + +include('../../../inc/includes.php'); + +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(); +} diff --git a/front/modelcontainerfield.form.php b/front/modelcontainerfield.form.php new file mode 100644 index 0000000..581cb56 --- /dev/null +++ b/front/modelcontainerfield.form.php @@ -0,0 +1,58 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2015-2023 by Teclib'. + * @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html + * @link https://github.com/pluginsGLPI/uninstall + * ------------------------------------------------------------------------- + */ + +include('../../../inc/includes.php'); + +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(); +} diff --git a/hook.php b/hook.php index 0d62f63..2fac3c8 100644 --- a/hook.php +++ b/hook.php @@ -57,6 +57,16 @@ function plugin_uninstall_addDefaultWhere($itemtype) return "`glpi_plugin_uninstall_models`.`types_id` = '1'"; } break; + case 'PluginUninstallModelcontainer': + if (isset($_GET['id'])) { + return "`glpi_plugin_uninstall_modelcontainers`.`plugin_uninstall_models_id` = '" . $_GET['id'] . "'"; + } + break; + case 'PluginUninstallModelcontainerfield': + if (isset($_GET['id'])) { + return "`glpi_plugin_uninstall_modelcontainerfields`.`plugin_uninstall_modelcontainers_id` = '" . $_GET['id'] . "'"; + } + break; } } @@ -76,11 +86,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(); @@ -103,5 +117,92 @@ function plugin_uninstall_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 09a6c7e..24b4746 100644 --- a/inc/model.class.php +++ b/inc/model.class.php @@ -39,6 +39,16 @@ class PluginUninstallModel extends CommonDBTM const TYPE_MODEL_REPLACEMENT = 2; 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 _n("Template", "Templates", $nb); @@ -92,7 +102,7 @@ public function prepareInputForAdd($input) if (array_key_exists('types_id', $input) && array_key_exists('replace_method', $input)) { if ($input['types_id'] == self::TYPE_MODEL_REPLACEMENT_UNINSTALL && $input['replace_method'] == PluginUninstallReplace::METHOD_PURGE) { Session::addMessageAfterRedirect( - __("The purge archiving method is not available for this model type", 'uninstall'), + __("The purge archiving method is not available for this type of model", 'uninstall'), true, ERROR ); @@ -196,6 +206,10 @@ public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) $tab = []; $tab[1] = self::getTypeName(1); $tab[2] = __('Replacing data', 'uninstall'); + $plugin = new Plugin(); + if ($plugin->isActivated('fields')) { + $tab[3] = __('Additional fields options', 'uninstall'); + } return $tab; } return ''; @@ -215,6 +229,9 @@ public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $ case 2: $item->showFormAction($item); break; + case 3: + $item->showFormPluginFields($item); + break; } } return true; @@ -462,6 +479,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() @@ -669,6 +713,33 @@ public function showPartFormRemplacement() ); echo ""; echo ""; + + if ((new Plugin())->isActivated('fields')) { + echo ""; + echo "" . __('Replacement', 'uninstall') . ' - ' . __("Additionnal fields", "fields") . + ""; + + echo ""; + echo "" . __('Fields plugin informations', 'uninstall') . ""; + echo ""; + $choices = [ + self::PLUGIN_FIELDS_ACTION_NONE => __('Do nothing'), + self::PLUGIN_FIELDS_ACTION_COPY => __('Copy'), + self::PLUGIN_FIELDS_ACTION_ADVANCED => __('Advanced options', 'uninstall') + ]; + Dropdown::showFromArray( + "action_plugin_fields_replace", + $choices, + [ + 'value' => isset($this->fields["action_plugin_fields_replace"]) ? + $this->fields["action_plugin_fields_replace"] : self::PLUGIN_FIELDS_ACTION_NONE, + 'width' => '100%' + ] + ); + echo ""; + echo ""; + echo ""; + } } /** @@ -764,26 +835,6 @@ public function showFormAction($item) echo ""; } - if ($plug->isActivated('fields')) { - echo ""; - echo "" . __("Additionnal fields", "fields") . - ""; - - echo ""; - echo "" . __('Delete Fields plugin informations', 'uninstall') . ""; - echo ""; - Dropdown::showYesNo( - "raz_plugin_fields", - (isset($this->fields["raz_plugin_fields"]) - ? $this->fields["raz_plugin_fields"] : 1), - -1, - ['width' => '100%'] - ); - echo ""; - echo ""; - echo ""; - } - if ($canedit) { echo ""; echo ""; @@ -800,6 +851,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 @@ -1365,6 +1470,41 @@ public static function install($migration) $migration->addField($table, 'raz_glpiinventory', "integer"); } + // from 2.9.2 to 2.10.0 + 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'] + ) + ); + } $migration->migrationOneTable($table); $self = new self(); @@ -1415,7 +1555,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`) @@ -1480,7 +1621,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; @@ -1580,4 +1722,43 @@ public static function getIcon() { return "fas fa-recycle"; } + + /** + * 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..a33eead --- /dev/null +++ b/inc/modelcontainer.class.php @@ -0,0 +1,607 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2015-2023 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 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 + echo "

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

"; + echo ""; + // associated plugin fields block informations + echo "" . __('Block informations', 'uninstall') . + ""; + echo ""; + echo "" . $pluginFieldsContainer->getTypeName() . " : "; + echo ""; + echo "" . $pluginFieldsContainer->fields['label'] . ""; + echo ""; + echo "" . __("Associated item type") . " : "; + echo ""; + $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++; + } + echo $obj; + echo ""; + echo ""; + + // actual form data + $titleColspan = 4; + $actionColspan = 3; + if ($model->fields['types_id'] == $model::TYPE_MODEL_REPLACEMENT_UNINSTALL) { + $titleColspan = 2; + $actionColspan = 1; + } + + echo ""; + if ($model->fields['types_id'] != $model::TYPE_MODEL_UNINSTALL) { + echo "" . __('Action for ', 'uninstall') . __('Replacement', 'uninstall') . ""; + } + if ($model->fields['types_id'] != $model::TYPE_MODEL_REPLACEMENT) { + echo "" . __('Action for ', 'uninstall') . __('Uninstallation', 'uninstall') . ""; + } + echo ""; + echo ""; + if ($model->fields['types_id'] != $model::TYPE_MODEL_UNINSTALL) { + echo "" . __('Action') . ""; + echo ""; + if ($model->fields['action_plugin_fields_replace'] == $model::PLUGIN_FIELDS_ACTION_ADVANCED) { + $rand = mt_rand(); + Dropdown::showFromArray( + "action_replace", + self::getActions($model::TYPE_MODEL_REPLACEMENT), + [ + 'value' => (isset($this->fields["action_replace"]) + ? $this->fields["action_replace"] : $this::ACTION_NONE), + 'width' => '100%', + 'rand' => $rand + ] + ); + } else { + switch ($model->fields['action_plugin_fields_replace']) { + case $model::PLUGIN_FIELDS_ACTION_NONE: + $action = __('Do nothing'); + break; + case $model::PLUGIN_FIELDS_ACTION_COPY: + $action = __('Copy'); + } + + echo "" . $action . " " . "(" . __('inherit from model', 'uninstall') . ")"; + } + echo ""; + } + + if ($model->fields['types_id'] != $model::TYPE_MODEL_REPLACEMENT) { + echo "" . __('Action') . ""; + echo ""; + if ($model->fields['action_plugin_fields_uninstall'] == $model::PLUGIN_FIELDS_ACTION_ADVANCED) { + $rand = mt_rand(); + Dropdown::showFromArray( + "action_uninstall", + self::getActions($model::TYPE_MODEL_UNINSTALL), + [ + 'value' => (isset($this->fields["action_uninstall"]) + ? $this->fields["action_uninstall"] : $this::ACTION_NONE), + 'width' => '100%', + 'rand' => $rand + ] + ); + } else { + switch ($model->fields['action_plugin_fields_uninstall']) { + case $model::PLUGIN_FIELDS_ACTION_NONE: + $action = __('Do nothing'); + break; + case $model::PLUGIN_FIELDS_ACTION_RAZ: + $action = __('Blank'); + } + + echo "" . $action . " " . "(" . __('inherit from model', 'uninstall') . ")"; + } + echo ""; + } + echo ""; + + $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)) { + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + $actionProperty = $type === PluginUninstallModel::TYPE_MODEL_UNINSTALL ? 'action_uninstall' : 'action_replace'; + foreach ($uninstallContainers as $uninstallContainer) { + if ($fieldContainer->getFromDB($uninstallContainer['plugin_fields_containers_id'])) { + echo ""; + $link = PluginUninstallModelContainer::getFormURLWithID($uninstallContainer['id']); + echo ""; + echo ""; + $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++; + } + echo ""; + echo ""; + } + } + echo ""; + echo "
" . __('Block', 'fields') . "" . __("Action") . "" . __("Associated item type") . "
"; + echo "" . $fieldContainer->fields['label'] . ""; + echo "" . self::getActions()[$uninstallContainer[$actionProperty]] . "" . $obj . "
"; + } 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->queryOrDie($query, $DB->error()); + } + return true; + } + + public static function uninstall() + { + /** @var DBmysql $DB */ + global $DB; + + $DB->query("DROP TABLE IF EXISTS `" . getTableForItemType(__CLASS__) . "`"); + + $DB->query("DELETE FROM `glpi_displaypreferences` WHERE `itemtype` = '" . self::class . "';"); + + //Delete history + $log = new Log(); + $log->dohistory = false; + $log->deleteByCriteria(['itemtype' => __CLASS__]); + } +} diff --git a/inc/modelcontainerfield.class.php b/inc/modelcontainerfield.class.php new file mode 100644 index 0000000..0da39e6 --- /dev/null +++ b/inc/modelcontainerfield.class.php @@ -0,0 +1,308 @@ +. + * ------------------------------------------------------------------------- + * @copyright Copyright (C) 2015-2023 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'])) { + // context + echo ""; + echo "" . __('Parents', 'uninstall') . + ""; + echo ""; + echo "" . __('Model') . " : "; + echo ""; + echo "" . $model->fields['name'] . ""; + echo ""; + echo "" . __('Bloc') . " : "; + echo ""; + echo "" . $fieldsContainer->fields['name'] . ""; + echo ""; + echo ""; + echo ""; + // field infos + echo "" . __('Field informations', 'uninstall') . + ""; + echo ""; + echo "" . __("Label") . " : "; + echo ""; + echo $pluginFieldsField->fields['label']; + echo ""; + echo "" . __("Type") . " : "; + echo ""; + echo PluginFieldsField::getTypes(true)[$pluginFieldsField->fields['type']]; + echo ""; + echo ""; + // DEFAULT VALUE + echo ""; + echo "" . __('Active') . " :"; + echo ""; + echo $pluginFieldsField->fields["is_active"] ? __('Yes') : __('No'); + echo ""; + echo "" . __("Mandatory field") . " : "; + echo ""; + echo $pluginFieldsField->fields["mandatory"] ? __('Yes') : __('No'); + echo ""; + echo ""; + + $actionFields = ['action_replace', 'action_uninstall']; + foreach ($actionFields as $field) { + // model can use the property + 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; + } + + echo "" . __('Action for ', 'uninstall') . $typeTitle . + ""; + echo ""; + // model and container let the action be decided at this level, display dropdown + if ( + $model->fields[$modelProperty] == $model::PLUGIN_FIELDS_ACTION_ADVANCED + && $uninstallContainer->fields[$field] == $uninstallContainer::ACTION_CUSTOM + ) { + echo "" . __('Action') . " :"; + $colspan = $field == 'action_uninstall' ? 1 : 3; + echo ""; + $rand = mt_rand(); + $options = [ + self::ACTION_NONE => __('Do nothing'), + ]; + if ($field == 'action_uninstall') { + $options[self::ACTION_RAZ] = __('Blank'); + if ($pluginFieldsField->fields['type'] !== 'glpi_item') { + $options[self::ACTION_NEW_VALUE] = __('Set value', 'uninstall'); + } + } else { + $options[self::ACTION_COPY] = __('Copy'); + } + + Dropdown::showFromArray( + $field, + $options, + [ + 'value' => (isset($this->fields[$field]) + ? $this->fields[$field] : self::ACTION_NONE), + 'width' => '100%', + 'rand' => $rand + ] + ); + echo ""; + // for uninstall, show the part that allow for a new value to be set + if ($field == 'action_uninstall') { + echo ""; + echo ""; + if ($pluginFieldsField->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 " + + "; + } + } else { + if ($model->fields[$modelProperty] == $model::PLUGIN_FIELDS_ACTION_ADVANCED) { + echo "" . $uninstallContainer::getActions()[$uninstallContainer->fields[$field]] . " (" . __('set by bloc', 'uninstall') . ")"; + } else { + 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; + } + + echo "" . $action . " (" . __('set by model', 'uninstall') . ")"; + } + } + echo ""; + } + } + + $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->queryOrDie($query, $DB->error()); + } + return true; + } + + public static function uninstall() + { + /** @var DBmysql $DB */ + global $DB; + + $DB->query("DROP TABLE IF EXISTS `" . getTableForItemType(__CLASS__) . "`"); + + $DB->query("DELETE FROM `glpi_displaypreferences` WHERE `itemtype` = '" . self::class . "';"); + + //Delete history + $log = new Log(); + $log->dohistory = false; + $log->deleteByCriteria(['itemtype' => __CLASS__]); + } +} diff --git a/inc/replace.class.php b/inc/replace.class.php index ded1479..9230fe8 100644 --- a/inc/replace.class.php +++ b/inc/replace.class.php @@ -448,6 +448,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 : Purge switch ($model->fields['replace_method']) { case self::METHOD_PURGE: @@ -1097,4 +1124,101 @@ public static function getPdfUserPreference($item) return $tabs; } } + + /** + * 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 789d560..dd4e1c9 100644 --- a/inc/uninstall.class.php +++ b/inc/uninstall.class.php @@ -316,9 +316,12 @@ private static function doOneUninstall(PluginUninstallModel $model, Transfer $tr } if ($plug->isActivated('fields')) { - if ($model->fields['raz_plugin_fields'] == 1) { + if ($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 @@ -508,6 +511,110 @@ public static function deletePluginFieldsLink($itemtype, $items_id) PluginFieldsContainer::preItemPurge($item); } + /** + * 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/locales/fr_FR.mo b/locales/fr_FR.mo index bb630e1..5f86a77 100644 Binary files a/locales/fr_FR.mo and b/locales/fr_FR.mo differ diff --git a/locales/fr_FR.po b/locales/fr_FR.po index 8718585..06d5205 100644 --- a/locales/fr_FR.po +++ b/locales/fr_FR.po @@ -328,4 +328,4 @@ msgstr "Désinstallation" #: inc/uninstall.class.php:367 front/action.php:114 msgid "Uninstallation successful" -msgstr "Désinstallation effectuée avec succès" +msgstr "Désinstallation effectuée avec succès" \ No newline at end of file diff --git a/setup.php b/setup.php index 842207d..b0936f9 100644 --- a/setup.php +++ b/setup.php @@ -30,7 +30,7 @@ use Glpi\Plugin\Hooks; -define('PLUGIN_UNINSTALL_VERSION', '2.9.2'); +define('PLUGIN_UNINSTALL_VERSION', '2.9.3'); // Minimal GLPI version, inclusive define("PLUGIN_UNINSTALL_MIN_GLPI", "10.0.7"); @@ -135,6 +135,17 @@ function plugin_init_uninstall() } } $PLUGIN_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', + ]; + } } }