mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-17 01:14:14 +01:00
Compare commits
20 Commits
feature/58
...
support/77
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4558f40631 | ||
|
|
afd96a0f49 | ||
|
|
a77765ec7b | ||
|
|
64b4b03ea9 | ||
|
|
a797878b17 | ||
|
|
1fa0f7bdd9 | ||
|
|
f718b4173d | ||
|
|
e057c0f081 | ||
|
|
5a49fc7654 | ||
|
|
6fca659c9d | ||
|
|
eacd08f31e | ||
|
|
5f7d8f6cc0 | ||
|
|
cbb4281a37 | ||
|
|
d7a8d335d5 | ||
|
|
bd1d447677 | ||
|
|
bb405d5173 | ||
|
|
4723fc885c | ||
|
|
06dcae1dd1 | ||
|
|
e03033ce52 | ||
|
|
19eae916f0 |
@@ -5923,14 +5923,14 @@ JS
|
||||
*
|
||||
* @since 3.1.0
|
||||
*/
|
||||
final protected function FireEventCheckToWrite(): void
|
||||
final protected function FireEventCheckToWrite(?string $sStimulusBeingApplied): void
|
||||
{
|
||||
$this->FireEvent(EVENT_DB_CHECK_TO_WRITE, ['is_new' => $this->IsNew()]);
|
||||
$this->FireEvent(EVENT_DB_CHECK_TO_WRITE, ['is_new' => $this->IsNew(), 'stimulus_applied' => $sStimulusBeingApplied]);
|
||||
}
|
||||
|
||||
final protected function FireEventBeforeWrite()
|
||||
final protected function FireEventBeforeWrite(?string $sStimulusBeingApplied)
|
||||
{
|
||||
$this->FireEvent(EVENT_DB_BEFORE_WRITE, ['is_new' => $this->IsNew()]);
|
||||
$this->FireEvent(EVENT_DB_BEFORE_WRITE, ['is_new' => $this->IsNew(), 'stimulus_applied' => $sStimulusBeingApplied]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5942,11 +5942,11 @@ JS
|
||||
* @throws \CoreException
|
||||
* @since 3.1.0
|
||||
*/
|
||||
final protected function FireEventAfterWrite(array $aChanges, bool $bIsNew): void
|
||||
final protected function FireEventAfterWrite(array $aChanges, bool $bIsNew, ?string $sStimulusBeingApplied): void
|
||||
{
|
||||
$this->NotifyAttachedObjectsOnLinkClassModification();
|
||||
$this->RemoveObjectAwaitingEventDbLinksChanged(get_class($this), $this->GetKey());
|
||||
$this->FireEvent(EVENT_DB_AFTER_WRITE, ['is_new' => $bIsNew, 'changes' => $aChanges]);
|
||||
$this->FireEvent(EVENT_DB_AFTER_WRITE, ['is_new' => $bIsNew, 'changes' => $aChanges, 'stimulus_applied' => $sStimulusBeingApplied]);
|
||||
}
|
||||
|
||||
//////////////
|
||||
@@ -6179,9 +6179,9 @@ JS
|
||||
* @inheritDoc
|
||||
* @throws \CoreException
|
||||
*/
|
||||
final protected function FireEventComputeValues(): void
|
||||
final protected function FireEventComputeValues(?string $sStimulusBeingApplied): void
|
||||
{
|
||||
$this->FireEvent(EVENT_DB_COMPUTE_VALUES);
|
||||
$this->FireEvent(EVENT_DB_COMPUTE_VALUES, ['is_new' => $this->IsNew(), 'stimulus_applied' => $sStimulusBeingApplied]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1266,13 +1266,12 @@ EOF
|
||||
$sOkButtonLabel = Dict::S('UI:Button:Save');
|
||||
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
||||
|
||||
$sId = utils::HtmlEntities($this->sId);
|
||||
$sLayoutClass = utils::HtmlEntities($this->sLayoutClass);
|
||||
$sId = json_encode($this->sId);
|
||||
$sLayoutClass = json_encode($this->sLayoutClass);
|
||||
$sAutoReload = $this->bAutoReload ? 'true' : 'false';
|
||||
$sAutoReloadSec = (string) $this->iAutoReloadSec;
|
||||
$sTitle = utils::HtmlEntities($this->sTitle);
|
||||
$sFile = utils::HtmlEntities($this->GetDefinitionFile());
|
||||
$sFileForJS = json_encode($this->GetDefinitionFile());
|
||||
$sTitle = json_encode($this->sTitle);
|
||||
$sFile = json_encode($this->GetDefinitionFile());
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
|
||||
$sReloadURL = $this->GetReloadURL();
|
||||
|
||||
@@ -1328,15 +1327,15 @@ $('#dashboard_editor').dialog({
|
||||
});
|
||||
|
||||
$('#dashboard_editor .ui-layout-center').runtimedashboard({
|
||||
dashboard_id: '$sId',
|
||||
layout_class: '$sLayoutClass',
|
||||
title: '$sTitle',
|
||||
dashboard_id: $sId,
|
||||
layout_class: $sLayoutClass,
|
||||
title: $sTitle,
|
||||
auto_reload: $sAutoReload,
|
||||
auto_reload_sec: $sAutoReloadSec,
|
||||
submit_to: '$sUrl',
|
||||
submit_parameters: {operation: 'save_dashboard', file: {$sFileForJS}, extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
|
||||
submit_parameters: {operation: 'save_dashboard', file: $sFile, extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
|
||||
render_to: '$sUrl',
|
||||
render_parameters: {operation: 'render_dashboard', file: {$sFileForJS}, extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
|
||||
render_parameters: {operation: 'render_dashboard', file: $sFile, extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
|
||||
new_dashlet_parameters: {operation: 'new_dashlet'}
|
||||
});
|
||||
|
||||
|
||||
@@ -238,6 +238,10 @@ The object can be modified.]]></description>
|
||||
<description>Creation flag</description>
|
||||
<type>boolean</type>
|
||||
</event_datum>
|
||||
<event_datum id="stimulus_applied">
|
||||
<description>Life cycle stimulus applied (null if not within a transition)</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
@@ -263,6 +267,10 @@ Call $this->AddCheckWarning($sWarningMessage) to display a warning.
|
||||
<description>Creation flag</description>
|
||||
<type>boolean</type>
|
||||
</event_datum>
|
||||
<event_datum id="stimulus_applied">
|
||||
<description>Life cycle stimulus applied (null if not within a transition)</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
@@ -290,6 +298,10 @@ The modifications can be propagated to other objects.]]></description>
|
||||
<description><![CDATA[For updates, the list of changes done during this operation]]></description>
|
||||
<type>array</type>
|
||||
</event_datum>
|
||||
<event_datum id="stimulus_applied">
|
||||
<description>Life cycle stimulus applied (null if not within a transition)</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
@@ -420,6 +432,14 @@ The only action allowed is to deny transitions with $this->DenyTransition($sTran
|
||||
<description>The object inserted</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="is_new">
|
||||
<description>Creation flag</description>
|
||||
<type>boolean</type>
|
||||
</event_datum>
|
||||
<event_datum id="stimulus_applied">
|
||||
<description>Life cycle stimulus applied (null if not within a transition)</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
|
||||
@@ -181,7 +181,7 @@ abstract class Action extends cmdbAbstractObject
|
||||
{
|
||||
parent::DisplayBareRelations($oPage, false);
|
||||
|
||||
if ($oPage instanceof iTopWebPage) {
|
||||
if ($oPage instanceof iTopWebPage && !$this->IsNew()) {
|
||||
$this->GenerateLastExecutionsTab($oPage, $bEditMode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,6 +212,8 @@ abstract class DBObject implements iDisplay
|
||||
private $aEventListeners = [];
|
||||
private array $aAllowedTransitions = [];
|
||||
|
||||
private ?string $sStimulusBeingApplied = null;
|
||||
|
||||
/**
|
||||
* DBObject constructor.
|
||||
*
|
||||
@@ -1206,7 +1208,7 @@ abstract class DBObject implements iDisplay
|
||||
if ($aCallInfo["function"] != "ComputeValues") continue;
|
||||
return; //skip!
|
||||
}
|
||||
$this->FireEventComputeValues();
|
||||
$this->FireEventComputeValues($this->sStimulusBeingApplied);
|
||||
$oKPI = new ExecutionKPI();
|
||||
$this->ComputeValues();
|
||||
$oKPI->ComputeStatsForExtension($this, 'ComputeValues');
|
||||
@@ -2130,7 +2132,7 @@ abstract class DBObject implements iDisplay
|
||||
|
||||
return "Bad type";
|
||||
}
|
||||
elseif (($oAtt instanceof AttributeClassAttCodeSet) || ($oAtt instanceof AttributeEnumSet))
|
||||
elseif ($oAtt instanceof AttributeSet)
|
||||
{
|
||||
if (is_string($toCheck))
|
||||
{
|
||||
@@ -2669,7 +2671,7 @@ abstract class DBObject implements iDisplay
|
||||
|
||||
// Ultimate check - ensure DB integrity
|
||||
$this->SetReadOnly('No modification allowed during CheckToCreate');
|
||||
$this->FireEventCheckToWrite();
|
||||
$this->FireEventCheckToWrite($this->sStimulusBeingApplied);
|
||||
$this->SetReadWrite();
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
@@ -3398,7 +3400,7 @@ abstract class DBObject implements iDisplay
|
||||
$this->OnInsert();
|
||||
$oKPI->ComputeStatsForExtension($this, 'OnInsert');
|
||||
|
||||
$this->FireEventBeforeWrite();
|
||||
$this->FireEventBeforeWrite(null);
|
||||
|
||||
// If not automatically computed, then check that the key is given by the caller
|
||||
if (!MetaModel::IsAutoIncrementKey($sRootClass)) {
|
||||
@@ -3533,7 +3535,7 @@ abstract class DBObject implements iDisplay
|
||||
*/
|
||||
protected function PostInsertActions(): void
|
||||
{
|
||||
$this->FireEventAfterWrite([], true);
|
||||
$this->FireEventAfterWrite([], true, null);
|
||||
$oKPI = new ExecutionKPI();
|
||||
$this->AfterInsert();
|
||||
$oKPI->ComputeStatsForExtension($this, 'AfterInsert');
|
||||
@@ -3641,7 +3643,7 @@ abstract class DBObject implements iDisplay
|
||||
$this->OnUpdate();
|
||||
$oKPI->ComputeStatsForExtension($this, 'OnUpdate');
|
||||
|
||||
$this->FireEventBeforeWrite();
|
||||
$this->FireEventBeforeWrite($this->sStimulusBeingApplied);
|
||||
|
||||
// Freeze the changes at this point
|
||||
$this->InitPreviousValuesForUpdatedAttributes();
|
||||
@@ -3852,7 +3854,7 @@ abstract class DBObject implements iDisplay
|
||||
*/
|
||||
protected function PostUpdateActions(array $aChanges): void
|
||||
{
|
||||
$this->FireEventAfterWrite($aChanges, false);
|
||||
$this->FireEventAfterWrite($aChanges, false, $this->sStimulusBeingApplied);
|
||||
$oKPI = new ExecutionKPI();
|
||||
$this->AfterUpdate();
|
||||
$oKPI->ComputeStatsForExtension($this, 'AfterUpdate');
|
||||
@@ -3864,39 +3866,38 @@ abstract class DBObject implements iDisplay
|
||||
$this->ActivateOnObjectUpdateTriggersForTargetObjects();
|
||||
|
||||
$sClass = get_class($this);
|
||||
if (MetaModel::HasLifecycle($sClass))
|
||||
if (utils::IsNotNullOrEmptyString($this->sStimulusBeingApplied))
|
||||
{
|
||||
$this->sStimulusBeingApplied = null;
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
|
||||
if (isset($this->m_aPreviousValuesForUpdatedAttributes[$sStateAttCode])) {
|
||||
$sPreviousState = $this->m_aPreviousValuesForUpdatedAttributes[$sStateAttCode];
|
||||
// Change state triggers...
|
||||
$aParams = array(
|
||||
'class_list' => MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL),
|
||||
'previous_state' => $sPreviousState,
|
||||
'new_state' => $this->Get($sStateAttCode),
|
||||
);
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL('SELECT TriggerOnStateLeave AS t WHERE t.target_class IN (:class_list) AND t.state=:previous_state'), array(), $aParams);
|
||||
while ($oTrigger = $oSet->Fetch()) {
|
||||
/** @var \TriggerOnStateLeave $oTrigger */
|
||||
try {
|
||||
$oTrigger->DoActivate($this->ToArgs('this'));
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$oTrigger->LogException($e, $this);
|
||||
utils::EnrichRaisedException($oTrigger, $e);
|
||||
}
|
||||
$sPreviousState = $this->m_aPreviousValuesForUpdatedAttributes[$sStateAttCode];
|
||||
// Change state triggers...
|
||||
$aParams = array(
|
||||
'class_list' => MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL),
|
||||
'previous_state' => $sPreviousState,
|
||||
'new_state' => $this->Get($sStateAttCode),
|
||||
);
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL('SELECT TriggerOnStateLeave AS t WHERE t.target_class IN (:class_list) AND t.state=:previous_state'), array(), $aParams);
|
||||
while ($oTrigger = $oSet->Fetch()) {
|
||||
/** @var \TriggerOnStateLeave $oTrigger */
|
||||
try {
|
||||
$oTrigger->DoActivate($this->ToArgs('this'));
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$oTrigger->LogException($e, $this);
|
||||
utils::EnrichRaisedException($oTrigger, $e);
|
||||
}
|
||||
}
|
||||
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL('SELECT TriggerOnStateEnter AS t WHERE t.target_class IN (:class_list) AND t.state=:new_state'), array(), $aParams);
|
||||
while ($oTrigger = $oSet->Fetch()) {
|
||||
/** @var \TriggerOnStateEnter $oTrigger */
|
||||
try {
|
||||
$oTrigger->DoActivate($this->ToArgs('this'));
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$oTrigger->LogException($e, $this);
|
||||
utils::EnrichRaisedException($oTrigger, $e);
|
||||
}
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL('SELECT TriggerOnStateEnter AS t WHERE t.target_class IN (:class_list) AND t.state=:new_state'), array(), $aParams);
|
||||
while ($oTrigger = $oSet->Fetch()) {
|
||||
/** @var \TriggerOnStateEnter $oTrigger */
|
||||
try {
|
||||
$oTrigger->DoActivate($this->ToArgs('this'));
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$oTrigger->LogException($e, $this);
|
||||
utils::EnrichRaisedException($oTrigger, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4603,6 +4604,7 @@ abstract class DBObject implements iDisplay
|
||||
}
|
||||
if ($bSuccess)
|
||||
{
|
||||
$this->sStimulusBeingApplied = $sStimulusCode;
|
||||
// Stop watches
|
||||
foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
@@ -6617,7 +6619,7 @@ abstract class DBObject implements iDisplay
|
||||
* @return void
|
||||
* @since 3.1.0
|
||||
*/
|
||||
protected function FireEventCheckToWrite(): void
|
||||
protected function FireEventCheckToWrite(?string $sStimulusBeingApplied): void
|
||||
{
|
||||
}
|
||||
|
||||
@@ -6625,7 +6627,7 @@ abstract class DBObject implements iDisplay
|
||||
* @return void
|
||||
* @since 3.1.0
|
||||
*/
|
||||
protected function FireEventBeforeWrite()
|
||||
protected function FireEventBeforeWrite(?string $sStimulusBeingApplied)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -6635,7 +6637,7 @@ abstract class DBObject implements iDisplay
|
||||
* @return void
|
||||
* @since 3.1.0
|
||||
*/
|
||||
protected function FireEventAfterWrite(array $aChanges, bool $bIsNew): void
|
||||
protected function FireEventAfterWrite(array $aChanges, bool $bIsNew, ?string $sStimulusBeingApplied): void
|
||||
{
|
||||
}
|
||||
|
||||
@@ -6673,7 +6675,7 @@ abstract class DBObject implements iDisplay
|
||||
* @return void
|
||||
* @since 3.1.0
|
||||
*/
|
||||
protected function FireEventComputeValues(): void
|
||||
protected function FireEventComputeValues(?string $sStimulusBeingApplied): void
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,13 @@ class UnknownClassOqlException extends OqlNormalizeException
|
||||
{
|
||||
public function __construct($sInput, OqlName $oName, $aExpecting = null)
|
||||
{
|
||||
parent::__construct('Unknown class', $sInput, $oName, $aExpecting);
|
||||
$aAllowedClasses = [];
|
||||
foreach ($aExpecting as $sClass) {
|
||||
if (UserRights::IsActionAllowed($sClass, UR_ACTION_READ)) {
|
||||
$aAllowedClasses[] = $sClass;
|
||||
}
|
||||
}
|
||||
parent::__construct('Unknown class', $sInput, $oName, $aAllowedClasses);
|
||||
}
|
||||
|
||||
public function GetUserFriendlyDescription()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*!
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*!
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*!
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*!
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*!
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*!
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
2
css/backoffice/vendors/ckeditor/_all.scss
vendored
2
css/backoffice/vendors/ckeditor/_all.scss
vendored
@@ -1,4 +1,4 @@
|
||||
/*!
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*!
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*!
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*!
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*!
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -160,8 +160,7 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
private static function InitCASClient()
|
||||
{
|
||||
$bCASDebug = Config::Get('cas_debug');
|
||||
if ($bCASDebug)
|
||||
{
|
||||
if ($bCASDebug) {
|
||||
phpCAS::setLogger(new CASLogger(APPROOT.'log/cas.log'));
|
||||
}
|
||||
|
||||
@@ -171,18 +170,17 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
$iCASPort = Config::Get('cas_port');
|
||||
$sCASContext = Config::Get('cas_context');
|
||||
$sServiceBaseURL = Config::Get('service_base_url', self::GetServiceBaseURL());
|
||||
phpCAS::client($sCASVersion, $sCASHost, $iCASPort, $sCASContext, $sServiceBaseURL, false /* session already started */);
|
||||
if (!phpCAS::isInitialized()) {
|
||||
phpCAS::client($sCASVersion, $sCASHost, $iCASPort, $sCASContext, $sServiceBaseURL, false /* session already started */);
|
||||
}
|
||||
$sCASCACertPath = Config::Get('cas_server_ca_cert_path');
|
||||
if (empty($sCASCACertPath))
|
||||
{
|
||||
if (empty($sCASCACertPath)) {
|
||||
// If no certificate authority is provided, do not attempt to validate
|
||||
// the server's certificate
|
||||
// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
|
||||
// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
|
||||
phpCAS::setNoCasServerValidation();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
phpCAS::setCasServerCACert($sCASCACertPath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
Dict::Add('EN US', 'English', 'English', [
|
||||
'Menu:CreateMailbox' => 'Create a mailbox...',
|
||||
'Menu:OAuthClient' => 'OAuth client',
|
||||
'Menu:OAuthClient+' => '',
|
||||
'Menu:OAuthClient+' => 'Oauth for email access',
|
||||
'Menu:GenerateTokens' => 'Generate access token...',
|
||||
'Menu:RegenerateTokens' => 'Regenerate access token...',
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ Pour recalculer la valeur par défaut, il faut effacer le champ',
|
||||
'Menu:CreateMailbox' => 'Créer une boite mail...',
|
||||
'Menu:GenerateTokens' => 'Créer un jeton d\'accès...',
|
||||
'Menu:OAuthClient' => 'Client OAuth',
|
||||
'Menu:OAuthClient+' => '',
|
||||
'Menu:OAuthClient+' => 'Client OAuth pour l\'email',
|
||||
'Menu:RegenerateTokens' => 'Recréer un jeton d\'accès..',
|
||||
'OAuthClient:Name/UseForSMTPMustBeUnique' => 'La combinaison Login (%1$s) and Utilisé pour SMTP (%2$s) a déjà été utilisée pour OAuth Client',
|
||||
'OAuthClient:baseinfo' => 'Information',
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -18,7 +18,7 @@
|
||||
|
||||
@import 'variables.scss';
|
||||
@import '../../../../../node_modules/ckeditor5-itop-build/build/styles/compiled-theme';
|
||||
@import '../../../../../css/common/vendors/_highlightjs.scss';
|
||||
@import '../../../../../css/common/main.scss';
|
||||
|
||||
|
||||
/*!
|
||||
|
||||
@@ -659,4 +659,38 @@ abstract class AbstractBrick
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load brick configuration that is not part of the brick definition but is part of the portal global properties.
|
||||
*
|
||||
* @param $aPortalProperties
|
||||
*
|
||||
* @return void
|
||||
* @throws \DOMFormatException
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public function LoadFromPortalProperties($aPortalProperties)
|
||||
{
|
||||
// Get the bricks templates
|
||||
$aBricksTemplates = $aPortalProperties['templates']['bricks'];
|
||||
$sClassFQCN = get_class($this);
|
||||
|
||||
// Get the current brick templates
|
||||
$aCurrentBricksTemplates = array_key_exists($sClassFQCN, $aBricksTemplates) ? $aBricksTemplates[$sClassFQCN] : [];
|
||||
foreach($aCurrentBricksTemplates as $sTemplateKey => $sTemplate) {
|
||||
// Clean the template id
|
||||
$sTemplateId = str_ireplace($sClassFQCN.':', '', $sTemplateKey);
|
||||
|
||||
// Call the set method for the template
|
||||
$sSetTemplateMethodName = 'Set'.$sTemplateId.'TemplatePath';
|
||||
|
||||
if(method_exists($this, $sSetTemplateMethodName)) {
|
||||
$this->{$sSetTemplateMethodName}($sTemplate);
|
||||
}
|
||||
else {
|
||||
throw new DOMFormatException(
|
||||
'Template "'.$sTemplateId.'" is not a valid template for brick ' . $sClassFQCN,
|
||||
null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace Combodo\iTop\Portal\Brick;
|
||||
|
||||
use DOMFormatException;
|
||||
use Exception;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use UserRights;
|
||||
use ModuleDesign;
|
||||
use Combodo\iTop\Portal\Helper\ApplicationHelper;
|
||||
@@ -47,15 +48,21 @@ class BrickCollection
|
||||
private $aHomeOrdering;
|
||||
/** @var array $aNavigationMenuOrdering */
|
||||
private $aNavigationMenuOrdering;
|
||||
/** @var \array $aCombodoPortalInstanceConf
|
||||
* @since 3.2.1
|
||||
*/
|
||||
private $aCombodoPortalInstanceConf;
|
||||
|
||||
/**
|
||||
* BrickCollection constructor.
|
||||
*
|
||||
* @param \ModuleDesign $oModuleDesign
|
||||
* @param $aCombodoPortalInstanceConf
|
||||
*
|
||||
* @throws \Exception
|
||||
* @since 3.2.1 Added $aCombodoPortalInstanceConf parameter
|
||||
*/
|
||||
public function __construct(ModuleDesign $oModuleDesign)
|
||||
public function __construct(ModuleDesign $oModuleDesign, $aCombodoPortalInstanceConf)
|
||||
{
|
||||
$this->oModuleDesign = $oModuleDesign;
|
||||
$this->aAllowedBricks = null;
|
||||
@@ -63,6 +70,7 @@ class BrickCollection
|
||||
$this->iDisplayedInNavigationMenu = 0;
|
||||
$this->aHomeOrdering = array();
|
||||
$this->aNavigationMenuOrdering = array();
|
||||
$this->aCombodoPortalInstanceConf = $aCombodoPortalInstanceConf;
|
||||
|
||||
$this->Load();
|
||||
}
|
||||
@@ -196,6 +204,11 @@ class BrickCollection
|
||||
{
|
||||
/** @var \Combodo\iTop\Portal\Brick\PortalBrick $oBrick */
|
||||
$oBrick = new $sBrickClass();
|
||||
|
||||
// Load the portal properties that are common to all bricks of this type
|
||||
$oBrick->LoadFromPortalProperties($this->aCombodoPortalInstanceConf['properties']);
|
||||
|
||||
// Load the brick specific properties from its XML definition
|
||||
$oBrick->LoadFromXml($oBrickNode);
|
||||
|
||||
$aBricks[] = $oBrick;
|
||||
|
||||
@@ -1299,6 +1299,11 @@ class ObjectController extends BrickController
|
||||
$bIgnoreSilos = $this->oScopeValidatorHelper->IsAllDataAllowedForScope(UserRights::ListProfiles(), $sObjectClass);
|
||||
$aParams = array('objects_id' => $aObjectIds);
|
||||
$oSearch = DBObjectSearch::FromOQL("SELECT $sObjectClass WHERE id IN (:objects_id)");
|
||||
if (!$this->oScopeValidatorHelper->AddScopeToQuery($oSearch, $sObjectClass)
|
||||
) {
|
||||
IssueLog::Warning(__METHOD__.' at line '.__LINE__.' : User #'.UserRights::GetUserId().' not allowed to read '.$sObjectClass.' object.');
|
||||
throw new HttpException(Response::HTTP_NOT_FOUND, Dict::S('UI:ObjectDoesNotExist'));
|
||||
}
|
||||
if ($bIgnoreSilos === true) {
|
||||
$oSearch->AllowAllData();
|
||||
}
|
||||
@@ -1349,7 +1354,10 @@ class ObjectController extends BrickController
|
||||
$aObjectAttCodes = $this->oRequestManipulatorHelper->ReadParam('aObjectAttCodes', array(), FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY);
|
||||
$aLinkAttCodes = $this->oRequestManipulatorHelper->ReadParam('aLinkAttCodes', array(), FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY);
|
||||
$sDateTimePickerWidgetParent = $this->oRequestManipulatorHelper->ReadParam('sDateTimePickerWidgetParent', array(), FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY);
|
||||
|
||||
if (!MetaModel::IsLinkClass($sLinkClass)) {
|
||||
IssueLog::Warning(__METHOD__.' at line '.__LINE__.' : User #'.UserRights::GetUserId().' asked for wrong lnk class '.$sLinkClass);
|
||||
throw new HttpException(Response::HTTP_NOT_FOUND, Dict::S('UI:ObjectDoesNotExist'));
|
||||
}
|
||||
if (empty($sObjectClass) || empty($aObjectIds) || empty($aObjectAttCodes)) {
|
||||
IssueLog::Info(__METHOD__.' at line '.__LINE__.' : sObjectClass, aObjectIds and aObjectAttCodes expected, "'.$sObjectClass.'", "'.implode('/',
|
||||
$aObjectIds).'" given.');
|
||||
@@ -1360,6 +1368,10 @@ class ObjectController extends BrickController
|
||||
$bIgnoreSilos = $this->oScopeValidatorHelper->IsAllDataAllowedForScope(UserRights::ListProfiles(), $sObjectClass);
|
||||
$aParams = array('objects_id' => $aObjectIds);
|
||||
$oSearch = DBObjectSearch::FromOQL("SELECT $sObjectClass WHERE id IN (:objects_id)");
|
||||
if (!$this->oScopeValidatorHelper->AddScopeToQuery($oSearch, $sObjectClass)) {
|
||||
IssueLog::Warning(__METHOD__.' at line '.__LINE__.' : User #'.UserRights::GetUserId().' not allowed to read '.$sObjectClass.' object.');
|
||||
throw new HttpException(Response::HTTP_NOT_FOUND, Dict::S('UI:ObjectDoesNotExist'));
|
||||
}
|
||||
if ($bIgnoreSilos === true)
|
||||
{
|
||||
$oSearch->AllowAllData();
|
||||
@@ -1378,10 +1390,35 @@ class ObjectController extends BrickController
|
||||
// Prepare link data
|
||||
$aObjectData = $this->PrepareObjectInformation($oObject, $aObjectAttCodes);
|
||||
// New link object (needed for renderers)
|
||||
$oNewLink = new $sLinkClass();
|
||||
$aAttCodes = MetaModel::GetAttributesList($sLinkClass, ['AttributeExternalKey']);
|
||||
$sAttCodeToObject = '';
|
||||
foreach ($aAttCodes as $sAttCode) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($sLinkClass, $sAttCode);
|
||||
/** @var \AttributeExternalKey $oAttDef */
|
||||
if ($oAttDef->GetTargetClass() === $sObjectClass) {
|
||||
$sAttCodeToObject = $sAttCode;
|
||||
}
|
||||
}
|
||||
if ($sAttCodeToObject === '') {
|
||||
IssueLog::Warning(__METHOD__.' at line '.__LINE__.' : User #'.UserRights::GetUserId().' asked for incoherent lnk class '.$sLinkClass.' with object class '.$sObjectClass);
|
||||
throw new HttpException(Response::HTTP_NOT_FOUND, Dict::S('UI:ObjectDoesNotExist'));
|
||||
}
|
||||
$oNewLink = MetaModel::NewObject($sLinkClass, [
|
||||
$sAttCodeToObject => $oObject->GetKey(), // so later placeholders in filters will be applied on external keys on the same link
|
||||
]);
|
||||
foreach ($aLinkAttCodes as $sAttCode) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($sLinkClass, $sAttCode);
|
||||
/** @var \Combodo\iTop\Form\Field\SelectObjectField $oField */
|
||||
$oField = $oAttDef->MakeFormField($oNewLink);
|
||||
if ($oAttDef::GetFormFieldClass() === '\\Combodo\\iTop\\Form\\Field\\SelectObjectField') {
|
||||
$oFieldSearch = $oField->GetSearch();
|
||||
$sFieldClass = $oFieldSearch->GetClass();
|
||||
if ($this->oScopeValidatorHelper->AddScopeToQuery($oFieldSearch, $sFieldClass)){
|
||||
$oField->SetSearch($oFieldSearch);
|
||||
} else {
|
||||
$oField->SetSearch(DBObjectSearch::FromOQL("SELECT $sFieldClass WHERE 1=0"));
|
||||
}
|
||||
}
|
||||
// Prevent datetimepicker popup to be truncated
|
||||
if ($oField instanceof DateTimeField) {
|
||||
$oField->SetDateTimePickerWidgetParent($sDateTimePickerWidgetParent);
|
||||
|
||||
@@ -85,6 +85,7 @@ class Basic extends AbstractConfiguration
|
||||
'templates' => array(
|
||||
'layout' => 'itop-portal-base/portal/templates/layout.html.twig',
|
||||
'home' => 'itop-portal-base/portal/templates/home/layout.html.twig',
|
||||
'bricks' => array(),
|
||||
),
|
||||
'urlmaker_class' => null,
|
||||
'triggers_query' => null,
|
||||
@@ -185,6 +186,14 @@ class Basic extends AbstractConfiguration
|
||||
$aPortalConf['properties']['templates'][$sNodeId] = $oSubNode->GetText(null);
|
||||
break;
|
||||
default:
|
||||
// Try to accept the value as a global brick template, brick id format is "FQCN:page"
|
||||
[$sBrickFQCN, $sPage] = explode(':', $sNodeId);
|
||||
if (utils::IsNotNullOrEmptyString($sBrickFQCN) && utils::IsNotNullOrEmptyString($sPage))
|
||||
{
|
||||
$aPortalConf['properties']['templates']['bricks'][$sBrickFQCN][$sPage] = $oSubNode->GetText(null);
|
||||
break;
|
||||
}
|
||||
|
||||
throw new DOMFormatException(
|
||||
'Value "'.$sNodeId.'" is not handled for template[@id]',
|
||||
null, null, $oSubNode
|
||||
|
||||
@@ -592,6 +592,7 @@ EOF
|
||||
*/
|
||||
private static function GetDivAlert(string $message): string
|
||||
{
|
||||
$message = utils::EscapeHtml($message);
|
||||
return "<div class=\"ibo-csv-import--cell-error ibo-csv-import--cell-message\">$message</div>\n";
|
||||
}
|
||||
|
||||
|
||||
@@ -137,7 +137,6 @@ abstract class ItopCustomDatamodelTestCase extends ItopDataTestCase
|
||||
$sConfFile = utils::GetConfigFilePath($sTestEnv);
|
||||
$sConfFolder = dirname($sConfFile);
|
||||
if (is_file($sConfFile)) {
|
||||
chmod($sConfFile, 0777);
|
||||
SetupUtils::tidydir($sConfFolder);
|
||||
}
|
||||
|
||||
|
||||
@@ -102,6 +102,7 @@ class UnitTestRunTimeEnvironment extends RunTimeEnvironment
|
||||
$aTestDirs = array_merge($aTestDirs, glob(APPROOT.$sRoot.'tests', GLOB_ONLYDIR));
|
||||
}
|
||||
|
||||
$aLoadedTestClasses = [];
|
||||
foreach($aTestDirs as $sTestDir) {
|
||||
// Iterate on all PHP files in subdirectories
|
||||
// Note: grep is not available on Windows, so we will use the PHP Reflection API
|
||||
@@ -129,6 +130,11 @@ class UnitTestRunTimeEnvironment extends RunTimeEnvironment
|
||||
if ($sClass === '') {
|
||||
continue;
|
||||
}
|
||||
if (in_array($sClass, $aLoadedTestClasses)) {
|
||||
echo "class $sClass already loaded somehow \n";
|
||||
continue;
|
||||
}
|
||||
$aLoadedTestClasses[]=$sClass;
|
||||
require_once $sFile;
|
||||
$oReflectionClass = new ReflectionClass($sClass);
|
||||
if ($oReflectionClass->isAbstract()) {
|
||||
|
||||
@@ -101,13 +101,14 @@ class BulkChangeTest extends ItopDataTestCase
|
||||
//$this->debug("sStatus:".$sStatus->GetDescription());
|
||||
$this->assertEquals($aResult["__STATUS__"], $sStatus->GetDescription());
|
||||
foreach ($aRow as $i => $oCell) {
|
||||
/** @var $oCell \CellChangeSpec */
|
||||
if ($i !== "finalclass" && $i !== "__STATUS__" && $i !== "__ERRORS__" && array_key_exists($i, $aResult)) {
|
||||
$this->debug("i:".$i);
|
||||
$this->debug('GetCLIValue:'.$oCell->GetCLIValue());
|
||||
$this->debug("aResult:".$aResult[$i]);
|
||||
$this->assertEquals($aResult[$i], $oCell->GetCLIValue());
|
||||
$this->assertEquals($aResult[$i], $oCell->GetCLIValue(), "Unexpected CLI result for cell " . $i);
|
||||
if (null !== $aResultHTML) {
|
||||
$this->assertEquals($aResultHTML[$i], $oCell->GetHTMLValue());
|
||||
$this->assertEquals($aResultHTML[$i], $oCell->GetHTMLValue(), "Unexpected HTML result for cell " . $i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,13 +12,15 @@ namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use DBObjectSearch;
|
||||
use DBSearch;
|
||||
use OQLException;
|
||||
use OqlInterpreter;
|
||||
use OQLParserException;
|
||||
use UnknownClassOqlException;
|
||||
use UserRights;
|
||||
|
||||
class OQLParserTest extends ItopDataTestCase
|
||||
{
|
||||
const USE_TRANSACTION = false;
|
||||
|
||||
/**
|
||||
* @group iTopChangeMgt
|
||||
@@ -40,6 +42,21 @@ class OQLParserTest extends ItopDataTestCase
|
||||
self::assertEquals($sQuery,$sOql);
|
||||
}
|
||||
|
||||
public function testUnknownClassOqlException()
|
||||
{
|
||||
$oOrgId = $this->GivenObjectInDB('Organization', ['name' => 'TestOrg']);
|
||||
$sLogin = $this->GivenUserRestrictedToAnOrganizationInDB($oOrgId, self::$aURP_Profiles['Portal user']);
|
||||
UserRights::Login($sLogin);
|
||||
|
||||
try {
|
||||
DBSearch::FromOQL('SELECT UnknownClass');
|
||||
$this->fail('An UnknownClassOqlException should have been thrown');
|
||||
}
|
||||
catch (UnknownClassOqlException $e) {
|
||||
$this->assertNotContains('DBProperty', $e->GetSuggestions(), 'user should not be recommanded to perform queries on classes his not allowed to see');
|
||||
}
|
||||
}
|
||||
|
||||
public function NestedQueryProvider()
|
||||
{
|
||||
return array(
|
||||
|
||||
Reference in New Issue
Block a user