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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Fixed

- Fix the uploaded file name being lost after the client injection upload step
- Fix additional information sharing a field name across itemtypes (e.g. two device designations) overwriting each other, and show the itemtype next to each field
- Stop flagging a network port injection as partial when no connection to a network equipment port is requested
- Made several generic warnings more explicit. They explain why the mapping failed.
- Stop requesting a network port connection when its connection columns are empty

## [2.15.12] - 2026-10-05

Expand Down
73 changes: 59 additions & 14 deletions inc/commoninjectionlib.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@ class PluginDatainjectionCommonInjectionLib

public const ERROR_IMPORT_REFUSED = 39; //Dictionnary explicitly refuse import

public const ERROR_NAME_NOT_MAPPED = 40; //Dropdown/device not created: its name field is not mapped or empty in the row

public const WARNING_NETPORT_NOT_FOUND = 41; //Network port not connected: no matching network equipment port

public const WARNING_NETPORT_AMBIGUOUS = 42; //Network port not connected: several network equipment ports match

public const WARNING_NETPORT_ALREADY_CONNECTED = 43; //Network port not connected: the network equipment port is used

//Empty values
public const EMPTY_VALUE = '';

Expand Down Expand Up @@ -1705,15 +1713,13 @@ public function processAddOrUpdate()
$values = $this->getValuesForItemtype($this->primary_type);
$newID = $this->effectiveAddOrUpdate($this->injectionClass, $item, $values, $add);

if (!$newID) {
$this->addCheckWarning(self::WARNING, $item::class);
} else {
if ($newID) {
//Store id of the injected item
$this->setValueForItemtype($this->primary_type, 'id', $newID);

//If type needs it : process more data after type import
if ($this->processAfterInsertOrUpdate($this->injectionClass, $add) === false) {
$this->addCheckWarning(self::WARNING, $item::class);
if (($code = $this->processAfterInsertOrUpdate($this->injectionClass, $add)) !== null) {
$this->addCheckWarning($code, $item::class);
}

//$this->results['status'] = self::SUCCESS;
Expand Down Expand Up @@ -1753,10 +1759,8 @@ public function processAddOrUpdate()
$values = $this->getValuesForItemtype($itemtype);
if ($this->lastCheckBeforeProcess($injectionClass)) {
$tmpID = $this->effectiveAddOrUpdate($injectionClass, $item, $values, $add);
if (!$tmpID) {
$this->addCheckWarning(self::WARNING, $itemtype);
} elseif ($this->processAfterInsertOrUpdate($injectionClass, $add) === false) {
$this->addCheckWarning(self::WARNING, $itemtype);
if ($tmpID && ($code = $this->processAfterInsertOrUpdate($injectionClass, $add)) !== null) {
$this->addCheckWarning($code, $itemtype);
}
}
}
Expand Down Expand Up @@ -1897,6 +1901,22 @@ private function effectiveAddOrUpdate($injectionClass, $item, $values, $add = tr
$newID = $injectionClass->customimport($toinject, $add, $this->rights);
} elseif ($item instanceof CommonDropdown && $add && !($item instanceof SoftwareLicense)) {
$newID = $item->import($toinject);

// import() silently rejects items without a name (designation for devices): tell the user which field to map or fill
$name_field = $item instanceof CommonDevice ? 'designation' : 'name';
if ($newID <= 0 && empty($toinject[$name_field]) && empty($toinject['completename'])) {
$option = self::findSearchOption($options, $name_field);
$this->addCheckWarning(
self::ERROR_NAME_NOT_MAPPED,
sprintf(
__('%1$s - %2$s'),
$item::getTypeName(1),
$option['name'] ?? $name_field,
),
);
$this->setValueForItemtype($item::class, 'id', 0);
return 0; // reason already logged: no generic warning
}
} elseif ($add) {
if ($newID = $item->add($toinject)) {
self::logAddOrUpdate($item, $add);
Expand All @@ -1914,6 +1934,10 @@ private function effectiveAddOrUpdate($injectionClass, $item, $values, $add = tr
}
}

if (!$newID) {
$this->addCheckWarning(self::WARNING, $item::class);
}

$this->setValueForItemtype($item::class, 'id', $newID);
return $newID;
}
Expand Down Expand Up @@ -2317,6 +2341,22 @@ public static function getLogLabel($type)
$message = __('Import not allowed', 'datainjection');
break;

case self::ERROR_NAME_NOT_MAPPED:
$message = __('Item not created: the following field is not mapped or is empty', 'datainjection');
break;

case self::WARNING_NETPORT_NOT_FOUND:
$message = __('Network port not connected: no matching network equipment port found', 'datainjection');
break;

case self::WARNING_NETPORT_AMBIGUOUS:
$message = __('Network port not connected: several network equipment ports match', 'datainjection');
break;

case self::WARNING_NETPORT_ALREADY_CONNECTED:
$message = __('Network port not connected: the network equipment port is already connected to another port', 'datainjection');
break;

case self::FAILED:
$message = __('Import failed', 'datainjection');
break;
Expand Down Expand Up @@ -2512,17 +2552,22 @@ public static function addTemplateSearchOptions($injectionClass, &$tab)
* @param PluginDatainjectionInjectionInterface $injectionClass the injection class to use
* @param $add true if an item is created, false if it's an update
*
* @return bool false if the injection class rejected a post-processing step
* @return int|null log code of the rejected post-processing step, null if none
**/
private function processAfterInsertOrUpdate($injectionClass, $add = true)
private function processAfterInsertOrUpdate($injectionClass, $add = true): ?int
{

//If itemtype implements special process after type injection
if (method_exists($injectionClass, 'processAfterInsertOrUpdate')) {
//Invoke it
return $injectionClass->processAfterInsertOrUpdate($this->values, $add, $this->rights) !== false;
//Invoke it: false is a generic failure, an int is the log code explaining it
$result = $injectionClass->processAfterInsertOrUpdate($this->values, $add, $this->rights);
if (is_int($result)) {
return $result;
}

return $result === false ? self::WARNING : null;
}

return true;
return null;
}
}
9 changes: 4 additions & 5 deletions inc/contractinjection.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,12 @@ public function addOrUpdateObject($values = [], $options = [])


/**
* @param array $info array
* @param array $option array
**/
public function showAdditionalInformation($info = [], $option = [])
* @param array $option array
**/
public function showAdditionalInformation(PluginDatainjectionInfo $info, $option = [])
{

$name = "info[" . $option['linkfield'] . "]";
$name = $info->getInputName();

switch ($option['displaytype']) {
case 'alert':
Expand Down
9 changes: 3 additions & 6 deletions inc/engine.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -222,12 +222,9 @@ public function addAdditionalInformations()

$additional_infos = [];
foreach ($this->model->getInfos() as $info) {
if (
isset($this->infos[$info->getValue()])
&& PluginDatainjectionInfo::keepInfo($info, $this->infos[$info->getValue()])
) {
$additional_infos[$info->getInfosType()][$info->getValue()]
= $this->infos[$info->getValue()];
$value = $info->getPostedValue($this->infos);
if ($value !== null && PluginDatainjectionInfo::keepInfo($info, $value)) {
$additional_infos[$info->getInfosType()][$info->getValue()] = $value;
}
}

Expand Down
31 changes: 23 additions & 8 deletions inc/info.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,26 @@ public function getInfosType()
return $this->fields["itemtype"];
}

/**
* Name of the form input: keyed by itemtype too, as several itemtypes may share a field name
*/
public function getInputName(): string
{
return 'info[' . $this->getInfosType() . '][' . $this->getValue() . ']';
}

/**
* Value filled by the user for this info, as posted by the form built with getInputName()
*
* @param array $values infos posted by the user
*
* @return mixed|null
*/
public function getPostedValue(array $values)
{
return $values[$this->getInfosType()][$this->getValue()] ?? null;
}

/**
* @param PluginDatainjectionModel $model PluginDatainjectionModel object
* @param boolean $canedit (false by default)
Expand Down Expand Up @@ -309,7 +329,7 @@ public static function displayAdditionalInformation(PluginDatainjectionInfo $inf
$info->fields['value'],
);
if ($option) {
echo "<td>" . $option['name'] . "</td><td>";
echo "<td>" . htmlescape(sprintf(__('%1$s - %2$s'), $info->fields['itemtype']::getTypeName(1), $option['name'])) . "</td><td>";
self::showAdditionalInformation($info, $option, $injectionClass, $values);
echo "</td>";
}
Expand All @@ -330,13 +350,8 @@ public static function showAdditionalInformation(
$values = []
) {

$name = "info[" . $option['linkfield'] . "]";

if (isset($_SESSION['datainjection']['infos'][$option['linkfield']])) {
$value = $_SESSION['datainjection']['infos'][$option['linkfield']];
} else {
$value = '';
}
$name = $info->getInputName();
$value = $info->getPostedValue($_SESSION['datainjection']['infos'] ?? []) ?? '';

switch ($option['displaytype']) {
case 'text':
Expand Down
9 changes: 4 additions & 5 deletions inc/infocominjection.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,12 @@ public function getOptions($primary_type = '')


/**
* @param array $info array
* @param array $option array
**/
public function showAdditionalInformation($info = [], $option = [])
* @param array $option array
**/
public function showAdditionalInformation(PluginDatainjectionInfo $info, $option = [])
{

$name = "info[" . $option['linkfield'] . "]";
$name = $info->getInputName();

switch ($option['displaytype']) {
case 'sink_type':
Expand Down
7 changes: 4 additions & 3 deletions inc/model.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -1214,11 +1214,12 @@ public function checkMandatoryFields($fields)
$item = new $itemtype();
$option = $item->getSearchOptionByField('field', $info->getValue());
$tocheck = (!isset($option['datatype']) || ($option['datatype'] != 'bool'));
$value = $info->getPostedValue($fields);
if (
!isset($fields[$info->getValue()])
$value === null
//Check if no value defined only when it's not a yes/no
|| ($tocheck && !$fields[$info->getValue()])
|| ($fields[$info->getValue()] == 'NULL')
|| ($tocheck && !$value)
|| ($value == 'NULL')
) {
$check = false;
break;
Expand Down
46 changes: 25 additions & 21 deletions inc/networkportinjection.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -301,22 +301,20 @@ public function lastCheck($values = [])
* @param array $values
* @param boolean $add (true by default)
* @param array|null $rights array
* @return bool|int|null true or null if ok, a PluginDatainjectionCommonInjectionLib log code if the connection failed
**/
public function processAfterInsertOrUpdate($values, $add = true, $rights = [])
{
/** @var DBmysql $DB */
global $DB;

//Should the port be connected to another one ?
$use_name = (isset($values['NetworkPort']["netname"])
|| !empty($values['NetworkPort']["netname"]));
$use_logical_number = (isset($values['NetworkPort']["netport"])
|| !empty($values['NetworkPort']["netport"]));
$use_mac = (isset($values['NetworkPort']["netmac"])
|| !empty($values['NetworkPort']["netmac"]));
//Should the port be connected to another one ? (an empty mapped cell is not a request)
$use_name = (string) ($values['NetworkPort']["netname"] ?? '') !== '';
$use_logical_number = (string) ($values['NetworkPort']["netport"] ?? '') !== '';
$use_mac = (string) ($values['NetworkPort']["netmac"] ?? '') !== '';

if (!$use_name && !$use_logical_number && !$use_mac) {
return false;
return true; // nothing to connect is not a failure
}

// Find port in database
Expand Down Expand Up @@ -351,21 +349,27 @@ public function processAfterInsertOrUpdate($values, $add = true, $rights = [])
'WHERE' => $criteria,
]);

//if at least one parameter is given
if (count($result) === 1) {
//Get data for this port
$netport = $result->current();
$netport_netport = new NetworkPort_NetworkPort();
//If this port already connected to another one ?
if (!$netport_netport->getOppositeContact((int) $netport['id'])) {
//No, add a new port to port connection
$tmp['networkports_id_1'] = $values['NetworkPort']['id'];
$tmp['networkports_id_2'] = $netport['id'];
$netport_netport->add($tmp);
}
if (count($result) === 0) {
return PluginDatainjectionCommonInjectionLib::WARNING_NETPORT_NOT_FOUND;
}

if (count($result) > 1) {
return PluginDatainjectionCommonInjectionLib::WARNING_NETPORT_AMBIGUOUS;
}

$netport = $result->current();
$netport_netport = new NetworkPort_NetworkPort();
$opposite = $netport_netport->getOppositeContact((int) $netport['id']);
if (!$opposite) {
//Not connected yet: add a new port to port connection
$tmp['networkports_id_1'] = $values['NetworkPort']['id'];
$tmp['networkports_id_2'] = $netport['id'];
$netport_netport->add($tmp);
} elseif ((int) $opposite !== (int) $values['NetworkPort']['id']) {
// Connected to another port; already connected to this one (re-import) is fine
return PluginDatainjectionCommonInjectionLib::WARNING_NETPORT_ALREADY_CONNECTED;
}

//TODO add injection warning if no port found or more than one
return null;
}
}
9 changes: 4 additions & 5 deletions inc/softwarelicenseinjection.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,12 @@ public function getOptions($primary_type = '')


/**
* @param array $info array
* @param array $option array
**/
public function showAdditionalInformation($info = [], $option = [])
* @param array $option array
**/
public function showAdditionalInformation(PluginDatainjectionInfo $info, $option = [])
{

$name = "info[" . $option['linkfield'] . "]";
$name = $info->getInputName();

switch ($option['displaytype']) {
case 'computer':
Expand Down
9 changes: 4 additions & 5 deletions inc/softwareversioninjection.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,12 @@ public function getOptions($primary_type = '')


/**
* @param array $info array
* @param array $option array
**/
public function showAdditionalInformation($info = [], $option = [])
* @param array $option array
**/
public function showAdditionalInformation(PluginDatainjectionInfo $info, $option = [])
{

$name = "info[" . $option['linkfield'] . "]";
$name = $info->getInputName();
switch ($option['displaytype']) {
case 'computer':
Computer::dropdown(
Expand Down
Loading
Loading