diff --git a/datamodels/2.x/itop-structure/module.itop-structure.php b/datamodels/2.x/itop-structure/module.itop-structure.php index 838fa5b50..1e4304619 100644 --- a/datamodels/2.x/itop-structure/module.itop-structure.php +++ b/datamodels/2.x/itop-structure/module.itop-structure.php @@ -95,6 +95,111 @@ if (!class_exists('StructureInstaller')) */ public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion) { + if (version_compare($sPreviousVersion, '3.1.0', '<')) + { + SetupLog::Info("Adding default triggers/action for Person objects mentions. All DM classes with at least 1 log attribute will be concerned..."); + + $sPersonClass = 'Person'; + $sPersonStateAttCode = MetaModel::GetStateAttributeCode($sPersonClass); + $sPersonOwnerOrgAttCode = UserRightsProfile::GetOwnerOrganizationAttCode($sPersonClass); + + $iClassesWithLogCount = 0; + $aCreatedTriggerIds = []; + foreach (MetaModel::EnumRootClasses() as $sRootClass) { + foreach (MetaModel::EnumChildClasses($sRootClass, ENUM_CHILD_CLASSES_ALL, true) as $sClass) { + $aLogAttCodes = MetaModel::GetAttributesList($sClass, ['AttributeCaseLog']); + + // Skip class with log attribute + if (count($aLogAttCodes) === 0) { + continue; + } + + // Prepare the mentioned_filter OQL + $oPersonSearch = DBObjectSearch::FromOQL("SELECT $sPersonClass"); + + // - Add status condition if attribute present + if (empty($sPersonStateAttCode) === false) { + $oPersonSearch->AddConditionExpression(new BinaryExpression( + new FieldExpression($sPersonStateAttCode), + '=', + new ScalarExpression('active') + )); + } + + // - Check if the classes have a silo attribute so we can use them in the mentioned_filter + if (empty($sPersonOwnerOrgAttCode) === false) { + // Filter on current contact org. + $oCurrentContactExpr = new BinaryExpression( + new FieldExpression($sPersonOwnerOrgAttCode), + '=', + new VariableExpression("current_contact->org_id") + ); + + // Filter on class owner org. if any + $sClassOwnerOrgAttCode = UserRightsProfile::GetOwnerOrganizationAttCode($sClass); + $oOwnerOrgExpr = empty($sClassOwnerOrgAttCode) ? null : new BinaryExpression( + new FieldExpression($sPersonOwnerOrgAttCode), + '=', + new VariableExpression("this->$sClassOwnerOrgAttCode") + ); + + // No owner org, simple condition + if ($oOwnerOrgExpr === null) { + $oPersonSearch->AddConditionExpression($oCurrentContactExpr); + } + // Owner org, condition is either from owner org or current contact's + else { + $oOrExpr = new BinaryExpression($oCurrentContactExpr, 'OR', $oOwnerOrgExpr); + $oPersonSearch->AddConditionExpression($oOrExpr); + } + } + + // Build the trigger + $oTrigger = MetaModel::NewObject('TriggerOnObjectMention'); + $oTrigger->Set('description', 'Person mentioned on '.$sClass); + $oTrigger->Set('target_class', $sClass); + $oTrigger->Set('mentioned_filter', $oPersonSearch->ToOQL()); + $oTrigger->DBInsert(); + + SetupLog::Info("|- Created trigger \"{$oTrigger->Get('description')}\" for class $sClass."); + $aCreatedTriggerIds[] = $oTrigger->GetKey(); + $iClassesWithLogCount++; + // Note: We break because we only have to create one trigger/action for the class hierarchy as it will be for all their log attributes + break; + } + } + + // Build the corresponding action and link it to the triggers + if (count($aCreatedTriggerIds) > 0) { + $oAction = MetaModel::NewObject('ActionEmail'); + $oAction->Set('name', 'Email mentioned person'); + $oAction->Set('status', 'enabled'); + $oAction->Set('from', '$current_contact->email$'); + $oAction->Set('to', 'SELECT Person WHERE id = :mentioned->id'); + $oAction->Set('subject', 'You have been mentioned in "$this->friendlyname$"'); + $oAction->Set('body', '
Hello $mentioned->first_name$,
+You have been mentioned by $current_contact->friendlyname$ in $this->hyperlink()$
' + ); + + /** @var \ormLinkSet $oOrm */ + $oOrm = $oAction->Get('trigger_list'); + foreach ($aCreatedTriggerIds as $sTriggerId) { + $oLink = new lnkTriggerAction(); + $oLink->Set('trigger_id', $sTriggerId); + $oOrm->AddItem($oLink); + } + $oAction->Set('trigger_list', $oOrm); + $oAction->DBInsert(); + + SetupLog::Info("|- Created action \"{$oAction->Get('name')}\" and linked it to the previously created triggers."); + } + + if ($iClassesWithLogCount === 0) { + SetupLog::Info("... no trigger/action created as there is no DM class with a log attribute."); + } else { + SetupLog::Info("... default triggers/action successfully created for $iClassesWithLogCount classes."); + } + } } } } diff --git a/pages/ajax.render.php b/pages/ajax.render.php index ab8236e49..8d3ebeae8 100644 --- a/pages/ajax.render.php +++ b/pages/ajax.render.php @@ -2415,6 +2415,7 @@ EOF $sMarker = utils::ReadParam('marker', '', false, utils::ENUM_SANITIZATION_FILTER_RAW_DATA); $sNeedle = utils::ReadParam('needle', '', false, utils::ENUM_SANITIZATION_FILTER_RAW_DATA); $sHostClass = utils::ReadParam('host_class', '', false, utils::ENUM_SANITIZATION_FILTER_CLASS); + $iHostId = (int) utils::ReadParam('host_id', 0, false, utils::ENUM_SANITIZATION_FILTER_INTEGER); // Check parameters if($sMarker === '') { @@ -2439,6 +2440,13 @@ EOF // Retrieve restricting scopes from triggers if any if (strlen($sHostClass) > 0) { + if ($iHostId > 0) { + $oHostObj = MetaModel::GetObject($sHostClass, $iHostId); + } else { + // Object is being created, use a dummy object as we have no way to recreate it + $oHostObj = MetaModel::NewObject($sHostClass); + } + $aTriggerMentionedSearches = []; $aTriggerSetParams = array('class_list' => MetaModel::EnumParentClasses($sHostClass, ENUM_PARENT_CLASSES_ALL)); @@ -2479,7 +2487,7 @@ EOF new BinaryExpression(new FieldExpression('friendlyname', $sSearchMainClassAlias), 'LIKE', new VariableExpression('needle')) ); - $oSet = new DBObjectSet($oSearch, array(), array('needle' => "%$sNeedle%")); + $oSet = new DBObjectSet($oSearch, array(), array('needle' => "%$sNeedle%", 'this' => $oHostObj)); $oSet->OptimizeColumnLoad(array($oSearch->GetClassAlias() => array())); $oSet->SetLimit(MetaModel::GetConfig()->Get('max_autocomplete_results')); // Note: We have to this manually because of a bug in DBSearch not checking the user prefs. by default. diff --git a/sources/application/UI/Base/Layout/ActivityPanel/CaseLogEntryForm/CaseLogEntryForm.php b/sources/application/UI/Base/Layout/ActivityPanel/CaseLogEntryForm/CaseLogEntryForm.php index 9a7ca98d8..0d7fce004 100644 --- a/sources/application/UI/Base/Layout/ActivityPanel/CaseLogEntryForm/CaseLogEntryForm.php +++ b/sources/application/UI/Base/Layout/ActivityPanel/CaseLogEntryForm/CaseLogEntryForm.php @@ -210,7 +210,8 @@ class CaseLogEntryForm extends UIContentBlock if (isset($aConfig['mentions'])) { foreach ($aConfig['mentions'] as $iIdx => $aData) { $sFeed = $aConfig['mentions'][$iIdx]['feed']; - $aConfig['mentions'][$iIdx]['feed'] = utils::AddParameterToUrl($sFeed, 'host_class', $this->GetObjectClass()); + $sFeed = utils::AddParameterToUrl($sFeed, 'host_class', $this->GetObjectClass()); + $aConfig['mentions'][$iIdx]['feed'] = utils::AddParameterToUrl($sFeed, 'host_id', $this->GetObjectId()); } } $this->oTextInput->SetConfig($aConfig);