diff --git a/css/unauthenticated.css b/css/unauthenticated.css new file mode 100644 index 000000000..35fa3b49d --- /dev/null +++ b/css/unauthenticated.css @@ -0,0 +1,47 @@ +/*! + * Copyright (C) 2013-2020 Combodo SARL + * + * This file is part of iTop. + * + * iTop is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * iTop is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + */ +body { + display: block; +} +/* Landing page */ +#uwp-main-container { + margin-top: 40px; +} +#uwp-main-container #uwp-logo, #uwp-main-container #uwp-title { + vertical-align: middle; +} +#uwp-main-container #uwp-title { + margin-left: 25px; + font-size: 20px; + font-weight: bold; +} +#uwp-main-container #uwp-description { + margin-bottom: 25px; +} +#uwp-main-container .uwp-text-hint--icon { + font-size: 12px; + margin-left: 5px; + color: #939191; +} +#uwp-main-container #uwp-bottom-buttons { + margin-top: 25px; + text-align: right; +} +#uwp-main-container #uwp-bottom-buttons .btn ~ .btn { + margin-left: 8px; +} diff --git a/css/unauthenticated.scss b/css/unauthenticated.scss new file mode 100644 index 000000000..fd5cdffd2 --- /dev/null +++ b/css/unauthenticated.scss @@ -0,0 +1,54 @@ +/*! + * Copyright (C) 2013-2020 Combodo SARL + * + * This file is part of iTop. + * + * iTop is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * iTop is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + */ + + + +body{ + display: block; +} + +/* Landing page */ +#uwp-main-container{ + margin-top: 40px; + + #uwp-logo, + #uwp-title{ + vertical-align: middle; + } + #uwp-title{ + margin-left: 25px; + font-size: 20px; + font-weight: bold; + } + + #uwp-description{ + margin-bottom: 25px; + } + .uwp-text-hint--icon{ + font-size: 12px; + margin-left: 5px; + color: #939191; + } + #uwp-bottom-buttons { + margin-top: 25px; + text-align: right; + .btn ~ .btn{ + margin-left: 8px; + } + } +} \ No newline at end of file diff --git a/lib/composer/ClassLoader.php b/lib/composer/ClassLoader.php index 247294d66..6d0c3f2d0 100644 --- a/lib/composer/ClassLoader.php +++ b/lib/composer/ClassLoader.php @@ -338,7 +338,7 @@ class ClassLoader * Loads the given class or interface. * * @param string $class The name of the class - * @return bool|null True if loaded, null otherwise + * @return true|null True if loaded, null otherwise */ public function loadClass($class) { @@ -347,6 +347,8 @@ class ClassLoader return true; } + + return null; } /** diff --git a/lib/composer/autoload_classmap.php b/lib/composer/autoload_classmap.php index c3fd41f44..70cee8e73 100644 --- a/lib/composer/autoload_classmap.php +++ b/lib/composer/autoload_classmap.php @@ -297,6 +297,7 @@ return array( 'Combodo\\iTop\\Controller\\Base\\Layout\\ActivityPanelController' => $baseDir . '/sources/Controller/Base/Layout/ActivityPanelController.php', 'Combodo\\iTop\\Controller\\PreferencesController' => $baseDir . '/sources/Controller/PreferencesController.php', 'Combodo\\iTop\\Core\\CMDBChange\\CMDBChangeOrigin' => $baseDir . '/sources/Core/CMDBChange/CMDBChangeOrigin.php', + 'Combodo\\iTop\\Core\\MetaModel\\FriendlyNameType' => $baseDir . '/sources/Core/MetaModel/FriendlyNameType.php', 'Combodo\\iTop\\DesignDocument' => $baseDir . '/core/designdocument.class.inc.php', 'Combodo\\iTop\\DesignElement' => $baseDir . '/core/designdocument.class.inc.php', 'Combodo\\iTop\\Form\\Field\\BlobField' => $baseDir . '/sources/Form/Field/BlobField.php', @@ -2318,6 +2319,7 @@ return array( 'URLButtonItem' => $baseDir . '/application/applicationextension.inc.php', 'URLPopupMenuItem' => $baseDir . '/application/applicationextension.inc.php', 'UnaryExpression' => $baseDir . '/core/oql/expression.class.inc.php', + 'UnauthenticatedWebPage' => $baseDir . '/sources/application/WebPage/UnauthenticatedWebPage.php', 'UnknownClassOqlException' => $baseDir . '/core/oql/oqlinterpreter.class.inc.php', 'User' => $baseDir . '/core/userrights.class.inc.php', 'UserDashboard' => $baseDir . '/application/user.dashboard.class.inc.php', diff --git a/lib/composer/autoload_static.php b/lib/composer/autoload_static.php index 9a8a2d2b4..1c35fcf85 100644 --- a/lib/composer/autoload_static.php +++ b/lib/composer/autoload_static.php @@ -527,6 +527,7 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b 'Combodo\\iTop\\Controller\\Base\\Layout\\ActivityPanelController' => __DIR__ . '/../..' . '/sources/Controller/Base/Layout/ActivityPanelController.php', 'Combodo\\iTop\\Controller\\PreferencesController' => __DIR__ . '/../..' . '/sources/Controller/PreferencesController.php', 'Combodo\\iTop\\Core\\CMDBChange\\CMDBChangeOrigin' => __DIR__ . '/../..' . '/sources/Core/CMDBChange/CMDBChangeOrigin.php', + 'Combodo\\iTop\\Core\\MetaModel\\FriendlyNameType' => __DIR__ . '/../..' . '/sources/Core/MetaModel/FriendlyNameType.php', 'Combodo\\iTop\\DesignDocument' => __DIR__ . '/../..' . '/core/designdocument.class.inc.php', 'Combodo\\iTop\\DesignElement' => __DIR__ . '/../..' . '/core/designdocument.class.inc.php', 'Combodo\\iTop\\Form\\Field\\BlobField' => __DIR__ . '/../..' . '/sources/Form/Field/BlobField.php', @@ -2548,6 +2549,7 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b 'URLButtonItem' => __DIR__ . '/../..' . '/application/applicationextension.inc.php', 'URLPopupMenuItem' => __DIR__ . '/../..' . '/application/applicationextension.inc.php', 'UnaryExpression' => __DIR__ . '/../..' . '/core/oql/expression.class.inc.php', + 'UnauthenticatedWebPage' => __DIR__ . '/../..' . '/sources/application/WebPage/UnauthenticatedWebPage.php', 'UnknownClassOqlException' => __DIR__ . '/../..' . '/core/oql/oqlinterpreter.class.inc.php', 'User' => __DIR__ . '/../..' . '/core/userrights.class.inc.php', 'UserDashboard' => __DIR__ . '/../..' . '/application/user.dashboard.class.inc.php', diff --git a/sources/application/WebPage/UnauthenticatedWebPage.php b/sources/application/WebPage/UnauthenticatedWebPage.php new file mode 100644 index 000000000..6dc4c1166 --- /dev/null +++ b/sources/application/WebPage/UnauthenticatedWebPage.php @@ -0,0 +1,275 @@ + + * + * @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; + /** @var array $aReadyScripts */ + protected $aReadyScripts; + + /** + * @inheritDoc + * @throws \Exception + */ + public function __construct($s_title, $bPrintable = false) + { + parent::__construct($s_title, $bPrintable); + + $this->aReadyScripts = array(); + $this->sContent = ''; + $this->sPanelTitle = ''; + $this->sPanelIcon = utils::GetAbsoluteUrlAppRoot().'images/itop-logo.png'; + if (file_exists(MODULESROOT.'branding/main-logo.png')) + { + $this->sPanelIcon = utils::GetAbsoluteUrlModulesRoot().'branding/main-logo.png'; + } + + $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'); + } + + /** + * @inheritdoc + */ + public function add($sHtml) + { + $this->sContent .= $sHtml; + } + + /** + * @inheritdoc + */ + public function add_ready_script($sScript) + { + $this->aReadyScripts[] = $sScript; + } + + /** + * @inheritdoc + */ + public function output() + { + // 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()); + echo $sHtml; + + } + + /** + * Displays a success message. + * + * @param string $sMessage + * + * @throws \Exception + */ + public function DisplaySuccessMessage($sMessage) + { + $this->Display('