Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions ajax/inject_batch.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

/**
* -------------------------------------------------------------------------
* DataInjection plugin for GLPI
* -------------------------------------------------------------------------
*
* LICENSE
*
* This file is part of DataInjection.
*
* DataInjection 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.
*
* DataInjection 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 DataInjection. If not, see <http://www.gnu.org/licenses/>.
* -------------------------------------------------------------------------
* @copyright Copyright (C) 2007-2023 by DataInjection plugin team.
* @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html
* @link https://github.com/pluginsGLPI/datainjection
* -------------------------------------------------------------------------
*/
use function Safe\json_encode;

header("Content-Type: application/json; charset=UTF-8");
Html::header_nocache();

Session::checkCentralAccess();

$offset = (int) ($_POST['offset'] ?? 0);
$batch_size = (int) ($_POST['batch_size'] ?? 10);

echo json_encode(
PluginDatainjectionClientInjection::processBatch($offset, $batch_size),
);
187 changes: 86 additions & 101 deletions inc/clientinjection.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,34 +42,6 @@
use function Safe\readfile;
use function Safe\unlink;

/**
* -------------------------------------------------------------------------
* DataInjection plugin for GLPI
* -------------------------------------------------------------------------
*
* LICENSE
*
* This file is part of DataInjection.
*
* DataInjection 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.
*
* DataInjection 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 DataInjection. If not, see <http://www.gnu.org/licenses/>.
* -------------------------------------------------------------------------
* @copyright Copyright (C) 2007-2023 by DataInjection plugin team.
* @license GPLv2 https://www.gnu.org/licenses/gpl-2.0.html
* @link https://github.com/pluginsGLPI/datainjection
* -------------------------------------------------------------------------
*/

class PluginDatainjectionClientInjection
{
public static $rightname = "plugin_datainjection_use";
Expand All @@ -78,9 +50,6 @@ class PluginDatainjectionClientInjection
public const STEP_PROCESS = 1;
public const STEP_RESULT = 2;

//Injection results
private $results = [];

/**
* Print a good title for group pages
*
Expand Down Expand Up @@ -158,117 +127,133 @@ public static function showUploadFileForm($options = [])
**/
public static function showInjectionForm(PluginDatainjectionModel $model, $entities_id)
{
/** @var array $CFG_GLPI */
global $CFG_GLPI;

if (!PluginDatainjectionSession::getParam('infos')) {
PluginDatainjectionSession::setParam('infos', []);
}

$nblines = PluginDatainjectionSession::getParam('nblines');

//Read all CSV lines into session for batch processing
$backend = $model->getBackend();
$model->loadSpecificModel();
$backend->openFile();

$lines = [];
$line = $backend->getNextLine();

//If header is present, skip it
if ($model->getSpecificModel()->isHeaderPresent()) {
$line = $backend->getNextLine();
}

while ($line != null) {
$lines[] = $line;
$line = $backend->getNextLine();
}
$backend->closeFile();

//Store lines in session for batch processing
PluginDatainjectionSession::setParam('injection_lines', json_encode($lines));
PluginDatainjectionSession::setParam('injection_results', json_encode([]));
PluginDatainjectionSession::setParam('injection_error_lines', json_encode([]));

$batch_url = $CFG_GLPI['root_doc'] . "/plugins/datainjection/ajax/inject_batch.php";
$result_url = $CFG_GLPI['root_doc'] . "/plugins/datainjection/ajax/results.php";

TemplateRenderer::getInstance()->display('@datainjection/clientinjection_injection.html.twig', [
'model_name' => $model->fields['name'],
'nblines' => $nblines,
'model_id' => $model->fields['id'],
'batch_url' => $batch_url,
'result_url' => $result_url,
'plugin_url' => plugin_datainjection_geturl(),
]);

// L'injection réelle reste côté PHP, mais tu peux déclencher l'appel Ajax ici si besoin
echo "<span id='span_injection' name='span_injection'></span>";
self::processInjection($model, $entities_id);
}


/**
* @param PluginDatainjectionModel $model
* @param integer $entities_id
* Process a batch of injection lines.
*
* @param int $offset Starting line offset
* @param int $batch_size Number of lines to process in this batch
*
* @return array JSON-serializable result with progress info
**/
public static function processInjection(PluginDatainjectionModel $model, $entities_id)
public static function processBatch(int $offset, int $batch_size): array
{
/** @var array $CFG_GLPI */
global $CFG_GLPI;

try {
ini_set("max_execution_time", "0");
} catch (InfoException $e) {
//empty catch -- but keep trace of issue
ErrorHandler::logCaughtException($e);
}

// Disable recording each SQL request in $_SESSION
Profile::getCurrent()->disable();

$nblines = PluginDatainjectionSession::getParam('nblines');
$clientinjection = new PluginDatainjectionClientInjection();
$model = unserialize($_SESSION['datainjection']['currentmodel']);
$model->loadSpecificModel();
$entities_id = $_SESSION['glpiactive_entity'];
$lines_json = PluginDatainjectionSession::getParam('injection_lines');
$lines = json_decode($lines_json, true);

$results_json = PluginDatainjectionSession::getParam('injection_results');
$results = json_decode($results_json, true) ?: [];
$error_lines_json = PluginDatainjectionSession::getParam('injection_error_lines');
$error_lines = json_decode($error_lines_json, true) ?: [];

//New injection engine
$engine = new PluginDatainjectionEngine(
$model,
PluginDatainjectionSession::getParam('infos'),
$entities_id,
);
$backend = $model->getBackend();
$model->loadSpecificModel();

//Open CSV file
$backend->openFile();
$header_offset = $model->getSpecificModel()->isHeaderPresent() ? 2 : 1;
$total = count($lines);
$end = min($offset + $batch_size, $total);

$index = 0;

//Read CSV file
$line = $backend->getNextLine();

//If header is present, then get the second line
if ($model->getSpecificModel()->isHeaderPresent()) {
$line = $backend->getNextLine();
}
for ($i = $offset; $i < $end; $i++) {
$injectionline = $i + $header_offset;
$result = $engine->injectLine($lines[$i][0], $injectionline);
$results[] = $result;

//While CSV file is not EOF
$prev = '';
$deb = time();
while ($line != null) {
//Inject line
$injectionline = $index + ($model->getSpecificModel()->isHeaderPresent() ? 2 : 1);
$clientinjection->results[] = $engine->injectLine($line[0], $injectionline);

$pos = number_format($index * 100 / $nblines, 1);
if ($pos != $prev) {
$prev = $pos;
$fin = time() - $deb;
if ($result['status'] != PluginDatainjectionCommonInjectionLib::SUCCESS) {
$error_lines[] = $lines[$i][0];
}
$line = $backend->getNextLine();
$index++;
}

$js = <<<JAVASCRIPT
$(function() {
const progress = document.querySelector('.progress');
const progressBar = document.querySelector('.progress-bar');
if (progressBar && progress) {
progressBar.style.width = '100%';
progress.setAttribute('aria-valuenow', '100');
}
});
JAVASCRIPT;

//EOF : change progressbar to 100% !
echo Html::scriptBlock($js);

// Restore
Profile::getCurrent()->enable();
//Store updated results
PluginDatainjectionSession::setParam('injection_results', json_encode($results));
PluginDatainjectionSession::setParam('injection_error_lines', json_encode($error_lines));

//Close CSV file
$backend->closeFile();
$done = ($end >= $total);
$progress = $total > 0 ? round(($end / $total) * 100, 1) : 100;

//Delete CSV file
$backend->deleteFile();
if ($done) {
//Finalize: move results to the standard session params, clean up
PluginDatainjectionSession::setParam('results', json_encode($results));
PluginDatainjectionSession::setParam('error_lines', json_encode($error_lines));

//Change step
$_SESSION['datainjection']['step'] = self::STEP_RESULT;
$_SESSION['datainjection']['step'] = self::STEP_RESULT;
unset($_SESSION['datainjection']['go']);

//Display results form
PluginDatainjectionSession::setParam('results', json_encode($clientinjection->results));
PluginDatainjectionSession::setParam('error_lines', json_encode($engine->getLinesInError()));
$p['models_id'] = $model->fields['id'];
$p['nblines'] = $nblines;
//Delete CSV file
$backend = $model->getBackend();
$backend->deleteFile();
}

unset($_SESSION['datainjection']['go']);
Profile::getCurrent()->enable();

$url = $CFG_GLPI['root_doc'] . "/plugins/datainjection/ajax/results.php";
Ajax::updateItem("span_injection", $url, $p);
return [
'progress' => $progress,
'done' => $done,
'offset' => $end,
'total' => $total,
'processed' => $end,
];
}


Expand Down
23 changes: 16 additions & 7 deletions inc/session.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public static function getParam($param)
if (!isset($_SESSION['datainjection'][$param])) {
return false;
}
if (in_array($param, ['results', 'error_lines'])) {
if (in_array($param, ['results', 'error_lines', 'injection_lines', 'injection_results', 'injection_error_lines'])) {
$fic = $_SESSION['datainjection'][$param];
return file_get_contents(GLPI_TMP_DIR . '/' . $fic);
}
Expand All @@ -66,7 +66,13 @@ public static function getParam($param)
public static function setParam($param, $results): void
{

if (in_array($param, ['results', 'error_lines'])) {
if (in_array($param, ['results', 'error_lines', 'injection_lines', 'injection_results', 'injection_error_lines'])) {
if (isset($_SESSION['datainjection'][$param])) {
$old_fic = GLPI_TMP_DIR . '/' . $_SESSION['datainjection'][$param];
if (file_exists($old_fic)) {
unlink($old_fic);
}
}
$fic = Session::getLoginUserID() . '_' . $param . '_' . microtime(true);
file_put_contents(GLPI_TMP_DIR . '/' . $fic, $results);
$_SESSION['datainjection'][$param] = $fic;
Expand All @@ -84,11 +90,14 @@ public static function setParam($param, $results): void
public static function removeParams(): void
{

if (isset($_SESSION['datainjection']['results'])) {
unlink(GLPI_TMP_DIR . '/' . $_SESSION['datainjection']['results']);
}
if (isset($_SESSION['datainjection']['error_lines'])) {
unlink(GLPI_TMP_DIR . '/' . $_SESSION['datainjection']['error_lines']);
$file_params = ['results', 'error_lines', 'injection_lines', 'injection_results', 'injection_error_lines'];
foreach ($file_params as $param) {
if (isset($_SESSION['datainjection'][$param])) {
$fic = GLPI_TMP_DIR . '/' . $_SESSION['datainjection'][$param];
if (file_exists($fic)) {
unlink($fic);
}
}
}
unset($_SESSION['datainjection']);
}
Expand Down
30 changes: 25 additions & 5 deletions templates/clientinjection_injection.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,33 @@
</span>
</h3>
</div>
<div class="card p-3 my-5">
<div class="card p-3 my-5"
id="injection_container"
data-batch-url="{{ batch_url }}"
data-result-url="{{ result_url }}"
data-model-id="{{ model_id }}"
data-nblines="{{ nblines }}"
data-batch-size="10"
data-status-label="{{ __('Injection of the file', 'datainjection') }}"
data-lines-label="{{ __(' lines', 'datainjection') }}"
data-error-label="{{ __('Error', 'datainjection') }}"
>
<div class="hr-text mt-5 mb-5">
<i class="fa-2x ti ti-chart-bar"></i>
<span>{{ __('Import progress', 'datainjection') }}</span>
</div>
<div class="progress" role="progressbar" aria-label={{ __('Injection of the file', 'datainjection') }} aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="height: 20px;">
<div class="progress-bar progress-bar-striped bg-info" style="width: 0%; height: 20px;">
{{ __('Injection of the file', 'datainjection') }}
<div class="progress" role="progressbar" aria-label="{{ __('Injection of the file', 'datainjection') }}" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="height: 20px;">
<div class="progress-bar progress-bar-striped progress-bar-animated bg-info" style="width: 0%; height: 20px;">
0%
</div>
</div>
</div>
<div class="text-muted text-center mt-2" id="injection_status">
{{ __('Injection of the file', 'datainjection') }} — 0 / {{ nblines }} {{ __(' lines', 'datainjection') }}
</div>

<script src="{{ plugin_url }}js/injection_progress.js"></script>
<script>
$(function() {
startBatchInjection(document.getElementById('injection_container'));
});
</script>