array( "Web applications" => "SELECT WebApplication", "Person having an 'A' in their name" => "SELECT Person AS B WHERE B.name LIKE '%A%'", "Servers having a name like dbserver1.demo.com or dbserver023.foo.fr" => "SELECT Server WHERE name REGEXP '^dbserver[0-9]+\\\\..+\\\\.[a-z]{2,3}$'", "Changes planned on new year's day" => "SELECT Change AS ch WHERE ch.start_date >= '2009-12-31' AND ch.end_date <= '2010-01-01'", "IPs in a range" => "SELECT DatacenterDevice AS dev WHERE INET_ATON(dev.managementip) > INET_ATON('10.22.32.224') AND INET_ATON(dev.managementip) < INET_ATON('10.22.32.255')", "Persons below a given root organization" => "SELECT Person AS P JOIN Organization AS Node ON P.org_id = Node.id JOIN Organization AS Root ON Node.parent_id BELOW Root.id WHERE Root.id=1", ), 'Usefull examples' => array( "NW interfaces of equipment in production for customer 'Demo'" => "SELECT PhysicalInterface AS if JOIN DatacenterDevice AS dev ON if.connectableci_id = dev.id WHERE dev.status = 'production' AND dev.organization_name = 'Demo'", "My tickets" => "SELECT Ticket AS t WHERE t.agent_id = :current_contact_id", "People being owner of an active ticket" => "SELECT Person AS p JOIN UserRequest AS u ON u.agent_id = p.id WHERE u.status != 'closed'", "Contracts terminating in the next thirty days" => "SELECT Contract AS c WHERE c.end_date > NOW() AND c.end_date < DATE_ADD(NOW(), INTERVAL 30 DAY)", "Orphan tickets (opened one hour ago, still not assigned)" => "SELECT UserRequest AS u WHERE u.start_date < DATE_SUB(NOW(), INTERVAL 60 MINUTE) AND u.status = 'new'", "Long lasting incidents (duration > 8 hours)" => "SELECT UserRequest AS u WHERE u.close_date > DATE_ADD(u.start_date, INTERVAL 8 HOUR)", ), ); $aDisplayData = array(); $oAppContext = new ApplicationContext(); $sContext = $oAppContext->GetForForm(); foreach ($aExamples as $sTopic => $aQueries) { foreach ($aQueries as $sDescription => $sOql) { $sHighlight = ''; $sDisable = ''; if ($sOql == $sExpression) { // this one is currently being tested, highlight it $sHighlight = "background-color:yellow;"; $sDisable = 'disabled'; // and remember we are testing a query of the list $bUsingExample = true; } $oFormButton = FormUIBlockFactory::MakeStandard(); $oFormButton->AddSubBlock(InputUIBlockFactory::MakeForHidden("expression", $sOql)); $oButton = ButtonUIBlockFactory::MakeForSecondaryAction(Dict::S('UI:Button:Test'), '', '', true); $oButton->SetIsDisabled($sDisable); $oFormButton->AddSubBlock($oButton); $oFormButton->AddSubBlock(new Html($sContext)); //$aDisplayData[$sTopic][] = array( $aDisplayData[Dict::S('UI:RunQuery:QueryExamples')][] = array( 'desc' => "
".utils::EscapeHtml($sDescription)."
", 'oql' => "
".utils::EscapeHtml($sOql)."
", 'go' => BlockRenderer::RenderBlockTemplates($oFormButton), ); } } $aDisplayConfig = array(); $aDisplayConfig['desc'] = array( 'label' => Dict::S('UI:RunQuery:HeaderPurpose'), 'description' => Dict::S('UI:RunQuery:HeaderPurpose+'), ); $aDisplayConfig['oql'] = array( 'label' => Dict::S('UI:RunQuery:HeaderOQLExpression'), 'description' => Dict::S('UI:RunQuery:HeaderOQLExpression+'), ); $aDisplayConfig['go'] = array('label' => '', 'description' => ''); foreach ($aDisplayData as $sTopic => $aQueriesDisplayData) { $bShowOpened = $bUsingExample; $oTopic = DataTableUIBlockFactory::MakeForForm('oqlExample', $aDisplayConfig, $aQueriesDisplayData); $oTopicSection = new CollapsibleSection($sTopic, [$oTopic]); $oTopicSection->SetOpenedByDefault($bShowOpened); $oP->AddUiBlock($oTopicSection); } } $sOperation = utils::ReadParam('operation', 'menu'); $oAppContext = new ApplicationContext(); $oP = new iTopWebPage(Dict::S('UI:RunQuery:Title')); $oP->SetBreadCrumbEntry('ui-tool-runquery', Dict::S('Menu:RunQueriesMenu'), Dict::S('Menu:RunQueriesMenu+'), '', 'fas fa-terminal', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES); // Main program $sExpression = utils::ReadParam('expression', '', false, 'raw_data'); $sEncoding = utils::ReadParam('encoding', 'oql'); ShowExamples($oP, $sExpression); try { if ($sEncoding == 'crypted') { // Translate $sExpression into a oql expression $sClearText = base64_decode($sExpression); echo "FYI: '$sClearText'
\n"; $oFilter = DBObjectSearch::unserialize($sExpression); $sExpression = $oFilter->ToOQL(); } $oFilter = null; $aArgs = array(); $sSyntaxError = null; if (!empty($sExpression)) { try { $oFilter = DBObjectSearch::FromOQL($sExpression); } catch(Exception $e) { if ($e instanceof OqlException) { $sSyntaxError = $e->getHtmlDesc(); } else { $sSyntaxError = $e->getMessage(); } } if ($oFilter) { $aArgs = array(); foreach($oFilter->GetQueryParams() as $sParam => $foo) { $value = utils::ReadParam('arg_'.$sParam, null, true, 'raw_data'); if (!is_null($value)) { $aArgs[$sParam] = $value; } else { $aArgs[$sParam] = ''; } } $oFilter->SetInternalParams($aArgs); $aRealArgs = $aArgs; } } $oQueryForm = new Form(); $oP->AddUiBlock($oQueryForm); $oHiddenParams = new Html($oAppContext->GetForForm()); $oQueryForm->AddSubBlock($oHiddenParams); //--- Query textarea $oQueryForm->AddSubBlock(TitleUIBlockFactory::MakeNeutral(Dict::S('UI:RunQuery:ExpressionToEvaluate'), 2)); $oQueryTextArea = new TextArea('expression', utils::EscapeHtml($sExpression), 'expression', 120, 8); $oQueryTextArea->AddCSSClass('ibo-queryoql'); $oQueryForm->AddSubBlock($oQueryTextArea); $oP->add_linked_script(utils::GetAbsoluteUrlAppRoot()."/js/jquery.hotkeys.js"); $oP->add_ready_script(<< 0) { //--- Query arguments $oQueryArgsContainer = PanelUIBlockFactory::MakeForInformation('Query arguments') ->SetCSSClasses(['wizContainer']); $oQueryForm->AddSubBlock($oQueryArgsContainer); foreach ($aArgs as $sParam => $sValue) { $oArgInput = InputUIBlockFactory::MakeForInputWithLabel( $sParam, 'arg_'.$sParam, $sValue ); $oQueryArgsContainer->AddSubBlock($oArgInput); } } $oQuerySubmit = ButtonUIBlockFactory::MakeForPrimaryAction( Dict::S('UI:Button:Evaluate'), null, null, true )->SetTooltip(Dict::S('UI:Button:Evaluate:Title')); $oToolbarButtons = ToolbarUIBlockFactory::MakeStandard(null); $oToolbarButtons->AddCSSClass('ibo-toolbar--button'); $oToolbarButtons->AddCSSClass('mb-5'); $oQueryForm->AddSubBlock($oToolbarButtons); $oToolbarButtons->AddSubBlock($oQuerySubmit); if ($oFilter) { //--- Query filter $oP->AddSubBlock(TitleUIBlockFactory::MakeNeutral(Dict::S('UI:RunQuery:QueryResults'), 2)); $oResultBlock = new DisplayBlock($oFilter, 'list', false); $oResultBlock->Display($oP, 'runquery'); // Breadcrumb //$iCount = $oResultBlock->GetDisplayedCount(); $sPageId = "ui-search-".$oFilter->GetClass(); $sLabel = MetaModel::GetName($oFilter->GetClass()); $aArgs = array(); foreach (array_merge($_POST, $_GET) as $sKey => $value) { if (is_array($value)) { $aItems = array(); foreach ($value as $sItemKey => $sItemValue) { $aArgs[] = $sKey.'['.$sItemKey.']='.urlencode($sItemValue); } } else { $aArgs[] = $sKey.'='.urlencode($value); } } $sUrl = utils::GetAbsoluteUrlAppRoot().'pages/run_query.php?'.implode('&', $aArgs); $oP->SetBreadCrumbEntry($sPageId, $sLabel, $oFilter->ToOQL(true), $sUrl, 'fas fa-terminal', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES); //--- More info $aMoreInfoBlocks = []; $oDevelopedQuerySet = new FieldSet(Dict::S('UI:RunQuery:DevelopedQuery')); $oDevelopedQuerySet->AddSubBlock(UIContentBlockUIBlockFactory::MakeForCode(utils::EscapeHtml($oFilter->ToOQL()))); $aMoreInfoBlocks[] = $oDevelopedQuerySet; $oSerializedQuerySet = new FieldSet(Dict::S('UI:RunQuery:SerializedFilter')); $oSerializedQuerySet->AddSubBlock(UIContentBlockUIBlockFactory::MakeForCode(utils::EscapeHtml($oFilter->serialize()))); $aMoreInfoBlocks[] = $oSerializedQuerySet; $aModifierProperties = MetaModel::MakeModifierProperties($oFilter); // Avoid adding all the fields for counts or "group by" requests $aCountAttToLoad = array(); $sMainClass = null; foreach ($oFilter->GetSelectedClasses() as $sClassAlias => $sClass) { $aCountAttToLoad[$sClassAlias] = array(); if (empty($sMainClass)) { $sMainClass = $sClass; } } $aOrderBy = MetaModel::GetOrderByDefault($sMainClass); if (($oFilter instanceof DBObjectSearch) && !MetaModel::GetConfig()->Get('use_legacy_dbsearch')) { // OQL Developed for Count $oSQLObjectQueryBuilder = new SQLObjectQueryBuilder($oFilter); $oBuild = new QueryBuilderContext($oFilter, $aModifierProperties, null, null, null, $aCountAttToLoad); $oCountDevelopedQuerySet = new FieldSet(Dict::S('UI:RunQuery:DevelopedOQLCount')); $oCountDevelopedQuerySet->AddSubBlock(UIContentBlockUIBlockFactory::MakeForCode($oSQLObjectQueryBuilder->DebugOQLClassTree($oBuild))); $aMoreInfoBlocks[] = $oCountDevelopedQuerySet; } // SQL Count $sSQL = $oFilter->MakeSelectQuery(array(), $aRealArgs, $aCountAttToLoad, null, 0, 0, true); $oCountResultQuerySet = new FieldSet(Dict::S('UI:RunQuery:ResultSQLCount')); $oCountResultQuerySet->AddSubBlock(UIContentBlockUIBlockFactory::MakeForCode($sSQL)); $aMoreInfoBlocks[] = $oCountResultQuerySet; if (($oFilter instanceof DBObjectSearch) && !MetaModel::GetConfig()->Get('use_legacy_dbsearch')) { // OQL Developed $oSQLObjectQueryBuilder = new SQLObjectQueryBuilder($oFilter); $oBuild = new QueryBuilderContext($oFilter, $aModifierProperties); $oOqlDevelopedQuerySet = new FieldSet(Dict::S('UI:RunQuery:DevelopedOQL')); $oOqlDevelopedQuerySet->AddSubBlock(UIContentBlockUIBlockFactory::MakeForCode($oSQLObjectQueryBuilder->DebugOQLClassTree($oBuild))); $aMoreInfoBlocks[] = $oOqlDevelopedQuerySet; } // SQL $sSQL = $oFilter->MakeSelectQuery($aOrderBy, $aRealArgs, null, null, 0, 0, false); $oSqlQuerySet = new FieldSet(Dict::S('UI:RunQuery:ResultSQL')); $oSqlQuerySet->AddSubBlock(UIContentBlockUIBlockFactory::MakeForCode($sSQL)); $aMoreInfoBlocks[] = $oSqlQuerySet; $oMoreInfoSection = new CollapsibleSection(Dict::S('UI:RunQuery:MoreInfo'), $aMoreInfoBlocks); $oMoreInfoSection->EnableSaveCollapsibleState('run_query__more-info'); $oP->AddUiBlock($oMoreInfoSection); } elseif ($sSyntaxError) { $oSyntaxErrorPanel = PanelUIBlockFactory::MakeForFailure(Dict::S('UI:RunQuery:Error')); $oP->AddUiBlock($oSyntaxErrorPanel); if ($e instanceof OqlException) { $sWrongWord = $e->GetWrongWord(); $aSuggestedWords = $e->GetSuggestions(); if (is_array($aSuggestedWords) && count($aSuggestedWords) > 0) { $sSuggestedWord = OqlException::FindClosestString($sWrongWord, $aSuggestedWords); if (strlen($sSuggestedWord) > 0) { $sSyntaxErrorText = $e->GetIssue().'
'.$sWrongWord.''; $sBefore = substr($sExpression, 0, $e->GetColumn()); $sAfter = substr($sExpression, $e->GetColumn() + strlen($sWrongWord)); $sFixedExpression = $sBefore.$sSuggestedWord.$sAfter; $sFixedExpressionHtml = $sBefore.''.$sSuggestedWord.''.$sAfter; $sSyntaxErrorText .= "

Suggesting: $sFixedExpressionHtml

"; $oSyntaxErrorPanel->AddSubBlock(new Html($sSyntaxErrorText)); $sEscapedExpression = utils::EscapeHtml(addslashes($sFixedExpression)); $oUseSuggestedQueryButton = ButtonUIBlockFactory::MakeForDestructiveAction('Use this query'); $oUseSuggestedQueryButton->SetOnClickJsCode(<<AddSubBlock($oUseSuggestedQueryButton); } else { $oSyntaxErrorPanel->AddSubBlock(HtmlFactory::MakeParagraph($e->getHtmlDesc())); } } else { $oSyntaxErrorPanel->AddSubBlock(HtmlFactory::MakeParagraph($e->getHtmlDesc())); } } else { $oSyntaxErrorPanel->AddSubBlock(HtmlFactory::MakeParagraph($e->getMessage())); } } } catch (Exception $e) { $oErrorAlert = AlertUIBlockFactory::MakeForFailure( Dict::Format('UI:RunQuery:Error', $e->getMessage()), '
'.$e->getTraceAsString().'
' ); $oErrorAlert->SetOpenedByDefault(false); $oP->AddUiBlock($oErrorAlert); } $oP->output();