Compare commits

..

45 Commits

Author SHA1 Message Date
odain
0001e8ffc4 💚 use new ci validation 2020-10-09 10:13:51 +02:00
Molkobain
3dbbf296b8 Exclude combodo-db-tools module from packages by default 2020-01-22 09:10:54 +01:00
Stephen Abello
878c23892d Update version number for 2.5.4 2020-01-20 15:59:08 +01:00
Stephen Abello
248dab9289 N°2633 - Security hardening 2020-01-20 15:46:04 +01:00
Molkobain
3347f400b8 Internal: Revert files deleted by mistake 🙈 2020-01-08 11:57:29 +01:00
Molkobain
6082308e20 Add combodo-db-tools/1.0.7 module as a default module 2020-01-08 11:40:35 +01:00
Pierre Goiffon
b3369c8b0e Update version number for 2.5.3 beta 2019-07-02 14:54:36 +02:00
bruno DA SILVA
6c948873ff N°2323.6 Fix regression introduced in previous commit 2019-06-26 15:38:42 +02:00
Molkobain
93099ea3c7 N°2323.5 Fix regression introduced in previous commit
Could not upload images in HTML field anymore
2019-06-21 10:01:31 +02:00
Molkobain
2f9e050e2b N°2323.4 Fix regression introduced in previous commit
Current user picture was no longer displayed in the portal

(cherry picked from commit 56b9eb6cf3)
2019-06-20 17:52:26 +02:00
Eric
02c78d4044 N°2278 - Object-copier: Fix n:n link attributes set to default on copy
(cherry picked from commit 6564d84a2f)
2019-06-18 14:57:45 +02:00
Eric
5102b113ed N°2323 - Fix calls to ajax endpoints
(cherry picked from commit c723d19e01)
2019-06-18 10:45:50 +02:00
Eric
f1e4d94499 N°2323 - Fix calls to ajax endpoints for portal 2019-06-18 10:43:45 +02:00
OИUЯd da silva
23cf2b91f4 make demo_mode effect more expressive
closes #71
2019-05-06 11:42:27 +02:00
Thomas Casteleyn
2858d13fd5 🐛 Fix default usage of iTopMutex when TLS is enabled
See R-021467
2019-04-29 11:18:54 +02:00
Molkobain
16c8466841 N°2115 Fix regression introduced in N°1443: Left pane menu not showing due a JS error 2019-03-25 15:39:45 +01:00
Eric
764b0f8e31 N°1846 - Fix Object Copier: Create Ticket from CI, duplicate links
(cherry picked from commit 44b7821015)
2019-03-22 11:06:23 +01:00
Pierre Goiffon
7c7382f372 N°1835 add new 'transaction_id' sanitize filter 2019-03-21 14:28:24 +01:00
Pierre Goiffon
9f0e8dc49b 📦 Update CSS for 2.5.2 2019-03-19 11:47:29 +01:00
Pierre Goiffon
b8d5c01382 📦 Update versions for 2.5.2 2019-03-19 11:37:15 +01:00
Pierre Goiffon
d3db77c675 📦 Update modules versions for 2.5.2 2019-03-19 11:29:37 +01:00
Pierre Goiffon
533e65fcd1 🌐 Fix dict automatic update 2019-03-19 10:52:43 +01:00
Pierre Goiffon
3fb0c768e6 🌐 Update dictionnaries for iTop 2.5.2 2019-03-19 10:10:28 +01:00
Molkobain
3322074ce7 🐛 N°1889 Portal: Wrong encoding of special chars like in dashlets (eg. "ö", "&", ...)
(cherry picked from commit 83bb3b6d72)
2019-03-13 17:01:57 +01:00
Eric
229f800266 N° 1837 - Fix Synchro Obsolescence
(cherry picked from commit 75737b4ffe)
2019-03-13 14:19:25 +01:00
Molkobain
75a0979eee N°2045 Portal: Fix regression introduced with N°1980: New request with 2 Request Templates does not display fields 2019-03-06 14:46:01 +01:00
Pierre Goiffon
d6a0a279a5 N°1449 Update REST API version for new pagination params 2019-03-04 16:00:36 +01:00
Pierre Goiffon
44f5d71e1b 💡 PHPDoc for REST API 2019-03-04 16:00:35 +01:00
Pierre Goiffon
3de7aa1ada 🙈 Update ignore file 2019-03-04 09:15:38 +01:00
Stephen Abello
d4fec14123 N°1443: Handle disabled selectable rows in datatables when "All checking/unchecking" 2019-03-01 12:18:07 +01:00
Pierre Goiffon
e2c8237beb Allow params "limit" and "page" in REST-API
PR #25, code author Dennis Lassiter, many thanks !
Was commited to develop first but decided to retrofit this on support/2.5 (N°1449)
(cherry picked from commit fd55bdf9a8)
(cherry picked from commit 49e31ddb3d)
2019-02-28 10:06:42 +01:00
Pierre Goiffon
afb99c0f4b N°2054 fix search with sSearchValue GET param in BrowseBrick 2019-02-27 16:21:29 +01:00
Stephen Abello
c5943c6c28 Internal: Fix a regression introduced by 6b5cc7c on dot path 2019-02-22 10:06:10 +01:00
Pierre Goiffon
bc3b50ad23 Fix wrong method call 2019-02-22 10:00:23 +01:00
Pierre Goiffon
2f15bbdaf3 N°2033 backup : tar generation simplify buffer size computation
(cherry picked from commit 5b46644786)
2019-02-21 17:12:18 +01:00
Pierre Goiffon
cdba1e0d36 N°2033 backup : fix corrupted archive for files which size is a multiple of 1024 bytes
(cherry picked from commit 3356856a5f)
2019-02-20 17:29:10 +01:00
Eric
d0a766d424 N°1975 - Fix: Change Menu rights to "Admin only" leads in crash test
(cherry picked from commit a89bca4626)
2019-02-20 15:06:57 +01:00
Pierre Goiffon
23ec21e494 N°2031 backup : now logs using IssueLog, and remove debug config property 2019-02-19 14:46:44 +01:00
Pierre Goiffon
02617e8976 🔊 itop-backup : add some more logs 2019-02-19 12:21:53 +01:00
Stephen Abello
6b5cc7ca4b N°1877 & N°2012: Fix regression backup link on setup, security hardening 2019-02-18 10:40:51 +01:00
Eric
bf62b63173 N°1884 - Admin Tools Manager no longer has access to 'Schedule Backup' and 'Configuration' menus 2019-02-15 17:33:47 +01:00
Eric
b8fb1fa78a N°1884 - Admin Tools Manager no longer has access to 'Schedule Backup' and 'Configuration' menus
(cherry picked from commit 818b4d08da)
2019-02-15 17:31:37 +01:00
Stephen Abello
545504c0de (retrofit from master) N°1443 : Add table_id used by tables paging
(cherry picked from commit 43b0747b83)
2019-02-13 15:13:13 +01:00
Stephen Abello
32f1e97bcd (retrofit from master) N°1148: Fix regression on export
(cherry picked from commit 90e128f951)
2019-02-13 15:13:13 +01:00
Eric
9637e75f97 N°2011: Fix Issue with "ExecAsyncTask: async_task_retries" 2019-02-13 14:07:13 +01:00
787 changed files with 24744 additions and 42788 deletions

View File

@@ -1,9 +0,0 @@
[gitflow "branch"]
master = master
develop = develop
[gitflow "prefix"]
feature = feature/
release = release/
hotfix = hotfix/
versiontag =
support = support/

38
.gitignore vendored
View File

@@ -1,36 +1,37 @@
# no slash at the end to handle also symlinks
/toolkit
/conf/*
/env-*/*
/conf
/env-*
# composer reserver directory, from sources, populate/update using "composer install"
vendor/*
test/vendor/*
# all datas but listing prevention
data/*
!data/.htaccess
!data/index.php
!data/web.config
/data/**
!/data/.htaccess
!/data/index.php
!/data/web.config
# iTop extensions
extensions/*
!extensions/readme.txt
/extensions/**
!/extensions/readme.txt
# all logs but listing prevention
log/*
!log/.htaccess
!log/index.php
!log/web.config
/log/**
!/log/.htaccess
!/log/index.php
!/log/web.config
# Jetbrains
.idea/**
!.idea/encodings.xml
!.idea/codeStyles
!.idea/codeStyles/*
!.idea/inspectionProfiles
!.idea/inspectionProfiles/*
/.idea/**
!/.idea/encodings.xml
!/.idea/codeStyles
!/.idea/codeStyles/*
!/.idea/inspectionProfiles
!/.idea/inspectionProfiles/*
@@ -120,4 +121,3 @@ local.properties
.cache-main
.scala_dependencies
.worksheet

View File

@@ -1,11 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="LINE_SEPARATOR" value="&#10;" />
<option name="RIGHT_MARGIN" value="320" />
<HTMLCodeStyleSettings>
<option name="HTML_DO_NOT_INDENT_CHILDREN_OF" value="html,body,thead,tbody,tfoot,script,style" />
<option name="HTML_DO_NOT_ALIGN_CHILDREN_OF_MIN_LINES" value="4" />
</HTMLCodeStyleSettings>
<PHPCodeStyleSettings>
<option name="CONCAT_SPACES" value="false" />
<option name="PHPDOC_BLANK_LINE_BEFORE_TAGS" value="true" />
@@ -26,7 +20,6 @@
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="PHP">
<option name="RIGHT_MARGIN" value="320" />
<option name="BLANK_LINES_AFTER_PACKAGE" value="1" />
<option name="BRACE_STYLE" value="2" />
<option name="ELSE_ON_NEW_LINE" value="true" />
@@ -48,10 +41,5 @@
<option name="SMART_TABS" value="true" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="XML">
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

2
.idea/encodings.xml generated
View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8">
<component name="Encoding">
<file url="PROJECT" charset="UTF-8" />
</component>
</project>

View File

@@ -1,44 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Combodo" />
<inspection_tool class="InconsistentLineSeparators" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MysqlParsingInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PhpIncludeInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpMethodParametersCountMismatchInspection" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="PhpTooManyParametersInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="limit" value="7" />
</inspection_tool>
<inspection_tool class="PhpUndefinedClassInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="DONT_REPORT_MULTI_RESOLVE" value="true" />
</inspection_tool>
<inspection_tool class="PhpUndefinedMethodInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpUnhandledExceptionInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpUnusedLocalVariableInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="DONT_REPORT_INSIDE_LIST" value="true" />
</inspection_tool>
<inspection_tool class="PhpUnusedParameterInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="DONT_REPORT_ABSTRACT_CLASS" value="true" />
</inspection_tool>
<inspection_tool class="SqlAddNotNullColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlAmbiguousColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlAutoIncrementDuplicateInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlCheckUsingColumnsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlConstantConditionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDeprecateTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDerivedTableAliasInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDialectInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDropIndexedColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlIdentifierInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlInsertValuesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlNoDataSourceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlNullComparisonInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlPostgresqlSelectFromProcedureInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlResolveInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlShouldBeInGroupByInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlSideEffectsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlSignatureInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlStorageInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlUnusedVariableInspection" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

View File

@@ -1,19 +1,154 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="InconsistentLineSeparators" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PhpIncludeInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpMethodParametersCountMismatchInspection" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="PhpTooManyParametersInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="limit" value="7" />
<inspection_tool class="BladeControlDirectives" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CheckEmptyScriptTag" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CheckImageSize" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CheckNodeTest" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CheckTagEmptyBody" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CheckValidXmlInScriptTagBody" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CoffeeScriptArgumentsOutsideFunction" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CoffeeScriptFunctionSignatures" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="CoffeeScriptInfiniteLoop" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CoffeeScriptLiteralNotFunction" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CoffeeScriptSillyAssignment" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CoffeeScriptSwitchStatementWithNoDefaultBranch" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CoffeeScriptUnusedLocalSymbols" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ComposeFileStructure" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CssFloatPxLength" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="CssInvalidAtRule" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CssInvalidCharsetRule" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CssInvalidElement" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CssInvalidFunction" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CssInvalidHtmlTagReference" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CssInvalidImport" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CssInvalidMediaFeature" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CssInvalidPropertyValue" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CssInvalidPseudoSelector" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CssMissingComma" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CssNegativeValue" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CssNoGenericFontName" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CssOptimizeSimilarProperties" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="CssOverwrittenProperties" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CssRedundantUnit" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CssUnitlessNumber" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CssUnknownProperty" enabled="false" level="WARNING" enabled_by_default="false">
<option name="myCustomPropertiesEnabled" value="false" />
<option name="myIgnoreVendorSpecificProperties" value="false" />
<option name="myCustomPropertiesList">
<value>
<list size="0" />
</value>
</option>
</inspection_tool>
<inspection_tool class="PhpUndefinedClassInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="DONT_REPORT_MULTI_RESOLVE" value="true" />
<inspection_tool class="CssUnknownTarget" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CssUnresolvedClass" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CssUnresolvedCustomProperty" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CssUnresolvedCustomPropertySet" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CssUnusedSymbol" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CucumberExamplesColon" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CucumberMissedExamples" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CucumberTableInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="CucumberUndefinedStep" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DockerFileArgumentCount" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="DuplicateKeyInSection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DuplicateSectionInFile" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="EmptyEventHandler" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="FileHeaderInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="GherkinBrokenTableInspection" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="GherkinMisplacedBackground" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="HamlNestedTagContent" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="HardwiredNamespacePrefix" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="HtmlDeprecatedTag" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="HtmlExtraClosingTag" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="HtmlFormInputWithoutLabel" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="HtmlMissingClosingTag" enabled="false" level="INFORMATION" enabled_by_default="false" />
<inspection_tool class="HtmlPresentationalElement" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="HtmlUnknownAnchorTarget" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="HtmlUnknownAttribute" enabled="false" level="WARNING" enabled_by_default="false">
<option name="myValues">
<value>
<list size="0" />
</value>
</option>
<option name="myCustomValuesEnabled" value="true" />
</inspection_tool>
<inspection_tool class="PhpUnhandledExceptionInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpUnusedParameterInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="DONT_REPORT_ABSTRACT_CLASS" value="true" />
<inspection_tool class="HtmlUnknownBooleanAttribute" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="HtmlUnknownTag" enabled="false" level="WARNING" enabled_by_default="false">
<option name="myValues">
<value>
<list size="6">
<item index="0" class="java.lang.String" itemvalue="nobr" />
<item index="1" class="java.lang.String" itemvalue="noembed" />
<item index="2" class="java.lang.String" itemvalue="comment" />
<item index="3" class="java.lang.String" itemvalue="noscript" />
<item index="4" class="java.lang.String" itemvalue="embed" />
<item index="5" class="java.lang.String" itemvalue="script" />
</list>
</value>
</option>
<option name="myCustomValuesEnabled" value="true" />
</inspection_tool>
<inspection_tool class="HtmlUnknownTarget" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ImplicitTypeConversion" enabled="false" level="WARNING" enabled_by_default="false">
<option name="BITS" value="1720" />
<option name="FLAG_EXPLICIT_CONVERSION" value="true" />
<option name="IGNORE_NODESET_TO_BOOLEAN_VIA_STRING" value="true" />
</inspection_tool>
<inspection_tool class="IndexZeroUsage" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JSLastCommaInArrayLiteral" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JSLastCommaInObjectLiteral" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="JSUnresolvedFunction" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="JSUnresolvedVariable" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="LossyEncoding" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="MissingSinceTagDocInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="MysqlParsingInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="NonAsciiCharacters" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PhpDocMissingReturnTagInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="PhpDocMissingThrowsInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="PhpIncludeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PhpRedundantClosingTagInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="PhpUndefinedClassConstantInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PhpUndefinedClassInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PhpUndefinedConstantInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PhpUndefinedFieldInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PhpUndefinedFunctionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PhpUndefinedGotoLabelInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PhpUndefinedMethodInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PhpUndefinedNamespaceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="PhpUnusedParameterInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="RedundantTypeConversion" enabled="false" level="WARNING" enabled_by_default="false">
<option name="CHECK_ANY" value="false" />
</inspection_tool>
<inspection_tool class="RequiredAttributes" enabled="false" level="WARNING" enabled_by_default="false">
<option name="myAdditionalRequiredHtmlAttributes" value="" />
</inspection_tool>
<inspection_tool class="SqlAddNotNullColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlAmbiguousColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlAutoIncrementDuplicateInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlCheckUsingColumnsInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlConstantConditionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDeprecateTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDerivedTableAliasInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDialectInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlDropIndexedColumnInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlIdentifierInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlInsertValuesInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlNoDataSourceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlNullComparisonInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlPostgresqlSelectFromProcedureInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlResolveInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlShouldBeInGroupByInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlSignatureInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlStorageInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlTypeInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SqlUnusedVariableInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="TaskProblemsInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
<inspection_tool class="TypeScriptPreferShortImport" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="XmlDefaultAttributeValue" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="XmlUnboundNsPrefix" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="XmlUnusedNamespaceDeclaration" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="XsltUnusedDeclaration" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="XsltVariableShadowing" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

View File

@@ -1,7 +0,0 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="projectProfile" value="Combodo" />
<option name="PROJECT_PROFILE" value="Combodo" />
<version value="1.0" />
</settings>
</component>

View File

@@ -1,14 +0,0 @@
#!/usr/bin/env bash
set -x
# create target dirs
mkdir -p var
mkdir -p toolkit
# cleanup target dirs
rm -rf toolkit/*
# fill target dirs
curl http://www.combodo.com/documentation/iTopDataModelToolkit-2.3.zip | tar xvz --directory toolkit
cp -r .jenkins/configuration/default-environment/unattended_install/* toolkit

View File

@@ -1,11 +0,0 @@
#!/usr/bin/env bash
set -x
# on the root dir
composer install
# under the test dir
cd test
composer install

View File

@@ -1,13 +0,0 @@
#!/usr/bin/env bash
set -x
whoami
pwd
ls
echo "$BRANCH_NAME:${BRANCH_NAME}"
echo "printenv :"
printenv

View File

@@ -1,8 +0,0 @@
#!/usr/bin/env bash
set -x
cd test
export DEBUG_UNIT_TEST="0"
php vendor/bin/phpunit --log-junit ../var/test/phpunit-log.junit.xml --teamcity

View File

@@ -1,6 +0,0 @@
#!/usr/bin/env bash
set -x
cd toolkit
php unattended_install.php default-params.xml

View File

@@ -1,285 +0,0 @@
<?php
/**
*
* Configuration file, generated by the iTop configuration wizard
*
* The file is used in MetaModel::LoadConfig() which does all the necessary initialization job
*
*/
$MySettings = array(
// access_message: Message displayed to the users when there is any access restriction
// default: 'iTop is temporarily frozen, please wait... (the admin team)'
'access_message' => 'iTop is temporarily frozen, please wait... (the admin team)',
// access_mode: Access mode: ACCESS_READONLY = 0, ACCESS_ADMIN_WRITE = 2, ACCESS_FULL = 3
// default: 3
'access_mode' => 3,
'allowed_login_types' => 'form|basic|external',
// apc_cache.enabled: If set, the APC cache is allowed (the PHP extension must also be active)
// default: true
'apc_cache.enabled' => true,
// apc_cache.query_ttl: Time to live set in APC for the prepared queries (seconds - 0 means no timeout)
// default: 3600
'apc_cache.query_ttl' => 3600,
// app_root_url: Root URL used for navigating within the application, or from an email to the application (you can put $SERVER_NAME$ as a placeholder for the server's name)
// default: ''
'app_root_url' => 'http://127.0.0.1/itop/svn/trunk/',
// buttons_position: Position of the forms buttons: bottom | top | both
// default: 'both'
'buttons_position' => 'both',
// cas_include_path: The path where to find the phpCAS library
// default: '/usr/share/php'
'cas_include_path' => '/usr/share/php',
// cron_max_execution_time: Duration (seconds) of the page cron.php, must be shorter than php setting max_execution_time and shorter than the web server response timeout
// default: 600
'cron_max_execution_time' => 600,
// csv_file_default_charset: Character set used by default for downloading and uploading data as a CSV file. Warning: it is case sensitive (uppercase is preferable).
// default: 'ISO-8859-1'
'csv_file_default_charset' => 'ISO-8859-1',
'csv_import_charsets' => array (
),
// csv_import_history_display: Display the history tab in the import wizard
// default: false
'csv_import_history_display' => false,
// date_and_time_format: Format for date and time display (per language)
// default: array (
// 'default' =>
// array (
// 'date' => 'Y-m-d',
// 'time' => 'H:i:s',
// 'date_time' => '$date $time',
// ),
// )
'date_and_time_format' => array (
'default' =>
array (
'date' => 'Y-m-d',
'time' => 'H:i:s',
'date_time' => '$date $time',
),
'FR FR' =>
array (
'date' => 'd/m/Y',
'time' => 'H:i:s',
'date_time' => '$date $time',
),
),
'db_host' => '',
'db_name' => 'itop_ci_main',
'db_pwd' => 'IKnowYouSeeMeInJenkinsConf',
'db_subname' => '',
'db_user' => 'jenkins_itop',
// deadline_format: The format used for displaying "deadline" attributes: any string with the following placeholders: $date$, $difference$
// default: '$difference$'
'deadline_format' => '$difference$',
'default_language' => 'EN US',
// disable_attachments_download_legacy_portal: Disable attachments download from legacy portal
// default: true
'disable_attachments_download_legacy_portal' => true,
// draft_attachments_lifetime: Lifetime (in seconds) of drafts' attachments and inline images: after this duration, the garbage collector will delete them.
// default: 3600
'draft_attachments_lifetime' => 3600,
// email_asynchronous: If set, the emails are sent off line, which requires cron.php to be activated. Exception: some features like the email test utility will force the serialized mode
// default: false
'email_asynchronous' => false,
// email_default_sender_address: Default address provided in the email from header field.
// default: ''
'email_default_sender_address' => '',
// email_default_sender_label: Default label provided in the email from header field.
// default: ''
'email_default_sender_label' => '',
// email_transport: Mean to send emails: PHPMail (uses the function mail()) or SMTP (implements the client protocole)
// default: 'PHPMail'
'email_transport' => 'SMTP',
// email_transport_smtp.host: host name or IP address (optional)
// default: 'localhost'
'email_transport_smtp.host' => 'smtp.combodo.com',
// email_transport_smtp.password: Authentication password (optional)
// default: ''
'email_transport_smtp.password' => 'IDoNotWork',
// email_transport_smtp.port: port number (optional)
// default: 25
'email_transport_smtp.port' => 25,
// email_transport_smtp.username: Authentication user (optional)
// default: ''
'email_transport_smtp.username' => 'test2@combodo.com',
// email_validation_pattern: Regular expression to validate/detect the format of an eMail address
// default: '[a-zA-Z0-9._&\'-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z0-9-]{2,}'
'email_validation_pattern' => '[a-zA-Z0-9._&\'-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z0-9-]{2,}',
'encryption_key' => '@iT0pEncr1pti0n!',
'ext_auth_variable' => '$_SERVER[\'REMOTE_USER\']',
'fast_reload_interval' => '60',
// graphviz_path: Path to the Graphviz "dot" executable for graphing objects lifecycle
// default: '/usr/bin/dot'
'graphviz_path' => '/usr/bin/dot',
// inline_image_max_display_width: The maximum width (in pixels) when displaying images inside an HTML formatted attribute. Images will be displayed using this this maximum width.
// default: '250'
'inline_image_max_display_width' => 250,
// inline_image_max_storage_width: The maximum width (in pixels) when uploading images to be used inside an HTML formatted attribute. Images larger than the given size will be downsampled before storing them in the database.
// default: '1600'
'inline_image_max_storage_width' => 1600,
// link_set_attribute_qualifier: Link set from string: attribute qualifier (encloses both the attcode and the value)
// default: '\''
'link_set_attribute_qualifier' => '\'',
// link_set_attribute_separator: Link set from string: attribute separator
// default: ';'
'link_set_attribute_separator' => ';',
// link_set_item_separator: Link set from string: line separator
// default: '|'
'link_set_item_separator' => '|',
// link_set_value_separator: Link set from string: value separator (between the attcode and the value itself
// default: ':'
'link_set_value_separator' => ':',
'log_global' => true,
'log_issue' => true,
'log_notification' => true,
'log_web_service' => true,
// max_combo_length: The maximum number of elements in a drop-down list. If more then an autocomplete will be used
// default: 50
'max_combo_length' => 50,
'max_display_limit' => '15',
// max_linkset_output: Maximum number of items shown when getting a list of related items in an email, using the form $this->some_list$. 0 means no limit.
// default: 100
'max_linkset_output' => 100,
'min_display_limit' => '10',
// online_help: Hyperlink to the online-help web page
// default: 'http://www.combodo.com/itop-help'
'online_help' => 'http://www.combodo.com/itop-help',
// php_path: Path to the php executable in CLI mode
// default: 'php'
'php_path' => 'php',
// portal_tickets: CSV list of classes supported in the portal
// default: 'UserRequest'
'portal_tickets' => 'UserRequest',
'query_cache_enabled' => true,
// search_manual_submit: Force manual submit of search requests (class => true)
// default: false
'search_manual_submit' => array (
'Person' => true,
),
'secure_connection_required' => false,
// session_name: The name of the cookie used to store the PHP session id
// default: 'iTop'
'session_name' => 'iTop',
// shortcut_actions: Actions that are available as direct buttons next to the "Actions" menu
// default: 'UI:Menu:Modify,UI:Menu:New'
'shortcut_actions' => 'UI:Menu:Modify,UI:Menu:New',
// source_dir: Source directory for the datamodel files. (which gets compiled to env-production).
// default: ''
'source_dir' => 'datamodels/2.x/',
'standard_reload_interval' => '300',
// synchro_trace: Synchronization details: none, display, save (includes 'display')
// default: 'none'
'synchro_trace' => 'none',
// timezone: Timezone (reference: http://php.net/manual/en/timezones.php). If empty, it will be left unchanged and MUST be explicitely configured in PHP
// default: 'Europe/Paris'
'timezone' => 'Europe/Paris',
// tracking_level_linked_set_default: Default tracking level if not explicitely 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: 1
'tracking_level_linked_set_default' => 0,
// url_validation_pattern: Regular expression to validate/detect the format of an URL (URL attributes and Wiki formatting for Text attributes)
// default: '(https?|ftp)\\://([a-zA-Z0-9+!*(),;?&=\\$_.-]+(\\:[a-zA-Z0-9+!*(),;?&=\\$_.-]+)?@)?([a-zA-Z0-9-.]{3,})(\\:[0-9]{2,5})?(/([a-zA-Z0-9%+\\$_-]\\.?)+)*/?(\\?[a-zA-Z+&\\$_.-][a-zA-Z0-9;:[\\]@&%=+/\\$_.-]*)?(#[a-zA-Z_.-][a-zA-Z0-9+\\$_.-]*)?'
'url_validation_pattern' => '(https?|ftp)\\://([a-zA-Z0-9+!*(),;?&=\\$_.-]+(\\:[a-zA-Z0-9+!*(),;?&=\\$_.-]+)?@)?([a-zA-Z0-9-.]{3,})(\\:[0-9]{2,5})?(/([a-zA-Z0-9%+\\$_-]\\.?)+)*/?(\\?[a-zA-Z+&\\$_.-][a-zA-Z0-9;:[\\]@&%=+/\\$_.-]*)?(#[a-zA-Z_.-][a-zA-Z0-9+\\$_.-]*)?',
);
/**
*
* Modules specific settings
*
*/
$MyModuleSettings = array(
'itop-attachments' => array (
'allowed_classes' => array (
0 => 'Ticket',
),
'position' => 'relations',
'preview_max_width' => 290,
),
'itop-backup' => array (
'mysql_bindir' => '',
'week_days' => 'monday, tuesday, wednesday, thursday, friday',
'time' => '23:30',
'retention_count' => 5,
'enabled' => true,
'debug' => false,
),
'molkobain-console-tooltips' => array (
'decoration_class' => 'fas fa-question',
'enabled' => true,
),
);
/**
*
* Data model modules to be loaded. Names are specified as relative paths
*
*/
$MyModules = array(
'addons' => array (
'user rights' => 'addons/userrights/userrightsprofile.class.inc.php',
),
);
?>

View File

@@ -1,190 +0,0 @@
<?php
//this scrit will be run under the ./toolkit directory, relatively to the document root
require_once('../approot.inc.php');
require_once(APPROOT.'/application/utils.inc.php');
require_once(APPROOT.'/application/clipage.class.inc.php');
require_once(APPROOT.'/core/config.class.inc.php');
require_once(APPROOT.'/core/log.class.inc.php');
require_once(APPROOT.'/core/kpi.class.inc.php');
require_once(APPROOT.'/core/cmdbsource.class.inc.php');
require_once(APPROOT.'/setup/setuppage.class.inc.php');
require_once(APPROOT.'/setup/wizardcontroller.class.inc.php');
require_once(APPROOT.'/setup/wizardsteps.class.inc.php');
require_once(APPROOT.'/setup/applicationinstaller.class.inc.php');
/////////////////////////////////////////////////
$sParamFile = utils::ReadParam('response_file', 'default-params.xml', true /* CLI allowed */, 'raw_data');
$bCheckConsistency = (utils::ReadParam('check_consistency', '0', true /* CLI allowed */) == '1');
$oParams = new XMLParameters($sParamFile);
$sMode = $oParams->Get('mode');
if ($sMode == 'install')
{
echo "Installation mode detected.\n";
$bClean = utils::ReadParam('clean', false, true /* CLI allowed */);
if ($bClean)
{
echo "Cleanup mode detected.\n";
$sTargetEnvironment = $oParams->Get('target_env', '');
if ($sTargetEnvironment == '')
{
$sTargetEnvironment = 'production';
}
$sTargetDir = APPROOT.'env-'.$sTargetEnvironment;
// Configuration file
$sConfigFile = APPCONF.$sTargetEnvironment.'/'.ITOP_CONFIG_FILE;
if (file_exists($sConfigFile))
{
echo "Trying to delete the configuration file: '$sConfigFile'.\n";
@chmod($sConfigFile, 0770); // RWX for owner and group, nothing for others
unlink($sConfigFile);
}
else
{
echo "No config file to delete ($sConfigFile does not exist).\n";
}
// env-xxx directory
if (file_exists($sTargetDir))
{
if (is_dir($sTargetDir))
{
echo "Emptying the target directory '$sTargetDir'.\n";
SetupUtils::tidydir($sTargetDir);
}
else
{
die("ERROR the target dir '$sTargetDir' exists, but is NOT a directory !!!\nExiting.\n");
}
}
else
{
echo "No target directory to delete ($sTargetDir does not exist).\n";
}
// Database
$aDBSettings = $oParams->Get('database', array());
$sDBServer = $aDBSettings['server'];
$sDBUser = $aDBSettings['user'];
$sDBPwd = $aDBSettings['pwd'];
$sDBName = $aDBSettings['name'];
$sDBPrefix = $aDBSettings['prefix'];
if ($sDBPrefix != '')
{
die("Cleanup not implemented for a partial database (prefix= '$sDBPrefix')\nExiting.");
}
$oMysqli = new mysqli($sDBServer, $sDBUser, $sDBPwd);
if ($oMysqli->connect_errno)
{
die("Cannot connect to the MySQL server (".$mysqli->connect_errno . ") ".$mysqli->connect_error."\nExiting");
}
else
{
if ($oMysqli->select_db($sDBName))
{
echo "Deleting database '$sDBName'\n";
$oMysqli->query("DROP DATABASE `$sDBName`");
}
else
{
echo "The database '$sDBName' does not seem to exist. Nothing to cleanup.\n";
}
}
}
}
$bHasErrors = false;
$aChecks = SetupUtils::CheckBackupPrerequisites(APPROOT.'data'); // mmm should be the backup destination dir
$aSelectedModules = $oParams->Get('selected_modules');
$sSourceDir = $oParams->Get('source_dir', 'datamodels/latest');
$sExtensionDir = $oParams->Get('extensions_dir', 'extensions');
$aChecks = array_merge($aChecks, SetupUtils::CheckSelectedModules($sSourceDir, $sExtensionDir, $aSelectedModules));
foreach($aChecks as $oCheckResult)
{
switch($oCheckResult->iSeverity)
{
case CheckResult::ERROR:
$bHasErrors = true;
$sHeader = "Error";
break;
case CheckResult::WARNING:
$sHeader = "Warning";
break;
case CheckResult::INFO:
default:
$sHeader = "Info";
break;
}
echo $sHeader.": ".$oCheckResult->sLabel;
if (strlen($oCheckResult->sDescription))
{
echo ' - '.$oCheckResult->sDescription;
}
echo "\n";
}
if ($bHasErrors)
{
echo "Encountered stopper issues. Aborting...\n";
die;
}
$bFoundIssues = false;
$bInstall = utils::ReadParam('install', true, true /* CLI allowed */);
if ($bInstall)
{
echo "Starting the unattended installation...\n";
$oWizard = new ApplicationInstaller($oParams);
$bRes = $oWizard->ExecuteAllSteps();
if (!$bRes)
{
echo "\nencountered installation issues!";
$bFoundIssues = true;
}
}
else
{
echo "No installation requested.\n";
}
if (!$bFoundIssues && $bCheckConsistency)
{
echo "Checking data model consistency.\n";
ob_start();
$sCheckRes = '';
try
{
MetaModel::CheckDefinitions(false);
$sCheckRes = ob_get_clean();
}
catch(Exception $e)
{
$sCheckRes = ob_get_clean()."\nException: ".$e->getMessage();
}
if (strlen($sCheckRes) > 0)
{
echo $sCheckRes;
echo "\nfound consistency issues!";
$bFoundIssues = true;
}
}
if (!$bFoundIssues)
{
// last line: used to check the install
// the only way to track issues in case of Fatal error or even parsing error!
echo "\ninstalled!";
exit;
}

View File

@@ -1,105 +0,0 @@
# Contributing to iTop
You want to contribute to iTop? Many thanks to you! 🎉 👍
Here are some guidelines that will help us integrate your work!
## Contributions
### Subjects
You are welcome to create pull requests on any of those subjects:
* 🐛 `:bug:` bug fix
* 🔒 `:lock:` security
* 🌐 `:globe_with_meridians:` translation / i18n / l10n
If you want to implement a **new feature**, please [create a corresponding ticket](https://sourceforge.net/p/itop/tickets/new/) for review.
If you ever want to begin implementation, do so in a fork, and add a link to the corresponding commits in the ticket.
### License
iTop is distributed under the AGPL-3.0 license (see the [license.txt] file),
your code must comply with this license.
If you want to use another license, you may [create an extension][wiki new ext].
[license.txt]: https://github.com/Combodo/iTop/blob/develop/license.txt
[wiki new ext]: https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Astart#by_writing_your_own_extension
## Branch model
TL;DR:
> **create a fork from iTop main repository,
> create a branch based on either release branch if present, or develop otherwise**
We are using the [GitFlow](https://nvie.com/posts/a-successful-git-branching-model/) branch model. That means we have in our repo those
main branches:
- develop: ongoing development version
- release/\*: if present, that means we are working on a beta version
- master: previous stable version
For example, if no beta version is currently ongoing we could have:
- develop containing future 2.8.0 version
- master containing 2.7.x maintenance version
In this example, when 2.8.0-beta is shipped that will become:
- develop: future 2.9.0 version
- release/2.8: 2.8.0-beta
- master: 2.7.x maintenance version
And when 2.8.0 final will be out:
- develop: future 2.9.0 version
- master: 2.8.x maintenance version
- support/2.7 : 2.7.x maintenance version
## Coding
### PHP styleguide
Please follow [our guidelines](https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Acoding_standards).
### 🌐 Translations
A [dedicated page](https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Atranslation) is available in the official wiki.
### Tests
Please create tests that covers as much as possible the code you're submitting.
Our tests are located in the `test/` directory, containing a PHPUnit config file : `phpunit.xml.dist`.
### Git Commit Messages
* Describe the functional change instead of the technical modifications
* Use the present tense ("Add feature" not "Added feature")
* Use the imperative mood ("Move cursor to..." not "Moves cursor to...")
* Limit the first line to 72 characters or less
* Please start the commit message with an applicable emoji code (following the [Gitmoji guide](https://gitmoji.carloscuesta.me/)). For example :
* 🌐 `:globe_with_meridians:` for translations
* 🎨 `:art:` when improving the format/structure of the code
* ⚡️ `:zap:` when improving performance
* 🐛 `:bug:` when fixing a bug
* 🔥 `:fire:` when removing code or files
* 💚 `:green_heart:` when fixing the CI build
*`:white_check_mark:` when adding tests
* 🔒 `:lock:` when dealing with security
* ⬆️ `:arrow_up:` when upgrading dependencies
* ⬇️ `:arrow_down:` when downgrading dependencies
* ♻️ `:recycle:` code refactoring
* 💄 `:lipstick:` Updating the UI and style files.
## Pull request
When your code is working, please:
* stash as much as possible your commits,
* rebase your branch on our repo last commit,
* create a pull request.
Detailed procedure to work on fork and create PR is available [in GitHub help pages](https://help.github.com/articles/creating-a-pull-request-from-a-fork/).

70
Jenkinsfile vendored
View File

@@ -1,65 +1,11 @@
pipeline {
agent any
stages {
def infra
stage('init') {
parallel {
stage('debug') {
steps {
sh './.jenkins/bin/init/debug.sh'
}
}
stage('append files to project') {
steps {
sh './.jenkins/bin/init/append_files.sh'
}
}
stage('composer install') {
steps {
sh './.jenkins/bin/init/composer_install.sh'
}
}
}
}
node(){
checkout scm
stage('unattended_install') {
parallel {
stage('unattended_install default env') {
steps {
sh './.jenkins/bin/unattended_install/default_env.sh'
}
}
}
}
stage('test') {
parallel {
stage('phpunit') {
steps {
sh './.jenkins/bin/tests/phpunit.sh'
}
}
}
}
}
post {
always {
junit 'var/test/phpunit-log.junit.xml'
}
failure {
slackSend(channel: "#jenkins-itop", color: '#FF0000', message: "Ho no! Build failed! (${currentBuild.result}), Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})")
}
fixed {
slackSend(channel: "#jenkins-itop", color: '#FFa500', message: "Yes! Build repaired! (${currentBuild.result}), Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL})")
}
}
environment {
DEBUG_UNIT_TEST = '0'
}
options {
timeout(time: 20, unit: 'MINUTES')
}
infra = load '/var/lib/jenkins/workspace/itop-test-infra_master/src/Infra.groovy'
}
infra.call()

140
README.md
View File

@@ -1,140 +0,0 @@
<p align="center"><a href="https://www.combodo.com/itop-193" target="_blank">
<img src="https://www.combodo.com/logos/logo-itop.svg">
</a></p>
# iTop - ITSM & CMDB
iTop stands for *IT Operations Portal*.
It is a complete open source, ITIL, web based service management tool including a fully customizable CMDB, a helpdesk system and a document management tool.
iTop also offers mass import tools and web services to integrate with your IT
## Features
- Fully configurable [Configuration Management (CMDB)][10]
- [HelpDesk][11] and Incident Management
- [Service and Contract Management][12]
- [Change][13] Management
- Configurable [SLA][14] Management
- Graphical [impact analysis][15]
- [CSV import][16] tool for any data
- Consistency [audit][17] to check data quality
- [Data synchronization][18] (for data federation)
## Resources
- [iTop Forums][1]: for support request
- [iTop Tickets][2]: for feature requests and bug reports
- [Releases download][3]
- [iTop documentation][4] for iTop and official extensions
- [iTop extensions][5] for discovering and installing extensions
## Releases
### Version 2.6
- [Changes since the previous version][58]
- [New features][59]
- [Migration notes][60]
- [Download iTop 2.6.0][61]
### Version 2.5
- [Changes since the previous version][54]
- [New features][55]
- [Migration notes][56]
- [Download iTop 2.5.1][57]
### Version 2.4
- [Changes since the previous version][50]
- [New features][51]
- [Migration notes][52]
- [Download iTop 2.4.1][53]
# About Us
iTop development is sponsored, led and supported by [Combodo][0].
# Contributors
We would like to give a special thank you to the people from the community who contributed to this project, including:
- Alves, David
- Beck, Pedro
- Bilger, Jean-François
- Bostoen, Jeffrey
- Cardoso, Anderson
- Cassaro, Bruno
- Casteleyn, Thomas
- Castro, Randall Badilla
- Colantoni, Maria Laura
- Dvořák, Lukáš
- Goethals, Stefan
- Gumble, David
- Hippler, Lars
- Khamit, Shamil
- Konečný, Kamil
- Kunin, Vladimir
- Lassiter, Dennis
- Lucas, Jonathan
- Malik, Remie
- Rosenke, Stephan
- Seki, Shoji
- Shilov, Vladimir
- Tulio, Marco
- Turrubiates, Miguel
#### Aliases
- chifu1234
- cprobst
- Karkoff1212
- larhip
- Laura
- Purple Grape
- Schlobinux
- theBigOne
- ulmerspatz
#### Companies
- Hardis
- ITOMIG
[0]: https://www.combodo.com
[1]: https://sourceforge.net/p/itop/discussion/
[2]: https://sourceforge.net/p/itop/tickets/
[3]: https://sourceforge.net/projects/itop/files/itop/
[4]: https://www.itophub.io/wiki
[5]: https://store.itophub.io/en_US/
[10]: https://www.itophub.io/wiki/page?id=2_5_0%3Adatamodel%3Astart#configuration_management_cmdb
[11]: https://www.itophub.io/wiki/page?id=2_5_0%3Adatamodel%3Astart#ticketing
[12]: https://www.itophub.io/wiki/page?id=2_5_0%3Adatamodel%3Astart#service_management
[13]: https://www.itophub.io/wiki/page?id=2_5_0%3Adatamodel%3Astart#change_management
[14]: https://www.itophub.io/wiki/page?id=2_5_0%3Aimplementation%3Astart#service_level_agreements_and_targets
[15]: https://www.itophub.io/wiki/page?id=2_5_0%3Auser%3Aactions#relations
[16]: https://www.itophub.io/wiki/page?id=2_5_0%3Auser%3Abulk_modify#uploading_data
[17]: https://www.itophub.io/wiki/page?id=2_5_0%3Aadmin%3Aaudit
[18]: https://www.itophub.io/wiki/page?id=2_5_0%3Aadvancedtopics%3Adata_synchro_overview
[50]: https://www.itophub.io/wiki/page?id=2_4_0:release:change_log
[51]: https://www.itophub.io/wiki/page?id=2_4_0:release:2_4_whats_new
[52]: https://www.itophub.io/wiki/page?id=2_4_0:install:230_to_240_migration_notes
[53]: https://sourceforge.net/projects/itop/files/itop/2.4.1
[54]: https://www.itophub.io/wiki/page?id=2_5_0:release:change_log
[55]: https://www.itophub.io/wiki/page?id=2_5_0:release:2_5_whats_new
[56]: https://www.itophub.io/wiki/page?id=2_5_0:install:240_to_250_migration_notes
[57]: https://sourceforge.net/projects/itop/files/itop/2.5.1
[58]: https://www.itophub.io/wiki/page?id=2_6_0:release:change_log
[59]: https://www.itophub.io/wiki/page?id=2_6_0:release:2_6_whats_new
[60]: https://www.itophub.io/wiki/page?id=2_6_0:install:250_to_260_migration_notes
[61]: https://sourceforge.net/projects/itop/files/itop/2.6.0

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2018 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -20,7 +20,7 @@
/**
* Class ApplicationContext
*
* @copyright Copyright (C) 2010-2018 Combodo SARL
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -31,12 +31,6 @@ require_once(APPROOT."/application/utils.inc.php");
*/
interface iDBObjectURLMaker
{
/**
* @param string $sClass
* @param string $iId
*
* @return string
*/
public static function MakeObjectURL($sClass, $iId);
}
@@ -45,13 +39,6 @@ interface iDBObjectURLMaker
*/
class iTopStandardURLMaker implements iDBObjectURLMaker
{
/**
* @param string $sClass
* @param string $iId
*
* @return string
* @throws \Exception
*/
public static function MakeObjectURL($sClass, $iId)
{
$sPage = DBObject::ComputeStandardUIPage($sClass);
@@ -66,13 +53,6 @@ class iTopStandardURLMaker implements iDBObjectURLMaker
*/
class PortalURLMaker implements iDBObjectURLMaker
{
/**
* @param string $sClass
* @param string $iId
*
* @return string
* @throws \Exception
*/
public static function MakeObjectURL($sClass, $iId)
{
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
@@ -94,20 +74,10 @@ class PortalURLMaker implements iDBObjectURLMaker
*/
class ApplicationContext
{
public static $m_sUrlMakerClass = null;
protected static $m_aPluginProperties = null;
protected static $aDefaultValues; // Cache shared among all instances
protected $aNames;
protected $aValues;
/**
* ApplicationContext constructor.
*
* @param bool $bReadContext
*
* @throws \Exception
*/
protected static $aDefaultValues; // Cache shared among all instances
public function __construct($bReadContext = true)
{
$this->aNames = array(
@@ -119,13 +89,11 @@ class ApplicationContext
}
}
/**
* Read the context directly in the PHP parameters (either POST or GET)
* return nothing
*
* @throws \Exception
*/
/**
* Read the context directly in the PHP parameters (either POST or GET)
* return nothing
*/
protected function ReadContext()
{
if (!isset(self::$aDefaultValues))
@@ -142,26 +110,20 @@ class ApplicationContext
}
// Hmm, there must be a better (more generic) way to handle the case below:
// When there is only one possible (allowed) organization, the context must be
// fixed to this org unless there is only one organization in the system then
// no filter is applied
// fixed to this org
if ($sName == 'org_id')
{
if (MetaModel::IsValidClass('Organization'))
{
$oSearchFilter = new DBObjectSearch('Organization');
$oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
$oSet = new CMDBObjectSet($oSearchFilter);
$iCount = $oSet->CountWithLimit(2);
if ($iCount > 1)
if ($iCount == 1)
{
$oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
$oSet = new CMDBObjectSet($oSearchFilter);
$iCount = $oSet->CountWithLimit(2);
if ($iCount == 1)
{
// Only one possible value for org_id, set it in the context
$oOrg = $oSet->Fetch();
self::$aDefaultValues[$sName] = $oOrg->GetKey();
}
// Only one possible value for org_id, set it in the context
$oOrg = $oSet->Fetch();
self::$aDefaultValues[$sName] = $oOrg->GetKey();
}
}
}
@@ -169,15 +131,12 @@ class ApplicationContext
}
$this->aValues = self::$aDefaultValues;
}
/**
* Returns the current value for the given parameter
*
* @param string $sParamName Name of the parameter to read
* @param string $defaultValue
*
* @return mixed The value for this parameter
*/
/**
* Returns the current value for the given parameter
* @param string $sParamName Name of the parameter to read
* @return mixed The value for this parameter
*/
public function GetCurrentValue($sParamName, $defaultValue = '')
{
if (isset($this->aValues[$sParamName]))
@@ -189,7 +148,7 @@ class ApplicationContext
/**
* Returns the context as string with the format name1=value1&name2=value2....
* @return string The context as a string to be appended to an href property
* return string The context as a string to be appended to an href property
*/
public function GetForLink()
{
@@ -203,7 +162,7 @@ class ApplicationContext
/**
* Returns the context as sequence of input tags to be inserted inside a <form> tag
* @return string The context as a sequence of <input type="hidden" /> tags
* return string The context as a sequence of <input type="hidden" /> tags
*/
public function GetForForm()
{
@@ -217,7 +176,7 @@ class ApplicationContext
/**
* Returns the context as a hash array 'parameter_name' => value
* @return array The context information
* return array The context information
*/
public function GetAsHash()
{
@@ -240,7 +199,8 @@ class ApplicationContext
/**
* Removes the specified parameter from the context, for example when the same parameter
* is already a search parameter
* @param string $sParamName Name of the parameter to remove
* @param string $sParamName Name of the parameter to remove
* @return none
*/
public function Reset($sParamName)
{
@@ -252,11 +212,6 @@ class ApplicationContext
/**
* Initializes the given object with the default values provided by the context
*
* @param \DBObject $oObj
*
* @throws \Exception
* @throws \CoreUnexpectedValue
*/
public function InitObjectFromContext(DBObject &$oObj)
{
@@ -283,11 +238,13 @@ class ApplicationContext
}
}
}
static $m_sUrlMakerClass = null;
/**
* Set the current application url provider
* @param string $sClass Class implementing iDBObjectURLMaker
* @return string
* @param sClass string Class implementing iDBObjectURLMaker
* @return void
*/
public static function SetUrlMakerClass($sClass = 'iTopStandardURLMaker')
{
@@ -321,14 +278,7 @@ class ApplicationContext
/**
* Get the current application url provider
*
* @param string $sObjClass
* @param string $sObjKey
* @param null $sUrlMakerClass
* @param bool $bWithNavigationContext
*
* @return string the name of the class
* @throws \Exception
*/
public static function MakeObjectUrl($sObjClass, $sObjKey, $sUrlMakerClass = null, $bWithNavigationContext = true)
{
@@ -356,6 +306,8 @@ class ApplicationContext
}
}
protected static $m_aPluginProperties = null;
/**
* Load plugin properties for the current session
* @return void
@@ -374,9 +326,9 @@ class ApplicationContext
/**
* Set plugin properties
* @param string $sPluginClass Class implementing any plugin interface
* @param string $sProperty Name of the property
* @param mixed $value Value (numeric or string)
* @param sPluginClass string Class implementing any plugin interface
* @param sProperty string Name of the property
* @param value scalar Value (numeric or string)
* @return void
*/
public static function SetPluginProperty($sPluginClass, $sProperty, $value)
@@ -389,7 +341,7 @@ class ApplicationContext
/**
* Get plugin properties
* @param string $sPluginClass Class implementing any plugin interface
* @param sPluginClass string Class implementing any plugin interface
* @return array of sProperty=>value pairs
*/
public static function GetPluginProperties($sPluginClass)
@@ -407,3 +359,4 @@ class ApplicationContext
}
}
?>

View File

@@ -16,8 +16,6 @@
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
require_once(APPROOT.'application/newsroomprovider.class.inc.php');
/**
* Management of application plugins
*
@@ -124,8 +122,7 @@ interface iApplicationUIExtension
* Sorry, the verb has been reserved. You must implement it, but it is not called as of now.
*
* @param DBObject $oObject The object being displayed
*
* @return string[] desc
* @return type desc
*/
public function EnumUsedAttributes($oObject); // Not yet implemented
@@ -444,9 +441,8 @@ abstract class ApplicationPopupMenuItem
/**
* Returns the components to create a popup menu item in HTML
*
* @return array A hash array: array('label' => , 'url' => , 'target' => , 'onclick' => )
* @ignore
* @return Hash A hash array: array('label' => , 'url' => , 'target' => , 'onclick' => )
* @ignore
*/
abstract public function GetMenuItem();
@@ -763,15 +759,11 @@ interface iRestServiceProvider
* @return array An array of hash 'verb' => verb, 'description' => description
*/
public function ListOperations($sVersion);
/**
* Enumerate services delivered by this class
*
* @param string $sVersion The version (e.g. 1.0) supported by the services
* @param string $sVerb
* @param array $aParams
*
* @return RestResult The standardized result structure (at least a message)
* @throws Exception in case of internal failure.
*/
public function ExecOperation($sVersion, $sVerb, $aParams);
}
@@ -825,6 +817,10 @@ class RestResult
* Result: the requested operation cannot be performed because it can cause data (integrity) loss
*/
const UNSAFE = 12;
/**
* Result: the request page number is not valid. It must be an integer greater than 0
*/
const INVALID_PAGE = 13;
/**
* Result: the operation could not be performed, see the message for troubleshooting
*/
@@ -874,7 +870,7 @@ class RestUtils
* @param StdClass $oData Structured input data. Must contain the entry defined by sParamName.
* @param string $sParamName Name of the parameter to fetch from the input data
*
* @return mixed parameter value if present
* @return string
* @throws Exception If the parameter is missing
* @api
*/
@@ -897,8 +893,7 @@ class RestUtils
* @param StdClass $oData Structured input data.
* @param string $sParamName Name of the parameter to fetch from the input data
* @param mixed $default Default value if the parameter is not found in the input data
*
* @return mixed
* @return void
* @throws Exception
* @api
*/
@@ -942,8 +937,7 @@ class RestUtils
* @param string $sClass Name of the class
* @param StdClass $oData Structured input data.
* @param string $sParamName Name of the parameter to fetch from the input data
*
* @return array of class => list of attributes (see RestResultWithObjects::AddObject that uses it)
* @return An array of class => list of attributes (see RestResultWithObjects::AddObject that uses it)
* @throws Exception
* @api
*/
@@ -1091,10 +1085,13 @@ class RestUtils
*
* @param string $sClass Name of the class
* @param mixed $key Either search criteria (substructure), or an object or an OQL string.
* @param int $iLimit The limit of results to return
* @param int $iOffset The offset of results to return
*
* @return DBObjectSet The search result set
* @throws Exception If the input structure is not valid
*/
public static function GetObjectSetFromKey($sClass, $key)
public static function GetObjectSetFromKey($sClass, $key, $iLimit = 0, $iOffset = 0)
{
if (is_object($key))
{
@@ -1123,12 +1120,13 @@ class RestUtils
{
// OQL
$oSearch = DBObjectSearch::FromOQL($key);
$oObjectSet = new DBObjectSet($oSearch);
}
else
{
throw new Exception("Wrong format for key");
}
$oObjectSet = new DBObjectSet($oSearch);
$oObjectSet = new DBObjectSet($oSearch, array(), array(), null, $iLimit, $iOffset);
return $oObjectSet;
}
@@ -1171,14 +1169,6 @@ class RestUtils
}
$value = DBObjectSet::FromArray($sLnkClass, $aLinks);
}
elseif ($oAttDef instanceof AttributeTagSet)
{
if (!is_array($value))
{
throw new Exception("A tag set must be defined by an array of tag codes");
}
$value = $oAttDef->FromJSONToValue($value);
}
else
{
$value = $oAttDef->FromJSONToValue($value);

File diff suppressed because it is too large Load Diff

View File

@@ -21,7 +21,6 @@ require_once(APPROOT.'application/dashlet.class.inc.php');
require_once(APPROOT.'core/modelreflection.class.inc.php');
/**
*
* A user editable dashboard page
*
* @copyright Copyright (C) 2010-2017 Combodo SARL
@@ -50,11 +49,6 @@ abstract class Dashboard
$this->sId = $sId;
}
/**
* @param $sXml
*
* @throws \Exception
*/
public function FromXml($sXml)
{
$this->aCells = array(); // reset the content of the dashboard
@@ -106,10 +100,10 @@ abstract class Dashboard
$oCellsList = $oCellsNode->getElementsByTagName('cell');
$aCellOrder = array();
$iCellRank = 0;
/** @var \DOMElement $oCellNode */
foreach($oCellsList as $oCellNode)
{
$oCellRank = $oCellNode->getElementsByTagName('rank')->item(0);
$aDashletList = array();
$oCellRank = $oCellNode->getElementsByTagName('rank')->item(0);
if ($oCellRank)
{
$iCellRank = (float)$oCellRank->textContent;
@@ -119,7 +113,6 @@ abstract class Dashboard
$oDashletList = $oDashletsNode->getElementsByTagName('dashlet');
$iRank = 0;
$aDashletOrder = array();
/** @var \DOMElement $oDomNode */
foreach($oDashletList as $oDomNode)
{
$oRank = $oDomNode->getElementsByTagName('rank')->item(0);
@@ -152,11 +145,6 @@ abstract class Dashboard
}
}
/**
* @param \DOMElement $oDomNode
*
* @return mixed
*/
protected function InitDashletFromDOMNode($oDomNode)
{
$sId = $oDomNode->getAttribute('id');
@@ -164,8 +152,7 @@ abstract class Dashboard
// Test if dashlet can be instanciated, otherwise (uninstalled, broken, ...) we display a placeholder
$sClass = static::GetDashletClassFromType($sDashletType);
/** @var \Dashlet $oNewDashlet */
$oNewDashlet = new $sClass($this->oMetaModel, $sId);
$oNewDashlet = new $sClass($this->oMetaModel, $sId);
$oNewDashlet->SetDashletType($sDashletType);
$oNewDashlet->FromDOMNode($oDomNode);
@@ -176,17 +163,8 @@ abstract class Dashboard
{
return ($aItem1['rank'] > $aItem2['rank']) ? +1 : -1;
}
/**
* Error handler to turn XML loading warnings into exceptions
*
* @param $errno
* @param $errstr
* @param $errfile
* @param $errline
*
* @return bool
* @throws \DOMException
*/
public static function ErrorHandler($errno, $errstr, $errfile, $errline)
{
@@ -216,12 +194,8 @@ abstract class Dashboard
return $sXml;
}
/**
* @param \DOMElement $oDefinition
*/
public function ToDOMNode($oDefinition)
{
/** @var \DOMDocument $oDoc */
$oDoc = $oDefinition->ownerDocument;
$oNode = $oDoc->createElement('layout', $this->sLayoutClass);
@@ -253,7 +227,6 @@ abstract class Dashboard
$iDashletRank = 0;
$oDashletsNode = $oDoc->createElement('dashlets');
$oCellNode->appendChild($oDashletsNode);
/** @var \Dashlet $oDashlet */
foreach ($aCell as $oDashlet)
{
$oNode = $oDoc->createElement('dashlet');
@@ -283,7 +256,6 @@ abstract class Dashboard
{
$sDashletClass = $aDashletParams['dashlet_class'];
$sId = $aDashletParams['dashlet_id'];
/** @var \Dashlet $oNewDashlet */
$oNewDashlet = new $sDashletClass($this->oMetaModel, $sId);
if (isset($aDashletParams['dashlet_type']))
{
@@ -346,28 +318,31 @@ abstract class Dashboard
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int)$iAutoReloadSec);
}
/**
* @param \Dashlet $oDashlet
*/
public function AddDashlet($oDashlet)
{
$sId = $this->GetNewDashletId();
$oDashlet->SetId($sId);
$this->aCells[] = array($oDashlet);
}
/**
* @param \WebPage $oPage *
* @param array $aExtraParams
*
* @throws \ReflectionException
*/
public function RenderProperties($oPage, $aExtraParams = array())
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
{
$oPage->add('<h1>'.htmlentities(Dict::S($this->sTitle), ENT_QUOTES, 'UTF-8', false).'</h1>');
$oLayout = new $this->sLayoutClass;
$oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
if (!$bEditMode)
{
$oPage->add_linked_script('../js/dashlet.js');
$oPage->add_linked_script('../js/dashboard.js');
}
}
public function RenderProperties($oPage)
{
// menu to pick a layout and edit other properties of the dashboard
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Properties').'</div>');
$sUrl = utils::GetAbsoluteUrlAppRoot();
$oPage->add('<div style="text-align:center">'.Dict::S('UI:DashboardEdit:Layout').'</div>');
$oPage->add('<div id="select_layout" style="text-align:center">');
foreach( get_declared_classes() as $sLayoutClass)
@@ -385,13 +360,13 @@ abstract class Dashboard
}
}
$oPage->add('</div>');
$oForm = new DesignerForm();
$oField = new DesignerHiddenField('dashboard_id', '', $this->sId);
$oForm->AddField($oField);
$oField = new DesignerTextField('dashboard_title', Dict::S('UI:DashboardEdit:DashboardTitle'), $this->sTitle);
$oField = new DesignerLongTextField('dashboard_title', Dict::S('UI:DashboardEdit:DashboardTitle'), $this->sTitle);
$oForm->AddField($oField);
$oField = new DesignerBooleanField('auto_reload', Dict::S('UI:DashboardEdit:AutoReload'), $this->bAutoReload);
@@ -402,8 +377,8 @@ abstract class Dashboard
$oForm->AddField($oField);
$this->SetFormParams($oForm, $aExtraParams);
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
$this->SetFormParams($oForm);
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
$oPage->add('</div>');
@@ -447,28 +422,8 @@ abstract class Dashboard
EOF
);
}
/**
* @param \iTopWebPage $oPage
* @param bool $bEditMode
* @param array $aExtraParams
* @param bool $bCanEdit
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
{
$oPage->add('<div class="dashboard-title-line"><div class="dashboard-title">'.htmlentities(Dict::S($this->sTitle), ENT_QUOTES, 'UTF-8', false).'</div></div>');
$oLayout = new $this->sLayoutClass;
/** @var \DashboardLayoutMultiCol $oLayout */
$oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
if (!$bEditMode)
{
$oPage->add_linked_script('../js/dashlet.js');
$oPage->add_linked_script('../js/dashboard.js');
}
}
public function RenderDashletsSelection(WebPage $oPage)
public function RenderDashletsSelection($oPage)
{
// Toolbox/palette to drag and drop dashlets
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Dashlets').'</div>');
@@ -486,7 +441,7 @@ EOF
$oPage->add_ready_script("$('.dashlet_icon').draggable({helper: 'clone', appendTo: 'body', zIndex: 10000, revert:'invalid'});");
}
public function RenderDashletsProperties(WebPage $oPage, $aExtraParams = array())
public function RenderDashletsProperties($oPage)
{
// Toolbox/palette to edit the properties of each dashlet
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:DashletProperties').'</div>');
@@ -494,15 +449,15 @@ EOF
$oPage->add('<div id="dashlet_properties" style="text-align:center">');
foreach($this->aCells as $aCell)
{
/** @var \Dashlet $oDashlet */
foreach($aCell as $oDashlet)
{
$sId = $oDashlet->GetID();
$sClass = get_class($oDashlet);
if ($oDashlet->IsVisible())
{
$oPage->add('<div class="dashlet_properties" id="dashlet_properties_'.$sId.'" style="display:none">');
$oForm = $oDashlet->GetForm();
$this->SetFormParams($oForm, $aExtraParams);
$this->SetFormParams($oForm);
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
$oPage->add('</div>');
}
@@ -517,7 +472,6 @@ EOF
* Return an array of dashlets available for selection.
*
* @return array
* @throws \ReflectionException
*/
protected function GetAvailableDashlets()
{
@@ -551,7 +505,6 @@ EOF
$iNewId = 0;
foreach($this->aCells as $aDashlets)
{
/** @var \Dashlet $oDashlet */
foreach($aDashlets as $oDashlet)
{
$iNewId = max($iNewId, (int)$oDashlet->GetID());
@@ -559,14 +512,8 @@ EOF
}
return $iNewId + 1;
}
/**
* @param $oForm
* @param array $aExtraParams
*
* @return mixed
*/
abstract protected function SetFormParams($oForm, $aExtraParams = array());
abstract protected function SetFormParams($oForm);
public static function GetDashletClassFromType($sType, $oFactory = null)
{
@@ -576,22 +523,11 @@ EOF
}
return 'DashletUnknown';
}
/**
* @return mixed
*/
public function GetId()
{
return $this->sId;
}
}
class RuntimeDashboard extends Dashboard
{
protected $bCustomized;
private $sDefinitionFile = '';
private $sReloadURL = null;
public function __construct($sId)
{
@@ -604,17 +540,10 @@ class RuntimeDashboard extends Dashboard
{
$this->bCustomized = $bCustomized;
}
/**
* @param \DesignerForm $oForm
*
* @param array $aExtraParams
*
* @throws \Exception
*/
protected function SetFormParams($oForm, $aExtraParams = array())
protected function SetFormParams($oForm)
{
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property', 'extra_params' => $aExtraParams));
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property'));
}
public function Save()
@@ -658,265 +587,41 @@ class RuntimeDashboard extends Dashboard
utils::PopArchiveMode();
}
}
/**
* @param string $sDashboardFile file name relative to the current module folder
* @param string $sDashBoardId code of the dashboard either menu_id or <class>__<attcode>
*
* @return null|RuntimeDashboard
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
public static function GetDashboard($sDashboardFile, $sDashBoardId)
{
$bCustomized = false;
if (!appUserPreferences::GetPref('display_original_dashboard_'.$sDashBoardId, false))
{
// Search for an eventual user defined dashboard
$oUDSearch = new DBObjectSearch('UserDashboard');
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oUDSearch->AddCondition('menu_code', $sDashBoardId, '=');
$oUDSet = new DBObjectSet($oUDSearch);
if ($oUDSet->Count() > 0)
{
// Assuming there is at most one couple {user, menu}!
$oUserDashboard = $oUDSet->Fetch();
$sDashboardDefinition = $oUserDashboard->Get('contents');
$bCustomized = true;
}
else
{
$sDashboardDefinition = @file_get_contents($sDashboardFile);
}
}
else
{
$sDashboardDefinition = @file_get_contents($sDashboardFile);
}
if ($sDashboardDefinition !== false)
{
$oDashboard = new RuntimeDashboard($sDashBoardId);
$oDashboard->FromXml($sDashboardDefinition);
$oDashboard->SetCustomFlag($bCustomized);
$oDashboard->SetDefinitionFile($sDashboardFile);
}
else
{
$oDashboard = null;
}
return $oDashboard;
}
/**
* @param \iTopWebPage $oPage
* @param bool $bEditMode
* @param array $aExtraParams (class and id of the current object
*
* @throws \Exception
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
{
if (!isset($aExtraParams['query_params']) && isset($aExtraParams['this->class']))
{
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
$aRenderParams = array('query_params' => $oObj->ToArgsForQuery());
}
else
{
$aRenderParams = $aExtraParams;
}
parent::Render($oPage, $bEditMode, $aRenderParams);
if (isset($aExtraParams['query_params']['this->object()']))
{
/** @var \DBObject $oObj */
$oObj = $aExtraParams['query_params']['this->object()'];
$aAjaxParams = array('this->class' => get_class($oObj), 'this->id' => $oObj->GetKey());
}
else
{
$aAjaxParams = $aExtraParams;
}
if (!$bEditMode && !$oPage->IsPrintableVersion())
{
$sId = $this->GetId();
$sDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $sId);
if ($this->GetAutoReload())
{
$sFile = addslashes($this->GetDefinitionFile());
$sExtraParams = json_encode($aAjaxParams);
$iReloadInterval = 1000 * $this->GetAutoReloadInterval();
$sReloadURL = $this->GetReloadURL();
$oPage->add_script(
<<<EOF
if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined')
{
clearInterval(AutoReloadDashboardId$sDivId);
delete AutoReloadDashboardId$sDivId;
}
AutoReloadDashboardId$sDivId = setInterval("ReloadDashboard$sDivId();", $iReloadInterval);
function ReloadDashboard$sDivId()
{
// Do not reload when a dialog box is active
if (!($('.ui-dialog:visible').length > 0) && $('.dashboard_contents#$sDivId').is(':visible'))
{
$('.dashboard_contents#$sDivId').block();
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
{ operation: 'reload_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL'},
function(data){
$('.dashboard_contents#$sDivId').html(data);
$('.dashboard_contents#$sDivId').unblock();
}
);
}
}
EOF
);
}
else
{
$oPage->add_script(
<<<EOF
if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined')
{
clearInterval(AutoReloadDashboardId$sDivId);
delete AutoReloadDashboardId$sDivId;
}
EOF
);
}
if ($bCanEdit)
{
$this->RenderSelector($oPage, $aAjaxParams);
$this->RenderEditionTools($oPage, $aAjaxParams);
}
}
}
/**
* @param \iTopWebPage $oPage
* @param array $aAjaxParams
*/
protected function RenderSelector($oPage, $aAjaxParams = array())
{
$sId = $this->GetId();
$sDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $sId);
$sExtraParams = json_encode($aAjaxParams);
$sSelectorHtml = '<div class="dashboard-selector">';
if ($this->HasCustomDashboard())
{
$bStandardSelected = appUserPreferences::GetPref('display_original_dashboard_'.$sId, false);
$sStandard = Dict::S('UI:Toggle:StandardDashboard');
$sSelectorHtml .= '<div class="selector-label">'.$sStandard.'</div>';
$sSelectorHtml .= '<label class="switch"><input type="checkbox" onchange="ToggleDashboardSelector'.$sDivId.'();" '.($bStandardSelected ? '' : 'checked').'><span class="slider round"></span></label></input></label>';
$sCustom = Dict::S('UI:Toggle:CustomDashboard');
$sSelectorHtml .= '<div class="selector-label">'.$sCustom.'</div>';
}
$sSelectorHtml .= '</div>';
$sSelectorHtml = addslashes($sSelectorHtml);
$sFile = addslashes($this->GetDefinitionFile());
$sReloadURL = $this->GetReloadURL();
$oPage->add_ready_script(
<<<EOF
$('.dashboard-title').after('$sSelectorHtml');
EOF
);
$oPage->add_script(
<<<EOF
function ToggleDashboardSelector$sDivId()
{
$('.dashboard_contents#$sDivId').block();
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
{ operation: 'toggle_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL' },
function(data) {
$('.dashboard_contents#$sDivId').html(data);
$('.dashboard_contents#$sDivId').unblock();
}
);
}
EOF
);
}
protected function HasCustomDashboard()
{
try
{
// Search for an eventual user defined dashboard
$oUDSearch = new DBObjectSearch('UserDashboard');
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oUDSearch->AddCondition('menu_code', $this->GetId(), '=');
$oUDSet = new DBObjectSet($oUDSearch);
return ($oUDSet->Count() > 0);
}
catch (Exception $e)
{
return false;
}
}
/**
* @param \WebPage $oPage
* @param array $aExtraParams
*
* @throws \Exception
*/
protected function RenderEditionTools(WebPage $oPage, $aExtraParams)
public function RenderEditionTools($oPage)
{
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.iframe-transport.js');
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.fileupload.js');
$sEditMenu = "<div id=\"DashboardMenu\"><ul><li><img src=\"../images/pencil-menu.png\"><ul>";
$sEditMenu = "<td><span id=\"DashboardMenu\"><ul><li><img src=\"../images/pencil-menu.png\"><ul>";
$aActions = array();
$sFile = addslashes($this->sDefinitionFile);
$sJSExtraParams = json_encode($aExtraParams);
$bCanEdit = true;
if ($this->HasCustomDashboard())
{
$bCanEdit = !appUserPreferences::GetPref('display_original_dashboard_'.$this->GetId(), false);
}
if ($bCanEdit)
{
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:Edit'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
}
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:Edit'), "return EditDashboard('{$this->sId}')");
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
if ($this->bCustomized)
{
$oRevert = new JSPopupMenuItem('UI:Dashboard:RevertConfirm', Dict::S('UI:Dashboard:Revert'),
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}', $sJSExtraParams); else return false");
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}'); else return false");
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
}
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions);
$sEditMenu .= $oPage->RenderPopupMenuItems($aActions);
$sEditMenu = addslashes($sEditMenu);
$sReloadURL = $this->GetReloadURL();
//$sEditBtn = addslashes('<div style="display: inline-block; height: 55px; width:200px;vertical-align:center;line-height:60px;text-align:left;"><button onclick="EditDashboard(\''.$this->sId.'\');">Edit This Page</button></div>');
$oPage->add_ready_script(
<<<EOF
$('.dashboard-title').after('$sEditMenu');
$('#logOffBtn').parent().before('$sEditMenu');
$('#DashboardMenu>ul').popupmenu();
EOF
);
$oPage->add_script(
<<<EOF
function EditDashboard(sId, sDashboardFile, aExtraParams)
function EditDashboard(sId)
{
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'dashboard_editor', id: sId, file: sDashboardFile, extra_params: aExtraParams, reload_url: '$sReloadURL'},
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'dashboard_editor', id: sId},
function(data)
{
$('body').append(data);
@@ -924,12 +629,12 @@ function EditDashboard(sId, sDashboardFile, aExtraParams)
);
return false;
}
function RevertDashboard(sId, aExtraParams)
function RevertDashboard(sId)
{
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'revert_dashboard', dashboard_id: sId, extra_params: aExtraParams, reload_url: '$sReloadURL'},
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'revert_dashboard', dashboard_id: sId},
function(data)
{
location.reload();
$('body').append(data);
}
);
return false;
@@ -938,14 +643,9 @@ EOF
);
}
/**
* @param \WebPage $oPage
*
* @throws \ReflectionException
*/
public function RenderProperties($oPage, $aExtraParams = array())
public function RenderProperties($oPage)
{
parent::RenderProperties($oPage, $aExtraParams);
parent::RenderProperties($oPage);
$oPage->add_ready_script(
<<<EOF
@@ -976,36 +676,16 @@ EOF
}
/**
* @param \iTopWebPage $oPage
*
* @param array $aExtraParams
*
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \ReflectionException
* @throws \Exception
*/
public function RenderEditor($oPage, $aExtraParams = array())
public function RenderEditor($oPage)
{
if (isset($aExtraParams['this->class']))
{
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
$aRenderParams = array('query_params' => $oObj->ToArgsForQuery());
}
else
{
$aRenderParams = $aExtraParams;
}
$sJSExtraParams = json_encode($aExtraParams);
$oPage->add('<div id="dashboard_editor">');
$oPage->add('<div class="ui-layout-center">');
$this->Render($oPage, true, $aRenderParams);
$this->Render($oPage, true);
$oPage->add('</div>');
$oPage->add('<div class="ui-layout-east">');
$this->RenderProperties($oPage, $aExtraParams);
$this->RenderProperties($oPage);
$this->RenderDashletsSelection($oPage);
$this->RenderDashletsProperties($oPage, $aExtraParams);
$this->RenderDashletsProperties($oPage);
$oPage->add('</div>');
$oPage->add('<div id="event_bus"/>'); // For exchanging messages between the panes, same as in the designer
$oPage->add('</div>');
@@ -1019,9 +699,7 @@ EOF
$sAutoReload = $this->bAutoReload ? 'true' : 'false';
$sAutoReloadSec = (string) $this->iAutoReloadSec;
$sTitle = addslashes($this->sTitle);
$sFile = addslashes($this->GetDefinitionFile());
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
$sReloadURL = $this->GetReloadURL();
$sExitConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage'));
$sCancelConfirmationMessage = addslashes(Dict::S('UI:CancelConfirmationMessage'));
@@ -1051,7 +729,7 @@ $('#dashboard_editor').dialog({
}
}
window.bLeavingOnUserAction = true;
oDashboard.save($(this));
oDashboard.save();
} },
{ text: "$sCancelButtonLabel", click: function() {
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
@@ -1073,8 +751,8 @@ $('#dashboard_editor').dialog({
$('#dashboard_editor .ui-layout-center').runtimedashboard({
dashboard_id: '$sId', layout_class: '$sLayoutClass', title: '$sTitle',
auto_reload: $sAutoReload, auto_reload_sec: $sAutoReloadSec,
submit_to: '$sUrl', submit_parameters: {operation: 'save_dashboard', file: '$sFile', extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
render_to: '$sUrl', render_parameters: {operation: 'render_dashboard', file: '$sFile', extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
submit_to: '$sUrl', submit_parameters: {operation: 'save_dashboard'},
render_to: '$sUrl', render_parameters: {operation: 'render_dashboard'},
new_dashlet_parameters: {operation: 'new_dashlet'}
});
@@ -1157,8 +835,7 @@ EOF
$sParentId = $aParentMenu['parent'];
$aParentMenu = $aParentMenus[$sParentId];
}
/** @var \MenuNode $oParentMenu */
$oParentMenu = $aParentMenu['node'];
$oParentMenu = $aParentMenu['node'];
if ($oMenu->IsEnabled() && $oParentMenu->IsEnabled())
{
$sMenuLabel = $oMenu->GetTitle();
@@ -1213,7 +890,6 @@ EOF
{
$oSubForm = new DesignerForm();
$oMetaModel = new ModelReflectionRuntime();
/** @var \Dashlet $oDashlet */
$oDashlet = new $sDashletClass($oMetaModel, 0);
$oDashlet->GetPropertiesFieldsFromOQL($oSubForm, $sOQL);
@@ -1224,11 +900,7 @@ EOF
return $oForm;
}
/**
* @param \WebPage $oPage
* @param $sOQL
*/
public static function GetDashletCreationDlgFromOQL($oPage, $sOQL)
{
$oPage->add('<div id="dashlet_creation_dlg">');
@@ -1275,30 +947,4 @@ $('#dashlet_creation_dlg').dialog({
EOF
);
}
/**
* @return string
*/
public function GetDefinitionFile()
{
return $this->sDefinitionFile;
}
/**
* @param string $sDefinitionFile
*/
public function SetDefinitionFile($sDefinitionFile)
{
$this->sDefinitionFile = $sDefinitionFile;
}
public function GetReloadURL()
{
return $this->sReloadURL;
}
public function SetReloadURL($sReloadURL)
{
$this->sReloadURL = $sReloadURL;
}
}

View File

@@ -59,7 +59,6 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
$bNoVisibleFound = true;
while($idx < count($aKeys) && $bNoVisibleFound)
{
/** @var \Dashlet $oDashlet */
$oDashlet = $aDashlets[$aKeys[$idx]];
if ($oDashlet->IsVisible())
{
@@ -99,13 +98,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
return $aCells;
}
/**
* @param \WebPage $oPage
* @param $aCells
* @param bool $bEditMode
* @param array $aExtraParams
*/
public function Render($oPage, $aCells, $bEditMode = false, $aExtraParams = array())
{
// Trim the list of cells to remove the invisible/empty ones at the end of the array
@@ -129,7 +122,6 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
$aDashlets = $aCells[$iCellIdx];
if (count($aDashlets) > 0)
{
/** @var \Dashlet $oDashlet */
foreach($aDashlets as $oDashlet)
{
if ($oDashlet->IsVisible())

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.6">
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.5">
<portals>
<portal id="legacy_portal" _delta="define">
<url>portal/index.php</url>

View File

@@ -756,10 +756,6 @@ class DataTableSettings implements Serializable
{
foreach($this->aClassAliases as $sAlias => $sClass)
{
if (!isset($this->aColumns[$sAlias]))
{
continue;
}
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
{
// Remove non-existent columns
@@ -775,7 +771,7 @@ class DataTableSettings implements Serializable
$aTempData = array();
foreach($aList as $sAttCode => $oAttDef)
{
if ( (!array_key_exists($sAttCode, $this->aColumns[$sAlias])) && (!($oAttDef instanceof AttributeLinkedSet || $oAttDef instanceof AttributeDashboard)))
if ( (!array_key_exists($sAttCode, $this->aColumns[$sAlias])) && (!$oAttDef instanceof AttributeLinkSet))
{
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, false /* bChecked */, 'none');
if ($aFieldData) $aTempData[$aFieldData['label']] = $aFieldData;

View File

@@ -220,26 +220,9 @@ class DisplayBlock
$aExtraParams['currentId'] = $sId;
$sExtraParams = addslashes(str_replace('"', "'", json_encode($aExtraParams))); // JSON encode, change the style of the quotes and escape them
if (isset($aExtraParams['query_params']))
{
$aQueryParams = $aExtraParams['query_params'];
}
else
{
if (isset($aExtraParams['this->id']) && isset($aExtraParams['this->class']))
{
$sClass = $aExtraParams['this->class'];
$iKey = $aExtraParams['this->id'];
$oObj = MetaModel::GetObject($sClass, $iKey);
$aQueryParams = array('this->object()' => $oObj);
}
else
{
$aQueryParams = array();
}
}
$sFilter = addslashes($this->m_oFilter->serialize(false, $aQueryParams)); // Used either for asynchronous or auto_reload
$sFilter = $this->m_oFilter->serialize(); // Used either for asynchronous or auto_reload
if (!$this->m_bAsynchronous)
{
// render now
@@ -331,31 +314,20 @@ class DisplayBlock
* @throws MySQLException
* @throws Exception
*/
public function GetRenderContent(WebPage $oPage, $aExtraParams, $sId)
public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
{
$sHtml = '';
// Add the extra params into the filter if they make sense for such a filter
$bDoSearch = utils::ReadParam('dosearch', false);
$aQueryParams = array();
if (isset($aExtraParams['query_params']))
{
$aQueryParams = $aExtraParams['query_params'];
}
else
{
if (isset($aExtraParams['this->id']) && isset($aExtraParams['this->class']))
{
$sClass = $aExtraParams['this->class'];
$iKey = $aExtraParams['this->id'];
$oObj = MetaModel::GetObject($sClass, $iKey);
$aQueryParams = array('this->object()' => $oObj);
}
}
if ($this->m_oSet == null)
{
$aQueryParams = array();
if (isset($aExtraParams['query_params']))
{
$aQueryParams = $aExtraParams['query_params'];
}
// In case of search, the context filtering is done by the search itself
if (($this->m_sStyle != 'links') && ($this->m_sStyle != 'search') && ($this->m_sStyle != 'list_search'))
if (($this->m_sStyle != 'links') && ($this->m_sStyle != 'search'))
{
$oAppContext = new ApplicationContext();
$sClass = $this->m_oFilter->GetClass();
@@ -485,15 +457,7 @@ class DisplayBlock
$oSubsetSearch = $this->m_oFilter->DeepClone();
$oCondition = new BinaryExpression($oGroupByExp, '=', new ScalarExpression($aValues[$iRow]));
$oSubsetSearch->AddConditionExpression($oCondition);
if (isset($aExtraParams['query_params']))
{
$aQueryParams = $aExtraParams['query_params'];
}
else
{
$aQueryParams = array();
}
$sFilter = rawurlencode($oSubsetSearch->serialize(false, $aQueryParams));
$sFilter = urlencode($oSubsetSearch->serialize());
$aData[] = array ('group' => $aLabels[$iRow],
'value' => "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&dosearch=1&$sParams&filter=$sFilter\">$iCount</a>"); // TO DO: add the context information
@@ -616,7 +580,6 @@ class DisplayBlock
}
break;
case 'list_search':
case 'list':
$aClasses = $this->m_oSet->GetSelectedClasses();
$aAuthorizedClasses = array();
@@ -752,7 +715,7 @@ class DisplayBlock
$sClass = $this->m_oFilter->GetClass();
$oAppContext = new ApplicationContext();
$bContextFilter = isset($aExtraParams['context_filter']) ? isset($aExtraParams['context_filter']) != 0 : false;
if ($bContextFilter && is_null($this->m_oSet))
if ($bContextFilter)
{
foreach($oAppContext->GetNames() as $sFilterCode)
{
@@ -771,7 +734,7 @@ class DisplayBlock
$this->m_oSet->SetShowObsoleteData($this->m_bShowObsoleteData);
}
$iCount = $this->m_oSet->Count();
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.rawurlencode($this->m_oFilter->serialize());
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($this->m_oFilter->serialize());
$sHtml .= '<p><a class="actions" href="'.$sHyperlink.'">';
// Note: border set to 0 due to various browser interpretations (IE9 adding a 2px border)
$sHtml .= MetaModel::GetClassIcon($sClass, true, 'float;left;margin-right:10px;border:0;');
@@ -860,7 +823,7 @@ class DisplayBlock
}
$sHyperlink = utils::GetAbsoluteUrlAppRoot()
.'pages/UI.php?operation=search&'.$oAppContext->GetForLink()
.'&filter='.rawurlencode($oSingleGroupByValueFilter->serialize());
.'&filter='.urlencode($oSingleGroupByValueFilter->serialize());
$aCounts[$sStateValue] = "<a href=\"$sHyperlink\">{$aCounts[$sStateValue]}</a>";
}
}
@@ -869,7 +832,7 @@ class DisplayBlock
$sHtml .= '<tr><td>'.implode('</td><td>', $aCounts).'</td></tr></table></div>';
// Title & summary
$iCount = $this->m_oSet->Count();
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.rawurlencode($this->m_oFilter->serialize());
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($this->m_oFilter->serialize());
$sHtml .= '<h1>'.Dict::S(str_replace('_', ':', $sTitle)).'</h1>';
$sHtml .= '<a class="summary" href="'.$sHyperlink.'">'.Dict::Format(str_replace('_', ':', $sLabel), $iCount).'</a>';
$sHtml .= '<div style="clear:both;"></div>';
@@ -880,7 +843,7 @@ class DisplayBlock
$sCsvFile = strtolower($this->m_oFilter->GetClass()).'.csv';
$sDownloadLink = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?expression='.urlencode($this->m_oFilter->ToOQL(true)).'&format=csv&filename='.urlencode($sCsvFile);
$sLinkToToggle = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.rawurlencode($this->m_oFilter->serialize()).'&format=csv';
$sLinkToToggle = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($this->m_oFilter->serialize()).'&format=csv';
// Pass the parameters via POST, since expression may be very long
$aParamsToPost = array(
'expression' => $this->m_oFilter->ToOQL(true),
@@ -950,10 +913,10 @@ class DisplayBlock
$sChartType = isset($aExtraParams['chart_type']) ? $aExtraParams['chart_type'] : 'pie';
$sTitle = isset($aExtraParams['chart_title']) ? '<h1 style="text-align:center">'.htmlentities(Dict::S($aExtraParams['chart_title']), ENT_QUOTES, 'UTF-8').'</h1>' : '';
$sHtml = "$sTitle<div style=\"height:200px;width:100%\" class=\"dashboard_chart\" id=\"my_chart_$sId{$iChartCounter}\"><div style=\"height:200px;line-height:200px;vertical-align:center;text-align:center;width:100%\"><img src=\"../images/indicator.gif\"></div></div>\n";
$sHtml = "$sTitle<div style=\"height:200px;width:100%\" id=\"my_chart_$sId{$iChartCounter}\"><div style=\"height:200px;line-height:200px;vertical-align:center;text-align:center;width:100%\"><img src=\"../images/indicator.gif\"></div></div>\n";
$sGroupBy = isset($aExtraParams['group_by']) ? $aExtraParams['group_by'] : '';
$sGroupByExpr = isset($aExtraParams['group_by_expr']) ? '&params[group_by_expr]='.$aExtraParams['group_by_expr'] : '';
$sFilter = $this->m_oFilter->serialize(false, $aQueryParams);
$sFilter = $this->m_oFilter->serialize();
$oContext = new ApplicationContext();
$sContextParam = $oContext->GetForLink();
$sAggregationFunction = isset($aExtraParams['aggregation_function']) ? $aExtraParams['aggregation_function'] : '';
@@ -964,11 +927,11 @@ class DisplayBlock
if (isset($aExtraParams['group_by_label']))
{
$sUrl = json_encode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart&params[group_by]=$sGroupBy{$sGroupByExpr}&params[group_by_label]={$aExtraParams['group_by_label']}&params[chart_type]=$sChartType&params[currentId]=$sId{$iChartCounter}&params[order_direction]=$sOrderDirection&params[order_by]=$sOrderBy&params[limit]=$sLimit&params[aggregation_function]=$sAggregationFunction&params[aggregation_attribute]=$sAggregationAttr&id=$sId{$iChartCounter}&filter=".rawurlencode($sFilter).'&'.$sContextParam);
$sUrl = json_encode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart&params[group_by]=$sGroupBy{$sGroupByExpr}&params[group_by_label]={$aExtraParams['group_by_label']}&params[chart_type]=$sChartType&params[currentId]=$sId{$iChartCounter}&params[order_direction]=$sOrderDirection&params[order_by]=$sOrderBy&params[limit]=$sLimit&params[aggregation_function]=$sAggregationFunction&params[aggregation_attribute]=$sAggregationAttr&id=$sId{$iChartCounter}&filter=".urlencode($sFilter).'&'.$sContextParam);
}
else
{
$sUrl = json_encode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart&params[group_by]=$sGroupBy{$sGroupByExpr}&params[chart_type]=$sChartType&params[currentId]=$sId{$iChartCounter}&params[order_direction]=$sOrderDirection&params[order_by]=$sOrderBy&params[limit]=$sLimit&params[aggregation_function]=$sAggregationFunction&params[aggregation_attribute]=$sAggregationAttr&id=$sId{$iChartCounter}&filter=".rawurlencode($sFilter).'&'.$sContextParam);
$sUrl = json_encode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=chart&params[group_by]=$sGroupBy{$sGroupByExpr}&params[chart_type]=$sChartType&params[currentId]=$sId{$iChartCounter}&params[order_direction]=$sOrderDirection&params[order_by]=$sOrderBy&params[limit]=$sLimit&params[aggregation_function]=$sAggregationFunction&params[aggregation_attribute]=$sAggregationAttr&id=$sId{$iChartCounter}&filter=".urlencode($sFilter).'&'.$sContextParam);
}
$oPage->add_ready_script(
@@ -1008,7 +971,7 @@ EOF
$oSubsetSearch = $this->m_oFilter->DeepClone();
$oCondition = new BinaryExpression($oGroupByExp, '=', new ScalarExpression($sValue));
$oSubsetSearch->AddConditionExpression($oCondition);
$aURLs[] = utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&format=html&filter=".rawurlencode($oSubsetSearch->serialize()).'&'.$sContextParam;
$aURLs[] = utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&format=html&filter=".urlencode($oSubsetSearch->serialize()).'&'.$sContextParam;
}
$sJSURLs = json_encode($aURLs);
}
@@ -1026,7 +989,6 @@ EOF
$sJson = json_encode($aValues);
$oPage->add_ready_script(
<<<EOF
var chart = c3.generate({
bindto: d3.select('#my_chart_$sId'),
data: {
@@ -1074,12 +1036,6 @@ var chart = c3.generate({
}
}
});
if (typeof(charts) === "undefined")
{
charts = [];
}
charts.push(chart);
EOF
);
break;
@@ -1118,12 +1074,6 @@ var chart = c3.generate({
}
}
});
if (typeof(charts) === "undefined")
{
charts = [];
}
charts.push(chart);
EOF
);
break;
@@ -1172,7 +1122,7 @@ EOF
}
if (($bAutoReload) && ($this->m_sStyle != 'search')) // Search form do NOT auto-reload
{
$sFilter = addslashes(str_replace('"', "'", $this->m_oFilter->serialize())); // Used either for asynchronous or auto_reload
$sFilter = $this->m_oFilter->serialize(); // Used either for asynchronous or auto_reload
$sExtraParams = addslashes(str_replace('"', "'", json_encode($aExtraParams))); // JSON encode, change the style of the quotes and escape them
$oPage->add_script('if (typeof window.oAutoReloadBlock == "undefined") {
@@ -1181,7 +1131,7 @@ EOF
if (typeof window.oAutoReloadBlock[\''.$sId.'\'] != "undefined") {
clearInterval(window.oAutoReloadBlock[\''.$sId.'\']);
}
window.oAutoReloadBlock[\''.$sId.'\'] = setInterval("ReloadBlock(\''.$sId.'\', \''.$this->m_sStyle.'\', \"'.$sFilter.'\", \"'.$sExtraParams.'\")", '.$iReloadInterval.');');
window.oAutoReloadBlock[\''.$sId.'\'] = setInterval("ReloadBlock(\''.$sId.'\', \''.$this->m_sStyle.'\', \''.$sFilter.'\', \"'.$sExtraParams.'\")", '.$iReloadInterval.');');
}
return $sHtml;
@@ -1441,7 +1391,7 @@ class HistoryBlock extends DisplayBlock
default:
if ($bTruncated)
{
$sFilter = htmlentities($this->m_oFilter->serialize(), ENT_QUOTES, 'UTF-8');
$sFilter = $this->m_oFilter->serialize();
$sHtml .= '<div id="history_container"><p>';
$sHtml .= Dict::Format('UI:TruncatedResults', $this->iLimitCount, $oSet->Count());
$sHtml .= ' ';

View File

@@ -378,9 +378,9 @@ $('#$sDialogId').dialog({
}
}
} },
{ text: "$sCancelButtonLabel", click: function() { $(this).dialog( "close" ); $(this).remove(); } },
{ text: "$sCancelButtonLabel", click: function() { KillAllMenus(); $(this).dialog( "close" ); $(this).remove(); } },
],
close: function() { $(this).remove(); }
close: function() { KillAllMenus(); $(this).remove(); }
});
var oForm = $('#$sDialogId form');
var sFormId = oForm.attr('id');
@@ -682,7 +682,6 @@ class DesignerFormField
protected $sLabel;
protected $sCode;
protected $defaultValue;
/** @var \DesignerForm $oForm */
protected $oForm;
protected $bMandatory;
protected $bReadOnly;
@@ -708,11 +707,8 @@ class DesignerFormField
{
return $this->sCode;
}
/**
* @param \DesignerForm $oForm
*/
public function SetForm(\DesignerForm $oForm)
public function SetForm($oForm)
{
$this->oForm = $oForm;
}

File diff suppressed because it is too large Load Diff

View File

@@ -50,9 +50,6 @@ class LoginWebPage extends NiceWebPage
self::$sHandlerClass = $sClass;
}
/**
* @return \LoginWebPage
*/
public static function NewLoginWebPage()
{
return new self::$sHandlerClass;
@@ -707,6 +704,7 @@ EOF
{
// No rights to be here, redirect to the portal
header('Location: '.$ret);
die();
}
}
}
@@ -846,8 +844,8 @@ EOF
{
$sAuthUser = $_SESSION['auth_user'];
UserRights::Login($sAuthUser); // Set the user's language
$sOldPwd = utils::ReadPostedParam('old_pwd', '', false, 'raw_data');
$sNewPwd = utils::ReadPostedParam('new_pwd', '', false, 'raw_data');
$sOldPwd = utils::ReadPostedParam('old_pwd', '', 'raw_data');
$sNewPwd = utils::ReadPostedParam('new_pwd', '', 'raw_data');
if (UserRights::CanChangePassword() && ((!UserRights::CheckCredentials($sAuthUser, $sOldPwd)) || (!UserRights::ChangePassword($sOldPwd, $sNewPwd))))
{
$oPage = self::NewLoginWebPage();

View File

@@ -84,11 +84,14 @@ class ApplicationMenu
{
// Build menus from module handlers
//
/** @var \ModuleHandlerApiInterface $oPHPClass */
foreach(MetaModel::EnumPlugins('ModuleHandlerApiInterface') as $oPHPClass)
{
$oPHPClass::OnMenuCreation();
}
foreach(get_declared_classes() as $sPHPClass)
{
if (is_subclass_of($sPHPClass, 'ModuleHandlerAPI'))
{
$aCallSpec = array($sPHPClass, 'OnMenuCreation');
call_user_func($aCallSpec);
}
}
// Build menus from the menus themselves (e.g. the ShortcutContainerMenuNode will do that)
//
@@ -122,11 +125,9 @@ class ApplicationMenu
}
/**
* Check whether a menu Id is enabled or not
*
* Check wether a menu Id is enabled or not
* @param $sMenuId
*
* @throws \Exception
* @throws DictExceptionMissingString
*/
static public function CheckMenuIdEnabled($sMenuId)
{
@@ -166,9 +167,7 @@ class ApplicationMenu
}
else
{
/** @var \MenuNode $oNode */
$oNode = self::$aMenusIndex[$iParentIndex]['node'];
$sParentId = $oNode->GetMenuId();
$sParentId = self::$aMenusIndex[$iParentIndex]['node']->GetMenuId();
self::$aMenusIndex[$iParentIndex]['children'][] = array ('rank' => $fRank, 'index' => $index);
}
@@ -182,9 +181,7 @@ class ApplicationMenu
else
{
// the menu already exists, let's combine the conditions that make it visible
/** @var \MenuNode $oNode */
$oNode = self::$aMenusIndex[$index]['node'];
$oNode->AddCondition($oMenuNode);
self::$aMenusIndex[$index]['node']->AddCondition($oMenuNode);
}
return $index;
@@ -201,7 +198,7 @@ class ApplicationMenu
/**
* Entry point to display the whole menu into the web page, used by iTopWebPage
* @param \iTopWebPage $oPage
* @param $oPage
* @param $aExtraParams
* @throws DictExceptionMissingString
*/
@@ -211,7 +208,6 @@ class ApplicationMenu
// Sort the root menu based on the rank
usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank'));
$iAccordion = 0;
$iActiveAccordion = $iAccordion;
$iActiveMenu = self::GetMenuIndexById(self::GetActiveNodeId());
foreach(self::$aRootMenus as $aMenu)
{
@@ -225,18 +221,16 @@ class ApplicationMenu
$oPage->AddToMenu('</ul>');
if ($bActive)
{
$iActiveAccordion = $iAccordion;
$oPage->add_ready_script(
<<<EOF
// Accordion Menu
$("#accordion").css({display:'block'}).accordion({ header: "h3", navigation: true, heightStyle: "content", collapsible: true, active: $iAccordion, icons: false, animate:true }); // collapsible will be enabled once the item will be selected
EOF
);
}
$oPage->AddToMenu('</div>');
$iAccordion++;
}
$oPage->add_ready_script(
<<<EOF
// Accordion Menu
$("#accordion").css({display:'block'}).accordion({ header: "h3", heightStyle: "content", collapsible: true, active: $iActiveAccordion, icons: false, animate: true }); // collapsible will be enabled once the item will be selected
EOF
);
}
/**
@@ -270,7 +264,7 @@ EOF
/**
* Handles the display of the sub-menus (called recursively if necessary)
* @param \iTopWebPage $oPage
* @param WebPage $oPage
* @param array $aMenus
* @param array $aExtraParams
* @param int $iActiveMenu
@@ -362,7 +356,6 @@ EOF
static public function GetMenuIndexById($sTitle)
{
$index = -1;
/** @var MenuNode[] $aMenu */
foreach(self::$aMenusIndex as $aMenu)
{
if ($aMenu['node']->GetMenuId() == $sTitle)
@@ -844,7 +837,7 @@ class OQLMenuNode extends MenuNode
/**
* Set some extra parameters to be passed to the display block to fine tune its appearence
* @param array $aParams paramCode => value. See DisplayBlock::GetDisplay for the meaning of the parameters
* @param Hash $aParams paramCode => value. See DisplayBlock::GetDisplay for the meaning of the parameters
*/
public function SetParameters($aParams)
{
@@ -957,7 +950,7 @@ class SearchMenuNode extends MenuNode
}
/**
* @param \iTopWebPage $oPage
* @param WebPage $oPage
* @param array $aExtraParams
* @return mixed|void
* @throws DictExceptionMissingString
@@ -1061,9 +1054,7 @@ class NewObjectMenuNode extends MenuNode
/**
* @param string[] $aExtraParams
*
* @return string
* @throws \Exception
*/
public function GetHyperlink($aExtraParams)
{
@@ -1152,11 +1143,37 @@ class DashboardMenuNode extends MenuNode
*/
public function GetDashboard()
{
return RuntimeDashboard::GetDashboard($this->sDashboardFile, $this->sMenuId);
$sDashboardDefinition = @file_get_contents($this->sDashboardFile);
if ($sDashboardDefinition !== false)
{
$bCustomized = false;
// Search for an eventual user defined dashboard, overloading the existing one
$oUDSearch = new DBObjectSearch('UserDashboard');
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oUDSearch->AddCondition('menu_code', $this->sMenuId, '=');
$oUDSet = new DBObjectSet($oUDSearch);
if ($oUDSet->Count() > 0)
{
// Assuming there is at most one couple {user, menu}!
$oUserDashboard = $oUDSet->Fetch();
$sDashboardDefinition = $oUserDashboard->Get('contents');
$bCustomized = true;
}
$oDashboard = new RuntimeDashboard($this->sMenuId);
$oDashboard->FromXml($sDashboardDefinition);
$oDashboard->SetCustomFlag($bCustomized);
}
else
{
$oDashboard = null;
}
return $oDashboard;
}
/**
* @param \iTopWebPage $oPage
* @param WebPage $oPage
* @param string[] $aExtraParams
* @throws CoreException
* @throws Exception
@@ -1169,9 +1186,38 @@ class DashboardMenuNode extends MenuNode
{
$sDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $this->sMenuId);
$oPage->add('<div class="dashboard_contents" id="'.$sDivId.'">');
$oDashboard->SetReloadURL($this->GetHyperlink($aExtraParams));
$oDashboard->Render($oPage, false, $aExtraParams);
$oPage->add('</div>');
$oDashboard->RenderEditionTools($oPage);
if ($oDashboard->GetAutoReload())
{
$sId = $this->sMenuId;
$sExtraParams = json_encode($aExtraParams);
$iReloadInterval = 1000 * $oDashboard->GetAutoReloadInterval();
$oPage->add_script(
<<<EOF
setInterval("ReloadDashboard('$sDivId');", $iReloadInterval);
function ReloadDashboard(sDivId)
{
var oExtraParams = $sExtraParams;
// Do not reload when a dialog box is active
if (!($('.ui-dialog:visible').length > 0))
{
$('.dashboard_contents#'+sDivId).block();
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
{ operation: 'reload_dashboard', dashboard_id: '$sId', extra_params: oExtraParams},
function(data){
$('.dashboard_contents#'+sDivId).html(data);
$('.dashboard_contents#'+sDivId).unblock();
}
);
}
}
EOF
);
}
$bEdit = utils::ReadParam('edit', false);
if ($bEdit)

View File

@@ -1,159 +0,0 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* A provider for messages to be displayed in the iTop Newsroom
*/
interface iNewsroomProvider
{
/**
* Inject the current configuration in the provider
* @param Config $oConfig
* @return void
*/
public function SetConfig(Config $oConfig);
/**
* Tells if this provider is enabled for the given user
* @param User $oUser The user for who to check if the provider is applicable.
* return bool
*/
public function IsApplicable(User $oUser = null);
/**
* The human readable (localized) label for this provider
* @return string
*/
public function GetLabel();
/**
* The URL to query (from the browser, using jsonp) to fetch all unread messages
* @return string
*/
public function GetFetchURL();
/**
* The URL to navigate to in order to display all messages
* @return string
*/
public function GetViewAllURL();
/**
* The URL to query(from the browser, using jsonp) to mark all unread messages as read
* @return string
*/
public function GetMarkAllAsReadURL();
/**
* Return the URL to configure the preferences for this provider or null is there is nothing to configure
* @return string|null
*/
public function GetPreferencesUrl();
/**
* Return an array key => value to be replaced in URL of the messages
* Example: '%itop_root%' => utils::GetAbsoluteUrlAppRoot();
* @return string[]
*/
public function GetPlaceholders();
/**
* The duration between to refreshes of the cache (in seconds)
* @return int
*/
public function GetTTL();
}
/**
* Basic implementation of a Newsroom provider, to be overloaded by your own provider implementation
*
*/
abstract class NewsroomProviderBase implements iNewsroomProvider
{
/**
* The current configuration parameters
* @var Config
*/
protected $oConfig;
public function __construct()
{
$this->oConfig = null;
}
/**
* {@inheritDoc}
* @see iNewsroomProvider::SetConfig()
*/
public function SetConfig(Config $oConfig)
{
$this->oConfig = $oConfig;
}
/**
* {@inheritDoc}
* @see iNewsroomProvider::GetPreferencesUrl()
*/
public function GetPreferencesUrl()
{
return null; // No preferences
}
/**
* {@inheritDoc}
* @see iNewsroomProvider::GetLabel()
*/
public abstract function GetLabel();
/**
* {@inheritDoc}
* @see iNewsroomProvider::GetFetchURL()
*/
public abstract function GetFetchURL();
/**
* {@inheritDoc}
* @see iNewsroomProvider::GetMarkAllURL()
*/
public abstract function GetMarkAllAsReadURL();
/**
* {@inheritDoc}
* @see iNewsroomProvider::GetViewAllURL()
*/
public abstract function GetViewAllURL();
public function IsApplicable(User $oUser = null)
{
return false;
}
/**
* {@inheritDoc}
* @see iNewsroomProvider::GetPlaceholders()
*/
public function GetPlaceholders()
{
return array(); // By default, empty set of placeholders
}
public function GetTTL()
{
return 10*60; // Refresh every 10 minutes
}
}

View File

@@ -37,15 +37,8 @@ class NiceWebPage extends WebPage
{
parent::__construct($s_title, $bPrintable);
$this->m_aReadyScripts = array();
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-3.3.1.min.js');
if(utils::IsDevelopmentEnvironment()) // Needed since many other plugins still rely on oldies like $.browser
{
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate-3.0.1.dev.js');
}
else
{
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate-3.0.1.prod.min.js');
}
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-1.12.4.min.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate-1.4.1.min.js'); // Needed since many other plugins still rely on oldies like $.browser
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/ui-lightness/jquery-ui-1.11.4.custom.css');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-ui-1.11.4.custom.min.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/utils.js');
@@ -54,7 +47,6 @@ class NiceWebPage extends WebPage
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablesorter.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablesorter.pager.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablehover.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/table-selectable-lines.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/field_sorter.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/datatable.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.positionBy.js');
@@ -69,7 +61,6 @@ class NiceWebPage extends WebPage
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_external_field.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_numeric.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_enum.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_tag_set.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_external_key.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_hierarchical_key.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_date_abstract.js');

View File

@@ -35,7 +35,7 @@ class iTopPDF extends TCPDF
// Display the page number (right aligned)
// Warning: the 'R'ight alignment does not work when using placeholders like $this->getAliasNumPage() or $this->getAliasNbPages()
$this->MultiCell($iPageNumberWidth, 15, Dict::Format('Core:BulkExport:PDF:PageNumber' ,$this->page), 0, 'R', false, 0 /* $ln */, '', '', true, 0, false, true, 15, 'M' /* $valign */);
$this->MultiCell($iPageNumberWidth, 15, 'Page '.$this->page, 0, 'R', false, 0 /* $ln */, '', '', true, 0, false, true, 15, 'M' /* $valign */);
// Branding logo
$sBrandingIcon = APPROOT.'images/itop-logo.png';

View File

@@ -807,7 +807,7 @@ EOF
*/
public function DoUpdateObjectFromPostedForm(DBObject $oObj, $aAttList = null)
{
$sTransactionId = utils::ReadPostedParam('transaction_id', '', 'transaction_id');
$sTransactionId = utils::ReadPostedParam('transaction_id', '');
if (!utils::IsTransactionValid($sTransactionId))
{
throw new TransactionException();

View File

@@ -47,12 +47,13 @@ abstract class Query extends cmdbAbstractObject
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("fields", array("allowed_values"=>null, "sql"=>"fields", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('details', array('name', 'description', 'fields')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('name', 'description')); // Criteria of the std search form
MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'fields')); // Criteria of the std search form
MetaModel::Init_SetZListItems('default_search', array('name', 'description')); // Criteria of the default search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
@@ -77,9 +78,6 @@ class QueryOQL extends Query
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("fields", array("allowed_values"=>null, "sql"=>"fields", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// Rolled back to AttributeText until AttributeQueryAttCodeSet can manage fields order correctly
//MetaModel::Init_AddAttribute(new AttributeQueryAttCodeSet("fields", array("allowed_values"=>null,"max_items" => 1000, "query_field" => "oql", "sql"=>"fields", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array('oql'))));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'oql', 'fields')); // Attributes to be displayed for the complete details
@@ -138,41 +136,6 @@ class QueryOQL extends Query
}
return $aFieldsMap;
}
// Rolled back until 'fields' can be properly managed by AttributeQueryAttCodeSet
//
// public function ComputeValues()
// {
// parent::ComputeValues();
//
// // Remove unwanted attribute codes
// $aChanges = $this->ListChanges();
// if (isset($aChanges['fields']))
// {
// $oAttDef = MetaModel::GetAttributeDef(get_class($this), 'fields');
// $aArgs = array('this' => $this);
// $aAllowedValues = $oAttDef->GetAllowedValues($aArgs);
//
// /** @var \ormSet $oValue */
// $oValue = $this->Get('fields');
// $aValues = $oValue->GetValues();
// $bChanged = false;
// foreach($aValues as $key => $sValue)
// {
// if (!isset($aAllowedValues[$sValue]))
// {
// unset($aValues[$key]);
// $bChanged = true;
// }
// }
// if ($bChanged)
// {
// $oValue->SetValues($aValues);
// $this->Set('fields', $oValue);
// }
// }
// }
}
?>

View File

@@ -24,26 +24,6 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
// This storage is freed on error (case of allowed memory exhausted)
$sReservedMemory = str_repeat('*', 1024 * 1024);
register_shutdown_function(function()
{
global $sReservedMemory;
$sReservedMemory = null;
if (!is_null($err = error_get_last()) && ($err['type'] == E_ERROR))
{
if (strpos($err['message'], 'Allowed memory size of') !== false)
{
$sLimit = ini_get('memory_limit');
echo "<p>iTop: Allowed memory size of $sLimit exhausted, contact your administrator to increase memory_limit in php.ini</p>\n";
}
else
{
echo "<p>iTop: An error occurred, check server error log for more information.</p>\n";
}
}
});
require_once(APPROOT.'/core/cmdbobject.class.inc.php');
require_once(APPROOT.'/application/utils.inc.php');
require_once(APPROOT.'/core/contexttag.class.inc.php');

View File

@@ -119,7 +119,7 @@ class privUITransactionSession
// Strictly speaking, the two lines below should be grouped together
// by a critical section
// sem_acquire($rSemIdentified);
$id = static::GetUserPrefix() . str_replace(array('.', ' '), '', microtime()); //1 + count($_SESSION['transactions']);
$id = str_replace(array('.', ' '), '', microtime()); //1 + count($_SESSION['transactions']);
$_SESSION['transactions'][$id] = true;
// sem_release($rSemIdentified);
@@ -174,17 +174,6 @@ class privUITransactionSession
// sem_release($rSemIdentified);
}
}
/**
* Returns a string to prefix transaction ID with info from the current user.
*
* @return string
*/
protected static function GetUserPrefix()
{
$sPrefix = 'u'.UserRights::GetUserId();
return $sPrefix.'-';
}
}
/**
@@ -217,7 +206,7 @@ class privUITransactionFile
throw new Exception('The directory "'.APPROOT.'data/transactions" must be writable to the application.');
}
self::CleanupOldTransactions();
$id = basename(tempnam(APPROOT.'data/transactions', static::GetUserPrefix()));
$id = basename(tempnam(APPROOT.'data/transactions', self::GetUserPrefix()));
self::Info('GetNewTransactionId: Created transaction: '.$id);
return (string)$id;
@@ -321,11 +310,6 @@ class privUITransactionFile
return $aResult;
}
/**
* Returns a prefix based on the user login instead of its ID for a better usage in tempnam()
*
* @inheritdoc
*/
protected static function GetUserPrefix()
{
$sPrefix = substr(UserRights::GetUser(), 0, 10);

View File

@@ -332,8 +332,7 @@ EOF
if ( ($oCurrObject != null) && ($this->sAttCode != ''))
{
$oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode);
/** @var \DBObject $oCurrObject */
$aArgs = $oCurrObject->ToArgsForQuery();
$aArgs = array('this' => $oCurrObject);
$aParams = array('query_params' => $aArgs);
$oSet = $oAttDef->GetAllowedValuesAsObjectSet($aArgs);
$oFilter = $oSet->GetFilter();
@@ -403,7 +402,7 @@ EOF
// Current extkey value, so we can display event if it is not available anymore (eg. archived).
$iCurrentExtKeyId = (is_null($oObj)) ? 0 : $oObj->Get($this->sAttCode);
$oBlock = new DisplayBlock($oFilter, 'list_search', false, array('query_params' => array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId)));
$oBlock = new DisplayBlock($oFilter, 'list', false, array('query_params' => array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId)));
$oBlock->Display($oP, $this->iId.'_results', array('this' => $oObj, 'cssCount'=> '#count_'.$this->iId, 'menu' => false, 'selection_mode' => true, 'selection_type' => 'single', 'table_id' => 'select_'.$this->sAttCode)); // Don't display the 'Actions' menu on the results
}

View File

@@ -101,7 +101,7 @@ class UIHTMLEditorWidget
$oPage->add_ready_script(
<<<EOF
$('#$iId').bind('update', function(evt){
BlockField('cke_$iId', $('#$iId').prop('disabled'));
BlockField('cke_$iId', $('#$iId').attr('disabled'));
//Delayed execution - ckeditor must be properly initialized before setting readonly
var retryCount = 0;
var oMe = $('#$iId');

View File

@@ -133,14 +133,15 @@ class UILinksWidget
$sPrefix = "$this->m_sAttCode{$this->m_sNameSuffix}";
$aRow = array();
$aFieldsMap = array();
$iKey = 0;
if(is_object($linkObjOrId) && (!$linkObjOrId->IsNew()))
{
$key = $linkObjOrId->GetKey();
$iKey = $linkObjOrId->GetKey();
$iRemoteObjKey = $linkObjOrId->Get($this->m_sExtKeyToRemote);
$sPrefix .= "[$key][";
$sPrefix .= "[$iKey][";
$sNameSuffix = "]"; // To make a tabular form
$aArgs['prefix'] = $sPrefix;
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}{$key}";
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}{$iKey}";
$aArgs['this'] = $linkObjOrId;
if($bReadOnly)
@@ -154,7 +155,7 @@ class UILinksWidget
}
else
{
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"$key\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$key\">";
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"$iKey\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$iKey\">";
foreach($this->m_aEditableFields as $sFieldCode)
{
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.$linkObjOrId->GetKey().']';
@@ -195,7 +196,30 @@ class UILinksWidget
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}_".($iUniqueId < 0 ? -$iUniqueId : $iUniqueId);
$aArgs['this'] = $oNewLinkObj;
$sInputValue = $iUniqueId > 0 ? "-$iUniqueId" : "$iUniqueId";
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$sInputValue\">";
$aRow['form::checkbox'] = "<input class=\"selection\" data-remote-id=\"$iRemoteObjKey\" data-link-id=\"0\" data-unique-id=\"$iUniqueId\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$sInputValue\">";
if ($iUniqueId > 0)
{
// Rows created with ajax call need OnLinkAdded call.
//
$oP->add_ready_script(
<<<EOF
PrepareWidgets();
oWidget{$this->m_iInputId}.OnLinkAdded($iUniqueId, $iRemoteObjKey);
EOF
);
}
else
{
// Rows added before loading the form don't have to call OnLinkAdded.
// Listeners are already present and DOM is not recreated
$iPositiveUniqueId = -$iUniqueId;
$oP->add_ready_script(<<<EOF
oWidget{$this->m_iInputId}.AddLink($iPositiveUniqueId, $iRemoteObjKey);
EOF
);
}
foreach($this->m_aEditableFields as $sFieldCode)
{
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.-$iUniqueId.']';
@@ -207,20 +231,12 @@ class UILinksWidget
cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $sValue, $sDisplayValue, $sSafeId /* id */, $sNameSuffix, 0, $aArgs).
'</div></div></div>';
$aFieldsMap[$sFieldCode] = $sSafeId;
$oP->add_ready_script(<<<EOF
oWidget{$this->m_iInputId}.OnValueChange($iKey, $iUniqueId, '$sFieldCode', '$sValue');
EOF
);
}
$sState = '';
// Rows created with ajax call need OnLinkAdded call.
// Rows added before loading the form cannot call OnLinkAdded.
if ($iUniqueId > 0)
{
$oP->add_ready_script(
<<<EOF
PrepareWidgets();
oWidget{$this->m_iInputId}.OnLinkAdded($iUniqueId, $iRemoteObjKey);
EOF
);
}
}
if(!$bReadOnly)
@@ -337,8 +353,19 @@ EOF
$sHtmlValue .= "<input type=\"hidden\" id=\"{$sFormPrefix}{$this->m_iInputId}\">\n";
$oValue->Rewind();
$aForm = array();
$iAddedId = 1; // Unique id for new links
$aAddedLinks = array();
$iAddedId = -1; // Unique id for new links
$sDuplicates = ($this->m_bDuplicatesAllowed) ? 'true' : 'false';
// Don't automatically launch the search if the table is huge
$bDoSearch = !utils::IsHighCardinality($this->m_sRemoteClass);
$sJSDoSearch = $bDoSearch ? 'true' : 'false';
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
$oPage->add_ready_script(<<<EOF
oWidget{$this->m_iInputId} = new LinksWidget('{$this->m_sAttCode}{$this->m_sNameSuffix}', '{$this->m_sClass}', '{$this->m_sAttCode}', '{$this->m_iInputId}', '{$this->m_sNameSuffix}', $sDuplicates, $sWizHelper, '{$this->m_sExtKeyToRemote}', $sJSDoSearch);
oWidget{$this->m_iInputId}.Init();
EOF
);
while($oCurrentLink = $oValue->Fetch())
{
// We try to retrieve the remote object as usual
@@ -357,9 +384,7 @@ EOF
if ($oCurrentLink->IsNew())
{
$key = -($iAddedId++);
$iUniqueId = -$key;
$aAddedLinks[] = array('iAddedId' => $iUniqueId, 'iRemote' => $oCurrentLink->Get($this->m_sExtKeyToRemote));
$key = $iAddedId--;
}
else
{
@@ -368,24 +393,6 @@ EOF
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs, $oCurrentObj, $key, $bReadOnly);
}
$sHtmlValue .= $this->DisplayFormTable($oPage, $this->m_aTableConfig, $aForm);
$sDuplicates = ($this->m_bDuplicatesAllowed) ? 'true' : 'false';
// Don't automatically launch the search if the table is huge
$bDoSearch = !utils::IsHighCardinality($this->m_sRemoteClass);
$sJSDoSearch = $bDoSearch ? 'true' : 'false';
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
$oPage->add_ready_script(<<<EOF
oWidget{$this->m_iInputId} = new LinksWidget('{$this->m_sAttCode}{$this->m_sNameSuffix}', '{$this->m_sClass}', '{$this->m_sAttCode}', '{$this->m_iInputId}', '{$this->m_sNameSuffix}', $sDuplicates, $sWizHelper, '{$this->m_sExtKeyToRemote}', $sJSDoSearch);
oWidget{$this->m_iInputId}.Init();
EOF
);
foreach ($aAddedLinks as $aAddedLink)
{
$oPage->add_ready_script(<<<EOF
oWidget{$this->m_iInputId}.AddLink({$aAddedLink['iAddedId']}, {$aAddedLink['iRemote']});
EOF
);
}
$sHtmlValue .= "<span style=\"float:left;\">&nbsp;&nbsp;&nbsp;<img src=\"../images/tv-item-last.gif\">&nbsp;&nbsp;<input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnRemove\" type=\"button\" value=\"".Dict::S('UI:RemoveLinkedObjectsOf_Class')."\" onClick=\"oWidget{$this->m_iInputId}.RemoveSelected();\" >";
$sHtmlValue .= "&nbsp;&nbsp;&nbsp;<input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnAdd\" type=\"button\" value=\"".Dict::Format('UI:AddLinkedObjectsOf_Class', MetaModel::GetName($this->m_sRemoteClass))."\" onClick=\"oWidget{$this->m_iInputId}.AddObjects();\"><span id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_indicatorAdd\"></span></span>\n";

View File

@@ -73,17 +73,17 @@ class UIPasswordWidget
$oPage->add_ready_script("$('#{$this->iId}_confirm').bind('keyup change', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#{$this->iId}').bind('update', function(evt, sFormId)
{
if ($(this).prop('disabled'))
if ($(this).attr('disabled'))
{
$('#{$this->iId}_confirm').prop('disabled', true);
$('#{$this->iId}_changed').prop('disabled', true);
$('#{$this->iId}_reset').prop('disabled', true);
$('#{$this->iId}_confirm').attr('disabled', 'disabled');
$('#{$this->iId}_changed').attr('disabled', 'disabled');
$('#{$this->iId}_reset').attr('disabled', 'disabled');
}
else
{
$('#{$this->iId}_confirm').prop('disabled', false);
$('#{$this->iId}_changed').prop('disabled', false);
$('#{$this->iId}_reset').prop('disabled', false);
$('#{$this->iId}_confirm').removeAttr('disabled');
$('#{$this->iId}_changed').removeAttr('disabled');
$('#{$this->iId}_reset').removeAttr('disabled');
}
}
);"); // Bind to a custom event: update to handle enabling/disabling

View File

@@ -273,7 +273,18 @@ class utils
}
return $retValue;
}
/**
* @param string|string[] $value
* @param string $sSanitizationFilter one of : integer, class, string, context_param, parameter, field_name,
* transaction_id, parameter, raw_data
*
* @return string|string[]|bool boolean for :
* * the 'class' filter (true if valid, false otherwise)
* * if the filter fails (@see \filter_var())
*
* @since 2.5.2 2.6.0 new 'transaction_id' filter
*/
protected static function Sanitize_Internal($value, $sSanitizationFilter)
{
switch($sSanitizationFilter)
@@ -320,14 +331,12 @@ class utils
// it must be included at the regexp beginning otherwise you'll get an invalid character error
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP,
array("options" => array("regexp" => '/^[\. A-Za-z0-9_=-]*$/')));
break;
case 'parameter':
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP,
array("options" => array("regexp" => '/^[ A-Za-z0-9_=-]*$/'))); // the '=', '%3D, '%2B', '%2F'
// characters are used in serialized filters (starting 2.5, only the url encoded versions are presents, but the "=" is kept for BC)
break;
case 'parameter':
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options"=>array("regexp"=>'/^([ A-Za-z0-9_=-]|%3D|%2B|%2F)*$/'))); // the '=', '%3D, '%2B', '%2F' characters are used in serialized filters (starting 2.5, only the url encoded versions are presents, but the "=" is kept for BC)
break;
case 'field_name':
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options"=>array("regexp"=>'/^[A-Za-z0-9_]+(->[A-Za-z0-9_]+)*$/'))); // att_code or att_code->name or AttCode->Name or AttCode->Key2->Name
break;
@@ -527,7 +536,7 @@ class utils
/**
* Returns a unique tmp id for the current upload based on the transaction system (db).
*
* Build as static::GetNewTransactionId()
* Build as session_id() . '_' . static::GetNewTransactionId()
*
* @return string
*/
@@ -537,7 +546,7 @@ class utils
{
$sTransactionId = static::GetNewTransactionId();
}
return $sTransactionId;
return session_id() . '_' . $sTransactionId;
}
public static function ReadFromFile($sFileName)
@@ -572,18 +581,6 @@ class utils
}
return $iReturn;
}
/**
* Checks if the memory limit is at least what is required
*
* @param int $memoryLimit set limit in bytes
* @param int $requiredLimit required limit in bytes
* @return bool
*/
public static function IsMemoryLimitOk($memoryLimit, $requiredLimit)
{
return ($memoryLimit >= $requiredLimit) || ($memoryLimit == -1);
}
/**
* Format a value into a more friendly format (KB, MB, GB, TB) instead a juste a Bytes amount.
@@ -728,11 +725,7 @@ class utils
}
/**
* Returns the absolute URL to the application root path
*
* @return string The absolute URL to the application root, without the first slash
*
* @throws \Exception
* @return string The absolute URL to the application, including host and path
*/
static public function GetAbsoluteUrlAppRoot()
{
@@ -761,15 +754,7 @@ class utils
return $sUrl;
}
/**
* Builds an root url from the server's variables.
* For most usages, when an root url is needed, use utils::GetAbsoluteUrlAppRoot() instead as uses this only as a fallback when the app_root_url conf parameter is not defined.
*
* @return string
*
* @throws \Exception
*/
static public function GetDefaultUrlAppRoot()
static public function GetDefaultUrlAppRoot()
{
// Build an absolute URL to this page on this server/port
$sServerName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : '';
@@ -838,7 +823,7 @@ class utils
/**
* Helper to handle the variety of HTTP servers
* See 286 (fixed in [896]), and 634 (this fix)
* See #286 (fixed in [896]), and #634 (this fix)
*
* Though the official specs says 'a non empty string', some servers like IIS do set it to 'off' !
* nginx set it to an empty string
@@ -1091,7 +1076,12 @@ class utils
// $param is a DBObject
$oObj = $param;
$sOQL = "SELECT ".get_class($oObj)." WHERE id=".$oObj->GetKey();
$oFilter = DBObjectSearch::FromOQL($sOQL);
$sFilter = $oFilter->serialize();
$sUrl = ApplicationContext::MakeObjectUrl(get_class($oObj), $oObj->GetKey());
$sUIPage = cmdbAbstractObject::ComputeStandardUIPage(get_class($oObj));
$oAppContext = new ApplicationContext();
$sContext = $oAppContext->GetForLink();
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/tabularfieldsselector.js');
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.dragtable.js');
$oPage->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/dragtable.css');
@@ -1111,29 +1101,21 @@ class utils
break;
case iPopupMenuExtension::MENU_DASHBOARD_ACTIONS:
// $param is a Dashboard
/** @var \RuntimeDashboard $oDashboard */
$oDashboard = $param;
$sDashboardId = $oDashboard->GetId();
$sDashboardFile = $oDashboard->GetDefinitionFile();
$sDlgTitle = addslashes(Dict::S('UI:ImportDashboardTitle'));
$sDlgText = addslashes(Dict::S('UI:ImportDashboardText'));
$sCloseBtn = addslashes(Dict::S('UI:Button:Cancel'));
$sDashboardFileJS = addslashes($sDashboardFile);
$sDashboardFileURL = urlencode($sDashboardFile);
// $param is a Dashboard
$oAppContext = new ApplicationContext();
$aParams = $oAppContext->GetAsHash();
$sMenuId = ApplicationMenu::GetActiveNodeId();
$sDlgTitle = addslashes(Dict::S('UI:ImportDashboardTitle'));
$sDlgText = addslashes(Dict::S('UI:ImportDashboardText'));
$sCloseBtn = addslashes(Dict::S('UI:Button:Cancel'));
$sUploadDashboardTransactId = utils::GetNewTransactionId();
$aResult = array(
new SeparatorPopupMenuItem(),
new URLPopupMenuItem('UI:ExportDashboard', Dict::S('UI:ExportDashBoard'), utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=export_dashboard&id='.$sDashboardId.'&file='.$sDashboardFileURL),
new JSPopupMenuItem('UI:ImportDashboard', Dict::S('UI:ImportDashBoard'), "UploadDashboard({dashboard_id: '$sDashboardId', file: '$sDashboardFileJS', title: '$sDlgTitle', text: '$sDlgText', close_btn: '$sCloseBtn', transaction: '$sUploadDashboardTransactId' })"),
);
if ($oDashboard->GetReloadURL())
{
$aResult[] = new SeparatorPopupMenuItem();
$aResult[] = new URLPopupMenuItem('UI:Menu:PrintableVersion', Dict::S('UI:Menu:PrintableVersion'), $oDashboard->GetReloadURL().'&printable=1', '_blank');
}
break;
$aResult = array(
new SeparatorPopupMenuItem(),
new URLPopupMenuItem('UI:ExportDashboard', Dict::S('UI:ExportDashBoard'), utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=export_dashboard&id='.$sMenuId),
new JSPopupMenuItem('UI:ImportDashboard', Dict::S('UI:ImportDashBoard'),
"UploadDashboard({dashboard_id: '$sMenuId', title: '$sDlgTitle', text: '$sDlgText', close_btn: '$sCloseBtn', transaction: '$sUploadDashboardTransactId' })"),
);
break;
default:
// Unknown type of menu, do nothing
@@ -1500,7 +1482,7 @@ class utils
static public function GetCSSFromSASS($sSassRelPath, $aImportPaths = null)
{
// Avoiding compilation if file is already a css file.
if (preg_match('/\.css(\?.*)?$/', $sSassRelPath))
if (preg_match('/\.css$/', $sSassRelPath))
{
return $sSassRelPath;
}
@@ -2008,14 +1990,4 @@ class utils
$aHugeClasses = MetaModel::GetConfig()->Get('high_cardinality_classes');
return in_array($sClass, $aHugeClasses);
}
/**
* Check if iTop is in a development environment (VCS vs build number)
*
* @return bool
*/
public static function IsDevelopmentEnvironment()
{
return ITOP_REVISION === 'svn';
}
}

View File

@@ -311,10 +311,7 @@ class WebPage implements Page
}
/**
* Add a script (as an include, i.e. link) to the header of the page.<br>
* Handles duplicates : calling twice with the same script will add the script only once
*
* @param string $s_linked_script
* Add a script (as an include, i.e. link) to the header of the page
*/
public function add_linked_script($s_linked_script)
{

View File

@@ -154,7 +154,7 @@ class WizardHelper
}
else
{
// May happen for security reasons (portal, see ticket 1074)
// May happen for security reasons (portal, see ticket #1074)
$oObj->Set($sAttCode, $value);
}
}
@@ -174,30 +174,6 @@ class WizardHelper
}
$oObj->Set($sAttCode, $value);
}
else if ($oAttDef instanceof AttributeTagSet) // AttributeDate is derived from AttributeDateTime
{
if (is_null($value))
{
// happens if field is hidden (see N°1827)
$value = array();
}
else
{
$value = json_decode($value, true);
}
$oTagSet = new ormTagSet(get_class($oObj), $sAttCode, $oAttDef->GetMaxItems());
$oTagSet->SetValues($value['orig_value']);
$oTagSet->ApplyDelta($value);
$oObj->Set($sAttCode, $oTagSet);
}
else if ($oAttDef instanceof AttributeSet) // AttributeDate is derived from AttributeDateTime
{
$value = json_decode($value, true);
$oTagSet = new ormSet(get_class($oObj), $sAttCode, $oAttDef->GetMaxItems());
$oTagSet->SetValues($value['orig_value']);
$oTagSet->ApplyDelta($value);
$oObj->Set($sAttCode, $oTagSet);
}
else
{
$oObj->Set($sAttCode, $value);
@@ -229,10 +205,11 @@ class WizardHelper
// this as to be handled as an array of objects
// thus encoded in json like: [ { name:'link1', 'id': 123}, { name:'link2', 'id': 124}...]
// NOT YET IMPLEMENTED !!
$sLinkedClass = $oAttDef->GetLinkedClass();
$oSet = $value;
$aData = array();
$aFields = $this->GetLinkedWizardStructure($oAttDef);
while($oLinkedObj = $oSet->fetch())
while($oSet->fetch())
{
foreach($aFields as $sLinkedAttCode)
{

View File

@@ -40,7 +40,7 @@ Class XLSXWriter
protected function tempFilename()
{
$filename = tempnam(SetupUtils::GettmpDir(), 'xlsx_writer_');
$filename = tempnam("/tmp", "xlsx_writer_");
$this->temp_files[] = $filename;
return $filename;
}

View File

@@ -9,8 +9,6 @@
"ext-json": "*",
"ext-zip": "*",
"ext-mysqli": "*",
"ext-dom": "*",
"ext-iconv": "*",
"ext-gd": "*"
},
"config": {

View File

@@ -223,14 +223,7 @@ class ActionEmail extends ActionNotification
return implode(', ', $aRecipients);
}
/**
* @param \Trigger $oTrigger
* @param array $aContextArgs
*
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
*/
public function DoExecute($oTrigger, $aContextArgs)
{
if (MetaModel::IsLogEnabledNotification())
@@ -299,14 +292,6 @@ class ActionEmail extends ActionNotification
}
/**
* @param \Trigger $oTrigger
* @param array $aContextArgs
* @param \EventNotification $oLog
*
* @return string
* @throws \CoreException
*/
protected function _DoExecute($oTrigger, $aContextArgs, &$oLog)
{
$sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass();

View File

@@ -150,7 +150,7 @@ abstract class AsyncTask extends DBObject
public function GetRetryDelay($iErrorCode = null)
{
$iRetryDelay = 600;
$aRetries = MetaModel::GetConfig()->Get('async_task_retries');
$aRetries = MetaModel::GetConfig()->Get('async_task_retries', array());
if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries))
{
$aConfig = $aRetries[get_class($this)];
@@ -162,7 +162,7 @@ abstract class AsyncTask extends DBObject
public function GetMaxRetries($iErrorCode = null)
{
$iMaxRetries = 0;
$aRetries = MetaModel::GetConfig()->Get('async_task_retries');
$aRetries = MetaModel::GetConfig()->Get('async_task_retries', array());
if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries))
{
$aConfig = $aRetries[get_class($this)];
@@ -381,6 +381,6 @@ class AsyncSendEmail extends AsyncTask
case EMAIL_SEND_ERROR:
return "Failed: ".implode(', ', $aIssues);
}
return '';
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@@ -29,7 +29,6 @@ MetaModel::IncludeModule('core/action.class.inc.php');
MetaModel::IncludeModule('core/trigger.class.inc.php');
MetaModel::IncludeModule('core/bulkexport.class.inc.php');
MetaModel::IncludeModule('core/ownershiplock.class.inc.php');
MetaModel::IncludeModule('core/tagsetfield.class.inc.php');
MetaModel::IncludeModule('synchro/synchrodatasource.class.inc.php');
MetaModel::IncludeModule('core/backgroundtask.class.inc.php');
MetaModel::IncludeModule('core/inlineimage.class.inc.php');

View File

@@ -242,64 +242,6 @@ class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
return $sResult;
}
}
/**
* Record the modification of a tag set attribute
*
* @package iTopORM
*/
class CMDBChangeOpSetAttributeTagSet extends CMDBChangeOpSetAttribute
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb",
"key_type" => "",
"name_attcode" => "change",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_changeop_setatt_tagset",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeText("oldvalue", array("allowed_values"=>null, "sql"=>"oldvalue", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("newvalue", array("allowed_values"=>null, "sql"=>"newvalue", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode', 'oldvalue', 'newvalue')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode', 'oldvalue', 'newvalue')); // Attributes to be displayed for a list
}
/**
* Describe (as a text string) the modifications corresponding to this change
*/
public function GetDescription()
{
$sResult = '';
$sTargetObjectClass = $this->Get('objclass');
$oTargetObjectKey = $this->Get('objkey');
$sAttCode = $this->Get('attcode');
$oTargetSearch = new DBObjectSearch($sTargetObjectClass);
$oTargetSearch->AddCondition('id', $oTargetObjectKey, '=');
$oMonoObjectSet = new DBObjectSet($oTargetSearch);
if (UserRights::IsActionAllowedOnAttribute($sTargetObjectClass, $sAttCode, UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES)
{
if (!MetaModel::IsValidAttCode($this->Get('objclass'), $this->Get('attcode'))) return ''; // Protects against renamed attributes...
$oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode'));
$sAttName = $oAttDef->GetLabel();
$sNewValue = $this->Get('newvalue');
$sOldValue = $this->Get('oldvalue');
$sResult = $oAttDef->DescribeChangeAsHTML($sOldValue, $sNewValue);
}
return $sResult;
}
}
/**
* Record the modification of an URL
*

View File

@@ -188,16 +188,6 @@ abstract class CMDBObject extends DBObject
self::$m_oCurrChange->DBInsert();
}
/**
* @inheritdoc
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
* @throws \MySQLException
* @throws \OQLException
*/
protected function RecordObjCreation()
{
// Delete any existing change tracking about the current object (IDs can be reused due to InnoDb bug; see TRAC #886)
@@ -216,7 +206,6 @@ abstract class CMDBObject extends DBObject
MetaModel::PurgeData($oFilter);
parent::RecordObjCreation();
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpCreate");
$oMyChangeOp->Set("objclass", get_class($this));
$oMyChangeOp->Set("objkey", $this->GetKey());
@@ -243,17 +232,9 @@ abstract class CMDBObject extends DBObject
}
/**
* @param string $sAttCode
* @param $sAttCode
* @param $original Original value
* @param $value Current value
*
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
* @throws \MySQLException
* @throws \OQLException
*/
protected function RecordAttChange($sAttCode, $original, $value)
{
@@ -428,19 +409,7 @@ abstract class CMDBObject extends DBObject
$oMyChangeOp->Set("newvalue", $value);
$iId = $oMyChangeOp->DBInsertNoReload();
}
elseif ($oAttDef instanceOf AttributeSet)
{
// Tag Set
//
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeTagSet");
$oMyChangeOp->Set("objclass", get_class($this));
$oMyChangeOp->Set("objkey", $this->GetKey());
$oMyChangeOp->Set("attcode", $sAttCode);
$oMyChangeOp->Set("oldvalue", implode(' ', $original->GetValues()));
$oMyChangeOp->Set("newvalue", implode(' ', $value->GetValues()));
$iId = $oMyChangeOp->DBInsertNoReload();
}
else
else
{
// Scalars
//
@@ -457,14 +426,6 @@ abstract class CMDBObject extends DBObject
/**
* @param array $aValues
* @param array $aOrigValues
*
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
* @throws \MySQLException
* @throws \OQLException
*/
protected function RecordAttChanges(array $aValues, array $aOrigValues)
{
@@ -590,12 +551,6 @@ abstract class CMDBObject extends DBObject
$this->DBUpdate();
}
/**
* @param null $oDeletionPlan
*
* @return \DeletionPlan|null
* @throws \DeleteException
*/
public function DBDelete(&$oDeletionPlan = null)
{
return $this->DBDeleteTracked_Internal($oDeletionPlan);
@@ -608,12 +563,6 @@ abstract class CMDBObject extends DBObject
$this->DBDeleteTracked_Internal($oDeletionPlan);
}
/**
* @param null $oDeletionPlan
*
* @return \DeletionPlan|null
* @throws \DeleteException
*/
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
{
$prevkey = $this->GetKey();

View File

@@ -108,22 +108,18 @@ class MySQLHasGoneAwayException extends MySQLException
*/
class CMDBSource
{
const ENUM_DB_VENDOR_MYSQL = 'MySQL';
const ENUM_DB_VENDOR_MARIADB = 'MariaDB';
const ENUM_DB_VENDOR_PERCONA = 'Percona';
protected static $m_sDBHost;
protected static $m_sDBUser;
protected static $m_sDBPwd;
protected static $m_sDBName;
/**
* @var boolean
* @since 2.5 1260 MySQL TLS first implementation
* @since 2.5 #1260 MySQL TLS first implementation
*/
protected static $m_bDBTlsEnabled;
/**
* @var string
* @since 2.5 1260 MySQL TLS first implementation
* @since 2.5 #1260 MySQL TLS first implementation
*/
protected static $m_sDBTlsCA;
@@ -137,7 +133,7 @@ class CMDBSource
* use expression as value)
*
* @see https://dev.mysql.com/doc/refman/5.7/en/charset-column.html
* @since 2.5 1001 switch to utf8mb4
* @since 2.5 #1001 switch to utf8mb4
*/
public static function GetSqlStringColumnDefinition()
{
@@ -410,27 +406,6 @@ class CMDBSource
return $aVersions[0];
}
/**
* Get the DB vendor between MySQL and its main forks
* @return string
*/
static public function GetDBVendor()
{
$sDBVendor = static::ENUM_DB_VENDOR_MYSQL;
$sVersionComment = static::GetServerVariable('version') . ' - ' . static::GetServerVariable('version_comment');
if(preg_match('/mariadb/i', $sVersionComment) === 1)
{
$sDBVendor = static::ENUM_DB_VENDOR_MARIADB;
}
else if(preg_match('/percona/i', $sVersionComment) === 1)
{
$sDBVendor = static::ENUM_DB_VENDOR_PERCONA;
}
return $sDBVendor;
}
/**
* @param string $sSource
*
@@ -480,15 +455,10 @@ class CMDBSource
public static function DropTable($sTable)
{
$res = self::Query("DROP TABLE `$sTable`");
self::_TablesInfoCacheReset(); // reset the table info cache!
self::_TablesInfoCacheReset(true); // reset the table info cache!
return $res;
}
public static function CacheReset($sTable)
{
self::_TablesInfoCacheReset($sTable);
}
/**
* @return \mysqli
*/
@@ -900,20 +870,6 @@ class CMDBSource
return ($aFieldData["Type"]);
}
private static function IsNumericType($aFieldData)
{
$aNumericTypes = array('tinyint(', 'decimal(', 'int(' );
$sType = strtolower($aFieldData["Type"]);
foreach ($aNumericTypes as $sNumericType)
{
if (strpos($sType, $sNumericType) === 0)
{
return true;
}
}
return false;
}
/**
* @param string $sTable
* @param string $sField
@@ -952,15 +908,8 @@ class CMDBSource
}
else
{
if (self::IsNumericType($aFieldData))
{
$sRet .= ' DEFAULT '.$aFieldData["Default"];
}
else
{
$default = $aFieldData["Default"] + 0; // Coerce to a numeric variable
$sRet .= ' DEFAULT '.self::Quote($default);
}
$default = $aFieldData["Default"] + 0; // Coerce to a numeric variable
$sRet .= ' DEFAULT '.self::Quote($default);
}
}
elseif (is_string($aFieldData["Default"]) == 'string')
@@ -1018,16 +967,9 @@ class CMDBSource
// Cache the information about existing tables, and their fields
private static $m_aTablesInfo = array();
private static function _TablesInfoCacheReset($sTableName = null)
private static function _TablesInfoCacheReset()
{
if (is_null($sTableName))
{
self::$m_aTablesInfo = array();
}
else
{
self::$m_aTablesInfo[strtolower($sTableName)] = null;
}
self::$m_aTablesInfo = array();
}
/**
@@ -1100,7 +1042,7 @@ class CMDBSource
* @return string query to upgrade table charset and collation if needed, null if not
* @throws \MySQLException
*
* @since 2.5 1001 switch to utf8mb4
* @since 2.5 #1001 switch to utf8mb4
* @see https://dev.mysql.com/doc/refman/5.7/en/charset-table.html
*/
public static function DBCheckTableCharsetAndCollation($sTableName)
@@ -1250,7 +1192,7 @@ class CMDBSource
* @return string query to upgrade database charset and collation if needed, null if not
* @throws \MySQLException
*
* @since 2.5 1001 switch to utf8mb4
* @since 2.5 #1001 switch to utf8mb4
* @see https://dev.mysql.com/doc/refman/5.7/en/charset-database.html
*/
public static function DBCheckCharsetAndCollation()

View File

@@ -19,7 +19,7 @@
define('ITOP_APPLICATION', 'iTop');
define('ITOP_APPLICATION_SHORT', 'iTop');
define('ITOP_VERSION', '2.6.0');
define('ITOP_VERSION', '2.5.0');
define('ITOP_REVISION', 'svn');
define('ITOP_BUILD_DATE', '$WCNOW$');
@@ -37,7 +37,6 @@ define('ACCESS_READONLY', 0);
require_once('coreexception.class.inc.php');
require_once('attributedef.class.inc.php'); // For the defines
require_once('simplecrypt.class.inc.php');
class ConfigException extends CoreException
{
@@ -65,16 +64,13 @@ define('DEFAULT_FAST_RELOAD_INTERVAL', 1 * 60);
define('DEFAULT_SECURE_CONNECTION_REQUIRED', false);
define('DEFAULT_ALLOWED_LOGIN_TYPES', 'form|basic|external');
define('DEFAULT_EXT_AUTH_VARIABLE', '$_SERVER[\'REMOTE_USER\']');
define('DEFAULT_ENCRYPTION_KEY', '@iT0pEncr1pti0n!'); // We'll use a random generated key later (if possible)
define('DEFAULT_ENCRYPTION_LIB', 'Mcrypt'); // We'll define the best encryption available later
define('DEFAULT_ENCRYPTION_KEY', '@iT0pEncr1pti0n!'); // We'll use a random value, later...
/**
* Config
* configuration data (this class cannot not be localized, because it is responsible for loading the dictionaries)
*
* @package iTopORM
*
* @see \MetaModel::GetConfig() to get the config, if the metamodel was already loaded
* @see utils::GetConfig() to load config from the current env, if metamodel is not loaded
*/
class Config
{
@@ -97,7 +93,7 @@ class Config
protected $m_aSettings = array(
'app_env_label' => array(
'type' => 'string',
'description' => 'Label displayed to describe the current application environment, defaults to the environment name (e.g. "production")',
'description' => 'Label displayed to describe the current application environnment, defaults to the environment name (e.g. "production")',
'default' => '',
'value' => '',
'source_of_value' => '',
@@ -170,7 +166,7 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'db_character_set' => array( // @deprecated to remove in 2.7 ? 1001 utf8mb4 switch
'db_character_set' => array( // @deprecated to remove in 2.7 ? #1001 utf8mb4 switch
'type' => 'string',
'description' => 'Deprecated since iTop 2.5 : now using utf8mb4',
'default' => 'DEPRECATED_2.5',
@@ -178,7 +174,7 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'db_collation' => array( // @deprecated to remove in 2.7 ? 1001 utf8mb4 switch
'db_collation' => array( // @deprecated to remove in 2.7 ? #1001 utf8mb4 switch
'type' => 'string',
'description' => 'Deprecated since iTop 2.5 : now using utf8mb4_unicode_ci',
'default' => 'DEPRECATED_2.5',
@@ -204,7 +200,7 @@ class Config
),
'skip_strong_security' => array(
'type' => 'bool',
'description' => 'Disable strong security - TEMPORARY: this flag should be removed when we are more confident in the recent change in security',
'description' => 'Disable strong security - TEMPORY: this flag should be removed when we are more confident in the recent change in security',
'default' => true,
'value' => true,
'source_of_value' => '',
@@ -220,7 +216,7 @@ class Config
),
'query_indentation_enabled' => array(
'type' => 'bool',
'description' => 'For developers: format the SQL queries for human analysis',
'description' => 'For developpers: format the SQL queries for human analysis',
'default' => false,
'value' => false,
'source_of_value' => '',
@@ -228,7 +224,7 @@ class Config
),
'disable_mandatory_ext_keys' => array(
'type' => 'bool',
'description' => 'For developers: allow every external keys to be undefined',
'description' => 'For developpers: allow every external keys to be undefined',
'default' => false,
'value' => false,
'source_of_value' => '',
@@ -411,14 +407,6 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'tag_set_item_separator' => array(
'type' => 'string',
'description' => 'Tag set from string: tag label separator',
'default' => '|',
'value' => '|',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'cron_max_execution_time' => array(
'type' => 'integer',
'description' => 'Duration (seconds) of the page cron.php, must be shorter than php setting max_execution_time and shorter than the web server response timeout',
@@ -453,7 +441,7 @@ class Config
),
'email_transport' => array(
'type' => 'string',
'description' => 'Mean to send emails: PHPMail (uses the function mail()) or SMTP (implements the client protocol)',
'description' => 'Mean to send emails: PHPMail (uses the function mail()) or SMTP (implements the client protocole)',
'default' => "PHPMail",
'value' => "PHPMail",
'source_of_value' => '',
@@ -549,7 +537,7 @@ class Config
),
'timezone' => array(
'type' => 'string',
'description' => 'Timezone (reference: http://php.net/manual/en/timezones.php). If empty, it will be left unchanged and MUST be explicitly configured in PHP',
'description' => 'Timezone (reference: http://php.net/manual/en/timezones.php). If empty, it will be left unchanged and MUST be explicitely configured in PHP',
// examples... not used (nor 'description')
'examples' => array(
'America/Sao_Paulo',
@@ -947,7 +935,7 @@ class Config
),
'tracking_level_linked_set_default' => array(
'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)',
'description' => 'Default tracking level if not explicitely 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_LIST,
'value' => LINKSET_TRACKING_LIST,
'source_of_value' => '',
@@ -955,7 +943,7 @@ class Config
),
'tracking_level_linked_set_indirect_default' => array(
'type' => 'integer',
'description' => 'Default tracking level if not explicitly set at the attribute level, for AttributeLinkedSetIndirect',
'description' => 'Default tracking level if not explicitely set at the attribute level, for AttributeLinkedSetIndirect',
'default' => LINKSET_TRACKING_ALL,
'value' => LINKSET_TRACKING_ALL,
'source_of_value' => '',
@@ -996,7 +984,7 @@ class Config
'transaction_storage' => array(
'type' => 'string',
'description' => 'The type of mechanism to use for storing the unique identifiers for transactions (Session|File).',
'default' => 'File',
'default' => 'Session',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
@@ -1068,7 +1056,7 @@ class Config
'draft_attachments_lifetime' => array(
'type' => 'integer',
'description' => 'Lifetime (in seconds) of drafts\' attachments and inline images: after this duration, the garbage collector will delete them.',
'default' => 86400,
'default' => 3600,
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
@@ -1129,14 +1117,6 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'optimize_requests_for_join_count' => array(
'type' => 'bool',
'description' => 'Optimize request joins to minimize the count (default is true, try to set it to false in case of performance issues)',
'default' => true,
'value' => true,
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'high_cardinality_classes' => array(
'type' => 'array',
'description' => 'List of classes with high cardinality (Force manual submit of search)',
@@ -1145,22 +1125,6 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'newsroom_enabled' => array(
'type' => 'bool',
'description' => 'Whether or not the whole newsroom is enabled',
'default' => true,
'value' => true,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'regenerate_session_id_enabled' => array(
'type' => 'bool',
'description' => 'If true then session id will be regenerated on each login, to prevent session fixation.',
'default' => true,
'value' => true,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
);
public function IsProperty($sPropCode)
@@ -1220,11 +1184,6 @@ class Config
}
/**
* @param string $sPropCode
*
* @return mixed
*/
public function Get($sPropCode)
{
return $this->m_aSettings[$sPropCode]['value'];
@@ -1287,29 +1246,13 @@ class Config
*/
protected $m_sEncryptionKey;
/**
* @var string Encryption key used for all attributes of type "encrypted string". Can be set to a random value
* unless you want to import a database from another iTop instance, in which case you must use
* the same encryption key in order to properly decode the encrypted fields
*/
protected $m_sEncryptionLibrary;
/**
* @var array Additional character sets to be supported by the interactive CSV import
* 'iconv_code' => 'display name'
*/
protected $m_aCharsets;
/**
* Config constructor.
*
* @param string|null $sConfigFile
* @param bool $bLoadConfig
*
* @throws \ConfigException
* @throws \CoreException
*/
public function __construct($sConfigFile = null, $bLoadConfig = true)
public function __construct($sConfigFile = null, $bLoadConfig = true)
{
$this->m_sFile = $sConfigFile;
if (is_null($sConfigFile))
@@ -1339,14 +1282,10 @@ class Config
$this->m_sDefaultLanguage = 'EN US';
$this->m_sAllowedLoginTypes = DEFAULT_ALLOWED_LOGIN_TYPES;
$this->m_sExtAuthVariable = DEFAULT_EXT_AUTH_VARIABLE;
$this->m_sEncryptionKey = DEFAULT_ENCRYPTION_KEY;
$this->m_aCharsets = array();
$this->m_bQueryCacheEnabled = DEFAULT_QUERY_CACHE_ENABLED;
//define default encryption params according to php install
$aEncryptParams = SimpleCrypt::GetNewDefaultParams();
$this->m_sEncryptionLibrary = isset($aEncryptParams['lib']) ? $aEncryptParams['lib'] : DEFAULT_ENCRYPTION_LIB;
$this->m_sEncryptionKey= isset($aEncryptParams['key']) ? $aEncryptParams['key'] : DEFAULT_ENCRYPTION_KEY;
$this->m_aModuleSettings = array();
if ($bLoadConfig)
@@ -1371,13 +1310,7 @@ class Config
*/
}
/**
* @param string $sPurpose
* @param string $sFileName
*
* @throws \ConfigException
*/
protected function CheckFile($sPurpose, $sFileName)
protected function CheckFile($sPurpose, $sFileName)
{
if (!file_exists($sFileName))
{
@@ -1492,8 +1425,7 @@ class Config
$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;
$this->m_sEncryptionKey = isset($MySettings['encryption_key']) ? trim($MySettings['encryption_key']) : DEFAULT_ENCRYPTION_KEY;
$this->m_aCharsets = isset($MySettings['csv_import_charsets']) ? $MySettings['csv_import_charsets'] : array();
}
@@ -1514,14 +1446,7 @@ class Config
return $this->GetModuleParameter($sModule, $sProperty, $defaultvalue);
}
/**
* @param string $sModule
* @param string $sProperty
* @param mixed|null $defaultvalue
*
* @return mixed|null
*/
public function GetModuleParameter($sModule, $sProperty, $defaultvalue = null)
public function GetModuleParameter($sModule, $sProperty, $defaultvalue = null)
{
$ret = $defaultvalue;
if (class_exists('ModulesXMLParameters'))
@@ -1553,7 +1478,6 @@ class Config
/**
* @return string
*
* @deprecated 2.5 will be removed in 2.6
* @see Config::Get() as a replacement
*/
@@ -1564,7 +1488,6 @@ class Config
/**
* @return string
*
* @deprecated 2.5 will be removed in 2.6
* @see Config::Get() as a replacement
*/
@@ -1575,7 +1498,6 @@ class Config
/**
* @return string
*
* @deprecated 2.5 will be removed in 2.6
* @see Config::Get() as a replacement
*/
@@ -1586,8 +1508,7 @@ class Config
/**
* @return string
*
* @deprecated 2.5 will be removed in 2.6 N°1001 utf8mb4 switch
* @deprecated 2.5 will be removed in 2.6 #1001 utf8mb4 switch
* @see Config::DEFAULT_CHARACTER_SET
*/
public function GetDBCharacterSet()
@@ -1597,8 +1518,7 @@ class Config
/**
* @return string
*
* @deprecated 2.5 will be removed in 2.6 N°1001 utf8mb4 switch
* @deprecated 2.5 will be removed in 2.6 #1001 utf8mb4 switch
* @see Config::DEFAULT_COLLATION
*/
public function GetDBCollation()
@@ -1608,7 +1528,6 @@ class Config
/**
* @return string
*
* @deprecated 2.5 will be removed in 2.6
* @see Config::Get() as a replacement
*/
@@ -1619,7 +1538,6 @@ class Config
/**
* @return string
*
* @deprecated 2.5 will be removed in 2.6
* @see Config::Get() as a replacement
*/
@@ -1693,11 +1611,6 @@ class Config
return $this->m_sEncryptionKey;
}
public function GetEncryptionLibrary()
{
return $this->m_sEncryptionLibrary;
}
public function GetAllowedLoginTypes()
{
return explode('|', $this->m_sAllowedLoginTypes);
@@ -1826,7 +1739,6 @@ class Config
$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;
$aSettings['csv_import_charsets'] = $this->m_aCharsets;
foreach ($this->m_aModuleSettings as $sModule => $aProperties)
@@ -1844,16 +1756,14 @@ class Config
return $aSettings;
}
/**
* Write the configuration to a file (php format) that can be reloaded later
* By default write to the same file that was specified when constructing the object
*
* @param string $sFileName string Name of the file to write to (emtpy to write to the same file)
*
* @return boolean True otherwise throws an Exception
/**
* Write the configuration to a file (php format) that can be reloaded later
* By default write to the same file that was specified when constructing the object
*
* @throws \ConfigException
*/
* @param $sFileName string Name of the file to write to (emtpy to write to the same file)
*
* @return boolean True otherwise throws an Exception
*/
public function WriteToFile($sFileName = '')
{
if (empty($sFileName))
@@ -1915,7 +1825,6 @@ class Config
'allowed_login_types' => $this->m_sAllowedLoginTypes,
'ext_auth_variable' => $this->m_sExtAuthVariable,
'encryption_key' => $this->m_sEncryptionKey,
'encryption_library' => $this->m_sEncryptionLibrary,
'csv_import_charsets' => $this->m_aCharsets,
);
foreach ($aOtherValues as $sKey => $value)
@@ -2001,16 +1910,9 @@ class Config
}
}
/**
* Helper function to initialize a configuration from the page arguments
*
* @param array $aParamValues
* @param string|null $sModulesDir
* @param bool $bPreserveModuleSettings
*
* @throws \Exception
* @throws \CoreException
*/
/**
* Helper function to initialize a configuration from the page arguments
*/
public function UpdateFromParams($aParamValues, $sModulesDir = null, $bPreserveModuleSettings = false)
{
if (isset($aParamValues['application_path']))
@@ -2140,13 +2042,9 @@ class Config
}
}
/**
* Helper: for an array of string, change the prefix when found
*
* @param array $aStrings
* @param string $sSearchPrefix
* @param string $sNewPrefix
*/
/**
* Helper: for an array of string, change the prefix when found
*/
protected static function ChangePrefix(&$aStrings, $sSearchPrefix, $sNewPrefix)
{
foreach ($aStrings as &$sFile)
@@ -2158,13 +2056,10 @@ class Config
}
}
/**
* Obsolete: kept only for backward compatibility of the Toolkit
* Quick and dirty way to clone a config file into another environment
*
* @param string $sSourceEnv
* @param string $sTargetEnv
*/
/**
* Obsolete: kept only for backward compatibility of the Toolkit
* Quick and dirty way to clone a config file into another environment
*/
public function ChangeModulesPath($sSourceEnv, $sTargetEnv)
{
// Now does nothing since the includes are built into the environment itself
@@ -2201,3 +2096,5 @@ class Config
}
}
?>

View File

@@ -107,82 +107,6 @@ class CoreException extends Exception
}
}
/**
* Class CoreCannotSaveObjectException
*
* Specialized exception to raise if {@link DBObject::CheckToWrite()} fails, which allow easy data retrieval
*
* @see \DBObject::DBInsertNoReload()
* @see \DBObject::DBUpdate()
*
* @since 2.6 N°659 uniqueness constraint
*/
class CoreCannotSaveObjectException extends CoreException
{
/** @var string[] */
private $aIssues;
/** @var int */
private $iObjectId;
/** @var string */
private $sObjectClass;
/**
* CoreCannotSaveObjectException constructor.
*
* @param array $aContextData containing at least those keys : issues, id, class
*/
public function __construct($aContextData)
{
$this->aIssues = $aContextData['issues'];
$this->iObjectId = $aContextData['id'];
$this->sObjectClass = $aContextData['class'];
$sIssues = implode(', ', $this->aIssues);
parent::__construct($sIssues, $aContextData);
}
/**
* @return string
*/
public function getHtmlMessage()
{
$sTitle = Dict::S('UI:Error:SaveFailed');
$sContent = "<span><strong>{$sTitle}</strong></span>";
if (count($this->aIssues) == 1)
{
$sIssue = reset($this->aIssues);
$sContent .= " <span>{$sIssue}</span>";
}
else
{
$sContent .= '<ul>';
foreach ($this->aIssues as $sError)
{
$sContent .= "<li>$sError</li>";
}
$sContent .= '</ul>';
}
return $sContent;
}
public function getIssues()
{
return $this->aIssues;
}
public function getObjectId()
{
return $this->iObjectId;
}
public function getObjectClass()
{
return $this->sObjectClass;
}
}
class CoreWarning extends CoreException
{
}

View File

@@ -266,7 +266,7 @@ EOF
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 991)
// and thus to convert field by field and not the whole row or file at once (see ticket #991)
$aData[$idx] = @iconv('UTF-8', $this->aStatusInfo['charset'].'//IGNORE//TRANSLIT', $aData[$idx]);
}
}
@@ -325,7 +325,7 @@ EOF
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 991)
// and thus to convert field by field and not the whole row or file at once (see ticket #991)
$aData[] = @iconv('UTF-8', $this->aStatusInfo['charset'].'//IGNORE//TRANSLIT', $sField);
}
else

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.6">
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.5">
<user_rights>
<profiles>
<profile id="1024" _delta="define">

File diff suppressed because it is too large Load Diff

View File

@@ -480,11 +480,6 @@ class DBObjectSearch extends DBSearch
$oNewCondition = Expression::FromOQL($sOQLCondition);
break;
case 'MATCHES':
$oRightExpr = new ScalarExpression($value);
$oNewCondition = new MatchExpression($oField, $oRightExpr);
break;
case 'Contains':
case 'Begins with':
case 'Finishes with':
@@ -1304,13 +1299,6 @@ class DBObjectSearch extends DBSearch
$oRight = $this->OQLExpressionToCondition($sQuery, $oExpression->GetRightExpr(), $aClassAliases);
return new BinaryExpression($oLeft, $sOperator, $oRight);
}
elseif ($oExpression instanceof MatchOqlExpression)
{
$oLeft = $this->OQLExpressionToCondition($sQuery, $oExpression->GetLeftExpr(), $aClassAliases);
$oRight = $this->OQLExpressionToCondition($sQuery, $oExpression->GetRightExpr(), $aClassAliases);
return new MatchExpression($oLeft, $oRight);
}
elseif ($oExpression instanceof FieldOqlExpression)
{
$sClassAlias = $oExpression->GetParent();
@@ -1937,86 +1925,46 @@ class DBObjectSearch extends DBSearch
}
}
$bRootFirst = MetaModel::GetConfig()->Get('optimize_requests_for_join_count');
if ($bRootFirst)
// First query built from the root, adding all tables including the leaf
// Before N.1065 we were joining from the leaf first, but this wasn't a good choice :
// most of the time (obsolescence, friendlyname, ...) we want to get a root attribute !
//
$oSelectBase = null;
$aClassHierarchy = MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL, true);
$bIsClassStandaloneClass = (count($aClassHierarchy) == 1);
foreach($aClassHierarchy as $sSomeClass)
{
// First query built from the root, adding all tables including the leaf
// Before N.1065 we were joining from the leaf first, but this wasn't a good choice :
// most of the time (obsolescence, friendlyname, ...) we want to get a root attribute !
//
$oSelectBase = null;
$aClassHierarchy = MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL, true);
$bIsClassStandaloneClass = (count($aClassHierarchy) == 1);
foreach($aClassHierarchy as $sSomeClass)
if (!MetaModel::HasTable($sSomeClass))
{
if (!MetaModel::HasTable($sSomeClass))
{
continue;
}
self::DbgTrace("Adding join from root to leaf: $sSomeClass... let's call MakeSQLObjectQuerySingleTable()");
$oSelectParentTable = $this->MakeSQLObjectQuerySingleTable($oBuild, $aAttToLoad, $sSomeClass, $aExtKeys, $aValues);
if (is_null($oSelectBase))
{
$oSelectBase = $oSelectParentTable;
if (!$bIsClassStandaloneClass && (MetaModel::IsRootClass($sSomeClass)))
{
// As we're linking to root class first, we're adding a where clause on the finalClass attribute :
// COALESCE($sRootClassFinalClass IN ('$sExpectedClasses'), 1)
// If we don't, the child classes can be removed in the query optimisation phase, including the leaf that was queried
// So we still need to filter records to only those corresponding to the child classes !
// The coalesce is mandatory if we have a polymorphic query (left join)
$oClassListExpr = ListExpression::FromScalars(MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL));
$sFinalClassSqlColumnName = MetaModel::DBGetClassField($sSomeClass);
$oClassExpr = new FieldExpression($sFinalClassSqlColumnName, $oSelectBase->GetTableAlias());
$oInExpression = new BinaryExpression($oClassExpr, 'IN', $oClassListExpr);
$oTrueExpression = new TrueExpression();
$aCoalesceAttr = array($oInExpression, $oTrueExpression);
$oFinalClassRestriction = new FunctionExpression("COALESCE", $aCoalesceAttr);
$oBuild->m_oQBExpressions->AddCondition($oFinalClassRestriction);
}
}
else
{
$oSelectBase->AddInnerJoin($oSelectParentTable, $sKeyField, MetaModel::DBGetKey($sSomeClass));
}
continue;
}
}
else
{
// First query built upon on the leaf (ie current) class
//
self::DbgTrace("Main (=leaf) class, call MakeSQLObjectQuerySingleTable()");
if (MetaModel::HasTable($sClass))
self::DbgTrace("Adding join from root to leaf: $sSomeClass... let's call MakeSQLObjectQuerySingleTable()");
$oSelectParentTable = $this->MakeSQLObjectQuerySingleTable($oBuild, $aAttToLoad, $sSomeClass, $aExtKeys, $aValues);
if (is_null($oSelectBase))
{
$oSelectBase = $this->MakeSQLObjectQuerySingleTable($oBuild, $aAttToLoad, $sClass, $aExtKeys, $aValues);
$oSelectBase = $oSelectParentTable;
if (!$bIsClassStandaloneClass && (MetaModel::IsRootClass($sSomeClass)))
{
// As we're linking to root class first, we're adding a where clause on the finalClass attribute :
// COALESCE($sRootClassFinalClass IN ('$sExpectedClasses'), 1)
// If we don't, the child classes can be removed in the query optimisation phase, including the leaf that was queried
// So we still need to filter records to only those corresponding to the child classes !
// The coalesce is mandatory if we have a polymorphic query (left join)
$oClassListExpr = ListExpression::FromScalars(MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL));
$sFinalClassSqlColumnName = MetaModel::DBGetClassField($sSomeClass);
$oClassExpr = new FieldExpression($sFinalClassSqlColumnName, $oSelectBase->GetTableAlias());
$oInExpression = new BinaryExpression($oClassExpr, 'IN', $oClassListExpr);
$oTrueExpression = new TrueExpression();
$aCoalesceAttr = array($oInExpression, $oTrueExpression);
$oFinalClassRestriction = new FunctionExpression("COALESCE", $aCoalesceAttr);
$oBuild->m_oQBExpressions->AddCondition($oFinalClassRestriction);
}
}
else
{
$oSelectBase = null;
// As the join will not filter on the expected classes, we have to specify it explicitely
$sExpectedClasses = implode("', '", MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL));
$oFinalClassRestriction = Expression::FromOQL("`$sClassAlias`.finalclass IN ('$sExpectedClasses')");
$oBuild->m_oQBExpressions->AddCondition($oFinalClassRestriction);
}
// Then we join the queries of the eventual parent classes (compound model)
foreach(MetaModel::EnumParentClasses($sClass) as $sParentClass)
{
if (!MetaModel::HasTable($sParentClass)) continue;
self::DbgTrace("Parent class: $sParentClass... let's call MakeSQLObjectQuerySingleTable()");
$oSelectParentTable = $this->MakeSQLObjectQuerySingleTable($oBuild, $aAttToLoad, $sParentClass, $aExtKeys, $aValues);
if (is_null($oSelectBase))
{
$oSelectBase = $oSelectParentTable;
}
else
{
$oSelectBase->AddInnerJoin($oSelectParentTable, $sKeyField, MetaModel::DBGetKey($sParentClass));
}
$oSelectBase->AddInnerJoin($oSelectParentTable, $sKeyField, MetaModel::DBGetKey($sSomeClass));
}
}

View File

@@ -38,7 +38,7 @@ class DBObjectSet implements iDBObjectSetIterator
*/
protected $m_aAddedIds; // Ids of objects added (discrete lists)
/**
* @var array array of (row => array of (classalias) => object/null) storing the objects added "in memory"
* @var hash array of (row => array of (classalias) => object/null) storing the objects added "in memory"
*/
protected $m_aAddedObjects;
/**
@@ -118,19 +118,12 @@ class DBObjectSet implements iDBObjectSetIterator
}
}
/**
* @return string
*
* @throws \Exception
* @throws \CoreException
* @throws \MissingQueryArgument
*/
public function __toString()
{
$sRet = '';
$this->Rewind();
$sRet .= "Set (".$this->m_oFilter->ToOQL().")<br/>\n";
$sRet .= "Query: <pre style=\"font-size: smaller; display:inline;\">".$this->m_oFilter->MakeSelectQuery().")</pre>\n";
$sRet .= "Query: <pre style=\"font-size: smaller; display:inline;\">".$this->m_oFilter->MakeSelectQuery().")</pre>\n";
$sRet .= $this->Count()." records<br/>\n";
if ($this->Count() > 0)
@@ -178,16 +171,13 @@ class DBObjectSet implements iDBObjectSetIterator
return $this->m_oFilter->GetShowObsoleteData();
}
/**
* Specify the subset of attributes to load (for each class of objects) before performing the SQL query for retrieving the rows from the DB
*
* @param array $aAttToLoad Format: alias => array of attribute_codes
*
* @return void
*
* @throws \Exception
* @throws \CoreException
*/
/**
* Specify the subset of attributes to load (for each class of objects) before performing the SQL query for retrieving the rows from the DB
*
* @param array $aAttToLoad Format: alias => array of attribute_codes
*
* @return void
*/
public function OptimizeColumnLoad($aAttToLoad)
{
if (is_null($aAttToLoad))
@@ -259,15 +249,13 @@ class DBObjectSet implements iDBObjectSetIterator
}
}
/**
* Create a set (in-memory) containing just the given object
*
* @param \DBobject $oObject
*
* @return \DBObjectSet The singleton set
*
* @throws \Exception
*/
/**
* Create a set (in-memory) containing just the given object
*
* @param DBobject $oObject
*
* @return DBObjectSet The singleton set
*/
static public function FromObject($oObject)
{
$oRetSet = self::FromScratch(get_class($oObject));
@@ -275,15 +263,13 @@ class DBObjectSet implements iDBObjectSetIterator
return $oRetSet;
}
/**
* Create an empty set (in-memory), for the given class (and its subclasses) of objects
*
* @param string $sClass The class (or an ancestor) for the objects to be added in this set
*
* @return \DBObjectSet The empty set
*
* @throws \Exception
*/
/**
* Create an empty set (in-memory), for the given class (and its subclasses) of objects
*
* @param string $sClass The class (or an ancestor) for the objects to be added in this set
*
* @return DBObjectSet The empty set
*/
static public function FromScratch($sClass)
{
$oFilter = new DBObjectSearch($sClass);
@@ -292,38 +278,34 @@ class DBObjectSet implements iDBObjectSetIterator
$oRetSet->m_bLoaded = true; // no DB load
$oRetSet->m_iNumTotalDBRows = 0; // Nothing from the DB
return $oRetSet;
}
}
/**
* Create a set (in-memory) with just one column (i.e. one object per row) and filled with the given array of objects
*
* @param string $sClass The class of the objects (must be a common ancestor to all objects in the set)
* @param array $aObjects The list of objects to add into the set
*
* @return \DBObjectSet
*
* @throws \Exception
*/
/**
* Create a set (in-memory) with just one column (i.e. one object per row) and filled with the given array of objects
*
* @param string $sClass The class of the objects (must be a common ancestor to all objects in the set)
* @param array $aObjects The list of objects to add into the set
*
* @return DBObjectSet
*/
static public function FromArray($sClass, $aObjects)
{
$oRetSet = self::FromScratch($sClass);
$oRetSet->AddObjectArray($aObjects, $sClass);
return $oRetSet;
}
}
/**
* Create a set in-memory with several classes of objects per row (with one alias per "column")
*
* Limitation:
* The filter/OQL query representing such a set can not be rebuilt (only the first column will be taken into account)
*
* @param array $aClasses Format: array of (alias => class)
* @param array $aObjects Format: array of (array of (classalias => object))
*
* @return \DBObjectSet
*
* @throws \Exception
*/
/**
* Create a set in-memory with several classes of objects per row (with one alias per "column")
*
* Limitation:
* The filter/OQL query representing such a set can not be rebuilt (only the first column will be taken into account)
*
* @param hash $aClasses Format: array of (alias => class)
* @param hash $aObjects Format: array of (array of (classalias => object))
*
* @return DBObjectSet
*/
static public function FromArrayAssoc($aClasses, $aObjects)
{
// In a perfect world, we should create a complete tree of DBObjectSearch,
@@ -342,19 +324,9 @@ class DBObjectSet implements iDBObjectSetIterator
$oRetSet->AddObjectExtended($aObjectsByClassAlias);
}
return $oRetSet;
}
}
/**
* @param $oObject
* @param string $sLinkSetAttCode
* @param string $sExtKeyToRemote
*
* @return \DBObjectSet
*
* @throws \Exception
* @throws \ArchivedObjectException
* @throws \CoreException
*/static public function FromLinkSet($oObject, $sLinkSetAttCode, $sExtKeyToRemote)
static public function FromLinkSet($oObject, $sLinkSetAttCode, $sExtKeyToRemote)
{
$oLinkAttCode = MetaModel::GetAttributeDef(get_class($oObject), $sLinkSetAttCode);
$oExtKeyAttDef = MetaModel::GetAttributeDef($oLinkAttCode->GetLinkedClass(), $sExtKeyToRemote);
@@ -374,13 +346,7 @@ class DBObjectSet implements iDBObjectSetIterator
* Note: After calling this method, the set cursor will be at the end of the set. You might want to rewind it.
*
* @param bool $bWithId
*
* @return array
*
* @throws \Exception
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
public function ToArray($bWithId = true)
{
@@ -398,16 +364,8 @@ class DBObjectSet implements iDBObjectSetIterator
}
}
return $aRet;
}
}
/**
* @return array
*
* @throws \Exception
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
public function ToArrayOfValues()
{
if (!$this->m_bLoaded) $this->Load();
@@ -463,11 +421,7 @@ class DBObjectSet implements iDBObjectSetIterator
*
* @param string $sAttCode
* @param bool $bWithId
*
* @return array
*
* @throws \Exception
* @throws \CoreException
*/
public function GetColumnAsArray($sAttCode, $bWithId = true)
{
@@ -487,16 +441,14 @@ class DBObjectSet implements iDBObjectSetIterator
return $aRet;
}
/**
* Retrieve the DBSearch corresponding to the objects present in this set
*
* Limitation:
* This method will NOT work for sets with several columns (i.e. several objects per row)
*
* @return \DBObjectSearch
*
* @throws \CoreException
*/
/**
* Retrieve the DBSearch corresponding to the objects present in this set
*
* Limitation:
* This method will NOT work for sets with several columns (i.e. several objects per row)
*
* @return DBObjectSearch
*/
public function GetFilter()
{
// Make sure that we carry on the parameters of the set with the filter
@@ -543,20 +495,18 @@ class DBObjectSet implements iDBObjectSetIterator
/**
* The list of all classes (one per column) which are part of this set
*
* @return array Format: alias => class
* @return hash Format: alias => class
*/
public function GetSelectedClasses()
{
return $this->m_oFilter->GetSelectedClasses();
}
/**
* The root class (i.e. highest ancestor in the MeaModel class hierarchy) for the first column on this set
*
* @return string The root class for the objects in the first column of the set
*
* @throws \CoreException
*/
/**
* The root class (i.e. highest ancestor in the MeaModel class hierarchy) for the first column on this set
*
* @return string The root class for the objects in the first column of the set
*/
public function GetRootClass()
{
return MetaModel::GetRootClass($this->GetClass());
@@ -565,7 +515,7 @@ class DBObjectSet implements iDBObjectSetIterator
/**
* The arguments used for building this set
*
* @return array Format: parameter_name => value
* @return hash Format: parameter_name => value
*/
public function GetArgs()
{
@@ -583,13 +533,11 @@ class DBObjectSet implements iDBObjectSetIterator
$this->m_iLimitStart = $iLimitStart;
}
/**
* Sets the sort order for loading the rows from the DB. Changing the order by causes a Reload.
*
* @param array $aOrderBy Format: [alias.]attcode => boolean (true = ascending, false = descending)
*
* @throws \MySQLException
*/
/**
* Sets the sort order for loading the rows from the DB. Changing the order by causes a Reload.
*
* @param hash $aOrderBy Format: [alias.]attcode => boolean (true = ascending, false = descending)
*/
public function SetOrderBy($aOrderBy)
{
if ($this->m_aOrderBy != $aOrderBy)
@@ -603,14 +551,11 @@ class DBObjectSet implements iDBObjectSetIterator
}
}
/**
* Sets the sort order for loading the rows from the DB. Changing the order by causes a Reload.
*
* @param array $aAliases Format: alias => boolean (true = ascending, false = descending). If omitted, then it defaults to all the selected classes
*
* @throws \CoreException
* @throws \MySQLException
*/
/**
* Sets the sort order for loading the rows from the DB. Changing the order by causes a Reload.
*
* @param hash $aAliases Format: alias => boolean (true = ascending, false = descending). If omitted, then it defaults to all the selected classes
*/
public function SetOrderByClasses($aAliases = null)
{
if ($aAliases === null)
@@ -654,15 +599,13 @@ class DBObjectSet implements iDBObjectSetIterator
return $this->m_iLimitStart;
}
/**
* Get the sort order used for loading this set from the database
*
* Limitation: the sort order has no effect on objects added in-memory
*
* @return array Format: field_code => boolean (true = ascending, false = descending)
*
* @throws \CoreException
*/
/**
* Get the sort order used for loading this set from the database
*
* Limitation: the sort order has no effect on objects added in-memory
*
* @return array Format: field_code => boolean (true = ascending, false = descending)
*/
public function GetRealSortOrder()
{
if (!$this->m_bSort)
@@ -682,12 +625,9 @@ class DBObjectSet implements iDBObjectSetIterator
}
}
/**
* Loads the set from the database. Actually performs the SQL query to retrieve the records from the DB.
*
* @throws \Exception
* @throws \MySQLException
*/
/**
* Loads the set from the database. Actually performs the SQL query to retrieve the records from the DB.
*/
public function Load()
{
if ($this->m_bLoaded) return;
@@ -742,14 +682,11 @@ class DBObjectSet implements iDBObjectSetIterator
$this->m_iNumLoadedDBRows = $this->m_oSQLResult->num_rows;
}
/**
* @param string[] $aAttToLoad
*
* @return string SQL query
*
* @throws \CoreException
* @throws \MissingQueryArgument
*/
/**
* @param string[] $aAttToLoad
*
* @return string SQL query
*/
private function _makeSelectQuery($aAttToLoad)
{
if ($this->m_iLimitCount > 0)
@@ -766,20 +703,15 @@ class DBObjectSet implements iDBObjectSetIterator
return $sSQL;
}
/**
* The total number of rows in this set. Independently of the SetLimit used for loading the set and taking into
* account the rows added in-memory.
*
* May actually perform the SQL query SELECT COUNT... if the set was not previously loaded, or loaded with a
* SetLimit
*
* @return int The total number of rows for this set.
*
* @throws \CoreException
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
/**
* The total number of rows in this set. Independently of the SetLimit used for loading the set and taking into
* account the rows added in-memory.
*
* May actually perform the SQL query SELECT COUNT... if the set was not previously loaded, or loaded with a
* SetLimit
*
* @return int The total number of rows for this set.
*/
public function Count()
{
if (is_null($this->m_iNumTotalDBRows))
@@ -800,7 +732,6 @@ class DBObjectSet implements iDBObjectSetIterator
* @param $iLimit
*
* @return bool
*
* @throws \CoreException
* @throws \MissingQueryArgument
* @throws \MySQLException
@@ -815,8 +746,8 @@ class DBObjectSet implements iDBObjectSetIterator
if ($resQuery)
{
$aRow = CMDBSource::FetchArray($resQuery);
$iCount = intval($aRow['COUNT']);
CMDBSource::FreeResult($resQuery);
$iCount = intval($aRow['COUNT']);
}
else
{
@@ -835,7 +766,6 @@ class DBObjectSet implements iDBObjectSetIterator
* @param $iLimit
*
* @return int
*
* @throws \CoreException
* @throws \MissingQueryArgument
* @throws \MySQLException
@@ -876,17 +806,12 @@ class DBObjectSet implements iDBObjectSetIterator
return $this->m_iNumLoadedDBRows + count($this->m_aAddedObjects);
}
/**
* Fetch the object (with the given class alias) at the current position in the set and move the cursor to the next position.
*
* @param string $sRequestedClassAlias The class alias to fetch (if there are several objects/classes per row)
*
* @return \DBObject The fetched object or null when at the end
*
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
/**
* Fetch the object (with the given class alias) at the current position in the set and move the cursor to the next position.
*
* @param string $sRequestedClassAlias The class alias to fetch (if there are several objects/classes per row)
* @return DBObject The fetched object or null when at the end
*/
public function Fetch($sRequestedClassAlias = '')
{
if (!$this->m_bLoaded) $this->Load();
@@ -930,15 +855,11 @@ class DBObjectSet implements iDBObjectSetIterator
return $oRetObj;
}
/**
* Fetch the whole row of objects (if several classes have been specified in the query) and move the cursor to the next position
*
* @return array An associative with the format 'classAlias' => $oObj representing the current row of the set. Returns null when at the end.
*
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
/**
* Fetch the whole row of objects (if several classes have been specified in the query) and move the cursor to the next position
*
* @return hash A hash with the format 'classAlias' => $oObj representing the current row of the set. Returns null when at the end.
*/
public function FetchAssoc()
{
if (!$this->m_bLoaded) $this->Load();
@@ -981,8 +902,6 @@ class DBObjectSet implements iDBObjectSetIterator
/**
* Position the cursor (for iterating in the set) to the first position (equivalent to Seek(0))
*
* @throws \Exception
*/
public function Rewind()
{
@@ -992,18 +911,11 @@ class DBObjectSet implements iDBObjectSetIterator
}
}
/**
* Position the cursor (for iterating in the set) to the given position
*
* @param int $iRow
*
* @return int|mixed
*
* @throws \CoreException
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
/**
* Position the cursor (for iterating in the set) to the given position
*
* @param int $iRow
*/
public function Seek($iRow)
{
if (!$this->m_bLoaded) $this->Load();
@@ -1016,17 +928,15 @@ class DBObjectSet implements iDBObjectSetIterator
return $this->m_iCurrRow;
}
/**
* Add an object to the current set (in-memory only, nothing is written to the database)
*
* Limitation:
* Sets with several objects per row are NOT supported
*
* @param \DBObject $oObject The object to add
* @param string $sClassAlias The alias for the class of the object
*
* @throws \MySQLException
*/
/**
* Add an object to the current set (in-memory only, nothing is written to the database)
*
* Limitation:
* Sets with several objects per row are NOT supported
*
* @param DBObject $oObject The object to add
* @param string $sClassAlias The alias for the class of the object
*/
public function AddObject($oObject, $sClassAlias = '')
{
if (!$this->m_bLoaded) $this->Load();
@@ -1044,18 +954,16 @@ class DBObjectSet implements iDBObjectSetIterator
}
}
/**
* Add a hash containig objects into the current set.
*
* The expected format for the hash is: $aObjectArray[$idx][$sClassAlias] => $oObject
* Limitation:
* The aliases MUST match the ones used in the current set
* Only the ID of the objects associated to the first alias (column) is remembered.. in case we have to rebuild a filter
*
* @param array $aObjectArray
*
* @throws \MySQLException
*/
/**
* Add a hash containig objects into the current set.
*
* The expected format for the hash is: $aObjectArray[$idx][$sClassAlias] => $oObject
* Limitation:
* The aliases MUST match the ones used in the current set
* Only the ID of the objects associated to the first alias (column) is remembered.. in case we have to rebuild a filter
*
* @param hash $aObjectArray
*/
protected function AddObjectExtended($aObjectArray)
{
if (!$this->m_bLoaded) $this->Load();
@@ -1075,17 +983,15 @@ class DBObjectSet implements iDBObjectSetIterator
}
}
/**
* Add an array of objects into the current set
*
* Limitation:
* Sets with several classes per row are not supported (use AddObjectExtended instead)
*
* @param array $aObjects The array of objects to add
* @param string $sClassAlias The Alias of the class for the added objects
*
* @throws \MySQLException
*/
/**
* Add an array of objects into the current set
*
* Limitation:
* Sets with several classes per row are not supported (use AddObjectExtended instead)
*
* @param array $aObjects The array of objects to add
* @param string $sClassAlias The Alias of the class for the added objects
*/
public function AddObjectArray($aObjects, $sClassAlias = '')
{
if (!$this->m_bLoaded) $this->Load();
@@ -1103,9 +1009,8 @@ class DBObjectSet implements iDBObjectSetIterator
* Limitation:
* The added objects are not checked for duplicates (i.e. one cann add several times the same object, or add an object already present in the set).
*
* @param \DBObjectSet $oObjectSet The set to append
*
* @throws \CoreException
* @param DBObjectSet $oObjectSet The set to append
* @throws CoreException
*/
public function Append(DBObjectSet $oObjectSet)
{
@@ -1122,24 +1027,17 @@ class DBObjectSet implements iDBObjectSetIterator
}
}
/**
* Create a set containing the objects present in both the current set and another specified set
*
* Limitations:
* Will NOT work if only a subset of the sets was loaded with SetLimit.
* Works only with sets made of objects loaded from the database since the comparison is based on the objects identifiers
*
* @param \DBObjectSet $oObjectSet The set to intersect with. The current position inside the set will be lost (= at the end)
*
* @return \DBObjectSet A new set of objects, containing the objects present in both sets (based on their identifier)
*
* @throws \Exception
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
/**
* Create a set containing the objects present in both the current set and another specified set
*
* Limitations:
* Will NOT work if only a subset of the sets was loaded with SetLimit.
* Works only with sets made of objects loaded from the database since the comparison is based on the objects identifiers
*
* @param DBObjectSet $oObjectSet The set to intersect with. The current position inside the set will be lost (= at the end)
* @throws CoreException
* @return DBObjectSet A new set of objects, containing the objects present in both sets (based on their identifier)
*/
public function CreateIntersect(DBObjectSet $oObjectSet)
{
if ($this->GetRootClass() != $oObjectSet->GetRootClass())
@@ -1171,19 +1069,16 @@ class DBObjectSet implements iDBObjectSetIterator
return $oNewSet;
}
/**
* Compare two sets of objects to determine if their content is identical or not.
*
* Limitation:
* Works only for sets of 1 column (i.e. one class of object selected)
*
* @param \DBObjectSet $oObjectSet
* @param array $aExcludeColumns The list of columns to exclude frop the comparison
*
* @return boolean True if the sets are identical, false otherwise
*
* @throws \CoreException
*/
/**
* Compare two sets of objects to determine if their content is identical or not.
*
* Limitation:
* Works only for sets of 1 column (i.e. one class of object selected)
*
* @param DBObjectSet $oObjectSet
* @param array $aExcludeColumns The list of columns to exclude frop the comparison
* @return boolean True if the sets are identical, false otherwise
*/
public function HasSameContents(DBObjectSet $oObjectSet, $aExcludeColumns = array())
{
$oComparator = new DBObjectSetComparator($this, $oObjectSet, $aExcludeColumns);
@@ -1197,12 +1092,10 @@ class DBObjectSet implements iDBObjectSetIterator
* The objects inside the set must be written in the database since the comparison is based on their identifiers
* Sets with several objects per row are NOT supported
*
* @param \DBObjectSet $oObjectSet
* @param DBObjectSet $oObjectSet
* @throws CoreException
*
* @return \DBObjectSet The "delta" set.
*
* @throws \Exception
* @throws \CoreException
* @return DBObjectSet The "delta" set.
*/
public function CreateDelta(DBObjectSet $oObjectSet)
{
@@ -1235,11 +1128,9 @@ class DBObjectSet implements iDBObjectSetIterator
return $oNewSet;
}
/**
* Will be deprecated soon - use MetaModel::GetRelatedObjectsDown/Up instead to take redundancy into account
*
* @throws \Exception
*/
/**
* Will be deprecated soon - use MetaModel::GetRelatedObjectsDown/Up instead to take redundancy into account
*/
public function GetRelatedObjects($sRelCode, $iMaxDepth = 99)
{
$aRelatedObjs = array();
@@ -1263,21 +1154,16 @@ class DBObjectSet implements iDBObjectSetIterator
return $aRelatedObjs;
}
/**
* Compute the "RelatedObjects" (forward or "down" direction) for the set
* for the specified relation
*
* @param string $sRelCode The code of the relation to use for the computation
* @param int $iMaxDepth Maximum recursion depth
* @param bool $bEnableRedundancy
*
* @return \RelationGraph The graph of all the related objects
*
* @throws \Exception
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
/**
* Compute the "RelatedObjects" (forward or "down" direction) for the set
* for the specified relation
*
* @param string $sRelCode The code of the relation to use for the computation
* @param int $iMaxDepth Maximum recursion depth
* @param boolean $bEnableReduncancy Whether or not to take into account the redundancy
*
* @return RelationGraph The graph of all the related objects
*/
public function GetRelatedObjectsDown($sRelCode, $iMaxDepth = 99, $bEnableRedundancy = true)
{
$oGraph = new RelationGraph();
@@ -1289,22 +1175,17 @@ class DBObjectSet implements iDBObjectSetIterator
$oGraph->ComputeRelatedObjectsDown($sRelCode, $iMaxDepth, $bEnableRedundancy);
return $oGraph;
}
/**
* Compute the "RelatedObjects" (reverse or "up" direction) for the set
* for the specified relation
*
* @param string $sRelCode The code of the relation to use for the computation
* @param int $iMaxDepth Maximum recursion depth
* @param bool $bEnableRedundancy
*
* @return \RelationGraph The graph of all the related objects
*
* @throws \Exception
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
/**
* Compute the "RelatedObjects" (reverse or "up" direction) for the set
* for the specified relation
*
* @param string $sRelCode The code of the relation to use for the computation
* @param int $iMaxDepth Maximum recursion depth
* @param boolean $bEnableReduncancy Whether or not to take into account the redundancy
*
* @return RelationGraph The graph of all the related objects
*/
public function GetRelatedObjectsUp($sRelCode, $iMaxDepth = 99, $bEnableRedundancy = true)
{
$oGraph = new RelationGraph();
@@ -1316,21 +1197,14 @@ class DBObjectSet implements iDBObjectSetIterator
$oGraph->ComputeRelatedObjectsUp($sRelCode, $iMaxDepth, $bEnableRedundancy);
return $oGraph;
}
/**
* Builds an object that contains the values that are common to all the objects
* in the set. If for a given attribute, objects in the set have various values
* then the resulting object will contain null for this value.
*
* @param array $aValues Hash Output: the distribution of the values, in the set, for each attribute
*
* @return \DBObject The object with the common values
*
* @throws \Exception
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
/**
* Builds an object that contains the values that are common to all the objects
* in the set. If for a given attribute, objects in the set have various values
* then the resulting object will contain null for this value.
* @param $aValues Hash Output: the distribution of the values, in the set, for each attribute
* @return DBObject The object with the common values
*/
public function ComputeCommonObject(&$aValues)
{
$sClass = $this->GetClass();
@@ -1414,7 +1288,7 @@ class DBObjectSet implements iDBObjectSetIterator
/**
* List the constant fields (and their value) in the given query
* @return array [Alias][AttCode] => value
* @return Hash [Alias][AttCode] => value
*/
public function ListConstantFields()
{
@@ -1504,12 +1378,10 @@ class DBObjectSetComparator
$this->oSet1 = $oSet1;
$this->oSet2 = $oSet2;
}
/**
* Builds the lists of fingerprints and initializes internal structures, if it was not already done
*
* @throws \CoreException
*/
/**
* Builds the lists of fingerprints and initializes internal structures, if it was not already done
*/
protected function ComputeFingerprints()
{
if ($this->aFingerprints1 === null)
@@ -1554,13 +1426,11 @@ class DBObjectSetComparator
}
}
}
/**
* Tells if the sets are equivalent or not. Returns as soon as the first difference is found.
* @return boolean true if the set have an equivalent content, false otherwise
*
* @throws \CoreException
*/
/**
* Tells if the sets are equivalent or not. Returns as soon as the first difference is found.
* @return boolean true if the set have an equivalent content, false otherwise
*/
public function SetsAreEquivalent()
{
if (($this->oSet1 === null) && ($this->oSet2 === null))
@@ -1599,16 +1469,13 @@ class DBObjectSetComparator
return true;
}
/**
* Get the list of differences between the two sets. In ordeer to write back into the database only the minimum changes
* THE FIRST SET MUST BE THE ONE LOADED FROM THE DATABASE
* Returns a hash: 'added' => DBObject(s), 'removed' => DBObject(s), 'modified' => DBObjects(s)
* @return array
*
* @throws \Exception
* @throws \CoreException
*/
/**
* Get the list of differences between the two sets. In ordeer to write back into the database only the minimum changes
* THE FIRST SET MUST BE THE ONE LOADED FROM THE DATABASE
* Returns a hash: 'added' => DBObject(s), 'removed' => DBObject(s), 'modified' => DBObjects(s)
* @return Ambigous <int:DBObject: , unknown>
*/
public function GetDifferences()
{
$aResult = array('added' => array(), 'removed' => array(), 'modified' => array());
@@ -1657,19 +1524,13 @@ class DBObjectSetComparator
}
return $aResult;
}
/**
* Helpr to clone (in memory) an object and to apply to it the values taken from a second object
*
* @param \DBObject $oObjToClone
* @param \DBObject $oObjWithValues
*
* @return \DBObject The modified clone
*
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
*/
/**
* Helpr to clone (in memory) an object and to apply to it the values taken from a second object
* @param DBObject $oObjToClone
* @param DBObject $oObjWithValues
* @return DBObject The modified clone
*/
protected function CopyFrom($oObjToClone, $oObjWithValues)
{
$oObj = MetaModel::GetObject(get_class($oObjToClone), $oObjToClone->GetKey());

View File

@@ -235,96 +235,29 @@ abstract class DBSearch
abstract public function GetInternalParams();
abstract public function GetQueryParams($bExcludeMagicParams = true);
abstract public function ListConstantFields();
/**
* Turn the parameters (:xxx) into scalar values in order to easily
* serialize a search
*
* @param array $aArgs
*
* @return string
*/
abstract public function ApplyParameters($aArgs);
public function serialize($bDevelopParams = false, $aContextParams = array())
public function serialize($bDevelopParams = false, $aContextParams = null)
{
$aQueryParams = $this->GetQueryParams();
$aContextParams = array_merge($this->GetInternalParams(), $aContextParams);
foreach($aQueryParams as $sParam => $sValue)
{
if (isset($aContextParams[$sParam]))
{
$aQueryParams[$sParam] = $aContextParams[$sParam];
}
elseif (($iPos = strpos($sParam, '->')) !== false)
{
$sParamName = substr($sParam, 0, $iPos);
if (isset($aContextParams[$sParamName.'->object()']))
{
$sAttCode = substr($sParam, $iPos + 2);
/** @var \DBObject $oObj */
$oObj = $aContextParams[$sParamName.'->object()'];
if ($oObj->IsModified())
{
if ($sAttCode == 'id')
{
$aQueryParams[$sParam] = $oObj->GetKey();
}
else
{
$aQueryParams[$sParam] = $oObj->Get($sAttCode);
}
}
else
{
unset($aQueryParams[$sParam]);
// For database objects, serialize only class, key
$aQueryParams[$sParamName.'->id'] = $oObj->GetKey();
$aQueryParams[$sParamName.'->class'] = get_class($oObj);
}
}
}
}
$sOql = $this->ToOql($bDevelopParams, $aContextParams);
return json_encode(array($sOql, $aQueryParams, $this->m_aModifierProperties));
return rawurlencode(base64_encode(serialize(array($sOql, $this->GetInternalParams(), $this->m_aModifierProperties))));
}
/**
* @param string $sValue Serialized OQL query
*
* @return \DBSearch
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \OQLException
*/
static public function unserialize($sValue)
{
$aData = json_decode($sValue, true);
if (is_null($aData))
{
throw new CoreException("Invalid filter parameter");
}
$aData = unserialize(base64_decode(rawurldecode($sValue)));
$sOql = $aData[0];
$aParams = $aData[1];
$aExtraParams = array();
foreach($aParams as $sParam => $sValue)
{
if (($iPos = strpos($sParam, '->class')) !== false)
{
$sParamName = substr($sParam, 0, $iPos);
if (isset($aParams[$sParamName.'->id']))
{
$sClass = $aParams[$sParamName.'->class'];
$iKey = $aParams[$sParamName.'->id'];
$oObj = MetaModel::GetObject($sClass, $iKey);
$aExtraParams[$sParamName.'->object()'] = $oObj;
}
}
}
$aParams = array_merge($aExtraParams, $aParams);
// We've tried to use gzcompress/gzuncompress, but for some specific queries
// it was not working at all (See Trac #193)
// gzuncompress was issuing a warning "data error" and the return object was null
@@ -402,7 +335,6 @@ abstract class DBSearch
}
}
/** @var DBObjectSearch | null $oResultFilter */
if (!isset($oResultFilter))
{
$oKPI = new ExecutionKPI();
@@ -441,20 +373,11 @@ abstract class DBSearch
return $oResultFilter;
}
// Alternative to object mapping: the data are transfered directly into an array
// This is 10 times faster than creating a set of objects, and makes sense when optimization is required
/**
* Alternative to object mapping: the data are transfered directly into an array
* This is 10 times faster than creating a set of objects, and makes sense when optimization is required
*
* @param array $aColumns
* @param array $aOrderBy Array of '[<classalias>.]attcode' => bAscending
* @param array $aArgs
*
* @return array|void
* @throws \CoreException
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
* @param hash $aOrderBy Array of '[<classalias>.]attcode' => bAscending
*/
public function ToDataArray($aColumns = array(), $aOrderBy = array(), $aArgs = array())
{
$sSQL = $this->MakeSelectQuery($aOrderBy, $aArgs);

View File

@@ -116,22 +116,6 @@ class Dict
self::$m_iErrorMode = $iErrorMode;
}
/**
* Check if a dictionary entry exists or not
* @param $sStringCode
*
* @return bool
*/
public static function Exists($sStringCode)
{
$sImpossibleString = 'aVlHYKEI3TZuDV5o0pghv7fvhYNYuzYkTk7WL0Zoqw8rggE7aq';
if (static::S($sStringCode, $sImpossibleString) === $sImpossibleString)
{
return false;
}
return true;
}
/**
* Returns a localised string from the dictonary
*
@@ -213,7 +197,7 @@ class Dict
/**
* Initialize a the entries for a given language (replaces the former Add() method)
* @param string $sLanguageCode Code identifying the language i.e. 'FR-FR', 'EN-US'
* @param array $aEntries Hash array of dictionnary entries
* @param hash $aEntries Hash array of dictionnary entries
*/
public static function SetEntries($sLanguageCode, $aEntries)
{

View File

@@ -188,16 +188,11 @@ EOF
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
$sRet = $oAttDef->GetAsCSV($value, '', '', $oObj);
}
else if ($value instanceOf ormDocument)
{
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
$sRet = $oAttDef->GetAsCSV($value, '', '', $oObj);
}
else if ($value instanceOf ormTagSet)
{
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
$sRet = $oAttDef->GetAsCSV($value, '', '', $oObj);
}
else if ($value instanceOf ormDocument)
{
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
$sRet = $oAttDef->GetAsCSV($value, '', '', $oObj);
}
else
{
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);

View File

@@ -78,6 +78,7 @@ EOF;
}
EOF;
SetupUtils::builddir(dirname($sFilePath));
file_put_contents($sFilePath, $content);
}
}

View File

@@ -154,7 +154,7 @@ class HTMLDOMSanitizer extends HTMLSanitizer
/**
* @var array
* @see https://www.itophub.io/wiki/page?id=2_6_0%3Aadmin%3Arich_text_limitations
* @see https://www.itophub.io/wiki/page?id=2_5_0%3Aadmin%3Arich_text_limitations
*/
protected static $aTagsWhiteList = array(
'html' => array(),
@@ -211,7 +211,7 @@ class HTMLDOMSanitizer extends HTMLSanitizer
/**
* @var array
* @see https://www.itophub.io/wiki/page?id=2_6_0%3Aadmin%3Arich_text_limitations
* @see https://www.itophub.io/wiki/page?id=2_5_0%3Aadmin%3Arich_text_limitations
*/
protected static $aStylesWhiteList = array(
'background-color',
@@ -230,9 +230,7 @@ class HTMLDOMSanitizer extends HTMLSanitizer
'margin',
'padding',
'text-align',
'vertical-align',
'width',
'white-space',
);
public function __construct()

View File

@@ -166,7 +166,7 @@ class InlineImage extends DBObject
*/
public static function FinalizeInlineImages(DBObject $oObject)
{
$iTransactionId = utils::ReadParam('transaction_id', null, false, 'transaction_id');
$iTransactionId = utils::ReadParam('transaction_id', null);
if (!is_null($iTransactionId))
{
// Attach new (temporary) inline images
@@ -183,19 +183,6 @@ class InlineImage extends DBObject
$oInlineImage->DBUpdate();
}
}
// For tracing issues with Inline Images... but beware not all updates are interactive, so this trace happens when creating objects non-interactively (REST, Synchro...)
// else
// {
// IssueLog::Error('InlineImage: Error during FinalizeInlineImages(), no transaction ID for object '.get_class($oObject).'#'.$oObject->GetKey().'.');
//
// IssueLog::Error('|- Call stack:');
// $oException = new Exception();
// $sStackTrace = $oException->getTraceAsString();
// IssueLog::Error($sStackTrace);
//
// IssueLog::Error('|- POST vars:');
// IssueLog::Error(print_r($_POST, true));
// }
}
/**
@@ -312,12 +299,8 @@ EOF
/**
* Check if an the given mimeType is an image that can be processed by the system
*
* @param string $sMimeType
*
* @return boolean always false if php-gd not installed
* otherwise true if file is one of those type : image/gif, image/jpeg, image/png
* @uses php-gd extension
* @return boolean
*/
public static function IsImage($sMimeType)
{
@@ -463,11 +446,9 @@ EOF
* Get the fragment of javascript needed to complete the initialization of
* CKEditor when creating/modifying an object
*
* @param \DBObject $oObject The object being edited
* @param string $sTempId Generated through utils::GetUploadTempId($iTransactionId)
*
* @param DBObject $oObject The object being edited
* @param string $sTempId The concatenation of session_id().'_'.$iTransactionId.
* @return string The JS fragment to insert in "on document ready"
* @throws \Exception
*/
public static function EnableCKEditorImageUpload(DBObject $oObject, $sTempId)
{
@@ -560,67 +541,49 @@ class InlineImageGC implements iBackgroundProcess
{
public function GetPeriodicity()
{
return 1; // Runs every 8 hours
return 3600; // Runs every hour
}
/**
* @param int $iTimeLimit
*
* @return string
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DeleteException
* @throws \MySQLException
* @throws \OQLException
*/
public function Process($iTimeLimit)
{
$sDateLimit = date(AttributeDateTime::GetSQLFormat(), time()); // Every temporary InlineImage/Attachment expired will be deleted
$aResults = array();
$aClasses = array('InlineImage', 'Attachment');
foreach($aClasses as $sClass)
{
$iProcessed = 0;
if(class_exists($sClass))
{
$iProcessed = $this->DeleteExpiredDocuments($sClass, $iTimeLimit, $sDateLimit);
}
$aResults[] = "$iProcessed old temporary $sClass(s)";
}
return "Cleaned ".implode(' and ', $aResults).".";
}
/**
* @param string $sClass
* @param int $iTimeLimit
* @param string $sDateLimit
*
* @return int
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DeleteException
* @throws \MySQLException
* @throws \OQLException
*/
protected function DeleteExpiredDocuments($sClass, $iTimeLimit, $sDateLimit)
{
$iProcessed = 0;
$sOQL = "SELECT $sClass WHERE (item_id = 0) AND (expire < '$sDateLimit')";
// Next one ?
$oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL), array('expire' => true) /* order by*/, array(), null,
1 /* limit count */);
$oSet->OptimizeColumnLoad(array());
while ((time() < $iTimeLimit) && ($oResult = $oSet->Fetch()))
$sOQL = "SELECT InlineImage WHERE (item_id = 0) AND (expire < '$sDateLimit')";
while (time() < $iTimeLimit)
{
/** @var \ormDocument $oDocument */
$oDocument = $oResult->Get('contents');
IssueLog::Info($sClass.' GC: Removed temp. file '.$oDocument->GetFileName().' on "'.$oResult->Get('item_class').'" #'.$oResult->Get('item_id').' as it has expired.');
$oResult->DBDelete();
// Next one ?
$oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL), array('expire' => true) /* order by*/, array(), null, 1 /* limit count */);
$oSet->OptimizeColumnLoad(array());
$oResult = $oSet->Fetch();
if (is_null($oResult))
{
// Nothing to be done
break;
}
$iProcessed++;
$oResult->DBDelete();
}
return $iProcessed;
}
$iProcessed2 = 0;
if (class_exists('Attachment'))
{
$sOQL = "SELECT Attachment WHERE (item_id = 0) AND (expire < '$sDateLimit')";
while (time() < $iTimeLimit)
{
// Next one ?
$oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL), array('expire' => true) /* order by*/, array(), null, 1 /* limit count */);
$oSet->OptimizeColumnLoad(array());
$oResult = $oSet->Fetch();
if (is_null($oResult))
{
// Nothing to be done
break;
}
$iProcessed2++;
$oResult->DBDelete();
}
}
return "Cleaned $iProcessed old temporary InlineImage(s) and $iProcessed2 old temporary Attachment(s).";
}
}

View File

@@ -116,14 +116,13 @@ class ExecutionKPI
foreach (self::$m_aExecData as $aOpStats)
{
$sOperation = $aOpStats['op'];
$sBegin = $sEnd = $sDuration = $sMemBegin = $sMemEnd = $sMemPeak = '?';
$sBegin = round($aOpStats['time_begin'], 3);
$sEnd = round($aOpStats['time_end'], 3);
$fDuration = $aOpStats['time_end'] - $aOpStats['time_begin'];
$sDuration = round($fDuration, 3);
$sMemBegin = 'n/a';
$sMemEnd = 'n/a';
$sMemPeak = 'n/a';
if (isset($aOpStats['mem_begin']))
{
$sMemBegin = self::MemStr($aOpStats['mem_begin']);
@@ -198,13 +197,12 @@ class ExecutionKPI
self::Report("</div>");
self::Report("<p><a href=\"#end-".md5($sExecId)."\">Next page stats</a></p>");
// Report operation details
foreach (self::$m_aStats as $sOperation => $aOpStats)
{
$sOperationHtml = '<a name="'.md5($sExecId.$sOperation).'">'.$sOperation.'</a>';
self::Report("<h4>$sOperationHtml</h4>");
self::Report("<p><a href=\"#".md5($sExecId)."\">Back to page stats</a></p>");
self::Report("<table border=\"1\" style=\"$sTableStyle\">");
self::Report("<thead>");
self::Report(" <th>Operation details (+ blame caller if log_kpi_duration = 2)</th><th>Count</th><th>Duration</th><th>Min</th><th>Max</th>");
@@ -253,9 +251,7 @@ class ExecutionKPI
self::Report("</tr>");
}
self::Report("</table>");
self::Report("<p><a href=\"#".md5($sExecId)."\">Back to page stats</a></p>");
}
self::Report('<a name="end-'.md5($sExecId).'">&nbsp;</a>');
}

View File

@@ -144,7 +144,7 @@ abstract class MetaModel
// $aBacktrace[1] is the info we want
if (!empty($sExpectedFunctionName))
{
assert($aBacktrace[2]['function'] == $sExpectedFunctionName);
assert('$aBacktrace[2]["function"] == $sExpectedFunctionName');
}
if ($bRecordSourceFile)
{
@@ -320,7 +320,8 @@ abstract class MetaModel
final static public function GetName($sClass)
{
self::_check_subclass($sClass);
return $sClass::GetClassName($sClass);
$sStringCode = 'Class:'.$sClass;
return Dict::S($sStringCode, str_replace('_', ' ', $sClass));
}
/**
@@ -410,7 +411,8 @@ abstract class MetaModel
final static public function GetClassDescription($sClass)
{
self::_check_subclass($sClass);
return $sClass::GetClassDescription($sClass);
$sStringCode = 'Class:'.$sClass.'+';
return Dict::S($sStringCode, '');
}
/**
@@ -526,104 +528,6 @@ abstract class MetaModel
return $oRet;
}
/**
* @param string $sClass
*
* @return array
* @throws \CoreException
*
* @since 2.6 N°659 uniqueness constraint
*/
final public static function GetUniquenessRules($sClass)
{
if (!isset(self::$m_aClassParams[$sClass]))
{
return array();
}
$aCurrentUniquenessRules = array();
if (array_key_exists('uniqueness_rules', self::$m_aClassParams[$sClass]))
{
$aCurrentUniquenessRules = self::$m_aClassParams[$sClass]['uniqueness_rules'];
}
$sParentClass = self::GetParentClass($sClass);
if ($sParentClass)
{
$aParentUniquenessRules = self::GetUniquenessRules($sParentClass);
foreach ($aParentUniquenessRules as $sUniquenessRuleId => $aParentUniquenessRuleProperties)
{
$bCopyDisabledKey = true;
$bCurrentDisabledValue = null;
if (array_key_exists($sUniquenessRuleId, $aCurrentUniquenessRules))
{
if (self::IsUniquenessRuleContainingOnlyDisabledKey($aCurrentUniquenessRules[$sUniquenessRuleId]))
{
$bCopyDisabledKey = false;
}
else
{
continue;
}
}
$aMergedUniquenessProperties = $aParentUniquenessRuleProperties;
if (!$bCopyDisabledKey)
{
$aMergedUniquenessProperties['disabled'] = $aCurrentUniquenessRules[$sUniquenessRuleId]['disabled'];
}
$aCurrentUniquenessRules[$sUniquenessRuleId] = $aMergedUniquenessProperties;
}
}
return $aCurrentUniquenessRules;
}
/**
* @param string $sRuleId
* @param string $sLeafClassName
*
* @return string name of the class, null if not present
*/
final public static function GetRootClassForUniquenessRule($sRuleId, $sLeafClassName)
{
$sFirstClassWithRuleId = null;
if (isset(self::$m_aClassParams[$sLeafClassName]['uniqueness_rules'][$sRuleId]))
{
$sFirstClassWithRuleId = $sLeafClassName;
}
$sParentClass = self::GetParentClass($sLeafClassName);
if ($sParentClass)
{
$sParentClassWithRuleId = self::GetRootClassForUniquenessRule($sRuleId, $sParentClass);
if (!is_null($sParentClassWithRuleId))
{
$sFirstClassWithRuleId = $sParentClassWithRuleId;
}
}
return $sFirstClassWithRuleId;
}
/**
* @param array $aRuleProperties
*
* @return bool
* @since 2.6 N°659 uniqueness constraint
*/
private static function IsUniquenessRuleContainingOnlyDisabledKey($aRuleProperties)
{
$aNonNullRuleProperties = array_filter($aRuleProperties, function ($v) {
return (!is_null($v));
});
return ((count($aNonNullRuleProperties) == 1) && (array_key_exists('disabled', $aNonNullRuleProperties)));
}
/**
* @param string $sClass
*
@@ -1120,7 +1024,7 @@ abstract class MetaModel
/**
* array of ("classname" => array of attributes)
*
* @var \AttributeDefinition[]
* @var array
*/
private static $m_aAttribDefs = array();
/**
@@ -2695,7 +2599,7 @@ abstract class MetaModel
// Build the list of available extensions
//
$aInterfaces = array('iApplicationUIExtension', 'iApplicationObjectExtension', 'iQueryModifier', 'iOnClassInitialization', 'iPopupMenuExtension', 'iPageUIExtension', 'iPortalUIExtension', 'ModuleHandlerApiInterface', 'iNewsroomProvider');
$aInterfaces = array('iApplicationUIExtension', 'iApplicationObjectExtension', 'iQueryModifier', 'iOnClassInitialization', 'iPopupMenuExtension', 'iPageUIExtension', 'iPortalUIExtension');
foreach($aInterfaces as $sInterface)
{
self::$m_aExtensionClasses[$sInterface] = array();
@@ -2778,25 +2682,6 @@ abstract class MetaModel
$oClassInit->OnAfterClassInitialization($sPHPClass);
}
}
$aCurrentClassUniquenessRules = MetaModel::GetUniquenessRules($sPHPClass);
if (!empty($aCurrentClassUniquenessRules))
{
$aClassFields = self::GetAttributesList($sPHPClass);
foreach ($aCurrentClassUniquenessRules as $sUniquenessRuleId => $aUniquenessRuleProperties)
{
$bHasSameRuleInParent = self::HasSameUniquenessRuleInParent($sPHPClass, $sUniquenessRuleId);
try
{
self::CheckUniquenessRuleValidity($aUniquenessRuleProperties, $bHasSameRuleInParent, $aClassFields);
}
catch (CoreUnexpectedValue $e)
{
throw new Exception("Invalid uniqueness rule declaration : class={$sPHPClass}, rule=$sUniquenessRuleId, reason={$e->getMessage()}");
}
}
}
}
catch (ReflectionException $e)
{
@@ -3065,101 +2950,6 @@ abstract class MetaModel
}
}
/**
* @param string $sClassName
* @param string $sUniquenessRuleId
*
* @return bool true if one of the parent class (recursive) has the same rule defined
* @throws \CoreException
*/
private static function HasSameUniquenessRuleInParent($sClassName, $sUniquenessRuleId)
{
$sParentClass = self::GetParentClass($sClassName);
if (empty($sParentClass))
{
return false;
}
$aParentClassUniquenessRules = self::GetUniquenessRules($sParentClass);
if (array_key_exists($sUniquenessRuleId, $aParentClassUniquenessRules))
{
return true;
}
return self::HasSameUniquenessRuleInParent($sParentClass, $sUniquenessRuleId);
}
/**
* @param array $aUniquenessRuleProperties
* @param bool $bRuleOverride if false then control an original declaration validity,
* otherwise an override validity (can have only the disabled key)
* @param string[] $aExistingClassFields if non empty, will check that all fields declared in the rules exists in the class
*
* @throws \CoreUnexpectedValue if the rule is invalid
*
* @since 2.6 N°659 uniqueness constraint
*/
public static function CheckUniquenessRuleValidity($aUniquenessRuleProperties, $bRuleOverride = true, $aExistingClassFields = array())
{
$MANDATORY_ATTRIBUTES = array('attributes');
$UNIQUENESS_MANDATORY_KEYS_NB = count($MANDATORY_ATTRIBUTES);
$bHasDisabledKey = false;
$bHasMissingMandatoryKey = true;
$iMissingMandatoryKeysNb = $UNIQUENESS_MANDATORY_KEYS_NB;
$bHasAllMandatoryKeysMissing = false;
$bHasNonDisabledKeys = false;
foreach ($aUniquenessRuleProperties as $sUniquenessRuleKey => $aUniquenessRuleProperty)
{
if (($sUniquenessRuleKey === 'disabled') && (!is_null($aUniquenessRuleProperty)))
{
$bHasDisabledKey = true;
continue;
}
$bHasNonDisabledKeys = true;
if (in_array($sUniquenessRuleKey, $MANDATORY_ATTRIBUTES, true)) {
$bHasMissingMandatoryKey = false;
$iMissingMandatoryKeysNb--;
}
if (($sUniquenessRuleKey === 'attributes') && (!empty($aExistingClassFields)))
{
foreach ($aUniquenessRuleProperties[$sUniquenessRuleKey] as $sRuleAttribute)
{
if (!in_array($sRuleAttribute, $aExistingClassFields, true))
{
throw new CoreUnexpectedValue("Uniqueness rule : non existing field '$sRuleAttribute'");
}
}
}
}
if ($iMissingMandatoryKeysNb == $UNIQUENESS_MANDATORY_KEYS_NB)
{
$bHasAllMandatoryKeysMissing = true;
}
if ($bHasDisabledKey)
{
if ($bRuleOverride && $bHasAllMandatoryKeysMissing && !$bHasNonDisabledKeys)
{
return;
}
if ($bHasMissingMandatoryKey)
{
throw new CoreUnexpectedValue('Uniqueness rule : missing mandatory properties');
}
return;
}
if ($bHasMissingMandatoryKey)
{
throw new CoreUnexpectedValue('Uniqueness rule : missing mandatory properties');
}
}
/**
* To be overriden, must be called for any object class (optimization)
*/
@@ -4715,7 +4505,7 @@ abstract class MetaModel
}
}
// Check SQL columns uniqueness
// Check unicity of the SQL columns
//
if (self::HasTable($sClass))
{
@@ -5181,7 +4971,6 @@ abstract class MetaModel
$aCreateTableItems = array(); // array of <table> => array of <create definition>
$aAlterTableMetaData = array();
$aAlterTableItems = array(); // array of <table> => <alter specification>
$aPostTableAlteration = array(); // array of <table> => post alteration queries
foreach(self::GetClasses() as $sClass)
{
@@ -5276,7 +5065,6 @@ abstract class MetaModel
$aTableInfo['Fields'][$sField]['used'] = true;
$bIndexNeeded = $oAttDef->RequiresIndex();
$bFullTextIndexNeeded = false;
if (!$bIndexNeeded)
{
// Add an index on the columns of the friendlyname
@@ -5285,13 +5073,6 @@ abstract class MetaModel
$bIndexNeeded = true;
}
}
else
{
if ($oAttDef->RequiresFullTextIndex())
{
$bFullTextIndexNeeded = true;
}
}
$sFieldDefinition = "`$sField` $sDBFieldSpec";
if (!CMDBSource::IsField($sTable, $sField))
@@ -5311,37 +5092,21 @@ abstract class MetaModel
if ($bIndexNeeded)
{
$aTableInfo['Indexes'][$sField]['used'] = true;
$sIndexName = $sField;
$aColumns = array($sField);
$aLength = self::DBGetIndexesLength($sClass, $aColumns, $aTableInfo);
$sColumns = '`'.$sField.'`';
if ($bFullTextIndexNeeded)
if (!is_null($aLength[0]))
{
$sIndexType = 'FULLTEXT INDEX';
$sColumns .= ' ('.$aLength[0].')';
}
$aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` ADD INDEX `$sField` ($sColumns)";
if ($bTableToCreate)
{
$aCreateTableItems[$sTable][] = "INDEX `$sField` ($sColumns)";
}
else
{
$sIndexType = 'INDEX';
$aColumns = array($sField);
$aLength = self::DBGetIndexesLength($sClass, $aColumns, $aTableInfo);
if (!is_null($aLength[0]))
{
$sColumns .= ' ('.$aLength[0].')';
}
}
$sSugFix = "ALTER TABLE `$sTable` ADD $sIndexType `$sIndexName` ($sColumns)";
$aSugFix[$sClass][$sAttCode][] = $sSugFix;
if ($bFullTextIndexNeeded)
{
// MySQL does not support multi fulltext index creation in a single query (mysql_errno = 1795)
$aPostTableAlteration[$sTable][] = $sSugFix;
}
elseif ($bTableToCreate)
{
$aCreateTableItems[$sTable][] = "$sIndexType `$sIndexName` ($sColumns)";
}
else
{
$aAlterTableItems[$sTable][] = "ADD $sIndexType `$sIndexName` ($sColumns)";
$aAlterTableItems[$sTable][] = "ADD INDEX `$sField` ($sColumns)";
}
}
@@ -5354,24 +5119,12 @@ abstract class MetaModel
$sAlterTableItemsAfterChange = '';
if ($bIndexNeeded)
{
$aColumns = array($sField);
$aLength = self::DBGetIndexesLength($sClass, $aColumns, $aTableInfo);
$aTableInfo['Indexes'][$sField]['used'] = true;
if ($bFullTextIndexNeeded)
{
$sIndexType = 'FULLTEXT INDEX';
$aColumns = null;
$aLength = null;
}
else
{
$sIndexType = 'INDEX';
$aColumns = array($sField);
$aLength = self::DBGetIndexesLength($sClass, $aColumns, $aTableInfo);
}
if (!CMDBSource::HasIndex($sTable, $sField, $aColumns, $aLength))
{
$sIndexName = $sField;
$sColumns = '`'.$sField.'`';
if (!is_null($aLength[0]))
{
@@ -5381,11 +5134,16 @@ abstract class MetaModel
$aErrors[$sClass][$sAttCode][] = "Foreign key '$sField' in table '$sTable' should have an index";
if (CMDBSource::HasIndex($sTable, $sField))
{
$aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` DROP INDEX `$sIndexName`";
$aAlterTableItems[$sTable][] = "DROP INDEX `$sIndexName`";
$aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` DROP INDEX `$sField`";
$sSugFixAfterChange = "ALTER TABLE `$sTable` ADD INDEX `$sField` ($sColumns)";
$aAlterTableItems[$sTable][] = "DROP INDEX `$sField`";
$sAlterTableItemsAfterChange = "ADD INDEX `$sField` ($sColumns)";
}
else
{
$sSugFixAfterChange = "ALTER TABLE `$sTable` ADD INDEX `$sField` ($sColumns)";
$sAlterTableItemsAfterChange = "ADD INDEX `$sField` ($sColumns)";
}
$sSugFixAfterChange = "ALTER TABLE `$sTable` ADD $sIndexType `$sIndexName` ($sColumns)";
$sAlterTableItemsAfterChange = "ADD $sIndexType `$sIndexName` ($sColumns)";
}
}
@@ -5409,15 +5167,7 @@ abstract class MetaModel
if (!empty($sSugFixAfterChange))
{
$aSugFix[$sClass][$sAttCode][] = $sSugFixAfterChange;
if ($bFullTextIndexNeeded)
{
// MySQL does not support multi fulltext index creation in a single query (mysql_errno = 1795)
$aPostTableAlteration[$sTable][] = $sSugFixAfterChange;
}
else
{
$aAlterTableItems[$sTable][] = $sAlterTableItemsAfterChange;
}
$aAlterTableItems[$sTable][] = $sAlterTableItemsAfterChange;
}
}
}
@@ -5541,10 +5291,6 @@ abstract class MetaModel
$sChangeList = implode(', ', $aChangeList);
$aCondensedQueries[] = "ALTER TABLE `$sTable` $sChangeList";
}
foreach($aPostTableAlteration as $sTable => $aChangeList)
{
$aCondensedQueries = array_merge($aCondensedQueries, $aChangeList);
}
return array($aErrors, $aSugFix, $aCondensedQueries);
}
@@ -6112,10 +5858,20 @@ abstract class MetaModel
CMDBSource::SelectDB(self::$m_sDBName);
foreach(MetaModel::EnumPlugins('ModuleHandlerApiInterface') as $oPHPClass)
{
$oPHPClass::OnMetaModelStarted();
}
foreach(get_declared_classes() as $sPHPClass)
{
if (is_subclass_of($sPHPClass, 'ModuleHandlerAPI'))
{
$aCallSpec = array($sPHPClass, 'OnMetaModelStarted');
call_user_func_array($aCallSpec, array());
}
}
// if (false)
// {
// echo "Debug<br/>\n";
// self::static_var_dump();
// }
ExpressionCache::Warmup();
}
@@ -6570,7 +6326,7 @@ abstract class MetaModel
*
* @param string $sClass
* @param int $iKey id value of the object to retrieve
* @param bool $bMustBeFound see throws ArchivedObjectException
* @param bool $bMustBeFound
* @param bool $bAllowAllData if true then no rights filtering
* @param null $aModifierProperties
*
@@ -6637,14 +6393,12 @@ abstract class MetaModel
}
catch(Exception $e)
{
// In the finally block we will pop the pushed archived mode
// otherwise the application stays in ArchiveMode true which has caused hazardious behavior!
// We need to pop the pushed archived mode before the exception is thrown, otherwise the application stays in ArchiveMode true which has caused hazardious behavior!
// Note: When switching to PHP 5.6, we can use a finally block instead of duplicating this line.
utils::PopArchiveMode();
throw $e;
}
finally
{
utils::PopArchiveMode();
}
utils::PopArchiveMode();
if (empty($aRow))
{

View File

@@ -56,11 +56,6 @@ abstract class ModelReflection
abstract public function GetFiltersList($sClass);
abstract public function IsValidFilterCode($sClass, $sFilterCode);
/**
* @param string $sOQL
*
* @return \DBObjectSearch
*/
abstract public function GetQuery($sOQL);
abstract public function DictString($sStringCode, $sDefault = null, $bUserLanguageOnly = false);
@@ -80,13 +75,6 @@ abstract class ModelReflection
return vsprintf($sLocalizedFormat, $aArguments);
}
/**
* @param $sCode
* @param string $sLabel
* @param string $defaultValue
*
* @return \RunTimeIconSelectionField
*/
abstract public function GetIconSelectionField($sCode, $sLabel = '', $defaultValue = '');
abstract public function GetRootClass($sClass);

View File

@@ -25,7 +25,7 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
abstract class ModuleHandlerAPI implements ModuleHandlerApiInterface
abstract class ModuleHandlerAPI
{
public static function OnMetaModelStarted()
{
@@ -34,19 +34,5 @@ abstract class ModuleHandlerAPI implements ModuleHandlerApiInterface
public static function OnMenuCreation()
{
}
public function __construct()
{
}
}
interface ModuleHandlerApiInterface
{
public static function OnMetaModelStarted();
public static function OnMenuCreation();
public function __construct(); //empty params is required in order to be instantiable by MetaModel::InitClasses()
}
?>

View File

@@ -45,7 +45,7 @@ class iTopMutex
static protected $aAcquiredLocks = array(); // Number of instances of the Mutex, having the lock, in this page
public function __construct(
$sName, $sDBHost = null, $sDBUser = null, $sDBPwd = null, $bDBTlsEnabled = false, $sDBTlsCA = null
$sName, $sDBHost = null, $sDBUser = null, $sDBPwd = null, $bDBTlsEnabled = null, $sDBTlsCA = null
)
{
// Compute the name of a lock for mysql

View File

@@ -42,7 +42,7 @@
* @copyright 2006 Gregory Beaver
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
*/
//require_once 'PEAR/Exception.php';
require_once 'PEAR/Exception.php';
/**
* @package PHP_LexerGenerator
* @author Gregory Beaver <cellog@php.net>
@@ -51,5 +51,5 @@
* @version @package_version@
* @since File available since Release 0.1.0
*/
class PHP_LexerGenerator_Exception extends Exception {}
class PHP_LexerGenerator_Exception extends PEAR_Exception {}
?>

View File

@@ -22,9 +22,6 @@ class MissingQueryArgument extends CoreException
}
/**
* @method Check($oModelReflection, array $aAliases, $sSourceQuery)
*/
abstract class Expression
{
/**
@@ -50,30 +47,13 @@ abstract class Expression
/**
* recursive rendering
*
* @deprecated use RenderExpression
*
* @param array $aArgs used as input by default, or used as output if bRetrofitParams set to True
* @param bool $bRetrofitParams
*
* @return array|string
* @throws \MissingQueryArgument
*/
public function Render(&$aArgs = null, $bRetrofitParams = false)
{
return $this->RenderExpression(false, $aArgs, $bRetrofitParams);
}
/**
* recursive rendering
*
* @param bool $bForSQL generates code for OQL if false, for SQL otherwise
* @param array $aArgs used as input by default, or used as output if bRetrofitParams set to True
* @param bool $bRetrofitParams
*
* @return array|string
* @throws \MissingQueryArgument
*/
abstract public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false);
abstract public function Render(&$aArgs = null, $bRetrofitParams = false);
/**
* @param DBObjectSearch $oSearch
@@ -86,7 +66,7 @@ abstract class Expression
*/
public function Display($oSearch, &$aArgs = null, $oAttDef = null, &$aCtx = array())
{
return $this->RenderExpression(false, $aArgs);
return $this->Render($aArgs);
}
public function GetAttDef($aClasses = array())
@@ -124,7 +104,7 @@ abstract class Expression
public function serialize()
{
return base64_encode($this->RenderExpression(false));
return base64_encode($this->Render());
}
/**
@@ -192,7 +172,7 @@ abstract class Expression
* @param string sValue The value returned by the query, for this expression
* @param string sDefault The default value if no relevant label could be computed
*
* @return string label
* @return The label
*/
public function MakeValueLabel($oFilter, $sValue, $sDefault)
{
@@ -203,7 +183,7 @@ abstract class Expression
{
return array(
'widget' => AttributeDefinition::SEARCH_WIDGET_TYPE_RAW,
'oql' => $this->RenderExpression(false, $aArgs, $bRetrofitParams),
'oql' => $this->Render($aArgs, $bRetrofitParams),
'label' => $this->Display($oSearch, $aArgs, $oAttDef),
'source' => get_class($this),
);
@@ -249,7 +229,7 @@ class SQLExpression extends Expression
}
// recursive rendering
public function RenderExpression($bForSql = false, &$aArgs = null, $bRetrofitParams = false)
public function Render(&$aArgs = null, $bRetrofitParams = false)
{
return $this->m_sSQL;
}
@@ -305,30 +285,7 @@ class BinaryExpression extends Expression
protected $m_oRightExpr;
protected $m_sOperator;
/**
* @param \Expression $oLeftExpr
* @param string $sOperator
* @param \Expression $oRightExpr
*
* @throws \CoreException
*/
public function __construct($oLeftExpr, $sOperator, $oRightExpr)
{
$this->ValidateConstructorParams($oLeftExpr, $sOperator, $oRightExpr);
$this->m_oLeftExpr = $oLeftExpr;
$this->m_oRightExpr = $oRightExpr;
$this->m_sOperator = $sOperator;
}
/**
* @param $oLeftExpr
* @param $sOperator
* @param $oRightExpr
*
* @throws \CoreException if one of the parameter is invalid
*/
protected function ValidateConstructorParams($oLeftExpr, $sOperator, $oRightExpr)
{
if (!is_object($oLeftExpr))
{
@@ -346,11 +303,13 @@ class BinaryExpression extends Expression
{
throw new CoreException('Expecting an Expression object on the right hand', array('found_class' => get_class($oRightExpr)));
}
if ((($sOperator == "IN") || ($sOperator == "NOT IN")) && !($oRightExpr instanceof ListExpression))
if ( (($sOperator == "IN") || ($sOperator == "NOT IN")) && !$oRightExpr instanceof ListExpression)
{
throw new CoreException("Expecting a List Expression object on the right hand for operator $sOperator",
array('found_class' => get_class($oRightExpr)));
throw new CoreException("Expecting a List Expression object on the right hand for operator $sOperator", array('found_class' => get_class($oRightExpr)));
}
$this->m_oLeftExpr = $oLeftExpr;
$this->m_oRightExpr = $oRightExpr;
$this->m_sOperator = $sOperator;
}
public function IsTrue()
@@ -382,11 +341,12 @@ class BinaryExpression extends Expression
return $this->m_sOperator;
}
public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false)
// recursive rendering
public function Render(&$aArgs = null, $bRetrofitParams = false)
{
$sOperator = $this->GetOperator();
$sLeft = $this->GetLeftExpr()->RenderExpression($bForSQL, $aArgs, $bRetrofitParams);
$sRight = $this->GetRightExpr()->RenderExpression($bForSQL, $aArgs, $bRetrofitParams);
$sLeft = $this->GetLeftExpr()->Render($aArgs, $bRetrofitParams);
$sRight = $this->GetRightExpr()->Render($aArgs, $bRetrofitParams);
return "($sLeft $sOperator $sRight)";
}
@@ -578,7 +538,6 @@ class BinaryExpression extends Expression
* @param null $oAttDef
*
* @return array
* @throws \MissingQueryArgument
*/
public function GetCriterion($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null)
{
@@ -646,7 +605,7 @@ class BinaryExpression extends Expression
$aCriteria = self::MergeCriteria($aCriteriaLeft, $aCriteriaRight, $this->GetOperator());
}
$aCriteria['oql'] = $this->RenderExpression(false, $aArgs, $bRetrofitParams);
$aCriteria['oql'] = $this->Render($aArgs, $bRetrofitParams);
$aCriteria['label'] = $this->Display($oSearch, $aArgs, $oAttDef);
if (isset($aCriteriaLeft['ref']) && isset($aCriteriaRight['ref']) && ($aCriteriaLeft['ref'] != $aCriteriaRight['ref']))
@@ -677,10 +636,6 @@ class BinaryExpression extends Expression
}
}
}
if (isset($aCriteriaLeft['widget']) && isset($aCriteriaRight['widget']) && ($aCriteriaLeft['widget'] == AttributeDefinition::SEARCH_WIDGET_TYPE_TAG_SET) && ($aCriteriaRight['widget'] == AttributeDefinition::SEARCH_WIDGET_TYPE_TAG_SET))
{
$aCriteriaOverride['operator'] = 'MATCHES';
}
}
return array_merge($aCriteriaLeft, $aCriteriaRight, $aCriteriaOverride);
@@ -688,58 +643,6 @@ class BinaryExpression extends Expression
}
/**
* @since 2.6 N°931 tag fields
*/
class MatchExpression extends BinaryExpression
{
/** @var \FieldExpression */
protected $m_oLeftExpr;
/** @var \ScalarExpression */
protected $m_oRightExpr;
/**
* MatchExpression constructor.
*
* @param \FieldExpression $oLeftExpr
* @param \ScalarExpression $oRightExpr
*
* @throws \CoreException
*/
public function __construct(FieldExpression $oLeftExpr, ScalarExpression $oRightExpr)
{
parent::__construct($oLeftExpr, 'MATCHES', $oRightExpr);
}
public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false)
{
$sLeft = $this->GetLeftExpr()->RenderExpression($bForSQL, $aArgs, $bRetrofitParams);
$sRight = $this->GetRightExpr()->RenderExpression($bForSQL, $aArgs, $bRetrofitParams);
if ($bForSQL)
{
$sRet = "MATCH ($sLeft) AGAINST ($sRight IN BOOLEAN MODE)";
}
else
{
$sRet = "$sLeft MATCHES $sRight";
}
return $sRet;
}
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
{
/** @var \FieldExpression $oLeft */
$oLeft = $this->GetLeftExpr()->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
/** @var \ScalarExpression $oRight */
$oRight = $this->GetRightExpr()->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
return new static($oLeft, $oRight);
}
}
class UnaryExpression extends Expression
{
protected $m_value;
@@ -761,7 +664,7 @@ class UnaryExpression extends Expression
}
// recursive rendering
public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false)
public function Render(&$aArgs = null, $bRetrofitParams = false)
{
return CMDBSource::Quote($this->m_value);
}
@@ -869,11 +772,11 @@ class ScalarExpression extends UnaryExpression
return $aCtx['date_display']->MakeValueLabel($oSearch, $this->m_value, $this->m_value);
}
return $this->RenderExpression(false, $aArgs);
return $this->Render($aArgs);
}
// recursive rendering
public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false)
public function Render(&$aArgs = null, $bRetrofitParams = false)
{
if (is_null($this->m_value))
{
@@ -893,23 +796,23 @@ class ScalarExpression extends UnaryExpression
public function GetCriterion($oSearch, &$aArgs = null, $bRetrofitParams = false, $oAttDef = null)
{
$aCriterion = array();
$aCriteria = array();
switch ((string)($this->m_value))
{
case '%Y-%m-%d':
$aCriterion['unit'] = 'DAY';
$aCriteria['unit'] = 'DAY';
break;
case '%Y-%m':
$aCriterion['unit'] = 'MONTH';
$aCriteria['unit'] = 'MONTH';
break;
case '%w':
$aCriterion['unit'] = 'WEEKDAY';
$aCriteria['unit'] = 'WEEKDAY';
break;
case '%H':
$aCriterion['unit'] = 'HOUR';
$aCriteria['unit'] = 'HOUR';
break;
default:
$aValue = array();
$aValue = array('value' => $this->GetValue());
if (!is_null($oAttDef))
{
switch (true)
@@ -919,7 +822,7 @@ class ScalarExpression extends UnaryExpression
{
$oFinalAttDef = $oAttDef->GetFinalAttDef();
if($oFinalAttDef instanceof AttributeExternalKey)
{
{
if ($this->GetValue() !== 0)
{
/** @var AttributeExternalKey $oFinalAttDef */
@@ -946,79 +849,42 @@ class ScalarExpression extends UnaryExpression
IssueLog::Error($e->getMessage());
}
break;
case ($oAttDef instanceof AttributeTagSet):
try
{
if (!empty($this->GetValue()))
{
$aValues = array();
$oValue = $this->GetValue();
if (is_string($oValue))
{
$oValue = $oAttDef->GetExistingTagsFromString($oValue, true);
}
/** @var \ormTagSet $oValue */
$aTags = $oValue->GetTags();
foreach($aTags as $oTag)
{
$aValue['label'] = $oTag->Get('label');
$aValue['value'] = $oTag->Get('code');
$aValues[] = $aValue;
}
$aCriterion['values'] = $aValues;
}
else
{
$aCriterion['has_undefined'] = true;
}
} catch (Exception $e)
{
IssueLog::Error($e->getMessage());
}
break;
case $oAttDef->IsExternalKey():
try
{
if ($this->GetValue() != 0)
if ($this->GetValue() == 0)
{
$aValue['label'] = Dict::S('UI:UndefinedObject');
}
else
{
/** @var AttributeExternalKey $oAttDef */
$sTarget = $oAttDef->GetTargetClass();
$oObj = MetaModel::GetObject($sTarget, $this->GetValue(), true, true);
$aValue['label'] = $oObj->Get("friendlyname");
$aValue['value'] = $this->GetValue();
$aCriterion['values'] = array($aValue);
}
else
{
$aValue['label'] = Dict::S('Enum:Undefined');
$aValue['value'] = $this->GetValue();
$aCriterion['values'] = array($aValue);
}
} catch (Exception $e)
}
catch (Exception $e)
{
// This object cannot be seen... ignore
IssueLog::Error($e->getMessage());
}
break;
default:
try
{
$aValue['label'] = $oAttDef->GetAsPlainText($this->GetValue());
$aValue['value'] = $this->GetValue();
$aCriterion['values'] = array($aValue);
} catch (Exception $e)
{
$aValue['label'] = $this->GetValue();
$aValue['value'] = $this->GetValue();
$aCriterion['values'] = array($aValue);
}
break;
}
}
$aCriteria['values'] = array($aValue);
break;
}
$aCriterion['oql'] = $this->RenderExpression(false, $aArgs, $bRetrofitParams);
return $aCriterion;
$aCriteria['oql'] = $this->Render($aArgs, $bRetrofitParams);
return $aCriteria;
}
}
@@ -1125,7 +991,7 @@ class FieldExpression extends UnaryExpression
}
// recursive rendering
public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false)
public function Render(&$aArgs = null, $bRetrofitParams = false)
{
if (empty($this->m_sParent))
{
@@ -1231,7 +1097,7 @@ class FieldExpression extends UnaryExpression
* @param string sValue The value returned by the query, for this expression
* @param string sDefault The default value if no relevant label could be computed
*
* @return string label
* @return The label
* @throws \CoreException
*/
public function MakeValueLabel($oFilter, $sValue, $sDefault)
@@ -1471,18 +1337,19 @@ class VariableExpression extends UnaryExpression
return $oAttDef->GetAsPlainText($sValue);
}
return $this->RenderExpression(false, $aArgs);
return $this->Render($aArgs);
}
// recursive rendering
/**
* @param bool $bForSQL
* @param array $aArgs
* @param null $aArgs
* @param bool $bRetrofitParams
*
* @return array|string
* @throws \MissingQueryArgument
*/
public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false)
public function Render(&$aArgs = null, $bRetrofitParams = false)
{
if (is_null($aArgs))
{
@@ -1600,12 +1467,12 @@ class ListExpression extends Expression
}
// recursive rendering
public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false)
public function Render(&$aArgs = null, $bRetrofitParams = false)
{
$aRes = array();
foreach ($this->m_aExpressions as $oExpr)
{
$aRes[] = $oExpr->RenderExpression($bForSQL, $aArgs, $bRetrofitParams);
$aRes[] = $oExpr->Render($aArgs, $bRetrofitParams);
}
return '('.implode(', ', $aRes).')';
}
@@ -1621,11 +1488,12 @@ class ListExpression extends Expression
public function ApplyParameters($aArgs)
{
$aRes = array();
foreach ($this->m_aExpressions as $idx => $oExpr)
{
if ($oExpr instanceof VariableExpression)
{
$this->m_aExpressions[$idx] = $oExpr->GetAsScalar($aArgs);
$this->m_aExpressions[$idx] = $oExpr->GetAsScalar();
}
else
{
@@ -1682,6 +1550,7 @@ class ListExpression extends Expression
public function RenameParam($sOldName, $sNewName)
{
$aRes = array();
foreach ($this->m_aExpressions as $key => $oExpr)
{
$this->m_aExpressions[$key] = $oExpr->RenameParam($sOldName, $sNewName);
@@ -1690,6 +1559,7 @@ class ListExpression extends Expression
public function RenameAlias($sOldName, $sNewName)
{
$aRes = array();
foreach ($this->m_aExpressions as $key => $oExpr)
{
$oExpr->RenameAlias($sOldName, $sNewName);
@@ -1753,12 +1623,12 @@ class FunctionExpression extends Expression
}
// recursive rendering
public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false)
public function Render(&$aArgs = null, $bRetrofitParams = false)
{
$aRes = array();
foreach ($this->m_aArgs as $iPos => $oExpr)
{
$aRes[] = $oExpr->RenderExpression($bForSQL, $aArgs, $bRetrofitParams);
$aRes[] = $oExpr->Render($aArgs, $bRetrofitParams);
}
return $this->m_sVerb.'('.implode(', ', $aRes).')';
}
@@ -1774,6 +1644,7 @@ class FunctionExpression extends Expression
public function ApplyParameters($aArgs)
{
$aRes = array();
foreach ($this->m_aArgs as $idx => $oExpr)
{
if ($oExpr instanceof VariableExpression)
@@ -1867,7 +1738,7 @@ class FunctionExpression extends Expression
* @param string sValue The value returned by the query, for this expression
* @param string sDefault The default value if no relevant label could be computed
*
* @return string label
* @return The label
*/
public function MakeValueLabel($oFilter, $sValue, $sDefault)
{
@@ -1943,7 +1814,6 @@ class FunctionExpression extends Expression
$sVerb = '';
switch ($this->m_sVerb)
{
case 'ISNULL':
case 'NOW':
$sVerb = $this->VerbToNaturalLanguage();
break;
@@ -1957,7 +1827,7 @@ class FunctionExpression extends Expression
$aCtx['date_display'] = $this;
break;
default:
return $this->RenderExpression(false, $aArgs);
return $this->Render($aArgs);
}
foreach($this->m_aArgs as $oExpression)
@@ -1974,7 +1844,7 @@ class FunctionExpression extends Expression
{
$sOperation .= $sVerb;
}
return '('.$sOperation.')';
return $sOperation;
}
private function VerbToNaturalLanguage()
@@ -1994,7 +1864,7 @@ class FunctionExpression extends Expression
$aCriteria = array_merge($oExpression->GetCriterion($oSearch, $aArgs, $bRetrofitParams, $oAttDef), $aCriteria);
}
$aCriteria['has_undefined'] = true;
$aCriteria['oql'] = $this->RenderExpression(false, $aArgs, $bRetrofitParams);
$aCriteria['oql'] = $this->Render($aArgs, $bRetrofitParams);
break;
case 'NOW':
@@ -2022,9 +1892,6 @@ class FunctionExpression extends Expression
}
}
/**
* @see https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html
*/
class IntervalExpression extends Expression
{
protected $m_oValue; // expression
@@ -2053,9 +1920,9 @@ class IntervalExpression extends Expression
}
// recursive rendering
public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false)
public function Render(&$aArgs = null, $bRetrofitParams = false)
{
return 'INTERVAL '.$this->m_oValue->RenderExpression($bForSQL, $aArgs, $bRetrofitParams).' '.$this->m_sUnit;
return 'INTERVAL '.$this->m_oValue->Render($aArgs, $bRetrofitParams).' '.$this->m_sUnit;
}
public function Browse(Closure $callback)
@@ -2120,7 +1987,7 @@ class IntervalExpression extends Expression
public function Display($oSearch, &$aArgs = null, $oAttDef = null, &$aCtx = array())
{
return $this->m_oValue->RenderExpression(false, $aArgs).' '.Dict::S('Expression:Unit:Long:'.$this->m_sUnit, $this->m_sUnit);
return $this->m_oValue->Render($aArgs).' '.Dict::S('Expression:Unit:Long:'.$this->m_sUnit, $this->m_sUnit);
}
}
@@ -2145,12 +2012,12 @@ class CharConcatExpression extends Expression
}
// recursive rendering
public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false)
public function Render(&$aArgs = null, $bRetrofitParams = false)
{
$aRes = array();
foreach ($this->m_aExpressions as $oExpr)
{
$sCol = $oExpr->RenderExpression($bForSQL, $aArgs, $bRetrofitParams);
$sCol = $oExpr->Render($aArgs, $bRetrofitParams);
// Concat will be globally NULL if one single argument is null !
$aRes[] = "COALESCE($sCol, '')";
}
@@ -2168,11 +2035,12 @@ class CharConcatExpression extends Expression
public function ApplyParameters($aArgs)
{
$aRes = array();
foreach ($this->m_aExpressions as $idx => $oExpr)
{
if ($oExpr instanceof VariableExpression)
{
$this->m_aExpressions[$idx] = $oExpr->GetAsScalar($aArgs);
$this->m_aExpressions[$idx] = $oExpr->GetAsScalar();
}
else
{
@@ -2256,12 +2124,12 @@ class CharConcatWSExpression extends CharConcatExpression
}
// recursive rendering
public function RenderExpression($bForSQL = false, &$aArgs = null, $bRetrofitParams = false)
public function Render(&$aArgs = null, $bRetrofitParams = false)
{
$aRes = array();
foreach ($this->m_aExpressions as $oExpr)
{
$sCol = $oExpr->RenderExpression($bForSQL, $aArgs, $bRetrofitParams);
$sCol = $oExpr->Render($aArgs, $bRetrofitParams);
// Concat will be globally NULL if one single argument is null !
$aRes[] = "COALESCE($sCol, '')";
}

View File

@@ -140,7 +140,6 @@ class OQLLexerRaw
'/\GNOT LIKE/ ',
'/\GIN/ ',
'/\GNOT IN/ ',
'/\GMATCHES/ ',
'/\GINTERVAL/ ',
'/\GIF/ ',
'/\GELT/ ',
@@ -442,209 +441,204 @@ class OQLLexerRaw
function yy_r1_33($yy_subpatterns)
{
$this->token = OQLParser::MATCHES;
$this->token = OQLParser::INTERVAL;
}
function yy_r1_34($yy_subpatterns)
{
$this->token = OQLParser::INTERVAL;
$this->token = OQLParser::F_IF;
}
function yy_r1_35($yy_subpatterns)
{
$this->token = OQLParser::F_IF;
$this->token = OQLParser::F_ELT;
}
function yy_r1_36($yy_subpatterns)
{
$this->token = OQLParser::F_ELT;
$this->token = OQLParser::F_COALESCE;
}
function yy_r1_37($yy_subpatterns)
{
$this->token = OQLParser::F_COALESCE;
$this->token = OQLParser::F_ISNULL;
}
function yy_r1_38($yy_subpatterns)
{
$this->token = OQLParser::F_ISNULL;
$this->token = OQLParser::F_CONCAT;
}
function yy_r1_39($yy_subpatterns)
{
$this->token = OQLParser::F_CONCAT;
$this->token = OQLParser::F_SUBSTR;
}
function yy_r1_40($yy_subpatterns)
{
$this->token = OQLParser::F_SUBSTR;
$this->token = OQLParser::F_TRIM;
}
function yy_r1_41($yy_subpatterns)
{
$this->token = OQLParser::F_TRIM;
$this->token = OQLParser::F_DATE;
}
function yy_r1_42($yy_subpatterns)
{
$this->token = OQLParser::F_DATE;
$this->token = OQLParser::F_DATE_FORMAT;
}
function yy_r1_43($yy_subpatterns)
{
$this->token = OQLParser::F_DATE_FORMAT;
$this->token = OQLParser::F_CURRENT_DATE;
}
function yy_r1_44($yy_subpatterns)
{
$this->token = OQLParser::F_CURRENT_DATE;
$this->token = OQLParser::F_NOW;
}
function yy_r1_45($yy_subpatterns)
{
$this->token = OQLParser::F_NOW;
$this->token = OQLParser::F_TIME;
}
function yy_r1_46($yy_subpatterns)
{
$this->token = OQLParser::F_TIME;
$this->token = OQLParser::F_TO_DAYS;
}
function yy_r1_47($yy_subpatterns)
{
$this->token = OQLParser::F_TO_DAYS;
$this->token = OQLParser::F_FROM_DAYS;
}
function yy_r1_48($yy_subpatterns)
{
$this->token = OQLParser::F_FROM_DAYS;
$this->token = OQLParser::F_YEAR;
}
function yy_r1_49($yy_subpatterns)
{
$this->token = OQLParser::F_YEAR;
$this->token = OQLParser::F_MONTH;
}
function yy_r1_50($yy_subpatterns)
{
$this->token = OQLParser::F_MONTH;
$this->token = OQLParser::F_DAY;
}
function yy_r1_51($yy_subpatterns)
{
$this->token = OQLParser::F_DAY;
$this->token = OQLParser::F_HOUR;
}
function yy_r1_52($yy_subpatterns)
{
$this->token = OQLParser::F_HOUR;
$this->token = OQLParser::F_MINUTE;
}
function yy_r1_53($yy_subpatterns)
{
$this->token = OQLParser::F_MINUTE;
$this->token = OQLParser::F_SECOND;
}
function yy_r1_54($yy_subpatterns)
{
$this->token = OQLParser::F_SECOND;
$this->token = OQLParser::F_DATE_ADD;
}
function yy_r1_55($yy_subpatterns)
{
$this->token = OQLParser::F_DATE_ADD;
$this->token = OQLParser::F_DATE_SUB;
}
function yy_r1_56($yy_subpatterns)
{
$this->token = OQLParser::F_DATE_SUB;
$this->token = OQLParser::F_ROUND;
}
function yy_r1_57($yy_subpatterns)
{
$this->token = OQLParser::F_ROUND;
$this->token = OQLParser::F_FLOOR;
}
function yy_r1_58($yy_subpatterns)
{
$this->token = OQLParser::F_FLOOR;
$this->token = OQLParser::F_INET_ATON;
}
function yy_r1_59($yy_subpatterns)
{
$this->token = OQLParser::F_INET_ATON;
$this->token = OQLParser::F_INET_NTOA;
}
function yy_r1_60($yy_subpatterns)
{
$this->token = OQLParser::F_INET_NTOA;
$this->token = OQLParser::BELOW;
}
function yy_r1_61($yy_subpatterns)
{
$this->token = OQLParser::BELOW;
$this->token = OQLParser::BELOW_STRICT;
}
function yy_r1_62($yy_subpatterns)
{
$this->token = OQLParser::BELOW_STRICT;
$this->token = OQLParser::NOT_BELOW;
}
function yy_r1_63($yy_subpatterns)
{
$this->token = OQLParser::NOT_BELOW;
$this->token = OQLParser::NOT_BELOW_STRICT;
}
function yy_r1_64($yy_subpatterns)
{
$this->token = OQLParser::NOT_BELOW_STRICT;
$this->token = OQLParser::ABOVE;
}
function yy_r1_65($yy_subpatterns)
{
$this->token = OQLParser::ABOVE;
$this->token = OQLParser::ABOVE_STRICT;
}
function yy_r1_66($yy_subpatterns)
{
$this->token = OQLParser::ABOVE_STRICT;
$this->token = OQLParser::NOT_ABOVE;
}
function yy_r1_67($yy_subpatterns)
{
$this->token = OQLParser::NOT_ABOVE;
$this->token = OQLParser::NOT_ABOVE_STRICT;
}
function yy_r1_68($yy_subpatterns)
{
$this->token = OQLParser::NOT_ABOVE_STRICT;
$this->token = OQLParser::HEXVAL;
}
function yy_r1_69($yy_subpatterns)
{
$this->token = OQLParser::HEXVAL;
$this->token = OQLParser::NUMVAL;
}
function yy_r1_70($yy_subpatterns)
{
$this->token = OQLParser::NUMVAL;
$this->token = OQLParser::STRVAL;
}
function yy_r1_71($yy_subpatterns)
{
$this->token = OQLParser::STRVAL;
$this->token = OQLParser::NAME;
}
function yy_r1_72($yy_subpatterns)
{
$this->token = OQLParser::NAME;
}
function yy_r1_73($yy_subpatterns)
{
$this->token = OQLParser::VARNAME;
}
function yy_r1_74($yy_subpatterns)
function yy_r1_73($yy_subpatterns)
{
$this->token = OQLParser::DOT;
@@ -672,25 +666,25 @@ class OQLLexer extends OQLLexerRaw
function yylex()
{
try
{
return parent::yylex();
}
catch (Exception $e)
{
$sMessage = $e->getMessage();
if (substr($sMessage, 0, strlen(UNEXPECTED_INPUT_AT_LINE)) == UNEXPECTED_INPUT_AT_LINE)
{
$sLineAndChar = substr($sMessage, strlen(UNEXPECTED_INPUT_AT_LINE));
if (preg_match('#^([0-9]+): (.+)$#', $sLineAndChar, $aMatches))
{
$iLine = $aMatches[1];
$sUnexpected = $aMatches[2];
throw new OQLLexerException($this->data, $iLine, $this->count, $sUnexpected);
}
}
// Default: forward the exception
throw $e;
try
{
return parent::yylex();
}
catch (Exception $e)
{
$sMessage = $e->getMessage();
if (substr($sMessage, 0, strlen(UNEXPECTED_INPUT_AT_LINE)) == UNEXPECTED_INPUT_AT_LINE)
{
$sLineAndChar = substr($sMessage, strlen(UNEXPECTED_INPUT_AT_LINE));
if (preg_match('#^([0-9]+): (.+)$#', $sLineAndChar, $aMatches))
{
$iLine = $aMatches[1];
$sUnexpected = $aMatches[2];
throw new OQLLexerException($this->data, $iLine, $this->count, $sUnexpected);
}
}
// Default: forward the exception
throw $e;
}
}
}

View File

@@ -139,7 +139,6 @@ f_round = "ROUND"
f_floor = "FLOOR"
f_inet_aton = "INET_ATON"
f_inet_ntoa = "INET_NTOA"
matches = "MATCHES"
below = "BELOW"
below_strict = "BELOW STRICT"
not_below = "NOT BELOW"
@@ -274,9 +273,6 @@ in {
not_in {
$this->token = OQLParser::NOT_IN;
}
matches {
$this->token = OQLParser::MATCHES;
}
interval {
$this->token = OQLParser::INTERVAL;
}
@@ -423,25 +419,25 @@ class OQLLexer extends OQLLexerRaw
function yylex()
{
try
{
return parent::yylex();
}
catch (Exception $e)
{
$sMessage = $e->getMessage();
if (substr($sMessage, 0, strlen(UNEXPECTED_INPUT_AT_LINE)) == UNEXPECTED_INPUT_AT_LINE)
{
$sLineAndChar = substr($sMessage, strlen(UNEXPECTED_INPUT_AT_LINE));
if (preg_match('#^([0-9]+): (.+)$#', $sLineAndChar, $aMatches))
{
$iLine = $aMatches[1];
$sUnexpected = $aMatches[2];
throw new OQLLexerException($this->data, $iLine, $this->count, $sUnexpected);
}
}
// Default: forward the exception
throw $e;
try
{
return parent::yylex();
}
catch (Exception $e)
{
$sMessage = $e->getMessage();
if (substr($sMessage, 0, strlen(UNEXPECTED_INPUT_AT_LINE)) == UNEXPECTED_INPUT_AT_LINE)
{
$sLineAndChar = substr($sMessage, strlen(UNEXPECTED_INPUT_AT_LINE));
if (preg_match('#^([0-9]+): (.+)$#', $sLineAndChar, $aMatches))
{
$iLine = $aMatches[1];
$sUnexpected = $aMatches[2];
throw new OQLLexerException($this->data, $iLine, $this->count, $sUnexpected);
}
}
// Default: forward the exception
throw $e;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -16,7 +16,7 @@ Example:
%left TIMES DIVIDE MOD.
%right EXP NOT.
later : solve the 2 remaining shift-reduce conflicts (JOIN)
TODO : solve the 2 remaining shift-reduce conflicts (JOIN)
*/
@@ -108,16 +108,7 @@ expression_prio1(A) ::= expression_basic(X). { A = X; }
expression_prio1(A) ::= expression_prio1(X) operator1(Y) expression_basic(Z). { A = new BinaryOqlExpression(X, Y, Z); }
expression_prio2(A) ::= expression_prio1(X). { A = X; }
expression_prio2(A) ::= expression_prio2(X) operator2(Y) expression_prio1(Z).{
if (Y == 'MATCHES')
{
A = new MatchOqlExpression(X, Z);
}
else
{
A = new BinaryOqlExpression(X, Y, Z);
}
}
expression_prio2(A) ::= expression_prio2(X) operator2(Y) expression_prio1(Z). { A = new BinaryOqlExpression(X, Y, Z); }
expression_prio3(A) ::= expression_prio2(X). { A = X; }
expression_prio3(A) ::= expression_prio3(X) operator3(Y) expression_prio2(Z). { A = new BinaryOqlExpression(X, Y, Z); }
@@ -189,22 +180,18 @@ str_value(A) ::= STRVAL(X). {A=stripslashes(substr(X, 1, strlen(X) - 2));}
operator1(A) ::= num_operator1(X). {A=X;}
operator1(A) ::= bitwise_operator1(X). {A=X;}
operator2(A) ::= num_operator2(X). {A=X;}
operator2(A) ::= str_operator(X). {A=X;}
operator2(A) ::= REGEXP(X). {A=X;}
operator2(A) ::= EQ(X). {A=X;}
operator2(A) ::= NOT_EQ(X). {A=X;}
operator3(A) ::= LOG_AND(X). {A=X;}
operator3(A) ::= bitwise_operator3(X). {A=X;}
operator4(A) ::= LOG_OR(X). {A=X;}
operator4(A) ::= bitwise_operator4(X). {A=X;}
num_operator1(A) ::= MATH_DIV(X). {A=X;}
num_operator1(A) ::= MATH_MULT(X). {A=X;}
num_operator2(A) ::= MATH_PLUS(X). {A=X;}
num_operator2(A) ::= MATH_MINUS(X). {A=X;}
num_operator2(A) ::= GT(X). {A=X;}
@@ -214,13 +201,10 @@ num_operator2(A) ::= LE(X). {A=X;}
str_operator(A) ::= LIKE(X). {A=X;}
str_operator(A) ::= NOT_LIKE(X). {A=X;}
str_operator(A) ::= MATCHES(X). {A=X;}
bitwise_operator1(A) ::= BITWISE_LEFT_SHIFT(X). {A=X;}
bitwise_operator1(A) ::= BITWISE_RIGHT_SHIFT(X). {A=X;}
bitwise_operator3(A) ::= BITWISE_AND(X). {A=X;}
bitwise_operator4(A) ::= BITWISE_OR(X). {A=X;}
bitwise_operator4(A) ::= BITWISE_XOR(X). {A=X;}

View File

@@ -84,7 +84,7 @@ class OqlInterpreter
}
/**
* @return \OqlObjectQuery|\OqlUnionQuery
* @return OqlQuery
* @throws \OQLException
*/
public function ParseQuery()

View File

@@ -160,26 +160,6 @@ class BinaryOqlExpression extends BinaryExpression implements CheckableExpressio
}
}
class MatchOqlExpression extends MatchExpression implements CheckableExpression
{
public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery)
{
$this->m_oLeftExpr->Check($oModelReflection, $aAliases, $sSourceQuery);
$this->m_oRightExpr->Check($oModelReflection, $aAliases, $sSourceQuery);
// Only field MATCHES scalar is allowed
if (!$this->m_oLeftExpr instanceof FieldExpression)
{
throw new OqlNormalizeException('Only "field MATCHES string" syntax is allowed', $sSourceQuery, new OqlName($this->m_oLeftExpr->RenderExpression(true), 0));
}
// Only field MATCHES scalar is allowed
if (!$this->m_oRightExpr instanceof ScalarExpression)
{
throw new OqlNormalizeException('Only "field MATCHES string" syntax is allowed', $sSourceQuery, new OqlName($this->m_oRightExpr->RenderExpression(true), 0));
}
}
}
class ScalarOqlExpression extends ScalarExpression implements CheckableExpression
{
public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery)

View File

@@ -1 +1 @@
2018-08-31
2015-08-31

View File

@@ -34,7 +34,7 @@ class ormCaseLog {
/**
* Initializes the log with the first (initial) entry
* @param $sLog string The text of the whole case log
* @param $aIndex array The case log index
* @param $aIndex hash The case log index
*/
public function __construct($sLog = '', $aIndex = array())
{
@@ -159,7 +159,6 @@ class ormCaseLog {
$aEntries[] = array(
'date' => '',
'user_login' => '',
'user_id' => 0,
'message' => $sTextEntry,
'message_html' => utils::TextToHtml($sTextEntry),
);
@@ -296,6 +295,7 @@ class ormCaseLog {
*/
public function GetAsSimpleHtml($aTransfoHandler = null)
{
$sStyleCaseLogHeader = '';
$sStyleCaseLogEntry = '';
$sHtml = '<ul class="case_log_simple_html">';
@@ -513,6 +513,7 @@ class ormCaseLog {
public function AddLogEntry($sText, $sOnBehalfOf = '')
{
$sText = HTMLSanitizer::Sanitize($sText);
$bMergeEntries = false;
$sDate = date(AttributeDateTime::GetInternalFormat());
if ($sOnBehalfOf == '')
{
@@ -698,6 +699,7 @@ class ormCaseLog {
{
$iPos = 0;
$index = count($this->m_aIndex) - 1;
$aIndex = $this->m_aIndex;
while($index > $iIndex)
{
$iPos += $this->m_aIndex[$index]['separator_length'];

View File

@@ -126,6 +126,7 @@ class ormDocument
*/
public function GetDisplayURL($sClass, $Id, $sAttCode)
{
// TODO: When refactoring this with the URLMaker system, mind to also change calls in the portal (look for the "p_object_document_display" route)
return utils::GetAbsoluteUrlAppRoot() . "pages/ajax.render.php?operation=display_document&class=$sClass&id=$Id&field=$sAttCode";
}
@@ -137,6 +138,7 @@ class ormDocument
{
// Compute a signature to reset the cache anytime the data changes (this is acceptable if used only with icon files)
$sSignature = md5($this->GetData());
// TODO: When refactoring this with the URLMaker system, mind to also change calls in the portal (look for the "p_object_document_display" route)
return utils::GetAbsoluteUrlAppRoot() . "pages/ajax.document.php?operation=download_document&class=$sClass&id=$Id&field=$sAttCode&s=$sSignature&cache=86400";
}

View File

@@ -42,7 +42,6 @@ class ormPassword
public function __construct($sHash = '', $sSalt = '')
{
$this->m_sHashed = $sHash;
//only used for <= 2.5 hashed password
$this->m_sSalt = $sSalt;
}
@@ -51,7 +50,8 @@ class ormPassword
*/
public function SetPassword($sClearTextPassword)
{
$this->m_sHashed = password_hash($sClearTextPassword, PASSWORD_DEFAULT);
$this->m_sSalt = SimpleCrypt::GetNewSalt();
$this->m_sHashed = $this->ComputeHash($sClearTextPassword);
}
/**
@@ -95,19 +95,10 @@ class ormPassword
public function CheckPassword($sClearTextPassword)
{
$bResult = false;
$aInfo = password_get_info($this->m_sHashed);
switch ($aInfo["algo"])
$sHashedPwd = $this->ComputeHash($sClearTextPassword);
if ($this->m_sHashed == $sHashedPwd)
{
case 0:
//unknown, assume it's a legacy password
$sHashedPwd = $this->ComputeHash($sClearTextPassword);
if ($this->m_sHashed == $sHashedPwd)
{
$bResult = true;
}
break;
default:
$bResult = password_verify($sClearTextPassword, $this->m_sHashed);
$bResult = true;
}
return $bResult;
}

View File

@@ -1,380 +0,0 @@
<?php
/**
* Copyright (c) 2010-2018 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*
*/
/**
* Created by PhpStorm.
* Date: 24/08/2018
* Time: 14:35
*/
class ormSet
{
protected $sClass; // class of the field
protected $sAttCode; // attcode of the field
protected $aOriginalObjects = null;
/**
* Object from the original set, minus the removed objects
*/
protected $aPreserved = array();
/**
* New items
*/
protected $aAdded = array();
/**
* Removed items
*/
protected $aRemoved = array();
/**
* Modified items (mass edit)
*/
protected $aModified = array();
/**
* @var int Max number of tags in collection
*/
protected $iLimit;
/**
* __toString magical function overload.
*/
public function __toString()
{
$aValue = $this->GetValues();
if (!empty($aValue))
{
return implode(', ', $aValue);
}
else
{
return ' ';
}
}
/**
* ormSet constructor.
*
* @param string $sClass
* @param string $sAttCode
* @param int $iLimit
*
* @throws \Exception
*/
public function __construct($sClass, $sAttCode, $iLimit = 12)
{
$this->sAttCode = $sAttCode;
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if (!$oAttDef instanceof AttributeSet)
{
throw new Exception("ormSet: field {$sClass}:{$sAttCode} is not a set");
}
$this->sClass = $sClass;
$this->iLimit = $iLimit;
}
/**
* @return string
*/
public function GetClass()
{
return $this->sClass;
}
/**
* @return string
*/
public function GetAttCode()
{
return $this->sAttCode;
}
/**
*
* @param array $aItems
*
* @throws \CoreException
* @throws \CoreUnexpectedValue when a code is invalid
*/
public function SetValues($aItems)
{
if (!is_array($aItems))
{
throw new CoreUnexpectedValue("Wrong value {$aItems} for {$this->sClass}:{$this->sAttCode}");
}
$aValues = array();
$iCount = 0;
$bError = false;
foreach($aItems as $oItem)
{
$iCount++;
if (($this->iLimit != 0) && ($iCount > $this->iLimit))
{
$bError = true;
continue;
}
$aValues[] = $oItem;
}
$this->aPreserved = &$aValues;
$this->aRemoved = array();
$this->aAdded = array();
$this->aModified = array();
$this->aOriginalObjects = $aValues;
if ($bError)
{
throw new CoreException("Maximum number of items ({$this->iLimit}) reached for {$this->sClass}:{$this->sAttCode}");
}
}
public function Count()
{
return count($this->aPreserved) + count($this->aAdded) - count($this->aRemoved);
}
/**
* @return array of codes
*/
public function GetValues()
{
$aValues = array_merge($this->aPreserved, $this->aAdded);
return $aValues;
}
/**
* @return array of tag labels indexed by code for only the added tags
*/
private function GetAdded()
{
return $this->aAdded;
}
/**
* @return array of tag labels indexed by code for only the removed tags
*/
private function GetRemoved()
{
return $this->aRemoved;
}
/** Get the delta with another ItemSet
*
* $aDelta['added] = array of tag codes for only the added tags
* $aDelta['removed'] = array of tag codes for only the removed tags
*
* @param \ormSet $oOtherSet
*
* @return array
*
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \Exception
*/
public function GetDelta(ormSet $oOtherSet)
{
$oSet = new ormSet($this->sClass, $this->sAttCode, $this->iLimit);
// Set the initial value
$aOrigItems = $this->GetValues();
$oSet->SetValues($aOrigItems);
// now remove everything
foreach($aOrigItems as $oItem)
{
$oSet->Remove($oItem);
}
// now add the tags of the other ItemSet
foreach($oOtherSet->GetValues() as $oItem)
{
$oSet->Add($oItem);
}
$aDelta = array();
$aDelta['added'] = $oSet->GetAdded();
$aDelta['removed'] = $oSet->GetRemoved();
return $aDelta;
}
/**
* @return string[] list of codes for partial entries
*/
public function GetModified()
{
return $this->aModified;
}
/**
* Apply a delta to the current ItemSet
* $aDelta['added] = array of added items
* $aDelta['removed'] = array of removed items
*
* @param $aDelta
*
* @throws \CoreException
*/
public function ApplyDelta($aDelta)
{
if (isset($aDelta['removed']))
{
foreach($aDelta['removed'] as $oItem)
{
$this->Remove($oItem);
}
}
if (isset($aDelta['added']))
{
foreach($aDelta['added'] as $oItem)
{
$this->Add($oItem);
}
}
// Reset the object
$this->SetValues($this->GetValues());
}
/**
* @param string $oItem
*
* @throws \CoreException
*/
public function Add($oItem)
{
if (($this->iLimit != 0) && ($this->Count() > $this->iLimit))
{
throw new CoreException("Maximum number of items ({$this->iLimit}) reached for {$this->sClass}:{$this->sAttCode}");
}
if ($this->IsItemInList($this->aPreserved, $oItem) || $this->IsItemInList($this->aAdded, $oItem))
{
// nothing to do, already existing tag
return;
}
// if removed and added again
if (($this->RemoveItemFromList($this->aRemoved, $oItem)) !== false)
{
// put it back into preserved
$this->aPreserved[] = $oItem;
// no need to add it to aModified : was already done when calling RemoveItem method
}
else
{
$this->aAdded[] = $oItem;
$this->aModified[] = $oItem;
}
}
/**
* @param $oItem
*/
public function Remove($oItem)
{
if ($this->IsItemInList($this->aRemoved, $oItem))
{
// nothing to do, already removed tag
return;
}
if ($this->RemoveItemFromList($this->aAdded, $oItem) !== false)
{
$this->aModified[] = $oItem;
return; // if present in added, can't be in preserved !
}
if ($this->RemoveItemFromList($this->aPreserved, $oItem) !== false)
{
$this->aModified[] = $oItem;
$this->aRemoved[] = $oItem;
}
}
private function IsItemInList($aItemList, $oItem)
{
return in_array($oItem, $aItemList);
}
/**
* @param \DBObject[] $aItemList
* @param $oItem
*
* @return bool|\DBObject false if not found, else the removed element
*/
private function RemoveItemFromList(&$aItemList, $oItem)
{
if (!($this->IsItemInList($aItemList, $oItem)))
{
return false;
}
foreach ($aItemList as $index => $value)
{
if ($value === $oItem)
{
unset($aItemList[$index]);
return $oItem;
}
}
return false;
}
/**
* Populates the added and removed arrays for bulk edit
*
* @param string[] $aItems
*
* @throws \CoreException
*/
public function GenerateDiffFromArray($aItems)
{
foreach($this->GetValues() as $oCurrentItem)
{
if (!in_array($oCurrentItem, $aItems))
{
$this->Remove($oCurrentItem);
}
}
foreach($aItems as $oNewItem)
{
$this->Add($oNewItem);
}
}
/**
* Compare Item Set
*
* @param \ormSet $other
*
* @return bool true if same tag set
*/
public function Equals(ormSet $other)
{
return implode(', ', $this->GetValue()) === implode(', ', $other->GetValue());
}
}

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2018 Combodo SARL
// Copyright (C) 2010-2017 Combodo SARL
//
// This file is part of iTop.
//
@@ -85,12 +85,8 @@ class ormStopWatch
/**
* Get the working elapsed time since the start of the stop watch
* even if it is currently running
*
* @param AttributeDefinition oAttDef Attribute hosting the stop watch
* @param Object oObject Hosting object (used for query parameters)
*
* @return int|mixed
* @throws \CoreException
* @param oAttDef AttributeDefinition Attribute hosting the stop watch
* @param oObject Hosting object (used for query parameters)
*/
public function GetElapsedTime($oAttDef, $oObject)
{
@@ -264,16 +260,6 @@ class ormStopWatch
return $iRet;
}
/**
* @param $oObject
* @param $oAttDef
* @param $iPercent
* @param $iStartTime
* @param $iDurationSec
*
* @return mixed
* @throws \CoreException
*/
protected function ComputeDeadline($oObject, $oAttDef, $iPercent, $iStartTime, $iDurationSec)
{
$sWorkingTimeComputer = $oAttDef->Get('working_time_computing');
@@ -281,6 +267,11 @@ class ormStopWatch
{
$sWorkingTimeComputer = class_exists('SLAComputation') ? 'SLAComputation' : 'DefaultWorkingTimeComputer';
}
$aCallSpec = array($sWorkingTimeComputer, '__construct');
if (!is_callable($aCallSpec))
{
//throw new CoreException("Pas de constructeur pour $sWorkingTimeComputer!");
}
$oComputer = new $sWorkingTimeComputer();
$aCallSpec = array($oComputer, 'GetDeadline');
if (!is_callable($aCallSpec))
@@ -294,15 +285,6 @@ class ormStopWatch
return $iRet;
}
/**
* @param $oObject
* @param $oAttDef
* @param $iStartTime
* @param $iEndTime
*
* @return mixed
* @throws \CoreException
*/
protected function ComputeDuration($oObject, $oAttDef, $iStartTime, $iEndTime)
{
$sWorkingTimeComputer = $oAttDef->Get('working_time_computing');
@@ -402,20 +384,7 @@ class ormStopWatch
$sAttCode = $oAttDef->GetCode();
WorkingTimeRecorder::Start($oObject, $iComputationRefTime, "ormStopWatch-Deadline-$iPercent-$sAttCode", 'Core:ExplainWTC:StopWatch-Deadline', array("Class:$sClass/Attribute:$sAttCode", $iPercent));
}
$iRemaining = $iThresholdDuration - $this->iTimeSpent;
if ($iRemaining < 0)
{
if (class_exists('WorkingTimeRecorder'))
{
$sClass = get_class($oObject);
$sKey = $oObject->GetKey();
$sAttCode = $oAttDef->GetCode();
$sDate = date('Y-m-d H:i:s', $aThresholdData['deadline']);
WorkingTimeRecorder::Log(WorkingTimeRecorder::TRACE_INFO, "$sClass($sKey) ormStopWatch-Deadline-$iPercent-$sAttCode ($sDate) already reached, not changed.");
}
continue;
}
$aThresholdData['deadline'] = $this->ComputeDeadline($oObject, $oAttDef, $iPercent, $this->iLastStart, $iRemaining);
$aThresholdData['deadline'] = $this->ComputeDeadline($oObject, $oAttDef, $iPercent, $this->iLastStart, $iThresholdDuration - $this->iTimeSpent);
// OR $aThresholdData['deadline'] = $this->ComputeDeadline($oObject, $oAttDef, $iPercent, $this->iStarted, $iThresholdDuration);
if (class_exists('WorkingTimeRecorder'))
@@ -429,7 +398,7 @@ class ormStopWatch
$aThresholdData['triggered'] = false;
$aThresholdData['overrun'] = null;
}
// else
else
{
// The new threshold is in the past
// Note: the overrun can be wrong, but the correct algorithm to compute
@@ -485,10 +454,7 @@ class ormStopWatch
$aThresholdData['overrun'] = $iOverrun;
}
}
if ($aThresholdData['overrun'] == 0)
{
$aThresholdData['deadline'] = null;
}
$aThresholdData['deadline'] = null;
}
$this->iLastStart = null;
@@ -592,7 +558,7 @@ class CheckStopWatchThresholds implements iBackgroundProcess
CMDBObject::SetTrackInfo("Automatic - threshold triggered");
$oMyChange = CMDBObject::GetCurrentChange();
$oObj->DBUpdateTracked($oMyChange);
$oObj->DBUpdateTracked($oMyChange, true /*skip security*/);
}
// Activate any existing trigger

View File

@@ -1,482 +0,0 @@
<?php
/**
* Copyright (c) 2010-2018 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*
*/
/**
* Created by PhpStorm.
* Date: 24/08/2018
* Time: 14:35
*/
final class ormTagSet extends ormSet
{
/**
* ormTagSet constructor.
*
* @param string $sClass
* @param string $sAttCode
* @param int $iLimit
*
* @throws \Exception
*/
public function __construct($sClass, $sAttCode, $iLimit = 12)
{
parent::__construct($sClass, $sAttCode, $iLimit);
}
/**
*
* @param array $aTagCodes
*
* @throws \CoreException
* @throws \CoreUnexpectedValue when a code is invalid
*/
public function SetValues($aTagCodes)
{
if (is_null($aTagCodes))
{
$aTagCodes = array();
}
if (!is_array($aTagCodes))
{
throw new CoreUnexpectedValue("Wrong value {$aTagCodes} for {$this->sClass}:{$this->sAttCode}");
}
$oTags = array();
$iCount = 0;
$bError = false;
foreach($aTagCodes as $sTagCode)
{
$iCount++;
if (($this->iLimit != 0) && ($iCount > $this->iLimit))
{
$bError = true;
continue;
}
$oTag = $this->GetTagFromCode($sTagCode);
$oTags[$sTagCode] = $oTag;
}
$this->aPreserved = &$oTags;
$this->aRemoved = array();
$this->aAdded = array();
$this->aModified = array();
$this->aOriginalObjects = $oTags;
if ($bError)
{
throw new CoreException("Maximum number of tags ({$this->iLimit}) reached for {$this->sClass}:{$this->sAttCode}");
}
}
/**
* @return array of tag codes
*/
public function GetValues()
{
$aValues = array();
foreach($this->aPreserved as $sTagCode => $oTag)
{
$aValues[] = $sTagCode;
}
foreach($this->aAdded as $sTagCode => $oTag)
{
$aValues[] = $sTagCode;
}
sort($aValues);
return $aValues;
}
/**
* @return array of tag labels indexed by code
*/
public function GetLabels()
{
$aTags = array();
/** @var \TagSetFieldData $oTag */
foreach($this->aPreserved as $sTagCode => $oTag)
{
try
{
$aTags[$sTagCode] = $oTag->Get('label');
} catch (CoreException $e)
{
IssueLog::Error($e->getMessage());
}
}
foreach($this->aAdded as $sTagCode => $oTag)
{
try
{
$aTags[$sTagCode] = $oTag->Get('label');
} catch (CoreException $e)
{
IssueLog::Error($e->getMessage());
}
}
ksort($aTags);
return $aTags;
}
/**
* @return array of tags indexed by code
*/
public function GetTags()
{
$aTags = array();
foreach($this->aPreserved as $sTagCode => $oTag)
{
$aTags[$sTagCode] = $oTag;
}
foreach($this->aAdded as $sTagCode => $oTag)
{
$aTags[$sTagCode] = $oTag;
}
ksort($aTags);
return $aTags;
}
/**
* @return array of tag labels indexed by code for only the added tags
*/
private function GetAddedCodes()
{
$aTags = array();
foreach($this->aAdded as $sTagCode => $oTag)
{
$aTags[] = $sTagCode;
}
ksort($aTags);
return $aTags;
}
/**
* @return array of tag labels indexed by code for only the removed tags
*/
private function GetRemovedCodes()
{
$aTags = array();
foreach($this->aRemoved as $sTagCode => $oTag)
{
$aTags[] = $sTagCode;
}
ksort($aTags);
return $aTags;
}
/**
* @return array of tag labels indexed by code for only the added tags
*/
private function GetAddedTags()
{
$aTags = array();
foreach($this->aAdded as $sTagCode => $oTag)
{
$aTags[$sTagCode] = $oTag;
}
ksort($aTags);
return $aTags;
}
/**
* @return array of tag labels indexed by code for only the removed tags
*/
private function GetRemovedTags()
{
$aTags = array();
foreach($this->aRemoved as $sTagCode => $oTag)
{
$aTags[$sTagCode] = $oTag;
}
ksort($aTags);
return $aTags;
}
/** Get the delta with another TagSet
*
* $aDelta['added] = array of tag codes for only the added tags
* $aDelta['removed'] = array of tag codes for only the removed tags
*
* @param \ormTagSet $oOtherTagSet
*
* @return array
*
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \Exception
*/
public function GetDelta(ormSet $oOtherTagSet)
{
$oTag = new ormTagSet($this->sClass, $this->sAttCode, 0);
// Set the initial value
$aOrigTagCodes = $this->GetValues();
$oTag->SetValues($aOrigTagCodes);
// now remove everything
foreach($aOrigTagCodes as $sTagCode)
{
$oTag->Remove($sTagCode);
}
// now add the tags of the other TagSet
foreach($oOtherTagSet->GetValues() as $sTagCode)
{
$oTag->Add($sTagCode);
}
$aDelta = array();
$aDelta['added'] = $oTag->GetAddedCodes();
$aDelta['removed'] = $oTag->GetRemovedCodes();
return $aDelta;
}
/** Get the delta with another TagSet
*
* $aDelta['added] = array of tag labels indexed by code for only the added tags
* $aDelta['removed'] = array of tag labels indexed by code for only the removed tags
*
* @param \ormTagSet $oOtherTagSet
*
* @return array
*
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \Exception
*/
public function GetDeltaTags(ormTagSet $oOtherTagSet)
{
$oTag = new ormTagSet($this->sClass, $this->sAttCode, 0);
// Set the initial value
$aOrigTagCodes = $this->GetValues();
$oTag->SetValues($aOrigTagCodes);
// now remove everything
foreach($aOrigTagCodes as $sTagCode)
{
$oTag->Remove($sTagCode);
}
// now add the tags of the other TagSet
foreach($oOtherTagSet->GetValues() as $sTagCode)
{
$oTag->Add($sTagCode);
}
$aDelta = array();
$aDelta['added'] = $oTag->GetAddedTags();
$aDelta['removed'] = $oTag->GetRemovedTags();
return $aDelta;
}
/**
* @return string[] list of codes for partial entries
*/
public function GetModified()
{
$aModifiedTagCodes = array_keys($this->aModified);
sort($aModifiedTagCodes);
return $aModifiedTagCodes;
}
/**
* Check whether a tag code is valid or not for this TagSet
*
* @param string $sTagCode
*
* @return bool
*/
public function IsValidTag($sTagCode)
{
try
{
$this->GetTagFromCode($sTagCode);
return true;
} catch (Exception $e)
{
return false;
}
}
/**
* @param string $sTagCode
*
* @throws \CoreException
* @throws \CoreUnexpectedValue
*/
public function Add($sTagCode)
{
if (($this->iLimit != 0) && ($this->Count() == $this->iLimit))
{
throw new CoreException("Maximum number of tags ({$this->iLimit}) reached for {$this->sClass}:{$this->sAttCode}");
}
if ($this->IsTagInList($this->aPreserved, $sTagCode) || $this->IsTagInList($this->aAdded, $sTagCode))
{
// nothing to do, already existing tag
return;
}
// if removed then added again
if (($oTag = $this->RemoveTagFromList($this->aRemoved, $sTagCode)) !== false)
{
// put it back into preserved
$this->aPreserved[$sTagCode] = $oTag;
// no need to add it to aModified : was already done when calling Remove method
}
else
{
$oTag = $this->GetTagFromCode($sTagCode);
$this->aAdded[$sTagCode] = $oTag;
$this->aModified[$sTagCode] = $oTag;
}
}
/**
* @param $sTagCode
*/
public function Remove($sTagCode)
{
if ($this->IsTagInList($this->aRemoved, $sTagCode))
{
// nothing to do, already removed tag
return;
}
$oTag = $this->RemoveTagFromList($this->aAdded, $sTagCode);
if ($oTag !== false)
{
$this->aModified[$sTagCode] = $oTag;
return; // if present in added, can't be in preserved !
}
$oTag = $this->RemoveTagFromList($this->aPreserved, $sTagCode);
if ($oTag !== false)
{
$this->aModified[$sTagCode] = $oTag;
$this->aRemoved[$sTagCode] = $oTag;
}
}
private function IsTagInList($aTagList, $sTagCode)
{
return isset($aTagList[$sTagCode]);
}
/**
* @param \DBObject[] $aTagList
* @param string $sTagCode
*
* @return bool|\DBObject false if not found, else the removed element
*/
private function RemoveTagFromList(&$aTagList, $sTagCode)
{
if (!($this->IsTagInList($aTagList, $sTagCode)))
{
return false;
}
$oTag = $aTagList[$sTagCode];
unset($aTagList[$sTagCode]);
return $oTag;
}
/**
* @param $sTagCode
*
* @return DBObject tag
* @throws \CoreUnexpectedValue
* @throws \CoreException
*/
private function GetTagFromCode($sTagCode)
{
$aAllowedTags = $this->GetAllowedTags();
foreach($aAllowedTags as $oAllowedTag)
{
if ($oAllowedTag->Get('code') === $sTagCode)
{
return $oAllowedTag;
}
}
throw new CoreUnexpectedValue("{$sTagCode} is not defined as a valid tag for {$this->sClass}:{$this->sAttCode}");
}
/**
* @param $sTagCode
*
* @return DBObject tag
* @throws \CoreUnexpectedValue
* @throws \CoreException
*/
public function GetTagFromLabel($sTagLabel)
{
$aAllowedTags = $this->GetAllowedTags();
foreach($aAllowedTags as $oAllowedTag)
{
if ($oAllowedTag->Get('label') === $sTagLabel)
{
return $oAllowedTag->Get('code');
}
}
throw new CoreUnexpectedValue("{$sTagLabel} is not defined as a valid tag for {$this->sClass}:{$this->sAttCode}");
}
/**
* @return \TagSetFieldData[]
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
private function GetAllowedTags()
{
return TagSetFieldData::GetAllowedValues($this->sClass, $this->sAttCode);
}
/**
* Compare Tag Set
*
* @param \ormTagSet $other
*
* @return bool true if same tag set
*/
public function Equals(ormSet $other)
{
if (!($other instanceof ormTagSet))
{
return false;
}
if ($this->GetTagDataClass() !== $other->GetTagDataClass())
{
return false;
}
return implode(' ', $this->GetValues()) === implode(' ', $other->GetValues());
}
public function GetTagDataClass()
{
return TagSetFieldData::GetTagDataClassName($this->sClass, $this->sAttCode);
}
}

View File

@@ -257,13 +257,14 @@ class CoreServices implements iRestServiceProvider
*/
public function ListOperations($sVersion)
{
// 1.4 - iTop 2.5.2, 2.6.1, 2.7.0, Verb 'core/get': added pagination parameters limit and page
// 1.3 - iTop 2.2.0, Verb 'get_related': added the options 'redundancy' and 'direction' to take into account the redundancy in the impact analysis
// 1.2 - was documented in the wiki but never released ! Same as 1.3
// 1.1 - In the reply, objects have a 'key' entry so that it is no more necessary to split class::key programmaticaly
// 1.0 - Initial implementation in iTop 2.0.1
//
$aOps = array();
if (in_array($sVersion, array('1.0', '1.1', '1.2', '1.3')))
if (in_array($sVersion, array('1.0', '1.1', '1.2', '1.3', '1.4')))
{
$aOps[] = array(
'verb' => 'core/create',
@@ -299,9 +300,16 @@ class CoreServices implements iRestServiceProvider
/**
* Enumerate services delivered by this class
*
* @param string $sVersion The version (e.g. 1.0) supported by the services
* @param string $sVerb
* @param $aParams
*
* @return RestResult The standardized result structure (at least a message)
* @throws Exception in case of internal failure.
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \SimpleGraphException
* @throws \Exception
*/
public function ExecOperation($sVersion, $sVerb, $aParams)
{
@@ -436,8 +444,10 @@ class CoreServices implements iRestServiceProvider
$key = RestUtils::GetMandatoryParam($aParams, 'key');
$aShowFields = RestUtils::GetFieldList($sClass, $aParams, 'output_fields');
$bExtendedOutput = (RestUtils::GetOptionalParam($aParams, 'output_fields', '*') == '*+');
$iLimit = (int)RestUtils::GetOptionalParam($aParams, 'limit', 0);
$iPage = (int)RestUtils::GetOptionalParam($aParams, 'page', 1);
$oObjectSet = RestUtils::GetObjectSetFromKey($sClass, $key);
$oObjectSet = RestUtils::GetObjectSetFromKey($sClass, $key, $iLimit, self::getOffsetFromLimitAndPage($iLimit, $iPage));
$sTargetClass = $oObjectSet->GetFilter()->GetClass();
if (UserRights::IsActionAllowed($sTargetClass, UR_ACTION_READ) != UR_ALLOWED_YES)
@@ -450,6 +460,11 @@ class CoreServices implements iRestServiceProvider
$oResult->code = RestResult::UNAUTHORIZED;
$oResult->message = "The current user does not have enough permissions for exporting data of class $sTargetClass";
}
elseif ($iPage < 1)
{
$oResult->code = RestResult::INVALID_PAGE;
$oResult->message = "The request page number is not valid. It must be an integer greater than 0";
}
else
{
while ($oObject = $oObjectSet->Fetch())
@@ -774,4 +789,15 @@ class CoreServices implements iRestServiceProvider
$oResult->message = $sRes;
}
}
/**
* @param int $iLimit
* @param int $iPage
*
* @return int Offset for a given page number
*/
protected static function getOffsetFromLimitAndPage($iLimit, $iPage)
{
return $iLimit * max(0, $iPage - 1);
}
}

View File

@@ -43,61 +43,17 @@
class SimpleCrypt
{
public static function GetNewDefaultParams()
{
if(function_exists('sodium_crypto_secretbox_open') && function_exists('random_bytes')){
$sEngineName = 'Sodium';
}
else if (function_exists('openssl_decrypt'))
{
$sEngineName = 'OpenSSL';
}
else if(function_exists('mcrypt_module_open')){
$sEngineName = 'Mcrypt';
}
else
{
$sEngineName = 'Simple';
}
$sEngineName = 'SimpleCrypt' . $sEngineName . 'Engine';
return $sEngineName::GetNewDefaultParams();
}
/**
* Constructor
* @param string $sEngineName Engine for encryption. Values: Simple, Mcrypt, Sodium or OpenSSL
* @throws Exception This library is unkown
* @param string $sEngineName Engine for encryption. Values: Simple, Mcrypt
*/
function __construct($sEngineName = 'Mcrypt')
{
switch($sEngineName){
case 'Sodium':
if(!function_exists('sodium_crypto_secretbox_open')){
$sEngineName = 'Simple';
}
break;
case 'Mcrypt':
if(!function_exists('mcrypt_module_open')){
if (function_exists('openssl_decrypt'))
{
$sEngineName = 'OpenSSLMcryptCompatibility';
}
else
{
$sEngineName = 'Simple';
}
}
break;
case 'OpenSSL':
if(!function_exists('openssl_decrypt')){
$sEngineName = 'Simple';
}
break;
case 'Simple':
break;
default:
throw new Exception(Dict::Format("Core:AttributeEncryptUnknownLibrary", $sEngineName));
}
if (($sEngineName == 'Mcrypt') && (!function_exists('mcrypt_module_open')))
{
// Defaults to Simple encryption if the mcrypt module is not present
$sEngineName = 'Simple';
}
$sEngineName = 'SimpleCrypt' . $sEngineName . 'Engine';
$this->oEngine = new $sEngineName;
}
@@ -194,7 +150,6 @@ class SimpleCrypt
*/
interface CryptEngine
{
public static function GetNewDefaultParams();
function Encrypt($key, $sString);
function Decrypt($key, $encrypted_data);
}
@@ -206,12 +161,7 @@ interface CryptEngine
*/
class SimpleCryptSimpleEngine implements CryptEngine
{
public static function GetNewDefaultParams()
{
return array( 'lib' => 'Simple', 'key' => null);
}
public function Encrypt($key, $sString)
public function Encrypt($key, $sString)
{
$result = '';
for($i=1; $i<=strlen($sString); $i++)
@@ -247,13 +197,7 @@ class SimpleCryptMcryptEngine implements CryptEngine
{
var $alg = MCRYPT_BLOWFISH;
var $td = null;
public static function GetNewDefaultParams()
{
return array('lib' => 'Mcrypt', 'key' => null);
}
public function __construct()
{
$this->td = mcrypt_module_open($this->alg,'','cbc','');
@@ -261,7 +205,7 @@ class SimpleCryptMcryptEngine implements CryptEngine
public function Encrypt($key, $sString)
{
$iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($this->td), MCRYPT_RAND_URANDOM); // MCRYPT_RAND_URANDOM is now useable since itop requires php >= 5.6
$iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($this->td), MCRYPT_RAND); // MCRYPT_RAND is the only choice on Windows prior to PHP 5.3
mcrypt_generic_init($this->td, $key, $iv);
if (empty($sString))
{
@@ -279,7 +223,7 @@ class SimpleCryptMcryptEngine implements CryptEngine
$r = mcrypt_generic_init($this->td, $key, $iv);
if (($r < 0) || ($r === false))
{
$decrypted_data = Dict::S("Core:AttributeEncryptFailedToDecrypt");
$decrypted_data = '** decryption error **';
}
else
{
@@ -294,121 +238,4 @@ class SimpleCryptMcryptEngine implements CryptEngine
mcrypt_module_close($this->td);
}
}
/**
* SodiumEngine requires Sodium extension
* Every encryption of the same string with the same key
* will return a different encrypted string.
* The key has to be SODIUM_CRYPTO_SECRETBOX_KEYBYTES bytes long.
*/
class SimpleCryptSodiumEngine implements CryptEngine
{
public static function GetNewDefaultParams()
{
return array('lib' => 'Sodium', 'key' => bin2hex(sodium_crypto_secretbox_keygen()));
}
public function Encrypt($key, $sString)
{
$key = hex2bin($key);
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$encrypted_string = sodium_crypto_secretbox($sString, $nonce, $key);
sodium_memzero($sString);
sodium_memzero($key);
return base64_encode($nonce.$encrypted_string);
}
public function Decrypt($key, $encrypted_data)
{
$key = hex2bin($key);
$encrypted_data = base64_decode($encrypted_data);
$nonce = mb_substr($encrypted_data, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
$encrypted_data = mb_substr($encrypted_data, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
$plaintext = sodium_crypto_secretbox_open($encrypted_data, $nonce, $key);
if ($plaintext === false)
{
$plaintext = Dict::S("Core:AttributeEncryptFailedToDecrypt");
}
sodium_memzero($encrypted_data);
sodium_memzero($key);
return $plaintext;
}
}
class SimpleCryptOpenSSLEngine implements CryptEngine
{
public static function GetNewDefaultParams()
{
return array('lib' => 'OpenSSL', 'key' => bin2hex(openssl_random_pseudo_bytes(32)));
}
public function Encrypt($key, $sString)
{
$key = hex2bin($key);
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length("AES-256-CBC"));
$encrypted_string = openssl_encrypt($sString, "AES-256-CBC", $key, 0 , $iv);
return $iv.$encrypted_string;
}
public function Decrypt($key, $encrypted_data)
{
$key = hex2bin($key);
$iv = mb_substr($encrypted_data, 0, openssl_cipher_iv_length("AES-256-CBC"), '8bit');
$encrypted_data = mb_substr($encrypted_data, openssl_cipher_iv_length("AES-256-CBC"), null, '8bit');
$plaintext = openssl_decrypt($encrypted_data,"AES-256-CBC", $key, 0 , $iv);
if ($plaintext === false)
{
$plaintext = Dict::S("Core:AttributeEncryptFailedToDecrypt");
}
return trim($plaintext);
}
}
class SimpleCryptOpenSSLMcryptCompatibilityEngine implements CryptEngine
{
public static function GetNewDefaultParams()
{
return array('lib' => 'OpenSSLMcryptCompatibility', 'key' => null);
}
//fix for php < 7.1.8 (keys are Zero padded instead of cycle padded)
static private function MakeOpenSSLBlowfishKey($key)
{
if("$key" === '')
{
return $key;
}
$len = (16+2)*4;
while(strlen($key) < $len)
{
$key .= $key;
}
$key = substr($key, 0, $len);
return $key;
}
public function Encrypt($key, $sString)
{
$key = SimpleCryptOpenSSLMcryptCompatibilityEngine::MakeOpenSSLBlowfishKey($key);
$blockSize = 8;
$len = strlen($sString);
$paddingLen = intval (($len + $blockSize -1) / $blockSize) * $blockSize - $len;
$padding = str_repeat("\0", $paddingLen);
$sData = $sString . $padding;
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length("BF-CBC"));
$encrypted_string = openssl_encrypt($sData, "BF-CBC", $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
return $iv.$encrypted_string;
}
public function Decrypt($key, $encrypted_data)
{
$key = SimpleCryptOpenSSLMcryptCompatibilityEngine::MakeOpenSSLBlowfishKey($key);
$iv = mb_substr($encrypted_data, 0, openssl_cipher_iv_length("BF-CBC"), '8bit');
$encrypted_data = mb_substr($encrypted_data, openssl_cipher_iv_length("BF-CBC"), null, '8bit');
$plaintext = openssl_decrypt($encrypted_data,"BF-CBC", $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
if ($plaintext === false)
{
$plaintext = Dict::S("Core:AttributeEncryptFailedToDecrypt");
}
return trim($plaintext);
}
}
?>

View File

@@ -275,7 +275,6 @@ EOF
$sAttCode = $aFieldSpec['sAttCode'];
$sField = '';
/** @var \DBObject $oObj */
$oObj = $aRow[$sAlias];
if ($oObj == null)
{
@@ -333,16 +332,11 @@ EOF
$sField = utils::TextToHtml($oObj->GetEditValue($sAttCode));
$sData .= "<td x:str>$sField</td>";
}
else if ($oAttDef instanceof AttributeString)
else if($oAttDef instanceof AttributeString)
{
$sField = $oObj->GetAsHTML($sAttCode, $this->bLocalizeOutput);
$sData .= "<td x:str>$sField</td>";
}
else if ($oAttDef instanceof AttributeTagSet)
{
$sField = $oObj->GetAsCSV($sAttCode, $this->bLocalizeOutput, '');
$sData .= "<td x:str>$sField</td>";
}
else
{
$rawValue = $oObj->Get($sAttCode);

View File

@@ -95,7 +95,7 @@ class SQLObjectQuery extends SQLQuery
$aFieldDesc = array();
foreach ($this->m_aFields as $sAlias => $oExpression)
{
$aFieldDesc[] = $oExpression->RenderExpression(false)." as <em>$sAlias</em>";
$aFieldDesc[] = $oExpression->Render()." as <em>$sAlias</em>";
}
$sFields = " =&gt; ".implode(', ', $aFieldDesc);
}
@@ -112,7 +112,7 @@ class SQLObjectQuery extends SQLQuery
$oSQLQuery = $aJoinInfo["select"];
if (isset($aJoinInfo["on_expression"]))
{
$sOnCondition = $aJoinInfo["on_expression"]->RenderExpression(false);
$sOnCondition = $aJoinInfo["on_expression"]->Render();
echo "<li>Join '$sJoinType', ON ($sOnCondition)".$oSQLQuery->DisplayHtml()."</li>\n";
}
@@ -339,12 +339,8 @@ class SQLObjectQuery extends SQLQuery
$this->PrepareRendering();
$sFrom = self::ClauseFrom($this->__aFrom, $sIndent);
$sWhere = self::ClauseWhere($this->m_oConditionExpr, $aArgs);
// Sanity
$iLimitCount = (int)$iLimitCount;
if ($iLimitCount > 0)
{
// Sanity
$iLimitStart = (int)$iLimitStart;
$sLimit = 'LIMIT '.$iLimitStart.', '.$iLimitCount;
}
else
@@ -468,7 +464,7 @@ class SQLObjectQuery extends SQLQuery
case "left":
if (isset($aJoinData["on_expression"]))
{
$sJoinCond = $aJoinData["on_expression"]->RenderExpression(true);
$sJoinCond = $aJoinData["on_expression"]->Render();
}
else
{
@@ -535,13 +531,13 @@ class SQLObjectQuery extends SQLQuery
//
foreach($this->m_aFields as $sAlias => $oExpression)
{
$oRootQuery->__aFields["`$sAlias`"] = $oExpression->RenderExpression(true);
$oRootQuery->__aFields["`$sAlias`"] = $oExpression->Render();
}
if ($this->m_aGroupBy)
{
foreach($this->m_aGroupBy as $sAlias => $oExpression)
{
$oRootQuery->__aGroupBy["`$sAlias`"] = $oExpression->RenderExpression(true);
$oRootQuery->__aGroupBy["`$sAlias`"] = $oExpression->Render();
}
}
if ($this->m_bToDelete)
@@ -555,7 +551,7 @@ class SQLObjectQuery extends SQLQuery
if (!is_null($this->m_oSelectedIdField))
{
$oRootQuery->__aSelectedIdFields[] = $this->m_oSelectedIdField->RenderExpression(true);
$oRootQuery->__aSelectedIdFields[] = $this->m_oSelectedIdField->Render();
}
// loop on joins, to complete the list of tables/fields/conditions

View File

@@ -177,7 +177,7 @@ abstract class SQLQuery
}
else
{
return $oConditionExpr->RenderExpression(true, $aArgs);
return $oConditionExpr->Render($aArgs);
}
}

View File

@@ -168,7 +168,7 @@ class SQLUnionQuery extends SQLQuery
}
foreach($this->aSelectExpr as $sSelectAlias => $oExpr)
{
$aSelectAliases[$sSelectAlias] = $oExpr->RenderExpression(true)." AS `$sSelectAlias`";
$aSelectAliases[$sSelectAlias] = $oExpr->Render()." AS `$sSelectAlias`";
}
$sSelect = implode(",$sLineSep ", $aSelectAliases);

View File

@@ -150,18 +150,15 @@ abstract class TabularBulkExport extends BulkExport
// Add the reconciliation keys
foreach(MetaModel::GetReconcKeys($sRemoteClass) as $sRemoteAttCode)
{
if (!empty($sRemoteAttCode))
{
$sAttCodeEx = $sAttCode.'->'.$sRemoteAttCode;
if (!array_key_exists($sAttCodeEx, $aResult))
{
$oRemoteAttDef = MetaModel::GetAttributeDef($sRemoteClass, $sRemoteAttCode);
if ($this->IsExportableField($sRemoteClass, $sRemoteAttCode, $oRemoteAttDef))
{
$aResult[$sAttCodeEx] = array('code' => $sAttCodeEx, 'unique_label' => $oAttDef->GetLabel().'->'.$oRemoteAttDef->GetLabel(), 'label' => MetaModel::GetLabel($sRemoteClass, $sRemoteAttCode), 'attdef' => $oRemoteAttDef);
}
}
}
$sAttCodeEx = $sAttCode.'->'.$sRemoteAttCode;
if (!array_key_exists($sAttCodeEx, $aResult))
{
$oRemoteAttDef = MetaModel::GetAttributeDef($sRemoteClass, $sRemoteAttCode);
if ($this->IsExportableField($sRemoteClass, $sRemoteAttCode, $oRemoteAttDef))
{
$aResult[$sAttCodeEx] = array('code' => $sAttCodeEx, 'unique_label' => $oAttDef->GetLabel().'->'.$oRemoteAttDef->GetLabel(), 'label' => MetaModel::GetLabel($sRemoteClass, $sRemoteAttCode), 'attdef' => $oRemoteAttDef);
}
}
}
break;

View File

@@ -1,394 +0,0 @@
<?php
// Copyright (C) 2018 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* <p>Stores data for {@link AttributeTagSet} fields
*
* <p>We will have an implementation for each class/field to be able to customize rights (generated in
* \MFCompiler::CompileClass).<br> Only this abstract class will exists in the DB : the implementations won't had any
* new field.
*
* @since 2.6 N°931 tag fields
*/
abstract class TagSetFieldData extends cmdbAbstractObject
{
private static $m_aAllowedValues = array();
/**
* @throws \CoreException
* @throws \Exception
*/
public static function Init()
{
$aParams = array
(
'category' => 'bizmodel',
'key_type' => 'autoincrement',
'name_attcode' => array('label'),
'state_attcode' => '',
'reconc_keys' => array('code'),
'db_table' => 'priv_tagfielddata',
'db_key_field' => 'id',
'db_finalclass_field' => 'finalclass',
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("code", array(
"allowed_values" => null,
"sql" => 'code',
"default_value" => '',
"is_null_allowed" => false,
"depends_on" => array(),
"validation_pattern" => '^[a-zA-Z][a-zA-Z0-9]{3,}$',
)));
MetaModel::Init_AddAttribute(new AttributeString("label", array(
"allowed_values" => null,
"sql" => 'label',
"default_value" => '',
"is_null_allowed" => false,
"depends_on" => array()
)));
MetaModel::Init_AddAttribute(new AttributeHTML("description", array(
"allowed_values" => null,
"sql" => 'description',
"default_value" => '',
"is_null_allowed" => true,
"depends_on" => array()
)));
MetaModel::Init_AddAttribute(new AttributeString("obj_class", array(
"allowed_values" => null,
"sql" => 'obj_class',
"default_value" => '',
"is_null_allowed" => false,
"depends_on" => array()
)));
MetaModel::Init_AddAttribute(new AttributeString("obj_attcode", array(
"allowed_values" => null,
"sql" => 'obj_attcode',
"default_value" => '',
"is_null_allowed" => false,
"depends_on" => array()
)));
MetaModel::Init_SetZListItems('details', array('code', 'label', 'description'));
MetaModel::Init_SetZListItems('standard_search', array('code', 'label', 'description'));
MetaModel::Init_SetZListItems('list', array('code', 'label', 'description'));
}
public function ComputeValues()
{
$sClassName = get_class($this);
$aRes = static::ExtractTagFieldName($sClassName);
$this->_Set('obj_class', $aRes['obj_class']);
$this->_Set('obj_attcode', $aRes['obj_attcode']);
}
public static function GetTagDataClassName($sClass, $sAttCode)
{
$sTagSuffix = $sClass.'__'.$sAttCode;
return 'TagSetFieldDataFor_'.$sTagSuffix;
}
/**
* Extract Tag class and attcode from the TagFieldData class name
*
* @param $sClassName
*
* @return string[]
* @throws \CoreException
*/
public static function ExtractTagFieldName($sClassName)
{
$aRes = array();
// Extract class and attcode from class name using pattern TagSetFieldDataFor_<class>_<attcode>>;
if (preg_match('@^TagSetFieldDataFor_(?<class>\w+)__(?<attcode>\w+)$@', $sClassName, $aMatches))
{
$aRes['obj_class'] = $aMatches['class'];
$aRes['obj_attcode'] = $aMatches['attcode'];
}
else
{
throw new CoreException("Bad Class name format: $sClassName");
}
return $aRes;
}
/**
* @param \DeletionPlan $oDeletionPlan
*
* @throws \CoreException
*/
public function DoCheckToDelete(&$oDeletionPlan)
{
parent::DoCheckToDelete($oDeletionPlan);
$sTagCode = $this->Get('code');
if ($this->IsCodeUsed($sTagCode))
{
$this->m_aDeleteIssues[] = Dict::S('Core:TagSetFieldData:ErrorDeleteUsedTag');
}
// Clear cache
$sClass = $this->Get('obj_class');
$sAttCode = $this->Get('obj_attcode');
$sTagDataClass = self::GetTagDataClassName($sClass, $sAttCode);
unset(self::$m_aAllowedValues[$sTagDataClass]);
}
/**
* @throws \CoreException
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
* @throws \Exception
*/
public function DoCheckToWrite()
{
$this->ComputeValues();
$sClass = $this->Get('obj_class');
$sAttCode = $this->Get('obj_attcode');
$iMaxLen = 20;
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef instanceof AttributeTagSet)
{
$iMaxLen = $oAttDef->GetTagCodeMaxLength();
}
$sTagCode = $this->Get('code');
// Check code syntax
$iMax = $iMaxLen - 1;
if (!preg_match("@^[a-zA-Z][a-zA-Z0-9]{2,$iMax}$@", $sTagCode))
{
$this->m_aCheckIssues[] = Dict::Format('Core:TagSetFieldData:ErrorTagCodeSyntax', $iMaxLen);
}
// Check that the code is not a MySQL stop word
$sSQL = "SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DEFAULT_STOPWORD";
try
{
$aResults = CMDBSource::QueryToArray($sSQL);
} catch (MySQLException $e)
{
IssueLog::Warning($e->getMessage());
$aResults = array();
}
foreach($aResults as $aResult)
{
if ($aResult['value'] == $sTagCode)
{
$this->m_aCheckIssues[] = Dict::S('Core:TagSetFieldData:ErrorTagCodeReservedWord');
break;
}
}
$sTagLabel = $this->Get('label');
$sSepItem = MetaModel::GetConfig()->Get('tag_set_item_separator');
if (empty($sTagLabel) || (strpos($sTagLabel, $sSepItem) !== false))
{
// Label must not contain | character
$this->m_aCheckIssues[] = Dict::Format('Core:TagSetFieldData:ErrorTagLabelSyntax', $sSepItem);
}
// Check that code and labels are uniques
$id = $this->GetKey();
$sClassName = get_class($this);
if (empty($id))
{
$oSearch = DBSearch::FromOQL("SELECT $sClassName WHERE (code = :tag_code OR label = :tag_label)");
}
else
{
$oSearch = DBSearch::FromOQL("SELECT $sClassName WHERE id != :id AND (code = :tag_code OR label = :tag_label)");
}
$aArgs = array('id' => $id, 'tag_code' => $sTagCode, 'tag_label' => $sTagLabel);
$oSet = new DBObjectSet($oSearch, array(), $aArgs);
if ($oSet->CountExceeds(0))
{
$this->m_aCheckIssues[] = Dict::S('Core:TagSetFieldData:ErrorDuplicateTagCodeOrLabel');
}
// Clear cache
$sTagDataClass = self::GetTagDataClassName($sClass, $sAttCode);
unset(self::$m_aAllowedValues[$sTagDataClass]);
parent::DoCheckToWrite();
}
/**
* @throws \CoreException
*/
public function OnUpdate()
{
parent::OnUpdate();
$aChanges = $this->ListChanges();
if (array_key_exists('code', $aChanges))
{
$sTagCode = $this->GetOriginal('code');
if ($this->IsCodeUsed($sTagCode))
{
throw new CoreException(Dict::S('Core:TagSetFieldData:ErrorCodeUpdateNotAllowed'));
}
}
if (array_key_exists('obj_class', $aChanges))
{
throw new CoreException(Dict::S('Core:TagSetFieldData:ErrorClassUpdateNotAllowed'));
}
if (array_key_exists('obj_attcode', $aChanges))
{
throw new CoreException(Dict::S('Core:TagSetFieldData:ErrorAttCodeUpdateNotAllowed'));
}
}
private function IsCodeUsed($sTagCode)
{
try
{
$sClass = $this->Get('obj_class');
$sAttCode = $this->Get('obj_attcode');
$oSearch = DBSearch::FromOQL("SELECT $sClass WHERE $sAttCode MATCHES '$sTagCode'");
$oSet = new DBObjectSet($oSearch);
if ($oSet->CountExceeds(0))
{
return true;
}
}
catch (Exception $e)
{
IssueLog::Warning($e->getMessage());
}
return false;
}
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
{
if ($sAttCode == 'code')
{
if ((!$this->IsNew()) && ($this->IsCodeUsed($this->Get('code'))))
{
return OPT_ATT_READONLY;
}
}
return parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
}
/**
* Display Tag Usage
*
* @param \WebPage $oPage
* @param bool $bEditMode
*
* @throws \CoreException
* @throws \DictExceptionMissingString
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
*/
function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
{
parent::DisplayBareRelations($oPage, $bEditMode);
if (!$bEditMode)
{
$sClass = $this->Get('obj_class');
$sAttCode = $this->Get('obj_attcode');
$sTagCode = $this->Get('code');
$oFilter = DBSearch::FromOQL("SELECT $sClass WHERE $sAttCode MATCHES '$sTagCode'");
$oSet = new DBObjectSet($oFilter);
$iCount = $oSet->Count();
$oPage->SetCurrentTab(Dict::Format('Core:TagSetFieldData:WhereIsThisTagTab', $iCount));
if ($iCount === 0)
{
$sNoEntries = Dict::S('Core:TagSetFieldData:NoEntryFound');
$oPage->add("<p>$sNoEntries</p>");
return;
}
$oFilter = DBSearch::FromOQL("SELECT $sClass WHERE $sAttCode MATCHES '$sTagCode'");
$oSet = new DBObjectSet($oFilter);
if ($oSet->CountExceeds(0))
{
$sClassLabel = MetaModel::GetName($sClass);
$oPage->add("<h2>$sClassLabel</h2>");
$oResultBlock = new DisplayBlock($oFilter, 'list', false);
$oResultBlock->Display($oPage, 1);
}
}
}
public static function GetClassName($sClass)
{
if ($sClass == 'TagSetFieldData')
{
$aWords = preg_split('/(?=[A-Z]+)/', $sClass);
return trim(implode(' ', $aWords));
}
try
{
$aTagFieldInfo = self::ExtractTagFieldName($sClass);
} catch (CoreException $e)
{
return $sClass;
}
$sClassDesc = MetaModel::GetName($aTagFieldInfo['obj_class']);
$sAttDesc = MetaModel::GetAttributeDef($aTagFieldInfo['obj_class'], $aTagFieldInfo['obj_attcode'])->GetLabel();
if (Dict::Exists("Class:$sClass"))
{
$sName = Dict::Format("Class:$sClass", $sClassDesc, $sAttDesc);
}
else
{
$sName = Dict::Format('Class:TagSetFieldData', $sClassDesc, $sAttDesc);
}
return $sName;
}
/**
* @param $sClass
* @param $sAttCode
*
* @return \TagSetFieldData[]
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
public static function GetAllowedValues($sClass, $sAttCode)
{
$sClass = MetaModel::GetAttributeOrigin($sClass, $sAttCode);
$sTagDataClass = self::GetTagDataClassName($sClass, $sAttCode);
if (!isset(self::$m_aAllowedValues[$sTagDataClass]))
{
$oSearch = new DBObjectSearch($sTagDataClass);
$oSearch->AddCondition('obj_class', $sClass);
$oSearch->AddCondition('obj_attcode', $sAttCode);
$oSet = new DBObjectSet($oSearch);
self::$m_aAllowedValues[$sTagDataClass] = $oSet->ToArray();
}
return self::$m_aAllowedValues[$sTagDataClass];
}
}

View File

@@ -56,20 +56,18 @@ class TemplateString
{
protected $m_sRaw;
protected $m_aPlaceholders;
public function __construct($sRaw)
{
$this->m_sRaw = $sRaw;
$this->m_aPlaceholders = null;
}
/**
* Split the string into placholders
*
* @param array $aParamTypes Class of the expected parameters: hash array of '<param_id>' => '<class_name>'
*
* @throws \Exception
*/
* Split the string into placholders
* @param Hash $aParamTypes Class of the expected parameters: hash array of '<param_id>' => '<class_name>'
* @return void
*/
protected function Analyze($aParamTypes = array())
{
if (!is_null($this->m_aPlaceholders)) return;
@@ -102,10 +100,9 @@ class TemplateString
}
/**
* Return the placeholders (for reporting purposes)
*
* @return array
*/
* Return the placeholders (for reporting purposes)
* @return void
*/
public function GetPlaceholders()
{
return $this->m_aPlaceholders;
@@ -113,11 +110,9 @@ class TemplateString
/**
* Check the format when possible
*
* @param array $aParamTypes Class of the expected parameters: hash array of '<param_id>' => '<class_name>'
*
* @return boolean
*/
* @param Hash $aParamTypes Class of the expected parameters: hash array of '<param_id>' => '<class_name>'
* @return void
*/
public function IsValid($aParamTypes = array())
{
$this->Analyze($aParamTypes);
@@ -140,12 +135,10 @@ class TemplateString
}
/**
* Apply the given parameters to replace the placeholders
*
* @param array $aParamValues Value of the expected parameters: hash array of '<param_id>' => '<value>'
*
* @return string
*/
* Apply the given parameters to replace the placeholders
* @param Hash $aParamValues Value of the expected parameters: hash array of '<param_id>' => '<value>'
* @return void
*/
public function Render($aParamValues = array())
{
$aParamTypes = array();
@@ -181,4 +174,5 @@ class TemplateString
}
return str_replace($aSearch, $aReplace, $this->m_sRaw);
}
}
}
?>

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2018 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -19,25 +19,21 @@
/**
* Persistent class Trigger and derived
* User defined triggers, that may be used in conjunction with user defined actions
* User defined triggers, that may be used in conjunction with user defined actions
*
* @copyright Copyright (C) 2010-2018 Combodo SARL
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* A user defined trigger, to customize the application
* A user defined trigger, to customize the application
* A trigger will activate an action
*
* @package iTopORM
*/
abstract class Trigger extends cmdbAbstractObject
{
/**
* @throws \CoreException
* @throws \Exception
*/
public static function Init()
{
$aParams = array
@@ -54,32 +50,25 @@ abstract class Trigger extends cmdbAbstractObject
);
MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values" => null, "sql" => "description", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("action_list", array("linked_class" => "lnkTriggerAction", "ext_key_to_me" => "trigger_id", "ext_key_to_remote" => "action_id", "allowed_values" => null, "count_min" => 1, "count_max" => 0, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("action_list", array("linked_class"=>"lnkTriggerAction", "ext_key_to_me"=>"trigger_id", "ext_key_to_remote"=>"action_id", "allowed_values"=>null, "count_min"=>1, "count_max"=>0, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('finalclass', 'description', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
/**
* @param $aContextArgs
*
* @throws \ArchivedObjectException
* @throws \CoreException
*/
public function DoActivate($aContextArgs)
{
// Find the related actions
$oLinkedActions = $this->Get('action_list');
while ($oLink = $oLinkedActions->Fetch())
{
/** @var \DBObject $oLink */
$iActionId = $oLink->Get('action_id');
/** @var \Action $oAction */
$oAction = MetaModel::GetObject('Action', $iActionId);
if ($oAction->IsActive())
{
@@ -87,13 +76,11 @@ abstract class Trigger extends cmdbAbstractObject
}
}
}
/**
* Check whether the given object is in the scope of this trigger
* and can potentially be the subject of notifications
*
* @param DBObject $oObject The object to check
*
* @return bool
*/
public function IsInScope(DBObject $oObject)
@@ -104,15 +91,8 @@ abstract class Trigger extends cmdbAbstractObject
}
}
/**
* Class TriggerOnObject
*/
abstract class TriggerOnObject extends Trigger
{
/**
* @throws \CoreException
* @throws \Exception
*/
public static function Init()
{
$aParams = array
@@ -129,20 +109,17 @@ abstract class TriggerOnObject extends Trigger
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeClass("target_class", array("class_category" => "bizmodel", "more_values" => "User,UserExternal,UserInternal,UserLDAP,UserLocal", "sql" => "target_class", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeOQL("filter", array("allowed_values" => null, "sql" => "filter", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeClass("target_class", array("class_category"=>"bizmodel", "more_values"=>"User,UserExternal,UserInternal,UserLDAP,UserLocal", "sql"=>"target_class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeOQL("filter", array("allowed_values"=>null, "sql"=>"filter", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'filter', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class', 'description')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('default_search', array('description', 'target_class')); // Default criteria of the search banner
// MetaModel::Init_SetZListItems('standard_search', array('name', 'target_class', 'description')); // Criteria of the search form
// MetaModel::Init_SetZListItems('standard_search', array('name', 'target_class', 'description')); // Criteria of the search form
}
/**
* @throws \CoreException
*/
public function DoCheckToWrite()
{
parent::DoCheckToWrite();
@@ -158,7 +135,8 @@ abstract class TriggerOnObject extends Trigger
{
$this->m_aCheckIssues[] = Dict::Format('TriggerOnObject:WrongFilterClass', $this->Get('target_class'));
}
} catch (OqlException $e)
}
catch(OqlException $e)
{
$this->m_aCheckIssues[] = Dict::Format('TriggerOnObject:WrongFilterQuery', $e->getMessage());
}
@@ -168,33 +146,21 @@ abstract class TriggerOnObject extends Trigger
/**
* Check whether the given object is in the scope of this trigger
* and can potentially be the subject of notifications
*
* @param DBObject $oObject The object to check
*
* @return bool
* @throws \CoreException
*/
public function IsInScope(DBObject $oObject)
{
$sRootClass = $this->Get('target_class');
return ($oObject instanceof $sRootClass);
}
/**
* @param $aContextArgs
*
* @throws \ArchivedObjectException
* @throws \CoreException
*/
public function DoActivate($aContextArgs)
{
$bGo = true;
if (isset($aContextArgs['this->object()']))
{
/** @var \DBObject $oObject */
$oObject = $aContextArgs['this->object()'];
$bGo = $this->IsTargetObject($oObject->GetKey(), $oObject->ListChanges());
$bGo = $this->IsTargetObject($aContextArgs['this->object()']->GetKey());
}
if ($bGo)
{
@@ -202,18 +168,7 @@ abstract class TriggerOnObject extends Trigger
}
}
/**
* @param $iObjectId
* @param array $aChanges
*
* @return bool
* @throws \CoreException
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
*/
public function IsTargetObject($iObjectId, $aChanges = array())
public function IsTargetObject($iObjectId)
{
$sFilter = trim($this->Get('filter'));
if (strlen($sFilter) > 0)
@@ -227,19 +182,14 @@ abstract class TriggerOnObject extends Trigger
{
$bRet = true;
}
return $bRet;
}
}
/**
* To trigger notifications when a ticket is updated from the portal
*/
class TriggerOnPortalUpdate extends TriggerOnObject
{
/**
* @throws \CoreException
*/
public static function Init()
{
$aParams = array
@@ -264,15 +214,8 @@ class TriggerOnPortalUpdate extends TriggerOnObject
}
}
/**
* Class TriggerOnStateChange
*/
abstract class TriggerOnStateChange extends TriggerOnObject
{
/**
* @throws \CoreException
* @throws \Exception
*/
public static function Init()
{
$aParams = array
@@ -289,25 +232,19 @@ abstract class TriggerOnStateChange extends TriggerOnObject
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeClassState("state", array("class_field" => 'target_class', "allowed_values" => null, "sql" => "state", "default_value" => null, "is_null_allowed" => false, "depends_on" => array('target_class'))));
MetaModel::Init_AddAttribute(new AttributeString("state", array("allowed_values"=>null, "sql"=>"state", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'filter', 'state', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class', 'state')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
/**
* Class TriggerOnStateEnter
*/
class TriggerOnStateEnter extends TriggerOnStateChange
{
/**
* @throws \CoreException
*/
public static function Init()
{
$aParams = array
@@ -330,18 +267,12 @@ class TriggerOnStateEnter extends TriggerOnStateChange
MetaModel::Init_SetZListItems('list', array('target_class', 'state')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
/**
* Class TriggerOnStateLeave
*/
class TriggerOnStateLeave extends TriggerOnStateChange
{
/**
* @throws \CoreException
*/
public static function Init()
{
$aParams = array
@@ -364,18 +295,12 @@ class TriggerOnStateLeave extends TriggerOnStateChange
MetaModel::Init_SetZListItems('list', array('target_class', 'state')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('')); // Criteria of the advanced search form
// MetaModel::Init_SetZListItems('advanced_search', array('')); // Criteria of the advanced search form
}
}
/**
* Class TriggerOnObjectCreate
*/
class TriggerOnObjectCreate extends TriggerOnObject
{
/**
* @throws \CoreException
*/
public static function Init()
{
$aParams = array
@@ -398,146 +323,12 @@ class TriggerOnObjectCreate extends TriggerOnObject
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
/**
* Class TriggerOnObjectCreate
*/
class TriggerOnObjectDelete extends TriggerOnObject
{
/**
* @throws \CoreException
*/
public static function Init()
{
$aParams = array
(
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"state_attcode" => "",
"reconc_keys" => array('description'),
"db_table" => "priv_trigger_onobjdelete",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'filter', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
/**
* Class TriggerOnObjectCreate
*/
class TriggerOnObjectUpdate extends TriggerOnObject
{
/**
* @throws \CoreException
* @throws \Exception
*/
public static function Init()
{
$aParams = array
(
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"state_attcode" => "",
"reconc_keys" => array('description'),
"db_table" => "priv_trigger_onobjupdate",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeClassAttCodeSet('target_attcodes', array("allowed_values" => null, "class_field" => "target_class", "sql" => "target_attcodes", "default_value" => null, "is_null_allowed" => true, "max_items" => 20, "min_items" => 0, "attribute_definition_exclusion_list" => "AttributeDashboard,AttributeExternalField,AttributeFinalClass,AttributeFriendlyName,AttributeObsolescenceDate,AttributeObsolescenceFlag,AttributeSubItem", "attribute_definition_list" => null, "depends_on" => array('target_class'))));
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'filter', 'target_attcodes', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
}
public function IsTargetObject($iObjectId, $aChanges = array())
{
if (!parent::IsTargetObject($iObjectId, $aChanges))
{
return false;
}
// Check the attribute
$oAttCodeSet = $this->Get('target_attcodes');
$aAttCodes = $oAttCodeSet->GetValues();
if (empty($aAttCodes))
{
return true;
}
foreach($aAttCodes as $sAttCode)
{
if (array_key_exists($sAttCode, $aChanges))
{
return true;
}
}
return false;
}
public function ComputeValues()
{
parent::ComputeValues();
// Remove unwanted attribute codes
$aChanges = $this->ListChanges();
if (isset($aChanges['target_attcodes']))
{
$oAttDef = MetaModel::GetAttributeDef(get_class($this), 'target_attcodes');
$aArgs = array('this' => $this);
$aAllowedValues = $oAttDef->GetAllowedValues($aArgs);
/** @var \ormSet $oValue */
$oValue = $this->Get('target_attcodes');
$aValues = $oValue->GetValues();
$bChanged = false;
foreach($aValues as $key => $sValue)
{
if (!isset($aAllowedValues[$sValue]))
{
unset($aValues[$key]);
$bChanged = true;
}
}
if ($bChanged)
{
$oValue->SetValues($aValues);
$this->Set('target_attcodes', $oValue);
}
}
}
}
/**
* Class lnkTriggerAction
*/
class lnkTriggerAction extends cmdbAbstractObject
{
/**
* @throws \CoreException
* @throws \Exception
*/
public static function Init()
{
$aParams = array
@@ -554,11 +345,11 @@ class lnkTriggerAction extends cmdbAbstractObject
"is_link" => true,
);
MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeExternalKey("action_id", array("targetclass" => "Action", "jointype" => '', "allowed_values" => null, "sql" => "action_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("action_name", array("allowed_values" => null, "extkey_attcode" => 'action_id', "target_attcode" => "name")));
MetaModel::Init_AddAttribute(new AttributeExternalKey("trigger_id", array("targetclass" => "Trigger", "jointype" => '', "allowed_values" => null, "sql" => "trigger_id", "is_null_allowed" => false, "on_target_delete" => DEL_AUTO, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("trigger_name", array("allowed_values" => null, "extkey_attcode" => 'trigger_id', "target_attcode" => "description")));
MetaModel::Init_AddAttribute(new AttributeInteger("order", array("allowed_values" => null, "sql" => "order", "default_value" => 0, "is_null_allowed" => true, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeExternalKey("action_id", array("targetclass"=>"Action", "jointype"=> '', "allowed_values"=>null, "sql"=>"action_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("action_name", array("allowed_values"=>null, "extkey_attcode"=> 'action_id', "target_attcode"=>"name")));
MetaModel::Init_AddAttribute(new AttributeExternalKey("trigger_id", array("targetclass"=>"Trigger", "jointype"=> '', "allowed_values"=>null, "sql"=>"trigger_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("trigger_name", array("allowed_values"=>null, "extkey_attcode"=> 'trigger_id', "target_attcode"=>"description")));
MetaModel::Init_AddAttribute(new AttributeInteger("order", array("allowed_values"=>null, "sql"=>"order", "default_value"=>0, "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('action_id', 'trigger_id', 'order')); // Attributes to be displayed for a list
@@ -569,15 +360,8 @@ class lnkTriggerAction extends cmdbAbstractObject
}
}
/**
* Class TriggerOnThresholdReached
*/
class TriggerOnThresholdReached extends TriggerOnObject
{
/**
* @throws \CoreException
* @throws \Exception
*/
public static function Init()
{
$aParams = array
@@ -595,14 +379,15 @@ class TriggerOnThresholdReached extends TriggerOnObject
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeClassAttCodeSet('stop_watch_code', array("allowed_values" => null, "class_field" => "target_class", "sql" => "stop_watch_code", "default_value" => null, "is_null_allowed" => false, "max_items" => 1, "min_items" => 1, "attribute_definition_exclusion_list" => null, "attribute_definition_list" => "AttributeStopWatch", "include_child_classes_attributes" => true, "depends_on" => array('target_class'))));
MetaModel::Init_AddAttribute(new AttributeString("threshold_index", array("allowed_values" => null, "sql" => "threshold_index", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
MetaModel::Init_AddAttribute(new AttributeString("stop_watch_code", array("allowed_values"=>null, "sql"=>"stop_watch_code", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("threshold_index", array("allowed_values"=>null, "sql"=>"threshold_index", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'stop_watch_code', 'threshold_index', 'filter', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('target_class', 'threshold_index', 'threshold_index')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
?>

View File

@@ -289,13 +289,13 @@ abstract class User extends cmdbAbstractObject
$oSet = $this->Get('profile_list');
if ($oSet->Count() == 0)
{
$this->m_aCheckIssues[] = Dict::S('Class:User/Error:AtLeastOneProfileIsNeeded');
$this->m_aCheckIssues[] = Dict::Format('Class:User/Error:AtLeastOneProfileIsNeeded');
}
}
// Only administrators can manage administrators
if (UserRights::IsAdministrator($this) && !UserRights::IsAdministrator())
{
$this->m_aCheckIssues[] = Dict::S('UI:Login:Error:AccessRestricted');
$this->m_aCheckIssues[] = Dict::Format('UI:Login:Error:AccessRestricted');
}
if (!UserRights::IsAdministrator())
@@ -304,37 +304,30 @@ abstract class User extends cmdbAbstractObject
$oAddon = UserRights::GetModuleInstance();
if (!is_null($oUser) && method_exists($oAddon, 'GetUserOrgs'))
{
if ((empty($this->GetOriginal('contactid')) && !($this->IsNew())) || empty($this->Get('contactid')))
$aOrgs = $oAddon->GetUserOrgs($oUser, '');
if (count($aOrgs) > 0)
{
$this->m_aCheckIssues[] = Dict::S('Class:User/Error:PersonIsMandatory');
}
else
{
$aOrgs = $oAddon->GetUserOrgs($oUser, '');
if (count($aOrgs) > 0)
// Check that the modified User belongs to one of our organization
if (!in_array($this->GetOriginal('org_id'), $aOrgs) && !in_array($this->Get('org_id'), $aOrgs))
{
// Check that the modified User belongs to one of our organization
if (!in_array($this->GetOriginal('org_id'), $aOrgs) && !in_array($this->Get('org_id'), $aOrgs))
$this->m_aCheckIssues[] = Dict::Format('Class:User/Error:UserOrganizationNotAllowed');
}
// Check users with restricted organizations when allowed organizations have changed
if ($this->IsNew() || array_key_exists('allowed_org_list', $aChanges))
{
$oSet = $this->get('allowed_org_list');
if ($oSet->Count() == 0)
{
$this->m_aCheckIssues[] = Dict::S('Class:User/Error:UserOrganizationNotAllowed');
$this->m_aCheckIssues[] = Dict::Format('Class:User/Error:AtLeastOneOrganizationIsNeeded');
}
// Check users with restricted organizations when allowed organizations have changed
if ($this->IsNew() || array_key_exists('allowed_org_list', $aChanges))
else
{
$oSet = $this->get('allowed_org_list');
if ($oSet->Count() == 0)
$aModifiedLinks = $oSet->ListModifiedLinks();
foreach($aModifiedLinks as $oLink)
{
$this->m_aCheckIssues[] = Dict::S('Class:User/Error:AtLeastOneOrganizationIsNeeded');
}
else
{
$aModifiedLinks = $oSet->ListModifiedLinks();
foreach ($aModifiedLinks as $oLink)
if (!in_array($oLink->Get('allowed_org_id'), $aOrgs))
{
if (!in_array($oLink->Get('allowed_org_id'), $aOrgs))
{
$this->m_aCheckIssues[] = Dict::S('Class:User/Error:OrganizationNotAllowed');
}
$this->m_aCheckIssues[] = Dict::Format('Class:User/Error:OrganizationNotAllowed');
}
}
}
@@ -1225,9 +1218,8 @@ class UserRights
}
/**
* @param string $sProfileName Profile name to search for
* @param User|null $oUser
*
* @param $sProfileName Profile name to search for
* @param $oUser User|null
* @return bool
*/
public static function HasProfile($sProfileName, $oUser = null)
@@ -1241,6 +1233,8 @@ class UserRights
* @param Bool Reset admin cache as well
* @return void
*/
// Reset cached data
//
public static function FlushPrivileges($bResetAdminCache = false)
{
if ($bResetAdminCache)
@@ -1261,16 +1255,12 @@ class UserRights
}
static $m_aCacheUsers;
/**
* Find a user based on its login and its type of authentication
*
* @param string $sLogin Login/identifier of the user
* @param string $sAuthentication Type of authentication used: internal|external|any
* @param bool $bAllowDisabledUsers Whether or not to retrieve disabled users (status != enabled)
*
* @return User The found user or null
* @throws \OQLException
*/
protected static function FindUser($sLogin, $sAuthentication = 'any', $bAllowDisabledUsers = false)
{
@@ -1331,24 +1321,6 @@ class UserRights
{
$_SESSION['profile_list'] = self::ListProfiles();
}
$oConfig = MetaModel::GetConfig();
$bSessionIdRegeneration = $oConfig->Get('regenerate_session_id_enabled');
if ($bSessionIdRegeneration)
{
// Protection against session fixation/injection: generate a new session id.
// Alas a PHP bug (technically a bug in the memcache session handler, https://bugs.php.net/bug.php?id=71187)
// causes session_regenerate_id to fail with a catchable fatal error in PHP 7.0 if the session handler is memcache(d).
// The bug has been fixed in PHP 7.2, but in case session_regenerate_id()
// fails we just silently ignore the error and keep the same session id...
$old_error_handler = set_error_handler(array(__CLASS__, 'VoidErrorHandler'));
session_regenerate_id();
if ($old_error_handler !== null)
{
set_error_handler($old_error_handler);
}
}
}
public static function _ResetSessionCache()
@@ -1362,19 +1334,6 @@ class UserRights
unset($_SESSION['archive_allowed']);
}
}
/**
* Fake error handler to silently discard fatal errors
* @param int $iErrNo
* @param string $sErrStr
* @param string $sErrFile
* @param int $iErrLine
* @return boolean
*/
public static function VoidErrorHandler($iErrno, $sErrStr, $sErrFile, $iErrLine)
{
return true; // Ignore the error
}
}
/**

View File

@@ -1,5 +1,5 @@
// Beware the version number MUST be enclosed with quotes otherwise v2.3.0 becomes v2 0.3 .0
$version: "v2.6.0";
$version: "v2.5.4";
// Base colors
$gray-base: #000 !default;
@@ -29,12 +29,13 @@ $frame-background-color: $gray-extra-light;
$text-color: #000;
$box-radius: 0px;
$box-shadow-regular: 0 1px 1px rgba(0, 0, 0, 0.15);
$hyperlink-color: $complement-color;
$hyperlink-text-decoration: none;
////////////
// Search //
// - Boxes
//$search-criteria-box-color: #2D2D2D;
//$search-criteria-box-bg-color: #f0f3f5;
//$search-criteria-box-border-color: #3f7294;
//$search-criteria-box-border: 1px solid $search-criteria-box-border-color;
//$search-criteria-box-radius: 1px;
//
$search-criteria-box-color: #2D2D2D;
$search-criteria-box-picto-color: #E87C1E;
$search-criteria-box-bg-color: #EEEEEE;

115
css/fg.menu.css Executable file
View File

@@ -0,0 +1,115 @@
/* Styles for jQuery menu widget
Author: Maggie Wachs, maggie@filamentgroup.com
Date: September 2008
*/
/* REQUIRED STYLES - the menus will only render correctly with these rules */
.positionHelper { z-index: 2999; }
.fg-menu-container { position: absolute; top:0; left:-999px; padding: .4em; overflow: hidden; }
.fg-menu-container.fg-menu-flyout { overflow: visible; }
.fg-menu, .fg-menu ul { list-style-type:none; padding: 0; margin:0; }
.fg-menu { position:relative; }
.fg-menu-flyout .fg-menu { position:static; }
.fg-menu ul { position:absolute; top:0; }
.fg-menu ul ul { top:-1px; }
.fg-menu-container.fg-menu-ipod .fg-menu-content,
.fg-menu-container.fg-menu-ipod .fg-menu-content ul { background: none !important; }
.fg-menu.fg-menu-scroll,
.fg-menu ul.fg-menu-scroll { overflow: scroll; overflow-x: hidden; }
.fg-menu li { clear:both; float:left; width:100%; margin: 0; padding:0; border: 0; }
.fg-menu li li { font-size:1em; } /* inner li font size must be reset so that they don't blow up */
.fg-menu-flyout ul ul { padding: .4em; }
.fg-menu-flyout li { position:relative; }
.fg-menu-scroll { overflow: scroll; overflow-x: hidden; }
.fg-menu-breadcrumb { margin: 0; padding: 0; }
.fg-menu-footer { margin-top: .4em; padding: .4em; }
.fg-menu-header { margin-bottom: .4em; padding: .4em; }
.fg-menu-breadcrumb li { float: left; list-style: none; margin: 0; padding: 0 .2em; font-size: .9em; opacity: .7; }
.fg-menu-breadcrumb li.fg-menu-prev-list,
.fg-menu-breadcrumb li.fg-menu-current-crumb { clear: left; float: none; opacity: 1; }
.fg-menu-breadcrumb li.fg-menu-current-crumb { padding-top: .2em; }
.fg-menu-breadcrumb a,
.fg-menu-breadcrumb span { float: left; }
.fg-menu-footer a:link,
.fg-menu-footer a:visited { float:left; width:100%; text-decoration: none; }
.fg-menu-footer a:hover,
.fg-menu-footer a:active { }
.fg-menu-footer a span { float:left; cursor: pointer; }
.fg-menu-breadcrumb .fg-menu-prev-list a:link,
.fg-menu-breadcrumb .fg-menu-prev-list a:visited,
.fg-menu-breadcrumb .fg-menu-prev-list a:hover,
.fg-menu-breadcrumb .fg-menu-prev-list a:active { background-image: none; text-decoration:none; }
.fg-menu-breadcrumb .fg-menu-prev-list a { float: left; padding-right: .4em; }
.fg-menu-breadcrumb .fg-menu-prev-list a .ui-icon { float: left; }
.fg-menu-breadcrumb .fg-menu-current-crumb a:link,
.fg-menu-breadcrumb .fg-menu-current-crumb a:visited,
.fg-menu-breadcrumb .fg-menu-current-crumb a:hover,
.fg-menu-breadcrumb .fg-menu-current-crumb a:active { display:block; background-image:none; font-size:1.3em; text-decoration:none; }
/* REQUIRED LINK STYLES: links are "display:block" by default; if the menu options are split into
selectable node links and 'next' links, the script floats the node links left and floats the 'next' links to the right */
.fg-menu a:link,
.fg-menu a:visited,
.fg-menu a:hover,
.fg-menu a:active { float:left; width:92%; padding:.3em 3%; text-decoration:none; outline: 0 !important; }
.fg-menu a { border: 1px dashed transparent; }
.fg-menu a.ui-state-default:link,
.fg-menu a.ui-state-default:visited,
.fg-menu a.ui-state-default:hover,
.fg-menu a.ui-state-default:active,
.fg-menu a.ui-state-hover:link,
.fg-menu a.ui-state-hover:visited,
.fg-menu a.ui-state-hover:hover,
.fg-menu a.ui-state-hover:active,
.fg-menu a.ui-state-active:link,
.fg-menu a.ui-state-active:visited,
.fg-menu a.ui-state-active:hover,
.fg-menu a.ui-state-active:active { border-style: solid; font-weight: normal; }
.fg-menu a span { display:block; cursor:pointer; }
/* SUGGESTED STYLES - for use with jQuery UI Themeroller CSS */
.fg-menu-indicator span { float:left; }
.fg-menu-indicator span.ui-icon { float:right; }
.fg-menu-content.ui-widget-content,
.fg-menu-content ul.ui-widget-content { border:0; }
/* ICONS AND DIVIDERS */
.fg-menu.fg-menu-has-icons a:link,
.fg-menu.fg-menu-has-icons a:visited,
.fg-menu.fg-menu-has-icons a:hover,
.fg-menu.fg-menu-has-icons a:active { padding-left:20px; }
.fg-menu .horizontal-divider hr, .fg-menu .horizontal-divider span { padding:0; margin:5px .6em; }
.fg-menu .horizontal-divider hr { border:0; height:1px; }
.fg-menu .horizontal-divider span { font-size:.9em; text-transform: uppercase; padding-left:.2em; }

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