Compare commits

..

108 Commits

Author SHA1 Message Date
jf-cbd
e1bd815094 WIP Tom Select options 2025-11-25 17:46:18 +01:00
Eric Espie
a19472cfd1 🎨 N°8772 - CS Fixer 2025-11-20 10:55:10 +01:00
Eric Espie
7b29d562c8 N°8772 - wip 2025-11-20 10:31:18 +01:00
Eric Espie
3e471edefd 🎨 N°8772 - Moved DI under Service 2025-11-19 15:27:18 +01:00
Eric Espie
bd44f971e4 🎨 N°8772 - CS Fixer 2025-11-19 14:49:20 +01:00
Eric Espie
65bd6d9fd0 Add ModelReflection Service as dependency injection + tests 2025-11-19 14:42:32 +01:00
jf-cbd
6678689b77 Fix wrong path for turbo 2025-11-19 11:04:36 +01:00
jf-cbd
8f05c2bcba Fix CI error (cf. 2651) 2025-11-19 10:52:33 +01:00
jf-cbd
4169e10eec Fix wrong path for turbo 2025-11-19 10:49:01 +01:00
Eric Espie
e95ce21188 Add sAPPROOTURL to the data of the twig 2025-11-19 10:06:16 +01:00
Eric Espie
24d78df21d 🎨 N°8772 - CS Fixer 2025-11-19 09:21:34 +01:00
Eric Espie
546912ad77 N°8772 - 2025-11-18 18:08:50 +01:00
jf-cbd
f93926528f Add Tom-Select lib 2025-11-18 17:18:46 +01:00
Eric Espie
0cb7c7359f N°8772 - AbstractFormIO tests 2025-11-18 16:45:11 +01:00
Eric Espie
7c0f454936 Runtime Model Reflection & namespace 2025-11-18 15:36:22 +01:00
Eric Espie
11973d61ec 🎨 CS Fixer 2025-11-18 14:52:10 +01:00
Eric Espie
e08835c1a2 N°8772 - AbstractFormIO tests 2025-11-18 14:00:41 +01:00
Eric Espie
8ecb36b1fe N°8772 - FormBinding tests 2025-11-18 11:24:05 +01:00
Eric Espie
6a4ed98299 Merge remote-tracking branch 'origin/develop' into feature/8772_form_dependencies_manager 2025-11-18 09:54:29 +01:00
Eric Espie
2a8ed931e9 N°8772 - AbstractFormIO and FormBinding tests 2025-11-18 09:25:37 +01:00
Eric Espie
07a61d5f0d N°8772 - AbstractFormIO and FormBinding tests 2025-11-17 17:26:47 +01:00
Eric Espie
047c820466 N°8772 - AbstractFormIO and FormBinding tests 2025-11-17 17:26:12 +01:00
Benjamin Dalsass
753d0acce4 N°8772 - dynamic form 2025-11-17 14:51:11 +01:00
Eric Espie
51ebbc4274 N°8772 - Refactor 2025-11-14 16:42:42 +01:00
Eric Espie
3085023267 N°8772 - Error message 2025-11-14 16:24:18 +01:00
Eric Espie
e02fc9cb44 Merge dicos... 2025-11-14 16:14:34 +01:00
Eric Espie
ea95ae60a6 Merge remote-tracking branch 'origin/develop' into feature/8772_form_dependencies_manager 2025-11-14 16:08:37 +01:00
Eric Espie
b9d905ad1b N°8772 - refactor 2025-11-14 15:57:17 +01:00
Eric Espie
5b114285cc N°8772 - Error message 2025-11-14 15:39:16 +01:00
Eric Espie
b34566076e N°8772 - Form Expressions using iTop Expressions 2025-11-14 15:33:47 +01:00
Benjamin Dalsass
750b2b9cfa Merge remote-tracking branch 'origin/feature/8772_form_dependencies_manager' into feature/8772_form_dependencies_manager 2025-11-14 14:32:56 +01:00
Benjamin Dalsass
bdde63a39c N°8772 - dynamic form 2025-11-14 14:30:50 +01:00
Eric Espie
891df6ab1c N°8772 - Expressions inputs are now :input instead of [[input]] (and quotes are added automatically) 2025-11-14 14:05:22 +01:00
Benjamin Dalsass
dc1ce2dc64 Merge remote-tracking branch 'origin/feature/8772_form_dependencies_manager' into feature/8772_form_dependencies_manager
# Conflicts:
#	lib/composer/autoload_classmap.php
#	lib/composer/autoload_static.php
#	sources/Forms/Block/Base/ChoiceFormBlock.php
#	sources/Forms/IO/Format/StringIOFormat.php
2025-11-14 10:53:42 +01:00
Benjamin Dalsass
e5058fb8f7 N°8772 - dynamic form 2025-11-14 10:50:57 +01:00
Eric Espie
f68082da96 N°8772 - Dashlet group by 2025-11-13 17:10:39 +01:00
jf-cbd
7733f13d14 Add Tom-Select lib 2025-11-13 16:43:49 +01:00
Eric Espie
cef8fbc859 N°8772 - Dashlet group by 2025-11-13 16:42:04 +01:00
Eric Espie
36d49d3550 N°8772 - wip 2025-11-13 15:02:09 +01:00
Eric Espie
c2ec3a9f02 N°8772 - remove unused class 2025-11-13 09:36:36 +01:00
Benjamin Dalsass
4d159ea3f1 Merge remote-tracking branch 'origin/feature/8772_form_dependencies_manager' into feature/8772_form_dependencies_manager 2025-11-12 17:11:29 +01:00
Benjamin Dalsass
5cacfcb754 N°8772 - dynamic form 2025-11-12 17:09:40 +01:00
Eric Espie
101b1b217e N°8772 - remove debug if not wanted like in config edition 2025-11-12 14:23:19 +01:00
Eric Espie
5af8adf7ce N°8772 - fix debug display 2025-11-12 13:07:37 +01:00
Benjamin Dalsass
3d2485a004 N°8772 - dynamic form 2025-11-12 09:33:29 +01:00
Benjamin Dalsass
cbb0e2ef7e N°8772 - dynamic form 2025-11-12 08:33:28 +01:00
Benjamin Dalsass
7095e5e959 Merge remote-tracking branch 'origin/feature/8772_form_dependencies_manager' into feature/8772_form_dependencies_manager 2025-11-12 08:24:04 +01:00
Benjamin Dalsass
7fd27913f4 N°8772 - dynamic form 2025-11-12 08:20:17 +01:00
Eric Espie
cfdf4121d3 N°8772 - Dynamic debug and error 2025-11-07 11:24:31 +01:00
Benjamin Dalsass
a448f668bc N°8772 - dynamic form 2025-11-07 11:00:15 +01:00
Eric Espie
b6ec29c6ec N°8772 - ExpressionFormBlock WIP 2025-11-06 17:12:25 +01:00
Eric Espie
03c37f2021 N°8772 - Fix IO tests 2025-11-05 16:54:18 +01:00
Benjamin Dalsass
5b7a1ee44f N°8772 - dynamic form 2025-11-05 15:52:23 +01:00
Eric Espie
9ea546ebf6 N°8772 - Turbo + Collections WIP 2025-11-05 11:19:03 +01:00
Eric Espie
8fdad7997e N°8772 - Turbo Ok 2025-11-05 10:15:58 +01:00
Eric Espie
b3ed7f4f5b N°8772 - UIBlocks 2025-11-04 17:36:44 +01:00
jf-cbd
4f4ba7167d WIP 2025-11-04 17:02:56 +01:00
Eric Espie
a092b65be7 N°8772 - WIP dependencies - Does not work yet 2025-11-04 15:22:14 +01:00
Eric Espie
5a1f6ffde9 N°8772 - WIP dependencies - Does not work yet 2025-11-04 09:05:29 +01:00
Benjamin Dalsass
0909ddfb3a N°8772 - dynamic form 2025-11-03 14:01:32 +01:00
Benjamin Dalsass
20da9664c2 N°8772 - dynamic form 2025-11-03 13:50:07 +01:00
Benjamin Dalsass
68d2038488 N°8772 - dynamic form 2025-11-03 13:47:07 +01:00
Eric Espie
4c9373d034 N°8772 - Fix error 2025-11-03 10:07:49 +01:00
Eric Espie
0d7ccd7d82 N°8772 - Moved debug forms 2025-10-31 16:48:06 +01:00
jf-cbd
077c48870f Merge remote-tracking branch 'origin/feature/8772_form_dependencies_manager' into feature/8772_form_dependencies_manager 2025-10-31 16:44:03 +01:00
jf-cbd
5df44b8a18 Remove .compilation-symlinks 2025-10-31 16:42:30 +01:00
Eric Espie
d4415d6c3a N°8772 - some tests 2025-10-31 14:35:44 +01:00
Eric Espie
0196765eb6 N°8772 - automatic dependency in controller WIP 2025-10-31 08:58:50 +01:00
Eric Espie
45e4d9239c N°8772 - automatic dependency in controller WIP 2025-10-31 08:55:45 +01:00
Eric Espie
0df54413b3 N°8772 - cleanup code 2025-10-30 14:24:09 +01:00
Eric Espie
601cde0e2d N°8772 - Traditional parameters declaration 2025-10-30 14:16:36 +01:00
Eric Espie
4c10cfee60 N°8772 - Errors & turbo 2025-10-30 11:53:29 +01:00
Eric Espie
7a6f36b395 N°8772 - Debug & turbo 2025-10-30 10:00:12 +01:00
Eric Espie
06dbdcb5cd N°8772 - Turbo WIP 2025-10-29 16:52:19 +01:00
Benjamin Dalsass
c00bcbcd81 Merge remote-tracking branch 'origin/feature/8772_form_dependencies_manager' into feature/8772_form_dependencies_manager 2025-10-29 14:00:08 +01:00
Eric Espie
1394edc111 N°8772 - Turbo WIP
N°8772 - Twig factorization
2025-10-29 13:59:35 +01:00
Benjamin Dalsass
8582e89b8c Merge remote-tracking branch 'origin/feature/8772_form_dependencies_manager' into feature/8772_form_dependencies_manager
# Conflicts:
#	sources/Forms/Block/AbstractFormBlock.php
#	sources/Forms/Block/DataModel/AttributeValueChoiceFormBlock.php
#	templates/application/forms/itop_console_layout.html.twig
2025-10-29 13:31:02 +01:00
Benjamin Dalsass
6952bfa978 N°8771 - Add Symfony form component to iTop core
- IO debug
2025-10-29 13:14:15 +01:00
Eric Espie
98048219e7 N°8772 - Twig factorization 2025-10-29 09:31:40 +01:00
Eric Espie
8134d9a592 N°8772 - Form turbo stream WIP 2025-10-28 16:41:59 +01:00
Eric Espie
2a3de68652 N°8772 - Form turbo stream WIP 2025-10-28 15:34:19 +01:00
Benjamin Dalsass
5d335b39d2 N°8771 - Add Symfony form component to iTop core
- IO debug
2025-10-28 15:22:29 +01:00
Eric Espie
c2fcf4144b N°8772 - Sub-forms WIP 2025-10-24 16:56:45 +02:00
Eric Espie
675db85131 N°8772 - log for exception 2025-10-24 15:44:41 +02:00
Benjamin Dalsass
212309e938 N°8771 - Add Symfony form component to iTop core
- IO debug
2025-10-24 15:42:33 +02:00
Benjamin Dalsass
a4fbe90579 N°8771 - Add Symfony form component to iTop core
- IO debug
2025-10-24 15:36:51 +02:00
Benjamin Dalsass
eb3c5e4eee N°8771 - Add Symfony form component to iTop core
- IO debug
2025-10-24 14:46:59 +02:00
Benjamin Dalsass
33c03f9493 N°8771 - Add Symfony form component to iTop core
- IO debug
2025-10-24 09:29:53 +02:00
Benjamin Dalsass
243a525e15 N°8771 - Add Symfony form component to iTop core
- IO debug
2025-10-24 08:56:04 +02:00
Benjamin Dalsass
a1025ac837 N°8771 - Add Symfony form component to iTop core
- IO
2025-10-24 08:35:10 +02:00
Benjamin Dalsass
7708f8e00e N°8771 - Add Symfony form component to iTop core
- IO
2025-10-24 07:54:51 +02:00
Benjamin Dalsass
a51272f107 N°8771 - Add Symfony form component to iTop core
- IO
2025-10-24 07:15:35 +02:00
Benjamin Dalsass
5582afe5ae N°8771 - Add Symfony form component to iTop core
- add licence info
2025-10-24 06:37:22 +02:00
Eric Espie
21b786e0fa N°8772 - Form dependencies manager implementation - WIP 2025-10-23 16:57:35 +02:00
Eric Espie
fd449d195d N°8772 - Form dependencies manager implementation - WIP 2025-10-23 15:11:14 +02:00
Eric Espie
98c0b11db7 N°8772 - Form dependencies manager implementation - WIP 2025-10-23 13:51:24 +02:00
Benjamin Dalsass
8c3543363e N°8771 - Add Symfony form component to iTop core
- WIP
2025-10-23 13:29:04 +02:00
Benjamin Dalsass
5dea3f5299 N°8771 - Add Symfony form component to iTop core
- WIP
2025-10-23 12:11:02 +02:00
Benjamin Dalsass
239814a38c N°8771 - Add Symfony form component to iTop core
- restore branch
2025-10-23 11:28:01 +02:00
Benjamin Dalsass
c4e2cc6c1c Merge remote-tracking branch 'origin/develop' into feature/8772_form_dependencies_manager
# Conflicts:
#	sources/Application/TwigBase/Controller/Controller.php
2025-10-23 11:14:24 +02:00
Benjamin Dalsass
ee745f8be9 N°8772 - Form dependencies manager implementation
- turbo implementation
2025-10-23 11:11:51 +02:00
Benjamin Dalsass
1a4a64cec1 N°8772 - Form dependencies manager implementation 2025-10-23 11:11:39 +02:00
Benjamin Dalsass
834d4d461b N°8771 - Add Symfony form component to iTop core
- restore $aAdditionalPaths missing parameter
2025-10-23 11:10:59 +02:00
Eric Espie
5df73f5820 N°8781 - Improve twig base controller render error report 2025-10-23 11:10:54 +02:00
odain
c83d998924 N°4058 - fix PHP Deprecated base64_decodestrlen : Passing nul 2025-10-23 11:10:17 +02:00
Stephen Abello
ccdfbbe0bf N°8701 - Fix class icon alt text displaying in portal tile when there's no icon defined 2025-10-23 11:10:17 +02:00
Benjamin Dalsass
0dae7346d1 N°8772 - Form dependencies manager implementation
- turbo implementation
2025-10-20 15:16:44 +02:00
Benjamin Dalsass
cdfded766f N°8772 - Form dependencies manager implementation 2025-10-17 09:03:45 +02:00
1486 changed files with 15552 additions and 109553 deletions

View File

@@ -1,9 +0,0 @@
# Developers
## PHP Code Styles
We use `PHP CS Fixer` to ensure code formating consistency across PHP codebase.
You can find the configuration and instructions to run it [here](../tests/php-code-style/README.md).
## PHP Static Analysis
We use `PHPStan` to ensure code quality and to detect potential bugs in our PHP codebase.
You can find the configuration and instructions to run it [here](../tests/php-static-analysis/README.md).

View File

@@ -26,23 +26,13 @@ jobs:
fi
- name: Add internal tag if member of the organization
- name: Add internal tag if member
if: env.is_member == 'true'
run: |
curl -X POST -H "Authorization: token ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/Combodo/iTop/issues/${{ github.event.pull_request.number }}/labels \
-d '{"labels":["internal"]}'
- name: Set PR author as assignee if member of the organization
if: env.is_member == 'true'
run: |
curl -L \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}" \
https://api.github.com/repos/Combodo/iTop/issues/${{ github.event.pull_request.number }}/assignees \
-d '{"assignees":["${{ github.event.pull_request.user.login }}"]}'
env:
is_member: ${{ env.is_member }}
@@ -50,4 +40,4 @@ jobs:
uses: actions/add-to-project@v1.0.2
with:
project-url: ${{ env.project_url }}
github-token: ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}
github-token: ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}

3
.gitignore vendored
View File

@@ -58,9 +58,6 @@ tests/*/vendor/*
/tests/php-unit-tests/phpunit.xml
/tests/php-unit-tests/postbuild_integration.xml
# PHP CS Fixer: Cache file
/.php-cs-fixer.cache
# Jetbrains
/.idea/**

View File

@@ -1,16 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2025 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace PHPSTORM_META
{
override(\MetaModel::NewObject(0), map([
'' => '@',
]));
override(\MetaModel::GetObject(0), map([
'' => '@',
]));
}

View File

@@ -73,9 +73,6 @@ iTop development is sponsored, led, and supported by [Combodo][0].
[0]: https://www.combodo.com
## Developers
You can find information and instructions about our quality tools and how to run them [here](.doc/developers.md).
## Contributors

View File

@@ -16,5 +16,5 @@ require_once(APPROOT.'/application/audit.category.class.inc.php');
require_once(APPROOT.'/application/audit.domain.class.inc.php');
require_once(APPROOT.'/application/audit.rule.class.inc.php');
require_once(APPROOT.'/application/query.class.inc.php');
require_once(APPROOT.'/setup/moduleinstallation/moduleinstallation.class.inc.php');
require_once(APPROOT.'/setup/moduleinstallation.class.inc.php');
require_once(APPROOT.'/application/utils.inc.php');

View File

@@ -819,7 +819,6 @@ HTML
foreach ($aNotificationClasses as $sNotifClass) {
$aNotifSearches[$sNotifClass] = DBObjectSearch::FromOQL("SELECT $sNotifClass AS Ev WHERE Ev.object_id = :id AND Ev.object_class = :class");
$aNotifSearches[$sNotifClass]->SetInternalParams($aParams);
$aNotifSearches[$sNotifClass]->AllowAllData();
$oNotifSet = new DBObjectSet($aNotifSearches[$sNotifClass], []);
$iNotifsCount += $oNotifSet->Count();
}
@@ -833,7 +832,6 @@ HTML
'menu' => false,
'panel_title' => MetaModel::GetName($sNotifClass),
'panel_icon' => MetaModel::GetClassIcon($sNotifClass, false),
'display_unauthorized_objects' => true,
]);
}
}
@@ -5634,7 +5632,7 @@ JS
* @return void
* @since 3.1.0
*/
final public function AddAttributeFlags(string $sAttCode, int $iFlags, string $sTargetState = '', ?string $sReason = null): void
final public function AddAttributeFlags(string $sAttCode, int $iFlags, string $sTargetState = '', string $sReason = null): void
{
if (!isset($this->aAttributesFlags[$sTargetState])) {
$this->aAttributesFlags[$sTargetState] = [];
@@ -5657,7 +5655,7 @@ JS
* @return void
* @since 3.1.0
*/
final public function ForceAttributeFlags(string $sAttCode, int $iFlags, string $sTargetState = '', ?string $sReason = null): void
final public function ForceAttributeFlags(string $sAttCode, int $iFlags, string $sTargetState = '', string $sReason = null): void
{
if (!isset($this->aAttributesFlags[$sTargetState])) {
$this->aAttributesFlags[$sTargetState] = [];
@@ -5698,7 +5696,7 @@ JS
* @return void
* @since 3.1.0
*/
final public function AddInitialAttributeFlags(string $sAttCode, int $iFlags, ?string $sReason = null)
final public function AddInitialAttributeFlags(string $sAttCode, int $iFlags, string $sReason = null)
{
if (!isset($this->aInitialAttributesFlags)) {
$this->aInitialAttributesFlags = [];
@@ -5720,7 +5718,7 @@ JS
* @return void
* @since 3.1.0
*/
final public function ForceInitialAttributeFlags(string $sAttCode, int $iFlags, ?string $sReason = null)
final public function ForceInitialAttributeFlags(string $sAttCode, int $iFlags, string $sReason = null)
{
if (!isset($this->aInitialAttributesFlags)) {
$this->aInitialAttributesFlags = [];

View File

@@ -497,7 +497,7 @@ EOF
* @param array $aExtraParams
* @param bool $bCanEdit
*
* @return null|\Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout
* @return \Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = [], $bCanEdit = true)
{
@@ -1029,7 +1029,7 @@ EOF
var dashboard = $('.ibo-dashboard#$sDivId')
dashboard.block();
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
{ operation: 'toggle_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: $sReloadURL },
{ operation: 'toggle_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL' },
function(data) {
dashboard.html(data);
dashboard.unblock();

View File

@@ -1,12 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://www.combodo.com/itop-schema/3.3"
version="3.3">
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.3">
<classes>
<class id="AbstractResource" _delta="define">
<parent>cmdbAbstractObject</parent>
<properties>
<comment>/* Resource access control abstraction. Can be herited by abstract resource access control classes. Generally controlled using UR_ACTION_MODIFY access right. */</comment>
<comment>/* Resource access control abstraction. Can be herited by abstract resource access control classes. Generaly controlled using UR_ACTION_MODIFY access right. */</comment>
<abstract>true</abstract>
</properties>
<presentation/>
@@ -554,7 +552,7 @@ Call $this->AddInitialAttributeFlags($sAttCode, $iFlags) for all the initial att
<description><![CDATA[Inform the listeners about the connection states]]></description>
<event_data>
<event_datum id="code">
<description>The login step result code (LoginWebPage::EXIT_CODE_...)</description>
<description>The login step result code (LoginWebPage::EXIT_CODE_...) </description>
<type>integer</type>
</event_datum>
<event_datum id="state">
@@ -851,168 +849,5 @@ Call $this->AddInitialAttributeFlags($sAttCode, $iFlags) for all the initial att
</methods>
</class>
</classes>
<property_types _delta="define">
<property_type id="Dashlet" xsi:type="Combodo-AbstractPropertyType"/>
<property_type id="DashletGroupBy" xsi:type="Combodo-PropertyType">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<label>UI:DashletGroupBy:Title</label>
<nodes>
<node id="title" xsi:type="Combodo-ValueType-Label">
<label>UI:DashletGroupBy:Prop-Title</label>
</node>
<node id="query" xsi:type="Combodo-ValueType-OQL">
<label>UI:DashletGroupBy:Prop-Query</label>
</node>
<node id="group_by" xsi:type="Combodo-ValueType-ClassAttributeGroupBy">
<label>UI:DashletGroupBy:Prop-GroupBy</label>
<class>{{query.selected_class}}</class>
</node>
<node id="style" xsi:type="Combodo-ValueType-Choice"> <!-- Possible de le cacher, etc celui-ci nous met dedans -->
<label>UI:DashletGroupBy:Prop-Style</label>
<values>
<value id="bars">
<label>UI:DashletGroupByBars:Label</label>
</value>
<value id="pie">
<label>UI:DashletGroupByPie:Label</label>
</value>
<value id="table">
<label>UI:DashletGroupByTable:Label</label>
</value>
</values>
</node>
<node id="aggregation_function" xsi:type="Combodo-ValueType-AggregateFunction">
<label>UI:DashletGroupBy:Prop-Function</label>
<class>{{query.selected_class}}</class> <!-- pour savoir si il y a des attributs additionnables -->
</node>
<node id="aggregation_attribute" xsi:type="Combodo-ValueType-ClassAttribute">
<label>UI:DashletGroupBy:Prop-FunctionAttribute</label>
<relevance-condition>{{aggregation_function.value != 'count'}}</relevance-condition>
<class>{{query.selected_class}}</class>
<category>numeric</category>
</node>
<node id="order_by" xsi:type="Combodo-ValueType-ChoiceFromInput">
<label>UI:DashletGroupBy:Prop-OrderField</label>
<values>
<value id="attribute">
<label>{{aggregation_attribute.label}}</label>
</value>
<value id="function">
<label>{{aggregation_function.label}}</label>
</value>
</values>
</node>
<node id="limit" xsi:type="Combodo-ValueType-Integer">
<label>UI:DashletGroupBy:Prop-Limit</label>
<relevance-condition>{{order_by.value = 'function'}}</relevance-condition>
</node>
<node id="order_direction" xsi:type="Combodo-ValueType-Choice">
<label>UI:DashletGroupBy:Prop-OrderDirection</label>
<values>
<value id="asc">
<label>UI:DashletGroupBy:Order:asc</label>
</value>
<value id="desc">
<label>UI:DashletGroupBy:Order:desc</label>
</value>
</values>
</node>
</nodes>
</definition>
</property_type>
<property_type id="DashletBadge" xsi:type="Combodo-PropertyType">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes>
<node id="class" xsi:type="Combodo-ValueType-Class">
<label>UI:DashletBadge:Prop-Class</label>
<categories-csv>bizmodel</categories-csv>
</node>
</nodes>
</definition>
</property_type>
<property_type id="DashletHeaderDynamic" xsi:type="Combodo-PropertyType">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<label>UI:DashletHeaderDynamic:Title</label>
<nodes>
<node id="title" xsi:type="Combodo-ValueType-Label">
<label>UI:DashletHeaderDynamic:Prop-Title</label>
</node>
<node id="icon" xsi:type="Combodo-ValueType-Icon">
<label>UI:DashletHeaderDynamic:Prop-Icon</label>
</node>
<node id="subtitle" xsi:type="Combodo-ValueType-Label">
<label>UI:DashletHeaderDynamic:Prop-Subtitle</label>
</node>
<node id="query" xsi:type="Combodo-ValueType-OQL">
<label>UI:DashletHeaderDynamic:Prop-Query</label>
</node>
<node id="group_by" xsi:type="Combodo-ValueType-ClassAttribute">
<label>UI:DashletHeaderDynamic:Prop-GroupBy</label>
<class>{{query.selected_class}}</class>
<category>enum</category>
</node>
<node id="values" xsi:type="Combodo-ValueType-CollectionOfValues">
<label>UI:DashletHeaderDynamic:Prop-Values</label>
<xml-format xsi:type="Combodo-XMLFormat-CSV"/>
<value-type xsi:type="Combodo-ValueType-ClassAttributeValue">
<class>{{query.selected_class}}</class>
<attribute>{{group_by.attribute}}</attribute>
</value-type>
</node>
</nodes>
</definition>
</property_type>
<property_type id="DashletHeaderStatic" xsi:type="Combodo-PropertyType">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes>
<node id="title" xsi:type="Combodo-ValueType-Label">
<label>UI:DashletHeaderStatic:Prop-Title</label>
</node>
<node id="icon" xsi:type="Combodo-ValueType-Icon">
<label>UI:DashletHeaderStatic:Prop-Icon</label>
</node>
</nodes>
</definition>
</property_type>
<property_type id="DashletObjectList" xsi:type="Combodo-PropertyType">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes>
<node id="title" xsi:type="Combodo-ValueType-Label">
<label>UI:DashletObjectList:Prop-Title</label>
</node>
<node id="query" xsi:type="Combodo-ValueType-OQL">
<label>UI:DashletObjectList:Prop-Query</label>
</node>
<node id="menu" xsi:type="Combodo-ValueType-Boolean">
<label>UI:DashletObjectList:Prop-Menu</label>
<on>
<!-- not so cute, but matches exactly 3.2 implementation of boolean fields -->
<label>UI:UserManagement:ActionAllowed:Yes</label>
<value>true</value>
</on>
<off>
<label>UI:UserManagement:ActionAllowed:No</label>
<value>false</value>
</off>
</node>
</nodes>
</definition>
</property_type>
<property_type id="DashletPlainText" xsi:type="Combodo-PropertyType">
<extends>Dashlet</extends>
<definition xsi:type="Combodo-ValueType-PropertyTree">
<nodes>
<node id="text" xsi:type="Combodo-ValueType-Text">
<label>UI:DashletPlainText:Prop-Text</label>
</node>
</nodes>
</definition>
</property_type>
</property_types>
</meta>
</itop_design>

View File

@@ -726,10 +726,6 @@ class DisplayBlock
}
}
if (!$this->m_oFilter->IsAllDataAllowed() && ($aExtraParams['display_unauthorized_objects'] ?? false) === true) {
$this->m_oFilter->AllowAllData();
}
$aExtraParams['query_params'] = $this->m_oFilter->GetInternalParams();
$this->m_oSet = new CMDBObjectSet($this->m_oFilter, $aOrderBy, $aQueryParams);
}
@@ -1383,10 +1379,7 @@ JS
// Check the classes that can be read (i.e authorized) by this user...
foreach ($aClasses as $sAlias => $sClassName) {
if (
(UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $this->m_oSet) !== UR_ALLOWED_NO)
|| ($aExtraParams['display_unauthorized_objects'] ?? false) === true
) {
if (UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $this->m_oSet) != UR_ALLOWED_NO) {
$aAuthorizedClasses[$sAlias] = $sClassName;
}
}

View File

@@ -1,10 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
class ForgotPasswordApplicationException extends Exception
{
}

View File

@@ -1,10 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
class ForgotPasswordUserInputException extends Exception
{
}

View File

@@ -1387,7 +1387,7 @@ class DesignerIconSelectionField extends DesignerFormField
public function AddAllowedValue($aValue)
{
// Add a null value to the list of allowed values
$this->aAllowedValues = array_merge([$aValue], $this->aAllowedValues ?? [null]);
$this->aAllowedValues = array_merge([$aValue], $this->aAllowedValues);
}
public function EnableUpload($sIconUploadUrl)
{

View File

@@ -243,12 +243,15 @@ class LoginTwigRenderer
public function GetDefaultVars()
{
$sVersionShort = Dict::Format('UI:iTopVersion:Short', ITOP_APPLICATION, ITOP_VERSION);
$sIconUrl = Utils::GetConfig()->Get('app_icon_url');
$sDisplayIcon = Branding::GetLoginLogoAbsoluteUrl();
$aVars = [
'sAppRootUrl' => utils::GetAbsoluteUrlAppRoot(),
'aPluginFormData' => $this->GetPluginFormData(),
'sItopVersion' => ITOP_VERSION,
'sVersionShort' => $sVersionShort,
'sIconUrl' => $sIconUrl,
'sDisplayIcon' => $sDisplayIcon,
];

View File

@@ -221,15 +221,15 @@ class LoginWebPage extends NiceWebPage
if ($oUser != null) {
if (!MetaModel::IsValidAttCode(get_class($oUser), 'reset_pwd_token')) {
throw new ForgotPasswordUserInputException('External accounts do not allow password reset');
throw new Exception(Dict::S('UI:ResetPwd-Error-NotPossible'));
}
if (!$oUser->CanChangePassword()) {
throw new ForgotPasswordUserInputException('The account does not allow password reset');
throw new Exception(Dict::S('UI:ResetPwd-Error-FixedPwd'));
}
$sTo = $oUser->GetResetPasswordEmail(); // throws Exceptions if not allowed
if ($sTo == '') {
throw new ForgotPasswordUserInputException('Missing email address for this account');
throw new Exception(Dict::S('UI:ResetPwd-Error-NoEmail'));
}
// This token allows the user to change the password without knowing the previous one
@@ -255,21 +255,17 @@ class LoginWebPage extends NiceWebPage
case EMAIL_SEND_ERROR:
default:
throw new ForgotPasswordApplicationException('Failed to send the password reset email for '.$oUser->Get('friendlyname').': '.implode(', ', $aIssues));
IssueLog::Error('Failed to send the email with the NEW password for '.$oUser->Get('friendlyname').': '.implode(', ', $aIssues));
throw new Exception(Dict::S('UI:ResetPwd-Error-Send'));
}
}
} catch (ForgotPasswordApplicationException $e) {
IssueLog::Error('Failed to process the forgot password request for user "'.$sAuthUser.'" [reason='.get_class($e).']: '.$e->getMessage());
} catch (ForgotPasswordUserInputException $e) {
IssueLog::Info('Failed to process the forgot password request for user "'.$sAuthUser.'" [reason='.get_class($e).']: '.$e->getMessage());
} catch (\Throwable $e) {
IssueLog::Error('Unexpected error while processing the forgot password request for user "'.$sAuthUser.'": '.$e->getMessage());
$oTwigContext = new LoginTwigRenderer();
$aVars = $oTwigContext->GetDefaultVars();
$oTwigContext->Render($this, 'forgotpwdsent.html.twig', $aVars);
} catch (Exception $e) {
$this->DisplayForgotPwdForm(true, $e->getMessage());
}
$oTwigContext = new LoginTwigRenderer();
$aVars = $oTwigContext->GetDefaultVars();
$oTwigContext->Render($this, 'forgotpwdsent.html.twig', $aVars);
}
public function DisplayResetPwdForm($sErrorMessage = null)

View File

@@ -34,7 +34,7 @@ interface iNewsroomProvider
* @param User $oUser The user for who to check if the provider is applicable.
* return bool
*/
public function IsApplicable(?User $oUser = null);
public function IsApplicable(User $oUser = null);
/**
* The human readable (localized) label for this provider
@@ -139,7 +139,7 @@ abstract class NewsroomProviderBase implements iNewsroomProvider
*/
abstract public function GetViewAllURL();
public function IsApplicable(?User $oUser = null)
public function IsApplicable(User $oUser = null)
{
return false;
}

View File

@@ -151,7 +151,7 @@ abstract class Query extends cmdbAbstractObject
* @return string|null
* @since 3.1.0
*/
abstract public function GetExportUrl(?array $aValues = null): ?string;
abstract public function GetExportUrl(array $aValues = null): ?string;
/**
* Update last export information.
@@ -227,7 +227,7 @@ class QueryOQL extends Query
}
/** @inheritdoc */
public function GetExportUrl(?array $aValues = null): ?string
public function GetExportUrl(array $aValues = null): ?string
{
try {
// retrieve attributes

View File

@@ -924,6 +924,11 @@ CSS;
public static function CloneThemeParameterAndIncludeVersion($aThemeParameters, $bSetupCompilationTimestamp, $aImportsPaths)
{
$aThemeParametersVariable = [];
if (array_key_exists('variables', $aThemeParameters)) {
if (is_array($aThemeParameters['variables'])) {
$aThemeParametersVariable = array_merge([], $aThemeParameters['variables']);
}
}
if (array_key_exists('variable_imports', $aThemeParameters)) {
if (is_array($aThemeParameters['variable_imports'])) {
@@ -931,14 +936,6 @@ CSS;
}
}
// Variables defined in theme XML have the priority over variables defined in XML imports files
// They're defined after so they overwrite previous parameters
if (array_key_exists('variables', $aThemeParameters)) {
if (is_array($aThemeParameters['variables'])) {
$aThemeParametersVariable = array_merge($aThemeParametersVariable, $aThemeParameters['variables']);
}
}
$aThemeParametersVariable['$version'] = $bSetupCompilationTimestamp;
return $aThemeParametersVariable;
}
@@ -970,9 +967,7 @@ CSS;
}
}
}
array_map(function ($sVariableValue) {
return ltrim($sVariableValue);
}, $aVariablesResults);
array_map(function ($sVariableValue) { return ltrim($sVariableValue); }, $aVariablesResults);
return $aVariablesResults;
}

View File

@@ -27,9 +27,6 @@ require_once(APPROOT.'/application/displayblock.class.inc.php');
class UISearchFormForeignKeys
{
private $m_sRemoteClass;
private $m_iInputId;
public function __construct($sTargetClass, $iInputId = null)
{
$this->m_sRemoteClass = $sTargetClass;
@@ -43,7 +40,7 @@ class UISearchFormForeignKeys
*
* @throws \Exception
*/
public function ShowModalSearchForeignKeys($oPage)
public function ShowModalSearchForeignKeys($oPage, $sTitle)
{
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
@@ -63,6 +60,8 @@ class UISearchFormForeignKeys
]
));
$sEmptyList = Dict::S('UI:Message:EmptyList:UseSearchForm');
$sCancel = Dict::S('UI:Button:Cancel');
$sAdd = Dict::S('UI:Button:Add');
$oPage->add(
<<<HTML
@@ -74,6 +73,39 @@ class UISearchFormForeignKeys
</form>
HTML
);
$oPage->add_ready_script(
<<<JS
$('#dlg_{$this->m_iInputId}').dialog({
width: $(window).width()*0.8,
height: $(window).height()*0.8,
autoOpen: false,
modal: true,
resizeStop: oForeignKeysWidget{$this->m_iInputId}.UpdateSizes,
buttons: [
{
text: Dict.S('UI:Button:Cancel'),
class: "cancel ibo-is-alternative ibo-is-neutral",
click: function() {
$('#dlg_{$this->m_iInputId}').dialog('close');
}
},
{
text: Dict.S('UI:Button:Add'),
id: 'btn_ok_{$this->m_iInputId}',
class: "ok ibo-is-regular ibo-is-primary",
click: function() {
oForeignKeysWidget{$this->m_iInputId}.DoAddObjects(this.id);
}
},
],
});
$('#dlg_{$this->m_iInputId}').dialog('option', {title:'$sTitle'});
$('#SearchFormToAdd_{$this->m_iInputId} form').on('submit.uilinksWizard', oForeignKeysWidget{$this->m_iInputId}.SearchObjectsToAdd);
$('#SearchFormToAdd_{$this->m_iInputId}').on('resize', oForeignKeysWidget{$this->m_iInputId}.UpdateSizes);
JS
);
}
public function GetFullListForeignKeysFromSelection($oPage, $oFullSetFilter)
@@ -87,4 +119,31 @@ HTML
IssueLog::Error($e->getMessage()."\nDebug trace:\n".$e->getTraceAsString());
}
}
/**
* Search for objects to be linked to the current object (i.e "remote" objects)
*
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of m_sRemoteClass
*
* @throws \Exception
*/
public function ListResultsSearchForeignKeys(WebPage $oP, $sRemoteClass = '')
{
if ($sRemoteClass != '') {
// assert(MetaModel::IsParentClass($this->m_sRemoteClass, $sRemoteClass));
$oFilter = new DBObjectSearch($sRemoteClass);
} else {
// No remote class specified use the one defined in the linkedset
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
}
$oBlock = new DisplayBlock($oFilter, 'list', false);
$oBlock->Display(
$oP,
"ResultsToAdd_{$this->m_iInputId}",
['menu' => false, 'cssCount' => "#count_{$this->m_iInputId}", 'selection_mode' => true, 'table_id' => "add_{$this->m_iInputId}"]
);
}
}

View File

@@ -122,11 +122,6 @@ class utils
* @since 3.0.0
*/
public const ENUM_SANITIZATION_FILTER_VARIABLE_NAME = 'variable_name';
/**
* @var string For module codes (e.g. `itop-portal-base`, `combodo-webhook-integration`, `some-module-code-x.y`, ...)
* @since 3.2.3 3.3.0 N°8554
*/
public const ENUM_SANITIZATION_FILTER_MODULE_CODE = 'module_code';
/**
* @var string
* @since 2.7.10 3.0.0
@@ -186,9 +181,6 @@ class utils
protected static function LoadParamFile($sParamFile)
{
if (utils::RealPath($sParamFile, APPROOT) !== false) {
throw new Exception("File '".utils::HtmlEntities($sParamFile)."' should be outside iTop");
}
if (!file_exists($sParamFile)) {
throw new Exception("Could not find the parameter file: '".utils::HtmlEntities($sParamFile)."'");
}
@@ -398,7 +390,6 @@ class utils
* @since 2.7.10 N°6606 use the utils::ENUM_SANITIZATION_* const
* @since 2.7.10 N°6606 new case for ENUM_SANITIZATION_FILTER_PHP_CLASS
* @since 3.2.1-1 N°8242 Allow value to be an array for every filter
* @since 3.2.3 3.3.0 N°8554 new case for ENUM_SANITIZATION_FILTER_MODULE_CODE
*
* @link https://www.php.net/manual/en/filter.filters.sanitize.php PHP sanitization filters
*/
@@ -486,7 +477,7 @@ class utils
);
break;
// For XML / HTML node selector
// For XML / HTML node id selector
case static::ENUM_SANITIZATION_FILTER_ELEMENT_SELECTOR:
$retValue = filter_var(
$value,
@@ -499,15 +490,6 @@ class utils
$retValue = preg_replace('/[^a-zA-Z0-9_]/', '', $value);
break;
case static::ENUM_SANITIZATION_FILTER_MODULE_CODE:
// Module codes allow all alphabets letters, numbers, dash and dot characters
$retValue = filter_var(
$value,
FILTER_VALIDATE_REGEXP,
['options' => ['regexp' => '/^[\p{L}\d.-]+$/u']]
);
break;
// For URL
case static::ENUM_SANITIZATION_FILTER_URL:
$retValue = filter_var($value, FILTER_SANITIZE_URL);
@@ -976,7 +958,7 @@ class utils
return self::$oConfig;
}
$sProductionEnvConfigPath = self::GetConfigFilePath(ITOP_DEFAULT_ENV);
$sProductionEnvConfigPath = self::GetConfigFilePath('production');
if (file_exists($sProductionEnvConfigPath)) {
$oProductionEnvDiskConfig = new Config($sProductionEnvConfigPath);
self::SetConfig($oProductionEnvDiskConfig);
@@ -1302,7 +1284,7 @@ class utils
* @throws \CoreException
* @throws \Exception
*/
public static function ExecITopScript(string $sScriptName, array $aArguments, ?string $sAuthUser = null, ?string $sAuthPwd = null)
public static function ExecITopScript(string $sScriptName, array $aArguments, string $sAuthUser = null, string $sAuthPwd = null)
{
$aDisabled = explode(', ', ini_get('disable_functions'));
if (in_array('exec', $aDisabled)) {
@@ -1392,7 +1374,7 @@ class utils
* @return string A path to a folder into which any module can store cache data
* The corresponding folder is created or cleaned upon code compilation
*/
public static function GetCachePath(?string $sEnvironment = null): string
public static function GetCachePath(string $sEnvironment = null): string
{
if (is_null($sEnvironment)) {
$sEnvironment = MetaModel::GetEnvironment();
@@ -1455,12 +1437,6 @@ class utils
case iPopupMenuExtension::MENU_OBJLIST_TOOLKIT:
/** @var \DBObjectSet $param */
// Check if the user has the right to read the objects of this list, otherwise do not propose any action (eg. configure this list, export, etc.)
if (UserRights::IsActionAllowed($param->GetFilter()->GetClass(), UR_ACTION_READ, $param) !== UR_ALLOWED_YES) {
break;
}
$oAppContext = new ApplicationContext();
$sContext = $oAppContext->GetForLink(true);
$sDataTableId = is_null($sDataTableId) ? '' : $sDataTableId;
@@ -1924,12 +1900,6 @@ SQL;
return $response;
}
public static function QuoteForPHP(string $sValue): string
{
$sEscaped = str_replace(['\\', "'"], ['\\\\', "\\'"], $sValue);
return "'$sEscaped'";
}
/**
* Get a standard list of character sets
*
@@ -2105,9 +2075,7 @@ SQL;
}
// Remove any remaining nulls (for positions that weren't referenced)
$aReplacements = array_filter($aReplacements, static function ($val) {
return $val !== null;
});
$aReplacements = array_filter($aReplacements, static function ($val) { return $val !== null; });
} else {
// For non-positional, we need to map each position
$aReplacements = [];

View File

@@ -4,7 +4,7 @@
"type": "project",
"license": "AGPL-3.0-only",
"require": {
"php": ">=8.1.0 <8.5.0",
"php": ">=8.1.0 <8.4.0",
"ext-ctype": "*",
"ext-dom": "*",
"ext-gd": "*",
@@ -12,43 +12,37 @@
"ext-json": "*",
"ext-mysqli": "*",
"ext-soap": "*",
"apereo/phpcas": "dev-master",
"apereo/phpcas": "~1.6.0",
"firebase/php-jwt": "^6.4.0",
"guzzlehttp/guzzle": "^7.5.1",
"league/oauth2-google": "^4.0.1",
"nikic/php-parser": "^4.14.0",
"nikic/php-parser": "dev-master",
"pear/archive_tar": "~1.4.14",
"pelago/emogrifier": "^7.2.0",
"psr/log": "^3.0.0",
"scssphp/scssphp": "dev-combodo/1.x",
"scssphp/scssphp": "^1.12.1",
"soundasleep/html2text": "~2.1",
"symfony/console": "~6.4.0",
"symfony/dotenv": "~6.4.0",
"symfony/form": "^6.4",
"symfony/framework-bundle": "~6.4.0",
"symfony/http-foundation": "~6.4.0",
"symfony/http-kernel": "~6.4.0",
"symfony/runtime": "~6.4.0",
"symfony/mailer": "^6.4",
"symfony/security-csrf": "^6.4",
"symfony/twig-bundle": "~6.4.0",
"symfony/var-dumper": "~6.4.0",
"symfony/yaml": "~6.4.0",
"symfony/mailer": "~6.4.0",
"tecnickcom/tcpdf": "^6.6.0",
"thenetworg/oauth2-azure": "^2.0",
"soundasleep/html2text": "~2.1"
"thenetworg/oauth2-azure": "^2.0"
},
"require-dev": {
"symfony/debug-bundle": "~6.4.0",
"symfony/stopwatch": "~6.4.0",
"symfony/web-profiler-bundle": "~6.4.0"
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/EsupPortail/phpCAS"
},
{
"type": "vcs",
"url": "https://github.com/combodo-itop-libs/scssphp"
}
],
"repositories": [{
"type": "vcs",
"url": "https://github.com/Combodo/PHP-Parser"
}],
"suggest": {
"ext-libsodium": "Required to use the AttributeEncryptedString.",
"ext-openssl": "Can be used as a polyfill if libsodium is not installed",
@@ -68,10 +62,7 @@
},
"sort-packages": true,
"classmap-authoritative": true,
"platform-check": true,
"allow-plugins": {
"symfony/runtime": true
}
"platform-check": true
},
"autoload": {
"classmap": [
@@ -80,7 +71,6 @@
"sources"
],
"exclude-from-classmap": [
"application/twigextension.class.inc.php",
"core/oql/build/PHP/",
"core/apc-emulation.php",
"application/startup.inc.php",
@@ -100,7 +90,7 @@
"extra": {
"symfony": {
"allow-contrib": false,
"require": "3.4.*"
"require": "6.4.*"
},
"runtime": {
"dotenv_path": "resources/symfony/.env"

1219
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -234,11 +234,10 @@ abstract class Action extends cmdbAbstractObject
}
$oActionFilter = DBObjectSearch::FromOQL($sActionQueryOql, $aActionQueryParams);
$oActionFilter->AllowAllData();
$oSet = new DBObjectSet($oActionFilter, ['date' => false]);
$sPanelTitle = Dict::Format('Action:last_executions_tab_panel_title', $sActionQueryLimit);
$oExecutionsListBlock = DataTableUIBlockFactory::MakeForResult($oPage, 'action_executions_list', $oSet, ['panel_title' => $sPanelTitle, 'display_unauthorized_objects' => true]);
$oExecutionsListBlock = DataTableUIBlockFactory::MakeForResult($oPage, 'action_executions_list', $oSet, ['panel_title' => $sPanelTitle]);
$oPage->AddUiBlock($oExecutionsListBlock);
}

View File

@@ -24,7 +24,7 @@ MetaModel::IncludeModule('application/user.dashboard.class.inc.php');
MetaModel::IncludeModule('application/audit.rule.class.inc.php');
MetaModel::IncludeModule('application/audit.domain.class.inc.php');
MetaModel::IncludeModule('application/query.class.inc.php');
MetaModel::IncludeModule('setup/moduleinstallation/moduleinstallation.class.inc.php');
MetaModel::IncludeModule('setup/moduleinstallation.class.inc.php');
MetaModel::IncludeModule('core/event.class.inc.php');
MetaModel::IncludeModule('core/action.class.inc.php');

View File

@@ -199,7 +199,7 @@ class CellStatus_SearchIssue extends CellStatus_Issue
* @param null $sAllowedValues : used for additional message that provides allowed values $sAllowedValues for current class
* @param string|null $sAllowedValuesSearch : used to search all allowed values
*/
public function __construct($sSerializedSearch, $sReason, $sClass = null, $sAllowedValues = null, ?string $sAllowedValuesSearch = null)
public function __construct($sSerializedSearch, $sReason, $sClass = null, $sAllowedValues = null, string $sAllowedValuesSearch = null)
{
parent::__construct(null, null, $sReason);
$this->sSerializedSearch = $sSerializedSearch;
@@ -876,7 +876,7 @@ class BulkChange
return $aResults;
}
protected function CreateObject(&$aResult, $iRow, $aRowData, ?CMDBChange $oChange = null)
protected function CreateObject(&$aResult, $iRow, $aRowData, CMDBChange $oChange = null)
{
$oTargetObj = MetaModel::NewObject($this->m_sClass);
@@ -965,7 +965,7 @@ class BulkChange
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
protected function UpdateObject(&$aResult, $iRow, $oTargetObj, $aRowData, ?CMDBChange $oChange = null)
protected function UpdateObject(&$aResult, $iRow, $oTargetObj, $aRowData, CMDBChange $oChange = null)
{
$aResult[$iRow] = $this->PrepareObject($oTargetObj, $aRowData, $aErrors);
@@ -1008,7 +1008,7 @@ class BulkChange
*
* @throws \BulkChangeException
*/
protected function UpdateMissingObject(&$aResult, $iRow, $oTargetObj, ?CMDBChange $oChange = null)
protected function UpdateMissingObject(&$aResult, $iRow, $oTargetObj, CMDBChange $oChange = null)
{
$aResult[$iRow] = $this->PrepareMissingObject($oTargetObj, $aErrors);
@@ -1043,7 +1043,7 @@ class BulkChange
}
}
public function Process(?CMDBChange $oChange = null)
public function Process(CMDBChange $oChange = null)
{
if ($oChange) {
CMDBObject::SetCurrentChange($oChange);

View File

@@ -20,6 +20,9 @@
*
*/
use Combodo\iTop\Config\Validator\iTopConfigAstValidator;
use Combodo\iTop\Config\Validator\iTopConfigSyntaxValidator;
define('ITOP_APPLICATION', 'iTop');
define('ITOP_APPLICATION_SHORT', 'iTop');
@@ -208,14 +211,6 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => true,
],
'allowed_login_types' => [
'type' => 'string',
'description' => 'List of login types allowed (separated by | ): form, external, basic, token',
'default' => DEFAULT_ALLOWED_LOGIN_TYPES,
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => true,
],
'app_icon_url' => [
'type' => 'string',
'description' => 'Hyperlink to redirect the user when clicking on the application icon (in the main window, or login/logoff pages)',
@@ -925,7 +920,7 @@ class Config
'type' => 'string',
'description' => 'Actions that are available as direct buttons next to the "Actions" menu',
// examples... not used
'default' => 'UI:Menu:Modify,UI:Menu:New,UI:Menu:impacts_down,UI:Menu:impacts_up',
'default' => 'UI:Menu:Modify,UI:Menu:New',
'value' => 'UI:Menu:Modify',
'source_of_value' => '',
'show_in_conf_sample' => true,
@@ -1170,8 +1165,8 @@ class Config
'tracking_level_linked_set_default' => [
'type' => 'integer',
'description' => 'Default tracking level if not explicitly set at the attribute level, for AttributeLinkedSet (defaults to NONE in case of a fresh install, LIST otherwise - this to preserve backward compatibility while upgrading from a version older than 2.0.3 - see TRAC #936)',
'default' => LINKSET_TRACKING_NONE,
'value' => LINKSET_TRACKING_NONE,
'default' => LINKSET_TRACKING_LIST,
'value' => LINKSET_TRACKING_LIST,
'source_of_value' => '',
'show_in_conf_sample' => false,
],
@@ -1737,14 +1732,6 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'security.disable_joined_classes_filter' => [
'type' => 'bool',
'description' => 'If true, scope filters aren\'t applied to joined classes or union classes not directly listed in the SELECT clause.',
'default' => true,
'value' => true,
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'security.hide_administrators' => [
'type' => 'bool',
'description' => 'If true, non-administrator users will not be able to see the administrator accounts, the Administrator profile and the links between the administrator accounts and their profiles.',
@@ -1753,14 +1740,6 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'security.disable_exec_forced_login_for_all_enpoints' => [
'type' => 'bool',
'description' => 'If true, when no delegated authentication module is defined, no login will be forced on modules exec endpoints',
'default' => true,
'value' => true,
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'behind_reverse_proxy' => [
'type' => 'bool',
'description' => 'If true, then proxies custom header (X-Forwarded-*) are taken into account. Use only if the webserver is not publicly accessible (reachable only by the reverse proxy)',
@@ -1967,6 +1946,11 @@ class Config
*/
protected $m_sDefaultLanguage;
/**
* @var string Type of login process allowed: form|basic|url|external
*/
protected $m_sAllowedLoginTypes;
/**
* @var string Name of the PHP variable in which external authentication information is passed by the web server
*/
@@ -2040,6 +2024,7 @@ class Config
$this->m_iFastReloadInterval = DEFAULT_FAST_RELOAD_INTERVAL;
$this->m_bSecureConnectionRequired = DEFAULT_SECURE_CONNECTION_REQUIRED;
$this->m_sDefaultLanguage = 'EN US';
$this->m_sAllowedLoginTypes = DEFAULT_ALLOWED_LOGIN_TYPES;
$this->m_sExtAuthVariable = DEFAULT_EXT_AUTH_VARIABLE;
$this->m_aCharsets = [];
$this->m_bQueryCacheEnabled = DEFAULT_QUERY_CACHE_ENABLED;
@@ -2186,6 +2171,7 @@ class Config
$this->m_aModuleSettings = isset($MyModuleSettings) ? $MyModuleSettings : [];
$this->m_sDefaultLanguage = isset($MySettings['default_language']) ? trim($MySettings['default_language']) : 'EN US';
$this->m_sAllowedLoginTypes = isset($MySettings['allowed_login_types']) ? trim($MySettings['allowed_login_types']) : DEFAULT_ALLOWED_LOGIN_TYPES;
$this->m_sExtAuthVariable = isset($MySettings['ext_auth_variable']) ? trim($MySettings['ext_auth_variable']) : DEFAULT_EXT_AUTH_VARIABLE;
$this->m_sEncryptionKey = isset($MySettings['encryption_key']) ? trim($MySettings['encryption_key']) : $this->m_sEncryptionKey;
$this->m_sEncryptionLibrary = isset($MySettings['encryption_library']) ? trim($MySettings['encryption_library']) : $this->m_sEncryptionLibrary;
@@ -2345,7 +2331,7 @@ class Config
public function GetAllowedLoginTypes()
{
return explode('|', $this->m_aSettings['allowed_login_types']['value']);
return explode('|', $this->m_sAllowedLoginTypes);
}
public function GetExternalAuthenticationVariable()
@@ -2423,7 +2409,7 @@ class Config
public function SetAllowedLoginTypes($aAllowedLoginTypes)
{
$this->Set('allowed_login_types', implode('|', $aAllowedLoginTypes));
$this->m_sAllowedLoginTypes = implode('|', $aAllowedLoginTypes);
}
/**
@@ -2500,6 +2486,7 @@ class Config
$aSettings['fast_reload_interval'] = $this->m_iFastReloadInterval;
$aSettings['secure_connection_required'] = $this->m_bSecureConnectionRequired;
$aSettings['default_language'] = $this->m_sDefaultLanguage;
$aSettings['allowed_login_types'] = $this->m_sAllowedLoginTypes;
$aSettings['ext_auth_variable'] = $this->m_sExtAuthVariable;
$aSettings['encryption_key'] = $this->m_sEncryptionKey;
$aSettings['encryption_library'] = $this->m_sEncryptionLibrary;
@@ -2603,6 +2590,7 @@ class Config
// Old fashioned remaining values
$aOtherValues = [
'default_language' => $this->m_sDefaultLanguage,
'allowed_login_types' => $this->m_sAllowedLoginTypes,
'ext_auth_variable' => $this->m_sExtAuthVariable,
'encryption_key' => $this->m_sEncryptionKey,
'encryption_library' => $this->m_sEncryptionLibrary,
@@ -2688,13 +2676,14 @@ class Config
*
* @param array $aParamValues
* @param ?string $sModulesDir
* @param bool $bPreserveModuleSettings
*
* @return void The current object is modified directly
*
* @throws \Exception
* @throws \CoreException
*/
public function UpdateFromParams($aParamValues, $sModulesDir = null)
public function UpdateFromParams($aParamValues, $sModulesDir = null, $bPreserveModuleSettings = false)
{
if (isset($aParamValues['application_path'])) {
$this->Set('app_root_url', $aParamValues['application_path']);
@@ -2742,10 +2731,7 @@ class Config
} else {
$aSelectedModules = null;
}
if (! is_null($sModulesDir)) {
$this->UpdateIncludes($sModulesDir, $aSelectedModules);
}
$this->UpdateIncludes($sModulesDir, $aSelectedModules);
if (isset($aParamValues['source_dir'])) {
$this->Set('source_dir', $aParamValues['source_dir']);
@@ -2763,13 +2749,17 @@ class Config
*
* @throws Exception
*/
public function UpdateIncludes(string $sModulesDir, $aSelectedModules = null)
public function UpdateIncludes($sModulesDir, $aSelectedModules = null)
{
if ($sModulesDir === null) {
return;
}
// Initialize the arrays below with default values for the application...
$oEmptyConfig = new Config('dummy_file', false); // Do NOT load any config file, just set the default values
$aAddOns = $oEmptyConfig->GetAddOns();
$aModules = ModuleDiscovery::GetModulesOrderedByDependencies([APPROOT.$sModulesDir]);
$aModules = ModuleDiscovery::GetAvailableModules([APPROOT.$sModulesDir]);
foreach ($aModules as $sModuleId => $aModuleInfo) {
list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId);
if (is_null($aSelectedModules) || in_array($sModuleName, $aSelectedModules)) {

View File

@@ -5,7 +5,6 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Application\Helper\ExportHelper;
use Combodo\iTop\Application\UI\Base\Component\FieldSet\FieldSetUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
@@ -14,6 +13,7 @@ use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectUIBlockFactory
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\ColumnUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactory;
use Combodo\iTop\Application\Helper\ExportHelper;
use Combodo\iTop\Application\WebPage\Page;
use Combodo\iTop\Application\WebPage\WebPage;
@@ -55,8 +55,6 @@ class CSVBulkExport extends TabularBulkExport
$this->aStatusInfo['charset'] = strtoupper(utils::ReadParam('charset', 'UTF-8', true, 'raw_data'));
$this->aStatusInfo['formatted_text'] = (bool)utils::ReadParam('formatted_text', 0, true);
$this->aStatusInfo['ignore_excel_sanitization'] = (bool)utils::ReadParam('ignore_excel_sanitization', 0, true, utils::ENUM_SANITIZATION_FILTER_INTEGER);
$sDateFormatRadio = utils::ReadParam('csv_date_format_radio', '');
switch ($sDateFormatRadio) {
case 'default':
@@ -225,10 +223,6 @@ class CSVBulkExport extends TabularBulkExport
$oRadioCustom->GetInput()->AddCSSClass('ibo-input-checkbox');
$oFieldSetDate->AddSubBlock($oRadioCustom);
$oFieldSetSecurity = FieldSetUIBlockFactory::MakeStandard(Dict::S('Core:BulkExport:Security'));
$oMulticolumn->AddColumn(ColumnUIBlockFactory::MakeForBlock($oFieldSetSecurity));
$oFieldSetSecurity->AddSubBlock(ExportHelper::GetInputForSanitizeExcelExport());
$oP->add_ready_script(
<<<EOF
$('#form_part_csv_options').on('preview_updated', function() { FormatDatesInPreview('csv', 'csv'); });
@@ -270,13 +264,6 @@ EOF
default:
$sRet = trim($oObj->GetAsCSV($sAttCode), '"');
}
// If the option to ignore Excel sanitization is not set or explicitly set to false, apply sanitization
if (!(array_key_exists('ignore_excel_sanitization', $this->aStatusInfo)) || $this->aStatusInfo['ignore_excel_sanitization'] === false) {
return ExportHelper::SanitizeField($sRet, $this->aStatusInfo['text_qualifier'] ?? '');
}
// The option to ignore Excel sanitization is explicitly set to true: return the raw value without sanitization
return $sRet;
}
@@ -350,12 +337,6 @@ EOF
$sField = $oObj->GetAsCSV($sAttCode, $this->aStatusInfo['separator'], $this->aStatusInfo['text_qualifier'], $this->bLocalizeOutput, !$this->aStatusInfo['formatted_text']);
}
}
// If the option to ignore Excel sanitization is not set or absent, sanitize the field
if (!(array_key_exists('ignore_excel_sanitization', $this->aStatusInfo)) || $this->aStatusInfo['ignore_excel_sanitization'] === false) {
$sField = ExportHelper::SanitizeField($sField, $this->aStatusInfo['text_qualifier']);
}
if ($this->aStatusInfo['charset'] != 'UTF-8') {
// Note: due to bugs in the glibc library it's safer to call iconv on the smallest possible string
// and thus to convert field by field and not the whole row or file at once (see ticket N°991)

View File

@@ -425,7 +425,7 @@
</php_parent>
<parent>cmdbAbstractObject</parent>
<properties>
<category>core/cmdb,grant_by_profile,silo</category>
<category>core/cmdb,view_in_gui</category>
<abstract>false</abstract>
<key_type>autoincrement</key_type>
<db_table>priv_event_newsroom</db_table>
@@ -904,7 +904,7 @@
<!-- Generated by toolkit/export-class-to-meta.php -->
<parent>Event</parent>
<properties>
<category>core/cmdb,grant_by_profile,silo</category>
<category>core/cmdb,view_in_gui</category>
</properties>
<fields>
<field id="message" xsi:type="AttributeText"/>

View File

@@ -2567,7 +2567,7 @@ abstract class DBObject implements iDisplay
*
* @see \RestUtils::FindObjectFromKey for the same check in the REST endpoint
*/
final public function CheckChangedExtKeysValues(?callable $oIsObjectLoadableCallback = null)
final public function CheckChangedExtKeysValues(callable $oIsObjectLoadableCallback = null)
{
if (is_null($oIsObjectLoadableCallback)) {
$oIsObjectLoadableCallback = function ($sClass, $sId) {
@@ -3727,7 +3727,7 @@ abstract class DBObject implements iDisplay
* @throws \MySQLException
* @throws \OQLException
*/
private function ActivateOnObjectUpdateTriggers(?DBObject $oObject, ?array $aAttributes = null): void
private function ActivateOnObjectUpdateTriggers(?DBObject $oObject, array $aAttributes = null): void
{
if (is_null($oObject)) {
return;
@@ -5108,8 +5108,8 @@ abstract class DBObject implements iDisplay
protected function GetReferencingObjectsForDeletion($bAllowAllData = false)
{
$aDependentObjects = [];
$aReferencingMe = MetaModel::EnumReferencingClasses(get_class($this));
foreach ($aReferencingMe as $sRemoteClass => $aExtKeys) {
$aRererencingMe = MetaModel::EnumReferencingClasses(get_class($this));
foreach ($aRererencingMe as $sRemoteClass => $aExtKeys) {
/** @var \AttributeExternalKey $oExtKeyAttDef */
foreach ($aExtKeys as $sExtKeyAttCode => $oExtKeyAttDef) {
// skip if external key doesn't require the deletion cascading

View File

@@ -1932,37 +1932,4 @@ class DBObjectSearch extends DBSearch
{
return $this->GetCriteria()->ListParameters();
}
/**
* @inheritDoc
* @return DBObjectSearch
*/
protected function ApplyDataFilters(): DBObjectSearch
{
if ($this->IsAllDataAllowed() || $this->IsDataFiltered()) {
return $this;
}
$oSearch = $this;
$aClassesToFilter = $this->GetSelectedClasses();
// Opt-in for joined classes filtering, otherwise only filter the selected class(es)
if (MetaModel::GetConfig()->Get('security.disable_joined_classes_filter') === false) {
$aClassesToFilter = $this->GetJoinedClasses();
}
// Apply filter (this is similar to the one in DBSearch but the factorization could make it less readable)
foreach ($aClassesToFilter as $sClassAlias => $sClass) {
$oVisibleObjects = UserRights::GetSelectFilter($sClass, $this->GetModifierProperties('UserRightsGetSelectFilter'));
if ($oVisibleObjects === false) {
$oVisibleObjects = DBObjectSearch::FromEmptySet($sClass);
}
if (is_object($oVisibleObjects)) {
$oVisibleObjects->AllowAllData();
$oSearch = $oSearch->Filter($sClassAlias, $oVisibleObjects);
$oSearch->SetDataFiltered();
}
}
return $oSearch;
}
}

View File

@@ -650,7 +650,7 @@ abstract class DBSearch
*
* @throws OQLException
*/
public static function FromOQL($sQuery, $aParams = null, ?ModelReflection $oMetaModel = null)
public static function FromOQL($sQuery, $aParams = null, ModelReflection $oMetaModel = null)
{
if (empty($sQuery)) {
return null;
@@ -1048,7 +1048,21 @@ abstract class DBSearch
*/
protected function GetSQLQuery($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $aGroupByExpr = null, $aSelectExpr = null)
{
$oSearch = $this->ApplyDataFilters();
$oSearch = $this;
if (!$this->IsAllDataAllowed() && !$this->IsDataFiltered()) {
foreach ($this->GetSelectedClasses() as $sClassAlias => $sClass) {
$oVisibleObjects = UserRights::GetSelectFilter($sClass, $this->GetModifierProperties('UserRightsGetSelectFilter'));
if ($oVisibleObjects === false) {
// Make sure this is a valid search object, saying NO for all
$oVisibleObjects = DBObjectSearch::FromEmptySet($sClass);
}
if (is_object($oVisibleObjects)) {
$oVisibleObjects->AllowAllData();
$oSearch = $oSearch->Filter($sClassAlias, $oVisibleObjects);
$oSearch->SetDataFiltered();
}
}
}
if (is_array($aGroupByExpr)) {
foreach ($aGroupByExpr as $sAlias => $oGroupByExp) {
@@ -1510,33 +1524,4 @@ abstract class DBSearch
* @return array{\VariableExpression}
*/
abstract public function GetExpectedArguments(): array;
/**
* Apply data filters to the search, if needed
*
* @return DBSearch
* @throws CoreException
*/
protected function ApplyDataFilters(): DBSearch
{
if ($this->IsAllDataAllowed() || $this->IsDataFiltered()) {
return $this;
}
$oSearch = $this;
$aClassesToFilter = $this->GetSelectedClasses();
foreach ($aClassesToFilter as $sClassAlias => $sClass) {
$oVisibleObjects = UserRights::GetSelectFilter($sClass, $this->GetModifierProperties('UserRightsGetSelectFilter'));
if ($oVisibleObjects === false) {
$oVisibleObjects = DBObjectSearch::FromEmptySet($sClass);
}
if (is_object($oVisibleObjects)) {
$oVisibleObjects->AllowAllData();
$oSearch = $oSearch->Filter($sClassAlias, $oVisibleObjects);
$oSearch->SetDataFiltered();
}
}
return $oSearch;
}
}

View File

@@ -59,7 +59,7 @@ class DBUnionSearch extends DBSearch
public function AllowAllData($bAllowAllData = true)
{
foreach ($this->aSearches as $oSearch) {
$oSearch->AllowAllData($bAllowAllData);
$oSearch->AllowAllData();
}
}
@@ -673,30 +673,4 @@ class DBUnionSearch extends DBSearch
return $aVariableCriteria;
}
/**
* @inheritDoc
* @return DBUnionSearch
*/
protected function ApplyDataFilters(): DBUnionSearch
{
if ($this->IsAllDataAllowed() || $this->IsDataFiltered()) {
return $this;
}
// Opt-in for joined classes filtering, otherwise fallback on DBSearch filtering
if (MetaModel::GetConfig()->Get('security.disable_joined_classes_filter') === true) {
return parent::ApplyDataFilters();
}
// Apply filters per sub-search
$aFilteredSearches = [];
foreach ($this->GetSearches() as $oSubSearch) {
// Recursively call ApplyDataFilters on sub-searches
$aFilteredSearches[] = $oSubSearch->ApplyDataFilters();
}
$oSearch = new DBUnionSearch($aFilteredSearches);
return $oSearch;
}
}

View File

@@ -41,7 +41,7 @@ use utils;
/**
* Class \Combodo\iTop\DesignDocument
*
* A design document is the DOM tree that models behaviors. One of its
* A design document is the DOM tree that modelize behaviors. One of its
* characteristics is that it can be altered by the mean of the same kind of document.
*
*/
@@ -360,10 +360,10 @@ class DesignElement extends \DOMElement
* @param string $sTagName
* @param string|null $sDefault
*
* @return null|string
* @return string
* @throws \DOMFormatException
*/
public function GetChildText($sTagName, $sDefault = null): ?string
public function GetChildText($sTagName, $sDefault = null)
{
$sRet = $sDefault;
if ($oChild = $this->GetOptionalElement($sTagName)) {
@@ -453,7 +453,7 @@ class DesignElement extends \DOMElement
* @throws Exception
* @since 3.1.2 3.2.0 N°6974
*/
public static function _FindNode(DOMNode $oParent, DesignElement $oRefNode, ?string $sSearchId = null): ?DesignElement
public static function _FindNode(DOMNode $oParent, DesignElement $oRefNode, string $sSearchId = null): ?DesignElement
{
$oNodes = self::_FindNodes($oParent, $oRefNode, $sSearchId);
if ($oNodes instanceof DOMNodeList) {
@@ -477,7 +477,7 @@ class DesignElement extends \DOMElement
* @return \DOMNodeList|false|mixed
* @since 3.1.2 3.2.0 N°6974
*/
public static function _FindNodes(DOMNode $oParent, DesignElement $oRefNode, ?string $sSearchId = null)
public static function _FindNodes(DOMNode $oParent, DesignElement $oRefNode, string $sSearchId = null)
{
if ($oParent instanceof DOMDocument) {
$oDoc = $oParent->firstChild->ownerDocument;

View File

@@ -632,7 +632,7 @@ class DisplayableGroupNode extends DisplayableNode
$this->aObjects = [];
}
public function AddObject(?DBObject $oObj = null)
public function AddObject(DBObject $oObj = null)
{
if (is_object($oObj)) {
$sPrevClass = $this->GetObjectClass();

View File

@@ -26,7 +26,7 @@ class Event extends DBObject implements iDisplay
{
$aParams =
[
"category" => "core/cmdb,grant_by_profile,silo",
"category" => "core/cmdb,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
@@ -120,7 +120,7 @@ class EventNotification extends Event
{
$aParams =
[
"category" => "core/cmdb,grant_by_profile,silo",
"category" => "core/cmdb,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
@@ -156,7 +156,7 @@ class EventNotificationEmail extends EventNotification
{
$aParams =
[
"category" => "core/cmdb,grant_by_profile,silo",
"category" => "core/cmdb,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
@@ -192,7 +192,7 @@ class EventIssue extends Event
{
$aParams =
[
"category" => "core/cmdb,grant_by_profile,silo",
"category" => "core/cmdb,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
@@ -286,7 +286,7 @@ class EventWebService extends Event
{
$aParams =
[
"category" => "core/cmdb,grant_by_profile,silo",
"category" => "core/cmdb,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
@@ -321,7 +321,7 @@ class EventRestService extends Event
{
$aParams =
[
"category" => "core/cmdb,grant_by_profile,silo",
"category" => "core/cmdb,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
@@ -356,7 +356,7 @@ class EventLoginUsage extends Event
{
$aParams =
[
"category" => "core/cmdb,grant_by_profile,silo",
"category" => "core/cmdb,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",
@@ -394,7 +394,7 @@ class EventOnObject extends Event
{
$aParams =
[
"category" => "core/cmdb,grant_by_profile,silo",
"category" => "core/cmdb,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "",
"state_attcode" => "",

View File

@@ -5,13 +5,13 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Application\Helper\ExportHelper;
use Combodo\iTop\Application\UI\Base\Component\FieldSet\FieldSetUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\ColumnUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactory;
use Combodo\iTop\Application\Helper\ExportHelper;
use Combodo\iTop\Application\WebPage\Page;
use Combodo\iTop\Application\WebPage\WebPage;
@@ -63,8 +63,6 @@ class ExcelBulkExport extends TabularBulkExport
// Export from the command line (or scripted) => default format is SQL, as in previous versions of iTop, unless specified otherwise
$this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetSQLFormat(), true, 'raw_data');
}
$this->aStatusInfo['ignore_excel_sanitization'] = (bool)utils::ReadParam('ignore_excel_sanitization', 0, true, utils::ENUM_SANITIZATION_FILTER_INTEGER);
}
public function EnumFormParts()
@@ -123,10 +121,6 @@ class ExcelBulkExport extends TabularBulkExport
$oRadioCustom->GetInput()->AddCSSClass('ibo-input-checkbox');
$oFieldSetDate->AddSubBlock($oRadioCustom);
$oFieldSetSecurity = FieldSetUIBlockFactory::MakeStandard(Dict::S('Core:BulkExport:Security'));
$oMulticolumn->AddColumn(ColumnUIBlockFactory::MakeForBlock($oFieldSetSecurity));
$oFieldSetSecurity->AddSubBlock(ExportHelper::GetInputForSanitizeExcelExport());
$oP->add_ready_script(
<<<EOF
$('#form_part_xlsx_options').on('preview_updated', function() { FormatDatesInPreview('excel', 'xlsx'); });
@@ -222,12 +216,6 @@ EOF
}
}
}
// If the option to ignore Excel sanitization is not set or absent, sanitize the field
if (!(array_key_exists('ignore_excel_sanitization', $this->aStatusInfo)) || $this->aStatusInfo['ignore_excel_sanitization'] === false) {
return ExportHelper::SanitizeField($sRet, '');
}
return $sRet;
}

View File

@@ -259,18 +259,13 @@ class InlineImage extends DBObject
* that refer to an InlineImage (detected via the attribute data-img-id="") so that
* the URL is consistent with the current URL of the application.
*
N°8681 * @param string|null $sHtml The HTML fragment to process
* @param string $sHtml The HTML fragment to process
*
* @return string The modified HTML
* @throws \Exception
*
* @since 3.3.0 N°8681 Add type hint for parameters and return value
*/
public static function FixUrls(string|null $sHtml): string
public static function FixUrls($sHtml)
{
// N°8681 - Ensure to have a string value
$sHtml = $sHtml ?? '';
$aNeedles = [];
$aReplacements = [];
// Find img tags with an attribute data-img-id
@@ -298,46 +293,6 @@ N°8681 * @param string|null $sHtml The HTML fragment to process
return $sHtml;
}
/**
* Replace <img> tags with a data-img-id attribute by the actual image in base64 representation
* so that the image can be displayed even if the download URL is not accessible (e.g. in unauthenticated approval templates)
*
* @param string $sHtml The HTML fragment to process
*
* @return String The modified HTML
* @since 3.2.3
*/
public static function ReplaceInlineImagesWithBase64Representation(string $sHtml): String
{
return preg_replace_callback(
'/<img\s+[^>]*'.static::DOM_ATTR_ID.'="(\d+)"[^>]*>/i',
function ($matches) {
// Extract inline image ID from the tag
$id = $matches[1];
try {
// Retrieve inline image
$oInline = MetaModel::GetObject(InlineImage::class, $id, true, true);
$oOrmDocument = $oInline->Get('contents');
// Replace src image by the base64 representation
$sInlineImageAsBase64 = base64_encode($oOrmDocument->GetData());
$sDataUri = 'data:'.$oOrmDocument->GetMimeType().';base64,'.$sInlineImageAsBase64;
$sImage = preg_replace('/src=["\'][^"\']+["\']/', 'src="'.$sDataUri.'"', $matches[0]);
// Remove sensitive information (the image ID and secret) from the tag
$sImage = preg_replace('/'.static::DOM_ATTR_ID.'="\d+"\s+'.static::DOM_ATTR_SECRET.'="\w+"/', '', $sImage);
} catch (Exception $e) {
$sImage = '<img src="" alt="'.Dict::S('UI:MissingInlineImage').'">';
}
return $sImage;
},
$sHtml
);
}
/**
* Add an extra attribute data-img-id for images which are based on an actual InlineImage
* so that we can later reconstruct the full "src" URL when needed
@@ -434,7 +389,7 @@ 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 since 3.3.0 Replaced by ormDocument::ResizeImageToFit
* @deprecated Replaced by ormDocument::ResizeImageToFit
*/
public static function ResizeImageToFit(ormDocument $oImage, &$aDimensions = null)
{

View File

@@ -1,20 +1,18 @@
<?php
/**
* @copyright Copyright (C) 2010-2026 Combodo SAS
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Application\EventRegister\ApplicationEvents;
use Combodo\iTop\Core\Kpi\KpiLogData;
use Combodo\iTop\Service\Events\EventService;
use Combodo\iTop\Service\Events\iEventServiceSetup;
use Combodo\iTop\Service\Module\ModuleService;
/**
* Measures operations duration, memory usage, etc. (and some other KPIs)
*/
class ExecutionKPI implements iEventServiceSetup
class ExecutionKPI
{
protected static $m_bEnabled_Duration = false;
protected static $m_bEnabled_Memory = false;
@@ -25,18 +23,15 @@ class ExecutionKPI implements iEventServiceSetup
protected static $m_aStats = []; // Recurrent operations
protected static $m_aExecData = []; // One shot operations
/** @var true */
private static bool $bMetamodelStarted = false;
/**
* @var array[ExecutionKPI]
*/
protected static $m_aExecutionStack = []; // embedded execution stats
private static ?float $fLastReportTime = null;
private static ?float $iLastReportMemory = null;
// For stats
protected $m_fStarted = null;
protected $m_fChildrenDuration = 0; // Count embedded
protected $m_iInitialMemory = null;
private static array $aBootstrapOperations = [];
public static function EnableDuration($iLevel)
{
if ($iLevel > 0) {
@@ -76,7 +71,6 @@ class ExecutionKPI implements iEventServiceSetup
return true;
}
}
return false;
}
@@ -103,7 +97,7 @@ class ExecutionKPI implements iEventServiceSetup
$sFor = self::$m_sAllowedUser == '*' ? 'EVERYBODY' : "'".trim(self::$m_sAllowedUser)."'";
$sSlowQueries = '';
if (self::$m_fSlowQueries > 0) {
$sSlowQueries = '. Slow Queries: '.self::$m_fSlowQueries.'s';
$sSlowQueries = ". Slow Queries: ".self::$m_fSlowQueries."s";
}
$aExtensions = [];
@@ -133,7 +127,7 @@ class ExecutionKPI implements iEventServiceSetup
$sRequest .= ' operation: '.$_POST['operation'];
}
$fStop = microtime(true);
$fStop = MyHelpers::getmicrotime();
if (($fStop - $fItopStarted) > self::$m_fSlowQueries) {
// Invoke extensions to log the KPI operation
/** @var \iKPILoggerExtension $oExtensionInstance */
@@ -157,17 +151,17 @@ class ExecutionKPI implements iEventServiceSetup
$sTableStyle = 'background-color: #ccc; margin: 10px;';
$sHtml = '<hr/>';
$sHtml = "<hr/>";
$sHtml .= "<div style=\"background-color: grey; padding: 10px;\">";
$sHtml .= "<h3><a name=\"".md5($sExecId)."\">KPIs</a> - $sRequest</h3>";
$oStarted = DateTime::createFromFormat('U.u', $fItopStarted);
$sHtml .= '<p>'.$oStarted->format('Y-m-d H:i:s.u').'</p>';
$sHtml .= '<p>log_kpi_user_id: '.UserRights::GetUserId().'</p>';
$sHtml .= '<div>';
$sHtml .= "<p>log_kpi_user_id: ".UserRights::GetUserId()."</p>";
$sHtml .= "<div>";
$sHtml .= "<table border=\"1\" style=\"$sTableStyle\">";
$sHtml .= '<thead>';
$sHtml .= ' <th>Operation</th><th>Begin</th><th>End</th><th>Duration</th><th>Memory start</th><th>Memory end</th><th>Memory peak</th>';
$sHtml .= '</thead>';
$sHtml .= "<thead>";
$sHtml .= " <th>Operation</th><th>Begin</th><th>End</th><th>Duration</th><th>Memory start</th><th>Memory end</th><th>Memory peak</th>";
$sHtml .= "</thead>";
foreach (self::$m_aExecData as $aOpStats) {
$sOperation = $aOpStats['op'];
$sBegin = round($aOpStats['time_begin'], 3);
@@ -186,12 +180,12 @@ class ExecutionKPI implements iEventServiceSetup
}
}
$sHtml .= '<tr>';
$sHtml .= "<tr>";
$sHtml .= " <td>$sOperation</td><td>$sBegin</td><td>$sEnd</td><td>$sDuration</td><td>$sMemBegin</td><td>$sMemEnd</td><td>$sMemPeak</td>";
$sHtml .= '</tr>';
$sHtml .= "</tr>";
}
$sHtml .= '</table>';
$sHtml .= '</div>';
$sHtml .= "</table>";
$sHtml .= "</div>";
$aConsolidatedStats = [];
foreach (self::$m_aStats as $sOperation => $aOpStats) {
@@ -214,20 +208,20 @@ class ExecutionKPI implements iEventServiceSetup
}
}
$aConsolidatedStats[$sOperation] = [
'count' => $iTotalOp,
'count' => $iTotalOp,
'duration' => $fTotalOp,
'min' => $fMinOp,
'max' => $fMaxOp,
'avg' => $fTotalOp / $iTotalOp,
'min' => $fMinOp,
'max' => $fMaxOp,
'avg' => $fTotalOp / $iTotalOp,
'max_args' => $sMaxOpArguments,
];
}
$sHtml .= '<div>';
$sHtml .= "<div>";
$sHtml .= "<table border=\"1\" style=\"$sTableStyle\">";
$sHtml .= '<thead>';
$sHtml .= ' <th>Operation</th><th>Count</th><th>Duration</th><th>Min</th><th>Max</th><th>Avg</th>';
$sHtml .= '</thead>';
$sHtml .= "<thead>";
$sHtml .= " <th>Operation</th><th>Count</th><th>Duration</th><th>Min</th><th>Max</th><th>Avg</th>";
$sHtml .= "</thead>";
foreach ($aConsolidatedStats as $sOperation => $aOpStats) {
$sOperation = '<a href="#'.md5($sExecId.$sOperation).'">'.$sOperation.'</a>';
$sCount = $aOpStats['count'];
@@ -236,14 +230,14 @@ class ExecutionKPI implements iEventServiceSetup
$sMax = '<a href="#'.md5($sExecId.$aOpStats['max_args']).'">'.round($aOpStats['max'], 3).'</a>';
$sAvg = round($aOpStats['avg'], 3);
$sHtml .= '<tr>';
$sHtml .= "<tr>";
$sHtml .= " <td>$sOperation</td><td>$sCount</td><td>$sDuration</td><td>$sMin</td><td>$sMax</td><td>$sAvg</td>";
$sHtml .= '</tr>';
$sHtml .= "</tr>";
}
$sHtml .= '</table>';
$sHtml .= '</div>';
$sHtml .= "</table>";
$sHtml .= "</div>";
$sHtml .= '</div>';
$sHtml .= "</div>";
$sHtml .= "<p><a href=\"#end-".md5($sExecId)."\">Next page stats</a></p>";
@@ -293,18 +287,18 @@ class ExecutionKPI implements iEventServiceSetup
$sOperationHtml = '<a name="'.md5($sExecId.$sOperation).'">'.$sOperation.'</a>';
$sHtml .= "<h4>$sOperationHtml</h4>";
$sHtml .= "<table border=\"1\" style=\"$sTableStyle\">";
$sHtml .= '<thead>';
$sHtml .= ' <th>Operation details (+ blame caller if log_kpi_duration = 2)</th><th>Count</th><th>Duration</th><th>Min</th><th>Max</th>';
$sHtml .= '</thead>';
$sHtml .= "<thead>";
$sHtml .= " <th>Operation details (+ blame caller if log_kpi_duration = 2)</th><th>Count</th><th>Duration</th><th>Min</th><th>Max</th>";
$sHtml .= "</thead>";
$bDisplayHeader = false;
}
$sHtml .= '<tr>';
$sHtml .= "<tr>";
$sHtml .= " <td>$sHtmlArguments</td><td>$iCountInter</td><td>$sTotalInter</td><td>$sMinInter</td><td>$sMaxInter</td>";
$sHtml .= '</tr>';
$sHtml .= "</tr>";
}
}
if (!$bDisplayHeader) {
$sHtml .= '</table>';
$sHtml .= "</table>";
$sHtml .= "<p><a href=\"#".md5($sExecId)."\">Back to page stats</a></p>";
}
self::Report($sHtml);
@@ -339,50 +333,39 @@ class ExecutionKPI implements iEventServiceSetup
$aNewEntry = null;
if (is_null(static::$fLastReportTime)) {
static::$fLastReportTime = $fItopStarted;
}
if (is_null(static::$iLastReportMemory)) {
global $iItopInitialMemory;
static::$iLastReportMemory = $iItopInitialMemory;
}
$fStarted = static::$fLastReportTime;
$fStopped = microtime(true);
$fStarted = $this->m_fStarted;
$fStopped = $this->m_fStarted;
if (self::$m_bEnabled_Duration) {
$fStopped = MyHelpers::getmicrotime();
$aNewEntry = [
'op' => $sOperationDesc,
'time_begin' => $fStarted - $fItopStarted,
'time_begin' => $this->m_fStarted - $fItopStarted,
'time_end' => $fStopped - $fItopStarted,
];
// Reset for the next operation (if the object is recycled)
$this->m_fStarted = $fStopped;
}
static::$fLastReportTime = $fStopped;
$iInitialMemory = static::$iLastReportMemory;
$iCurrentMemory = $iInitialMemory;
$iPeakMemory = $iInitialMemory;
$iInitialMemory = is_null($this->m_iInitialMemory) ? 0 : $this->m_iInitialMemory;
$iCurrentMemory = 0;
$iPeakMemory = 0;
if (self::$m_bEnabled_Memory) {
$iCurrentMemory = self::memory_get_usage();
if (is_null($aNewEntry)) {
$aNewEntry = ['op' => $sOperationDesc];
}
$aNewEntry['mem_begin'] = $iInitialMemory;
$aNewEntry['mem_begin'] = $this->m_iInitialMemory;
$aNewEntry['mem_end'] = $iCurrentMemory;
$iPeakMemory = self::memory_get_peak_usage();
$aNewEntry['mem_peak'] = $iPeakMemory;
// Reset for the next operation (if the object is recycled)
static::$iLastReportMemory = $iCurrentMemory;
$this->m_iInitialMemory = $iCurrentMemory;
}
if (self::$m_bEnabled_Duration || self::$m_bEnabled_Memory) {
$aCallstack = ['callstack' => $this->GetCallStack()];
if (static::$bMetamodelStarted) {
foreach (static::$aBootstrapOperations as $oLog) {
$this->LogOperation($oLog);
}
static::$aBootstrapOperations = [];
// Invoke extensions to log the KPI operation
// Invoke extensions to log the KPI operation
/** @var \iKPILoggerExtension $oExtensionInstance */
foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) {
$sExtension = ModuleService::GetInstance()->GetModuleNameFromCallStack(1);
$oKPILogData = new KpiLogData(
KpiLogData::TYPE_REPORT,
@@ -393,24 +376,9 @@ class ExecutionKPI implements iEventServiceSetup
$sExtension,
$iInitialMemory,
$iCurrentMemory,
$iPeakMemory,
$aCallstack
$iPeakMemory
);
$this->LogOperation($oKPILogData);
} else {
$oKPILogData = new KpiLogData(
KpiLogData::TYPE_REPORT,
'Step',
$sOperationDesc,
$fStarted,
$fStopped,
'',
$iInitialMemory,
$iCurrentMemory,
$iPeakMemory,
$aCallstack
);
static::$aBootstrapOperations[] = $oKPILogData;
$oExtensionInstance->LogOperation($oKPILogData);
}
}
@@ -420,21 +388,13 @@ class ExecutionKPI implements iEventServiceSetup
$this->ResetCounters();
}
private function LogOperation(KpiLogData $oKPILogData): void
{
/** @var \iKPILoggerExtension $oExtensionInstance */
foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) {
$oExtensionInstance->LogOperation($oKPILogData);
}
}
/**
* Compute statistics for a call to an extension
* Note: not working in dev mode (with links to env-production)
*
* @param object|string $object object called
* @param string $sMethod method called on the object
* @param string $sMessage additional message
* @param string $sMethod method called on the object
* @param string $sMessage additional message
*
* @return bool true if an extension was found for this object::method
* @throws \ReflectionException
@@ -463,23 +423,21 @@ class ExecutionKPI implements iEventServiceSetup
$fDuration = 0;
if (self::$m_bEnabled_Duration) {
$fStopped = microtime(true);
$fStopped = MyHelpers::getmicrotime();
$fDuration = $fStopped - $this->m_fStarted;
$aCallstack = [];
if (self::$m_bGenerateLegacyReport) {
if (self::$m_bBlameCaller) {
$aCallstack = MyHelpers::get_callstack(1);
self::$m_aStats[$sOperation][$sArguments][] = [
'time' => $fDuration,
'callers' => $aCallstack,
'time' => $fDuration,
'callers' => $aCallstack,
];
} else {
self::$m_aStats[$sOperation][$sArguments][] = [
'time' => $fDuration,
'time' => $fDuration,
];
}
} else {
$aCallstack = ['callstack' => $this->GetCallStack()];
}
$iInitialMemory = is_null($this->m_iInitialMemory) ? 0 : $this->m_iInitialMemory;
@@ -490,45 +448,33 @@ class ExecutionKPI implements iEventServiceSetup
$iPeakMemory = self::memory_get_peak_usage();
}
if (static::$bMetamodelStarted) {
foreach (static::$aBootstrapOperations as $oLog) {
$this->LogOperation($oLog);
}
static::$aBootstrapOperations = [];
// Invoke extensions to log the KPI operation
/** @var \iKPILoggerExtension $oExtensionInstance */
foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) {
//$sExtension = ModuleService::GetInstance()->GetModuleNameFromCallStack(1);
$sExtension = '';
$oKPILogData = new KpiLogData(
KpiLogData::TYPE_STATS,
$sOperation,
$sArguments,
$this->m_fStarted,
$fStopped,
'',
$sExtension,
$iInitialMemory,
$iCurrentMemory,
$iPeakMemory,
$aCallstack
);
$this->LogOperation($oKPILogData);
} else {
$oKPILogData = new KpiLogData(
KpiLogData::TYPE_STATS,
$sOperation,
$sArguments,
$this->m_fStarted,
$fStopped,
'',
$iInitialMemory,
$iCurrentMemory,
$iPeakMemory,
$aCallstack
);
static::$aBootstrapOperations[] = $oKPILogData;
$oExtensionInstance->LogOperation($oKPILogData);
}
}
}
protected function ResetCounters()
{
$this->m_fStarted = microtime(true);
if (self::$m_bEnabled_Duration) {
$this->m_fStarted = microtime(true);
}
if (self::$m_bEnabled_Memory) {
$this->m_iInitialMemory = self::memory_get_usage();
@@ -557,33 +503,7 @@ class ExecutionKPI implements iEventServiceSetup
if (function_exists('memory_get_peak_usage')) {
return memory_get_peak_usage($bRealUsage);
}
// PHP > 5.2.1 - this verb depends on a compilation option
return 0;
}
/*
* ModuleHandlerApiInterface methods
*/
public static function OnMetaModelStarted()
{
static::$bMetamodelStarted = true;
}
public function RegisterEventsAndListeners()
{
EventService::RegisterListener(ApplicationEvents::APPLICATION_EVENT_METAMODEL_STARTED, [$this, 'OnMetaModelStarted']);
}
private function GetCallStack(): string
{
$aCallStack = MyHelpers::get_callstack(2);
$sCallStack = "Call stack:\n";
foreach ($aCallStack as $index => $aLine) {
$sCallStack .= "#$index ".$aLine['File'].'('.$aLine['Line'].'): '.$aLine['Function']."\n";
}
return $sCallStack;
}
}

View File

@@ -691,26 +691,11 @@ abstract class LogAPI
static::$m_oMockMetaModelConfig = $oMetaModelConfig;
}
public static function Exception(string $sMessage, throwable $oException, ?string $sChannel = null, array $aContext = []): void
public static function Exception(string $sMessage, throwable $previous, string $sChannel = null, array $aContext = []): void
{
$aErrorLogs = [];
$aErrorLogs[] = static::PrepareErrorLog($sMessage, $oException, $aContext);
$oException = $oException->getPrevious();
while ($oException !== null) {
$aErrorLogs[] = static::PrepareErrorLog($oException->getMessage(), $oException, $aContext, true);
$oException = $oException->getPrevious();
}
$aErrorLogs = array_reverse($aErrorLogs);
foreach ($aErrorLogs as $aErrorLog) {
static::Error($aErrorLog['message'], $sChannel, $aErrorLog['context']);
}
}
private static function PrepareErrorLog(string $sMessage, throwable $oException, array $aContext, bool $isPrevious = false): array
{
$aContext['Error Message'] = $oException->getMessage();
$aContext['Stack Trace'] = $oException->getTraceAsString();
return ['message' => ($isPrevious ? "Previous " : '')."Exception: $sMessage", 'context' => $aContext];
$aContext['Error Message'] = $previous->getMessage();
$aContext['Stack Trace'] = $previous->getTraceAsString();
static::Error($sMessage, $sChannel, $aContext);
}
public static function Error($sMessage, $sChannel = null, $aContext = [])

View File

@@ -22,8 +22,6 @@ use Combodo\iTop\Application\EventRegister\ApplicationEvents;
use Combodo\iTop\Core\MetaModel\FriendlyNameType;
use Combodo\iTop\Service\Events\EventData;
use Combodo\iTop\Service\Events\EventService;
use Combodo\iTop\Setup\ModuleDependency\Module;
use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReader;
require_once APPROOT.'core/modulehandler.class.inc.php';
require_once APPROOT.'core/querymodifier.class.inc.php';
@@ -130,7 +128,7 @@ abstract class MetaModel
/** @var array */
private static $m_aClassToFile = [];
/** @var string */
protected static $m_sEnvironment = ITOP_DEFAULT_ENV;
protected static $m_sEnvironment = 'production';
/**
* Objects currently created/updated.
@@ -464,43 +462,6 @@ abstract class MetaModel
return call_user_func([$sClass, 'GetClassDescription'], $sClass);
}
/**
* @param string $sClass
*
* @return string
* @throws \CoreException
*/
final public static function GetModuleName($sClass)
{
try {
$oReflectionClass = new ReflectionClass($sClass);
$sDir = realpath(dirname($oReflectionClass->getFileName()));
$sApproot = realpath(APPROOT);
while (($sDir !== $sApproot) && (str_contains($sDir, $sApproot))) {
$aFiles = glob("$sDir/module.*.php");
if (count($aFiles) > 1) {
return 'core';
}
if (count($aFiles) == 0) {
$sDir = realpath(dirname($sDir));
continue;
}
$sModuleFilePath = $aFiles[0];
$aModuleInfo = ModuleFileReader::GetInstance()->ReadModuleFileInformation($sModuleFilePath);
$sModuleId = $aModuleInfo[ModuleFileReader::MODULE_INFO_ID];
list($sModuleName, ) = ModuleDiscovery::GetModuleName($sModuleId);
return $sModuleName;
}
} catch (\Exception $e) {
throw new CoreException("Cannot find class module", ['class' => $sClass], '', $e);
}
return 'core';
}
/**
* @param string $sClass
*
@@ -5748,7 +5709,7 @@ abstract class MetaModel
* @throws \DictExceptionUnknownLanguage
* @throws \Exception
*/
public static function Startup($config, $bModelOnly = false, $bAllowCache = true, $bTraceSourceFiles = false, $sEnvironment = ITOP_DEFAULT_ENV)
public static function Startup($config, $bModelOnly = false, $bAllowCache = true, $bTraceSourceFiles = false, $sEnvironment = 'production')
{
// Startup on a new environment is not supported
static $bStarted = false;

View File

@@ -55,11 +55,6 @@ abstract class ModelReflection
abstract public function GetFiltersList($sClass);
abstract public function IsValidFilterCode($sClass, $sFilterCode);
/**
* @since 3.3.0
*/
abstract public function IsAbstract($sClass): bool;
/**
* @param string $sOQL
*
@@ -235,11 +230,6 @@ class ModelReflectionRuntime extends ModelReflection
return MetaModel::IsValidFilterCode($sClass, $sFilterCode);
}
public function IsAbstract($sClass): bool
{
return MetaModel::IsAbstract($sClass);
}
public function GetQuery($sOQL)
{
return new QueryReflectionRuntime($sOQL, $this);

View File

@@ -1656,7 +1656,7 @@ class PHP_ParserGenerator_Data
function emit_code($out, PHP_ParserGenerator_Rule $rp, &$lineno)
{
$linecnt = 0;
/* Generate code to do the reduce action */
if ($rp->code) {
$this->tplt_linedir($out, $rp->line, $this->filename);

View File

@@ -1084,7 +1084,7 @@ static public $yy_action = array(
function yy_find_shift_action($iLookAhead)
{
$stateno = $this->yystack[$this->yyidx]->stateno;
/* if ($this->yyidx < 0) return self::YY_NO_ACTION; */
if (!isset(self::$yy_shift_ofst[$stateno])) {
// no shift actions
@@ -1767,7 +1767,7 @@ throw new OQLParserParseFailureException($this->m_sSourceQuery, $this->m_iLine,
function yy_syntax_error($yymajor, $TOKEN)
{
#line 25 "..\oql-parser.y"
throw new OQLParserSyntaxErrorException($this->m_sSourceQuery, $this->m_iLine, $this->m_iCol, $this->tokenName($yymajor), $TOKEN);
#line 1779 "..\oql-parser.php"
}
@@ -1806,7 +1806,7 @@ throw new OQLParserSyntaxErrorException($this->m_sSourceQuery, $this->m_iLine, $
// $yyact; /* The parser action. */
// $yyendofinput; /* True if we are at the end of input */
$yyerrorhit = 0; /* True if yymajor has invoked an error */
/* (re)initialize the parser, if necessary */
if ($this->yyidx === null || $this->yyidx < 0) {
/* if ($yymajor == 0) return; // not sure why this was here... */
@@ -1819,7 +1819,7 @@ throw new OQLParserSyntaxErrorException($this->m_sSourceQuery, $this->m_iLine, $
array_push($this->yystack, $x);
}
$yyendofinput = ($yymajor==0);
if (self::$yyTraceFILE) {
fprintf(
self::$yyTraceFILE,
@@ -1828,7 +1828,7 @@ throw new OQLParserSyntaxErrorException($this->m_sSourceQuery, $this->m_iLine, $
self::$yyTokenName[$yymajor]
);
}
do {
$yyact = $this->yy_find_shift_action($yymajor);
if ($yymajor < self::YYERRORSYMBOL
@@ -2002,7 +2002,7 @@ class OQLParser extends OQLParserRaw
$this->m_sSourceQuery = $sQuery;
// no constructor - parent::__construct();
}
public function doParse($token, $value, $iCurrPosition = 0)
{
$this->m_iColPrev = $this->m_iCol;
@@ -2016,7 +2016,7 @@ class OQLParser extends OQLParserRaw
$this->doParse(0, 0);
return $this->my_result;
}
public function __destruct()
{
// Bug in the original destructor, causing an infinite loop !

View File

@@ -72,15 +72,9 @@ class OQLException extends CoreException
}
else
{
$sMessage = "$sIssue - found '{$this->m_sUnexpected}' at $iCol in '$sInput'";
if (count($this->m_aExpecting) < 30) {
$sExpectations = '{'.implode(', ', $this->m_aExpecting).'}';
$sMessage .= ', expecting '.json_encode($sExpectations);
}
$sExpectations = '{'.implode(', ', $this->m_aExpecting).'}';
$sSuggest = self::FindClosestString($this->m_sUnexpected, $this->m_aExpecting);
if (strlen($sSuggest) > 0) {
$sMessage .= ", I would suggest to use ".json_encode($sSuggest);
}
$sMessage = "$sIssue - found '{$this->m_sUnexpected}' at $iCol in '$sInput', expecting $sExpectations, I would suggest to use '$sSuggest'";
}
// make sure everything is assigned properly
@@ -161,3 +155,5 @@ class OQLException extends CoreException
return $sRet;
}
}
?>

View File

@@ -370,7 +370,7 @@ class ormCaseLog
/**
* Produces an HTML representation, aimed at being used within the iTop framework
*/
public function GetAsHTML(?WebPage $oP = null, $bEditMode = false, $aTransfoHandler = null)
public function GetAsHTML(WebPage $oP = null, $bEditMode = false, $aTransfoHandler = null)
{
$bPrintableVersion = (utils::ReadParam('printable', '0') == '1');

View File

@@ -350,22 +350,20 @@ class ormDocument
if (!is_object($oObj)) {
// If access to the document is not granted, check if the access to the host object is allowed
$oObj = MetaModel::GetObject($sClass, $id, false, true);
$bHasHostRights = false;
if ($oObj instanceof Attachment) {
$sItemClass = $oObj->Get('item_class');
$sItemId = $oObj->Get('item_id');
$oHost = MetaModel::GetObject($sItemClass, $sItemId, false, false);
if (is_object($oHost)) {
$bHasHostRights = true;
if (!is_object($oHost)) {
$oObj = null;
}
}
// We could neither read the object nor get a host object matching our rights
if ($bHasHostRights !== true) {
if (!is_object($oObj)) {
throw new Exception("Invalid id ($id) for class '$sClass' - the object does not exist or you are not allowed to view it");
}
}
if (($sSecretField != null) && !hash_equals($oObj->Get($sSecretField), $sSecretValue)) {
if (($sSecretField != null) && ($oObj->Get($sSecretField) != $sSecretValue)) {
usleep(200);
throw new Exception("Invalid secret for class '$sClass' - the object does not exist or you are not allowed to view it");
}
/** @var \ormDocument $oDocument */

View File

@@ -93,7 +93,7 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
* @param DBObjectSet|null $oOriginalSet
* @throws Exception
*/
public function __construct($sHostClass, $sAttCode, ?DBObjectSet $oOriginalSet = null)
public function __construct($sHostClass, $sAttCode, DBObjectSet $oOriginalSet = null)
{
$this->sHostClass = $sHostClass;
$this->sAttCode = $sAttCode;
@@ -470,6 +470,17 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|| ($this->oOriginalSet->GetFilter()->ToOQL() == $oFellow->oOriginalSet->GetFilter()->ToOQL())) {
$bUpdateFromDelta = true;
}
} else {
//@since 3.2.2 N°2364 - API : remove old linkedset persistance
/* Goo pattern to use:
* $oCISet = $oTicket->Get(functioncis_list);
* $oCISet->AddItem(MetaModel::NewObject(lnkFunctionCIToTicket, array(ci_id=> 12345));
* $oCISet->RemoveItem(123456);
* $oTicket->Set(functionalcis_list, $oCISet);
*/
if (!ContextTag::Check(ContextTag::TAG_SETUP)) {
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('old pattern - please get previous value of the linked set, modify it and set it back to the host object');
}
}
if ($bUpdateFromDelta) {

View File

@@ -98,9 +98,9 @@ class ormPassword
$bResult = false;
$aInfo = password_get_info($this->m_sHashed);
if (is_null($aInfo["algo"]) || $aInfo["algo"] === 0) {
// - Unknown algorithm, assume it's a legacy password
//unknown, assume it's a legacy password
$sHashedPwd = $this->ComputeHash($sClearTextPassword);
$bResult = hash_equals($this->m_sHashed, $sHashedPwd);
$bResult = ($this->m_sHashed == $sHashedPwd);
} else {
$bResult = password_verify($sClearTextPassword, $this->m_sHashed);
}

View File

@@ -415,7 +415,12 @@ abstract class User extends cmdbAbstractObject
$this->m_aCheckIssues[] = Dict::S('Class:User/Error:CurrentProfilesHaveInsufficientRights');
}
$oAddon->ResetCache();
Session::Set('profile_list', $aCurrentProfiles);
if (is_null($aCurrentProfiles)) {
Session::IsSet('profile_list');
} else {
Session::Set('profile_list', $aCurrentProfiles);
}
}
// Prevent an administrator to remove their own admin profile
if (UserRights::IsAdministrator($this)) {

View File

@@ -4,4 +4,3 @@
*/
@import "bulk-modify";
@import "bulk-export";

View File

@@ -1,10 +0,0 @@
/*
* @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
#form_part_csv_options:has(#ibo-sanitize-excel-export--input:checked), #form_part_xlsx_options:has(#ibo-sanitize-excel-export--input:checked){
#ibo-sanitize-excel-export--alert {
display: none;
}
}

View File

@@ -22,6 +22,4 @@
@import "medallion-with-blocklist";
@import "field-badge-within-datatable";
@import "jquery-blockui-within-dialog";
@import "jquery-blockui-within-datatable";
@import "badge-with-badge";
@import "extension-details-with-extension-details";
@import "jquery-blockui-within-datatable";

View File

@@ -1,10 +0,0 @@
/*
* @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
$ibo-badge--spacing-left--with-same-block: $ibo-spacing-200 !default;
.ibo-badge + .ibo-badge {
margin-left: $ibo-badge--spacing-left--with-same-block;
}

View File

@@ -1,11 +0,0 @@
/*
* @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
$ibo-extension-details--margin-top: $ibo-spacing-300 !default;
.ibo-extension-details + .ibo-extension-details,
.ibo-extension-details--information--description .ibo-extension-details {
margin-top: $ibo-extension-details--margin-top;
}

View File

@@ -4,7 +4,7 @@
*/
$ibo-field--spacing-top--with-same-block: $ibo-spacing-500 !default;
.ibo-field + .ibo-field:not(:empty) {
.ibo-field + .ibo-field {
margin-top: $ibo-field--spacing-top--with-same-block;
}

View File

@@ -33,5 +33,4 @@
@import "field-badge";
@import "file-select";
@import "medallion-icon";
@import "toast";
@import "badge";
@import "toast";

View File

@@ -1,41 +0,0 @@
$ibo-badge--padding-x : $ibo-spacing-200 !default;
$ibo-badge--padding-y : $ibo-spacing-100 !default;
$ibo-badge--border-radius : $ibo-border-radius-400 !default;
$ibo-badge-colors: (
'primary': ($ibo-color-primary-100, $ibo-color-primary-900),
'secondary': ($ibo-color-secondary-100, $ibo-color-secondary-900),
'neutral': ($ibo-color-secondary-100, $ibo-color-secondary-900),
'information': ($ibo-color-information-100, $ibo-color-information-900),
'success': ($ibo-color-success-100, $ibo-color-success-900),
'failure': ($ibo-color-danger-100, $ibo-color-danger-900),
'warning': ($ibo-color-warning-100,$ibo-color-warning-900),
'danger': ($ibo-color-danger-100,$ibo-color-danger-900),
'grey' : ($ibo-color-grey-100, $ibo-color-grey-900),
'blue-grey': ($ibo-color-blue-grey-100, $ibo-color-blue-grey-900),
'blue': ($ibo-color-blue-100, $ibo-color-blue-900),
'cyan': ($ibo-color-cyan-100, $ibo-color-cyan-900),
'green': ($ibo-color-green-100, $ibo-color-green-900),
'orange' : ($ibo-color-orange-100, $ibo-color-orange-900),
'red': ($ibo-color-red-100, $ibo-color-red-900),
'pink': ($ibo-color-pink-100, $ibo-color-pink-900),
) !default;
.ibo-badge {
display: inline-block;
white-space: nowrap;
padding : $ibo-badge--padding-y $ibo-badge--padding-x;
border-radius : $ibo-badge--border-radius;
@extend %ibo-font-ral-med-50;
@each $sColor, $aColorValues in $ibo-badge-colors {
$bg-color: nth($aColorValues, 1);
$text-color: nth($aColorValues, 2);
&.ibo-is-#{$sColor} {
background-color: $bg-color;
color: $text-color;
}
}
}

View File

@@ -47,31 +47,10 @@
align-items: center;
}
.turbo-refreshing{
.form[aria-busy="true"] {
opacity: .5;
}
.ibo-field legend{
margin-top: 24px;
}
collection-entry-element {
margin-top: 8px;
display: block;
padding: 10px 10px;
background-color: #f5f5f5;
border-radius: 5px;
}
.ts-control{
height: auto;
min-height: 30px;
}
.ibo-form-actions > .ibo-button > span{
margin-right: 5px;
}
.ibo-form textarea{
resize: vertical;
}
}

View File

@@ -72,12 +72,9 @@ $ibo-panel--icon--spacing--as-medallion--is-sticking: $ibo-panel--icon--spacing-
$ibo-panel--icon--bottom--as-medallion--is-sticking: -12px !default;
$ibo-panel--icon--border--as-medallion--is-sticking: 1px $ibo-panel--base-border-style $ibo-panel--base-border-color !default;
$ibo-panel--icon-background--size--must-contain: contain !default; // deprecated, to be removed in favor of $ibo-panel--icon-img--size--must-contain
$ibo-panel--icon-background--size--must-cover: cover !default; // deprecated, to be removed in favor of $ibo-panel--icon-img--size--must-cover
$ibo-panel--icon-background--size--must-zoomout: 66.67% !default; // deprecated, to be removed in favor of $ibo-panel--icon-img--size--must-zoomout
$ibo-panel--icon-img--size--must-contain: $ibo-panel--icon-background--size--must-contain !default; // TODO remove when dealing with N°9317
$ibo-panel--icon-img--size--must-cover: $ibo-panel--icon-background--size--must-cover !default; // TODO remove when dealing with N°9317
$ibo-panel--icon-img--size--must-zoomout: $ibo-panel--icon-background--size--must-zoomout !default; // TODO remove when dealing with N°9317
$ibo-panel--icon-background--size--must-contain: contain !default;
$ibo-panel--icon-background--size--must-cover: cover !default;
$ibo-panel--icon-background--size--must-zoomout: 66.67% !default;
$ibo-panel--title--font-size--is-sticking: $ibo-font-size-150 !default;
$ibo-panel--title--color: $ibo-color-grey-900 !default;
@@ -182,25 +179,24 @@ $ibo-panel--is-selectable--body--after--font-size: $ibo-font-size-700 !default;
min-height: $ibo-panel--icon--size;
}
.ibo-panel--icon-img, .ibo-panel--icon-background { // second class is deprecated, remove it when dealing with N°9317
.ibo-panel--icon-background {
width: 100%;
height: 100%;
background-position: center;
background-repeat: no-repeat;
background-size: $ibo-panel--icon-img--size--must-contain;
background-size: $ibo-panel--icon-background--size--must-contain;
}
.ibo-panel--icon-img--must-contain, .ibo-panel--icon-background--must-contain { // second class is deprecated, remove it when dealing with N°9317
background-size: $ibo-panel--icon-img--size--must-contain;
.ibo-panel--icon-background--must-contain {
background-size: $ibo-panel--icon-background--size--must-contain;
}
.ibo-panel--icon-img--must-cover, .ibo-panel--icon-background--must-cover { // second class is deprecated, remove it when dealing with N°9317
background-size: $ibo-panel--icon-img--size--must-cover;
.ibo-panel--icon-background--must-cover {
background-size: $ibo-panel--icon-background--size--must-cover;
}
.ibo-panel--icon-img--must-zoomout, .ibo-panel--icon-background--must-zoomout { // second class is deprecated, remove it when dealing with N°9317
width: $ibo-panel--icon-img--size--must-zoomout;
height: $ibo-panel--icon-img--size--must-zoomout;
.ibo-panel--icon-background--must-zoomout {
background-size: $ibo-panel--icon-background--size--must-zoomout;
}
.ibo-panel--title {

View File

@@ -21,8 +21,6 @@ $ibo-search-form-panel--more-criteria--color: $ibo-color-blue-grey-800 !default;
$ibo-search-form-panel--more-criteria--background-color: $ibo-color-white-100 !default;
$ibo-search-form-panel--more-criteria--icon--color: $ibo-color-primary-600 !default;
$ibo-search-form-panel--more-criteria--border-color: $ibo-search-form-panel--criteria--border-color !default;
// calc is redundant but avoid SCSS min() from being used instead of CSS min()
$ibo-search-form-panel--criteria--max-height: calc(min(#{$ibo-size-750}, 50vh)) !default;
$ibo-search-form-panel--items--hover--color: $ibo-color-grey-200 !default;
@@ -280,10 +278,9 @@ $ibo-search-results-area--datatable-scrollhead--border--is-sticking: $ibo-search
}
.sfc_form_group {
display: flex;
flex-direction: column;
margin-top: -1px;
z-index: -1;
display: block;
margin-top: -1px;
z-index: -1;
}
}
@@ -349,15 +346,11 @@ $ibo-search-results-area--datatable-scrollhead--border--is-sticking: $ibo-search
display: none;
max-width: 450px;
width: max-content;
max-height: $ibo-search-form-panel--criteria--max-height;
max-height: 520px;
overflow-x: auto;
overflow-y: hidden;
.sfc_fg_operators {
display: flex;
flex-direction: column;
overflow: auto;
min-height: 0;
font-size: 12px;
.sfc_fg_operator {
@@ -394,9 +387,6 @@ $ibo-search-results-area--datatable-scrollhead--border--is-sticking: $ibo-search
}
.sfc_opc_multichoices {
display: flex;
flex-direction: column;
height: 100%;
label > input {
vertical-align: text-top;
margin-left: $ibo-spacing-0;
@@ -408,6 +398,7 @@ $ibo-search-results-area--datatable-scrollhead--border--is-sticking: $ibo-search
}
.sfc_opc_mc_items_wrapper {
max-height: 415px; /* Must be less than .sfc_form_group:max-height - .sfc_opc_mc_toggler:height - .sfc_opc_mc_filter:height */
overflow-y: auto;
margin: $ibo-spacing-0 -8px; /* Compensate .sfc_opc_multichoices side padding so the hover style can take the full with */
@@ -569,14 +560,8 @@ $ibo-search-results-area--datatable-scrollhead--border--is-sticking: $ibo-search
&.search_form_criteria_enum {
.sfc_form_group {
.sfc_fg_operator_in {
display: flex;
flex-direction: column;
height: 100%;
min-height: 0;
> label {
display: flex;
height: 100%;
min-height: 0;
display: inline-block;
width: 100%;
line-height: initial;
white-space: nowrap;

View File

@@ -11,12 +11,9 @@ $ibo-title--icon--size: 90px !default;
$ibo-title--icon--size-2: 80px !default;
$ibo-title--icon--size-3: 70px !default;
$ibo-title--icon-background--size--must-contain: contain !default; // deprecated, to be removed in favor of $ibo-title--icon-img--size--must-contain
$ibo-title--icon-background--size--must-cover: cover !default; // deprecated, to be removed in favor of $ibo-title--icon-img--size--must-cover
$ibo-title--icon-background--size--must-zoomout: 66.67% !default; // deprecated, to be removed in favor of $ibo-title--icon-img--size--must-zoomout
$ibo-title--icon-img--size--must-contain: $ibo-title--icon-background--size--must-contain !default; // TODO remove when dealing with N°9317
$ibo-title--icon-img--size--must-cover: $ibo-title--icon-background--size--must-cover !default; // TODO remove when dealing with N°9317
$ibo-title--icon-img--size--must-zoomout: $ibo-title--icon-background--size--must-zoomout !default; // TODO remove when dealing with N°9317
$ibo-title--icon-background--size--must-contain: contain !default;
$ibo-title--icon-background--size--must-cover: cover !default;
$ibo-title--icon-background--size--must-zoomout: 66.67% !default;
.ibo-title {
@@ -47,23 +44,24 @@ $ibo-title--icon-img--size--must-zoomout: $ibo-title--icon-background--size--mus
min-height: $ibo-title--icon--size-3;
}
.ibo-title--icon-img, .ibo-title--icon-background { // second class is deprecated, remove it when dealing with N°9317
.ibo-title--icon-background {
width: 100%;
height: 100%;
object-position: center;
background-size: $ibo-title--icon-img--size--must-contain;
background-position: center;
background-repeat: no-repeat;
background-size: $ibo-title--icon-background--size--must-contain;
}
.ibo-title--icon-img--must-contain, .ibo-title--icon-background--must-contain { // second class is deprecated, remove it when dealing with N°9317
background-size: $ibo-title--icon-img--size--must-contain;
.ibo-title--icon-background--must-contain {
background-size: $ibo-title--icon-background--size--must-contain;
}
.ibo-title--icon-img--must-cover, .ibo-title--icon-background--must-cover { // second class is deprecated, remove it when dealing with N°9317
background-size: $ibo-title--icon-img--size--must-cover;
.ibo-title--icon-background--must-cover {
background-size: $ibo-title--icon-background--size--must-cover;
}
.ibo-title--icon-img--must-zoomout, .ibo-title--icon-background--must-zoomout { // second class is deprecated, remove it when dealing with N°9317
background-size: $ibo-title--icon-img--size--must-zoomout;
.ibo-title--icon-background--must-zoomout {
background-size: $ibo-title--icon-background--size--must-zoomout;
}
.ibo-title--for-object-details {

View File

@@ -8,7 +8,6 @@ $ibo-toggler--wrapper--height: 20px !default;
$ibo-toggler--slider--border-radius: $ibo-border-radius-900 !default;
$ibo-toggler--slider--background-color: $ibo-color-secondary-600 !default;
$ibo-toggler--slider--disabled--background-color: $ibo-color-secondary-200 !default;
$ibo-toggler--slider--before--left: 3px !default;
$ibo-toggler--slider--before--bottom: 3px !default;
@@ -18,7 +17,6 @@ $ibo-toggler--slider--before--border-radius: $ibo-border-radius-full !default;
$ibo-toggler--slider--before--background-color: $ibo-color-grey-100 !default;
$ibo-toggler--slider--checked--background-color: $ibo-color-primary-600 !default;
$ibo-toggler--slider--checked-disabled--background-color: $ibo-color-primary-200 !default;
$ibo-toggler--slider--focus--box-shadow: 0 0 1px $ibo-color-primary-600 !default;
$ibo-toggler--label--margin-left: 4px !default;
@@ -63,13 +61,6 @@ $ibo-toggler--label--margin-left: 4px !default;
background-color: $ibo-toggler--slider--checked--background-color;
}
.ibo-toggler--wrapper input:disabled + .ibo-toggler--slider {
background-color: $ibo-toggler--slider--disabled--background-color;
}
.ibo-toggler--wrapper input:checked:disabled + .ibo-toggler--slider {
background-color: $ibo-toggler--slider--checked-disabled--background-color;
}
input:focus + .ibo-toggler--slider {
box-shadow: $ibo-toggler--slider--focus--box-shadow;
}

View File

@@ -15,4 +15,3 @@
@import "wizard-container/wizard-container";
@import "object/all";
@import "activity-panel/all";
@import "extension/all";

View File

@@ -1 +0,0 @@
@import "extension-details";

View File

@@ -1,65 +0,0 @@
$ibo-extension-details--information--metadata--padding: $ibo-spacing-200 !default;
$ibo-extension-details--information--metadata--delimiter: "-" !default;
$ibo-extension-details--information--metadata--color: $ibo-color-grey-700 !default;
$ibo-extension-details--actions--button--padding-y: 3px !default;
$ibo-extension-details--actions--button--padding-x: $ibo-button--padding-x !default;
.ibo-extension-details {
display: inline-flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
width: 100%;
}
.ibo-extension-details--information {
flex-grow: 1;
display: flex;
flex-direction: column;
}
.ibo-extension-details--actions {
display: flex;
}
.ibo-extension-details--information--label {
@extend %ibo-font-ral-med-150;
}
.ibo-extension-details--information--metadata {
@extend %ibo-font-ral-med-100;
color: $ibo-extension-details--information--metadata--color;
}
.ibo-extension-details--information--description {
@extend %ibo-font-ral-med-100;
}
.ibo-extension-details--information--metadata span + span:before {
content: $ibo-extension-details--information--metadata--delimiter;
padding-left: $ibo-extension-details--information--metadata--padding;
padding-right: $ibo-extension-details--information--metadata--padding;
}
//ibo-extension-details can have other ibo-extension-details inside its ibo-extension-details--information--description in the setup. We need to only affect direct children
.ibo-extension-details:has(>.ibo-extension-details--actions input:is([type="checkbox"], [type="radio"]):checked){
&>.ibo-extension-details--information>.ibo-extension-details--information--label .ibo-badge.unchecked {
display: none;
}
}
//Merging the two lines below with :is([type="checkbox"], [type="radio"]) will generate a warning in scss compiler
.ibo-extension-details:has(>.ibo-extension-details--actions input[type="checkbox"]:not(:checked)),
.ibo-extension-details:has(>.ibo-extension-details--actions input[type="radio"]:not(:checked)) {
&>.ibo-extension-details--information>.ibo-extension-details--information--label .ibo-badge.checked {
display: none;
}
}
.ibo-extension-details--actions > button {
padding: $ibo-extension-details--actions--button--padding-y $ibo-extension-details--actions--button--padding-x;
}
.ibo-extension-details--actions:has(.toggler-install:not(:disabled)) .ibo-popover-menu--section a[data-resource-id="force_uninstall"] {
display: none;
}

View File

@@ -5,11 +5,9 @@
$ibo-multi-column--margin-x: -$ibo-spacing-500 !default; /* This is to compensate columns padding and make the whole multicolumn align with the parent borders (cf. Bootstrap rows / cols) */
$ibo-multi-column--margin-y: $ibo-spacing-0 !default;
$ibo-multi-column--row-gap: $ibo-spacing-800 !default;
.ibo-multi-column {
display: flex;
flex-wrap: wrap;
margin: $ibo-multi-column--margin-y $ibo-multi-column--margin-x;
row-gap: $ibo-multi-column--row-gap;
}

View File

@@ -29,7 +29,7 @@ $ibo-vendors-selectize--element--active--background: $ibo-color-blue-100 !defaul
$ibo-vendors-selectize--element--active--color: $ibo-color-grey-900 !default;
$ibo-vendors-selectize--dropdown--background-color: $ibo-vendors-selectize-input--background-color !default;
$ibo-vendors-selectize--dropdown--color: $ibo-vendors-selectize-input--color !default;
$ibo-vendors-selectize--dropdown--color: $ibo-vendors-selectize-input--color!default;
$ibo-vendors-selectize--header--padding-x: 8px !default;
$ibo-vendors-selectize--header--padding-y: 5px !default;

File diff suppressed because one or more lines are too long

View File

@@ -311,39 +311,28 @@ fieldset {
}
.module-selection-body {
overflow: auto;
box-shadow: inset 0 2px 4px 0 rgba(0, 0, 0, .06) !important;
background-color: #F7FAFC;
padding: 10px;
.wiz-choice{
&:not(:checked) ~ label .checked{
display:none;
}
&:checked ~ label .unchecked{
display:none;
}
}
overflow: auto;
box-shadow: inset 0 2px 4px 0 rgba(0, 0, 0, .06) !important;
background-color: #F7FAFC;
padding: 10px;
.wiz-choice:checked ~ .description {
#itop-ticket-mgmt-simple-ticket-enhanced-portal:not(:checked),
#itop-ticket-mgmt-itil-enhanced-portal:not(:checked) {
~ .description::after {
content: "Legacy portal is no longer part of iTop, by leaving this option unchecked your portal users won't be able to access iTop anymore.";
display: block;
margin-top: 0.5em;
font-weight: bold;
color: $legacy-portal-removal-text-color;
}
}
}
}
.ibo-extension-details:has(>.ibo-extension-details--actions>input:checked) {
.ibo-extension-details:has(#itop-ticket-mgmt-simple-ticket-enhanced-portal:not(:checked), #itop-ticket-mgmt-itil-enhanced-portal:not(:checked)) {
.ibo-extension-details--information--description::after {
content: "Legacy portal is no longer part of iTop, by leaving this option unchecked your portal users won't be able to access iTop anymore.";
display: block;
margin-top: 0.5em;
font-weight: bold;
color: $legacy-portal-removal-text-color;
}
}
}
.ibo-extension-details--information--metadata{
color: $ibo-color-grey-800;
}
.choice-disabled {
color: $ibo-color-grey-700;
}
body {
font-size: 1.17rem;
@@ -527,12 +516,10 @@ body {
}
}
.ibo-setup-summary-title, .ibo-setup-summary-title:visited, .ibo-setup-summary-title:hover {
font-size: $ibo-font-size-150;
color: inherit;
.ibo-setup-summary-title {
font-size: $ibo-font-size-150;
}
#ibo-setup-licenses--components-list {
background-color: $ibo-color-white-200;
padding: 12px;
@@ -608,51 +595,6 @@ body {
color: $ibo-color-blue-700;
font-size: $ibo-font-size-200;
}
.setup-extension--missing .setup-extension--icon{
color:#a00000;
}
.setup-extension-tag {
display: inline-flex;
background-color: grey;
border-radius: 8px;
padding-left: 3px;
padding-right: 3px;
margin-right: 3px;
&.installed{
background-color:#9eff9e
}
&.notinstalled{
background-color:#ed9eff
}
&.tobeinstalled{
background-color:#9ef0ff
}
&.tobeuninstalled{
background-color:#ff9e9e
}
&.notuninstallable{
background-color:#ffc98c
}
&.removed{
background-color: #969594
}
}
.ibo-extension-details {
align-items: flex-start;
}
.ibo-extension-details--actions input{
margin:0.2em 0.5em;
width: 12px;
}
:not(.ibo-badge) ~ .ibo-badge{
margin-left:0.5em;
}
.ibo-extension-details--information--label i{
font-size : 0.9em;
margin-left:0.3em;
}
.setup--wizard-choice--label + .setup--wizard-choice--more-info {
margin-left: 0.5rem;
}
@@ -704,6 +646,9 @@ body {
overflow: auto;
text-align: center;
}
#installation_progress {
display: none;
}
#fresh_content{
border: 0;
min-height: 300px;

View File

@@ -2,7 +2,7 @@
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.3">
<module_parameters>
<parameters id="authent-local" _delta="define">
<password_validation.pattern>^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\da-zA-Z]).{12,}$</password_validation.pattern>
<password_validation.pattern>^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\da-zA-Z]).{8,}$</password_validation.pattern>
<password_validation.message type="hash"/>
</parameters>
</module_parameters>

View File

@@ -29,7 +29,7 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', [
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Heslo nemůže uživatel změnit.',
'Class:UserLocal/Attribute:password_renewed_date' => 'Heslo bylo obnoveno',
'Class:UserLocal/Attribute:password_renewed_date+' => 'Termín, kdy bylo heslo změneno',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Heslo musí obsahovat minimálně 12 znaků a musí obsahovat minimálně jedno velké písmeno, jedno malé písmeno, jedno číslo a speciální znak.',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Heslo musí obsahovat minimálně 8 znaků a musí obsahovat minimálně jedno velké písmeno, jedno malé písmeno, jedno číslo a speciální znak.',
'UserLocal:password:expiration' => 'Níže uvedená pole vyžadují rozšíření',
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Nastavení exspirace "Jednorázového hesla" nelze u vlastního účtu uživatele.',
]);

View File

@@ -28,7 +28,7 @@ Dict::Add('DA DA', 'Danish', 'Dansk', [
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~',
'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewed on~~',
'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 12 characters and include uppercase, lowercase, numeric and special characters.~~',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~',
'UserLocal:password:expiration' => 'The fields below require an extension~~',
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User~~',
]);

View File

@@ -28,7 +28,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', [
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => '',
'Class:UserLocal/Attribute:password_renewed_date' => 'Letzte Passworterneuerung',
'Class:UserLocal/Attribute:password_renewed_date+' => 'Letztes Änderungsdatum',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Das Passwort muss mindestens 12 Zeichen lang sein und Großbuchstaben, Kleinbuchstaben, Zahlen und Sonderzeichen enthalten.',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Das Passwort entspricht nicht dem in den Konfigurationsregeln hinterlegten RegEx-Ausdruck',
'UserLocal:password:expiration' => 'Die folgenden Felder benötigen eine '.ITOP_APPLICATION_SHORT.' Erweiterung',
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Das setzen des Passwortablaufs auf "Einmalpasswort" ist für den eigenen Benutzer nicht erlaubt.',
]);

View File

@@ -55,7 +55,7 @@ Dict::Add('EN US', 'English', 'English', [
'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewed on',
'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 12 characters and include uppercase, lowercase, numeric and special characters.',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.',
'UserLocal:password:expiration' => 'The fields below require an extension',
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User',
]);

View File

@@ -55,7 +55,7 @@ Dict::Add('EN GB', 'British English', 'British English', [
'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewed on',
'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 12 characters and include uppercase, lowercase, numeric and special characters.',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.',
'UserLocal:password:expiration' => 'The fields below require an extension',
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User',
]);

View File

@@ -25,7 +25,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'El usuario no puede cambiar la contraseña.',
'Class:UserLocal/Attribute:password_renewed_date' => 'Renovación de contraseña',
'Class:UserLocal/Attribute:password_renewed_date+' => 'Cuando fue el último cambio de contraseña',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'La contraseña debe ser de al menos 12 caracteres e incluir mayúsculas, minúsculas, números y caracteres especiales.',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'La contraseña debe ser de al menos 8 caracteres e incluír mayúsculas, minúsculas, números y caracteres especiales.',
'UserLocal:password:expiration' => 'El siguiente campo requiere una extensión',
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Configurar expiración de contraseña para "ontraseña de un solo uso" no está permitido para su propio Usuario',
]);

View File

@@ -27,7 +27,7 @@ Dict::Add('FR FR', 'French', 'Français', [
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => '',
'Class:UserLocal/Attribute:password_renewed_date' => 'Mot de passe changé le',
'Class:UserLocal/Attribute:password_renewed_date+' => 'Dernière date à laquelle le mot de passe a été changé',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Le mot de passe doit contenir au moins 12 caractères, avec minuscule, majuscule, nombre et caractère spécial.',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Le mot de passe doit contenir au moins 8 caractères, avec minuscule, majuscule, nombre et caractère spécial.',
'UserLocal:password:expiration' => 'Les champs ci-dessous nécessitent une extension',
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Impossible de mettre "Usage unique" comme validité du mot de passe pour son propre utilisateur.',
]);

View File

@@ -27,7 +27,7 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', [
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'A felhasználó nem változtathat jelszót.',
'Class:UserLocal/Attribute:password_renewed_date' => 'Jelszó megújítás ideje',
'Class:UserLocal/Attribute:password_renewed_date+' => 'A jelszó legutóbbi módosításának időpontja',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'A jelszónak legalább 12 karakterből kell állnia, és tartalmaznia kell nagybetűket, kisbetűket, numerikus és speciális karaktereket.',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'A jelszónak legalább 8 karakterből kell állnia, és tartalmaznia kell nagybetűket, kisbetűket, numerikus és speciális karaktereket.',
'UserLocal:password:expiration' => 'Az alábbi mezőkhöz egy bővítmény szükséges',
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'A jelszó lejárati idejének beállítása "Egyszeri jelszóra" nem engedélyezett a saját Felhasználó számára.',
]);

View File

@@ -27,7 +27,7 @@ Dict::Add('IT IT', 'Italian', 'Italiano', [
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'La password non può essere cambiata dall\'utente.',
'Class:UserLocal/Attribute:password_renewed_date' => 'Rinnovo della password',
'Class:UserLocal/Attribute:password_renewed_date+' => 'Quando è stata cambiata l\'ultima volta la password',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'La password deve essere di almeno 12 caratteri e includere lettere maiuscole, minuscole, numeri e caratteri speciali.',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'La password deve essere di almeno 8 caratteri e includere lettere maiuscole, minuscole, numeri e caratteri speciali.',
'UserLocal:password:expiration' => 'I campi sottostanti richiedono un\'estensione',
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Impostare la scadenza della password su "Password monouso" non è consentito per il proprio utente',
]);

View File

@@ -28,7 +28,7 @@ Dict::Add('JA JP', 'Japanese', '日本語', [
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~',
'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewed on~~',
'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 12 characters and include uppercase, lowercase, numeric and special characters.~~',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~',
'UserLocal:password:expiration' => 'The fields below require an extension~~',
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User~~',
]);

View File

@@ -28,7 +28,7 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', [
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'De gebruiker kan dit wachtwoord niet veranderen.',
'Class:UserLocal/Attribute:password_renewed_date' => 'Wachtwoord laatst aangepast',
'Class:UserLocal/Attribute:password_renewed_date+' => 'Tijdstip waarop het wachtwoord het laatst aangepast werd.',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Het wachtwoord bestaat uit minstens 12 tekens en bestaat uit een mix van minstens 1 hoofdletter, kleine letter, cijfer en speciaal teken.',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Het wachtwoord bestaat uit minstens 8 tekens en bestaat uit een mix van minstens 1 hoofdletter, kleine letter, cijfer en speciaal teken.',
'UserLocal:password:expiration' => 'De velden hieronder vereisen een extensie.',
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Je kan geen eenmalig wachtwoord instellen voor je eigen gebruiker.',
]);

View File

@@ -27,7 +27,7 @@ Dict::Add('PL PL', 'Polish', 'Polski', [
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Hasło nie może być zmienione przez użytkownika.',
'Class:UserLocal/Attribute:password_renewed_date' => 'Odnowienie hasła',
'Class:UserLocal/Attribute:password_renewed_date+' => 'Kiedy ostatnio zmieniano hasło',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Hasło musi mieć co najmniej 12 znaków i zawierać duże, małe litery, cyfry i znaki specjalne.',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Hasło musi mieć co najmniej 8 znaków i zawierać duże, małe litery, cyfry i znaki specjalne.',
'UserLocal:password:expiration' => 'Poniższe pola wymagają rozszerzenia',
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Ustawienie wygaśnięcia hasła "Hasło jednorazowe" nie jest dozwolone dla własnego użytkownika',
]);

View File

@@ -28,7 +28,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', [
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~',
'Class:UserLocal/Attribute:password_renewed_date' => 'Дата изменения пароля',
'Class:UserLocal/Attribute:password_renewed_date+' => 'Когда пароль был изменен в последний раз',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Пароль должен содержать не менее 12 символов и включать прописные, строчные, числовые и специальные символы.',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Пароль должен содержать не менее 8 символов и включать прописные, строчные, числовые и специальные символы.',
'UserLocal:password:expiration' => 'Поля требуют наличия доп. расширения',
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User~~',
]);

View File

@@ -27,7 +27,7 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~',
'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewed on~~',
'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 12 characters and include uppercase, lowercase, numeric and special characters.~~',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~',
'UserLocal:password:expiration' => 'The fields below require an extension~~',
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User~~',
]);

View File

@@ -28,7 +28,7 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', [
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~',
'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewed on~~',
'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 12 characters and include uppercase, lowercase, numeric and special characters.~~',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~',
'UserLocal:password:expiration' => 'The fields below require an extension~~',
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User~~',
]);

View File

@@ -51,7 +51,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => '用户不允许修改密码.',
'Class:UserLocal/Attribute:password_renewed_date' => '密码更新',
'Class:UserLocal/Attribute:password_renewed_date+' => '上次修改密码的时间',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => '密码必须至少12个字符, 包含大小写, 数字和特殊字符.',
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => '密码必须至少8个字符, 包含大小写, 数字和特殊字符.',
'UserLocal:password:expiration' => '下面的区域需要插件扩展',
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => '不允许用户为自己设置 "一次性密码" 的失效期限',
]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -68,47 +68,47 @@ $ibo-color-information-900: #0f172a !default;
$ibo-color-information-950: #020617 !default;
$ibo-lifecycle-new-state-primary-color: $ibo-color-information-600 !default;
$ibo-lifecycle-new-state-secondary-color: $ibo-color-white-100 !default;
$ibo-lifecycle-neutral-state-primary-color: $ibo-color-information-600 !default;
$ibo-lifecycle-neutral-state-secondary-color: $ibo-color-white-100 !default;
$ibo-lifecycle-waiting-state-primary-color: $ibo-color-yellow-700 !default;
$ibo-lifecycle-waiting-state-secondary-color: $ibo-color-white-100 !default;
$ibo-lifecycle-success-state-primary-color: $ibo-color-blue-700 !default;
$ibo-lifecycle-success-state-secondary-color: $ibo-color-white-100 !default;
$ibo-lifecycle-failure-state-primary-color: $ibo-color-orange-800 !default;
$ibo-lifecycle-failure-state-secondary-color: $ibo-color-white-100 !default;
$ibo-lifecycle-frozen-state-primary-color: $ibo-color-information-200 !default;
$ibo-lifecycle-frozen-state-secondary-color: $ibo-color-information-700 !default;
$ibo-lifecycle-new-state-primary-color: $ibo-color-information-600;
$ibo-lifecycle-new-state-secondary-color: $ibo-color-white-100;
$ibo-lifecycle-neutral-state-primary-color: $ibo-color-information-600;
$ibo-lifecycle-neutral-state-secondary-color: $ibo-color-white-100;
$ibo-lifecycle-waiting-state-primary-color: $ibo-color-yellow-700;
$ibo-lifecycle-waiting-state-secondary-color: $ibo-color-white-100;
$ibo-lifecycle-success-state-primary-color: $ibo-color-blue-700;
$ibo-lifecycle-success-state-secondary-color: $ibo-color-white-100;
$ibo-lifecycle-failure-state-primary-color: $ibo-color-orange-800;
$ibo-lifecycle-failure-state-secondary-color: $ibo-color-white-100;
$ibo-lifecycle-frozen-state-primary-color: $ibo-color-information-200;
$ibo-lifecycle-frozen-state-secondary-color: $ibo-color-information-700;
$ibo-lifecycle-active-state-primary-color: $ibo-color-blue-700 !default;
$ibo-lifecycle-active-state-secondary-color: $ibo-color-white-100 !default;
$ibo-lifecycle-inactive-state-primary-color: $ibo-color-yellow-700 !default;
$ibo-lifecycle-inactive-state-secondary-color: $ibo-color-white-100 !default;
$ibo-lifecycle-active-state-primary-color: $ibo-color-blue-700;
$ibo-lifecycle-active-state-secondary-color: $ibo-color-white-100;
$ibo-lifecycle-inactive-state-primary-color: $ibo-color-yellow-700;
$ibo-lifecycle-inactive-state-secondary-color: $ibo-color-white-100;
$ibo-caselog-highlight-color-1: $ibo-color-blue-700 !default;
$ibo-caselog-highlight-color-2: $ibo-color-yellow-700 !default;
$ibo-caselog-highlight-color-3: $ibo-color-information-600 !default;
$ibo-caselog-highlight-color-4: $ibo-color-yellow-500 !default;
$ibo-caselog-highlight-color-5: $ibo-color-blue-500 !default;
$ibo-caselog-highlight-color-6: $ibo-color-yellow-300 !default;
$ibo-caselog-highlight-color-7: $ibo-color-blue-300 !default;
$ibo-caselog-highlight-color-1: $ibo-color-blue-700;
$ibo-caselog-highlight-color-2: $ibo-color-yellow-700;
$ibo-caselog-highlight-color-3: $ibo-color-information-600;
$ibo-caselog-highlight-color-4: $ibo-color-yellow-500;
$ibo-caselog-highlight-color-5: $ibo-color-blue-500;
$ibo-caselog-highlight-color-6: $ibo-color-yellow-300;
$ibo-caselog-highlight-color-7: $ibo-color-blue-300;
$ibo-input-wrapper--is-error--border-color: $ibo-color-warning-700 !default;
$ibo-field-validation: $ibo-color-warning-800 !default;
$ibo-input-wrapper--is-error--border-color: $ibo-color-warning-700;
$ibo-field-validation: $ibo-color-warning-800;
$ibo-navigation-menu--visual-hint--background-color: $ibo-color-blue-400 !default;
$ibo-navigation-menu--visual-hint--background-color: $ibo-color-blue-400;
$ibo-wizard-container--background-color: $ibo-color-information-200 !default;
$ibo-wizard-container--border-color: $ibo-color-information-600 !default;
$ibo-wizard-container--background-color: $ibo-color-information-200;
$ibo-wizard-container--border-color: $ibo-color-information-600;
$ibo-navigation-menu--notifications--item--new-message-indicator--background-color: $ibo-color-white-100 !default;
$ibo-navigation-menu--notifications--item--new-message-indicator--border: solid 2px $ibo-color-grey-500 !default;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-1--background-color: $ibo-color-danger-100 !default;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-1--border: solid 2px $ibo-color-danger-500 !default;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-2--background-color: $ibo-color-warning-100 !default;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-2--border: solid 2px $ibo-color-warning-500 !default;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-3--background-color: $ibo-color-success-100 !default;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-3--border: solid 2px $ibo-color-success-500 !default;
$ibo-navigation-menu--notifications--item--new-message-indicator--background-color: $ibo-color-white-100;
$ibo-navigation-menu--notifications--item--new-message-indicator--border: solid 2px $ibo-color-grey-500;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-1--background-color: $ibo-color-danger-100;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-1--border: solid 2px $ibo-color-danger-500;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-2--background-color: $ibo-color-warning-100;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-2--border: solid 2px $ibo-color-warning-500;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-3--background-color: $ibo-color-success-100;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-3--border: solid 2px $ibo-color-success-500;
$ibo-notifications--view-all--item--unread--highlight--background-color: $ibo-color-blue-600 !default;
$ibo-notifications--view-all--item--unread--highlight--background-color: $ibo-color-blue-600;

View File

@@ -32,47 +32,47 @@ $ibo-color-information-900: #0f172a !default;
$ibo-color-information-950: #020617 !default;
$ibo-lifecycle-new-state-primary-color: $ibo-color-information-600 !default;
$ibo-lifecycle-new-state-secondary-color: $ibo-color-white-100 !default;
$ibo-lifecycle-neutral-state-primary-color: $ibo-color-information-600 !default;
$ibo-lifecycle-neutral-state-secondary-color: $ibo-color-white-100 !default;
$ibo-lifecycle-waiting-state-primary-color: $ibo-color-red-200 !default;
$ibo-lifecycle-waiting-state-secondary-color: $ibo-color-red-800 !default;
$ibo-lifecycle-success-state-primary-color: $ibo-color-blue-700 !default;
$ibo-lifecycle-success-state-secondary-color: $ibo-color-white-100 !default;
$ibo-lifecycle-failure-state-primary-color: $ibo-color-red-800 !default;
$ibo-lifecycle-failure-state-secondary-color: $ibo-color-white-100 !default;
$ibo-lifecycle-frozen-state-primary-color: $ibo-color-information-200 !default;
$ibo-lifecycle-frozen-state-secondary-color: $ibo-color-information-700 !default;
$ibo-lifecycle-new-state-primary-color: $ibo-color-information-600;
$ibo-lifecycle-new-state-secondary-color: $ibo-color-white-100;
$ibo-lifecycle-neutral-state-primary-color: $ibo-color-information-600;
$ibo-lifecycle-neutral-state-secondary-color: $ibo-color-white-100;
$ibo-lifecycle-waiting-state-primary-color: $ibo-color-red-200;
$ibo-lifecycle-waiting-state-secondary-color: $ibo-color-red-800;
$ibo-lifecycle-success-state-primary-color: $ibo-color-blue-700;
$ibo-lifecycle-success-state-secondary-color: $ibo-color-white-100;
$ibo-lifecycle-failure-state-primary-color: $ibo-color-red-800;
$ibo-lifecycle-failure-state-secondary-color: $ibo-color-white-100;
$ibo-lifecycle-frozen-state-primary-color: $ibo-color-information-200;
$ibo-lifecycle-frozen-state-secondary-color: $ibo-color-information-700;
$ibo-lifecycle-active-state-primary-color: $ibo-color-blue-700 !default;
$ibo-lifecycle-active-state-secondary-color: $ibo-color-white-100 !default;
$ibo-lifecycle-inactive-state-primary-color: $ibo-color-red-700 !default;
$ibo-lifecycle-inactive-state-secondary-color: $ibo-color-white-100 !default;
$ibo-lifecycle-active-state-primary-color: $ibo-color-blue-700;
$ibo-lifecycle-active-state-secondary-color: $ibo-color-white-100;
$ibo-lifecycle-inactive-state-primary-color: $ibo-color-red-700;
$ibo-lifecycle-inactive-state-secondary-color: $ibo-color-white-100;
$ibo-caselog-highlight-color-1: $ibo-color-blue-700 !default;
$ibo-caselog-highlight-color-2: $ibo-color-red-700 !default;
$ibo-caselog-highlight-color-3: $ibo-color-information-600 !default;
$ibo-caselog-highlight-color-4: $ibo-color-red-500 !default;
$ibo-caselog-highlight-color-5: $ibo-color-blue-500 !default;
$ibo-caselog-highlight-color-6: $ibo-color-red-300 !default;
$ibo-caselog-highlight-color-7: $ibo-color-blue-300 !default;
$ibo-caselog-highlight-color-1: $ibo-color-blue-700;
$ibo-caselog-highlight-color-2: $ibo-color-red-700;
$ibo-caselog-highlight-color-3: $ibo-color-information-600;
$ibo-caselog-highlight-color-4: $ibo-color-red-500;
$ibo-caselog-highlight-color-5: $ibo-color-blue-500;
$ibo-caselog-highlight-color-6: $ibo-color-red-300;
$ibo-caselog-highlight-color-7: $ibo-color-blue-300;
$ibo-input-wrapper--is-error--border-color: $ibo-color-pink-700 !default;
$ibo-field-validation: $ibo-color-pink-800 !default;
$ibo-input-wrapper--is-error--border-color: $ibo-color-pink-700;
$ibo-field-validation: $ibo-color-pink-800;
$ibo-navigation-menu--visual-hint--background-color: $ibo-color-pink-600 !default;
$ibo-navigation-menu--visual-hint--background-color: $ibo-color-pink-600;
$ibo-wizard-container--background-color: $ibo-color-information-200 !default;
$ibo-wizard-container--border-color: $ibo-color-information-600 !default;
$ibo-wizard-container--background-color: $ibo-color-information-200;
$ibo-wizard-container--border-color: $ibo-color-information-600;
$ibo-navigation-menu--notifications--item--new-message-indicator--background-color: $ibo-color-white-100 !default;
$ibo-navigation-menu--notifications--item--new-message-indicator--border: solid 2px $ibo-color-grey-500 !default;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-1--background-color: $ibo-color-pink-100 !default;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-1--border: solid 2px $ibo-color-pink-600 !default;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-2--background-color: $ibo-color-warning-100 !default;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-2--border: solid 2px $ibo-color-warning-400 !default;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-3--background-color: $ibo-color-success-100 !default;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-3--border: solid 2px $ibo-color-success-500 !default;
$ibo-navigation-menu--notifications--item--new-message-indicator--background-color: $ibo-color-white-100;
$ibo-navigation-menu--notifications--item--new-message-indicator--border: solid 2px $ibo-color-grey-500;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-1--background-color: $ibo-color-pink-100;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-1--border: solid 2px $ibo-color-pink-600;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-2--background-color: $ibo-color-warning-100;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-2--border: solid 2px $ibo-color-warning-400;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-3--background-color: $ibo-color-success-100;
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-3--border: solid 2px $ibo-color-success-500;
$ibo-notifications--view-all--item--unread--highlight--background-color: $ibo-color-pink-500 !default;
$ibo-notifications--view-all--item--unread--highlight--background-color: $ibo-color-pink-500;

View File

@@ -1,9 +0,0 @@
/*
* @copyright Copyright (C) 2010-2025 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/*
* CSS of the template page
*/

View File

@@ -1,9 +0,0 @@
/*
* @copyright Copyright (C) 2010-2025 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/*
* Javascript file loaded in template page
*/

View File

@@ -1,17 +0,0 @@
{
"config": {
"classmap-authoritative": true
},
"autoload": {
"psr-4": {
"Combodo\\iTop\\DataFeatureRemoval\\": "src",
"": "src/NoNamespace"
}
},
"name": "combodo/combodo-data-feature-removal",
"type": "itop-extension",
"description": "iTop Data Feature Removal",
"require": {
"composer-runtime-api": "^2.0"
}
}

View File

@@ -1,20 +0,0 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "b862a55cbf5448fb99f0905a4db6529b",
"packages": [],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"composer-runtime-api": "^2.0"
},
"platform-dev": {},
"plugin-api-version": "2.6.0"
}

View File

@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.3">
<menus>
<menu id="DataFeatureRemovalMenu" xsi:type="WebPageMenuNode" _delta="define">
<rank>30</rank>
<parent>SystemTools</parent>
<url>$pages/exec.php?exec_module=combodo-data-feature-removal&amp;exec_page=index.php&amp;c[menu]=DataFeatureRemovalMenu</url>
<enable_admin_only>1</enable_admin_only>
</menu>
</menus>
<module_parameters>
<parameters id="combodo-data-feature-removal">
<max_count_estimation_for_safe_cleanup>100</max_count_estimation_for_safe_cleanup>
</parameters>
</module_parameters>
</itop_design>

View File

@@ -1,58 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2025 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Localized data
*/
Dict::Add('EN US', 'English', 'English', [
'Menu:DataFeatureRemovalMenu' => 'Features Removal',
'combodo-data-feature-removal/Operation:Main/Title' => 'Features Removal',
'DataFeatureRemoval:Main:Title' => 'Features Removal',
'DataFeatureRemoval:Main:SubTitle' => 'Prepare features you want to enable/disable in a future setup',
'DataFeatureRemoval:Failure:Title' => 'Feature dry removal errors',
'DataFeatureRemoval:Helper:Title' => 'Enable or disable features that are installed in your iTop.',
'DataFeatureRemoval:Helper:Desc1' => 'It will prepare the setup step that proceeds to feature enabling or disabling.',
'DataFeatureRemoval:Helper:Desc2' => 'Analyze if there are any data or dependency preventing you from enabling/disabling a feature.',
'DataFeatureRemoval:Features:Title' => 'Features',
'DataFeatureRemoval:Analysis:Title' => 'Analysis result',
'DataFeatureRemoval:Analysis:SubTitle' => '%1$s element(s) to clean before continuing',
'DataFeatureRemoval:DeletionPlan:Title' => 'Deletion plan',
'DataFeatureRemoval:DeletionPlan:SubTitle' => '%1$s rows to clean before continuing',
'DataFeatureRemoval:DoDeletion:Title' => 'Do deletion',
'DataFeatureRemoval:DoDeletion:SubTitle' => 'Remove all the entries from the database',
'DataFeatureRemoval:DeletionPlan:ToManyOperations' => 'Too many entries to clean',
'DataFeatureRemoval:Table:Analysis:ClassName' => 'Element to remove',
'DataFeatureRemoval:Table:Analysis:FeatureName' => 'Feature name',
'DataFeatureRemoval:Table:Analysis:Module' => 'Module name',
'DataFeatureRemoval:Table:Analysis:Occurrence' => 'Occurrence',
'UI:Button:Analyze' => 'Analyze',
'UI:Button:ModifyChoices' => 'Modify Choices',
'UI:Button:AnalyzeAndSetup' => 'Analyze and go to setup',
'UI:Button:PlanDeletion' => 'Prepare deletion plan',
'UI:Button:DoDeletion' => 'Delete data',
'UI:Button:BackToMain' => 'Back to Feature Removal',
'UI:Button:Setup' => 'Back to setup',
'UI:Action:ForceUninstall' => 'Force uninstall',
'UI:Action:MoreInfo' => 'More information',
'DataFeatureRemoval:Table:Empty' => 'No data to remove',
'DataFeatureRemoval:Column:Class' => 'Class',
'DataFeatureRemoval:Column:DeleteCount' => 'Entries to delete',
'DataFeatureRemoval:Column:UpdateCount' => 'Entries to update',
'DataFeatureRemoval:Column:Issue' => 'Issue',
'DataFeatureRemoval:Column:DeletedCount' => 'Deleted entries',
'DataFeatureRemoval:Column:UpdatedCount' => 'Updated entries',
]);

View File

@@ -1,58 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2025 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Localized data
*/
Dict::Add('FR FR', 'French', 'Français', [
'Menu:DataFeatureRemovalMenu' => 'Suppression de fonctionnalités',
'combodo-data-feature-removal/Operation:Main/Title' => 'Suppression de fonctionnalités',
'DataFeatureRemoval:Main:Title' => 'Suppression de fonctionnalités',
'DataFeatureRemoval:Main:SubTitle' => 'Préparez les fonctionnalités que vous souhaitez activer ou désactiver lors dune prochaine configuration',
'DataFeatureRemoval:Failure:Title' => 'Erreurs lors de la simulation de suppression de fonctionnalités',
'DataFeatureRemoval:Helper:Title' => 'Activez ou désactivez les fonctionnalités installées dans votre iTop.',
'DataFeatureRemoval:Helper:Desc1' => 'Cette étape prépare lassistant de configuration à activer ou désactiver des fonctionnalités.',
'DataFeatureRemoval:Helper:Desc2' => 'Analyse si des données ou des dépendances empêchent lactivation ou la désactivation dune fonctionnalité.',
'DataFeatureRemoval:Features:Title' => 'Fonctionnalités',
'DataFeatureRemoval:Analysis:Title' => 'Résultat de lanalyse',
'DataFeatureRemoval:Analysis:SubTitle' => '%1$s élément(s) à nettoyer avant de poursuivre',
'DataFeatureRemoval:DeletionPlan:Title' => 'Plan de suppression',
'DataFeatureRemoval:DeletionPlan:SubTitle' => '%1$s ligne(s) à nettoyer avant de poursuivre',
'DataFeatureRemoval:DoDeletion:Title' => 'Exécuter la suppression',
'DataFeatureRemoval:DoDeletion:SubTitle' => 'Supprime toutes les entrées de la base de données',
'DataFeatureRemoval:DeletionPlan:ToManyOperations' => 'Trop dentrées à nettoyer',
'DataFeatureRemoval:Table:Analysis:ClassName' => 'Élément à supprimer',
'DataFeatureRemoval:Table:Analysis:FeatureName' => 'Fonctionnalité',
'DataFeatureRemoval:Table:Analysis:Module' => 'Module',
'DataFeatureRemoval:Table:Analysis:Occurrence' => 'Occurrence',
'UI:Button:Analyze' => 'Analyser',
'UI:Button:ModifyChoices' => 'Modifier les choix',
'UI:Button:AnalyzeAndSetup' => 'Analyser et ouvrir lassistant de configuration',
'UI:Button:PlanDeletion' => 'Préparer le plan de suppression',
'UI:Button:DoDeletion' => 'Supprimer les données',
'UI:Button:BackToMain' => 'Retour à la suppression de fonctionnalités',
'UI:Button:Setup' => 'Retour à lassistant de configuration',
'UI:Action:ForceUninstall' => 'Forcer la désinstallation',
'UI:Action:MoreInfo' => 'Plus dinformations',
'DataFeatureRemoval:Table:Empty' => 'Aucune donnée à supprimer',
'DataFeatureRemoval:Column:Class' => 'Classe',
'DataFeatureRemoval:Column:DeleteCount' => 'Entrées à supprimer',
'DataFeatureRemoval:Column:UpdateCount' => 'Entrées à mettre à jour',
'DataFeatureRemoval:Column:Issue' => 'Problème',
'DataFeatureRemoval:Column:DeletedCount' => 'Entrées supprimées',
'DataFeatureRemoval:Column:UpdatedCount' => 'Entrées mises à jour',
]);

View File

@@ -1,20 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2025 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\DataFeatureRemoval;
use Combodo\iTop\DataFeatureRemoval\Controller\DataFeatureRemovalController;
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalHelper;
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalLog;
require_once(APPROOT.'application/startup.inc.php');
DataFeatureRemovalLog::Enable();
$oController = new DataFeatureRemovalController(MODULESROOT.DataFeatureRemovalHelper::MODULE_NAME.'/templates', DataFeatureRemovalHelper::MODULE_NAME);
$oController->SetDefaultOperation('Main');
$oController->HandleOperation();

View File

@@ -1,16 +0,0 @@
<?php
// PHP Data Model definition file
// WARNING - WARNING - WARNING
// DO NOT EDIT THIS FILE (unless you know what you are doing)
//
// If you provide a datamodel.xxxx.xml file with your module,
// this file WILL BE overwritten by the compilation of the
// module (during the setup) if the datamodel.xxxx.xml file
// contains the definition of new classes or menus.
//
// The recommended way to define new classes (for iTop 2.0 and later) is via the XML definition.
// This file remains in the module's template only for the cases where there is:
// - either no new class or menu defined in the XML file
// - or no XML file at all supplied by the module

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