Projet/Mission4/roles/glpi/files/fusioninventory/inc/deploypackage.class.php
2022-02-11 15:48:06 +01:00

2116 lines
72 KiB
PHP

<?php
/**
* FusionInventory
*
* Copyright (C) 2010-2016 by the FusionInventory Development Team.
*
* http://www.fusioninventory.org/
* https://github.com/fusioninventory/fusioninventory-for-glpi
* http://forge.fusioninventory.org/
*
* ------------------------------------------------------------------------
*
* LICENSE
*
* This file is part of FusionInventory project.
*
* FusionInventory is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FusionInventory 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with FusionInventory. If not, see <http://www.gnu.org/licenses/>.
*
* ------------------------------------------------------------------------
*
* This file is used to manage the deploy packages.
*
* ------------------------------------------------------------------------
*
* @package FusionInventory
* @author David Durieux
* @author Alexandre Delaunay
* @copyright Copyright (c) 2010-2016 FusionInventory team
* @license AGPL License 3.0 or (at your option) any later version
* http://www.gnu.org/licenses/agpl-3.0-standalone.html
* @link http://www.fusioninventory.org/
* @link https://github.com/fusioninventory/fusioninventory-for-glpi
*
*/
if (!defined('GLPI_ROOT')) {
die("Sorry. You can't access directly to this file");
}
/**
* Manage the deploy packages.
*/
class PluginFusioninventoryDeployPackage extends CommonDBTM {
/**
* Initialize the tasks running with this package (updated with overrided getFromDB method)
*
* @var array
*/
public $running_tasks = [];
/**
* The right name for this class
*
* @var string
*/
static $rightname = 'plugin_fusioninventory_package';
/**
* Initialize the users visibility of package for self-service deploy
*
* @var array
*/
protected $users = [];
/**
* Initialize the groups visibility of package for self-service deploy
*
* @var array
*/
protected $groups = [];
/**
* Initialize the profiles visibility of package for self-service deploy
*
* @var array
*/
protected $profiles = [];
/**
* Initialize the entities visibility of package for self-service deploy
*
* @var array
*/
protected $entities = [];
/**
* Get name of this type by language of the user connected
*
* @param integer $nb number of elements
* @return string name of this type
*/
static function getTypeName($nb = 0) {
return __('Package', 'fusioninventory');
}
function getFromDB($ID) {
$found = parent::getFromDB($ID);
if ($found) {
// Get all tasks runnning
$this->running_tasks =
PluginFusioninventoryTask::getItemsFromDB(
[
'is_active' => true,
'is_running' => true,
'targets' => [__CLASS__ => $this->fields['id']],
'by_entities' => false,
]
);
}
return $found;
}
/**
* Have I the right to "update" the object content (package actions)
*
* Also call canUpdateItem()
*
* @return booleen
**/
function canUpdateContent() {
// check if a task is currenlty runnning with this package
if (count($this->running_tasks)) {
return false;
}
return parent::canUpdateItem();
}
/**
* Get the massive actions for this object
*
* @param object|null $checkitem
* @return array list of actions
*/
function getSpecificMassiveActions($checkitem = null) {
$actions = [];
if (strstr($_SERVER["HTTP_REFERER"], 'deploypackage.import.php')) {
$actions[__CLASS__.MassiveAction::CLASS_ACTION_SEPARATOR.'import'] = __('Import', 'fusioninventory');
} else {
$actions[__CLASS__.MassiveAction::CLASS_ACTION_SEPARATOR.'transfert'] = __('Transfer');
$actions[__CLASS__.MassiveAction::CLASS_ACTION_SEPARATOR.'export'] = __('Export', 'fusioninventory');
$actions[__CLASS__.MassiveAction::CLASS_ACTION_SEPARATOR.'duplicate'] = _sx('button', 'Duplicate');
}
return $actions;
}
/**
* Define standard massiveaction actions to deny
*
* @return array list of actions to deny
*/
function getForbiddenStandardMassiveAction() {
$forbidden = parent::getForbiddenStandardMassiveAction();
if (strstr($_SERVER["HTTP_REFERER"], 'deploypackage.import.php')) {
$forbidden[] = 'update';
$forbidden[] = 'add';
$forbidden[] = 'delete';
$forbidden[] = 'purge';
}
return $forbidden;
}
/**
* Display form related to the massive action selected
*
* @param object $ma MassiveAction instance
* @return boolean
*/
static function showMassiveActionsSubForm(MassiveAction $ma) {
switch ($ma->getAction()) {
case 'transfert':
Dropdown::show('Entity');
echo "<br><br>".Html::submit(__('Post'),
['name' => 'massiveaction']);
return true;
case 'duplicate':
echo Html::submit(_x('button', 'Post'), ['name' => 'massiveaction']);
return true;
}
return parent::showMassiveActionsSubForm($ma);
}
/**
* Execution code for massive action
*
* @param object $ma MassiveAction instance
* @param object $item item on which execute the code
* @param array $ids list of ID on which execute the code
*/
static function processMassiveActionsForOneItemtype(MassiveAction $ma, CommonDBTM $item, array $ids) {
switch ($ma->getAction()) {
case 'export' :
foreach ($ids as $key) {
if ($item->can($key, UPDATE)) {
$item->exportPackage($key);
$ma->itemDone($item->getType(), $key, MassiveAction::ACTION_OK);
}
}
break;
case 'transfert' :
$pfDeployPackage = new PluginFusioninventoryDeployPackage();
foreach ($ids as $key) {
if ($pfDeployPackage->getFromDB($key)) {
$input = [];
$input['id'] = $key;
$input['entities_id'] = $ma->POST['entities_id'];
$pfDeployPackage->update($input);
}
}
break;
case 'import' :
foreach ($ids as $key) {
$item->importPackage($key);
$ma->itemDone($item->getType(), $key, MassiveAction::ACTION_OK);
}
break;
case 'duplicate':
$pfPackage = new self();
foreach ($ids as $key) {
if ($pfPackage->getFromDB($key)) {
if ($pfPackage->duplicate($pfPackage->getID())) {
//set action massive ok for this item
$ma->itemDone($item->getType(), $key, MassiveAction::ACTION_OK);
} else {
// KO
$ma->itemDone($item->getType(), $key, MassiveAction::ACTION_KO);
}
}
}
break;
}
}
/**
* Define error message if package used in task. This will prevent edit the
* package
*
* @return string
*/
function getEditErrorMessage() {
$error_message = "";
if (count($this->running_tasks) > 0) {
// Display error message
$error_message .= "<div class='warning'>";
$error_message .= "<i class='fa fa-exclamation-triangle fa-3x'></i>";
$error_message .= "<h3>".__("Modification Denied", 'fusioninventory')."</h3>\n";
$error_message .= "<h4>".
_n(
"The following task is running with this package",
"The following tasks are running with this package",
count($this->running_tasks), 'fusioninventory'
).
"</h4>\n";
foreach ($this->running_tasks as $task) {
$taskurl =
PluginFusioninventoryTask::getFormURLWithID($task['task']['id'], true);
$error_message .= "<a href='$taskurl'>".$task['task']['name']."</a>, ";
}
$error_message .= "</div>";
}
return $error_message;
}
/**
* Prepare data before add to database
*
* @param array $input
* @return array
*/
function prepareInputForAdd($input) {
if (!isset($input['json'])) {
$input['json'] = json_encode([
'jobs' => [
'checks' => [],
'associatedFiles' => [],
'actions' => [],
'userinteractions' => []
],
'associatedFiles' => []]);
}
return parent::prepareInputForAdd($input);
}
/**
* Get search function for the class
*
* @return array
*/
function rawSearchOptions() {
$tab = [];
$tab[] = [
'id' => 'common',
'name' => __('Characteristics')
];
$tab[] = [
'id' => '1',
'table' => $this->getTable(),
'field' => 'name',
'name' => __('Name'),
'datatype' => 'itemlink',
'itemlink_link' => $this->getType(),
'autocomplete' => true,
];
$tab[] = [
'id' => '2',
'table' => $this->getTable(),
'field' => 'id',
'name' => __('ID'),
];
$tab[] = [
'id' => '16',
'table' => $this->getTable(),
'field' => 'comment',
'name' => __('Comments'),
'datatype' => 'text',
];
$tab[] = [
'id' => '19',
'table' => $this->getTable(),
'field' => 'date_mod',
'name' => __('Last update'),
'datatype' => 'datetime',
];
$tab[] = [
'id' => '80',
'table' => 'glpi_entities',
'field' => 'completename',
'name' => Entity::getTypeName(1),
'datatype' => 'dropdown',
];
$tab[] = [
'id' => '86',
'table' => $this->getTable(),
'field' => 'is_recursive',
'name' => __('Child entities'),
'datatype' => 'bool',
];
$tab[] = [
'id' => '20',
'table' => 'glpi_plugin_fusioninventory_deploygroups',
'field' => 'name',
'name' => __('Enable deploy on demand for the following group', 'fusioninventory'),
'datatype' => 'dropdown',
];
return $tab;
}
/**
* Get all packages in json format
*
* @return json
*/
function getAllDatas() {
global $DB;
$sql = " SELECT id, name
FROM `".$this->getTable()."`
ORDER BY name";
$res = $DB->query($sql);
$nb = $DB->numrows($res);
$json = [];
$i = 0;
while ($row = $DB->fetchAssoc($res)) {
$json['packages'][$i]['package_id'] = $row['id'];
$json['packages'][$i]['package_name'] = $row['name'];
$i++;
}
$json['results'] = $nb;
return json_encode($json);
}
/**
* Clean orders after delete the package
*
*/
function post_deleteFromDB() {
$pfDeployFile = new PluginFusioninventoryDeployFile();
// remove file in repo
$json = json_decode($this->fields['json'], true);
if (is_null($json)) {
return;
}
foreach ($json['associatedFiles'] as $sha512 => $file) {
$pfDeployFile->removeFileInRepo($sha512);
}
}
/**
* Display the menu / list of packages
*
* @param array $options
*/
function showMenu($options = []) {
$this->displaylist = false;
$this->fields['id'] = -1;
$this->showList();
}
/**
* Display list of packages
*/
function showList() {
Search::show('PluginFusioninventoryDeployPackage');
}
/**
* Define tabs to display on form page
*
* @param array $options
* @return array containing the tabs name
*/
function defineTabs($options = []) {
$ong = [];
$this->addDefaultFormTab($ong);
$this->addStandardTab(__CLASS__, $ong, $options);
$ong['no_all_tab'] = true;
return $ong;
}
/**
* Display form
*
* @param integer $ID
* @param array $options
* @return true
*/
function showForm($ID, $options = []) {
$this->initForm($ID, $options);
$this->showFormHeader($options);
//Add redips_clone element before displaying tabs
//If we don't do this, dragged element won't be visible on the other tab not displayed at
//first (for reminder, GLPI tabs are displayed dynamically on-demand)
echo "<div id='redips_clone'></div>";
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Name')."&nbsp;:</td>";
echo "<td>";
Html::autocompletionTextField($this, 'name', ['size' => 40]);
echo "</td>";
echo "<td>".__('Comments')."&nbsp;:</td>";
echo "<td>";
echo "<textarea cols='40' rows='2' name='comment' >".$this->fields["comment"]."</textarea>";
echo "</td>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<td>".__('Enable deploy on demand for the following group', 'fusioninventory')."&nbsp;:</td>";
echo "<td>";
PluginFusioninventoryDeployGroup::dropdown(['value' => $this->fields["plugin_fusioninventory_deploygroups_id"]]);
echo "</td>";
echo "<td colspan='2'></td>";
echo "</tr>";
$this->showFormButtons($options);
return true;
}
/**
* Display order type form
*
* @global array $CFG_GLPI
*/
function displayOrderTypeForm() {
global $CFG_GLPI;
$subtypes = [
'check' => __("Audits", 'fusioninventory'),
'file' => __("Files", 'fusioninventory'),
'action' => __("Actions", 'fusioninventory'),
'userinteraction' => __("User interactions", 'fusioninventory')
];
$json_subtypes = [
'check' => 'checks',
'file' => 'associatedFiles',
'action' => 'actions',
'userinteraction' => 'userinteractions'
];
$rand = mt_rand();
$datas = json_decode($this->fields['json'], true);
echo "<table class='tab_cadre_fixe' id='package_order_".$this->getID()."'>";
// Display an error if the package modification is not possible
$canedit = $this->canUpdateContent();
$error_msg = $this->getEditErrorMessage();
if (!empty($error_msg)) {
echo "<tr><td>$error_msg</td></tr>";
}
// Display the lists of each subtypes of a package
foreach ($subtypes as $subtype => $label) {
echo "<tr>";
echo "<th id='th_title_{$subtype}_$rand'>";
echo "<img src='".Plugin::getWebDir('fusioninventory')."/pics/$subtype.png' />";
echo "&nbsp;".__($label, 'fusioninventory');
if ($canedit) {
$this->plusButtonSubtype($this->getID(), $subtype, $rand);
}
echo "</th>";
echo "</tr>";
/**
* File's form must be encoded as multipart/form-data
**/
$multipart = "";
if ($subtype == "file") {
$multipart = "enctype='multipart/form-data'";
}
echo "<tr>";
echo "<td style='vertical-align:top'>";
/**
* Display subtype form
**/
echo "<form name='addition$subtype' method='post' ".$multipart.
" action='deploypackage.form.php'>";
echo "<input type='hidden' name='id' value='".$this->getID()."' />";
echo "<input type='hidden' name='itemtype' value='PluginFusioninventoryDeploy".
ucfirst($subtype)."' />";
$classname = "PluginFusioninventoryDeploy".ucfirst($subtype);
$class = new $classname();
$class->displayForm($this, $datas, $rand, "init");
Html::closeForm();
$json_subtype = $json_subtypes[$subtype];
/**
* Display stored actions datas
**/
if (isset($datas['jobs'][$json_subtype])
&& !empty($datas['jobs'][$json_subtype])) {
echo "<div id='drag_deploypackage_". $subtype . "s'>";
echo "<form name='remove" . $subtype. "s' ".
"method='post' action='deploypackage.form.php' ".
"id='" . $subtype . "sList" . $rand . "'>";
echo Html::hidden('remove_item');
echo Html::hidden('itemtype', ['value' => $classname]);
echo Html::hidden('packages_id', ['value' => $this->getID()]);
$class->displayList($this, $datas, $rand);
Html::closeForm();
echo "</div>";
}
/**
* Initialize drag and drop on subtype lists
**/
echo "<script type='text/javascript'>";
echo "redipsInit('deploypackage', '$subtype', '".$this->getID()."');";
echo "</script>";
echo "</td>";
echo "</tr>";
}
echo "</table>";
}
/**
* Manage + button (audits, files, actions)
*
* @global array $CFG_GLPI
* @param integer $id id of the package
* @param string $subtype name of subtype (audits, files, actions)
* @param string $rand random string for js to prevent collisions
*/
function plusButtonSubtype($id, $subtype, $rand) {
global $CFG_GLPI;
if ($this->can($id, UPDATE)) {
echo "&nbsp;";
echo "<img id='plus_{$subtype}s_block{$rand}'";
echo " onclick=\"new_subtype('{$subtype}', {$id}, {$rand})\" ";
echo " title='".__('Add')."' alt='".__('Add')."' ";
echo " class='pointer' src='".
$CFG_GLPI["root_doc"].
"/pics/add_dropdown.png' /> ";
}
}
/**
* Plus button used to add an element
*
* @global array $CFG_GLPI
* @param string $dom_id
* @param boolean $clone
*/
static function plusButton($dom_id, $clone = false) {
global $CFG_GLPI;
echo "&nbsp;";
echo "<img id='plus_$dom_id' ";
if ($clone !== false) {
echo " onClick=\"plusbutton('$dom_id', '$clone')\" ";
} else {
echo " onClick=\"plusbutton('$dom_id')\" ";
}
echo " title='".__('Add')."' alt='".__('Add')."' ";
echo " class='pointer' src='".$CFG_GLPI["root_doc"].
"/pics/add_dropdown.png'> ";
}
/**
* When user is in DEBUG mode, we display the json
*
* @global array $CFG_GLPI
*/
function showDebug() {
global $CFG_GLPI;
echo "<table class='tab_cadre_fixe'>";
echo "<tr><th>".__('JSON package representation', 'fusioninventory')."</th></tr>";
echo "<tr><td>";
echo "<textarea cols='132' rows='50' style='border:1' name='json'>";
echo PluginFusioninventoryToolbox::formatJson($this->fields['json']);
echo "</textarea></td></tr>";
echo "</table>";
}
/**
* Update the json structure
*
* @param string $action_type type of action
* @param array $params data used to update the json
*/
static function alterJSON($action_type, $params) {
//route to sub class
$item_type = $params['itemtype'];
if (in_array($item_type, [
'PluginFusioninventoryDeployCheck',
'PluginFusioninventoryDeployFile',
'PluginFusioninventoryDeployAction',
'PluginFusioninventoryDeployUserinteraction'
])) {
$class = new $item_type();
switch ($action_type) {
case "add_item" :
return $class->add_item($params);
break;
case "save_item" :
return $class->save_item($params);
break;
case "remove_item" :
return $class->remove_item($params);
break;
case "move_item" :
return $class->move_item($params);
break;
}
} else {
Toolbox::logDebug("package subtype not found : " . $params['itemtype']);
Html::displayErrorAndDie ("package subtype not found");
}
}
/**
* Export the package (information, actions, files...)
*
* @param integer $packages_id id of the package to export
*/
function exportPackage($packages_id) {
$this->getFromDB($packages_id);
if (empty($this->fields['uuid'])) {
$input = [
'id' => $this->fields['id'],
'uuid' => Rule::getUuid()
];
$this->update($input);
}
$pfDeployFile = new PluginFusioninventoryDeployFile();
// Generate JSON
$input = $this->fields;
unset($input['id']);
$a_xml = [
'package' => $input,
'files' => [],
'manifests' => [],
'repository' => [],
'orders' => [['json' => $this->fields['json']]],
];
$json = json_decode($this->fields['json'], true);
$a_files = $json['associatedFiles'];
// Add files
foreach ($a_files as $files_id=>$data) {
$a_pkgfiles = current($pfDeployFile->find(['sha512' => $files_id], [], 1));
if (count($a_pkgfiles) > 0) {
unset($a_pkgfiles['id']);
$a_xml['files'][] = $a_pkgfiles;
}
}
// Create zip with JSON and files
$name = preg_replace("/[^a-zA-Z0-9]/", '', $this->fields['name']);
$filename = GLPI_PLUGIN_DOC_DIR."/fusioninventory/files/export/".$this->fields['uuid'].".".$name.".zip";
if (file_exists($filename)) {
unlink($filename);
}
$zip = new ZipArchive();
if ($zip->open($filename) == true) {
if ($zip->open($filename, ZipArchive::CREATE) == true) {
$zip->addEmptyDir('files');
$zip->addEmptyDir('files/manifests');
$zip->addEmptyDir('files/repository');
$pfDeployFile = new PluginFusioninventoryDeployFile();
foreach ($a_files as $hash=>$data) {
$sha512 = trim(file_get_contents(PLUGIN_FUSIONINVENTORY_MANIFESTS_DIR.$hash));
$zip->addFile(PLUGIN_FUSIONINVENTORY_MANIFESTS_DIR.$hash, "files/manifests/".$hash);
$a_xml['manifests'][] = $hash;
$file = $pfDeployFile->getDirBySha512($sha512).
"/".$sha512;
$zip->addFile(GLPI_PLUGIN_DOC_DIR."/fusioninventory/files/repository/".$file, "files/repository/".$file);
$a_xml['repository'][] = $file;
}
$json_string = json_encode($a_xml);
$zip->addFromString('information.json', $json_string);
}
$zip->close();
Session::addMessageAfterRedirect(__("Package exported in", "fusioninventory")." ".GLPI_PLUGIN_DOC_DIR."/fusioninventory/files/export/".$this->fields['uuid'].".".$name.".zip");
}
}
/**
* Import the package
*
* @param string $zipfile the zip file with all data inside
*/
function importPackage($zipfile) {
$zip = new ZipArchive();
$pfDeployFile = new PluginFusioninventoryDeployFile();
$filename = GLPI_PLUGIN_DOC_DIR."/fusioninventory/files/import/".$zipfile;
$extract_folder = GLPI_PLUGIN_DOC_DIR."/fusioninventory/files/import/".$zipfile.".extract";
if ($zip->open($filename, ZipArchive::CREATE) == true) {
$zip->extractTo($extract_folder);
$zip->close();
}
$json_string = file_get_contents($extract_folder."/information.json");
$a_info = json_decode($json_string, true);
// Find package with this uuid
$a_packages = $this->find(['uuid' => $a_info['package']['uuid']]);
if (count($a_packages) == 0) {
// Create it
$_SESSION['tmp_clone_package'] = true;
$this->add($a_info['package']);
foreach ($a_info['files'] as $input) {
$pfDeployFile->add($input);
}
}
// Copy files
foreach ($a_info['manifests'] as $manifest) {
rename($extract_folder."/files/manifests/".$manifest, PLUGIN_FUSIONINVENTORY_MANIFESTS_DIR.$manifest);
}
foreach ($a_info['repository'] as $repository) {
$split = explode('/', $repository);
array_pop($split);
$folder = '';
foreach ($split as $dir) {
$folder .= '/'.$dir;
if (!file_exists(GLPI_PLUGIN_DOC_DIR."/fusioninventory/files/repository".$folder)) {
mkdir(GLPI_PLUGIN_DOC_DIR."/fusioninventory/files/repository".$folder);
}
}
rename($extract_folder."/files/repository/".$repository, GLPI_PLUGIN_DOC_DIR."/fusioninventory/files/repository/".$repository);
}
}
/**
* Display list of packages to import
*/
function listPackagesToImport() {
$rand = mt_rand();
echo "<div class='spaced'>";
Html::openMassiveActionsForm('mass'.__CLASS__.$rand);
$massiveactionparams = ['container' => 'mass'.__CLASS__.$rand];
Html::showMassiveActions($massiveactionparams);
echo "<table class='tab_cadre_fixe'>";
echo "<tr class='tab_bg_1'>";
echo "<th colspan='5'>";
echo __('Packages to import', 'fusioninventory');
echo "</th>";
echo "</tr>";
echo "<tr class='tab_bg_1'>";
echo "<th width='10'>".Html::getCheckAllAsCheckbox('mass'.__CLASS__.$rand)."</th>";
echo "<th>";
echo __('Name');
echo "</th>";
echo "<th>";
echo __('uuid');
echo "</th>";
echo "<th>";
echo __('Package to update');
echo "</th>";
echo "</tr>";
foreach (glob(GLPI_PLUGIN_DOC_DIR."/fusioninventory/files/import/*.zip") as $file) {
echo "<tr class='tab_bg_1'>";
$file = str_replace(GLPI_PLUGIN_DOC_DIR."/fusioninventory/files/import/", "", $file);
$split = explode('.', $file);
echo "<td>";
Html::showMassiveActionCheckBox(__CLASS__, $file);
echo "</td>";
echo "<td>";
echo $split[2];
echo "</td>";
echo "<td>";
echo $split[0].".".$split[1];
echo "</td>";
echo "<td>";
$a_packages = current($this->find(['uuid' => $split[0].".".$split[1]], [], 1));
if (count($a_packages) > 1) {
$this->getFromDB($a_packages['id']);
echo $this->getLink();
}
echo "</td>";
echo "</tr>";
}
echo "</table>";
$massiveactionparams['ontop'] =false;
Html::showMassiveActions($massiveactionparams);
echo "</div>";
}
/**
* Get a sub element at index
*
* @param string $subtype
* @param integer $index
* @return string
*/
function getSubElement($subtype, $index) {
$data_o = json_decode($this->fields['json'], true);
return $data_o['jobs'][$subtype][$index];
}
/**
* Get Order's associated file by hash
*
* @param string $hash
* @return null|string
*/
function getAssociatedFile($hash) {
$data_o = json_decode($this->fields['json'], true);
if (array_key_exists( $hash, $data_o['associatedFiles'])) {
return $data_o['associatedFiles'][$hash];
}
return null;
}
/**
* Get the json
*
* @param integer $packages_id id of the order
* @return boolean|string the string is in json format
*/
static function getJson($packages_id) {
$pfDeployPackage = new self;
$pfDeployPackage->getFromDB($packages_id);
if (!empty($pfDeployPackage->fields['json'])) {
return $pfDeployPackage->fields['json'];
} else {
return false;
}
}
/**
* Update the order json
*
* @param integer $packages_id
* @param array $datas
* @return integer error number
*/
static function updateOrderJson($packages_id, $datas) {
$pfDeployPackage = new self;
$options = JSON_UNESCAPED_SLASHES;
$json = json_encode($datas, $options);
$json_error_consts = [
JSON_ERROR_NONE => "JSON_ERROR_NONE",
JSON_ERROR_DEPTH => "JSON_ERROR_DEPTH",
JSON_ERROR_STATE_MISMATCH => "JSON_ERROR_STATE_MISMATCH",
JSON_ERROR_CTRL_CHAR => "JSON_ERROR_CTRL_CHAR",
JSON_ERROR_SYNTAX => "JSON_ERROR_SYNTAX",
JSON_ERROR_UTF8 => "JSON_ERROR_UTF8"
];
$error_json = json_last_error();
if (version_compare(PHP_VERSION, '5.5.0', "ge")) {
$error_json_message = json_last_error_msg();
} else {
$error_json_message = "";
}
$error = 0;
if ($error_json != JSON_ERROR_NONE) {
$error_msg = $json_error_consts[$error_json];
Session::addMessageAfterRedirect(
__("The modified JSON contained a syntax error :", "fusioninventory") . "<br/>" .
$error_msg . "<br/>". $error_json_message, false, ERROR, false
);
$error = 1;
} else {
$error = $pfDeployPackage->update(
[
'id' => $packages_id,
'json' => Toolbox::addslashes_deep($json)
]
);
}
return $error;
}
/**
* Get the tab name used for item
*
* @param object $item the item object
* @param integer $withtemplate 1 if is a template form
* @return string name of the tab
*/
function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) {
if (!$withtemplate) {
switch ($item->getType()) {
case __CLASS__ :
if ($item->canUpdateItem()) {
$tabs = [];
if ($item->fields['id'] > 0) {
$tabs[1] = __('Package actions', 'fusioninventory');
}
if ($item->fields['plugin_fusioninventory_deploygroups_id'] > 0) {
if ($_SESSION['glpishow_count_on_tabs']) {
$nb = $item->countVisibilities();
$tabs[2] = self::createTabEntry(_n('Target for deploy on demand',
'Targets for deploy on demand',
$nb, 'fusioninventory'),
$nb);
} else {
$tabs[2] = _n('Target for deploy on demand',
'Targets for deploy on demand', 2,
'fusioninventory');
}
}
return $tabs;
}
case 'Computer':
if (Session::haveRight("plugin_fusioninventory_selfpackage", READ)
&& PluginFusioninventoryToolbox::isAFusionInventoryDevice($item)
&& self::isDeployEnabled($item->fields['id'])) {
return __('Package deploy', 'fusioninventory');
}
}
}
return '';
}
/**
* Display the content of the tab
*
* @param object $item
* @param integer $tabnum number of the tab to display
* @param integer $withtemplate 1 if is a template form
* @return boolean
*/
static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) {
if ($item->getType() == __CLASS__) {
if ($tabnum == 2) {
$item->showVisibility();
return true;
} else if ($tabnum == 1) {
$item->displayOrderTypeForm();
return true;
}
} else if ($item->getType() == 'Computer') {
$package = new self();
$package->showPackageForMe($_SESSION['glpiID'], $item);
return true;
}
return false;
}
/**
* Count number elements for the visibility
*
* @return integer
*/
function countVisibilities() {
return (count($this->entities)
+ count($this->users)
+ count($this->groups)
+ count($this->profiles));
}
/**
* Display the visibility, so who can read. write...
*
* @global array $CFG_GLPI
* @return true
*/
function showVisibility() {
global $CFG_GLPI;
$ID = $this->fields['id'];
$canedit = $this->can($ID, UPDATE);
echo "<div class='center'>";
$rand = mt_rand();
$nb = count($this->users) + count($this->groups) + count($this->profiles)
+ count($this->entities);
if ($canedit) {
echo "<div class='firstbloc'>";
echo "<form name='deploypackagevisibility_form$rand' id='deploypackagevisibility_form$rand' ";
echo " method='post' action='".Toolbox::getItemTypeFormURL('PluginFusioninventoryDeployPackage')."'>";
echo "<input type='hidden' name='plugin_fusioninventory_deploypackages_id' value='$ID'>";
echo "<table class='tab_cadre_fixe'>";
echo "<tr class='tab_bg_1'><th colspan='4'>".__('Add a target for self-service', 'fusioninventory')."</th></tr>";
echo "<tr class='tab_bg_2'><td width='100px'>";
$types = ['Entity', 'Group', 'Profile', 'User'];
$addrand = Dropdown::showItemTypes('_type', $types);
$params = ['type' => '__VALUE__',
'right' => 'plugin_fusioninventory_selfpackage'];
Ajax::updateItemOnSelectEvent("dropdown__type".$addrand, "visibility$rand",
$CFG_GLPI["root_doc"]."/ajax/visibility.php",
$params);
echo "</td>";
echo "<td><span id='visibility$rand'></span>";
echo "</td></tr>";
echo "</table>";
Html::closeForm();
echo "</div>";
}
echo "<div class='spaced'>";
if ($canedit && $nb) {
Html::openMassiveActionsForm('mass'.__CLASS__.$rand);
$massiveactionparams
= ['num_displayed'
=> $nb,
'container'
=> 'mass'.__CLASS__.$rand,
'specific_actions'
=> ['delete' => _x('button', 'Delete permanently')] ];
Html::showMassiveActions($massiveactionparams);
}
echo "<table class='tab_cadre_fixehov'>";
$header_begin = "<tr>";
$header_top = '';
$header_bottom = '';
$header_end = '';
if ($canedit && $nb) {
$header_begin .= "<th width='10'>";
$header_top .= Html::getCheckAllAsCheckbox('mass'.__CLASS__.$rand);
$header_bottom .= Html::getCheckAllAsCheckbox('mass'.__CLASS__.$rand);
$header_end .= "</th>";
}
$header_end .= "<th>".__('Type')."</th>";
$header_end .= "<th>"._n('Recipient', 'Recipients', Session::getPluralNumber())."</th>";
$header_end .= "</tr>";
echo $header_begin.$header_top.$header_end;
// Users
if (count($this->users)) {
foreach ($this->users as $key => $val) {
foreach ($val as $data) {
echo "<tr class='tab_bg_1'>";
if ($canedit) {
echo "<td>";
Html::showMassiveActionCheckBox('PluginFusioninventoryDeployPackage_User', $data["id"]);
echo "</td>";
}
echo "<td>".__('User')."</td>";
echo "<td>".getUserName($data['users_id'])."</td>";
echo "</tr>";
}
}
}
// Groups
if (count($this->groups)) {
foreach ($this->groups as $key => $val) {
foreach ($val as $data) {
echo "<tr class='tab_bg_1'>";
if ($canedit) {
echo "<td>";
Html::showMassiveActionCheckBox('PluginFusioninventoryDeployPackage_Group', $data["id"]);
echo "</td>";
}
echo "<td>".__('Group')."</td>";
echo "<td>";
$names = Dropdown::getDropdownName('glpi_groups', $data['groups_id'], 1);
$groupname = sprintf(__('%1$s %2$s'), $names["name"],
Html::showToolTip($names["comment"], ['display' => false]));
if ($data['entities_id'] >= 0) {
$groupname = sprintf(__('%1$s / %2$s'), $groupname,
Dropdown::getDropdownName('glpi_entities',
$data['entities_id']));
if ($data['is_recursive']) {
$groupname = sprintf(__('%1$s %2$s'), $groupname,
"<span class='b'>(".__('R').")</span>");
}
}
echo $groupname;
echo "</td>";
echo "</tr>";
}
}
}
// Entity
if (count($this->entities)) {
foreach ($this->entities as $key => $val) {
foreach ($val as $data) {
echo "<tr class='tab_bg_1'>";
if ($canedit) {
echo "<td>";
Html::showMassiveActionCheckBox('PluginFusioninventoryDeployPackage_Entity', $data["id"]);
echo "</td>";
}
echo "<td>".Entity::getTypeName(1)."</td>";
echo "<td>";
$names = Dropdown::getDropdownName('glpi_entities', $data['entities_id'], 1);
$entityname = sprintf(__('%1$s %2$s'), $names["name"],
Html::showToolTip($names["comment"], ['display' => false]));
if ($data['is_recursive']) {
$entityname = sprintf(__('%1$s %2$s'), $entityname,
"<span class='b'>(".__('R').")</span>");
}
echo $entityname;
echo "</td>";
echo "</tr>";
}
}
}
// Profiles
if (count($this->profiles)) {
foreach ($this->profiles as $key => $val) {
foreach ($val as $data) {
echo "<tr class='tab_bg_1'>";
if ($canedit) {
echo "<td>";
Html::showMassiveActionCheckBox('PluginFusioninventoryDeployPackage_Profile', $data["id"]);
echo "</td>";
}
echo "<td>"._n('Profile', 'Profiles', 1)."</td>";
echo "<td>";
$names = Dropdown::getDropdownName('glpi_profiles', $data['profiles_id'], 1);
$profilename = sprintf(__('%1$s %2$s'), $names["name"],
Html::showToolTip($names["comment"], ['display' => false]));
if ($data['entities_id'] >= 0) {
$profilename = sprintf(__('%1$s / %2$s'), $profilename,
Dropdown::getDropdownName('glpi_entities',
$data['entities_id']));
if ($data['is_recursive']) {
$profilename = sprintf(__('%1$s %2$s'), $profilename,
"<span class='b'>(".__('R').")</span>");
}
}
echo $profilename;
echo "</td>";
echo "</tr>";
}
}
}
if ($nb) {
echo $header_begin.$header_bottom.$header_end;
}
echo "</table>";
if ($canedit && $nb) {
$massiveactionparams['ontop'] =false;
Html::showMassiveActions($massiveactionparams);
Html::closeForm();
}
echo "</div>";
return true;
}
/**
* Fill internal variable with visibility elements when load package
* information from database
*/
function post_getFromDB() {
// Users
$this->users = PluginFusioninventoryDeployPackage_User::getUsers($this->fields['id']);
// Entities
$this->entities = PluginFusioninventoryDeployPackage_Entity::getEntities($this->fields['id']);
// Group / entities
$this->groups = PluginFusioninventoryDeployPackage_Group::getGroups($this->fields['id']);
// Profile / entities
$this->profiles = PluginFusioninventoryDeployPackage_Profile::getProfiles($this->fields['id']);
}
/**
* Get all available states for a package
* @return an array of states and their labels
*/
static function getPackageDeploymentStates() {
return [
'agents_notdone' => __('Not done yet', 'fusioninventory'),
'agents_error' => __('In error', 'fusioninventory'),
'agents_success' => __('Successful', 'fusioninventory'),
'agents_running' => __('Running', 'fusioninventory'),
'agents_prepared' => __('Prepared', 'fusioninventory'),
'agents_cancelled' => __('Cancelled', 'fusioninventory') ];
}
/**
* Get a label for a state
* @param state the state
* @return the label associated to a state
*/
static function getDeploymentLabelForAState($state) {
$states = self::getPackageDeploymentStates();
if (isset($states[$state])) {
return $states[$state];
} else {
return '';
}
}
/**
* Display a form with a list of packages and their state, that a user
* has request to install on it's computer
*
* @param integer $users_id id of the user
* @param $item source item (maybe a User or a computer)
*/
function showPackageForMe($users_id, $item = false) {
global $CFG_GLPI;
$computer = new Computer();
$self_service = !($_SESSION['glpiactiveprofile']['interface'] == 'central');
if (!$self_service) {
$computers_id = false;
if ($item && $item instanceof Computer) {
$computers_id = $item->getID();
}
$my_packages = $this->getPackageForMe(false, $computers_id);
} else {
$my_packages = $this->getPackageForMe($users_id);
}
// check current interface
$is_tech = isset($_SESSION['glpiactiveprofile']['interface'])
&& $_SESSION['glpiactiveprofile']['interface'] == "central";
// retrieve state name
$joblogs_labels = PluginFusioninventoryTaskjoblog::dropdownStateValues();
// Display for each computer, list of packages you can deploy
$url = Plugin::getWebDir('fusioninventory');
echo "<form name='onetimedeploy_form' id='onetimedeploy_form'
method='POST'
action='$url/front/deploypackage.public.php'
enctype=\"multipart/form-data\">";
echo "<table class='tab_cadre_fixe'>";
foreach ($my_packages as $computers_id => $data) {
$package_to_install = [];
$computer->getFromDB($computers_id);
echo "<tr>";
echo "<th><img src='$url/pics/computer_icon.png'/> "
.__('Computer', 'Computers', 1)." <i>"
.$computer->fields['name']."</i></th>";
echo "</tr>";
if (count($data)) {
echo "<tr class='tab_bg_1'>";
echo "<td>";
echo '<div class="target_block">';
echo '<div class="target_details">';
echo '<div class="target_stats">';
foreach ($data as $packages_id => $package_info) {
if (isset($package_info['taskjobs_id'])) {
$taskjob_id = $package_info['taskjobs_id'];
echo "<div class='counter_block ".$package_info['last_taskjobstate']['state']."'
id='block_$taskjob_id'>";
// display deploy informations
echo "<table>";
echo "<tr>";
echo "<td style='min-width: 600px'>";
// add a toggle control
if ($is_tech) {
echo "<a class='toggle_run'
href='#'
id='toggle_run_$taskjob_id'>";
echo $package_info['name'];
echo "</a>";
} else {
echo $package_info['name'];
}
echo "</td>";
echo "<td style='width: 200px'>";
echo Html::convDateTime($package_info['last_taskjobstate']['date']);
echo "</td>";
echo "<td style='width: 200px'>";
echo self::getDeploymentLabelForAState($package_info['last_taskjobstate']['state']);
echo "</td>";
echo "</tr>";
echo "</table>";
if ($is_tech) {
// display also last log (folded)
echo "<div class='agent_block'
id='run_$taskjob_id'
style='display:none;'>";
echo "<div class='buttons'>";
// if job is in error, suggest restart
if (in_array($package_info['last_taskjobstate']['state'],
["agents_error", "agents_success"])) {
echo "<a class='restart btn'
href='#'
title='".__("Restart job", 'fusioninventory')."'
id='restart_run_$taskjob_id'>
<i class='fa fa-bolt'></i></a>";
}
// if job has not started, user can cancel it
if ($package_info['last_taskjobstate']['state'] == "agents_prepared") {
echo "<a class='cancel btn'
href='#'
title='".__("Cancel job", 'fusioninventory')."'
id='cancel_run_$taskjob_id'>
<i class='fa fa-stop'></i></a>";
}
// permits to "soft" refresh
echo "<a href='#'
title='".__("refresh job", 'fusioninventory')."'
class='btn'
id='refresh_run_$taskjob_id'>
<i class='fa fa-refresh fa-fx'></i></a>";
echo "</div>"; // .buttons
// log list
echo "<table class='runs' id='runs_$taskjob_id'>";
foreach ($package_info['last_taskjobstate']['logs'] as $log) {
echo "<tr class='run log'>";
echo "<td>".$log['log.f_date']."</td>";
echo "<td>".$joblogs_labels[$log['log.state']]."</td>";
echo "<td>".$log['log.comment']."</td>";
echo "</tr>";
}
echo "</table>"; // .runs
echo '</div>'; // .agent_block
}
echo '</div>'; // .counter_block
// js controls (toggle, restart)
echo Html::scriptBlock("$(function() {
var logstatuses_names = ".json_encode($joblogs_labels).";
$('#toggle_run_$taskjob_id').click(function(event){
event.preventDefault();
$('#run_$taskjob_id').toggle();
$(this).toggleClass('expand')
.parent('td')
.nextAll('td').toggle();
});
$('#cancel_run_$taskjob_id').click(function(event){
event.preventDefault();
$.ajax({
url: '".$url."/ajax/cancel_job.php',
data: {
'jobstate_id': ".$package_info['last_taskjobstate']['id'].",
'agent_id': ".$package_info['agent_id']."
},
complete: function() {
document.location.reload();
}
});
});
$('#restart_run_$taskjob_id').click(function(event){
event.preventDefault();
$.ajax({
url: '".$url."/ajax/restart_job.php',
data: {
'jobstate_id': ".$package_info['last_taskjobstate']['id'].",
'agent_id': ".$package_info['agent_id']."
},
complete: function() {
document.location.reload();
}
});
});
$('#refresh_run_$taskjob_id i').click(function() {
var fa = $(this);
fa.addClass('fa-spin fa-spinner')
.removeClass('fa-refresh');
$.ajax({
url: '".$url."/ajax/jobstates_logs.php',
data: {
'id': ".$package_info['last_taskjobstate']['id'].",
'last_date': '2999-01-01 00:00:00' // force a future date
},
success: function(data){
// no data -> reload tab
if (typeof data.logs == 'undefined') {
reloadTab();
return;
}
if (data.logs.length) {
// remove old data
$('#runs_$taskjob_id').empty();
$.each(data.logs, function( index, log ) {
$('#runs_$taskjob_id').append(
'<tr>'+
'<td>'+log['log.f_date']+'</td>'+
'<td>'+logstatuses_names[log['log.state']]+'</td>'+
'<td>'+log['log.comment']+'</td>'+
'<tr>'
)
});
var class_to_apply = '';
switch (data.logs[0]['log.state']) {
case '".PluginFusioninventoryTaskjoblog::TASK_RUNNING."':
class_to_apply = 'agents_running';
break;
case '".PluginFusioninventoryTaskjoblog::TASK_ERROR."':
class_to_apply = 'agents_error';
break;
case '".PluginFusioninventoryTaskjoblog::TASK_OK."':
class_to_apply = 'agents_success';
break;
}
if (class_to_apply.length) {
$('#block_$taskjob_id')
.attr('class', 'counter_block '+class_to_apply);
}
}
},
complete: function() {
setTimeout(function() {
fa.removeClass('fa-spin fa-spinner')
.addClass('fa-refresh');
}, 300);
}
});
})
});");
} else {
$package_to_install[$packages_id] = $package_info['name'];
}
}
echo '</div>'; // .target_stats
echo '</div>'; // .target_details
echo '</div>'; // .target_block
echo "</td>";
echo "</tr>";
}
if (count($package_to_install)) {
$p['name'] = 'deploypackages_'.$computers_id;
$p['display'] = true;
$p['multiple'] = true;
$p['size'] = 3;
$p['width'] = 950;
echo "<tr class='tab_bg_1'>";
echo "<td>";
echo __('Select packages you want install', 'fusioninventory');
echo "<br/>";
Dropdown::showFromArray($p['name'], $package_to_install, $p);
echo "</td>";
echo "</tr>";
echo "<tr>";
echo "<th colspan='2'>";
echo Html::submit(__('Prepare for install', 'fusioninventory'),
['name' => 'prepareinstall']);
echo "&nbsp;";
if (!$self_service) {
$options = ['local' => __("I'm on this computer: local wakeup", 'fusioninventory'),
'remote' => __("I'm not on this computer: wakeup from the server", 'fusioninventory'),
'none' => __("Don't wakeup", 'fusioninventory')
];
Dropdown::showFromArray('wakeup_type', $options,
['value' => 'remote']);
} else {
echo Html::hidden('wakeup_type', ['value' => 'local']);
}
echo Html::hidden('self_service', ['value' => $self_service]);
echo "</th>";
echo "</tr>";
} else {
echo "<tr>";
echo "<th colspan='2'>";
echo __('No packages available to install', 'fusioninventory');
echo "</th>";
echo "</tr>";
}
}
echo "</table>"; // .tab_cadre_fixe
Html::closeForm();
}
/**
* Check if an agent have deploy feature enabled
* @since 9.2
*
* @param integer $computers_id the ID of the computer to check
* @return boolean true if deploy is enabled for the agent
*/
static function isDeployEnabled($computers_id) {
$pfAgent = new PluginFusioninventoryAgent();
//If the agent associated with the computer has not the
//deploy feature enabled, do not propose to deploy packages on
if (!$pfAgent->getAgentWithComputerid($computers_id)) {
return false;
}
$pfAgentModule = new PluginFusioninventoryAgentmodule();
if ($pfAgentModule->isAgentCanDo('deploy', $pfAgent->getID())) {
return true;
} else {
return false;
}
}
/**
* Get deploy packages available to install on user computer(s) and for
* packages requested the state of deploy
*
* @param integer $users_id id of the user
*/
function getPackageForMe($users_id, $computers_id = false) {
$computer = new Computer();
$pfDeployGroup = new PluginFusioninventoryDeployGroup();
$my_packages = []; //Store all installable packages
$query = [];
if ($users_id) {
$query += ['users_id' => $users_id];
}
if ($computers_id) {
$query += ['id' => $computers_id];
}
$query += ['entities_id' => $_SESSION['glpiactiveentities']];
//Get all computers of the user
$mycomputers = $computer->find($query);
$pfAgent = new PluginFusioninventoryAgent();
foreach ($mycomputers as $mycomputers_id => $data) {
$my_packages[$mycomputers_id] = [];
}
//Get packages used for the user or a specific computer
$packages_used = $this->getMyDepoyPackages($my_packages, $users_id);
//Get packages that a the user can deploy
$packages = $this->canUserDeploySelf();
if ($packages) {
//Browse all packages that the user can install
foreach ($packages as $package) {
//Get computers that can be targeted for this package installation
$computers = $pfDeployGroup->getTargetsForGroup($package['plugin_fusioninventory_deploygroups_id']);
//Browse all computers that are target by a a package installation
foreach ($mycomputers as $comp_id => $data) {
//If we only want packages for one computer
//check if it's the computer we look for
if ($computers_id && $comp_id != $computers_id) {
continue;
}
//If the agent associated with the computer has not the
//deploy feature enabled, do not propose to deploy packages on it
if (!self::isDeployEnabled($comp_id)) {
continue;
}
//Get computers that can be targeted for this package installation
//Check if the package belong to one of the entity that
//are currenlty visible
//The package is recursive, and visible in computer's entity
if (Session::isMultiEntitiesMode()) {
if (!$package['is_recursive']
&& $package['entities_id'] != $data['entities_id']) {
continue;
} else if ($package['is_recursive']
&& $package['entities_id'] != $data['entities_id']
&& !in_array($package['entities_id'],
getAncestorsOf('glpi_entities', $data['entities_id']))) {
//The package is not recursive, and invisible in the computer's entity
continue;
}
}
//Does the computer belongs to the group
//associated with the package ?
if (isset($computers[$comp_id])) {
$my_packages[$comp_id][$package['id']]
= ['name' => $package['name'],
'agent_id' => $pfAgent->getId()];
//The package has already been deployed or requested to deploy
if (isset($packages_used[$comp_id][$package['id']])) {
$taskjobs_id = $packages_used[$comp_id][$package['id']];
$my_packages[$comp_id][$package['id']]['taskjobs_id'] = $taskjobs_id;
$last_job_state = $this->getMyDepoyPackagesState($comp_id, $taskjobs_id);
if ($last_job_state) {
$my_packages[$comp_id][$package['id']]['last_taskjobstate']
= $last_job_state;
}
}
}
}
}
}
return $my_packages;
}
/**
* Add the package in task or use existant task and add the computer in
* taskjob
*
* @global object $DB
* @param integer $computers_id id of the computer where depoy package
* @param integer $packages_id id of the package to install in computer
* @param integer $users_id id of the user have requested the installation
*/
function deployToComputer($computers_id, $packages_id, $users_id) {
global $DB;
$pfTask = new PluginFusioninventoryTask();
$pfTaskJob = new PluginFusioninventoryTaskJob();
$computer = new Computer();
$computer->getFromDB($computers_id);
//Get jobs for a package on a computer
$query = "SELECT `job`.*
FROM `glpi_plugin_fusioninventory_taskjobs` AS job"
. " LEFT JOIN `glpi_plugin_fusioninventory_tasks` AS task"
. " ON `task`.`id` = `job`.`plugin_fusioninventory_tasks_id`"
. " WHERE `job`.`targets`='[{\"PluginFusioninventoryDeployPackage\":\"".$packages_id."\"}]'"
. " AND `task`.`is_active`='1'"
. " AND `task`.`is_deploy_on_demand`='1'"
. " AND `task`.`entities_id`='".$computer->fields['entities_id']."'"
. " AND `task`.`reprepare_if_successful`='0'"
." AND `job`.`method`='deployinstall'"
. " LIMIT 1";
$iterator = $DB->request($query);
// case 1: if exist, we add computer in actors of the taskjob
if ($iterator->numrows() == 1) {
foreach ($iterator as $data) {
//Get current list of actors
$actors = importArrayFromDB($data['actors']);
//Add a new actor : the computer that is being processed
$actors[] = ['Computer' => $computers_id];
//Get end user computers
$enduser = importArrayFromDB($data['enduser']);
if (isset($enduser[$users_id])) {
if (!in_array($computers_id, $enduser[$users_id])) {
$enduser[$users_id][] = $computers_id;
}
} else {
$enduser[$users_id] = [$computers_id];
}
$input = [
'id' => $data['id'],
'actors' => exportArrayToDB($actors),
'enduser' => exportArrayToDB($enduser)
];
//Update the job with the new actor
$pfTaskJob->update($input);
$tasks_id = $data['plugin_fusioninventory_tasks_id'];
}
} else {
// case 2: if not exist, create a new task + taskjob
$this->getFromDB($packages_id);
//Add the new task
$input = [
'name' => '[deploy on demand] '.$this->fields['name'],
'entities_id' => $computer->fields['entities_id'],
'reprepare_if_successful' => 0,
'is_deploy_on_demand' => 1,
'is_active' => 1,
];
$tasks_id = $pfTask->add($input);
//Add a new job for the newly created task
//and enable it
$input = [
'plugin_fusioninventory_tasks_id' => $tasks_id,
'entities_id' => $computer->fields['entities_id'],
'name' => 'deploy',
'method' => 'deployinstall',
'targets' => '[{"PluginFusioninventoryDeployPackage":"'.$packages_id.'"}]',
'actors' => exportArrayToDB([['Computer' => $computers_id]]),
'enduser' => exportArrayToDB([$users_id => [$computers_id]]),
];
$pfTaskJob->add($input);
}
//Prepare the task (and only this one)
$pfTask->prepareTaskjobs(['deployinstall'], $tasks_id);
}
/**
* Get all packages that a user has requested to install
* on one of it's computer
*
* @global object $DB
* @param array $computers_packages
* @param integer $users_id
* @return array
*/
function getMyDepoyPackages($computers_packages, $users_id = false) {
global $DB;
// Get packages yet deployed by enduser
$packages_used = [];
foreach ($computers_packages as $computers_id => $data) {
$packages_used[$computers_id] = [];
}
if ($users_id) {
$where = "`enduser` IS NOT NULL";
} else {
$where = "1 ";
}
$sql = "SELECT `job`.*
FROM `glpi_plugin_fusioninventory_taskjobs` AS job
LEFT JOIN `glpi_plugin_fusioninventory_tasks` AS task
ON `task`.`id` = `job`.`plugin_fusioninventory_tasks_id`
WHERE $where
AND `task`.`is_deploy_on_demand`='1'
AND `task`.`is_active`='1'
AND `task`.`entities_id`
IN (".$_SESSION['glpiactiveentities_string'].")";
foreach ($DB->request($sql) as $data) {
//Only look for deploy tasks
if ($data['method'] != 'deployinstall') {
continue;
}
//Look for all deploy on demand packages for a user
if ($users_id) {
$enduser = importArrayFromDB($data['enduser']);
if (isset($enduser[$users_id])) {
$targets = importArrayFromDB($data['targets']);
foreach ($enduser[$users_id] as $computers_id) {
$packages_used[$computers_id][$targets[0]['PluginFusioninventoryDeployPackage']] = $data['id'];
}
}
//Look for all deploy on demand package for a computer
} else {
$targets = importArrayFromDB($data['targets']);
$actors = importArrayFromDB($data['actors']);
foreach ($actors as $actor) {
foreach ($actor as $itemtype => $items_id) {
if ($itemtype == 'Computer' && $items_id == $computers_id) {
$packages_used[$computers_id][$targets[0]['PluginFusioninventoryDeployPackage']] = $data['id'];
}
}
}
}
}
return $packages_used;
}
/**
* Get the state of the package I have requeted to install
*
* @param integer $computers_id id of the computer
* @param integer $taskjobs_id id of the taskjob (where order defined)
* @param string $packages_name name of the package
*/
function getMyDepoyPackagesState($computers_id, $taskjobs_id) {
$pfTaskJobState = new PluginFusioninventoryTaskjobstate();
$pfAgent = new PluginFusioninventoryAgent();
// Get a taskjobstate by giving a taskjobID and a computer ID
$agents_id = $pfAgent->getAgentWithComputerid($computers_id);
$last_job_state = [];
$taskjobstates = current($pfTaskJobState->find(
['plugin_fusioninventory_taskjobs_id' => $taskjobs_id,
'plugin_fusioninventory_agents_id' => $agents_id], ['id DESC'], 1));
if ($taskjobstates) {
$state = '';
switch ($taskjobstates['state']) {
case PluginFusioninventoryTaskjobstate::CANCELLED :
$state = 'agents_cancelled';
break;
case PluginFusioninventoryTaskjobstate::PREPARED :
$state = 'agents_prepared';
break;
case PluginFusioninventoryTaskjobstate::SERVER_HAS_SENT_DATA :
case PluginFusioninventoryTaskjobstate::AGENT_HAS_SENT_DATA :
$state = 'agents_running';
break;
case PluginFusioninventoryTaskjobstate::IN_ERROR :
$state = 'agents_error';
break;
case PluginFusioninventoryTaskjobstate::FINISHED :
$state = 'agents_success';
break;
}
$logs = $pfTaskJobState->getLogs($taskjobstates['id'],
$_SESSION['glpi_currenttime']);
$last_job_state['id'] = $taskjobstates['id'];
$last_job_state['state'] = $state;
$last_job_state['date'] = $logs['logs'][0]['log.date'];
$last_job_state['logs'] = $logs['logs'];
}
return $last_job_state;
}
/**
* Check I have rights to deploy packages
*
* @global object $DB
* @return false|array
*/
function canUserDeploySelf() {
global $DB;
$table = "glpi_plugin_fusioninventory_deploypackages";
$where = " WHERE `".$table."`.`plugin_fusioninventory_deploygroups_id` > 0 "
. " AND (";
//Include groups
if (!empty($_SESSION['glpigroups'])) {
$where .= " `glpi_plugin_fusioninventory_deploypackages_groups`.`groups_id`
IN ('".implode("', '", $_SESSION['glpigroups'])."') OR ";
}
//Include entity
$where.= getEntitiesRestrictRequest('', 'glpi_plugin_fusioninventory_deploypackages_entities',
'entities_id', $_SESSION['glpiactive_entity'], true);
//Include user
$where .= " OR `glpi_plugin_fusioninventory_deploypackages_users`.`users_id`='".$_SESSION['glpiID']."' OR ";
//Include profile
$where .= " `glpi_plugin_fusioninventory_deploypackages_profiles`.`profiles_id`='".$_SESSION['glpiactiveprofile']['id']."' ";
$where .= " )";
$query = "SELECT DISTINCT `".$table."`.*
FROM `$table`
LEFT JOIN `glpi_plugin_fusioninventory_deploypackages_groups`
ON (`glpi_plugin_fusioninventory_deploypackages_groups`.`plugin_fusioninventory_deploypackages_id` = `$table`.`id`)
LEFT JOIN `glpi_plugin_fusioninventory_deploypackages_entities`
ON (`glpi_plugin_fusioninventory_deploypackages_entities`.`plugin_fusioninventory_deploypackages_id` = `$table`.`id`)
LEFT JOIN `glpi_plugin_fusioninventory_deploypackages_users`
ON (`glpi_plugin_fusioninventory_deploypackages_users`.`plugin_fusioninventory_deploypackages_id` = `$table`.`id`)
LEFT JOIN `glpi_plugin_fusioninventory_deploypackages_profiles`
ON (`glpi_plugin_fusioninventory_deploypackages_profiles`.`plugin_fusioninventory_deploypackages_id` = `$table`.`id`)
$where";
$result = $DB->query($query);
$a_packages = [];
if ($DB->numrows($result) > 0) {
while ($data = $DB->fetchAssoc($result)) {
$a_packages[$data['id']] = $data;
}
return $a_packages;
}
return false;
}
/**
* Duplicate a deploy package
* @param $deploypackages_id the ID of the package to duplicate
* @return duplication process status
*/
public function duplicate($deploypackages_id) {
if (!$this->getFromDB($deploypackages_id)) {
return false;
}
$result = true;
$input = $this->fields;
$input['name'] = sprintf(__('Copy of %s'),
$this->fields['name']);
unset($input['id']);
$input = Toolbox::addslashes_deep($input);
if (!$this->add($input)) {
$result = false;
}
return $result;
}
/**
* Append needed informations to the json job for an agent
* @since 9.2
* @param $agent_task_version the version of the agent's deploy task
* @param $job the job as an array
* @return array the job plus new needed fields
*/
function buildJson($agent_task_version, $job) {
//If task doesn't support checks skip, info, warning,
//send an ignore instead
//tasks version needs to be at least 2.2
$is_old_agent = version_compare($agent_task_version, '2.2', 'lt');
if ($is_old_agent && isset($job['job']['checks'])) {
foreach ($job['job']['checks'] as $key => $value) {
if (in_array($value['return'], ['skip', 'info', 'warning'])) {
$job['job']['checks'][$key]['return'] = 'ignore';
}
}
}
//No need to perform further test if the agent doesn't support
//user interactions
if ($is_old_agent) {
return $job;
}
$do_interaction = true;
$jobstate = new PluginFusioninventoryTaskjobstate();
//Job has reached the maximum number of retries, do not interact with the user
//and execute the job
$jobstate->getFromDBByUniqID($job['job']['uuid']);
if (isset($jobstate->fields['nb_retry'])
&& $jobstate->fields['max_retry'] > 0) {
if ($jobstate->fields['nb_retry'] >= $jobstate->fields['max_retry']) {
$do_interaction = false;
}
}
//If the number of retries has been met,
//remove all userinteractions directives
if (!$do_interaction) {
unset($job['job']['userinteractions']);
} else if (isset($job['job']['userinteractions'])) {
$template = new PluginFusioninventoryDeployUserinteractionTemplate();
foreach ($job['job']['userinteractions'] as $key => $value) {
if (isset($value['template']) && $value['template']) {
if ($template->getFromDB($value['template'])) {
$job['job']['userinteractions'][$key]
= $template->addJsonFieldsToArray($job['job']['userinteractions'][$key]);
unset ($job['job']['userinteractions'][$key]['template']);
$job['job']['userinteractions'][$key]['text']
= str_replace(PluginFusioninventoryDeployUserinteraction::RN_TRANSFORMATION, "\r\n",
$job['job']['userinteractions'][$key]['text']);
}
}
}
}
return $job;
}
/**
* Transform \r\n in an userinteraction text
* @since 9.2
* @param array $params the input parameters
* @return array $params input parameters with text modified
*/
public function escapeText($params) {
//Hack to keep \r\n in the user interaction text
//before going to stripslashes_deep
if (isset($params['text'])) {
$params['text']
= str_replace('\r\n',
PluginFusioninventoryDeployUserinteraction::RN_TRANSFORMATION,
$params['text']);
}
return $params;
}
}