Compare commits

...

108 Commits

Author SHA1 Message Date
odain
9872702f59 revert nikic enhancements and keep them for later + finalize work and tests 2025-09-05 15:36:27 +02:00
odain
7e7b5874a6 Evaluator fixes/enhancements + tests 2025-09-05 15:21:15 +02:00
odain
11f142b782 enhance nikic evaluators + test with/without nikic lib 2025-09-04 22:42:02 +02:00
odain
af790269f0 fix few Evaluators code 2025-09-04 22:41:14 +02:00
odain
86fe9d6a2b cleanup + replace last eval call in VariableEvaluator 2025-09-03 18:11:34 +02:00
odain
cdbe331c35 cleanup useless testing resources 2025-09-03 17:11:49 +02:00
odain
c14ac90a13 complete Evaluators list + autoload 2025-09-03 16:48:40 +02:00
odain
794a9afe3e fix broken setup 2025-09-02 19:23:34 +02:00
odain
a0a86782c7 fix broken setup 2025-09-02 19:23:12 +02:00
odain
ac2b787e09 move PhpParser/Evaluation classes in a specific namespave + composer dumpautoload 2025-09-02 19:19:56 +02:00
odain
1962cd7a88 replace eval by iTop custom evaluation classes 2025-09-02 17:03:02 +02:00
odain
f7b5091b39 temp evaluation work 2025-09-02 12:23:46 +02:00
odain
a587bd68eb PR review + code cleanup + added usecases and test cover 2025-09-01 21:19:24 +02:00
odain
08c77f8106 N°4789 - PR review changes with Romain 2025-08-27 21:45:56 +02:00
odain
61c2b71f1f N°4789 - refactor and split in ModuleDiscoveryEvaluationService + handle ModuleInstallerAPI methods calls during setup 2025-08-27 11:47:09 +02:00
odain
f47309f535 N°4789 - fix BeforeWritingConfig calls during setup 2025-08-26 16:55:08 +02:00
odain
79e1572c9e cleanup 2025-08-26 11:30:52 +02:00
odain
812e24b402 N°4789 - make autoselect and dependencies work as well 2025-08-26 11:29:19 +02:00
odain
8af748bd3e N°4789 - compute boolean expressions 2025-08-25 18:51:56 +02:00
odain
788b23a485 N°4789 - handle constants and if conditional structures 2025-08-25 11:45:38 +02:00
odain
6d80b2e5ed N°4789 - replace legacy eval by module file parsing 2025-08-25 06:45:17 +02:00
odain
07d7995a51 N°4789 - fix broken setup + tests 2025-08-21 14:38:05 +02:00
odain
1bc14f97e1 N°4789 - Parse datamodel module.xxx.php files instead of interpreting them - refactoring all in a dedicated service first 2025-08-20 12:22:16 +02:00
Anne-Cath
f03b008ebf N°8189 - Addons userrights - one is enough - remove files 2025-08-19 13:54:51 +02:00
jf-cbd
7f98ef3478 Update README.md 2025-08-18 16:02:50 +02:00
odain
d80e26791d N°8511 - Enhance DBObjectSet to be able to order by id 2025-08-18 14:42:06 +02:00
Anne-Cath
e6a0d95cba N°7835 - Dashboard - modification on iTop UI with header static without icon 2025-08-18 13:16:29 +02:00
Anne-Cath
965c9dba14 N°4718 - Remove "FilterCodes" - fix $m_aFilterForbiddenAttributes init 2025-08-14 11:04:47 +02:00
Benjamin Dalsass
8bca3ac830 N°7176 - Update nikic/php-parser to 5.0.0 (#735) 2025-08-14 09:03:32 +02:00
Stephen Abello
a975f67bd5 N°8455 - Fix portal environment banner displaying poorly 2025-08-13 17:02:48 +02:00
Anne-Cath
f5b86ff4d9 N°4718 - Remove "FilterCodes" - rename GetMagicAttributes to GetMagicFields 2025-08-13 16:59:40 +02:00
Anne-Cath
0deeeeb587 N°4718 - Remove "FilterCodes" - rename GetMagicAttributes to GetMagicField 2025-08-13 16:56:46 +02:00
Anne-Cath
2011570b84 N°4718 - Remove "FilterCodes" - case of AttributeStopWatch and AttributePassword 2025-08-12 15:50:51 +02:00
Benjamin Dalsass
1458ba877b N°7659 - Remove utils::GetClassesForInterface (#732) 2025-08-12 14:06:26 +02:00
Timmy38
71386198cf N°3124 - Refactorize ResizeImageToFit methods (#734) 2025-08-08 10:43:35 +02:00
Anne-Cath
5b9e0a1d4f N°3817 - Audit and fix calls to deprecated jQuery method 2025-08-06 19:47:57 +02:00
Anne-Cath
1667f834b9 Remove unusued lines 2025-08-06 09:44:35 +02:00
Benjamin Dalsass
cdbcd14767 N°8017 - Security - dependabot - Symfony's VarDumper vulnerable to un… (#731)
Upgrade all Symfony components to last security fix (~6.4.0)
2025-08-06 08:54:56 +02:00
Benjamin Dalsass
603340b852 Correct tcpdf composer update fonts script case issue 2025-08-06 08:33:50 +02:00
Anne-Cath
820087e4d1 N°4500 - Remove iPageUIExtension & AbstractPageUIExtension API 2025-08-04 10:30:38 +02:00
Benjamin Dalsass
c5ee123f88 Restore compilation symlinks file 2025-08-04 10:19:56 +02:00
Benjamin Dalsass
69d5015a24 N°7320 - Remove WebPage::add_linked_stylesheet method 2025-08-04 10:19:05 +02:00
Benjamin Dalsass
1d1365d951 N°7319 - Remove WebPage::add_linked_script method 2025-08-04 10:19:05 +02:00
Thomas Casteleyn
3da33c4c64 chore(auth-ldap): Prepare for php 8.3 deprecation (#720) 2025-08-01 15:28:19 +02:00
Anne-Cath
7b95d65f60 N°3653 - Remove parameter for \DBObjectSearch::GetQueryParams 2025-08-01 10:05:40 +02:00
Stephen Abello
d3e450c54e N°3749 - Remove old JS tooltip libs (qTip, jQuery tooltip, Bootstrap tooltip) calls 2025-08-01 10:01:30 +02:00
Anne-Cath
5a50398dba N°2592 - API : remove \CMDBObject::CheckUserRights 2025-08-01 09:32:52 +02:00
Anne-Cath
387ca19ec2 N°2711 - Portal: Remove "goto" xsi:type in action rules 2025-08-01 09:21:59 +02:00
Anne-Cath
c0651edaa1 N°8578 - Remove CollapsibleSection functions deprecated in 3.0.0 2025-08-01 09:19:21 +02:00
Anne-Cath
b06f3cd13e N°2711 - Portal: Remove "goto" xsi:type in action rules 2025-08-01 09:14:05 +02:00
Benjamin Dalsass
5aeb408edd N°4717 - Remove ajax.render.php xlsx_* operations 2025-08-01 08:15:26 +02:00
Benjamin Dalsass
7456383d72 N°4716 - Remove core/expression.class.inc.php 2025-08-01 08:03:59 +02:00
Anne-Cath
9c6b8f90f0 N°8189 - Addons userrights - one is enough - deprecate other files 2025-07-31 17:09:05 +02:00
Anne-Cath
e6ea2fd541 N°3815 - Remove "DisplayTemplate" PHP classes - modify comment 2025-07-31 17:07:48 +02:00
Anne-Cath
7d94e6f1f8 N°8578 - Remove CollapsibleSection functions deprecated in 3.0.0 2025-07-31 14:25:20 +02:00
Anne-Cath
2bd7c7a01a N°3815 - Remove "DisplayTemplate" PHP classes 2025-07-31 14:23:35 +02:00
Anne-Cath
f1762845f0 N°4720 - Remove old unreferenced methods that are @deprecated 2025-07-31 11:06:09 +02:00
Anne-Cath
3eb8437c32 N°4693 - Restore API to add sass entries in the backoffice pages - rename Interface 2025-07-31 10:07:15 +02:00
Anne-Cath
9acc6a8bd4 N°4693 - Restore API to add saas entries in the backoffice pages 2025-07-30 16:41:31 +02:00
Anne-Cath
4d794fe656 N°4813 - Remove DataTable class and file 2025-07-30 15:29:15 +02:00
Stephen Abello
c9f88a16ef N°6792 - Remove deprecated method \cmdbAbstract::DisplayCaseLog 2025-07-30 10:54:45 +02:00
Stephen Abello
95f84a98cc N°4455 - Remove old PNG icons for datamodel classes 2025-07-30 09:35:13 +02:00
Anne-Cath
6cb10ab13a N°4718 - Remove "FilterCodes" 2025-07-29 17:26:15 +02:00
Stephen Abello
048aaeb854 N°5312 - Remove old backoffice stylesheets 2025-07-29 15:05:18 +02:00
Benjamin Dalsass
2b18ab9690 N°6491 - Remove \Combodo\iTop\Form\Validator\Validator class 2025-07-29 15:03:19 +02:00
Stephen Abello
36dc71fdce N°4035 - Remove duplicated TWIG extensions class 2025-07-29 14:51:14 +02:00
Benjamin Dalsass
db2ad86c70 N°6533 - Remove core/coreexception.class.inc.php 2025-07-29 14:22:50 +02:00
Anne-Cath
56616ab08e N°8397 - Suppress export V1 from iTop packages - fix tests 2025-07-29 12:03:46 +02:00
Anne-Cath
f339498497 N°7002 - API : remove DisplayableGraph::Display and DisplayableGraph::DisplayFiltering 2025-07-29 11:46:27 +02:00
Anne-Cath
b24a359b36 N°6982 - Remove \cmdbAbstractObject::DBDeleteTracked_Internal 2025-07-29 11:39:54 +02:00
Anne-Cath
78c63f7502 N°6980 - Remove cmdbAbstractObject::DBCloneTracked_Internal 2025-07-29 11:35:45 +02:00
Anne-Cath
2f8b35c153 N°3393 - Remove WebPages deprecated in 3.0.0 2025-07-29 10:59:04 +02:00
Stephen Abello
271a1f66c1 N°6262 - Remove \DataTableUIBlockFactory::MakeForRenderingObject() method 2025-07-29 10:51:48 +02:00
Stephen Abello
738c7e1b8e N°6490 - Remove SelectObjectField::VerifyCurrentValue 2025-07-29 10:41:44 +02:00
Stephen Abello
54278f8c02 N°5233 - Remove \CMDBObject::DBCloneTracked 2025-07-29 10:36:29 +02:00
Stephen Abello
00e117b05f N°3898 - Remove ThemeHandler::GetCurrentThemeId() 2025-07-29 10:11:20 +02:00
Stephen Abello
504261a2c2 N°6775 - Remove WizardHelper::GetJsForUpdateFields() 2025-07-29 10:02:31 +02:00
Anne-Cath
14a1a4e9c7 N°8397 - Suppress export V1 from iTop packages 2025-07-29 09:53:12 +02:00
Stephen Abello
cfc4a43d0b N°7072 - Remove \iNewsroomProvider from \MetaModel::InitExtensions() 2025-07-29 09:48:55 +02:00
Stephen Abello
503a5ec25a N°4379 - Removed deprecated methods AbstractController::ForwardFromRoute and AbstractController::GetControllerNameFromRoute 2025-07-29 09:31:32 +02:00
Stephen Abello
09364ccf84 N°4386 - Remove deprecated EncodeHtml in utils.js 2025-07-29 08:48:44 +02:00
BenGrenoble
4bbd1fea5c N°8286 - Be able to add additional data in iTop session files via custom classes
Change to fit convention.
2025-07-24 10:59:12 +02:00
BenGrenoble
3c27847a04 N°8286 - Be able to add additional data in iTop session files via custom classes
Experimental warning
2025-07-24 10:29:48 +02:00
Benjamin Dalsass
8523da3329 Merge remote-tracking branch 'origin/support/3.2' into develop 2025-07-23 16:37:12 +02:00
Benjamin Dalsass
c63e01e27b N°8552 - Aggregate brick, Search Brick and new look issue 2025-07-23 16:36:01 +02:00
Benjamin Dalsass
8580cb70a4 Merge remote-tracking branch 'origin/support/3.2' into develop 2025-07-16 16:46:42 +02:00
Benjamin Dalsass
1438006861 N°8419 - Improve Setup process by avoiding the update of the attachment table when contact_id is already set 2025-07-16 16:41:50 +02:00
Stephen Abello
700470dd29 N°8219 - Allow to reset user cache 2025-07-11 10:28:24 +02:00
v-dumas
bfbc939bac N°3610 - shortcut_actions supports menu with JS code (2) 2025-07-10 11:48:24 +02:00
bdalsass
dffce3f2f7 Merge remote-tracking branch 'origin/support/3.2' into develop 2025-07-10 10:21:45 +02:00
bdalsass
497fc4978a N°8340 - CKEditor is slow with large texts 2025-07-10 10:20:23 +02:00
v-dumas
e96095e02d Merge remote-tracking branch 'origin/support/3.2' into develop 2025-07-09 17:16:02 +02:00
v-dumas
6826ab509d N°6925 - Add a dedicated dict entry for "View the OQL query" 2025-07-09 17:10:07 +02:00
v-dumas
8330582f86 N°3610 - shortcut_actions supports menu with JS code 2025-07-09 15:34:37 +02:00
v-dumas
5a4ad7b8c3 N°6925 - Add a dedicated dict entry for "View the OQL query" 2025-07-09 15:03:40 +02:00
v-dumas
a116967b0a N°8520 - 'shortcut_actions' support any standard menu 2025-07-09 14:58:52 +02:00
v-dumas
a13f353721 N°8520 - 'shortcut_actions' support blanks between menu ids 2025-07-09 14:53:29 +02:00
bdalsass
bd254e56d1 Portal fix unpatched template.
Note: The new look extension is already fixed.
2025-07-09 07:46:08 +02:00
bdalsass
346bd5de47 Merge remote-tracking branch 'origin/support/3.2' into develop 2025-07-09 07:38:59 +02:00
bdalsass
41194ce9ab N°8365 - Portal: impact analysis and silo, Ticket cannot be created due to CI not visible 2025-07-09 07:38:07 +02:00
Romain Quetiez
599e08f150 N°8440 XML assembly failing when a file name contains a quote 2025-07-08 17:31:42 +02:00
Anne-Catherine
0e5bece5b6 N°8347 - Bad display of special characters on the portal CheckToWrite message (#712) 2025-07-08 11:16:11 +02:00
v-dumas
0462298cd3 N°7796 - Fix impact analyses without functionalcis_list on Ticket 2025-07-08 09:42:18 +02:00
jf-cbd
80abaec9a6 Merge remote-tracking branch 'origin/support/3.2' into develop 2025-07-07 16:09:04 +02:00
jf-cbd
e987ea72bc Fix broken URI 2025-07-07 16:01:57 +02:00
bdalsass
a7877dc6a6 Merge remote-tracking branch 'origin/support/3.2' into develop 2025-07-07 14:04:18 +02:00
bdalsass
c8371f1c19 N°8395 - php8.1 compatibility in class extended Exception 2025-07-07 14:03:29 +02:00
v-dumas
a2d6423f32 N°7796 - Fix impact analyses without functionalcis_list on Ticket 2025-07-04 18:30:16 +02:00
1265 changed files with 21216 additions and 29155 deletions

View File

@@ -23,7 +23,7 @@
$(document).ready(function() {
$("#viewer").iviewer({src: '{{ path('graphs/classes.svg') }}', zoom_animation: false});
$('#viewer img').bind('dragstart', function(event){
$('#viewer img').on('dragstart', function(event){
event.preventDefault();
});
$(window).resize();

View File

@@ -25,7 +25,7 @@ if (false === file_exists($sTcPdfRootFolder)) {
echo $sCurrentScriptFileName.": No TCPDF lib detected, exiting !\n";
return;
}
$sTcPdfFontsFolder = $sTcPdfRootFolder.'/Fonts/';
$sTcPdfFontsFolder = $sTcPdfRootFolder.'/fonts/';
/**

View File

@@ -1,5 +1,9 @@
<p align="center"><a href="https://www.combodo.com/itop-193" target="_blank">
<img src="https://www.combodo.com/logos/logo-itop-baseline.svg" width=350>
<p align="center"><a href="https://combodo.com" target="_blank">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="/images/logos/logo-itop-baseline-light.svg">
<source media="(prefers-color-scheme: light)" srcset="/images/logos/logo-itop-baseline-dark.svg">
<img src="/images/logos/logo-itop-baseline-light.svg" width="350" alt="Logo iTop with baseline" />
</picture>
</a></p>

View File

@@ -1,362 +0,0 @@
<?php
// Copyright (C) 2010-2024 Combodo SAS
//
// 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/>
/**
* UserRightsMatrix (User management Module)
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
class UserRightsMatrixClassGrant extends DBObject
{
public static function Init()
{
$aParams = array
(
"category" => "addon/userrights",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_ur_matrixclasses",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("action", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
}
}
class UserRightsMatrixClassStimulusGrant extends DBObject
{
public static function Init()
{
$aParams = array
(
"category" => "addon/userrights",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_ur_matrixclassesstimulus",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("stimulus", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
}
}
class UserRightsMatrixAttributeGrant extends DBObject
{
public static function Init()
{
$aParams = array
(
"category" => "addon/userrights",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_ur_matrixattributes",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("userid", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"userid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("login", array("allowed_values"=>null, "extkey_attcode"=> 'userid', "target_attcode"=>"login")));
MetaModel::Init_AddAttribute(new AttributeString("class", array("allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("attcode", array("allowed_values"=>null, "sql"=>"attcode", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("action", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
}
}
class UserRightsMatrix extends UserRightsAddOnAPI
{
static public $m_aActionCodes = array(
UR_ACTION_READ => 'read',
UR_ACTION_MODIFY => 'modify',
UR_ACTION_DELETE => 'delete',
UR_ACTION_BULK_READ => 'bulk read',
UR_ACTION_BULK_MODIFY => 'bulk modify',
UR_ACTION_BULK_DELETE => 'bulk delete',
);
// Installation: create the very first user
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
{
// Maybe we should check that no other user with userid == 0 exists
$oUser = new UserLocal();
$oUser->Set('login', $sAdminUser);
$oUser->Set('password', $sAdminPwd);
$oUser->Set('contactid', 1); // one is for root !
$oUser->Set('language', $sLanguage); // Language was chosen during the installation
// Now record the admin user object
$iUserId = $oUser->DBInsertNoReload();
$this->SetupUser($iUserId, true);
return true;
}
public function IsAdministrator($oUser)
{
return ($oUser->GetKey() == 1);
}
public function IsPortalUser($oUser)
{
return ($oUser->GetKey() == 1);
}
// Deprecated - create a new module !
public function Setup()
{
// Users must be added manually
// This procedure will then update the matrix when a new user is found or a new class/attribute appears
$oUserSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT User"));
while ($oUser = $oUserSet->Fetch())
{
$this->SetupUser($oUser->GetKey());
}
return true;
}
protected function SetupUser($iUserId, $bNewUser = false)
{
foreach(array('bizmodel', 'application', 'gui', 'core/cmdb') as $sCategory)
{
foreach (MetaModel::GetClasses($sCategory) as $sClass)
{
foreach (self::$m_aActionCodes as $iActionCode => $sAction)
{
if ($bNewUser)
{
$bAddCell = true;
}
else
{
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassGrant WHERE class = '$sClass' AND action = '$sAction' AND userid = $iUserId"));
$bAddCell = ($oSet->Count() < 1);
}
if ($bAddCell)
{
// Create a new entry
$oMyClassGrant = MetaModel::NewObject("UserRightsMatrixClassGrant");
$oMyClassGrant->Set("userid", $iUserId);
$oMyClassGrant->Set("class", $sClass);
$oMyClassGrant->Set("action", $sAction);
$oMyClassGrant->Set("permission", "yes");
$iId = $oMyClassGrant->DBInsertNoReload();
}
}
foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus)
{
if ($bNewUser)
{
$bAddCell = true;
}
else
{
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassStimulusGrant WHERE class = '$sClass' AND stimulus = '$sStimulusCode' AND userid = $iUserId"));
$bAddCell = ($oSet->Count() < 1);
}
if ($bAddCell)
{
// Create a new entry
$oMyClassGrant = MetaModel::NewObject("UserRightsMatrixClassStimulusGrant");
$oMyClassGrant->Set("userid", $iUserId);
$oMyClassGrant->Set("class", $sClass);
$oMyClassGrant->Set("stimulus", $sStimulusCode);
$oMyClassGrant->Set("permission", "yes");
$iId = $oMyClassGrant->DBInsertNoReload();
}
}
foreach (MetaModel::GetAttributesList($sClass) as $sAttCode)
{
if ($bNewUser)
{
$bAddCell = true;
}
else
{
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixAttributeGrant WHERE class = '$sClass' AND attcode = '$sAttCode' AND userid = $iUserId"));
$bAddCell = ($oSet->Count() < 1);
}
if ($bAddCell)
{
foreach (array('read', 'modify') as $sAction)
{
// Create a new entry
$oMyAttGrant = MetaModel::NewObject("UserRightsMatrixAttributeGrant");
$oMyAttGrant->Set("userid", $iUserId);
$oMyAttGrant->Set("class", $sClass);
$oMyAttGrant->Set("attcode", $sAttCode);
$oMyAttGrant->Set("action", $sAction);
$oMyAttGrant->Set("permission", "yes");
$iId = $oMyAttGrant->DBInsertNoReload();
}
}
}
}
}
/*
// Create the "My Bookmarks" menu item (parent_id = 0, rank = 6)
if ($bNewUser)
{
$bAddMenu = true;
}
else
{
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT menuNode WHERE type = 'user' AND parent_id = 0 AND user_id = $iUserId"));
$bAddMenu = ($oSet->Count() < 1);
}
if ($bAddMenu)
{
$oMenu = MetaModel::NewObject('menuNode');
$oMenu->Set('type', 'user');
$oMenu->Set('parent_id', 0); // It's a toplevel entry
$oMenu->Set('rank', 6); // Located just above the Admin Tools section (=7)
$oMenu->Set('name', 'My Bookmarks');
$oMenu->Set('label', 'My Favorite Items');
$oMenu->Set('hyperlink', 'UI.php');
$oMenu->Set('template', '<p></p><p></p><p style="text-align:center; font-family:Georgia, Times, serif; font-size:32px;">My bookmarks</p><p style="text-align:center; font-family:Georgia, Times, serif; font-size:14px;"><i>This section contains my most favorite search results</i></p>');
$oMenu->Set('user_id', $iUserId);
$oMenu->DBInsert();
}
*/
}
public function Init()
{
// Could be loaded in a shared memory (?)
return true;
}
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
{
$oNullFilter = new DBObjectSearch($sClass);
return $oNullFilter;
}
public function IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet = null)
{
if (!array_key_exists($iActionCode, self::$m_aActionCodes))
{
return UR_ALLOWED_NO;
}
$sAction = self::$m_aActionCodes[$iActionCode];
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassGrant WHERE class = '$sClass' AND action = '$sAction' AND userid = '{$oUser->GetKey()}'"));
if ($oSet->Count() < 1)
{
return UR_ALLOWED_NO;
}
$oGrantRecord = $oSet->Fetch();
switch ($oGrantRecord->Get('permission'))
{
case 'yes':
$iRetCode = UR_ALLOWED_YES;
break;
case 'no':
default:
$iRetCode = UR_ALLOWED_NO;
break;
}
return $iRetCode;
}
public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
{
if (!array_key_exists($iActionCode, self::$m_aActionCodes))
{
return UR_ALLOWED_NO;
}
$sAction = self::$m_aActionCodes[$iActionCode];
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixAttributeGrant WHERE class = '$sClass' AND attcode = '$sAttCode' AND action = '$sAction' AND userid = '{$oUser->GetKey()}'"));
if ($oSet->Count() < 1)
{
return UR_ALLOWED_NO;
}
$oGrantRecord = $oSet->Fetch();
switch ($oGrantRecord->Get('permission'))
{
case 'yes':
$iRetCode = UR_ALLOWED_YES;
break;
case 'no':
default:
$iRetCode = UR_ALLOWED_NO;
break;
}
return $iRetCode;
}
public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null)
{
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixClassStimulusGrant WHERE class = '$sClass' AND stimulus = '$sStimulusCode' AND userid = '{$oUser->GetKey()}'"));
if ($oSet->Count() < 1)
{
return UR_ALLOWED_NO;
}
$oGrantRecord = $oSet->Fetch();
switch ($oGrantRecord->Get('permission'))
{
case 'yes':
$iRetCode = UR_ALLOWED_YES;
break;
case 'no':
default:
$iRetCode = UR_ALLOWED_NO;
break;
}
return $iRetCode;
}
public function FlushPrivileges()
{
}
}
UserRights::SelectModule('UserRightsMatrix');
?>

View File

@@ -1,78 +0,0 @@
<?php
// Copyright (C) 2010-2024 Combodo SAS
//
// 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/>
/**
* UserRightsNull
* User management Module - say Yeah! to everything
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
class UserRightsNull extends UserRightsAddOnAPI
{
// Installation: create the very first user
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
{
return true;
}
public function IsAdministrator($oUser)
{
return true;
}
public function IsPortalUser($oUser)
{
return true;
}
public function Init()
{
return true;
}
public function GetSelectFilter($oUser, $sClass, $aSettings = array())
{
$oNullFilter = new DBObjectSearch($sClass);
return $oNullFilter;
}
public function IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet = null)
{
return UR_ALLOWED_YES;
}
public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null)
{
return UR_ALLOWED_YES;
}
public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
{
return UR_ALLOWED_YES;
}
public function FlushPrivileges()
{
}
}
UserRights::SelectModule('UserRightsNull');
?>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,25 +0,0 @@
<?php
/**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/AjaxPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2024 Combodo SAS
*/
// cannot notify depreciation for now as this is still load in autoloader
//DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/AjaxPage.php, now loadable using autoloader');
use Combodo\iTop\Application\WebPage\AjaxPage;
/**
* Class ajax_page
*
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to AjaxPage
*/
class ajax_page extends AjaxPage
{
function __construct($s_title)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('ajax_page is deprecated. Please use AjaxPage instead');
parent::__construct($s_title);
}
}

View File

@@ -1158,61 +1158,6 @@ class JSButtonItem extends JSPopupMenuItem
}
/**
* 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 UIExtensibilityAPI
* @since 2.0
* @deprecated 3.0.0 If you need to include:
* * JS/CSS files/snippets, use {@see \iBackofficeLinkedScriptsExtension}, {@see \iBackofficeLinkedStylesheetsExtension}, etc instead
* * HTML (and optionally JS/CSS), use {@see \iPageUIBlockExtension} to manipulate {@see \Combodo\iTop\Application\UI\Base\UIBlock} instead
*/
interface iPageUIExtension
{
/**
* Add content to the header of the page
*
* @api
* @param iTopWebPage $oPage The page to insert stuff into.
*
* @return string The HTML content to add into the page
*/
public function GetNorthPaneHtml(iTopWebPage $oPage);
/**
* Add content to the footer of the page
*
* @api
* @param iTopWebPage $oPage The page to insert stuff into.
*
* @return string The HTML content to add into the page
*/
public function GetSouthPaneHtml(iTopWebPage $oPage);
/**
* Add content to the "admin banner"
*
* @api
* @param iTopWebPage $oPage The page to insert stuff into.
*
* @return string The HTML content to add into the page
*/
public function GetBannerHtml(iTopWebPage $oPage);
}
/**
* Implement this interface to add content to any iTopWebPage
*
@@ -1260,43 +1205,7 @@ interface iPageUIBlockExtension
}
/**
* Extend this class instead of iPageUIExtension if you don't need to overload all methods
*
* @api
* @package UIExtensibilityAPI
* @since 2.7.0
* @deprecated 3.0.0 use AbstractPageUIBlockExtension instead
*/
abstract class AbstractPageUIExtension implements iPageUIExtension
{
/**
* @inheritDoc
*/
public function GetNorthPaneHtml(iTopWebPage $oPage)
{
return '';
}
/**
* @inheritDoc
*/
public function GetSouthPaneHtml(iTopWebPage $oPage)
{
return '';
}
/**
* @inheritDoc
*/
public function GetBannerHtml(iTopWebPage $oPage)
{
return '';
}
}
/**
* Extend this class instead of iPageUIExtension if you don't need to overload all methods
* Extend this class instead of iPageUIBlockExtension if you don't need to overload all methods
*
* @api
* @package UIBlockExtensibilityAPI
@@ -1457,6 +1366,23 @@ interface iBackofficeStyleExtension
public function GetStyle(): string;
}
/**
* Implement this interface to add sass file (SCSS) to the backoffice pages.
* example: return "css/setup.scss"
*
* @api
* @package BackofficeUIExtensibilityAPI
* @since 3.3.0
*/
interface iBackofficeSassExtension
{
/**
* @api
* @see \iTopWebPage::$a_styles
* @return string
*/
public function GetSass(): string;
}
/**
* Implement this interface to add Dict entries
*

View File

@@ -1,8 +0,0 @@
<?php
/**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/CaptureWebPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2024 Combodo SAS
*/
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/CaptureWebPage.php, now loadable using autoloader');

View File

@@ -1,8 +0,0 @@
<?php
/**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/CLIPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2024 Combodo SAS
*/
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/CLIPage.php, now loadable using autoloader');

View File

@@ -2931,11 +2931,11 @@ JS
$sStatesSelection .= '</select>';
$sStatesSelection .= '<input type="hidden" id="obj_state_orig" name="obj_state_orig" value="'.$this->GetState().'"/>';
$oPage->add_ready_script(<<<JS
$('.state_select_{$this->m_iFormId}').change( function() {
$('.state_select_{$this->m_iFormId}').on('change', function() {
if ($('#obj_state_orig').val() != $(this).val()) {
$('.state_select_{$this->m_iFormId}').val($(this).val());
$('#form_{$this->m_iFormId}').data('force_submit', true);
$('#form_{$this->m_iFormId}').submit();
$('#form_{$this->m_iFormId}').trigger('submit');
}
});
JS
@@ -3925,7 +3925,7 @@ HTML;
public static function GetShortcutActions($sFinalClass)
{
$sShortcutActions = MetaModel::GetConfig()->Get('shortcut_actions');
$aShortcutActions = explode(',', $sShortcutActions);
$aShortcutActions = array_map('trim', explode(',', $sShortcutActions));
return $aShortcutActions;
}
@@ -4313,24 +4313,15 @@ HTML;
case 'Image':
$value = null;
$aDimensions = null;
$oImage = utils::ReadPostedDocument("attr_{$sFormPrefix}{$sAttCode}", 'fcontents');
if (!is_null($oImage->GetData()))
{
$aSize = utils::GetImageSize($oImage->GetData());
if (is_array($aSize) && $aSize[0] > 0 && $aSize[1] > 0)
{
$oImage = utils::ResizeImageToFit(
$oImage,
$aSize[0],
$aSize[1],
$oAttDef->Get('storage_max_width'),
$oAttDef->Get('storage_max_height')
);
}
else
{
IssueLog::Warning($sClass . ':' . $this->GetKey() . '/' . $sAttCode . ': Image could not be resized. Mimetype: ' . $oImage->GetMimeType() . ', filename: ' . $oImage->GetFileName());
}
$oImage = $oImage->ResizeImageToFit(
$oAttDef->Get('storage_max_width'),
$oAttDef->Get('storage_max_height'),
$aDimensions
);
if (is_null($aDimensions)) {
IssueLog::Warning($sClass . ':' . $this->GetKey() . '/' . $sAttCode . ': Image could not be resized. Mimetype: ' . $oImage->GetMimeType() . ', filename: ' . $oImage->GetFileName());
}
$aOtherData = utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}", null, 'raw_data');
if (is_array($aOtherData))
@@ -4575,28 +4566,6 @@ HTML;
InlineImage::FinalizeInlineImages($this);
}
/**
* @deprecated 3.1.1 3.2.0 N°6966 We will have only one DBClone method in the future
*/
protected function DBCloneTracked_Internal($newKey = null)
{
/** @var cmdbAbstractObject $oNewObj */
$oNewObj = MetaModel::GetObject(get_class($this), parent::DBCloneTracked_Internal($newKey));
// Invoke extensions after insertion (the object must exist, have an id, etc.)
/** @var \iApplicationObjectExtension $oExtensionInstance */
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
{
$sExtensionClass = get_class($oExtensionInstance);
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnDBInsert()");
$oKPI = new ExecutionKPI();
$oExtensionInstance->OnDBInsert($oNewObj, self::GetCurrentChange());
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBInsert');
}
return $oNewObj;
}
public function DBUpdate()
{
$this->LogCRUDEnter(__METHOD__);
@@ -4690,25 +4659,6 @@ HTML;
parent::PostDeleteActions();
}
/**
* @deprecated 3.1.1 3.2.0 N°6967 We will have only one DBDelete method in the future
*/
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
{
// Invoke extensions before the deletion (the deletion will do some cleanup and we might loose some information
/** @var \iApplicationObjectExtension $oExtensionInstance */
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
{
$sExtensionClass = get_class($oExtensionInstance);
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnDBDelete()");
$oKPI = new ExecutionKPI();
$oExtensionInstance->OnDBDelete($this, self::GetCurrentChange());
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBDelete');
}
return parent::DBDeleteTracked_Internal($oDeletionPlan);
}
public function IsModified()
{
if (parent::IsModified())
@@ -4860,110 +4810,6 @@ HTML;
}
}
/**
* Special display where the case log uses the whole "screen" at the bottom of the "Properties" tab
*
* @param WebPage $oPage
* @param string $sAttCode
* @param string $sComment
* @param string $sPrefix
* @param bool $bEditMode
*
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DictExceptionMissingString
* @throws \MySQLException
* @throws \OQLException
* @throws \Exception
* @deprecated 3.0.0, will be removed in 3.1.0
*/
public function DisplayCaseLog(WebPage $oPage, $sAttCode, $sComment = '', $sPrefix = '', $bEditMode = false)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod();
$oPage->SetCurrentTab('UI:PropertiesTab');
$sClass = get_class($this);
if ($this->IsNew()) {
$iFlags = $this->GetInitialStateAttributeFlags($sAttCode);
} else {
$iFlags = $this->GetAttributeFlags($sAttCode);
}
if ($iFlags & OPT_ATT_HIDDEN) {
// The case log is hidden do nothing
} else
{
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
$sAttDefClass = get_class($oAttDef);
$sAttLabel = $oAttDef->GetLabel();
$sAttMetaDataLabel = utils::HtmlEntities($sAttLabel);
$sAttMetaDataFlagHidden = (($iFlags & OPT_ATT_HIDDEN) === OPT_ATT_HIDDEN) ? 'true' : 'false';
$sAttMetaDataFlagReadOnly = (($iFlags & OPT_ATT_READONLY) === OPT_ATT_READONLY) ? 'true' : 'false';
$sAttMetaDataFlagMandatory = (($iFlags & OPT_ATT_MANDATORY) === OPT_ATT_MANDATORY) ? 'true' : 'false';
$sAttMetaDataFlagMustChange = (($iFlags & OPT_ATT_MUSTCHANGE) === OPT_ATT_MUSTCHANGE) ? 'true' : 'false';
$sAttMetaDataFlagMustPrompt = (($iFlags & OPT_ATT_MUSTPROMPT) === OPT_ATT_MUSTPROMPT) ? 'true' : 'false';
$sAttMetaDataFlagSlave = (($iFlags & OPT_ATT_SLAVE) === OPT_ATT_SLAVE) ? 'true' : 'false';
$sInputId = $this->m_iFormId.'_'.$sAttCode;
if ((!$bEditMode) || ($iFlags & (OPT_ATT_READONLY | OPT_ATT_SLAVE)))
{
// Check if the attribute is not read-only because of a synchro...
if ($iFlags & OPT_ATT_SLAVE)
{
$aReasons = array();
$sTip = '';
foreach($aReasons as $aRow) {
$sDescription = utils::EscapeHtml($aRow['description']);
$sDescription = str_replace(array("\r\n", "\n"), "<br/>", $sDescription);
$sTip .= "<div class=\"synchro-source\">";
$sTip .= "<div class=\"synchro-source-title\">Synchronized with {$aRow['name']}</div>";
$sTip .= "<div class=\"synchro-source-description\">$sDescription</div>";
}
$sTip = addslashes($sTip);
$oPage->add_ready_script("$('#synchro_$sInputId').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
}
// Attribute is read-only
$sHTMLValue = $this->GetAsHTML($sAttCode);
$sHTMLValue .= '<input type="hidden" id="'.$sInputId.'" name="attr_'.$sPrefix.$sAttCode.'" value="'.utils::EscapeHtml($this->GetEditValue($sAttCode)).'"/>';
$aFieldsMap[$sAttCode] = $sInputId;
}
else
{
$sValue = $this->Get($sAttCode);
$sDisplayValue = $this->GetEditValue($sAttCode);
$aArgs = array('this' => $this, 'formPrefix' => $sPrefix);
$sCommentAsHtml = ($sComment != '') ? '<span>'.$sComment.'</span><br/>' : '';
$sFieldAsHtml = self::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $sValue, $sDisplayValue, $sInputId, '', $iFlags, $aArgs);
$sHTMLValue = <<<HTML
<div class="field_data">
<div class="field_value">
$sCommentAsHtml
$sFieldAsHtml
</div>
</div>
HTML;
$aFieldsMap[$sAttCode] = $sInputId;
}
$oPage->add(<<<HTML
<fieldset>
<legend>{$sAttLabel}</legend>
<div class="field_container field_large" data-attribute-code="{$sAttCode}" data-attribute-type="{$sAttDefClass}" data-attribute-label="{$sAttMetaDataLabel}"
data-attribute-flag-hidden="{$sAttMetaDataFlagHidden}" data-attribute-flag-read-only="{$sAttMetaDataFlagReadOnly}" data-attribute-flag-mandatory="{$sAttMetaDataFlagMandatory}"
data-attribute-flag-must-change="{$sAttMetaDataFlagMustChange}" data-attribute-flag-must-prompt="{$sAttMetaDataFlagMustPrompt}" data-attribute-flag-slave="{$sAttMetaDataFlagSlave}">
{$sHTMLValue}
</div>
</fieldset>
HTML
);
}
}
/**
* Special display where the case log uses the whole "screen" at the bottom of the "Properties" tab
*

View File

@@ -1,8 +0,0 @@
<?php
/**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/CSVPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2024 Combodo SAS
*/
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/CSVPage.php, now loadable using autoloader');

View File

@@ -1967,7 +1967,10 @@ class DashletHeaderStatic extends Dashlet
$sIcon = $this->aProperties['icon'];
$oIconSelect = $this->oModelReflection->GetIconSelectionField('icon');
$sIconPath = utils::HtmlEntities($oIconSelect->MakeFileUrl($sIcon));
$sIconPath = '';
if (Utils::IsNotNullOrEmptyString($sIcon)) {
$sIconPath = utils::HtmlEntities($oIconSelect->MakeFileUrl($sIcon));
}
return DashletFactory::MakeForDashletHeaderStatic($this->oModelReflection->DictString($sTitle), $sIconPath);
}
@@ -1981,6 +1984,7 @@ class DashletHeaderStatic extends Dashlet
$oForm->AddField($oField);
$oField = $this->oModelReflection->GetIconSelectionField('icon', Dict::S('UI:DashletHeaderStatic:Prop-Icon'), $this->aProperties['icon']);
$oField->AddAllowedValue(['value' => '', 'label' => Dict::S('UI:DashletIcon:None'), 'icon' => '']);
$oForm->AddField($oField);
}
@@ -2093,7 +2097,10 @@ class DashletHeaderDynamic extends Dashlet
$sGroupBy = $this->aProperties['group_by'];
$oIconSelect = $this->oModelReflection->GetIconSelectionField('icon');
$sIconPath = $oIconSelect->MakeFileUrl($sIcon);
$sIconPath = '';
if (Utils::IsNotNullOrEmptyString($sIcon)) {
$sIconPath = $oIconSelect->MakeFileUrl($sIcon);
}
$aValues = $this->GetValues();
if (count($aValues) > 0) {
@@ -2223,6 +2230,7 @@ class DashletHeaderDynamic extends Dashlet
$oForm->AddField($oField);
$oField = $this->oModelReflection->GetIconSelectionField('icon', Dict::S('UI:DashletHeaderDynamic:Prop-Icon'), $this->aProperties['icon']);
$oField->AddAllowedValue(['value' => '', 'label' => Dict::S('UI:DashletIcon:None'), 'icon' => '']);
$oForm->AddField($oField);
$oField = new DesignerTextField('subtitle', Dict::S('UI:DashletHeaderDynamic:Prop-Subtitle'), $this->aProperties['subtitle']);

View File

@@ -111,7 +111,6 @@
<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>
@@ -141,7 +140,6 @@
<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>
@@ -188,7 +186,6 @@
<menu id="Integrations" xsi:type="TemplateMenuNode" _delta="define">
<rank>50</rank>
<parent>ConfigurationTools</parent>
<template_file/>
</menu>
<menu id="DataSources" xsi:type="OQLMenuNode" _delta="define">
<rank>20</rank>

View File

@@ -1,880 +0,0 @@
<?php
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableSettings;
use Combodo\iTop\Application\WebPage\WebPage;
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
/**
* Copyright (C) 2013-2024 Combodo SAS
*
* 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
*
* @deprecated 3.0.0 use Combodo\iTop\Application\UI\Base\Component\DataTable\Datatable
*/
class DataTable
{
protected $iListId; // Unique ID inside the web page
/** @var string */
private $sDatatableContainerId;
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 $bUseCustomSettings; // Whether or not the current display uses custom settings
protected $oDefaultSettings; // the default settings for displaying such a list
protected $bShowObsoleteData;
/**
* @param string $iListId Unique ID for this div/table in the page
* @param DBObjectSet $oSet The set of data to display
* @param array$aClassAliases The list of classes/aliases to be displayed in this set $sAlias => $sClassName
* @param string $sTableId A string (or null) identifying this table in order to persist its settings
*
* @throws \CoreException
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
public function __construct($iListId, $oSet, $aClassAliases, $sTableId = null)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use Combodo\iTop\Application\UI\Base\Component\DataTable\Datatable');
$this->iListId = utils::GetSafeId($iListId); // Make a "safe" ID for jQuery
$this->sDatatableContainerId = 'datatable_'.utils::GetSafeId($iListId);
$this->oSet = $oSet;
$this->aClassAliases = $aClassAliases;
$this->sTableId = $sTableId;
$this->iNbObjects = $oSet->Count();
$this->bUseCustomSettings = false;
$this->oDefaultSettings = null;
$this->bShowObsoleteData = $oSet->GetShowObsoleteData();
}
/**
* @param WebPage $oPage
* @param DataTableSettings $oSettings
* @param $bActionsMenu
* @param $sSelectMode
* @param $bViewLink
* @param $aExtraParams
*
* @return string
* @throws \CoreException
* @throws \MySQLException
*/
public function Display(WebPage $oPage, DataTableSettings $oSettings, $bActionsMenu, $sSelectMode, $bViewLink, $aExtraParams)
{
$this->oDefaultSettings = $oSettings;
// Identified tables can have their own specific settings
$oCustomSettings = DataTableSettings::GetTableSettings($this->aClassAliases, $this->sTableId);
if ($oCustomSettings != null)
{
// Custom settings overload the default ones
$this->bUseCustomSettings = true;
if ($this->oDefaultSettings->iDefaultPageSize == 0)
{
$oCustomSettings->iDefaultPageSize = 0;
}
}
else
{
$oCustomSettings = $oSettings;
}
if ($oCustomSettings->iDefaultPageSize > 0)
{
$this->oSet->SetLimit($oCustomSettings->iDefaultPageSize);
}
$this->oSet->SetOrderBy($oCustomSettings->GetSortOrder());
// Load only the requested columns
$aColumnsToLoad = array();
foreach($oCustomSettings->aColumns as $sAlias => $aColumnsInfo)
{
foreach($aColumnsInfo as $sAttCode => $aData)
{
if ($sAttCode != '_key_')
{
if ($aData['checked'])
{
$aColumnsToLoad[$sAlias][] = $sAttCode;
}
else
{
// See if this column is a must to load
$sClass = $this->aClassAliases[$sAlias];
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef->AlwaysLoadInTables()) {
$aColumnsToLoad[$sAlias][] = $sAttCode;
}
}
}
}
}
$this->oSet->OptimizeColumnLoad($aColumnsToLoad);
$bToolkitMenu = true;
if (isset($aExtraParams['toolkit_menu']))
{
$bToolkitMenu = (bool) $aExtraParams['toolkit_menu'];
}
if (UserRights::IsPortalUser())
{
// Portal users have a limited access to data, for now they can only see what's configured for them
$bToolkitMenu = false;
}
return $this->GetAsHTML($oPage, $oCustomSettings->iDefaultPageSize, $oCustomSettings->iDefaultPageSize, 0, $oCustomSettings->aColumns, $bActionsMenu, $bToolkitMenu, $sSelectMode, $bViewLink, $aExtraParams);
}
/**
* @param WebPage $oPage
* @param $iPageSize
* @param $iDefaultPageSize
* @param $iPageIndex
* @param $aColumns
* @param $bActionsMenu
* @param $bToolkitMenu
* @param $sSelectMode
* @param $bViewLink
* @param $aExtraParams
*
* @return string
* @throws \ArchivedObjectException
* @throws \CoreException
*/
public function GetAsHTML(WebPage $oPage, $iPageSize, $iDefaultPageSize, $iPageIndex, $aColumns, $bActionsMenu, $bToolkitMenu, $sSelectMode, $bViewLink, $aExtraParams)
{
$sObjectsCount = $this->GetObjectCount($oPage, $sSelectMode);
$sPager = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
$sActionsMenu = '';
$sToolkitMenu = '';
if ($bActionsMenu) {
$sActionsMenu = $this->GetActionsMenu($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%;\">";
$sHtml .= "<tr><td class=\"pagination_container\">$sObjectsCount</td><td class=\"menucontainer\">$sToolkitMenu $sActionsMenu</td></tr>";
$sHtml .= "<tr>$sPager</tr>";
$sHtml .= "</table>";
$sHtml .= "</td></tr>";
$sHtml .= "<tr><td class=\"datacontents\">$sDataTable</td></tr>";
$sHtml .= "</table>\n";
$oPage->add_at_the_end($sConfigDlg);
$aExtraParams['show_obsolete_data'] = $this->bShowObsoleteData;
$aOptions = array(
'sPersistentId' => '',
'sFilter' => $this->oSet->GetFilter()->serialize(),
'oColumns' => $aColumns,
'sSelectMode' => $sSelectMode,
'sViewLink' => ($bViewLink ? 'true' : 'false'),
'iNbObjects' => $this->iNbObjects,
'iDefaultPageSize' => $iDefaultPageSize,
'iPageSize' => $iPageSize,
'iPageIndex' => $iPageIndex,
'oClassAliases' => $this->aClassAliases,
'sTableId' => $this->sTableId,
'oExtraParams' => $aExtraParams,
'sRenderUrl' => utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php',
'oRenderParameters' => array('str' => ''), // Forces JSON to encode this as a object...
'oDefaultSettings' => array('str' => ''), // Forces JSON to encode this as a object...
'oLabels' => array('moveup' => Dict::S('UI:Button:MoveUp'), 'movedown' => Dict::S('UI:Button:MoveDown')),
);
if($this->oDefaultSettings != null)
{
$aOptions['oDefaultSettings'] = $this->GetAsHash($this->oDefaultSettings);
}
$sJSOptions = json_encode($aOptions);
$oPage->add_ready_script("$('#{$this->sDatatableContainerId}').datatable($sJSOptions);");
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
*/
public function GetAsHTMLTableRows(WebPage $oPage, $iPageSize, $aColumns, $sSelectMode, $bViewLink, $aExtraParams)
{
if ($iPageSize < 1)
{
$iPageSize = -1; // convention: no pagination
}
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
$sHtml = '';
foreach($aValues as $aRow)
{
$sHtml .= $oPage->GetTableRow($aRow, $aAttribs);
}
return $sHtml;
}
/**
* @param WebPage $oPage
* @param $sSelectMode
*
* @return string
*/
protected function GetObjectCount(WebPage $oPage, $sSelectMode)
{
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
{
$sHtml = '<div class="pagination_objcount">'.Dict::Format('UI:Pagination:HeaderSelection', '<span id="total">'.$this->iNbObjects.'</span>', '<span class="selectedCount">0</span>').'</div>';
}
else
{
$sHtml = '<div class="pagination_objcount">'.Dict::Format('UI:Pagination:HeaderNoSelection', '<span id="total">'.$this->iNbObjects.'</span>').'</div>';
}
return $sHtml;
}
/**
* @param WebPage $oPage
* @param $iPageSize
* @param $iDefaultPageSize
* @param $iPageIndex
*
* @return string
*/
protected function GetPager(WebPage $oPage, $iPageSize, $iDefaultPageSize, $iPageIndex)
{
$sHtml = '';
if ($iPageSize < 1) // Display all
{
$sPagerStyle = 'style="display:none"'; // no limit: display the full table, so hide the "pager" UI
// WARNING: mPDF does not take the "display" style into account
// when applied to a <td> or a <table> tag, so make sure you apply this to a div
}
else
{
$sPagerStyle = '';
}
$sCombo = '<select class="pagesize">';
if($iPageSize < 1)
{
$sCombo .= "<option selected=\"selected\" value=\"-1\">".Dict::S('UI:Pagination:All')."</option>";
}
else
{
for($iPage = 1; $iPage < 5; $iPage++)
{
$iNbItems = $iPage * $iDefaultPageSize;
$sSelected = ($iNbItems == $iPageSize) ? 'selected="selected"' : '';
$sCombo .= "<option $sSelected value=\"$iNbItems\">$iNbItems</option>";
}
$sCombo .= "<option value=\"-1\">".Dict::S('UI:Pagination:All')."</option>";
}
$sCombo .= '</select>';
$sPages = Dict::S('UI:Pagination:PagesLabel');
$sPageSizeCombo = Dict::Format('UI:Pagination:PageSize', $sCombo);
$iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize);
if ($iNbPages == 1)
{
// No need to display the pager
$sPagerStyle = 'style="display:none"';
}
$aPagesToDisplay = array();
for($idx = 0; $idx <= min(4, $iNbPages-1); $idx++)
{
if ($idx == 0)
{
$aPagesToDisplay[$idx] = '<span page="0" class="curr_page">1</span>';
}
else
{
$aPagesToDisplay[$idx] = "<span id=\"gotopage_$idx\" class=\"gotopage\" page=\"$idx\">".(1+$idx)."</span>";
}
}
$iLastPageIdx = $iNbPages - 1;
if (!isset($aPagesToDisplay[$iLastPageIdx]))
{
unset($aPagesToDisplay[$idx - 1]); // remove the last page added to make room for the very last page
$aPagesToDisplay[$iLastPageIdx] = "<span id=\"gotopage_$iLastPageIdx\" class=\"gotopage\" page=\"$iLastPageIdx\">... $iNbPages</span>";
}
$sPagesLinks = implode('', $aPagesToDisplay);
$sPagesList = '['.implode(',', array_keys($aPagesToDisplay)).']';
$sAppRootUrl = utils::GetAbsoluteUrlAppRoot();
$sSelectionMode = ($iNbPages == 1) ? '' : 'positive';
$sHtml =
<<<EOF
<td colspan="2">
<div $sPagerStyle>
<table id="pager{$this->iListId}" class="pager"><tr>
<td>$sPages</td>
<td><img src="{$sAppRootUrl}images/first.png" class="first"/>AAAA</td>
<td><img src="{$sAppRootUrl}images/prev.png" class="prev"/></td>
<td><span id="index">$sPagesLinks</span></td>
<td><img src="{$sAppRootUrl}images/next.png" class="next"/></td>
<td><img src="{$sAppRootUrl}images/last.png" class="last"/></td>
<td>$sPageSizeCombo</td>
<td><span id="loading">&nbsp;</span><input type="hidden" name="selectionMode" value="$sSelectionMode"></input>
</td>
</tr>
</table>
</div>
</td>
EOF;
return $sHtml;
}
/**
* @param WebPage $oPage
* @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);
}
/**
* @param WebPage $oPage
* @param $aExtraParams
*
* @return string
* @throws \Exception
*/
protected function GetToolkitMenu(WebPage $oPage, $aExtraParams)
{
if (!$oPage->IsPrintableVersion())
{
$sMenuTitle = Dict::S('UI:ConfigureThisList');
$sHtml = '<div class="itop_popup toolkit_menu" id="tk_'.$this->iListId.'"><ul><li aria-label="'.Dict::S('UI:Menu:Toolkit').'"><i class="fas fa-tools"></i><i class="fas fa-caret-down"></i><ul>';
$oMenuItem1 = new JSPopupMenuItem('iTop::ConfigureList', $sMenuTitle, "$('#datatable_dlg_".$this->iListId."').dialog('open');");
$aActions = array(
$oMenuItem1->GetUID() => $oMenuItem1->GetMenuItem(),
);
$this->oSet->Rewind();
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_OBJLIST_TOOLKIT, $this->oSet, $aActions, $this->sTableId, $this->iListId);
$this->oSet->Rewind();
$sHtml .= $oPage->RenderPopupMenuItems($aActions);
}
else
{
$sHtml = '';
}
return $sHtml;
}
/**
* @param WebPage $oPage
* @param $aColumns
* @param $bViewLink
* @param $iDefaultPageSize
*
* @return string
*/
protected function GetTableConfigDlg(WebPage $oPage, $aColumns, $bViewLink, $iDefaultPageSize)
{
$sHtml = "<div id=\"datatable_dlg_{$this->iListId}\" style=\"display: none;\">";
$sHtml .= "<form onsubmit=\"return false\">";
$sChecked = ($this->bUseCustomSettings) ? '' : 'checked';
$sHtml .= "<p><input id=\"dtbl_dlg_settings_{$this->iListId}\" type=\"radio\" name=\"settings\" $sChecked value=\"defaults\"><label for=\"dtbl_dlg_settings_{$this->iListId}\">&nbsp;".Dict::S('UI:UseDefaultSettings').'</label></p>';
$sHtml .= "<fieldset>";
$sChecked = ($this->bUseCustomSettings) ? 'checked': '';
$sHtml .= "<legend class=\"transparent\"><input id=\"dtbl_dlg_specific_{$this->iListId}\" type=\"radio\" class=\"specific_settings\" name=\"settings\" $sChecked value=\"specific\"><label for=\"dtbl_dlg_specific_{$this->iListId}\">&nbsp;".Dict::S('UI:UseSpecificSettings')."</label></legend>";
$sHtml .= Dict::S('UI:ColumnsAndSortOrder').'<br/><ul class="sortable_field_list" id="sfl_'.$this->iListId.'"></ul>';
$sHtml .= '<p>'.Dict::Format('UI:Display_X_ItemsPerPage', '<input type="text" size="4" name="page_size" value="'.$iDefaultPageSize.'">').'</p>';
$sHtml .= "</fieldset>";
$sHtml .= "<fieldset>";
$sSaveChecked = ($this->sTableId != null) ? 'checked' : '';
$sCustomDisabled = ($this->sTableId == null) ? 'disabled="disabled" stay-disabled="true" ' : '';
$sCustomChecked = ($this->sTableId != null) ? 'checked' : '';
$sGenericChecked = ($this->sTableId == null) ? 'checked' : '';
$sHtml .= "<legend class=\"transparent\"><input id=\"dtbl_dlg_save_{$this->iListId}\" type=\"checkbox\" $sSaveChecked name=\"save_settings\"><label for=\"dtbl_dlg_save_{$this->iListId}\">&nbsp;".Dict::S('UI:UseSavetheSettings')."</label></legend>";
$sHtml .= "<p><input id=\"dtbl_dlg_this_list_{$this->iListId}\" type=\"radio\" name=\"scope\" $sCustomChecked $sCustomDisabled value=\"this_list\"><label for=\"dtbl_dlg_this_list_{$this->iListId}\">&nbsp;".Dict::S('UI:OnlyForThisList').'</label>&nbsp;&nbsp;&nbsp;&nbsp;';
$sHtml .= "<input id=\"dtbl_dlg_all_{$this->iListId}\" type=\"radio\" name=\"scope\" $sGenericChecked value=\"defaults\"><label for=\"dtbl_dlg_all_{$this->iListId}\">&nbsp;".Dict::S('UI:ForAllLists').'</label></p>';
$sHtml .= "</fieldset>";
$sHtml .= '<table style="width:100%"><tr><td style="text-align:center;">';
$sHtml .= '<button type="button" onclick="$(\'#'.$this->sDatatableContainerId.'\').datatable(\'onDlgCancel\'); $(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'close\')">'.Dict::S('UI:Button:Cancel').'</button>';
$sHtml .= '</td><td style="text-align:center;">';
$sHtml .= '<button type="submit" onclick="$(\'#'.$this->sDatatableContainerId.'\').datatable(\'onDlgOk\');$(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'close\');">'.Dict::S('UI:Button:Ok').'</button>';
$sHtml .= '</td></tr></table>';
$sHtml .= "</form>";
$sHtml .= "</div>";
$sDlgTitle = addslashes(Dict::S('UI:ListConfigurationTitle'));
$oPage->add_ready_script("$('#datatable_dlg_{$this->iListId}').dialog({autoOpen: false, title: '$sDlgTitle', width: 500, close: function() { $('#{$this->sDatatableContainerId}').datatable('onDlgCancel'); } });");
return $sHtml;
}
/**
* @param $oSetting
*
* @return array
*/
public function GetAsHash($oSetting)
{
$aSettings = array('iDefaultPageSize' => $oSetting->iDefaultPageSize, 'oColumns' => $oSetting->aColumns);
return $aSettings;
}
/**
* @param array $aColumns
* @param string $sSelectMode
* @param bool $bViewLink
*
* @return array
* @throws \CoreException
* @throws \DictExceptionMissingString
* @throws \Exception
*/
protected function GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink)
{
$aAttribs = array();
if ($sSelectMode == 'multiple')
{
$aAttribs['form::select'] = array(
'label' => "<input type=\"checkbox\" onClick=\"CheckAll('.selectList{$this->iListId}:not(:disabled)', this.checked);\" class=\"checkAll\"></input>",
'description' => Dict::S('UI:SelectAllToggle+'),
'metadata' => array(),
);
}
else if ($sSelectMode == 'single')
{
$aAttribs['form::select'] = array('label' => '', 'description' => '', 'metadata' => array());
}
foreach($this->aClassAliases as $sAlias => $sClassName)
{
foreach($aColumns[$sAlias] as $sAttCode => $aData)
{
if ($aData['checked'])
{
if ($sAttCode == '_key_')
{
$sAttLabel = MetaModel::GetName($sClassName);
$aAttribs['key_'.$sAlias] = array(
'label' => $sAttLabel,
'description' => '',
'metadata' => array(
'object_class' => $sClassName,
'attribute_label' => $sAttLabel,
),
);
}
else
{
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCode);
$sAttDefClass = get_class($oAttDef);
$sAttLabel = MetaModel::GetLabel($sClassName, $sAttCode);
$aAttribs[$sAttCode.'_'.$sAlias] = array(
'label' => $sAttLabel,
'description' => $oAttDef->GetOrderByHint(),
'metadata' => array(
'object_class' => $sClassName,
'attribute_code' => $sAttCode,
'attribute_type' => $sAttDefClass,
'attribute_label' => $sAttLabel,
),
);
}
}
}
}
return $aAttribs;
}
/**
* @param $aColumns
* @param $sSelectMode
* @param $iPageSize
* @param $bViewLink
* @param $aExtraParams
*
* @return array
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \Exception
*/
protected function GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
{
$bLocalize = true;
if (isset($aExtraParams['localize_values']))
{
$bLocalize = (bool) $aExtraParams['localize_values'];
}
$aValues = array();
$aAttDefsCache = array();
$this->oSet->Seek(0);
$iMaxObjects = $iPageSize;
while (($aObjects = $this->oSet->FetchAssoc()) && ($iMaxObjects != 0))
{
$bFirstObject = true;
$aRow = array();
foreach($this->aClassAliases as $sAlias => $sClassName)
{
if (is_object($aObjects[$sAlias]))
{
$sHilightClass = MetaModel::GetHilightClass($sClassName, $aObjects[$sAlias]);
if ($sHilightClass != '')
{
$aRow['@class'] = $sHilightClass;
}
if ((($sSelectMode == 'single') || ($sSelectMode == 'multiple')) && $bFirstObject)
{
if (array_key_exists('selection_enabled', $aExtraParams) && isset($aExtraParams['selection_enabled'][$aObjects[$sAlias]->GetKey()]))
{
$sDisabled = ($aExtraParams['selection_enabled'][$aObjects[$sAlias]->GetKey()]) ? '' : ' disabled="disabled"';
}
else
{
$sDisabled = '';
}
if ($sSelectMode == 'single')
{
$aRow['form::select'] = "<input type=\"radio\" $sDisabled class=\"selectList{$this->iListId}\" name=\"selectObject\" value=\"".$aObjects[$sAlias]->GetKey()."\"></input>";
}
else
{
$aRow['form::select'] = "<input type=\"checkbox\" $sDisabled class=\"selectList{$this->iListId}\" name=\"selectObject[]\" value=\"".$aObjects[$sAlias]->GetKey()."\"></input>";
}
}
foreach($aColumns[$sAlias] as $sAttCode => $aData)
{
if ($aData['checked'])
{
if ($sAttCode == '_key_')
{
$aRow['key_'.$sAlias] = array(
'value_raw' => $aObjects[$sAlias]->GetKey(),
'value_html' => $aObjects[$sAlias]->GetHyperLink(),
);
}
else
{
// Prepare att. def. classes cache to avoid retrieving AttDef for each row
if(!isset($aAttDefsCache[$sClassName][$sAttCode]))
{
$aAttDefClassesCache[$sClassName][$sAttCode] = get_class(MetaModel::GetAttributeDef($sClassName, $sAttCode));
}
// Only retrieve raw (stored) value for simple fields
$bExcludeRawValue = false;
foreach (cmdbAbstractObject::GetAttDefClassesToExcludeFromMarkupMetadataRawValue() as $sAttDefClassToExclude)
{
if (is_a($aAttDefClassesCache[$sClassName][$sAttCode], $sAttDefClassToExclude, true))
{
$bExcludeRawValue = true;
break;
}
}
if($bExcludeRawValue)
{
$aRow[$sAttCode.'_'.$sAlias] = $aObjects[$sAlias]->GetAsHTML($sAttCode, $bLocalize);
}
else
{
$aRow[$sAttCode.'_'.$sAlias] = array(
'value_raw' => $aObjects[$sAlias]->Get($sAttCode),
'value_html' => $aObjects[$sAlias]->GetAsHTML($sAttCode, $bLocalize),
);
}
}
}
}
}
else
{
foreach($aColumns[$sAlias] as $sAttCode => $aData)
{
if ($aData['checked'])
{
if ($sAttCode == '_key_')
{
$aRow['key_'.$sAlias] = '';
}
else
{
$aRow[$sAttCode.'_'.$sAlias] = '';
}
}
}
}
$bFirstObject = false;
}
$aValues[] = $aRow;
$iMaxObjects--;
}
return $aValues;
}
/**
* @param WebPage $oPage
* @param $aColumns
* @param $sSelectMode
* @param $iPageSize
* @param $bViewLink
* @param $aExtraParams
*
* @return string
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DictExceptionMissingString
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \Exception
*/
public function GetHTMLTable(WebPage $oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
{
$iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize);
if ($iPageSize < 1)
{
$iPageSize = -1; // convention: no pagination
}
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
$sHtml = '<table class="listContainer object-list">';
foreach($this->oSet->GetFilter()->GetInternalParams() as $sName => $sValue)
{
$aExtraParams['query_params'][$sName] = $sValue;
}
$aExtraParams['show_obsolete_data'] = $this->bShowObsoleteData;
$sHtml .= "<tr><td>";
$sHtml .= $oPage->GetTable($aAttribs, $aValues);
$sHtml .= '</td></tr>';
$sHtml .= '</table>';
$iCount = $this->iNbObjects;
$aArgs = $this->oSet->GetArgs();
$sExtraParams = addslashes(str_replace('"', "'", json_encode(array_merge($aExtraParams, $aArgs)))); // JSON encode, change the style of the quotes and escape them
$sSelectModeJS = '';
$sHeaders = '';
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
{
$sSelectModeJS = $sSelectMode;
$sHeaders = 'headers: { 0: {sorter: false}},';
}
$sDisplayKey = ($bViewLink) ? 'true' : 'false';
// Protect against duplicate elements in the Zlist
$aUniqueOrderedList = array();
foreach($this->aClassAliases as $sAlias => $sClassName)
{
foreach($aColumns[$sAlias] as $sAttCode => $aData)
{
if ($aData['checked'])
{
$aUniqueOrderedList[$sAttCode] = true;
}
}
}
$aUniqueOrderedList = array_keys($aUniqueOrderedList);
$sJSColumns = json_encode($aColumns);
$sJSClassAliases = json_encode($this->aClassAliases);
$sCssCount = isset($aExtraParams['cssCount']) ? ", cssCount: '{$aExtraParams['cssCount']}'" : '';
$this->oSet->ApplyParameters();
// Display the actual sort order of the table
$aRealSortOrder = $this->oSet->GetRealSortOrder();
$aDefaultSort = array();
$iColOffset = 0;
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
{
$iColOffset += 1;
}
if ($bViewLink)
{
// $iColOffset += 1;
}
foreach($aRealSortOrder as $sColCode => $bAscending)
{
$iPos = array_search($sColCode, $aUniqueOrderedList);
if ($iPos !== false)
{
$aDefaultSort[] = "[".($iColOffset+$iPos).",".($bAscending ? '0' : '1')."]";
}
else if (($iPos = array_search(preg_replace('/_friendlyname$/', '', $sColCode), $aUniqueOrderedList)) !== false)
{
// if sorted on the friendly name of an external key, then consider it sorted on the column that shows the links
$aDefaultSort[] = "[".($iColOffset+$iPos).",".($bAscending ? '0' : '1')."]";
}
else if($sColCode == 'friendlyname' && $bViewLink)
{
$aDefaultSort[] = "[".($iColOffset).",".($bAscending ? '0' : '1')."]";
}
}
$sFakeSortList = '';
if (count($aDefaultSort) > 0)
{
$sFakeSortList = '['.implode(',', $aDefaultSort).']';
}
$sOQL = addslashes($this->oSet->GetFilter()->serialize());
$oPage->add_ready_script(
<<<JS
var oTable = $('#{$this->sDatatableContainerId} table.listResults');
oTable.tableHover();
oTable
.tablesorter({ $sHeaders widgets: ['myZebra', 'truncatedList']})
.tablesorterPager({
container: $('#pager{$this->iListId}'),
totalRows:$iCount,
size: $iPageSize,
filter: '$sOQL',
extra_params: '$sExtraParams',
select_mode: '$sSelectModeJS',
displayKey: $sDisplayKey,
table_id: '{$this->sDatatableContainerId}',
columns: $sJSColumns,
class_aliases: $sJSClassAliases $sCssCount
});
JS
);
if ($sFakeSortList != '')
{
$oPage->add_ready_script("oTable.trigger(\"fakesorton\", [$sFakeSortList]);");
}
return $sHtml;
}
/**
* @param WebPage $oPage
* @param $iDefaultPageSize
* @param $iStart
*/
public function UpdatePager(WebPage $oPage, $iDefaultPageSize, $iStart)
{
$iPageSize = $iDefaultPageSize;
$iPageIndex = 0;
$sHtml = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
$oPage->add_ready_script("$('#pager{$this->iListId}').html('".json_encode($sHtml)."');");
if ($iDefaultPageSize < 1)
{
$oPage->add_ready_script("$('#pager{$this->iListId}').parent().hide()");
}
else
{
$oPage->add_ready_script("$('#pager{$this->iListId}').parent().show()");
}
}
}
/**
* Simplified version of the data table with less "decoration" (and no paging)
* which is optimized for printing
*/
class PrintableDataTable extends DataTable
{
/**
* @param WebPage $oPage
* @param $iPageSize
* @param $iDefaultPageSize
* @param $iPageIndex
* @param $aColumns
* @param $bActionsMenu
* @param $bToolkitMenu
* @param $sSelectMode
* @param $bViewLink
* @param $aExtraParams
*
* @return string
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DictExceptionMissingString
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
public function GetAsHTML(WebPage $oPage, $iPageSize, $iDefaultPageSize, $iPageIndex, $aColumns, $bActionsMenu, $bToolkitMenu, $sSelectMode, $bViewLink, $aExtraParams)
{
return $this->GetHTMLTable($oPage, $aColumns, $sSelectMode, -1, $bViewLink, $aExtraParams);
}
/**
* @param WebPage $oPage
* @param $aColumns
* @param $sSelectMode
* @param $iPageSize
* @param $bViewLink
* @param $aExtraParams
*
* @return string
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DictExceptionMissingString
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
public function GetHTMLTable(WebPage $oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
{
$iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize);
if ($iPageSize < 1)
{
$iPageSize = -1; // convention: no pagination
}
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
$sHtml = $oPage->GetTable($aAttribs, $aValues);
return $sHtml;
}
}

View File

@@ -2224,6 +2224,11 @@ class MenuBlock extends DisplayBlock
$aFavoriteRegularActions[$key] = $aRegularActions[$key];
unset($aRegularActions[$key]);
}
// Toolkit actions
if (isset($aToolkitActions[$key])) {
$aFavoriteRegularActions[$key] = $aToolkitActions[$key];
unset($aToolkitActions[$key]);
}
// Transitions
if (isset($aTransitionActions[$key])) {
@@ -2313,7 +2318,27 @@ class MenuBlock extends DisplayBlock
break;
case 'UI:Menu:EMail':
$sIconClass = 'fas fa-share-alt';
$sIconClass = 'far fa-envelope fa-lg';
$sLabel = '';
break;
case 'UI:Menu:OpenOQL':
$sIconClass = 'fas fa-play fa-sm';
$sLabel = '';
break;
case 'UI:Menu:ExportXLSX':
$sIconClass = 'far fa-file-excel fa-lg';
$sLabel = '';
break;
case 'UI:Menu:CSVExport':
$sIconClass = 'fas fa-file-csv fa-lg';
$sLabel = '';
break;
case 'UI:Menu:PrintableVersion':
$sIconClass = 'fas fa-print';
$sLabel = '';
break;
case 'UI:Menu:ExportPDF':
$sIconClass = 'fas fa-file-pdf fa-lg';
$sLabel = '';
break;
@@ -2325,7 +2350,12 @@ class MenuBlock extends DisplayBlock
}
$sTarget = isset($aAction['target']) ? $aAction['target'] : '';
$oActionButton = ButtonUIBlockFactory::MakeLinkNeutral($sUrl, $sLabel, $sIconClass, $sTarget, utils::Sanitize($sActionId, '', utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER));
if (!empty($aAction['onclick'])) {
$oActionButton = ButtonUIBlockFactory::MakeIconAction($sIconClass, $aAction['label'], $aAction['label'], $sLabel,false); //utils::Sanitize($sActionId.md5($aAction['onclick']), '', utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER))
$oActionButton->SetOnClickJsCode($aAction['onclick']);
} else {
$oActionButton = ButtonUIBlockFactory::MakeLinkNeutral($sUrl, $sLabel, $sIconClass, $sTarget, utils::Sanitize($sActionId, '', utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER));
}
// ResourceId should not be sanitized
$oActionButton->AddDataAttribute('resource-id', $sActionId);
$oActionButton->AddCSSClasses(['ibo-action-button', 'ibo-regular-action-button']);

View File

@@ -1,8 +0,0 @@
<?php
/**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/ErrorPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2024 Combodo SAS
*/
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/ErrorPage.php, now loadable using autoloader');

View File

@@ -63,14 +63,14 @@ class CoreCannotSaveObjectException extends CoreException
public function getTextMessage()
{
$sTitle = Dict::S('UI:Error:SaveFailed');
$sContent = utils::HtmlEntities($sTitle);
$sContent = $sTitle;
if (count($this->aIssues) == 1) {
$sIssue = reset($this->aIssues);
$sContent .= utils::HtmlEntities($sIssue);
$sContent .= $sIssue;
} else {
foreach ($this->aIssues as $sError) {
$sContent .= " ".utils::HtmlEntities($sError).", ";
$sContent .= " " . $sError . ", ";
}
}

View File

@@ -363,7 +363,7 @@ $('#$sDialogId').dialog({
buttons: [
{ text: "$sOkButtonLabel", click: function() {
var oForm = $(this).closest('.ui-dialog').find('form');
oForm.submit();
oForm.trigger('submit');
if (AnimateDlgButtons)
{
sFormId = oForm.attr('id');
@@ -1501,6 +1501,11 @@ class DesignerIconSelectionField extends DesignerFormField
$this->aAllowedValues = $aAllowedValues;
}
public function AddAllowedValue($aValue)
{
// Add a null value to the list of allowed values
$this->aAllowedValues = array_merge([$aValue], $this->aAllowedValues);
}
public function EnableUpload($sIconUploadUrl)
{
$this->sUploadUrl = $sIconUploadUrl;

View File

@@ -1,9 +0,0 @@
<?php
/**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/iTopWebPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2024 Combodo SAS
*/
// cannot notify depreciation for now as this is still MASSIVELY used in iTop core !
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/iTopWebPage.php, now loadable using autoloader');

View File

@@ -1,8 +0,0 @@
<?php
/**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/iTopWizardWebPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2024 Combodo SAS
*/
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/iTopWizardWebPage.php, now loadable using autoloader');

View File

@@ -91,15 +91,6 @@ function _MaintenanceJsonMessage($sTitle, $sMessage)
$oP->AddData($aMessage);
$oP->Output();
} else {
@include_once(APPROOT."/application/ajaxwebpage.class.inc.php");
if (class_exists('ajax_page')) {
$oP = new ajax_page($sTitle);
$oP->add_header('Access-Control-Allow-Origin: *');
$oP->SetContentType('application/json');
$oP->add('{"code":100, "message":"'.$sMessage.'"}');
$oP->Output();
} else {
_MaintenanceTextMessage($sMessage);
}
_MaintenanceTextMessage($sMessage);
}
}

View File

@@ -10,7 +10,6 @@ use Combodo\iTop\Application\WebPage\iTopWebPage;
use Combodo\iTop\Application\WebPage\WebPage;
require_once(APPROOT.'/application/utils.inc.php');
require_once(APPROOT.'/application/template.class.inc.php');
require_once(APPROOT."/application/user.dashboard.class.inc.php");
@@ -999,15 +998,11 @@ class MenuGroup extends MenuNode
*/
class TemplateMenuNode extends MenuNode
{
/**
* @var string
*/
protected $sTemplateFile;
/**
* Create a menu item based on a custom template 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 string $sTemplateFile Path (or URL) to the file that will be used as a template for displaying the page's content
* @param string $sTemplateFile unused deprecated
* @param integer $iParentIndex ID of the parent menu
* @param float $fRank Number used to order the list, any number will do, but for a given level (i.e same parent) all menus are sorted based on this value
* @param string $sEnableClass Name of class of object
@@ -1018,17 +1013,6 @@ class TemplateMenuNode extends MenuNode
public function __construct($sMenuId, $sTemplateFile, $iParentIndex, $fRank = 0.0, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
{
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
$this->sTemplateFile = $sTemplateFile;
$this->aReflectionProperties['template_file'] = $sTemplateFile;
}
/**
* @inheritDoc
*/
public function GetHyperlink($aExtraParams)
{
if ($this->sTemplateFile == '') return '';
return parent::GetHyperlink($aExtraParams);
}
/**
@@ -1037,18 +1021,7 @@ class TemplateMenuNode extends MenuNode
*/
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
ApplicationMenu::CheckMenuIdEnabled($this->GetMenuId());
$sTemplate = @file_get_contents($this->sTemplateFile);
if ($sTemplate !== false)
{
$aExtraParams['table_id'] = 'Menu_'.$this->GetMenuId();
$oTemplate = new DisplayTemplate($sTemplate);
$oTemplate->Render($oPage, $aExtraParams);
}
else
{
$oPage->p("Error: failed to load template file: '{$this->sTemplateFile}'"); // No need to translate ?
}
//DO NOTHING this type of menu is only used for title not clickable
}
}

View File

@@ -1,8 +0,0 @@
<?php
/**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/NiceWebPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2024 Combodo SAS
*/
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/NiceWebPage.php, now loadable using autoloader');

View File

@@ -1,8 +0,0 @@
<?php
/**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/PDFPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2024 Combodo SAS
*/
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/PDFPage.php, now loadable using autoloader');

View File

@@ -221,17 +221,10 @@ class QueryOQL extends Query
{
try{
// retrieve attributes
$sFields = trim($this->Get('fields'));
$sOql = $this->Get('oql');
// construct base url depending on version
$bExportV1Recommended = ($sFields == '');
if ($bExportV1Recommended) {
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?format=spreadsheet&login_mode=basic&query='.$this->GetKey();
}
else{
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export-v2.php?format=spreadsheet&login_mode=basic&date_format='.urlencode((string)AttributeDateTime::GetFormat()).'&query='.$this->GetKey();
}
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export-v2.php?format=spreadsheet&login_mode=basic&date_format='.urlencode((string)AttributeDateTime::GetFormat()).'&query='.$this->GetKey();
// search object from OQL
$oSearch = DBObjectSearch::FromOQL($sOql);
@@ -256,22 +249,9 @@ class QueryOQL extends Query
$oPage->add_script("$('[name=\"attr_oql\"]').addClass('ibo-query-oql ibo-is-code'); $('[data-attribute-code=\"oql\"]').addClass('ibo-query-oql ibo-is-code');");
if (!$bEditMode) {
$sFields = trim($this->Get('fields'));
$bExportV1Recommended = ($sFields == '');
if ($bExportV1Recommended) {
$oFieldAttDef = MetaModel::GetAttributeDef('QueryOQL', 'fields');
$oAlert = AlertUIBlockFactory::MakeForFailure()
->SetIsClosable(false)
->SetIsCollapsible(false);
$oAlert->AddCSSClass('mb-5');
$oAlert->AddSubBlock(new Html(Dict::Format('UI:Query:UrlV1', '')));
$oPage->AddSubBlock($oAlert);
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?format=spreadsheet&login_mode=basic&query='.$this->GetKey();
} else {
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export-v2.php?format=spreadsheet&login_mode=basic&date_format='.urlencode((string)AttributeDateTime::GetFormat()).'&query='.$this->GetKey();
}
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export-v2.php?format=spreadsheet&login_mode=basic&date_format='.urlencode((string)AttributeDateTime::GetFormat()).'&query='.$this->GetKey();
$sOql = $this->Get('oql');
$sMessage = null;
try {
$oSearch = DBObjectSearch::FromOQL($sOql);
$aParameters = $oSearch->GetQueryParams();

View File

@@ -1,427 +0,0 @@
<?php
/**
* Copyright (C) 2013-2024 Combodo SAS
*
* 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\WebPage\iTopWebPage;
use Combodo\iTop\Application\WebPage\WebPage;
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
{
protected $m_sTemplate;
protected $m_aTags;
static protected $iBlockCount = 0;
public function __construct($sTemplate)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod();
$this->m_aTags = array(
'itopblock',
'itopcheck',
'itoptabs',
'itoptab',
'itoptoggle',
'itopstring',
'sqlblock',
);
$this->m_sTemplate = $sTemplate;
}
public function Render(WebPage $oPage, $aParams = array())
{
$this->m_sTemplate = MetaModel::ApplyParams($this->m_sTemplate, $aParams);
$iStart = 0;
$iEnd = strlen($this->m_sTemplate);
$iCount = 0;
$iBeforeTagPos = $iStart;
$iAfterTagPos = $iStart;
while($sTag = $this->GetNextTag($iStart, $iEnd))
{
$sContent = $this->GetTagContent($sTag, $iStart, $iEnd);
$iAfterTagPos = $iEnd + strlen('</'.$sTag.'>');
$sOuterTag = substr($this->m_sTemplate, $iStart, $iAfterTagPos - $iStart);
$oPage->add(substr($this->m_sTemplate, $iBeforeTagPos, $iStart - $iBeforeTagPos));
if ($sTag == DisplayBlock::TAG_BLOCK)
{
try
{
$oBlock = DisplayBlock::FromTemplate($sOuterTag);
if (is_object($oBlock))
{
$oBlock->Display($oPage, 'block_'.self::$iBlockCount, $aParams);
}
}
catch(OQLException $e)
{
$oPage->p('Error in template (please contact your administrator) - Invalid query<!--'.$sOuterTag.'-->');
}
catch(Exception $e)
{
$oPage->p('Error in template (please contact your administrator)<!--'.$e->getMessage().'--><!--'.$sOuterTag.'-->');
}
self::$iBlockCount++;
}
else
{
$aAttributes = $this->GetTagAttributes($sTag, $iStart, $iEnd);
//$oPage->p("Tag: $sTag - ($iStart, $iEnd)");
$this->RenderTag($oPage, $sTag, $aAttributes, $sContent);
}
$iAfterTagPos = $iEnd + strlen('</'.$sTag.'>');
$iBeforeTagPos = $iAfterTagPos;
$iStart = $iEnd;
$iEnd = strlen($this->m_sTemplate);
$iCount++;
}
$oPage->add(substr($this->m_sTemplate, $iAfterTagPos));
}
public function GetNextTag(&$iStartPos, &$iEndPos)
{
$iChunkStartPos = $iStartPos;
$sNextTag = null;
$iStartPos = $iEndPos;
foreach($this->m_aTags as $sTag)
{
// Search for the opening tag
$iOpeningPos = stripos($this->m_sTemplate, '<'.$sTag.' ', $iChunkStartPos);
if ($iOpeningPos === false)
{
$iOpeningPos = stripos($this->m_sTemplate, '<'.$sTag.'>', $iChunkStartPos);
}
if ($iOpeningPos !== false)
{
$iClosingPos = stripos($this->m_sTemplate, '</'.$sTag.'>', $iOpeningPos);
}
if ( ($iOpeningPos !== false) && ($iClosingPos !== false))
{
if ($iOpeningPos < $iStartPos)
{
// This is the next tag
$iStartPos = $iOpeningPos;
$iEndPos = $iClosingPos;
$sNextTag = $sTag;
}
}
}
return $sNextTag;
}
public function GetTagContent($sTag, $iStartPos, $iEndPos)
{
$sContent = "";
$iContentStart = strpos($this->m_sTemplate, '>', $iStartPos); // Content of tag start immediatly after the first closing bracket
if ($iContentStart !== false)
{
$sContent = substr($this->m_sTemplate, 1+$iContentStart, $iEndPos - $iContentStart - 1);
}
return $sContent;
}
public function GetTagAttributes($sTag, $iStartPos, $iEndPos)
{
$aAttr = array();
$iAttrStart = strpos($this->m_sTemplate, ' ', $iStartPos); // Attributes start just after the first space
$iAttrEnd = strpos($this->m_sTemplate, '>', $iStartPos); // Attributes end just before the first closing bracket
if ( ($iAttrStart !== false) && ($iAttrEnd !== false) && ($iAttrEnd > $iAttrStart))
{
$sAttributes = substr($this->m_sTemplate, 1+$iAttrStart, $iAttrEnd - $iAttrStart - 1);
$aAttributes = explode(' ', $sAttributes);
foreach($aAttributes as $sAttr)
{
if ( preg_match('/(.+) *= *"(.+)"$/', $sAttr, $aMatches) )
{
$aAttr[strtolower($aMatches[1])] = $aMatches[2];
}
}
}
return $aAttr;
}
protected function RenderTag($oPage, $sTag, $aAttributes, $sContent)
{
static $iTabContainerCount = 0;
switch($sTag)
{
case 'itoptabs':
$oPage->AddTabContainer('Tabs_'.$iTabContainerCount);
$oPage->SetCurrentTabContainer('Tabs_'.$iTabContainerCount);
$iTabContainerCount++;
//$oPage->p('Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
$oTemplate = new DisplayTemplate($sContent);
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
$oPage->SetCurrentTabContainer('');
break;
case 'itopcheck':
$sClassName = $aAttributes['class'];
if (MetaModel::IsValidClass($sClassName) && UserRights::IsActionAllowed($sClassName, UR_ACTION_READ))
{
$oTemplate = new DisplayTemplate($sContent);
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
}
else
{
// Leave a trace for those who'd like to understand why nothing is displayed
$oPage->add("<!-- class $sClassName does not exist, skipping some part of the template -->\n");
}
break;
case 'itoptab':
$oPage->SetCurrentTab($aAttributes['name'], str_replace('_', ' ', $aAttributes['name']));
$oTemplate = new DisplayTemplate($sContent);
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
$oPage->SetCurrentTab('');
break;
case 'itoptoggle':
$sName = isset($aAttributes['name']) ? $aAttributes['name'] : 'Tagada';
$bOpen = isset($aAttributes['open']) ? $aAttributes['open'] : true;
$oPage->StartCollapsibleSection(Dict::S($sName), $bOpen);
$oTemplate = new DisplayTemplate($sContent);
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');
$oPage->EndCollapsibleSection();
break;
case 'itopstring':
$oPage->add(Dict::S($sContent));
break;
case 'sqlblock':
$oBlock = SqlBlock::FromTemplate($sContent);
$oBlock->RenderContent($oPage);
break;
case 'itopblock': // No longer used, handled by DisplayBlock::FromTemplate see above
$oPage->add("<!-- Application Error: should be handled by DisplayBlock::FromTemplate -->");
break;
default:
// Unknown tag, just ignore it or now -- output an HTML comment
$oPage->add("<!-- unsupported tag: $sTag -->");
}
}
/**
* Unit test
*/
static public function UnitTest()
{
require_once(APPROOT.'/application/startup.inc.php');
$sAppRootUrl = utils::GetAbsoluteUrlAppRoot();
$sTemplate = '<div class="page_header">
<div class="actions_details"><a href="#"><span>Actions</span></a></div>
<h1>$class$: <span class="hilite">$name$</span></h1>
</div>
<img src="'.$sAppRootUrl.'images/connect_to_network.png" style="margin-top:-10px; margin-right:10px; float:right">
<itoptabs>
<itoptab name="Interfaces">
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT Interface AS i WHERE i.device_id = $id$</itopblock>
</itoptab>
<itoptab name="Contacts">
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT Contact AS c JOIN lnkContactToCI AS l ON l.contact_id = c.id WHERE l.ci_id = $id$</itopblock>
</itoptab>
<itoptab name="Documents">
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT Document AS d JOIN lnkDocumentToCI as l ON l.document_id = d.id WHERE l.ci_id = $id$)</itopblock>
</itoptab>
</itoptabs>';
$oPage = new iTopWebPage('Unit Test');
//$oPage->add("Template content: <pre>".htmlentities($sTemplate, ENT_QUOTES, 'UTF-8')."</pre>\n");
$oTemplate = new DisplayTemplate($sTemplate);
$oTemplate->Render($oPage, array('class'=>'Network device','pkey'=> 271, 'name' => 'deliversw01.mecanorama.fr', 'org_id' => 3));
$oPage->output();
}
}
/**
* Special type of template for displaying the details of an object
* On top of the defaut 'blocks' managed by the parent class, the following placeholders
* are available in such a template:
* $attribute_code$ An attribute of the object (in edit mode this is the input for the attribute)
* $attribute_code->label()$ The label of an attribute
* $PlugIn:plugInClass->properties()$ The ouput of OnDisplayProperties of the specified plugInClass
*/
class ObjectDetailsTemplate extends DisplayTemplate
{
public function __construct($sTemplate, $oObj, $sFormPrefix = '')
{
parent::__construct($sTemplate);
$this->m_oObj = $oObj;
$this->m_sPrefix = $sFormPrefix;
}
public function Render(WebPage $oPage, $aParams = array(), $bEditMode = false)
{
$sStateAttCode = MetaModel :: GetStateAttributeCode(get_class($this->m_oObj));
$aTemplateFields = array();
preg_match_all('/\\$this->([a-z0-9_]+)\\$/', $this->m_sTemplate, $aMatches);
foreach ($aMatches[1] as $sAttCode)
{
if (MetaModel::IsValidAttCode(get_class($this->m_oObj), $sAttCode))
{
$aTemplateFields[] = $sAttCode;
}
else
{
$aParams['this->'.$sAttCode] = "<!--Unknown attribute: $sAttCode-->";
}
}
preg_match_all('/\\$this->field\\(([a-z0-9_]+)\\)\\$/', $this->m_sTemplate, $aMatches);
foreach ($aMatches[1] as $sAttCode)
{
if (MetaModel::IsValidAttCode(get_class($this->m_oObj), $sAttCode))
{
$aTemplateFields[] = $sAttCode;
}
else
{
$aParams['this->field('.$sAttCode.')'] = "<!--Unknown attribute: $sAttCode-->";
}
}
$aFieldsComments = (isset($aParams['fieldsComments'])) ? $aParams['fieldsComments'] : array();
$aFieldsMap = array();
$sClass = get_class($this->m_oObj);
// Renders the fields used in the template
foreach(MetaModel::ListAttributeDefs(get_class($this->m_oObj)) as $sAttCode => $oAttDef)
{
$aParams['this->label('.$sAttCode.')'] = $oAttDef->GetLabel();
$aParams['this->comments('.$sAttCode.')'] = isset($aFieldsComments[$sAttCode]) ? $aFieldsComments[$sAttCode] : '';
$iInputId = '2_'.$sAttCode; // TODO: generate a real/unique prefix...
if (in_array($sAttCode, $aTemplateFields))
{
if ($this->m_oObj->IsNew())
{
$iFlags = $this->m_oObj->GetInitialStateAttributeFlags($sAttCode);
}
else
{
$iFlags = $this->m_oObj->GetAttributeFlags($sAttCode);
}
if (($iFlags & OPT_ATT_MANDATORY) && $this->m_oObj->IsNew())
{
$iFlags = $iFlags & ~OPT_ATT_READONLY; // Mandatory fields cannot be read-only when creating an object
}
if ((!$oAttDef->IsWritable()) || ($sStateAttCode == $sAttCode))
{
$iFlags = $iFlags | OPT_ATT_READONLY;
}
if ($iFlags & OPT_ATT_HIDDEN)
{
$aParams['this->label('.$sAttCode.')'] = '';
$aParams['this->field('.$sAttCode.')'] = '';
$aParams['this->comments('.$sAttCode.')'] = '';
$aParams['this->'.$sAttCode] = '';
}
else
{
if ($bEditMode && ($iFlags & (OPT_ATT_READONLY|OPT_ATT_SLAVE)))
{
// Check if the attribute is not read-only because of a synchro...
$aReasons = array();
$sSynchroIcon = '';
if ($iFlags & OPT_ATT_SLAVE)
{
$iSynchroFlags = $this->m_oObj->GetSynchroReplicaFlags($sAttCode, $aReasons);
$sAppRooturl = utils::GetAbsoluteUrlAppRoot();
$sSynchroIcon = "&nbsp;<img id=\"synchro_$iInputId\" src=\"{$sAppRooturl}images/transp-lock.png\" style=\"vertical-align:middle\"/>";
$sTip = '';
foreach($aReasons as $aRow)
{
$sDescription = utils::EscapeHtml($aRow['description']);
$sDescription = str_replace(array("\r\n", "\n"), "<br/>", $sDescription);
$sTip .= "<div class='synchro-source'>";
$sTip .= "<div class='synchro-source-title'>Synchronized with {$aRow['name']}</div>";
$sTip .= "<div class='synchro-source-description'>$sDescription</div>";
}
$oPage->add_ready_script("$('#synchro_$iInputId').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
}
// Attribute is read-only
$sHTMLValue = "<span id=\"field_{$iInputId}\">".$this->m_oObj->GetAsHTML($sAttCode);
$sHTMLValue .= '<input type="hidden" id="'.$iInputId.'" name="attr_'.$sAttCode.'" value="'.utils::EscapeHtml($this->m_oObj->Get($sAttCode)).'"/></span>';
$aFieldsMap[$sAttCode] = $iInputId;
$aParams['this->comments('.$sAttCode.')'] = $sSynchroIcon;
}
if ($bEditMode && !($iFlags & OPT_ATT_READONLY)) //TODO: check the data synchro status...
{
$aParams['this->field('.$sAttCode.')'] = "<span id=\"field_{$iInputId}\">".$this->m_oObj->GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef,
$this->m_oObj->Get($sAttCode),
$this->m_oObj->GetEditValue($sAttCode),
$iInputId, // InputID
'',
$iFlags,
array('this' => $this->m_oObj) // aArgs
).'</span>';
$aFieldsMap[$sAttCode] = $iInputId;
}
else
{
$aParams['this->field('.$sAttCode.')'] = $this->m_oObj->GetAsHTML($sAttCode);
}
$aParams['this->'.$sAttCode] = "<table class=\"field\"><tr><td class=\"label\">".$aParams['this->label('.$sAttCode.')'].":</td><td>".$aParams['this->field('.$sAttCode.')']."</td><td>".$aParams['this->comments('.$sAttCode.')']."</td></tr></table>";
}
}
}
// Renders the PlugIns used in the template
preg_match_all('/\\$PlugIn:([A-Za-z0-9_]+)->properties\\(\\)\\$/', $this->m_sTemplate, $aMatches);
$aPlugInProperties = $aMatches[1];
foreach($aPlugInProperties as $sPlugInClass)
{
/** @var \iApplicationUIExtension $oInstance */
$oInstance = MetaModel::GetPlugins('iApplicationUIExtension', $sPlugInClass);
if ($oInstance != null) // Safety check...
{
$offset = $oPage->start_capture();
$oInstance->OnDisplayProperties($this->m_oObj, $oPage, $bEditMode);
$sContent = $oPage->end_capture($offset);
$aParams["PlugIn:{$sPlugInClass}->properties()"]= $sContent;
}
else
{
$aParams["PlugIn:{$sPlugInClass}->properties()"]= "Missing PlugIn: $sPlugInClass";
}
}
$offset = $oPage->start_capture();
parent::Render($oPage, $aParams);
$sContent = $oPage->end_capture($offset);
// Remove empty table rows in case some attributes are hidden...
$sContent = preg_replace('/<tr[^>]*>\s*(<td[^>]*>\s*<\\/td>)+\s*<\\/tr>/im', '', $sContent);
$oPage->add($sContent);
return $aFieldsMap;
}
}
//DisplayTemplate::UnitTest();
?>

View File

@@ -55,18 +55,6 @@ class ThemeHandler
];
}
/**
* Return the ID of the theme currently defined in the config. file
*
* @deprecated 3.0.0, will be removed in 3.1, see N°3898
* @return string
*/
public static function GetCurrentThemeId()
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod();
static::GetCurrentUserThemeId();
}
/**
* @return string ID of the theme currently defined in the config. file, which applies to all users by default. If non defined, fallback on the default one.
* @since 3.0.0

View File

@@ -1,127 +0,0 @@
<?php
namespace Combodo\iTop;
use AttributeDate;
use AttributeDateTime;
use DeprecatedCallsLog;
use Dict;
use Exception;
use MetaModel;
use Twig\Environment;
use Twig\TwigFilter;
use Twig\TwigFunction;
use utils;
DeprecatedCallsLog::NotifyDeprecatedFile('instead use sources/Application/TwigBase/Twig/Extension.php, which is loaded by the autoloader');
/**
* Class TwigExtension
*
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @package Combodo\iTop
* @deprecated 3.1.0 N°4034
*/
class TwigExtension
{
/**
* Registers Twig extensions such as filters or functions.
* It allows us to access some stuff directly in twig.
*
* @param Environment $oTwigEnv
*/
public static function RegisterTwigExtensions(Environment &$oTwigEnv)
{
// Filter to translate a string via the Dict::S function
// Usage in twig: {{ 'String:ToTranslate'|dict_s }}
$oTwigEnv->addFilter(new TwigFilter('dict_s',
function ($sStringCode, $sDefault = null, $bUserLanguageOnly = false) {
return Dict::S($sStringCode, $sDefault, $bUserLanguageOnly);
})
);
// Filter to format a string via the Dict::Format function
// Usage in twig: {{ 'String:ToTranslate'|dict_format() }}
$oTwigEnv->addFilter(new TwigFilter('dict_format',
function ($sStringCode, $sParam01 = null, $sParam02 = null, $sParam03 = null, $sParam04 = null) {
return Dict::Format($sStringCode, $sParam01, $sParam02, $sParam03, $sParam04);
})
);
// Filter to format output
// example a DateTime is converted to user format
// Usage in twig: {{ 'String:ToFormat'|output_format }}
$oTwigEnv->addFilter(new TwigFilter('date_format',
function ($sDate) {
try {
if (preg_match('@^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d$@', trim($sDate))) {
return AttributeDateTime::GetFormat()->Format($sDate);
}
if (preg_match('@^\d\d\d\d-\d\d-\d\d$@', trim($sDate))) {
return AttributeDate::GetFormat()->Format($sDate);
}
}
catch (Exception $e)
{
}
return $sDate;
})
);
// Filter to format output
// example a DateTime is converted to user format
// Usage in twig: {{ 'String:ToFormat'|output_format }}
$oTwigEnv->addFilter(new TwigFilter('size_format',
function ($sSize) {
return utils::BytesToFriendlyFormat($sSize);
})
);
// Filter to enable base64 encode/decode
// Usage in twig: {{ 'String to encode'|base64_encode }}
$oTwigEnv->addFilter(new TwigFilter('base64_encode', 'base64_encode'));
$oTwigEnv->addFilter(new TwigFilter('base64_decode', 'base64_decode'));
// Filter to enable json decode (encode already exists)
// Usage in twig: {{ aSomeArray|json_decode }}
$oTwigEnv->addFilter(new TwigFilter('json_decode', function ($sJsonString, $bAssoc = false) {
return json_decode($sJsonString, $bAssoc);
})
);
// Filter to add itopversion to an url
$oTwigEnv->addFilter(new TwigFilter('add_itop_version', function ($sUrl) {
$sUrl = utils::AddParameterToUrl($sUrl, 'itopversion', ITOP_VERSION);
return $sUrl;
}));
// Filter to add a module's version to an url
$oTwigEnv->addFilter(new TwigFilter('add_module_version', function ($sUrl, $sModuleName) {
$sModuleVersion = utils::GetCompiledModuleVersion($sModuleName);
$sUrl = utils::AddParameterToUrl($sUrl, 'moduleversion', $sModuleVersion);
return $sUrl;
}));
// Function to check our current environment
// Usage in twig: {% if is_development_environment() %}
$oTwigEnv->addFunction(new TwigFunction('is_development_environment', function () {
return utils::IsDevelopmentEnvironment();
}));
// Function to get the URL of a static page in a module
// Usage in twig: {{ get_static_page_module_url('itop-my-module', 'path-to-my-page') }}
$oTwigEnv->addFunction(new TwigFunction('get_static_page_module_url', function ($sModuleName, $sPage) {
return utils::GetAbsoluteUrlModulesRoot().$sModuleName.'/'.$sPage;
}));
// Function to get the URL of a php page in a module
// Usage in twig: {{ get_page_module_url('itop-my-module', 'path-to-my-my-page.php') }}
$oTwigEnv->addFunction(new TwigFunction('get_page_module_url', function ($sModuleName, $sPage) {
return utils::GetAbsoluteUrlModulePage($sModuleName, $sPage);
}));
}
}

View File

@@ -1556,8 +1556,7 @@ class utils
$aResult[] = new JSPopupMenuItem('UI:Menu:AddToDashboard', Dict::S('UI:Menu:AddToDashboard'), "DashletCreationDlg('$sOQL', '$sContext')");
$aResult[] = new JSPopupMenuItem('UI:Menu:ShortcutList', Dict::S('UI:Menu:ShortcutList'), "ShortcutListDlg('$sOQL', '$sDataTableId', '$sContext')");
if (ApplicationMenu::IsMenuIdEnabled('RunQueriesMenu')) {
$oMenuItemPlay = new JSPopupMenuItem('UI:Menu:OpenOQL', Dict::S('UI:Edit:TestQuery'), "OpenOql('$sOQL')");
$oMenuItemPlay->SetIconClass('fas fa-play');
$oMenuItemPlay = new JSPopupMenuItem('UI:Menu:OpenOQL', Dict::S('UI:Menu:OpenOQL'), "OpenOql('$sOQL')");
$aResult[] = $oMenuItemPlay;
}
@@ -1571,9 +1570,6 @@ class utils
$oContainerBlock->AddJsFileRelPath('js/tabularfieldsselector.js');
$oContainerBlock->AddJsFileRelPath('js/jquery.dragtable.js');
$oContainerBlock->AddCssFileRelPath('css/dragtable.css');
$oContainerBlock->AddJsFileRelPath('js/tabularfieldsselector.js');
$oContainerBlock->AddJsFileRelPath('js/jquery.dragtable.js');
$oContainerBlock->AddCssFileRelPath('css/dragtable.css');
$aResult = array(
new SeparatorPopupMenuItem(),
@@ -2316,97 +2312,6 @@ SQL;
return @getimagesizefromstring($sImageData);
}
/**
* Resize an image attachment so that it fits in the given dimensions
* @param ormDocument $oImage The original image stored as an ormDocument
* @param int $iWidth Image's original width
* @param int $iHeight Image's original height
* @param int $iMaxImageWidth Maximum width for the resized image
* @param int $iMaxImageHeight Maximum height for the resized image
* @return ormDocument The resampled image
*/
public static function ResizeImageToFit(ormDocument $oImage, $iWidth, $iHeight, $iMaxImageWidth, $iMaxImageHeight)
{
// If image size smaller than maximums, we do nothing
if (($iWidth <= $iMaxImageWidth) && ($iHeight <= $iMaxImageHeight))
{
return $oImage;
}
// If gd extension is not loaded, we put a warning in the log and return the image as is
if (extension_loaded('gd') === false)
{
IssueLog::Warning('Image could not be resized as the "gd" extension does not seem to be loaded. It will remain as ' . $iWidth . 'x' . $iHeight . ' instead of ' . $iMaxImageWidth . 'x' . $iMaxImageHeight);
return $oImage;
}
switch($oImage->GetMimeType())
{
case 'image/gif':
case 'image/jpeg':
case 'image/png':
$img = @imagecreatefromstring($oImage->GetData());
break;
default:
// Unsupported image type, return the image as-is
//throw new Exception("Unsupported image type: '".$oImage->GetMimeType()."'. Cannot resize the image, original image will be used.");
return $oImage;
}
if ($img === false)
{
//throw new Exception("Warning: corrupted image: '".$oImage->GetFileName()." / ".$oImage->GetMimeType()."'. Cannot resize the image, original image will be used.");
return $oImage;
}
else
{
// Let's scale the image, preserving the transparency for GIFs and PNGs
$fScale = min($iMaxImageWidth / $iWidth, $iMaxImageHeight / $iHeight);
$iNewWidth = $iWidth * $fScale;
$iNewHeight = $iHeight * $fScale;
$new = imagecreatetruecolor($iNewWidth, $iNewHeight);
// Preserve transparency
if(($oImage->GetMimeType() == "image/gif") || ($oImage->GetMimeType() == "image/png"))
{
imagecolortransparent($new, imagecolorallocatealpha($new, 0, 0, 0, 127));
imagealphablending($new, false);
imagesavealpha($new, true);
}
imagecopyresampled($new, $img, 0, 0, 0, 0, $iNewWidth, $iNewHeight, $iWidth, $iHeight);
ob_start();
switch ($oImage->GetMimeType())
{
case 'image/gif':
imagegif($new); // send image to output buffer
break;
case 'image/jpeg':
imagejpeg($new, null, 80); // null = send image to output buffer, 80 = good quality
break;
case 'image/png':
imagepng($new, null, 5); // null = send image to output buffer, 5 = medium compression
break;
}
$oResampledImage = new ormDocument(ob_get_contents(), $oImage->GetMimeType(), $oImage->GetFileName());
@ob_end_clean();
imagedestroy($img);
imagedestroy($new);
return $oResampledImage;
}
}
/**
* Create a 128 bit UUID in the format: {########-####-####-####-############}
*
@@ -2897,21 +2802,6 @@ TXT
return static::$iNextId++;
}
/**
* @param string $sInterface
* @param string $sClassNameFilter
* @param array $aExcludedPath Reg. exp. of the paths to exclude. Note that backslashes (typically for Windows env.) need to be 4 backslashes, 2 for the escaping backslash, 2 for the actual backslash 😅
*
* @return array classes are returned in the same order as the module dependency tree, so core classes on top
* @since 3.0.0
* @deprecated 3.2.0 Use {@see InterfaceDiscovery::FindItopClasses()} instead
*/
public static function GetClassesForInterface(string $sInterface, string $sClassNameFilter = '', $aExcludedPath = []): array
{
$oInterfaceDiscoveryService = InterfaceDiscovery::GetInstance();
return $oInterfaceDiscoveryService->FindItopClasses($sInterface);
}
/**
* @return array All keyboard shortcuts config as an array
* @throws \CoreException

View File

@@ -1,8 +0,0 @@
<?php
/**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/WebPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2024 Combodo SAS
*/
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/WebPage.php, now loadable using autoloader');

View File

@@ -350,22 +350,6 @@ class WizardHelper
return $this->m_aData['m_bReturnNotEditableFields'] ?? false;
}
/**
* @return string JS code to be executed for fields update
* @since 3.0.0 N°3198
* @deprecated 3.0.3-2 3.0.4 3.1.1 3.2.0 Use {@see \WizardHelper::AddJsForUpdateFields()} instead
*/
public function GetJsForUpdateFields()
{
$sWizardHelperJsVar = (!is_null($this->m_aData['m_sWizHelperJsVarName'])) ? utils::Sanitize($this->m_aData['m_sWizHelperJsVarName'], '', utils::ENUM_SANITIZATION_FILTER_PARAMETER) : 'oWizardHelper'.$this->GetFormPrefix();
$sWizardHelperJson = $this->ToJSON();
return <<<JS
{$sWizardHelperJsVar}.m_oData = {$sWizardHelperJson};
{$sWizardHelperJsVar}.UpdateFields();
JS;
}
/**
* Add necessary JS snippets (to the page) to be executed for fields update
*

View File

@@ -1,8 +0,0 @@
<?php
/**
* @deprecated 3.0.0 will be removed in 3.1.0 - moved to sources/Application/WebPage/XMLPage.php, now loadable using autoloader
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2010-2024 Combodo SAS
*/
DeprecatedCallsLog::NotifyDeprecatedFile('moved to sources/Application/WebPage/XMLPage.php, now loadable using autoloader');

View File

@@ -18,7 +18,7 @@
"laminas/laminas-mail": "^2.11",
"laminas/laminas-servicemanager": "^3.5",
"league/oauth2-google": "^4.0.1",
"nikic/php-parser": "^4.14.0",
"nikic/php-parser": "~5.6.0",
"pear/archive_tar": "~1.4.14",
"pelago/emogrifier": "^7.2.0",
"psr/log": "^3.0.0",
@@ -72,7 +72,6 @@
"sources"
],
"exclude-from-classmap": [
"application/twigextension.class.inc.php",
"core/oql/build/PHP/",
"core/apc-emulation.php",
"application/startup.inc.php",

748
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -955,14 +955,9 @@ abstract class AttributeDefinition
//abstract protected GetBasicFilterHTMLInput();
abstract public function GetBasicFilterSQLExpr($sOpCode, $value);
/**
* since 3.1.0 return has changed (N°4690 - Deprecate "FilterCodes")
*
* @return array filtercode => attributecode
*/
public function GetFilterDefinitions()
public function GetMagicFields()
{
return array();
return [];
}
public function GetEditValue($sValue, $oHostObj = null)
@@ -2788,11 +2783,6 @@ class AttributeDBFieldVoid extends AttributeDefinition
return $aColumns;
}
public function GetFilterDefinitions()
{
return array($this->GetCode() => $this->GetCode());
}
public function GetBasicFilterOperators()
{
return array("=" => "equals", "!=" => "differs from");
@@ -4260,13 +4250,6 @@ class AttributePassword extends AttributeString implements iAttributeNoGroupBy
return 64;
}
public function GetFilterDefinitions()
{
// Note: due to this, you will get an error if a password is being declared as a search criteria (see ZLists)
// not allowed to search on passwords!
return array();
}
public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
{
if (utils::IsNullOrEmptyString($sValue))
@@ -4307,13 +4290,6 @@ class AttributeEncryptedString extends AttributeString implements iAttributeNoGr
return 255;
}
public function GetFilterDefinitions()
{
// Note: due to this, you will get an error if a an encrypted field is declared as a search criteria (see ZLists)
// not allowed to search on encrypted fields !
return array();
}
public function MakeRealValue($proposedValue, $oHostObj)
{
if (is_null($proposedValue))
@@ -7986,11 +7962,6 @@ class AttributeExternalField extends AttributeDefinition
return true;
}
public function GetFilterDefinitions()
{
return array($this->GetCode() => $this->GetCode());
}
public function GetBasicFilterOperators()
{
$oExtAttDef = $this->GetExtAttDef();
@@ -8479,11 +8450,6 @@ class AttributeBlob extends AttributeDefinition
return $aColumns;
}
public function GetFilterDefinitions()
{
return array();
}
public function GetBasicFilterOperators()
{
return array();
@@ -9123,20 +9089,19 @@ class AttributeStopWatch extends AttributeDefinition
return $aColumns;
}
public function GetFilterDefinitions()
public function GetMagicFields()
{
$aRes = array(
$this->GetCode() => $this->GetCode(),
$this->GetCode().'_started' => $this->GetCode(),
$this->GetCode().'_laststart' => $this->GetCode(),
$this->GetCode().'_stopped' => $this->GetCode(),
);
$aRes =[
$this->GetCode().'_started' ,
$this->GetCode().'_laststart',
$this->GetCode().'_stopped' ,
];
foreach ($this->ListThresholds() as $iThreshold => $aFoo) {
$sPrefix = $this->GetCode().'_'.$iThreshold;
$aRes[$sPrefix.'_deadline'] = $this->GetCode();
$aRes[$sPrefix.'_passed'] = $this->GetCode();
$aRes[$sPrefix.'_triggered'] = $this->GetCode();
$aRes[$sPrefix.'_overrun'] = $this->GetCode();
$aRes[] = $sPrefix.'_deadline';
$aRes[] = $sPrefix.'_passed';
$aRes[] = $sPrefix.'_triggered';
$aRes[] = $sPrefix.'_overrun';
}
return $aRes;
@@ -9912,11 +9877,6 @@ class AttributeSubItem extends AttributeDefinition
return array();
}
public function GetFilterDefinitions()
{
return array($this->GetCode() => $this->GetCode());
}
public function GetBasicFilterOperators()
{
return array();
@@ -10199,12 +10159,6 @@ class AttributeOneWayPassword extends AttributeDefinition implements iAttributeN
return $oPassword;
}
public function GetFilterDefinitions()
{
return array();
// still not working... see later...
}
public function GetBasicFilterOperators()
{
return array();
@@ -12652,11 +12606,6 @@ class AttributeFriendlyName extends AttributeDefinition
return '';
}
public function GetFilterDefinitions()
{
return array($this->GetCode() => $this->GetCode());
}
public function GetBasicFilterOperators()
{
return array("=" => "equals", "!=" => "differs from");
@@ -13111,7 +13060,7 @@ class AttributeRedundancySettings extends AttributeDBField
$sEditValue = $bSelected ? $iCurrentValue : '';
$sValue = '<input class="redundancy-min-up-count" type="string" size="3" name="'.$sName.'" value="'.$sEditValue.'">';
// To fix an issue on Firefox: focus set to the option (because the input is within the label for the option)
$oPage->add_ready_script("\$('[name=\"$sName\"]').on('click', function(){var me=this; setTimeout(function(){\$(me).focus();}, 100);});");
$oPage->add_ready_script("\$('[name=\"$sName\"]').on('click', function(){var me=this; setTimeout(function(){\$(me).trigger('focus');}, 100);});");
}
else
{
@@ -13126,7 +13075,7 @@ class AttributeRedundancySettings extends AttributeDBField
$sEditValue = $bSelected ? $iCurrentValue : '';
$sValue = '<input class="redundancy-min-up-percent" type="string" size="3" name="'.$sName.'" value="'.$sEditValue.'">';
// To fix an issue on Firefox: focus set to the option (because the input is within the label for the option)
$oPage->add_ready_script("\$('[name=\"$sName\"]').on('click', function(){var me=this; setTimeout(function(){\$(me).focus();}, 100);});");
$oPage->add_ready_script("\$('[name=\"$sName\"]').on('click', function(){var me=this; setTimeout(function(){\$(me).trigger('focus');}, 100);});");
}
else
{

View File

@@ -39,7 +39,6 @@ require_once('kpi.class.inc.php');
require_once('dict.class.inc.php');
require_once('attributedef.class.inc.php');
require_once('filterdef.class.inc.php');
require_once('stimulus.class.inc.php');
require_once('valuesetdef.class.inc.php');
require_once('MyHelpers.class.inc.php');
@@ -397,60 +396,7 @@ abstract class CMDBObject extends DBObject
}
}
/**
* Helper to ultimately check user rights before writing (Insert, Update or Delete)
* The check should never fail, because the UI should prevent from such a usage
* Anyhow, if the user has found a workaround... the security gets enforced here
*
* @deprecated 3.0.0 N°2591 will be removed in 3.1.0
*
* @param bool $bSkipStrongSecurity
* @param int $iActionCode
*
* @throws \SecurityException
*/
protected function CheckUserRights($bSkipStrongSecurity, $iActionCode)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod();
if (is_null($bSkipStrongSecurity)) {
// This is temporary
// We have implemented this safety net right before releasing iTop 1.0
// and we decided that it was too risky to activate it
// Anyhow, users willing to have a very strong security could set
// skip_strong_security = 0, in the config file
$bSkipStrongSecurity = MetaModel::GetConfig()->Get('skip_strong_security');
}
if (!$bSkipStrongSecurity)
{
$sClass = get_class($this);
$oSet = DBObjectSet::FromObject($this);
if (!UserRights::IsActionAllowed($sClass, $iActionCode, $oSet))
{
// Intrusion detected
throw new SecurityException('You are not allowed to modify objects of class: '.$sClass);
}
}
}
public function DBClone($newKey = null)
{
return $this->DBCloneTracked_Internal();
}
/**
* @deprecated 3.1.0 N°5232 N°6966 simply use {@see DBObject::DBClone()} instead, that will automatically create and persist a CMDBChange object.
* If you need to persist your own, call {@see CMDBObject::SetCurrentChange()} before.
*/
public function DBCloneTracked(CMDBChange $oChange, $newKey = null)
{
self::SetCurrentChange($oChange);
$this->DBCloneTracked_Internal($newKey);
}
/**
* @deprecated 3.1.1 3.2.0 N°6966 We will have only one DBClone method in the future
*/
protected function DBCloneTracked_Internal($newKey = null)
{
$newKey = parent::DBClone($newKey);
$oClone = MetaModel::GetObject(get_class($this), $newKey);
@@ -479,16 +425,6 @@ abstract class CMDBObject extends DBObject
return $oDeletionPlan;
}
/**
* @deprecated 3.1.1 3.2.0 N°6967 We will have only one DBDelete method in the future
*/
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
{
$ret = parent::DBDelete($oDeletionPlan);
return $ret;
}
public function DBArchive()
{
// Note: do the job anyway, so as to repair any DB discrepancy

View File

@@ -308,15 +308,6 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
],
// Deprecated in 3.0.0 N°2591 Will be removed in 3.1
'skip_strong_security' => [
'type' => 'bool',
'description' => 'Disable strong security - TEMPORARY: this flag should be removed when we are more confident in the recent change in security',
'default' => true,
'value' => true,
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'query_optimization_enabled' => [
'type' => 'bool',
'description' => 'The queries are optimized based on the assumption that the DB integrity has been preserved. By disabling the optimization one can ensure that the fetched data is clean... but this can be really slower or not usable at all (some queries will exceed the allowed number of joins in MySQL: 61!)',
@@ -2865,20 +2856,8 @@ class Config
}
}
}
if (isset($aModuleInfo['installer']))
{
$sModuleInstallerClass = $aModuleInfo['installer'];
if (!class_exists($sModuleInstallerClass))
{
throw new Exception("Wrong installer class: '$sModuleInstallerClass' is not a PHP class - Module: ".$aModuleInfo['label']);
}
if (!is_subclass_of($sModuleInstallerClass, 'ModuleInstallerAPI'))
{
throw new Exception("Wrong installer class: '$sModuleInstallerClass' is not derived from 'ModuleInstallerAPI' - Module: ".$aModuleInfo['label']);
}
$aCallSpec = array($sModuleInstallerClass, 'BeforeWritingConfig');
call_user_func_array($aCallSpec, array($this));
}
RunTimeEnvironment::CallInstallerHandler($aModuleInfo, "BeforeWritingConfig", [$this]);
}
}
$this->SetAddOns($aAddOns);

View File

@@ -1,11 +0,0 @@
<?php
/**
* This file is only here for compatibility reasons.
* It will be removed in future iTop versions (N°6533)
*
* @deprecated 3.0.0 N°3663 Exception classes were moved to `/application/exceptions`, use autoloader instead of require !
*/
require_once __DIR__ . '/../approot.inc.php';
DeprecatedCallsLog::NotifyDeprecatedFile('Classes were moved to /application/exceptions and can be used directly with the autoloader');

View File

@@ -417,8 +417,17 @@ class DBObjectSearch extends DBSearch
*/
public function AddCondition($sFilterCode, $value, $sOpCode = null, $bParseSearchString = false)
{
MyHelpers::CheckKeyInArray('filter code in class: '.$this->GetClass(), $sFilterCode, MetaModel::GetFilterAttribList($this->GetClass()));
if (MetaModel::IsValidFilterCode($this->GetClass(),$sFilterCode) == false){
/* $sArrayDesc = if (count($aData) == 0)
{
$sArrayDesc = "{}";
}
else
{
$sArrayDesc = "{".implode(", ", $aData)."}";
}*/
throw new CoreException("Wrong value for '".$this->GetClass()."', found '$sFilterCode'");// while expecting a value in $sArrayDesc");
}
$oField = new FieldExpression($sFilterCode, $this->GetClassAlias());
if (empty($sOpCode)) {
if ($sFilterCode == 'id') {
@@ -1364,44 +1373,41 @@ class DBObjectSearch extends DBSearch
$this->m_aParams[$sKey] = $value;
}
public function GetQueryParams($bExcludeMagicParams = true)
public function GetQueryParams()
{
$aParams = array();
$this->m_oSearchCondition->RenderExpression(false, $aParams, true);
if ($bExcludeMagicParams)
{
$aRet = array();
$aRet = array();
// Make the list of acceptable arguments... could be factorized with run_query, into oSearch->GetQueryParams($bExclude magic params)
$aNakedMagicArguments = array();
foreach (MetaModel::PrepareQueryArguments(array(),array(), $this->GetExpectedArguments()) as $sArgName => $value)
// Make the list of acceptable arguments... could be factorized with run_query, into oSearch->GetQueryParams()
$aNakedMagicArguments = array();
foreach (MetaModel::PrepareQueryArguments(array(),array(), $this->GetExpectedArguments()) as $sArgName => $value)
{
$iPos = strpos($sArgName, '->object()');
if ($iPos === false)
{
$iPos = strpos($sArgName, '->object()');
if ($iPos === false)
{
$aNakedMagicArguments[$sArgName] = $value;
}
else
{
$aNakedMagicArguments[substr($sArgName, 0, $iPos)] = true;
}
$aNakedMagicArguments[$sArgName] = $value;
}
foreach ($aParams as $sParam => $foo)
else
{
$iPos = strpos($sParam, '->');
if ($iPos === false)
{
$sRefName = $sParam;
}
else
{
$sRefName = substr($sParam, 0, $iPos);
}
if (!array_key_exists($sRefName, $aNakedMagicArguments))
{
$aRet[$sParam] = $foo;
}
$aNakedMagicArguments[substr($sArgName, 0, $iPos)] = true;
}
}
foreach ($aParams as $sParam => $foo)
{
$iPos = strpos($sParam, '->');
if ($iPos === false)
{
$sRefName = $sParam;
}
else
{
$sRefName = substr($sParam, 0, $iPos);
}
if (!array_key_exists($sRefName, $aNakedMagicArguments))
{
$aRet[$sParam] = $foo;
}
}

View File

@@ -372,7 +372,7 @@ abstract class DBSearch
* @internal
*
* @param string $sAttSpec Can be either an attribute code or extkey->[sAttSpec] or linkset->[sAttSpec] and so on, recursively
* Example: infra_list->ci_id->location_id->country
* Example: infra_list->ci_id->location_id->country
* @param mixed $value The value to match (can be an array => IN(val1, val2...)
* @return void
*/
@@ -533,11 +533,9 @@ abstract class DBSearch
/**
* @internal
*
* @param bool $bExcludeMagicParams
*
* @return mixed
*/
abstract public function GetQueryParams($bExcludeMagicParams = true);
abstract public function GetQueryParams();
/**
* @internal
@@ -771,7 +769,7 @@ abstract class DBSearch
$oKPI = new ExecutionKPI();
$result = apc_fetch($sAPCCacheId);
$oKPI->ComputeStats('Search APC (fetch)', $sQuery);
if (is_object($result))
{
$oResultFilter = $result;
@@ -787,17 +785,17 @@ abstract class DBSearch
$oOql = new OqlInterpreter($sQuery);
$oOqlQuery = $oOql->ParseQuery();
if ($oMetaModel === null)
{
$oMetaModel = new ModelReflectionRuntime();
}
$oOqlQuery->Check($oMetaModel, $sQuery); // Exceptions thrown in case of issue
$oResultFilter = $oOqlQuery->ToDBSearch($sQuery);
$oKPI->ComputeStats('Parse OQL', $sQuery);
if ($bOQLCacheEnabled)
{
self::$m_aOQLQueries[$sQueryId] = $oResultFilter->DeepClone();
@@ -1089,17 +1087,17 @@ abstract class DBSearch
{
$aOrderSpec[$sSQLExpression] = $bAscending;
}
}
else
{
$aOrderSpec['`'.$sAttClassAlias.$sAttCode.'`'] = $bAscending;
}
// Make sure that the columns used for sorting are present in the loaded columns
if (!is_null($aAttToLoad) && !isset($aAttToLoad[$sAttClassAlias][$sAttCode]))
{
$aAttToLoad[$sAttClassAlias][$sAttCode] = MetaModel::GetAttributeDef($sAttClass, $sAttCode);
}
}
}
else
{
$aOrderSpec['`'.$sAttClassAlias.$sAttCode.'`'] = $bAscending;
}
}
$oSQLQuery = $this->GetSQLQuery($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount);
@@ -1257,7 +1255,7 @@ abstract class DBSearch
$oSQLQueryExt = new SQLObjectQuery($aExtendedDataSpec['table'], $sTableAlias, $aExtendedFields);
$oSQLQuery->AddInnerJoin($oSQLQueryExt, 'id', $aExtendedDataSpec['join_key'] /*, $sTableAlias*/);
}
return $oSQLQuery;
}
@@ -1592,7 +1590,7 @@ abstract class DBSearch
}
$aBacktrace = debug_backtrace();
$iCallStackPos = count($aBacktrace) - self::$m_bDebugQuery;
$sIndent = "";
$sIndent = "";
for ($i = 0 ; $i < $iCallStackPos ; $i++)
{
$sIndent .= " .-=^=-. ";

View File

@@ -479,12 +479,12 @@ class DBUnionSearch extends DBSearch
return $aParams;
}
public function GetQueryParams($bExcludeMagicParams = true)
public function GetQueryParams()
{
$aParams = array();
foreach ($this->aSearches as $oSearch)
{
$aParams = array_merge($oSearch->GetQueryParams($bExcludeMagicParams), $aParams);
$aParams = array_merge($oSearch->GetQueryParams(), $aParams);
}
return $aParams;
}

View File

@@ -1416,32 +1416,6 @@ class DisplayableGraph extends SimpleGraph
return $aContextDefs;
}
/**
* Display the graph inside the given page, with the "filter" drawer above it
*
* @deprecated 3.1.1 3.2.0 N°3767 Use \DisplayableGraph::DisplayFilterBox() and \DisplayableGraph::DisplayGraph() instead
*
* @param WebPage $oP
* @param array $aResults
* @param string $sRelation
* @param ApplicationContext $oAppContext
* @param array $aExcludedObjects
* @param string $sObjClass
* @param int $iObjKey
* @param string $sContextKey
* @param array $aContextParams
* @param bool $bLazyLoading since 2.7.7 3.0.1
*
* @throws \CoreException
* @throws \DictExceptionMissingString
*
*/
function Display(WebPage $oP, $aResults, $sRelation, ApplicationContext $oAppContext, $aExcludedObjects, $sObjClass, $iObjKey, $sContextKey, $aContextParams = array(), bool $bLazyLoading = false)
{
$oP->AddSubBlock($this->DisplayFilterBox($oP, $aResults, $bLazyLoading));
$this->DisplayGraph($oP, $sRelation, $oAppContext, $aExcludedObjects, $sObjClass, $iObjKey, $sContextKey, $aContextParams, $bLazyLoading);
}
/**
* Display only the graph inside the given page, with the parameters of filter box draw with DisplayFilterBox
*
@@ -1581,31 +1555,6 @@ EOF
);
}
/**
* @param string $sContextKey
* @param array $aContextParams
* @param array $aExcludedObjects
* @param WebPage $oP
* @param array $aResults
* @param bool $bLazyLoading
*
* @return array
* @throws \CoreException
* @throws \DictExceptionMissingString
* @throws \ReflectionException
* @throws \Twig\Error\LoaderError
* @throws \Twig\Error\RuntimeError
* @throws \Twig\Error\SyntaxError
*
* @deprecated 3.1.1 3.2.0 N°3767 Use \DisplayableGraph::DisplayFilterBox() and \DisplayableGraph::GetFilteringData() instead
*/
public function DisplayFiltering(string $sContextKey, array $aContextParams, array $aExcludedObjects, WebPage $oP, array $aResults, bool $bLazyLoading = false): array
{
$oP->Add($this->DisplayFilterBox($oP, $aResults, $bLazyLoading));
return $this->GetFilteringData($sContextKey, $aContextParams, $aExcludedObjects);
}
/**
* @param WebPage $oP
* @param array $aResults

View File

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

View File

@@ -1,216 +0,0 @@
<?php
// Copyright (C) 2010-2024 Combodo SAS
//
// 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/>
/**
* Definition of a filter
* Most of the time, a filter corresponds to an attribute, but we could imagine other search criteria
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once('MyHelpers.class.inc.php');
/**
* Definition of a filter (could be made out of an existing attribute, or from an expression)
*
* @deprecated 3.1.0 not used N°4690 - Deprecate "FilterCodes"
* @package iTopORM
*/
abstract class FilterDefinition
{
abstract public function GetType();
abstract public function GetTypeDesc();
protected $m_sCode;
private $m_aParams = array();
protected function Get($sParamName) {return $this->m_aParams[$sParamName];}
public function __construct($sCode, $aParams = array())
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod("Deprecated class ".$this->GetClass().". Do not use. Will be removed in next version.");
$this->m_sCode = $sCode;
$this->m_aParams = $aParams;
$this->ConsistencyCheck();
}
// to be overloaded
static protected function ListExpectedParams()
{
return array();
}
private function ConsistencyCheck()
{
// Check that any mandatory param has been specified
//
$aExpectedParams = $this->ListExpectedParams();
foreach($aExpectedParams as $sParamName)
{
if (!array_key_exists($sParamName, $this->m_aParams))
{
$aBacktrace = debug_backtrace();
$sTargetClass = $aBacktrace[2]["class"];
$sCodeInfo = $aBacktrace[1]["file"]." - ".$aBacktrace[1]["line"];
throw new CoreException("ERROR missing parameter '$sParamName' in ".get_class($this)." declaration for class $sTargetClass ($sCodeInfo)");
}
}
}
public function GetCode() {return $this->m_sCode;}
abstract public function GetLabel();
abstract public function GetValuesDef();
// returns an array of opcode=>oplabel (e.g. "differs from")
abstract public function GetOperators();
// returns an opcode
abstract public function GetLooseOperator();
abstract public function GetSQLExpressions();
// Wrapper - no need for overloading this one
public function GetOpDescription($sOpCode)
{
$aOperators = $this->GetOperators();
if (!array_key_exists($sOpCode, $aOperators))
{
throw new CoreException("Unknown operator '$sOpCode'");
}
return $aOperators[$sOpCode];
}
}
/**
* Match against the object unique identifier
*
* @deprecated 3.1.0 N°4690 - Deprecate "FilterCodes"
* @package iTopORM
*/
class FilterPrivateKey extends FilterDefinition
{
static protected function ListExpectedParams()
{
return array_merge(parent::ListExpectedParams(), array("id_field"));
}
public function GetType() {return "PrivateKey";}
public function GetTypeDesc() {return "Match against object identifier";}
public function GetLabel()
{
return "Object Private Key";
}
public function GetValuesDef()
{
return null;
}
public function GetOperators()
{
return array(
"="=>"equals",
"!="=>"differs from",
"IN"=>"in",
"NOTIN"=>"not in"
);
}
public function GetLooseOperator()
{
return "IN";
}
public function GetSQLExpressions()
{
return array(
'' => $this->Get("id_field"),
);
}
}
/**
* Match against an existing attribute (the attribute type will determine the available operators)
*
* @deprecated 3.1.0 N°4690 - Deprecate "FilterCodes"
* @package iTopORM
*/
class FilterFromAttribute extends FilterDefinition
{
static protected function ListExpectedParams()
{
return array_merge(parent::ListExpectedParams(), array("refattribute"));
}
public function __construct($oRefAttribute, $sSuffix = '')
{
// In this very specific case, the code is the one of the attribute
// (this to get a very very simple syntax upon declaration)
$aParam = array();
$aParam["refattribute"] = $oRefAttribute;
parent::__construct($oRefAttribute->GetCode().$sSuffix, $aParam);
}
public function GetType() {return "Basic";}
public function GetTypeDesc() {return "Match against field contents";}
public function __GetRefAttribute() // for checking purposes only !!!
{
return $oAttDef = $this->Get("refattribute");
}
public function GetLabel()
{
$oAttDef = $this->Get("refattribute");
return $oAttDef->GetLabel();
}
public function GetValuesDef()
{
$oAttDef = $this->Get("refattribute");
return $oAttDef->GetValuesDef();
}
public function GetAllowedValues($aArgs = array(), $sContains = '')
{
$oAttDef = $this->Get("refattribute");
return $oAttDef->GetAllowedValues($aArgs, $sContains);
}
public function GetOperators()
{
$oAttDef = $this->Get("refattribute");
return $oAttDef->GetBasicFilterOperators();
}
public function GetLooseOperator()
{
$oAttDef = $this->Get("refattribute");
return $oAttDef->GetBasicFilterLooseOperator();
}
public function GetSQLExpressions()
{
$oAttDef = $this->Get("refattribute");
return $oAttDef->GetSQLExpressions();
}
}
?>

View File

@@ -37,7 +37,7 @@ class iTopConfigParser
*/
public function __construct($sConfig)
{
$oParser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
$oParser = (new ParserFactory())->createForNewestSupportedVersion();
$this->aVarsMap = array(
'MySettings' => array(),

View File

@@ -407,86 +407,12 @@ JS
* Resize an image so that it fits the maximum width/height defined in the config file
* @param ormDocument $oImage The original image stored as an array (content / mimetype / filename)
* @return ormDocument The resampled image (or the original one if it already fit)
* @deprecated Replaced by ormDocument::ResizeImageToFit
*/
public static function ResizeImageToFit(ormDocument $oImage, &$aDimensions = null)
{
$img = false;
switch($oImage->GetMimeType())
{
case 'image/gif':
case 'image/jpeg':
case 'image/png':
$img = @imagecreatefromstring($oImage->GetData());
break;
default:
// Unsupported image type, return the image as-is
$aDimensions = null;
return $oImage;
}
if ($img === false)
{
$aDimensions = null;
return $oImage;
}
else
{
// Let's scale the image, preserving the transparency for GIFs and PNGs
$iWidth = imagesx($img);
$iHeight = imagesy($img);
$aDimensions = array('width' => $iWidth, 'height' => $iHeight);
$iMaxImageSize = (int)MetaModel::GetConfig()->Get('inline_image_max_storage_width', 0);
if (($iMaxImageSize > 0) && ($iWidth <= $iMaxImageSize) && ($iHeight <= $iMaxImageSize))
{
// No need to resize
return $oImage;
}
$fScale = min($iMaxImageSize / $iWidth, $iMaxImageSize / $iHeight);
$iNewWidth = (int) ($iWidth * $fScale);
$iNewHeight = (int) ($iHeight * $fScale);
$aDimensions['width'] = $iNewWidth;
$aDimensions['height'] = $iNewHeight;
$new = imagecreatetruecolor($iNewWidth, $iNewHeight);
// Preserve transparency
if(($oImage->GetMimeType() == "image/gif") || ($oImage->GetMimeType() == "image/png"))
{
imagecolortransparent($new, imagecolorallocatealpha($new, 0, 0, 0, 127));
imagealphablending($new, false);
imagesavealpha($new, true);
}
imagecopyresampled($new, $img, 0, 0, 0, 0, $iNewWidth, $iNewHeight, $iWidth, $iHeight);
ob_start();
switch ($oImage->GetMimeType())
{
case 'image/gif':
imagegif($new); // send image to output buffer
break;
case 'image/jpeg':
imagejpeg($new, null, 80); // null = send image to output buffer, 80 = good quality
break;
case 'image/png':
imagepng($new, null, 5); // null = send image to output buffer, 5 = medium compression
break;
}
$oNewImage = new ormDocument(ob_get_contents(), $oImage->GetMimeType(), $oImage->GetFileName());
@ob_end_clean();
imagedestroy($img);
imagedestroy($new);
return $oNewImage;
}
$iMaxImageSize = (int)MetaModel::GetConfig()->Get('inline_image_max_storage_width', 0);
return $oImage->ResizeImageToFit($iMaxImageSize, $iMaxImageSize, $aDimensions);
}
/**

View File

@@ -1134,22 +1134,6 @@ abstract class MetaModel
return self::$m_aAttribOrigins[$sClass][$sAttCode];
}
/** *
* @param string $sClass
* @param string $sAttCode
*
* @return mixed
* @throws \CoreException
*/
final public static function GetFilterCodeOrigin($sClass, $sAttCode)
{
if ($sAttCode == 'id') {
return MetaModel::GetRootClass($sClass);
}
return MetaModel::GetAttributeOrigin($sClass, self::$m_aFilterAttribList[$sClass][$sAttCode]);
}
/**
* @param string $sClass
* @param string $sAttCode
@@ -1508,9 +1492,21 @@ abstract class MetaModel
*/
final public static function GetFiltersList($sClass)
{
self::_check_subclass($sClass);
return array_keys(self::$m_aFilterAttribList[$sClass]);
$aFilterList = MetaModel::GetAttributesList($sClass);
if (array_key_exists($sClass, self::$m_aFilterForbiddenAttributes)) {
// Remove the attributes that are not allowed in filters
foreach (self::$m_aFilterForbiddenAttributes[$sClass] as $sAttCode) {
if (array_key_exists($sAttCode, $aFilterList)) {
unset($aFilterList[$sAttCode]);
}
}
}
if (array_key_exists($sClass, self::$m_aMagicFields)) {
// Add the magic fields
$aFilterList = array_merge($aFilterList,self::$m_aMagicFields[$sClass]);
}
$aFilterList[] = 'id';
return $aFilterList;
}
/**
@@ -1613,11 +1609,16 @@ abstract class MetaModel
*/
final public static function IsValidFilterCode($sClass, $sFilterCode)
{
if (!array_key_exists($sClass, self::$m_aFilterAttribList)) {
if ($sFilterCode == 'id') {
return true;
}
if (array_key_exists($sClass, self::$m_aMagicFields) && array_key_exists($sFilterCode, self::$m_aMagicFields[$sClass])) {
return true;
}
if (array_key_exists($sClass, self::$m_aFilterForbiddenAttributes) && array_key_exists($sFilterCode, self::$m_aFilterForbiddenAttributes[$sClass])) {
return false;
}
return (array_key_exists($sFilterCode, self::$m_aFilterAttribList[$sClass]));
return self::IsValidAttCode($sClass, $sFilterCode);
}
/**
@@ -1899,54 +1900,14 @@ abstract class MetaModel
}
/**
* @var array array of (FilterCode => AttributeCode)
* @var array array of MagicFieldName
*/
private static $m_aFilterAttribList = array();
private static $m_aMagicFields = [];
/**
* @deprecated 3.0.0 do not use : dead code, will be removed in the future N°4690 - Deprecate "FilterCodes"
* instead of array_keys(MetaModel::GetClassFilterDefs($sClass)); use MetaModel::GetFiltersList($sClass)
*
* @param string $sClass
*
* @return mixed
* @throws \CoreException
* @var array array of filter Forbidden Attributes
*/
public static function GetClassFilterDefs($sClass)
{
// cannot notify depreciation for now as this is still MASSIVELY used in iTop core !
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use MetaModel::GetClassFilterDefs: dead code, will be removed in the future. Use MetaModel::GetFiltersList or MetaModel::GetFiltersAttributes');
return self::$m_aFilterAttribList[$sClass];
}
/**
*
* @param string $sClass
*
* @return array ($sFilterCode=>$sAttributeCode) + id=>id
* @throws \CoreException
*/
public static function GetFilterAttribList($sClass)
{
return self::$m_aFilterAttribList[$sClass];
}
/**
* @deprecated 3.0.0 do not use : dead code, will be removed in the future use GetLabel instead N°4690 - Deprecate "FilterCodes"
*
* @param string $sClass
* @param string $sFilterCode
*
* @return string
* @throws \CoreException
*/
public static function GetFilterLabel($sClass, $sFilterCode)
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use MetaModel::GetFilterLabel : dead code, will be removed in the future. Use MetaModel::GetLabel instead');
return this::GetLabel($sClass, $sFilterCode);
}
private static $m_aFilterForbiddenAttributes = [];
/**
* @var array array of ("listcode" => various info on the list, common to every classes)
@@ -2820,25 +2781,6 @@ abstract class MetaModel
return $oAttDef->GetAllowedValues($aArgs, $sContains);
}
/**
* @deprecated 3.1.0 use GetAllowedValues_att N°4690 - Deprecate "FilterCodes"
*
* @param string $sClass
* @param string $sFltCode
* @param array $aArgs
* @param string $sContains
*
* @return mixed
* @throws \CoreException
*/
public static function GetAllowedValues_flt($sClass, $sFltCode, $aArgs = array(), $sContains = '')
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('do not use MetaModel::GetAllowedValues_flt: dead code, will be removed in the future. Use MetaModel::GetAllowedValues');
return self::GetAllowedValues_att($sClass, $sFltCode);
}
/**
* @param string $sClass
* @param string $sAttCode
@@ -2911,8 +2853,6 @@ abstract class MetaModel
$oAttribute->SetHostClass($sTargetClass);
self::$m_aAttribDefs[$sTargetClass][$sCode] = $oAttribute;
self::$m_aAttribOrigins[$sTargetClass][$sCode] = $sOriginClass;
self::$m_aFilterAttribList[$sTargetClass][$sCode] = $sCode;
}
/**
@@ -3076,9 +3016,6 @@ abstract class MetaModel
if (array_key_exists('finalclass', self::$m_aAttribDefs[$sChildClass])) {
throw new CoreException("Class $sChildClass, 'finalclass' is a reserved keyword, it cannot be used as an attribute code");
}
if (array_key_exists('finalclass', self::$m_aFilterAttribList[$sChildClass])) {
throw new CoreException("Class $sChildClass, 'finalclass' is a reserved keyword, it cannot be used as a filter code");
}
$oCloned = clone $oClassAtt;
$oCloned->SetFixedValue($sChildClass);
self::AddMagicAttribute($oCloned, $sChildClass, $sRootClass);
@@ -3142,8 +3079,17 @@ abstract class MetaModel
foreach (self::$m_aAttribDefs[$sClass] as $sAttCode => $oAttDef) {
// Compute the filter codes
//
foreach ($oAttDef->GetFilterDefinitions() as $sFilterCode => $sCode) {
self::$m_aFilterAttribList[$sClass][$sFilterCode] = $sCode;
foreach ($oAttDef->GetMagicFields() as $sCode) {
if(!array_key_exists($sClass, self::$m_aMagicFields)) {
self::$m_aMagicFields[] = $sClass;
}
self::$m_aMagicFields[$sClass][] = $sCode;
}
if(!$oAttDef->IsSearchable()){
if(!array_key_exists($sClass, self::$m_aFilterForbiddenAttributes)) {
self::$m_aFilterForbiddenAttributes[] = $sClass;
}
self::$m_aFilterForbiddenAttributes[$sClass][] = $sAttCode;
}
// Compute the fields that will be used to display a pointer to another object
@@ -3252,7 +3198,6 @@ abstract class MetaModel
if (array_key_exists('id', self::$m_aAttribDefs[$sClass])) {
throw new CoreException("Class $sClass, 'id' is a reserved keyword, it cannot be used as an attribute code");
}
self::$m_aFilterAttribList[$sClass]['id'] = 'id';
}
}
@@ -3412,7 +3357,6 @@ abstract class MetaModel
self::$m_aAttribDefs[$sClass] = array();
self::$m_aAttribOrigins[$sClass] = array();
self::$m_aFilterAttribList[$sClass] = array();
}
/**
@@ -6512,7 +6456,8 @@ abstract class MetaModel
self::$m_aAttribDefs = $result['m_aAttribDefs'];
self::$m_aAttribOrigins = $result['m_aAttribOrigins'];
self::$m_aIgnoredAttributes = $result['m_aIgnoredAttributes'];
self::$m_aFilterAttribList = $result['m_aFilterList'];
self::$m_aFilterForbiddenAttributes = $result['m_aFilterForbiddenAttributes'];
self::$m_aMagicFields = $result['m_aMagicFields'];
self::$m_aListInfos = $result['m_aListInfos'];
self::$m_aListData = $result['m_aListData'];
self::$m_aRelationInfos = $result['m_aRelationInfos'];
@@ -6548,7 +6493,8 @@ abstract class MetaModel
$aCache['m_aAttribDefs'] = self::$m_aAttribDefs; // array of ("classname" => array of attributes)
$aCache['m_aAttribOrigins'] = self::$m_aAttribOrigins; // array of ("classname" => array of ("attcode"=>"sourceclass"))
$aCache['m_aIgnoredAttributes'] = self::$m_aIgnoredAttributes; //array of ("classname" => array of ("attcode")
$aCache['m_aFilterList'] = self::$m_aFilterAttribList; // array of ("classname" => array filterdef)
$aCache['m_aFilterForbiddenAttributes'] = self::$m_aFilterForbiddenAttributes; // array of ("classname" => array attributename)
$aCache['m_aMagicFields'] = self::$m_aMagicFields; // array of ("classname" => array fieldname)
$aCache['m_aListInfos'] = self::$m_aListInfos; // array of ("listcode" => various info on the list, common to every classes)
$aCache['m_aListData'] = self::$m_aListData; // array of ("classname" => array of "listcode" => list)
$aCache['m_aRelationInfos'] = self::$m_aRelationInfos; // array of ("relcode" => various info on the list, common to every classes)
@@ -7765,7 +7711,6 @@ abstract class MetaModel
'iApplicationUIExtension',
'iApplicationObjectExtension',
'iPopupMenuExtension',
'iPageUIExtension',
'iPageUIBlockExtension',
'iBackofficeLinkedScriptsExtension',
'iBackofficeEarlyScriptExtension',
@@ -7774,6 +7719,7 @@ abstract class MetaModel
'iBackofficeReadyScriptExtension',
'iBackofficeLinkedStylesheetsExtension',
'iBackofficeStyleExtension',
'iBackofficeSassExtension',
'iBackofficeDictEntriesExtension',
'iBackofficeDictEntriesPrefixesExtension',
'iPortalUIExtension',
@@ -7782,7 +7728,6 @@ abstract class MetaModel
'iModuleExtension',
'iKPILoggerExtension',
'ModuleHandlerApiInterface',
'iNewsroomProvider',
];
foreach ($aInterfaces as $sInterface) {
self::$m_aExtensionClassNames[$sInterface] = array();

View File

@@ -90,26 +90,6 @@ abstract class Expression {
return $aRet;
}
/**
* recursive rendering
*
* @deprecated 3.0.0 use RenderExpression
*
* @param array $aArgs used as input by default, or used as output if bRetrofitParams set to True
* @param bool $bRetrofitParams
*
* @return array|string
* @throws \MissingQueryArgument
*/
public function Render(&$aArgs = null, $bRetrofitParams = false)
{
// cannot notify depreciation for now as this is still MASSIVELY used in iTop core !
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use RenderExpression');
return $this->RenderExpression(false, $aArgs, $bRetrofitParams);
}
/**
* recursive rendering
*

View File

@@ -71,16 +71,11 @@ class OQLActualClassTreeResolver
}
// Attributes can be stored in attributes list or for magic ones into filter codes list.
$sOriginClass = null;
if (MetaModel::IsValidAttCode($sClass, $sAttCode))
{
if (MetaModel::IsValidAttCode($sClass, $sAttCode)) {
$sOriginClass = MetaModel::GetAttributeOrigin($sClass, $sAttCode);
}
else if (MetaModel::IsValidFilterCode($sClass, $sAttCode))
{
$sOriginClass = MetaModel::GetFilterCodeOrigin($sClass, $sAttCode);
}
else
{
} else if ($sAttCode == 'id') {
$sOriginClass = $sClass;
} else {
continue;
}
if (!isset($aClassAndAncestorsNodes[$sOriginClass]) || is_null($aClassAndAncestorsNodes[$sOriginClass]))

View File

@@ -405,6 +405,101 @@ class ormDocument
}
}
/**
* Resize an image so that it fits in the given dimensions
* @param int $iMaxImageWidth Maximum width for the resized image
* @param int $iMaxImageHeight Maximum height for the resized image
* @param array|null $aFinalDimensions Image dimensions after resizing or null if unable to read the image
* @return ormDocument The resampled image
*
*/
public function ResizeImageToFit(int $iMaxWidth, int $iMaxHeight, array|null &$aFinalDimensions = null) : static
{
$aFinalDimensions = null;
// If gd extension is not loaded, we put a warning in the log and return the image as is
if (extension_loaded('gd') === false) {
IssueLog::Warning('Image could not be resized as the "gd" extension does not seem to be loaded. Its dimensions will remain the same instead of ' . $iMaxWidth . 'x' . $iMaxHeight);
return $this;
}
$oGdImage = false;
switch($this->GetMimeType()) {
case 'image/gif':
case 'image/jpeg':
case 'image/png':
$oGdImage = @imagecreatefromstring($this->GetData());
break;
default:
// Unsupported image type, return the image as-is
return $this;
}
if ($oGdImage === false) {
IssueLog::Warning('Image could not be resized as . It will remain as imagecreatefromstring could not read its data.Its dimensions will remain the same instead of ' . $iMaxWidth . 'x' . $iMaxHeight);
return $this;
}
$iWidth = imagesx($oGdImage);
$iHeight = imagesy($oGdImage);
if ( ($iMaxWidth === 0 || $iWidth <= $iMaxWidth) && ($iMaxHeight === 0 || $iHeight <= $iMaxHeight)) {
// No need to resize
$aFinalDimensions = [
'width' => $iWidth,
'height' =>$iHeight
];
return $this;
}
$fScale = 1.0;
if ($iMaxWidth > 0) {
$fScale = min($fScale, $iMaxWidth / $iWidth);
}
if ($iMaxHeight > 0) {
$fScale = min($fScale, $iMaxHeight / $iHeight);
}
$iNewWidth = (int)($iWidth * $fScale);
$iNewHeight = (int)($iHeight * $fScale);
$oNewGdImage = imagecreatetruecolor($iNewWidth, $iNewHeight);
$aFinalDimensions = [
'width' => $iNewWidth,
'height' =>$iNewHeight
];
// Preserve transparency
if($this->GetMimeType() == "image/gif" || $this->GetMimeType() == "image/png") {
imagecolortransparent($oNewGdImage, imagecolorallocatealpha($oNewGdImage, 0, 0, 0, 127));
imagealphablending($oNewGdImage, false);
imagesavealpha($oNewGdImage, true);
}
imagecopyresampled($oNewGdImage, $oGdImage, 0, 0, 0, 0, $iNewWidth, $iNewHeight, $iWidth, $iHeight);
ob_start();
switch ($this->GetMimeType()) {
case 'image/gif':
imagegif($oNewGdImage); // send image to output buffer
break;
case 'image/jpeg':
imagejpeg($oNewGdImage, null, 80); // null = send image to output buffer, 80 = good quality
break;
case 'image/png':
imagepng($oNewGdImage, null, 5); // null = send image to output buffer, 5 = medium compression
break;
}
$oResampledImage = new ormDocument(ob_get_contents(), $this->GetMimeType(), $this->GetFileName());
@ob_end_clean();
imagedestroy($oGdImage);
imagedestroy($oNewGdImage);
return $oResampledImage;
}
/**
* @return string
*/
@@ -412,4 +507,6 @@ class ormDocument
{
return md5($this->GetData() ?? '');
}
}

View File

@@ -145,18 +145,6 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
$this->bHasDelta = true;
}
/**
* @param DBObject $oObject
* @param string $sClassAlias
*
* @deprecated Since iTop 2.4, use {@link \ormLinkSet::AddItem()} instead.
*/
public function AddObject(DBObject $oObject, $sClassAlias = '')
{
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use \ormLinkSet::AddItem() instead');
$this->AddItem($oObject);
}
/**
* @param $iObjectId
*/

View File

@@ -1962,6 +1962,15 @@ class UserRights
return self::$m_aCacheUsers[$sAuthentication][$sLogin];
}
/**
* Reset the cache of users
* @return void
*/
public static function ResetCacheUsers()
{
self::$m_aCacheUsers = [ 'internal' => [], 'external' => [] ];
}
/**
* @param string$sClass
* @param array $aAllowedOrgs

View File

@@ -1,150 +0,0 @@
/*!
* Copyright (C) 2013-2024 Combodo SAS
*
* 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
*/
/********************************************************************************/
/* */
/* @deprecated 3.0.0 N°5311 The backoffice now uses files from css/backoffice/* */
/* */
/********************************************************************************/
// Beware the version number MUST be enclosed with quotes otherwise v2.3.0 becomes v2 0.3 .0
$version: "v2.7.7";
$approot-relative: "../../../../" !default; // relative to env-***/branding/themes/***/main.css
$version: "v2.7.8";
$approot-relative: "../../../../../" !default; // relative to env-***/branding/themes/***/main.css
// Base colors
$gray-base: #000 !default;
$gray-darker: lighten($gray-base, 13.5%) !default; // #222
$gray-dark: #444 !default;
$gray: #777 !default;
$gray-light: #808080 !default;
$gray-lighter: #ddd !default;
$gray-extra-light: #F1F1F1 !default;
$white: #FFFFFF !default;
$combodo-orange: #EA7D1E !default;
$combodo-dark-gray: #585653 !default;
$combodo-orange-dark: darken($combodo-orange, 13.8%) !default;
$combodo-orange-darker: darken($combodo-orange, 18%) !default;
$combodo-dark-gray-dark: darken($combodo-dark-gray, 13.5%) !default;
$combodo-dark-gray-darker: darken($combodo-dark-gray, 18%) !default;
// Brand colors
// - Bases
$brand-primary: $combodo-orange !default;
$brand-secondary: $combodo-dark-gray !default;
// - Shades
$brand-primary-lightest: lighten($brand-primary, 15%) !default;
$brand-primary-lighter: lighten($brand-primary, 10%) !default;
$brand-primary-light: lighten($brand-primary, 6%) !default;
$brand-primary-dark: darken($brand-primary, 6%) !default;
$brand-primary-darker: darken($brand-primary, 10%) !default;
$brand-primary-darkest: darken($brand-primary, 15%) !default;
$brand-secondary-lightest: lighten($brand-secondary, 15%) !default;
$brand-secondary-lighter: lighten($brand-secondary, 10%) !default;
$brand-secondary-light: lighten($brand-secondary, 6%) !default;
$brand-secondary-dark: darken($brand-secondary, 6%) !default;
$brand-secondary-darker: darken($brand-secondary, 10%) !default;
$brand-secondary-darkest: darken($brand-secondary, 15%) !default;
// Vars
$highlight-color: $brand-primary !default;
$grey-color: #555555 !default;
$complement-color: #1c94c4 !default;
$complement-light: #d6e8ef !default;
$frame-background-color: $gray-extra-light !default;
$text-color: #000 !default;
$box-radius: 0px !default;
$box-shadow-lightest: 0 1px 1px rgba(0, 0, 0, 0.15) !default;
$box-shadow-lighter: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24) !default;
$box-shadow-light: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22) !default;
$box-shadow-regular: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23) !default;
$box-shadow-strong: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23) !default;
$box-shadow-stronger: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22) !default;
$box-shadow-strongest: 0 19px 38px rgba(0,0,0,0.30), 0 15px 12px rgba(0,0,0,0.22) !default;
$body-background-color : $white !default;
$hyperlink-color: $complement-color !default;
$hyperlink-text-decoration: none !default;
////////////
// Search //
$search-form-container-color: $white !default;
$search-form-container-bg-color: $complement-color !default;
//
$search-criteria-box-color: #2D2D2D !default;
$search-criteria-box-picto-color: $brand-primary !default;
$search-criteria-box-bg-color: #EEEEEE !default;
$search-criteria-box-hover-color: $white !default;
$search-criteria-box-border-color: #CCCCCC !default;
$search-criteria-box-border: 1px solid $search-criteria-box-border-color !default;
$search-criteria-box-radius: 1px !default;
$search-criteria-more-less-details-color: #3F7294 !default;
//
$search-add-criteria-box-color: $search-criteria-box-color !default;
$search-add-criteria-box-bg-color: $white !default;
$search-add-criteria-box-hover-color: $gray-extra-light !default;
//
$search-button-box-color: $brand-primary !default;
$search-button-box-bg-color: $white !default;
$search-button-box-bg-hover-color: $gray-extra-light !default;
/////////////
// Buttons //
/////////////
// Toggle button
$toggle-button-bg-color: #CCCCCC !default;
$toggle-button-bg-checked-color: $brand-primary !default;
$toggle-button-slider-bg-color: #FFFFFF !default;
// Console elements
$summary-details-background: $grey-color !default;
$main-header-background: $frame-background-color !default;
$table-even-background: $frame-background-color !default;
$table-hover-background: #fdf5d0 !default;
$popup-menu-highlight-color: $highlight-color !default;
$popup-menu-text-color: #000 !default;
$popup-menu-background-color: #fff !default;
$popup-menu-text-higlight-color: #fff !default;
$breadcrumb-color: $grey-color !default;
$breadcrumb-highlight-color: $highlight-color !default;
// jQuery UI widgets vars
$primary-text-color: #333333 !default;
$secondary-text-color: $grey-color !default;
$error-text-color: $white !default;
$highlight-text-color: #363636 !default;
$button-content-background-color: $gray-extra-light !default;
$button-header-background-color: $gray-extra-light !default;
$main-menu-background-color: $gray-extra-light !default;
$hover-background-color: #fde17c !default;
$border-highlight-color: $brand-primary-dark !default;
$highlight-item-color: $white !default;
$content-color: #eeeeee !default;
$default-font-family: "Raleway";
$icons-filter: hue-rotate(0deg) !default;
%font-awesome-prerequisites {
font-family: 'Font Awesome 5 Free';
font-weight: 600;
}

File diff suppressed because it is too large Load Diff

View File

View File

@@ -1,7 +1,7 @@
{# @copyright Copyright (C) 2010-2024 Combodo SAS #}
{# @license http://opensource.org/licenses/AGPL-3.0 #}
<div class="sso-button" title="{{ aData.sTooltip }}" onclick="$('#login_mode').val('{{ aData.sLoginMode }}'); $('#login_form').submit(); return false;">
<div class="sso-button" title="{{ aData.sTooltip }}" onclick="$('#login_mode').val('{{ aData.sLoginMode }}'); $('#login_form').trigger('submit'); return false;">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 336.82 167.83" class="logo sso-image" style="max-height: 20px;">
<defs>
<style>

View File

@@ -66,8 +66,7 @@
$sServer = $this->Get('ldap_server');
if (empty($sServer))
{
$sLDAPHost = MetaModel::GetModuleSetting('authent-ldap', 'host', 'localhost');
$iLDAPPort = MetaModel::GetModuleSetting('authent-ldap', 'port', 389);
$sURI = MetaModel::GetModuleSetting('authent-ldap', 'uri', 'ldap://localhost');
$sDefaultLDAPUser = MetaModel::GetModuleSetting('authent-ldap', 'default_user', '');
$sDefaultLDAPPwd = MetaModel::GetModuleSetting('authent-ldap', 'default_pwd', '');
@@ -88,8 +87,7 @@
return false;
}
$aServerParams = $aServers[$sServer];
$sLDAPHost = isset($aServerParams['host']) ? $aServerParams['host'] : 'localhost';
$iLDAPPort = isset($aServerParams['port']) ? $aServerParams['port'] : 389;
$sURI = $aServerParams['uri'] ?? 'ldap://localhost';
$sDefaultLDAPUser = isset($aServerParams['default_user']) ? $aServerParams['default_user'] : '';
$sDefaultLDAPPwd = isset($aServerParams['default_pwd']) ? $aServerParams['default_pwd'] : '';
$bLDAPStartTLS = isset($aServerParams['start_tls']) ? $aServerParams['start_tls'] : false;
@@ -99,10 +97,10 @@
$bDebug = isset($aServerParams['debug']) ? $aServerParams['debug'] : false;
}
$hDS = @ldap_connect($sLDAPHost, $iLDAPPort);
$hDS = @ldap_connect($sURI);
if ($hDS === false)
{
$this->LogIssue($bDebug, "ldap_authentication: can not connect to the LDAP server '$sLDAPHost' (port: $iLDAPPort). Check the configuration file config-itop.php.");
$this->LogIssue($bDebug, "ldap_authentication: can not connect to the LDAP server '$sURI'. Check the configuration file config-itop.php.");
return false;
}
if (array_key_exists(LDAP_OPT_DEBUG_LEVEL, $aOptions))
@@ -184,7 +182,7 @@
else
{
// Trace: invalid default user for LDAP initial binding
$this->LogIssue($bDebug, "ldap_authentication: cannot bind to the LDAP server '$sLDAPHost' (port: $iLDAPPort), user='$sDefaultLDAPUser', pwd='****'. Error: '".ldap_error($hDS)."'. Check the configuration file config-itop.php.");
$this->LogIssue($bDebug, "ldap_authentication: cannot bind to the LDAP server '$sURI', user='$sDefaultLDAPUser', pwd='****'. Error: '".ldap_error($hDS)."'. Check the configuration file config-itop.php.");
return false;
}
}]]></code>

View File

@@ -43,8 +43,7 @@ SetupWebPage::AddModule(
// Default settings
//
'settings' => array(
'host' => 'localhost', // host or IP address of your LDAP server
'port' => 389, // LDAP port (std: 389)
'uri' => 'ldap://localhost', // URI with host or IP address of your LDAP server
'default_user' => '', // User and password used for initial "Anonymous" bind to LDAP
'default_pwd' => '', // Leave both blank, if anonymous (read-only) bind is allowed
'base_dn' => 'dc=yourcompany,dc=com', // Base DN for User queries, adjust it to your LDAP schema
@@ -75,6 +74,27 @@ class AuthentLDAPInstaller extends ModuleInstallerAPI
$sSQL = "insert into $sUserLDAPTable (id) select U.id from $sUserTable as U left join $sUserLDAPTable as L on U.id = L.id where U.finalclass='UserLDAP' and isnull(L.id);";
CMDBSource::Query($sSQL);
}
public static function BeforeWritingConfig(Config $oConfiguration)
{
$sURI = $oConfiguration->GetModuleSetting('authent-ldap', 'uri');
if (empty($sURI)) {
$sLDAPHost = MetaModel::GetModuleSetting('authent-ldap', 'host', 'localhost');
$iLDAPPort = MetaModel::GetModuleSetting('authent-ldap', 'port', 389);
$sURI = preg_match('#^ldaps?://#i', $sLDAPHost) ? $sLDAPHost : 'ldap://'.$sLDAPHost.':'.$iLDAPPort;
$oConfiguration->SetModuleSetting('authent-ldap', 'uri', $sURI);
}
$aServers = $oConfiguration->GetModuleSetting('authent-ldap', 'servers', []);
foreach ($aServers as &$aServer) {
if (!array_key_exists($aServer, 'uri')) {
$sLDAPHost = $aServerParams['host'] ?? 'localhost';
$iLDAPPort = $aServerParams['port'] ?? 389;
$aServer['uri'] = preg_match('#^ldaps?://#i', $sLDAPHost) ? $sLDAPHost : 'ldap://'.$sLDAPHost.':'.$iLDAPPort;
}
}
$oConfiguration->SetModuleSetting('authent-ldap', 'servers', $aServers);
}
}
} // if (function_exists('ldap_connect'))

View File

@@ -204,7 +204,7 @@ SQL;
}
SetupLog::Info("Initializing attachment/item_org_id - $iUpdated records have been adjusted");
if (MetaModel::GetAttributeDef('Attachment', 'contact_id') instanceof AttributeExternalKey) {
if (MetaModel::GetAttributeDef('Attachment', 'contact_id') instanceof AttributeExternalKey && version_compare($sPreviousVersion, '3.2.0', '<')) {
SetupLog::Info("Upgrading itop-attachment from '$sPreviousVersion' to '$sCurrentVersion'. Starting with 3.2.0, contact_id will be added into the DB...");
$sUserTableName = MetaModel::DBGetTable('User');
$sUserFieldContactId = MetaModel::GetAttributeDef('User', 'contactid')->Get('sql');

View File

@@ -4591,7 +4591,6 @@
<menu id="Change:Shortcuts" xsi:type="TemplateMenuNode" _delta="define">
<rank>3</rank>
<parent>ChangeManagement</parent>
<template_file/>
</menu>
<menu id="MyChanges" xsi:type="OQLMenuNode" _delta="define">
<rank>1</rank>
@@ -4641,7 +4640,7 @@
AND (C.id != :this->id)
]]></oql>
<dict>Tickets:Related:OpenChanges</dict>
<icon>itop-change-mgmt-itil/images/change-ongoing.png</icon>
<icon>itop-change-mgmt-itil/images/change-ongoing.svg</icon>
</item>
<item id="recent_changes" _delta="define">
<oql><![CDATA[
@@ -4656,7 +4655,7 @@
AND (C.end_date < NOW() AND C.end_date > DATE_SUB(NOW(), INTERVAL 3 DAY ))
]]></oql>
<dict>Tickets:Related:RecentChanges</dict>
<icon>itop-change-mgmt-itil/images/change-done.png</icon>
<icon>itop-change-mgmt-itil/images/change-done.svg</icon>
</item>
</items>
</down>
@@ -4678,7 +4677,7 @@
AND (C.id != :this->id)
]]></oql>
<dict>Tickets:Related:OpenChanges</dict>
<icon>itop-change-mgmt-itil/images/change-ongoing.png</icon>
<icon>itop-change-mgmt-itil/images/change-ongoing.svg</icon>
</item>
<item id="recent_changes" _delta="define">
<oql><![CDATA[
@@ -4693,7 +4692,7 @@
AND (C.end_date < NOW() AND C.end_date > DATE_SUB(NOW(), INTERVAL 3 DAY ))
]]></oql>
<dict>Tickets:Related:RecentChanges</dict>
<icon>itop-change-mgmt-itil/images/change-done.png</icon>
<icon>itop-change-mgmt-itil/images/change-done.svg</icon>
</item>
</items>
</down>
@@ -4715,7 +4714,7 @@
AND (C.id != :this->id)
]]></oql>
<dict>Tickets:Related:OpenChanges</dict>
<icon>itop-change-mgmt-itil/images/change-ongoing.png</icon>
<icon>itop-change-mgmt-itil/images/change-ongoing.svg</icon>
</item>
<item id="recent_changes" _delta="define">
<oql><![CDATA[
@@ -4730,7 +4729,7 @@
AND (C.end_date < NOW() AND C.end_date > DATE_SUB(NOW(), INTERVAL 3 DAY ))
]]></oql>
<dict>Tickets:Related:RecentChanges</dict>
<icon>itop-change-mgmt-itil/images/change-done.png</icon>
<icon>itop-change-mgmt-itil/images/change-done.svg</icon>
</item>
</items>
</down>
@@ -4755,7 +4754,7 @@
AND (L.impact_code != 'not_impacted')
]]></oql>
<dict>Tickets:Related:OpenChanges</dict>
<icon>itop-change-mgmt-itil/images/change-ongoing.png</icon>
<icon>itop-change-mgmt-itil/images/change-ongoing.svg</icon>
</item>
<item id="recent_changes" _delta="define">
<oql><![CDATA[
@@ -4769,7 +4768,7 @@
AND (C.end_date < NOW() AND C.end_date > DATE_SUB(NOW(), INTERVAL 3 DAY ))
]]></oql>
<dict>Tickets:Related:RecentChanges</dict>
<icon>itop-change-mgmt-itil/images/change-done.png</icon>
<icon>itop-change-mgmt-itil/images/change-done.svg</icon>
</item>
</items>
</down>
@@ -4786,7 +4785,7 @@
AND (L.impact_code != 'not_impacted')
]]></oql>
<dict>Tickets:Related:OpenChanges</dict>
<icon>itop-change-mgmt-itil/images/change-ongoing.png</icon>
<icon>itop-change-mgmt-itil/images/change-ongoing.svg</icon>
</item>
<item id="recent_changes" _delta="define">
<oql><![CDATA[
@@ -4800,7 +4799,7 @@
AND (C.end_date < NOW() AND C.end_date > DATE_SUB(NOW(), INTERVAL 3 DAY ))
]]></oql>
<dict>Tickets:Related:RecentChanges</dict>
<icon>itop-change-mgmt-itil/images/change-done.png</icon>
<icon>itop-change-mgmt-itil/images/change-done.svg</icon>
</item>
</items>
</up>

View File

@@ -833,7 +833,6 @@
<menu id="Change:Shortcuts" xsi:type="TemplateMenuNode" _delta="define">
<rank>3</rank>
<parent>ChangeManagement</parent>
<template_file/>
</menu>
<menu id="MyChanges" xsi:type="OQLMenuNode" _delta="define">
<rank>1</rank>
@@ -876,7 +875,7 @@
AND (C.id != :this->id)
]]></oql>
<dict>Tickets:Related:OpenChanges</dict>
<icon>itop-change-mgmt/images/change-ongoing.png</icon>
<icon>itop-change-mgmt/images/change-ongoing.svg</icon>
<default>yes</default>
</item>
<item id="recent_changes" _delta="define">
@@ -892,7 +891,7 @@
AND (C.end_date < NOW() AND C.end_date > DATE_SUB(NOW(), INTERVAL 3 DAY ))
]]></oql>
<dict>Tickets:Related:RecentChanges</dict>
<icon>itop-change-mgmt/images/change-done.png</icon>
<icon>itop-change-mgmt/images/change-done.svg</icon>
<default>no</default>
</item>
</items>
@@ -915,7 +914,7 @@
AND (C.id != :this->id)
]]></oql>
<dict>Tickets:Related:OpenChanges</dict>
<icon>itop-change-mgmt/images/change-ongoing.png</icon>
<icon>itop-change-mgmt/images/change-ongoing.svg</icon>
<default>yes</default>
</item>
<item id="recent_changes" _delta="define">
@@ -931,7 +930,7 @@
AND (C.end_date < NOW() AND C.end_date > DATE_SUB(NOW(), INTERVAL 3 DAY ))
]]></oql>
<dict>Tickets:Related:RecentChanges</dict>
<icon>itop-change-mgmt/images/change-done.png</icon>
<icon>itop-change-mgmt/images/change-done.svg</icon>
<default>no</default>
</item>
</items>
@@ -954,7 +953,7 @@
AND (C.id != :this->id)
]]></oql>
<dict>Tickets:Related:OpenChanges</dict>
<icon>itop-change-mgmt/images/change-ongoing.png</icon>
<icon>itop-change-mgmt/images/change-ongoing.svg</icon>
<default>yes</default>
</item>
<item id="recent_changes" _delta="define">
@@ -970,7 +969,7 @@
AND (C.end_date < NOW() AND C.end_date > DATE_SUB(NOW(), INTERVAL 3 DAY ))
]]></oql>
<dict>Tickets:Related:RecentChanges</dict>
<icon>itop-change-mgmt/images/change-done.png</icon>
<icon>itop-change-mgmt/images/change-done.svg</icon>
<default>no</default>
</item>
</items>
@@ -996,7 +995,7 @@
AND (L.impact_code != 'not_impacted')
]]></oql>
<dict>Tickets:Related:OpenChanges</dict>
<icon>itop-change-mgmt/images/change-ongoing.png</icon>
<icon>itop-change-mgmt/images/change-ongoing.svg</icon>
<default>yes</default>
</item>
<item id="recent_changes" _delta="define">
@@ -1011,7 +1010,7 @@
AND (C.end_date < NOW() AND C.end_date > DATE_SUB(NOW(), INTERVAL 3 DAY ))
]]></oql>
<dict>Tickets:Related:RecentChanges</dict>
<icon>itop-change-mgmt/images/change-done.png</icon>
<icon>itop-change-mgmt/images/change-done.svg</icon>
<default>no</default>
</item>
</items>
@@ -1029,7 +1028,7 @@
AND (L.impact_code != 'not_impacted')
]]></oql>
<dict>Tickets:Related:OpenChanges</dict>
<icon>itop-change-mgmt/images/change-ongoing.png</icon>
<icon>itop-change-mgmt/images/change-ongoing.svg</icon>
<default>yes</default>
</item>
<item id="recent_changes" _delta="define">
@@ -1044,7 +1043,7 @@
AND (C.end_date < NOW() AND C.end_date > DATE_SUB(NOW(), INTERVAL 3 DAY ))
]]></oql>
<dict>Tickets:Related:RecentChanges</dict>
<icon>itop-change-mgmt/images/change-done.png</icon>
<icon>itop-change-mgmt/images/change-done.svg</icon>
<default>no</default>
</item>
</items>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

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