Compare commits

..

23 Commits

Author SHA1 Message Date
Denis Flaven
d40c85a64b (retrofit from trunk) Security: prevent grouping on password fields since it may lead to disclosure of the encrypted version of the password.
SVN:2.1.1[4246]
2016-06-22 14:00:37 +00:00
Denis Flaven
bfed914893 (retrofit from trunk) Properly sanitize the "switch_env" parameter and take it into account only if it contains a valid value.
SVN:2.1.1[4240]
2016-06-22 12:12:04 +00:00
Denis Flaven
17e49dcc55 (retrofit from trunk) Optimization/bug (!): Never use the whole object as a placeholder in ApplyParams !!
SVN:2.1.1[3933]
2016-02-29 16:26:18 +00:00
Denis Flaven
6ceab2ab5e Use one-way encryption for storing the token used for the "Forgotten password" feature.
SVN:2.1.1[3922]
2016-02-19 18:20:28 +00:00
Denis Flaven
b621e746d9 (retrofit from trunk) #1202: Fix for a security vulnerability in the Configuration Editor.
SVN:2.1.1[3905]
2016-02-11 10:30:19 +00:00
Denis Flaven
41345e6636 #1150: Spurious message "A restore is running..." - FIXED !
SVN:2.1.1[3866]
2016-01-20 16:06:05 +00:00
Denis Flaven
7c3a3820b7 Support of derived classes in "add_remove" edition mode for AttributeLinkSet fields (the search form was not refreshing / loading properly when toggling the class to search for).
SVN:2.1.1[3824]
2015-11-20 14:26:05 +00:00
Denis Flaven
b4b25b3c5b Make ReloadSearchForm work properly when the "submit" event handler is declared either with or without a "namespace" portion (e.g. 'submit.itop' vs 'submit') - retrofit from trunk
SVN:2.1.1[3818]
2015-11-09 10:50:38 +00:00
Denis Flaven
f45b9921a6 Retrofit of file based "transactions" as an alternative to session based ones.
SVN:2.1.1[3670]
2015-08-05 14:18:13 +00:00
Denis Flaven
fd21ae262b Fixed a potential XSS vulnerability.
SVN:2.1.1[3663]
2015-07-30 09:07:47 +00:00
Denis Flaven
0d14a20e1b Bug fix: typo causing the generation of invalid SQL queries (in some rare cases). - fix for the 2.1.1 branch.
SVN:2.1.1[3655]
2015-07-28 12:32:22 +00:00
Denis Flaven
ad36b978c5 Better error reporting (thanks to Stefan Goethals for suggesting it).
SVN:2.1.1[3625]
2015-07-06 17:08:34 +00:00
Denis Flaven
e3f550fb39 Bug fix: don't accept attachments (like images) via Chrome's copy/paste since it may duplicate the text content of a normal copy/paste and moreover causes troubles because there is no file name associated with the pasted content.
SVN:2.1.1[3623]
2015-07-06 14:37:42 +00:00
Denis Flaven
96e886199f #1107: Make sure that all settings are preserved upon update.
SVN:2.1.1[3615]
2015-07-01 08:45:05 +00:00
Denis Flaven
ff4ba2ddfe Bug fix: make Excel export work on results of the global search.
SVN:2.1.1[3605]
2015-06-22 10:12:03 +00:00
Denis Flaven
a4091ea771 Bug fix: make Excel export work on results of the global search.
SVN:2.1.1[3604]
2015-06-22 10:05:15 +00:00
Denis Flaven
c33bbd853d Added an alternate implementation for storing "transaction" identifiers on disk instead of inside the $_SESSION variable.
SVN:2.1.1[3600]
2015-06-20 13:41:13 +00:00
Denis Flaven
3345b07cc0 Mutex instrumentation for troubleshooting...
SVN:2.1.1[3597]
2015-06-19 14:49:15 +00:00
Romain Quetiez
5dd7141d54 ormStopWatch::GetElapsedTime not working in case of queries containing :this-> parameters (the prototype of GetElapsedTime has changed and is NOT compatible with the previous one) -reintegrated from trunk
SVN:2.1.1[3566]
2015-04-27 09:33:26 +00:00
Denis Flaven
55da100f9c Bug fix: prevent a crash of the web services when trying to log a non scalar paramater value...
SVN:2.1.1[3550]
2015-04-16 15:35:09 +00:00
Denis Flaven
88665da96e Enhancement: allow the API to create entries with a specified user_login.
SVN:2.1.1[3515]
2015-03-24 17:08:03 +00:00
Denis Flaven
4c25362b84 #594: properly display attachments inside "properties" by closing the span and the fieldset in non-edit mode.
SVN:2.1.1[3511]
2015-03-23 17:55:24 +00:00
Romain Quetiez
e520320736 Creating 2.1.1
SVN:2.1.1[3508]
2015-03-20 10:14:45 +00:00
4787 changed files with 220205 additions and 681114 deletions

View File

@@ -1,103 +0,0 @@
# Phpdoc dokuwiki template
This directory contains a template rendering iTop phpdoc as wiki pages.
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
* `@link` : external url
* if you point to another page of the wiki, please use relative links.
* `@example` : let you provide example of code
* `@param`, `@return`, `@throws`, ...
## Special instructions
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
* `@phpdoc-tuning-exclude-inherited`: once this tag is present on a class, it's inherited methods won't be showed.
### known limitations:
#### `@see` tags must be very specific:
* always prefix class members with `ClassName::`
* for methods always suffix them with `()`,
* do not reference variables since they are not documented. If you have to, always prefix them with `$`
examples:
```
/**
* @see DBObject
* @see DBObject::Get()
* @see DBObject::$foo
*/
```
#### Do not use inline tags, they do not work properly, example:
```
/**
* 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 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:
```
/**
* @example "This is the title of the multiline example"
* $foo = DBObject::Get('foo');
* DBObject::Set('foo', ++$foo);
*/
```
## How content is included into the documentation
**For a class** those requirements have to be respected:
- the file containing the class must be listed in `/phpdoc/files/file[]` of `.doc/phpdoc-objects-manipulation.dist.xml`
- the class **must not** have the tag `@internal`
- the class **must** have at least one of: `@api`, `@api-advanced`, `@overwritable-hook`, `@extension-hook`
Then, **for a method** of an eligible class:
- **public** methods **must** have at least one of: `@api`, `@api-advanced`, `@overwritable-hook`, `@extension-hook`
- **protected** methods **must** have at least one of: `@overwritable-hook`, `@extension-hook`
- **private** methods are **always excluded**
**Class properties** and **constants** are never documented (this is subject to change).
## A note about the rendering engine
:notebook: as spaces are used to mark code, the templates (`.doc/phpdoc-templates/combodo-wiki/*`) have very few indentation, thus they are awful to read (sorry).
## Installation
```
composer require phpdocumentor/phpdocumentor:~2 --dev
```
## Generation
`.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
```
the resulting documentation is written into `data/phpdocumentor/output`
## Dokuwiki requirements
* the template uses the [wrap plugin](https://www.dokuwiki.org/plugin:wrap).
* 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,7 +0,0 @@
#!/bin/sh -x
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

View File

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

View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<phpdoc>
<title><![CDATA[iTop extensions]]></title>
<parser>
<target>../data/phpdocumentor/temp/extensions</target>
</parser>
<transformer>
<target>../data/phpdocumentor/output/extensions</target>
</transformer>
<transformations>
<template name="phpdoc-templates/combodo-wiki"/>
</transformations>
<files>
<file>../application/applicationextension.inc.php</file>
</files>
</phpdoc>

View File

@@ -1,58 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<phpdoc>
<!--
/**
The documentation of this file can be found here : https://docs.phpdoc.org/references/configuration.html
it has to be completed by the CLI parameters documentation which is more comprehensive: https://docs.phpdoc.org/references/commands/project_run.html#usage
usage:
vendor/bin/phpdoc -c phpdoc-objects-manipulation.dist.xml
*/
-->
<title><![CDATA[iTop's objects manipulation API]]></title>
<parser>
<default-package-name>iTopORM</default-package-name>
<target>../data/phpdocumentor/temp/objects-manipulation</target>
<visibility>public,protected</visibility>
<markers>
<!--<item>TODO</item>-->
<!--<item>FIXME</item>-->
</markers>
<extensions>
<extension>php</extension>
</extensions>
</parser>
<transformer>
<target>../data/phpdocumentor/output/objects-manipulation</target>
</transformer>
<transformations>
<template name="phpdoc-templates/combodo-wiki"/>
</transformations>
<!--<logging>-->
<!--<level>warn</level>-->
<!--<paths>-->
<!--&lt;!&ndash;<default>data/phpdocumentor/log/objects-manipulation/{DATE}.log</default>&ndash;&gt;-->
<!--&lt;!&ndash;<errors>data/phpdocumentor/log/objects-manipulation/{DATE}.errors.log</errors>&ndash;&gt;-->
<!--<default>{APP_ROOT}/data/log/{DATE}.log</default>-->
<!--<errors>{APP_ROOT}/data/log/{DATE}.errors.log</errors>-->
<!--</paths>-->
<!--</logging>-->
<files>
<file>../core/dbobject.class.php</file>
<file>../core/dbobjectsearch.class.php</file>
<file>../core/metamodel.class.php</file>
<file>../core/dbobjectset.class.php</file>
<file>../core/dbsearch.class.php</file>
<file>../core/dbunionsearch.class.php</file>
</files>
</phpdoc>

View File

@@ -1,136 +0,0 @@
{% extends 'layout.txt.twig' %}
{% block content %}
<wrap button>[[start|🔙 Back]]</wrap>
{% if node.tags['internal'] is defined %}
====== {{ node.name }} ======
<WRAP alert>This class is "internal", and thus is not documented!</WRAP>
{% elseif node.tags['api'] is not defined and node.tags['api-advanced'] is not defined and node.tags['overwritable-hook'] is not defined and node.tags['extension-hook'] is not defined %}
====== {{ node.name }} ======
<WRAP alert>This class is neither "api", "api-advanced", "overwritable-hook" or "extension-hook", and thus is not documented!</WRAP>
{% else %}
====== {{ node.name }} ======
{% if node.deprecated %}<wrap danger>deprecated</wrap>{% endif %}
{% if node.abstract %}<wrap warning>abstract</wrap>{% endif %}
{% if node.final %}<wrap notice>final</wrap>{% endif %}
{% include 'includes/wrap-tags.txt.twig' with {structure:node, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
{% if node.deprecated %}
=== **<del>Deprecated</del>**===
//{{ node.tags.deprecated[0].description }}//
{% endif %}
== {{ node.summary|replace({"\n":""})|raw }} ==
<html>{{ node.description|markdown|raw }}</html>
{% include 'includes/code-examples.txt.twig' with {structure:node, title_level: '====='} %}
{% set class = node.parent %}
{% block hierarchy_element %}
{% if class and class.name is defined and class.name|trim != '' %}
==== parent ====
{% set child = class %}
{% set class = class.parent %}
{{ block('hierarchy_element') }}
[[{{ child.name }}|{{ child.name }}]]
{% endif %}
{% endblock %}
{% for interface in node.interfaces|sort_asc %}
{% if loop.first %}
==== Implements ====
{% endif %}
{% if loop.length > 1 %} * {% endif %}{{ interface.fullyQualifiedStructuralElementName ?: interface }}
{% endfor %}
{% for trait in node.usedTraits|sort_asc %}
{% if loop.first %}
==== Uses traits ====
{% endif %}
{% if loop.length > 1 %} * {% endif %}{{ trait.fullyQualifiedStructuralElementName ?: trait }}
{% endfor %}
{% include 'includes/see-also.txt.twig' with {structure:node, title_level: '==='} %}
{% include 'includes/tags.txt.twig' with {structure:node, title_level: '=====', blacklist: ['link', 'see', 'abstract', 'example', 'method', 'property', 'property-read', 'property-write', 'package', 'subpackage', 'phpdoc-tuning-exclude-inherited', 'api', 'api-advanced', 'overwritable-hook', 'extension-hook', 'copyright', 'license', 'code-example']} %}
{% set methods = node.inheritedMethods.merge(node.methods.merge(node.magicMethods)) %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api'} %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api-advanced'} %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'overwritable-hook'} %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'extension-hook'} %}
{% include 'includes/code-examples.txt.twig' with {structure:node, title_level: '=====', sub_title_level: '=='} %}
<WRAP clear />
{% for method in methods|sort_asc
if method.visibility == 'public'
and (
method.tags['api'] is defined
or method.tags['api-advanced'] is defined
or method.tags['overwritable-hook'] is defined
or method.tags['extension-hook'] is defined
)
and (
node.tags['phpdoc-tuning-exclude-inherited'] is not defined
or method.parent.name == node.name
)
%}
{%- if loop.first %}
===== Public methods =====
{% endif %}
{{ block('method') }}
{% endfor %}
{% for method in methods|sort_asc if method.visibility == 'protected' and (method.tags['overwritable-hook'] is defined or method.tags['extension-hook'] is defined) %}
{%- if loop.first %}
===== Protected methods =====
{% endif %}
{{ block('method') }}
{% endfor %}
{% set constants = node.inheritedConstants.merge(node.constants) %}
{% if constants|length > 0 %}
===== Constants =====
{% for constant in constants|sort_asc %}
{{ block('constant') }}
{% endfor %}
{% endif %}
{#{% set properties = node.inheritedProperties.merge(node.properties.merge(node.magicProperties)) %}#}
{#{% for property in properties|sort_asc if property.visibility == 'public' %}#}
{#{%- if loop.first %}#}
{#===== Public properties =====#}
{#{% endif %}#}
{#{{ block('property') }}#}
{#{% endfor %}#}
{#{% for property in properties|sort_asc if property.visibility == 'protected' %}#}
{#{%- if loop.first %}#}
{#===== Protected properties =====#}
{#{% endif %}#}
{#{{ block('property') }}#}
{#{% endfor %}#}
{%- endif %} {#{% elseif node.tags['xxx'] is not defined and ... #}
<wrap button>[[start|🔙 Back]]</wrap>
{% endblock %}

View File

@@ -1,31 +0,0 @@
{% block constant %}
<WRAP group box >
<WRAP twothirds column >
==== {{ constant.name }} ====
</WRAP>{# twothirds column#}
<WRAP third column>
{% if constant.deprecated %}<wrap danger>deprecated</wrap> {% endif %}
{% if (node.parent is not null and constant.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
</WRAP>{# third column#}
== {{ constant.summary|replace({"\n":""})|raw }} ==
<html>{{ constant.description|markdown|raw }}</html>
{% if constant.deprecated %}
=== Deprecated ===
{{ constant.tags.deprecated[0].description|raw }}
{% endif %}
{% include 'includes/inherited-from.txt.twig' with {structure:constant} %}
{% include 'includes/see-also.txt.twig' with {structure:constant, title_level: '=='} %}
{% include 'includes/uses.txt.twig' with {structure:constant, title_level: '=='} %}
{% include 'includes/tags.txt.twig' with {structure:constant, title_level: '==', blacklist: ['link', 'see', 'var', 'deprecated', 'uses', 'package', 'subpackage', 'todo', 'code-example']} %}
</WRAP>{# group #}
{% endblock %}

View File

@@ -1,95 +0,0 @@
{% block method %}
<WRAP group box >
<WRAP twothirds column >
==== {{ method.name }} ====
</WRAP>{# twothirds column#}
<WRAP third column >
{% include 'includes/wrap-tags.txt.twig' with {structure:method, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
{% if method.deprecated %}<wrap danger>deprecated</wrap> {% endif %}
{% if (node.parent is not null and method.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
{% if method.abstract %}<wrap warning>abstract</wrap> {% endif %}
{% if method.final %}<wrap notice>final</wrap> {% endif %}
<wrap notice>{{ method.visibility }}</wrap>
{% if method.static %}<wrap warning>static</wrap> {% endif %}
</WRAP>{# third column#}
== {{ method.summary|replace({"\n":""})|raw }} ==
<html>{{ method.description|markdown|raw }}</html>
<code php>{% if method.abstract %}abstract {% endif %}{% if method.final %}final {% endif %}{{ method.visibility }} {% if method.static %}static {% endif %}{{ method.name }}({% for argument in method.arguments %}{{ argument.isVariadic ? '...' }}{{ argument.name }}{{ argument.default ? (' = '~argument.default)|raw }}{% if not loop.last %}, {% endif %}{% endfor %})</code>
<WRAP twothirds column >
=== Parameters ===
{% if method.arguments|length > 0 -%}
^ types ^ name ^ default ^ description ^
{% for argument in method.arguments -%}
| **<nowiki>{{ argument.types|join('|')|raw }}</nowiki>** | {{ argument.name }} {{ argument.isVariadic ? '<small style="color: gray">variadic</small>' }} | <nowiki>{{ argument.default|raw }}</nowiki> | {{ argument.description|trim|replace("\n", ' ')|raw }} |{{ "\r\n" }}
{%- endfor %}
{% else %}
//none//
{% endif %}
{#=== Parameters ===#}
{#{% if method.arguments|length > 0 -%}#}
{#{% for argument in method.arguments -%}#}
{#== {{ argument.name }} ==#}
{#{% set varDesc %}#}
{#<span style="margin:0 10px; 0 20px; font-weight: bold;">{{ argument.types|join('|') }}</span>#}
{#{{ argument.isVariadic ? '<small style="color: gray">variadic</small>' }}#}
{#{{ argument.description|raw }}#}
{#{% endset %}#}
{#<html>{{ varDesc|markdown|raw }}</html>#}
{#{%- endfor %}#}
{#{% else %}#}
{#<wrap tip>This method has no parameter</wrap>#}
{#{% endif %}#}
{% if method.response and method.response.types|join() != 'void' %}
=== Returns ===
<html>{{ ('**' ~ method.response.types|join('|')|trim ~ '** ' ~ method.response.description)|markdown|raw }}</html>
{% endif %}
</WRAP>{# twothirds column#}
<WRAP third column >
{% if method.tags.throws|length > 0 or method.tags.throw|length > 0 %}
=== Throws ===
{% for exception in method.tags.throws -%}
{% if loop.length > 1 %} * {% endif %}''{{ exception.types|join('|')|raw }}'' <nowiki>{{ exception.description|raw }}</nowiki>
{% endfor %}
{% endif %}
{% include 'includes/inherited-from.txt.twig' with {structure:method} %}
{% include 'includes/see-also.txt.twig' with {structure:method, title_level: '==='} %}
{% include 'includes/uses.txt.twig' with {structure:method, title_level: '==='} %}
{% include 'includes/used-by.txt.twig' with {structure:method, title_level: '==='} %}
{% include 'includes/tags-with-description.txt.twig' with {structure:method, title_level: '===', WRAP: 'info', tagsWithDescription: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
{% include 'includes/tags.txt.twig' with {structure:method, title_level: '===', blacklist: ['todo', 'link', 'see', 'abstract', 'example', 'param', 'return', 'access', 'deprecated', 'throws', 'throw', 'uses', 'api', 'api-advanced', 'overwritable-hook', 'extension-hook', 'used-by', 'inheritdoc', 'code-example']} %}
</WRAP>{# third column#}
{% include 'includes/code-examples.txt.twig' with {structure:method, title_level: '==='} %}
</WRAP>{# group #}
{% endblock %}

View File

@@ -1,49 +0,0 @@
{% block property %}
<WRAP group box>
<WRAP twothirds column >
==== ${{ property.name }} ====
</WRAP>{# twothirds column#}
<WRAP third column>
{% if property.deprecated %}<wrap danger>deprecated</wrap> {% endif %}
{% if (node.parent is not null and property.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
</WRAP>{# third column#}
== {{ property.summary|replace({"\n":""})|raw }} ==
<html>{{ property.description|markdown|raw }}</html>
{% if property.var.0.description %}<html>{{ property.var.0.description|markdown|raw }}</html>{% endif %}
{#{% if property.types %}#}
{#== Type ==#}
{#{% for type in property.types %}#}
{#{% if loop.length > 1 %} * {% endif %}{{ type|raw }} : {{ type.description|raw }}#}
{#{% endfor %}#}
{#{{ property.types|join('|')|raw }}#}
{#{% endif %}#}
{% if property.deprecated %}
== Deprecated ==
{{ property.tags.deprecated[0].description }}
{% endif %}
{% include 'includes/inherited-from.txt.twig' with {structure:property} %}
{% include 'includes/see-also.txt.twig' with {structure:property, title_level: '=='} %}
{% include 'includes/uses.txt.twig' with {structure:property, title_level: ''} %}
{% include 'includes/tags.txt.twig' with {structure:property, title_level: '==', blacklist: ['link', 'see', 'access', 'var', 'deprecated', 'uses', 'todo', 'code-example']} %}
<code php>{{ property.visibility }} ${{ property.name }}{% if property.types %} : {{ property.types|join('|')|raw }}{% endif %}</code>
</WRAP>{# group #}
{% endblock %}

View File

@@ -1 +0,0 @@
{{ node.source|raw }}

View File

@@ -1,122 +0,0 @@
{% extends 'layout.txt.twig' %}
{% block javascripts %}
{% endblock %}
{% block content %}
{#<section class="row-fluid">#}
{#<div class="span2 sidebar">#}
{#{% set namespace = project.namespace %}#}
{#{{ block('sidebarNamespaces') }}#}
{#</div>#}
{#</section>#}
{#<section class="row-fluid">#}
====== {{ node.path|split('/')|slice(0,-1)|join('/') }}{{ node.name }} ======
{{ node.summary }}
<html>{{ node.description|markdown|raw }}</html>
{% if node.traits|length > 0 %}
===== Traits =====
{% for trait in node.traits %}
<tr>
<td>{{ trait|raw }}</td>
<td><em>{{ trait.summary }}</em></td>
</tr>
{% endfor %}
{% endif %}
{% if node.interfaces|length > 0 %}
===== Interfaces =====
{% for interface in node.interfaces %}
<tr>
<td>{{ interface|raw }}</td>
<td><em>{{ interface.summary }}</em></td>
</tr>
{% endfor %}
{% endif %}
{% if node.classes|length > 0 %}
===== Classes =====
{% for class in node.classes %}
{{ class|raw }}
<em>{{ class.summary }}</em>
{% endfor %}
{% endif %}
{% if node.package is not empty and node.package != '\\' %}
===== Package =====
{{ node.subpackage ? (node.package ~ '\\' ~ node.subpackage) : node.package }}
{% endif %}
{% for tagName,tags in node.tags if tagName in ['link', 'see'] %}
{% if loop.first %}
===== See also =====
{% endif %}
{% for tag in tags %}
<dd><a href="{{ tag.reference ?: tag.link }}"><div class="namespace-wrapper">{{ tag.description ?: tag.reference }}</div></a></dd>
{% endfor %}
{% endfor %}
<h2>Tags</h2>
<table class="table table-condensed">
{% for tagName,tags in node.tags if tagName not in ['link', 'see', 'package', 'subpackage'] %}
<tr>
<th>
{{ tagName }}
</th>
<td>
{% for tag in tags %}
{{ tag.description|markdown|raw }}
{% endfor %}
</td>
</tr>
{% else %}
<tr><td colspan="2"><em>None found</em></td></tr>
{% endfor %}
</table>
</aside>
</div>
{% if node.constants|length > 0 %}
<div class="row-fluid">
<section class="span8 content file">
<h2>Constants</h2>
</section>
<aside class="span4 detailsbar"></aside>
</div>
{% for constant in node.constants %}
{{ block('constant') }}
{% endfor %}
{% endif %}
{% if node.functions|length > 0 %}
<div class="row-fluid">
<section class="span8 content file">
<h2>Functions</h2>
</section>
<aside class="span4 detailsbar"></aside>
</div>
{% for method in node.functions %}
{{ block('method') }}
{% endfor %}
{% endif %}
</div>
</section>
<div id="source-view" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="source-view-label" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="source-view-label">{{ node.file.name }}</h3>
</div>
<div class="modal-body">
<pre data-src="{{ path('files/' ~ node.path ~ '.txt')|raw }}" class="language-php line-numbers"></pre>
</div>
</div>
{% endblock %}

View File

@@ -1,42 +0,0 @@
{% extends 'layout.html.twig' %}
{% block stylesheets %}
<link href="{{ path('css/jquery.iviewer.css') }}" rel="stylesheet" media="all"/>
<style>
#viewer {
position: relative;
width: 100%;
}
.wrapper {
overflow: hidden;
}
</style>
{% endblock %}
{% block javascripts %}
<script src="{{ path('js/jquery.mousewheel.js') }}" type="text/javascript"></script>
<script src="{{ path('js/jquery.iviewer.js') }}" type="text/javascript"></script>
<script type="text/javascript">
$(window).resize(function(){
$("#viewer").height($(window).height() - 100);
});
$(document).ready(function() {
$("#viewer").iviewer({src: '{{ path('graphs/classes.svg') }}', zoom_animation: false});
$('#viewer img').bind('dragstart', function(event){
event.preventDefault();
});
$(window).resize();
});
</script>
{% endblock %}
{% block content %}
<div class="row-fluid">
<div class="span12">
<div class="wrapper">
<div id="viewer" class="viewer"></div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -1,5 +0,0 @@
# Fixes a vulnerability in CentOS: http://stackoverflow.com/questions/20533279/prevent-php-from-parsing-non-php-files-such-as-somefile-php-txt
<FilesMatch \.php\.txt$>
RemoveHandler .php
ForceType text/plain
</FilesMatch>

View File

@@ -1,34 +0,0 @@
{% if title_level is not defined %}
{%- set title_level = '==' -%}
{% endif %}
{% if sub_title_level is not defined %}
{%- set sub_title_level = title_level|slice(1) -%}
{% endif %}
{% if sub_title_level == '=' %}
{%- set sub_title_level = '' -%}
{% endif %}
{#{% for tagName,tags in structure.tags if tagName in ['code-example'] %}#}
{#{% if loop.first %}#}
{#{{title_level}} Examples {{title_level}}#}
{#{% endif %}#}
{#{% for tag in tags %}#}
{#{%- set descToken = tag.description|split("\n", 2) -%}#}
{#{%- set title = descToken[0] -%}#}
{#{%- set code = descToken[1] -%}#}
{#{{sub_title_level}} {{ title }} {{sub_title_level}}#}
{#<code php>{{ code|raw }}</code>#}
{#{% endfor %}#}
{#{% endfor %}#}
{% for tagName,tags in structure.tags if tagName in ['example'] %}
{% if loop.first %}
{{title_level}} Examples {{title_level}}
{% endif %}
{% for tag in tags %}
{{ sub_title_level }} {{ tag.filePath|escape }}{{ sub_title_level }}
<code php>{{ tag.description|raw }}</code>
{% endfor %}
{% endfor %}

View File

@@ -1,12 +0,0 @@
{% if title_level is not defined %}
{% set title_level='' %}
{% endif %}
{% if (node.parent is null) %}
{{title_level}} File {{ structure.path }} {{title_level}}
{% endif %}
{% if (node.parent is not null and structure.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}
{{title_level}} Inherited from {{title_level}}
[[{{structure.parent}}|{{structure.parent}}]]
{% endif %}

View File

@@ -1,26 +0,0 @@
{% for structure in structures|sort_asc if structure.tags['internal'] is not defined and (structure.tags['api'] is defined or structure.tags['api-advanced'] is defined or structure.tags['overwritable-hook'] is defined or structure.tags['extension-hook'] is defined ) %}
{#{{ structure|raw }}#}
{% set structureName = structure|trim('\\', 'left') %}
<WRAP group box>
<WRAP twothirds column >
==== {{ structureName }} ====
</WRAP>{# twothirds column#}
<WRAP third column>
{% if structure.deprecated %}<wrap danger>deprecated</wrap>{% endif %}
{% if structure.abstract %}<wrap warning>abstract</wrap>{% endif %}
{% if structure.final %}<wrap notice>final</wrap>{% endif %}
{% if (node.parent is not null and structure.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
{% include 'includes/wrap-tags.txt.twig' with {structure:structure, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
</WRAP>{# third column#}
{{ structure.summary|raw }}
[[{{structureName}}|More informations]]
</WRAP>{# group #}
{% endfor %}

View File

@@ -1,26 +0,0 @@
{% if title_level is not defined %}
{%- set title_level='==' -%}
{% endif %}
{% for tagName,tags in structure.tags if tagName in ['link', 'see'] %}
{% if loop.first %}
{{title_level}} See also {{title_level}}
{% endif %}
{% for tag in tags %}
{%- set linkTag = tag.reference|trim('\\', 'left') -%}
{% if not('()' in linkTag or '$' in linkTag or node.name in linkTag or '::' in linkTag ) %}
{%- set linkTag = linkTag|lower -%}
{% elseif node.name~'::' in linkTag %}
{%- set linkTag = linkTag|replace({(node.name~'::'): '#'})|lower -%}
{% elseif '::' in linkTag -%}
{%- set linkTag = linkTag|replace({'::': '#'})|lower -%}
{% else %}
{%- set linkTag = '#' ~ linkTag|lower -%}
{%- endif %}
{% if loop.length > 1 %} * {% endif %}{% if tag.reference is not empty -%}
[[{{linkTag}}|{{ (tag.reference)|trim('\\', 'left') }}]] {% if tag.description|trim is not empty %}: {{ tag.description|trim('\\', 'left') }} {% endif %}
{%- else -%}
{#{{ tag.description|trim('\\', 'left') }}#}
{% endif %}
{% endfor %}
{% endfor %}

View File

@@ -1,56 +0,0 @@
{% if tag is not defined -%}
{# Do not display @api if @api-advanced is also present #}
{%- set tag = "api" -%}
{%- endif %}
{% if hidden_by is not defined -%}
{# Do not display @api if @api-advanced is also present #}
{%- set hidden_by = {"api" : "api-advanced"} -%}
{%- endif %}
{% for method in methods|sort_asc
if (method.visibility == 'public')
and (
method.tags[tag] is defined
and (
hidden_by[tag] is not defined or method.tags[hidden_by[tag]] is not defined
)
)
%}
{%- if loop.first %}
{% if tag == 'api' %}
===== API synthesis =====
<WRAP>
List of the public API methods.
When manipulating {{ node.name }}, You can call those methods:
</WRAP>
{% elseif tag == 'api-advanced' %}
===== Advanced API synthesis =====
<WRAP>
List of advanced API methods
Beware they usage is recommended to advanced users only.
</WRAP>
{% elseif tag == 'overwritable-hook' %}
===== overwritable-hook synthesis =====
<WRAP >When inheriting from {{ node.name }},
you can overwrite those methods in order to add custom logic:
</WRAP>
{% elseif tag == 'extension-hook' %}
===== extension-hook synthesis =====
<WRAP >
When inheriting from {{ node.name }},
you can extend the behaviour of iTop by implementing:
</WRAP>
{% endif %}
{% endif %}
{% set sanitizedMethod = method|trim('\\', 'left')|replace({(node.name~'::'): ''}) %}
{% if '::' in sanitizedMethod -%}
{%- if node.tags['phpdoc-tuning-exclude-inherited'] is not defined %}
* [[{{sanitizedMethod|replace({'::': '#'})|lower}}|↪{{sanitizedMethod}}]] — {{ method.summary|replace({"\n":""})|raw }}
{% endif %}
{%- else %}
* [[#{{sanitizedMethod}}|{{sanitizedMethod}}]] — {{ method.summary|replace({"\n":""})|raw }}
{% endif %}
{% endfor %}

View File

@@ -1,20 +0,0 @@
{% if title_level is not defined %}
{% set title_level = '==' %}
{% endif %}
{%- for tagName,tags in structure.tags if tagName in tagsWithDescription -%}
{%- for tag in tags -%}
{%- if tag.description is not empty -%}
{%- if WRAP is defined -%}
<WRAP {{WRAP}}>
{%- endif -%}
{{title_level}} {{ tagName }} {{title_level}}
{{ tag.description|escape }}
{%- if WRAP is defined -%}
</WRAP>
{%- endif -%}
{%- endif -%}
{%- endfor -%}
{%- endfor -%}

View File

@@ -1,22 +0,0 @@
{% if title_level is not defined %}
{% set title_level='=====' %}
{% endif %}
{% if blacklist is not defined %}
{% set blacklist =['link', 'see', 'abstract', 'example', 'method', 'property', 'property-read', 'property-write', 'package', 'subpackage', 'api', 'api-advanced', 'todo', 'code-example'] %}
{% endif %}
{% if hidden_by is not defined -%}
{# Do not display @api if @api-advanced is also present #}
{%- set hidden_by = {"api" : "api-advanced"} -%}
{%- endif %}
{#^ {% for tagName,tags in structure.tags if tagName not in blacklist -%}#}
{#{{ tagName }} ^#}
{#{%- endfor %}#}
{% for tagName,tags in structure.tags if tagName not in blacklist and (hidden_by[tagName] is not defined or structure.tags[hidden_by[tagName]] is not defined) %}
{%- if loop.first %}
{{title_level}} Tags {{title_level}}
{% endif %}
^ {{ tagName }} | {% for tag in tags %}{{ tag.version ? tag.version ~ ' ' : '' }}{{ tag.description}}{% endfor %} |
{% endfor %}

View File

@@ -1,24 +0,0 @@
{% if title_level is not defined %}
{% set title_level='' %}
{% endif %}
{% for tagName,tags in structure.tags if tagName in ['used-by'] %}
{% if loop.first %}
{{title_level}} Used by {{title_level}}
{% endif %}
{% for tag in tags %}
{% if loop.length > 1 %} * {% endif %}{{ tag.reference ?: tag.link }} : {{ tag.description ?: tag.reference }}
{% endfor %}
{% endfor %}
{#{% for tagName,tags in method.tags if tagName in ['uses'] %}#}
{#{% if loop.first %}#}
{#<dt>Uses</dt>#}
{#{% endif %}#}
{#{% for tag in tags %}#}
{#<dd>{{ tag.reference|raw }}</dd>#}
{#{% endfor %}#}
{#{% endfor %}#}

View File

@@ -1,24 +0,0 @@
{% if title_level is not defined %}
{% set title_level='' %}
{% endif %}
{% for tagName,tags in structure.tags if tagName in ['uses'] %}
{% if loop.first %}
{{title_level}} Uses {{title_level}}
{% endif %}
{% for tag in tags %}
{% if loop.length > 1 %} * {% endif %}{{ tag.reference ?: tag.link }} : {{ tag.description ?: tag.reference }}
{% endfor %}
{% endfor %}
{#{% for tagName,tags in method.tags if tagName in ['uses'] %}#}
{#{% if loop.first %}#}
{#<dt>Uses</dt>#}
{#{% endif %}#}
{#{% for tag in tags %}#}
{#<dd>{{ tag.reference|raw }}</dd>#}
{#{% endfor %}#}
{#{% endfor %}#}

View File

@@ -1,11 +0,0 @@
{% if wrap is not defined -%}
{% set wrap = 'notice' %}
{%- endif -%}
{% if hidden_by is not defined -%}
{# Do not display @api if @api-advanced is also present #}
{%- set hidden_by = {"api" : "api-advanced"} -%}
{%- endif %}
{%- for tagName,tags in structure.tags if tagName in wrapTags and (hidden_by[tagName] is not defined or structure.tags[hidden_by[tagName]] is not defined) %}
<wrap {{wrap}}>{{tagName}}</wrap>
{% endfor %}

View File

@@ -1,121 +0,0 @@
{% extends 'layout.txt.twig' %}
{% block content %}
<wrap button>[[start|🔙 Back]]</wrap>
{% if node.tags['internal'] is defined %}
====== {{ node.name }} ======
<WRAP alert>This interface is "internal", and thus is not documented!</WRAP>
{% elseif node.tags['api'] is not defined and node.tags['api-advanced'] is not defined and node.tags['overwritable-hook'] is not defined and node.tags['extension-hook'] is not defined %}
====== {{ node.name }} ======
<WRAP alert>This interface is neither "api", "overwritable-hook" or "extension-hook", and thus is not documented!</WRAP>
{% else %}
====== {{ node.name }} ======
{% if node.deprecated %}<wrap danger>deprecated</wrap>{% endif %}
{% if node.abstract %}<wrap warning>abstract</wrap>{% endif %}
{% if node.final %}<wrap notice>final</wrap>{% endif %}
{% include 'includes/wrap-tags.txt.twig' with {structure:node, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
{% if node.deprecated %}
=== **<del>Deprecated</del>**===
//{{ node.tags.deprecated[0].description }}//
{% endif %}
== {{ node.summary|replace({"\n":""})|raw }} ==
<html>{{ node.description|markdown|raw }}</html>
{% include 'includes/code-examples.txt.twig' with {structure:node, title_level: '====='} %}
{% set class = node.parent %}
{% block hierarchy_element %}
{% if class and class.name is defined and class.name|trim != '' %}
==== parent ====
{% set child = class %}
{% set class = class.parent %}
{{ block('hierarchy_element') }}
[[{{ child.name }}|{{ child.name }}]]
{% endif %}
{% endblock %}
{% for interface in node.interfaces|sort_asc %}
{% if loop.first %}
==== Implements ====
{% endif %}
{% if loop.length > 1 %} * {% endif %}{{ interface.fullyQualifiedStructuralElementName ?: interface }}
{% endfor %}
{% for trait in node.usedTraits|sort_asc %}
{% if loop.first %}
==== Uses traits ====
{% endif %}
{% if loop.length > 1 %} * {% endif %}{{ trait.fullyQualifiedStructuralElementName ?: trait }}
{% endfor %}
{% include 'includes/see-also.txt.twig' with {structure:node, title_level: '==='} %}
{% include 'includes/tags.txt.twig' with {structure:node, title_level: '=====', blacklist: ['link', 'see', 'abstract', 'example', 'method', 'property', 'property-read', 'property-write', 'package', 'subpackage', 'phpdoc-tuning-exclude-inherited', 'api', 'api-advanced', 'overwritable-hook', 'extension-hook', 'copyright', 'license', 'code-example']} %}
{% set methods = node.inheritedMethods.merge(node.methods) %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api'} %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api-advanced'} %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'overwritable-hook'} %}
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'extension-hook'} %}
<WRAP clear />
{% for method in methods|sort_asc if method.visibility == 'public' %}
{%- if loop.first %}
===== Public methods =====
{% endif %}
{{ block('method') }}
{% endfor %}
{% for method in methods|sort_asc if method.visibility == 'protected' %}
{%- if loop.first %}
===== Protected methods =====
{% endif %}
{{ block('method') }}
{% endfor %}
{% set constants = node.inheritedConstants.merge(node.constants) %}
{% if constants|length > 0 %}
===== Constants =====
{% for constant in constants|sort_asc %}
{{ block('constant') }}
{% endfor %}
{% endif %}
{#{% set properties = node.inheritedProperties.merge(node.properties) %}#}
{#{% for property in properties|sort_asc if property.visibility == 'public' %}#}
{#{%- if loop.first %}#}
{#===== Public properties =====#}
{#{% endif %}#}
{#{{ block('property') }}#}
{#{% endfor %}#}
{#{% for property in properties|sort_asc if property.visibility == 'protected' %}#}
{#{%- if loop.first %}#}
{#===== Protected properties =====#}
{#{% endif %}#}
{#{{ block('property') }}#}
{#{% endfor %}#}
{%- endif %} {#{% elseif node.tags['xxx'] is not defined and ... #}
<wrap button>[[start|🔙 Back]]</wrap>
{% endblock %}

View File

@@ -1,5 +0,0 @@
{% use 'elements/constant.txt.twig' %}
{% use 'elements/property.txt.twig' %}
{% use 'elements/method.txt.twig' %}
{% block content %}{% endblock %}

View File

@@ -1,51 +0,0 @@
{% extends 'layout.txt.twig' %}
{% block content %}
{% set namespace = project.namespace %}
{{ block('sidebarNamespaces') }}
{#{{ node.parent|raw }}#}
{#====== {{ node.parent.fullyQualifiedStructuralElementName }}{{ node.name }} ======#}
{% if node.children|length > 0 %}
=====Namespaces=====
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.children} %}
----
{% endif %}
{% if node.traits|length > 0 %}
===== Traits =====
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.traits} %}
----
{%- endif %}
{% if node.interfaces|length > 0 %}
===== Interfaces =====
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.interfaces} %}
----
{% endif %}
{% if node.classes|length > 0 %}
===== Classes =====
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.classes} %}
----
{% endif %}
{#{% if node.constants|length > 0 %}#}
{#===== Constants =====#}
{#{% for constant in node.constants|sort_asc %}#}
{# {{ block('constant') }}#}
{#{% endfor %}#}
{#{% endif %}#}
{#{% if node.functions|length > 0 %}#}
{#===== Functions =====#}
{#{% for method in node.functions|sort_asc %}#}
{# {{ block('method') }}#}
{#{% endfor %}#}
{#{% endif %}#}
{% endblock %}

View File

@@ -1,49 +0,0 @@
====== Deprecated elements ======
{#{% for element in project.indexes.elements if element.deprecated %}#}
{#{% if element.file.path != previousPath %}#}
{#<li><a href="#{{ element.file.path }}"><i class="icon-file"></i> {{ element.file.path }}</a></li>#}
{#{% endif %}#}
{#{% set previousPath = element.file.path %}#}
{#{% endfor %}#}
{% for element in project.indexes.elements if element.deprecated %}
{% if element.file.path != previousPath %}
{% if previousPath %}
</WRAP>{# group #}
{% endif %}
{#<a name="{{ element.file.path }}" id="{{ element.file.path }}"></a>#}
===== {{ element.file.path }} ({{ element.tags.deprecated.count }} found)=====
<WRAP group >
<WRAP third column >
Element
</WRAP>{# third column#}
<WRAP third column >
Line
</WRAP>{# third column#}
<WRAP third column >
Description
</WRAP>{# third column#}
{% endif %}
{% for tag in element.tags.deprecated %}
<WRAP group >
<WRAP third column >
{{ element.fullyQualifiedStructuralElementName }}
</WRAP>{# third column#}
<WRAP third column >
{{ element.line }}
</WRAP>{# third column#}
<WRAP third column >
{{ tag.description }}
</WRAP>{# third column#}
{% endfor %}
</WRAP>{# group #}
{% set previousPath = element.file.path %}
{% else %}
<WRAP info>No deprecated elements have been found in this project.</WRAP>
{% endfor %}

View File

@@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<template>
<author>Bruno DA SILVA</author>
<email>contact [at] combodo.com</email>
<version>1.0.0</version>
<copyright>Combodo 2018</copyright>
<description><![CDATA[
Forked from the clean theme of https://github.com/phpDocumentor/phpDocumentor2 provided under the MIT licence.
The original work is copyright "Mike van Riel".
------------------------------------------------------------------------------------------------------------------
To improve performance you can add the following to your .htaccess:
<ifModule mod_deflate.c>
<filesMatch "\.(js|css|html)$">
SetOutputFilter DEFLATE
</filesMatch>
</ifModule>
]]></description>
<transformations>
<transformation writer="twig" query="namespace" source="templates/combodo-wiki/namespace.txt.twig" artifact="start.txt"/>
<transformation writer="twig" query="indexes.classes" source="templates/combodo-wiki/class.txt.twig" artifact="{{name}}.txt"/>
<transformation writer="twig" query="indexes.interfaces" source="templates/combodo-wiki/interface.txt.twig" artifact="{{name}}.txt" />
</transformations>
</template>

View File

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

125
.gitignore vendored
View File

@@ -1,125 +0,0 @@
# no slash at the end to handle also symlinks
/toolkit
/conf
/env-*
# composer reserver directory, from sources, populate/update using "composer install"
vendor/*
test/vendor/*
# all datas but listing prevention
/data/**
!/data/.htaccess
!/data/index.php
!/data/web.config
# iTop extensions
/extensions/**
!/extensions/readme.txt
# all logs but listing prevention
/log/**
!/log/.htaccess
!/log/index.php
!/log/web.config
# Jetbrains
/.idea/**
!/.idea/encodings.xml
!/.idea/codeStyles
!/.idea/codeStyles/*
!/.idea/inspectionProfiles
!/.idea/inspectionProfiles/*
#phpdocumentor temp file
ast.dump
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
### Eclipse template
.metadata
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
.project
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# CDT- autotools
.autotools
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
# Annotation Processing
.apt_generated/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet

View File

@@ -1,57 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="LINE_SEPARATOR" value="&#10;" />
<option name="RIGHT_MARGIN" value="320" />
<HTMLCodeStyleSettings>
<option name="HTML_DO_NOT_INDENT_CHILDREN_OF" value="html,body,thead,tbody,tfoot,script,style" />
<option name="HTML_DO_NOT_ALIGN_CHILDREN_OF_MIN_LINES" value="4" />
</HTMLCodeStyleSettings>
<PHPCodeStyleSettings>
<option name="CONCAT_SPACES" value="false" />
<option name="PHPDOC_BLANK_LINE_BEFORE_TAGS" value="true" />
<option name="PHPDOC_BLANK_LINES_AROUND_PARAMETERS" value="true" />
<option name="PHPDOC_WRAP_LONG_LINES" value="true" />
<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>
<codeStyleSettings language="JavaScript">
<option name="BRACE_STYLE" value="2" />
<option name="ELSE_ON_NEW_LINE" value="true" />
<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="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" />
<option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
<option name="ARRAY_INITIALIZER_WRAP" value="5" />
<option name="ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE" value="true" />
<option name="ARRAY_INITIALIZER_RBRACE_ON_NEXT_LINE" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />
<option name="SMART_TABS" value="true" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="XML">
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

View File

@@ -1,5 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Combodo" />
</state>
</component>

6
.idea/encodings.xml generated
View File

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

View File

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

View File

@@ -1,19 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="InconsistentLineSeparators" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="PhpIncludeInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpMethodParametersCountMismatchInspection" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="PhpTooManyParametersInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="limit" value="7" />
</inspection_tool>
<inspection_tool class="PhpUndefinedClassInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="DONT_REPORT_MULTI_RESOLVE" value="true" />
</inspection_tool>
<inspection_tool class="PhpUnhandledExceptionInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
<inspection_tool class="PhpUnusedParameterInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="DONT_REPORT_ABSTRACT_CLASS" value="true" />
</inspection_tool>
<inspection_tool class="SqlNoDataSourceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,72 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<installation>
<!-- On manual installs, this file is generated in setup/install-*.xml -->
<mode>upgrade</mode>
<preinstall>
<copies type="array"/>
</preinstall>
<source_dir>datamodels/2.x/</source_dir>
<datamodel_version>2.5.0</datamodel_version>
<previous_configuration_file>/var/lib/jenkins/workspace/iTop-CI/unattended_install/default-config-itop.php</previous_configuration_file>
<extensions_dir>extensions</extensions_dir>
<target_env>production</target_env>
<workspace_dir></workspace_dir>
<database>
<server></server>
<user>jenkins_itop</user>
<pwd>IKnowYouSeeMeInJenkinsConf</pwd>
<name>itop_ci</name>
<db_tls_enabled></db_tls_enabled>
<db_tls_ca></db_tls_ca>
<prefix></prefix>
</database>
<url>http://127.0.0.1/itop/svn/trunk/</url>
<graphviz_path>/usr/bin/dot</graphviz_path>
<admin_account>
<user>admin</user>
<pwd>admin</pwd>
<language>EN US</language>
</admin_account>
<language>EN US</language>
<selected_modules type="array">
<item>authent-external</item>
<item>authent-local</item>
<item>itop-backup</item>
<item>itop-config</item>
<item>itop-profiles-itil</item>
<item>itop-sla-computation</item>
<item>itop-tickets</item>
<item>itop-welcome-itil</item>
<item>itop-config-mgmt</item>
<item>itop-attachments</item>
<item>itop-datacenter-mgmt</item>
<item>itop-endusers-devices</item>
<item>itop-storage-mgmt</item>
<item>itop-virtualization-mgmt</item>
<item>itop-bridge-virtualization-storage</item>
<item>itop-service-mgmt</item>
<item>itop-request-mgmt</item>
<item>itop-portal</item>
<item>itop-portal-base</item>
<item>itop-change-mgmt</item>
<item>itop-knownerror-mgmt</item>
</selected_modules>
<selected_extensions type="array">
<item>itop-config-mgmt-core</item>
<item>itop-config-mgmt-datacenter</item>
<item>itop-config-mgmt-end-user</item>
<item>itop-config-mgmt-storage</item>
<item>itop-config-mgmt-virtualization</item>
<item>itop-service-mgmt-enterprise</item>
<item>itop-ticket-mgmt-simple-ticket</item>
<item>itop-ticket-mgmt-simple-ticket-enhanced-portal</item>
<item>itop-change-mgmt-simple</item>
<item>itop-kown-error-mgmt</item>
</selected_extensions>
<sample_data>1</sample_data>
<old_addon></old_addon>
<options>
<generate_config>1</generate_config>
</options>
<mysql_bindir></mysql_bindir>
</installation>

View File

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

141
README.md
View File

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

View File

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

View File

@@ -1,78 +1,78 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010-2012 Combodo SARL
// //
// This file is part of iTop. // 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 // 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 // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// iTop is distributed in the hope that it will be useful, // iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details. // GNU Affero General Public License for more details.
// //
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* UserRightsNull * UserRightsNull
* User management Module - say Yeah! to everything * User management Module - say Yeah! to everything
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
class UserRightsNull extends UserRightsAddOnAPI class UserRightsNull extends UserRightsAddOnAPI
{ {
// Installation: create the very first user // Installation: create the very first user
public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US') public function CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage = 'EN US')
{ {
return true; return true;
} }
public function IsAdministrator($oUser) public function IsAdministrator($oUser)
{ {
return true; return true;
} }
public function IsPortalUser($oUser) public function IsPortalUser($oUser)
{ {
return true; return true;
} }
public function Init() public function Init()
{ {
return true; return true;
} }
public function GetSelectFilter($oUser, $sClass, $aSettings = array()) public function GetSelectFilter($oUser, $sClass, $aSettings = array())
{ {
$oNullFilter = new DBObjectSearch($sClass); $oNullFilter = new DBObjectSearch($sClass);
return $oNullFilter; return $oNullFilter;
} }
public function IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet = null) public function IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet = null)
{ {
return UR_ALLOWED_YES; return UR_ALLOWED_YES;
} }
public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null) public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null)
{ {
return UR_ALLOWED_YES; return UR_ALLOWED_YES;
} }
public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null) public function IsActionAllowedOnAttribute($oUser, $sClass, $sAttCode, $iActionCode, $oInstanceSet = null)
{ {
return UR_ALLOWED_YES; return UR_ALLOWED_YES;
} }
public function FlushPrivileges() public function FlushPrivileges()
{ {
} }
} }
UserRights::SelectModule('UserRightsNull'); UserRights::SelectModule('UserRightsNull');
?> ?>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,328 +0,0 @@
<?php
namespace Html2Text;
if (!function_exists('mb_split'))
{
function mb_split($pattern, $subject, $limit = -1)
{
return preg_split('/'.$pattern.'/', $subject, $limit);
}
}
/**
* Replace all occurrences of the search string with the replacement string.
*
* @author Sean Murphy <sean@iamseanmurphy.com>
* @copyright Copyright 2012 Sean Murphy. All rights reserved.
* @license http://creativecommons.org/publicdomain/zero/1.0/
* @link http://php.net/manual/function.str-replace.php
*
* @param mixed $search
* @param mixed $replace
* @param mixed $subject
* @param int $count
* @return mixed
*/
function mb_str_replace($search, $replace, $subject, &$count = 0) {
if (!is_array($subject)) {
// Normalize $search and $replace so they are both arrays of the same length
$searches = is_array($search) ? array_values($search) : array($search);
$replacements = is_array($replace) ? array_values($replace) : array($replace);
$replacements = array_pad($replacements, count($searches), '');
foreach ($searches as $key => $search) {
$parts = mb_split(preg_quote($search), $subject);
$count += count($parts) - 1;
$subject = implode($replacements[$key], $parts);
}
} else {
// Call mb_str_replace for each subject in array, recursively
foreach ($subject as $key => $value) {
$subject[$key] = mb_str_replace($search, $replace, $value, $count);
}
}
return $subject;
}
/******************************************************************************
* Copyright (c) 2010 Jevon Wright and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* or
*
* LGPL which is available at http://www.gnu.org/licenses/lgpl.html
*
*
* Contributors:
* Jevon Wright - initial API and implementation
* Denis Flaven - some fixes for properly handling UTF-8 characters
****************************************************************************/
class Html2Text {
/**
* Tries to convert the given HTML into a plain text format - best suited for
* e-mail display, etc.
*
* <p>In particular, it tries to maintain the following features:
* <ul>
* <li>Links are maintained, with the 'href' copied over
* <li>Information in the &lt;head&gt; is lost
* </ul>
*
* @param string html the input HTML
* @return string the HTML converted, as best as possible, to text
* @throws Html2TextException if the HTML could not be loaded as a {@link DOMDocument}
*/
static function convert($html) {
// replace &nbsp; with spaces
$html = str_replace("&nbsp;", " ", $html);
$html = mb_str_replace("\xc2\xa0", " ", $html); // DO NOT USE str_replace since it breaks the "à" character which is \xc3 \xa0 in UTF-8
$html = static::fixNewlines($html);
$doc = new \DOMDocument();
if (!@$doc->loadHTML('<?xml encoding="UTF-8">'.$html)) // Forces the UTF-8 character set for HTML fragments
{
throw new Html2TextException("Could not load HTML - badly formed?", $html);
}
$output = static::iterateOverNode($doc);
// remove leading and trailing spaces on each line
$output = preg_replace("/[ \t]*\n[ \t]*/im", "\n", $output);
$output = preg_replace("/ *\t */im", "\t", $output);
// remove unnecessary empty lines
$output = preg_replace("/\n\n\n*/im", "\n\n", $output);
// remove leading and trailing whitespace
$output = trim($output);
return $output;
}
/**
* Unify newlines; in particular, \r\n becomes \n, and
* then \r becomes \n. This means that all newlines (Unix, Windows, Mac)
* all become \ns.
*
* @param string text text with any number of \r, \r\n and \n combinations
* @return string the fixed text
*/
static function fixNewlines($text) {
// replace \r\n to \n
$text = str_replace("\r\n", "\n", $text);
// remove \rs
$text = str_replace("\r", "\n", $text);
return $text;
}
static function nextChildName($node) {
// get the next child
$nextNode = $node->nextSibling;
while ($nextNode != null) {
if ($nextNode instanceof \DOMElement) {
break;
}
$nextNode = $nextNode->nextSibling;
}
$nextName = null;
if ($nextNode instanceof \DOMElement && $nextNode != null) {
$nextName = strtolower($nextNode->nodeName);
}
return $nextName;
}
static function prevChildName($node) {
// get the previous child
$nextNode = $node->previousSibling;
while ($nextNode != null) {
if ($nextNode instanceof \DOMElement) {
break;
}
$nextNode = $nextNode->previousSibling;
}
$nextName = null;
if ($nextNode instanceof \DOMElement && $nextNode != null) {
$nextName = strtolower($nextNode->nodeName);
}
return $nextName;
}
static function iterateOverNode($node) {
if ($node instanceof \DOMText) {
// Replace whitespace characters with a space (equivilant to \s)
return preg_replace("/[\\t\\n\\f\\r ]+/im", " ", $node->wholeText);
}
if ($node instanceof \DOMDocumentType) {
// ignore
return "";
}
$nextName = static::nextChildName($node);
$prevName = static::prevChildName($node);
$name = strtolower($node->nodeName);
// start whitespace
switch ($name) {
case "hr":
return "---------------------------------------------------------------\n";
case "style":
case "head":
case "title":
case "meta":
case "script":
// ignore these tags
return "";
case "h1":
case "h2":
case "h3":
case "h4":
case "h5":
case "h6":
case "ol":
case "ul":
// add two newlines, second line is added below
$output = "\n";
break;
case "td":
case "th":
// add tab char to separate table fields
$output = "\t";
break;
case "tr":
case "p":
case "div":
// add one line
$output = "\n";
break;
case "li":
$output = "- ";
break;
default:
// print out contents of unknown tags
$output = "";
break;
}
// debug
//$output .= "[$name,$nextName]";
if (isset($node->childNodes)) {
for ($i = 0; $i < $node->childNodes->length; $i++) {
$n = $node->childNodes->item($i);
$text = static::iterateOverNode($n);
$output .= $text;
}
}
// end whitespace
switch ($name) {
case "h1":
case "h2":
case "h3":
case "h4":
case "h5":
case "h6":
$output .= "\n";
break;
case "p":
case "br":
// add one line
if ($nextName != "div")
$output .= "\n";
break;
case "div":
// add one line only if the next child isn't a div
if ($nextName != "div" && $nextName != null)
$output .= "\n";
break;
case "a":
// links are returned in [text](link) format
$href = $node->getAttribute("href");
$output = trim($output);
// remove double [[ ]] s from linking images
if (substr($output, 0, 1) == "[" && substr($output, -1) == "]") {
$output = substr($output, 1, strlen($output) - 2);
// for linking images, the title of the <a> overrides the title of the <img>
if ($node->getAttribute("title")) {
$output = $node->getAttribute("title");
}
}
// if there is no link text, but a title attr
if (!$output && $node->getAttribute("title")) {
$output = $node->getAttribute("title");
}
if ($href == null) {
// it doesn't link anywhere
if ($node->getAttribute("name") != null) {
$output = "[$output]";
}
} else {
if ($href == $output || $href == "mailto:$output" || $href == "http://$output" || $href == "https://$output") {
// link to the same address: just use link
$output;
} else {
// replace it
if ($output) {
$output = "[$output]($href)";
} else {
// empty string
$output = $href;
}
}
}
// does the next node require additional whitespace?
switch ($nextName) {
case "h1": case "h2": case "h3": case "h4": case "h5": case "h6":
$output .= "\n";
break;
}
break;
case "img":
if ($node->getAttribute("title")) {
$output = "[" . $node->getAttribute("title") . "]";
} elseif ($node->getAttribute("alt")) {
$output = "[" . $node->getAttribute("alt") . "]";
} else {
$output = "";
}
break;
case "li":
$output .= "\n";
break;
default:
// do nothing
}
return $output;
}
}

View File

@@ -1,28 +0,0 @@
<?php
/******************************************************************************
* Copyright (c) 2010 Jevon Wright and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* or
*
* LGPL which is available at http://www.gnu.org/licenses/lgpl.html
*
*
* Contributors:
* Jevon Wright - initial API and implementation
****************************************************************************/
namespace Html2Text;
class Html2TextException extends \Exception {
var $more_info;
public function __construct($message = "", $more_info = "") {
parent::__construct($message);
$this->more_info = $more_info;
}
}

View File

@@ -1,401 +1,394 @@
<?php <?php
// Copyright (C) 2010-2018 Combodo SARL // Copyright (C) 2010-2014 Combodo SARL
// //
// This file is part of iTop. // 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 // 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 // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// iTop is distributed in the hope that it will be useful, // iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details. // GNU Affero General Public License for more details.
// //
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* Simple web page with no includes, header or fancy formatting, useful to * Simple web page with no includes, header or fancy formatting, useful to
* generate HTML fragments when called by an AJAX method * generate HTML fragments when called by an AJAX method
* *
* @copyright Copyright (C) 2010-2017 Combodo SARL * @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
require_once(APPROOT."/application/webpage.class.inc.php"); require_once(APPROOT."/application/webpage.class.inc.php");
class ajax_page extends WebPage implements iTabbedPage class ajax_page extends WebPage implements iTabbedPage
{ {
/** /**
* Jquery style ready script * Jquery style ready script
* @var Hash * @var Hash
*/ */
protected $m_sReadyScript; protected $m_sReadyScript;
protected $m_oTabs; protected $m_oTabs;
private $m_sMenu; // If set, then the menu will be updated private $m_sMenu; // If set, then the menu will be updated
/** /**
* constructor for the web page * constructor for the web page
* @param string $s_title Not used * @param string $s_title Not used
*/ */
function __construct($s_title) function __construct($s_title)
{ {
$sPrintable = utils::ReadParam('printable', '0'); parent::__construct($s_title);
$bPrintable = ($sPrintable == '1'); $this->m_sReadyScript = "";
//$this->add_header("Content-type: text/html; charset=utf-8");
parent::__construct($s_title, $bPrintable); $this->add_header("Cache-control: no-cache");
$this->m_sReadyScript = ""; $this->m_oTabs = new TabManager();
//$this->add_header("Content-type: text/html; charset=utf-8"); $this->sContentType = 'text/html';
$this->add_header("Cache-control: no-cache"); $this->sContentDisposition = 'inline';
$this->m_oTabs = new TabManager(); $this->m_sMenu = "";
$this->sContentType = 'text/html'; }
$this->sContentDisposition = 'inline';
$this->m_sMenu = ""; public function AddTabContainer($sTabContainer, $sPrefix = '')
{
utils::InitArchiveMode(); $this->add($this->m_oTabs->AddTabContainer($sTabContainer, $sPrefix));
} }
public function AddTabContainer($sTabContainer, $sPrefix = '') public function AddToTab($sTabContainer, $sTabLabel, $sHtml)
{ {
$this->add($this->m_oTabs->AddTabContainer($sTabContainer, $sPrefix)); $this->add($this->m_oTabs->AddToTab($sTabContainer, $sTabLabel, $sHtml));
} }
public function AddToTab($sTabContainer, $sTabLabel, $sHtml) public function SetCurrentTabContainer($sTabContainer = '')
{ {
$this->add($this->m_oTabs->AddToTab($sTabContainer, $sTabLabel, $sHtml)); return $this->m_oTabs->SetCurrentTabContainer($sTabContainer);
} }
public function SetCurrentTabContainer($sTabContainer = '') public function SetCurrentTab($sTabLabel = '')
{ {
return $this->m_oTabs->SetCurrentTabContainer($sTabContainer); return $this->m_oTabs->SetCurrentTab($sTabLabel);
} }
public function SetCurrentTab($sTabLabel = '') /**
{ * Add a tab which content will be loaded asynchronously via the supplied URL
return $this->m_oTabs->SetCurrentTab($sTabLabel); *
} * 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.
* Add a tab which content will be loaded asynchronously via the supplied URL *
* * @param string $sTabLabel The (localised) label of the tab
* Limitations: * @param string $sUrl The URL to load (on the same server)
* 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. * @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.
* Static content cannot be added inside such tabs. * @since 2.0.3
* */
* @param string $sTabLabel The (localised) label of the tab public function AddAjaxTab($sTabLabel, $sUrl, $bCache = true)
* @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. $this->add($this->m_oTabs->AddAjaxTab($sTabLabel, $sUrl, $bCache));
* @since 2.0.3 }
*/
public function AddAjaxTab($sTabLabel, $sUrl, $bCache = true) public function GetCurrentTab()
{ {
$this->add($this->m_oTabs->AddAjaxTab($sTabLabel, $sUrl, $bCache)); return $this->m_oTabs->GetCurrentTab();
} }
public function GetCurrentTab() public function RemoveTab($sTabLabel, $sTabContainer = null)
{ {
return $this->m_oTabs->GetCurrentTab(); $this->m_oTabs->RemoveTab($sTabLabel, $sTabContainer);
} }
public function RemoveTab($sTabLabel, $sTabContainer = null) /**
{ * Finds the tab whose title matches a given pattern
$this->m_oTabs->RemoveTab($sTabLabel, $sTabContainer); * @return mixed The name of the tab as a string or false if not found
} */
public function FindTab($sPattern, $sTabContainer = null)
/** {
* Finds the tab whose title matches a given pattern return $this->m_oTabs->FindTab($sPattern, $sTabContainer);
* @return mixed The name of the tab as a string or false if not found }
*/
public function FindTab($sPattern, $sTabContainer = null) /**
{ * Make the given tab the active one, as if it were clicked
return $this->m_oTabs->FindTab($sPattern, $sTabContainer); * 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...
/** */
* Make the given tab the active one, as if it were clicked public function SelectTab($sTabContainer, $sTabLabel)
* DOES NOT WORK: apparently in the *old* version of jquery {
* that we are using this is not supported... TO DO upgrade $this->add_ready_script($this->m_oTabs->SelectTab($sTabContainer, $sTabLabel));
* the whole jquery bundle... }
*/
public function SelectTab($sTabContainer, $sTabLabel) public function AddToMenu($sHtml)
{ {
$this->add_ready_script($this->m_oTabs->SelectTab($sTabContainer, $sTabLabel)); $this->m_sMenu .= $sHtml;
} }
public function AddToMenu($sHtml) /**
{ * Echoes the content of the whole page
$this->m_sMenu .= $sHtml; * @return void
} */
public function output()
/** {
* Echoes the content of the whole page if (!empty($this->sContentType))
* @return void {
*/ $this->add_header('Content-type: '.$this->sContentType);
public function output() }
{ if (!empty($this->sContentDisposition))
if (!empty($this->sContentType)) {
{ $this->add_header('Content-Disposition: '.$this->sContentDisposition.'; filename="'.$this->sContentFileName.'"');
$this->add_header('Content-type: '.$this->sContentType); }
} foreach($this->a_headers as $s_header)
if (!empty($this->sContentDisposition)) {
{ header($s_header);
$this->add_header('Content-Disposition: '.$this->sContentDisposition.'; filename="'.$this->sContentFileName.'"'); }
} if ($this->m_oTabs->TabsContainerCount() > 0)
foreach($this->a_headers as $s_header) {
{ $this->add_ready_script(
header($s_header); <<<EOF
} // The "tab widgets" to handle.
if ($this->m_oTabs->TabsContainerCount() > 0) var tabs = $('div[id^=tabbedContent]');
{
$this->add_ready_script( // Ugly patch for a change in the behavior of jQuery UI:
<<<EOF // Before jQuery UI 1.9, tabs were always considered as "local" (opposed to Ajax)
// The "tab widgets" to handle. // when their href was beginning by #. Starting with 1.9, a <base> tag in the page
var tabs = $('div[id^=tabbedContent]'); // is taken into account and causes "local" tabs to be considered as Ajax
// unless their URL is equal to the URL of the page...
// Ugly patch for a change in the behavior of jQuery UI: if ($('base').length > 0)
// Before jQuery UI 1.9, tabs were always considered as "local" (opposed to Ajax) {
// when their href was beginning by #. Starting with 1.9, a <base> tag in the page $('div[id^=tabbedContent] > ul > li > a').each(function() {
// is taken into account and causes "local" tabs to be considered as Ajax var sHash = location.hash;
// unless their URL is equal to the URL of the page... var sCleanLocation = location.href.toString().replace(sHash, '').replace(/#$/, '');
if ($('base').length > 0) $(this).attr("href", sCleanLocation+$(this).attr("href"));
{ });
$('div[id^=tabbedContent] > ul > li > a').each(function() { }
var sHash = location.hash; if ($.bbq)
var sCleanLocation = location.href.toString().replace(sHash, '').replace(/#$/, ''); {
$(this).attr("href", sCleanLocation+$(this).attr("href")); // This selector will be reused when selecting actual tab widget A elements.
}); var tab_a_selector = 'ul.ui-tabs-nav a';
}
if ($.bbq) // Enable tabs on all tab widgets. The `event` property must be overridden so
{ // that the tabs aren't changed on click, and any custom event name can be
// This selector will be reused when selecting actual tab widget A elements. // specified. Note that if you define a callback for the 'select' event, it
var tab_a_selector = 'ul.ui-tabs-nav a'; // will be executed for the selected tab whenever the hash changes.
tabs.tabs({ event: 'change' });
// Enable tabs on all tab widgets. The `event` property must be overridden so
// that the tabs aren't changed on click, and any custom event name can be // Define our own click handler for the tabs, overriding the default.
// specified. Note that if you define a callback for the 'select' event, it tabs.find( tab_a_selector ).click(function()
// will be executed for the selected tab whenever the hash changes. {
tabs.tabs({ event: 'change' }); var state = {};
// Define our own click handler for the tabs, overriding the default. // Get the id of this tab widget.
tabs.find( tab_a_selector ).click(function() var id = $(this).closest( 'div[id^=tabbedContent]' ).attr( 'id' );
{
var state = {}; // Get the index of this tab.
var idx = $(this).parent().prevAll().length;
// Get the id of this tab widget.
var id = $(this).closest( 'div[id^=tabbedContent]' ).attr( 'id' ); // Set the state!
state[ id ] = idx;
// Get the index of this tab. $.bbq.pushState( state );
var idx = $(this).parent().prevAll().length; });
}
// Set the state! else
state[ id ] = idx; {
$.bbq.pushState( state ); tabs.tabs();
}); }
} EOF
else );
{ }
tabs.tabs(); // Render the tabs in the page (if any)
} $this->s_content = $this->m_oTabs->RenderIntoContent($this->s_content);
EOF
); // Additional UI widgets to be activated inside the ajax fragment ??
} if (($this->sContentType == 'text/html') && (preg_match('/class="date-pick"/', $this->s_content) || preg_match('/class="datetime-pick"/', $this->s_content)) )
// Render the tabs in the page (if any) {
$this->s_content = $this->m_oTabs->RenderIntoContent($this->s_content, $this); $this->add_ready_script(
<<<EOF
// Additional UI widgets to be activated inside the ajax fragment $(".date-pick").datepicker({
// Important: Testing the content type is not enough because some ajax handlers have not correctly positionned the flag (e.g json response corrupted by the script) showOn: 'button',
if (($this->sContentType == 'text/html') && (preg_match('/class="date-pick"/', $this->s_content) || preg_match('/class="datetime-pick"/', $this->s_content)) ) buttonImage: '../images/calendar.png',
{ buttonImageOnly: true,
$this->add_ready_script( dateFormat: 'yy-mm-dd',
<<<EOF constrainInput: false,
PrepareWidgets(); changeMonth: true,
EOF changeYear: true
); });
} $(".datetime-pick").datepicker({
$s_captured_output = $this->ob_get_clean_safe(); showOn: 'button',
if (($this->sContentType == 'text/html') && ($this->sContentDisposition == 'inline')) buttonImage: '../images/calendar.png',
{ buttonImageOnly: true,
// inline content != attachment && html => filter all scripts for malicious XSS scripts dateFormat: 'yy-mm-dd 00:00:00',
echo self::FilterXSS($this->s_content); constrainInput: false,
} changeMonth: true,
else changeYear: true
{ });
echo $this->s_content; EOF
} );
if (!empty($this->m_sMenu)) }
{ $s_captured_output = $this->ob_get_clean_safe();
$uid = time(); if (($this->sContentType == 'text/html') && ($this->sContentDisposition == 'inline'))
echo "<div id=\"accordion_temp_$uid\">\n"; {
echo "<div id=\"accordion\">\n"; // inline content != attachment && html => filter all scripts for malicious XSS scripts
echo "<!-- Beginning of the accordion menu -->\n"; echo self::FilterXSS($this->s_content);
echo self::FilterXSS($this->m_sMenu); }
echo "<!-- End of the accordion menu-->\n"; else
echo "</div>\n"; {
echo "</div>\n"; echo $this->s_content;
}
echo "<script type=\"text/javascript\">\n"; if (!empty($this->m_sMenu))
echo "$('#inner_menu').html($('#accordion_temp_$uid').html());\n"; {
echo "$('#accordion_temp_$uid').remove();\n"; $uid = time();
echo "\n</script>\n"; echo "<div id=\"accordion_temp_$uid\">\n";
} echo "<div id=\"accordion\">\n";
echo "<!-- Beginning of the accordion menu -->\n";
//echo $this->s_deferred_content; echo self::FilterXSS($this->m_sMenu);
if (count($this->a_scripts) > 0) echo "<!-- End of the accordion menu-->\n";
{ echo "</div>\n";
echo "<script type=\"text/javascript\">\n"; echo "</div>\n";
echo implode("\n", $this->a_scripts);
echo "\n</script>\n"; echo "<script type=\"text/javascript\">\n";
} echo "$('#inner_menu').html($('#accordion_temp_$uid').html());\n";
if (count($this->a_linked_scripts) > 0) echo "$('#accordion_temp_$uid').remove();\n";
{ echo "$('#accordion').accordion({ header: 'h3', navigation: true, autoHeight: false, collapsible: false, icons: false });\n";
echo "<script type=\"text/javascript\">\n"; echo "\n</script>\n";
foreach($this->a_linked_scripts as $sScriptUrl) }
{
echo '$.getScript('.json_encode($sScriptUrl).");\n"; //echo $this->s_deferred_content;
} if (count($this->a_scripts) > 0)
echo "\n</script>\n"; {
} echo "<script type=\"text/javascript\">\n";
if (!empty($this->s_deferred_content)) echo implode("\n", $this->a_scripts);
{ echo "\n</script>\n";
echo "<script type=\"text/javascript\">\n"; }
echo "\$('body').append('".addslashes(str_replace("\n", '', $this->s_deferred_content))."');\n"; if (!empty($this->s_deferred_content))
echo "\n</script>\n"; {
} echo "<script type=\"text/javascript\">\n";
if (!empty($this->m_sReadyScript)) echo "\$('body').append('".addslashes(str_replace("\n", '', $this->s_deferred_content))."');\n";
{ echo "\n</script>\n";
echo "<script type=\"text/javascript\">\n"; }
echo $this->m_sReadyScript; // Ready Scripts are output as simple scripts if (!empty($this->m_sReadyScript))
echo "\n</script>\n"; {
} echo "<script type=\"text/javascript\">\n";
if(count($this->a_linked_stylesheets) > 0) echo $this->m_sReadyScript; // Ready Scripts are output as simple scripts
{ echo "\n</script>\n";
echo "<script type=\"text/javascript\">"; }
foreach($this->a_linked_stylesheets as $aStylesheet)
{ if (trim($s_captured_output) != "")
$sStylesheetUrl = $aStylesheet['link']; {
echo "if (!$('link[href=\"{$sStylesheetUrl}\"]').length) $('<link href=\"{$sStylesheetUrl}\" rel=\"stylesheet\">').appendTo('head');\n"; echo self::FilterXSS($s_captured_output);
} }
echo "\n</script>\n";
} if (class_exists('MetaModel'))
{
if (trim($s_captured_output) != "") MetaModel::RecordQueryTrace();
{ }
echo self::FilterXSS($s_captured_output); }
}
/**
if (class_exists('DBSearch')) * Adds a paragraph with a smaller font into the page
{ * NOT implemented (i.e does nothing)
DBSearch::RecordQueryTrace(); * @param string $sText Content of the (small) paragraph
} * @return void
} */
public function small_p($sText)
/** {
* Adds a paragraph with a smaller font into the page }
* NOT implemented (i.e does nothing)
* @param string $sText Content of the (small) paragraph public function add($sHtml)
* @return void {
*/ if (($this->m_oTabs->GetCurrentTabContainer() != '') && ($this->m_oTabs->GetCurrentTab() != ''))
public function small_p($sText) {
{ $this->m_oTabs->AddToTab($this->m_oTabs->GetCurrentTabContainer(), $this->m_oTabs->GetCurrentTab(), $sHtml);
} }
else
public function add($sHtml) {
{ parent::add($sHtml);
if (($this->m_oTabs->GetCurrentTabContainer() != '') && ($this->m_oTabs->GetCurrentTab() != '')) }
{ }
$this->m_oTabs->AddToTab($this->m_oTabs->GetCurrentTabContainer(), $this->m_oTabs->GetCurrentTab(), $sHtml);
} /**
else * Records the current state of the 'html' part of the page output
{ * @return mixed The current state of the 'html' output
parent::add($sHtml); */
} public function start_capture()
} {
$sCurrentTabContainer = $this->m_oTabs->GetCurrentTabContainer();
/** $sCurrentTab = $this->m_oTabs->GetCurrentTab();
* Records the current state of the 'html' part of the page output
* @return mixed The current state of the 'html' output if (!empty($sCurrentTabContainer) && !empty($sCurrentTab))
*/ {
public function start_capture() $iOffset = $this->m_oTabs->GetCurrentTabLength();
{ return array('tc' => $sCurrentTabContainer, 'tab' => $sCurrentTab, 'offset' => $iOffset);
$sCurrentTabContainer = $this->m_oTabs->GetCurrentTabContainer(); }
$sCurrentTab = $this->m_oTabs->GetCurrentTab(); else
{
if (!empty($sCurrentTabContainer) && !empty($sCurrentTab)) return parent::start_capture();
{ }
$iOffset = $this->m_oTabs->GetCurrentTabLength(); }
return array('tc' => $sCurrentTabContainer, 'tab' => $sCurrentTab, 'offset' => $iOffset);
} /**
else * Returns the part of the html output that occurred since the call to start_capture
{ * and removes this part from the current html output
return parent::start_capture(); * @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)
/** {
* Returns the part of the html output that occurred since the call to start_capture if (is_array($offset))
* and removes this part from the current html output {
* @param $offset mixed The value returned by start_capture if ($this->m_oTabs->TabExists($offset['tc'], $offset['tab']))
* @return string The part of the html output that was added since the call to start_capture {
*/ $sCaptured = $this->m_oTabs->TruncateTab($offset['tc'], $offset['tab'], $offset['offset']);
public function end_capture($offset) }
{ else
if (is_array($offset)) {
{ $sCaptured = '';
if ($this->m_oTabs->TabExists($offset['tc'], $offset['tab'])) }
{ }
$sCaptured = $this->m_oTabs->TruncateTab($offset['tc'], $offset['tab'], $offset['offset']); else
} {
else $sCaptured = parent::end_capture($offset);
{ }
$sCaptured = ''; return $sCaptured;
} }
}
else /**
{ * Add any text or HTML fragment (identified by an ID) at the end of the body of the page
$sCaptured = parent::end_capture($offset); * This is useful to add hidden content, DIVs or FORMs that should not
} * be embedded into each other.
return $sCaptured; */
} public function add_at_the_end($s_html, $sId = '')
{
/** if ($sId != '')
* 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 $this->add_script("$('#{$sId}').remove();"); // Remove any previous instance of the same Id
* be embedded into each other. }
*/ $this->s_deferred_content .= $s_html;
public function add_at_the_end($s_html, $sId = '') }
{
if ($sId != '') /**
{ * Adds a script to be executed when the DOM is ready (typical JQuery use)
$this->add_script("$('#{$sId}').remove();"); // Remove any previous instance of the same Id * NOT implemented in this version of the class.
} * @return void
$this->s_deferred_content .= $s_html; */
} public function add_ready_script($sScript)
{
/** $this->m_sReadyScript .= $sScript."\n";
* Adds a script to be executed when the DOM is ready (typical JQuery use) }
* NOT implemented in this version of the class.
* @return void /**
*/ * Cannot be called in this context, since Ajax pages do not share
public function add_ready_script($sScript) * any context with the calling page !!
{ */
$this->m_sReadyScript .= $sScript."\n"; public function GetUniqueId()
} {
assert(false);
/** return 0;
* Cannot be called in this context, since Ajax pages do not share }
* any context with the calling page !!
*/ public static function FilterXSS($sHTML)
public function GetUniqueId() {
{ return str_ireplace(array('<script', '</script>'), array('<!-- <removed-script', '</removed-script> -->'), $sHTML);
assert(false); }
return 0; }
}
public static function FilterXSS($sHTML)
{
return str_ireplace(array('<script', '</script>'), array('<!-- <removed-script', '</removed-script> -->'), $sHTML);
}
}

View File

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

View File

@@ -1,409 +1,362 @@
<?php <?php
// Copyright (C) 2010-2018 Combodo SARL // Copyright (C) 2010-2012 Combodo SARL
// //
// This file is part of iTop. // 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 // 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 // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// iTop is distributed in the hope that it will be useful, // iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details. // GNU Affero General Public License for more details.
// //
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* Class ApplicationContext * Class ApplicationContext
* *
* @copyright Copyright (C) 2010-2018 Combodo SARL * @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
require_once(APPROOT."/application/utils.inc.php"); require_once(APPROOT."/application/utils.inc.php");
/** /**
* Interface for directing end-users to the relevant application * Interface for directing end-users to the relevant application
*/ */
interface iDBObjectURLMaker interface iDBObjectURLMaker
{ {
/** public static function MakeObjectURL($sClass, $iId);
* @param string $sClass }
* @param string $iId
* /**
* @return string * Direct end-users to the standard iTop application: UI.php
*/ */
public static function MakeObjectURL($sClass, $iId); class iTopStandardURLMaker implements iDBObjectURLMaker
} {
public static function MakeObjectURL($sClass, $iId)
/** {
* Direct end-users to the standard iTop application: UI.php $sPage = DBObject::ComputeStandardUIPage($sClass);
*/ $sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
class iTopStandardURLMaker implements iDBObjectURLMaker $sUrl = "{$sAbsoluteUrl}pages/$sPage?operation=details&class=$sClass&id=$iId";
{ return $sUrl;
/** }
* @param string $sClass }
* @param string $iId
* /**
* @return string * Direct end-users to the standard Portal application
* @throws \Exception */
*/ class PortalURLMaker implements iDBObjectURLMaker
public static function MakeObjectURL($sClass, $iId) {
{ public static function MakeObjectURL($sClass, $iId)
$sPage = DBObject::ComputeStandardUIPage($sClass); {
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot(); $sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
$sUrl = "{$sAbsoluteUrl}pages/$sPage?operation=details&class=$sClass&id=$iId"; $sUrl = "{$sAbsoluteUrl}portal/index.php?operation=details&class=$sClass&id=$iId";
return $sUrl; return $sUrl;
} }
} }
/**
* Direct end-users to the standard Portal application /**
*/ * Helper class to store and manipulate the parameters that make the application's context
class PortalURLMaker implements iDBObjectURLMaker *
{ * Usage:
/** * 1) Build the application's context by constructing the object
* @param string $sClass * (the object will read some of the page's parameters)
* @param string $iId *
* * 2) Add these parameters to hyperlinks or to forms using the helper, functions
* @return string * GetForLink(), GetForForm() or GetAsHash()
* @throws \Exception */
*/ class ApplicationContext
public static function MakeObjectURL($sClass, $iId) {
{ protected $aNames;
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot(); protected $aValues;
$sUrl = "{$sAbsoluteUrl}portal/index.php?operation=details&class=$sClass&id=$iId"; protected static $aDefaultValues; // Cache shared among all instances
return $sUrl;
} public function __construct($bReadContext = true)
} {
$this->aNames = array(
'org_id', 'menu'
/** );
* Helper class to store and manipulate the parameters that make the application's context if ($bReadContext)
* {
* Usage: $this->ReadContext();
* 1) Build the application's context by constructing the object }
* (the object will read some of the page's parameters)
* }
* 2) Add these parameters to hyperlinks or to forms using the helper, functions
* GetForLink(), GetForForm() or GetAsHash() /**
*/ * Read the context directly in the PHP parameters (either POST or GET)
class ApplicationContext * return nothing
{ */
public static $m_sUrlMakerClass = null; protected function ReadContext()
protected static $m_aPluginProperties = null; {
protected static $aDefaultValues; // Cache shared among all instances if (!isset(self::$aDefaultValues))
{
protected $aNames; self::$aDefaultValues = array();
protected $aValues; $aContext = utils::ReadParam('c', array(), false, 'context_param');
foreach($this->aNames as $sName)
/** {
* ApplicationContext constructor. $sValue = isset($aContext[$sName]) ? $aContext[$sName] : '';
* // TO DO: check if some of the context parameters are mandatory (or have default values)
* @param bool $bReadContext if (!empty($sValue))
* {
* @throws \Exception self::$aDefaultValues[$sName] = $sValue;
*/ }
public function __construct($bReadContext = true) // Hmm, there must be a better (more generic) way to handle the case below:
{ // When there is only one possible (allowed) organization, the context must be
$this->aNames = array( // fixed to this org
'org_id', 'menu' if ($sName == 'org_id')
); {
if ($bReadContext) if (MetaModel::IsValidClass('Organization'))
{ {
$this->ReadContext(); $oSearchFilter = new DBObjectSearch('Organization');
} $oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
$oSet = new CMDBObjectSet($oSearchFilter);
} $iCount = $oSet->Count();
if ($iCount == 1)
/** {
* Read the context directly in the PHP parameters (either POST or GET) // Only one possible value for org_id, set it in the context
* return nothing $oOrg = $oSet->Fetch();
* self::$aDefaultValues[$sName] = $oOrg->GetKey();
* @throws \Exception }
*/ }
protected function ReadContext() }
{ }
if (!isset(self::$aDefaultValues)) }
{ $this->aValues = self::$aDefaultValues;
self::$aDefaultValues = array(); }
$aContext = utils::ReadParam('c', array(), false, 'context_param');
foreach($this->aNames as $sName) /**
{ * Returns the current value for the given parameter
$sValue = isset($aContext[$sName]) ? $aContext[$sName] : ''; * @param string $sParamName Name of the parameter to read
// TO DO: check if some of the context parameters are mandatory (or have default values) * @return mixed The value for this parameter
if (!empty($sValue)) */
{ public function GetCurrentValue($sParamName, $defaultValue = '')
self::$aDefaultValues[$sName] = $sValue; {
} if (isset($this->aValues[$sParamName]))
// Hmm, there must be a better (more generic) way to handle the case below: {
// When there is only one possible (allowed) organization, the context must be return $this->aValues[$sParamName];
// fixed to this org unless there is only one organization in the system then }
// no filter is applied return $defaultValue;
if ($sName == 'org_id') }
{
if (MetaModel::IsValidClass('Organization')) /**
{ * Returns the context as string with the format name1=value1&name2=value2....
$oSearchFilter = new DBObjectSearch('Organization'); * return string The context as a string to be appended to an href property
$oSet = new CMDBObjectSet($oSearchFilter); */
$iCount = $oSet->CountWithLimit(2); public function GetForLink()
if ($iCount > 1) {
{ $aParams = array();
$oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true); foreach($this->aValues as $sName => $sValue)
$oSet = new CMDBObjectSet($oSearchFilter); {
$iCount = $oSet->CountWithLimit(2); $aParams[] = "c[$sName]".'='.urlencode($sValue);
if ($iCount == 1) }
{ return implode("&", $aParams);
// Only one possible value for org_id, set it in the context }
$oOrg = $oSet->Fetch();
self::$aDefaultValues[$sName] = $oOrg->GetKey(); /**
} * Returns the context as sequence of input tags to be inserted inside a <form> tag
} * return string The context as a sequence of <input type="hidden" /> tags
} */
} public function GetForForm()
} {
} $sContext = "";
$this->aValues = self::$aDefaultValues; foreach($this->aValues as $sName => $sValue)
} {
$sContext .= "<input type=\"hidden\" name=\"c[$sName]\" value=\"".htmlentities($sValue, ENT_QUOTES, 'UTF-8')."\" />\n";
/** }
* Returns the current value for the given parameter return $sContext;
* }
* @param string $sParamName Name of the parameter to read
* @param string $defaultValue /**
* * Returns the context as a hash array 'parameter_name' => value
* @return mixed The value for this parameter * return array The context information
*/ */
public function GetCurrentValue($sParamName, $defaultValue = '') public function GetAsHash()
{ {
if (isset($this->aValues[$sParamName])) $aReturn = array();
{ foreach($this->aValues as $sName => $sValue)
return $this->aValues[$sParamName]; {
} $aReturn["c[$sName]"] = $sValue;
return $defaultValue; }
} return $aReturn;
}
/**
* Returns the context as string with the format name1=value1&name2=value2.... /**
* @return string The context as a string to be appended to an href property * Returns an array of the context parameters NAMEs
*/ * @return array The list of context parameters
public function GetForLink() */
{ public function GetNames()
$aParams = array(); {
foreach($this->aValues as $sName => $sValue) return $this->aNames;
{ }
$aParams[] = "c[$sName]".'='.urlencode($sValue); /**
} * Removes the specified parameter from the context, for example when the same parameter
return implode("&", $aParams); * is already a search parameter
} * @param string $sParamName Name of the parameter to remove
* @return none
/** */
* Returns the context as sequence of input tags to be inserted inside a <form> tag public function Reset($sParamName)
* @return string The context as a sequence of <input type="hidden" /> tags {
*/ if (isset($this->aValues[$sParamName]))
public function GetForForm() {
{ unset($this->aValues[$sParamName]);
$sContext = ""; }
foreach($this->aValues as $sName => $sValue) }
{
$sContext .= "<input type=\"hidden\" name=\"c[$sName]\" value=\"".htmlentities($sValue, ENT_QUOTES, 'UTF-8')."\" />\n"; /**
} * Initializes the given object with the default values provided by the context
return $sContext; */
} public function InitObjectFromContext(DBObject &$oObj)
{
/** $sClass = get_class($oObj);
* Returns the context as a hash array 'parameter_name' => value foreach($this->GetNames() as $key)
* @return array The context information {
*/ $aCallSpec = array($sClass, 'MapContextParam');
public function GetAsHash() if (is_callable($aCallSpec))
{ {
$aReturn = array(); $sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
foreach($this->aValues as $sName => $sValue)
{ if (MetaModel::IsValidAttCode($sClass, $sAttCode))
$aReturn["c[$sName]"] = $sValue; {
} $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
return $aReturn; if ($oAttDef->IsWritable())
} {
$value = $this->GetCurrentValue($key, null);
/** if (!is_null($value))
* Returns an array of the context parameters NAMEs {
* @return array The list of context parameters $oObj->Set($sAttCode, $value);
*/ }
public function GetNames() }
{ }
return $this->aNames; }
} }
/** }
* Removes the specified parameter from the context, for example when the same parameter
* is already a search parameter static $m_sUrlMakerClass = null;
* @param string $sParamName Name of the parameter to remove
*/ /**
public function Reset($sParamName) * Set the current application url provider
{ * @param sClass string Class implementing iDBObjectURLMaker
if (isset($this->aValues[$sParamName])) * @return void
{ */
unset($this->aValues[$sParamName]); public static function SetUrlMakerClass($sClass = 'iTopStandardURLMaker')
} {
} $sPrevious = self::GetUrlMakerClass();
/** self::$m_sUrlMakerClass = $sClass;
* Initializes the given object with the default values provided by the context $_SESSION['UrlMakerClass'] = $sClass;
*
* @param \DBObject $oObj return $sPrevious;
* }
* @throws \Exception
* @throws \CoreUnexpectedValue /**
*/ * Get the current application url provider
public function InitObjectFromContext(DBObject &$oObj) * @return string the name of the class
{ */
$sClass = get_class($oObj); public static function GetUrlMakerClass()
foreach($this->GetNames() as $key) {
{ if (is_null(self::$m_sUrlMakerClass))
$aCallSpec = array($sClass, 'MapContextParam'); {
if (is_callable($aCallSpec)) if (isset($_SESSION['UrlMakerClass']))
{ {
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter self::$m_sUrlMakerClass = $_SESSION['UrlMakerClass'];
}
if (MetaModel::IsValidAttCode($sClass, $sAttCode)) else
{ {
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); self::$m_sUrlMakerClass = 'iTopStandardURLMaker';
if ($oAttDef->IsWritable()) }
{ }
$value = $this->GetCurrentValue($key, null); return self::$m_sUrlMakerClass;
if (!is_null($value)) }
{
$oObj->Set($sAttCode, $value); /**
} * Get the current application url provider
} * @return string the name of the class
} */
} public static function MakeObjectUrl($sObjClass, $sObjKey, $sUrlMakerClass = null, $bWithNavigationContext = true)
} {
} $oAppContext = new ApplicationContext();
/** if (is_null($sUrlMakerClass))
* Set the current application url provider {
* @param string $sClass Class implementing iDBObjectURLMaker $sUrlMakerClass = self::GetUrlMakerClass();
* @return string }
*/ $sUrl = call_user_func(array($sUrlMakerClass, 'MakeObjectUrl'), $sObjClass, $sObjKey);
public static function SetUrlMakerClass($sClass = 'iTopStandardURLMaker') if (strlen($sUrl) > 0)
{ {
$sPrevious = self::GetUrlMakerClass(); if ($bWithNavigationContext)
{
self::$m_sUrlMakerClass = $sClass; return $sUrl."&".$oAppContext->GetForLink();
$_SESSION['UrlMakerClass'] = $sClass; }
else
return $sPrevious; {
} return $sUrl;
}
/** }
* Get the current application url provider else
* @return string the name of the class {
*/ return '';
public static function GetUrlMakerClass() }
{ }
if (is_null(self::$m_sUrlMakerClass))
{ protected static $m_aPluginProperties = null;
if (isset($_SESSION['UrlMakerClass']))
{ /**
self::$m_sUrlMakerClass = $_SESSION['UrlMakerClass']; * Load plugin properties for the current session
} * @return void
else */
{ protected static function LoadPluginProperties()
self::$m_sUrlMakerClass = 'iTopStandardURLMaker'; {
} if (isset($_SESSION['PluginProperties']))
} {
return self::$m_sUrlMakerClass; self::$m_aPluginProperties = $_SESSION['PluginProperties'];
} }
else
/** {
* Get the current application url provider self::$m_aPluginProperties = array();
* }
* @param string $sObjClass }
* @param string $sObjKey
* @param null $sUrlMakerClass /**
* @param bool $bWithNavigationContext * Set plugin properties
* * @param sPluginClass string Class implementing any plugin interface
* @return string the name of the class * @param sProperty string Name of the property
* @throws \Exception * @param value scalar Value (numeric or string)
*/ * @return void
public static function MakeObjectUrl($sObjClass, $sObjKey, $sUrlMakerClass = null, $bWithNavigationContext = true) */
{ public static function SetPluginProperty($sPluginClass, $sProperty, $value)
$oAppContext = new ApplicationContext(); {
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
if (is_null($sUrlMakerClass))
{ self::$m_aPluginProperties[$sPluginClass][$sProperty] = $value;
$sUrlMakerClass = self::GetUrlMakerClass(); $_SESSION['PluginProperties'][$sPluginClass][$sProperty] = $value;
} }
$sUrl = call_user_func(array($sUrlMakerClass, 'MakeObjectUrl'), $sObjClass, $sObjKey);
if (strlen($sUrl) > 0) /**
{ * Get plugin properties
if ($bWithNavigationContext) * @param sPluginClass string Class implementing any plugin interface
{ * @return array of sProperty=>value pairs
return $sUrl."&".$oAppContext->GetForLink(); */
} public static function GetPluginProperties($sPluginClass)
else {
{ if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
return $sUrl;
} if (array_key_exists($sPluginClass, self::$m_aPluginProperties))
} {
else return self::$m_aPluginProperties[$sPluginClass];
{ }
return ''; else
} {
} return array();
}
/** }
* Load plugin properties for the current session
* @return void }
*/ ?>
protected static function LoadPluginProperties()
{
if (isset($_SESSION['PluginProperties']))
{
self::$m_aPluginProperties = $_SESSION['PluginProperties'];
}
else
{
self::$m_aPluginProperties = array();
}
}
/**
* Set plugin properties
* @param string $sPluginClass Class implementing any plugin interface
* @param string $sProperty Name of the property
* @param mixed $value Value (numeric or string)
* @return void
*/
public static function SetPluginProperty($sPluginClass, $sProperty, $value)
{
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
self::$m_aPluginProperties[$sPluginClass][$sProperty] = $value;
$_SESSION['PluginProperties'][$sPluginClass][$sProperty] = $value;
}
/**
* Get plugin properties
* @param string $sPluginClass Class implementing any plugin interface
* @return array of sProperty=>value pairs
*/
public static function GetPluginProperties($sPluginClass)
{
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
if (array_key_exists($sPluginClass, self::$m_aPluginProperties))
{
return self::$m_aPluginProperties[$sPluginClass];
}
else
{
return array();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,60 +1,60 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010-2012 Combodo SARL
// //
// This file is part of iTop. // 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 // 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 // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// iTop is distributed in the hope that it will be useful, // iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details. // GNU Affero General Public License for more details.
// //
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* This class manages the audit "categories". Each category defines a set of objects * This class manages the audit "categories". Each category defines a set of objects
* to check and is linked to a set of rules that determine the valid or invalid objects * to check and is linked to a set of rules that determine the valid or invalid objects
* inside the set * inside the set
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
require_once(APPROOT.'/application/cmdbabstract.class.inc.php'); require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
class AuditCategory extends cmdbAbstractObject class AuditCategory extends cmdbAbstractObject
{ {
public static function Init() public static function Init()
{ {
$aParams = array $aParams = array
( (
"category" => "application, grant_by_profile", "category" => "application",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array('name'), "reconc_keys" => array('name'),
"db_table" => "priv_auditcategory", "db_table" => "priv_auditcategory",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
); );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeString("name", array("description"=>"Short name for this category", "allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("name", array("description"=>"Short name for this category", "allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeOQL("definition_set", array("allowed_values"=>null, "sql"=>"definition_set", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeOQL("definition_set", array("allowed_values"=>null, "sql"=>"definition_set", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeLinkedSet("rules_list", array("linked_class"=>"AuditRule", "ext_key_to_me"=>"category_id", "allowed_values"=>null, "count_min"=>0, "count_max"=>0, "depends_on"=>array(), "edit_mode" => LINKSET_EDITMODE_INPLACE, "tracking_level" => LINKSET_TRACKING_ALL))); MetaModel::Init_AddAttribute(new AttributeLinkedSet("rules_list", array("linked_class"=>"AuditRule", "ext_key_to_me"=>"category_id", "allowed_values"=>null, "count_min"=>0, "count_max"=>0, "depends_on"=>array(), "edit_mode" => LINKSET_EDITMODE_INPLACE)));
// Display lists // Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'definition_set', 'rules_list')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('details', array('name', 'description', 'definition_set', 'rules_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('description', )); // Attributes to be displayed for a list MetaModel::Init_SetZListItems('list', array('description', )); // Attributes to be displayed for a list
// Search criteria // Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'definition_set')); // Criteria of the std search form MetaModel::Init_SetZListItems('standard_search', array('name', 'description')); // Criteria of the std search form
MetaModel::Init_SetZListItems('default_search', array('name', 'description')); // Criteria of the default search form MetaModel::Init_SetZListItems('advanced_search', array('name', 'description', 'definition_set')); // Criteria of the advanced search form
} }
} }
?> ?>

View File

@@ -1,64 +1,64 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010-2012 Combodo SARL
// //
// This file is part of iTop. // 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 // 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 // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// iTop is distributed in the hope that it will be useful, // iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details. // GNU Affero General Public License for more details.
// //
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* This class manages the audit "rule" linked to a given audit category. * This class manages the audit "rule" linked to a given audit category.
* Each rule is based on an OQL expression that returns either the "good" objects * Each rule is based on an OQL expression that returns either the "good" objects
* or the "bad" ones. The core audit engines computes the complement to the definition * or the "bad" ones. The core audit engines computes the complement to the definition
* set when needed to obtain either the valid objects, or the ones with an error * set when needed to obtain either the valid objects, or the ones with an error
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
require_once(APPROOT.'/application/audit.category.class.inc.php'); require_once(APPROOT.'/application/audit.category.class.inc.php');
class AuditRule extends cmdbAbstractObject class AuditRule extends cmdbAbstractObject
{ {
public static function Init() public static function Init()
{ {
$aParams = array $aParams = array
( (
"category" => "application, grant_by_profile", "category" => "application",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array('name'), "reconc_keys" => array('name'),
"db_table" => "priv_auditrule", "db_table" => "priv_auditrule",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
"display_template" => "", "display_template" => "",
); );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeOQL("query", array("allowed_values"=>null, "sql"=>"query", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeOQL("query", array("allowed_values"=>null, "sql"=>"query", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("valid_flag", array("allowed_values"=>new ValueSetEnum('true,false'), "sql"=>"valid_flag", "default_value"=>"true", "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeEnum("valid_flag", array("allowed_values"=>new ValueSetEnum('true,false'), "sql"=>"valid_flag", "default_value"=>"true", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", array("allowed_values"=>null, "sql"=>"category_id", "targetclass"=>"AuditCategory", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeExternalKey("category_id", array("allowed_values"=>null, "sql"=>"category_id", "targetclass"=>"AuditCategory", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", array("allowed_values"=>null, "extkey_attcode"=> 'category_id', "target_attcode"=>"name"))); MetaModel::Init_AddAttribute(new AttributeExternalField("category_name", array("allowed_values"=>null, "extkey_attcode"=> 'category_id', "target_attcode"=>"name")));
// Display lists // Display lists
MetaModel::Init_SetZListItems('details', array('category_id', 'name', 'description', 'query', 'valid_flag')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('details', array('category_id', 'name', 'description', 'query', 'valid_flag')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('category_id', 'description', 'valid_flag')); // Attributes to be displayed for a list MetaModel::Init_SetZListItems('list', array('category_id', 'description', 'valid_flag')); // Attributes to be displayed for a list
// Search criteria // Search criteria
MetaModel::Init_SetZListItems('standard_search', array('category_id', 'name', 'description', 'valid_flag', 'query')); // Criteria of the std search form MetaModel::Init_SetZListItems('standard_search', array('category_id', 'name', 'description', 'valid_flag')); // Criteria of the std search form
MetaModel::Init_SetZListItems('default_search', array('name', 'description', 'category_id')); // Criteria of the advanced search form MetaModel::Init_SetZListItems('advanced_search', array('category_id', 'name', 'description', 'valid_flag', 'query')); // Criteria of the advanced search form
} }
} }
?> ?>

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -1,5 +1,5 @@
<?php <?php
// Copyright (C) 2010-2017 Combodo SARL // Copyright (C) 2010-2013 Combodo SARL
// //
// This file is part of iTop. // This file is part of iTop.
// //
@@ -21,10 +21,9 @@ require_once(APPROOT.'application/dashlet.class.inc.php');
require_once(APPROOT.'core/modelreflection.class.inc.php'); require_once(APPROOT.'core/modelreflection.class.inc.php');
/** /**
*
* A user editable dashboard page * A user editable dashboard page
* *
* @copyright Copyright (C) 2010-2017 Combodo SARL * @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
abstract class Dashboard abstract class Dashboard
@@ -50,11 +49,6 @@ abstract class Dashboard
$this->sId = $sId; $this->sId = $sId;
} }
/**
* @param $sXml
*
* @throws \Exception
*/
public function FromXml($sXml) public function FromXml($sXml)
{ {
$this->aCells = array(); // reset the content of the dashboard $this->aCells = array(); // reset the content of the dashboard
@@ -106,10 +100,10 @@ abstract class Dashboard
$oCellsList = $oCellsNode->getElementsByTagName('cell'); $oCellsList = $oCellsNode->getElementsByTagName('cell');
$aCellOrder = array(); $aCellOrder = array();
$iCellRank = 0; $iCellRank = 0;
/** @var \DOMElement $oCellNode */
foreach($oCellsList as $oCellNode) foreach($oCellsList as $oCellNode)
{ {
$oCellRank = $oCellNode->getElementsByTagName('rank')->item(0); $aDashletList = array();
$oCellRank = $oCellNode->getElementsByTagName('rank')->item(0);
if ($oCellRank) if ($oCellRank)
{ {
$iCellRank = (float)$oCellRank->textContent; $iCellRank = (float)$oCellRank->textContent;
@@ -119,16 +113,17 @@ abstract class Dashboard
$oDashletList = $oDashletsNode->getElementsByTagName('dashlet'); $oDashletList = $oDashletsNode->getElementsByTagName('dashlet');
$iRank = 0; $iRank = 0;
$aDashletOrder = array(); $aDashletOrder = array();
/** @var \DOMElement $oDomNode */
foreach($oDashletList as $oDomNode) foreach($oDashletList as $oDomNode)
{ {
$sDashletClass = $oDomNode->getAttribute('xsi:type');
$oRank = $oDomNode->getElementsByTagName('rank')->item(0); $oRank = $oDomNode->getElementsByTagName('rank')->item(0);
if ($oRank) if ($oRank)
{ {
$iRank = (float)$oRank->textContent; $iRank = (float)$oRank->textContent;
} }
$sId = $oDomNode->getAttribute('id');
$oNewDashlet = $this->InitDashletFromDOMNode($oDomNode); $oNewDashlet = new $sDashletClass($this->oMetaModel, $sId);
$oNewDashlet->FromDOMNode($oDomNode);
$aDashletOrder[] = array('rank' => $iRank, 'dashlet' => $oNewDashlet); $aDashletOrder[] = array('rank' => $iRank, 'dashlet' => $oNewDashlet);
} }
usort($aDashletOrder, array(get_class($this), 'SortOnRank')); usort($aDashletOrder, array(get_class($this), 'SortOnRank'));
@@ -152,41 +147,12 @@ abstract class Dashboard
} }
} }
/**
* @param \DOMElement $oDomNode
*
* @return mixed
*/
protected function InitDashletFromDOMNode($oDomNode)
{
$sId = $oDomNode->getAttribute('id');
$sDashletType = $oDomNode->getAttribute('xsi:type');
// Test if dashlet can be instanciated, otherwise (uninstalled, broken, ...) we display a placeholder
$sClass = static::GetDashletClassFromType($sDashletType);
/** @var \Dashlet $oNewDashlet */
$oNewDashlet = new $sClass($this->oMetaModel, $sId);
$oNewDashlet->SetDashletType($sDashletType);
$oNewDashlet->FromDOMNode($oDomNode);
return $oNewDashlet;
}
static function SortOnRank($aItem1, $aItem2) static function SortOnRank($aItem1, $aItem2)
{ {
return ($aItem1['rank'] > $aItem2['rank']) ? +1 : -1; return ($aItem1['rank'] > $aItem2['rank']) ? +1 : -1;
} }
/** /**
* Error handler to turn XML loading warnings into exceptions * Error handler to turn XML loading warnings into exceptions
*
* @param $errno
* @param $errstr
* @param $errfile
* @param $errline
*
* @return bool
* @throws \DOMException
*/ */
public static function ErrorHandler($errno, $errstr, $errfile, $errline) public static function ErrorHandler($errno, $errstr, $errfile, $errline)
{ {
@@ -216,12 +182,8 @@ abstract class Dashboard
return $sXml; return $sXml;
} }
/**
* @param \DOMElement $oDefinition
*/
public function ToDOMNode($oDefinition) public function ToDOMNode($oDefinition)
{ {
/** @var \DOMDocument $oDoc */
$oDoc = $oDefinition->ownerDocument; $oDoc = $oDefinition->ownerDocument;
$oNode = $oDoc->createElement('layout', $this->sLayoutClass); $oNode = $oDoc->createElement('layout', $this->sLayoutClass);
@@ -253,13 +215,12 @@ abstract class Dashboard
$iDashletRank = 0; $iDashletRank = 0;
$oDashletsNode = $oDoc->createElement('dashlets'); $oDashletsNode = $oDoc->createElement('dashlets');
$oCellNode->appendChild($oDashletsNode); $oCellNode->appendChild($oDashletsNode);
/** @var \Dashlet $oDashlet */
foreach ($aCell as $oDashlet) foreach ($aCell as $oDashlet)
{ {
$oNode = $oDoc->createElement('dashlet'); $oNode = $oDoc->createElement('dashlet');
$oDashletsNode->appendChild($oNode); $oDashletsNode->appendChild($oNode);
$oNode->setAttribute('id', $oDashlet->GetID()); $oNode->setAttribute('id', $oDashlet->GetID());
$oNode->setAttribute('xsi:type', $oDashlet->GetDashletType()); $oNode->setAttribute('xsi:type', get_class($oDashlet));
$oDashletRank = $oDoc->createElement('rank', $iDashletRank); $oDashletRank = $oDoc->createElement('rank', $iDashletRank);
$oNode->appendChild($oDashletRank); $oNode->appendChild($oDashletRank);
$iDashletRank++; $iDashletRank++;
@@ -283,12 +244,8 @@ abstract class Dashboard
{ {
$sDashletClass = $aDashletParams['dashlet_class']; $sDashletClass = $aDashletParams['dashlet_class'];
$sId = $aDashletParams['dashlet_id']; $sId = $aDashletParams['dashlet_id'];
/** @var \Dashlet $oNewDashlet */
$oNewDashlet = new $sDashletClass($this->oMetaModel, $sId); $oNewDashlet = new $sDashletClass($this->oMetaModel, $sId);
if (isset($aDashletParams['dashlet_type']))
{
$oNewDashlet->SetDashletType($aDashletParams['dashlet_type']);
}
$oForm = $oNewDashlet->GetForm(); $oForm = $oNewDashlet->GetForm();
$oForm->SetParamsContainer($sId); $oForm->SetParamsContainer($sId);
$oForm->SetPrefix(''); $oForm->SetPrefix('');
@@ -346,28 +303,31 @@ abstract class Dashboard
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int)$iAutoReloadSec); $this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int)$iAutoReloadSec);
} }
/**
* @param \Dashlet $oDashlet
*/
public function AddDashlet($oDashlet) public function AddDashlet($oDashlet)
{ {
$sId = $this->GetNewDashletId(); $sId = $this->GetNewDashletId();
$oDashlet->SetId($sId); $oDashlet->SetId($sId);
$this->aCells[] = array($oDashlet); $this->aCells[] = array($oDashlet);
} }
/** public function Render($oPage, $bEditMode = false, $aExtraParams = array())
* @param \WebPage $oPage * {
* @param array $aExtraParams $oPage->add('<h1>'.htmlentities(Dict::S($this->sTitle), ENT_QUOTES, 'UTF-8', false).'</h1>');
* $oLayout = new $this->sLayoutClass;
* @throws \ReflectionException $oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
*/ if (!$bEditMode)
public function RenderProperties($oPage, $aExtraParams = array()) {
$oPage->add_linked_script('../js/dashlet.js');
$oPage->add_linked_script('../js/dashboard.js');
}
}
public function RenderProperties($oPage)
{ {
// menu to pick a layout and edit other properties of the dashboard // menu to pick a layout and edit other properties of the dashboard
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Properties').'</div>'); $oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Properties').'</div>');
$sUrl = utils::GetAbsoluteUrlAppRoot(); $sUrl = utils::GetAbsoluteUrlAppRoot();
$oPage->add('<div style="text-align:center">'.Dict::S('UI:DashboardEdit:Layout').'</div>'); $oPage->add('<div style="text-align:center">'.Dict::S('UI:DashboardEdit:Layout').'</div>');
$oPage->add('<div id="select_layout" style="text-align:center">'); $oPage->add('<div id="select_layout" style="text-align:center">');
foreach( get_declared_classes() as $sLayoutClass) foreach( get_declared_classes() as $sLayoutClass)
@@ -385,13 +345,13 @@ abstract class Dashboard
} }
} }
$oPage->add('</div>'); $oPage->add('</div>');
$oForm = new DesignerForm(); $oForm = new DesignerForm();
$oField = new DesignerHiddenField('dashboard_id', '', $this->sId); $oField = new DesignerHiddenField('dashboard_id', '', $this->sId);
$oForm->AddField($oField); $oForm->AddField($oField);
$oField = new DesignerTextField('dashboard_title', Dict::S('UI:DashboardEdit:DashboardTitle'), $this->sTitle); $oField = new DesignerLongTextField('dashboard_title', Dict::S('UI:DashboardEdit:DashboardTitle'), $this->sTitle);
$oForm->AddField($oField); $oForm->AddField($oField);
$oField = new DesignerBooleanField('auto_reload', Dict::S('UI:DashboardEdit:AutoReload'), $this->bAutoReload); $oField = new DesignerBooleanField('auto_reload', Dict::S('UI:DashboardEdit:AutoReload'), $this->bAutoReload);
@@ -402,8 +362,8 @@ abstract class Dashboard
$oForm->AddField($oField); $oForm->AddField($oField);
$this->SetFormParams($oForm, $aExtraParams); $this->SetFormParams($oForm);
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard'); $oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
$oPage->add('</div>'); $oPage->add('</div>');
@@ -447,86 +407,17 @@ abstract class Dashboard
EOF EOF
); );
} }
/** public function RenderDashletsSelection($oPage)
* @param \iTopWebPage $oPage
* @param bool $bEditMode
* @param array $aExtraParams
* @param bool $bCanEdit
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
{
$oPage->add('<div class="dashboard-title-line"><div class="dashboard-title">'.htmlentities(Dict::S($this->sTitle), ENT_QUOTES, 'UTF-8', false).'</div></div>');
$oLayout = new $this->sLayoutClass;
/** @var \DashboardLayoutMultiCol $oLayout */
$oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
if (!$bEditMode)
{
$oPage->add_linked_script('../js/dashlet.js');
$oPage->add_linked_script('../js/dashboard.js');
}
}
public function RenderDashletsSelection(WebPage $oPage)
{ {
// Toolbox/palette to drag and drop dashlets // Toolbox/palette to drag and drop dashlets
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Dashlets').'</div>'); $oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Dashlets').'</div>');
$sUrl = utils::GetAbsoluteUrlAppRoot(); $sUrl = utils::GetAbsoluteUrlAppRoot();
$oPage->add('<div id="select_dashlet" style="text-align:center; max-height:120px; overflow-y:auto;">'); $oPage->add('<div id="select_dashlet" style="text-align:center">');
$aAvailableDashlets = $this->GetAvailableDashlets();
foreach($aAvailableDashlets as $sDashletClass => $aInfo)
{
$oPage->add('<span dashlet_class="'.$sDashletClass.'" class="dashlet_icon ui-widget-content ui-corner-all" id="dashlet_'.$sDashletClass.'" title="'.$aInfo['label'].'" style="width:34px; height:34px; display:inline-block; margin:2px;"><img src="'.$sUrl.$aInfo['icon'].'" /></span>');
}
$oPage->add('</div>');
$oPage->add('</div>');
$oPage->add_ready_script("$('.dashlet_icon').draggable({helper: 'clone', appendTo: 'body', zIndex: 10000, revert:'invalid'});");
}
public function RenderDashletsProperties(WebPage $oPage, $aExtraParams = array())
{
// Toolbox/palette to edit the properties of each dashlet
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:DashletProperties').'</div>');
$oPage->add('<div id="dashlet_properties" style="text-align:center">');
foreach($this->aCells as $aCell)
{
/** @var \Dashlet $oDashlet */
foreach($aCell as $oDashlet)
{
$sId = $oDashlet->GetID();
if ($oDashlet->IsVisible())
{
$oPage->add('<div class="dashlet_properties" id="dashlet_properties_'.$sId.'" style="display:none">');
$oForm = $oDashlet->GetForm();
$this->SetFormParams($oForm, $aExtraParams);
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
$oPage->add('</div>');
}
}
}
$oPage->add('</div>');
$oPage->add('</div>');
}
/**
* Return an array of dashlets available for selection.
*
* @return array
* @throws \ReflectionException
*/
protected function GetAvailableDashlets()
{
$aDashlets = array();
foreach( get_declared_classes() as $sDashletClass) foreach( get_declared_classes() as $sDashletClass)
{ {
// DashletUnknown is not among the selection as it is just a fallback for dashlets that can't instanciated. if (is_subclass_of($sDashletClass, 'Dashlet'))
if ( is_subclass_of($sDashletClass, 'Dashlet') && !in_array($sDashletClass, array('DashletUnknown', 'DashletProxy')) )
{ {
$oReflection = new ReflectionClass($sDashletClass); $oReflection = new ReflectionClass($sDashletClass);
if (!$oReflection->isAbstract()) if (!$oReflection->isAbstract())
@@ -537,13 +428,42 @@ EOF
{ {
$aCallSpec = array($sDashletClass, 'GetInfo'); $aCallSpec = array($sDashletClass, 'GetInfo');
$aInfo = call_user_func($aCallSpec); $aInfo = call_user_func($aCallSpec);
$aDashlets[$sDashletClass] = $aInfo; $oPage->add('<span dashlet_class="'.$sDashletClass.'" class="dashlet_icon ui-widget-content ui-corner-all" id="dashlet_'.$sDashletClass.'" title="'.$aInfo['label'].'" style="width:34px; height:34px; display:inline-block; margin:2px;"><img src="'.$sUrl.$aInfo['icon'].'" /></span>');
} }
} }
} }
} }
$oPage->add('</div>');
return $aDashlets; $oPage->add('</div>');
$oPage->add_ready_script("$('.dashlet_icon').draggable({helper: 'clone', appendTo: 'body', zIndex: 10000, revert:'invalid'});");
}
public function RenderDashletsProperties($oPage)
{
// Toolbox/palette to edit the properties of each dashlet
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:DashletProperties').'</div>');
$oPage->add('<div id="dashlet_properties" style="text-align:center">');
foreach($this->aCells as $aCell)
{
foreach($aCell as $oDashlet)
{
$sId = $oDashlet->GetID();
$sClass = get_class($oDashlet);
if ($oDashlet->IsVisible())
{
$oPage->add('<div class="dashlet_properties" id="dashlet_properties_'.$sId.'" style="display:none">');
$oForm = $oDashlet->GetForm();
$this->SetFormParams($oForm);
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
$oPage->add('</div>');
}
}
}
$oPage->add('</div>');
$oPage->add('</div>');
} }
protected function GetNewDashletId() protected function GetNewDashletId()
@@ -551,7 +471,6 @@ EOF
$iNewId = 0; $iNewId = 0;
foreach($this->aCells as $aDashlets) foreach($this->aCells as $aDashlets)
{ {
/** @var \Dashlet $oDashlet */
foreach($aDashlets as $oDashlet) foreach($aDashlets as $oDashlet)
{ {
$iNewId = max($iNewId, (int)$oDashlet->GetID()); $iNewId = max($iNewId, (int)$oDashlet->GetID());
@@ -559,39 +478,13 @@ EOF
} }
return $iNewId + 1; return $iNewId + 1;
} }
/** abstract protected function SetFormParams($oForm);
* @param $oForm
* @param array $aExtraParams
*
* @return mixed
*/
abstract protected function SetFormParams($oForm, $aExtraParams = array());
public static function GetDashletClassFromType($sType, $oFactory = null)
{
if (is_subclass_of($sType, 'Dashlet'))
{
return $sType;
}
return 'DashletUnknown';
}
/**
* @return mixed
*/
public function GetId()
{
return $this->sId;
}
} }
class RuntimeDashboard extends Dashboard class RuntimeDashboard extends Dashboard
{ {
protected $bCustomized; protected $bCustomized;
private $sDefinitionFile = '';
private $sReloadURL = null;
public function __construct($sId) public function __construct($sId)
{ {
@@ -604,17 +497,10 @@ class RuntimeDashboard extends Dashboard
{ {
$this->bCustomized = $bCustomized; $this->bCustomized = $bCustomized;
} }
/** protected function SetFormParams($oForm)
* @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)); $oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property'));
} }
public function Save() public function Save()
@@ -629,6 +515,8 @@ class RuntimeDashboard extends Dashboard
// Assuming there is at most one couple {user, menu}! // Assuming there is at most one couple {user, menu}!
$oUserDashboard = $oUDSet->Fetch(); $oUserDashboard = $oUDSet->Fetch();
$oUserDashboard->Set('contents', $sXml); $oUserDashboard->Set('contents', $sXml);
$oUserDashboard->DBUpdate();
} }
else else
{ {
@@ -637,10 +525,9 @@ class RuntimeDashboard extends Dashboard
$oUserDashboard->Set('user_id', UserRights::GetUserId()); $oUserDashboard->Set('user_id', UserRights::GetUserId());
$oUserDashboard->Set('menu_code', $this->sId); $oUserDashboard->Set('menu_code', $this->sId);
$oUserDashboard->Set('contents', $sXml); $oUserDashboard->Set('contents', $sXml);
}
utils::PushArchiveMode(false); $oUserDashboard->DBInsert();
$oUserDashboard->DBWrite(); }
utils::PopArchiveMode();
} }
public function Revert() public function Revert()
@@ -653,270 +540,42 @@ class RuntimeDashboard extends Dashboard
{ {
// Assuming there is at most one couple {user, menu}! // Assuming there is at most one couple {user, menu}!
$oUserDashboard = $oUDSet->Fetch(); $oUserDashboard = $oUDSet->Fetch();
utils::PushArchiveMode(false);
$oUserDashboard->DBDelete(); $oUserDashboard->DBDelete();
utils::PopArchiveMode();
} }
} }
/** public function RenderEditionTools($oPage)
* @param string $sDashboardFile file name relative to the current module folder
* @param string $sDashBoardId code of the dashboard either menu_id or <class>__<attcode>
*
* @return null|RuntimeDashboard
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
public static function GetDashboard($sDashboardFile, $sDashBoardId)
{ {
$bCustomized = false; $sEditMenu = "<td><span id=\"DashboardMenu\"><ul><li><img src=\"../images/edit.png\"><ul>";
if (!appUserPreferences::GetPref('display_original_dashboard_'.$sDashBoardId, false))
{
// Search for an eventual user defined dashboard
$oUDSearch = new DBObjectSearch('UserDashboard');
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oUDSearch->AddCondition('menu_code', $sDashBoardId, '=');
$oUDSet = new DBObjectSet($oUDSearch);
if ($oUDSet->Count() > 0)
{
// Assuming there is at most one couple {user, menu}!
$oUserDashboard = $oUDSet->Fetch();
$sDashboardDefinition = $oUserDashboard->Get('contents');
$bCustomized = true;
}
else
{
$sDashboardDefinition = @file_get_contents($sDashboardFile);
}
}
else
{
$sDashboardDefinition = @file_get_contents($sDashboardFile);
}
if ($sDashboardDefinition !== false)
{
$oDashboard = new RuntimeDashboard($sDashBoardId);
$oDashboard->FromXml($sDashboardDefinition);
$oDashboard->SetCustomFlag($bCustomized);
$oDashboard->SetDefinitionFile($sDashboardFile);
}
else
{
$oDashboard = null;
}
return $oDashboard;
}
/**
* @param \iTopWebPage $oPage
* @param bool $bEditMode
* @param array $aExtraParams (class and id of the current object
*
* @throws \Exception
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = array(), $bCanEdit = true)
{
if (!isset($aExtraParams['query_params']) && isset($aExtraParams['this->class']))
{
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
$aRenderParams = array('query_params' => $oObj->ToArgsForQuery());
}
else
{
$aRenderParams = $aExtraParams;
}
parent::Render($oPage, $bEditMode, $aRenderParams);
if (isset($aExtraParams['query_params']['this->object()']))
{
/** @var \DBObject $oObj */
$oObj = $aExtraParams['query_params']['this->object()'];
$aAjaxParams = array('this->class' => get_class($oObj), 'this->id' => $oObj->GetKey());
}
else
{
$aAjaxParams = $aExtraParams;
}
if (!$bEditMode && !$oPage->IsPrintableVersion())
{
$sId = $this->GetId();
$sDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $sId);
if ($this->GetAutoReload())
{
$sFile = addslashes($this->GetDefinitionFile());
$sExtraParams = json_encode($aAjaxParams);
$iReloadInterval = 1000 * $this->GetAutoReloadInterval();
$sReloadURL = $this->GetReloadURL();
$oPage->add_script(
<<<EOF
if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined')
{
clearInterval(AutoReloadDashboardId$sDivId);
delete AutoReloadDashboardId$sDivId;
}
AutoReloadDashboardId$sDivId = setInterval("ReloadDashboard$sDivId();", $iReloadInterval);
function ReloadDashboard$sDivId()
{
// Do not reload when a dialog box is active
if (!($('.ui-dialog:visible').length > 0) && $('.dashboard_contents#$sDivId').is(':visible'))
{
$('.dashboard_contents#$sDivId').block();
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
{ operation: 'reload_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL'},
function(data){
$('.dashboard_contents#$sDivId').html(data);
$('.dashboard_contents#$sDivId').unblock();
}
);
}
}
EOF
);
}
else
{
$oPage->add_script(
<<<EOF
if (typeof(AutoReloadDashboardId$sDivId) !== 'undefined')
{
clearInterval(AutoReloadDashboardId$sDivId);
delete AutoReloadDashboardId$sDivId;
}
EOF
);
}
if ($bCanEdit)
{
$this->RenderSelector($oPage, $aAjaxParams);
$this->RenderEditionTools($oPage, $aAjaxParams);
}
}
}
/**
* @param \iTopWebPage $oPage
* @param array $aAjaxParams
*/
protected function RenderSelector($oPage, $aAjaxParams = array())
{
$sId = $this->GetId();
$sDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $sId);
$sExtraParams = json_encode($aAjaxParams);
$sSelectorHtml = '<div class="dashboard-selector">';
if ($this->HasCustomDashboard())
{
$bStandardSelected = appUserPreferences::GetPref('display_original_dashboard_'.$sId, false);
$sStandard = Dict::S('UI:Toggle:StandardDashboard');
$sSelectorHtml .= '<div class="selector-label">'.$sStandard.'</div>';
$sSelectorHtml .= '<label class="switch"><input type="checkbox" onchange="ToggleDashboardSelector'.$sDivId.'();" '.($bStandardSelected ? '' : 'checked').'><span class="slider round"></span></label></input></label>';
$sCustom = Dict::S('UI:Toggle:CustomDashboard');
$sSelectorHtml .= '<div class="selector-label">'.$sCustom.'</div>';
}
$sSelectorHtml .= '</div>';
$sSelectorHtml = addslashes($sSelectorHtml);
$sFile = addslashes($this->GetDefinitionFile());
$sReloadURL = $this->GetReloadURL();
$oPage->add_ready_script(
<<<EOF
$('.dashboard-title').after('$sSelectorHtml');
EOF
);
$oPage->add_script(
<<<EOF
function ToggleDashboardSelector$sDivId()
{
$('.dashboard_contents#$sDivId').block();
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
{ operation: 'toggle_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL' },
function(data) {
$('.dashboard_contents#$sDivId').html(data);
$('.dashboard_contents#$sDivId').unblock();
}
);
}
EOF
);
}
protected function HasCustomDashboard()
{
try
{
// Search for an eventual user defined dashboard
$oUDSearch = new DBObjectSearch('UserDashboard');
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oUDSearch->AddCondition('menu_code', $this->GetId(), '=');
$oUDSet = new DBObjectSet($oUDSearch);
return ($oUDSet->Count() > 0);
}
catch (Exception $e)
{
return false;
}
}
/**
* @param \WebPage $oPage
* @param array $aExtraParams
*
* @throws \Exception
*/
protected function RenderEditionTools(WebPage $oPage, $aExtraParams)
{
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.iframe-transport.js');
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.fileupload.js');
$sEditMenu = "<div id=\"DashboardMenu\"><ul><li><img src=\"../images/pencil-menu.png\"><ul>";
$aActions = array(); $aActions = array();
$sFile = addslashes($this->sDefinitionFile); $oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:Edit'), "return EditDashboard('{$this->sId}')");
$sJSExtraParams = json_encode($aExtraParams); $aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
$bCanEdit = true;
if ($this->HasCustomDashboard())
{
$bCanEdit = !appUserPreferences::GetPref('display_original_dashboard_'.$this->GetId(), false);
}
if ($bCanEdit)
{
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:Edit'), "return EditDashboard('{$this->sId}', '$sFile', $sJSExtraParams)");
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
}
if ($this->bCustomized) if ($this->bCustomized)
{ {
$oRevert = new JSPopupMenuItem('UI:Dashboard:RevertConfirm', Dict::S('UI:Dashboard:Revert'), $oRevert = new JSPopupMenuItem('UI:Dashboard:RevertConfirm', Dict::S('UI:Dashboard:Revert'),
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}', $sJSExtraParams); else return false"); "if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}'); else return false");
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem(); $aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
} }
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions); utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions);
$sEditMenu .= $oPage->RenderPopupMenuItems($aActions); $sEditMenu .= $oPage->RenderPopupMenuItems($aActions);
$sEditMenu = addslashes($sEditMenu); $sEditMenu = addslashes($sEditMenu);
$sReloadURL = $this->GetReloadURL(); //$sEditBtn = addslashes('<div style="display: inline-block; height: 55px; width:200px;vertical-align:center;line-height:60px;text-align:left;"><button onclick="EditDashboard(\''.$this->sId.'\');">Edit This Page</button></div>');
$oPage->add_ready_script( $oPage->add_ready_script(
<<<EOF <<<EOF
$('.dashboard-title').after('$sEditMenu'); $('#logOffBtn').parent().before('$sEditMenu');
$('#DashboardMenu>ul').popupmenu(); $('#DashboardMenu>ul').popupmenu();
EOF EOF
); );
$oPage->add_script( $oPage->add_script(
<<<EOF <<<EOF
function EditDashboard(sId, sDashboardFile, aExtraParams) function EditDashboard(sId)
{ {
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'dashboard_editor', id: sId, file: sDashboardFile, extra_params: aExtraParams, reload_url: '$sReloadURL'}, $.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'dashboard_editor', id: sId},
function(data) function(data)
{ {
$('body').append(data); $('body').append(data);
@@ -924,12 +583,12 @@ function EditDashboard(sId, sDashboardFile, aExtraParams)
); );
return false; return false;
} }
function RevertDashboard(sId, aExtraParams) function RevertDashboard(sId)
{ {
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'revert_dashboard', dashboard_id: sId, extra_params: aExtraParams, reload_url: '$sReloadURL'}, $.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'revert_dashboard', dashboard_id: sId},
function(data) function(data)
{ {
location.reload(); $('body').append(data);
} }
); );
return false; return false;
@@ -938,14 +597,9 @@ EOF
); );
} }
/** public function RenderProperties($oPage)
* @param \WebPage $oPage
*
* @throws \ReflectionException
*/
public function RenderProperties($oPage, $aExtraParams = array())
{ {
parent::RenderProperties($oPage, $aExtraParams); parent::RenderProperties($oPage);
$oPage->add_ready_script( $oPage->add_ready_script(
<<<EOF <<<EOF
@@ -976,36 +630,16 @@ EOF
} }
/** public function RenderEditor($oPage)
* @param \iTopWebPage $oPage
*
* @param array $aExtraParams
*
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \ReflectionException
* @throws \Exception
*/
public function RenderEditor($oPage, $aExtraParams = array())
{ {
if (isset($aExtraParams['this->class']))
{
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
$aRenderParams = array('query_params' => $oObj->ToArgsForQuery());
}
else
{
$aRenderParams = $aExtraParams;
}
$sJSExtraParams = json_encode($aExtraParams);
$oPage->add('<div id="dashboard_editor">'); $oPage->add('<div id="dashboard_editor">');
$oPage->add('<div class="ui-layout-center">'); $oPage->add('<div class="ui-layout-center">');
$this->Render($oPage, true, $aRenderParams); $this->Render($oPage, true);
$oPage->add('</div>'); $oPage->add('</div>');
$oPage->add('<div class="ui-layout-east">'); $oPage->add('<div class="ui-layout-east">');
$this->RenderProperties($oPage, $aExtraParams); $this->RenderProperties($oPage);
$this->RenderDashletsSelection($oPage); $this->RenderDashletsSelection($oPage);
$this->RenderDashletsProperties($oPage, $aExtraParams); $this->RenderDashletsProperties($oPage);
$oPage->add('</div>'); $oPage->add('</div>');
$oPage->add('<div id="event_bus"/>'); // For exchanging messages between the panes, same as in the designer $oPage->add('<div id="event_bus"/>'); // For exchanging messages between the panes, same as in the designer
$oPage->add('</div>'); $oPage->add('</div>');
@@ -1019,9 +653,7 @@ EOF
$sAutoReload = $this->bAutoReload ? 'true' : 'false'; $sAutoReload = $this->bAutoReload ? 'true' : 'false';
$sAutoReloadSec = (string) $this->iAutoReloadSec; $sAutoReloadSec = (string) $this->iAutoReloadSec;
$sTitle = addslashes($this->sTitle); $sTitle = addslashes($this->sTitle);
$sFile = addslashes($this->GetDefinitionFile());
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php'; $sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
$sReloadURL = $this->GetReloadURL();
$sExitConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage')); $sExitConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage'));
$sCancelConfirmationMessage = addslashes(Dict::S('UI:CancelConfirmationMessage')); $sCancelConfirmationMessage = addslashes(Dict::S('UI:CancelConfirmationMessage'));
@@ -1051,7 +683,7 @@ $('#dashboard_editor').dialog({
} }
} }
window.bLeavingOnUserAction = true; window.bLeavingOnUserAction = true;
oDashboard.save($(this)); oDashboard.save();
} }, } },
{ text: "$sCancelButtonLabel", click: function() { { text: "$sCancelButtonLabel", click: function() {
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard'); var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
@@ -1073,8 +705,8 @@ $('#dashboard_editor').dialog({
$('#dashboard_editor .ui-layout-center').runtimedashboard({ $('#dashboard_editor .ui-layout-center').runtimedashboard({
dashboard_id: '$sId', layout_class: '$sLayoutClass', title: '$sTitle', dashboard_id: '$sId', layout_class: '$sLayoutClass', title: '$sTitle',
auto_reload: $sAutoReload, auto_reload_sec: $sAutoReloadSec, auto_reload: $sAutoReload, auto_reload_sec: $sAutoReloadSec,
submit_to: '$sUrl', submit_parameters: {operation: 'save_dashboard', file: '$sFile', extra_params: $sJSExtraParams, reload_url: '$sReloadURL'}, submit_to: '$sUrl', submit_parameters: {operation: 'save_dashboard'},
render_to: '$sUrl', render_parameters: {operation: 'render_dashboard', file: '$sFile', extra_params: $sJSExtraParams, reload_url: '$sReloadURL'}, render_to: '$sUrl', render_parameters: {operation: 'render_dashboard'},
new_dashlet_parameters: {operation: 'new_dashlet'} new_dashlet_parameters: {operation: 'new_dashlet'}
}); });
@@ -1120,66 +752,33 @@ EOF
public static function GetDashletCreationForm($sOQL = null) public static function GetDashletCreationForm($sOQL = null)
{ {
$oAppContext = new ApplicationContext();
$sContextMenuId = $oAppContext->GetCurrentValue('menu', null);
$oForm = new DesignerForm(); $oForm = new DesignerForm();
// Get the list of all 'dashboard' menus in which we can insert a dashlet // Get the list of all 'dashboard' menus in which we can insert a dashlet
$aAllMenus = ApplicationMenu::ReflectionMenuNodes(); $aAllMenus = ApplicationMenu::ReflectionMenuNodes();
$sRootMenuId = ApplicationMenu::GetRootMenuId($sContextMenuId);
$aAllowedDashboards = array(); $aAllowedDashboards = array();
$sDefaultDashboard = null; foreach($aAllMenus as $idx => $aMenu)
// Store the parent menus for acces check
$aParentMenus = array();
foreach($aAllMenus as $idx => $aMenu)
{
/** @var MenuNode $oMenu */
$oMenu = $aMenu['node'];
if (count(ApplicationMenu::GetChildren($oMenu->GetIndex())) > 0)
{
$aParentMenus[$oMenu->GetMenuId()] = $aMenu;
}
}
foreach($aAllMenus as $idx => $aMenu)
{ {
$oMenu = $aMenu['node']; $oMenu = $aMenu['node'];
if ($oMenu instanceof DashboardMenuNode) $sParentId = $aMenu['parent'];
{ if ($oMenu instanceof DashboardMenuNode)
// Get the root parent for access check {
$sParentId = $aMenu['parent']; $sMenuLabel = $oMenu->GetTitle();
$aParentMenu = $aParentMenus[$sParentId]; $sParentLabel = Dict::S('Menu:'.$sParentId);
while (isset($aParentMenus[$aParentMenu['parent']])) if ($sParentLabel != $sMenuLabel)
{ {
// grand parent exists $aAllowedDashboards[$oMenu->GetMenuId()] = $sParentLabel.' - '.$sMenuLabel;
$sParentId = $aParentMenu['parent']; }
$aParentMenu = $aParentMenus[$sParentId]; else
} {
/** @var \MenuNode $oParentMenu */ $aAllowedDashboards[$oMenu->GetMenuId()] = $sMenuLabel;
$oParentMenu = $aParentMenu['node']; }
if ($oMenu->IsEnabled() && $oParentMenu->IsEnabled()) }
{
$sMenuLabel = $oMenu->GetTitle();
$sParentLabel = Dict::S('Menu:'.$sParentId);
if ($sParentLabel != $sMenuLabel)
{
$aAllowedDashboards[$oMenu->GetMenuId()] = $sParentLabel.' - '.$sMenuLabel;
}
else
{
$aAllowedDashboards[$oMenu->GetMenuId()] = $sMenuLabel;
}
if (empty($sDefaultDashboard) && ($sRootMenuId == ApplicationMenu::GetRootMenuId($oMenu->GetMenuId())))
{
$sDefaultDashboard = $oMenu->GetMenuId();
}
}
}
} }
asort($aAllowedDashboards); asort($aAllowedDashboards);
$aKeys = array_keys($aAllowedDashboards); // Select the first one by default
$sDefaultDashboard = $aKeys[0];
$oField = new DesignerComboField('menu_id', Dict::S('UI:DashletCreation:Dashboard'), $sDefaultDashboard); $oField = new DesignerComboField('menu_id', Dict::S('UI:DashletCreation:Dashboard'), $sDefaultDashboard);
$oField->SetAllowedValues($aAllowedDashboards); $oField->SetAllowedValues($aAllowedDashboards);
$oField->SetMandatory(true); $oField->SetMandatory(true);
@@ -1213,7 +812,6 @@ EOF
{ {
$oSubForm = new DesignerForm(); $oSubForm = new DesignerForm();
$oMetaModel = new ModelReflectionRuntime(); $oMetaModel = new ModelReflectionRuntime();
/** @var \Dashlet $oDashlet */
$oDashlet = new $sDashletClass($oMetaModel, 0); $oDashlet = new $sDashletClass($oMetaModel, 0);
$oDashlet->GetPropertiesFieldsFromOQL($oSubForm, $sOQL); $oDashlet->GetPropertiesFieldsFromOQL($oSubForm, $sOQL);
@@ -1224,11 +822,7 @@ EOF
return $oForm; return $oForm;
} }
/**
* @param \WebPage $oPage
* @param $sOQL
*/
public static function GetDashletCreationDlgFromOQL($oPage, $sOQL) public static function GetDashletCreationDlgFromOQL($oPage, $sOQL)
{ {
$oPage->add('<div id="dashlet_creation_dlg">'); $oPage->add('<div id="dashlet_creation_dlg">');
@@ -1245,7 +839,7 @@ EOF
$oPage->add_ready_script( $oPage->add_ready_script(
<<<EOF <<<EOF
$('#dashlet_creation_dlg').dialog({ $('#dashlet_creation_dlg').dialog({
width: 600, width: 400,
modal: true, modal: true,
title: '$sDialogTitle', title: '$sDialogTitle',
buttons: [ buttons: [
@@ -1275,30 +869,4 @@ $('#dashlet_creation_dlg').dialog({
EOF EOF
); );
} }
/**
* @return string
*/
public function GetDefinitionFile()
{
return $this->sDefinitionFile;
}
/**
* @param string $sDefinitionFile
*/
public function SetDefinitionFile($sDefinitionFile)
{
$this->sDefinitionFile = $sDefinitionFile;
}
public function GetReloadURL()
{
return $this->sReloadURL;
}
public function SetReloadURL($sReloadURL)
{
$this->sReloadURL = $sReloadURL;
}
} }

View File

@@ -59,7 +59,6 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
$bNoVisibleFound = true; $bNoVisibleFound = true;
while($idx < count($aKeys) && $bNoVisibleFound) while($idx < count($aKeys) && $bNoVisibleFound)
{ {
/** @var \Dashlet $oDashlet */
$oDashlet = $aDashlets[$aKeys[$idx]]; $oDashlet = $aDashlets[$aKeys[$idx]];
if ($oDashlet->IsVisible()) if ($oDashlet->IsVisible())
{ {
@@ -99,19 +98,13 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
return $aCells; return $aCells;
} }
/**
* @param \WebPage $oPage
* @param $aCells
* @param bool $bEditMode
* @param array $aExtraParams
*/
public function Render($oPage, $aCells, $bEditMode = false, $aExtraParams = array()) public function Render($oPage, $aCells, $bEditMode = false, $aExtraParams = array())
{ {
// Trim the list of cells to remove the invisible/empty ones at the end of the array // Trim the list of cells to remove the invisible/empty ones at the end of the array
$aCells = $this->TrimCellsArray($aCells); $aCells = $this->TrimCellsArray($aCells);
$oPage->add('<table style="width:100%;table-layout:fixed;"><tbody>'); $oPage->add('<table style="width:100%"><tbody>');
$iCellIdx = 0; $iCellIdx = 0;
$fColSize = 100 / $this->iNbCols; $fColSize = 100 / $this->iNbCols;
$sStyle = $bEditMode ? 'border: 1px #ccc dashed; width:'.$fColSize.'%;' : 'width: '.$fColSize.'%;'; $sStyle = $bEditMode ? 'border: 1px #ccc dashed; width:'.$fColSize.'%;' : 'width: '.$fColSize.'%;';
@@ -129,7 +122,6 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
$aDashlets = $aCells[$iCellIdx]; $aDashlets = $aCells[$iCellIdx];
if (count($aDashlets) > 0) if (count($aDashlets) > 0)
{ {
/** @var \Dashlet $oDashlet */
foreach($aDashlets as $oDashlet) foreach($aDashlets as $oDashlet)
{ {
if ($oDashlet->IsVisible()) if ($oDashlet->IsVisible())

File diff suppressed because it is too large Load Diff

View File

@@ -1,27 +0,0 @@
<?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>
<handler/>
<allow/>
<deny>
<profile id="Portal user"/>
</deny>
</portal>
</portals>
<menus>
<menu id="AdminTools" xsi:type="MenuGroup" _delta="define">
<rank>80</rank>
</menu>
</menus>
</itop_design>

View File

@@ -1,5 +1,5 @@
<?php <?php
// Copyright (C) 2010-2017 Combodo SARL // Copyright (C) 2010-2013 Combodo SARL
// //
// This file is part of iTop. // This file is part of iTop.
// //
@@ -18,7 +18,7 @@
/** /**
* Data Table to display a set of objects in a tabular manner in HTML * Data Table to display a set of objects in a tabular manner in HTML
* *
* @copyright Copyright (C) 2010-2017 Combodo SARL * @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
@@ -31,8 +31,7 @@ class DataTable
protected $iNbObjects; // Total number of objects inthe set protected $iNbObjects; // Total number of objects inthe set
protected $bUseCustomSettings; // Whether or not the current display uses custom settings protected $bUseCustomSettings; // Whether or not the current display uses custom settings
protected $oDefaultSettings; // the default settings for displaying such a list protected $oDefaultSettings; // the default settings for displaying such a list
protected $bShowObsoleteData;
/** /**
* @param $iListId mixed Unique ID for this div/table in the page * @param $iListId mixed Unique ID for this div/table in the page
* @param $oSet DBObjectSet The set of data to display * @param $oSet DBObjectSet The set of data to display
@@ -48,7 +47,6 @@ class DataTable
$this->iNbObjects = $oSet->Count(); $this->iNbObjects = $oSet->Count();
$this->bUseCustomSettings = false; $this->bUseCustomSettings = false;
$this->oDefaultSettings = null; $this->oDefaultSettings = null;
$this->bShowObsoleteData = $oSet->GetShowObsoleteData();
} }
public function Display(WebPage $oPage, DataTableSettings $oSettings, $bActionsMenu, $sSelectMode, $bViewLink, $aExtraParams) public function Display(WebPage $oPage, DataTableSettings $oSettings, $bActionsMenu, $sSelectMode, $bViewLink, $aExtraParams)
@@ -147,9 +145,7 @@ class DataTable
$sHtml .= "<tr><td class=\"datacontents\">$sDataTable</td></tr>"; $sHtml .= "<tr><td class=\"datacontents\">$sDataTable</td></tr>";
$sHtml .= "</table>\n"; $sHtml .= "</table>\n";
$oPage->add_at_the_end($sConfigDlg); $oPage->add_at_the_end($sConfigDlg);
$aExtraParams['show_obsolete_data'] = $this->bShowObsoleteData;
$aOptions = array( $aOptions = array(
'sPersistentId' => '', 'sPersistentId' => '',
'sFilter' => $this->oSet->GetFilter()->serialize(), 'sFilter' => $this->oSet->GetFilter()->serialize(),
@@ -174,7 +170,6 @@ class DataTable
} }
$sJSOptions = json_encode($aOptions); $sJSOptions = json_encode($aOptions);
$oPage->add_ready_script("$('#datatable_{$this->iListId}').datatable($sJSOptions);"); $oPage->add_ready_script("$('#datatable_{$this->iListId}').datatable($sJSOptions);");
return $sHtml; return $sHtml;
} }
@@ -184,10 +179,6 @@ class DataTable
*/ */
public function GetAsHTMLTableRows(WebPage $oPage, $iPageSize, $aColumns, $sSelectMode, $bViewLink, $aExtraParams) public function GetAsHTMLTableRows(WebPage $oPage, $iPageSize, $aColumns, $sSelectMode, $bViewLink, $aExtraParams)
{ {
if ($iPageSize < 1)
{
$iPageSize = -1; // convention: no pagination
}
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink); $aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams); $aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
@@ -226,21 +217,14 @@ class DataTable
} }
$sCombo = '<select class="pagesize">'; $sCombo = '<select class="pagesize">';
if($iPageSize < 1) for($iPage = 1; $iPage < 5; $iPage++)
{ {
$sCombo .= "<option selected=\"selected\" value=\"-1\">".Dict::S('UI:Pagination:All')."</option>"; $iNbItems = $iPage * $iDefaultPageSize;
$sSelected = ($iNbItems == $iPageSize) ? 'selected="selected"' : '';
$sCombo .= "<option $sSelected value=\"$iNbItems\">$iNbItems</option>";
} }
else $sSelected = ($iPageSize < 1) ? 'selected="selected"' : '';
{ $sCombo .= "<option $sSelected value=\"-1\">".Dict::S('UI:Pagination:All')."</option>";
for($iPage = 1; $iPage < 5; $iPage++)
{
$iNbItems = $iPage * $iDefaultPageSize;
$sSelected = ($iNbItems == $iPageSize) ? 'selected="selected"' : '';
$sCombo .= "<option $sSelected value=\"$iNbItems\">$iNbItems</option>";
}
$sCombo .= "<option value=\"-1\">".Dict::S('UI:Pagination:All')."</option>";
}
$sCombo .= '</select>'; $sCombo .= '</select>';
$sPages = Dict::S('UI:Pagination:PagesLabel'); $sPages = Dict::S('UI:Pagination:PagesLabel');
@@ -306,24 +290,17 @@ EOF;
protected function GetToolkitMenu(WebPage $oPage, $aExtraParams) 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><img src="../images/toolkit_menu.png"><ul>';
$sMenuTitle = Dict::S('UI:ConfigureThisList');
$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(
$oMenuItem1 = new JSPopupMenuItem('iTop::ConfigureList', $sMenuTitle, "$('#datatable_dlg_".$this->iListId."').dialog('open');"); $oMenuItem1->GetUID() => $oMenuItem1->GetMenuItem(),
$aActions = array( );
$oMenuItem1->GetUID() => $oMenuItem1->GetMenuItem(), $this->oSet->Rewind();
); utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_OBJLIST_TOOLKIT, $this->oSet, $aActions, $this->sTableId, $this->iListId);
$this->oSet->Rewind(); $this->oSet->Rewind();
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_OBJLIST_TOOLKIT, $this->oSet, $aActions, $this->sTableId, $this->iListId); $sHtml .= $oPage->RenderPopupMenuItems($aActions);
$this->oSet->Rewind();
$sHtml .= $oPage->RenderPopupMenuItems($aActions);
}
else
{
$sHtml = '';
}
return $sHtml; return $sHtml;
} }
@@ -442,7 +419,7 @@ EOF;
} }
else else
{ {
$aRow['form::select'] = "<input type=\"checkbox\" $sDisabled class=\"selectList{$this->iListId}\" name=\"selectObject[]\" value=\"".$aObjects[$sAlias]->GetKey()."\"></input>"; $aRow['form::select'] = "<input type=\"checkBox\" $sDisabled class=\"selectList{$this->iListId}\" name=\"selectObject[]\" value=\"".$aObjects[$sAlias]->GetKey()."\"></input>";
} }
} }
foreach($aColumns[$sAlias] as $sAttCode => $aData) foreach($aColumns[$sAlias] as $sAttCode => $aData)
@@ -502,7 +479,6 @@ EOF;
{ {
$aExtraParams['query_params'][$sName] = $sValue; $aExtraParams['query_params'][$sName] = $sValue;
} }
$aExtraParams['show_obsolete_data'] = $this->bShowObsoleteData;
$sHtml .= "<tr><td>"; $sHtml .= "<tr><td>";
$sHtml .= $oPage->GetTable($aAttribs, $aValues); $sHtml .= $oPage->GetTable($aAttribs, $aValues);
@@ -576,22 +552,49 @@ EOF;
<<<EOF <<<EOF
var oTable = $('#{$this->iListId} table.listResults'); var oTable = $('#{$this->iListId} table.listResults');
oTable.tableHover(); oTable.tableHover();
oTable.tablesorter( { $sHeaders widgets: ['myZebra', 'truncatedList']} ).tablesorterPager({container: $('#pager{$this->iListId}'), totalRows:$iCount, size: $iPageSize, filter: '$sOQL', extra_params: '$sExtraParams', select_mode: '$sSelectModeJS', displayKey: $sDisplayKey, table_id: '{$this->iListId}', columns: $sJSColumns, class_aliases: $sJSClassAliases $sCssCount}); oTable.tablesorter( { $sHeaders widgets: ['myZebra', 'truncatedList']} ).tablesorterPager({container: $('#pager{$this->iListId}'), totalRows:$iCount, size: $iPageSize, filter: '$sOQL', extra_params: '$sExtraParams', select_mode: '$sSelectModeJS', displayKey: $sDisplayKey, columns: $sJSColumns, class_aliases: $sJSClassAliases $sCssCount});
EOF EOF
); );
if ($sFakeSortList != '') if ($sFakeSortList != '')
{ {
$oPage->add_ready_script("oTable.trigger(\"fakesorton\", [$sFakeSortList]);"); $oPage->add_ready_script("oTable.trigger(\"fakesorton\", [$sFakeSortList]);");
} }
//if ($iNbPages == 1)
if (false)
{
if (isset($aExtraParams['cssCount']))
{
$sCssCount = $aExtraParams['cssCount'];
if ($sSelectMode == 'single')
{
$sSelectSelector = ":radio[name^=selectObj]";
}
else if ($sSelectMode == 'multiple')
{
$sSelectSelector = ":checkbox[name^=selectObj]";
}
$oPage->add_ready_script(
<<<EOF
$('#{$this->iListId} table.listResults $sSelectSelector').change(function() {
var c = $('{$sCssCount}');
var v = $('#{$this->iListId} table.listResults $sSelectSelector:checked').length;
c.val(v);
$('#{$this->iListId} .selectedCount').text(v);
c.trigger('change');
});
EOF
);
}
}
return $sHtml; return $sHtml;
} }
public function UpdatePager(WebPage $oPage, $iDefaultPageSize, $iStart) public function UpdatePager(WebPage $oPage, $iDefaultPageSize, $iStart)
{ {
$iPageSize = $iDefaultPageSize; $iPageSize = ($iDefaultPageSize < 1) ? 1 : $iDefaultPageSize;
$iPageIndex = 0; $iPageIndex = 1 + floor($iStart / $iPageSize);
$sHtml = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex); $sHtml = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
$oPage->add_ready_script("$('#pager{$this->iListId}').html('".json_encode($sHtml)."');"); $oPage->add_ready_script("$('#pager{$this->iListId}').html('".str_replace("\n", ' ', addslashes($sHtml))."');");
if ($iDefaultPageSize < 1) if ($iDefaultPageSize < 1)
{ {
$oPage->add_ready_script("$('#pager{$this->iListId}').parent().hide()"); $oPage->add_ready_script("$('#pager{$this->iListId}').parent().hide()");
@@ -603,34 +606,6 @@ EOF
} }
} }
/**
* Simplified version of the data table with less "decoration" (and no paging)
* which is optimized for printing
*/
class PrintableDataTable extends DataTable
{
public function GetAsHTML(WebPage $oPage, $iPageSize, $iDefaultPageSize, $iPageIndex, $aColumns, $bActionsMenu, $bToolkitMenu, $sSelectMode, $bViewLink, $aExtraParams)
{
return $this->GetHTMLTable($oPage, $aColumns, $sSelectMode, -1, $bViewLink, $aExtraParams);
}
public function GetHTMLTable(WebPage $oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
{
$iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize);
if ($iPageSize < 1)
{
$iPageSize = -1; // convention: no pagination
}
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
$sHtml = $oPage->GetTable($aAttribs, $aValues);
return $sHtml;
}
}
class DataTableSettings implements Serializable class DataTableSettings implements Serializable
{ {
public $aClassAliases; public $aClassAliases;
@@ -738,12 +713,6 @@ class DataTableSettings implements Serializable
{ {
$sSort = $aSortOrder['friendlyname'] ? 'asc' : 'desc'; $sSort = $aSortOrder['friendlyname'] ? 'asc' : 'desc';
} }
$sNormalizedFName = MetaModel::NormalizeFieldSpec($sClass, 'friendlyname');
if(array_key_exists($sNormalizedFName, $aSortOrder))
{
$sSort = $aSortOrder[$sNormalizedFName] ? 'asc' : 'desc';
}
$aColumns[$sAlias]['_key_'] = $oSettings->GetFieldData($sAlias, '_key_', null, true /* bChecked */, $sSort); $aColumns[$sAlias]['_key_'] = $oSettings->GetFieldData($sAlias, '_key_', null, true /* bChecked */, $sSort);
} }
foreach($aList as $sAttCode) foreach($aList as $sAttCode)
@@ -767,10 +736,6 @@ class DataTableSettings implements Serializable
{ {
foreach($this->aClassAliases as $sAlias => $sClass) foreach($this->aClassAliases as $sAlias => $sClass)
{ {
if (!isset($this->aColumns[$sAlias]))
{
continue;
}
foreach($this->aColumns[$sAlias] as $sAttCode => $aData) foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
{ {
// Remove non-existent columns // Remove non-existent columns
@@ -786,7 +751,7 @@ class DataTableSettings implements Serializable
$aTempData = array(); $aTempData = array();
foreach($aList as $sAttCode => $oAttDef) foreach($aList as $sAttCode => $oAttDef)
{ {
if ( (!array_key_exists($sAttCode, $this->aColumns[$sAlias])) && (!($oAttDef instanceof AttributeLinkedSet || $oAttDef instanceof AttributeDashboard))) if ( (!array_key_exists($sAttCode, $this->aColumns[$sAlias])) && (!$oAttDef instanceof AttributeLinkSet))
{ {
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, false /* bChecked */, 'none'); $aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, false /* bChecked */, 'none');
if ($aFieldData) $aTempData[$aFieldData['label']] = $aFieldData; if ($aFieldData) $aTempData[$aFieldData['label']] = $aFieldData;
@@ -922,15 +887,8 @@ class DataTableSettings implements Serializable
} }
else if ($oAttDef->IsExternalField()) else if ($oAttDef->IsExternalField())
{ {
if ($oAttDef->IsFriendlyName()) $oExtAttDef = $oAttDef->GetExtAttDef();
{ $sLabel = Dict::Format('UI:ExtField_AsRemoteField', $oAttDef->GetLabel(), $oExtAttDef->GetLabel());
$sLabel = Dict::Format('UI:ExtKey_AsFriendlyName', $oAttDef->GetLabel());
}
else
{
$oExtAttDef = $oAttDef->GetExtAttDef();
$sLabel = Dict::Format('UI:ExtField_AsRemoteField', $oAttDef->GetLabel(), $oExtAttDef->GetLabel());
}
} }
elseif ($oAttDef instanceof AttributeFriendlyName) elseif ($oAttDef instanceof AttributeFriendlyName)
{ {
@@ -947,4 +905,4 @@ class DataTableSettings implements Serializable
} }
return $ret; return $ret;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -462,7 +462,7 @@ class ExcelExporter
$this->aAuthorizedClasses = array(); $this->aAuthorizedClasses = array();
foreach($aClasses as $sAlias => $sClassName) foreach($aClasses as $sAlias => $sClassName)
{ {
if (UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $oSet) != UR_ALLOWED_NO) if (UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $oSet) && (UR_ALLOWED_YES || UR_ALLOWED_DEPENDS))
{ {
$this->aAuthorizedClasses[$sAlias] = $sClassName; $this->aAuthorizedClasses[$sAlias] = $sClassName;
} }

View File

@@ -203,7 +203,7 @@ class DesignerForm
public function RenderAsPropertySheet($oP, $bReturnHTML = false, $sNotifyParentSelector = null) public function RenderAsPropertySheet($oP, $bReturnHTML = false, $sNotifyParentSelector = null)
{ {
$sReturn = ''; $sReturn = '';
$sActionUrl = addslashes($this->sSubmitTo); $sActionUrl = addslashes($this->sSubmitTo);
$sJSSubmitParams = json_encode($this->aSubmitParams); $sJSSubmitParams = json_encode($this->aSubmitParams);
$sFormId = $this->GetFormId(); $sFormId = $this->GetFormId();
@@ -339,7 +339,7 @@ EOF
return '</tr>'; return '</tr>';
} }
public function RenderAsDialog($oPage, $sDialogId, $sDialogTitle, $iDialogWidth, $sOkButtonLabel, $sIntroduction = null, $bAutoOpen = true) public function RenderAsDialog($oPage, $sDialogId, $sDialogTitle, $iDialogWidth, $sOkButtonLabel, $sIntroduction = null)
{ {
$this->SetPrefix('dlg_'); // To make sure that the controls have different IDs that the property sheet which may be displayed at the same time $this->SetPrefix('dlg_'); // To make sure that the controls have different IDs that the property sheet which may be displayed at the same time
@@ -355,15 +355,12 @@ EOF
$this->Render($oPage); $this->Render($oPage);
$oPage->add('</div>'); $oPage->add('</div>');
$sAutoOpen = $bAutoOpen ? 'true' : 'false';
$oPage->add_ready_script( $oPage->add_ready_script(
<<<EOF <<<EOF
$('#$sDialogId').dialog({ $('#$sDialogId').dialog({
height: 'auto', height: 'auto',
maxHeight: $(window).height() - 8,
width: $iDialogWidth, width: $iDialogWidth,
modal: true, modal: true,
autoOpen: $sAutoOpen,
title: '$sDialogTitle', title: '$sDialogTitle',
buttons: [ buttons: [
{ text: "$sOkButtonLabel", click: function() { { text: "$sOkButtonLabel", click: function() {
@@ -378,9 +375,9 @@ $('#$sDialogId').dialog({
} }
} }
} }, } },
{ text: "$sCancelButtonLabel", click: function() { $(this).dialog( "close" ); $(this).remove(); } }, { text: "$sCancelButtonLabel", click: function() { KillAllMenus(); $(this).dialog( "close" ); $(this).remove(); } },
], ],
close: function() { $(this).remove(); } close: function() { KillAllMenus(); $(this).remove(); }
}); });
var oForm = $('#$sDialogId form'); var oForm = $('#$sDialogId form');
var sFormId = oForm.attr('id'); var sFormId = oForm.attr('id');
@@ -532,7 +529,7 @@ EOF
public function GetFieldId($sCode) public function GetFieldId($sCode)
{ {
return $this->GetPrefix().'attr_'.utils::GetSafeId($sCode.$this->GetSuffix()); return $this->GetPrefix().'attr_'.$sCode;
} }
public function GetFieldName($sCode) public function GetFieldName($sCode)
@@ -682,7 +679,6 @@ class DesignerFormField
protected $sLabel; protected $sLabel;
protected $sCode; protected $sCode;
protected $defaultValue; protected $defaultValue;
/** @var \DesignerForm $oForm */
protected $oForm; protected $oForm;
protected $bMandatory; protected $bMandatory;
protected $bReadOnly; protected $bReadOnly;
@@ -708,11 +704,8 @@ class DesignerFormField
{ {
return $this->sCode; return $this->sCode;
} }
/** public function SetForm($oForm)
* @param \DesignerForm $oForm
*/
public function SetForm(\DesignerForm $oForm)
{ {
$this->oForm = $oForm; $this->oForm = $oForm;
} }
@@ -886,7 +879,7 @@ class DesignerTextField extends DesignerFormField
$this->sValidationPattern = $sValidationPattern; $this->sValidationPattern = $sValidationPattern;
} }
public function SetForbiddenValues($aValues, $sExplain, $bCaseSensitive = true) public function SetForbiddenValues($aValues, $sExplain)
{ {
$aForbiddenValues = $aValues; $aForbiddenValues = $aValues;
@@ -898,7 +891,7 @@ class DesignerTextField extends DesignerFormField
} }
$this->aForbiddenValues[] = array('values' => $aForbiddenValues, 'message' => $sExplain, 'case_sensitive' => $bCaseSensitive); $this->aForbiddenValues[] = array('values' => $aForbiddenValues, 'message' => $sExplain);
} }
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog') public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
@@ -944,8 +937,8 @@ EOF
public function ReadParam(&$aValues) public function ReadParam(&$aValues)
{ {
parent::ReadParam($aValues); parent::ReadParam($aValues);
$sPattern = '/'.str_replace('/', '\/', $this->sValidationPattern).'/'; // Escape the forward slashes since they are used as delimiters for preg_match
if (($this->sValidationPattern != '') && (!preg_match($sPattern, $aValues[$this->sCode])) ) if (($this->sValidationPattern != '') &&(!preg_match('/'.$this->sValidationPattern.'/', $aValues[$this->sCode])) )
{ {
$aValues[$this->sCode] = $this->defaultValue; $aValues[$this->sCode] = $this->defaultValue;
} }
@@ -1343,7 +1336,7 @@ EOF
} }
else else
{ {
$sValue = '<span style="display:inline-block;line-height:48px;height:48px;"><span><img style="vertical-align:middle" src="'.$this->aAllowedValues[$idx]['icon'].'" />&nbsp;'.htmlentities($this->aAllowedValues[$idx]['label'], ENT_QUOTES, 'UTF-8').'</span></span>'; $sValue = '<img src="'.$this->MakeFileUrl($this->defaultValue).'" />';
} }
$sReadOnly = $this->IsReadOnly() ? 'disabled' : ''; $sReadOnly = $this->IsReadOnly() ? 'disabled' : '';
return array('label' => $this->sLabel, 'value' => $sValue); return array('label' => $this->sLabel, 'value' => $sValue);
@@ -1352,19 +1345,14 @@ EOF
class RunTimeIconSelectionField extends DesignerIconSelectionField class RunTimeIconSelectionField extends DesignerIconSelectionField
{ {
static $aAllIcons = array();
public function __construct($sCode, $sLabel = '', $defaultValue = '') public function __construct($sCode, $sLabel = '', $defaultValue = '')
{ {
parent::__construct($sCode, $sLabel, $defaultValue); parent::__construct($sCode, $sLabel, $defaultValue);
if (count(self::$aAllIcons) == 0) $aAllIcons = self::FindIconsOnDisk(APPROOT.'env-'.utils::GetCurrentEnvironment());
{ ksort($aAllIcons);
self::$aAllIcons = self::FindIconsOnDisk(APPROOT.'env-'.utils::GetCurrentEnvironment());
ksort(self::$aAllIcons);
}
$aValues = array(); $aValues = array();
foreach(self::$aAllIcons as $sFilePath) foreach($aAllIcons as $sFilePath)
{ {
$aValues[] = array('value' => $sFilePath, 'label' => basename($sFilePath), 'icon' => utils::GetAbsoluteUrlModulesRoot().$sFilePath); $aValues[] = array('value' => $sFilePath, 'label' => basename($sFilePath), 'icon' => utils::GetAbsoluteUrlModulesRoot().$sFilePath);
} }
@@ -1372,36 +1360,6 @@ class RunTimeIconSelectionField extends DesignerIconSelectionField
} }
static protected function FindIconsOnDisk($sBaseDir, $sDir = '') static protected function FindIconsOnDisk($sBaseDir, $sDir = '')
{
$aFiles = null;
$sKey = $sBaseDir.'/'.$sDir;
$sShortKey = abs(crc32($sKey));
$sCacheFile = utils::GetCachePath().'available-icons-'.$sShortKey.'.php';
$sCacheClass = 'AvailableIcons_'.$sShortKey;
if (file_exists($sCacheFile))
{
require_once($sCacheFile);
if ($sCacheClass::$sKey === $sKey) // crc32 collision detection
{
$aFiles = $sCacheClass::$aIconFiles;
}
}
if ($aFiles === null)
{
$aFiles = self::_FindIconsOnDisk($sBaseDir, $sDir);
$sAvailableIcons = '<?php'.PHP_EOL;
$sAvailableIcons .= '// Generated and used by '.__METHOD__.PHP_EOL;
$sAvailableIcons .= 'class '.$sCacheClass.PHP_EOL;
$sAvailableIcons .= '{'.PHP_EOL;
$sAvailableIcons .= ' static $sKey = '.var_export($sKey, true).';'.PHP_EOL;
$sAvailableIcons .= ' static $aIconFiles = '.var_export($aFiles, true).';'.PHP_EOL;
$sAvailableIcons .= '}'.PHP_EOL;
file_put_contents($sCacheFile, $sAvailableIcons, LOCK_EX);
}
return $aFiles;
}
static protected function _FindIconsOnDisk($sBaseDir, $sDir = '')
{ {
$aResult = array(); $aResult = array();
// Populate automatically the list of icon files // Populate automatically the list of icon files
@@ -1413,7 +1371,7 @@ class RunTimeIconSelectionField extends DesignerIconSelectionField
if (($sFile != '.') && ($sFile != '..') && ($sFile != 'lifecycle') && is_dir($sBaseDir.'/'.$sDir.'/'.$sFile)) if (($sFile != '.') && ($sFile != '..') && ($sFile != 'lifecycle') && is_dir($sBaseDir.'/'.$sDir.'/'.$sFile))
{ {
$sDirSubPath = ($sDir == '') ? $sFile : $sDir.'/'.$sFile; $sDirSubPath = ($sDir == '') ? $sFile : $sDir.'/'.$sFile;
$aResult = array_merge($aResult, self::_FindIconsOnDisk($sBaseDir, $sDirSubPath)); $aResult = array_merge($aResult, self::FindIconsOnDisk($sBaseDir, $sDirSubPath));
} }
if (preg_match("/\.(png|jpg|jpeg|gif)$/i", $sFile, $aMatches)) // png, jp(e)g and gif are considered valid if (preg_match("/\.(png|jpg|jpeg|gif)$/i", $sFile, $aMatches)) // png, jp(e)g and gif are considered valid
{ {
@@ -1443,12 +1401,8 @@ class RunTimeIconSelectionField extends DesignerIconSelectionField
public function GetDefaultValue($sClass = 'Contact') public function GetDefaultValue($sClass = 'Contact')
{ {
$sIcon = ''; $sIconPath = MetaModel::GetClassIcon($sClass, false);
if (MetaModel::IsValidClass($sClass)) $sIcon = str_replace(utils::GetAbsoluteUrlModulesRoot(), '', $sIconPath);
{
$sIconPath = MetaModel::GetClassIcon($sClass, false);
$sIcon = str_replace(utils::GetAbsoluteUrlModulesRoot(), '', $sIconPath);
}
return $sIcon; return $sIcon;
} }
} }
@@ -1529,6 +1483,7 @@ class DesignerFormSelectorField extends DesignerFormField
public function AddSubForm($oSubForm, $sLabel, $sValue) public function AddSubForm($oSubForm, $sLabel, $sValue)
{ {
$idx = count($this->aSubForms);
$this->aSubForms[] = array('form' => $oSubForm, 'label' => $sLabel, 'value' => $sValue); $this->aSubForms[] = array('form' => $oSubForm, 'label' => $sLabel, 'value' => $sValue);
if ($sValue == $this->defaultRealValue) if ($sValue == $this->defaultRealValue)
{ {
@@ -1542,7 +1497,7 @@ class DesignerFormSelectorField extends DesignerFormField
$sId = $this->oForm->GetFieldId($this->sCode); $sId = $this->oForm->GetFieldId($this->sCode);
$sName = $this->oForm->GetFieldName($this->sCode); $sName = $this->oForm->GetFieldName($this->sCode);
$sReadOnly = $this->IsReadOnly() ? 'disabled="disabled"' : ''; $sReadOnly = $this->IsReadOnly() ? 'disabled="disabled"' : '';
$this->aCSSClasses[] = 'formSelector'; $this->aCSSClasses[] = 'formSelector';
$sCSSClasses = ''; $sCSSClasses = '';
@@ -1558,6 +1513,8 @@ class DesignerFormSelectorField extends DesignerFormField
if ($this->IsReadOnly()) if ($this->IsReadOnly())
{ {
$aSelected = array();
$aHiddenValues = array();
$sDisplayValue = ''; $sDisplayValue = '';
$sHiddenValue = ''; $sHiddenValue = '';
foreach($this->aSubForms as $iKey => $aFormData) foreach($this->aSubForms as $iKey => $aFormData)
@@ -1573,6 +1530,8 @@ class DesignerFormSelectorField extends DesignerFormField
} }
else else
{ {
$sHtml = "<select $sCSSClasses id=\"$sId\" name=\"$sName\" $sReadOnly>"; $sHtml = "<select $sCSSClasses id=\"$sId\" name=\"$sName\" $sReadOnly>";
foreach($this->aSubForms as $iKey => $aFormData) foreach($this->aSubForms as $iKey => $aFormData)
{ {
@@ -1588,6 +1547,7 @@ class DesignerFormSelectorField extends DesignerFormField
{ {
$sHtml .= '</td><td class="prop_icon prop_apply"><span title="Apply" class="ui-icon ui-icon-circle-check"/></td><td class="prop_icon prop_cancel"><span title="Revert" class="ui-icon ui-icon-circle-close"/></td></tr>'; $sHtml .= '</td><td class="prop_icon prop_apply"><span title="Apply" class="ui-icon ui-icon-circle-check"/></td><td class="prop_icon prop_cancel"><span title="Revert" class="ui-icon ui-icon-circle-close"/></td></tr>';
} }
foreach($this->aSubForms as $sKey => $aFormData) foreach($this->aSubForms as $sKey => $aFormData)
{ {
$sId = $this->oForm->GetFieldId($this->sCode); $sId = $this->oForm->GetFieldId($this->sCode);
@@ -1613,7 +1573,25 @@ class DesignerFormSelectorField extends DesignerFormField
$oSubForm->SetHierarchyPath($sPath); $oSubForm->SetHierarchyPath($sPath);
$oSubForm->SetDisplayed($sKey == $this->defaultValue); $oSubForm->SetDisplayed($sKey == $this->defaultValue);
$sState = ($sKey == $this->defaultValue) ? 'visible' : 'hidden';
//$sHtml .= "</tbody><tbody data-selector=\"$sSelector\" data-path=\"$sPath\" data-state=\"$sState\" $sStyle>";
$sHtml .= $oSubForm->RenderAsPropertySheet($oP, true); $sHtml .= $oSubForm->RenderAsPropertySheet($oP, true);
$sState = $this->oForm->IsDisplayed() ? 'visible' : 'hidden';
$sParentStyle = '';
if ($oParent = $this->oForm->GetParentForm())
{
$sParentStyle = ($oParent->IsDisplayed()) ? '' : 'style="display:none"';
$sParentSelector = $oParent->GetHierarchyParent();
$sParentPath = $oParent->GetHierarchyPath();
}
else
{
$sParentSelector = '';
$sParentPath = '';
}
//$sHtml .= "</tbody><tbody data-selector=\"$sParentSelector\" data-path=\"$sParentPath\" data-state=\"$sState\" $sParentStyle>";
} }
else else
{ {
@@ -1661,6 +1639,7 @@ EOF
if ($selectedValue == $aFormData['value']) if ($selectedValue == $aFormData['value'])
{ {
$this->defaultValue =$iKey; $this->defaultValue =$iKey;
$aDefaultValues = $this->oForm->GetDefaultValues();
$oSubForm = $aFormData['form']; $oSubForm = $aFormData['form'];
$oSubForm->SetDefaultValues($aAllDefaultValues); $oSubForm->SetDefaultValues($aAllDefaultValues);
} }

View File

@@ -1,69 +1,69 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010-2012 Combodo SARL
// //
// This file is part of iTop. // 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 // 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 // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// iTop is distributed in the hope that it will be useful, // iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details. // GNU Affero General Public License for more details.
// //
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* Persistent class InputOutputTask * Persistent class InputOutputTask
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
require_once(APPROOT.'/application/cmdbabstract.class.inc.php'); require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
/** /**
* This class manages the input/output tasks * This class manages the input/output tasks
* for synchronizing information with external data sources * for synchronizing information with external data sources
*/ */
class InputOutputTask extends cmdbAbstractObject class InputOutputTask extends cmdbAbstractObject
{ {
public static function Init() public static function Init()
{ {
$aParams = array $aParams = array
( (
"category" => "application", "category" => "application",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array(), "reconc_keys" => array(),
"db_table" => "priv_iotask", "db_table" => "priv_iotask",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
"display_template" => "", "display_template" => "",
); );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("category", array("allowed_values"=>new ValueSetEnum('Input, Ouput'), "sql"=>"category", "default_value"=>"Input", "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeEnum("category", array("allowed_values"=>new ValueSetEnum('Input, Ouput'), "sql"=>"category", "default_value"=>"Input", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("source_type", array("allowed_values"=>new ValueSetEnum('File, Database, Web Service'), "sql"=>"source_type", "default_value"=>"File", "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeEnum("source_type", array("allowed_values"=>new ValueSetEnum('File, Database, Web Service'), "sql"=>"source_type", "default_value"=>"File", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("source_subtype", array("allowed_values"=>new ValueSetEnum('Oracle, MySQL, Postgress, MSSQL, SOAP, HTTP-Get, HTTP-Post, XML/RPC, CSV, XML, Excel'), "sql"=>"source_subtype", "default_value"=>"CSV", "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeEnum("source_subtype", array("allowed_values"=>new ValueSetEnum('Oracle, MySQL, Postgress, MSSQL, SOAP, HTTP-Get, HTTP-Post, XML/RPC, CSV, XML, Excel'), "sql"=>"source_subtype", "default_value"=>"CSV", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("source_path", array("allowed_values"=>null, "sql"=>"source_path", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("source_path", array("allowed_values"=>null, "sql"=>"source_path", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeClass("objects_class", array("class_category"=>"", "more_values"=>"", "sql"=>"objects_class", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeClass("objects_class", array("class_category"=>"", "more_values"=>"", "sql"=>"objects_class", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("test_mode", array("allowed_values"=>new ValueSetEnum('Yes,No'), "sql"=>"test_mode", "default_value"=>'No', "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeEnum("test_mode", array("allowed_values"=>new ValueSetEnum('Yes,No'), "sql"=>"test_mode", "default_value"=>'No', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("verbose_mode", array("allowed_values"=>new ValueSetEnum('Yes,No'), "sql"=>"verbose_mode", "default_value" => 'No', "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeEnum("verbose_mode", array("allowed_values"=>new ValueSetEnum('Yes,No'), "sql"=>"verbose_mode", "default_value" => 'No', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("options", array("allowed_values"=>new ValueSetEnum('Full, Update Only, Creation Only'), "sql"=>"options", "default_value"=> 'Full', "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeEnum("options", array("allowed_values"=>new ValueSetEnum('Full, Update Only, Creation Only'), "sql"=>"options", "default_value"=> 'Full', "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists // Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description', 'category', 'objects_class', 'source_type', 'source_subtype', 'source_path' , 'options', 'test_mode', 'verbose_mode')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('details', array('name', 'description', 'category', 'objects_class', 'source_type', 'source_subtype', 'source_path' , 'options', 'test_mode', 'verbose_mode')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('description', 'category', 'objects_class', 'source_type', 'source_subtype', 'options')); // Attributes to be displayed for a list MetaModel::Init_SetZListItems('list', array('description', 'category', 'objects_class', 'source_type', 'source_subtype', 'options')); // Attributes to be displayed for a list
// Search criteria // Search criteria
MetaModel::Init_SetZListItems('standard_search', array('name', 'category', 'objects_class', 'source_type', 'source_subtype')); // Criteria of the std search form MetaModel::Init_SetZListItems('standard_search', array('name', 'category', 'objects_class', 'source_type', 'source_subtype')); // Criteria of the std search form
MetaModel::Init_SetZListItems('advanced_search', array('name', 'description', 'category', 'objects_class', 'source_type', 'source_subtype')); // Criteria of the advanced search form MetaModel::Init_SetZListItems('advanced_search', array('name', 'description', 'category', 'objects_class', 'source_type', 'source_subtype')); // Criteria of the advanced search form
} }
} }
?> ?>

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -1,194 +0,0 @@
<?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;
public function SetDocumentTitle($sDocumentTitle)
{
$this->sDocumentTitle = $sDocumentTitle;
}
/**
* Builds the custom header. Called for each new page.
* @see TCPDF::Header()
*/
public function Header()
{
// Title
// Set font
$this->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->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 */);
// Branding logo
$sBrandingIcon = APPROOT.'images/itop-logo.png';
if (file_exists(MODULESROOT.'branding/main-logo.png'))
{
$sBrandingIcon = MODULESROOT.'branding/main-logo.png';
}
$this->Image($sBrandingIcon, $aMargins['left'], 5, 0, 10);
}
// Page footer
public function Footer()
{
// No footer
}
}
/**
* Special class of WebPage for printing into a PDF document
*/
class PDFPage extends WebPage
{
/**
* 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/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->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
table {
padding: 2pt;
}
table.listResults td {
border: 0.5pt solid #000 ;
}
table.listResults th {
background-color: #eee;
border: 0.5pt solid #000 ;
}
a {
text-decoration: none;
color: #000;
}
table.section td {
vertical-align: middle;
font-size: 10pt;
background-color:#eee;
}
td.icon {
width: 30px;
}
EOF
);
}
/**
* Get access to the underlying TCPDF object
* @return 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
* - to process the HTML by smaller chunks instead of processing the whole page at once for performance reasons
*/
public function flush()
{
if (strlen($this->s_content) > 0)
{
$sHtml = '';
if (count($this->a_styles) > 0)
{
$sHtml .= "<style>\n".implode("\n", $this->a_styles)."\n</style>\n";
}
$sHtml .= $this->s_content;
$this->oPdf->writeHTML($sHtml); // The style(s) must be supplied each time we call writeHtml
$this->s_content = '';
}
}
/**
* Whether or not the page is a PDF page
* @return boolean
*/
public function is_pdf()
{
return true;
}
/**
* Generates the PDF document and returns the PDF content as a string
* @return string
* @see WebPage::output()
*/
public function output()
{
$this->add_header('Content-type: application/x-pdf');
if (!empty($this->sContentDisposition))
{
$this->add_header('Content-Disposition: '.$this->sContentDisposition.'; filename="'.$this->sContentFileName.'"');
}
foreach($this->a_headers as $s_header)
{
header($s_header);
}
$this->flush();
echo $this->oPdf->Output($this->s_title.'.pdf', 'S');
}
public function get_pdf()
{
$this->flush();
return $this->oPdf->Output($this->s_title.'.pdf', 'S');
}
}

View File

@@ -1,66 +0,0 @@
<?php
class PortalDispatcher
{
protected $sPortalid;
protected $aData;
public function __construct($sPortalId)
{
$this->sPortalid = $sPortalId;
$this->aData = PortalDispatcherData::GetData($sPortalId);
}
public function IsUserAllowed()
{
$bRet = true;
$aProfiles = UserRights::ListProfiles();
foreach($this->aData['deny'] as $sDeniedProfile)
{
// If one denied profile is present, it's enough => return false
if (in_array($sDeniedProfile, $aProfiles))
{
return false;
}
}
// If there are some "allow" profiles, then by default the result is false
// since the user must have at least one of the profiles to be allowed
if (count($this->aData['allow']) > 0)
{
$bRet = false;
}
foreach($this->aData['allow'] as $sAllowProfile)
{
// If one "allow" profile is present, it's enough => return true
if (in_array($sAllowProfile, $aProfiles))
{
return true;
}
}
return $bRet;
}
public function GetURL()
{
$aOverloads = MetaModel::GetConfig()->Get('portal_dispatch_urls');
if (array_key_exists($this->sPortalid, $aOverloads))
{
$sRet = $aOverloads[$this->sPortalid];
}
else
{
$sRet = utils::GetAbsoluteUrlAppRoot().$this->aData['url'];
}
return $sRet;
}
public function GetLabel()
{
return Dict::S('portal:'.$this->sPortalid);
}
public function GetRank()
{
return $this->aData['rank'];
}
}

View File

@@ -1,5 +1,5 @@
<?php <?php
// Copyright (C) 2010-2017 Combodo SARL // Copyright (C) 2010-2013 Combodo SARL
// //
// This file is part of iTop. // This file is part of iTop.
// //
@@ -19,7 +19,7 @@
/** /**
* Class PortalWebPage * Class PortalWebPage
* *
* @copyright Copyright (C) 2010-2017 Combodo SARL * @copyright Copyright (C) 2010-2013 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
@@ -49,12 +49,9 @@ class PortalWebPage extends NiceWebPage
*/ */
protected $m_sWelcomeMsg; protected $m_sWelcomeMsg;
protected $m_aMenuButtons; protected $m_aMenuButtons;
protected $m_oCtx;
public function __construct($sTitle, $sAlternateStyleSheet = '') public function __construct($sTitle, $sAlternateStyleSheet = '')
{ {
$this->m_oCtx = new ContextTag('GUI:Portal');
$this->m_sWelcomeMsg = ''; $this->m_sWelcomeMsg = '';
$this->m_aMenuButtons = array(); $this->m_aMenuButtons = array();
parent::__construct($sTitle); parent::__construct($sTitle);
@@ -91,94 +88,8 @@ class PortalWebPage extends NiceWebPage
$this->add_linked_script("../js/forms-json-utils.js"); $this->add_linked_script("../js/forms-json-utils.js");
$this->add_linked_script("../js/swfobject.js"); $this->add_linked_script("../js/swfobject.js");
$this->add_linked_script("../js/jquery.qtip-1.0.min.js"); $this->add_linked_script("../js/jquery.qtip-1.0.min.js");
$this->add_linked_script('../js/jquery.multiselect.js'); $this->add_linked_script('../js/jquery.multiselect.min.js');
$this->add_linked_script("../js/ajaxfileupload.js"); $this->add_linked_script("../js/ajaxfileupload.js");
$this->add_linked_script("../js/ckeditor/ckeditor.js");
$this->add_linked_script("../js/ckeditor/adapters/jquery.js");
$this->add_linked_script("../js/jquery-ui-timepicker-addon.js");
$this->add_linked_script("../js/jquery-ui-timepicker-addon-i18n.min.js");
$this->add_linked_stylesheet("../css/jquery-ui-timepicker-addon.css");
$sJSDisconnectedMessage = json_encode(Dict::S('UI:DisconnectedDlgMessage'));
$sJSTitle = json_encode(Dict::S('UI:DisconnectedDlgTitle'));
$sJSLoginAgain = json_encode(Dict::S('UI:LoginAgain'));
$sJSStayOnThePage = json_encode(Dict::S('UI:StayOnThePage'));
$aDaysMin = array(Dict::S('DayOfWeek-Sunday-Min'), Dict::S('DayOfWeek-Monday-Min'), Dict::S('DayOfWeek-Tuesday-Min'), Dict::S('DayOfWeek-Wednesday-Min'),
Dict::S('DayOfWeek-Thursday-Min'), Dict::S('DayOfWeek-Friday-Min'), Dict::S('DayOfWeek-Saturday-Min'));
$aMonthsShort = array(Dict::S('Month-01-Short'), Dict::S('Month-02-Short'), Dict::S('Month-03-Short'), Dict::S('Month-04-Short'), Dict::S('Month-05-Short'), Dict::S('Month-06-Short'),
Dict::S('Month-07-Short'), Dict::S('Month-08-Short'), Dict::S('Month-09-Short'), Dict::S('Month-10-Short'), Dict::S('Month-11-Short'), Dict::S('Month-12-Short'));
$sTimeFormat = AttributeDateTime::GetFormat()->ToTimeFormat();
$oTimeFormat = new DateTimeFormat($sTimeFormat);
$sJSLangShort = json_encode(strtolower(substr(Dict::GetUserLanguage(), 0, 2)));
// Date picker options
$aPickerOptions = array(
'showOn' => 'button',
'buttonImage' => '../images/calendar.png',
'buttonImageOnly' => true,
'dateFormat' => AttributeDate::GetFormat()->ToDatePicker(),
'constrainInput' => false,
'changeMonth' => true,
'changeYear' => true,
'dayNamesMin' => $aDaysMin,
'monthNamesShort' => $aMonthsShort,
'firstDay' => (int) Dict::S('Calendar-FirstDayOfWeek'),
);
$sJSDatePickerOptions = json_encode($aPickerOptions);
// Time picker additional options
$aPickerOptions['showOn'] = '';
$aPickerOptions['buttonImage'] = null;
$aPickerOptions['timeFormat'] = $oTimeFormat->ToDatePicker();
$aPickerOptions['controlType'] = 'select';
$aPickerOptions['closeText'] = Dict::S('UI:Button:Ok');
$sJSDateTimePickerOptions = json_encode($aPickerOptions);
if ($sJSLangShort != '"en"')
{
// More options that cannot be passed via json_encode since they must be evaluated client-side
$aMoreJSOptions = ",
'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(
<<< EOF
function PrepareWidgets()
{
// note: each action implemented here must be idempotent,
// because this helper function might be called several times on a given page
$(".date-pick").datepicker($sJSDatePickerOptions);
// Hack for the date and time picker addon issue on Chrome (see #1305)
// The workaround is to instantiate the widget on demand
// It relies on the same markup, thus reverting to the original implementation should be straightforward
$(".datetime-pick:not(.is-widget-ready)").each(function(){
var oInput = this;
$(oInput).addClass('is-widget-ready');
$('<img class="datetime-pick-button" src="../images/calendar.png">')
.insertAfter($(this))
.on('click', function(){
$(oInput)
.datetimepicker($sJSDateTimePickerOptions)
.datetimepicker('show')
.datetimepicker('option', 'onClose', function(dateText,inst){
$(oInput).datetimepicker('destroy');
})
.on('click keypress', function(){
$(oInput).datetimepicker('hide');
});
});
});
}
EOF
);
$this->add_ready_script( $this->add_ready_script(
<<<EOF <<<EOF
try try
@@ -219,29 +130,28 @@ try
} }
}); });
PrepareWidgets(); $(".date-pick").datepicker({
showOn: 'button',
buttonImage: '../images/calendar.png',
buttonImageOnly: true,
dateFormat: 'yy-mm-dd',
constrainInput: false,
changeMonth: true,
changeYear: true
});
$(".datetime-pick").datepicker({
showOn: 'button',
buttonImage: '../images/calendar.png',
buttonImageOnly: true,
dateFormat: 'yy-mm-dd 00:00:00',
constrainInput: false,
changeMonth: true,
changeYear: true
});
//$('.resizable').resizable(); // Make resizable everything that claims to be resizable ! //$('.resizable').resizable(); // Make resizable everything that claims to be resizable !
$('.caselog_header').click( function () { $(this).toggleClass('open').next('.caselog_entry,.caselog_entry_html').toggle(); }); $('.caselog_header').click( function () { $(this).toggleClass('open').next('.caselog_entry').toggle(); });
$(document).ajaxSend(function(event, jqxhr, options) {
jqxhr.setRequestHeader('X-Combodo-Ajax', 'true');
});
$(document).ajaxError(function(event, jqxhr, options) {
if (jqxhr.status == 401)
{
$('<div>'+$sJSDisconnectedMessage+'</div>').dialog({
modal:true,
title: $sJSTitle,
close: function() { $(this).remove(); },
minWidth: 400,
buttons: [
{ text: $sJSLoginAgain, click: function() { window.location.href= GetAbsoluteUrlAppRoot()+'pages/UI.php' } },
{ text: $sJSStayOnThePage, click: function() { $(this).dialog('close'); } }
]
});
}
});
} }
catch(err) catch(err)
{ {
@@ -312,7 +222,7 @@ EOF
{ {
var form = $('FORM'); var form = $('FORM');
form.unbind('submit'); // De-activate validation form.unbind('submit'); // De-activate validation
window.location.href = window.location.href.replace(/operation=[^&]*&?/, ''); window.location.href = '?operation=';
return false; return false;
} }
@@ -321,20 +231,6 @@ EOF
var next_step = $('input[id=next_step]'); var next_step = $('input[id=next_step]');
next_step.val(sStep); next_step.val(sStep);
} }
// For disabling the CKEditor at init time when the corresponding textarea is disabled !
CKEDITOR.plugins.add( 'disabler',
{
init : function( editor )
{
editor.on( 'instanceReady', function(e)
{
e.removeListener();
$('#'+ editor.name).trigger('update');
});
}
});
EOF EOF
); );
@@ -387,7 +283,7 @@ EOF
{ {
$sReadOnly = Dict::S('UI:AccessRO-Users'); $sReadOnly = Dict::S('UI:AccessRO-Users');
$sAdminMessage = trim(MetaModel::GetConfig()->Get('access_message')); $sAdminMessage = trim(MetaModel::GetConfig()->Get('access_message'));
$sApplicationBanner .= '<div class="app-message">'; $sApplicationBanner .= '<div id="admin-banner">';
$sApplicationBanner .= '<img src="../images/locked.png" style="vertical-align:middle;">'; $sApplicationBanner .= '<img src="../images/locked.png" style="vertical-align:middle;">';
$sApplicationBanner .= '&nbsp;<b>'.$sReadOnly.'</b>'; $sApplicationBanner .= '&nbsp;<b>'.$sReadOnly.'</b>';
if (strlen($sAdminMessage) > 0) if (strlen($sAdminMessage) > 0)
@@ -400,7 +296,7 @@ EOF
$sMenu = ''; $sMenu = '';
if ($this->m_bEnableDisconnectButton) if ($this->m_bEnableDisconnectButton)
{ {
$this->AddMenuButton('logoff', 'Portal:Disconnect', utils::GetAbsoluteUrlAppRoot().'pages/logoff.php?operation=do_logoff'); // This menu is always present and is the last one $this->AddMenuButton('logoff', 'Portal:Disconnect', utils::GetAbsoluteUrlAppRoot().'pages/logoff.php'); // This menu is always present and is the last one
} }
foreach($this->m_aMenuButtons as $aMenuItem) foreach($this->m_aMenuButtons as $aMenuItem)
{ {
@@ -807,7 +703,7 @@ EOF
*/ */
public function DoUpdateObjectFromPostedForm(DBObject $oObj, $aAttList = null) public function DoUpdateObjectFromPostedForm(DBObject $oObj, $aAttList = null)
{ {
$sTransactionId = utils::ReadPostedParam('transaction_id', '', 'transaction_id'); $sTransactionId = utils::ReadPostedParam('transaction_id', '');
if (!utils::IsTransactionValid($sTransactionId)) if (!utils::IsTransactionValid($sTransactionId))
{ {
throw new TransactionException(); throw new TransactionException();
@@ -816,7 +712,7 @@ EOF
$sClass = get_class($oObj); $sClass = get_class($oObj);
$sStimulus = trim(utils::ReadPostedParam('apply_stimulus', '')); $sStimulus = trim(utils::ReadPostedParam('apply_stimulus', ''));
$aExpectedAttributes = array(); $sTargetState = '';
if (!empty($sStimulus)) if (!empty($sStimulus))
{ {
// Compute the target state // Compute the target state
@@ -826,10 +722,10 @@ EOF
{ {
throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus, $oObj->GetName(), $oObj->GetStateLabel())); throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus, $oObj->GetName(), $oObj->GetStateLabel()));
} }
$aExpectedAttributes = $oObj->GetTransitionAttributes($sStimulus /*, current state*/); $sTargetState = $aTransitions[$sStimulus]['target_state'];
} }
$oObj->UpdateObjectFromPostedForm('' /* form prefix */, $aAttList, $aExpectedAttributes); $oObj->UpdateObjectFromPostedForm('' /* form prefix */, $aAttList, $sTargetState);
// Optional: apply a stimulus // Optional: apply a stimulus
// //
@@ -859,17 +755,6 @@ EOF
$this->p("<h1>".Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($oObj)), $oObj->GetName())."</h1>\n"); $this->p("<h1>".Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($oObj)), $oObj->GetName())."</h1>\n");
} }
$bLockEnabled = MetaModel::GetConfig()->Get('concurrent_lock_enabled');
if ($bLockEnabled)
{
// Release the concurrent lock, if any
$sOwnershipToken = utils::ReadPostedParam('ownership_token', null, false, 'raw_data');
if ($sOwnershipToken !== null)
{
// We're done, let's release the lock
iTopOwnershipLock::ReleaseLock(get_class($oObj), $oObj->GetKey(), $sOwnershipToken);
}
}
} }
/** /**
@@ -952,7 +837,7 @@ EOF
$sTransactionId = utils::GetNewTransactionId(); $sTransactionId = utils::GetNewTransactionId();
$this->SetTransactionId($sTransactionId); $this->SetTransactionId($sTransactionId);
$this->add("<input type=\"hidden\" id=\"transaction_id\" name=\"transaction_id\" value=\"$sTransactionId\">\n"); $this->add("<input type=\"hidden\" id=\"transaction_id\" name=\"transaction_id\" value=\"$sTransactionId\">\n");
$this->add_ready_script("$(window).on('unload', function() { OnUnload('$sTransactionId') } );\n"); $this->add_ready_script("$(window).unload(function() { OnUnload('$sTransactionId') } );\n");
} }
public function WizardFormButtons($iButtonFlags) public function WizardFormButtons($iButtonFlags)

View File

@@ -1,178 +1,130 @@
<?php <?php
// Copyright (C) 2010-2015 Combodo SARL // Copyright (C) 2010-2012 Combodo SARL
// //
// This file is part of iTop. // 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 // 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 // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// iTop is distributed in the hope that it will be useful, // iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details. // GNU Affero General Public License for more details.
// //
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* Persistent class Event and derived * Persistent class Event and derived
* Application internal events * Application internal events
* There is also a file log * There is also a file log
* *
* @copyright Copyright (C) 2010-2015 Combodo SARL * @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
abstract class Query extends cmdbAbstractObject abstract class Query extends cmdbAbstractObject
{ {
public static function Init() public static function Init()
{ {
$aParams = array $aParams = array
( (
"category" => "core/cmdb,view_in_gui,application,grant_by_profile", "category" => "core/cmdb,view_in_gui,application",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array(), "reconc_keys" => array(),
"db_table" => "priv_query", "db_table" => "priv_query",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "realclass", "db_finalclass_field" => "realclass",
"display_template" => "", "display_template" => "",
); );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes(); //MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeText("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("fields", array("allowed_values"=>null, "sql"=>"fields", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('name', 'description')); // Attributes to be displayed for the complete details // Display lists
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list MetaModel::Init_SetZListItems('details', array('name', 'description', 'fields')); // Attributes to be displayed for the complete details
// Search criteria MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
MetaModel::Init_SetZListItems('standard_search', array('name', 'description')); // Criteria of the std search form // Search criteria
MetaModel::Init_SetZListItems('default_search', array('name', 'description')); // Criteria of the default search form MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'fields')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form // MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
} }
} }
class QueryOQL extends Query class QueryOQL extends Query
{ {
public static function Init() public static function Init()
{ {
$aParams = array $aParams = array
( (
"category" => "core/cmdb,view_in_gui,application,grant_by_profile", "category" => "core/cmdb,view_in_gui,application",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array(), "reconc_keys" => array(),
"db_table" => "priv_query_oql", "db_table" => "priv_query_oql",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
"display_template" => "", "display_template" => "",
); );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes(); MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("fields", array("allowed_values"=>null, "sql"=>"fields", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// Rolled back to AttributeText until AttributeQueryAttCodeSet can manage fields order correctly // Display lists
//MetaModel::Init_AddAttribute(new AttributeQueryAttCodeSet("fields", array("allowed_values"=>null,"max_items" => 1000, "query_field" => "oql", "sql"=>"fields", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array('oql')))); MetaModel::Init_SetZListItems('details', array('name', 'description', 'oql', 'fields')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
// Display lists // Search criteria
MetaModel::Init_SetZListItems('details', array('name', 'description', 'oql', 'fields')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'fields', 'oql')); // Criteria of the std search form
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list // MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
// Search criteria }
MetaModel::Init_SetZListItems('standard_search', array('name', 'description', 'fields', 'oql')); // Criteria of the std search form
} function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
{
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array()) $aFieldsMap = parent::DisplayBareProperties($oPage, $bEditMode, $sPrefix, $aExtraParams);
{
$aFieldsMap = parent::DisplayBareProperties($oPage, $bEditMode, $sPrefix, $aExtraParams); if (!$bEditMode)
{
if (!$bEditMode) $sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?format=spreadsheet&login_mode=basic&query='.$this->GetKey();
{ $sOql = $this->Get('oql');
$sFields = trim($this->Get('fields')); $sMessage = null;
$bExportV1Recommended = ($sFields == ''); try
if ($bExportV1Recommended) {
{ $oSearch = DBObjectSearch::FromOQL($sOql);
$oFieldAttDef = MetaModel::GetAttributeDef('QueryOQL', 'fields'); $aParameters = $oSearch->GetQueryParams();
$oPage->add('<div class="message message_error" style="padding-left: 30px;"><div style="padding: 10px;">'.Dict::Format('UI:Query:UrlV1', $oFieldAttDef->GetLabel()).'</div></div>'); foreach($aParameters as $sParam => $val)
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?format=spreadsheet&login_mode=basic&query='.$this->GetKey(); {
} $sUrl .= '&arg_'.$sParam.'=["'.$sParam.'"]';
else }
{
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export-v2.php?format=spreadsheet&login_mode=basic&date_format='.urlencode((string)AttributeDateTime::GetFormat()).'&query='.$this->GetKey(); $oPage->p(Dict::S('UI:Query:UrlForExcel').':<br/><textarea cols="80" rows="3" READONLY>'.$sUrl.'</textarea>');
}
$sOql = $this->Get('oql'); if (count($aParameters) == 0)
$sMessage = null; {
try $oBlock = new DisplayBlock($oSearch, 'list');
{ $aExtraParams = array(
$oSearch = DBObjectSearch::FromOQL($sOql); //'menu' => $sShowMenu,
$aParameters = $oSearch->GetQueryParams(); 'table_id' => 'query_preview_'.$this->getKey(),
foreach($aParameters as $sParam => $val) );
{ $sBlockId = 'block_query_preview_'.$this->GetKey(); // make a unique id (edition occuring in the same DOM)
$sUrl .= '&arg_'.$sParam.'=["'.$sParam.'"]'; $oBlock->Display($oPage, $sBlockId, $aExtraParams);
} }
}
$oPage->p(Dict::S('UI:Query:UrlForExcel').':<br/><textarea cols="80" rows="3" READONLY>'.$sUrl.'</textarea>'); catch (OQLException $e)
{
if (count($aParameters) == 0) $sMessage = '<div class="message message_error" style="padding-left: 30px;"><div style="padding: 10px;">'.Dict::Format('UI:RunQuery:Error', $e->getHtmlDesc()).'</div></div>';
{ $oPage->p($sMessage);
$oBlock = new DisplayBlock($oSearch, 'list'); }
$aExtraParams = array( }
//'menu' => $sShowMenu, return $aFieldsMap;
'table_id' => 'query_preview_'.$this->getKey(), }
); }
$sBlockId = 'block_query_preview_'.$this->GetKey(); // make a unique id (edition occuring in the same DOM)
$oBlock->Display($oPage, $sBlockId, $aExtraParams); ?>
}
}
catch (OQLException $e)
{
$sMessage = '<div class="message message_error" style="padding-left: 30px;"><div style="padding: 10px;">'.Dict::Format('UI:RunQuery:Error', $e->getHtmlDesc()).'</div></div>';
$oPage->p($sMessage);
}
}
return $aFieldsMap;
}
// Rolled back until 'fields' can be properly managed by AttributeQueryAttCodeSet
//
// public function ComputeValues()
// {
// parent::ComputeValues();
//
// // Remove unwanted attribute codes
// $aChanges = $this->ListChanges();
// if (isset($aChanges['fields']))
// {
// $oAttDef = MetaModel::GetAttributeDef(get_class($this), 'fields');
// $aArgs = array('this' => $this);
// $aAllowedValues = $oAttDef->GetAllowedValues($aArgs);
//
// /** @var \ormSet $oValue */
// $oValue = $this->Get('fields');
// $aValues = $oValue->GetValues();
// $bChanged = false;
// foreach($aValues as $key => $sValue)
// {
// if (!isset($aAllowedValues[$sValue]))
// {
// unset($aValues[$key]);
// $bChanged = true;
// }
// }
// if ($bChanged)
// {
// $oValue->SetValues($aValues);
// $this->Set('fields', $oValue);
// }
// }
// }
}
?>

View File

@@ -1,338 +1,338 @@
<?php <?php
// Copyright (C) 2010-2016 Combodo SARL // Copyright (C) 2010-2013 Combodo SARL
// //
// This file is part of iTop. // 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 // 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 // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// iTop is distributed in the hope that it will be useful, // iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details. // GNU Affero General Public License for more details.
// //
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* Persistent class Shortcut and derived * Persistent class Shortcut and derived
* Shortcuts of any kind * Shortcuts of any kind
* *
* @copyright Copyright (C) 2010-2016 Combodo SARL * @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
abstract class Shortcut extends DBObject implements iDisplay abstract class Shortcut extends DBObject implements iDisplay
{ {
public static function Init() public static function Init()
{ {
$aParams = array $aParams = array
( (
"category" => "gui,view_in_gui", "category" => "gui,view_in_gui",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array(), "reconc_keys" => array(),
"db_table" => "priv_shortcut", "db_table" => "priv_shortcut",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "realclass", "db_finalclass_field" => "realclass",
"display_template" => "", "display_template" => "",
); );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes(); //MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_AUTO, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("context", array("allowed_values"=>null, "sql"=>"context", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeText("context", array("allowed_values"=>null, "sql"=>"context", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists // Display lists
MetaModel::Init_SetZListItems('details', array('name', 'context')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('details', array('name', 'context')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('name')); // Attributes to be displayed for a list MetaModel::Init_SetZListItems('list', array('name')); // Attributes to be displayed for a list
// Search criteria // Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form // MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form // MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
} }
abstract public function RenderContent(WebPage $oPage, $aExtraParams = array()); abstract public function RenderContent(WebPage $oPage, $aExtraParams = array());
protected function OnInsert() protected function OnInsert()
{ {
$this->Set('user_id', UserRights::GetUserId()); $this->Set('user_id', UserRights::GetUserId());
} }
public function StartRenameDialog($oPage) public function StartRenameDialog($oPage)
{ {
$oPage->add('<div id="shortcut_rename_dlg">'); $oPage->add('<div id="shortcut_rename_dlg">');
$oForm = new DesignerForm(); $oForm = new DesignerForm();
$sDefault = $this->Get('name'); $sDefault = $this->Get('name');
$oField = new DesignerTextField('name', Dict::S('Class:Shortcut/Attribute:name'), $sDefault); $oField = new DesignerTextField('name', Dict::S('Class:Shortcut/Attribute:name'), $sDefault);
$oField->SetMandatory(true); $oField->SetMandatory(true);
$oForm->AddField($oField); $oForm->AddField($oField);
$oForm->Render($oPage); $oForm->Render($oPage);
$oPage->add('</div>'); $oPage->add('</div>');
$sDialogTitle = Dict::S('UI:ShortcutRenameDlg:Title'); $sDialogTitle = Dict::S('UI:ShortcutRenameDlg:Title');
$sOkButtonLabel = Dict::S('UI:Button:Ok'); $sOkButtonLabel = Dict::S('UI:Button:Ok');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel'); $sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$iShortcut = $this->GetKey(); $iShortcut = $this->GetKey();
$oPage->add_ready_script( $oPage->add_ready_script(
<<<EOF <<<EOF
function ShortcutRenameOK() function ShortcutRenameOK()
{ {
var oForm = $(this).find('form'); var oForm = $(this).find('form');
var sFormId = oForm.attr('id'); var sFormId = oForm.attr('id');
var oParams = null; var oParams = null;
var aErrors = ValidateForm(sFormId, false); var aErrors = ValidateForm(sFormId, false);
if (aErrors.length == 0) if (aErrors.length == 0)
{ {
oParams = ReadFormParams(sFormId); oParams = ReadFormParams(sFormId);
} }
oParams.operation = 'shortcut_rename_go'; oParams.operation = 'shortcut_rename_go';
oParams.id = $iShortcut; oParams.id = $iShortcut;
var me = $(this); var me = $(this);
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function(data) { $.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function(data) {
me.dialog( "close" ); me.dialog( "close" );
me.remove(); me.remove();
$('body').append(data); $('body').append(data);
}); });
} }
$('#shortcut_rename_dlg form').bind('submit', function() { return false; }); $('#shortcut_rename_dlg form').bind('submit', function() { return false; });
$('#shortcut_rename_dlg').dialog({ $('#shortcut_rename_dlg').dialog({
width: 400, width: 400,
modal: true, modal: true,
title: '$sDialogTitle', title: '$sDialogTitle',
buttons: [ buttons: [
{ text: "$sOkButtonLabel", click: ShortcutRenameOK}, { text: "$sOkButtonLabel", click: ShortcutRenameOK},
{ text: "$sCancelButtonLabel", click: function() { { text: "$sCancelButtonLabel", click: function() {
$(this).dialog( "close" ); $(this).remove(); $(this).dialog( "close" ); $(this).remove();
} }, } },
], ],
close: function() { $(this).remove(); } close: function() { $(this).remove(); }
}); });
EOF EOF
); );
} }
// Minimual implementation of iDisplay: to make the shortcut be listable // Minimual implementation of iDisplay: to make the shortcut be listable
// //
public static function MapContextParam($sContextParam) public static function MapContextParam($sContextParam)
{ {
return (($sContextParam == 'menu') ? null : $sContextParam); return (($sContextParam == 'menu') ? null : $sContextParam);
} }
public function GetHilightClass() public function GetHilightClass()
{ {
return HILIGHT_CLASS_NONE; return HILIGHT_CLASS_NONE;
} }
public static function GetUIPage() public static function GetUIPage()
{ {
return ''; return '';
} }
function DisplayDetails(WebPage $oPage, $bEditMode = false) function DisplayDetails(WebPage $oPage, $bEditMode = false)
{ {
} }
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array()) function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
{ {
return array(); return array();
} }
// End of the minimal implementation of iDisplay // End of the minimal implementation of iDisplay
} }
class ShortcutOQL extends Shortcut class ShortcutOQL extends Shortcut
{ {
public static function Init() public static function Init()
{ {
$aParams = array $aParams = array
( (
"category" => "gui,view_in_gui", "category" => "gui,view_in_gui",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array(), "reconc_keys" => array(),
"db_table" => "priv_shortcut_oql", "db_table" => "priv_shortcut_oql",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
"display_template" => "", "display_template" => "",
); );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes(); MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEnum("auto_reload", array("allowed_values"=>new ValueSetEnum('none,custom'), "sql"=>"auto_reload", "default_value"=>"none", "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeEnum("auto_reload", array("allowed_values"=>new ValueSetEnum('none,custom'), "sql"=>"auto_reload", "default_value"=>"none", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("auto_reload_sec", array("allowed_values"=>null, "sql"=>"auto_reload_sec", "default_value"=>60, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeInteger("auto_reload_sec", array("allowed_values"=>null, "sql"=>"auto_reload_sec", "default_value"=>60, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists // Display lists
MetaModel::Init_SetZListItems('details', array('name', 'context', 'oql')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('details', array('name', 'context', 'oql')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('name')); // Attributes to be displayed for a list MetaModel::Init_SetZListItems('list', array('name')); // Attributes to be displayed for a list
// Search criteria // Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form // MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form // MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
} }
public function RenderContent(WebPage $oPage, $aExtraParams = array()) public function RenderContent(WebPage $oPage, $aExtraParams = array())
{ {
$oPage->set_title($this->Get('name')); $oPage->set_title($this->Get('name'));
switch($this->Get('auto_reload')) switch($this->Get('auto_reload'))
{ {
case 'custom': case 'custom':
$iRate = (int)$this->Get('auto_reload_sec'); $iRate = (int)$this->Get('auto_reload_sec');
if ($iRate > 0) if ($iRate > 0)
{ {
// Must a string otherwise it can be evaluated to 'true' and defaults to "standard" refresh rate! // Must a string otherwise it can be evaluated to 'true' and defaults to "standard" refresh rate!
$aExtraParams['auto_reload'] = (string)$iRate; $aExtraParams['auto_reload'] = (string)$iRate;
} }
break; break;
default: default:
case 'none': case 'none':
} }
$bSearchPane = true; $bSearchPane = true;
$bSearchOpen = true; $bSearchOpen = false;
try try
{ {
OQLMenuNode::RenderOQLSearch($this->Get('oql'), $this->Get('name'), 'shortcut_'.$this->GetKey(), $bSearchPane, $bSearchOpen, $oPage, $aExtraParams, true); OQLMenuNode::RenderOQLSearch($this->Get('oql'), $this->Get('name'), 'shortcut_'.$this->GetKey(), $bSearchPane, $bSearchOpen, $oPage, $aExtraParams);
} }
catch (Exception $e) catch (Exception $e)
{ {
throw new Exception("The OQL shortcut '".$this->Get('name')."' (id: ".$this->GetKey().") could not be displayed: ".$e->getMessage()); throw new Exception("The OQL shortcut '".$this->Get('name')."' (id: ".$this->GetKey().") could not be displayed: ".$e->getMessage());
} }
} }
public function CloneTableSettings($sTableSettings) public function CloneTableSettings($sTableSettings)
{ {
$aTableSettings = json_decode($sTableSettings, true); $aTableSettings = json_decode($sTableSettings, true);
$oFilter = DBObjectSearch::FromOQL($this->Get('oql')); $oFilter = DBObjectSearch::FromOQL($this->Get('oql'));
$oCustomSettings = new DataTableSettings($oFilter->GetSelectedClasses()); $oCustomSettings = new DataTableSettings($oFilter->GetSelectedClasses());
$oCustomSettings->iDefaultPageSize = $aTableSettings['iPageSize']; $oCustomSettings->iDefaultPageSize = $aTableSettings['iPageSize'];
$oCustomSettings->aColumns = $aTableSettings['oColumns']; $oCustomSettings->aColumns = $aTableSettings['oColumns'];
$oCustomSettings->Save('shortcut_'.$this->GetKey()); $oCustomSettings->Save('shortcut_'.$this->GetKey());
} }
public static function GetCreationForm($sOQL = null, $sTableSettings = null) public static function GetCreationForm($sOQL = null, $sTableSettings = null)
{ {
$oForm = new DesignerForm(); $oForm = new DesignerForm();
// Find a unique default name // Find a unique default name
// -> The class of the query + an index if necessary // -> The class of the query + an index if necessary
if ($sOQL == null) if ($sOQL == null)
{ {
$sDefault = ''; $sDefault = '';
} }
else else
{ {
$oBMSearch = new DBObjectSearch('Shortcut'); $oBMSearch = new DBObjectSearch('Shortcut');
$oBMSearch->AddCondition('user_id', UserRights::GetUserId(), '='); $oBMSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oBMSet = new DBObjectSet($oBMSearch); $oBMSet = new DBObjectSet($oBMSearch);
$aNames = $oBMSet->GetColumnAsArray('name'); $aNames = $oBMSet->GetColumnAsArray('name');
$oSearch = DBObjectSearch::FromOQL($sOQL); $oSearch = DBObjectSearch::FromOQL($sOQL);
$sDefault = utils::MakeUniqueName($oSearch->GetClass(), $aNames); $sDefault = utils::MakeUniqueName($oSearch->GetClass(), $aNames);
} }
$oField = new DesignerTextField('name', Dict::S('Class:Shortcut/Attribute:name'), $sDefault); $oField = new DesignerTextField('name', Dict::S('Class:Shortcut/Attribute:name'), $sDefault);
$oField->SetMandatory(true); $oField->SetMandatory(true);
$oForm->AddField($oField); $oForm->AddField($oField);
/* /*
$oField = new DesignerComboField('auto_reload', Dict::S('Class:ShortcutOQL/Attribute:auto_reload'), 'none'); $oField = new DesignerComboField('auto_reload', Dict::S('Class:ShortcutOQL/Attribute:auto_reload'), 'none');
$oAttDef = MetaModel::GetAttributeDef(__class__, 'auto_reload'); $oAttDef = MetaModel::GetAttributeDef(__class__, 'auto_reload');
$oField->SetAllowedValues($oAttDef->GetAllowedValues()); $oField->SetAllowedValues($oAttDef->GetAllowedValues());
$oField->SetMandatory(true); $oField->SetMandatory(true);
$oForm->AddField($oField); $oForm->AddField($oField);
*/ */
$oField = new DesignerBooleanField('auto_reload', Dict::S('Class:ShortcutOQL/Attribute:auto_reload'), false); $oField = new DesignerBooleanField('auto_reload', Dict::S('Class:ShortcutOQL/Attribute:auto_reload'), false);
$oForm->AddField($oField); $oForm->AddField($oField);
$oField = new DesignerIntegerField('auto_reload_sec', Dict::S('Class:ShortcutOQL/Attribute:auto_reload_sec'), MetaModel::GetConfig()->GetStandardReloadInterval()); $oField = new DesignerIntegerField('auto_reload_sec', Dict::S('Class:ShortcutOQL/Attribute:auto_reload_sec'), MetaModel::GetConfig()->GetStandardReloadInterval());
$oField->SetBoundaries(MetaModel::GetConfig()->Get('min_reload_interval'), null); // no upper limit $oField->SetBoundaries(MetaModel::GetConfig()->Get('min_reload_interval'), null); // no upper limit
$oField->SetMandatory(false); $oField->SetMandatory(false);
$oForm->AddField($oField); $oForm->AddField($oField);
$oField = new DesignerHiddenField('oql', '', $sOQL); $oField = new DesignerHiddenField('oql', '', $sOQL);
$oForm->AddField($oField); $oForm->AddField($oField);
$oField = new DesignerHiddenField('table_settings', '', $sTableSettings); $oField = new DesignerHiddenField('table_settings', '', $sTableSettings);
$oForm->AddField($oField); $oForm->AddField($oField);
return $oForm; return $oForm;
} }
public static function GetCreationDlgFromOQL($oPage, $sOQL, $sTableSettings) public static function GetCreationDlgFromOQL($oPage, $sOQL, $sTableSettings)
{ {
$oPage->add('<div id="shortcut_creation_dlg">'); $oPage->add('<div id="shortcut_creation_dlg">');
$oForm = self::GetCreationForm($sOQL, $sTableSettings); $oForm = self::GetCreationForm($sOQL, $sTableSettings);
$oForm->Render($oPage); $oForm->Render($oPage);
$oPage->add('</div>'); $oPage->add('</div>');
$sDialogTitle = Dict::S('UI:ShortcutListDlg:Title'); $sDialogTitle = Dict::S('UI:ShortcutListDlg:Title');
$sOkButtonLabel = Dict::S('UI:Button:Ok'); $sOkButtonLabel = Dict::S('UI:Button:Ok');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel'); $sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$oAppContext = new ApplicationContext(); $oAppContext = new ApplicationContext();
$sContext = $oAppContext->GetForLink(); $sContext = $oAppContext->GetForLink();
$sRateTitle = addslashes(Dict::Format('Class:ShortcutOQL/Attribute:auto_reload_sec/tip', MetaModel::GetConfig()->Get('min_reload_interval'))); $sRateTitle = addslashes(Dict::Format('Class:ShortcutOQL/Attribute:auto_reload_sec/tip', MetaModel::GetConfig()->Get('min_reload_interval')));
$oPage->add_ready_script( $oPage->add_ready_script(
<<<EOF <<<EOF
// Note: the title gets deleted by the validation mechanism // Note: the title gets deleted by the validation mechanism
$("#attr_auto_reload_sec").tooltip({items: 'input', content: '$sRateTitle'}); $("#attr_auto_reload_sec").tooltip({items: 'input', content: '$sRateTitle'});
$("#attr_auto_reload_sec").prop('disabled', !$('#attr_auto_reload').is(':checked')); $("#attr_auto_reload_sec").prop('disabled', !$('#attr_auto_reload').is(':checked'));
$('#attr_auto_reload').change( function(ev) { $('#attr_auto_reload').change( function(ev) {
$("#attr_auto_reload_sec").prop('disabled', !$(this).is(':checked')); $("#attr_auto_reload_sec").prop('disabled', !$(this).is(':checked'));
} ); } );
function ShortcutCreationOK() function ShortcutCreationOK()
{ {
var oForm = $('#shortcut_creation_dlg form'); var oForm = $('#shortcut_creation_dlg form');
var sFormId = oForm.attr('id'); var sFormId = oForm.attr('id');
var oParams = null; var oParams = null;
var aErrors = ValidateForm(sFormId, false); var aErrors = ValidateForm(sFormId, false);
if (aErrors.length == 0) if (aErrors.length == 0)
{ {
oParams = ReadFormParams(sFormId); oParams = ReadFormParams(sFormId);
} }
oParams.operation = 'shortcut_list_create'; oParams.operation = 'shortcut_list_create';
var me = $('#shortcut_creation_dlg'); var me = $('#shortcut_creation_dlg');
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?$sContext', oParams, function(data) { $.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?$sContext', oParams, function(data) {
me.dialog( "close" ); me.dialog( "close" );
me.remove(); me.remove();
$('body').append(data); $('body').append(data);
}); });
} }
$('#shortcut_creation_dlg form').bind('submit', function() { ShortcutCreationOK(); return false; }); $('#shortcut_creation_dlg form').bind('submit', function() { ShortcutCreationOK(); return false; });
$('#shortcut_creation_dlg').dialog({ $('#shortcut_creation_dlg').dialog({
width: 400, width: 400,
modal: true, modal: true,
title: '$sDialogTitle', title: '$sDialogTitle',
buttons: [ buttons: [
{ text: "$sOkButtonLabel", click: ShortcutCreationOK }, { text: "$sOkButtonLabel", click: ShortcutCreationOK },
{ text: "$sCancelButtonLabel", click: function() { { text: "$sCancelButtonLabel", click: function() {
$(this).dialog( "close" ); $(this).remove(); $(this).dialog( "close" ); $(this).remove();
} }, } },
], ],
close: function() { $(this).remove(); } close: function() { $(this).remove(); }
}); });
EOF EOF
); );
} }
} }
?> ?>

View File

@@ -0,0 +1,531 @@
<?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/>
/**
* SqlBlock - display tables or charts, given an SQL query - use cautiously!
*
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/application/webpage.class.inc.php');
require_once(APPROOT.'/application/utils.inc.php');
require_once(APPROOT.'/pages/php-ofc-library/open-flash-chart.php');
/**
* Helper class to design optimized dashboards, based on an SQL query
*
*/
class SqlBlock
{
protected $m_sQuery;
protected $m_aColumns;
protected $m_sTitle;
protected $m_sType;
protected $m_aParams;
public function __construct($sQuery, $aColumns, $sTitle, $sType, $aParams = array())
{
$this->m_sQuery = $sQuery;
$this->m_aColumns = $aColumns;
$this->m_sTitle = $sTitle;
$this->m_sType = $sType;
$this->m_aParams = $aParams;
}
/**
* Constructs a SqlBlock object from an XML template
/*
*
* <sqlblock>
* <sql>SELECT date_format(start_date, '%d') AS Date, count(*) AS Count FROM ticket WHERE DATE_SUB(NOW(), INTERVAL 15 DAY) &lt; start_date AND finalclass = 'UserIssue' GROUP BY date_format(start_date, '%d') AND $CONDITION(param1, ticket.org_id)$</sql>
* <type>table</type>
* <title>UserRequest:Overview-Title</title>
* <parameter>
* <name>param1</name>
* <type>context</type>
* <mapping>org_id</mapping>
* </parameter>
* <column>
* <name>Date</name>
* <label>UserRequest:Overview-Date</label>
* <drilldown></drilldown>
* </column>
* <column>
* <name>Count</name>
* <label>UserRequest:Overview-Count</label>
* <drilldown>SELECT UserIssue WHERE date_format(start_date, '%d') = :Date</drilldown>
* </column>
* </sqlblock>
*
* Tags
* - sql: a (My)SQL query. Do not forget to use html entities (e.g. &lt; for <)
* - type: table (default), bars or pie. If bars or pie is selected only the two first columns are taken into account.
* - title: optional title, typed in clear or given as a dictionnary entry
* - parameter: specifies how to map the context parameters (namely org_id) to a given named parameter in the query.
* The expression $CONDITION(<param_name>, <sql_column_name>) will be automatically replaced by:
* either the string "1" if there is no restriction on the organisation in iTop
* or the string "(<sql_column_name>=<value_of_org_id>)" if there is a limitation to one organizations in iTop
* or the string "(<sql_column_name> IN (<values_of_org_id>))" if there is a limitation to a given set of organizations in iTop
* - column: specification of a column (not displayed if omitted)
* - column / name: name of the column in the SQL query (use aliases)
* - column / label: label, typed in clear or given as a dictionnary entry
* - column / drilldown: NOT IMPLEMENTED YET - OQL with parameters corresponding to column names (in the query)
*
* @param $sTemplate string The XML template
* @return DisplayBlock The DisplayBlock object, or null if the template is invalid
*/
public static function FromTemplate($sTemplate)
{
$oXml = simplexml_load_string('<root>'.$sTemplate.'</root>', 'SimpleXMLElement', LIBXML_NOCDATA);
if (false)
{
// Debug
echo "<pre>\n";
print_r($oXml);
echo "</pre>\n";
}
if (isset($oXml->title))
{
$sTitle = (string)$oXml->title;
}
if (isset($oXml->type))
{
$sType = (string)$oXml->type;
}
else
{
$sType = 'table';
}
if (!isset($oXml->sql))
{
throw new Exception('Missing tag "sql" in sqlblock');
}
$sQuery = (string)$oXml->sql;
$aColumns = array();
if (isset($oXml->column))
{
foreach ($oXml->column AS $oColumnData)
{
if (!isset($oColumnData->name))
{
throw new Exception("Missing tag 'name' in sqlblock/column");
}
$sName = (string) $oColumnData->name;
if (strlen($sName) == 0)
{
throw new Exception("Empty tag 'name' in sqlblock/column");
}
$aColumns[$sName] = array();
if (isset($oColumnData->label))
{
$sLabel = (string)$oColumnData->label;
if (strlen($sLabel) > 0)
{
$aColumns[$sName]['label'] = Dict::S($sLabel);
}
}
if (isset($oColumnData->drilldown))
{
$sDrillDown = (string)$oColumnData->drilldown;
if (strlen($sDrillDown) > 0)
{
$aColumns[$sName]['drilldown'] = $sDrillDown;
}
}
}
}
$aParams = array();
if (isset($oXml->parameter))
{
foreach ($oXml->parameter AS $oParamData)
{
if (!isset($oParamData->name))
{
throw new Exception("Missing tag 'name' for parameter in sqlblock/column");
}
$sName = (string) $oParamData->name;
if (strlen($sName) == 0)
{
throw new Exception("Empty tag 'name' for parameter in sqlblock/column");
}
if (!isset($oParamData->mapping))
{
throw new Exception("Missing tag 'mapping' for parameter in sqlblock/column");
}
$sMapping = (string) $oParamData->mapping;
if (strlen($sMapping) == 0)
{
throw new Exception("Empty tag 'mapping' for parameter in sqlblock/column");
}
if (isset($oParamData->type))
{
$sParamType = $oParamData->type;
}
else
{
$sParamType = 'context';
}
$aParams[$sName] = array('mapping' => $sMapping, 'type' => $sParamType);
}
}
return new SqlBlock($sQuery, $aColumns, $sTitle, $sType, $aParams);
}
/**
* Applies the defined parameters into the SQL query
* @return string the SQL query to execute
*/
public function BuildQuery()
{
$oAppContext = new ApplicationContext();
$sQuery = $this->m_sQuery;
$sQuery = str_replace('$DB_PREFIX$', MetaModel::GetConfig()->GetDBSubname(), $sQuery); // put the tables DB prefix (if any)
foreach($this->m_aParams as $sName => $aParam)
{
if ($aParam['type'] == 'context')
{
$sSearchPattern = '/\$CONDITION\('.$sName.',([^\)]+)\)\$/';
$value = $oAppContext->GetCurrentValue($aParam['mapping']);
if (empty($value))
{
$sSQLExpr = '(1)';
}
else
{
// Special case for managing the hierarchy of organizations
if (($aParam['mapping'] == 'org_id') && ( MetaModel::IsValidClass('Organization')))
{
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass('Organization');
if ($sHierarchicalKeyCode != false)
{
// organizations are in hierarchy... gather all the orgs below the given one...
$sOQL = "SELECT Organization AS node JOIN Organization AS root ON node.$sHierarchicalKeyCode BELOW root.id WHERE root.id = :value";
$oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL), array(), array('value' => $value));
$aOrgIds = array();
while($oOrg = $oSet->Fetch())
{
$aOrgIds[]= $oOrg->GetKey();
}
$sSQLExpr = '($1 IN('.implode(',', $aOrgIds).'))';
}
else
{
$sSQLExpr = '($1 = '.CMDBSource::Quote($value).')';
}
}
else
{
$sSQLExpr = '($1 = '.CMDBSource::Quote($value).')';
}
}
$sQuery = preg_replace($sSearchPattern, $sSQLExpr, $sQuery);
}
}
return $sQuery;
}
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
if (empty($aExtraParams['currentId']))
{
$sId = 'sqlblock_'.$oPage->GetUniqueId(); // Works only if the page is not an Ajax one !
}
else
{
$sId = $aExtraParams['currentId'];
}
// $oPage->add($this->GetRenderContent($oPage, $aExtraParams, $sId));
$sQuery = $this->BuildQuery();
$res = CMDBSource::Query($sQuery);
$aQueryCols = CMDBSource::GetColumns($res);
// Prepare column definitions (check + give default values)
//
foreach($this->m_aColumns as $sName => $aColumnData)
{
if (!in_array($sName, $aQueryCols))
{
throw new Exception("Unknown column name '$sName' in sqlblock column");
}
if (!isset($aColumnData['label']))
{
$this->m_aColumns[$sName]['label'] = $sName;
}
if (isset($aColumnData['drilldown']) && !empty($aColumnData['drilldown']))
{
// Check if the OQL is valid
try
{
$this->m_aColumns[$sName]['filter'] = DBObjectSearch::FromOQL($aColumnData['drilldown']);
}
catch(OQLException $e)
{
unset($aColumnData['drilldown']);
}
}
}
if (strlen($this->m_sTitle) > 0)
{
$oPage->add("<h2>".Dict::S($this->m_sTitle)."</h2>\n");
}
switch ($this->m_sType)
{
case 'bars':
case 'pie':
$aColNames = array_keys($this->m_aColumns);
$sXColName = $aColNames[0];
$sYColName = $aColNames[1];
$aData = array();
$aRows = array();
while($aRow = CMDBSource::FetchArray($res))
{
$aData[$aRow[$sXColName]] = $aRow[$sYColName];
$aRows[$aRow[$sXColName]] = $aRow;
}
$this->RenderChart($oPage, $sId, $aData, $this->m_aColumns[$sYColName]['drilldown'], $aRows);
break;
default:
case 'table':
$oAppContext = new ApplicationContext();
$sContext = $oAppContext->GetForLink();
if (!empty($sContext))
{
$sContext = '&'.$sContext;
}
$aDisplayConfig = array();
foreach($this->m_aColumns as $sName => $aColumnData)
{
$aDisplayConfig[$sName] = array('label' => $aColumnData['label'], 'description' => '');
}
$aDisplayData = array();
while($aRow = CMDBSource::FetchArray($res))
{
$aSQLColNames = array_keys($aRow);
$aDisplayRow = array();
foreach($this->m_aColumns as $sName => $aColumnData)
{
if (isset($aColumnData['filter']))
{
$sFilter = $aColumnData['drilldown'];
$sClass = $aColumnData['filter']->GetClass();
$sFilter = str_replace('SELECT '.$sClass, '', $sFilter);
foreach($aSQLColNames as $sColName)
{
$sFilter = str_replace(':'.$sColName, "'".addslashes( $aRow[$sColName] )."'", $sFilter);
}
$sURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search_oql&search_form=0&oql_class='.$sClass.'&oql_clause='.urlencode($sFilter).'&format=html'.$sContext;
$aDisplayRow[$sName] = '<a href="'.$sURL.'">'.$aRow[$sName]."</a>";
}
else
{
$aDisplayRow[$sName] = $aRow[$sName];
}
}
$aDisplayData[] = $aDisplayRow;
}
$oPage->table($aDisplayConfig, $aDisplayData);
break;
}
}
public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
{
$sHtml = '';
return $sHtml;
}
protected function RenderChart($oPage, $sId, $aValues, $sDrillDown = '', $aRows = array())
{
// 1- Compute Open Flash Chart data
//
$aValueKeys = array();
$index = 0;
if ((count($aValues) > 0) && ($sDrillDown != ''))
{
$oFilter = DBObjectSearch::FromOQL($sDrillDown);
$sClass = $oFilter->GetClass();
$sOQLClause = str_replace('SELECT '.$sClass, '', $sDrillDown);
$aSQLColNames = array_keys(current($aRows)); // Read the list of columns from the current (i.e. first) element of the array
$oAppContext = new ApplicationContext();
$sURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search_oql&search_form=0&oql_class='.$sClass.'&format=html&'.$oAppContext->GetForLink().'&oql_clause=';
}
$aURLs = array();
foreach($aValues as $key => $value)
{
// Make sure that values are integers (so that max() will work....)
// and build an array of STRING with the keys (numeric keys are transformed into string by PHP :-(
$aValues[$key] = (int)$value;
$aValueKeys[] = (string)$key;
// Build the custom query for the 'drill down' on each element
if ($sDrillDown != '')
{
$sFilter = $sOQLClause;
foreach($aSQLColNames as $sColName)
{
$sFilter = str_replace(':'.$sColName, "'".addslashes( $aRows[$key][$sColName] )."'", $sFilter);
$aURLs[$index] = $sURL.urlencode($sFilter);
}
}
$index++;
}
$oChart = new open_flash_chart();
if ($this->m_sType == 'bars')
{
$oChartElement = new bar_glass();
if (count($aValues) > 0)
{
$maxValue = max($aValues);
}
else
{
$maxValue = 1;
}
$oYAxis = new y_axis();
$aMagicValues = array(1,2,5,10);
$iMultiplier = 1;
$index = 0;
$iTop = $aMagicValues[$index % count($aMagicValues)]*$iMultiplier;
while($maxValue > $iTop)
{
$index++;
$iTop = $aMagicValues[$index % count($aMagicValues)]*$iMultiplier;
if (($index % count($aMagicValues)) == 0)
{
$iMultiplier = $iMultiplier * 10;
}
}
//echo "oYAxis->set_range(0, $iTop, $iMultiplier);\n";
$oYAxis->set_range(0, $iTop, $iMultiplier);
$oChart->set_y_axis( $oYAxis );
$aBarValues = array();
foreach($aValues as $iValue)
{
$oBarValue = new bar_value($iValue);
$oBarValue->on_click("ofc_drilldown_{$sId}");
$aBarValues[] = $oBarValue;
}
$oChartElement->set_values($aBarValues);
//$oChartElement->set_values(array_values($aValues));
$oXAxis = new x_axis();
$oXLabels = new x_axis_labels();
// set them vertical
$oXLabels->set_vertical();
// set the label text
$oXLabels->set_labels($aValueKeys);
// Add the X Axis Labels to the X Axis
$oXAxis->set_labels( $oXLabels );
$oChart->set_x_axis( $oXAxis );
}
else
{
$oChartElement = new pie();
$oChartElement->set_start_angle( 35 );
$oChartElement->set_animate( true );
$oChartElement->set_tooltip( '#label# - #val# (#percent#)' );
$oChartElement->set_colours( array('#FF8A00', '#909980', '#2C2B33', '#CCC08D', '#596664') );
$aData = array();
foreach($aValues as $sValue => $iValue)
{
$oPieValue = new pie_value($iValue, $sValue); //@@ BUG: not passed via ajax !!!
$oPieValue->on_click("ofc_drilldown_{$sId}");
$aData[] = $oPieValue;
}
$oChartElement->set_values( $aData );
$oChart->x_axis = null;
}
// Title given in HTML
//$oTitle = new title($this->m_sTitle);
//$oChart->set_title($oTitle);
$oChart->set_bg_colour('#FFFFFF');
$oChart->add_element( $oChartElement );
$sData = $oChart->toPrettyString();
$sData = json_encode($sData);
// 2- Declare the Javascript function that will render the chart data\
//
$oPage->add_script(
<<< EOF
function ofc_get_data_{$sId}()
{
return $sData;
}
EOF
);
if (count($aURLs) > 0)
{
$sURLList = '';
foreach($aURLs as $index => $sURL)
{
$sURLList .= "\taURLs[$index] = '".addslashes($sURL)."';\n";
}
$oPage->add_script(
<<< EOF
function ofc_drilldown_{$sId}(index)
{
var aURLs = new Array();
{$sURLList}
var sURL = aURLs[index];
window.location.href = sURL; // Navigate !
}
EOF
);
}
// 3- Insert the Open Flash chart
//
$oPage->add("<div id=\"$sId\"><div>\n");
$oPage->add_ready_script(
<<<EOF
swfobject.embedSWF( "../images/open-flash-chart.swf",
"{$sId}",
"100%", "300","9.0.0",
"expressInstall.swf",
{"get-data":"ofc_get_data_{$sId}", "id":"{$sId}"},
{'wmode': 'transparent'}
);
EOF
);
}
}
?>

View File

@@ -1,82 +1,50 @@
<?php <?php
// Copyright (C) 2010-2016 Combodo SARL // Copyright (C) 2010-2012 Combodo SARL
// //
// This file is part of iTop. // 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 // 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 // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// iTop is distributed in the hope that it will be useful, // iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details. // GNU Affero General Public License for more details.
// //
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* File to include to initialize the datamodel in memory * File to include to initialize the datamodel in memory
* *
* @copyright Copyright (C) 2010-2016 Combodo SARL * @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
// This storage is freed on error (case of allowed memory exhausted) require_once(APPROOT.'/core/cmdbobject.class.inc.php');
$sReservedMemory = str_repeat('*', 1024 * 1024); require_once(APPROOT.'/application/utils.inc.php');
register_shutdown_function(function() session_name('itop-'.md5(APPROOT));
{ session_start();
global $sReservedMemory; $sSwitchEnv = utils::ReadParam('switch_env', null);
$sReservedMemory = null; if (($sSwitchEnv != null) && (file_exists(APPCONF.$sSwitchEnv.'/'.ITOP_CONFIG_FILE)))
if (!is_null($err = error_get_last()) && ($err['type'] == E_ERROR)) {
{ $_SESSION['itop_env'] = $sSwitchEnv;
if (strpos($err['message'], 'Allowed memory size of') !== false) $sEnv = $sSwitchEnv;
{ // TODO: reset the credentials as well ??
$sLimit = ini_get('memory_limit'); }
echo "<p>iTop: Allowed memory size of $sLimit exhausted, contact your administrator to increase memory_limit in php.ini</p>\n"; else if (isset($_SESSION['itop_env']))
} {
else $sEnv = $_SESSION['itop_env'];
{ }
echo "<p>iTop: An error occurred, check server error log for more information.</p>\n"; else
} {
} $sEnv = ITOP_DEFAULT_ENV;
}); $_SESSION['itop_env'] = ITOP_DEFAULT_ENV;
}
require_once(APPROOT.'/core/cmdbobject.class.inc.php'); $sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE;
require_once(APPROOT.'/application/utils.inc.php'); MetaModel::Startup($sConfigFile);
require_once(APPROOT.'/core/contexttag.class.inc.php');
session_name('itop-'.md5(APPROOT)); ?>
session_start();
$sSwitchEnv = utils::ReadParam('switch_env', null);
$bAllowCache = true;
if (($sSwitchEnv != null) && (file_exists(APPCONF.$sSwitchEnv.'/'.ITOP_CONFIG_FILE)) && isset($_SESSION['itop_env']) && ($_SESSION['itop_env'] !== $sSwitchEnv))
{
$_SESSION['itop_env'] = $sSwitchEnv;
$sEnv = $sSwitchEnv;
$bAllowCache = false;
// Reset the opcache since otherwise the PHP "model" files may still be cached !!
if (function_exists('opcache_reset'))
{
// Zend opcode cache
opcache_reset();
}
if (function_exists('apc_clear_cache'))
{
// APC(u) cache
apc_clear_cache();
}
// TODO: reset the credentials as well ??
}
else if (isset($_SESSION['itop_env']))
{
$sEnv = $_SESSION['itop_env'];
}
else
{
$sEnv = ITOP_DEFAULT_ENV;
$_SESSION['itop_env'] = ITOP_DEFAULT_ENV;
}
$sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE;
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, $bAllowCache, false /* $bTraceSourceFiles */, $sEnv);

View File

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

View File

@@ -1,12 +1,12 @@
<div class="page_header"> <div class="page_header">
<itopblock blockclass="MenuBlock" type="popup" encoding="text/oql" label="Actions">SELECT $class$ WHERE id = $id$</itopblock> <itopblock blockclass="MenuBlock" type="popup" encoding="text/oql" label="Actions">SELECT $class$ WHERE id = $id$</itopblock>
<h1>$class$: <span class="hilite">$name$</span></h1> <h1>$class$: <span class="hilite">$name$</span></h1>
<itopblock blockclass="HistoryBlock" type="toggle" encoding="text/oql">SELECT CMDBChangeOp WHERE objkey = $id$ AND objclass = '$class$'</itopblock> <itopblock blockclass="HistoryBlock" type="toggle" encoding="text/oql">SELECT CMDBChangeOp WHERE objkey = $id$ AND objclass = '$class$'</itopblock>
</div> </div>
<img src="../../images/clean.png" style="margin-top:-20px; margin-right:10px; float:right"> <img src="../../images/clean.png" style="margin-top:-20px; margin-right:10px; float:right">
<itopblock blockclass="DisplayBlock" asynchronous="false" type="bare_details" encoding="text/oql">SELECT $class$ WHERE id = $id$</itopblock> <itopblock blockclass="DisplayBlock" asynchronous="false" type="bare_details" encoding="text/oql">SELECT $class$ WHERE id = $id$</itopblock>
<itoptabs> <itoptabs>
<itoptab name="Rules"> <itoptab name="Rules">
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT AuditRule WHERE category_id = $id$</itopblock> <itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT AuditRule WHERE category_id = $id$</itopblock>
</itoptab> </itoptab>
</itoptabs> </itoptabs>

View File

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

View File

@@ -1,5 +1,5 @@
<?php <?php
// Copyright (C) 2010-2017 Combodo SARL // Copyright (C) 2010-2012 Combodo SARL
// //
// This file is part of iTop. // This file is part of iTop.
// //
@@ -19,15 +19,15 @@
* Class UIExtKeyWidget * Class UIExtKeyWidget
* UI wdiget for displaying and editing external keys when * UI wdiget for displaying and editing external keys when
* A simple drop-down list is not enough... * A simple drop-down list is not enough...
* *
* The layout is the following * The layout is the following
* *
* +-- #label_<id> (input)-------+ +-----------+ * +-- #label_<id> (input)-------+ +-----------+
* | | | Browse... | * | | | Browse... |
* +-----------------------------+ +-----------+ * +-----------------------------+ +-----------+
* *
* And the popup dialog has the following layout: * And the popup dialog has the following layout:
* *
* +------------------- ac_dlg_<id> (div)-----------+ * +------------------- ac_dlg_<id> (div)-----------+
* + +--- ds_<id> (div)---------------------------+ | * + +--- ds_<id> (div)---------------------------+ |
* | | +------------- fs_<id> (form)------------+ | | * | | +------------- fs_<id> (form)------------+ | |
@@ -54,23 +54,20 @@
* | | +--------+ +-----+ | | * | | +--------+ +-----+ | |
* | +--------------------------------------------+ | * | +--------------------------------------------+ |
* +------------------------------------------------+ * +------------------------------------------------+
* @copyright Copyright (C) 2010-2017 Combodo SARL * @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
require_once(APPROOT.'/application/webpage.class.inc.php'); require_once(APPROOT.'/application/webpage.class.inc.php');
require_once(APPROOT.'/application/displayblock.class.inc.php'); require_once(APPROOT.'/application/displayblock.class.inc.php');
class UIExtKeyWidget class UIExtKeyWidget
{ {
const ENUM_OUTPUT_FORMAT_CSV = 'csv';
const ENUM_OUTPUT_FORMAT_JSON = 'json';
protected $iId; protected $iId;
protected $sTargetClass; protected $sTargetClass;
protected $sAttCode; protected $sAttCode;
protected $bSearchMode; protected $bSearchMode;
//public function __construct($sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '') //public function __construct($sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '')
static public function DisplayFromAttCode($oPage, $sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName = '', $sFormPrefix = '', $aArgs, $bSearchMode = false) static public function DisplayFromAttCode($oPage, $sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName = '', $sFormPrefix = '', $aArgs, $bSearchMode = false)
{ {
@@ -97,36 +94,36 @@ class UIExtKeyWidget
$this->sAttCode = $sAttCode; $this->sAttCode = $sAttCode;
$this->bSearchMode = $bSearchMode; $this->bSearchMode = $bSearchMode;
} }
/** /**
* Get the HTML fragment corresponding to the ext key editing widget * Get the HTML fragment corresponding to the ext key editing widget
* @param WebPage $oP The web page used for all the output * @param WebPage $oP The web page used for all the output
* @param array $aArgs Extra context arguments * @param Hash $aArgs Extra context arguments
* @return string The HTML fragment to be inserted into the page * @return string The HTML fragment to be inserted into the page
*/ */
public function Display(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, DBObjectset $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = array(), $bSearchMode = null, $sDisplayStyle = 'select', $bSearchMultiple = true) public function Display(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = array(), $bSearchMode = null, $sDisplayStyle = 'select', $bSearchMultiple = true)
{ {
if (!is_null($bSearchMode)) if (!is_null($bSearchMode))
{ {
$this->bSearchMode = $bSearchMode; $this->bSearchMode = $bSearchMode;
} }
$sTitle = addslashes($sTitle); $sTitle = addslashes($sTitle);
$oPage->add_linked_script('../js/extkeywidget.js'); $oPage->add_linked_script('../js/extkeywidget.js');
$oPage->add_linked_script('../js/forms-json-utils.js'); $oPage->add_linked_script('../js/forms-json-utils.js');
$bCreate = (!$this->bSearchMode) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation); $bCreate = (!$this->bSearchMode) && (!MetaModel::IsAbstract($this->sTargetClass)) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation);
$bExtensions = true; $bExtensions = true;
$sMessage = Dict::S('UI:Message:EmptyList:UseSearchForm'); $sMessage = Dict::S('UI:Message:EmptyList:UseSearchForm');
$sAttrFieldPrefix = ($this->bSearchMode) ? '' : 'attr_'; $sAttrFieldPrefix = ($this->bSearchMode) ? '' : 'attr_';
$sHTMLValue = "<div class=\"field_input_zone field_input_extkey\">"; $sHTMLValue = "<span style=\"white-space:nowrap\">"; // no wrap
$sFilter = addslashes($oAllowedValues->GetFilter()->ToOQL()); $sFilter = addslashes($oAllowedValues->GetFilter()->ToOQL());
if($this->bSearchMode) if($this->bSearchMode)
{ {
$sWizHelper = 'null'; $sWizHelper = 'null';
$sWizHelperJSON = "''"; $sWizHelperJSON = "''";
$sJSSearchMode = 'true'; $sJSSearchMode = 'true';
} }
else else
{ {
if (isset($aArgs['wizHelper'])) if (isset($aArgs['wizHelper']))
@@ -144,22 +141,16 @@ class UIExtKeyWidget
{ {
throw new Exception('Implementation: null value for allowed values definition'); throw new Exception('Implementation: null value for allowed values definition');
} }
$oAllowedValues->SetShowObsoleteData(utils::ShowObsoleteData()); elseif ($oAllowedValues->Count() < $iMaxComboLength)
// Don't automatically launch the search if the table is huge
$bDoSearch = !utils::IsHighCardinality($this->sTargetClass);
$sJSDoSearch = $bDoSearch ? 'true' : 'false';
// We just need to compare the number of entries with MaxComboLength, so no need to get the real count.
if (!$oAllowedValues->CountExceeds($iMaxComboLength))
{ {
// Discrete list of values, use a SELECT or RADIO buttons depending on the config // Discrete list of values, use a SELECT or RADIO buttons depending on the config
switch($sDisplayStyle) switch($sDisplayStyle)
{ {
case 'radio': case 'radio':
case 'radio_horizontal': case 'radio_horizontal':
case 'radio_vertical': case 'radio_vertical':
$sValidationField = null; $sValidationField = "<span id=\"v_{$this->iId}\"></span>";
$sHTMLValue = '';
$bVertical = ($sDisplayStyle != 'radio_horizontal'); $bVertical = ($sDisplayStyle != 'radio_horizontal');
$bExtensions = false; $bExtensions = false;
$oAllowedValues->Rewind(); $oAllowedValues->Rewind();
@@ -167,62 +158,53 @@ class UIExtKeyWidget
while($oObj = $oAllowedValues->Fetch()) while($oObj = $oAllowedValues->Fetch())
{ {
$aAllowedValues[$oObj->GetKey()] = $oObj->GetName(); $aAllowedValues[$oObj->GetKey()] = $oObj->GetName();
} }
$sHTMLValue .= $oPage->GetRadioButtons($aAllowedValues, $value, $this->iId, "{$sAttrFieldPrefix}{$sFieldName}", false /* $bMandatory will be placed manually */, $bVertical, $sValidationField); $sHTMLValue = $oPage->GetRadioButtons($aAllowedValues, $value, $this->iId, "{$sAttrFieldPrefix}{$sFieldName}", $bMandatory, $bVertical, $sValidationField);
$aEventsList[] ='change'; $aEventsList[] ='change';
break; break;
case 'select': case 'select':
case 'list':
default: default:
$sSelectMode = 'true';
$sHelpText = ''; //$this->oAttDef->GetHelpOnEdition(); $sHelpText = ''; //$this->oAttDef->GetHelpOnEdition();
$sHTMLValue .= "<div class=\"field_select_wrapper\">\n";
if ($this->bSearchMode) if ($this->bSearchMode)
{ {
if ($bSearchMultiple) if ($bSearchMultiple)
{ {
$sHTMLValue .= "<select class=\"multiselect\" multiple title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$sFieldName}[]\" id=\"$this->iId\">\n"; $sHTMLValue = "<select class=\"multiselect\" multiple title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$sFieldName}[]\" id=\"$this->iId\">\n";
} }
else else
{ {
$sHTMLValue .= "<select title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" id=\"$this->iId\">\n"; $sHTMLValue = "<select title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" id=\"$this->iId\">\n";
$sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : Dict::S('UI:SearchValue:Any'); $sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : Dict::S('UI:SearchValue:Any');
$sHTMLValue .= "<option value=\"\">$sDisplayValue</option>\n"; $sHTMLValue .= "<option value=\"\">$sDisplayValue</option>\n";
} }
} }
else else
{ {
$sHTMLValue .= "<select title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" id=\"$this->iId\">\n"; $sHTMLValue = "<select title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" id=\"$this->iId\">\n";
$sHTMLValue .= "<option value=\"\">".Dict::S('UI:SelectOne')."</option>\n"; $sHTMLValue .= "<option value=\"\">".Dict::S('UI:SelectOne')."</option>\n";
} }
$oAllowedValues->Rewind(); $oAllowedValues->Rewind();
while($oObj = $oAllowedValues->Fetch()) while($oObj = $oAllowedValues->Fetch())
{ {
$key = $oObj->GetKey(); $key = $oObj->GetKey();
$display_value = $oObj->GetName(); $display_value = $oObj->GetName();
if (($oAllowedValues->Count() == 1) && ($bMandatory == 'true') ) if (($oAllowedValues->Count() == 1) && ($bMandatory == 'true') )
{ {
// When there is only once choice, select it by default // When there is only once choice, select it by default
$sSelected = 'selected'; $sSelected = ' selected';
$oPage->add_ready_script(
<<<EOF
$('#$this->iId').attr('data-validate','dependencies');
EOF
);
} }
else else
{ {
$sSelected = (is_array($value) && in_array($key, $value)) || ($value == $key) ? 'selected' : ''; $sSelected = (is_array($value) && in_array($key, $value)) || ($value == $key) ? ' selected' : '';
} }
$sHTMLValue .= "<option value=\"$key\" $sSelected>$display_value</option>\n"; $sHTMLValue .= "<option value=\"$key\"$sSelected>$display_value</option>\n";
} }
$sHTMLValue .= "</select>\n"; $sHTMLValue .= "</select>\n";
$sHTMLValue .= "</div>\n";
if (($this->bSearchMode) && $bSearchMultiple) if (($this->bSearchMode) && $bSearchMultiple)
{ {
$aOptions = array( $aOptions = array(
@@ -238,7 +220,7 @@ EOF
} }
$oPage->add_ready_script( $oPage->add_ready_script(
<<<EOF <<<EOF
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode, $sJSDoSearch); oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode);
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>"; oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
$('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } ); $('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } );
$('#$this->iId').bind('change', function() { $(this).trigger('extkeychange') } ); $('#$this->iId').bind('change', function() { $(this).trigger('extkeychange') } );
@@ -250,6 +232,8 @@ EOF
else else
{ {
// Too many choices, use an autocomplete // Too many choices, use an autocomplete
$sSelectMode = 'false';
// Check that the given value is allowed // Check that the given value is allowed
$oSearch = $oAllowedValues->GetFilter(); $oSearch = $oAllowedValues->GetFilter();
$oSearch->AddCondition('id', $value); $oSearch->AddCondition('id', $value);
@@ -268,19 +252,20 @@ EOF
$sDisplayValue = $this->GetObjectName($value); $sDisplayValue = $this->GetObjectName($value);
} }
$iMinChars = isset($aArgs['iMinChars']) ? $aArgs['iMinChars'] : 3; //@@@ $this->oAttDef->GetMinAutoCompleteChars(); $iMinChars = isset($aArgs['iMinChars']) ? $aArgs['iMinChars'] : 3; //@@@ $this->oAttDef->GetMinAutoCompleteChars();
$iFieldSize = isset($aArgs['iFieldSize']) ? $aArgs['iFieldSize'] : 30; //@@@ $this->oAttDef->GetMaxSize();
// the input for the auto-complete // the input for the auto-complete
$sHTMLValue .= "<input class=\"field_autocomplete\" type=\"text\" id=\"label_$this->iId\" value=\"$sDisplayValue\"/>"; $sHTMLValue = "<input count=\"".$oAllowedValues->Count()."\" type=\"text\" id=\"label_$this->iId\" size=\"$iFieldSize\" value=\"$sDisplayValue\"/>&nbsp;";
$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>"; $sHTMLValue .= "<img id=\"mini_search_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_search.gif\" onClick=\"oACWidget_{$this->iId}.Search();\"/>&nbsp;";
// another hidden input to store & pass the object's Id // 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"; $sHTMLValue .= "<input type=\"hidden\" id=\"$this->iId\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" value=\"".htmlentities($value, ENT_QUOTES, 'UTF-8')."\" />\n";
$JSSearchMode = $this->bSearchMode ? 'true' : 'false'; $JSSearchMode = $this->bSearchMode ? 'true' : 'false';
// Scripts to start the autocomplete and bind some events to it // Scripts to start the autocomplete and bind some events to it
$oPage->add_ready_script( $oPage->add_ready_script(
<<<EOF <<<EOF
oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode, $sJSDoSearch); oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper, '{$this->sAttCode}', $sJSSearchMode);
oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>"; oACWidget_{$this->iId}.emptyHtml = "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>$sMessage</p></div>";
$('#label_$this->iId').autocomplete(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', { scroll:true, minChars:{$iMinChars}, autoFill:false, matchContains:true, mustMatch: true, keyHolder:'#{$this->iId}', extraParams:{operation:'ac_extkey', sTargetClass:'{$this->sTargetClass}',sFilter:'$sFilter',bSearchMode:$JSSearchMode, json: function() { return $sWizHelperJSON; } }}); $('#label_$this->iId').autocomplete(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', { scroll:true, minChars:{$iMinChars}, autoFill:false, matchContains:true, mustMatch: true, keyHolder:'#{$this->iId}', extraParams:{operation:'ac_extkey', sTargetClass:'{$this->sTargetClass}',sFilter:'$sFilter',bSearchMode:$JSSearchMode, json: function() { return $sWizHelperJSON; } }});
$('#label_$this->iId').keyup(function() { if ($(this).val() == '') { $('#$this->iId').val(''); } } ); // Useful for search forms: empty value in the "label", means no value, immediatly ! $('#label_$this->iId').keyup(function() { if ($(this).val() == '') { $('#$this->iId').val(''); } } ); // Useful for search forms: empty value in the "label", means no value, immediatly !
@@ -295,7 +280,7 @@ EOF
} }
if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false) if ($bExtensions && MetaModel::IsHierarchicalClass($this->sTargetClass) !== false)
{ {
$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>"; $sHTMLValue .= "<img id=\"mini_tree_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_tree.gif\" onClick=\"oACWidget_{$this->iId}.HKDisplay();\"/>&nbsp;";
$oPage->add_ready_script( $oPage->add_ready_script(
<<<EOF <<<EOF
if ($('#ac_tree_{$this->iId}').length == 0) if ($('#ac_tree_{$this->iId}').length == 0)
@@ -307,9 +292,7 @@ EOF
} }
if ($bCreate && $bExtensions) if ($bCreate && $bExtensions)
{ {
$sCallbackName = (MetaModel::IsAbstract($this->sTargetClass)) ? 'SelectObjectClass' : 'CreateObject'; $sHTMLValue .= "<img id=\"mini_add_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_add.gif\" onClick=\"oACWidget_{$this->iId}.CreateObject();\"/>&nbsp;";
$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( $oPage->add_ready_script(
<<<EOF <<<EOF
if ($('#ajax_{$this->iId}').length == 0) if ($('#ajax_{$this->iId}').length == 0)
@@ -319,17 +302,14 @@ EOF
EOF EOF
); );
} }
$sHTMLValue .= "</div>"; if ($sDisplayStyle == 'select')
{
// Note: This test is no longer necessary as we changed the markup to extract validation decoration in the standard .field_input_xxx container $sHTMLValue .= "<span id=\"v_{$this->iId}\"></span>";
//if (($sDisplayStyle == 'select') || ($sDisplayStyle == 'list')) }
//{ $sHTMLValue .= "</span>"; // end of no wrap
$sHTMLValue .= "<span class=\"form_validation\" id=\"v_{$this->iId}\"></span><span class=\"field_status\" id=\"fstatus_{$this->iId}\"></span>";
//}
return $sHTMLValue; return $sHTMLValue;
} }
public function GetSearchDialog(WebPage $oPage, $sTitle, $oCurrObject = null) public function GetSearchDialog(WebPage $oPage, $sTitle, $oCurrObject = null)
{ {
$sHTML = '<div class="wizContainer" style="vertical-align:top;"><div id="dc_'.$this->iId.'">'; $sHTML = '<div class="wizContainer" style="vertical-align:top;"><div id="dc_'.$this->iId.'">';
@@ -337,8 +317,7 @@ EOF
if ( ($oCurrObject != null) && ($this->sAttCode != '')) if ( ($oCurrObject != null) && ($this->sAttCode != ''))
{ {
$oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode); $oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode);
/** @var \DBObject $oCurrObject */ $aArgs = array('this' => $oCurrObject);
$aArgs = $oCurrObject->ToArgsForQuery();
$aParams = array('query_params' => $aArgs); $aParams = array('query_params' => $aArgs);
$oSet = $oAttDef->GetAllowedValuesAsObjectSet($aArgs); $oSet = $oAttDef->GetAllowedValuesAsObjectSet($aArgs);
$oFilter = $oSet->GetFilter(); $oFilter = $oSet->GetFilter();
@@ -350,16 +329,7 @@ EOF
} }
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode); $oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oBlock = new DisplayBlock($oFilter, 'search', false, $aParams); $oBlock = new DisplayBlock($oFilter, 'search', false, $aParams);
$sHTML .= $oBlock->GetDisplay($oPage, $this->iId, $sHTML .= $oBlock->GetDisplay($oPage, $this->iId, array('open' => true, 'currentId' => $this->iId));
array(
'menu' => false,
'currentId' => $this->iId,
'table_id' => "dr_{$this->iId}",
'table_inner_id' => "{$this->iId}_results",
'selection_mode' => true,
'selection_type' => 'single',
'cssCount' => '#count_'.$this->iId)
);
$sHTML .= "<form id=\"fr_{$this->iId}\" OnSubmit=\"return oACWidget_{$this->iId}.DoOk();\">\n"; $sHTML .= "<form id=\"fr_{$this->iId}\" OnSubmit=\"return oACWidget_{$this->iId}.DoOk();\">\n";
$sHTML .= "<div id=\"dr_{$this->iId}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n"; $sHTML .= "<div id=\"dr_{$this->iId}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
$sHTML .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n"; $sHTML .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
@@ -383,13 +353,9 @@ EOF
/** /**
* Search for objects to be selected * Search for objects to be selected
*
* @param WebPage $oP The page used for the output (usually an AjaxWebPage) * @param WebPage $oP The page used for the output (usually an AjaxWebPage)
* @param $sFilter
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of m_sRemoteClass * @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of m_sRemoteClass
* @param null $oObj * @param Array $aAlreadyLinkedIds List of IDs of objects of "remote" class already linked, to be filtered out of the search
*
* @throws \OQLException
*/ */
public function SearchObjectsToSelect(WebPage $oP, $sFilter, $sRemoteClass = '', $oObj = null) public function SearchObjectsToSelect(WebPage $oP, $sFilter, $sRemoteClass = '', $oObj = null)
{ {
@@ -397,87 +363,39 @@ EOF
{ {
throw new Exception('Implementation: null value for allowed values definition'); throw new Exception('Implementation: null value for allowed values definition');
} }
$oFilter = DBObjectSearch::FromOQL($sFilter); $oFilter = DBObjectSearch::FromOQL($sFilter);
if (strlen($sRemoteClass) > 0) if (strlen($sRemoteClass) > 0)
{ {
$oFilter->ChangeClass($sRemoteClass); $oFilter->ChangeClass($sRemoteClass);
} }
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode); $oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oBlock = new DisplayBlock($oFilter, 'list', false, array('query_params' => array('this' => $oObj)));
// Current extkey value, so we can display event if it is not available anymore (eg. archived).
$iCurrentExtKeyId = (is_null($oObj)) ? 0 : $oObj->Get($this->sAttCode);
$oBlock = new DisplayBlock($oFilter, 'list_search', false, array('query_params' => array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId)));
$oBlock->Display($oP, $this->iId.'_results', array('this' => $oObj, 'cssCount'=> '#count_'.$this->iId, 'menu' => false, 'selection_mode' => true, 'selection_type' => 'single', 'table_id' => 'select_'.$this->sAttCode)); // Don't display the 'Actions' menu on the results $oBlock->Display($oP, $this->iId.'_results', array('this' => $oObj, 'cssCount'=> '#count_'.$this->iId, 'menu' => false, 'selection_mode' => true, 'selection_type' => 'single', 'table_id' => 'select_'.$this->sAttCode)); // Don't display the 'Actions' menu on the results
} }
/** /**
* Search for objects to be selected * Search for objects to be selected
* * @param WebPage $oP The page used for the output (usually an AjaxWebPage)
* @param WebPage $oP The page used for the output (usually an AjaxWebPage) * @param string $sFilter The OQL expression used to define/limit limit the scope of possible values
* @param string $sFilter The OQL expression used to define/limit limit the scope of possible values * @param DBObject $oObj The current object for the OQL context
* @param DBObject $oObj The current object for the OQL context * @param string $sContains The text of the autocomplete to filter the results
* @param string $sContains The text of the autocomplete to filter the results */
* @param string $sOutputFormat public function AutoComplete(WebPage $oP, $sFilter, $oObj = null, $sContains)
* @param null $sOperation for the values @see ValueSetObjects->LoadValues()
*
* @throws CoreException
* @throws OQLException
*/
public function AutoComplete(WebPage $oP, $sFilter, $oObj = null, $sContains, $sOutputFormat = self::ENUM_OUTPUT_FORMAT_CSV, $sOperation = null)
{ {
if (is_null($sFilter)) if (is_null($sFilter))
{ {
throw new Exception('Implementation: null value for allowed values definition'); throw new Exception('Implementation: null value for allowed values definition');
} }
// Current extkey value, so we can display event if it is not available anymore (eg. archived).
$iCurrentExtKeyId = (is_null($oObj) || $this->sAttCode === '') ? 0 : $oObj->Get($this->sAttCode);
$oValuesSet = new ValueSetObjects($sFilter, 'friendlyname'); // Bypass GetName() to avoid the encoding by htmlentities $oValuesSet = new ValueSetObjects($sFilter, 'friendlyname'); // Bypass GetName() to avoid the encoding by htmlentities
$iMax = 150;
$oValuesSet->SetLimit($iMax);
$oValuesSet->SetSort(false);
$oValuesSet->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode); $oValuesSet->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oValuesSet->SetLimit($iMax); $aValues = $oValuesSet->GetValues(array('this' => $oObj), $sContains);
$aValuesContains = $oValuesSet->GetValues(array('this' => $oObj, 'current_extkey_id' => $iCurrentExtKeyId), $sContains, 'contains'); foreach($aValues as $sKey => $sFriendlyName)
asort($aValuesContains);
$aValues = array();
foreach($aValuesContains as $sKey => $sFriendlyName)
{ {
if (!isset($aValues[$sKey])) $oP->add(trim($sFriendlyName)."\t".$sKey."\n");
{
$aValues[$sKey] = $sFriendlyName;
}
}
switch($sOutputFormat)
{
case static::ENUM_OUTPUT_FORMAT_JSON:
$aJsonMap = array();
foreach ($aValues as $sKey => $sLabel)
{
$aJsonMap[] = array('value' => $sKey, 'label' => $sLabel);
}
$oP->SetContentType('application/json');
$oP->add(json_encode($aJsonMap));
break;
case static::ENUM_OUTPUT_FORMAT_CSV:
foreach($aValues as $sKey => $sFriendlyName)
{
$oP->add(trim($sFriendlyName)."\t".$sKey."\n");
}
break;
default:
throw new Exception('Invalid output format, "'.$sOutputFormat.'" given.');
break;
} }
} }
/** /**
* Get the display name of the selected object, to fill back the autocomplete * Get the display name of the selected object, to fill back the autocomplete
*/ */
@@ -496,56 +414,11 @@ EOF
return ''; return '';
} }
} }
/**
* Get the form to select a leaf class from the $this->sTargetClass (that should be abstract)
* Note: Inspired from UILinksWidgetDirect::GetObjectCreationDialog()
*
* @param WebPage $oPage
*
* @throws \CoreException
* @throws \DictExceptionMissingString
*/
public function GetClassSelectionForm(WebPage $oPage)
{
// For security reasons: check that the "proposed" class is actually a subclass of the linked class
// and that the current user is allowed to create objects of this class
$aSubClasses = MetaModel::EnumChildClasses($this->sTargetClass);
$aPossibleClasses = array();
foreach($aSubClasses as $sCandidateClass)
{
if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES))
{
$aPossibleClasses[$sCandidateClass] = MetaModel::GetName($sCandidateClass);
}
}
$sDialogTitle = '';
$oPage->add('<div id="ac_create_'.$this->iId.'"><div class="wizContainer" style="vertical-align:top;"><div id="dcr_'.$this->iId.'">');
$oPage->add('<form>');
$sClassLabel = MetaModel::GetName($this->sTargetClass);
$oPage->add('<p>'.Dict::Format('UI:SelectTheTypeOf_Class_ToCreate', $sClassLabel));
$oPage->add('<nobr><select name="class">');
asort($aPossibleClasses);
foreach($aPossibleClasses as $sClassName => $sClassLabel)
{
$oPage->add("<option value=\"$sClassName\">$sClassLabel</option>");
}
$oPage->add('</select>');
$oPage->add('&nbsp; <button type="submit" class="action" style="margin-top:15px;"><span>' . Dict::S('UI:Button:Ok') . '</span></button></nobr></p>');
$oPage->add('</form>');
$oPage->add('</div></div></div>');
$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');");
$oPage->add_ready_script("$('#dcr_{$this->iId} form').bind('submit.uilinksWizard', oACWidget_{$this->iId}.DoSelectObjectClass);");
}
/** /**
* Get the form to create a new object of the 'target' class * Get the form to create a new object of the 'target' class
*/ */
public function GetObjectCreationForm(WebPage $oPage, $oCurrObject, $aPrefillFormParam) public function GetObjectCreationForm(WebPage $oPage, $oCurrObject)
{ {
// Set all the default values in an object and clone this "default" object // Set all the default values in an object and clone this "default" object
$oNewObj = MetaModel::NewObject($this->sTargetClass); $oNewObj = MetaModel::NewObject($this->sTargetClass);
@@ -553,7 +426,7 @@ EOF
// 1st - set context values // 1st - set context values
$oAppContext = new ApplicationContext(); $oAppContext = new ApplicationContext();
$oAppContext->InitObjectFromContext($oNewObj); $oAppContext->InitObjectFromContext($oNewObj);
$oNewObj->PrefillForm('creation_from_extkey', $aPrefillFormParam);
// 2nd set the default values from the constraint on the external key... if any // 2nd set the default values from the constraint on the external key... if any
if ( ($oCurrObject != null) && ($this->sAttCode != '')) if ( ($oCurrObject != null) && ($this->sAttCode != ''))
{ {
@@ -570,24 +443,14 @@ EOF
} }
} }
} }
// 3rd - set values from the page argument 'default' // 3rd - set values from the page argument 'default'
$oNewObj->UpdateObjectFromArg('default'); $oNewObj->UpdateObjectFromArg('default');
$sDialogTitle = ''; $sDialogTitle = '';
$oPage->add('<div id="ac_create_'.$this->iId.'"><div class="wizContainer" style="vertical-align:top;"><div id="dcr_'.$this->iId.'">'); $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"); $oPage->add("<h1>".MetaModel::GetClassIcon($this->sTargetClass)."&nbsp;".Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sTargetClass))."</h1>\n");
$aFieldsFlags = array(); cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, $oNewObj, array(), array('formPrefix' => $this->iId, 'noRelations' => true));
$aFieldsComments = array();
foreach(MetaModel::ListAttributeDefs($this->sTargetClass) as $sAttCode => $oAttDef)
{
if (($oAttDef instanceof AttributeBlob) || (false))
{
$aFieldsFlags[$sAttCode] = OPT_ATT_READONLY;
$aFieldsComments[$sAttCode] = '&nbsp;<img src="../images/transp-lock.png" style="vertical-align:middle" title="'.htmlentities(Dict::S('UI:UploadNotSupportedInThisMode')).'"/>';
}
}
cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, $oNewObj, array(), array('formPrefix' => $this->iId, 'noRelations' => true, 'fieldsFlags' => $aFieldsFlags, 'fieldsComments' => $aFieldsComments));
$oPage->add('</div></div></div>'); $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: $(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("\$('#ac_create_$this->iId').dialog({ width: 'auto', height: 'auto', maxHeight: $(window).height() - 50, autoOpen: false, modal: true, title: '$sDialogTitle'});\n");
@@ -607,12 +470,21 @@ EOF
{ {
throw new Exception('Implementation: null value for allowed values definition'); throw new Exception('Implementation: null value for allowed values definition');
} }
try
$oFilter = DBObjectSearch::FromOQL($sFilter); {
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode); $oFilter = DBObjectSearch::FromOQL($sFilter);
$oSet = new DBObjectSet($oFilter, array(), array('this' => $oObj, 'current_extkey_id' => $currValue)); $oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oSet = new DBObjectSet($oFilter, array(), array('this' => $oObj));
$oSet->SetShowObsoleteData(utils::ShowObsoleteData()); }
catch(MissingQueryArgument $e)
{
// When used in a search form the $this parameter may be missing, in this case return all possible values...
// TODO check if we can improve this behavior...
$sOQL = 'SELECT '.$this->m_sTargetClass;
$oFilter = DBObjectSearch::FromOQL($sOQL);
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oSet = new DBObjectSet($oFilter);
}
$sHKAttCode = MetaModel::IsHierarchicalClass($this->sTargetClass); $sHKAttCode = MetaModel::IsHierarchicalClass($this->sTargetClass);
$this->DumpTree($oPage, $oSet, $sHKAttCode, $currValue); $this->DumpTree($oPage, $oSet, $sHKAttCode, $currValue);
@@ -621,7 +493,7 @@ EOF
$oPage->add('</div>'); $oPage->add('</div>');
$oPage->add("<input type=\"button\" id=\"btn_cancel_{$this->iId}\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_tree_{$this->iId}').dialog('close');\">&nbsp;&nbsp;"); $oPage->add("<input type=\"button\" id=\"btn_cancel_{$this->iId}\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_tree_{$this->iId}').dialog('close');\">&nbsp;&nbsp;");
$oPage->add("<input type=\"button\" id=\"btn_ok_{$this->iId}\" value=\"".Dict::S('UI:Button:Ok')."\" onClick=\"oACWidget_{$this->iId}.DoHKOk();\">"); $oPage->add("<input type=\"button\" id=\"btn_ok_{$this->iId}\" value=\"".Dict::S('UI:Button:Ok')."\" onClick=\"oACWidget_{$this->iId}.DoHKOk();\">");
$oPage->add('</div></div>'); $oPage->add('</div></div>');
$oPage->add_ready_script("\$('#tree_$this->iId ul').treeview();\n"); $oPage->add_ready_script("\$('#tree_$this->iId ul').treeview();\n");
$oPage->add_ready_script("\$('#dlg_tree_$this->iId').dialog({ width: 'auto', height: 'auto', autoOpen: true, modal: true, title: '$sDialogTitle', resizeStop: oACWidget_{$this->iId}.OnHKResize, close: oACWidget_{$this->iId}.OnHKClose });\n"); $oPage->add_ready_script("\$('#dlg_tree_$this->iId').dialog({ width: 'auto', height: 'auto', autoOpen: true, modal: true, title: '$sDialogTitle', resizeStop: oACWidget_{$this->iId}.OnHKResize, close: oACWidget_{$this->iId}.OnHKClose });\n");
@@ -632,23 +504,16 @@ EOF
*/ */
public function DoCreateObject($oPage) public function DoCreateObject($oPage)
{ {
try $oObj = MetaModel::NewObject($this->sTargetClass);
$aErrors = $oObj->UpdateObjectFromPostedForm($this->iId);
if (count($aErrors) == 0)
{ {
$oObj = MetaModel::NewObject($this->sTargetClass); $oObj->DBInsert();
$aErrors = $oObj->UpdateObjectFromPostedForm($this->iId); return array('name' => $oObj->GetName(), 'id' => $oObj->GetKey());
if (count($aErrors) == 0)
{
$oObj->DBInsert();
return array('name' => $oObj->GetName(), 'id' => $oObj->GetKey());
}
else
{
return array('error' => implode(' ', $aErrors), 'id' => 0);
}
} }
catch(Exception $e) else
{ {
return array('error' => $e->getMessage(), 'id' => 0); return array('name' => implode(' ', $aErrors), 'id' => 0);
} }
} }
@@ -666,7 +531,7 @@ EOF
$aTree[$iParentId][$oObj->GetKey()] = $oObj->GetName(); $aTree[$iParentId][$oObj->GetKey()] = $oObj->GetName();
$aNodes[$oObj->GetKey()] = $oObj; $aNodes[$oObj->GetKey()] = $oObj;
} }
$aParents = array_keys($aTree); $aParents = array_keys($aTree);
$aRoots = array(); $aRoots = array();
foreach($aParents as $id) foreach($aParents as $id)
@@ -681,7 +546,7 @@ EOF
$this->DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue); $this->DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue);
} }
} }
function DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue) function DumpNodes($oP, $iRootId, $aTree, $aNodes, $currValue)
{ {
$bSelect = true; $bSelect = true;
@@ -716,3 +581,4 @@ EOF
} }
} }
?>

View File

@@ -1,5 +1,5 @@
<?php <?php
// Copyright (C) 2010-2016 Combodo SARL // Copyright (C) 2010-2012 Combodo SARL
// //
// This file is part of iTop. // This file is part of iTop.
// //
@@ -20,15 +20,14 @@
* Class UIHTMLEditorWidget * Class UIHTMLEditorWidget
* UI wdiget for displaying and editing one-way encrypted passwords * UI wdiget for displaying and editing one-way encrypted passwords
* *
* @author Romain Quetiez * @author Phil Eddies
* @copyright Copyright (C) 2010-2016 Combodo SARL * @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
class UIHTMLEditorWidget class UIHTMLEditorWidget
{ {
protected $m_iId; protected $m_iId;
protected $m_oAttDef;
protected $m_sAttCode; protected $m_sAttCode;
protected $m_sNameSuffix; protected $m_sNameSuffix;
protected $m_sFieldPrefix; protected $m_sFieldPrefix;
@@ -37,11 +36,10 @@ class UIHTMLEditorWidget
protected $m_sValue; protected $m_sValue;
protected $m_sMandatory; protected $m_sMandatory;
public function __construct($iInputId, $oAttDef, $sNameSuffix, $sFieldPrefix, $sHelpText, $sValidationField, $sValue, $sMandatory) public function __construct($iInputId, $sAttCode, $sNameSuffix, $sFieldPrefix, $sHelpText, $sValidationField, $sValue, $sMandatory)
{ {
$this->m_iId = $iInputId; $this->m_iId = $iInputId;
$this->m_oAttDef = $oAttDef; $this->m_sAttCode = $sAttCode;
$this->m_sAttCode = $oAttDef->GetCode();
$this->m_sNameSuffix = $sNameSuffix; $this->m_sNameSuffix = $sNameSuffix;
$this->m_sHelpText = $sHelpText; $this->m_sHelpText = $sHelpText;
$this->m_sValidationField = $sValidationField; $this->m_sValidationField = $sValidationField;
@@ -64,30 +62,14 @@ class UIHTMLEditorWidget
$sHelpText = $this->m_sHelpText; $sHelpText = $this->m_sHelpText;
$sValidationField = $this->m_sValidationField; $sValidationField = $this->m_sValidationField;
$sHtmlValue = "<div class=\"field_input_zone field_input_html\"><textarea class=\"htmlEditor\" title=\"$sHelpText\" name=\"attr_{$this->m_sFieldPrefix}{$sCode}\" rows=\"10\" cols=\"10\" id=\"$iId\">$sValue</textarea></div>$sValidationField"; $sHtmlValue = "<table><tr><td><textarea class=\"htmlEditor\" title=\"$sHelpText\" name=\"attr_{$this->m_sFieldPrefix}{$sCode}\" rows=\"10\" cols=\"10\" id=\"$iId\">$sValue</textarea></td><td>$sValidationField</td></tr></table>";
// Replace the text area with CKEditor // Replace the text area with CKEditor
// To change the default settings of the editor, // To change the default settings of the editor,
// a) edit the file /js/ckeditor/config.js // a) edit the file /js/ckeditor/config.js
// b) or override some of the configuration settings, using the second parameter of ckeditor() // b) or override some of the configuration settings, using the second parameter of ckeditor()
$aConfig = array();
$sLanguage = strtolower(trim(UserRights::GetUserLanguage())); $sLanguage = strtolower(trim(UserRights::GetUserLanguage()));
$aConfig['language'] = $sLanguage; $oPage->add_ready_script("$('#$iId').ckeditor(function() { /* callback code */ }, { language : '$sLanguage' , contentsLanguage : '$sLanguage', extraPlugins: 'disabler' });"); // Transform $iId into a CKEdit
$aConfig['contentsLanguage'] = $sLanguage;
$aConfig['extraPlugins'] = 'disabler';
$sWidthSpec = addslashes(trim($this->m_oAttDef->GetWidth()));
if ($sWidthSpec != '')
{
$aConfig['width'] = $sWidthSpec;
}
$sHeightSpec = addslashes(trim($this->m_oAttDef->GetHeight()));
if ($sHeightSpec != '')
{
$aConfig['height'] = $sHeightSpec;
}
$sConfigJS = json_encode($aConfig);
$oPage->add_ready_script("$('#$iId').ckeditor(function() { /* callback code */ }, $sConfigJS);"); // Transform $iId into a CKEdit
// Please read... // Please read...
// ValidateCKEditField triggers a timer... calling itself indefinitely // ValidateCKEditField triggers a timer... calling itself indefinitely
@@ -98,26 +80,9 @@ class UIHTMLEditorWidget
// Could also be bound to 'instanceReady.ckeditor' // Could also be bound to 'instanceReady.ckeditor'
$oPage->add_ready_script("$('#$iId').bind('validate', function(evt, sFormId) { return ValidateCKEditField('$iId', '', {$this->m_sMandatory}, sFormId, '') } );\n"); $oPage->add_ready_script("$('#$iId').bind('validate', function(evt, sFormId) { return ValidateCKEditField('$iId', '', {$this->m_sMandatory}, sFormId, '') } );\n");
$oPage->add_ready_script( $oPage->add_ready_script("$('#$iId').bind('update', function() { BlockField('cke_$iId', $('#$iId').attr('disabled')); } );\n");
<<<EOF
$('#$iId').bind('update', function(evt){
BlockField('cke_$iId', $('#$iId').prop('disabled'));
//Delayed execution - ckeditor must be properly initialized before setting readonly
var retryCount = 0;
var oMe = $('#$iId');
var delayedSetReadOnly = function () {
if (oMe.data('ckeditorInstance').editable() == undefined && retryCount++ < 10) {
setTimeout(delayedSetReadOnly, retryCount * 100); //Wait a while longer each iteration
}
else
{
oMe.data('ckeditorInstance').setReadOnly(oMe.prop('disabled'));
}
};
setTimeout(delayedSetReadOnly, 50);
});
EOF
);
return $sHtmlValue; return $sHtmlValue;
} }
} }
?>

View File

@@ -1,5 +1,5 @@
<?php <?php
// Copyright (C) 2010-2017 Combodo SARL // Copyright (C) 2010-2012 Combodo SARL
// //
// This file is part of iTop. // This file is part of iTop.
// //
@@ -19,7 +19,7 @@
/** /**
* Class UILinksWidgetDirect * Class UILinksWidgetDirect
* *
* @copyright Copyright (C) 2010-2017 Combodo SARL * @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
@@ -30,14 +30,7 @@ class UILinksWidgetDirect
protected $sInputid; protected $sInputid;
protected $sNameSuffix; protected $sNameSuffix;
protected $sLinkedClass; protected $sLinkedClass;
/**
* UILinksWidgetDirect constructor.
* @param string $sClass
* @param string $sAttCode
* @param string $sInputId
* @param string $sNameSuffix
*/
public function __construct($sClass, $sAttCode, $sInputId, $sNameSuffix = '') public function __construct($sClass, $sAttCode, $sInputId, $sNameSuffix = '')
{ {
$this->sClass = $sClass; $this->sClass = $sClass;
@@ -78,15 +71,8 @@ class UILinksWidgetDirect
} }
} }
/** public function Display(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj)
* @param WebPage $oPage
* @param DBObjectSet|ormLinkSet $oValue
* @param array $aArgs
* @param string $sFormPrefix
* @param DBObject $oCurrentObj
*/
public function Display(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj)
{ {
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode); $oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
switch($oLinksetDef->GetEditMode()) switch($oLinksetDef->GetEditMode())
@@ -103,7 +89,7 @@ class UILinksWidgetDirect
$sDefault = "default[$sExtKeyToMe]=".$oCurrentObj->GetKey(); $sDefault = "default[$sExtKeyToMe]=".$oCurrentObj->GetKey();
$oAppContext = new ApplicationContext(); $oAppContext = new ApplicationContext();
$sParams = $oAppContext->GetForLink(); $sParams = $oAppContext->GetForLink();
$oPage->p("<a target=\"_blank\" href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=new&class=$sTargetClass&$sParams&{$sDefault}\">".Dict::Format('UI:ClickToCreateNew', Metamodel::GetName($sTargetClass))."</a>\n"); $oPage->p("<a target=\"_blank\" href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=new&class=$sTargetClass&$sParams{$sDefault}\">".Dict::Format('UI:ClickToCreateNew', Metamodel::GetName($sTargetClass))."</a>\n");
} }
$this->DisplayAsBlock($oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, false /* bDisplayMenu*/); $this->DisplayAsBlock($oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, false /* bDisplayMenu*/);
break; break;
@@ -129,16 +115,8 @@ class UILinksWidgetDirect
$this->DisplayAsBlock($oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, true /* bDisplayMenu*/); $this->DisplayAsBlock($oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, true /* bDisplayMenu*/);
} }
} }
/** protected function DisplayAsBlock(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $bDisplayMenu)
* @param WebPage $oPage
* @param DBObjectSet $oValue
* @param array $aArgs
* @param string $sFormPrefix
* @param DBObject $oCurrentObj
* @param bool $bDisplayMenu
*/
protected function DisplayAsBlock(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $bDisplayMenu)
{ {
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode); $oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
$sTargetClass = $oLinksetDef->GetLinkedClass(); $sTargetClass = $oLinksetDef->GetLinkedClass();
@@ -165,7 +143,6 @@ class UILinksWidgetDirect
'target_attr' => $oLinksetDef->GetExtKeyToMe(), 'target_attr' => $oLinksetDef->GetExtKeyToMe(),
'object_id' => $oCurrentObj ? $oCurrentObj->GetKey() : null, 'object_id' => $oCurrentObj ? $oCurrentObj->GetKey() : null,
'menu' => $bDisplayMenu, 'menu' => $bDisplayMenu,
'menu_actions_target' => '_blank',
'default' => $aDefaults, 'default' => $aDefaults,
'table_id' => $this->sClass.'_'.$this->sAttCode, 'table_id' => $this->sClass.'_'.$this->sAttCode,
); );
@@ -174,12 +151,46 @@ class UILinksWidgetDirect
$oBlock->Display($oPage, $this->sInputid, $aParams); $oBlock->Display($oPage, $this->sInputid, $aParams);
} }
} }
protected function DisplayEditInPlace(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $aButtons = array('create', 'delete'))
{
$aAttribs = $this->GetTableConfig();
$oValue->Rewind();
$oPage->add('<table class="listContainer" id="'.$this->sInputid.'"><tr><td>');
/** $aData = array();
* @param WebPage $oPage while($oLinkObj = $oValue->Fetch())
* @param string $sProposedRealClass {
*/ $aRow = array();
public function GetObjectCreationDlg(WebPage $oPage, $sProposedRealClass = '', $oSourceObj = null) $aRow['form::select'] = '<input type="checkbox" class="selectList'.$this->sInputid.'" value="'.$oLinkObj->GetKey().'"/>';
foreach($this->aZlist as $sLinkedAttCode)
{
$aRow[$sLinkedAttCode] = $oLinkObj->GetAsHTML($sLinkedAttCode);
}
$aData[] = $aRow;
}
$oPage->table($aAttribs, $aData);
$oPage->add('</td></tr></table>'); //listcontainer
$sInputName = $sFormPrefix.'attr_'.$this->sAttCode;
$aLabels = array(
'delete' => Dict::S('UI:Button:Delete'),
// 'modify' => 'Modify...' ,
'creation_title' => Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sLinkedClass)),
'create' => Dict::Format('UI:ClickToCreateNew', MetaModel::GetName($this->sLinkedClass)),
'remove' => Dict::S('UI:Button:Remove'),
'add' => Dict::Format('UI:AddAnExisting_Class', MetaModel::GetName($this->sLinkedClass)),
'selection_title' => Dict::Format('UI:SelectionOf_Class', MetaModel::GetName($this->sLinkedClass)),
);
$oContext = new ApplicationContext();
$sSubmitUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?'.$oContext->GetForLink();
$sJSONLabels = json_encode($aLabels);
$sJSONButtons = json_encode($aButtons);
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
$oPage->add_ready_script("$('#{$this->sInputid}').directlinks({class_name: '$this->sClass', att_code: '$this->sAttCode', input_name:'$sInputName', labels: $sJSONLabels, submit_to: '$sSubmitUrl', buttons: $sJSONButtons, oWizardHelper: $sWizHelper });");
}
public function GetObjectCreationDlg(WebPage $oPage, $sProposedRealClass = '')
{ {
// For security reasons: check that the "proposed" class is actually a subclass of the linked class // For security reasons: check that the "proposed" class is actually a subclass of the linked class
// and that the current user is allowed to create objects of this class // and that the current user is allowed to create objects of this class
@@ -204,17 +215,14 @@ class UILinksWidgetDirect
$aKeys = array_keys($aPossibleClasses); $aKeys = array_keys($aPossibleClasses);
$sRealClass = $aKeys[0]; $sRealClass = $aKeys[0];
} }
if ($sRealClass != '') if ($sRealClass != '')
{ {
$oPage->add("<h1>".MetaModel::GetClassIcon($sRealClass)."&nbsp;".Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($sRealClass))."</h1>\n"); $oPage->add("<h1>".MetaModel::GetClassIcon($sRealClass)."&nbsp;".Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($sRealClass))."</h1>\n");
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode); $oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
$sExtKeyToMe = $oLinksetDef->GetExtKeyToMe(); $sExtKeyToMe = $oLinksetDef->GetExtKeyToMe();
$aFieldFlags = array( $sExtKeyToMe => OPT_ATT_HIDDEN); $aFieldFlags = array( $sExtKeyToMe => OPT_ATT_HIDDEN);
$oObj = DBObject::MakeDefaultInstance($sRealClass); cmdbAbstractObject::DisplayCreationForm($oPage, $sRealClass, null, array(), array('formPrefix' => $this->sInputid, 'noRelations' => true, 'fieldsFlags' => $aFieldFlags));
$aPrefillParam = array('source_obj' => $oSourceObj);
$oObj->PrefillForm('creation_from_editinplace', $aPrefillParam);
cmdbAbstractObject::DisplayCreationForm($oPage, $sRealClass, $oObj, array(), array('formPrefix' => $this->sInputid, 'noRelations' => true, 'fieldsFlags' => $aFieldFlags));
} }
else else
{ {
@@ -231,91 +239,13 @@ class UILinksWidgetDirect
} }
$oPage->add('</div></div>'); $oPage->add('</div></div>');
} }
/** public function GetObjectsSelectionDlg($oPage, $oCurrentObj)
* @param WebPage $oPage
* @param DBObjectSet $oValue
* @param array $aArgs
* @param string $sFormPrefix
* @param DBObject $oCurrentObj
* @param array $aButtons
*/
protected function DisplayEditInPlace(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $aButtons = array('create', 'delete'))
{
$aAttribs = $this->GetTableConfig();
$oValue->Rewind();
$oPage->add('<table class="listContainer" id="'.$this->sInputid.'"><tr><td>');
$aData = array();
while($oLinkObj = $oValue->Fetch())
{
$aRow = array();
$aRow['form::select'] = '<input type="checkbox" class="selectList'.$this->sInputid.'" value="'.$oLinkObj->GetKey().'"/>';
foreach($this->aZlist as $sLinkedAttCode)
{
$aRow[$sLinkedAttCode] = $oLinkObj->GetAsHTML($sLinkedAttCode);
}
$aData[] = $aRow;
}
$oPage->table($aAttribs, $aData);
$oPage->add('</td></tr></table>'); //listcontainer
$sInputName = $sFormPrefix.'attr_'.$this->sAttCode;
$aLabels = array(
'delete' => Dict::S('UI:Button:Delete'),
// 'modify' => 'Modify...' ,
'creation_title' => Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sLinkedClass)),
'create' => Dict::Format('UI:ClickToCreateNew', MetaModel::GetName($this->sLinkedClass)),
'remove' => Dict::S('UI:Button:Remove'),
'add' => Dict::Format('UI:AddAnExisting_Class', MetaModel::GetName($this->sLinkedClass)),
'selection_title' => Dict::Format('UI:SelectionOf_Class', MetaModel::GetName($this->sLinkedClass)),
);
$oContext = new ApplicationContext();
$sSubmitUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?'.$oContext->GetForLink();
$sJSONLabels = json_encode($aLabels);
$sJSONButtons = json_encode($aButtons);
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
// Don't automatically launch the search if the table is huge
$bDoSearch = !utils::IsHighCardinality($this->sLinkedClass);
$sJSDoSearch = $bDoSearch ? 'true' : 'false';
$oPage->add_ready_script("$('#{$this->sInputid}').directlinks({class_name: '$this->sClass', att_code: '$this->sAttCode', input_name:'$sInputName', labels: $sJSONLabels, submit_to: '$sSubmitUrl', buttons: $sJSONButtons, oWizardHelper: $sWizHelper, do_search: $sJSDoSearch});");
}
/**
* @param WebPage $oPage
* @param DBObject $oCurrentObj
* @param $aAlreadyLinked
*
* @param array $aPrefillFormParam
*
* @throws \CoreException
* @throws \MissingQueryArgument
* @throws \OQLException
*/
public function GetObjectsSelectionDlg($oPage, $oCurrentObj, $aAlreadyLinked, $aPrefillFormParam = array())
{ {
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n"; $sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
$oHiddenFilter = new DBObjectSearch($this->sLinkedClass); $oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
if (($oCurrentObj != null) && MetaModel::IsSameFamilyBranch($this->sLinkedClass, $this->sClass)) $valuesDef = $oLinksetDef->GetValuesDef();
{
// Prevent linking to self if the linked object is of the same family
// and already present in the database
if (!$oCurrentObj->IsNew())
{
$oHiddenFilter->AddCondition('id', $oCurrentObj->GetKey(), '!=');
}
}
if (count($aAlreadyLinked) > 0)
{
$oHiddenFilter->AddCondition('id', $aAlreadyLinked, 'NOTIN');
}
$oHiddenCriteria = $oHiddenFilter->GetCriteria();
$aArgs = $oHiddenFilter->GetInternalParams();
$sHiddenCriteria = $oHiddenCriteria->Render($aArgs);
$oLinkSetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
$valuesDef = $oLinkSetDef->GetValuesDef();
if ($valuesDef === null) if ($valuesDef === null)
{ {
$oFilter = new DBObjectSearch($this->sLinkedClass); $oFilter = new DBObjectSearch($this->sLinkedClass);
@@ -328,28 +258,12 @@ class UILinksWidgetDirect
} }
$oFilter = DBObjectSearch::FromOQL($valuesDef->GetFilterExpression()); $oFilter = DBObjectSearch::FromOQL($valuesDef->GetFilterExpression());
} }
if ($oCurrentObj != null) if ($oCurrentObj != null)
{ {
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter); $this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
$aArgs = array_merge($oCurrentObj->ToArgs('this'), $oFilter->GetInternalParams());
$oFilter->SetInternalParams($aArgs);
$aPrefillFormParam['filter'] = $oFilter;
$oCurrentObj->PrefillForm('search', $aPrefillFormParam);
} }
$oBlock = new DisplayBlock($oFilter, 'search', false); $oBlock = new DisplayBlock($oFilter, 'search', false);
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->sInputid}", $sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->sInputid}", array('open' => true));
array(
'result_list_outer_selector' => "SearchResultsToAdd_{$this->sInputid}",
'table_id' => "add_{$this->sInputid}",
'table_inner_id' => "ResultsToAdd_{$this->sInputid}",
'selection_mode' => true,
'cssCount' => "#count_{$this->sInputid}",
'query_params' => $oFilter->GetInternalParams(),
'hidden_criteria' => $sHiddenCriteria,
)
);
$sHtml .= "<form id=\"ObjectsAddForm_{$this->sInputid}\">\n"; $sHtml .= "<form id=\"ObjectsAddForm_{$this->sInputid}\">\n";
$sHtml .= "<div id=\"SearchResultsToAdd_{$this->sInputid}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n"; $sHtml .= "<div id=\"SearchResultsToAdd_{$this->sInputid}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
$sHtml .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n"; $sHtml .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
@@ -359,28 +273,25 @@ class UILinksWidgetDirect
$sHtml .= "</div>\n"; $sHtml .= "</div>\n";
$sHtml .= "</form>\n"; $sHtml .= "</form>\n";
$oPage->add($sHtml); $oPage->add($sHtml);
//$oPage->add_ready_script("$('#SearchFormToAdd_{$this->sAttCode}{$this->sNameSuffix} form').bind('submit.uilinksWizard', oWidget{$this->sInputId}.SearchObjectsToAdd);");
//$oPage->add_ready_script("$('#SearchFormToAdd_{$this->sAttCode}{$this->sNameSuffix}').resize(oWidget{$this->siInputId}.UpdateSizes);");
} }
/** /**
* Search for objects to be linked to the current object (i.e "remote" objects) * Search for objects to be linked to the current object (i.e "remote" objects)
*
* @param WebPage $oP The page used for the output (usually an AjaxWebPage) * @param WebPage $oP The page used for the output (usually an AjaxWebPage)
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of $this->sLinkedClass * @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of $this->sLinkedClass
* @param array $aAlreadyLinked Array of indentifiers of objects which are already linke to the current object (or about to be linked) * @param array $aAlreadyLinked Array of indentifiers of objects which are already linke to the current object (or about to be linked)
* @param DBObject $oCurrentObj The object currently being edited... if known... * @param DBObject $oCurrentObj The object currently being edited... if known...
* @param array $aPrefillFormParam
*
* @throws \CoreException
* @throws \OQLException
*/ */
public function SearchObjectsToAdd(WebPage $oP, $sRemoteClass = '', $aAlreadyLinked = array(), $oCurrentObj = null, $aPrefillFormParam = array()) public function SearchObjectsToAdd(WebPage $oP, $sRemoteClass = '', $aAlreadyLinked = array(), $oCurrentObj = null)
{ {
if ($sRemoteClass == '') if ($sRemoteClass == '')
{ {
$sRemoteClass = $this->sLinkedClass; $sRemoteClass = $this->sLinkedClass;
} }
$oLinkSetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode); $oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
$valuesDef = $oLinkSetDef->GetValuesDef(); $valuesDef = $oLinksetDef->GetValuesDef();
if ($valuesDef === null) if ($valuesDef === null)
{ {
$oFilter = new DBObjectSearch($sRemoteClass); $oFilter = new DBObjectSearch($sRemoteClass);
@@ -397,34 +308,25 @@ class UILinksWidgetDirect
if (($oCurrentObj != null) && MetaModel::IsSameFamilyBranch($sRemoteClass, $this->sClass)) if (($oCurrentObj != null) && MetaModel::IsSameFamilyBranch($sRemoteClass, $this->sClass))
{ {
// Prevent linking to self if the linked object is of the same family // Prevent linking to self if the linked object is of the same family
// and already present in the database // and laready present in the database
if (!$oCurrentObj->IsNew()) if (!$oCurrentObj->IsNew())
{ {
$oFilter->AddCondition('id', $oCurrentObj->GetKey(), '!='); $oFilter->AddCondition('id', $oCurrentObj->GetKey(), '!=');
} }
} }
if ($oCurrentObj != null)
{
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
$aArgs = array_merge($oCurrentObj->ToArgs('this'), $oFilter->GetInternalParams());
$oFilter->SetInternalParams($aArgs);
$aPrefillFormParam['filter'] = $oFilter;
$oCurrentObj->PrefillForm('search', $aPrefillFormParam);
}
if (count($aAlreadyLinked) > 0) if (count($aAlreadyLinked) > 0)
{ {
$oFilter->AddCondition('id', $aAlreadyLinked, 'NOTIN'); $oFilter->AddCondition('id', $aAlreadyLinked, 'NOTIN');
} }
if ($oCurrentObj != null)
{
$aArgs = array_merge($oCurrentObj->ToArgs('this'), $oFilter->GetInternalParams());
$oFilter->SetInternalParams($aArgs);
}
$oBlock = new DisplayBlock($oFilter, 'list', false); $oBlock = new DisplayBlock($oFilter, 'list', false);
$oBlock->Display($oP, "ResultsToAdd_{$this->sInputid}", array('menu' => false, 'cssCount'=> '#count_'.$this->sInputid , 'selection_mode' => true, 'table_id' => 'add_'.$this->sInputid)); // Don't display the 'Actions' menu on the results $oBlock->Display($oP, "ResultsToAdd_{$this->sInputid}", array('menu' => false, 'cssCount'=> '#count_'.$this->sInputid , 'selection_mode' => true, 'table_id' => 'add_'.$this->sInputid)); // Don't display the 'Actions' menu on the results
} }
/**
* @param WebPage $oP
* @param $oFullSetFilter
*/
public function DoAddObjects(WebPage $oP, $oFullSetFilter) public function DoAddObjects(WebPage $oP, $oFullSetFilter)
{ {
$aLinkedObjectIds = utils::ReadMultipleSelection($oFullSetFilter); $aLinkedObjectIds = utils::ReadMultipleSelection($oFullSetFilter);
@@ -452,14 +354,7 @@ class UILinksWidgetDirect
} }
return $aAttribs; return $aAttribs;
} }
/**
* @param WebPage $oPage
* @param string $sRealClass
* @param array $aValues
* @param int $iTempId
* @return mixed
*/
public function GetRow($oPage, $sRealClass, $aValues, $iTempId) public function GetRow($oPage, $sRealClass, $aValues, $iTempId)
{ {
if ($sRealClass == '') if ($sRealClass == '')
@@ -471,13 +366,7 @@ class UILinksWidgetDirect
return $this->GetObjectRow($oPage, $oLinkObj, $iTempId); return $this->GetObjectRow($oPage, $oLinkObj, $iTempId);
} }
/**
* @param WebPage $oPage
* @param $oLinkObj
* @param int $iTempId
* @return mixed
*/
protected function GetObjectRow($oPage, $oLinkObj, $iTempId) protected function GetObjectRow($oPage, $oLinkObj, $iTempId)
{ {
$aAttribs = $this->GetTableConfig(); $aAttribs = $this->GetTableConfig();
@@ -493,7 +382,7 @@ class UILinksWidgetDirect
/** /**
* Initializes the default search parameters based on 1) a 'current' object and 2) the silos defined by the context * Initializes the default search parameters based on 1) a 'current' object and 2) the silos defined by the context
* @param DBObject $oSourceObj * @param DBObject $oSourceObj
* @param DBSearch|DBObjectSearch $oSearch * @param DBObjectSearch $oSearch
*/ */
protected function SetSearchDefaultFromContext($oSourceObj, &$oSearch) protected function SetSearchDefaultFromContext($oSourceObj, &$oSearch)
{ {
@@ -512,6 +401,7 @@ class UILinksWidgetDirect
if (MetaModel::IsValidAttCode($sSrcClass, $sAttCode)) if (MetaModel::IsValidAttCode($sSrcClass, $sAttCode))
{ {
$oAttDef = MetaModel::GetAttributeDef($sSrcClass, $sAttCode);
$defaultValue = $oSourceObj->Get($sAttCode); $defaultValue = $oSourceObj->Get($sAttCode);
// Find the attcode for the same 'context' parameter in the destination class // Find the attcode for the same 'context' parameter in the destination class

File diff suppressed because it is too large Load Diff

View File

@@ -58,32 +58,26 @@ class UIPasswordWidget
$sConfirmPasswordValue = $aPasswordValues ? $aPasswordValues['confirm'] : '*****'; $sConfirmPasswordValue = $aPasswordValues ? $aPasswordValues['confirm'] : '*****';
$sChangedValue = (($sPasswordValue != '*****') || ($sConfirmPasswordValue != '*****')) ? 1 : 0; $sChangedValue = (($sPasswordValue != '*****') || ($sConfirmPasswordValue != '*****')) ? 1 : 0;
$sHtmlValue = ''; $sHtmlValue = '';
$sHtmlValue .= '<div class="field_input_zone field_input_onewaypassword">'; $sHtmlValue = '<input type="password" maxlength="255" name="attr_'.$sCode.'[value]" id="'.$this->iId.'" value="'.htmlentities($sPasswordValue, ENT_QUOTES, 'UTF-8').'"/>&nbsp;<span class="form_validation" id="v_'.$this->iId.'"></span><br/>';
$sHtmlValue .= '<input type="password" maxlength="255" name="attr_'.$sCode.'[value]" id="'.$this->iId.'" value="'.htmlentities($sPasswordValue, ENT_QUOTES, 'UTF-8').'"/>'; $sHtmlValue .= '<input type="password" maxlength="255" id="'.$this->iId.'_confirm" value="'.htmlentities($sConfirmPasswordValue, ENT_QUOTES, 'UTF-8').'" name="attr_'.$sCode.'[confirm]"/> '.Dict::S('UI:PasswordConfirm').' <input id="'.$this->iId.'_reset" type="button" value="'.Dict::S('UI:Button:ResetPassword').'" onClick="ResetPwd(\''.$this->iId.'\');">';
$sHtmlValue .= '<input type="password" maxlength="255" id="'.$this->iId.'_confirm" value="'.htmlentities($sConfirmPasswordValue, ENT_QUOTES, 'UTF-8').'" name="attr_'.$sCode.'[confirm]"/>';
$sHtmlValue .= '<span>'.Dict::S('UI:PasswordConfirm').'</span>';
$sHtmlValue .= '<input id="'.$this->iId.'_reset" type="button" value="'.Dict::S('UI:Button:ResetPassword').'" onClick="ResetPwd(\''.$this->iId.'\');">';
$sHtmlValue .= '<input type="hidden" id="'.$this->iId.'_changed" name="attr_'.$sCode.'[changed]" value="'.$sChangedValue.'"/>'; $sHtmlValue .= '<input type="hidden" id="'.$this->iId.'_changed" name="attr_'.$sCode.'[changed]" value="'.$sChangedValue.'"/>';
$sHtmlValue .= '</div>';
$sHtmlValue .= '<span class="form_validation" id="v_'.$this->iId.'"></span><span class="field_status" id="fstatus_'.$this->iId.'"></span>';
$oPage->add_ready_script("$('#$this->iId').bind('keyup change', function(evt) { return PasswordFieldChanged('$this->iId') } );"); // Bind to a custom event: validate $oPage->add_ready_script("$('#$this->iId').bind('keyup change', function(evt) { return PasswordFieldChanged('$this->iId') } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#$this->iId').bind('keyup change validate', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate $oPage->add_ready_script("$('#$this->iId').bind('keyup change validate', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#{$this->iId}_confirm').bind('keyup change', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate $oPage->add_ready_script("$('#{$this->iId}_confirm').bind('keyup change', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#{$this->iId}').bind('update', function(evt, sFormId) $oPage->add_ready_script("$('#{$this->iId}').bind('update', function(evt, sFormId)
{ {
if ($(this).prop('disabled')) if ($(this).attr('disabled'))
{ {
$('#{$this->iId}_confirm').prop('disabled', true); $('#{$this->iId}_confirm').attr('disabled', 'disabled');
$('#{$this->iId}_changed').prop('disabled', true); $('#{$this->iId}_changed').attr('disabled', 'disabled');
$('#{$this->iId}_reset').prop('disabled', true); $('#{$this->iId}_reset').attr('disabled', 'disabled');
} }
else else
{ {
$('#{$this->iId}_confirm').prop('disabled', false); $('#{$this->iId}_confirm').removeAttr('disabled');
$('#{$this->iId}_changed').prop('disabled', false); $('#{$this->iId}_changed').removeAttr('disabled');
$('#{$this->iId}_reset').prop('disabled', false); $('#{$this->iId}_reset').removeAttr('disabled');
} }
} }
);"); // Bind to a custom event: update to handle enabling/disabling );"); // Bind to a custom event: update to handle enabling/disabling

View File

@@ -1,115 +0,0 @@
<?php
/**
*
* Copyright (C) 2010-2018 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*
*/
require_once(APPROOT.'/application/webpage.class.inc.php');
require_once(APPROOT.'/application/displayblock.class.inc.php');
class UISearchFormForeignKeys
{
public function __construct($sTargetClass, $iInputId = null)
{
$this->m_sRemoteClass = $sTargetClass;
$this->m_iInputId = $iInputId;
}
/**
* @param WebPage $oPage
*
* @param $sTitle
*
* @throws \Exception
*/
public function ShowModalSearchForeignKeys($oPage, $sTitle)
{
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
$oBlock = new DisplayBlock($oFilter, 'search', false);
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_iInputId}",
array(
'menu' => false,
'result_list_outer_selector' => "SearchResultsToAdd_{$this->m_iInputId}",
'table_id' => "add_{$this->m_iInputId}",
'table_inner_id' => "ResultsToAdd_{$this->m_iInputId}",
'selection_mode' => true,
'cssCount' => "#count_{$this->m_iInputId}",
'query_params' => $oFilter->GetInternalParams(),
));
$sHtml .= "<form id=\"ObjectsAddForm_{$this->m_iInputId}\">\n";
$sHtml .= "<div id=\"SearchResultsToAdd_{$this->m_iInputId}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
$sHtml .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
$sHtml .= "</div>\n";
$sHtml .= "<input type=\"hidden\" id=\"count_{$this->m_iInputId}\" value=\"0\"/>";
$sHtml .= "<input type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_{$this->m_iInputId}').dialog('close');\">&nbsp;&nbsp;<input id=\"btn_ok_{$this->m_iInputId}\" disabled=\"disabled\" type=\"button\" onclick=\"return oForeignKeysWidget{$this->m_iInputId}.DoAddObjects(this.id);\" value=\"".Dict::S('UI:Button:Add')."\">";
$sHtml .= "</div>\n";
$sHtml .= "</form>\n";
$oPage->add($sHtml);
$oPage->add_ready_script("$('#dlg_{$this->m_iInputId}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, resizeStop: oForeignKeysWidget{$this->m_iInputId}.UpdateSizes });");
$oPage->add_ready_script("$('#dlg_{$this->m_iInputId}').dialog('option', {title:'$sTitle'});");
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_iInputId} form').bind('submit.uilinksWizard', oForeignKeysWidget{$this->m_iInputId}.SearchObjectsToAdd);");
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_iInputId}').resize(oForeignKeysWidget{$this->m_iInputId}.UpdateSizes);");
}
public function GetFullListForeignKeysFromSelection($oPage, $oFullSetFilter)
{
try
{
$aLinkedObjects = utils::ReadMultipleSelectionWithFriendlyname($oFullSetFilter);
$oPage->add(json_encode($aLinkedObjects));
}
catch (CoreException $e)
{
http_response_code(500);
$oPage->add(json_encode(array('error' => $e->GetMessage())));
IssueLog::Error($e->getMessage()."\nDebug trace:\n".$e->getTraceAsString());
}
}
/**
* Search for objects to be linked to the current object (i.e "remote" objects)
*
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of m_sRemoteClass
*
* @throws \Exception
*/
public function ListResultsSearchForeignKeys(WebPage $oP, $sRemoteClass = '')
{
if ($sRemoteClass != '')
{
// assert(MetaModel::IsParentClass($this->m_sRemoteClass, $sRemoteClass));
$oFilter = new DBObjectSearch($sRemoteClass);
}
else
{
// No remote class specified use the one defined in the linkedset
$oFilter = new DBObjectSearch($this->m_sRemoteClass);
}
$oBlock = new DisplayBlock($oFilter, 'list', false);
$oBlock->Display($oP, "ResultsToAdd_{$this->m_iInputId}",
array('menu' => false, 'cssCount' => "#count_{$this->m_iInputId}", 'selection_mode' => true, 'table_id' => "add_{$this->m_iInputId}"));
}
}

View File

@@ -0,0 +1,423 @@
<?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/>
/**
* Class UILinksWizard
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class UILinksWizard
{
protected $m_sClass;
protected $m_sLinkageAttr;
protected $m_iObjectId;
protected $m_sLinkedClass;
protected $m_sLinkingAttCode;
protected $m_aEditableFields;
protected $m_aTableConfig;
public function __construct($sClass, $sLinkageAttr, $iObjectId, $sLinkedClass = '')
{
$this->m_sClass = $sClass;
$this->m_sLinkageAttr = $sLinkageAttr;
$this->m_iObjectId = $iObjectId;
$this->m_sLinkedClass = $sLinkedClass; // Will try to guess below, if it's empty
$this->m_sLinkingAttCode = ''; // Will be filled once we've found the attribute corresponding to the linked class
$this->m_aEditableFields = array();
$this->m_aTableConfig = array();
$this->m_aTableConfig['form::checkbox'] = array( 'label' => "<input class=\"select_all\" type=\"checkbox\" value=\"1\" onChange=\"var value = this.checked; $('.selection').each( function() { this.checked = value; } );OnSelectChange();\">", 'description' => Dict::S('UI:SelectAllToggle+'));
foreach(MetaModel::GetAttributesList($this->m_sClass) as $sAttCode)
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
if ($oAttDef->IsExternalKey() && ($sAttCode != $this->m_sLinkageAttr))
{
if (empty($this->m_sLinkedClass))
{
// This is a class of objects we can manage !
// Since nothing was specify, any class will do !
$this->m_sLinkedClass = $oAttDef->GetTargetClass();
$this->m_sLinkingAttCode = $sAttCode;
}
else if ($this->m_sLinkedClass == $oAttDef->GetTargetClass())
{
// This is the class of objects we want to manage !
$this->m_sLinkingAttCode = $sAttCode;
}
}
else if ( (!$oAttDef->IsExternalKey()) && (!$oAttDef->IsExternalField()))
{
$this->m_aEditableFields[] = $sAttCode;
$this->m_aTableConfig[$sAttCode] = array( 'label' => $oAttDef->GetLabel(), 'description' => $oAttDef->GetDescription());
}
}
if (empty($this->m_sLinkedClass))
{
throw( new Exception(Dict::Format('UI:Error:IncorrectLinkDefinition_LinkedClass_Class', $sLinkedClass, $sClass)));
}
foreach(MetaModel::GetZListItems($this->m_sLinkedClass, 'list') as $sFieldCode)
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
$this->m_aTableConfig['static::'.$sFieldCode] = array( 'label' => $oAttDef->GetLabel(), 'description' => $oAttDef->GetDescription());
}
}
public function Display(WebPage $oP, $aExtraParams = array())
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $this->m_sLinkageAttr);
$sTargetClass = $oAttDef->GetTargetClass();
$oTargetObj = MetaModel::GetObject($sTargetClass, $this->m_iObjectId);
$oP->set_title("iTop - ".MetaModel::GetName($this->m_sLinkedClass)." objects linked with ".MetaModel::GetName(get_class($oTargetObj)).": ".$oTargetObj->GetRawName());
$oP->add("<div class=\"wizContainer\">\n");
$oP->add("<form method=\"post\">\n");
$oP->add("<div class=\"page_header\">\n");
$oP->add("<input type=\"hidden\" id=\"linksToRemove\" name=\"linksToRemove\" value=\"\">\n");
$oP->add("<input type=\"hidden\" name=\"operation\" value=\"do_modify_links\">\n");
$oP->add("<input type=\"hidden\" name=\"class\" value=\"{$this->m_sClass}\">\n");
$oP->add("<input type=\"hidden\" name=\"linkage\" value=\"{$this->m_sLinkageAttr}\">\n");
$oP->add("<input type=\"hidden\" name=\"object_id\" value=\"{$this->m_iObjectId}\">\n");
$oP->add("<input type=\"hidden\" name=\"linking_attcode\" value=\"{$this->m_sLinkingAttCode}\">\n");
$oP->add("<h1>".Dict::Format('UI:ManageObjectsOf_Class_LinkedWith_Class_Instance', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName(get_class($oTargetObj)), "<span class=\"hilite\">".$oTargetObj->GetHyperlink()."</span>")."</h1>\n");
$oP->add("</div>\n");
$oP->add_script(
<<<EOF
function OnSelectChange()
{
var nbChecked = $('.selection:checked').length;
if (nbChecked > 0)
{
$('#btnRemove').removeAttr('disabled');
}
else
{
$('#btnRemove').attr('disabled','disabled');
}
}
function RemoveSelected()
{
$('.selection:checked').each(
function()
{
$('#linksToRemove').val($('#linksToRemove').val() + ' ' + this.value);
$('#row_'+this.value).remove();
}
);
// Disable the button since all the selected items have been removed
$('#btnRemove').attr('disabled','disabled');
// Re-run the zebra plugin to properly highlight the remaining lines
$('.listResults').trigger('update');
}
function AddObjects()
{
// TO DO: compute the list of objects already linked with the current Object
$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', { 'operation': 'addObjects',
'class': '{$this->m_sClass}',
'linkageAttr': '{$this->m_sLinkageAttr}',
'linkedClass': '{$this->m_sLinkedClass}',
'objectId': '{$this->m_iObjectId}'
},
function(data)
{
$('#ModalDlg').html(data);
dlgWidth = $(document).width() - 100;
$('#ModalDlg').css('width', dlgWidth);
$('#ModalDlg').css('left', 50);
$('#ModalDlg').css('top', 50);
$('#ModalDlg').dialog( 'open' );
},
'html'
);
}
function SearchObjectsToAdd(currentFormId)
{
var theMap = { 'class': '{$this->m_sClass}',
'linkageAttr': '{$this->m_sLinkageAttr}',
'linkedClass': '{$this->m_sLinkedClass}',
'objectId': '{$this->m_iObjectId}'
}
if ($('#'+currentFormId+' :input[name=class]').val() != undefined)
{
theMap.linkedClass = $('#'+currentFormId+' :input[name=class]').val();
}
// Gather the parameters from the search form
$('#'+currentFormId+' :input').each(
function(i)
{
if (this.name != '')
{
theMap[this.name] = this.value;
}
}
);
theMap['operation'] = 'searchObjectsToAdd';
// Run the query and display the results
$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', theMap,
function(data)
{
$('#SearchResultsToAdd').html(data);
$('#SearchResultsToAdd .listResults').tablesorter( { headers: {0: false}}, widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
},
'html'
);
return false;
}
function DoAddObjects(currentFormId)
{
var theMap = { 'class': '{$this->m_sClass}',
'linkageAttr': '{$this->m_sLinkageAttr}',
'linkedClass': '{$this->m_sLinkedClass}',
'objectId': '{$this->m_iObjectId}'
}
// Gather the parameters from the search form
$('#'+currentFormId+' :input').each(
function(i)
{
if ( (this.name != '') && ((this.type != 'checkbox') || (this.checked)) )
{
//console.log(this.type);
arrayExpr = /\[\]$/;
if (arrayExpr.test(this.name))
{
// Array
if (theMap[this.name] == undefined)
{
theMap[this.name] = new Array();
}
theMap[this.name].push(this.value);
}
else
{
theMap[this.name] = this.value;
}
}
}
);
theMap['operation'] = 'doAddObjects';
// Run the query and display the results
$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', theMap,
function(data)
{
//console.log('Data: ' + data);
if (data != '')
{
$('#empty_row').remove();
}
$('.listResults tbody').append(data);
$('.listResults').trigger('update');
$('.listResults').tablesorter( { headers: {0: false}}, widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
},
'html'
);
$('#ModalDlg').dialog('close');
return false;
}
function InitForm()
{
// make sure that the form is clean
$('.selection').each( function() { this.checked = false; });
$('#btnRemove').attr('disabled','disabled');
$('#linksToRemove').val('');
}
function SubmitHook()
{
var the_form = this;
SearchObjectsToAdd(the_form.id);
return false;
}
EOF
);
$oP->add_ready_script("InitForm();");
$oFilter = new DBObjectSearch($this->m_sClass);
$oFilter->AddCondition($this->m_sLinkageAttr, $this->m_iObjectId, '=');
$oSet = new DBObjectSet($oFilter);
$aForm = array();
while($oCurrentLink = $oSet->Fetch())
{
$aRow = array();
$key = $oCurrentLink->GetKey();
$oLinkedObj = MetaModel::GetObject($this->m_sLinkedClass, $oCurrentLink->Get($this->m_sLinkingAttCode));
$aForm[$key] = $this->GetFormRow($oP, $oLinkedObj, $oCurrentLink);
}
//var_dump($aTableLabels);
//var_dump($aForm);
$this->DisplayFormTable($oP, $this->m_aTableConfig, $aForm);
$oP->add("<span style=\"float:left;\">&nbsp;&nbsp;&nbsp;<img src=\"../images/tv-item-last.gif\">&nbsp;&nbsp;<input id=\"btnRemove\" type=\"button\" value=\"".Dict::S('UI:RemoveLinkedObjectsOf_Class')."\" onClick=\"RemoveSelected();\" >");
$oP->add("&nbsp;&nbsp;&nbsp;<input id=\"btnAdd\" type=\"button\" value=\"".Dict::Format('UI:AddLinkedObjectsOf_Class', MetaModel::GetName($this->m_sLinkedClass))."\" onClick=\"AddObjects();\"></span>\n");
$oP->add("<span style=\"float:right;\"><input id=\"btnCancel\" type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"BackToDetails('".$sTargetClass."', ".$this->m_iObjectId.");\">");
$oP->add("&nbsp;&nbsp;&nbsp;<input id=\"btnOk\" type=\"submit\" value=\"".Dict::S('UI:Button:Ok')."\"></span>\n");
$oP->add("<span style=\"clear:both;\"><p>&nbsp;</p></span>\n");
$oP->add("</div>\n");
$oP->add("</form>\n");
if (isset($aExtraParams['StartWithAdd']) && ($aExtraParams['StartWithAdd']))
{
$oP->add_ready_script("AddObjects();");
}
}
protected function GetFormRow($oP, $oLinkedObj, $currentLink = null )
{
$aRow = array();
if(is_object($currentLink))
{
$key = $currentLink->GetKey();
$sNameSuffix = "[$key]"; // To make a tabular form
$aRow['form::checkbox'] = "<input class=\"selection\" type=\"checkbox\" onChange=\"OnSelectChange();\" value=\"$key\">";
$aRow['form::checkbox'] .= "<input type=\"hidden\" name=\"linkId[$key]\" value=\"$key\">";
foreach($this->m_aEditableFields as $sFieldCode)
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sFieldCode);
$aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sClass, $sFieldCode, $oAttDef, $currentLink->Get($sFieldCode), '' /* DisplayValue */, $key, $sNameSuffix);
}
}
else
{
// form for creating a new record
$sNameSuffix = "[$currentLink]"; // To make a tabular form
$aRow['form::checkbox'] = "<input class=\"selection\" type=\"checkbox\" onChange=\"OnSelectChange();\" value=\"$currentLink\">";
$aRow['form::checkbox'] .= "<input type=\"hidden\" name=\"linkId[$currentLink]\" value=\"$currentLink\">";
foreach($this->m_aEditableFields as $sFieldCode)
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sFieldCode);
$aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sClass, $sFieldCode, $oAttDef, '' /* TO DO/ call GetDefaultValue($oObject->ToArgs()) */, '' /* DisplayValue */, '' /* id */, $sNameSuffix);
}
}
foreach(MetaModel::GetZListItems($this->m_sLinkedClass, 'list') as $sFieldCode)
{
$aRow['static::'.$sFieldCode] = $oLinkedObj->GetAsHTML($sFieldCode);
}
return $aRow;
}
protected function DisplayFormTable(WebPage $oP, $aConfig, $aData)
{
$oP->add("<table class=\"listResults\">\n");
// Header
$oP->add("<thead>\n");
$oP->add("<tr>\n");
foreach($aConfig as $sName=>$aDef)
{
$oP->add("<th title=\"".$aDef['description']."\">".$aDef['label']."</th>\n");
}
$oP->add("</tr>\n");
$oP->add("</thead>\n");
// Content
$oP->add("</tbody>\n");
if (count($aData) == 0)
{
$oP->add("<tr id=\"empty_row\"><td colspan=\"".count($aConfig)."\" style=\"text-align:center;\">".Dict::S('UI:Message:EmptyList:UseAdd')."</td></td>");
}
else
{
foreach($aData as $iRowId => $aRow)
{
$this->DisplayFormRow($oP, $aConfig, $aRow, $iRowId);
}
}
$oP->add("</tbody>\n");
// Footer
$oP->add("</table>\n");
}
protected function DisplayFormRow(WebPage $oP, $aConfig, $aRow, $iRowId)
{
$oP->add("<tr id=\"row_$iRowId\">\n");
foreach($aConfig as $sName=>$void)
{
$oP->add("<td>".$aRow[$sName]."</td>\n");
}
$oP->add("</tr>\n");
}
public function DisplayAddForm(WebPage $oP)
{
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $this->m_sLinkageAttr);
$sTargetClass = $oAttDef->GetTargetClass();
$oTargetObj = MetaModel::GetObject($sTargetClass, $this->m_iObjectId);
$oP->add("<div class=\"wizContainer\">\n");
//$oP->add("<div class=\"page_header\">\n");
//$oP->add("<h1>".Dict::Format('UI:AddObjectsOf_Class_LinkedWith_Class_Instance', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName(get_class($oTargetObj)), "<span class=\"hilite\">".$oTargetObj->GetHyperlink()."</span>")."</h1>\n");
//$oP->add("</div>\n");
$oFilter = new DBObjectSearch($this->m_sLinkedClass);
$oSet = new CMDBObjectSet($oFilter);
$oBlock = new DisplayBlock($oFilter, 'search', false);
$oBlock->Display($oP, 'SearchFormToAdd', array('open' => true));
$oP->Add("<form id=\"ObjectsAddForm\" OnSubmit=\"return DoAddObjects(this.id);\">\n");
$oP->Add("<div id=\"SearchResultsToAdd\">\n");
$oP->Add("<div style=\"height: 100px; background: #fff;border-color:#F6F6F1 #E6E6E1 #E6E6E1 #F6F6F1; border-style:solid; border-width:3px; text-align: center; vertical-align: center;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n");
$oP->Add("</div>\n");
$oP->add("<input type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#ModalDlg').dialog('close');\">&nbsp;&nbsp;<input type=\"submit\" value=\"".Dict::S('UI:Button:Add')."\">");
$oP->Add("</div>\n");
$oP->Add("</form>\n");
$oP->add_ready_script("$('#ModalDlg').dialog('option', {title:'".Dict::Format('UI:AddObjectsOf_Class_LinkedWith_Class_Instance', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName(get_class($oTargetObj)), "<span class=\"hilite\">".$oTargetObj->GetHyperlink()."</span>")."'});");
$oP->add_ready_script("$('div#SearchFormToAdd form').bind('submit.uilinksWizard', SubmitHook);");
}
public function SearchObjectsToAdd(WebPage $oP)
{
//$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $this->m_sLinkageAttr);
$oFilter = new DBObjectSearch($this->m_sLinkedClass);
$oSet = new CMDBObjectSet($oFilter);
$oBlock = new DisplayBlock($oFilter, 'list', false);
$oBlock->Display($oP, 'ResultsToAdd', array('menu' => false, 'selection_mode' => true)); // Don't display the 'Actions' menu on the results
}
public function DoAddObjects(WebPage $oP, $aLinkedObjectIds = array())
{
//$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $this->m_sLinkageAttr);
//$sTargetClass = $oAttDef->GetTargetClass();
//$oP->Add("<!-- nb of objects to add: ".count($aLinkedObjectIds)." -->\n"); // Just to make sure it's not empty
$aTable = array();
foreach($aLinkedObjectIds as $iObjectId)
{
$oLinkedObj = MetaModel::GetObject($this->m_sLinkedClass, $iObjectId);
if (is_object($oLinkedObj))
{
$aRow = $this->GetFormRow($oP, $oLinkedObj, -$iObjectId ); // Not yet created link get negative Ids
$this->DisplayFormRow($oP, $this->m_aTableConfig, $aRow, -$iObjectId);
}
else
{
echo Dict::Format('UI:Error:Object_Class_Id_NotFound', $this->m_sLinkedClass, $iObjectId);
}
}
//var_dump($aTable);
//$oP->Add("<!-- end of added list -->\n"); // Just to make sure it's not empty
}
}
?>

View File

@@ -1,331 +1,331 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010-2012 Combodo SARL
// //
// This file is part of iTop. // 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 // 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 // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// iTop is distributed in the hope that it will be useful, // iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details. // GNU Affero General Public License for more details.
// //
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with iTop. If not, see <http://www.gnu.org/licenses/>
/** /**
* Class UIWizard * Class UIWizard
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
class UIWizard class UIWizard
{ {
protected $m_oPage; protected $m_oPage;
protected $m_sClass; protected $m_sClass;
protected $m_sTargetState; protected $m_sTargetState;
protected $m_aWizardSteps; protected $m_aWizardSteps;
public function __construct($oPage, $sClass, $sTargetState = '') public function __construct($oPage, $sClass, $sTargetState = '')
{ {
$this->m_oPage = $oPage; $this->m_oPage = $oPage;
$this->m_sClass = $sClass; $this->m_sClass = $sClass;
if (empty($sTargetState)) if (empty($sTargetState))
{ {
$sTargetState = MetaModel::GetDefaultState($sClass); $sTargetState = MetaModel::GetDefaultState($sClass);
} }
$this->m_sTargetState = $sTargetState; $this->m_sTargetState = $sTargetState;
$this->m_aWizardSteps = $this->ComputeWizardStructure(); $this->m_aWizardSteps = $this->ComputeWizardStructure();
} }
public function GetObjectClass() { return $this->m_sClass; } public function GetObjectClass() { return $this->m_sClass; }
public function GetTargetState() { return $this->m_sTargetState; } public function GetTargetState() { return $this->m_sTargetState; }
public function GetWizardStructure() { return $this->m_aWizardSteps; } public function GetWizardStructure() { return $this->m_aWizardSteps; }
/** /**
* Displays one step of the wizard * Displays one step of the wizard
*/ */
public function DisplayWizardStep($aStep, $iStepIndex, &$iMaxInputId, &$aFieldsMap, $bFinishEnabled = false, $aArgs = array()) public function DisplayWizardStep($aStep, $iStepIndex, &$iMaxInputId, &$aFieldsMap, $bFinishEnabled = false, $aArgs = array())
{ {
if ($iStepIndex == 1) // one big form that contains everything, to make sure that the uploaded files are posted too if ($iStepIndex == 1) // one big form that contains everything, to make sure that the uploaded files are posted too
{ {
$this->m_oPage->add("<form method=\"post\" enctype=\"multipart/form-data\" action=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php\">\n"); $this->m_oPage->add("<form method=\"post\" enctype=\"multipart/form-data\" action=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php\">\n");
} }
$this->m_oPage->add("<div class=\"wizContainer\" id=\"wizStep$iStepIndex\" style=\"display:none;\">\n"); $this->m_oPage->add("<div class=\"wizContainer\" id=\"wizStep$iStepIndex\" style=\"display:none;\">\n");
$this->m_oPage->add("<a name=\"step$iStepIndex\" />\n"); $this->m_oPage->add("<a name=\"step$iStepIndex\" />\n");
$aStates = MetaModel::EnumStates($this->m_sClass); $aStates = MetaModel::EnumStates($this->m_sClass);
$aDetails = array(); $aDetails = array();
$sJSHandlerCode = ''; // Javascript code to be executed each time this step of the wizard is entered $sJSHandlerCode = ''; // Javascript code to be executed each time this step of the wizard is entered
foreach($aStep as $sAttCode) foreach($aStep as $sAttCode)
{ {
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode); $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
if ($oAttDef->IsWritable()) if ($oAttDef->IsWritable())
{ {
$sAttLabel = $oAttDef->GetLabel(); $sAttLabel = $oAttDef->GetLabel();
$iOptions = isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode]) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0; $iOptions = isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode]) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0;
$aPrerequisites = $oAttDef->GetPrerequisiteAttributes(); $aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
if ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) if ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT))
{ {
$aFields[$sAttCode] = array(); $aFields[$sAttCode] = array();
foreach($aPrerequisites as $sCode) foreach($aPrerequisites as $sCode)
{ {
$aFields[$sAttCode][$sCode] = ''; $aFields[$sAttCode][$sCode] = '';
} }
} }
if (count($aPrerequisites) > 0) if (count($aPrerequisites) > 0)
{ {
$aOptions[] = 'Prerequisites: '.implode(', ', $aPrerequisites); $aOptions[] = 'Prerequisites: '.implode(', ', $aPrerequisites);
} }
$sFieldFlag = (($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE)) || (!$oAttDef->IsNullAllowed()) )? ' <span class="hilite">*</span>' : ''; $sFieldFlag = (($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE)) || (!$oAttDef->IsNullAllowed()) )? ' <span class="hilite">*</span>' : '';
$oDefaultValuesSet = $oAttDef->GetDefaultValue(/* $oObject->ToArgs() */); // @@@ TO DO: get the object's current value if the object exists $oDefaultValuesSet = $oAttDef->GetDefaultValue(/* $oObject->ToArgs() */); // @@@ TO DO: get the object's current value if the object exists
$sHTMLValue = cmdbAbstractObject::GetFormElementForField($this->m_oPage, $this->m_sClass, $sAttCode, $oAttDef, $oDefaultValuesSet, '', "att_$iMaxInputId", '', $iOptions, $aArgs); $sHTMLValue = cmdbAbstractObject::GetFormElementForField($this->m_oPage, $this->m_sClass, $sAttCode, $oAttDef, $oDefaultValuesSet, '', "att_$iMaxInputId", '', $iOptions, $aArgs);
$aFieldsMap["att_$iMaxInputId"] = $sAttCode; $aFieldsMap["att_$iMaxInputId"] = $sAttCode;
$aDetails[] = array('label' => '<span title="'.$oAttDef->GetDescription().'">'.$oAttDef->GetLabel().$sFieldFlag.'</span>', 'value' => "<span id=\"field_att_$iMaxInputId\">$sHTMLValue</span>"); $aDetails[] = array('label' => '<span title="'.$oAttDef->GetDescription().'">'.$oAttDef->GetLabel().$sFieldFlag.'</span>', 'value' => "<span id=\"field_att_$iMaxInputId\">$sHTMLValue</span>");
if ($oAttDef->GetValuesDef() != null) if ($oAttDef->GetValuesDef() != null)
{ {
$sJSHandlerCode .= "\toWizardHelper.RequestAllowedValues('$sAttCode');\n"; $sJSHandlerCode .= "\toWizardHelper.RequestAllowedValues('$sAttCode');\n";
} }
if ($oAttDef->GetDefaultValue() != null) if ($oAttDef->GetDefaultValue() != null)
{ {
$sJSHandlerCode .= "\toWizardHelper.RequestDefaultValue('$sAttCode');\n"; $sJSHandlerCode .= "\toWizardHelper.RequestDefaultValue('$sAttCode');\n";
} }
if ($oAttDef->IsLinkSet()) if ($oAttDef->IsLinkSet())
{ {
$sJSHandlerCode .= "\toLinkWidgetatt_$iMaxInputId.Init();"; $sJSHandlerCode .= "\toLinkWidgetatt_$iMaxInputId.Init();";
} }
$iMaxInputId++; $iMaxInputId++;
} }
} }
//$aDetails[] = array('label' => '', 'value' => '<input type="button" value="Next &gt;&gt;">'); //$aDetails[] = array('label' => '', 'value' => '<input type="button" value="Next &gt;&gt;">');
$this->m_oPage->details($aDetails); $this->m_oPage->details($aDetails);
$sBackButtonDisabled = ($iStepIndex <= 1) ? 'disabled' : ''; $sBackButtonDisabled = ($iStepIndex <= 1) ? 'disabled' : '';
$sDisabled = $bFinishEnabled ? '' : 'disabled'; $sDisabled = $bFinishEnabled ? '' : 'disabled';
$nbSteps = count($this->m_aWizardSteps['mandatory']) + count($this->m_aWizardSteps['optional']); $nbSteps = count($this->m_aWizardSteps['mandatory']) + count($this->m_aWizardSteps['optional']);
$this->m_oPage->add("<div style=\"text-align:center\"> $this->m_oPage->add("<div style=\"text-align:center\">
<input type=\"button\" value=\"".Dict::S('UI:Button:Back')."\" $sBackButtonDisabled onClick=\"GoToStep($iStepIndex, $iStepIndex - 1)\" /> <input type=\"button\" value=\"".Dict::S('UI:Button:Back')."\" $sBackButtonDisabled onClick=\"GoToStep($iStepIndex, $iStepIndex - 1)\" />
<input type=\"button\" value=\"".Dict::S('UI:Button:Next')."\" onClick=\"GoToStep($iStepIndex, 1+$iStepIndex)\" /> <input type=\"button\" value=\"".Dict::S('UI:Button:Next')."\" onClick=\"GoToStep($iStepIndex, 1+$iStepIndex)\" />
<input type=\"button\" value=\"".Dict::S('UI:Button:Finish')."\" $sDisabled onClick=\"GoToStep($iStepIndex, 1+$nbSteps)\" /> <input type=\"button\" value=\"".Dict::S('UI:Button:Finish')."\" $sDisabled onClick=\"GoToStep($iStepIndex, 1+$nbSteps)\" />
</div>\n"); </div>\n");
$this->m_oPage->add_script(" $this->m_oPage->add_script("
function OnEnterStep{$iStepIndex}() function OnEnterStep{$iStepIndex}()
{ {
oWizardHelper.ResetQuery(); oWizardHelper.ResetQuery();
oWizardHelper.UpdateWizard(); oWizardHelper.UpdateWizard();
$sJSHandlerCode $sJSHandlerCode
oWizardHelper.AjaxQueryServer(); oWizardHelper.AjaxQueryServer();
} }
"); ");
$this->m_oPage->add("</div>\n\n"); $this->m_oPage->add("</div>\n\n");
} }
/** /**
* Display the final step of the wizard: a confirmation screen * Display the final step of the wizard: a confirmation screen
*/ */
public function DisplayFinalStep($iStepIndex, $aFieldsMap) public function DisplayFinalStep($iStepIndex, $aFieldsMap)
{ {
$oAppContext = new ApplicationContext(); $oAppContext = new ApplicationContext();
$this->m_oPage->add("<div class=\"wizContainer\" id=\"wizStep$iStepIndex\" style=\"display:none;\">\n"); $this->m_oPage->add("<div class=\"wizContainer\" id=\"wizStep$iStepIndex\" style=\"display:none;\">\n");
$this->m_oPage->add("<a name=\"step$iStepIndex\" />\n"); $this->m_oPage->add("<a name=\"step$iStepIndex\" />\n");
$this->m_oPage->P(Dict::S('UI:Wizard:FinalStepTitle')); $this->m_oPage->P(Dict::S('UI:Wizard:FinalStepTitle'));
$this->m_oPage->add("<input type=\"hidden\" name=\"operation\" value=\"wizard_apply_new\" />\n"); $this->m_oPage->add("<input type=\"hidden\" name=\"operation\" value=\"wizard_apply_new\" />\n");
$this->m_oPage->add("<input type=\"hidden\" name=\"transaction_id\" value=\"".utils::GetNewTransactionId()."\" />\n"); $this->m_oPage->add("<input type=\"hidden\" name=\"transaction_id\" value=\"".utils::GetNewTransactionId()."\" />\n");
$this->m_oPage->add("<input type=\"hidden\" id=\"wizard_json_obj\" name=\"json_obj\" value=\"\" />\n"); $this->m_oPage->add("<input type=\"hidden\" id=\"wizard_json_obj\" name=\"json_obj\" value=\"\" />\n");
$sScript = "function OnEnterStep$iStepIndex() {\n"; $sScript = "function OnEnterStep$iStepIndex() {\n";
foreach($aFieldsMap as $iInputId => $sAttCode) foreach($aFieldsMap as $iInputId => $sAttCode)
{ {
$sScript .= "\toWizardHelper.UpdateCurrentValue('$sAttCode');\n"; $sScript .= "\toWizardHelper.UpdateCurrentValue('$sAttCode');\n";
} }
$sScript .= "\toWizardHelper.Preview('object_preview');\n"; $sScript .= "\toWizardHelper.Preview('object_preview');\n";
$sScript .= "\t$('#wizard_json_obj').val(oWizardHelper.ToJSON());\n"; $sScript .= "\t$('#wizard_json_obj').val(oWizardHelper.ToJSON());\n";
$sScript .= "}\n"; $sScript .= "}\n";
$this->m_oPage->add_script($sScript); $this->m_oPage->add_script($sScript);
$this->m_oPage->add("<div id=\"object_preview\">\n"); $this->m_oPage->add("<div id=\"object_preview\">\n");
$this->m_oPage->add("</div>\n"); $this->m_oPage->add("</div>\n");
$this->m_oPage->add($oAppContext->GetForForm()); $this->m_oPage->add($oAppContext->GetForForm());
$this->m_oPage->add("<input type=\"button\" value=\"".Dict::S('UI:Button:Back')."\" onClick=\"GoToStep($iStepIndex, $iStepIndex - 1)\" />"); $this->m_oPage->add("<input type=\"button\" value=\"".Dict::S('UI:Button:Back')."\" onClick=\"GoToStep($iStepIndex, $iStepIndex - 1)\" />");
$this->m_oPage->add("<input type=\"submit\" value=\"Create ".MetaModel::GetName($this->m_sClass)."\" />\n"); $this->m_oPage->add("<input type=\"submit\" value=\"Create ".MetaModel::GetName($this->m_sClass)."\" />\n");
$this->m_oPage->add("</div>\n"); $this->m_oPage->add("</div>\n");
$this->m_oPage->add("</form>\n"); $this->m_oPage->add("</form>\n");
} }
/** /**
* Compute the order of the fields & pages in the wizard * Compute the order of the fields & pages in the wizard
* @param $oPage iTopWebPage The current page (used to display error messages) * @param $oPage iTopWebPage The current page (used to display error messages)
* @param $sClass string Name of the class * @param $sClass string Name of the class
* @param $sStateCode string Code of the target state of the object * @param $sStateCode string Code of the target state of the object
* @return hash Two dimensional array: each element represents the list of fields for a given page * @return hash Two dimensional array: each element represents the list of fields for a given page
*/ */
protected function ComputeWizardStructure() protected function ComputeWizardStructure()
{ {
$aWizardSteps = array( 'mandatory' => array(), 'optional' => array()); $aWizardSteps = array( 'mandatory' => array(), 'optional' => array());
$aFieldsDone = array(); // Store all the fields that are already covered by a previous step of the wizard $aFieldsDone = array(); // Store all the fields that are already covered by a previous step of the wizard
$aStates = MetaModel::EnumStates($this->m_sClass); $aStates = MetaModel::EnumStates($this->m_sClass);
$sStateAttCode = MetaModel::GetStateAttributeCode($this->m_sClass); $sStateAttCode = MetaModel::GetStateAttributeCode($this->m_sClass);
$aMandatoryAttributes = array(); $aMandatoryAttributes = array();
// Some attributes are always mandatory independently of the state machine (if any) // Some attributes are always mandatory independently of the state machine (if any)
foreach(MetaModel::GetAttributesList($this->m_sClass) as $sAttCode) foreach(MetaModel::GetAttributesList($this->m_sClass) as $sAttCode)
{ {
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode); $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
if (!$oAttDef->IsExternalField() && !$oAttDef->IsNullAllowed() && if (!$oAttDef->IsExternalField() && !$oAttDef->IsNullAllowed() &&
$oAttDef->IsWritable() && ($sAttCode != $sStateAttCode) ) $oAttDef->IsWritable() && ($sAttCode != $sStateAttCode) )
{ {
$aMandatoryAttributes[$sAttCode] = OPT_ATT_MANDATORY; $aMandatoryAttributes[$sAttCode] = OPT_ATT_MANDATORY;
} }
} }
// Now check the attributes that are mandatory in the specified state // Now check the attributes that are mandatory in the specified state
if ( (!empty($this->m_sTargetState)) && (count($aStates[$this->m_sTargetState]['attribute_list']) > 0) ) if ( (!empty($this->m_sTargetState)) && (count($aStates[$this->m_sTargetState]['attribute_list']) > 0) )
{ {
// Check all the fields that *must* be included in the wizard for this // Check all the fields that *must* be included in the wizard for this
// particular target state // particular target state
$aFields = array(); $aFields = array();
foreach($aStates[$this->m_sTargetState]['attribute_list'] as $sAttCode => $iOptions) foreach($aStates[$this->m_sTargetState]['attribute_list'] as $sAttCode => $iOptions)
{ {
if ( (isset($aMandatoryAttributes[$sAttCode])) && if ( (isset($aMandatoryAttributes[$sAttCode])) &&
($aMandatoryAttributes[$sAttCode] & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) ) ($aMandatoryAttributes[$sAttCode] & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) )
{ {
$aMandatoryAttributes[$sAttCode] |= $iOptions; $aMandatoryAttributes[$sAttCode] |= $iOptions;
} }
else else
{ {
$aMandatoryAttributes[$sAttCode] = $iOptions; $aMandatoryAttributes[$sAttCode] = $iOptions;
} }
} }
} }
// Check all the fields that *must* be included in the wizard // Check all the fields that *must* be included in the wizard
// i.e. all mandatory, must-change or must-prompt fields that are // i.e. all mandatory, must-change or must-prompt fields that are
// not also read-only or hidden. // not also read-only or hidden.
// Some fields may be required (null not allowed) from the database // Some fields may be required (null not allowed) from the database
// perspective, but hidden or read-only from the user interface perspective // perspective, but hidden or read-only from the user interface perspective
$aFields = array(); $aFields = array();
foreach($aMandatoryAttributes as $sAttCode => $iOptions) foreach($aMandatoryAttributes as $sAttCode => $iOptions)
{ {
if ( ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) && if ( ($iOptions & (OPT_ATT_MANDATORY | OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) &&
!($iOptions & (OPT_ATT_READONLY | OPT_ATT_HIDDEN)) ) !($iOptions & (OPT_ATT_READONLY | OPT_ATT_HIDDEN)) )
{ {
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode); $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
$aPrerequisites = $oAttDef->GetPrerequisiteAttributes(); $aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
$aFields[$sAttCode] = array(); $aFields[$sAttCode] = array();
foreach($aPrerequisites as $sCode) foreach($aPrerequisites as $sCode)
{ {
$aFields[$sAttCode][$sCode] = ''; $aFields[$sAttCode][$sCode] = '';
} }
} }
} }
// Now use the dependencies between the fields to order them // Now use the dependencies between the fields to order them
// Start from the order of the 'details' // Start from the order of the 'details'
$aList = MetaModel::FlattenZlist(MetaModel::GetZListItems($this->m_sClass, 'details')); $aList = MetaModel::FlattenZlist(MetaModel::GetZListItems($this->m_sClass, 'details'));
$index = 0; $index = 0;
$aOrder = array(); $aOrder = array();
foreach($aFields as $sAttCode => $void) foreach($aFields as $sAttCode => $void)
{ {
$aOrder[$sAttCode] = 999; // At the end of the list... $aOrder[$sAttCode] = 999; // At the end of the list...
} }
foreach($aList as $sAttCode) foreach($aList as $sAttCode)
{ {
if (array_key_exists($sAttCode, $aFields)) if (array_key_exists($sAttCode, $aFields))
{ {
$aOrder[$sAttCode] = $index; $aOrder[$sAttCode] = $index;
} }
$index++; $index++;
} }
foreach($aFields as $sAttCode => $aDependencies) foreach($aFields as $sAttCode => $aDependencies)
{ {
// All fields with no remaining dependencies can be entered at this // All fields with no remaining dependencies can be entered at this
// step of the wizard // step of the wizard
if (count($aDependencies) > 0) if (count($aDependencies) > 0)
{ {
$iMaxPos = 0; $iMaxPos = 0;
// Remove this field from the dependencies of the other fields // Remove this field from the dependencies of the other fields
foreach($aDependencies as $sDependentAttCode => $void) foreach($aDependencies as $sDependentAttCode => $void)
{ {
// position the current field after the ones it depends on // position the current field after the ones it depends on
$iMaxPos = max($iMaxPos, 1+$aOrder[$sDependentAttCode]); $iMaxPos = max($iMaxPos, 1+$aOrder[$sDependentAttCode]);
} }
} }
} }
asort($aOrder); asort($aOrder);
$aCurrentStep = array(); $aCurrentStep = array();
foreach($aOrder as $sAttCode => $rank) foreach($aOrder as $sAttCode => $rank)
{ {
$aCurrentStep[] = $sAttCode; $aCurrentStep[] = $sAttCode;
$aFieldsDone[$sAttCode] = ''; $aFieldsDone[$sAttCode] = '';
} }
$aWizardSteps['mandatory'][] = $aCurrentStep; $aWizardSteps['mandatory'][] = $aCurrentStep;
// Now computes the steps to fill the optional fields // Now computes the steps to fill the optional fields
$aFields = array(); // reset $aFields = array(); // reset
foreach(MetaModel::ListAttributeDefs($this->m_sClass) as $sAttCode=>$oAttDef) foreach(MetaModel::ListAttributeDefs($this->m_sClass) as $sAttCode=>$oAttDef)
{ {
$iOptions = (isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode])) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0; $iOptions = (isset($aStates[$this->m_sTargetState]['attribute_list'][$sAttCode])) ? $aStates[$this->m_sTargetState]['attribute_list'][$sAttCode] : 0;
if ( ($sStateAttCode != $sAttCode) && if ( ($sStateAttCode != $sAttCode) &&
(!$oAttDef->IsExternalField()) && (!$oAttDef->IsExternalField()) &&
(($iOptions & (OPT_ATT_HIDDEN | OPT_ATT_READONLY)) == 0) && (($iOptions & (OPT_ATT_HIDDEN | OPT_ATT_READONLY)) == 0) &&
(!isset($aFieldsDone[$sAttCode])) ) (!isset($aFieldsDone[$sAttCode])) )
{ {
// 'State', external fields, read-only and hidden fields // 'State', external fields, read-only and hidden fields
// and fields that are already listed in the wizard // and fields that are already listed in the wizard
// are removed from the 'optional' part of the wizard // are removed from the 'optional' part of the wizard
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode); $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
$aPrerequisites = $oAttDef->GetPrerequisiteAttributes(); $aPrerequisites = $oAttDef->GetPrerequisiteAttributes();
$aFields[$sAttCode] = array(); $aFields[$sAttCode] = array();
foreach($aPrerequisites as $sCode) foreach($aPrerequisites as $sCode)
{ {
if (!isset($aFieldsDone[$sCode])) if (!isset($aFieldsDone[$sCode]))
{ {
// retain only the dependencies that were not covered // retain only the dependencies that were not covered
// in the 'mandatory' part of the wizard // in the 'mandatory' part of the wizard
$aFields[$sAttCode][$sCode] = ''; $aFields[$sAttCode][$sCode] = '';
} }
} }
} }
} }
// Now use the dependencies between the fields to order them // Now use the dependencies between the fields to order them
while(count($aFields) > 0) while(count($aFields) > 0)
{ {
$aCurrentStep = array(); $aCurrentStep = array();
foreach($aFields as $sAttCode => $aDependencies) foreach($aFields as $sAttCode => $aDependencies)
{ {
// All fields with no remaining dependencies can be entered at this // All fields with no remaining dependencies can be entered at this
// step of the wizard // step of the wizard
if (count($aDependencies) == 0) if (count($aDependencies) == 0)
{ {
$aCurrentStep[] = $sAttCode; $aCurrentStep[] = $sAttCode;
$aFieldsDone[$sAttCode] = ''; $aFieldsDone[$sAttCode] = '';
unset($aFields[$sAttCode]); unset($aFields[$sAttCode]);
// Remove this field from the dependencies of the other fields // Remove this field from the dependencies of the other fields
foreach($aFields as $sUpdatedCode => $aDummy) foreach($aFields as $sUpdatedCode => $aDummy)
{ {
// remove the dependency // remove the dependency
unset($aFields[$sUpdatedCode][$sAttCode]); unset($aFields[$sUpdatedCode][$sAttCode]);
} }
} }
} }
if (count($aCurrentStep) == 0) if (count($aCurrentStep) == 0)
{ {
// This step of the wizard would contain NO field ! // This step of the wizard would contain NO field !
$this->m_oPage->add(Dict::S('UI:Error:WizardCircularReferenceInDependencies')); $this->m_oPage->add(Dict::S('UI:Error:WizardCircularReferenceInDependencies'));
print_r($aFields); print_r($aFields);
break; break;
} }
$aWizardSteps['optional'][] = $aCurrentStep; $aWizardSteps['optional'][] = $aCurrentStep;
} }
return $aWizardSteps; return $aWizardSteps;
} }
} }
?> ?>

View File

@@ -1,5 +1,5 @@
<?php <?php
// Copyright (C) 2010-2017 Combodo SARL // Copyright (C) 2010-2012 Combodo SARL
// //
// This file is part of iTop. // This file is part of iTop.
// //
@@ -19,7 +19,7 @@
/** /**
* Store and retrieve user's preferences (i.e persistent per user settings) * Store and retrieve user's preferences (i.e persistent per user settings)
* *
* @copyright Copyright (C) 2010-2017 Combodo SARL * @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0 * @license http://opensource.org/licenses/AGPL-3.0
*/ */
require_once(APPROOT.'/core/dbobject.class.php'); require_once(APPROOT.'/core/dbobject.class.php');
@@ -50,7 +50,7 @@ class appUserPreferences extends DBObject
self::Load(); self::Load();
} }
$aPrefs = self::$oUserPrefs->Get('preferences'); $aPrefs = self::$oUserPrefs->Get('preferences');
if (array_key_exists($sCode, $aPrefs)) if (isset($aPrefs[$sCode]))
{ {
return $aPrefs[$sCode]; return $aPrefs[$sCode];
} }
@@ -72,16 +72,9 @@ class appUserPreferences extends DBObject
self::Load(); self::Load();
} }
$aPrefs = self::$oUserPrefs->Get('preferences'); $aPrefs = self::$oUserPrefs->Get('preferences');
if (array_key_exists($sCode, $aPrefs) && ($aPrefs[$sCode] === $sValue)) $aPrefs[$sCode] = $sValue;
{ self::$oUserPrefs->Set('preferences', $aPrefs);
// Do not write it again self::Save();
}
else
{
$aPrefs[$sCode] = $sValue;
self::$oUserPrefs->Set('preferences', $aPrefs);
self::Save();
}
} }
/** /**
@@ -155,9 +148,7 @@ class appUserPreferences extends DBObject
{ {
if (self::$oUserPrefs->IsModified()) if (self::$oUserPrefs->IsModified())
{ {
utils::PushArchiveMode(false);
self::$oUserPrefs->DBUpdate(); self::$oUserPrefs->DBUpdate();
utils::PopArchiveMode();
} }
} }
} }
@@ -181,9 +172,7 @@ class appUserPreferences extends DBObject
$oObj->Set('preferences', array()); // Default preferences: an empty array $oObj->Set('preferences', array()); // Default preferences: an empty array
try try
{ {
utils::PushArchiveMode(false);
$oObj->DBInsert(); $oObj->DBInsert();
utils::PopArchiveMode();
} }
catch(Exception $e) catch(Exception $e)
{ {
@@ -218,8 +207,7 @@ class appUserPreferences extends DBObject
*/ */
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null) public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null)
{ {
utils::PushArchiveMode(false);
$this->DBDelete($oDeletionPlan); $this->DBDelete($oDeletionPlan);
utils::PopArchiveMode();
} }
} }
?>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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