586 lines
20 KiB
PHP
586 lines
20 KiB
PHP
<?php
|
|
/**
|
|
* ---------------------------------------------------------------------
|
|
* GLPI - Gestionnaire Libre de Parc Informatique
|
|
* Copyright (C) 2015-2020 Teclib' and contributors.
|
|
*
|
|
* http://glpi-project.org
|
|
*
|
|
* based on GLPI - Gestionnaire Libre de Parc Informatique
|
|
* Copyright (C) 2003-2014 by the INDEPNET Development Team.
|
|
*
|
|
* ---------------------------------------------------------------------
|
|
*
|
|
* LICENSE
|
|
*
|
|
* This file is part of GLPI.
|
|
*
|
|
* GLPI 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.
|
|
*
|
|
* GLPI 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 GLPI. If not, see <http://www.gnu.org/licenses/>.
|
|
* ---------------------------------------------------------------------
|
|
*/
|
|
|
|
if (!defined('GLPI_ROOT')) {
|
|
die("Sorry. You can't access this file directly");
|
|
}
|
|
|
|
class RuleDictionnarySoftwareCollection extends RuleCollection {
|
|
// From RuleCollection
|
|
|
|
public $stop_on_first_match = true;
|
|
public $can_replay_rules = true;
|
|
public $menu_type = 'dictionnary';
|
|
public $menu_option = 'software';
|
|
|
|
static $rightname = 'rule_dictionnary_software';
|
|
|
|
/**
|
|
* @see RuleCollection::getTitle()
|
|
**/
|
|
function getTitle() {
|
|
//TRANS: software in plural
|
|
return __('Dictionnary of software');
|
|
}
|
|
|
|
|
|
/**
|
|
* @see RuleCollection::cleanTestOutputCriterias()
|
|
**/
|
|
function cleanTestOutputCriterias(array $output) {
|
|
|
|
//If output array contains keys begining with _ : drop it
|
|
foreach ($output as $criteria => $value) {
|
|
if (($criteria[0] == '_') && ($criteria != '_ignore_import')) {
|
|
unset ($output[$criteria]);
|
|
}
|
|
}
|
|
return $output;
|
|
}
|
|
|
|
|
|
/**
|
|
* @see RuleCollection::warningBeforeReplayRulesOnExistingDB()
|
|
**/
|
|
function warningBeforeReplayRulesOnExistingDB($target) {
|
|
global $CFG_GLPI;
|
|
|
|
echo "<form name='testrule_form' id='softdictionnary_confirmation' method='post' action=\"" .
|
|
$target . "\">\n";
|
|
echo "<div class='center'>";
|
|
echo "<table class='tab_cadre_fixe'>";
|
|
echo "<tr><th colspan='2' class='b'>" .
|
|
__('Warning before running rename based on the dictionary rules') . "</th></tr>\n";
|
|
echo "<tr><td class='tab_bg_2 center'>";
|
|
echo "<img src=\"" . $CFG_GLPI["root_doc"] . "/pics/warning.png\"></td>";
|
|
echo "<td class='tab_bg_2 center'>" .
|
|
__('Warning! This operation can put merged software in the trashbin.<br>Sure to notify your users.').
|
|
"</td></tr>\n";
|
|
echo "<tr><th colspan='2' class='b'>" . __('Manufacturer choice') . "</th></tr>\n";
|
|
echo "<tr><td class='tab_bg_2 center'>" .
|
|
__('Replay dictionary rules for manufacturers (----- = All)') . "</td>";
|
|
echo "<td class='tab_bg_2 center'>";
|
|
Manufacturer::dropdown(['name' => 'manufacturer']);
|
|
echo "</td></tr>\n";
|
|
|
|
echo "<tr><td class='tab_bg_2 center' colspan='2'>";
|
|
echo "<input type='submit' name='replay_rule' value=\""._sx('button', 'Post')."\"
|
|
class='submit'>";
|
|
echo "<input type='hidden' name='replay_confirm' value='replay_confirm'>";
|
|
echo "</td></tr>";
|
|
echo "</table>\n";
|
|
echo "</div>\n";
|
|
Html::closeForm();
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* @see RuleCollection::replayRulesOnExistingDB()
|
|
**/
|
|
function replayRulesOnExistingDB($offset = 0, $maxtime = 0, $items = [], $params = []) {
|
|
global $DB;
|
|
|
|
if (isCommandLine()) {
|
|
echo "replayRulesOnExistingDB started : " . date("r") . "\n";
|
|
}
|
|
$nb = 0;
|
|
$i = $offset;
|
|
|
|
if (count($items) == 0) {
|
|
//Select all the differents software
|
|
$criteria = [
|
|
'SELECT' => [
|
|
'glpi_softwares.name',
|
|
'glpi_manufacturers.name AS manufacturer',
|
|
'glpi_softwares.manufacturers_id AS manufacturers_id',
|
|
'glpi_softwares.entities_id AS entities_id',
|
|
'glpi_softwares.is_helpdesk_visible AS helpdesk',
|
|
'glpi_softwares.softwarecategories_id AS softwarecategories_id',
|
|
],
|
|
'DISTINCT' => true,
|
|
'FROM' => 'glpi_softwares',
|
|
'LEFT JOIN' => [
|
|
'glpi_manufacturers' => [
|
|
'ON' => [
|
|
'glpi_manufacturers' => 'id',
|
|
'glpi_softwares' => 'manufacturers_id'
|
|
]
|
|
]
|
|
],
|
|
'WHERE' => [
|
|
// Do not replay on trashbin and templates
|
|
'glpi_softwares.is_deleted' => 0,
|
|
'glpi_softwares.is_template' => 0
|
|
]
|
|
];
|
|
|
|
if (isset($params['manufacturer']) && $params['manufacturer']) {
|
|
$criteria['WHERE']['glpi_softwares.manufacturers_id'] = $params['manufacturer'];
|
|
}
|
|
if ($offset) {
|
|
$criteria['START'] = (int)$offset;
|
|
}
|
|
|
|
$iterator = $DB->request($criteria);
|
|
$nb = count($iterator) + $offset;
|
|
$step = (($nb > 1000) ? 50 : (($nb > 20) ? floor(count($iterator) / 20) : 1));
|
|
|
|
while ($input = $iterator->next()) {
|
|
if (!($i % $step)) {
|
|
if (isCommandLine()) {
|
|
printf(__('%1$s - replay rules on existing database: %2$s/%3$s (%4$s Mio)')."\n",
|
|
date("H:i:s"), $i, $nb, round(memory_get_usage() / (1024 * 1024), 2));
|
|
} else {
|
|
Html::changeProgressBarPosition($i, $nb, "$i / $nb");
|
|
}
|
|
}
|
|
|
|
//If manufacturer is set, then first run the manufacturer's dictionnary
|
|
if (isset($input["manufacturer"])) {
|
|
$input["manufacturer"] = Manufacturer::processName($input["manufacturer"]);
|
|
}
|
|
|
|
//Replay software dictionnary rules
|
|
$res_rule = $this->processAllRules($input, [], []);
|
|
|
|
if ((isset($res_rule["name"]) && (strtolower($res_rule["name"]) != strtolower($input["name"])))
|
|
|| (isset($res_rule["version"]) && ($res_rule["version"] != ''))
|
|
|| (isset($res_rule['new_entities_id'])
|
|
&& ($res_rule['new_entities_id'] != $input['entities_id']))
|
|
|| (isset($res_rule['is_helpdesk_visible'])
|
|
&& ($res_rule['is_helpdesk_visible'] != $input['helpdesk']))
|
|
|| (isset($res_rule['manufacturer'])
|
|
&& ($res_rule['manufacturer'] != $input['manufacturer']))
|
|
|| (isset($res_rule['softwarecategories_id'])
|
|
&& ($res_rule['softwarecategories_id'] != $input['softwarecategories_id']))) {
|
|
|
|
$IDs = [];
|
|
//Find all the softwares in the database with the same name and manufacturer
|
|
$same_iterator = $DB->request([
|
|
'SELECT' => 'id',
|
|
'FROM' => 'glpi_softwares',
|
|
'WHERE' => [
|
|
'name' => $input['name'],
|
|
'manufacturers_id' => $input['manufacturers_id']
|
|
]
|
|
]);
|
|
|
|
if (count($same_iterator)) {
|
|
//Store all the software's IDs in an array
|
|
while ($result = $same_iterator->next()) {
|
|
$IDs[] = $result["id"];
|
|
}
|
|
//Replay dictionnary on all the softwares
|
|
$this->replayDictionnaryOnSoftwaresByID($IDs, $res_rule);
|
|
}
|
|
}
|
|
$i++;
|
|
if ($maxtime) {
|
|
$crt = explode(" ", microtime());
|
|
if (($crt[0] + $crt[1]) > $maxtime) {
|
|
break;
|
|
}
|
|
}
|
|
} // each distinct software
|
|
|
|
if (isCommandLine()) {
|
|
printf(__('Replay rules on existing database: %1$s/%2$s')." \n", $i, $nb);
|
|
} else {
|
|
Html::changeProgressBarPosition($i, $nb, "$i / $nb");
|
|
}
|
|
|
|
} else {
|
|
$this->replayDictionnaryOnSoftwaresByID($items);
|
|
return true;
|
|
}
|
|
|
|
if (isCommandLine()) {
|
|
printf(__('Replay rules on existing database ended on %s')."\n", date("r"));
|
|
}
|
|
|
|
return (($i == $nb) ? -1 : $i);
|
|
}
|
|
|
|
|
|
/**
|
|
* Replay dictionnary on several softwares
|
|
*
|
|
* @param $IDs array of software IDs to replay
|
|
* @param $res_rule array of rule results
|
|
*
|
|
* @return Query result handler
|
|
**/
|
|
function replayDictionnaryOnSoftwaresByID(array $IDs, $res_rule = []) {
|
|
global $DB;
|
|
|
|
$new_softs = [];
|
|
$delete_ids = [];
|
|
|
|
foreach ($IDs as $ID) {
|
|
$iterator = $DB->request([
|
|
'SELECT' => [
|
|
'gs.id',
|
|
'gs.name AS name',
|
|
'gs.entities_id AS entities_id',
|
|
'gm.name AS manufacturer'
|
|
],
|
|
'FROM' => 'glpi_softwares AS gs',
|
|
'LEFT JOIN' => [
|
|
'glpi_manufacturers AS gm' => [
|
|
'ON' => [
|
|
'gs' => 'manufacturers_id',
|
|
'gm' => 'id'
|
|
]
|
|
]
|
|
],
|
|
'WHERE' => [
|
|
'gs.is_template' => 0,
|
|
'gs.id' => $ID
|
|
]
|
|
]);
|
|
|
|
if (count($iterator)) {
|
|
$soft = $iterator->next();
|
|
//For each software
|
|
$this->replayDictionnaryOnOneSoftware(
|
|
$new_softs,
|
|
$res_rule,
|
|
$ID,
|
|
(isset($res_rule['new_entities_id'])
|
|
? $res_rule['new_entities_id']
|
|
: $soft["entities_id"]
|
|
),
|
|
$soft['name'] ?? '',
|
|
$soft['manufacturer'] ?? '',
|
|
$delete_ids
|
|
);
|
|
}
|
|
}
|
|
//Delete software if needed
|
|
$this->putOldSoftsInTrash($delete_ids);
|
|
}
|
|
|
|
|
|
/**
|
|
* Replay dictionnary on one software
|
|
*
|
|
* @param &$new_softs array containing new softwares already computed
|
|
* @param $res_rule array of rule results
|
|
* @param $ID ID of the software
|
|
* @param $entity working entity ID
|
|
* @param $name softwrae name
|
|
* @param $manufacturer manufacturer name
|
|
* @param &$soft_ids array containing replay software need to be put in trashbin
|
|
**/
|
|
function replayDictionnaryOnOneSoftware(array &$new_softs, array $res_rule, $ID, $entity, $name,
|
|
$manufacturer, array &$soft_ids) {
|
|
global $DB;
|
|
|
|
$input["name"] = $name;
|
|
$input["manufacturer"] = $manufacturer;
|
|
$input["entities_id"] = $entity;
|
|
|
|
if (empty($res_rule)) {
|
|
$res_rule = $this->processAllRules($input, [], []);
|
|
}
|
|
$soft = new Software();
|
|
if (isset($res_rules['_ignore_import']) && ($res_rules['_ignore_import'] == 1)) {
|
|
$soft->putInTrash($ID, __('Software deleted by GLPI dictionary rules'));
|
|
return;
|
|
}
|
|
|
|
//Software's name has changed or entity
|
|
if ((isset($res_rule["name"]) && (strtolower($res_rule["name"]) != strtolower($name)))
|
|
//Entity has changed, and new entity is a parent of the current one
|
|
|| (!isset($res_rule["name"])
|
|
&& isset($res_rule['new_entities_id'])
|
|
&& in_array($res_rule['new_entities_id'],
|
|
getAncestorsOf('glpi_entities', $entity)))) {
|
|
|
|
if (isset($res_rule["name"])) {
|
|
$new_name = $res_rule["name"];
|
|
} else {
|
|
$new_name = addslashes($name);
|
|
}
|
|
|
|
if (isset($res_rule["manufacturer"]) && $res_rule["manufacturer"]) {
|
|
$manufacturer = $res_rule["manufacturer"];
|
|
} else {
|
|
$manufacturer = addslashes($manufacturer);
|
|
}
|
|
|
|
//New software not already present in this entity
|
|
if (!isset($new_softs[$entity][$new_name])) {
|
|
// create new software or restore it from trashbin
|
|
$new_software_id = $soft->addOrRestoreFromTrash($new_name, $manufacturer,
|
|
$entity, '', true);
|
|
$new_softs[$entity][$new_name] = $new_software_id;
|
|
} else {
|
|
$new_software_id = $new_softs[$entity][$new_name];
|
|
}
|
|
// Move licenses to new software
|
|
$this->moveLicenses($ID, $new_software_id);
|
|
|
|
} else {
|
|
$new_software_id = $ID;
|
|
$res_rule["id"] = $ID;
|
|
if (isset($res_rule["manufacturer"]) && $res_rule["manufacturer"]) {
|
|
$res_rule["manufacturers_id"] = Dropdown::importExternal('Manufacturer',
|
|
$res_rule["manufacturer"]);
|
|
unset($res_rule["manufacturer"]);
|
|
}
|
|
$soft->update($res_rule);
|
|
}
|
|
|
|
// Add to software to deleted list
|
|
if ($new_software_id != $ID) {
|
|
$soft_ids[] = $ID;
|
|
}
|
|
|
|
//Get all the different versions for a software
|
|
$iterator = $DB->request([
|
|
'FROM' => 'glpi_softwareversions',
|
|
'WHERE' => ['softwares_id' => $ID]
|
|
]);
|
|
|
|
while ($version = $iterator->next()) {
|
|
$input["version"] = addslashes($version["name"]);
|
|
$old_version_name = $input["version"];
|
|
|
|
if (isset($res_rule['version_append']) && $res_rule['version_append'] != '') {
|
|
$new_version_name = $old_version_name . $res_rule['version_append'];
|
|
} else if (isset($res_rule["version"]) && $res_rule["version"] != '') {
|
|
$new_version_name = $res_rule["version"];
|
|
} else {
|
|
$new_version_name = $version["name"];
|
|
}
|
|
if (($ID != $new_software_id)
|
|
|| ($new_version_name != $old_version_name)) {
|
|
$this->moveVersions($ID, $new_software_id, $version["id"], $old_version_name,
|
|
$new_version_name, $entity);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Delete a list of softwares
|
|
*
|
|
* @param $soft_ids array containing replay software need to be put in trashbin
|
|
**/
|
|
function putOldSoftsInTrash(array $soft_ids) {
|
|
global $DB;
|
|
|
|
if (count($soft_ids) > 0) {
|
|
//Try to delete all the software that are not used anymore
|
|
// (which means that don't have version associated anymore)
|
|
$iterator = $DB->request([
|
|
'SELECT' => [
|
|
'glpi_softwares.id',
|
|
'COUNT' => 'glpi_softwareversions.softwares_id AS cpt'
|
|
],
|
|
'FROM' => 'glpi_softwares',
|
|
'LEFT JOIN' => [
|
|
'glpi_softwareversions' => [
|
|
'ON' => [
|
|
'glpi_softwareversions' => 'softwares_id',
|
|
'glpi_softwares' => 'id'
|
|
]
|
|
]
|
|
],
|
|
'WHERE' => [
|
|
'glpi_softwares.id' => $soft_ids,
|
|
'is_deleted' => 0
|
|
],
|
|
'GROUPBY' => 'glpi_softwares.id',
|
|
'HAVING' => ['cpt' => 0]
|
|
]);
|
|
|
|
$software = new Software();
|
|
while ($soft = $iterator->next()) {
|
|
$software->putInTrash($soft["id"], __('Software deleted by GLPI dictionary rules'));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Change software's name, and move versions if needed
|
|
*
|
|
* @param int $ID old software ID
|
|
* @param int $new_software_id new software ID
|
|
* @param int $version_id version ID to move
|
|
* @param string $old_version old version name
|
|
* @param string $new_version new version name
|
|
* @param int $entity entity ID
|
|
* @return void
|
|
*/
|
|
function moveVersions($ID, $new_software_id, $version_id, $old_version, $new_version, $entity) {
|
|
global $DB;
|
|
|
|
$new_versionID = $this->versionExists($new_software_id, $new_version);
|
|
|
|
// Do something if it is not the same version
|
|
if ($new_versionID != $version_id) {
|
|
//A version does not exist : update existing one
|
|
if ($new_versionID == -1) {
|
|
//Transfer versions from old software to new software for a specific version
|
|
$DB->update(
|
|
'glpi_softwareversions', [
|
|
'name' => $new_version,
|
|
'softwares_id' => $new_software_id
|
|
], [
|
|
'id' => $version_id
|
|
]
|
|
);
|
|
} else {
|
|
// Delete software can be in double after update
|
|
$item_softwareversion_table = Item_SoftwareVersion::getTable();
|
|
$iterator = $DB->request([
|
|
'SELECT' => ['gcs_2.*'],
|
|
'FROM' => $item_softwareversion_table,
|
|
'LEFT JOIN' => [
|
|
"{$item_softwareversion_table} AS gcs_2" => [
|
|
'FKEY' => [
|
|
'gcs_2' => 'items_id',
|
|
$item_softwareversion_table => 'items_id', [
|
|
'AND' => [
|
|
'gcs_2.itemtype' => $item_softwareversion_table.'.itemtype'
|
|
]
|
|
]
|
|
]
|
|
]
|
|
],
|
|
'WHERE' => [
|
|
"{$item_softwareversion_table}.softwareversions_id" => $new_versionID,
|
|
'gcs_2.softwareversions_id' => $version_id
|
|
]
|
|
]);
|
|
while ($data = $iterator->next()) {
|
|
$DB->delete(
|
|
'glpi_items_softwareversions', [
|
|
'id' => $data['id']
|
|
]
|
|
);
|
|
}
|
|
|
|
//Change ID of the version in glpi_items_softwareversions
|
|
$DB->update(
|
|
$item_softwareversion_table, [
|
|
'softwareversions_id' => $new_versionID
|
|
], [
|
|
'softwareversions_id' => $version_id
|
|
]
|
|
);
|
|
|
|
// Update licenses version link
|
|
$DB->update(
|
|
'glpi_softwarelicenses', [
|
|
'softwareversions_id_buy' => $new_versionID
|
|
], [
|
|
'softwareversions_id_buy' => $version_id
|
|
]
|
|
);
|
|
|
|
$DB->update(
|
|
'glpi_softwarelicenses', [
|
|
'softwareversions_id_use' => $new_versionID
|
|
], [
|
|
'softwareversions_id_use' => $version_id
|
|
]
|
|
);
|
|
|
|
//Delete old version
|
|
$old_version = new SoftwareVersion();
|
|
$old_version->delete(["id" => $version_id]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Move licenses from a software to another
|
|
*
|
|
* @param $old_software_id old software ID
|
|
* @param $new_software_id new software ID
|
|
* @return true if move was successful
|
|
**/
|
|
function moveLicenses($old_software_id, $new_software_id) {
|
|
global $DB;
|
|
|
|
//Return false if one of the 2 softwares doesn't exists
|
|
if (!countElementsInTable('glpi_softwares', ['id' => $old_software_id])
|
|
|| !countElementsInTable('glpi_softwares', ['id' => $new_software_id])) {
|
|
return false;
|
|
}
|
|
|
|
//Transfer licenses to new software if needed
|
|
if ($old_software_id != $new_software_id) {
|
|
$DB->update(
|
|
'glpi_softwarelicenses', [
|
|
'softwares_id' => $new_software_id
|
|
], [
|
|
'softwares_id' => $old_software_id
|
|
]
|
|
);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Check if a version exists
|
|
*
|
|
* @param $software_id software ID
|
|
* @param $version version name
|
|
**/
|
|
function versionExists($software_id, $version) {
|
|
global $DB;
|
|
|
|
//Check if the version exists
|
|
$iterator = $DB->request([
|
|
'FROM' => 'glpi_softwareversions',
|
|
'WHERE' => [
|
|
'softwares_id' => $software_id,
|
|
'name' => $version
|
|
]
|
|
]);
|
|
if (count($iterator)) {
|
|
$current = $iterator->next();
|
|
return $current['id'];
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
}
|