From 900e8ac6d760013f83818669676ed15fcd16d834 Mon Sep 17 00:00:00 2001 From: Eric Date: Mon, 20 Jan 2020 15:50:08 +0100 Subject: [PATCH] =?UTF-8?q?N=C2=B0985=20-=20Add=20applicable=20contexts=20?= =?UTF-8?q?on=20Trigger?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/itopwebpage.class.inc.php | 2 +- core/attributedef.class.inc.php | 227 +++++++++++++----- core/contexttag.class.inc.php | 45 +++- core/dbobject.class.php | 2 +- core/ormset.class.inc.php | 13 +- core/trigger.class.inc.php | 63 ++++- .../2.x/authent-local/model.authent-local.php | 4 +- datamodels/2.x/itop-core-update/ajax.php | 2 +- datamodels/2.x/itop-core-update/index.php | 2 +- .../itop-portal-base/portal/public/index.php | 2 +- .../src/UrlMaker/AbstractPortalUrlMaker.php | 6 +- dictionaries/en.dictionary.itop.core.php | 12 + dictionaries/fr.dictionary.itop.core.php | 12 + lib/composer/autoload_classmap.php | 1 + lib/composer/autoload_static.php | 1 + setup/applicationinstaller.class.inc.php | 8 +- setup/compiler.class.inc.php | 19 ++ synchro/synchrodatasource.class.inc.php | 2 +- test/core/TriggerTest.php | 32 +++ webservices/cron.php | 2 +- webservices/rest.php | 2 +- 21 files changed, 366 insertions(+), 93 deletions(-) create mode 100644 test/core/TriggerTest.php diff --git a/application/itopwebpage.class.inc.php b/application/itopwebpage.class.inc.php index 9c13d3742..bc24b877f 100644 --- a/application/itopwebpage.class.inc.php +++ b/application/itopwebpage.class.inc.php @@ -51,7 +51,7 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage { parent::__construct($sTitle, $bPrintable); $this->m_oTabs = new TabManager(); - $this->oCtx = new ContextTag('GUI:Console'); + $this->oCtx = new ContextTag(ContextTag::TAG_CONSOLE); ApplicationContext::SetUrlMakerClass('iTopStandardURLMaker'); diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php index fabf1d13d..200f349c9 100644 --- a/core/attributedef.class.inc.php +++ b/core/attributedef.class.inc.php @@ -17,6 +17,10 @@ * You should have received a copy of the GNU Affero General Public License */ +use Combodo\iTop\Form\Field\LabelField; +use Combodo\iTop\Form\Validator\NotEmptyExtKeyValidator; +use Combodo\iTop\Form\Validator\Validator; + require_once('MyHelpers.class.inc.php'); require_once('ormdocument.class.inc.php'); require_once('ormstopwatch.class.inc.php'); @@ -1022,7 +1026,7 @@ abstract class AttributeDefinition // Validation pattern if ($this->GetValidationPattern() !== '') { - $oFormField->AddValidator(new \Combodo\iTop\Form\Validator\Validator($this->GetValidationPattern())); + $oFormField->AddValidator(new Validator($this->GetValidationPattern())); } // Metadata @@ -6730,7 +6734,7 @@ class AttributeExternalKey extends AttributeDBFieldVoid // If ExtKey is mandatory, we add a validator to ensure that the value 0 is not selected if ($oObject->GetAttributeFlags($this->GetCode()) & OPT_ATT_MANDATORY) { - $oFormField->AddValidator(new \Combodo\iTop\Form\Validator\NotEmptyExtKeyValidator()); + $oFormField->AddValidator(new NotEmptyExtKeyValidator()); } parent::MakeFormField($oObject, $oFormField); @@ -9812,10 +9816,19 @@ abstract class AttributeSet extends AttributeDBFieldVoid $aValues = array(); if (!empty($proposedValue)) { - foreach(explode(',', $proposedValue) as $sCode) + $sSepItem = MetaModel::GetConfig()->Get('tag_set_item_separator'); + // convert also , separated strings + if ($sSepItem !== ',') + { + $proposedValue = str_replace(',', $sSepItem, $proposedValue); + } + foreach(explode($sSepItem, $proposedValue) as $sCode) { $sValue = trim($sCode); - $aValues[] = $sValue; + if ($sValue !== '') + { + $aValues[] = $sValue; + } } } return $aValues; @@ -9835,20 +9848,6 @@ abstract class AttributeSet extends AttributeDBFieldVoid return $this->MakeRealValue($sValue, null, true); } - /** - * @param $aCols - * @param string $sPrefix - * - * @return mixed - * @throws \Exception - */ - public function FromImportToValue($aCols, $sPrefix = '') - { - $sValue = $aCols["$sPrefix"]; - - return $this->MakeRealValue($sValue, null); - } - /** * force an allowed value (type conversion and possibly forces a value as mySQL would do upon writing! * @@ -9951,7 +9950,7 @@ abstract class AttributeSet extends AttributeDBFieldVoid } /** - * @param $value + * @param string $value * * @return string */ @@ -9967,7 +9966,16 @@ abstract class AttributeSet extends AttributeDBFieldVoid } if (is_array($value)) { - return implode(', ', $value); + $sSepItem = MetaModel::GetConfig()->Get('tag_set_item_separator'); + $sRes = implode($sSepItem, $value); + if (!empty($sRes)) + { + $value = "{$sSepItem}{$sRes}{$sSepItem}"; + } + else + { + $value = ''; + } } return $value; } @@ -9994,6 +10002,43 @@ abstract class AttributeSet extends AttributeDBFieldVoid return $value; } + /** + * @param $value + * @param string $sSeparator + * @param string $sTextQualifier + * @param \DBObject $oHostObject + * @param bool $bLocalize + * @param bool $bConvertToPlainText + * + * @return mixed|string + */ + public function GetAsCSV($value, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true, $bConvertToPlainText = false) + { + $sSepItem = MetaModel::GetConfig()->Get('tag_set_item_separator'); + if (is_object($value) && ($value instanceof ormSet)) + { + if ($bLocalize) + { + $aValues = $value->GetLabels(); + } + else + { + $aValues = $value->GetValues(); + } + $sRes = implode($sSepItem, $aValues); + if (!empty($sRes)) + { + $sRes = "{$sSepItem}{$sRes}{$sSepItem}"; + } + } + else + { + $sRes = ''; + } + + return "{$sTextQualifier}{$sRes}{$sTextQualifier}"; + } + public function GetMaxItems() { return $this->Get('max_items'); @@ -10005,6 +10050,111 @@ abstract class AttributeSet extends AttributeDBFieldVoid } } +class AttributeEnumSet extends AttributeSet +{ + const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_STRING; + + public function GetAllowedValues($aArgs = array(), $sContains = '') + { + $aRawValues = parent::GetAllowedValues($aArgs, $sContains); + if (is_null($aRawValues)) + { + return null; + } + $aLocalizedValues = array(); + foreach($aRawValues as $sKey => $sValue) + { + $aLocalizedValues[$sKey] = $this->GetValueLabel($sKey); + } + + return $aLocalizedValues; + } + + public function GetValueLabel($sValue) + { + if (is_null($sValue)) + { + // Unless a specific label is defined for the null value of this enum, use a generic "undefined" label + $sLabel = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue, + Dict::S('Enum:Undefined')); + } + else + { + $sLabel = $this->SearchLabel('/Attribute:'.$this->m_sCode.'/Value:'.$sValue, null, true /*user lang*/); + if (is_null($sLabel)) + { + $sDefault = str_replace('_', ' ', $sValue); + // Browse the hierarchy again, accepting default (english) translations + $sLabel = $this->SearchLabel('/Attribute:'.$this->m_sCode.'/Value:'.$sValue, $sDefault, false); + } + } + + return $sLabel; + } + + public function GetValueDescription($sValue) + { + if (is_null($sValue)) + { + // Unless a specific label is defined for the null value of this enum, use a generic "undefined" label + $sDescription = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue.'+', + Dict::S('Enum:Undefined')); + } + else + { + $sDescription = Dict::S('Class:'.$this->GetHostClass().'/Attribute:'.$this->GetCode().'/Value:'.$sValue.'+', + '', true /* user language only */); + if (strlen($sDescription) == 0) + { + $sParentClass = MetaModel::GetParentClass($this->m_sHostClass); + if ($sParentClass) + { + if (MetaModel::IsValidAttCode($sParentClass, $this->m_sCode)) + { + $oAttDef = MetaModel::GetAttributeDef($sParentClass, $this->m_sCode); + $sDescription = $oAttDef->GetValueDescription($sValue); + } + } + } + } + + return $sDescription; + } + + public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true) + { + if ($bLocalize) + { + if ($sValue instanceof ormSet) + { + /** @var ormSet $oOrmSet */ + $oOrmSet = $sValue; + $aRes = array(); + foreach ($oOrmSet->GetValues() as $sValue) + { + $sLabel = $this->GetValueLabel($sValue); + $sDescription = $this->GetValueDescription($sValue); + $aRes[] = "".parent::GetAsHtml($sLabel).""; + } + $sRes = implode(', ', $aRes); + } + else + { + $sLabel = $this->GetValueLabel($sValue); + $sDescription = $this->GetValueDescription($sValue); + $sRes = "".parent::GetAsHtml($sLabel).""; + } + } + else + { + $sRes = parent::GetAsHtml($sValue, $oHostObject, $bLocalize); + } + + return $sRes; + } + +} + class AttributeClassAttCodeSet extends AttributeSet { const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_STRING; @@ -11018,41 +11168,6 @@ class AttributeTagSet extends AttributeSet return $sRes; } - /** - * @param $value - * @param string $sSeparator - * @param string $sTextQualifier - * @param \DBObject $oHostObject - * @param bool $bLocalize - * @param bool $bConvertToPlainText - * - * @return mixed|string - */ - public function GetAsCSV( - $value, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true, - $bConvertToPlainText = false - ) { - $sSepItem = MetaModel::GetConfig()->Get('tag_set_item_separator'); - if (is_object($value) && ($value instanceof ormTagSet)) - { - if ($bLocalize) - { - $aValues = $value->GetLabels(); - } - else - { - $aValues = $value->GetValues(); - } - $sRes = implode($sSepItem, $aValues); - } - else - { - $sRes = ''; - } - - return "{$sTextQualifier}{$sRes}{$sTextQualifier}"; - } - /** * List the available verbs for 'GetForTemplate' */ @@ -12031,7 +12146,7 @@ class AttributeCustomFields extends AttributeDefinition } catch (Exception $e) { $oForm = new \Combodo\iTop\Form\Form(''); - $oField = new \Combodo\iTop\Form\Field\LabelField(''); + $oField = new LabelField(''); $oField->SetLabel('Custom field error: '.$e->getMessage()); $oForm->AddField($oField); $oForm->Finalize(); diff --git a/core/contexttag.class.inc.php b/core/contexttag.class.inc.php index f32ebdcf1..e3725de13 100644 --- a/core/contexttag.class.inc.php +++ b/core/contexttag.class.inc.php @@ -19,14 +19,14 @@ /** * Simple helper class for keeping track of the context inside the call stack - * + * * To check (anywhere in the code) if a particular context tag is present * in the call stack simply do: - * + * * if (ContextTag::Check()) ... - * + * * For example to know if the code is being executed in the context of a portal do: - * + * * if (ContextTag::Check('GUI:Portal')) * * @copyright Copyright (C) 2016-2017 Combodo SARL @@ -35,8 +35,15 @@ class ContextTag { + const TAG_PORTAL = 'GUI:Portal'; + const TAG_CRON = 'CRON'; + const TAG_CONSOLE = 'GUI:Console'; + const TAG_SETUP = 'Setup'; + const TAG_SYNCHRO = 'Synchro'; + const TAG_REST = 'REST/JSON'; + protected static $aStack = array(); - + /** * Store a context tag on the stack * @param string $sTag @@ -46,6 +53,11 @@ class ContextTag static::$aStack[] = $sTag; } + public static function AddContext($sTag) + { + static::$aStack[] = $sTag; + } + /** * Cleanup the context stack */ @@ -53,7 +65,7 @@ class ContextTag { array_pop(static::$aStack); } - + /** * Check if a given tag is present in the stack * @param string $sTag @@ -63,13 +75,28 @@ class ContextTag { return in_array($sTag, static::$aStack); } - + /** * Get the whole stack as an array - * @return hash + * @return array */ public static function GetStack() { return static::$aStack; } -} \ No newline at end of file + + /** + * Get all the predefined context tags + * @return array + */ + public static function GetTags() + { + return array( + ContextTag::TAG_REST, + ContextTag::TAG_SYNCHRO, + ContextTag::TAG_SETUP, + ContextTag::TAG_CONSOLE, + ContextTag::TAG_CRON, + ContextTag::TAG_PORTAL); + } +} diff --git a/core/dbobject.class.php b/core/dbobject.class.php index 74389851f..276217563 100644 --- a/core/dbobject.class.php +++ b/core/dbobject.class.php @@ -1912,7 +1912,7 @@ abstract class DBObject implements iDisplay return "Bad type"; } - elseif ($oAtt instanceof AttributeClassAttCodeSet) + elseif (($oAtt instanceof AttributeClassAttCodeSet) || ($oAtt instanceof AttributeEnumSet)) { if (is_string($toCheck)) { diff --git a/core/ormset.class.inc.php b/core/ormset.class.inc.php index 9879d8b49..8ceb884c1 100644 --- a/core/ormset.class.inc.php +++ b/core/ormset.class.inc.php @@ -164,6 +164,17 @@ class ormSet return $aValues; } + public function GetLabels() + { + $aLabels = array(); + $aValues = $this->GetValues(); + foreach ($aValues as $sValue) + { + $aLabels[$sValue] = $sValue; + } + return $aLabels; + } + /** * @return array of tag labels indexed by code for only the added tags */ @@ -377,4 +388,4 @@ class ormSet } -} \ No newline at end of file +} diff --git a/core/trigger.class.inc.php b/core/trigger.class.inc.php index e3c33f824..8240d57ef 100644 --- a/core/trigger.class.inc.php +++ b/core/trigger.class.inc.php @@ -56,15 +56,49 @@ abstract class Trigger extends cmdbAbstractObject //MetaModel::Init_InheritAttributes(); MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values" => null, "sql" => "description", "default_value" => null, "is_null_allowed" => false, "depends_on" => array()))); MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("action_list", array("linked_class" => "lnkTriggerAction", "ext_key_to_me" => "trigger_id", "ext_key_to_remote" => "action_id", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => array()))); + $aTags = ContextTag::GetTags(); + $sTags = implode(',', $aTags); + MetaModel::Init_AddAttribute( new AttributeEnumSet("context", array("allowed_values" => new ValueSetEnum($sTags), "sql" => "context", "depends_on" => array(), "is_null_allowed" => true, "max_items" => 12))); // Display lists - MetaModel::Init_SetZListItems('details', array('finalclass', 'description', 'action_list')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('details', array('finalclass', 'description', 'context', 'action_list')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('list', array('finalclass')); // Attributes to be displayed for a list // Search criteria // MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form // MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form } + /** + * Check if the trigger can be used in the current context + * + * @return bool true if context OK + * @throws \ArchivedObjectException + * @throws \CoreException + */ + public function IsContextValid() + { + // Check the context + $oContext = $this->Get('context'); + $bChecked = false; + $bValid = false; + foreach ($oContext->GetValues() as $sValue) + { + $bChecked = true; + if (ContextTag::Check($sValue)) + { + $bValid = true; + break; + } + } + if ($bChecked && !$bValid) + { + // Trigger does not match the current context + return false; + } + + return true; + } + /** * @param $aContextArgs * @@ -73,6 +107,15 @@ abstract class Trigger extends cmdbAbstractObject */ public function DoActivate($aContextArgs) { + // Check the context + if (!$this->IsContextValid()) + { + // Trigger does not match the current context + IssueLog::Info("Context NOT valid for: ".$this->Get('friendlyname')); + return; + } + IssueLog::Info("Context VALID for: ".$this->Get('friendlyname')); + // Find the related actions $oLinkedActions = $this->Get('action_list'); while ($oLink = $oLinkedActions->Fetch()) @@ -133,7 +176,7 @@ abstract class TriggerOnObject extends Trigger MetaModel::Init_AddAttribute(new AttributeOQL("filter", array("allowed_values" => null, "sql" => "filter", "default_value" => null, "is_null_allowed" => true, "depends_on" => array()))); // Display lists - MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'filter', 'action_list')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'action_list')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class', 'description')); // Attributes to be displayed for a list // Search criteria MetaModel::Init_SetZListItems('default_search', array('description', 'target_class')); // Default criteria of the search banner @@ -258,7 +301,7 @@ class TriggerOnPortalUpdate extends TriggerOnObject MetaModel::Init_InheritAttributes(); // Display lists - MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'filter', 'action_list')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'action_list')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class', 'description')); // Attributes to be displayed for a list // Search criteria } @@ -292,7 +335,7 @@ abstract class TriggerOnStateChange extends TriggerOnObject MetaModel::Init_AddAttribute(new AttributeClassState("state", array("class_field" => 'target_class', "allowed_values" => null, "sql" => "state", "default_value" => null, "is_null_allowed" => false, "depends_on" => array('target_class')))); // Display lists - MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'filter', 'state', 'action_list')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'action_list')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class', 'state')); // Attributes to be displayed for a list // Search criteria MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form @@ -326,7 +369,7 @@ class TriggerOnStateEnter extends TriggerOnStateChange MetaModel::Init_InheritAttributes(); // Display lists - MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'filter', 'state', 'action_list')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'action_list')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('list', array('target_class', 'state')); // Attributes to be displayed for a list // Search criteria MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form @@ -360,7 +403,7 @@ class TriggerOnStateLeave extends TriggerOnStateChange MetaModel::Init_InheritAttributes(); // Display lists - MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'filter', 'state', 'action_list')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'action_list')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('list', array('target_class', 'state')); // Attributes to be displayed for a list // Search criteria MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form @@ -394,7 +437,7 @@ class TriggerOnObjectCreate extends TriggerOnObject MetaModel::Init_InheritAttributes(); // Display lists - MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'filter', 'action_list')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'action_list')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list // Search criteria MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form @@ -428,7 +471,7 @@ class TriggerOnObjectDelete extends TriggerOnObject MetaModel::Init_InheritAttributes(); // Display lists - MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'filter', 'action_list')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'action_list')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list // Search criteria MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form @@ -464,7 +507,7 @@ class TriggerOnObjectUpdate extends TriggerOnObject MetaModel::Init_AddAttribute(new AttributeClassAttCodeSet('target_attcodes', array("allowed_values" => null, "class_field" => "target_class", "sql" => "target_attcodes", "default_value" => null, "is_null_allowed" => true, "max_items" => 20, "min_items" => 0, "attribute_definition_exclusion_list" => "AttributeDashboard,AttributeExternalField,AttributeFinalClass,AttributeFriendlyName,AttributeObsolescenceDate,AttributeObsolescenceFlag,AttributeSubItem", "attribute_definition_list" => null, "depends_on" => array('target_class')))); // Display lists - MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'filter', 'target_attcodes', 'action_list')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'target_attcodes', 'action_list')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list // Search criteria MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form @@ -599,7 +642,7 @@ class TriggerOnThresholdReached extends TriggerOnObject MetaModel::Init_AddAttribute(new AttributeString("threshold_index", array("allowed_values" => null, "sql" => "threshold_index", "default_value" => null, "is_null_allowed" => false, "depends_on" => array()))); // Display lists - MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'stop_watch_code', 'threshold_index', 'filter', 'action_list')); // Attributes to be displayed for the complete details + MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'stop_watch_code', 'threshold_index', 'filter', 'action_list')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('list', array('target_class', 'threshold_index', 'threshold_index')); // Attributes to be displayed for a list // Search criteria MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form diff --git a/datamodels/2.x/authent-local/model.authent-local.php b/datamodels/2.x/authent-local/model.authent-local.php index 19981bebc..9f342dc42 100755 --- a/datamodels/2.x/authent-local/model.authent-local.php +++ b/datamodels/2.x/authent-local/model.authent-local.php @@ -179,7 +179,7 @@ class UserLocal extends UserInternal public function IsPasswordValid() { - if (ContextTag::Check('Setup')) + if (ContextTag::Check(ContextTag::TAG_SETUP)) { // during the setup, the admin account can have whatever password you want ... return true; @@ -190,7 +190,7 @@ class UserLocal extends UserInternal public function getPasswordValidityMessage() { - if (ContextTag::Check('Setup')) + if (ContextTag::Check(ContextTag::TAG_SETUP)) { // during the setup, the admin account can have whatever password you want ... return null; diff --git a/datamodels/2.x/itop-core-update/ajax.php b/datamodels/2.x/itop-core-update/ajax.php index 2d0ba9c1a..ce60866ef 100644 --- a/datamodels/2.x/itop-core-update/ajax.php +++ b/datamodels/2.x/itop-core-update/ajax.php @@ -23,7 +23,7 @@ require_once(MODULESROOT.'itop-core-update/src/Controller/AjaxController.php'); MetaModel::LoadConfig(utils::GetConfig()); -new ContextTag('Setup'); +new ContextTag(ContextTag::TAG_SETUP); $oUpdateController = new AjaxController(MODULESROOT.'itop-core-update/view', 'itop-core-update'); $oUpdateController->DisableInDemoMode(); diff --git a/datamodels/2.x/itop-core-update/index.php b/datamodels/2.x/itop-core-update/index.php index af136b500..ac4897d81 100644 --- a/datamodels/2.x/itop-core-update/index.php +++ b/datamodels/2.x/itop-core-update/index.php @@ -10,7 +10,7 @@ use Combodo\iTop\CoreUpdate\Controller\UpdateController; use ContextTag; require_once(APPROOT.'application/startup.inc.php'); -new ContextTag('Setup'); +new ContextTag(ContextTag::TAG_SETUP); $oUpdateController = new UpdateController(MODULESROOT.'itop-core-update/view', 'itop-core-update'); $oUpdateController->DisableInDemoMode(); diff --git a/datamodels/2.x/itop-portal-base/portal/public/index.php b/datamodels/2.x/itop-portal-base/portal/public/index.php index 805bbd5da..04d090984 100644 --- a/datamodels/2.x/itop-portal-base/portal/public/index.php +++ b/datamodels/2.x/itop-portal-base/portal/public/index.php @@ -23,7 +23,7 @@ use Symfony\Component\HttpFoundation\Request; require_once MODULESROOT.'itop-portal-base/portal/config/bootstrap.php'; // Stacking context tag so it knows we are in the portal -$oContext = new ContextTag('GUI:Portal'); +$oContext = new ContextTag(ContextTag::TAG_PORTAL); $oContext2 = new ContextTag('Portal:' . $_ENV['PORTAL_ID']); // Note: Manually refactored ternary condition to be PHP 5.x compatible diff --git a/datamodels/2.x/itop-portal-base/portal/src/UrlMaker/AbstractPortalUrlMaker.php b/datamodels/2.x/itop-portal-base/portal/src/UrlMaker/AbstractPortalUrlMaker.php index 97eff720d..eb965a86b 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/UrlMaker/AbstractPortalUrlMaker.php +++ b/datamodels/2.x/itop-portal-base/portal/src/UrlMaker/AbstractPortalUrlMaker.php @@ -100,7 +100,7 @@ abstract class AbstractPortalUrlMaker implements iDBObjectURLMaker switch ($sMode) { case 'view': - if (!ContextTag::Check('GUI:Portal') || $oSecurityHelper->IsActionAllowed(UR_ACTION_READ, $sClass, $iId)) + if (!ContextTag::Check(ContextTag::TAG_PORTAL) || $oSecurityHelper->IsActionAllowed(UR_ACTION_READ, $sClass, $iId)) { $sObjectQueryString = $oUrlGenerator->generate('p_object_view', array('sObjectClass' => $sClass, 'sObjectId' => $iId)); } @@ -109,11 +109,11 @@ abstract class AbstractPortalUrlMaker implements iDBObjectURLMaker case 'edit': default: // Checking if user is allowed to edit object, if not we check if it can at least view it. - if (!ContextTag::Check('GUI:Portal') || $oSecurityHelper->IsActionAllowed(UR_ACTION_MODIFY, $sClass, $iId)) + if (!ContextTag::Check(ContextTag::TAG_PORTAL) || $oSecurityHelper->IsActionAllowed(UR_ACTION_MODIFY, $sClass, $iId)) { $sObjectQueryString = $oUrlGenerator->generate('p_object_edit', array('sObjectClass' => $sClass, 'sObjectId' => $iId)); } - elseif (!ContextTag::Check('GUI:Portal') || $oSecurityHelper->IsActionAllowed(UR_ACTION_READ, $sClass, $iId)) + elseif (!ContextTag::Check(ContextTag::TAG_PORTAL) || $oSecurityHelper->IsActionAllowed(UR_ACTION_READ, $sClass, $iId)) { $sObjectQueryString = $oUrlGenerator->generate('p_object_view', array('sObjectClass' => $sClass, 'sObjectId' => $iId)); } diff --git a/dictionaries/en.dictionary.itop.core.php b/dictionaries/en.dictionary.itop.core.php index ad1ac55af..9399c5bfd 100644 --- a/dictionaries/en.dictionary.itop.core.php +++ b/dictionaries/en.dictionary.itop.core.php @@ -535,6 +535,18 @@ Dict::Add('EN US', 'English', 'English', array( 'Class:Trigger/Attribute:action_list+' => 'Actions performed when the trigger is activated', 'Class:Trigger/Attribute:finalclass' => 'Trigger sub-class', 'Class:Trigger/Attribute:finalclass+' => 'Name of the final class', + 'Class:Trigger/Attribute:context/Value:REST/JSON' => 'REST', + 'Class:Trigger/Attribute:context/Value:REST/JSON+' => 'REST/JSON', + 'Class:Trigger/Attribute:context/Value:Synchro' => 'Synchro', + 'Class:Trigger/Attribute:context/Value:Synchro+' => 'Synchro', + 'Class:Trigger/Attribute:context/Value:Setup' => 'Setup', + 'Class:Trigger/Attribute:context/Value:Setup+' => 'Setup', + 'Class:Trigger/Attribute:context/Value:GUI:Console' => 'Console', + 'Class:Trigger/Attribute:context/Value:GUI:Console+' => 'GUI:Console', + 'Class:Trigger/Attribute:context/Value:CRON' => 'CRON', + 'Class:Trigger/Attribute:context/Value:CRON+' => 'CRON', + 'Class:Trigger/Attribute:context/Value:GUI:Portal' => 'Portal', + 'Class:Trigger/Attribute:context/Value:GUI:Portal+' => 'GUI:Portal', )); // diff --git a/dictionaries/fr.dictionary.itop.core.php b/dictionaries/fr.dictionary.itop.core.php index 2e2e0e7d2..3213c067b 100644 --- a/dictionaries/fr.dictionary.itop.core.php +++ b/dictionaries/fr.dictionary.itop.core.php @@ -533,6 +533,18 @@ Dict::Add('FR FR', 'French', 'Français', array( 'Class:Trigger/Attribute:action_list+' => '', 'Class:Trigger/Attribute:finalclass' => 'Sous-classe de Déclencheur', 'Class:Trigger/Attribute:finalclass+' => 'Nom de la classe instanciable', + 'Class:Trigger/Attribute:context/Value:REST/JSON' => 'REST', + 'Class:Trigger/Attribute:context/Value:REST/JSON+' => 'REST/JSON', + 'Class:Trigger/Attribute:context/Value:Synchro' => 'Synchro', + 'Class:Trigger/Attribute:context/Value:Synchro+' => 'Synchro', + 'Class:Trigger/Attribute:context/Value:Setup' => 'Setup', + 'Class:Trigger/Attribute:context/Value:Setup+' => 'Setup', + 'Class:Trigger/Attribute:context/Value:GUI:Console' => 'Console', + 'Class:Trigger/Attribute:context/Value:GUI:Console+' => 'GUI:Console', + 'Class:Trigger/Attribute:context/Value:CRON' => 'CRON', + 'Class:Trigger/Attribute:context/Value:CRON+' => 'CRON', + 'Class:Trigger/Attribute:context/Value:GUI:Portal' => 'Portal', + 'Class:Trigger/Attribute:context/Value:GUI:Portal+' => 'GUI:Portal', )); // diff --git a/lib/composer/autoload_classmap.php b/lib/composer/autoload_classmap.php index 0b4f45369..83ad48760 100644 --- a/lib/composer/autoload_classmap.php +++ b/lib/composer/autoload_classmap.php @@ -45,6 +45,7 @@ return array( 'AttributeEmailAddress' => $baseDir . '/core/attributedef.class.inc.php', 'AttributeEncryptedString' => $baseDir . '/core/attributedef.class.inc.php', 'AttributeEnum' => $baseDir . '/core/attributedef.class.inc.php', + 'AttributeEnumSet' => $baseDir . '/core/attributedef.class.inc.php', 'AttributeExternalField' => $baseDir . '/core/attributedef.class.inc.php', 'AttributeExternalKey' => $baseDir . '/core/attributedef.class.inc.php', 'AttributeFinalClass' => $baseDir . '/core/attributedef.class.inc.php', diff --git a/lib/composer/autoload_static.php b/lib/composer/autoload_static.php index 9b6a75236..82c2ef070 100644 --- a/lib/composer/autoload_static.php +++ b/lib/composer/autoload_static.php @@ -275,6 +275,7 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b 'AttributeEmailAddress' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php', 'AttributeEncryptedString' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php', 'AttributeEnum' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php', + 'AttributeEnumSet' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php', 'AttributeExternalField' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php', 'AttributeExternalKey' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php', 'AttributeFinalClass' => __DIR__ . '/../..' . '/core/attributedef.class.inc.php', diff --git a/setup/applicationinstaller.class.inc.php b/setup/applicationinstaller.class.inc.php index f191fa7de..5403e3bf3 100644 --- a/setup/applicationinstaller.class.inc.php +++ b/setup/applicationinstaller.class.inc.php @@ -685,7 +685,7 @@ class ApplicationInstaller $oProductionEnv = new RunTimeEnvironment($sTargetEnvironment); $oProductionEnv->InitDataModel($oConfig, true); // load data model only - $oContextTag = new ContextTag('Setup'); + $oContextTag = new ContextTag(ContextTag::TAG_SETUP); // Migrate columns self::MoveColumns($sDBPrefix); @@ -878,7 +878,7 @@ class ApplicationInstaller $oProductionEnv = new RunTimeEnvironment($sTargetEnvironment); $oProductionEnv->InitDataModel($oConfig, true); // load data model and connect to the database - $oContextTag = new ContextTag('Setup'); + $oContextTag = new ContextTag(ContextTag::TAG_SETUP); self::$bMetaModelStarted = true; // No need to reload the final MetaModel in case the installer runs synchronously // Perform here additional DB setup... profiles, etc... @@ -945,7 +945,7 @@ class ApplicationInstaller if (!self::$bMetaModelStarted) { $oProductionEnv->InitDataModel($oConfig, false); // load data model and connect to the database - $oContextTag = new ContextTag('Setup'); + $oContextTag = new ContextTag(ContextTag::TAG_SETUP); self::$bMetaModelStarted = true; // No need to reload the final MetaModel in case the installer runs synchronously } @@ -1018,7 +1018,7 @@ class ApplicationInstaller // Record which modules are installed... $oProductionEnv = new RunTimeEnvironment($sTargetEnvironment); $oProductionEnv->InitDataModel($oConfig, true); // load data model and connect to the database - $oContextTag = new ContextTag('Setup'); + $oContextTag = new ContextTag(ContextTag::TAG_SETUP); if (!$oProductionEnv->RecordInstallation($oConfig, $sDataModelVersion, $aSelectedModuleCodes, $aSelectedExtensionCodes, $sInstallComment)) { diff --git a/setup/compiler.class.inc.php b/setup/compiler.class.inc.php index 803a771e9..f8a943f54 100644 --- a/setup/compiler.class.inc.php +++ b/setup/compiler.class.inc.php @@ -1528,6 +1528,25 @@ EOF // Exclusion list of AttributeDefinition Classes to filter class_field (empty means no exclusion) $aParameters['attribute_definition_exclusion_list'] = $this->GetPropString($oField, 'attribute_definition_exclusion_list', ''); } + elseif ($sAttType == 'AttributeEnumSet') + { + $aTagFieldsInfo[] = $sAttCode; + $oValues = $oField->GetUniqueElement('values'); + $oValueNodes = $oValues->getElementsByTagName('value'); + $aValues = array(); + foreach($oValueNodes as $oValue) + { + // new style... $aValues[] = self::QuoteForPHP($oValue->textContent); + $aValues[] = $oValue->textContent; + } + // new style... $sValues = 'array('.implode(', ', $aValues).')'; + $sValues = '"'.implode(',', $aValues).'"'; + $aParameters['allowed_values'] = "new ValueSetEnum($sValues)"; + $aParameters['sql'] = $this->GetMandatoryPropString($oField, 'sql'); + $aParameters['is_null_allowed'] = $this->GetPropBoolean($oField, 'is_null_allowed', false); + $aParameters['depends_on'] = $sDependencies; + $aParameters['max_items'] = $this->GetPropNumber($oField, 'max_items', 12); + } elseif ($sAttType == 'AttributeQueryAttCodeSet') { $aTagFieldsInfo[] = $sAttCode; diff --git a/synchro/synchrodatasource.class.inc.php b/synchro/synchrodatasource.class.inc.php index 72e5f7769..eac1c4048 100644 --- a/synchro/synchrodatasource.class.inc.php +++ b/synchro/synchrodatasource.class.inc.php @@ -2957,7 +2957,7 @@ class SynchroExecution $this->m_bIsImportPhaseDateKnown = ($oImportPhaseStartDate != null); $this->m_oImportPhaseStartDate = $oImportPhaseStartDate; - $this->m_oCtx = new ContextTag('Synchro'); + $this->m_oCtx = new ContextTag(ContextTag::TAG_SYNCHRO); $this->m_oCtx1 = new ContextTag('Synchro:'.$oDataSource->GetRawName()); // More precise context information } diff --git a/test/core/TriggerTest.php b/test/core/TriggerTest.php new file mode 100644 index 000000000..e9c703cec --- /dev/null +++ b/test/core/TriggerTest.php @@ -0,0 +1,32 @@ +Set('context', ContextTag::TAG_PORTAL.', '.ContextTag::TAG_CRON); + $this->assertFalse($oTrigger->IsContextValid()); + ContextTag::AddContext(ContextTag::TAG_SETUP); + $this->assertFalse($oTrigger->IsContextValid()); + ContextTag::AddContext(ContextTag::TAG_CRON); + $this->assertTrue($oTrigger->IsContextValid()); + } +} diff --git a/webservices/cron.php b/webservices/cron.php index ca023f193..a406f4718 100644 --- a/webservices/cron.php +++ b/webservices/cron.php @@ -44,7 +44,7 @@ if (!file_exists($sConfigFile)) require_once(APPROOT.'/application/startup.inc.php'); -$oCtx = new ContextTag('CRON'); +$oCtx = new ContextTag(ContextTag::TAG_CRON); function ReadMandatoryParam($oP, $sParam, $sSanitizationFilter = 'parameter') { diff --git a/webservices/rest.php b/webservices/rest.php index 5c020402b..433f2b365 100644 --- a/webservices/rest.php +++ b/webservices/rest.php @@ -66,7 +66,7 @@ if (!function_exists('json_last_error_msg')) { // Main // $oP = new ajax_page('rest'); -$oCtx = new ContextTag('REST/JSON'); +$oCtx = new ContextTag(ContextTag::TAG_REST); $sVersion = utils::ReadParam('version', null, false, 'raw_data'); $sOperation = utils::ReadParam('operation', null);