Compare commits

..

1 Commits

Author SHA1 Message Date
bruno-ds
80cb3a11db [WIP][POC] the PhpUnit tests can now build and use various environments
drawbacks: the application startup was emulated since it is not compatible with a custom env. when launched with the CLI (it rely on the session in an incompatible way)
2021-04-09 17:29:18 +02:00
3218 changed files with 58974 additions and 292640 deletions

18
.gitignore vendored
View File

@@ -1,15 +1,4 @@
################################### Temporary ignore rules during 2.8 UI/UX dev - START
/css/backoffice/main.css
# Sass converter
/**/.sass-cache/
################################### Temporary ignore rules during 2.8 UI/UX dev - END
# no slash at the end to handle also symlinks
/toolkit
/env-*
@@ -17,6 +6,12 @@
# maintenance mode (N°2240)
/.maintenance
# listing prevention in conf directory
/conf/**
!/conf/.htaccess
!/conf/index.php
!/conf/web.config
# composer reserver directory, from sources, populate/update using "composer install"
vendor/*
test/vendor/*
@@ -24,7 +19,6 @@ test/vendor/*
# all conf but listing prevention
/conf/**
!/conf/.htaccess
!/conf/index.php
!/conf/web.config
# all datas but listing prevention

View File

@@ -1,7 +1,7 @@
<?php
/**
* Copyright (C) 2010-2021 Combodo SARL
* Copyright (C) 2010-2020 Combodo SARL
*
* This file is part of iTop.
*

View File

@@ -1,6 +1,6 @@
<?php
/**
* Copyright (C) 2010-2021 Combodo SARL
* Copyright (C) 2010-2020 Combodo SARL
*
* This file is part of iTop.
*

View File

@@ -1,6 +1,6 @@
<?php
/**
* Copyright (C) 2010-2021 Combodo SARL
* Copyright (C) 2010-2020 Combodo SARL
*
* This file is part of iTop.
*

View File

@@ -1,26 +1,7 @@
<?php
/**
* script used to sort license file (useful for autogeneration)
*
* Requirements :
* * bash (on Windows, use Git Bash)
* * composer (if you use the phar version, mind to create a `Composer` alias !)
* * JQ command
* to install on Windows :
* `curl -L -o /usr/bin/jq.exe https://github.com/stedolan/jq/releases/latest/download/jq-win64.exe`
* this is a Windows port : https://stedolan.github.io/jq/
*
* Known bug on Windows :
* Licenses added from Composer contains a path in the product node (N°3870)
* `<product scope="lib">C:\Dev\wamp64\www\itop-dev\.make\license/../..//lib/symfony/console</product>`
*
* Licenses sources :
* * `composer licenses --format json` (see https://getcomposer.org/doc/03-cli.md#licenses)
* * keep every existing nodes with `/licenses/license[11]/product/@scope` not in ['lib', 'datamodels']
* ⚠ If licenses were added manually, they might be removed by this tool ! Be very careful to check for the result before pushing !
*
* To launch, check requirements and run `php updateLicenses.php`
* The target license file path is in `$xmlFilePath`
* script used to sort license file (usefull for autogeneration)
* Example: php
*/
$iTopFolder = __DIR__ . "/../../" ;

View File

@@ -42,7 +42,7 @@ If you want to use another license, you may [create an extension][wiki new ext].
When we first start with Git, we were using the [GitFlow](https://nvie.com/posts/a-successful-git-branching-model/) branch model. As
there was some confusions about branches to use for current developed release and previous maintained release, and also because we were
using just a very few of the GitFlow commands, we decided to add just a little modification to this branch model : since april 2020
we don't have a `master` branch anymore.
we don't have anymore a `master` branch.
Here are the branches we use and their meaning :
@@ -52,23 +52,23 @@ 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 2.8.0 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 2.8.0-beta is shipped that will become:
- `develop`: future 3.1.0 version
- `release/3.0.0`: 3.0.0-beta
- `develop`: future 2.9.0 version
- `release/2.8`: 2.8.0-beta
- `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 2.8.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 2.9.0 version
- `support/2.8`: 2.8.x maintenance version (will host developments for 2.8.1)
- `support/2.7`: 2.7.x maintenance version
- `support/2.6`: 2.6.x maintenance version
- `support/2.5`: 2.5.x maintenance version

150
README.md
View File

@@ -21,35 +21,21 @@ iTop also offers mass import tools and web services to integrate with your IT
- [Data synchronization][18] (for data federation)
## Latest release
- [Changes since the previous version][62]
- [New features][63]
- [Installation notes][64]
- [Download][65]
[62]: https://www.itophub.io/wiki/page?id=latest:release:change_log
[63]: https://www.itophub.io/wiki/page?id=latest:release:start
[64]: https://www.itophub.io/wiki/page?id=latest:install:start
[65]: https://sourceforge.net/projects/itop/files/latest/download
## Resources
- [iTop Forums][1]: community support
- [iTop Tickets][2]: for feature requests and bug reports
- [Releases download][3]
- [Software requirements][4]
- [Documentation][5] covering both iTop and its official extensions
- [iTop Hub][6] : discover and install extensions !
- [Documentation][4] covering both iTop and its official extensions
- [iTop Hub][5] : discover and install extensions !
[1]: https://sourceforge.net/p/itop/discussion/
[2]: https://sourceforge.net/p/itop/tickets/
[3]: https://sourceforge.net/projects/itop/files/itop/
[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/
[4]: https://www.itophub.io/wiki
[5]: https://store.itophub.io/en_US/
[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
@@ -63,6 +49,47 @@ iTop also offers mass import tools and web services to integrate with your IT
## Last releases
### Versions 2.7.*
- 2.7.1 published on April 8, 2020
- [Changes since the previous version][62]
- [New features][63]
- [Migration notes][64]
- [Download iTop 2.7.0-2][65]
[62]: https://www.itophub.io/wiki/page?id=2_7_0:release:change_log
[63]: https://www.itophub.io/wiki/page?id=2_7_0:release:2_7_whats_new
[64]: https://www.itophub.io/wiki/page?id=2_7_0:install:260_to_270_migration_notes
[65]: https://sourceforge.net/projects/itop/files/itop/2.7.0-2
### Versions 2.6.*
- 2.6.0 published on January 9, 2019
- [Changes since the previous version][58]
- [New features][59]
- [Migration notes][60]
- [Download iTop 2.6.3][61]
[58]: https://www.itophub.io/wiki/page?id=2_6_0:release:change_log
[59]: https://www.itophub.io/wiki/page?id=2_6_0:release:2_6_whats_new
[60]: https://www.itophub.io/wiki/page?id=2_6_0:install:250_to_260_migration_notes
[61]: https://sourceforge.net/projects/itop/files/itop/2.6.3
### Versions 2.5.*
- 2.5.0 published on July 11, 2018
- [Changes since the previous version][54]
- [New features][55]
- [Migration notes][56]
- [Download iTop 2.5.1][57]
[54]: https://www.itophub.io/wiki/page?id=2_5_0:release:change_log
[55]: https://www.itophub.io/wiki/page?id=2_5_0:release:2_5_whats_new
[56]: https://www.itophub.io/wiki/page?id=2_5_0:install:240_to_250_migration_notes
[57]: https://sourceforge.net/projects/itop/files/itop/2.5.1
## About Us
iTop development is sponsored, led and supported by [Combodo][0].
@@ -72,55 +99,50 @@ iTop development is sponsored, led and supported by [Combodo][0].
## Contributors
We would like to give a special thank you 🤗 to the people from the community who contributed to this project, including:
We would like to give a special thank you to the people from the community who contributed to this project, including:
### Names
- Alves, David
- Beck, Pedro
- Bilger, Jean-François
- Bostoen, Jeffrey (a.k.a @jbostoen)
- Cardoso, Anderson
- Cassaro, Bruno
- Casteleyn, Thomas (a.k.a @Hipska)
- Castro, Randall Badilla
- Colantoni, Maria Laura
- Couronné, Guy
- Dvořák, Lukáš
- Goethals, Stefan
- Gumble, David
- Kaltefleiter, Lars (a.k.a @larhip)
- Khamit, Shamil
- Kincel, Martin
- Konečný, Kamil
- Kunin, Vladimir
- Lassiter, Dennis
- Lazcano, Federico
- Lucas, Jonathan
- Malik, Remie
- Mindêllo de Andrade, Lucas (a.k.a @rokam)
- Rosenke, Stephan
- Seki, Shoji
- Shilov, Vladimir
- Tulio, Marco
- Turrubiates, Miguel
- Alves, David
- Beck, Pedro
- Bilger, Jean-François
- Bostoen, Jeffrey
- Cardoso, Anderson
- Cassaro, Bruno
- Casteleyn, Thomas
- Castro, Randall Badilla
- Colantoni, Maria Laura
- Couronné, Guy
- Dvořák, Lukáš
- Goethals, Stefan
- Gumble, David
- Hippler, Lars
- Khamit, Shamil
- Kincel, Martin
- Konečný, Kamil
- Kunin, Vladimir
- Lassiter, Dennis
- Lazcano, Federico
- Lucas, Jonathan
- Malik, Remie
- Rosenke, Stephan
- Seki, Shoji
- Shilov, Vladimir
- Tulio, Marco
- Turrubiates, Miguel
### Aliases
- chifu1234
- cprobst
- DudekArtur
- Karkoff1212
- Laura
- Purple Grape
- Schlobinux
- theBigOne
- ulmerspatz
- chifu1234
- cprobst
- Karkoff1212
- larhip
- Laura
- Purple Grape
- Schlobinux
- theBigOne
- ulmerspatz
### Companies
- [Hardis](https://www.hardis-group.com/)
- [ITOMIG](https://www.itomig.de/)
- [Pimkie](https://www.pimkie.com/)
- [Super-Visions](https://www.super-visions.com/)
- Hardis
- ITOMIG
- Pimkie

View File

@@ -9,7 +9,7 @@ responsible disclosure and will make every effort to acknowledge your contributi
### iTop vulnerabilities
Please send a procedure to reproduce iTop vulnerabilities to [itop-security@combodo.com](mailto:itop-security@combodo.com).
You can send us a standard "given / when / then" report, including iTop version, impacts, and maybe installed modules or data if they are
You can send us a standard "given / then / when" report, including iTop version, impacts, and maybe installed modules or data if they are
needed to reproduce.
### Dependencies vulnerabilities

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -19,7 +19,7 @@
/**
* UserRightsMatrix (User management Module)
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -20,7 +20,7 @@
* UserRightsNull
* User management Module - say Yeah! to everything
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -1,7 +1,20 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
define('ADMIN_PROFILE_NAME', 'Administrator');
@@ -42,6 +55,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
"db_table" => "priv_urp_profiles",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -156,9 +170,11 @@ class URP_Profiles extends UserRightsBaseClassGUI
function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
{
parent::DisplayBareRelations($oPage, $bEditMode);
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
$this->DoShowGrantSumary($oPage);
if (!$bEditMode)
{
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
$this->DoShowGrantSumary($oPage);
}
}
public static function GetReadOnlyAttributes()
@@ -227,6 +243,7 @@ class URP_UserProfile extends UserRightsBaseClassGUI
"db_table" => "priv_urp_userprofile",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -253,54 +270,17 @@ class URP_UserProfile extends UserRightsBaseClassGUI
public function CheckToDelete(&$oDeletionPlan)
{
if (MetaModel::GetConfig()->Get('demo_mode')) {
if (MetaModel::GetConfig()->Get('demo_mode'))
{
// Users deletion is NOT allowed in demo mode
$oDeletionPlan->AddToDelete($this, null);
$oDeletionPlan->SetDeletionIssues($this, array('deletion not allowed in demo mode.'), true);
$oDeletionPlan->ComputeResults();
return false;
}
try {
$this->CheckIfProfileIsAllowed(UR_ACTION_DELETE);
}
catch (SecurityException $e) {
// Users deletion is NOT allowed
$oDeletionPlan->AddToDelete($this, null);
$oDeletionPlan->SetDeletionIssues($this, [$e->getMessage()], true);
$oDeletionPlan->ComputeResults();
return false;
}
return parent::CheckToDelete($oDeletionPlan);
}
public function DoCheckToDelete(&$oDeletionPlan)
{
if (MetaModel::GetConfig()->Get('demo_mode')) {
// Users deletion is NOT allowed in demo mode
$oDeletionPlan->AddToDelete($this, null);
$oDeletionPlan->SetDeletionIssues($this, array('deletion not allowed in demo mode.'), true);
$oDeletionPlan->ComputeResults();
return false;
}
try {
$this->CheckIfProfileIsAllowed(UR_ACTION_DELETE);
}
catch (SecurityException $e) {
// Users deletion is NOT allowed
$oDeletionPlan->AddToDelete($this, null);
$oDeletionPlan->SetDeletionIssues($this, [$e->getMessage()], true);
$oDeletionPlan->ComputeResults();
return false;
}
return parent::DoCheckToDelete($oDeletionPlan);
}
protected function OnInsert()
{
$this->CheckIfProfileIsAllowed(UR_ACTION_CREATE);
@@ -313,6 +293,7 @@ class URP_UserProfile extends UserRightsBaseClassGUI
protected function OnDelete()
{
$this->CheckIfProfileIsAllowed(UR_ACTION_DELETE);
}
/**
@@ -368,6 +349,7 @@ class URP_UserOrg extends UserRightsBaseClassGUI
"db_table" => "priv_urp_userorg",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();

View File

@@ -1,6 +1,6 @@
<?php
/**
* Copyright (C) 2013-2021 Combodo SARL
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
@@ -77,6 +77,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
"db_table" => "priv_urp_profiles",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -311,9 +312,11 @@ class URP_Profiles extends UserRightsBaseClassGUI
function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
{
parent::DisplayBareRelations($oPage, $bEditMode);
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
$this->DoShowGrantSumary($oPage);
if (!$bEditMode)
{
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
$this->DoShowGrantSumary($oPage);
}
}
}
@@ -333,6 +336,7 @@ class URP_UserProfile extends UserRightsBaseClassGUI
"db_table" => "priv_urp_userprofile",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -372,6 +376,7 @@ class URP_UserOrg extends UserRightsBaseClassGUI
"db_table" => "priv_urp_userorg",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -412,6 +417,7 @@ class URP_ActionGrant extends UserRightsBaseClass
"db_table" => "priv_urp_grant_actions",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -448,6 +454,7 @@ class URP_StimulusGrant extends UserRightsBaseClass
"db_table" => "priv_urp_grant_stimulus",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -484,6 +491,7 @@ class URP_AttributeGrant extends UserRightsBaseClass
"db_table" => "priv_urp_grant_attributes",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();

View File

@@ -1,6 +1,6 @@
<?php
/**
* Copyright (C) 2013-2021 Combodo SARL
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
@@ -58,6 +58,7 @@ class URP_Profiles extends UserRightsBaseClass
"db_table" => "priv_urp_profiles",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -143,9 +144,11 @@ class URP_Profiles extends UserRightsBaseClass
function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
{
parent::DisplayBareRelations($oPage, $bEditMode);
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
$this->DoShowGrantSumary($oPage);
if (!$bEditMode)
{
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
$this->DoShowGrantSumary($oPage);
}
}
}
@@ -164,6 +167,7 @@ class URP_Dimensions extends UserRightsBaseClass
"db_table" => "priv_urp_dimensions",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -276,6 +280,7 @@ class URP_UserProfile extends UserRightsBaseClass
"db_table" => "priv_urp_userprofile",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -316,6 +321,7 @@ class URP_ProfileProjection extends UserRightsBaseClass
"db_table" => "priv_urp_profileprojection",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -396,6 +402,7 @@ class URP_ClassProjection extends UserRightsBaseClass
"db_table" => "priv_urp_classprojection",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -467,6 +474,7 @@ class URP_ActionGrant extends UserRightsBaseClass
"db_table" => "priv_urp_grant_actions",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -503,6 +511,7 @@ class URP_StimulusGrant extends UserRightsBaseClass
"db_table" => "priv_urp_grant_stimulus",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -539,6 +548,7 @@ class URP_AttributeGrant extends UserRightsBaseClass
"db_table" => "priv_urp_grant_attributes",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();

View File

@@ -30,11 +30,8 @@ function mb_str_replace($search, $replace, $subject, &$count = 0) {
$replacements = array_pad($replacements, count($searches), '');
foreach ($searches as $key => $search) {
$parts = mb_split(preg_quote($search), $subject);
if (is_array($parts))
{
$count += count($parts) - 1;
$subject = implode($replacements[$key], $parts);
}
$count += count($parts) - 1;
$subject = implode($replacements[$key], $parts);
}
} else {
// Call mb_str_replace for each subject in array, recursively

View File

@@ -1,16 +1,415 @@
<?php
/**
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/AjaxPage.php
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2021 Combodo SARL
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
/**
* Class ajax_page
* @deprecated will be removed in 3.1.0 - moved to AjaxPage
*/
class ajax_page extends AjaxPage
require_once(APPROOT."/application/webpage.class.inc.php");
class ajax_page extends WebPage implements iTabbedPage
{
/**
* Jquery style ready script
* @var array
*/
protected $m_sReadyScript;
protected $m_oTabs;
private $m_sMenu; // If set, then the menu will be updated
/**
* constructor for the web page
*
* @param string $s_title Not used
*/
function __construct($s_title) {
$sPrintable = utils::ReadParam('printable', '0');
$bPrintable = ($sPrintable == '1');
parent::__construct($s_title, $bPrintable);
$this->m_sReadyScript = "";
//$this->add_header("Content-type: text/html; charset=utf-8");
$this->no_cache();
$this->add_xframe_options();
$this->m_oTabs = new TabManager();
$this->sContentType = 'text/html';
$this->sContentDisposition = 'inline';
$this->m_sMenu = "";
utils::InitArchiveMode();
}
/**
* @inheritDoc
* @throws \Exception
*/
public function AddTabContainer($sTabContainer, $sPrefix = '')
{
$this->add($this->m_oTabs->AddTabContainer($sTabContainer, $sPrefix));
}
/**
* @inheritDoc
* @throws \Exception
*/
public function AddToTab($sTabContainer, $sTabCode, $sHtml)
{
$this->add($this->m_oTabs->AddToTab($sTabContainer, $sTabCode, $sHtml));
}
/**
* @inheritDoc
*/
public function SetCurrentTabContainer($sTabContainer = '')
{
return $this->m_oTabs->SetCurrentTabContainer($sTabContainer);
}
/**
* @inheritDoc
*/
public function SetCurrentTab($sTabCode = '', $sTabTitle = null)
{
return $this->m_oTabs->SetCurrentTab($sTabCode, $sTabTitle);
}
/**
* @inheritDoc
* @throws \Exception
*/
public function AddAjaxTab($sTabCode, $sUrl, $bCache = true, $sTabTitle = null)
{
$this->add($this->m_oTabs->AddAjaxTab($sTabCode, $sUrl, $bCache, $sTabTitle));
}
/**
* @inheritDoc
*/
public function GetCurrentTab()
{
return $this->m_oTabs->GetCurrentTab();
}
/**
* @inheritDoc
*/
public function RemoveTab($sTabCode, $sTabContainer = null)
{
$this->m_oTabs->RemoveTab($sTabCode, $sTabContainer);
}
/**
* @inheritDoc
*/
public function FindTab($sPattern, $sTabContainer = null)
{
return $this->m_oTabs->FindTab($sPattern, $sTabContainer);
}
/**
* Make the given tab the active one, as if it were clicked
* DOES NOT WORK: apparently in the *old* version of jquery
* that we are using this is not supported... TO DO upgrade
* the whole jquery bundle...
*/
public function SelectTab($sTabContainer, $sTabCode)
{
$this->add_ready_script($this->m_oTabs->SelectTab($sTabContainer, $sTabCode));
}
/**
* @param string $sHtml
*/
public function AddToMenu($sHtml)
{
$this->m_sMenu .= $sHtml;
}
/**
* @inheritDoc
*/
public function output()
{
if (!empty($this->sContentType))
{
$this->add_header('Content-type: '.$this->sContentType);
}
if (!empty($this->sContentDisposition))
{
$this->add_header('Content-Disposition: '.$this->sContentDisposition.'; filename="'.$this->sContentFileName.'"');
}
foreach($this->a_headers as $s_header)
{
header($s_header);
}
if ($this->m_oTabs->TabsContainerCount() > 0)
{
$this->add_ready_script(
<<<EOF
// The "tab widgets" to handle.
var tabs = $('div[id^=tabbedContent]');
// Ugly patch for a change in the behavior of jQuery UI:
// Before jQuery UI 1.9, tabs were always considered as "local" (opposed to Ajax)
// when their href was beginning by #. Starting with 1.9, a <base> tag in the page
// is taken into account and causes "local" tabs to be considered as Ajax
// unless their URL is equal to the URL of the page...
if ($('base').length > 0)
{
$('div[id^=tabbedContent] > ul > li > a').each(function() {
var sHash = location.hash;
var sCleanLocation = location.href.toString().replace(sHash, '').replace(/#$/, '');
$(this).attr("href", sCleanLocation+$(this).attr("href"));
});
}
if ($.bbq)
{
// This selector will be reused when selecting actual tab widget A elements.
var tab_a_selector = 'ul.ui-tabs-nav a';
// Enable tabs on all tab widgets. The `event` property must be overridden so
// that the tabs aren't changed on click, and any custom event name can be
// specified. Note that if you define a callback for the 'select' event, it
// will be executed for the selected tab whenever the hash changes.
tabs.tabs({ event: 'change' });
// Define our own click handler for the tabs, overriding the default.
tabs.find( tab_a_selector ).click(function()
{
var state = {};
// Get the id of this tab widget.
var id = $(this).closest( 'div[id^=tabbedContent]' ).attr( 'id' );
// Get the index of this tab.
var idx = $(this).parent().prevAll().length;
// Set the state!
state[ id ] = idx;
$.bbq.pushState( state );
});
}
else
{
tabs.tabs();
}
EOF
);
}
// Render the tabs in the page (if any)
$this->s_content = $this->m_oTabs->RenderIntoContent($this->s_content, $this);
// Additional UI widgets to be activated inside the ajax fragment
// Important: Testing the content type is not enough because some ajax handlers have not correctly positionned the flag (e.g json response corrupted by the script)
if (($this->sContentType == 'text/html') && (preg_match('/class="date-pick"/', $this->s_content) || preg_match('/class="datetime-pick"/', $this->s_content)) )
{
$this->add_ready_script(
<<<EOF
PrepareWidgets();
EOF
);
}
$this->outputCollapsibleSectionInit();
$oKPI = new ExecutionKPI();
$s_captured_output = $this->ob_get_clean_safe();
if (($this->sContentType == 'text/html') && ($this->sContentDisposition == 'inline'))
{
// inline content != attachment && html => filter all scripts for malicious XSS scripts
echo self::FilterXSS($this->s_content);
}
else
{
echo $this->s_content;
}
if (!empty($this->m_sMenu))
{
$uid = time();
echo "<div id=\"accordion_temp_$uid\">\n";
echo "<div id=\"accordion\">\n";
echo "<!-- Beginning of the accordion menu -->\n";
echo self::FilterXSS($this->m_sMenu);
echo "<!-- End of the accordion menu-->\n";
echo "</div>\n";
echo "</div>\n";
echo "<script type=\"text/javascript\">\n";
echo "$('#inner_menu').html($('#accordion_temp_$uid').html());\n";
echo "$('#accordion_temp_$uid').remove();\n";
echo "\n</script>\n";
}
//echo $this->s_deferred_content;
if (count($this->a_scripts) > 0)
{
echo "<script type=\"text/javascript\">\n";
echo implode("\n", $this->a_scripts);
echo "\n</script>\n";
}
if (count($this->a_linked_scripts) > 0)
{
echo "<script type=\"text/javascript\">\n";
foreach($this->a_linked_scripts as $sScriptUrl)
{
echo '$.getScript('.json_encode($sScriptUrl).");\n";
}
echo "\n</script>\n";
}
if (!empty($this->s_deferred_content))
{
echo "<script type=\"text/javascript\">\n";
echo "\$('body').append('".addslashes(str_replace("\n", '', $this->s_deferred_content))."');\n";
echo "\n</script>\n";
}
if (!empty($this->m_sReadyScript))
{
echo "<script type=\"text/javascript\">\n";
echo $this->m_sReadyScript; // Ready Scripts are output as simple scripts
echo "\n</script>\n";
}
if(count($this->a_linked_stylesheets) > 0)
{
echo "<script type=\"text/javascript\">";
foreach($this->a_linked_stylesheets as $aStylesheet)
{
$sStylesheetUrl = $aStylesheet['link'];
echo "if (!$('link[href=\"{$sStylesheetUrl}\"]').length) $('<link href=\"{$sStylesheetUrl}\" rel=\"stylesheet\">').appendTo('head');\n";
}
echo "\n</script>\n";
}
if (trim($s_captured_output) != "")
{
echo self::FilterXSS($s_captured_output);
}
$oKPI->ComputeAndReport('Echoing');
if (class_exists('DBSearch'))
{
DBSearch::RecordQueryTrace();
}
if (class_exists('ExecutionKPI'))
{
ExecutionKPI::ReportStats();
}
}
/**
* Adds a paragraph with a smaller font into the page
* NOT implemented (i.e does nothing)
* @param string $sText Content of the (small) paragraph
* @return void
*/
public function small_p($sText)
{
}
/**
* @inheritDoc
* @throws \Exception
*/
public function add($sHtml)
{
if (($this->m_oTabs->GetCurrentTabContainer() != '') && ($this->m_oTabs->GetCurrentTab() != ''))
{
$this->m_oTabs->AddToTab($this->m_oTabs->GetCurrentTabContainer(), $this->m_oTabs->GetCurrentTab(), $sHtml);
}
else
{
parent::add($sHtml);
}
}
/**
* @inheritDoc
*/
public function start_capture()
{
$sCurrentTabContainer = $this->m_oTabs->GetCurrentTabContainer();
$sCurrentTab = $this->m_oTabs->GetCurrentTab();
if (!empty($sCurrentTabContainer) && !empty($sCurrentTab))
{
$iOffset = $this->m_oTabs->GetCurrentTabLength();
return array('tc' => $sCurrentTabContainer, 'tab' => $sCurrentTab, 'offset' => $iOffset);
}
else
{
return parent::start_capture();
}
}
/**
* @inheritDoc
*/
public function end_capture($offset)
{
if (is_array($offset))
{
if ($this->m_oTabs->TabExists($offset['tc'], $offset['tab']))
{
$sCaptured = $this->m_oTabs->TruncateTab($offset['tc'], $offset['tab'], $offset['offset']);
}
else
{
$sCaptured = '';
}
}
else
{
$sCaptured = parent::end_capture($offset);
}
return $sCaptured;
}
/**
* @inheritDoc
*/
public function add_at_the_end($s_html, $sId = '')
{
if ($sId != '')
{
$this->add_script("$('#{$sId}').remove();"); // Remove any previous instance of the same Id
}
$this->s_deferred_content .= $s_html;
}
/**
* @inheritDoc
*/
public function add_ready_script($sScript)
{
$this->m_sReadyScript .= $sScript."\n";
}
/**
* @inheritDoc
*/
public function GetUniqueId()
{
assert(false);
return 0;
}
/**
* @inheritDoc
*/
public static function FilterXSS($sHTML)
{
return str_ireplace(array('<script', '</script>'), array('<!-- <removed-script', '</removed-script> -->'), $sHTML);
}
}

View File

@@ -1,11 +1,27 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Includes all the classes to have the application up and running
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/application/applicationcontext.class.inc.php');
@@ -15,4 +31,10 @@ require_once(APPROOT.'/application/audit.category.class.inc.php');
require_once(APPROOT.'/application/audit.rule.class.inc.php');
require_once(APPROOT.'/application/query.class.inc.php');
require_once(APPROOT.'/setup/moduleinstallation.class.inc.php');
//require_once(APPROOT.'/application/menunode.class.inc.php');
require_once(APPROOT.'/application/utils.inc.php');
class ApplicationException extends CoreException
{
}
?>

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2018 Combodo SARL
//
// This file is part of iTop.
//
@@ -20,27 +20,23 @@
/**
* Class ApplicationContext
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2018 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
use Combodo\iTop\Application\UI\Base\UIBlock;
require_once(APPROOT."/application/utils.inc.php");
/**
* Interface for directing end-users to the relevant application
*/
*/
interface iDBObjectURLMaker
{
/**
* @param string $sClass
* @param string $iId
*
* @return string
*/
/**
* @param string $sClass
* @param string $iId
*
* @return string
*/
public static function MakeObjectURL($sClass, $iId);
}
@@ -204,46 +200,23 @@ class ApplicationContext
}
return implode("&", $aParams);
}
/**
* @since 3.0.0 N°2534 - dashboard: bug with autorefresh that deactivates filtering on organisation
* Returns the params as c[menu]:..., c[org_id]:....
* @return string The params
*/
public function GetForPostParams()
{
return json_encode($this->aValues);
}
/**
* Returns the context as sequence of input tags to be inserted inside a <form> tag
*
* @return string The context as a sequence of <input type="hidden" /> tags
*/
public function GetForForm()
{
$sContext = "";
foreach ($this->aValues as $sName => $sValue) {
foreach($this->aValues as $sName => $sValue)
{
$sContext .= "<input type=\"hidden\" name=\"c[$sName]\" value=\"".htmlentities($sValue, ENT_QUOTES, 'UTF-8')."\" />\n";
}
return $sContext;
}
/**
* Returns the context as sequence of input tags to be inserted inside a <form> tag
*
*/
public function GetForFormBlock(): UIBlock
{
$oContext = new UIContentBlock();
foreach ($this->aValues as $sName => $sValue) {
$oContext->AddSubBlock(InputUIBlockFactory::MakeForHidden('c[$sName]', utils::HtmlEntities($sValue)));
}
return $oContext;
}
/**
* Returns the context as a hash array 'parameter_name' => value
*
* @return array The context information
*/
public function GetAsHash()

View File

@@ -1,7 +1,7 @@
<?php
/**
* Copyright (C) 2013-2021 Combodo SARL
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
@@ -18,7 +18,6 @@
* You should have received a copy of the GNU Affero General Public License
*/
use Combodo\iTop\Application\UI\Base\iUIBlock;
use Symfony\Component\DependencyInjection\Container;
require_once(APPROOT.'application/newsroomprovider.class.inc.php');
@@ -30,7 +29,7 @@ require_once(APPROOT.'application/newsroomprovider.class.inc.php');
* You may implement such interfaces in a module file (e.g. main.mymodule.php)
*
* @api
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
* @package Extensibility
* @since 2.7.0
@@ -431,7 +430,7 @@ interface iApplicationUIExtension
*
* @param DBObjectSet $oSet A set of persistent objects (DBObject)
*
* @return array
* @return string[string]
*/
public function EnumAllowedActions(DBObjectSet $oSet);
}
@@ -870,7 +869,7 @@ abstract class ApplicationPopupMenuItem
class URLPopupMenuItem extends ApplicationPopupMenuItem
{
/** @ignore */
protected $sUrl;
protected $sURL;
/** @ignore */
protected $sTarget;
@@ -879,32 +878,20 @@ class URLPopupMenuItem extends ApplicationPopupMenuItem
*
* @param string $sUID The unique identifier of this menu in iTop... make sure you pass something unique enough
* @param string $sLabel The display label of the menu (must be localized)
* @param string $sUrl If the menu is an hyperlink, provide the absolute hyperlink here
* @param string $sURL If the menu is an hyperlink, provide the absolute hyperlink here
* @param string $sTarget In case the menu is an hyperlink and a specific target is needed (_blank for example), pass it here
*/
public function __construct($sUID, $sLabel, $sUrl, $sTarget = '_top')
public function __construct($sUID, $sLabel, $sURL, $sTarget = '_top')
{
parent::__construct($sUID, $sLabel);
$this->sUrl = $sUrl;
$this->sURL = $sURL;
$this->sTarget = $sTarget;
}
/** @ignore */
public function GetMenuItem()
{
return array('label' => $this->GetLabel(), 'url' => $this->GetUrl(), 'target' => $this-> GetTarget(), 'css_classes' => $this->aCssClasses);
}
/** @ignore */
public function GetUrl()
{
return $this->sUrl;
}
/** @ignore */
public function GetTarget()
{
return $this->sTarget;
return array('label' => $this->GetLabel(), 'url' => $this->sURL, 'target' => $this->sTarget, 'css_classes' => $this->aCssClasses);
}
}
@@ -918,9 +905,7 @@ class URLPopupMenuItem extends ApplicationPopupMenuItem
class JSPopupMenuItem extends ApplicationPopupMenuItem
{
/** @ignore */
protected $sJsCode;
/** @ignore */
protected $sUrl;
protected $sJSCode;
/** @ignore */
protected $aIncludeJSFiles;
@@ -938,8 +923,7 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
public function __construct($sUID, $sLabel, $sJSCode, $aIncludeJSFiles = array())
{
parent::__construct($sUID, $sLabel);
$this->sJsCode = $sJSCode;
$this->sUrl = '#';
$this->sJSCode = $sJSCode;
$this->aIncludeJSFiles = $aIncludeJSFiles;
}
@@ -949,9 +933,9 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
// Note: the semicolumn is a must here!
return array(
'label' => $this->GetLabel(),
'onclick' => $this->GetJsCode().'; return false;',
'url' => $this->GetUrl(),
'css_classes' => $this->GetCssClasses(),
'onclick' => $this->sJSCode.'; return false;',
'url' => '#',
'css_classes' => $this->aCssClasses,
);
}
@@ -960,18 +944,6 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
{
return $this->aIncludeJSFiles;
}
/** @ignore */
public function GetJsCode()
{
return $this->sJsCode;
}
/** @ignore */
public function GetUrl()
{
return $this->sUrl;
}
}
/**
@@ -1043,12 +1015,11 @@ class JSButtonItem extends JSPopupMenuItem
* @api
* @package Extensibility
* @since 2.0
* @deprecated since 3.0.0 use iPageUIBlockExtension instead
*/
interface iPageUIExtension
{
/**
* Add content to the header of the page
* Add content to the North pane
*
* @param iTopWebPage $oPage The page to insert stuff into.
*
@@ -1057,7 +1028,7 @@ interface iPageUIExtension
public function GetNorthPaneHtml(iTopWebPage $oPage);
/**
* Add content to the footer of the page
* Add content to the South pane
*
* @param iTopWebPage $oPage The page to insert stuff into.
*
@@ -1075,56 +1046,12 @@ interface iPageUIExtension
public function GetBannerHtml(iTopWebPage $oPage);
}
/**
* Implement this interface to add content to any iTopWebPage
*
* There are 3 places where content can be added:
*
* * The north pane: (normaly empty/hidden) at the top of the page, spanning the whole
* width of the page
* * The south pane: (normaly empty/hidden) at the bottom of the page, spanning the whole
* width of the page
* * The admin banner (two tones gray background) at the left of the global search.
* Limited space, use it for short messages
*
* Each of the methods of this interface is supposed to return the HTML to be inserted at
* the specified place and can use the passed iTopWebPage object to add javascript or CSS definitions
*
* @api
* @package Extensibility
* @since 3.0.0
*/
interface iPageUIBlockExtension
{
/**
* Add content to the "admin banner"
*
* @return iUIBlock|null The Block to add into the page
*/
public function GetBannerBlock();
/**
* Add content to the header of the page
*
* @return iUIBlock|null The Block to add into the page
*/
public function GetHeaderBlock();
/**
* Add content to the footer of the page
*
* @return iUIBlock|null The Block to add into the page
*/
public function GetFooterBlock();
}
/**
* Extend this class instead of iPageUIExtension if you don't need to overload all methods
*
* @api
* @package Extensibility
* @since 2.7.0
* @deprecated since 3.0.0 use AbstractPageUIBlockExtension instead
*/
abstract class AbstractPageUIExtension implements iPageUIExtension
{
@@ -1154,40 +1081,6 @@ abstract class AbstractPageUIExtension implements iPageUIExtension
}
/**
* Extend this class instead of iPageUIExtension if you don't need to overload all methods
*
* @api
* @package Extensibility
* @since 3.0.0
*/
abstract class AbstractPageUIBlockExtension implements iPageUIBlockExtension
{
/**
* @inheritDoc
*/
public function GetBannerBlock()
{
return null;
}
/**
* @inheritDoc
*/
public function GetHeaderBlock()
{
return null;
}
/**
* @inheritDoc
*/
public function GetFooterBlock()
{
return null;
}
}
/**
* Implement this interface to add content to any enhanced portal page
*

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -22,7 +22,7 @@
* to check and is linked to a set of rules that determine the valid or invalid objects
* inside the set
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -23,7 +23,7 @@
* or the "bad" ones. The core audit engines computes the complement to the definition
* set when needed to obtain either the valid objects, or the ones with an error
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -43,6 +43,7 @@ class AuditRule extends cmdbAbstractObject
"db_table" => "priv_auditrule",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));

View File

@@ -1,7 +1,84 @@
<?php
// Copyright (C) 2016 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/CaptureWebPage.php
* Adapter class: when an API requires WebPage and you want to produce something else
*
* @copyright Copyright (C) 2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2021 Combodo SARL
*/
require_once(APPROOT."/application/webpage.class.inc.php");
class CaptureWebPage extends WebPage
{
protected $aReadyScripts;
function __construct()
{
parent::__construct('capture web page');
$this->aReadyScripts = array();
}
public function GetHtml()
{
$trash = $this->ob_get_clean_safe();
return $this->s_content;
}
public function GetJS()
{
$sRet = implode("\n", $this->a_scripts);
if (!empty($this->s_deferred_content))
{
$sRet .= "\n\$('body').append('".addslashes(str_replace("\n", '', $this->s_deferred_content))."');";
}
return $sRet;
}
public function GetReadyJS()
{
return "\$(document).ready(function() {\n".implode("\n", $this->aReadyScripts)."\n});";
}
public function GetCSS()
{
return $this->a_styles;
}
public function GetJSFiles()
{
return $this->a_linked_scripts;
}
public function GetCSSFiles()
{
return $this->a_linked_stylesheets;
}
public function output()
{
throw new Exception(__method__.' should not be called');
}
public function add_ready_script($sScript)
{
$this->aReadyScripts[] = $sScript;
}
}

View File

@@ -1,7 +1,97 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/CLIPage.php
* CLI page
* The page adds the content-type text/XML and the encoding into the headers
*
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2021 Combodo SARL
*/
require_once(APPROOT."/application/webpage.class.inc.php");
class CLIPage implements Page
{
function __construct($s_title)
{
}
public function output()
{
if (class_exists('DBSearch'))
{
DBSearch::RecordQueryTrace();
}
if (class_exists('ExecutionKPI'))
{
ExecutionKPI::ReportStats();
}
}
public function add($sText)
{
echo $sText;
}
public function p($sText)
{
echo $sText."\n";
}
public function pre($sText)
{
echo $sText."\n";
}
public function add_comment($sText)
{
echo "#".$sText."\n";
}
public function table($aConfig, $aData, $aParams = array())
{
$aCells = array();
foreach($aConfig as $sName=>$aDef)
{
if (strlen($aDef['description']) > 0)
{
$aCells[] = $aDef['label'].' ('.$aDef['description'].')';
}
else
{
$aCells[] = $aDef['label'];
}
}
echo implode(';', $aCells)."\n";
foreach($aData as $aRow)
{
$aCells = array();
foreach($aConfig as $sName=>$aAttribs)
{
$sValue = $aRow["$sName"];
$aCells[] = $sValue;
}
echo implode(';', $aCells)."\n";
}
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@@ -1,38 +0,0 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
/**
* Class CompileCSSService : used to ease testing ThemeHander class via mocks
*
* @author Olivier DAIN <olivier.dain@combodo.com>
* @since 3.0.0 N°2982
*/
class CompileCSSService
{
/**
* CompileCSSService constructor.
*/
public function __construct()
{
}
public function CompileCSSFromSASS($sSassContent, $aImportPaths = [], $aVariables = []){
return utils::CompileCSSFromSASS($sSassContent, $aImportPaths, $aVariables);
}
}

View File

@@ -1,7 +1,111 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/CSVPage.php
* Simple web page with no includes or fancy formatting, useful to generateXML documents
* The page adds the content-type text/XML and the encoding into the headers
*
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2021 Combodo SARL
*/
require_once(APPROOT."/application/webpage.class.inc.php");
class CSVPage extends WebPage
{
function __construct($s_title) {
parent::__construct($s_title);
$this->add_header("Content-type: text/plain; charset=".self::PAGES_CHARSET);
$this->no_cache();
$this->add_xframe_options();
//$this->add_header("Content-Transfer-Encoding: binary");
}
public function output()
{
$this->add_header("Content-Length: ".strlen(trim($this->s_content)));
// Get the unexpected output but do nothing with it
$sTrash = $this->ob_get_clean_safe();
foreach($this->a_headers as $s_header)
{
header($s_header);
}
echo trim($this->s_content);
echo "\n";
if (class_exists('DBSearch'))
{
DBSearch::RecordQueryTrace();
}
if (class_exists('ExecutionKPI'))
{
ExecutionKPI::ReportStats();
}
}
public function small_p($sText)
{
}
public function add($sText)
{
$this->s_content .= $sText;
}
public function p($sText)
{
$this->s_content .= $sText."\n";
}
public function add_comment($sText)
{
$this->s_content .= "#".$sText."\n";
}
public function table($aConfig, $aData, $aParams = array())
{
$aCells = array();
foreach($aConfig as $sName=>$aDef)
{
if (strlen($aDef['description']) > 0)
{
$aCells[] = $aDef['label'].' ('.$aDef['description'].')';
}
else
{
$aCells[] = $aDef['label'];
}
}
$this->s_content .= implode(';', $aCells)."\n";
foreach($aData as $aRow)
{
$aCells = array();
foreach($aConfig as $sName=>$aAttribs)
{
$sValue = $aRow["$sName"];
$aCells[] = $sValue;
}
$this->s_content .= implode(';', $aCells)."\n";
}
}
}

View File

@@ -1,14 +1,22 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
/**
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
use Combodo\iTop\Application\UI\Base\Component\Button\ButtonUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableSettings;
use Combodo\iTop\Application\UI\Base\Component\Toolbar\ToolbarUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout as DashboardLayoutUIBlock;
require_once(APPROOT.'application/dashboardlayout.class.inc.php');
require_once(APPROOT.'application/dashlet.class.inc.php');
require_once(APPROOT.'core/modelreflection.class.inc.php');
@@ -430,19 +438,22 @@ abstract class Dashboard
public function RenderProperties($oPage, $aExtraParams = array())
{
// menu to pick a layout and edit other properties of the dashboard
$oPage->add('<div class="ui-widget-content ui-corner-all ibo-dashboard-editor--properties"><div class="ui-widget-header ui-corner-all ibo-dashboard-editor--properties-title">'.Dict::S('UI:DashboardEdit:Properties').'</div>');
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Properties').'</div>');
$sUrl = utils::GetAbsoluteUrlAppRoot();
$oPage->add('<div class="ibo-dashboard-editor--properties-subtitle" data-role="ibo-dashboard-editor--properties-subtitle">'.Dict::S('UI:DashboardEdit:Layout').'</div>');
$oPage->add('<div id="select_layout" class="ibo-dashboard-editor--layout-list" data-role="ibo-dashboard-editor--layout-list">');
foreach (get_declared_classes() as $sLayoutClass) {
if (is_subclass_of($sLayoutClass, 'DashboardLayout')) {
$oPage->add('<div style="text-align:center">'.Dict::S('UI:DashboardEdit:Layout').'</div>');
$oPage->add('<div id="select_layout" style="text-align:center">');
foreach( get_declared_classes() as $sLayoutClass)
{
if (is_subclass_of($sLayoutClass, 'DashboardLayout'))
{
$oReflection = new ReflectionClass($sLayoutClass);
if (!$oReflection->isAbstract()) {
if (!$oReflection->isAbstract())
{
$aCallSpec = array($sLayoutClass, 'GetInfo');
$aInfo = call_user_func($aCallSpec);
$sChecked = ($this->sLayoutClass == $sLayoutClass) ? 'checked' : '';
$oPage->add('<input type="radio" name="layout_class" '.$sChecked.' value="'.$sLayoutClass.'" id="layout_'.$sLayoutClass.'"><label for="layout_'.$sLayoutClass.'"><img src="'.$sUrl.$aInfo['icon'].'" class="ibo-dashboard--properties--icon" data-role="ibo-dashboard--properties--icon"/></label>'); // title="" on either the img or the label does nothing !
$oPage->add('<input type="radio" name="layout_class" '.$sChecked.' value="'.$sLayoutClass.'" id="layout_'.$sLayoutClass.'"><label for="layout_'.$sLayoutClass.'"><img src="'.$sUrl.$aInfo['icon'].'" /></label>'); // title="" on either the img or the label does nothing !
}
}
}
@@ -473,15 +484,14 @@ abstract class Dashboard
$oPage->add_ready_script(
<<<EOF
// Note: the title gets deleted by the validation mechanism
$("#attr_auto_reload_sec").attr('data-tooltip-content', '$sRateTitle');
CombodoTooltip.InitTooltipFromMarkup($("#attr_auto_reload_sec"));
$("#attr_auto_reload_sec").tooltip({items: 'input', content: '$sRateTitle'});
$("#attr_auto_reload_sec").prop('disabled', !$('#attr_auto_reload').is(':checked'));
$('#attr_auto_reload').change( function(ev) {
$("#attr_auto_reload_sec").prop('disabled', !$(this).is(':checked'));
} );
$('#select_layout').controlgroup();
$('#select_layout').buttonset();
$('#select_dashlet').droppable({
accept: '.dashlet',
drop: function(event, ui) {
@@ -491,7 +501,7 @@ abstract class Dashboard
},
});
$('#event_bus').on('dashlet-selected', function(event, data){
$('#event_bus').bind('dashlet-selected', function(event, data){
var sDashletId = data.dashlet_id;
var sPropId = 'dashlet_properties_'+sDashletId;
$('.dashlet_properties').each(function() {
@@ -516,55 +526,34 @@ EOF
* @param bool $bEditMode
* @param array $aExtraParams
* @param bool $bCanEdit
*
* @return \Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
{
if (!array_key_exists('dashboard_div_id', $aExtraParams)) {
if (!array_key_exists('dashboard_div_id', $aExtraParams))
{
$aExtraParams['dashboard_div_id'] = utils::Sanitize($this->GetId(), '', 'element_identifier');
}
$oPage->add('<div class="dashboard-title-line"><div class="dashboard-title">'.htmlentities(Dict::S($this->sTitle), ENT_QUOTES, 'UTF-8', false).'</div></div>');
/** @var \DashboardLayoutMultiCol $oLayout */
$oLayout = new $this->sLayoutClass();
foreach ($this->aCells as $iCellIdx => $aDashlets) {
foreach ($aDashlets as $oDashlet) {
foreach($this->aCells as $iCellIdx => $aDashlets)
{
foreach($aDashlets as $oDashlet)
{
$aDashletCoordinates = $oLayout->GetDashletCoordinates($iCellIdx);
$this->PrepareDashletForRendering($oDashlet, $aDashletCoordinates, $aExtraParams);
}
}
$oDashboard = $oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
$oPage->AddUiBlock($oDashboard);
$bFromDasboardPage = isset($aExtraParams['from_dashboard_page']) ? isset($aExtraParams['from_dashboard_page']) : false;
if ($bFromDasboardPage) {
$sTitleForHTML = utils::HtmlEntities(Dict::S($this->sTitle));
$sHtml = "<div class=\"ibo-top-bar--toolbar-dashboard-title\">{$sTitleForHTML}</div>";
if ($oPage instanceof iTopWebPage) {
$oTopBar = $oPage->GetTopBarLayout();
$oToolbar = ToolbarUIBlockFactory::MakeStandard();
$oTopBar->SetToolbar($oToolbar);
$oToolbar->AddHtml($sHtml);
} else {
$oPage->add_script(<<<JS
$(".ibo-top-bar--toolbar-dashboard-title").html("$sTitleForHTML");
JS
);
}
} else {
$oDashboard->SetTitle(Dict::S($this->sTitle));
}
if (!$bEditMode) {
$oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
if (!$bEditMode)
{
$oPage->add_linked_script('../js/dashlet.js');
$oPage->add_linked_script('../js/dashboard.js');
}
return $oDashboard;
}
/**
@@ -576,18 +565,19 @@ JS
public function RenderDashletsSelection(WebPage $oPage)
{
// Toolbox/palette to drag and drop dashlets
$oPage->add('<div class="ui-widget-content ui-corner-all ibo-dashboard--available-dashlets"><div class="ui-widget-header ui-corner-all ibo-dashboard--available-dashlet--title">'.Dict::S('UI:DashboardEdit:Dashlets').'</div>');
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Dashlets').'</div>');
$sUrl = utils::GetAbsoluteUrlAppRoot();
$oPage->add('<div id="select_dashlet" class="ibo-dashboard--available-dashlets--list" data-role="ibo-dashboard--available-dashlets--list">');
$oPage->add('<div id="select_dashlet" style="text-align:center; max-height:120px; overflow-y:auto;">');
$aAvailableDashlets = $this->GetAvailableDashlets();
foreach ($aAvailableDashlets as $sDashletClass => $aInfo) {
$oPage->add('<span dashlet_class="'.$sDashletClass.'" class="ibo-dashboard-editor--available-dashlet-icon dashlet_icon ui-widget-content ui-corner-all" data-role="ibo-dashboard-editor--available-dashlet-icon" id="dashlet_'.$sDashletClass.'" title="'.$aInfo['label'].'"><img src="'.$sUrl.$aInfo['icon'].'" /></span>');
foreach($aAvailableDashlets as $sDashletClass => $aInfo)
{
$oPage->add('<span dashlet_class="'.$sDashletClass.'" class="dashlet_icon ui-widget-content ui-corner-all" id="dashlet_'.$sDashletClass.'" title="'.$aInfo['label'].'" style="width:34px; height:34px; display:inline-block; margin:2px;"><img src="'.$sUrl.$aInfo['icon'].'" /></span>');
}
$oPage->add('</div>');
$oPage->add('</div>');
$oPage->add_ready_script("$('.dashlet_icon').draggable({cursor: 'move', helper: 'clone', appendTo: 'body', zIndex: 10000, revert:'invalid'});");
$oPage->add_ready_script("$('.dashlet_icon').draggable({helper: 'clone', appendTo: 'body', zIndex: 10000, revert:'invalid'});");
}
/**
@@ -597,12 +587,12 @@ JS
public function RenderDashletsProperties(WebPage $oPage, $aExtraParams = array())
{
// Toolbox/palette to edit the properties of each dashlet
$oPage->add('<div class="ui-widget-content ui-corner-all ibo-dashlet--properties"><div class="ui-widget-header ui-corner-all ibo-dashlet--properties--title">'.Dict::S('UI:DashboardEdit:DashletProperties').'</div>');
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:DashletProperties').'</div>');
/** @var \DashboardLayoutMultiCol $oLayout */
$oLayout = new $this->sLayoutClass();
$oPage->add('<div id="dashlet_properties">');
$oPage->add('<div id="dashlet_properties" style="text-align:center">');
foreach($this->aCells as $iCellIdx => $aCell)
{
/** @var \Dashlet $oDashlet */
@@ -635,13 +625,16 @@ JS
foreach( get_declared_classes() as $sDashletClass)
{
// DashletUnknown is not among the selection as it is just a fallback for dashlets that can't instantiated.
if (is_subclass_of($sDashletClass, 'Dashlet') && !in_array($sDashletClass, array('DashletUnknown', 'DashletProxy'))) {
// DashletUnknown is not among the selection as it is just a fallback for dashlets that can't instanciated.
if ( is_subclass_of($sDashletClass, 'Dashlet') && !in_array($sDashletClass, array('DashletUnknown', 'DashletProxy')) )
{
$oReflection = new ReflectionClass($sDashletClass);
if (!$oReflection->isAbstract()) {
if (!$oReflection->isAbstract())
{
$aCallSpec = array($sDashletClass, 'IsVisible');
$bVisible = call_user_func($aCallSpec);
if ($bVisible) {
if ($bVisible)
{
$aCallSpec = array($sDashletClass, 'GetInfo');
$aInfo = call_user_func($aCallSpec);
$aDashlets[$sDashletClass] = $aInfo;
@@ -889,53 +882,11 @@ class RuntimeDashboard extends Dashboard
$oDashboard->FromXml($sDashboardDefinition);
$oDashboard->SetCustomFlag($bCustomized);
$oDashboard->SetDefinitionFile($sDashboardFile);
} else {
}
else
{
$oDashboard = null;
}
return $oDashboard;
}
/**
* @param string $sDashboardFile file name relative to the current module folder
* @param string $sDashBoardId code of the dashboard either menu_id or <class>__<attcode>
*
* @return null|RuntimeDashboard
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \Exception
*/
public static function GetDashboardToEdit($sDashboardFile, $sDashBoardId)
{
$bCustomized = false;
// Search for an eventual user defined dashboard
$oUDSearch = new DBObjectSearch('UserDashboard');
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oUDSearch->AddCondition('menu_code', $sDashBoardId, '=');
$oUDSet = new DBObjectSet($oUDSearch);
if ($oUDSet->Count() > 0) {
// Assuming there is at most one couple {user, menu}!
$oUserDashboard = $oUDSet->Fetch();
$sDashboardDefinition = $oUserDashboard->Get('contents');
$bCustomized = true;
} else {
$sDashboardDefinition = @file_get_contents($sDashboardFile);
}
if ($sDashboardDefinition !== false) {
$oDashboard = new RuntimeDashboard($sDashBoardId);
$oDashboard->FromXml($sDashboardDefinition);
$oDashboard->SetCustomFlag($bCustomized);
$oDashboard->SetDefinitionFile($sDashboardFile);
} else {
$oDashboard = null;
}
return $oDashboard;
}
@@ -945,33 +896,40 @@ class RuntimeDashboard extends Dashboard
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
{
if (!isset($aExtraParams['query_params']) && isset($aExtraParams['this->class'])) {
if (!isset($aExtraParams['query_params']) && isset($aExtraParams['this->class']))
{
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
$aRenderParams = array('query_params' => $oObj->ToArgsForQuery());
} else {
}
else
{
$aRenderParams = $aExtraParams;
}
$oDashboard = parent::Render($oPage, $bEditMode, $aRenderParams);
parent::Render($oPage, $bEditMode, $aRenderParams);
if (isset($aExtraParams['query_params']['this->object()'])) {
if (isset($aExtraParams['query_params']['this->object()']))
{
/** @var \DBObject $oObj */
$oObj = $aExtraParams['query_params']['this->object()'];
$aAjaxParams = array('this->class' => get_class($oObj), 'this->id' => $oObj->GetKey());
if (isset($aExtraParams['from_dashboard_page'])) {
$aAjaxParams['from_dashboard_page'] = $aExtraParams['from_dashboard_page'];
}
} else {
}
else
{
$aAjaxParams = $aExtraParams;
}
if (!$bEditMode && !$oPage->IsPrintableVersion()) {
if (!$bEditMode && !$oPage->IsPrintableVersion())
{
$sId = $this->GetId();
$sDivId = utils::Sanitize($sId, '', 'element_identifier');
if ($this->GetAutoReload()) {
if ($this->GetAutoReload())
{
$sFile = addslashes($this->GetDefinitionFile());
$sExtraParams = json_encode($aAjaxParams);
$iReloadInterval = 1000 * $this->GetAutoReloadInterval();
$sReloadURL = $this->GetReloadURL();
$oPage->add_script(
<<<JS
<<<EOF
if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined')
{
clearInterval(AutoReloadDashboardId$sDivId);
@@ -983,18 +941,25 @@ class RuntimeDashboard extends Dashboard
function ReloadDashboard$sDivId()
{
// Do not reload when a dialog box is active
if (!($('.ui-dialog:visible').length > 0) && $('.ibo-dashboard#$sDivId').is(':visible'))
if (!($('.ui-dialog:visible').length > 0) && $('.dashboard_contents#$sDivId').is(':visible'))
{
updateDashboard$sDivId();
$('.dashboard_contents#$sDivId').block();
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
{ operation: 'reload_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL'},
function(data){
$('.dashboard_contents#$sDivId').html(data);
$('.dashboard_contents#$sDivId').unblock();
}
);
}
}
JS
EOF
);
}
else
{
$oPage->add_script(
<<<EOF
<<<EOF
if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined')
{
clearInterval(AutoReloadDashboardId$sDivId);
@@ -1004,75 +969,60 @@ EOF
);
}
if ($bCanEdit) {
$this->RenderSelector($oPage, $oDashboard, $aAjaxParams);
$this->RenderEditionTools($oPage, $oDashboard, $aAjaxParams);
if ($bCanEdit)
{
$this->RenderSelector($oPage, $aAjaxParams);
$this->RenderEditionTools($oPage, $aAjaxParams);
}
}
}
/**
* @param WebPage $oPage
* @param \Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout $oDashboard
* @param bool $bFromDashboardPage
* @param \iTopWebPage $oPage
* @param array $aAjaxParams
*
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
protected function RenderSelector(WebPage $oPage, DashboardLayoutUIBlock $oDashboard, $aAjaxParams = array())
protected function RenderSelector($oPage, $aAjaxParams = array())
{
if (!$this->HasCustomDashboard()) {
return;
}
$sId = $this->GetId();
$sDivId = utils::Sanitize($sId, '', 'element_identifier');
$sExtraParams = json_encode($aAjaxParams);
$sSwitchToStandard = Dict::S('UI:Toggle:SwitchToStandardDashboard');
$sSwitchToCustom = Dict::S('UI:Toggle:SwitchToCustomDashboard');
$bStandardSelected = appUserPreferences::GetPref('display_original_dashboard_'.$sId, false);
$sSelectorHtml = '<div class="dashboard-selector">';
if ($this->HasCustomDashboard())
{
$bStandardSelected = appUserPreferences::GetPref('display_original_dashboard_'.$sId, false);
$sStandard = Dict::S('UI:Toggle:StandardDashboard');
$sSelectorHtml .= '<div class="selector-label">'.$sStandard.'</div>';
$sSelectorHtml .= '<label class="switch"><input type="checkbox" onchange="ToggleDashboardSelector'.$sDivId.'();" '.($bStandardSelected ? '' : 'checked').'><span class="slider round"></span></label></input></label>';
$sCustom = Dict::S('UI:Toggle:CustomDashboard');
$sSelectorHtml .= '<div class="selector-label">'.$sCustom.'</div>';
$sSelectorHtml = '<div id="ibo-dashboard-selector'.$sDivId.'" class="ibo-dashboard--selector" data-tooltip-content="'.($bStandardSelected ? $sSwitchToCustom : $sSwitchToStandard).'">';
$sSelectorHtml .= '<label class="ibo-dashboard--switch"><input type="checkbox" onchange="ToggleDashboardSelector'.$sDivId.'();" '.($bStandardSelected ? '' : 'checked').'><span class="ibo-dashboard--slider"></span></label></input></label>';
}
$sSelectorHtml .= '</div>';
$sSelectorHtml = addslashes($sSelectorHtml);
$sFile = addslashes($this->GetDefinitionFile());
$sReloadURL = $this->GetReloadURL();
$bFromDashboardPage = isset($aAjaxParams['from_dashboard_page']) ? isset($aAjaxParams['from_dashboard_page']) : false;
if ($bFromDashboardPage) {
if ($oPage instanceof iTopWebPage) {
$oToolbar = $oPage->GetTopBarLayout()->GetToolbar();
$oToolbar->AddHtml($sSelectorHtml);
}
} else {
$oToolbar = $oDashboard->GetToolbar();
$oToolbar->AddHtml($sSelectorHtml);
}
$oPage->add_ready_script(
<<<EOF
$('.dashboard-title').after('$sSelectorHtml');
EOF
);
$oPage->add_script(
<<<JS
<<<EOF
function ToggleDashboardSelector$sDivId()
{
var dashboard = $('.ibo-dashboard#$sDivId')
dashboard.block();
$('.dashboard_contents#$sDivId').block();
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
{ operation: 'toggle_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL' },
function(data) {
dashboard.html(data);
dashboard.unblock();
if ($('#ibo-dashboard-selector$sDivId input').prop("checked")) {
$('#ibo-dashboard-selector$sDivId').data('tooltip-content', '$sSwitchToStandard');
} else {
$('#ibo-dashboard-selector$sDivId').data('tooltip-content', '$sSwitchToCustom');
}
CombodoTooltip.InitAllNonInstantiatedTooltips($('#ibo-dashboard-selector$sDivId').parent());
$('.dashboard_contents#$sDivId').html(data);
$('.dashboard_contents#$sDivId').unblock();
}
);
}
JS
EOF
);
}
@@ -1103,58 +1053,45 @@ JS
*
* @throws \Exception
*/
protected function RenderEditionTools(WebPage $oPage, DashboardLayoutUIBlock $oDashboard, $aExtraParams)
protected function RenderEditionTools(WebPage $oPage, $aExtraParams)
{
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.iframe-transport.js');
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.fileupload.js');
$sId = utils::Sanitize($this->GetId(), '', 'element_identifier');
$sMenuTogglerId = "ibo-dashboard-menu-toggler-{$sId}";
$sPopoverMenuId = "ibo-dashboard-menu-popover-{$sId}";
$sName = 'UI:Dashboard:Actions';
$bFromDashboardPage = isset($aExtraParams['from_dashboard_page']) ? isset($aExtraParams['from_dashboard_page']) : false;
if ($bFromDashboardPage) {
if (!($oPage instanceof iTopWebPage)) {
// TODO 3.0 change the menu
return;
}
$oToolbar = $oPage->GetTopBarLayout()->GetToolbar();
} else {
$oToolbar = $oDashboard->GetToolbar();
}
$oActionButton = ButtonUIBlockFactory::MakeIconAction('fas fa-ellipsis-v', Dict::S($sName), $sName, '', false, $sMenuTogglerId)
->AddCSSClass('ibo-top-bar--toolbar-dashboard-menu-toggler')
->AddCSSClass('ibo-action-button');
$oToolbar->AddSubBlock($oActionButton);
$sEditMenu = "<div id=\"DashboardMenu\"><ul><li><i class=\"top-right-icon icon-additional-arrow fas fa-pencil-alt\"></i><ul>";
$aActions = array();
$sFile = addslashes($this->sDefinitionFile);
$sJSExtraParams = json_encode($aExtraParams);
if ($this->HasCustomDashboard()) {
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:EditCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
$oRevert = new JSPopupMenuItem('UI:Dashboard:RevertConfirm', Dict::S('UI:Dashboard:DeleteCustom'),
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}', $sJSExtraParams); else return false");
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
} else {
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:CreateCustom'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
$bCanEdit = true;
if ($this->HasCustomDashboard())
{
$bCanEdit = !appUserPreferences::GetPref('display_original_dashboard_'.$this->GetId(), false);
}
if ($bCanEdit)
{
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:Edit'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
}
if ($this->bCustomized)
{
$oRevert = new JSPopupMenuItem('UI:Dashboard:RevertConfirm', Dict::S('UI:Dashboard:Revert'),
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}', $sJSExtraParams); else return false");
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
}
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions);
$oActionsMenu = $oPage->GetPopoverMenu($sPopoverMenuId, $aActions)
->SetTogglerJSSelector("#$sMenuTogglerId");
$oToolbar->AddSubBlock($oActionButton)
->AddSubBlock($oActionsMenu);
$sEditMenu .= $oPage->RenderPopupMenuItems($aActions);
$sEditMenu = addslashes($sEditMenu);
$sReloadURL = $this->GetReloadURL();
$oPage->add_ready_script(
<<<EOF
$('.dashboard-title').after('$sEditMenu');
$('#DashboardMenu>ul').popupmenu();
EOF
);
$oPage->add_script(
<<<EOF
<<<EOF
function EditDashboard(sId, sDashboardFile, aExtraParams)
{
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'dashboard_editor', id: sId, file: sDashboardFile, extra_params: aExtraParams, reload_url: '$sReloadURL'},
@@ -1188,7 +1125,7 @@ EOF
$oPage->add_ready_script(
<<<EOF
$('#select_layout input').on('click', function() {
$('#select_layout input').click( function() {
var sLayoutClass = $(this).val();
$('.itop-dashboard').runtimedashboard('option', {layout_class: sLayoutClass});
} );
@@ -1227,27 +1164,30 @@ EOF
*/
public function RenderEditor($oPage, $aExtraParams = array())
{
if (isset($aExtraParams['this->class'])) {
if (isset($aExtraParams['this->class']))
{
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
$aRenderParams = array('query_params' => $oObj->ToArgsForQuery());
} else {
}
else
{
$aRenderParams = $aExtraParams;
}
$aRenderParams['dashboard_div_id'] = $aExtraParams['dashboard_div_id'];
$sJSExtraParams = json_encode($aExtraParams);
$oPage->add('<div id="dashboard_editor" class="ibo-dashboard-editor" data-role="ibo-dashboard-editor">');
$oPage->add('<div id="dashboard_editor">');
$oPage->add('<div class="ui-layout-center">');
$this->SetCustomFlag(true);
$this->Render($oPage, true, $aRenderParams);
$oPage->add('</div>');
$oPage->add('<div class="ui-layout-east ibo-dashboard-editor--pane" data-role="ibo-dashboard-editor--pane">');
$oPage->add('<div class="ui-layout-east">');
$this->RenderProperties($oPage, $aExtraParams);
$this->RenderDashletsSelection($oPage);
$this->RenderDashletsProperties($oPage, $aExtraParams);
$oPage->add('</div>');
$oPage->add('<div id="event_bus"/>'); // For exchanging messages between the panes, same as in the designer
$oPage->add('</div>');
$sDialogTitle = Dict::S('UI:DashboardEdit:Title');
$sOkButtonLabel = Dict::S('UI:Button:Save');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
@@ -1275,24 +1215,7 @@ $('#dashboard_editor').dialog({
modal: true,
title: '$sDialogTitle',
buttons: [
{ text: "$sCancelButtonLabel",
class: "ibo-is-alternative",
click: function() {
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
if (oDashboard.is_modified())
{
if (!confirm('$sCancelConfirmationMessage'))
{
return;
}
}
window.bLeavingOnUserAction = true;
$(this).dialog( "close" );
$(this).remove();
} },
{ text: "$sOkButtonLabel",
class: "ibo-is-primary",
click: function() {
{ text: "$sOkButtonLabel", click: function() {
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
if (oDashboard.is_dirty())
{
@@ -1308,6 +1231,19 @@ $('#dashboard_editor').dialog({
window.bLeavingOnUserAction = true;
oDashboard.save($(this));
} },
{ text: "$sCancelButtonLabel", click: function() {
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
if (oDashboard.is_modified())
{
if (!confirm('$sCancelConfirmationMessage'))
{
return;
}
}
window.bLeavingOnUserAction = true;
$(this).dialog( "close" );
$(this).remove();
} },
],
close: function() { $(this).remove(); }
});
@@ -1325,16 +1261,20 @@ $('#dashboard_editor .ui-layout-center').runtimedashboard({
new_dashlet_parameters: {operation: 'new_dashlet'}
});
var dashboard_prop_size = GetUserPreference('dashboard_prop_size', 400);
$('#dashboard_editor > .itop-dashboard').width($('#dashboard_editor').width() - dashboard_prop_size);
// We check when we finish click on the pane with the resize slider
// if the pane size changed (% 5px), if it's the case we save the value in userpref
$('#dashboard_editor > .itop-dashboard').on('mouseup',function (){
var iWidthDiff = $(this).width() - ($('#dashboard_editor').width() - dashboard_prop_size);
if( Math.abs(iWidthDiff) > 5){
dashboard_prop_size = iWidthDiff;
SetUserPreference('dashboard_prop_size', $('#dashboard_editor').width() - $(this).width(), true);
dashboard_prop_size = GetUserPreference('dashboard_prop_size', 350);
$('#dashboard_editor').layout({
east: {
minSize: 200,
size: dashboard_prop_size,
togglerLength_open: 0,
togglerLength_closed: 0,
onresize_end: function(name, elt, state, options, layout)
{
if (state.isSliding == false)
{
SetUserPreference('dashboard_prop_size', state.size, true);
}
},
}
});
@@ -1496,37 +1436,32 @@ JS
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$oPage->add_ready_script(
<<<JS
<<<JS
$('#dashlet_creation_dlg').dialog({
width: 600,
modal: true,
title: '$sDialogTitle',
buttons: [
{ text: "$sCancelButtonLabel",
click: function() {
{ text: "$sOkButtonLabel", click: function() {
var oForm = $(this).find('form');
var sFormId = oForm.attr('id');
var oParams = null;
var aErrors = ValidateForm(sFormId, false);
if (aErrors.length == 0)
{
oParams = ReadFormParams(sFormId);
}
oParams.operation = 'add_dashlet';
var me = $(this);
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function(data) {
me.dialog( "close" );
me.remove();
$('body').append(data);
});
} },
{ text: "$sCancelButtonLabel", click: function() {
$(this).dialog( "close" ); $(this).remove();
} ,
'class': 'ibo-button ibo-is-alternative ibo-is-neutral action cancel'
},
{ text: "$sOkButtonLabel",
click: function() {
var oForm = $(this).find('form');
var sFormId = oForm.attr('id');
var oParams = null;
var aErrors = ValidateForm(sFormId, false);
if (aErrors.length == 0)
{
oParams = ReadFormParams(sFormId);
}
oParams.operation = 'add_dashlet';
var me = $(this);
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function(data) {
me.dialog( "close" );
me.remove();
$('body').append(data);
});
},
'class': 'ibo-button ibo-is-regular ibo-is-primary action' }
} },
],
close: function() { $(this).remove(); }
});
@@ -1640,10 +1575,12 @@ JS
{
$sDataTableId = Dashlet::APPUSERPREFERENCES_PREFIX.$sDashletId;
$aClassAliases = array();
try {
try{
$oFilter = $oDashlet->GetDBSearch($aExtraParams);
$aClassAliases = $oFilter->GetSelectedClasses();
} catch (Exception $e) {
}
catch (Exception $e)
{
//on error, return default value
return null;
}

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -15,17 +15,15 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardColumn;
use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout as DashboardLayoutUIBlock;
use Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardRow;
/**
* Dashboard presentation
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
*/
abstract class DashboardLayout
{
abstract public function Render($oPage, $aDashlets, $bEditMode = false);
@@ -116,59 +114,61 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
// Trim the list of cells to remove the invisible/empty ones at the end of the array
$aCells = $this->TrimCellsArray($aCells);
$oDashboardLayout = new DashboardLayoutUIBlock();
//$oPage->AddUiBlock($oDashboardLayout);
$oPage->add('<table style="width:100%;table-layout:fixed;"><tbody>');
$iCellIdx = 0;
$fColSize = 100 / $this->iNbCols;
$sStyle = $bEditMode ? 'border: 1px #ccc dashed; width:'.$fColSize.'%;' : 'width: '.$fColSize.'%;';
$sClass = $bEditMode ? 'layout_cell edit_mode' : 'dashboard';
$iNbRows = ceil(count($aCells) / $this->iNbCols);
//Js given by each dashlet to reload
$sJSReload = "";
for ($iRows = 0; $iRows < $iNbRows; $iRows++) {
$oDashboardRow = new DashboardRow();
$oDashboardLayout->AddDashboardRow($oDashboardRow);
for ($iCols = 0; $iCols < $this->iNbCols; $iCols++) {
$oDashboardColumn = new DashboardColumn($bEditMode);
$oDashboardColumn->SetCellIndex($iCellIdx);
$oDashboardRow->AddDashboardColumn($oDashboardColumn);
if (array_key_exists($iCellIdx, $aCells)) {
for($iRows = 0; $iRows < $iNbRows; $iRows++)
{
$oPage->add("<tr data-dashboard-row-index=\"$iRows\">");
for($iCols = 0; $iCols < $this->iNbCols; $iCols++)
{
$sCellClass = ($iRows == $iNbRows-1) ? $sClass.' layout_last_used_rank' : $sClass;
$oPage->add("<td style=\"$sStyle\" class=\"$sCellClass\" data-dashboard-column-index=\"$iCols\" data-dashboard-cell-index=\"$iCellIdx\">");
if (array_key_exists($iCellIdx, $aCells))
{
$aDashlets = $aCells[$iCellIdx];
if (count($aDashlets) > 0) {
if (count($aDashlets) > 0)
{
/** @var \Dashlet $oDashlet */
foreach ($aDashlets as $oDashlet) {
if ($oDashlet::IsVisible()) {
$oDashboardColumn->AddUIBlock($oDashlet->DoRender($oPage, $bEditMode, true /* bEnclosingDiv */, $aExtraParams));
foreach($aDashlets as $oDashlet)
{
if ($oDashlet::IsVisible())
{
$oDashlet->DoRender($oPage, $bEditMode, true /* bEnclosingDiv */, $aExtraParams);
}
}
} else {
$oDashboardColumn->AddUIBlock(new Html('&nbsp;'));
}
} else {
$oDashboardColumn->AddUIBlock(new Html('&nbsp;'));
else
{
$oPage->add('&nbsp;');
}
}
else
{
$oPage->add('&nbsp;');
}
$oPage->add('</td>');
$iCellIdx++;
}
$sJSReload .= $oDashboardRow->GetJSRefreshCallback()." ";
$oPage->add('</tr>');
}
$oPage->add_script("function updateDashboard".$aExtraParams['dashboard_div_id']."(){".$sJSReload."}");
if ($bEditMode) // Add one row for extensibility
{
$oDashboardRow = new DashboardRow();
$oDashboardLayout->AddDashboardRow($oDashboardRow);
for ($iCols = 0; $iCols < $this->iNbCols; $iCols++) {
$oDashboardColumn = new DashboardColumn($bEditMode, true);
$oDashboardRow->AddDashboardColumn($oDashboardColumn);
$oDashboardColumn->AddUIBlock(new Html('&nbsp;'));
$sStyle = 'style="border: 1px #ccc dashed; width:'.$fColSize.'%;" class="layout_cell edit_mode layout_extension" data-dashboard-cell-index="'.$iCellIdx.'"';
$oPage->add("<tr data-dashboard-row-index=\"$iRows\">");
for($iCols = 0; $iCols < $this->iNbCols; $iCols++)
{
$oPage->add("<td $sStyle data-dashboard-column-index=\"$iCols\">");
$oPage->add('&nbsp;');
$oPage->add('</td>');
}
$oPage->add('</tr>');
}
return $oDashboardLayout;
$oPage->add('</tbody></table>');
}
/**

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2012-2021 Combodo SARL
// Copyright (C) 2012-2018 Combodo SARL
//
// This file is part of iTop.
//
@@ -16,19 +16,12 @@
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
use Combodo\iTop\Application\UI\Base\Component\Dashlet\DashletContainer;
use Combodo\iTop\Application\UI\Base\Component\Dashlet\DashletFactory;
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
use Combodo\iTop\Application\UI\Base\iUIBlock;
use Combodo\iTop\Application\UI\Base\UIBlock;
require_once(APPROOT.'application/forms.class.inc.php');
/**
* Base class for all 'dashlets' (i.e. widgets to be inserted into a dashboard)
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
abstract class Dashlet
@@ -57,7 +50,7 @@ abstract class Dashlet
$this->bRedrawNeeded = true; // By default: redraw each time a property changes
$this->bFormRedrawNeeded = false; // By default: no need to redraw the form (independent fields)
$this->aProperties = array(); // By default: there is no property
$this->aCSSClasses = array('ibo-dashlet');
$this->aCSSClasses = array('dashlet');
$this->sDashletType = get_class($this);
}
@@ -73,17 +66,21 @@ abstract class Dashlet
{
$refValue = $this->aProperties[$sProperty];
$sRefType = gettype($refValue);
if (gettype($sValue) == $sRefType) {
if (gettype($sValue) == $sRefType)
{
// Do not change anything in that case!
$ret = $sValue;
} elseif ($sRefType == 'boolean') {
}
elseif ($sRefType == 'boolean')
{
$ret = ($sValue == 'true');
} elseif ($sRefType == 'array') {
}
elseif ($sRefType == 'array')
{
$ret = explode(',', $sValue);
} elseif (is_array($sValue)) {
$ret = $sValue;
} else {
}
else
{
$ret = $sValue;
settype($ret, $sRefType);
}
@@ -194,8 +191,10 @@ abstract class Dashlet
*/
public function FromParams($aParams)
{
foreach ($this->aProperties as $sProperty => $value) {
if (array_key_exists($sProperty, $aParams)) {
foreach ($this->aProperties as $sProperty => $value)
{
if (array_key_exists($sProperty, $aParams))
{
$this->aProperties[$sProperty] = $aParams[$sProperty];
}
}
@@ -208,55 +207,79 @@ abstract class Dashlet
* @param bool $bEnclosingDiv
* @param array $aExtraParams
*/
public function DoRender($oPage, $bEditMode = false, $bEnclosingDiv = true, $aExtraParams = array()): UIBlock
public function DoRender($oPage, $bEditMode = false, $bEnclosingDiv = true, $aExtraParams = array())
{
$sCSSClasses = implode(' ', $this->aCSSClasses);
$sId = $this->GetID();
if ($bEnclosingDiv) {
if ($bEditMode) {
$oDashletContainer = new DashletContainer("dashlet_{$sId}");
} else {
$oDashletContainer = new DashletContainer();
if ($bEnclosingDiv)
{
if ($bEditMode)
{
$oPage->add('<div class="'.$sCSSClasses.'" id="dashlet_'.$sId.'">');
}
else
{
$oPage->add('<div class="'.$sCSSClasses.'">');
}
}
else
{
foreach ($this->aCSSClasses as $sCSSClass)
{
$oPage->add_ready_script("$('#dashlet_".$sId."').addClass('$sCSSClass');");
}
$oDashletContainer->AddCSSClasses($this->aCSSClasses);
} else {
$oDashletContainer = new DashletContainer();
$oDashletContainer->AddCSSClasses($this->aCSSClasses);
}
try {
if (get_class($this->oModelReflection) == 'ModelReflectionRuntime') {
$oBlock = $this->Render($oPage, $bEditMode, $aExtraParams);
} else {
$oBlock = $this->RenderNoData($oPage, $bEditMode, $aExtraParams);
try
{
if (get_class($this->oModelReflection) == 'ModelReflectionRuntime')
{
$this->Render($oPage, $bEditMode, $aExtraParams);
}
$oDashletContainer->AddSubBlock($oBlock);
} catch (UnknownClassOqlException $e) {
else
{
$this->RenderNoData($oPage, $bEditMode, $aExtraParams);
}
}
catch(UnknownClassOqlException $e)
{
// Maybe the class is part of a non-installed module, fail silently
// Except in Edit mode
if ($bEditMode) {
$oDashletContainer->AddCSSClass("dashlet-content");
$oDashletContainer->AddHtml('<h2>'.$e->GetUserFriendlyDescription().'</h2>');
if ($bEditMode)
{
$oPage->add('<div class="dashlet-content">');
$oPage->add('<h2>'.$e->GetUserFriendlyDescription().'</h2>');
$oPage->add('</div>');
}
} catch (OqlException $e) {
$oDashletContainer->AddCSSClass("dashlet-content");
$oDashletContainer->AddHtml('<p>'.$e->GetUserFriendlyDescription().'</p>');
} catch (Exception $e) {
$oDashletContainer->AddCSSClass("dashlet-content");
$oDashletContainer->AddHtml('<p>'.$e->getMessage().'</p>');
}
catch(OqlException $e)
{
$oPage->add('<div class="dashlet-content">');
$oPage->p($e->GetUserFriendlyDescription());
$oPage->add('</div>');
}
catch(Exception $e)
{
$oPage->add('<div class="dashlet-content">');
$oPage->p($e->getMessage());
$oPage->add('</div>');
}
if ($bEditMode) {
if ($bEnclosingDiv)
{
$oPage->add('</div>');
}
if ($bEditMode)
{
$sClass = get_class($this);
$sType = $this->sDashletType;
$oPage->add_ready_script(
<<<EOF
<<<EOF
$('#dashlet_$sId').dashlet({dashlet_id: '$sId', dashlet_class: '$sClass', 'dashlet_type': '$sType'});
EOF
);
}
return $oDashletContainer;
}
/**
@@ -280,7 +303,7 @@ EOF
* @param bool $bEditMode
* @param array $aExtraParams
*
* @return iUIBlock
* @return mixed
*/
abstract public function Render($oPage, $bEditMode = false, $aExtraParams = array());
@@ -290,12 +313,10 @@ EOF
* @param \WebPage $oPage
* @param bool $bEditMode
* @param array $aExtraParams
*
* @return iUIBlock
*/
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
{
return $this->Render($oPage, $bEditMode, $aExtraParams);
$this->Render($oPage, $bEditMode, $aExtraParams);
}
/**
@@ -602,12 +623,12 @@ class DashletUnknown extends Dashlet
$sIconUrl = utils::HtmlEntities(utils::GetAbsoluteUrlAppRoot().$aInfos['icon']);
$sExplainText = ($bEditMode) ? Dict::Format('UI:DashletUnknown:RenderText:Edit', $this->GetDashletType()) : Dict::S('UI:DashletUnknown:RenderText:View');
$oDashletContainer = new DashletContainer(null, ['dashlet-content']);
$oPage->add('<div class="dashlet-content">');
$oDashletContainer->AddHtml('<div class="dashlet-ukn-image"><img src="'.$sIconUrl.'" /></div>');
$oDashletContainer->AddHtml('<div class="dashlet-ukn-text">'.$sExplainText.'</div>');
$oPage->add('<div class="dashlet-ukn-image"><img src="'.$sIconUrl.'" /></div>');
$oPage->add('<div class="dashlet-ukn-text">'.$sExplainText.'</div>');
return $oDashletContainer;
$oPage->add('</div>');
}
/**
@@ -622,12 +643,12 @@ class DashletUnknown extends Dashlet
$sIconUrl = utils::HtmlEntities(utils::GetAbsoluteUrlAppRoot().$aInfos['icon']);
$sExplainText = Dict::Format('UI:DashletUnknown:RenderNoDataText:Edit', $this->GetDashletType());
$oDashletContainer = new DashletContainer(null, ['dashlet-content']);
$oPage->add('<div class="dashlet-content">');
$oDashletContainer->AddHtml('<div class="dashlet-ukn-image"><img src="'.$sIconUrl.'" /></div>');
$oDashletContainer->AddHtml('<div class="dashlet-ukn-text">'.$sExplainText.'</div>');
$oPage->add('<div class="dashlet-ukn-image"><img src="'.$sIconUrl.'" /></div>');
$oPage->add('<div class="dashlet-ukn-text">'.$sExplainText.'</div>');
return $oDashletContainer;
$oPage->add('</div>');
}
/**
@@ -746,9 +767,9 @@ class DashletProxy extends DashletUnknown
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
{
// This should never be called.
$oDashletContainer = new DashletContainer(null, ['dashlet-content']);
$oDashletContainer->AddHtml('<div>This dashlet is not supposed to be rendered as it is just a proxy for third-party widgets.</div>');
return $oDashletContainer;
$oPage->add('<div class="dashlet-content">');
$oPage->add('<div>This dashlet is not supposed to be rendered as it is just a proxy for third-party widgets.</div>');
$oPage->add('</div>');
}
/**
@@ -763,14 +784,12 @@ class DashletProxy extends DashletUnknown
$sIconUrl = utils::HtmlEntities(utils::GetAbsoluteUrlAppRoot().$aInfos['icon']);
$sExplainText = Dict::Format('UI:DashletProxy:RenderNoDataText:Edit', $this->GetDashletType());
$oDashletContainer = new DashletContainer(null, ['dashlet-content']);
$oPage->add('<div class="dashlet-content">');
$sHtml = '';
$sHtml .= '<div class="dashlet-pxy-image"><img src="'.$sIconUrl.'" /></div>';
$sHtml .= '<div class="dashlet-pxy-text">'.$sExplainText.'</div>';
$oPage->add('<div class="dashlet-pxy-image"><img src="'.$sIconUrl.'" /></div>');
$oPage->add('<div class="dashlet-pxy-text">'.$sExplainText.'</div>');
$oDashletContainer->AddHtml($sHtml);
return $oDashletContainer;
$oPage->add('</div>');
}
/**
@@ -801,7 +820,7 @@ class DashletEmptyCell extends Dashlet
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
{
return new Html('&nbsp;');
$oPage->add('&nbsp;');
}
/**
@@ -848,13 +867,11 @@ class DashletPlainText extends Dashlet
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
{
$sText = $this->aProperties['text'];
$sText = utils::EscapeHtml($sText);
$sText = utils::HtmlEntities($this->aProperties['text']);
$sText = str_replace(array("\r\n", "\n", "\r"), "<br/>", $sText);
$sId = 'plaintext_'.($bEditMode ? 'edit_' : '').$this->sId;
return DashletFactory::MakeForDashletPlainText($sText, $sId);
$sId = 'plaintext_'.($bEditMode? 'edit_' : '').$this->sId;
$oPage->add('<div id="'.$sId.'" class="dashlet-content">'.$sText.'</div>');
}
/**
@@ -874,7 +891,7 @@ class DashletPlainText extends Dashlet
{
return array(
'label' => Dict::S('UI:DashletPlainText:Label'),
'icon' => 'images/dashlets/icons8-text-box-48.png',
'icon' => 'images/dashlet-text.png',
'description' => Dict::S('UI:DashletPlainText:Description'),
);
}
@@ -904,21 +921,42 @@ class DashletObjectList extends Dashlet
{
$sTitle = $this->aProperties['title'];
$sShowMenu = $this->aProperties['menu'] ? '1' : '0';
$oFilter = $this->GetDBSearch($aExtraParams);
$sClass = $oFilter->GetClass();
$oPanel = PanelUIBlockFactory::MakeForClass($sClass, Dict::S($sTitle))
->AddCSSClass('ibo-datatable-panel');
$oPage->add('<div class="dashlet-content">');
$sHtmlTitle = utils::HtmlEntities(Dict::S($sTitle)); // done in the itop block
if ($sHtmlTitle != '')
{
$oPage->add('<div class="main_header"><h1>&nbsp;'.$sHtmlTitle.'</h1></div>');
}
$oFilter = $this->GetDBSearch($aExtraParams);
$oBlock = new DisplayBlock($oFilter, 'list');
$aParams = array(
'menu' => $sShowMenu,
'table_id' => self::APPUSERPREFERENCES_PREFIX.$this->sId,
'surround_with_panel' => false,
);
$sBlockId = 'block_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occurring in the same DOM)
$oBlock->DisplayIntoContentBlock($oPanel, $oPage, $sBlockId, array_merge($aExtraParams, $aParams));
$oBlock->Display($oPage, $sBlockId, array_merge($aExtraParams, $aParams));
$oPage->add('</div>');
}
return $oPanel;
public function GetDBSearch($aExtraParams = array())
{
$sQuery = $this->aProperties['query'];
if (isset($aExtraParams['query_params']))
{
$aQueryParams = $aExtraParams['query_params'];
}
elseif (isset($aExtraParams['this->class']) && isset($aExtraParams['this->id']))
{
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
$aQueryParams = $oObj->ToArgsForQuery();
}
else
{
$aQueryParams = array();
}
return DBObjectSearch::FromOQL($sQuery, $aQueryParams);
}
/**
@@ -932,35 +970,22 @@ class DashletObjectList extends Dashlet
$oPage->add('<div class="dashlet-content">');
$sHtmlTitle = utils::HtmlEntities($this->oModelReflection->DictString($sTitle)); // done in the itop block
if ($sHtmlTitle != '') {
if ($sHtmlTitle != '')
{
$oPage->add('<h1>'.$sHtmlTitle.'</h1>');
}
$oQuery = $this->oModelReflection->GetQuery($sQuery);
$sClass = $oQuery->GetClass();
$oPage->add('<div id="block_fake_'.$this->sId.'" class="display_block">');
$oPage->p(Dict::S('UI:NoObjectToDisplay'));
if ($bShowMenu) {
if ($bShowMenu)
{
$oPage->p('<a>'.Dict::Format('UI:ClickToCreateNew', $this->oModelReflection->GetName($sClass)).'</a>');
}
$oPage->add('</div>');
$oPage->add('</div>');
}
public function GetDBSearch($aExtraParams = array())
{
$sQuery = $this->aProperties['query'];
if (isset($aExtraParams['query_params'])) {
$aQueryParams = $aExtraParams['query_params'];
} elseif (isset($aExtraParams['this->class']) && isset($aExtraParams['this->id'])) {
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
$aQueryParams = $oObj->ToArgsForQuery();
} else {
$aQueryParams = array();
}
return DBObjectSearch::FromOQL($sQuery, $aQueryParams);
}
/**
* @inheritdoc
*/
@@ -984,7 +1009,7 @@ class DashletObjectList extends Dashlet
{
return array(
'label' => Dict::S('UI:DashletObjectList:Label'),
'icon' => 'images/dashlets/icons8-list-48.png',
'icon' => 'images/dashlet-list.png',
'description' => Dict::S('UI:DashletObjectList:Description'),
);
}
@@ -1178,81 +1203,93 @@ abstract class DashletGroupBy extends Dashlet
$sStyle = $this->aProperties['style'];
// First perform the query - if the OQL is not ok, it will generate an exception : no need to go further
if (isset($aExtraParams['query_params'])) {
if (isset($aExtraParams['query_params']))
{
$aQueryParams = $aExtraParams['query_params'];
} elseif (isset($aExtraParams['this->class']) && isset($aExtraParams['this->id'])) {
}
elseif (isset($aExtraParams['this->class']) && isset($aExtraParams['this->id']))
{
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
$aQueryParams = $oObj->ToArgsForQuery();
} else {
}
else
{
$aQueryParams = array();
}
$oFilter = DBObjectSearch::FromOQL($sQuery, $aQueryParams);
$oFilter->SetShowObsoleteData(utils::ShowObsoleteData());
$sClass = $oFilter->GetClass();
if (!$this->oModelReflection->IsValidAttCode($sClass, $this->sGroupByAttCode)) {
return new Html('<p>'.Dict::S('UI:DashletGroupBy:MissingGroupBy').'</p>');
if (!$this->oModelReflection->IsValidAttCode($sClass, $this->sGroupByAttCode))
{
$oPage->add('<p>'.Dict::S('UI:DashletGroupBy:MissingGroupBy').'</p>');
}
else
{
switch($sStyle)
{
case 'bars':
$sType = 'chart';
$aParams = array(
'chart_type' => 'bars',
'chart_title' => $sTitle,
'group_by' => $this->sGroupByExpr,
'group_by_label' => $this->sGroupByLabel,
'aggregation_function' => $this->sAggregationFunction,
'aggregation_attribute' => $this->sAggregationAttribute,
'limit' => $this->sLimit,
'order_direction' => $this->sOrderDirection,
'order_by' => $this->sOrderBy,
);
$sHtmlTitle = ''; // done in the itop block
break;
switch ($sStyle) {
case 'bars':
$sType = 'chart';
$aParams = array(
'chart_type' => 'bars',
'chart_title' => $sTitle,
'group_by' => $this->sGroupByExpr,
'group_by_label' => $this->sGroupByLabel,
'aggregation_function' => $this->sAggregationFunction,
'aggregation_attribute' => $this->sAggregationAttribute,
'limit' => $this->sLimit,
'order_direction' => $this->sOrderDirection,
'order_by' => $this->sOrderBy,
);
$sHtmlTitle = ''; // done in the itop block
break;
case 'pie':
$sType = 'chart';
$aParams = array(
'chart_type' => 'pie',
'chart_title' => $sTitle,
'group_by' => $this->sGroupByExpr,
'group_by_label' => $this->sGroupByLabel,
'aggregation_function' => $this->sAggregationFunction,
'aggregation_attribute' => $this->sAggregationAttribute,
'limit' => $this->sLimit,
'order_direction' => $this->sOrderDirection,
'order_by' => $this->sOrderBy,
);
$sHtmlTitle = ''; // done in the itop block
break;
case 'pie':
$sType = 'chart';
$aParams = array(
'chart_type' => 'pie',
'chart_title' => $sTitle,
'group_by' => $this->sGroupByExpr,
'group_by_label' => $this->sGroupByLabel,
'aggregation_function' => $this->sAggregationFunction,
'aggregation_attribute' => $this->sAggregationAttribute,
'limit' => $this->sLimit,
'order_direction' => $this->sOrderDirection,
'order_by' => $this->sOrderBy,
);
$sHtmlTitle = ''; // done in the itop block
break;
case 'table':
default:
$sHtmlTitle = utils::HtmlEntities(Dict::S($sTitle)); // done in the itop block
$sType = 'count';
$aParams = array(
'group_by' => $this->sGroupByExpr,
'group_by_label' => $this->sGroupByLabel,
'aggregation_function' => $this->sAggregationFunction,
'aggregation_attribute' => $this->sAggregationAttribute,
'limit' => $this->sLimit,
'order_direction' => $this->sOrderDirection,
'order_by' => $this->sOrderBy,
);
break;
}
case 'table':
default:
$sHtmlTitle = utils::HtmlEntities(Dict::S($sTitle)); // done in the itop block
$sType = 'count';
$aParams = array(
'group_by' => $this->sGroupByExpr,
'group_by_label' => $this->sGroupByLabel,
'aggregation_function' => $this->sAggregationFunction,
'aggregation_attribute' => $this->sAggregationAttribute,
'limit' => $this->sLimit,
'order_direction' => $this->sOrderDirection,
'order_by' => $this->sOrderBy,
);
break;
$oPage->add('<div class="dashlet-content">');
if ($sHtmlTitle != '')
{
$oPage->add('<div class="main_header"><h1>&nbsp;'.$sHtmlTitle.'</h1></div>');
}
$sBlockId = 'block_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
$oBlock = new DisplayBlock($oFilter, $sType);
$oBlock->Display($oPage, $sBlockId, array_merge($aExtraParams, $aParams));
if($bEditMode)
{
$oPage->add('<div class="dashlet-blocker"></div>');
}
$oPage->add('</div>');
}
$oPanel = PanelUIBlockFactory::MakeForClass($sClass, Dict::S($sTitle));
$sBlockId = 'block_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occurring in the same DOM)
$oBlock = new DisplayBlock($oFilter, $sType);
$oBlock->DisplayIntoContentBlock($oPanel, $oPage, $sBlockId, array_merge($aExtraParams, $aParams));
if ($bEditMode) {
$oPanel->AddHtml('<div class="dashlet-blocker"></div>');
}
return $oPanel;
}
/**
@@ -1335,9 +1372,9 @@ abstract class DashletGroupBy extends Dashlet
*/
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
{
$oDashletContainer = new DashletContainer(null, ['dashlet-content']);
$oDashletContainer->AddHtml('error!');
return $oDashletContainer;
$oPage->add('<div class="dashlet-content">');
$oPage->add('error!');
$oPage->add('</div>');
}
/**
@@ -1584,7 +1621,7 @@ abstract class DashletGroupBy extends Dashlet
// Note: no need to translate, should never be visible to the end-user!
return array(
'label' => 'Objects grouped by...',
'icon' => 'images/dashlets/icons8-transaction-list-48.png',
'icon' => 'images/dashlet-object-grouped.png',
'description' => 'Grouped objects dashlet (abstract)',
);
}
@@ -1648,7 +1685,7 @@ class DashletGroupByPie extends DashletGroupBy
{
return array(
'label' => Dict::S('UI:DashletGroupByPie:Label'),
'icon' => 'images/dashlets/icons8-pie-chart-48.png',
'icon' => 'images/dashlet-pie-chart.png',
'description' => Dict::S('UI:DashletGroupByPie:Description'),
);
}
@@ -1658,27 +1695,26 @@ class DashletGroupByPie extends DashletGroupBy
*/
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
{
$oDashletContainer = new DashletContainer(null, ['dashlet-content']);
$sTitle = $this->aProperties['title'];
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
$HTMLsTitle = ($sTitle != '') ? '<h1 style="text-align:center">'.utils::HtmlEntities($sTitle).'</h1>' : '';
$oDashletContainer->AddHtml("<div style=\"background-color:#fff;padding:0.25em;\">$HTMLsTitle<div id=\"$sBlockId\" style=\"background-color:#fff;\"></div></div>");
$oPage->add("<div style=\"background-color:#fff;padding:0.25em;\">$HTMLsTitle<div id=\"$sBlockId\" style=\"background-color:#fff;\"></div></div>");
$aDisplayValues = $this->MakeSimulatedData();
$aColumns = array();
$aNames = array();
foreach ($aDisplayValues as $idx => $aValue) {
foreach($aDisplayValues as $idx => $aValue)
{
$aColumns[] = array('series_'.$idx, (int)$aValue['value']);
$aNames['series_'.$idx] = $aValue['label'];
}
$sJSColumns = json_encode($aColumns);
$sJSNames = json_encode($aNames);
$oPage->add_ready_script(
<<<EOF
<<<EOF
window.setTimeout(function() {
var chart = c3.generate({
bindto: '#{$sBlockId}',
@@ -1699,8 +1735,6 @@ var chart = c3.generate({
});}, 100);
EOF
);
return $oDashletContainer;
}
}
@@ -1723,7 +1757,7 @@ class DashletGroupByBars extends DashletGroupBy
{
return array(
'label' => Dict::S('UI:DashletGroupByBars:Label'),
'icon' => 'images/dashlets/icons8-bar-chart-48.png',
'icon' => 'images/dashlet-bar-chart.png',
'description' => Dict::S('UI:DashletGroupByBars:Description'),
);
}
@@ -1733,26 +1767,25 @@ class DashletGroupByBars extends DashletGroupBy
*/
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
{
$oDashletContainer = new DashletContainer(null, ['dashlet-content']);
$sTitle = $this->aProperties['title'];
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
$HTMLsTitle = ($sTitle != '') ? '<h1 style="text-align:center">'.utils::HtmlEntities($sTitle).'</h1>' : '';
$oDashletContainer->AddHtml("<div style=\"background-color:#fff;padding:0.25em;\">$HTMLsTitle<div id=\"$sBlockId\" style=\"background-color:#fff;\"></div></div>");
$oPage->add("<div style=\"background-color:#fff;padding:0.25em;\">$HTMLsTitle<div id=\"$sBlockId\" style=\"background-color:#fff;\"></div></div>");
$aDisplayValues = $this->MakeSimulatedData();
$aNames = array();
foreach ($aDisplayValues as $idx => $aValue) {
foreach($aDisplayValues as $idx => $aValue)
{
$aNames[$idx] = $aValue['label'];
}
$sJSNames = json_encode($aNames);
$sJson = json_encode($aDisplayValues);
$oPage->add_ready_script(
<<<EOF
<<<EOF
window.setTimeout(function() {
var chart = c3.generate({
bindto: '#{$sBlockId}',
@@ -1800,8 +1833,6 @@ window.setTimeout(function() {
}, 100);
EOF
);
return $oDashletContainer;
}
}
@@ -1824,7 +1855,7 @@ class DashletGroupByTable extends DashletGroupBy
return array(
'label' => Dict::S('UI:DashletGroupByTable:Label'),
'description' => Dict::S('UI:DashletGroupByTable:Description'),
'icon' => 'images/dashlets/icons8-transaction-list-48.png',
'icon' => 'images/dashlet-groupby-table.png',
);
}
@@ -1833,44 +1864,40 @@ class DashletGroupByTable extends DashletGroupBy
*/
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
{
$oDashletContainer = new DashletContainer();
$aDisplayValues = $this->MakeSimulatedData();
$iTotal = 0;
foreach ($aDisplayValues as $iRow => $aDisplayData) {
foreach($aDisplayValues as $iRow => $aDisplayData)
{
$iTotal += $aDisplayData['value'];
}
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
$sHtml = '';
$sHtml .= '<div id="'.$sBlockId.'" class="display_block">';
$sHtml .= '<div class="dashlet-content">';
$sHtml .= '<p>'.Dict::Format('UI:Pagination:HeaderNoSelection', $iTotal).'</p>';
$sHtml .= '<table class="listResults">';
$sHtml .= '<thead>';
$sHtml .= '<tr>';
$sHtml .= '<th class="header" title="">'.$this->sGroupByLabel.'</th>';
$sHtml .= '<th class="header" title="'.Dict::S('UI:GroupBy:Count+').'">'.Dict::S('UI:GroupBy:Count').'</th>';
$sHtml .= '</tr>';
$sHtml .= '</thead>';
$sHtml .= '<tbody>';
foreach ($aDisplayValues as $aDisplayData) {
$sHtml .= '<tr class="even">';
$sHtml .= '<td class=""><span title="Active">'.$aDisplayData['label'].'</span></td>';
$sHtml .= '<td class=""><a>'.$aDisplayData['value'].'</a></td>';
$sHtml .= '</tr>';
$oPage->add('<div id="'.$sBlockId.'" class="display_block">');
$oPage->add('<div class="dashlet-content">');
$oPage->add('<p>'.Dict::Format('UI:Pagination:HeaderNoSelection', $iTotal).'</p>');
$oPage->add('<table class="listResults">');
$oPage->add('<thead>');
$oPage->add('<tr>');
$oPage->add('<th class="header" title="">'.$this->sGroupByLabel.'</th>');
$oPage->add('<th class="header" title="'.Dict::S('UI:GroupBy:Count+').'">'.Dict::S('UI:GroupBy:Count').'</th>');
$oPage->add('</tr>');
$oPage->add('</thead>');
$oPage->add('<tbody>');
foreach($aDisplayValues as $aDisplayData)
{
$oPage->add('<tr class="even">');
$oPage->add('<td class=""><span title="Active">'.$aDisplayData['label'].'</span></td>');
$oPage->add('<td class=""><a>'.$aDisplayData['value'].'</a></td>');
$oPage->add('</tr>');
}
$sHtml .= '</tbody>';
$sHtml .= '</table>';
$sHtml .= '</div>';
$oPage->add('</tbody>');
$oPage->add('</table>');
$oPage->add('</div>');
$sHtml .= '</div>';
$oDashletContainer->AddHtml($sHtml);
return $oDashletContainer;
$oPage->add('</div>');
}
}
@@ -1893,13 +1920,20 @@ class DashletHeaderStatic extends Dashlet
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
{
$sTitle = $this->aProperties['title'];
$sTitle = utils::HtmlEntities($this->aProperties['title']);
$sIcon = $this->aProperties['icon'];
$oIconSelect = $this->oModelReflection->GetIconSelectionField('icon');
$sIconPath = utils::HtmlEntities($oIconSelect->MakeFileUrl($sIcon));
return DashletFactory::MakeForDashletHeaderStatic($this->oModelReflection->DictString($sTitle), $sIconPath);
$oPage->add('<div class="dashlet-content">');
$oPage->add('<div class="main_header">');
$oPage->add('<img src="'.$sIconPath.'">');
$oPage->add('<div class="main_header"><h1>&nbsp;'.$this->oModelReflection->DictString($sTitle).'</h1></div>');
$oPage->add('</div>');
$oPage->add('</div>');
}
/**
@@ -1953,7 +1987,7 @@ class DashletHeaderStatic extends Dashlet
{
return array(
'label' => Dict::S('UI:DashletHeaderStatic:Label'),
'icon' => 'images/dashlets/icons8-header-48.png',
'icon' => 'images/dashlet-header.png',
'description' => Dict::S('UI:DashletHeaderStatic:Description'),
);
}
@@ -2023,10 +2057,11 @@ class DashletHeaderDynamic extends Dashlet
$sGroupBy = $this->aProperties['group_by'];
$oIconSelect = $this->oModelReflection->GetIconSelectionField('icon');
$sIconPath = $oIconSelect->MakeFileUrl($sIcon);
$sIconPath = utils::HtmlEntities($oIconSelect->MakeFileUrl($sIcon));
$aValues = $this->GetValues();
if (count($aValues) > 0) {
if (count($aValues) > 0)
{
// Stats grouped by <group_by>
$sCSV = implode(',', $aValues);
$aParams = array(
@@ -2036,7 +2071,9 @@ class DashletHeaderDynamic extends Dashlet
'status_codes[block]' => $sCSV,
'context_filter' => 1,
);
} else {
}
else
{
// Simple stats
$aParams = array(
'title[block]' => $sTitle,
@@ -2045,33 +2082,31 @@ class DashletHeaderDynamic extends Dashlet
);
}
if (isset($aExtraParams['query_params'])) {
$oPage->add('<div class="dashlet-content">');
$oPage->add('<div class="main_header">');
$oPage->add('<img src="'.$sIconPath.'">');
if (isset($aExtraParams['query_params']))
{
$aQueryParams = $aExtraParams['query_params'];
} elseif (isset($aExtraParams['this->class'])) {
}
elseif (isset($aExtraParams['this->class']))
{
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
$aQueryParams = $oObj->ToArgsForQuery();
} else {
}
else
{
$aQueryParams = array();
}
$oFilter = DBObjectSearch::FromOQL($sQuery, $aQueryParams);
$oFilter->SetShowObsoleteData(utils::ShowObsoleteData());
$sClass = $oFilter->GetClass();
$oPanel = PanelUIBlockFactory::MakeNeutral(Dict::S(str_replace('_', ':', $sTitle)))
->SetIcon($sIconPath)
->SetColorFromClass($sClass);
$oBlock = new DisplayBlock($oFilter, 'summary');
$sBlockId = 'block_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
$oBlock->DisplayIntoContentBlock($oPanel, $oPage, $sBlockId, array_merge($aExtraParams, $aParams));
$oBlock->Display($oPage, $sBlockId, array_merge($aExtraParams, $aParams));
$oSubTitle = $oPanel->GetSubTitleBlock();
$oSet = new DBObjectSet($oFilter);
$iCount = $oSet->Count();
$oAppContext = new ApplicationContext();
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.rawurlencode($oFilter->serialize());
$oSubTitle->AddHtml('<a class="summary" href="'.$sHyperlink.'">'.Dict::Format(str_replace('_', ':', $sSubtitle), $iCount).'</a>');
return $oPanel;
$oPage->add('</div>');
$oPage->add('</div>');
}
/**
@@ -2091,48 +2126,46 @@ class DashletHeaderDynamic extends Dashlet
$oIconSelect = $this->oModelReflection->GetIconSelectionField('icon');
$sIconPath = utils::HtmlEntities($oIconSelect->MakeFileUrl($sIcon));
$oDashletContainer = new DashletContainer(null, ['dashlet-content']);
$oPage->add('<div class="dashlet-content">');
$oPage->add('<div class="main_header">');
$sHtml = '';
$sHtml .= '<img src="'.$sIconPath.'">';
$oPage->add('<img src="'.$sIconPath.'">');
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
$iTotal = 0;
$aValues = $this->GetValues();
$sHtml .= '<div class="display_block" id="'.$sBlockId.'">';
$sHtml .= '<div class="summary-details">';
$sHtml .= '<table><tbody>';
$sHtml .= '<tr>';
foreach ($aValues as $sValue) {
$oPage->add('<div class="display_block" id="'.$sBlockId.'">');
$oPage->add('<div class="summary-details">');
$oPage->add('<table><tbody>');
$oPage->add('<tr>');
foreach ($aValues as $sValue)
{
$sValueLabel = $this->oModelReflection->GetValueLabel($sClass, $sGroupBy, $sValue);
$sHtml .= ' <th>'.$sValueLabel.'</th>';
$oPage->add(' <th>'.$sValueLabel.'</th>');
}
$sHtml .= '</tr>';
$sHtml .= '<tr>';
foreach ($aValues as $sValue) {
$iCount = (int)rand(2, 100);
$oPage->add('</tr>');
$oPage->add('<tr>');
foreach ($aValues as $sValue)
{
$iCount = (int) rand(2, 100);
$iTotal += $iCount;
$sHtml .= ' <td>'.$iCount.'</td>';
$oPage->add(' <td>'.$iCount.'</td>');
}
$sHtml .= '</tr>';
$sHtml .= '</tbody></table>';
$sHtml .= '</div>';
$oPage->add('</tr>');
$oPage->add('</tbody></table>');
$oPage->add('</div>');
$sTitle = $this->oModelReflection->DictString($sTitle);
$sSubtitle = $this->oModelReflection->DictFormat($sSubtitle, $iTotal);
$sHtml .= '<h1>'.utils::HtmlEntities($sTitle).'</h1>';
$sHtml .= '<a class="summary">'.utils::HtmlEntities($sSubtitle).'</a>';
$sHtml .= '</div>';
$sHtml .= '</div>';
$oDashletContainer->AddHtml($sHtml);
return $oDashletContainer;
$oPage->add('<h1>'.utils::HtmlEntities($sTitle).'</h1>');
$oPage->add('<a class="summary">'.utils::HtmlEntities($sSubtitle).'</a>');
$oPage->add('</div>');
$oPage->add('</div>');
$oPage->add('</div>');
}
/**
@@ -2261,7 +2294,7 @@ class DashletHeaderDynamic extends Dashlet
{
return array(
'label' => Dict::S('UI:DashletHeaderDynamic:Label'),
'icon' => 'images/dashlets/icons8-header-altered-48.png',
'icon' => 'images/dashlet-header-stats.png',
'description' => Dict::S('UI:DashletHeaderDynamic:Description'),
);
}
@@ -2277,8 +2310,8 @@ class DashletBadge extends Dashlet
{
parent::__construct($oModelReflection, $sId);
$this->aProperties['class'] = 'Contact';
$this->aCSSClasses[] = 'ibo-dashlet--is-inline';
$this->aCSSClasses[] = 'ibo-dashlet-badge';
$this->aCSSClasses[] = 'dashlet-inline';
$this->aCSSClasses[] = 'dashlet-badge';
}
/**
@@ -2288,17 +2321,17 @@ class DashletBadge extends Dashlet
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
{
$oDashletContainer = new DashletContainer($this->sId, ['dashlet-content']);
$sClass = $this->aProperties['class'];
$oPage->add('<div class="dashlet-content">');
$oFilter = new DBObjectSearch($sClass);
$oBlock = new DisplayBlock($oFilter, 'actions');
$aExtraParams['context_filter'] = 1;
$aExtraParams['withJSRefreshCallBack'] = true;
$sBlockId = 'block_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occurring in the same DOM)
$oBlock->DisplayIntoContentBlock($oDashletContainer, $oPage, $sBlockId, $aExtraParams);
$oBlock->Display($oPage, $sBlockId, $aExtraParams);
return $oDashletContainer;
$oPage->add('</div>');
}
/**
@@ -2306,25 +2339,25 @@ class DashletBadge extends Dashlet
*/
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
{
$oDashletContainer = new DashletContainer($this->sId, ['dashlet-content']);
$sClass = $this->aProperties['class'];
$sIconUrl = $this->oModelReflection->GetClassIcon($sClass, false);
$sClassLabel = $this->oModelReflection->GetName($sClass);
$sHtml = '';
$sHtml .= '<div id="block_fake_'.$this->sId.'" class="display_block">';
$sHtml .= '<p>';
$sHtml .= ' <a class="actions"><img src="'.utils::HtmlEntities($sIconUrl).'" style="vertical-align:middle;float;left;margin-right:10px;border:0;">'.$sClassLabel.': 947</a>';
$sHtml .= '</p>';
$sHtml .= '<p>';
$sHtml .= ' <a>'.Dict::Format('UI:ClickToCreateNew', $sClassLabel).'</a>';
$sHtml .= '</p>';
$sHtml .= '</div>';
$oPage->add('<div class="dashlet-content">');
$oDashletContainer->AddHtml($sHtml);
$oPage->add('<div id="block_fake_'.$this->sId.'" class="display_block">');
$oPage->add('<p>');
$oPage->add(' <a class="actions"><img src="'.utils::HtmlEntities($sIconUrl).'" style="vertical-align:middle;float;left;margin-right:10px;border:0;">'.$sClassLabel.': 947</a>');
$oPage->add('</p>');
$oPage->add('<p>');
$oPage->add(' <a>'.Dict::Format('UI:ClickToCreateNew', $sClassLabel).'</a>');
$oPage->add(' <br/>');
$oPage->add(' <a>'.Dict::Format('UI:SearchFor_Class', $sClassLabel).'</a>');
$oPage->add('</p>');
$oPage->add('</div>');
return $oDashletContainer;
$oPage->add('</div>');
}
static protected $aClassList = null;
@@ -2374,7 +2407,7 @@ class DashletBadge extends Dashlet
{
return array(
'label' => Dict::S('UI:DashletBadge:Label'),
'icon' => 'images/dashlets/icons8-badge-48.png',
'icon' => 'images/dashlet-badge.png',
'description' => Dict::S('UI:DashletBadge:Description'),
);
}

View File

@@ -1,46 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0">
<classes>
<class id="AbstractResource" _delta="define">
<parent>cmdbAbstractObject</parent>
<properties>
<comment>/* Resource access control abstraction. Can be herited by abstract resource access control classes. Generaly controlled using UR_ACTION_MODIFY access right. */</comment>
<abstract>true</abstract>
</properties>
<presentation/>
<methods/>
</class>
<class id="ResourceAdminMenu" _delta="define">
<parent>AbstractResource</parent>
<properties>
<comment>/* AdminTools menu access control. */</comment>
<abstract>true</abstract>
<category>grant_by_profile</category>
</properties>
<presentation/>
<methods/>
</class>
<class id="ResourceRunQueriesMenu" _delta="define">
<parent>AbstractResource</parent>
<properties>
<comment>/* RunQueriesMenu menu access control. */</comment>
<abstract>true</abstract>
<category>grant_by_profile</category>
</properties>
<presentation/>
<methods/>
</class>
<class id="ResourceSystemMenu" _delta="define">
<parent>AbstractResource</parent>
<properties>
<comment>/* System menu access control. */</comment>
<abstract>true</abstract>
<category>grant_by_profile</category>
</properties>
<presentation/>
<methods/>
</class>
</classes>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.7">
<portals>
<portal id="backoffice" _delta="define">
<url>pages/UI.php</url>
@@ -53,388 +12,13 @@
</portal>
</portals>
<menus>
<menu id="WelcomeMenu" xsi:type="MenuGroup" _delta="define">
<rank>10</rank>
<style>
<decoration_classes>fas fa-home</decoration_classes>
</style>
</menu>
<menu id="WelcomeMenuPage" xsi:type="DashboardMenuNode" _delta="define">
<rank>10</rank>
<parent>WelcomeMenu</parent>
<definition>
<layout>DashboardLayoutOneCol</layout>
<title>Menu:WelcomeMenuPage</title>
<cells>
<cell id="0">
<rank>0</rank>
<dashlets>
</dashlets>
</cell>
</cells>
</definition>
</menu>
<menu id="MyShortcuts" xsi:type="ShortcutContainerMenuNode" _delta="define">
<rank>20</rank>
<parent>WelcomeMenu</parent>
</menu>
<menu id="UserManagement" xsi:type="TemplateMenuNode" _delta="define">
<rank>10</rank>
<parent>AdminTools</parent>
<template_file/>
</menu>
<menu id="UserAccountsMenu" xsi:type="OQLMenuNode" _delta="define">
<rank>11</rank>
<parent>UserManagement</parent>
<oql><![CDATA[SELECT User]]></oql>
<do_search>1</do_search>
<search_form_open>1</search_form_open>
<enable_class>User</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
</menu>
<menu id="ProfilesMenu" xsi:type="OQLMenuNode" _delta="define">
<rank>12</rank>
<parent>UserManagement</parent>
<oql><![CDATA[SELECT URP_Profiles]]></oql>
<do_search>1</do_search>
<enable_class>URP_Profiles</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
</menu>
<menu id="AuditCategories" xsi:type="OQLMenuNode" _delta="define">
<rank>20</rank>
<parent>AdminTools</parent>
<oql><![CDATA[SELECT AuditCategory]]></oql>
<do_search>1</do_search>
<enable_class>AuditCategory</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
</menu>
<menu id="Queries" xsi:type="TemplateMenuNode" _delta="define">
<rank>30</rank>
<parent>AdminTools</parent>
<template_file/>
</menu>
<menu id="RunQueriesMenu" xsi:type="WebPageMenuNode" _delta="define">
<rank>31</rank>
<parent>Queries</parent>
<url>$pages/run_query.php</url>
<enable_class>ResourceRunQueriesMenu</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
</menu>
<menu id="QueryMenu" xsi:type="OQLMenuNode" _delta="define">
<rank>32</rank>
<parent>Queries</parent>
<oql><![CDATA[SELECT Query]]></oql>
<do_search>1</do_search>
<enable_class>Query</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
</menu>
<menu id="ExportMenu" xsi:type="WebPageMenuNode" _delta="define">
<rank>33</rank>
<parent>Queries</parent>
<url>$webservices/export-v2.php?interactive=1</url>
<enable_class>ResourceAdminMenu</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
</menu>
<menu id="DataModelMenu" xsi:type="WebPageMenuNode" _delta="define">
<rank>40</rank>
<parent>AdminTools</parent>
<url>$pages/schema.php</url>
<enable_class>ResourceRunQueriesMenu</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
</menu>
<menu id="UniversalSearchMenu" xsi:type="WebPageMenuNode" _delta="define">
<rank>35</rank>
<parent>Queries</parent>
<url>$pages/UniversalSearch.php</url>
<enable_class>ResourceAdminMenu</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
</menu>
<menu id="ConfigurationTools" xsi:type="MenuGroup" _delta="define_if_not_exists">
<rank>90</rank>
<style>
<decoration_classes>fas fa-cog</decoration_classes>
</style>
</menu>
<menu id="DataSources" xsi:type="OQLMenuNode" _delta="define">
<rank>20</rank>
<parent>ConfigurationTools</parent>
<oql><![CDATA[SELECT SynchroDataSource]]></oql>
<do_search>1</do_search>
<enable_class>SynchroDataSource</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
</menu>
<menu id="NotificationsMenu" xsi:type="WebPageMenuNode" _delta="define">
<rank>40</rank>
<parent>ConfigurationTools</parent>
<url>$pages/notifications.php</url>
<enable_class>Trigger</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
</menu>
<menu id="AdminTools" xsi:type="MenuGroup" _delta="define">
<rank>80</rank>
<style>
<decoration_classes>fas fa-tools</decoration_classes>
</style>
</menu>
<menu id="SystemTools" xsi:type="MenuGroup" _delta="define">
<rank>100</rank>
<enable_class>ResourceSystemMenu</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
<style>
<decoration_classes>fas fa-terminal</decoration_classes>
</style>
</menu>
</menus>
<meta>
<classes>
<class id="cmdbAbstractObject" _delta="define">
<methods>
<method id="Set">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>deny</operation>
<types>
<type id="AttributeStopWatch"/>
<type id="AttributeSubItem"/>
<type id="AttributeExternalField"/>
<type id="AttributeLinkedSetIndirect"/>
<type id="AttributeLinkedSet"/>
<type id="AttributeImage"/>
<type id="AttributeBlob"/>
</types>
</type_restrictions>
</argument>
<argument id="2">
<type>string</type>
<mandatory>true</mandatory>
</argument>
</arguments>
</method>
<method id="SetIfNull">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>deny</operation>
<types>
<type id="AttributeStopWatch"/>
<type id="AttributeSubItem"/>
<type id="AttributeExternalField"/>
<type id="AttributeLinkedSetIndirect"/>
<type id="AttributeLinkedSet"/>
<type id="AttributeImage"/>
<type id="AttributeBlob"/>
</types>
</type_restrictions>
</argument>
<argument id="2">
<type>string</type>
<mandatory>true</mandatory>
</argument>
</arguments>
</method>
<method id="AddValue">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>allow</operation>
<types>
<type id="AttributeInteger"/>
<type id="AttributeDecimal"/>
<type id="AttributePercentage"/>
<type id="AttributeDuration"/>
</types>
</type_restrictions>
</argument>
<argument id="2">
<type>string</type>
<mandatory>false</mandatory>
</argument>
</arguments>
</method>
<method id="SetCurrentDate">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>allow</operation>
<types>
<type id="AttributeDate"/>
<type id="AttributeDateTime"/>
<type id="AttributeString"/>
</types>
</type_restrictions>
</argument>
</arguments>
</method>
<method id="SetCurrentDateIfNull">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>allow</operation>
<types>
<type id="AttributeDate"/>
<type id="AttributeDateTime"/>
<type id="AttributeString"/>
</types>
</type_restrictions>
</argument>
</arguments>
</method>
<method id="SetCurrentUser">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>allow</operation>
<types>
<type id="AttributeExternalKey"/>
<type id="AttributeInteger"/>
<type id="AttributeString"/>
</types>
</type_restrictions>
</argument>
</arguments>
</method>
<method id="SetCurrentPerson">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>allow</operation>
<types>
<type id="AttributeExternalKey"/>
<type id="AttributeInteger"/>
<type id="AttributeString"/>
</types>
</type_restrictions>
</argument>
</arguments>
</method>
<method id="SetElapsedTime">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>allow</operation>
<types>
<type id="AttributeDuration"/>
</types>
</type_restrictions>
</argument>
<argument id="2">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>allow</operation>
<types>
<type id="AttributeDate"/>
<type id="AttributeDateTime"/>
</types>
</type_restrictions>
</argument>
<argument id="3">
<type>string</type>
<mandatory>false</mandatory>
</argument>
</arguments>
</method>
<method id="Reset">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>deny</operation>
<types>
<type id="AttributeStopWatch"/>
<type id="AttributeSubItem"/>
<type id="AttributeExternalField"/>
</types>
</type_restrictions>
</argument>
</arguments>
</method>
<method id="ResetStopWatch">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>allow</operation>
<types>
<type id="AttributeStopWatch"/>
</types>
</type_restrictions>
</argument>
</arguments>
</method>
<method id="Copy">
<arguments>
<argument id="1">
<type>attcode</type>
<mandatory>true</mandatory>
<type_restrictions>
<operation>deny</operation>
<types>
<type id="AttributeStopWatch"/>
<type id="AttributeSubItem"/>
<type id="AttributeExternalField"/>
</types>
</type_restrictions>
</argument>
<argument id="2">
<type>attcode</type>
<mandatory>true</mandatory>
</argument>
</arguments>
</method>
<method id="ApplyStimulus">
<arguments>
<argument id="1">
<type>string</type>
<mandatory>true</mandatory>
</argument>
</arguments>
</method>
<method id="PrefillCreationForm">
<arguments>
<argument id="1">
<type>reference</type>
<mandatory>true</mandatory>
</argument>
</arguments>
</method>
<method id="PrefillTransitionForm">
<arguments>
<argument id="1">
<type>reference</type>
<mandatory>true</mandatory>
</argument>
</arguments>
</method>
<method id="PrefillSearchForm">
<arguments>
<argument id="1">
<type>reference</type>
<mandatory>true</mandatory>
</argument>
</arguments>
</method>
</methods>
</class>
</classes>
</meta>
</itop_design>

View File

@@ -1,9 +1,6 @@
<?php
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
/**
* Copyright (C) 2013-2021 Combodo SARL
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
@@ -18,8 +15,6 @@ use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
* GNU Affero General Public License for more details.
*
* 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
*/
class DataTable
@@ -30,7 +25,7 @@ class DataTable
protected $sTableId; // identifier for saving the settings (combined with the class aliases)
protected $oSet; // The set of objects to display
protected $aClassAliases; // The aliases (alias => class) inside the set
protected $iNbObjects; // Total number of objects in the set
protected $iNbObjects; // Total number of objects inthe set
protected $bUseCustomSettings; // Whether or not the current display uses custom settings
protected $oDefaultSettings; // the default settings for displaying such a list
protected $bShowObsoleteData;
@@ -162,17 +157,17 @@ class DataTable
$sPager = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
$sActionsMenu = '';
$sToolkitMenu = '';
if ($bActionsMenu) {
if ($bActionsMenu)
{
$sActionsMenu = $this->GetActionsMenu($oPage, $aExtraParams);
}
// if ($bToolkitMenu)
// {
// $sToolkitMenu = $this->GetToolkitMenu($oPage, $aExtraParams);
// }
if ($bToolkitMenu)
{
$sToolkitMenu = $this->GetToolkitMenu($oPage, $aExtraParams);
}
$sDataTable = $this->GetHTMLTable($oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
$sConfigDlg = $this->GetTableConfigDlg($oPage, $aColumns, $bViewLink, $iDefaultPageSize);
$sHtml = "<table id=\"{$this->sDatatableContainerId}\" class=\"datatable\">";
$sHtml .= "<tr><td>";
$sHtml .= "<table style=\"width:100%;\">";
@@ -213,7 +208,7 @@ class DataTable
return $sHtml;
}
/**
* When refreshing the body of a paginated table, get the rows of the table (inside the TBODY)
* return string The HTML rows to insert inside the <tbody> node
@@ -352,26 +347,17 @@ EOF;
* @param $aExtraParams
*
* @return string
* @throws \ApplicationException
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DictExceptionMissingString
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
* @throws \ReflectionException
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
*/
protected function GetActionsMenu(WebPage $oPage, $aExtraParams)
{
$oMenuBlock = new MenuBlock($this->oSet->GetFilter(), 'list');
$oBlock = $oMenuBlock->GetRenderContent($oPage, $aExtraParams, $this->iListId);
return ConsoleBlockRenderer::RenderBlockTemplateInPage($oPage, $oBlock);
$sHtml = $oMenuBlock->GetRenderContent($oPage, $aExtraParams, $this->iListId);
return $sHtml;
}
/**
@@ -527,7 +513,6 @@ EOF;
return $aAttribs;
}
/**
* @param $aColumns
* @param $sSelectMode
@@ -875,3 +860,396 @@ class PrintableDataTable extends DataTable
return $sHtml;
}
}
class DataTableSettings implements Serializable
{
public $aClassAliases;
public $sTableId;
public $iDefaultPageSize;
public $aColumns;
/**
* DataTableSettings constructor.
*
* @param $aClassAliases
* @param null $sTableId
*/
public function __construct($aClassAliases, $sTableId = null)
{
$this->aClassAliases = $aClassAliases;
$this->sTableId = $sTableId;
$this->iDefaultPageSize = 10;
$this->aColumns = array();
}
/**
* @param $iDefaultPageSize
* @param $aSortOrder
* @param $aColumns
*/
protected function Init($iDefaultPageSize, $aSortOrder, $aColumns)
{
$this->iDefaultPageSize = $iDefaultPageSize;
$this->aColumns = $aColumns;
$this->FixVisibleColumns();
}
/**
* @return string
*/
public function serialize()
{
// Save only the 'visible' columns
$aColumns = array();
foreach($this->aClassAliases as $sAlias => $sClass)
{
$aColumns[$sAlias] = array();
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
{
unset($aData['label']); // Don't save the display name
unset($aData['alias']); // Don't save the alias (redundant)
unset($aData['code']); // Don't save the code (redundant)
if ($aData['checked'])
{
$aColumns[$sAlias][$sAttCode] = $aData;
}
}
}
return serialize(
array(
'iDefaultPageSize' => $this->iDefaultPageSize,
'aColumns' => $aColumns,
)
);
}
/**
* @param string $sData
*
* @throws \Exception
*/
public function unserialize($sData)
{
$aData = unserialize($sData);
$this->iDefaultPageSize = $aData['iDefaultPageSize'];
$this->aColumns = $aData['aColumns'];
foreach($this->aClassAliases as $sAlias => $sClass)
{
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
{
$aFieldData = false;
if ($sAttCode == '_key_')
{
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, null, true /* bChecked */, $aData['sort']);
}
else if (MetaModel::isValidAttCode($sClass, $sAttCode))
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, true /* bChecked */, $aData['sort']);
}
if ($aFieldData)
{
$this->aColumns[$sAlias][$sAttCode] = $aFieldData;
}
else
{
unset($this->aColumns[$sAlias][$sAttCode]);
}
}
}
$this->FixVisibleColumns();
}
/**
* @param $aClassAliases
* @param $bViewLink
* @param $aDefaultLists
*
* @return \DataTableSettings
* @throws \CoreException
* @throws \DictExceptionMissingString
*/
static public function GetDataModelSettings($aClassAliases, $bViewLink, $aDefaultLists)
{
$oSettings = new DataTableSettings($aClassAliases);
// Retrieve the class specific settings for each class/alias based on the 'list' ZList
//TODO let the caller pass some other default settings (another Zlist, extre fields...)
$aColumns = array();
foreach($aClassAliases as $sAlias => $sClass)
{
if ($aDefaultLists == null)
{
$aList = cmdbAbstract::FlattenZList(MetaModel::GetZListItems($sClass, 'list'));
}
else
{
$aList = $aDefaultLists[$sAlias];
}
$aSortOrder = MetaModel::GetOrderByDefault($sClass);
if ($bViewLink)
{
$sSort = 'none';
if(array_key_exists('friendlyname', $aSortOrder))
{
$sSort = $aSortOrder['friendlyname'] ? 'asc' : 'desc';
}
$sNormalizedFName = MetaModel::NormalizeFieldSpec($sClass, 'friendlyname');
if(array_key_exists($sNormalizedFName, $aSortOrder))
{
$sSort = $aSortOrder[$sNormalizedFName] ? 'asc' : 'desc';
}
$aColumns[$sAlias]['_key_'] = $oSettings->GetFieldData($sAlias, '_key_', null, true /* bChecked */, $sSort);
}
foreach($aList as $sAttCode)
{
$sSort = 'none';
if(array_key_exists($sAttCode, $aSortOrder))
{
$sSort = $aSortOrder[$sAttCode] ? 'asc' : 'desc';
}
$oAttDef = Metamodel::GetAttributeDef($sClass, $sAttCode);
$aFieldData = $oSettings->GetFieldData($sAlias, $sAttCode, $oAttDef, true /* bChecked */, $sSort);
if ($aFieldData) $aColumns[$sAlias][$sAttCode] = $aFieldData;
}
}
$iDefaultPageSize = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit());
$oSettings->Init($iDefaultPageSize, $aSortOrder, $aColumns);
return $oSettings;
}
/**
* @throws \CoreException
*/
protected function FixVisibleColumns()
{
foreach($this->aClassAliases as $sAlias => $sClass)
{
if (!isset($this->aColumns[$sAlias]))
{
continue;
}
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
{
// Remove non-existent columns
// TODO: check if the existing ones are still valid (in case their type changed)
if (($sAttCode != '_key_') && (!MetaModel::IsValidAttCode($sClass, $sAttCode)))
{
unset($this->aColumns[$sAlias][$sAttCode]);
}
}
$aList = MetaModel::ListAttributeDefs($sClass);
// Add the other (non visible ones), sorted in alphabetical order
$aTempData = array();
foreach($aList as $sAttCode => $oAttDef)
{
if ( (!array_key_exists($sAttCode, $this->aColumns[$sAlias])) && (!($oAttDef instanceof AttributeLinkedSet || $oAttDef instanceof AttributeDashboard)))
{
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, false /* bChecked */, 'none');
if ($aFieldData) $aTempData[$aFieldData['label']] = $aFieldData;
}
}
ksort($aTempData);
foreach($aTempData as $sLabel => $aFieldData)
{
$this->aColumns[$sAlias][$aFieldData['code']] = $aFieldData;
}
}
}
/**
* @param $aClassAliases
* @param null $sTableId
* @param bool $bOnlyOnTable
*
* @return \DataTableSettings|null
* @throws \Exception
*/
static public function GetTableSettings($aClassAliases, $sTableId = null, $bOnlyOnTable = false)
{
$pref = null;
$oSettings = new DataTableSettings($aClassAliases, $sTableId);
if ($sTableId != null)
{
// An identified table, let's fetch its own settings (if any)
$pref = appUserPreferences::GetPref($oSettings->GetPrefsKey($sTableId), null);
}
if ($pref == null)
{
if (!$bOnlyOnTable)
{
// Try the global preferred values for this class / set of classes
$pref = appUserPreferences::GetPref($oSettings->GetPrefsKey(null), null);
}
if ($pref == null)
{
// no such settings, use the default values provided by the data model
return null;
}
}
$oSettings->unserialize($pref);
return $oSettings;
}
/**
* @return array
*/
public function GetSortOrder()
{
$aSortOrder = array();
foreach($this->aColumns as $sAlias => $aColumns)
{
foreach($aColumns as $aColumn)
{
if ($aColumn['sort'] != 'none')
{
$sCode = ($aColumn['code'] == '_key_') ? 'friendlyname' : $aColumn['code'];
$aSortOrder[$sCode] = ($aColumn['sort']=='asc'); // true for ascending, false for descending
}
}
break; // TODO: For now the Set object supports only sorting on the first class of the set
}
return $aSortOrder;
}
/**
* @param null $sTargetTableId
*
* @return bool
*/
public function Save($sTargetTableId = null)
{
$sSaveId = is_null($sTargetTableId) ? $this->sTableId : $sTargetTableId;
if ($sSaveId == null) return false; // Cannot save, the table is not identified, use SaveAsDefault instead
$sSettings = $this->serialize();
appUserPreferences::SetPref($this->GetPrefsKey($sSaveId), $sSettings);
return true;
}
/**
* @return bool
*/
public function SaveAsDefault()
{
$sSettings = $this->serialize();
appUserPreferences::SetPref($this->GetPrefsKey(null), $sSettings);
return true;
}
/**
* Clear the preferences for this particular table
* @param $bResetAll boolean If true,the settings for all tables of the same class(es)/alias(es) are reset
*/
public function ResetToDefault($bResetAll)
{
if (($this->sTableId == null) && (!$bResetAll)) return false; // Cannot reset, the table is not identified, use force $bResetAll instead
if ($bResetAll)
{
// Turn the key into a suitable PCRE pattern
$sKey = $this->GetPrefsKey(null);
$sPattern = str_replace(array('|'), array('\\|'), $sKey); // escape the | character
$sPattern = '#^'.str_replace(array('*'), array('.*'), $sPattern).'$#'; // Don't use slash as the delimiter since it's used in our key to delimit aliases
appUserPreferences::UnsetPref($sPattern, true);
}
else
{
appUserPreferences::UnsetPref($this->GetPrefsKey($this->sTableId), false);
}
return true;
}
/**
* @param null $sTableId
*
* @return string
*/
protected function GetPrefsKey($sTableId = null)
{
return static::GetAppUserPreferenceKey($this->aClassAliases, $sTableId);
}
public static function GetAppUserPreferenceKey($aClassAliases, $sTableId)
{
if ($sTableId === null)
{
$sTableId = '*';
}
$aKeys = array();
foreach($aClassAliases as $sAlias => $sClass)
{
$aKeys[] = $sAlias.'-'.$sClass;
}
return implode('/', $aKeys).'|'.$sTableId;
}
/**
* @param $sAlias
* @param $sAttCode
* @param $oAttDef
* @param $bChecked
* @param $sSort
*
* @return array|bool
* @throws \CoreException
* @throws \DictExceptionMissingString
*/
protected function GetFieldData($sAlias, $sAttCode, $oAttDef, $bChecked, $sSort)
{
$ret = false;
if ($sAttCode == '_key_')
{
$sLabel = Dict::Format('UI:ExtKey_AsLink', MetaModel::GetName($this->aClassAliases[$sAlias]));
$ret = array(
'label' => $sLabel,
'checked' => true,
'disabled' => true,
'alias' => $sAlias,
'code' => $sAttCode,
'sort' => $sSort,
);
}
else if (!$oAttDef->IsLinkSet())
{
$sLabel = $oAttDef->GetLabel();
if ($oAttDef->IsExternalKey())
{
$sLabel = Dict::Format('UI:ExtKey_AsLink', $oAttDef->GetLabel());
}
else if ($oAttDef->IsExternalField())
{
if ($oAttDef->IsFriendlyName())
{
$sLabel = Dict::Format('UI:ExtKey_AsFriendlyName', $oAttDef->GetLabel());
}
else
{
$oExtAttDef = $oAttDef->GetExtAttDef();
$sLabel = Dict::Format('UI:ExtField_AsRemoteField', $oAttDef->GetLabel(), $oExtAttDef->GetLabel());
}
}
elseif ($oAttDef instanceof AttributeFriendlyName)
{
$sLabel = Dict::Format('UI:ExtKey_AsFriendlyName', $oAttDef->GetLabel());
}
$ret = array(
'label' => $sLabel,
'checked' => $bChecked,
'disabled' => false,
'alias' => $sAlias,
'code' => $sAttCode,
'sort' => $sSort,
);
}
return $ret;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,82 @@
<?php
/**
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/ErrorPage.php
* @copyright Copyright (C) 2010-2020 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2021 Combodo SARL
*/
class ErrorPage extends NiceWebPage
{
public function __construct($sTitle)
{
parent::__construct($sTitle);
$this->add_linked_script("../js/jquery.blockUI.js");
$this->add_linked_script("../setup/setup.js");
$this->add_saas("css/setup.scss");
}
public function info($sText)
{
$this->add("<p class=\"info\">$sText</p>\n");
$this->log_info($sText);
}
public function ok($sText)
{
$this->add("<div class=\"message message-valid\"><span class=\"message-title\">Success:</span>$sText</div>");
$this->log_ok($sText);
}
public function warning($sText)
{
$this->add("<div class=\"message message-warning\"><span class=\"message-title\">Warning:</span>$sText</div>");
$this->log_warning($sText);
}
public function error($sText)
{
$this->add("<div class=\"message message-error\">$sText</div>");
$this->log_error($sText);
}
public function output()
{
$sLogo = utils::GetAbsoluteUrlAppRoot().'/images/itop-logo.png';
$sTimeStamp = utils::GetCacheBusterTimestamp();
$sTitle = utils::HtmlEntities($this->s_title);
$this->s_content = <<<HTML
<div id="header" class="error_page">
<h1><a href="http://www.combodo.com/itop" target="_blank"><img title="iTop by Combodo" alt=" " src="{$sLogo}?t={$sTimeStamp}"></a>&nbsp;{$sTitle}</h1>
</div>
<div id="setup" class="error_page">
{$this->s_content}
</div>
HTML;
return parent::output();
}
public static function log_error($sText)
{
IssueLog::Error($sText);
}
public static function log_warning($sText)
{
IssueLog::Warning($sText);
}
public static function log_info($sText)
{
IssueLog::Info($sText);
}
public static function log_ok($sText)
{
IssueLog::Ok($sText);
}
public static function log($sText)
{
IssueLog::Ok($sText);
}
}

View File

@@ -1,9 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class ApplicationException extends CoreException
{
}

View File

@@ -1,14 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Thrown when querying on an object that exists in the database but is archived
*
* @since 2.5.1 N°1108
*/
class ArchivedObjectException extends CoreException
{
}

View File

@@ -1,9 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class BulkChangeException extends CoreException
{
}

View File

@@ -1,9 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class CSVParserException extends CoreException
{
}

View File

@@ -1,9 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class ConfigException extends CoreException
{
}

View File

@@ -1,77 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Class CoreCannotSaveObjectException
*
* Specialized exception to raise if {@link DBObject::CheckToWrite()} fails, which allow easy data retrieval
*
* @see \DBObject::DBInsertNoReload()
* @see \DBObject::DBUpdate()
*
* @since 2.6.0 N°659 uniqueness constraint
*/
class CoreCannotSaveObjectException extends CoreException
{
/** @var string[] */
private $aIssues;
/** @var int */
private $iObjectId;
/** @var string */
private $sObjectClass;
/**
* CoreCannotSaveObjectException constructor.
*
* @param array $aContextData containing at least those keys : issues, id, class
*/
public function __construct($aContextData)
{
$this->aIssues = $aContextData['issues'];
$this->iObjectId = $aContextData['id'];
$this->sObjectClass = $aContextData['class'];
$sIssues = implode(', ', $this->aIssues);
parent::__construct($sIssues, $aContextData);
}
/**
* @return string
*/
public function getHtmlMessage()
{
$sTitle = Dict::S('UI:Error:SaveFailed');
$sContent = "<span><strong>{$sTitle}</strong></span>";
if (count($this->aIssues) == 1) {
$sIssue = reset($this->aIssues);
$sContent .= " <span>{$sIssue}</span>";
} else {
$sContent .= '<ul>';
foreach ($this->aIssues as $sError) {
$sContent .= "<li>$sError</li>";
}
$sContent .= '</ul>';
}
return $sContent;
}
public function getIssues()
{
return $this->aIssues;
}
public function getObjectId()
{
return $this->iObjectId;
}
public function getObjectClass()
{
return $this->sObjectClass;
}
}

View File

@@ -1,108 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class CoreException extends Exception
{
/**
* CoreException constructor.
*
* @param string $sIssue error message
* @param array|null $aContextData key/value array, value MUST implements _toString
* @param string $sImpact
* @param Exception|null $oPrevious
*/
public function __construct($sIssue, $aContextData = null, $sImpact = '', $oPrevious = null)
{
$this->m_sIssue = $sIssue;
$this->m_sImpact = $sImpact;
if (is_array($aContextData)) {
$this->m_aContextData = $aContextData;
} else {
$this->m_aContextData = [];
}
$sMessage = $sIssue;
if (!empty($sImpact)) {
$sMessage .= "($sImpact)";
}
if (count($this->m_aContextData) > 0) {
$sMessage .= ": ";
$aContextItems = array();
foreach ($this->m_aContextData as $sKey => $value) {
if (is_array($value)) {
$aPairs = array();
foreach ($value as $key => $val) {
if (is_array($val)) {
$aPairs[] = $key.'=>('.implode(', ', $val).')';
} else {
$aPairs[] = $key.'=>'.$val;
}
}
$sValue = '{'.implode('; ', $aPairs).'}';
} else {
$sValue = $value;
}
$aContextItems[] = "$sKey = $sValue";
}
$sMessage .= implode(', ', $aContextItems);
}
parent::__construct($sMessage, 0, $oPrevious);
}
/**
* @return string code and message for log purposes
*/
public function getInfoLog()
{
return 'error_code='.$this->getCode().', message="'.$this->getMessage().'"';
}
public function getHtmlDesc($sHighlightHtmlBegin = '<b>', $sHighlightHtmlEnd = '</b>')
{
return $this->getMessage();
}
/**
* getTraceAsString() cannot be overrided and it is limited as only current exception stack is returned.
* we need stack of all previous exceptions
*
* @uses __tostring() already does the work.
* @since 2.7.2/ 3.0.0
*/
public function getFullStackTraceAsString()
{
return "".$this;
}
public function getTraceAsHtml()
{
$aBackTrace = $this->getTrace();
return MyHelpers::get_callstack_html(0, $this->getTrace());
// return "<pre>\n".$this->getTraceAsString()."</pre>\n";
}
public function addInfo($sKey, $value)
{
$this->m_aContextData[$sKey] = $value;
}
public function getIssue()
{
return $this->m_sIssue;
}
public function getImpact()
{
return $this->m_sImpact;
}
public function getContextData()
{
return $this->m_aContextData;
}
}

View File

@@ -1,13 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* @since 2.7.0 N°2555
*/
class CorePortalInvalidActionRuleException extends CoreException
{
}

View File

@@ -1,17 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* @since 3.0.0 N°3522
*/
class CoreTemplateException extends CoreException
{
public function __construct(Exception $oTwigException, string $sTemplatePath)
{
$sMessage = "Twig Exception when rendering '$sTemplatePath' : ".$oTwigException->getMessage();
parent::__construct($sMessage, null, '', $oTwigException);
}
}

View File

@@ -1,9 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class CoreUnexpectedValue extends CoreException
{
}

View File

@@ -1,9 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class CoreWarning extends CoreException
{
}

View File

@@ -1,9 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class DeleteException extends CoreException
{
}

View File

@@ -1,14 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* A parameter stored in the {@link Config} is invalid
*
* @since 2.7.0
*/
class InvalidConfigParamException extends CoreException
{
}

View File

@@ -1,14 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Thrown when the password is not valid
*
* @since 2.7.0
*/
class InvalidPasswordAttributeOneWayPassword extends CoreException
{
}

View File

@@ -1,13 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Application\TwigBase\Controller;
use Exception;
class PageNotFoundException extends Exception
{
}

View File

@@ -1,9 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class SecurityException extends CoreException
{
}

View File

@@ -1,9 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class SynchroExceptionNotStarted extends CoreException
{
}

View File

@@ -1,9 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class UserRightException extends CoreException
{
}

View File

@@ -1,9 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class DictException extends CoreException
{
}

View File

@@ -1,16 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class DictExceptionMissingString extends DictException
{
public function __construct($sLanguageCode, $sStringCode)
{
$aContext = array();
$aContext['language_code'] = $sLanguageCode;
$aContext['string_code'] = $sStringCode;
parent::__construct('Missing localized string', $aContext);
}
}

View File

@@ -1,15 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class DictExceptionUnknownLanguage extends DictException
{
public function __construct($sLanguageCode)
{
$aContext = array();
$aContext['language_code'] = $sLanguageCode;
parent::__construct('Unknown localization language', $aContext);
}
}

View File

@@ -1,34 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class MySQLException extends CoreException
{
/**
* MySQLException constructor.
*
* @param string $sIssue
* @param array $aContext
* @param \Exception $oException
* @param \mysqli $oMysqli to use when working with a custom mysqli instance
*/
public function __construct($sIssue, $aContext, $oException = null, $oMysqli = null)
{
if ($oException != null) {
$aContext['mysql_errno'] = $oException->getCode();
$this->code = $oException->getCode();
$aContext['mysql_error'] = $oException->getMessage();
} else if ($oMysqli != null) {
$aContext['mysql_errno'] = $oMysqli->errno;
$this->code = $oMysqli->errno;
$aContext['mysql_error'] = $oMysqli->error;
} else {
$aContext['mysql_errno'] = CMDBSource::GetErrNo();
$this->code = CMDBSource::GetErrNo();
$aContext['mysql_error'] = CMDBSource::GetError();
}
parent::__construct($sIssue, $aContext);
}
}

View File

@@ -1,32 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Class MySQLHasGoneAwayException
*
* @see https://dev.mysql.com/doc/refman/5.7/en/gone-away.html
* @since 2.5.0 N°1195
*/
class MySQLHasGoneAwayException extends MySQLException
{
/**
* can not be a constant before PHP 5.6 (http://php.net/manual/fr/language.oop5.constants.php)
*
* @return int[]
*/
public static function getErrorCodes()
{
return array(
2006,
2013,
);
}
public function __construct($sIssue, $aContext)
{
parent::__construct($sIssue, $aContext, null);
}
}

View File

@@ -1,13 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* @since 2.7.0 N°679
*/
class MySQLNoTransactionException extends MySQLException
{
}

View File

@@ -1,15 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Class MySQLQueryHasNoResultException
*
* @since 2.5.0
*/
class MySQLQueryHasNoResultException extends MySQLException
{
}

View File

@@ -1,13 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* @since 2.7.0 N°2555
*/
class CoreOqlException extends CoreException
{
}

View File

@@ -1,13 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* @since 2.7.0 N°2555
*/
class CoreOqlMultipleResultsForbiddenException extends CoreOqlException
{
}

View File

@@ -1,15 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Exception for {@link iProcess} implementations.<br>
* An error happened during the processing but we can go on with the next implementations.
*
* @since 2.5.0 N°1195
*/
class ProcessException extends CoreException
{
}

View File

@@ -1,16 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Class ProcessFatalException
* Exception for iProcess implementations.<br>
* A big error occurred, we have to stop the iProcess processing.
*
* @since 2.5.0 N°1195
*/
class ProcessFatalException extends CoreException
{
}

View File

@@ -1,12 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* @since 2.7.0 PR #89
*/
class ProcessInvalidConfigException extends ProcessException
{
}

View File

@@ -1,114 +0,0 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
/**
* Class FindStylesheetObject: dedicated class to store computations made in method ThemeHandler::FindStylesheetFile.
* @author Olivier DAIN <olivier.dain@combodo.com>
* @since 3.0.0 N°3588
*/
class FindStylesheetObject{
//file URIs
private $aStylesheetFileURIs;
//fill paths
private $aStylesheetImportPaths;
private $aAllStylesheetFilePaths;
private $sLastStyleSheetPath;
private $iLastModified;
/**
* FindStylesheetObject constructor.
*/
public function __construct()
{
$this->aStylesheetFileURIs = [];
$this->aStylesheetImportPaths = [];
$this->aAllStylesheetFilePaths = [];
$this->sLastStyleSheetPath = "";
$this->iLastModified = 0;
}
public function GetLastStylesheetFile(): string
{
return $this->sLastStyleSheetPath;
}
public function GetImportPaths(): array
{
return $this->aStylesheetImportPaths;
}
/**
* @return array : main stylesheets URIs
*/
public function GetStylesheetFileURIs(): array
{
return $this->aStylesheetFileURIs;
}
public function GetLastModified() : int
{
return $this->iLastModified;
}
/**
* @return array : main stylesheets paths + included files paths
*/
public function GetAllStylesheetPaths(): array
{
return $this->aAllStylesheetFilePaths;
}
/**
* @return string : last found stylesheet URI
*/
public function GetLastStyleSheetPath(): string
{
return $this->sLastStyleSheetPath;
}
public function AddStylesheet(string $sStylesheetFileURI, string $sStylesheetFilePath): void
{
$this->aStylesheetFileURIs[] = $sStylesheetFileURI;
$this->aAllStylesheetFilePaths[] = $sStylesheetFilePath;
$this->sLastStyleSheetPath = $sStylesheetFilePath;
}
public function AlreadyFetched(string $sStylesheetFilePath) : bool {
return in_array($sStylesheetFilePath, $this->aAllStylesheetFilePaths);
}
public function AddImport(string $sStylesheetFileURI, string $sStylesheetFilePath): void
{
$this->aStylesheetImportPaths[$sStylesheetFileURI] = $sStylesheetFilePath;
$this->aAllStylesheetFilePaths[] = $sStylesheetFilePath;
}
public function UpdateLastModified(string $sStylesheetFile): void
{
$this->iLastModified = max($this->iLastModified, @filemtime($sStylesheetFile));
}
public function ResetLastStyleSheet(): void
{
$this->sLastStyleSheetPath = "";
}
}

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -20,7 +20,7 @@
* Helper class to build interactive forms to be used either in stand-alone
* modal dialog or in "property-sheet" panes.
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class DesignerForm
@@ -102,19 +102,23 @@ class DesignerForm
$sReturn .= '<fieldset>';
$sReturn .= '<legend>'.$sLabel.'</legend>';
}
foreach($aFields as $oField) {
foreach($aFields as $oField)
{
$aRow = $oField->Render($oP, $sFormId);
if ($oField->IsVisible()) {
$sValidation = '<span class="prop_apply ibo-prop--apply">'.$this->GetValidationArea($oField->GetFieldId()).'</span>';
if ($oField->IsVisible())
{
$sValidation = '&nbsp;<span class="prop_apply">'.$this->GetValidationArea($oField->GetFieldId()).'</span>';
$sField = $aRow['value'].$sValidation;
$aDetails[] = array('label' => $aRow['label'], 'value' => $sField);
} else {
}
else
{
$sHiddenFields .= $aRow['value'];
}
}
$sReturn .= $oP->GetDetails($aDetails);
if ($sLabel != '') {
if ($sLabel != '')
{
$sReturn .= '</fieldset>';
}
}
@@ -226,18 +230,18 @@ class DesignerForm
if ($oField->IsVisible())
{
$sFieldId = $this->GetFieldId($oField->GetCode());
$sValidation = $this->GetValidationArea($sFieldId, '<span data-tooltip-content="Apply"><i class="fas fa-check"></i></span>');
$sValidationFields = '</td><td class="prop_icon prop_apply ibo-prop--apply">'.$sValidation.'</td><td class="prop_icon prop_cancel ibo-prop--cancel"><span data-tooltip-content="Revert"><i class="fas fa-times"></i></span></td>'.$this->EndRow();
$sValidation = $this->GetValidationArea($sFieldId, '<span title="Apply" class="ui-icon ui-icon-circle-check"/>');
$sValidationFields = '</td><td class="prop_icon prop_apply">'.$sValidation.'</td><td class="prop_icon prop_cancel"><span title="Revert" class="ui-icon ui-icon-circle-close"/></td>'.$this->EndRow();
$sPath = $this->GetHierarchyPath().'/'.$oField->GetCode();
if (is_null($aRow['label']))
{
$sReturn .= $this->StartRow($sFieldId).'<td class="prop_value ibo-field--value" colspan="2">'.$aRow['value'];
$sReturn .= $this->StartRow($sFieldId).'<td class="prop_value" colspan="2">'.$aRow['value'];
}
else
{
$sReturn .= $this->StartRow($sFieldId).'<td class="prop_label ibo-field--label">'.$aRow['label'].'</td><td class="prop_value ibo-field--value">'.$aRow['value'];
$sReturn .= $this->StartRow($sFieldId).'<td class="prop_label">'.$aRow['label'].'</td><td class="prop_value">'.$aRow['value'];
}
if (!($oField instanceof DesignerFormSelectorField) && !($oField instanceof DesignerMultipleSubFormField))
{
@@ -262,7 +266,6 @@ class DesignerForm
$this->AddReadyScript(
<<<EOF
$('#row_$sFieldId').$sWidgetClass({parent_selector: $sNotifyParentSelectorJS, field_id: '$sFieldId', equals: $sHandlerEquals, get_field_value: $sHandlerGetValue, auto_apply: $sAutoApply, value: '', submit_to: '$sActionUrl', submit_parameters: $sJSSubmitParams $sJSExtraParams });
CombodoTooltip.InitTooltipFromMarkup($('#$sFormId [data-tooltip-content]'));
EOF
);
}
@@ -288,6 +291,7 @@ EOF
}
$this->AddReadyScript(
<<<EOF
$('.prop_table').tableHover();
var idx = 0;
$('.prop_table tbody tr').each(function() {
if ((idx % 2) == 0)
@@ -544,7 +548,7 @@ EOF
public function GetValidationArea($sId, $sContent = '')
{
return "<span id=\"v_{$sId}\">$sContent</span>";
return "<span style=\"display:inline-block;width:20px;\" id=\"v_{$sId}\"><span class=\"ui-icon ui-icon-alert\"></span>$sContent</span>";
}
public function GetAsyncActionClass()
{
@@ -712,7 +716,7 @@ class DesignerFormField
$this->bMandatory = false;
$this->bReadOnly = false;
$this->bAutoApply = false;
$this->aCSSClasses = array('ibo-input');
$this->aCSSClasses = array();
$this->bDisplayed = true;
$this->aWidgetExtraParams = array();
}
@@ -1016,10 +1020,10 @@ class DesignerTextField extends DesignerFormField
$sMandatory = $this->bMandatory ? 'true' : 'false';
$oP->add_ready_script(
<<<EOF
$('#$sId').on('change keyup validate', function() { ValidateWithPattern('$sId', $sMandatory, '$sPattern', $(this).closest('form').attr('id'), $sForbiddenValues); } );
$('#$sId').bind('change keyup validate', function() { ValidateWithPattern('$sId', $sMandatory, '$sPattern', $(this).closest('form').attr('id'), $sForbiddenValues); } );
{
var myTimer = null;
$('#$sId').on('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
$('#$sId').bind('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
}
EOF
);
@@ -1051,12 +1055,6 @@ EOF
class DesignerLongTextField extends DesignerTextField
{
public function __construct($sCode, $sLabel = '', $defaultValue = '')
{
parent::__construct($sCode, $sLabel, $defaultValue);
$this->aCSSClasses[] = 'ibo-input-text';
}
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
{
$sId = $this->oForm->GetFieldId($this->sCode);
@@ -1080,10 +1078,10 @@ class DesignerLongTextField extends DesignerTextField
{
$oP->add_ready_script(
<<<EOF
$('#$sId').on('change keyup validate', function() { ValidateWithPattern('$sId', $sMandatory, '$sPattern', $(this).closest('form').attr('id'), $sForbiddenValues); } );
$('#$sId').bind('change keyup validate', function() { ValidateWithPattern('$sId', $sMandatory, '$sPattern', $(this).closest('form').attr('id'), $sForbiddenValues); } );
{
var myTimer = null;
$('#$sId').on('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
$('#$sId').bind('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
}
EOF
);
@@ -1131,10 +1129,10 @@ class DesignerIntegerField extends DesignerFormField
$sMandatory = $this->bMandatory ? 'true' : 'false';
$oP->add_ready_script(
<<<EOF
$('#$sId').on('change keyup validate', function() { ValidateInteger('$sId', $sMandatory, $(this).closest('form').attr('id'), $sMin, $sMax); } );
$('#$sId').bind('change keyup validate', function() { ValidateInteger('$sId', $sMandatory, $(this).closest('form').attr('id'), $sMin, $sMax); } );
{
var myTimer = null;
$('#$sId').on('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
$('#$sId').bind('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
}
EOF
);
@@ -1180,7 +1178,6 @@ class DesignerComboField extends DesignerFormField
$this->bMultipleSelection = false;
$this->bOtherChoices = false;
$this->sNullLabel = Dict::S('UI:SelectOne');
$this->aCSSClasses[] = 'ibo-input-select';
$this->bAutoApply = true;
$this->bSorted = true; // Sorted by default
@@ -1295,12 +1292,11 @@ class DesignerComboField extends DesignerFormField
}
$oP->add_ready_script(
<<<EOF
$('#$sId').on('change validate', function() { ValidateWithPattern('$sId', $sMandatory, '', $(this).closest('form').attr('id'), null, null); } );
$('#$sId').bind('change validate', function() { ValidateWithPattern('$sId', $sMandatory, '', $(this).closest('form').attr('id'), null, null); } );
EOF
);
}
return array('label' => $this->sLabel, 'value' => $sHtml);
}
public function ReadParam(&$aValues)
@@ -1319,7 +1315,6 @@ class DesignerBooleanField extends DesignerFormField
{
parent::__construct($sCode, $sLabel, $defaultValue);
$this->bAutoApply = true;
$this->aCSSClasses[] = 'ibo-input-checkbox';
}
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
@@ -1602,7 +1597,6 @@ class DesignerFormSelectorField extends DesignerFormField
$this->defaultRealValue = $defaultValue;
$this->aSubForms = array();
$this->bSorted = true;
$this->aCSSClasses[] = 'ibo-input-select';
}
public function IsSorted()
@@ -1736,7 +1730,7 @@ class DesignerFormSelectorField extends DesignerFormField
{
$oP->add_ready_script(
<<<EOF
$('#$sId').on('change reverted', function() { $('.subform_{$sId}').hide(); $('.{$sId}_'+this.value).show(); } );
$('#$sId').bind('change reverted', function() { $('.subform_{$sId}').hide(); $('.{$sId}_'+this.value).show(); } );
EOF
);
}

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -20,7 +20,7 @@
/**
* Persistent class InputOutputTask
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -44,6 +44,7 @@ class InputOutputTask extends cmdbAbstractObject
"db_table" => "priv_iotask",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,57 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/iTopWizardWebPage.php
* Class iTopWizardWebPage
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2021 Combodo SARL
*/
require_once('itopwebpage.class.inc.php');
/**
* Web page to display a wizard in the iTop framework
*/
class iTopWizardWebPage extends iTopWebPage
{
var $m_iCurrentStep;
var $m_aSteps;
public function __construct($sTitle, $currentOrganization, $iCurrentStep, $aSteps)
{
parent::__construct($sTitle." - step $iCurrentStep of ".count($aSteps)." - ".$aSteps[$iCurrentStep - 1], $currentOrganization);
$this->m_iCurrentStep = $iCurrentStep;
$this->m_aSteps = $aSteps;
}
public function output()
{
$aSteps = array();
$iIndex = 0;
foreach($this->m_aSteps as $sStepTitle)
{
$iIndex++;
$sStyle = ($iIndex == $this->m_iCurrentStep) ? 'wizActiveStep' : 'wizStep';
$aSteps[] = "<div class=\"$sStyle\"><span>$sStepTitle</span></div>";
}
$sWizardHeader = "<div class=\"wizHeader\"><h1>".htmlentities($this->s_title, ENT_QUOTES, 'UTF-8')."</h1>\n".implode("<div class=\"wizSeparator\"><img align=\"bottom\" src=\"../images/wizArrow.gif\"></div>", $aSteps)."<br style=\"clear:both;\"/></div>\n";
$this->s_content = "$sWizardHeader<div class=\"wizContainer\">".$this->s_content."</div>";
parent::output();
}
}
?>

View File

@@ -2,7 +2,7 @@
/**
* Class LoginBasic
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -1,6 +1,6 @@
<?php
/**
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -3,7 +3,7 @@
/**
* Class LoginExternal
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -1,7 +1,7 @@
<?php
/**
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -2,7 +2,7 @@
/**
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -224,7 +224,7 @@ class LoginTwigRenderer
}
$oCoreLoader = new Twig_Loader_Filesystem(array(), APPROOT.'templates');
$aCoreTemplatesPaths = array('pages/login', 'pages/login/password');
$aCoreTemplatesPaths = array('login', 'login/password');
// Having this path declared after the plugins let the plugins replace the core templates
$oCoreLoader->setPaths($aCoreTemplatesPaths);
// Having the core templates accessible within a different namespace offer the possibility to extend them while replacing them

View File

@@ -3,7 +3,7 @@
/**
* Class LoginURL
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2017 Combodo SARL
//
// This file is part of iTop.
//
@@ -20,7 +20,7 @@
/**
* Class LoginWebPage
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -92,6 +92,7 @@ class LoginWebPage extends NiceWebPage
{
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/login.css');
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/all.min.css');
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/v4-shims.min.css');
}
public static function SetLoginFailedMessage($sMessage)
@@ -99,44 +100,6 @@ class LoginWebPage extends NiceWebPage
self::$m_sLoginFailedMessage = $sMessage;
}
/**
* @param $oUser
* @param array $aProfiles
*
* @return array
* @throws \CoreException
* @throws \CoreUnexpectedValue
*/
public static function SynchronizeProfiles(&$oUser, array $aProfiles, $sOrigin)
{
$oProfilesSet = $oUser->Get(profile_list);
//delete old profiles
$aExistingProfiles = [];
while ($oProfile = $oProfilesSet->Fetch())
{
array_push($aExistingProfiles, $oProfile->Get('profileid'));
$iArrayKey = array_search($oProfile->Get('profileid'), $aProfiles);
if (!$iArrayKey)
{
$oProfilesSet->RemoveItem($oProfile->Get('profileid'));
}
else
{
unset($aProfiles[$iArrayKey]);
}
}
//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);
}
public function DisplayLoginHeader($bMainAppLogo = false)
{
$sLogo = 'itop-logo-external.png';
@@ -923,12 +886,20 @@ class LoginWebPage extends NiceWebPage
}
// Now synchronize the profiles
$oProfilesSet = DBObjectSet::FromScratch('URP_UserProfile');
$sOrigin = 'External User provisioning';
if (isset($_SESSION['login_mode']))
{
$sOrigin .= " ({$_SESSION['login_mode']})";
}
$aExistingProfiles = self::SynchronizeProfiles($oUser, $aProfiles, $sOrigin);
foreach ($aProfiles as $iProfileId)
{
$oLink = new URP_UserProfile();
$oLink->Set('profileid', $iProfileId);
$oLink->Set('reason', $sOrigin);
$oProfilesSet->AddObject($oLink);
}
$oUser->Set('profile_list', $oProfilesSet);
if ($oUser->IsModified())
{
$oUser->DBWrite();

View File

@@ -1,6 +1,6 @@
<?php
/**
* Copyright (C) 2013-2021 Combodo SARL
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*

View File

@@ -1,6 +1,6 @@
<?php
/**
* Copyright (C) 2013-2021 Combodo SARL
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
@@ -17,8 +17,6 @@
* You should have received a copy of the GNU Affero General Public License
*/
use Combodo\iTop\Application\UI\Base\Component\Title\TitleUIBlockFactory;
require_once(APPROOT.'/application/utils.inc.php');
require_once(APPROOT.'/application/template.class.inc.php');
require_once(APPROOT."/application/user.dashboard.class.inc.php");
@@ -53,10 +51,7 @@ require_once(APPROOT."/application/user.dashboard.class.inc.php");
* new OQLMenuNode('PersonsMenu', 'SELECT bizPerson', $oContactsMenu->GetIndex(), 0);
*
*/
/**
* Class ApplicationMenu
*/
class ApplicationMenu
{
/**
@@ -76,10 +71,7 @@ class ApplicationMenu
*/
static $sFavoriteSiloQuery = 'SELECT Organization';
/**
* @return void
*/
public static function LoadAdditionalMenus()
static public function LoadAdditionalMenus()
{
if (!self::$bAdditionalMenusLoaded)
{
@@ -105,10 +97,10 @@ class ApplicationMenu
/**
* Set the query used to limit the list of displayed organizations in the drop-down menu
* @param string $sOQL The OQL query returning a list of Organization objects
* @param $sOQL string The OQL query returning a list of Organization objects
* @return void
*/
public static function SetFavoriteSiloQuery($sOQL)
static public function SetFavoriteSiloQuery($sOQL)
{
self::$sFavoriteSiloQuery = $sOQL;
}
@@ -117,7 +109,7 @@ class ApplicationMenu
* Get the query used to limit the list of displayed organizations in the drop-down menu
* @return string The OQL query returning a list of Organization objects
*/
public static function GetFavoriteSiloQuery()
static public function GetFavoriteSiloQuery()
{
return self::$sFavoriteSiloQuery;
}
@@ -125,11 +117,11 @@ class ApplicationMenu
/**
* Check whether a menu Id is enabled or not
*
* @param string $sMenuId
* @param $sMenuId
*
* @throws \Exception
*/
public static function CheckMenuIdEnabled($sMenuId)
static public function CheckMenuIdEnabled($sMenuId)
{
self::LoadAdditionalMenus();
$oMenuNode = self::GetMenuNode(self::GetMenuIndexById($sMenuId));
@@ -148,11 +140,11 @@ class ApplicationMenu
* Main function to add a menu entry into the application, can be called during the definition
* of the data model objects
* @param MenuNode $oMenuNode
* @param int $iParentIndex
* @param float $fRank
* @param $iParentIndex
* @param $fRank
* @return int
*/
public static function InsertMenu(MenuNode $oMenuNode, $iParentIndex, $fRank)
static public function InsertMenu(MenuNode $oMenuNode, $iParentIndex, $fRank)
{
$index = self::GetMenuIndexById($oMenuNode->GetMenuId());
if ($index == -1)
@@ -193,154 +185,20 @@ class ApplicationMenu
/**
* Reflection API - Get menu entries
*
* @return array
*/
public static function ReflectionMenuNodes()
static public function ReflectionMenuNodes()
{
self::LoadAdditionalMenus();
return self::$aMenusIndex;
}
/**
* Get entries count for all the menus
*
* @param array $aExtraParams
*
* @return array
* @throws \DictExceptionMissingString
* @since 3.0.0
*/
public static function GetMenusCount($aExtraParams = array())
{
$aMenuGroups = static::GetMenuGroups($aExtraParams);
$aMenusCount = [];
foreach ($aMenuGroups as $aMenuGroup) {
$aSubMenuNodes = $aMenuGroup['aSubMenuNodes'];
$aMenusCount = array_merge($aMenusCount, static::GetSubMenusCount($aSubMenuNodes));
}
return $aMenusCount;
}
/**
* Recurse sub menus for counts
*
* @param array $aSubMenuNodes
*
* @return array
* @since 3.0.0
*/
private static function GetSubMenusCount(array $aSubMenuNodes)
{
$aSubMenusCount = [];
foreach ($aSubMenuNodes as $aSubMenuNode) {
if ($aSubMenuNode['bHasCount']) {
$oMenuNode = static::GetMenuNode(static::GetMenuIndexById($aSubMenuNode['sId']));
$aSubMenusCount[$aSubMenuNode['sId']] = $oMenuNode->GetEntriesCount();
}
$aSubMenusCount = array_merge($aSubMenusCount, static::GetSubMenusCount($aSubMenuNode['aSubMenuNodes']));
}
return $aSubMenusCount;
}
/**
* Return an array of menu groups
*
* @param array $aExtraParams
*
* @return array
* @throws \DictExceptionMissingString
* @since 3.0.0
*/
public static function GetMenuGroups($aExtraParams = array())
{
self::LoadAdditionalMenus();
// Sort the root menu based on the rank
usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank'));
$aMenuGroups = [];
foreach(static::$aRootMenus as $aMenuGroup)
{
if(!static::CanDisplayMenu($aMenuGroup))
{
continue;
}
$sMenuGroupIdx = $aMenuGroup['index'];
/** @var \MenuGroup $oMenuNode */
$oMenuNode = static::GetMenuNode($sMenuGroupIdx);
$aMenuGroups[] = [
'sId' => $oMenuNode->GetMenuID(),
'sIconCssClasses' => $oMenuNode->GetDecorationClasses(),
'sInitials' => $oMenuNode->GetInitials(),
'sTitle' => $oMenuNode->GetTitle(),
'aSubMenuNodes' => static::GetSubMenuNodes($sMenuGroupIdx, $aExtraParams),
];
}
return $aMenuGroups;
}
/**
* Return an array of sub-menu nodes for $sMenuGroupIdx
*
* @param string $sMenuGroupIdx
* @param array $aExtraParams
*
* @return array
* @throws \DictExceptionMissingString
* @throws \Exception
* @since 3.0.0
*/
public static function GetSubMenuNodes($sMenuGroupIdx, $aExtraParams = array())
{
$aSubMenuItems = self::GetChildren($sMenuGroupIdx);
// Sort the children based on the rank
usort($aSubMenuItems, array('ApplicationMenu', 'CompareOnRank'));
$aSubMenuNodes = [];
foreach($aSubMenuItems as $aSubMenuItem)
{
if(!static::CanDisplayMenu($aSubMenuItem))
{
continue;
}
$sSubMenuItemIdx = $aSubMenuItem['index'];
$oSubMenuNode = static::GetMenuNode($sSubMenuItemIdx);
if(!$oSubMenuNode->IsEnabled())
{
continue;
}
$aSubMenuNodes[] = [
'sId' => $oSubMenuNode->GetMenuId(),
'sTitle' => $oSubMenuNode->GetTitle(),
'bHasCount' => $oSubMenuNode->HasCount(),
'sUrl' => $oSubMenuNode->GetHyperlink($aExtraParams),
'bOpenInNewWindow' => $oSubMenuNode->IsHyperLinkInNewWindow(),
'aSubMenuNodes' => static::GetSubMenuNodes($sSubMenuItemIdx, $aExtraParams),
];
}
return $aSubMenuNodes;
}
/**
* Entry point to display the whole menu into the web page, used by iTopWebPage
* @param \WebPage $oPage
* @param array $aExtraParams
* @param $aExtraParams
* @throws DictExceptionMissingString
*
* @deprecated Will be removed in 3.0.0, use static::GetMenuGroups() instead
*/
public static function DisplayMenu($oPage, $aExtraParams)
static public function DisplayMenu($oPage, $aExtraParams)
{
self::LoadAdditionalMenus();
// Sort the root menu based on the rank
@@ -379,7 +237,7 @@ EOF
* @param array $aMenu menu entry
* @return bool true if at least one menu is enabled
*/
private static function CanDisplayMenu($aMenu)
static private function CanDisplayMenu($aMenu)
{
$oMenuNode = self::GetMenuNode($aMenu['index']);
if ($oMenuNode->IsEnabled())
@@ -411,12 +269,11 @@ EOF
* @param array $aExtraParams
* @param int $iActiveMenu
*
* @return bool True if the currently selected menu is one of the submenus
* @return true if the currently selected menu is one of the submenus
* @throws DictExceptionMissingString
* @throws \Exception
* @deprecated Will be removed in 3.0.0, use static::GetSubMenuNodes() instead
*/
protected static function DisplaySubMenu($oPage, $aMenus, $aExtraParams, $iActiveMenu = -1)
static protected function DisplaySubMenu($oPage, $aMenus, $aExtraParams, $iActiveMenu = -1)
{
// Sort the menu based on the rank
$bActive = false;
@@ -473,11 +330,11 @@ EOF
/**
* Helper function to sort the menus based on their rank
* @param array $a
* @param array $b
* @param $a
* @param $b
* @return int
*/
public static function CompareOnRank($a, $b)
static public function CompareOnRank($a, $b)
{
$result = 1;
if ($a['rank'] == $b['rank'])
@@ -496,7 +353,7 @@ EOF
* @param int $index
* @return MenuNode|null
*/
public static function GetMenuNode($index)
static public function GetMenuNode($index)
{
return isset(self::$aMenusIndex[$index]) ? self::$aMenusIndex[$index]['node'] : null;
}
@@ -506,7 +363,7 @@ EOF
* @param int $index
* @return array
*/
public static function GetChildren($index)
static public function GetChildren($index)
{
return self::$aMenusIndex[$index]['children'];
}
@@ -516,7 +373,7 @@ EOF
* @param string $sTitle Title of the menu (as passed when creating the menu)
* @return integer ID of the menu, or -1 if not found
*/
public static function GetMenuIndexById($sTitle)
static public function GetMenuIndexById($sTitle)
{
$index = -1;
/** @var MenuNode[] $aMenu */
@@ -535,7 +392,7 @@ EOF
* Retrieves the currently active menu (if any, otherwise the first menu is the default)
* @return string The Id of the currently active menu
*/
public static function GetActiveNodeId()
static public function GetActiveNodeId()
{
$oAppContext = new ApplicationContext();
$sMenuId = $oAppContext->GetCurrentValue('menu', null);
@@ -549,7 +406,7 @@ EOF
/**
* @return null|string
*/
public static function GetDefaultMenuId()
static public function GetDefaultMenuId()
{
static $sDefaultMenuId = null;
if (is_null($sDefaultMenuId))
@@ -569,7 +426,7 @@ EOF
* @param $sMenuId
* @return string
*/
public static function GetRootMenuId($sMenuId)
static public function GetRootMenuId($sMenuId)
{
$iMenuIndex = self::GetMenuIndexById($sMenuId);
if ($iMenuIndex == -1)
@@ -706,95 +563,29 @@ abstract class MenuNode
/**
* @return string
* @throws DictExceptionMissingString
*/
public function GetTitle()
{
return Dict::S("Menu:$this->sMenuId", str_replace('_', ' ', $this->sMenuId));
}
/**
* Indicates if the page corresponding to this menu node is countable
*
* @return bool true if corresponding page is countable
* @since 3.0.0
*/
public function HasCount()
{
return false;
}
protected function GetEntriesCountFromOQL(string $sOQL)
{
// Count the entries up to 99
$oSearch = DBSearch::FromOQL($sOQL);
$oAppContext = new ApplicationContext();
$sClass = $oSearch->GetClass();
foreach ($oAppContext->GetNames() as $key) {
// Find the value of the object corresponding to each 'context' parameter
$aCallSpec = [$sClass, 'MapContextParam'];
$sAttCode = '';
if (is_callable($aCallSpec)) {
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
}
if (MetaModel::IsValidAttCode($sClass, $sAttCode)) {
// Add Hierarchical condition if hierarchical key
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if (isset($oAttDef) && ($oAttDef->IsExternalKey())) {
$iDefaultValue = intval($oAppContext->GetCurrentValue($key));
if ($iDefaultValue != 0) {
try {
/** @var AttributeExternalKey $oAttDef */
$sTargetClass = $oAttDef->GetTargetClass();
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass($sTargetClass);
if ($sHierarchicalKeyCode !== false) {
$oFilter = new DBObjectSearch($sTargetClass);
$oFilter->AddCondition('id', $iDefaultValue);
$oHKFilter = new DBObjectSearch($sTargetClass);
$oHKFilter->AddCondition_PointingTo($oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW);
$oSearch->AddCondition_PointingTo($oHKFilter, $sAttCode);
}
}
catch (Exception $e) {
// If filtering fails just ignore it
}
}
}
}
}
$oSet = new DBObjectSet($oSearch);
$iCount = $oSet->CountWithLimit(99);
if ($iCount > 99) {
$iCount = "99+";
}
return $iCount;
}
/**
* Get the number of entries of the page corresponding to this menu item.
*
* @return int the number of entries
* @since 3.0.0
*/
public function GetEntriesCount()
{
return 0;
}
/**
* @return string
* @throws DictExceptionMissingString
*/
public function GetLabel()
{
$sRet = Dict::S("Menu:$this->sMenuId+", "");
if ($sRet === '') {
if ($this->iParentIndex != -1) {
if ($sRet === '')
{
if ($this->iParentIndex != -1)
{
$oParentMenu = ApplicationMenu::GetMenuNode($this->iParentIndex);
$sRet = $oParentMenu->GetTitle().' / '.$this->GetTitle();
} else {
}
else
{
$sRet = $this->GetTitle();
}
//$sRet = $this->GetTitle();
@@ -809,10 +600,7 @@ abstract class MenuNode
{
return $this->index;
}
/**
* @return void
*/
public function PopulateChildMenus()
{
foreach (ApplicationMenu::GetChildren($this->GetIndex()) as $aMenu)
@@ -937,64 +725,18 @@ abstract class MenuNode
*/
class MenuGroup extends MenuNode
{
/** @var string DEFAULT_DECORATION_CLASSES Set to null by default so it is replaced by initials when none is specified */
const DEFAULT_DECORATION_CLASSES = null;
/** @var string The CSS classes used to display the menu group's icon */
protected $sDecorationClasses = self::DEFAULT_DECORATION_CLASSES;
/**
* Create a top-level menu group and inserts it into the application's main menu
*
* @param string $sMenuId Unique identifier of the menu (used to identify the menu for bookmarking, and for getting the labels from the dictionary)
* @param float $fRank Number used to order the list, the groups are sorted based on this value
* @param string|null $sDecorationClasses CSS classes used to display the menu group's icon
* @param string $sEnableClass Name of class of object
* @param integer $iActionCode Either UR_ACTION_READ, UR_ACTION_MODIFY, UR_ACTION_DELETE, UR_ACTION_BULKREAD, UR_ACTION_BULKMODIFY or UR_ACTION_BULKDELETE
* @param integer $iAllowedResults Expected "rights" for the action: either UR_ALLOWED_YES, UR_ALLOWED_NO, UR_ALLOWED_DEPENDS or a mix of them...
* @param string $sEnableStimulus
*/
public function __construct($sMenuId, $fRank, $sDecorationClasses = null, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
public function __construct($sMenuId, $fRank, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
{
parent::__construct($sMenuId, -1 /* no parent, groups are at root level */, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
if(!empty($sDecorationClasses))
{
$this->sDecorationClasses = $sDecorationClasses;
}
}
/**
* Return true if the menu group has some decoration classes
*
* @return bool
* @since 3.0.0
*/
public function HasDecorationClasses()
{
return (empty($this->GetDecorationClasses()) === false);
}
/**
* Return the CSS classes used for decorating the menu group (typically the icon in the navigation menu)
*
* @return string
* @since 3.0.0
*/
public function GetDecorationClasses()
{
return $this->sDecorationClasses;
}
/**
* Returns the initials of the menu group, used by the rendering in case there is no decoration classes
*
* @return string
* @since 3.0.0
*/
public function GetInitials()
{
return mb_substr($this->GetTitle(), 0, 1);
}
/**
@@ -1171,43 +913,30 @@ class OQLMenuNode extends MenuNode
{
$sUsageId = utils::GetSafeId($sUsageId);
$oSearch = DBObjectSearch::FromOQL($sOql);
//$sIcon = MetaModel::GetClassIcon($oSearch->GetClass(), false);
$sIcon = MetaModel::GetClassIcon($oSearch->GetClass());
if ($bSearchPane) {
if ($bSearchPane)
{
$aParams = array_merge(array('open' => $bSearchOpen, 'table_id' => $sUsageId), $aExtraParams);
$oBlock = new DisplayBlock($oSearch, 'search', false /* Asynchronous */, $aParams);
$oBlock->Display($oPage, 0);
}
//$oPage->add("<p class=\"page-header\">$sIcon ".utils::HtmlEntities(Dict::S($sTitle))."</p>");
$oPage->add("<div class='sf_results_area' data-target='search_results'>");
$oTitle = TitleUIBlockFactory::MakeForPage($sTitle);
$oPage->AddUiBlock($oTitle);
$oPage->add("<p class=\"page-header\">$sIcon ".utils::HtmlEntities(Dict::S($sTitle))."</p>");
$aParams = array_merge(array('table_id' => $sUsageId), $aExtraParams);
$oBlock = new DisplayBlock($oSearch, 'list', false /* Asynchronous */, $aParams);
$oBlock->Display($oPage, $sUsageId);
$oPage->add("</div>");
if ($bEnableBreadcrumb && ($oPage instanceof iTopWebPage)) {
if ($bEnableBreadcrumb && ($oPage instanceof iTopWebPage))
{
// Breadcrumb
//$iCount = $oBlock->GetDisplayedCount();
$sPageId = "ui-search-".$oSearch->GetClass();
$sLabel = MetaModel::GetName($oSearch->GetClass());
$oPage->SetBreadCrumbEntry($sPageId, $sLabel, $sTitle, '', 'fas fa-list', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
$oPage->SetBreadCrumbEntry($sPageId, $sLabel, $sTitle, '', '../images/breadcrumb-search.png');
}
}
public function HasCount()
{
return true;
}
public function GetEntriesCount()
{
return $this->GetEntriesCountFromOQL($this->sOQL);
}
}
/**
@@ -1252,7 +981,7 @@ class SearchMenuNode extends MenuNode
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
ApplicationMenu::CheckMenuIdEnabled($this->GetMenuId());
$oPage->SetBreadCrumbEntry("menu-".$this->sMenuId, $this->GetTitle(), '', '', 'fas fa-search', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
$oPage->SetBreadCrumbEntry("menu-".$this->sMenuId, $this->GetTitle(), '', '', utils::GetAbsoluteUrlAppRoot().'images/breadcrumb-search.png');
$oSearch = new DBObjectSearch($this->sClass);
$aParams = array_merge(array('table_id' => 'Menu_'.utils::GetSafeId($this->GetMenuId())), $aExtraParams);
@@ -1462,32 +1191,40 @@ class DashboardMenuNode extends MenuNode
if ($oDashboard != null)
{
$sDivId = utils::Sanitize($this->sMenuId, '', 'element_identifier');
$oPage->add('<div id="'.$sDivId.'" class="ibo-dashboard" data-role="ibo-dashboard">');
$oPage->add('<div class="dashboard_contents" id="'.$sDivId.'">');
$aExtraParams['dashboard_div_id'] = $sDivId;
$aExtraParams['from_dashboard_page'] = true;
$oDashboard->SetReloadURL($this->GetHyperlink($aExtraParams));
$oDashboard->Render($oPage, false, $aExtraParams);
$oPage->add('</div>');
$bEdit = utils::ReadParam('edit', false);
if ($bEdit) {
if ($bEdit)
{
$sId = addslashes($this->sMenuId);
$oPage->add_ready_script("EditDashboard('$sId');");
} else {
}
else
{
$oParentMenu = ApplicationMenu::GetMenuNode($this->iParentIndex);
$sParentTitle = $oParentMenu->GetTitle();
$sThisTitle = $this->GetTitle();
if ($sParentTitle != $sThisTitle) {
if ($sParentTitle != $sThisTitle)
{
$sDescription = $sParentTitle.' / '.$sThisTitle;
} else {
}
else
{
$sDescription = $sThisTitle;
}
if ($this->sMenuId == ApplicationMenu::GetDefaultMenuId()) {
$sIcon = 'fas fa-home';
} else {
$sIcon = 'fas fa-chart-pie';
if ($this->sMenuId == ApplicationMenu::GetDefaultMenuId())
{
$sIcon = '../images/breadcrumb_home.png';
}
$oPage->SetBreadCrumbEntry("ui-dashboard-".$this->sMenuId, $this->GetTitle(), $sDescription, '', $sIcon, iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
else
{
$sIcon = '../images/breadcrumb-dashboard.png';
}
$oPage->SetBreadCrumbEntry("ui-dashboard-".$this->sMenuId, $this->GetTitle(), $sDescription, '', $sIcon);
}
}
else
@@ -1656,23 +1393,5 @@ class ShortcutMenuNode extends MenuNode
{
return $this->oShortcut->Get('name');
}
/**
* Indicates if the page corresponding to this menu node is countable
*
* @return bool true if corresponding page is countable
* @since 3.0.0
*/
public function HasCount()
{
return true;
}
public function GetEntriesCount()
{
return $this->GetEntriesCountFromOQL($this->oShortcut->Get('oql'));
}
}

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//

View File

@@ -1,7 +1,262 @@
<?php
/**
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/NiceWebPage.php
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2021 Combodo SARL
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
require_once(APPROOT."/application/webpage.class.inc.php");
/**
* Web page with some associated CSS and scripts (jquery) for a fancier display
*/
class NiceWebPage extends WebPage
{
var $m_aReadyScripts;
var $m_sRootUrl;
public function __construct($s_title, $bPrintable = false)
{
parent::__construct($s_title, $bPrintable);
$this->m_aReadyScripts = array();
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.min.js');
if(utils::IsDevelopmentEnvironment()) // Needed since many other plugins still rely on oldies like $.browser
{
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate.dev.js');
}
else
{
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate.prod.min.js');
}
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-ui-1.11.4.custom.min.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/utils.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/hovertip.js');
// table sorting
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablesorter.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablesorter.pager.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablehover.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/table-selectable-lines.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/field_sorter.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/datatable.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.positionBy.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.popupmenu.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/searchformforeignkeys.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/latinise/latinise.min.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_handler.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_handler_history.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_raw.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_string.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_external_field.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_numeric.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_enum.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_tag_set.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_external_key.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_hierarchical_key.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_date_abstract.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_date.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_date_time.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/clipboard.min.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/clipboardwidget.js');
$this->add_dict_entries('UI:Combo');
$this->add_ready_script(
<<< EOF
//add new widget called TruncatedList to properly display truncated lists when they are sorted
$.tablesorter.addWidget({
// give the widget a id
id: "truncatedList",
// format is called when the on init and when a sorting has finished
format: function(table)
{
// Check if there is a "truncated" line
this.truncatedList = false;
if ($("tr td.truncated",table).length > 0)
{
this.truncatedList = true;
}
if (this.truncatedList)
{
$("tr td",table).removeClass('truncated');
$("tr:last td",table).addClass('truncated');
}
}
});
$.tablesorter.addWidget({
// give the widget a id
id: "myZebra",
// format is called when the on init and when a sorting has finished
format: function(table)
{
// Replace the 'red even' lines by 'red_even' since most browser do not support 2 classes selector in CSS, etc..
$("tbody tr:even",table).addClass('even');
$("tbody tr.red:even",table).removeClass('red').removeClass('even').addClass('red_even');
$("tbody tr.orange:even",table).removeClass('orange').removeClass('even').addClass('orange_even');
$("tbody tr.green:even",table).removeClass('green').removeClass('even').addClass('green_even');
// In case we sort again the table, we need to remove the added 'even' classes on odd rows
$("tbody tr:odd",table).removeClass('even');
$("tbody tr.red_even:odd",table).removeClass('even').removeClass('red_even').addClass('red');
$("tbody tr.orange_even:odd",table).removeClass('even').removeClass('orange_even').addClass('orange');
$("tbody tr.green_even:odd",table).removeClass('even').removeClass('green_even').addClass('green');
}
});
$("table.listResults").tableHover(); // hover tables
EOF
);
$this->LoadTheme();
$this->m_sRootUrl = $this->GetAbsoluteUrlAppRoot();
$sAbsURLAppRoot = addslashes($this->m_sRootUrl);
$sAbsURLModulesRoot = addslashes($this->GetAbsoluteUrlModulesRoot());
$sEnvironment = addslashes(utils::GetCurrentEnvironment());
$sAppContext = addslashes($this->GetApplicationContext());
$this->add_script(
<<<EOF
function GetAbsoluteUrlAppRoot()
{
return '$sAbsURLAppRoot';
}
function GetAbsoluteUrlModulesRoot()
{
return '$sAbsURLModulesRoot';
}
function GetAbsoluteUrlModulePage(sModule, sPage, aArguments)
{
// aArguments is optional, it default to an empty hash
aArguments = typeof aArguments !== 'undefined' ? aArguments : {};
var sUrl = '$sAbsURLAppRoot'+'pages/exec.php?exec_module='+sModule+'&exec_page='+sPage+'&exec_env='+'$sEnvironment';
for (var sArgName in aArguments)
{
if (aArguments.hasOwnProperty(sArgName))
{
sUrl = sUrl + '&'+sArgName+'='+aArguments[sArgname];
}
}
return sUrl;
}
function AddAppContext(sURL)
{
var sContext = '$sAppContext';
if (sContext.length > 0)
{
if (sURL.indexOf('?') == -1)
{
return sURL+'?'+sContext;
}
return sURL+'&'+sContext;
}
return sURL;
}
EOF
);
}
public function SetRootUrl($sRootUrl)
{
$this->m_sRootUrl = $sRootUrl;
}
public function small_p($sText)
{
$this->add("<p style=\"font-size:smaller\">$sText</p>\n");
}
public function GetAbsoluteUrlAppRoot()
{
return utils::GetAbsoluteUrlAppRoot();
}
public function GetAbsoluteUrlModulesRoot()
{
return utils::GetAbsoluteUrlModulesRoot();
}
function GetApplicationContext()
{
$oAppContext = new ApplicationContext();
return $oAppContext->GetForLink();
}
// By Rom, used by CSVImport and Advanced search
public function MakeClassesSelect($sName, $sDefaultValue, $iWidthPx, $iActionCode = null)
{
// $aTopLevelClasses = array('bizService', 'bizContact', 'logInfra', 'bizDocument');
// These are classes wich root class is cmdbAbstractObject !
$this->add("<select id=\"select_$sName\" name=\"$sName\">");
$aValidClasses = array();
foreach(MetaModel::GetClasses('bizmodel') as $sClassName)
{
if (is_null($iActionCode) || UserRights::IsActionAllowed($sClassName, $iActionCode))
{
$sSelected = ($sClassName == $sDefaultValue) ? " SELECTED" : "";
$sDescription = MetaModel::GetClassDescription($sClassName);
$sDisplayName = MetaModel::GetName($sClassName);
$aValidClasses[$sDisplayName] = "<option style=\"width: ".$iWidthPx." px;\" title=\"$sDescription\" value=\"$sClassName\"$sSelected>$sDisplayName</option>";
}
}
ksort($aValidClasses);
$this->add(implode("\n", $aValidClasses));
$this->add("</select>");
}
// By Rom, used by Advanced search
public function add_select($aChoices, $sName, $sDefaultValue, $iWidthPx)
{
$this->add("<select id=\"select_$sName\" name=\"$sName\">");
foreach($aChoices as $sKey => $sValue)
{
$sSelected = ($sKey == $sDefaultValue) ? " SELECTED" : "";
$this->add("<option style=\"width: ".$iWidthPx." px;\" value=\"".htmlspecialchars($sKey)."\"$sSelected>".htmlentities($sValue,
ENT_QUOTES, self::PAGES_CHARSET)."</option>");
}
$this->add("</select>");
}
public function add_ready_script($sScript)
{
$this->m_aReadyScripts[] = $sScript;
}
/**
* Outputs (via some echo) the complete HTML page by assembling all its elements
*/
public function output()
{
//$this->set_base($this->m_sRootUrl.'pages/');
if (count($this->m_aReadyScripts)>0)
{
$this->add_script("\$(document).ready(function() {\n".implode("\n", $this->m_aReadyScripts)."\n});");
}
parent::output();
}
/**
* @throws \Exception
* @since 2.7.0
*/
protected function LoadTheme()
{
$sCssThemeUrl = ThemeHandler::GetCurrentThemeUrl();
$this->add_linked_stylesheet($sCssThemeUrl);
}
}

View File

@@ -1,7 +1,248 @@
<?php
/**
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/PDFPage.php
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2021 Combodo SARL
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
require_once(APPROOT.'application/utils.inc.php');
/**
* Custom class derived from TCPDF for providing custom headers and footers
*
* @author denis
*
*/
class iTopPDF extends TCPDF
{
protected $sDocumentTitle;
/**
* Shortcut for {@link TCPDF::SetFont}, to use the font configured
*
* @param string $style
* @param int $size
* @param string $fontfile
* @param string $subset
* @param bool $out
*
* @uses \TCPDF::SetFont()
* @uses \iTopPDF::GetPdfFont()
* @since 2.7.0
*/
public function SetFontParams($style, $size, $fontfile='', $subset='default', $out=true)
{
$siTopFont = self::GetPdfFont();
$this->SetFont($siTopFont, $style, $size, $fontfile, $subset, $out);
}
public function SetDocumentTitle($sDocumentTitle)
{
$this->sDocumentTitle = $sDocumentTitle;
}
/**
* Builds the custom header. Called for each new page.
*
* @see TCPDF::Header()
*/
public function Header()
{
// Title
// Set font
$this->SetFontParams('B', 10);
$iPageNumberWidth = 25;
$aMargins = $this->getMargins();
// Display the title (centered)
$this->SetXY($aMargins['left'] + $iPageNumberWidth, 0);
$this->MultiCell($this->getPageWidth() - $aMargins['left'] - $aMargins['right'] - 2 * $iPageNumberWidth, 15, $this->sDocumentTitle,
0, 'C', false, 0 /* $ln */, '', '', true, 0, false, true, 15, 'M' /* $valign */);
$this->SetFontParams('', 10);
// Display the page number (right aligned)
// Warning: the 'R'ight alignment does not work when using placeholders like $this->getAliasNumPage() or $this->getAliasNbPages()
$this->MultiCell($iPageNumberWidth, 15, Dict::Format('Core:BulkExport:PDF:PageNumber', $this->page), 0, 'R', false, 0 /* $ln */, '',
'', true, 0, false, true, 15, 'M' /* $valign */);
// Branding logo
$sBrandingIcon = APPROOT.'images/itop-logo.png';
if (file_exists(MODULESROOT.'branding/main-logo.png'))
{
$sBrandingIcon = MODULESROOT.'branding/main-logo.png';
}
$this->Image($sBrandingIcon, $aMargins['left'], 5, 0, 10);
}
// Page footer
public function Footer()
{
// No footer
}
/**
* dejavusans is a UTF-8 Unicode font. Standard PDF fonts like helvetica or times new roman are NOT UTF-8
* @return string font in the config file (export_pdf_font)
*/
public static function GetPdfFont()
{
$oConfig = utils::GetConfig();
$sPdfFont = $oConfig->Get('export_pdf_font');
return $sPdfFont;
}
}
/**
* Special class of WebPage for printing into a PDF document
*/
class PDFPage extends WebPage
{
/** @var \iTopPDF Instance of the TCPDF object for creating the PDF */
protected $oPdf;
public function __construct($s_title, $sPageFormat = 'A4', $sPageOrientation = 'L')
{
parent::__construct($s_title);
define(K_PATH_FONTS, APPROOT.'lib/combodo/tcpdf/fonts');
$this->oPdf = new iTopPDF($sPageOrientation, 'mm', $sPageFormat, true, self::PAGES_CHARSET, false);
// set document information
$this->oPdf->SetCreator(PDF_CREATOR);
$this->oPdf->SetAuthor('iTop');
$this->oPdf->SetTitle($s_title);
$this->oPdf->SetDocumentTitle($s_title);
$this->oPdf->setFontSubsetting(true);
// dejavusans is a UTF-8 Unicode font. Standard PDF fonts like helvetica or times new roman are NOT UTF-8
$this->oPdf->SetFontParams('', 10, '', true);
// set auto page breaks
$this->oPdf->SetAutoPageBreak(true, 15); // 15 mm break margin at the bottom
$this->oPdf->SetTopMargin(15);
// Add a page, we're ready to start
$this->oPdf->AddPage();
$this->SetContentDisposition('inline', $s_title.'.pdf');
$this->SetDefaultStyle();
}
/**
* Sets a default style (suitable for printing) to be included each time $this->oPdf->writeHTML() is called
*/
protected function SetDefaultStyle()
{
$this->add_style(
<<<EOF
table {
padding: 2pt;
}
table.listResults td {
border: 0.5pt solid #000 ;
}
table.listResults th {
background-color: #eee;
border: 0.5pt solid #000 ;
}
a {
text-decoration: none;
color: #000;
}
table.section td {
vertical-align: middle;
font-size: 10pt;
background-color:#eee;
}
td.icon {
width: 30px;
}
EOF
);
}
/**
* Get access to the underlying TCPDF object
*
* @return \iTopPDF
*/
public function get_tcpdf()
{
$this->flush();
return $this->oPdf;
}
/**
* Writes the currently buffered HTML content into the PDF. This can be useful:
* - to sync the flow in case you want to access the underlying TCPDF object for some specific/graphic output
* - to process the HTML by smaller chunks instead of processing the whole page at once for performance reasons
*/
public function flush()
{
if (strlen($this->s_content) > 0)
{
$sHtml = '';
if (count($this->a_styles) > 0)
{
$sHtml .= "<style>\n".implode("\n", $this->a_styles)."\n</style>\n";
}
$sHtml .= $this->s_content;
$this->oPdf->writeHTML($sHtml); // The style(s) must be supplied each time we call writeHtml
$this->s_content = '';
}
}
/**
* Whether or not the page is a PDF page
*
* @return boolean
*/
public function is_pdf()
{
return true;
}
/**
* Generates the PDF document and returns the PDF content as a string
*
* @return string
* @see WebPage::output()
*/
public function output()
{
$this->add_header('Content-type: application/x-pdf');
if (!empty($this->sContentDisposition))
{
$this->add_header('Content-Disposition: '.$this->sContentDisposition.'; filename="'.$this->sContentFileName.'"');
}
foreach ($this->a_headers as $s_header)
{
header($s_header);
}
$this->flush();
echo $this->oPdf->Output($this->s_title.'.pdf', 'S');
}
public function get_pdf()
{
$this->flush();
return $this->oPdf->Output($this->s_title.'.pdf', 'S');
}
}

View File

@@ -1,28 +1,33 @@
<?php
/*
* Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Persistent class Event and derived
* Application internal events
* There is also a file log
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
abstract class Query extends cmdbAbstractObject
{
/**
* @throws \CoreException
* @since 3.0.0 N°3227 add is_template field for predefined queries
*/
public static function Init()
{
$aParams = array
@@ -35,41 +40,20 @@ abstract class Query extends cmdbAbstractObject
"db_table" => "priv_query",
"db_key_field" => "id",
"db_finalclass_field" => "realclass",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("name", array(
"allowed_values" => null,
"sql" => "name",
"default_value" => null,
"is_null_allowed" => false,
"depends_on" => array(),
)));
MetaModel::Init_AddAttribute(new AttributeText("description", array(
"allowed_values" => null,
"sql" => "description",
"default_value" => null,
"is_null_allowed" => false,
"depends_on" => array(),
)));
MetaModel::Init_AddAttribute(new AttributeEnum("is_template", array(
'allowed_values' => new ValueSetEnum('yes,no'),
'sql' => 'is_template',
'default_value' => 'no',
'is_null_allowed' => false,
'depends_on' => [],
'display_style' => 'radio_horizontal',
)));
// Display lists
MetaModel::Init_SetZListItems('details',
array('name', 'is_template', 'description')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array('name', 'description')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'is_template')); // Criteria of the std search form
MetaModel::Init_SetZListItems('default_search',
array('name', 'description', 'is_template')); // Criteria of the default search form
MetaModel::Init_SetZListItems('standard_search', array('name', 'description')); // Criteria of the std search form
MetaModel::Init_SetZListItems('default_search', array('name', 'description')); // Criteria of the default search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
@@ -84,37 +68,24 @@ class QueryOQL extends Query
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array('oql', 'is_template'),
"reconc_keys" => array(),
"db_table" => "priv_query_oql",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array(
"allowed_values" => null,
"sql" => "oql",
"default_value" => null,
"is_null_allowed" => false,
"depends_on" => array(),
)));
MetaModel::Init_AddAttribute(new AttributeText("fields", array(
"allowed_values" => null,
"sql" => "fields",
"default_value" => null,
"is_null_allowed" => true,
"depends_on" => array(),
)));
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("fields", array("allowed_values"=>null, "sql"=>"fields", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// Rolled back to AttributeText until AttributeQueryAttCodeSet can manage fields order correctly
//MetaModel::Init_AddAttribute(new AttributeQueryAttCodeSet("fields", array("allowed_values"=>null,"max_items" => 1000, "query_field" => "oql", "sql"=>"fields", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array('oql'))));
// Display lists
MetaModel::Init_SetZListItems('details',
array('name', 'is_template', 'description', 'oql', 'fields')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array('name', 'description', 'oql', 'fields')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search',
array('name', 'description', 'is_template', 'fields', 'oql')); // Criteria of the std search form
MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'fields', 'oql')); // Criteria of the std search form
}
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
@@ -15,14 +15,13 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableSettings;
/**
* Persistent class Shortcut and derived
* Shortcuts of any kind
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -40,6 +39,7 @@ abstract class Shortcut extends DBObject implements iDisplay
"db_table" => "priv_shortcut",
"db_key_field" => "id",
"db_finalclass_field" => "realclass",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
@@ -101,7 +101,7 @@ function ShortcutRenameOK()
});
}
$('#shortcut_rename_dlg form').on('submit', function() { return false; });
$('#shortcut_rename_dlg form').bind('submit', function() { return false; });
$('#shortcut_rename_dlg').dialog({
width: 400,
@@ -161,6 +161,7 @@ class ShortcutOQL extends Shortcut
"db_table" => "priv_shortcut_oql",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
@@ -286,7 +287,8 @@ class ShortcutOQL extends Shortcut
$sRateTitle = addslashes(Dict::Format('Class:ShortcutOQL/Attribute:auto_reload_sec/tip', MetaModel::GetConfig()->Get('min_reload_interval')));
$oPage->add_ready_script(
<<<JS
<<<EOF
// Note: the title gets deleted by the validation mechanism
$("#attr_auto_reload_sec").tooltip({items: 'input', content: '$sRateTitle'});
$("#attr_auto_reload_sec").prop('disabled', !$('#attr_auto_reload').is(':checked'));
@@ -314,30 +316,23 @@ function ShortcutCreationOK()
});
}
$('#shortcut_creation_dlg form').on('submit', function() { ShortcutCreationOK(); return false; });
$('#shortcut_creation_dlg form').bind('submit', function() { ShortcutCreationOK(); return false; });
$('#shortcut_creation_dlg').dialog({
width: 400,
modal: true,
title: '$sDialogTitle',
buttons: [
{
text: "$sCancelButtonLabel",
class: "ibo-is-alternative",
click: function() {
$(this).dialog( "close" );
$(this).remove();
}
},
{
text: "$sOkButtonLabel",
class: "ibo-is-primary",
click: ShortcutCreationOK
},
{ text: "$sOkButtonLabel", click: ShortcutCreationOK },
{ text: "$sCancelButtonLabel", click: function() {
$(this).dialog( "close" ); $(this).remove();
} },
],
close: function() { $(this).remove(); }
});
JS
EOF
);
}
}
?>

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
@@ -23,7 +23,7 @@ require_once(APPROOT.'/core/contexttag.class.inc.php');
/**
* File to include to initialize the datamodel in memory
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -1,6 +1,6 @@
<?php
/**
* Copyright (C) 2013-2021 Combodo SARL
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
@@ -20,8 +20,6 @@
require_once(APPROOT.'/application/displayblock.class.inc.php');
/**
* This class manages the special template format used internally to build the iTop web pages
*
* @deprecated 3.0.0
*/
class DisplayTemplate
{

View File

@@ -1,6 +1,6 @@
<?php
/**
* Copyright (C) 2013-2021 Combodo SARL
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
@@ -25,15 +25,6 @@
*/
class ThemeHandler
{
const IMAGE_EXTENSIONS = ['png', 'gif', 'jpg', 'jpeg'];
private static $oCompileCSSService;
public static function GetAppRootWithSlashes()
{
return str_replace('\\', '/', APPROOT);
}
/**
* Return default theme name and parameters
*
@@ -42,17 +33,19 @@ class ThemeHandler
*/
public static function GetDefaultThemeInformation()
{
return [
'name' => 'fullmoon',
'parameters' => [
'variables' => [],
'imports' => [
],
'stylesheets' => [
'main' => '../css/backoffice/main.scss',
],
],
];
return array(
'name' => 'light-grey',
'parameters' => array(
'variables' => array(),
'imports' => array(
'css-variables' => '../css/css-variables.scss',
),
'stylesheets' => array(
'jqueryui' => '../css/ui-lightness/jqueryui.scss',
'main' => '../css/light-grey.scss',
),
),
);
}
/**
@@ -119,46 +112,37 @@ class ThemeHandler
SetupUtils::builddir($sDefaultThemeDirPath);
}
static::CompileTheme($sThemeId, false, "", $aDefaultTheme['parameters']);
static::CompileTheme($sThemeId, $aDefaultTheme['parameters']);
}
// Return absolute url to theme compiled css
return utils::GetAbsoluteUrlModulesRoot().'branding/themes/'.$sThemeId.'/main.css';
return utils::GetAbsoluteUrlModulesRoot().'/branding/themes/'.$sThemeId.'/main.css';
}
/**
* Compile the $sThemeId theme, the actual compilation is skipped when either
* 1) The produced CSS file exists and is more recent than any of its components (imports, stylesheets)
* 2) The produced CSS file exists and its signature is equal to the expected signature (imports, stylesheets, variables)
* Compile the $sThemeId theme
*
* @param string $sThemeId
* @param boolean $bSetup
* @param string $sSetupCompilationTimestamp : setup compilation timestamp in micro secunds
* @param array|null $aThemeParameters Parameters (variables, imports, stylesheets) for the theme, if not passed, will be retrieved from compiled DM
* @param array|null $aImportsPaths Paths where imports can be found. Must end with '/'
* @param string|null $sWorkingPath Path of the folder used during compilation. Must end with a '/'
*
* @throws \CoreException
* @return boolean: indicate whether theme compilation occured
*/
public static function CompileTheme($sThemeId, $bSetup=false, $sSetupCompilationTimestamp="", $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null) {
if ($sSetupCompilationTimestamp === "") {
$sSetupCompilationTimestamp = microtime(true);
}
$sSetupCompilationTimestampInSecunds = (strpos($sSetupCompilationTimestamp, '.') !== false) ? explode('.',
$sSetupCompilationTimestamp)[0] : $sSetupCompilationTimestamp;
$sEnv = APPROOT.'env-'.utils::GetCurrentEnvironment().'/';
public static function CompileTheme($sThemeId, $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null)
{
// Default working path
if ($sWorkingPath === null) {
$sWorkingPath = $sEnv;
if($sWorkingPath === null)
{
$sWorkingPath = APPROOT.'env-'.utils::GetCurrentEnvironment().'/';
}
// Default import paths (env-*)
if ($aImportsPaths === null) {
$aImportsPaths = [$sEnv];
if($aImportsPaths === null)
{
$aImportsPaths = array(
APPROOT.'env-'.utils::GetCurrentEnvironment().'/',
);
}
// Note: We do NOT check that the folder exists!
@@ -166,732 +150,45 @@ class ThemeHandler
$sThemeCssPath = $sThemeFolderPath.'main.css';
// Save parameters if passed... (typically during DM compilation)
if (is_array($aThemeParameters)) {
if (!is_dir($sThemeFolderPath)) {
mkdir($sWorkingPath.'/branding/');
mkdir($sWorkingPath.'/branding/themes/');
}
if(is_array($aThemeParameters))
{
file_put_contents($sThemeFolderPath.'/theme-parameters.json', json_encode($aThemeParameters));
} // ... Otherwise, retrieve them from compiled DM (typically when switching current theme in the config. file)
else {
}
// ... Otherwise, retrieve them from compiled DM (typically when switching current theme in the config. file)
else
{
$aThemeParameters = json_decode(@file_get_contents($sThemeFolderPath.'theme-parameters.json'), true);
if ($aThemeParameters === null) {
if ($aThemeParameters === null)
{
throw new CoreException('Could not load "'.$sThemeId.'" theme parameters from file, check that it has been compiled correctly');
}
}
$aThemeParametersWithVersion = self::CloneThemeParameterAndIncludeVersion($aThemeParameters, $sSetupCompilationTimestampInSecunds);
clearstatcache();
// Loading files to import and stylesheet to compile, also getting most recent modification time on overall files
$sTmpThemeScssContent = '';
$oFindStylesheetObject = new FindStylesheetObject();
if (isset($aThemeParameters['imports_utility'])) {
foreach ($aThemeParameters['imports_utility'] as $sImport) {
static::FindStylesheetFile($sImport, $aImportsPaths, $oFindStylesheetObject);
}
}
if (isset($aThemeParameters['stylesheets'])) {
foreach ($aThemeParameters['stylesheets'] as $sStylesheet) {
static::FindStylesheetFile($sStylesheet, $aImportsPaths, $oFindStylesheetObject);
}
}
foreach ($oFindStylesheetObject->GetStylesheetFileURIs() as $sStylesheet){
$sTmpThemeScssContent .= '@import "'.$sStylesheet.'";'."\n";
}
$iStyleLastModified = $oFindStylesheetObject->GetLastModified();
$aIncludedImages=static::GetIncludedImages($aThemeParametersWithVersion, $oFindStylesheetObject->GetAllStylesheetPaths(), $sThemeId);
foreach ($aIncludedImages as $sImage)
$iStyleLastModified = 0;
clearstatcache();
// Loading files to import and stylesheet to compile, also getting most recent modification time on overall files
foreach ($aThemeParameters['imports'] as $sImport)
{
if (is_file($sImage))
{
$iStylesheetLastModified = @filemtime($sImage);
$iStyleLastModified = $iStyleLastModified < $iStylesheetLastModified ? $iStylesheetLastModified : $iStyleLastModified;
}
$sTmpThemeScssContent .= '@import "'.$sImport.'";'."\n";
$iImportLastModified = @filemtime($sWorkingPath.$sImport);
$iStyleLastModified = $iStyleLastModified < $iImportLastModified ? $iImportLastModified : $iStyleLastModified;
}
foreach ($aThemeParameters['stylesheets'] as $sStylesheet)
{
$sTmpThemeScssContent .= '@import "'.$sStylesheet.'";'."\n";
$iStylesheetLastModified = @filemtime($sWorkingPath.$sStylesheet);
$iStyleLastModified = $iStyleLastModified < $iStylesheetLastModified ? $iStylesheetLastModified : $iStyleLastModified;
}
// Checking if our compiled css is outdated
$iFilemetime = @filemtime($sThemeCssPath);
$bFileExists = file_exists($sThemeCssPath);
$bVarSignatureChanged=false;
if ($bFileExists && $bSetup)
if (!file_exists($sThemeCssPath) || (is_writable($sThemeFolderPath) && (@filemtime($sThemeCssPath) < $iStyleLastModified)))
{
$sPrecompiledSignature = static::GetSignature($sThemeCssPath);
//check variable signature has changed which is independant from any file modification
if (!empty($sPrecompiledSignature)){
$sPreviousVariableSignature = static::GetVarSignature($sPrecompiledSignature);
$sCurrentVariableSignature = md5(json_encode($aThemeParameters['variables']));
$bVarSignatureChanged= ($sPreviousVariableSignature!==$sCurrentVariableSignature);
}
}
if (!$bFileExists || $bVarSignatureChanged || (is_writable($sThemeFolderPath) && ($iFilemetime < $iStyleLastModified)))
{
// Dates don't match. Second chance: check if the already compiled stylesheet exists and is consistent based on its signature
$sActualSignature = static::ComputeSignature($aThemeParameters, $aImportsPaths, $aIncludedImages);
if ($bFileExists && !$bSetup)
{
$sPrecompiledSignature = static::GetSignature($sThemeCssPath);
}
if (!empty($sPrecompiledSignature) && $sActualSignature == $sPrecompiledSignature)
{
touch($sThemeCssPath); // Stylesheet is up to date, mark it as more recent to speedup next time
}
else
{
// Alas, we really need to recompile
// Add the signature to the generated CSS file so that the file can be used as a precompiled stylesheet if needed
$sSignatureComment =
<<<CSS
/*
=== SIGNATURE BEGIN ===
$sActualSignature
=== SIGNATURE END ===
*/
CSS;
if (!static::$oCompileCSSService)
{
static::$oCompileCSSService = new CompileCSSService();
}
//store it again to change $version with latest compiled time
$sTmpThemeCssContent = static::$oCompileCSSService->CompileCSSFromSASS($sTmpThemeScssContent, $aImportsPaths,
$aThemeParametersWithVersion);
file_put_contents($sThemeFolderPath.'/theme-parameters.json', json_encode($aThemeParameters));
file_put_contents($sThemeCssPath, $sSignatureComment.$sTmpThemeCssContent);
SetupLog::Info("Theme $sThemeId file compiled.");
return true;
}
}
return false;
}
/**
* @since 3.0.0 N°2982
* Compute the signature of a theme defined by its theme parameters. The signature is a JSON structure of
* 1) one MD5 of all the variables/values (JSON encoded)
* 2) the MD5 of each stylesheet file
* 3) the MD5 of each import file
* 3) the MD5 of each images referenced in style sheets
*
* @param string[] $aThemeParameters
* @param string[] $aImportsPaths
* @param string[] $aIncludedImages
*
* @return string
* @throws \Exception
*/
public static function ComputeSignature($aThemeParameters, $aImportsPaths, $aIncludedImages) {
$aSignature = [
'variables' => md5(json_encode($aThemeParameters['variables'])),
'stylesheets' => [],
'imports' => [],
'images' => []
];
$oFindStylesheetObject = new FindStylesheetObject();
if (isset($aThemeParameters['imports_variable'])) {
foreach ($aThemeParameters['imports_variable'] as $key => $sImport) {
static::FindStylesheetFile($sImport, $aImportsPaths, $oFindStylesheetObject);
$sFile = $oFindStylesheetObject->GetLastStylesheetFile();
if (!empty($sFile)) {
$aSignature['stylesheets'][$key] = md5_file($sFile);
}
}
}
if (isset($aThemeParameters['imports_utility'])) {
foreach ($aThemeParameters['imports_utility'] as $key => $sImport) {
static::FindStylesheetFile($sImport, $aImportsPaths, $oFindStylesheetObject);
$sFile = $oFindStylesheetObject->GetLastStylesheetFile();
if (!empty($sFile)) {
$aSignature['stylesheets'][$key] = md5_file($sFile);
}
}
}
if (isset($aThemeParameters['stylesheets'])) {
foreach ($aThemeParameters['stylesheets'] as $key => $sStylesheet) {
static::FindStylesheetFile($sStylesheet, $aImportsPaths, $oFindStylesheetObject);
$sFile = $oFindStylesheetObject->GetLastStylesheetFile();
if (!empty($sFile)) {
$aSignature['stylesheets'][$key] = md5_file($sFile);
}
}
}
$aFiles = $oFindStylesheetObject->GetImportPaths();
if (count($aFiles) !== 0) {
foreach ($aFiles as $sFileURI => $sFilePath) {
$aSignature['imports_utility'][$sFileURI] = md5_file($sFilePath);
}
}
foreach ($aIncludedImages as $sImage)
{
if (is_file($sImage)) {
$sUri = str_replace(self::GetAppRootWithSlashes(), '', $sImage);
$aSignature['images'][$sUri] = md5_file($sImage);
}
}
return json_encode($aSignature);
}
/**
* Search for images referenced in stylesheet files
*
* @param array $aThemeParametersVariables
* @param array $aStylesheetFiles
* @param string $sThemeId : used only for logging purpose
*
* @return array complete path of the images, but with slashes as dir separator instead of DIRECTORY_SEPARATOR
* @since 3.0.0 N°2982
*/
public static function GetIncludedImages($aThemeParametersVariables, $aStylesheetFiles, $sThemeId)
{
$sTargetThemeFolderPath = static::GetCompiledThemeFolderAbsolutePath($sThemeId);
$aCompleteUrls = [];
$aToCompleteUrls = [];
$aMissingVariables = [];
$aFoundVariables = ['version'=>''];
$aMap = [
'aCompleteUrls' => $aCompleteUrls,
'aToCompleteUrls' => $aToCompleteUrls,
'aMissingVariables' => $aMissingVariables,
'aFoundVariables' => $aFoundVariables,
];
foreach ($aStylesheetFiles as $sStylesheetFile)
{
$aRes = static::GetAllUrlFromScss($aThemeParametersVariables, $sStylesheetFile);
/** @var array $aVal */
foreach($aMap as $key => $aVal)
{
if (array_key_exists($key, $aMap))
{
$aMap[$key] = array_merge($aVal, $aRes[$key]);
}
}
}
$aMap = static::ResolveUncompleteUrlsFromScss($aMap, $aThemeParametersVariables, $aStylesheetFiles);
$aImages = [];
foreach ($aMap ['aCompleteUrls'] as $sUri => $sUrl)
{
$sImg = $sUrl;
if (preg_match("/(.*)\?/", $sUrl, $aMatches))
{
$sImg=$aMatches[1];
}
if (static::HasImageExtension($sImg)
&& ! array_key_exists($sImg, $aImages))
{
$sFilePath = realpath($sImg);
if ($sFilePath !== false) {
$sFilePathWithSlashes = str_replace('\\', '/', $sFilePath);
$aImages[$sImg] = $sFilePathWithSlashes;
continue;
}
$sCanonicalPath = static::CanonicalizePath($sTargetThemeFolderPath.'/'.$sImg);
$sFilePath = realpath($sCanonicalPath);
if ($sFilePath !== false) {
$sFilePathWithSlashes = str_replace('\\', '/', $sFilePath);
$aImages[$sImg] = $sFilePathWithSlashes;
continue;
}
SetupLog::Warning("Cannot find $sCanonicalPath ($sImg) during SCSS $sThemeId precompilation");
}
}
return array_values($aImages);
}
/**
* Reduce path without using realpath (works only when file exists)
* @param $path
*
* @return string
*/
public static function CanonicalizePath($path)
{
$path = explode('/', str_replace('//','/', $path));
$stack = array();
foreach ($path as $seg) {
if ($seg == '..') {
// Ignore this segment, remove last segment from stack
array_pop($stack);
continue;
}
if ($seg == '.') {
// Ignore this segment
continue;
}
$stack[] = $seg;
}
return implode('/', $stack);
}
/**
* @since 3.0.0 N°2982
* Complete url using provided variables. Example with $var=1: XX + $var => XX1
* @param $aMap
* @param $aThemeParametersVariables
* @param $aStylesheetFile
*
* @return mixed
*/
public static function ResolveUncompleteUrlsFromScss($aMap, $aThemeParametersVariables, $aStylesheetFile)
{
$sContent="";
foreach ($aStylesheetFile as $sStylesheetFile)
{
if (is_file($sStylesheetFile))
{
$sContent .= '\n' . file_get_contents($sStylesheetFile);
}
}
$aMissingVariables=$aMap['aMissingVariables'];
$aFoundVariables=$aMap['aFoundVariables'];
$aToCompleteUrls=$aMap['aToCompleteUrls'];
$aCompleteUrls=$aMap['aCompleteUrls'];
list($aMissingVariables, $aFoundVariables) = static::FindMissingVariables($aThemeParametersVariables, $aMissingVariables, $aFoundVariables, $sContent, true);
list($aToCompleteUrls, $aCompleteUrls) = static::ResolveUrls($aFoundVariables, $aToCompleteUrls, $aCompleteUrls);
$aMap['aMissingVariables']=$aMissingVariables;
$aMap['aFoundVariables']=$aFoundVariables;
$aMap['aToCompleteUrls']=$aToCompleteUrls;
$aMap['aCompleteUrls']=$aCompleteUrls;
return $aMap;
}
/**
* @since 3.0.0 N°2982
* Find missing variable values from SCSS content based on their name.
*
* @param $aThemeParametersVariables
* @param $aMissingVariables
* @param $aFoundVariables
* @param $sContent : scss content
* @param bool $bForceEmptyValueWhenNotFound
*
* @return array
*/
public static function FindMissingVariables($aThemeParametersVariables, $aMissingVariables, $aFoundVariables, $sContent, $bForceEmptyValueWhenNotFound=false)
{
$aNewMissingVars = [];
if (!empty($aMissingVariables))
{
foreach ($aMissingVariables as $var)
{
if (array_key_exists($var, $aThemeParametersVariables))
{
$aFoundVariables[$var] = $aThemeParametersVariables[$var];
}
else
{
if (preg_match_all("/\\\$$var\s*:\s*[\"']{0,1}(.*)[\"']{0,1};/", $sContent, $aValues))
{
$sValue = $aValues[1][0];
if (preg_match_all("/([^!]+)!/", $sValue, $aSubValues))
{
$sValue = trim($aSubValues[1][0], ' "\'');
}
if (strpos($sValue, '$') === false)
{
$aFoundVariables[$var] = $sValue;
}
else{
$aNewMissingVars[] = $var;
}
}
else
{
if ($bForceEmptyValueWhenNotFound)
{
$aFoundVariables[$var] = '';
}
else
{
$aNewMissingVars[] = $var;
}
}
}
}
}
return [ $aNewMissingVars, $aFoundVariables ];
}
/**
* @since 3.0.0 N°2982
* @param $aFoundVariables
* @param array $aToCompleteUrls
* @param array $aCompleteUrls
*
* @return array
*/
public static function ResolveUrls($aFoundVariables, array $aToCompleteUrls, array $aCompleteUrls)
{
if (!empty($aFoundVariables))
{
$aFoundVariablesWithEmptyValue = [];
foreach ($aFoundVariables as $aFoundVariable => $sValue)
{
$aFoundVariablesWithEmptyValue[$aFoundVariable] = '';
}
foreach ($aToCompleteUrls as $sUrlTemplate)
{
unset($aToCompleteUrls[$sUrlTemplate]);
$sResolvedUrl = static::ResolveUrl($sUrlTemplate, $aFoundVariables);
if ($sResolvedUrl == false)
{
$aToCompleteUrls[$sUrlTemplate] = $sUrlTemplate;
}
else
{
$sUri = static::ResolveUrl($sUrlTemplate, $aFoundVariablesWithEmptyValue);
$aExplodedUri = explode('?', $sUri);
if (empty($aExplodedUri))
{
$aCompleteUrls[$sUri] = $sResolvedUrl;
}
else
{
$aCompleteUrls[$aExplodedUri[0]] = $sResolvedUrl;
}
}
}
}
return [ $aToCompleteUrls, $aCompleteUrls];
}
/**
* @since 3.0.0 N°2982
* Find all referenced URLs from a SCSS file.
* @param $aThemeParametersVariables
* @param $sStylesheetFile
*
* @return array
*/
public static function GetAllUrlFromScss($aThemeParametersVariables, $sStylesheetFile)
{
$aCompleteUrls = [];
$aToCompleteUrls = [];
$aMissingVariables = [];
$aFoundVariables = [];
if (is_file($sStylesheetFile))
{
$sContent = file_get_contents($sStylesheetFile);
if (preg_match_all("/url\s*\((.*)\)/", $sContent, $aMatches))
{
foreach ($aMatches[1] as $path)
{
$iRemainingClosingParenthesisPos = strpos($path, ')');
if ($iRemainingClosingParenthesisPos !== false){
$path = substr($path, 0, $iRemainingClosingParenthesisPos);
}
if (!array_key_exists($path, $aCompleteUrls)
&& !array_key_exists($path, $aToCompleteUrls))
{
if (preg_match_all("/\\$([\w\-_]+)/", $path, $aCurrentVars))
{
/** @var string $aCurrentVars */
foreach ($aCurrentVars[1] as $var)
{
if (!array_key_exists($var, $aMissingVariables))
{
$aMissingVariables[$var] = $var;
}
}
$aToCompleteUrls[$path] = $path;
}
else
{
$aCompleteUrls[$path] = trim($path, "\"'");
}
}
}
}
if (!empty($aMissingVariables))
{
list($aMissingVariables, $aFoundVariables) = static::FindMissingVariables($aThemeParametersVariables, $aMissingVariables, $aFoundVariables, $sContent);
list($aToCompleteUrls, $aCompleteUrls) = static::ResolveUrls($aFoundVariables, $aToCompleteUrls, $aCompleteUrls);
}
}
return [
'aCompleteUrls' => $aCompleteUrls,
'aToCompleteUrls' => $aToCompleteUrls,
'aMissingVariables' => $aMissingVariables,
'aFoundVariables' => $aFoundVariables
];
}
/**
* @since 3.0.0 N°2982
* Calculate url based on its template + variables.
* @param $sUrlTemplate
* @param $aFoundVariables
*
* @return bool|string
*/
public static function ResolveUrl($sUrlTemplate, $aFoundVariables)
{
$aPattern= [];
$aReplacement= [];
foreach ($aFoundVariables as $aFoundVariable => $aFoundVariableValue)
{
//XX + $key + YY
$aPattern[]="/['\"]\s*\+\s*\\\$" . $aFoundVariable . "[\s\+]+\s*['\"]/";
$aReplacement[]=$aFoundVariableValue;
//$key + YY
$aPattern[]="/\\\$" . $aFoundVariable. "[\s\+]+\s*['\"]/";
$aReplacement[]=$aFoundVariableValue;
//XX + $key
$aPattern[]="/['\"]\s*[\+\s]+\\\$" . $aFoundVariable . "$/";
$aReplacement[]=$aFoundVariableValue;
}
$sResolvedUrl=preg_replace($aPattern, $aReplacement, $sUrlTemplate);
if (strpos($sResolvedUrl, "+")!==false)
{
return false;
}
return trim($sResolvedUrl, "\"'");
}
/**
* indicate whether a string ends with image suffix.
* @param $path
*
* @return bool
*/
private static function HasImageExtension($path)
{
foreach (static::IMAGE_EXTENSIONS as $sExt)
{
if (endsWith($path, $sExt))
{
return true;
}
}
return false;
}
/**
* @since 3.0.0 N°2982
* Extract the signature for a generated CSS file.
* The signature MUST be alone one line immediately followed (on the next line) by the === SIGNATURE END === pattern
* The signature MUST be in the first 100th lines of the file.
*
* Note the signature can be place anywhere in the CSS file (obviously inside a CSS comment !) but the
* function will be faster if the signature is at the beginning of the file (since the file is scanned from the start)
*
* @param $sFilepath
*
* @return string
*/
public static function GetSignature($sFilepath)
{
$iCount = 0;
$sPreviousLine = '';
$hFile = @fopen($sFilepath, "r");
if ($hFile !== false)
{
$sLine = '';
do
{
$iCount++;
$sPreviousLine = $sLine;
$sLine = rtrim(fgets($hFile)); // Remove the trailing \n
}
while (($sLine !== false) && ($sLine != '=== SIGNATURE END ===') && ($iCount <= 100));
fclose($hFile);
}
return $sPreviousLine;
}
/**
* @since 3.0.0 N°2982
* @param $JsonSignature
*
* @return false|mixed
*/
public static function GetVarSignature($JsonSignature)
{
$aJsonArray = json_decode($JsonSignature, true);
if (array_key_exists('variables', $aJsonArray))
{
return $aJsonArray['variables'];
}
return false;
}
/**
* @param string $sFileURI
* @param string[] $aImportsPaths
* @param FindStylesheetObject $oFindStylesheetObject
* @param bool $bImports
*
* @throws \Exception
*@since 3.0.0 N°2982
* Find the given file in the list '$aImportsPaths' of directory and all included stylesheets as well
* Compute latest timestamp found among all found stylesheets
*
*/
public static function FindStylesheetFile(string $sFileURI, array $aImportsPaths, $oFindStylesheetObject, $bImports = false)
{
if (! $bImports) {
$oFindStylesheetObject->ResetLastStyleSheet();
}
foreach($aImportsPaths as $sPath)
{
$sFilePath = $sPath.'/'.$sFileURI;
$sImportedFile = realpath($sFilePath);
if ($sImportedFile === false){
// Handle shortcut syntax : @import "typo" ;
// file matched: typo.scss
$sFilePath2 = "$sFilePath.scss";
$sImportedFile = realpath($sFilePath2);
if ($sImportedFile){
self::FindStylesheetFile("$sFileURI.scss", [ $sPath ], $oFindStylesheetObject, $bImports);
$sImportedFile = false;
}
}
if ($sImportedFile === false){
// Handle shortcut syntax : @import "typo" ;
// file matched: _typo.scss
$sShortCut = substr($sFilePath, strrpos($sFilePath, '/') + 1);
$sFilePath = static::ReplaceLastOccurrence($sShortCut, "_$sShortCut.scss", $sFilePath);
$sFileURI = static::ReplaceLastOccurrence($sShortCut, "_$sShortCut.scss", $sFileURI);
$sImportedFile = realpath($sFilePath);
}
if ((file_exists($sImportedFile))
&& (!$oFindStylesheetObject->AlreadyFetched($sImportedFile)))
{
if ($bImports){
$oFindStylesheetObject->AddImport($sFileURI, $sImportedFile);
}else{
$oFindStylesheetObject->AddStylesheet($sFileURI, $sImportedFile);
}
$oFindStylesheetObject->UpdateLastModified($sImportedFile);
//Regexp matching on all included scss files : @import 'XXX.scss';
$sDirUri = dirname($sFileURI);
preg_match_all('/@import \s*[\"\']([^\"\']*)\s*[\"\']\s*;/', file_get_contents($sImportedFile), $aMatches);
if ( (is_array($aMatches)) && (count($aMatches)!==0) ){
foreach ($aMatches[1] as $sImportedFile){
self::FindStylesheetFile("$sDirUri/$sImportedFile", [ $sPath ], $oFindStylesheetObject, true);
}
}
}
$sTmpThemeCssContent = utils::CompileCSSFromSASS($sTmpThemeScssContent, $aImportsPaths, $aThemeParameters['variables']);
file_put_contents($sThemeCssPath, $sTmpThemeCssContent);
}
}
/**
* @param $search
* @param $replace
* @param $subject
*
* @since 3.0.0 N°2982
* Replaces last occurrence of the string
* @return string|string[]
*/
public static function ReplaceLastOccurrence($sSearch, $sReplace, $sSubject)
{
$iPos = strrpos($sSubject, $sSearch);
if($iPos !== false)
{
$sSubject = substr_replace($sSubject, $sReplace, $iPos, strlen($sSearch));
}
return $sSubject;
}
/**
* @since 3.0.0 N°2982
* Used for testing purpose
* @param $oCompileCSSServiceMock
*/
public static function MockCompileCSSService($oCompileCSSServiceMock)
{
static::$oCompileCSSService = $oCompileCSSServiceMock;
}
/**
* @since 3.0.0 N°2982
* Clone variable array and include $version with bSetupCompilationTimestamp value
* @param $aThemeParameters
* @param $bSetupCompilationTimestamp
*
* @return array
*/
public static function CloneThemeParameterAndIncludeVersion($aThemeParameters, $bSetupCompilationTimestamp)
{
$aThemeParametersVariable = [];
if (array_key_exists('variables', $aThemeParameters))
{
if (is_array($aThemeParameters['variables']))
{
$aThemeParametersVariable = array_merge([], $aThemeParameters['variables']);
}
}
if (array_key_exists('imports_variable', $aThemeParameters))
{
if (is_array($aThemeParameters['imports_variable']))
{
$aThemeParametersVariable = array_merge($aThemeParametersVariable, static::GetVariablesFromFile($aThemeParameters['imports_variable']));
}
}
$aThemeParametersVariable['$version'] = $bSetupCompilationTimestamp;
return $aThemeParametersVariable;
}
/**
* @param $aVariableFiles
*
* @return array
* @since 3.0.0 N°3593
*/
public static function GetVariablesFromFile($aVariableFiles){
$aVariablesResults = [];
foreach ($aVariableFiles as $sVariableFile)
{
$sFileContent = file_get_contents(APPROOT.'env-'.utils::GetCurrentEnvironment().'/'.$sVariableFile);
$aVariableMatches = [];
preg_match_all( '/\$(.*?):(.*?);/', $sFileContent,$aVariableMatches);
$aVariableMatches = array_combine( $aVariableMatches[1], array_map( function($sVariableValue) { return ltrim($sVariableValue); }, $aVariableMatches[2] ) );
$aVariablesResults = array_merge($aVariablesResults, $aVariableMatches);
}
array_map( function($sVariableValue) { return ltrim($sVariableValue); }, $aVariablesResults );
return $aVariablesResults;
}
}

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//
@@ -23,7 +23,7 @@
* which choice is configured via the parameter 'transaction_storage'
*
* @package iTop
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
@@ -21,7 +21,7 @@
* UI wdiget for displaying and editing one-way encrypted passwords
*
* @author Romain Quetiez
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -70,7 +70,11 @@ class UIHTMLEditorWidget
// To change the default settings of the editor,
// a) edit the file /js/ckeditor/config.js
// b) or override some of the configuration settings, using the second parameter of ckeditor()
$aConfig = utils::GetCkeditorPref();
$aConfig = array();
$sLanguage = strtolower(trim(UserRights::GetUserLanguage()));
$aConfig['language'] = $sLanguage;
$aConfig['contentsLanguage'] = $sLanguage;
$aConfig['extraPlugins'] = 'disabler,codesnippet';
$sWidthSpec = addslashes(trim($this->m_oAttDef->GetWidth()));
if ($sWidthSpec != '')
{
@@ -93,10 +97,10 @@ class UIHTMLEditorWidget
// The most relevant solution would be to implement a plugin to CKEdit, and handle the internal events like: setData, insertHtml, insertElement, loadSnapshot, key, afterUndo, afterRedo
// Could also be bound to 'instanceReady.ckeditor'
$oPage->add_ready_script("$('#$iId').on('validate', function(evt, sFormId) { return ValidateCKEditField('$iId', '', {$this->m_sMandatory}, sFormId, '') } );\n");
$oPage->add_ready_script("$('#$iId').bind('validate', function(evt, sFormId) { return ValidateCKEditField('$iId', '', {$this->m_sMandatory}, sFormId, '') } );\n");
$oPage->add_ready_script(
<<<EOF
$('#$iId').on('update', function(evt){
$('#$iId').bind('update', function(evt){
BlockField('cke_$iId', $('#$iId').prop('disabled'));
//Delayed execution - ckeditor must be properly initialized before setting readonly
var retryCount = 0;

View File

@@ -1,18 +1,28 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
// Copyright (C) 2010-2017 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Class UILinksWidgetDirect
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
*
* @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
*/
class UILinksWidgetDirect
{
protected $sClass;
@@ -174,7 +184,7 @@ class UILinksWidgetDirect
// For security reasons: check that the "proposed" class is actually a subclass of the linked class
// and that the current user is allowed to create objects of this class
$sRealClass = '';
//$oPage->add('<div class="wizContainer" style="vertical-align:top;"><div>');
$oPage->add('<div class="wizContainer" style="vertical-align:top;"><div>');
$aSubClasses = MetaModel::EnumChildClasses($this->sLinkedClass, ENUM_CHILD_CLASSES_ALL); // Including the specified class itself
$aPossibleClasses = array();
foreach($aSubClasses as $sCandidateClass)
@@ -233,21 +243,23 @@ class UILinksWidgetDirect
protected function DisplayEditInPlace(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $aButtons = array('create', 'delete'))
{
$aAttribs = $this->GetTableConfig();
$oValue->Rewind();
$oPage->add('<table class="listContainer" id="'.$this->sInputid.'"><tr><td>');
$aData = array();
while ($oLinkObj = $oValue->Fetch()) {
while($oLinkObj = $oValue->Fetch())
{
$aRow = array();
$aRow['form::select'] = '<input type="checkbox" class="selectList'.$this->sInputid.'" value="'.$oLinkObj->GetKey().'"/>';
foreach ($this->aZlist as $sLinkedAttCode) {
foreach($this->aZlist as $sLinkedAttCode)
{
$aRow[$sLinkedAttCode] = $oLinkObj->GetAsHTML($sLinkedAttCode);
}
$aData[] = $aRow;
}
$oDiv = UIContentBlockUIBlockFactory::MakeStandard($this->sInputid, ['listContainer']);
$oPage->AddSubBlock($oDiv);
$oDatatable = DataTableUIBlockFactory::MakeForForm($this->sInputid, $aAttribs, $aData);
$oDatatable->SetOptions(['select_mode' => 'custom']);
$oDiv->AddSubBlock($oDatatable);
$oPage->table($aAttribs, $aData);
$oPage->add('</td></tr></table>'); //listcontainer
$sInputName = $sFormPrefix.'attr_'.$this->sAttCode;
$aLabels = array(
'delete' => Dict::S('UI:Button:Delete'),
@@ -282,17 +294,20 @@ class UILinksWidgetDirect
*/
public function GetObjectsSelectionDlg($oPage, $oCurrentObj, $aAlreadyLinked, $aPrefillFormParam = array())
{
//$oPage->add("<div class=\"wizContainer\" style=\"vertical-align:top;\">\n");
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
$oHiddenFilter = new DBObjectSearch($this->sLinkedClass);
if (($oCurrentObj != null) && MetaModel::IsSameFamilyBranch($this->sLinkedClass, $this->sClass)) {
if (($oCurrentObj != null) && MetaModel::IsSameFamilyBranch($this->sLinkedClass, $this->sClass))
{
// Prevent linking to self if the linked object is of the same family
// and already present in the database
if (!$oCurrentObj->IsNew()) {
if (!$oCurrentObj->IsNew())
{
$oHiddenFilter->AddCondition('id', $oCurrentObj->GetKey(), '!=');
}
}
if (count($aAlreadyLinked) > 0) {
if (count($aAlreadyLinked) > 0)
{
$oHiddenFilter->AddCondition('id', $aAlreadyLinked, 'NOTIN');
}
$oHiddenCriteria = $oHiddenFilter->GetCriteria();
@@ -304,14 +319,18 @@ class UILinksWidgetDirect
if ($valuesDef === null)
{
$oFilter = new DBObjectSearch($this->sLinkedClass);
} else {
if (!$valuesDef instanceof ValueSetObjects) {
}
else
{
if (!$valuesDef instanceof ValueSetObjects)
{
throw new Exception('Error: only ValueSetObjects are supported for "allowed_values" in AttributeLinkedSet ('.$this->sClass.'/'.$this->sAttCode.').');
}
$oFilter = DBObjectSearch::FromOQL($valuesDef->GetFilterExpression());
}
if ($oCurrentObj != null) {
if ($oCurrentObj != null)
{
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
$aArgs = array_merge($oCurrentObj->ToArgs('this'), $oFilter->GetInternalParams());
@@ -320,7 +339,7 @@ class UILinksWidgetDirect
$oCurrentObj->PrefillForm('search', $aPrefillFormParam);
}
$oBlock = new DisplayBlock($oFilter, 'search', false);
$oPage->AddUiBlock($oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->sInputid}",
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->sInputid}",
array(
'result_list_outer_selector' => "SearchResultsToAdd_{$this->sInputid}",
'table_id' => "add_{$this->sInputid}",
@@ -330,21 +349,16 @@ class UILinksWidgetDirect
'query_params' => $oFilter->GetInternalParams(),
'hidden_criteria' => $sHiddenCriteria,
)
));
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
$sCancel = Dict::S('UI:Button:Cancel');
$sAdd = Dict::S('UI:Button:Add');
$oPage->add(<<<HTML
<form id="ObjectsAddForm_{$this->sInputid}">
<div id="SearchResultsToAdd_{$this->sInputid}" style="vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;">
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
</div>
<input type="hidden" id="count_{$this->sInputid}" value="0"/>
<button type="button" class="cancel">{$sCancel}</button>&nbsp;&nbsp;<button type="button" class="ok" disabled="disabled">{$sAdd}</button>
</form>
HTML
);
);
$sHtml .= "<form id=\"ObjectsAddForm_{$this->sInputid}\">\n";
$sHtml .= "<div id=\"SearchResultsToAdd_{$this->sInputid}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
$sHtml .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
$sHtml .= "</div>\n";
$sHtml .= "<input type=\"hidden\" id=\"count_{$this->sInputid}\" value=\"0\"/>";
$sHtml .= "<button type=\"button\" class=\"cancel\">".Dict::S('UI:Button:Cancel')."</button>&nbsp;&nbsp;<button type=\"button\" class=\"ok\" disabled=\"disabled\">".Dict::S('UI:Button:Add')."</button>";
$sHtml .= "</div>\n";
$sHtml .= "</form>\n";
$oPage->add($sHtml);
}
/**

View File

@@ -1,15 +1,30 @@
<?php
/*
* @copyright Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2017 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Class UILinksWidget
*
* @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\DataTable\StaticTable\FormTableRow\FormTableRow;
use Combodo\iTop\Application\UI\Links\Indirect\BlockIndirectLinksEdit\BlockIndirectLinksEdit;
use Combodo\iTop\Application\UI\Links\Indirect\BlockObjectPickerDialog\BlockObjectPickerDialog;
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
require_once(APPROOT.'application/webpage.class.inc.php');
require_once(APPROOT.'application/displayblock.class.inc.php');
class UILinksWidget
@@ -24,7 +39,6 @@ class UILinksWidget
protected $m_sLinkedClass;
protected $m_sRemoteClass;
protected $m_bDuplicatesAllowed;
/** @var string[] list of editables attcodes */
protected $m_aEditableFields;
protected $m_aTableConfig;
@@ -32,7 +46,7 @@ class UILinksWidget
* UILinksWidget constructor.
*
* @param string $sClass
* @param string $sAttCode AttributeLinkedSetIndirect attcode
* @param string $sAttCode
* @param int $iInputId
* @param string $sNameSuffix
* @param bool $bDuplicatesAllowed
@@ -59,35 +73,41 @@ class UILinksWidget
/** @var AttributeExternalKey $oLinkingAttDef */
$oLinkingAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $this->m_sExtKeyToRemote);
$this->m_sRemoteClass = $oLinkingAttDef->GetTargetClass();
$sExtKeyToMe = $oAttDef->GetExtKeyToMe();
$sStateAttCode = MetaModel::GetStateAttributeCode($this->m_sClass);
$sDefaultState = MetaModel::GetDefaultState($this->m_sClass);
$this->m_aEditableFields = array();
$this->m_aTableConfig = array();
$this->m_aTableConfig['form::checkbox'] = array(
'label' => "<input class=\"select_all\" type=\"checkbox\" value=\"1\" onClick=\"CheckAll('#linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix} .selection', this.checked); oWidget".$this->m_iInputId.".OnSelectChange();\">",
'description' => Dict::S('UI:SelectAllToggle+'),
);
$this->m_aTableConfig['form::checkbox'] = array( 'label' => "<input class=\"select_all\" type=\"checkbox\" value=\"1\" onClick=\"CheckAll('#linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix} .selection', this.checked); oWidget".$this->m_iInputId.".OnSelectChange();\">", 'description' => Dict::S('UI:SelectAllToggle+'));
$aLnkAttDefsToDisplay = MetaModel::GetZListAttDefsFilteredForIndirectLinkClass($sClass, $sAttCode);
foreach ($aLnkAttDefsToDisplay as $oLnkAttDef)
foreach(MetaModel::FlattenZList(MetaModel::GetZListItems($this->m_sLinkedClass, 'list')) as $sAttCode)
{
$sLnkAttCode = $oLnkAttDef->GetCode();
$this->m_aEditableFields[] = $sLnkAttCode;
$this->m_aTableConfig[$sLnkAttCode] = array('label' => $oLnkAttDef->GetLabel(), 'description' => $oLnkAttDef->GetDescription());
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sAttCode);
if ($sStateAttCode == $sAttCode)
{
// State attribute is always hidden from the UI
}
else if ($oAttDef->IsWritable() && ($sAttCode != $sExtKeyToMe) && ($sAttCode != $this->m_sExtKeyToRemote) && ($sAttCode != 'finalclass'))
{
$iFlags = MetaModel::GetAttributeFlags($this->m_sLinkedClass, $sDefaultState, $sAttCode);
if ( !($iFlags & OPT_ATT_HIDDEN) && !($iFlags & OPT_ATT_READONLY) )
{
$this->m_aEditableFields[] = $sAttCode;
$this->m_aTableConfig[$sAttCode] = array( 'label' => $oAttDef->GetLabel(), 'description' => $oAttDef->GetDescription());
}
}
}
$this->m_aTableConfig['static::key'] = array(
'label' => MetaModel::GetName($this->m_sRemoteClass),
'description' => MetaModel::GetClassDescription($this->m_sRemoteClass),
);
$this->m_aEditableFields[] = $this->m_sExtKeyToRemote;
$aRemoteAttDefsToDisplay = MetaModel::GetZListAttDefsFilteredForIndirectRemoteClass($this->m_sRemoteClass);
foreach ($aRemoteAttDefsToDisplay as $oRemoteAttDef) {
$sRemoteAttCode = $oRemoteAttDef->GetCode();
$this->m_aTableConfig['static::'.$sRemoteAttCode] = array(
'label' => $oRemoteAttDef->GetLabel(),
'description' => $oRemoteAttDef->GetDescription(),
);
$this->m_aTableConfig['static::key'] = array( 'label' => MetaModel::GetName($this->m_sRemoteClass), 'description' => MetaModel::GetClassDescription($this->m_sRemoteClass));
foreach(MetaModel::GetZListItems($this->m_sRemoteClass, 'list') as $sFieldCode)
{
// TO DO: check the state of the attribute: hidden or visible ?
if ($sFieldCode != 'finalclass')
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sRemoteClass, $sFieldCode);
$this->m_aTableConfig['static::'.$sFieldCode] = array( 'label' => $oAttDef->GetLabel(), 'description' => $oAttDef->GetDescription());
}
}
}
@@ -96,7 +116,7 @@ class UILinksWidget
*
* @param WebPage $oP Web page used for the ouput
* @param DBObject $oLinkedObj Remote object
* @param DBObject|int $linkObjOrId Either the lnk object or a unique number for new link records to add
* @param mixed $linkObjOrId Either the object linked or a unique number for new link records to add
* @param array $aArgs Extra context arguments
* @param DBObject $oCurrentObj The object to which all the elements of the linked set refer to
* @param int $iUniqueId A unique identifier of new links
@@ -114,39 +134,43 @@ class UILinksWidget
$aRow = array();
$aFieldsMap = array();
$iKey = 0;
if (is_object($linkObjOrId) && (!$linkObjOrId->IsNew()))
if(is_object($linkObjOrId) && (!$linkObjOrId->IsNew()))
{
$iKey = $linkObjOrId->GetKey();
$iRemoteObjKey = $linkObjOrId->Get($this->m_sExtKeyToRemote);
$iRemoteObjKey = $linkObjOrId->Get($this->m_sExtKeyToRemote);
$sPrefix .= "[$iKey][";
$sNameSuffix = "]"; // To make a tabular form
$aArgs['prefix'] = $sPrefix;
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}{$iKey}";
$aArgs['this'] = $linkObjOrId;
if ($bReadOnly)
{
$aRow['form::checkbox'] = "";
foreach ($this->m_aEditableFields as $sFieldCode)
{
$sDisplayValue = $linkObjOrId->GetEditValue($sFieldCode);
$aRow[$sFieldCode] = $sDisplayValue;
}
}
else
{
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"$iKey\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$iKey\">";
foreach ($this->m_aEditableFields as $sFieldCode)
{
$sSafeFieldId = $this->GetFieldId($linkObjOrId->GetKey(), $sFieldCode);
$this->AddRowForFieldCode($aRow, $sFieldCode, $aArgs, $linkObjOrId, $oP, $sNameSuffix, $sSafeFieldId);
$aFieldsMap[$sFieldCode] = $sSafeFieldId;
}
}
if($bReadOnly)
{
$aRow['form::checkbox'] = "";
foreach($this->m_aEditableFields as $sFieldCode)
{
$sDisplayValue = $linkObjOrId->GetEditValue($sFieldCode);
$aRow[$sFieldCode] = $sDisplayValue;
}
}
else
{
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"$iKey\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$iKey\">";
foreach($this->m_aEditableFields as $sFieldCode)
{
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.$linkObjOrId->GetKey().']';
$sSafeId = utils::GetSafeId($sFieldId);
$sValue = $linkObjOrId->Get($sFieldCode);
$sDisplayValue = $linkObjOrId->GetEditValue($sFieldCode);
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
$aRow[$sFieldCode] = '<div class="field_container" style="border:none;"><div class="field_data"><div class="field_value">'.
cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $sValue, $sDisplayValue, $sSafeId, $sNameSuffix, 0, $aArgs).
'</div></div></div>';
$aFieldsMap[$sFieldCode] = $sSafeId;
}
}
$sState = $linkObjOrId->GetState();
$sRemoteKeySafeFieldId = $this->GetFieldId($aArgs['this']->GetKey(), $this->m_sExtKeyToRemote);;
}
else
{
@@ -156,18 +180,15 @@ class UILinksWidget
// New link existing only in memory
$oNewLinkObj = $linkObjOrId;
$iRemoteObjKey = $oNewLinkObj->Get($this->m_sExtKeyToRemote);
$oNewLinkObj->Set($this->m_sExtKeyToMe,
$oCurrentObj); // Setting the extkey with the object also fills the related external fields
$oNewLinkObj->Set($this->m_sExtKeyToMe, $oCurrentObj); // Setting the extkey with the object also fills the related external fields
}
else
{
$iRemoteObjKey = $linkObjOrId;
$oNewLinkObj = MetaModel::NewObject($this->m_sLinkedClass);
$oRemoteObj = MetaModel::GetObject($this->m_sRemoteClass, $iRemoteObjKey);
$oNewLinkObj->Set($this->m_sExtKeyToRemote,
$oRemoteObj); // Setting the extkey with the object alsoo fills the related external fields
$oNewLinkObj->Set($this->m_sExtKeyToMe,
$oCurrentObj); // Setting the extkey with the object also fills the related external fields
$oNewLinkObj->Set($this->m_sExtKeyToRemote, $oRemoteObj); // Setting the extkey with the object alsoo fills the related external fields
$oNewLinkObj->Set($this->m_sExtKeyToMe, $oCurrentObj); // Setting the extkey with the object also fills the related external fields
}
$sPrefix .= "[-$iUniqueId][";
$sNameSuffix = "]"; // To make a tabular form
@@ -201,136 +222,113 @@ EOF
foreach($this->m_aEditableFields as $sFieldCode)
{
$sSafeFieldId = $this->GetFieldId($iUniqueId, $sFieldCode);
$this->AddRowForFieldCode($aRow, $sFieldCode, $aArgs, $oNewLinkObj, $oP, $sNameSuffix, $sSafeFieldId);
$aFieldsMap[$sFieldCode] = $sSafeFieldId;
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.-$iUniqueId.']';
$sSafeId = utils::GetSafeId($sFieldId);
$sValue = $oNewLinkObj->Get($sFieldCode);
$oP->add_ready_script(
<<<JS
$sDisplayValue = $oNewLinkObj->GetEditValue($sFieldCode);
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
$aRow[$sFieldCode] = '<div class="field_container" style="border:none;"><div class="field_data"><div class="field_value">'.
cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $sValue, $sDisplayValue, $sSafeId /* id */, $sNameSuffix, 0, $aArgs).
'</div></div></div>';
$aFieldsMap[$sFieldCode] = $sSafeId;
$oP->add_ready_script(<<<EOF
oWidget{$this->m_iInputId}.OnValueChange($iKey, $iUniqueId, '$sFieldCode', '$sValue');
JS
);
EOF
);
}
$sState = '';
$sRemoteKeySafeFieldId = $this->GetFieldId($iUniqueId, $this->m_sExtKeyToRemote);
}
if (!$bReadOnly)
{
$sExtKeyToMeId = utils::GetSafeId($sPrefix.$this->m_sExtKeyToMe);
$aFieldsMap[$this->m_sExtKeyToMe] = $sExtKeyToMeId;
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToMeId\" value=\"".$oCurrentObj->GetKey()."\">";
if(!$bReadOnly)
{
$sExtKeyToMeId = utils::GetSafeId($sPrefix.$this->m_sExtKeyToMe);
$aFieldsMap[$this->m_sExtKeyToMe] = $sExtKeyToMeId;
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToMeId\" value=\"".$oCurrentObj->GetKey()."\">";
$sExtKeyToRemoteId = utils::GetSafeId($sPrefix.$this->m_sExtKeyToRemote);
$aFieldsMap[$this->m_sExtKeyToRemote] = $sExtKeyToRemoteId;
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToRemoteId\" value=\"$iRemoteObjKey\">";
}
$sExtKeyToRemoteId = utils::GetSafeId($sPrefix.$this->m_sExtKeyToRemote);
$aFieldsMap[$this->m_sExtKeyToRemote] = $sExtKeyToRemoteId;
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToRemoteId\" value=\"$iRemoteObjKey\">";
}
// Adding fields from remote class
// all fields are embedded in a span + added to $aFieldsMap array so that we can refresh them after extkey change
$aRemoteFieldsMap = [];
foreach (MetaModel::GetZListItems($this->m_sRemoteClass, 'list') as $sFieldCode)
{
$sSafeFieldId = $this->GetFieldId($aArgs['this']->GetKey(), $sFieldCode);
$aRow['static::'.$sFieldCode] = "<span id='field_$sSafeFieldId'>".$oLinkedObj->GetAsHTML($sFieldCode).'</span>';
$aRemoteFieldsMap[$sFieldCode] = $sSafeFieldId;
}
// id field is needed so that remote object could be load server side
$aRemoteFieldsMap['id'] = $sRemoteKeySafeFieldId;
// Generate WizardHelper to update dependant fields
$this->AddWizardHelperInit($oP, $aArgs['wizHelper'], $this->m_sLinkedClass, $sState, $aFieldsMap);
//instantiate specific WizarHelper instance for remote class fields refresh
$bHasExtKeyUpdatingRemoteClassFields = (
array_key_exists('replaceDependenciesByRemoteClassFields', $aArgs)
&& ($aArgs['replaceDependenciesByRemoteClassFields'])
$iFieldsCount = count($aFieldsMap);
$sJsonFieldsMap = json_encode($aFieldsMap);
$oP->add_script(
<<<EOF
var {$aArgs['wizHelper']} = new WizardHelper('{$this->m_sLinkedClass}', '', '$sState');
{$aArgs['wizHelper']}.SetFieldsMap($sJsonFieldsMap);
{$aArgs['wizHelper']}.SetFieldsCount($iFieldsCount);
EOF
);
if ($bHasExtKeyUpdatingRemoteClassFields)
$aRow['static::key'] = $oLinkedObj->GetHyperLink();
foreach(MetaModel::GetZListItems($this->m_sRemoteClass, 'list') as $sFieldCode)
{
$this->AddWizardHelperInit($oP, $aArgs['wizHelperRemote'], $this->m_sRemoteClass, $sState, $aRemoteFieldsMap);
$aRow['static::'.$sFieldCode] = $oLinkedObj->GetAsHTML($sFieldCode);
}
return $aRow;
}
private function AddRowForFieldCode(&$aRow, $sFieldCode, &$aArgs, $oLnk, $oP, $sNameSuffix, $sSafeFieldId): void
/**
* Display one row of the whole form
* @param WebPage $oP
* @param array $aConfig
* @param array $aRow
* @param int $iRowId
* @return string
*/
protected function DisplayFormRow(WebPage $oP, $aConfig, $aRow, $iRowId)
{
if (($sFieldCode === $this->m_sExtKeyToRemote))
$sHtml = '';
$sHtml .= "<tr id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_row_$iRowId\">\n";
foreach($aConfig as $sName=>$void)
{
// current field is the lnk extkey to the remote class
$aArgs['replaceDependenciesByRemoteClassFields'] = true;
$sRowFieldCode = 'static::key';
$aArgs['wizHelperRemote'] = $aArgs['wizHelper'].'_remote';
$aRemoteAttDefs = MetaModel::GetZListAttDefsFilteredForIndirectRemoteClass($this->m_sRemoteClass);
$aRemoteCodes = array_map(
function ($value) {
return $value->GetCode();
},
$aRemoteAttDefs
);
$aArgs['remoteCodes'] = $aRemoteCodes;
$sHtml .= "<td>".$aRow[$sName]."</td>\n";
}
else
{
$aArgs['replaceDependenciesByRemoteClassFields'] = false;
$sRowFieldCode = $sFieldCode;
}
$sValue = $oLnk->Get($sFieldCode);
$sDisplayValue = $oLnk->GetEditValue($sFieldCode);
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
$aRow[$sRowFieldCode] = '<div class="field_container" style="border:none;"><div class="field_data"><div class="field_value">'
.cmdbAbstractObject::GetFormElementForField(
$oP,
$this->m_sLinkedClass,
$sFieldCode,
$oAttDef,
$sValue,
$sDisplayValue,
$sSafeFieldId,
$sNameSuffix,
0,
$aArgs
)
.'</div></div></div>';
$sHtml .= "</tr>\n";
return $sHtml;
}
private function GetFieldId($iLnkId, $sFieldCode, $bSafe = true)
{
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.$iLnkId.']';
return ($bSafe) ? utils::GetSafeId($sFieldId) : $sFieldId;
}
private function AddWizardHelperInit($oP, $sWizardHelperVarName, $sWizardHelperClass, $sState, $aFieldsMap): void
{
$iFieldsCount = count($aFieldsMap);
$sJsonFieldsMap = json_encode($aFieldsMap);
$oP->add_script(
<<<JS
var $sWizardHelperVarName = new WizardHelper('$sWizardHelperClass', '', '$sState');
$sWizardHelperVarName.SetFieldsMap($sJsonFieldsMap);
$sWizardHelperVarName.SetFieldsCount($iFieldsCount);
$sWizardHelperVarName.SetReturnNotEditableFields(true);
$sWizardHelperVarName.SetWizHelperJsVarName('$sWizardHelperVarName');
JS
);
}
/**
* Display the table with the form for editing all the links at once
*
* @param WebPage $oP The web page used for the output
* @param array $aConfig The table's header configuration
* @param array $aData The tabular data to be displayed
*
* @return \Combodo\iTop\Application\UI\Base\Component\DataTable\StaticTable\FormTable\FormTable
* @return string Html fragment representing the form table
*/
protected function GetFormTableBlock($aConfig, $aData)
protected function DisplayFormTable(WebPage $oP, $aConfig, $aData)
{
return DataTableUIBlockFactory::MakeForForm("{$this->m_sAttCode}{$this->m_sNameSuffix}", $aConfig, $aData);
$sHtml = "<input type=\"hidden\" name=\"attr_{$this->m_sAttCode}{$this->m_sNameSuffix}\" value=\"\">";
$sHtml .= "<table class=\"listResults\">\n";
// Header
$sHtml .= "<thead>\n";
$sHtml .= "<tr>\n";
foreach($aConfig as $sName=>$aDef)
{
$sHtml .= "<th title=\"".$aDef['description']."\">".$aDef['label']."</th>\n";
}
$sHtml .= "</tr>\n";
$sHtml .= "</thead>\n";
// Content
$sHtml .= "</tbody>\n";
$sEmptyRowStyle = '';
if (count($aData) != 0)
{
$sEmptyRowStyle = 'style="display:none;"';
}
foreach($aData as $iRowId => $aRow)
{
$sHtml .= $this->DisplayFormRow($oP, $aConfig, $aRow, $iRowId);
}
$sHtml .= "<tr $sEmptyRowStyle id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_empty_row\"><td colspan=\"".count($aConfig)."\" style=\"text-align:center;\">".Dict::S('UI:Message:EmptyList:UseAdd')."</td></tr>";
$sHtml .= "</tbody>\n";
// Footer
$sHtml .= "</table>\n";
return $sHtml;
}
@@ -345,65 +343,63 @@ JS
*
* @return string The HTML fragment to be inserted into the page
* @throws \ArchivedObjectException
* @throws \ConfigException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
* @throws \ReflectionException
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
* @throws \DictExceptionMissingString
*/
public function Display(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj): string
public function Display(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj)
{
$sLinkedSetId = "{$this->m_sAttCode}{$this->m_sNameSuffix}";
$oBlock = new BlockIndirectLinksEdit("linkedset_{$sLinkedSetId}", ["ibo-block-indirect-links--edit"]);
$oBlock->sLinkedSetId = $sLinkedSetId;
$oBlock->sClass = $this->m_sClass;
$oBlock->sAttCode = $this->m_sAttCode;
$oBlock->iInputId = $this->m_iInputId;
$oBlock->sNameSuffix = $this->m_sNameSuffix;
$oBlock->bDuplicates = ($this->m_bDuplicatesAllowed) ? 'true' : 'false';
$oBlock->oWizHelper = 'oWizardHelper'.$sFormPrefix;
$oBlock->sExtKeyToRemote = $this->m_sExtKeyToRemote;
// Don't automatically launch the search if the table is huge
$oBlock->bJSDoSearch = utils::IsHighCardinality($this->m_sRemoteClass) ? 'false' : 'true';
$oBlock->sFormPrefix = $sFormPrefix;
$oBlock->sRemoteClass = $this->m_sRemoteClass;
$sHtmlValue = '';
$sHtmlValue .= "<div id=\"linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix}\">\n";
$sHtmlValue .= "<input type=\"hidden\" id=\"{$sFormPrefix}{$this->m_iInputId}\">\n";
$oValue->Rewind();
$aForm = array();
$iAddedId = -1; // Unique id for new links
while ($oCurrentLink = $oValue->Fetch())
$sDuplicates = ($this->m_bDuplicatesAllowed) ? 'true' : 'false';
// Don't automatically launch the search if the table is huge
$bDoSearch = !utils::IsHighCardinality($this->m_sRemoteClass);
$sJSDoSearch = $bDoSearch ? 'true' : 'false';
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
$oPage->add_ready_script(<<<EOF
oWidget{$this->m_iInputId} = new LinksWidget('{$this->m_sAttCode}{$this->m_sNameSuffix}', '{$this->m_sClass}', '{$this->m_sAttCode}', '{$this->m_iInputId}', '{$this->m_sNameSuffix}', $sDuplicates, $sWizHelper, '{$this->m_sExtKeyToRemote}', $sJSDoSearch);
oWidget{$this->m_iInputId}.Init();
EOF
);
while($oCurrentLink = $oValue->Fetch())
{
// We try to retrieve the remote object as usual
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote),
false /* Must not be found */);
// We try to retrieve the remote object as usual
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote), false /* Must not be found */);
// If successful, it means that we can edit its link
if ($oLinkedObj !== null) {
$bReadOnly = false;
} // Else we retrieve it without restrictions (silos) and will display its link as readonly
else {
$bReadOnly = true;
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote), false /* Must not be found */, true);
}
if($oLinkedObj !== null)
{
$bReadOnly = false;
}
// Else we retrieve it without restrictions (silos) and will display its link as readonly
else
{
$bReadOnly = true;
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $oCurrentLink->Get($this->m_sExtKeyToRemote), false /* Must not be found */, true);
}
if ($oCurrentLink->IsNew()) {
$key = $iAddedId--;
} else {
$key = $oCurrentLink->GetKey();
}
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs, $oCurrentObj, $key, $bReadOnly);
if ($oCurrentLink->IsNew())
{
$key = $iAddedId--;
}
else
{
$key = $oCurrentLink->GetKey();
}
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs, $oCurrentObj, $key, $bReadOnly);
}
$oDataTable = DataTableUIBlockFactory::MakeForForm("{$this->m_sAttCode}{$this->m_sNameSuffix}", $this->m_aTableConfig, $aForm);
$oDataTable->SetOptions(['select_mode' => 'custom']);
$oBlock->AddSubBlock($oDataTable);
$sHtmlValue .= $this->DisplayFormTable($oPage, $this->m_aTableConfig, $aForm);
$oBlock->AddControls();
return ConsoleBlockRenderer::RenderBlockTemplateInPage($oPage, $oBlock);
$sHtmlValue .= "<span style=\"float:left;\">&nbsp;&nbsp;&nbsp;<img src=\"../images/tv-item-last.gif\">&nbsp;&nbsp;<input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnRemove\" type=\"button\" value=\"".Dict::S('UI:RemoveLinkedObjectsOf_Class')."\" onClick=\"oWidget{$this->m_iInputId}.RemoveSelected();\" >";
$sHtmlValue .= "&nbsp;&nbsp;&nbsp;<input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnAdd\" type=\"button\" value=\"".Dict::Format('UI:AddLinkedObjectsOf_Class', MetaModel::GetName($this->m_sRemoteClass))."\" onClick=\"oWidget{$this->m_iInputId}.AddObjects();\"><span id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_indicatorAdd\"></span></span>\n";
$sHtmlValue .= "<span style=\"clear:both;\"><p>&nbsp;</p></span>\n";
$sHtmlValue .= "</div>\n";
$oPage->add_at_the_end("<div id=\"dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}\"></div>"); // To prevent adding forms inside the main form
return $sHtmlValue;
}
/**
@@ -447,49 +443,55 @@ JS
*/
public function GetObjectPickerDialog($oPage, $oCurrentObj, $sJson, $aAlreadyLinkedIds = array(), $aPrefillFormParam = array())
{
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
$oAlreadyLinkedFilter = new DBObjectSearch($this->m_sRemoteClass);
if (!$this->m_bDuplicatesAllowed && count($aAlreadyLinkedIds) > 0) {
if (!$this->m_bDuplicatesAllowed && count($aAlreadyLinkedIds) > 0)
{
$oAlreadyLinkedFilter->AddCondition('id', $aAlreadyLinkedIds, 'NOTIN');
$oAlreadyLinkedExpression = $oAlreadyLinkedFilter->GetCriteria();
$sAlreadyLinkedExpression = $oAlreadyLinkedExpression->RenderExpression();
} else {
$sAlreadyLinkedExpression = $oAlreadyLinkedExpression->Render();
}
else
{
$sAlreadyLinkedExpression = '';
}
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
if (!empty($oCurrentObj)) {
if(!empty($oCurrentObj))
{
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
$aPrefillFormParam['filter'] = $oFilter;
$aPrefillFormParam['dest_class'] = $this->m_sRemoteClass;
$oCurrentObj->PrefillForm('search', $aPrefillFormParam);
}
$sLinkedSetId = "{$this->m_sAttCode}{$this->m_sNameSuffix}";
$oBlock = new BlockObjectPickerDialog();
$oPage->AddUiBlock($oBlock);
$oBlock->sLinkedSetId = $sLinkedSetId;
$oBlock->iInputId = $this->m_iInputId;
$oBlock->sLinkedClassName = MetaModel::GetName($this->m_sLinkedClass);
$oBlock->sClassName = MetaModel::GetName($this->m_sClass);
$oDisplayBlock = new DisplayBlock($oFilter, 'search', false);
$oBlock->AddSubBlock($oDisplayBlock->GetDisplay($oPage, "SearchFormToAdd_{$sLinkedSetId}",
$oBlock = new DisplayBlock($oFilter, 'search', false);
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}",
array(
'menu' => false,
'result_list_outer_selector' => "SearchResultsToAdd_{$sLinkedSetId}",
'table_id' => "add_{$sLinkedSetId}",
'table_inner_id' => "ResultsToAdd_{$sLinkedSetId}",
'result_list_outer_selector' => "SearchResultsToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}",
'table_id' => 'add_'.$this->m_sAttCode,
'table_inner_id' => "ResultsToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}",
'selection_mode' => true,
'json' => $sJson,
'cssCount' => '#count_'.$this->m_sAttCode.$this->m_sNameSuffix,
'query_params' => $oFilter->GetInternalParams(),
'hidden_criteria' => $sAlreadyLinkedExpression,
)));
$oBlock->AddForm();
));
$sHtml .= "<form id=\"ObjectsAddForm_{$this->m_sAttCode}{$this->m_sNameSuffix}\">\n";
$sHtml .= "<div id=\"SearchResultsToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
$sHtml .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
$sHtml .= "</div>\n";
$sHtml .= "<input type=\"hidden\" id=\"count_{$this->m_sAttCode}{$this->m_sNameSuffix}\" value=\"0\"/>";
$sHtml .= "<input type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('close');\">&nbsp;&nbsp;<input id=\"btn_ok_{$this->m_sAttCode}{$this->m_sNameSuffix}\" disabled=\"disabled\" type=\"button\" onclick=\"return oWidget{$this->m_iInputId}.DoAddObjects(this.id);\" value=\"".Dict::S('UI:Button:Add')."\">";
$sHtml .= "</div>\n";
$sHtml .= "</form>\n";
$oPage->add($sHtml);
$oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, resizeStop: oWidget{$this->m_iInputId}.UpdateSizes });");
$oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('option', {title:'".addslashes(Dict::Format('UI:AddObjectsOf_Class_LinkedWith_Class', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName($this->m_sClass)))."'});");
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix} form').bind('submit.uilinksWizard', oWidget{$this->m_iInputId}.SearchObjectsToAdd);");
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}').resize(oWidget{$this->m_iInputId}.UpdateSizes);");
}
/**
@@ -539,44 +541,17 @@ JS
$aLinkedObjectIds = utils::ReadMultipleSelection($oFullSetFilter);
$iAdditionId = $iMaxAddedId + 1;
foreach ($aLinkedObjectIds as $iObjectId) {
foreach($aLinkedObjectIds as $iObjectId)
{
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $iObjectId, false);
if (is_object($oLinkedObj)) {
if (is_object($oLinkedObj))
{
$aRow = $this->GetFormRow($oP, $oLinkedObj, $iObjectId, array(), $oCurrentObj, $iAdditionId); // Not yet created link get negative Ids
$oRow = new FormTableRow("{$this->m_sAttCode}{$this->m_sNameSuffix}", $this->m_aTableConfig, $aRow, -$iAdditionId);
$oP->AddUiBlock($oRow);
$oP->add($this->DisplayFormRow($oP, $this->m_aTableConfig, $aRow, -$iAdditionId));
$iAdditionId++;
} else {
$oP->p(Dict::Format('UI:Error:Object_Class_Id_NotFound', $this->m_sLinkedClass, $iObjectId));
}
}
}
/**
* @param WebPage $oP
* @param int $iMaxAddedId
* @param $oFullSetFilter
* @param DBObject $oCurrentObj
*
* @throws \ArchivedObjectException
* @throws \CoreException
*/
public function DoAddIndirectLinks(JsonPage $oP, $iMaxAddedId, $oFullSetFilter, $oCurrentObj)
{
$aLinkedObjectIds = utils::ReadMultipleSelection($oFullSetFilter);
$iAdditionId = $iMaxAddedId + 1;
foreach ($aLinkedObjectIds as $iObjectId) {
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $iObjectId, false);
if (is_object($oLinkedObj)) {
$aRow = $this->GetFormRow($oP, $oLinkedObj, $iObjectId, array(), $oCurrentObj, $iAdditionId); // Not yet created link get negative Ids
$aData = [];
foreach ($aRow as $item) {
$aData[] = $item;
}
$oP->AddData($aData);
$iAdditionId++;
} else {
else
{
$oP->p(Dict::Format('UI:Error:Object_Class_Id_NotFound', $this->m_sLinkedClass, $iObjectId));
}
}

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -20,10 +20,11 @@
* Class UIPasswordWidget
* UI wdiget for displaying and editing one-way encrypted passwords
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/application/webpage.class.inc.php');
require_once(APPROOT.'/application/displayblock.class.inc.php');
class UIPasswordWidget
@@ -65,12 +66,12 @@ class UIPasswordWidget
$sHtmlValue .= '<input type="hidden" id="'.$this->iId.'_changed" name="attr_'.$sCode.'[changed]" value="'.$sChangedValue.'"/>';
$sHtmlValue .= '</div>';
$sHtmlValue .= '<span class="form_validation ibo-field-validation" id="v_'.$this->iId.'"></span><span class="field_status" id="fstatus_'.$this->iId.'"></span>';
$sHtmlValue .= '<span class="form_validation" id="v_'.$this->iId.'"></span><span class="field_status" id="fstatus_'.$this->iId.'"></span>';
$oPage->add_ready_script("$('#$this->iId').on('keyup change', function(evt) { return PasswordFieldChanged('$this->iId') } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#$this->iId').on('keyup change validate', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#{$this->iId}_confirm').on('keyup change', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#{$this->iId}').on('update', function(evt, sFormId)
$oPage->add_ready_script("$('#$this->iId').bind('keyup change', function(evt) { return PasswordFieldChanged('$this->iId') } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#$this->iId').bind('keyup change validate', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#{$this->iId}_confirm').bind('keyup change', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#{$this->iId}').bind('update', function(evt, sFormId)
{
if ($(this).prop('disabled'))
{

View File

@@ -1,7 +1,7 @@
<?php
/**
*
* Copyright (C) 2010-2021 Combodo SARL
* Copyright (C) 2010-2018 Combodo SARL
*
* This file is part of iTop.
*
@@ -21,6 +21,7 @@
*/
require_once(APPROOT.'/application/webpage.class.inc.php');
require_once(APPROOT.'/application/displayblock.class.inc.php');
class UISearchFormForeignKeys
@@ -40,11 +41,12 @@ class UISearchFormForeignKeys
*/
public function ShowModalSearchForeignKeys($oPage, $sTitle)
{
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
$oBlock = new DisplayBlock($oFilter, 'search', false);
$oPage->AddUiBlock($oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_iInputId}",
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_iInputId}",
array(
'menu' => false,
'result_list_outer_selector' => "SearchResultsToAdd_{$this->m_iInputId}",
@@ -53,26 +55,19 @@ class UISearchFormForeignKeys
'selection_mode' => true,
'cssCount' => "#count_{$this->m_iInputId}",
'query_params' => $oFilter->GetInternalParams(),
)));
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
$sCancel = Dict::S('UI:Button:Cancel');
$sAdd = Dict::S('UI:Button:Add');
$oPage->add(<<<HTML
<form id="ObjectsAddForm_{$this->m_iInputId}">
<div id="SearchResultsToAdd_{$this->m_iInputId}" style="vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;">
<div style="background: #fff; border:0; text-align:center; vertical-align:middle;"><p>{$sEmptyList}</p></div>
</div>
<input type="hidden" id="count_{$this->m_iInputId}" value="0"/>
<input type="button" value="{$sCancel}" onClick="$('#dlg_{$this->m_iInputId}').dialog('close');">&nbsp;&nbsp;
<input id="btn_ok_add_{$this->m_iInputId}" disabled="disabled" type="button" onclick="return oForeignKeysWidget{$this->m_iInputId}.DoAddObjects(this.id);" value="{$sAdd}">
</form>
HTML
);
));
$sHtml .= "<form id=\"ObjectsAddForm_{$this->m_iInputId}\">\n";
$sHtml .= "<div id=\"SearchResultsToAdd_{$this->m_iInputId}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
$sHtml .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
$sHtml .= "</div>\n";
$sHtml .= "<input type=\"hidden\" id=\"count_{$this->m_iInputId}\" value=\"0\"/>";
$sHtml .= "<input type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_{$this->m_iInputId}').dialog('close');\">&nbsp;&nbsp;<input id=\"btn_ok_{$this->m_iInputId}\" disabled=\"disabled\" type=\"button\" onclick=\"return oForeignKeysWidget{$this->m_iInputId}.DoAddObjects(this.id);\" value=\"".Dict::S('UI:Button:Add')."\">";
$sHtml .= "</div>\n";
$sHtml .= "</form>\n";
$oPage->add($sHtml);
$oPage->add_ready_script("$('#dlg_{$this->m_iInputId}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, resizeStop: oForeignKeysWidget{$this->m_iInputId}.UpdateSizes });");
$oPage->add_ready_script("$('#dlg_{$this->m_iInputId}').dialog('option', {title:'$sTitle'});");
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_iInputId} form').on('submit.uilinksWizard', oForeignKeysWidget{$this->m_iInputId}.SearchObjectsToAdd);");
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_iInputId} form').bind('submit.uilinksWizard', oForeignKeysWidget{$this->m_iInputId}.SearchObjectsToAdd);");
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_iInputId}').resize(oForeignKeysWidget{$this->m_iInputId}.UpdateSizes);");
}
@@ -117,4 +112,4 @@ HTML
array('menu' => false, 'cssCount' => "#count_{$this->m_iInputId}", 'selection_mode' => true, 'table_id' => "add_{$this->m_iInputId}"));
}
}
}

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -20,7 +20,7 @@
/**
* Class UIWizard
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -19,7 +19,7 @@
/**
* Store and retrieve user custom dashboards
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/core/dbobject.class.php');

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2017 Combodo SARL
//
// This file is part of iTop.
//
@@ -19,7 +19,7 @@
/**
* Store and retrieve user's preferences (i.e persistent per user settings)
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/core/dbobject.class.php');
@@ -34,215 +34,165 @@ require_once(APPROOT.'/core/userrights.class.inc.php');
*/
class appUserPreferences extends DBObject
{
/** @var array Associative array of the prefs. of users: <USER_ID> => <PREFS> */
private static $aUsersPrefs = []; // Local cache
private static $oUserPrefs = null; // Local cache
/**
* Get the value of the given property/preference
* If not set, the default value will be returned
*
* @param string $sCode Code/Name of the property to set
* @param mixed $defaultValue The default value
* @param string|null $sUserId Added in 3.0.0. ID of the user we want the pref. from, default is the current user
*
* @return mixed The value of the property for the current user
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
* @throws \OQLException
* @since 3.0.0 Added the $sUserId parameter
* @param string $sDefaultValue The default value
* @return string The value of the property for the current user
*/
public static function GetPref($sCode, $defaultValue, ?string $sUserId = null)
public static function GetPref($sCode, $sDefaultValue)
{
if (null === $sUserId) {
$sUserId = UserRights::GetUserId();
if (self::$oUserPrefs == null)
{
self::Load();
}
if (false === array_key_exists($sUserId, self::$aUsersPrefs)) {
self::Load($sUserId);
}
$aPrefs = self::$aUsersPrefs[$sUserId]->Get('preferences');
if (array_key_exists($sCode, $aPrefs)) {
$aPrefs = self::$oUserPrefs->Get('preferences');
if (array_key_exists($sCode, $aPrefs))
{
return $aPrefs[$sCode];
} else {
return $defaultValue;
}
else
{
return $sDefaultValue;
}
}
/**
* Set the value for a given preference for the current user, and stores it into the database
*
* Set the value for a given preference, and stores it into the database
* @param string $sCode Code/Name of the property/preference to set
* @param mixed $value Value to set
*
* @return void
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
* @param string $sValue Value to set
*/
public static function SetPref($sCode, $value)
public static function SetPref($sCode, $sValue)
{
$sUserId = UserRights::GetUserId();
if (false === array_key_exists($sUserId, self::$aUsersPrefs)) {
self::Load($sUserId);
if (self::$oUserPrefs == null)
{
self::Load();
}
$aPrefs = self::$aUsersPrefs[$sUserId]->Get('preferences');
if (array_key_exists($sCode, $aPrefs) && ($aPrefs[$sCode] === $value)) {
$aPrefs = self::$oUserPrefs->Get('preferences');
if (array_key_exists($sCode, $aPrefs) && ($aPrefs[$sCode] === $sValue))
{
// Do not write it again
} else {
$aPrefs[$sCode] = $value;
self::$aUsersPrefs[$sUserId]->Set('preferences', $aPrefs);
}
else
{
$aPrefs[$sCode] = $sValue;
self::$oUserPrefs->Set('preferences', $aPrefs);
self::Save();
}
}
/**
* Clears the value for a given preference (or list of preferences that matches a pattern) for the current user, and updates the database
*
* Clears the value for a given preference (or list of preferences that matches a pattern), and updates the database
* @param string $sCodeOrPattern Code/Pattern of the properties/preferences to reset
* @param boolean $bPattern Whether or not the supplied code is a PCRE pattern
*
* @return void
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
public static function UnsetPref($sCodeOrPattern, $bPattern = false)
{
$sUserId = UserRights::GetUserId();
if (false === array_key_exists($sUserId, self::$aUsersPrefs)) {
self::Load($sUserId);
if (self::$oUserPrefs == null)
{
self::Load();
}
$aPrefs = self::$aUsersPrefs[$sUserId]->Get('preferences');
if ($bPattern) {
$aPrefs = self::$oUserPrefs->Get('preferences');
if ($bPattern)
{
// the supplied code is a pattern, clear all preferences that match
foreach ($aPrefs as $sKey => $void) {
if (preg_match($sCodeOrPattern, $sKey)) {
foreach($aPrefs as $sKey => $void)
{
if (preg_match($sCodeOrPattern, $sKey))
{
unset($aPrefs[$sKey]);
}
}
self::$aUsersPrefs[$sUserId]->Set('preferences', $aPrefs);
} else {
unset($aPrefs[$sCodeOrPattern]);
self::$aUsersPrefs[$sUserId]->Set('preferences', $aPrefs);
self::$oUserPrefs->Set('preferences', $aPrefs);
}
else
{
unset($aPrefs[$sCodeOrPattern]);
self::$oUserPrefs->Set('preferences', $aPrefs);
}
// Save only if needed
if (self::$aUsersPrefs[$sUserId]->IsModified()) {
if (self::$oUserPrefs->IsModified())
{
self::Save();
}
}
/**
* Call this function to get all the preferences for the current user, packed as a JSON object
*
* Call this function to get all the preferences for the user, packed as a JSON object
* @return string JSON representation of the preferences
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
public static function GetAsJSON()
{
$sUserId = UserRights::GetUserId();
if (false === array_key_exists($sUserId, self::$aUsersPrefs)) {
self::Load($sUserId);
if (self::$oUserPrefs == null)
{
self::Load();
}
$aPrefs = self::$aUsersPrefs[$sUserId]->Get('preferences');
$aPrefs = self::$oUserPrefs->Get('preferences');
return json_encode($aPrefs);
}
/**
* Call this function if the user has changed (like when doing a logoff...)
*
* @return void
*/
public static function ResetPreferences()
{
self::$aUsersPrefs = [];
self::$oUserPrefs = null;
}
/**
* Call this function to ERASE all the preferences from the current user (only in memory, not in DB)
*
* @return void
* Call this function to ERASE all the preferences from the current user
*/
public static function ClearPreferences()
{
$sUserId = UserRights::GetUserId();
unset(self::$aUsersPrefs[$sUserId]);
self::$oUserPrefs = null;
}
/**
* Save preferences of the current user in the DB, for now we don't allow interfering with an other users preferences
*
* @return void;
*/
protected static function Save()
{
$sUserId = UserRights::GetUserId();
if (array_key_exists($sUserId, self::$aUsersPrefs)) {
if (self::$aUsersPrefs[$sUserId]->IsModified()) {
if (self::$oUserPrefs != null)
{
if (self::$oUserPrefs->IsModified())
{
utils::PushArchiveMode(false);
self::$aUsersPrefs[$sUserId]->DBUpdate();
self::$oUserPrefs->DBUpdate();
utils::PopArchiveMode();
}
}
}
/**
* Loads the preferences for the current user, creating the record in the database
* if needed
*
* @param string|null $sUserId Added in 3.0.0. ID of the user to load the prefs for, if null then current user will be used.
*
* @return void;
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
* @throws \OQLException
* @since 3.0.0 Added $sUserId parameter
*/
protected static function Load(?string $sUserId = null)
protected static function Load()
{
// Already in cache
if (array_key_exists($sUserId, self::$aUsersPrefs)) {
return;
}
if (null === $sUserId) {
$sUserId = UserRights::GetUserId();
}
if (self::$oUserPrefs != null) return;
$oSearch = new DBObjectSearch('appUserPreferences');
$oSearch->AddCondition('userid', $sUserId, '=');
$oSearch->AddCondition('userid', UserRights::GetUserId(), '=');
$oSet = new DBObjectSet($oSearch);
$oObj = $oSet->Fetch();
if ($oObj == null) {
if ($oObj == null)
{
// No prefs (yet) for this user, create the object
$oObj = new appUserPreferences();
$oObj->Set('userid', $sUserId);
$oObj->Set('userid', UserRights::GetUserId());
$oObj->Set('preferences', array()); // Default preferences: an empty array
try {
try
{
utils::PushArchiveMode(false);
$oObj->DBInsert();
utils::PopArchiveMode();
}
catch (Exception $e) {
catch(Exception $e)
{
// Ignore errors
}
}
self::$aUsersPrefs[$sUserId] = $oObj;
self::$oUserPrefs = $oObj;
}
/**
* @throws \CoreException
*/
public static function Init()
{
$aParams = array
@@ -263,22 +213,9 @@ class appUserPreferences extends DBObject
}
/**
* Overloading this function here to secure a fix done right before the release
* The real fix should be to implement this verb in DBObject
*
* @param \CMDBChange $oChange
* @param bool|null $bSkipStrongSecurity
* @param \DeletionPlan|null $oDeletionPlan
*
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DeleteException
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
*/
* Overloading this function here to secure a fix done right before the release
* The real fix should be to implement this verb in DBObject
*/
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null)
{
utils::PushArchiveMode(false);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2021 Combodo SARL
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
@@ -20,7 +20,7 @@
/**
* Class WizardHelper
*
* @copyright Copyright (C) 2010-2021 Combodo SARL
* @copyright Copyright (C) 2010-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -335,41 +335,20 @@ class WizardHelper
{
$sResult = $this->m_aData['m_oFieldsMap'][$sFieldName];
}
return $sResult;
}
public function GetReturnNotEditableFields()
{
return $this->m_aData['m_bReturnNotEditableFields'] ?? false;
}
/**
* @return string JS code to be executed for fields update
* @since 3.0.0 N°3198
*/
public function GetJsForUpdateFields()
{
$sWizardHelperJsVar = ($this->m_aData['m_sWizHelperJsVarName']) ?? 'oWizardHelper'.$this->GetFormPrefix();
$sWizardHelperJson = $this->ToJSON();
return <<<JS
{$sWizardHelperJsVar}.m_oData = {$sWizardHelperJson};
{$sWizardHelperJsVar}.UpdateFields();
JS;
}
static function ParseJsonSet($oMe, $sLinkClass, $sExtKeyToMe, $sJsonSet)
{
$aSet = json_decode($sJsonSet, true); // true means hash array instead of object
$oSet = CMDBObjectSet::FromScratch($sLinkClass);
foreach ($aSet as $aLinkObj)
foreach($aSet as $aLinkObj)
{
$oLink = MetaModel::NewObject($sLinkClass);
foreach ($aLinkObj as $sAttCode => $value)
foreach($aLinkObj as $sAttCode => $value)
{
$oAttDef = MetaModel::GetAttributeDef($sLinkClass, $sAttCode);
if (($oAttDef->IsExternalKey()) && ($value != '') && ($value > 0))
if (($oAttDef->IsExternalKey()) && ($value != '') && ($value > 0))
{
// For external keys: load the target object so that external fields
// get filled too

View File

@@ -1,7 +1,109 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* @deprecated will be removed in 3.1.0 - moved to sources/application/WebPage/XMLPage.php
* Class XMLPage
*
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2021 Combodo SARL
*/
require_once(APPROOT."/application/webpage.class.inc.php");
/**
* Simple web page with no includes or fancy formatting, useful to generateXML documents
* The page adds the content-type text/XML and the encoding into the headers
*/
class XMLPage extends WebPage
{
/**
* For big XML files, it's better NOT to store everything in memory and output the XML piece by piece
*/
var $m_bPassThrough;
var $m_bHeaderSent;
function __construct($s_title, $bPassThrough = false)
{
parent::__construct($s_title);
$this->m_bPassThrough = $bPassThrough;
$this->m_bHeaderSent = false;
$this->add_header("Content-type: text/xml; charset=".self::PAGES_CHARSET);
$this->no_cache();
$this->add_xframe_options();
$this->add_header("Content-location: export.xml");
}
public function output()
{
if (!$this->m_bPassThrough)
{
// Get the unexpected output but do nothing with it
$sTrash = $this->ob_get_clean_safe();
$sCharset = self::PAGES_CHARSET;
$this->s_content = "<?xml version=\"1.0\" encoding=\"$sCharset\"?".">\n".trim($this->s_content);
$this->add_header("Content-Length: ".strlen($this->s_content));
foreach($this->a_headers as $s_header)
{
header($s_header);
}
echo $this->s_content;
}
if (class_exists('DBSearch'))
{
DBSearch::RecordQueryTrace();
}
}
public function add($sText)
{
if (!$this->m_bPassThrough)
{
parent::add($sText);
}
else
{
if ($this->m_bHeaderSent)
{
echo $sText;
}
else
{
$s_captured_output = $this->ob_get_clean_safe();
foreach($this->a_headers as $s_header)
{
header($s_header);
}
$sCharset = self::PAGES_CHARSET;
echo "<?xml version=\"1.0\" encoding=\"$sCharset\"?".">\n";
echo trim($s_captured_output);
echo trim($this->s_content);
echo $sText;
$this->m_bHeaderSent = true;
}
}
}
public function small_p($sText)
{
}
public function table($aConfig, $aData, $aParams = array())
{
}
}

View File

@@ -1,7 +1,7 @@
<?php
/**
* Copyright (C) 2013-2021 Combodo SARL
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
@@ -18,35 +18,16 @@
* You should have received a copy of the GNU Affero General Public License
*/
/**
* Checks PHP version
*
* This is a hard-coded check that limits errors : we are stopping for anything < PHP 7.0.0
* The "real one" will be done in {@link \SetupUtils::CheckPhpVersion()}
*
* Note that since Composer 2 there is a platform_check that make this useless, but keeping it anyway to be extra safe !
*
* @see https://github.com/composer/composer/blob/master/doc/07-runtime.md#platform-check Composer's platform check
*
* @since 3.0.0 N°2214
*/
$bIsValidPhpVersion = false;
if (PHP_MAJOR_VERSION >= 7) {
$bIsValidPhpVersion = true;
} else {
echo 'Your PHP version ('.PHP_VERSION.') isn\'t supported.';
exit(-1);
}
define('ITOP_DEFAULT_ENV', 'production');
define('MAINTENANCE_MODE_FILE', APPROOT.'data/.maintenance');
define('READONLY_MODE_FILE', APPROOT.'data/.readonly');
if (function_exists('microtime')) {
if (function_exists('microtime'))
{
$fItopStarted = microtime(true);
} else {
}
else
{
$fItopStarted = 1000 * time();
}

View File

@@ -2,7 +2,7 @@
"type": "project",
"license": "AGPLv3",
"require": {
"php": ">=7.1.3",
"php": ">=5.6.0",
"ext-ctype": "*",
"ext-dom": "*",
"ext-gd": "*",
@@ -37,7 +37,7 @@
},
"config": {
"platform": {
"php": "7.2.0"
"php": "5.6.0"
},
"vendor-dir": "lib",
"preferred-install": {
@@ -52,9 +52,7 @@
"application",
"sources/application",
"sources/Composer",
"sources/Controller",
"sources/Form",
"sources/Renderer"
"sources/Controller"
],
"exclude-from-classmap": [
"core/dbobjectsearch.class.php",
@@ -63,9 +61,6 @@
"core/legacy/querybuildercontextlegacy.class.inc.php",
"core/querybuilderexpressions.class.inc.php",
"core/legacy/querybuilderexpressionslegacy.class.inc.php",
"core/oql/build/PHP/",
"core/apc-emulation.php",
"application/startup.inc.php",
"application/loginform.class.inc.php",
"application/loginbasic.class.inc.php",
"application/logindefault.class.inc.php",

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