From 1394bc221d3681da578ef6884139c8c63e22b2db Mon Sep 17 00:00:00 2001
From: Anne-Catherine <57360138+accognet@users.noreply.github.com>
Date: Wed, 28 Feb 2024 09:59:11 +0100
Subject: [PATCH] =?UTF-8?q?N=C2=B03363=20-=20Add=20favicon=20in=20branding?=
=?UTF-8?q?=20(#522)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
application/loginwebpage.class.inc.php | 11 ++-
.../PortalXmlConfiguration/Basic.php | 38 +++++++---
.../portal/templates/layout.html.twig | 2 +-
setup/compiler.class.inc.php | 17 +++--
setup/itopdesignformat.class.inc.php | 9 ++-
sources/Application/Branding.php | 69 +++++++++++++++++--
.../WebPage/UnauthenticatedWebPage.php | 11 ++-
sources/Application/WebPage/WebPage.php | 13 ++--
.../Convert-samples/3.1_to_3.2.expected.xml | 3 +
.../Convert-samples/3.1_to_3.2.input.xml | 3 +
.../Convert-samples/3.2_to_3.1.expected.xml | 4 ++
.../Convert-samples/3.2_to_3.1.input.xml | 14 ++++
.../iTopDesignFormat/iTopDesignFormatTest.php | 2 +
13 files changed, 161 insertions(+), 35 deletions(-)
create mode 100644 tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.1_to_3.2.expected.xml
create mode 100644 tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.1_to_3.2.input.xml
create mode 100644 tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.2_to_3.1.expected.xml
create mode 100644 tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.2_to_3.1.input.xml
diff --git a/application/loginwebpage.class.inc.php b/application/loginwebpage.class.inc.php
index a7ecd12fb..5c5cb6eaf 100644
--- a/application/loginwebpage.class.inc.php
+++ b/application/loginwebpage.class.inc.php
@@ -82,7 +82,7 @@ class LoginWebPage extends NiceWebPage
}
protected static $m_sLoginFailedMessage = '';
-
+
public function __construct($sTitle = null)
{
if ($sTitle === null) {
@@ -101,6 +101,15 @@ class LoginWebPage extends NiceWebPage
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/all.min.css');
}
+ /**
+ * @inheritDoc
+ * @since 3.2.0
+ */
+ protected function GetFaviconAbsoluteUrl()
+ {
+ return Branding::GetLoginFavIconAbsoluteUrl();
+ }
+
public static function SetLoginFailedMessage($sMessage)
{
self::$m_sLoginFailedMessage = $sMessage;
diff --git a/datamodels/2.x/itop-portal-base/portal/src/DependencyInjection/SilexCompatBootstrap/PortalXmlConfiguration/Basic.php b/datamodels/2.x/itop-portal-base/portal/src/DependencyInjection/SilexCompatBootstrap/PortalXmlConfiguration/Basic.php
index 5a6d12527..fc9b27604 100644
--- a/datamodels/2.x/itop-portal-base/portal/src/DependencyInjection/SilexCompatBootstrap/PortalXmlConfiguration/Basic.php
+++ b/datamodels/2.x/itop-portal-base/portal/src/DependencyInjection/SilexCompatBootstrap/PortalXmlConfiguration/Basic.php
@@ -52,6 +52,8 @@ class Basic extends AbstractConfiguration
$aPortalConf = $this->ParseGlobalProperties($aPortalConf);
// - Rectifying portal logo url
$aPortalConf = $this->AppendLogoUri($aPortalConf);
+ // - Rectifying portal favicon url
+ $aPortalConf = $this->AppendFavIconUri($aPortalConf);
}
catch (Exception $oException)
{
@@ -71,10 +73,11 @@ class Basic extends AbstractConfiguration
{
$aPortalConf = array(
'properties' => array(
- 'id' => $_ENV['PORTAL_ID'],
- 'name' => 'Page:DefaultTitle',
- 'logo' => Branding::GetPortalLogoAbsoluteUrl(),
- 'themes' => array(
+ 'id' => $_ENV['PORTAL_ID'],
+ 'name' => 'Page:DefaultTitle',
+ 'logo' => Branding::GetPortalLogoAbsoluteUrl(),
+ 'favicon' => Branding::GetPortalFavIconAbsoluteUrl(),
+ 'themes' => array(
'bootstrap' => 'itop-portal-base/portal/public/css/bootstrap-theme-combodo.scss',
'portal' => 'itop-portal-base/portal/public/css/portal.scss',
'others' => array(),
@@ -116,11 +119,8 @@ class Basic extends AbstractConfiguration
case 'name':
case 'urlmaker_class':
case 'triggers_query':
- $aPortalConf['properties'][$oPropertyNode->nodeName] = $oPropertyNode->GetText(
- $aPortalConf['properties'][$oPropertyNode->nodeName]
- );
- break;
case 'logo':
+ case 'favicon':
$aPortalConf['properties'][$oPropertyNode->nodeName] = $oPropertyNode->GetText(
$aPortalConf['properties'][$oPropertyNode->nodeName]
);
@@ -263,8 +263,7 @@ class Basic extends AbstractConfiguration
private function AppendLogoUri(array $aPortalConf)
{
$sLogoUri = $aPortalConf['properties']['logo'];
- if (!preg_match('/^http/', $sLogoUri))
- {
+ if (!preg_match('/^http/', $sLogoUri)) {
// We prefix it with the server base url
$sLogoUri = utils::GetAbsoluteUrlAppRoot().'env-'.utils::GetCurrentEnvironment().'/'.$sLogoUri;
}
@@ -272,4 +271,23 @@ class Basic extends AbstractConfiguration
return $aPortalConf;
}
+
+ /**
+ * @param array $aPortalConf
+ *
+ * @return array
+ * @throws \Exception
+ * @since 3.2.0 N°3363
+ */
+ private function AppendFaviconUri(array $aPortalConf)
+ {
+ $sFaviconUri = $aPortalConf['properties']['favicon'];
+ if (!preg_match('/^http/', $sFaviconUri)) {
+ // We prefix it with the server base url
+ $sFaviconUri = utils::GetAbsoluteUrlAppRoot().'env-'.utils::GetCurrentEnvironment().'/'.$sFaviconUri;
+ }
+ $aPortalConf['properties']['favicon'] = $sFaviconUri;
+
+ return $aPortalConf;
+ }
}
\ No newline at end of file
diff --git a/datamodels/2.x/itop-portal-base/portal/templates/layout.html.twig b/datamodels/2.x/itop-portal-base/portal/templates/layout.html.twig
index afb837ba7..62260ccf8 100644
--- a/datamodels/2.x/itop-portal-base/portal/templates/layout.html.twig
+++ b/datamodels/2.x/itop-portal-base/portal/templates/layout.html.twig
@@ -23,7 +23,7 @@
{% block pPageExtraMetas %}
{% endblock %}
{% block pPageTitle %}{% if sPageTitle is defined and sPageTitle is not null %}{{ sPageTitle }} - {{ constant('ITOP_APPLICATION_SHORT') }}{% else %}{{ 'Page:DefaultTitle'|dict_format(constant('ITOP_APPLICATION_SHORT')) }}{% endif %}{% endblock %}
-
+
{% block pPageStylesheets %}
{# First bootstrap core, lib themes, then bootstrap theme, portal adjustements #}
diff --git a/setup/compiler.class.inc.php b/setup/compiler.class.inc.php
index 1ae74c20f..8d95d519a 100644
--- a/setup/compiler.class.inc.php
+++ b/setup/compiler.class.inc.php
@@ -3652,12 +3652,15 @@ EOF;
$this->CompileFiles($oBrandingNode, $sTempTargetDir.'/branding', $sFinalTargetDir.'/branding', 'branding');
$aDataBranding = [];
- $aLogosToCompile = [
- ['sNodeName' => 'login_logo', 'sTargetFile' => 'login-logo', 'sType' => Branding::ENUM_LOGO_TYPE_LOGIN_LOGO],
- ['sNodeName' => 'main_logo', 'sTargetFile' => 'main-logo-full', 'sType' => Branding::ENUM_LOGO_TYPE_MAIN_LOGO_FULL],
- ['sNodeName' => 'main_logo_compact', 'sTargetFile' => 'main-logo-compact', 'sType' => Branding::ENUM_LOGO_TYPE_MAIN_LOGO_COMPACT],
- ['sNodeName' => 'portal_logo', 'sTargetFile' =>'portal-logo', 'sType' => Branding::ENUM_LOGO_TYPE_PORTAL_LOGO],
- ];
+ $aLogosToCompile = [
+ ['sNodeName' => 'login_logo', 'sTargetFile' => 'login-logo', 'sType' => Branding::ENUM_LOGO_TYPE_LOGIN_LOGO],
+ ['sNodeName' => 'main_logo', 'sTargetFile' => 'main-logo-full', 'sType' => Branding::ENUM_LOGO_TYPE_MAIN_LOGO_FULL],
+ ['sNodeName' => 'main_logo_compact', 'sTargetFile' => 'main-logo-compact', 'sType' => Branding::ENUM_LOGO_TYPE_MAIN_LOGO_COMPACT],
+ ['sNodeName' => 'portal_logo', 'sTargetFile' => 'portal-logo', 'sType' => Branding::ENUM_LOGO_TYPE_PORTAL_LOGO],
+ ['sNodeName' => 'login_favicon', 'sTargetFile' => 'login_favicon', 'sType' => Branding::ENUM_LOGO_TYPE_LOGIN_FAVICON],
+ ['sNodeName' => 'main_favicon', 'sTargetFile' => 'main_favicon', 'sType' => Branding::ENUM_LOGO_TYPE_MAIN_FAVICON],
+ ['sNodeName' => 'portal_favicon', 'sTargetFile' => 'portal_favicon', 'sType' => Branding::ENUM_LOGO_TYPE_PORTAL_FAVICON],
+ ];
foreach ($aLogosToCompile as $aLogo) {
$sLogo = $this->CompileLogo($oBrandingNode, $sTempTargetDir, $sFinalTargetDir, $aLogo['sNodeName'], $aLogo['sTargetFile']);
if ($sLogo != null) {
@@ -3677,7 +3680,7 @@ EOF;
{
SetupUtils::rrmdir($sTempTargetDir.'/branding/images');
}
-
+
// Compile themes
$this->CompileThemes($oBrandingNode, $sTempTargetDir);
}
diff --git a/setup/itopdesignformat.class.inc.php b/setup/itopdesignformat.class.inc.php
index 5f38ea7dd..1614a6a1c 100644
--- a/setup/itopdesignformat.class.inc.php
+++ b/setup/itopdesignformat.class.inc.php
@@ -910,8 +910,8 @@ class iTopDesignFormat
$oNodeList = $oXPath->query('/itop_design/branding/themes/theme[@id="test-red"]/variables/variable[@id="backoffice-environment-banner-background-color"]');
foreach ($oNodeList as $oNode) {
$oNode->setAttribute('id', 'ibo-page-banner--background-color');
- }
-
+ }
+
$oNodeList = $oXPath->query( '/itop_design/branding/themes/theme[@id="test-red"]/variables/variable[@id="backoffice-environment-banner-text-color"]');
foreach ($oNodeList as $oNode) {
$oNode->setAttribute('id', 'ibo-page-banner--text-color');
@@ -1108,7 +1108,10 @@ class iTopDesignFormat
*/
protected function From32To31($oFactory)
{
- // Nothing for now...
+ // N°3363 - Add favicon in branding
+ $this->RemoveNodeFromXPath('/itop_design/branding/main_favicon');
+ $this->RemoveNodeFromXPath('/itop_design/branding/portal_favicon');
+ $this->RemoveNodeFromXPath('/itop_design/branding/login_favicon');
}
/**
diff --git a/sources/Application/Branding.php b/sources/Application/Branding.php
index 609a873c3..b9c9cf061 100644
--- a/sources/Application/Branding.php
+++ b/sources/Application/Branding.php
@@ -19,6 +19,7 @@
namespace Combodo\iTop\Application;
+use MetaModel;
use utils;
/**
@@ -38,27 +39,52 @@ class Branding
public const ENUM_LOGO_TYPE_PORTAL_LOGO = 'portal_logo';
/** @var string Logo used in the login pages */
public const ENUM_LOGO_TYPE_LOGIN_LOGO = 'login_logo';
+ /**
+ * @var string Logo used in most pages (backoffice, ...)
+ * @since 3.2.0 N°3363
+ */
+ public const ENUM_LOGO_TYPE_MAIN_FAVICON = 'main_favicon';
+ /**
+ * @var string Logo used in the end-users portals
+ * @since 3.2.0 N°3363
+ */
+ public const ENUM_LOGO_TYPE_PORTAL_FAVICON = 'portal_favicon';
+ /**
+ * @var string Logo used in the login page
+ * @since 3.2.0 N°3363
+ */
+ public const ENUM_LOGO_TYPE_LOGIN_FAVICON = 'login_favicon';
/** @var string Default logo */
public const DEFAULT_LOGO_TYPE = self::ENUM_LOGO_TYPE_MAIN_LOGO_FULL;
/** @var \string[][] Relative paths to the logos from the current environment folder */
public static $aLogoPaths = [
- self::ENUM_LOGO_TYPE_MAIN_LOGO_FULL => [
+ self::ENUM_LOGO_TYPE_MAIN_LOGO_FULL => [
'default' => 'images/itop-logo.png',
],
self::ENUM_LOGO_TYPE_MAIN_LOGO_COMPACT => [
'default' => 'images/itop-logo-square.png',
],
- self::ENUM_LOGO_TYPE_PORTAL_LOGO => [
+ self::ENUM_LOGO_TYPE_PORTAL_LOGO => [
'default' => 'images/logo-itop-dark-bg.svg',
],
- self::ENUM_LOGO_TYPE_LOGIN_LOGO => [
+ self::ENUM_LOGO_TYPE_LOGIN_LOGO => [
'default' => 'images/itop-logo-external.png',
],
+ self::ENUM_LOGO_TYPE_MAIN_FAVICON => [
+ 'default' => 'images/favicon.ico',
+ ],
+ self::ENUM_LOGO_TYPE_PORTAL_FAVICON => [
+ 'default' => 'images/favicon.ico',
+ ],
+ self::ENUM_LOGO_TYPE_LOGIN_FAVICON => [
+ 'default' => 'images/favicon.ico',
+ ],
];
/**
* Return url or path of logo defined by $sType
+ *
* @param string $sType
* @param string $sAppPath
* @param ?string $sModulePath
@@ -73,7 +99,7 @@ class Branding
if (isset($aThemeParameters[$sType])) {
$sCustomLogoPath = $aThemeParameters[$sType];
if (file_exists($sWorkingPath.$sCustomLogoPath)) {
- return ($sModulePath??$sAppPath).$sCustomLogoPath;
+ return ($sModulePath ?? $sAppPath).$sCustomLogoPath;
}
}
@@ -154,4 +180,39 @@ class Branding
return static::GetLogoAbsoluteUrl(static::ENUM_LOGO_TYPE_LOGIN_LOGO);
}
+ /**
+ * Return the absolute URL for thefavicon
+ *
+ * @return string
+ * @throws \Exception
+ * @since 3.2.0 N°3363
+ */
+ public static function GetMainFavIconAbsoluteUrl(): string
+ {
+ return static::GetLogoAbsoluteUrl(static::ENUM_LOGO_TYPE_MAIN_FAVICON);
+ }
+
+ /**
+ * Return the absolute URL for thefavicon
+ *
+ * @return string
+ * @throws \Exception
+ * @since 3.2.0 N°3363
+ */
+ public static function GetPortalFavIconAbsoluteUrl(): string
+ {
+ return static::GetLogoAbsoluteUrl(static::ENUM_LOGO_TYPE_PORTAL_FAVICON);
+ }
+
+ /**
+ * Return the absolute URL for thefavicon
+ *
+ * @return string
+ * @throws \Exception
+ * @since 3.2.0 N°3363
+ */
+ public static function GetLoginFavIconAbsoluteUrl(): string
+ {
+ return static::GetLogoAbsoluteUrl(static::ENUM_LOGO_TYPE_LOGIN_FAVICON);
+ }
}
\ No newline at end of file
diff --git a/sources/Application/WebPage/UnauthenticatedWebPage.php b/sources/Application/WebPage/UnauthenticatedWebPage.php
index 7f101a1a2..d81b0df7a 100644
--- a/sources/Application/WebPage/UnauthenticatedWebPage.php
+++ b/sources/Application/WebPage/UnauthenticatedWebPage.php
@@ -41,7 +41,7 @@ class UnauthenticatedWebPage extends NiceWebPage
private $sContent;
private $sPanelTitle;
private $sPanelIcon;
-
+
// TODO 3.0 Find a clever way to allow theme customization for unauthenticated webpages
private $sCustomThemeUrl;
@@ -288,4 +288,13 @@ class UnauthenticatedWebPage extends NiceWebPage
$this->add_linked_stylesheet($this->sCustomThemeUrl);
}
}
+
+ /**
+ * @inheritDoc
+ * @since 3.2.0
+ */
+ protected function GetFaviconAbsoluteUrl()
+ {
+ return Branding::GetLoginFavIconAbsoluteUrl();
+ }
}
\ No newline at end of file
diff --git a/sources/Application/WebPage/WebPage.php b/sources/Application/WebPage/WebPage.php
index 281f23ac0..ee9ae8e82 100644
--- a/sources/Application/WebPage/WebPage.php
+++ b/sources/Application/WebPage/WebPage.php
@@ -6,6 +6,7 @@
namespace Combodo\iTop\Application\WebPage;
+use Combodo\iTop\Application\Branding;
use Combodo\iTop\Application\Helper\Session;
use Combodo\iTop\Application\Helper\WebResourcesHelper;
use Combodo\iTop\Application\TwigBase\Twig\TwigHelper;
@@ -1761,17 +1762,13 @@ EOD
}
/**
- * Return the absolute URL for the favicon
- *
- * @return string
+ * @return string Absolute URL for the favicon
* @throws \Exception
* @since 3.0.0
*/
protected function GetFaviconAbsoluteUrl()
{
- // TODO 3.0.0: Make it a property so it can be changed programmatically
- // TODO 3.0.0: How to set both dark/light mode favicons
- return utils::GetAbsoluteUrlAppRoot().'images/favicon.ico';
+ return Branding::GetMainFavIconAbsoluteUrl();
}
/**
@@ -1838,7 +1835,7 @@ EOD
/**
* @return bool
- *
+ *
* @since 3.2.0
*/
public function GetAddJSDict(): bool
@@ -1850,7 +1847,7 @@ EOD
* @param bool $bAddJSDict
*
* @return $this
- *
+ *
* @since 3.2.0
*/
public function SetAddJSDict(bool $bAddJSDict)
diff --git a/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.1_to_3.2.expected.xml b/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.1_to_3.2.expected.xml
new file mode 100644
index 000000000..da9755d33
--- /dev/null
+++ b/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.1_to_3.2.expected.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.1_to_3.2.input.xml b/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.1_to_3.2.input.xml
new file mode 100644
index 000000000..bcd33d37d
--- /dev/null
+++ b/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.1_to_3.2.input.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.2_to_3.1.expected.xml b/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.2_to_3.1.expected.xml
new file mode 100644
index 000000000..24015d8fa
--- /dev/null
+++ b/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.2_to_3.1.expected.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.2_to_3.1.input.xml b/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.2_to_3.1.input.xml
new file mode 100644
index 000000000..f36793519
--- /dev/null
+++ b/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/Convert-samples/3.2_to_3.1.input.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/iTopDesignFormatTest.php b/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/iTopDesignFormatTest.php
index a68ab04ea..7f8fe2bbe 100644
--- a/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/iTopDesignFormatTest.php
+++ b/tests/php-unit-tests/unitary-tests/setup/iTopDesignFormat/iTopDesignFormatTest.php
@@ -143,6 +143,8 @@ class iTopDesignFormatTest extends ItopTestCase
'3.0 to 1.7' => ['sXmlFileName' => '3.0_to_1.7'],
'3.0 to 3.1' => ['sXmlFileName' => '3.0_to_3.1'],
'3.1 to 3.0' => ['sXmlFileName' => '3.1_to_3.0'],
+ '3.1 to 3.2' => ['sXmlFileName' => '3.1_to_3.2'],
+ '3.2 to 3.1' => ['sXmlFileName' => '3.2_to_3.1'],
'Bug_4569' => ['sXmlFileName' => 'Bug_4569'],
];
}