Merge remote-tracking branch 'refs/remotes/origin/support/3.1' into support/3.2

# Conflicts:
#	.make/composer/rmDeniedTestDir.php
#	application/utils.inc.php
This commit is contained in:
jf-cbd
2024-05-17 11:16:56 +02:00
4 changed files with 56 additions and 54 deletions

View File

@@ -27,7 +27,7 @@ $iTopFolder = __DIR__."/../../../";
require_once("$iTopFolder/approot.inc.php"); require_once("$iTopFolder/approot.inc.php");
require_once(APPROOT."/application/utils.inc.php"); require_once(APPROOT."/application/utils.inc.php");
if (php_sapi_name() !== 'cli') if (PHP_SAPI !== 'cli')
{ {
throw new \Exception('This script can only run from CLI'); throw new \Exception('This script can only run from CLI');
} }
@@ -48,4 +48,4 @@ if (!file_exists($sCssFile))
{ {
fwrite(STDERR, "Failed to compile $sCssFile, exiting."); fwrite(STDERR, "Failed to compile $sCssFile, exiting.");
exit(1); exit(1);
} }

View File

@@ -244,13 +244,8 @@ class utils
public static function IsModeCLI() public static function IsModeCLI()
{ {
$sSAPIName = php_sapi_name(); $sCleanName = strtolower(trim(PHP_SAPI));
$sCleanName = strtolower(trim($sSAPIName)); return ($sCleanName === 'cli');
if ($sCleanName == 'cli') {
return true;
} else {
return false;
}
} }
/** /**
@@ -373,13 +368,13 @@ class utils
} }
return self::Sanitize($retValue, $defaultValue, $sSanitizationFilter); return self::Sanitize($retValue, $defaultValue, $sSanitizationFilter);
} }
public static function ReadPostedParam($sName, $defaultValue = '', $sSanitizationFilter = 'parameter') public static function ReadPostedParam($sName, $defaultValue = '', $sSanitizationFilter = 'parameter')
{ {
$retValue = isset($_POST[$sName]) ? $_POST[$sName] : $defaultValue; $retValue = isset($_POST[$sName]) ? $_POST[$sName] : $defaultValue;
return self::Sanitize($retValue, $defaultValue, $sSanitizationFilter); return self::Sanitize($retValue, $defaultValue, $sSanitizationFilter);
} }
public static function Sanitize($value, $defaultValue, $sSanitizationFilter) public static function Sanitize($value, $defaultValue, $sSanitizationFilter)
{ {
if ($value === $defaultValue) if ($value === $defaultValue)
@@ -395,7 +390,7 @@ class utils
$retValue = $defaultValue; $retValue = $defaultValue;
} }
} }
return $retValue; return $retValue;
} }
/** /**
@@ -551,11 +546,11 @@ class utils
$sMimeType = self::GetFileMimeType($sTmpName); $sMimeType = self::GetFileMimeType($sTmpName);
$oDocument = new ormDocument($doc_content, $sMimeType, $sName); $oDocument = new ormDocument($doc_content, $sMimeType, $sName);
break; break;
case UPLOAD_ERR_NO_FILE: case UPLOAD_ERR_NO_FILE:
// no file to load, it's a normal case, just return an empty document // no file to load, it's a normal case, just return an empty document
break; break;
case UPLOAD_ERR_FORM_SIZE: case UPLOAD_ERR_FORM_SIZE:
case UPLOAD_ERR_INI_SIZE: case UPLOAD_ERR_INI_SIZE:
throw new FileUploadException(Dict::Format('UI:Error:UploadedFileTooBig', ini_get('upload_max_filesize'))); throw new FileUploadException(Dict::Format('UI:Error:UploadedFileTooBig', ini_get('upload_max_filesize')));
@@ -564,7 +559,7 @@ class utils
case UPLOAD_ERR_PARTIAL: case UPLOAD_ERR_PARTIAL:
throw new FileUploadException(Dict::S('UI:Error:UploadedFileTruncated.')); throw new FileUploadException(Dict::S('UI:Error:UploadedFileTruncated.'));
break; break;
case UPLOAD_ERR_NO_TMP_DIR: case UPLOAD_ERR_NO_TMP_DIR:
throw new FileUploadException(Dict::S('UI:Error:NoTmpDir')); throw new FileUploadException(Dict::S('UI:Error:NoTmpDir'));
break; break;
@@ -577,7 +572,7 @@ class utils
$sName = is_null($sIndex) ? $aFileInfo['name'] : $aFileInfo['name'][$sIndex]; $sName = is_null($sIndex) ? $aFileInfo['name'] : $aFileInfo['name'][$sIndex];
throw new FileUploadException(Dict::Format('UI:Error:UploadStoppedByExtension_FileName', $sName)); throw new FileUploadException(Dict::Format('UI:Error:UploadStoppedByExtension_FileName', $sName));
break; break;
default: default:
throw new FileUploadException(Dict::Format('UI:Error:UploadFailedUnknownCause_Code', $sError)); throw new FileUploadException(Dict::Format('UI:Error:UploadFailedUnknownCause_Code', $sError));
break; break;
@@ -683,17 +678,17 @@ class utils
return $aSelectedObj; return $aSelectedObj;
} }
public static function GetNewTransactionId() public static function GetNewTransactionId()
{ {
return privUITransaction::GetNewTransactionId(); return privUITransaction::GetNewTransactionId();
} }
public static function IsTransactionValid($sId, $bRemoveTransaction = true) public static function IsTransactionValid($sId, $bRemoveTransaction = true)
{ {
return privUITransaction::IsTransactionValid($sId, $bRemoveTransaction); return privUITransaction::IsTransactionValid($sId, $bRemoveTransaction);
} }
public static function RemoveTransaction($sId) public static function RemoveTransaction($sId)
{ {
return privUITransaction::RemoveTransaction($sId); return privUITransaction::RemoveTransaction($sId);
@@ -877,9 +872,9 @@ class utils
$aDateTokens = array_keys($aSpec); $aDateTokens = array_keys($aSpec);
$aDateRegexps = array_values($aSpec); $aDateRegexps = array_values($aSpec);
} }
$sDateRegexp = str_replace($aDateTokens, $aDateRegexps, $sFormat); $sDateRegexp = str_replace($aDateTokens, $aDateRegexps, $sFormat);
if (preg_match('!^(?<head>)'.$sDateRegexp.'(?<tail>)$!', $sDate, $aMatches)) if (preg_match('!^(?<head>)'.$sDateRegexp.'(?<tail>)$!', $sDate, $aMatches))
{ {
$sYear = isset($aMatches['year']) ? $aMatches['year'] : 0; $sYear = isset($aMatches['year']) ? $aMatches['year'] : 0;
@@ -896,7 +891,7 @@ class utils
} }
// http://www.spaweditor.com/scripts/regex/index.php // http://www.spaweditor.com/scripts/regex/index.php
} }
/** /**
* Convert an old date/time format specification (using % placeholders) * Convert an old date/time format specification (using % placeholders)
* to a format compatible with DateTime::createFromFormat * to a format compatible with DateTime::createFromFormat
@@ -1492,7 +1487,7 @@ class utils
$aResult = []; $aResult = [];
// 1st - add standard built-in menu items // 1st - add standard built-in menu items
// //
switch($iMenuId) switch($iMenuId)
{ {
case iPopupMenuExtension::MENU_OBJLIST_ACTIONS: case iPopupMenuExtension::MENU_OBJLIST_ACTIONS:
@@ -1876,7 +1871,7 @@ SQL;
return $sProposed; return $sProposed;
} }
} }
/** /**
* Some characters cause troubles with jQuery when used inside DOM IDs, so let's replace them by the safe _ (underscore) * Some characters cause troubles with jQuery when used inside DOM IDs, so let's replace them by the safe _ (underscore)
* @param string $sId The ID to sanitize * @param string $sId The ID to sanitize
@@ -1886,7 +1881,7 @@ SQL;
{ {
return str_replace(array(':', '[', ']', '+', '-', ' '), '_', $sId); return str_replace(array(':', '[', ']', '+', '-', ' '), '_', $sId);
} }
/** /**
* Helper to execute an HTTP POST request, uses CURL PHP extension * Helper to execute an HTTP POST request, uses CURL PHP extension
* *
@@ -1971,7 +1966,7 @@ SQL;
/** /**
* Get a standard list of character sets * Get a standard list of character sets
* *
* @param array $aAdditionalEncodings Additional values * @param array $aAdditionalEncodings Additional values
* @return array of iconv code => english label, sorted by label * @return array of iconv code => english label, sorted by label
*/ */
@@ -2078,7 +2073,7 @@ SQL;
return $e->getMessage(); return $e->getMessage();
} }
} }
/** /**
* Convert (?) plain text to some HTML markup by replacing newlines by <br/> tags * Convert (?) plain text to some HTML markup by replacing newlines by <br/> tags
* and escaping HTML entities * and escaping HTML entities
@@ -2095,7 +2090,7 @@ SQL;
return str_replace("\n", '<br/>', utils::EscapeHtml($sText)); return str_replace("\n", '<br/>', utils::EscapeHtml($sText));
} }
/** /**
* Eventually compiles the SASS (.scss) file into the CSS (.css) file * Eventually compiles the SASS (.scss) file into the CSS (.css) file
* *
@@ -2209,7 +2204,7 @@ SQL;
case 'image/png': case 'image/png':
$img = @imagecreatefromstring($oImage->GetData()); $img = @imagecreatefromstring($oImage->GetData());
break; break;
default: default:
// Unsupported image type, return the image as-is // Unsupported image type, return the image as-is
//throw new Exception("Unsupported image type: '".$oImage->GetMimeType()."'. Cannot resize the image, original image will be used."); //throw new Exception("Unsupported image type: '".$oImage->GetMimeType()."'. Cannot resize the image, original image will be used.");
@@ -2223,14 +2218,14 @@ SQL;
else else
{ {
// Let's scale the image, preserving the transparency for GIFs and PNGs // Let's scale the image, preserving the transparency for GIFs and PNGs
$fScale = min($iMaxImageWidth / $iWidth, $iMaxImageHeight / $iHeight); $fScale = min($iMaxImageWidth / $iWidth, $iMaxImageHeight / $iHeight);
$iNewWidth = floor($iWidth * $fScale); $iNewWidth = $iWidth * $fScale;
$iNewHeight = floor($iHeight * $fScale); $iNewHeight = $iHeight * $fScale;
$new = imagecreatetruecolor($iNewWidth, $iNewHeight); $new = imagecreatetruecolor($iNewWidth, $iNewHeight);
// Preserve transparency // Preserve transparency
if(($oImage->GetMimeType() == "image/gif") || ($oImage->GetMimeType() == "image/png")) if(($oImage->GetMimeType() == "image/gif") || ($oImage->GetMimeType() == "image/png"))
{ {
@@ -2238,38 +2233,38 @@ SQL;
imagealphablending($new, false); imagealphablending($new, false);
imagesavealpha($new, true); imagesavealpha($new, true);
} }
imagecopyresampled($new, $img, 0, 0, 0, 0, $iNewWidth, $iNewHeight, $iWidth, $iHeight); imagecopyresampled($new, $img, 0, 0, 0, 0, $iNewWidth, $iNewHeight, $iWidth, $iHeight);
ob_start(); ob_start();
switch ($oImage->GetMimeType()) switch ($oImage->GetMimeType())
{ {
case 'image/gif': case 'image/gif':
imagegif($new); // send image to output buffer imagegif($new); // send image to output buffer
break; break;
case 'image/jpeg': case 'image/jpeg':
imagejpeg($new, null, 80); // null = send image to output buffer, 80 = good quality imagejpeg($new, null, 80); // null = send image to output buffer, 80 = good quality
break; break;
case 'image/png': case 'image/png':
imagepng($new, null, 5); // null = send image to output buffer, 5 = medium compression imagepng($new, null, 5); // null = send image to output buffer, 5 = medium compression
break; break;
} }
$oResampledImage = new ormDocument(ob_get_contents(), $oImage->GetMimeType(), $oImage->GetFileName()); $oResampledImage = new ormDocument(ob_get_contents(), $oImage->GetMimeType(), $oImage->GetFileName());
@ob_end_clean(); @ob_end_clean();
imagedestroy($img); imagedestroy($img);
imagedestroy($new); imagedestroy($new);
return $oResampledImage; return $oResampledImage;
} }
} }
/** /**
* Create a 128 bit UUID in the format: {########-####-####-####-############} * Create a 128 bit UUID in the format: {########-####-####-####-############}
* *
* Note: this method can be run from the command line as well as from the web server. * Note: this method can be run from the command line as well as from the web server.
* Note2: this method is not cryptographically secure! If you need a cryptographically secure value * Note2: this method is not cryptographically secure! If you need a cryptographically secure value
* consider using open_ssl or PHP 7 methods. * consider using open_ssl or PHP 7 methods.
@@ -2307,7 +2302,7 @@ SQL;
{ {
return ModuleService::GetInstance()->GetCurrentModuleName($iCallDepth + 1); return ModuleService::GetInstance()->GetCurrentModuleName($iCallDepth + 1);
} }
/** /**
* **Warning** : returned result can be invalid as we're using backtrace to find the module dir name * **Warning** : returned result can be invalid as we're using backtrace to find the module dir name
* *
@@ -2344,7 +2339,7 @@ SQL;
{ {
return ModuleService::GetInstance()->GetCurrentModuleUrl(1); return ModuleService::GetInstance()->GetCurrentModuleUrl(1);
} }
/** /**
* @param string $sProperty The name of the property to retrieve * @param string $sProperty The name of the property to retrieve
* @param mixed $defaultvalue * @param mixed $defaultvalue
@@ -2354,7 +2349,7 @@ SQL;
{ {
return ModuleService::GetInstance()->GetCurrentModuleSetting($sProperty, $defaultvalue); return ModuleService::GetInstance()->GetCurrentModuleSetting($sProperty, $defaultvalue);
} }
/** /**
* @param string $sModuleName * @param string $sModuleName
* @return string|NULL compiled version of a given module, as it was seen by the compiler * @return string|NULL compiled version of a given module, as it was seen by the compiler
@@ -2363,7 +2358,7 @@ SQL;
{ {
return ModuleService::GetInstance()->GetCompiledModuleVersion($sModuleName); return ModuleService::GetInstance()->GetCompiledModuleVersion($sModuleName);
} }
/** /**
* Check if the given path/url is an http(s) URL * Check if the given path/url is an http(s) URL
* @param string $sPath * @param string $sPath
@@ -2378,7 +2373,7 @@ SQL;
} }
return $bRet; return $bRet;
} }
/** /**
* Check if the given URL is a link to download a document/image on the CURRENT iTop * Check if the given URL is a link to download a document/image on the CURRENT iTop
* In such a case we can read the content of the file directly in the database (if the users rights allow) and return the ormDocument * In such a case we can read the content of the file directly in the database (if the users rights allow) and return the ormDocument
@@ -2427,7 +2422,7 @@ SQL;
} }
return $result; return $result;
} }
/** /**
* Read the content of a file (and retrieve its MIME type) from either: * Read the content of a file (and retrieve its MIME type) from either:
* - an URL pointing to a blob (image/document) on the current iTop server * - an URL pointing to a blob (image/document) on the current iTop server
@@ -2471,7 +2466,7 @@ SQL;
'html' => 'text/html', 'html' => 'text/html',
'exe' => 'application/octet-stream', 'exe' => 'application/octet-stream',
); );
$sData = null; $sData = null;
$sMimeType = 'text/plain'; // Default MIME Type: treat the file as a bunch a characters... $sMimeType = 'text/plain'; // Default MIME Type: treat the file as a bunch a characters...
$sFileName = 'uploaded-file'; // Default name for downloaded-files $sFileName = 'uploaded-file'; // Default name for downloaded-files
@@ -2529,7 +2524,7 @@ SQL;
} }
$sExtension = strtolower(pathinfo($sPath, PATHINFO_EXTENSION)); $sExtension = strtolower(pathinfo($sPath, PATHINFO_EXTENSION));
$sFileName = basename($sPath); $sFileName = basename($sPath);
if (array_key_exists($sExtension, $aKnownExtensions)) if (array_key_exists($sExtension, $aKnownExtensions))
{ {
$sMimeType = $aKnownExtensions[$sExtension]; $sMimeType = $aKnownExtensions[$sExtension];
@@ -2543,7 +2538,7 @@ SQL;
} }
return $oUploadedDoc; return $oUploadedDoc;
} }
protected static function ParseHeaders($aHeaders) protected static function ParseHeaders($aHeaders)
{ {
$aCleanHeaders = array(); $aCleanHeaders = array();
@@ -2568,7 +2563,7 @@ SQL;
} }
return $aCleanHeaders; return $aCleanHeaders;
} }
/** /**
* @return string a string based on compilation time or (if not available because the datamodel has not been loaded) * @return string a string based on compilation time or (if not available because the datamodel has not been loaded)
* the version of iTop. This string is useful to prevent browser side caching of content that may vary at each * the version of iTop. This string is useful to prevent browser side caching of content that may vary at each

View File

@@ -68,7 +68,7 @@ if (file_exists(MAINTENANCE_MODE_FILE) && !$bBypassMaintenance)
http_response_code(503); http_response_code(503);
// Display message depending on the request // Display message depending on the request
include(APPROOT.'application/maintenancemsg.php'); include(APPROOT.'application/maintenancemsg.php');
$sSAPIName = strtoupper(trim(php_sapi_name())); $sSAPIName = strtoupper(trim(PHP_SAPI));
switch (true) switch (true)
{ {

View File

@@ -4,6 +4,7 @@
{# SET WIDGET #} {# SET WIDGET #}
{% set oDataProvider = oUIBlock.GetDataProvider() %} {% set oDataProvider = oUIBlock.GetDataProvider() %}
let optionsBeforeFilter;
let oWidget{{ oUIBlock.GetId() }} = $('#{{ oUIBlock.GetId() }}').selectize({ let oWidget{{ oUIBlock.GetId() }} = $('#{{ oUIBlock.GetId() }}').selectize({
{# Global options #} {# Global options #}
@@ -117,6 +118,7 @@ let oWidget{{ oUIBlock.GetId() }} = $('#{{ oUIBlock.GetId() }}').selectize({
// Filter old options data to keep selected values // Filter old options data to keep selected values
// (options with force flag will be kept event if they doesn't be part of the current value) // (options with force flag will be kept event if they doesn't be part of the current value)
let options = Object.values(me.options); let options = Object.values(me.options);
optionsBeforeFilter = options;
options = options.filter(item => (typeof(item.force) !== "undefined" && item.force === true) || aSelectedItems.includes(item['{{ oDataProvider.GetDataValueField() }}'])); options = options.filter(item => (typeof(item.force) !== "undefined" && item.force === true) || aSelectedItems.includes(item['{{ oDataProvider.GetDataValueField() }}']));
// Merge kept and new values // Merge kept and new values
options = $.merge(options, res.data.search_data); options = $.merge(options, res.data.search_data);
@@ -235,6 +237,11 @@ let oWidget{{ oUIBlock.GetId() }} = $('#{{ oUIBlock.GetId() }}').selectize({
{% endif %} {% endif %}
}, },
onBlur: function(){
this.clearOptionGroups()
this.addOption(optionsBeforeFilter)
},
{# plugin combodo_add_button #} {# plugin combodo_add_button #}
{% if oUIBlock.HasAddOptionButton() and oUIBlock.HasAddOptionButtonJsOnClick() %} {% if oUIBlock.HasAddOptionButton() and oUIBlock.HasAddOptionButtonJsOnClick() %}
onAdd: function(){ onAdd: function(){