diff --git a/application/utils.inc.php b/application/utils.inc.php index 2292b5a29..1c45e7121 100644 --- a/application/utils.inc.php +++ b/application/utils.inc.php @@ -2638,9 +2638,21 @@ class utils if(!empty($aMentionsAllowedClasses)) { $aDefaultConf['mentions'] = []; - foreach($aMentionsAllowedClasses as $sMentionChar => $sMentionClass) { + foreach($aMentionsAllowedClasses as $sMentionMarker => $sMentionScope) { + // Retrieve mention class + // - First test if the conf is a simple Datamodel class + if (MetaModel::IsValidClass($sMentionScope)) { + $sMentionClass = $sMentionScope; + } + // - Otherwise it must be a valid OQL + else { + $oTmpSearch = DBSearch::FromOQL($sMentionScope); + $sMentionClass = $oTmpSearch->GetClass(); + unset($oTmpSearch); + } + // Note: Endpoints are defaults only and should be overloaded by other GUIs such as the end-users portal - $sMentionEndpoint = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=cke_mentions&target_class='.$sMentionClass.'&needle={encodedQuery}'; + $sMentionEndpoint = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=cke_mentions&marker='.$sMentionMarker.'&needle={encodedQuery}'; $sMentionItemUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=details&class='.$sMentionClass.'&id={id}'; $sMentionItemPictureTemplate = (empty(MetaModel::GetImageAttributeCode($sMentionClass))) ? '' : <<{$sMentionItemPictureTemplate}{friendlyname} HTML; $sMentionOutputTemplate = <<{$sMentionChar}{friendlyname} +{$sMentionMarker}{friendlyname} HTML; $aDefaultConf['mentions'][] = [ 'feed' => $sMentionEndpoint, - 'marker' => $sMentionChar, + 'marker' => $sMentionMarker, 'minChars' => MetaModel::GetConfig()->Get('min_autocomplete_chars'), 'itemTemplate' => $sMentionItemTemplate, 'outputTemplate' => $sMentionOutputTemplate, diff --git a/core/config.class.inc.php b/core/config.class.inc.php index 98625aff5..c327d7b40 100644 --- a/core/config.class.inc.php +++ b/core/config.class.inc.php @@ -1287,9 +1287,9 @@ class Config ], 'mentions.allowed_classes' => [ 'type' => 'array', - 'description' => 'Classes which can be mentioned through the autocomplete in the caselogs. Key of the array must be a single character that will trigger the autocomplete (eg. "@" => "Person")', + 'description' => 'Classes which can be mentioned through the autocomplete in the caselogs. Key of the array must be a single character that will trigger the autocomplete, value can be either a DM class or a valid OQL (eg. "@" => "Person", "?" => "SELECT FAQ WHERE status = \'published\')', 'default' => [ - '@' => 'Person', + '@' => 'SELECT Person WHERE status = \'active\'', ], 'value' => false, 'source_of_value' => '', diff --git a/pages/ajax.render.php b/pages/ajax.render.php index 257dcffe3..587b193f4 100644 --- a/pages/ajax.render.php +++ b/pages/ajax.render.php @@ -2677,19 +2677,38 @@ EOF // TODO 3.0.0: Move this to new ajax render controller? case 'cke_mentions': $oPage->SetContentType('application/json'); - $sTargetClass = utils::ReadParam('target_class', '', false, 'class'); + $sMarker = utils::ReadParam('marker', '', false, 'raw_data'); $sNeedle = utils::ReadParam('needle', '', false, 'raw_data'); // Check parameters - if($sTargetClass === '') { - throw new Exception('Invalid parameters, target_class must be specified.'); + if($sMarker === '') { + throw new Exception('Invalid parameters, marker must be specified.'); + } + + $aMentionsAllowedClasses = MetaModel::GetConfig()->Get('mentions.allowed_classes'); + if (isset($aMentionsAllowedClasses[$sMarker]) === false) { + throw new Exception('Invalid marker "'.$sMarker.'"'); } $aMatches = array(); if ($sNeedle !== '') { - $sObjectImageAttCode = MetaModel::GetImageAttributeCode($sTargetClass); + // Retrieve scope from marker + $sScope = $aMentionsAllowedClasses[$sMarker]; + if (MetaModel::IsValidClass($sScope)) { + $sScope = "SELECT $sScope"; + } + $oSearch = DBSearch::FromOQL($sScope); - $oSearch = DBObjectSearch::FromOQL("SELECT $sTargetClass WHERE friendlyname LIKE :needle"); + $sSearchMainClassName = $oSearch->GetClass(); + $sSearchMainClassAlias = $oSearch->GetClassAlias(); + + $sObjectImageAttCode = MetaModel::GetImageAttributeCode($sSearchMainClassName); + + // Add condition to filter on the friendlyname + $oSearch->AddConditionExpression( + new BinaryExpression(new FieldExpression('friendlyname', $sSearchMainClassAlias), 'LIKE', new VariableExpression('needle')) + ); + //$oSearch = DBObjectSearch::FromOQL("SELECT $sMarker WHERE friendlyname LIKE :needle"); $oSet = new DBObjectSet($oSearch, array(), array('needle' => "%$sNeedle%")); $oSet->OptimizeColumnLoad(array($oSearch->GetClassAlias() => array())); $oSet->SetLimit(MetaModel::GetConfig()->Get('max_autocomplete_results')); @@ -2712,7 +2731,7 @@ EOF /** @var \ormDocument $oImage */ $oImage = $oObject->Get($sObjectImageAttCode); if (!$oImage->IsEmpty()) { - $aMatch['picture_url'] = $oImage->GetDisplayURL($sTargetClass, $iObjectId, $sObjectImageAttCode); + $aMatch['picture_url'] = $oImage->GetDisplayURL($sObjectClass, $iObjectId, $sObjectImageAttCode); } }