* * @since 3.0.0 */ class UnauthenticatedWebPage extends NiceWebPage { const DEFAULT_PAGE_TEMPLATE_REL_PATH = 'pages/backoffice/unauthenticatedwebpage/layout'; private $sContent; private $sPanelTitle; private $sPanelIcon; // TODO 3.0 Find a clever way to allow theme customization for unauthenticated webpages private $sCustomThemeUrl; /** @since 3.2.0 */ protected string $sPortalBaseFolderRelPath; /** @since 3.2.0 */ protected string $sPortalSourcesFolderRelPath; /** @since 3.2.0 */ protected string $sPortalPublicFolderRelPath; /** @since 3.2.0 */ protected string $sPortalBaseFolderAbsPath; /** @since 3.2.0 */ protected string $sPortalSourcesFolderAbsPath; /** @since 3.2.0 */ protected string $sPortalPublicFolderAbsPath; /** @since 3.2.0 */ protected string $sPortalPublicFolderAbsUrl; /** * @inheritDoc * @throws \Exception */ public function __construct($s_title, $bPrintable = false) { $this->Init(); $oKpi = new ExecutionKPI(); parent::__construct($s_title, $bPrintable); $this->sContent = ''; $this->sPanelTitle = ''; $this->sPanelIcon = Branding::GetLoginLogoAbsoluteUrl(); $this->SetContentType('text/html'); // - bootstrap $this->add_linked_script(UAWP_PORTAL_PUBLIC_FOLDER_ABSOLUTE_URL . 'lib/bootstrap/js/bootstrap.min.js'); // Note: Since 2.6.0 moment was moved from portal to iTop core $sMomentURL = utils::GetAbsoluteUrlAppRoot().'/js/moment-with-locales.min.js'; $this->add_linked_script($sMomentURL); $this->add_linked_script(UAWP_PORTAL_PUBLIC_FOLDER_ABSOLUTE_URL . 'lib/bootstrap-datetimepicker/js/bootstrap-datetimepicker.min.js'); // CSS files $this->add_linked_stylesheet(UAWP_PORTAL_PUBLIC_FOLDER_ABSOLUTE_URL . 'lib/bootstrap/css/bootstrap.min.css'); $this->add_saas(UAWP_PORTAL_PUBLIC_FOLDER_RELATIVE_PATH . 'css/bootstrap-theme-combodo.scss'); $this->add_linked_stylesheet(UAWP_PORTAL_PUBLIC_FOLDER_ABSOLUTE_URL . 'lib/bootstrap-datetimepicker/css/bootstrap-datetimepicker.css'); // Default theme $this->add_saas('css/unauthenticated.scss'); $oKpi->ComputeStats(get_class($this).' creation', $s_title); } /** * Init. * * @return void * @throws \Exception */ private function Init(): void { $this->sPortalBaseFolderRelPath = 'env-' . utils::GetCurrentEnvironment() . '/itop-portal-base/portal/'; $this->sPortalSourcesFolderRelPath = $this->sPortalBaseFolderRelPath . 'src/'; $this->sPortalPublicFolderRelPath = $this->sPortalBaseFolderRelPath . 'public/'; $this->sPortalBaseFolderAbsPath = APPROOT . $this->sPortalBaseFolderRelPath; $this->sPortalSourcesFolderAbsPath = APPROOT . $this->sPortalSourcesFolderRelPath; $this->sPortalPublicFolderAbsPath = APPROOT . $this->sPortalPublicFolderRelPath; /** @noinspection PhpUnhandledExceptionInspection */ $this->sPortalPublicFolderAbsUrl = utils::GetAbsoluteUrlModulesRoot().'/itop-portal-base/portal/public/'; // Constants to be used in the UnauthenticatedWebPage if(!defined('UAWP_PORTAL_PUBLIC_FOLDER_ABSOLUTE_URL')) { define('UAWP_PORTAL_PUBLIC_FOLDER_ABSOLUTE_URL', $this->sPortalPublicFolderAbsUrl); } if(!defined('UAWP_PORTAL_PUBLIC_FOLDER_RELATIVE_PATH')) { define('UAWP_PORTAL_PUBLIC_FOLDER_RELATIVE_PATH', $this->sPortalPublicFolderRelPath); } } /** * @inheritdoc */ public function add($sHtml) { $this->sContent .= $sHtml; } /** * @inheritdoc */ public function output() { $oKpi = new ExecutionKPI(); // Send headers foreach ($this->a_headers as $sHeader) { header($sHeader); } $s_captured_output = $this->ob_get_clean_safe(); $aData = []; // Prepare internal parts (js files, css files, js snippets, css snippets, ...) // - Generate necessary dict. files if ($this->bAddJSDict) { $this->output_dict_entries(); } $aData['oLayout'] = $this->oContentLayout; $aData['aDeferredBlocks'] = $this->GetDeferredBlocks($this->oContentLayout); ConsoleBlockRenderer::AddCssJsToPage($this, $this->oContentLayout); // Base structure of data to pass to the TWIG template $aData['aPage'] = [ 'sAbsoluteUrlAppRoot' => addslashes(utils::GetAbsoluteUrlAppRoot()), 'sTitle' => $this->s_title, 'aMetadata' => [ 'sCharset' => static::PAGES_CHARSET, 'sLang' => $this->GetLanguageForMetadata(), ], 'aCssFiles' => $this->a_linked_stylesheets, 'aCssInline' => $this->a_styles, 'aJsInlineEarly' => $this->a_early_scripts, 'aJsFiles' => $this->a_linked_scripts, 'aJsInlineLive' => $this->a_scripts, 'aJsInlineOnDomReady' => $this->GetReadyScripts(), 'aJsInlineOnInit' => $this->a_init_scripts, // TODO 3.0.0: TEMP, used while developing, remove it. 'sCapturedOutput' => utils::FilterXSS($s_captured_output), 'sDeferredContent' => utils::FilterXSS($this->s_deferred_content), 'sContent' => $this->sContent, 'sPanelIcon' => $this->sPanelIcon, 'sPanelTitle' => $this->sPanelTitle ]; $aData['aBlockParams'] = $this->GetBlockParams(); if ($this->a_base['href'] != '') { $aData['aPage']['aMetadata']['sBaseUrl'] = $this->a_base['href']; } if ($this->a_base['target'] != '') { $aData['aPage']['aMetadata']['sBaseTarget'] = $this->a_base['target']; } // Favicon $aData['aPage']['sFaviconUrl'] = $this->GetFaviconAbsoluteUrl(); $oTwigEnv = TwigHelper::GetTwigEnvironment(BlockRenderer::TWIG_BASE_PATH, BlockRenderer::TWIG_ADDITIONAL_PATHS); // Render final TWIG into global HTML $sHtml = TwigHelper::RenderTemplate($oTwigEnv, $aData, $this->GetTemplateRelPath()); $oKpi->ComputeAndReport(get_class($this).' output'); echo $sHtml; $oKpi->ComputeAndReport('Echoing ('.round(strlen($sHtml) / 1024).' Kb)'); ExecutionKPI::ReportStats(); } /** * Displays a success message. * * @param string $sMessage * * @throws Exception */ public function DisplaySuccessMessage($sMessage) { $this->Display('