Files
MYSOPHAL/inc/lock.class.php
2025-08-07 13:15:31 +01:00

699 lines
25 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");
}
/**
* This class manages locks
* Lock management is available for objects and link between objects. It relies on the use of
* a is_dynamic field, to incidate if item supports lock, and is_deleted field to incidate if the
* item or link is locked
* By setting is_deleted to 0 again, the item is unlock
*
* Note : GLPI's core supports locks for objects. It's up to the external inventory tool to manage
* locks for fields
*
* @since 0.84
**/
class Lock {
static function getTypeName($nb = 0) {
return _n('Lock', 'Locks', $nb);
}
/**
* Display form to unlock fields and links
*
* @param CommonDBTM $item the source item
**/
static function showForItem(CommonDBTM $item) {
global $DB;
$ID = $item->getID();
$itemtype = $item->getType();
$header = false;
//If user doesn't have update right on the item, lock form must not be displayed
if (!$item->isDynamic() || !$item->can($item->fields['id'], UPDATE)) {
return false;
}
echo "<div width='50%'>";
echo "<form method='post' id='lock_form'
name='lock_form' action='".Toolbox::getItemTypeFormURL(__CLASS__)."'>";
echo "<input type='hidden' name='id' value='$ID'>\n";
echo "<input type='hidden' name='itemtype' value='$itemtype'>\n";
echo "<table class='tab_cadre_fixe'>";
echo "<tr><th colspan='2'>".__('Locked items')."</th></tr>";
//Use a hook to allow external inventory tools to manage per field lock
$results = Plugin::doHookFunction('display_locked_fields', ['item' => $item,
'header' => $header]);
$header |= $results['header'];
//Special locks for computers only
if ($itemtype == 'Computer') {
$computer_item = new Computer_Item();
//Locks for items recorded in glpi_computers_items table
$types = ['Monitor', 'Peripheral', 'Printer'];
foreach ($types as $type) {
$params = ['is_dynamic' => 1,
'is_deleted' => 1,
'computers_id' => $ID,
'itemtype' => $type];
$params['FIELDS'] = ['id', 'items_id'];
$first = true;
foreach ($DB->request('glpi_computers_items', $params) as $line) {
/** @var CommonDBTM $asset */
$asset = new $type();
$asset->getFromDB($line['items_id']);
if ($first) {
echo "<tr><th colspan='2'>".$type::getTypeName(Session::getPluralNumber())."</th></tr>\n";
$first = false;
}
echo "<tr class='tab_bg_1'>";
echo "<td class='center' width='10'>";
if ($computer_item->can($line['id'], UPDATE) || $computer_item->can($line['id'], PURGE)) {
$header = true;
echo "<input type='checkbox' name='Computer_Item[" . $line['id'] . "]'>";
}
echo "</td>";
echo "<td class='left' width='95%'>" . $asset->getName() . "</td>";
echo "</tr>\n";
}
}
//items disks
$item_disk = new Item_Disk();
$params = [
'is_dynamic' => 1,
'is_deleted' => 1,
'items_id' => $ID,
'itemtype' => $itemtype
];
$params['FIELDS'] = ['id', 'name'];
$first = true;
foreach ($DB->request($item_disk->getTable(), $params) as $line) {
if ($first) {
echo "<tr><th colspan='2'>".$item_disk->getTypeName(Session::getPluralNumber())."</th></tr>\n";
$first = false;
}
echo "<tr class='tab_bg_1'>";
echo "<td class='center' width='10'>";
if ($item_disk->can($line['id'], UPDATE) || $item_disk->can($line['id'], PURGE)) {
$header = true;
echo "<input type='checkbox' name='Item_Disk[" . $line['id'] . "]'>";
}
echo "</td>";
echo "<td class='left' width='95%'>" . $line['name'] . "</td>";
echo "</tr>\n";
}
$computer_vm = new ComputerVirtualMachine();
$params = ['is_dynamic' => 1,
'is_deleted' => 1,
'computers_id' => $ID];
$params['FIELDS'] = ['id', 'name'];
$first = true;
foreach ($DB->request($computer_vm->getTable(), $params) as $line) {
if ($first) {
echo "<tr><th colspan='2'>".$computer_vm->getTypeName(Session::getPluralNumber())."</th></tr>\n";
$first = false;
}
echo "<tr class='tab_bg_1'>";
echo "<td class='center' width='10'>";
if ($computer_vm->can($line['id'], UPDATE) || $computer_vm->can($line['id'], PURGE)) {
$header = true;
echo "<input type='checkbox' name='ComputerVirtualMachine[" . $line['id'] . "]'>";
}
echo "</td>";
echo "<td class='left' width='95%'>" . $line['name'] . "</td>";
echo "</tr>\n";
}
}
//Software versions
$item_sv = new Item_SoftwareVersion();
$item_sv_table = Item_SoftwareVersion::getTable();
$iterator = $DB->request([
'SELECT' => [
'isv.id AS id',
'sv.name AS version',
's.name AS software'
],
'FROM' => "{$item_sv_table} AS isv",
'LEFT JOIN' => [
'glpi_softwareversions AS sv' => [
'FKEY' => [
'isv' => 'softwareversions_id',
'sv' => 'id'
]
],
'glpi_softwares AS s' => [
'FKEY' => [
'sv' => 'softwares_id',
's' => 'id'
]
]
],
'WHERE' => [
'isv.is_deleted' => 1,
'isv.is_dynamic' => 1,
'isv.items_id' => $ID,
'isv.itemtype' => $itemtype,
]
]);
echo "<tr><th colspan='2'>".Software::getTypeName(Session::getPluralNumber())."</th></tr>\n";
while ($data = $iterator->next()) {
echo "<tr class='tab_bg_1'>";
echo "<td class='center' width='10'>";
if ($item_sv->can($data['id'], UPDATE) || $item_sv->can($data['id'], PURGE)) {
$header = true;
echo "<input type='checkbox' name='Item_SoftwareVersion[" . $data['id'] . "]'>";
}
echo "</td>";
echo "<td class='left' width='95%'>" . $data['software']." ".$data['version'] . "</td>";
echo "</tr>\n";
}
//Software licenses
$item_sl = new Item_SoftwareLicense();
$item_sl_table = Item_SoftwareLicense::getTable();
$iterator = $DB->request([
'SELECT' => [
'isl.id AS id',
'sl.name AS version',
's.name AS software'
],
'FROM' => "{$item_sl_table} AS isl",
'LEFT JOIN' => [
'glpi_softwarelicenses AS sl' => [
'FKEY' => [
'isl' => 'softwarelicenses_id',
'sl' => 'id'
]
],
'glpi_softwares AS s' => [
'FKEY' => [
'sl' => 'softwares_id',
's' => 'id'
]
]
],
'WHERE' => [
'isl.is_deleted' => 1,
'isl.is_dynamic' => 1,
'isl.items_id' => $ID,
'isl.itemtype' => $itemtype,
]
]);
echo "<tr><th colspan='2'>".SoftwareLicense::getTypeName(Session::getPluralNumber())."</th></tr>\n";
while ($data = $iterator->next()) {
echo "<tr class='tab_bg_1'>";
echo "<td class='center' width='10'>";
if ($item_sl->can($data['id'], UPDATE) || $item_sl->can($data['id'], PURGE)) {
$header = true;
echo "<input type='checkbox' name='Item_SoftwareLicense[" . $data['id'] . "]'>";
}
echo "</td>";
echo "<td class='left' width='95%'>" . $data['software']." ".$data['version'] . "</td>";
echo "</tr>\n";
}
$first = true;
$networkport = new NetworkPort();
$params = ['is_dynamic' => 1,
'is_deleted' => 1,
'items_id' => $ID,
'itemtype' => $itemtype];
$params['FIELDS'] = ['id'];
foreach ($DB->request($networkport->getTable(), $params) as $line) {
$networkport->getFromDB($line['id']);
if ($first) {
echo "<tr><th colspan='2'>".$networkport->getTypeName(Session::getPluralNumber())."</th></tr>\n";
$first = false;
}
echo "<tr class='tab_bg_1'>";
echo "<td class='center' width='10'>";
if ($networkport->can($line['id'], UPDATE) || $networkport->can($line['id'], PURGE)) {
$header = true;
echo "<input type='checkbox' name='NetworkPort[" . $line['id'] . "]'>";
}
echo "</td>";
echo "<td class='left' width='95%'>" . $networkport->getName() . "</td>";
echo "</tr>\n";
}
$first = true;
$networkname = new NetworkName();
$params = [
'glpi_networknames.is_dynamic' => 1,
'glpi_networknames.is_deleted' => 1,
'glpi_networknames.itemtype' => 'NetworkPort',
'glpi_networknames.items_id' => new QueryExpression($DB->quoteName('glpi_networkports.id')),
'glpi_networkports.items_id' => $ID,
'glpi_networkports.itemtype' => $itemtype
];
$params['FIELDS'] = ['glpi_networknames' => 'id'];
foreach ($DB->request(['glpi_networknames', 'glpi_networkports'], $params) as $line) {
$networkname->getFromDB($line['id']);
if ($first) {
echo "<tr><th colspan='2'>".NetworkName::getTypeName(Session::getPluralNumber())."</th></tr>\n";
$first = false;
}
echo "<tr class='tab_bg_1'>";
echo "<td class='center' width='10'>";
if ($networkname->can($line['id'], UPDATE) || $networkname->can($line['id'], PURGE)) {
$header = true;
echo "<input type='checkbox' name='NetworkName[" . $line['id'] . "]'>";
}
echo "</td>";
echo "<td class='left' width='95%'>" . $networkname->getName() . "</td>";
echo "</tr>\n";
}
$first = true;
$ipaddress = new IPAddress();
$params = [
'glpi_ipaddresses.is_dynamic' => 1,
'glpi_ipaddresses.is_deleted' => 1,
'glpi_ipaddresses.itemtype' => 'NetworkName',
'glpi_ipaddresses.items_id' => new QueryExpression($DB->quoteName('glpi_networknames.id')),
'glpi_networknames.itemtype' => 'NetworkPort',
'glpi_networknames.items_id' => new QueryExpression($DB->quoteName('glpi_networkports.id')),
'glpi_networkports.items_id' => $ID,
'glpi_networkports.itemtype' => $itemtype
];
$params['FIELDS'] = ['glpi_ipaddresses' => 'id'];
foreach ($DB->request(['glpi_ipaddresses',
'glpi_networknames',
'glpi_networkports'], $params) as $line) {
$ipaddress->getFromDB($line['id']);
if ($first) {
echo "<tr><th colspan='2'>".IPAddress::getTypeName(Session::getPluralNumber())."</th></tr>\n";
$first = false;
}
echo "<tr class='tab_bg_1'>";
echo "<td class='center' width='10'>";
if ($ipaddress->can($line['id'], UPDATE) || $ipaddress->can($line['id'], PURGE)) {
$header = true;
echo "<input type='checkbox' name='IPAddress[" . $line['id'] . "]'>";
}
echo "</td>";
echo "<td class='left' width='95%'>" . $ipaddress->getName() . "</td>";
echo "</tr>\n";
}
$types = Item_Devices::getDeviceTypes();
$nb = 0;
foreach ($types as $type) {
$nb += countElementsInTable(getTableForItemType($type),
['items_id' => $ID,
'itemtype' => $itemtype,
'is_dynamic' => 1,
'is_deleted' => 1 ]);
}
if ($nb) {
echo "<tr><th colspan='2'>"._n('Component', 'Components', Session::getPluralNumber())."</th></tr>\n";
foreach ($types as $type) {
$type_item = new $type();
$associated_type = str_replace('Item_', '', $type);
$associated_table = getTableForItemType($associated_type);
$fk = getForeignKeyFieldForTable($associated_table);
$iterator = $DB->request([
'SELECT' => [
'i.id',
't.designation AS name'
],
'FROM' => getTableForItemType($type) . ' AS i',
'LEFT JOIN' => [
"$associated_table AS t" => [
'ON' => [
't' => 'id',
'i' => $fk
]
]
],
'WHERE' => [
'itemtype' => $itemtype,
'items_id' => $ID,
'is_dynamic' => 1,
'is_deleted' => 1
]
]);
while ($data = $iterator->next()) {
echo "<tr class='tab_bg_1'>";
echo "<td class='center' width='10'>";
if ($type_item->can($data['id'], UPDATE) || $type_item->can($data['id'], PURGE)) {
$header = true;
echo "<input type='checkbox' name='".$type."[" . $data['id'] . "]'>";
}
echo "</td>";
echo "<td class='left' width='95%'>";
printf(__('%1$s: %2$s'), $associated_type::getTypeName(), $data['name']);
echo "</td></tr>\n";
}
}
}
if ($header) {
echo "<tr><th>";
echo Html::getCheckAllAsCheckbox('lock_form');
echo "</th><th>&nbsp</th></tr>\n";
echo "</table>";
Html::openArrowMassives('lock_form', true);
Html::closeArrowMassives(['unlock' => _sx('button', 'Unlock'),
'purge' => _sx('button', 'Delete permanently')]);
} else {
echo "<tr class='tab_bg_2'>";
echo "<td class='center' colspan='2'>". __('No locked item')."</td></tr>";
echo "</table>";
}
Html::closeForm();
echo "</div>\n";
}
/**
* @see CommonGLPI::getTabNameForItem()
*
* @param $item CommonGLPI object
* @param $withtemplate (default 0)
**/
function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) {
if ($item->isDynamic() && $item->can($item->fields['id'], UPDATE)) {
return Lock::getTypeName(Session::getPluralNumber());
}
return '';
}
/**
* @param $item CommonGLPI object
* @param $tabnum (default 1)
* @param $withtemplate (default 0)
**/
static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) {
if ($item->isDynamic() && $item->can($item->fields['id'], UPDATE)) {
self::showForItem($item);
}
return true;
}
/**
* Get infos to build an SQL query to get locks fields in a table
*
* @param string $itemtype itemtype of the item to look for locked fields
* @param string $baseitemtype itemtype of the based item
*
* @return array which contains necessary informations to build the SQL query
**/
static function getLocksQueryInfosByItemType($itemtype, $baseitemtype) {
global $DB;
$condition = [];
$table = false;
$field = '';
$type = $itemtype;
switch ($itemtype) {
case 'Peripheral' :
case 'Monitor' :
case 'Printer' :
case 'Phone' :
$condition = ['itemtype' => $itemtype,
'is_dynamic' => 1,
'is_deleted' => 1];
$table = 'glpi_computers_items';
$field = 'computers_id';
$type = 'Computer_Item';
break;
case 'NetworkPort' :
$condition = ['itemtype' => $baseitemtype,
'is_dynamic' => 1,
'is_deleted' => 1];
$table = 'glpi_networkports';
$field = 'items_id';
break;
case 'NetworkName' :
$condition = [
'glpi_networknames.is_dynamic' => 1,
'glpi_networknames.is_deleted' => 1,
'glpi_networknames.itemtype' => 'NetworkPort',
'glpi_networknames.items_id' => new QueryExpression($DB->quoteName('glpi_networkports.id')),
'glpi_networkports.itemtype' => $baseitemtype
];
$condition['FIELDS']
= ['glpi_networknames' => 'id'];
$table = ['glpi_networknames', 'glpi_networkports'];
$field = 'glpi_networkports.items_id';
break;
case 'IPAddress' :
$condition = [
'glpi_ipaddresses.is_dynamic' => 1,
'glpi_ipaddresses.is_deleted' => 1,
'glpi_ipaddresses.itemtype' => 'NetworkName',
'glpi_ipaddresses.items_id' => 'glpi_networknames.id',
'glpi_networknames.itemtype' => 'NetworkPort',
'glpi_networknames.items_id' => 'glpi_networkports.id',
'glpi_networkports.itemtype' => $baseitemtype];
$condition['FIELDS']
= ['glpi_ipaddresses' => 'id'];
$table = ['glpi_ipaddresses', 'glpi_networknames', 'glpi_networkports'];
$field = 'glpi_networkports.items_id';
break;
case 'Item_Disk' :
$condition = [
'is_dynamic' => 1,
'is_deleted' => 1,
'itemtype' => $itemtype
];
$table = Item_Disk::getTable();
$field = 'items_id';
break;
case 'ComputerVirtualMachine' :
$condition = [
'is_dynamic' => 1,
'is_deleted' => 1,
'itemtype' => $itemtype];
$table = 'glpi_computervirtualmachines';
$field = 'computers_id';
break;
case 'SoftwareVersion' :
$condition = [
'is_dynamic' => 1,
'is_deleted' => 1,
'itemtype' => $itemtype];
$table = 'glpi_items_softwareversions';
$field = 'items_id';
$type = 'Item_SoftwareVersion';
break;
default :
// Devices
if (preg_match('/^Item\_Device/', $itemtype)) {
$condition = ['itemtype' => $baseitemtype,
'is_dynamic' => 1,
'is_deleted' => 1];
$table = getTableForItemType($itemtype);
$field = 'items_id';
}
}
return ['condition' => $condition,
'table' => $table,
'field' => $field,
'type' => $type];
}
/**
* @since 0.85
*
* @see CommonDBTM::getMassiveActionsForItemtype()
**/
static function getMassiveActionsForItemtype(array &$actions, $itemtype, $is_deleted = 0,
CommonDBTM $checkitem = null) {
$action_name = __CLASS__.MassiveAction::CLASS_ACTION_SEPARATOR.'unlock';
if (Session::haveRight('computer', UPDATE)
&& ($itemtype == 'Computer')) {
$actions[$action_name] = __('Unlock components');
}
}
/**
* @since 0.85
*
* @see CommonDBTM::showMassiveActionsSubForm()
**/
static function showMassiveActionsSubForm(MassiveAction $ma) {
switch ($ma->getAction()) {
case 'unlock' :
$types = ['Monitor' => _n('Monitor', 'Monitors', Session::getPluralNumber()),
'Peripheral' => Peripheral::getTypeName(Session::getPluralNumber()),
'Printer' => Printer::getTypeName(Session::getPluralNumber()),
'SoftwareVersion' => SoftwareVersion::getTypeName(Session::getPluralNumber()),
'NetworkPort' => NetworkPort::getTypeName(Session::getPluralNumber()),
'NetworkName' => NetworkName::getTypeName(Session::getPluralNumber()),
'IPAddress' => IPAddress::getTypeName(Session::getPluralNumber()),
'Item_Disk' => Item_Disk::getTypeName(Session::getPluralNumber()),
'Device' => _n('Component', 'Components', Session::getPluralNumber()),
'ComputerVirtualMachine' => ComputerVirtualMachine::getTypeName(Session::getPluralNumber())];
echo __('Select the type of the item that must be unlock');
echo "<br><br>\n";
Dropdown::showFromArray('attached_item', $types,
['multiple' => true,
'size' => 5,
'values' => array_keys($types)]);
echo "<br><br>".Html::submit(_x('button', 'Post'), ['name' => 'massiveaction']);
return true;
}
return false;
}
/**
* @since 0.85
*
* @see CommonDBTM::processMassiveActionsForOneItemtype()
**/
static function processMassiveActionsForOneItemtype(MassiveAction $ma, CommonDBTM $baseitem,
array $ids) {
global $DB;
switch ($ma->getAction()) {
case 'unlock' :
$input = $ma->getInput();
if (isset($input['attached_item'])) {
$attached_items = $input['attached_item'];
if (($device_key = array_search('Device', $attached_items)) !== false) {
unset($attached_items[$device_key]);
$attached_items = array_merge($attached_items, Item_Devices::getDeviceTypes());
}
$links = [];
foreach ($attached_items as $attached_item) {
$infos = self::getLocksQueryInfosByItemType($attached_item, $baseitem->getType());
if ($item = getItemForItemtype($infos['type'])) {
$infos['item'] = $item;
$links[$attached_item] = $infos;
}
}
foreach ($ids as $id) {
$action_valid = false;
foreach ($links as $infos) {
$infos['condition'][$infos['field']] = $id;
$locked_items = $DB->request($infos['table'], $infos['condition']);
if ($locked_items->count() === 0) {
$action_valid = true;
continue;
}
foreach ($locked_items as $data) {
// Restore without history
$action_valid = $infos['item']->restore(['id' => $data['id']]);
}
}
$baseItemType = $baseitem->getType();
if ($action_valid) {
$ma->itemDone($baseItemType, $id, MassiveAction::ACTION_OK);
} else {
$ma->itemDone($baseItemType, $id, MassiveAction::ACTION_KO);
$erroredItem = new $baseItemType();
$erroredItem->getFromDB($id);
$ma->addMessage($erroredItem->getErrorMessage(ERROR_ON_ACTION));
}
}
}
return;
}
}
}