diff --git a/.doc/contributing-guide/2021.contributing-stickers-side-by-side.png b/.doc/contributing-guide/2021.contributing-stickers-side-by-side.png
new file mode 100644
index 0000000000..d63f1f72a6
Binary files /dev/null and b/.doc/contributing-guide/2021.contributing-stickers-side-by-side.png differ
diff --git a/.doc/contributing-guide/2022.contributing-stickers-side-by-side.png b/.doc/contributing-guide/2022.contributing-stickers-side-by-side.png
new file mode 100644
index 0000000000..adaea4d86e
Binary files /dev/null and b/.doc/contributing-guide/2022.contributing-stickers-side-by-side.png differ
diff --git a/.doc/contributing-guide/contributing-stickers-side-by-side.png b/.doc/contributing-guide/contributing-stickers-side-by-side.png
deleted file mode 100644
index 8bc8cc2082..0000000000
Binary files a/.doc/contributing-guide/contributing-stickers-side-by-side.png and /dev/null differ
diff --git a/.doc/itop-version-history.md b/.doc/itop-version-history.md
new file mode 100644
index 0000000000..32ee32dbf4
--- /dev/null
+++ b/.doc/itop-version-history.md
@@ -0,0 +1,61 @@
+# iTop version history
+
+```mermaid
+%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'showBranches': true,'mainBranchName': 'develop','rotateCommitLabel': true}} }%%
+gitGraph
+ commit id: "2016-07-06" tag: "2.3.0"
+ branch support/2.3 order: 900
+ commit id: "2016-07-08" tag: "2.3.1"
+ commit id: "2016-12-22" tag: "2.3.3"
+ commit id: "2017-04-14" tag: "2.3.4"
+ checkout develop
+ commit id: "2017-07-12" tag: "2.4.0-beta" type: REVERSE
+ commit id: "2017-11-16" tag: "2.4.0"
+ branch support/2.4 order: 890
+ commit id: "2018-02-14" tag: "2.4.1"
+ checkout develop
+ commit id: "2018-04-25" tag: "2.5.0-beta" type: REVERSE
+ checkout support/2.4
+ commit id: "2018-06-14" tag: "2.4.2"
+ checkout develop
+ commit id: "2018-06-27" tag: "2.5.0"
+ branch support/2.5 order: 880
+ checkout develop
+ commit id: "2019-01-09" tag: "2.6.0"
+ branch support/2.6 order: 870
+ commit id: "2019-03-28" tag: "2.6.1"
+ checkout develop
+ commit id: "2019-12-18" tag: "2.7.0-beta" type: REVERSE
+ checkout support/2.5
+ commit id: "2020-01-22" tag: "2.5.4"
+ checkout support/2.6
+ commit id: "2020-01-23" tag: "2.6.3"
+ checkout develop
+ commit id: "2020-01-29" tag: "2.7.0-beta2" type: REVERSE
+ branch support/2.7 order: 860
+ commit id: "2020-04-01" tag: "2.7.0-1"
+ checkout support/2.6
+ commit id: "2020-04-22" tag: "2.6.4"
+ checkout support/2.7
+ commit id: "2020-06-26" tag: "2.7.1"
+ checkout support/2.7
+ commit id: "2020-12-09" tag: "2.7.3"
+ commit id: "2021-03-31" tag: "2.7.4"
+ checkout develop
+ commit id: "2021-04-06" tag: "3.0.0-beta" type: REVERSE
+ checkout support/2.7
+ commit id: "2021-07-05" tag: "2.7.5"
+ checkout develop
+ commit id: "2021-07-05." tag: "3.0.0-beta2" type: REVERSE
+ checkout support/2.7
+ commit id: "2021-12-17" tag: "2.7.6"
+ checkout develop
+ commit id: "2022-01-04" tag: "3.0.0"
+ branch support/3.0 order: 850
+ commit id: "2022-04-08" tag: "3.0.1"
+ checkout support/2.7
+ commit id: "2022-07-11" tag: "2.7.7"
+ checkout support/3.0
+ commit id: "2022-09-12" tag: "3.0.2-1"
+ checkout develop
+```
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000000..690f3fdbc1
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,48 @@
+# Set the default behavior, in case people don't have core.autocrlf set.
+* text=auto
+
+# Explicitly declare text files you want to always be normalized and converted
+# to native line endings on checkout.
+*.bash text eol=lf
+*.bat text eol=lf
+*.cmd text eol=lf
+*.css text eol=lf
+*.scss text eol=lf
+*.dist text eol=lf
+.editorconfig text eol=lf
+.env* text eol=lf
+.gitignore text eol=lf
+.htaccess text eol=lf
+*.htm text eol=lf
+*.html text eol=lf
+*.ini text eol=lf
+*.js text eol=lf
+*.json text eol=lf
+*.lock text eol=lf
+*.md text eol=lf
+*.php text eol=lf
+*.php_cs text eol=lf
+*.php8 text eol=lf
+*.plex text eol=lf
+*.sh text eol=lf
+*.svg text eol=lf
+*.ts text eol=lf
+*.twig text eol=lf
+*.txt text eol=lf
+*.xml text eol=lf
+*.xsd text eol=lf
+*.yaml text eol=lf
+*.yml text eol=lf
+
+# Denote all files that are truly binary and should not be modified.
+*.png binary
+*.jpeg binary
+*.jpg binary
+*.gif binary
+*.ico binary
+*.pdf binary
+*.swf binary
+*.zip binary
+*.ttf binary
+*.woff binary
+*.woff2 binary
diff --git a/.gitignore b/.gitignore
index 4c314c12db..9029eaca76 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,9 +45,13 @@ test/vendor/*
!/log/index.php
!/log/web.config
+# PHPUnit cache file
+/test/.phpunit.result.cache
+
# Jetbrains
/.idea/**
+!/.idea/IntelliLang.xml
# doc. generation
/.doc/vendor
diff --git a/.idea/IntelliLang.xml b/.idea/IntelliLang.xml
new file mode 100644
index 0000000000..2703c6f182
--- /dev/null
+++ b/.idea/IntelliLang.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ iTop - Class method code
+
+ name(..) = 'method' and count(/itop_design) = 1
+
+
+ iTop - Snippet code
+
+ name(..) = 'snippets' and count(/itop_design) = 1
+
+
+
\ No newline at end of file
diff --git a/.make/composer/listOutdated.php b/.make/composer/listOutdated.php
index 4c47bfa81e..84ab90d740 100644
--- a/.make/composer/listOutdated.php
+++ b/.make/composer/listOutdated.php
@@ -19,16 +19,23 @@
*
*/
-$iTopFolder = __DIR__ . "/../../" ;
+/**
+ * Alias for `composer show -loD`
+ * You can also use `composer outdated -D`
+ *
+ * @link https://getcomposer.org/doc/03-cli.md#show
+ */
-require_once ("$iTopFolder/approot.inc.php");
+$iTopFolder = __DIR__."/../../";
+
+require_once("$iTopFolder/approot.inc.php");
$sApproot = APPROOT;
$aTrace = array();
$aParamsConfig = array(
'composer-path' => array(
- 'default' => 'composer.phar',
- )
+ 'default' => 'composer',
+ ),
);
$aParamsConfigNotFound = array_flip(array_keys($aParamsConfig));
$aGivenArgs = $argv;
diff --git a/.make/composer/rmDeniedTestDir.php b/.make/composer/rmDeniedTestDir.php
index 6a5f7837ce..a7f0072c52 100644
--- a/.make/composer/rmDeniedTestDir.php
+++ b/.make/composer/rmDeniedTestDir.php
@@ -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);
}
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 2d03f2bdb9..32c75ebccc 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -27,11 +27,14 @@ If you have an idea you're sure would benefit to all of iTop users, you may
[create a corresponding ticket](https://sourceforge.net/p/itop/tickets/new/) to submit it, but be warned that there are lots of good
reasons to refuse such changes.
-### 📄 License
-iTop is distributed under the AGPL-3.0 license (see the [license.txt] file),
-your code must comply with this license.
+### 📄 License and copyright
+iTop is distributed under the AGPL-3.0 license (see the [license.txt] file).
-If you want to use another license, you may [create an extension][wiki new ext].
+The iTop repository is divided in three parts: iTop (mainly PHP/JS/XML sources and dictionaries), images, and third-party libraries.
+Combodo has the copyright on most of the source files in the iTop part of the repository: please do not modify the existing file copyrights.
+Anyhow, you are encouraged to signal your contribution by the mean of `@author` annotations.
+
+If you want to use another license or keep the code ownership (copyright), you may [create an extension][wiki new ext].
[license.txt]: https://github.com/Combodo/iTop/blob/develop/license.txt
[wiki new ext]: https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Astart#by_writing_your_own_extension
@@ -52,26 +55,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.
@@ -111,9 +114,9 @@ Our tests are located in the `test/` directory, containing a PHPUnit config file
* Use the present tense ("Add feature" not "Added feature")
* Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
* Limit the first line to 72 characters or less
-* Please start the commit message with an applicable emoji code (following the [Gitmoji guide](https://gitmoji.carloscuesta.me/)).
- Beware to use the code (for example `:bug:`) and not the character (🐛) as Unicode support in git clients is very poor for now...
- Emoji examples :
+* Please start the commit message with an applicable emoji code (following the [Gitmoji guide](https://gitmoji.dev/)).
+ Beware to use the code (for example `:bug:`) and not the character (🐛) as Unicode support in git clients is very poor for now...
+ Emoji examples :
* 🌐 `:globe_with_meridians:` for translations
* 🎨 `:art:` when improving the format/structure of the code
* ⚡️ `:zap:` when improving performance
@@ -133,19 +136,17 @@ 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
-We are thankful for all your contributions to the iTop universe! As a thank you gift, we will send stickers to every iTop (& extensions) contributors!
+We are thankful for all your contributions to the iTop universe! As a thank you gift, we will send stickers to every iTop (& extensions) contributors!
-Stickers' design might change from one year to another. For the first year we wanted to try a "craft beer label" look, see examples below:
+We have one sticker per contribution type. You might get multiple stickers with one contribution though :)
* Bug hunter: Fix a bug
* Translator: Add/update translations
@@ -157,4 +158,6 @@ Stickers' design might change from one year to another. For the first year we wa
* Beta tester: Test and give feedback on beta releases
* Extension developer: Develop and publish an extension
-
+Here is the design of each stickers for year 2022:
+
+
diff --git a/README.md b/README.md
index b291bbc3d7..637259eccc 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,11 @@
-# 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]
@@ -42,6 +40,7 @@ iTop also offers mass import tools and web services to integrate with your IT
- [Software requirements][4]
- [Documentation][5] covering both iTop and its official extensions
- [iTop Hub][6] : discover and install extensions !
+ - [iTop versions history][7]
[1]: https://sourceforge.net/p/itop/discussion/
@@ -50,6 +49,7 @@ iTop also offers mass import tools and web services to integrate with your IT
[4]: https://www.itophub.io/wiki/page?id=latest:install:upgrading_itop
[5]: https://www.itophub.io/wiki
[6]: https://store.itophub.io/en_US/
+[7]: .doc/itop-version-history.md
[10]: https://www.itophub.io/wiki/page?id=latest%3Adatamodel%3Astart#configuration_management_cmdb
[11]: https://www.itophub.io/wiki/page?id=latest%3Adatamodel%3Astart#ticketing
@@ -78,18 +78,19 @@ We would like to give a special thank you 🤗 to the people from the community
- Alves, David
- Beck, Pedro
+- Beer, Christian (a.k.a [@ChristianBeer](https://www.github.com/ChristianBeer))
- Bilger, Jean-François
-- Bostoen, Jeffrey (a.k.a @jbostoen)
+- Bostoen, Jeffrey (a.k.a [@jbostoen](https://www.github.com/jbostoen))
- Cardoso, Anderson
- Cassaro, Bruno
-- Casteleyn, Thomas (a.k.a @Hipska)
+- Casteleyn, Thomas (a.k.a [@Hipska](https://www.github.com/Hipska))
- Castro, Randall Badilla
- Colantoni, Maria Laura
- Couronné, Guy
- Dvořák, Lukáš
- Goethals, Stefan
- Gumble, David
-- Kaltefleiter, Lars (a.k.a @larhip)
+- Kaltefleiter, Lars (a.k.a [@larhip](https://www.github.com/larhip))
- Khamit, Shamil
- Kincel, Martin
- Konečný, Kamil
@@ -98,12 +99,15 @@ We would like to give a special thank you 🤗 to the people from the community
- Lazcano, Federico
- Lucas, Jonathan
- Malik, Remie
-- Mindêllo de Andrade, Lucas (a.k.a @rokam)
+- Mindêllo de Andrade, Lucas (a.k.a [@rokam](https://www.github.com/rokam))
+- Mozart de Oliveira, Eduardo (a.k.a [@eduardomozart](https://github.com/eduardomozart))
- Raenker, Martin
+- Roháč, Richard (a.k.a [@RohacRichard](https://github.com/RohacRichard))
- Rosenke, Stephan
+- Rudner, Björn (a.k.a [@rudnerbjoern](https://github.com/rudnerbjoern))
- Seki, Shoji
- Shilov, Vladimir
-- Stukalov, Ilya (a.k.a @ilya-stukalov)
+- Stukalov, Ilya (a.k.a [@ilya](https://www.github.com/ilya)-stukalov)
- Tulio, Marco
- Turrubiates, Miguel
@@ -114,6 +118,7 @@ We would like to give a special thank you 🤗 to the people from the community
- DudekArtur
- Karkoff1212
- Laura
+- nv35
- Purple Grape
- Schlobinux
- theBigOne
diff --git a/addons/userrights/userrightsmatrix.class.inc.php b/addons/userrights/userrightsmatrix.class.inc.php
index d80af3ed04..da64e17df7 100644
--- a/addons/userrights/userrightsmatrix.class.inc.php
+++ b/addons/userrights/userrightsmatrix.class.inc.php
@@ -121,7 +121,6 @@ class UserRightsMatrix extends UserRightsAddOnAPI
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
{
// Maybe we should check that no other user with userid == 0 exists
- CMDBObject::SetTrackInfo('Initialization');
$oUser = new UserLocal();
$oUser->Set('login', $sAdminUser);
$oUser->Set('password', $sAdminPwd);
diff --git a/addons/userrights/userrightsprofile.class.inc.php b/addons/userrights/userrightsprofile.class.inc.php
index 1fb9fc3b1e..9d1c771bec 100644
--- a/addons/userrights/userrightsprofile.class.inc.php
+++ b/addons/userrights/userrightsprofile.class.inc.php
@@ -10,7 +10,7 @@ define('PORTAL_PROFILE_NAME', 'Portal user');
class UserRightsBaseClassGUI extends cmdbAbstractObject
{
// Whenever something changes, reload the privileges
-
+
protected function AfterInsert()
{
UserRights::FlushPrivileges();
@@ -59,7 +59,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
}
protected static $m_aCacheProfiles = null;
-
+
public static function DoCreateProfile($sName, $sDescription)
{
if (is_null(self::$m_aCacheProfiles))
@@ -71,7 +71,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
{
self::$m_aCacheProfiles[$oProfile->Get('name')] = $oProfile->GetKey();
}
- }
+ }
$sCacheKey = $sName;
if (isset(self::$m_aCacheProfiles[$sCacheKey]))
@@ -82,10 +82,10 @@ class URP_Profiles extends UserRightsBaseClassGUI
$oNewObj->Set('name', $sName);
$oNewObj->Set('description', $sDescription);
$iId = $oNewObj->DBInsertNoReload();
- self::$m_aCacheProfiles[$sCacheKey] = $iId;
+ self::$m_aCacheProfiles[$sCacheKey] = $iId;
return $iId;
}
-
+
function GetGrantAsHtml($oUserRights, $sClass, $sAction)
{
$bGrant = $oUserRights->GetProfileActionGrant($this->GetKey(), $sClass, $sAction);
@@ -102,7 +102,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
return ''.Dict::S('UI:UserManagement:ActionAllowed:No').'';
}
}
-
+
function DoShowGrantSumary($oPage)
{
if ($this->GetRawName() == "Administrator")
@@ -114,7 +114,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
// Note: for sure, we assume that the instance is derived from UserRightsProfile
$oUserRights = UserRights::GetModuleInstance();
-
+
$aDisplayData = array();
foreach (MetaModel::GetClasses('bizmodel,grant_by_profile') as $sClass)
{
@@ -123,12 +123,12 @@ class URP_Profiles extends UserRightsBaseClassGUI
{
$bGrant = $oUserRights->GetClassStimulusGrant($this->GetKey(), $sClass, $sStimulusCode);
if ($bGrant === true)
- {
- $aStimuli[] = ''.htmlentities($oStimulus->GetLabel(), ENT_QUOTES, 'UTF-8').'';
+ {
+ $aStimuli[] = ''.utils::EscapeHtml($oStimulus->GetLabel()).'';
}
}
$sStimuli = implode(', ', $aStimuli);
-
+
$aDisplayData[] = array(
'class' => MetaModel::GetName($sClass),
'read' => $this->GetGrantAsHtml($oUserRights, $sClass, 'r'),
@@ -140,7 +140,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
'stimuli' => $sStimuli,
);
}
-
+
$aDisplayConfig = array();
$aDisplayConfig['class'] = array('label' => Dict::S('UI:UserManagement:Class'), 'description' => Dict::S('UI:UserManagement:Class+'));
$aDisplayConfig['read'] = array('label' => Dict::S('UI:UserManagement:Action:Read'), 'description' => Dict::S('UI:UserManagement:Action:Read+'));
@@ -198,7 +198,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
* @param $aReasons array To store the reasons why the attribute is read-only (info about the synchro replicas)
* @param $sTargetState string The target state in which to evalutate the flags, if empty the current state will be used
* @return integer Flags: the binary combination of the flags applicable to this attribute
- */
+ */
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
{
$iFlags = parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
@@ -404,7 +404,7 @@ class URP_UserOrg extends UserRightsBaseClassGUI
{
if (!UserRights::IsLoggedIn() || UserRights::IsAdministrator()) { return; }
- $oUser = UserRights::GetUserObject();
+ $oUser = UserRights::GetUserObject();
$oAddon = UserRights::GetModuleInstance();
$aOrgs = $oAddon->GetUserOrgs($oUser, '');
if (count($aOrgs) > 0)
@@ -435,20 +435,18 @@ class UserRightsProfile extends UserRightsAddOnAPI
// Installation: create the very first user
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
{
- CMDBObject::SetTrackInfo('Initialization');
+ CMDBObject::SetCurrentChangeFromParams('Initialization create administrator');
$iContactId = 0;
// Support drastic data model changes: no organization class (or not writable)!
- if (MetaModel::IsValidClass('Organization') && !MetaModel::IsAbstract('Organization'))
- {
+ if (MetaModel::IsValidClass('Organization') && !MetaModel::IsAbstract('Organization')) {
$oOrg = MetaModel::NewObject('Organization');
$oOrg->Set('name', 'My Company/Department');
$oOrg->Set('code', 'SOMECODE');
$iOrgId = $oOrg->DBInsertNoReload();
// Support drastic data model changes: no Person class (or not writable)!
- if (MetaModel::IsValidClass('Person') && !MetaModel::IsAbstract('Person'))
- {
+ if (MetaModel::IsValidClass('Person') && !MetaModel::IsAbstract('Person')) {
$oContact = MetaModel::NewObject('Person');
$oContact->Set('name', 'My last name');
$oContact->Set('first_name', 'My first name');
@@ -528,7 +526,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
$oSearch->AllowAllData();
$oCondition = new BinaryExpression(new FieldExpression('userid'), '=', new VariableExpression('userid'));
$oSearch->AddConditionExpression($oCondition);
-
+
$oUserOrgSet = new DBObjectSet($oSearch, array(), array('userid' => $iUser));
while ($oUserOrg = $oUserOrgSet->Fetch())
{
@@ -738,8 +736,10 @@ class UserRightsProfile extends UserRightsAddOnAPI
// load and cache permissions for the current user on the given class
//
$iUser = $oUser->GetKey();
- $aTest = @$this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode];
- if (is_array($aTest)) return $aTest;
+ if (isset($this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode])){
+ $aTest = $this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode];
+ if (is_array($aTest)) return $aTest;
+ }
$sAction = self::$m_aActionCodes[$iActionCode];
@@ -905,8 +905,8 @@ class UserRightsProfile extends UserRightsAddOnAPI
/**
* Find out which attribute is corresponding the the dimension 'owner org'
- * returns null if no such attribute has been found (no filtering should occur)
- */
+ * returns null if no such attribute has been found (no filtering should occur)
+ */
public static function GetOwnerOrganizationAttCode($sClass)
{
$sAttCode = null;
diff --git a/addons/userrights/userrightsprofile.db.class.inc.php b/addons/userrights/userrightsprofile.db.class.inc.php
index ac5b2277b3..10fc826d9d 100644
--- a/addons/userrights/userrightsprofile.db.class.inc.php
+++ b/addons/userrights/userrightsprofile.db.class.inc.php
@@ -278,8 +278,8 @@ class URP_Profiles extends UserRightsBaseClassGUI
{
$oGrant = $oUserRights->GetClassStimulusGrant($this->GetKey(), $sClass, $sStimulusCode);
if (is_object($oGrant) && ($oGrant->Get('permission') == 'yes'))
- {
- $aStimuli[] = ''.htmlentities($oStimulus->GetLabel(), ENT_QUOTES, 'UTF-8').'';
+ {
+ $aStimuli[] = ''.utils::EscapeHtml($oStimulus->GetLabel()).'';
}
}
$sStimuli = implode(', ', $aStimuli);
@@ -508,24 +508,18 @@ class UserRightsProfile extends UserRightsAddOnAPI
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
{
// Create a change to record the history of the User object
- /** @var \CMDBChange $oChange */
- $oChange = MetaModel::NewObject("CMDBChange");
- $oChange->Set("date", time());
- $oChange->Set("userinfo", "Initialization");
+ CMDBObject::SetCurrentChangeFromParams('Initialization : create first user admin profile');
$iContactId = 0;
// Support drastic data model changes: no organization class (or not writable)!
- if (MetaModel::IsValidClass('Organization') && !MetaModel::IsAbstract('Organization'))
- {
+ if (MetaModel::IsValidClass('Organization') && !MetaModel::IsAbstract('Organization')) {
$oOrg = MetaModel::NewObject('Organization');
$oOrg->Set('name', 'My Company/Department');
$oOrg->Set('code', 'SOMECODE');
- $oOrg::SetCurrentChange($oChange);
$iOrgId = $oOrg->DBInsertNoReload();
// Support drastic data model changes: no Person class (or not writable)!
- if (MetaModel::IsValidClass('Person') && !MetaModel::IsAbstract('Person'))
- {
+ if (MetaModel::IsValidClass('Person') && !MetaModel::IsAbstract('Person')) {
$oContact = MetaModel::NewObject('Person');
$oContact->Set('name', 'My last name');
$oContact->Set('first_name', 'My first name');
@@ -534,7 +528,6 @@ class UserRightsProfile extends UserRightsAddOnAPI
$oContact->Set('org_id', $iOrgId);
}
$oContact->Set('email', 'my.email@foo.org');
- $oContact::SetCurrentChange($oChange);
$iContactId = $oContact->DBInsertNoReload();
}
}
@@ -543,24 +536,22 @@ class UserRightsProfile extends UserRightsAddOnAPI
$oUser = new UserLocal();
$oUser->Set('login', $sAdminUser);
$oUser->Set('password', $sAdminPwd);
- if (MetaModel::IsValidAttCode('UserLocal', 'contactid') && ($iContactId != 0))
- {
+ if (MetaModel::IsValidAttCode('UserLocal', 'contactid') && ($iContactId != 0)) {
$oUser->Set('contactid', $iContactId);
}
$oUser->Set('language', $sLanguage); // Language was chosen during the installation
// Add this user to the very specific 'admin' profile
$oAdminProfile = MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", array('name' => ADMIN_PROFILE_NAME), true /*all data*/);
- if (is_object($oAdminProfile))
- {
+ if (is_object($oAdminProfile)) {
$oUserProfile = new URP_UserProfile();
$oUserProfile->Set('profileid', $oAdminProfile->GetKey());
$oUserProfile->Set('reason', 'By definition, the administrator must have the administrator profile');
$oSet = DBObjectSet::FromObject($oUserProfile);
$oUser->Set('profile_list', $oSet);
}
- $oUser::SetCurrentChange($oChange);
- $iUserId = $oUser->DBInsertNoReload();
+ $oUser->DBInsertNoReload();
+
return true;
}
diff --git a/addons/userrights/userrightsprojection.class.inc.php b/addons/userrights/userrightsprojection.class.inc.php
index 61fb07fe63..84f239c526 100644
--- a/addons/userrights/userrightsprojection.class.inc.php
+++ b/addons/userrights/userrightsprojection.class.inc.php
@@ -110,8 +110,8 @@ class URP_Profiles extends UserRightsBaseClass
{
$oGrant = $oUserRights->GetClassStimulusGrant($this->GetKey(), $sClass, $sStimulusCode);
if (is_object($oGrant) && ($oGrant->Get('permission') == 'yes'))
- {
- $aStimuli[] = ''.htmlentities($oStimulus->GetLabel(), ENT_QUOTES, 'UTF-8').'';
+ {
+ $aStimuli[] = ''.utils::EscapeHtml($oStimulus->GetLabel()).'';
}
}
$sStimuli = implode(', ', $aStimuli);
@@ -568,14 +568,11 @@ class UserRightsProjection extends UserRightsAddOnAPI
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
{
// Create a change to record the history of the User object
- $oChange = MetaModel::NewObject("CMDBChange");
- $oChange->Set("date", time());
- $oChange->Set("userinfo", "Initialization");
+ CMDBObject::SetCurrentChangeFromParams('Initialization : create first user admin');
$oOrg = new Organization();
$oOrg->Set('name', 'My Company/Department');
$oOrg->Set('code', 'SOMECODE');
- $oOrg::SetCurrentChange($oChange);
$iOrgId = $oOrg->DBInsertNoReload();
$oContact = new Person();
@@ -584,7 +581,6 @@ class UserRightsProjection extends UserRightsAddOnAPI
//$oContact->Set('status', 'available');
$oContact->Set('org_id', $iOrgId);
$oContact->Set('email', 'my.email@foo.org');
- $oContact::SetCurrentChange($oChange);
$iContactId = $oContact->DBInsertNoReload();
$oUser = new UserLocal();
@@ -592,7 +588,6 @@ class UserRightsProjection extends UserRightsAddOnAPI
$oUser->Set('password', $sAdminPwd);
$oUser->Set('contactid', $iContactId);
$oUser->Set('language', $sLanguage); // Language was chosen during the installation
- $oUser::SetCurrentChange($oChange);
$iUserId = $oUser->DBInsertNoReload();
// Add this user to the very specific 'admin' profile
@@ -600,7 +595,6 @@ class UserRightsProjection extends UserRightsAddOnAPI
$oUserProfile->Set('userid', $iUserId);
$oUserProfile->Set('profileid', ADMIN_PROFILE_ID);
$oUserProfile->Set('reason', 'By definition, the administrator must have the administrator profile');
- $oUserProfile::SetCurrentChange($oChange);
$oUserProfile->DBInsertNoReload();
return true;
}
diff --git a/application/ajaxwebpage.class.inc.php b/application/ajaxwebpage.class.inc.php
index d6303d067f..57e96cdf23 100644
--- a/application/ajaxwebpage.class.inc.php
+++ b/application/ajaxwebpage.class.inc.php
@@ -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);
+ }
}
diff --git a/application/applicationcontext.class.inc.php b/application/applicationcontext.class.inc.php
index 1361f92d30..903fa2cee1 100644
--- a/application/applicationcontext.class.inc.php
+++ b/application/applicationcontext.class.inc.php
@@ -224,7 +224,7 @@ class ApplicationContext
{
$sContext = "";
foreach ($this->aValues as $sName => $sValue) {
- $sContext .= "\n";
+ $sContext .= "\n";
}
return $sContext;
}
@@ -238,7 +238,7 @@ class ApplicationContext
{
$aContextInputBlocks = [];
foreach ($this->aValues as $sName => $sValue) {
- $aContextInputBlocks[] = InputUIBlockFactory::MakeForHidden("c[$sName]", htmlentities($sValue, ENT_QUOTES, 'UTF-8'));
+ $aContextInputBlocks[] = InputUIBlockFactory::MakeForHidden("c[$sName]", utils::EscapeHtml($sValue));
}
return $aContextInputBlocks;
}
diff --git a/application/applicationextension.inc.php b/application/applicationextension.inc.php
index 94254dc951..6d2f959452 100644
--- a/application/applicationextension.inc.php
+++ b/application/applicationextension.inc.php
@@ -1184,7 +1184,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
{
@@ -1402,11 +1402,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
{
@@ -1479,7 +1479,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
{
diff --git a/application/cmdbabstract.class.inc.php b/application/cmdbabstract.class.inc.php
index fb5a4987a2..b6cc4a95d1 100644
--- a/application/cmdbabstract.class.inc.php
+++ b/application/cmdbabstract.class.inc.php
@@ -341,13 +341,17 @@ JS
}
/**
- * Important: For compatibility reasons, this function still allows to manipulate the $oPage. In that case, markup will be put above the real header of the panel.
- * To insert something IN the panel, we now need to add UIBlocks in either the "subtitle" or "toolbar" sections of the array that will be returned.
+ * @param \WebPage $oPage Warning, since 3.0.0 this parameter was kept for compatibility reason. You shouldn't write directly on the page!
+ * When writing to the page, markup will be put above the real header of the panel.
+ * To insert something IN the panel, we now need to add UIBlocks in either the "subtitle" or "toolbar" sections of the array that will be returned.
+ * @param bool $bEditMode Deprecated parameter in iTop 3.0.0, use {@see GetDisplayMode()} and ENUM_DISPLAY_MODE_* constants instead
*
- * @param \WebPage $oPage
- * @param bool $bEditMode Note that this parameter is no longer used in this method. Use {@see static::$sDisplayMode} instead
- *
- * @return array UIBlocks to be inserted in the "subtitle" and the "toolbar" sections of the ObjectDetails block. eg. ['subtitle' => [, ], 'toolbar' => []]
+ * @return array{
+ * subtitle: \Combodo\iTop\Application\UI\Base\UIBlock[],
+ * toolbar: \Combodo\iTop\Application\UI\Base\UIBlock[]
+ * }
+ * blocks to be inserted in the "subtitle" and the "toolbar" sections of the ObjectDetails block.
+ * eg. ['subtitle' => [, ], 'toolbar' => []]
*
* @throws \ApplicationException
* @throws \ArchivedObjectException
@@ -356,7 +360,10 @@ JS
* @throws \MySQLException
* @throws \OQLException
*
- * @since 3.0.0 $bEditMode is deprecated and no longer used
+ * @since 3.0.0 $bEditMode is deprecated, see param documentation above
+ * @since 3.0.0 Changed signature: Method must return header content in an array (no more writing directly to the $oPage)
+ *
+ * @noinspection PhpUnusedParameterInspection
*/
public function DisplayBareHeader(WebPage $oPage, $bEditMode = false)
{
@@ -721,7 +728,7 @@ HTML
$oClassIcon = new MedallionIcon(MetaModel::GetClassIcon($sTargetClass, false));
$oClassIcon->SetDescription($oAttDef->GetDescription())->AddCSSClass('ibo-block-list--medallion');
$oPage->AddUiBlock($oClassIcon);
-
+
$sDisplayValue = ''; // not used
$sHTMLValue = "".self::GetFormElementForField($oPage, $sClass, $sAttCode,
$oAttDef, $oLinkSet, $sDisplayValue, $sInputId, '', $iFlags, $aArgs).'';
@@ -980,10 +987,8 @@ HTML
$this->GetSynchroReplicaFlags($sAttCode, $aReasons);
$sTip = '';
foreach ($aReasons as $aRow) {
- $sDescription = htmlentities($aRow['description'], ENT_QUOTES,
- 'UTF-8');
- $sDescription = str_replace(array("\r\n", "\n"), " ",
- $sDescription);
+ $sDescription = utils::EscapeHtml($aRow['description']);
+ $sDescription = str_replace(array("\r\n", "\n"), " ", $sDescription);
$sTip .= "
";
$sTip .= "
Synchronized with {$aRow['name']}
";
$sTip .= "
$sDescription
";
@@ -1396,7 +1401,7 @@ HTML
} else {
if ($oAttDef instanceof AttributeCaseLog) {
$rawValue = $oObj->Get($sAttCodeEx);
- $outputValue = str_replace("\n", " ", htmlentities($rawValue->__toString(), ENT_QUOTES, 'UTF-8'));
+ $outputValue = str_replace("\n", " ", utils::EscapeHtml($rawValue->__toString()));
// Trick for Excel: treat the content as text even if it begins with an equal sign
$aRow[$oAttDef->GetCode()] = $outputValue;
} else {
@@ -1410,9 +1415,9 @@ HTML
}
}
if ($bLocalize) {
- $outputValue = htmlentities($oFinalAttDef->GetEditValue($rawValue), ENT_QUOTES, 'UTF-8');
+ $outputValue = utils::EscapeHtml($oFinalAttDef->GetEditValue($rawValue));
} else {
- $outputValue = htmlentities($rawValue, ENT_QUOTES, 'UTF-8');
+ $outputValue = utils::EscapeHtml($rawValue);
}
$aRow[$oAttDef->GetCode()] = $outputValue;
}
@@ -1448,7 +1453,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())
{
@@ -1888,7 +1893,7 @@ HTML
{
$rawValue = $oObj->Get($sAttCodeEx);
$outputValue = str_replace("\n", " ",
- htmlentities($rawValue->__toString(), ENT_QUOTES, 'UTF-8'));
+ utils::EscapeHtml($rawValue->__toString()));
// Trick for Excel: treat the content as text even if it begins with an equal sign
$aRow[] = '
{$sValidationSpan}{$sReloadSpan}$sHidden";
+ $sHTMLValue .= "";
+ $sHTMLValue .= "$sPreviousLog{$sValidationSpan}{$sReloadSpan}$sHidden";
// Note: This should be refactored for all types of attribute (see at the end of this function) but as we are doing this for a maintenance release, we are scheduling it for the next main release in to order to avoid regressions as much as possible.
$sNullValue = $oAttDef->GetNullValue();
@@ -2563,16 +2564,16 @@ JS
case 'Set':
case 'TagSet':
- $sInputType = self::ENUM_INPUT_TYPE_TAGSET;
- $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/selectize.min.js');
- $oPage->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/selectize.default.css');
- $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.itop-set-widget.js');
+ $sInputType = self::ENUM_INPUT_TYPE_TAGSET;
+ $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/selectize.min.js');
+ $oPage->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/selectize.default.css');
+ $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.itop-set-widget.js');
- $oPage->add_dict_entry('Core:AttributeSet:placeholder');
+ $oPage->add_dict_entry('Core:AttributeSet:placeholder');
- /** @var \ormSet $value */
+ /** @var \ormSet $value */
$sJson = $oAttDef->GetJsonForWidget($value, $aArgs);
- $sEscapedJson = htmlentities($sJson, ENT_QUOTES, 'UTF-8');
+ $sEscapedJson = utils::EscapeHtml($sJson);
$sSetInputName = "attr_{$sFormPrefix}{$sAttCode}";
// handle form validation
@@ -3685,8 +3686,7 @@ HTML;
break;
default:
- $oPage->add("