Compare commits

..

1 Commits

Author SHA1 Message Date
Timothee
0cac103e7d N°7383 Show data table even when there is no data after filtering 2024-12-27 18:06:07 +01:00
1174 changed files with 80633 additions and 113195 deletions

View File

@@ -93,12 +93,6 @@ gitGraph
checkout support/3.2
commit id: "2024-06-25" tag: "3.2.0-beta1" type: REVERSE
commit id: "2024-08-07" tag: "3.2.0"
checkout support/2.7
commit id: "2025-02-25" tag: "2.7.12"
checkout support/3.1
commit id: "2025-02-25 " tag: "3.1.3"
checkout support/3.2
commit id: "2025-02-25 " tag: "3.2.1"
```
To learn more, check the [iTop community versions history on the official wiki](https://www.itophub.io/wiki/page?id=latest:release:start).

View File

@@ -1,9 +1,5 @@
<p align="center"><a href="https://www.combodo.com/itop-193" target="_blank">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="/images/logos/logo-itop-baseline-light.svg">
<source media="(prefers-color-scheme: light)" srcset="/images/logos/logo-itop-baseline-dark.svg">
<img src="/images/logos/logo-itop-baseline-light.svg" width="350" alt="Logo iTop with baseline" />
</picture>
<img src="https://www.combodo.com/logos/logo-itop-baseline.svg" width=350>
</a></p>
@@ -110,7 +106,6 @@ We would like to give a special thank you 🤗 to the people from the community
- Raenker, Martin
- Roháč, Richard (a.k.a [@RohacRichard](https://github.com/RohacRichard))
- Rosenke, Stephan
- Rossi, Tommaso (a.k.a [@tomrss](https://www.github.com/tomrss))
- Rudner, Björn (a.k.a [@rudnerbjoern](https://github.com/rudnerbjoern))
- Šafránek, Jaroslav (a.k.a [jkcinik](https://sourceforge.net/u/jkcinik/profile/) on SourceForge)
- Seki, Shoji
@@ -120,7 +115,6 @@ We would like to give a special thank you 🤗 to the people from the community
- Tarjányi, Csaba (a.k.a [@tacsaby](https://github.com/tacsaby))
- Tulio, Marco
- Turrubiates, Miguel
- Vlk, Karel (a.k.a [@vlk-charles](https://www.github.com/vlk-charles))
### Aliases

View File

@@ -195,31 +195,16 @@ class ApplicationContext
/**
* Returns the context as string with the format name1=value1&name2=value2....
* @return string The context as a string to be appended to an href property
*
*/
public function GetForLink(bool $bWithLeadingAmpersand = false)
public function GetForLink()
{
// If there are no parameters, return an empty string
if(empty($this->aValues)){
return '';
}
// Build the query string with ampersand separated parameters
$aParams = array();
foreach($this->aValues as $sName => $sValue)
{
$aParams[] = "c[$sName]".'='.urlencode($sValue);
}
$sReturnValue = implode('&', $aParams);
// add the leading ampersand if requested
if($bWithLeadingAmpersand){
$sReturnValue = '&' . $sReturnValue;
}
return $sReturnValue;
return implode("&", $aParams);
}
/**
* @since 3.0.0 N°2534 - dashboard: bug with autorefresh that deactivates filtering on organisation
* Returns the params as c[menu]:..., c[org_id]:....
@@ -397,7 +382,7 @@ class ApplicationContext
$sUrl = call_user_func(array($sUrlMakerClass, 'MakeObjectUrl'), $sObjClass, $sObjKey);
if (utils::StrLen($sUrl) > 0) {
if ($bWithNavigationContext) {
return $sUrl.$oAppContext->GetForLink(true);
return $sUrl."&".$oAppContext->GetForLink();
} else {
return $sUrl;
}

View File

@@ -1711,11 +1711,6 @@ interface iRestServiceProvider
public function ExecOperation($sVersion, $sVerb, $aParams);
}
interface iRestInputSanitizer
{
public function SanitizeJsonInput(string $sJsonInput): string;
}
/**
* Minimal REST response structure. Derive this structure to add response data and error codes.
*
@@ -1807,14 +1802,6 @@ class RestResult
* @api
*/
public $message;
/**
* Sanitize the content of this result to hide sensitive information
*/
public function SanitizeContent()
{
// The default implementation does nothing
}
}
/**

View File

@@ -311,7 +311,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
{
$sParams .= $sName.'='.urlencode($value).'&'; // Always add a trailing &
}
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/'.$oObj->GetUIPage().'?'.$sParams.'class='.get_class($oObj).'&id='.$oObj->getKey().$oAppContext->GetForLink(true).'&a=1';
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/'.$oObj->GetUIPage().'?'.$sParams.'class='.get_class($oObj).'&id='.$oObj->getKey().'&'.$oAppContext->GetForLink().'&a=1';
$oPage->add_early_script(<<<JS
if (!sessionStorage.getItem('$sSessionStorageKey'))
{
@@ -1113,10 +1113,8 @@ HTML
}
// Note: DisplayBareHeader is called before adding $oObjectDetails to the page, so it can inject HTML before it through $oPage.
/** @var \iTopWebPage $oPage */
$oKPI = new ExecutionKPI();
/** @var iTopWebPage $oPage */
$aHeadersBlocks = $this->DisplayBareHeader($oPage, $bEditMode);
$oKPI->ComputeStatsForExtension($this, 'DisplayBareHeader');
if (false === empty($aHeadersBlocks['subtitle'])) {
$oObjectDetails->AddSubTitleBlocks($aHeadersBlocks['subtitle']);
}
@@ -1129,12 +1127,8 @@ HTML
$oPage->AddTabContainer(OBJECT_PROPERTIES_TAB, '', $oObjectDetails);
$oPage->SetCurrentTabContainer(OBJECT_PROPERTIES_TAB);
$oPage->SetCurrentTab('UI:PropertiesTab');
$oKPI = new ExecutionKPI();
$this->DisplayBareProperties($oPage, $bEditMode);
$oKPI->ComputeStatsForExtension($this, 'DisplayBareProperties');
$oKPI = new ExecutionKPI();
$this->DisplayBareRelations($oPage, $bEditMode);
$oKPI->ComputeStatsForExtension($this, 'DisplayBareRelations');
// Note: Adding the JS snippet which enables the image upload should have been done directly by the ActivityPanel which would have kept the independance principle
@@ -1337,7 +1331,7 @@ HTML
}
}
}
$aHeader['friendlyname'] = ['label' => MetaModel::GetName($sClassName)];
foreach ($aList[$sAlias] as $sAttCodeEx => $oAttDef) {
$sColLabel = $bLocalize ? MetaModel::GetLabel($sClassName, $sAttCodeEx) : $sAttCodeEx;
@@ -1358,7 +1352,6 @@ HTML
$aRow = [];
foreach ($aAuthorizedClasses as $sAlias => $sClassName) {
$oObj = $aObjects[$sAlias];
$aRow["friendlyname"] = $oObj->Get('friendlyname');
foreach ($aList[$sAlias] as $sAttCodeEx => $oAttDef) {
if (is_null($oObj)) {
$aRow[$oAttDef->GetCode()] = '';
@@ -3072,7 +3065,7 @@ JS
$oPage->add($oAppContext->GetForForm());
// Hook the cancel button via jQuery so that it can be unhooked easily as well if needed
$sDefaultUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search_form&class='.$sClass.$oAppContext->GetForLink(true);
$sDefaultUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search_form&class='.$sClass.'&'.$oAppContext->GetForLink();
$sCancelButtonOnClickScript = "let fOnClick{$this->m_iFormId}CancelButton = ";
if(isset($aExtraParams['js_handlers']['cancel_button_on_click'])){
@@ -3080,7 +3073,7 @@ JS
} else {
$sCancelButtonOnClickScript .= "function() { BackToDetails('$sClass', $iKey, '$sDefaultUrl', $sJSToken)};";
}
$sCancelButtonOnClickScript .= "$('#form_{$this->m_iFormId} button.cancel').on('click.navigation.itop', fOnClick{$this->m_iFormId}CancelButton);";
$sCancelButtonOnClickScript .= "$('#form_{$this->m_iFormId} button.cancel').on('click', fOnClick{$this->m_iFormId}CancelButton);";
$oPage->add_ready_script($sCancelButtonOnClickScript);
$iFieldsCount = count($aFieldsMap);
@@ -3446,18 +3439,8 @@ EOF
}
$sInputType = '';
$sInputId = 'att_'.$iFieldIndex;
$value = $this->Get($sAttCode);
$sDisplayValue = $this->GetEditValue($sAttCode);
if ($oAttDef instanceof AttributeDateTime && !$oAttDef->IsNullAllowed() && $value === $oAttDef->GetNullValue()) {
$value = $oAttDef->GetDefaultValue($this);
if ($value !== $oAttDef->GetNullValue()) {
// Set default date
$this->Set($sAttCode, $value);
$sDisplayValue = $this->GetEditValue($sAttCode);
}
}
$sHTMLValue = cmdbAbstractObject::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef,
$value, $sDisplayValue, $sInputId, '', $iExpectCode,
$this->Get($sAttCode), $this->GetEditValue($sAttCode), $sInputId, '', $iExpectCode,
$aArgs, true, $sInputType);
$aAttrib = array(
'label' => '<span>'.$oAttDef->GetLabel().'</span>',
@@ -6104,9 +6087,7 @@ JS
// We want to avoid launching the listener twice, first here, and secondly after saving the Ticket in the listener
// By disabling the event to be fired, we can remove the current object from the attribute !
$oObject = MetaModel::GetObject($sClass, $sId, false);
if (!is_null($oObject)) {
self::FireEventDbLinksChangedForObject($oObject);
}
self::FireEventDbLinksChangedForObject($oObject);
self::RemoveObjectAwaitingEventDbLinksChanged($sClass, $sId);
}
@@ -6114,11 +6095,13 @@ JS
{
self::SetEventDBLinksChangedBlocked(true);
// N°6408 The object can have been deleted
$oObject->FireEvent(EVENT_DB_LINKS_CHANGED);
if (!is_null($oObject)) {
$oObject->FireEvent(EVENT_DB_LINKS_CHANGED);
// Update the object if needed
if (count($oObject->ListChanges()) !== 0) {
$oObject->DBUpdate();
// Update the object if needed
if (count($oObject->ListChanges()) !== 0) {
$oObject->DBUpdate();
}
}
cmdbAbstractObject::SetEventDBLinksChangedBlocked(false);
}

View File

@@ -524,7 +524,9 @@ EOF
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
{
$aExtraParams['dashboard_div_id'] = utils::Sanitize($aExtraParams['dashboard_div_id'] ?? null, $this->GetId(), utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER);
if (!array_key_exists('dashboard_div_id', $aExtraParams)) {
$aExtraParams['dashboard_div_id'] = utils::Sanitize($this->GetId(), '', 'element_identifier');
}
/** @var \DashboardLayoutMultiCol $oLayout */
$oLayout = new $this->sLayoutClass();
@@ -1050,7 +1052,7 @@ EOF
$sSelectorHtml .= '</div>';
$sFile = addslashes($this->GetDefinitionFile());
$sReloadURL = json_encode($this->GetReloadURL());
$sReloadURL = $this->GetReloadURL();
$bFromDashboardPage = isset($aAjaxParams['from_dashboard_page']) ? isset($aAjaxParams['from_dashboard_page']) : false;
if ($bFromDashboardPage) {
@@ -1139,6 +1141,7 @@ JS
->AddCSSClass('ibo-action-button');
$oToolbar->AddSubBlock($oActionButton);
$aActions = array();
$sFile = addslashes(utils::LocalPath($this->sDefinitionFile));
$sJSExtraParams = json_encode($aExtraParams);
@@ -1163,7 +1166,7 @@ JS
$oToolbar->AddSubBlock($oActionButton)
->AddSubBlock($oActionsMenu);
$sReloadURL = json_encode($this->GetReloadURL());
$sReloadURL = $this->GetReloadURL();
$oPage->add_script(
<<<EOF
function EditDashboard(sId, sDashboardFile, aExtraParams)
@@ -1270,7 +1273,7 @@ EOF
$sTitle = json_encode($this->sTitle);
$sFile = json_encode($this->GetDefinitionFile());
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
$sReloadURL = json_encode($this->GetReloadURL());
$sReloadURL = $this->GetReloadURL();
$sExitConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage'));
$sCancelConfirmationMessage = addslashes(Dict::S('UI:CancelConfirmationMessage'));

View File

@@ -2138,7 +2138,7 @@ class DashletHeaderDynamic extends Dashlet
$oSet = new DBObjectSet($oFilter);
$iCount = $oSet->Count();
$oAppContext = new ApplicationContext();
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search'.$oAppContext->GetForLink(true).'&filter='.rawurlencode($oFilter->serialize());
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.rawurlencode($oFilter->serialize());
$oSubTitle->AddHtml('<a class="summary" href="'.$sHyperlink.'">'.Dict::Format(str_replace('_', ':', $sSubtitle), $iCount).'</a>');
return $oPanel;

View File

@@ -1124,7 +1124,7 @@ JS
$oSingleGroupByValueFilter->SetShowObsoleteData($this->m_bShowObsoleteData);
}
$sHyperlink = utils::GetAbsoluteUrlAppRoot()
.'pages/UI.php?operation=search'.$oAppContext->GetForLink(true)
.'pages/UI.php?operation=search&'.$oAppContext->GetForLink()
.'&filter='.rawurlencode($oSingleGroupByValueFilter->serialize());
$aCounts[$sStateValue] = ['link' => $sHyperlink, 'label' => $aCounts[$sStateValue]];
}
@@ -1232,7 +1232,7 @@ JS
$iCount = $this->m_oSet->Count();
$sClassLabel = MetaModel::GetName($sClass);
$sClassIconUrl = MetaModel::GetClassIcon($sClass, false);
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search'.$oAppContext->GetForLink(true).'&filter='.rawurlencode($this->m_oFilter->serialize());
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.rawurlencode($this->m_oFilter->serialize());
$aExtraParams['query_params'] = $this->m_oFilter->GetInternalParams();
$aRefreshParams = [
@@ -1241,7 +1241,7 @@ JS
];
if (UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY)) {
$sCreateActionUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=new&class='.$sClass.$oAppContext->GetForLink(true);
$sCreateActionUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=new&class='.$sClass.'&'.$oAppContext->GetForLink();
$sCreateActionLabel = Dict::Format('UI:Button:Create');
$oBlock = DashletFactory::MakeForDashletBadge($sClassIconUrl, $sHyperlink, $iCount, $sClassLabel, $sCreateActionUrl,
$sCreateActionLabel, $aRefreshParams);
@@ -1289,7 +1289,7 @@ JS
$aData = array();
$oAppContext = new ApplicationContext();
$sParams = $oAppContext->GetForLink(true);
$sParams = $oAppContext->GetForLink();
foreach ($aGroupBy as $iRow => $iCount) {
// Build the search for this subset
$oSubsetSearch = $this->m_oFilter->DeepClone();
@@ -1304,7 +1304,7 @@ JS
$aData[] = array(
'group' => $aLabels[$iRow],
'value' => "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&dosearch=1$sParams&filter=$sFilter\">$iCount</a>"
'value' => "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&dosearch=1&$sParams&filter=$sFilter\">$iCount</a>"
); // TO DO: add the context information
}
$aAttribs = array(
@@ -1636,7 +1636,7 @@ JS
$sGroupByExpr = isset($aExtraParams['group_by_expr']) ? '&params[group_by_expr]='.$aExtraParams['group_by_expr'] : '';
$sFilter = $this->m_oFilter->serialize(false, $aQueryParams);
$oContext = new ApplicationContext();
$sContextParam = $oContext->GetForLink(true);
$sContextParam = $oContext->GetForLink();
$sAggregationFunction = isset($aExtraParams['aggregation_function']) ? $aExtraParams['aggregation_function'] : '';
$sAggregationAttr = isset($aExtraParams['aggregation_attribute']) ? $aExtraParams['aggregation_attribute'] : '';
$sLimit = isset($aExtraParams['limit']) ? $aExtraParams['limit'] : '';
@@ -1644,7 +1644,7 @@ JS
$sOrderDirection = isset($aExtraParams['order_direction']) ? $aExtraParams['order_direction'] : '';
if (isset($aExtraParams['group_by_label'])) {
$sUrl = utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart&params[group_by]=$sGroupBy{$sGroupByExpr}&params[group_by_label]={$aExtraParams['group_by_label']}&params[chart_type]=$sChartType&params[currentId]=$sChartId{$iChartCounter}&params[order_direction]=$sOrderDirection&params[order_by]=$sOrderBy&params[limit]=$sLimit&params[aggregation_function]=$sAggregationFunction&params[aggregation_attribute]=$sAggregationAttr&id=$sChartId{$iChartCounter}&filter=".rawurlencode($sFilter).$sContextParam;
$sUrl = utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart&params[group_by]=$sGroupBy{$sGroupByExpr}&params[group_by_label]={$aExtraParams['group_by_label']}&params[chart_type]=$sChartType&params[currentId]=$sChartId{$iChartCounter}&params[order_direction]=$sOrderDirection&params[order_by]=$sOrderBy&params[limit]=$sLimit&params[aggregation_function]=$sAggregationFunction&params[aggregation_attribute]=$sAggregationAttr&id=$sChartId{$iChartCounter}&filter=".rawurlencode($sFilter).'&'.$sContextParam;
} else {
$sUrl = utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart&params[group_by]=$sGroupBy{$sGroupByExpr}&params[chart_type]=$sChartType&params[currentId]=$sChartId{$iChartCounter}&params[order_direction]=$sOrderDirection&params[order_by]=$sOrderBy&params[limit]=$sLimit&params[aggregation_function]=$sAggregationFunction&params[aggregation_attribute]=$sAggregationAttr&id=$sChartId{$iChartCounter}&filter=".rawurlencode($sFilter).'&'.$sContextParam;
}
@@ -1681,14 +1681,11 @@ JS
$oBlock = null;
$sJSURLs = '';
$oContext = new ApplicationContext();
$sContextParam = $oContext->GetForLink(true);
if (isset($aExtraParams['group_by'])) {
$this->MakeGroupByQuery($aExtraParams, $oGroupByExp, $sGroupByLabel, $aGroupBy, $sAggregationFunction, $sFctVar, $sAggregationAttr, $sSql);
$aRes = CMDBSource::QueryToArray($sSql);
$oContext = new ApplicationContext();
$sContextParam = $oContext->GetForLink();
$iTotalCount = 0;
$aURLs = array();
@@ -1708,14 +1705,14 @@ JS
$oSubsetSearch = $this->m_oFilter->DeepClone();
$oCondition = new BinaryExpression($oGroupByExp, '=', new ScalarExpression($sValue));
$oSubsetSearch->AddConditionExpression($oCondition);
$aURLs[] = utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&format=html&filter=".rawurlencode($oSubsetSearch->serialize()).$sContextParam;
$aURLs[] = utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&format=html&filter=".rawurlencode($oSubsetSearch->serialize()).'&'.$sContextParam;
}
$sJSURLs = json_encode($aURLs);
}
if (isset($aExtraParams['group_by_label'])) {
$sUrl = utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart&params[group_by]=$aExtraParams[group_by]&params[group_by_label]={$aExtraParams['group_by_label']}&params[chart_type]=$sChartType&params[currentId]=$aExtraParams[currentId]&params[order_direction]=$aExtraParams[order_direction]&params[order_by]=$aExtraParams[order_by]&params[limit]=$aExtraParams[limit]&params[aggregation_function]=$sAggregationFunction&params[aggregation_attribute]=$sAggregationAttr&id=$sId&filter=".rawurlencode($this->m_oFilter->ToOQL()).$sContextParam;
$sUrl = utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart&params[group_by]=$aExtraParams[group_by]&params[group_by_label]={$aExtraParams['group_by_label']}&params[chart_type]=$sChartType&params[currentId]=$aExtraParams[currentId]&params[order_direction]=$aExtraParams[order_direction]&params[order_by]=$aExtraParams[order_by]&params[limit]=$aExtraParams[limit]&params[aggregation_function]=$sAggregationFunction&params[aggregation_attribute]=$sAggregationAttr&id=$sId&filter=".rawurlencode($this->m_oFilter->ToOQL()).'&'.$sContextParam;
} else {
$sUrl = utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart&params[group_by]=$aExtraParams[group_by]&params[chart_type]=$sChartType&params[currentId]=$aExtraParams[currentId]&params[order_direction]=$aExtraParams[order_direction]&params[order_by]=$aExtraParams[order_by]&params[limit]=$aExtraParams[limit]&params[aggregation_function]=$sAggregationFunction&params[aggregation_attribute]=$sAggregationAttr&id=$sId&filter=".rawurlencode($this->m_oFilter->ToOQL()).$sContextParam;
$sUrl = utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart&params[group_by]=$aExtraParams[group_by]&params[chart_type]=$sChartType&params[currentId]=$aExtraParams[currentId]&params[order_direction]=$aExtraParams[order_direction]&params[order_by]=$aExtraParams[order_by]&params[limit]=$aExtraParams[limit]&params[aggregation_function]=$sAggregationFunction&params[aggregation_attribute]=$sAggregationAttr&id=$sId&filter=".rawurlencode($this->m_oFilter->ToOQL()).'&'.$sContextParam;
}
switch ($sChartType) {
@@ -1788,7 +1785,7 @@ JS
$oBlock->sCsvFile = strtolower($this->m_oFilter->GetClass()).'.csv';
$oBlock->sDownloadLink = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?expression='.urlencode($this->m_oFilter->ToOQL(true)).'&format=csv&filename='.urlencode($oBlock->sCsvFile);
$oBlock->sLinkToToggle = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search'.$oAppContext->GetForLink(true).'&filter='.rawurlencode($this->m_oFilter->serialize()).'&format=csv';
$oBlock->sLinkToToggle = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.rawurlencode($this->m_oFilter->serialize()).'&format=csv';
// Pass the parameters via POST, since expression may be very long
$aParamsToPost = array(
'expression' => $this->m_oFilter->ToOQL(true),
@@ -1888,7 +1885,10 @@ class MenuBlock extends DisplayBlock
&& (!isset($aExtraParams['menu']) || $aExtraParams['menu'] === "1" || $aExtraParams['menu'] === true)
) {
$oAppContext = new ApplicationContext();
$sContext = $oAppContext->GetForLink(true);
$sContext = $oAppContext->GetForLink();
if (utils::IsNotNullOrEmptyString($sContext)) {
$sContext = '&'.$sContext;
}
$sFilter = $this->GetFilter()->serialize();
@@ -2578,8 +2578,11 @@ class MenuBlock extends DisplayBlock
$sUrl = "{$sRootUrl}pages/{$sUIPage}?{$sUrlParams}";
$oAppContext = new ApplicationContext();
$sContext = $oAppContext->GetForLink(true);
$sContext = $oAppContext->GetForLink();
if (utils::IsNotNullOrEmptyString($sContext)) {
$sUrl .= '&'.$sContext;
}
return $sUrl . $sContext;
return $sUrl;
}
}

View File

@@ -63,14 +63,14 @@ class CoreCannotSaveObjectException extends CoreException
public function getTextMessage()
{
$sTitle = Dict::S('UI:Error:SaveFailed');
$sContent = $sTitle;
$sContent = utils::HtmlEntities($sTitle);
if (count($this->aIssues) == 1) {
$sIssue = reset($this->aIssues);
$sContent .= $sIssue;
$sContent .= utils::HtmlEntities($sIssue);
} else {
foreach ($this->aIssues as $sError) {
$sContent .= " " . $sError . ", ";
$sContent .= " ".utils::HtmlEntities($sError).", ";
}
}

View File

@@ -67,7 +67,7 @@ class CoreException extends Exception
public function getHtmlDesc($sHighlightHtmlBegin = '<b>', $sHighlightHtmlEnd = '</b>')
{
return utils::EscapeHtml($this->getMessage());
return $this->getMessage();
}
/**

View File

@@ -250,7 +250,7 @@ class UIExtKeyWidget
foreach ($aAdditionalField as $sAdditionalField) {
array_push($aArguments, $oObj->Get($sAdditionalField));
}
$aOption['additional_field'] = utils::HtmlEntities(utils::VSprintf($sFormatAdditionalField, $aArguments));
$aOption['additional_field'] = utils::HtmlEntities(vsprintf($sFormatAdditionalField, $aArguments));
}
if (!empty($sObjectImageAttCode)) {
// Try to retrieve image for contact

View File

@@ -249,9 +249,9 @@ class appUserPreferences extends DBObject
(
"category" => "gui",
"key_type" => "autoincrement",
"name_attcode" => "login",
"name_attcode" => "userid",
"state_attcode" => "",
"reconc_keys" => array("userid","login"),
"reconc_keys" => array("userid"),
"db_table" => "priv_app_preferences",
"db_key_field" => "id",
"db_finalclass_field" => "",
@@ -260,10 +260,8 @@ class appUserPreferences extends DBObject
MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributePropertySet("preferences", array("allowed_values"=>null, "sql"=>"preferences", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("org_id", array("allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "org_id")));
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values" => null, "extkey_attcode" => 'userid', "target_attcode" => "login")));
MetaModel::Init_SetZListItems('list', array('org_id','preferences'));
MetaModel::Init_SetZListItems('default_search', array('userid','login','org_id'));
MetaModel::Init_SetZListItems('list', array('preferences',));
MetaModel::Init_SetZListItems('default_search', array('userid'));
}
/**

View File

@@ -180,7 +180,6 @@ class utils
*/
private static $sAbsoluteUrlAppRootCache = null;
protected static function LoadParamFile($sParamFile)
{
if (!file_exists($sParamFile)) {
@@ -419,26 +418,11 @@ class utils
* @since 2.7.7, 3.0.2, 3.1.0 N°4899 - new 'url' filter
* @since 2.7.10 N°6606 use the utils::ENUM_SANITIZATION_* const
* @since 2.7.10 N°6606 new case for ENUM_SANITIZATION_FILTER_PHP_CLASS
* @since 3.2.1-1 N°8242 Allow value to be an array for every filter
*
* @link https://www.php.net/manual/en/filter.filters.sanitize.php PHP sanitization filters
*/
protected static function Sanitize_Internal($value, $sSanitizationFilter)
{
if (is_array($value))
{
$retValue = array();
foreach ($value as $key => $val)
{
$retValue[$key] = self::Sanitize_Internal($val, $sSanitizationFilter); // recursively check arrays
if ($retValue[$key] === false)
{
return false;
}
}
return $retValue;
}
switch ($sSanitizationFilter)
{
case static::ENUM_SANITIZATION_FILTER_INTEGER:
@@ -469,36 +453,52 @@ class utils
case static::ENUM_SANITIZATION_FILTER_PARAMETER:
case static::ENUM_SANITIZATION_FILTER_FIELD_NAME:
case static::ENUM_SANITIZATION_FILTER_TRANSACTION_ID:
switch ($sSanitizationFilter)
if (is_array($value))
{
case static::ENUM_SANITIZATION_FILTER_TRANSACTION_ID:
// Same as parameter type but keep the dot character
// transaction_id, the dot is mostly for Windows servers when using file storage as the tokens are named *.tmp
// - See N°1835
// - Note: It must be included at the regexp beginning otherwise you'll get an invalid character error
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options" => array("regexp" => '/^[\. A-Za-z0-9_=-]*$/')));
break;
$retValue = array();
foreach ($value as $key => $val)
{
$retValue[$key] = self::Sanitize_Internal($val, $sSanitizationFilter); // recursively check arrays
if ($retValue[$key] === false)
{
$retValue = false;
break;
}
}
}
else
{
switch ($sSanitizationFilter)
{
case static::ENUM_SANITIZATION_FILTER_TRANSACTION_ID:
// Same as parameter type but keep the dot character
// transaction_id, the dot is mostly for Windows servers when using file storage as the tokens are named *.tmp
// - See N°1835
// - Note: It must be included at the regexp beginning otherwise you'll get an invalid character error
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options" => array("regexp" => '/^[\. A-Za-z0-9_=-]*$/')));
break;
case static::ENUM_SANITIZATION_FILTER_ROUTE:
case static::ENUM_SANITIZATION_FILTER_OPERATION:
// - Routes should be of the "controller_namespace_code.controller_method_name" form
// - Operations should be allowed to be namespaced as well even though then don't have dedicated controller yet
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options" => array("regexp" => '/^[\.A-Za-z0-9_-]*$/')));
break;
case static::ENUM_SANITIZATION_FILTER_ROUTE:
case static::ENUM_SANITIZATION_FILTER_OPERATION:
// - Routes should be of the "controller_namespace_code.controller_method_name" form
// - Operations should be allowed to be namespaced as well even though then don't have dedicated controller yet
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options" => array("regexp" => '/^[\.A-Za-z0-9_-]*$/')));
break;
case static::ENUM_SANITIZATION_FILTER_PARAMETER:
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options" => array("regexp" => '/^[ A-Za-z0-9_=-]*$/'))); // the '=', '%3D, '%2B', '%2F'
// Characters are used in serialized filters (starting 2.5, only the url encoded versions are presents, but the "=" is kept for BC)
break;
case static::ENUM_SANITIZATION_FILTER_PARAMETER:
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options" => array("regexp" => '/^[ A-Za-z0-9_=-]*$/'))); // the '=', '%3D, '%2B', '%2F'
// Characters are used in serialized filters (starting 2.5, only the url encoded versions are presents, but the "=" is kept for BC)
break;
case static::ENUM_SANITIZATION_FILTER_FIELD_NAME:
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options" => array("regexp" => '/^[A-Za-z0-9_]+(->[A-Za-z0-9_]+)*$/'))); // att_code or att_code->name or AttCode->Name or AttCode->Key2->Name
break;
case static::ENUM_SANITIZATION_FILTER_FIELD_NAME:
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options" => array("regexp" => '/^[A-Za-z0-9_]+(->[A-Za-z0-9_]+)*$/'))); // att_code or att_code->name or AttCode->Name or AttCode->Key2->Name
break;
case static::ENUM_SANITIZATION_FILTER_CONTEXT_PARAM:
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options" => array("regexp" => '/^[ A-Za-z0-9_=%:+-]*$/')));
break;
case static::ENUM_SANITIZATION_FILTER_CONTEXT_PARAM:
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options" => array("regexp" => '/^[ A-Za-z0-9_=%:+-]*$/')));
break;
}
}
break;
@@ -521,8 +521,8 @@ class utils
// For URL
case static::ENUM_SANITIZATION_FILTER_URL:
$retValue = filter_var($value, FILTER_SANITIZE_URL);
$retValue = filter_var($retValue, FILTER_VALIDATE_URL);
// N°6350 - returns only valid URLs
$retValue = filter_var($value, FILTER_VALIDATE_URL);
break;
default:
@@ -1516,12 +1516,12 @@ class utils
case iPopupMenuExtension::MENU_OBJLIST_TOOLKIT:
/** @var \DBObjectSet $param */
$oAppContext = new ApplicationContext();
$sContext = $oAppContext->GetForLink(true);
$sContext = $oAppContext->GetForLink();
$sDataTableId = is_null($sDataTableId) ? '' : $sDataTableId;
$sUIPage = cmdbAbstractObject::ComputeStandardUIPage($param->GetFilter()->GetClass());
$sOQL = addslashes($param->GetFilter()->ToOQL(true));
$sFilter = urlencode($param->GetFilter()->serialize());
$sUrl = utils::GetAbsoluteUrlAppRoot()."pages/$sUIPage?operation=search&filter=".$sFilter.$sContext;
$sUrl = utils::GetAbsoluteUrlAppRoot()."pages/$sUIPage?operation=search&filter=".$sFilter."&{$sContext}";
$oContainerBlock->AddJsFileRelPath('js/tabularfieldsselector.js');
$oContainerBlock->AddJsFileRelPath('js/jquery.dragtable.js');
$oContainerBlock->AddCssFileRelPath('css/dragtable.css');
@@ -1555,10 +1555,6 @@ class utils
}
$aResult[] = new JSPopupMenuItem('UI:Menu:AddToDashboard', Dict::S('UI:Menu:AddToDashboard'), "DashletCreationDlg('$sOQL', '$sContext')");
$aResult[] = new JSPopupMenuItem('UI:Menu:ShortcutList', Dict::S('UI:Menu:ShortcutList'), "ShortcutListDlg('$sOQL', '$sDataTableId', '$sContext')");
if (ApplicationMenu::IsMenuIdEnabled('RunQueriesMenu')) {
$oMenuItemPlay = new JSPopupMenuItem('UI:Menu:OpenOQL', Dict::S('UI:Menu:OpenOQL'), "OpenOql('$sOQL')");
$aResult[] = $oMenuItemPlay;
}
break;
@@ -1695,8 +1691,8 @@ class utils
$oAppContext = new ApplicationContext();
$sUrl = $sAppRootUrl
.'pages/UI.php?operation=search'
.$oAppContext->GetForLink(true)
.'pages/UI.php?operation=search&'
.$oAppContext->GetForLink()
.'&filter='.rawurlencode($oDataTableSearchFilter->serialize());
$sUrl .= '&aParams='.rawurlencode($sParams); // Not working... yet, cause not handled by UI.php
@@ -2079,127 +2075,6 @@ SQL;
);
}
/**
* Format a string using vsprintf with safety checks to avoid ValueError
*
* This method fills missing arguments with their original format specifiers,
* then calls vsprintf with the complete array.
*
* @param string $sFormat The format string
* @param array $aArgs The arguments to format
* @param bool $bLogErrors Whether to log errors (defaults to true)
*
* @return string The formatted string
* @since 3.2.2
*/
public static function VSprintf(string $sFormat, array $aArgs, bool $bLogErrors = true): string
{
// Extract all format specifiers
$sPattern = '/%(?:(?:[1-9][0-9]*)\$)?[-+\'0# ]*(?:[0-9]*|\*)?(?:\.(?:[0-9]*|\*))?(?:[hlL])?[diouxXeEfFgGcrs%]/';
preg_match_all($sPattern, $sFormat, $aMatches, PREG_OFFSET_CAPTURE);
// Process matches, keeping track of their positions and excluding escaped percent signs (%%)
$aSpecifierMatches = [];
foreach ($aMatches[0] as $sMatch) {
if ($sMatch[0] !== '%%') {
$aSpecifierMatches[] = $sMatch;
}
}
// Check for positional specifiers and build position map
$bHasPositional = false;
$iMaxPosition = 0;
$aPositions = [];
$aUniquePositions = [];
foreach ($aSpecifierMatches as $index => $match) {
$sSpec = $match[0];
if (preg_match('/^%([1-9][0-9]*)\$/', $sSpec, $posMatch)) {
$bHasPositional = true;
$iPosition = (int)$posMatch[1] - 1; // Convert to 0-based
$aPositions[$index] = $iPosition;
$aUniquePositions[$iPosition] = true;
$iMaxPosition = max($iMaxPosition, $iPosition + 1);
} else {
$aPositions[$index] = $index;
$aUniquePositions[$index] = true;
$iMaxPosition = max($iMaxPosition, $index + 1);
}
}
// Count unique positions, this tells us how many arguments we actually need
$iExpectedCount = count($aUniquePositions);
$iActualCount = count($aArgs);
// If we have enough arguments, just use vsprintf
if ($iActualCount >= $iExpectedCount) {
return vsprintf($sFormat, $aArgs);
}
// else log the error if needed
if ($bLogErrors) {
IssueLog::Warning("Format string requires $iExpectedCount arguments, but only $iActualCount provided. Format: '$sFormat'" );
}
// Create a replacement map
if ($bHasPositional) {
// For positional, we need to handle the exact positions
$aReplacements = array_fill(0, $iMaxPosition, null);
// Fill in the real arguments first
foreach ($aArgs as $index => $sValue) {
if ($index < $iMaxPosition) {
$aReplacements[$index] = $sValue;
}
}
// For null values in the replacement map, use the original specifier
foreach ($aSpecifierMatches as $index => $sMatch) {
$iPosition = $aPositions[$index];
if ($aReplacements[$iPosition] === null) {
// Use the original format specifier when we don't have an argument
$aReplacements[$iPosition] = $sMatch[0];
}
}
// Remove any remaining nulls (for positions that weren't referenced)
$aReplacements = array_filter($aReplacements, static function($val) { return $val !== null; });
} else {
// For non-positional, we need to map each position
$aReplacements = [];
$iUsed = 0;
// Create a map of what values to use for each position
$aPositionValues = [];
for ($i = 0; $i < $iMaxPosition; $i++) {
if (isset($aUniquePositions[$i])) {
if ($iUsed < $iActualCount) {
// We have an actual argument for this position
$aPositionValues[$i] = $aArgs[$iUsed++];
} else {
// Mark this position to use the original specifier
$aPositionValues[$i] = null;
}
}
}
// Build the replacements array preserving the original order
foreach ($aSpecifierMatches as $index => $sMatch) {
$iPosition = $aPositions[$index];
if (isset($aPositionValues[$iPosition])) {
$aReplacements[] = $aPositionValues[$iPosition];
} else {
// Use the original format specifier when we don't have an argument
$aReplacements[] = $sMatch[0];
// Mark this position as used, so if it appears again, it gets the same replacement
$aPositionValues[$iPosition] = $sMatch[0];
}
}
}
// Process the format string with our filled-in arguments
return vsprintf($sFormat, $aReplacements);
}
/**
* Convert a string containing some (valid) HTML markup to plain text
*
@@ -2518,75 +2393,53 @@ SQL;
return $bRet;
}
/**
* @param $sPath
*
* @return false|\ormDocument
* @throws \Exception
*
* @deprecated 3.2.1 use utils::GetDocumentFromSelfURL instead
*/
public static function IsSelfURL($sPath)
{
return self::GetDocumentFromSelfURL($sPath);
}
/**
* 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
*
* @Since 3.2.1 a local URL is transformed into a local file to read
*
* @param string $sPath
* @return false|ormDocument
* @throws Exception
*/
public static function GetDocumentFromSelfURL(string $sPath)
public static function IsSelfURL($sPath)
{
$result = false;
$sPageUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.document.php';
if (utils::StartsWith($sPath, $sPageUrl)) {
if (substr($sPath, 0, strlen($sPageUrl)) == $sPageUrl)
{
// If the URL is an URL pointing to this instance of iTop, then
// extract the "query" part of the URL and analyze it
$sQuery = parse_url($sPath, PHP_URL_QUERY);
if ($sQuery !== null) {
if ($sQuery !== null)
{
$aParams = array();
foreach (explode('&', $sQuery) as $sChunk) {
foreach(explode('&', $sQuery) as $sChunk)
{
$aParts = explode('=', $sChunk ?? '');
if (count($aParts) != 2) {
continue;
}
if (count($aParts) != 2) continue;
$aParams[$aParts[0]] = urldecode($aParts[1]);
}
$result = array_key_exists('operation', $aParams) && array_key_exists('class', $aParams) && array_key_exists('id', $aParams) && array_key_exists('field', $aParams) && ($aParams['operation'] == 'download_document');
if ($result) {
if ($result)
{
// This is a 'download_document' operation, let's retrieve the document directly from the database
$sClass = $aParams['class'];
$iKey = $aParams['id'];
$sAttCode = $aParams['field'];
$oObj = MetaModel::GetObject($sClass, $iKey, false /* must exist */); // Users rights apply here !!
if ($oObj) {
if ($oObj)
{
/**
* @var ormDocument $result
*/
return clone $oObj->Get($sAttCode);
$result = clone $oObj->Get($sAttCode);
return $result;
}
}
}
throw new Exception('Invalid URL. This iTop URL is not pointing to a valid Document/Image.');
}
if (utils::StartsWith($sPath, utils::GetAbsoluteUrlAppRoot())) {
$sFilePath = utils::LocalPath(APPROOT.substr($sPath, strlen(utils::GetAbsoluteUrlAppRoot())));
if (false === $sFilePath) {
return false;
}
$sFilePath = APPROOT.$sFilePath;
return ormDocument::FromFile($sFilePath);
}
return false;
return $result;
}
/**
@@ -2594,28 +2447,68 @@ SQL;
* - an URL pointing to a blob (image/document) on the current iTop server
* - an http(s) URL
* - the local file system (but only if you are an administrator)
*
* @param string|null $sPath
* @param string $sPath
* @return ormDocument|null
* @throws Exception
*/
public static function FileGetContentsAndMIMEType($sPath)
{
if (utils::IsNullOrEmptyString($sPath)) {
$oUploadedDoc = null;
$aKnownExtensions = array(
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'gif' => 'image/gif',
'png' => 'image/png',
'pdf' => 'application/pdf',
'doc' => 'application/msword',
'dot' => 'application/msword',
'xls' => 'application/vnd.ms-excel',
'ppt' => 'application/vnd.ms-powerpoint',
'vsd' => 'application/x-visio',
'vdx' => 'application/visio.drawing',
'odt' => 'application/vnd.oasis.opendocument.text',
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
'odp' => 'application/vnd.oasis.opendocument.presentation',
'zip' => 'application/zip',
'txt' => 'text/plain',
'htm' => 'text/html',
'html' => 'text/html',
'exe' => 'application/octet-stream',
);
$sData = null;
$sMimeType = 'text/plain'; // Default MIME Type: treat the file as a bunch a characters...
$sFileName = 'uploaded-file'; // Default name for downloaded-files
$sExtension = '.txt'; // Default file extension in case we don't know the MIME Type
if(empty($sPath))
{
// Empty path (NULL or '') means that there is no input, making an empty document.
return new ormDocument('', '', '');
$oUploadedDoc = new ormDocument('', '', '');
}
if (static::IsURL($sPath)) {
$oUploadedDoc = static::GetDocumentFromSelfURL($sPath);
if ($oUploadedDoc) {
return $oUploadedDoc;
elseif (static::IsURL($sPath))
{
if ($oUploadedDoc = static::IsSelfURL($sPath))
{
// Nothing more to do, we've got it !!
}
// Remote file, let's use the HTTP headers to find the MIME Type
$sData = @file_get_contents($sPath);
if ($sData === false) {
IssueLog::Error(<<<TXT
else
{
// Remote file, let's use the HTTP headers to find the MIME Type
$sData = @file_get_contents($sPath);
if ($sData === false)
{
IssueLog::Error(<<<TXT
Failed to load the file from URL. This can happen for multiple reasons:
- Invalid URL
- URL using HTTPS with an untrusted certificate on the remote server
@@ -2624,40 +2517,54 @@ TXT
, LogChannels::CORE, [
'URL' => $sPath,
]);
throw new Exception("Failed to load the file from the URL '$sPath'.");
}
$sMimeType = 'text/plain'; // Default MIME Type: treat the file as a bunch a characters...
$sFileName = 'uploaded-file'; // Default name for downloaded-files
$sExtension = '.txt'; // Default file extension in case we don't know the MIME Type
if (isset($http_response_header)) {
$aHeaders = static::ParseHeaders($http_response_header);
$sMimeType = array_key_exists('Content-Type', $aHeaders) ? strtolower($aHeaders['Content-Type']) : 'application/x-octet-stream';
// Compute the file extension from the MIME Type
foreach (ormDocument::GetKnownExtensions() as $sExtValue => $sMime) {
if ($sMime === $sMimeType) {
$sExtension = '.'.$sExtValue;
break;
}
throw new Exception("Failed to load the file from the URL '$sPath'.");
}
else
{
if (isset($http_response_header))
{
$aHeaders = static::ParseHeaders($http_response_header);
$sMimeType = array_key_exists('Content-Type', $aHeaders) ? strtolower($aHeaders['Content-Type']) : 'application/x-octet-stream';
// Compute the file extension from the MIME Type
foreach ($aKnownExtensions as $sExtValue => $sMime) {
if ($sMime === $sMimeType) {
$sExtension = '.'.$sExtValue;
break;
}
}
}
$sPathName = pathinfo($sPath, PATHINFO_FILENAME);
if (utils::IsNotNullOrEmptyString($sPathName)) {
$sFileName = $sPathName;
}
$sFileName .= $sExtension;
}
$oUploadedDoc = new ormDocument($sData, $sMimeType, $sFileName);
}
$sPathName = pathinfo($sPath, PATHINFO_FILENAME);
if (utils::IsNotNullOrEmptyString($sPathName)) {
$sFileName = $sPathName;
}
$sFileName .= $sExtension;
return new ormDocument($sData, $sMimeType, $sFileName);
}
// Local file
if (UserRights::IsAdministrator()) {
else if (UserRights::IsAdministrator())
{
// Only administrators are allowed to read local files
return ormDocument::FromFile($sPath);
}
$sData = @file_get_contents($sPath);
if ($sData === false)
{
throw new Exception("Failed to load the file '$sPath'. The file does not exist or the current process is not allowed to access it.");
}
$sExtension = strtolower(pathinfo($sPath, PATHINFO_EXTENSION));
$sFileName = basename($sPath);
return null;
if (array_key_exists($sExtension, $aKnownExtensions))
{
$sMimeType = $aKnownExtensions[$sExtension];
}
else if (extension_loaded('fileinfo'))
{
$finfo = new finfo(FILEINFO_MIME);
$sMimeType = $finfo->file($sPath);
}
$oUploadedDoc = new ormDocument($sData, $sMimeType, $sFileName);
}
return $oUploadedDoc;
}
protected static function ParseHeaders($aHeaders)
@@ -3228,13 +3135,30 @@ TXT
* @throws \Exception
* @since 3.0.0
*/
public static function GetMentionedObjectsFromText(string $sText): array
public static function GetMentionedObjectsFromText(string $sText, string $sFormat = self::ENUM_TEXT_FORMAT_HTML): array
{
$aMentionedObjects = [];
$aMentionMatches = [];
$sText = html_entity_decode($sText);
// First transform text so it can be parsed
switch ($sFormat) {
case static::ENUM_TEXT_FORMAT_HTML:
$sText = static::HtmlToText($sText);
break;
default:
// Don't transform it
break;
}
// Then parse text to find objects
$aMentionedObjects = array();
$aMentionMatches = array();
// Note: As the sanitizer (or CKEditor autocomplete plugin? 🤔) removes data-* attributes from the hyperlink,
// - we can't use the following (simpler) regexp that only checks data attributes on hyperlinks, which would have worked for hyperlinks pointing to any GUIs: '/<a\s*([^>]*)data-object-class="([^"]*)"\s*data-object-id="([^"]*)">/i'
// - instead we use a regexp to match the following pattern '[Some object label](<APP_ROOT_URL>...&class=<OBJECT_CLASS>&id=<OBJECT_ID>...)' which only works for the backoffice
// If we change the sanitizer, we might want to switch to the other regexp as it's universal and easier to read
$sAppRootUrlForRegExp = addcslashes(utils::GetAbsoluteUrlAppRoot(), '/&');
preg_match_all("/\[([^\]]*)\]\({$sAppRootUrlForRegExp}[^\)]*\&class=([^\)\&]*)\&id=([\d]*)[^\)]*\)/i", $sText, $aMentionMatches);
preg_match_all('/<a\s*([^>]*)data-object-class="([^"]*)"\s.*data-object-key="([^"]*)"/Ui', $sText, $aMentionMatches);
foreach ($aMentionMatches[0] as $iMatchIdx => $sCompleteMatch) {
$sMatchedClass = $aMentionMatches[2][$iMatchIdx];
$sMatchedId = $aMentionMatches[3][$iMatchIdx];

View File

@@ -23,7 +23,7 @@ define('ITOP_DESIGN_LATEST_VERSION', '3.2');
* @used-by utils::GetItopVersionWikiSyntax()
* @used-by iTopModulesPhpVersionIntegrationTest
*/
define('ITOP_CORE_VERSION', '3.2.1');
define('ITOP_CORE_VERSION', '3.2.0');
/**
* @var string

View File

@@ -89,7 +89,7 @@ abstract class AsyncTask extends DBObject
// The value is set from null to planned in the setup program
MetaModel::Init_AddAttribute(new AttributeEnum("status", array("allowed_values"=>new ValueSetEnum('planned,running,idle,error'), "sql"=>"status", "default_value"=>"planned", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("created", array("allowed_values"=>null, "sql"=>"created", "default_value"=>"NOW()", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("created", array("allowed_values"=>null, "sql"=>"created", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("started", array("allowed_values"=>null, "sql"=>"started", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("planned", array("allowed_values"=>null, "sql"=>"planned", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalKey("event_id", array("targetclass"=>"Event", "jointype"=> "", "allowed_values"=>null, "sql"=>"event_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_SILENT, "depends_on"=>array())));
@@ -489,7 +489,7 @@ class AsyncSendNewsroom extends AsyncTask {
MetaModel::Init_AddAttribute(new AttributeInteger("object_id", array("allowed_values"=>null, "sql"=>"object_id", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("object_class", array("allowed_values"=>null, "sql"=>"object_class", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("url", array("allowed_values"=>null, "sql"=>"url", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>'NOW()', "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
}

View File

@@ -142,7 +142,7 @@ abstract class AttributeDefinition
protected $aCSSClasses;
public function GetType()
public function GetType()
{
return Dict::S('Core:'.get_class($this));
}
@@ -4193,7 +4193,7 @@ class AttributeFinalClass extends AttributeString
*/
class AttributePassword extends AttributeString implements iAttributeNoGroupBy
{
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_RAW;
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_RAW;
/**
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
@@ -4270,7 +4270,7 @@ class AttributePassword extends AttributeString implements iAttributeNoGroupBy
*/
class AttributeEncryptedString extends AttributeString implements iAttributeNoGroupBy
{
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_RAW;
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_RAW;
protected function GetSQLCol($bFullSpec = false)
{
@@ -4995,7 +4995,7 @@ class AttributeCaseLog extends AttributeLongText
}
else
{
if (utils::StrLen($proposedValue) > 0)
if (strlen($proposedValue) > 0)
{
//N°5135 - add impersonation information in caselog
if (UserRights::IsImpersonated()){
@@ -6346,15 +6346,10 @@ class AttributeDateTime extends AttributeDBField
$oFormField = parent::MakeFormField($oObject, $oFormField);
// After call to the parent as it sets the current value
$oValue = $oObject->Get($this->GetCode());
if ($oValue === $this->GetNullValue()) {
$oValue = $this->GetDefaultValue($oObject);
}
$oFormField->SetCurrentValue($this->GetFormat()->Format($oValue));
// After call to the parent as it sets the current value
$oFormField->SetCurrentValue($this->GetFormat()->Format($oObject->Get($this->GetCode())));
return $oFormField;
return $oFormField;
}
/**
@@ -6438,26 +6433,8 @@ class AttributeDateTime extends AttributeDBField
public function GetDefaultValue(DBObject $oHostObject = null)
{
$sDefaultValue = $this->Get('default_value');
if (utils::IsNotNullOrEmptyString($sDefaultValue)) {
try {
$sDefaultDate = Expression::FromOQL($sDefaultValue)->Evaluate([]);
} catch (Exception $e) {
try {
$sDefaultDate = Expression::FromOQL('"'.$sDefaultValue.'"')->Evaluate([]);
} catch (Exception $e) {
IssueLog::Error("Invalid default value '$sDefaultValue' for field '{$this->GetCode()}' on class '{$this->GetHostClass()}', defaulting to null");
return $this->GetNullValue();
}
}
try {
$oDate = new DateTimeImmutable($sDefaultDate);
} catch (Exception $e) {
IssueLog::Error("Invalid default value '$sDefaultValue' for field '{$this->GetCode()}' on class '{$this->GetHostClass()}', defaulting to null");
return $this->GetNullValue();
}
return $oDate->format($this->GetInternalFormat());
if (!$this->IsNullAllowed()) {
return date($this->GetInternalFormat());
}
return $this->GetNullValue();
}
@@ -10012,7 +9989,7 @@ class AttributeSubItem extends AttributeDefinition
*/
class AttributeOneWayPassword extends AttributeDefinition implements iAttributeNoGroupBy
{
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_RAW;
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_RAW;
/**
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
@@ -10954,12 +10931,12 @@ abstract class AttributeSet extends AttributeDBFieldVoid
$sDescription = utils::EscapeHtml($this->GetValueDescription($sValue));
$oFilter = DBSearch::FromOQL("SELECT $sClass WHERE $sAttCode MATCHES '$sValue'");
$oAppContext = new ApplicationContext();
$sContext = $oAppContext->GetForLink(true);
$sContext = $oAppContext->GetForLink();
$sUIPage = cmdbAbstractObject::ComputeStandardUIPage($oFilter->GetClass());
$sFilter = rawurlencode($oFilter->serialize());
$sLink = '';
if ($bWithLink && $this->bDisplayLink) {
$sUrl = utils::GetAbsoluteUrlAppRoot()."pages/$sUIPage?operation=search&filter=".$sFilter.$sContext;
$sUrl = utils::GetAbsoluteUrlAppRoot()."pages/$sUIPage?operation=search&filter=".$sFilter."&{$sContext}";
$sLink = ' href="'.$sUrl.'"';
}
@@ -12276,13 +12253,13 @@ class AttributeTagSet extends AttributeSet
$sTagDescription = $oTag->Get('description');
$oFilter = DBSearch::FromOQL("SELECT $sClass WHERE $sAttCode MATCHES '$sTagCode'");
$oAppContext = new ApplicationContext();
$sContext = $oAppContext->GetForLink(true);
$sContext = $oAppContext->GetForLink();
$sUIPage = cmdbAbstractObject::ComputeStandardUIPage($oFilter->GetClass());
$sFilter = rawurlencode($oFilter->serialize());
$sLink = '';
if ($bWithLink && $this->bDisplayLink) {
$sUrl = utils::GetAbsoluteUrlAppRoot()."pages/$sUIPage?operation=search&filter=".$sFilter.$sContext;
$sUrl = utils::GetAbsoluteUrlAppRoot()."pages/$sUIPage?operation=search&filter=".$sFilter."&{$sContext}";
$sLink = ' href="'.$sUrl.'"';
}

View File

@@ -1406,7 +1406,7 @@ class BulkChange
$aDetails = array();
while ($oChange = $oBulkChanges->Fetch())
{
$sDate = '<a href="csvimport.php?step=10&changeid='.$oChange->GetKey().$oAppContext->GetForLink(true).'">'.$oChange->Get('date').'</a>';
$sDate = '<a href="csvimport.php?step=10&changeid='.$oChange->GetKey().'&'.$oAppContext->GetForLink().'">'.$oChange->Get('date').'</a>';
$sUser = $oChange->GetUserName();
if (preg_match('/^(.*)\\(CSV\\)$/i', $oChange->Get('userinfo'), $aMatches))
{
@@ -1488,7 +1488,7 @@ EOF
function OnTruncatedHistoryToggle(bShowAll)
{
$('#csv_history_reload').html('<img src="' + GetAbsoluteUrlAppRoot() + 'images/indicator.gif"/>');
$.get(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?$sAppContext', {operation: 'displayCSVHistory', showall: bShowAll}, function(data)
$.get(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?{$sAppContext}', {operation: 'displayCSVHistory', showall: bShowAll}, function(data)
{
$('#$sAjaxDivId').html(data);
}

View File

@@ -25,7 +25,7 @@ define('EXPORTER_DEFAULT_CHUNK_SIZE', 1000);
class BulkExportException extends Exception
{
protected $sLocalizedMessage;
public function __construct($message, $sLocalizedMessage, $code = 0, $previous = null)
public function __construct($message, $sLocalizedMessage, $code = null, $previous = null)
{
parent::__construct($message, $code, $previous);
$this->sLocalizedMessage = $sLocalizedMessage;
@@ -70,7 +70,7 @@ class BulkExportResult extends DBObject
);
MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeDateTime("created", array("allowed_values"=>null, "sql"=>"created", "default_value"=>"NOW()", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("created", array("allowed_values"=>null, "sql"=>"created", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("user_id", array("allowed_values"=>null, "sql"=>"user_id", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("chunk_size", array("allowed_values"=>null, "sql"=>"chunk_size", "default_value"=>0, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("format", array("allowed_values"=>null, "sql"=>"format", "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array())));

View File

@@ -33,7 +33,7 @@ class CMDBChange extends DBObject
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>"NOW()", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("allowed_values"=>null, "sql"=>"user_id", "targetclass"=>"User", "is_null_allowed"=>true, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("origin", array("allowed_values"=>new ValueSetEnum(implode(',', [CMDBChangeOrigin::INTERACTIVE, CMDBChangeOrigin::CSV_INTERACTIVE, CMDBChangeOrigin::CSV_IMPORT, CMDBChangeOrigin::WEBSERVICE_SOAP, CMDBChangeOrigin::WEBSERVICE_REST, CMDBChangeOrigin::SYNCHRO_DATA_SOURCE, CMDBChangeOrigin::EMAIL_PROCESSING, CMDBChangeOrigin::CUSTOM_EXTENSION])), "sql"=>"origin", "default_value"=>CMDBChangeOrigin::INTERACTIVE, "is_null_allowed"=>true, "depends_on"=>array())));

View File

@@ -1233,14 +1233,6 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'sessions_tracking.session_handler_extension' => [
'type' => 'string',
'description' => 'to store more data in itop session files, set your own iSessionHandlerExtension implementation class in this variable',
'default' => '',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'sessions_tracking.gc_threshold' => [
'type' => 'integer',
'description' => 'fallback in case cron is not active: probability in percent that session files are cleanup during any itop request (100 means always)',

View File

@@ -2867,14 +2867,6 @@ abstract class DBObject implements iDisplay
protected function ListChangedValues(array $aProposal)
{
$aDelta = array();
$sClass = get_class($this);
if (MetaModel::HasLifecycle($sClass) && utils::IsNotNullOrEmptyString($this->sStimulusBeingApplied)) {
$sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
if (!in_array($sStateAttCode, $aProposal)) {
// Same state but the transition was asked, act as if the state was changed
$aDelta[$sStateAttCode] = $this->m_aCurrValues[$sStateAttCode];
}
}
foreach ($aProposal as $sAtt => $proposedValue)
{
if (!array_key_exists($sAtt, $this->m_aOrigValues))
@@ -3624,13 +3616,13 @@ abstract class DBObject implements iDisplay
*/
public function DBUpdate()
{
$this->LogCRUDEnter(__METHOD__);
if (!MetaModel::StartReentranceProtection($this)) {
$this->LogCRUDExit(__METHOD__, 'Rejected (reentrance)');
return false;
}
$this->LogCRUDEnter(__METHOD__);
if (!$this->m_bIsInDB)
{
throw new CoreException("DBUpdate: could not update a newly created object, please call DBInsert instead");
@@ -3819,7 +3811,7 @@ abstract class DBObject implements iDisplay
}
try {
$this->PostUpdateActions($this->m_aPreviousValuesForUpdatedAttributes, $sClass);
$this->PostUpdateActions($aChanges, $sClass);
}
catch (Exception $e) {
$this->LogCRUDExit(__METHOD__, 'Error: '.$e->getMessage());
@@ -3862,9 +3854,7 @@ abstract class DBObject implements iDisplay
*/
protected function PostUpdateActions(array $aChanges): void
{
$sStimulusBeingApplied = $this->sStimulusBeingApplied;
$this->sStimulusBeingApplied = null;
$this->FireEventAfterWrite($aChanges, false, $sStimulusBeingApplied);
$this->FireEventAfterWrite($aChanges, false, $this->sStimulusBeingApplied);
$oKPI = new ExecutionKPI();
$this->AfterUpdate();
$oKPI->ComputeStatsForExtension($this, 'AfterUpdate');
@@ -3876,8 +3866,9 @@ abstract class DBObject implements iDisplay
$this->ActivateOnObjectUpdateTriggersForTargetObjects();
$sClass = get_class($this);
if (utils::IsNotNullOrEmptyString($sStimulusBeingApplied))
if (utils::IsNotNullOrEmptyString($this->sStimulusBeingApplied))
{
$this->sStimulusBeingApplied = null;
$sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
$sPreviousState = $this->m_aPreviousValuesForUpdatedAttributes[$sStateAttCode];
// Change state triggers...
@@ -4034,7 +4025,7 @@ abstract class DBObject implements iDisplay
foreach ($aUpdatedLogAttCodes as $sAttCode) {
/** @var \ormCaseLog $oUpdatedCaseLog */
$oUpdatedCaseLog = $this->Get($sAttCode);
$aMentionedObjects = array_merge_recursive($aMentionedObjects, utils::GetMentionedObjectsFromText($oUpdatedCaseLog->GetModifiedEntry(ormCaseLog::ENUM_FORMAT_HTML)));
$aMentionedObjects = array_merge_recursive($aMentionedObjects, utils::GetMentionedObjectsFromText($oUpdatedCaseLog->GetModifiedEntry()));
}
// 3 - Trigger for those objects
@@ -4511,8 +4502,6 @@ abstract class DBObject implements iDisplay
*/
public function ApplyStimulus($sStimulusCode, $bDoNotWrite = false)
{
$this->LogCRUDEnter(__METHOD__, "Code: $sStimulusCode");
$sClass = get_class($this);
if (!MetaModel::HasLifecycle($sClass))
{
@@ -4539,8 +4528,6 @@ abstract class DBObject implements iDisplay
} else {
$aBackupValues[$sAttCode] = $value;
}
} else {
$aBackupValues[$sAttCode] = $oAttDef->GetNullValue();
}
}
@@ -4548,6 +4535,7 @@ abstract class DBObject implements iDisplay
// Change the state before proceeding to the actions, this is necessary because an action might
// trigger another stimuli (alternative: push the stimuli into a queue)
$sPreviousState = $this->Get($sStateAttCode);
$sNewState = $aTransitionDef['target_state'];
$this->Set($sStateAttCode, $sNewState);
@@ -4555,67 +4543,64 @@ abstract class DBObject implements iDisplay
// array('target_state'=>..., 'actions'=>array of handlers procs, 'user_restriction'=>TBD
$bSuccess = true;
// Prevent current object from being updated by the actions
$this->AddCurrentObjectInCrudStack('APPLY_STIMULUS');
$bIsNewlyProtected = MetaModel::StartReentranceProtection($this);
try {
foreach ($aTransitionDef['actions'] as $actionHandler) {
if (is_string($actionHandler)) {
// Old (pre-2.1.0 modules) action definition without any parameter
$aActionCallSpec = array($this, $actionHandler);
$sActionDesc = $sClass.'::'.$actionHandler;
$sActionDesc = '';
foreach ($aTransitionDef['actions'] as $actionHandler)
{
if (is_string($actionHandler))
{
// Old (pre-2.1.0 modules) action definition without any parameter
$aActionCallSpec = array($this, $actionHandler);
$sActionDesc = $sClass.'::'.$actionHandler;
if (!is_callable($aActionCallSpec)) {
throw new CoreException("Unable to call action: $sClass::$actionHandler");
}
$bRet = call_user_func($aActionCallSpec, $sStimulusCode);
} else // if (is_array($actionHandler))
if (!is_callable($aActionCallSpec))
{
// New syntax: 'verb' and typed parameters
$sAction = $actionHandler['verb'];
$sActionDesc = "$sClass::$sAction";
$aParams = array();
foreach ($actionHandler['params'] as $aDefinition) {
$sParamType = array_key_exists('type', $aDefinition) ? $aDefinition['type'] : 'string';
switch ($sParamType) {
case 'int':
$value = (int)$aDefinition['value'];
break;
throw new CoreException("Unable to call action: $sClass::$actionHandler");
}
$bRet = call_user_func($aActionCallSpec, $sStimulusCode);
}
else // if (is_array($actionHandler))
{
// New syntax: 'verb' and typed parameters
$sAction = $actionHandler['verb'];
$sActionDesc = "$sClass::$sAction";
$aParams = array();
foreach($actionHandler['params'] as $aDefinition)
{
$sParamType = array_key_exists('type', $aDefinition) ? $aDefinition['type'] : 'string';
switch($sParamType)
{
case 'int':
$value = (int)$aDefinition['value'];
break;
case 'float':
$value = (float)$aDefinition['value'];
break;
case 'float':
$value = (float)$aDefinition['value'];
break;
case 'bool':
$value = (bool)$aDefinition['value'];
break;
case 'bool':
$value = (bool)$aDefinition['value'];
break;
case 'reference':
$value = ${$aDefinition['value']};
break;
case 'reference':
$value = ${$aDefinition['value']};
break;
case 'string':
default:
$value = (string)$aDefinition['value'];
}
$aParams[] = $value;
case 'string':
default:
$value = (string)$aDefinition['value'];
}
$aCallSpec = array($this, $sAction);
$bRet = call_user_func_array($aCallSpec, $aParams);
}
// if one call fails, the whole is considered as failed
// (in case there is no returned value, null is obtained and means "ok")
if ($bRet === false) {
IssueLog::Info("Lifecycle action $sActionDesc returned false on object #$sClass:".$this->GetKey());
$bSuccess = false;
$aParams[] = $value;
}
$aCallSpec = array($this, $sAction);
$bRet = call_user_func_array($aCallSpec, $aParams);
}
} finally {
if ($bIsNewlyProtected) {
// Stops protection only if the object was not already protected
MetaModel::StopReentranceProtection($this);
// if one call fails, the whole is considered as failed
// (in case there is no returned value, null is obtained and means "ok")
if ($bRet === false)
{
IssueLog::Info("Lifecycle action $sActionDesc returned false on object #$sClass:".$this->GetKey());
$bSuccess = false;
}
$this->RemoveCurrentObjectInCrudStack();
}
if ($bSuccess)
{
@@ -4648,7 +4633,6 @@ abstract class DBObject implements iDisplay
$this->m_aCurrValues[$sAttCode] = $aBackupValues[$sAttCode];
}
}
$this->LogCRUDExit(__METHOD__, 'Current State: '.$this->Get($sStateAttCode));
return $bSuccess;
}
@@ -6733,13 +6717,12 @@ abstract class DBObject implements iDisplay
$oRootClass = MetaModel::GetRootClass($sClass);
foreach (self::$m_aCrudStack as $aCrudStackEntry) {
if (($oRootClass === $aCrudStackEntry['class']) && ($sConvertedId === $aCrudStackEntry['id'])) {
IssueLog::Trace('CRUD '.__METHOD__." $sClass:$sId IS in CRUD Stack", LogChannels::DM_CRUD);
if (($oRootClass === $aCrudStackEntry['class'])
&& ($sConvertedId === $aCrudStackEntry['id'])) {
return true;
}
}
IssueLog::Trace('CRUD '.__METHOD__." $sClass:$sId NOT in CRUD Stack", LogChannels::DM_CRUD);
return false;
}
@@ -6757,12 +6740,10 @@ abstract class DBObject implements iDisplay
$sRootClass = MetaModel::GetRootClass($sClass);
foreach (self::$m_aCrudStack as $aCrudStackEntry) {
if ($sRootClass === $aCrudStackEntry['class']) {
IssueLog::Trace("CRUD ".__METHOD__." $sClass IS in CRUD Stack", LogChannels::DM_CRUD);
return true;
}
}
IssueLog::Trace('CRUD '.__METHOD__." $sClass NOT in CRUD Stack", LogChannels::DM_CRUD);
return false;
}
@@ -6772,20 +6753,17 @@ abstract class DBObject implements iDisplay
* @param string $sCrudType
*
* @return void
* @throws \CoreException
* @since 3.1.0 N°5609
*/
private function AddCurrentObjectInCrudStack(string $sCrudType): void
{
$this->LogCRUDDebug(__METHOD__);
$sRootClass = MetaModel::GetRootClass(get_class($this));
$sKey = (string)$this->GetKey();
self::$m_aCrudStack[] = [
'type' => $sCrudType,
'class' => $sRootClass,
'id' => $sKey, // GetKey() doesn't have type hinting, so forcing type to avoid getting an int
'id' => (string)$this->GetKey(), // GetKey() doesn't have type hinting, so forcing type to avoid getting an int
];
$iCount = count(self::$m_aCrudStack);
$this->LogCRUDDebug(__METHOD__, "$sCrudType $sRootClass:$sKey count $iCount");
}
/**
@@ -6797,15 +6775,10 @@ abstract class DBObject implements iDisplay
*/
private function UpdateCurrentObjectInCrudStack(): void
{
$this->LogCRUDDebug(__METHOD__);
$aCurrentCrudStack = array_pop(self::$m_aCrudStack);
$sOldId = $aCurrentCrudStack['id'];
$sNewId = (string)$this->GetKey();
$aCurrentCrudStack['id'] = $sNewId;
$aCurrentCrudStack['id'] = (string)$this->GetKey();
self::$m_aCrudStack[] = $aCurrentCrudStack;
$sClass = $aCurrentCrudStack['class'];
$sType = $aCurrentCrudStack['type'];
$iCount = count(self::$m_aCrudStack);
$this->LogCRUDDebug(__METHOD__, "$sType $sClass:$sOldId => $sClass:$sNewId count $iCount");
}
/**
@@ -6817,11 +6790,7 @@ abstract class DBObject implements iDisplay
private function RemoveCurrentObjectInCrudStack(): void
{
$aRemoved = array_pop(self::$m_aCrudStack);
$sType = $aRemoved['type'];
$sClass = $aRemoved['class'];
$sId = $aRemoved['id'];
$iCount = count(self::$m_aCrudStack);
$this->LogCRUDDebug(__METHOD__, "$sType $sClass:$sId count $iCount");
$this->LogCRUDDebug(__METHOD__, $aRemoved['class'].':'.$aRemoved['id']);
}
/**
@@ -6838,53 +6807,37 @@ abstract class DBObject implements iDisplay
protected function LogCRUDEnter($sFunction, $sComment = '')
{
$sClass = get_class($this);
if (utils::StartsWith($sClass, 'CMDBChange')) {
return;
}
$sKey = $this->GetKey();
$sUUID = $this->m_sObjectUniqId;
$sPadding = str_pad('', count(self::$m_aCrudStack), '-');
IssueLog::Debug("CRUD +$sPadding> $sFunction $sClass:$sKey ($sUUID) $sComment", LogChannels::DM_CRUD);
IssueLog::Debug("CRUD +$sPadding> $sFunction $sClass:$sKey $sComment", LogChannels::DM_CRUD);
}
protected function LogCRUDExit($sFunction, $sComment = '')
{
$sClass = get_class($this);
if (utils::StartsWith($sClass, 'CMDBChange')) {
return;
}
$sKey = $this->GetKey();
$sUUID = $this->m_sObjectUniqId;
$sPadding = str_pad('', count(self::$m_aCrudStack), '-');
if (strlen($sComment) === 0) {
IssueLog::Trace("CRUD <$sPadding+ $sFunction $sClass:$sKey", LogChannels::DM_CRUD);
} else {
IssueLog::Debug("CRUD <$sPadding+ $sFunction $sClass:$sKey ($sUUID) $sComment", LogChannels::DM_CRUD);
IssueLog::Debug("CRUD <$sPadding+ $sFunction $sClass:$sKey $sComment", LogChannels::DM_CRUD);
}
}
protected function LogCRUDDebug($sFunction, $sComment = '')
{
$sClass = get_class($this);
if (utils::StartsWith($sClass, 'CMDBChange')) {
return;
}
$sKey = $this->GetKey();
$sUUID = $this->m_sObjectUniqId;
$sPadding = str_pad('', count(self::$m_aCrudStack), '-');
IssueLog::Debug("CRUD --$sPadding $sFunction $sClass:$sKey ($sUUID) $sComment", LogChannels::DM_CRUD);
IssueLog::Debug("CRUD --$sPadding $sFunction $sClass:$sKey $sComment", LogChannels::DM_CRUD);
}
protected function LogCRUDError($sFunction, $sComment = '')
{
$sClass = get_class($this);
if (utils::StartsWith($sClass, 'CMDBChange')) {
return;
}
$sKey = $this->GetKey();
$sUUID = $this->m_sObjectUniqId;
$sPadding = str_pad('', count(self::$m_aCrudStack), '!');
IssueLog::Error("CRUD !!$sPadding Error $sFunction $sClass:$sKey ($sUUID) $sComment", LogChannels::DM_CRUD);
IssueLog::Error("CRUD !!$sPadding Error $sFunction $sClass:$sKey $sComment", LogChannels::DM_CRUD);
}
/**

View File

@@ -51,7 +51,7 @@ class DBProperty extends DBObject
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("value", array("allowed_values"=>null, "sql"=>"value", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("change_date", array("allowed_values"=>null, "sql"=>"change_date", "default_value"=>"NOW()", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("change_date", array("allowed_values"=>null, "sql"=>"change_date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("change_comment", array("allowed_values"=>null, "sql"=>"change_comment", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
}

View File

@@ -206,7 +206,7 @@ class Dict
}
try{
return utils::VSprintf($sLocalizedFormat, $aArguments);
return vsprintf($sLocalizedFormat, $aArguments);
} catch(\Throwable $e){
\IssueLog::Error("Cannot format dict key", null, ["sFormatCode" => $sFormatCode, "sLangCode" => $sLangCode, 'exception_msg' => $e->getMessage() ]);
return $sFormatCode.' - '.implode(', ', $aArguments);

View File

@@ -1470,8 +1470,8 @@ class DisplayableGraph extends SimpleGraph
try {
$this->InitFromGraphviz();
$sExportAsPdfURL = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=relation_pdf&relation='.$sRelation.'&direction='.($this->bDirectionDown ? 'down' : 'up');
$sContext = $oAppContext->GetForLink(true);
$sDrillDownURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=details&class=%1$s&id=%2$s'.$sContext;
$sContext = $oAppContext->GetForLink();
$sDrillDownURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=details&class=%1$s&id=%2$s&'.$sContext;
$sExportAsDocumentURL = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=relation_attachment&relation='.$sRelation.'&direction='.($this->bDirectionDown ? 'down' : 'up');
$sLoadFromURL = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=relation_json&relation='.$sRelation.'&direction='.($this->bDirectionDown ? 'down' : 'up');
$sAttachmentExportTitle = '';

View File

@@ -39,7 +39,7 @@ class Event extends DBObject implements iDisplay
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>"NOW()", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));

View File

@@ -278,7 +278,7 @@ class HTMLDOMSanitizer extends DOMSanitizer
protected static $aTagsWhiteList = array(
'html' => array(),
'body' => array(),
'a' => array('href', 'name', 'style', 'class', 'target', 'title', 'data-role', 'data-object-class', 'data-object-id', 'data-object-key'),
'a' => array('href', 'name', 'style', 'class', 'target', 'title', 'data-role', 'data-object-class', 'data-object-id'),
'p' => array('style', 'class'),
'blockquote' => array('style', 'class'),
'br' => array(),
@@ -354,8 +354,6 @@ class HTMLDOMSanitizer extends DOMSanitizer
'font-style',
'height',
'margin',
'margin-left',
'margin-right',
'padding',
'text-align',
'vertical-align',

View File

@@ -54,7 +54,7 @@ class InlineImage extends DBObject
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeDateTime("expire", array("allowed_values" => null, "sql" => 'expire', "default_value" => 'DATE_ADD(NOW(), INTERVAL 1 DAY)', "is_null_allowed" => false, "depends_on" => array(), "always_load_in_tables" => false)));
MetaModel::Init_AddAttribute(new AttributeDateTime("expire", array("allowed_values"=>null, "sql"=>'expire', "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array(), "always_load_in_tables"=>false)));
MetaModel::Init_AddAttribute(new AttributeString("temp_id", array("allowed_values"=>null, "sql"=>'temp_id', "default_value"=>'', "is_null_allowed"=>true, "depends_on"=>array(), "always_load_in_tables"=>false)));
MetaModel::Init_AddAttribute(new AttributeString("item_class", array("allowed_values"=>null, "sql"=>'item_class', "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array(), "always_load_in_tables"=>false)));
MetaModel::Init_AddAttribute(new AttributeObjectKey("item_id", array("class_attcode"=>'item_class', "allowed_values"=>null, "sql"=>'item_id', "is_null_allowed"=>true, "depends_on"=>array(), "always_load_in_tables"=>false)));

View File

@@ -469,8 +469,7 @@ class ExecutionKPI
// Invoke extensions to log the KPI operation
/** @var \iKPILoggerExtension $oExtensionInstance */
foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) {
//$sExtension = ModuleService::GetInstance()->GetModuleNameFromCallStack(1);
$sExtension = '';
$sExtension = ModuleService::GetInstance()->GetModuleNameFromCallStack(1);
$oKPILogData = new KpiLogData(
KpiLogData::TYPE_STATS,
$sOperation,

View File

@@ -7081,7 +7081,7 @@ abstract class MetaModel
* @param array $aParams
* @param bool $bAllowAllData
*
* @return \DBObject|null
* @return \DBObject
* @throws \OQLException
*/
public static function GetObjectFromOQL($sQuery, $aParams = null, $bAllowAllData = false)

View File

@@ -77,7 +77,7 @@ abstract class ModelReflection
return $sFormatCode.' - '.implode(', ', $aArguments);
}
return utils::VSprintf($sLocalizedFormat, $aArguments);
return vsprintf($sLocalizedFormat, $aArguments);
}
/**

View File

@@ -575,15 +575,6 @@ class BinaryExpression extends Expression
case 'LIKE':
$sType = 'like';
break;
case 'NOT LIKE':
$sType = 'notlike';
break;
case 'IN':
$sType = 'in';
break;
case 'NOT IN':
$sType = 'notin';
break;
default:
throw new Exception("Operator '$sOperator' not yet supported");
}
@@ -648,26 +639,7 @@ class BinaryExpression extends Expression
case 'like':
$sEscaped = preg_quote($mRight, '/');
$sEscaped = str_replace(array('%', '_', '\\\\.*', '\\\\.'), array('.*', '.', '%', '_'), $sEscaped);
$pregRes = preg_match("/$sEscaped/i", $mLeft);
if ($pregRes === false) {
throw new Exception("Error in regular expression '$sEscaped'");
}
$result = ($pregRes === 1);
break;
case 'notlike':
$sEscaped = preg_quote($mRight, '/');
$sEscaped = str_replace(array('%', '_', '\\\\.*', '\\\\.'), array('.*', '.', '%', '_'), $sEscaped);
$pregRes = preg_match("/$sEscaped/i", $mLeft);
if ($pregRes === false) {
throw new Exception("Error in regular expression '$sEscaped'");
}
$result = ($pregRes !== 1);
break;
case 'in':
$result = in_array($mLeft, $mRight);
break;
case 'notin':
$result = !in_array($mLeft, $mRight);
$result = (int) preg_match("/$sEscaped/i", $mLeft);
break;
}
return $result;
@@ -2278,12 +2250,7 @@ class ListExpression extends Expression
*/
public function Evaluate(array $aArgs)
{
//throw new Exception('list expression not yet supported');
$aResult = [];
foreach ($this->m_aExpressions as $oExpressions) {
$aResult[] = $oExpressions->Evaluate($aArgs);
}
return $aResult;
throw new Exception('list expression not yet supported');
}
/**

View File

@@ -48,42 +48,6 @@ class ormDocument
* @since 3.1.0
*/
public const DEFAULT_DOWNLOADS_COUNT = 0;
private static $aKnownExtensions = [
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'gif' => 'image/gif',
'png' => 'image/png',
'pdf' => 'application/pdf',
'doc' => 'application/msword',
'dot' => 'application/msword',
'xls' => 'application/vnd.ms-excel',
'ppt' => 'application/vnd.ms-powerpoint',
'vsd' => 'application/x-visio',
'vdx' => 'application/visio.drawing',
'odt' => 'application/vnd.oasis.opendocument.text',
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
'odp' => 'application/vnd.oasis.opendocument.presentation',
'zip' => 'application/zip',
'txt' => 'text/plain',
'htm' => 'text/html',
'html' => 'text/html',
'exe' => 'application/octet-stream',
];
public static function GetKnownExtensions(): array
{
return self::$aKnownExtensions;
}
protected $m_data;
protected $m_sMimeType;
@@ -112,36 +76,6 @@ class ormDocument
$this->m_iDownloadsCount = $iDownloadsCount;
}
/**
* @param string $sPath Absolute path of the document to read
*
* @return \ormDocument
* @throws \Exception
*/
public static function FromFile(string $sPath): ormDocument
{
$sPath = utils::RealPath($sPath, APPROOT);
if (false === $sPath) {
throw new Exception("Failed to load the file '$sPath'. The file does not exist or the current process is not allowed to access it.");
}
$sData = @file_get_contents($sPath);
if (false === $sData) {
throw new Exception("Failed to load the file '$sPath'. The file does not exist or the current process is not allowed to access it.");
}
$sExtension = strtolower(pathinfo($sPath, PATHINFO_EXTENSION));
$sFileName = basename($sPath);
$sMimeType = 'text/plain';
if (array_key_exists($sExtension, ormDocument::$aKnownExtensions)) {
$sMimeType = ormDocument::$aKnownExtensions[$sExtension];
} else if (extension_loaded('fileinfo')) {
$fInfo = new finfo(FILEINFO_MIME);
$sMimeType = $fInfo->file($sPath);
}
return new ormDocument($sData, $sMimeType, $sFileName);
}
public function __toString()
{
if($this->IsEmpty()) return '';

View File

@@ -42,8 +42,8 @@ class iTopOwnershipToken extends DBObject
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeDateTime("acquired", array("allowed_values"=>null, "sql"=>'acquired', "default_value"=>'NOW()', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("last_seen", array("allowed_values"=>null, "sql"=>'last_seen', "default_value"=>'NOW()', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("acquired", array("allowed_values"=>null, "sql"=>'acquired', "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeDateTime("last_seen", array("allowed_values"=>null, "sql"=>'last_seen', "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("obj_class", array("allowed_values"=>null, "sql"=>'obj_class', "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("obj_key", array("allowed_values"=>null, "sql"=>'obj_key', "default_value"=>'', "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("token", array("allowed_values"=>null, "sql"=>'token', "default_value"=>'', "is_null_allowed"=>true, "depends_on"=>array())));

View File

@@ -44,8 +44,6 @@ class ObjectResult
* @var string
* @api
*/
use SanitizeTrait;
public $message;
/**
* @var mixed|null
@@ -76,52 +74,6 @@ class ObjectResult
$this->fields = array();
}
/**
* Creates an ObjectResult from a DBObject.
*
* @param DBObject $oObj The object.
* @param array|null $aFieldSpec An array of class => attribute codes (Cf. RestUtils::GetFieldList). List of the attributes to be reported.
* @param boolean $bExtendedOutput Output all of the link set attributes ?
* @param integer $iCode An error code (RestResult::OK is no issue has been found)
* @param string $sMessage Description of the error if any, an empty string otherwise
*
* @return ObjectResult
*/
public static function FromDBObject(DBObject $oObj, ?array $aFieldSpec = null, $bExtendedOutput = false, $iCode = 0, $sMessage = '') : ObjectResult {
$oObjRes = new ObjectResult($oObj::class, $oObj->GetKey());
$oObjRes->code = $iCode;
$oObjRes->message = $sMessage;
$aFields = null;
if (!is_null($aFieldSpec))
{
// Enum all classes in the hierarchy, starting with the current one
foreach (MetaModel::EnumParentClasses($oObj::class, ENUM_PARENT_CLASSES_ALL, false) as $sRefClass)
{
if (array_key_exists($sRefClass, $aFieldSpec))
{
$aFields = $aFieldSpec[$sRefClass];
break;
}
}
}
if (is_null($aFields))
{
// No fieldspec given, or not found...
$aFields = array('id', 'friendlyname');
}
foreach ($aFields as $sAttCode)
{
$oObjRes->AddField($oObj, $sAttCode, $bExtendedOutput);
}
return $oObjRes;
}
/**
* Helper to make an output value for a given attribute
*
@@ -204,19 +156,6 @@ class ObjectResult
{
$this->fields[$sAttCode] = $this->MakeResultValue($oObject, $sAttCode, $bExtendedOutput);
}
public function SanitizeContent()
{
foreach($this->fields as $sFieldAttCode => $fieldValue)
{
try {
$oAttDef = MetaModel::GetAttributeDef($this->class, $sFieldAttCode);
} catch (Exception $e) { // for special cases like ID
continue;
}
$this->SanitizeFieldIfSensitive($this->fields, $sFieldAttCode, $fieldValue, $oAttDef);
}
}
}
@@ -250,21 +189,38 @@ class RestResultWithObjects extends RestResult
*/
public function AddObject($iCode, $sMessage, $oObject, $aFieldSpec = null, $bExtendedOutput = false)
{
$oObjRes = ObjectResult::FromDBObject($oObject, $aFieldSpec, $bExtendedOutput, $iCode, $sMessage);
$sClass = get_class($oObject);
$oObjRes = new ObjectResult($sClass, $oObject->GetKey());
$oObjRes->code = $iCode;
$oObjRes->message = $sMessage;
$aFields = null;
if (!is_null($aFieldSpec))
{
// Enum all classes in the hierarchy, starting with the current one
foreach (MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL, false) as $sRefClass)
{
if (array_key_exists($sRefClass, $aFieldSpec))
{
$aFields = $aFieldSpec[$sRefClass];
break;
}
}
}
if (is_null($aFields))
{
// No fieldspec given, or not found...
$aFields = array('id', 'friendlyname');
}
foreach ($aFields as $sAttCode)
{
$oObjRes->AddField($oObject, $sAttCode, $bExtendedOutput);
}
$sObjKey = get_class($oObject).'::'.$oObject->GetKey();
$this->objects[$sObjKey] = $oObjRes;
}
public function SanitizeContent()
{
parent::SanitizeContent();
foreach($this->objects as $sObjKey => $oObjRes)
{
$oObjRes->SanitizeContent();
}
}
}
/**
@@ -352,10 +308,9 @@ class RestDelete
*
* @package Core
*/
class CoreServices implements iRestServiceProvider, iRestInputSanitizer
class CoreServices implements iRestServiceProvider
{
use SanitizeTrait;
/**
/**
* Enumerate services delivered by this class
*
* @param string $sVersion The version (e.g. 1.0) supported by the services
@@ -573,18 +528,18 @@ class CoreServices implements iRestServiceProvider, iRestInputSanitizer
}
else
{
if (!$bExtendedOutput && RestUtils::GetOptionalParam($aParams, 'output_fields', '*') != '*')
if (!$bExtendedOutput && RestUtils::GetOptionalParam($aParams, 'output_fields', '*') != '*')
{
$aFields = $aShowFields[$sClass];
//Id is not a valid attribute to optimize
if (in_array('id', $aFields))
if (in_array('id', $aFields))
{
unset($aFields[array_search('id', $aFields)]);
}
$aAttToLoad = array($oObjectSet->GetClassAlias() => $aFields);
$oObjectSet->OptimizeColumnLoad($aAttToLoad);
}
while ($oObject = $oObjectSet->Fetch())
{
$oResult->AddObject(0, '', $oObject, $aShowFields, $bExtendedOutput);
@@ -782,33 +737,6 @@ class CoreServices implements iRestServiceProvider, iRestInputSanitizer
return $oResult;
}
public function SanitizeJsonInput(string $sJsonInput): string
{
$sSanitizedJsonInput = $sJsonInput;
$aJsonData = json_decode($sSanitizedJsonInput, true);
$sOperation = $aJsonData['operation'];
switch ($sOperation) {
case 'core/check_credentials':
if (isset($aJsonData['password'])) {
$aJsonData['password'] = '*****';
}
break;
case 'core/update':
case 'core/create':
default :
$sClass = $aJsonData['class'];
if (isset($aJsonData['fields'])) {
foreach ($aJsonData['fields'] as $sFieldAttCode => $fieldValue) {
$oAttDef = MetaModel::GetAttributeDef($sClass, $sFieldAttCode);
$this->SanitizeFieldIfSensitive($aJsonData['fields'], $sFieldAttCode, $fieldValue, $oAttDef);
}
}
break;
}
return json_encode($aJsonData, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
}
/**
* Helper for object deletion
*/
@@ -947,50 +875,3 @@ class CoreServices implements iRestServiceProvider, iRestInputSanitizer
return $iLimit * max(0, $iPage - 1);
}
}
trait SanitizeTrait
{
/**
* Sanitize a field if it is sensitive.
*
* @param array $fields The fields array
* @param string $sFieldAttCode The attribute code
* @param mixed $oAttDef The attribute definition
* @throws Exception
*/
private function SanitizeFieldIfSensitive(array &$fields, string $sFieldAttCode, $fieldValue, $oAttDef): void
{
// for simple attribute
if ($oAttDef instanceof iAttributeNoGroupBy) // iAttributeNoGroupBy is equivalent to sensitive attribute
{
$fields[$sFieldAttCode] = '*****';
return;
}
// for 1-n / n-n relation
if ($oAttDef instanceof AttributeLinkedSet) {
foreach ($fieldValue as $i => $aLnkValues) {
foreach ($aLnkValues as $sLnkAttCode => $sLnkValue) {
$oLnkAttDef = MetaModel::GetAttributeDef($oAttDef->GetLinkedClass(), $sLnkAttCode);
if ($oLnkAttDef instanceof iAttributeNoGroupBy) { // 1-n relation
$fields[$sFieldAttCode][$i][$sLnkAttCode] = '*****';
}
elseif ($oAttDef instanceof AttributeLinkedSetIndirect && $oLnkAttDef instanceof AttributeExternalField) { // for n-n relation
$oExtKeyAttDef = MetaModel::GetAttributeDef($oLnkAttDef->GetTargetClass(), $oLnkAttDef->GetExtAttCode());
if ($oExtKeyAttDef instanceof iAttributeNoGroupBy) {
$fields[$sFieldAttCode][$i][$sLnkAttCode] = '*****';
}
}
}
}
return;
}
// for external attribute
if ($oAttDef instanceof AttributeExternalField) {
$oExtKeyAttDef = MetaModel::GetAttributeDef($oAttDef->GetTargetClass(), $oAttDef->GetExtAttCode());
if ($oExtKeyAttDef instanceof iAttributeNoGroupBy) {
$fields[$sFieldAttCode] = '*****';
}
}
}
}

View File

@@ -1921,56 +1921,52 @@ class UserRights
*/
protected static function FindUser($sLogin, $sAuthentication = 'any', $bAllowDisabledUsers = false)
{
if ($sAuthentication === 'any') {
$oUser = self::FindUser($sLogin, 'internal', $bAllowDisabledUsers);
if ($oUser !== null) {
return $oUser;
if ($sAuthentication == 'any')
{
$oUser = self::FindUser($sLogin, 'internal');
if ($oUser == null)
{
$oUser = self::FindUser($sLogin, 'external');
}
}
else
{
if (!isset(self::$m_aCacheUsers))
{
self::$m_aCacheUsers = array('internal' => array(), 'external' => array());
}
return self::FindUser($sLogin, 'external', $bAllowDisabledUsers);
}
if (!isset(self::$m_aCacheUsers[$sAuthentication][$sLogin]))
{
switch($sAuthentication)
{
case 'external':
$sBaseClass = 'UserExternal';
break;
if (!isset(self::$m_aCacheUsers)) {
self::$m_aCacheUsers = [ 'internal' => [], 'external' => [] ];
}
case 'internal':
$sBaseClass = 'UserInternal';
break;
if (! isset(self::$m_aCacheUsers[$sAuthentication]) || ! array_key_exists($sLogin, self::$m_aCacheUsers[$sAuthentication])) {
switch($sAuthentication) {
case 'external':
$sBaseClass = 'UserExternal';
break;
case 'internal':
$sBaseClass = 'UserInternal';
break;
default:
echo "<p>sAuthentication = $sAuthentication</p>\n";
assert(false); // should never happen
default:
echo "<p>sAuthentication = $sAuthentication</p>\n";
assert(false); // should never happen
}
$oSearch = DBObjectSearch::FromOQL("SELECT $sBaseClass WHERE login = :login");
$oSearch->AllowAllData();
if (!$bAllowDisabledUsers)
{
$oSearch->AddCondition('status', 'enabled');
}
$oSet = new DBObjectSet($oSearch, array(), array('login' => $sLogin));
$oUser = $oSet->fetch();
self::$m_aCacheUsers[$sAuthentication][$sLogin] = $oUser;
}
$oSearch = DBObjectSearch::FromOQL("SELECT $sBaseClass WHERE login = :login");
$oSearch->AllowAllData();
if (!$bAllowDisabledUsers) {
$oSearch->AddCondition('status', 'enabled');
}
$oSet = new DBObjectSet($oSearch, array(), array('login' => $sLogin));
$oUser = $oSet->fetch();
self::$m_aCacheUsers[$sAuthentication][$sLogin] = $oUser;
$oUser = self::$m_aCacheUsers[$sAuthentication][$sLogin];
}
return self::$m_aCacheUsers[$sAuthentication][$sLogin];
return $oUser;
}
/**
* Reset the cache of users
* @return void
*/
public static function ResetCacheUsers()
{
self::$m_aCacheUsers = [ 'internal' => [], 'external' => [] ];
}
/**
* @param string$sClass
* @param array $aAllowedOrgs
@@ -2129,8 +2125,6 @@ class StimulusChecker extends ActionChecker
{
var $sState = null;
public mixed $iState = null;
public function __construct(DBSearch $oFilter, $sState, $iStimulusCode)
{
parent::__construct($oFilter, $iStimulusCode);

View File

@@ -435,7 +435,7 @@ class ValueSetObjects extends ValueSetDefinition
foreach ($aAdditionalField as $sAdditionalField) {
array_push($aArguments, $oObject->Get($sAdditionalField));
}
$aData['additional_field'] = utils::VSprintf($sFormatAdditionalField, $aArguments);
$aData['additional_field'] = vsprintf($sFormatAdditionalField, $aArguments);
} else {
$aData['additional_field'] = '';
}

View File

@@ -99,28 +99,6 @@ $ibo-color-pink-800: $common-color-pink-800 !default;
$ibo-color-pink-900: $common-color-pink-900 !default;
$ibo-color-pink-950: $common-color-pink-950 !default;
$ibo-color-yellow-100: $common-color-yellow-100 !default;
$ibo-color-yellow-200: $common-color-yellow-200 !default;
$ibo-color-yellow-300: $common-color-yellow-300 !default;
$ibo-color-yellow-400: $common-color-yellow-400 !default;
$ibo-color-yellow-500: $common-color-yellow-500 !default;
$ibo-color-yellow-600: $common-color-yellow-600 !default;
$ibo-color-yellow-700: $common-color-yellow-700 !default;
$ibo-color-yellow-800: $common-color-yellow-800 !default;
$ibo-color-yellow-900: $common-color-yellow-900 !default;
$ibo-color-yellow-950: $common-color-yellow-950 !default;
$ibo-color-purple-100: $common-color-purple-100 !default;
$ibo-color-purple-200: $common-color-purple-200 !default;
$ibo-color-purple-300: $common-color-purple-300 !default;
$ibo-color-purple-400: $common-color-purple-400 !default;
$ibo-color-purple-500: $common-color-purple-500 !default;
$ibo-color-purple-600: $common-color-purple-600 !default;
$ibo-color-purple-700: $common-color-purple-700 !default;
$ibo-color-purple-800: $common-color-purple-800 !default;
$ibo-color-purple-900: $common-color-purple-900 !default;
$ibo-color-purple-950: $common-color-purple-950 !default;
$ibo-colors: $common-colors;
/* CSS variables */
@@ -218,26 +196,4 @@ $ibo-colors: $common-colors;
--ibo-color-pink-800: #{$ibo-color-pink-800};
--ibo-color-pink-900: #{$ibo-color-pink-900};
--ibo-color-pink-950: #{$ibo-color-pink-950};
--ibo-color-yellow-100: #{$ibo-color-yellow-100};
--ibo-color-yellow-200: #{$ibo-color-yellow-200};
--ibo-color-yellow-300: #{$ibo-color-yellow-300};
--ibo-color-yellow-400: #{$ibo-color-yellow-400};
--ibo-color-yellow-500: #{$ibo-color-yellow-500};
--ibo-color-yellow-600: #{$ibo-color-yellow-600};
--ibo-color-yellow-700: #{$ibo-color-yellow-700};
--ibo-color-yellow-800: #{$ibo-color-yellow-800};
--ibo-color-yellow-900: #{$ibo-color-yellow-900};
--ibo-color-yellow-950: #{$ibo-color-yellow-950};
--ibo-color-purple-100: #{$ibo-color-purple-100};
--ibo-color-purple-200: #{$ibo-color-purple-200};
--ibo-color-purple-300: #{$ibo-color-purple-300};
--ibo-color-purple-400: #{$ibo-color-purple-400};
--ibo-color-purple-500: #{$ibo-color-purple-500};
--ibo-color-purple-600: #{$ibo-color-purple-600};
--ibo-color-purple-700: #{$ibo-color-purple-700};
--ibo-color-purple-800: #{$ibo-color-purple-800};
--ibo-color-purple-900: #{$ibo-color-purple-900};
--ibo-color-purple-950: #{$ibo-color-purple-950};
}

View File

@@ -99,26 +99,4 @@ $common-color-pink-800: hsla(322, 60%, 37%, 1) !default;
$common-color-pink-900: hsla(318, 51%, 29%, 1) !default;
$common-color-pink-950: hsla(318, 51%, 21%, 1) !default;
$common-color-yellow-100: hsla(60, 100%, 97.06%, 1) !default;
$common-color-yellow-200: hsla(58.1, 96.92%, 87.25%, 1) !default;
$common-color-yellow-300: hsla(54.69, 91.87%, 75.88%, 1) !default;
$common-color-yellow-400: hsla(51.32, 89.41%, 66.67%, 1) !default;
$common-color-yellow-500: hsla(46.96, 80.9%, 60.98%, 1) !default;
$common-color-yellow-600: hsla(40, 67.2%, 50.98%, 1) !default;
$common-color-yellow-700: hsla(35.53, 71.03%, 41.96%, 1) !default;
$common-color-yellow-800: hsla(31.63, 74.57%, 33.92%, 1) !default;
$common-color-yellow-900: hsla(30, 75.76%, 25.88%, 1) !default;
$common-color-yellow-950: hsla(29, 80%, 17%, 1) !default;
$common-color-purple-100: hsla(251.43, 91.3%, 95.49%, 1) !default;
$common-color-purple-200: hsla(250.5, 95.24%, 91.76%, 1) !default;
$common-color-purple-300: hsla(252.5, 94.74%, 85.1%, 1) !default;
$common-color-purple-400: hsla(255.14, 91.74%, 76.27%, 1) !default;
$common-color-purple-500: hsla(258.31, 89.53%, 66.27%, 1) !default;
$common-color-purple-600: hsla(262.12, 83.26%, 57.84%, 1) !default;
$common-color-purple-700: hsla(263.39, 69.96%, 50.39%, 1) !default;
$common-color-purple-800: hsla(263.36, 69.3%, 42.16%, 1) !default;
$common-color-purple-900: hsla(263.5, 67.42%, 34.9%, 1) !default;
$common-color-purple-950: hsla(263, 71%, 26%, 1) !default;
$common-colors: ('grey', 'blue-grey', 'blue', 'cyan', 'green', 'orange', 'red', 'pink', 'yellow', 'purple', 'primary', 'secondary', 'information', 'success', 'warning', 'danger');
$common-colors: ('grey', 'blue-grey', 'blue', 'cyan', 'green', 'orange', 'red', 'pink', 'primary', 'secondary', 'information', 'success', 'warning', 'danger');

View File

@@ -1,5 +1,4 @@
{
"name": "combodo/authent-cas",
"config" : {
"classmap-authoritative" : true
},

View File

@@ -4,15 +4,15 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "2f342cfe65023402c1e00d88698d52b9",
"content-hash": "d751713988987e9331980363e24189ce",
"packages": [],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {},
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {},
"platform-dev": {},
"plugin-api-version": "2.6.0"
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.1.0"
}

View File

@@ -9,8 +9,8 @@
/**
*
*/
Dict::Add('CS CZ', 'Czech', 'Čeština', array(
Dict::Add('CS CZ', 'Czech', 'Čeština', [
'CAS:Error:UserNotAllowed' => 'Uživatel není oprávněn',
'CAS:Login:SignIn' => 'Přihlásit se prostřednictvím CAS',
'CAS:Login:SignInTooltip' => 'Klikni zde pro příhlášení prostřednictvím CAS serveru',
));
]);

View File

@@ -9,8 +9,8 @@
/**
*
*/
Dict::Add('DA DA', 'Danish', 'Dansk', array(
Dict::Add('DA DA', 'Danish', 'Dansk', [
'CAS:Error:UserNotAllowed' => 'User not allowed~~',
'CAS:Login:SignIn' => 'Sign in with CAS~~',
'CAS:Login:SignInTooltip' => 'Click here to authenticate yourself with the CAS server~~',
));
]);

View File

@@ -9,8 +9,8 @@
/**
*
*/
Dict::Add('DE DE', 'German', 'Deutsch', array(
Dict::Add('DE DE', 'German', 'Deutsch', [
'CAS:Error:UserNotAllowed' => 'Benutzer ist nicht zugelassen',
'CAS:Login:SignIn' => 'Anmeldung mit CAS',
'CAS:Login:SignInTooltip' => 'Hier klicken, um sich am CAS-Server zu authentifizieren',
));
]);

View File

@@ -7,8 +7,8 @@
* @author Miguel Turrubiates <miguel_tf@yahoo.com>
* @notas Utilizar codificación UTF-8 para mostrar acentos y otros caracteres especiales
*/
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [
'CAS:Error:UserNotAllowed' => 'Usuario no permitido',
'CAS:Login:SignIn' => 'Iniciar sesión con CAS',
'CAS:Login:SignInTooltip' => 'Click para autenticarse con servidor CAS',
));
]);

View File

@@ -9,8 +9,8 @@
/**
*
*/
Dict::Add('FR FR', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', [
'CAS:Error:UserNotAllowed' => 'Utilisateur non autorisé',
'CAS:Login:SignIn' => 'S\'identifier avec CAS',
'CAS:Login:SignInTooltip' => 'Cliquer ici pour s\'identifier avec le serveur CAS',
));
]);

View File

@@ -9,8 +9,8 @@
/**
*
*/
Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
Dict::Add('HU HU', 'Hungarian', 'Magyar', [
'CAS:Error:UserNotAllowed' => 'Nem engedélyezett felhasználó',
'CAS:Login:SignIn' => 'Bejelentkezés CAS szerverrel',
'CAS:Login:SignInTooltip' => 'Kattintson ide az azonosításhoz a CAS szerveren',
));
]);

View File

@@ -9,8 +9,8 @@
/**
*
*/
Dict::Add('IT IT', 'Italian', 'Italiano', array(
Dict::Add('IT IT', 'Italian', 'Italiano', [
'CAS:Error:UserNotAllowed' => 'Utente non autorizzato',
'CAS:Login:SignIn' => 'Accedi con CAS',
'CAS:Login:SignInTooltip' => 'Clicca qui per autenticarti con il server CAS',
));
]);

View File

@@ -9,8 +9,8 @@
/**
*
*/
Dict::Add('JA JP', 'Japanese', '日本語', array(
Dict::Add('JA JP', 'Japanese', '日本語', [
'CAS:Error:UserNotAllowed' => 'User not allowed~~',
'CAS:Login:SignIn' => 'Sign in with CAS~~',
'CAS:Login:SignInTooltip' => 'Click here to authenticate yourself with the CAS server~~',
));
]);

View File

@@ -10,8 +10,8 @@
* @author Jeffrey Bostoen <info@jeffreybostoen.be> (2018 - 2022)
*
*/
Dict::Add('NL NL', 'Dutch', 'Nederlands', array(
Dict::Add('NL NL', 'Dutch', 'Nederlands', [
'CAS:Error:UserNotAllowed' => 'Gebruiker heeft onvoldoende rechten.',
'CAS:Login:SignIn' => 'Inloggen met CAS',
'CAS:Login:SignInTooltip' => 'Klik hier om aan te melden via de CAS-server',
));
]);

View File

@@ -9,8 +9,8 @@
/**
*
*/
Dict::Add('PL PL', 'Polish', 'Polski', array(
Dict::Add('PL PL', 'Polish', 'Polski', [
'CAS:Error:UserNotAllowed' => 'Użytkownik niedozwolony',
'CAS:Login:SignIn' => 'Zaloguj się za pomocą CAS',
'CAS:Login:SignInTooltip' => 'Kliknij tutaj, aby uwierzytelnić się na serwerze CAS',
));
]);

View File

@@ -9,8 +9,8 @@
/**
*
*/
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
'CAS:Error:UserNotAllowed' => 'Usuário não permitido',
'CAS:Login:SignIn' => 'Autenticar com CAS',
'CAS:Login:SignInTooltip' => 'Clique aqui para se autenticar no servidor CAS',
));
]);

View File

@@ -10,8 +10,8 @@
* @author Vladimir Kunin <v.b.kunin@gmail.com>
*
*/
Dict::Add('RU RU', 'Russian', 'Русский', array(
Dict::Add('RU RU', 'Russian', 'Русский', [
'CAS:Error:UserNotAllowed' => 'Вход не разрешён',
'CAS:Login:SignIn' => 'Вход через CAS',
'CAS:Login:SignInTooltip' => 'Нажмите здесь, чтобы войти через CAS сервер',
));
]);

View File

@@ -9,8 +9,8 @@
/**
*
*/
Dict::Add('SK SK', 'Slovak', 'Slovenčina', array(
Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
'CAS:Error:UserNotAllowed' => 'User not allowed~~',
'CAS:Login:SignIn' => 'Sign in with CAS~~',
'CAS:Login:SignInTooltip' => 'Click here to authenticate yourself with the CAS server~~',
));
]);

View File

@@ -9,8 +9,8 @@
/**
*
*/
Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
Dict::Add('TR TR', 'Turkish', 'Türkçe', [
'CAS:Error:UserNotAllowed' => 'User not allowed~~',
'CAS:Login:SignIn' => 'Sign in with CAS~~',
'CAS:Login:SignInTooltip' => 'Click here to authenticate yourself with the CAS server~~',
));
]);

View File

@@ -5,8 +5,9 @@
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license https://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'CAS:Error:UserNotAllowed' => '用户被禁止登录',
'CAS:Login:SignIn' => '使用CAS登录',
'CAS:Login:SignInTooltip' => '点击这里使用CAS服务器认证',
));
]);

View File

@@ -5,7 +5,7 @@
SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'authent-cas/3.2.1',
'authent-cas/3.2.0',
array(
// Identification
//

View File

@@ -2,24 +2,6 @@
// autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, $err);
} elseif (!headers_sent()) {
echo $err;
}
}
trigger_error(
$err,
E_USER_ERROR
);
}
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit2f342cfe65023402c1e00d88698d52b9::getLoader();
return ComposerAutoloaderInit1878ad96115c3aa0fa5e9fd9807f5db0::getLoader();

View File

@@ -42,37 +42,35 @@ namespace Composer\Autoload;
*/
class ClassLoader
{
/** @var \Closure(string):void */
private static $includeFile;
/** @var string|null */
/** @var ?string */
private $vendorDir;
// PSR-4
/**
* @var array<string, array<string, int>>
* @var array[]
* @psalm-var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array();
/**
* @var array<string, list<string>>
* @var array[]
* @psalm-var array<string, array<int, string>>
*/
private $prefixDirsPsr4 = array();
/**
* @var list<string>
* @var array[]
* @psalm-var array<string, string>
*/
private $fallbackDirsPsr4 = array();
// PSR-0
/**
* List of PSR-0 prefixes
*
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
*
* @var array<string, array<string, list<string>>>
* @var array[]
* @psalm-var array<string, array<string, string[]>>
*/
private $prefixesPsr0 = array();
/**
* @var list<string>
* @var array[]
* @psalm-var array<string, string>
*/
private $fallbackDirsPsr0 = array();
@@ -80,7 +78,8 @@ class ClassLoader
private $useIncludePath = false;
/**
* @var array<string, string>
* @var string[]
* @psalm-var array<string, string>
*/
private $classMap = array();
@@ -88,29 +87,29 @@ class ClassLoader
private $classMapAuthoritative = false;
/**
* @var array<string, bool>
* @var bool[]
* @psalm-var array<string, bool>
*/
private $missingClasses = array();
/** @var string|null */
/** @var ?string */
private $apcuPrefix;
/**
* @var array<string, self>
* @var self[]
*/
private static $registeredLoaders = array();
/**
* @param string|null $vendorDir
* @param ?string $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
self::initializeIncludeClosure();
}
/**
* @return array<string, list<string>>
* @return string[]
*/
public function getPrefixes()
{
@@ -122,7 +121,8 @@ class ClassLoader
}
/**
* @return array<string, list<string>>
* @return array[]
* @psalm-return array<string, array<int, string>>
*/
public function getPrefixesPsr4()
{
@@ -130,7 +130,8 @@ class ClassLoader
}
/**
* @return list<string>
* @return array[]
* @psalm-return array<string, string>
*/
public function getFallbackDirs()
{
@@ -138,7 +139,8 @@ class ClassLoader
}
/**
* @return list<string>
* @return array[]
* @psalm-return array<string, string>
*/
public function getFallbackDirsPsr4()
{
@@ -146,7 +148,8 @@ class ClassLoader
}
/**
* @return array<string, string> Array of classname => path
* @return string[] Array of classname => path
* @psalm-var array<string, string>
*/
public function getClassMap()
{
@@ -154,7 +157,8 @@ class ClassLoader
}
/**
* @param array<string, string> $classMap Class to filename map
* @param string[] $classMap Class to filename map
* @psalm-param array<string, string> $classMap
*
* @return void
*/
@@ -171,25 +175,24 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param list<string>|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*
* @return void
*/
public function add($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
$paths,
(array) $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
$paths
(array) $paths
);
}
@@ -198,19 +201,19 @@ class ClassLoader
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = $paths;
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$paths,
(array) $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
$paths
(array) $paths
);
}
}
@@ -219,9 +222,9 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param list<string>|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*
@@ -229,18 +232,17 @@ class ClassLoader
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
$paths,
(array) $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
$paths
(array) $paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
@@ -250,18 +252,18 @@ class ClassLoader
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = $paths;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$paths,
(array) $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
$paths
(array) $paths
);
}
}
@@ -270,8 +272,8 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param list<string>|string $paths The PSR-0 base directories
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 base directories
*
* @return void
*/
@@ -288,8 +290,8 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param list<string>|string $paths The PSR-4 base directories
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*
@@ -423,8 +425,7 @@ class ClassLoader
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
$includeFile = self::$includeFile;
$includeFile($file);
includeFile($file);
return true;
}
@@ -475,9 +476,9 @@ class ClassLoader
}
/**
* Returns the currently registered loaders keyed by their corresponding vendor directories.
* Returns the currently registered loaders indexed by their corresponding vendor directories.
*
* @return array<string, self>
* @return self[]
*/
public static function getRegisteredLoaders()
{
@@ -554,26 +555,18 @@ class ClassLoader
return false;
}
/**
* @return void
*/
private static function initializeIncludeClosure()
{
if (self::$includeFile !== null) {
return;
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
*/
self::$includeFile = \Closure::bind(static function($file) {
include $file;
}, null, null);
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
* @private
*/
function includeFile($file)
{
include $file;
}

View File

@@ -21,31 +21,11 @@ use Composer\Semver\VersionParser;
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
* To require its presence, you can require `composer-runtime-api ^2.0`
*
* @final
*/
class InstalledVersions
{
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
*/
private static $installed;
/**
* @var bool
*/
private static $installedIsLocalDir;
/**
* @var bool|null
*/
private static $canGetVendors;
/**
* @var array[]
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static $installedByVendor = array();
/**
@@ -103,7 +83,7 @@ class InstalledVersions
{
foreach (self::getInstalled() as $installed) {
if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']);
}
}
@@ -124,7 +104,7 @@ class InstalledVersions
*/
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints((string) $constraint);
$constraint = $parser->parseConstraints($constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
@@ -248,7 +228,7 @@ class InstalledVersions
/**
* @return array
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
*/
public static function getRootPackage()
{
@@ -262,7 +242,7 @@ class InstalledVersions
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[]
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
*/
public static function getRawData()
{
@@ -285,7 +265,7 @@ class InstalledVersions
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
*/
public static function getAllRawData()
{
@@ -308,23 +288,17 @@ class InstalledVersions
* @param array[] $data A vendor/composer/installed.php data set
* @return void
*
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
*/
public static function reload($data)
{
self::$installed = $data;
self::$installedByVendor = array();
// when using reload, we disable the duplicate protection to ensure that self::$installed data is
// always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
// so we have to assume it does not, and that may result in duplicate data being returned when listing
// all installed packages for example
self::$installedIsLocalDir = false;
}
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
*/
private static function getInstalled()
{
@@ -333,27 +307,17 @@ class InstalledVersions
}
$installed = array();
$copiedLocalDir = false;
if (self::$canGetVendors) {
$selfDir = strtr(__DIR__, '\\', '/');
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
$vendorDir = strtr($vendorDir, '\\', '/');
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require $vendorDir.'/composer/installed.php';
self::$installedByVendor[$vendorDir] = $required;
$installed[] = $required;
if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
self::$installed = $required;
self::$installedIsLocalDir = true;
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php';
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
self::$installed = $installed[count($installed) - 1];
}
}
if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
$copiedLocalDir = true;
}
}
}
@@ -361,17 +325,12 @@ class InstalledVersions
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require __DIR__ . '/installed.php';
self::$installed = $required;
self::$installed = require __DIR__ . '/installed.php';
} else {
self::$installed = array();
}
}
if (self::$installed !== array() && !$copiedLocalDir) {
$installed[] = self::$installed;
}
$installed[] = self::$installed;
return $installed;
}

View File

@@ -2,7 +2,7 @@
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(__DIR__);
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(

View File

@@ -2,7 +2,7 @@
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(__DIR__);
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(

View File

@@ -2,7 +2,7 @@
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(__DIR__);
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(

View File

@@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit2f342cfe65023402c1e00d88698d52b9
class ComposerAutoloaderInit1878ad96115c3aa0fa5e9fd9807f5db0
{
private static $loader;
@@ -22,12 +22,21 @@ class ComposerAutoloaderInit2f342cfe65023402c1e00d88698d52b9
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit2f342cfe65023402c1e00d88698d52b9', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInit2f342cfe65023402c1e00d88698d52b9', 'loadClassLoader'));
spl_autoload_register(array('ComposerAutoloaderInit1878ad96115c3aa0fa5e9fd9807f5db0', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
spl_autoload_unregister(array('ComposerAutoloaderInit1878ad96115c3aa0fa5e9fd9807f5db0', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit2f342cfe65023402c1e00d88698d52b9::getInitializer($loader));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit1878ad96115c3aa0fa5e9fd9807f5db0::getInitializer($loader));
} else {
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->setClassMapAuthoritative(true);
$loader->register(true);

View File

@@ -4,7 +4,7 @@
namespace Composer\Autoload;
class ComposerStaticInit2f342cfe65023402c1e00d88698d52b9
class ComposerStaticInit1878ad96115c3aa0fa5e9fd9807f5db0
{
public static $prefixLengthsPsr4 = array (
'C' =>
@@ -31,9 +31,9 @@ class ComposerStaticInit2f342cfe65023402c1e00d88698d52b9
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit2f342cfe65023402c1e00d88698d52b9::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit2f342cfe65023402c1e00d88698d52b9::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit2f342cfe65023402c1e00d88698d52b9::$classMap;
$loader->prefixLengthsPsr4 = ComposerStaticInit1878ad96115c3aa0fa5e9fd9807f5db0::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit1878ad96115c3aa0fa5e9fd9807f5db0::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit1878ad96115c3aa0fa5e9fd9807f5db0::$classMap;
}, null, ClassLoader::class);
}

View File

@@ -1,22 +1,22 @@
<?php return array(
'root' => array(
'name' => 'combodo/authent-cas',
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => '567bdc4200f5edb335a39c4b48fbd18bacb6cfc7',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '5a1627632aa2e605996c1c556c60c2a2cddc0a05',
'name' => '__root__',
'dev' => true,
),
'versions' => array(
'combodo/authent-cas' => array(
'__root__' => array(
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => '567bdc4200f5edb335a39c4b48fbd18bacb6cfc7',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '5a1627632aa2e605996c1c556c60c2a2cddc0a05',
'dev_requirement' => false,
),
),

View File

@@ -11,7 +11,7 @@
* @author Daniel Rokos <daniel.rokos@itopportal.cz>
*
*/
Dict::Add('CS CZ', 'Czech', 'Čeština', array(
Dict::Add('CS CZ', 'Czech', 'Čeština', [
'Class:UserExternal' => 'Externí uživatel',
'Class:UserExternal+' => 'Uživatel definovaný mimo '.ITOP_APPLICATION_SHORT,
));
]);

View File

@@ -10,7 +10,7 @@
* @author Erik Bøg <erik@boegmoeller.dk>
*
*/
Dict::Add('DA DA', 'Danish', 'Dansk', array(
Dict::Add('DA DA', 'Danish', 'Dansk', [
'Class:UserExternal' => 'Extern Bruger',
'Class:UserExternal+' => 'Bruger udenfor '.ITOP_APPLICATION_SHORT,
));
]);

View File

@@ -10,7 +10,7 @@
* @author ITOMIG GmbH <martin.raenker@itomig.de>
*
*/
Dict::Add('DE DE', 'German', 'Deutsch', array(
Dict::Add('DE DE', 'German', 'Deutsch', [
'Class:UserExternal' => 'Externer Benutzer',
'Class:UserExternal+' => 'Extern authentifizierter '.ITOP_APPLICATION_SHORT.'-Benutzer',
));
]);

View File

@@ -7,7 +7,7 @@
* @author Miguel Turrubiates <miguel_tf@yahoo.com>
* @notas Utilizar codificación UTF-8 para mostrar acentos y otros caracteres especiales
*/
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [
'Class:UserExternal' => 'Usuario externo',
'Class:UserExternal+' => 'Usuario autenticado fuera de '.ITOP_APPLICATION_SHORT,
));
]);

View File

@@ -9,7 +9,7 @@
/**
*
*/
Dict::Add('FR FR', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', [
'Class:UserExternal' => 'Utilisateur externe à '.ITOP_APPLICATION_SHORT,
'Class:UserExternal+' => 'Utilisateur authentifié à l\'extérieur de '.ITOP_APPLICATION_SHORT,
));
]);

View File

@@ -9,7 +9,7 @@
/**
*
*/
Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
Dict::Add('HU HU', 'Hungarian', 'Magyar', [
'Class:UserExternal' => 'Külső felhasználó',
'Class:UserExternal+' => '',
));
]);

View File

@@ -9,7 +9,7 @@
/**
*
*/
Dict::Add('IT IT', 'Italian', 'Italiano', array(
Dict::Add('IT IT', 'Italian', 'Italiano', [
'Class:UserExternal' => 'Esterno utente',
'Class:UserExternal+' => 'Utente autenticato al di fuori di '.ITOP_APPLICATION_SHORT,
));
]);

View File

@@ -10,7 +10,7 @@
* @author Hirofumi Kosaka <kosaka@rworks.jp>
*
*/
Dict::Add('JA JP', 'Japanese', '日本語', array(
Dict::Add('JA JP', 'Japanese', '日本語', [
'Class:UserExternal' => '外部ユーザー',
'Class:UserExternal+' => '外部認証ユーザー',
));
]);

View File

@@ -10,7 +10,7 @@
* @author Jeffrey Bostoen <info@jeffreybostoen.be> (2018 - 2022)
*
*/
Dict::Add('NL NL', 'Dutch', 'Nederlands', array(
Dict::Add('NL NL', 'Dutch', 'Nederlands', [
'Class:UserExternal' => 'Externe gebruiker',
'Class:UserExternal+' => 'Gebruiker aangemeld via externe authenticatie',
));
]);

View File

@@ -9,7 +9,7 @@
/**
*
*/
Dict::Add('PL PL', 'Polish', 'Polski', array(
Dict::Add('PL PL', 'Polish', 'Polski', [
'Class:UserExternal' => 'Użytkownik zewnętrzny',
'Class:UserExternal+' => 'Użytkownik uwierzytelniony poza '.ITOP_APPLICATION_SHORT,
));
]);

View File

@@ -9,7 +9,7 @@
/**
*
*/
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
'Class:UserExternal' => 'Usuário externo',
'Class:UserExternal+' => '',
));
]);

View File

@@ -10,7 +10,7 @@
* @author Vladimir Kunin <v.b.kunin@gmail.com>
*
*/
Dict::Add('RU RU', 'Russian', 'Русский', array(
Dict::Add('RU RU', 'Russian', 'Русский', [
'Class:UserExternal' => 'Внешний пользователь',
'Class:UserExternal+' => 'Пользователь, аутентифицируемый вне '.ITOP_APPLICATION_SHORT,
));
]);

View File

@@ -9,7 +9,7 @@
/**
*
*/
Dict::Add('SK SK', 'Slovak', 'Slovenčina', array(
Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
'Class:UserExternal' => 'Externý užívateľ',
'Class:UserExternal+' => 'User authentified outside of '.ITOP_APPLICATION_SHORT.'~~',
));
]);

View File

@@ -10,7 +10,7 @@
* @author Izzet Sirin <izzet.sirin@htr.com.tr>
*
*/
Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
Dict::Add('TR TR', 'Turkish', 'Türkçe', [
'Class:UserExternal' => 'Harici kullanıcı',
'Class:UserExternal+' => ITOP_APPLICATION_SHORT.' dışında yetki kontrolü yapılan kullanıcı',
));
]);

View File

@@ -22,6 +22,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
@@ -31,10 +32,12 @@
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//
// Class: UserExternal
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:UserExternal' => '外部用户',
'Class:UserExternal+' => '用户在'.ITOP_APPLICATION_SHORT.'外部验证身份',
));
]);

View File

@@ -27,7 +27,7 @@
SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'authent-external/3.2.1',
'authent-external/3.2.0',
array(
// Identification
//

View File

@@ -21,10 +21,12 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="login"/>
</attributes>
</naming>
<display_template/>
<style>
<icon/>
</style>

View File

@@ -11,17 +11,8 @@
* @author Daniel Rokos <daniel.rokos@itopportal.cz>
*
*/
Dict::Add('CS CZ', 'Czech', 'Čeština', array(
Dict::Add('CS CZ', 'Czech', 'Čeština', [
'Class:UserLDAP' => 'LDAP uživatel',
'Class:UserLDAP+' => 'Uživatel ověřen přes LDAP',
'UserLDAP:server' => 'Specifika LDAP',
));
//
// Class: UserLDAP
//
Dict::Add('CS CZ', 'Czech', 'Čeština', array(
'Class:UserLDAP/Attribute:ldap_server' => 'Ldap server~~',
'Class:UserLDAP/Attribute:ldap_server+' => '~~',
));
]);

View File

@@ -10,17 +10,8 @@
* @author Erik Bøg <erik@boegmoeller.dk>
*
*/
Dict::Add('DA DA', 'Danish', 'Dansk', array(
Dict::Add('DA DA', 'Danish', 'Dansk', [
'Class:UserLDAP' => 'LDAP-Bruger',
'Class:UserLDAP+' => 'Bruger der godkendes via LDAP',
'UserLDAP:server' => 'LDAP specifics~~',
));
//
// Class: UserLDAP
//
Dict::Add('DA DA', 'Danish', 'Dansk', array(
'Class:UserLDAP/Attribute:ldap_server' => 'Ldap server~~',
'Class:UserLDAP/Attribute:ldap_server+' => '~~',
));
]);

View File

@@ -10,17 +10,10 @@
* @author ITOMIG GmbH <martin.raenker@itomig.de>
*
*/
Dict::Add('DE DE', 'German', 'Deutsch', array(
Dict::Add('DE DE', 'German', 'Deutsch', [
'Class:UserLDAP' => 'LDAP-Benutzer',
'Class:UserLDAP+' => 'Benutzer, der via LDAP authentifiziert wird',
'UserLDAP:server' => 'LDAP-Einstellungen',
));
//
// Class: UserLDAP
//
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:UserLDAP/Attribute:ldap_server' => 'LDAP-Server',
'Class:UserLDAP/Attribute:ldap_server+' => 'Optional: LDAP-Server, der zur Authentifizierung verwendet werden soll, falls mehrere LDAP-Server konfiguriert sind.',
));
'UserLDAP:server' => 'LDAP-Einstellungen',
]);

View File

@@ -40,12 +40,3 @@ Dict::Add('EN US', 'English', 'English', array(
'Class:UserLDAP+' => 'User authenticated by LDAP',
'UserLDAP:server' => 'LDAP specifics',
));
//
// Class: UserLDAP
//
Dict::Add('EN US', 'English', 'English', array(
'Class:UserLDAP/Attribute:ldap_server' => 'Ldap server',
'Class:UserLDAP/Attribute:ldap_server+' => '',
));

View File

@@ -7,17 +7,8 @@
* @author Miguel Turrubiates <miguel_tf@yahoo.com>
* @notas Utilizar codificación UTF-8 para mostrar acentos y otros caracteres especiales
*/
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [
'Class:UserLDAP' => 'Usuario LDAP',
'Class:UserLDAP+' => 'Usuario autenticado vía LDAP',
'UserLDAP:server' => 'Especificaciones LDAP',
));
//
// Class: UserLDAP
//
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Class:UserLDAP/Attribute:ldap_server' => 'Ldap server~~',
'Class:UserLDAP/Attribute:ldap_server+' => '~~',
));
]);

View File

@@ -9,17 +9,8 @@
/**
*
*/
Dict::Add('FR FR', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', [
'Class:UserLDAP' => 'Utilisateur LDAP',
'Class:UserLDAP+' => 'Utilisateur authentifié par un serveur LDAP',
'UserLDAP:server' => 'Champs spécifiques pour LDAP',
));
//
// Class: UserLDAP
//
Dict::Add('FR FR', 'French', 'Français', array(
'Class:UserLDAP/Attribute:ldap_server' => 'Ldap server~~',
'Class:UserLDAP/Attribute:ldap_server+' => '~~',
));
]);

View File

@@ -9,17 +9,8 @@
/**
*
*/
Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
Dict::Add('HU HU', 'Hungarian', 'Magyar', [
'Class:UserLDAP' => 'LDAP felhasználó',
'Class:UserLDAP+' => 'LDAP vagy AD felhasználó',
'UserLDAP:server' => 'LDAP specifics~~',
));
//
// Class: UserLDAP
//
Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'Class:UserLDAP/Attribute:ldap_server' => 'Ldap server~~',
'Class:UserLDAP/Attribute:ldap_server+' => '~~',
));
]);

View File

@@ -9,17 +9,8 @@
/**
*
*/
Dict::Add('IT IT', 'Italian', 'Italiano', array(
Dict::Add('IT IT', 'Italian', 'Italiano', [
'Class:UserLDAP' => 'Utente LDAP',
'Class:UserLDAP+' => 'Utente autenticato da LDAP',
'UserLDAP:server' => 'Specifiche LDAP',
));
//
// Class: UserLDAP
//
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:UserLDAP/Attribute:ldap_server' => 'Ldap server~~',
'Class:UserLDAP/Attribute:ldap_server+' => '~~',
));
]);

View File

@@ -10,17 +10,8 @@
* @author Hirofumi Kosaka <kosaka@rworks.jp>
*
*/
Dict::Add('JA JP', 'Japanese', '日本語', array(
Dict::Add('JA JP', 'Japanese', '日本語', [
'Class:UserLDAP' => 'LDAP ユーザー',
'Class:UserLDAP+' => 'LDAP認証ユーザー',
'UserLDAP:server' => 'LDAP specifics~~',
));
//
// Class: UserLDAP
//
Dict::Add('JA JP', 'Japanese', '日本語', array(
'Class:UserLDAP/Attribute:ldap_server' => 'Ldap server~~',
'Class:UserLDAP/Attribute:ldap_server+' => '~~',
));
]);

View File

@@ -6,21 +6,13 @@
* @license https://opensource.org/licenses/AGPL-3.0
*
*/
/**
* @author Thomas Casteleyn <thomas.casteleyn@super-visions.com>
* @author Jeffrey Bostoen <info@jeffreybostoen.be> (2018 - 2022)
*/
Dict::Add('NL NL', 'Dutch', 'Nederlands', array(
Dict::Add('NL NL', 'Dutch', 'Nederlands', [
'Class:UserLDAP' => 'LDAP-gebruiker',
'Class:UserLDAP+' => 'Gebruiker die aanmeldt via LDAP',
'UserLDAP:server' => 'LDAP informatie',
));
//
// Class: UserLDAP
//
Dict::Add('NL NL', 'Dutch', 'Nederlands', array(
'Class:UserLDAP/Attribute:ldap_server' => 'Ldap server~~',
'Class:UserLDAP/Attribute:ldap_server+' => '~~',
));
]);

View File

@@ -9,17 +9,8 @@
/**
*
*/
Dict::Add('PL PL', 'Polish', 'Polski', array(
Dict::Add('PL PL', 'Polish', 'Polski', [
'Class:UserLDAP' => 'Użytkownik LDAP',
'Class:UserLDAP+' => 'Użytkownik uwierzytelniony przez LDAP',
'UserLDAP:server' => 'Serwer LDAP',
));
//
// Class: UserLDAP
//
Dict::Add('PL PL', 'Polish', 'Polski', array(
'Class:UserLDAP/Attribute:ldap_server' => 'Ldap server~~',
'Class:UserLDAP/Attribute:ldap_server+' => '~~',
));
]);

View File

@@ -9,17 +9,8 @@
/**
*
*/
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
'Class:UserLDAP' => 'Usuário externo via LDAP',
'Class:UserLDAP+' => '',
'UserLDAP:server' => 'LDAP specifics~~',
));
//
// Class: UserLDAP
//
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Class:UserLDAP/Attribute:ldap_server' => 'Ldap server~~',
'Class:UserLDAP/Attribute:ldap_server+' => '~~',
));
]);

View File

@@ -10,17 +10,8 @@
* @author Vladimir Kunin <v.b.kunin@gmail.com>
*
*/
Dict::Add('RU RU', 'Russian', 'Русский', array(
Dict::Add('RU RU', 'Russian', 'Русский', [
'Class:UserLDAP' => 'Пользователь LDAP',
'Class:UserLDAP+' => 'Пользователь, аутентифицируемый через LDAP',
'UserLDAP:server' => 'LDAP specifics~~',
));
//
// Class: UserLDAP
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:UserLDAP/Attribute:ldap_server' => 'Ldap server~~',
'Class:UserLDAP/Attribute:ldap_server+' => '~~',
));
]);

View File

@@ -9,17 +9,8 @@
/**
*
*/
Dict::Add('SK SK', 'Slovak', 'Slovenčina', array(
Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
'Class:UserLDAP' => 'LDAP užívateľ',
'Class:UserLDAP+' => 'User authenticated by LDAP~~',
'UserLDAP:server' => 'LDAP specifics~~',
));
//
// Class: UserLDAP
//
Dict::Add('SK SK', 'Slovak', 'Slovenčina', array(
'Class:UserLDAP/Attribute:ldap_server' => 'Ldap server~~',
'Class:UserLDAP/Attribute:ldap_server+' => '~~',
));
]);

View File

@@ -10,17 +10,8 @@
* @author Izzet Sirin <izzet.sirin@htr.com.tr>
*
*/
Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
Dict::Add('TR TR', 'Turkish', 'Türkçe', [
'Class:UserLDAP' => 'LDAP kullanıcısı',
'Class:UserLDAP+' => 'Yetki kontrolü LDAP tarafından yapılan',
'UserLDAP:server' => 'LDAP specifics~~',
));
//
// Class: UserLDAP
//
Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
'Class:UserLDAP/Attribute:ldap_server' => 'Ldap server~~',
'Class:UserLDAP/Attribute:ldap_server+' => '~~',
));
]);

View File

@@ -21,6 +21,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
@@ -30,20 +31,13 @@
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//
// Class: UserLDAP
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:UserLDAP' => 'LDAP用户',
'Class:UserLDAP+' => '用户身份由LDAP认证',
'UserLDAP:server' => 'LDAP详情',
));
//
// Class: UserLDAP
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Class:UserLDAP/Attribute:ldap_server' => 'Ldap server~~',
'Class:UserLDAP/Attribute:ldap_server+' => '~~',
));
]);

View File

@@ -9,7 +9,7 @@ if (function_exists('ldap_connect'))
SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'authent-ldap/3.2.1',
'authent-ldap/3.2.0',
array(
// Identification
//

View File

@@ -11,24 +11,24 @@
* @author Daniel Rokos <daniel.rokos@itopportal.cz>
*
*/
Dict::Add('CS CZ', 'Czech', 'Čeština', array(
Dict::Add('CS CZ', 'Czech', 'Čeština', [
'Class:UserLocal' => 'interní uživatel '.ITOP_APPLICATION_SHORT,
'Class:UserLocal+' => 'Uživatel ověřen interně v '.ITOP_APPLICATION_SHORT,
'Class:UserLocal/Attribute:password' => 'Heslo',
'Class:UserLocal/Attribute:password+' => '',
'Class:UserLocal/Attribute:expiration' => 'Exspirace hesla',
'Class:UserLocal/Attribute:expiration+' => 'Status exspirace hesla (je vyžadováno rozšíření, aby mělo efekt)',
'Class:UserLocal/Attribute:expiration/Value:can_expire' => 'Může exspirovat',
'Class:UserLocal/Attribute:expiration/Value:can_expire+' => '~~',
'Class:UserLocal/Attribute:expiration/Value:never_expire' => 'Nikdy neexspiruje',
'Class:UserLocal/Attribute:expiration/Value:never_expire+' => '~~',
'Class:UserLocal/Attribute:expiration/Value:force_expire' => 'Exspirován',
'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '~~',
'Class:UserLocal/Attribute:expiration/Value:never_expire' => 'Nikdy neexspiruje',
'Class:UserLocal/Attribute:expiration/Value:never_expire+' => '~~',
'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'Jednorázové heslo',
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Heslo nemůže uživatel změnit.',
'Class:UserLocal/Attribute:password' => 'Heslo',
'Class:UserLocal/Attribute:password+' => '',
'Class:UserLocal/Attribute:password_renewed_date' => 'Heslo bylo obnoveno',
'Class:UserLocal/Attribute:password_renewed_date+' => 'Termín, kdy bylo heslo změneno',
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Nastavení exspirace "Jednorázového hesla" nelze u vlastního účtu uživatele.',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Heslo musí obsahovat minimálně 8 znaků a musí obsahovat minimálně jedno velké písmeno, jedno malé písmeno, jedno číslo a speciální znak.',
'UserLocal:password:expiration' => 'Níže uvedená pole vyžadují rozšíření',
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Nastavení exspirace "Jednorázového hesla" nelze u vlastního účtu uživatele.',
));
]);

Some files were not shown because too many files have changed in this diff Show More