Compare commits

..

1 Commits

Author SHA1 Message Date
Benjamin Dalsass
74e87ed8e3 N°6218 - 1:n & n:n - Read mode: No refresh of tab count on Add/Remove in pop-up 2023-11-14 08:59:46 +01:00
481 changed files with 6660 additions and 15736 deletions

View File

@@ -1,83 +0,0 @@
<!--
IMPORTANT: Please follow the guidelines within this PR template before submitting it, it will greatly help us process your PR. 🙏
Any PRs not following the guidelines or with missing information will not be considered.
-->
## Base information
| Question | Answer
|---------------------------------------------------------------|--------
| Related to a SourceForge thead / Another PR / Combodo ticket? | <!-- Put the URL -->
| Type of change? | Bug fix / Enhancement / Translations
## Symptom (bug) / Objective (enhancement)
<!--
If it's a bug
- Explain the symptom in details
- If possible put error messages, logs or screenshots (you can paste image directly in this editor).
If it's an enhancement
- Describe what is blocking you, what is the objective with as much details as possible.
- Add screenshots if it's related to UI.
-->
## Reproduction procedure (bug)
<!--
Remove this section only if it's NOT a bug.
Otherwise, explain step by step how to reproduce the issue on a standard iTop Community.
If it requires a custom datamodel, provide the minimal XML delta to reproduce it on a standard iTop Community.
-->
1. On iTop x.y.z <!-- Put complete iTop version (eg. 3.1.0-2) -->
2. With PHP x.y.z <!-- Put complete PHP version (eg. 8.1.24) -->
2. First go there
2. Then do that
3. ...
4. Finally, see that...
## Cause (bug)
<!--
Remove this section only if it's NOT a bug.
Otherwise, explain what is the cause of the issue (where in the code and why)
-->
## Proposed solution (bug and enhancement)
<!--
Explain in details how you are proposing to solve this:
- What did you do in the code and why
- If you changed something in the UI, put before / after screenshots (you can paste image directly in this editor)
-->
## Checklist before requesting a review
<!--
Don't remove these lines, check them once done.
-->
- [ ] I have performed a self-review of my code
- [ ] I have tested all changes I made on an iTop instance
- [ ] I have added a unit test, otherwise I have explained why I couldn't
- [ ] Is the PR clear and detailed enough so anyone can understand digging in the code?
## Checklist of things to do before PR is ready to merge
<!--
Things that needs to be done in the PR before it can be considered as ready to be merged
Examples:
- Changes requested in the review
- Unit test to add
- Dictionary entries to translate
- ...
-->
- [ ] ...
- [ ] ...
- [ ] ...

View File

@@ -1,16 +0,0 @@
name: Add PRs to Combodo PRs Dashboard
on:
pull_request_target:
types:
- opened
jobs:
add-to-project:
name: Add PR to Combodo Project
runs-on: ubuntu-latest
steps:
- uses: actions/add-to-project@v1.0.2
with:
project-url: https://github.com/orgs/Combodo/projects/5
github-token: ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}

View File

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

View File

@@ -26,7 +26,7 @@ $iTopFolder = __DIR__ . "/../../" ;
require_once ("$iTopFolder/approot.inc.php"); require_once ("$iTopFolder/approot.inc.php");
require_once (APPROOT."/setup/setuputils.class.inc.php"); require_once (APPROOT."/setup/setuputils.class.inc.php");
if (PHP_SAPI !== 'cli') if (php_sapi_name() !== 'cli')
{ {
throw new \Exception('This script can only run from CLI'); throw new \Exception('This script can only run from CLI');
} }
@@ -70,4 +70,4 @@ if (false === empty($aMissing)) {
echo "Some new tests dirs exists !\n" echo "Some new tests dirs exists !\n"
.' They must be declared either in the allowed or denied list in '.iTopComposer::class." (see N°2651).\n" .' They must be declared either in the allowed or denied list in '.iTopComposer::class." (see N°2651).\n"
.' List of dirs:'."\n".var_export($aMissing, true); .' List of dirs:'."\n".var_export($aMissing, true);
} }

View File

@@ -107,8 +107,7 @@ We would like to give a special thank you 🤗 to the people from the community
- Rudner, Björn (a.k.a [@rudnerbjoern](https://github.com/rudnerbjoern)) - Rudner, Björn (a.k.a [@rudnerbjoern](https://github.com/rudnerbjoern))
- Seki, Shoji - Seki, Shoji
- Shilov, Vladimir - Shilov, Vladimir
- Stukalov, Ilya (a.k.a [@ilya](https://www.github.com/ilya-stukalov)) - Stukalov, Ilya (a.k.a [@ilya](https://www.github.com/ilya)-stukalov)
- Tarjányi, Csaba (a.k.a [@tacsaby](https://github.com/tacsaby))
- Tulio, Marco - Tulio, Marco
- Turrubiates, Miguel - Turrubiates, Miguel

View File

@@ -933,9 +933,8 @@ class UserRightsProfile extends UserRightsAddOnAPI
} }
/** /**
* @param string $sClass * Find out which attribute is corresponding the the dimension 'owner org'
* @return string|null Find out which attribute is corresponding the dimension 'owner org' * returns null if no such attribute has been found (no filtering should occur)
* returns null if no such attribute has been found (no filtering should occur)
*/ */
public static function GetOwnerOrganizationAttCode($sClass) public static function GetOwnerOrganizationAttCode($sClass)
{ {

View File

@@ -580,10 +580,10 @@ class UserRightsProfile extends UserRightsAddOnAPI
/** /**
* Read and cache organizations allowed to the given user * Read and cache organizations allowed to the given user
* *
* @param User $oUser * @param $oUser
* @param string $sClass (not used here but can be used in overloads) * @param $sClass (not used here but can be used in overloads)
* *
* @return array keys of the User allowed org * @return array
* @throws \CoreException * @throws \CoreException
* @throws \Exception * @throws \Exception
*/ */

View File

@@ -2015,8 +2015,6 @@ class RestUtils
* *
* @return DBObject The object found * @return DBObject The object found
* @throws Exception If the input structure is not valid or it could not find exactly one object * @throws Exception If the input structure is not valid or it could not find exactly one object
*
* @see DBObject::CheckChangedExtKeysValues() generic method to check that we can access the linked object isn't used in that use case because values can be literal, OQL, friendlyname
*/ */
public static function FindObjectFromKey($sClass, $key, $bAllowNullValue = false) public static function FindObjectFromKey($sClass, $key, $bAllowNullValue = false)
{ {
@@ -2103,16 +2101,8 @@ class RestUtils
elseif (is_string($key)) elseif (is_string($key))
{ {
// OQL // OQL
try { $oSearch = DBObjectSearch::FromOQL($key);
$oSearch = DBObjectSearch::FromOQL($key); }
} catch (Exception $e) {
throw new CoreOqlException('Query failed to execute', [
'query' => $key,
'exception_class' => get_class($e),
'exception_message' => $e->getMessage(),
]);
}
}
else else
{ {
throw new Exception("Wrong format for key"); throw new Exception("Wrong format for key");

View File

@@ -86,7 +86,7 @@ class lnkAuditCategoryToAuditDomain extends cmdbAbstractObject
{ {
$aParams = array $aParams = array
( (
"category" => "application,grant_by_profile", "category" => "application, grant_by_profile",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "", "name_attcode" => "",
"state_attcode" => "", "state_attcode" => "",

View File

@@ -134,8 +134,6 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
/** @var string */ /** @var string */
public const ENUM_INPUT_TYPE_TAGSET = 'tagset'; public const ENUM_INPUT_TYPE_TAGSET = 'tagset';
/** @var string */ /** @var string */
public const ENUM_INPUT_TYPE_TAGSET_LINKEDSET = 'tagset_linkedset';
/** @var string */
public const ENUM_INPUT_TYPE_RADIO = 'radio'; public const ENUM_INPUT_TYPE_RADIO = 'radio';
/** @var string */ /** @var string */
public const ENUM_INPUT_TYPE_CHECKBOX = 'checkbox'; public const ENUM_INPUT_TYPE_CHECKBOX = 'checkbox';
@@ -2361,7 +2359,6 @@ EOF
case 'LinkedSet': case 'LinkedSet':
if ($oAttDef->GetDisplayStyle() === LINKSET_DISPLAY_STYLE_PROPERTY) { if ($oAttDef->GetDisplayStyle() === LINKSET_DISPLAY_STYLE_PROPERTY) {
$sInputType = self::ENUM_INPUT_TYPE_TAGSET_LINKEDSET;
if (array_key_exists('bulk_context', $aArgs)) { if (array_key_exists('bulk_context', $aArgs)) {
$oTagSetBlock = LinkSetUIBlockFactory::MakeForBulkLinkSet($iId, $oAttDef, $value, $sWizardHelperJsVarName, $aArgs['bulk_context']); $oTagSetBlock = LinkSetUIBlockFactory::MakeForBulkLinkSet($iId, $oAttDef, $value, $sWizardHelperJsVarName, $aArgs['bulk_context']);
} else { } else {
@@ -3712,7 +3709,7 @@ HTML;
if ($oAttDef->GetEditClass() == 'Document') { if ($oAttDef->GetEditClass() == 'Document') {
/** @var \ormDocument $oDocument */ /** @var \ormDocument $oDocument */
$oDocument = $this->Get($sAttCode); $oDocument = $this->Get($sAttCode);
if (is_object($oDocument) && !$oDocument->IsEmpty()) { if (!$oDocument->IsEmpty()) {
$sFieldAsHtml = $this->GetAsHTML($sAttCode); $sFieldAsHtml = $this->GetAsHTML($sAttCode);
$sDisplayLabel = Dict::S('UI:OpenDocumentInNewWindow_'); $sDisplayLabel = Dict::S('UI:OpenDocumentInNewWindow_');
@@ -4547,7 +4544,7 @@ HTML;
return $res; return $res;
} }
protected function PostInsertActions(): void public function PostInsertActions(): void
{ {
parent::PostInsertActions(); parent::PostInsertActions();
@@ -4571,9 +4568,6 @@ HTML;
InlineImage::FinalizeInlineImages($this); InlineImage::FinalizeInlineImages($this);
} }
/**
* @deprecated 3.1.1 3.2.0 N°6966 We will have only one DBClone method in the future
*/
protected function DBCloneTracked_Internal($newKey = null) protected function DBCloneTracked_Internal($newKey = null)
{ {
/** @var cmdbAbstractObject $oNewObj */ /** @var cmdbAbstractObject $oNewObj */
@@ -4583,8 +4577,6 @@ HTML;
/** @var \iApplicationObjectExtension $oExtensionInstance */ /** @var \iApplicationObjectExtension $oExtensionInstance */
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance) foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
{ {
$sExtensionClass = get_class($oExtensionInstance);
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnDBInsert()");
$oKPI = new ExecutionKPI(); $oKPI = new ExecutionKPI();
$oExtensionInstance->OnDBInsert($oNewObj, self::GetCurrentChange()); $oExtensionInstance->OnDBInsert($oNewObj, self::GetCurrentChange());
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBInsert'); $oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBInsert');
@@ -4596,7 +4588,6 @@ HTML;
public function DBUpdate() public function DBUpdate()
{ {
$this->LogCRUDEnter(__METHOD__); $this->LogCRUDEnter(__METHOD__);
$res = 0;
try { try {
if (count($this->ListChanges()) === 0) { if (count($this->ListChanges()) === 0) {
@@ -4616,7 +4607,7 @@ HTML;
return $res; return $res;
} }
protected function PostUpdateActions(array $aChanges): void public function PostUpdateActions(array $aChanges): void
{ {
parent::PostUpdateActions($aChanges); parent::PostUpdateActions($aChanges);
@@ -4657,7 +4648,6 @@ HTML;
if (static::IsCrudStackEmpty()) { if (static::IsCrudStackEmpty()) {
// Avoid signaling the current object that links were modified // Avoid signaling the current object that links were modified
static::RemoveObjectAwaitingEventDbLinksChanged(get_class($this), $this->GetKey()); static::RemoveObjectAwaitingEventDbLinksChanged(get_class($this), $this->GetKey());
$this->LogCRUDDebug(__METHOD__, var_export(self::$aObjectsAwaitingEventDbLinksChanged, true));
static::FireEventDbLinksChangedForAllObjects(); static::FireEventDbLinksChangedForAllObjects();
} }
} }
@@ -4666,37 +4656,12 @@ HTML;
return $oDeletionPlan; return $oDeletionPlan;
} }
final protected function PreDeleteActions(): void protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
{
/** @var \iApplicationObjectExtension $oExtensionInstance */
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
{
$sExtensionClass = get_class($oExtensionInstance);
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnDBDelete()");
$oKPI = new ExecutionKPI();
$oExtensionInstance->OnDBDelete($this, self::GetCurrentChange());
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBDelete');
}
parent::PreDeleteActions();
}
final protected function PostDeleteActions(): void
{
parent::PostDeleteActions();
}
/**
* @deprecated 3.1.1 3.2.0 N°6967 We will have only one DBDelete method in the future
*/
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
{ {
// Invoke extensions before the deletion (the deletion will do some cleanup and we might loose some information // Invoke extensions before the deletion (the deletion will do some cleanup and we might loose some information
/** @var \iApplicationObjectExtension $oExtensionInstance */ /** @var \iApplicationObjectExtension $oExtensionInstance */
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance) foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
{ {
$sExtensionClass = get_class($oExtensionInstance);
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnDBDelete()");
$oKPI = new ExecutionKPI(); $oKPI = new ExecutionKPI();
$oExtensionInstance->OnDBDelete($this, self::GetCurrentChange()); $oExtensionInstance->OnDBDelete($this, self::GetCurrentChange());
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBDelete'); $oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBDelete');
@@ -4718,7 +4683,6 @@ HTML;
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance) foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
{ {
$sExtensionClass = get_class($oExtensionInstance); $sExtensionClass = get_class($oExtensionInstance);
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnIsModified()");
$oKPI = new ExecutionKPI(); $oKPI = new ExecutionKPI();
$bIsModified = $oExtensionInstance->OnIsModified($this); $bIsModified = $oExtensionInstance->OnIsModified($this);
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnIsModified'); $oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnIsModified');
@@ -4778,8 +4742,6 @@ HTML;
/** @var \iApplicationObjectExtension $oExtensionInstance */ /** @var \iApplicationObjectExtension $oExtensionInstance */
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance) foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
{ {
$sExtensionClass = get_class($oExtensionInstance);
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnCheckToWrite()");
$oKPI = new ExecutionKPI(); $oKPI = new ExecutionKPI();
$aNewIssues = $oExtensionInstance->OnCheckToWrite($this); $aNewIssues = $oExtensionInstance->OnCheckToWrite($this);
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnCheckToWrite'); $oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnCheckToWrite');
@@ -4830,8 +4792,6 @@ HTML;
/** @var \iApplicationObjectExtension $oExtensionInstance */ /** @var \iApplicationObjectExtension $oExtensionInstance */
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance) foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
{ {
$sExtensionClass = get_class($oExtensionInstance);
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnCheckToDelete()");
$oKPI = new ExecutionKPI(); $oKPI = new ExecutionKPI();
$aNewIssues = $oExtensionInstance->OnCheckToDelete($this); $aNewIssues = $oExtensionInstance->OnCheckToDelete($this);
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnCheckToDelete'); $oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnCheckToDelete');
@@ -5388,7 +5348,7 @@ EOF
$aErrors = $oObj->UpdateObjectFromPostedForm(''); $aErrors = $oObj->UpdateObjectFromPostedForm('');
$bResult = (count($aErrors) == 0); $bResult = (count($aErrors) == 0);
if ($bResult) { if ($bResult) {
[$bResult, $aErrors] = $oObj->CheckToWrite(); list($bResult, $aErrors) = $oObj->CheckToWrite();
} }
if ($bPreview) { if ($bPreview) {
$sStatus = $bResult ? Dict::S('UI:BulkModifyStatusOk') : Dict::S('UI:BulkModifyStatusError'); $sStatus = $bResult ? Dict::S('UI:BulkModifyStatusOk') : Dict::S('UI:BulkModifyStatusError');
@@ -5405,11 +5365,6 @@ EOF
'errors' => '<p>'.($bResult ? '' : implode('</p><p>', $aErrorsToDisplay)).'</p>', 'errors' => '<p>'.($bResult ? '' : implode('</p><p>', $aErrorsToDisplay)).'</p>',
); );
if ($bResult && (!$bPreview)) { if ($bResult && (!$bPreview)) {
// doing the check will load multiple times same objects :/
// but it shouldn't cost too much on execution time
// user can mitigate by selecting less extkeys/lnk to set and/or less objects to update 🤷‍♂️
$oObj->CheckChangedExtKeysValues();
$oObj->DBUpdate(); $oObj->DBUpdate();
} }
} }
@@ -5958,7 +5913,7 @@ JS
final protected function FireEventAfterWrite(array $aChanges, bool $bIsNew): void final protected function FireEventAfterWrite(array $aChanges, bool $bIsNew): void
{ {
$this->NotifyAttachedObjectsOnLinkClassModification(); $this->NotifyAttachedObjectsOnLinkClassModification();
$this->RemoveObjectAwaitingEventDbLinksChanged(get_class($this), $this->GetKey()); $this->FireEventDbLinksChangedForCurrentObject();
$this->FireEvent(EVENT_DB_AFTER_WRITE, ['is_new' => $bIsNew, 'changes' => $aChanges]); $this->FireEvent(EVENT_DB_AFTER_WRITE, ['is_new' => $bIsNew, 'changes' => $aChanges]);
} }
@@ -5978,16 +5933,6 @@ JS
$this->FireEvent(EVENT_DB_CHECK_TO_DELETE, ['deletion_plan' => $oDeletionPlan]); $this->FireEvent(EVENT_DB_CHECK_TO_DELETE, ['deletion_plan' => $oDeletionPlan]);
} }
/**
* @return void
* @throws \CoreException
* @since 3.1.2
*/
final protected function FireEventAboutToDelete(): void
{
$this->FireEvent(EVENT_DB_ABOUT_TO_DELETE);
}
/** /**
* @return void * @return void
* @throws \CoreException * @throws \CoreException
@@ -5997,63 +5942,47 @@ JS
final protected function FireEventAfterDelete(): void final protected function FireEventAfterDelete(): void
{ {
$this->NotifyAttachedObjectsOnLinkClassModification(); $this->NotifyAttachedObjectsOnLinkClassModification();
$this->FireEventDbLinksChangedForCurrentObject();
$this->FireEvent(EVENT_DB_AFTER_DELETE); $this->FireEvent(EVENT_DB_AFTER_DELETE);
} }
/** /**
* Possibility for linked classes to be notified of current class modification * If the passed object is an instance of a link class, then will register each remote object for modification using {@see static::RegisterObjectAwaitingEventDbLinksChanged()}
*
* If an external key was modified, register also the previous object that was linked previously. * If an external key was modified, register also the previous object that was linked previously.
* *
* @uses static::RegisterObjectAwaitingEventDbLinksChanged() * @throws \ArchivedObjectException
* @throws \CoreException
* @throws \Exception
* *
* @throws ArchivedObjectException * @since 3.1.0 N°5906
* @throws CoreException
* @throws Exception
*
* @since 3.1.0 N°5906 method creation
* @since 3.1.1 3.2.0 N°6228 now just notify attributes having `with_php_computation`
*/ */
final protected function NotifyAttachedObjectsOnLinkClassModification(): void final protected function NotifyAttachedObjectsOnLinkClassModification(): void
{ {
$sClass = get_class($this);
if (false === MetaModel::IsLinkClass($sClass)) {
return;
}
// previous values in case of link change // previous values in case of link change
$aPreviousValues = $this->ListPreviousValuesForUpdatedAttributes(); $aPreviousValues = $this->ListPreviousValuesForUpdatedAttributes();
$sClass = get_class($this);
$aClassExtKeyAttCodes = MetaModel::GetAttributesList($sClass, [AttributeExternalKey::class]);
foreach ($aClassExtKeyAttCodes as $sExternalKeyAttCode) {
/** @var AttributeExternalKey $oAttDef */
$oAttDef = MetaModel::GetAttributeDef($sClass, $sExternalKeyAttCode);
if (false === $this->DoesTargetObjectHavePhpComputation($oAttDef)) { $aLnkClassExternalKeys = MetaModel::GetAttributesList($sClass, [AttributeExternalKey::class]);
continue; foreach ($aLnkClassExternalKeys as $sExternalKeyAttCode) {
/** @var \AttributeExternalKey $oExternalKeyAttDef */
$oExternalKeyAttDef = MetaModel::GetAttributeDef($sClass, $sExternalKeyAttCode);
$sRemoteClassName = $oExternalKeyAttDef->GetTargetClass();
$sRemoteObjectId = $this->Get($sExternalKeyAttCode);
if ($sRemoteObjectId > 0) {
self::RegisterObjectAwaitingEventDbLinksChanged($sRemoteClassName, $sRemoteObjectId);
} }
$sTargetObjectId = $this->Get($sExternalKeyAttCode); $sPreviousRemoteObjectId = $aPreviousValues[$sExternalKeyAttCode] ?? 0;
$sTargetClass = $oAttDef->GetTargetClass(); if ($sPreviousRemoteObjectId > 0) {
if ($sTargetObjectId > 0) { self::RegisterObjectAwaitingEventDbLinksChanged($sRemoteClassName, $sPreviousRemoteObjectId);
$this->LogCRUDDebug(__METHOD__, "Add $sTargetClass:$sTargetObjectId for DBLINKS_CHANGED");
self::RegisterObjectAwaitingEventDbLinksChanged($sTargetClass, $sTargetObjectId);
}
$sPreviousTargetObjectId = $aPreviousValues[$sExternalKeyAttCode] ?? 0;
if ($sPreviousTargetObjectId > 0) {
$this->LogCRUDDebug(__METHOD__, "Add $sTargetClass:$sPreviousTargetObjectId for DBLINKS_CHANGED");
self::RegisterObjectAwaitingEventDbLinksChanged($sTargetClass, $sPreviousTargetObjectId);
} }
} }
} }
private function DoesTargetObjectHavePhpComputation(AttributeExternalKey $oAttDef): bool
{
/** @var AttributeLinkedSet $oAttDefMirrorLink */
$oAttDefMirrorLink = $oAttDef->GetMirrorLinkAttribute();
if (is_null($oAttDefMirrorLink) || false === $oAttDefMirrorLink->HasPHPComputation()){
return false;
}
return true;
}
/** /**
* Register one object for later EVENT_DB_LINKS_CHANGED event. * Register one object for later EVENT_DB_LINKS_CHANGED event.
* *
@@ -6071,6 +6000,26 @@ JS
} }
} }
/**
* Fire the EVENT_DB_LINKS_CHANGED event if current object is registered
*
* @return void
* @throws \ArchivedObjectException
* @throws \CoreException
*
* @since 3.1.0 N°5906
*/
final protected function FireEventDbLinksChangedForCurrentObject(): void
{
if (true === static::IsEventDBLinksChangedBlocked()) {
return;
}
$sClass = get_class($this);
$sId = $this->GetKey();
self::FireEventDbLinksChangedForClassId($sClass, $sId);
}
/** /**
* Fire the EVENT_DB_LINKS_CHANGED event if given object is registered, and unregister it * Fire the EVENT_DB_LINKS_CHANGED event if given object is registered, and unregister it
* *
@@ -6100,22 +6049,17 @@ JS
// We want to avoid launching the listener twice, first here, and secondly after saving the Ticket in the listener // 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 ! // By disabling the event to be fired, we can remove the current object from the attribute !
$oObject = MetaModel::GetObject($sClass, $sId, false); $oObject = MetaModel::GetObject($sClass, $sId, false);
self::FireEventDbLinksChangedForObject($oObject);
self::RemoveObjectAwaitingEventDbLinksChanged($sClass, $sId);
}
private static function FireEventDbLinksChangedForObject(DBObject $oObject)
{
self::SetEventDBLinksChangedBlocked(true);
// N°6408 The object can have been deleted // N°6408 The object can have been deleted
if (!is_null($oObject)) { if (!is_null($oObject)) {
self::SetEventDBLinksChangedBlocked(true);
MetaModel::StartReentranceProtection($oObject);
$oObject->FireEvent(EVENT_DB_LINKS_CHANGED); $oObject->FireEvent(EVENT_DB_LINKS_CHANGED);
MetaModel::StopReentranceProtection($oObject);
// Update the object if needed
if (count($oObject->ListChanges()) !== 0) { if (count($oObject->ListChanges()) !== 0) {
$oObject->DBUpdate(); $oObject->DBUpdate();
} }
} }
self::RemoveObjectAwaitingEventDbLinksChanged($sClass, $sId);
cmdbAbstractObject::SetEventDBLinksChangedBlocked(false); cmdbAbstractObject::SetEventDBLinksChangedBlocked(false);
} }

View File

@@ -187,9 +187,7 @@
</menus> </menus>
<events> <events>
<event id="EVENT_DB_BEFORE_WRITE" _delta="define"> <event id="EVENT_DB_BEFORE_WRITE" _delta="define">
<name>Before create or update</name> <description>An object is about to be written into the database. The object can be modified.</description>
<description><![CDATA[An object is about to be written into the database.
The object can be modified.]]></description>
<sources> <sources>
<source id="cmdbAbstractObject">cmdbAbstractObject</source> <source id="cmdbAbstractObject">cmdbAbstractObject</source>
</sources> </sources>
@@ -210,9 +208,7 @@ The object can be modified.]]></description>
</event_data> </event_data>
</event> </event>
<event id="EVENT_DB_CHECK_TO_WRITE" _delta="define"> <event id="EVENT_DB_CHECK_TO_WRITE" _delta="define">
<name>Check to write</name> <description>Check an object before it is written into the database (no change possible). Call DBObject::AddCheckIssue() to signal an issue</description>
<description><![CDATA[Check an object before it is written into the database (no change possible).
Call $this->AddCheckIssue() to signal an issue.]]></description>
<sources> <sources>
<source id="cmdbAbstractObject">cmdbAbstractObject</source> <source id="cmdbAbstractObject">cmdbAbstractObject</source>
</sources> </sources>
@@ -233,9 +229,7 @@ Call $this->AddCheckIssue() to signal an issue.]]></description>
</event_data> </event_data>
</event> </event>
<event id="EVENT_DB_AFTER_WRITE" _delta="define"> <event id="EVENT_DB_AFTER_WRITE" _delta="define">
<name>After create or update</name> <description>An object has been written into the database. The modifications can be propagated to other objects.</description>
<description><![CDATA[An object has been written into the database.
The modifications can be propagated to other objects.]]></description>
<sources> <sources>
<source id="cmdbAbstractObject">cmdbAbstractObject</source> <source id="cmdbAbstractObject">cmdbAbstractObject</source>
</sources> </sources>
@@ -250,7 +244,7 @@ The modifications can be propagated to other objects.]]></description>
<type>boolean</type> <type>boolean</type>
</event_datum> </event_datum>
<event_datum id="changes"> <event_datum id="changes">
<description><![CDATA[For updates, the list of changes done during this operation]]></description> <description>For updates, the list of changes done during this operation</description>
<type>array</type> <type>array</type>
</event_datum> </event_datum>
<event_datum id="debug_info"> <event_datum id="debug_info">
@@ -260,9 +254,7 @@ The modifications can be propagated to other objects.]]></description>
</event_data> </event_data>
</event> </event>
<event id="EVENT_DB_CHECK_TO_DELETE" _delta="define"> <event id="EVENT_DB_CHECK_TO_DELETE" _delta="define">
<name>Check to delete</name> <description>Check an object before it is deleted from the database. Call DBObject::AddDeleteIssue() to signal an issue</description>
<description><![CDATA[Check an object before it is deleted from the database.
Call $this->AddDeleteIssue() to signal an issue.]]></description>
<sources> <sources>
<source id="cmdbAbstractObject">cmdbAbstractObject</source> <source id="cmdbAbstractObject">cmdbAbstractObject</source>
</sources> </sources>
@@ -278,27 +270,8 @@ Call $this->AddDeleteIssue() to signal an issue.]]></description>
</event_datum> </event_datum>
</event_data> </event_data>
</event> </event>
<event id="EVENT_DB_ABOUT_TO_DELETE" _delta="define">
<name>Before delete</name>
<description><![CDATA[An object is about to be deleted from the database]]></description>
<sources>
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
</sources>
<replaces>cmdbAbstractObject::OnDelete</replaces>
<event_data>
<event_datum id="object">
<description>The object about to be deleted</description>
<type>DBObject</type>
</event_datum>
<event_datum id="debug_info">
<description>Debug string</description>
<type>string</type>
</event_datum>
</event_data>
</event>
<event id="EVENT_DB_AFTER_DELETE" _delta="define"> <event id="EVENT_DB_AFTER_DELETE" _delta="define">
<name>After delete</name> <description>An object has been deleted into the database</description>
<description><![CDATA[An object has been deleted into the database]]></description>
<sources> <sources>
<source id="cmdbAbstractObject">cmdbAbstractObject</source> <source id="cmdbAbstractObject">cmdbAbstractObject</source>
</sources> </sources>
@@ -314,10 +287,8 @@ Call $this->AddDeleteIssue() to signal an issue.]]></description>
</event_datum> </event_datum>
</event_data> </event_data>
</event> </event>
<event id="EVENT_ENUM_TRANSITIONS" _delta="define"> <event id="EVENT_DB_BEFORE_APPLY_STIMULUS" _delta="define">
<name>Enum transitions</name> <description>A stimulus is about to be applied to an object</description>
<description><![CDATA[Manage the allowed transitions in current object state.
The only action allowed is to deny transitions with $this->DenyTransition()]]></description>
<sources> <sources>
<source id="cmdbAbstractObject">cmdbAbstractObject</source> <source id="cmdbAbstractObject">cmdbAbstractObject</source>
</sources> </sources>
@@ -326,9 +297,89 @@ The only action allowed is to deny transitions with $this->DenyTransition()]]></
<description>The object where the stimulus is targeted</description> <description>The object where the stimulus is targeted</description>
<type>DBObject</type> <type>DBObject</type>
</event_datum> </event_datum>
<event_datum id="allowed_stimuli"> <event_datum id="stimulus">
<description>The list of available stimuli in the current state</description> <description>Current stimulus applied</description>
<type>array</type> <type>string</type>
</event_datum>
<event_datum id="previous_state">
<description>Object previous state</description>
<type>string</type>
</event_datum>
<event_datum id="new_state">
<description>Object new state</description>
<type>string</type>
</event_datum>
<event_datum id="save_object">
<description>The object must be saved in the database</description>
<type>boolean</type>
</event_datum>
<event_datum id="debug_info">
<description>Debug string</description>
<type>string</type>
</event_datum>
</event_data>
</event>
<event id="EVENT_DB_AFTER_APPLY_STIMULUS" _delta="define">
<description>A stimulus has been applied to an object</description>
<sources>
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
</sources>
<event_data>
<event_datum id="object">
<description>The object where the stimulus is targeted</description>
<type>DBObject</type>
</event_datum>
<event_datum id="stimulus">
<description>Current stimulus applied</description>
<type>string</type>
</event_datum>
<event_datum id="previous_state">
<description>Object previous state</description>
<type>string</type>
</event_datum>
<event_datum id="new_state">
<description>Object new state</description>
<type>string</type>
</event_datum>
<event_datum id="save_object">
<description>The object is asked to be saved in the database</description>
<type>boolean</type>
</event_datum>
<event_datum id="debug_info">
<description>Debug string</description>
<type>string</type>
</event_datum>
</event_data>
</event>
<event id="EVENT_DB_APPLY_STIMULUS_FAILED" _delta="define">
<description>A stimulus has failed</description>
<sources>
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
</sources>
<event_data>
<event_datum id="action">
<description>The action that failed to apply the stimulus</description>
<type>string</type>
</event_datum>
<event_datum id="object">
<description>The object where the stimulus is targeted</description>
<type>DBObject</type>
</event_datum>
<event_datum id="stimulus">
<description>Current stimulus applied</description>
<type>string</type>
</event_datum>
<event_datum id="previous_state">
<description>Object previous state</description>
<type>string</type>
</event_datum>
<event_datum id="new_state">
<description>Object new state</description>
<type>string</type>
</event_datum>
<event_datum id="save_object">
<description>The object must be saved in the database</description>
<type>boolean</type>
</event_datum> </event_datum>
<event_datum id="debug_info"> <event_datum id="debug_info">
<description>Debug string</description> <description>Debug string</description>
@@ -337,8 +388,7 @@ The only action allowed is to deny transitions with $this->DenyTransition()]]></
</event_data> </event_data>
</event> </event>
<event id="EVENT_DB_LINKS_CHANGED" _delta="define"> <event id="EVENT_DB_LINKS_CHANGED" _delta="define">
<name>Links on object have changed</name> <description>At least one link class was changed</description>
<description><![CDATA[At least one link class was changed]]></description>
<sources> <sources>
<source id="cmdbAbstractObject">cmdbAbstractObject</source> <source id="cmdbAbstractObject">cmdbAbstractObject</source>
</sources> </sources>
@@ -354,9 +404,7 @@ The only action allowed is to deny transitions with $this->DenyTransition()]]></
</event_data> </event_data>
</event> </event>
<event id="EVENT_DB_OBJECT_RELOAD" _delta="define"> <event id="EVENT_DB_OBJECT_RELOAD" _delta="define">
<name>Object reload</name> <description>An object has been re-loaded from the database</description>
<internal>true</internal>
<description><![CDATA[An object has been re-loaded from the database]]></description>
<sources> <sources>
<source id="cmdbAbstractObject">cmdbAbstractObject</source> <source id="cmdbAbstractObject">cmdbAbstractObject</source>
</sources> </sources>
@@ -372,8 +420,7 @@ The only action allowed is to deny transitions with $this->DenyTransition()]]></
</event_data> </event_data>
</event> </event>
<event id="EVENT_DB_COMPUTE_VALUES" _delta="define"> <event id="EVENT_DB_COMPUTE_VALUES" _delta="define">
<name>Recompute object values</name> <description>An object needs to be recomputed after changes</description>
<description><![CDATA[An object needs to be recomputed after changes]]></description>
<sources> <sources>
<source id="cmdbAbstractObject">cmdbAbstractObject</source> <source id="cmdbAbstractObject">cmdbAbstractObject</source>
</sources> </sources>
@@ -390,8 +437,7 @@ The only action allowed is to deny transitions with $this->DenyTransition()]]></
</event_data> </event_data>
</event> </event>
<event id="EVENT_DB_ARCHIVE" _delta="define"> <event id="EVENT_DB_ARCHIVE" _delta="define">
<name>Object archived</name> <description>An object has been archived</description>
<description><![CDATA[An object has been archived]]></description>
<sources> <sources>
<source id="cmdbAbstractObject">cmdbAbstractObject</source> <source id="cmdbAbstractObject">cmdbAbstractObject</source>
</sources> </sources>
@@ -407,8 +453,7 @@ The only action allowed is to deny transitions with $this->DenyTransition()]]></
</event_data> </event_data>
</event> </event>
<event id="EVENT_DB_UNARCHIVE" _delta="define"> <event id="EVENT_DB_UNARCHIVE" _delta="define">
<name>Object unarchived</name> <description>An object has been unarchived</description>
<description><![CDATA[An object has been unarchived]]></description>
<sources> <sources>
<source id="cmdbAbstractObject">cmdbAbstractObject</source> <source id="cmdbAbstractObject">cmdbAbstractObject</source>
</sources> </sources>
@@ -424,9 +469,7 @@ The only action allowed is to deny transitions with $this->DenyTransition()]]></
</event_data> </event_data>
</event> </event>
<event id="EVENT_DB_SET_ATTRIBUTES_FLAGS" _delta="define"> <event id="EVENT_DB_SET_ATTRIBUTES_FLAGS" _delta="define">
<name>Set attributes flags</name> <description>Set object attributes flags. Call cmdbAbstractObject::AddAttributeFlags() for all the attributes to be set for this target state.</description>
<description><![CDATA[Set object attributes flags.
Call $this->AddAttributeFlags() for all the attributes to be set for this target state.]]></description>
<sources> <sources>
<source id="cmdbAbstractObject">cmdbAbstractObject</source> <source id="cmdbAbstractObject">cmdbAbstractObject</source>
</sources> </sources>
@@ -437,7 +480,7 @@ Call $this->AddAttributeFlags() for all the attributes to be set for this target
</event_datum> </event_datum>
<event_datum id="target_state"> <event_datum id="target_state">
<description>The target state in which to evaluate the flags</description> <description>The target state in which to evaluate the flags</description>
<type>string</type> <type>array</type>
</event_datum> </event_datum>
<event_datum id="debug_info"> <event_datum id="debug_info">
<description>Debug string</description> <description>Debug string</description>
@@ -446,9 +489,7 @@ Call $this->AddAttributeFlags() for all the attributes to be set for this target
</event_data> </event_data>
</event> </event>
<event id="EVENT_DB_SET_INITIAL_ATTRIBUTES_FLAGS" _delta="define"> <event id="EVENT_DB_SET_INITIAL_ATTRIBUTES_FLAGS" _delta="define">
<name>Set initial attributes flags</name> <description>Set object initial attributes flags. Call cmdbAbstractObject::AddInitialAttributeFlags() for all the initial attributes to be set initially.</description>
<description><![CDATA[Set object initial attributes flags.
Call $this->AddInitialAttributeFlags() for all the initial attributes to be set initially.]]></description>
<sources> <sources>
<source id="cmdbAbstractObject">cmdbAbstractObject</source> <source id="cmdbAbstractObject">cmdbAbstractObject</source>
</sources> </sources>
@@ -464,8 +505,7 @@ Call $this->AddInitialAttributeFlags() for all the initial attributes to be set
</event_data> </event_data>
</event> </event>
<event id="EVENT_DOWNLOAD_DOCUMENT" _delta="define"> <event id="EVENT_DOWNLOAD_DOCUMENT" _delta="define">
<name>Document downloaded</name> <description>A document has been downloaded from the GUI</description>
<description><![CDATA[A document has been downloaded from the GUI]]></description>
<sources> <sources>
<source id="Document">Document</source> <source id="Document">Document</source>
</sources> </sources>
@@ -485,9 +525,7 @@ Call $this->AddInitialAttributeFlags() for all the initial attributes to be set
</event_data> </event_data>
</event> </event>
<event id="EVENT_LOGIN" _delta="define"> <event id="EVENT_LOGIN" _delta="define">
<name>Login</name> <description>Inform the listeners about the connection states</description>
<internal>true</internal>
<description><![CDATA[Inform the listeners about the connection states]]></description>
<event_data> <event_data>
<event_datum id="code"> <event_datum id="code">
<description>The login step result code (LoginWebPage::EXIT_CODE_...) </description> <description>The login step result code (LoginWebPage::EXIT_CODE_...) </description>

View File

@@ -704,7 +704,7 @@ class DisplayBlock
if ($bDoSearch) if ($bDoSearch)
{ {
// Keep the table_id identifying this table if we're performing a search // Keep the table_id identifying this table if we're performing a search
$sTableId = utils::ReadParam('_table_id_', null, false, utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER); $sTableId = utils::ReadParam('_table_id_', null, false, 'raw_data');
if ($sTableId != null) if ($sTableId != null)
{ {
$aExtraParams['table_id'] = $sTableId; $aExtraParams['table_id'] = $sTableId;

View File

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

View File

@@ -1,36 +0,0 @@
<?php
/**
* @since 2.7.10 3.0.4 3.1.1 3.2.0 N°6458 object creation
*/
class InvalidExternalKeyValueException extends CoreUnexpectedValue
{
private const ENUM_PARAMS_OBJECT = 'current_object';
private const ENUM_PARAMS_ATTCODE = 'attcode';
private const ENUM_PARAMS_ATTVALUE = 'attvalue';
private const ENUM_PARAMS_USER = 'current_user';
public function __construct($oObject, $sAttCode, $aContextData = null, $oPrevious = null)
{
$aContextData[self::ENUM_PARAMS_OBJECT] = get_class($oObject) . '::' . $oObject->GetKey();
$aContextData[self::ENUM_PARAMS_ATTCODE] = $sAttCode;
$aContextData[self::ENUM_PARAMS_ATTVALUE] = $oObject->Get($sAttCode);
$oCurrentUser = UserRights::GetUserObject();
if (false === is_null($oCurrentUser)) {
$aContextData[self::ENUM_PARAMS_USER] = get_class($oCurrentUser) . '::' . $oCurrentUser->GetKey();
}
parent::__construct('Attribute pointing to an object that is either non existing or not readable by the current user', $aContextData, '', $oPrevious);
}
public function GetAttCode(): string
{
return $this->getContextData()[self::ENUM_PARAMS_ATTCODE];
}
public function GetAttValue(): string
{
return $this->getContextData()[self::ENUM_PARAMS_ATTVALUE];
}
}

View File

@@ -119,11 +119,6 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
protected function OnConnected(&$iErrorCode) protected function OnConnected(&$iErrorCode)
{ {
Session::Unset('login_temp_auth_user'); Session::Unset('login_temp_auth_user');
if (is_null(UserRights::GetUserObject())){
//N°7085 avoid infinite loop
IssueLog::Error("No user logged in. exit");
exit(-1);
}
return LoginWebPage::LOGIN_FSM_CONTINUE; return LoginWebPage::LOGIN_FSM_CONTINUE;
} }
@@ -139,4 +134,4 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
} }
} }
} }
} }

View File

@@ -90,7 +90,7 @@ class LoginWebPage extends NiceWebPage
parent::__construct($sTitle); parent::__construct($sTitle);
$this->SetStyleSheet(); $this->SetStyleSheet();
$this->no_cache(); $this->no_cache();
$this->add_http_headers(); $this->add_xframe_options();
} }
public function SetStyleSheet() public function SetStyleSheet()

View File

@@ -103,7 +103,7 @@ class ApplicationMenu
{ {
self::$sFavoriteSiloQuery = $sOQL; self::$sFavoriteSiloQuery = $sOQL;
} }
/** /**
* Get the query used to limit the list of displayed organizations in the drop-down menu * Get the query used to limit the list of displayed organizations in the drop-down menu
* @return string The OQL query returning a list of Organization objects * @return string The OQL query returning a list of Organization objects
@@ -536,7 +536,7 @@ EOF
return -1; return -1;
} }
/** /**
* Retrieves the currently active menu (if any, otherwise the first menu is the default) * Retrieves the currently active menu (if any, otherwise the first menu is the default)
* @return string The Id of the currently active menu * @return string The Id of the currently active menu
@@ -544,7 +544,7 @@ EOF
public static function GetActiveNodeId() public static function GetActiveNodeId()
{ {
$oAppContext = new ApplicationContext(); $oAppContext = new ApplicationContext();
$sMenuId = $oAppContext->GetCurrentValue('menu', null); $sMenuId = $oAppContext->GetCurrentValue('menu', null);
if ($sMenuId === null) if ($sMenuId === null)
{ {
$sMenuId = self::GetDefaultMenuId(); $sMenuId = self::GetDefaultMenuId();
@@ -654,7 +654,7 @@ abstract class MenuNode
/** /**
* Stimulus to check: if the user can 'apply' this stimulus, then she/he can see this menu * Stimulus to check: if the user can 'apply' this stimulus, then she/he can see this menu
*/ */
protected $m_aEnableStimuli; protected $m_aEnableStimuli;
/** /**
@@ -814,7 +814,7 @@ abstract class MenuNode
{ {
return false; return false;
} }
/** /**
* Add a limiting display condition for the same menu node. The conditions will be combined with a AND * Add a limiting display condition for the same menu node. The conditions will be combined with a AND
* @param $oMenuNode MenuNode Another definition of the same menu node, with potentially different access restriction * @param $oMenuNode MenuNode Another definition of the same menu node, with potentially different access restriction
@@ -987,7 +987,7 @@ class TemplateMenuNode extends MenuNode
* @var string * @var string
*/ */
protected $sTemplateFile; protected $sTemplateFile;
/** /**
* Create a menu item based on a custom template and inserts it into the application's main menu * Create a menu item based on a custom template and inserts it into the application's main menu
* @param string $sMenuId Unique identifier of the menu (used to identify the menu for bookmarking, and for getting the labels from the dictionary) * @param string $sMenuId Unique identifier of the menu (used to identify the menu for bookmarking, and for getting the labels from the dictionary)
@@ -1058,7 +1058,7 @@ class OQLMenuNode extends MenuNode
* @var bool|null * @var bool|null
*/ */
protected $bSearchFormOpen; protected $bSearchFormOpen;
/** /**
* Extra parameters to be passed to the display block to fine tune its appearence * Extra parameters to be passed to the display block to fine tune its appearence
*/ */
@@ -1091,7 +1091,7 @@ class OQLMenuNode extends MenuNode
// Enhancement: we could set as the "enable" condition that the user has enough rights to "read" the objects // Enhancement: we could set as the "enable" condition that the user has enough rights to "read" the objects
// of the class specified by the OQL... // of the class specified by the OQL...
} }
/** /**
* Set some extra parameters to be passed to the display block to fine tune its appearence * Set some extra parameters to be passed to the display block to fine tune its appearence
* @param array $aParams paramCode => value. See DisplayBlock::GetDisplay for the meaning of the parameters * @param array $aParams paramCode => value. See DisplayBlock::GetDisplay for the meaning of the parameters
@@ -1111,7 +1111,7 @@ class OQLMenuNode extends MenuNode
*/ */
public function RenderContent(WebPage $oPage, $aExtraParams = array()) public function RenderContent(WebPage $oPage, $aExtraParams = array())
{ {
$oTag = new ContextTag(ContextTag::TAG_OBJECT_SEARCH); ContextTag::AddContext(ContextTag::TAG_OBJECT_SEARCH);
ApplicationMenu::CheckMenuIdEnabled($this->GetMenuId()); ApplicationMenu::CheckMenuIdEnabled($this->GetMenuId());
OQLMenuNode::RenderOQLSearch OQLMenuNode::RenderOQLSearch
( (
@@ -1120,7 +1120,7 @@ class OQLMenuNode extends MenuNode
'Menu_'.$this->GetMenuId(), 'Menu_'.$this->GetMenuId(),
$this->bSearch, // Search pane $this->bSearch, // Search pane
$this->bSearchFormOpen, // Search open $this->bSearchFormOpen, // Search open
$oPage, $oPage,
array_merge($this->m_aParams, $aExtraParams), array_merge($this->m_aParams, $aExtraParams),
true true
); );
@@ -1354,10 +1354,10 @@ class NewObjectMenuNode extends MenuNode
{ {
// Enable this menu, only if the current user has enough rights to create such an object, or an object of // Enable this menu, only if the current user has enough rights to create such an object, or an object of
// any child class // any child class
$aSubClasses = MetaModel::EnumChildClasses($this->sClass, ENUM_CHILD_CLASSES_ALL); // Including the specified class itself $aSubClasses = MetaModel::EnumChildClasses($this->sClass, ENUM_CHILD_CLASSES_ALL); // Including the specified class itself
$bActionIsAllowed = false; $bActionIsAllowed = false;
foreach($aSubClasses as $sCandidateClass) foreach($aSubClasses as $sCandidateClass)
{ {
if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES)) if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES))
@@ -1366,7 +1366,7 @@ class NewObjectMenuNode extends MenuNode
break; // Enough for now break; // Enough for now
} }
} }
return $bActionIsAllowed; return $bActionIsAllowed;
} }
/** /**
@@ -1508,7 +1508,7 @@ class DashboardMenuNode extends MenuNode
throw new Exception("Error: failed to load dashboard file: '{$this->sDashboardFile}'"); throw new Exception("Error: failed to load dashboard file: '{$this->sDashboardFile}'");
} }
} }
} }
/** /**
@@ -1549,7 +1549,7 @@ class ShortcutContainerMenuNode extends MenuNode
$sName = $this->GetMenuId().'_'.$oShortcut->GetKey(); $sName = $this->GetMenuId().'_'.$oShortcut->GetKey();
new ShortcutMenuNode($sName, $oShortcut, $this->GetIndex(), $fRank++); new ShortcutMenuNode($sName, $oShortcut, $this->GetIndex(), $fRank++);
} }
// Complete the tree // Complete the tree
// //
parent::PopulateChildMenus(); parent::PopulateChildMenus();

View File

@@ -71,16 +71,15 @@ class UIHTMLEditorWidget
// To change the default settings of the editor, // To change the default settings of the editor,
// a) edit the file /js/ckeditor/config.js // a) edit the file /js/ckeditor/config.js
// b) or override some of the configuration settings, using the second parameter of ckeditor() // b) or override some of the configuration settings, using the second parameter of ckeditor()
$sJSDefineWidth = '';
$aConfig = utils::GetCkeditorPref(); $aConfig = utils::GetCkeditorPref();
$sWidthSpec = addslashes(trim($this->m_oAttDef->GetWidth())); $sWidthSpec = addslashes(trim($this->m_oAttDef->GetWidth()));
if ($sWidthSpec != '') { if ($sWidthSpec != '')
/*N°6543 - the function min allow to keep text inside the column when width is defined*/ {
$aConfig['width'] = "min($sWidthSpec,100%)"; $aConfig['width'] = $sWidthSpec;
$sJSDefineWidth = '$("#cke_'.$iId.' iframe").contents().find("body").css("width", "'.$sWidthSpec.'")';
} }
$sHeightSpec = addslashes(trim($this->m_oAttDef->GetHeight())); $sHeightSpec = addslashes(trim($this->m_oAttDef->GetHeight()));
if ($sHeightSpec != '') { if ($sHeightSpec != '')
{
$aConfig['height'] = $sHeightSpec; $aConfig['height'] = $sHeightSpec;
} }
$sConfigJS = json_encode($aConfig); $sConfigJS = json_encode($aConfig);
@@ -111,7 +110,6 @@ $('#$iId').on('update', function(evt){
else else
{ {
oMe.data('ckeditorInstance').setReadOnly(oMe.prop('disabled')); oMe.data('ckeditorInstance').setReadOnly(oMe.prop('disabled'));
$sJSDefineWidth
} }
}; };
setTimeout(delayedSetReadOnly, 50); setTimeout(delayedSetReadOnly, 50);

View File

@@ -109,11 +109,6 @@ class utils
* @since 2.7.10 3.0.0 * @since 2.7.10 3.0.0
*/ */
public const ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER = 'element_identifier'; public const ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER = 'element_identifier';
/**
* @var string For XML / HTML node id/class selector
* @since 3.1.2 3.2.1
*/
public const ENUM_SANITIZATION_FILTER_ELEMENT_SELECTOR = 'element_selector';
/** /**
* @var string For variables names * @var string For variables names
* @since 3.0.0 * @since 3.0.0
@@ -243,8 +238,13 @@ class utils
public static function IsModeCLI() public static function IsModeCLI()
{ {
$sCleanName = strtolower(trim(PHP_SAPI)); $sSAPIName = php_sapi_name();
return ($sCleanName === 'cli'); $sCleanName = strtolower(trim($sSAPIName));
if ($sCleanName == 'cli') {
return true;
} else {
return false;
}
} }
/** /**
@@ -367,13 +367,13 @@ class utils
} }
return self::Sanitize($retValue, $defaultValue, $sSanitizationFilter); return self::Sanitize($retValue, $defaultValue, $sSanitizationFilter);
} }
public static function ReadPostedParam($sName, $defaultValue = '', $sSanitizationFilter = 'parameter') public static function ReadPostedParam($sName, $defaultValue = '', $sSanitizationFilter = 'parameter')
{ {
$retValue = isset($_POST[$sName]) ? $_POST[$sName] : $defaultValue; $retValue = isset($_POST[$sName]) ? $_POST[$sName] : $defaultValue;
return self::Sanitize($retValue, $defaultValue, $sSanitizationFilter); return self::Sanitize($retValue, $defaultValue, $sSanitizationFilter);
} }
public static function Sanitize($value, $defaultValue, $sSanitizationFilter) public static function Sanitize($value, $defaultValue, $sSanitizationFilter)
{ {
if ($value === $defaultValue) if ($value === $defaultValue)
@@ -389,7 +389,7 @@ class utils
$retValue = $defaultValue; $retValue = $defaultValue;
} }
} }
return $retValue; return $retValue;
} }
/** /**
@@ -494,17 +494,8 @@ class utils
} }
break; break;
// For XML / HTML node identifiers
case static::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER: case static::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER:
$retValue = preg_replace('/[^a-zA-Z0-9_-]/', '', $value); $retValue = preg_replace('/[^a-zA-Z0-9_-]/', '', $value);
$retValue = filter_var($retValue, FILTER_VALIDATE_REGEXP,
['options' => ['regexp' => '/^[A-Za-z0-9][A-Za-z0-9_-]*$/']]);
break;
// For XML / HTML node id selector
case static::ENUM_SANITIZATION_FILTER_ELEMENT_SELECTOR:
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP,
['options' => ['regexp' => '/^[#\.][A-Za-z0-9][A-Za-z0-9_-]*$/']]);
break; break;
case static::ENUM_SANITIZATION_FILTER_VARIABLE_NAME: case static::ENUM_SANITIZATION_FILTER_VARIABLE_NAME:
@@ -554,11 +545,11 @@ class utils
$sMimeType = self::GetFileMimeType($sTmpName); $sMimeType = self::GetFileMimeType($sTmpName);
$oDocument = new ormDocument($doc_content, $sMimeType, $sName); $oDocument = new ormDocument($doc_content, $sMimeType, $sName);
break; break;
case UPLOAD_ERR_NO_FILE: case UPLOAD_ERR_NO_FILE:
// no file to load, it's a normal case, just return an empty document // no file to load, it's a normal case, just return an empty document
break; break;
case UPLOAD_ERR_FORM_SIZE: case UPLOAD_ERR_FORM_SIZE:
case UPLOAD_ERR_INI_SIZE: case UPLOAD_ERR_INI_SIZE:
throw new FileUploadException(Dict::Format('UI:Error:UploadedFileTooBig', ini_get('upload_max_filesize'))); throw new FileUploadException(Dict::Format('UI:Error:UploadedFileTooBig', ini_get('upload_max_filesize')));
@@ -567,7 +558,7 @@ class utils
case UPLOAD_ERR_PARTIAL: case UPLOAD_ERR_PARTIAL:
throw new FileUploadException(Dict::S('UI:Error:UploadedFileTruncated.')); throw new FileUploadException(Dict::S('UI:Error:UploadedFileTruncated.'));
break; break;
case UPLOAD_ERR_NO_TMP_DIR: case UPLOAD_ERR_NO_TMP_DIR:
throw new FileUploadException(Dict::S('UI:Error:NoTmpDir')); throw new FileUploadException(Dict::S('UI:Error:NoTmpDir'));
break; break;
@@ -580,7 +571,7 @@ class utils
$sName = is_null($sIndex) ? $aFileInfo['name'] : $aFileInfo['name'][$sIndex]; $sName = is_null($sIndex) ? $aFileInfo['name'] : $aFileInfo['name'][$sIndex];
throw new FileUploadException(Dict::Format('UI:Error:UploadStoppedByExtension_FileName', $sName)); throw new FileUploadException(Dict::Format('UI:Error:UploadStoppedByExtension_FileName', $sName));
break; break;
default: default:
throw new FileUploadException(Dict::Format('UI:Error:UploadFailedUnknownCause_Code', $sError)); throw new FileUploadException(Dict::Format('UI:Error:UploadFailedUnknownCause_Code', $sError));
break; break;
@@ -686,17 +677,17 @@ class utils
return $aSelectedObj; return $aSelectedObj;
} }
public static function GetNewTransactionId() public static function GetNewTransactionId()
{ {
return privUITransaction::GetNewTransactionId(); return privUITransaction::GetNewTransactionId();
} }
public static function IsTransactionValid($sId, $bRemoveTransaction = true) public static function IsTransactionValid($sId, $bRemoveTransaction = true)
{ {
return privUITransaction::IsTransactionValid($sId, $bRemoveTransaction); return privUITransaction::IsTransactionValid($sId, $bRemoveTransaction);
} }
public static function RemoveTransaction($sId) public static function RemoveTransaction($sId)
{ {
return privUITransaction::RemoveTransaction($sId); return privUITransaction::RemoveTransaction($sId);
@@ -880,9 +871,9 @@ class utils
$aDateTokens = array_keys($aSpec); $aDateTokens = array_keys($aSpec);
$aDateRegexps = array_values($aSpec); $aDateRegexps = array_values($aSpec);
} }
$sDateRegexp = str_replace($aDateTokens, $aDateRegexps, $sFormat); $sDateRegexp = str_replace($aDateTokens, $aDateRegexps, $sFormat);
if (preg_match('!^(?<head>)'.$sDateRegexp.'(?<tail>)$!', $sDate, $aMatches)) if (preg_match('!^(?<head>)'.$sDateRegexp.'(?<tail>)$!', $sDate, $aMatches))
{ {
$sYear = isset($aMatches['year']) ? $aMatches['year'] : 0; $sYear = isset($aMatches['year']) ? $aMatches['year'] : 0;
@@ -899,7 +890,7 @@ class utils
} }
// http://www.spaweditor.com/scripts/regex/index.php // http://www.spaweditor.com/scripts/regex/index.php
} }
/** /**
* Convert an old date/time format specification (using % placeholders) * Convert an old date/time format specification (using % placeholders)
* to a format compatible with DateTime::createFromFormat * to a format compatible with DateTime::createFromFormat
@@ -1497,7 +1488,7 @@ class utils
$aResult = []; $aResult = [];
// 1st - add standard built-in menu items // 1st - add standard built-in menu items
// //
switch($iMenuId) switch($iMenuId)
{ {
case iPopupMenuExtension::MENU_OBJLIST_ACTIONS: case iPopupMenuExtension::MENU_OBJLIST_ACTIONS:
@@ -1881,7 +1872,7 @@ SQL;
return $sProposed; return $sProposed;
} }
} }
/** /**
* Some characters cause troubles with jQuery when used inside DOM IDs, so let's replace them by the safe _ (underscore) * Some characters cause troubles with jQuery when used inside DOM IDs, so let's replace them by the safe _ (underscore)
* @param string $sId The ID to sanitize * @param string $sId The ID to sanitize
@@ -1891,7 +1882,7 @@ SQL;
{ {
return str_replace(array(':', '[', ']', '+', '-', ' '), '_', $sId); return str_replace(array(':', '[', ']', '+', '-', ' '), '_', $sId);
} }
/** /**
* Helper to execute an HTTP POST request, uses CURL PHP extension * Helper to execute an HTTP POST request, uses CURL PHP extension
* *
@@ -1976,7 +1967,7 @@ SQL;
/** /**
* Get a standard list of character sets * Get a standard list of character sets
* *
* @param array $aAdditionalEncodings Additional values * @param array $aAdditionalEncodings Additional values
* @return array of iconv code => english label, sorted by label * @return array of iconv code => english label, sorted by label
*/ */
@@ -2083,7 +2074,7 @@ SQL;
return $e->getMessage(); return $e->getMessage();
} }
} }
/** /**
* Convert (?) plain text to some HTML markup by replacing newlines by <br/> tags * Convert (?) plain text to some HTML markup by replacing newlines by <br/> tags
* and escaping HTML entities * and escaping HTML entities
@@ -2100,7 +2091,7 @@ SQL;
return str_replace("\n", '<br/>', utils::EscapeHtml($sText)); return str_replace("\n", '<br/>', utils::EscapeHtml($sText));
} }
/** /**
* Eventually compiles the SASS (.scss) file into the CSS (.css) file * Eventually compiles the SASS (.scss) file into the CSS (.css) file
* *
@@ -2214,7 +2205,7 @@ SQL;
case 'image/png': case 'image/png':
$img = @imagecreatefromstring($oImage->GetData()); $img = @imagecreatefromstring($oImage->GetData());
break; break;
default: default:
// Unsupported image type, return the image as-is // Unsupported image type, return the image as-is
//throw new Exception("Unsupported image type: '".$oImage->GetMimeType()."'. Cannot resize the image, original image will be used."); //throw new Exception("Unsupported image type: '".$oImage->GetMimeType()."'. Cannot resize the image, original image will be used.");
@@ -2228,14 +2219,14 @@ SQL;
else else
{ {
// Let's scale the image, preserving the transparency for GIFs and PNGs // Let's scale the image, preserving the transparency for GIFs and PNGs
$fScale = min($iMaxImageWidth / $iWidth, $iMaxImageHeight / $iHeight); $fScale = min($iMaxImageWidth / $iWidth, $iMaxImageHeight / $iHeight);
$iNewWidth = $iWidth * $fScale; $iNewWidth = $iWidth * $fScale;
$iNewHeight = $iHeight * $fScale; $iNewHeight = $iHeight * $fScale;
$new = imagecreatetruecolor($iNewWidth, $iNewHeight); $new = imagecreatetruecolor($iNewWidth, $iNewHeight);
// Preserve transparency // Preserve transparency
if(($oImage->GetMimeType() == "image/gif") || ($oImage->GetMimeType() == "image/png")) if(($oImage->GetMimeType() == "image/gif") || ($oImage->GetMimeType() == "image/png"))
{ {
@@ -2243,38 +2234,38 @@ SQL;
imagealphablending($new, false); imagealphablending($new, false);
imagesavealpha($new, true); imagesavealpha($new, true);
} }
imagecopyresampled($new, $img, 0, 0, 0, 0, $iNewWidth, $iNewHeight, $iWidth, $iHeight); imagecopyresampled($new, $img, 0, 0, 0, 0, $iNewWidth, $iNewHeight, $iWidth, $iHeight);
ob_start(); ob_start();
switch ($oImage->GetMimeType()) switch ($oImage->GetMimeType())
{ {
case 'image/gif': case 'image/gif':
imagegif($new); // send image to output buffer imagegif($new); // send image to output buffer
break; break;
case 'image/jpeg': case 'image/jpeg':
imagejpeg($new, null, 80); // null = send image to output buffer, 80 = good quality imagejpeg($new, null, 80); // null = send image to output buffer, 80 = good quality
break; break;
case 'image/png': case 'image/png':
imagepng($new, null, 5); // null = send image to output buffer, 5 = medium compression imagepng($new, null, 5); // null = send image to output buffer, 5 = medium compression
break; break;
} }
$oResampledImage = new ormDocument(ob_get_contents(), $oImage->GetMimeType(), $oImage->GetFileName()); $oResampledImage = new ormDocument(ob_get_contents(), $oImage->GetMimeType(), $oImage->GetFileName());
@ob_end_clean(); @ob_end_clean();
imagedestroy($img); imagedestroy($img);
imagedestroy($new); imagedestroy($new);
return $oResampledImage; return $oResampledImage;
} }
} }
/** /**
* Create a 128 bit UUID in the format: {########-####-####-####-############} * Create a 128 bit UUID in the format: {########-####-####-####-############}
* *
* Note: this method can be run from the command line as well as from the web server. * Note: this method can be run from the command line as well as from the web server.
* Note2: this method is not cryptographically secure! If you need a cryptographically secure value * Note2: this method is not cryptographically secure! If you need a cryptographically secure value
* consider using open_ssl or PHP 7 methods. * consider using open_ssl or PHP 7 methods.
@@ -2312,7 +2303,7 @@ SQL;
{ {
return ModuleService::GetInstance()->GetCurrentModuleName($iCallDepth + 1); return ModuleService::GetInstance()->GetCurrentModuleName($iCallDepth + 1);
} }
/** /**
* **Warning** : returned result can be invalid as we're using backtrace to find the module dir name * **Warning** : returned result can be invalid as we're using backtrace to find the module dir name
* *
@@ -2349,7 +2340,7 @@ SQL;
{ {
return ModuleService::GetInstance()->GetCurrentModuleUrl(1); return ModuleService::GetInstance()->GetCurrentModuleUrl(1);
} }
/** /**
* @param string $sProperty The name of the property to retrieve * @param string $sProperty The name of the property to retrieve
* @param mixed $defaultvalue * @param mixed $defaultvalue
@@ -2359,7 +2350,7 @@ SQL;
{ {
return ModuleService::GetInstance()->GetCurrentModuleSetting($sProperty, $defaultvalue); return ModuleService::GetInstance()->GetCurrentModuleSetting($sProperty, $defaultvalue);
} }
/** /**
* @param string $sModuleName * @param string $sModuleName
* @return string|NULL compiled version of a given module, as it was seen by the compiler * @return string|NULL compiled version of a given module, as it was seen by the compiler
@@ -2368,7 +2359,7 @@ SQL;
{ {
return ModuleService::GetInstance()->GetCompiledModuleVersion($sModuleName); return ModuleService::GetInstance()->GetCompiledModuleVersion($sModuleName);
} }
/** /**
* Check if the given path/url is an http(s) URL * Check if the given path/url is an http(s) URL
* @param string $sPath * @param string $sPath
@@ -2383,7 +2374,7 @@ SQL;
} }
return $bRet; return $bRet;
} }
/** /**
* Check if the given URL is a link to download a document/image on the CURRENT iTop * Check if the given URL is a link to download a document/image on the CURRENT iTop
* In such a case we can read the content of the file directly in the database (if the users rights allow) and return the ormDocument * In such a case we can read the content of the file directly in the database (if the users rights allow) and return the ormDocument
@@ -2432,7 +2423,7 @@ SQL;
} }
return $result; return $result;
} }
/** /**
* Read the content of a file (and retrieve its MIME type) from either: * Read the content of a file (and retrieve its MIME type) from either:
* - an URL pointing to a blob (image/document) on the current iTop server * - an URL pointing to a blob (image/document) on the current iTop server
@@ -2476,7 +2467,7 @@ SQL;
'html' => 'text/html', 'html' => 'text/html',
'exe' => 'application/octet-stream', 'exe' => 'application/octet-stream',
); );
$sData = null; $sData = null;
$sMimeType = 'text/plain'; // Default MIME Type: treat the file as a bunch a characters... $sMimeType = 'text/plain'; // Default MIME Type: treat the file as a bunch a characters...
$sFileName = 'uploaded-file'; // Default name for downloaded-files $sFileName = 'uploaded-file'; // Default name for downloaded-files
@@ -2508,17 +2499,15 @@ SQL;
$aHeaders = static::ParseHeaders($http_response_header); $aHeaders = static::ParseHeaders($http_response_header);
$sMimeType = array_key_exists('Content-Type', $aHeaders) ? strtolower($aHeaders['Content-Type']) : 'application/x-octet-stream'; $sMimeType = array_key_exists('Content-Type', $aHeaders) ? strtolower($aHeaders['Content-Type']) : 'application/x-octet-stream';
// Compute the file extension from the MIME Type // Compute the file extension from the MIME Type
foreach ($aKnownExtensions as $sExtValue => $sMime) { foreach($aKnownExtensions as $sExtValue => $sMime)
if ($sMime === $sMimeType) { {
if ($sMime === $sMimeType)
{
$sExtension = '.'.$sExtValue; $sExtension = '.'.$sExtValue;
break; break;
} }
} }
} }
$sPathName = pathinfo($sPath, PATHINFO_FILENAME);
if (utils::IsNotNullOrEmptyString($sPathName)) {
$sFileName = $sPathName;
}
$sFileName .= $sExtension; $sFileName .= $sExtension;
} }
$oUploadedDoc = new ormDocument($sData, $sMimeType, $sFileName); $oUploadedDoc = new ormDocument($sData, $sMimeType, $sFileName);
@@ -2534,7 +2523,7 @@ SQL;
} }
$sExtension = strtolower(pathinfo($sPath, PATHINFO_EXTENSION)); $sExtension = strtolower(pathinfo($sPath, PATHINFO_EXTENSION));
$sFileName = basename($sPath); $sFileName = basename($sPath);
if (array_key_exists($sExtension, $aKnownExtensions)) if (array_key_exists($sExtension, $aKnownExtensions))
{ {
$sMimeType = $aKnownExtensions[$sExtension]; $sMimeType = $aKnownExtensions[$sExtension];
@@ -2548,7 +2537,7 @@ SQL;
} }
return $oUploadedDoc; return $oUploadedDoc;
} }
protected static function ParseHeaders($aHeaders) protected static function ParseHeaders($aHeaders)
{ {
$aCleanHeaders = array(); $aCleanHeaders = array();
@@ -2573,7 +2562,7 @@ SQL;
} }
return $aCleanHeaders; return $aCleanHeaders;
} }
/** /**
* @return string a string based on compilation time or (if not available because the datamodel has not been loaded) * @return string a string based on compilation time or (if not available because the datamodel has not been loaded)
* the version of iTop. This string is useful to prevent browser side caching of content that may vary at each * the version of iTop. This string is useful to prevent browser side caching of content that may vary at each
@@ -3040,7 +3029,6 @@ HTML;
* *
* @return bool if string null or empty * @return bool if string null or empty
* @since 3.0.2 N°5302 * @since 3.0.2 N°5302
* @since 2.7.10 N°6458 add method in the 2.7 branch
*/ */
public static function IsNullOrEmptyString(?string $sString): bool public static function IsNullOrEmptyString(?string $sString): bool
{ {
@@ -3056,7 +3044,6 @@ HTML;
* *
* @return bool if string is not null and not empty * @return bool if string is not null and not empty
* @since 3.0.2 N°5302 * @since 3.0.2 N°5302
* @since 2.7.10 N°6458 add method in the 2.7 branch
*/ */
public static function IsNotNullOrEmptyString(?string $sString): bool public static function IsNotNullOrEmptyString(?string $sString): bool
{ {

View File

@@ -23,13 +23,11 @@ define('ITOP_DESIGN_LATEST_VERSION', '3.1');
* @used-by utils::GetItopVersionWikiSyntax() * @used-by utils::GetItopVersionWikiSyntax()
* @used-by iTopModulesPhpVersionIntegrationTest * @used-by iTopModulesPhpVersionIntegrationTest
*/ */
define('ITOP_CORE_VERSION', '3.1.2'); define('ITOP_CORE_VERSION', '3.1.0');
/** /**
* @var string * @since 3.0.4 N°6274 Allow to test if PHPUnit is currently running. Starting with PHPUnit 9.5 we'll be able to replace it with $GLOBALS['phpunit_version']
* @since 3.0.4 3.1.0 3.2.0 N°6274 Allow to test if PHPUnit is currently running. Starting with PHPUnit 9.5 we'll be able to replace it with $GLOBALS['phpunit_version']
* @since 3.0.4 3.1.1 3.2.0 N°6976 Fix constant name (DeprecatedCallsLog error handler was never set)
*/ */
const ITOP_PHPUNIT_RUNNING_CONSTANT_NAME = 'ITOP_PHPUNIT_RUNNING'; define('ITOP_PHPUNIT_RUNNING_CONSTANT_NAME', 'ITOP_PHPUNIT_RUNNING');
require_once APPROOT.'bootstrap.inc.php'; require_once APPROOT.'bootstrap.inc.php';

View File

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

View File

@@ -629,7 +629,9 @@ class ActionEmail extends ActionNotification
$oLog->Set('body', HTMLSanitizer::Sanitize($aMessageContent['body'])); $oLog->Set('body', HTMLSanitizer::Sanitize($aMessageContent['body']));
} }
} }
$sStyles = file_get_contents(APPROOT.'css/email.css');
$sStyles .= MetaModel::GetConfig()->Get('email_css');
if ($this->IsBeingTested()) { if ($this->IsBeingTested()) {
$sTestBody = $aMessageContent['body']; $sTestBody = $aMessageContent['body'];
$sTestBody .= "<div style=\"border: dashed;\">\n"; $sTestBody .= "<div style=\"border: dashed;\">\n";

View File

@@ -60,15 +60,14 @@ function apc_store($key, $var = NULL, $ttl = 0)
*/ */
function apc_fetch($key) function apc_fetch($key)
{ {
if (is_array($key)) { if (is_array($key))
$aResult = []; {
foreach ($key as $sKey) { $aResult = array();
foreach($key as $sKey)
{
$aResult[$sKey] = apcFile::FetchOneFile($sKey); $aResult[$sKey] = apcFile::FetchOneFile($sKey);
} }
return $aResult; return $aResult;
} elseif (is_null($key)) {
return false;
} }
return apcFile::FetchOneFile($key); return apcFile::FetchOneFile($key);
} }
@@ -212,16 +211,21 @@ class apcFile
*/ */
static public function StoreOneFile($sKey, $value, $iTTL) static public function StoreOneFile($sKey, $value, $iTTL)
{ {
if (empty($sKey)) { if (empty($sKey))
{
return false; return false;
} }
if (is_file(self::GetCacheFileName($sKey))) {
if (is_file(self::GetCacheFileName($sKey)))
{
@unlink(self::GetCacheFileName($sKey)); @unlink(self::GetCacheFileName($sKey));
} }
if (is_file(self::GetCacheFileName('-'.$sKey))) { if (is_file(self::GetCacheFileName('-'.$sKey)))
{
@unlink(self::GetCacheFileName('-'.$sKey)); @unlink(self::GetCacheFileName('-'.$sKey));
} }
if ($iTTL > 0) { if ($iTTL > 0)
{
// hint for ttl management // hint for ttl management
$sKey = '-'.$sKey; $sKey = '-'.$sKey;
} }
@@ -229,14 +233,15 @@ class apcFile
$sFilename = self::GetCacheFileName($sKey); $sFilename = self::GetCacheFileName($sKey);
// try to create the folder // try to create the folder
$sDirname = dirname($sFilename); $sDirname = dirname($sFilename);
if (!is_dir($sDirname)) { if (!file_exists($sDirname))
if (!@mkdir($sDirname, 0755, true)) { {
if (!@mkdir($sDirname, 0755, true))
{
return false; return false;
} }
} }
$bRes = !(@file_put_contents($sFilename, serialize($value), LOCK_EX) === false); $bRes = !(@file_put_contents($sFilename, serialize($value), LOCK_EX) === false);
self::AddFile($sFilename); self::AddFile($sFilename);
return $bRes; return $bRes;
} }
@@ -320,15 +325,19 @@ class apcFile
*/ */
static protected function ReadCacheLocked($sFilename) static protected function ReadCacheLocked($sFilename)
{ {
$sContent = false; if (!is_file($sFilename))
$file = @fopen($sFilename, 'r'); {
if ($file !== false) { return false;
if (flock($file, LOCK_SH)) {
$sContent = file_get_contents($sFilename);
flock($file, LOCK_UN);
}
fclose($file);
} }
$file = @fopen($sFilename, 'r');
if ($file === false)
{
return false;
}
flock($file, LOCK_SH);
$sContent = @fread($file, @filesize($sFilename));
flock($file, LOCK_UN);
fclose($file);
return $sContent; return $sContent;
} }

View File

@@ -1739,20 +1739,11 @@ class AttributeLinkedSet extends AttributeDefinition
* @return bool true if Attribute has constraints * @return bool true if Attribute has constraints
* @since 3.1.0 N°6228 * @since 3.1.0 N°6228
*/ */
public function HasPHPConstraint(): bool public function GetHasConstraint()
{ {
return $this->GetOptional('with_php_constraint', false); return $this->GetOptional('with_php_constraint', false);
} }
/**
* @return bool true if Attribute has computation (DB_LINKS_CHANGED event propagation, `with_php_computation` attribute xml property), false otherwise
* @since 3.1.1 3.2.0 N°6228
*/
public function HasPHPComputation(): bool
{
return $this->GetOptional('with_php_computation', false);
}
public function GetLinkedClass() public function GetLinkedClass()
{ {
return $this->Get('linked_class'); return $this->Get('linked_class');
@@ -3061,11 +3052,6 @@ class AttributeObjectKey extends AttributeDBFieldVoid
return ((int) $proposedValue) !== 0; return ((int) $proposedValue) !== 0;
} }
/**
* @inheritDoc
*
* @param int|DBObject $proposedValue Object key or valid ({@see MetaModel::IsValidObject()}) datamodel object
*/
public function MakeRealValue($proposedValue, $oHostObj) public function MakeRealValue($proposedValue, $oHostObj)
{ {
if (is_null($proposedValue)) if (is_null($proposedValue))
@@ -3078,6 +3064,7 @@ class AttributeObjectKey extends AttributeDBFieldVoid
} }
if (MetaModel::IsValidObject($proposedValue)) if (MetaModel::IsValidObject($proposedValue))
{ {
/** @var \DBObject $proposedValue */
return $proposedValue->GetKey(); return $proposedValue->GetKey();
} }
@@ -4534,6 +4521,7 @@ class AttributeText extends AttributeString
$sStyle = ''; $sStyle = '';
if (count($aStyles) > 0) if (count($aStyles) > 0)
{ {
$aStyles[] = 'overflow:auto';
$sStyle = 'style="'.implode(';', $aStyles).'"'; $sStyle = 'style="'.implode(';', $aStyles).'"';
} }
@@ -6513,11 +6501,6 @@ class AttributeDateTime extends AttributeDBField
} }
} }
/**
* @inheritDoc
*
* @param int|string $proposedValue timestamp ({@see DateTime::getTimestamp()) or date as string, following the {@see GetInternalFormat} format.
*/
public function MakeRealValue($proposedValue, $oHostObj) public function MakeRealValue($proposedValue, $oHostObj)
{ {
if (is_null($proposedValue)) if (is_null($proposedValue))
@@ -8307,9 +8290,9 @@ class AttributeBlob extends AttributeDefinition
} }
/** /**
* {@inheritDoc} * Users can provide the document from an URL (including an URL on iTop itself)
* * for CSV import. Administrators can even provide the path to a local file
* @param string $proposedValue Can be an URL (including an URL to iTop itself), or a local path (CSV import) * {@inheritDoc}
* *
* @see AttributeDefinition::MakeRealValue() * @see AttributeDefinition::MakeRealValue()
*/ */
@@ -8550,7 +8533,7 @@ class AttributeBlob extends AttributeDefinition
$sFingerprint = ''; $sFingerprint = '';
if ($value instanceOf ormDocument) if ($value instanceOf ormDocument)
{ {
$sFingerprint = $value->GetSignature(); $sFingerprint = md5($value->GetData());
} }
return $sFingerprint; return $sFingerprint;
@@ -11508,11 +11491,6 @@ class AttributeClassAttCodeSet extends AttributeSet
} }
return '<span class="'.implode(' ', $this->aCSSClasses).'">'.$value.'</span>'; return '<span class="'.implode(' ', $this->aCSSClasses).'">'.$value.'</span>';
} }
public function IsNull($proposedValue)
{
return (empty($proposedValue));
}
} }
class AttributeQueryAttCodeSet extends AttributeSet class AttributeQueryAttCodeSet extends AttributeSet

View File

@@ -32,37 +32,11 @@ abstract class CellChangeSpec
return $this->m_proposedValue; return $this->m_proposedValue;
} }
/** public function GetDisplayableValue()
* @throws \Exception
* @since 3.2.0
*/
public function GetCLIValue(bool $bLocalizedValues = false): string
{ {
if (is_object($this->m_proposedValue)) {
if ($this->m_proposedValue instanceof ReportValue) {
return $this->m_proposedValue->GetAsCSV($bLocalizedValues, ',', '"');
}
throw new Exception('Unexpected class : '. get_class($this->m_proposedValue));
}
return $this->m_proposedValue; return $this->m_proposedValue;
} }
/**
* @throws \Exception
* @since 3.2.0
*/
public function GetHTMLValue(bool $bLocalizedValues = false): string
{
if (is_object($this->m_proposedValue)) {
if ($this->m_proposedValue instanceof ReportValue) {
return $this->m_proposedValue->GetAsHTML($bLocalizedValues);
}
throw new Exception('Unexpected class : '. get_class($this->m_proposedValue));
}
return utils::EscapeHtml($this->m_proposedValue);
}
/** /**
* @since 3.1.0 N°5305 * @since 3.1.0 N°5305
*/ */
@@ -77,12 +51,12 @@ abstract class CellChangeSpec
} }
/** /**
* @since 3.2.0 * @since 3.1.0 N°5305
*/ */
public function GetCLIValueAndDescription(): string public function GetDisplayableValueAndDescription(): string
{ {
return sprintf("%s%s", return sprintf("%s%s",
$this->GetCLIValue(), $this->GetDisplayableValue(),
$this->GetDescription() $this->GetDescription()
); );
} }
@@ -131,25 +105,13 @@ class CellStatus_Issue extends CellStatus_Modify
parent::__construct($proposedValue, $previousValue); parent::__construct($proposedValue, $previousValue);
} }
public function GetCLIValue(bool $bLocalizedValues = false): string public function GetDisplayableValue()
{
if (is_null($this->m_proposedValue)) {
return Dict::Format('UI:CSVReport-Value-SetIssue');
}
return Dict::Format('UI:CSVReport-Value-ChangeIssue',$this->m_proposedValue);
}
public function GetHTMLValue(bool $bLocalizedValues = false): string
{ {
if (is_null($this->m_proposedValue)) if (is_null($this->m_proposedValue))
{ {
return Dict::Format('UI:CSVReport-Value-SetIssue'); return Dict::Format('UI:CSVReport-Value-SetIssue');
} }
if ($this->m_proposedValue instanceof ReportValue) return Dict::Format('UI:CSVReport-Value-ChangeIssue', \utils::EscapeHtml($this->m_proposedValue));
{
return Dict::Format('UI:CSVReport-Value-ChangeIssue', $this->m_proposedValue->GetAsHTML($bLocalizedValues));
}
return Dict::Format('UI:CSVReport-Value-ChangeIssue',utils::EscapeHtml($this->m_proposedValue));
} }
public function GetDescription() public function GetDescription()
@@ -157,12 +119,12 @@ class CellStatus_Issue extends CellStatus_Modify
return $this->m_sReason; return $this->m_sReason;
} }
/* /*
* @since 3.2.0 * @since 3.1.0 N°5305
*/ */
public function GetCLIValueAndDescription(): string public function GetDisplayableValueAndDescription(): string
{ {
return sprintf("%s. %s", return sprintf("%s. %s",
$this->GetCLIValue(), $this->GetDisplayableValue(),
$this->GetDescription() $this->GetDescription()
); );
} }
@@ -198,7 +160,7 @@ class CellStatus_SearchIssue extends CellStatus_Issue
* @param null $sAllowedValues : used for additional message that provides allowed values $sAllowedValues for current class * @param null $sAllowedValues : used for additional message that provides allowed values $sAllowedValues for current class
* @param string|null $sAllowedValuesSearch : used to search all allowed values * @param string|null $sAllowedValuesSearch : used to search all allowed values
*/ */
public function __construct($sSerializedSearch, $sReason, $sClass = null, $sAllowedValues = null, string $sAllowedValuesSearch = null) public function __construct($sSerializedSearch, $sReason, $sClass=null, $sAllowedValues=null, string $sAllowedValuesSearch=null)
{ {
parent::__construct(null, null, $sReason); parent::__construct(null, null, $sReason);
$this->sSerializedSearch = $sSerializedSearch; $this->sSerializedSearch = $sSerializedSearch;
@@ -207,7 +169,7 @@ class CellStatus_SearchIssue extends CellStatus_Issue
$this->sAllowedValuesSearch = $sAllowedValuesSearch; $this->sAllowedValuesSearch = $sAllowedValuesSearch;
} }
public function GetCLIValue(bool $bLocalizedValues = false): string public function GetDisplayableValue()
{ {
if (null === $this->m_sReason) { if (null === $this->m_sReason) {
return Dict::Format('UI:CSVReport-Value-NoMatch', ''); return Dict::Format('UI:CSVReport-Value-NoMatch', '');
@@ -216,15 +178,6 @@ class CellStatus_SearchIssue extends CellStatus_Issue
return $this->m_sReason; return $this->m_sReason;
} }
public function GetHTMLValue(bool $bLocalizedValues = false): string
{
if (null === $this->m_sReason) {
return Dict::Format('UI:CSVReport-Value-NoMatch', '');
}
return utils::EscapeHtml($this->m_sReason);
}
public function GetDescription() public function GetDescription()
{ {
if (\utils::IsNullOrEmptyString($this->m_sAllowedValues) || if (\utils::IsNullOrEmptyString($this->m_sAllowedValues) ||
@@ -242,7 +195,7 @@ class CellStatus_SearchIssue extends CellStatus_Issue
public function GetSearchLinkUrl() public function GetSearchLinkUrl()
{ {
return sprintf("UI.php?operation=search&filter=%s", return sprintf("UI.php?operation=search&filter=%s",
rawurlencode($this->sSerializedSearch ?? "") rawurlencode($this->sSerializedSearch)
); );
} }
@@ -253,7 +206,7 @@ class CellStatus_SearchIssue extends CellStatus_Issue
public function GetAllowedValuesLinkUrl(): ?string public function GetAllowedValuesLinkUrl(): ?string
{ {
return sprintf("UI.php?operation=search&filter=%s", return sprintf("UI.php?operation=search&filter=%s",
rawurlencode($this->sAllowedValuesSearch ?? "") rawurlencode($this->sAllowedValuesSearch)
); );
} }
} }
@@ -271,42 +224,6 @@ class CellStatus_NullIssue extends CellStatus_Issue
} }
} }
/**
* Class to differ formatting depending on the caller
*/
class ReportValue
{
protected DBObject $oObject;
protected string $sAttCode;
protected bool $bOriginal;
/**
* @param DBObject $oObject
* @param string $sAttCode
* @param bool $bOriginal
*/
public function __construct(DBObject $oObject, string $sAttCode, bool $bOriginal)
{
$this->oObject = $oObject;
$this->sAttCode = $sAttCode;
$this->bOriginal = $bOriginal;
}
public function GetAsHTML(bool $bLocalizedValues)
{
if ($this->bOriginal) {
return $this->oObject->GetOriginalAsHTML($this->sAttCode, $bLocalizedValues);
}
return $this->oObject->GetAsHTML($this->sAttCode, $bLocalizedValues);
}
public function GetAsCSV (bool $bLocalizedValues, string $sCsvSep, string $sCsvDelimiter) {
if ($this->bOriginal) {
return $this->oObject->GetOriginalAsCSV($this->sAttCode, $sCsvSep, $sCsvDelimiter, $bLocalizedValues);
}
return $this->oObject->GetAsCSV($this->sAttCode, $sCsvSep, $sCsvDelimiter, $bLocalizedValues);
}
}
class CellStatus_Ambiguous extends CellStatus_Issue class CellStatus_Ambiguous extends CellStatus_Issue
{ {
@@ -345,7 +262,7 @@ class CellStatus_Ambiguous extends CellStatus_Issue
public function GetSearchLinkUrl() public function GetSearchLinkUrl()
{ {
return sprintf("UI.php?operation=search&filter=%s", return sprintf("UI.php?operation=search&filter=%s",
rawurlencode($this->sSerializedSearch ?? "") rawurlencode($this->sSerializedSearch)
); );
} }
} }
@@ -493,6 +410,22 @@ class BulkChange
$this->m_aExtKeysMappingCache = array(); $this->m_aExtKeysMappingCache = array();
} }
protected $m_bReportHtml = false;
protected $m_sReportCsvSep = ',';
protected $m_sReportCsvDelimiter = '"';
public function SetReportHtml()
{
$this->m_bReportHtml = true;
}
public function SetReportCsv($sSeparator = ',', $sDelimiter = '"')
{
$this->m_bReportHtml = false;
$this->m_sReportCsvSep = $sSeparator;
$this->m_sReportCsvDelimiter = $sDelimiter;
}
protected function ResolveExternalKey($aRowData, $sAttCode, &$aResults) protected function ResolveExternalKey($aRowData, $sAttCode, &$aResults)
{ {
$oExtKey = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode); $oExtKey = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
@@ -510,7 +443,7 @@ class BulkChange
$value = $oForeignAtt->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues); $value = $oForeignAtt->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues);
} }
$oReconFilter->AddCondition($sReconKeyAttCode, $value, '='); $oReconFilter->AddCondition($sReconKeyAttCode, $value, '=');
$aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]); $aResults[$iCol] = new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
} }
$oExtObjects = new CMDBObjectSet($oReconFilter); $oExtObjects = new CMDBObjectSet($oReconFilter);
@@ -534,7 +467,7 @@ class BulkChange
} }
/** /**
* @param DBObject $oTargetObj * @param \DBObject $oTargetObj
* @param array $aRowData * @param array $aRowData
* @param array $aErrors * @param array $aErrors
* *
@@ -597,7 +530,7 @@ class BulkChange
} }
$aCacheKeys[] = $value; $aCacheKeys[] = $value;
$oReconFilter->AddCondition($sReconKeyAttCode, $value, '='); $oReconFilter->AddCondition($sReconKeyAttCode, $value, '=');
$aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]); $aResults[$iCol] = new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
} }
$sCacheKey = implode('_|_', $aCacheKeys); // Unique key for this query... $sCacheKey = implode('_|_', $aCacheKeys); // Unique key for this query...
$iForeignKey = null; $iForeignKey = null;
@@ -666,7 +599,7 @@ class BulkChange
foreach ($aReconKeys as $sReconKeyAttCode => $iCol) foreach ($aReconKeys as $sReconKeyAttCode => $iCol)
{ {
// Report the change on reconciliation values as well // Report the change on reconciliation values as well
$aResults[$iCol] = new CellStatus_Modify($aRowData[$iCol]); $aResults[$iCol] = new CellStatus_Modify(utils::HtmlEntities($aRowData[$iCol]));
} }
} }
} }
@@ -744,32 +677,50 @@ class BulkChange
// Reporting on fields // Reporting on fields
// //
$aChangedFields = $oTargetObj->ListChanges(); $aChangedFields = $oTargetObj->ListChanges();
foreach ($this->m_aAttList as $sAttCode => $iCol) { foreach ($this->m_aAttList as $sAttCode => $iCol)
if ($sAttCode == 'id') { {
$aResults[$iCol]= new CellStatus_Void($aRowData[$iCol]); if ($sAttCode == 'id')
{
$aResults[$iCol]= new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
} }
else { else
$sCurValue = new ReportValue($oTargetObj, $sAttCode, false); {
$sOrigValue = new ReportValue($oTargetObj, $sAttCode, true); if ($this->m_bReportHtml)
if (isset($aErrors[$sAttCode])) { {
$aResults[$iCol]= new CellStatus_Issue($aRowData[$iCol], $sOrigValue, $aErrors[$sAttCode]); $sCurValue = $oTargetObj->GetAsHTML($sAttCode, $this->m_bLocalizedValues);
$sOrigValue = $oTargetObj->GetOriginalAsHTML($sAttCode, $this->m_bLocalizedValues);
} }
elseif (array_key_exists($sAttCode, $aChangedFields)){ else
if ($oTargetObj->IsNew()) { {
$sCurValue = $oTargetObj->GetAsCSV($sAttCode, $this->m_sReportCsvSep, $this->m_sReportCsvDelimiter, $this->m_bLocalizedValues);
$sOrigValue = $oTargetObj->GetOriginalAsCSV($sAttCode, $this->m_sReportCsvSep, $this->m_sReportCsvDelimiter, $this->m_bLocalizedValues);
}
if (isset($aErrors[$sAttCode]))
{
$aResults[$iCol]= new CellStatus_Issue(utils::HtmlEntities($aRowData[$iCol]), $sOrigValue, $aErrors[$sAttCode]);
}
elseif (array_key_exists($sAttCode, $aChangedFields))
{
if ($oTargetObj->IsNew())
{
$aResults[$iCol]= new CellStatus_Void($sCurValue); $aResults[$iCol]= new CellStatus_Void($sCurValue);
} }
else { else
{
$aResults[$iCol]= new CellStatus_Modify($sCurValue, $sOrigValue); $aResults[$iCol]= new CellStatus_Modify($sCurValue, $sOrigValue);
} }
} }
else { else
{
// By default... nothing happens // By default... nothing happens
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode); $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
if ($oAttDef instanceof AttributeDateTime) { if ($oAttDef instanceof AttributeDateTime)
{
$aResults[$iCol]= new CellStatus_Void($oAttDef->GetFormat()->Format($aRowData[$iCol])); $aResults[$iCol]= new CellStatus_Void($oAttDef->GetFormat()->Format($aRowData[$iCol]));
} }
else { else
$aResults[$iCol]= new CellStatus_Void($aRowData[$iCol]); {
$aResults[$iCol]= new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
} }
} }
} }
@@ -834,7 +785,7 @@ class BulkChange
// Possibles values are displayed to UI user. we have to limit the amount of displayed values // Possibles values are displayed to UI user. we have to limit the amount of displayed values
$oExtObjectSetWithCurrentUserPermissions->SetLimit(4); $oExtObjectSetWithCurrentUserPermissions->SetLimit(4);
for($i = 0; $i < 3; $i++){ for($i = 0; $i < 3; $i++){
/** @var DBObject $oVisibleObject */ /** @var \DBObject $oVisibleObject */
$oVisibleObject = $oExtObjectSetWithCurrentUserPermissions->Fetch(); $oVisibleObject = $oExtObjectSetWithCurrentUserPermissions->Fetch();
if (is_null($oVisibleObject)){ if (is_null($oVisibleObject)){
break; break;
@@ -1201,7 +1152,7 @@ class BulkChange
if (!preg_match($sRegExp, $sValue)) if (!preg_match($sRegExp, $sValue))
{ {
$aResult[$iRow]["__STATUS__"]= new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-DateFormat')); $aResult[$iRow]["__STATUS__"]= new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-DateFormat'));
$aResult[$iRow][$iCol] = new CellStatus_Issue($sValue, null, $sErrorMsg); $aResult[$iRow][$iCol] = new CellStatus_Issue(utils::HtmlEntities($sValue), null, $sErrorMsg);
} }
else else
@@ -1214,7 +1165,6 @@ class BulkChange
} }
else else
{ {
// almost impossible ti reproduce since even incorrect dates with correct formats are formated and $oDate will not be false
// Leave the cell unchanged // Leave the cell unchanged
$aResult[$iRow]["__STATUS__"]= new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-DateFormat')); $aResult[$iRow]["__STATUS__"]= new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-DateFormat'));
$aResult[$iRow][$iCol] = new CellStatus_Issue($sValue, null, $sErrorMsg); $aResult[$iRow][$iCol] = new CellStatus_Issue($sValue, null, $sErrorMsg);
@@ -1354,7 +1304,7 @@ class BulkChange
{ {
if (!array_key_exists($iCol, $aResult[$iRow])) if (!array_key_exists($iCol, $aResult[$iRow]))
{ {
$aResult[$iRow][$iCol] = new CellStatus_Void($aRowData[$iCol]); $aResult[$iRow][$iCol] = new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
} }
} }
foreach($this->m_aExtKeys as $sAttCode => $aForeignAtts) foreach($this->m_aExtKeys as $sAttCode => $aForeignAtts)
@@ -1368,7 +1318,7 @@ class BulkChange
if (!array_key_exists($iCol, $aResult[$iRow])) if (!array_key_exists($iCol, $aResult[$iRow]))
{ {
// The foreign attribute is one of our reconciliation key // The foreign attribute is one of our reconciliation key
$aResult[$iRow][$iCol] = new CellStatus_Void($aRowData[$iCol]); $aResult[$iRow][$iCol] = new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
} }
} }
} }

View File

@@ -335,7 +335,7 @@ abstract class CMDBObject extends DBObject
$oMyChangeOp->Set("objclass", MetaModel::GetRootClass(get_class($this))); $oMyChangeOp->Set("objclass", MetaModel::GetRootClass(get_class($this)));
$oMyChangeOp->Set("objkey", $objkey); $oMyChangeOp->Set("objkey", $objkey);
$oMyChangeOp->Set("fclass", get_class($this)); $oMyChangeOp->Set("fclass", get_class($this));
$oMyChangeOp->SetTrim("fname", $this->GetRawName()); // Protect against very long friendly names $oMyChangeOp->Set("fname", substr($this->GetRawName(), 0, 255)); // Protect against very long friendly names
$iId = $oMyChangeOp->DBInsertNoReload(); $iId = $oMyChangeOp->DBInsertNoReload();
} }
@@ -438,8 +438,7 @@ abstract class CMDBObject extends DBObject
} }
/** /**
* @deprecated 3.1.0 N°5232 N°6966 simply use {@see DBObject::DBClone()} instead, that will automatically create and persist a CMDBChange object. * @deprecated 3.1.0 N°5232 not used
* If you need to persist your own, call {@see CMDBObject::SetCurrentChange()} before.
*/ */
public function DBCloneTracked(CMDBChange $oChange, $newKey = null) public function DBCloneTracked(CMDBChange $oChange, $newKey = null)
{ {
@@ -447,9 +446,6 @@ abstract class CMDBObject extends DBObject
$this->DBCloneTracked_Internal($newKey); $this->DBCloneTracked_Internal($newKey);
} }
/**
* @deprecated 3.1.1 3.2.0 N°6966 We will have only one DBClone method in the future
*/
protected function DBCloneTracked_Internal($newKey = null) protected function DBCloneTracked_Internal($newKey = null)
{ {
$newKey = parent::DBClone($newKey); $newKey = parent::DBClone($newKey);
@@ -474,13 +470,23 @@ abstract class CMDBObject extends DBObject
public function DBDelete(&$oDeletionPlan = null) public function DBDelete(&$oDeletionPlan = null)
{ {
$this->LogCRUDEnter(__METHOD__); $this->LogCRUDEnter(__METHOD__);
$oDeletionPlan = parent::DBDelete($oDeletionPlan); $oDeletionPlan = $this->DBDeleteTracked_Internal($oDeletionPlan);
$this->LogCRUDExit(__METHOD__); $this->LogCRUDExit(__METHOD__);
return $oDeletionPlan; return $oDeletionPlan;
} }
/** /**
* @deprecated 3.1.1 3.2.0 N°6967 We will have only one DBDelete method in the future * @param null $oDeletionPlan
*
* @return \DeletionPlan|null
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DeleteException
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
*/ */
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null) protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
{ {

View File

@@ -3,7 +3,7 @@
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -42,12 +42,6 @@ class CMDBSource
const ENUM_DB_VENDOR_MARIADB = 'MariaDB'; const ENUM_DB_VENDOR_MARIADB = 'MariaDB';
const ENUM_DB_VENDOR_PERCONA = 'Percona'; const ENUM_DB_VENDOR_PERCONA = 'Percona';
/**
* @since 2.7.10 3.0.4 3.1.2 3.0.2 N°6889 constant creation
* @internal will be removed in a future version
*/
const MYSQL_DEFAULT_PORT = 3306;
/** /**
* Error: 1205 SQLSTATE: HY000 (ER_LOCK_WAIT_TIMEOUT) * Error: 1205 SQLSTATE: HY000 (ER_LOCK_WAIT_TIMEOUT)
* Message: Lock wait timeout exceeded; try restarting transaction * Message: Lock wait timeout exceeded; try restarting transaction
@@ -218,19 +212,16 @@ class CMDBSource
/** /**
* @param string $sDbHost initial value ("p:domain:port" syntax) * @param string $sDbHost initial value ("p:domain:port" syntax)
* @param string $sServer server variable to update * @param string $sServer server variable to update
* @param int|null $iPort port variable to update, will return null if nothing is specified in $sDbHost * @param int $iPort port variable to update
*
* @since 2.7.10 3.0.4 3.1.2 3.2.0 N°6889 will return null in $iPort if port isn't present in $sDbHost. Use {@see MYSQL_DEFAULT_PORT} if needed
*
* @link http://php.net/manual/en/mysqli.persistconns.php documentation for the "p:" prefix (persistent connexion)
*/ */
public static function InitServerAndPort($sDbHost, &$sServer, &$iPort) public static function InitServerAndPort($sDbHost, &$sServer, &$iPort)
{ {
$aConnectInfo = explode(':', $sDbHost); $aConnectInfo = explode(':', $sDbHost);
$bUsePersistentConnection = false; $bUsePersistentConnection = false;
if (strcasecmp($aConnectInfo[0], 'p') === 0) if (strcasecmp($aConnectInfo[0], 'p') == 0)
{ {
// we might have "p:" prefix to use persistent connections (see http://php.net/manual/en/mysqli.persistconns.php)
$bUsePersistentConnection = true; $bUsePersistentConnection = true;
$sServer = $aConnectInfo[0].':'.$aConnectInfo[1]; $sServer = $aConnectInfo[0].':'.$aConnectInfo[1];
} }
@@ -248,6 +239,10 @@ class CMDBSource
{ {
$iPort = (int)($aConnectInfo[1]); $iPort = (int)($aConnectInfo[1]);
} }
else
{
$iPort = 3306;
}
} }
/** /**
@@ -385,7 +380,7 @@ class CMDBSource
public static function GetDBVendor() public static function GetDBVendor()
{ {
$sDBVendor = static::ENUM_DB_VENDOR_MYSQL; $sDBVendor = static::ENUM_DB_VENDOR_MYSQL;
$sVersionComment = static::GetServerVariable('version') . ' - ' . static::GetServerVariable('version_comment'); $sVersionComment = static::GetServerVariable('version') . ' - ' . static::GetServerVariable('version_comment');
if(preg_match('/mariadb/i', $sVersionComment) === 1) if(preg_match('/mariadb/i', $sVersionComment) === 1)
{ {
@@ -395,7 +390,7 @@ class CMDBSource
{ {
$sDBVendor = static::ENUM_DB_VENDOR_PERCONA; $sDBVendor = static::ENUM_DB_VENDOR_PERCONA;
} }
return $sDBVendor; return $sDBVendor;
} }
@@ -549,9 +544,10 @@ class CMDBSource
/** /**
* @param string $sSQLQuery * @param string $sSQLQuery
* *
* @return mysqli_result|null * @return \mysqli_result|null
* @throws MySQLException * @throws \MySQLException
* @throws MySQLHasGoneAwayException * @throws \MySQLHasGoneAwayException
* @throws \CoreException
* *
* @since 2.7.0 N°679 handles nested transactions * @since 2.7.0 N°679 handles nested transactions
*/ */
@@ -938,7 +934,7 @@ class CMDBSource
{ {
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql)); throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
} }
while ($aRow = $oResult->fetch_array($iMode)) while ($aRow = $oResult->fetch_array($iMode))
{ {
$aData[] = $aRow; $aData[] = $aRow;
@@ -1092,7 +1088,7 @@ class CMDBSource
if (!array_key_exists($iKey, $aTableInfo["Fields"])) return false; if (!array_key_exists($iKey, $aTableInfo["Fields"])) return false;
$aFieldData = $aTableInfo["Fields"][$iKey]; $aFieldData = $aTableInfo["Fields"][$iKey];
if (!array_key_exists("Key", $aFieldData)) return false; if (!array_key_exists("Key", $aFieldData)) return false;
return ($aFieldData["Key"] == "PRI"); return ($aFieldData["Key"] == "PRI");
} }
public static function IsAutoIncrement($sTable, $sField) public static function IsAutoIncrement($sTable, $sField)
@@ -1103,7 +1099,7 @@ class CMDBSource
$aFieldData = $aTableInfo["Fields"][$sField]; $aFieldData = $aTableInfo["Fields"][$sField];
if (!array_key_exists("Extra", $aFieldData)) return false; if (!array_key_exists("Extra", $aFieldData)) return false;
//MyHelpers::debug_breakpoint($aFieldData); //MyHelpers::debug_breakpoint($aFieldData);
return (strstr($aFieldData["Extra"], "auto_increment")); return (strstr($aFieldData["Extra"], "auto_increment"));
} }
public static function IsField($sTable, $sField) public static function IsField($sTable, $sField)
@@ -1169,8 +1165,8 @@ class CMDBSource
*/ */
public static function IsSameFieldTypes($sItopGeneratedFieldType, $sDbFieldType) public static function IsSameFieldTypes($sItopGeneratedFieldType, $sDbFieldType)
{ {
[$sItopFieldDataType, $sItopFieldTypeOptions, $sItopFieldOtherOptions] = static::GetFieldDataTypeAndOptions($sItopGeneratedFieldType); list($sItopFieldDataType, $sItopFieldTypeOptions, $sItopFieldOtherOptions) = static::GetFieldDataTypeAndOptions($sItopGeneratedFieldType);
[$sDbFieldDataType, $sDbFieldTypeOptions, $sDbFieldOtherOptions] = static::GetFieldDataTypeAndOptions($sDbFieldType); list($sDbFieldDataType, $sDbFieldTypeOptions, $sDbFieldOtherOptions) = static::GetFieldDataTypeAndOptions($sDbFieldType);
if (strcasecmp($sItopFieldDataType, $sDbFieldDataType) !== 0) if (strcasecmp($sItopFieldDataType, $sDbFieldDataType) !== 0)
{ {
@@ -1370,13 +1366,13 @@ class CMDBSource
public static function GetTableFieldsList($sTable) public static function GetTableFieldsList($sTable)
{ {
assert(!empty($sTable)); assert(!empty($sTable));
$aTableInfo = self::GetTableInfo($sTable); $aTableInfo = self::GetTableInfo($sTable);
if (empty($aTableInfo)) return array(); // #@# or an error ? if (empty($aTableInfo)) return array(); // #@# or an error ?
return array_keys($aTableInfo["Fields"]); return array_keys($aTableInfo["Fields"]);
} }
// Cache the information about existing tables, and their fields // Cache the information about existing tables, and their fields
private static $m_aTablesInfo = array(); private static $m_aTablesInfo = array();
private static function _TablesInfoCacheReset($sTableName = null) private static function _TablesInfoCacheReset($sTableName = null)
@@ -1509,7 +1505,7 @@ class CMDBSource
{ {
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql)); throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
} }
$aRows = array(); $aRows = array();
while ($aRow = $oResult->fetch_array(MYSQLI_ASSOC)) while ($aRow = $oResult->fetch_array(MYSQLI_ASSOC))
{ {
@@ -1518,7 +1514,7 @@ class CMDBSource
$oResult->free(); $oResult->free();
return $aRows; return $aRows;
} }
/** /**
* Returns the value of the specified server variable * Returns the value of the specified server variable
* @param string $sVarName Name of the server variable * @param string $sVarName Name of the server variable
@@ -1534,7 +1530,7 @@ class CMDBSource
/** /**
* Returns the privileges of the current user * Returns the privileges of the current user
* @return string privileges in a raw format * @return string privileges in a raw format
*/ */
public static function GetRawPrivileges() public static function GetRawPrivileges()
{ {
try try
@@ -1560,8 +1556,8 @@ class CMDBSource
/** /**
* Determine the slave status of the server * Determine the slave status of the server
* @return bool true if the server is slave * @return bool true if the server is slave
*/ */
public static function IsSlaveServer() public static function IsSlaveServer()
{ {
try try
@@ -1603,19 +1599,7 @@ class CMDBSource
return false; return false;
} }
public static function GetClusterNb() /**
{
$result = 0;
$sSql = "SHOW STATUS LIKE 'wsrep_cluster_size';";
$aRows = self::QueryToArray($sSql);
if (count($aRows) > 0)
{
$result = $aRows[0]['Value'];
}
return intval($result);
}
/**
* @see https://dev.mysql.com/doc/refman/5.7/en/charset-database.html * @see https://dev.mysql.com/doc/refman/5.7/en/charset-database.html
* @return string query to upgrade database charset and collation if needed, null if not * @return string query to upgrade database charset and collation if needed, null if not
* @throws \MySQLException * @throws \MySQLException

View File

@@ -1193,30 +1193,6 @@ class Config
'source_of_value' => '', 'source_of_value' => '',
'show_in_conf_sample' => false, 'show_in_conf_sample' => false,
], ],
'sessions_tracking.enabled' => [
'type' => 'bool',
'description' => 'Whether or not the whole mechanism to track active sessions is enabled. See PHP session.gc_maxlifetime setting to configure session expiration.',
'default' => false,
'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)',
'default' => 1,
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'sessions_tracking.gc_duration_in_seconds' => [
'type' => 'integer',
'description' => 'fallback in case cron is not active: when a cleanup is triggered cleanup duration will not exceed this duration (in seconds).',
'default' => 1,
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'transaction_storage' => [ 'transaction_storage' => [
'type' => 'string', 'type' => 'string',
'description' => 'The type of mechanism to use for storing the unique identifiers for transactions (Session|File).', 'description' => 'The type of mechanism to use for storing the unique identifiers for transactions (Session|File).',
@@ -1643,14 +1619,6 @@ class Config
'source_of_value' => '', 'source_of_value' => '',
'show_in_conf_sample' => false, 'show_in_conf_sample' => false,
], ],
'security.enable_header_xcontent_type_options' => [
'type' => 'bool',
'description' => 'If set to false, iTop will stop sending the X-Content-Type-Options HTTP header. This header could trigger CORB protection on certain resources (JSON, XML, HTML, text) therefore blocking them.',
'default' => true,
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'security.disable_inline_documents_sandbox' => [ 'security.disable_inline_documents_sandbox' => [
'type' => 'bool', 'type' => 'bool',
'description' => 'If true then the sandbox for documents displayed in a browser tab will be disabled; enabling scripts and other interactive content. Note that setting this to true will open the application to potential XSS attacks!', 'description' => 'If true then the sandbox for documents displayed in a browser tab will be disabled; enabling scripts and other interactive content. Note that setting this to true will open the application to potential XSS attacks!',
@@ -2321,24 +2289,6 @@ class Config
$this->m_sAllowedLoginTypes = implode('|', $aAllowedLoginTypes); $this->m_sAllowedLoginTypes = implode('|', $aAllowedLoginTypes);
} }
/**
* @since 2.7.11 N°7085
* Add login mode if not configured already
* @param string $sLoginMode
*
* @return void
*/
public function AddAllowedLoginTypes($sLoginMode)
{
$aAllowedLoginTypes = $this->GetAllowedLoginTypes();
if (in_array($sLoginMode, $aAllowedLoginTypes)){
return;
}
$aAllowedLoginTypes[] = $sLoginMode;
$this->SetAllowedLoginTypes($aAllowedLoginTypes);
}
public function SetExternalAuthenticationVariable($sExtAuthVariable) public function SetExternalAuthenticationVariable($sExtAuthVariable)
{ {
$this->m_sExtAuthVariable = $sExtAuthVariable; $this->m_sExtAuthVariable = $sExtAuthVariable;

View File

@@ -12,7 +12,6 @@ use Combodo\iTop\Application\UI\Base\Component\Input\SelectUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory; use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\ColumnUIBlockFactory; use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\ColumnUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactory; use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactory;
use Combodo\iTop\Application\Helper\ExportHelper;
/** /**
* Bulk export: CSV export * Bulk export: CSV export
@@ -115,7 +114,6 @@ class CSVBulkExport extends TabularBulkExport
case 'csv_options': case 'csv_options':
$oPanel = PanelUIBlockFactory::MakeNeutral(Dict::S('Core:BulkExport:CSVOptions')); $oPanel = PanelUIBlockFactory::MakeNeutral(Dict::S('Core:BulkExport:CSVOptions'));
$oPanel->AddSubBlock(ExportHelper::GetAlertForExcelMaliciousInjection());
$oMulticolumn = MultiColumnUIBlockFactory::MakeStandard(); $oMulticolumn = MultiColumnUIBlockFactory::MakeStandard();
$oPanel->AddSubBlock($oMulticolumn); $oPanel->AddSubBlock($oMulticolumn);

View File

@@ -502,12 +502,6 @@
<type>boolean</type> <type>boolean</type>
<default>false</default> <default>false</default>
</property> </property>
<property id="with_php_computation">
<php_param>with_php_computation</php_param>
<mandatory>false</mandatory>
<type>boolean</type>
<default>false</default>
</property>
<property id="create_temporary_object"> <property id="create_temporary_object">
<php_param>create_temporary_object</php_param> <php_param>create_temporary_object</php_param>
<mandatory>false</mandatory> <mandatory>false</mandatory>

File diff suppressed because it is too large Load Diff

View File

@@ -851,11 +851,11 @@ abstract class DBSearch
return; return;
} }
if (count($aColumns) == 0) if (count($aColumns) == 0)
{ {
$aColumns = array_keys(MetaModel::ListAttributeDefs($this->GetClass())); $aColumns = array_keys(MetaModel::ListAttributeDefs($this->GetClass()));
// Add the standard id (as first column) // Add the standard id (as first column)
array_unshift($aColumns, 'id'); array_unshift($aColumns, 'id');
} }
$aQueryCols = CMDBSource::GetColumns($resQuery, $sSQL); $aQueryCols = CMDBSource::GetColumns($resQuery, $sSQL);
@@ -885,55 +885,6 @@ abstract class DBSearch
return $aRes; return $aRes;
} }
/**
* Selects a column ($sAttCode) from the specified class ($sClassAlias - default main class) of the DBsearch object and gives the result as an array
* @param string $sAttCode
* @param string|null $sClassAlias
*
* @return array
* @throws ConfigException
* @throws CoreException
* @throws MissingQueryArgument
* @throws MySQLException
* @throws MySQLHasGoneAwayException
*/
public function SelectAttributeToArray(string $sAttCode, ?string $sClassAlias = null):array
{
if(is_null($sClassAlias)) {
$sClassAlias = $this->GetClassAlias();
}
$sClass = $this->GetClass();
if($sAttCode === 'id'){
$aAttToLoad[$sClassAlias]=[];
} else {
$aAttToLoad[$sClassAlias][$sAttCode] = MetaModel::GetAttributeDef($sClass, $sAttCode);
}
$sSQL = $this->MakeSelectQuery([], [], $aAttToLoad);
$resQuery = CMDBSource::Query($sSQL);
if (!$resQuery)
{
return [];
}
$sColName = $sClassAlias.$sAttCode;
$aRes = [];
while ($aRow = CMDBSource::FetchArray($resQuery))
{
$aMappedRow = array();
if($sAttCode === 'id') {
$aMappedRow[$sAttCode] = $aRow[$sColName];
} else {
$aMappedRow[$sAttCode] = $aAttToLoad[$sClassAlias][$sAttCode]->FromSQLToValue($aRow, $sColName);
}
$aRes[] = $aMappedRow;
}
CMDBSource::FreeResult($resQuery);
return $aRes;
}
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// //
// Construction of the SQL queries // Construction of the SQL queries

View File

@@ -28,13 +28,8 @@ namespace Combodo\iTop;
use DOMDocument; use DOMDocument;
use DOMFormatException; use DOMFormatException;
use DOMNode;
use DOMNodeList;
use DOMXPath;
use Exception;
use IssueLog; use IssueLog;
use LogAPI; use LogAPI;
use MFElement;
use utils; use utils;
/** /**
@@ -46,11 +41,6 @@ use utils;
*/ */
class DesignDocument extends DOMDocument class DesignDocument extends DOMDocument
{ {
/** To fix DOMNode::getLineNo() ref https://www.php.net/manual/en/domnode.getlineno.php */
public const XML_PARSE_BIG_LINES = 4194304;
/** /**
* @throws \Exception * @throws \Exception
*/ */
@@ -79,12 +69,10 @@ class DesignDocument extends DOMDocument
*/ */
public function load($filename, $options = null) public function load($filename, $options = null)
{ {
if (is_file($filename)) { libxml_clear_errors();
libxml_clear_errors(); if (parent::load($filename, LIBXML_NOBLANKS) === false) {
if (parent::load($filename, LIBXML_NOBLANKS | LIBXML_BIGLINES | LIBXML_PARSEHUGE | self::XML_PARSE_BIG_LINES) === false) { $aErrors = libxml_get_errors();
$aErrors = libxml_get_errors(); IssueLog::Error("Error loading $filename", LogAPI::CHANNEL_DEFAULT, $aErrors);
IssueLog::Error("Error loading $filename", LogAPI::CHANNEL_DEFAULT, $aErrors);
}
} }
} }
@@ -239,56 +227,6 @@ class DesignElement extends \DOMElement
return ''; return '';
} }
/**
* Compatibility with PHP8.0
*
* @return \DOMElement|null
*
* @since 3.1.2
*/
public function GetFirstElementChild()
{
if (property_exists($this, 'firstElementChild')) {
return $this->firstElementChild;
}
$oChildNode = $this->firstChild;
while (!is_null($oChildNode)) {
if ($oChildNode instanceof \DOMElement) {
return $oChildNode;
}
$oChildNode = $oChildNode->nextSibling;
}
return null;
}
/**
* Compatibility with PHP8.0
*
* @return \DOMElement|null
*
* @since 3.1.2
*/
public function GetNextElementSibling()
{
if (property_exists($this, 'nextElementSibling')) {
return $this->nextElementSibling;
}
$oSibling = $this->nextSibling;
while (!is_null($oSibling)) {
if ($oSibling instanceof \DOMElement) {
return $oSibling;
}
$oSibling = $oSibling->nextSibling;
}
return null;
}
/** /**
* Returns the node directly under the given node * Returns the node directly under the given node
* @param $sTagName * @param $sTagName
@@ -369,146 +307,4 @@ class DesignElement extends \DOMElement
} }
return $sRet; return $sRet;
} }
/**
* Check that the current node is actually a class node, under classes
* @since 3.1.2 3.2.0 N°6974
*/
public function IsClassNode(): bool
{
if ($this->tagName == 'class') {
// Beware: classes/class also exists in the group definition
if (($this->parentNode->tagName == 'classes') && ($this->parentNode->parentNode->tagName == 'itop_design')) {
return true;
}
}
return false;
}
/**
* True if the node is contained in a _delta="merge" tree
* @return bool
*/
public function IsInSpecifiedMerge(): bool
{
// Iterate through the parents: reset the flag if any of them has a flag set
for ($oParent = $this; $oParent instanceof MFElement; $oParent = $oParent->parentNode) {
$sDeltaSpec = $oParent->getAttribute('_delta');
if ($sDeltaSpec === 'merge') {
return true;
}
if (in_array($sDeltaSpec, ['define', 'define_if_not_exists', 'force', 'redefine'])) {
return false;
}
}
return false;
}
/**
* Find the child node matching the given node.
* UNSAFE: may return nodes marked as _alteration="removed"
* A method with the same signature MUST exist in MFDocument for the recursion to work fine
*
* @param DesignElement $oRefNode The node to search for
* @param null|string $sSearchId substitutes to the value of the 'id' attribute
*
* @return DesignElement|null
* @throws \Exception
* @since 3.1.2 3.2.0 N°6974
*/
public function _FindChildNode(DesignElement $oRefNode, $sSearchId = null): ?DesignElement
{
return self::_FindNode($this, $oRefNode, $sSearchId);
}
/**
* Find the child node matching the given node.
* UNSAFE: may return nodes marked as _alteration="removed"
* A method with the same signature MUST exist in MFDocument for the recursion to work fine
*
* @param DesignElement $oRefNode The node to search for
*
* @return DesignElement|null
* @throws \Exception
* @since 3.1.2 3.2.0 N°6974
*/
public function _FindChildNodes(DesignElement $oRefNode): ?DesignElement
{
return self::_FindNodes($this, $oRefNode);
}
/**
* Find the child node matching the given node under the specified parent.
* UNSAFE: may return nodes marked as _alteration="removed"
*
* @param \DOMNode $oParent
* @param DesignElement $oRefNode
* @param string|null $sSearchId
*
* @return DesignElement|null
* @throws Exception
* @since 3.1.2 3.2.0 N°6974
*/
public static function _FindNode(DOMNode $oParent, DesignElement $oRefNode, string $sSearchId = null): ?DesignElement
{
$oNodes = self::_FindNodes($oParent, $oRefNode, $sSearchId);
if ($oNodes instanceof DOMNodeList) {
/** @var DesignElement $oNode */
$oNode = $oNodes->item(0);
return $oNode;
}
return null;
}
/**
* Find the child node matching the given node under the specified parent.
* UNSAFE: may return nodes marked as _alteration="removed"
*
* @param \DOMNode $oParent
* @param DesignElement $oRefNode
* @param string|null $sSearchId
*
* @return \DOMNodeList|false|mixed
* @since 3.1.2 3.2.0 N°6974
*/
public static function _FindNodes(DOMNode $oParent, DesignElement $oRefNode, string $sSearchId = null)
{
if ($oParent instanceof DOMDocument)
{
$oDoc = $oParent->firstChild->ownerDocument;
$oRoot = $oParent;
}
else
{
$oDoc = $oParent->ownerDocument;
$oRoot = $oParent;
}
$oXPath = new DOMXPath($oDoc);
if ($oRefNode->hasAttribute('id'))
{
// Find the elements having the same tag name and id
if (!$sSearchId)
{
$sSearchId = $oRefNode->getAttribute('id');
}
$sXPath = './'.$oRefNode->tagName."[@id='$sSearchId']";
$oRes = $oXPath->query($sXPath, $oRoot);
}
else
{
// Get the elements having the same tag name
$sXPath = './'.$oRefNode->tagName;
$oRes = $oXPath->query($sXPath, $oRoot);
}
return $oRes;
}
} }

View File

@@ -16,11 +16,8 @@
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
use Combodo\iTop\Application\Helper\WebResourcesHelper; use Combodo\iTop\Application\Helper\WebResourcesHelper;
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
use Combodo\iTop\Application\UI\Base\Component\MedallionIcon\MedallionIcon; use Combodo\iTop\Application\UI\Base\Component\MedallionIcon\MedallionIcon;
use Combodo\iTop\Application\UI\Base\Component\Panel\Panel; use Combodo\iTop\Application\UI\Base\Component\Panel\Panel;
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
use Combodo\iTop\Renderer\BlockRenderer; use Combodo\iTop\Renderer\BlockRenderer;
/** /**
@@ -62,7 +59,7 @@ class DisplayableNode extends GraphNode
public function GetWidth() public function GetWidth()
{ {
return max(32, 5 * mb_strlen($this->GetProperty('label'))); // approximation of the text's bounding box return max(32, 5*strlen($this->GetProperty('label'))); // approximation of the text's bounding box
} }
public function GetHeight() public function GetHeight()
@@ -491,7 +488,7 @@ class DisplayableNode extends GraphNode
if ($bNoLabel) if ($bNoLabel)
{ {
// simulate a fake label with the approximate same size as the true label // simulate a fake label with the approximate same size as the true label
$sLabel = str_repeat('x', mb_strlen($this->GetProperty('label', $this->GetId()))); $sLabel = str_repeat('x',strlen($this->GetProperty('label', $this->GetId())));
$sDot = 'label="'.$sLabel.'"'; $sDot = 'label="'.$sLabel.'"';
} }
else else
@@ -1415,8 +1412,6 @@ class DisplayableGraph extends SimpleGraph
/** /**
* Display the graph inside the given page, with the "filter" drawer above it * Display the graph inside the given page, with the "filter" drawer above it
* *
* @deprecated 3.1.1 3.2.0 N°3767 Use \DisplayableGraph::DisplayFilterBox() and \DisplayableGraph::DisplayGraph() instead
*
* @param WebPage $oP * @param WebPage $oP
* @param array $aResults * @param array $aResults
* @param string $sRelation * @param string $sRelation
@@ -1430,35 +1425,10 @@ class DisplayableGraph extends SimpleGraph
* *
* @throws \CoreException * @throws \CoreException
* @throws \DictExceptionMissingString * @throws \DictExceptionMissingString
*
*/ */
function Display(WebPage $oP, $aResults, $sRelation, ApplicationContext $oAppContext, $aExcludedObjects, $sObjClass, $iObjKey, $sContextKey, $aContextParams = array(), bool $bLazyLoading = false) function Display(WebPage $oP, $aResults, $sRelation, ApplicationContext $oAppContext, $aExcludedObjects, $sObjClass, $iObjKey, $sContextKey, $aContextParams = array(), bool $bLazyLoading = false)
{ {
$oP->AddSubBlock($this->DisplayFilterBox($oP, $aResults, $bLazyLoading)); list($aExcludedByClass, $aAdditionalContexts) = $this->DisplayFiltering($sContextKey, $aContextParams, $aExcludedObjects, $oP, $aResults, $bLazyLoading);
$this->DisplayGraph($oP, $sRelation, $oAppContext, $aExcludedObjects, $sObjClass, $iObjKey, $sContextKey, $aContextParams, $bLazyLoading);
}
/**
* Display only the graph inside the given page, with the parameters of filter box draw with DisplayFilterBox
*
* @param WebPage $oP
* @param string $sRelation
* @param ApplicationContext $oAppContext
* @param array $aExcludedObjects
* @param string $sObjClass
* @param int $iObjKey
* @param string $sContextKey
* @param array $aContextParams
* @param bool $bLazyLoading
*
* @throws \CoreException
* @throws \DictExceptionMissingString
*
* @since 3.1.1 3.2.0 N°3767
*/
function DisplayGraph(WebPage $oP, $sRelation, ApplicationContext $oAppContext, $aExcludedObjects, $sObjClass, $iObjKey, $sContextKey, $aContextParams = array(), bool $bLazyLoading = false): void
{
list($aExcludedByClass, $aAdditionalContexts) = $this->GetFilteringData($sContextKey, $aContextParams, $aExcludedObjects);
$iGroupingThreshold = utils::ReadParam('g', 5); $iGroupingThreshold = utils::ReadParam('g', 5);
@@ -1543,10 +1513,12 @@ class DisplayableGraph extends SimpleGraph
$oP->add_ready_script(" $('#$sId').simple_graph(".json_encode($aParams).");"); $oP->add_ready_script(" $('#$sId').simple_graph(".json_encode($aParams).");");
} else { } else {
$oP->add_script("function Load(){var aExcluded = []; $('input[name^=excluded]').each( function() {if (!$(this).prop('checked')) { aExcluded.push($(this).val()); }} ); var params= $.extend(".json_encode($aParams).", {excluded_classes: aExcluded}); $('#$sId').simple_graph(params);}"); $oP->add_script("function Load(){var aExcluded = []; $('input[name^=excluded]').each( function() {if (!$(this).prop('checked')) { aExcluded.push($(this).val()); }} ); var params= $.extend(".json_encode($aParams).", {excluded_classes: aExcluded}); $('#$sId').simple_graph(params);}");
$oP->add_ready_script("$('#graph').html('".utils::TextToHtml(Dict::S('Relation:impacts/NoFilteredData'))."');$('#impacted_objects_lists').html('".utils::TextToHtml(Dict::S('Relation:impacts/NoFilteredData'))."');$('#impacted_groups').html('".utils::TextToHtml(Dict::S('Relation:impacts/NoFilteredData'))."');"); $oP->add_ready_script("$('#impacted_objects_lists').html('".utils::TextToHtml(Dict::S('Relation:impacts/NoFilteredData'))."');$('#impacted_groups').html('".utils::TextToHtml(Dict::S('Relation:impacts/NoFilteredData'))."');");
} }
} }
catch (Exception $e) { catch(Exception $e)
{
$oP->add('<div>'.$e->getMessage().'</div>'); $oP->add('<div>'.$e->getMessage().'</div>');
} }
$oP->add_script( $oP->add_script(
@@ -1591,41 +1563,23 @@ EOF
* @throws \Twig\Error\LoaderError * @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError * @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError * @throws \Twig\Error\SyntaxError
*
* @deprecated 3.1.1 3.2.0 N°3767 Use \DisplayableGraph::DisplayFilterBox() and \DisplayableGraph::GetFilteringData() instead
*/ */
public function DisplayFiltering(string $sContextKey, array $aContextParams, array $aExcludedObjects, WebPage $oP, array $aResults, bool $bLazyLoading = false): array public function DisplayFiltering(string $sContextKey, array $aContextParams, array $aExcludedObjects, WebPage $oP, array $aResults, bool $bLazyLoading = false): array
{ {
$oP->Add($this->DisplayFilterBox($oP, $aResults, $bLazyLoading)); $aContextDefs = static::GetContextDefinitions($sContextKey, true, $aContextParams);
$aExcludedByClass = array();
return $this->GetFilteringData($sContextKey, $aContextParams, $aExcludedObjects); foreach ($aExcludedObjects as $oObj) {
} if (!array_key_exists(get_class($oObj), $aExcludedByClass)) {
$aExcludedByClass[get_class($oObj)] = array();
/** }
* @param \WebPage $oP $aExcludedByClass[get_class($oObj)][] = $oObj->GetKey();
* @param array $aResults }
* @param bool $bLazyLoading
*
* @return UIContentBlock
* @throws \CoreException
* @throws \DictExceptionMissingString
* @throws \ReflectionException
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
*
* @since 3.1.1 3.2.0 N°3767
*/
public function DisplayFilterBox(WebPage $oP, array $aResults, bool $bLazyLoading = false): UIContentBlock
{
$sSftShort = Dict::S('UI:ElementsDisplayed'); $sSftShort = Dict::S('UI:ElementsDisplayed');
$oBlock = UIContentBlockUIBlockFactory::MakeStandard(null, ['not-printable']); $oP->add("<div class=\"not-printable\">\n");
$oUiSearchBlock = new Panel($sSftShort, [], Panel::ENUM_COLOR_SCHEME_CYAN, 'dh_flash'); $oUiSearchBlock = new Panel($sSftShort, [], Panel::ENUM_COLOR_SCHEME_CYAN, 'dh_flash');
$oUiSearchBlock->SetCSSClasses(["ibo-search-form-panel", "display_block"]) $oUiSearchBlock->SetCSSClasses(["ibo-search-form-panel", "display_block"]);
->SetIsCollapsible(true); $oUiSearchBlock->SetIsCollapsible(true);
$oUiHtmlBlock = new Combodo\iTop\Application\UI\Base\Component\Html\Html(
$oUiHtmlBlock = new Html(
<<<EOF <<<EOF
<div id="ds_flash" class="search_box ibo-display-graph--search-box"> <div id="ds_flash" class="search_box ibo-display-graph--search-box">
@@ -1672,23 +1626,11 @@ EOF
$oUiHtmlBlock->AddHtml("<button type=\"button\" id=\"ReloadMovieBtn\" class=\"ibo-button ibo-is-neutral ibo-is-regular\" onClick=\"$sOnCLick\">".Dict::S('UI:Button:Refresh')."</button></div></form>"); $oUiHtmlBlock->AddHtml("<button type=\"button\" id=\"ReloadMovieBtn\" class=\"ibo-button ibo-is-neutral ibo-is-regular\" onClick=\"$sOnCLick\">".Dict::S('UI:Button:Refresh')."</button></div></form>");
} }
$oUiHtmlBlock->AddHtml("</div>\n"); $oUiHtmlBlock->AddHtml("</div>\n");
$oUiHtmlBlock->AddHtml("</div>\n"); // class="not-printable"
$oUiSearchBlock->AddSubBlock($oUiHtmlBlock); $oUiSearchBlock->AddSubBlock($oUiHtmlBlock);
$oBlock->AddSubBlock($oUiSearchBlock); $oP->AddUiBlock($oUiSearchBlock);
return $oBlock;
}
public function GetFilteringData(string $sContextKey, array $aContextParams, array $aExcludedObjects): array
{
$aContextDefs = static::GetContextDefinitions($sContextKey, true, $aContextParams);
$aExcludedByClass = array();
foreach ($aExcludedObjects as $oObj) {
if (!array_key_exists(get_class($oObj), $aExcludedByClass)) {
$aExcludedByClass[get_class($oObj)] = array();
}
$aExcludedByClass[get_class($oObj)][] = $oObj->GetKey();
}
$aAdditionalContexts = array(); $aAdditionalContexts = array();
foreach ($aContextDefs as $sKey => $aDefinition) { foreach ($aContextDefs as $sKey => $aDefinition) {
$aAdditionalContexts[] = array('key' => $sKey, 'label' => Dict::S($aDefinition['dict']), 'oql' => $aDefinition['oql'], 'default' => (array_key_exists('default', $aDefinition) && ($aDefinition['default'] == 'yes'))); $aAdditionalContexts[] = array('key' => $sKey, 'label' => Dict::S($aDefinition['dict']), 'oql' => $aDefinition['oql'], 'default' => (array_key_exists('default', $aDefinition) && ($aDefinition['default'] == 'yes')));

View File

@@ -242,33 +242,44 @@ class EventIssue extends Event
{ {
if (is_string($sValue)) if (is_string($sValue))
{ {
if (mb_strlen($sValue) < 256) { if (strlen($sValue) < 256)
{
$aPost[$sKey] = $sValue; $aPost[$sKey] = $sValue;
} else {
$aPost[$sKey] = "!long string: ".mb_strlen($sValue)." chars";
} }
} else { else
{
$aPost[$sKey] = "!long string: ".strlen($sValue). " chars";
}
}
else
{
// Not a string (avoid warnings in case the value cannot be easily casted into a string) // Not a string (avoid warnings in case the value cannot be easily casted into a string)
$aPost[$sKey] = @(string)$sValue; $aPost[$sKey] = @(string) $sValue;
} }
} }
$this->Set('arguments_post', $aPost); $this->Set('arguments_post', $aPost);
} else { }
else
{
$this->Set('arguments_post', array()); $this->Set('arguments_post', array());
} }
$sLength = mb_strlen($this->Get('issue'));
if ($sLength > 255) { $sLength = strlen($this->Get('issue'));
$this->Set('issue', mb_substr($this->Get('issue'), 0, 210)." -truncated ($sLength chars)"); if ($sLength > 255)
{
$this->Set('issue', substr($this->Get('issue'), 0, 200)." -truncated ($sLength chars)");
} }
$sLength = mb_strlen($this->Get('impact')); $sLength = strlen($this->Get('impact'));
if ($sLength > 255) { if ($sLength > 255)
$this->Set('impact', mb_substr($this->Get('impact'), 0, 210)." -truncated ($sLength chars)"); {
$this->Set('impact', substr($this->Get('impact'), 0, 200)." -truncated ($sLength chars)");
} }
$sLength = mb_strlen($this->Get('page')); $sLength = strlen($this->Get('page'));
if ($sLength > 255) { if ($sLength > 255)
$this->Set('page', mb_substr($this->Get('page'), 0, 210)." -truncated ($sLength chars)"); {
$this->Set('page', substr($this->Get('page'), 0, 200)." -truncated ($sLength chars)");
} }
} }
} }

View File

@@ -10,7 +10,6 @@ use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory; use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\ColumnUIBlockFactory; use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\ColumnUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactory; use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactory;
use Combodo\iTop\Application\Helper\ExportHelper;
require_once(APPROOT.'application/xlsxwriter.class.php'); require_once(APPROOT.'application/xlsxwriter.class.php');
@@ -83,7 +82,6 @@ class ExcelBulkExport extends TabularBulkExport
case 'xlsx_options': case 'xlsx_options':
$oPanel = PanelUIBlockFactory::MakeNeutral(Dict::S('Core:BulkExport:XLSXOptions')); $oPanel = PanelUIBlockFactory::MakeNeutral(Dict::S('Core:BulkExport:XLSXOptions'));
$oPanel->AddSubBlock(ExportHelper::GetAlertForExcelMaliciousInjection());
$oMulticolumn = MultiColumnUIBlockFactory::MakeStandard(); $oMulticolumn = MultiColumnUIBlockFactory::MakeStandard();
$oPanel->AddSubBlock($oMulticolumn); $oPanel->AddSubBlock($oMulticolumn);

View File

@@ -101,7 +101,7 @@ EOF;
EOF; EOF;
SetupUtils::builddir(dirname($sFilePath)); SetupUtils::builddir(dirname($sFilePath));
file_put_contents($sFilePath, $content, LOCK_EX); file_put_contents($sFilePath, $content);
} }
} }
Dict::SetUserLanguage($sUserLang); Dict::SetUserLanguage($sUserLang);

View File

@@ -3,7 +3,7 @@
// //
// This file is part of iTop. // This file is part of iTop.
// //
// iTop is free software; you can redistribute it and/or modify // iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by // it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
@@ -576,11 +576,6 @@ class LogChannels
public const DATATABLE = 'Datatable'; public const DATATABLE = 'Datatable';
public const DEADLOCK = 'DeadLock'; public const DEADLOCK = 'DeadLock';
/**
* @var string Everything related to PHP sessions tracking
* @since 3.1.1 3.2.0 N°6901
*/
public const SESSIONTRACKER = 'SessionTracker';
/** /**
* @var string Everything related to the datamodel CRUD * @var string Everything related to the datamodel CRUD
@@ -1143,13 +1138,9 @@ class DeprecatedCallsLog extends LogAPI
parent::Enable($sTargetFile); parent::Enable($sTargetFile);
if ( if (
( (false === defined('ITOP_PHPUNIT_RUNNING_CONSTANT_NAME'))
(false === defined(ITOP_PHPUNIT_RUNNING_CONSTANT_NAME))
|| (defined(ITOP_PHPUNIT_RUNNING_CONSTANT_NAME) && (constant(ITOP_PHPUNIT_RUNNING_CONSTANT_NAME) !== true))
)
&& static::IsLogLevelEnabledSafe(self::LEVEL_WARNING, self::ENUM_CHANNEL_PHP_LIBMETHOD) && static::IsLogLevelEnabledSafe(self::LEVEL_WARNING, self::ENUM_CHANNEL_PHP_LIBMETHOD)
) { ) {
IssueLog::Trace('Setting '.static::class.' error handler to catch DEPRECATED', static::ENUM_CHANNEL_PHP_LIBMETHOD);
set_error_handler([static::class, 'DeprecatedNoticesErrorHandler'], E_DEPRECATED | E_USER_DEPRECATED); set_error_handler([static::class, 'DeprecatedNoticesErrorHandler'], E_DEPRECATED | E_USER_DEPRECATED);
} }
} }
@@ -1301,7 +1292,19 @@ class DeprecatedCallsLog extends LogAPI
} }
$aStack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3); $aStack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
$sMessage = self::GetMessageFromStack($aStack); $iStackDeprecatedMethodLevel = 1; // level 0 = current method, level 1 = method containing the `NotifyDeprecatedPhpMethod` call
$sDeprecatedObject = $aStack[$iStackDeprecatedMethodLevel]['class'];
$sDeprecatedMethod = $aStack[$iStackDeprecatedMethodLevel]['function'];
$sCallerFile = $aStack[$iStackDeprecatedMethodLevel]['file'];
$sCallerLine = $aStack[$iStackDeprecatedMethodLevel]['line'];
$sMessage = "Call to {$sDeprecatedObject}::{$sDeprecatedMethod} in {$sCallerFile}#L{$sCallerLine}";
$iStackCallerMethodLevel = $iStackDeprecatedMethodLevel + 1; // level 2 = caller of the deprecated method
if (array_key_exists($iStackCallerMethodLevel, $aStack)) {
$sCallerObject = $aStack[$iStackCallerMethodLevel]['class'];
$sCallerMethod = $aStack[$iStackCallerMethodLevel]['function'];
$sMessage .= " ({$sCallerObject}::{$sCallerMethod})";
}
if (!is_null($sAdditionalMessage)) { if (!is_null($sAdditionalMessage)) {
$sMessage .= ' : '.$sAdditionalMessage; $sMessage .= ' : '.$sAdditionalMessage;
@@ -1310,45 +1313,6 @@ class DeprecatedCallsLog extends LogAPI
static::Warning($sMessage, self::ENUM_CHANNEL_PHP_METHOD); static::Warning($sMessage, self::ENUM_CHANNEL_PHP_METHOD);
} }
/**
* @param array $aDebugBacktrace data from {@see debug_backtrace()}
*
* @return string message to print to the log
*/
private static function GetMessageFromStack(array $aDebugBacktrace): string
{
// level 0 = current method
// level 1 = deprecated method, containing the `NotifyDeprecatedPhpMethod` call
$sMessage = 'Call'.self::GetMessageForCurrentStackLevel($aDebugBacktrace[1], " to ");
// level 2 = caller of the deprecated method
if (array_key_exists(2, $aDebugBacktrace)) {
$sMessage .= ' (from ';
$sMessage .= self::GetMessageForCurrentStackLevel($aDebugBacktrace[2]);
$sMessage .= ')';
}
return $sMessage;
}
private static function GetMessageForCurrentStackLevel(array $aCurrentLevelDebugTrace, ?string $sPrefix = ""): string
{
$sMessage = "";
if (array_key_exists('class', $aCurrentLevelDebugTrace)) {
$sDeprecatedObject = $aCurrentLevelDebugTrace['class'];
$sDeprecatedMethod = $aCurrentLevelDebugTrace['function'] ?? "";
$sMessage = "{$sPrefix}{$sDeprecatedObject}::{$sDeprecatedMethod} in ";
}
if (array_key_exists('file', $aCurrentLevelDebugTrace)) {
$sCallerFile = $aCurrentLevelDebugTrace['file'];
$sCallerLine = $aCurrentLevelDebugTrace['line'] ?? "";
$sMessage .= "{$sCallerFile}#L{$sCallerLine}";
}
return $sMessage;
}
/** /**
* @param string|null $sAdditionalMessage * @param string|null $sAdditionalMessage
* @since 3.1.0 * @since 3.1.0

View File

@@ -1445,10 +1445,8 @@ abstract class MetaModel
* *
* @return AttributeDefinition[] * @return AttributeDefinition[]
* @throws \CoreException * @throws \CoreException
*
* @see GetAttributesList for attcode list
*/ */
final public static function ListAttributeDefs($sClass) final static public function ListAttributeDefs($sClass)
{ {
self::_check_subclass($sClass); self::_check_subclass($sClass);
return self::$m_aAttribDefs[$sClass]; return self::$m_aAttribDefs[$sClass];
@@ -1461,10 +1459,8 @@ abstract class MetaModel
* @param string[] $aDesiredAttTypes Array of AttributeDefinition classes to filter the list on * @param string[] $aDesiredAttTypes Array of AttributeDefinition classes to filter the list on
* @param string|null $sListCode If provided, attributes will be limited to those in this zlist * @param string|null $sListCode If provided, attributes will be limited to those in this zlist
* *
* @return string[] list of attcodes * @return array
* @throws \CoreException * @throws \CoreException
*
* @see ListAttributeDefs to get AttributeDefinition array instead
*/ */
final public static function GetAttributesList(string $sClass, array $aDesiredAttTypes = [], ?string $sListCode = null) final public static function GetAttributesList(string $sClass, array $aDesiredAttTypes = [], ?string $sListCode = null)
{ {
@@ -4267,17 +4263,16 @@ abstract class MetaModel
]; ];
IssueLog::Warning("Unresolved placeholders due to null object in current context", null, IssueLog::Warning("Unresolved placeholders due to null object in current context", null,
$aContext); $aContext);
$aPlaceholders[$sPlaceHolderKey] = Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey); $aPlaceholders[$sPlaceHolderKey] = \Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey);
foreach ($aCurrentUser as $sField) { foreach ($aCurrentUser as $sField) {
$sPlaceHolderKey = $sPlaceHolderPrefix . "->$sField"; $sPlaceHolderKey = $sPlaceHolderPrefix . "->$sField";
$aPlaceholders[$sPlaceHolderKey] = Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey); $aPlaceholders[$sPlaceHolderKey] = \Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey);
} }
} else { } else {
$aPlaceholders[$sPlaceHolderKey] = $oObject; $aPlaceholders[$sPlaceHolderKey] = $oObject;
foreach ($aCurrentUser as $sField) { foreach ($aCurrentUser as $sField) {
$sPlaceHolderKey = $sPlaceHolderPrefix . "->$sField"; $sPlaceHolderKey = $sPlaceHolderPrefix . "->$sField";
// Mind that the "id" is not viewed as a valid att. code by \MetaModel::IsValidAttCode() so we have to test it manually if (false === MetaModel::IsValidAttCode(get_class($oObject), $sField)){
if ($sField !== "id" && false === MetaModel::IsValidAttCode(get_class($oObject), $sField)){
$aContext = [ $aContext = [
"current_user_id" => UserRights::GetUserId(), "current_user_id" => UserRights::GetUserId(),
"obj_class" => get_class($oObject), "obj_class" => get_class($oObject),
@@ -4286,7 +4281,7 @@ abstract class MetaModel
]; ];
IssueLog::Warning("Unresolved placeholder due to invalid attribute", null, IssueLog::Warning("Unresolved placeholder due to invalid attribute", null,
$aContext); $aContext);
$aPlaceholders[$sPlaceHolderKey] = Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey); $aPlaceholders[$sPlaceHolderKey] = \Dict::Format("Core:Placeholder:CannotBeResolved", $sPlaceHolderKey);
continue; continue;
} }
@@ -5156,7 +5151,7 @@ abstract class MetaModel
*/ */
protected static function DBCreateTables($aCallback = null) protected static function DBCreateTables($aCallback = null)
{ {
[$aErrors, $aSugFix, $aCondensedQueries] = self::DBCheckFormat(); list($aErrors, $aSugFix, $aCondensedQueries) = self::DBCheckFormat();
//$sSQL = implode('; ', $aCondensedQueries); Does not work - multiple queries not allowed //$sSQL = implode('; ', $aCondensedQueries); Does not work - multiple queries not allowed
foreach($aCondensedQueries as $sQuery) foreach($aCondensedQueries as $sQuery)
@@ -5178,7 +5173,7 @@ abstract class MetaModel
*/ */
protected static function DBCreateViews() protected static function DBCreateViews()
{ {
[$aErrors, $aSugFix] = self::DBCheckViews(); list($aErrors, $aSugFix) = self::DBCheckViews();
foreach($aSugFix as $sClass => $aTarget) foreach($aSugFix as $sClass => $aTarget)
{ {
@@ -6846,15 +6841,24 @@ abstract class MetaModel
$sClass = $aRow[$sClassAlias."finalclass"]; $sClass = $aRow[$sClassAlias."finalclass"];
} }
// if an object is already being updated, then this method will return this object instead of recreating a new one.
// At this point the method DBUpdate of a new object with the same class and id won't do anything due to reentrance protection,
// so to ensure that the potential modifications are correctly saved, the object currently being updated is returned.
// DBUpdate() method then will take care that all the modifications will be saved.
if (array_key_exists($sClassAlias.'id', $aRow)) {
$iKey = $aRow[$sClassAlias."id"];
$oObject = self::GetReentranceObject($sClass, $iKey);
if ($oObject !== false) {
return $oObject;
}
}
return new $sClass($aRow, $sClassAlias, $aAttToLoad, $aExtendedDataSpec); return new $sClass($aRow, $sClassAlias, $aAttToLoad, $aExtendedDataSpec);
} }
/** /**
* Instantiate an object already persisted to the Database. * Instantiate an object already persisted to the Database.
* *
* Note that LinkedSet attributes are not loaded.
* DBObject::Reload() will be called when getting a LinkedSet attribute
*
* @api * @api
* @see MetaModel::GetObjectWithArchive to get object even if it's archived * @see MetaModel::GetObjectWithArchive to get object even if it's archived
* @see utils::PushArchiveMode() to enable search on archived objects * @see utils::PushArchiveMode() to enable search on archived objects
@@ -6918,22 +6922,6 @@ abstract class MetaModel
return $iCount === 1; return $iCount === 1;
} }
public static function GetFinalClassName(string $sClass, int $iKey): string
{
if (MetaModel::IsStandaloneClass($sClass)) {
return $sClass;
}
$sRootClass = MetaModel::GetRootClass($sClass);
$sTable = MetaModel::DBGetTable($sRootClass);
$sKeyCol = MetaModel::DBGetKey($sRootClass);
$sEscapedKey = CMDBSource::Quote($iKey);
$sFinalClassField = Metamodel::DBGetClassField($sRootClass);
$sQuery = "SELECT `{$sFinalClassField}` FROM `{$sTable}` WHERE `{$sKeyCol}` = {$sEscapedKey}";
return CMDBSource::QueryToScalar($sQuery);
}
/** /**
* Search for the specified class and id. If the object is archived it will be returned anyway (this is for pre-2.4 * Search for the specified class and id. If the object is archived it will be returned anyway (this is for pre-2.4
* module compatibility, see N.1108) * module compatibility, see N.1108)

View File

@@ -22,9 +22,7 @@
* A class to serialize the execution of some code sections * A class to serialize the execution of some code sections
* Emulates the API of PECL Mutex class * Emulates the API of PECL Mutex class
* Relies on MySQL locks because the API sem_get is not always present in the * Relies on MySQL locks because the API sem_get is not always present in the
* installed PHP. * installed PHP.
*
* @link https://dev.mysql.com/doc/refman/5.7/en/locking-functions.html MySQL locking functions documentation
* *
* @copyright Copyright (C) 2013-2023 Combodo SARL * @copyright Copyright (C) 2013-2023 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0

View File

@@ -169,7 +169,7 @@ class ormCaseLog {
} }
// Process the case of an eventual remainder (quick migration of AttributeText fields) // Process the case of an eventual remainder (quick migration of AttributeText fields)
if ($iPos < (utils::StrLen($this->m_sLog) - 1)) if ($iPos < (strlen($this->m_sLog) - 1))
{ {
$sTextEntry = substr($this->m_sLog, $iPos); $sTextEntry = substr($this->m_sLog, $iPos);
@@ -292,7 +292,7 @@ class ormCaseLog {
} }
// Process the case of an eventual remainder (quick migration of AttributeText fields) // Process the case of an eventual remainder (quick migration of AttributeText fields)
if ($iPos < (utils::StrLen($this->m_sLog) - 1)) { if ($iPos < (strlen($this->m_sLog) - 1)) {
$sTextEntry = substr($this->m_sLog, $iPos); $sTextEntry = substr($this->m_sLog, $iPos);
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", utils::EscapeHtml($sTextEntry)); $sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", utils::EscapeHtml($sTextEntry));
@@ -373,7 +373,7 @@ class ormCaseLog {
} }
// Process the case of an eventual remainder (quick migration of AttributeText fields) // Process the case of an eventual remainder (quick migration of AttributeText fields)
if ($iPos < (utils::StrLen($this->m_sLog) - 1)) { if ($iPos < (strlen($this->m_sLog) - 1)) {
$sTextEntry = substr($this->m_sLog, $iPos); $sTextEntry = substr($this->m_sLog, $iPos);
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", utils::EscapeHtml($sTextEntry)); $sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", utils::EscapeHtml($sTextEntry));
@@ -467,7 +467,7 @@ class ormCaseLog {
$oBlock->AddSubBlock($oCollapsibleBlock); $oBlock->AddSubBlock($oCollapsibleBlock);
} }
// Process the case of an eventual remainder (quick migration of AttributeText fields) // Process the case of an eventual remainder (quick migration of AttributeText fields)
if ($iPos < (utils::StrLen($this->m_sLog) - 1)) { if ($iPos < (strlen($this->m_sLog) - 1)) {
// In this case the format is always "text" // In this case the format is always "text"
$sTextEntry = substr($this->m_sLog, $iPos); $sTextEntry = substr($this->m_sLog, $iPos);
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", utils::EscapeHtml($sTextEntry)); $sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", utils::EscapeHtml($sTextEntry));

View File

@@ -343,6 +343,6 @@ class ormDocument
*/ */
public function GetSignature(): string public function GetSignature(): string
{ {
return md5($this->GetData() ?? ''); return md5($this->GetData());
} }
} }

View File

@@ -537,7 +537,7 @@ EOF
} }
else else
{ {
throw new Exception('graphviz not found'); throw new Exception('graphviz not found (executable path: '.$sDotExecutable.')');
} }
return $sHtml; return $sHtml;
} }
@@ -592,7 +592,7 @@ EOF
} }
else else
{ {
throw new Exception('graphviz not found'); throw new Exception('graphviz not found (executable path: '.$sDotExecutable.')');
} }
return $sHtml; return $sHtml;
} }

View File

@@ -256,38 +256,6 @@ abstract class TriggerOnObject extends Trigger
} }
} }
/**
* Activate trigger based on attribute list given instead of changed attributes
*
* @param array $aContextArgs
* @param array|null $aAttributes if null default to changed attributes
*
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
* @since 3.1.1 3.2.0 N°6228
*/
public function DoActivateForSpecificAttributes(array $aContextArgs, ?array $aAttributes)
{
if (isset($aContextArgs['this->object()']))
{
/** @var \DBObject $oObject */
$oObject = $aContextArgs['this->object()'];
if (is_null($aAttributes)) {
$aChanges = $oObject->ListPreviousValuesForUpdatedAttributes();
} else {
$aChanges = array_fill_keys($aAttributes, true);
}
if (false === $this->IsTargetObject($oObject->GetKey(), $aChanges)) {
return;
}
}
parent::DoActivate($aContextArgs);
}
/** /**
* @param $iObjectId * @param $iObjectId
* @param array $aChanges * @param array $aChanges

View File

@@ -161,7 +161,7 @@ abstract class UserRightsAddOnAPI
$oSearchSharers->AllowAllData(); $oSearchSharers->AllowAllData();
$oSearchSharers->AddCondition_ReferencedBy($oShareSearch, 'sharing_org_id'); $oSearchSharers->AddCondition_ReferencedBy($oShareSearch, 'sharing_org_id');
$aSharers = array(); $aSharers = array();
foreach($oSearchSharers->SelectAttributeToArray('id') as $aRow) foreach($oSearchSharers->ToDataArray(array('id')) as $aRow)
{ {
$aSharers[] = $aRow['id']; $aSharers[] = $aRow['id'];
} }
@@ -186,7 +186,7 @@ abstract class UserRightsAddOnAPI
$oOrgField = new FieldExpression('org_id', $sShareClass); $oOrgField = new FieldExpression('org_id', $sShareClass);
$oSearchShares->AddConditionExpression(new BinaryExpression($oOrgField, 'IN', $oListExpr)); $oSearchShares->AddConditionExpression(new BinaryExpression($oOrgField, 'IN', $oListExpr));
$aShared = array(); $aShared = array();
foreach($oSearchShares->SelectAttributeToArray($sShareAttCode) as $aRow) foreach($oSearchShares->ToDataArray(array($sShareAttCode)) as $aRow)
{ {
$aShared[] = $aRow[$sShareAttCode]; $aShared[] = $aRow[$sShareAttCode];
} }
@@ -248,7 +248,7 @@ abstract class User extends cmdbAbstractObject
"depends_on" => array(), "depends_on" => array(),
))); )));
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("profile_list",array("linked_class" => "URP_UserProfile", "ext_key_to_me" => "userid", "ext_key_to_remote" => "profileid", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => array(), "display_style" => 'property', "with_php_constraint" => true, "with_php_computation" => true))); MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("profile_list",array("linked_class" => "URP_UserProfile", "ext_key_to_me" => "userid", "ext_key_to_remote" => "profileid", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => array(), "display_style" => 'property', "with_php_constraint" => true)));
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("allowed_org_list", array("linked_class" => "URP_UserOrg", "ext_key_to_me" => "userid", "ext_key_to_remote" => "allowed_org_id", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => array(), 'with_php_constraint' => true))); MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("allowed_org_list", array("linked_class" => "URP_UserOrg", "ext_key_to_me" => "userid", "ext_key_to_remote" => "allowed_org_id", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => array(), 'with_php_constraint' => true)));
MetaModel::Init_AddAttribute(new AttributeCaseLog("log", array("sql" => 'log', "is_null_allowed" => true, "default_value" => '', "allowed_values" => null, "depends_on" => array(), "always_load_in_tables" => false))); MetaModel::Init_AddAttribute(new AttributeCaseLog("log", array("sql" => 'log', "is_null_allowed" => true, "default_value" => '', "allowed_values" => null, "depends_on" => array(), "always_load_in_tables" => false)));
@@ -1121,7 +1121,9 @@ class UserRights
} }
/** /**
* @return string connected {@see User} login field value, otherwise empty string * Return the current user login or an empty string if nobody connected.
*
* @return string
*/ */
public static function GetUser() public static function GetUser()
{ {
@@ -1569,9 +1571,9 @@ class UserRights
/** /**
* @param string $sClass * @param string $sClass
* @param int $iActionCode see UR_ACTION_* constants * @param int $iActionCode
* @param DBObjectSet $oInstanceSet * @param \DBObjectSet $oInstanceSet
* @param User $oUser * @param \User $oUser
* *
* @return int (UR_ALLOWED_YES|UR_ALLOWED_NO|UR_ALLOWED_DEPENDS) * @return int (UR_ALLOWED_YES|UR_ALLOWED_NO|UR_ALLOWED_DEPENDS)
* @throws \CoreException * @throws \CoreException

View File

@@ -80,29 +80,16 @@ $ibo-field--enable-bulk--checkbox--margin-left: $ibo-spacing-300 !default;
} }
} }
} }
/*N°6543 - We need the rule to keep text inside the column when width is defined*/
&[data-attribute-type="AttributeHtml"],
&[data-attribute-type="AttributeText"] {
&[data-attribute-flag-read-only="true"] {
display: grid;
> .ibo-field--value {
max-width: 100%;
overflow: auto;
}
}
}
} }
/* Large field = Label on top, value below */ /* Large field = Label on top, value below */
.ibo-field-large { .ibo-field-large {
display: block; display: block;
.ibo-field--label { .ibo-field--label {
position: relative; /* Necessary for fullscreen toggler */ position: relative; /* Necessary for fullscreen toggler */
display: flex; display: flex;
align-items: center; align-items: center;
max-width: initial; max-width: initial;
width: 100%; width: 100%;
} }

View File

@@ -123,13 +123,6 @@ $ibo-fieldsorter--selected--background-color: $ibo-color-blue-200 !default;
.ibo-datatable--row-actions-toolbar{ .ibo-datatable--row-actions-toolbar{
justify-content: end; justify-content: end;
} }
/* N°6543 - We need the rule to keep text inside the column when width is defined */
> [data-attribute-type="AttributeHtml"],
> [data-attribute-type="AttributeText"] {
max-width: 100%;
overflow: auto;
}
} }
} }

File diff suppressed because one or more lines are too long

View File

@@ -58,9 +58,6 @@ $progress-bar-error-bg-color: #F56565 !default;
.center { .center {
text-align: center; text-align: center;
} }
.hidden {
display: none;
}
/* Animations */ /* Animations */
@keyframes progress_bar_color_ongoing { @keyframes progress_bar_color_ongoing {

View File

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

View File

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

View File

@@ -21,6 +21,6 @@
*/ */
Dict::Add('HU HU', 'Hungarian', 'Magyar', array( Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'Class:UserLDAP' => 'LDAP felhasználó', 'Class:UserLDAP' => 'LDAP felhasználó',
'Class:UserLDAP+' => 'LDAP vagy AD felhasználó', 'Class:UserLDAP+' => '',
'UserLDAP:server' => 'LDAP specifics~~', 'UserLDAP:server' => 'LDAP specifics~~',
)); ));

View File

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

View File

@@ -50,7 +50,7 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', array(
'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '~~', 'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '~~',
'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'One-time Password~~', 'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'One-time Password~~',
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~', 'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~',
'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewed on~~', 'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewal~~',
'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~', 'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~', 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~',
'UserLocal:password:expiration' => 'The fields below require an extension~~', 'UserLocal:password:expiration' => 'The fields below require an extension~~',

View File

@@ -35,7 +35,7 @@ Dict::Add('DA DA', 'Danish', 'Dansk', array(
'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '~~', 'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '~~',
'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'One-time Password~~', 'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'One-time Password~~',
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~', 'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~',
'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewed on~~', 'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewal~~',
'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~', 'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~', 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~',
'UserLocal:password:expiration' => 'The fields below require an extension~~', 'UserLocal:password:expiration' => 'The fields below require an extension~~',

View File

@@ -21,7 +21,7 @@
*/ */
Dict::Add('HU HU', 'Hungarian', 'Magyar', array( Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'Class:UserLocal' => ITOP_APPLICATION_SHORT.' felhasználó', 'Class:UserLocal' => ITOP_APPLICATION_SHORT.' felhasználó',
'Class:UserLocal+' => 'Rendszeren belül létrehozott felhasználó', 'Class:UserLocal+' => '',
'Class:UserLocal/Attribute:password' => 'Jelszó', 'Class:UserLocal/Attribute:password' => 'Jelszó',
'Class:UserLocal/Attribute:password+' => '', 'Class:UserLocal/Attribute:password+' => '',
'Class:UserLocal/Attribute:expiration' => 'Jelszó lejárati ideje', 'Class:UserLocal/Attribute:expiration' => 'Jelszó lejárati ideje',

View File

@@ -48,7 +48,7 @@ Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '~~', 'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '~~',
'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'One-time Password~~', 'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'One-time Password~~',
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~', 'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~',
'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewed on~~', 'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewal~~',
'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~', 'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~', 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~',
'UserLocal:password:expiration' => 'The fields below require an extension~~', 'UserLocal:password:expiration' => 'The fields below require an extension~~',

View File

@@ -35,7 +35,7 @@ Dict::Add('JA JP', 'Japanese', '日本語', array(
'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '~~', 'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '~~',
'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'One-time Password~~', 'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'One-time Password~~',
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~', 'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~',
'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewed on~~', 'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewal~~',
'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~', 'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~', 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~',
'UserLocal:password:expiration' => 'The fields below require an extension~~', 'UserLocal:password:expiration' => 'The fields below require an extension~~',

View File

@@ -47,7 +47,7 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', array(
'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '~~', 'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '~~',
'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'One-time Password~~', 'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'One-time Password~~',
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~', 'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~',
'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewed on~~', 'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewal~~',
'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~', 'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~', 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~',
'UserLocal:password:expiration' => 'The fields below require an extension~~', 'UserLocal:password:expiration' => 'The fields below require an extension~~',

View File

@@ -49,7 +49,7 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '~~', 'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '~~',
'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'One-time Password~~', 'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'One-time Password~~',
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~', 'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~',
'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewed on~~', 'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewal~~',
'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~', 'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~', 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~',
'UserLocal:password:expiration' => 'The fields below require an extension~~', 'UserLocal:password:expiration' => 'The fields below require an extension~~',

View File

@@ -3,7 +3,7 @@
SetupWebPage::AddModule( SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file __FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'authent-local/3.1.2', 'authent-local/3.1.0',
array( array(
// Identification // Identification
// //

View File

@@ -22,4 +22,4 @@
*/ */
Dict::Add('HU HU', 'Hungarian', 'Magyar', array( Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'theme:darkmoon' => 'Dark moon', 'theme:darkmoon' => 'Dark moon',
)); ));

View File

@@ -5,7 +5,7 @@
SetupWebPage::AddModule( SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file __FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'combodo-backoffice-darkmoon-theme/3.1.2', 'combodo-backoffice-darkmoon-theme/3.1.0',
array( array(
// Identification // Identification
// //

View File

@@ -23,9 +23,9 @@
// Database inconsistencies // Database inconsistencies
Dict::Add('CS CZ', 'Czech', 'Čeština', array( Dict::Add('CS CZ', 'Czech', 'Čeština', array(
// Dictionary entries go here // Dictionary entries go here
'Menu:DBToolsMenu' => 'Database integrity~~', 'Menu:DBToolsMenu' => 'DB Tools~~',
'DBTools:Class' => 'Class~~', 'DBTools:Class' => 'Class~~',
'DBTools:Title' => 'Database integrity check~~', 'DBTools:Title' => 'Database Maintenance Tools~~',
'DBTools:ErrorsFound' => 'Errors Found~~', 'DBTools:ErrorsFound' => 'Errors Found~~',
'DBTools:Indication' => 'Important: after fixing errors in the database you\'ll have to run the analysis again as new inconsistencies will be generated~~', 'DBTools:Indication' => 'Important: after fixing errors in the database you\'ll have to run the analysis again as new inconsistencies will be generated~~',
'DBTools:Disclaimer' => 'DISCLAIMER: BACKUP YOUR DATABASE BEFORE RUNNING THE FIXES~~', 'DBTools:Disclaimer' => 'DISCLAIMER: BACKUP YOUR DATABASE BEFORE RUNNING THE FIXES~~',

View File

@@ -23,9 +23,9 @@
// Database inconsistencies // Database inconsistencies
Dict::Add('DA DA', 'Danish', 'Dansk', array( Dict::Add('DA DA', 'Danish', 'Dansk', array(
// Dictionary entries go here // Dictionary entries go here
'Menu:DBToolsMenu' => 'Database integrity~~', 'Menu:DBToolsMenu' => 'DB Tools~~',
'DBTools:Class' => 'Class~~', 'DBTools:Class' => 'Class~~',
'DBTools:Title' => 'Database integrity check~~', 'DBTools:Title' => 'Database Maintenance Tools~~',
'DBTools:ErrorsFound' => 'Errors Found~~', 'DBTools:ErrorsFound' => 'Errors Found~~',
'DBTools:Indication' => 'Important: after fixing errors in the database you\'ll have to run the analysis again as new inconsistencies will be generated~~', 'DBTools:Indication' => 'Important: after fixing errors in the database you\'ll have to run the analysis again as new inconsistencies will be generated~~',
'DBTools:Disclaimer' => 'DISCLAIMER: BACKUP YOUR DATABASE BEFORE RUNNING THE FIXES~~', 'DBTools:Disclaimer' => 'DISCLAIMER: BACKUP YOUR DATABASE BEFORE RUNNING THE FIXES~~',

View File

@@ -42,15 +42,15 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'DBTools:FetchCheck' => 'Lehívás ellenőrzés (hosszú)', 'DBTools:FetchCheck' => 'Lehívás ellenőrzés (hosszú)',
'DBTools:SelectAnalysisType' => 'Válasszon elemzés típust', 'DBTools:SelectAnalysisType' => 'Válasszon elemzés típust',
'DBTools:Analyze' => 'Elemzés', 'DBTools:Analyze' => 'Elemzés',
'DBTools:Details' => 'Részletek megjelenítése', 'DBTools:Details' => 'Részletek mutatása',
'DBTools:ShowAll' => 'Minden hiba megjelenítése', 'DBTools:ShowAll' => 'Minden hiba mutatása',
'DBTools:Inconsistencies' => 'Adatbázis inkonzisztenciák', 'DBTools:Inconsistencies' => 'Adatbázis inkonzisztenciák',
'DBTools:DetailedErrorTitle' => '%2$s hiba a %1$s osztályban: %3$s', 'DBTools:DetailedErrorTitle' => '%2$s hiba a %1$s osztályban: %3$s',
'DBTools:DetailedErrorLimit' => 'List limited to %1$s errors~~', 'DBTools:DetailedErrorLimit' => 'List limited to %1$s errors~~',
'DBAnalyzer-Integrity-OrphanRecord' => 'Árva rekord a `%1$s` -ban, kell hogy legyen megfelelője a `%2$s` táblázatban', 'DBAnalyzer-Integrity-OrphanRecord' => 'Árva rekord a `%1$s` -ban, kell hogy legyen megfelelője a `%2$s` táblázatban',
'DBAnalyzer-Integrity-InvalidExtKey' => 'Érvénytelen a %1$s külső kulcs (oszlop: `%2$s.%3$s`)', 'DBAnalyzer-Integrity-InvalidExtKey' => 'Érvénytelen a %1$s külső kulcs (oszlop: `%2$s.%3$s`)',
'DBAnalyzer-Integrity-MissingExtKey' => 'Hiányzik a %1$s külső külcs (oszlop: `%2$s.%3$s`)', 'DBAnalyzer-Integrity-MissingExtKey' => 'Hiányzik a %1$s külső külcs (oszlop: `%2$s.%3$s`)',
'DBAnalyzer-Integrity-InvalidValue' => '%1$s értéke érvénytelen (oszlop: `%2$s.%3$s`)', 'DBAnalyzer-Integrity-InvalidValue' => '%1$s értéke érvénytelen (oszlop: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Néhány felhasználónak egyáltalán nincs fiókja', 'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Néhány felhasználónak egyáltalán nincs fiókja',
'DBAnalyzer-Integrity-HKInvalid' => 'Sérült a `%1$s` hierarchikus kulcs', 'DBAnalyzer-Integrity-HKInvalid' => 'Sérült a `%1$s` hierarchikus kulcs',
'DBAnalyzer-Fetch-Count-Error' => 'Lekérési hiba a `%1$s` -nál, %2$d bejegyzés lekérve / %3$d megszámlálva', 'DBAnalyzer-Fetch-Count-Error' => 'Lekérési hiba a `%1$s` -nál, %2$d bejegyzés lekérve / %3$d megszámlálva',

View File

@@ -23,9 +23,9 @@
// Database inconsistencies // Database inconsistencies
Dict::Add('IT IT', 'Italian', 'Italiano', array( Dict::Add('IT IT', 'Italian', 'Italiano', array(
// Dictionary entries go here // Dictionary entries go here
'Menu:DBToolsMenu' => 'Database integrity~~', 'Menu:DBToolsMenu' => 'DB Tools~~',
'DBTools:Class' => 'Class~~', 'DBTools:Class' => 'Class~~',
'DBTools:Title' => 'Database integrity check~~', 'DBTools:Title' => 'Database Maintenance Tools~~',
'DBTools:ErrorsFound' => 'Errors Found~~', 'DBTools:ErrorsFound' => 'Errors Found~~',
'DBTools:Indication' => 'Important: after fixing errors in the database you\'ll have to run the analysis again as new inconsistencies will be generated~~', 'DBTools:Indication' => 'Important: after fixing errors in the database you\'ll have to run the analysis again as new inconsistencies will be generated~~',
'DBTools:Disclaimer' => 'DISCLAIMER: BACKUP YOUR DATABASE BEFORE RUNNING THE FIXES~~', 'DBTools:Disclaimer' => 'DISCLAIMER: BACKUP YOUR DATABASE BEFORE RUNNING THE FIXES~~',

View File

@@ -23,9 +23,9 @@
// Database inconsistencies // Database inconsistencies
Dict::Add('JA JP', 'Japanese', '日本語', array( Dict::Add('JA JP', 'Japanese', '日本語', array(
// Dictionary entries go here // Dictionary entries go here
'Menu:DBToolsMenu' => 'Database integrity~~', 'Menu:DBToolsMenu' => 'DB Tools~~',
'DBTools:Class' => 'Class~~', 'DBTools:Class' => 'Class~~',
'DBTools:Title' => 'Database integrity check~~', 'DBTools:Title' => 'Database Maintenance Tools~~',
'DBTools:ErrorsFound' => 'Errors Found~~', 'DBTools:ErrorsFound' => 'Errors Found~~',
'DBTools:Indication' => 'Important: after fixing errors in the database you\'ll have to run the analysis again as new inconsistencies will be generated~~', 'DBTools:Indication' => 'Important: after fixing errors in the database you\'ll have to run the analysis again as new inconsistencies will be generated~~',
'DBTools:Disclaimer' => 'DISCLAIMER: BACKUP YOUR DATABASE BEFORE RUNNING THE FIXES~~', 'DBTools:Disclaimer' => 'DISCLAIMER: BACKUP YOUR DATABASE BEFORE RUNNING THE FIXES~~',

View File

@@ -12,7 +12,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
// Dictionary entries go here // Dictionary entries go here
'Menu:DBToolsMenu' => 'Инструменты БД', 'Menu:DBToolsMenu' => 'Инструменты БД',
'DBTools:Class' => 'Класс', 'DBTools:Class' => 'Класс',
'DBTools:Title' => 'Инструменты обслуживания базы данных', 'DBTools:Title' => 'Инструменты обслуживания базы данных~~',
'DBTools:ErrorsFound' => 'Найденные ошибки', 'DBTools:ErrorsFound' => 'Найденные ошибки',
'DBTools:Indication' => 'Important: after fixing errors in the database you\'ll have to run the analysis again as new inconsistencies will be generated~~', 'DBTools:Indication' => 'Important: after fixing errors in the database you\'ll have to run the analysis again as new inconsistencies will be generated~~',
'DBTools:Disclaimer' => 'DISCLAIMER: BACKUP YOUR DATABASE BEFORE RUNNING THE FIXES~~', 'DBTools:Disclaimer' => 'DISCLAIMER: BACKUP YOUR DATABASE BEFORE RUNNING THE FIXES~~',

View File

@@ -25,7 +25,7 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', array(
// Dictionary entries go here // Dictionary entries go here
'Menu:DBToolsMenu' => 'Database integrity~~', 'Menu:DBToolsMenu' => 'Database integrity~~',
'DBTools:Class' => 'Class~~', 'DBTools:Class' => 'Class~~',
'DBTools:Title' => 'Database integrity check~~', 'DBTools:Title' => 'Database Maintenance Tools~~',
'DBTools:ErrorsFound' => 'Errors Found~~', 'DBTools:ErrorsFound' => 'Errors Found~~',
'DBTools:Indication' => 'Important: after fixing errors in the database you\'ll have to run the analysis again as new inconsistencies will be generated~~', 'DBTools:Indication' => 'Important: after fixing errors in the database you\'ll have to run the analysis again as new inconsistencies will be generated~~',
'DBTools:Disclaimer' => 'DISCLAIMER: BACKUP YOUR DATABASE BEFORE RUNNING THE FIXES~~', 'DBTools:Disclaimer' => 'DISCLAIMER: BACKUP YOUR DATABASE BEFORE RUNNING THE FIXES~~',

View File

@@ -23,9 +23,9 @@
// Database inconsistencies // Database inconsistencies
Dict::Add('TR TR', 'Turkish', 'Türkçe', array( Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
// Dictionary entries go here // Dictionary entries go here
'Menu:DBToolsMenu' => 'Database integrity~~', 'Menu:DBToolsMenu' => 'DB Tools~~',
'DBTools:Class' => 'Class~~', 'DBTools:Class' => 'Class~~',
'DBTools:Title' => 'Database integrity check~~', 'DBTools:Title' => 'Database Maintenance Tools~~',
'DBTools:ErrorsFound' => 'Errors Found~~', 'DBTools:ErrorsFound' => 'Errors Found~~',
'DBTools:Indication' => 'Important: after fixing errors in the database you\'ll have to run the analysis again as new inconsistencies will be generated~~', 'DBTools:Indication' => 'Important: after fixing errors in the database you\'ll have to run the analysis again as new inconsistencies will be generated~~',
'DBTools:Disclaimer' => 'DISCLAIMER: BACKUP YOUR DATABASE BEFORE RUNNING THE FIXES~~', 'DBTools:Disclaimer' => 'DISCLAIMER: BACKUP YOUR DATABASE BEFORE RUNNING THE FIXES~~',

View File

@@ -24,7 +24,7 @@
/** @noinspection PhpUnhandledExceptionInspection */ /** @noinspection PhpUnhandledExceptionInspection */
SetupWebPage::AddModule( SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file __FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'combodo-db-tools/3.1.2', 'combodo-db-tools/3.1.0',
array( array(
// Identification // Identification
// //

View File

@@ -260,19 +260,19 @@
</classes> </classes>
<events> <events>
<event id="EVENT_ADD_ATTACHMENT_TO_OBJECT" _delta="define"> <event id="EVENT_ADD_ATTACHMENT_TO_OBJECT" _delta="define">
<name>Attachment added</name> <description>An attachment has been added to an object</description>
<description><![CDATA[An attachment has been added to an object]]></description>
<replaces>Attachment::AfterUpdate</replaces> <replaces>Attachment::AfterUpdate</replaces>
<sources> <sources>
<source id="Attachment">Attachment</source>
<source id="cmdbAbstractObject">cmdbAbstractObject</source> <source id="cmdbAbstractObject">cmdbAbstractObject</source>
</sources> </sources>
<event_data> <event_data>
<event_datum id="object"> <event_datum id="object">
<description>The object where the attachment is added</description> <description>The attachment updated</description>
<type>DBObject</type> <type>DBObject</type>
</event_datum> </event_datum>
<event_datum id="attachment"> <event_datum id="target_object">
<description>The attachment added to the objet</description> <description>The object to which the attachment is linked</description>
<type>DBObject</type> <type>DBObject</type>
</event_datum> </event_datum>
<event_datum id="debug_info"> <event_datum id="debug_info">
@@ -282,19 +282,19 @@
</event_data> </event_data>
</event> </event>
<event id="EVENT_REMOVE_ATTACHMENT_FROM_OBJECT" _delta="define"> <event id="EVENT_REMOVE_ATTACHMENT_FROM_OBJECT" _delta="define">
<name>Attachment removed</name> <description>An attachment has been removed from an object</description>
<description><![CDATA[An attachment has been removed from an object]]></description>
<replaces>Attachment::AfterUpdate</replaces> <replaces>Attachment::AfterUpdate</replaces>
<sources> <sources>
<source id="Attachment">Attachment</source>
<source id="cmdbAbstractObject">cmdbAbstractObject</source> <source id="cmdbAbstractObject">cmdbAbstractObject</source>
</sources> </sources>
<event_data> <event_data>
<event_datum id="object"> <event_datum id="object">
<description>The object where the attachment is removed</description> <description>The attachment updated</description>
<type>DBObject</type> <type>DBObject</type>
</event_datum> </event_datum>
<event_datum id="attachment"> <event_datum id="target_object">
<description>The attachment removed</description> <description>The object to which the attachment is linked</description>
<type>DBObject</type> <type>DBObject</type>
</event_datum> </event_datum>
<event_datum id="debug_info"> <event_datum id="debug_info">

View File

@@ -26,9 +26,9 @@ Dict::Add('EN US', 'English', 'English', array(
'Attachments:History_File_Removed' => 'Attachment %1$s removed.', 'Attachments:History_File_Removed' => 'Attachment %1$s removed.',
'Attachments:AddAttachment' => 'Add attachment: ', 'Attachments:AddAttachment' => 'Add attachment: ',
'Attachments:UploadNotAllowedOnThisSystem' => 'File upload in NOT allowed on this system.', 'Attachments:UploadNotAllowedOnThisSystem' => 'File upload in NOT allowed on this system.',
'Attachment:Max_Go' => '(Maximum file size: %1$s GB)', 'Attachment:Max_Go' => '(Maximum file size: %1$s Go)',
'Attachment:Max_Mo' => '(Maximum file size: %1$s MB)', 'Attachment:Max_Mo' => '(Maximum file size: %1$s Mo)',
'Attachment:Max_Ko' => '(Maximum file size: %1$s KB)', 'Attachment:Max_Ko' => '(Maximum file size: %1$s Ko)',
'Attachments:NoAttachment' => 'No attachment. ', 'Attachments:NoAttachment' => 'No attachment. ',
'Attachments:PreviewNotAvailable' => 'Preview not available for this type of attachment.', 'Attachments:PreviewNotAvailable' => 'Preview not available for this type of attachment.',
'Attachments:Error:FileTooLarge' => 'File is too large to be uploaded. %1$s', 'Attachments:Error:FileTooLarge' => 'File is too large to be uploaded. %1$s',

View File

@@ -34,7 +34,7 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'Attachment:Max_Ko' => '(Maximum fájlméret: %1$s KB)', 'Attachment:Max_Ko' => '(Maximum fájlméret: %1$s KB)',
'Attachments:NoAttachment' => 'Nincs melléklet. ', 'Attachments:NoAttachment' => 'Nincs melléklet. ',
'Attachments:PreviewNotAvailable' => 'Az előnézet nem érhető el ilyen típusú melléklethez', 'Attachments:PreviewNotAvailable' => 'Az előnézet nem érhető el ilyen típusú melléklethez',
'Attachments:Error:FileTooLarge' => 'Túl nagy a %1$s fájl a feltöltéshez.', 'Attachments:Error:FileTooLarge' => 'Túl nagy a fájl a feltöltéshez. %1$s',
'Attachments:Error:UploadedFileEmpty' => 'A kapott fájl üres, ezért nem csatolható. Vagy egy üres fájlt húzott be, vagy kérdezze meg a rendszergazdát, hátha az iTop szerver lemeze telt meg.', 'Attachments:Error:UploadedFileEmpty' => 'A kapott fájl üres, ezért nem csatolható. Vagy egy üres fájlt húzott be, vagy kérdezze meg a rendszergazdát, hátha az iTop szerver lemeze telt meg.',
'Attachments:Render:Icons' => 'Mutassa ikonként', 'Attachments:Render:Icons' => 'Mutassa ikonként',
'Attachments:Render:Table' => 'Mutassa listaként', 'Attachments:Render:Table' => 'Mutassa listaként',
@@ -52,7 +52,7 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'Class:Attachment/Attribute:expire+' => '~~', 'Class:Attachment/Attribute:expire+' => '~~',
'Class:Attachment/Attribute:temp_id' => 'Átmeneti azonosító', 'Class:Attachment/Attribute:temp_id' => 'Átmeneti azonosító',
'Class:Attachment/Attribute:temp_id+' => '~~', 'Class:Attachment/Attribute:temp_id+' => '~~',
'Class:Attachment/Attribute:item_class' => 'Elem típus', 'Class:Attachment/Attribute:item_class' => 'Elem osztály',
'Class:Attachment/Attribute:item_class+' => '~~', 'Class:Attachment/Attribute:item_class+' => '~~',
'Class:Attachment/Attribute:item_id' => 'Elem', 'Class:Attachment/Attribute:item_id' => 'Elem',
'Class:Attachment/Attribute:item_id+' => '~~', 'Class:Attachment/Attribute:item_id+' => '~~',

View File

@@ -29,9 +29,9 @@ Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Attachments:History_File_Removed' => 'Attachment %1$s removed.~~', 'Attachments:History_File_Removed' => 'Attachment %1$s removed.~~',
'Attachments:AddAttachment' => 'Add attachment: ~~', 'Attachments:AddAttachment' => 'Add attachment: ~~',
'Attachments:UploadNotAllowedOnThisSystem' => 'File upload in NOT allowed on this system.~~', 'Attachments:UploadNotAllowedOnThisSystem' => 'File upload in NOT allowed on this system.~~',
'Attachment:Max_Go' => '(Maximum file size: %1$s GB)~~', 'Attachment:Max_Go' => '(Maximum file size: %1$s Go)~~',
'Attachment:Max_Mo' => '(Maximum file size: %1$s MB)~~', 'Attachment:Max_Mo' => '(Maximum file size: %1$s Mo)~~',
'Attachment:Max_Ko' => '(Maximum file size: %1$s KB)~~', 'Attachment:Max_Ko' => '(Maximum file size: %1$s Ko)~~',
'Attachments:NoAttachment' => 'No attachment. ~~', 'Attachments:NoAttachment' => 'No attachment. ~~',
'Attachments:PreviewNotAvailable' => 'Preview not available for this type of attachment.~~', 'Attachments:PreviewNotAvailable' => 'Preview not available for this type of attachment.~~',
'Attachments:Error:FileTooLarge' => 'File is too large to be uploaded. %1$s~~', 'Attachments:Error:FileTooLarge' => 'File is too large to be uploaded. %1$s~~',

View File

@@ -29,9 +29,9 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
'Attachments:History_File_Removed' => 'Attachment %1$s removed.~~', 'Attachments:History_File_Removed' => 'Attachment %1$s removed.~~',
'Attachments:AddAttachment' => 'Add attachment: ~~', 'Attachments:AddAttachment' => 'Add attachment: ~~',
'Attachments:UploadNotAllowedOnThisSystem' => 'File upload in NOT allowed on this system.~~', 'Attachments:UploadNotAllowedOnThisSystem' => 'File upload in NOT allowed on this system.~~',
'Attachment:Max_Go' => '(Maximum file size: %1$s GB)~~', 'Attachment:Max_Go' => '(Maximum file size: %1$s Go)~~',
'Attachment:Max_Mo' => '(Maximum file size: %1$s MB)~~', 'Attachment:Max_Mo' => '(Maximum file size: %1$s Mo)~~',
'Attachment:Max_Ko' => '(Maximum file size: %1$s KB)~~', 'Attachment:Max_Ko' => '(Maximum file size: %1$s Ko)~~',
'Attachments:NoAttachment' => 'No attachment. ~~', 'Attachments:NoAttachment' => 'No attachment. ~~',
'Attachments:PreviewNotAvailable' => 'Preview not available for this type of attachment.~~', 'Attachments:PreviewNotAvailable' => 'Preview not available for this type of attachment.~~',
'Attachments:Error:FileTooLarge' => 'File is too large to be uploaded. %1$s~~', 'Attachments:Error:FileTooLarge' => 'File is too large to be uploaded. %1$s~~',

View File

@@ -262,26 +262,10 @@ class AttachmentPlugIn implements iApplicationUIExtension, iApplicationObjectExt
else else
{ {
$oAttachmentsRenderer->RenderViewAttachmentsList(); $oAttachmentsRenderer->RenderViewAttachmentsList();
} }
} }
/**
*
* @see ObjectFormManager::FinalizeAttachments() for the portal version
*
* @param $oObject
* @param $oChange
*
* @return void
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DeleteException
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
*/
protected static function UpdateAttachments($oObject, $oChange = null) protected static function UpdateAttachments($oObject, $oChange = null)
{ {
self::$m_bIsModified = false; self::$m_bIsModified = false;
@@ -307,8 +291,8 @@ class AttachmentPlugIn implements iApplicationUIExtension, iApplicationObjectExt
// Remove attachments that are no longer attached to the current object // Remove attachments that are no longer attached to the current object
if (in_array($oAttachment->GetKey(), $aRemovedAttachmentIds)) if (in_array($oAttachment->GetKey(), $aRemovedAttachmentIds))
{ {
$aData = ['attachment' => $oAttachment]; $aData = ['target_object' => $oObject];
$oObject->FireEvent(EVENT_REMOVE_ATTACHMENT_FROM_OBJECT, $aData); $oAttachment->FireEvent(EVENT_REMOVE_ATTACHMENT_FROM_OBJECT, $aData);
$oAttachment->DBDelete(); $oAttachment->DBDelete();
$aActions[] = self::GetActionChangeOp($oAttachment, false /* false => deletion */); $aActions[] = self::GetActionChangeOp($oAttachment, false /* false => deletion */);
} }
@@ -336,8 +320,8 @@ class AttachmentPlugIn implements iApplicationUIExtension, iApplicationObjectExt
$oAttachment->DBUpdate(); $oAttachment->DBUpdate();
// temporary attachment confirmed, list it in the history // temporary attachment confirmed, list it in the history
$aActions[] = self::GetActionChangeOp($oAttachment, true /* true => creation */); $aActions[] = self::GetActionChangeOp($oAttachment, true /* true => creation */);
$aData = ['attachment' => $oAttachment]; $aData = ['target_object' => $oObject];
$oObject->FireEvent(EVENT_ADD_ATTACHMENT_TO_OBJECT, $aData); $oAttachment->FireEvent(EVENT_ADD_ATTACHMENT_TO_OBJECT, $aData);
} }
} }
if (count($aActions) > 0) if (count($aActions) > 0)

View File

@@ -19,7 +19,7 @@
SetupWebPage::AddModule( SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file __FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-attachments/3.1.2', 'itop-attachments/3.1.0',
array( array(
// Identification // Identification
// //

View File

@@ -23,8 +23,8 @@
Dict::Add('DA DA', 'Danish', 'Dansk', array( Dict::Add('DA DA', 'Danish', 'Dansk', array(
'bkp-backup-running' => 'A backup is running. Please wait...~~', 'bkp-backup-running' => 'A backup is running. Please wait...~~',
'bkp-restore-running' => 'A restore is running. Please wait...~~', 'bkp-restore-running' => 'A restore is running. Please wait...~~',
'Menu:BackupStatus' => 'Backups~~', 'Menu:BackupStatus' => 'Scheduled Backups~~',
'bkp-status-title' => 'Backups~~', 'bkp-status-title' => 'Scheduled Backups~~',
'bkp-status-checks' => 'Settings and checks~~', 'bkp-status-checks' => 'Settings and checks~~',
'bkp-mysqldump-ok' => 'mysqldump is present: %1$s~~', 'bkp-mysqldump-ok' => 'mysqldump is present: %1$s~~',
'bkp-mysqldump-notfound' => 'mysqldump could not be found: %1$s - Please make sure it is installed and in the path, or edit the configuration file to tune mysql_bindir.~~', 'bkp-mysqldump-notfound' => 'mysqldump could not be found: %1$s - Please make sure it is installed and in the path, or edit the configuration file to tune mysql_bindir.~~',
@@ -46,7 +46,7 @@ Dict::Add('DA DA', 'Danish', 'Dansk', array(
'bkp-status-backups-auto' => 'Scheduled backups~~', 'bkp-status-backups-auto' => 'Scheduled backups~~',
'bkp-status-backups-manual' => 'Manual backups~~', 'bkp-status-backups-manual' => 'Manual backups~~',
'bkp-status-backups-none' => 'No backup yet~~', 'bkp-status-backups-none' => 'No backup yet~~',
'bkp-next-backup' => 'The next backup will occur on <b>%1$s</b> (%2$s) at %3$s.~~', 'bkp-next-backup' => 'The next backup will occur on <b>%1$s</b> (%2$s) at %3$s~~',
'bkp-next-backup-unknown' => 'The next backup is <b>not scheduled</b> yet.~~', 'bkp-next-backup-unknown' => 'The next backup is <b>not scheduled</b> yet.~~',
'bkp-button-backup-now' => 'Backup now!~~', 'bkp-button-backup-now' => 'Backup now!~~',
'bkp-button-restore-now' => 'Restore!~~', 'bkp-button-restore-now' => 'Restore!~~',

View File

@@ -23,8 +23,8 @@
Dict::Add('HU HU', 'Hungarian', 'Magyar', array( Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'bkp-backup-running' => 'A mentés fut. Kérem várjon...', 'bkp-backup-running' => 'A mentés fut. Kérem várjon...',
'bkp-restore-running' => 'A visszaállítás fut. Kérem várjon...', 'bkp-restore-running' => 'A visszaállítás fut. Kérem várjon...',
'Menu:BackupStatus' => 'Biztonsági mentés', 'Menu:BackupStatus' => 'Ütemezett biztonsági mentés',
'bkp-status-title' => 'Adatbázis biztonsági mentés', 'bkp-status-title' => 'Ütemezett biztonsági mentés',
'bkp-status-checks' => 'Beállítás és ellenőrzés', 'bkp-status-checks' => 'Beállítás és ellenőrzés',
'bkp-mysqldump-ok' => 'mysqldump megvan: %1$s', 'bkp-mysqldump-ok' => 'mysqldump megvan: %1$s',
'bkp-mysqldump-notfound' => 'mysqldump nem található: %1$s - Győződjön meg róla, hogy telepítve van és szerepel az elérési útvonalban, vagy szerkessze a konfigurációs fájlt a mysql_bindir beállításához..', 'bkp-mysqldump-notfound' => 'mysqldump nem található: %1$s - Győződjön meg róla, hogy telepítve van és szerepel az elérési útvonalban, vagy szerkessze a konfigurációs fájlt a mysql_bindir beállításához..',
@@ -43,7 +43,7 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'bkp-table-size+' => '~~', 'bkp-table-size+' => '~~',
'bkp-table-actions' => 'Műveletek', 'bkp-table-actions' => 'Műveletek',
'bkp-table-actions+' => '~~', 'bkp-table-actions+' => '~~',
'bkp-status-backups-auto' => 'Automatikus biztonsági mentés', 'bkp-status-backups-auto' => 'Ütemezett biztonsági mentés',
'bkp-status-backups-manual' => 'Manuális biztonsági mentés', 'bkp-status-backups-manual' => 'Manuális biztonsági mentés',
'bkp-status-backups-none' => 'Még nincs biztonsági mentés', 'bkp-status-backups-none' => 'Még nincs biztonsági mentés',
'bkp-next-backup' => 'A következő mentés <b>%1$s</b> (%2$s) fog lefutni %3$s -kor', 'bkp-next-backup' => 'A következő mentés <b>%1$s</b> (%2$s) fog lefutni %3$s -kor',

View File

@@ -23,8 +23,8 @@
Dict::Add('IT IT', 'Italian', 'Italiano', array( Dict::Add('IT IT', 'Italian', 'Italiano', array(
'bkp-backup-running' => 'A backup is running. Please wait...~~', 'bkp-backup-running' => 'A backup is running. Please wait...~~',
'bkp-restore-running' => 'A restore is running. Please wait...~~', 'bkp-restore-running' => 'A restore is running. Please wait...~~',
'Menu:BackupStatus' => 'Backups~~', 'Menu:BackupStatus' => 'Scheduled backups~~',
'bkp-status-title' => 'Backups~~', 'bkp-status-title' => 'Scheduled Backups~~',
'bkp-status-checks' => 'Settings and checks~~', 'bkp-status-checks' => 'Settings and checks~~',
'bkp-mysqldump-ok' => 'mysqldump is present: %1$s~~', 'bkp-mysqldump-ok' => 'mysqldump is present: %1$s~~',
'bkp-mysqldump-notfound' => 'mysqldump could not be found: %1$s - Please make sure it is installed and in the path, or edit the configuration file to tune mysql_bindir.~~', 'bkp-mysqldump-notfound' => 'mysqldump could not be found: %1$s - Please make sure it is installed and in the path, or edit the configuration file to tune mysql_bindir.~~',
@@ -46,7 +46,7 @@ Dict::Add('IT IT', 'Italian', 'Italiano', array(
'bkp-status-backups-auto' => 'Scheduled backups~~', 'bkp-status-backups-auto' => 'Scheduled backups~~',
'bkp-status-backups-manual' => 'Manual backups~~', 'bkp-status-backups-manual' => 'Manual backups~~',
'bkp-status-backups-none' => 'No backup yet~~', 'bkp-status-backups-none' => 'No backup yet~~',
'bkp-next-backup' => 'The next backup will occur on <b>%1$s</b> (%2$s) at %3$s.~~', 'bkp-next-backup' => 'The next backup will occur on <b>%1$s</b> (%2$s) at %3$s~~',
'bkp-next-backup-unknown' => 'The next backup is <b>not scheduled</b> yet.~~', 'bkp-next-backup-unknown' => 'The next backup is <b>not scheduled</b> yet.~~',
'bkp-button-backup-now' => 'Backup now!~~', 'bkp-button-backup-now' => 'Backup now!~~',
'bkp-button-restore-now' => 'Restore!~~', 'bkp-button-restore-now' => 'Restore!~~',

View File

@@ -23,8 +23,8 @@
Dict::Add('JA JP', 'Japanese', '日本語', array( Dict::Add('JA JP', 'Japanese', '日本語', array(
'bkp-backup-running' => 'A backup is running. Please wait...~~', 'bkp-backup-running' => 'A backup is running. Please wait...~~',
'bkp-restore-running' => 'A restore is running. Please wait...~~', 'bkp-restore-running' => 'A restore is running. Please wait...~~',
'Menu:BackupStatus' => 'Backups~~', 'Menu:BackupStatus' => 'Scheduled backups~~',
'bkp-status-title' => 'Backups~~', 'bkp-status-title' => 'Scheduled Backups~~',
'bkp-status-checks' => 'Settings and checks~~', 'bkp-status-checks' => 'Settings and checks~~',
'bkp-mysqldump-ok' => 'mysqldump is present: %1$s~~', 'bkp-mysqldump-ok' => 'mysqldump is present: %1$s~~',
'bkp-mysqldump-notfound' => 'mysqldump could not be found: %1$s - Please make sure it is installed and in the path, or edit the configuration file to tune mysql_bindir.~~', 'bkp-mysqldump-notfound' => 'mysqldump could not be found: %1$s - Please make sure it is installed and in the path, or edit the configuration file to tune mysql_bindir.~~',
@@ -46,7 +46,7 @@ Dict::Add('JA JP', 'Japanese', '日本語', array(
'bkp-status-backups-auto' => 'Scheduled backups~~', 'bkp-status-backups-auto' => 'Scheduled backups~~',
'bkp-status-backups-manual' => 'Manual backups~~', 'bkp-status-backups-manual' => 'Manual backups~~',
'bkp-status-backups-none' => 'No backup yet~~', 'bkp-status-backups-none' => 'No backup yet~~',
'bkp-next-backup' => 'The next backup will occur on <b>%1$s</b> (%2$s) at %3$s.~~', 'bkp-next-backup' => 'The next backup will occur on <b>%1$s</b> (%2$s) at %3$s~~',
'bkp-next-backup-unknown' => 'The next backup is <b>not scheduled</b> yet.~~', 'bkp-next-backup-unknown' => 'The next backup is <b>not scheduled</b> yet.~~',
'bkp-button-backup-now' => 'Backup now!~~', 'bkp-button-backup-now' => 'Backup now!~~',
'bkp-button-restore-now' => 'Restore!~~', 'bkp-button-restore-now' => 'Restore!~~',

View File

@@ -23,8 +23,8 @@
Dict::Add('SK SK', 'Slovak', 'Slovenčina', array( Dict::Add('SK SK', 'Slovak', 'Slovenčina', array(
'bkp-backup-running' => 'A backup is running. Please wait...~~', 'bkp-backup-running' => 'A backup is running. Please wait...~~',
'bkp-restore-running' => 'A restore is running. Please wait...~~', 'bkp-restore-running' => 'A restore is running. Please wait...~~',
'Menu:BackupStatus' => 'Backups~~', 'Menu:BackupStatus' => 'Scheduled Backups~~',
'bkp-status-title' => 'Backups~~', 'bkp-status-title' => 'Scheduled Backups~~',
'bkp-status-checks' => 'Settings and checks~~', 'bkp-status-checks' => 'Settings and checks~~',
'bkp-mysqldump-ok' => 'mysqldump is present: %1$s~~', 'bkp-mysqldump-ok' => 'mysqldump is present: %1$s~~',
'bkp-mysqldump-notfound' => 'mysqldump could not be found: %1$s - Please make sure it is installed and in the path, or edit the configuration file to tune mysql_bindir.~~', 'bkp-mysqldump-notfound' => 'mysqldump could not be found: %1$s - Please make sure it is installed and in the path, or edit the configuration file to tune mysql_bindir.~~',
@@ -46,7 +46,7 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', array(
'bkp-status-backups-auto' => 'Scheduled backups~~', 'bkp-status-backups-auto' => 'Scheduled backups~~',
'bkp-status-backups-manual' => 'Manual backups~~', 'bkp-status-backups-manual' => 'Manual backups~~',
'bkp-status-backups-none' => 'No backup yet~~', 'bkp-status-backups-none' => 'No backup yet~~',
'bkp-next-backup' => 'The next backup will occur on <b>%1$s</b> (%2$s) at %3$s.~~', 'bkp-next-backup' => 'The next backup will occur on <b>%1$s</b> (%2$s) at %3$s~~',
'bkp-next-backup-unknown' => 'The next backup is <b>not scheduled</b> yet.~~', 'bkp-next-backup-unknown' => 'The next backup is <b>not scheduled</b> yet.~~',
'bkp-button-backup-now' => 'Backup now!~~', 'bkp-button-backup-now' => 'Backup now!~~',
'bkp-button-restore-now' => 'Restore!~~', 'bkp-button-restore-now' => 'Restore!~~',

View File

@@ -23,8 +23,8 @@
Dict::Add('TR TR', 'Turkish', 'Türkçe', array( Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
'bkp-backup-running' => 'A backup is running. Please wait...~~', 'bkp-backup-running' => 'A backup is running. Please wait...~~',
'bkp-restore-running' => 'A restore is running. Please wait...~~', 'bkp-restore-running' => 'A restore is running. Please wait...~~',
'Menu:BackupStatus' => 'Backups~~', 'Menu:BackupStatus' => 'Scheduled Backups~~',
'bkp-status-title' => 'Backups~~', 'bkp-status-title' => 'Scheduled Backups~~',
'bkp-status-checks' => 'Settings and checks~~', 'bkp-status-checks' => 'Settings and checks~~',
'bkp-mysqldump-ok' => 'mysqldump is present: %1$s~~', 'bkp-mysqldump-ok' => 'mysqldump is present: %1$s~~',
'bkp-mysqldump-notfound' => 'mysqldump could not be found: %1$s - Please make sure it is installed and in the path, or edit the configuration file to tune mysql_bindir.~~', 'bkp-mysqldump-notfound' => 'mysqldump could not be found: %1$s - Please make sure it is installed and in the path, or edit the configuration file to tune mysql_bindir.~~',
@@ -46,7 +46,7 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
'bkp-status-backups-auto' => 'Scheduled backups~~', 'bkp-status-backups-auto' => 'Scheduled backups~~',
'bkp-status-backups-manual' => 'Manual backups~~', 'bkp-status-backups-manual' => 'Manual backups~~',
'bkp-status-backups-none' => 'No backup yet~~', 'bkp-status-backups-none' => 'No backup yet~~',
'bkp-next-backup' => 'The next backup will occur on <b>%1$s</b> (%2$s) at %3$s.~~', 'bkp-next-backup' => 'The next backup will occur on <b>%1$s</b> (%2$s) at %3$s~~',
'bkp-next-backup-unknown' => 'The next backup is <b>not scheduled</b> yet.~~', 'bkp-next-backup-unknown' => 'The next backup is <b>not scheduled</b> yet.~~',
'bkp-button-backup-now' => 'Backup now!~~', 'bkp-button-backup-now' => 'Backup now!~~',
'bkp-button-restore-now' => 'Restore!~~', 'bkp-button-restore-now' => 'Restore!~~',

View File

@@ -3,7 +3,7 @@
SetupWebPage::AddModule( SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file __FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-backup/3.1.2', 'itop-backup/3.1.0',
array( array(
// Identification // Identification
// //

View File

@@ -79,7 +79,7 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
Dict::Add('HU HU', 'Hungarian', 'Magyar', array( Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'Class:Document/Attribute:contracts_list' => 'Szerződések', 'Class:Document/Attribute:contracts_list' => 'Szerződések',
'Class:Document/Attribute:contracts_list+' => 'Ehhez a dokumentumhoz kapcsolódó szerződések', 'Class:Document/Attribute:contracts_list+' => 'All the contracts linked to this document~~',
'Class:Document/Attribute:services_list' => 'Szolgáltatások', 'Class:Document/Attribute:services_list' => 'Szolgáltatások',
'Class:Document/Attribute:services_list+' => 'Ehhez a dokumentumhoz kapcsolódó szolgáltatások', 'Class:Document/Attribute:services_list+' => 'All the services linked to this document~~',
)); ));

View File

@@ -5,7 +5,7 @@
SetupWebPage::AddModule( SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file __FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-bridge-cmdb-services/3.1.2', 'itop-bridge-cmdb-services/3.1.0',
array( array(
// Identification // Identification
// //

View File

@@ -36,9 +36,9 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'Class:lnkFunctionalCIToTicket/Name' => '%1$s / %2$s~~', 'Class:lnkFunctionalCIToTicket/Name' => '%1$s / %2$s~~',
'Class:lnkFunctionalCIToTicket/Attribute:ticket_id' => 'Hibajegy', 'Class:lnkFunctionalCIToTicket/Attribute:ticket_id' => 'Hibajegy',
'Class:lnkFunctionalCIToTicket/Attribute:ticket_id+' => '~~', 'Class:lnkFunctionalCIToTicket/Attribute:ticket_id+' => '~~',
'Class:lnkFunctionalCIToTicket/Attribute:ticket_ref' => 'Referenciaszám', 'Class:lnkFunctionalCIToTicket/Attribute:ticket_ref' => 'Ref',
'Class:lnkFunctionalCIToTicket/Attribute:ticket_ref+' => '~~', 'Class:lnkFunctionalCIToTicket/Attribute:ticket_ref+' => '~~',
'Class:lnkFunctionalCIToTicket/Attribute:ticket_title' => 'Hibajegy tárgya', 'Class:lnkFunctionalCIToTicket/Attribute:ticket_title' => 'Hibajegy cím',
'Class:lnkFunctionalCIToTicket/Attribute:ticket_title+' => '~~', 'Class:lnkFunctionalCIToTicket/Attribute:ticket_title+' => '~~',
'Class:lnkFunctionalCIToTicket/Attribute:functionalci_id' => 'CI', 'Class:lnkFunctionalCIToTicket/Attribute:functionalci_id' => 'CI',
'Class:lnkFunctionalCIToTicket/Attribute:functionalci_id+' => '~~', 'Class:lnkFunctionalCIToTicket/Attribute:functionalci_id+' => '~~',
@@ -46,7 +46,7 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'Class:lnkFunctionalCIToTicket/Attribute:functionalci_name+' => '~~', 'Class:lnkFunctionalCIToTicket/Attribute:functionalci_name+' => '~~',
'Class:lnkFunctionalCIToTicket/Attribute:impact' => 'Hatása (szöveg)', 'Class:lnkFunctionalCIToTicket/Attribute:impact' => 'Hatása (szöveg)',
'Class:lnkFunctionalCIToTicket/Attribute:impact+' => '~~', 'Class:lnkFunctionalCIToTicket/Attribute:impact+' => '~~',
'Class:lnkFunctionalCIToTicket/Attribute:impact_code' => 'Hatás kód', 'Class:lnkFunctionalCIToTicket/Attribute:impact_code' => 'Hatása',
'Class:lnkFunctionalCIToTicket/Attribute:impact_code/Value:manual' => 'Kézzel hozzáadva', 'Class:lnkFunctionalCIToTicket/Attribute:impact_code/Value:manual' => 'Kézzel hozzáadva',
'Class:lnkFunctionalCIToTicket/Attribute:impact_code/Value:computed' => 'Számított', 'Class:lnkFunctionalCIToTicket/Attribute:impact_code/Value:computed' => 'Számított',
'Class:lnkFunctionalCIToTicket/Attribute:impact_code/Value:not_impacted' => 'Nincs hatása', 'Class:lnkFunctionalCIToTicket/Attribute:impact_code/Value:not_impacted' => 'Nincs hatása',

View File

@@ -5,7 +5,7 @@
SetupWebPage::AddModule( SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file __FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-bridge-cmdb-ticket/3.1.2', 'itop-bridge-cmdb-ticket/3.1.0',
array( array(
// Identification // Identification
// //

View File

@@ -5,7 +5,7 @@
SetupWebPage::AddModule( SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file __FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-bridge-datacenter-mgmt-services/3.1.2', 'itop-bridge-datacenter-mgmt-services/3.1.0',
array( array(
// Identification // Identification
// //

View File

@@ -5,7 +5,7 @@
SetupWebPage::AddModule( SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file __FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-bridge-endusers-devices-services/3.1.2', 'itop-bridge-endusers-devices-services/3.1.0',
array( array(
// Identification // Identification
// //

View File

@@ -5,7 +5,7 @@
SetupWebPage::AddModule( SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file __FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-bridge-storage-mgmt-services/3.1.2', 'itop-bridge-storage-mgmt-services/3.1.0',
array( array(
// Identification // Identification
// //

View File

@@ -5,7 +5,7 @@
SetupWebPage::AddModule( SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file __FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-bridge-virtualization-mgmt-services/3.1.2', 'itop-bridge-virtualization-mgmt-services/3.1.0',
array( array(
// Identification // Identification
// //

View File

@@ -3,7 +3,7 @@
SetupWebPage::AddModule( SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file __FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-bridge-virtualization-storage/3.1.2', 'itop-bridge-virtualization-storage/3.1.0',
array( array(
// Identification // Identification
// //

View File

@@ -22,21 +22,21 @@
Dict::Add('HU HU', 'Hungarian', 'Magyar', array( Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'Menu:ChangeManagement' => 'Változáskezelés', 'Menu:ChangeManagement' => 'Változáskezelés',
'Menu:Change:Overview' => 'Áttekintő', 'Menu:Change:Overview' => 'Áttekintő',
'Menu:Change:Overview+' => 'Áttekintő oldal', 'Menu:Change:Overview+' => '~~',
'Menu:NewChange' => 'Új változás', 'Menu:NewChange' => 'Új változás',
'Menu:NewChange+' => 'Új változásjegy létrehozása', 'Menu:NewChange+' => 'Új változásjegy létrehozása',
'Menu:SearchChanges' => 'Változás keresés', 'Menu:SearchChanges' => 'Változás keresés',
'Menu:SearchChanges+' => 'Változásjegy keresés', 'Menu:SearchChanges+' => 'Változásjegy keresés',
'Menu:Change:Shortcuts' => 'Gyorsgombok', 'Menu:Change:Shortcuts' => 'Gyorsgombok',
'Menu:Change:Shortcuts+' => 'Gyorselérés gombok', 'Menu:Change:Shortcuts+' => '~~',
'Menu:WaitingAcceptance' => 'Elfogadásra váró változások', 'Menu:WaitingAcceptance' => 'Elfogadásra váró változások',
'Menu:WaitingAcceptance+' => 'Elfogadásra váró változások', 'Menu:WaitingAcceptance+' => '~~',
'Menu:WaitingApproval' => 'Jóváhagyásra váró változások', 'Menu:WaitingApproval' => 'Jóváhagyásra váró változások',
'Menu:WaitingApproval+' => 'Jóváhagyásra váró változások', 'Menu:WaitingApproval+' => '~~',
'Menu:Changes' => 'Nyitott változási kérelmek', 'Menu:Changes' => 'Nyitott változási kérelmek',
'Menu:Changes+' => 'Nyitott változási kérelmek összesítése', 'Menu:Changes+' => 'Minden nyitott változási kérelem',
'Menu:MyChanges' => 'Hozzám rendelt változások', 'Menu:MyChanges' => 'Hozzám rendelt változások',
'Menu:MyChanges+' => 'Ügyintézőként hozzám rendelt változások', 'Menu:MyChanges+' => 'Changes assigned to me (as Agent)~~',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => 'Változások kategóriánként az elmúlt 7 napban', 'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => 'Változások kategóriánként az elmúlt 7 napban',
'UI-ChangeManagementOverview-Last-7-days' => 'A változások száma az elmúlt 7 napban', 'UI-ChangeManagementOverview-Last-7-days' => 'A változások száma az elmúlt 7 napban',
'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => 'Változások tartományonként az elmúlt 7 napban', 'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => 'Változások tartományonként az elmúlt 7 napban',
@@ -119,22 +119,22 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'Class:Change/Attribute:outage/Value:yes+' => '', 'Class:Change/Attribute:outage/Value:yes+' => '',
'Class:Change/Attribute:fallback' => 'Visszavonás', 'Class:Change/Attribute:fallback' => 'Visszavonás',
'Class:Change/Attribute:fallback+' => '', 'Class:Change/Attribute:fallback+' => '',
'Class:Change/Attribute:parent_id' => 'Fölérendelt változás', 'Class:Change/Attribute:parent_id' => 'Szülő változás',
'Class:Change/Attribute:parent_id+' => '', 'Class:Change/Attribute:parent_id+' => '~~',
'Class:Change/Attribute:parent_name' => 'Referenciaszám', 'Class:Change/Attribute:parent_name' => 'Szülő változás Ref',
'Class:Change/Attribute:parent_name+' => '', 'Class:Change/Attribute:parent_name+' => '~~',
'Class:Change/Attribute:related_request_list' => 'Kapcsolódó kérelmek', 'Class:Change/Attribute:related_request_list' => 'Kapcsolódó kérelmek',
'Class:Change/Attribute:related_request_list+' => 'Ehhez a változáshoz kapcsolódó felhasználói kérelmek', 'Class:Change/Attribute:related_request_list+' => 'All the user requests linked to this change~~',
'Class:Change/Attribute:related_problems_list' => 'Kapcsolódó problémák', 'Class:Change/Attribute:related_problems_list' => 'Kapcsolódó problémák',
'Class:Change/Attribute:related_problems_list+' => 'Ehhez a változáshoz kapcsolódó problémák', 'Class:Change/Attribute:related_problems_list+' => 'All the problems linked to this change~~',
'Class:Change/Attribute:related_incident_list' => 'Kapcsolódó incidensek', 'Class:Change/Attribute:related_incident_list' => 'Kapcsolódó incidensek',
'Class:Change/Attribute:related_incident_list+' => 'Ehhez a változáshoz kapcsolódó incidensek', 'Class:Change/Attribute:related_incident_list+' => 'All the incidents linked to this change~~',
'Class:Change/Attribute:child_changes_list' => 'Kapcsolódó változások', 'Class:Change/Attribute:child_changes_list' => 'Gyermek változások',
'Class:Change/Attribute:child_changes_list+' => 'Ehhez a változáshoz kapcsolódó változások', 'Class:Change/Attribute:child_changes_list+' => 'All the sub changes linked to this change~~',
'Class:Change/Attribute:parent_id_friendlyname' => 'Fölérendelt változás rövid név', 'Class:Change/Attribute:parent_id_friendlyname' => 'Szülő változás rövid név',
'Class:Change/Attribute:parent_id_friendlyname+' => '', 'Class:Change/Attribute:parent_id_friendlyname+' => '~~',
'Class:Change/Attribute:parent_id_finalclass_recall' => 'Változás típus', 'Class:Change/Attribute:parent_id_finalclass_recall' => 'Változás típus',
'Class:Change/Attribute:parent_id_finalclass_recall+' => '', 'Class:Change/Attribute:parent_id_finalclass_recall+' => '~~',
'Class:Change/Stimulus:ev_validate' => 'Ellenőrzés', 'Class:Change/Stimulus:ev_validate' => 'Ellenőrzés',
'Class:Change/Stimulus:ev_validate+' => '', 'Class:Change/Stimulus:ev_validate+' => '',
'Class:Change/Stimulus:ev_reject' => 'Elutasítás', 'Class:Change/Stimulus:ev_reject' => 'Elutasítás',

View File

@@ -3,7 +3,7 @@
SetupWebPage::AddModule( SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file __FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-change-mgmt-itil/3.1.2', 'itop-change-mgmt-itil/3.1.0',
array( array(
// Identification // Identification
// //

View File

@@ -21,23 +21,23 @@
* along with iTop. If not, see <http://www.gnu.org/licenses/> * along with iTop. If not, see <http://www.gnu.org/licenses/>
*/ */
Dict::Add('HU HU', 'Hungarian', 'Magyar', array( Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'Menu:ChangeManagement' => 'Változáskezelés', 'Menu:ChangeManagement' => 'Változáskezelés',
'Menu:Change:Overview' => 'Áttekintő', 'Menu:Change:Overview' => 'Áttekintő',
'Menu:Change:Overview+' => 'Áttekintő oldal', 'Menu:Change:Overview+' => '~~',
'Menu:NewChange' => 'Új változás', 'Menu:NewChange' => 'Új változás',
'Menu:NewChange+' => 'Új változásjegy létrehozása', 'Menu:NewChange+' => 'Új változásjegy létrehozása',
'Menu:SearchChanges' => 'Változás keresés', 'Menu:SearchChanges' => 'Változás keresés',
'Menu:SearchChanges+' => 'Változásjegy keresés', 'Menu:SearchChanges+' => 'Változásjegy keresés',
'Menu:Change:Shortcuts' => 'Gyorsgombok', 'Menu:Change:Shortcuts' => 'Gyorsgombok',
'Menu:Change:Shortcuts+' => 'Gyorselérés gombok', 'Menu:Change:Shortcuts+' => '~~',
'Menu:WaitingAcceptance' => 'Elfogadásra váró változások', 'Menu:WaitingAcceptance' => 'Elfogadásra váró változások',
'Menu:WaitingAcceptance+' => 'Elfogadásra váró változások', 'Menu:WaitingAcceptance+' => '~~',
'Menu:WaitingApproval' => 'Jóváhagyásra váró változások', 'Menu:WaitingApproval' => 'Jóváhagyásra váró változások',
'Menu:WaitingApproval+' => 'Jóváhagyásra váró változások', 'Menu:WaitingApproval+' => '~~',
'Menu:Changes' => 'Nyitott változási kérelmek', 'Menu:Changes' => 'Nyitott változási kérelmek',
'Menu:Changes+' => 'Nyitott változási kérelmek összesítése', 'Menu:Changes+' => 'Minden nyitott változási kérelem',
'Menu:MyChanges' => 'Hozzám rendelt változások', 'Menu:MyChanges' => 'Hozzám rendelt változások',
'Menu:MyChanges+' => 'Ügyintézőként hozzám rendelt változások', 'Menu:MyChanges+' => 'Changes assigned to me (as Agent)~~',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => 'Változások kategóriánként az elmúlt 7 napban', 'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => 'Változások kategóriánként az elmúlt 7 napban',
'UI-ChangeManagementOverview-Last-7-days' => 'A változások száma az elmúlt 7 napban', 'UI-ChangeManagementOverview-Last-7-days' => 'A változások száma az elmúlt 7 napban',
'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => 'Változások tartományonként az elmúlt 7 napban', 'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => 'Változások tartományonként az elmúlt 7 napban',
@@ -81,26 +81,26 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'Class:Change/Attribute:category' => 'Kategória', 'Class:Change/Attribute:category' => 'Kategória',
'Class:Change/Attribute:category+' => '~~', 'Class:Change/Attribute:category+' => '~~',
'Class:Change/Attribute:category/Value:application' => 'Alkalmazás', 'Class:Change/Attribute:category/Value:application' => 'Alkalmazás',
'Class:Change/Attribute:category/Value:application+' => '', 'Class:Change/Attribute:category/Value:application+' => 'application~~',
'Class:Change/Attribute:category/Value:hardware' => 'Hardver', 'Class:Change/Attribute:category/Value:hardware' => 'Hardver',
'Class:Change/Attribute:category/Value:hardware+' => '', 'Class:Change/Attribute:category/Value:hardware+' => 'hardware~~',
'Class:Change/Attribute:category/Value:network' => 'Hálózat', 'Class:Change/Attribute:category/Value:network' => 'Hálózat',
'Class:Change/Attribute:category/Value:network+' => '', 'Class:Change/Attribute:category/Value:network+' => 'network~~',
'Class:Change/Attribute:category/Value:other' => 'Egyéb', 'Class:Change/Attribute:category/Value:other' => 'Egyéb',
'Class:Change/Attribute:category/Value:other+' => '', 'Class:Change/Attribute:category/Value:other+' => 'other~~',
'Class:Change/Attribute:category/Value:software' => 'Szoftver', 'Class:Change/Attribute:category/Value:software' => 'Szoftver',
'Class:Change/Attribute:category/Value:software+' => '', 'Class:Change/Attribute:category/Value:software+' => 'software~~',
'Class:Change/Attribute:category/Value:system' => 'Rendszer', 'Class:Change/Attribute:category/Value:system' => 'Rendszer',
'Class:Change/Attribute:category/Value:system+' => '', 'Class:Change/Attribute:category/Value:system+' => 'system~~',
'Class:Change/Attribute:reject_reason' => 'Elutasítás oka', 'Class:Change/Attribute:reject_reason' => 'Elutasítás oka',
'Class:Change/Attribute:reject_reason+' => '~~', 'Class:Change/Attribute:reject_reason+' => '~~',
'Class:Change/Attribute:changemanager_id' => 'Változás menedzser', 'Class:Change/Attribute:changemanager_id' => 'Változás menedzser',
'Class:Change/Attribute:changemanager_id+' => '~~', 'Class:Change/Attribute:changemanager_id+' => '~~',
'Class:Change/Attribute:changemanager_email' => 'Változás menedzser email címe', 'Class:Change/Attribute:changemanager_email' => 'Változás menedzser email címe',
'Class:Change/Attribute:changemanager_email+' => '~~', 'Class:Change/Attribute:changemanager_email+' => '~~',
'Class:Change/Attribute:parent_id' => 'Fölérendelt változás', 'Class:Change/Attribute:parent_id' => 'Szülő változás',
'Class:Change/Attribute:parent_id+' => '~~', 'Class:Change/Attribute:parent_id+' => '~~',
'Class:Change/Attribute:parent_name' => 'Referenciaszám', 'Class:Change/Attribute:parent_name' => 'Szülő változás ref.',
'Class:Change/Attribute:parent_name+' => '~~', 'Class:Change/Attribute:parent_name+' => '~~',
'Class:Change/Attribute:creation_date' => 'Létrehozás dátuma', 'Class:Change/Attribute:creation_date' => 'Létrehozás dátuma',
'Class:Change/Attribute:creation_date+' => '~~', 'Class:Change/Attribute:creation_date+' => '~~',
@@ -109,14 +109,14 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'Class:Change/Attribute:fallback_plan' => 'Tartalék terv', 'Class:Change/Attribute:fallback_plan' => 'Tartalék terv',
'Class:Change/Attribute:fallback_plan+' => '~~', 'Class:Change/Attribute:fallback_plan+' => '~~',
'Class:Change/Attribute:related_request_list' => 'Kapcsolódó kérelmek', 'Class:Change/Attribute:related_request_list' => 'Kapcsolódó kérelmek',
'Class:Change/Attribute:related_request_list+' => 'Ehhez a változáshoz kapcsolódó felhasználói kérelmek', 'Class:Change/Attribute:related_request_list+' => 'All the user requests linked to this change~~',
'Class:Change/Attribute:related_incident_list' => 'Kapcsolódó incidensek', 'Class:Change/Attribute:related_incident_list' => 'Kapcsolódó incidensek',
'Class:Change/Attribute:related_incident_list+' => 'Ehhez a változáshoz kapcsolódó incidensek', 'Class:Change/Attribute:related_incident_list+' => 'All the incidents linked to this change~~',
'Class:Change/Attribute:related_problems_list' => 'Kapcsolódó problémák', 'Class:Change/Attribute:related_problems_list' => 'Kapcsolódó problémák',
'Class:Change/Attribute:related_problems_list+' => 'Ehhez a változáshoz kapcsolódó problémák', 'Class:Change/Attribute:related_problems_list+' => 'All the problems linked to this change~~',
'Class:Change/Attribute:child_changes_list' => 'Kapcsolódó változások', 'Class:Change/Attribute:child_changes_list' => 'Gyermek változások',
'Class:Change/Attribute:child_changes_list+' => 'Ehhez a változáshoz kapcsolódó változások', 'Class:Change/Attribute:child_changes_list+' => 'All the sub changes linked to this change~~',
'Class:Change/Attribute:parent_id_friendlyname' => 'Fölérendelt változás rövid név', 'Class:Change/Attribute:parent_id_friendlyname' => 'Szülő változás rövid név',
'Class:Change/Attribute:parent_id_friendlyname+' => '~~', 'Class:Change/Attribute:parent_id_friendlyname+' => '~~',
'Class:Change/Stimulus:ev_assign' => 'Hozzárendelés', 'Class:Change/Stimulus:ev_assign' => 'Hozzárendelés',
'Class:Change/Stimulus:ev_assign+' => '~~', 'Class:Change/Stimulus:ev_assign+' => '~~',

View File

@@ -3,7 +3,7 @@
SetupWebPage::AddModule( SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file __FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-change-mgmt/3.1.2', 'itop-change-mgmt/3.1.0',
array( array(
// Identification // Identification
// //

View File

@@ -77,7 +77,7 @@
<default_value/> <default_value/>
<is_null_allowed>true</is_null_allowed> <is_null_allowed>true</is_null_allowed>
</field> </field>
<field id="contacts_list" xsi:type="AttributeLinkedSetIndirect"> <field id="contacts_list" xsi:type="AttributeLinkedSetIndirect" _delta="define">
<linked_class>lnkContactToFunctionalCI</linked_class> <linked_class>lnkContactToFunctionalCI</linked_class>
<ext_key_to_me>functionalci_id</ext_key_to_me> <ext_key_to_me>functionalci_id</ext_key_to_me>
<count_min>0</count_min> <count_min>0</count_min>

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