Merge branch 'develop' into feature/faf_event_service

This commit is contained in:
Eric Espie
2022-05-25 10:04:54 +02:00
929 changed files with 65776 additions and 34526 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

3
.gitignore vendored
View File

@@ -45,6 +45,9 @@ test/vendor/*
!/log/index.php
!/log/web.config
# PHPUnit cache file
/test/.phpunit.result.cache
# Jetbrains
/.idea/**

View File

@@ -50,14 +50,24 @@ foreach ($aDeniedButStillPresent as $sDir)
continue;
}
try
{
try {
SetupUtils::rrmdir($sDir);
echo "OK Remove denied test dir: '$sDir'\n";
}
catch (\Exception $e)
{
catch (\Exception $e) {
echo "\nFAILED to remove denied test dir: '$sDir'\n";
}
}
$aAllowedAndDeniedDirs = array_merge(
$oiTopComposer->ListAllowedTestDir(),
$oiTopComposer->ListDeniedTestDir()
);
$aExistingDirs = $oiTopComposer->ListAllTestDir();
$aMissing = array_diff($aExistingDirs, $aAllowedAndDeniedDirs);
if (false === empty($aMissing)) {
echo "Some new tests dirs exists !\n"
.' They must be declared either in the allowed or denied list in '.iTopComposer::class." (see N°2651).\n"
.' List of dirs:'."\n".var_export($aMissing, true);
}

View File

@@ -52,26 +52,26 @@ Here are the branches we use and their meaning :
For example, if no version is currently prepared for shipping we could have:
- `develop` containing future 3.0.0 version
- `develop` containing future 3.1.0 version
- `support/3.0`: 3.0.x maintenance version
- `support/2.7`: 2.7.x maintenance version
- `support/2.6`: 2.6.x maintenance version
- `support/2.5`: 2.5.x maintenance version
In this example, when 3.0.0-beta is shipped that will become:
In this example, when 3.1.0-beta is shipped that will become:
- `develop`: future 3.1.0 version
- `release/3.0.0`: 3.0.0-beta
- `develop`: future 3.2.0 version
- `release/3.1.0`: 3.1.0-beta
- `support/3.0`: 3.0.x maintenance version
- `support/2.7`: 2.7.x maintenance version
- `support/2.6`: 2.6.x maintenance version
- `support/2.5`: 2.5.x maintenance version
And when 3.0.0 final will be out:
And when 3.1.0 final will be out:
- `develop`: future 3.1.0 version
- `support/3.0`: 3.0.x maintenance version (will host developments for 3.0.1)
- `develop`: future 3.2.0 version
- `support/3.1`: 3.1.x maintenance version (will host developments for 3.1.1)
- `support/3.0`: 3.0.x maintenance version
- `support/2.7`: 2.7.x maintenance version
- `support/2.6`: 2.6.x maintenance version
- `support/2.5`: 2.5.x maintenance version
Also note that we have a "micro-version" concept : each of those versions have a very small amount of modifications. They are made from
`support/*` branches as well. For example 2.6.2-1 and 2.6.2-2 were made from the `support/2.6.2` branch.
@@ -133,13 +133,11 @@ When your code is working, please:
* stash as much as possible your commits,
* rebase your branch on our repo last commit,
* create a pull request.
* create a pull request
* mind to check the "[Allow edits from maintainers](https://docs.github.com/en/github-ae@latest/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork)" option !
Detailed procedure to work on fork and create PR is available [in GitHub help pages](https://help.github.com/articles/creating-a-pull-request-from-a-fork/).
You might check the ["Allow edits from maintainers" PR checkbox][allow_edits_checkbox] to ease review.
[allow_edits_checkbox]: https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork#enabling-repository-maintainer-permissions-on-existing-pull-requests
### 🙏 We are thankful

View File

@@ -1,13 +1,11 @@
<p align="center"><a href="https://www.combodo.com/itop-193" target="_blank">
<img src="https://www.combodo.com/logos/logo-itop.svg">
<img src="https://www.combodo.com/logos/logo-itop-baseline.svg" width=350>
</a></p>
# iTop - ITSM & CMDB
iTop stands for *IT Operations Portal*.
It is a complete open source, ITIL, web based service management tool including a fully customizable CMDB, a helpdesk system and a document management tool.
iTop also offers mass import tools and web services to integrate with your IT
iTop stands for IT Operations Portal. It is a complete open source and web based IT service management platform including a fully customizable CMDB, a helpdesk system and a document management tool. It is ITIL compliant and easily customizable and extensible thanks to a high number of adds-on and web services to integrate with your IT.
iTop also offers mass import tools to help you being even more efficient.
## Features
- Fully configurable [Configuration Management (CMDB)][10]

View File

@@ -5,16 +5,20 @@
* @copyright Copyright (C) 2010-2021 Combodo SARL
*/
// cannot notify depreciation for now as this is still MASSIVELY used in iTop core !
// cannot notify depreciation for now as this is still load in autoloader
//DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/AjaxPage.php, now loadable using autoloader');
/**
* Class ajax_page
*
* @deprecated will be removed in 3.1.0 - moved to AjaxPage
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to AjaxPage
*/
class ajax_page extends AjaxPage
{
function __construct($s_title)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('ajax_page is deprecated. Please use AjaxPage instead');
parent::__construct($s_title);
}
}

View File

@@ -1186,7 +1186,7 @@ interface iPageUIBlockExtension
* @api
* @package Extensibility
* @since 2.7.0
* @deprecated since 3.0.0 use AbstractPageUIBlockExtension instead
* @deprecated 3.0.0 use AbstractPageUIBlockExtension instead
*/
abstract class AbstractPageUIExtension implements iPageUIExtension
{
@@ -1404,11 +1404,11 @@ interface iBackofficeDictEntriesPrefixesExtension
/**
* Implement this interface to add content to any enhanced portal page
*
* IMPORTANT! Experimental API, may be removed at anytime, we don't recommend to use it just now!
*
* @api
* @package Extensibility
* @since 2.4.0
*
* @since 2.4.0 interface creation
* @since 2.7.0 change method signatures due to Silex to Symfony migration
*/
interface iPortalUIExtension
{
@@ -1481,7 +1481,11 @@ interface iPortalUIExtension
}
/**
* IMPORTANT! Experimental API, may be removed at anytime, we don't recommend to use it just now!
* Extend this class instead of iPortalUIExtension if you don't need to overload all methods
*
* @api
* @package Extensibility
* @since 2.4.0
*/
abstract class AbstractPortalUIExtension implements iPortalUIExtension
{

View File

@@ -1449,7 +1449,7 @@ HTML
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @deprecated since 3.0.0
* @deprecated 3.0.0
*/
public static function GetDisplayExtendedSet(WebPage $oPage, CMDBObjectSet $oSet, $aExtraParams = array())
{
@@ -3930,7 +3930,7 @@ HTML;
}
elseif ($iFlags & OPT_ATT_SLAVE)
{
$aErrors[$sAttCode] = Dict::Format('UI:AttemptingToSetASlaveAttribute_Name', $oAttDef->GetLabel());
$aErrors[$sAttCode] = Dict::Format('UI:AttemptingToSetASlaveAttribute_Name', $oAttDef->GetLabel(), $sAttCode);
}
else
{
@@ -4516,11 +4516,9 @@ HTML;
*/
protected function SetWarningsAsSessionMessages($sMessageIdPrefix)
{
if (!empty($this->m_aCheckWarnings) && is_array($this->m_aCheckWarnings))
{
if (!empty($this->m_aCheckWarnings) && is_array($this->m_aCheckWarnings)) {
$iMsgNb = 0;
foreach ($this->m_aCheckWarnings as $sWarningMessage)
{
foreach ($this->m_aCheckWarnings as $sWarningMessage) {
$iMsgNb++;
$sMessageId = "$sMessageIdPrefix-$iMsgNb"; // each message must have its own messageId !
$this->SetSessionMessageFromInstance($sMessageId, $sWarningMessage, 'warning', 0);
@@ -4528,12 +4526,6 @@ HTML;
}
}
protected static function BulkUpdateTracked_Internal(DBSearch $oFilter, array $aValues)
{
// Todo - invoke the extension
return parent::BulkUpdateTracked_Internal($oFilter, $aValues);
}
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
{
// Invoke extensions before the deletion (the deletion will do some cleanup and we might loose some information
@@ -5205,7 +5197,7 @@ EOF
} else {
$sStatus = $bResult ? Dict::S('UI:BulkModifyStatusModified') : Dict::S('UI:BulkModifyStatusSkipped');
}
$sChecked = $bResult ? 'checked' : '';
$aRows[] = array(
'object' => $oObj->GetHyperlink(),
'status' => $sStatus,

View File

@@ -789,6 +789,7 @@ class RuntimeDashboard extends Dashboard
/**
* @inheritDoc
* @return bool $bIsNew
* @throws \Exception
*/
public function Save()
@@ -798,6 +799,7 @@ class RuntimeDashboard extends Dashboard
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oUDSearch->AddCondition('menu_code', $this->sId, '=');
$oUDSet = new DBObjectSet($oUDSearch);
$bIsNew = false;
if ($oUDSet->Count() > 0)
{
// Assuming there is at most one couple {user, menu}!
@@ -811,10 +813,12 @@ class RuntimeDashboard extends Dashboard
$oUserDashboard->Set('user_id', UserRights::GetUserId());
$oUserDashboard->Set('menu_code', $this->sId);
$oUserDashboard->Set('contents', $sXml);
$bIsNew = true;
}
utils::PushArchiveMode(false);
$oUserDashboard->DBWrite();
utils::PopArchiveMode();
return $bIsNew;
}
/**

View File

@@ -262,7 +262,7 @@ abstract class Dashlet
}
} catch (OqlException $e) {
$oDashletContainer->AddCSSClass("dashlet-content");
$oDashletContainer->AddHtml('<p>'.$e->GetUserFriendlyDescription().'</p>');
$oDashletContainer->AddHtml('<p>'.utils::HtmlEntities($e->GetUserFriendlyDescription()).'</p>');
} catch (Exception $e) {
$oDashletContainer->AddCSSClass("dashlet-content");
$oDashletContainer->AddHtml('<p>'.$e->getMessage().'</p>');

View File

@@ -19,7 +19,7 @@ use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
*
* You should have received a copy of the GNU Affero General Public License
*
* @deprecated since 3.0.0 use Combodo\iTop\Application\UI\Base\Component\DataTable\Datatable
* @deprecated 3.0.0 use Combodo\iTop\Application\UI\Base\Component\DataTable\Datatable
*/
class DataTable

View File

@@ -566,7 +566,7 @@ class DisplayBlock
if (($this->m_sStyle != 'links') && ($this->m_sStyle != 'search') && ($this->m_sStyle != 'list_search')) {
$oAppContext = new ApplicationContext();
$sClass = $this->m_oFilter->GetClass();
$aFilterCodes = array_keys(MetaModel::GetClassFilterDefs($sClass));
$aFilterCodes = MetaModel::GetFiltersList($sClass);
$aCallSpec = array($sClass, 'MapContextParam');
if (is_callable($aCallSpec)) {
foreach ($oAppContext->GetNames() as $sContextParam) {

View File

@@ -1272,7 +1272,7 @@ class DesignerComboField extends DesignerFormField
$sChecked = $this->defaultValue ? 'checked' : '';
$sMandatory = $this->bMandatory ? 'true' : 'false';
$sReadOnly = $this->IsReadOnly() ? 'disabled="disabled"' : '';
if ($this->IsSorted())
if ($this->IsSorted() )
{
asort($this->aAllowedValues);
}
@@ -1320,18 +1320,14 @@ class DesignerComboField extends DesignerFormField
$sHtml .= "<option value=\"\">".$this->sNullLabel."</option>";
}
}
foreach($this->aAllowedValues as $sKey => $sDisplayValue)
{
if ($this->bMultipleSelection)
{
foreach ($this->aAllowedValues as $sKey => $sDisplayValue) {
if ($this->bMultipleSelection) {
$sSelected = in_array($sKey, $this->defaultValue) ? 'selected' : '';
}
else
{
} else {
$sSelected = ($sKey == $this->defaultValue) ? 'selected' : '';
}
// Quick and dirty: display the menu parents as a tree
$sHtmlValue = str_replace(' ', '&nbsp;', htmlentities($sDisplayValue, ENT_QUOTES, 'UTF-8'));
$sHtmlValue = str_replace(' ', '&nbsp;', $sDisplayValue);
$sHtml .= "<option value=\"".htmlentities($sKey, ENT_QUOTES, 'UTF-8')."\" $sSelected>$sHtmlValue</option>";
}
$sHtml .= "</select></span>";

View File

@@ -6,4 +6,4 @@
*/
// cannot notify depreciation for now as this is still MASSIVELY used in iTop core !
//DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/iTopWebPage.php, now loadable using autoloader');
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/iTopWebPage.php, now loadable using autoloader');

View File

@@ -8,7 +8,7 @@
use Combodo\iTop\Application\Branding;
use Combodo\iTop\TwigExtension;
use Combodo\iTop\Application\TwigBase\Twig\Extension;
/**
* Twig context for modules extending the login screen
@@ -234,7 +234,7 @@ class LoginTwigRenderer
$oLoader = new Twig_Loader_Chain($aTwigLoaders);
$this->oTwig = new Twig_Environment($oLoader);
TwigExtension::RegisterTwigExtensions($this->oTwig);
Extension::RegisterTwigExtensions($this->oTwig);
}
public function GetDefaultVars()

View File

@@ -133,10 +133,6 @@ class LoginWebPage extends NiceWebPage
//add profiles not already linked with user
foreach ($aProfiles as $iProfileId)
{
$oLink = new URP_UserProfile();
$oLink->Set('profileid', $iProfileId);
$oLink->Set('reason', $sOrigin);
$oProfilesSet->AddItem(MetaModel::NewObject('URP_UserProfile', array('profileid' => $iProfileId, 'reason' => $sOrigin)));
}
$oUser->Set('profile_list', $oProfilesSet);

View File

@@ -655,7 +655,7 @@ abstract class MenuNode
$this->sMenuId = $sMenuId;
$this->iParentIndex = $iParentIndex;
$this->aReflectionProperties = array();
if (strlen($sEnableClass) > 0)
if (utils::StrLen($sEnableClass) > 0)
{
$this->aReflectionProperties['enable_class'] = $sEnableClass;
$this->aReflectionProperties['enable_action'] = $iActionCode;

View File

@@ -4,6 +4,7 @@ namespace Combodo\iTop;
use AttributeDate;
use AttributeDateTime;
use DeprecatedCallsLog;
use Dict;
use Exception;
use MetaModel;
@@ -12,6 +13,8 @@ use Twig_SimpleFilter;
use Twig_SimpleFunction;
use utils;
DeprecatedCallsLog::NotifyDeprecatedFile('instead use sources/Application/TwigBase/Twig/Extension.php, which is loaded by the autoloader');
/**
* Class TwigExtension
*

View File

@@ -97,6 +97,11 @@ class utils
* @since 3.0.0
*/
public const ENUM_SANITIZATION_FILTER_RAW_DATA = 'raw_data';
/**
* @var string
* @since 3.0.2, 3.1.0 N°4899
*/
public const ENUM_SANITIZATION_FILTER_URL = 'url';
/**
* @var string
@@ -377,6 +382,7 @@ class utils
* @since 2.5.2 2.6.0 new 'transaction_id' filter
* @since 2.7.0 new 'element_identifier' filter
* @since 3.0.0 new utils::ENUM_SANITIZATION_* const
* @since 2.7.7, 3.0.2, 3.1.0 N°4899 - new 'url' filter
*/
protected static function Sanitize_Internal($value, $sSanitizationFilter)
{
@@ -454,6 +460,11 @@ class utils
$retValue = preg_replace('/[^a-zA-Z0-9_]/', '', $value);
break;
// For URL
case static::ENUM_SANITIZATION_FILTER_URL:
$retValue = filter_var($value, FILTER_SANITIZE_URL);
break;
default:
case static::ENUM_SANITIZATION_FILTER_RAW_DATA:
$retValue = $value;
@@ -2809,6 +2820,24 @@ HTML;
return $aPrefs[$sShortcutId];
}
//----------------------------------------------
// PHP function helpers
//----------------------------------------------
/**
* Helper around the native strlen() PHP method to keep allowing usage of null value when computing the length of a string as null value is no longer allowed with PHP 8.1+
* @link https://www.php.net/releases/8.1/en.php#deprecations_and_bc_breaks "Passing null to non-nullable internal function parameters is deprecated"
*
* @param string|null $sString
*
* @return int Length of $sString, 0 if null
* @since 3.0.2 N°5172
*/
public static function StrLen(?string $sString): int
{
return strlen($sString ?? '');
}
//----------------------------------------------
// Environment helpers
//----------------------------------------------

View File

@@ -359,6 +359,10 @@ class WizardHelper
JS;
}
/*
* Function with an old pattern of code
* @deprecated 3.1.0
*/
static function ParseJsonSet($oMe, $sLinkClass, $sExtKeyToMe, $sJsonSet)
{
$aSet = json_decode($sJsonSet, true); // true means hash array instead of object

View File

@@ -10,18 +10,19 @@
"ext-json": "*",
"ext-mysqli": "*",
"ext-soap": "*",
"combodo/tcpdf": "6.3.5",
"nikic/php-parser": "^4.12.0",
"pear/archive_tar": "1.4.14",
"pelago/emogrifier": "3.1.0",
"combodo/tcpdf": "~6.4.4",
"laminas/laminas-mail": "^2.12",
"laminas/laminas-servicemanager": "^3.5",
"nikic/php-parser": "~4.13.2",
"pear/archive_tar": "~1.4.14",
"pelago/emogrifier": "~3.1.0",
"scssphp/scssphp": "1.0.6",
"swiftmailer/swiftmailer": "5.4.12",
"symfony/console": "~3.4.47",
"symfony/dotenv": "~3.4.47",
"symfony/framework-bundle": "~3.4.47",
"symfony/polyfill-php70": "1.*",
"symfony/twig-bundle": "~3.4.47",
"symfony/yaml": "~3.4.47"
"symfony/yaml": "~3.4.47",
"twig/twig": "~1.42.5"
},
"require-dev": {
"symfony/stopwatch": "~3.4.47",
@@ -60,6 +61,7 @@
"core/legacy/querybuildercontextlegacy.class.inc.php",
"core/querybuilderexpressions.class.inc.php",
"core/legacy/querybuilderexpressionslegacy.class.inc.php",
"application/twigextension.class.inc.php",
"core/oql/build/PHP/",
"core/apc-emulation.php",
"application/startup.inc.php",

704
composer.lock generated
View File

@@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "4c5cdd1e0feb4abaab8f86959ffc7a64",
"content-hash": "0a00d21469578133ce5f1b2712a64c78",
"packages": [
{
"name": "combodo/tcpdf",
"version": "6.3.5",
"version": "6.4.4",
"source": {
"type": "git",
"url": "https://github.com/combodo-itop-libs/TCPDF.git",
"reference": "aedd4b7b8cf7fcc24e617c405c9d3304150f4b94"
"reference": "0e31c013ccd000aa6762e9186778aa6e259ac8e8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/combodo-itop-libs/TCPDF/zipball/aedd4b7b8cf7fcc24e617c405c9d3304150f4b94",
"reference": "aedd4b7b8cf7fcc24e617c405c9d3304150f4b94",
"url": "https://api.github.com/repos/combodo-itop-libs/TCPDF/zipball/0e31c013ccd000aa6762e9186778aa6e259ac8e8",
"reference": "0e31c013ccd000aa6762e9186778aa6e259ac8e8",
"shasum": ""
},
"require": {
@@ -62,22 +62,564 @@
"email": "contact@combodo.com"
}
],
"description": "TCPDF fork adding requirements for iTop: Specific fonts.",
"description": "TCPDF is a PHP class for generating PDF documents and barcodes.",
"homepage": "https://github.com/combodo-itop-libs/TCPDF",
"time": "2020-09-28T12:19:09+00:00"
"keywords": [
"PDFD32000-2008",
"TCPDF",
"barcodes",
"datamatrix",
"pdf",
"pdf417",
"qrcode"
],
"support": {
"source": "https://github.com/combodo-itop-libs/TCPDF/tree/6.4.4"
},
"funding": [
{
"url": "https://www.paypal.com/cgi-bin/webscr?cmd=_donations&currency_code=GBP&business=paypal@tecnick.com&item_name=donation%20for%20tcpdf%20project",
"type": "custom"
}
],
"time": "2022-03-10T14:36:39+00:00"
},
{
"name": "nikic/php-parser",
"version": "v4.12.0",
"name": "container-interop/container-interop",
"version": "1.2.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "6608f01670c3cc5079e18c1dab1104e002579143"
"url": "https://github.com/container-interop/container-interop.git",
"reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6608f01670c3cc5079e18c1dab1104e002579143",
"reference": "6608f01670c3cc5079e18c1dab1104e002579143",
"url": "https://api.github.com/repos/container-interop/container-interop/zipball/79cbf1341c22ec75643d841642dd5d6acd83bdb8",
"reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8",
"shasum": ""
},
"require": {
"psr/container": "^1.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Interop\\Container\\": "src/Interop/Container/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
"homepage": "https://github.com/container-interop/container-interop",
"support": {
"issues": "https://github.com/container-interop/container-interop/issues",
"source": "https://github.com/container-interop/container-interop/tree/master"
},
"abandoned": "psr/container",
"time": "2017-02-14T19:40:03+00:00"
},
{
"name": "laminas/laminas-loader",
"version": "2.6.1",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-loader.git",
"reference": "5d01c2c237ae9e68bec262f339947e2ea18979bc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laminas/laminas-loader/zipball/5d01c2c237ae9e68bec262f339947e2ea18979bc",
"reference": "5d01c2c237ae9e68bec262f339947e2ea18979bc",
"shasum": ""
},
"require": {
"laminas/laminas-zendframework-bridge": "^1.0",
"php": "^5.6 || ^7.0"
},
"replace": {
"zendframework/zend-loader": "self.version"
},
"require-dev": {
"laminas/laminas-coding-standard": "~1.0.0",
"phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.6.x-dev",
"dev-develop": "2.7.x-dev"
}
},
"autoload": {
"psr-4": {
"Laminas\\Loader\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "Autoloading and plugin loading strategies",
"homepage": "https://laminas.dev",
"keywords": [
"laminas",
"loader"
],
"support": {
"chat": "https://laminas.dev/chat",
"docs": "https://docs.laminas.dev/laminas-loader/",
"forum": "https://discourse.laminas.dev",
"issues": "https://github.com/laminas/laminas-loader/issues",
"rss": "https://github.com/laminas/laminas-loader/releases.atom",
"source": "https://github.com/laminas/laminas-loader"
},
"time": "2019-12-31T17:18:27+00:00"
},
{
"name": "laminas/laminas-mail",
"version": "2.12.5",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-mail.git",
"reference": "ed5b36a0deef4ffafe6138c2ae9cafcffafab856"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laminas/laminas-mail/zipball/ed5b36a0deef4ffafe6138c2ae9cafcffafab856",
"reference": "ed5b36a0deef4ffafe6138c2ae9cafcffafab856",
"shasum": ""
},
"require": {
"ext-iconv": "*",
"laminas/laminas-loader": "^2.5",
"laminas/laminas-mime": "^2.5",
"laminas/laminas-stdlib": "^2.7 || ^3.0",
"laminas/laminas-validator": "^2.10.2",
"laminas/laminas-zendframework-bridge": "^1.0",
"php": "^7.1",
"true/punycode": "^2.1"
},
"replace": {
"zendframework/zend-mail": "^2.10.0"
},
"require-dev": {
"laminas/laminas-coding-standard": "~1.0.0",
"laminas/laminas-config": "^2.6",
"laminas/laminas-crypt": "^2.6 || ^3.0",
"laminas/laminas-servicemanager": "^3.2.1",
"phpunit/phpunit": "^7.5.20"
},
"suggest": {
"laminas/laminas-crypt": "Crammd5 support in SMTP Auth",
"laminas/laminas-servicemanager": "^2.7.10 || ^3.3.1 when using SMTP to deliver messages"
},
"type": "library",
"extra": {
"laminas": {
"component": "Laminas\\Mail",
"config-provider": "Laminas\\Mail\\ConfigProvider"
}
},
"autoload": {
"psr-4": {
"Laminas\\Mail\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "Provides generalized functionality to compose and send both text and MIME-compliant multipart e-mail messages",
"homepage": "https://laminas.dev",
"keywords": [
"laminas",
"mail"
],
"support": {
"chat": "https://laminas.dev/chat",
"docs": "https://docs.laminas.dev/laminas-mail/",
"forum": "https://discourse.laminas.dev",
"issues": "https://github.com/laminas/laminas-mail/issues",
"rss": "https://github.com/laminas/laminas-mail/releases.atom",
"source": "https://github.com/laminas/laminas-mail"
},
"funding": [
{
"url": "https://funding.communitybridge.org/projects/laminas-project",
"type": "community_bridge"
}
],
"time": "2020-12-31T11:41:57+00:00"
},
{
"name": "laminas/laminas-mime",
"version": "2.7.4",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-mime.git",
"reference": "e45a7d856bf7b4a7b5bd00d6371f9961dc233add"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laminas/laminas-mime/zipball/e45a7d856bf7b4a7b5bd00d6371f9961dc233add",
"reference": "e45a7d856bf7b4a7b5bd00d6371f9961dc233add",
"shasum": ""
},
"require": {
"laminas/laminas-stdlib": "^2.7 || ^3.0",
"laminas/laminas-zendframework-bridge": "^1.0",
"php": "^5.6 || ^7.0"
},
"replace": {
"zendframework/zend-mime": "^2.7.2"
},
"require-dev": {
"laminas/laminas-coding-standard": "~1.0.0",
"laminas/laminas-mail": "^2.6",
"phpunit/phpunit": "^5.7.27 || ^6.5.14 || ^7.5.20"
},
"suggest": {
"laminas/laminas-mail": "Laminas\\Mail component"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.7.x-dev",
"dev-develop": "2.8.x-dev"
}
},
"autoload": {
"psr-4": {
"Laminas\\Mime\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "Create and parse MIME messages and parts",
"homepage": "https://laminas.dev",
"keywords": [
"laminas",
"mime"
],
"support": {
"chat": "https://laminas.dev/chat",
"docs": "https://docs.laminas.dev/laminas-mime/",
"forum": "https://discourse.laminas.dev",
"issues": "https://github.com/laminas/laminas-mime/issues",
"rss": "https://github.com/laminas/laminas-mime/releases.atom",
"source": "https://github.com/laminas/laminas-mime"
},
"time": "2020-03-29T13:12:07+00:00"
},
{
"name": "laminas/laminas-servicemanager",
"version": "3.5.2",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-servicemanager.git",
"reference": "0669e1eec8d9f61e35a5bc5012796d49f418b259"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laminas/laminas-servicemanager/zipball/0669e1eec8d9f61e35a5bc5012796d49f418b259",
"reference": "0669e1eec8d9f61e35a5bc5012796d49f418b259",
"shasum": ""
},
"require": {
"container-interop/container-interop": "^1.2",
"laminas/laminas-stdlib": "^3.2.1",
"laminas/laminas-zendframework-bridge": "^1.0",
"php": "^5.6 || ^7.0",
"psr/container": "^1.0"
},
"provide": {
"container-interop/container-interop-implementation": "^1.2",
"psr/container-implementation": "^1.0"
},
"replace": {
"zendframework/zend-servicemanager": "^3.4.0"
},
"require-dev": {
"laminas/laminas-coding-standard": "~1.0.0",
"mikey179/vfsstream": "^1.6.5",
"ocramius/proxy-manager": "^1.0 || ^2.0",
"phpbench/phpbench": "^0.13.0",
"phpunit/phpunit": "^5.7.25 || ^6.4.4"
},
"suggest": {
"laminas/laminas-stdlib": "laminas-stdlib ^2.5 if you wish to use the MergeReplaceKey or MergeRemoveKey features in Config instances",
"ocramius/proxy-manager": "ProxyManager 1.* to handle lazy initialization of services"
},
"bin": [
"bin/generate-deps-for-config-factory",
"bin/generate-factory-for-class"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.3-dev",
"dev-develop": "4.0-dev"
}
},
"autoload": {
"psr-4": {
"Laminas\\ServiceManager\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "Factory-Driven Dependency Injection Container",
"homepage": "https://laminas.dev",
"keywords": [
"PSR-11",
"dependency-injection",
"di",
"dic",
"laminas",
"service-manager",
"servicemanager"
],
"support": {
"chat": "https://laminas.dev/chat",
"docs": "https://docs.laminas.dev/laminas-servicemanager/",
"forum": "https://discourse.laminas.dev",
"issues": "https://github.com/laminas/laminas-servicemanager/issues",
"rss": "https://github.com/laminas/laminas-servicemanager/releases.atom",
"source": "https://github.com/laminas/laminas-servicemanager"
},
"funding": [
{
"url": "https://funding.communitybridge.org/projects/laminas-project",
"type": "community_bridge"
}
],
"time": "2021-01-17T16:54:43+00:00"
},
{
"name": "laminas/laminas-stdlib",
"version": "3.2.1",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-stdlib.git",
"reference": "2b18347625a2f06a1a485acfbc870f699dbe51c6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/2b18347625a2f06a1a485acfbc870f699dbe51c6",
"reference": "2b18347625a2f06a1a485acfbc870f699dbe51c6",
"shasum": ""
},
"require": {
"laminas/laminas-zendframework-bridge": "^1.0",
"php": "^5.6 || ^7.0"
},
"replace": {
"zendframework/zend-stdlib": "self.version"
},
"require-dev": {
"laminas/laminas-coding-standard": "~1.0.0",
"phpbench/phpbench": "^0.13",
"phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.2.x-dev",
"dev-develop": "3.3.x-dev"
}
},
"autoload": {
"psr-4": {
"Laminas\\Stdlib\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "SPL extensions, array utilities, error handlers, and more",
"homepage": "https://laminas.dev",
"keywords": [
"laminas",
"stdlib"
],
"support": {
"chat": "https://laminas.dev/chat",
"docs": "https://docs.laminas.dev/laminas-stdlib/",
"forum": "https://discourse.laminas.dev",
"issues": "https://github.com/laminas/laminas-stdlib/issues",
"rss": "https://github.com/laminas/laminas-stdlib/releases.atom",
"source": "https://github.com/laminas/laminas-stdlib"
},
"time": "2019-12-31T17:51:15+00:00"
},
{
"name": "laminas/laminas-validator",
"version": "2.13.5",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-validator.git",
"reference": "d334dddda43af263d6a7e5024fd2b013cb6981f7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laminas/laminas-validator/zipball/d334dddda43af263d6a7e5024fd2b013cb6981f7",
"reference": "d334dddda43af263d6a7e5024fd2b013cb6981f7",
"shasum": ""
},
"require": {
"container-interop/container-interop": "^1.1",
"laminas/laminas-stdlib": "^3.2.1",
"laminas/laminas-zendframework-bridge": "^1.0",
"php": "^7.1"
},
"replace": {
"zendframework/zend-validator": "^2.13.0"
},
"require-dev": {
"laminas/laminas-cache": "^2.6.1",
"laminas/laminas-coding-standard": "~1.0.0",
"laminas/laminas-config": "^2.6",
"laminas/laminas-db": "^2.7",
"laminas/laminas-filter": "^2.6",
"laminas/laminas-http": "^2.5.4",
"laminas/laminas-i18n": "^2.6",
"laminas/laminas-math": "^2.6",
"laminas/laminas-servicemanager": "^2.7.5 || ^3.0.3",
"laminas/laminas-session": "^2.8",
"laminas/laminas-uri": "^2.5",
"phpunit/phpunit": "^7.5.20 || ^8.5.2",
"psr/http-client": "^1.0",
"psr/http-factory": "^1.0",
"psr/http-message": "^1.0"
},
"suggest": {
"laminas/laminas-db": "Laminas\\Db component, required by the (No)RecordExists validator",
"laminas/laminas-filter": "Laminas\\Filter component, required by the Digits validator",
"laminas/laminas-i18n": "Laminas\\I18n component to allow translation of validation error messages",
"laminas/laminas-i18n-resources": "Translations of validator messages",
"laminas/laminas-math": "Laminas\\Math component, required by the Csrf validator",
"laminas/laminas-servicemanager": "Laminas\\ServiceManager component to allow using the ValidatorPluginManager and validator chains",
"laminas/laminas-session": "Laminas\\Session component, ^2.8; required by the Csrf validator",
"laminas/laminas-uri": "Laminas\\Uri component, required by the Uri and Sitemap\\Loc validators",
"psr/http-message": "psr/http-message, required when validating PSR-7 UploadedFileInterface instances via the Upload and UploadFile validators"
},
"type": "library",
"extra": {
"laminas": {
"component": "Laminas\\Validator",
"config-provider": "Laminas\\Validator\\ConfigProvider"
}
},
"autoload": {
"psr-4": {
"Laminas\\Validator\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "Validation classes for a wide range of domains, and the ability to chain validators to create complex validation criteria",
"homepage": "https://laminas.dev",
"keywords": [
"laminas",
"validator"
],
"support": {
"chat": "https://laminas.dev/chat",
"docs": "https://docs.laminas.dev/laminas-validator/",
"forum": "https://discourse.laminas.dev",
"issues": "https://github.com/laminas/laminas-validator/issues",
"rss": "https://github.com/laminas/laminas-validator/releases.atom",
"source": "https://github.com/laminas/laminas-validator"
},
"funding": [
{
"url": "https://funding.communitybridge.org/projects/laminas-project",
"type": "community_bridge"
}
],
"time": "2021-01-06T15:05:04+00:00"
},
{
"name": "laminas/laminas-zendframework-bridge",
"version": "1.1.1",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-zendframework-bridge.git",
"reference": "6ede70583e101030bcace4dcddd648f760ddf642"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/6ede70583e101030bcace4dcddd648f760ddf642",
"reference": "6ede70583e101030bcace4dcddd648f760ddf642",
"shasum": ""
},
"require": {
"php": "^5.6 || ^7.0 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1 || ^9.3",
"squizlabs/php_codesniffer": "^3.5"
},
"type": "library",
"extra": {
"laminas": {
"module": "Laminas\\ZendFrameworkBridge"
}
},
"autoload": {
"files": [
"src/autoload.php"
],
"psr-4": {
"Laminas\\ZendFrameworkBridge\\": "src//"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "Alias legacy ZF class names to Laminas Project equivalents.",
"keywords": [
"ZendFramework",
"autoloading",
"laminas",
"zf"
],
"support": {
"forum": "https://discourse.laminas.dev/",
"issues": "https://github.com/laminas/laminas-zendframework-bridge/issues",
"rss": "https://github.com/laminas/laminas-zendframework-bridge/releases.atom",
"source": "https://github.com/laminas/laminas-zendframework-bridge"
},
"funding": [
{
"url": "https://funding.communitybridge.org/projects/laminas-project",
"type": "community_bridge"
}
],
"time": "2020-09-14T14:23:00+00:00"
},
{
"name": "nikic/php-parser",
"version": "v4.13.2",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "210577fe3cf7badcc5814d99455df46564f3c077"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077",
"reference": "210577fe3cf7badcc5814d99455df46564f3c077",
"shasum": ""
},
"require": {
@@ -118,9 +660,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.12.0"
"source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2"
},
"time": "2021-07-21T10:44:31+00:00"
"time": "2021-11-30T19:35:32+00:00"
},
{
"name": "paragonie/random_compat",
@@ -736,62 +1278,12 @@
"scss",
"stylesheet"
],
"support": {
"issues": "https://github.com/scssphp/scssphp/issues",
"source": "https://github.com/scssphp/scssphp/tree/master"
},
"time": "2019-12-12T05:00:52+00:00"
},
{
"name": "swiftmailer/swiftmailer",
"version": "v5.4.12",
"source": {
"type": "git",
"url": "https://github.com/swiftmailer/swiftmailer.git",
"reference": "181b89f18a90f8925ef805f950d47a7190e9b950"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/181b89f18a90f8925ef805f950d47a7190e9b950",
"reference": "181b89f18a90f8925ef805f950d47a7190e9b950",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"mockery/mockery": "~0.9.1",
"symfony/phpunit-bridge": "~3.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.4-dev"
}
},
"autoload": {
"files": [
"lib/swift_required.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Chris Corbyn"
},
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Swiftmailer, free feature-rich PHP mailer",
"homepage": "https://swiftmailer.symfony.com",
"keywords": [
"email",
"mail",
"mailer"
],
"time": "2018-07-31T09:26:32+00:00"
},
{
"name": "symfony/cache",
"version": "v3.4.47",
@@ -2697,17 +3189,67 @@
"time": "2020-10-24T10:57:07+00:00"
},
{
"name": "twig/twig",
"version": "v1.42.4",
"name": "true/punycode",
"version": "v2.1.1",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "e587180584c3d2d6cb864a0454e777bb6dcb6152"
"url": "https://github.com/true/php-punycode.git",
"reference": "a4d0c11a36dd7f4e7cd7096076cab6d3378a071e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/e587180584c3d2d6cb864a0454e777bb6dcb6152",
"reference": "e587180584c3d2d6cb864a0454e777bb6dcb6152",
"url": "https://api.github.com/repos/true/php-punycode/zipball/a4d0c11a36dd7f4e7cd7096076cab6d3378a071e",
"reference": "a4d0c11a36dd7f4e7cd7096076cab6d3378a071e",
"shasum": ""
},
"require": {
"php": ">=5.3.0",
"symfony/polyfill-mbstring": "^1.3"
},
"require-dev": {
"phpunit/phpunit": "~4.7",
"squizlabs/php_codesniffer": "~2.0"
},
"type": "library",
"autoload": {
"psr-4": {
"TrueBV\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Renan Gonçalves",
"email": "renan.saddam@gmail.com"
}
],
"description": "A Bootstring encoding of Unicode for Internationalized Domain Names in Applications (IDNA)",
"homepage": "https://github.com/true/php-punycode",
"keywords": [
"idna",
"punycode"
],
"support": {
"issues": "https://github.com/true/php-punycode/issues",
"source": "https://github.com/true/php-punycode/tree/master"
},
"time": "2016-11-16T10:37:54+00:00"
},
{
"name": "twig/twig",
"version": "v1.42.5",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "87b2ea9d8f6fd014d0621ca089bb1b3769ea3f8e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/87b2ea9d8f6fd014d0621ca089bb1b3769ea3f8e",
"reference": "87b2ea9d8f6fd014d0621ca089bb1b3769ea3f8e",
"shasum": ""
},
"require": {
@@ -2716,8 +3258,7 @@
},
"require-dev": {
"psr/container": "^1.0",
"symfony/debug": "^3.4|^4.2",
"symfony/phpunit-bridge": "^4.4@dev|^5.0"
"symfony/phpunit-bridge": "^4.4|^5.0"
},
"type": "library",
"extra": {
@@ -2746,7 +3287,6 @@
},
{
"name": "Twig Team",
"homepage": "https://twig.symfony.com/contributors",
"role": "Contributors"
},
{
@@ -2760,7 +3300,11 @@
"keywords": [
"templating"
],
"time": "2019-11-11T16:49:32+00:00"
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/1.x"
},
"time": "2020-02-11T05:59:23+00:00"
}
],
"packages-dev": [
@@ -3007,5 +3551,5 @@
"platform-overrides": {
"php": "7.1.3"
},
"plugin-api-version": "2.1.0"
"plugin-api-version": "2.3.0"
}

View File

@@ -277,7 +277,7 @@ class ActionEmail extends ActionNotification
protected function FindRecipients($sRecipAttCode, $aArgs)
{
$sOQL = $this->Get($sRecipAttCode);
if (strlen($sOQL) == '') return '';
if (strlen($sOQL) === 0) return '';
try
{

View File

@@ -409,8 +409,6 @@ class AsyncSendEmail extends AsyncTask
$oNew->Set('to', $oEMail->GetRecipientTO(true /* string */));
$oNew->Set('subject', $oEMail->GetSubject());
// $oNew->Set('version', 1);
// $sMessage = serialize($oEMail);
$oNew->Set('version', 2);
$sMessage = $oEMail->SerializeV2();
$oNew->Set('message', $sMessage);

View File

@@ -854,6 +854,11 @@ abstract class AttributeDefinition
//abstract protected GetBasicFilterHTMLInput();
abstract public function GetBasicFilterSQLExpr($sOpCode, $value);
/**
* since 3.1.0 return has changed (N°4690 - Deprecate "FilterCodes")
*
* @return array filtercode => attributecode
*/
public function GetFilterDefinitions()
{
return array();
@@ -2452,7 +2457,7 @@ class AttributeDBFieldVoid extends AttributeDefinition
public function GetFilterDefinitions()
{
return array($this->GetCode() => new FilterFromAttribute($this));
return array($this->GetCode() => $this->GetCode());
}
public function GetBasicFilterOperators()
@@ -7486,7 +7491,7 @@ class AttributeExternalField extends AttributeDefinition
public function GetFilterDefinitions()
{
return array($this->GetCode() => new FilterFromAttribute($this));
return array($this->GetCode() => $this->GetCode());
}
public function GetBasicFilterOperators()
@@ -8523,18 +8528,17 @@ class AttributeStopWatch extends AttributeDefinition
public function GetFilterDefinitions()
{
$aRes = array(
$this->GetCode() => new FilterFromAttribute($this),
$this->GetCode().'_started' => new FilterFromAttribute($this, '_started'),
$this->GetCode().'_laststart' => new FilterFromAttribute($this, '_laststart'),
$this->GetCode().'_stopped' => new FilterFromAttribute($this, '_stopped')
$this->GetCode() => $this->GetCode(),
$this->GetCode().'_started' => $this->GetCode(),
$this->GetCode().'_laststart' => $this->GetCode(),
$this->GetCode().'_stopped' => $this->GetCode(),
);
foreach($this->ListThresholds() as $iThreshold => $aFoo)
{
foreach ($this->ListThresholds() as $iThreshold => $aFoo) {
$sPrefix = $this->GetCode().'_'.$iThreshold;
$aRes[$sPrefix.'_deadline'] = new FilterFromAttribute($this, '_deadline');
$aRes[$sPrefix.'_passed'] = new FilterFromAttribute($this, '_passed');
$aRes[$sPrefix.'_triggered'] = new FilterFromAttribute($this, '_triggered');
$aRes[$sPrefix.'_overrun'] = new FilterFromAttribute($this, '_overrun');
$aRes[$sPrefix.'_deadline'] = $this->GetCode();
$aRes[$sPrefix.'_passed'] = $this->GetCode();
$aRes[$sPrefix.'_triggered'] = $this->GetCode();
$aRes[$sPrefix.'_overrun'] = $this->GetCode();
}
return $aRes;
@@ -9276,7 +9280,7 @@ class AttributeSubItem extends AttributeDefinition
public function GetFilterDefinitions()
{
return array($this->GetCode() => new FilterFromAttribute($this));
return array($this->GetCode() => $this->GetCode());
}
public function GetBasicFilterOperators()
@@ -11935,7 +11939,7 @@ class AttributeFriendlyName extends AttributeDefinition
public function GetFilterDefinitions()
{
return array($this->GetCode() => new FilterFromAttribute($this));
return array($this->GetCode() => $this->GetCode());
}
public function GetBasicFilterOperators()

View File

@@ -78,23 +78,31 @@ class CMDBChangeOp extends DBObject implements iCMDBChangeOp
}
/**
* @inheritDoc
*/
* Describe (as a text string) the modifications corresponding to this change
*/
public function GetDescription()
{
return '';
}
/**
* Safety net: in case the change is not given, let's guarantee that it will
* be set to the current ongoing change (or create a new one)
*/
* Safety net:
* * if change isn't persisted yet, use the current change and persist it if needed
* * in case the change is not given, let's guarantee that it will be set to the current ongoing change (or create a new one)
*
* @since 2.7.7 3.0.2 3.1.0 N°3717 do persist the current change if needed
*/
protected function OnInsert()
{
if ($this->Get('change') <= 0)
{
$this->Set('change', CMDBObject::GetCurrentChange());
$iChange = $this->Get('change');
if (($iChange <= 0) || (is_null($iChange))) {
$oChange = CMDBObject::GetCurrentChange();
if ($oChange->IsNew()) {
$oChange->DBWrite();
}
$this->Set('change', $oChange);
}
parent::OnInsert();
}
}

View File

@@ -113,6 +113,26 @@ abstract class CMDBObject extends DBObject
self::$m_oCurrChange = $oChange;
}
/**
* @param string $sUserInfo
* @param string $sOrigin
* @param \DateTime $oDate
*
* @throws \CoreException
*
* @since 2.7.7 3.0.2 3.1.0 N°3717 new method to reset current change
*/
public static function SetCurrentChangeFromParams($sUserInfo, $sOrigin = null, $oDate = null)
{
static::SetTrackInfo($sUserInfo);
static::SetTrackOrigin($sOrigin);
static::CreateChange();
if (!is_null($oDate)) {
static::$m_oCurrChange->Set("date", $oDate);
}
}
//
// Todo: simplify the APIs and do not pass the current change as an argument anymore
// SetTrackInfo to be invoked in very few cases (UI.php, CSV import, Data synchro)
@@ -144,6 +164,8 @@ abstract class CMDBObject extends DBObject
* $oMyChange->Set("userinfo", 'this is done by ... for ...');
* $iChangeId = $oMyChange->DBInsert();
*
* **warning** : this will do nothing if current change already exists !
*
* @see SetCurrentChange to specify a CMDBObject instance instead
*
* @param string $sInfo
@@ -171,6 +193,8 @@ abstract class CMDBObject extends DBObject
/**
* Provides information about the origin of the change
*
* **warning** : this will do nothing if current change already exists !
*
* @see SetTrackInfo
* @see SetCurrentChange to specify a CMDBObject instance instead
*
@@ -181,18 +205,15 @@ abstract class CMDBObject extends DBObject
{
self::$m_sOrigin = $sOrigin;
}
/**
* Get the additional information (defaulting to user name)
*/
protected static function GetTrackInfo()
*/
public static function GetTrackInfo()
{
if (is_null(self::$m_sInfo))
{
if (is_null(self::$m_sInfo)) {
return CMDBChange::GetCurrentUserName();
}
else
{
} else {
return self::$m_sInfo;
}
}
@@ -243,6 +264,9 @@ abstract class CMDBObject extends DBObject
* @throws \CoreWarning
* @throws \MySQLException
* @throws \OQLException
*
* @since 2.7.7 3.0.2 3.1.0 N°3717 {@see CMDBChange} **will be persisted later** in {@see \CMDBChangeOp::OnInsert} (was done previously directly here)
* This will avoid creating in DB CMDBChange lines without any corresponding CMDBChangeOp
*/
protected static function CreateChange()
{
@@ -251,7 +275,6 @@ abstract class CMDBObject extends DBObject
self::$m_oCurrChange->Set("userinfo", self::GetTrackInfo());
self::$m_oCurrChange->Set("user_id", self::GetTrackUserId());
self::$m_oCurrChange->Set("origin", self::GetTrackOrigin());
self::$m_oCurrChange->DBInsert();
}
/**
@@ -646,46 +669,7 @@ abstract class CMDBObject extends DBObject
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
{
$ret = parent::DBDelete($oDeletionPlan);
return $ret;
}
public static function BulkUpdate(DBSearch $oFilter, array $aValues)
{
return static::BulkUpdateTracked_Internal($oFilter, $aValues);
}
public static function BulkUpdateTracked(CMDBChange $oChange, DBSearch $oFilter, array $aValues)
{
self::SetCurrentChange($oChange);
static::BulkUpdateTracked_Internal($oFilter, $aValues);
}
protected static function BulkUpdateTracked_Internal(DBSearch $oFilter, array $aValues)
{
// $aValues is an array of $sAttCode => $value
// Get the list of objects to update (and load it before doing the change)
$oObjSet = new CMDBObjectSet($oFilter);
$oObjSet->Load();
// Keep track of the previous values (will be overwritten when the objects are synchronized with the DB)
$aOriginalValues = array();
$oObjSet->Rewind();
while ($oItem = $oObjSet->Fetch())
{
$aOriginalValues[$oItem->GetKey()] = $oItem->m_aOrigValues;
}
// Update in one single efficient query
$ret = parent::BulkUpdate($oFilter, $aValues);
// Record... in many queries !!!
$oObjSet->Rewind();
while ($oItem = $oObjSet->Fetch())
{
$aChangedValues = $oItem->ListChangedValues($aValues);
$oItem->RecordAttChanges($aChangedValues, $aOriginalValues[$oItem->GetKey()]);
}
return $ret;
}

View File

@@ -351,19 +351,21 @@ class CMDBSource
}
/**
* Get the version of the database server.
*
* @return string
* @throws \MySQLException
*
* @uses \CMDBSource::QueryToCol() so needs a connection opened !
* @uses \CMDBSource::QueryToScalar() so needs a connection opened !
*/
public static function GetDBVersion()
{
$aVersions = self::QueryToCol('SELECT Version() as version', 'version');
return $aVersions[0];
return static::QueryToScalar('SELECT VERSION()', 0);
}
/**
* @return string
* @deprecated Use `CMDBSource::GetDBVersion` instead.
* @uses mysqli_get_server_info
*/
public static function GetServerInfo()
{
@@ -705,7 +707,11 @@ class CMDBSource
private static function Commit()
{
$aStackTrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT , 3);
$sCaller = 'From '.$aStackTrace[1]['file'].'('.$aStackTrace[1]['line'].'): '.$aStackTrace[2]['class'].'->'.$aStackTrace[2]['function'].'()';
if(isset($aStackTrace[2]['class']) && isset($aStackTrace[2]['function'])) {
$sCaller = 'From '.$aStackTrace[1]['file'].'('.$aStackTrace[1]['line'].'): '.$aStackTrace[2]['class'].'->'.$aStackTrace[2]['function'].'()';
} else {
$sCaller = 'From '.$aStackTrace[1]['file'].'('.$aStackTrace[1]['line'].') ';
}
if (!self::IsInsideTransaction()) {
// should not happen !
IssueLog::Error("No Transaction COMMIT $sCaller", LogChannels::CMDB_SOURCE);
@@ -739,7 +745,11 @@ class CMDBSource
private static function Rollback()
{
$aStackTrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT , 3);
$sCaller = 'From '.$aStackTrace[1]['file'].'('.$aStackTrace[1]['line'].'): '.$aStackTrace[2]['class'].'->'.$aStackTrace[2]['function'].'()';
if(isset($aStackTrace[2]['class']) && isset($aStackTrace[2]['function'])) {
$sCaller = 'From '.$aStackTrace[1]['file'].'('.$aStackTrace[1]['line'].'): '.$aStackTrace[2]['class'].'->'.$aStackTrace[2]['function'].'()';
} else {
$sCaller = 'From '.$aStackTrace[1]['file'].'('.$aStackTrace[1]['line'].') ';
}
if (!self::IsInsideTransaction()) {
// should not happen !
IssueLog::Error("No Transaction ROLLBACK $sCaller", LogChannels::CMDB_SOURCE);
@@ -1499,20 +1509,14 @@ class CMDBSource
* Returns the value of the specified server variable
* @param string $sVarName Name of the server variable
* @return mixed Current value of the variable
*/
* @throws \MySQLQueryHasNoResultException|\MySQLException
*/
public static function GetServerVariable($sVarName)
{
$result = '';
$sSql = "SELECT @@$sVarName as theVar";
$aRows = self::QueryToArray($sSql);
if (count($aRows) > 0)
{
$result = $aRows[0]['theVar'];
}
return $result;
$sSql = 'SELECT @@'.$sVarName;
return static::QueryToScalar($sSql, 0) ?: '';
}
/**
* Returns the privileges of the current user
* @return string privileges in a raw format

View File

@@ -489,11 +489,11 @@ class Config
'show_in_conf_sample' => true,
],
'cron_max_execution_time' => [
'type' => 'integer',
'description' => 'Duration (seconds) of the page cron.php, must be shorter than php setting max_execution_time and shorter than the web server response timeout',
'default' => 600,
'value' => 600,
'source_of_value' => '',
'type' => 'integer',
'description' => 'Duration (seconds) of the cron.php script : if exceeded the script will exit even if there are remaining tasks to process. Must be shorter than php max_execution_time setting (note than when using CLI, this is set to 0 by default which means unlimited). If cron.php is ran via web, it must be shorter than the web server response timeout.',
'default' => 600,
'value' => 600,
'source_of_value' => '',
'show_in_conf_sample' => true,
],
'cron_task_max_execution_time' => [
@@ -886,7 +886,7 @@ class Config
'type' => 'string',
'description' => 'Regular expression to validate/detect the format of an URL (URL attributes and Wiki formatting for Text attributes)',
'default' => /** @lang RegExp */
'(https?|ftp)\://([a-zA-Z0-9+!*(),;?&=\$_.-]+(\:[a-zA-Z0-9+!*(),;?&=\$_.-]+)?@)?([a-zA-Z0-9-.]{3,})(\:[0-9]{2,5})?(/([a-zA-Z0-9:%+\$_-]\.?)+)*/?(\?[a-zA-Z+&\$_.-][a-zA-Z0-9;:[\]@&%=+/\$_.-]*)?(#[a-zA-Z_.-][a-zA-Z0-9+\$_.-]*)?',
'(https?|ftp)\://([a-zA-Z0-9+!*(),;?&=\$_.-]+(\:[a-zA-Z0-9+!*(),;?&=\$_.-]+)?@)?([a-zA-Z0-9-.]{3,})(\:[0-9]{2,5})?(/([a-zA-Z0-9:%+\$_-]\.?)+)*/?(\?[a-zA-Z+&\$_.-][a-zA-Z0-9;:[\]@&%=+/\$_.-]*)?(#[a-zA-Z0-9_.-][a-zA-Z0-9+\$_.-]*)?',
// SCHEME....... USER....................... PASSWORD.......................... HOST/IP........... PORT.......... PATH......................... GET............................................ ANCHOR..........................
// Example: http://User:passWord@127.0.0.1:8888/patH/Page.php?arrayArgument[2]=something:blah20#myAnchor
// RegExp source: http://www.php.net/manual/fr/function.preg-match.php#93824
@@ -1008,8 +1008,8 @@ class Config
'type' => 'integer',
'description' => 'Maximum length of the history table (in the "History" tab on each object) before it gets truncated. Latest modifications are displayed first.',
// examples... not used
'default' => 50,
'value' => 50,
'default' => 200,
'value' => 200,
'source_of_value' => '',
'show_in_conf_sample' => false,
],
@@ -1457,11 +1457,11 @@ class Config
'show_in_conf_sample' => false,
],
'use_legacy_dbsearch' => [
'type' => 'bool',
'description' => 'If set, DBSearch will use legacy SQL query generation',
'default' => false,
'value' => false,
'source_of_value' => '',
'type' => 'bool',
'description' => 'Deprecated since 3.1.0, there is now only one dbsearch method.',
'default' => false,
'value' => false,
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'query_cache_enabled' => [
@@ -1552,6 +1552,14 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'setup.launch_button.enabled' => [
'type' => 'bool',
'description' => 'If true displays in the Application Upgrade screen a button allowing to launch the setup in a single click (no more manual config file permission change needed)',
'default' => null,
'value' => false,
'source_of_value' => '',
'show_in_conf_sample' => false,
],
];
public function IsProperty($sPropCode)

View File

@@ -2026,9 +2026,9 @@ abstract class DBObject implements iDisplay
/**
* check attributes together
*
* @overwritable-hook You can extend this method in order to provide your own logic.
*
* @return bool
* @overwritable-hook You can extend this method in order to provide your own logic.
*
* @return true|string true if successful, the error description otherwise
*/
public function CheckConsistency()
{
@@ -2249,8 +2249,9 @@ abstract class DBObject implements iDisplay
foreach($aChanges as $sAttCode => $value) {
$res = $this->CheckValue($sAttCode);
if ($res !== true) {
$sAttLabel = $this->GetLabel($sAttCode);
// $res contains the error description
$this->m_aCheckIssues[] = "Unexpected value for attribute '$sAttCode': $res";
$this->m_aCheckIssues[] = Dict::Format('Core:CheckValueError', $sAttLabel, $sAttCode, $res);
}
$this->DoCheckLinkedSetDuplicates($sAttCode, $value);
@@ -2265,7 +2266,7 @@ abstract class DBObject implements iDisplay
if ($res !== true)
{
// $res contains the error description
$this->m_aCheckIssues[] = "Consistency rules not followed: $res";
$this->m_aCheckIssues[] = Dict::Format('Core:CheckConsistencyError', $res);
}
// Synchronization: are we attempting to modify an attribute for which an external source is master?
@@ -2278,12 +2279,10 @@ abstract class DBObject implements iDisplay
if ($iFlags & OPT_ATT_SLAVE)
{
// Note: $aReasonInfo['name'] could be reported (the task owning the attribute)
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
$sAttLabel = $oAttDef->GetLabel();
if (!empty($aReasons))
{
// Todo: associate the attribute code with the error
$this->m_aCheckIssues[] = Dict::Format('UI:AttemptingToSetASlaveAttribute_Name', $sAttLabel);
$sAttLabel = $this->GetLabel($sAttCode);
$this->m_aCheckIssues[] = Dict::Format('UI:AttemptingToSetASlaveAttribute_Name', $sAttLabel, $sAttCode);
}
}
}
@@ -4470,14 +4469,22 @@ abstract class DBObject implements iDisplay
$sAttCode = $sPlaceholderAttCode;
}
if ($sVerb == 'hyperlink')
if (in_array($sVerb, ['hyperlink', 'url']))
{
$sPortalId = ($sAttCode === '') ? 'console' : $sAttCode;
if (!array_key_exists($sPortalId, self::$aPortalToURLMaker))
{
throw new Exception("Unknown portal id '$sPortalId' in placeholder '$sPlaceholderAttCode''");
}
$ret = $this->GetHyperlink(self::$aPortalToURLMaker[$sPortalId], false);
if($sVerb == 'hyperlink')
{
$ret = $this->GetHyperlink(self::$aPortalToURLMaker[$sPortalId], false);
}
else
{
$ret = ApplicationContext::MakeObjectUrl(get_class($this), $this->GetKey(), self::$aPortalToURLMaker[$sPortalId], false);
}
}
else
{
@@ -5237,45 +5244,34 @@ abstract class DBObject implements iDisplay
if ($sSourceAttCode == 'id')
{
$oSourceAttDef = null;
}
else
{
if (!MetaModel::IsValidAttCode(get_class($this), $sDestAttCode))
{
} else {
if (!MetaModel::IsValidAttCode(get_class($this), $sDestAttCode)) {
throw new Exception("Unknown attribute ".get_class($this)."::".$sDestAttCode);
}
if (!MetaModel::IsValidAttCode(get_class($oSourceObject), $sSourceAttCode))
{
if (!MetaModel::IsValidAttCode(get_class($oSourceObject), $sSourceAttCode)) {
throw new Exception("Unknown attribute ".get_class($oSourceObject)."::".$sSourceAttCode);
}
$oSourceAttDef = MetaModel::GetAttributeDef(get_class($oSourceObject), $sSourceAttCode);
}
if (is_object($oSourceAttDef) && $oSourceAttDef->IsLinkSet())
{
if (is_object($oSourceAttDef) && $oSourceAttDef->IsLinkSet()) {
// The copy requires that we create a new object set (the semantic of DBObject::Set is unclear about link sets)
/** @var \AttributeLinkedSet $oSourceAttDef */
$oDestSet = DBObjectSet::FromScratch($oSourceAttDef->GetLinkedClass());
$oDestSet = $this->Get($sDestAttCode);
$oSourceSet = $oSourceObject->Get($sSourceAttCode);
$oSourceSet->Rewind();
/** @var \DBObject $oSourceLink */
while ($oSourceLink = $oSourceSet->Fetch())
{
while ($oSourceLink = $oSourceSet->Fetch()) {
// Clone the link
$sLinkClass = get_class($oSourceLink);
$oLinkClone = MetaModel::NewObject($sLinkClass);
foreach(MetaModel::ListAttributeDefs($sLinkClass) as $sAttCode => $oAttDef)
{
foreach (MetaModel::ListAttributeDefs($sLinkClass) as $sAttCode => $oAttDef) {
// As of now, ignore other attribute (do not attempt to recurse!)
if ($oAttDef->IsScalar() && $oAttDef->IsWritable())
{
if ($oAttDef->IsScalar() && $oAttDef->IsWritable()) {
$oLinkClone->Set($sAttCode, $oSourceLink->Get($sAttCode));
}
}
// Not necessary - this will be handled by DBObject
// $oLinkClone->Set($oSourceAttDef->GetExtKeyToMe(), 0);
$oDestSet->AddObject($oLinkClone);
$oDestSet->AddItem($oLinkClone);
}
$this->Set($sDestAttCode, $oDestSet);
}

View File

@@ -413,6 +413,10 @@ class DBObjectSearch extends DBSearch
}
/**
* Important: If you need to add a condition on the same $sFilterCode several times with different $value values; do not use this method as the previous $value occurences will be replaced by the last. Instead use:
* * {@see \DBObjectSearch::AddConditionExpression()} in loops to add conditions one by one
* * {@see \DBObjectSearch::AddConditionForInOperatorUsingParam()} for IN/NOT IN queries with lots of params at once
*
* @param string $sFilterCode
* @param mixed $value
* @param string $sOpCode operator to use : 'IN', 'NOT IN', 'Contains',' Begins with', 'Finishes with', ...
@@ -423,22 +427,16 @@ class DBObjectSearch extends DBSearch
* @param bool $bParseSearchString
*
* @throws \CoreException
*
* @see AddConditionForInOperatorUsingParam for IN/NOT IN queries with lots of params
*/
public function AddCondition($sFilterCode, $value, $sOpCode = null, $bParseSearchString = false)
{
MyHelpers::CheckKeyInArray('filter code in class: '.$this->GetClass(), $sFilterCode, MetaModel::GetClassFilterDefs($this->GetClass()));
MyHelpers::CheckKeyInArray('filter code in class: '.$this->GetClass(), $sFilterCode, MetaModel::GetFilterAttribList($this->GetClass()));
$oField = new FieldExpression($sFilterCode, $this->GetClassAlias());
if (empty($sOpCode))
{
if ($sFilterCode == 'id')
{
if (empty($sOpCode)) {
if ($sFilterCode == 'id') {
$sOpCode = '=';
}
else
{
} else {
$oAttDef = MetaModel::GetAttributeDef($this->GetClass(), $sFilterCode);
$oNewCondition = $oAttDef->GetSmartConditionExpression($value, $oField, $this->m_aParams);
$this->AddConditionExpression($oNewCondition);
@@ -1900,16 +1898,13 @@ class DBObjectSearch extends DBSearch
// Hide objects that are not visible to the current user
//
$oSearch = $this;
if (!$this->IsAllDataAllowed() && !$this->IsDataFiltered())
{
if (!$this->IsAllDataAllowed() && !$this->IsDataFiltered()) {
$oVisibleObjects = UserRights::GetSelectFilter($this->GetClass(), $this->GetModifierProperties('UserRightsGetSelectFilter'));
if ($oVisibleObjects === false)
{
if ($oVisibleObjects === false) {
// Make sure this is a valid search object, saying NO for all
$oVisibleObjects = DBObjectSearch::FromEmptySet($this->GetClass());
}
if (is_object($oVisibleObjects))
{
if (is_object($oVisibleObjects)) {
$oVisibleObjects->AllowAllData();
$oSearch = $this->Intersect($oVisibleObjects);
$oSearch->SetDataFiltered();
@@ -1929,63 +1924,49 @@ class DBObjectSearch extends DBSearch
if (isset($_SERVER['REQUEST_URI']))
{
$aContextData['sRequestUri'] = $_SERVER['REQUEST_URI'];
}
else if (isset($_SERVER['SCRIPT_NAME']))
{
} else if (isset($_SERVER['SCRIPT_NAME'])) {
$aContextData['sRequestUri'] = $_SERVER['SCRIPT_NAME'];
}
else
{
} else {
$aContextData['sRequestUri'] = '';
}
// Need to identify the query
$sOqlQuery = $oSearch->ToOql(false, null, true);
if ((strpos($sOqlQuery, '`id` IN (') !== false) || (strpos($sOqlQuery, '`id` NOT IN (') !== false))
{
if ((strpos($sOqlQuery, '`id` IN (') !== false) || (strpos($sOqlQuery, '`id` NOT IN (') !== false)) {
// Requests containing "id IN" are not worth caching
$bCanCache = false;
}
$aContextData['sOqlQuery'] = $sOqlQuery;
if (count($aModifierProperties))
{
if (count($aModifierProperties)) {
array_multisort($aModifierProperties);
$sModifierProperties = json_encode($aModifierProperties);
}
else
{
} else {
$sModifierProperties = '';
}
$aContextData['sModifierProperties'] = $sModifierProperties;
$sRawId = Dict::GetUserLanguage().'-'.$sOqlQuery.$sModifierProperties;
if (!is_null($aAttToLoad))
{
if (!is_null($aAttToLoad)) {
$sRawId .= json_encode($aAttToLoad);
}
$aContextData['aAttToLoad'] = $aAttToLoad;
if (!is_null($aGroupByExpr))
{
foreach($aGroupByExpr as $sAlias => $oExpr)
{
$sRawId .= 'g:'.$sAlias.'!'.$oExpr->Render();
if (!is_null($aGroupByExpr)) {
foreach ($aGroupByExpr as $sAlias => $oExpr) {
$sRawId .= 'g:'.$sAlias.'!'.$oExpr->RenderExpression();
}
}
if (!is_null($aSelectExpr))
{
foreach($aSelectExpr as $sAlias => $oExpr)
{
$sRawId .= 'se:'.$sAlias.'!'.$oExpr->Render();
if (!is_null($aSelectExpr)) {
foreach ($aSelectExpr as $sAlias => $oExpr) {
$sRawId .= 'se:'.$sAlias.'!'.$oExpr->RenderExpression();
}
}
$aContextData['aGroupByExpr'] = $aGroupByExpr;
$aContextData['aSelectExpr'] = $aSelectExpr;
$sRawId .= $bGetCount;
$aContextData['bGetCount'] = $bGetCount;
if (is_array($aSelectedClasses))
{
if (is_array($aSelectedClasses)) {
$sRawId .= implode(',', $aSelectedClasses); // Unions may alter the list of selected columns
}
$aContextData['aSelectedClasses'] = $aSelectedClasses;
@@ -2096,17 +2077,13 @@ class DBObjectSearch extends DBSearch
// 3rd step - position the attributes in the hierarchy of classes
//
$oSubClassExp->Browse(function($oNode) use ($sSubClass) {
if ($oNode instanceof FieldExpression)
{
if ($oNode instanceof FieldExpression) {
$sAttCode = $oNode->GetName();
$oAttDef = MetaModel::GetAttributeDef($sSubClass, $sAttCode);
if ($oAttDef->IsExternalField())
{
if ($oAttDef->IsExternalField()) {
$sKeyAttCode = $oAttDef->GetKeyAttCode();
$sClassOfAttribute = MetaModel::GetAttributeOrigin($sSubClass, $sKeyAttCode);
}
else
{
} else {
$sClassOfAttribute = MetaModel::GetAttributeOrigin($sSubClass, $sAttCode);
}
$sParent = MetaModel::GetAttributeOrigin($sClassOfAttribute, $oNode->GetName());
@@ -2114,12 +2091,11 @@ class DBObjectSearch extends DBSearch
}
});
$sSignature = $oSubClassExp->Render();
if (!array_key_exists($sSignature, $aExpressions))
{
$sSignature = $oSubClassExp->RenderExpression();
if (!array_key_exists($sSignature, $aExpressions)) {
$aExpressions[$sSignature] = array(
'expression' => $oSubClassExp,
'classes' => array(),
'classes' => array(),
);
}
$aExpressions[$sSignature]['classes'][] = $sSubClass;

View File

@@ -1195,8 +1195,10 @@ class DisplayableGraph extends SimpleGraph
* @param float $xMax Right coordinate of the bounding box to display the graph
* @param float $yMin Top coordinate of the bounding box to display the graph
* @param float $yMax Bottom coordinate of the bounding box to display the graph
*
* @since 2.7.7 3.0.2 3.1.0 N°4985 $sComments param is no longer optional
*/
function RenderAsPDF(PDFPage $oPage, $sComments = '', $sContextKey, $xMin = -1, $xMax = -1, $yMin = -1, $yMax = -1)
function RenderAsPDF(PDFPage $oPage, $sComments, $sContextKey, $xMin = -1, $xMax = -1, $yMin = -1, $yMax = -1)
{
$aContextDefs = static::GetContextDefinitions($sContextKey, false); // No need to develop the parameters
$oPdf = $oPage->get_tcpdf();

View File

@@ -24,13 +24,18 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Laminas\Mail\Header\ContentType;
use Laminas\Mail\Message;
use Laminas\Mail\Transport\File;
use Laminas\Mail\Transport\FileOptions;
use Laminas\Mail\Transport\SmtpOptions;
use Laminas\Mail\Transport\Smtp;
use Laminas\Mime\Mime;
use Laminas\Mime\Part;
use Pelago\Emogrifier\CssInliner;
use Pelago\Emogrifier\HtmlProcessor\CssToAttributeConverter;
use Pelago\Emogrifier\HtmlProcessor\HtmlPruner;
Swift_Preferences::getInstance()->setCharset('UTF-8');
define ('EMAIL_SEND_OK', 0);
define ('EMAIL_SEND_PENDING', 1);
define ('EMAIL_SEND_ERROR', 2);
@@ -58,7 +63,8 @@ class EMail
public function __construct()
{
$this->m_aData = array();
$this->m_oMessage = Swift_Message::newInstance();
$this->m_oMessage = new Message();
$this->m_oMessage->setEncoding('UTF-8');
$this->SetRecipientFrom(MetaModel::GetConfig()->Get('email_default_sender_address'), MetaModel::GetConfig()->Get('email_default_sender_label'));
}
@@ -72,12 +78,18 @@ class EMail
{
return serialize($this->m_aData);
}
/**
* Custom de-serialization method
*
* @param string $sSerializedMessage The serialized representation of the message
*
* @return \EMail
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \Symfony\Component\CssSelector\Exception\SyntaxErrorException
*/
static public function UnSerializeV2($sSerializedMessage)
public static function UnSerializeV2($sSerializedMessage)
{
$aData = unserialize($sSerializedMessage);
$oMessage = new Email();
@@ -115,7 +127,6 @@ class EMail
$oMessage->SetSubject($aData['subject']);
}
if (array_key_exists('headers', $aData))
{
foreach($aData['headers'] as $sKey => $sValue)
@@ -155,10 +166,11 @@ class EMail
return EMAIL_SEND_PENDING;
}
/**
* @throws \Exception
*/
protected function SendSynchronous(&$aIssues, $oLog = null)
{
// If the body of the message is in HTML, embed all images based on attachments
$this->EmbedInlineImages();
$this->LoadConfig();
@@ -172,50 +184,54 @@ class EMail
$sUserName = self::$m_oConfig->Get('email_transport_smtp.username');
$sPassword = self::$m_oConfig->Get('email_transport_smtp.password');
$oTransport = Swift_SmtpTransport::newInstance($sHost, $sPort, $sEncryption);
$oTransport = new Smtp();
$aOptions= [
'host' => $sHost,
'port' => $sPort,
'connection_class' => 'login',
'connection_config' => [
'ssl' => $sEncryption,
],
];
if (strlen($sUserName) > 0)
{
$oTransport->setUsername($sUserName);
$oTransport->setPassword($sPassword);
$aOptions['connection_config']['username'] = $sUserName;
$aOptions['connection_config']['password'] = $sPassword;
}
$oOptions = new SmtpOptions($aOptions);
$oTransport->setOptions($oOptions);
break;
case 'Null':
$oTransport = Swift_NullTransport::newInstance();
$oTransport = new Smtp();
break;
case 'LogFile':
$oTransport = Swift_LogFileTransport::newInstance();
$oTransport->setLogFile(APPROOT.'log/mail.log');
$oTransport = new File();
$aOptions = new FileOptions([
'path' => APPROOT.'log/mail.log',
]);
$oTransport->setOptions($aOptions);
break;
case 'PHPMail':
default:
$oTransport = Swift_MailTransport::newInstance();
$oTransport = new Smtp();
}
$oMailer = Swift_Mailer::newInstance($oTransport);
$aFailedRecipients = array();
$this->m_oMessage->setMaxLineLength(0);
$oKPI = new ExecutionKPI();
try
{
$iSent = $oMailer->send($this->m_oMessage, $aFailedRecipients);
if ($iSent === 0)
{
// Beware: it seems that $aFailedRecipients sometimes contains the recipients that actually received the message !!!
IssueLog::Warning('Email sending failed: Some recipients were invalid, aFailedRecipients contains: '.implode(', ', $aFailedRecipients));
$aIssues = array('Some recipients were invalid.');
$oKPI->ComputeStats('Email Sent', 'Error received');
return EMAIL_SEND_ERROR;
}
else
{
$aIssues = array();
$oKPI->ComputeStats('Email Sent', 'Succeded');
return EMAIL_SEND_OK;
}
$oTransport->send($this->m_oMessage);
$aIssues = array();
$oKPI->ComputeStats('Email Sent', 'Succeded');
return EMAIL_SEND_OK;
}
catch(Laminas\Mail\Transport\Exception\RuntimeException $e){
IssueLog::Warning('Email sending failed: Some recipients were invalid');
$aIssues = array('Some recipients were invalid.');
$oKPI->ComputeStats('Email Sent', 'Error received');
return EMAIL_SEND_ERROR;
}
catch (Exception $e)
{
@@ -223,51 +239,65 @@ class EMail
throw $e;
}
}
/**
* Reprocess the body of the message (if it is an HTML message)
* to replace the URL of images based on attachments by a link
* to an embedded image (i.e. cid:....)
* to an embedded image (i.e. cid:....) and returns images to be attached as an array
*
* @param string $sBody Email body to process/alter
*
* @return array Array of Part that needs to be added as inline attachment later to render as embed
* @throws \ArchivedObjectException
* @throws \CoreException
*/
protected function EmbedInlineImages()
protected function EmbedInlineImages(string &$sBody)
{
if ($this->m_aData['body']['mimeType'] == 'text/html')
$oDOMDoc = new DOMDocument();
$oDOMDoc->preserveWhitespace = true;
@$oDOMDoc->loadHTML('<?xml encoding="UTF-8"?>'.$sBody); // For loading HTML chunks where the character set is not specified
$oXPath = new DOMXPath($oDOMDoc);
$sXPath = '//img[@'.InlineImage::DOM_ATTR_ID.']';
$oImagesList = $oXPath->query($sXPath);
$oImagesContent = new \Laminas\Mime\Message();
$aImagesParts = [];
if ($oImagesList->length != 0)
{
$oDOMDoc = new DOMDocument();
$oDOMDoc->preserveWhitespace = true;
@$oDOMDoc->loadHTML('<?xml encoding="UTF-8"?>'.$this->m_aData['body']['body']); // For loading HTML chunks where the character set is not specified
$oXPath = new DOMXPath($oDOMDoc);
$sXPath = '//img[@'.InlineImage::DOM_ATTR_ID.']';
$oImagesList = $oXPath->query($sXPath);
if ($oImagesList->length != 0)
foreach($oImagesList as $oImg)
{
foreach($oImagesList as $oImg)
$iAttId = $oImg->getAttribute(InlineImage::DOM_ATTR_ID);
$oAttachment = MetaModel::GetObject('InlineImage', $iAttId, false, true /* Allow All Data */);
if ($oAttachment)
{
$iAttId = $oImg->getAttribute(InlineImage::DOM_ATTR_ID);
$oAttachment = MetaModel::GetObject('InlineImage', $iAttId, false, true /* Allow All Data */);
if ($oAttachment)
$sImageSecret = $oImg->getAttribute('data-img-secret');
$sAttachmentSecret = $oAttachment->Get('secret');
if ($sImageSecret !== $sAttachmentSecret)
{
$sImageSecret = $oImg->getAttribute('data-img-secret');
$sAttachmentSecret = $oAttachment->Get('secret');
if ($sImageSecret !== $sAttachmentSecret)
{
// @see N°1921
// If copying from another iTop we could get an IMG pointing to an InlineImage with wrong secret
continue;
}
$oDoc = $oAttachment->Get('contents');
$oSwiftImage = new Swift_Image($oDoc->GetData(), $oDoc->GetFileName(), $oDoc->GetMimeType());
$sCid = $this->m_oMessage->embed($oSwiftImage);
$oImg->setAttribute('src', $sCid);
// @see N°1921
// If copying from another iTop we could get an IMG pointing to an InlineImage with wrong secret
continue;
}
$oDoc = $oAttachment->Get('contents');
$sCid = uniqid('', true);
$oNewAttachment = new Part($oDoc->GetData());
$oNewAttachment->id = $sCid;
$oNewAttachment->type = $oDoc->GetMimeType();
$oNewAttachment->filename = $oDoc->GetFileName();
$oNewAttachment->disposition = Mime::DISPOSITION_INLINE;
$oNewAttachment->encoding = Mime::ENCODING_BASE64;
$oImagesContent->addPart($oNewAttachment);
$oImg->setAttribute('src', 'cid:'.$sCid);
$aImagesParts[] = $oNewAttachment;
}
}
$sHtmlBody = $oDOMDoc->saveHTML();
$this->m_oMessage->setBody($sHtmlBody, 'text/html', 'UTF-8');
}
$sBody = $oDOMDoc->saveHTML();
return $aImagesParts;
}
public function Send(&$aIssues, $bForceSynchronous = false, $oLog = null)
@@ -313,7 +343,7 @@ class EMail
break;
default:
$oHeaders->addTextHeader($sKey, $sValue);
$oHeaders->addHeaderLine($sKey, $sValue);
}
}
}
@@ -326,8 +356,7 @@ class EMail
// so let's remove the angle brackets if present, for historical reasons
$sId = str_replace(array('<', '>'), '', $sId);
$oMsgId = $this->m_oMessage->getHeaders()->get('Message-ID');
$oMsgId->SetId($sId);
$this->m_oMessage->getHeaders()->addHeaderLine('Message-ID', $sId);
}
public function SetReferences($sReferences)
@@ -349,35 +378,123 @@ class EMail
$this->AddToHeader('In-Reply-To', $sMessageId);
}
public function SetBody($sBody, $sMimeType = 'text/html', $sCustomStyles = null)
/**
* Set current Email body and process inline images.
*
* @param $sBody
* @param string $sMimeType
* @param $sCustomStyles
*
* @return void
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \Symfony\Component\CssSelector\Exception\SyntaxErrorException
*/
public function SetBody($sBody, string $sMimeType = Mime::TYPE_HTML, $sCustomStyles = null)
{
if (($sMimeType === 'text/html') && ($sCustomStyles !== null)) {
$oBody = new Laminas\Mime\Message();
$aAdditionalParts = [];
if (($sMimeType === Mime::TYPE_HTML) && ($sCustomStyles !== null)) {
$oDomDocument = CssInliner::fromHtml($sBody)->inlineCss($sCustomStyles)->getDomDocument();
HtmlPruner::fromDomDocument($oDomDocument)->removeElementsWithDisplayNone();
$sBody = CssToAttributeConverter::fromDomDocument($oDomDocument)->convertCssToVisualAttributes()->render(); // Adds html/body tags if not already present
}
$this->m_aData['body'] = array('body' => $sBody, 'mimeType' => $sMimeType);
$this->m_oMessage->setBody($sBody, $sMimeType);
// We don't want these modifications in m_aData['body'], otherwise it'll ruin asynchronous mail as they go through this method twice
if ($sMimeType === Mime::TYPE_HTML){
$aAdditionalParts = $this->EmbedInlineImages($sBody);
}
// Add body content to as a new part
$oNewPart = new Part($sBody);
$oNewPart->encoding = Mime::ENCODING_8BIT;
$oNewPart->type = $sMimeType;
$oBody->addPart($oNewPart);
// Add additional images as new body parts
foreach ($aAdditionalParts as $oAdditionalPart) {
$oBody->addPart($oAdditionalPart);
}
if($oBody->isMultiPart()){
$oContentTypeHeader = $this->m_oMessage->getHeaders();
foreach ($oContentTypeHeader as $oHeader) {
if (!$oHeader instanceof ContentType) {
continue;
}
$oHeader->setType(Mime::MULTIPART_MIXED);
$oHeader->addParameter('boundary', $oBody->getMime()->boundary());
break;
}
}
$this->m_oMessage->setBody($oBody);
}
public function AddPart($sText, $sMimeType = 'text/html')
/**
* Add a new part to the existing body
* @param $sText
* @param string $sMimeType
*
* @return void
*/
public function AddPart($sText, string $sMimeType = Mime::TYPE_HTML)
{
if (!array_key_exists('parts', $this->m_aData))
{
$this->m_aData['parts'] = array();
}
$this->m_aData['parts'][] = array('text' => $sText, 'mimeType' => $sMimeType);
$this->m_oMessage->addPart($sText, $sMimeType);
$oNewPart = new Part($sText);
$oNewPart->encoding = Mime::ENCODING_8BIT;
$oNewPart->type = $sMimeType;
$this->m_oMessage->getBody()->addPart($oNewPart);
}
public function AddAttachment($data, $sFileName, $sMimeType)
{
$oBody = $this->m_oMessage->getBody();
if(!$oBody->isMultiPart()){
$multipart_content = new Part($oBody->generateMessage());
$multipart_content->setType($oBody->getParts()[0]->getType());
$multipart_content->setBoundary($oBody->getMime()->boundary());
$oBody = new Laminas\Mime\Message();
$oBody->addPart($multipart_content);
}
if (!array_key_exists('attachments', $this->m_aData))
{
$this->m_aData['attachments'] = array();
}
$this->m_aData['attachments'][] = array('data' => base64_encode($data), 'filename' => $sFileName, 'mimeType' => $sMimeType);
$this->m_oMessage->attach(Swift_Attachment::newInstance($data, $sFileName, $sMimeType));
$oNewAttachment = new Part($data);
$oNewAttachment->type = $sMimeType;
$oNewAttachment->filename = $sFileName;
$oNewAttachment->disposition = Mime::DISPOSITION_ATTACHMENT;
$oNewAttachment->encoding = Mime::ENCODING_BASE64;
$oBody->addPart($oNewAttachment);
if($oBody->isMultiPart()){
$oContentTypeHeader = $this->m_oMessage->getHeaders();
foreach ($oContentTypeHeader as $oHeader) {
if (!$oHeader instanceof ContentType) {
continue;
}
$oHeader->setType(Mime::MULTIPART_MIXED);
$oHeader->addParameter('boundary', $oBody->getMime()->boundary());
break;
}
}
$this->m_oMessage->setBody($oBody);
}
public function SetSubject($sSubject)
@@ -422,7 +539,7 @@ class EMail
public function GetRecipientTO($bAsString = false)
{
$aRes = $this->m_oMessage->getTo();
if ($aRes === null)
if ($aRes === null || $aRes->count() === 0)
{
// There is no "To" header field
$aRes = array();
@@ -430,8 +547,10 @@ class EMail
if ($bAsString)
{
$aStrings = array();
foreach ($aRes as $sEmail => $sName)
foreach ($aRes as $oEmail)
{
$sName = $oEmail->getName();
$sEmail = $oEmail->getEmail();
if (is_null($sName))
{
$aStrings[] = $sEmail;
@@ -495,78 +614,4 @@ class EMail
$this->m_oMessage->setReplyTo($sAddress);
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
/**
* Extension to SwiftMailer: "debug" transport that pretends messages have been sent,
* but just log them to a file.
*
* @package Swift
* @author Denis Flaven
*/
class Swift_Transport_LogFileTransport extends Swift_Transport_NullTransport
{
protected $sLogFile;
/**
* Sends the given message.
*
* @param Swift_Mime_Message $message
* @param string[] $failedRecipients An array of failures by-reference
*
* @return int The number of sent emails
*/
public function send(Swift_Mime_Message $message, &$failedRecipients = null)
{
$hFile = @fopen($this->sLogFile, 'a');
if ($hFile)
{
$sTxt = "================== ".date('Y-m-d H:i:s')." ==================\n";
$sTxt .= $message->toString()."\n";
@fwrite($hFile, $sTxt);
@fclose($hFile);
}
return parent::send($message, $failedRecipients);
}
public function setLogFile($sFilename)
{
$this->sLogFile = $sFilename;
}
}
/**
* Pretends messages have been sent, but just log them to a file.
*
* @package Swift
* @author Denis Flaven
*/
class Swift_LogFileTransport extends Swift_Transport_LogFileTransport
{
/**
* Create a new LogFileTransport.
*/
public function __construct()
{
call_user_func_array(
array($this, 'Swift_Transport_LogFileTransport::__construct'),
Swift_DependencyContainer::getInstance()
->createDependenciesFor('transport.null')
);
}
/**
* Create a new LogFileTransport instance.
*
* @return Swift_LogFileTransport
*/
public static function newInstance()
{
return new self();
}
}

View File

@@ -1,4 +1,8 @@
<?php
// The file has been moved in iTop 2.2.0+ (revision 3803)
// Preserve backward compatibility with some external tools (Cf. toolkit)
// @deprecated 3.1.0
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use core/oql/expression.class.inc.php instead');
require_once(APPROOT.'core/oql/expression.class.inc.php');

View File

@@ -31,8 +31,9 @@ require_once('MyHelpers.class.inc.php');
/**
* Definition of a filter (could be made out of an existing attribute, or from an expression)
* Definition of a filter (could be made out of an existing attribute, or from an expression)
*
* @deprecated 3.1.0 not used N°4690 - Deprecate "FilterCodes"
* @package iTopORM
*/
abstract class FilterDefinition
@@ -46,6 +47,7 @@ abstract class FilterDefinition
public function __construct($sCode, $aParams = array())
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod("Deprecated class ".$this->GetClass().". Do not use. Will be removed in next version.");
$this->m_sCode = $sCode;
$this->m_aParams = $aParams;
$this->ConsistencyCheck();
@@ -98,8 +100,9 @@ abstract class FilterDefinition
}
/**
* Match against the object unique identifier
* Match against the object unique identifier
*
* @deprecated 3.1.0 N°4690 - Deprecate "FilterCodes"
* @package iTopORM
*/
class FilterPrivateKey extends FilterDefinition
@@ -145,8 +148,9 @@ class FilterPrivateKey extends FilterDefinition
}
/**
* Match against an existing attribute (the attribute type will determine the available operators)
* Match against an existing attribute (the attribute type will determine the available operators)
*
* @deprecated 3.1.0 N°4690 - Deprecate "FilterCodes"
* @package iTopORM
*/
class FilterFromAttribute extends FilterDefinition

View File

@@ -108,6 +108,18 @@ abstract class DOMSanitizer extends HTMLSanitizer
{
/** @var DOMDocument */
protected $oDoc;
/**
* @var string Class to use for InlineImage static method calls
* @used-by \Combodo\iTop\Test\UnitTest\Core\Sanitizer\HTMLDOMSanitizerTest::testDoSanitizeCallInlineImageProcessImageTag
*/
protected $sInlineImageClassName;
public function __construct($sInlineImageClassName = InlineImage::class)
{
parent::__construct();
$this->sInlineImageClassName = $sInlineImageClassName;
}
abstract public function GetTagsWhiteList();
@@ -203,7 +215,7 @@ abstract class DOMSanitizer extends HTMLSanitizer
// Recurse
$this->CleanNode($oNode);
if (($oNode instanceof DOMElement) && (strtolower($oNode->tagName) == 'img')) {
InlineImage::ProcessImageTag($oNode);
$this->sInlineImageClassName::ProcessImageTag($oNode);
}
}
}
@@ -338,6 +350,30 @@ class HTMLDOMSanitizer extends DOMSanitizer
'white-space',
);
public function __construct($sInlineImageClassName = InlineImage::class)
{
parent::__construct($sInlineImageClassName);
// Building href validation pattern from url and email validation patterns as the patterns are not used the same way in HTML content than in standard attributes value.
// eg. "foo@bar.com" vs "mailto:foo@bar.com?subject=Title&body=Hello%20world"
if (!array_key_exists('href', self::$aAttrsWhiteList)) {
// Regular urls
$sUrlPattern = utils::GetConfig()->Get('url_validation_pattern');
// Mailto urls
$sMailtoPattern = '(mailto:('.utils::GetConfig()->Get('email_validation_pattern').')(?:\?(?:subject|body)=([a-zA-Z0-9+\$_.-]*)(?:&(?:subject|body)=([a-zA-Z0-9+\$_.-]*))?)?)';
// Notification placeholders
// eg. $this->caller_id$, $this->hyperlink()$, $this->hyperlink(portal)$, $APP_URL$, $MODULES_URL$, ...
// Note: Authorize both $xxx$ and %24xxx%24 as the latter one is encoded when used in HTML attributes (eg. a[href])
$sPlaceholderPattern = '(\$|%24)[\w-]*(->[\w]*(\([\w-]*?\))?)?(\$|%24)';
$sPattern = $sUrlPattern.'|'.$sMailtoPattern.'|'.$sPlaceholderPattern;
$sPattern = '/'.str_replace('/', '\/', $sPattern).'/i';
self::$aAttrsWhiteList['href'] = $sPattern;
}
}
public function GetTagsWhiteList()
{
return static::$aTagsWhiteList;
@@ -363,31 +399,6 @@ class HTMLDOMSanitizer extends DOMSanitizer
return static::$aStylesWhiteList;
}
public function __construct()
{
parent::__construct();
// Building href validation pattern from url and email validation patterns as the patterns are not used the same way in HTML content than in standard attributes value.
// eg. "foo@bar.com" vs "mailto:foo@bar.com?subject=Title&body=Hello%20world"
if (!array_key_exists('href', self::$aAttrsWhiteList))
{
// Regular urls
$sUrlPattern = utils::GetConfig()->Get('url_validation_pattern');
// Mailto urls
$sMailtoPattern = '(mailto:(' . utils::GetConfig()->Get('email_validation_pattern') . ')(?:\?(?:subject|body)=([a-zA-Z0-9+\$_.-]*)(?:&(?:subject|body)=([a-zA-Z0-9+\$_.-]*))?)?)';
// Notification placeholders
// eg. $this->caller_id$, $this->hyperlink()$, $this->hyperlink(portal)$, $APP_URL$, $MODULES_URL$, ...
// Note: Authorize both $xxx$ and %24xxx%24 as the latter one is encoded when used in HTML attributes (eg. a[href])
$sPlaceholderPattern = '(\$|%24)[\w-]*(->[\w]*(\([\w-]*?\))?)?(\$|%24)';
$sPattern = $sUrlPattern . '|' . $sMailtoPattern . '|' . $sPlaceholderPattern;
$sPattern = '/'.str_replace('/', '\/', $sPattern).'/i';
self::$aAttrsWhiteList['href'] = $sPattern;
}
}
public function LoadDoc($sHTML)
{
@$this->oDoc->loadHTML('<?xml encoding="UTF-8"?>'.$sHTML); // For loading HTML chunks where the character set is not specified

View File

@@ -17,8 +17,10 @@
// along with iTop. If not, see <http://www.gnu.org/licenses/>
//
// THIS FILE IS DEPRECATED
/*
* @deprecated 3.0.0 N°3141 - Deprecate legacy SQL build
*/
DeprecatedCallsLog::NotifyDeprecatedFile("dbobjectsearchlegacy.class.php is deprecated. Please use dbobjectsearch.class.php instead");
/** @internal Dev hack for disabling some query build optimizations (Folding/Merging) */
define('ENABLE_OPT', true);

View File

@@ -17,11 +17,13 @@
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* @deprecated 3.1.0 N°3141 - Deprecate legacy SQL build
* Associated with the metamodel -> MakeQuery/MakeQuerySingleTable
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
DeprecatedCallsLog::NotifyDeprecatedFile("querybuildercontextlegacy.class.inc.php is deprecated. Please use querybuildercontext.class.inc.php instead");
class QueryBuilderContext
{

View File

@@ -1,4 +1,8 @@
<?php
/*
* @deprecated 3.1.0 N°3141 - Deprecate legacy SQL build
*/
DeprecatedCallsLog::NotifyDeprecatedFile("querybuilderexpressionslegacy.class.inc.php is deprecated. Please use querybuilderexpressions.class.inc.php instead");
class QueryBuilderExpressions
{

View File

@@ -718,6 +718,7 @@ abstract class LogAPI
/**
* @throws \ConfigException if log wrongly configured
* @uses GetMinLogLevel
* @since 3.0.0 N°3731
*/
final public static function IsLogLevelEnabled(string $sLevel, string $sChannel, string $sConfigKey = self::ENUM_CONFIG_PARAM_FILE): bool
{

View File

@@ -461,7 +461,7 @@ abstract class MetaModel
$oStyle = self::$m_aClassParams[$sClass]['style'];
$sIcon = $oStyle->GetIconAsAbsUrl();
}
if (strlen($sIcon) == 0) {
if (utils::StrLen($sIcon) == 0) {
$sParentClass = self::GetParentPersistentClass($sClass);
if (strlen($sParentClass) > 0) {
return self::GetClassIcon($sParentClass, $bImgTag, $sMoreStyles);
@@ -494,7 +494,7 @@ abstract class MetaModel
$oStyle = new ormStyle("ibo-class-style--$sClass", "ibo-class-style-alt--$sClass");
}
if ((strlen($oStyle->GetMainColor()) > 0) && (strlen($oStyle->GetComplementaryColor()) > 0) && (strlen($oStyle->GetIconAsRelPath()) > 0)) {
if ((utils::StrLen($oStyle->GetMainColor()) > 0) && (utils::StrLen($oStyle->GetComplementaryColor()) > 0) && (utils::StrLen($oStyle->GetIconAsRelPath()) > 0)) {
// all the parameters are set, no need to search in the parent classes
return $oStyle;
}
@@ -504,18 +504,18 @@ abstract class MetaModel
while (strlen($sParentClass) > 0) {
$oParentStyle = self::GetClassStyle($sParentClass);
if (!is_null($oParentStyle)) {
if (strlen($oStyle->GetMainColor()) == 0) {
if (utils::StrLen($oStyle->GetMainColor()) == 0) {
$oStyle->SetMainColor($oParentStyle->GetMainColor());
$oStyle->SetStyleClass($oParentStyle->GetStyleClass());
}
if (strlen($oStyle->GetComplementaryColor()) == 0) {
if (utils::StrLen($oStyle->GetComplementaryColor()) == 0) {
$oStyle->SetComplementaryColor($oParentStyle->GetComplementaryColor());
$oStyle->SetAltStyleClass($oParentStyle->GetAltStyleClass());
}
if (strlen($oStyle->GetIconAsRelPath()) == 0) {
if (utils::StrLen($oStyle->GetIconAsRelPath()) == 0) {
$oStyle->SetIcon($oParentStyle->GetIconAsRelPath());
}
if ((strlen($oStyle->GetMainColor()) > 0) && (strlen($oStyle->GetComplementaryColor()) > 0) && (strlen($oStyle->GetIconAsRelPath()) > 0)) {
if ((utils::StrLen($oStyle->GetMainColor()) > 0) && (utils::StrLen($oStyle->GetComplementaryColor()) > 0) && (utils::StrLen($oStyle->GetIconAsRelPath()) > 0)) {
// all the parameters are set, no need to search in the parent classes
return $oStyle;
}
@@ -523,7 +523,7 @@ abstract class MetaModel
$sParentClass = self::GetParentPersistentClass($sParentClass);
}
if ((strlen($oStyle->GetMainColor()) == 0) && (strlen($oStyle->GetComplementaryColor()) == 0) && (strlen($oStyle->GetIconAsRelPath()) == 0)) {
if ((utils::StrLen($oStyle->GetMainColor()) == 0) && (utils::StrLen($oStyle->GetComplementaryColor()) == 0) && (utils::StrLen($oStyle->GetIconAsRelPath()) == 0)) {
return null;
}
@@ -1119,9 +1119,7 @@ abstract class MetaModel
return self::$m_aAttribOrigins[$sClass][$sAttCode];
}
/**
* @deprecated do not use : dead code, will be removed in the future
*
/** *
* @param string $sClass
* @param string $sAttCode
*
@@ -1130,9 +1128,11 @@ abstract class MetaModel
*/
final public static function GetFilterCodeOrigin($sClass, $sAttCode)
{
self::_check_subclass($sClass);
if ($sAttCode == 'id') {
return MetaModel::GetRootClass($sClass);
}
return self::$m_aFilterOrigins[$sClass][$sAttCode];
return MetaModel::GetAttributeOrigin($sClass, self::$m_aFilterAttribList[$sClass][$sAttCode]);
}
/**
@@ -1481,7 +1481,6 @@ abstract class MetaModel
}
/**
* @deprecated do not use : dead code, will be removed in the future
*
* @param string $sClass
*
@@ -1490,11 +1489,9 @@ abstract class MetaModel
*/
final public static function GetFiltersList($sClass)
{
// cannot notify depreciation for now as this is still MASSIVELY used in iTop core !
//DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use : dead code, will be removed in the future');
self::_check_subclass($sClass);
return array_keys(self::$m_aFilterDefs[$sClass]);
return array_keys(self::$m_aFilterAttribList[$sClass]);
}
/**
@@ -1564,9 +1561,7 @@ abstract class MetaModel
$oKeyAttDef = MetaModel::GetAttributeDef($sClass, $sExtKeyAttCode);
$sRemoteClass = $oKeyAttDef->GetTargetClass();
$bRes = MetaModel::IsValidAttCode($sRemoteClass, $sRemoteAttCode, true);
}
else
{
} else {
$bRes = false;
}
}
@@ -1591,7 +1586,6 @@ abstract class MetaModel
}
/**
* @deprecated do not use : dead code, will be removed in the future
*
* @param string $sClass
* @param string $sFilterCode
@@ -1600,13 +1594,11 @@ abstract class MetaModel
*/
final public static function IsValidFilterCode($sClass, $sFilterCode)
{
// cannot notify depreciation for now as this is still MASSIVELY used in iTop core !
//DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use : dead code, will be removed in the future');
if (!array_key_exists($sClass, self::$m_aFilterDefs)) {
if (!array_key_exists($sClass, self::$m_aFilterAttribList)) {
return false;
}
return (array_key_exists($sFilterCode, self::$m_aFilterDefs[$sClass]));
return (array_key_exists($sFilterCode, self::$m_aFilterAttribList[$sClass]));
}
/**
@@ -1880,31 +1872,21 @@ abstract class MetaModel
public static function GetDescription($sClass, $sAttCode)
{
$oAttDef = self::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef)
{
if ($oAttDef) {
return $oAttDef->GetDescription();
}
return "";
}
/**
* Filters of a given class may contain filters defined in a parent class
* - Some filters are a copy of the definition
* - Some filters correspond to the upper class table definition (compound objects)
* (see also attributes definition)
*
* @deprecated do not use : dead code, will be removed in the future
* @var array array of ("classname" => array filterdef)
* @var array array of (FilterCode => AttributeCode)
*/
private static $m_aFilterDefs = array();
/**
* @deprecated do not use : dead code, will be removed in the future
* @var array array of ("classname" => array of ("attcode"=>"sourceclass"))
*/
private static $m_aFilterOrigins = array();
private static $m_aFilterAttribList = array();
/**
* @deprecated do not use : dead code, will be removed in the future
* @deprecated 3.0.0 do not use : dead code, will be removed in the future N°4690 - Deprecate "FilterCodes"
* instead of array_keys(MetaModel::GetClassFilterDefs($sClass)); use MetaModel::GetFiltersList($sClass)
*
* @param string $sClass
*
@@ -1914,34 +1896,25 @@ abstract class MetaModel
public static function GetClassFilterDefs($sClass)
{
// cannot notify depreciation for now as this is still MASSIVELY used in iTop core !
//DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use : dead code, will be removed in the future');
self::_check_subclass($sClass);
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use MetaModel::GetClassFilterDefs: dead code, will be removed in the future. Use MetaModel::GetFiltersList or MetaModel::GetFiltersAttributes');
return self::$m_aFilterDefs[$sClass];
return self::$m_aFilterAttribList[$sClass];
}
/**
* @deprecated do not use : dead code, will be removed in the future
*
* @param string $sClass
* @param string $sFilterCode
*
* @return mixed
* @return array ($sFilterCode=>$sAttributeCode) + id=>id
* @throws \CoreException
*/
final public static function GetClassFilterDef($sClass, $sFilterCode)
public static function GetFilterAttribList($sClass)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use : dead code, will be removed in the future');
self::_check_subclass($sClass);
if (!array_key_exists($sFilterCode, self::$m_aFilterDefs[$sClass])) {
throw new CoreException("Unknown filter code '$sFilterCode' for class '$sClass'");
}
return self::$m_aFilterDefs[$sClass][$sFilterCode];
return self::$m_aFilterAttribList[$sClass];
}
/**
* @deprecated do not use : dead code, will be removed in the future
* @deprecated 3.0.0 do not use : dead code, will be removed in the future use GetLabel instead N°4690 - Deprecate "FilterCodes"
*
* @param string $sClass
* @param string $sFilterCode
@@ -1951,103 +1924,9 @@ abstract class MetaModel
*/
public static function GetFilterLabel($sClass, $sFilterCode)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use : dead code, will be removed in the future');
$oFilter = self::GetClassFilterDef($sClass, $sFilterCode);
if ($oFilter) {
return $oFilter->GetLabel();
}
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use MetaModel::GetFilterLabel : dead code, will be removed in the future. Use MetaModel::GetLabel instead');
return "";
}
/**
* @deprecated do not use : dead code, will be removed in the future
* @param string $sClass
* @param string $sFilterCode
*
* @return string
* @throws \CoreException
*/
public static function GetFilterDescription($sClass, $sFilterCode)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use : dead code, will be removed in the future');
$oFilter = self::GetClassFilterDef($sClass, $sFilterCode);
if ($oFilter) {
return $oFilter->GetDescription();
}
return "";
}
/**
* @deprecated do not use : dead code, will be removed in the future
* @param string $sClass
* @param string $sFilterCode
*
* @return array
* @throws \CoreException
*/
public static function GetFilterOperators($sClass, $sFilterCode)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use : dead code, will be removed in the future');
$oFilter = self::GetClassFilterDef($sClass, $sFilterCode);
if ($oFilter) {
return $oFilter->GetOperators();
}
return array();
}
/**
* @deprecated do not use : dead code, will be removed in the future
* @param string $sClass
* @param string $sFilterCode
*
* @return array
* @throws \CoreException
*/
public static function GetFilterLooseOperator($sClass, $sFilterCode)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use : dead code, will be removed in the future');
$oFilter = self::GetClassFilterDef($sClass, $sFilterCode);
if ($oFilter) {
return $oFilter->GetLooseOperator();
}
return array();
}
/**
* @deprecated do not use : dead code, will be removed in the future
* @param string $sClass
* @param string $sFilterCode
* @param string $sOpCode
*
* @return string
* @throws \CoreException
*/
public static function GetFilterOpDescription($sClass, $sFilterCode, $sOpCode)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use : dead code, will be removed in the future');
$oFilter = self::GetClassFilterDef($sClass, $sFilterCode);
if ($oFilter) {
return $oFilter->GetOpDescription($sOpCode);
}
return "";
}
/**
* @deprecated do not use : dead code, will be removed in the future
* @param string $sFilterCode
*
* @return string
*/
public static function GetFilterHTMLInput($sFilterCode)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use : dead code, will be removed in the future');
return "<INPUT name=\"$sFilterCode\">";
return this::GetLabel($sClass, $sFilterCode);
}
/**
@@ -2889,6 +2768,8 @@ abstract class MetaModel
}
/**
* @deprecated 3.1.0 use GetAllowedValues_att N°4690 - Deprecate "FilterCodes"
*
* @param string $sClass
* @param string $sFltCode
* @param array $aArgs
@@ -2899,10 +2780,12 @@ abstract class MetaModel
*/
public static function GetAllowedValues_flt($sClass, $sFltCode, $aArgs = array(), $sContains = '')
{
$oFltDef = self::GetClassFilterDef($sClass, $sFltCode);
return $oFltDef->GetAllowedValues($aArgs, $sContains);
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use MetaModel::GetAllowedValues_flt: dead code, will be removed in the future. Use MetaModel::GetAllowedValues');
return self::GetAllowedValues_att($sClass, $sFltCode);
}
/**
* @param string $sClass
* @param string $sAttCode
@@ -2969,17 +2852,14 @@ abstract class MetaModel
private static function AddMagicAttribute(AttributeDefinition $oAttribute, $sTargetClass, $sOriginClass = null)
{
$sCode = $oAttribute->GetCode();
if (is_null($sOriginClass))
{
if (is_null($sOriginClass)) {
$sOriginClass = $sTargetClass;
}
$oAttribute->SetHostClass($sTargetClass);
self::$m_aAttribDefs[$sTargetClass][$sCode] = $oAttribute;
self::$m_aAttribOrigins[$sTargetClass][$sCode] = $sOriginClass;
$oFlt = new FilterFromAttribute($oAttribute);
self::$m_aFilterDefs[$sTargetClass][$sCode] = $oFlt;
self::$m_aFilterOrigins[$sTargetClass][$sCode] = $sOriginClass;
self::$m_aFilterAttribList[$sTargetClass][$sCode] = $sCode;
}
/**
@@ -3171,44 +3051,38 @@ abstract class MetaModel
self::$m_aClassParams[$sRootClass]["db_finalclass_field"] = 'finalclass';
}
$oClassAtt = new AttributeFinalClass('finalclass', array(
"sql" => $sDbFinalClassField,
"default_value" => $sRootClass,
"sql" => $sDbFinalClassField,
"default_value" => $sRootClass,
"is_null_allowed" => false,
"depends_on" => array()
"depends_on" => array(),
));
self::AddMagicAttribute($oClassAtt, $sRootClass);
$bObsoletable = array_key_exists($sRootClass, $aObsoletableRootClasses);
if ($bObsoletable && is_null(self::$m_aClassParams[$sRootClass]['obsolescence_expression']))
{
if ($bObsoletable && is_null(self::$m_aClassParams[$sRootClass]['obsolescence_expression'])) {
self::$m_aClassParams[$sRootClass]['obsolescence_expression'] = '0';
}
foreach(self::EnumChildClasses($sRootClass, ENUM_CHILD_CLASSES_EXCLUDETOP) as $sChildClass)
{
if (array_key_exists('finalclass', self::$m_aAttribDefs[$sChildClass]))
{
foreach (self::EnumChildClasses($sRootClass, ENUM_CHILD_CLASSES_EXCLUDETOP) as $sChildClass) {
if (array_key_exists('finalclass', self::$m_aAttribDefs[$sChildClass])) {
throw new CoreException("Class $sChildClass, 'finalclass' is a reserved keyword, it cannot be used as an attribute code");
}
if (array_key_exists('finalclass', self::$m_aFilterDefs[$sChildClass]))
{
if (array_key_exists('finalclass', self::$m_aFilterAttribList[$sChildClass])) {
throw new CoreException("Class $sChildClass, 'finalclass' is a reserved keyword, it cannot be used as a filter code");
}
$oCloned = clone $oClassAtt;
$oCloned->SetFixedValue($sChildClass);
self::AddMagicAttribute($oCloned, $sChildClass, $sRootClass);
if ($bObsoletable && is_null(self::$m_aClassParams[$sChildClass]['obsolescence_expression']))
{
if ($bObsoletable && is_null(self::$m_aClassParams[$sChildClass]['obsolescence_expression'])) {
self::$m_aClassParams[$sChildClass]['obsolescence_expression'] = '0';
}
}
}
// Add magic attributes to the classes
foreach(self::GetClasses() as $sClass)
{
foreach (self::GetClasses() as $sClass) {
$sRootClass = self::$m_aRootClasses[$sClass];
// Create the friendly name attribute
@@ -3216,40 +3090,35 @@ abstract class MetaModel
$oFriendlyName = new AttributeFriendlyName($sFriendlyNameAttCode);
self::AddMagicAttribute($oFriendlyName, $sClass);
if (self::$m_aClassParams[$sClass]["archive_root"])
{
if (self::$m_aClassParams[$sClass]["archive_root"]) {
// Create archive attributes on top the archivable hierarchy
$oArchiveFlag = new AttributeArchiveFlag('archive_flag');
self::AddMagicAttribute($oArchiveFlag, $sClass);
$oArchiveDate = new AttributeArchiveDate('archive_date', array('magic' => true, "allowed_values" => null, "sql" => 'archive_date', "default_value" => '', "is_null_allowed" => true, "depends_on" => array()));
self::AddMagicAttribute($oArchiveDate, $sClass);
}
elseif (self::$m_aClassParams[$sClass]["archive"])
{
} elseif (self::$m_aClassParams[$sClass]["archive"]) {
$sArchiveRoot = self::$m_aClassParams[$sClass]['archive_root_class'];
// Inherit archive attributes
$oArchiveFlag = clone self::$m_aAttribDefs[$sArchiveRoot]['archive_flag'];
$oArchiveFlag->SetHostClass($sClass);
self::$m_aAttribDefs[$sClass]['archive_flag'] = $oArchiveFlag;
self::$m_aAttribOrigins[$sClass]['archive_flag'] = $sArchiveRoot;
$oArchiveDate = clone self::$m_aAttribDefs[$sArchiveRoot]['archive_date'];
$oArchiveDate->SetHostClass($sClass);
self::$m_aAttribDefs[$sClass]['archive_date'] = $oArchiveDate;
self::$m_aAttribOrigins[$sClass]['archive_date'] = $sArchiveRoot;
}
if (!is_null(self::$m_aClassParams[$sClass]['obsolescence_expression']))
{
if (!is_null(self::$m_aClassParams[$sClass]['obsolescence_expression'])) {
$oObsolescenceFlag = new AttributeObsolescenceFlag('obsolescence_flag');
self::AddMagicAttribute($oObsolescenceFlag, $sClass);
if (self::$m_aRootClasses[$sClass] == $sClass)
{
if (self::$m_aRootClasses[$sClass] == $sClass) {
$oObsolescenceDate = new AttributeObsolescenceDate('obsolescence_date', array('magic' => true, "allowed_values" => null, "sql" => 'obsolescence_date', "default_value" => '', "is_null_allowed" => true, "depends_on" => array()));
self::AddMagicAttribute($oObsolescenceDate, $sClass);
}
else
{
} else {
$oObsolescenceDate = clone self::$m_aAttribDefs[$sRootClass]['obsolescence_date'];
$oObsolescenceDate->SetHostClass($sClass);
self::$m_aAttribDefs[$sClass]['obsolescence_date'] = $oObsolescenceDate;
@@ -3261,40 +3130,24 @@ abstract class MetaModel
// Prepare external fields and filters
// Add final class to external keys
// Add magic attributes to external keys (finalclass, friendlyname, archive_flag, obsolescence_flag)
foreach(self::GetClasses() as $sClass)
{
foreach(self::$m_aAttribDefs[$sClass] as $sAttCode => $oAttDef)
{
foreach (self::GetClasses() as $sClass) {
foreach (self::$m_aAttribDefs[$sClass] as $sAttCode => $oAttDef) {
// Compute the filter codes
//
foreach($oAttDef->GetFilterDefinitions() as $sFilterCode => $oFilterDef)
{
self::$m_aFilterDefs[$sClass][$sFilterCode] = $oFilterDef;
if ($oAttDef->IsExternalField())
{
$sKeyAttCode = $oAttDef->GetKeyAttCode();
$oKeyDef = self::GetAttributeDef($sClass, $sKeyAttCode);
self::$m_aFilterOrigins[$sClass][$sFilterCode] = $oKeyDef->GetTargetClass();
}
else
{
self::$m_aFilterOrigins[$sClass][$sFilterCode] = self::$m_aAttribOrigins[$sClass][$sAttCode];
}
foreach ($oAttDef->GetFilterDefinitions() as $sFilterCode => $sCode) {
self::$m_aFilterAttribList[$sClass][$sFilterCode] = $sCode;
}
// Compute the fields that will be used to display a pointer to another object
//
if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE))
{
if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) {
// oAttDef is either
// - an external KEY / FIELD (direct),
// - an external field pointing to an external KEY / FIELD
// - an external field pointing to an external field pointing to....
$sRemoteClass = $oAttDef->GetTargetClass(EXTKEY_ABSOLUTE);
if ($oAttDef->IsExternalField())
{
if ($oAttDef->IsExternalField()) {
// This is a key, but the value comes from elsewhere
// Create an external field pointing to the remote friendly name attribute
$sKeyAttCode = $oAttDef->GetKeyAttCode();
@@ -3302,24 +3155,21 @@ abstract class MetaModel
$sFriendlyNameAttCode = $sAttCode.'_friendlyname';
$oFriendlyName = new AttributeExternalField($sFriendlyNameAttCode, array("allowed_values" => null, "extkey_attcode" => $sKeyAttCode, "target_attcode" => $sRemoteAttCode, "depends_on" => array()));
self::AddMagicAttribute($oFriendlyName, $sClass, self::$m_aAttribOrigins[$sClass][$sKeyAttCode]);
}
else
{
} else {
// Create the friendly name attribute
$sFriendlyNameAttCode = $sAttCode.'_friendlyname';
$oFriendlyName = new AttributeExternalField($sFriendlyNameAttCode, array('allowed_values' => null, 'extkey_attcode' => $sAttCode, "target_attcode" => 'friendlyname', 'depends_on' => array()));
self::AddMagicAttribute($oFriendlyName, $sClass, self::$m_aAttribOrigins[$sClass][$sAttCode]);
if (self::HasChildrenClasses($sRemoteClass))
{
if (self::HasChildrenClasses($sRemoteClass)) {
// First, create an external field attribute, that gets the final class
$sClassRecallAttCode = $sAttCode.'_finalclass_recall';
$oClassRecall = new AttributeExternalField($sClassRecallAttCode, array(
"allowed_values" => null,
"extkey_attcode" => $sAttCode,
"target_attcode" => "finalclass",
"allowed_values" => null,
"extkey_attcode" => $sAttCode,
"target_attcode" => "finalclass",
"is_null_allowed" => true,
"depends_on" => array()
"depends_on" => array(),
));
self::AddMagicAttribute($oClassRecall, $sClass, self::$m_aAttribOrigins[$sClass][$sAttCode]);
@@ -3350,18 +3200,14 @@ abstract class MetaModel
}
}
if (self::IsArchivable($sRemoteClass))
{
if (self::IsArchivable($sRemoteClass)) {
$sCode = $sAttCode.'_archive_flag';
if ($oAttDef->IsExternalField())
{
if ($oAttDef->IsExternalField()) {
// This is a key, but the value comes from elsewhere
// Create an external field pointing to the remote attribute
$sKeyAttCode = $oAttDef->GetKeyAttCode();
$sRemoteAttCode = $oAttDef->GetExtAttCode().'_archive_flag';
}
else
{
} else {
$sKeyAttCode = $sAttCode;
$sRemoteAttCode = 'archive_flag';
}
@@ -3369,18 +3215,14 @@ abstract class MetaModel
self::AddMagicAttribute($oMagic, $sClass, self::$m_aAttribOrigins[$sClass][$sKeyAttCode]);
}
if (self::IsObsoletable($sRemoteClass))
{
if (self::IsObsoletable($sRemoteClass)) {
$sCode = $sAttCode.'_obsolescence_flag';
if ($oAttDef->IsExternalField())
{
if ($oAttDef->IsExternalField()) {
// This is a key, but the value comes from elsewhere
// Create an external field pointing to the remote attribute
$sKeyAttCode = $oAttDef->GetKeyAttCode();
$sRemoteAttCode = $oAttDef->GetExtAttCode().'_obsolescence_flag';
}
else
{
} else {
$sKeyAttCode = $sAttCode;
$sRemoteAttCode = 'obsolescence_flag';
}
@@ -3388,11 +3230,9 @@ abstract class MetaModel
self::AddMagicAttribute($oMagic, $sClass, self::$m_aAttribOrigins[$sClass][$sKeyAttCode]);
}
}
if ($oAttDef instanceof AttributeMetaEnum)
{
if ($oAttDef instanceof AttributeMetaEnum) {
$aMappingData = $oAttDef->GetMapRule($sClass);
if ($aMappingData != null)
{
if ($aMappingData != null) {
$sEnumAttCode = $aMappingData['attcode'];
self::$m_aEnumToMeta[$sClass][$sEnumAttCode][$sAttCode] = $oAttDef;
}
@@ -3401,17 +3241,10 @@ abstract class MetaModel
// Add a 'id' filter
//
if (array_key_exists('id', self::$m_aAttribDefs[$sClass]))
{
if (array_key_exists('id', self::$m_aAttribDefs[$sClass])) {
throw new CoreException("Class $sClass, 'id' is a reserved keyword, it cannot be used as an attribute code");
}
if (array_key_exists('id', self::$m_aFilterDefs[$sClass]))
{
throw new CoreException("Class $sClass, 'id' is a reserved keyword, it cannot be used as a filter code");
}
$oFilter = new FilterPrivateKey('id', array('id_field' => self::DBGetKey($sClass)));
self::$m_aFilterDefs[$sClass]['id'] = $oFilter;
self::$m_aFilterOrigins[$sClass]['id'] = $sClass;
self::$m_aFilterAttribList[$sClass]['id'] = 'id';
}
}
@@ -3571,8 +3404,7 @@ abstract class MetaModel
self::$m_aAttribDefs[$sClass] = array();
self::$m_aAttribOrigins[$sClass] = array();
self::$m_aFilterDefs[$sClass] = array();
self::$m_aFilterOrigins[$sClass] = array();
self::$m_aFilterAttribList[$sClass] = array();
}
/**
@@ -3602,25 +3434,20 @@ abstract class MetaModel
public static function Init_InheritAttributes($sSourceClass = null)
{
$sTargetClass = self::GetCallersPHPClass("Init");
if (empty($sSourceClass))
{
if (empty($sSourceClass)) {
// Default: inherit from parent class
$sSourceClass = self::GetParentPersistentClass($sTargetClass);
if (empty($sSourceClass))
{
if (empty($sSourceClass)) {
return;
} // no attributes for the mother of all classes
}
if (isset(self::$m_aAttribDefs[$sSourceClass]))
{
if (!isset(self::$m_aAttribDefs[$sTargetClass]))
{
if (isset(self::$m_aAttribDefs[$sSourceClass])) {
if (!isset(self::$m_aAttribDefs[$sTargetClass])) {
self::$m_aAttribDefs[$sTargetClass] = array();
self::$m_aAttribOrigins[$sTargetClass] = array();
}
self::$m_aAttribDefs[$sTargetClass] = self::object_array_mergeclone(self::$m_aAttribDefs[$sTargetClass], self::$m_aAttribDefs[$sSourceClass]);
foreach(self::$m_aAttribDefs[$sTargetClass] as $sAttCode => $oAttDef)
{
foreach (self::$m_aAttribDefs[$sTargetClass] as $sAttCode => $oAttDef) {
$oAttDef->SetHostClass($sTargetClass);
}
self::$m_aAttribOrigins[$sTargetClass] = array_merge(self::$m_aAttribOrigins[$sTargetClass], self::$m_aAttribOrigins[$sSourceClass]);
@@ -3675,22 +3502,18 @@ abstract class MetaModel
*/
public static function Init_AddAttribute(AttributeDefinition $oAtt, $sTargetClass = null)
{
if (!$sTargetClass)
{
if (!$sTargetClass) {
$sTargetClass = self::GetCallersPHPClass("Init");
}
$sAttCode = $oAtt->GetCode();
if ($sAttCode == 'finalclass')
{
if ($sAttCode == 'finalclass') {
throw new Exception("Declaration of $sTargetClass: using the reserved keyword '$sAttCode' in attribute declaration");
}
if ($sAttCode == 'friendlyname')
{
if ($sAttCode == 'friendlyname') {
throw new Exception("Declaration of $sTargetClass: using the reserved keyword '$sAttCode' in attribute declaration");
}
if (array_key_exists($sAttCode, self::$m_aAttribDefs[$sTargetClass]))
{
if (array_key_exists($sAttCode, self::$m_aAttribDefs[$sTargetClass])) {
throw new Exception("Declaration of $sTargetClass: attempting to redeclare the inherited attribute '$sAttCode', originally declared in ".self::$m_aAttribOrigins[$sTargetClass][$sAttCode]);
}
@@ -3727,6 +3550,7 @@ abstract class MetaModel
{
// The corresponding external key has already been ignored
self::$m_aIgnoredAttributes[$sTargetClass][$oAtt->GetCode()] = self::$m_aIgnoredAttributes[$sTargetClass][$sExtKeyAttCode];
return;
}
//TODO Check if the target attribute is still there
@@ -4989,18 +4813,6 @@ abstract class MetaModel
}
}
}
foreach(self::GetClassFilterDefs($sClass) as $sFltCode => $oFilterDef)
{
if (method_exists($oFilterDef, '__GetRefAttribute'))
{
$oAttDef = $oFilterDef->__GetRefAttribute();
if (!self::IsValidAttCode($sClass, $oAttDef->GetCode()))
{
$aErrors[$sClass][] = "Wrong attribute code '".$oAttDef->GetCode()."' (wrong class) for the \"basic\" filter $sFltCode";
$aSugFix[$sClass][] = "Expecting a value in {".implode(", ", self::GetAttributesList($sClass))."}";
}
}
}
// Lifecycle
//
@@ -6619,16 +6431,14 @@ abstract class MetaModel
// classes have to be derived from cmdbabstract (to be editable in the UI)
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
if (!defined('MODULESROOT'))
{
if (!defined('MODULESROOT')) {
define('MODULESROOT', APPROOT.'env-'.self::$m_sEnvironment.'/');
}
require_once(APPROOT.'core/autoload.php');
require_once(APPROOT.'env-'.self::$m_sEnvironment.'/autoload.php');
foreach(self::$m_oConfig->GetAddons() as $sModule => $sToInclude)
{
foreach (self::$m_oConfig->GetAddons() as $sModule => $sToInclude) {
self::IncludeModule($sToInclude, 'addons');
}
@@ -6636,16 +6446,14 @@ abstract class MetaModel
$sTablePrefix = self::$m_oConfig->Get('db_subname');
$oKPI->ComputeAndReport('Load config');
if (self::$m_bUseAPCCache)
{
if (self::$m_bUseAPCCache) {
$oKPI = new ExecutionKPI();
// Note: For versions of APC older than 3.0.17, fetch() accepts only one parameter
//
$sOqlAPCCacheId = 'itop-'.MetaModel::GetEnvironmentId().'-metamodel';
$result = apc_fetch($sOqlAPCCacheId);
if (is_array($result))
{
if (is_array($result)) {
// todo - verifier que toutes les classes mentionnees ici sont chargees dans InitClasses()
self::$m_aExtensionClassNames = $result['m_aExtensionClassNames'];
self::$m_Category2Class = $result['m_Category2Class'];
@@ -6656,8 +6464,7 @@ abstract class MetaModel
self::$m_aAttribDefs = $result['m_aAttribDefs'];
self::$m_aAttribOrigins = $result['m_aAttribOrigins'];
self::$m_aIgnoredAttributes = $result['m_aIgnoredAttributes'];
self::$m_aFilterDefs = $result['m_aFilterDefs'];
self::$m_aFilterOrigins = $result['m_aFilterOrigins'];
self::$m_aFilterAttribList = $result['m_aFilterList'];
self::$m_aListInfos = $result['m_aListInfos'];
self::$m_aListData = $result['m_aListData'];
self::$m_aRelationInfos = $result['m_aRelationInfos'];
@@ -6693,8 +6500,7 @@ abstract class MetaModel
$aCache['m_aAttribDefs'] = self::$m_aAttribDefs; // array of ("classname" => array of attributes)
$aCache['m_aAttribOrigins'] = self::$m_aAttribOrigins; // array of ("classname" => array of ("attcode"=>"sourceclass"))
$aCache['m_aIgnoredAttributes'] = self::$m_aIgnoredAttributes; //array of ("classname" => array of ("attcode")
$aCache['m_aFilterDefs'] = self::$m_aFilterDefs; // array of ("classname" => array filterdef)
$aCache['m_aFilterOrigins'] = self::$m_aFilterOrigins; // array of ("classname" => array of ("attcode"=>"sourceclass"))
$aCache['m_aFilterList'] = self::$m_aFilterAttribList; // array of ("classname" => array filterdef)
$aCache['m_aListInfos'] = self::$m_aListInfos; // array of ("listcode" => various info on the list, common to every classes)
$aCache['m_aListData'] = self::$m_aListData; // array of ("classname" => array of "listcode" => list)
$aCache['m_aRelationInfos'] = self::$m_aRelationInfos; // array of ("relcode" => various info on the list, common to every classes)
@@ -7274,38 +7080,11 @@ abstract class MetaModel
}
/**
* Deletion of records, bypassing {@link DBObject::DBDelete} !!!
* It is NOT recommended to use this shortcut
* In particular, it will not work
* - if the class is not a final class
* - if the class has a hierarchical key (need to rebuild the indexes)
* - if the class overload DBDelete !
* @internal
*
* @deprecated do not use : dead code, will be removed in the future
* @experimental
*
* @param \DBObjectSearch $oFilter
*
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @todo: protect it against forbidden usages (in such a case, delete objects one by one)
*
*/
public static function BulkDelete(DBObjectSearch $oFilter)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use : dead code, will be removed in the future');
$sSQL = $oFilter->MakeDeleteQuery();
if (!self::DBIsReadOnly()) {
CMDBSource::Query($sSQL);
}
}
/**
* @param DBObjectSearch $oFilter
* @param array $aValues array of attcode => value
* @param DBObjectSearch $oFilter
*
* @deprecated do not use : dead code, will be removed in the future
* @experimental
* @return int Modified objects
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException

View File

@@ -107,7 +107,7 @@ abstract class Expression {
/**
* recursive rendering
*
* @deprecated use RenderExpression
* @deprecated 3.0.0 use RenderExpression
*
* @param array $aArgs used as input by default, or used as output if bRetrofitParams set to True
* @param bool $bRetrofitParams
@@ -118,7 +118,7 @@ abstract class Expression {
public function Render(&$aArgs = null, $bRetrofitParams = false)
{
// cannot notify depreciation for now as this is still MASSIVELY used in iTop core !
//DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use RenderExpression');
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use RenderExpression');
return $this->RenderExpression(false, $aArgs, $bRetrofitParams);
}
@@ -1765,6 +1765,7 @@ class FieldExpression extends UnaryExpression
*/
public function MakeValueLabel($oFilter, $sValue, $sDefault)
{
$sAttCode = $this->GetName();
$sParentAlias = $this->GetParent();
@@ -2762,25 +2763,96 @@ class FunctionExpression extends Expression
return $iRet;
case 'DATE_FORMAT':
if (count($this->m_aArgs) != 2)
{
if (count($this->m_aArgs) != 2) {
throw new \Exception("Function {$this->m_sVerb} requires 2 arguments");
}
$oDate = new DateTime($this->m_aArgs[0]->Evaluate($aArgs));
$sFormat = $this->m_aArgs[1]->Evaluate($aArgs);
$sFormat = str_replace(
array('%y', '%x', '%w', '%W', '%v', '%T', '%S', '%r', '%p', '%M', '%l', '%k', '%I', '%h', '%b', '%a', '%D', '%c', '%e', '%Y', '%d', '%m', '%H', '%i', '%s'),
array('y', 'o', 'w', 'l', 'W', 'H:i:s', 's', 'h:i:s A', 'A', 'F', 'g', 'H', 'h', 'h','M', 'D', 'jS', 'n', 'j', 'Y', 'd', 'm', 'H', 'i', 's'),
$sFormat);
if (preg_match('/%j/', $sFormat))
{
$sFormat = str_replace('%j', date_format($oDate, 'z') + 1, $sFormat);
}
if (preg_match('/%[fUuVX]/', $sFormat))
{
$sFormatForMysqlDateFormat = $this->m_aArgs[1]->Evaluate($aArgs);
if (preg_match('/%[fUuVX]/', $sFormatForMysqlDateFormat)) {
throw new NotYetEvaluatedExpression("Expression ".$this->RenderExpression().' cannot be evaluated (known limitation)');
}
$sRet = date_format($oDate, $sFormat);
if (preg_match('/%j/', $sFormatForMysqlDateFormat)) {
$sFormatForMysqlDateFormat = str_replace('%j', 'z', $sFormatForMysqlDateFormat);
$sRet = date_format($oDate, $sFormatForMysqlDateFormat);
$sRet++;
/** @noinspection PhpUnnecessaryLocalVariableInspection */
$sRet = str_pad($sRet, 3, '0', STR_PAD_LEFT);
return $sRet;
}
/**
* @var string[] $aFormatsForMysqlDateFormat
* @link https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-format
*/
//@formatter:off we want to keep every single item on its own line to ease comp between MySQL and PHP formats !
$aFormatsForMysqlDateFormat = [
'%y',
'%x',
'%w',
'%W',
'%v',
'%T',
'%S',
'%r',
'%p',
'%M',
'%l',
'%k',
'%I',
'%h',
'%b',
'%a',
'%D',
'%c',
'%e',
'%Y',
'%d',
'%m',
'%H',
'%i',
'%s'
];
//@formatter:on
/**
* @var string[] $aFormatsForPhpDateFormat
* @link https://www.php.net/manual/en/datetime.format.php
*/
//@formatter:off we want to keep every single item on its own line to ease comp between MySQL and PHP formats !
$aFormatsForPhpDateFormat = [
'y',
'o',
'w',
'l',
'W',
'H:i:s',
's',
'h:i:s A',
'A',
'F',
'g',
'G',
'h',
'h',
'M',
'D',
'jS',
'n',
'j',
'Y',
'd',
'm',
'H',
'i',
's'
];
//@formatter:on
$sFormatForPhpDateFormat = str_replace($aFormatsForMysqlDateFormat, $aFormatsForPhpDateFormat, $sFormatForMysqlDateFormat);
/** @noinspection PhpUnnecessaryLocalVariableInspection */
$sRet = date_format($oDate, $sFormatForPhpDateFormat);
return $sRet;
case 'TO_DAYS':
@@ -2978,8 +3050,7 @@ class FunctionExpression extends Expression
public function MakeValueLabel($oFilter, $sValue, $sDefault)
{
static $aWeekDayToString = null;
if (is_null($aWeekDayToString))
{
if (is_null($aWeekDayToString)) {
// Init the correspondance table
$aWeekDayToString = array(
0 => Dict::S('DayOfWeek-Sunday'),
@@ -2988,7 +3059,7 @@ class FunctionExpression extends Expression
3 => Dict::S('DayOfWeek-Wednesday'),
4 => Dict::S('DayOfWeek-Thursday'),
5 => Dict::S('DayOfWeek-Friday'),
6 => Dict::S('DayOfWeek-Saturday')
6 => Dict::S('DayOfWeek-Saturday'),
);
}
static $aMonthToString = null;
@@ -2996,15 +3067,15 @@ class FunctionExpression extends Expression
{
// Init the correspondance table
$aMonthToString = array(
1 => Dict::S('Month-01'),
2 => Dict::S('Month-02'),
3 => Dict::S('Month-03'),
4 => Dict::S('Month-04'),
5 => Dict::S('Month-05'),
6 => Dict::S('Month-06'),
7 => Dict::S('Month-07'),
8 => Dict::S('Month-08'),
9 => Dict::S('Month-09'),
1 => Dict::S('Month-01'),
2 => Dict::S('Month-02'),
3 => Dict::S('Month-03'),
4 => Dict::S('Month-04'),
5 => Dict::S('Month-05'),
6 => Dict::S('Month-06'),
7 => Dict::S('Month-07'),
8 => Dict::S('Month-08'),
9 => Dict::S('Month-09'),
10 => Dict::S('Month-10'),
11 => Dict::S('Month-11'),
12 => Dict::S('Month-12'),
@@ -3012,30 +3083,22 @@ class FunctionExpression extends Expression
}
$sRes = $sDefault;
if (strtolower($this->m_sVerb) == 'date_format')
{
if (strtolower($this->m_sVerb) == 'date_format') {
$oFormatExpr = $this->m_aArgs[1];
if ($oFormatExpr->Render() == "'%w'")
{
if (isset($aWeekDayToString[(int)$sValue]))
{
if ($oFormatExpr->RenderExpression() == "'%w'") {
if (isset($aWeekDayToString[(int)$sValue])) {
$sRes = $aWeekDayToString[(int)$sValue];
}
}
elseif ($oFormatExpr->Render() == "'%Y-%m'")
{
} elseif ($oFormatExpr->RenderExpression() == "'%Y-%m'") {
// yyyy-mm => "yyyy month"
$iMonth = (int) substr($sValue, -2); // the two last chars
$iMonth = (int)substr($sValue, -2); // the two last chars
$sRes = substr($sValue, 0, 4).' '.$aMonthToString[$iMonth];
}
elseif ($oFormatExpr->Render() == "'%Y-%m-%d'")
{
} elseif ($oFormatExpr->RenderExpression() == "'%Y-%m-%d'") {
// yyyy-mm-dd => "month d"
$iMonth = (int) substr($sValue, 5, 2);
$iMonth = (int)substr($sValue, 5, 2);
$sRes = $aMonthToString[$iMonth].' '.(int)substr($sValue, -2);
}
elseif ($oFormatExpr->Render() == "'%H'")
{
} elseif ($oFormatExpr->RenderExpression() == "'%H'") {
// H => "H Hour(s)"
$sRes = $sValue.':00';
}

View File

@@ -50,7 +50,7 @@ class ormStyle
*/
public function HasMainColor(): bool
{
return strlen($this->sMainColor) > 0;
return utils::StrLen($this->sMainColor) > 0;
}
/**
@@ -68,7 +68,7 @@ class ormStyle
*/
public function SetMainColor(?string $sMainColor)
{
$this->sMainColor = (strlen($sMainColor) === 0) ? null : $sMainColor;
$this->sMainColor = (utils::StrLen($sMainColor) === 0) ? null : $sMainColor;
return $this;
}
@@ -78,7 +78,7 @@ class ormStyle
*/
public function HasComplementaryColor(): bool
{
return strlen($this->sComplementaryColor) > 0;
return utils::StrLen($this->sComplementaryColor) > 0;
}
/**
@@ -96,7 +96,7 @@ class ormStyle
*/
public function SetComplementaryColor(?string $sComplementaryColor)
{
$this->sComplementaryColor = (strlen($sComplementaryColor) === 0) ? null : $sComplementaryColor;
$this->sComplementaryColor = (utils::StrLen($sComplementaryColor) === 0) ? null : $sComplementaryColor;
return $this;
}
@@ -116,7 +116,7 @@ class ormStyle
*/
public function HasStyleClass(): bool
{
return strlen($this->sStyleClass) > 0;
return utils::StrLen($this->sStyleClass) > 0;
}
/**
@@ -134,7 +134,7 @@ class ormStyle
*/
public function SetStyleClass(?string $sStyleClass)
{
$this->sStyleClass = (strlen($sStyleClass) === 0) ? null : $sStyleClass;
$this->sStyleClass = (utils::StrLen($sStyleClass) === 0) ? null : $sStyleClass;
return $this;
}
@@ -144,7 +144,7 @@ class ormStyle
*/
public function HasAltStyleClass(): bool
{
return strlen($this->sAltStyleClass) > 0;
return utils::StrLen($this->sAltStyleClass) > 0;
}
/**
@@ -162,7 +162,7 @@ class ormStyle
*/
public function SetAltStyleClass(?string $sAltStyleClass)
{
$this->sAltStyleClass = (strlen($sAltStyleClass) === 0) ? null : $sAltStyleClass;
$this->sAltStyleClass = (utils::StrLen($sAltStyleClass) === 0) ? null : $sAltStyleClass;
return $this;
}
@@ -172,7 +172,7 @@ class ormStyle
*/
public function HasDecorationClasses(): bool
{
return strlen($this->sDecorationClasses) > 0;
return utils::StrLen($this->sDecorationClasses) > 0;
}
/**
@@ -190,7 +190,7 @@ class ormStyle
*/
public function SetDecorationClasses(?string $sDecorationClasses)
{
$this->sDecorationClasses = (strlen($sDecorationClasses) === 0) ? null : $sDecorationClasses;
$this->sDecorationClasses = (utils::StrLen($sDecorationClasses) === 0) ? null : $sDecorationClasses;
return $this;
}
@@ -200,7 +200,7 @@ class ormStyle
*/
public function HasIcon(): bool
{
return strlen($this->sIcon) > 0;
return utils::StrLen($this->sIcon) > 0;
}
/**
@@ -210,7 +210,7 @@ class ormStyle
*/
public function SetIcon(?string $sIcon)
{
$this->sIcon = (strlen($sIcon) === 0) ? null : $sIcon;
$this->sIcon = (utils::StrLen($sIcon) === 0) ? null : $sIcon;
return $this;
}

View File

@@ -153,8 +153,7 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
*/
public function AddObject(DBObject $oObject, $sClassAlias = '')
{
// cannot notify depreciation for now as this is still MASSIVELY used in iTop core !
//DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use \ormLinkSet::AddItem() instead');
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use \ormLinkSet::AddItem() instead');
$this->AddItem($oObject);
}

View File

@@ -43,23 +43,3 @@
.ibo-svg-illustration--container > svg *[fill="#6c63ff"]{
fill: $ibo-svg-illustration--fill;
}
// N°4481 - Restore HTML tables style identical between edition and visualization
// This is a hack to compensate missing variables in the bulma lib, PR has been made here: https://github.com/jgthms/bulma/pull/3455
// The following can't be reset to it's original value (from the browser stylesheet), so we have to hardcode it even though it might change in future browser versions...
.ibo-is-html-content table {
&:not(:last-child) {
margin-bottom: 0;
}
tbody {
tr {
&:last-child {
td,
th {
border-bottom-width: 1px;
}
}
}
}
}

View File

@@ -14,7 +14,7 @@ $ibo-navigation-menu--body--background-color: $ibo-color-blue-grey-900 !default;
$ibo-navigation-menu--body--text-color: $ibo-color-grey-300 !default;
$ibo-navigation-menu--top-part--height: 120px !default;
$ibo-navigation-menu--top-part--padding-y: $ibo-navigation-menu--body--padding-y !default;
$ibo-navigation-menu--top-part--padding-y: $ibo-spacing-400 !default;
$ibo-navigation-menu--top-part--padding-x: $ibo-navigation-menu--body--padding-x !default;
$ibo-navigation-menu--top-part--elements-spacing: 20px !default;
@@ -70,13 +70,13 @@ $ibo-navigation-menu--square-company-logo--width: 38px !default;
$ibo-navigation-menu--square-company-logo--height: 38px !default;
$ibo-navigation-menu--square-company-logo--margin-top: $ibo-spacing-0 !default;
$ibo-navigation-menu--square-company-logo--margin-x: -5px !default;
$ibo-navigation-menu--square-company-logo--margin-bottom: $ibo-navigation-menu--body--padding-y * 2 !default;
$ibo-navigation-menu--square-company-logo--margin-bottom: ($ibo-navigation-menu--body--padding-y * 2) + 12px !default; /* +12px to keep burger & menu groups icons align in both expanded and collapsed mode */
$ibo-navigation-menu--full-company-logo--width: $ibo-navigation-menu--body--width-expanded !default;
$ibo-navigation-menu--full-company-logo--height: 70px !default;
$ibo-navigation-menu--full-company-logo--margin-top: $ibo-spacing-0 !default;
$ibo-navigation-menu--full-company-logo--margin-right: $ibo-spacing-0 !default;
$ibo-navigation-menu--full-company-logo--margin-bottom: $ibo-spacing-0 !default;
$ibo-navigation-menu--full-company-logo--margin-bottom: $ibo-spacing-400 !default;
$ibo-navigation-menu--full-company-logo--margin-left: -$ibo-navigation-menu--body--padding-y !default;
$ibo-navigation-menu--full-company-logo--image--margin-x: auto !default;
$ibo-navigation-menu--full-company-logo--image--margin-y: $ibo-spacing-0 !default;

View File

@@ -0,0 +1,20 @@
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
$ibo-about-box--top-part--children--padding-y: $ibo-spacing-500 !default;
$ibo-about-box--top-part--children--padding-x: $ibo-spacing-400 !default;
$ibo-about-box--top-part--children--margin-y: auto !default;
$ibo-about-box--top-part--children--margin-x: auto !default;
$ibo-about-box--top-part--children--width: 50% !default;
.ibo-about-box--top-part{
display: flex;
flex-direction: row;
align-content: center;
> div{
padding: $ibo-about-box--top-part--children--padding-y $ibo-about-box--top-part--children--padding-x;
margin: $ibo-about-box--top-part--children--margin-y $ibo-about-box--top-part--children--margin-x;
width: $ibo-about-box--top-part--children--width;
}
}

View File

@@ -3,6 +3,7 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
@import "about";
@import "base";
@import "preferences";
@import "attachments";

View File

@@ -17,8 +17,11 @@ $body-overflow-y: auto !default;
* customize Bulma content variables
* See https://bulma.io/documentation/elements/content/
*/
$content-block-margin-bottom: 0 !default;
/* Table: Reset style as much as possible to match rich text editor preview, which is the browser's default stylesheet.
* As there is no way to avoid bulma rules, we simply make them invalid by setting an invalid variable value, the rules will then be ignored by the browser.
* "!default" has been omitted on purpose as we want to overload the variables no matter what.
* See N°4481 for more information
*/
$content-table-cell-border: 'invalid on purpose';
@@ -27,5 +30,6 @@ $content-table-cell-padding: 'invalid on purpose';
$content-table-cell-heading-color: 'invalid on purpose';
$content-table-head-cell-border-width: 'invalid on purpose';
$content-table-head-cell-color: 'invalid on purpose';
$content-table-body-last-row-cell-border-bottom-width: 1px !default;
$content-table-foot-cell-border-width: 'invalid on purpose';
$content-table-foot-cell-color: 'invalid on purpose';

View File

@@ -49,7 +49,7 @@ $ibo-vendors-ckeditor--autocomplete-item-title--text-color: #3A3A3A !default;
padding: $ibo-vendors-highlightjs--padding !important;
box-shadow: 0 0px 3px 2px inset rgba(0, 0, 0, 0.4);
border-radius: $ibo-vendors-highlightjs--border-radius;
white-space: pre-line;
white-space: pre-wrap;
}
.ibo-hljs-container{

View File

@@ -1,6 +1,8 @@
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*
* Combodo modification : replaced the `Alpha(` by `alpha(` to avoid warnings generated by SCSSPHP
*/
/*
@@ -206,7 +208,7 @@ $ibo-vendors-jqueryui--ui-slider--ui-slider-handle--hover--border-color: $ibo-co
width: 100%;
height: 100%;
opacity: .6;
filter: Alpha(Opacity=60);
filter: alpha(opacity=60);
background-color: $ibo-vendors-jqueryui--ui-widget-overlay--background-color;
}
// Resiable

View File

@@ -2582,6 +2582,12 @@
}
}
}
&[data-attribute-type="AttributeDuration"] {
.field_value_container {
white-space: nowrap;
}
}
}
.one-col-details .details .field_container.field_small {

View File

@@ -59,8 +59,8 @@ a:hover {
padding-right: 20px;
padding-top: 10px;
padding-bottom: 10px;
height: 54px;
margin-top: 150px;
height: 94px;
margin-top: 110px;
}
#login-content {
@@ -75,9 +75,10 @@ a:hover {
{
#login-logo {
margin-top: 0;
padding-top: 0;
}
#login-content {
margin-top: 74px;
margin-top: 94px;
}
h1 {
margin-top: 0;
@@ -86,7 +87,7 @@ a:hover {
#login-logo img {
border: 0;
max-height: 54px;
max-height: 94px;
}
#login-form {

View File

@@ -4,6 +4,8 @@
* To view and modify this theme, visit http://jqueryui.com/themeroller/?scope=&folderName=custom-theme&bgImgOpacityError=18&bgImgOpacityHighlight=75&bgImgOpacityActive=65&bgImgOpacityHover=100&bgImgOpacityDefault=100&bgImgOpacityContent=100&bgImgOpacityHeader=35&cornerRadiusShadow=5px&offsetLeftShadow=-5px&offsetTopShadow=-5px&thicknessShadow=5px&opacityShadow=20&bgImgOpacityShadow=10&bgTextureShadow=flat&bgColorShadow=%23000000&opacityOverlay=50&bgImgOpacityOverlay=20&bgTextureOverlay=diagonals_thick&bgColorOverlay=%23666666&iconColorError=%23ffd27a&fcError=%23ffffff&borderColorError=%23cd0a0a&bgTextureError=diagonals_thick&bgColorError=%23b81900&iconColorHighlight=%231c94c4&fcHighlight=%23363636&borderColorHighlight=%23fed22f&bgTextureHighlight=flat&bgColorHighlight=%23ffe45c&iconColorActive=%23E87C1E&fcActive=%23E87C1E&borderColorActive=%23E87C1E&bgTextureActive=flat&bgColorActive=%23ffffff&iconColorHover=%23E87C1E&fcHover=%23E87C1E&borderColorHover=%23E87C1E&bgTextureHover=flat&bgColorHover=%23fde17c&iconColorDefault=%23F26522&fcDefault=%23555555&borderColorDefault=%23cccccc&bgTextureDefault=flat&bgColorDefault=%23f1f1f1&iconColorContent=%23222222&fcContent=%23333333&borderColorContent=%23dddddd&bgTextureContent=flat&bgColorContent=%23eeeeee&iconColorHeader=%23ffffff&fcHeader=%23ffffff&borderColorHeader=%23F26522&bgTextureHeader=flat&bgColorHeader=%23E87C1E&cornerRadius=0&fwDefault=bold&fsDefault=1.1em&ffDefault=Trebuchet%20MS%2CTahoma%2CVerdana%2CArial%2Csans-serif
* Copyright jQuery Foundation and other contributors; Licensed MIT
* The original css file has been scssized (through www.css2scss.com)
*
* Other modification done : replaced the `Alpha(` by `alpha(` to avoid warnings generated by SCSSPHP
*/
.ui-draggable-handle {
-ms-touch-action: none;
@@ -46,26 +48,27 @@
}
}
.ui-helper-zfix {
width: 100%;
height: 100%;
top: 0;
left: 0;
position: absolute;
opacity: 0;
filter: Alpha(Opacity=0);
width: 100%;
height: 100%;
top: 0;
left: 0;
position: absolute;
opacity: 0;
filter: alpha(Opacity=0);
}
.ui-front {
z-index: 100;
}
.ui-state-disabled {
cursor: default !important;
pointer-events: none;
opacity: .35;
filter: Alpha(Opacity=35);
background-image: none;
.ui-icon {
filter: Alpha(Opacity=35);
}
cursor: default !important;
pointer-events: none;
opacity: .35;
filter: alpha(Opacity=35);
background-image: none;
.ui-icon {
filter: alpha(Opacity=35);
}
}
.ui-icon {
display: inline-block;
@@ -93,7 +96,7 @@
height: 100%;
// background: #666666 url($approot-relative + "css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png?v=" + $version) 50% 50% repeat;
opacity: .5;
filter: Alpha(Opacity=50);
filter: alpha(Opacity=50);
}
.ui-resizable {
position: relative;
@@ -1078,13 +1081,13 @@ body {
}
.ui-priority-secondary {
opacity: .7;
filter: Alpha(Opacity=70);
filter: alpha(Opacity=70);
//font-weight: normal;
}
.ui-state-disabled {
opacity: .35;
filter: Alpha(Opacity=35);
background-image: none;
opacity: .35;
filter: alpha(Opacity=35);
background-image: none;
}
.ui-icon {
background-image: url($approot-relative + "css/ui-lightness/images/ui-icons_222222_256x240.png?v=" + $version);
@@ -1148,13 +1151,13 @@ body {
}
.ui-priority-secondary {
opacity: .7;
filter: Alpha(Opacity=70);
filter: alpha(Opacity=70);
//font-weight: normal;
}
.ui-state-disabled {
opacity: .35;
filter: Alpha(Opacity=35);
background-image: none;
opacity: .35;
filter: alpha(Opacity=35);
background-image: none;
}
.ui-icon {
background-image: url($approot-relative + "css/ui-lightness/images/ui-icons_ffffff_256x240.png?v=" + $version);
@@ -1362,7 +1365,7 @@ a {
}
.ui-priority-secondary {
opacity: .7;
filter: Alpha(Opacity=70);
filter: alpha(Opacity=70);
//font-weight: normal;
}
.ui-icon-blank {

View File

@@ -14,34 +14,4 @@
* 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;
}
*/body{display:block}#uwp-main-container{margin-top:40px}#uwp-main-container #uwp-logo,#uwp-main-container #uwp-title{vertical-align:middle;max-height:74px}#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}

View File

@@ -29,6 +29,7 @@ body{
#uwp-logo,
#uwp-title{
vertical-align: middle;
max-height: 74px;
}
#uwp-title{
margin-left: 25px;

View File

@@ -359,9 +359,7 @@ function DisplayLostAttachments(iTopWebPage &$oP, ApplicationContext &$oAppConte
$sHistoryEntry = Dict::Format('DBTools:LostAttachments:History', $oOrmDocument->GetFileName());
CMDBObject::SetTrackInfo(UserRights::GetUserFriendlyName());
$oChangeOp = MetaModel::NewObject('CMDBChangeOpPlugin');
/** @var \Change $oChange */
$oChange = CMDBObject::GetCurrentChange();
$oChangeOp->Set('change', $oChange->GetKey());
// CMDBChangeOp.change will be automatically filled
$oChangeOp->Set('objclass', $sTargetClass);
$oChangeOp->Set('objkey', $sTargetId);
$oChangeOp->Set('description', $sHistoryEntry);

View File

@@ -30,7 +30,6 @@ if (!defined('APPROOT'))
}
}
require_once(APPROOT.'application/application.inc.php');
require_once(APPROOT.'application/ajaxwebpage.class.inc.php');
require_once(APPROOT.'core/log.class.inc.php');
require_once(APPROOT.'application/startup.inc.php');

View File

@@ -30,7 +30,6 @@ if (!defined('APPROOT'))
}
}
require_once(APPROOT.'application/application.inc.php');
require_once(APPROOT.'application/ajaxwebpage.class.inc.php');
require_once(APPROOT.'core/log.class.inc.php');
require_once(APPROOT.'application/startup.inc.php');

View File

@@ -30,7 +30,6 @@ if (!defined('APPROOT'))
}
}
require_once(APPROOT.'application/application.inc.php');
require_once(APPROOT.'application/ajaxwebpage.class.inc.php');
require_once(APPROOT.'core/log.class.inc.php');
require_once(APPROOT.'application/startup.inc.php');
require_once(dirname(__FILE__).'/dbrestore.class.inc.php');

View File

@@ -5828,30 +5828,69 @@
<type>Overload-cmdbAbstractObject</type>
<code><![CDATA[ protected function UpdateConnectedNetworkDevice()
{
$oDevice = MetaModel::GetObject('ConnectableCI', $this->Get('connectableci_id'));
if (is_object($oDevice) && (get_class($oDevice) == 'NetworkDevice'))
{
// Note: in case a port has been changed, search with the original values
$sOQL = "SELECT lnkConnectableCIToNetworkDevice WHERE connectableci_id = :device AND networkdevice_id = :network AND network_port = :nwport AND device_port = :devport";
$aFields = array('networkdevice_id','connectableci_id','network_port','device_port','connection_type');
$aChanges = $this->ListPreviousValuesForUpdatedAttributes();
$aPrev = array(); // Previous values of the current link object before it was modified
foreach ($aFields as $sFieldCode) {
$aPrev[$sFieldCode] = array_key_exists($sFieldCode, $aChanges) ? $aChanges[$sFieldCode] : $this->Get($sFieldCode);
}
$sPrevLink = ($aPrev['connection_type'] == 'uplink') ? 'downlink' : 'uplink';
$sConnLink = ($this->Get('connection_type') == 'uplink') ? 'downlink' : 'uplink';
$oNewDevice = MetaModel::GetObject('ConnectableCI', $this->Get('connectableci_id'), false);
$oPrevDevice = MetaModel::GetObject('ConnectableCI', $aPrev['connectableci_id'], false);
$bNew = (is_object($oNewDevice) && (get_class($oNewDevice) == 'NetworkDevice'));
$bPrev = (is_object($oPrevDevice) && (get_class($oPrevDevice) == 'NetworkDevice'));
$sOQL = "SELECT lnkConnectableCIToNetworkDevice WHERE connectableci_id = :device AND networkdevice_id = :network AND network_port = :nwport AND device_port = :devport AND connection_type = :link";
if ($bPrev) { // There was a twin
// Retrieve twin link using previous values of the current link
$oConnectionSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL),
array(),
array(
'network' => $aPrev['connectableci_id'],
'device' => $aPrev['networkdevice_id'],
'devport' => $aPrev['network_port'],
'nwport' => $aPrev['device_port'],
'link' => $sPrevLink,
)
);
if ($bNew) { // and a twin must still exist, so update the existing
while ($oConnection = $oConnectionSet->Fetch()) {
$oConnection->Set('networkdevice_id', $this->Get('connectableci_id'));
$oConnection->Set('connectableci_id', $this->Get('networkdevice_id'));
$oConnection->Set('network_port', $this->Get('device_port'));
$oConnection->Set('device_port', $this->Get('network_port'));
$oConnection->Set('connection_type',$sConnLink);
$oConnection->DBUpdate();
}
}
else { // and no twin is needed anymore, so delete the existing
while ($oConnection = $oConnectionSet->Fetch()) {
$oConnection->DBDelete();
}
}
}
elseif ($bNew) { // There was no twin but a twin must exist now
// Search for a twin link using current values inverted
$oConnectionSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL),
array(),
array(
'network' => $this->Get('connectableci_id'),
'device' => $this->Get('networkdevice_id'),
'devport' => $this->GetOriginal('network_port'),
'nwport' => $this->GetOriginal('device_port'),
'devport' => $this->Get('device_port'),
'nwport' => $this->Get('network_port'),
'link' => $sConnLink,
)
);
$sLink = $this->Get('connection_type');
$sConnLink = ($sLink == 'uplink') ? 'downlink' : 'uplink';
// There should be one link - do it in a safe manner anyway
while ($oConnection = $oConnectionSet->Fetch())
{
$oConnection->Set('connection_type', $sConnLink);
$oConnection->Set('network_port', $this->Get('device_port'));
$oConnection->Set('device_port', $this->Get('network_port'));
$oConnection->DBUpdate();
if ($oConnectionSet->Count() == 0) {
$oNewLink = new lnkConnectableCIToNetworkDevice();
$oNewLink->Set('networkdevice_id', $this->Get('connectableci_id'));
$oNewLink->Set('connectableci_id', $this->Get('networkdevice_id'));
$oNewLink->Set('network_port', $this->Get('device_port'));
$oNewLink->Set('device_port', $this->Get('network_port'));
$oNewLink->Set('connection_type', $sConnLink);
$oNewLink->DBInsert();
}
}
}]]></code>

View File

@@ -189,14 +189,16 @@ try {
$oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden('operation', 'save'));
$oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden('transaction_id', utils::GetNewTransactionId()));
// - Cancel button
//--- Cancel button
$oCancelButton = ButtonUIBlockFactory::MakeForCancel(Dict::S('config-cancel'), 'cancel_button', null, true, 'cancel_button');
$oCancelButton->SetOnClickJsCode("return ResetConfig();");
$oForm->AddSubBlock($oCancelButton);
// - Submit button
//--- Submit button
$oSubmitButton = ButtonUIBlockFactory::MakeForPrimaryAction(Dict::S('config-apply'), null, Dict::S('config-apply'), true, 'submit_button');
$oForm->AddSubBlock($oSubmitButton);
//--- Config editor
$oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden('prev_config', $sOriginalConfigEscaped, 'prev_config'));
$oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden('new_config', $sConfigEscaped));
$oForm->AddHtml("<div id =\"new_config\" style=\"position: absolute; top: ".$iEditorTopMargin."em; bottom: 0; left: 5px; right: 5px;\"></div>");

View File

@@ -54,6 +54,7 @@ Dict::Add('EN US', 'English', 'English', array(
'iTopUpdate:UI:Status' => 'Status',
'iTopUpdate:UI:Action' => 'Update',
'iTopUpdate:UI:Setup' => ITOP_APPLICATION_SHORT.' Setup',
'iTopUpdate:UI:History' => 'Versions History',
'iTopUpdate:UI:Progress' => 'Progress of the upgrade',
@@ -81,6 +82,9 @@ Dict::Add('EN US', 'English', 'English', array(
'iTopUpdate:UI:SetupLaunch' => 'Launch '.ITOP_APPLICATION_SHORT.' Setup',
'iTopUpdate:UI:SetupLaunchConfirm' => 'This will launch '.ITOP_APPLICATION_SHORT.' setup, are you sure?',
// Setup Messages
'iTopUpdate:UI:SetupMessage:Ready' => 'Ready to start',
'iTopUpdate:UI:SetupMessage:EnterMaintenance' => 'Entering maintenance mode',

View File

@@ -17,6 +17,7 @@ use Dict;
use Exception;
use IssueLog;
use MetaModel;
use SecurityException;
use SetupUtils;
use utils;
@@ -211,8 +212,7 @@ class AjaxController extends Controller
CoreUpdater::UpdateDatabase();
$iResponseCode = 200;
}
catch (Exception $e)
{
catch (Exception $e) {
IssueLog::Error("Compile: ".$e->getMessage());
$aParams['sError'] = $e->getMessage();
$iResponseCode = 500;
@@ -220,4 +220,22 @@ class AjaxController extends Controller
$this->DisplayJSONPage($aParams, $iResponseCode);
}
/**
* @throws \SecurityException if CSRF token invalid
*
* @since 3.1.0 N°4919
*/
public function OperationLaunchSetup()
{
$sTransactionId = utils::ReadParam('transaction_id', '', false, 'transaction_id');
if (false === utils::IsTransactionValid($sTransactionId)) {
throw new SecurityException('Access forbidden');
}
$sConfigFile = APPCONF.'production/config-itop.php';
@chmod($sConfigFile, 0770); // Allow overwriting the file
header('Location: ../setup/');
}
}

View File

@@ -35,6 +35,25 @@ class UpdateController extends Controller
$oSet = new DBObjectSet($oFilter, ['installed' => false]); // Most recent first
$aParams['oSet'] = $oSet;
$oConfig = utils::GetConfig();
$bConfigParamSetupLaunchButtonEnabled = $oConfig->Get('setup.launch_button.enabled');
if (is_null($bConfigParamSetupLaunchButtonEnabled)) {
$bIsSetupLaunchButtonEnabled = utils::IsDevelopmentEnvironment();
} else if (false === $bConfigParamSetupLaunchButtonEnabled) {
$bIsSetupLaunchButtonEnabled = false;
} else {
$bIsSetupLaunchButtonEnabled = $bConfigParamSetupLaunchButtonEnabled || utils::IsDevelopmentEnvironment();
}
$aParams['bIsSetupLaunchButtonEnabled'] = $bIsSetupLaunchButtonEnabled;
if ($bIsSetupLaunchButtonEnabled) {
$sLaunchSetupUrl = utils::GetAbsoluteUrlModulePage('itop-core-update', 'ajax.php',
[
'operation' => 'LaunchSetup',
'transaction_id' => $sTransactionId,
]);;
$aParams['sLaunchSetupUrl'] = $sLaunchSetupUrl;
}
$this->DisplayPage($aParams);
}

View File

@@ -87,6 +87,14 @@
{% EndUIFieldSet %}
{% if bIsSetupLaunchButtonEnabled %}
{% UIFieldSet Standard {'sLegend':'iTopUpdate:UI:Setup'|dict_s} %}
{% UIForm Standard {'sId':'launch-setup-form', Action:sLaunchSetupUrl} %}
{% UIButton ForDestructiveAction {'sLabel':'iTopUpdate:UI:SetupLaunch'|dict_s, 'sName':'launch-setup', 'sValue':'launch-setup', 'bIsSubmit':true, 'sId':'launch-setup'} %}
{% EndUIForm %}
{% EndUIFieldSet %}
{% endif %}
{% UIFieldSet Standard {'sLegend':'iTopUpdate:UI:History'|dict_s} %}
{% UIDataTable ForRendering {'sListId':'iboupdatehistory', 'oSet':oSet} %}{% EndUIDataTable %}
{% EndUIFieldSet %}

View File

@@ -101,3 +101,7 @@ $("#check-update").on("click", function(e) {
e.stopPropagation();
return false;
});
$("#launch-setup-form").on("submit", function () {
return window.confirm("{{ 'iTopUpdate:UI:SetupLaunchConfirm'|dict_s }}");
});

View File

@@ -22,18 +22,20 @@
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
if (!defined('__DIR__')) define('__DIR__', dirname(__FILE__));
require_once (APPROOT.'application/webpage.class.inc.php');
require_once (APPROOT.'application/utils.inc.php');
require_once (APPROOT.'core/log.class.inc.php');
if (!defined('__DIR__')) {
define('__DIR__', dirname(__FILE__));
}
require_once(APPROOT.'application/utils.inc.php');
require_once(APPROOT.'core/log.class.inc.php');
IssueLog::Enable(APPROOT.'log/error.log');
require_once (APPROOT.'setup/runtimeenv.class.inc.php');
require_once (APPROOT.'setup/backup.class.inc.php');
require_once (APPROOT.'core/mutex.class.inc.php');
require_once (APPROOT.'core/dict.class.inc.php');
require_once (APPROOT.'setup/xmldataloader.class.inc.php');
require_once (__DIR__.'/hubruntimeenvironment.class.inc.php');
require_once(APPROOT.'setup/runtimeenv.class.inc.php');
require_once(APPROOT.'setup/backup.class.inc.php');
require_once(APPROOT.'core/mutex.class.inc.php');
require_once(APPROOT.'core/dict.class.inc.php');
require_once(APPROOT.'setup/xmldataloader.class.inc.php');
require_once(__DIR__.'/hubruntimeenvironment.class.inc.php');
/**
* Overload of DBBackup to handle logging

View File

@@ -280,7 +280,6 @@ try {
switch ($sTargetRoute) {
case 'inform_after_setup':
// Hidden IFRAME at the end of the setup
require_once(APPROOT.'/application/ajaxwebpage.class.inc.php');
$oPage = new NiceWebPage('');
$aDataToPost = MakeDataToPost($sTargetRoute);
$oPage->add('<form id="hub_launch_form" action="'.$sHubUrlStateless.'" method="post">');

View File

@@ -1142,39 +1142,40 @@
<static>false</static>
<access>public</access>
<type>LifecycleAction</type>
<code><![CDATA[ public function ComputePriority()
{
// priority[impact][urgency]
$aPriorities = array(
// single person
1 => array(
1 => 1,
2 => 1,
3 => 2,
4 => 4,
),
// a group
2 => array(
1 => 1,
2 => 2,
3 => 3,
4 => 4,
),
// a departement!
3 => array(
1 => 2,
2 => 3,
3 => 3,
4 => 4,
),
);
$iPriority = 1;
if (isset($aPriorities[(int)$this->Get('impact')]) && isset($aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')]))
{
$iPriority = $aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')];
}
return $iPriority;
}]]></code>
<code><![CDATA[public function ComputePriority()
{
// priority[impact][urgency]
$aPriorities = array(
// single person
1 => array(
1 => 1,
2 => 1,
3 => 2,
4 => 4,
),
// a group
2 => array(
1 => 1,
2 => 2,
3 => 3,
4 => 4,
),
// a departement!
3 => array(
1 => 2,
2 => 3,
3 => 3,
4 => 4,
),
);
$oAttDef = MetaModel::GetAttributeDef(get_class($this), 'priority');
$iPriority = $oAttDef->IsNullAllowed() ? null : $oAttDef->GetDefaultValue();
if (isset($aPriorities[(int)$this->Get('impact')]) && isset($aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')])) {
$iPriority = $aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')];
}
return $iPriority;
}]]></code>
</method>
<method id="ComputeValues">
<static>false</static>

View File

@@ -162,12 +162,20 @@ class BrickCollection
// - Home
$this->aHomeOrdering = $this->aAllowedBricks;
usort($this->aHomeOrdering, function (PortalBrick $a, PortalBrick $b) {
return $a->GetRankHome() > $b->GetRankHome();
if ($a->GetRankHome() === $b->GetRankHome()) {
return 0;
}
return $a->GetRankHome() > $b->GetRankHome() ? 1 : -1;
});
// - Navigation menu
$this->aNavigationMenuOrdering = $this->aAllowedBricks;
usort($this->aNavigationMenuOrdering, function (PortalBrick $a, PortalBrick $b) {
return $a->GetRankNavigationMenu() > $b->GetRankNavigationMenu();
if ($a->GetRankNavigationMenu() === $b->GetRankNavigationMenu()) {
return 0;
}
return $a->GetRankNavigationMenu() > $b->GetRankNavigationMenu() ? 1 : -1;
});
}

View File

@@ -485,7 +485,11 @@ class ManageBrick extends PortalBrick
if (!$this->IsGroupingByDistinctValues($sName))
{
usort($this->aGrouping[$sName]['groups'], function ($a, $b) {
return $a['rank'] > $b['rank'];
if ($a['rank'] === $b['rank']) {
return 0;
}
return $a['rank'] > $b['rank'] ? 1 : -1;
});
}

View File

@@ -1246,7 +1246,7 @@ class ObjectController extends BrickController
}
$aData['att_id'] = $iAttId;
$aData['preview'] = $oDocument->IsPreviewAvailable() ;
$aData['preview'] = $oDocument->IsPreviewAvailable();
$aData['file_size'] = $oDocument->GetFormattedSize();
$aData['creation_date'] = $oAttachment->Get('creation_date');
$aData['user_id_friendlyname'] = $oAttachment->Get('user_id_friendlyname');

View File

@@ -91,7 +91,10 @@ class Lists extends AbstractConfiguration
}
// - Sorting list items by rank
usort($aListItems, function ($a, $b) {
return $a['rank'] > $b['rank'];
if ($a['rank'] == $b['rank']) {
return 0;
}
return $a['rank'] > $b['rank'] ? 1 : -1;
});
$aClassLists[$sListId] = $aListItems;
}

View File

@@ -120,17 +120,6 @@ class ObjectFormManager extends FormManager
{
$aJson = static::DecodeFormManagerData($sJson);
$oConfig = utils::GetConfig();
$bIsContentCheckEnabled = $oConfig->GetModuleSetting(PORTAL_ID, 'enable_formmanager_content_check', true);
if ($bIsContentCheckEnabled && (false === $bTrustContent)) {
/** @noinspection NestedPositiveIfStatementsInspection */
if (isset($aJson['formproperties']['layout']['type']) && ($aJson['formproperties']['layout']['type'] === 'twig')) {
// There will be an IssueLog above in the hierarchy due to the exception, but we are logging here so that we can output the JSON data !
IssueLog::Error('Portal received a query with forbidden twig content!', \LogChannels::PORTAL, ['formmanager_data' => $aJson]);
throw new \SecurityException('Twig content not allowed in this context!');
}
}
/** @var \Combodo\iTop\Portal\Form\ObjectFormManager $oFormManager */
$oFormManager = parent::FromJSON($sJson);
@@ -703,7 +692,7 @@ class ObjectFormManager extends FormManager
/** @var Field $oField */
$oField = null;
if (is_callable(get_class($oAttDef).'::MakeFormField'))
if (is_callable([$oAttDef, 'MakeFormField']))
{
$oField = $oAttDef->MakeFormField($this->oObject);
}
@@ -1185,16 +1174,18 @@ class ObjectFormManager extends FormManager
$sObjectClass = get_class($this->oObject);
try {
// modification flags
$bIsNew = $this->oObject->IsNew();
$bWasModified = $this->oObject->IsModified();
$bActivateTriggers = (!$bIsNew && $bWasModified);
// Forcing allowed writing on the object if necessary. This is used in some particular cases.
$bAllowWrite = ($sObjectClass === 'Person' && $this->oObject->GetKey() == UserRights::GetContactId());
$bAllowWrite = $this->oContainer->get('security_helper')->IsActionAllowed($bIsNew ? UR_ACTION_CREATE : UR_ACTION_MODIFY, $sObjectClass, $this->oObject->GetKey());
if ($bAllowWrite) {
$this->oObject->AllowWrite(true);
}
// Writing object to DB
$bIsNew = $this->oObject->IsNew();
$bWasModified = $this->oObject->IsModified();
$bActivateTriggers = (!$bIsNew && $bWasModified);
try
{
$this->oObject->DBWrite();

View File

@@ -103,6 +103,12 @@ class SecurityHelper
return false;
}
// Forcing allowed writing on the object if necessary. This is used in some particular cases.
$bObjectIsCurrentUser = ($sObjectClass === 'Person' && $sObjectId == UserRights::GetContactId());
if(in_array($sAction , array(UR_ACTION_MODIFY, UR_ACTION_READ)) && $bObjectIsCurrentUser){
return true;
}
// Checking the scopes layer
// - Transforming scope action as there is only 2 values
$sScopeAction = ($sAction === UR_ACTION_READ) ? UR_ACTION_READ : UR_ACTION_MODIFY;

View File

@@ -20,6 +20,7 @@
namespace Combodo\iTop\Portal\Twig;
use AttributeDate;
use Combodo\iTop\Application\TwigBase\Twig\Extension;
use Twig\Extension\AbstractExtension;
use AttributeDateTime;
@@ -33,194 +34,29 @@ use MetaModel;
/**
* Class AppExtension
*
* Automatically loaded by portal's Symfony configuration to register TWIG extensions.
* The class must be kept by it is using the factorized filters/functions of the iTop core.
*
* @package Combodo\iTop\Portal\Twig
* @since 2.7.0
* @author Bruno Da Silva <bruno.dasilva@combodo.com>
* @deprected 3.1.0 N°4287
*/
class AppExtension extends AbstractExtension
{
/**
* @return array|\Twig\TwigFilter[]|\Twig_SimpleFilter[]
* @inheritDoc
*/
public function getFilters()
{
$filters = array();
// Filter to translate a string via the Dict::S function
// Usage in twig: {{ 'String:ToTranslate'|dict_s }}
$filters[] = new Twig_SimpleFilter('dict_s',
function ($sStringCode, $sDefault = null, $bUserLanguageOnly = false) {
return Dict::S($sStringCode, $sDefault, $bUserLanguageOnly);
}
);
// Filter to format a string via the Dict::Format function
// Usage in twig: {{ 'String:ToTranslate'|dict_format() }}
$filters[] = new Twig_SimpleFilter('dict_format',
function ($sStringCode, $sParam01 = null, $sParam02 = null, $sParam03 = null, $sParam04 = null) {
return Dict::Format($sStringCode, $sParam01, $sParam02, $sParam03, $sParam04);
}
);
/**
* Filter to format output
* example a DateTime is converted to user format
* Usage in twig: {{ 'String:ToFormat'|output_format }}
*
* @since 3.0.0
*/
$filters[] = new Twig_SimpleFilter('date_format',
function ($sDate) {
try
{
if (preg_match('@^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d$@', trim($sDate)))
{
return AttributeDateTime::GetFormat()->Format($sDate);
}
if (preg_match('@^\d\d\d\d-\d\d-\d\d$@', trim($sDate)))
{
return AttributeDate::GetFormat()->Format($sDate);
}
}
catch (Exception $e)
{
}
return $sDate;
}
);
/**
* Filter to format output
* example a DateTime is converted to user format
* Usage in twig: {{ 'String:ToFormat'|output_format }}
*
* @since 3.0.0
*/
$filters[] = new Twig_SimpleFilter('size_format',
function ($sSize) {
return utils::BytesToFriendlyFormat($sSize);
}
);
// Filter to enable base64 encode/decode
// Usage in twig: {{ 'String to encode'|base64_encode }}
$filters[] = new Twig_SimpleFilter('base64_encode', 'base64_encode');
$filters[] = new Twig_SimpleFilter('base64_decode', 'base64_decode');
// Filter to enable json decode (encode already exists)
// Usage in twig: {{ aSomeArray|json_decode }}
$filters[] = new Twig_SimpleFilter('json_decode', function ($sJsonString, $bAssoc = false) {
return json_decode($sJsonString, $bAssoc);
}
);
/**
* Filter to sanitize a text
* Usage in twig: {{ 'variable_name:to-sanitize'|sanitize(constant('utils::ENUM_SANITIZATION_FILTER_VARIABLE_NAME')) }}
*
* @uses \utils::Sanitize()
* @since 3.0.0
*/
$filters[] = new Twig_SimpleFilter('sanitize', function (string $sString, string $sFilter) {
return utils::Sanitize($sString, '', $sFilter);
}
);
/**
* Filter to transform the wiki syntax ONLY into HTML.
*
* @uses \AttributeText::RenderWikiHtml()
* @since 3.0.0
*/
$filters[] = new Twig_SimpleFilter('render_wiki_to_html', function ($sString) {
return AttributeText::RenderWikiHtml($sString, true /* Important, otherwise hyperlinks will be tranformed as well */);
}
);
// Filter to add itopversion to an url
$filters[] = new Twig_SimpleFilter('add_itop_version', function ($sUrl) {
$sUrl = utils::AddParameterToUrl($sUrl, 'itopversion', ITOP_VERSION);
return $sUrl;
});
// Filter to add a module's version to an url
$filters[] = new Twig_SimpleFilter('add_module_version', function ($sUrl, $sModuleName) {
$sModuleVersion = utils::GetCompiledModuleVersion($sModuleName);
$sUrl = utils::AddParameterToUrl($sUrl, 'moduleversion', $sModuleVersion);
return $sUrl;
});
/**
* var_export can be used for example to transform a PHP boolean to 'true' or 'false' strings
* @see https://www.php.net/manual/fr/function.var-export.php
*
* @since 3.0.0
*/
$filters[] = new Twig_SimpleFilter('var_export', 'var_export');
return $filters;
return Extension::GetFilters();
}
/**
* @return array|\Twig\TwigFunction[]|\Twig_SimpleFunction[]
* @inheritDoc
*/
public function getFunctions()
{
$functions = array();
// Function to check our current environment
// Usage in twig: {% if is_development_environment() %}
$functions[] = new Twig_SimpleFunction('is_development_environment', function () {
return utils::IsDevelopmentEnvironment();
});
// Function to get configuration parameter
// Usage in twig: {{ get_config_parameter('foo') }}
$functions[] = new Twig_SimpleFunction('get_config_parameter', function ($sParamName) {
$oConfig = MetaModel::GetConfig();
return $oConfig->Get($sParamName);
});
/**
* Function to get a module setting
* Usage in twig: {{ get_module_setting(<MODULE_CODE>, <PROPERTY_CODE> [, <DEFAULT_VALUE>]) }}
*
* @uses Config::GetModuleSetting()
* @since 3.0.0
*/
$functions[] = new Twig_SimpleFunction('get_module_setting',
function (string $sModuleCode, string $sPropertyCode, $defaultValue = null) {
$oConfig = MetaModel::GetConfig();
return $oConfig->GetModuleSetting($sModuleCode, $sPropertyCode, $defaultValue);
});
/**
* Function to get iTop's app root absolute URL (eg. https://aaa.bbb.ccc/xxx/yyy/)
* Usage in twig: {{ get_absolute_url_app_root() }}
*
* @since 3.0.0
*/
$functions[] = new Twig_SimpleFunction('get_absolute_url_app_root', function () {
return utils::GetAbsoluteUrlAppRoot();
});
/**
* Function to get iTop's modules root absolute URL (eg. https://aaa.bbb.ccc/xxx/yyy/env-zzz/)
* Usage in twig: {{ get_absolute_url_modules_root() }}
*
* @since 3.0.0
*/
$functions[] = new Twig_SimpleFunction('get_absolute_url_modules_root', function () {
return utils::GetAbsoluteUrlModulesRoot();
});
return $functions;
return Extension::GetFunctions();
}

View File

@@ -172,9 +172,13 @@
</value>
</values>
<sql>priority</sql>
<default_value>1</default_value>
<default_value>4</default_value>
<is_null_allowed>false</is_null_allowed>
<display_style>list</display_style>
<dependencies>
<attribute id="impact"/>
<attribute id="urgency"/>
</dependencies>
</field>
<field id="related_change_id" xsi:type="AttributeExternalKey">
<filter><![CDATA[SELECT Change WHERE status != "closed"]]></filter>
@@ -481,39 +485,40 @@
<static>false</static>
<access>public</access>
<type>LifecycleAction</type>
<code><![CDATA[ public function ComputePriority()
{
// priority[impact][urgency]
$aPriorities = array(
// single person
1 => array(
1 => 1,
2 => 1,
3 => 2,
4 => 4,
),
// a group
2 => array(
1 => 1,
2 => 2,
3 => 3,
4 => 4,
),
// a departement!
3 => array(
1 => 2,
2 => 3,
3 => 3,
4 => 4,
),
);
$iPriority = 1;
if (isset($aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')]))
{
$iPriority = $aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')];
}
return $iPriority;
}]]></code>
<code><![CDATA[public function ComputePriority()
{
// priority[impact][urgency]
$aPriorities = array(
// single person
1 => array(
1 => 1,
2 => 1,
3 => 2,
4 => 4,
),
// a group
2 => array(
1 => 1,
2 => 2,
3 => 3,
4 => 4,
),
// a departement!
3 => array(
1 => 2,
2 => 3,
3 => 3,
4 => 4,
),
);
$oAttDef = MetaModel::GetAttributeDef(get_class($this), 'priority');
$iPriority = $oAttDef->IsNullAllowed() ? null : $oAttDef->GetDefaultValue();
if (isset($aPriorities[(int)$this->Get('impact')]) && isset($aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')])) {
$iPriority = $aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')];
}
return $iPriority;
}]]></code>
</method>
<method id="ComputeValues">
<static>false</static>
@@ -564,10 +569,10 @@
<rank>50</rank>
</item>
<item id="related_incident_list">
<rank>50</rank>
<rank>60</rank>
</item>
<item id="col:col1">
<rank>60</rank>
<rank>70</rank>
<items>
<item id="fieldset:Ticket:baseinfo">
<rank>10</rank>
@@ -575,31 +580,44 @@
<item id="ref">
<rank>10</rank>
</item>
<item id="title">
<item id="org_id">
<rank>20</rank>
</item>
<item id="org_id">
<item id="caller_id">
<rank>30</rank>
</item>
<item id="status">
<rank>40</rank>
</item>
<item id="priority">
<item id="product">
<rank>50</rank>
</item>
<item id="service_id">
<item id="title">
<rank>60</rank>
</item>
<item id="servicesubcategory_id">
<item id="description">
<rank>70</rank>
</item>
<item id="product">
<rank>80</rank>
</item>
</items>
</item>
<item id="fieldset:Ticket:moreinfo">
<rank>20</rank>
<items>
<item id="service_id">
<rank>10</rank>
</item>
<item id="servicesubcategory_id">
<rank>20</rank>
</item>
</items>
</item>
</items>
</item>
<item id="col:col2">
<rank>80</rank>
<items>
<item id="fieldset:Ticket:Type">
<rank>10</rank>
<items>
<item id="impact">
<rank>10</rank>
@@ -607,18 +625,13 @@
<item id="urgency">
<rank>20</rank>
</item>
<item id="description">
<item id="priority">
<rank>30</rank>
</item>
</items>
</item>
</items>
</item>
<item id="col:col2">
<rank>70</rank>
<items>
<item id="fieldset:Ticket:date">
<rank>10</rank>
<rank>20</rank>
<items>
<item id="start_date">
<rank>10</rank>
@@ -637,22 +650,25 @@
</item>
</items>
</item>
</items>
</item>
<item id="col:col3">
<rank>90</rank>
<items>
<item id="fieldset:Ticket:contact">
<rank>20</rank>
<rank>10</rank>
<items>
<item id="caller_id">
<item id="team_id">
<rank>10</rank>
</item>
<item id="team_id">
<rank>20</rank>
</item>
<item id="agent_id">
<rank>30</rank>
<rank>20</rank>
</item>
</items>
</item>
<item id="fieldset:Ticket:relation">
<rank>30</rank>
<rank>20</rank>
<items>
<item id="related_change_id">
<rank>10</rank>
@@ -743,9 +759,9 @@
<menus>
<menu id="ProblemManagement" xsi:type="MenuGroup" _delta="define_if_not_exists">
<rank>42</rank>
<style>
<decoration_classes>fas fa-question</decoration_classes>
</style>
<style>
<decoration_classes>fas fa-question</decoration_classes>
</style>
</menu>
<menu id="Problem:Shortcuts" xsi:type="TemplateMenuNode" _delta="define_if_not_exists">
<rank>5</rank>

View File

@@ -1302,39 +1302,40 @@
<static>false</static>
<access>public</access>
<type>LifecycleAction</type>
<code><![CDATA[ public function ComputePriority()
{
// priority[impact][urgency]
$aPriorities = array(
// a department
1 => array(
1 => 1,
2 => 1,
3 => 2,
4 => 4,
),
// a group
2 => array(
1 => 1,
2 => 2,
3 => 3,
4 => 4,
),
// a person
3 => array(
1 => 2,
2 => 3,
3 => 3,
4 => 4,
),
);
$iPriority = 1;
if (isset($aPriorities[(int)$this->Get('impact')]) && isset($aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')]))
{
$iPriority = $aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')];
}
return $iPriority;
}]]></code>
<code><![CDATA[public function ComputePriority()
{
// priority[impact][urgency]
$aPriorities = array(
// a department
1 => array(
1 => 1,
2 => 1,
3 => 2,
4 => 4,
),
// a group
2 => array(
1 => 1,
2 => 2,
3 => 3,
4 => 4,
),
// a person
3 => array(
1 => 2,
2 => 3,
3 => 3,
4 => 4,
),
);
$oAttDef = MetaModel::GetAttributeDef(get_class($this), 'priority');
$iPriority = $oAttDef->IsNullAllowed() ? null : $oAttDef->GetDefaultValue();
if (isset($aPriorities[(int)$this->Get('impact')]) && isset($aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')])) {
$iPriority = $aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')];
}
return $iPriority;
}]]></code>
</method>
<method id="ComputeValues">
<static>false</static>

View File

@@ -1348,39 +1348,40 @@
<static>false</static>
<access>public</access>
<type>LifecycleAction</type>
<code><![CDATA[ public function ComputePriority()
{
// priority[impact][urgency]
$aPriorities = array(
// a department
1 => array(
1 => 1,
2 => 1,
3 => 2,
4 => 4,
),
// a group
2 => array(
1 => 1,
2 => 2,
3 => 3,
4 => 4,
),
// a person
3 => array(
1 => 2,
2 => 3,
3 => 3,
4 => 4,
),
);
$iPriority = 1;
if (isset($aPriorities[(int)$this->Get('impact')]) && isset($aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')]))
{
$iPriority = $aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')];
}
return $iPriority;
}]]></code>
<code><![CDATA[public function ComputePriority()
{
// priority[impact][urgency]
$aPriorities = array(
// a department
1 => array(
1 => 1,
2 => 1,
3 => 2,
4 => 4,
),
// a group
2 => array(
1 => 1,
2 => 2,
3 => 3,
4 => 4,
),
// a person
3 => array(
1 => 2,
2 => 3,
3 => 3,
4 => 4,
),
);
$oAttDef = MetaModel::GetAttributeDef(get_class($this), 'priority');
$iPriority = $oAttDef->IsNullAllowed() ? null : $oAttDef->GetDefaultValue();
if (isset($aPriorities[(int)$this->Get('impact')]) && isset($aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')])) {
$iPriority = $aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')];
}
return $iPriority;
}]]></code>
</method>
<method id="ComputeValues">
<static>false</static>

View File

@@ -1544,120 +1544,100 @@ public function PrefillSearchForm(&$aContextParam)
</reconciliation>
</properties>
<fields>
<field id="name" xsi:type="AttributeString">
<sql>name</sql>
<default_value/>
<is_null_allowed>false</is_null_allowed>
</field>
<field id="description" xsi:type="AttributeText">
<sql>description</sql>
<default_value/>
<is_null_allowed>true</is_null_allowed>
</field>
<field id="org_id" xsi:type="AttributeExternalKey">
<sql>org_id</sql>
<target_class>Organization</target_class>
<is_null_allowed>false</is_null_allowed>
<on_target_delete>DEL_MANUAL</on_target_delete>
</field>
<field id="organization_name" xsi:type="AttributeExternalField">
<extkey_attcode>org_id</extkey_attcode>
<target_attcode>name</target_attcode>
</field>
<field id="slts_list" xsi:type="AttributeLinkedSetIndirect">
<linked_class>lnkSLAToSLT</linked_class>
<ext_key_to_me>sla_id</ext_key_to_me>
<count_min>0</count_min>
<count_max>0</count_max>
<ext_key_to_remote>slt_id</ext_key_to_remote>
<duplicates/>
</field>
<field id="customercontracts_list" xsi:type="AttributeLinkedSetIndirect">
<linked_class>lnkCustomerContractToService</linked_class>
<ext_key_to_me>sla_id</ext_key_to_me>
<count_min>0</count_min>
<count_max>0</count_max>
<ext_key_to_remote>customercontract_id</ext_key_to_remote>
<duplicates>true</duplicates>
</field>
</fields>
<methods>
<method id="DoCheckToWrite">
<static>false</static>
<access>public</access>
<code><![CDATA[
public function DoCheckToWrite()
{
parent::DoCheckToWrite();
$aCustomerContracts = $this->Get("customercontracts_list");
foreach ($aCustomerContracts as $sAttCode => $oCustomerContracts)
{
// Recurse inside the subdirectories
$sOql = "SELECT lnkCustomerContractToService AS ccs WHERE ccs.customercontract_id=:customercontract_id AND ccs.service_id=:service_id";
$aQueryParams['customercontract_id'] = $oCustomerContracts->Get("customercontract_id");
$aQueryParams['service_id'] = $oCustomerContracts->Get("service_id");
if ($this->Get("id") != null)
{
$sOql = $sOql." AND ccs.sla_id!=:sla_id";
$aQueryParams['sla_id'] = $this->Get("id");
}
$oQuery = DBSearch::FromOQL($sOql, $aQueryParams);
$oResultSql = new DBObjectSet($oQuery);
$oResultSql->OptimizeColumnLoad(['ccs' => ['customercontract_name','service_name']]);
if ($aCurrentRow = $oResultSql->Fetch())
{
$this->m_aCheckIssues[] = Dict::Format('Class:SLA/Error:UniqueLnkCustomerContractToService',$aCurrentRow->Get('customercontract_name'),$aCurrentRow->Get('service_name'));
}
}
}
]]></code>
</method>
</methods>
<field id="name" xsi:type="AttributeString">
<sql>name</sql>
<default_value/>
<is_null_allowed>false</is_null_allowed>
</field>
<field id="description" xsi:type="AttributeText">
<sql>description</sql>
<default_value/>
<is_null_allowed>true</is_null_allowed>
</field>
<field id="org_id" xsi:type="AttributeExternalKey">
<sql>org_id</sql>
<target_class>Organization</target_class>
<is_null_allowed>false</is_null_allowed>
<on_target_delete>DEL_MANUAL</on_target_delete>
</field>
<field id="organization_name" xsi:type="AttributeExternalField">
<extkey_attcode>org_id</extkey_attcode>
<target_attcode>name</target_attcode>
</field>
<field id="slts_list" xsi:type="AttributeLinkedSetIndirect">
<linked_class>lnkSLAToSLT</linked_class>
<ext_key_to_me>sla_id</ext_key_to_me>
<count_min>0</count_min>
<count_max>0</count_max>
<ext_key_to_remote>slt_id</ext_key_to_remote>
<duplicates/>
</field>
<field id="customercontracts_list" xsi:type="AttributeLinkedSet">
<linked_class>lnkCustomerContractToService</linked_class>
<ext_key_to_me>sla_id</ext_key_to_me>
<count_min>0</count_min>
<count_max>0</count_max>
<edit_mode>none</edit_mode>
</field>
</fields>
<methods/>
<presentation>
<details>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="org_id">
<rank>20</rank>
</item>
<item id="description">
<rank>30</rank>
</item>
<item id="slts_list">
<rank>40</rank>
</item>
<item id="customercontracts_list">
<rank>50</rank>
</item>
</items>
</details>
<search>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="org_id">
<rank>20</rank>
</item>
<item id="description">
<rank>30</rank>
</item>
</items>
</search>
<list>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="org_id">
<rank>20</rank>
</item>
</items>
</list>
</presentation>
<details>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="org_id">
<rank>20</rank>
</item>
<item id="description">
<rank>30</rank>
</item>
<item id="slts_list">
<rank>40</rank>
</item>
<item id="customercontracts_list">
<rank>50</rank>
</item>
</items>
</details>
<search>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="org_id">
<rank>20</rank>
</item>
<item id="description">
<rank>30</rank>
</item>
</items>
</search>
<default_search>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="org_id">
<rank>20</rank>
</item>
<item id="description">
<rank>30</rank>
</item>
</items>
</default_search>
<list>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="org_id">
<rank>20</rank>
</item>
</items>
</list>
</presentation>
</class>
<class id="SLT" _delta="define">
<parent>cmdbAbstractObject</parent>
@@ -1748,83 +1728,110 @@ public function PrefillSearchForm(&$aContextParam)
<values>
<value id="hours">
<code>hours</code>
</value>
<value id="minutes">
<code>minutes</code>
</value>
</values>
<sql>unit</sql>
<default_value/>
<is_null_allowed>true</is_null_allowed>
<display_style>radio_horizontal</display_style>
</field>
</fields>
</value>
<value id="minutes">
<code>minutes</code>
</value>
</values>
<sql>unit</sql>
<default_value/>
<is_null_allowed>true</is_null_allowed>
<display_style>radio_horizontal</display_style>
</field>
<field id="slas_list" xsi:type="AttributeLinkedSetIndirect">
<linked_class>lnkSLAToSLT</linked_class>
<ext_key_to_me>slt_id</ext_key_to_me>
<count_min>0</count_min>
<count_max>0</count_max>
<ext_key_to_remote>sla_id</ext_key_to_remote>
<duplicates/>
</field>
</fields>
<methods/>
<presentation>
<details>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="priority">
<rank>20</rank>
</item>
<item id="request_type">
<rank>30</rank>
</item>
<item id="metric">
<rank>40</rank>
</item>
<item id="value">
<rank>50</rank>
</item>
<item id="unit">
<rank>60</rank>
</item>
</items>
</details>
<search>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="priority">
<rank>20</rank>
</item>
<item id="request_type">
<rank>30</rank>
</item>
<item id="metric">
<rank>40</rank>
</item>
<item id="value">
<rank>50</rank>
</item>
<item id="unit">
<rank>60</rank>
</item>
</items>
</search>
<list>
<items>
<item id="priority">
<rank>10</rank>
</item>
<item id="request_type">
<rank>20</rank>
</item>
<item id="metric">
<rank>30</rank>
</item>
<item id="value">
<rank>40</rank>
</item>
<item id="unit">
<rank>50</rank>
</item>
</items>
</list>
</presentation>
</item>
<item id="priority">
<rank>20</rank>
</item>
<item id="request_type">
<rank>30</rank>
</item>
<item id="metric">
<rank>40</rank>
</item>
<item id="value">
<rank>50</rank>
</item>
<item id="unit">
<rank>60</rank>
</item>
<item id="slas_list">
<rank>100</rank>
</item>
</items>
</details>
<search>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="priority">
<rank>20</rank>
</item>
<item id="request_type">
<rank>30</rank>
</item>
<item id="metric">
<rank>40</rank>
</item>
<item id="value">
<rank>50</rank>
</item>
<item id="unit">
<rank>60</rank>
</item>
</items>
</search>
<default_search>
<items>
<item id="name">
<rank>10</rank>
</item>
<item id="priority">
<rank>20</rank>
</item>
<item id="request_type">
<rank>30</rank>
</item>
<item id="metric">
<rank>40</rank>
</item>
</items>
</default_search>
<list>
<items>
<item id="priority">
<rank>10</rank>
</item>
<item id="request_type">
<rank>20</rank>
</item>
<item id="metric">
<rank>30</rank>
</item>
<item id="value">
<rank>40</rank>
</item>
<item id="unit">
<rank>50</rank>
</item>
</items>
</list>
</presentation>
</class>
<class id="lnkSLAToSLT" _delta="define">
<parent>cmdbAbstractObject</parent>

View File

@@ -341,7 +341,7 @@ Dict::Add('EN US', 'English', 'English', array(
'Class:SLA/Attribute:slts_list' => 'SLTs',
'Class:SLA/Attribute:slts_list+' => 'All the service level targets for this SLA',
'Class:SLA/Attribute:customercontracts_list' => 'Customer contracts',
'Class:SLA/Attribute:customercontracts_list+' => 'All the customer contracts using this SLA',
'Class:SLA/Attribute:customercontracts_list+' => 'All the customer contracted services using this SLA',
'Class:SLA/Error:UniqueLnkCustomerContractToService' => 'Could not save link with Customer contract %1$s and service %2$s : SLA already exists',
));
@@ -384,6 +384,8 @@ Dict::Add('EN US', 'English', 'English', array(
'Class:SLT/Attribute:unit/Value:hours+' => 'hours',
'Class:SLT/Attribute:unit/Value:minutes' => 'minutes',
'Class:SLT/Attribute:unit/Value:minutes+' => 'minutes',
'Class:SLT/Attribute:slas_list' => 'SLAs',
'Class:SLT/Attribute:slas_list+' => 'All the service level agreements using this SLT',
));
//

View File

@@ -331,7 +331,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Class:SLA/Attribute:slts_list' => 'SLTs',
'Class:SLA/Attribute:slts_list+' => '',
'Class:SLA/Attribute:customercontracts_list' => 'Contrats clients',
'Class:SLA/Attribute:customercontracts_list+' => '',
'Class:SLA/Attribute:customercontracts_list+' => 'Services contractés par des clients avec ce niveau de service',
'Class:SLA/Error:UniqueLnkCustomerContractToService' => 'Impossible de sauvegarder le lien avec le contrat client %1$s et le service %2$s : un SLA existe déjà.',
));
@@ -374,6 +374,8 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Class:SLT/Attribute:unit/Value:hours+' => 'heures',
'Class:SLT/Attribute:unit/Value:minutes' => 'minutes',
'Class:SLT/Attribute:unit/Value:minutes+' => 'minutes',
'Class:SLT/Attribute:slas_list' => 'SLAs',
'Class:SLT/Attribute:slas_list+' => 'Tous les niveaux de service utilisant cet objectif',
));
//

View File

@@ -1873,6 +1873,14 @@
<precompiled_stylesheet>itop-structure/precompiled-themes/test-red/main.css</precompiled_stylesheet>
</theme>
</themes>
<themes_common>
<variables>
</variables>
<imports>
</imports>
<stylesheets>
</stylesheets>
</themes_common>
</branding>
<user_rights>
<groups>

View File

@@ -2,7 +2,7 @@
/**
* Localized data
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2022 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
@@ -29,6 +29,8 @@ Dict::Add('EN US', 'English', 'English', array(
'Core:UnknownObjectTip' => 'The object could not be found. It may have been deleted some time ago and the log has been purged since.',
'Core:UniquenessDefaultError' => 'Uniqueness rule \'%1$s\' in error',
'Core:CheckConsistencyError' => 'Consistency rules not followed: %1$s',
'Core:CheckValueError' => 'Unexpected value for attribute \'%1$s\' (%2$s) : %3$s',
'Core:AttributeLinkedSet' => 'Array of objects',
'Core:AttributeLinkedSet+' => 'Any kind of objects of the same class or subclass',

View File

@@ -1168,7 +1168,7 @@ When associated with a trigger, each action is given an "order" number, specifyi
'UI:CaseLogTypeYourTextHere' => 'Type your text here...',
'UI:CaseLog:Header_Date_UserName' => '%1$s - %2$s:',
'UI:CaseLog:InitialValue' => 'Initial value:',
'UI:AttemptingToSetASlaveAttribute_Name' => 'The field %1$s is not writable because it is mastered by the data synchronization. Value not set.',
'UI:AttemptingToSetASlaveAttribute_Name' => 'The field %1$s (%2$s) is not writable because it is mastered by the data synchronization. Value not set.',
'UI:ActionNotAllowed' => 'You are not allowed to perform this action on these objects.',
'UI:BulkAction:NoObjectSelected' => 'Please select at least one object to perform this operation',
'UI:AttemptingToChangeASlaveAttribute_Name' => 'The field %1$s is not writable because it is mastered by the data synchronization. Value remains unchanged.',

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 30 KiB

BIN
images/logo-combodo.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -1,59 +1 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Basic//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-basic.dtd">
<svg version="1.1" baseProfile="basic" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" width="198.43px" height="85.04px" viewBox="0 0 198.43 85.04" xml:space="preserve">
<g id="Layer_2" display="none">
<rect x="-1.658" y="-6.145" display="inline" width="207.663" height="99.234"/>
</g>
<g id="Layer_1">
<g>
<rect x="6" y="13.088" fill="#E87C1E" width="63" height="63"/>
<g>
<path fill="#FFFFFF" d="M79.051,33.36h10.297v30.5H79.051V33.36z"/>
</g>
<g>
<path fill="#FFFFFF" d="M113.873,27.93V63.86h-10.656l0.071-35.931h-8.497v-9.433h27.65v9.433H113.873z"/>
<path fill="#FFFFFF" d="M120.209,46.219c0-8.353,4.896-18.722,15.841-18.722c10.945,0,15.841,10.369,15.841,18.722
S146.995,64.94,136.05,64.94C125.105,64.94,120.209,54.571,120.209,46.219z M130.649,46.219c0,6.265,2.017,10.081,5.4,10.081
s5.401-3.889,5.401-10.081c0-6.265-2.018-10.009-5.401-10.009S130.649,39.954,130.649,46.219z"/>
<path fill="#FFFFFF" d="M168.089,62.42v14.042h-10.513V28.577h10.513l-0.071,2.593c0,0,3.6-3.673,7.488-3.673
c9.36,0,13.465,10.009,13.465,17.498c0,8.064-2.52,19.945-14.977,19.945C170.609,64.94,168.089,62.42,168.089,62.42z
M168.089,39.09v7.705c0,4.032,0.433,9.721,5.616,9.721c4.753,0,4.609-7.849,4.609-10.945c0-3.168-0.072-9.433-4.609-9.433
C170.754,36.138,169.674,37.722,168.089,39.09z"/>
</g>
<path fill="#E87C1E" d="M79,18.61h10.297v9.262H79V18.61z"/>
<g>
<g>
<rect x="33.496" y="61.822" transform="matrix(0.7071 0.7071 -0.7071 0.7071 57.2161 -7.1075)" fill="#FFFFFF" stroke="#FFFFFF" stroke-width="1.8998" width="7.383" height="7.381"/>
<line fill="#FFFFFF" stroke="#FFFFFF" stroke-width="1.8998" x1="37.188" y1="28.905" x2="37.188" y2="60.994"/>
<rect x="33.497" y="19.954" transform="matrix(0.7073 0.7069 -0.7069 0.7073 27.6001 -19.3671)" fill="#FFFFFF" stroke="#FFFFFF" stroke-width="1.8998" width="7.381" height="7.383"/>
</g>
<g>
<rect x="54.429" y="40.889" transform="matrix(0.7072 -0.707 0.707 0.7072 -14.501 54.1405)" fill="#FFFFFF" stroke="#FFFFFF" stroke-width="1.8998" width="7.382" height="7.38"/>
<line fill="#FFFFFF" stroke="#FFFFFF" stroke-width="1.8998" x1="21.514" y1="44.579" x2="53.604" y2="44.579"/>
<rect x="12.564" y="40.889" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -26.7615 24.5502)" fill="#FFFFFF" stroke="#FFFFFF" stroke-width="1.8998" width="7.38" height="7.38"/>
</g>
<g>
<rect x="48.297" y="55.69" fill="#FFFFFF" stroke="#FFFFFF" stroke-width="1.8998" width="7.382" height="7.381"/>
<line fill="#FFFFFF" stroke="#FFFFFF" stroke-width="1.8998" x1="26.104" y1="33.496" x2="48.795" y2="56.187"/>
<rect x="18.694" y="26.086" fill="#FFFFFF" stroke="#FFFFFF" stroke-width="1.8998" width="7.382" height="7.383"/>
</g>
<g>
<rect x="48.297" y="26.086" fill="#FFFFFF" stroke="#FFFFFF" stroke-width="1.8998" width="7.382" height="7.383"/>
<line fill="#FFFFFF" stroke="#FFFFFF" stroke-width="1.8998" x1="26.104" y1="55.66" x2="48.793" y2="32.971"/>
<rect x="18.694" y="55.69" fill="#FFFFFF" stroke="#FFFFFF" stroke-width="1.8998" width="7.382" height="7.381"/>
</g>
<g>
<path fill="#FFFFFF" stroke="#E77C24" stroke-width="1.8998" d="M46.094,37.725l0.012,13.496c0,2.094-3.992,3.792-8.918,3.792
c-4.928,0-8.921-1.698-8.921-3.792l0.019-13.478L46.094,37.725z"/>
<ellipse fill="#FFFFFF" stroke="#E77C24" stroke-width="1.8998" cx="37.186" cy="37.389" rx="8.919" ry="3.794"/>
</g>
</g>
</g>
</g>
</svg>
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 452.53 224.62"><defs><style>.e{fill:#fff;}.f{fill:#f18700;}</style></defs><g id="a"/><g id="b"><g id="c"><g id="d"><path class="f" d="M434.94,147.04c9.69,0,17.59-7.9,17.59-17.59s-8.16-17.59-17.59-17.59c-9.94,0-17.59,8.16-17.59,17.59s7.65,17.59,17.59,17.59"/><path class="f" d="M20.19,34.42c9.43,0,17.08-7.65,17.08-17.34C37.27,7.9,29.37,0,20.19,0,9.99,0,2.85,7.9,2.85,17.08c0,9.69,7.14,17.34,17.34,17.34"/><path class="e" d="M55.86,137.2c-10.77,0-20.28-6.26-20.28-20.78v-1.4l.05,.04v-33.98h0v-25.42H0v25.49H9.8v38.54c0,29.54,18.28,43.31,43.31,43.31,7.1,0,14.56-2.1,21.06-5.82v-30.81c-2.99,6.65-9.69,10.84-18.3,10.84m181.86-27.04c0,16.52-12.52,28.79-28.04,28.79s-28.04-11.52-28.04-28.79,11.77-29.04,28.04-29.04,28.04,12.52,28.04,29.04m26.79,0c0-31.55-24.53-55.83-54.83-55.83s-55.08,22.78-54.83,57.33v6.51c0,11.27-8.26,19.03-20.03,19.03-10.77,0-20.28-6.26-20.28-20.78v-33.05h24.28v-25.79h-26.29c8.01-8.01,12.27-18.53,14.52-33.55h-26.04c-3.26,20.53-12.77,33.55-33.05,33.55v25.79h20.78v36.3c0,29.54,18.28,43.31,43.31,43.31,13.02,0,27.29-7.01,34.55-18.28,10.01,13.02,25.53,21.03,43.06,21.03,30.29,0,54.83-24.53,54.83-55.58m96.3-2.81c0,18.53-12.27,30.04-28.79,30.04-15.27,0-29.04-11.77-29.04-28.29v-2.75c0-16.27,13.27-29.29,29.04-29.29s28.79,12.02,28.79,30.29m26.79,.25c0-32.8-22.78-56.08-50.57-56.08-18.28,0-31.04,9.26-34.8,16.52v-13.52h-25.79V224.62c14.46-2.24,22.27-6.81,25.79-22.24v-51.97s11.01,13.02,32.55,12.77c27.29-.25,53.07-21.78,52.82-55.58"/></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 184.3 42.5" style="enable-background:new 0 0 184.3 42.5;" xml:space="preserve">
<style type="text/css">
.st0{fill:#F18700;}
.st1{fill:#202B2F;}
</style>
<g>
<g>
<path class="st0" d="M2,24.5C2,21.5,4.5,19,7.6,19c3,0,5.5,2.5,5.5,5.6c0,3.1-2.5,5.6-5.5,5.6C4.5,30.1,2,27.6,2,24.5z"/>
</g>
<g>
<path class="st1" d="M35.9,26.5c-1,4.6-4.9,7.5-9.5,7.5c-5.2,0-9.3-4.2-9.3-9.8c0-5.5,4.4-9.7,9.5-9.7c4.7,0,8.7,3.3,9.4,8.2h-4.7
c-0.7-2.2-2.5-3.5-4.7-3.5c-2.7,0-4.9,2.2-4.9,5.1c0,3,2.2,5.1,4.9,5.1c2,0,3.6-1,4.5-2.8H35.9z"/>
<path class="st1" d="M58.1,24.2c0,5.5-4.3,9.9-9.6,9.9s-9.6-4.4-9.6-9.9c0-5.4,4.3-9.7,9.6-9.7S58.1,18.7,58.1,24.2z M53.5,24.2
c0-2.8-2.2-5-4.9-5s-4.9,2.2-4.9,5c0,2.9,2.2,5.2,4.9,5.2S53.5,27.1,53.5,24.2z"/>
<path class="st1" d="M62,33.5V15.1h4.5v2.1c0.7-1.2,2.4-2.7,4.9-2.7c2.4,0,4.1,1.2,5.1,2.6c1.1-1.4,2.9-2.6,5.8-2.6
c4.2,0,7.4,2.5,7.4,7.6v11.4h-4.5V22.6c0-2.4-1.3-3.8-3.5-3.8c-2.1,0-3.5,1.4-3.5,3.8v10.8h-4.5V22.6c0-2.4-1.4-3.8-3.5-3.8
c-2.2,0-3.5,1.5-3.5,3.9v10.7H62z"/>
<path class="st1" d="M114,24.2c0,5.7-4.2,9.8-9.1,9.8c-3.1,0-5.1-1.6-5.8-2.9v2.4h-4.5V5.1h4.5v12.2c1-1.3,3.2-2.8,6.2-2.8
C110.1,14.6,114,18.3,114,24.2z M109.3,24.3c0-3.2-2.2-5.2-5-5.2c-2.7,0-5.1,2.1-5.1,5v0.6c0,2.8,2.4,4.9,5.1,4.9
C107.1,29.5,109.3,27.4,109.3,24.3z"/>
<path class="st1" d="M136.1,24.2c0,5.5-4.3,9.9-9.6,9.9s-9.6-4.4-9.6-9.9c0-5.4,4.3-9.7,9.6-9.7S136.1,18.7,136.1,24.2z
M131.5,24.2c0-2.8-2.2-5-4.9-5s-4.9,2.2-4.9,5c0,2.9,2.2,5.2,4.9,5.2S131.5,27.1,131.5,24.2z"/>
<path class="st1" d="M158.3,5.1v28.4h-4.5v-2.2c-0.4,1.1-2.5,2.8-5.7,2.8c-4.9,0-9-3.9-9.1-9.6c0-5.9,4.1-9.9,9.1-9.9
c3.5,0,5.1,1.5,5.6,2.4V5.1H158.3z M153.7,24.8v-0.7c0-2.8-2.2-4.9-5-4.9c-2.7,0-4.9,2.1-4.9,5.1c0,3.1,2.2,5.2,4.9,5.2
C151.3,29.5,153.7,27.4,153.7,24.8z"/>
<path class="st1" d="M181.7,24.2c0,5.5-4.3,9.9-9.6,9.9s-9.6-4.4-9.6-9.9c0-5.4,4.3-9.7,9.6-9.7S181.7,18.7,181.7,24.2z M177,24.2
c0-2.8-2.2-5-4.9-5s-4.9,2.2-4.9,5c0,2.9,2.2,5.2,4.9,5.2S177,27.1,177,24.2z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 184.3 42.5" style="enable-background:new 0 0 184.3 42.5;" xml:space="preserve">
<style type="text/css">
.st0{fill:#F18700;}
.st1{fill:#FFFFFF;}
</style>
<g>
<g>
<path class="st0" d="M2,24.5C2,21.5,4.5,19,7.6,19c3,0,5.5,2.5,5.5,5.6c0,3.1-2.5,5.6-5.5,5.6C4.5,30.1,2,27.6,2,24.5z"/>
</g>
<g>
<path class="st1" d="M35.9,26.5c-1,4.6-4.9,7.5-9.5,7.5c-5.2,0-9.3-4.2-9.3-9.8c0-5.5,4.4-9.7,9.5-9.7c4.7,0,8.7,3.3,9.4,8.2h-4.7
c-0.7-2.2-2.5-3.5-4.7-3.5c-2.7,0-4.9,2.2-4.9,5.1c0,3,2.2,5.1,4.9,5.1c2,0,3.6-1,4.5-2.8H35.9z"/>
<path class="st1" d="M58.1,24.2c0,5.5-4.3,9.9-9.6,9.9s-9.6-4.4-9.6-9.9c0-5.4,4.3-9.7,9.6-9.7S58.1,18.7,58.1,24.2z M53.5,24.2
c0-2.8-2.2-5-4.9-5s-4.9,2.2-4.9,5c0,2.9,2.2,5.2,4.9,5.2S53.5,27.1,53.5,24.2z"/>
<path class="st1" d="M62,33.5V15.1h4.5v2.1c0.7-1.2,2.4-2.7,4.9-2.7c2.4,0,4.1,1.2,5.1,2.6c1.1-1.4,2.9-2.6,5.8-2.6
c4.2,0,7.4,2.5,7.4,7.6v11.4h-4.5V22.6c0-2.4-1.3-3.8-3.5-3.8c-2.1,0-3.5,1.4-3.5,3.8v10.8h-4.5V22.6c0-2.4-1.4-3.8-3.5-3.8
c-2.2,0-3.5,1.5-3.5,3.9v10.7H62z"/>
<path class="st1" d="M114,24.2c0,5.7-4.2,9.8-9.1,9.8c-3.1,0-5.1-1.6-5.8-2.9v2.4h-4.5V5.1h4.5v12.2c1-1.3,3.2-2.8,6.2-2.8
C110.1,14.6,114,18.3,114,24.2z M109.3,24.3c0-3.2-2.2-5.2-5-5.2c-2.7,0-5.1,2.1-5.1,5v0.6c0,2.8,2.4,4.9,5.1,4.9
C107.1,29.5,109.3,27.4,109.3,24.3z"/>
<path class="st1" d="M136.1,24.2c0,5.5-4.3,9.9-9.6,9.9s-9.6-4.4-9.6-9.9c0-5.4,4.3-9.7,9.6-9.7S136.1,18.7,136.1,24.2z
M131.5,24.2c0-2.8-2.2-5-4.9-5s-4.9,2.2-4.9,5c0,2.9,2.2,5.2,4.9,5.2S131.5,27.1,131.5,24.2z"/>
<path class="st1" d="M158.3,5.1v28.4h-4.5v-2.2c-0.4,1.1-2.5,2.8-5.7,2.8c-4.9,0-9-3.9-9.1-9.6c0-5.9,4.1-9.9,9.1-9.9
c3.5,0,5.1,1.5,5.6,2.4V5.1H158.3z M153.7,24.8v-0.7c0-2.8-2.2-4.9-5-4.9c-2.7,0-4.9,2.1-4.9,5.1c0,3.1,2.2,5.2,4.9,5.2
C151.3,29.5,153.7,27.4,153.7,24.8z"/>
<path class="st1" d="M181.7,24.2c0,5.5-4.3,9.9-9.6,9.9s-9.6-4.4-9.6-9.9c0-5.4,4.3-9.7,9.6-9.7S181.7,18.7,181.7,24.2z M177,24.2
c0-2.8-2.2-5-4.9-5s-4.9,2.2-4.9,5c0,2.9,2.2,5.2,4.9,5.2S177,27.1,177,24.2z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 238.1 113.4" style="enable-background:new 0 0 238.1 113.4;" xml:space="preserve">
<style type="text/css">
.st0{fill:#F08700;}
.st1{fill:#202B2F;}
</style>
<g>
<path class="st0" d="M228.1,70.7c4.1,0,7.4-3.3,7.4-7.4c0-4-3.5-7.4-7.4-7.4c-4.2,0-7.4,3.5-7.4,7.4
C220.7,67.4,223.9,70.7,228.1,70.7L228.1,70.7z"/>
<path class="st0" d="M52.6,23.1c4,0,7.2-3.2,7.2-7.3c0-3.9-3.3-7.2-7.2-7.2c-4.3,0-7.3,3.3-7.3,7.2C45.3,19.8,48.3,23.1,52.6,23.1
L52.6,23.1z"/>
<path class="st1" d="M67.7,66.6c-4.6,0-8.6-2.6-8.6-8.8v-0.6l0,0V42.8h0V32H44.1v10.8h4.1v16.3c0,12.5,7.7,18.3,18.3,18.3
c3,0,6.2-0.9,8.9-2.5V62C74.2,64.8,71.4,66.6,67.7,66.6L67.7,66.6z M144.7,55.1c0,7-5.3,12.2-11.9,12.2c-6.6,0-11.9-4.9-11.9-12.2
c0-7,5-12.3,11.9-12.3C139.4,42.8,144.7,48.1,144.7,55.1L144.7,55.1z M156,55.1c0-13.3-10.4-23.6-23.2-23.6
c-12.8,0-23.3,9.6-23.2,24.3v2.8c0,4.8-3.5,8.1-8.5,8.1c-4.6,0-8.6-2.6-8.6-8.8v-14h10.3V32.9H91.7c3.4-3.4,5.2-7.8,6.1-14.2h-11
c-1.4,8.7-5.4,14.2-14,14.2v10.9h8.8v15.4c0,12.5,7.7,18.3,18.3,18.3c5.5,0,11.5-3,14.6-7.7c4.2,5.5,10.8,8.9,18.2,8.9
C145.6,78.6,156,68.2,156,55.1L156,55.1z M196.8,53.9c0,7.8-5.2,12.7-12.2,12.7c-6.5,0-12.3-5-12.3-12v-1.2
c0-6.9,5.6-12.4,12.3-12.4C191.6,41.1,196.8,46.2,196.8,53.9L196.8,53.9z M208.1,54c0-13.9-9.6-23.7-21.4-23.7
c-7.7,0-13.1,3.9-14.7,7v-5.7h-10.9v72c6.1-0.9,9.4-2.9,10.9-9.4v-22c0,0,4.7,5.5,13.8,5.4C197.3,77.4,208.2,68.3,208.1,54
L208.1,54z"/>
<path class="st1" d="M152.5,99v2.2c0,0.5,0.2,0.9,0.7,0.9h0.6v1.5h-1c-1.1,0-1.9-0.8-1.9-1.8V99h-1.2v-1.5c1.1,0,1.7-0.7,1.9-1.9
h1.5c-0.1,0.8-0.4,1.4-0.8,1.9h1.5V99H152.5z M144.9,103.4V100c0-0.7,0.5-1.3,1.3-1.3c0.8,0,1.2,0.5,1.2,1.3v3.5h1.5v-3.7
c0-1.6-0.9-2.4-2.3-2.4c-0.8,0-1.4,0.5-1.7,0.9v-0.7h-1.5v6H144.9z M137.6,99.8c0.2-0.6,0.8-1.1,1.5-1.1c0.8,0,1.3,0.5,1.5,1.1
H137.6z M139.1,97.3c-1.7,0-3,1.4-3,3.2c0,1.8,1.3,3.2,3.1,3.2c1.3,0,2.5-0.9,2.9-2.1h-1.6c-0.3,0.4-0.7,0.7-1.3,0.7
c-0.9,0-1.5-0.6-1.6-1.4h4.6C142.2,98.9,141,97.3,139.1,97.3L139.1,97.3z M127.4,103.4V100c0-0.8,0.4-1.3,1.1-1.3
c0.7,0,1.1,0.5,1.1,1.2v3.5h1.5v-3.5c0-0.8,0.5-1.2,1.1-1.2c0.7,0,1.1,0.4,1.1,1.2v3.5h1.5v-3.7c0-1.6-1-2.5-2.4-2.5
c-0.9,0-1.5,0.4-1.9,0.8c-0.3-0.5-0.9-0.8-1.7-0.8c-0.8,0-1.4,0.5-1.6,0.9v-0.7H126v6H127.4z M120.1,99.8c0.2-0.6,0.8-1.1,1.5-1.1
c0.8,0,1.3,0.5,1.5,1.1H120.1z M121.6,97.3c-1.7,0-3,1.4-3,3.2c0,1.8,1.3,3.2,3.1,3.2c1.3,0,2.5-0.9,2.9-2.1h-1.6
c-0.3,0.4-0.7,0.7-1.3,0.7c-0.9,0-1.5-0.6-1.6-1.4h4.6C124.8,98.9,123.5,97.3,121.6,97.3L121.6,97.3z M114.1,105.3
c-0.8,0-1.5-0.7-1.6-1.5h-1.5c0,1.7,1.4,3,3.1,3c1.7,0,3-1.3,3.1-3h-1.5C115.7,104.6,115,105.3,114.1,105.3L114.1,105.3z
M114.2,102.1c-0.9,0-1.6-0.7-1.6-1.6c0-0.9,0.7-1.5,1.6-1.5c0.8,0,1.6,0.7,1.6,1.5C115.7,101.4,115,102.1,114.2,102.1L114.2,102.1
z M114.1,97.5c-1.7,0-3.1,1.4-3.1,3.1c0,1.7,1.4,3.1,3.1,3.1c1.7,0,3.1-1.4,3.1-3.1c0-0.6-0.2-1.1-0.5-1.6h1.2v-1.5H114.1z
M106.7,102.1c-0.9,0-1.6-0.7-1.6-1.7c0-1,0.7-1.7,1.6-1.7c0.9,0,1.6,0.7,1.6,1.6v0.2C108.3,101.4,107.6,102.1,106.7,102.1
L106.7,102.1z M108.3,97.5v0.6c-0.3-0.5-1-0.8-1.9-0.8c-1.7,0-2.9,1.4-2.9,3.2c0,1.9,1.4,3.1,2.9,3.1c1,0,1.7-0.5,1.8-0.9v0.7h1.5
v-6H108.3z M98.4,103.4V100c0-0.7,0.5-1.3,1.3-1.3c0.8,0,1.2,0.5,1.2,1.3v3.5h1.5v-3.7c0-1.6-0.9-2.4-2.3-2.4
c-0.8,0-1.4,0.5-1.7,0.9v-0.7H97v6H98.4z M92.2,102.1c-0.9,0-1.6-0.7-1.6-1.7c0-1,0.7-1.7,1.6-1.7c0.9,0,1.6,0.7,1.6,1.6v0.2
C93.9,101.4,93.1,102.1,92.2,102.1L92.2,102.1z M93.9,97.5v0.6c-0.3-0.5-1-0.8-1.9-0.8c-1.7,0-2.9,1.4-2.9,3.2
c0,1.9,1.4,3.1,2.9,3.1c1,0,1.7-0.5,1.8-0.9v0.7h1.5v-6H93.9z M80.5,103.4V100c0-0.8,0.4-1.3,1.1-1.3c0.7,0,1.1,0.5,1.1,1.2v3.5
h1.5v-3.5c0-0.8,0.5-1.2,1.1-1.2c0.7,0,1.1,0.4,1.1,1.2v3.5H88v-3.7c0-1.6-1-2.5-2.4-2.5c-0.9,0-1.5,0.4-1.9,0.8
c-0.3-0.5-0.9-0.8-1.7-0.8c-0.8,0-1.4,0.5-1.6,0.9v-0.7h-1.5v6H80.5z M70.5,99.8c0.2-0.6,0.8-1.1,1.5-1.1c0.8,0,1.3,0.5,1.5,1.1
H70.5z M72,97.3c-1.7,0-3,1.4-3,3.2c0,1.8,1.3,3.2,3.1,3.2c1.3,0,2.5-0.9,2.9-2.1h-1.6c-0.3,0.4-0.7,0.7-1.3,0.7
c-0.9,0-1.5-0.6-1.6-1.4H75C75.1,98.9,73.8,97.3,72,97.3L72,97.3z M66.4,101.2c-0.3,0.6-0.8,0.9-1.4,0.9c-0.9,0-1.6-0.7-1.6-1.6
c0-0.9,0.7-1.6,1.6-1.6c0.7,0,1.3,0.4,1.5,1.1H68c-0.3-1.6-1.5-2.6-3.1-2.6c-1.7,0-3.1,1.4-3.1,3.2c0,1.8,1.3,3.2,3,3.2
c1.5,0,2.7-0.9,3.1-2.4H66.4z M60.5,97.5h-2V99H59v4.5h1.5V97.5z M59.6,96.6c0.5,0,0.9-0.4,0.9-1c0-0.5-0.4-0.9-0.9-0.9
c-0.6,0-1,0.4-1,0.9C58.6,96.2,59,96.6,59.6,96.6L59.6,96.6z M54.3,101.5l-1.7-4H51l2.5,6h1.5l2.5-6H56L54.3,101.5z M50,97.5
c-1.1,0-1.7,0.6-2,1.1v-1.1h-1.4v6H48v-2.3c0-1.6,0.9-2.2,2.1-2.2h0.4v-1.5H50z M40.7,99.8c0.2-0.6,0.8-1.1,1.5-1.1
c0.8,0,1.3,0.5,1.5,1.1H40.7z M42.2,97.3c-1.7,0-3,1.4-3,3.2c0,1.8,1.3,3.2,3.1,3.2c1.3,0,2.5-0.9,2.9-2.1h-1.6
c-0.3,0.4-0.7,0.7-1.3,0.7c-0.9,0-1.5-0.6-1.6-1.4h4.6C45.4,98.9,44.1,97.3,42.2,97.3L42.2,97.3z M36,102.4c-0.5,0-0.8-0.3-1-0.7
h-1.5c0.1,0.8,0.7,1.9,2.3,1.9c1.3,0,2.3-0.7,2.3-1.9c0-0.9-0.6-1.5-1.7-1.8C35.4,99.6,35,99.3,35,99c0-0.3,0.3-0.5,0.7-0.5
c0.5,0,0.9,0.3,0.9,0.7h1.5c-0.2-1-0.9-1.9-2.4-1.9c-1.1,0-2.2,0.7-2.2,1.8c0,1.1,1.1,1.7,2,1.9c0.6,0.2,1.2,0.3,1.2,0.7
C36.7,102.1,36.4,102.4,36,102.4L36,102.4z M27.9,100.8c0,0.8-0.5,1.4-1.3,1.4c-0.8,0-1.3-0.5-1.3-1.3v-3.5H24v3.6
c0,1.6,0.9,2.5,2.4,2.5c0.8,0,1.3-0.3,1.6-0.7v0.8c0,0.8-0.8,1.5-1.6,1.5c-0.7,0-1.3-0.5-1.5-1.1h-1.5c0.2,1.5,1.5,2.5,3,2.5
c1.7,0,3-1.3,3-3.1v-6.1h-1.5V100.8z M20.6,102.4c-0.5,0-0.8-0.3-1-0.7h-1.5c0.1,0.8,0.7,1.9,2.3,1.9c1.3,0,2.3-0.7,2.3-1.9
c0-0.9-0.6-1.5-1.7-1.8c-1.1-0.3-1.5-0.6-1.5-0.9c0-0.3,0.3-0.5,0.7-0.5c0.5,0,0.9,0.3,0.9,0.7h1.5c-0.2-1-0.9-1.9-2.4-1.9
c-1.1,0-2.2,0.7-2.2,1.8c0,1.1,1.1,1.7,2,1.9c0.6,0.2,1.2,0.3,1.2,0.7C21.3,102.1,21.1,102.4,20.6,102.4L20.6,102.4z M13.6,102.1
c-0.9,0-1.6-0.7-1.6-1.7c0-1,0.7-1.7,1.6-1.7c0.9,0,1.6,0.7,1.6,1.6v0.2C15.2,101.4,14.5,102.1,13.6,102.1L13.6,102.1z M15.3,97.5
v0.6c-0.3-0.5-1-0.8-1.9-0.8c-1.7,0-2.9,1.4-2.9,3.2c0,1.9,1.4,3.1,2.9,3.1c1,0,1.7-0.5,1.8-0.9v0.7h1.5v-6H15.3z M5.1,99.8
c0.2-0.6,0.8-1.1,1.5-1.1c0.8,0,1.3,0.5,1.5,1.1H5.1z M6.5,97.3c-1.7,0-3,1.4-3,3.2c0,1.8,1.3,3.2,3.1,3.2c1.3,0,2.5-0.9,2.9-2.1
H7.8c-0.3,0.4-0.7,0.7-1.3,0.7c-0.9,0-1.5-0.6-1.6-1.4h4.6C9.7,98.9,8.4,97.3,6.5,97.3L6.5,97.3z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 238.1 113.4" style="enable-background:new 0 0 238.1 113.4;" xml:space="preserve">
<style type="text/css">
.st0{fill:#F08700;}
.st1{fill:#FFFFFF;}
</style>
<g>
<path class="st0" d="M228.1,69.4c4.1,0,7.4-3.3,7.4-7.4c0-4-3.5-7.4-7.4-7.4c-4.2,0-7.4,3.5-7.4,7.4
C220.7,66.1,223.9,69.4,228.1,69.4L228.1,69.4z"/>
<path class="st0" d="M52.6,21.8c4,0,7.2-3.2,7.2-7.3c0-3.9-3.3-7.2-7.2-7.2c-4.3,0-7.3,3.3-7.3,7.2C45.3,18.5,48.3,21.8,52.6,21.8
L52.6,21.8z"/>
<path class="st1" d="M67.7,65.3c-4.6,0-8.6-2.6-8.6-8.8v-0.6l0,0V41.5l0,0V30.7h-15v10.8h4.1v16.3c0,12.5,7.7,18.3,18.3,18.3
c3,0,6.2-0.9,8.9-2.5V60.7C74.2,63.5,71.4,65.3,67.7,65.3L67.7,65.3z M144.7,53.8c0,7-5.3,12.2-11.9,12.2
c-6.6,0-11.9-4.9-11.9-12.2c0-7,5-12.3,11.9-12.3C139.4,41.5,144.7,46.8,144.7,53.8L144.7,53.8z M156,53.8
c0-13.3-10.4-23.6-23.2-23.6s-23.3,9.6-23.2,24.3v2.8c0,4.8-3.5,8.1-8.5,8.1c-4.6,0-8.6-2.6-8.6-8.8v-14h10.3v-11H91.7
c3.4-3.4,5.2-7.8,6.1-14.2h-11c-1.4,8.7-5.4,14.2-14,14.2v10.9h8.8v15.4c0,12.5,7.7,18.3,18.3,18.3c5.5,0,11.5-3,14.6-7.7
c4.2,5.5,10.8,8.9,18.2,8.9C145.6,77.3,156,66.9,156,53.8L156,53.8z M196.8,52.6c0,7.8-5.2,12.7-12.2,12.7c-6.5,0-12.3-5-12.3-12
v-1.2c0-6.9,5.6-12.4,12.3-12.4C191.6,39.8,196.8,44.9,196.8,52.6L196.8,52.6z M208.1,52.7c0-13.9-9.6-23.7-21.4-23.7
c-7.7,0-13.1,3.9-14.7,7v-5.7h-10.9v72c6.1-0.9,9.4-2.9,10.9-9.4v-22c0,0,4.7,5.5,13.8,5.4C197.3,76.1,208.2,67,208.1,52.7
L208.1,52.7z"/>
<path class="st1" d="M152.5,97.7v2.2c0,0.5,0.2,0.9,0.7,0.9h0.6v1.5h-1c-1.1,0-1.9-0.8-1.9-1.8v-2.8h-1.2v-1.5
c1.1,0,1.7-0.7,1.9-1.9h1.5c-0.1,0.8-0.4,1.4-0.8,1.9h1.5v1.5H152.5z M144.9,102.1v-3.4c0-0.7,0.5-1.3,1.3-1.3s1.2,0.5,1.2,1.3v3.5
h1.5v-3.7c0-1.6-0.9-2.4-2.3-2.4c-0.8,0-1.4,0.5-1.7,0.9v-0.7h-1.5v6h1.5V102.1z M137.6,98.5c0.2-0.6,0.8-1.1,1.5-1.1
c0.8,0,1.3,0.5,1.5,1.1H137.6z M139.1,96c-1.7,0-3,1.4-3,3.2c0,1.8,1.3,3.2,3.1,3.2c1.3,0,2.5-0.9,2.9-2.1h-1.6
c-0.3,0.4-0.7,0.7-1.3,0.7c-0.9,0-1.5-0.6-1.6-1.4h4.6C142.2,97.6,141,96,139.1,96L139.1,96z M127.4,102.1v-3.4
c0-0.8,0.4-1.3,1.1-1.3s1.1,0.5,1.1,1.2v3.5h1.5v-3.5c0-0.8,0.5-1.2,1.1-1.2c0.7,0,1.1,0.4,1.1,1.2v3.5h1.5v-3.7
c0-1.6-1-2.5-2.4-2.5c-0.9,0-1.5,0.4-1.9,0.8c-0.3-0.5-0.9-0.8-1.7-0.8s-1.4,0.5-1.6,0.9v-0.7H126v6H127.4z M120.1,98.5
c0.2-0.6,0.8-1.1,1.5-1.1c0.8,0,1.3,0.5,1.5,1.1H120.1z M121.6,96c-1.7,0-3,1.4-3,3.2c0,1.8,1.3,3.2,3.1,3.2c1.3,0,2.5-0.9,2.9-2.1
H123c-0.3,0.4-0.7,0.7-1.3,0.7c-0.9,0-1.5-0.6-1.6-1.4h4.6C124.8,97.6,123.5,96,121.6,96L121.6,96z M114.1,104
c-0.8,0-1.5-0.7-1.6-1.5H111c0,1.7,1.4,3,3.1,3s3-1.3,3.1-3h-1.5C115.7,103.3,115,104,114.1,104L114.1,104z M114.2,100.8
c-0.9,0-1.6-0.7-1.6-1.6s0.7-1.5,1.6-1.5c0.8,0,1.6,0.7,1.6,1.5C115.7,100.1,115,100.8,114.2,100.8L114.2,100.8z M114.1,96.2
c-1.7,0-3.1,1.4-3.1,3.1s1.4,3.1,3.1,3.1s3.1-1.4,3.1-3.1c0-0.6-0.2-1.1-0.5-1.6h1.2v-1.5H114.1z M106.7,100.8
c-0.9,0-1.6-0.7-1.6-1.7s0.7-1.7,1.6-1.7s1.6,0.7,1.6,1.6v0.2C108.3,100.1,107.6,100.8,106.7,100.8L106.7,100.8z M108.3,96.2v0.6
c-0.3-0.5-1-0.8-1.9-0.8c-1.7,0-2.9,1.4-2.9,3.2c0,1.9,1.4,3.1,2.9,3.1c1,0,1.7-0.5,1.8-0.9v0.7h1.5v-6h-1.4V96.2z M98.4,102.1
v-3.4c0-0.7,0.5-1.3,1.3-1.3s1.2,0.5,1.2,1.3v3.5h1.5v-3.7c0-1.6-0.9-2.4-2.3-2.4c-0.8,0-1.4,0.5-1.7,0.9v-0.7H97v6h1.4V102.1z
M92.2,100.8c-0.9,0-1.6-0.7-1.6-1.7s0.7-1.7,1.6-1.7s1.6,0.7,1.6,1.6v0.2C93.9,100.1,93.1,100.8,92.2,100.8L92.2,100.8z
M93.9,96.2v0.6c-0.3-0.5-1-0.8-1.9-0.8c-1.7,0-2.9,1.4-2.9,3.2c0,1.9,1.4,3.1,2.9,3.1c1,0,1.7-0.5,1.8-0.9v0.7h1.5v-6h-1.4V96.2z
M80.5,102.1v-3.4c0-0.8,0.4-1.3,1.1-1.3s1.1,0.5,1.1,1.2v3.5h1.5v-3.5c0-0.8,0.5-1.2,1.1-1.2c0.7,0,1.1,0.4,1.1,1.2v3.5H88v-3.7
c0-1.6-1-2.5-2.4-2.5c-0.9,0-1.5,0.4-1.9,0.8c-0.3-0.5-0.9-0.8-1.7-0.8c-0.8,0-1.4,0.5-1.6,0.9v-0.7h-1.5v6H80.5z M70.5,98.5
c0.2-0.6,0.8-1.1,1.5-1.1c0.8,0,1.3,0.5,1.5,1.1H70.5z M72,96c-1.7,0-3,1.4-3,3.2c0,1.8,1.3,3.2,3.1,3.2c1.3,0,2.5-0.9,2.9-2.1
h-1.6c-0.3,0.4-0.7,0.7-1.3,0.7c-0.9,0-1.5-0.6-1.6-1.4H75C75.1,97.6,73.8,96,72,96L72,96z M66.4,99.9c-0.3,0.6-0.8,0.9-1.4,0.9
c-0.9,0-1.6-0.7-1.6-1.6s0.7-1.6,1.6-1.6c0.7,0,1.3,0.4,1.5,1.1H68c-0.3-1.6-1.5-2.6-3.1-2.6c-1.7,0-3.1,1.4-3.1,3.2
c0,1.8,1.3,3.2,3,3.2c1.5,0,2.7-0.9,3.1-2.4h-1.5V99.9z M60.5,96.2h-2v1.5H59v4.5h1.5V96.2z M59.6,95.3c0.5,0,0.9-0.4,0.9-1
c0-0.5-0.4-0.9-0.9-0.9c-0.6,0-1,0.4-1,0.9C58.6,94.9,59,95.3,59.6,95.3L59.6,95.3z M54.3,100.2l-1.7-4H51l2.5,6H55l2.5-6H56
L54.3,100.2z M50,96.2c-1.1,0-1.7,0.6-2,1.1v-1.1h-1.4v6H48v-2.3c0-1.6,0.9-2.2,2.1-2.2h0.4v-1.5H50z M40.7,98.5
c0.2-0.6,0.8-1.1,1.5-1.1c0.8,0,1.3,0.5,1.5,1.1H40.7z M42.2,96c-1.7,0-3,1.4-3,3.2c0,1.8,1.3,3.2,3.1,3.2c1.3,0,2.5-0.9,2.9-2.1
h-1.6c-0.3,0.4-0.7,0.7-1.3,0.7c-0.9,0-1.5-0.6-1.6-1.4h4.6C45.4,97.6,44.1,96,42.2,96L42.2,96z M36,101.1c-0.5,0-0.8-0.3-1-0.7
h-1.5c0.1,0.8,0.7,1.9,2.3,1.9c1.3,0,2.3-0.7,2.3-1.9c0-0.9-0.6-1.5-1.7-1.8c-1-0.3-1.4-0.6-1.4-0.9s0.3-0.5,0.7-0.5
c0.5,0,0.9,0.3,0.9,0.7h1.5c-0.2-1-0.9-1.9-2.4-1.9c-1.1,0-2.2,0.7-2.2,1.8c0,1.1,1.1,1.7,2,1.9c0.6,0.2,1.2,0.3,1.2,0.7
C36.7,100.8,36.4,101.1,36,101.1L36,101.1z M27.9,99.5c0,0.8-0.5,1.4-1.3,1.4s-1.3-0.5-1.3-1.3v-3.5H24v3.6c0,1.6,0.9,2.5,2.4,2.5
c0.8,0,1.3-0.3,1.6-0.7v0.8c0,0.8-0.8,1.5-1.6,1.5c-0.7,0-1.3-0.5-1.5-1.1h-1.5c0.2,1.5,1.5,2.5,3,2.5c1.7,0,3-1.3,3-3.1V96h-1.5
V99.5z M20.6,101.1c-0.5,0-0.8-0.3-1-0.7h-1.5c0.1,0.8,0.7,1.9,2.3,1.9c1.3,0,2.3-0.7,2.3-1.9c0-0.9-0.6-1.5-1.7-1.8
s-1.5-0.6-1.5-0.9s0.3-0.5,0.7-0.5c0.5,0,0.9,0.3,0.9,0.7h1.5c-0.2-1-0.9-1.9-2.4-1.9c-1.1,0-2.2,0.7-2.2,1.8c0,1.1,1.1,1.7,2,1.9
c0.6,0.2,1.2,0.3,1.2,0.7C21.3,100.8,21.1,101.1,20.6,101.1L20.6,101.1z M13.6,100.8c-0.9,0-1.6-0.7-1.6-1.7s0.7-1.7,1.6-1.7
c0.9,0,1.6,0.7,1.6,1.6v0.2C15.2,100.1,14.5,100.8,13.6,100.8L13.6,100.8z M15.3,96.2v0.6c-0.3-0.5-1-0.8-1.9-0.8
c-1.7,0-2.9,1.4-2.9,3.2c0,1.9,1.4,3.1,2.9,3.1c1,0,1.7-0.5,1.8-0.9v0.7h1.5v-6h-1.4V96.2z M5.1,98.5c0.2-0.6,0.8-1.1,1.5-1.1
c0.8,0,1.3,0.5,1.5,1.1H5.1z M6.5,96c-1.7,0-3,1.4-3,3.2c0,1.8,1.3,3.2,3.1,3.2c1.3,0,2.5-0.9,2.9-2.1H7.8
c-0.3,0.4-0.7,0.7-1.3,0.7c-0.9,0-1.5-0.6-1.6-1.4h4.6C9.7,97.6,8.4,96,6.5,96L6.5,96z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 184.3 184.3" style="enable-background:new 0 0 184.3 184.3;" xml:space="preserve">
<style type="text/css">
.st0{fill:#202B2F;}
.st1{clip-path:url(#SVGID_00000154414157060718331780000015037401224567852977_);fill:none;stroke:#F18700;stroke-width:8.546;stroke-miterlimit:10;}
</style>
<g>
<g>
<path class="st0" d="M91.4,181.1c49.4,0,89.7-40.3,89.7-89.7c0-48.1-41.6-89.7-89.7-89.7C40.7,1.7,1.7,43.3,1.7,91.4
C1.7,140.8,40.7,181.1,91.4,181.1"/>
</g>
<g>
<defs>
<path id="SVGID_1_" d="M1.7,91.4c0,49.4,39,89.7,89.7,89.7c49.4,0,89.7-40.3,89.7-89.7c0-48.1-41.6-89.7-89.7-89.7
C40.7,1.7,1.7,43.3,1.7,91.4"/>
</defs>
<use xlink:href="#SVGID_1_" style="overflow:visible;fill:#202B2F;"/>
<clipPath id="SVGID_00000015353187537913533220000007234501527802501527_">
<use xlink:href="#SVGID_1_" style="overflow:visible;"/>
</clipPath>
<path style="clip-path:url(#SVGID_00000015353187537913533220000007234501527802501527_);fill:none;stroke:#F18700;stroke-width:8.546;stroke-miterlimit:10;" d="
M113.9,207.1L113.9,207.1l1.5-2.4l1.8,0.1c4,0.2,7.5-2.8,7.7-6.9c0.1-0.9-0.1-1.8-0.3-2.7l-1.6-5l2.4-10.3l16.2-2.1
c3.1-0.4,6.2,0.7,8.4,2.9c2.1,2.1,3.1,5,2.8,8c-1.1,6.3-3.7,12.3-7.4,17.6c-14.2,21.8-11.1,46.5,8.6,66.2c3,3,7.7,3.2,11,0.5
c3.4-2.6,4.3-7.4,2-11.1c-12.3-20.5-8.9-37.4,10.1-50.3c13.8-9.3,18.4-24,13.4-42.5c-0.3-1.3-1.7-4.6-4.2-10.9
c-1.4-3.4-2.8-7-4-10.2c-0.9-2.3,0.2-5,2.6-6l11.7-4.9l7.2,7.7l1.1,5.1c0.8,4,4.7,6.5,8.7,5.6c0.9-0.2,1.8-0.5,2.5-1.1l1.5-1
l2.5,1.3c3.4,1.7,7.6,0.4,9.3-3c1-1.9,1-4.1,0.1-6l-1-2.1l1.7-2.8c2-3.2,1-7.4-2.2-9.4c-0.5-0.3-1-0.6-1.6-0.7l-5.9-1.8l-7.8-8.3
c-6.3-6.7-16-8.8-24.4-5.3l-14.4,6c-1.1-2-2.4-4-3.8-5.8c-2.7-3.5-5.7-6.8-9-9.8c-1.6-1.5-2.3-3.6-1.8-5.7l4.2-18.8
c2-8.9-1.8-18.2-9.5-23.2l-9.6-6.2l-2.8-5.5c-1.7-3.4-5.8-4.7-9.1-3c-0.5,0.3-1,0.6-1.5,1l-2.5,2.2l-2.3-0.6c-3.7-1-7.5,1.3-8.4,5
c-0.5,2-0.1,4.2,1.2,5.9l1.7,2.3l-0.7,1.7c-1.6,3.7,0.1,8,3.8,9.6c0.8,0.4,1.8,0.6,2.7,0.6l5.3,0.2l8.9,5.8L138.1,90
c-6.3-3.1-12.9-5.6-19.6-7.6c-1.2-0.3-11.3-3.5-12-12.5c0-0.2,0-0.3-0.1-0.5c-0.3-1.7-2.3-9.9-7.5-12.6l-11.7-7.8
c-7.1-4.8-16-6.5-24.3-4.5c-3.1,0.6-5.9,2.1-8.3,4.2c-3.1,3.8-4.6,8.5-4.5,13.4c-0.3,5.9,1,11.7,3.9,16.8
c3.2,6.8,7.7,12.9,13.1,18.1c3.3,2.3,7.2,3.6,11.3,3.7c5.7,1.5,10.5,5.3,13.2,10.5c1.3,3,3,6.6,4.9,10.6c0.5,1.1,0.4,2.4-0.3,3.4
l-7,9.1L79,131.2l-3.5-3.9c-2.7-3-7.3-3.3-10.3-0.6c-0.7,0.6-1.2,1.4-1.7,2.2l-0.8,1.7l-2.1,0.1c-4,0.2-7,3.6-6.8,7.6
c0.1,2.2,1.2,4.2,3,5.5l1.3,0.9l-0.1,3.3c-0.1,3.8,2.8,6.9,6.6,7c0.6,0,1.2,0,1.8-0.2l6-1.4l10.9,3.3c8.8,2.7,18.2-0.4,23.8-7.6
l2.6-3.4c0.2-0.3,0.6-0.6,1.1-0.6c0.4,0,0.8,0.2,1.1,0.5c3.7,4.1,7.7,7.8,12.1,11.1l-2.3,0.3c-9.1,1.2-16.4,7.9-18.5,16.8
l-2.6,11.1l-4.2,4.5c-2.6,2.7-2.4,7.1,0.3,9.6c0.4,0.4,0.9,0.8,1.4,1l2.9,1.6l0.2,2.3c0.4,3.8,3.8,6.6,7.6,6.2
C110.9,210,112.8,208.8,113.9,207.1z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 184.3 184.3" style="enable-background:new 0 0 184.3 184.3;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
.st1{clip-path:url(#SVGID_00000080179353162800512540000009207223319737624221_);fill:none;stroke:#F18700;stroke-width:8.546;stroke-miterlimit:10;}
</style>
<g>
<g>
<path class="st0" d="M91.4,181.1c49.4,0,89.7-40.3,89.7-89.7c0-48.1-41.6-89.7-89.7-89.7C40.7,1.7,1.7,43.3,1.7,91.4
C1.7,140.8,40.7,181.1,91.4,181.1"/>
</g>
<g>
<defs>
<path id="SVGID_1_" d="M1.7,91.4c0,49.4,39,89.7,89.7,89.7c49.4,0,89.7-40.3,89.7-89.7c0-48.1-41.6-89.7-89.7-89.7
C40.7,1.7,1.7,43.3,1.7,91.4"/>
</defs>
<use xlink:href="#SVGID_1_" style="overflow:visible;fill:#FFFFFF;"/>
<clipPath id="SVGID_00000095318863407012403130000015283420982180448417_">
<use xlink:href="#SVGID_1_" style="overflow:visible;"/>
</clipPath>
<path style="clip-path:url(#SVGID_00000095318863407012403130000015283420982180448417_);fill:none;stroke:#F18700;stroke-width:8.546;stroke-miterlimit:10;" d="
M113.9,207.1L113.9,207.1l1.5-2.4l1.8,0.1c4,0.2,7.5-2.8,7.7-6.9c0.1-0.9-0.1-1.8-0.3-2.7l-1.6-5l2.4-10.3l16.2-2.1
c3.1-0.4,6.2,0.7,8.4,2.9c2.1,2.1,3.1,5,2.8,8c-1.1,6.3-3.7,12.3-7.4,17.6c-14.2,21.8-11.1,46.5,8.6,66.2c3,3,7.7,3.2,11,0.5
c3.4-2.6,4.3-7.4,2-11.1c-12.3-20.5-8.9-37.4,10.1-50.3c13.8-9.3,18.4-24,13.4-42.5c-0.3-1.3-1.7-4.6-4.2-10.9
c-1.4-3.4-2.8-7-4-10.2c-0.9-2.3,0.2-5,2.6-6l11.7-4.9l7.2,7.7l1.1,5.1c0.8,4,4.7,6.5,8.7,5.6c0.9-0.2,1.8-0.5,2.5-1.1l1.5-1
l2.5,1.3c3.4,1.7,7.6,0.4,9.3-3c1-1.9,1-4.1,0.1-6l-1-2.1l1.7-2.8c2-3.2,1-7.4-2.2-9.4c-0.5-0.3-1-0.6-1.6-0.7l-5.9-1.8l-7.8-8.3
c-6.3-6.7-16-8.8-24.4-5.3l-14.4,6c-1.1-2-2.4-4-3.8-5.8c-2.7-3.5-5.7-6.8-9-9.8c-1.6-1.5-2.3-3.6-1.8-5.7l4.2-18.8
c2-8.9-1.8-18.2-9.5-23.2l-9.6-6.2l-2.8-5.5c-1.7-3.4-5.8-4.7-9.1-3c-0.5,0.3-1,0.6-1.5,1l-2.5,2.2l-2.3-0.6c-3.7-1-7.5,1.3-8.4,5
c-0.5,2-0.1,4.2,1.2,5.9l1.7,2.3l-0.7,1.7c-1.6,3.7,0.1,8,3.8,9.6c0.8,0.4,1.8,0.6,2.7,0.6l5.3,0.2l8.9,5.8L138.1,90
c-6.3-3.1-12.9-5.6-19.6-7.6c-1.2-0.3-11.3-3.5-12-12.5c0-0.2,0-0.3-0.1-0.5c-0.3-1.7-2.3-9.9-7.5-12.6l-11.7-7.8
c-7.1-4.8-16-6.5-24.3-4.5c-3.1,0.6-5.9,2.1-8.3,4.2c-3.1,3.8-4.6,8.5-4.5,13.4c-0.3,5.9,1,11.7,3.9,16.8
c3.2,6.8,7.7,12.9,13.1,18.1c3.3,2.3,7.2,3.6,11.3,3.7c5.7,1.5,10.5,5.3,13.2,10.5c1.3,3,3,6.6,4.9,10.6c0.5,1.1,0.4,2.4-0.3,3.4
l-7,9.1L79,131.2l-3.5-3.9c-2.7-3-7.3-3.3-10.3-0.6c-0.7,0.6-1.2,1.4-1.7,2.2l-0.8,1.7l-2.1,0.1c-4,0.2-7,3.6-6.8,7.6
c0.1,2.2,1.2,4.2,3,5.5l1.3,0.9l-0.1,3.3c-0.1,3.8,2.8,6.9,6.6,7c0.6,0,1.2,0,1.8-0.2l6-1.4l10.9,3.3c8.8,2.7,18.2-0.4,23.8-7.6
l2.6-3.4c0.2-0.3,0.6-0.6,1.1-0.6c0.4,0,0.8,0.2,1.1,0.5c3.7,4.1,7.7,7.8,12.1,11.1l-2.3,0.3c-9.1,1.2-16.4,7.9-18.5,16.8
l-2.6,11.1l-4.2,4.5c-2.6,2.7-2.4,7.1,0.3,9.6c0.4,0.4,0.9,0.8,1.4,1l2.9,1.6l0.2,2.3c0.4,3.8,3.8,6.6,7.6,6.2
C110.9,210,112.8,208.8,113.9,207.1z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 184.3 184.3" style="enable-background:new 0 0 184.3 184.3;" xml:space="preserve">
<style type="text/css">
.st0{fill:#F18700;}
.st1{clip-path:url(#SVGID_00000137816205278705090550000017982420943049526169_);fill:none;stroke:#FFFFFF;stroke-width:8.546;stroke-miterlimit:10;}
</style>
<g>
<g>
<path class="st0" d="M91.4,181.1c49.4,0,89.7-40.3,89.7-89.7c0-48.1-41.6-89.7-89.7-89.7C40.7,1.7,1.7,43.3,1.7,91.4
C1.7,140.8,40.7,181.1,91.4,181.1"/>
</g>
<g>
<defs>
<path id="SVGID_1_" d="M1.7,91.4c0,49.4,39,89.7,89.7,89.7c49.4,0,89.7-40.3,89.7-89.7c0-48.1-41.6-89.7-89.7-89.7
C40.7,1.7,1.7,43.3,1.7,91.4"/>
</defs>
<clipPath id="SVGID_00000001625123124405100830000017779290640023179407_">
<use xlink:href="#SVGID_1_" style="overflow:visible;"/>
</clipPath>
<path style="clip-path:url(#SVGID_00000001625123124405100830000017779290640023179407_);fill:none;stroke:#FFFFFF;stroke-width:8.546;stroke-miterlimit:10;" d="
M113.9,207.1L113.9,207.1l1.5-2.4l1.8,0.1c4,0.2,7.5-2.8,7.7-6.9c0.1-0.9-0.1-1.8-0.3-2.7l-1.6-5l2.4-10.3l16.2-2.1
c3.1-0.4,6.2,0.7,8.4,2.9c2.1,2.1,3.1,5,2.8,8c-1.1,6.3-3.7,12.3-7.4,17.6c-14.2,21.8-11.1,46.5,8.6,66.2c3,3,7.7,3.2,11,0.5
c3.4-2.6,4.3-7.4,2-11.1c-12.3-20.5-8.9-37.4,10.1-50.3c13.8-9.3,18.4-24,13.4-42.5c-0.3-1.3-1.7-4.6-4.2-10.9
c-1.4-3.4-2.8-7-4-10.2c-0.9-2.3,0.2-5,2.6-6l11.7-4.9l7.2,7.7l1.1,5.1c0.8,4,4.7,6.5,8.7,5.6c0.9-0.2,1.8-0.5,2.5-1.1l1.5-1
l2.5,1.3c3.4,1.7,7.6,0.4,9.3-3c1-1.9,1-4.1,0.1-6l-1-2.1l1.7-2.8c2-3.2,1-7.4-2.2-9.4c-0.5-0.3-1-0.6-1.6-0.7l-5.9-1.8l-7.8-8.3
c-6.3-6.7-16-8.8-24.4-5.3l-14.4,6c-1.1-2-2.4-4-3.8-5.8c-2.7-3.5-5.7-6.8-9-9.8c-1.6-1.5-2.3-3.6-1.8-5.7l4.2-18.8
c2-8.9-1.8-18.2-9.5-23.2l-9.6-6.2l-2.8-5.5c-1.7-3.4-5.8-4.7-9.1-3c-0.5,0.3-1,0.6-1.5,1l-2.5,2.2l-2.3-0.6c-3.7-1-7.5,1.3-8.4,5
c-0.5,2-0.1,4.2,1.2,5.9l1.7,2.3l-0.7,1.7c-1.6,3.7,0.1,8,3.8,9.6c0.8,0.4,1.8,0.6,2.7,0.6l5.3,0.2l8.9,5.8L138.1,90
c-6.3-3.1-12.9-5.6-19.6-7.6c-1.2-0.3-11.3-3.5-12-12.5c0-0.2,0-0.3-0.1-0.5c-0.3-1.7-2.3-9.9-7.5-12.6l-11.7-7.8
c-7.1-4.8-16-6.5-24.3-4.5c-3.1,0.6-5.9,2.1-8.3,4.2c-3.1,3.8-4.6,8.5-4.5,13.4c-0.3,5.9,1,11.7,3.9,16.8
c3.2,6.8,7.7,12.9,13.1,18.1c3.3,2.3,7.2,3.6,11.3,3.7c5.7,1.5,10.5,5.3,13.2,10.5c1.3,3,3,6.6,4.9,10.6c0.5,1.1,0.4,2.4-0.3,3.4
l-7,9.1L79,131.2l-3.5-3.9c-2.7-3-7.3-3.3-10.3-0.6c-0.7,0.6-1.2,1.4-1.7,2.2l-0.8,1.7l-2.1,0.1c-4,0.2-7,3.6-6.8,7.6
c0.1,2.2,1.2,4.2,3,5.5l1.3,0.9l-0.1,3.3c-0.1,3.8,2.8,6.9,6.6,7c0.6,0,1.2,0,1.8-0.2l6-1.4l10.9,3.3c8.8,2.7,18.2-0.4,23.8-7.6
l2.6-3.4c0.2-0.3,0.6-0.6,1.1-0.6c0.4,0,0.8,0.2,1.1,0.5c3.7,4.1,7.7,7.8,12.1,11.1l-2.3,0.3c-9.1,1.2-16.4,7.9-18.5,16.8
l-2.6,11.1l-4.2,4.5c-2.6,2.7-2.4,7.1,0.3,9.6c0.4,0.4,0.9,0.8,1.4,1l2.9,1.6l0.2,2.3c0.4,3.8,3.8,6.6,7.6,6.2
C110.9,210,112.8,208.8,113.9,207.1z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

Some files were not shown because too many files have changed in this diff Show More