Merge branch 'saas/3.0' into develop

This commit is contained in:
odain
2022-09-20 16:04:55 +02:00
26 changed files with 1186 additions and 344 deletions

View File

@@ -138,7 +138,7 @@ try {
}
return $aResult;
}
/**
* Return the most frequent (and regularly occuring) character among the given set, in the specified lines
* @param array $aCSVData The input data, one entry per line
@@ -174,7 +174,7 @@ try {
}
$iLine++;
}
$aScores = array();
foreach($aGuesses as $sSep => $aData)
{
@@ -185,7 +185,7 @@ try {
$sSeparator = $aKeys[0]; // Take the first key, the one with the best score
return $sSeparator;
}
/**
* Try to predict the CSV parameters based on the input data
* @param string $sCSVData The input data
@@ -196,10 +196,10 @@ try {
$aData = explode("\n", $sCSVData);
$sSeparator = GuessFromFrequency($aData, array("\t", ',', ';', '|')); // Guess the most frequent (and regular) character on each line
$sQualifier = GuessFromFrequency($aData, array('"', "'")); // Guess the most frequent (and regular) character on each line
return array('separator' => $sSeparator, 'qualifier' => $sQualifier);
}
/**
* Display a banner for the special "synchro" mode
* @param WebPage $oP The Page for the output
@@ -215,6 +215,7 @@ try {
* Add a paragraph to the body of the page
*
* @param string $s_html
* @param ?string $sLinkUrl
*
* @return string
*/
@@ -259,9 +260,9 @@ try {
$sSynchroScope = utils::ReadParam('synchro_scope', '', false, 'raw_data');
$sDateTimeFormat = utils::ReadParam('date_time_format', 'default');
$sCustomDateTimeFormat = utils::ReadParam('custom_date_time_format', (string)AttributeDateTime::GetFormat(), false, 'raw_data');
$sChosenDateFormat = ($sDateTimeFormat == 'default') ? (string)AttributeDateTime::GetFormat() : $sCustomDateTimeFormat;
if (!empty($sSynchroScope))
{
$oSearch = DBObjectSearch::FromOQL($sSynchroScope);
@@ -276,7 +277,7 @@ try {
$sSynchroScope = '';
$aSynchroUpdate = null;
}
// Parse the data set
$oCSVParser = new CSVParser($sCSVData, $sSeparator, $sTextQualifier, MetaModel::GetConfig()->Get('max_execution_time_per_loop'));
$aData = $oCSVParser->ToArray($iSkippedLines);
@@ -286,10 +287,10 @@ try {
$aResult[] = $sTextQualifier.implode($sTextQualifier.$sSeparator.$sTextQualifier, array_shift($aData)).$sTextQualifier; // Remove the first line and store it in case of error
$iRealSkippedLines++;
}
// Format for the line numbers
$sMaxLen = (strlen(''.count($aData)) < 3) ? 3 : strlen(''.count($aData)); // Pad line numbers to the appropriate number of chars, but at least 3
// Compute the list of search/reconciliation criteria
$aSearchKeys = array();
foreach($aSearchFields as $index => $sDummy)
@@ -303,16 +304,16 @@ try {
}
else
{
$aSearchKeys[$sSearchField] = '';
$aSearchKeys[$sSearchField] = '';
}
if (!MetaModel::IsValidFilterCode($sClassName, $sSearchField))
{
// Remove invalid or unmapped search fields
$aSearchFields[$index] = null;
unset($aSearchKeys[$sSearchField]);
unset($aSearchKeys[$sSearchField]);
}
}
// Compute the list of fields and external keys to process
$aExtKeys = array();
$aAttributes = array();
@@ -345,13 +346,13 @@ try {
}
else
{
$aAttributes[$sAttCode] = $iIndex;
$aAttributes[$sAttCode] = $iIndex;
}
}
}
}
}
}
$oMyChange = null;
if (!$bSimulate)
{
@@ -360,7 +361,7 @@ try {
CMDBObject::SetCurrentChangeFromParams($sUserString, CMDBChangeOrigin::CSV_INTERACTIVE);
$oMyChange = CMDBObject::GetCurrentChange();
}
$oBulk = new BulkChange(
$sClassName,
$aData,
@@ -370,7 +371,7 @@ try {
empty($sSynchroScope) ? null : $sSynchroScope,
$aSynchroUpdate,
$sChosenDateFormat, // date format
true // localize
true // localize
);
$oBulk->SetReportHtml();
@@ -437,7 +438,6 @@ try {
case 'RowStatus_NewObj':
$iCreated++;
$sFinalClass = $aResRow['finalclass'];
$sStatus = '<img src="../images/added.png" title="'.Dict::S('UI:CSVReport-Icon-Created').'">';
$sCSSRowClass = 'ibo-csv-import--row-added';
if ($bSimulate) {
@@ -453,7 +453,7 @@ try {
case 'RowStatus_Issue':
$iErrors++;
$sMessage .= GetDivAlert($oStatus->GetDescription());
$sStatus = '<img src="../images/error.png" title="'.Dict::S('UI:CSVReport-Icon-Error').'">';//translate
$sStatus = '<div class="ibo-csv-import--cell-error"><i class="fas fa-exclamation-triangle" title="'.Dict::S('UI:CSVReport-Icon-Error').'" /></div>';//translate
$sCSSMessageClass = 'ibo-csv-import--cell-error';
$sCSSRowClass = 'ibo-csv-import--row-error';
if (array_key_exists($iLine, $aData)) {
@@ -474,33 +474,36 @@ try {
if (isset($aExternalKeysByColumn[$iNumber - 1])) {
$sExtKeyName = $aExternalKeysByColumn[$iNumber - 1];
$oExtKeyCellStatus = $aResRow[$sExtKeyName];
switch (get_class($oExtKeyCellStatus)) {
case 'CellStatus_Issue':
case 'CellStatus_SearchIssue':
case 'CellStatus_NullIssue':
case 'CellStatus_Ambiguous':
$sCellMessage .= GetDivAlert($oExtKeyCellStatus->GetDescription());
break;
default:
// Do nothing
}
$oCellStatus = $oExtKeyCellStatus;
}
$sHtmlValue = $oCellStatus->GetDisplayableValue();
switch (get_class($oCellStatus)) {
case 'CellStatus_Issue':
case 'CellStatus_NullIssue':
$sCellMessage .= GetDivAlert($oCellStatus->GetDescription());
$aTableRow[$sClassName.'/'.$sAttCode] = '<div class="ibo-csv-import--cell-error">'.Dict::Format('UI:CSVReport-Object-Error', $sHtmlValue).$sCellMessage.'</div>';
break;
case 'CellStatus_SearchIssue':
$sCellMessage .= GetDivAlert($oCellStatus->GetDescription());
$aTableRow[$sClassName.'/'.$sAttCode] = '<div class="ibo-csv-import--cell-error">ERROR: '.$sHtmlValue.$sCellMessage.'</div>';
$aTableRow[$sClassName.'/'.$sAttCode] = sprintf("%s%s%s%s%s%s",
'<a href="',
$oCellStatus->GetSearchLinkUrl(),
'"><div class="ibo-csv-import--cell-error">',
Dict::Format('UI:CSVReport-Object-Error', $sHtmlValue),
GetDivAlert($oCellStatus->GetDescription()),
'<i class="fas fa-search"></i></div><a/>'
);
break;
case 'CellStatus_Ambiguous':
$sCellMessage .= GetDivAlert($oCellStatus->GetDescription());
$aTableRow[$sClassName.'/'.$sAttCode] = '<div class="ibo-csv-import--cell-error" >'.Dict::Format('UI:CSVReport-Object-Ambiguous', $sHtmlValue).$sCellMessage.'</div>';
$aTableRow[$sClassName.'/'.$sAttCode] = sprintf("%s%s%s%s%s%s",
'<a href="',
$oCellStatus->GetSearchLinkUrl(),
'"><i class="fas fa-search"/><div class="ibo-csv-import--cell-error">',
Dict::Format('UI:CSVReport-Object-Ambiguous', $sHtmlValue),
GetDivAlert($oCellStatus->GetDescription()),
'<i class="fas fa-search"></i></div><a/>'
);
break;
case 'CellStatus_Modify':
@@ -589,7 +592,7 @@ try {
$oMulticolumn->AddColumn(ColumnUIBlockFactory::MakeForBlock($oCheckBoxUnchanged));
$oPage->add_ready_script("$('#show_created').on('click', function(){ToggleRows('ibo-csv-import--row-added')})");
$oCheckBoxUnchanged = InputUIBlockFactory::MakeForInputWithLabel('<img src="../images/error.png">&nbsp;'.sprintf($aDisplayFilters['errors'], $iErrors), '', "1", "show_errors", "checkbox");
$oCheckBoxUnchanged = InputUIBlockFactory::MakeForInputWithLabel('<i class="fas fa-exclamation-triangle" style="color:#A33; background-color: #FFF0F0;">&nbsp;'.sprintf($aDisplayFilters['errors'], $iErrors).'</i></i>', '', "1", "show_errors", "checkbox");
$oCheckBoxUnchanged->GetInput()->SetIsChecked(true);
$oCheckBoxUnchanged->SetBeforeInput(false);
$oCheckBoxUnchanged->GetInput()->AddCSSClass('ibo-input-checkbox');
@@ -676,7 +679,7 @@ try {
EOF
);
}
$sErrors = json_encode(Dict::Format('UI:CSVImportError_items', $iErrors));
$sCreated = json_encode(Dict::Format('UI:CSVImportCreated_items', $iCreated));
$sModified = json_encode(Dict::Format('UI:CSVImportModified_items', $iModified));
@@ -771,7 +774,7 @@ EOF
{
return null;
}
}
/**
* Perform the actual load of the CSV data and display the results
@@ -795,7 +798,7 @@ EOF
$oField->AddSubBlock($oText);
}
}
/**
* Simulate the load of the CSV data and display the results
* @param WebPage $oPage The web page to display the wizard
@@ -807,7 +810,7 @@ EOF
$oPage->AddSubBlock($oPanel);
ProcessCSVData($oPage, true /* simulate */);
}
/**
* Select the mapping between the CSV column and the fields of the objects
* @param WebPage $oPage The web page to display the wizard
@@ -920,10 +923,10 @@ EOF
$aSearchFields = utils::ReadParam('search_field', array(), false, 'field_name');
$sFieldsMapping = addslashes(json_encode($aFieldsMapping));
$sSearchFields = addslashes(json_encode($aSearchFields));
$oPage->add_ready_script("DoMapping('$sFieldsMapping', '$sSearchFields');"); // There is already a class selected, run the mapping
}
$oPage->add_script(
<<<EOF
var aDefaultKeys = new Array();
@@ -1139,7 +1142,7 @@ EOF
EOF
);
}
/**
* Select the options of the CSV load and check for CSV parsing errors
* @param WebPage $oPage The current web page
@@ -1163,7 +1166,7 @@ EOF
$sCSVData = utils::ReadPostedParam('csvdata', '', 'raw_data');
}
$sEncoding = utils::ReadParam('encoding', 'UTF-8');
// Compute a subset of the data set, now that we know the charset
if ($sEncoding == 'UTF-8')
{
@@ -1180,7 +1183,7 @@ EOF
{
$sUTF8Data = iconv($sEncoding, 'UTF-8//IGNORE//TRANSLIT', $sCSVData);
}
$aGuesses = GuessParameters($sUTF8Data); // Try to predict the parameters, based on the input data
$iSkippedLines = utils::ReadParam('nb_skipped_lines', '');
@@ -1188,7 +1191,7 @@ EOF
$sTextQualifier = utils::ReadParam('text_qualifier', '', false, 'raw_data');
if ($sTextQualifier == '') // May be set to an empty value by the previous page
{
$sTextQualifier = $aGuesses['qualifier'];
$sTextQualifier = $aGuesses['qualifier'];
}
$sOtherTextQualifier = in_array($sTextQualifier, array('"', "'")) ? '' : $sTextQualifier;
$bHeaderLine = utils::ReadParam('header_line', 0);
@@ -1606,7 +1609,7 @@ EOF
null, AjaxTab::ENUM_TAB_PLACEHOLDER_MISC);
}
}
switch($iStep)
{
case 11:
@@ -1614,45 +1617,45 @@ EOF
$oPage = new AjaxPage('');
BulkChange::DisplayImportHistory($oPage);
$oPage->add_ready_script('$("#CSVImportHistory table.listResults").tableHover();');
$oPage->add_ready_script('$("#CSVImportHistory table.listResults").tablesorter( { widgets: ["myZebra", "truncatedList"]} );');
$oPage->add_ready_script('$("#CSVImportHistory table.listResults").tablesorter( { widgets: ["myZebra", "truncatedList"]} );');
break;
case 10:
// Case generated by BulkChange::DisplayImportHistory
$iChange = (int)utils::ReadParam('changeid', 0);
BulkChange::DisplayImportHistoryDetails($oPage, $iChange);
break;
case 5:
LoadData($oPage);
break;
case 4:
Preview($oPage);
break;
case 3:
SelectMapping($oPage);
break;
case 2:
SelectOptions($oPage);
break;
case 1:
case 6: // Loop back here when we are done
default:
Welcome($oPage);
}
$oPage->output();
}
catch(CoreException $e)
{
require_once(APPROOT.'/setup/setuppage.class.inc.php');
$oP = new ErrorPage(Dict::S('UI:PageTitle:FatalError'));
$oP->add("<h1>".Dict::S('UI:FatalErrorMessage')."</h1>\n");
$oP->error(Dict::Format('UI:Error_Details', $e->getHtmlDesc()));
$oP->add("<h1>".Dict::S('UI:FatalErrorMessage')."</h1>\n");
$oP->error(Dict::Format('UI:Error_Details', $e->getHtmlDesc()));
$oP->output();
if (MetaModel::IsLogEnabledIssue())
@@ -1680,8 +1683,8 @@ catch(Exception $e)
{
require_once(APPROOT.'/setup/setuppage.class.inc.php');
$oP = new ErrorPage(Dict::S('UI:PageTitle:FatalError'));
$oP->add("<h1>".Dict::S('UI:FatalErrorMessage')."</h1>\n");
$oP->error(Dict::Format('UI:Error_Details', $e->getMessage()));
$oP->add("<h1>".Dict::S('UI:FatalErrorMessage')."</h1>\n");
$oP->error(Dict::Format('UI:Error_Details', $e->getMessage()));
$oP->output();
if (MetaModel::IsLogEnabledIssue())
@@ -1701,4 +1704,4 @@ catch(Exception $e)
IssueLog::Error($e->getMessage());
}
}
}