Compare commits

..

76 Commits

Author SHA1 Message Date
Pierre Goiffon
8295eaed90 Merge remote-tracking branch 'origin/support/2.5' into support/2.6 2023-07-26 12:06:32 +02:00
Pierre Goiffon
219b970703 N°4478 Fix linkedset widget in portal when adding new items with already selected ones
Was already committed to develop with e59d472c
2021-12-10 15:56:33 +01:00
Pierre Goiffon
76c139253e 🎨 Fix language injection 2021-12-10 15:24:16 +01:00
Pierre Goiffon
10cfb373f2 N°4481 Fix badly escaped dialog tooltip
Was commited to develop first (99a0e0c5 and 4f27f3ac)
2021-12-10 13:38:24 +01:00
Pierre Goiffon
97d6d413bb N°4502 Fix dashboard page not refreshed after saving customm dashboard 2021-12-10 12:30:33 +01:00
Pierre Goiffon
3f8f57fa9a N°4502 Fix cannot create new or edit existing custom dashboard
Regression brought by dbaf9241
2021-12-10 09:15:43 +01:00
Pierre Goiffon
f916f9cde8 N°4289 Allow to use privUITransactionFile when no user logged
Before we were throwing a SecurityException, which was blocking for combodo-unauthenticated-form for example
2021-12-08 17:16:12 +01:00
Molkobain
8a65a592f3 N°4360 - Rename class to match other classes convention 2021-11-26 13:47:05 +01:00
Pierre Goiffon
5e48400cb1 N°4478 Fix line selection (global and unique) not checking checkbox anymore 2021-11-26 11:44:32 +01:00
Pierre Goiffon
252562ace9 N°4478 Fix "Requested unknown parameter '' for row 0, column 0" when opening search on related object
Forgotten file :/
2021-11-26 11:08:25 +01:00
Pierre Goiffon
770ac8ffe5 N°4478 Fix "Requested unknown parameter '' for row 0, column 0" when opening search on related object 2021-11-26 10:58:17 +01:00
Pierre Goiffon
ed3c387712 N°4478 Update Datatables lib 2021-11-25 10:55:48 +01:00
Pierre Goiffon
81a2a9278c N°4360 Fix SvgDOMSanitizer expected data 2021-11-23 17:38:30 +01:00
Pierre Goiffon
e15d4bfab6 N°4360 Security hardening 2021-11-23 17:25:50 +01:00
Pierre Goiffon
3e8dd2f4a5 N°4286 Setup : fix loop in first steps
Setup token wasn't removed at the right place :/
2021-11-18 08:54:10 +01:00
Pierre Goiffon
51a49dfce8 Remove warnings, use finally block, formatting 2021-11-17 16:10:50 +01:00
Pierre Goiffon
066b71686d N°4286 Setup : restore backup download on WizStepDone
Setup token was put with N°2016 (6b5cc7c)
But later on we refactored the token handling in SetupUtils methods, and we had token removal in WizStepDone (43daa2ef) : so the backup download cannot be done :/
2021-11-17 14:39:44 +01:00
Pierre Goiffon
be633001a5 Revert "N°4360 Security hardening"
This reverts commit 8adf743cc7.

We will implement a different solution later (hopefully for 2.6.5 / 2.7.6 / 3.0.0 as well)
2021-11-17 11:13:29 +01:00
Pierre Goiffon
84426c6634 N°4365 Security hardening 2021-11-17 10:15:12 +01:00
Pierre Goiffon
dbaf924171 N°4363 Security hardening 2021-11-16 17:19:19 +01:00
Pierre Goiffon
8adf743cc7 N°4360 Security hardening 2021-11-16 12:01:16 +01:00
Pierre Goiffon
75450ded1d N°4359 Security hardening 2021-11-15 16:38:11 +01:00
Pierre Goiffon
2beb795f9a N°4304 Security hardening 2021-11-09 11:32:53 +01:00
Pierre Goiffon
e8d314e1f6 N°4367 Fix \privUITransactionFileTest::testIsTransactionValid
* change user name for when password policy is active
* admin user doesn't exist on Jenkins : create a second user
* test UserRights::Login return value
* document that we depend on the sample data
2021-11-03 10:50:25 +01:00
Pierre Goiffon
e29f1825be N°4367 Fix "redeclaration of const CombodoSanitizer"
The utils.js can be included more than once in old iTop branches :( This is fixed in 3.0.0 (develop branch)

Also add missing ";"
2021-11-02 17:14:16 +01:00
Pierre Goiffon
9b854dbcc7 N°4289 skip test (not working on Jenkins) 2021-10-21 14:52:59 +02:00
Pierre Goiffon
7757f1f2d2 N°4289 Security hardening 2021-10-21 12:43:03 +02:00
Pierre Goiffon
a353317746 N°4289 Fix privUITransactionFile generating error if MetaModel not loaded 2021-10-20 17:26:32 +02:00
Pierre Goiffon
723eb90160 N°4289 privUITransactionSession phpDoc 2021-10-20 17:25:58 +02:00
Pierre Goiffon
b3f827ed5e N°4367 Security hardening 2021-10-18 14:27:58 +02:00
Pierre Goiffon
eaf8a187aa N°3332 report function rename
The method was renamed in 18d52319 but only on support/2.7 and above
2021-10-18 11:36:17 +02:00
Pierre Goiffon
34f64c61f6 privUITransaction fix inspections errors + formatting 2021-10-18 11:32:38 +02:00
Molkobain
92a9a8c65f N°4129 - Security hardening 2021-08-18 15:57:18 +02:00
Pierre Goiffon
834ac00d37 📝 README : update latest releases
Was made in #143 but on develop only, but we are still maintaining older branches !
2021-07-21 12:15:22 +02:00
Eric
5691ca0327 Fix CI 2021-05-28 08:48:47 +02:00
Eric
86f649affc N°4002 - code hardening 2021-05-27 16:13:27 +02:00
Eric
4f5c987d8b N°4002 - code hardening 2021-05-27 15:57:04 +02:00
Eric
e441e5e78a documentation 2021-05-27 11:49:32 +02:00
Eric
43daa2ef08 N°3952 - code hardening 2021-05-27 09:29:50 +02:00
acognet
db6e813cba N°3945 - Password database is visible in the setup process 2021-05-18 17:34:57 +02:00
Pierre Goiffon
066a6d8b36 🔧 Use same .editorconfig in all supported branches 2021-01-25 09:12:38 +01:00
Pierre Goiffon
b9ca2ac13d N°3416 Fix DocumentFile preview not working anymore
Was caused by X-Frame-Options http header added with N°3317

(cherry picked from commit 35d77ff642)

# Conflicts:
#	pages/ajax.render.php
2020-12-03 08:20:51 +01:00
Pierre Goiffon
65e43e8d04 🔧 remove .gitflow as we don't have any master branch anymore 2020-10-22 10:10:15 +02:00
Pierre Goiffon
5fee2438ab Fix comments : iTop 2.8.0 renamed to 3.0.0 2020-10-14 09:06:07 +02:00
Pierre Goiffon
8b1c20cc11 N°3332 Security hardening 2020-10-12 12:40:51 +02:00
odain
0001e8ffc4 💚 use new ci validation 2020-10-09 10:13:51 +02:00
odain
df5aacca42 💚 use new ci validation 2020-10-09 10:08:31 +02:00
Eric
1f53757318 N°3248 - code hardening
(cherry picked from commit 6a25933744)
(cherry picked from commit f74c78d61c)
2020-10-05 14:54:17 +02:00
Pierre Goiffon
090119147c 🎨 PHP formatting 2020-10-05 14:42:03 +02:00
Pierre Goiffon
1551694198 N°3317 Security hardening 2020-10-05 14:42:03 +02:00
Eric
bef1832ac7 N°3317 - Add http headers 2020-09-29 14:07:24 +02:00
Pierre Goiffon
45e366745d N°3333 Security hardening 2020-09-24 17:34:57 +02:00
Pierre Goiffon
1e634a8bba N°3332 Security hardening 2020-09-23 17:17:05 +02:00
Pierre Goiffon
228a945da9 N°2984 Security hardening 2020-05-14 11:26:35 +02:00
Pierre Goiffon
834297e675 N°2985 Security hardening (#140)
Thanks @bruno-ds  for the review !
2020-05-13 10:04:40 +02:00
Pierre Goiffon
3c9318d56a N°2990 Fix count warning on audit OQL error 2020-05-12 09:41:24 +02:00
Pierre Goiffon
30d10b6f11 N°2990 Security hardening 2020-05-12 09:40:58 +02:00
Pierre Goiffon
f8e39877b3 N°2988 Security hardening 2020-05-07 11:49:58 +02:00
Pierre Goiffon
0a3f7d7ef7 N°2989 ajax.backup small updates
* update copyright
* in messages replace iTop by constant
2020-05-07 11:18:21 +02:00
Pierre Goiffon
222eb47bd2 N°2989 ajax.backup : refactor exit conditions
Adding a die() call so that we are sure to exit on errors !
2020-05-07 10:49:05 +02:00
Pierre Goiffon
c5b1f02d2b 🔖 Update versions to 2.6.4 2020-04-21 08:52:42 +02:00
Pierre Goiffon
f81ab4d71a 🚀 Release tool to update versions
Was already comitted in 2.7 branch (fd1e17cc)
2020-04-21 08:50:25 +02:00
Eric
b88b9dabdb N°2919 - Dashboard - Fix dashboard not saved
The sanitization was too strong. Some names can contain ':'
2020-04-09 17:59:52 +02:00
Eric
06b17e82db N°2755 - Security hardening 2020-04-09 11:03:07 +02:00
Eric
2add79a473 N°2853 - Security hardening 2020-04-09 10:55:17 +02:00
Eric
3a37e24496 N°2306 - Security hardening 2020-04-08 09:28:20 +02:00
Eric
b1d703bff3 N°1671 Portal: Fix Aggregate Brick when user profile is not allowed to see one of the sub-brick 2020-04-06 14:07:42 +02:00
Eric
a3a34a94e7 N°1355 - Security hardening 2020-04-06 11:47:57 +02:00
Stephen Abello
6edc365685 N°2742 - HTML files preview are now raw text only 2020-04-06 09:47:24 +02:00
Stephen Abello
4b7f736af0 N°2755 - Security hardening 2020-04-06 09:42:41 +02:00
Stephen Abello
016fbaed36 N°2755 - Security hardening 2020-04-06 09:42:15 +02:00
Stephen Abello
bfcd137e52 N°2853 - Security hardening
(cherry picked from commit d01caaf4e4)
2020-04-06 09:37:58 +02:00
Stephen Abello
f9af8fc912 N°2855 - Security hardening
(cherry picked from commit c5c7fd5c85)
2020-04-06 09:20:02 +02:00
Stephen Abello
bd083d632f Update readme for 2.6.3 release 2020-02-05 11:22:39 +01:00
Molkobain
bd9da07734 Merge branch 'support/2.5' 2020-01-22 09:55:50 +01:00
Molkobain
3dbbf296b8 Exclude combodo-db-tools module from packages by default 2020-01-22 09:10:54 +01:00
7841 changed files with 286897 additions and 478127 deletions

View File

@@ -1,8 +1,8 @@
# Phpdoc dokuwiki template
This directory contains a template for rendering iTop phpdoc as dokuwiki pages.
This directory contains a template rendering iTop phpdoc as wiki pages.
Conventional tags that you should use:
conventional tag that you should use:
* `@internal` : exclude from the documentation.
* `@api` : it means that a method is an api, thus it may be interacted with.
* `@see` : it points to another documented method
@@ -14,7 +14,7 @@ Conventional tags that you should use:
## Special instructions
Some iTop specific tags were added :
some tags where added :
* `@api-advanced`: it means that a method is an `@api` but mark it also as "complex" to use
* `@overwritable-hook`: used to mark a method as "designed to be extended"
* `@extension-hook`: not used for now
@@ -39,12 +39,12 @@ examples:
#### Do not use inline tags, they do not work properly, example:
```
/**
* This is a texts with an inline tag {@see [FQSEN] [<description>]} it must never be used
* This is a texts with ans inline tag {@see [FQSEN] [<description>]} it must never be used
*/
```
#### The `@example` tag must respect this very precise syntax
* the sentence in the first line (next to the tag) is the title, it must be enclosed by double quotes
* the sentence in the first line (next to the tag) is the title, it must be enclose by double quotes
* the following lines are the sample code.
* 💔 since we simply hack the official tag, this syntax must be respected carefully 💔
example:
@@ -82,15 +82,14 @@ Then, **for a method** of an eligible class:
## Installation
```
cd .doc
composer require phpdocumentor/phpdocumentor:~2 --dev
```
## Generation
`./bin/build-doc-object-manipulation` and `./bin/build-doc-extensions` contains examples of doc. generation, beware: they have to be called from the .doc directory:
`.doc/bin/build-doc-object-manipulation` and `.doc/bin/build-doc-extensions` contains examples of doc. generation, beware: they have to be called from iTop root directory:
```shell
cd /path/to/itop/.doc
./bin/build-doc-object-manipulation
cd /path/to/itop/
./.doc/bin/build-doc-object-manipulation
```
the resulting documentation is written into `data/phpdocumentor/output`
@@ -101,3 +100,4 @@ the resulting documentation is written into `data/phpdocumentor/output`
* the generated files have to be placed under an arbitrary directory of `[/path/to/dokuwiki]/data/pages`.
* the html has to be activated [config:htmlok](https://www.dokuwiki.org/config:htmlok)
* the generated files have to be in lowercase

View File

@@ -1,6 +1,7 @@
#!/bin/sh -x
rm -rf /tmp/phpdoc-twig-cache/ && rm -rf data/phpdocumentor/output/extensions/ && rm -rf data/phpdocumentor/temp/extensions/ && .doc/vendor/bin/phpdoc -c .doc/phpdoc-extensions.dist.xml -vvv
rm -rf /tmp/phpdoc-twig-cache/ && rm -rf data/phpdocumentor/output/extensions/ && rm -rf data/phpdocumentor/temp/extensions/ && vendor/bin/phpdoc -c .doc/phpdoc-extensions.dist.xml -vvv
# now wee need to lowercase every generated file because dokuwiki can't handle uppercase
cd data/phpdocumentor/output/extensions/ && for i in $( ls | grep [A-Z] ); do mv -i $i `echo $i | tr 'A-Z' 'a-z'`; done
cd data/phpdocumentor/output/extensions/
for i in $( ls | grep [A-Z] ); do mv -i $i `echo $i | tr 'A-Z' 'a-z'`; done

View File

@@ -1,7 +1,8 @@
#!/bin/sh -x
rm -rf /tmp/phpdoc-twig-cache/ && rm -rf ../data/phpdocumentor/output/objects-manipulation/ && rm -rf ../data/phpdocumentor/temp/objects-manipulation/ && ./vendor/bin/phpdoc -c ./phpdoc-objects-manipulation.dist.xml -vvv
rm -rf /tmp/phpdoc-twig-cache/ && rm -rf data/phpdocumentor/output/objects-manipulation/ && rm -rf data/phpdocumentor/temp/objects-manipulation/ && vendor/bin/phpdoc -c .doc/phpdoc-objects-manipulation.dist.xml -vvv
# now wee need to lowercase every generated file because dokuwiki can't handle uppercase
cd ../data/phpdocumentor/output/objects-manipulation/ && for i in $( ls | grep [A-Z] ); do mv -i $i `echo $i | tr 'A-Z' 'a-z'`; done
cd data/phpdocumentor/output/objects-manipulation/
for i in $( ls | grep [A-Z] ); do mv -i $i `echo $i | tr 'A-Z' 'a-z'`; done

View File

@@ -1,6 +0,0 @@
{
"require-dev": {
"phpdocumentor/phpdocumentor": "~2",
"jms/serializer": "1.7.*"
}
}

View File

@@ -18,7 +18,7 @@
{{ structure.summary|raw }}
[[{{structureName}}|More information]]
[[{{structureName}}|More informations]]
</WRAP>{# group #}

View File

@@ -1,3 +1,5 @@
root = true
[*]
charset = utf-8
end_of_line = lf
@@ -11,16 +13,18 @@ ij_formatter_off_tag = @formatter:off
ij_formatter_on_tag = @formatter:on
ij_formatter_tags_enabled = false
ij_smart_tabs = false
ij_visual_guides = 80, 120, 140
ij_visual_guides = 80,120
ij_wrap_on_typing = true
[*.css]
indent_style = tab
ij_smart_tabs = true
ij_visual_guides = none
ij_css_align_closing_brace_with_properties = false
ij_css_blank_lines_around_nested_selector = 1
ij_css_blank_lines_between_blocks = 1
ij_css_brace_placement = 0
ij_css_brace_placement = end_of_line
ij_css_enforce_quotes_on_format = false
ij_css_hex_color_long_format = false
ij_css_hex_color_lower_case = false
ij_css_hex_color_short_format = false
@@ -31,59 +35,18 @@ ij_css_keep_single_line_blocks = false
ij_css_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_css_space_after_colon = true
ij_css_space_before_opening_brace = true
ij_css_value_alignment = 0
[*.csv]
max_line_length = 2147483647
ij_wrap_on_typing = false
ij_csv_wrap_long_lines = false
[*.feature]
indent_size = 2
ij_gherkin_keep_indents_on_empty_lines = false
[*.less]
indent_size = 2
ij_less_align_closing_brace_with_properties = false
ij_less_blank_lines_around_nested_selector = 1
ij_less_blank_lines_between_blocks = 1
ij_less_brace_placement = 0
ij_less_hex_color_long_format = false
ij_less_hex_color_lower_case = false
ij_less_hex_color_short_format = false
ij_less_hex_color_upper_case = false
ij_less_keep_blank_lines_in_code = 2
ij_less_keep_indents_on_empty_lines = false
ij_less_keep_single_line_blocks = false
ij_less_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_less_space_after_colon = true
ij_less_space_before_opening_brace = true
ij_less_value_alignment = 0
[*.sass]
indent_size = 2
ij_sass_align_closing_brace_with_properties = false
ij_sass_blank_lines_around_nested_selector = 1
ij_sass_blank_lines_between_blocks = 1
ij_sass_brace_placement = 0
ij_sass_hex_color_long_format = false
ij_sass_hex_color_lower_case = false
ij_sass_hex_color_short_format = false
ij_sass_hex_color_upper_case = false
ij_sass_keep_blank_lines_in_code = 2
ij_sass_keep_indents_on_empty_lines = false
ij_sass_keep_single_line_blocks = false
ij_sass_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_sass_space_after_colon = true
ij_sass_space_before_opening_brace = true
ij_sass_value_alignment = 0
ij_css_use_double_quotes = true
ij_css_value_alignment = do_not_align
[*.scss]
indent_style = tab
indent_size = 2
tab_width = 2
ij_visual_guides = none
ij_scss_align_closing_brace_with_properties = false
ij_scss_blank_lines_around_nested_selector = 1
ij_scss_blank_lines_between_blocks = 1
ij_scss_brace_placement = 0
ij_scss_enforce_quotes_on_format = false
ij_scss_hex_color_long_format = false
ij_scss_hex_color_lower_case = false
ij_scss_hex_color_short_format = false
@@ -94,17 +57,20 @@ ij_scss_keep_single_line_blocks = false
ij_scss_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_scss_space_after_colon = true
ij_scss_space_before_opening_brace = true
ij_scss_use_double_quotes = true
ij_scss_value_alignment = 0
[*.twig]
indent_style = tab
ij_smart_tabs = true
ij_visual_guides = none
ij_wrap_on_typing = false
ij_twig_keep_indents_on_empty_lines = false
ij_twig_spaces_inside_comments_delimiters = true
ij_twig_spaces_inside_delimiters = true
ij_twig_spaces_inside_variable_delimiters = true
[.editorconfig]
ij_visual_guides = none
ij_editorconfig_align_group_field_declarations = false
ij_editorconfig_space_after_colon = false
ij_editorconfig_space_after_comma = true
@@ -112,10 +78,44 @@ ij_editorconfig_space_before_colon = false
ij_editorconfig_space_before_comma = false
ij_editorconfig_spaces_around_assignment_operators = true
[{*.ant, *.fxml, *.jhm, *.jnlp, *.jrxml, *.rng, *.tld, *.wsdl, *.xml, *.xsd, *.xsl, *.xslt, *.xul, phpunit.xml.dist}]
indent_size = 2
tab_width = 2
ij_smart_tabs = true
ij_visual_guides = none
ij_wrap_on_typing = false
ij_xml_align_attributes = true
ij_xml_align_text = false
ij_xml_attribute_wrap = normal
ij_xml_block_comment_at_first_column = true
ij_xml_keep_blank_lines = 2
ij_xml_keep_indents_on_empty_lines = false
ij_xml_keep_line_breaks = false
ij_xml_keep_line_breaks_in_text = true
ij_xml_keep_whitespaces = false
ij_xml_keep_whitespaces_around_cdata = preserve
ij_xml_keep_whitespaces_inside_cdata = true
ij_xml_line_comment_at_first_column = true
ij_xml_space_after_tag_name = false
ij_xml_space_around_equals_in_attribute = false
ij_xml_space_inside_empty_tag = false
ij_xml_text_wrap = off
[{*.bash,*.sh,*.zsh}]
indent_size = 2
tab_width = 2
ij_visual_guides = none
ij_shell_binary_ops_start_line = false
ij_shell_keep_column_alignment_padding = false
ij_shell_minify_program = false
ij_shell_redirect_followed_by_space = false
ij_shell_switch_cases_indented = false
[{*.cjs,*.js}]
indent_style = tab
ij_continuation_indent_size = 4
ij_smart_tabs = true
ij_visual_guides = none
ij_javascript_align_imports = false
ij_javascript_align_multiline_array_initializer_expression = false
ij_javascript_align_multiline_binary_operation = false
@@ -134,13 +134,13 @@ ij_javascript_array_initializer_wrap = off
ij_javascript_assignment_wrap = off
ij_javascript_binary_operation_sign_on_next_line = false
ij_javascript_binary_operation_wrap = off
ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**/*
ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/**
ij_javascript_blank_lines_after_imports = 1
ij_javascript_blank_lines_around_class = 1
ij_javascript_blank_lines_around_field = 0
ij_javascript_blank_lines_around_function = 1
ij_javascript_blank_lines_around_method = 1
ij_javascript_block_brace_style = next_line
ij_javascript_block_brace_style = end_of_line
ij_javascript_call_parameters_new_line_after_left_paren = false
ij_javascript_call_parameters_right_paren_on_new_line = false
ij_javascript_call_parameters_wrap = off
@@ -148,15 +148,15 @@ ij_javascript_catch_on_new_line = false
ij_javascript_chained_call_dot_on_new_line = true
ij_javascript_class_brace_style = end_of_line
ij_javascript_comma_on_new_line = false
ij_javascript_do_while_brace_force = never
ij_javascript_else_on_new_line = true
ij_javascript_do_while_brace_force = always
ij_javascript_else_on_new_line = false
ij_javascript_enforce_trailing_comma = keep
ij_javascript_extends_keyword_wrap = off
ij_javascript_extends_list_wrap = off
ij_javascript_field_prefix = _
ij_javascript_file_name_style = relaxed
ij_javascript_finally_on_new_line = false
ij_javascript_for_brace_force = never
ij_javascript_for_brace_force = always
ij_javascript_for_statement_new_line_after_left_paren = false
ij_javascript_for_statement_right_paren_on_new_line = false
ij_javascript_for_statement_wrap = off
@@ -192,6 +192,9 @@ ij_javascript_parentheses_expression_new_line_after_left_paren = false
ij_javascript_parentheses_expression_right_paren_on_new_line = false
ij_javascript_place_assignment_sign_on_next_line = false
ij_javascript_prefer_as_type_cast = false
ij_javascript_prefer_explicit_types_function_expression_returns = false
ij_javascript_prefer_explicit_types_function_returns = false
ij_javascript_prefer_explicit_types_vars_fields = false
ij_javascript_prefer_parameters_wrap = false
ij_javascript_reformat_c_style_comments = false
ij_javascript_space_after_colon = true
@@ -272,11 +275,11 @@ ij_javascript_use_path_mapping = always
ij_javascript_use_public_modifier = false
ij_javascript_use_semicolon_after_statement = true
ij_javascript_var_declaration_wrap = normal
ij_javascript_while_brace_force = never
ij_javascript_while_brace_force = always
ij_javascript_while_on_new_line = false
ij_javascript_wrap_comments = false
[{*.module,*.hphp,*.phtml,*.php5,*.php4,*.php,*.ctp,*.inc}]
[{*.ctp,*.hphp,*.inc,*.module,*.php,*.php4,*.php5,*.phtml}]
indent_style = tab
ij_continuation_indent_size = 4
ij_smart_tabs = true
@@ -296,12 +299,14 @@ ij_php_align_multiline_parameters_in_calls = false
ij_php_align_multiline_ternary_operation = false
ij_php_align_phpdoc_comments = false
ij_php_align_phpdoc_param_names = false
ij_php_anonymous_brace_style = end_of_line
ij_php_api_weight = 1
ij_php_array_initializer_new_line_after_left_brace = true
ij_php_array_initializer_right_brace_on_new_line = true
ij_php_array_initializer_wrap = on_every_item
ij_php_assignment_wrap = off
ij_php_author_weight = 7
ij_php_attributes_wrap = off
ij_php_author_weight = 8
ij_php_binary_operation_sign_on_next_line = false
ij_php_binary_operation_wrap = off
ij_php_blank_lines_after_class_header = 0
@@ -318,7 +323,8 @@ ij_php_blank_lines_before_imports = 1
ij_php_blank_lines_before_method_body = 0
ij_php_blank_lines_before_package = 1
ij_php_blank_lines_before_return_statement = 1
ij_php_block_brace_style = next_line
ij_php_blank_lines_between_imports = 0
ij_php_block_brace_style = end_of_line
ij_php_call_parameters_new_line_after_left_paren = false
ij_php_call_parameters_right_paren_on_new_line = false
ij_php_call_parameters_wrap = normal
@@ -328,11 +334,11 @@ ij_php_class_brace_style = next_line
ij_php_comma_after_last_array_element = true
ij_php_concat_spaces = false
ij_php_copyright_weight = 28
ij_php_deprecated_weight = 28
ij_php_deprecated_weight = 2
ij_php_do_while_brace_force = always
ij_php_else_if_style = as_is
ij_php_else_on_new_line = true
ij_php_example_weight = 3
ij_php_else_on_new_line = false
ij_php_example_weight = 4
ij_php_extends_keyword_wrap = off
ij_php_extends_list_wrap = off
ij_php_fields_default_visibility = private
@@ -343,6 +349,8 @@ ij_php_for_statement_new_line_after_left_paren = false
ij_php_for_statement_right_paren_on_new_line = false
ij_php_for_statement_wrap = off
ij_php_force_short_declaration_array_style = false
ij_php_getters_setters_naming_style = camel_case
ij_php_getters_setters_order_style = getters_first
ij_php_global_weight = 28
ij_php_group_use_wrap = on_every_item
ij_php_if_brace_force = always
@@ -362,7 +370,8 @@ ij_php_keep_control_statement_in_one_line = true
ij_php_keep_first_column_comment = true
ij_php_keep_indents_on_empty_lines = false
ij_php_keep_line_breaks = true
ij_php_keep_rparen_and_lbrace_on_one_line = true
ij_php_keep_rparen_and_lbrace_on_one_line = false
ij_php_keep_simple_classes_in_one_line = false
ij_php_keep_simple_methods_in_one_line = false
ij_php_lambda_brace_style = end_of_line
ij_php_license_weight = 28
@@ -370,6 +379,7 @@ ij_php_line_comment_add_space = false
ij_php_line_comment_at_first_column = true
ij_php_link_weight = 28
ij_php_lower_case_boolean_const = true
ij_php_lower_case_keywords = true
ij_php_lower_case_null_const = true
ij_php_method_brace_style = next_line
ij_php_method_call_chain_wrap = off
@@ -380,9 +390,11 @@ ij_php_method_weight = 28
ij_php_modifier_list_wrap = false
ij_php_multiline_chained_calls_semicolon_on_new_line = false
ij_php_namespace_brace_style = 1
ij_php_new_line_after_php_opening_tag = false
ij_php_null_type_position = in_the_end
ij_php_package_weight = 28
ij_php_param_weight = 4
ij_php_param_weight = 5
ij_php_parameters_attributes_wrap = off
ij_php_parentheses_expression_new_line_after_left_paren = false
ij_php_parentheses_expression_right_paren_on_new_line = false
ij_php_phpdoc_blank_line_before_tags = true
@@ -399,11 +411,12 @@ ij_php_property_read_weight = 28
ij_php_property_weight = 28
ij_php_property_write_weight = 28
ij_php_return_type_on_new_line = false
ij_php_return_weight = 5
ij_php_see_weight = 2
ij_php_return_weight = 6
ij_php_see_weight = 3
ij_php_since_weight = 28
ij_php_sort_phpdoc_elements = true
ij_php_space_after_colon = true
ij_php_space_after_colon_in_named_argument = true
ij_php_space_after_colon_in_return_type = true
ij_php_space_after_comma = true
ij_php_space_after_for_semicolon = true
@@ -417,6 +430,7 @@ ij_php_space_before_catch_parentheses = true
ij_php_space_before_class_left_brace = true
ij_php_space_before_closure_left_parenthesis = true
ij_php_space_before_colon = true
ij_php_space_before_colon_in_named_argument = false
ij_php_space_before_colon_in_return_type = false
ij_php_space_before_comma = false
ij_php_space_before_do_left_brace = true
@@ -433,6 +447,7 @@ ij_php_space_before_method_call_parentheses = false
ij_php_space_before_method_left_brace = true
ij_php_space_before_method_parentheses = false
ij_php_space_before_quest = true
ij_php_space_before_short_closure_left_parenthesis = false
ij_php_space_before_switch_left_brace = true
ij_php_space_before_switch_parentheses = true
ij_php_space_before_try_left_brace = true
@@ -465,11 +480,11 @@ ij_php_spaces_within_parentheses = false
ij_php_spaces_within_short_echo_tags = true
ij_php_spaces_within_switch_parentheses = false
ij_php_spaces_within_while_parentheses = false
ij_php_special_else_if_treatment = false
ij_php_special_else_if_treatment = true
ij_php_subpackage_weight = 28
ij_php_ternary_operation_signs_on_next_line = false
ij_php_ternary_operation_wrap = off
ij_php_throws_weight = 6
ij_php_throws_weight = 7
ij_php_todo_weight = 28
ij_php_unknown_tag_weight = 28
ij_php_upper_case_boolean_const = false
@@ -481,10 +496,25 @@ ij_php_version_weight = 28
ij_php_while_brace_force = always
ij_php_while_on_new_line = false
[{*.sht,*.htm,*.html,*.shtm,*.shtml}]
[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.stylelintrc,bowerrc,composer.lock,jest.config}]
indent_size = 2
ij_visual_guides = none
ij_json_keep_blank_lines_in_code = 0
ij_json_keep_indents_on_empty_lines = false
ij_json_keep_line_breaks = true
ij_json_space_after_colon = true
ij_json_space_after_comma = true
ij_json_space_before_colon = true
ij_json_space_before_comma = false
ij_json_spaces_within_braces = false
ij_json_spaces_within_brackets = false
ij_json_wrap_long_lines = false
[{*.htm,*.html,*.sht,*.shtm,*.shtml}]
indent_style = tab
ij_smart_tabs = true
ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3
ij_visual_guides = none
ij_html_add_new_line_before_tags = body, div, p, form, h1, h2, h3
ij_html_align_attributes = true
ij_html_align_text = false
ij_html_attribute_wrap = normal
@@ -503,209 +533,24 @@ ij_html_keep_whitespaces_inside = span,pre,textarea
ij_html_line_comment_at_first_column = true
ij_html_new_line_after_last_attribute = never
ij_html_new_line_before_first_attribute = never
ij_html_quote_style = double
ij_html_quote_style = none
ij_html_remove_new_line_before_tags = br
ij_html_space_after_tag_name = false
ij_html_space_around_equality_in_attribute = false
ij_html_space_inside_empty_tag = false
ij_html_text_wrap = normal
ij_html_uniform_ident = false
[{*.ts,*.ats}]
ij_continuation_indent_size = 4
ij_typescript_align_imports = false
ij_typescript_align_multiline_array_initializer_expression = false
ij_typescript_align_multiline_binary_operation = false
ij_typescript_align_multiline_chained_methods = false
ij_typescript_align_multiline_extends_list = false
ij_typescript_align_multiline_for = true
ij_typescript_align_multiline_parameters = true
ij_typescript_align_multiline_parameters_in_calls = false
ij_typescript_align_multiline_ternary_operation = false
ij_typescript_align_object_properties = 0
ij_typescript_align_union_types = false
ij_typescript_align_var_statements = 0
ij_typescript_array_initializer_new_line_after_left_brace = false
ij_typescript_array_initializer_right_brace_on_new_line = false
ij_typescript_array_initializer_wrap = off
ij_typescript_assignment_wrap = off
ij_typescript_binary_operation_sign_on_next_line = false
ij_typescript_binary_operation_wrap = off
ij_typescript_blacklist_imports = rxjs/Rx,node_modules/**/*
ij_typescript_blank_lines_after_imports = 1
ij_typescript_blank_lines_around_class = 1
ij_typescript_blank_lines_around_field = 0
ij_typescript_blank_lines_around_field_in_interface = 0
ij_typescript_blank_lines_around_function = 1
ij_typescript_blank_lines_around_method = 1
ij_typescript_blank_lines_around_method_in_interface = 1
ij_typescript_block_brace_style = end_of_line
ij_typescript_call_parameters_new_line_after_left_paren = false
ij_typescript_call_parameters_right_paren_on_new_line = false
ij_typescript_call_parameters_wrap = off
ij_typescript_catch_on_new_line = false
ij_typescript_chained_call_dot_on_new_line = true
ij_typescript_class_brace_style = end_of_line
ij_typescript_comma_on_new_line = false
ij_typescript_do_while_brace_force = never
ij_typescript_else_on_new_line = false
ij_typescript_enforce_trailing_comma = keep
ij_typescript_extends_keyword_wrap = off
ij_typescript_extends_list_wrap = off
ij_typescript_field_prefix = _
ij_typescript_file_name_style = relaxed
ij_typescript_finally_on_new_line = false
ij_typescript_for_brace_force = never
ij_typescript_for_statement_new_line_after_left_paren = false
ij_typescript_for_statement_right_paren_on_new_line = false
ij_typescript_for_statement_wrap = off
ij_typescript_force_quote_style = false
ij_typescript_force_semicolon_style = false
ij_typescript_function_expression_brace_style = end_of_line
ij_typescript_if_brace_force = never
ij_typescript_import_merge_members = global
ij_typescript_import_prefer_absolute_path = global
ij_typescript_import_sort_members = true
ij_typescript_import_sort_module_name = false
ij_typescript_import_use_node_resolution = true
ij_typescript_imports_wrap = on_every_item
ij_typescript_indent_case_from_switch = true
ij_typescript_indent_chained_calls = true
ij_typescript_indent_package_children = 0
ij_typescript_jsdoc_include_types = false
ij_typescript_jsx_attribute_value = braces
ij_typescript_keep_blank_lines_in_code = 2
ij_typescript_keep_first_column_comment = true
ij_typescript_keep_indents_on_empty_lines = false
ij_typescript_keep_line_breaks = true
ij_typescript_keep_simple_blocks_in_one_line = false
ij_typescript_keep_simple_methods_in_one_line = false
ij_typescript_line_comment_add_space = true
ij_typescript_line_comment_at_first_column = false
ij_typescript_method_brace_style = end_of_line
ij_typescript_method_call_chain_wrap = off
ij_typescript_method_parameters_new_line_after_left_paren = false
ij_typescript_method_parameters_right_paren_on_new_line = false
ij_typescript_method_parameters_wrap = off
ij_typescript_object_literal_wrap = on_every_item
ij_typescript_parentheses_expression_new_line_after_left_paren = false
ij_typescript_parentheses_expression_right_paren_on_new_line = false
ij_typescript_place_assignment_sign_on_next_line = false
ij_typescript_prefer_as_type_cast = false
ij_typescript_prefer_parameters_wrap = false
ij_typescript_reformat_c_style_comments = false
ij_typescript_space_after_colon = true
ij_typescript_space_after_comma = true
ij_typescript_space_after_dots_in_rest_parameter = false
ij_typescript_space_after_generator_mult = true
ij_typescript_space_after_property_colon = true
ij_typescript_space_after_quest = true
ij_typescript_space_after_type_colon = true
ij_typescript_space_after_unary_not = false
ij_typescript_space_before_async_arrow_lparen = true
ij_typescript_space_before_catch_keyword = true
ij_typescript_space_before_catch_left_brace = true
ij_typescript_space_before_catch_parentheses = true
ij_typescript_space_before_class_lbrace = true
ij_typescript_space_before_class_left_brace = true
ij_typescript_space_before_colon = true
ij_typescript_space_before_comma = false
ij_typescript_space_before_do_left_brace = true
ij_typescript_space_before_else_keyword = true
ij_typescript_space_before_else_left_brace = true
ij_typescript_space_before_finally_keyword = true
ij_typescript_space_before_finally_left_brace = true
ij_typescript_space_before_for_left_brace = true
ij_typescript_space_before_for_parentheses = true
ij_typescript_space_before_for_semicolon = false
ij_typescript_space_before_function_left_parenth = true
ij_typescript_space_before_generator_mult = false
ij_typescript_space_before_if_left_brace = true
ij_typescript_space_before_if_parentheses = true
ij_typescript_space_before_method_call_parentheses = false
ij_typescript_space_before_method_left_brace = true
ij_typescript_space_before_method_parentheses = false
ij_typescript_space_before_property_colon = false
ij_typescript_space_before_quest = true
ij_typescript_space_before_switch_left_brace = true
ij_typescript_space_before_switch_parentheses = true
ij_typescript_space_before_try_left_brace = true
ij_typescript_space_before_type_colon = false
ij_typescript_space_before_unary_not = false
ij_typescript_space_before_while_keyword = true
ij_typescript_space_before_while_left_brace = true
ij_typescript_space_before_while_parentheses = true
ij_typescript_spaces_around_additive_operators = true
ij_typescript_spaces_around_arrow_function_operator = true
ij_typescript_spaces_around_assignment_operators = true
ij_typescript_spaces_around_bitwise_operators = true
ij_typescript_spaces_around_equality_operators = true
ij_typescript_spaces_around_logical_operators = true
ij_typescript_spaces_around_multiplicative_operators = true
ij_typescript_spaces_around_relational_operators = true
ij_typescript_spaces_around_shift_operators = true
ij_typescript_spaces_around_unary_operator = false
ij_typescript_spaces_within_array_initializer_brackets = false
ij_typescript_spaces_within_brackets = false
ij_typescript_spaces_within_catch_parentheses = false
ij_typescript_spaces_within_for_parentheses = false
ij_typescript_spaces_within_if_parentheses = false
ij_typescript_spaces_within_imports = false
ij_typescript_spaces_within_interpolation_expressions = false
ij_typescript_spaces_within_method_call_parentheses = false
ij_typescript_spaces_within_method_parentheses = false
ij_typescript_spaces_within_object_literal_braces = false
ij_typescript_spaces_within_object_type_braces = true
ij_typescript_spaces_within_parentheses = false
ij_typescript_spaces_within_switch_parentheses = false
ij_typescript_spaces_within_type_assertion = false
ij_typescript_spaces_within_union_types = true
ij_typescript_spaces_within_while_parentheses = false
ij_typescript_special_else_if_treatment = true
ij_typescript_ternary_operation_signs_on_next_line = false
ij_typescript_ternary_operation_wrap = off
ij_typescript_union_types_wrap = on_every_item
ij_typescript_use_chained_calls_group_indents = false
ij_typescript_use_double_quotes = true
ij_typescript_use_explicit_js_extension = global
ij_typescript_use_path_mapping = always
ij_typescript_use_public_modifier = false
ij_typescript_use_semicolon_after_statement = true
ij_typescript_var_declaration_wrap = normal
ij_typescript_while_brace_force = never
ij_typescript_while_on_new_line = false
ij_typescript_wrap_comments = false
[{*.yml,*.yaml}]
[{*.yaml, *.yml}]
indent_size = 2
ij_continuation_indent_size = 2
ij_visual_guides = none
ij_yaml_align_values_properties = do_not_align
ij_yaml_autoinsert_sequence_marker = true
ij_yaml_block_mapping_on_new_line = false
ij_yaml_indent_sequence_value = true
ij_yaml_keep_indents_on_empty_lines = false
ij_yaml_keep_line_breaks = true
[{*.zsh,*.bash,*.sh}]
ij_shell_binary_ops_start_line = false
ij_shell_keep_column_alignment_padding = false
ij_shell_minify_program = false
ij_shell_redirect_followed_by_space = false
ij_shell_switch_cases_indented = false
[{.stylelintrc,.eslintrc,.babelrc,jest.config,*.bowerrc,*.jsb3,*.jsb2,*.json}]
indent_size = 2
ij_json_keep_blank_lines_in_code = 0
ij_json_keep_indents_on_empty_lines = false
ij_json_keep_line_breaks = true
ij_json_space_after_colon = true
ij_json_space_after_comma = true
ij_json_space_before_colon = true
ij_json_space_before_comma = false
ij_json_spaces_within_braces = false
ij_json_spaces_within_brackets = false
ij_json_wrap_long_lines = false
[{phpunit.xml.dist,*.jhm,*.rng,*.wsdl,*.fxml,*.xslt,*.jrxml,*.ant,*.xul,*.xsl,*.xsd,*.tld,*.jnlp,*.xml}]
indent_size = 2
indent_style = tab
tab_width = 2
ij_smart_tabs = true
ij_xml_block_comment_at_first_column = true
ij_xml_keep_indents_on_empty_lines = false
ij_xml_line_comment_at_first_column = true
ij_yaml_sequence_on_new_line = false
ij_yaml_space_before_colon = false
ij_yaml_spaces_within_braces = true
ij_yaml_spaces_within_brackets = true

View File

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

14
.gitignore vendored
View File

@@ -3,19 +3,15 @@
/toolkit
/env-*
# maintenance mode (N°2240)
/.maintenance
# listing prevention in conf directory
/conf/**
!/conf/.htaccess
!/conf/index.php
!/conf/web.config
# composer reserver directory, from sources, populate/update using "composer install"
vendor/*
test/vendor/*
# all conf but listing prevention
/conf/**
!/conf/.htaccess
!/conf/web.config
# all datas but listing prevention
/data/**
!/data/.htaccess

View File

@@ -1,56 +1,37 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="LINE_SEPARATOR" value="&#10;" />
<option name="RIGHT_MARGIN" value="140" />
<option name="WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN" value="true" />
<option name="SOFT_MARGINS" value="140" />
<option name="RIGHT_MARGIN" value="320" />
<HTMLCodeStyleSettings>
<option name="HTML_DO_NOT_INDENT_CHILDREN_OF" value="html,body,thead,tbody,tfoot,style,script,head" />
<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>
<JSCodeStyleSettings version="0">
<option name="USE_CHAINED_CALLS_GROUP_INDENTS" value="true" />
</JSCodeStyleSettings>
<PHPCodeStyleSettings>
<option name="CONCAT_SPACES" value="false" />
<option name="COMMA_AFTER_LAST_ARRAY_ELEMENT" value="true" />
<option name="PHPDOC_BLANK_LINE_BEFORE_TAGS" value="true" />
<option name="PHPDOC_BLANK_LINES_AROUND_PARAMETERS" value="true" />
<option name="PHPDOC_WRAP_LONG_LINES" value="true" />
<option name="THROWS_WEIGHT" value="6" />
<option name="PARAM_WEIGHT" value="4" />
<option name="RETURN_WEIGHT" value="5" />
<option name="AUTHOR_WEIGHT" value="7" />
<option name="INTERNAL_WEIGHT" value="0" />
<option name="API_WEIGHT" value="1" />
<option name="EXAMPLE_WEIGHT" value="3" />
<option name="SEE_WEIGHT" value="2" />
<option name="LOWER_CASE_BOOLEAN_CONST" value="true" />
<option name="LOWER_CASE_NULL_CONST" value="true" />
<option name="BLANK_LINES_BEFORE_RETURN_STATEMENT" value="1" />
<option name="KEEP_RPAREN_AND_LBRACE_ON_ONE_LINE" value="true" />
<option name="PHPDOC_USE_FQCN" value="true" />
</PHPCodeStyleSettings>
<XML>
<option name="XML_TEXT_WRAP" value="0" />
<option name="XML_KEEP_LINE_BREAKS" value="false" />
<option name="XML_KEEP_WHITE_SPACES_INSIDE_CDATA" value="true" />
</XML>
<codeStyleSettings language="JavaScript">
<option name="BRACE_STYLE" value="2" />
<option name="ELSE_ON_NEW_LINE" value="true" />
<option name="SPACE_AROUND_ADDITIVE_OPERATORS" value="false" />
<option name="IF_BRACE_FORCE" value="3" />
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />
</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" />
<option name="CATCH_ON_NEW_LINE" value="true" />
<option name="FINALLY_ON_NEW_LINE" value="true" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="SPACE_BEFORE_FOR_PARENTHESES" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
@@ -68,7 +49,9 @@
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="XML">
<option name="WRAP_ON_TYPING" value="1" />
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

View File

@@ -1,81 +1,10 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Combodo" />
<inspection_tool class="CascadeStringReplacementInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ForgottenDebugOutputInspection" enabled="true" level="ERROR" enabled_by_default="true">
<option name="configuration">
<list>
<option value="\Codeception\Util\Debug::debug" />
<option value="\Codeception\Util\Debug::pause" />
<option value="\Doctrine\Common\Util\Debug::dump" />
<option value="\Doctrine\Common\Util\Debug::export" />
<option value="\Illuminate\Support\Debug\Dumper::dump" />
<option value="\Symfony\Component\Debug\Debug::enable" />
<option value="\Symfony\Component\Debug\DebugClassLoader::enable" />
<option value="\Symfony\Component\Debug\ErrorHandler::register" />
<option value="\Symfony\Component\Debug\ExceptionHandler::register" />
<option value="\TYPO3\CMS\Core\Utility\DebugUtility::debug" />
<option value="\Zend\Debug\Debug::dump" />
<option value="\Zend\Di\Display\Console::export" />
<option value="dd" />
<option value="debug_print_backtrace" />
<option value="debug_zval_dump" />
<option value="dpm" />
<option value="dpq" />
<option value="dsm" />
<option value="dump" />
<option value="dvm" />
<option value="error_log" />
<option value="kpr" />
<option value="phpinfo" />
<option value="print_r" />
<option value="var_dump" />
<option value="var_export" />
<option value="xdebug_break" />
<option value="xdebug_call_class" />
<option value="xdebug_call_file" />
<option value="xdebug_call_function" />
<option value="xdebug_call_line" />
<option value="xdebug_code_coverage_started" />
<option value="xdebug_debug_zval" />
<option value="xdebug_debug_zval_stdout" />
<option value="xdebug_dump_superglobals" />
<option value="xdebug_enable" />
<option value="xdebug_get_code_coverage" />
<option value="xdebug_get_collected_errors" />
<option value="xdebug_get_declared_vars" />
<option value="xdebug_get_function_stack" />
<option value="xdebug_get_headers" />
<option value="xdebug_get_monitored_functions" />
<option value="xdebug_get_profiler_filename" />
<option value="xdebug_get_stack_depth" />
<option value="xdebug_get_tracefile_name" />
<option value="xdebug_is_enabled" />
<option value="xdebug_memory_usage" />
<option value="xdebug_peak_memory_usage" />
<option value="xdebug_print_function_stack" />
<option value="xdebug_start_code_coverage" />
<option value="xdebug_start_error_collection" />
<option value="xdebug_start_function_monitor" />
<option value="xdebug_start_trace" />
<option value="xdebug_stop_code_coverage" />
<option value="xdebug_stop_error_collection" />
<option value="xdebug_stop_function_monitor" />
<option value="xdebug_stop_trace" />
<option value="xdebug_time_index" />
<option value="xdebug_var_dump" />
</list>
</option>
<option name="migratedIntoUserSpace" value="true" />
</inspection_tool>
<inspection_tool class="HtmlRequiredAltAttribute" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="HtmlRequiredLangAttribute" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<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="PhpComposerExtensionStubsInspection" 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="PhpShortOpenTagInspection" 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>
@@ -90,61 +19,6 @@
<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="SecurityAdvisoriesInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="optionConfiguration">
<list>
<option value="barryvdh/laravel-debugbar" />
<option value="behat/behat" />
<option value="brianium/paratest" />
<option value="codeception/codeception" />
<option value="codedungeon/phpunit-result-printer" />
<option value="composer/composer" />
<option value="doctrine/coding-standard" />
<option value="filp/whoops" />
<option value="friendsofphp/php-cs-fixer" />
<option value="humbug/humbug" />
<option value="infection/infection" />
<option value="jakub-onderka/php-parallel-lint" />
<option value="johnkary/phpunit-speedtrap" />
<option value="kalessil/production-dependencies-guard" />
<option value="mikey179/vfsStream" />
<option value="mockery/mockery" />
<option value="mybuilder/phpunit-accelerator" />
<option value="orchestra/testbench" />
<option value="pdepend/pdepend" />
<option value="phan/phan" />
<option value="phing/phing" />
<option value="phpcompatibility/php-compatibility" />
<option value="phpmd/phpmd" />
<option value="phpro/grumphp" />
<option value="phpspec/phpspec" />
<option value="phpspec/prophecy" />
<option value="phpstan/phpstan" />
<option value="phpunit/phpunit" />
<option value="povils/phpmnd" />
<option value="roave/security-advisories" />
<option value="satooshi/php-coveralls" />
<option value="sebastian/phpcpd" />
<option value="slevomat/coding-standard" />
<option value="spatie/phpunit-watcher" />
<option value="squizlabs/php_codesniffer" />
<option value="sstalle/php7cc" />
<option value="symfony/debug" />
<option value="symfony/maker-bundle" />
<option value="symfony/phpunit-bridge" />
<option value="symfony/var-dumper" />
<option value="vimeo/psalm" />
<option value="wimg/php-compatibility" />
<option value="wp-coding-standards/wpcs" />
<option value="yiisoft/yii2-coding-standards" />
<option value="yiisoft/yii2-debug" />
<option value="yiisoft/yii2-gii" />
<option value="zendframework/zend-coding-standard" />
<option value="zendframework/zend-debug" />
<option value="zendframework/zend-test" />
</list>
</option>
</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" />

View File

@@ -1,16 +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 https://www.combodo.com/documentation/iTopDataModelToolkit-2.3.zip > toolkit.zip
unzip toolkit.zip
rm toolkit.zip
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 -a # => Not needed anymore (libs were added to git with N°2435)
# under the test dir
cd test
composer install

View File

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

View File

@@ -1,22 +0,0 @@
#!/usr/bin/env bash
set -x
cd test
export DEBUG_UNIT_TEST=0
RUN_NONREG_TESTS=0
if [ $# -ge 1 -a "x$1" == "xtrue" ]
then
export DEBUG_UNIT_TEST=1
else
export DEBUG_UNIT_TEST=0
fi
if [ $# -ge 2 -a "x$2" == "xtrue" ]
then
php vendor/bin/phpunit --log-junit ../var/test/phpunit-log.junit.xml --teamcity
else
#echo php vendor/bin/phpunit --log-junit ../var/test/phpunit-log.junit.xml --teamcity
php vendor/bin/phpunit --log-junit ../var/test/phpunit-log.junit.xml --exclude-group OQL --teamcity
fi

View File

@@ -1,8 +0,0 @@
#!/usr/bin/env bash
set -x
chmod 666 conf/production/config-itop.php
cd toolkit
php unattended_install.php --response_file=default-params.xml --clean=true

View File

@@ -1,284 +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',
'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',
// 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(
'authent-local' => array (
'password_validation.pattern' => '',
),
'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,208 +0,0 @@
<?php
/**
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
//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,6 +0,0 @@
= Make Doc =
.make folder is meant to gather tools for releasing process. Maybe other new purposes will come as well....
== license ==
- updateLicenses.php: used to update community-licenses.xml easily based on composer.json files
- sortLicenceXml.php: used to sort licenses based on scope + product name

View File

@@ -1,84 +0,0 @@
#/bin/bash
#git diff --name-status 2.6.2..HEAD js |grep 'A\sjs/' |awk -F/ '{printf("lib/%s/%s\n",$2,$3)}'|sort |uniq >/tmp/toto
#git diff --name-status 2.6.2..HEAD lib |grep 'A\slib/' |awk -F/ '{printf("lib/%s/%s\n",$2,$3)}'|sort |uniq >/tmp/toto
function HELP(){
echo " Syntax: bash $0 /var/www/html/iTop"
}
if [ $# -eq 0 ]
then
echo "no iTop path provided"
HELP
exit 1
fi
iTopPath=$1
if [ ! -d $iTopPath ]
then
echo "$iTopPath is not an iTop path."
HELP
exit 1
fi
echo "<?xml version=\"1.0\"?>
<licenses>"
for subfolder in lib datamodels
do
for l in $(find $iTopPath/$subfolder/ -name composer.json|sed 's|/composer.json||')
do
if [ ! -d $l ]
then
continue
fi
dir=$(dirname $(dirname $l))
prod=$(echo $l| sed "s|$dir/||1")
echo $l $subfolder
lictype=$(cd $l && composer licenses --format json |jq .license[] |sed 's|\"||g')
authors=""
if [ -f $l/composer.json ]
then
author_nb=$(grep -c authors $l/composer.json|sed 's| ||g')
if [ "x$author_nb" != "x0" ]
then
OLDIFS=$IFS
IFS=$'\n'
for a in $(cat $l/composer.json |jq .authors[].name|sed 's|\"||g')
do
authors="$authors$a - "
done
authors="$authors#"
authors=$(echo $authors |sed 's| - #||')
IFS=$OLDIFS
fi
fi
lic=""
for licf in $(find $l -name LICEN*)
do
lic=$(cat $licf)
break
done
#if [ "x$lic" == "x" ]
#then
# echo "============== no license found $l"
#fi
echo " <license>
<product scope=\"$subfolder\">$prod</product>
<author>$authors</author>
<license_type>$lictype</license_type>
<text><![CDATA[
$lic
]]></text>
</license>"
done
done
echo "</licenses>"

View File

@@ -1,64 +0,0 @@
<?php
/**
* script used to sort license file (usefull for autogeneration)
* Example:
*/
$iTopFolder = __DIR__ . "/../../" ;
$xmlFilePath = $iTopFolder . "setup/licenses/community-licenses.xml";
$dom = new DOMDocument();
$dom->load($xmlFilePath);
$xp = new DOMXPath($dom);
$licenseList = $xp->query('/licenses/license');
$licenses = iterator_to_array($licenseList);
function get_scope($product_node)
{
$scope = $product_node->getAttribute("scope");
if ($scope === "")
{ //put iTop first
return "aaaaaaaaa";
}
return $scope;
}
function get_product_node($license_node)
{
foreach ($license_node->childNodes as $child)
{
if (is_a($child, 'DomElement') && $child->tagName === "product")
{
return $child;
}
}
return null;
}
function sort_by_product($a, $b)
{
$aProductNode = get_product_node($a);
$bProductNode = get_product_node($b);
$res = strcmp(get_scope($aProductNode), get_scope($bProductNode));
if ($res !== 0)
{
return $res;
}
//sort on node product name
return strcmp($aProductNode->nodeValue, $bProductNode->nodeValue);
}
usort($licenses, 'sort_by_product');
$newdom = new DOMDocument("1.0");
$newdom->formatOutput = true;
$root = $newdom->createElement("licenses");
$newdom->appendChild($root);
foreach ($licenses as $b) {
$node = $newdom->importNode($b,true);
$root->appendChild($newdom->importNode($b,true));
}
$newdom->save($xmlFilePath);

View File

@@ -1,89 +0,0 @@
<?php
/**
* script used to sort license file (usefull for autogeneration)
* Example: php
*/
$iTopFolder = __DIR__ . "/../../" ;
$xmlFilePath = $iTopFolder . "setup/licenses/community-licenses.xml";
function get_scope($product_node)
{
$scope = $product_node->getAttribute("scope");
if ($scope === "")
{ //put iTop first
return "aaaaaaaaa";
}
return $scope;
}
function get_product_node($license_node)
{
foreach ($license_node->childNodes as $child)
{
if (is_a($child, 'DomElement') && $child->tagName === "product")
{
return $child;
}
}
return null;
}
function sort_by_product($a, $b)
{
$aProductNode = get_product_node($a);
$bProductNode = get_product_node($b);
$res = strcmp(get_scope($aProductNode), get_scope($bProductNode));
if ($res !== 0)
{
return $res;
}
//sort on node product name
return strcmp($aProductNode->nodeValue, $bProductNode->nodeValue);
}
function get_license_nodes($file_path)
{
$dom = new DOMDocument();
$dom->load($file_path);
$xp = new DOMXPath($dom);
$licenseList = $xp->query('/licenses/license');
$licenses = iterator_to_array($licenseList);
usort($licenses, 'sort_by_product');
return $licenses;
}
$old_licenses = get_license_nodes($xmlFilePath);
//generate file with updated licenses
$generated_license_file_path = __DIR__."/provfile.xml";
exec("bash " . __DIR__ . "/gen-community-license.sh $iTopFolder > ". $generated_license_file_path);
$new_licenses = get_license_nodes($generated_license_file_path);
exec("rm -f ". $generated_license_file_path);
foreach ($old_licenses as $b) {
$aProductNode = get_product_node($b);
if (get_scope($aProductNode) !== "lib" && get_scope($aProductNode) !== "datamodels" )
{
$new_licenses[] = $b;
}
}
usort($new_licenses, 'sort_by_product');
$new_dom = new DOMDocument("1.0");
$new_dom->formatOutput = true;
$root = $new_dom->createElement("licenses");
$new_dom->appendChild($root);
foreach ($new_licenses as $b) {
$node = $new_dom->importNode($b,true);
$root->appendChild($new_dom->importNode($b,true));
}
$new_dom->save($xmlFilePath);

View File

@@ -0,0 +1,47 @@
<?php
/*******************************************************************************
* Tool to automate version update before release
*
* Will update version in the following files :
*
* * datamodels/2.x/.../module.*.php
* * datamodels/2.x/version.xml
* * css/css-variables.scss $version
*
* Usage :
* `php .make\release\update-versions.php "2.7.0-rc"`
*
* @since 2.7.0
******************************************************************************/
require_once (__DIR__.'/../../approot.inc.php');
require_once (__DIR__.DIRECTORY_SEPARATOR.'update.classes.inc.php');
/** @var \FileVersionUpdater[] $aFilesUpdaters */
$aFilesUpdaters = array(
new iTopVersionFileUpdater(),
new CssVariablesFileUpdater(),
new DatamodelsModulesFiles(),
);
if (count($argv) === 1)
{
echo '/!\ You must pass the new version as parameter';
exit(1);
}
$sVersionLabel = $argv[1];
if (empty($sVersionLabel))
{
echo 'Version passed as parameter is empty !';
exit(2);
}
foreach ($aFilesUpdaters as $oFileVersionUpdater)
{
$oFileVersionUpdater->UpdateAllFiles($sVersionLabel);
}

View File

@@ -0,0 +1,36 @@
<?php
/*******************************************************************************
* Tool to automate datamodel version update in XML
*
* Will update version in the following files :
*
* datamodels/2.x/.../datamodel.*.xml
*
* Usage :
* `php .make\release\update-xml.php "1.7"`
*
* @since 2.7.0
******************************************************************************/
require_once (__DIR__.'/../../approot.inc.php');
require_once (__DIR__.DIRECTORY_SEPARATOR.'update.classes.inc.php');
if (count($argv) === 1)
{
echo '/!\ You must pass the new version as parameter';
exit(1);
}
$sVersionLabel = $argv[1];
if (empty($sVersionLabel))
{
echo 'Version passed as parameter is empty !';
exit(2);
}
$oFileVersionUpdater = new DatamodelsXmlFiles();
$oFileVersionUpdater->UpdateAllFiles($sVersionLabel);

View File

@@ -0,0 +1,169 @@
<?php
/*******************************************************************************
* Classes for updater tools
*
* @see update-versions.php
* @see update-xml.php
******************************************************************************/
require_once (__DIR__.'/../../approot.inc.php');
abstract class FileVersionUpdater
{
/**
* @return string[] full path of files to modify
*/
abstract public function GetFiles();
/**
* Warnign : will consume lots of memory on larger files !
*
* @param string $sVersionLabel
* @param string $sFileContent
* @param string $sFileFullPath
*
* @return string file content with replaced values
*/
abstract public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath);
public function UpdateAllFiles($sVersionLabel)
{
$aFilesToUpdate = $this->GetFiles();
$sFileUpdaterName = get_class($this);
echo "# Updater : $sFileUpdaterName\n";
foreach ($aFilesToUpdate as $sFileToUpdateFullPath)
{
try
{
$sCurrentFileContent = file_get_contents($sFileToUpdateFullPath);
$sNewFileContent = $this->UpdateFileContent($sVersionLabel, $sCurrentFileContent, $sFileToUpdateFullPath);
file_put_contents($sFileToUpdateFullPath, $sNewFileContent);
echo " - $sFileToUpdateFullPath : OK !\n";
}
catch (Exception $e)
{
echo " - $sFileToUpdateFullPath : Error :(\n";
}
}
}
}
abstract class AbstractSingleFileVersionUpdater extends FileVersionUpdater
{
private $sFileToUpdate;
public function __construct($sFileToUpdate)
{
$this->sFileToUpdate = $sFileToUpdate;
}
public function GetFiles()
{
return array(APPROOT.$this->sFileToUpdate);
}
}
class iTopVersionFileUpdater extends AbstractSingleFileVersionUpdater
{
public function __construct()
{
parent::__construct('datamodels/2.x/version.xml');
}
/**
* @inheritDoc
*/
public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath)
{
return preg_replace(
'/(<version>)[^<]*(<\/version>)/',
'${1}'.$sVersionLabel.'${2}',
$sFileContent
);
}
}
class CssVariablesFileUpdater extends AbstractSingleFileVersionUpdater
{
public function __construct()
{
parent::__construct('css/css-variables.scss');
}
/**
* @inheritDoc
*/
public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath)
{
return preg_replace(
'/(\$version: "v)[^"]*(";)/',
'${1}'.$sVersionLabel.'${2}',
$sFileContent
);
}
}
abstract class AbstractGlobFileVersionUpdater extends FileVersionUpdater
{
protected $sGlobPattern;
public function __construct($sGlobPattern)
{
$this->sGlobPattern = $sGlobPattern;
}
public function GetFiles()
{
return glob($this->sGlobPattern);
}
}
class DatamodelsModulesFiles extends AbstractGlobFileVersionUpdater
{
public function __construct()
{
parent::__construct(APPROOT.'datamodels/2.x/*/module.*.php');
}
/**
* @inheritDoc
*/
public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath)
{
$sModulePath = realpath($sFileFullPath);
$sModuleFileName = basename($sModulePath, 1);
$sModuleName = preg_replace('/[^.]+\.([^.]+)\.php/', '$1', $sModuleFileName);
return preg_replace(
"/('$sModuleName\/)[^']+(')/",
'${1}'.$sVersionLabel.'${2}',
$sFileContent
);
}
}
class DatamodelsXmlFiles extends AbstractGlobFileVersionUpdater
{
public function __construct()
{
parent::__construct(APPROOT.'datamodels/2.x/*/datamodel.*.xml');
}
/**
* @inheritDoc
*/
public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath)
{
return preg_replace(
'/(<itop_design .* version=")[^"]+(">)/',
'${1}'.$sVersionLabel.'${2}',
$sFileContent
);
}
}

View File

@@ -1,128 +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
* 🌐 `: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.
For all **security related subjects**, please see our [security policy](SECURITY.md).
All **datamodel modification** should be done in an extension. Beware that such change would
impact all existing customers, and could prevent them from
upgrading!
Combodo has a long experience of datamodel changes: they are very disruptive!
This is why we avoid them in iTop core, especially the changes on existing objects/fields.
If you have an idea you're sure would benefit to all of iTop users, you may
[create a corresponding ticket](https://sourceforge.net/p/itop/tickets/new/) to submit it, but be warned that there are lots of good
reasons to refuse such changes.
### License
iTop is distributed under the AGPL-3.0 license (see the [license.txt] file),
your code must comply with this license.
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 the develop branch**
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
- support/\*: maintenance branches for older versions
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
- support/2.6 containing 2.6.x maintenance version
- support/2.5 containing 2.5.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
- support/2.6 containing 2.6.x maintenance version
- support/2.5 containing 2.5.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
- support/2.6 containing 2.6.x maintenance version
- support/2.5 containing 2.5.x maintenance version
Most of the time you should based your developments on the develop branch.
That may be different if you want to fix a bug, please use develop anyway and ask in your PR if rebase is possible.
## 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/)).
Beware to use the code (for example `:bug:`) and not the character (🐛) as Unicode support in git clients is very poor for now...
Emoji examples :
* 🌐 `:globe_with_meridians:` for translations
* 🎨 `:art:` when improving the format/structure of the code
* ⚡️ `:zap:` when improving performance
* 🐛 `: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/).

74
Jenkinsfile vendored
View File

@@ -1,69 +1,11 @@
pipeline {
agent any
parameters {
booleanParam(name: 'debugMode', defaultValue: 'false', description: 'Debug mode?')
booleanParam(name: 'runNonRegOQLTests', defaultValue: 'false', description: 'Do You want to run legacy OQL regression tests?')
}
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 ${debugMode} ${runNonRegOQLTests}'
}
}
}
}
}
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()

146
README.md
View File

@@ -21,101 +21,36 @@ iTop also offers mass import tools and web services to integrate with your IT
- [Data synchronization][18] (for data federation)
## Latest release
- [Changes since the previous version][62]
- [New features][63]
- [Installation notes][64]
- [Download][65]
[62]: https://www.itophub.io/wiki/page?id=latest:release:change_log
[63]: https://www.itophub.io/wiki/page?id=latest:release:start
[64]: https://www.itophub.io/wiki/page?id=latest:install:start
[65]: https://sourceforge.net/projects/itop/files/latest/download
## Resources
- [iTop Forums][1]: community support
- [iTop Forums][1]: for support request
- [iTop Tickets][2]: for feature requests and bug reports
- [Releases download][3]
- [Documentation][4] covering both iTop and its official extensions
- [iTop Hub][5] : discover and install extensions !
- [iTop documentation][4] for iTop and official extensions
- [iTop extensions][5] for discovering and installing extensions
[1]: https://sourceforge.net/p/itop/discussion/
[2]: https://sourceforge.net/p/itop/tickets/
[3]: https://sourceforge.net/projects/itop/files/itop/
[4]: https://www.itophub.io/wiki
[5]: https://store.itophub.io/en_US/
[10]: https://www.itophub.io/wiki/page?id=latest%3Adatamodel%3Astart#configuration_management_cmdb
[11]: https://www.itophub.io/wiki/page?id=latest%3Adatamodel%3Astart#ticketing
[12]: https://www.itophub.io/wiki/page?id=latest%3Adatamodel%3Astart#service_management
[13]: https://www.itophub.io/wiki/page?id=latest%3Adatamodel%3Astart#change_management
[14]: https://www.itophub.io/wiki/page?id=latest%3Aimplementation%3Astart#service_level_agreements_and_targets
[15]: https://www.itophub.io/wiki/page?id=latest%3Auser%3Aactions#relations
[16]: https://www.itophub.io/wiki/page?id=latest%3Auser%3Abulk_modify#uploading_data
[17]: https://www.itophub.io/wiki/page?id=latest%3Aadmin%3Aaudit
[18]: https://www.itophub.io/wiki/page?id=latest%3Aadvancedtopics%3Adata_synchro_overview
## Last releases
### Versions 2.7.*
- 2.7.0-beta published on December 18, 2019
- [Changes since the previous version][62]
- [New features][63]
- [Migration notes][64]
- [Download iTop 2.7.0-beta][65]
[62]: https://www.itophub.io/wiki/page?id=2_7_0:release:change_log
[63]: https://www.itophub.io/wiki/page?id=2_7_0:release:2_7_whats_new
[64]: https://www.itophub.io/wiki/page?id=2_7_0:install:260_to_270_migration_notes
[65]: https://sourceforge.net/projects/itop/files/itop/2.7.0-beta
### Versions 2.6.*
- 2.6.0 published on January 9, 2019
- [Changes since the previous version][58]
- [New features][59]
- [Migration notes][60]
- [Download iTop 2.6.1][61]
[58]: https://www.itophub.io/wiki/page?id=2_6_0:release:change_log
[59]: https://www.itophub.io/wiki/page?id=2_6_0:release:2_6_whats_new
[60]: https://www.itophub.io/wiki/page?id=2_6_0:install:250_to_260_migration_notes
[61]: https://sourceforge.net/projects/itop/files/itop/2.6.1
### Versions 2.5.*
- 2.5.0 published on July 11, 2018
- [Changes since the previous version][54]
- [New features][55]
- [Migration notes][56]
- [Download iTop 2.5.1][57]
[54]: https://www.itophub.io/wiki/page?id=2_5_0:release:change_log
[55]: https://www.itophub.io/wiki/page?id=2_5_0:release:2_5_whats_new
[56]: https://www.itophub.io/wiki/page?id=2_5_0:install:240_to_250_migration_notes
[57]: https://sourceforge.net/projects/itop/files/itop/2.5.1
### Versions 2.4.*
- 2.4.0 published on November 16, 2017
- [Changes since the previous version][50]
- [New features][51]
- [Migration notes][52]
- [Download iTop 2.4.1][53]
[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
## About Us
# About Us
iTop development is sponsored, led and supported by [Combodo][0].
[0]: https://www.combodo.com
## Contributors
# Contributors
We would like to give a special thank you to the people from the community who contributed to this project, including:
### Names
- Alves, David
- Beck, Pedro
- Bilger, Jean-François
@@ -125,7 +60,6 @@ We would like to give a special thank you to the people from the community who c
- Casteleyn, Thomas
- Castro, Randall Badilla
- Colantoni, Maria Laura
- Couronné, Guy
- Dvořák, Lukáš
- Goethals, Stefan
- Gumble, David
@@ -135,7 +69,6 @@ We would like to give a special thank you to the people from the community who c
- Konečný, Kamil
- Kunin, Vladimir
- Lassiter, Dennis
- Lazcano, Federico
- Lucas, Jonathan
- Malik, Remie
- Rosenke, Stephan
@@ -144,7 +77,7 @@ We would like to give a special thank you to the people from the community who c
- Tulio, Marco
- Turrubiates, Miguel
### Aliases
#### Aliases
- chifu1234
- cprobst
- Karkoff1212
@@ -155,8 +88,45 @@ We would like to give a special thank you to the people from the community who c
- theBigOne
- ulmerspatz
### Companies
#### Companies
- Hardis
- ITOMIG
- Pimkie
[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.3

View File

@@ -1,36 +0,0 @@
# 🔒 Reporting vulnerabilities
We take all security bugs seriously. Thank you for improving the security of iTop! We appreciate your efforts and
responsible disclosure and will make every effort to acknowledge your contributions.
## ✉️ How to report
### iTop vulnerabilities
Please send a procedure to reproduce iTop vulnerabilities to [itop-security@combodo.com](mailto:itop-security@combodo.com).
You can send us a standard "given / then / when" report, including iTop version, impacts, and maybe installed modules or data if they are
needed to reproduce.
### Dependencies vulnerabilities
Report security bugs in third-party modules to the person or team maintaining the module, and notify us of this report by sending an email
to [itop-security@combodo.com](mailto:itop-security@combodo.com).
## 📆 Disclosure Policy
Report sent to us will be acknowledged within the week.
Then, a Combodo developer will be assigned to the reported issue and will:
* confirm the problem and determine the affected iTop versions
* audit the code to search any potential similar problems
* try to find a workaround if any
* create fixes for all releases still under maintenance
* send you the commit(s) for review
* send you the next version(s) that will contain the fix, and the estimated release dates
Security issues always take precedence over bug fixes and feature work.
The assignee will keep you informed of the resolution progress, and may ask you for additional information or guidance.

View File

@@ -121,15 +121,20 @@ class UserRightsMatrix extends UserRightsAddOnAPI
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
{
// Maybe we should check that no other user with userid == 0 exists
CMDBObject::SetTrackInfo('Initialization');
$oUser = new UserLocal();
$oUser->Set('login', $sAdminUser);
$oUser->Set('password', $sAdminPwd);
$oUser->Set('contactid', 1); // one is for root !
$oUser->Set('language', $sLanguage); // Language was chosen during the installation
// Create a change to record the history of the User object
$oChange = MetaModel::NewObject("CMDBChange");
$oChange->Set("date", time());
$oChange->Set("userinfo", "Initialization");
$iChangeId = $oChange->DBInsert();
// Now record the admin user object
$iUserId = $oUser->DBInsertNoReload();
$iUserId = $oUser->DBInsertTrackedNoReload($oChange, true /* skip security */);
$this->SetupUser($iUserId, true);
return true;
}

View File

@@ -1,20 +1,27 @@
<?php
// Copyright (C) 2010-2013 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/>
/**
* Copyright (C) 2013-2020 Combodo SARL
* UserRightsProfile
* User management Module, basing the right on profiles and a matrix (similar to UserRightsMatrix, but profiles and other decorations have been added)
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
define('ADMIN_PROFILE_NAME', 'Administrator');
@@ -172,7 +179,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
parent::DisplayBareRelations($oPage, $bEditMode);
if (!$bEditMode)
{
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
$oPage->SetCurrentTab(Dict::S('UI:UserManagement:GrantMatrix'));
$this->DoShowGrantSumary($oPage);
}
}
@@ -430,6 +437,8 @@ class UserRightsProfile extends UserRightsAddOnAPI
{
CMDBObject::SetTrackInfo('Initialization');
$oChange = CMDBObject::GetCurrentChange();
$iContactId = 0;
// Support drastic data model changes: no organization class (or not writable)!
if (MetaModel::IsValidClass('Organization') && !MetaModel::IsAbstract('Organization'))
@@ -437,7 +446,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
$oOrg = new Organization();
$oOrg->Set('name', 'My Company/Department');
$oOrg->Set('code', 'SOMECODE');
$iOrgId = $oOrg->DBInsertNoReload();
$iOrgId = $oOrg->DBInsertTrackedNoReload($oChange, true /* skip security */);
// Support drastic data model changes: no Person class (or not writable)!
if (MetaModel::IsValidClass('Person') && !MetaModel::IsAbstract('Person'))
@@ -454,7 +463,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
$oContact->Set('phone', '+00 000 000 000');
}
$oContact->Set('email', 'my.email@foo.org');
$iContactId = $oContact->DBInsertNoReload();
$iContactId = $oContact->DBInsertTrackedNoReload($oChange, true /* skip security */);
}
}
@@ -473,12 +482,14 @@ class UserRightsProfile extends UserRightsAddOnAPI
if (is_object($oAdminProfile))
{
$oUserProfile = new URP_UserProfile();
//$oUserProfile->Set('userid', $iUserId);
$oUserProfile->Set('profileid', $oAdminProfile->GetKey());
$oUserProfile->Set('reason', 'By definition, the administrator must have the administrator profile');
//$oUserProfile->DBInsertTrackedNoReload($oChange, true /* skip security */);
$oSet = DBObjectSet::FromObject($oUserProfile);
$oUser->Set('profile_list', $oSet);
}
$iUserId = $oUser->DBInsertNoReload();
$iUserId = $oUser->DBInsertTrackedNoReload($oChange, true /* skip security */);
return true;
}

View File

@@ -1,20 +1,27 @@
<?php
// Copyright (C) 2010-2013 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/>
/**
* Copyright (C) 2013-2020 Combodo SARL
* UserRightsProfile
* User management Module, basing the right on profiles and a matrix (similar to UserRightsMatrix, but profiles and other decorations have been added)
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
define('ADMIN_PROFILE_NAME', 'Administrator');
@@ -314,7 +321,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
parent::DisplayBareRelations($oPage, $bEditMode);
if (!$bEditMode)
{
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
$oPage->SetCurrentTab(Dict::S('UI:UserManagement:GrantMatrix'));
$this->DoShowGrantSumary($oPage);
}
}
@@ -526,10 +533,10 @@ class UserRightsProfile extends UserRightsAddOnAPI
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
{
// Create a change to record the history of the User object
/** @var \CMDBChange $oChange */
$oChange = MetaModel::NewObject("CMDBChange");
$oChange->Set("date", time());
$oChange->Set("userinfo", "Initialization");
$iChangeId = $oChange->DBInsert();
$iContactId = 0;
// Support drastic data model changes: no organization class (or not writable)!
@@ -538,8 +545,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
$oOrg = new Organization();
$oOrg->Set('name', 'My Company/Department');
$oOrg->Set('code', 'SOMECODE');
$oOrg::SetCurrentChange($oChange);
$iOrgId = $oOrg->DBInsertNoReload();
$iOrgId = $oOrg->DBInsertTrackedNoReload($oChange, true /* skip security */);
// Support drastic data model changes: no Person class (or not writable)!
if (MetaModel::IsValidClass('Person') && !MetaModel::IsAbstract('Person'))
@@ -556,8 +562,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
$oContact->Set('phone', '+00 000 000 000');
}
$oContact->Set('email', 'my.email@foo.org');
$oContact::SetCurrentChange($oChange);
$iContactId = $oContact->DBInsertNoReload();
$iContactId = $oContact->DBInsertTrackedNoReload($oChange, true /* skip security */);
}
}
@@ -576,13 +581,14 @@ class UserRightsProfile extends UserRightsAddOnAPI
if (is_object($oAdminProfile))
{
$oUserProfile = new URP_UserProfile();
//$oUserProfile->Set('userid', $iUserId);
$oUserProfile->Set('profileid', $oAdminProfile->GetKey());
$oUserProfile->Set('reason', 'By definition, the administrator must have the administrator profile');
//$oUserProfile->DBInsertTrackedNoReload($oChange, true /* skip security */);
$oSet = DBObjectSet::FromObject($oUserProfile);
$oUser->Set('profile_list', $oSet);
}
$oUser::SetCurrentChange($oChange);
$iUserId = $oUser->DBInsertNoReload();
$iUserId = $oUser->DBInsertTrackedNoReload($oChange, true /* skip security */);
return true;
}

View File

@@ -1,20 +1,27 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Copyright (C) 2013-2020 Combodo SARL
* UserRightsProjection
* User management Module, basing the right on profiles and a matrix (similar to UserRightsProfile, but enhanced with dimensions and projection of classes and profile over the dimensions)
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
define('ADMIN_PROFILE_ID', 1);
@@ -146,7 +153,7 @@ class URP_Profiles extends UserRightsBaseClass
parent::DisplayBareRelations($oPage, $bEditMode);
if (!$bEditMode)
{
$oPage->SetCurrentTab('UI:UserManagement:GrantMatrix');
$oPage->SetCurrentTab(Dict::S('UI:UserManagement:GrantMatrix'));
$this->DoShowGrantSumary($oPage);
}
}
@@ -586,12 +593,25 @@ class UserRightsProjection extends UserRightsAddOnAPI
$oChange = MetaModel::NewObject("CMDBChange");
$oChange->Set("date", time());
$oChange->Set("userinfo", "Initialization");
$iChangeId = $oChange->DBInsert();
$oOrg = new Organization();
$oOrg->Set('name', 'My Company/Department');
$oOrg->Set('code', 'SOMECODE');
$oOrg::SetCurrentChange($oChange);
$iOrgId = $oOrg->DBInsertNoReload();
// $oOrg->Set('status', 'implementation');
//$oOrg->Set('parent_id', xxx);
$iOrgId = $oOrg->DBInsertTrackedNoReload($oChange, true /* skip strong security */);
// Location : optional
//$oLocation = new bizLocation();
//$oLocation->Set('name', 'MyOffice');
//$oLocation->Set('status', 'implementation');
//$oLocation->Set('org_id', $iOrgId);
//$oLocation->Set('severity', 'high');
//$oLocation->Set('address', 'my building in my city');
//$oLocation->Set('country', 'my country');
//$oLocation->Set('parent_location_id', xxx);
//$iLocationId = $oLocation->DBInsertNoReload();
$oContact = new Person();
$oContact->Set('name', 'My last name');
@@ -599,24 +619,24 @@ class UserRightsProjection extends UserRightsAddOnAPI
//$oContact->Set('status', 'available');
$oContact->Set('org_id', $iOrgId);
$oContact->Set('email', 'my.email@foo.org');
$oContact::SetCurrentChange($oChange);
$iContactId = $oContact->DBInsertNoReload();
//$oContact->Set('phone', '');
//$oContact->Set('location_id', $iLocationId);
//$oContact->Set('employee_number', '');
$iContactId = $oContact->DBInsertTrackedNoReload($oChange, true /* skip security */);
$oUser = new UserLocal();
$oUser->Set('login', $sAdminUser);
$oUser->Set('password', $sAdminPwd);
$oUser->Set('contactid', $iContactId);
$oUser->Set('language', $sLanguage); // Language was chosen during the installation
$oUser::SetCurrentChange($oChange);
$iUserId = $oUser->DBInsertNoReload();
$iUserId = $oUser->DBInsertTrackedNoReload($oChange, true /* skip security */);
// Add this user to the very specific 'admin' profile
$oUserProfile = new URP_UserProfile();
$oUserProfile->Set('userid', $iUserId);
$oUserProfile->Set('profileid', ADMIN_PROFILE_ID);
$oUserProfile->Set('reason', 'By definition, the administrator must have the administrator profile');
$oUserProfile::SetCurrentChange($oChange);
$oUserProfile->DBInsertNoReload();
$oUserProfile->DBInsertTrackedNoReload($oChange, true /* skip security */);
return true;
}

View File

@@ -1,20 +1,27 @@
<?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/>
/**
* Copyright (C) 2013-2020 Combodo SARL
* Simple web page with no includes, header or fancy formatting, useful to
* generate HTML fragments when called by an AJAX method
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT."/application/webpage.class.inc.php");
@@ -23,94 +30,86 @@ class ajax_page extends WebPage implements iTabbedPage
{
/**
* Jquery style ready script
* @var array
*/
* @var Hash
*/
protected $m_sReadyScript;
protected $m_oTabs;
private $m_sMenu; // If set, then the menu will be updated
/**
* constructor for the web page
* @param string $s_title Not used
*/
function __construct($s_title)
{
/**
* constructor for the web page
*
* @param string $s_title Not used
*/
function __construct($s_title) {
$sPrintable = utils::ReadParam('printable', '0');
$bPrintable = ($sPrintable == '1');
parent::__construct($s_title, $bPrintable);
$this->m_sReadyScript = "";
parent::__construct($s_title, $bPrintable);
$this->m_sReadyScript = "";
//$this->add_header("Content-type: text/html; charset=utf-8");
$this->add_header("Cache-control: no-cache");
$this->add_header('Cache-control: no-cache, no-store, must-revalidate');
$this->add_header('Pragma: no-cache');
$this->add_header('Expires: 0');
$this->add_header('X-Frame-Options: deny');
$this->m_oTabs = new TabManager();
$this->sContentType = 'text/html';
$this->sContentDisposition = 'inline';
$this->m_sMenu = "";
utils::InitArchiveMode();
}
}
/**
* @inheritDoc
* @throws \Exception
*/
public function AddTabContainer($sTabContainer, $sPrefix = '')
{
$this->add($this->m_oTabs->AddTabContainer($sTabContainer, $sPrefix));
}
/**
* @inheritDoc
* @throws \Exception
*/
public function AddToTab($sTabContainer, $sTabCode, $sHtml)
public function AddToTab($sTabContainer, $sTabLabel, $sHtml)
{
$this->add($this->m_oTabs->AddToTab($sTabContainer, $sTabCode, $sHtml));
$this->add($this->m_oTabs->AddToTab($sTabContainer, $sTabLabel, $sHtml));
}
/**
* @inheritDoc
*/
public function SetCurrentTabContainer($sTabContainer = '')
{
return $this->m_oTabs->SetCurrentTabContainer($sTabContainer);
}
/**
* @inheritDoc
*/
public function SetCurrentTab($sTabCode = '', $sTabTitle = null)
public function SetCurrentTab($sTabLabel = '')
{
return $this->m_oTabs->SetCurrentTab($sTabCode, $sTabTitle);
return $this->m_oTabs->SetCurrentTab($sTabLabel);
}
/**
* @inheritDoc
* @throws \Exception
* Add a tab which content will be loaded asynchronously via the supplied URL
*
* Limitations:
* Cross site scripting is not not allowed for security reasons. Use a normal tab with an IFRAME if you want to pull content from another server.
* Static content cannot be added inside such tabs.
*
* @param string $sTabLabel The (localised) label of the tab
* @param string $sUrl The URL to load (on the same server)
* @param boolean $bCache Whether or not to cache the content of the tab once it has been loaded. flase will cause the tab to be reloaded upon each activation.
* @since 2.0.3
*/
public function AddAjaxTab($sTabCode, $sUrl, $bCache = true, $sTabTitle = null)
public function AddAjaxTab($sTabLabel, $sUrl, $bCache = true)
{
$this->add($this->m_oTabs->AddAjaxTab($sTabCode, $sUrl, $bCache, $sTabTitle));
$this->add($this->m_oTabs->AddAjaxTab($sTabLabel, $sUrl, $bCache));
}
/**
* @inheritDoc
*/
public function GetCurrentTab()
{
return $this->m_oTabs->GetCurrentTab();
}
/**
* @inheritDoc
*/
public function RemoveTab($sTabCode, $sTabContainer = null)
public function RemoveTab($sTabLabel, $sTabContainer = null)
{
$this->m_oTabs->RemoveTab($sTabCode, $sTabContainer);
$this->m_oTabs->RemoveTab($sTabLabel, $sTabContainer);
}
/**
* @inheritDoc
* Finds the tab whose title matches a given pattern
* @return mixed The name of the tab as a string or false if not found
*/
public function FindTab($sPattern, $sTabContainer = null)
{
@@ -123,23 +122,21 @@ class ajax_page extends WebPage implements iTabbedPage
* that we are using this is not supported... TO DO upgrade
* the whole jquery bundle...
*/
public function SelectTab($sTabContainer, $sTabCode)
public function SelectTab($sTabContainer, $sTabLabel)
{
$this->add_ready_script($this->m_oTabs->SelectTab($sTabContainer, $sTabCode));
$this->add_ready_script($this->m_oTabs->SelectTab($sTabContainer, $sTabLabel));
}
/**
* @param string $sHtml
*/
public function AddToMenu($sHtml)
{
$this->m_sMenu .= $sHtml;
}
/**
* @inheritDoc
*/
public function output()
/**
* Echoes the content of the whole page
* @return void
*/
public function output()
{
if (!empty($this->sContentType))
{
@@ -220,11 +217,8 @@ PrepareWidgets();
EOF
);
}
$this->outputCollapsibleSectionInit();
$oKPI = new ExecutionKPI();
$s_captured_output = $this->ob_get_clean_safe();
if (($this->sContentType == 'text/html') && ($this->sContentDisposition == 'inline'))
$s_captured_output = $this->ob_get_clean_safe();
if (($this->sContentType == 'text/html') && ($this->sContentDisposition == 'inline'))
{
// inline content != attachment && html => filter all scripts for malicious XSS scripts
echo self::FilterXSS($this->s_content);
@@ -294,16 +288,10 @@ EOF
echo self::FilterXSS($s_captured_output);
}
$oKPI->ComputeAndReport('Echoing');
if (class_exists('DBSearch'))
{
DBSearch::RecordQueryTrace();
}
if (class_exists('ExecutionKPI'))
{
ExecutionKPI::ReportStats();
}
}
/**
@@ -316,11 +304,7 @@ EOF
{
}
/**
* @inheritDoc
* @throws \Exception
*/
public function add($sHtml)
public function add($sHtml)
{
if (($this->m_oTabs->GetCurrentTabContainer() != '') && ($this->m_oTabs->GetCurrentTab() != ''))
{
@@ -333,9 +317,10 @@ EOF
}
/**
* @inheritDoc
*/
public function start_capture()
* Records the current state of the 'html' part of the page output
* @return mixed The current state of the 'html' output
*/
public function start_capture()
{
$sCurrentTabContainer = $this->m_oTabs->GetCurrentTabContainer();
$sCurrentTab = $this->m_oTabs->GetCurrentTab();
@@ -351,10 +336,13 @@ EOF
}
}
/**
* @inheritDoc
*/
public function end_capture($offset)
/**
* Returns the part of the html output that occurred since the call to start_capture
* and removes this part from the current html output
* @param $offset mixed The value returned by start_capture
* @return string The part of the html output that was added since the call to start_capture
*/
public function end_capture($offset)
{
if (is_array($offset))
{
@@ -375,9 +363,11 @@ EOF
}
/**
* @inheritDoc
* Add any text or HTML fragment (identified by an ID) at the end of the body of the page
* This is useful to add hidden content, DIVs or FORMs that should not
* be embedded into each other.
*/
public function add_at_the_end($s_html, $sId = '')
public function add_at_the_end($s_html, $sId = '')
{
if ($sId != '')
{
@@ -385,27 +375,27 @@ EOF
}
$this->s_deferred_content .= $s_html;
}
/**
* @inheritDoc
*/
* Adds a script to be executed when the DOM is ready (typical JQuery use)
* NOT implemented in this version of the class.
* @return void
*/
public function add_ready_script($sScript)
{
$this->m_sReadyScript .= $sScript."\n";
}
/**
* @inheritDoc
* Cannot be called in this context, since Ajax pages do not share
* any context with the calling page !!
*/
public function GetUniqueId()
{
assert(false);
return 0;
}
/**
* @inheritDoc
*/
public static function FilterXSS($sHTML)
{
return str_ireplace(array('<script', '</script>'), array('<!-- <removed-script', '</removed-script> -->'), $sHTML);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -29,13 +29,15 @@ require_once(APPROOT."/application/webpage.class.inc.php");
class CSVPage extends WebPage
{
function __construct($s_title)
{
parent::__construct($s_title);
$this->add_header("Content-type: text/plain; charset=".self::PAGES_CHARSET);
$this->add_header("Cache-control: no-cache");
function __construct($s_title) {
parent::__construct($s_title);
$this->add_header("Content-type: text/plain; charset=utf-8");
$this->add_header('Cache-control: no-cache, no-store, must-revalidate');
$this->add_header('Pragma: no-cache');
$this->add_header('Expires: 0');
$this->add_header('X-Frame-Options: deny');
//$this->add_header("Content-Transfer-Encoding: binary");
}
}
public function output()
{

View File

@@ -1,21 +1,20 @@
<?php
/**
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
// Copyright (C) 2010-2017 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
require_once(APPROOT.'application/dashboardlayout.class.inc.php');
require_once(APPROOT.'application/dashlet.class.inc.php');
@@ -25,33 +24,21 @@ require_once(APPROOT.'core/modelreflection.class.inc.php');
*
* A user editable dashboard page
*
* @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
abstract class Dashboard
{
/** @var string $sTitle*/
protected $sTitle;
/** @var bool $bAutoReload */
protected $bAutoReload;
/** @var float|int $iAutoReloadSec */
protected $iAutoReloadSec;
/** @var string $sLayoutClass */
protected $sLayoutClass;
/** @var array $aWidgetsData */
protected $aWidgetsData;
/** @var \DOMNode|null $oDOMNode */
protected $oDOMNode;
/** @var string $sId */
protected $sId;
/** @var array $aCells */
protected $aCells;
/** @var \ModelReflection $oMetaModel */
protected $oMetaModel;
/**
* Dashboard constructor.
*
* @param string $sId
*/
public function __construct($sId)
{
$this->sTitle = '';
@@ -64,7 +51,7 @@ abstract class Dashboard
}
/**
* @param string $sXml
* @param $sXml
*
* @throws \Exception
*/
@@ -77,10 +64,7 @@ abstract class Dashboard
restore_error_handler();
$this->FromDOMDocument($oDoc);
}
/**
* @param \DOMDocument $oDoc
*/
public function FromDOMDocument(DOMDocument $oDoc)
{
$this->oDOMNode = $oDoc->getElementsByTagName('dashboard')->item(0);
@@ -176,16 +160,9 @@ abstract class Dashboard
protected function InitDashletFromDOMNode($oDomNode)
{
$sId = $oDomNode->getAttribute('id');
// To avoid collision with other dashlets with the same ID we suffix it. Collisions typically happen with extensions.
// Note: The check is done so we don't append it at each save of the dashboard.
if(strpos($sId, 'uniqid_') === false)
{
$sId .= '_uniqid_' . uniqid();
}
$sDashletType = $oDomNode->getAttribute('xsi:type');
// Test if dashlet can be instantiated, otherwise (uninstalled, broken, ...) we display a placeholder
// 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);
@@ -195,13 +172,7 @@ abstract class Dashboard
return $oNewDashlet;
}
/**
* @param array $aItem1
* @param array $aItem2
*
* @return int
*/
public static function SortOnRank($aItem1, $aItem2)
static function SortOnRank($aItem1, $aItem2)
{
return ($aItem1['rank'] > $aItem2['rank']) ? +1 : -1;
}
@@ -229,10 +200,6 @@ abstract class Dashboard
}
}
/**
* @return string
* @throws \Exception
*/
public function ToXml()
{
$oDoc = new DOMDocument();
@@ -301,9 +268,7 @@ abstract class Dashboard
}
}
/**
* @param array $aParams
*/
public function FromParams($aParams)
{
$this->sLayoutClass = $aParams['layout_class'];
@@ -340,66 +305,42 @@ abstract class Dashboard
{
}
/**
* @return string
*/
public function GetLayout()
{
return $this->sLayoutClass;
}
/**
* @param string $sLayoutClass
*/
public function SetLayout($sLayoutClass)
{
$this->sLayoutClass = $sLayoutClass;
}
/**
* @return string
*/
public function GetTitle()
{
return $this->sTitle;
}
/**
* @param string $sTitle
*/
public function SetTitle($sTitle)
{
$this->sTitle = $sTitle;
}
/**
* @return bool
*/
public function GetAutoReload()
{
return $this->bAutoReload;
}
/**
* @param bool $bAutoReload
*/
public function SetAutoReload($bAutoReload)
{
$this->bAutoReload = $bAutoReload;
}
/**
* @return float|int
*/
public function GetAutoReloadInterval()
{
return $this->iAutoReloadSec;
}
/**
* @param bool $iAutoReloadSec
*/
public function SetAutoReloadInterval($iAutoReloadSec)
{
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int)$iAutoReloadSec);
@@ -415,13 +356,12 @@ abstract class Dashboard
$this->aCells[] = array($oDashlet);
}
/**
* @param \WebPage $oPage *
* @param array $aExtraParams
*
* @throws \ReflectionException
* @throws \Exception
*/
/**
* @param \WebPage $oPage *
* @param array $aExtraParams
*
* @throws \ReflectionException
*/
public function RenderProperties($oPage, $aExtraParams = array())
{
// menu to pick a layout and edit other properties of the dashboard
@@ -509,7 +449,7 @@ EOF
}
/**
* @param \WebPage $oPage
* @param \iTopWebPage $oPage
* @param bool $bEditMode
* @param array $aExtraParams
* @param bool $bCanEdit
@@ -528,12 +468,6 @@ EOF
}
}
/**
* @param \WebPage $oPage
*
* @throws \ReflectionException
* @throws \Exception
*/
public function RenderDashletsSelection(WebPage $oPage)
{
// Toolbox/palette to drag and drop dashlets
@@ -551,11 +485,7 @@ EOF
$oPage->add('</div>');
$oPage->add_ready_script("$('.dashlet_icon').draggable({helper: 'clone', appendTo: 'body', zIndex: 10000, revert:'invalid'});");
}
/**
* @param \WebPage $oPage
* @param array $aExtraParams
*/
public function RenderDashletsProperties(WebPage $oPage, $aExtraParams = array())
{
// Toolbox/palette to edit the properties of each dashlet
@@ -615,10 +545,7 @@ EOF
return $aDashlets;
}
/**
* @return int|mixed
*/
protected function GetNewDashletId()
{
$iNewId = 0;
@@ -634,19 +561,13 @@ EOF
}
/**
* @param \DesignerForm $oForm
* @param $oForm
* @param array $aExtraParams
*
* @return mixed
*/
abstract protected function SetFormParams($oForm, $aExtraParams = array());
/**
* @param string $sType
* @param \ModelFactory|null $oFactory
*
* @return string
*/
public static function GetDashletClassFromType($sType, $oFactory = null)
{
if (is_subclass_of($sType, 'Dashlet'))
@@ -665,49 +586,37 @@ EOF
}
}
/**
* Class RuntimeDashboard
*/
class RuntimeDashboard extends Dashboard
{
/** @var bool $bCustomized */
protected $bCustomized;
/** @var string $sDefinitionFile */
private $sDefinitionFile = '';
/** @var null $sReloadURL */
private $sReloadURL = null;
/**
* @inheritDoc
*/
public function __construct($sId)
{
parent::__construct($sId);
$this->bCustomized = false;
$this->oMetaModel = new ModelReflectionRuntime();
}
/**
* @param bool $bCustomized
*/
public function SetCustomFlag($bCustomized)
{
$this->bCustomized = $bCustomized;
}
/**
* @inheritDoc
* @param \DesignerForm $oForm
*
* @param array $aExtraParams
*
* @throws \Exception
*/
protected function SetFormParams($oForm, $aExtraParams = array())
{
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property', 'extra_params' => $aExtraParams));
}
/**
* @inheritDoc
* @throws \Exception
*/
public function Save()
{
$sXml = $this->ToXml();
@@ -723,7 +632,7 @@ class RuntimeDashboard extends Dashboard
}
else
{
// No such customized dashboard for the current user, let's create a new record
// No such customized dasboard for the current user, let's create a new record
$oUserDashboard = new UserDashboard();
$oUserDashboard->Set('user_id', UserRights::GetUserId());
$oUserDashboard->Set('menu_code', $this->sId);
@@ -733,18 +642,7 @@ class RuntimeDashboard extends Dashboard
$oUserDashboard->DBWrite();
utils::PopArchiveMode();
}
/**
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DeleteException
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
*/
public function Revert()
{
$oUDSearch = new DBObjectSearch('UserDashboard');
@@ -771,34 +669,34 @@ class RuntimeDashboard extends Dashboard
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \Exception
*/
public static function GetDashboard($sDashboardFile, $sDashBoardId)
{
$bCustomized = false;
if (!appUserPreferences::GetPref('display_original_dashboard_'.$sDashBoardId, false))
{
$sDashboardFileSanitized = utils::RealPath($sDashboardFile, APPROOT);
if (false === $sDashboardFileSanitized) {
throw new SecurityException('Invalid dashboard file !');
}
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)
{
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($sDashboardFileSanitized);
}
}
else
{
$sDashboardDefinition = @file_get_contents($sDashboardFile);
$sDashboardDefinition = @file_get_contents($sDashboardFileSanitized);
}
if ($sDashboardDefinition !== false)
@@ -806,7 +704,7 @@ class RuntimeDashboard extends Dashboard
$oDashboard = new RuntimeDashboard($sDashBoardId);
$oDashboard->FromXml($sDashboardDefinition);
$oDashboard->SetCustomFlag($bCustomized);
$oDashboard->SetDefinitionFile($sDashboardFile);
$oDashboard->SetDefinitionFile($sDashboardFileSanitized);
}
else
{
@@ -816,7 +714,10 @@ class RuntimeDashboard extends Dashboard
}
/**
* @inheritDoc
* @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)
@@ -951,9 +852,6 @@ EOF
);
}
/**
* @return bool
*/
protected function HasCustomDashboard()
{
try
@@ -982,7 +880,7 @@ EOF
{
$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><i class=\"top-right-icon icon-additional-arrow fas fa-pencil-alt\"></i><ul>";
$sEditMenu = "<div id=\"DashboardMenu\"><ul><li><img src=\"../images/pencil-menu.png\"><ul>";
$aActions = array();
$sFile = addslashes($this->sDefinitionFile);
@@ -1042,7 +940,9 @@ EOF
}
/**
* @inheritDoc
* @param \WebPage $oPage
*
* @throws \ReflectionException
*/
public function RenderProperties($oPage, $aExtraParams = array())
{
@@ -1078,7 +978,7 @@ EOF
/**
* @param \WebPage $oPage
* @param \iTopWebPage $oPage
*
* @param array $aExtraParams
*
@@ -1218,14 +1118,7 @@ EOF
);
$oPage->add_ready_script("");
}
/**
* @param string|null $sOQL
*
* @return \DesignerForm
* @throws \DictExceptionMissingString
* @throws \ReflectionException
*/
public static function GetDashletCreationForm($sOQL = null)
{
$oAppContext = new ApplicationContext();
@@ -1336,9 +1229,6 @@ EOF
/**
* @param \WebPage $oPage
* @param $sOQL
*
* @throws \DictExceptionMissingString
* @throws \ReflectionException
*/
public static function GetDashletCreationDlgFromOQL($oPage, $sOQL)
{
@@ -1403,19 +1293,13 @@ EOF
$this->sDefinitionFile = $sDefinitionFile;
}
/**
* @return string|null
*/
public function GetReloadURL()
{
return $this->sReloadURL;
}
/**
* @param string $sReloadURL
*/
public function SetReloadURL($sReloadURL)
{
$this->sReloadURL = $sReloadURL;
}
}
}

View File

@@ -613,12 +613,12 @@ class DashletUnknown extends Dashlet
{
$aInfos = static::GetInfo();
$sIconUrl = utils::GetAbsoluteUrlAppRoot().$aInfos['icon'];
$sIconUrl = utils::HtmlEntities(utils::GetAbsoluteUrlAppRoot().$aInfos['icon']);
$sExplainText = ($bEditMode) ? Dict::Format('UI:DashletUnknown:RenderText:Edit', $this->GetDashletType()) : Dict::S('UI:DashletUnknown:RenderText:View');
$oPage->add('<div class="dashlet-content">');
$oPage->add('<div class="dashlet-ukn-image"><img src="'.utils::HtmlEntities($sIconUrl).'" /></div>');
$oPage->add('<div class="dashlet-ukn-image"><img src="'.$sIconUrl.'" /></div>');
$oPage->add('<div class="dashlet-ukn-text">'.$sExplainText.'</div>');
$oPage->add('</div>');
@@ -633,12 +633,12 @@ class DashletUnknown extends Dashlet
{
$aInfos = static::GetInfo();
$sIconUrl = utils::GetAbsoluteUrlAppRoot().$aInfos['icon'];
$sIconUrl = utils::HtmlEntities(utils::GetAbsoluteUrlAppRoot().$aInfos['icon']);
$sExplainText = Dict::Format('UI:DashletUnknown:RenderNoDataText:Edit', $this->GetDashletType());
$oPage->add('<div class="dashlet-content">');
$oPage->add('<div class="dashlet-ukn-image"><img src="'.utils::HtmlEntities($sIconUrl).'" /></div>');
$oPage->add('<div class="dashlet-ukn-image"><img src="'.$sIconUrl.'" /></div>');
$oPage->add('<div class="dashlet-ukn-text">'.$sExplainText.'</div>');
$oPage->add('</div>');
@@ -774,12 +774,12 @@ class DashletProxy extends DashletUnknown
{
$aInfos = static::GetInfo();
$sIconUrl = utils::GetAbsoluteUrlAppRoot().$aInfos['icon'];
$sIconUrl = utils::HtmlEntities(utils::GetAbsoluteUrlAppRoot().$aInfos['icon']);
$sExplainText = Dict::Format('UI:DashletProxy:RenderNoDataText:Edit', $this->GetDashletType());
$oPage->add('<div class="dashlet-content">');
$oPage->add('<div class="dashlet-pxy-image"><img src="'.utils::HtmlEntities($sIconUrl).'" /></div>');
$oPage->add('<div class="dashlet-pxy-image"><img src="'.$sIconUrl.'" /></div>');
$oPage->add('<div class="dashlet-pxy-text">'.$sExplainText.'</div>');
$oPage->add('</div>');
@@ -860,7 +860,7 @@ class DashletPlainText extends Dashlet
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
{
$sText = htmlentities($this->aProperties['text'], ENT_QUOTES, 'UTF-8');
$sText = utils::HtmlEntities($this->aProperties['text']);
$sText = str_replace(array("\r\n", "\n", "\r"), "<br/>", $sText);
$sId = 'plaintext_'.($bEditMode? 'edit_' : '').$this->sId;
@@ -917,7 +917,7 @@ class DashletObjectList extends Dashlet
$sShowMenu = $this->aProperties['menu'] ? '1' : '0';
$oPage->add('<div class="dashlet-content">');
$sHtmlTitle = htmlentities(Dict::S($sTitle), ENT_QUOTES, 'UTF-8'); // done in the itop block
$sHtmlTitle = utils::HtmlEntities(Dict::S($sTitle)); // done in the itop block
if ($sHtmlTitle != '')
{
$oPage->add('<h1>'.$sHtmlTitle.'</h1>');
@@ -956,7 +956,7 @@ class DashletObjectList extends Dashlet
$bShowMenu = $this->aProperties['menu'];
$oPage->add('<div class="dashlet-content">');
$sHtmlTitle = htmlentities($this->oModelReflection->DictString($sTitle), ENT_QUOTES, 'UTF-8'); // done in the itop block
$sHtmlTitle = utils::HtmlEntities($this->oModelReflection->DictString($sTitle)); // done in the itop block
if ($sHtmlTitle != '')
{
$oPage->add('<h1>'.$sHtmlTitle.'</h1>');
@@ -1249,7 +1249,7 @@ abstract class DashletGroupBy extends Dashlet
case 'table':
default:
$sHtmlTitle = htmlentities(Dict::S($sTitle), ENT_QUOTES, 'UTF-8'); // done in the itop block
$sHtmlTitle = utils::HtmlEntities(Dict::S($sTitle)); // done in the itop block
$sType = 'count';
$aParams = array(
'group_by' => $this->sGroupByExpr,
@@ -1686,7 +1686,7 @@ class DashletGroupByPie extends DashletGroupBy
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
$HTMLsTitle = ($sTitle != '') ? '<h1 style="text-align:center">'.htmlentities($sTitle, ENT_QUOTES, 'UTF-8').'</h1>' : '';
$HTMLsTitle = ($sTitle != '') ? '<h1 style="text-align:center">'.utils::HtmlEntities($sTitle).'</h1>' : '';
$oPage->add("<div style=\"background-color:#fff;padding:0.25em;\">$HTMLsTitle<div id=\"$sBlockId\" style=\"background-color:#fff;\"></div></div>");
$aDisplayValues = $this->MakeSimulatedData();
@@ -1758,7 +1758,7 @@ class DashletGroupByBars extends DashletGroupBy
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
$HTMLsTitle = ($sTitle != '') ? '<h1 style="text-align:center">'.htmlentities($sTitle, ENT_QUOTES, 'UTF-8').'</h1>' : '';
$HTMLsTitle = ($sTitle != '') ? '<h1 style="text-align:center">'.utils::HtmlEntities($sTitle).'</h1>' : '';
$oPage->add("<div style=\"background-color:#fff;padding:0.25em;\">$HTMLsTitle<div id=\"$sBlockId\" style=\"background-color:#fff;\"></div></div>");
$aDisplayValues = $this->MakeSimulatedData();
@@ -1907,16 +1907,16 @@ class DashletHeaderStatic extends Dashlet
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
{
$sTitle = $this->aProperties['title'];
$sTitle = utils::HtmlEntities($this->aProperties['title']);
$sIcon = $this->aProperties['icon'];
$oIconSelect = $this->oModelReflection->GetIconSelectionField('icon');
$sIconPath = $oIconSelect->MakeFileUrl($sIcon);
$sIconPath = utils::HtmlEntities($oIconSelect->MakeFileUrl($sIcon));
$oPage->add('<div class="dashlet-content">');
$oPage->add('<div class="main_header">');
$oPage->add('<img src="'.utils::HtmlEntities($sIconPath).'">');
$oPage->add('<img src="'.$sIconPath.'">');
$oPage->add('<h1>'.$this->oModelReflection->DictString($sTitle).'</h1>');
$oPage->add('</div>');
@@ -2037,14 +2037,14 @@ class DashletHeaderDynamic extends Dashlet
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
{
$sTitle = $this->aProperties['title'];
$sTitle = utils::HtmlEntities($this->aProperties['title']);
$sIcon = $this->aProperties['icon'];
$sSubtitle = $this->aProperties['subtitle'];
$sSubtitle = utils::HtmlEntities($this->aProperties['subtitle']);
$sQuery = $this->aProperties['query'];
$sGroupBy = $this->aProperties['group_by'];
$oIconSelect = $this->oModelReflection->GetIconSelectionField('icon');
$sIconPath = $oIconSelect->MakeFileUrl($sIcon);
$sIconPath = utils::HtmlEntities($oIconSelect->MakeFileUrl($sIcon));
$aValues = $this->GetValues();
if (count($aValues) > 0)
@@ -2072,7 +2072,7 @@ class DashletHeaderDynamic extends Dashlet
$oPage->add('<div class="dashlet-content">');
$oPage->add('<div class="main_header">');
$oPage->add('<img src="'.utils::HtmlEntities($sIconPath).'">');
$oPage->add('<img src="'.$sIconPath.'">');
if (isset($aExtraParams['query_params']))
{
@@ -2101,9 +2101,9 @@ class DashletHeaderDynamic extends Dashlet
*/
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = array())
{
$sTitle = $this->aProperties['title'];
$sTitle = utils::HtmlEntities($this->aProperties['title']);
$sIcon = $this->aProperties['icon'];
$sSubtitle = $this->aProperties['subtitle'];
$sSubtitle = utils::HtmlEntities($this->aProperties['subtitle']);
$sQuery = $this->aProperties['query'];
$sGroupBy = $this->aProperties['group_by'];
@@ -2111,12 +2111,12 @@ class DashletHeaderDynamic extends Dashlet
$sClass = $oQuery->GetClass();
$oIconSelect = $this->oModelReflection->GetIconSelectionField('icon');
$sIconPath = $oIconSelect->MakeFileUrl($sIcon);
$sIconPath = utils::HtmlEntities($oIconSelect->MakeFileUrl($sIcon));
$oPage->add('<div class="dashlet-content">');
$oPage->add('<div class="main_header">');
$oPage->add('<img src="'.utils::HtmlEntities($sIconPath).'">');
$oPage->add('<img src="'.$sIconPath.'">');
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
@@ -2147,8 +2147,8 @@ class DashletHeaderDynamic extends Dashlet
$sTitle = $this->oModelReflection->DictString($sTitle);
$sSubtitle = $this->oModelReflection->DictFormat($sSubtitle, $iTotal);
$oPage->add('<h1>'.$sTitle.'</h1>');
$oPage->add('<a class="summary">'.$sSubtitle.'</a>');
$oPage->add('<h1>'.utils::HtmlEntities($sTitle).'</h1>');
$oPage->add('<a class="summary">'.utils::HtmlEntities($sSubtitle).'</a>');
$oPage->add('</div>');
$oPage->add('</div>');

View File

@@ -1,6 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.6">
<portals>
<portal id="legacy_portal" _delta="define">
<url>portal/index.php</url>
<rank>1.0</rank>
<handler/>
<allow>
</allow>
<deny/>
</portal>
<portal id="backoffice" _delta="define">
<url>pages/UI.php</url>
<rank>2.0</rank>
@@ -15,10 +23,5 @@
<menu id="AdminTools" xsi:type="MenuGroup" _delta="define">
<rank>80</rank>
</menu>
<menu id="System" xsi:type="MenuGroup" _delta="define">
<rank>100</rank>
<enable_class>ResourceSystemMenu</enable_class>
<enable_action>UR_ACTION_MODIFY</enable_action>
</menu>
</menus>
</itop_design>

View File

@@ -1,20 +1,25 @@
<?php
// Copyright (C) 2010-2017 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Copyright (C) 2013-2020 Combodo SARL
* Data Table to display a set of objects in a tabular manner in HTML
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class DataTable
@@ -31,13 +36,8 @@ class DataTable
/**
* @param $iListId mixed Unique ID for this div/table in the page
* @param $oSet DBObjectSet The set of data to display
* @param $aClassAliases array The list of classes/aliases to be displayed in this set $sAlias => $sClassName
* @param $aClassAliases Hash The list of classes/aliases to be displayed in this set $sAlias => $sClassName
* @param $sTableId mixed A string (or null) identifying this table in order to persist its settings
*
* @throws \CoreException
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
public function __construct($iListId, $oSet, $aClassAliases, $sTableId = null)
{
@@ -50,19 +50,7 @@ class DataTable
$this->oDefaultSettings = null;
$this->bShowObsoleteData = $oSet->GetShowObsoleteData();
}
/**
* @param \WebPage $oPage
* @param \DataTableSettings $oSettings
* @param $bActionsMenu
* @param $sSelectMode
* @param $bViewLink
* @param $aExtraParams
*
* @return string
* @throws \CoreException
* @throws \MySQLException
*/
public function Display(WebPage $oPage, DataTableSettings $oSettings, $bActionsMenu, $sSelectMode, $bViewLink, $aExtraParams)
{
$this->oDefaultSettings = $oSettings;
@@ -131,23 +119,7 @@ class DataTable
return $this->GetAsHTML($oPage, $oCustomSettings->iDefaultPageSize, $oCustomSettings->iDefaultPageSize, 0, $oCustomSettings->aColumns, $bActionsMenu, $bToolkitMenu, $sSelectMode, $bViewLink, $aExtraParams);
}
/**
* @param \WebPage $oPage
* @param $iPageSize
* @param $iDefaultPageSize
* @param $iPageIndex
* @param $aColumns
* @param $bActionsMenu
* @param $bToolkitMenu
* @param $sSelectMode
* @param $bViewLink
* @param $aExtraParams
*
* @return string
* @throws \ArchivedObjectException
* @throws \CoreException
*/
public function GetAsHTML(WebPage $oPage, $iPageSize, $iDefaultPageSize, $iPageIndex, $aColumns, $bActionsMenu, $bToolkitMenu, $sSelectMode, $bViewLink, $aExtraParams)
{
$sObjectsCount = $this->GetObjectCount($oPage, $sSelectMode);
@@ -226,13 +198,7 @@ class DataTable
}
return $sHtml;
}
/**
* @param \WebPage $oPage
* @param $sSelectMode
*
* @return string
*/
protected function GetObjectCount(WebPage $oPage, $sSelectMode)
{
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
@@ -245,15 +211,6 @@ class DataTable
}
return $sHtml;
}
/**
* @param \WebPage $oPage
* @param $iPageSize
* @param $iDefaultPageSize
* @param $iPageIndex
*
* @return string
*/
protected function GetPager(WebPage $oPage, $iPageSize, $iDefaultPageSize, $iPageIndex)
{
$sHtml = '';
@@ -338,17 +295,7 @@ class DataTable
EOF;
return $sHtml;
}
/**
* @param \WebPage $oPage
* @param $aExtraParams
*
* @return string
* @throws \CoreException
* @throws \DictExceptionMissingString
* @throws \MissingQueryArgument
* @throws \MySQLException
*/
protected function GetActionsMenu(WebPage $oPage, $aExtraParams)
{
$oMenuBlock = new MenuBlock($this->oSet->GetFilter(), 'list');
@@ -356,20 +303,13 @@ EOF;
$sHtml = $oMenuBlock->GetRenderContent($oPage, $aExtraParams, $this->iListId);
return $sHtml;
}
/**
* @param \WebPage $oPage
* @param $aExtraParams
*
* @return string
* @throws \Exception
*/
protected function GetToolkitMenu(WebPage $oPage, $aExtraParams)
{
if (!$oPage->IsPrintableVersion())
{
$sMenuTitle = Dict::S('UI:ConfigureThisList');
$sHtml = '<div class="itop_popup toolkit_menu" id="tk_'.$this->iListId.'"><ul><li><i class="fas fa-tools"></i><i class="fas fa-caret-down"></i><ul>';
$sHtml = '<div class="itop_popup toolkit_menu" id="tk_'.$this->iListId.'"><ul><li><img src="../images/toolkit_menu.png?t='.utils::GetCacheBusterTimestamp().'"><ul>';
$oMenuItem1 = new JSPopupMenuItem('iTop::ConfigureList', $sMenuTitle, "$('#datatable_dlg_".$this->iListId."').dialog('open');");
$aActions = array(
@@ -386,15 +326,7 @@ EOF;
}
return $sHtml;
}
/**
* @param \WebPage $oPage
* @param $aColumns
* @param $bViewLink
* @param $iDefaultPageSize
*
* @return string
*/
protected function GetTableConfigDlg(WebPage $oPage, $aColumns, $bViewLink, $iDefaultPageSize)
{
$sHtml = "<div id=\"datatable_dlg_{$this->iListId}\" style=\"display: none;\">";
@@ -430,42 +362,23 @@ EOF;
return $sHtml;
}
/**
* @param $oSetting
*
* @return array
*/
public function GetAsHash($oSetting)
{
$aSettings = array('iDefaultPageSize' => $oSetting->iDefaultPageSize, 'oColumns' => $oSetting->aColumns);
return $aSettings;
}
/**
* @param array $aColumns
* @param string $sSelectMode
* @param bool $bViewLink
*
* @return array
* @throws \CoreException
* @throws \DictExceptionMissingString
* @throws \Exception
*/
protected function GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink)
{
$aAttribs = array();
if ($sSelectMode == 'multiple')
{
$aAttribs['form::select'] = array(
'label' => "<input type=\"checkbox\" onClick=\"CheckAll('.selectList{$this->iListId}:not(:disabled)', this.checked);\" class=\"checkAll\"></input>",
'description' => Dict::S('UI:SelectAllToggle+'),
'metadata' => array(),
);
$aAttribs['form::select'] = array('label' => "<input type=\"checkbox\" onClick=\"CheckAll('.selectList{$this->iListId}:not(:disabled)', this.checked);\" class=\"checkAll\"></input>", 'description' => Dict::S('UI:SelectAllToggle+'));
}
else if ($sSelectMode == 'single')
{
$aAttribs['form::select'] = array('label' => '', 'description' => '', 'metadata' => array());
$aAttribs['form::select'] = array('label' => "", 'description' => '');
}
foreach($this->aClassAliases as $sAlias => $sClassName)
@@ -476,55 +389,19 @@ EOF;
{
if ($sAttCode == '_key_')
{
$sAttLabel = MetaModel::GetName($sClassName);
$aAttribs['key_'.$sAlias] = array(
'label' => $sAttLabel,
'description' => '',
'metadata' => array(
'object_class' => $sClassName,
'attribute_label' => $sAttLabel,
),
);
$aAttribs['key_'.$sAlias] = array('label' => MetaModel::GetName($sClassName), 'description' => '');
}
else
{
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCode);
$sAttDefClass = get_class($oAttDef);
$sAttLabel = MetaModel::GetLabel($sClassName, $sAttCode);
$aAttribs[$sAttCode.'_'.$sAlias] = array(
'label' => $sAttLabel,
'description' => $oAttDef->GetOrderByHint(),
'metadata' => array(
'object_class' => $sClassName,
'attribute_code' => $sAttCode,
'attribute_type' => $sAttDefClass,
'attribute_label' => $sAttLabel,
),
);
$aAttribs[$sAttCode.'_'.$sAlias] = array('label' => MetaModel::GetLabel($sClassName, $sAttCode), 'description' => $oAttDef->GetOrderByHint());
}
}
}
}
return $aAttribs;
}
/**
* @param $aColumns
* @param $sSelectMode
* @param $iPageSize
* @param $bViewLink
* @param $aExtraParams
*
* @return array
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \Exception
*/
protected function GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
{
$bLocalize = true;
@@ -534,7 +411,6 @@ EOF;
}
$aValues = array();
$aAttDefsCache = array();
$this->oSet->Seek(0);
$iMaxObjects = $iPageSize;
while (($aObjects = $this->oSet->FetchAssoc()) && ($iMaxObjects != 0))
@@ -575,41 +451,11 @@ EOF;
{
if ($sAttCode == '_key_')
{
$aRow['key_'.$sAlias] = array(
'value_raw' => $aObjects[$sAlias]->GetKey(),
'value_html' => $aObjects[$sAlias]->GetHyperLink(),
);
$aRow['key_'.$sAlias] = $aObjects[$sAlias]->GetHyperLink();
}
else
{
// Prepare att. def. classes cache to avoid retrieving AttDef for each row
if(!isset($aAttDefsCache[$sClassName][$sAttCode]))
{
$aAttDefClassesCache[$sClassName][$sAttCode] = get_class(MetaModel::GetAttributeDef($sClassName, $sAttCode));
}
// Only retrieve raw (stored) value for simple fields
$bExcludeRawValue = false;
foreach (cmdbAbstractObject::GetAttDefClassesToExcludeFromMarkupMetadataRawValue() as $sAttDefClassToExclude)
{
if (is_a($aAttDefClassesCache[$sClassName][$sAttCode], $sAttDefClassToExclude, true))
{
$bExcludeRawValue = true;
break;
}
}
if($bExcludeRawValue)
{
$aRow[$sAttCode.'_'.$sAlias] = $aObjects[$sAlias]->GetAsHTML($sAttCode, $bLocalize);
}
else
{
$aRow[$sAttCode.'_'.$sAlias] = array(
'value_raw' => $aObjects[$sAlias]->Get($sAttCode),
'value_html' => $aObjects[$sAlias]->GetAsHTML($sAttCode, $bLocalize),
);
}
$aRow[$sAttCode.'_'.$sAlias] = $aObjects[$sAlias]->GetAsHTML($sAttCode, $bLocalize);
}
}
}
@@ -638,25 +484,7 @@ EOF;
}
return $aValues;
}
/**
* @param \WebPage $oPage
* @param $aColumns
* @param $sSelectMode
* @param $iPageSize
* @param $bViewLink
* @param $aExtraParams
*
* @return string
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DictExceptionMissingString
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \Exception
*/
public function GetHTMLTable(WebPage $oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
{
$iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize);
@@ -668,7 +496,7 @@ EOF;
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
$sHtml = '<table class="listContainer object-list">';
$sHtml = '<table class="listContainer">';
foreach($this->oSet->GetFilter()->GetInternalParams() as $sName => $sValue)
{
@@ -757,12 +585,7 @@ EOF
}
return $sHtml;
}
/**
* @param \WebPage $oPage
* @param $iDefaultPageSize
* @param $iStart
*/
public function UpdatePager(WebPage $oPage, $iDefaultPageSize, $iStart)
{
$iPageSize = $iDefaultPageSize;
@@ -786,48 +609,11 @@ EOF
*/
class PrintableDataTable extends DataTable
{
/**
* @param \WebPage $oPage
* @param $iPageSize
* @param $iDefaultPageSize
* @param $iPageIndex
* @param $aColumns
* @param $bActionsMenu
* @param $bToolkitMenu
* @param $sSelectMode
* @param $bViewLink
* @param $aExtraParams
*
* @return string
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DictExceptionMissingString
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
public function GetAsHTML(WebPage $oPage, $iPageSize, $iDefaultPageSize, $iPageIndex, $aColumns, $bActionsMenu, $bToolkitMenu, $sSelectMode, $bViewLink, $aExtraParams)
{
return $this->GetHTMLTable($oPage, $aColumns, $sSelectMode, -1, $bViewLink, $aExtraParams);
}
/**
* @param \WebPage $oPage
* @param $aColumns
* @param $sSelectMode
* @param $iPageSize
* @param $bViewLink
* @param $aExtraParams
*
* @return string
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DictExceptionMissingString
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
public function GetHTMLTable(WebPage $oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
{
$iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize);
@@ -852,13 +638,7 @@ class DataTableSettings implements Serializable
public $iDefaultPageSize;
public $aColumns;
/**
* DataTableSettings constructor.
*
* @param $aClassAliases
* @param null $sTableId
*/
public function __construct($aClassAliases, $sTableId = null)
{
$this->aClassAliases = $aClassAliases;
@@ -866,22 +646,14 @@ class DataTableSettings implements Serializable
$this->iDefaultPageSize = 10;
$this->aColumns = array();
}
/**
* @param $iDefaultPageSize
* @param $aSortOrder
* @param $aColumns
*/
protected function Init($iDefaultPageSize, $aSortOrder, $aColumns)
{
$this->iDefaultPageSize = $iDefaultPageSize;
$this->aColumns = $aColumns;
$this->FixVisibleColumns();
}
/**
* @return string
*/
public function serialize()
{
// Save only the 'visible' columns
@@ -907,12 +679,7 @@ class DataTableSettings implements Serializable
)
);
}
/**
* @param string $sData
*
* @throws \Exception
*/
public function unserialize($sData)
{
$aData = unserialize($sData);
@@ -945,16 +712,7 @@ class DataTableSettings implements Serializable
}
$this->FixVisibleColumns();
}
/**
* @param $aClassAliases
* @param $bViewLink
* @param $aDefaultLists
*
* @return \DataTableSettings
* @throws \CoreException
* @throws \DictExceptionMissingString
*/
static public function GetDataModelSettings($aClassAliases, $bViewLink, $aDefaultLists)
{
$oSettings = new DataTableSettings($aClassAliases);
@@ -1004,10 +762,7 @@ class DataTableSettings implements Serializable
$oSettings->Init($iDefaultPageSize, $aSortOrder, $aColumns);
return $oSettings;
}
/**
* @throws \CoreException
*/
protected function FixVisibleColumns()
{
foreach($this->aClassAliases as $sAlias => $sClass)
@@ -1044,15 +799,7 @@ class DataTableSettings implements Serializable
}
}
}
/**
* @param $aClassAliases
* @param null $sTableId
* @param bool $bOnlyOnTable
*
* @return \DataTableSettings|null
* @throws \Exception
*/
static public function GetTableSettings($aClassAliases, $sTableId = null, $bOnlyOnTable = false)
{
$pref = null;
@@ -1081,10 +828,7 @@ class DataTableSettings implements Serializable
return $oSettings;
}
/**
* @return array
*/
public function GetSortOrder()
{
$aSortOrder = array();
@@ -1102,12 +846,7 @@ class DataTableSettings implements Serializable
}
return $aSortOrder;
}
/**
* @param null $sTargetTableId
*
* @return bool
*/
public function Save($sTargetTableId = null)
{
$sSaveId = is_null($sTargetTableId) ? $this->sTableId : $sTargetTableId;
@@ -1118,9 +857,6 @@ class DataTableSettings implements Serializable
return true;
}
/**
* @return bool
*/
public function SaveAsDefault()
{
$sSettings = $this->serialize();
@@ -1150,12 +886,7 @@ class DataTableSettings implements Serializable
}
return true;
}
/**
* @param null $sTableId
*
* @return string
*/
protected function GetPrefsKey($sTableId = null)
{
if ($sTableId == null) $sTableId = '*';
@@ -1166,18 +897,7 @@ class DataTableSettings implements Serializable
}
return implode('/', $aKeys).'|'.$sTableId;
}
/**
* @param $sAlias
* @param $sAttCode
* @param $oAttDef
* @param $bChecked
* @param $sSort
*
* @return array|bool
* @throws \CoreException
* @throws \DictExceptionMissingString
*/
protected function GetFieldData($sAlias, $sAttCode, $oAttDef, $bChecked, $sSort)
{
$ret = false;

View File

@@ -1,20 +1,26 @@
<?php
// Copyright (C) 2010-2017 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Copyright (C) 2013-2019 Combodo SARL
* DisplayBlock and derived class
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/application/webpage.class.inc.php');
@@ -85,7 +91,7 @@ class DisplayBlock
{
$oDummyFilter = new DBObjectSearch($oSet->GetClass());
$aKeys = array();
$oSet->OptimizeColumnLoad(array($oSet->GetClassAlias() => array())); // No need to load all the columns just to get the id
$oSet->OptimizeColumnLoad(array('id')); // No need to load all the columns just to get the id
while($oObject = $oSet->Fetch())
{
$aKeys[] = $oObject->GetKey();
@@ -243,7 +249,7 @@ class DisplayBlock
$sHtml .= $this->GetRenderContent($oPage, $aExtraParams, $sId);
} catch (Exception $e)
{
IssueLog::Error('Exception during GetDisplay: ' . $e->getMessage());
}
$sHtml .= "</div>\n";
}
@@ -1880,11 +1886,11 @@ class MenuBlock extends DisplayBlock
{
if (count($aFavoriteActions) > 0)
{
$sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>".Dict::S('UI:Menu:OtherActions')."<i class=\"fas fa-caret-down\"></i>"."\n<ul>\n";
$sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>".Dict::S('UI:Menu:OtherActions')."\n<ul>\n";
}
else
{
$sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>".Dict::S('UI:Menu:Actions')."<i class=\"fas fa-caret-down\"></i>"."\n<ul>\n";
$sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>".Dict::S('UI:Menu:Actions')."\n<ul>\n";
}
$sHtml .= $oPage->RenderPopupMenuItems($aActions, $aFavoriteActions);
@@ -1892,8 +1898,7 @@ class MenuBlock extends DisplayBlock
if ($this->m_sStyle == 'details')
{
$sSearchAction = "window.location=\"{$sRootUrl}pages/UI.php?operation=search_form&do_search=0&class=$sClass{$sContext}\"";
$sHtml .= "<div class=\"actions_button icon_actions_button\" title=\"".htmlentities(Dict::Format('UI:SearchFor_Class',
MetaModel::GetName($sClass)), ENT_QUOTES, 'UTF-8')."\"><span class=\"search-button fas fa-search\" onclick='$sSearchAction'></span></div>";
$sHtml .= "<div class=\"actions_button icon_actions_button\" title=\"".htmlentities(Dict::Format('UI:SearchFor_Class', MetaModel::GetName($sClass)), ENT_QUOTES, 'UTF-8')."\"><span class=\"search-button fa fa-search\" onclick='$sSearchAction'></span></div>";
}
@@ -1904,8 +1909,7 @@ class MenuBlock extends DisplayBlock
}
if (!$oPage->IsPrintableVersion() && ($sRefreshAction!=''))
{
$sHtml .= "<div class=\"actions_button icon_actions_button\" title=\"".htmlentities(Dict::S('UI:Button:Refresh'),
ENT_QUOTES, 'UTF-8')."\"><span class=\"refresh-button fas fa-sync\" onclick=\"$sRefreshAction\"></span></div>";
$sHtml .= "<div class=\"actions_button icon_actions_button\" title=\"".htmlentities(Dict::S('UI:Button:Refresh'), ENT_QUOTES, 'UTF-8')."\"><span class=\"refresh-button fa fa-refresh\" onclick=\"$sRefreshAction\"></span></div>";
}

View File

@@ -395,7 +395,6 @@ EOF
{
foreach($aFields as $oField)
{
/** @var \DesignerFormField $oField */
$oField->ReadParam($aValues);
}
}
@@ -680,34 +679,18 @@ class DesignerTabularForm extends DesignerForm
class DesignerFormField
{
/** @var string $sLabel */
protected $sLabel;
/** @var string $sCode */
protected $sCode;
/** @var mixed $defaultValue */
protected $defaultValue;
/** @var \DesignerForm $oForm */
protected $oForm;
/** @var bool $bMandatory */
protected $bMandatory;
/** @var bool $bReadOnly */
protected $bReadOnly;
/** @var bool $bAutoApply */
protected $bAutoApply;
/** @var array $aCSSClasses */
protected $aCSSClasses;
/** @var bool $bDisplayed */
protected $bDisplayed;
/** @var array $aWidgetExtraParams */
protected $aWidgetExtraParams;
/**
* DesignerFormField constructor.
*
* @param string $sCode
* @param string $sLabel
* @param mixed $defaultValue
*/
public function __construct($sCode, $sLabel, $defaultValue)
{
$this->sLabel = $sLabel;
@@ -720,10 +703,7 @@ class DesignerFormField
$this->bDisplayed = true;
$this->aWidgetExtraParams = array();
}
/**
* @return string
*/
public function GetCode()
{
return $this->sCode;
@@ -732,108 +712,69 @@ class DesignerFormField
/**
* @param \DesignerForm $oForm
*/
public function SetForm(DesignerForm $oForm)
public function SetForm(\DesignerForm $oForm)
{
$this->oForm = $oForm;
}
/**
* @param bool $bMandatory
*/
public function SetMandatory($bMandatory = true)
{
$this->bMandatory = $bMandatory;
}
/**
* @param bool $bReadOnly
*/
public function SetReadOnly($bReadOnly = true)
{
$this->bReadOnly = $bReadOnly;
}
/**
* @return bool
*/
public function IsReadOnly()
{
return ($this->oForm->IsReadOnly() || $this->bReadOnly);
}
/**
* @param bool $bAutoApply
*/
public function SetAutoApply($bAutoApply)
{
$this->bAutoApply = $bAutoApply;
}
/**
* @return bool
*/
public function IsAutoApply()
{
return $this->bAutoApply;
}
/**
* @param bool $bDisplayed
*/
public function SetDisplayed($bDisplayed)
{
$this->bDisplayed = $bDisplayed;
}
/**
* @return bool
*/
public function IsDisplayed()
{
return $this->bDisplayed;
}
/**
* @return string
*/
public function GetFieldId()
{
return $this->oForm->GetFieldId($this->sCode);
}
/**
* @return string
*/
public function GetWidgetClass()
{
return 'property_field';
}
/**
* @return array
*/
public function GetWidgetExtraParams()
{
return $this->aWidgetExtraParams;
}
/**
* @param \WebPage $oP
* @param string $sFormId
* @param string $sRenderMode
*
* @return array
*/
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
{
$sId = $this->oForm->GetFieldId($this->sCode);
$sName = $this->oForm->GetFieldName($this->sCode);
return array('label' => $this->sLabel, 'value' => "<input type=\"text\" id=\"$sId\" name=\"$sName\" value=\"".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."\">");
}
/**
* @param array $aValues
*/
public function ReadParam(&$aValues)
{
if ($this->IsReadOnly())
@@ -860,18 +801,12 @@ class DesignerFormField
}
}
}
/**
* @return bool
*/
public function IsVisible()
{
return true;
}
/**
* @param string $sCSSClass
*/
public function AddCSSClass($sCSSClass)
{
$this->aCSSClasses[] = $sCSSClass;
@@ -879,8 +814,6 @@ class DesignerFormField
/**
* A way to set/change the default value after constructing the field
*
* @param array $aAllDefaultValue
*/
public function SetDefaultValueFrom($aAllDefaultValue)
{
@@ -889,12 +822,7 @@ class DesignerFormField
$this->defaultValue = $aAllDefaultValue[$this->GetCode()];
}
}
/**
* @param $sFieldCode
*
* @return \DesignerFormField|false
*/
public function FindField($sFieldCode)
{
if ($this->sCode == $sFieldCode)
@@ -904,17 +832,11 @@ class DesignerFormField
return false;
}
/**
* @return string
*/
public function GetHandlerEquals()
{
return 'null';
}
/**
* @return string
*/
public function GetHandlerGetValue()
{
return 'null';
@@ -923,43 +845,25 @@ class DesignerFormField
class DesignerLabelField extends DesignerFormField
{
/** @var int $iCount A counter to automatically make the field code */
protected static $iCount = 0;
/** @var string $sDescription */
protected $sDescription;
/**
* @inheritdoc
*/
public function __construct($sLabel, $sDescription)
{
// Increase counter
static::$iCount++;
parent::__construct('label_number_' . static::$iCount, $sLabel, '');
parent::__construct('', $sLabel, '');
$this->sDescription = $sDescription;
}
/**
* @inheritdoc
*/
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
{
$sId = $this->oForm->GetFieldId($this->sCode);
$sName = $this->oForm->GetFieldName($this->sCode);
return array('label' => $this->sLabel, 'value' => $this->sDescription);
}
/**
* @inheritdoc
*/
public function ReadParam(&$aValues)
{
}
/**
* @inheritdoc
*/
public function IsVisible()
{
return true;
@@ -1430,8 +1334,7 @@ class DesignerIconSelectionField extends DesignerFormField
$sPostUploadTo = ($this->sUploadUrl == null) ? 'null' : "'{$this->sUploadUrl}'";
if (!$this->IsReadOnly())
{
$sDefaultValue = ($this->defaultValue !== '') ? $this->defaultValue : $this->aAllowedValues[$idx]['value'];
$sValue = "<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"{$sDefaultValue}\"/>";
$sValue = "<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"{$this->defaultValue}\"/>";
$oP->add_ready_script(
<<<EOF
$('#$sId').icon_select({current_idx: $idx, items: $sJSItems, post_upload_to: $sPostUploadTo});
@@ -1493,7 +1396,6 @@ class RunTimeIconSelectionField extends DesignerIconSelectionField
$sAvailableIcons .= ' static $sKey = '.var_export($sKey, true).';'.PHP_EOL;
$sAvailableIcons .= ' static $aIconFiles = '.var_export($aFiles, true).';'.PHP_EOL;
$sAvailableIcons .= '}'.PHP_EOL;
SetupUtils::builddir(dirname($sCacheFile));
file_put_contents($sCacheFile, $sAvailableIcons, LOCK_EX);
}
return $aFiles;

View File

@@ -1,20 +1,27 @@
<?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/>
/**
* Copyright (C) 2013-2020 Combodo SARL
* Class iTopWebPage
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* @copyright Copyright (C) 2010-2018 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT."/application/nicewebpage.class.inc.php");
@@ -39,19 +46,13 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
protected $sBreadCrumbEntryIcon;
protected $oCtx;
/**
* iTopWebPage constructor.
*
* @param string $sTitle
* @param bool $bPrintable
*
* @throws \Exception
*/
protected $bHasCollapsibleSection = false;
public function __construct($sTitle, $bPrintable = false)
{
parent::__construct($sTitle, $bPrintable);
$this->m_oTabs = new TabManager();
$this->oCtx = new ContextTag(ContextTag::TAG_CONSOLE);
$this->oCtx = new ContextTag('GUI:Console');
ApplicationContext::SetUrlMakerClass('iTopStandardURLMaker');
@@ -70,16 +71,18 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
$this->m_sMenu = "";
$this->m_aMessages = array();
$this->SetRootUrl(utils::GetAbsoluteUrlAppRoot());
$this->add_header("Content-type: text/html; charset=".self::PAGES_CHARSET);
$this->add_header("Cache-control: no-cache");
$this->add_header("Content-type: text/html; charset=utf-8");
$this->add_header('Cache-control: no-cache, no-store, must-revalidate');
$this->add_header('Pragma: no-cache');
$this->add_header('Expires: 0');
$this->add_header('X-Frame-Options: deny');
$this->add_linked_stylesheet("../css/jquery.treeview.css");
$this->add_linked_stylesheet("../css/jquery.autocomplete.css");
$this->add_linked_stylesheet("../css/jquery-ui-timepicker-addon.css");
$this->add_linked_stylesheet("../css/jquery.multiselect.css");
$this->add_linked_stylesheet("../css/magnific-popup.css");
$this->add_linked_stylesheet("../css/c3.min.css");
$this->add_linked_stylesheet("../css/font-awesome/css/all.min.css");
$this->add_linked_stylesheet("../css/font-awesome/css/v4-shims.min.css");
$this->add_linked_stylesheet("../css/font-awesome/css/font-awesome.min.css");
$this->add_linked_script('../js/jquery.layout.min.js');
$this->add_linked_script('../js/jquery.ba-bbq.min.js');
@@ -151,9 +154,6 @@ EOF
}
}
/**
* @return bool
*/
protected function IsMenuPaneVisible()
{
$bLeftPaneOpen = true;
@@ -176,9 +176,6 @@ EOF
return $bLeftPaneOpen;
}
/**
*
*/
protected function PrepareLayout()
{
if (MetaModel::GetConfig()->Get('demo_mode'))
@@ -227,6 +224,7 @@ EOF;
);
$sTimeFormat = AttributeDateTime::GetFormat()->ToTimeFormat();
$oTimeFormat = new DateTimeFormat($sTimeFormat);
$sJSLangShort = json_encode(strtolower(substr(Dict::GetUserLanguage(), 0, 2)));
// Date picker options
$aPickerOptions = array(
@@ -244,38 +242,29 @@ EOF;
$sJSDatePickerOptions = json_encode($aPickerOptions);
// Time picker additional options
$sUserLang = Dict::GetUserLanguage();
$sUserLangShort = strtolower(
substr($sUserLang, 0, 2)
);
// PR #40 : we are picking correct values for specific cases in dict files
// some languages are using codes like zh-CN or pt-BR
$sTimePickerLang = json_encode(
Dict::S('INTERNAL:JQuery-DatePicker:LangCode', $sUserLangShort)
);
$aPickerOptions['showOn'] = '';
$aPickerOptions['buttonImage'] = null;
$aPickerOptions['timeFormat'] = $oTimeFormat->ToDatePicker();
$aPickerOptions['controlType'] = 'select';
$aPickerOptions['closeText'] = Dict::S('UI:Button:Ok');
$sJSDateTimePickerOptions = json_encode($aPickerOptions);
if ($sTimePickerLang != '"en"')
if ($sJSLangShort != '"en"')
{
// More options that cannot be passed via json_encode since they must be evaluated client-side
$aMoreJSOptions = ",
'timeText': $.timepicker.regional[$sTimePickerLang].timeText,
'hourText': $.timepicker.regional[$sTimePickerLang].hourText,
'minuteText': $.timepicker.regional[$sTimePickerLang].minuteText,
'secondText': $.timepicker.regional[$sTimePickerLang].secondText,
'currentText': $.timepicker.regional[$sTimePickerLang].currentText
'timeText': $.timepicker.regional[$sJSLangShort].timeText,
'hourText': $.timepicker.regional[$sJSLangShort].hourText,
'minuteText': $.timepicker.regional[$sJSLangShort].minuteText,
'secondText': $.timepicker.regional[$sJSLangShort].secondText,
'currentText': $.timepicker.regional[$sJSLangShort].currentText
}";
$sJSDateTimePickerOptions = substr($sJSDateTimePickerOptions, 0, -1).$aMoreJSOptions;
}
$this->add_script(
<<< JS
<<< EOF
function GetUserLanguage()
{
return $sTimePickerLang;
return $sJSLangShort;
}
function PrepareWidgets()
{
@@ -307,12 +296,12 @@ EOF;
});
});
}
JS
EOF
);
// Attribute set tooltip on items
$this->add_ready_script(
<<<JS
<<<EOF
$('.attribute-set-item').each(function(){
// Encoding only title as the content is already sanitized by the HTML attribute.
var sLabel = $('<div/>').text($(this).attr('data-label')).html();
@@ -339,24 +328,25 @@ JS
position: { corner: { target: 'topMiddle', tooltip: 'bottomLeft' }}
});
});
JS
EOF
);
// Make image attributes zoomable
$this->add_ready_script(
<<<JS
<<<EOF
$('.view-image img').each(function(){
$(this).attr('href', $(this).attr('src'))
})
.magnificPopup({type: 'image', closeOnContentClick: true });
JS
EOF
);
$this->add_init_script(
<<< JS
<<< EOF
try
{
var myLayout; // a var is required because this page utilizes: myLayout.allowOverflow() method
// Layout
paneSize = GetUserPreference('menu_size', 300);
if ($('body').length > 0)
@@ -462,11 +452,11 @@ JS
// Do something with the error !
alert(err);
}
JS
EOF
);
$this->add_ready_script(
<<< JS
<<< EOF
// Adjust initial size
$('.v-resizable').each( function()
@@ -627,7 +617,7 @@ JS
});
}
});
JS
EOF
);
$this->add_ready_script(InlineImage::FixImagesWidth());
/*
@@ -638,7 +628,7 @@ JS
$sUserPrefs = appUserPreferences::GetAsJSON();
$this->add_script(
<<<JS
<<<EOF
// // for JQuery history
// function history_callback(hash)
// {
@@ -708,7 +698,7 @@ JS
{
$('.ui-layout-center, .ui-layout-north, .ui-layout-south').css({display: 'block'});
}
JS
EOF
);
}
@@ -743,22 +733,11 @@ JS
$this->sBreadCrumbEntryIcon = null;
}
/**
* @param string $sHtml
*/
public function AddToMenu($sHtml)
{
$this->m_sMenu .= $sHtml;
}
/**
* @return string
* @throws \CoreException
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
*/
public function GetSiloSelectionForm()
{
// List of visible Organizations
@@ -785,11 +764,17 @@ JS
switch ($iCount)
{
case 0:
case 1:
// No such dimension/silo or only one possible choice => nothing to select
// No such dimension/silo => nothing to select
$sHtml = '<div id="SiloSelection"><!-- nothing to select --></div>';
break;
case 1:
// Only one possible choice... no selection, but display the value
$oOrg = $oSet->Fetch();
$sHtml = '<div id="SiloSelection">'.$oOrg->GetName().'</div>';
$sHtml .= '';
break;
default:
$sHtml = '';
$oAppContext = new ApplicationContext();
@@ -819,9 +804,6 @@ JS
return $sHtml;
}
/**
* @throws \DictExceptionMissingString
*/
public function DisplayMenu()
{
// Display the menu
@@ -837,8 +819,6 @@ JS
protected function InitNewsroom()
{
$sNewsroomInitialImage = '';
$aProviderParams = array();
if (MetaModel::GetConfig()->Get('newsroom_enabled') !== false)
{
$oUser = UserRights::GetUserObject();
@@ -846,32 +826,31 @@ JS
* @var iNewsroomProvider[] $aProviders
*/
$aProviders = MetaModel::EnumPlugins('iNewsroomProvider');
$aProviderParams = array();
foreach($aProviders as $oProvider)
{
$oProvider->SetConfig(MetaModel::GetConfig());
$bProviderEnabled = appUserPreferences::GetPref('newsroom_provider_'.get_class($oProvider),true);
if ($bProviderEnabled && $oProvider->IsApplicable($oUser))
{
$aProviderParams[] = array(
'label' => $oProvider->GetLabel(),
'fetch_url' => $oProvider->GetFetchURL(),
'view_all_url' => $oProvider->GetViewAllURL(),
'mark_all_as_read_url' => $oProvider->GetMarkAllAsReadURL(),
'placeholders' => $oProvider->GetPlaceholders(),
'ttl' => $oProvider->GetTTL(),
);
}
$bProviderEnabled = appUserPreferences::GetPref('newsroom_provider_'.get_class($oProvider), true);
if ($bProviderEnabled && $oProvider->IsApplicable($oUser))
{
$aProviderParams[] = array(
'label' => $oProvider->GetLabel(),
'fetch_url' => $oProvider->GetFetchURL(),
'view_all_url' => $oProvider->GetViewAllURL(),
'mark_all_as_read_url' => $oProvider->GetMarkAllAsReadURL(),
'placeholders' => $oProvider->GetPlaceholders(),
'ttl' => $oProvider->GetTTL(),
);
}
}
// Show newsroom only if there are some providers
if (count($aProviderParams) > 0)
{
$sImageUrl= 'fas fa-comment-dots';
$sPlaceholderImageUrl= 'far fa-envelope';
$sImageUrl= '../images/newsroom_menu.png';
$sPlaceholderImageUrl= '../images/newsroom-message.svg';
$aParams = array(
'image_icon' => $sImageUrl,
'placeholder_image_icon' => $sPlaceholderImageUrl,
'cache_uuid' => 'itop-newsroom-'.UserRights::GetUserId().'-'.md5(APPROOT),
'image_url' => $sImageUrl,
'placeholder_image_url' => $sPlaceholderImageUrl,
'cache_uuid' => 'itop-newsroom-'.md5(APPROOT),
'providers' => $aProviderParams,
'display_limit' => (int)appUserPreferences::GetPref('newsroom_display_size', 7),
'labels' => array(
@@ -886,16 +865,20 @@ JS
$('#top-left-newsroom-cell').newsroom_menu($sParams);
EOF
);
$sNewsroomInitialImage = '<i style="opacity:0.4" class="top-right-icon fas fa-comment-dots"></i>';
$sNewsroomInitialImage = '<img style="opacity:0.4" src="../images/newsroom_menu.png">';
}
// else no newsroom menu
return $sNewsroomInitialImage;
else
{
// No newsroom menu at all
}
}
// else no newsroom menu
return $sNewsroomInitialImage;
}
/**
* @inheritDoc
* @throws \Exception
* Outputs (via some echo) the complete HTML page by assembling all its elements
*/
public function output()
{
@@ -974,8 +957,8 @@ EOF
$sNewEntry = json_encode(array(
'id' => $this->sBreadCrumbEntryId,
'url' => $this->sBreadCrumbEntryUrl,
'label' => htmlentities($this->sBreadCrumbEntryLabel, ENT_QUOTES, self::PAGES_CHARSET),
'description' => htmlentities($this->sBreadCrumbEntryDescription, ENT_QUOTES, self::PAGES_CHARSET),
'label' => htmlentities($this->sBreadCrumbEntryLabel, ENT_QUOTES, 'UTF-8'),
'description' => htmlentities($this->sBreadCrumbEntryDescription, ENT_QUOTES, 'UTF-8'),
'icon' => $this->sBreadCrumbEntryIcon,
));
}
@@ -1008,9 +991,8 @@ EOF
$sHtml .= "<head>\n";
// Make sure that Internet Explorer renders the page using its latest/highest/greatest standards !
$sHtml .= "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n";
$sPageCharset = self::PAGES_CHARSET;
$sHtml .= "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=$sPageCharset\" />\n";
$sHtml .= "<title>".htmlentities($this->s_title, ENT_QUOTES, $sPageCharset)."</title>\n";
$sHtml .= "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
$sHtml .= "<title>".htmlentities($this->s_title, ENT_QUOTES, 'UTF-8')."</title>\n";
$sHtml .= $this->get_base_tag();
// Stylesheets MUST be loaded before any scripts otherwise
// jQuery scripts may face some spurious problems (like failing on a 'reload')
@@ -1129,18 +1111,16 @@ EOF
{
$sBodyClass = 'printable-version';
}
$sHtml .= "<body class=\"$sBodyClass\" data-gui-type=\"backoffice\">\n";
$sHtml .= "<body class=\"$sBodyClass\">\n";
if ($this->IsPrintableVersion())
{
$sHtml .= "<div class=\"explain-printable not-printable\">";
$sHtml .= '<p>'.Dict::Format('UI:ExplainPrintable',
'<img src="../images/eye-open-555.png" style="vertical-align:middle">').'</p>';
$sHtml .= "<div id=\"hiddeable_chapters\"></div>";
$sHtml .= '<button onclick="window.print()">'.htmlentities(Dict::S('UI:Button:GoPrint'), ENT_QUOTES,
self::PAGES_CHARSET).'</button>';
$sHtml .= '<button onclick="window.print()">'.htmlentities(Dict::S('UI:Button:GoPrint'), ENT_QUOTES, 'UTF-8').'</button>';
$sHtml .= '&nbsp;';
$sHtml .= '<button onclick="window.close()">'.htmlentities(Dict::S('UI:Button:Cancel'), ENT_QUOTES,
self::PAGES_CHARSET).'</button>';
$sHtml .= '<button onclick="window.close()">'.htmlentities(Dict::S('UI:Button:Cancel'), ENT_QUOTES, 'UTF-8').'</button>';
$sHtml .= '&nbsp;';
$sDefaultResolution = '27.7cm';
@@ -1166,7 +1146,7 @@ EOF;
}
// Render the revision number
if (ITOP_REVISION == 'svn')
if (ITOP_REVISION == '$WCREV$')
{
// This is NOT a version built using the buil system, just display the main version
$sVersionString = Dict::Format('UI:iTopVersion:Short', ITOP_APPLICATION, ITOP_VERSION);
@@ -1178,7 +1158,7 @@ EOF;
}
// Render the text of the global search form
$sText = htmlentities(utils::ReadParam('text', '', false, 'raw_data'), ENT_QUOTES, self::PAGES_CHARSET);
$sText = htmlentities(utils::ReadParam('text', '', false, 'raw_data'), ENT_QUOTES, 'UTF-8');
$sOnClick = " onclick=\"if ($('#global-search-input').val() != '') { $('#global-search form').submit(); } \"";
$sDefaultPlaceHolder = Dict::S("UI:YourSearch");
@@ -1202,7 +1182,7 @@ EOF;
{
$sLogonMessage = Dict::Format('UI:LoggedAsMessage', $sUserName);
}
$sLogOffMenu = "<span id=\"logOffBtn\"><ul><li><i class=\"top-right-icon icon-additional-arrow fas fa-power-off\"></i><ul>";
$sLogOffMenu = "<span id=\"logOffBtn\"><ul><li><img src=\"../images/on-off-menu.png\"><ul>";
$sLogOffMenu .= "<li><span>$sLogonMessage</span></li>\n";
$aActions = array();
@@ -1233,7 +1213,7 @@ EOF;
$oExitArchive = new JSPopupMenuItem('UI:ArchiveModeOff', Dict::S('UI:ArchiveModeOff'), 'return ArchiveMode(false);');
$aActions[$oExitArchive->GetUID()] = $oExitArchive->GetMenuItem();
$sIcon = '<span class="fas fa-lock fa-1x"></span>';
$sIcon = '<span class="fa fa-lock fa-1x"></span>';
$this->AddApplicationMessage(Dict::S('UI:ArchiveMode:Banner'), $sIcon, Dict::S('UI:ArchiveMode:Banner+'));
}
elseif (UserRights::CanBrowseArchive())
@@ -1279,8 +1259,8 @@ EOF;
$sIcon =
<<<EOF
<span class="fa-stack fa-sm">
<i class="fas fa-pencil-alt fa-flip-horizontal fa-stack-1x"></i>
<i class="fas fa-ban fa-stack-2x text-danger"></i>
<i class="fa fa-pencil fa-flip-horizontal fa-stack-1x"></i>
<i class="fa fa-ban fa-stack-2x text-danger"></i>
</span>
EOF;
@@ -1297,7 +1277,7 @@ EOF;
{
$sHtmlIcon = $aMessage['icon'] ? $aMessage['icon'] : '';
$sHtmlMessage = $aMessage['message'];
$sTitleAttr = $aMessage['tip'] ? 'title="'.htmlentities($aMessage['tip'], ENT_QUOTES, self::PAGES_CHARSET).'"' : '';
$sTitleAttr = $aMessage['tip'] ? 'title="'.htmlentities($aMessage['tip'], ENT_QUOTES, 'UTF-8').'"' : '';
$sApplicationMessages .= '<div class="app-message" '.$sTitleAttr.'><span class="app-message-icon">'.$sHtmlIcon.'</span><span class="app-message-body">'.$sHtmlMessage.'</div></span>';
}
@@ -1328,11 +1308,9 @@ EOF;
$sHtml .= '<!-- Beginning of the left pane -->';
$sHtml .= ' <div class="ui-layout-north">';
$sHtml .= ' <div id="header-logo">';
$sHtml .= ' <div id="top-left"></div><div id="logo"><a href="'
.htmlentities($sIconUrl, ENT_QUOTES, self::PAGES_CHARSET)
.'"><img src="'.$sDisplayIcon.'" title="'
.htmlentities($sVersionString, ENT_QUOTES, self::PAGES_CHARSET)
.'" style="border:0; margin-top:16px; margin-right:40px;"/></a></div>';
$sHtml .= ' <div id="top-left"></div><div id="logo"><a href="'.htmlentities($sIconUrl, ENT_QUOTES,
'UTF-8').'"><img src="'.$sDisplayIcon.'" title="'.htmlentities($sVersionString, ENT_QUOTES,
'UTF-8').'" style="border:0; margin-top:16px; margin-right:40px;"/></a></div>';
$sHtml .= ' </div>';
$sHtml .= ' <div class="header-menu">';
if (!MetaModel::GetConfig()->Get('demo_mode'))
@@ -1364,10 +1342,10 @@ EOF;
$sHtml .= ' <table id="top-bar-table">';
$sHtml .= ' <tr>';
$sHtml .= ' <td id="open-left-pane" class="menu-pane-exclusive" style="'.$GoHomeInitialStyle.'" onclick="$(\'body\').layout().open(\'west\');">';
$sHtml .= ' <i class="fas fa-bars"></i>';
$sHtml .= ' <img src="../images/menu.png">';
$sHtml .= ' </td>';
$sHtml .= ' <td id="go-home" class="menu-pane-exclusive" style="'.$GoHomeInitialStyle.'">';
$sHtml .= ' <a href="'.utils::GetAbsoluteUrlAppRoot().'pages/UI.php"><i class="fas fa-home"></i></a>';
$sHtml .= ' <a href="'.utils::GetAbsoluteUrlAppRoot().'pages/UI.php"><img src="../images/home.png"></a>';
$sHtml .= ' </td>';
$sHtml .= ' <td class="top-bar-spacer menu-pane-exclusive" style="'.$GoHomeInitialStyle.'">';
$sHtml .= ' </td>';
@@ -1377,8 +1355,8 @@ EOF;
$sHtml .= ' <td id="top-bar-table-search">';
$sHtml .= ' <div id="global-search"><form action="'.utils::GetAbsoluteUrlAppRoot().'pages/UI.php">';
$sHtml .= ' <table id="top-left-buttons-area"><tr>';
$sHtml .= ' <td id="top-left-global-search-cell"><div id="global-search-area"><input id="global-search-input" type="text" name="text" placeholder="'.$sDefaultPlaceHolder.'" value="'.$sText.'"></input><div '.$sOnClick.' id="global-search-image"><i class="top-right-icon fa-flip-horizontal fas fa-search"></i><input type="hidden" name="operation" value="full_text"/></div></div></td>';
$sHtml .= ' <td id="top-left-help-cell"><a id="help-link" href="'.$sOnlineHelpUrl.'" target="_blank" title="'.Dict::S('UI:Help').'"><i class="top-right-icon fas fa-question-circle"></i></a></td>';
$sHtml .= ' <td id="top-left-global-search-cell"><div id="global-search-area"><input id="global-search-input" type="text" name="text" placeholder="'.$sDefaultPlaceHolder.'" value="'.$sText.'"></input><div '.$sOnClick.' id="global-search-image"><input type="hidden" name="operation" value="full_text"/></div></div></td>';
$sHtml .= ' <td id="top-left-help-cell"><a id="help-link" href="'.$sOnlineHelpUrl.'" target="_blank"><img title="'.Dict::S('UI:Help').'" src="../images/help.png?t='.utils::GetCacheBusterTimestamp().'"/></td>';
$sHtml .= ' <td id="top-left-newsroom-cell">'.$sNewsRoomInitialImage.'</td>';
$sHtml .= ' <td id="top-left-logoff-cell">'.self::FilterXSS($sLogOffMenu).'</td>';
$sHtml .= ' </tr></table></form></div>';
@@ -1433,12 +1411,9 @@ EOF;
{
if ($this->GetOutputFormat() == 'pdf' && $this->IsOutputFormatAvailable('pdf'))
{
// Note: Apparently this was a demand from ITOMIG a while back, so it's not "dead code" per say.
// The last trace we got is in R-007989. Do not remove this without checking before with the concerned parties if it is still used!
if (@is_readable(APPROOT.'lib/MPDF/mpdf.php'))
{
require_once(APPROOT.'lib/MPDF/mpdf.php');
/** @noinspection PhpUndefinedClassInspection Check above comment */
$oMPDF = new mPDF('c');
$oMPDF->mirroMargins = false;
if ($this->a_base['href'] != '')
@@ -1466,67 +1441,90 @@ EOF;
}
/**
* @inheritDoc
* @throws \Exception
* Adds init scripts for the collapsible sections
*/
private function outputCollapsibleSectionInit()
{
if (!$this->bHasCollapsibleSection)
{
return;
}
$this->add_script(<<<'EOD'
function initCollapsibleSection(iSectionId, bOpenedByDefault, sSectionStateStorageKey)
{
var bStoredSectionState = JSON.parse(localStorage.getItem(sSectionStateStorageKey));
var bIsSectionOpenedInitially = (bStoredSectionState == null) ? bOpenedByDefault : bStoredSectionState;
if (bIsSectionOpenedInitially) {
$("#LnkCollapse_"+iSectionId).toggleClass("open");
$("#Collapse_"+iSectionId).toggle();
}
$("#LnkCollapse_"+iSectionId).click(function(e) {
localStorage.setItem(sSectionStateStorageKey, !($("#Collapse_"+iSectionId).is(":visible")));
$("#LnkCollapse_"+iSectionId).toggleClass("open");
$("#Collapse_"+iSectionId).slideToggle("normal");
e.preventDefault(); // we don't want to do anything more (see #1030 : a non wanted tab switching was triggered)
});
}
EOD
);
}
public function AddTabContainer($sTabContainer, $sPrefix = '')
{
$this->add($this->m_oTabs->AddTabContainer($sTabContainer, $sPrefix));
}
/**
* @inheritDoc
* @throws \Exception
*/
public function AddToTab($sTabContainer, $sTabCode, $sHtml)
public function AddToTab($sTabContainer, $sTabLabel, $sHtml)
{
$this->add($this->m_oTabs->AddToTab($sTabContainer, $sTabCode, $sHtml));
$this->add($this->m_oTabs->AddToTab($sTabContainer, $sTabLabel, $sHtml));
}
/**
* @inheritDoc
*/
public function SetCurrentTabContainer($sTabContainer = '')
{
return $this->m_oTabs->SetCurrentTabContainer($sTabContainer);
}
/**
* @inheritDoc
*/
public function SetCurrentTab($sTabCode = '', $sTabTitle = null)
public function SetCurrentTab($sTabLabel = '')
{
return $this->m_oTabs->SetCurrentTab($sTabCode, $sTabTitle);
return $this->m_oTabs->SetCurrentTab($sTabLabel);
}
/**
* @inheritDoc
* @throws \Exception
* Add a tab which content will be loaded asynchronously via the supplied URL
*
* Limitations:
* Cross site scripting is not not allowed for security reasons. Use a normal tab with an IFRAME if you want to pull content from
* another server. Static content cannot be added inside such tabs.
*
* @param string $sTabLabel The (localised) label of the tab
* @param string $sUrl The URL to load (on the same server)
* @param boolean $bCache Whether or not to cache the content of the tab once it has been loaded. flase will cause the tab to be
* reloaded upon each activation.
*
* @since 2.0.3
*/
public function AddAjaxTab($sTabCode, $sUrl, $bCache = true, $sTabTitle = null)
public function AddAjaxTab($sTabLabel, $sUrl, $bCache = true)
{
$this->add($this->m_oTabs->AddAjaxTab($sTabCode, $sUrl, $bCache, $sTabTitle));
$this->add($this->m_oTabs->AddAjaxTab($sTabLabel, $sUrl, $bCache));
}
/**
* @inheritDoc
*/
public function GetCurrentTab()
{
return $this->m_oTabs->GetCurrentTab();
}
/**
* @inheritDoc
*/
public function RemoveTab($sTabCode, $sTabContainer = null)
public function RemoveTab($sTabLabel, $sTabContainer = null)
{
$this->m_oTabs->RemoveTab($sTabCode, $sTabContainer);
$this->m_oTabs->RemoveTab($sTabLabel, $sTabContainer);
}
/**
* @inheritDoc
* Finds the tab whose title matches a given pattern
*
* @return mixed The name of the tab as a string or false if not found
*/
public function FindTab($sPattern, $sTabContainer = null)
{
@@ -1538,19 +1536,49 @@ EOF;
* DOES NOT WORK: apparently in the *old* version of jquery
* that we are using this is not supported... TO DO upgrade
* the whole jquery bundle...
*
* @param string $sTabContainer
* @param string $sTabCode
*/
public function SelectTab($sTabContainer, $sTabCode)
public function SelectTab($sTabContainer, $sTabLabel)
{
$this->add_ready_script($this->m_oTabs->SelectTab($sTabContainer, $sTabCode));
$this->add_ready_script($this->m_oTabs->SelectTab($sTabContainer, $sTabLabel));
}
public function StartCollapsibleSection(
$sSectionLabel, $bOpenedByDefault = false, $sSectionStateStorageBusinessKey = ''
) {
$this->add($this->GetStartCollapsibleSection($sSectionLabel, $bOpenedByDefault,
$sSectionStateStorageBusinessKey));
}
private function GetStartCollapsibleSection(
$sSectionLabel, $bOpenedByDefault = false, $sSectionStateStorageBusinessKey = ''
) {
$this->bHasCollapsibleSection = true;
$sHtml = '';
static $iSectionId = 0;
$sHtml .= '<a id="LnkCollapse_'.$iSectionId.'" class="CollapsibleLabel" href="#">'.$sSectionLabel.'</a></br>'."\n";
$sHtml .= '<div id="Collapse_'.$iSectionId.'" style="display:none">'."\n";
$oConfig = MetaModel::GetConfig();
$sSectionStateStorageKey = $oConfig->GetItopInstanceid().'/'.$sSectionStateStorageBusinessKey.'/collapsible-'.$iSectionId;
$sSectionStateStorageKey = json_encode($sSectionStateStorageKey);
$sOpenedByDefault = ($bOpenedByDefault) ? 'true' : 'false';
$this->add_ready_script("initCollapsibleSection($iSectionId, $sOpenedByDefault, '$sSectionStateStorageKey');");
$iSectionId++;
return $sHtml;
}
public function EndCollapsibleSection()
{
$this->add($this->GetEndCollapsibleSection());
}
public function GetEndCollapsibleSection()
{
return "</div>";
}
/**
* @inheritDoc
* @throws \Exception
*/
public function add($sHtml)
{
if (($this->m_oTabs->GetCurrentTabContainer() != '') && ($this->m_oTabs->GetCurrentTab() != ''))
@@ -1564,7 +1592,9 @@ EOF;
}
/**
* @inheritDoc
* Records the current state of the 'html' part of the page output
*
* @return mixed The current state of the 'html' output
*/
public function start_capture()
{
@@ -1584,7 +1614,12 @@ EOF;
}
/**
* @inheritDoc
* Returns the part of the html output that occurred since the call to start_capture
* and removes this part from the current html output
*
* @param $offset mixed The value returned by start_capture
*
* @return string The part of the html output that was added since the call to start_capture
*/
public function end_capture($offset)
{
@@ -1609,21 +1644,15 @@ EOF;
/**
* Set the message to be displayed in the 'app-banner' section at the top of the page
*
* @param string $sHtmlMessage
*/
public function SetMessage($sHtmlMessage)
{
$sHtmlIcon = '<span class="fas fa-comment fa-1x"></span>';
$sHtmlIcon = '<span class="fa fa-comment fa-1x"></span>';
$this->AddApplicationMessage($sHtmlMessage, $sHtmlIcon);
}
/**
* Add message to be displayed in the 'app-banner' section at the top of the page
*
* @param string $sHtmlMessage
* @param string|null $sHtmlIcon
* @param string|null $sTip
*/
public function AddApplicationMessage($sHtmlMessage, $sHtmlIcon = null, $sTip = null)
{
@@ -1644,7 +1673,6 @@ EOF;
* @param string $sContent
* @param string $sCssClasses CSS classes to add to the container
*
* @throws \Exception
* @since 2.6
*/
public function AddHeaderMessage($sContent, $sCssClasses = 'message_info')
@@ -1658,8 +1686,6 @@ EOF
/**
* Adds a script to be executed when the DOM is ready (typical JQuery use), right before add_ready_script
*
* @param string $sScript
*
* @return void
*/
public function add_init_script($sScript)

View File

@@ -1,124 +0,0 @@
<?php
/**
* Class LoginBasic
*
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class LoginBasic extends AbstractLoginFSMExtension
{
/**
* Return the list of supported login modes for this plugin
*
* @return array of supported login modes
*/
public function ListSupportedLoginModes()
{
return array('basic');
}
protected function OnModeDetection(&$iErrorCode)
{
if (!isset($_SESSION['login_mode']))
{
if (isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION']))
{
$_SESSION['login_mode'] = 'basic';
}
elseif (isset($_SERVER['PHP_AUTH_USER']))
{
$_SESSION['login_mode'] = 'basic';
}
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnReadCredentials(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'basic')
{
list($sAuthUser, $sAuthPwd) = $this->GetAuthUserAndPassword();
$_SESSION['login_temp_auth_user'] = $sAuthUser;
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnCheckCredentials(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'basic')
{
list($sAuthUser, $sAuthPwd) = $this->GetAuthUserAndPassword();
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, $_SESSION['login_mode'], 'internal'))
{
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
return LoginWebPage::LOGIN_FSM_ERROR;
}
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnCredentialsOK(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'basic')
{
list($sAuthUser) = $this->GetAuthUserAndPassword();
LoginWebPage::OnLoginSuccess($sAuthUser, 'internal', $_SESSION['login_mode']);
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnError(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'basic')
{
LoginWebPage::HTTP401Error();
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnConnected(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'basic')
{
$_SESSION['can_logoff'] = true;
return LoginWebPage::CheckLoggedUser($iErrorCode);
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
private function GetAuthUserAndPassword()
{
$sAuthUser = '';
$sAuthPwd = null;
if (isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION']))
{
list($sAuthUser, $sAuthPwd) = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
}
else
{
if (isset($_SERVER['PHP_AUTH_USER']))
{
$sAuthUser = $_SERVER['PHP_AUTH_USER'];
// Unfortunately, the RFC is not clear about the encoding...
// IE and FF supply the user and password encoded in ISO-8859-1 whereas Chrome provides them encoded in UTF-8
// So let's try to guess if it's an UTF-8 string or not... fortunately all encodings share the same ASCII base
if (!LoginWebPage::LooksLikeUTF8($sAuthUser))
{
// Does not look like and UTF-8 string, try to convert it from iso-8859-1 to UTF-8
// Supposed to be harmless in case of a plain ASCII string...
$sAuthUser = iconv('iso-8859-1', 'utf-8', $sAuthUser);
}
$sAuthPwd = $_SERVER['PHP_AUTH_PW'];
if (!LoginWebPage::LooksLikeUTF8($sAuthPwd))
{
// Does not look like and UTF-8 string, try to convert it from iso-8859-1 to UTF-8
// Supposed to be harmless in case of a plain ASCII string...
$sAuthPwd = iconv('iso-8859-1', 'utf-8', $sAuthPwd);
}
}
}
return array($sAuthUser, $sAuthPwd);
}
}

View File

@@ -1,129 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Class LoginDefaultBefore
*/
class LoginDefaultBefore extends AbstractLoginFSMExtension
{
/**
* Must be executed before the other login plugins
*
* @return array of supported login modes
*/
public function ListSupportedLoginModes()
{
return array('before');
}
protected function OnStart(&$iErrorCode)
{
$iErrorCode = LoginWebPage::EXIT_CODE_OK;
unset($_SESSION['login_temp_auth_user']);
// Check if proposed login mode is present and allowed
$aAllowedLoginTypes = MetaModel::GetConfig()->GetAllowedLoginTypes();
$sProposedLoginMode = utils::ReadParam('login_mode', '');
$index = array_search($sProposedLoginMode, $aAllowedLoginTypes);
if ($index !== false)
{
// Force login mode
$_SESSION['login_mode'] = $sProposedLoginMode;
}
else
{
unset($_SESSION['login_mode']);
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnReadCredentials(&$iErrorCode)
{
// Check if proposed login mode is present and allowed
$aAllowedLoginTypes = MetaModel::GetConfig()->GetAllowedLoginTypes();
$sProposedLoginMode = utils::ReadParam('login_mode', '');
$index = array_search($sProposedLoginMode, $aAllowedLoginTypes);
if ($index !== false)
{
// Force login mode
LoginWebPage::SetLoginModeAndReload($sProposedLoginMode);
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
}
/**
* Class LoginDefaultAfter
*/
class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExtension
{
/**
* Must be executed after the other login plugins
*
* @return array of supported login modes
*/
public function ListSupportedLoginModes()
{
return array('after');
}
protected function OnError(&$iErrorCode)
{
self::ResetLoginSession();
$iOnExit = LoginWebPage::getIOnExit();
if ($iOnExit == LoginWebPage::EXIT_RETURN)
{
return LoginWebPage::LOGIN_FSM_RETURN; // Error, exit FSM
}
elseif ($iOnExit == LoginWebPage::EXIT_HTTP_401)
{
LoginWebPage::HTTP401Error(); // Error, exit
}
// LoginWebPage::EXIT_PROMPT
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnCredentialsOk(&$iErrorCode)
{
if (!isset($_SESSION['login_mode']))
{
// If no plugin validated the user, exit
self::ResetLoginSession();
exit();
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
/**
* Execute all actions to log out properly
*/
public function LogoutAction()
{
self::ResetLoginSession();
}
protected function OnConnected(&$iErrorCode)
{
unset($_SESSION['login_temp_auth_user']);
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
// Hard reset of the session
private static function ResetLoginSession()
{
LoginWebPage::ResetSession();
foreach (array_keys($_SESSION) as $sKey)
{
if (utils::StartsWith($sKey, 'login_'))
{
unset($_SESSION[$sKey]);
}
}
}
}

View File

@@ -1,80 +0,0 @@
<?php
/**
* Class LoginExternal
*
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class LoginExternal extends AbstractLoginFSMExtension
{
/**
* Return the list of supported login modes for this plugin
*
* @return array of supported login modes
*/
public function ListSupportedLoginModes()
{
return array('external');
}
protected function OnModeDetection(&$iErrorCode)
{
if (!isset($_SESSION['login_mode']))
{
$sAuthUser = $this->GetAuthUser();
if ($sAuthUser && (strlen($sAuthUser) > 0))
{
$_SESSION['login_mode'] = 'external';
}
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnCheckCredentials(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'external')
{
$sAuthUser = $this->GetAuthUser();
if (!UserRights::CheckCredentials($sAuthUser, '', $_SESSION['login_mode'], 'external'))
{
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
return LoginWebPage::LOGIN_FSM_ERROR;
}
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnCredentialsOK(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'external')
{
$sAuthUser = $this->GetAuthUser();
LoginWebPage::OnLoginSuccess($sAuthUser, 'external', $_SESSION['login_mode']);
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnConnected(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'external')
{
$_SESSION['can_logoff'] = false;
return LoginWebPage::CheckLoggedUser($iErrorCode);
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
/**
* @return bool
*/
private function GetAuthUser()
{
$sExtAuthVar = MetaModel::GetConfig()->GetExternalAuthenticationVariable(); // In which variable is the info passed ?
eval('$sAuthUser = isset('.$sExtAuthVar.') ? '.$sExtAuthVar.' : false;'); // Retrieve the value
/** @var string $sAuthUser */
return $sAuthUser; // Retrieve the value
}
}

View File

@@ -1,138 +0,0 @@
<?php
/**
* Class LoginForm
*
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
{
private $bForceFormOnError = false;
/**
* Return the list of supported login modes for this plugin
*
* @return array of supported login modes
*/
public function ListSupportedLoginModes()
{
return array('form');
}
protected function OnReadCredentials(&$iErrorCode)
{
if (!isset($_SESSION['login_mode']) || ($_SESSION['login_mode'] == 'form'))
{
$sAuthUser = utils::ReadPostedParam('auth_user', '', 'raw_data');
$sAuthPwd = utils::ReadPostedParam('auth_pwd', null, 'raw_data');
if ($this->bForceFormOnError || empty($sAuthUser) || empty($sAuthPwd))
{
if (array_key_exists('HTTP_X_COMBODO_AJAX', $_SERVER))
{
// X-Combodo-Ajax is a special header automatically added to all ajax requests
// Let's reply that we're currently logged-out
header('HTTP/1.0 401 Unauthorized');
exit;
}
// No credentials yet, display the form
$oPage = LoginWebPage::NewLoginWebPage();
$oPage->DisplayLoginForm($this->bForceFormOnError);
$oPage->output();
$this->bForceFormOnError = false;
exit;
}
$_SESSION['login_temp_auth_user'] = $sAuthUser;
$_SESSION['login_mode'] = 'form';
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnCheckCredentials(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'form')
{
$sAuthUser = utils::ReadPostedParam('auth_user', '', 'raw_data');
$sAuthPwd = utils::ReadPostedParam('auth_pwd', null, 'raw_data');
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, $_SESSION['login_mode'], 'internal'))
{
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
return LoginWebPage::LOGIN_FSM_ERROR;
}
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnCredentialsOK(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'form')
{
if (isset($_SESSION['auth_user']))
{
// If FSM reenter this state (example 2FA) then the auth_user is not resubmitted
$sAuthUser = $_SESSION['auth_user'];
}
else
{
$sAuthUser = utils::ReadPostedParam('auth_user', '', 'raw_data');
}
// Store 'auth_user' in session for further use
LoginWebPage::OnLoginSuccess($sAuthUser, 'internal', $_SESSION['login_mode']);
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnError(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'form')
{
$this->bForceFormOnError = true;
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnConnected(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'form')
{
$_SESSION['can_logoff'] = true;
return LoginWebPage::CheckLoggedUser($iErrorCode);
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
/**
* @return LoginTwigContext
* @throws \Exception
*/
public function GetTwigContext()
{
$oLoginContext = new LoginTwigContext();
$oLoginContext->AddPostedVar('auth_user');
$oLoginContext->AddPostedVar('auth_pwd');
$sAuthUser = utils::ReadParam('auth_user', '', true, 'raw_data');
$sAuthPwd = utils::ReadParam('suggest_pwd', '', true, 'raw_data');
$aData = array(
'sAuthUser' => $sAuthUser,
'sAuthPwd' => $sAuthPwd,
);
$oLoginContext->AddBlockExtension('login_input', new LoginBlockExtension('extensionblock/loginforminput.html.twig', $aData));
$oLoginContext->AddBlockExtension('login_submit', new LoginBlockExtension('extensionblock/loginformsubmit.html.twig'));
$oLoginContext->AddBlockExtension('login_form_footer', new LoginBlockExtension('extensionblock/loginformfooter.html.twig'));
$bEnableResetPassword = empty(MetaModel::GetConfig()->Get('forgot_password')) ? true : MetaModel::GetConfig()->Get('forgot_password');
$sResetPasswordUrl = utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php?loginop=forgot_pwd';
$aData = array(
'bEnableResetPassword' => $bEnableResetPassword,
'sResetPasswordUrl' => $sResetPasswordUrl,
);
$oLoginContext->AddBlockExtension('login_links', new LoginBlockExtension('extensionblock/loginformlinks.html.twig', $aData));
return $oLoginContext;
}
}

View File

@@ -1,321 +0,0 @@
<?php
/**
*
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\TwigExtension;
/**
* Twig context for modules extending the login screen
* Class LoginTwigContext
*/
class LoginTwigContext
{
/** @var array */
private $aBlockExtension;
/** @var array */
private $aPostedVars;
/** @var string */
private $sTwigLoaderPath;
/** @var array */
private $aCSSFiles;
/** @var array */
private $aJsFiles;
private $sTwigNameSpace;
/**
* Build a context to display the twig files used
* to extend the login screens
*
* LoginTwigContext constructor.
* @api
*/
public function __construct()
{
$this->aBlockExtension = array();
$this->aPostedVars = array();
$this->sTwigLoaderPath = null;
$this->aCSSFiles = array();
$this->aJsFiles = array();
$this->sTwigNameSpace = null;
}
/**
* Set the absolute path on disk of the folder containing the twig templates
*
* @param string $sPath absolute path of twig templates directory
* @api
*/
public function SetLoaderPath($sPath)
{
$this->sTwigLoaderPath = $sPath;
}
/**
* Add a Twig block extension
*
* @param string $sBlockName
* @param LoginBlockExtension $oBlockExtension
*/
public function AddBlockExtension($sBlockName, $oBlockExtension)
{
$this->aBlockExtension[$sBlockName] = $oBlockExtension;
}
/**
* Add a variable intended to be posted on URL (and managed) by the module.
* Declaring the posted variables will prevent the core engine to manipulate these variables.
*
* @param string $sPostedVar Name of the posted variable
* @api
*/
public function AddPostedVar($sPostedVar)
{
$this->aPostedVars[] = $sPostedVar;
}
/**
* Add the URL of a CSS file to link to the login screen
*
* @param string $sFile URL of the CSS file to link
* @api
*/
public function AddCSSFile($sFile)
{
$this->aCSSFiles[] = $sFile;
}
/**
* Add the URL of a javascript file to link to the login screen
* @param string $sFile URL of the javascript file to link
* @api
*/
public function AddJsFile($sFile)
{
$this->aJsFiles[] = $sFile;
}
/**
* @param string $sBlockName
*
* @return \LoginBlockExtension
*/
public function GetBlockExtension($sBlockName)
{
/** @var LoginBlockExtension $oBlockExtension */
$oBlockExtension = isset($this->aBlockExtension[$sBlockName]) ? $this->aBlockExtension[$sBlockName] : null;
return $oBlockExtension;
}
/**
* @return array
*/
public function GetPostedVars()
{
return $this->aPostedVars;
}
/**
* @return string
*/
public function GetTwigLoaderPath()
{
return $this->sTwigLoaderPath;
}
/**
* @return array
*/
public function GetCSSFiles()
{
return $this->aCSSFiles;
}
/**
* @return array
*/
public function GetJsFiles()
{
return $this->aJsFiles;
}
}
/**
* Twig block description for login screen extension
* The login screen can be extended by adding twig templates
* to specific blocks of the login screens
*
* Class LoginBlockExtension
*/
class LoginBlockExtension
{
private $sTwig;
private $aData;
/**
* Create a new twig extension block
* The given twig template can be HTML, CSS or JavaScript.
* CSS goes to the block named 'css' and is inline in the page.
* JavaScript goes to the blocks named 'script' or 'ready_script' and are inline in the page.
* HTML goes to everywhere else
*
* LoginBlockExtension constructor.
*
* @param string $sTwig name of the twig file relative to the path given to the LoginTwigContext
* @param array $aData Data given to the twig template (into the variable {{ aData }})
* @api
*/
public function __construct($sTwig, $aData = array())
{
$this->sTwig = $sTwig;
$this->aData = $aData;
}
public function GetTwig()
{
return $this->sTwig;
}
public function GetData()
{
return $this->aData;
}
}
/**
* Used by LoginWebPage to display the login screen
* Class LoginTwigRenderer
*/
class LoginTwigRenderer
{
private $aLoginPluginList;
private $aPluginFormData;
private $aPostedVars;
private $oTwig;
public function __construct()
{
$this->aLoginPluginList = LoginWebPage::GetLoginPluginList('iLoginUIExtension', false);
$this->aPluginFormData = array();
$aTwigLoaders = array();
$this->aPostedVars = array();
foreach ($this->aLoginPluginList as $oLoginPlugin)
{
/** @var \iLoginUIExtension $oLoginPlugin */
$oLoginContext = $oLoginPlugin->GetTwigContext();
if (is_null($oLoginContext))
{
continue;
}
$this->aPluginFormData[] = $oLoginContext;
$sTwigLoaderPath = $oLoginContext->GetTwigLoaderPath();
if ($sTwigLoaderPath != null)
{
$oExtensionLoader = new Twig_Loader_Filesystem();
$oExtensionLoader->setPaths($sTwigLoaderPath);
$aTwigLoaders[] = $oExtensionLoader;
}
$this->aPostedVars = array_merge($this->aPostedVars, $oLoginContext->GetPostedVars());
}
$oCoreLoader = new Twig_Loader_Filesystem(array(), APPROOT.'templates');
$aCoreTemplatesPaths = array('login', 'login/password');
// Having this path declared after the plugins let the plugins replace the core templates
$oCoreLoader->setPaths($aCoreTemplatesPaths);
// Having the core templates accessible within a different namespace offer the possibility to extend them while replacing them
$oCoreLoader->setPaths($aCoreTemplatesPaths, 'ItopCore');
$aTwigLoaders[] = $oCoreLoader;
$oLoader = new Twig_Loader_Chain($aTwigLoaders);
$this->oTwig = new Twig_Environment($oLoader);
TwigExtension::RegisterTwigExtensions($this->oTwig);
}
public function GetDefaultVars()
{
$sLogo = 'itop-logo-external.png';
$sBrandingLogo = 'login-logo.png';
$sVersionShort = Dict::Format('UI:iTopVersion:Short', ITOP_APPLICATION, ITOP_VERSION);
$sIconUrl = Utils::GetConfig()->Get('app_icon_url');
$sDisplayIcon = utils::GetAbsoluteUrlAppRoot().'images/'.$sLogo.'?t='.utils::GetCacheBusterTimestamp();
if (file_exists(MODULESROOT.'branding/'.$sBrandingLogo))
{
$sDisplayIcon = utils::GetAbsoluteUrlModulesRoot().'branding/'.$sBrandingLogo.'?t='.utils::GetCacheBusterTimestamp();
}
$aVars = array(
'sAppRootUrl' => utils::GetAbsoluteUrlAppRoot(),
'aPluginFormData' => $this->GetPluginFormData(),
'sItopVersion' => ITOP_VERSION,
'sVersionShort' => $sVersionShort,
'sIconUrl' => $sIconUrl,
'sDisplayIcon' => $sDisplayIcon,
);
return $aVars;
}
public function Render(NiceWebPage $oPage, $sTwigFile, $aVars = array())
{
$oTemplate = $this->GetTwig()->load($sTwigFile);
$oPage->add($oTemplate->renderBlock('body', $aVars));
$oPage->add_script($oTemplate->renderBlock('script', $aVars));
$oPage->add_ready_script($oTemplate->renderBlock('ready_script', $aVars));
$oPage->add_style($oTemplate->renderBlock('css', $aVars));
// Render CSS links
foreach ($this->aPluginFormData as $oFormData)
{
/** @var \LoginTwigContext $oFormData */
$aCSSFiles = $oFormData->GetCSSFiles();
foreach ($aCSSFiles as $sCSSFile)
{
$oPage->add_linked_stylesheet($sCSSFile);
}
$aJsFiles = $oFormData->GetJsFiles();
foreach ($aJsFiles as $sJsFile)
{
$oPage->add_linked_script($sJsFile);
}
}
}
/**
* @return mixed
*/
public function GetLoginPluginList()
{
return $this->aLoginPluginList;
}
/**
* @return array
*/
public function GetPluginFormData()
{
return $this->aPluginFormData;
}
/**
* @return array
*/
public function GetPostedVars()
{
return $this->aPostedVars;
}
/**
* @return \Twig_Environment
*/
public function GetTwig()
{
return $this->oTwig;
}
}

View File

@@ -1,93 +0,0 @@
<?php
/**
* Class LoginURL
*
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class LoginURL extends AbstractLoginFSMExtension
{
/**
* @var bool
*/
private $bErrorOccurred = false;
/**
* Return the list of supported login modes for this plugin
*
* @return array of supported login modes
*/
public function ListSupportedLoginModes()
{
return array('url');
}
protected function OnModeDetection(&$iErrorCode)
{
if (!isset($_SESSION['login_mode']) && !$this->bErrorOccurred)
{
$sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data');
$sAuthPwd = utils::ReadParam('auth_pwd', null, false, 'raw_data');
if (!empty($sAuthUser) && !empty($sAuthPwd))
{
$_SESSION['login_mode'] = 'url';
}
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnReadCredentials(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'url')
{
$_SESSION['login_temp_auth_user'] = utils::ReadParam('auth_user', '', false, 'raw_data');
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnCheckCredentials(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'url')
{
$sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data');
$sAuthPwd = utils::ReadParam('auth_pwd', null, false, 'raw_data');
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, $_SESSION['login_mode'], 'internal'))
{
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
return LoginWebPage::LOGIN_FSM_ERROR;
}
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnCredentialsOK(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'url')
{
$sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data');
LoginWebPage::OnLoginSuccess($sAuthUser, 'internal', $_SESSION['login_mode']);
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnError(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'url')
{
$this->bErrorOccurred = true;
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
protected function OnConnected(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'url')
{
$_SESSION['can_logoff'] = true;
return LoginWebPage::CheckLoggedUser($iErrorCode);
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,93 +0,0 @@
<?php
/**
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
//
// Maintenance message display functions
// Only included by approot.inc.php
//
/**
* Use a setup page to display the maintenance message
* @param $sTitle
* @param $sMessage
*/
function _MaintenanceSetupPageMessage($sTitle, $sMessage)
{
// Web Page
@include_once(APPROOT.'setup/setuppage.class.inc.php');
if (class_exists('SetupPage'))
{
$oP = new SetupPage($sTitle);
$oP->p("<h2 class=\"center\">$sMessage</h2>");
$oP->add_ready_script(
<<<JS
// Reload in 30s to check if maintenance is over
setTimeout(function(){ window.location.reload(); }, 30000);
JS
);
$oP->output();
}
else
{
_MaintenanceTextMessage($sMessage);
}
}
/**
* Use simple text to display the maintenance message
* @param $sMessage
*/
function _MaintenanceTextMessage($sMessage)
{
echo $sMessage;
}
/**
* Use a simple HTML to display the maintenance message
* @param $sMessage
*/
function _MaintenanceHtmlMessage($sMessage)
{
echo '<html><body><div>'.$sMessage.'</div></body></html>';
}
/**
* Use a simple JSON to display the maintenance message
*
* @param $sTitle
* @param $sMessage
*/
function _MaintenanceJsonMessage($sTitle, $sMessage)
{
@include_once(APPROOT."/application/ajaxwebpage.class.inc.php");
if (class_exists('ajax_page'))
{
$oP = new ajax_page($sTitle);
$oP->add_header('Access-Control-Allow-Origin: *');
$oP->SetContentType('application/json');
$oP->add('{"code":100, "message":"'.$sMessage.'"}');
$oP->Output();
}
else
{
_MaintenanceTextMessage($sMessage);
}
}

View File

@@ -1,20 +1,27 @@
<?php
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Copyright (C) 2013-2019 Combodo SARL
* Construction and display of the application's main menu
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* @copyright Copyright (C) 2010-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/application/utils.inc.php');
@@ -194,7 +201,7 @@ class ApplicationMenu
/**
* Entry point to display the whole menu into the web page, used by iTopWebPage
* @param \WebPage $oPage
* @param \iTopWebPage $oPage
* @param $aExtraParams
* @throws DictExceptionMissingString
*/
@@ -210,7 +217,7 @@ class ApplicationMenu
{
if (!self::CanDisplayMenu($aMenu)) { continue; }
$oMenuNode = self::GetMenuNode($aMenu['index']);
$oPage->AddToMenu('<h3 id="'.utils::GetSafeId('AccordionMenu_'.$oMenuNode->GetMenuID()).'" class="navigation-menu-group" data-menu-id="'.$oMenuNode->GetMenuId().'">'.$oMenuNode->GetTitle().'</h3>');
$oPage->AddToMenu('<h3 id="'.utils::GetSafeId('AccordionMenu_'.$oMenuNode->GetMenuID()).'">'.$oMenuNode->GetTitle().'</h3>');
$oPage->AddToMenu('<div>');
$oPage->AddToMenu('<ul>');
$aChildren = self::GetChildren($aMenu['index']);
@@ -263,7 +270,7 @@ EOF
/**
* Handles the display of the sub-menus (called recursively if necessary)
* @param \WebPage $oPage
* @param \iTopWebPage $oPage
* @param array $aMenus
* @param array $aExtraParams
* @param int $iActiveMenu
@@ -277,39 +284,22 @@ EOF
usort($aMenus, array('ApplicationMenu', 'CompareOnRank'));
foreach($aMenus as $aMenu)
{
if (!self::CanDisplayMenu($aMenu))
{
continue;
}
$index = $aMenu['index'];
$oMenu = self::GetMenuNode($index);
if ($oMenu->IsEnabled())
{
$aChildren = self::GetChildren($index);
$aCSSClasses = array('navigation-menu-item');
if (count($aChildren) > 0)
{
$aCSSClasses[] = 'submenu';
}
$sCSSClass = (count($aChildren) > 0) ? ' class="submenu"' : '';
$sHyperlink = $oMenu->GetHyperlink($aExtraParams);
$sItemHtml = '<li id="'.utils::GetSafeId('AccordionMenu_'.$oMenu->GetMenuID()).'" class="'.implode(' ', $aCSSClasses).'" data-menu-id="'.$oMenu->GetMenuID().'">';
if ($sHyperlink != '')
{
$sLinkTarget = '';
if ($oMenu->IsHyperLinkInNewWindow())
{
$sLinkTarget .= ' target="_blank"';
}
$sURL = '"'.$oMenu->GetHyperlink($aExtraParams).'"'.$sLinkTarget;
$sTitle = $oMenu->GetTitle();
$sItemHtml .= "<a href={$sURL}>{$sTitle}</a>";
$sTitle = utils::HtmlEntities($oMenu->GetTitle());
$oPage->AddToMenu('<li id="'.utils::GetSafeId('AccordionMenu_'.$oMenu->GetMenuID()).'" '.$sCSSClass.'><a href="'.$oMenu->GetHyperlink($aExtraParams).'">'.$sTitle.'</a></li>');
}
else
{
$sItemHtml .= $oMenu->GetTitle();
$oPage->AddToMenu('<li id="'.utils::GetSafeId('AccordionMenu_'.$oMenu->GetMenuID()).'" '.$sCSSClass.'>'.$oMenu->GetTitle().'</li>');
}
$sItemHtml .= '</li>';
$oPage->AddToMenu($sItemHtml);
if ($iActiveMenu == $index)
{
$bActive = true;
@@ -610,24 +600,13 @@ abstract class MenuNode
/**
* @param $aExtraParams
*
* @return string
* @throws \Exception
*/
public function GetHyperlink($aExtraParams)
{
$aExtraParams['c[menu]'] = $this->GetMenuId();
return $this->AddParams(utils::GetAbsoluteUrlAppRoot().'pages/UI.php', $aExtraParams);
}
/**
* @return bool true if the link should be opened in a new window
* @since 2.7.0 N°1283
*/
public function IsHyperLinkInNewWindow()
{
return false;
}
/**
* Add a limiting display condition for the same menu node. The conditions will be combined with a AND
@@ -927,7 +906,7 @@ class OQLMenuNode extends MenuNode
$oBlock->Display($oPage, 0);
}
$oPage->add("<p class=\"page-header\">$sIcon ".Dict::S($sTitle)."</p>");
$oPage->add("<p class=\"page-header\">$sIcon ".utils::HtmlEntities(Dict::S($sTitle))."</p>");
$aParams = array_merge(array('table_id' => $sUsageId), $aExtraParams);
$oBlock = new DisplayBlock($oSearch, 'list', false /* Asynchronous */, $aParams);
@@ -988,7 +967,7 @@ class SearchMenuNode extends MenuNode
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
ApplicationMenu::CheckMenuIdEnabled($this->GetMenuId());
$oPage->SetBreadCrumbEntry("menu-".$this->sMenuId, $this->GetTitle(), '', '', utils::GetAbsoluteUrlAppRoot().'images/breadcrumb-search.png');
$oPage->SetBreadCrumbEntry("menu-".$this->sMenuId, $this->GetTitle(), '', '', utils::GetAbsoluteUrlAppRoot().'images/search.png');
$oSearch = new DBObjectSearch($this->sClass);
$aParams = array_merge(array('table_id' => 'Menu_'.utils::GetSafeId($this->GetMenuId())), $aExtraParams);
@@ -1011,12 +990,8 @@ class WebPageMenuNode extends MenuNode
*/
protected $sHyperlink;
/** @var bool */
protected $bIsLinkInNewWindow;
/**
* Create a menu item that points to any web page (not only UI.php)
*
* @param string $sMenuId Unique identifier of the menu (used to identify the menu for bookmarking, and for getting the labels from the dictionary)
* @param string $sHyperlink URL to the page to load. Use relative URL if you want to keep the application portable !
* @param integer $iParentIndex ID of the parent menu
@@ -1025,17 +1000,12 @@ class WebPageMenuNode extends MenuNode
* @param integer $iActionCode Either UR_ACTION_READ, UR_ACTION_MODIFY, UR_ACTION_DELETE, UR_ACTION_BULKREAD, UR_ACTION_BULKMODIFY or UR_ACTION_BULKDELETE
* @param integer $iAllowedResults Expected "rights" for the action: either UR_ALLOWED_YES, UR_ALLOWED_NO, UR_ALLOWED_DEPENDS or a mix of them...
* @param string $sEnableStimulus
* @param bool $bIsLinkInNewWindow for the {@link WebPageMenuNode::IsHyperLinkInNewWindow} method
*/
public function __construct(
$sMenuId, $sHyperlink, $iParentIndex, $fRank = 0.0, $sEnableClass = null, $iActionCode = null,
$iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null, $bIsLinkInNewWindow = false
)
public function __construct($sMenuId, $sHyperlink, $iParentIndex, $fRank = 0.0, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
{
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
$this->sHyperlink = $sHyperlink;
$this->aReflectionProperties['url'] = $sHyperlink;
$this->bIsLinkInNewWindow = $bIsLinkInNewWindow;
}
/**
@@ -1048,11 +1018,6 @@ class WebPageMenuNode extends MenuNode
return $this->AddParams( $this->sHyperlink, $aExtraParams);
}
public function IsHyperLinkInNewWindow()
{
return $this->bIsLinkInNewWindow;
}
/**
* @param WebPage $oPage
* @param array $aExtraParams

View File

@@ -1,20 +1,27 @@
<?php
// Copyright (C) 2010-2016 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Copyright (C) 2013-2020 Combodo SARL
* Class NiceWebPage
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* @copyright Copyright (C) 2010-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT."/application/webpage.class.inc.php");
@@ -30,16 +37,17 @@ class NiceWebPage extends WebPage
{
parent::__construct($s_title, $bPrintable);
$this->m_aReadyScripts = array();
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.min.js');
$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.dev.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate-3.0.1.dev.js');
}
else
{
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate.prod.min.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate-3.0.1.prod.min.js');
}
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-ui-1.11.4.custom.min.js');
$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');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/hovertip.js');
// table sorting
@@ -67,8 +75,6 @@ class NiceWebPage extends WebPage
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_date_abstract.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_date.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/search/search_form_criteria_date_time.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/clipboard.min.js');
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/clipboardwidget.js');
$this->add_dict_entries('UI:Combo');
@@ -116,7 +122,7 @@ class NiceWebPage extends WebPage
$("table.listResults").tableHover(); // hover tables
EOF
);
$this->LoadTheme();
$this->add_saas("css/light-grey.scss");
$this->m_sRootUrl = $this->GetAbsoluteUrlAppRoot();
$sAbsURLAppRoot = addslashes($this->m_sRootUrl);
@@ -226,8 +232,7 @@ EOF
foreach($aChoices as $sKey => $sValue)
{
$sSelected = ($sKey == $sDefaultValue) ? " SELECTED" : "";
$this->add("<option style=\"width: ".$iWidthPx." px;\" value=\"".htmlspecialchars($sKey)."\"$sSelected>".htmlentities($sValue,
ENT_QUOTES, self::PAGES_CHARSET)."</option>");
$this->add("<option style=\"width: ".$iWidthPx." px;\" value=\"".htmlspecialchars($sKey)."\"$sSelected>".htmlentities($sValue, ENT_QUOTES, 'UTF-8')."</option>");
}
$this->add("</select>");
}
@@ -249,14 +254,6 @@ EOF
}
parent::output();
}
/**
* @throws \Exception
* @since 2.7.0
*/
protected function LoadTheme()
{
$sCssThemeUrl = ThemeHandler::GetDefaultThemeUrl();
$this->add_linked_stylesheet($sCssThemeUrl);
}
}
?>

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// 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.
@@ -15,15 +15,12 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
require_once(APPROOT.'/core/cmdbobject.class.inc.php');
require_once(APPROOT.'/application/utils.inc.php');
require_once(APPROOT.'/core/contexttag.class.inc.php');
/**
* File to include to initialize the datamodel in memory
*
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @copyright Copyright (C) 2010-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
@@ -35,16 +32,10 @@ register_shutdown_function(function()
$sReservedMemory = null;
if (!is_null($err = error_get_last()) && ($err['type'] == E_ERROR))
{
IssueLog::error($err['message']);
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";
}
elseif (strpos($err['message'], 'Maximum execution time') !== false)
{
$sLimit = ini_get('max_execution_time');
echo "<p>iTop: Maximum execution time of $sLimit exceeded, contact your administrator to increase 'max_execution_time' in php.ini</p>\n";
echo "<p>iTop: Allowed memory size of $sLimit exhausted, contact your administrator to increase memory_limit in php.ini</p>\n";
}
else
{
@@ -53,6 +44,9 @@ register_shutdown_function(function()
}
});
require_once(APPROOT.'/core/cmdbobject.class.inc.php');
require_once(APPROOT.'/application/utils.inc.php');
require_once(APPROOT.'/core/contexttag.class.inc.php');
session_name('itop-'.md5(APPROOT));
session_start();
$sSwitchEnv = utils::ReadParam('switch_env', null);
@@ -85,4 +79,4 @@ else
$_SESSION['itop_env'] = ITOP_DEFAULT_ENV;
}
$sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE;
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, $bAllowCache, false /* $bTraceSourceFiles */, $sEnv);
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, $bAllowCache, false /* $bTraceSourceFiles */, $sEnv);

View File

@@ -1,20 +1,27 @@
<?php
// Copyright (C) 2010-2017 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Copyright (C) 2013-2020 Combodo SARL
* Class DisplayTemplate
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/application/displayblock.class.inc.php');
@@ -184,7 +191,7 @@ class DisplayTemplate
break;
case 'itoptab':
$oPage->SetCurrentTab($aAttributes['name'], str_replace('_', ' ', $aAttributes['name']));
$oPage->SetCurrentTab(Dict::S(str_replace('_', ' ', $aAttributes['name'])));
$oTemplate = new DisplayTemplate($sContent);
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied
//$oPage->p('iTop Tab Content:<pre>'.htmlentities($sContent, ENT_QUOTES, 'UTF-8').'</pre>');

View File

@@ -1,117 +0,0 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
use ScssPhp\ScssPhp\Compiler;
/**
* Class ThemeHandler
*
* @author Stephen Abello <stephen.abello@combodo.com>
* @since 2.7.0
*/
class ThemeHandler
{
/**
* Return the absolute URL for the default theme CSS file
*
* @return string
* @throws \Exception
*/
public static function GetDefaultThemeUrl()
{
$sThemeId = MetaModel::GetConfig()->Get('backoffice_default_theme');
static::CompileTheme($sThemeId);
// Return absolute url to theme compiled css
return utils::GetAbsoluteUrlModulesRoot().'/branding/themes/'.$sThemeId.'/main.css';
}
/**
* Compile the $sThemeId theme
*
* @param string $sThemeId
* @param array|null $aThemeParameters Parameters (variables, imports, stylesheets) for the theme, if not passed, will be retrieved from compiled DM
* @param array|null $aImportsPaths Paths where imports can be found. Must end with '/'
* @param string|null $sWorkingPath Path of the folder used during compilation. Must end with a '/'
*
* @throws \CoreException
*/
public static function CompileTheme($sThemeId, $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null)
{
// Default working path
if($sWorkingPath === null)
{
$sWorkingPath = APPROOT.'env-'.utils::GetCurrentEnvironment().'/';
}
// Default import paths (env-*)
if($aImportsPaths === null)
{
$aImportsPaths = array(
APPROOT.'env-'.utils::GetCurrentEnvironment().'/',
);
}
// Note: We do NOT check that the folder exists!
$sThemeFolderPath = $sWorkingPath.'/branding/themes/'.$sThemeId.'/';
$sThemeCssPath = $sThemeFolderPath.'main.css';
// Save parameters if passed...
if(is_array($aThemeParameters))
{
file_put_contents($sThemeFolderPath.'/theme-parameters.json', json_encode($aThemeParameters));
}
// ... Otherwise, retrieve them from compiled DM
else
{
$aThemeParameters = json_decode(@file_get_contents($sThemeFolderPath.'theme-parameters.json'), true);
if ($aThemeParameters === null)
{
throw new CoreException('Could not load "'.$sThemeId.'" theme parameters from file, check that it has been compiled correctly');
}
}
$sTmpThemeScssContent = '';
$iStyleLastModified = 0;
clearstatcache();
// Loading files to import and stylesheet to compile, also getting most recent modification time on overall files
foreach ($aThemeParameters['imports'] as $sImport)
{
$sTmpThemeScssContent .= '@import "'.$sImport.'";'."\n";
$iImportLastModified = @filemtime($sWorkingPath.$sImport);
$iStyleLastModified = $iStyleLastModified < $iImportLastModified ? $iImportLastModified : $iStyleLastModified;
}
foreach ($aThemeParameters['stylesheets'] as $sStylesheet)
{
$sTmpThemeScssContent .= '@import "'.$sStylesheet.'";'."\n";
$iStylesheetLastModified = @filemtime($sWorkingPath.$sStylesheet);
$iStyleLastModified = $iStyleLastModified < $iStylesheetLastModified ? $iStylesheetLastModified : $iStyleLastModified;
}
// Checking if our compiled css is outdated
if (!file_exists($sThemeCssPath) || (is_writable($sThemeFolderPath) && (@filemtime($sThemeCssPath) < $iStyleLastModified)))
{
$sTmpThemeCssContent = utils::CompileCSSFromSASS($sTmpThemeScssContent, $aImportsPaths, $aThemeParameters['variables']);
file_put_contents($sThemeCssPath, $sTmpThemeCssContent);
}
}
}

View File

@@ -26,8 +26,6 @@
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class privUITransaction
{
/**
@@ -99,9 +97,10 @@ class privUITransaction
}
/**
* The original (and by default) mechanism for storing transaction information
* as an array in the $_SESSION variable
* The original mechanism for storing transaction information as an array in the $_SESSION variable
*
* Warning, since 2.6.0 the session is regenerated on each login (see PR #20) !
* Also, we saw some problems when using memcached as the PHP session implementation (see N°1835)
*/
class privUITransactionSession
{
@@ -194,9 +193,35 @@ class privUITransactionSession
*/
class privUITransactionFile
{
/** @var int Value to use when no user logged */
const UNAUTHENTICATED_USER_ID = -666;
/**
* @return int The new transaction identifier
* @return int current user id, or {@see self::UNAUTHENTICATED_USER_ID} if no user logged
*
* @since 2.6.5 2.7.6 3.0.0 N°4289 method creation
*/
private static function GetCurrentUserId()
{
$iCurrentUserId = UserRights::GetConnectedUserId();
if ('' === $iCurrentUserId) {
$iCurrentUserId = static::UNAUTHENTICATED_USER_ID;
}
return $iCurrentUserId;
}
/**
* Create a new transaction id, store it in the session and return its id
*
* @param void
*
* @return int The identifier of the new transaction
*
* @throws \SecurityException
* @throws \Exception
*
* @since 2.6.5 2.7.6 3.0.0 security hardening + throws SecurityException if no user logged
*/
public static function GetNewTransactionId()
{
@@ -206,84 +231,102 @@ class privUITransactionFile
{
throw new Exception('The directory "'.APPROOT.'data" must be writable to the application.');
}
// condition avoids race condition N°2345
// See https://github.com/kalessil/phpinspectionsea/blob/master/docs/probable-bugs.md#mkdir-race-condition
if (!mkdir($concurrentDirectory = APPROOT.'data/transactions') && !is_dir($concurrentDirectory))
/** @noinspection MkdirRaceConditionInspection */
if (!@mkdir(APPROOT.'data/transactions'))
{
throw new Exception('Failed to create the directory "'.APPROOT.'data/transactions". Ajust the rights on the parent directory or let an administrator create the transactions directory and give the web sever enough rights to write into it.');
}
}
if (!is_writable(APPROOT.'data/transactions'))
{
throw new Exception('The directory "'.APPROOT.'data/transactions" must be writable to the application.');
}
self::CleanupOldTransactions();
$id = basename(tempnam(APPROOT.'data/transactions', static::GetUserPrefix()));
self::Info('GetNewTransactionId: Created transaction: '.$id);
return (string)$id;
$iCurrentUserId = static::GetCurrentUserId();
self::CleanupOldTransactions();
$sTransactionIdFullPath = tempnam(APPROOT.'data/transactions', static::GetUserPrefix());
file_put_contents($sTransactionIdFullPath, $iCurrentUserId, LOCK_EX);
$sTransactionIdFileName = basename($sTransactionIdFullPath);
self::Info('GetNewTransactionId: Created transaction: '.$sTransactionIdFileName);
return $sTransactionIdFileName;
}
/**
* Check whether a transaction is valid or not and (optionally) remove the valid transaction from
* the session so that another call to IsTransactionValid for the same transaction id
* will return false
*
* @param int $id Identifier of the transaction, as returned by GetNewTransactionId
* @param bool $bRemoveTransaction True if the transaction must be removed
*
* @return bool True if the transaction is valid, false otherwise
*
* @since 2.6.5 2.7.6 3.0.0 N°4289 security hardening
*/
public static function IsTransactionValid($id, $bRemoveTransaction = true)
{
$sFilepath = APPROOT.'data/transactions/'.$id;
// Constraint the transaction file within APPROOT.'data/transactions'
$sTransactionDir = realpath(APPROOT.'data/transactions');
$sFilepath = utils::RealPath($sTransactionDir.'/'.$id, $sTransactionDir);
if (($sFilepath === false) || (strlen($sTransactionDir) == strlen($sFilepath)))
{
return false;
}
clearstatcache(true, $sFilepath);
$bResult = file_exists($sFilepath);
if ($bResult)
if (false === $bResult) {
self::Info("IsTransactionValid: Transaction '$id' not found. Pending transactions:\n".implode("\n", self::GetPendingTransactions()));
return false;
}
$iCurrentUserId = static::GetCurrentUserId();
$sTransactionIdUserId = file_get_contents($sFilepath);
if ($iCurrentUserId != $sTransactionIdUserId) {
self::Info("IsTransactionValid: Transaction '$id' not existing for current user. Pending transactions:\n".implode("\n", self::GetPendingTransactions()));
return false;
}
if ($bRemoveTransaction)
{
if ($bRemoveTransaction)
$bResult = @unlink($sFilepath);
if (!$bResult)
{
$bResult = @unlink($sFilepath);
if (!$bResult)
{
self::Error('IsTransactionValid: FAILED to remove transaction '.$id);
}
else
{
self::Info('IsTransactionValid: OK. Removed transaction: '.$id);
}
self::Error('IsTransactionValid: FAILED to remove transaction '.$id);
}
else
{
self::Info('IsTransactionValid: OK. Removed transaction: '.$id);
}
}
else
{
self::Info("IsTransactionValid: Transaction '$id' not found. Pending transactions for this user:\n".implode("\n", self::GetPendingTransactions()));
}
return $bResult;
}
/**
* Removes the transaction specified by its id
* @param int $id The Identifier (as returned by GetNewTransactionId) of the transaction to be removed.
* @return void
* @return bool true if the token can be removed
*
* @since 2.6.5 2.7.6 3.0.0 N°4289 security hardening
*/
public static function RemoveTransaction($id)
{
$bSuccess = true;
$sFilepath = APPROOT.'data/transactions/'.$id;
clearstatcache(true, $sFilepath);
if(!file_exists($sFilepath))
{
$bSuccess = false;
self::Error("RemoveTransaction: Transaction '$id' not found. Pending transactions for this user:\n".implode("\n", self::GetPendingTransactions()));
/** @noinspection PhpRedundantOptionalArgumentInspection */
$bResult = static::IsTransactionValid($id, true);
if (false === $bResult) {
self::Error("RemoveTransaction: Transaction '$id' is invalid. Pending transactions:\n"
.implode("\n", self::GetPendingTransactions()));
return false;
}
$bSuccess = @unlink($sFilepath);
if (!$bSuccess)
{
self::Error('RemoveTransaction: FAILED to remove transaction '.$id);
}
else
{
self::Info('RemoveTransaction: OK '.$id);
}
return $bSuccess;
return true;
}
/**
@@ -348,22 +391,35 @@ class privUITransactionFile
{
self::Write('Error | '.$sText);
}
protected static function IsLogEnabled() {
$oConfig = MetaModel::GetConfig();
if (is_null($oConfig)) {
return false;
}
$bLogTransactions = $oConfig->Get('log_transactions');
if (true === $bLogTransactions) {
return true;
}
return false;
}
protected static function Write($sText)
{
$bLogEnabled = MetaModel::GetConfig()->Get('log_transactions');
if ($bLogEnabled)
{
if (false === static::IsLogEnabled()) {
return;
}
$hLogFile = @fopen(APPROOT.'log/transactions.log', 'a');
if ($hLogFile !== false)
{
if ($hLogFile !== false) {
flock($hLogFile, LOCK_EX);
$sDate = date('Y-m-d H:i:s');
fwrite($hLogFile, "$sDate | $sText\n");
fflush($hLogFile);
flock($hLogFile, LOCK_UN);
fclose($hLogFile);
}
}
}
}

View File

@@ -1,140 +0,0 @@
<?php
namespace Combodo\iTop;
use AttributeDateTime;
use Dict;
use Exception;
use MetaModel;
use Twig_Environment;
use Twig_SimpleFilter;
use Twig_SimpleFunction;
use utils;
class TwigExtension
{
/**
* Registers Twig extensions such as filters or functions.
* It allows us to access some stuff directly in twig.
*
* @param \Twig_Environment $oTwigEnv
*/
public static function RegisterTwigExtensions(Twig_Environment &$oTwigEnv)
{
// Filter to translate a string via the Dict::S function
// Usage in twig: {{ 'String:ToTranslate'|dict_s }}
$oTwigEnv->addFilter(new Twig_SimpleFilter('dict_s',
function ($sStringCode, $sDefault = null, $bUserLanguageOnly = false) {
return Dict::S($sStringCode, $sDefault, $bUserLanguageOnly);
})
);
// Filter to format a string via the Dict::Format function
// Usage in twig: {{ 'String:ToTranslate'|dict_format() }}
$oTwigEnv->addFilter(new Twig_SimpleFilter('dict_format',
function ($sStringCode, $sParam01 = null, $sParam02 = null, $sParam03 = null, $sParam04 = null) {
return Dict::Format($sStringCode, $sParam01, $sParam02, $sParam03, $sParam04);
})
);
// Filter to format output
// example a DateTime is converted to user format
// Usage in twig: {{ 'String:ToFormat'|output_format }}
$oTwigEnv->addFilter(new Twig_SimpleFilter('date_format',
function ($sDate) {
try
{
if (preg_match('@^\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d$@', trim($sDate)))
{
return AttributeDateTime::GetFormat()->Format($sDate);
}
}
catch (Exception $e)
{
}
return $sDate;
})
);
// Filter to format output
// example a DateTime is converted to user format
// Usage in twig: {{ 'String:ToFormat'|output_format }}
$oTwigEnv->addFilter(new Twig_SimpleFilter('size_format',
function ($sSize) {
return utils::BytesToFriendlyFormat($sSize);
})
);
// Filter to enable base64 encode/decode
// Usage in twig: {{ 'String to encode'|base64_encode }}
$oTwigEnv->addFilter(new Twig_SimpleFilter('base64_encode', 'base64_encode'));
$oTwigEnv->addFilter(new Twig_SimpleFilter('base64_decode', 'base64_decode'));
// Filter to enable json decode (encode already exists)
// Usage in twig: {{ aSomeArray|json_decode }}
$oTwigEnv->addFilter(new Twig_SimpleFilter('json_decode', function ($sJsonString, $bAssoc = false) {
return json_decode($sJsonString, $bAssoc);
})
);
// Filter to add itopversion to an url
$oTwigEnv->addFilter(new Twig_SimpleFilter('add_itop_version', function ($sUrl) {
if (strpos($sUrl, '?') === false)
{
$sUrl = $sUrl."?itopversion=".ITOP_VERSION;
}
else
{
$sUrl = $sUrl."&itopversion=".ITOP_VERSION;
}
return $sUrl;
}));
// Filter to add a module's version to an url
$oTwigEnv->addFilter(new Twig_SimpleFilter('add_module_version', function ($sUrl, $sModuleName) {
$sModuleVersion = utils::GetCompiledModuleVersion($sModuleName);
if (strpos($sUrl, '?') === false)
{
$sUrl = $sUrl."?moduleversion=".$sModuleVersion;
}
else
{
$sUrl = $sUrl."&moduleversion=".$sModuleVersion;
}
return $sUrl;
}));
// Function to check our current environment
// Usage in twig: {% if is_development_environment() %}
$oTwigEnv->addFunction(new Twig_SimpleFunction('is_development_environment', function()
{
return utils::IsDevelopmentEnvironment();
}));
// Function to get configuration parameter
// Usage in twig: {{ get_config_parameter('foo') }}
$oTwigEnv->addFunction(new Twig_SimpleFunction('get_config_parameter', function($sParamName)
{
$oConfig = MetaModel::GetConfig();
return $oConfig->Get($sParamName);
}));
// Function to get the URL of a static page in a module
// Usage in twig: {{ get_static_page_module_url('itop-my-module', 'path-to-my-page') }}
$oTwigEnv->addFunction(new Twig_SimpleFunction('get_static_page_module_url', function($sModuleName, $sPage)
{
return utils::GetAbsoluteUrlModulesRoot().$sModuleName.'/'.$sPage;
}));
// Function to get the URL of a php page in a module
// Usage in twig: {{ get_page_module_url('itop-my-module', 'path-to-my-my-page.php') }}
$oTwigEnv->addFunction(new Twig_SimpleFunction('get_page_module_url', function($sModuleName, $sPage)
{
return utils::GetAbsoluteUrlModulePage($sModuleName, $sPage);
}));
}
}

View File

@@ -1,28 +1,23 @@
<?php
/**
* Copyright (C) 2013-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
require_once(APPROOT.'/application/webpage.class.inc.php');
require_once(APPROOT.'/application/displayblock.class.inc.php');
// Copyright (C) 2010-2017 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Class UIExtKeyWidget
* UI widget for displaying and editing external keys when
* UI wdiget for displaying and editing external keys when
* A simple drop-down list is not enough...
*
* The layout is the following
@@ -59,7 +54,13 @@ require_once(APPROOT.'/application/displayblock.class.inc.php');
* | | +--------+ +-----+ | |
* | +--------------------------------------------+ |
* +------------------------------------------------+
* @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/application/webpage.class.inc.php');
require_once(APPROOT.'/application/displayblock.class.inc.php');
class UIExtKeyWidget
{
const ENUM_OUTPUT_FORMAT_CSV = 'csv';
@@ -273,7 +274,7 @@ EOF
// the input for the auto-complete
$sHTMLValue .= "<input class=\"field_autocomplete\" type=\"text\" id=\"label_$this->iId\" value=\"$sDisplayValue\"/>";
$sHTMLValue .= "<span class=\"field_input_btn\"><div class=\"mini_button\" id=\"mini_search_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.Search();\"><i class=\"fas fa-search\"></i></div></span>";
$sHTMLValue .= "<span class=\"field_input_btn\"><img id=\"mini_search_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_search.gif?t=".utils::GetCacheBusterTimestamp()."\" onClick=\"oACWidget_{$this->iId}.Search();\"/></span>";
// another hidden input to store & pass the object's Id
$sHTMLValue .= "<input type=\"hidden\" id=\"$this->iId\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" value=\"".htmlentities($value, ENT_QUOTES, 'UTF-8')."\" />\n";
@@ -297,7 +298,7 @@ EOF
}
if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false)
{
$sHTMLValue .= "<span class=\"field_input_btn\"><div class=\"mini_button\" id=\"mini_tree_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\"><i class=\"fas fa-sitemap\"></i></div></span>";
$sHTMLValue .= "<span class=\"field_input_btn\"><img id=\"mini_tree_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_tree.gif?t=".utils::GetCacheBusterTimestamp()."\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\"/></span>";
$oPage->add_ready_script(
<<<EOF
if ($('#ac_tree_{$this->iId}').length == 0)
@@ -311,7 +312,7 @@ EOF
{
$sCallbackName = (MetaModel::IsAbstract($this->sTargetClass)) ? 'SelectObjectClass' : 'CreateObject';
$sHTMLValue .= "<span class=\"field_input_btn\"><div class=\"mini_button\" id=\"mini_add_{$this->iId}\" onClick=\"oACWidget_{$this->iId}.{$sCallbackName}();\"><i class=\"fas fa-plus\"></i></div></span>";
$sHTMLValue .= "<span class=\"field_input_btn\"><img id=\"mini_add_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_add.gif?t=".utils::GetCacheBusterTimestamp()."\" onClick=\"oACWidget_{$this->iId}.{$sCallbackName}();\"/></span>";
$oPage->add_ready_script(
<<<EOF
if ($('#ajax_{$this->iId}').length == 0)
@@ -372,10 +373,10 @@ EOF
$sHTML .= "</form>\n";
$sHTML .= '</div></div>';
$sDialogTitle = addslashes($sTitle);
$sDialogTitleSanitized = addslashes(utils::HtmlToText($sTitle));
$oPage->add_ready_script(
<<<EOF
$('#ac_dlg_{$this->iId}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, title: '$sDialogTitle', resizeStop: oACWidget_{$this->iId}.UpdateSizes, close: oACWidget_{$this->iId}.OnClose });
$('#ac_dlg_{$this->iId}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, title: '$sDialogTitleSanitized', resizeStop: oACWidget_{$this->iId}.UpdateSizes, close: oACWidget_{$this->iId}.OnClose });
$('#fs_{$this->iId}').bind('submit.uiAutocomplete', oACWidget_{$this->iId}.DoSearchObjects);
$('#dc_{$this->iId}').resize(oACWidget_{$this->iId}.UpdateSizes);
EOF
@@ -577,21 +578,8 @@ EOF
$oNewObj->UpdateObjectFromArg('default');
$sDialogTitle = '';
$sClassLabel = MetaModel::GetName($this->sTargetClass);
$sClassIcon = MetaModel::GetClassIcon($this->sTargetClass);
$sObjClass = get_class($oNewObj);
$sObjKey = $oNewObj->GetKey();
$sHeaderTitle = Dict::Format('UI:CreationTitle_Class', $sClassLabel);
$oPage->add(<<<HTML
<div id="ac_create_{$this->iId}">
<!-- Beginning of object-details -->
<div class="object-details" data-object-class="$sObjClass" data-object-id="$sObjKey" data-object-mode="create">
<!-- Beginning of wizContainer -->
<div class="wizContainer" style="vertical-align:top;">
<div id="dcr_{$this->iId}">
<h1>$sClassIcon&nbsp;$sHeaderTitle</h1>
HTML
);
$oPage->add('<div id="ac_create_'.$this->iId.'"><div class="wizContainer" style="vertical-align:top;"><div id="dcr_'.$this->iId.'">');
$oPage->add("<h1>".MetaModel::GetClassIcon($this->sTargetClass)."&nbsp;".Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sTargetClass))."</h1>\n");
$aFieldsFlags = array();
$aFieldsComments = array();
foreach(MetaModel::ListAttributeDefs($this->sTargetClass) as $sAttCode => $oAttDef)
@@ -603,13 +591,7 @@ HTML
}
}
cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, $oNewObj, array(), array('formPrefix' => $this->iId, 'noRelations' => true, 'fieldsFlags' => $aFieldsFlags, 'fieldsComments' => $aFieldsComments));
$oPage->add(<<<HTML
</div>
</div><!-- End of wizContainer -->
</div><!-- End of object-details -->
</div>
HTML
);
$oPage->add('</div></div></div>');
// $oPage->add_ready_script("\$('#ac_create_$this->iId').dialog({ width: $(window).width()*0.8, height: 'auto', autoOpen: false, modal: true, title: '$sDialogTitle'});\n");
$oPage->add_ready_script("\$('#ac_create_$this->iId').dialog({ width: 'auto', height: 'auto', maxHeight: $(window).height() - 50, autoOpen: false, modal: true, title: '$sDialogTitle'});\n");
$oPage->add_ready_script("$('#dcr_{$this->iId} form').removeAttr('onsubmit');");

View File

@@ -74,7 +74,7 @@ class UIHTMLEditorWidget
$sLanguage = strtolower(trim(UserRights::GetUserLanguage()));
$aConfig['language'] = $sLanguage;
$aConfig['contentsLanguage'] = $sLanguage;
$aConfig['extraPlugins'] = 'disabler,codesnippet';
$aConfig['extraPlugins'] = 'disabler';
$sWidthSpec = addslashes(trim($this->m_oAttDef->GetWidth()));
if ($sWidthSpec != '')
{

View File

@@ -346,7 +346,7 @@ EOF
* @throws \CoreException
* @throws \DictExceptionMissingString
*/
public function Display(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj)
public function Display(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj)
{
$sHtmlValue = '';
$sHtmlValue .= "<div id=\"linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix}\">\n";

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -273,6 +273,10 @@ class WizardHelper
static public function FromJSON($sJSON)
{
$oWizHelper = new WizardHelper();
if (get_magic_quotes_gpc())
{
$sJSON = stripslashes($sJSON);
}
$aData = json_decode($sJSON, true); // true means hash array instead of object
$oWizHelper->m_aData = $aData;
return $oWizHelper;

View File

@@ -42,10 +42,13 @@ class XMLPage extends WebPage
parent::__construct($s_title);
$this->m_bPassThrough = $bPassThrough;
$this->m_bHeaderSent = false;
$this->add_header("Content-type: text/xml; charset=".self::PAGES_CHARSET);
$this->add_header("Cache-control: no-cache");
$this->add_header("Content-type: text/xml; charset=utf-8");
$this->add_header('Cache-control: no-cache, no-store, must-revalidate');
$this->add_header('Pragma: no-cache');
$this->add_header('Expires: 0');
$this->add_header('X-Frame-Options: deny');
$this->add_header("Content-location: export.xml");
}
}
public function output()
{
@@ -54,8 +57,7 @@ class XMLPage extends WebPage
// Get the unexpected output but do nothing with it
$sTrash = $this->ob_get_clean_safe();
$sCharset = self::PAGES_CHARSET;
$this->s_content = "<?xml version=\"1.0\" encoding=\"$sCharset\"?".">\n".trim($this->s_content);
$this->s_content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n".trim($this->s_content);
$this->add_header("Content-Length: ".strlen($this->s_content));
foreach($this->a_headers as $s_header)
{
@@ -88,8 +90,7 @@ class XMLPage extends WebPage
{
header($s_header);
}
$sCharset = self::PAGES_CHARSET;
echo "<?xml version=\"1.0\" encoding=\"$sCharset\"?".">\n";
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n";
echo trim($s_captured_output);
echo trim($this->s_content);
echo $sText;

View File

@@ -2,5 +2,14 @@
define('APPROOT', dirname(__FILE__).'/');
define('APPCONF', APPROOT.'conf/');
define('ITOP_DEFAULT_ENV', 'production');
require_once APPROOT.'bootstrap.inc.php';
if (function_exists('microtime'))
{
$fItopStarted = microtime(true);
}
else
{
$fItopStarted = 1000 * time();
}
?>

View File

@@ -1,93 +0,0 @@
<?php
/**
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
define('ITOP_DEFAULT_ENV', 'production');
define('MAINTENANCE_MODE_FILE', APPROOT.'data/.maintenance');
define('READONLY_MODE_FILE', APPROOT.'data/.readonly');
if (function_exists('microtime'))
{
$fItopStarted = microtime(true);
}
else
{
$fItopStarted = 1000 * time();
}
if (! isset($GLOBALS['bBypassAutoload']) || $GLOBALS['bBypassAutoload'] == false)
{
require_once APPROOT.'/lib/autoload.php';
}
//
// Maintenance mode
//
// Use 'maintenance' parameter to bypass maintenance mode
if (!isset($bBypassMaintenance))
{
$bBypassMaintenance = isset($_REQUEST['maintenance']) ? boolval($_REQUEST['maintenance']) : false;
}
if (file_exists(MAINTENANCE_MODE_FILE) && !$bBypassMaintenance)
{
$sTitle = 'Maintenance';
$sMessage = 'This application is currently under maintenance.';
http_response_code(503);
// Display message depending on the request
include(APPROOT.'application/maintenancemsg.php');
$sSAPIName = strtoupper(trim(php_sapi_name()));
switch (true)
{
case isset($_SERVER['REQUEST_URI']) && EndsWith($_SERVER['REQUEST_URI'], '/pages/ajax.searchform.php'):
_MaintenanceHtmlMessage($sMessage);
break;
case $sSAPIName == 'CLI':
case array_key_exists('HTTP_X_COMBODO_AJAX', $_SERVER):
case isset($_SERVER['REQUEST_URI']) && (strpos($_SERVER['REQUEST_URI'], '/webservices/soapserver.php') !== false):
case isset($_SERVER['REQUEST_URI']) && (strpos($_SERVER['REQUEST_URI'], '/webservices/export-v2.php') !== false):
_MaintenanceTextMessage($sMessage);
break;
case isset($_SERVER['REQUEST_URI']) && (strpos($_SERVER['REQUEST_URI'], '/webservices/rest.php') !== false):
case isset($_SERVER['CONTENT_TYPE']) && ($_SERVER['CONTENT_TYPE'] == 'application/json'):
_MaintenanceJsonMessage($sTitle, $sMessage);
break;
default:
_MaintenanceSetupPageMessage($sTitle, $sMessage);
break;
}
exit();
}
/**
* helper to test if a string ends with another
* @param $haystack
* @param $needle
*
* @return bool
*/
function EndsWith($haystack, $needle) {
return substr_compare($haystack, $needle, -strlen($needle)) === 0;
}

View File

@@ -1,31 +1,13 @@
{
"type": "project",
"license": "AGPLv3",
"require": {
"php": ">=5.6.0",
"ext-ctype": "*",
"ext-dom": "*",
"ext-gd": "*",
"ext-iconv": "*",
"ext-json": "*",
"ext-mysqli": "*",
"ext-soap": "*",
"combodo/tcpdf": "6.3.2",
"nikic/php-parser": "^3.1",
"pear/archive_tar": "1.4.9",
"pelago/emogrifier": "2.1.0",
"scssphp/scssphp": "1.0.6",
"swiftmailer/swiftmailer": "5.4.12",
"symfony/console": "3.4.*",
"symfony/dotenv": "3.4.*",
"symfony/framework-bundle": "3.4.*",
"symfony/polyfill-php70": "1.*",
"symfony/twig-bundle": "3.4.*",
"symfony/yaml": "3.4.*"
},
"require-dev": {
"symfony/stopwatch": "3.4.*",
"symfony/web-profiler-bundle": "3.4.*"
"ext-json": "*",
"ext-zip": "*",
"ext-mysqli": "*",
"ext-dom": "*",
"ext-iconv": "*",
"ext-gd": "*"
},
"suggest": {
"ext-libsodium": "Required to use the AttributeEncryptedString.",
@@ -38,41 +20,6 @@
"config": {
"platform": {
"php": "5.6.0"
},
"vendor-dir": "lib",
"preferred-install": {
"*": "dist"
},
"sort-packages": true,
"classmap-authoritative": true
},
"autoload": {
"classmap": [
"core",
"application",
"sources/application"
],
"exclude-from-classmap": [
"core/dbobjectsearch.class.php",
"core/legacy/dbobjectsearchlegacy.class.php",
"core/querybuildercontext.class.inc.php",
"core/legacy/querybuildercontextlegacy.class.inc.php",
"core/querybuilderexpressions.class.inc.php",
"core/legacy/querybuilderexpressionslegacy.class.inc.php",
"application/loginform.class.inc.php",
"application/loginbasic.class.inc.php",
"application/logindefault.class.inc.php",
"application/loginexternal.class.inc.php",
"application/loginurl.class.inc.php"
]
},
"conflict": {
"symfony/symfony": "*"
},
"extra": {
"symfony": {
"allow-contrib": false,
"require": "3.4.*"
}
}
}
}

3823
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +0,0 @@
To regenerate the autoload, run:
composer dump-autoload -a

View File

@@ -1,2 +0,0 @@
<?php
echo 'Access denied';

View File

@@ -1,8 +1,13 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<authorization>
<deny users="*" /> <!-- Denies all users -->
</authorization>
</system.web>
<system.webServer>
<security>
<requestFiltering>
<fileExtensions applyToWebDAV="false" allowUnlisted="false"></fileExtensions>
</requestFiltering>
<authorization>
<deny users="*" /> <!-- Denies all users -->
</authorization>
</security>
</system.webServer>
</configuration>

105
contributing.md Normal file
View File

@@ -0,0 +1,105 @@
# 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/).

View File

@@ -457,7 +457,7 @@ class Str
public static function gpc2pure($gpc)
{
if (ini_get('magic_quotes_sybase')) $pure = str_replace("''", "'", $gpc);
else $pure = $gpc;
else $pure = get_magic_quotes_gpc() ? stripslashes($gpc) : $gpc;
return $pure;
}
public static function html2pure($html)

View File

@@ -314,42 +314,54 @@ class ActionEmail extends ActionNotification
{
$this->m_iRecipients = 0;
$this->m_aMailErrors = array();
$bRes = false; // until we do succeed in sending the email
// Determine recicipients
//
$sTo = $this->FindRecipients('to', $aContextArgs);
$sCC = $this->FindRecipients('cc', $aContextArgs);
$sBCC = $this->FindRecipients('bcc', $aContextArgs);
$sFrom = MetaModel::ApplyParams($this->Get('from'), $aContextArgs);
$sReplyTo = MetaModel::ApplyParams($this->Get('reply_to'), $aContextArgs);
$sSubject = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs);
$sBody = MetaModel::ApplyParams($this->Get('body'), $aContextArgs);
$oObj = $aContextArgs['this->object()'];
$sMessageId = sprintf('iTop_%s_%d_%f@%s.openitop.org', get_class($oObj), $oObj->GetKey(), microtime(true /* get as float*/), MetaModel::GetEnvironmentId());
$sMessageId = sprintf('iTop_%s_%d_%f@%s.openitop.org', get_class($oObj), $oObj->GetKey(), microtime(true /* get as float*/),
MetaModel::GetEnvironmentId());
$sReference = '<'.$sMessageId.'>';
}
catch(Exception $e)
{
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
throw $e;
}
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
if (!is_null($oLog))
{
catch (Exception $e) {
/** @noinspection PhpUnhandledExceptionInspection */
throw $e;
}
finally {
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
}
if (!is_null($oLog)) {
// Note: we have to secure this because those values are calculated
// inside the try statement, and we would like to keep track of as
// many data as we could while some variables may still be undefined
if (isset($sTo)) $oLog->Set('to', $sTo);
if (isset($sCC)) $oLog->Set('cc', $sCC);
if (isset($sBCC)) $oLog->Set('bcc', $sBCC);
if (isset($sFrom)) $oLog->Set('from', $sFrom);
if (isset($sSubject)) $oLog->Set('subject', $sSubject);
if (isset($sBody)) $oLog->Set('body', $sBody);
if (isset($sTo)) {
$oLog->Set('to', $sTo);
}
if (isset($sCC)) {
$oLog->Set('cc', $sCC);
}
if (isset($sBCC)) {
$oLog->Set('bcc', $sBCC);
}
if (isset($sFrom)) {
$oLog->Set('from', $sFrom);
}
if (isset($sSubject)) {
$oLog->Set('subject', $sSubject);
}
if (isset($sBody)) {
$oLog->Set('body', $sBody);
}
}
$sStyles = file_get_contents(APPROOT.'css/email.css');
$sStyles .= MetaModel::GetConfig()->Get('email_css');
@@ -439,4 +451,3 @@ class ActionEmail extends ActionNotification
}
}
}
?>

View File

@@ -166,14 +166,7 @@ class apcFile
}
else
{
if (is_file($sCache))
{
if (!@unlink($sCache))
{
return false;
}
}
else
if (!@unlink($sCache))
{
return false;
}
@@ -216,14 +209,8 @@ class apcFile
return false;
}
if (is_file(self::GetCacheFileName($sKey)))
{
@unlink(self::GetCacheFileName($sKey));
}
if (is_file(self::GetCacheFileName('-'.$sKey)))
{
@unlink(self::GetCacheFileName('-'.$sKey));
}
@unlink(self::GetCacheFileName($sKey));
@unlink(self::GetCacheFileName('-'.$sKey));
if ($iTTL > 0)
{
// hint for ttl management
@@ -325,10 +312,6 @@ class apcFile
*/
static protected function ReadCacheLocked($sFilename)
{
if (!is_file($sFilename))
{
return false;
}
$file = @fopen($sFilename, 'r');
if ($file === false)
{

335
core/archive.class.inc.php Normal file
View File

@@ -0,0 +1,335 @@
<?php
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* Utility to import/export the DB from/to a ZIP file
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* iTopArchive a class to manipulate (read/write) iTop archives with their catalog
* Each iTop archive is a zip file that contains (at the root of the archive)
* a file called catalog.xml holding the description of the archive
*/
class iTopArchive
{
const read = 0;
const create = ZipArchive::CREATE;
protected $m_sZipPath;
protected $m_oZip;
protected $m_sVersion;
protected $m_sTitle;
protected $m_sDescription;
protected $m_aPackages;
protected $m_aErrorMessages;
/**
* Construct an iTopArchive object
* @param $sArchivePath string The full path the archive file
* @param $iMode integrer Either iTopArchive::read for reading an existing archive or iTopArchive::create for creating a new one. Updating is not supported (yet)
*/
public function __construct($sArchivePath, $iMode = iTopArchive::read)
{
$this->m_sZipPath = $sArchivePath;
$this->m_oZip = new ZipArchive();
$this->m_oZip->open($this->m_sZipPath, $iMode);
$this->m_aErrorMessages = array();
$this->m_sVersion = '1.0';
$this->m_sTitle = '';
$this->m_sDescription = '';
$this->m_aPackages = array();
}
public function SetTitle($sTitle)
{
$this->m_sTitle = $sTitle;
}
public function SetDescription($sDescription)
{
$this->m_sDescription = $sDescription;
}
public function GetTitle()
{
return $this->m_sTitle;
}
public function GetDescription()
{
return $this->m_sDescription;
}
public function GetPackages()
{
return $this->m_aPackages;
}
public function __destruct()
{
$this->m_oZip->close();
}
/**
* Get the error message explaining the latest error encountered
* @return array All the error messages encountered during the validation
*/
public function GetErrors()
{
return $this->m_aErrorMessages;
}
/**
* Read the catalog from the archive (zip) file
* @param sPath string Path the the zip file
* @return boolean True in case of success, false otherwise
*/
public function ReadCatalog()
{
if ($this->IsValid())
{
$sXmlCatalog = $this->m_oZip->getFromName('catalog.xml');
$oParser = xml_parser_create();
xml_parse_into_struct($oParser, $sXmlCatalog, $aValues, $aIndexes);
xml_parser_free($oParser);
$iIndex = $aIndexes['ARCHIVE'][0];
$this->m_sVersion = $aValues[$iIndex]['attributes']['VERSION'];
$iIndex = $aIndexes['TITLE'][0];
$this->m_sTitle = $aValues[$iIndex]['value'];
$iIndex = $aIndexes['DESCRIPTION'][0];
if (array_key_exists('value', $aValues[$iIndex]))
{
// #@# implement a get_array_value(array, key, default) ?
$this->m_sDescription = $aValues[$iIndex]['value'];
}
foreach($aIndexes['PACKAGE'] as $iIndex)
{
$this->m_aPackages[$aValues[$iIndex]['attributes']['HREF']] = array( 'type' => $aValues[$iIndex]['attributes']['TYPE'], 'title'=> $aValues[$iIndex]['attributes']['TITLE'], 'description' => $aValues[$iIndex]['value']);
}
//echo "Archive path: {$this->m_sZipPath}<br/>\n";
//echo "Archive format version: {$this->m_sVersion}<br/>\n";
//echo "Title: {$this->m_sTitle}<br/>\n";
//echo "Description: {$this->m_sDescription}<br/>\n";
//foreach($this->m_aPackages as $aFile)
//{
// echo "{$aFile['title']} ({$aFile['type']}): {$aFile['description']}<br/>\n";
//}
}
return true;
}
public function WriteCatalog()
{
$sXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?".">\n"; // split the XML closing tag that disturbs PSPad's syntax coloring
$sXml .= "<archive version=\"1.0\">\n";
$sXml .= "<title>{$this->m_sTitle}</title>\n";
$sXml .= "<description>{$this->m_sDescription}</description>\n";
foreach($this->m_aPackages as $sFileName => $aFile)
{
$sXml .= "<package title=\"{$aFile['title']}\" type=\"{$aFile['type']}\" href=\"$sFileName\">{$aFile['description']}</package>\n";
}
$sXml .= "</archive>";
$this->m_oZip->addFromString('catalog.xml', $sXml);
}
/**
* Add a package to the archive
* @param string $sExternalFilePath The path to the file to be added to the archive as a package (directories are not yet implemented)
* @param string $sFilePath The name of the file inside the archive
* @param string $sTitle A short title for this package
* @param string $sType Type of the package. SQL scripts must be of type 'text/sql'
* @param string $sDescription A longer description of the purpose of this package
* @return none
*/
public function AddPackage($sExternalFilePath, $sFilePath, $sTitle, $sType, $sDescription)
{
$this->m_aPackages[$sFilePath] = array('title' => $sTitle, 'type' => $sType, 'description' => $sDescription);
$this->m_oZip->addFile($sExternalFilePath, $sFilePath);
}
/**
* Reads the contents of the given file from the archive
* @param string $sFileName The path to the file inside the archive
* @return string The content of the file read from the archive
*/
public function GetFileContents($sFileName)
{
return $this->m_oZip->getFromName($sFileName);
}
/**
* Extracts the contents of the given file from the archive
* @param string $sFileName The path to the file inside the archive
* @param string $sDestinationFileName The path of the file to write
* @return none
*/
public function ExtractToFile($sFileName, $sDestinationFileName)
{
$iBufferSize = 64 * 1024; // Read 64K at a time
$oZipStream = $this->m_oZip->getStream($sFileName);
$oDestinationStream = fopen($sDestinationFileName, 'wb');
while (!feof($oZipStream)) {
$sContents = fread($oZipStream, $iBufferSize);
fwrite($oDestinationStream, $sContents);
}
fclose($oZipStream);
fclose($oDestinationStream);
}
/**
* Apply a SQL script taken from the archive. The package must be listed in the catalog and of type text/sql
* @param string $sFileName The path to the SQL package inside the archive
* @return boolean false in case of error, true otherwise
*/
public function ImportSql($sFileName, $sDatabase = 'itop')
{
if ( ($this->m_oZip->locateName($sFileName) == false) || (!isset($this->m_aPackages[$sFileName])) || ($this->m_aPackages[$sFileName]['type'] != 'text/sql'))
{
// invalid type or not listed in the catalog
return false;
}
$sTempName = tempnam("../tmp/", "sql");
//echo "Extracting to: '$sTempName'<br/>\n";
$this->ExtractToFile($sFileName, $sTempName);
// Note: the command line below works on Windows with the right path to mysql !!!
$sCommandLine = 'type "'.$sTempName.'" | "/iTop/MySQL Server 5.0/bin/mysql.exe" -u root '.$sDatabase;
//echo "Executing: '$sCommandLine'<br/>\n";
exec($sCommandLine, $aOutput, $iRet);
//echo "Return code: $iRet<br/>\n";
//echo "Output:<br/><pre>\n";
//print_r($aOutput);
//echo "</pre><br/>\n";
unlink($sTempName);
return ($iRet == 0);
}
/**
* Dumps some part of the specified MySQL database into the archive as a text/sql package
* @param $sTitle string A short title for this SQL script
* @param $sDescription string A longer description of the purpose of this SQL script
* @param $sFileName string The name of the package inside the archive
* @param $sDatabase string name of the database
* @param $aTables array array or table names. If empty, all tables are dumped
* @param $bStructureOnly boolean Whether or not to dump the data or just the schema
* @return boolean False in case of error, true otherwise
*/
public function AddDatabaseDump($sTitle, $sDescription, $sFileName, $sDatabase = 'itop', $aTables = array(), $bStructureOnly = true)
{
$sTempName = tempnam("../tmp/", "sql");
$sNoData = $bStructureOnly ? "--no-data" : "";
$sCommandLine = "\"/iTop/MySQL Server 5.0/bin/mysqldump.exe\" --user=root --opt $sNoData --result-file=$sTempName $sDatabase ".implode(" ", $aTables);
//echo "Executing command: '$sCommandLine'<br/>\n";
exec($sCommandLine, $aOutput, $iRet);
//echo "Return code: $iRet<br/>\n";
//echo "Output:<br/><pre>\n";
//print_r($aOutput);
//echo "</pre><br/>\n";
if ($iRet == 0)
{
$this->AddPackage($sTempName, $sFileName, $sTitle, 'text/sql', $sDescription);
}
//unlink($sTempName);
return ($iRet == 0);
}
/**
* Check the consistency of the archive
* @return boolean True if the archive file is consistent
*/
public function IsValid()
{
// TO DO: use a DTD to validate the XML instead of this hand-made validation
$bResult = true;
$aMandatoryTags = array('ARCHIVE' => array('VERSION'),
'TITLE' => array(),
'DESCRIPTION' => array(),
'PACKAGE' => array('TYPE', 'HREF', 'TITLE'));
$sXmlCatalog = $this->m_oZip->getFromName('catalog.xml');
$oParser = xml_parser_create();
xml_parse_into_struct($oParser, $sXmlCatalog, $aValues, $aIndexes);
xml_parser_free($oParser);
foreach($aMandatoryTags as $sTag => $aAttributes)
{
// Check that all the required tags are present
if (!isset($aIndexes[$sTag]))
{
$this->m_aErrorMessages[] = "The XML catalog does not contain the mandatory tag $sTag.";
$bResult = false;
}
else
{
foreach($aIndexes[$sTag] as $iIndex)
{
switch($aValues[$iIndex]['type'])
{
case 'complete':
case 'open':
// Check that all the required attributes are present
foreach($aAttributes as $sAttribute)
{
if (!isset($aValues[$iIndex]['attributes'][$sAttribute]))
{
$this->m_aErrorMessages[] = "The tag $sTag ($iIndex) does not contain the required attribute $sAttribute.";
}
}
break;
default:
// ignore other type of tags: close or cdata
}
}
}
}
return $bResult;
}
}
/*
// Unit test - reading an archive
$sArchivePath = '../tmp/archive.zip';
$oArchive = new iTopArchive($sArchivePath, iTopArchive::read);
$oArchive->ReadCatalog();
$oArchive->ImportSql('full_backup.sql');
// Writing an archive --
$sArchivePath = '../tmp/archive2.zip';
$oArchive = new iTopArchive($sArchivePath, iTopArchive::create);
$oArchive->SetTitle('First Archive !');
$oArchive->SetDescription('This is just a test. Does not contain a lot of useful data.');
$oArchive->AddPackage('../tmp/schema.sql', 'test.sql', 'this is just a test', 'text/sql', 'My first attempt at creating an archive from PHP...');
$oArchive->WriteCatalog();
$sArchivePath = '../tmp/archive2.zip';
$oArchive = new iTopArchive($sArchivePath, iTopArchive::create);
$oArchive->SetTitle('First Archive !');
$oArchive->SetDescription('This is just a test. Does not contain a lot of useful data.');
$oArchive->AddDatabaseDump('Test', 'This is my first automatic dump', 'schema.sql', 'itop', array('objects'));
$oArchive->WriteCatalog();
*/
?>

File diff suppressed because it is too large Load Diff

View File

@@ -33,7 +33,6 @@ 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');
MetaModel::IncludeModule('core/counter.class.inc.php');
MetaModel::IncludeModule('webservices/webservices.basic.php');

View File

@@ -56,9 +56,8 @@ interface iBackgroundProcess extends iProcess
* interface iScheduledProcess
* A variant of process that must be called at specific times
*
* @see \AbstractWeeklyScheduledProcess for a bootstrap implementation
* @license http://opensource.org/licenses/AGPL-3.0
* @copyright Copyright (C) 2013 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
interface iScheduledProcess extends iProcess
{
@@ -68,189 +67,14 @@ interface iScheduledProcess extends iProcess
public function GetNextOccurrence();
}
/**
* Implementation of {@link iScheduledProcess}, using config parameters for module
*
* Use these parameters :
*
* * enabled
* * week_days
* * time
*
* Param names and some of their default values are in constant that can be overriden.
*
* Other info (module name and time default value) should be provided using a method that needs to be implemented.
*
* @since 2.7.0
*/
abstract class AbstractWeeklyScheduledProcess implements iScheduledProcess
{
// param have default names/values but can be overriden
const MODULE_SETTING_ENABLED = 'enabled';
const DEFAULT_MODULE_SETTING_ENABLED = true;
const MODULE_SETTING_WEEKDAYS = 'week_days';
const DEFAULT_MODULE_SETTING_WEEKDAYS = 'monday, tuesday, wednesday, thursday, friday, saturday, sunday';
const MODULE_SETTING_TIME = 'time';
/**
* Module must be declared in each implementation
*
* @return string
*/
abstract protected function GetModuleName();
/**
* @return string default value for {@link MODULE_SETTING_TIME} config param.
* example '23:30'
*/
abstract protected function GetDefaultModuleSettingTime();
/**
* Interpret current setting for the week days
*
* @returns int[] (monday = 1)
* @throws ProcessInvalidConfigException
*/
public function InterpretWeekDays()
{
static $aWEEKDAYTON = array(
'monday' => 1,
'tuesday' => 2,
'wednesday' => 3,
'thursday' => 4,
'friday' => 5,
'saturday' => 6,
'sunday' => 7,
);
$aDays = array();
$sWeekDays = MetaModel::GetConfig()->GetModuleSetting(
$this->GetModuleName(),
static::MODULE_SETTING_WEEKDAYS,
static::DEFAULT_MODULE_SETTING_WEEKDAYS
);
if ($sWeekDays !== '')
{
$aWeekDaysRaw = explode(',', $sWeekDays);
foreach ($aWeekDaysRaw as $sWeekDay)
{
$sWeekDay = strtolower(trim($sWeekDay));
if (array_key_exists($sWeekDay, $aWEEKDAYTON))
{
$aDays[] = $aWEEKDAYTON[$sWeekDay];
}
else
{
throw new ProcessInvalidConfigException($this->GetModuleName().": wrong format for setting '".static::MODULE_SETTING_WEEKDAYS."' (found '$sWeekDay')");
}
}
}
if (count($aDays) === 0)
{
throw new ProcessInvalidConfigException($this->GetModuleName().': missing setting \''.static::MODULE_SETTING_WEEKDAYS.'\'');
}
$aDays = array_unique($aDays);
sort($aDays);
return $aDays;
}
/**
* Gives the exact time at which the process must be run next time
*
* @return DateTime
* @throws Exception
*/
public function GetNextOccurrence()
{
$bEnabled = MetaModel::GetConfig()->GetModuleSetting(
$this->GetModuleName(),
static::MODULE_SETTING_ENABLED,
static::DEFAULT_MODULE_SETTING_ENABLED
);
if (!$bEnabled)
{
return new DateTime('3000-01-01');
}
// 1st - Interpret the list of days as ordered numbers (monday = 1)
//
$aDays = $this->InterpretWeekDays();
// 2nd - Find the next active week day
//
$sProcessTime = MetaModel::GetConfig()->GetModuleSetting(
$this->GetModuleName(),
static::MODULE_SETTING_TIME,
static::GetDefaultModuleSettingTime()
);
if (!preg_match('/[0-2]\d:[0-5]\d/', $sProcessTime))
{
throw new ProcessInvalidConfigException($this->GetModuleName().": wrong format for setting '".static::MODULE_SETTING_TIME."' (found '$sProcessTime')");
}
$oNow = new DateTime();
$iNextPos = false;
for ($iDay = $oNow->format('N'); $iDay <= 7; $iDay++)
{
$iNextPos = array_search($iDay, $aDays, true);
if ($iNextPos !== false)
{
if (($iDay > $oNow->format('N')) || ($oNow->format('H:i') < $sProcessTime))
{
break;
}
$iNextPos = false; // necessary on sundays
}
}
// 3rd - Compute the result
//
if ($iNextPos === false)
{
// Jump to the first day within the next week
$iFirstDayOfWeek = $aDays[0];
$iDayMove = $oNow->format('N') - $iFirstDayOfWeek;
$oRet = clone $oNow;
$oRet->modify('-'.$iDayMove.' days');
$oRet->modify('+1 weeks');
}
else
{
$iNextDayOfWeek = $aDays[$iNextPos];
$iMove = $iNextDayOfWeek - $oNow->format('N');
$oRet = clone $oNow;
$oRet->modify('+'.$iMove.' days');
}
list($sHours, $sMinutes) = explode(':', $sProcessTime);
$oRet->setTime((int)$sHours, (int)$sMinutes);
return $oRet;
}
/**
* @see \iProcess
*
* @param int $iUnixTimeLimit
*
* @return string
*/
abstract public function Process($iUnixTimeLimit);
}
/**
* Exception for {@link iProcess} implementations.<br>
* Class ProcessException
* Exception for iProcess implementations.<br>
* An error happened during the processing but we can go on with the next implementations.
*/
class ProcessException extends CoreException
{
}
/**
* @since 2.7.0
*/
class ProcessInvalidConfigException extends ProcessException
{
}
/**
@@ -260,4 +84,5 @@ class ProcessInvalidConfigException extends ProcessException
*/
class ProcessFatalException extends CoreException
{
}

View File

@@ -19,7 +19,7 @@
/**
* Class BackgroundTask
* A class to record information about the execution of background processes ({@link iProcess} impl)
* A class to record information about the execution of background processes
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
@@ -55,7 +55,6 @@ class BackgroundTask extends DBObject
MetaModel::Init_AddAttribute(new AttributeBoolean("running", array("allowed_values"=>null, "sql"=>"running", "default_value"=>false, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("status", array("allowed_values"=>new ValueSetEnum('active,paused'), "sql"=>"status", "default_value"=>'active', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("system_user", array("allowed_values"=>null, "sql"=>"system_user", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
}
public function ComputeDurations($fLatestDuration)
@@ -74,4 +73,4 @@ class BackgroundTask extends DBObject
}
$this->Set('latest_run_duration', sprintf('%.3f',$fLatestDuration));
}
}
}

View File

@@ -654,7 +654,7 @@ class BulkChange
return $aResults;
}
protected function CreateObject(&$aResult, $iRow, $aRowData, CMDBChange $oChange = null)
{
$oTargetObj = MetaModel::NewObject($this->m_sClass);
@@ -726,38 +726,25 @@ class BulkChange
$aResult[$iRow]["__STATUS__"] = new RowStatus_Issue(Dict::Format('UI:CSVReport-Row-Issue-MissingExtKey', $sMissingKeys));
return $oTargetObj;
}
// Optionally record the results
// Optionaly record the results
//
if ($oChange)
{
$newID = $oTargetObj->DBInsert();
$newID = $oTargetObj->DBInsertTrackedNoReload($oChange);
$aResult[$iRow]["__STATUS__"] = new RowStatus_NewObj();
$aResult[$iRow]["finalclass"] = get_class($oTargetObj);
$aResult[$iRow]["id"] = new CellStatus_Void($newID);
}
else
{
$newID = 0;
$aResult[$iRow]["__STATUS__"] = new RowStatus_NewObj();
$aResult[$iRow]["finalclass"] = get_class($oTargetObj);
$aResult[$iRow]["id"] = new CellStatus_Void(0);
}
$aResult[$iRow]["__STATUS__"] = new RowStatus_NewObj();
$aResult[$iRow]["finalclass"] = get_class($oTargetObj);
$aResult[$iRow]["id"] = new CellStatus_Void($newID);
return $oTargetObj;
}
/**
* @param array $aResult
* @param int $iRow
* @param \CMDBObject $oTargetObj
* @param array $aRowData
* @param \CMDBChange $oChange
*
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
protected function UpdateObject(&$aResult, $iRow, $oTargetObj, $aRowData, CMDBChange $oChange = null)
{
$aResult[$iRow] = $this->PrepareObject($oTargetObj, $aRowData, $aErrors);
@@ -785,7 +772,7 @@ class BulkChange
{
try
{
$oTargetObj->DBUpdate();
$oTargetObj->DBUpdateTracked($oChange);
}
catch(CoreException $e)
{
@@ -799,14 +786,6 @@ class BulkChange
}
}
/**
* @param array $aResult
* @param int $iRow
* @param \CMDBObject $oTargetObj
* @param \CMDBChange $oChange
*
* @throws \BulkChangeException
*/
protected function UpdateMissingObject(&$aResult, $iRow, $oTargetObj, CMDBChange $oChange = null)
{
$aResult[$iRow] = $this->PrepareMissingObject($oTargetObj, $aErrors);
@@ -834,7 +813,7 @@ class BulkChange
{
try
{
$oTargetObj->DBUpdate();
$oTargetObj->DBUpdateTracked($oChange);
}
catch(CoreException $e)
{
@@ -850,11 +829,6 @@ class BulkChange
public function Process(CMDBChange $oChange = null)
{
if ($oChange)
{
CMDBObject::SetCurrentChange($oChange);
}
// Note: $oChange can be null, in which case the aim is to check what would be done
// Debug...

View File

@@ -1,21 +1,20 @@
<?php
/**
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
// Copyright (C) 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/>
define('EXPORTER_DEFAULT_CHUNK_SIZE', 1000);
@@ -110,7 +109,7 @@ class BulkExportResultGC implements iBackgroundProcess
{
// Next one ?
$oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL), array('created' => true) /* order by*/, array(), null, 1 /* limit count */);
$oSet->OptimizeColumnLoad(array('BulkExportResult' => array('temp_file_path')));
$oSet->OptimizeColumnLoad(array('temp_file_path'));
$oResult = $oSet->Fetch();
if (is_null($oResult))
{
@@ -171,7 +170,6 @@ abstract class BulkExport
$oRefClass = new ReflectionClass($sPHPClass);
if ($oRefClass->isSubclassOf('BulkExport') && !$oRefClass->isAbstract())
{
/** @var BulkExport $oBulkExporter */
$oBulkExporter = new $sPHPClass();
if ($oBulkExporter->IsFormatSupported($sFormatCode, $oSearch))
{
@@ -191,7 +189,7 @@ abstract class BulkExport
*
* @param int $iPersistentToken The identifier of the BulkExportResult object storing the information
*
* @return BulkExport|null
* @return iBulkExport|null
* @throws ArchivedObjectException
* @throws CoreException
* @throws ReflectionException

View File

@@ -59,6 +59,7 @@ require_once('sqlobjectquery.class.inc.php');
require_once('sqlunionquery.class.inc.php');
require_once('dbobject.class.php');
require_once('dbsearch.class.php');
require_once('dbobjectset.class.php');
require_once('backgroundprocess.inc.php');
@@ -513,23 +514,7 @@ abstract class CMDBObject extends DBObject
}
}
/**
* @deprecated 2.7.0 N°2361 simply use {@link DBInsert} instead, that will automatically create and persist a CMDBChange object.
* If you need to persist your own, call {@link CMDBObject::SetCurrentChange} before.
*
* @param \CMDBChange $oChange
* @param null $bSkipStrongSecurity
*
* @return int|null
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
* @throws \MySQLException
* @throws \OQLException
* @throws \SecurityException
*/
public function DBInsertTracked(CMDBChange $oChange, $bSkipStrongSecurity = null)
{
self::SetCurrentChange($oChange);
@@ -537,24 +522,7 @@ abstract class CMDBObject extends DBObject
$ret = $this->DBInsertTracked_Internal();
return $ret;
}
/**
* @deprecated 2.7.0 N°2361 simply use {@link DBInsertNoReload} instead, that will automatically create and persist a CMDBChange object.
* If you need to persist your own, call {@link CMDBObject::SetCurrentChange} before.
*
* @param \CMDBChange $oChange
* @param null $bSkipStrongSecurity
*
* @return int
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
* @throws \MySQLException
* @throws \OQLException
* @throws \SecurityException
*/
public function DBInsertTrackedNoReload(CMDBChange $oChange, $bSkipStrongSecurity = null)
{
self::SetCurrentChange($oChange);
@@ -562,20 +530,13 @@ abstract class CMDBObject extends DBObject
$ret = $this->DBInsertTracked_Internal(true);
return $ret;
}
/**
* @deprecated 2.7.0 N°2361 simply use {@link DBInsert} or {@link DBInsertNoReload} instead
*
* To Be Obsoleted: DO NOT rely on an overload of this method since
* DBInsertTracked (resp. DBInsertTrackedNoReload) may call directly
* DBInsert (resp. DBInsertNoReload) in future versions of iTop.
* @param bool $bDoNotReload
*
* @return integer Identifier of the created object
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \CoreWarning
* @throws \MySQLException
* @throws \OQLException
*/
protected function DBInsertTracked_Internal($bDoNotReload = false)
{
@@ -622,18 +583,6 @@ abstract class CMDBObject extends DBObject
return $ret;
}
/**
* @deprecated 2.7.0 N°2361 simply use {@link DBUpdate} instead, that will automatically create and persist a CMDBChange object.
* If you need to persist your own, call {@link CMDBObject::SetCurrentChange} before.
*
* @param \CMDBChange $oChange
* @param null $bSkipStrongSecurity
*
* @return int|void
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \SecurityException
*/
public function DBUpdateTracked(CMDBChange $oChange, $bSkipStrongSecurity = null)
{
self::SetCurrentChange($oChange);
@@ -645,38 +594,13 @@ abstract class CMDBObject extends DBObject
* @param null $oDeletionPlan
*
* @return \DeletionPlan|null
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DeleteException
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
*/
public function DBDelete(&$oDeletionPlan = null)
{
return $this->DBDeleteTracked_Internal($oDeletionPlan);
}
/**
* @deprecated 2.7.0 N°2361 simply use {@link DBDelete} instead, that will automatically create and persist a CMDBChange object.
* If you need to persist your own, call {@link CMDBObject::SetCurrentChange} before.
*
* @param \CMDBChange $oChange
* @param null $bSkipStrongSecurity
* @param null $oDeletionPlan
*
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DeleteException
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
* @throws \SecurityException
*/
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null)
{
self::SetCurrentChange($oChange);
@@ -688,17 +612,11 @@ abstract class CMDBObject extends DBObject
* @param null $oDeletionPlan
*
* @return \DeletionPlan|null
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \DeleteException
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \OQLException
*/
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
{
$prevkey = $this->GetKey();
$ret = parent::DBDelete($oDeletionPlan);
return $ret;
}

View File

@@ -99,14 +99,6 @@ class MySQLHasGoneAwayException extends MySQLException
}
}
/**
* @since 2.7.0 N°679
*/
class MySQLNoTransactionException extends MySQLException
{
}
/**
* CMDBSource
@@ -138,12 +130,6 @@ class CMDBSource
/** @var mysqli $m_oMysqli */
protected static $m_oMysqli;
/**
* @var int number of level for nested transactions : 0 if no transaction was ever opened, +1 for each 'START TRANSACTION' sent
* @since 2.7.0 N°679
*/
protected static $m_iTransactionLevel = 0;
/**
* SQL charset & collation declaration for text columns
*
@@ -151,7 +137,7 @@ class CMDBSource
* use expression as value)
*
* @see https://dev.mysql.com/doc/refman/5.7/en/charset-column.html
* @since 2.5.1 N°1001 switch to utf8mb4
* @since 2.5 N°1001 switch to utf8mb4
*/
public static function GetSqlStringColumnDefinition()
{
@@ -303,11 +289,11 @@ class CMDBSource
$iConnectInfoCount = count($aConnectInfo);
if ($bUsePersistentConnection && ($iConnectInfoCount == 3))
{
$iPort = (int)($aConnectInfo[2]);
$iPort = $aConnectInfo[2];
}
else if (!$bUsePersistentConnection && ($iConnectInfoCount == 2))
{
$iPort = (int)($aConnectInfo[1]);
$iPort = $aConnectInfo[1];
}
else
{
@@ -424,14 +410,6 @@ class CMDBSource
return $aVersions[0];
}
/**
* @return string
*/
public static function GetServerInfo()
{
return mysqli_get_server_info ( self::$m_oMysqli );
}
/**
* Get the DB vendor between MySQL and its main forks
* @return string
@@ -576,6 +554,11 @@ class CMDBSource
return $aRes;
}
// Stripslashes
if (get_magic_quotes_gpc())
{
$value = stripslashes($value);
}
// Quote if not a number or a numeric string
if ($bAlways || is_string($value))
{
@@ -584,89 +567,28 @@ class CMDBSource
return $value;
}
/**
* MariaDB returns "'value'" for enum, while MySQL returns "value" (without the surrounding single quotes)
*
* @param string $sValue
*
* @return string without the surrounding quotes
* @since 2.7.0 N°2490
*/
private static function RemoveSurroundingQuotes($sValue)
{
if (utils::StartsWith($sValue, '\'') && utils::EndsWith($sValue, '\''))
{
$sValue = substr($sValue, 1, -1);
}
return $sValue;
}
/**
* @param string $sSQLQuery
*
* @return \mysqli_result|null
* @return \mysqli_result
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \CoreException
*
* @since 2.7.0 N°679 handles nested transactions
*/
public static function Query($sSQLQuery)
{
if (preg_match('/^START TRANSACTION;?$/i', $sSQLQuery))
{
self::StartTransaction();
return null;
}
if (preg_match('/^COMMIT;?$/i', $sSQLQuery))
{
self::Commit();
return null;
}
if (preg_match('/^ROLLBACK;?$/i', $sSQLQuery))
{
self::Rollback();
return null;
}
return self::DBQuery($sSQLQuery);
}
/**
* Send the query directly to the DB. **Be extra cautious with this !**
*
* Use {@link Query} if you're not sure.
*
* @internal
*
* @param string $sSql
*
* @return bool|\mysqli_result
* @throws \MySQLHasGoneAwayException
* @throws \MySQLException
*
* @since 2.7.0 N°679
*/
private static function DBQuery($sSql)
{
$oKPI = new ExecutionKPI();
try
{
$oResult = self::$m_oMysqli->query($sSql);
$oResult = self::$m_oMysqli->query($sSQLQuery);
}
catch (mysqli_sql_exception $e)
catch(mysqli_sql_exception $e)
{
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql, $e));
throw new MySQLException('Failed to issue SQL query', array('query' => $sSQLQuery, $e));
}
$oKPI->ComputeStats('Query exec (mySQL)', $sSql);
$oKPI->ComputeStats('Query exec (mySQL)', $sSQLQuery);
if ($oResult === false)
{
$aContext = array('query' => $sSql);
$aContext = array('query' => $sSQLQuery);
$iMySqlErrorNo = self::$m_oMysqli->errno;
$aMySqlHasGoneAwayErrorCodes = MySQLHasGoneAwayException::getErrorCodes();
@@ -677,138 +599,11 @@ class CMDBSource
throw new MySQLException('Failed to issue SQL query', $aContext);
}
return $oResult;
}
/**
* If nested transaction, we are not starting a new one : only one global transaction will exist.
*
* Indeed [the official documentation](https://dev.mysql.com/doc/refman/5.6/en/commit.html) states :
*
* > Beginning a transaction causes any pending transaction to be committed
*
* @internal
* @see m_iTransactionLevel
* @since 2.7.0 N°679
*/
private static function StartTransaction()
{
$bHasExistingTransactions = self::IsInsideTransaction();
if (!$bHasExistingTransactions)
{
self::DBQuery('START TRANSACTION');
}
self::AddTransactionLevel();
}
/**
* Sends the COMMIT to the db only if we are at the root transaction level
*
* @internal
* @see m_iTransactionLevel
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @throws \MySQLNoTransactionException if called with no opened transaction
* @since 2.7.0 N°679
*/
private static function Commit()
{
if (!self::IsInsideTransaction())
{
// should not happen !
throw new MySQLNoTransactionException('Trying to commit transaction whereas none have been started !', null);
}
self::RemoveLastTransactionLevel();
if (self::IsInsideTransaction())
{
return;
}
self::DBQuery('COMMIT');
}
/**
* Sends the ROLLBACK to the db only if we are at the root transaction level
*
* The parameter allows to send a ROLLBACK whatever the current transaction level is
*
* @internal
* @see m_iTransactionLevel
*
* @throws \MySQLNoTransactionException if called with no opened transaction
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
* @since 2.7.0 N°679
*/
private static function Rollback()
{
if (!self::IsInsideTransaction())
{
// should not happen !
throw new MySQLNoTransactionException('Trying to commit transaction whereas none have been started !', null);
}
self::RemoveLastTransactionLevel();
if (self::IsInsideTransaction())
{
return;
}
self::DBQuery('ROLLBACK');
}
/**
* @api
* @see m_iTransactionLevel
* @return bool true if there is one transaction opened, false otherwise (not a single 'START TRANSACTION' sent)
* @since 2.7.0 N°679
*/
public static function IsInsideTransaction()
{
return (self::$m_iTransactionLevel > 0);
}
/**
* @internal
* @see m_iTransactionLevel
* @since 2.7.0 N°679
*/
private static function AddTransactionLevel()
{
++self::$m_iTransactionLevel;
}
/**
* @internal
* @see m_iTransactionLevel
* @since 2.7.0 N°679
*/
private static function RemoveLastTransactionLevel()
{
if (self::$m_iTransactionLevel === 0)
{
return;
}
--self::$m_iTransactionLevel;
}
/**
* @internal
* @see m_iTransactionLevel
* @since 2.7.0 N°679
*/
private static function RemoveAllTransactionLevels()
{
self::$m_iTransactionLevel = 0;
}
/**
*
* @deprecated 2.7.0 N°1627 use ItopCounter instead
*
* @param string $sTable
*
* @return int
@@ -843,13 +638,6 @@ class CMDBSource
return false;
}
/**
* @param $sSQLQuery
*
* @throws \CoreException
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
public static function DeleteFrom($sSQLQuery)
{
self::Query($sSQLQuery);
@@ -1126,83 +914,6 @@ class CMDBSource
return false;
}
/**
* There may have some differences between DB : for example in MySQL 5.7 we have "INT", while in MariaDB >= 10.2 you get "int DEFAULT 'NULL'"
*
* We still do a case sensitive comparison for enum values !
*
* A better solution would be to generate SQL field definitions ({@link GetFieldSpec} method) based on the DB used... But for
* now (N°2490 / SF #1756 / PR #91) we did implement this simpler solution
*
* @param string $sItopGeneratedFieldType
* @param string $sDbFieldType
*
* @return bool true if same type and options (case sensitive comparison only for type options), false otherwise
* @since 2.7.0 N°2490
*/
public static function IsSameFieldTypes($sItopGeneratedFieldType, $sDbFieldType)
{
list($sItopFieldDataType, $sItopFieldTypeOptions, $sItopFieldOtherOptions) = static::GetFieldDataTypeAndOptions($sItopGeneratedFieldType);
list($sDbFieldDataType, $sDbFieldTypeOptions, $sDbFieldOtherOptions) = static::GetFieldDataTypeAndOptions($sDbFieldType);
if (strcasecmp($sItopFieldDataType, $sDbFieldDataType) !== 0)
{
return false;
}
if (strcmp($sItopFieldTypeOptions, $sDbFieldTypeOptions) !== 0)
{
// case sensitive comp as we need to check case for enum possible values for example
return false;
}
// remove the default value NULL added by MariadDB
$sMariaDbDefaultNull = ' DEFAULT \'NULL\'';
if (utils::EndsWith($sDbFieldOtherOptions, $sMariaDbDefaultNull))
{
$sDbFieldOtherOptions = substr($sDbFieldOtherOptions, 0, -strlen($sMariaDbDefaultNull));
}
// remove quotes around default values (always present in MariaDB)
$sDbFieldOtherOptions = preg_replace_callback(
'/( DEFAULT )\'([^\']+)\'/',
function ($aMatches) use ($sItopFieldDataType) {
// ENUM default values should keep quotes, but all other numeric values don't have quotes
if (is_numeric($aMatches[2]) && ($sItopFieldDataType !== 'ENUM'))
{
return $aMatches[1].$aMatches[2];
}
return $aMatches[0];
},
$sDbFieldOtherOptions);
if (strcasecmp($sItopFieldOtherOptions, $sDbFieldOtherOptions) !== 0)
{
return false;
}
return true;
}
/**
* @param string $sCompleteFieldType sql field type, for example 'VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT 0'
*
* @return string[] consisting of 3 items :
* 1. data type : for example 'VARCHAR'
* 2. type value : for example '255'
* 3. other options : for example ' CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT 0'
*/
private static function GetFieldDataTypeAndOptions($sCompleteFieldType)
{
preg_match('/^([a-zA-Z]+)(\(([^\)]+)\))?( .+)?$/', $sCompleteFieldType, $aMatches);
$sDataType = $aMatches[1];
$sTypeOptions = isset($aMatches[2]) ? $aMatches[3] : '';
$sOtherOptions = isset($aMatches[4]) ? $aMatches[4] : '';
return array($sDataType, $sTypeOptions, $sOtherOptions);
}
/**
* @param string $sTable
* @param string $sField
@@ -1254,8 +965,7 @@ class CMDBSource
}
elseif (is_string($aFieldData["Default"]) == 'string')
{
$sDefaultValue = static::RemoveSurroundingQuotes($aFieldData["Default"]);
$sRet .= ' DEFAULT '.self::Quote($sDefaultValue);
$sRet .= ' DEFAULT '.self::Quote($aFieldData["Default"]);
}
return $sRet;
@@ -1396,14 +1106,14 @@ class CMDBSource
public static function DBCheckTableCharsetAndCollation($sTableName)
{
$sDBName = self::DBName();
$sTableInfoQuery = "SELECT C.CHARACTER_SET_NAME, T.TABLE_COLLATION
$sTableInfoQuery = "SELECT C.character_set_name, T.table_collation
FROM information_schema.`TABLES` T inner join information_schema.`COLLATION_CHARACTER_SET_APPLICABILITY` C
ON T.table_collation = C.collation_name
WHERE T.table_schema = '$sDBName'
AND T.table_name = '$sTableName';";
$aTableInfo = self::QueryToArray($sTableInfoQuery);
$sTableCharset = $aTableInfo[0]['CHARACTER_SET_NAME'];
$sTableCollation = $aTableInfo[0]['TABLE_COLLATION'];
$sTableCharset = $aTableInfo[0]['character_set_name'];
$sTableCollation = $aTableInfo[0]['table_collation'];
if ((DEFAULT_CHARACTER_SET == $sTableCharset) && (DEFAULT_COLLATION == $sTableCollation))
{
@@ -1547,7 +1257,7 @@ class CMDBSource
{
$sDBName = CMDBSource::DBName();
$sDBInfoQuery = "SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = '$sDBName';";
FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '$sDBName';";
$aDBInfo = CMDBSource::QueryToArray($sDBInfoQuery);
$sDBCharset = $aDBInfo[0]['DEFAULT_CHARACTER_SET_NAME'];
$sDBCollation = $aDBInfo[0]['DEFAULT_COLLATION_NAME'];

View File

@@ -1,31 +1,27 @@
<?php
/**
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*
*
*/
// 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/>
define('ITOP_APPLICATION', 'iTop');
define('ITOP_APPLICATION_SHORT', 'iTop');
define('ITOP_VERSION', '2.7.0-dev');
define('ITOP_VERSION', '2.6.2');
define('ITOP_REVISION', 'svn');
define('ITOP_BUILD_DATE', '$WCNOW$');
define('ITOP_VERSION_FULL', ITOP_VERSION.'-'.ITOP_REVISION);
define('ACCESS_USER_WRITE', 1);
define('ACCESS_ADMIN_WRITE', 2);
@@ -67,18 +63,18 @@ define('DEFAULT_MAX_DISPLAY_LIMIT', 15);
define('DEFAULT_STANDARD_RELOAD_INTERVAL', 5 * 60);
define('DEFAULT_FAST_RELOAD_INTERVAL', 1 * 60);
define('DEFAULT_SECURE_CONNECTION_REQUIRED', false);
define('DEFAULT_ALLOWED_LOGIN_TYPES', 'form|external|basic');
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
/**
* 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
* @package iTopORM
*/
class Config
{
@@ -96,18 +92,9 @@ class Config
* New way to store the settings !
*
* @var array
* @since 2.5.0 db* variables
* @since 2.7.0 export_pdf_font param
* @since 2.5 db* variables
*/
protected $m_aSettings = array(
'log_level_min' => array(
'type' => 'array',
'description' => 'Optional min log level per channel',
'default' => '',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'app_env_label' => array(
'type' => 'string',
'description' => 'Label displayed to describe the current application environment, defaults to the environment name (e.g. "production")',
@@ -183,27 +170,19 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'db_core_transactions_enabled' => array(
'type' => 'bool',
'description' => 'If true, CRUD transactions in iTop core will be enabled',
'default' => true,
'value' => true,
'db_character_set' => array( // @deprecated to remove in 2.7 ? N°1001 utf8mb4 switch
'type' => 'string',
'description' => 'Deprecated since iTop 2.5 : now using utf8mb4',
'default' => 'DEPRECATED_2.5',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'db_core_transactions_retry_count' => array(
'type' => 'integer',
'description' => 'Number of times the current transaction is tried',
'default' => 3,
'value' => 3,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'db_core_transactions_retry_delay_ms' => array(
'type' => 'integer',
'description' => 'Base delay in milliseconds between transaction tries',
'default' => 500,
'value' => 500,
'db_collation' => array( // @deprecated to remove in 2.7 ? N°1001 utf8mb4 switch
'type' => 'string',
'description' => 'Deprecated since iTop 2.5 : now using utf8mb4_unicode_ci',
'default' => 'DEPRECATED_2.5',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
@@ -352,16 +331,6 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'export_pdf_font' => array( // @since 2.7 PR #49
'type' => 'string',
'description' => 'Font used when generating a PDF file',
'default' => 'DejaVuSans', // DejaVuSans is a UTF-8 Unicode font, embedded in the TCPPDF lib we're using
// Standard PDF fonts like helvetica or times newroman are NOT Unicode
// A new DroidSansFallback can be used to improve CJK support (se PR #49)
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'access_mode' => array(
'type' => 'integer',
'description' => 'Access mode: ACCESS_READONLY = 0, ACCESS_ADMIN_WRITE = 2, ACCESS_FULL = 3',
@@ -394,14 +363,6 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'log_filename_builder_impl' => array(
'type' => 'string',
'description' => 'Name of the ILogFileNameBuilder to use',
'default' => 'WeeklyRotatingLogFileNameBuilder',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'log_rest_service' => array(
'type' => 'bool',
'description' => 'Log the usage of the REST/JSON service',
@@ -597,7 +558,7 @@ class Config
'Asia/Istanbul',
'Asia/Singapore',
'Africa/Casablanca',
'Australia/Sydney',
'Australia/Sydney'
),
'default' => 'Europe/Paris',
'value' => 'Europe/Paris',
@@ -721,15 +682,6 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'login_debug' => array(
'type' => 'bool',
'description' => 'Activate the login FSM debug',
// examples... not used (nor 'description')
'default' => false,
'value' => false,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'forgot_password' => array(
'type' => 'bool',
'description' => 'Enable the "Forgot password" feature',
@@ -840,63 +792,55 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'email_validation_pattern' => array(
'type' => 'string',
'description' => '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,}",
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'email_decoration_class' => array(
'type' => 'string',
'description' => 'CSS class(es) to use as decoration for the HTML rendering of the attribute. eg. "fas fa-envelope" will put a mail icon.',
'default' => 'fas fa-envelope',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'phone_number_validation_pattern' => array(
'type' => 'string',
'description' => 'Regular expression to validate/detect the format of a phone number',
'default' => "[0-9.\-\ \+\(\)]+",
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'phone_number_url_pattern' => array(
'type' => 'string',
'description' => 'Format for phone number url, use %1$s as a placeholder for the value. eg. "tel:%1$s" for regular phone applications or "callto:%1$s" for Skype. Default is "tel:%1$s".',
'default' => 'tel:%1$s',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'phone_number_decoration_class' => array(
'type' => 'string',
'description' => 'CSS class(es) to use as decoration for the HTML rendering of the attribute. eg. "fas fa-phone" will put a phone icon.',
'default' => 'fas fa-phone',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'email_validation_pattern' => array(
'type' => 'string',
'description' => '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,}",
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'email_decoration_class' => array(
'type' => 'string',
'description' => 'CSS class(es) to use as decoration for the HTML rendering of the attribute. eg. "fa fa-envelope" will put a mail icon.',
'default' => 'fa fa-envelope',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'phone_number_validation_pattern' => array(
'type' => 'string',
'description' => 'Regular expression to validate/detect the format of a phone number',
'default' => "[0-9.\-\ \+\(\)]+",
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'phone_number_url_pattern' => array(
'type' => 'string',
'description' => 'Format for phone number url, use %1$s as a placeholder for the value. eg. "tel:%1$s" for regular phone applications or "callto:%1$s" for Skype. Default is "tel:%1$s".',
'default' => 'tel:%1$s',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'phone_number_decoration_class' => array(
'type' => 'string',
'description' => 'CSS class(es) to use as decoration for the HTML rendering of the attribute. eg. "fa fa-phone" will put a phone icon.',
'default' => 'fa fa-phone',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'log_kpi_duration' => array(
'type' => 'integer',
'description' => 'Level of logging for troubleshooting performance issues (1 to enable, 2 +blame callers) new: add "log_kpi_slow_queries" to limit the stats',
'description' => 'Level of logging for troubleshooting performance issues (1 to enable, 2 +blame callers)',
// examples... not used
'default' => 0,
'value' => 0,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'log_kpi_slow_queries' => array(
'type' => 'float',
'description' => 'Log only KPI duration stats lasting more than this value in seconds (0 for all)',
'default' => 1,
'value' => 1,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'log_kpi_memory' => array(
'type' => 'integer',
'description' => 'Level of logging for troubleshooting memory limit issues',
@@ -1105,6 +1049,14 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'svg_sanitizer' => array(
'type' => 'string',
'description' => 'The class to use for SVG sanitization : allow to provide a custom made sanitizer',
'default' => 'SVGDOMSanitizer',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'inline_image_max_display_width' => array(
'type' => 'integer',
'description' => 'The maximum width (in pixels) when displaying images inside an HTML formatted attribute. Images will be displayed using this this maximum width.',
@@ -1161,6 +1113,14 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'disable_attachments_download_legacy_portal' => array(
'type' => 'bool',
'description' => 'Disable attachments download from legacy portal',
'default' => true,
'value' => true,
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'secure_rest_services' => array(
'type' => 'bool',
'description' => 'When set to true, only the users with the profile "REST Services User" are allowed to use the REST web services.',
@@ -1209,51 +1169,15 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'use_legacy_dbsearch' => array(
'security.disable_inline_documents_sandbox' => array(
'type' => 'bool',
'description' => 'If set, DBSearch will use legacy SQL query generation',
'description' => 'If true then the sandbox for documents displayed in a browser tab will be disabled; enabling scripts and other interactive content. Note that setting this to true will open the application to potential XSS attacks!',
'default' => false,
'value' => false,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'query_cache_enabled' => array(
'type' => 'bool',
'description' => 'If set, DBSearch will use cache for query generation',
'default' => true,
'value' => true,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'expression_cache_enabled' => array(
'type' => 'bool',
'description' => 'If set, DBSearch will use cache for query expression generation',
'default' => true,
'value' => true,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'log_kpi_record_oql' => array(
'type' => 'integer',
'description' => '1 => Record OQL requests and parameters',
'default' => 0,
'value' => 0,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'backoffice_default_theme' => array(
'type' => 'string',
'description' => 'Default theme used for '.ITOP_APPLICATION_SHORT.'\'s console',
'default' => 'light-grey',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
);
/**
* @var \iTopConfigParser|null
*/
private $oItopConfigParser;
public function IsProperty($sPropCode)
{
@@ -1264,7 +1188,6 @@ class Config
* @return string identifier that can be used for example to name WebStorage/SessionStorage keys (they
* are related to a whole domain, and a domain can host multiple itop)
* Beware: do not expose server side information to the client !
* @throws \Exception
*/
public function GetItopInstanceid()
{
@@ -1286,7 +1209,7 @@ class Config
*
* @throws \CoreException
*/
public function Set($sPropCode, $value, $sSourceDesc = 'unknown', $bCanOverride = false)
public function Set($sPropCode, $value, $sSourceDesc = 'unknown')
{
$sType = $this->m_aSettings[$sPropCode]['type'];
switch ($sType)
@@ -1310,18 +1233,18 @@ class Config
}
$this->m_aSettings[$sPropCode]['value'] = $value;
$this->m_aSettings[$sPropCode]['source_of_value'] = $sSourceDesc;
$this->m_aCanOverrideSettings[$sPropCode] = $bCanOverride;
}
/**
* @param string $sPropCode
*
* @return mixed
*/
public function Get($sPropCode)
{
return $this->m_aSettings[$sPropCode]['value'];
}
/**
* @param string $sPropCode
*
* @return mixed
*/
public function Get($sPropCode)
{
return $this->m_aSettings[$sPropCode]['value'];
}
/**
* Event log options (see LOG_... definition)
@@ -1393,16 +1316,16 @@ class Config
*/
protected $m_aCharsets;
/**
* Config constructor.
*
* @param string|null $sConfigFile
* @param bool $bLoadConfig
*
* @throws \ConfigException
* @throws \CoreException
*/
public function __construct($sConfigFile = null, $bLoadConfig = true)
/**
* Config constructor.
*
* @param string|null $sConfigFile
* @param bool $bLoadConfig
*
* @throws \ConfigException
* @throws \CoreException
*/
public function __construct($sConfigFile = null, $bLoadConfig = true)
{
$this->m_sFile = $sConfigFile;
if (is_null($sConfigFile))
@@ -1438,7 +1361,7 @@ class Config
//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_sEncryptionKey= isset($aEncryptParams['key']) ? $aEncryptParams['key'] : DEFAULT_ENCRYPTION_KEY;
$this->m_aModuleSettings = array();
@@ -1464,13 +1387,13 @@ class Config
*/
}
/**
* @param string $sPurpose
* @param string $sFileName
*
* @throws \ConfigException
*/
protected function CheckFile($sPurpose, $sFileName)
/**
* @param string $sPurpose
* @param string $sFileName
*
* @throws \ConfigException
*/
protected function CheckFile($sPurpose, $sFileName)
{
if (!file_exists($sFileName))
{
@@ -1513,12 +1436,6 @@ class Config
$sNoise = trim(ob_get_contents());
ob_end_clean();
}
catch (Error $e)
{
// PHP 7
throw new ConfigException('Error in configuration file',
array('file' => $sConfigFile, 'error' => $e->getMessage().' at line '.$e->getLine()));
}
catch (Exception $e)
{
// well, never reach in case of parsing error :-(
@@ -1526,6 +1443,12 @@ class Config
throw new ConfigException('Error in configuration file',
array('file' => $sConfigFile, 'error' => $e->getMessage()));
}
catch(Error $e)
{
// PHP 7
throw new ConfigException('Error in configuration file',
array('file' => $sConfigFile, 'error' => $e->getMessage().' at line '.$e->getLine()));
}
if (strlen($sNoise) > 0)
{
// Note: sNoise is an html output, but so far it was ok for me (e.g. showing the entire call stack)
@@ -1564,15 +1487,10 @@ class Config
{
$value = $rawvalue;
}
$this->Set($sPropCode, $value, $sConfigFile, true);
$this->Set($sPropCode, $value, $sConfigFile);
}
}
if (file_exists(READONLY_MODE_FILE))
{
$this->Set('access_mode', ACCESS_READONLY, READONLY_MODE_FILE);
}
$this->m_bLogGlobal = isset($MySettings['log_global']) ? (bool)trim($MySettings['log_global']) : DEFAULT_LOG_GLOBAL;
$this->m_bLogNotification = isset($MySettings['log_notification']) ? (bool)trim($MySettings['log_notification']) : DEFAULT_LOG_NOTIFICATION;
$this->m_bLogIssue = isset($MySettings['log_issue']) ? (bool)trim($MySettings['log_issue']) : DEFAULT_LOG_ISSUE;
@@ -1601,16 +1519,6 @@ class Config
// (we have their final path at that point)
}
/**
* @see \MetaModel::GetModuleParameter()
*
* @param string $sProperty
* @param mixed $defaultvalue
*
* @param string $sModule
*
* @return mixed|null if present, value defined in the configuration file, if not module parameter from XML
*/
public function GetModuleSetting($sModule, $sProperty, $defaultvalue = null)
{
if (isset($this->m_aModuleSettings[$sModule][$sProperty]))
@@ -1622,18 +1530,14 @@ class Config
return $this->GetModuleParameter($sModule, $sProperty, $defaultvalue);
}
/**
* @see \MetaModel::GetModuleSetting() to get from the configuration file first
*
* @param string $sProperty
* @param mixed $defaultvalue
*
* @param string $sModule
*
* @return mixed|null parameter value defined in the XML
* @link https://www.itophub.io/wiki/page?id=latest%3Acustomization%3Axml_reference#modules_parameters
*/
public function GetModuleParameter($sModule, $sProperty, $defaultvalue = null)
/**
* @param string $sModule
* @param string $sProperty
* @param mixed|null $defaultvalue
*
* @return mixed|null
*/
public function GetModuleParameter($sModule, $sProperty, $defaultvalue = null)
{
$ret = $defaultvalue;
if (class_exists('ModulesXMLParameters'))
@@ -1663,6 +1567,83 @@ class Config
$this->m_aAddons = $aAddons;
}
/**
* @return string
*
* @deprecated 2.5 will be removed in 2.6
* @see Config::Get() as a replacement
*/
public function GetDBHost()
{
return $this->Get('db_host');
}
/**
* @return string
*
* @deprecated 2.5 will be removed in 2.6
* @see Config::Get() as a replacement
*/
public function GetDBName()
{
return $this->Get('db_name');
}
/**
* @return string
*
* @deprecated 2.5 will be removed in 2.6
* @see Config::Get() as a replacement
*/
public function GetDBSubname()
{
return $this->Get('db_subname');
}
/**
* @return string
*
* @deprecated 2.5 will be removed in 2.6 N°1001 utf8mb4 switch
* @see Config::DEFAULT_CHARACTER_SET
*/
public function GetDBCharacterSet()
{
return DEFAULT_CHARACTER_SET;
}
/**
* @return string
*
* @deprecated 2.5 will be removed in 2.6 N°1001 utf8mb4 switch
* @see Config::DEFAULT_COLLATION
*/
public function GetDBCollation()
{
return DEFAULT_COLLATION;
}
/**
* @return string
*
* @deprecated 2.5 will be removed in 2.6
* @see Config::Get() as a replacement
*/
public function GetDBUser()
{
return $this->Get('db_user');
}
/**
* @return string
*
* @deprecated 2.5 will be removed in 2.6
* @see Config::Get() as a replacement
*/
public function GetDBPwd()
{
return $this->Get('db_pwd');
}
public function GetLogGlobal()
{
return $this->m_bLogGlobal;
@@ -1879,46 +1860,22 @@ 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
/**
* 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
*
* @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
*
* @throws \ConfigException
*/
* @throws \ConfigException
*/
public function WriteToFile($sFileName = '')
{
if (empty($sFileName))
{
$sFileName = $this->m_sFile;
}
$oHandle = null;
$sConfig = null;
if (is_file($this->m_sFile))
{
$oHandle = fopen($this->m_sFile, 'r');
$index = 0;
while (!flock($oHandle, LOCK_SH))
{
if ($index > 50)
{
throw new ConfigException("Could not read to configuration file", array('file' => $this->m_sFile));
}
usleep(100000);
$index++;
}
$sConfig = file_get_contents($this->m_sFile);
}
$this->oItopConfigParser = new iTopConfigParser($sConfig);
if ($oHandle !==null)
{
flock($oHandle, LOCK_UN);
}
$hFile = @fopen($sFileName, 'w');
if ($hFile !== false)
{
@@ -1940,6 +1897,7 @@ class Config
'log_notification' => $this->m_bLogNotification,
'log_issue' => $this->m_bLogIssue,
'log_web_service' => $this->m_bLogWebService,
'query_cache_enabled' => $this->m_bQueryCacheEnabled,
'secure_connection_required' => $this->m_bSecureConnectionRequired,
);
foreach ($aBoolValues as $sKey => $bValue)
@@ -1992,37 +1950,30 @@ class Config
// Write all values that are either always visible or present in the cloned config file
if ($aSettingInfo['show_in_conf_sample'] || (!empty($aSettingInfo['source_of_value']) && ($aSettingInfo['source_of_value'] != 'unknown')))
{
$sType = $aSettingInfo['type'];
switch ($sType)
{
case 'bool':
$sSeenAs = $aSettingInfo['value'] ? 'true' : 'false';
break;
default:
$sSeenAs = self::PrettyVarExport($aSettingInfo['value'], "\t");
}
fwrite($hFile, "\n");
if (isset($aSettingInfo['description']))
{
fwrite($hFile, "\t// $sPropCode: {$aSettingInfo['description']}\n");
}
if (isset($aSettingInfo['default']))
{
if (isset($this->m_aCanOverrideSettings[$sPropCode]) && $this->m_aCanOverrideSettings[$sPropCode])
$default = $aSettingInfo['default'];
if ($aSettingInfo['type'] == 'bool')
{
$aParserValue = $this->oItopConfigParser->GetVarValue('MySettings', $sPropCode);
$default = $default ? 'true' : 'false';
}
else
{
$aParserValue = array('found' => false);
}
$sComment = self::PrettyVarExport($aParserValue,$aSettingInfo['default'], "\t//\t\t", true);
fwrite($hFile,"\t//\tdefault: {$sComment}\n");
fwrite($hFile,
"\t//\tdefault: ".self::PrettyVarExport($aSettingInfo['default'], "\t//\t\t", true)."\n");
}
if (isset($this->m_aCanOverrideSettings[$sPropCode]) && $this->m_aCanOverrideSettings[$sPropCode])
{
$aParserValue = $this->oItopConfigParser->GetVarValue('MySettings', $sPropCode);
}
else
{
$aParserValue = array('found' => false);
}
$sSeenAs = self::PrettyVarExport($aParserValue,$aSettingInfo['value'], "\t");
fwrite($hFile, "\t'$sPropCode' => $sSeenAs,\n");
}
}
@@ -2036,7 +1987,7 @@ class Config
fwrite($hFile, "\t'$sModule' => array (\n");
foreach ($aProperties as $sProperty => $value)
{
$sNiceExport = self::PrettyVarExport($this->oItopConfigParser->GetVarValue('MyModuleSettings', $sProperty), $value, "\t\t");
$sNiceExport = self::PrettyVarExport($value, "\t\t");
fwrite($hFile, "\t\t'$sProperty' => $sNiceExport,\n");
}
fwrite($hFile, "\t),\n");
@@ -2049,29 +2000,16 @@ class Config
fwrite($hFile, " *\n");
fwrite($hFile, " */\n");
fwrite($hFile, "\$MyModules = array(\n");
$aParserValue = $this->oItopConfigParser->GetVarValue('MyModules', 'addons');
if ($aParserValue['found'])
fwrite($hFile, "\t'addons' => array (\n");
foreach ($this->m_aAddons as $sKey => $sFile)
{
fwrite($hFile, "\t'addons' => {$aParserValue['value']},\n");
}
else
{
fwrite($hFile, "\t'addons' => array (\n");
foreach ($this->m_aAddons as $sKey => $sFile)
{
fwrite($hFile, "\t\t'$sKey' => '$sFile',\n");
}
fwrite($hFile, "\t),\n");
fwrite($hFile, "\t\t'$sKey' => '$sFile',\n");
}
fwrite($hFile, "\t),\n");
fwrite($hFile, ");\n");
fwrite($hFile, '?'.'>'); // Avoid perturbing the syntax highlighting !
$bReturn = fclose($hFile);
utils::SetConfig($this);
FileLog::RenameLegacyLogFiles();
return $bReturn;
return fclose($hFile);
}
else
{
@@ -2079,16 +2017,16 @@ 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
*
* @param array $aParamValues
* @param string|null $sModulesDir
* @param bool $bPreserveModuleSettings
*
* @throws \Exception
* @throws \CoreException
*/
public function UpdateFromParams($aParamValues, $sModulesDir = null, $bPreserveModuleSettings = false)
{
if (isset($aParamValues['application_path']))
@@ -2123,7 +2061,7 @@ class Config
$this->Set('db_name', $sDBName);
$this->Set('db_subname', $aParamValues['db_prefix']);
$bDbTlsEnabled = (bool)$aParamValues['db_tls_enabled'];
$bDbTlsEnabled = (bool) $aParamValues['db_tls_enabled'];
if ($bDbTlsEnabled)
{
$this->Set('db_tls.enabled', $bDbTlsEnabled, 'UpdateFromParams');
@@ -2134,12 +2072,9 @@ class Config
$this->Set('db_tls.enabled', $bDbTlsEnabled, null);
}
$sDbTlsCa = $bDbTlsEnabled ? $aParamValues['db_tls_ca'] : null;
if (isset($sDbTlsCa) && !empty($sDbTlsCa))
{
if (isset($sDbTlsCa) && !empty($sDbTlsCa)) {
$this->Set('db_tls.ca', $sDbTlsCa, 'UpdateFromParams');
}
else
{
} else {
// empty parameter : we don't want it in the file
$this->Set('db_tls.ca', null, null);
}
@@ -2166,7 +2101,7 @@ class Config
* selected modules
*
* @param string $sModulesDir The relative path to the directory to scan for modules (typically the 'env-xxx'
* directory resulting from the compilation). If null nothing will be done.
* directory resulting from the compilation)
* @param array $aSelectedModules An array of selected modules' identifiers. If null all modules found will be
* considered as installed
*
@@ -2174,62 +2109,60 @@ class Config
*/
public function UpdateIncludes($sModulesDir, $aSelectedModules = null)
{
if ($sModulesDir === null)
if (!is_null($sModulesDir))
{
return;
}
// Initialize the arrays below with default values for the application...
$oEmptyConfig = new Config('dummy_file', false); // Do NOT load any config file, just set the default values
$aAddOns = $oEmptyConfig->GetAddOns();
// Initialize the arrays below with default values for the application...
$oEmptyConfig = new Config('dummy_file', false); // Do NOT load any config file, just set the default values
$aAddOns = $oEmptyConfig->GetAddOns();
$aModules = ModuleDiscovery::GetAvailableModules(array(APPROOT.$sModulesDir));
foreach ($aModules as $sModuleId => $aModuleInfo)
{
list ($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId);
if (is_null($aSelectedModules) || in_array($sModuleName, $aSelectedModules))
$aModules = ModuleDiscovery::GetAvailableModules(array(APPROOT.$sModulesDir));
foreach ($aModules as $sModuleId => $aModuleInfo)
{
if (isset($aModuleInfo['settings']))
list ($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId);
if (is_null($aSelectedModules) || in_array($sModuleName, $aSelectedModules))
{
list ($sName, $sVersion) = ModuleDiscovery::GetModuleName($sModuleId);
foreach ($aModuleInfo['settings'] as $sProperty => $value)
if (isset($aModuleInfo['settings']))
{
if (isset($this->m_aModuleSettings[$sName][$sProperty]))
list ($sName, $sVersion) = ModuleDiscovery::GetModuleName($sModuleId);
foreach ($aModuleInfo['settings'] as $sProperty => $value)
{
// Do nothing keep the original value
}
else
{
$this->SetModuleSetting($sName, $sProperty, $value);
if (isset($this->m_aModuleSettings[$sName][$sProperty]))
{
// Do nothing keep the original value
}
else
{
$this->SetModuleSetting($sName, $sProperty, $value);
}
}
}
}
if (isset($aModuleInfo['installer']))
{
$sModuleInstallerClass = $aModuleInfo['installer'];
if (!class_exists($sModuleInstallerClass))
if (isset($aModuleInfo['installer']))
{
throw new Exception("Wrong installer class: '$sModuleInstallerClass' is not a PHP class - Module: ".$aModuleInfo['label']);
$sModuleInstallerClass = $aModuleInfo['installer'];
if (!class_exists($sModuleInstallerClass))
{
throw new Exception("Wrong installer class: '$sModuleInstallerClass' is not a PHP class - Module: ".$aModuleInfo['label']);
}
if (!is_subclass_of($sModuleInstallerClass, 'ModuleInstallerAPI'))
{
throw new Exception("Wrong installer class: '$sModuleInstallerClass' is not derived from 'ModuleInstallerAPI' - Module: ".$aModuleInfo['label']);
}
$aCallSpec = array($sModuleInstallerClass, 'BeforeWritingConfig');
call_user_func_array($aCallSpec, array($this));
}
if (!is_subclass_of($sModuleInstallerClass, 'ModuleInstallerAPI'))
{
throw new Exception("Wrong installer class: '$sModuleInstallerClass' is not derived from 'ModuleInstallerAPI' - Module: ".$aModuleInfo['label']);
}
$aCallSpec = array($sModuleInstallerClass, 'BeforeWritingConfig');
call_user_func_array($aCallSpec, array($this));
}
}
$this->SetAddOns($aAddOns);
}
$this->SetAddOns($aAddOns);
}
/**
* 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
*
* @param array $aStrings
* @param string $sSearchPrefix
* @param string $sNewPrefix
*/
protected static function ChangePrefix(&$aStrings, $sSearchPrefix, $sNewPrefix)
{
foreach ($aStrings as &$sFile)
@@ -2241,13 +2174,13 @@ 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
*
* @param string $sSourceEnv
* @param string $sTargetEnv
*/
public function ChangeModulesPath($sSourceEnv, $sTargetEnv)
{
// Now does nothing since the includes are built into the environment itself
@@ -2256,7 +2189,6 @@ class Config
/**
* Pretty format a var_export'ed value so that (if possible) the identation is preserved on every line
*
* @param array $aParserValue
* @param mixed $value The value to export
* @param string $sIndentation The string to use to indent the text
* @param bool $bForceIndentation Forces the identation (enven if it breaks/changes an eval, for example to ouput a
@@ -2264,13 +2196,8 @@ class Config
*
* @return string The indented export string
*/
protected static function PrettyVarExport($aParserValue, $value, $sIndentation, $bForceIndentation = false)
protected static function PrettyVarExport($value, $sIndentation, $bForceIndentation = false)
{
if ($aParserValue['found'])
{
return $aParserValue['value'];
}
$sExport = var_export($value, true);
$sNiceExport = str_replace(array("\r\n", "\n", "\r"), "\n".$sIndentation, trim($sExport));
if (!$bForceIndentation)

View File

@@ -19,14 +19,14 @@
/**
* Simple helper class for keeping track of the context inside the call stack
*
*
* To check (anywhere in the code) if a particular context tag is present
* in the call stack simply do:
*
*
* if (ContextTag::Check(<the_tag>)) ...
*
*
* For example to know if the code is being executed in the context of a portal do:
*
*
* if (ContextTag::Check('GUI:Portal'))
*
* @copyright Copyright (C) 2016-2017 Combodo SARL
@@ -35,15 +35,8 @@
class ContextTag
{
const TAG_PORTAL = 'GUI:Portal';
const TAG_CRON = 'CRON';
const TAG_CONSOLE = 'GUI:Console';
const TAG_SETUP = 'Setup';
const TAG_SYNCHRO = 'Synchro';
const TAG_REST = 'REST/JSON';
protected static $aStack = array();
/**
* Store a context tag on the stack
* @param string $sTag
@@ -53,11 +46,6 @@ class ContextTag
static::$aStack[] = $sTag;
}
public static function AddContext($sTag)
{
static::$aStack[] = $sTag;
}
/**
* Cleanup the context stack
*/
@@ -65,7 +53,7 @@ class ContextTag
{
array_pop(static::$aStack);
}
/**
* Check if a given tag is present in the stack
* @param string $sTag
@@ -75,53 +63,13 @@ class ContextTag
{
return in_array($sTag, static::$aStack);
}
/**
* Get the whole stack as an array
* @return array
* @return hash
*/
public static function GetStack()
{
return static::$aStack;
}
/**
* Get all the predefined context tags
* @return array
*/
public static function GetTags()
{
$aRawTags = array(
ContextTag::TAG_REST,
ContextTag::TAG_SYNCHRO,
ContextTag::TAG_SETUP,
ContextTag::TAG_CONSOLE,
ContextTag::TAG_CRON,
ContextTag::TAG_PORTAL);
$aTags = array();
foreach ($aRawTags as $sRawTag)
{
$aTags[$sRawTag] = Dict::S("Core:Context={$sRawTag}");
}
$aPortalsConf = PortalDispatcherData::GetData();
$aDispatchers = array();
foreach ($aPortalsConf as $sPortalId => $aConf)
{
$sHandlerClass = $aConf['handler'];
$aDispatchers[$sPortalId] = new $sHandlerClass($sPortalId);
}
foreach ($aDispatchers as $sPortalId => $oDispatcher)
{
if ($sPortalId != 'backoffice')
{
$aTags['Portal:'.$sPortalId] = $oDispatcher->GetLabel();
}
}
return $aTags;
}
}
}

View File

@@ -183,30 +183,6 @@ class CoreCannotSaveObjectException extends CoreException
}
}
/**
* @since 2.7.0 N°2555
*/
class CorePortalInvalidActionRuleException extends CoreException
{
}
/**
* @since 2.7.0 N°2555
*/
class CoreOqlException extends CoreException
{
}
/**
* @since 2.7.0 N°2555
*/
class CoreOqlMultipleResultsForbiddenException extends CoreOqlException
{
}
class CoreWarning extends CoreException
{
}
@@ -223,27 +199,7 @@ class SecurityException extends CoreException
* Throwned when querying on an object that exists in the database but is archived
*
* @see N.1108
* @since 2.5.1
*/
class ArchivedObjectException extends CoreException
{
}
/**
* A parameter stored in the {@link Config} is invalid
*
* @since 2.7.0
*/
class InvalidConfigParamException extends CoreException
{
}
/**
* Throwned when the password is not valid
*
* @since 2.7.0
*/
class InvalidPasswordAttributeOneWayPassword extends CoreException
{
}

View File

@@ -1,251 +0,0 @@
<?php
/**
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
/**
* Class ItopCounter
*
*/
final class ItopCounter
{
/**
* Key based counter.
* The counter is protected against concurrency script.
*
* @param $sCounterName
* @param null|callable $oNewObjectValueProvider optional callable that must return an integer. Used when no key is found
*
* @return int the counter starting at
* * `0` when no $oNewObjectValueProvider is given (or null)
* * `$oNewObjectValueProvider() + 1` otherwise
*
* @throws \CoreException
* @throws \MySQLException
* @throws \Exception
*/
public static function Inc($sCounterName, $oNewObjectValueProvider = null)
{
$sSelfClassName = self::class;
$sMutexKeyName = "{$sSelfClassName}-{$sCounterName}";
$oiTopMutex = new iTopMutex($sMutexKeyName);
$oiTopMutex->Lock();
$bIsInsideTransaction = CMDBSource::IsInsideTransaction();
if ($bIsInsideTransaction)
{
// # Transaction isolation hack:
// When inside a transaction, we need to open a new connection for the counter.
// So it is visible immediately to the connections outside of the transaction.
// Either way, the lock is not long enought, and there would be duplicate ref.
//
// SELECT ... FOR UPDATE would have also worked but with the cost of extra long lock (until the commit),
// we did not wanted this! As opening a short connection is less prone to starving than a long running one.
// Plus it would trigger way more deadlocks!
$hDBLink = self::InitMySQLSession();
}
else
{
$hDBLink = CMDBSource::GetMysqli();
}
try
{
$oFilter = DBObjectSearch::FromOQL('SELECT KeyValueStore WHERE key_name=:key_name AND namespace=:namespace', array(
'key_name' => $sCounterName,
'namespace' => $sSelfClassName,
));
$oAttDef = MetaModel::GetAttributeDef('KeyValueStore', 'value');
$aAttToLoad = array('KeyValueStore' => array('value' => $oAttDef));
$sSql = $oFilter->MakeSelectQuery(array(), array(), $aAttToLoad);
$hResult = mysqli_query($hDBLink, $sSql);
$aCounter = mysqli_fetch_array($hResult, MYSQLI_NUM);
mysqli_free_result($hResult);
//Rebuild the filter, as the MakeSelectQuery polluted the orignal and it cannot be reused
$oFilter = DBObjectSearch::FromOQL('SELECT KeyValueStore WHERE key_name=:key_name AND namespace=:namespace', array(
'key_name' => $sCounterName,
'namespace' => $sSelfClassName,
));
if (is_null($aCounter))
{
if (null != $oNewObjectValueProvider)
{
$iComputedValue = $oNewObjectValueProvider();
}
else
{
$iComputedValue = 0;
}
$iCurrentValue = $iComputedValue + 1;
$aQueryParams = array(
'key_name' => $sCounterName,
'value' => "$iCurrentValue",
'namespace' => $sSelfClassName,
);
$sSql = $oFilter->MakeInsertQuery($aQueryParams);
}
else
{
$iCurrentValue = (int) $aCounter[1];
$iCurrentValue++;
$aQueryParams = array(
'value' => "$iCurrentValue",
);
$sSql = $oFilter->MakeUpdateQuery($aQueryParams);
}
$hResult = mysqli_query($hDBLink, $sSql);
}
catch(Exception $e)
{
IssueLog::Error($e->getMessage());
throw $e;
}
finally
{
if ($bIsInsideTransaction)
{
mysqli_close($hDBLink);
}
$oiTopMutex->Unlock();
}
return $iCurrentValue;
}
/**
* handle a counter for the root class of given $sLeafClass.
* If no counter exist initialize it with the `max(id) + 1`
*
*
*
* @param $sLeafClass
*
* @return int
* @throws \ArchivedObjectException
* @throws \CoreCannotSaveObjectException
* @throws \CoreException
* @throws \CoreOqlMultipleResultsForbiddenException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
* @throws \OQLException
*/
public static function IncClass($sLeafClass)
{
$sRootClass = MetaModel::GetRootClass($sLeafClass);
$oNewObjectCallback = function() use ($sRootClass)
{
$sRootTable = MetaModel::DBGetTable($sRootClass);
$sIdField = MetaModel::DBGetKey($sRootClass);
return CMDBSource::QueryToScalar("SELECT max(`$sIdField`) FROM `$sRootTable`");
};
return self::Inc($sRootClass, $oNewObjectCallback);
}
/**
* @return \mysqli
* @throws \ConfigException
* @throws \CoreException
* @throws \MySQLException
*/
private static function InitMySQLSession()
{
$oConfig = utils::GetConfig();
$sDBHost = $oConfig->Get('db_host');
$sDBUser = $oConfig->Get('db_user');
$sDBPwd = $oConfig->Get('db_pwd');
$sDBName = $oConfig->Get('db_name');
$bDBTlsEnabled = $oConfig->Get('db_tls.enabled');
$sDBTlsCA = $oConfig->Get('db_tls.ca');
$hDBLink = CMDBSource::GetMysqliInstance($sDBHost, $sDBUser, $sDBPwd, $sDBName, $bDBTlsEnabled, $sDBTlsCA, false);
if (!$hDBLink)
{
throw new Exception("Could not connect to the DB server (host=$sDBHost, user=$sDBUser): ".mysqli_connect_error().' (mysql errno: '.mysqli_connect_errno().')');
}
return $hDBLink;
}
}
/**
* Persistent classes for a CMDB
*
* @copyright Copyright (C) 2010-2017 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class KeyValueStore extends DBObject
{
public static function Init()
{
$aParams = array(
'category' => '',
'key_type' => 'autoincrement',
'name_attcode' => array('key_name'),
'state_attcode' => '',
'reconc_keys' => array(''),
'db_table' => 'key_value_store',
'db_key_field' => 'id',
'db_finalclass_field' => '',
'indexes' => array (
array (
0 => 'key_name',
1 => 'namespace',
),
),);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("namespace", array("allowed_values"=>null, "sql"=>'namespace', "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array(), "always_load_in_tables"=>false)));
MetaModel::Init_AddAttribute(new AttributeString("key_name", array("allowed_values"=>null, "sql"=>'key_name', "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array(), "always_load_in_tables"=>false)));
MetaModel::Init_AddAttribute(new AttributeString("value", array("allowed_values"=>null, "sql"=>'value', "default_value"=>'0', "is_null_allowed"=>false, "depends_on"=>array(), "always_load_in_tables"=>false)));
MetaModel::Init_SetZListItems('details', array (
0 => 'key_name',
1 => 'value',
2 => 'namespace',
));
MetaModel::Init_SetZListItems('standard_search', array (
0 => 'key_name',
1 => 'value',
2 => 'namespace',
));
MetaModel::Init_SetZListItems('list', array (
0 => 'key_name',
1 => 'value',
2 => 'namespace',
));
;
}
}

View File

@@ -58,8 +58,8 @@ class DateTimeFormat
{
return array(
// Days
'd' => array('regexpr' => '(0[1-9]|[1-2][0-9]|3[0-1])', 'datepicker' => 'dd', 'excel' => 'dd', 'moment' => 'DD'), // Day of the month: 2 digits (with leading zero)
'j' => array('regexpr' => '([1-9]|[1-2][0-9]|3[0-1])', 'datepicker' => 'd', 'excel' => 'd', 'moment' => 'D'), // Day of the month: 1 or 2 digits (without leading zero)
'd' => array('regexpr' => '(0[1-9]|[1-2][0-9]||3[0-1])', 'datepicker' => 'dd', 'excel' => 'dd', 'moment' => 'DD'), // Day of the month: 2 digits (with leading zero)
'j' => array('regexpr' => '([1-9]|[1-2][0-9]||3[0-1])', 'datepicker' => 'd', 'excel' => 'd', 'moment' => 'D'), // Day of the month: 1 or 2 digits (without leading zero)
// Months
'm' => array('regexpr' => '(0[1-9]|1[0-2])', 'datepicker' => 'mm', 'excel' => 'MM', 'moment' => 'MM' ), // Month on 2 digits i.e. 01-12
'n' => array('regexpr' => '([1-9]|1[0-2])', 'datepicker' => 'm', 'excel' => 'm', 'moment' => 'M'), // Month on 1 or 2 digits 1-12
@@ -69,7 +69,7 @@ class DateTimeFormat
// Hours
'H' => array('regexpr' => '([0-1][0-9]|2[0-3])', 'datepicker' => 'HH', 'excel' => 'HH', 'moment' => 'HH'), // Hour 00..23
'h' => array('regexpr' => '(0[1-9]|1[0-2])', 'datepicker' => 'hh', 'excel' => 'hh', 'moment' => 'hh'), // Hour 01..12
'G' => array('regexpr' => '([0-9]|1[0-9]|2[0-3])', 'datepicker' => 'H', 'excel' => 'H', 'moment' => 'H'), // Hour 0..23
'G' => array('regexpr' => '([1-9]|[1[0-9]|2[0-3])', 'datepicker' => 'H', 'excel' => 'H', 'moment' => 'H'), // Hour 0..23
'g' => array('regexpr' => '([1-9]|1[0-2])', 'datepicker' => 'h', 'excel' => 'h', 'moment' => 'h'), // Hour 1..12
'a' => array('regexpr' => '(am|pm)', 'datepicker' => 'tt', 'excel' => 'am/pm', 'moment' => 'a'),
'A' => array('regexpr' => '(AM|PM)', 'datepicker' => 'TT', 'excel' => 'AM/PM', 'moment' => 'A'),

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -89,8 +89,7 @@ class DBObjectSet implements iDBObjectSetIterator
* @api
*
* @param DBSearch $oFilter The search filter defining the objects which are part of the set (multiple columns/objects per row are supported)
* @param array $aOrderBy Array of '[<classalias>.]attcode' => bAscending (true for ASC, false, for DESC)
* Example : array('name' => true, 'id' => false)
* @param array $aOrderBy Array of '[<classalias>.]attcode' => bAscending
* @param array $aArgs Values to substitute for the search/query parameters (if any). Format: param_name => value
* @param array $aExtendedDataSpec
* @param int $iLimitCount Maximum number of rows to load (i.e. equivalent to MySQL's LIMIT start, count)
@@ -218,81 +217,73 @@ class DBObjectSet implements iDBObjectSetIterator
*/
public function OptimizeColumnLoad($aAttToLoad)
{
// Check that the structure is an array of array
if (!is_array($aAttToLoad))
if (is_null($aAttToLoad))
{
$this->m_aAttToLoad = null;
return;
}
foreach ($aAttToLoad as $sAlias => $aAttCodes)
else
{
if (!is_array($aAttCodes))
// Complete the attribute list with the attribute codes
$aAttToLoadWithAttDef = array();
foreach($this->m_oFilter->GetSelectedClasses() as $sClassAlias => $sClass)
{
$this->m_aAttToLoad = null;
return;
}
}
// Complete the attribute list with the attribute codes
$aAttToLoadWithAttDef = array();
foreach($this->m_oFilter->GetSelectedClasses() as $sClassAlias => $sClass)
{
$aAttToLoadWithAttDef[$sClassAlias] = array();
if (array_key_exists($sClassAlias, $aAttToLoad))
{
$aAttList = $aAttToLoad[$sClassAlias];
foreach($aAttList as $sAttToLoad)
$aAttToLoadWithAttDef[$sClassAlias] = array();
if (array_key_exists($sClassAlias, $aAttToLoad))
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad);
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad] = $oAttDef;
if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE))
$aAttList = $aAttToLoad[$sClassAlias];
foreach($aAttList as $sAttToLoad)
{
// Add the external key friendly name anytime
$oFriendlyNameAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad.'_friendlyname');
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad.'_friendlyname'] = $oFriendlyNameAttDef;
if (MetaModel::IsArchivable($oAttDef->GetTargetClass(EXTKEY_ABSOLUTE)))
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad);
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad] = $oAttDef;
if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE))
{
// Add the archive flag if necessary
$oArchiveFlagAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad.'_archive_flag');
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad.'_archive_flag'] = $oArchiveFlagAttDef;
}
// Add the external key friendly name anytime
$oFriendlyNameAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad.'_friendlyname');
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad.'_friendlyname'] = $oFriendlyNameAttDef;
if (MetaModel::IsObsoletable($oAttDef->GetTargetClass(EXTKEY_ABSOLUTE)))
{
// Add the obsolescence flag if necessary
$oObsoleteFlagAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad.'_obsolescence_flag');
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad.'_obsolescence_flag'] = $oObsoleteFlagAttDef;
if (MetaModel::IsArchivable($oAttDef->GetTargetClass(EXTKEY_ABSOLUTE)))
{
// Add the archive flag if necessary
$oArchiveFlagAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad.'_archive_flag');
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad.'_archive_flag'] = $oArchiveFlagAttDef;
}
if (MetaModel::IsObsoletable($oAttDef->GetTargetClass(EXTKEY_ABSOLUTE)))
{
// Add the obsolescence flag if necessary
$oObsoleteFlagAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad.'_obsolescence_flag');
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad.'_obsolescence_flag'] = $oObsoleteFlagAttDef;
}
}
}
}
}
// Add the friendly name anytime
$oFriendlyNameAttDef = MetaModel::GetAttributeDef($sClass, 'friendlyname');
$aAttToLoadWithAttDef[$sClassAlias]['friendlyname'] = $oFriendlyNameAttDef;
// Add the friendly name anytime
$oFriendlyNameAttDef = MetaModel::GetAttributeDef($sClass, 'friendlyname');
$aAttToLoadWithAttDef[$sClassAlias]['friendlyname'] = $oFriendlyNameAttDef;
if (MetaModel::IsArchivable($sClass))
{
// Add the archive flag if necessary
$oArchiveFlagAttDef = MetaModel::GetAttributeDef($sClass, 'archive_flag');
$aAttToLoadWithAttDef[$sClassAlias]['archive_flag'] = $oArchiveFlagAttDef;
if (MetaModel::IsArchivable($sClass))
{
// Add the archive flag if necessary
$oArchiveFlagAttDef = MetaModel::GetAttributeDef($sClass, 'archive_flag');
$aAttToLoadWithAttDef[$sClassAlias]['archive_flag'] = $oArchiveFlagAttDef;
}
if (MetaModel::IsObsoletable($sClass))
{
// Add the obsolescence flag if necessary
$oObsoleteFlagAttDef = MetaModel::GetAttributeDef($sClass, 'obsolescence_flag');
$aAttToLoadWithAttDef[$sClassAlias]['obsolescence_flag'] = $oObsoleteFlagAttDef;
}
// Make sure that the final class is requested anytime, whatever the specification (needed for object construction!)
if (!MetaModel::IsStandaloneClass($sClass) && !array_key_exists('finalclass', $aAttToLoadWithAttDef[$sClassAlias]))
{
$aAttToLoadWithAttDef[$sClassAlias]['finalclass'] = MetaModel::GetAttributeDef($sClass, 'finalclass');
}
}
if (MetaModel::IsObsoletable($sClass))
{
// Add the obsolescence flag if necessary
$oObsoleteFlagAttDef = MetaModel::GetAttributeDef($sClass, 'obsolescence_flag');
$aAttToLoadWithAttDef[$sClassAlias]['obsolescence_flag'] = $oObsoleteFlagAttDef;
}
// Make sure that the final class is requested anytime, whatever the specification (needed for object construction!)
if (!MetaModel::IsStandaloneClass($sClass) && !array_key_exists('finalclass', $aAttToLoadWithAttDef[$sClassAlias]))
{
$aAttToLoadWithAttDef[$sClassAlias]['finalclass'] = MetaModel::GetAttributeDef($sClass, 'finalclass');
}
$this->m_aAttToLoad = $aAttToLoadWithAttDef;
}
$this->m_aAttToLoad = $aAttToLoadWithAttDef;
}
/**
@@ -980,15 +971,7 @@ class DBObjectSet implements iDBObjectSetIterator
}
else
{
try
{
$oRetObj = MetaModel::GetObjectByRow($sClass, $aRow, $sClassAlias, $this->m_aAttToLoad, $this->m_aExtendedDataSpec);
}
catch (CoreException $e)
{
$this->m_iCurrRow++;
$oRetObj = $this->Fetch($sRequestedClassAlias);
}
$oRetObj = MetaModel::GetObjectByRow($sClass, $aRow, $sClassAlias, $this->m_aAttToLoad, $this->m_aExtendedDataSpec);
}
break;
}

View File

@@ -1,39 +1,24 @@
<?php
/**
* Copyright (C) 2013-2019 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
*/
// Copyright (C) 2015-2017 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
$bUseLegacyDBSearch = utils::GetConfig()->Get('use_legacy_dbsearch');
if ($bUseLegacyDBSearch)
{
// excluded from autoload
require_once (APPROOT.'core/legacy/querybuilderexpressionslegacy.class.inc.php');
require_once (APPROOT.'core/legacy/querybuildercontextlegacy.class.inc.php');
require_once(APPROOT.'core/legacy/dbobjectsearchlegacy.class.php');
}
else
{
// excluded from autoload
require_once (APPROOT.'core/querybuilderexpressions.class.inc.php');
require_once (APPROOT.'core/querybuildercontext.class.inc.php');
require_once(APPROOT.'core/dbobjectsearch.class.php');
}
require_once('dbobjectsearch.class.php');
require_once('dbunionsearch.class.php');
/**
* An object search
@@ -272,10 +257,6 @@ abstract class DBSearch
*/
abstract public function RenameAlias($sOldName, $sNewName);
abstract public function RenameAliasesInNameSpace($aClassAliases, $aAliasTranslation = array());
abstract public function TranslateConditions($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true);
/**
* @internal
* @return mixed
@@ -438,27 +419,11 @@ abstract class DBSearch
*/
abstract public function AddCondition_ReferencedBy(DBObjectSearch $oFilter, $sForeignExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS, &$aRealiasingMap = null);
/**
* Filter this search with another search.
* Initial search is unmodified.
* The difference with Intersect, is that an alias can be provided,
* the filtered class does not need to be the first joined class,
* it can be any class of the search.
*
* @param string $sClassAlias class being filtered
* @param DBSearch $oFilter Filter to apply
*
* @return DBSearch The filtered search
* @throws \CoreException
*/
abstract public function Filter($sClassAlias, DBSearch $oFilter);
/**
/**
* Filter the result
*
* The filter is performed by returning only the values in common with the given $oFilter
* The impact on the resulting query performance/viability can be significant.
* Only the first joined class can be filtered.
*
* @internal
*
@@ -477,7 +442,7 @@ abstract class DBSearch
*
* @param DBSearch $oFilter The join is performed against $oFilter selected class
* @param integer $iDirection can be either DBSearch::JOIN_POINTING_TO or DBSearch::JOIN_REFERENCED_BY
* @param string $sExtKeyAttCode The join is performed against $sExtKeyAttCode whether it is compared against the current DBSearch or $oFilter depend of $iDirection
* @param string $sExtKeyAttCode The join is performed against $sExtKeyAttCode wetheir it is compared aginst the current DBSearch or $oFilter depend of $iDirection
* @param integer $iOperatorCode See DBSearch::AddCondition_PointingTo()
* @param array|null $aRealiasingMap Map of aliases from the attached query, that could have been renamed by the optimization process
*
@@ -704,15 +669,6 @@ abstract class DBSearch
*/
abstract public function ToOQL($bDevelopParams = false, $aContextParams = null, $bWithAllowAllFlag = false);
/**
* Export the DBSearch as a structure (array of arrays...) suitable for a conversion to JSON
*
* @internal
*
* @return mixed[string]
*/
abstract public function ToJSON();
static protected $m_aOQLQueries = array();
/**
@@ -748,13 +704,12 @@ abstract class DBSearch
*
* @param string $sQuery The OQL to convert to a DBSearch
* @param mixed[string] $aParams array of <mixed> params index by <string> name
* @param ModelReflection|null $oMetaModel The MetaModel to use when checking the consistency of the OQL
*
* @return DBObjectSearch|DBUnionSearch
*
* @throws OQLException
*/
static public function FromOQL($sQuery, $aParams = null, ModelReflection $oMetaModel=null)
static public function FromOQL($sQuery, $aParams = null)
{
if (empty($sQuery))
{
@@ -796,10 +751,7 @@ abstract class DBSearch
$oOql = new OqlInterpreter($sQuery);
$oOqlQuery = $oOql->ParseQuery();
if ($oMetaModel === null)
{
$oMetaModel = new ModelReflectionRuntime();
}
$oMetaModel = new ModelReflectionRuntime();
$oOqlQuery->Check($oMetaModel, $sQuery); // Exceptions thrown in case of issue
$oResultFilter = $oOqlQuery->ToDBSearch($sQuery);
@@ -979,15 +931,13 @@ abstract class DBSearch
$bBeautifulSQL = self::$m_bTraceQueries || self::$m_bDebugQuery || self::$m_bIndentQueries;
$sRes = $oSQLQuery->RenderGroupBy($aScalarArgs, $bBeautifulSQL, $aOrderBy, $iLimitCount, $iLimitStart);
}
// Catch CoreException to add info before throwing again
// Other exceptions will be thrown directly
catch (CoreException $e)
catch (Exception $e)
{
// Add some information...
$e->addInfo('OQL', $this->ToOQL());
throw $e;
}
$this->AddQueryTraceGroupBy($aArgs, $aGroupByExpr, $bExcludeNullValues, $aSelectExpr, $aOrderBy, $iLimitCount, $iLimitStart, $sRes);
$this->AddQueryTraceGroupBy($aArgs, $aGroupByExpr, $sRes);
return $sRes;
}
@@ -997,7 +947,7 @@ abstract class DBSearch
*
* @internal
*
* @param array $aOrderBy Array of '[<classalias>.]attcode' => bAscending
* @param array|hash $aOrderBy Array of '[<classalias>.]attcode' => bAscending
* @param array $aArgs
* @param null $aAttToLoad
* @param null $aExtendedDataSpec
@@ -1074,8 +1024,8 @@ abstract class DBSearch
}
try
{
// $bBeautifulSQL = self::$m_bTraceQueries || self::$m_bDebugQuery || self::$m_bIndentQueries;
$sRes = $oSQLQuery->RenderSelect($aOrderSpec, $aScalarArgs, $iLimitCount, $iLimitStart, $bGetCount, true);
$bBeautifulSQL = self::$m_bTraceQueries || self::$m_bDebugQuery || self::$m_bIndentQueries;
$sRes = $oSQLQuery->RenderSelect($aOrderSpec, $aScalarArgs, $iLimitCount, $iLimitStart, $bGetCount, $bBeautifulSQL);
if ($sClassAlias == '_itop_')
{
IssueLog::Info('SQL Query (_itop_): '.$sRes);
@@ -1087,43 +1037,10 @@ abstract class DBSearch
$e->addInfo('OQL', $this->ToOQL());
throw $e;
}
$this->AddQueryTraceSelect($oSQLQuery->GetSourceOQL(), $aOrderBy, $aScalarArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $sRes);
$this->AddQueryTraceSelect($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $sRes);
return $sRes;
}
/**
* @param bool $bMustHaveOneResultMax if true will throw a CoreOqlMultipleResultsFound if multiple results
* @param array $aOrderBy
* @param array $aSearchParams
*
* @return null|\DBObject query result
* @throws \CoreOqlMultipleResultsForbiddenException if multiple results found and parameter enforce the check
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
*/
public function GetFirstResult($bMustHaveOneResultMax = true, $aOrderBy = array(), $aSearchParams = array())
{
$oSet = new DBObjectSet($this, array(), $aSearchParams, null, 2);
$oFirstResult = $oSet->Fetch();
if ($oFirstResult === null) // useless but here for readability ;)
{
return null;
}
if ($bMustHaveOneResultMax)
{
$oSecondResult = $oSet->Fetch();
if ($oSecondResult !== null)
{
throw new CoreOqlMultipleResultsForbiddenException(
'Search returned multiple results, this is forbidden. Query was: '.$this->ToOQL());
}
}
return $oFirstResult;
}
/**
* @internal
* @return mixed
@@ -1136,42 +1053,38 @@ abstract class DBSearch
*/
protected abstract function SetDataFiltered();
/**
* @param $aOrderBy
* @param $aArgs
* @param $aAttToLoad
* @param $aExtendedDataSpec
* @param $iLimitCount
* @param $iLimitStart
* @param $bGetCount
* @param null $aGroupByExpr
* @param null $aSelectExpr
*
* @return SQLObjectQuery
* @throws \CoreException
* @internal
*
*/
/**
* @internal
*
* @param $aOrderBy
* @param $aArgs
* @param $aAttToLoad
* @param $aExtendedDataSpec
* @param $iLimitCount
* @param $iLimitStart
* @param $bGetCount
* @param null $aGroupByExpr
* @param null $aSelectExpr
*
* @return mixed
*/
protected function GetSQLQuery($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $aGroupByExpr = null, $aSelectExpr = null)
{
$oSearch = $this;
if (!$this->IsAllDataAllowed() && !$this->IsDataFiltered())
{
foreach ($this->GetSelectedClasses() as $sClassAlias => $sClass)
$oVisibleObjects = UserRights::GetSelectFilter($this->GetClass(), $this->GetModifierProperties('UserRightsGetSelectFilter'));
if ($oVisibleObjects === false)
{
$oVisibleObjects = UserRights::GetSelectFilter($sClass, $this->GetModifierProperties('UserRightsGetSelectFilter'));
if ($oVisibleObjects === false)
{
// Make sure this is a valid search object, saying NO for all
$oVisibleObjects = DBObjectSearch::FromEmptySet($sClass);
}
if (is_object($oVisibleObjects))
{
$oVisibleObjects->AllowAllData();
$oSearch = $this->Filter($sClassAlias, $oVisibleObjects);
/** @var DBSearch $oSearch */
$oSearch->SetDataFiltered();
}
// Make sure this is a valid search object, saying NO for all
$oVisibleObjects = DBObjectSearch::FromEmptySet($this->GetClass());
}
if (is_object($oVisibleObjects))
{
$oVisibleObjects->AllowAllData();
$oSearch = $this->Intersect($oVisibleObjects);
/** @var DBSearch $oSearch */
$oSearch->SetDataFiltered();
}
}
$oSQLQuery = $oSearch->GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr, null, $aSelectExpr);
@@ -1313,112 +1226,61 @@ abstract class DBSearch
self::$m_bOptimizeQueries = $bEnabled;
}
/**
* @param $sOql
* @param $aOrderBy
* @param $aArgs
* @param $aAttToLoad
* @param $aExtendedDataSpec
* @param $iLimitCount
* @param $iLimitStart
* @param $bGetCount
* @param $sSql
*
* @throws \ConfigException
* @throws \CoreException
* @internal
*
*/
protected function AddQueryTraceSelect($sOql, $aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $sSql)
/**
* @internal
*
* @param $aOrderBy
* @param $aArgs
* @param $aAttToLoad
* @param $aExtendedDataSpec
* @param $iLimitCount
* @param $iLimitStart
* @param $bGetCount
* @param $sSql
*
* @throws MySQLException
*/
protected function AddQueryTraceSelect($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $sSql)
{
if (self::$m_bTraceQueries)
{
$aQueryData = array(
'type' => 'select',
'filter' => $this,
'order_by' => $aOrderBy,
'args' => $aArgs,
'att_to_load' => $aAttToLoad,
'extended_data_spec' => $aExtendedDataSpec,
'limit_count' => $iLimitCount,
'limit_start' => $iLimitStart,
'is_count' => $bGetCount
);
DBSearch::EnableQueryTrace(false);
$aQueryData['oql'] = $this->ToOQL(true, $aArgs);
DBSearch::EnableQueryTrace(true);
if (!empty($aAttToLoad))
{
$aAttToLoadNames = array();
foreach ($aAttToLoad as $sClass => $aAttributes)
{
$aAttToLoadNames[$sClass] = array();
foreach ($aAttributes as $sAttCode => $oAttDef)
{
$aAttToLoadNames[$sClass][] = $sAttCode;
}
}
}
else
{
$aAttToLoadNames = null;
}
$aQueryData['att_to_load'] = $aAttToLoadNames;
$hLogFile = @fopen(APPROOT.'log/oql_records.txt', 'a');
if ($hLogFile !== false)
{
flock($hLogFile,LOCK_EX);
fwrite($hLogFile,serialize($aQueryData)."\n");
fflush($hLogFile);
flock($hLogFile,LOCK_UN);
fclose($hLogFile);
}
$sOql = $this->ToOQL(true, $aArgs);
self::AddQueryTrace($aQueryData, $sOql, $sSql);
}
}
/**
* @param $aArgs
* @param $aGroupByExpr
* @param $bExcludeNullValues
* @param $aSelectExpr
* @param $aOrderBy
* @param $iLimitCount
* @param $iLimitStart
* @param $sSql
*
* @throws \ConfigException
* @throws \CoreException
* @throws \MySQLException
* @internal
*
*/
protected function AddQueryTraceGroupBy($aArgs, $aGroupByExpr, $bExcludeNullValues, $aSelectExpr, $aOrderBy, $iLimitCount, $iLimitStart, $sSql)
/**
* @internal
*
* @param $aArgs
* @param $aGroupByExpr
* @param $sSql
*
* @throws MySQLException
*/
protected function AddQueryTraceGroupBy($aArgs, $aGroupByExpr, $sSql)
{
if (self::$m_bTraceQueries)
{
$aQueryData = array(
'type' => 'group_by',
'order_by' => $aOrderBy,
'group_by_expr' => $aGroupByExpr,
'exclude_null_values' => $bExcludeNullValues,
'select_expr' => $aSelectExpr,
'limit_count' => $iLimitCount,
'limit_start' => $iLimitStart,
'filter' => $this,
'args' => $aArgs,
'group_by_expr' => $aGroupByExpr
);
$aQueryData['oql'] = $this->ToOQL(true, $aArgs);
$aQueryData['group_by_expr'] = Expression::ConvertArrayToOQL($aQueryData['group_by_expr'], $aArgs);
$aQueryData['select_expr'] = Expression::ConvertArrayToOQL($aQueryData['select_expr'], $aArgs);
$hLogFile = @fopen(APPROOT.'log/oql_group_by_records.txt', 'a');
if ($hLogFile !== false)
{
flock($hLogFile,LOCK_EX);
fwrite($hLogFile,serialize($aQueryData)."\n");
fflush($hLogFile);
flock($hLogFile,LOCK_UN);
fclose($hLogFile);
}
$sOql = $this->ToOQL(true, $aArgs);
self::AddQueryTrace($aQueryData, $sOql, $sSql);
}
}
@@ -1562,16 +1424,15 @@ abstract class DBSearch
}
/**
* Updates archive_flag and archive_date fields in the whole class hierarchy
*
* @see \DBObject::DBWriteArchiveFlag()
*
* @param boolean $bArchive
*
* @throws Exception
* Experimental!
* @todo implement the change tracking
*
* @internal
*
* @param $bArchive
* @throws Exception
*/
public function DBBulkWriteArchiveFlag($bArchive)
function DBBulkWriteArchiveFlag($bArchive)
{
$sClass = $this->GetClass();
if (!MetaModel::IsArchivable($sClass))

View File

@@ -258,24 +258,6 @@ class DBUnionSearch extends DBSearch
return $bRet;
}
public function RenameAliasesInNameSpace($aClassAliases, $aAliasTranslation = array())
{
foreach ($this->aSearches as $oSearch)
{
$oSearch->RenameAliasesInNameSpace($aClassAliases, $aAliasTranslation);
}
}
public function TranslateConditions($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
{
foreach ($this->aSearches as $oSearch)
{
$oSearch->TranslateConditions($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
}
}
public function IsAny()
{
$bIsAny = true;
@@ -401,16 +383,6 @@ class DBUnionSearch extends DBSearch
}
}
public function Filter($sClassAlias, DBSearch $oFilter)
{
$aSearches = array();
foreach ($this->aSearches as $oSearch)
{
$aSearches[] = $oSearch->Filter($sClassAlias, $oFilter);
}
return new DBUnionSearch($aSearches);
}
public function Intersect(DBSearch $oFilter)
{
$aSearches = array();
@@ -481,25 +453,10 @@ class DBUnionSearch extends DBSearch
return $sRet;
}
/**
* {@inheritDoc}
* @see DBSearch::ToJSON()
*/
public function ToJSON()
{
$sRet = array('unions' => array());
foreach ($this->aSearches as $oSearch)
{
$sRet['unions'][] = $oSearch->ToJSON();
}
return $sRet;
}
/**
* Returns a new DBUnionSearch object where duplicates queries have been removed based on their OQLs
*
*
* @return \DBUnionSearch
* @throws \CoreException
*/
public function RemoveDuplicateQueries()
{
@@ -541,7 +498,7 @@ class DBUnionSearch extends DBSearch
{
if (count($this->aSearches) == 1)
{
return $this->aSearches[0]->GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr, $aSelectedClasses, $aSelectExpr);
return $this->aSearches[0]->GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr, $aSelectExpr);
}
$aSQLQueries = array();
@@ -694,8 +651,6 @@ class DBUnionSearch extends DBSearch
}
}
public function AddConditionForInOperatorUsingParam($sFilterCode, $aValues, $bPositiveMatch = true)
{
$sInParamName = $this->GenerateUniqueParamName();

View File

@@ -192,11 +192,7 @@ class Dict
/**
* Formats a localized string with numbered placeholders (%1$s...) for the additional arguments
* See vsprintf for more information about the syntax of the placeholders
*
* @see \TemplateString to use placeholders
*
* @param string $sFormatCode
*
* @return string
*/
public static function Format($sFormatCode /*, ... arguments ....*/)

View File

@@ -111,7 +111,7 @@ class DisplayableNode extends GraphNode
return $aNode;
}
public function RenderAsPDF(iTopPDF $oPdf, DisplayableGraph $oGraph, $fScale, $aContextDefs)
public function RenderAsPDF(TCPDF $oPdf, DisplayableGraph $oGraph, $fScale, $aContextDefs)
{
$Alpha = 1.0;
$oPdf->SetFillColor(200, 200, 200);
@@ -161,8 +161,8 @@ class DisplayableNode extends GraphNode
$idx++;
}
}
$oPdf->SetFontParams('', 24 * $fScale, '', true);
$oPdf->SetFont('dejavusans', '', 24 * $fScale, '', true);
$width = $oPdf->GetStringWidth($this->GetProperty('label'));
$height = $oPdf->GetStringHeight(1000, $this->GetProperty('label'));
$oPdf->setAlpha(0.6 * $Alpha);
@@ -265,7 +265,7 @@ class DisplayableNode extends GraphNode
/**
* Retrieves the list of neighbour nodes, in the given direction: 'up' or 'down'
* @param bool $bDirectionDown
* @return mixed|NULL
* @return multitype:NULL
*/
protected function GetNextNodes($bDirectionDown = true)
{
@@ -532,7 +532,7 @@ class DisplayableRedundancyNode extends DisplayableNode
return $aNode;
}
public function RenderAsPDF(iTopPDF $oPdf, DisplayableGraph $oGraph, $fScale, $aContextDefs)
public function RenderAsPDF(TCPDF $oPdf, DisplayableGraph $oGraph, $fScale, $aContextDefs)
{
$oPdf->SetAlpha(1);
if($this->GetProperty('is_reached_count') > $this->GetProperty('threshold'))
@@ -547,9 +547,9 @@ class DisplayableRedundancyNode extends DisplayableNode
$oPdf->Circle($this->x*$fScale, $this->y*$fScale, 16*$fScale, 0, 360, 'DF');
$oPdf->SetTextColor(255, 255, 255);
$oPdf->SetFontParams('', 28 * $fScale, '', true);
$oPdf->SetFont('dejavusans', '', 28 * $fScale, '', true);
$sLabel = (string)$this->GetProperty('label');
$width = $oPdf->GetStringWidth($sLabel, iTopPDF::GetPdfFont(), 'B', 24 * $fScale);
$width = $oPdf->GetStringWidth($sLabel, 'dejavusans', 'B', 24*$fScale);
$height = $oPdf->GetStringHeight(1000, $sLabel);
$xPos = (float)$this->x*$fScale - $width/2;
$yPos = (float)$this->y*$fScale - $height/2;
@@ -764,7 +764,7 @@ class DisplayableGroupNode extends DisplayableNode
return $aNode;
}
public function RenderAsPDF(iTopPDF $oPdf, DisplayableGraph $oGraph, $fScale, $aContextDefs)
public function RenderAsPDF(TCPDF $oPdf, DisplayableGraph $oGraph, $fScale, $aContextDefs)
{
$bReached = $this->GetProperty('is_reached');
$oPdf->SetFillColor(255, 255, 255);
@@ -794,7 +794,7 @@ class DisplayableGroupNode extends DisplayableNode
$oPdf->Image($sIconPath, ($this->x - 17)*$fScale, ($this->y - 17)*$fScale, 16*$fScale, 16*$fScale);
$oPdf->Image($sIconPath, ($this->x + 1)*$fScale, ($this->y - 17)*$fScale, 16*$fScale, 16*$fScale);
$oPdf->Image($sIconPath, ($this->x -8)*$fScale, ($this->y +1)*$fScale, 16*$fScale, 16*$fScale);
$oPdf->SetFontParams('', 24 * $fScale, '', true);
$oPdf->SetFont('dejavusans', '', 24 * $fScale, '', true);
$width = $oPdf->GetStringWidth($this->GetProperty('label'));
$oPdf->SetTextColor(0, 0, 0);
$oPdf->Text($this->x*$fScale - $width/2, ($this->y + 25)*$fScale, $this->GetProperty('label'));
@@ -1285,7 +1285,7 @@ class DisplayableGraph extends SimpleGraph
* @param hash $aContextDefs
* @return hash An array ('xmin' => , 'xmax' => ,'ymin' => , 'ymax' => ) of the remaining available area to paint the graph
*/
protected function RenderKey(iTopPDF $oPdf, $sComments, $xMin, $yMin, $xMax, $yMax, $aContextDefs)
protected function RenderKey(TCPDF $oPdf, $sComments, $xMin, $yMin, $xMax, $yMax, $aContextDefs)
{
$fFontSize = 7; // in mm
$fIconSize = 6; // in mm
@@ -1296,7 +1296,7 @@ class DisplayableGraph extends SimpleGraph
$aIcons = array();
$aContexts = array();
$aContextIcons = array();
$oPdf->SetFontParams('', $fFontSize, '', true);
$oPdf->SetFont('dejavusans', '', $fFontSize, '', true);
foreach($oIterator as $sId => $oNode)
{
if ($sClass = $oNode->GetObjectClass())
@@ -1418,24 +1418,16 @@ class DisplayableGraph extends SimpleGraph
}
return $aContextDefs;
}
/**
* Display the graph inside the given page, with the "filter" drawer above it
*
* @param WebPage $oP
* @param array $aResults
* @param hash $aResults
* @param string $sRelation
* @param ApplicationContext $oAppContext
* @param array $aExcludedObjects
* @param string $sObjClass
* @param int $iObjKey
* @param string $sContextKey
* @param array $aContextParams
*
* @throws \CoreException
* @throws \DictExceptionMissingString
*/
function Display(WebPage $oP, $aResults, $sRelation, ApplicationContext $oAppContext, $aExcludedObjects, $sObjClass, $iObjKey, $sContextKey, $aContextParams = array())
function Display(WebPage $oP, $aResults, $sRelation, ApplicationContext $oAppContext, $aExcludedObjects = array(), $sObjClass = null, $iObjKey = null, $sContextKey, $aContextParams = array())
{
$aContextDefs = static::GetContextDefinitions($sContextKey, true, $aContextParams);
$aExcludedByClass = array();
@@ -1454,7 +1446,7 @@ class DisplayableGraph extends SimpleGraph
<<<EOF
<div id="ds_flash" class="search_box">
<form id="dh_flash" class="search_form_handler closed">
<h2 class="sf_title"><span class="sft_long">$sSftShort</span><span class="sft_short">$sSftShort</span><span class="sft_toggler fas fa-caret-down pull-right" title="$sSearchToggle"></span></h2>
<h2 class="sf_title"><span class="sft_long">$sSftShort</span><span class="sft_short">$sSftShort</span><span class="sft_toggler fa fa-caret-down pull-right" title="$sSearchToggle"></span></h2>
<div id="dh_flash_criterion_outer" class="sf_criterion_area"><div class="sf_criterion_row">
EOF
);
@@ -1619,4 +1611,4 @@ EOF
);
}
}
}

View File

@@ -24,6 +24,8 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/lib/swiftmailer/lib/swift_required.php');
Swift_Preferences::getInstance()->setCharset('UTF-8');
@@ -331,6 +333,7 @@ class EMail
{
if (($sMimeType === 'text/html') && ($sCustomStyles !== null))
{
require_once(APPROOT.'lib/emogrifier/Classes/Emogrifier.php');
$emogrifier = new \Pelago\Emogrifier($sBody, $sCustomStyles);
$sBody = $emogrifier->emogrify(); // Adds html/body tags if not already present
}

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