Compare commits

..

50 Commits

Author SHA1 Message Date
Romain Quetiez
1e6437a615 Created branch 1.2.0 (now the branch 1.2 means 1.2.1)
SVN:1.2.0[1722]
2011-12-15 16:17:30 +00:00
Denis Flaven
78e173d5fb Bug fix: paginated lists were broken in the Impact Analysis "List" tab
SVN:1.2[1708]
2011-12-07 10:41:13 +00:00
Romain Quetiez
6b8abce03a - commited merge information (done earlier) -
SVN:1.2[1705]
2011-12-06 13:52:44 +00:00
Denis Flaven
33a7005069 - Bug ! Incorrectly appending a parameter ?version= to linked scripts already containing a parameter in their URL !
- changed the parameter name to itopversion to avoid collisions

SVN:1.2[1702]
2011-12-01 17:18:47 +00:00
Denis Flaven
006a6037d1 Increased Suhosin minimum value for get_max_value to 2048 due to a bug seen on some installations
SVN:1.2[1700]
2011-11-30 13:23:32 +00:00
Denis Flaven
e2f8be1745 Use the default language when creating a new user from CAS
SVN:1.2[1698]
2011-11-29 15:56:24 +00:00
Denis Flaven
ebae45f6a5 Support patterns for casMemberof
SVN:1.2[1696]
2011-11-29 15:36:58 +00:00
Denis Flaven
0685835d49 Allow to log entries on behalf of another user
SVN:1.2[1694]
2011-11-24 17:22:19 +00:00
Romain Quetiez
1b1e88f9a4 In french, organiZation takes an S
SVN:1.2[1691]
2011-11-23 15:30:11 +00:00
Denis Flaven
b90f443e75 - Don't create warnings for empty ext keys (i.e. empty string)
- Properly record multiple warnings
- Don't record warnings in case of creation error (error has precedence)

SVN:1.2[1689]
2011-11-23 09:55:44 +00:00
Romain Quetiez
4da64a64b1 Cosmetic on the API of the dictionnary (internal)
SVN:1.2[1686]
2011-11-21 17:03:36 +00:00
Denis Flaven
6673e171dc Properly handle restrictions (e.g. AllowedValues) on objects that are used as n:n relationships managed via LinksWidget.
SVN:1.2[1685]
2011-11-21 13:08:10 +00:00
Denis Flaven
afee7297cc Properly handle restrictions (e.g. AllowedValues) on objects that are used as n:n relationships managed via LinksWidget.
SVN:1.2[1683]
2011-11-21 10:57:50 +00:00
Denis Flaven
3cc8b5b88a Enhancement: when an (optional) external key cannot be reconciled, log a warning on the replica. the replicas containing a warning are then processed everytime in case the ext key changes
Also improved the search/display of replicas

SVN:1.2[1678]
2011-11-18 11:42:29 +00:00
Romain Quetiez
b2e6981b24 Fixed bug in change tracking: it was impossible to factorize code creating objects in the background either in the context of an object update or in the context of the application of a stimulus
SVN:1.2[1674]
2011-11-18 10:46:42 +00:00
Denis Flaven
c0a79fa573 Prevent warnings when checking the available stimuli in the menu...
SVN:1.2[1672]
2011-11-16 17:26:27 +00:00
Denis Flaven
02ad6d19fe Prevent Javascript errors in case a name contains a quote.
SVN:1.2[1670]
2011-11-15 13:12:22 +00:00
Denis Flaven
d16308ab62 - Reload the object after applying a stimulus, in case an action has an effect on an external field...
SVN:1.2[1665]
2011-11-14 10:44:31 +00:00
Denis Flaven
4598959bc2 - Reload the object after applying a stimulus, in case an action has an effect on an external field...
SVN:1.2[1664]
2011-11-14 10:43:06 +00:00
Denis Flaven
65a3755f81 - Regression from previous fix: don't Reload an object before saving it !
SVN:1.2[1662]
2011-11-10 16:37:18 +00:00
Denis Flaven
dc46c65499 - Don't activate triggers if the transition fails
- Reload the object, in case some custom action changed an external object

SVN:1.2[1659]
2011-11-10 10:12:43 +00:00
Denis Flaven
9d691c8e56 Removed obsolete code which caused a warning in bulk_stimulus
SVN:1.2[1658]
2011-11-10 10:07:28 +00:00
Denis Flaven
99f897bff7 Better error handling in case of OQL error
SVN:1.2[1657]
2011-11-09 17:07:25 +00:00
Denis Flaven
8d83447222 Added the capability for plug-ins to "listen" to add/remove attachment events.
SVN:1.2[1652]
2011-10-28 12:46:22 +00:00
Romain Quetiez
dcc8ad08a4 New helper class: TemplateString - to allow extended syntaxes such as $this->location_id->org_id->parent_id->name$... to be progressively introduced and replace the heavy ToArgs()
SVN:1.2[1646]
2011-10-24 13:45:49 +00:00
Denis Flaven
c1b0b73b51 Bug fix: Trac #494. It seems that PHPSoap does not understand the <wsdl:documentation> tag.
SVN:1.2[1644]
2011-10-21 08:42:13 +00:00
Romain Quetiez
81173decca Fixed issue: nobody in the list of persons to notify for portal users (security takes precedence)
SVN:1.2[1641]
2011-10-21 08:05:07 +00:00
Denis Flaven
9aca062bf5 Enhancement to provide a forward compatible API for some external plugins: support adding attachments to an email in a "clean" way.
SVN:1.2[1640]
2011-10-20 16:33:46 +00:00
Denis Flaven
09aba95d0a Fixed Trac #493: incorrect display of Users' Grant Matrix
SVN:1.2[1635]
2011-10-17 09:27:23 +00:00
Denis Flaven
1683ca2dd6 Merged some enhancements fro the trunk to better keep track of sent emails
SVN:1.2[1634]
2011-10-13 15:42:59 +00:00
Denis Flaven
9e732d6045 Fixed Trac #487: resizable text areas disappeared when located on the second tab !
SVN:1.2[1628]
2011-10-04 10:52:03 +00:00
Denis Flaven
69df343bd2 Automatic synchro of CAS/LDAP users
SVN:1.2[1627]
2011-10-03 14:07:29 +00:00
Denis Flaven
eb8f49ebfe Initializes the admin contact's phone number, in case it is a mandatory field in the data model...
SVN:1.2[1623]
2011-09-30 08:03:45 +00:00
Denis Flaven
398e294604 Prevent crash when trying to load the favicon during the setup !
SVN:1.2[1621]
2011-09-29 15:27:25 +00:00
Denis Flaven
d04c6bccd5 Added a link to a favicon (icon in the browser's bar and tab)
SVN:1.2[1619]
2011-09-29 14:54:03 +00:00
Denis Flaven
f00c7c6bc2 GetValueLabel is used in some dashboards... make sure that it is available for any attribute
SVN:1.2[1617]
2011-09-29 09:46:58 +00:00
Denis Flaven
d30e8c359f Make sure that the organisation's drop-down list is not bigger than the left menu...
SVN:1.2[1616]
2011-09-29 09:44:38 +00:00
Romain Quetiez
2bd4a61c00 #485 Export.php improved for integration into Excel / web queries (bug with IIS/HTTPS, limitation on the size of the OQL)
SVN:1.2[1613]
2011-09-29 08:12:28 +00:00
Romain Quetiez
e35c8323df Merge most recent (few) bug fixes from trunk
SVN:1.2[1611]
2011-09-28 14:38:37 +00:00
Romain Quetiez
e4e814281d #484 Fixed issue with IIS ("Wrong password" at first prompt)
SVN:1.2[1610]
2011-09-28 12:59:40 +00:00
Denis Flaven
635cb424a2 Fixed Trac #482: OpenSearch broken.
SVN:1.2[1608]
2011-09-28 10:50:58 +00:00
Romain Quetiez
e95aa6cc69 Merged latest changes in module Attachments (bug fix on install and cosmetic improvements)
SVN:1.2[1604]
2011-09-23 13:49:26 +00:00
Romain Quetiez
c58fd17fc9 Fixed regression on attribute labels; introduced in [1582]
SVN:1.2[1603]
2011-09-23 13:36:57 +00:00
Romain Quetiez
efdec7a343 #478 Fixed issue in the audit: the results are wrong whenever an organization is selected
SVN:1.2[1599]
2011-09-22 12:08:11 +00:00
Romain Quetiez
2352c05d36 Fixed security issue: the attachments were visible by anybody (by forming URLs manually), whatever the allowed organizations. The change requires the execution of the setup/migration procedure.
SVN:1.2[1597]
2011-09-22 11:58:31 +00:00
Romain Quetiez
23634964a5 #477 Could not specify more than one reconciliation key (regression) + took the opportunity to enhance protection against XSS injection (using column names in the data)
SVN:1.2[1589]
2011-09-21 12:39:22 +00:00
Romain Quetiez
619252db99 Merge fix on previous change (fixed #473, but getting a warning)
SVN:1.2[1585]
2011-09-19 11:49:43 +00:00
Romain Quetiez
ca4dbd833c (record merge info)
SVN:1.2[1583]
2011-09-19 10:58:40 +00:00
Romain Quetiez
f62a3b22a3 #473 Could not load NW interfaces (reconciliation issue) - merged from trunk
SVN:1.2[1582]
2011-09-19 10:55:24 +00:00
Romain Quetiez
88416bca5d Created branch 1.2
SVN:1.2[1580]
2011-09-19 10:30:29 +00:00
1326 changed files with 31263 additions and 180476 deletions

View File

@@ -1,26 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* UserRightsMatrix (User management Module) * UserRightsMatrix (User management Module)
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
@@ -274,7 +274,7 @@ class UserRightsMatrix extends UserRightsAddOnAPI
return true; return true;
} }
public function GetSelectFilter($oUser, $sClass, $aSettings = array()) public function GetSelectFilter($oUser, $sClass)
{ {
$oNullFilter = new DBObjectSearch($sClass); $oNullFilter = new DBObjectSearch($sClass);
return $oNullFilter; return $oNullFilter;

View File

@@ -1,27 +1,27 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* UserRightsNull * UserRightsNull
* User management Module - say Yeah! to everything * User management Module - say Yeah! to everything
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
class UserRightsNull extends UserRightsAddOnAPI class UserRightsNull extends UserRightsAddOnAPI
@@ -47,7 +47,7 @@ class UserRightsNull extends UserRightsAddOnAPI
return true; return true;
} }
public function GetSelectFilter($oUser, $sClass, $aSettings = array()) public function GetSelectFilter($oUser, $sClass)
{ {
$oNullFilter = new DBObjectSearch($sClass); $oNullFilter = new DBObjectSearch($sClass);
return $oNullFilter; return $oNullFilter;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,27 +1,27 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* UserRightsProjection * UserRightsProjection
* User management Module, basing the right on profiles and a matrix (similar to UserRightsProfile, but enhanced with dimensions and projection of classes and profile over the dimensions) * User management Module, basing the right on profiles and a matrix (similar to UserRightsProfile, but enhanced with dimensions and projection of classes and profile over the dimensions)
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
define('ADMIN_PROFILE_ID', 1); define('ADMIN_PROFILE_ID', 1);
@@ -734,7 +734,7 @@ exit;
return true; return true;
} }
public function GetSelectFilter($oUser, $sClass, $aSettings = array()) public function GetSelectFilter($oUser, $sClass)
{ {
$aConditions = array(); $aConditions = array();
foreach ($this->m_aDimensions as $iDimension => $oDimension) foreach ($this->m_aDimensions as $iDimension => $oDimension)

View File

@@ -1,27 +1,27 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* 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-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT."/application/webpage.class.inc.php"); require_once(APPROOT."/application/webpage.class.inc.php");
@@ -36,7 +36,6 @@ class ajax_page extends WebPage
protected $m_sCurrentTab; protected $m_sCurrentTab;
protected $m_sCurrentTabContainer; protected $m_sCurrentTabContainer;
protected $m_aTabs; protected $m_aTabs;
private $m_sMenu; // If set, then the menu will be updated
/** /**
* constructor for the web page * constructor for the web page
@@ -53,7 +52,6 @@ class ajax_page extends WebPage
$this->m_aTabs = array(); $this->m_aTabs = array();
$this->sContentType = 'text/html'; $this->sContentType = 'text/html';
$this->sContentDisposition = 'inline'; $this->sContentDisposition = 'inline';
$this->m_sMenu = "";
} }
public function AddTabContainer($sTabContainer, $sPrefix = '') public function AddTabContainer($sTabContainer, $sPrefix = '')
@@ -95,11 +93,6 @@ class ajax_page extends WebPage
return $this->m_sCurrentTab; return $this->m_sCurrentTab;
} }
public function AddToMenu($sHtml)
{
$this->m_sMenu .= $sHtml;
}
/** /**
* Echoes the content of the whole page * Echoes the content of the whole page
* @return void * @return void
@@ -120,42 +113,35 @@ class ajax_page extends WebPage
} }
if (count($this->m_aTabs) > 0) if (count($this->m_aTabs) > 0)
{ {
$this->add_ready_script( $this->add_ready_script(
<<<EOF <<<EOF
// The "tab widgets" to handle. // The "tab widgets" to handle.
var tabs = $('div[id^=tabbedContent]'); var tabs = $('div[id^=tabbedContent]');
if ($.bbq) // This selector will be reused when selecting actual tab widget A elements.
var tab_a_selector = 'ul.ui-tabs-nav a';
// 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
// specified. Note that if you define a callback for the 'select' event, it
// will be executed for the selected tab whenever the hash changes.
tabs.tabs({ event: 'change' });
// Define our own click handler for the tabs, overriding the default.
tabs.find( tab_a_selector ).click(function()
{ {
// This selector will be reused when selecting actual tab widget A elements. var state = {};
var tab_a_selector = 'ul.ui-tabs-nav a';
// Get the id of this tab widget.
var id = $(this).closest( 'div[id^=tabbedContent]' ).attr( 'id' );
// Enable tabs on all tab widgets. The `event` property must be overridden so // Get the index of this tab.
// that the tabs aren't changed on click, and any custom event name can be var idx = $(this).parent().prevAll().length;
// specified. Note that if you define a callback for the 'select' event, it
// will be executed for the selected tab whenever the hash changes. // Set the state!
tabs.tabs({ event: 'change' }); state[ id ] = idx;
$.bbq.pushState( state );
// Define our own click handler for the tabs, overriding the default. });
tabs.find( tab_a_selector ).click(function()
{
var state = {};
// Get the id of this tab widget.
var id = $(this).closest( 'div[id^=tabbedContent]' ).attr( 'id' );
// Get the index of this tab.
var idx = $(this).parent().prevAll().length;
// Set the state!
state[ id ] = idx;
$.bbq.pushState( state );
});
}
else
{
tabs.tabs();
}
EOF EOF
); );
} }
@@ -168,7 +154,7 @@ EOF
$container_index = 0; $container_index = 0;
if (count($m_aTabs) > 0) if (count($m_aTabs) > 0)
{ {
$sTabs = "<!-- tabs -->\n<div id=\"tabbedContent_{$sPrefix}{$sTabContainerName}\" class=\"light\">\n"; $sTabs = "<!-- tabs -->\n<div id=\"tabbedContent_{$sPrefix}{$container_index}\" class=\"light\">\n";
$sTabs .= "<ul>\n"; $sTabs .= "<ul>\n";
// Display the unordered list that will be rendered as the tabs // Display the unordered list that will be rendered as the tabs
$i = 0; $i = 0;
@@ -190,33 +176,7 @@ EOF
$this->s_content = str_replace("\$Tabs:$sTabContainerName\$", $sTabs, $this->s_content); $this->s_content = str_replace("\$Tabs:$sTabContainerName\$", $sTabs, $this->s_content);
$container_index++; $container_index++;
} }
// 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)) )
{
$this->add_ready_script(
<<<EOF
$(".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
});
EOF
);
}
$s_captured_output = ob_get_contents(); $s_captured_output = ob_get_contents();
ob_end_clean(); ob_end_clean();
if (($this->sContentType == 'text/html') && ($this->sContentDisposition == 'inline')) if (($this->sContentType == 'text/html') && ($this->sContentDisposition == 'inline'))
@@ -228,24 +188,6 @@ EOF
{ {
echo $this->s_content; echo $this->s_content;
} }
if (!empty($this->m_sMenu))
{
$uid = time();
echo "<div id=\"accordion_temp_$uid\">\n";
echo "<div id=\"accordion\">\n";
echo "<!-- Beginning of the accordion menu -->\n";
echo self::FilterXSS($this->m_sMenu);
echo "<!-- End of the accordion menu-->\n";
echo "</div>\n";
echo "</div>\n";
echo "<script type=\"text/javascript\">\n";
echo "$('#inner_menu').html($('#accordion_temp_$uid').html());\n";
echo "$('#accordion_temp_$uid').remove();\n";
echo "$('#accordion').accordion({ header: 'h3', navigation: true, autoHeight: false, collapsible: false, icons: false });\n";
echo "\n</script>\n";
}
//echo $this->s_deferred_content; //echo $this->s_deferred_content;
if (count($this->a_scripts) > 0) if (count($this->a_scripts) > 0)
{ {
@@ -265,16 +207,10 @@ EOF
echo $this->m_sReadyScript; // Ready Scripts are output as simple scripts echo $this->m_sReadyScript; // Ready Scripts are output as simple scripts
echo "\n</script>\n"; echo "\n</script>\n";
} }
if (trim($s_captured_output) != "") if (trim($s_captured_output) != "")
{ {
echo self::FilterXSS($s_captured_output); echo self::FilterXSS($s_captured_output);
} }
if (class_exists('MetaModel'))
{
MetaModel::RecordQueryTrace();
}
} }
/** /**
@@ -364,7 +300,7 @@ EOF
*/ */
public function add_ready_script($sScript) public function add_ready_script($sScript)
{ {
$this->m_sReadyScript .= $sScript."\n"; $this->m_sReadyScript .= $sScript;
} }
/** /**

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* 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 * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT.'/application/applicationcontext.class.inc.php'); require_once(APPROOT.'/application/applicationcontext.class.inc.php');
@@ -30,7 +29,6 @@ require_once(APPROOT.'/application/displayblock.class.inc.php');
require_once(APPROOT.'/application/sqlblock.class.inc.php'); require_once(APPROOT.'/application/sqlblock.class.inc.php');
require_once(APPROOT.'/application/audit.category.class.inc.php'); require_once(APPROOT.'/application/audit.category.class.inc.php');
require_once(APPROOT.'/application/audit.rule.class.inc.php'); require_once(APPROOT.'/application/audit.rule.class.inc.php');
require_once(APPROOT.'/application/query.class.inc.php');
//require_once(APPROOT.'/application/menunode.class.inc.php'); //require_once(APPROOT.'/application/menunode.class.inc.php');
require_once(APPROOT.'/application/utils.inc.php'); require_once(APPROOT.'/application/utils.inc.php');

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Class ApplicationContext * Class ApplicationContext
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT."/application/utils.inc.php"); require_once(APPROOT."/application/utils.inc.php");
@@ -78,16 +77,12 @@ class ApplicationContext
protected $aValues; protected $aValues;
protected static $aDefaultValues; // Cache shared among all instances protected static $aDefaultValues; // Cache shared among all instances
public function __construct($bReadContext = true) public function __construct()
{ {
$this->aNames = array( $this->aNames = array(
'org_id', 'menu' 'org_id', 'menu'
); );
if ($bReadContext) $this->ReadContext();
{
$this->ReadContext();
}
} }
/** /**
@@ -99,7 +94,7 @@ class ApplicationContext
if (!isset(self::$aDefaultValues)) if (!isset(self::$aDefaultValues))
{ {
self::$aDefaultValues = array(); self::$aDefaultValues = array();
$aContext = utils::ReadParam('c', array(), false, 'context_param'); $aContext = utils::ReadParam('c', array());
foreach($this->aNames as $sName) foreach($this->aNames as $sName)
{ {
$sValue = isset($aContext[$sName]) ? $aContext[$sName] : ''; $sValue = isset($aContext[$sName]) ? $aContext[$sName] : '';
@@ -116,7 +111,6 @@ class ApplicationContext
if (MetaModel::IsValidClass('Organization')) if (MetaModel::IsValidClass('Organization'))
{ {
$oSearchFilter = new DBObjectSearch('Organization'); $oSearchFilter = new DBObjectSearch('Organization');
$oSearchFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
$oSet = new CMDBObjectSet($oSearchFilter); $oSet = new CMDBObjectSet($oSearchFilter);
$iCount = $oSet->Count(); $iCount = $oSet->Count();
if ($iCount == 1) if ($iCount == 1)
@@ -222,17 +216,17 @@ class ApplicationContext
if (is_callable($aCallSpec)) if (is_callable($aCallSpec))
{ {
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter $sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
}
if (MetaModel::IsValidAttCode($sClass, $sAttCode)) if (MetaModel::IsValidAttCode($sClass, $sAttCode))
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef->IsWritable())
{ {
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); $value = $this->GetCurrentValue($key, null);
if ($oAttDef->IsWritable()) if (!is_null($value))
{ {
$value = $this->GetCurrentValue($key, null); $oObj->Set($sAttCode, $value);
if (!is_null($value))
{
$oObj->Set($sAttCode, $value);
}
} }
} }
} }
@@ -305,58 +299,5 @@ class ApplicationContext
return ''; return '';
} }
} }
protected static $m_aPluginProperties = null;
/**
* 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 sPluginClass string Class implementing any plugin interface
* @param sProperty string Name of the property
* @param value scalar Value (numeric or string)
* @return void
*/
public static function SetPluginProperty($sPluginClass, $sProperty, $value)
{
if (is_null(self::$m_aPluginProperties)) self::LoadPluginProperties();
self::$m_aPluginProperties[$sPluginClass][$sProperty] = $value;
$_SESSION['PluginProperties'][$sPluginClass][$sProperty] = $value;
}
/**
* Get plugin properties
* @param sPluginClass string 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();
}
}
} }
?> ?>

View File

@@ -1,27 +1,27 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Class iPlugin * Class iPlugin
* Management of application plugin * Management of application plugin
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
interface iApplicationUIExtension interface iApplicationUIExtension
@@ -48,616 +48,4 @@ interface iApplicationObjectExtension
public function OnDBDelete($oObject, $oChange = null); public function OnDBDelete($oObject, $oChange = null);
} }
/** ?>
* New extension to add menu items in the "popup" menus inside iTop. Provides a greater flexibility than
* iApplicationUIExtension::EnumAllowedActions.
*
* To add some menus into iTop, declare a class that implements this interface, it will be called automatically
* by the application, as long as the class definition is included somewhere in the code
*/
interface iPopupMenuExtension
{
// Possible types of menu into which new items can be added
const MENU_OBJLIST_ACTIONS = 1; // $param is a DBObjectSet containing the list of objects
const MENU_OBJLIST_TOOLKIT = 2; // $param is a DBObjectSet containing the list of objects
const MENU_OBJDETAILS_ACTIONS = 3; // $param is a DBObject instance: the object currently displayed
const MENU_DASHBOARD_ACTIONS = 4; // $param is a Dashboard instance: the dashboard currently displayed
const MENU_USER_ACTIONS = 5; // $param is a null ??
/**
* Get the list of items to be added to a menu. The items will be inserted in the menu in the order of the returned array
* @param int $iMenuId The identifier of the type of menu, as listed by the constants MENU_xxx above
* @param mixed $param Depends on $iMenuId, see the constants defined above
* @return Array An array of ApplicationPopupMenuItem or an empty array if no action is to be added to the menu
*/
public static function EnumItems($iMenuId, $param);
}
/**
* Each menu items is defined by an instance of an object derived from the class
* ApplicationPopupMenu below
*
*/
abstract class ApplicationPopupMenuItem
{
protected $sUID;
protected $sLabel;
public function __construct($sUID, $sLabel)
{
$this->sUID = $sUID;
$this->sLabel = $sLabel;
}
public function GetUID()
{
return $this->sUID;
}
public function GetLabel()
{
return $this->sLabel;
}
/**
* Returns the components to create a popup menu item in HTML
* @return Hash A hash array: array('label' => , 'url' => , 'target' => , 'onclick' => )
*/
abstract public function GetMenuItem();
public function GetLinkedScripts()
{
return array();
}
}
/**
* Class for adding an item into a popup menu that browses to the given URL
*/
class URLPopupMenuItem extends ApplicationPopupMenuItem
{
protected $sURL;
protected $sTarget;
/**
* Class for adding an item that browses to the given URL
* @param string $sUID The unique identifier of this menu in iTop... make sure you pass something unique enough
* @param string $sLabel The display label of the menu (must be localized)
* @param string $sURL If the menu is an hyperlink, provide the absolute hyperlink here
* @param string $sTarget In case the menu is an hyperlink and a specific target is needed (_blank for example), pass it here
*/
public function __construct($sUID, $sLabel, $sURL, $sTarget = '_top')
{
parent::__construct($sUID, $sLabel);
$this->sURL = $sURL;
$this->sTarget = $sTarget;
}
public function GetMenuItem()
{
return array ('label' => $this->GetLabel(), 'url' => $this->sURL, 'target' => $this->sTarget);
}
}
/**
* Class for adding an item into a popup menu that triggers some Javascript code
*/
class JSPopupMenuItem extends ApplicationPopupMenuItem
{
protected $sJSCode;
protected $aIncludeJSFiles;
/**
* Class for adding an item that triggers some Javascript code
* @param string $sUID The unique identifier of this menu in iTop... make sure you pass something unique enough
* @param string $sLabel The display label of the menu (must be localized)
* @param string $sJSCode In case the menu consists in executing some havascript code inside the page, pass it here. If supplied $sURL ans $sTarget will be ignored
* @param array $aIncludeJSFiles An array of file URLs to be included (once) to provide some JS libraries for the page.
*/
public function __construct($sUID, $sLabel, $sJSCode, $aIncludeJSFiles = array())
{
parent::__construct($sUID, $sLabel);
$this->sJSCode = $sJSCode;
$this->aIncludeJSFiles = $aIncludeJSFiles;
}
public function GetMenuItem()
{
return array ('label' => $this->GetLabel(), 'onclick' => $this->sJSCode, 'url' => '#');
}
public function GetLinkedScripts()
{
return $this->aIncludeJSFiles;
}
}
/**
* Class for adding a separator (horizontal line, not selectable) the output
* will automatically reduce several consecutive separators to just one
*/
class SeparatorPopupMenuItem extends ApplicationPopupMenuItem
{
/**
* Class for inserting a separator into a popup menu
*/
public function __construct()
{
parent::__construct('', '');
}
public function GetMenuItem()
{
return array ('label' => '<hr class="menu-separator">', 'url' => '');
}
}
/**
* Implement this interface to add content to any iTopWebPage
* There are 3 places where content can be added:
* - The north pane: (normaly empty/hidden) at the top of the page, spanning the whole
* width of the page
* - The south pane: (normaly empty/hidden) at the bottom of the page, spanning the whole
* width of the page
* - The admin banner (two tones gray background) at the left of the global search.
* Limited space, use it for short messages
* Each of the methods of this interface is supposed to return the HTML to be inserted at
* the specified place and can use the passed iTopWebPage object to add javascript or CSS definitions
*
*/
interface iPageUIExtension
{
/**
* Add content to the North pane
* @param WebPage $oPage The page to insert stuff into.
* @return string The HTML content to add into the page
*/
public function GetNorthPaneHtml(iTopWebPage $oPage);
/**
* Add content to the South pane
* @param WebPage $oPage The page to insert stuff into.
* @return string The HTML content to add into the page
*/
public function GetSouthPaneHtml(iTopWebPage $oPage);
/**
* Add content to the "admin banner"
* @param WebPage $oPage The page to insert stuff into.
* @return string The HTML content to add into the page
*/
public function GetBannerHtml(iTopWebPage $oPage);
}
/**
* Implement this interface to add new operations to the REST/JSON web service
*
* @package Extensibility
* @api
* @since 2.0.1
*/
interface iRestServiceProvider
{
/**
* Enumerate services delivered by this class
* @param string $sVersion The version (e.g. 1.0) supported by the services
* @return array An array of hash 'verb' => verb, 'description' => description
*/
public function ListOperations($sVersion);
/**
* Enumerate services delivered by this class
* @param string $sVersion The version (e.g. 1.0) supported by the services
* @return RestResult The standardized result structure (at least a message)
* @throws Exception in case of internal failure.
*/
public function ExecOperation($sVersion, $sVerb, $aParams);
}
/**
* Minimal REST response structure. Derive this structure to add response data and error codes.
*
* @package Extensibility
* @api
* @since 2.0.1
*/
class RestResult
{
/**
* Result: no issue has been encountered
*/
const OK = 0;
/**
* Result: missing/wrong credentials or the user does not have enough rights to perform the requested operation
*/
const UNAUTHORIZED = 1;
/**
* Result: the parameter 'version' is missing
*/
const MISSING_VERSION = 2;
/**
* Result: the parameter 'json_data' is missing
*/
const MISSING_JSON = 3;
/**
* Result: the input structure is not a valid JSON string
*/
const INVALID_JSON = 4;
/**
* Result: no operation is available for the specified version
*/
const UNSUPPORTED_VERSION = 10;
/**
* Result: the requested operation is not valid for the specified version
*/
const UNKNOWN_OPERATION = 11;
/**
* Result: the requested operation cannot be performed because it can cause data (integrity) loss
*/
const UNSAFE = 12;
/**
* Result: the operation could not be performed, see the message for troubleshooting
*/
const INTERNAL_ERROR = 100;
/**
* Default constructor - ok!
*
* @param DBObject $oObject The object being reported
* @param string $sAttCode The attribute code (must be valid)
* @return string A scalar representation of the value
*/
public function __construct()
{
$this->code = RestResult::OK;
}
public $code;
public $message;
}
/**
* Helpers for implementing REST services
*
* @package Extensibility
* @api
*/
class RestUtils
{
/**
* Registering tracking information. Any further object modification be associated with the given comment, when the modification gets recorded into the DB
*
* @param StdClass $oData Structured input data. Must contain 'comment'.
* @return void
* @throws Exception
* @api
*/
public static function InitTrackingComment($oData)
{
$sComment = self::GetMandatoryParam($oData, 'comment');
CMDBObject::SetTrackInfo($sComment);
}
/**
* Read a mandatory parameter from from a Rest/Json structure.
*
* @param StdClass $oData Structured input data. Must contain the entry defined by sParamName.
* @param string $sParamName Name of the parameter to fetch from the input data
* @return void
* @throws Exception If the parameter is missing
* @api
*/
public static function GetMandatoryParam($oData, $sParamName)
{
if (isset($oData->$sParamName))
{
return $oData->$sParamName;
}
else
{
throw new Exception("Missing parameter '$sParamName'");
}
}
/**
* Read an optional parameter from from a Rest/Json structure.
*
* @param StdClass $oData Structured input data.
* @param string $sParamName Name of the parameter to fetch from the input data
* @param mixed $default Default value if the parameter is not found in the input data
* @return void
* @throws Exception
* @api
*/
public static function GetOptionalParam($oData, $sParamName, $default)
{
if (isset($oData->$sParamName))
{
return $oData->$sParamName;
}
else
{
return $default;
}
}
/**
* Read a class from a Rest/Json structure.
*
* @param StdClass $oData Structured input data. Must contain the entry defined by sParamName.
* @param string $sParamName Name of the parameter to fetch from the input data
* @return void
* @throws Exception If the parameter is missing or the class is unknown
* @api
*/
public static function GetClass($oData, $sParamName)
{
$sClass = self::GetMandatoryParam($oData, $sParamName);
if (!MetaModel::IsValidClass($sClass))
{
throw new Exception("$sParamName: '$sClass' is not a valid class'");
}
return $sClass;
}
/**
* Read a list of attribute codes from a Rest/Json structure.
*
* @param string $sClass Name of the class
* @param StdClass $oData Structured input data.
* @param string $sParamName Name of the parameter to fetch from the input data
* @return void
* @throws Exception
* @api
*/
public static function GetFieldList($sClass, $oData, $sParamName)
{
$sFields = self::GetOptionalParam($oData, $sParamName, '*');
$aShowFields = array();
if ($sFields == '*')
{
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
{
$aShowFields[] = $sAttCode;
}
}
else
{
foreach(explode(',', $sFields) as $sAttCode)
{
$sAttCode = trim($sAttCode);
if (($sAttCode != 'id') && (!MetaModel::IsValidAttCode($sClass, $sAttCode)))
{
throw new Exception("$sParamName: invalid attribute code '$sAttCode'");
}
$aShowFields[] = $sAttCode;
}
}
return $aShowFields;
}
/**
* Read and interpret object search criteria from a Rest/Json structure
*
* @param string $sClass Name of the class
* @param StdClass $oCriteria Hash of attribute code => value (can be a substructure or a scalar, depending on the nature of the attriute)
* @return object The object found
* @throws Exception If the input structure is not valid or it could not find exactly one object
*/
protected static function FindObjectFromCriteria($sClass, $oCriteria)
{
$aCriteriaReport = array();
if (isset($oCriteria->finalclass))
{
$sClass = $oCriteria->finalclass;
if (!MetaModel::IsValidClass($sClass))
{
throw new Exception("finalclass: Unknown class '$sClass'");
}
}
$oSearch = new DBObjectSearch($sClass);
foreach ($oCriteria as $sAttCode => $value)
{
$realValue = self::MakeValue($sClass, $sAttCode, $value);
$oSearch->AddCondition($sAttCode, $realValue);
$aCriteriaReport[] = "$sAttCode: $value ($realValue)";
}
$oSet = new DBObjectSet($oSearch);
$iCount = $oSet->Count();
if ($iCount == 0)
{
throw new Exception("No item found with criteria: ".implode(', ', $aCriteriaReport));
}
elseif ($iCount > 1)
{
throw new Exception("Several items found ($iCount) with criteria: ".implode(', ', $aCriteriaReport));
}
$res = $oSet->Fetch();
return $res;
}
/**
* Find an object from a polymorph search specification (Rest/Json)
*
* @param string $sClass Name of the class
* @param mixed $key Either search criteria (substructure), or an object or an OQL string.
* @return DBObject The object found
* @throws Exception If the input structure is not valid or it could not find exactly one object
* @api
*/
public static function FindObjectFromKey($sClass, $key)
{
if (is_object($key))
{
$res = self::FindObjectFromCriteria($sClass, $key);
}
elseif (is_numeric($key))
{
$res = MetaModel::GetObject($sClass, $key, false);
if (is_null($res))
{
throw new Exception("Invalid object $sClass::$key");
}
}
elseif (is_string($key))
{
// OQL
$oSearch = DBObjectSearch::FromOQL($key);
$oSet = new DBObjectSet($oSearch);
$iCount = $oSet->Count();
if ($iCount == 0)
{
throw new Exception("No item found for query: $key");
}
elseif ($iCount > 1)
{
throw new Exception("Several items found ($iCount) for query: $key");
}
$res = $oSet->Fetch();
}
else
{
throw new Exception("Wrong format for key");
}
return $res;
}
/**
* Search objects from a polymorph search specification (Rest/Json)
*
* @param string $sClass Name of the class
* @param mixed $key Either search criteria (substructure), or an object or an OQL string.
* @return DBObjectSet The search result set
* @throws Exception If the input structure is not valid
*/
public static function GetObjectSetFromKey($sClass, $key)
{
if (is_object($key))
{
if (isset($key->finalclass))
{
$sClass = $key->finalclass;
if (!MetaModel::IsValidClass($sClass))
{
throw new Exception("finalclass: Unknown class '$sClass'");
}
}
$oSearch = new DBObjectSearch($sClass);
foreach ($key as $sAttCode => $value)
{
$realValue = self::MakeValue($sClass, $sAttCode, $value);
$oSearch->AddCondition($sAttCode, $realValue);
}
}
elseif (is_numeric($key))
{
$oSearch = new DBObjectSearch($sClass);
$oSearch->AddCondition('id', $key);
}
elseif (is_string($key))
{
// OQL
$oSearch = DBObjectSearch::FromOQL($key);
$oObjectSet = new DBObjectSet($oSearch);
}
else
{
throw new Exception("Wrong format for key");
}
$oObjectSet = new DBObjectSet($oSearch);
return $oObjectSet;
}
/**
* Interpret the Rest/Json value and get a valid attribute value
*
* @param string $sClass Name of the class
* @param string $sAttCode Attribute code
* @param mixed $value Depending on the type of attribute (a scalar, or search criteria, or list of related objects...)
* @return mixed The value that can be used with DBObject::Set()
* @throws Exception If the specification of the value is not valid.
* @api
*/
public static function MakeValue($sClass, $sAttCode, $value)
{
try
{
if (!MetaModel::IsValidAttCode($sClass, $sAttCode))
{
throw new Exception("Unknown attribute");
}
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef instanceof AttributeExternalKey)
{
$oExtKeyObject = self::FindObjectFromKey($oAttDef->GetTargetClass(), $value);
$value = $oExtKeyObject->GetKey();
}
elseif ($oAttDef instanceof AttributeLinkedSet)
{
if (!is_array($value))
{
throw new Exception("A link set must be defined by an array of objects");
}
$sLnkClass = $oAttDef->GetLinkedClass();
$aLinks = array();
foreach($value as $oValues)
{
$oLnk = self::MakeObjectFromFields($sLnkClass, $oValues);
$aLinks[] = $oLnk;
}
$value = DBObjectSet::FromArray($sLnkClass, $aLinks);
}
else
{
$value = $oAttDef->FromJSONToValue($value);
}
}
catch (Exception $e)
{
throw new Exception("$sAttCode: ".$e->getMessage(), $e->getCode());
}
return $value;
}
/**
* Interpret a Rest/Json structure that defines attribute values, and build an object
*
* @param string $sClass Name of the class
* @param array $aFields A hash of attribute code => value specification.
* @return DBObject The newly created object
* @throws Exception If the specification of the values is not valid
* @api
*/
public static function MakeObjectFromFields($sClass, $aFields)
{
$oObject = MetaModel::NewObject($sClass);
foreach ($aFields as $sAttCode => $value)
{
$realValue = self::MakeValue($sClass, $sAttCode, $value);
$oObject->Set($sAttCode, $realValue);
}
return $oObject;
}
/**
* Interpret a Rest/Json structure that defines attribute values, and update the given object
*
* @param DBObject $oObject The object being modified
* @param array $aFields A hash of attribute code => value specification.
* @return DBObject The object modified
* @throws Exception If the specification of the values is not valid
* @api
*/
public static function UpdateObjectFromFields($oObject, $aFields)
{
$sClass = get_class($oObject);
foreach ($aFields as $sAttCode => $value)
{
$realValue = self::MakeValue($sClass, $sAttCode, $value);
$oObject->Set($sAttCode, $realValue);
}
return $oObject;
}
}

View File

@@ -1,29 +1,28 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* 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 * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT.'/application/cmdbabstract.class.inc.php'); require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
@@ -47,7 +46,7 @@ class AuditCategory extends cmdbAbstractObject
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))); 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())));
// 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

View File

@@ -1,21 +1,18 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* This class manages the audit "rule" linked to a given audit category. * This class manages the audit "rule" linked to a given audit category.
@@ -23,8 +20,10 @@
* 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 * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT.'/application/audit.category.class.inc.php'); require_once(APPROOT.'/application/audit.category.class.inc.php');

View File

@@ -1,33 +1,32 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* 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-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT."/application/webpage.class.inc.php"); require_once(APPROOT."/application/webpage.class.inc.php");
class CLIPage implements Page class CLIPage
{ {
function __construct($s_title) function __construct($s_title)
{ {
@@ -35,10 +34,6 @@ class CLIPage implements Page
public function output() public function output()
{ {
if (class_exists('MetaModel'))
{
MetaModel::RecordQueryTrace();
}
} }
public function add($sText) public function add($sText)

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +1,27 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* 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-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT."/application/webpage.class.inc.php"); require_once(APPROOT."/application/webpage.class.inc.php");
@@ -32,9 +31,8 @@ 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/html; charset=utf-8");
$this->add_header("Cache-control: no-cache"); $this->add_header("Cache-control: no-cache");
//$this->add_header("Content-Transfer-Encoding: binary");
} }
public function output() public function output()
@@ -45,12 +43,6 @@ class CSVPage extends WebPage
header($s_header); header($s_header);
} }
echo trim($this->s_content); echo trim($this->s_content);
echo "\n";
if (class_exists('MetaModel'))
{
MetaModel::RecordQueryTrace();
}
} }
public function small_p($sText) public function small_p($sText)

View File

@@ -1,747 +0,0 @@
<?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/>
require_once(APPROOT.'application/dashboardlayout.class.inc.php');
require_once(APPROOT.'application/dashlet.class.inc.php');
/**
* A user editable dashboard page
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
abstract class Dashboard
{
protected $sTitle;
protected $sLayoutClass;
protected $aWidgetsData;
protected $oDOMNode;
protected $sId;
protected $aCells;
public function __construct($sId)
{
$this->sLayoutClass = null;
$this->aCells = array();
$this->oDOMNode = null;
$this->sId = $sId;
}
public function FromXml($sXml)
{
$this->aCells = array(); // reset the content of the dashboard
set_error_handler(array('Dashboard', 'ErrorHandler'));
$oDoc = new DOMDocument();
$oDoc->loadXML($sXml);
restore_error_handler();
$this->oDOMNode = $oDoc->getElementsByTagName('dashboard')->item(0);
$oLayoutNode = $this->oDOMNode->getElementsByTagName('layout')->item(0);
$this->sLayoutClass = $oLayoutNode->textContent;
$oTitleNode = $this->oDOMNode->getElementsByTagName('title')->item(0);
$this->sTitle = $oTitleNode->textContent;
$oCellsNode = $this->oDOMNode->getElementsByTagName('cells')->item(0);
$oCellsList = $oCellsNode->getElementsByTagName('cell');
$aCellOrder = array();
$iCellRank = 0;
foreach($oCellsList as $oCellNode)
{
$aDashletList = array();
$oCellRank = $oCellNode->getElementsByTagName('rank')->item(0);
if ($oCellRank)
{
$iCellRank = (float)$oCellRank->textContent;
}
$oDashletsNode = $oCellNode->getElementsByTagName('dashlets')->item(0);
$oDashletList = $oDashletsNode->getElementsByTagName('dashlet');
$iRank = 0;
$aDashletOrder = array();
foreach($oDashletList as $oDomNode)
{
$sDashletClass = $oDomNode->getAttribute('xsi:type');
$oRank = $oDomNode->getElementsByTagName('rank')->item(0);
if ($oRank)
{
$iRank = (float)$oRank->textContent;
}
$sId = $oDomNode->getAttribute('id');
$oNewDashlet = new $sDashletClass($sId);
$oNewDashlet->FromDOMNode($oDomNode);
$aDashletOrder[] = array('rank' => $iRank, 'dashlet' => $oNewDashlet);
}
usort($aDashletOrder, array(get_class($this), 'SortOnRank'));
$aDashletList = array();
foreach($aDashletOrder as $aItem)
{
$aDashletList[] = $aItem['dashlet'];
}
$aCellOrder[] = array('rank' => $iCellRank, 'dashlets' => $aDashletList);
}
usort($aCellOrder, array(get_class($this), 'SortOnRank'));
foreach($aCellOrder as $aItem)
{
$this->aCells[] = $aItem['dashlets'];
}
}
static function SortOnRank($aItem1, $aItem2)
{
return ($aItem1['rank'] > $aItem2['rank']) ? +1 : -1;
}
/**
* Error handler to turn XML loading warnings into exceptions
*/
public static function ErrorHandler($errno, $errstr, $errfile, $errline)
{
if ($errno == E_WARNING && (substr_count($errstr,"DOMDocument::loadXML()")>0))
{
throw new DOMException($errstr);
}
else
{
return false;
}
}
public function ToXml()
{
$oDoc = new DOMDocument();
$oDoc->formatOutput = true; // indent (must be loaded with option LIBXML_NOBLANKS)
$oDoc->preserveWhiteSpace = true; // otherwise the formatOutput option would have no effect
$oMainNode = $oDoc->createElement('dashboard');
$oMainNode->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance");
$oDoc->appendChild($oMainNode);
$oNode = $oDoc->createElement('layout', $this->sLayoutClass);
$oMainNode->appendChild($oNode);
$oNode = $oDoc->createElement('title', $this->sTitle);
$oMainNode->appendChild($oNode);
$oCellsNode = $oDoc->createElement('cells');
$oMainNode->appendChild($oCellsNode);
$iCellRank = 0;
foreach ($this->aCells as $aCell)
{
$oCellNode = $oDoc->createElement('cell');
$oCellNode->setAttribute('id', $iCellRank);
$oCellsNode->appendChild($oCellNode);
$oCellRank = $oDoc->createElement('rank', $iCellRank);
$oCellNode->appendChild($oCellRank);
$iCellRank++;
$iDashletRank = 0;
$oDashletsNode = $oDoc->createElement('dashlets');
$oCellNode->appendChild($oDashletsNode);
foreach ($aCell as $oDashlet)
{
$oNode = $oDoc->createElement('dashlet');
$oDashletsNode->appendChild($oNode);
$oNode->setAttribute('id', $oDashlet->GetID());
$oNode->setAttribute('xsi:type', get_class($oDashlet));
$oDashletRank = $oDoc->createElement('rank', $iDashletRank);
$oNode->appendChild($oDashletRank);
$iDashletRank++;
$oDashlet->ToDOMNode($oNode);
}
}
$sXml = $oDoc->saveXML();
return $sXml;
}
public function FromParams($aParams)
{
$this->sLayoutClass = $aParams['layout_class'];
$this->sTitle = $aParams['title'];
foreach($aParams['cells'] as $aCell)
{
$aCellDashlets = array();
foreach($aCell as $aDashletParams)
{
$sDashletClass = $aDashletParams['dashlet_class'];
$sId = $aDashletParams['dashlet_id'];
$oNewDashlet = new $sDashletClass($sId);
$oForm = $oNewDashlet->GetForm();
$oForm->SetParamsContainer($sId);
$oForm->SetPrefix('');
$aValues = $oForm->ReadParams();
$oNewDashlet->FromParams($aValues);
$aCellDashlets[] = $oNewDashlet;
}
$this->aCells[] = $aCellDashlets;
}
}
public function Save()
{
}
public function GetLayout()
{
return $this->sLayoutClass;
}
public function SetLayout($sLayoutClass)
{
$this->sLayoutClass = $sLayoutClass;
}
public function GetTitle()
{
return $this->sTitle;
}
public function SetTitle($sTitle)
{
$this->sTitle = $sTitle;
}
public function AddDashlet($oDashlet)
{
$sId = $this->GetNewDashletId();
$oDashlet->SetId($sId);
$this->aCells[] = array($oDashlet);
}
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
{
$oPage->add('<h1>'.Dict::S($this->sTitle).'</h1>');
$oLayout = new $this->sLayoutClass;
$oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
if (!$bEditMode)
{
$oPage->add_linked_script('../js/dashlet.js');
$oPage->add_linked_script('../js/dashboard.js');
}
}
public function RenderProperties($oPage)
{
// menu to pick a layout and edit other properties of the dashboard
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Properties').'</div>');
$sUrl = utils::GetAbsoluteUrlAppRoot();
$oPage->add('<div style="text-align:center">'.Dict::S('UI:DashboardEdit:Layout').'</div>');
$oPage->add('<div id="select_layout" style="text-align:center">');
foreach( get_declared_classes() as $sLayoutClass)
{
if (is_subclass_of($sLayoutClass, 'DashboardLayout'))
{
$oReflection = new ReflectionClass($sLayoutClass);
if (!$oReflection->isAbstract())
{
$aCallSpec = array($sLayoutClass, 'GetInfo');
$aInfo = call_user_func($aCallSpec);
$sChecked = ($this->sLayoutClass == $sLayoutClass) ? 'checked' : '';
$oPage->add('<input type="radio" name="layout_class" '.$sChecked.' value="'.$sLayoutClass.'" id="layout_'.$sLayoutClass.'"><label for="layout_'.$sLayoutClass.'"><img src="'.$sUrl.$aInfo['icon'].'" /></label>'); // title="" on either the img or the label does nothing !
}
}
}
$oPage->add('</div>');
$oForm = new DesignerForm();
$oField = new DesignerLongTextField('dashboard_title', Dict::S('UI:DashboardEdit:DashboardTitle'), $this->sTitle);
$oForm->AddField($oField);
$this->SetFormParams($oForm);
$oForm->RenderAsPropertySheet($oPage, false, ':itop-dashboard');
$oPage->add('</div>');
$oPage->add_ready_script(
<<<EOF
$('#select_layout').buttonset();
$('#select_layout input').click( function() {
var sLayoutClass = $(this).val();
$(':itop-dashboard').dashboard('option', {layout_class: sLayoutClass});
} );
$('#row_attr_dashboard_title').property_field('option', {parent_selector: ':itop-dashboard', auto_apply: false, 'do_apply': function() {
var sTitle = $('#attr_dashboard_title').val();
$(':itop-dashboard').dashboard('option', {title: sTitle});
return true;
}
});
EOF
);
}
public function RenderDashletsSelection($oPage)
{
// Toolbox/palette to drag and drop dashlets
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Dashlets').'</div>');
$sUrl = utils::GetAbsoluteUrlAppRoot();
$oPage->add('<div id="select_dashlet" style="text-align:center">');
foreach( get_declared_classes() as $sDashletClass)
{
if (is_subclass_of($sDashletClass, 'Dashlet'))
{
$oReflection = new ReflectionClass($sDashletClass);
if (!$oReflection->isAbstract())
{
$aCallSpec = array($sDashletClass, 'IsVisible');
$bVisible = call_user_func($aCallSpec);
if ($bVisible)
{
$aCallSpec = array($sDashletClass, 'GetInfo');
$aInfo = call_user_func($aCallSpec);
$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'});");
$oPage->add_ready_script("$('.layout_cell').droppable({accept:'.dashlet_icon', hoverClass:'dragHover'});");
}
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()
{
$iNewId = 0;
foreach($this->aCells as $aDashlets)
{
foreach($aDashlets as $oDashlet)
{
$iNewId = max($iNewId, (int)$oDashlet->GetID());
}
}
return $iNewId + 1;
}
abstract protected function SetFormParams($oForm);
}
class RuntimeDashboard extends Dashboard
{
protected $bCustomized;
public function __construct($sId)
{
parent::__construct($sId);
$this->bCustomized = false;
}
public function SetCustomFlag($bCustomized)
{
$this->bCustomized = $bCustomized;
}
protected function SetFormParams($oForm)
{
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property'));
}
public function Save()
{
$sXml = $this->ToXml();
$oUDSearch = new DBObjectSearch('UserDashboard');
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oUDSearch->AddCondition('menu_code', $this->sId, '=');
$oUDSet = new DBObjectSet($oUDSearch);
if ($oUDSet->Count() > 0)
{
// Assuming there is at most one couple {user, menu}!
$oUserDashboard = $oUDSet->Fetch();
$oUserDashboard->Set('contents', $sXml);
$oUserDashboard->DBUpdate();
}
else
{
// No such customized dasboard for the current user, let's create a new record
$oUserDashboard = new UserDashboard();
$oUserDashboard->Set('user_id', UserRights::GetUserId());
$oUserDashboard->Set('menu_code', $this->sId);
$oUserDashboard->Set('contents', $sXml);
$oUserDashboard->DBInsert();
}
}
public function Revert()
{
$oUDSearch = new DBObjectSearch('UserDashboard');
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oUDSearch->AddCondition('menu_code', $this->sId, '=');
$oUDSet = new DBObjectSet($oUDSearch);
if ($oUDSet->Count() > 0)
{
// Assuming there is at most one couple {user, menu}!
$oUserDashboard = $oUDSet->Fetch();
$oUserDashboard->DBDelete();
}
}
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
{
parent::Render($oPage, $bEditMode, $aExtraParams);
if (!$bEditMode)
{
$sEditMenu = "<td><span id=\"DashboardMenu\"><ul><li><img src=\"../images/edit.png\"><ul>";
$aActions = array();
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:Edit'), "return EditDashboard('{$this->sId}')");
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
if ($this->bCustomized)
{
$oRevert = new JSPopupMenuItem('UI:Dashboard:RevertConfirm', Dict::S('UI:Dashboard:Revert'),
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}'); else return false");
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
}
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions);
$sEditMenu .= $oPage->RenderPopupMenuItems($aActions);
$sEditMenu = addslashes($sEditMenu);
//$sEditBtn = addslashes('<div style="display: inline-block; height: 55px; width:200px;vertical-align:center;line-height:60px;text-align:left;"><button onclick="EditDashboard(\''.$this->sId.'\');">Edit This Page</button></div>');
$oPage->add_ready_script(
<<<EOF
$('#logOffBtn').parent().before('$sEditMenu');
$('#DashboardMenu>ul').popupmenu();
EOF
);
$oPage->add_script(
<<<EOF
function EditDashboard(sId)
{
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'dashboard_editor', id: sId},
function(data)
{
$('body').append(data);
}
);
return false;
}
function RevertDashboard(sId)
{
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'revert_dashboard', dashboard_id: sId},
function(data)
{
$('body').append(data);
}
);
return false;
}
EOF
);
}
}
public function RenderEditor($oPage)
{
$oPage->add('<div id="dashboard_editor">');
$oPage->add('<div class="ui-layout-center">');
$this->Render($oPage, true);
$oPage->add('</div>');
$oPage->add('<div class="ui-layout-east">');
$this->RenderProperties($oPage);
$this->RenderDashletsSelection($oPage);
$this->RenderDashletsProperties($oPage);
$oPage->add('</div>');
$oPage->add('<div id="event_bus"/>'); // For exchanging messages between the panes, same as in the designer
$oPage->add('</div>');
$sDialogTitle = Dict::S('UI:DashboardEdit:Title');
$sOkButtonLabel = Dict::S('UI:Button:Save');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$sId = addslashes($this->sId);
$sLayoutClass = addslashes($this->sLayoutClass);
$sTitle = addslashes($this->sTitle);
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
$sExitConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage'));
$sCancelConfirmationMessage = addslashes(Dict::S('UI:CancelConfirmationMessage'));
$sAutoApplyConfirmationMessage = addslashes(Dict::S('UI:AutoApplyConfirmationMessage'));
$oPage->add_ready_script(
<<<EOF
window.bLeavingOnUserAction = false;
$('#dashboard_editor').dialog({
height: $('body').height() - 50,
width: $('body').width() - 50,
modal: true,
title: '$sDialogTitle',
buttons: [
{ text: "$sOkButtonLabel", click: function() {
var oDashboard = $(':itop-dashboard').data('dashboard');
if (oDashboard.is_dirty())
{
if (!confirm('$sAutoApplyConfirmationMessage'))
{
return;
}
else
{
oDashboard.apply_changes();
}
}
window.bLeavingOnUserAction = true;
oDashboard.save();
} },
{ text: "$sCancelButtonLabel", click: function() {
var oDashboard = $(':itop-dashboard').data('dashboard');
if (oDashboard.is_modified())
{
if (!confirm('$sCancelConfirmationMessage'))
{
return;
}
}
window.bLeavingOnUserAction = true;
$(this).dialog( "close" );
$(this).remove();
} },
],
close: function() { $(this).remove(); }
});
$('#dashboard_editor .ui-layout-center').dashboard({
dashboard_id: '$sId', layout_class: '$sLayoutClass', title: '$sTitle',
submit_to: '$sUrl', submit_parameters: {operation: 'save_dashboard'},
render_to: '$sUrl', render_parameters: {operation: 'render_dashboard'},
new_dashlet_parameters: {operation: 'new_dashlet'}
});
$('#select_dashlet').droppable({
accept: '.dashlet',
drop: function(event, ui) {
$( this ).find( ".placeholder" ).remove();
var oDashlet = ui.draggable;
oDashlet.remove();
},
});
$('#event_bus').bind('dashlet-selected', function(event, data){
var sDashletId = data.dashlet_id;
var sPropId = 'dashlet_properties_'+sDashletId;
$('.dashlet_properties').each(function() {
var sId = $(this).attr('id');
var bShow = (sId == sPropId);
if (bShow)
{
$(this).show();
}
else
{
$(this).hide();
}
});
});
dashboard_prop_size = GetUserPreference('dashboard_prop_size', 350);
$('#dashboard_editor').layout({
east: {
minSize: 200,
size: dashboard_prop_size,
togglerLength_open: 0,
togglerLength_closed: 0,
onresize_end: function(name, elt, state, options, layout)
{
if (state.isSliding == false)
{
SetUserPreference('dashboard_prop_size', state.size, true);
}
},
}
});
window.onbeforeunload = function() {
if (!window.bLeavingOnUserAction)
{
var oDashboard = $(':itop-dashboard').data('dashboard');
if (oDashboard)
{
if (oDashboard.is_dirty())
{
return '$sExitConfirmationMessage';
}
if (oDashboard.is_modified())
{
return '$sExitConfirmationMessage';
}
}
}
// return nothing ! safer for IE
};
EOF
);
$oPage->add_ready_script("");
}
public static function GetDashletCreationForm($sOQL = null)
{
$oForm = new DesignerForm();
// Get the list of all 'dashboard' menus in which we can insert a dashlet
$aAllMenus = ApplicationMenu::ReflectionMenuNodes();
$aAllowedDashboards = array();
foreach($aAllMenus as $idx => $aMenu)
{
$oMenu = $aMenu['node'];
$sParentId = $aMenu['parent'];
if ($oMenu instanceof DashboardMenuNode)
{
$sMenuLabel = $oMenu->GetTitle();
$sParentLabel = Dict::S('Menu:'.$sParentId);
if ($sParentLabel != $sMenuLabel)
{
$aAllowedDashboards[$oMenu->GetMenuId()] = $sParentLabel.' - '.$sMenuLabel;
}
else
{
$aAllowedDashboards[$oMenu->GetMenuId()] = $sMenuLabel;
}
}
}
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->SetAllowedValues($aAllowedDashboards);
$oField->SetMandatory(true);
$oForm->AddField($oField);
// Get the list of possible dashlets that support a creation from
// an OQL
$aDashlets = array();
foreach(get_declared_classes() as $sDashletClass)
{
if (is_subclass_of($sDashletClass, 'Dashlet'))
{
$oReflection = new ReflectionClass($sDashletClass);
if (!$oReflection->isAbstract())
{
$aCallSpec = array($sDashletClass, 'CanCreateFromOQL');
$bShorcutMode = call_user_func($aCallSpec);
if ($bShorcutMode)
{
$aCallSpec = array($sDashletClass, 'GetInfo');
$aInfo = call_user_func($aCallSpec);
$aDashlets[$sDashletClass] = array('label' => $aInfo['label'], 'class' => $sDashletClass, 'icon' => $aInfo['icon']);
}
}
}
}
$oSelectorField = new DesignerFormSelectorField('dashlet_class', Dict::S('UI:DashletCreation:DashletType'), '');
$oForm->AddField($oSelectorField);
foreach($aDashlets as $sDashletClass => $aDashletInfo)
{
$oSubForm = new DesignerForm();
$oDashlet = new $sDashletClass(0);
$oDashlet->GetPropertiesFieldsFromOQL($oSubForm, $sOQL);
$oSelectorField->AddSubForm($oSubForm, $aDashletInfo['label'], $aDashletInfo['class']);
}
$oField = new DesignerBooleanField('open_editor', Dict::S('UI:DashletCreation:EditNow'), true);
$oForm->AddField($oField);
return $oForm;
}
public static function GetDashletCreationDlgFromOQL($oPage, $sOQL)
{
$oPage->add('<div id="dashlet_creation_dlg">');
$oForm = self::GetDashletCreationForm($sOQL);
$oForm->Render($oPage);
$oPage->add('</div>');
$sDialogTitle = Dict::S('UI:DashletCreation:Title');
$sOkButtonLabel = Dict::S('UI:Button:Ok');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$oPage->add_ready_script(
<<<EOF
$('#dashlet_creation_dlg').dialog({
width: 400,
modal: true,
title: '$sDialogTitle',
buttons: [
{ text: "$sOkButtonLabel", click: function() {
var oForm = $(this).find('form');
var sFormId = oForm.attr('id');
var oParams = null;
var aErrors = ValidateForm(sFormId, false);
if (aErrors.length == 0)
{
oParams = ReadFormParams(sFormId);
}
oParams.operation = 'add_dashlet';
var me = $(this);
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function(data) {
me.dialog( "close" );
me.remove();
$('body').append(data);
});
} },
{ text: "$sCancelButtonLabel", click: function() {
$(this).dialog( "close" ); $(this).remove();
} },
],
close: function() { $(this).remove(); }
});
EOF
);
}
}

View File

@@ -1,210 +0,0 @@
<?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/>
/**
* Dashboard presentation
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
abstract class DashboardLayout
{
public function __construct()
{
}
abstract public function Render($oPage, $aDashlets, $bEditMode = false);
static public function GetInfo()
{
return array(
'label' => '',
'icon' => '',
'description' => '',
);
}
}
abstract class DashboardLayoutMultiCol extends DashboardLayout
{
protected $iNbCols;
public function __construct()
{
$this->iNbCols = 1;
}
protected function TrimCell($aDashlets)
{
$aKeys = array_reverse(array_keys($aDashlets));
$idx = 0;
$bNoVisibleFound = true;
while($idx < count($aKeys) && $bNoVisibleFound)
{
$oDashlet = $aDashlets[$aKeys[$idx]];
if ($oDashlet->IsVisible())
{
$bNoVisibleFound = false;
}
else
{
unset($aDashlets[$aKeys[$idx]]);
}
$idx++;
}
return $aDashlets;
}
protected function TrimCellsArray($aCells)
{
foreach($aCells as $key => $aDashlets)
{
$aCells[$key] = $this->TrimCell($aDashlets);
}
$aKeys = array_reverse(array_keys($aCells));
$idx = 0;
$bNoVisibleFound = true;
while($idx < count($aKeys) && $bNoVisibleFound)
{
$aDashlets = $aCells[$aKeys[$idx]];
if (count($aDashlets) > 0)
{
$bNoVisibleFound = false;
}
else
{
unset($aCells[$aKeys[$idx]]);
}
$idx++;
}
return $aCells;
}
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
$aCells = $this->TrimCellsArray($aCells);
$oPage->add('<table style="width:100%"><tbody>');
$iCellIdx = 0;
$fColSize = 100 / $this->iNbCols;
$sStyle = $bEditMode ? 'style="border: 1px #ccc dashed; width:'.$fColSize.'%;" class="layout_cell edit_mode"' : 'style="width: '.$fColSize.'%;" class="dashboard"';
$iNbRows = ceil(count($aCells) / $this->iNbCols);
for($iRows = 0; $iRows < $iNbRows; $iRows++)
{
$oPage->add('<tr>');
for($iCols = 0; $iCols < $this->iNbCols; $iCols++)
{
$oPage->add("<td $sStyle>");
if (array_key_exists($iCellIdx, $aCells))
{
$aDashlets = $aCells[$iCellIdx];
if (count($aDashlets) > 0)
{
foreach($aDashlets as $oDashlet)
{
if ($oDashlet->IsVisible())
{
$oDashlet->DoRender($oPage, $bEditMode, true /* bEnclosingDiv */, $aExtraParams);
}
}
}
else
{
$oPage->add('&nbsp;');
}
}
else
{
$oPage->add('&nbsp;');
}
$oPage->add('</td>');
$iCellIdx++;
}
$oPage->add('</tr>');
}
if ($bEditMode) // Add one row for extensibility
{
$sStyle = 'style="border: 1px #ccc dashed; width:'.$fColSize.'%;" class="layout_cell edit_mode layout_extension"';
$oPage->add('<tr>');
for($iCols = 0; $iCols < $this->iNbCols; $iCols++)
{
$oPage->add("<td $sStyle>");
$oPage->add('&nbsp;');
$oPage->add('</td>');
}
$oPage->add('</tr>');
}
$oPage->add('</tbody></table>');
}
}
class DashboardLayoutOneCol extends DashboardLayoutMultiCol
{
public function __construct()
{
parent::__construct();
$this->iNbCols = 1;
}
static public function GetInfo()
{
return array(
'label' => 'One Column',
'icon' => 'images/layout_1col.png',
'description' => '',
);
}
}
class DashboardLayoutTwoCols extends DashboardLayoutMultiCol
{
public function __construct()
{
parent::__construct();
$this->iNbCols = 2;
}
static public function GetInfo()
{
return array(
'label' => 'Two Columns',
'icon' => 'images/layout_2col.png',
'description' => '',
);
}
}
class DashboardLayoutThreeCols extends DashboardLayoutMultiCol
{
public function __construct()
{
parent::__construct();
$this->iNbCols = 3;
}
static public function GetInfo()
{
return array(
'label' => 'Two Columns',
'icon' => 'images/layout_3col.png',
'description' => '',
);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,875 +0,0 @@
<?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/>
/**
* Data Table to display a set of objects in a tabular manner in HTML
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class DataTable
{
protected $iListId; // Unique ID inside the web page
protected $sTableId; // identifier for saving the settings (combined with the class aliases)
protected $oSet; // The set of objects to display
protected $aClassAliases; // The aliases (alias => class) inside the set
protected $iNbObjects; // Total number of objects inthe set
protected $bUseCustomSettings; // Whether or not the current display uses custom settings
protected $oDefaultSettings; // the default settings for displaying such a list
/**
* @param $iListId mixed Unique ID for this div/table in the page
* @param $oSet DBObjectSet The set of data to display
* @param $aClassAliases Hash The list of classes/aliases to be displayed in this set $sAlias => $sClassName
* @param $sTableId mixed A string (or null) identifying this table in order to persist its settings
*/
public function __construct($iListId, $oSet, $aClassAliases, $sTableId = null)
{
$this->iListId = utils::GetSafeId($iListId); // Make a "safe" ID for jQuery
$this->oSet = $oSet;
$this->aClassAliases = $aClassAliases;
$this->sTableId = $sTableId;
$this->iNbObjects = $oSet->Count();
$this->bUseCustomSettings = false;
$this->oDefaultSettings = null;
}
public function Display(WebPage $oPage, DataTableSettings $oSettings, $bActionsMenu, $sSelectMode, $bViewLink, $aExtraParams)
{
$this->oDefaultSettings = $oSettings;
// Identified tables can have their own specific settings
$oCustomSettings = DataTableSettings::GetTableSettings($this->aClassAliases, $this->sTableId);
if ($oCustomSettings != null)
{
// Custom settings overload the default ones
$this->bUseCustomSettings = true;
if ($this->oDefaultSettings->iDefaultPageSize == 0)
{
$oCustomSettings->iDefaultPageSize = 0;
}
}
else
{
$oCustomSettings = $oSettings;
}
if ($oCustomSettings->iDefaultPageSize > 0)
{
$this->oSet->SetLimit($oCustomSettings->iDefaultPageSize);
}
$this->oSet->SetOrderBy($oCustomSettings->GetSortOrder());
$bToolkitMenu = true;
if (isset($aExtraParams['toolkit_menu']))
{
$bToolkitMenu = (bool) $aExtraParams['toolkit_menu'];
}
if (UserRights::IsPortalUser())
{
// Portal users have a limited access to data, for now they can only see what's configured for them
$bToolkitMenu = false;
}
return $this->GetAsHTML($oPage, $oCustomSettings->iDefaultPageSize, $oCustomSettings->iDefaultPageSize, 0, $oCustomSettings->aColumns, $bActionsMenu, $bToolkitMenu, $sSelectMode, $bViewLink, $aExtraParams);
}
public function GetAsHTML(WebPage $oPage, $iPageSize, $iDefaultPageSize, $iPageIndex, $aColumns, $bActionsMenu, $bToolkitMenu, $sSelectMode, $bViewLink, $aExtraParams)
{
$sObjectsCount = $this->GetObjectCount($oPage, $sSelectMode);
$sPager = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
$sActionsMenu = '';
$sToolkitMenu = '';
if ($bActionsMenu)
{
$sActionsMenu = $this->GetActionsMenu($oPage, $aExtraParams);
}
if ($bToolkitMenu)
{
$sToolkitMenu = $this->GetToolkitMenu($oPage, $aExtraParams);
}
$sDataTable = $this->GetHTMLTable($oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
$sConfigDlg = $this->GetTableConfigDlg($oPage, $aColumns, $bViewLink, $iDefaultPageSize);
$sHtml = "<table id=\"datatable_{$this->iListId}\" class=\"datatable\">";
$sHtml .= "<tr><td>";
$sHtml .= "<table style=\"width:100%;\">";
$sHtml .= "<tr><td class=\"pagination_container\">$sObjectsCount</td><td class=\"menucontainer\">$sToolkitMenu $sActionsMenu</td></tr>";
$sHtml .= "<tr>$sPager</tr>";
$sHtml .= "</table>";
$sHtml .= "</td></tr>";
$sHtml .= "<tr><td class=\"datacontents\">$sDataTable</td></tr>";
$sHtml .= "</table>\n";
$oPage->add_at_the_end($sConfigDlg);
$aOptions = array(
'sPersistentId' => '',
'sFilter' => $this->oSet->GetFilter()->serialize(),
'oColumns' => $aColumns,
'sSelectMode' => $sSelectMode,
'sViewLink' => ($bViewLink ? 'true' : 'false'),
'iNbObjects' => $this->iNbObjects,
'iDefaultPageSize' => $iDefaultPageSize,
'iPageSize' => $iPageSize,
'iPageIndex' => $iPageIndex,
'oClassAliases' => $this->aClassAliases,
'sTableId' => $this->sTableId,
'oExtraParams' => $aExtraParams,
'sRenderUrl' => utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php',
'oRenderParameters' => array('str' => ''), // Forces JSON to encode this as a object...
'oDefaultSettings' => array('str' => ''), // Forces JSON to encode this as a object...
'oLabels' => array('moveup' => Dict::S('UI:Button:MoveUp'), 'movedown' => Dict::S('UI:Button:MoveDown')),
);
if($this->oDefaultSettings != null)
{
$aOptions['oDefaultSettings'] = $this->GetAsHash($this->oDefaultSettings);
}
$sJSOptions = json_encode($aOptions);
$oPage->add_ready_script("$('#datatable_{$this->iListId}').datatable($sJSOptions);");
return $sHtml;
}
/**
* When refreshing the body of a paginated table, get the rows of the table (inside the TBODY)
* return string The HTML rows to insert inside the <tbody> node
*/
public function GetAsHTMLTableRows(WebPage $oPage, $iPageSize, $aColumns, $sSelectMode, $bViewLink, $aExtraParams)
{
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
$sHtml = '';
foreach($aValues as $aRow)
{
$sHtml .= $oPage->GetTableRow($aRow, $aAttribs);
}
return $sHtml;
}
protected function GetObjectCount(WebPage $oPage, $sSelectMode)
{
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
{
$sHtml = '<div class="pagination_objcount">'.Dict::Format('UI:Pagination:HeaderSelection', '<span id="total">'.$this->iNbObjects.'</span>', '<span class="selectedCount">0</span>').'</div>';
}
else
{
$sHtml = '<div class="pagination_objcount">'.Dict::Format('UI:Pagination:HeaderNoSelection', '<span id="total">'.$this->iNbObjects.'</span>').'</div>';
}
return $sHtml;
}
protected function GetPager(WebPage $oPage, $iPageSize, $iDefaultPageSize, $iPageIndex)
{
$sHtml = '';
if ($iPageSize < 1) // Display all
{
$sPagerStyle = 'style="display:none"'; // no limit: display the full table, so hide the "pager" UI
// WARNING: mPDF does not take the "display" style into account
// when applied to a <td> or a <table> tag, so make sure you apply this to a div
}
else
{
$sPagerStyle = '';
}
$sCombo = '<select class="pagesize">';
for($iPage = 1; $iPage < 5; $iPage++)
{
$iNbItems = $iPage * $iDefaultPageSize;
$sSelected = ($iNbItems == $iPageSize) ? 'selected="selected"' : '';
$sCombo .= "<option $sSelected value=\"$iNbItems\">$iNbItems</option>";
}
$sSelected = ($iPageSize < 1) ? 'selected="selected"' : '';
$sCombo .= "<option $sSelected value=\"-1\">".Dict::S('UI:Pagination:All')."</option>";
$sCombo .= '</select>';
$sPages = Dict::S('UI:Pagination:PagesLabel');
$sPageSizeCombo = Dict::Format('UI:Pagination:PageSize', $sCombo);
$iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize);
if ($iNbPages == 1)
{
// No need to display the pager
$sPagerStyle = 'style="display:none"';
}
$aPagesToDisplay = array();
for($idx = 0; $idx <= min(4, $iNbPages-1); $idx++)
{
if ($idx == 0)
{
$aPagesToDisplay[$idx] = '<span page="0" class="curr_page">1</span>';
}
else
{
$aPagesToDisplay[$idx] = "<span id=\"gotopage_$idx\" class=\"gotopage\" page=\"$idx\">".(1+$idx)."</span>";
}
}
$iLastPageIdx = $iNbPages - 1;
if (!isset($aPagesToDisplay[$iLastPageIdx]))
{
unset($aPagesToDisplay[$idx - 1]); // remove the last page added to make room for the very last page
$aPagesToDisplay[$iLastPageIdx] = "<span id=\"gotopage_$iLastPageIdx\" class=\"gotopage\" page=\"$iLastPageIdx\">... $iNbPages</span>";
}
$sPagesLinks = implode('', $aPagesToDisplay);
$sPagesList = '['.implode(',', array_keys($aPagesToDisplay)).']';
$sSelectionMode = ($iNbPages == 1) ? '' : 'positive';
$sHtml =
<<<EOF
<td colspan="2">
<div $sPagerStyle>
<table id="pager{$this->iListId}" class="pager"><tr>
<td>$sPages</td>
<td><img src="../images/first.png" class="first"/></td>
<td><img src="../images/prev.png" class="prev"/></td>
<td><span id="index">$sPagesLinks</span></td>
<td><img src="../images/next.png" class="next"/></td>
<td><img src="../images/last.png" class="last"/></td>
<td>$sPageSizeCombo</td>
<td><span id="loading">&nbsp;</span><input type="hidden" name="selectionMode" value="$sSelectionMode"></input>
</td>
</tr>
</table>
</div>
</td>
EOF;
return $sHtml;
}
protected function GetActionsMenu(WebPage $oPage, $aExtraParams)
{
$oMenuBlock = new MenuBlock($this->oSet->GetFilter(), 'list');
$sHtml = $oMenuBlock->GetRenderContent($oPage, $aExtraParams, $this->iListId);
return $sHtml;
}
protected function GetToolkitMenu(WebPage $oPage, $aExtraParams)
{
$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>';
$oMenuItem1 = new JSPopupMenuItem('iTop::ConfigureList', $sMenuTitle, "$('#datatable_dlg_".$this->iListId."').dialog('open');");
$aActions = array(
$oMenuItem1->GetUID() => $oMenuItem1->GetMenuItem(),
);
$this->oSet->Rewind();
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_OBJLIST_TOOLKIT, $this->oSet, $aActions);
$this->oSet->Rewind();
$sHtml .= $oPage->RenderPopupMenuItems($aActions);
return $sHtml;
}
protected function GetTableConfigDlg(WebPage $oPage, $aColumns, $bViewLink, $iDefaultPageSize)
{
$sHtml = "<div id=\"datatable_dlg_{$this->iListId}\" style=\"display: none;\">";
$sHtml .= "<form onsubmit=\"return false\">";
$sChecked = ($this->bUseCustomSettings) ? '' : 'checked';
$sHtml .= "<p><input id=\"dtbl_dlg_settings_{$this->iListId}\" type=\"radio\" name=\"settings\" $sChecked value=\"defaults\"><label for=\"dtbl_dlg_settings_{$this->iListId}\">&nbsp;".Dict::S('UI:UseDefaultSettings').'</label></p>';
$sHtml .= "<fieldset>";
$sChecked = ($this->bUseCustomSettings) ? 'checked': '';
$sHtml .= "<legend class=\"transparent\"><input id=\"dtbl_dlg_specific_{$this->iListId}\" type=\"radio\" class=\"specific_settings\" name=\"settings\" $sChecked value=\"specific\"><label for=\"dtbl_dlg_specific_{$this->iListId}\">&nbsp;".Dict::S('UI:UseSpecificSettings')."</label></legend>";
$sHtml .= Dict::S('UI:ColumnsAndSortOrder').'<br/><ul class="sortable_field_list" id="sfl_'.$this->iListId.'"></ul>';
$sHtml .= '<p>'.Dict::Format('UI:Display_X_ItemsPerPage', '<input type="text" size="4" name="page_size" value="'.$iDefaultPageSize.'">').'</p>';
$sHtml .= "</fieldset>";
$sHtml .= "<fieldset>";
$sSaveChecked = ($this->sTableId != null) ? 'checked' : '';
$sCustomDisabled = ($this->sTableId == null) ? 'disabled="disabled" stay-disabled="true" ' : '';
$sCustomChecked = ($this->sTableId != null) ? 'checked' : '';
$sGenericChecked = ($this->sTableId == null) ? 'checked' : '';
$sHtml .= "<legend class=\"transparent\"><input id=\"dtbl_dlg_save_{$this->iListId}\" type=\"checkbox\" $sSaveChecked name=\"save_settings\"><label for=\"dtbl_dlg_save_{$this->iListId}\">&nbsp;".Dict::S('UI:UseSavetheSettings')."</label></legend>";
$sHtml .= "<p><input id=\"dtbl_dlg_this_list_{$this->iListId}\" type=\"radio\" name=\"scope\" $sCustomChecked $sCustomDisabled value=\"this_list\"><label for=\"dtbl_dlg_this_list_{$this->iListId}\">&nbsp;".Dict::S('UI:OnlyForThisList').'</label>&nbsp;&nbsp;&nbsp;&nbsp;';
$sHtml .= "<input id=\"dtbl_dlg_all_{$this->iListId}\" type=\"radio\" name=\"scope\" $sGenericChecked value=\"defaults\"><label for=\"dtbl_dlg_all_{$this->iListId}\">&nbsp;".Dict::S('UI:ForAllLists').'</label></p>';
$sHtml .= "</fieldset>";
$sHtml .= '<table style="width:100%"><tr><td style="text-align:center;">';
$sHtml .= '<button type="button" onclick="$(\'#datatable_'.$this->iListId.'\').datatable(\'onDlgCancel\'); $(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'close\')">'.Dict::S('UI:Button:Cancel').'</button>';
$sHtml .= '</td><td style="text-align:center;">';
$sHtml .= '<button type="submit" onclick="$(\'#datatable_'.$this->iListId.'\').datatable(\'onDlgOk\');$(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'close\');">'.Dict::S('UI:Button:Ok').'</button>';
$sHtml .= '</td></tr></table>';
$sHtml .= "</form>";
$sHtml .= "</div>";
$sDlgTitle = addslashes(Dict::S('UI:ListConfigurationTitle'));
$oPage->add_ready_script("$('#datatable_dlg_{$this->iListId}').dialog({autoOpen: false, title: '$sDlgTitle', width: 500, close: function() { $('#datatable_{$this->iListId}').datatable('onDlgCancel'); } });");
return $sHtml;
}
public function GetAsHash($oSetting)
{
$aSettings = array('iDefaultPageSize' => $oSetting->iDefaultPageSize, 'oColumns' => $oSetting->aColumns);
return $aSettings;
}
protected function GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink)
{
$aAttribs = array();
if ($sSelectMode == 'multiple')
{
$aAttribs['form::select'] = array('label' => "<input type=\"checkbox\" onClick=\"CheckAll('.selectList{$this->iListId}:not(:disabled)', this.checked);\" class=\"checkAll\"></input>", 'description' => Dict::S('UI:SelectAllToggle+'));
}
else if ($sSelectMode == 'single')
{
$aAttribs['form::select'] = array('label' => "", 'description' => '');
}
foreach($this->aClassAliases as $sAlias => $sClassName)
{
foreach($aColumns[$sAlias] as $sAttCode => $aData)
{
if ($aData['checked'])
{
if ($sAttCode == '_key_')
{
$aAttribs['key_'.$sAlias] = array('label' => MetaModel::GetName($sClassName), 'description' => '');
}
else
{
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCode);
$aAttribs[$sAttCode.'_'.$sAlias] = array('label' => MetaModel::GetLabel($sClassName, $sAttCode), 'description' => $oAttDef->GetOrderByHint());
}
}
}
}
return $aAttribs;
}
protected function GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
{
$bLocalize = true;
if (isset($aExtraParams['localize_values']))
{
$bLocalize = (bool) $aExtraParams['localize_values'];
}
$aValues = array();
$this->oSet->Seek(0);
$iMaxObjects = $iPageSize;
while (($aObjects = $this->oSet->FetchAssoc()) && ($iMaxObjects != 0))
{
$bFirstObject = true;
$aRow = array();
foreach($this->aClassAliases as $sAlias => $sClassName)
{
if (is_object($aObjects[$sAlias]))
{
$sHilightClass = $aObjects[$sAlias]->GetHilightClass();
if ($sHilightClass != '')
{
$aRow['@class'] = $sHilightClass;
}
if ((($sSelectMode == 'single') || ($sSelectMode == 'multiple')) && $bFirstObject)
{
if (array_key_exists('selection_enabled', $aExtraParams) && isset($aExtraParams['selection_enabled'][$aObjects[$sAlias]->GetKey()]))
{
$sDisabled = ($aExtraParams['selection_enabled'][$aObjects[$sAlias]->GetKey()]) ? '' : ' disabled="disabled"';
}
else
{
$sDisabled = '';
}
if ($sSelectMode == 'single')
{
$aRow['form::select'] = "<input type=\"radio\" $sDisabled class=\"selectList{$this->iListId}\" name=\"selectObject\" value=\"".$aObjects[$sAlias]->GetKey()."\"></input>";
}
else
{
$aRow['form::select'] = "<input type=\"checkBox\" $sDisabled class=\"selectList{$this->iListId}\" name=\"selectObject[]\" value=\"".$aObjects[$sAlias]->GetKey()."\"></input>";
}
}
foreach($aColumns[$sAlias] as $sAttCode => $aData)
{
if ($aData['checked'])
{
if ($sAttCode == '_key_')
{
$aRow['key_'.$sAlias] = $aObjects[$sAlias]->GetHyperLink();
}
else
{
$aRow[$sAttCode.'_'.$sAlias] = $aObjects[$sAlias]->GetAsHTML($sAttCode, $bLocalize);
}
}
}
}
else
{
foreach($aColumns[$sAlias] as $sAttCode => $aData)
{
if ($aData['checked'])
{
if ($sAttCode == '_key_')
{
$aRow['key_'.$sAlias] = '';
}
else
{
$aRow[$sAttCode.'_'.$sAlias] = '';
}
}
}
}
$bFirstObject = false;
}
$aValues[] = $aRow;
$iMaxObjects--;
}
return $aValues;
}
public function GetHTMLTable(WebPage $oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
{
$iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize);
if ($iPageSize < 1)
{
$iPageSize = -1; // convention: no pagination
}
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
$sHtml = '<table class="listContainer">';
foreach($this->oSet->GetFilter()->GetInternalParams() as $sName => $sValue)
{
$aExtraParams['query_params'][$sName] = $sValue;
}
$sHtml .= "<tr><td>";
$sHtml .= $oPage->GetTable($aAttribs, $aValues);
$sHtml .= '</td></tr>';
$sHtml .= '</table>';
$iCount = $this->iNbObjects;
$aArgs = $this->oSet->GetArgs();
$sExtraParams = addslashes(str_replace('"', "'", json_encode(array_merge($aExtraParams, $aArgs)))); // JSON encode, change the style of the quotes and escape them
$sSelectModeJS = '';
$sHeaders = '';
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
{
$sSelectModeJS = $sSelectMode;
$sHeaders = 'headers: { 0: {sorter: false}},';
}
$sDisplayKey = ($bViewLink) ? 'true' : 'false';
// Protect against duplicate elements in the Zlist
$aUniqueOrderedList = array();
foreach($this->aClassAliases as $sAlias => $sClassName)
{
foreach($aColumns[$sAlias] as $sAttCode => $aData)
{
if ($aData['checked'])
{
$aUniqueOrderedList[$sAttCode] = true;
}
}
}
$aUniqueOrderedList = array_keys($aUniqueOrderedList);
$sJSColumns = json_encode($aColumns);
$sJSClassAliases = json_encode($this->aClassAliases);
$sCssCount = isset($aExtraParams['cssCount']) ? ", cssCount: '{$aExtraParams['cssCount']}'" : '';
$this->oSet->ApplyParameters();
// Display the actual sort order of the table
$aRealSortOrder = $this->oSet->GetRealSortOrder();
$aDefaultSort = array();
$iColOffset = 0;
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
{
$iColOffset += 1;
}
if ($bViewLink)
{
// $iColOffset += 1;
}
foreach($aRealSortOrder as $sColCode => $bAscending)
{
$iPos = array_search($sColCode, $aUniqueOrderedList);
if ($iPos !== false)
{
$aDefaultSort[] = "[".($iColOffset+$iPos).",".($bAscending ? '0' : '1')."]";
}
else if (($iPos = array_search(preg_replace('/_friendlyname$/', '', $sColCode), $aUniqueOrderedList)) !== false)
{
// if sorted on the friendly name of an external key, then consider it sorted on the column that shows the links
$aDefaultSort[] = "[".($iColOffset+$iPos).",".($bAscending ? '0' : '1')."]";
}
else if($sColCode == 'friendlyname' && $bViewLink)
{
$aDefaultSort[] = "[".($iColOffset).",".($bAscending ? '0' : '1')."]";
}
}
$sFakeSortList = '';
if (count($aDefaultSort) > 0)
{
$sFakeSortList = '['.implode(',', $aDefaultSort).']';
}
$sOQL = addslashes($this->oSet->GetFilter()->serialize());
$oPage->add_ready_script(
<<<EOF
var oTable = $('#{$this->iListId} table.listResults');
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
);
if ($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;
}
public function UpdatePager(WebPage $oPage, $iDefaultPageSize, $iStart)
{
$iPageSize = ($iDefaultPageSize < 1) ? 1 : $iDefaultPageSize;
$iPageIndex = 1 + floor($iStart / $iPageSize);
$sHtml = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
$oPage->add_ready_script("$('#pager{$this->iListId}').html('".str_replace("\n", ' ', addslashes($sHtml))."');");
if ($iDefaultPageSize < 1)
{
$oPage->add_ready_script("$('#pager{$this->iListId}').parent().hide()");
}
else
{
$oPage->add_ready_script("$('#pager{$this->iListId}').parent().show()");
}
}
}
class DataTableSettings implements Serializable
{
public $aClassAliases;
public $sTableId;
public $iDefaultPageSize;
public $aColumns;
public function __construct($aClassAliases, $sTableId = null)
{
$this->aClassAliases = $aClassAliases;
$this->sTableId = $sTableId;
$this->iDefaultPageSize = 10;
$this->aColumns = array();
}
protected function Init($iDefaultPageSize, $aSortOrder, $aColumns)
{
$this->iDefaultPageSize = $iDefaultPageSize;
$this->aColumns = $aColumns;
$this->FixVisibleColumns();
}
public function serialize()
{
// Save only the 'visible' columns
$aColumns = array();
foreach($this->aClassAliases as $sAlias => $sClass)
{
$aColumns[$sAlias] = array();
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
{
unset($aData['label']); // Don't save the display name
unset($aData['alias']); // Don't save the alias (redundant)
unset($aData['code']); // Don't save the code (redundant)
if ($aData['checked'])
{
$aColumns[$sAlias][$sAttCode] = $aData;
}
}
}
return serialize(
array(
'iDefaultPageSize' => $this->iDefaultPageSize,
'aColumns' => $aColumns,
)
);
}
public function unserialize($sData)
{
$aData = unserialize($sData);
$this->iDefaultPageSize = $aData['iDefaultPageSize'];
$this->aColumns = $aData['aColumns'];
foreach($this->aClassAliases as $sAlias => $sClass)
{
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
{
$aFieldData = false;
if ($sAttCode == '_key_')
{
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, null, true /* bChecked */, $aData['sort']);
}
else if (MetaModel::isValidAttCode($sClass, $sAttCode))
{
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, true /* bChecked */, $aData['sort']);
}
if ($aFieldData)
{
$this->aColumns[$sAlias][$sAttCode] = $aFieldData;
}
else
{
unset($this->aColumns[$sAlias][$sAttCode]);
}
}
}
$this->FixVisibleColumns();
}
static public function GetDataModelSettings($aClassAliases, $bViewLink, $aDefaultLists)
{
$oSettings = new DataTableSettings($aClassAliases);
// Retrieve the class specific settings for each class/alias based on the 'list' ZList
//TODO let the caller pass some other default settings (another Zlist, extre fields...)
$aColumns = array();
foreach($aClassAliases as $sAlias => $sClass)
{
if ($aDefaultLists == null)
{
$aList = cmdbAbstract::FlattenZList(MetaModel::GetZListItems($sClass, 'list'));
}
else
{
$aList = $aDefaultLists[$sAlias];
}
$aSortOrder = MetaModel::GetOrderByDefault($sClass);
if ($bViewLink)
{
$sSort = 'none';
if(array_key_exists('friendlyname', $aSortOrder))
{
$sSort = $aSortOrder['friendlyname'] ? 'asc' : 'desc';
}
$aColumns[$sAlias]['_key_'] = $oSettings->GetFieldData($sAlias, '_key_', null, true /* bChecked */, $sSort);
}
foreach($aList as $sAttCode)
{
$sSort = 'none';
if(array_key_exists($sAttCode, $aSortOrder))
{
$sSort = $aSortOrder[$sAttCode] ? 'asc' : 'desc';
}
$oAttDef = Metamodel::GetAttributeDef($sClass, $sAttCode);
$aFieldData = $oSettings->GetFieldData($sAlias, $sAttCode, $oAttDef, true /* bChecked */, $sSort);
if ($aFieldData) $aColumns[$sAlias][$sAttCode] = $aFieldData;
}
}
$iDefaultPageSize = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit());
$oSettings->Init($iDefaultPageSize, $aSortOrder, $aColumns);
return $oSettings;
}
protected function FixVisibleColumns()
{
foreach($this->aClassAliases as $sAlias => $sClass)
{
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
{
// Remove non-existent columns
// TODO: check if the existing ones are still valid (in case their type changed)
if (($sAttCode != '_key_') && (!MetaModel::IsValidAttCode($sClass, $sAttCode)))
{
unset($this->aColumns[$sAlias][$sAttCode]);
}
}
$aList = MetaModel::ListAttributeDefs($sClass);
// Add the other (non visible ones), sorted in alphabetical order
$aTempData = array();
foreach($aList as $sAttCode => $oAttDef)
{
if ( (!array_key_exists($sAttCode, $this->aColumns[$sAlias])) && (!$oAttDef instanceof AttributeLinkSet))
{
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, false /* bChecked */, 'none');
if ($aFieldData) $aTempData[$aFieldData['label']] = $aFieldData;
}
}
ksort($aTempData);
foreach($aTempData as $sLabel => $aFieldData)
{
$this->aColumns[$sAlias][$aFieldData['code']] = $aFieldData;
}
}
}
static public function GetTableSettings($aClassAliases, $sTableId = null)
{
$pref = null;
$oSettings = new DataTableSettings($aClassAliases, $sTableId);
if ($sTableId != null)
{
// An identified table, let's fetch its own settings (if any)
$pref = appUserPreferences::GetPref($oSettings->GetPrefsKey($sTableId), null);
}
if ($pref == null)
{
// Try the global preferred values for this class / set of classes
$pref = appUserPreferences::GetPref($oSettings->GetPrefsKey(null), null);
if ($pref == null)
{
// no such settings, use the default values provided by the data model
return null;
}
}
$oSettings->unserialize($pref);
return $oSettings;
}
public function GetSortOrder()
{
$aSortOrder = array();
foreach($this->aColumns as $sAlias => $aColumns)
{
foreach($aColumns as $aColumn)
{
if ($aColumn['sort'] != 'none')
{
$sCode = ($aColumn['code'] == '_key_') ? 'friendlyname' : $aColumn['code'];
$aSortOrder[$sCode] = ($aColumn['sort']=='asc'); // true for ascending, false for descending
}
}
break; // TODO: For now the Set object supports only sorting on the first class of the set
}
return $aSortOrder;
}
public function Save()
{
if ($this->sTableId == null) return false; // Cannot save, the table is not identified, use SaveAsDefault instead
$sSettings = $this->serialize();
appUserPreferences::SetPref($this->GetPrefsKey($this->sTableId), $sSettings);
return true;
}
public function SaveAsDefault()
{
$sSettings = $this->serialize();
appUserPreferences::SetPref($this->GetPrefsKey(null), $sSettings);
return true;
}
/**
* Clear the preferences for this particular table
* @param $bResetAll boolean If true,the settings for all tables of the same class(es)/alias(es) are reset
*/
public function ResetToDefault($bResetAll)
{
if (($this->sTableId == null) && (!$bResetAll)) return false; // Cannot reset, the table is not identified, use force $bResetAll instead
if ($bResetAll)
{
// Turn the key into a suitable PCRE pattern
$sKey = $this->GetPrefsKey(null);
$sPattern = str_replace(array('|'), array('\\|'), $sKey); // escape the | character
$sPattern = '#^'.str_replace(array('*'), array('.*'), $sPattern).'$#'; // Don't use slash as the delimiter since it's used in our key to delimit aliases
appUserPreferences::UnsetPref($sPattern, true);
}
else
{
appUserPreferences::UnsetPref($this->GetPrefsKey($this->sTableId), false);
}
return true;
}
protected function GetPrefsKey($sTableId = null)
{
if ($sTableId == null) $sTableId = '*';
$aKeys = array();
foreach($this->aClassAliases as $sAlias => $sClass)
{
$aKeys[] = $sAlias.'-'.$sClass;
}
return implode('/', $aKeys).'|'.$sTableId;
}
protected function GetFieldData($sAlias, $sAttCode, $oAttDef, $bChecked, $sSort)
{
$ret = false;
if ($sAttCode == '_key_')
{
$sLabel = Dict::Format('UI:ExtKey_AsLink', MetaModel::GetName($this->aClassAliases[$sAlias]));
$ret = array(
'label' => $sLabel,
'checked' => true,
'disabled' => true,
'alias' => $sAlias,
'code' => $sAttCode,
'sort' => $sSort,
);
}
else if (!$oAttDef->IsLinkSet())
{
$sLabel = $oAttDef->GetLabel();
if ($oAttDef->IsExternalKey())
{
$sLabel = Dict::Format('UI:ExtKey_AsLink', $oAttDef->GetLabel());
}
else if ($oAttDef->IsExternalField())
{
$oExtAttDef = $oAttDef->GetExtAttDef();
$sLabel = Dict::Format('UI:ExtField_AsRemoteField', $oAttDef->GetLabel(), $oExtAttDef->GetLabel());
}
elseif ($oAttDef instanceof AttributeFriendlyName)
{
$sLabel = Dict::Format('UI:ExtKey_AsFriendlyName', $oAttDef->GetLabel());
}
$ret = array(
'label' => $sLabel,
'checked' => $bChecked,
'disabled' => false,
'alias' => $sAlias,
'code' => $sAttCode,
'sort' => $sSort,
);
}
return $ret;
}
}

View File

@@ -1,26 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* DisplayBlock and derived class * DisplayBlock and derived class
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT.'/application/webpage.class.inc.php'); require_once(APPROOT.'/application/webpage.class.inc.php');
@@ -44,7 +44,6 @@ class DisplayBlock
{ {
const TAG_BLOCK = 'itopblock'; const TAG_BLOCK = 'itopblock';
protected $m_oFilter; protected $m_oFilter;
protected $m_aConditions; // Conditions added to the filter -> avoid duplicate conditions
protected $m_sStyle; protected $m_sStyle;
protected $m_bAsynchronous; protected $m_bAsynchronous;
protected $m_aParams; protected $m_aParams;
@@ -52,18 +51,12 @@ class DisplayBlock
public function __construct(DBObjectSearch $oFilter, $sStyle = 'list', $bAsynchronous = false, $aParams = array(), $oSet = null) public function __construct(DBObjectSearch $oFilter, $sStyle = 'list', $bAsynchronous = false, $aParams = array(), $oSet = null)
{ {
$this->m_oFilter = $oFilter->DeepClone(); $this->m_oFilter = $oFilter;
$this->m_aConditions = array();
$this->m_sStyle = $sStyle; $this->m_sStyle = $sStyle;
$this->m_bAsynchronous = $bAsynchronous; $this->m_bAsynchronous = $bAsynchronous;
$this->m_aParams = $aParams; $this->m_aParams = $aParams;
$this->m_oSet = $oSet; $this->m_oSet = $oSet;
} }
public function GetFilter()
{
return $this->m_oFilter;
}
/** /**
* Constructs a DisplayBlock object from a DBObjectSet already in memory * Constructs a DisplayBlock object from a DBObjectSet already in memory
* @param $oSet DBObjectSet * @param $oSet DBObjectSet
@@ -259,7 +252,7 @@ class DisplayBlock
public function RenderContent(WebPage $oPage, $aExtraParams = array()) public function RenderContent(WebPage $oPage, $aExtraParams = array())
{ {
if (!isset($aExtraParams['currentId'])) if (empty($aExtraParams['currentId']))
{ {
$sId = $oPage->GetUniqueId(); // Works only if the page is not an Ajax one ! $sId = $oPage->GetUniqueId(); // Works only if the page is not an Ajax one !
} }
@@ -288,66 +281,37 @@ class DisplayBlock
$sClass = $this->m_oFilter->GetClass(); $sClass = $this->m_oFilter->GetClass();
$aFilterCodes = array_keys(MetaModel::GetClassFilterDefs($sClass)); $aFilterCodes = array_keys(MetaModel::GetClassFilterDefs($sClass));
$aCallSpec = array($sClass, 'MapContextParam'); $aCallSpec = array($sClass, 'MapContextParam');
if (is_callable($aCallSpec)) foreach($oAppContext->GetNames() as $sContextParam)
{ {
foreach($oAppContext->GetNames() as $sContextParam) $sParamCode = call_user_func($aCallSpec, $sContextParam); //Map context parameter to the value/filter code depending on the class
if (!is_null($sParamCode))
{ {
$sParamCode = call_user_func($aCallSpec, $sContextParam); //Map context parameter to the value/filter code depending on the class $sParamValue = $oAppContext->GetCurrentValue($sContextParam, null);
if (!is_null($sParamCode)) if (!is_null($sParamValue))
{ {
$sParamValue = $oAppContext->GetCurrentValue($sContextParam, null); $aExtraParams[$sParamCode] = $sParamValue;
if (!is_null($sParamValue))
{
$aExtraParams[$sParamCode] = $sParamValue;
}
} }
} }
} }
foreach($aFilterCodes as $sFilterCode) foreach($aFilterCodes as $sFilterCode)
{ {
$externalFilterValue = utils::ReadParam($sFilterCode, '', false, 'raw_data'); $sExternalFilterValue = utils::ReadParam($sFilterCode, '', false, 'raw_data');
$condition = null; $condition = null;
if (isset($aExtraParams[$sFilterCode])) if (isset($aExtraParams[$sFilterCode]))
{ {
$condition = $aExtraParams[$sFilterCode]; $condition = $aExtraParams[$sFilterCode];
} }
if ($bDoSearch && $externalFilterValue != "") // else if ($bDoSearch && $sExternalFilterValue != "")
if ($bDoSearch && $sExternalFilterValue != "")
{ {
// Search takes precedence over context params... // Search takes precedence over context params...
unset($aExtraParams[$sFilterCode]); unset($aExtraParams[$sFilterCode]);
if (!is_array($externalFilterValue)) $condition = trim($sExternalFilterValue);
{
$condition = trim($externalFilterValue);
}
else if (count($externalFilterValue) == 1)
{
$condition = trim($externalFilterValue[0]);
}
else
{
$condition = $externalFilterValue;
}
} }
if (!is_null($condition)) if (!is_null($condition))
{ {
$sOpCode = null; // default operator $this->AddCondition($sFilterCode, $condition);
if (is_array($condition))
{
// Multiple values, add them as AND X IN (v1, v2, v3...)
$sOpCode = 'IN';
}
$this->AddCondition($sFilterCode, $condition, $sOpCode);
}
}
if ($bDoSearch)
{
// Keep the table_id identifying this table if we're performing a search
$sTableId = utils::ReadParam('_table_id_', null, false, 'raw_data');
if ($sTableId != null)
{
$aExtraParams['table_id'] = $sTableId;
} }
} }
} }
@@ -380,55 +344,34 @@ class DisplayBlock
case 'count': case 'count':
if (isset($aExtraParams['group_by'])) if (isset($aExtraParams['group_by']))
{ {
if (isset($aExtraParams['group_by_label'])) $sGroupByField = $aExtraParams['group_by'];
{
$oGroupByExp = Expression::FromOQL($aExtraParams['group_by']);
$sGroupByLabel = $aExtraParams['group_by_label'];
}
else
{
// Backward compatibility: group_by is simply a field id
$sAlias = $this->m_oFilter->GetClassAlias();
$oGroupByExp = new FieldExpression($aExtraParams['group_by'], $sAlias);
$sGroupByLabel = MetaModel::GetLabel($this->m_oFilter->GetClass(), $aExtraParams['group_by']);
}
$aGroupBy = array(); $aGroupBy = array();
$aGroupBy['grouped_by_1'] = $oGroupByExp; $sLabels = array();
$sSql = MetaModel::MakeGroupByQuery($this->m_oFilter, $aQueryParams, $aGroupBy, true); $iTotalCount = $this->m_oSet->Count();
$aRes = CMDBSource::QueryToArray($sSql); while($oObj = $this->m_oSet->Fetch())
$aGroupBy = array();
$aLabels = array();
$aValues = array();
$iTotalCount = 0;
foreach ($aRes as $iRow => $aRow)
{ {
$sValue = $aRow['grouped_by_1']; if (isset($aExtraParams['group_by_expr']))
$aValues[$iRow] = $sValue; {
$sHtmlValue = $oGroupByExp->MakeValueLabel($this->m_oFilter, $sValue, $sValue); eval("\$sValue = ".sprintf($aExtraParams['group_by_expr'], $oObj->Get($sGroupByField)).';');
$aLabels[$iRow] = $sHtmlValue; }
$aGroupBy[$iRow] = (int) $aRow['_itop_count_']; else
$iTotalCount += $aRow['_itop_count_']; {
$sValue = $oObj->Get($sGroupByField);
}
$aGroupBy[$sValue] = isset($aGroupBy[$sValue]) ? $aGroupBy[$sValue]+1 : 1;
$sLabels[$sValue] = $oObj->GetAsHtml($sGroupByField);
} }
$sFilter = urlencode($this->m_oFilter->serialize());
$aData = array(); $aData = array();
$oAppContext = new ApplicationContext(); $oAppContext = new ApplicationContext();
$sParams = $oAppContext->GetForLink(); $sParams = $oAppContext->GetForLink();
foreach($aGroupBy as $iRow => $iCount) foreach($aGroupBy as $sValue => $iCount)
{ {
// Build the search for this subset $aData[] = array ( 'group' => $sLabels[$sValue],
$oSubsetSearch = $this->m_oFilter->DeepClone(); 'value' => "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&dosearch=1&$sParams&filter=$sFilter&$sGroupByField=".urlencode($sValue)."\">$iCount</a>"); // TO DO: add the context information
$oCondition = new BinaryExpression($oGroupByExp, '=', new ScalarExpression($aValues[$iRow]));
$oSubsetSearch->AddConditionExpression($oCondition);
$sFilter = urlencode($oSubsetSearch->serialize());
$aData[] = array ( 'group' => $aLabels[$iRow],
'value' => "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&dosearch=1&$sParams&filter=$sFilter\">$iCount</a>"); // TO DO: add the context information
} }
$aAttribs =array( $aAttribs =array(
'group' => array('label' => $sGroupByLabel, 'description' => ''), 'group' => array('label' => MetaModel::GetLabel($this->m_oFilter->GetClass(), $sGroupByField), 'description' => ''),
'value' => array('label'=> Dict::S('UI:GroupBy:Count'), 'description' => Dict::S('UI:GroupBy:Count+')) 'value' => array('label'=> Dict::S('UI:GroupBy:Count'), 'description' => Dict::S('UI:GroupBy:Count+'))
); );
$sFormat = isset($aExtraParams['format']) ? $aExtraParams['format'] : 'UI:Pagination:HeaderNoSelection'; $sFormat = isset($aExtraParams['format']) ? $aExtraParams['format'] : 'UI:Pagination:HeaderNoSelection';
@@ -497,7 +440,7 @@ class DisplayBlock
$sHtml .= "<table>\n"; $sHtml .= "<table>\n";
// Construct a new (parametric) query that will return the content of this block // Construct a new (parametric) query that will return the content of this block
$oBlockFilter = $this->m_oFilter->DeepClone(); $oBlockFilter = clone $this->m_oFilter;
$aExpressions = array(); $aExpressions = array();
$index = 0; $index = 0;
foreach($aGroupByFields as $aField) foreach($aGroupByFields as $aField)
@@ -590,13 +533,11 @@ class DisplayBlock
{ {
if ((UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES)) if ((UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES))
{ {
$sLinkTarget = '';
$oAppContext = new ApplicationContext(); $oAppContext = new ApplicationContext();
$sParams = $oAppContext->GetForLink(); $sParams = $oAppContext->GetForLink();
// 1:n links, populate the target object as a default value when creating a new linked object // 1:n links, populate the target object as a default value when creating a new linked object
if (isset($aExtraParams['target_attr'])) if (isset($aExtraParams['target_attr']))
{ {
$sLinkTarget = ' target="_blank" ';
$aExtraParams['default'][$aExtraParams['target_attr']] = $aExtraParams['object_id']; $aExtraParams['default'][$aExtraParams['target_attr']] = $aExtraParams['object_id'];
} }
$sDefault = ''; $sDefault = '';
@@ -608,7 +549,7 @@ class DisplayBlock
} }
} }
$sHtml .= $oPage->GetP("<a{$sLinkTarget} href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=new&class=$sClass&$sParams{$sDefault}\">".Dict::Format('UI:ClickToCreateNew', Metamodel::GetName($sClass))."</a>\n"); $sHtml .= $oPage->GetP("<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=new&class=$sClass&$sParams{$sDefault}\">".Dict::Format('UI:ClickToCreateNew', Metamodel::GetName($sClass))."</a>\n");
} }
} }
} }
@@ -680,10 +621,9 @@ class DisplayBlock
$this->m_oSet = new CMDBObjectSet($this->m_oFilter, array(), $aQueryParams); $this->m_oSet = new CMDBObjectSet($this->m_oFilter, array(), $aQueryParams);
} }
$iCount = $this->m_oSet->Count(); $iCount = $this->m_oSet->Count();
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($this->m_oFilter->serialize()); $sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.$this->m_oFilter->serialize();
$sHtml .= '<p><a class="actions" href="'.$sHyperlink.'">'; $sHtml .= '<p><a class="actions" href="'.$sHyperlink.'">';
// Note: border set to 0 due to various browser interpretations (IE9 adding a 2px border) $sHtml .= MetaModel::GetClassIcon($sClass, true, 'float;left;margin-right:10px;');
$sHtml .= MetaModel::GetClassIcon($sClass, true, 'float;left;margin-right:10px;border:0;');
$sHtml .= MetaModel::GetName($sClass).': '.$iCount.'</a></p>'; $sHtml .= MetaModel::GetName($sClass).': '.$iCount.'</a></p>';
$sParams = $oAppContext->GetForLink(); $sParams = $oAppContext->GetForLink();
$sHtml .= '<p>'; $sHtml .= '<p>';
@@ -731,18 +671,18 @@ class DisplayBlock
$oAttDef = MetaModel::GetAttributeDef($sClass, $sStateAttrCode); $oAttDef = MetaModel::GetAttributeDef($sClass, $sStateAttrCode);
foreach($aStates as $sStateValue) foreach($aStates as $sStateValue)
{ {
$oFilter = $this->m_oFilter->DeepClone(); $oFilter = clone($this->m_oFilter);
$oFilter->AddCondition($sStateAttrCode, $sStateValue, '='); $oFilter->AddCondition($sStateAttrCode, $sStateValue, '=');
$oSet = new DBObjectSet($oFilter); $oSet = new DBObjectSet($oFilter);
$aCounts[$sStateValue] = $oSet->Count(); $aCounts[$sStateValue] = $oSet->Count();
$aStateLabels[$sStateValue] = htmlentities($oAttDef->GetValueLabel($sStateValue), ENT_QUOTES, 'UTF-8'); $aStateLabels[$sStateValue] = $oAttDef->GetValueLabel($sStateValue);
if ($aCounts[$sStateValue] == 0) if ($aCounts[$sStateValue] == 0)
{ {
$aCounts[$sStateValue] = '-'; $aCounts[$sStateValue] = '-';
} }
else else
{ {
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($oFilter->serialize()); $sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.$oFilter->serialize();
$aCounts[$sStateValue] = "<a href=\"$sHyperlink\">{$aCounts[$sStateValue]}</a>"; $aCounts[$sStateValue] = "<a href=\"$sHyperlink\">{$aCounts[$sStateValue]}</a>";
} }
} }
@@ -751,73 +691,14 @@ class DisplayBlock
$sHtml .= '<tr><td>'.implode('</td><td>', $aCounts).'</td></tr></table></div>'; $sHtml .= '<tr><td>'.implode('</td><td>', $aCounts).'</td></tr></table></div>';
// Title & summary // Title & summary
$iCount = $this->m_oSet->Count(); $iCount = $this->m_oSet->Count();
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($this->m_oFilter->serialize()); $sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.$this->m_oFilter->serialize();
$sHtml .= '<h1>'.Dict::S(str_replace('_', ':', $sTitle)).'</h1>'; $sHtml .= '<h1>'.Dict::S(str_replace('_', ':', $sTitle)).'</h1>';
$sHtml .= '<a class="summary" href="'.$sHyperlink.'">'.Dict::Format(str_replace('_', ':', $sLabel), $iCount).'</a>'; $sHtml .= '<a class="summary" href="'.$sHyperlink.'">'.Dict::Format(str_replace('_', ':', $sLabel), $iCount).'</a>';
break; break;
case 'csv': case 'csv':
$bAdvancedMode = utils::ReadParam('advanced', false);
$sCsvFile = strtolower($this->m_oFilter->GetClass()).'.csv';
$sDownloadLink = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?expression='.urlencode($this->m_oFilter->ToOQL(true)).'&format=csv&filename='.urlencode($sCsvFile);
$sLinkToToggle = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($this->m_oFilter->serialize()).'&format=csv';
if ($bAdvancedMode)
{
$sDownloadLink .= '&fields_advanced=1';
$sChecked = 'CHECKED';
}
else
{
$sLinkToToggle = $sLinkToToggle.'&advanced=1';
$sChecked = '';
}
$sCSVData = cmdbAbstractObject::GetSetAsCSV($this->m_oSet, array('fields_advanced' => $bAdvancedMode));
$sCharset = MetaModel::GetConfig()->Get('csv_file_default_charset');
if ($sCharset == 'UTF-8')
{
$bLostChars = false;
}
else
{
$sConverted = @iconv('UTF-8', $sCharset, $sCSVData);
$sRestored = @iconv($sCharset, 'UTF-8', $sConverted);
$bLostChars = ($sRestored != $sCSVData);
}
if ($bLostChars)
{
$sCharsetNotice = "&nbsp;&nbsp;<span id=\"csv_charset_issue\">";
$sCharsetNotice .= '<img src="../images/error.png" style="vertical-align:middle"/>';
$sCharsetNotice .= "</span>";
$sTip = "<p>".htmlentities(Dict::S('UI:CSVExport:LostChars'), ENT_QUOTES, 'UTF-8')."</p>";
$sTip .= "<p>".htmlentities(Dict::Format('UI:CSVExport:LostChars+', $sCharset), ENT_QUOTES, 'UTF-8')."</p>";
$oPage->add_ready_script("$('#csv_charset_issue').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
}
else
{
$sCharsetNotice = '';
}
$sHtml .= "<div>";
$sHtml .= '<table style="width:100%" class="transparent">';
$sHtml .= '<tr>';
$sHtml .= '<td><a href="'.$sDownloadLink.'">'.Dict::Format('UI:Download-CSV', $sCsvFile).'</a>'.$sCharsetNotice.'</td>';
$sHtml .= '<td style="text-align:right"><input type="checkbox" '.$sChecked.' onClick="window.location.href=\''.$sLinkToToggle.'\'">&nbsp;'.Dict::S('UI:CSVExport:AdvancedMode').'</td>';
$sHtml .= '</tr>';
$sHtml .= '</table>';
if ($bAdvancedMode)
{
$sHtml .= "<p>";
$sHtml .= htmlentities(Dict::S('UI:CSVExport:AdvancedMode+'), ENT_QUOTES, 'UTF-8');
$sHtml .= "</p>";
}
$sHtml .= "</div>";
$sHtml .= "<textarea style=\"width:95%;height:98%\">\n"; $sHtml .= "<textarea style=\"width:95%;height:98%\">\n";
$sHtml .= htmlentities($sCSVData, ENT_QUOTES, 'UTF-8'); $sHtml .= cmdbAbstractObject::GetSetAsCSV($this->m_oSet);
$sHtml .= "</textarea>\n"; $sHtml .= "</textarea>\n";
break; break;
@@ -862,70 +743,43 @@ EOF
$sGroupBy = isset($aExtraParams['group_by']) ? $aExtraParams['group_by'] : ''; $sGroupBy = isset($aExtraParams['group_by']) ? $aExtraParams['group_by'] : '';
$sGroupByExpr = isset($aExtraParams['group_by_expr']) ? '&params[group_by_expr]='.$aExtraParams['group_by_expr'] : ''; $sGroupByExpr = isset($aExtraParams['group_by_expr']) ? '&params[group_by_expr]='.$aExtraParams['group_by_expr'] : '';
$sFilter = $this->m_oFilter->serialize(); $sFilter = $this->m_oFilter->serialize();
$sHtml .= "<div id=\"my_chart_$sId{$iChartCounter}\">If the chart does not display, <a href=\"http://get.adobe.com/flash/\" target=\"_blank\">install Flash</a></div>\n"; $sHtml .= "<div id=\"my_chart_{$iChartCounter}\">If the chart does not display, <a href=\"http://get.adobe.com/flash/\" target=\"_blank\">install Flash</a></div>\n";
$oPage->add_script("function ofc_resize(left, width, top, height) { /* do nothing special */ }"); $oPage->add_script("function ofc_resize(left, width, top, height) { /* do nothing special */ }");
if (isset($aExtraParams['group_by_label'])) $oPage->add_ready_script("swfobject.embedSWF(\"../images/open-flash-chart.swf\", \"my_chart_{$iChartCounter}\", \"100%\", \"300\",\"9.0.0\", \"expressInstall.swf\",
{ {\"data-file\":\"".urlencode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=open_flash_chart&params[group_by]=$sGroupBy{$sGroupByExpr}&params[chart_type]=$sChartType&params[chart_title]=$sTitle&id=$sId&filter=".$sFilter)."\"}, {wmode: 'transparent'} );\n");
$sUrl = urlencode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=open_flash_chart&params[group_by]=$sGroupBy{$sGroupByExpr}&params[group_by_label]={$aExtraParams['group_by_label']}&params[chart_type]=$sChartType&params[chart_title]=$sTitle&params[currentId]=$sId&id=$sId&filter=".urlencode($sFilter));
}
else
{
$sUrl = urlencode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=open_flash_chart&params[group_by]=$sGroupBy{$sGroupByExpr}&params[chart_type]=$sChartType&params[chart_title]=$sTitle&params[currentId]=$sId&id=$sId&filter=".urlencode($sFilter));
}
$oPage->add_ready_script("swfobject.embedSWF(\"../images/open-flash-chart.swf\", \"my_chart_$sId{$iChartCounter}\", \"100%\", \"300\",\"9.0.0\", \"expressInstall.swf\",
{\"data-file\":\"".$sUrl."\"}, {wmode: 'transparent'} );\n");
$iChartCounter++; $iChartCounter++;
if (isset($aExtraParams['group_by'])) if (isset($aExtraParams['group_by']))
{ {
if (isset($aExtraParams['group_by_label'])) $sGroupByField = $aExtraParams['group_by'];
{
$oGroupByExp = Expression::FromOQL($aExtraParams['group_by']);
$sGroupByLabel = $aExtraParams['group_by_label'];
}
else
{
// Backward compatibility: group_by is simply a field id
$sAlias = $this->m_oFilter->GetClassAlias();
$oGroupByExp = new FieldExpression($aExtraParams['group_by'], $sAlias);
$sGroupByLabel = MetaModel::GetLabel($this->m_oFilter->GetClass(), $aExtraParams['group_by']);
}
$aGroupBy = array(); $aGroupBy = array();
$aGroupBy['grouped_by_1'] = $oGroupByExp; while($oObj = $this->m_oSet->Fetch())
$sSql = MetaModel::MakeGroupByQuery($this->m_oFilter, $aQueryParams, $aGroupBy, true);
$aRes = CMDBSource::QueryToArray($sSql);
$aGroupBy = array();
$aLabels = array();
$aValues = array();
$iTotalCount = 0;
foreach ($aRes as $iRow => $aRow)
{ {
$sValue = $aRow['grouped_by_1']; if (isset($aExtraParams['group_by_expr']))
$aValues[$iRow] = $sValue; {
$sHtmlValue = $oGroupByExp->MakeValueLabel($this->m_oFilter, $sValue, $sValue); eval("\$sValue = ".sprintf($aExtraParams['group_by_expr'], $oObj->Get($sGroupByField)).';');
$aLabels[$iRow] = $sHtmlValue; }
$aGroupBy[$iRow] = (int) $aRow['_itop_count_']; else
$iTotalCount += $aRow['_itop_count_']; {
$sValue = $oObj->Get($sGroupByField);
}
$aGroupBy[$sValue] = isset($aGroupBy[$sValue]) ? $aGroupBy[$sValue]+1 : 1;
} }
$sFilter = urlencode($this->m_oFilter->serialize());
$aData = array(); $aData = array();
$aLabels = array();
$idx = 0; $idx = 0;
$aURLs = array(); $aURLs = array();
foreach($aGroupBy as $iRow => $iCount) foreach($aGroupBy as $sValue => $iValue)
{ {
// Build the search for this subset $oDrillDownFilter = clone $this->m_oFilter;
$oSubsetSearch = $this->m_oFilter->DeepClone(); $oDrillDownFilter->AddCondition($sGroupByField, $sValue, '=');
$oCondition = new BinaryExpression($oGroupByExp, '=', new ScalarExpression($aValues[$iRow])); $aURLs[$idx] = $oDrillDownFilter->serialize();
$oSubsetSearch->AddConditionExpression($oCondition);
$aURLs[$idx] = $oSubsetSearch->serialize();
$idx++; $idx++;
} }
$sURLList = ''; $sURLList = '';
foreach($aURLs as $index => $sURL) foreach($aURLs as $index => $sURL)
{ {
$sURLList .= "\taURLs[$index] = '".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&format=html{$sContext}&filter=".urlencode($sURL)."';\n"; $sURLList .= "\taURLs[$index] = '".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&format=html{$sContext}&filter=".addslashes($sURL)."';\n";
} }
$oPage->add_script( $oPage->add_script(
<<<EOF <<<EOF
@@ -953,46 +807,31 @@ EOF
if (isset($aExtraParams['group_by'])) if (isset($aExtraParams['group_by']))
{ {
if (isset($aExtraParams['group_by_label'])) $sGroupByField = $aExtraParams['group_by'];
{
$oGroupByExp = Expression::FromOQL($aExtraParams['group_by']);
$sGroupByLabel = $aExtraParams['group_by_label'];
}
else
{
// Backward compatibility: group_by is simply a field id
$sAlias = $this->m_oFilter->GetClassAlias();
$oGroupByExp = new FieldExpression($aExtraParams['group_by'], $sAlias);
$sGroupByLabel = MetaModel::GetLabel($this->m_oFilter->GetClass(), $aExtraParams['group_by']);
}
$aGroupBy = array(); $aGroupBy = array();
$aGroupBy['grouped_by_1'] = $oGroupByExp; while($oObj = $this->m_oSet->Fetch())
$sSql = MetaModel::MakeGroupByQuery($this->m_oFilter, $aQueryParams, $aGroupBy, true);
$aRes = CMDBSource::QueryToArray($sSql);
$aGroupBy = array();
$aLabels = array();
$iTotalCount = 0;
foreach ($aRes as $iRow => $aRow)
{ {
$sValue = $aRow['grouped_by_1']; if (isset($aExtraParams['group_by_expr']))
$sHtmlValue = $oGroupByExp->MakeValueLabel($this->m_oFilter, $sValue, $sValue); {
$aLabels[$iRow] = strip_tags($sHtmlValue); eval("\$sValue = ".sprintf($aExtraParams['group_by_expr'], $oObj->Get($sGroupByField)).';');
$aGroupBy[$iRow] = (int) $aRow['_itop_count_']; }
$iTotalCount += $aRow['_itop_count_']; else
{
$sValue = $oObj->Get($sGroupByField);
}
$aGroupBy[$sValue] = isset($aGroupBy[$sValue]) ? $aGroupBy[$sValue]+1 : 1;
} }
$sFilter = urlencode($this->m_oFilter->serialize());
$aData = array(); $aData = array();
$aChartLabels = array(); $aLabels = array();
$maxValue = 0; $maxValue = 0;
foreach($aGroupBy as $iRow => $iCount) foreach($aGroupBy as $sValue => $iValue)
{ {
$oBarValue = new bar_value($iCount); $oBarValue = new bar_value($iValue);
$oBarValue->on_click("ofc_drill_down_$sId"); $oBarValue->on_click("ofc_drill_down_$sId");
$aData[] = $oBarValue; $aData[] = $oBarValue;
if ($iCount > $maxValue) $maxValue = $iCount; if ($iValue > $maxValue) $maxValue = $iValue;
$aChartLabels[] = html_entity_decode($aLabels[$iRow], ENT_QUOTES, 'UTF-8'); $aLabels[] = $sValue;
} }
$oYAxis = new y_axis(); $oYAxis = new y_axis();
$aMagicValues = array(1,2,5,10); $aMagicValues = array(1,2,5,10);
@@ -1018,7 +857,7 @@ EOF
// set them vertical // set them vertical
$oXLabels->set_vertical(); $oXLabels->set_vertical();
// set the label text // set the label text
$oXLabels->set_labels($aChartLabels); $oXLabels->set_labels($aLabels);
// Add the X Axis Labels to the X Axis // Add the X Axis Labels to the X Axis
$oXAxis->set_labels( $oXLabels ); $oXAxis->set_labels( $oXLabels );
$oChart->set_x_axis( $oXAxis ); $oChart->set_x_axis( $oXAxis );
@@ -1034,65 +873,37 @@ EOF
$oChartElement->set_colours( array('#FF8A00', '#909980', '#2C2B33', '#CCC08D', '#596664') ); $oChartElement->set_colours( array('#FF8A00', '#909980', '#2C2B33', '#CCC08D', '#596664') );
if (isset($aExtraParams['group_by'])) if (isset($aExtraParams['group_by']))
{ {
if (isset($aExtraParams['group_by_label'])) $sGroupByField = $aExtraParams['group_by'];
{
$oGroupByExp = Expression::FromOQL($aExtraParams['group_by']);
$sGroupByLabel = $aExtraParams['group_by_label'];
}
else
{
// Backward compatibility: group_by is simply a field id
$sAlias = $this->m_oFilter->GetClassAlias();
$oGroupByExp = new FieldExpression($aExtraParams['group_by'], $sAlias);
$sGroupByLabel = MetaModel::GetLabel($this->m_oFilter->GetClass(), $aExtraParams['group_by']);
}
$aGroupBy = array(); $aGroupBy = array();
$aGroupBy['grouped_by_1'] = $oGroupByExp; while($oObj = $this->m_oSet->Fetch())
$sSql = MetaModel::MakeGroupByQuery($this->m_oFilter, $aQueryParams, $aGroupBy, true);
$aRes = CMDBSource::QueryToArray($sSql);
$aGroupBy = array();
$aLabels = array();
$iTotalCount = 0;
foreach ($aRes as $iRow => $aRow)
{ {
$sValue = $aRow['grouped_by_1']; if (isset($aExtraParams['group_by_expr']))
$sHtmlValue = $oGroupByExp->MakeValueLabel($this->m_oFilter, $sValue, $sValue); {
$aLabels[$iRow] = strip_tags($sHtmlValue); eval("\$sValue = ".sprintf($aExtraParams['group_by_expr'], $oObj->Get($sGroupByField)).';');
$aGroupBy[$iRow] = (int) $aRow['_itop_count_']; }
$iTotalCount += $aRow['_itop_count_']; else
{
$sValue = $oObj->Get($sGroupByField);
}
$aGroupBy[$sValue] = isset($aGroupBy[$sValue]) ? $aGroupBy[$sValue]+1 : 1;
} }
$sFilter = urlencode($this->m_oFilter->serialize());
$aData = array(); $aData = array();
foreach($aGroupBy as $iRow => $iCount) foreach($aGroupBy as $sValue => $iValue)
{ {
$sFlashLabel = html_entity_decode($aLabels[$iRow], ENT_QUOTES, 'UTF-8'); $PieValue = new pie_value($iValue, $sValue); //@@ BUG: not passed via ajax !!!
$PieValue = new pie_value($iCount, $sFlashLabel); //@@ BUG: not passed via ajax !!!
$PieValue->on_click("ofc_drill_down_$sId"); $PieValue->on_click("ofc_drill_down_$sId");
$aData[] = $PieValue; $aData[] = $PieValue;
} }
$oChartElement->set_values( $aData ); $oChartElement->set_values( $aData );
$oChart->x_axis = null; $oChart->x_axis = null;
} }
} }
if (isset($aExtraParams['chart_title'])) if (isset($aExtraParams['chart_title']))
{ {
// The title has been given in an url, and urlencoded... $oTitle = new title( Dict::S($aExtraParams['chart_title']) );
// and urlencode transforms utf-8 into something similar to ISO-8859-1
// Example: é (C3A9 becomes %E9)
// As a consequence, json_encode (called within open-flash-chart.php)
// was returning 'null' and the graph was not displayed at all
// To make sure that the graph is displayed AND to get a correct title
// (at least for european characters) let's transform back into utf-8 !
$sTitle = iconv("ISO-8859-1", "UTF-8//IGNORE", $aExtraParams['chart_title']);
// If the title is a dictionnary entry, fetch it
$sTitle = Dict::S($sTitle);
$oTitle = new title($sTitle);
$oChart->set_title( $oTitle ); $oChart->set_title( $oTitle );
} }
$oChart->set_bg_colour('#FFFFFF'); $oChart->set_bg_colour('#FFFFFF');
@@ -1112,17 +923,8 @@ EOF
* Add a condition (restriction) to the current DBObjectSearch on which the display block is based * Add a condition (restriction) to the current DBObjectSearch on which the display block is based
* taking into account the hierarchical keys for which the condition is based on the 'below' operator * taking into account the hierarchical keys for which the condition is based on the 'below' operator
*/ */
protected function AddCondition($sFilterCode, $condition, $sOpCode = null) protected function AddCondition($sFilterCode, $condition)
{ {
// Workaround to an issue revealed whenever a condition on org_id is applied twice (with a hierarchy of organizations)
// Moreover, it keeps the query as simple as possible
if (isset($this->m_aConditions[$sFilterCode]) && $condition == $this->m_aConditions[$sFilterCode])
{
// Skip
return;
}
$this->m_aConditions[$sFilterCode] = $condition;
$sClass = $this->m_oFilter->GetClass(); $sClass = $this->m_oFilter->GetClass();
$bConditionAdded = false; $bConditionAdded = false;
@@ -1138,29 +940,12 @@ EOF
if ($sHierarchicalKeyCode !== false) if ($sHierarchicalKeyCode !== false)
{ {
$oFilter = new DBObjectSearch($oAttDef->GetTargetClass()); $oFilter = new DBObjectSearch($oAttDef->GetTargetClass());
if (($sOpCode == 'IN') && is_array($condition)) $oFilter->AddCondition('id', $condition);
{
$oFilter->AddConditionExpression(self::GetConditionIN($oFilter, 'id', $condition));
}
else
{
$oFilter->AddCondition('id', $condition);
}
$oHKFilter = new DBObjectSearch($oAttDef->GetTargetClass()); $oHKFilter = new DBObjectSearch($oAttDef->GetTargetClass());
$oHKFilter->AddCondition_PointingTo($oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW); // Use the 'below' operator by default $oHKFilter->AddCondition_PointingTo($oFilter, $sHierarchicalKeyCode, TREE_OPERATOR_BELOW); // Use the 'below' operator by default
$this->m_oFilter->AddCondition_PointingTo($oHKFilter, $sFilterCode); $this->m_oFilter->AddCondition_PointingTo($oHKFilter, $sFilterCode);
$bConditionAdded = true; $bConditionAdded = true;
} }
else if (($sOpCode == 'IN') && is_array($condition))
{
$this->m_oFilter->AddConditionExpression(self::GetConditionIN($this->m_oFilter, $sFilterCode, $condition));
$bConditionAdded = true;
}
}
else if (($sOpCode == 'IN') && is_array($condition))
{
$this->m_oFilter->AddConditionExpression(self::GetConditionIN($this->m_oFilter, $sFilterCode, $condition));
$bConditionAdded = true;
} }
} }
@@ -1170,15 +955,6 @@ EOF
$this->m_oFilter->AddCondition($sFilterCode, $condition); // Use the default 'loose' operator $this->m_oFilter->AddCondition($sFilterCode, $condition); // Use the default 'loose' operator
} }
} }
static protected function GetConditionIN($oFilter, $sFilterCode, $condition)
{
$oField = new FieldExpression($sFilterCode, $oFilter->GetClassAlias());
$sListExpr = '('.implode(', ', CMDBSource::Quote($condition)).')';
$sOQLCondition = $oField->Render()." IN $sListExpr";
$oNewCondition = Expression::FromOQL($sOQLCondition);
return $oNewCondition;
}
} }
/** /**
@@ -1265,13 +1041,8 @@ class HistoryBlock extends DisplayBlock
} }
} }
/**
* Displays the 'Actions' menu for a given (list of) object(s)
* The 'style' of the list (see constructor of DisplayBlock) can be either 'list' or 'details'
* For backward compatibility 'popup' is equivalent to 'list'...
*/
class MenuBlock extends DisplayBlock class MenuBlock extends DisplayBlock
{ {
/** /**
* Renders the "Actions" popup menu for the given set of objects * Renders the "Actions" popup menu for the given set of objects
* *
@@ -1283,10 +1054,6 @@ class MenuBlock extends DisplayBlock
*/ */
public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId) public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
{ {
if ($this->m_sStyle == 'popup') // popup is a synonym of 'list' for backward compatibility
{
$this->m_sStyle = 'list';
}
$sHtml = ''; $sHtml = '';
$oAppContext = new ApplicationContext(); $oAppContext = new ApplicationContext();
$sContext = $oAppContext->GetForLink(); $sContext = $oAppContext->GetForLink();
@@ -1297,7 +1064,7 @@ class MenuBlock extends DisplayBlock
$sClass = $this->m_oFilter->GetClass(); $sClass = $this->m_oFilter->GetClass();
$oSet = new CMDBObjectSet($this->m_oFilter); $oSet = new CMDBObjectSet($this->m_oFilter);
$sFilter = $this->m_oFilter->serialize(); $sFilter = $this->m_oFilter->serialize();
$sFilterDesc = $this->m_oFilter->ToOql(true); $sFilterDesc = $this->m_oFilter->ToOql();
$aActions = array(); $aActions = array();
$sUIPage = cmdbAbstractObject::ComputeStandardUIPage($sClass); $sUIPage = cmdbAbstractObject::ComputeStandardUIPage($sClass);
$sRootUrl = utils::GetAbsoluteUrlAppRoot(); $sRootUrl = utils::GetAbsoluteUrlAppRoot();
@@ -1314,12 +1081,12 @@ class MenuBlock extends DisplayBlock
$sDefault.= "&default[$sKey]=$sValue"; $sDefault.= "&default[$sKey]=$sValue";
} }
} }
$bIsCreationAllowed = (UserRights::IsActionAllowed($sClass, UR_ACTION_CREATE) == UR_ALLOWED_YES);
switch($oSet->Count()) switch($oSet->Count())
{ {
case 0: case 0:
// No object in the set, the only possible action is "new" // No object in the set, the only possible action is "new"
if ($bIsCreationAllowed) { $aActions['UI:Menu:New'] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=new&class=$sClass{$sContext}{$sDefault}"); } $bIsModifyAllowed = (UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES);
if ($bIsModifyAllowed) { $aActions['UI:Menu:New'] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=new&class=$sClass{$sContext}{$sDefault}"); }
break; break;
case 1: case 1:
@@ -1333,7 +1100,7 @@ class MenuBlock extends DisplayBlock
if (!isset($aExtraParams['link_attr'])) if (!isset($aExtraParams['link_attr']))
{ {
if ($bIsModifyAllowed) { $aActions['UI:Menu:Modify'] = array ('label' => Dict::S('UI:Menu:Modify'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=modify&class=$sClass&id=$id{$sContext}#"); } if ($bIsModifyAllowed) { $aActions['UI:Menu:Modify'] = array ('label' => Dict::S('UI:Menu:Modify'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=modify&class=$sClass&id=$id{$sContext}#"); }
if ($bIsCreationAllowed) { $aActions['UI:Menu:New'] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=new&class=$sClass{$sContext}{$sDefault}"); } if ($bIsModifyAllowed) { $aActions['UI:Menu:New'] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=new&class=$sClass{$sContext}{$sDefault}"); }
if ($bIsDeleteAllowed) { $aActions['UI:Menu:Delete'] = array ('label' => Dict::S('UI:Menu:Delete'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=delete&class=$sClass&id=$id{$sContext}"); } if ($bIsDeleteAllowed) { $aActions['UI:Menu:Delete'] = array ('label' => Dict::S('UI:Menu:Delete'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=delete&class=$sClass&id=$id{$sContext}"); }
// Transitions / Stimuli // Transitions / Stimuli
$aTransitions = $oObj->EnumTransitions(); $aTransitions = $oObj->EnumTransitions();
@@ -1365,20 +1132,11 @@ class MenuBlock extends DisplayBlock
$aActions[$sRelationCode] = array ('label' => MetaModel::GetRelationVerbUp($sRelationCode), 'url' => "{$sRootUrl}pages/$sUIPage?operation=swf_navigator&relation=$sRelationCode&class=$sClass&id=$id{$sContext}"); $aActions[$sRelationCode] = array ('label' => MetaModel::GetRelationVerbUp($sRelationCode), 'url' => "{$sRootUrl}pages/$sUIPage?operation=swf_navigator&relation=$sRelationCode&class=$sClass&id=$id{$sContext}");
} }
} }
/*
$this->AddMenuSeparator($aActions); $this->AddMenuSeparator($aActions);
// Static menus: Email this page & CSV Export // Static menus: Email this page & CSV Export
$sUrl = ApplicationContext::MakeObjectUrl($sClass, $id); $sUrl = ApplicationContext::MakeObjectUrl($sClass, $id);
$aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=".urlencode($oObj->GetRawName())."&body=".urlencode($sUrl)); $aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=".urlencode($oObj->GetRawName())."&body=".urlencode($sUrl));
$aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv{$sContext}"); $aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=$sFilter&format=csv{$sContext}");
// The style tells us whether the menu is displayed on a list of one object, or on the details of the given object
if ($this->m_sStyle == 'list')
{
// Actions specific to the list
$sOQL = addslashes($sFilterDesc);
$aActions['UI:Menu:AddToDashboard'] = array ('label' => Dict::S('UI:Menu:AddToDashboard'), 'url' => "#", 'onclick' => "return DashletCreationDlg('$sOQL')");
}
*/
} }
$this->AddMenuSeparator($aActions); $this->AddMenuSeparator($aActions);
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance) foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
@@ -1411,16 +1169,13 @@ class MenuBlock extends DisplayBlock
else else
{ {
// many objects in the set, possible actions are: new / modify all / delete all // many objects in the set, possible actions are: new / modify all / delete all
if ($bIsCreationAllowed) { $aActions['UI:Menu:New'] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=new&class=$sClass{$sContext}{$sDefault}"); } if ($bIsModifyAllowed) { $aActions['UI:Menu:New'] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=new&class=$sClass{$sContext}{$sDefault}"); }
if ($bIsBulkModifyAllowed) { $aActions['UI:Menu:ModifyAll'] = array ('label' => Dict::S('UI:Menu:ModifyAll'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=select_for_modify_all&class=$sClass&filter=".urlencode($sFilter)."{$sContext}"); } if ($bIsBulkModifyAllowed) { $aActions['UI:Menu:ModifyAll'] = array ('label' => Dict::S('UI:Menu:ModifyAll'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=select_for_modify_all&class=$sClass&filter=$sFilter{$sContext}"); }
if ($bIsBulkDeleteAllowed) { $aActions['UI:Menu:BulkDelete'] = array ('label' => Dict::S('UI:Menu:BulkDelete'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=select_for_deletion&filter=".urlencode($sFilter)."{$sContext}"); } if ($bIsBulkDeleteAllowed) { $aActions['UI:Menu:BulkDelete'] = array ('label' => Dict::S('UI:Menu:BulkDelete'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=select_for_deletion&filter=$sFilter{$sContext}"); }
// Stimuli // Stimuli
$aStates = MetaModel::EnumStates($sClass); $aStates = MetaModel::EnumStates($sClass);
// Do not perform time consuming computations if there are too may objects in the list if (count($aStates) > 0)
$iLimit = MetaModel::GetConfig()->Get('complex_actions_limit');
if ((count($aStates) > 0) && (($iLimit == 0) || ($oSet->Count() < $iLimit)))
{ {
// Life cycle actions may be available... if all objects are in the same state // Life cycle actions may be available... if all objects are in the same state
$oSet->Rewind(); $oSet->Rewind();
@@ -1447,7 +1202,7 @@ class MenuBlock extends DisplayBlock
{ {
case UR_ALLOWED_YES: case UR_ALLOWED_YES:
case UR_ALLOWED_DEPENDS: case UR_ALLOWED_DEPENDS:
$aActions[$sStimulusCode] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "{$sRootUrl}pages/UI.php?operation=select_bulk_stimulus&stimulus=$sStimulusCode&state=$sState&class=$sClass&filter=".urlencode($sFilter)."{$sContext}"); $aActions[$sStimulusCode] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "{$sRootUrl}pages/UI.php?operation=select_bulk_stimulus&stimulus=$sStimulusCode&state=$sState&class=$sClass&filter=$sFilter{$sContext}");
break; break;
default: default:
@@ -1457,55 +1212,21 @@ class MenuBlock extends DisplayBlock
} }
} }
} }
/*
$this->AddMenuSeparator($aActions); $this->AddMenuSeparator($aActions);
$sUrl = utils::GetAbsoluteUrlAppRoot(); $sUrl = utils::GetAbsoluteUrlAppRoot();
$aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=$sFilterDesc&body=".urlencode("{$sUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."{$sContext}")); $aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=$sFilterDesc&body=".urlencode("{$sUrl}pages/$sUIPage?operation=search&filter=$sFilter{$sContext}"));
$aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv{$sContext}"); $aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=$sFilter&format=csv{$sContext}");
$sOQL = addslashes($sFilterDesc);
$aActions['UI:Menu:AddToDashboard'] = array ('label' => Dict::S('UI:Menu:AddToDashboard'), 'url' => "#", 'onclick' => "return DashletCreationDlg('$sOQL')");
*/
} }
} $this->AddMenuSeparator($aActions);
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
$this->AddMenuSeparator($aActions);
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
{
$oSet->Rewind();
foreach($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $data)
{ {
if (is_array($data)) $oSet->Rewind();
foreach($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $sUrl)
{ {
// New plugins can provide javascript handlers via the 'onclick' property $aActions[$sLabel] = array ('label' => $sLabel, 'url' => $sUrl);
//TODO: enable extension of different menus by checking the 'target' property ??
$aActions[$sLabel] = array ('label' => $sLabel, 'url' => isset($data['url']) ? $data['url'] : '#', 'onclick' => isset($data['onclick']) ? $data['onclick'] : '');
}
else
{
// Backward compatibility with old plugins
$aActions[$sLabel] = array ('label' => $sLabel, 'url' => $data);
} }
} }
} }
// New extensions based on iPopupMenuItem interface
switch($this->m_sStyle)
{
case 'list':
$oSet->Rewind();
$param = $oSet;
$iMenuId = iPopupMenuExtension::MENU_OBJLIST_ACTIONS;
break;
case 'details':
$oSet->Rewind();
$param = $oSet->Fetch();
$iMenuId = iPopupMenuExtension::MENU_OBJDETAILS_ACTIONS;
break;
}
utils::GetPopupMenuItems($oPage, $iMenuId, $param, $aActions);
$aFavoriteActions = array(); $aFavoriteActions = array();
$aCallSpec = array($sClass, 'GetShortcutActions'); $aCallSpec = array($sClass, 'GetShortcutActions');
if (is_callable($aCallSpec)) if (is_callable($aCallSpec))
@@ -1527,15 +1248,42 @@ class MenuBlock extends DisplayBlock
if (count($aFavoriteActions) > 0) if (count($aFavoriteActions) > 0)
{ {
$sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>".Dict::S('UI:Menu:OtherActions')."\n<ul>\n"; $sHtml .= "<div class=\"itop_popup\"><ul>\n<li>".Dict::S('UI:Menu:OtherActions')."\n<ul>\n";
} }
else else
{ {
$sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>".Dict::S('UI:Menu:Actions')."\n<ul>\n"; $sHtml .= "<div class=\"itop_popup\"><ul>\n<li>".Dict::S('UI:Menu:Actions')."\n<ul>\n";
}
$sPrevUrl = '';
foreach ($aActions as $key => $aAction)
{
if (in_array($key, $aShortcutActions))
{
$aFavoriteActions[] = $aAction;
}
else
{
$sClass = isset($aAction['class']) ? " class=\"{$aAction['class']}\"" : "";
if (empty($aAction['url']))
{
if ($sPrevUrl != '') // Don't output consecutively two separators...
{
$sHtml .= "<li>{$aAction['label']}</li>\n";
}
$sPrevUrl = '';
}
else
{
$sHtml .= "<li><a href=\"{$aAction['url']}\"$sClass>{$aAction['label']}</a></li>\n";
$sPrevUrl = $aAction['url'];
}
}
}
$sHtml .= "</ul>\n</li>\n</ul></div>";
foreach(array_reverse($aFavoriteActions) as $aAction)
{
$sHtml .= "<div class=\"actions_button\"><a href='{$aAction['url']}'>{$aAction['label']}</a></div>";
} }
$sHtml .= $oPage->RenderPopupMenuItems($aActions, $aFavoriteActions);
static $bPopupScript = false; static $bPopupScript = false;
if (!$bPopupScript) if (!$bPopupScript)
{ {
@@ -1565,114 +1313,4 @@ class MenuBlock extends DisplayBlock
} }
} }
} }
?>
/**
* Some dummy menus for testing
*/
class ExtraMenus implements iPopupMenuExtension
{
/*
const MENU_OBJLIST_ACTIONS = 1; // $param is a DBObjectSet containing the list of objects
const MENU_OBJLIST_TOOLKIT = 2; // $param is a DBObjectSet containing the list of objects
const MENU_OBJDETAILS_ACTIONS = 3; // $param is a DBObject instance: the object currently displayed
const MENU_DASHBOARD_ACTIONS = 4; // $param is a Dashboard instance: the dashboard currently displayed
const MENU_USER_ACTIONS = 5; // $param is a null ??
*/
/**
* Get the list of items to be added to a menu. The items will be inserted in the menu in the order of the returned array
* @param int $iMenuId The identifier of the type of menu, as listed by the constants MENU_xxx above
* @param mixed $param Depends on $iMenuId see the constants define above
* @return Array An array of ApplicationPopupMenuItem or an empty array if no action is to be added to the menu
*/
public static function EnumItems($iMenuId, $param)
{
switch($iMenuId)
{
/*
case iPopupMenuExtension::MENU_OBJLIST_ACTIONS:
// $param is a DBObjectSet
$aResult = array(
new JSPopupMenuItem('Test::Item1', 'List Test 1', "alert('Test 1')"),
new JSPopupMenuItem('Test::Item2', 'List Test 2', "alert('Test 2')"),
);
break;
$this->AddMenuSeparator($aActions);
$sUrl = utils::GetAbsoluteUrlAppRoot();
$aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=$sFilterDesc&body=".urlencode("{$sUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."{$sContext}"));
$aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv{$sContext}");
$sOQL = addslashes($sFilterDesc);
$aActions['UI:Menu:AddToDashboard'] = array ('label' => Dict::S('UI:Menu:AddToDashboard'), 'url' => "#", 'onclick' => "return DashletCreationDlg('$sOQL')");
*/
case iPopupMenuExtension::MENU_OBJLIST_TOOLKIT:
// $param is a DBObjectSet
$oAppContext = new ApplicationContext();
$sContext = $oAppContext->GetForLink();
$sUIPage = cmdbAbstractObject::ComputeStandardUIPage($param->GetFilter()->GetClass());
$sOQL = addslashes($param->GetFilter()->ToOQL(true));
$sFilter = urlencode($param->GetFilter()->serialize());
$sUrl = utils::GetAbsoluteUrlAppRoot()."pages/$sUIPage?operation=search&filter=".$sFilter."&{$sContext}";
$aResult = array(
new SeparatorPopupMenuItem(),
// Static menus: Email this page, CSV Export & Add to Dashboard
new URLPopupMenuItem('UI:Menu:EMail', Dict::S('UI:Menu:EMail'), "mailto:?body=".urlencode($sUrl)),
new URLPopupMenuItem('UI:Menu:CSVExport', Dict::S('UI:Menu:CSVExport'), $sUrl."&format=csv"),
new JSPopupMenuItem('UI:Menu:AddToDashboard', Dict::S('UI:Menu:AddToDashboard'), "DashletCreationDlg('$sOQL')"),
new JSPopupMenuItem('UI:Menu:ShortcutList', Dict::S('UI:Menu:ShortcutList'), "ShortcutListDlg('$sOQL', '$sContext')"),
);
break;
case iPopupMenuExtension::MENU_OBJDETAILS_ACTIONS:
// $param is a DBObject
$oObj = $param;
$oFilter = DBobjectSearch::FromOQL("SELECT ".get_class($oObj)." WHERE id=".$oObj->GetKey());
$sFilter = $oFilter->serialize();
$sUrl = ApplicationContext::MakeObjectUrl(get_class($oObj), $oObj->GetKey());
$sUIPage = cmdbAbstractObject::ComputeStandardUIPage(get_class($oObj));
$oAppContext = new ApplicationContext();
$sContext = $oAppContext->GetForLink();
$aResult = array(
new SeparatorPopupMenuItem(),
// Static menus: Email this page & CSV Export
new URLPopupMenuItem('UI:Menu:EMail', Dict::S('UI:Menu:EMail'), "mailto:?subject=".urlencode($oObj->GetRawName())."&body=".urlencode($sUrl)),
new URLPopupMenuItem('UI:Menu:CSVExport', Dict::S('UI:Menu:CSVExport'), utils::GetAbsoluteUrlAppRoot()."pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv&{$sContext}"),
);
break;
case iPopupMenuExtension::MENU_DASHBOARD_ACTIONS:
// $param is a Dashboard
$oAppContext = new ApplicationContext();
$aParams = $oAppContext->GetAsHash();
$sMenuId = ApplicationMenu::GetActiveNodeId();
$sDlgTitle = addslashes(Dict::S('UI:ImportDashboardTitle'));
$sDlgText = addslashes(Dict::S('UI:ImportDashboardText'));
$sCloseBtn = addslashes(Dict::S('UI:Button:Cancel'));
$aResult = array(
new SeparatorPopupMenuItem(),
new URLPopupMenuItem('UI:ExportDashboard', Dict::S('UI:ExportDashBoard'), utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=export_dashboard&id='.$sMenuId),
new JSPopupMenuItem('UI:ImportDashboard', Dict::S('UI:ImportDashBoard'), "UploadDashboard({dashboard_id: '$sMenuId', title: '$sDlgTitle', text: '$sDlgText', close_btn: '$sCloseBtn' })"),
);
break;
/*
case iPopupMenuExtension::MENU_USER_ACTIONS:
// $param is null ??
$aResult = array(
new SeparatorPopupMenuItem(),
new JSPopupMenuItem('Test::Item1', 'Reset preferences...', "alert('Test 1')"),
new JSPopupMenuItem('Test::Item2', 'Do Something Stupid', "alert('Hey Dude !')"),
);
break;
*/
default:
// Unknown type of menu, do nothing
$aResult = array();
}
return $aResult;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Persistent class InputOutputTask * Persistent class InputOutputTask
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT.'/application/cmdbabstract.class.inc.php'); require_once(APPROOT.'/application/cmdbabstract.class.inc.php');

File diff suppressed because it is too large Load Diff

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Class iTopWizardWebPage * Class iTopWizardWebPage
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once('itopwebpage.class.inc.php'); require_once('itopwebpage.class.inc.php');

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Class LoginWebPage * Class LoginWebPage
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT."/application/nicewebpage.class.inc.php"); require_once(APPROOT."/application/nicewebpage.class.inc.php");
@@ -30,9 +29,7 @@ require_once(APPROOT."/application/nicewebpage.class.inc.php");
*/ */
class LoginWebPage extends NiceWebPage class LoginWebPage extends NiceWebPage
{ {
protected static $m_sLoginFailedMessage = '';
public function __construct() public function __construct()
{ {
parent::__construct("iTop Login"); parent::__construct("iTop Login");
@@ -92,11 +89,6 @@ EOF
); );
} }
public static function SetLoginFailedMessage($sMessage)
{
self::$m_sLoginFailedMessage = $sMessage;
}
public function DisplayLoginForm($sLoginType, $bFailedLogin = false) public function DisplayLoginForm($sLoginType, $bFailedLogin = false)
{ {
switch($sLoginType) switch($sLoginType)
@@ -122,20 +114,12 @@ EOF
$sAuthPwd = utils::ReadParam('suggest_pwd', '', true, 'raw_data'); $sAuthPwd = utils::ReadParam('suggest_pwd', '', true, 'raw_data');
$sVersionShort = Dict::Format('UI:iTopVersion:Short', ITOP_VERSION); $sVersionShort = Dict::Format('UI:iTopVersion:Short', ITOP_VERSION);
$sIconUrl = Utils::GetConfig()->Get('app_icon_url'); $this->add("<div id=\"login-logo\"><a href=\"http://www.combodo.com/itop\"><img title=\"$sVersionShort\" src=\"../images/itop-logo-external.png\"></a></div>\n");
$this->add("<div id=\"login-logo\"><a href=\"".htmlentities($sIconUrl, ENT_QUOTES, 'UTF-8')."\"><img title=\"$sVersionShort\" src=\"../images/itop-logo-external.png\"></a></div>\n");
$this->add("<div id=\"login\">\n"); $this->add("<div id=\"login\">\n");
$this->add("<h1>".Dict::S('UI:Login:Welcome')."</h1>\n"); $this->add("<h1>".Dict::S('UI:Login:Welcome')."</h1>\n");
if ($bFailedLogin) if ($bFailedLogin)
{ {
if (self::$m_sLoginFailedMessage != '') $this->add("<p class=\"hilite\">".Dict::S('UI:Login:IncorrectLoginPassword')."</p>\n");
{
$this->add("<p class=\"hilite\">".self::$m_sLoginFailedMessage."</p>\n");
}
else
{
$this->add("<p class=\"hilite\">".Dict::S('UI:Login:IncorrectLoginPassword')."</p>\n");
}
} }
else else
{ {
@@ -149,7 +133,6 @@ EOF
$this->add("</table>\n"); $this->add("</table>\n");
$this->add("<input type=\"hidden\" name=\"loginop\" value=\"login\" />\n"); $this->add("<input type=\"hidden\" name=\"loginop\" value=\"login\" />\n");
$this->add("</form>\n"); $this->add("</form>\n");
$this->add(Dict::S('UI:Login:About'));
$this->add("</div>\n"); $this->add("</div>\n");
break; break;
} }
@@ -178,8 +161,7 @@ function DoCheckPwd()
} }
EOF EOF
); );
$sIconUrl = Utils::GetConfig()->Get('app_icon_url'); $this->add("<div id=\"login-logo\"><a href=\"http://www.combodo.com/itop\"><img title=\"$sVersionShort\" src=\"../images/itop-logo.png\"></a></div>\n");
$this->add("<div id=\"login-logo\"><a href=\"".htmlentities($sIconUrl, ENT_QUOTES, 'UTF-8')."\"><img title=\"$sVersionShort\" src=\"../images/itop-logo.png\"></a></div>\n");
$this->add("<div id=\"login\">\n"); $this->add("<div id=\"login\">\n");
$this->add("<h1>".Dict::S('UI:Login:ChangeYourPassword')."</h1>\n"); $this->add("<h1>".Dict::S('UI:Login:ChangeYourPassword')."</h1>\n");
if ($bFailedLogin) if ($bFailedLogin)
@@ -209,10 +191,15 @@ EOF
$sPreviousLoginMode = ''; $sPreviousLoginMode = '';
} }
// Unset all of the session variables. // Unset all of the session variables.
unset($_SESSION['auth_user']); $_SESSION = array();
unset($_SESSION['login_mode']);
// If it's desired to kill the session, also delete the session cookie. // If it's desired to kill the session, also delete the session cookie.
// Note: This will destroy the session, and not just the session data! // Note: This will destroy the session, and not just the session data!
if (isset($_COOKIE[session_name()]))
{
setcookie(session_name(), '', time()-3600, '/');
}
// Finally, destroy the session.
session_destroy();
} }
static function SecureConnectionRequired() static function SecureConnectionRequired()
@@ -263,17 +250,106 @@ EOF
// check CAS authentication // check CAS authentication
if (phpCAS::isAuthenticated()) if (phpCAS::isAuthenticated())
{ {
$sAuthUser = phpCAS::getUser(); // Check is a membership is required
$sAuthPwd = ''; $sCASMemberships = MetaModel::GetConfig()->Get('cas_memberof');
$sLoginMode = 'cas'; $bFound = false;
$sAuthentication = 'external'; if (!empty($sCASMemberships))
{
if (phpCAS::hasAttribute('memberOf'))
{
// A list of groups is specified, the user must a be member of (at least) one of them to pass
$aCASMemberships = array();
$aTmp = explode(';', $sCASMemberships);
setlocale(LC_ALL, "en_US.utf8"); // !!! WARNING: this is needed to have the iconv //TRANSLIT working fine below !!!
foreach($aTmp as $sGroupName)
{
$aCASMemberships[] = trim(iconv('UTF-8', 'ASCII//TRANSLIT', $sGroupName)); // Just in case remove accents and spaces...
}
$aMemberOf = phpCAS::getAttribute('memberOf');
if (!is_array($aMemberOf)) $aMemberOf = array($aMemberOf); // Just one entry, turn it into an array
$aFilteredGroupNames = array();
foreach($aMemberOf as $sGroupName)
{
phpCAS::log("Info: user if a member of the group: ".$sGroupName);
$sGroupName = trim(iconv('UTF-8', 'ASCII//TRANSLIT', $sGroupName)); // Remove accents and spaces as well
$aFilteredGroupNames[] = $sGroupName;
$bIsMember = false;
foreach($aCASMemberships as $sCASPattern)
{
if (self::IsPattern($sCASPattern))
{
if (preg_match($sCASPattern, $sGroupName))
{
$bIsMember = true;
break;
}
}
else if ($sPattern == $sGroupName)
{
$bIsMember = true;
break;
}
}
if ($bIsMember)
{
$bCASUserSynchro = MetaModel::GetConfig()->Get('cas_user_synchro');
if ($bCASUserSynchro)
{
// If needed create a new user for this email/profile
phpCAS::log('Info: cas_user_synchro is ON');
self::CreateCASUser(phpCAS::getUser(), $aMemberOf);
}
else
{
phpCAS::log('Info: cas_user_synchro is OFF');
}
$bFound = true;
break;
}
}
if(!$bFound)
{
phpCAS::log("User ".phpCAS::getUser().", none of his/her groups (".implode('; ', $aFilteredGroupNames).") match any of the required groups: ".implode('; ', $aCASMemberships));
}
}
else
{
// Too bad, the user is not part of any of the group => not allowed
phpCAS::log("No 'memberOf' attribute found for user ".phpCAS::getUser().". Are you using the SAML protocol (S1) ?");
}
}
else
{
// No membership required, anybody will pass
$bFound = true;
}
if ($bFound)
{
$sAuthUser = phpCAS::getUser();
$sAuthPwd = '';
$sLoginMode = 'cas';
$sAuthentication = 'external';
}
else
{
// The user is not part of the allowed groups, => log out
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php';
$sCASLogoutUrl = MetaModel::GetConfig()->Get('cas_logout_redirect_service');
if (empty($sCASLogoutUrl))
{
$sCASLogoutUrl = $sUrl;
}
phpCAS::logoutWithRedirectService($sCASLogoutUrl); // Redirects to the CAS logout page
}
} }
break; break;
case 'form': case 'form':
// iTop standard mode: form based authentication // iTop standard mode: form based authentication
$sAuthUser = utils::ReadPostedParam('auth_user', '', false, 'raw_data'); $sAuthUser = utils::ReadPostedParam('auth_user', '', 'raw_data');
$sAuthPwd = utils::ReadPostedParam('auth_pwd', '', false, 'raw_data'); $sAuthPwd = utils::ReadPostedParam('auth_pwd', '', 'raw_data');
if ($sAuthUser != '') if ($sAuthUser != '')
{ {
$sLoginMode = 'form'; $sLoginMode = 'form';
@@ -312,9 +388,9 @@ EOF
case 'url': case 'url':
// Credentials passed directly in the url // Credentials passed directly in the url
$sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data'); $sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data');
$sAuthPwd = utils::ReadParam('auth_pwd', null, false, 'raw_data'); if ($sAuthUser != '')
if (($sAuthUser != '') && ($sAuthPwd != null))
{ {
$sAuthPwd = utils::ReadParam('auth_pwd', '', false, 'raw_data');
$sLoginMode = 'url'; $sLoginMode = 'url';
} }
break; break;
@@ -341,7 +417,7 @@ EOF
} }
else else
{ {
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, $sLoginMode, $sAuthentication)) if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, $sAuthentication))
{ {
//echo "Check Credentials returned false for user $sAuthUser!"; //echo "Check Credentials returned false for user $sAuthUser!";
self::ResetSession(); self::ResetSession();
@@ -382,6 +458,8 @@ EOF
{ {
$sMessage = ''; // In case we need to return a message to the calling web page $sMessage = ''; // In case we need to return a message to the calling web page
$operation = utils::ReadParam('loginop', ''); $operation = utils::ReadParam('loginop', '');
session_name(MetaModel::GetConfig()->Get('session_name'));
session_start();
if ($operation == 'logoff') if ($operation == 'logoff')
{ {
@@ -420,8 +498,8 @@ EOF
{ {
$sAuthUser = $_SESSION['auth_user']; $sAuthUser = $_SESSION['auth_user'];
UserRights::Login($sAuthUser); // Set the user's language UserRights::Login($sAuthUser); // Set the user's language
$sOldPwd = utils::ReadPostedParam('old_pwd', '', false, 'raw_data'); $sOldPwd = utils::ReadPostedParam('old_pwd', 'raw_data');
$sNewPwd = utils::ReadPostedParam('new_pwd', '', false, 'raw_data'); $sNewPwd = utils::ReadPostedParam('new_pwd', 'raw_data');
if (UserRights::CanChangePassword() && ((!UserRights::CheckCredentials($sAuthUser, $sOldPwd)) || (!UserRights::ChangePassword($sOldPwd, $sNewPwd)))) if (UserRights::CanChangePassword() && ((!UserRights::CheckCredentials($sAuthUser, $sOldPwd)) || (!UserRights::ChangePassword($sOldPwd, $sNewPwd))))
{ {
$oPage = new LoginWebPage(); $oPage = new LoginWebPage();
@@ -436,7 +514,7 @@ EOF
if ($bMustBeAdmin && !UserRights::IsAdministrator()) if ($bMustBeAdmin && !UserRights::IsAdministrator())
{ {
require_once(APPROOT.'/setup/setuppage.class.inc.php'); require_once(APPROOT.'/setup/setuppage.class.inc.php');
$oP = new SetupPage(Dict::S('UI:PageTitle:FatalError')); $oP = new SetupWebPage(Dict::S('UI:PageTitle:FatalError'));
$oP->add("<h1>".Dict::S('UI:Login:Error:AccessAdmin')."</h1>\n"); $oP->add("<h1>".Dict::S('UI:Login:Error:AccessAdmin')."</h1>\n");
$oP->p("<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/logoff.php\">".Dict::S('UI:LogOffMenu')."</a>"); $oP->p("<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/logoff.php\">".Dict::S('UI:LogOffMenu')."</a>");
$oP->output(); $oP->output();
@@ -448,6 +526,124 @@ EOF
header('Location: '.utils::GetAbsoluteUrlAppRoot().'portal/index.php'); header('Location: '.utils::GetAbsoluteUrlAppRoot().'portal/index.php');
} }
return $sMessage; return $sMessage;
} }
protected static function CreateCASUser($sEmail, $aGroups)
{
if (!MetaModel::IsValidClass('URP_Profiles'))
{
phpCAS::log("URP_Profiles is not a valid class. Automatic creation of Users is not supported in this context, sorry.");
return;
}
// read all the existing profiles
$oProfilesSearch = new DBObjectSearch('URP_Profiles');
$oProfilesSet = new DBObjectSet($oProfilesSearch);
$aAllProfiles = array();
while($oProfile = $oProfilesSet->Fetch())
{
$aAllProfiles[strtolower($oProfile->GetName())] = $oProfile->GetKey();
}
// Translate the CAS/LDAP group names into iTop profile names
$aProfiles = array();
$sPattern = MetaModel::GetConfig()->Get('cas_profile_pattern');
foreach($aGroups as $sGroupName)
{
if (preg_match($sPattern, $sGroupName, $aMatches))
{
if (array_key_exists(strtolower($aMatches[1]), $aAllProfiles))
{
$aProfiles[] = $aAllProfiles[strtolower($aMatches[1])];
}
else
{
phpCAS::log("Warning: {$aMatches[1]} is not a valid iTop profile (extracted from group name: '$sGroupName'). Ignored.");
}
}
}
if (count($aProfiles) == 0)
{
phpCAS::log("Error: no group name matches the pattern: '$sPattern'. The user '$sEmail' has no profiles in iTop, and therefore cannot be created.");
return;
}
$oUser = MetaModel::GetObjectByName('UserExternal', $sEmail, false);
if ($oUser == null)
{
// Create the user, link it to a contact
phpCAS::log("Info: the user '$sEmail' does not exist. A new UserExternal will be created.");
$oSearch = new DBObjectSearch('Person');
$oSearch->AddCondition('email', $sEmail);
$oSet = new DBObjectSet($oSearch);
$iContactId = 0;
switch($oSet->Count())
{
case 0:
phpCAS::log("Error: found no contact with the email: '$sEmail'. Cannot create the user in iTop.");
return;
case 1:
$oContact = $oSet->Fetch();
$iContactId = $oContact->GetKey();
phpCAS::log("Info: Found 1 contact '".$oContact->GetName()."' (id=$iContactId) corresponding to the email '$sEmail'.");
break;
default:
phpCAS::log("Error: ".$oSet->Count()." contacts have the same email: '$sEmail'. Cannot create a user for this email.");
return;
}
$oUser = new UserExternal();
$oUser->Set('login', $sEmail);
$oUser->Set('contactid', $iContactId);
$oUser->Set('language', MetaModel::GetConfig()->GetDefaultLanguage());
}
else
{
phpCAS::log("Info: the user '$sEmail' already exists (id=".$oUser->GetKey().").");
}
// Now synchronize the profiles
$oProfilesSet = DBObjectSet::FromScratch('URP_UserProfile');
foreach($aProfiles as $iProfileId)
{
$oLink = new URP_UserProfile();
$oLink->Set('profileid', $iProfileId);
$oLink->Set('reason', 'CAS/LDAP Synchro');
$oProfilesSet->AddObject($oLink);
}
$oUser->Set('profile_list', $oProfilesSet);
phpCAS::log("Info: the user $sEmail (id=".$oUser->GetKey().") now has the following profiles: '".implode("', '", $aProfiles)."'.");
if ($oUser->IsNew() || $oUser->IsModified())
{
$oMyChange = MetaModel::NewObject("CMDBChange");
$oMyChange->Set("date", time());
$oMyChange->Set("userinfo", 'CAS/LDAP Synchro');
$oMyChange->DBInsert();
if ($oUser->IsNew())
{
$oUser->DBInsertTracked($oMyChange);
}
else
{
$oUser->DBUpdateTracked($oMyChange);
}
}
}
protected static function IsPattern($sCASPattern)
{
if ((substr($sCASPattern, 0, 1) == '/') && (substr($sCASPattern, -1) == '/'))
{
// the string is enclosed by slashes, let's assume it's a pattern
return true;
}
else
{
return false;
}
}
} // End of class } // End of class
?> ?>

View File

@@ -1,32 +1,30 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Construction and display of the application's main menu * Construction and display of the application's main menu
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT.'/application/utils.inc.php'); require_once(APPROOT.'/application/utils.inc.php');
require_once(APPROOT.'/application/template.class.inc.php'); require_once(APPROOT.'/application/template.class.inc.php');
require_once(APPROOT."/application/user.dashboard.class.inc.php");
/** /**
@@ -61,38 +59,10 @@ require_once(APPROOT."/application/user.dashboard.class.inc.php");
class ApplicationMenu class ApplicationMenu
{ {
static $bAdditionalMenusLoaded = false;
static $aRootMenus = array(); static $aRootMenus = array();
static $aMenusIndex = array(); static $aMenusIndex = array();
static $sFavoriteSiloQuery = 'SELECT Organization'; static $sFavoriteSiloQuery = 'SELECT Organization';
static public function LoadAdditionalMenus()
{
if (!self::$bAdditionalMenusLoaded)
{
// Build menus from module handlers
//
foreach(get_declared_classes() as $sPHPClass)
{
if (is_subclass_of($sPHPClass, 'ModuleHandlerAPI'))
{
$aCallSpec = array($sPHPClass, 'OnMenuCreation');
call_user_func($aCallSpec);
}
}
// Build menus from the menus themselves (e.g. the ShortcutContainerMenuNode will do that)
//
foreach(self::$aRootMenus as $aMenu)
{
$oMenuNode = self::GetMenuNode($aMenu['index']);
$oMenuNode->PopulateChildMenus();
}
self::$bAdditionalMenusLoaded = true;
}
}
/** /**
* Set the query used to limit the list of displayed organizations in the drop-down menu * Set the query used to limit the list of displayed organizations in the drop-down menu
* @param $sOQL string The OQL query returning a list of Organization objects * @param $sOQL string The OQL query returning a list of Organization objects
@@ -117,59 +87,35 @@ class ApplicationMenu
* Main function to add a menu entry into the application, can be called during the definition * Main function to add a menu entry into the application, can be called during the definition
* of the data model objects * of the data model objects
*/ */
static public function InsertMenu(MenuNode $oMenuNode, $iParentIndex, $fRank) static public function InsertMenu(MenuNode $oMenuNode, $iParentIndex = -1, $fRank)
{ {
$index = self::GetMenuIndexById($oMenuNode->GetMenuId()); $index = self::GetMenuIndexById($oMenuNode->GetMenuId());
if ($index == -1) if ($index == -1)
{ {
// The menu does not already exist, insert it // The menu does not already exist, insert it
$index = count(self::$aMenusIndex); $index = count(self::$aMenusIndex);
self::$aMenusIndex[$index] = array( 'node' => $oMenuNode, 'children' => array());
if ($iParentIndex == -1) if ($iParentIndex == -1)
{ {
$sParentId = '';
self::$aRootMenus[] = array ('rank' => $fRank, 'index' => $index); self::$aRootMenus[] = array ('rank' => $fRank, 'index' => $index);
} }
else else
{ {
$sParentId = self::$aMenusIndex[$iParentIndex]['node']->GetMenuId();
self::$aMenusIndex[$iParentIndex]['children'][] = array ('rank' => $fRank, 'index' => $index); self::$aMenusIndex[$iParentIndex]['children'][] = array ('rank' => $fRank, 'index' => $index);
} }
// Note: At the time when 'parent', 'rank' and 'source_file' have been added for the reflection API,
// they were not used to display the menus (redundant or unused)
//
$aBacktrace = debug_backtrace();
$sFile = isset($aBacktrace[2]["file"]) ? $aBacktrace[2]["file"] : $aBacktrace[1]["file"];
self::$aMenusIndex[$index] = array('node' => $oMenuNode, 'children' => array(), 'parent' => $sParentId, 'rank' => $fRank, 'source_file' => $sFile);
}
else
{
// the menu already exists, let's combine the conditions that make it visible
self::$aMenusIndex[$index]['node']->AddCondition($oMenuNode);
} }
return $index; return $index;
} }
/**
* Reflection API - Get menu entries
*/
static public function ReflectionMenuNodes()
{
self::LoadAdditionalMenus();
return self::$aMenusIndex;
}
/** /**
* Entry point to display the whole menu into the web page, used by iTopWebPage * Entry point to display the whole menu into the web page, used by iTopWebPage
*/ */
static public function DisplayMenu($oPage, $aExtraParams) static public function DisplayMenu(iTopWebPage $oPage, $aExtraParams)
{ {
self::LoadAdditionalMenus();
// Sort the root menu based on the rank // Sort the root menu based on the rank
usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank')); usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank'));
$iAccordion = 0; $iAccordion = 0;
$iActiveMenu = self::GetMenuIndexById(self::GetActiveNodeId()); $iActiveMenu = ApplicationMenu::GetActiveNodeId();
foreach(self::$aRootMenus as $aMenu) foreach(self::$aRootMenus as $aMenu)
{ {
$oMenuNode = self::GetMenuNode($aMenu['index']); $oMenuNode = self::GetMenuNode($aMenu['index']);
@@ -262,11 +208,11 @@ class ApplicationMenu
/** /**
* Helper function to get the list of child(ren) of a menu * Helper function to get the list of child(ren) of a menu
*/ */
static public function GetChildren($index) static protected function GetChildren($index)
{ {
return self::$aMenusIndex[$index]['children']; return self::$aMenusIndex[$index]['children'];
} }
/** /**
* Helper function to get the ID of a menu based on its name * Helper function to get the ID of a menu based on its name
* @param string $sTitle Title of the menu (as passed when creating the menu) * @param string $sTitle Title of the menu (as passed when creating the menu)
@@ -288,21 +234,22 @@ class ApplicationMenu
/** /**
* Retrieves the currently active menu (if any, otherwise the first menu is the default) * Retrieves the currently active menu (if any, otherwise the first menu is the default)
* @return string The Id of the currently active menu * @return MenuNode or null if there is no menu at all !
*/ */
static public function GetActiveNodeId() static public function GetActiveNodeId()
{ {
$oAppContext = new ApplicationContext(); $oAppContext = new ApplicationContext();
$sMenuId = $oAppContext->GetCurrentValue('menu', null); $iMenuIndex = $oAppContext->GetCurrentValue('menu', -1);
if ($sMenuId === null)
if ($iMenuIndex == -1)
{ {
// Make sure the root menu is sorted on 'rank' // Make sure the root menu is sorted on 'rank'
usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank')); usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank'));
$oFirstGroup = self::GetMenuNode(self::$aRootMenus[0]['index']); $oFirstGroup = self::GetMenuNode(self::$aRootMenus[0]['index']);
$oMenuNode = self::GetMenuNode(self::$aMenusIndex[$oFirstGroup->GetIndex()]['children'][0]['index']); $oMenuNode = self::GetMenuNode(self::$aMenusIndex[$oFirstGroup->GetIndex()]['children'][0]['index']);
$sMenuId = $oMenuNode->GetMenuId(); $iMenuIndex = $oMenuNode->GetIndex();
} }
return $sMenuId; return $iMenuIndex;
} }
} }
@@ -337,30 +284,25 @@ abstract class MenuNode
protected $sMenuId; protected $sMenuId;
protected $index; protected $index;
/**
* Properties reflecting how the node has been declared
*/
protected $aReflectionProperties;
/** /**
* Class of objects to check if the menu is enabled, null if none * Class of objects to check if the menu is enabled, null if none
*/ */
protected $m_aEnableClasses; protected $m_sEnableClass;
/** /**
* User Rights Action code to check if the menu is enabled, null if none * User Rights Action code to check if the menu is enabled, null if none
*/ */
protected $m_aEnableActions; protected $m_iEnableAction;
/** /**
* User Rights allowed results (actually a bitmask) to check if the menu is enabled, null if none * User Rights allowed results (actually a bitmask) to check if the menu is enabled, null if none
*/ */
protected $m_aEnableActionResults; protected $m_iEnableActionResults;
/** /**
* Stimulus to check: if the user can 'apply' this stimulus, then she/he can see this menu * Stimulus to check: if the user can 'apply' this stimulus, then she/he can see this menu
*/ */
protected $m_aEnableStimuli; protected $m_sEnableStimulus;
/** /**
* Create a menu item, sets the condition to have it displayed and inserts it into the application's main menu * Create a menu item, sets the condition to have it displayed and inserts it into the application's main menu
@@ -376,25 +318,12 @@ abstract class MenuNode
public function __construct($sMenuId, $iParentIndex = -1, $fRank = 0, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null) public function __construct($sMenuId, $iParentIndex = -1, $fRank = 0, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
{ {
$this->sMenuId = $sMenuId; $this->sMenuId = $sMenuId;
$this->aReflectionProperties = array(); $this->m_sEnableClass = $sEnableClass;
if (strlen($sEnableClass) > 0) $this->m_iEnableAction = $iActionCode;
{ $this->m_iEnableActionResults = $iAllowedResults;
$this->aReflectionProperties['enable_class'] = $sEnableClass; $this->m_sEnableStimulus = $sEnableStimulus;
$this->aReflectionProperties['enable_action'] = $iActionCode;
$this->aReflectionProperties['enable_permission'] = $iAllowedResults;
$this->aReflectionProperties['enable_stimulus'] = $sEnableStimulus;
}
$this->m_aEnableClasses = array($sEnableClass);
$this->m_aEnableActions = array($iActionCode);
$this->m_aEnableActionResults = array($iAllowedResults);
$this->m_aEnableStimuli = array($sEnableStimulus);
$this->index = ApplicationMenu::InsertMenu($this, $iParentIndex, $fRank); $this->index = ApplicationMenu::InsertMenu($this, $iParentIndex, $fRank);
} }
public function ReflectionProperties()
{
return $this->aReflectionProperties;
}
public function GetMenuId() public function GetMenuId()
{ {
@@ -403,12 +332,12 @@ abstract class MenuNode
public function GetTitle() public function GetTitle()
{ {
return Dict::S("Menu:$this->sMenuId", str_replace('_', ' ', $this->sMenuId)); return Dict::S("Menu:$this->sMenuId");
} }
public function GetLabel() public function GetLabel()
{ {
return Dict::S("Menu:$this->sMenuId+", ""); return Dict::S("Menu:$this->sMenuId+");
} }
public function GetIndex() public function GetIndex()
@@ -416,70 +345,44 @@ abstract class MenuNode
return $this->index; return $this->index;
} }
public function PopulateChildMenus()
{
foreach (ApplicationMenu::GetChildren($this->GetIndex()) as $aMenu)
{
$index = $aMenu['index'];
$oMenu = ApplicationMenu::GetMenuNode($index);
$oMenu->PopulateChildMenus();
}
}
public function GetHyperlink($aExtraParams) public function GetHyperlink($aExtraParams)
{ {
$aExtraParams['c[menu]'] = $this->GetMenuId(); $aExtraParams['c[menu]'] = $this->GetIndex();
return $this->AddParams(utils::GetAbsoluteUrlAppRoot().'pages/UI.php', $aExtraParams); return $this->AddParams(utils::GetAbsoluteUrlAppRoot().'pages/UI.php', $aExtraParams);
} }
/**
* Add a limiting display condition for the same menu node. The conditions will be combined with a AND
* @param $oMenuNode MenuNode Another definition of the same menu node, with potentially different access restriction
* @return void
*/
public function AddCondition(MenuNode $oMenuNode)
{
foreach($oMenuNode->m_aEnableClasses as $index => $sClass )
{
$this->m_aEnableClasses[] = $sClass;
$this->m_aEnableActions[] = $oMenuNode->m_aEnableActions[$index];
$this->m_aEnableActionResults[] = $oMenuNode->m_aEnableActionResults[$index];
$this->m_aEnableStimuli[] = $oMenuNode->m_aEnableStimuli[$index];
}
}
/** /**
* Tells whether the menu is enabled (i.e. displayed) for the current user * Tells whether the menu is enabled (i.e. displayed) for the current user
* @return bool True if enabled, false otherwise * @return bool True if enabled, false otherwise
*/ */
public function IsEnabled() public function IsEnabled()
{ {
foreach($this->m_aEnableClasses as $index => $sClass) if ($this->m_sEnableClass != null)
{ {
if ($sClass != null) if (MetaModel::IsValidClass($this->m_sEnableClass))
{ {
if (MetaModel::IsValidClass($sClass)) if ($this->m_sEnableStimulus != null)
{ {
if ($this->m_aEnableStimuli[$index] != null) if (!UserRights::IsStimulusAllowed($this->m_sEnableClass, $this->m_sEnableStimulus))
{ {
if (!UserRights::IsStimulusAllowed($sClass, $this->m_aEnableStimuli[$index])) return false;
{
return false;
}
}
if ($this->m_aEnableActions[$index] != null)
{
$iResult = UserRights::IsActionAllowed($sClass, $this->m_aEnableActions[$index]);
if (!($iResult & $this->m_aEnableActionResults[$index]))
{
return false;
}
} }
} }
else if ($this->m_iEnableAction != null)
{ {
return false; $iResult = UserRights::IsActionAllowed($this->m_sEnableClass, $this->m_iEnableAction);
if (($iResult & $this->m_iEnableActionResults))
{
return true;
}
else
{
return false;
}
} }
return true;
} }
return false;
} }
return true; return true;
} }
@@ -555,7 +458,6 @@ class TemplateMenuNode extends MenuNode
{ {
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus); parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
$this->sTemplateFile = $sTemplateFile; $this->sTemplateFile = $sTemplateFile;
$this->aReflectionProperties['template_file'] = $sTemplateFile;
} }
public function GetHyperlink($aExtraParams) public function GetHyperlink($aExtraParams)
@@ -569,7 +471,6 @@ class TemplateMenuNode extends MenuNode
$sTemplate = @file_get_contents($this->sTemplateFile); $sTemplate = @file_get_contents($this->sTemplateFile);
if ($sTemplate !== false) if ($sTemplate !== false)
{ {
$aExtraParams['table_id'] = 'Menu_'.$this->GetMenuId();
$oTemplate = new DisplayTemplate($sTemplate); $oTemplate = new DisplayTemplate($sTemplate);
$oTemplate->Render($oPage, $aExtraParams); $oTemplate->Render($oPage, $aExtraParams);
} }
@@ -615,8 +516,6 @@ class OQLMenuNode extends MenuNode
$this->sOQL = $sOQL; $this->sOQL = $sOQL;
$this->bSearch = $bSearch; $this->bSearch = $bSearch;
$this->m_aParams = array(); $this->m_aParams = array();
$this->aReflectionProperties['oql'] = $sOQL;
$this->aReflectionProperties['do_search'] = $bSearch;
// Enhancement: we could set as the "enable" condition that the user has enough rights to "read" the objects // Enhancement: we could set as the "enable" condition that the user has enough rights to "read" the objects
// of the class specified by the OQL... // of the class specified by the OQL...
} }
@@ -628,47 +527,47 @@ class OQLMenuNode extends MenuNode
public function SetParameters($aParams) public function SetParameters($aParams)
{ {
$this->m_aParams = $aParams; $this->m_aParams = $aParams;
foreach($aParams as $sKey => $value)
{
$this->aReflectionProperties[$sKey] = $value;
}
} }
public function RenderContent(WebPage $oPage, $aExtraParams = array()) public function RenderContent(WebPage $oPage, $aExtraParams = array())
{ {
OQLMenuNode::RenderOQLSearch $aExtraParams = array_merge($aExtraParams, $this->m_aParams);
( try
$this->sOQL,
Dict::S($this->sPageTitle),
'Menu_'.$this->GetMenuId(),
$this->bSearch, // Search pane
true, // Search open
$oPage,
array_merge($this->m_aParams, $aExtraParams)
);
}
public static function RenderOQLSearch($sOql, $sTitle, $sUsageId, $bSearchPane, $bSearchOpen, WebPage $oPage, $aExtraParams = array())
{
$sUsageId = utils::GetSafeId($sUsageId);
$oSearch = DBObjectSearch::FromOQL($sOql);
$sIcon = MetaModel::GetClassIcon($oSearch->GetClass());
if ($bSearchPane)
{ {
$aParams = array_merge(array('open' => $bSearchOpen, 'table_id' => $sUsageId), $aExtraParams); $oSearch = DBObjectSearch::FromOQL($this->sOQL);
$oBlock = new DisplayBlock($oSearch, 'search', false /* Asynchronous */, $aParams); $sIcon = MetaModel::GetClassIcon($oSearch->GetClass());
$oBlock->Display($oPage, 0);
} }
catch(Exception $e)
$oPage->add("<p class=\"page-header\">$sIcon ".Dict::S($sTitle)."</p>"); {
$sIcon = '';
$aParams = array_merge(array('table_id' => $sUsageId), $aExtraParams); }
$oBlock = new DisplayBlock($oSearch, 'list', false /* Asynchronous */, $aParams); // The standard template used for all such pages: a (closed) search form at the top and a list of results at the bottom
$oBlock->Display($oPage, $sUsageId); $sTemplate = '';
if ($this->bSearch)
{
$sTemplate .= <<<EOF
<itopblock BlockClass="DisplayBlock" type="search" asynchronous="false" encoding="text/oql">$this->sOQL</itopblock>
EOF;
}
$sParams = '';
if (!empty($this->m_aParams))
{
$sParams = 'parameters="';
foreach($this->m_aParams as $sName => $sValue)
{
$sParams .= $sName.':'.$sValue.';';
}
$sParams .= '"';
}
$sTemplate .= <<<EOF
<p class="page-header">$sIcon<itopstring>$this->sPageTitle</itopstring></p>
<itopblock BlockClass="DisplayBlock" type="list" asynchronous="false" encoding="text/oql" $sParams>$this->sOQL</itopblock>
EOF;
$oTemplate = new DisplayTemplate($sTemplate);
$oTemplate->Render($oPage, $aExtraParams);
} }
} }
/** /**
* This class defines a menu item that displays a search form for the given class of objects * This class defines a menu item that displays a search form for the given class of objects
*/ */
@@ -694,15 +593,16 @@ class SearchMenuNode extends MenuNode
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus); parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
$this->sPageTitle = "Menu:$sMenuId+"; $this->sPageTitle = "Menu:$sMenuId+";
$this->sClass = $sClass; $this->sClass = $sClass;
$this->aReflectionProperties['class'] = $sClass;
} }
public function RenderContent(WebPage $oPage, $aExtraParams = array()) public function RenderContent(WebPage $oPage, $aExtraParams = array())
{ {
$oSearch = new DBObjectSearch($this->sClass); // The standard template used for all such pages: an open search form at the top
$aParams = array_merge(array('open' => true, 'table_id' => 'Menu_'.utils::GetSafeId($this->GetMenuId())), $aExtraParams); $sTemplate = <<<EOF
$oBlock = new DisplayBlock($oSearch, 'search', false /* Asynchronous */, $aParams); <itopblock BlockClass="DisplayBlock" type="search" asynchronous="false" encoding="text/oql" parameters="open:true">SELECT $this->sClass</itopblock>
$oBlock->Display($oPage, 0); EOF;
$oTemplate = new DisplayTemplate($sTemplate);
$oTemplate->Render($oPage, $aExtraParams);
} }
} }
@@ -732,12 +632,11 @@ class WebPageMenuNode extends MenuNode
{ {
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus); parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
$this->sHyperlink = $sHyperlink; $this->sHyperlink = $sHyperlink;
$this->aReflectionProperties['url'] = $sHyperlink;
} }
public function GetHyperlink($aExtraParams) public function GetHyperlink($aExtraParams)
{ {
$aExtraParams['c[menu]'] = $this->GetMenuId(); $aExtraParams['c[menu]'] = $this->GetIndex();
return $this->AddParams( $this->sHyperlink, $aExtraParams); return $this->AddParams( $this->sHyperlink, $aExtraParams);
} }
@@ -770,13 +669,12 @@ class NewObjectMenuNode extends MenuNode
{ {
parent::__construct($sMenuId, $iParentIndex, $fRank); parent::__construct($sMenuId, $iParentIndex, $fRank);
$this->sClass = $sClass; $this->sClass = $sClass;
$this->aReflectionProperties['class'] = $sClass;
} }
public function GetHyperlink($aExtraParams) public function GetHyperlink($aExtraParams)
{ {
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=new&class='.$this->sClass; $sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=new&class='.$this->sClass;
$aExtraParams['c[menu]'] = $this->GetMenuId(); $aExtraParams['c[menu]'] = $this->GetIndex();
return $this->AddParams($sHyperlink, $aExtraParams); return $this->AddParams($sHyperlink, $aExtraParams);
} }
@@ -807,208 +705,4 @@ class NewObjectMenuNode extends MenuNode
assert(false); // Shall never be called, the external web page will handle the display by itself assert(false); // Shall never be called, the external web page will handle the display by itself
} }
} }
?>
require_once(APPROOT.'application/dashboard.class.inc.php');
/**
* This class defines a menu item which content is based on XML dashboard.
*/
class DashboardMenuNode extends MenuNode
{
protected $sDashboardFile;
/**
* Create a menu item based on a custom template and inserts it into the application's main menu
* @param string $sMenuId Unique identifier of the menu (used to identify the menu for bookmarking, and for getting the labels from the dictionary)
* @param string $sTemplateFile Path (or URL) to the file that will be used as a template for displaying the page's content
* @param integer $iParentIndex ID of the parent menu
* @param float $fRank Number used to order the list, any number will do, but for a given level (i.e same parent) all menus are sorted based on this value
* @param string $sEnableClass Name of class of object
* @param integer $iActionCode Either UR_ACTION_READ, UR_ACTION_MODIFY, UR_ACTION_DELETE, UR_ACTION_BULKREAD, UR_ACTION_BULKMODIFY or UR_ACTION_BULKDELETE
* @param integer $iAllowedResults Expected "rights" for the action: either UR_ALLOWED_YES, UR_ALLOWED_NO, UR_ALLOWED_DEPENDS or a mix of them...
* @return MenuNode
*/
public function __construct($sMenuId, $sDashboardFile, $iParentIndex, $fRank = 0, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
{
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
$this->sDashboardFile = $sDashboardFile;
$this->aReflectionProperties['definition_file'] = $sDashboardFile;
}
public function GetHyperlink($aExtraParams)
{
if ($this->sDashboardFile == '') return '';
return parent::GetHyperlink($aExtraParams);
}
public function GetDashboard()
{
$sDashboardDefinition = @file_get_contents($this->sDashboardFile);
if ($sDashboardDefinition !== false)
{
$bCustomized = false;
// Search for an eventual user defined dashboard, overloading the existing one
$oUDSearch = new DBObjectSearch('UserDashboard');
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oUDSearch->AddCondition('menu_code', $this->sMenuId, '=');
$oUDSet = new DBObjectSet($oUDSearch);
if ($oUDSet->Count() > 0)
{
// Assuming there is at most one couple {user, menu}!
$oUserDashboard = $oUDSet->Fetch();
$sDashboardDefinition = $oUserDashboard->Get('contents');
$bCustomized = true;
}
$oDashboard = new RuntimeDashboard($this->sMenuId);
$oDashboard->FromXml($sDashboardDefinition);
$oDashboard->SetCustomFlag($bCustomized);
}
else
{
$oDashboard = null;
}
return $oDashboard;
}
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
$oDashboard = $this->GetDashboard();
if ($oDashboard != null)
{
$oDashboard->Render($oPage, false, $aExtraParams);
$bEdit = utils::ReadParam('edit', false);
if ($bEdit)
{
$sId = addslashes($this->sMenuId);
$oPage->add_ready_script("EditDashboard('$sId');");
}
}
else
{
$oPage->p("Error: failed to load dashboard file: '{$this->sDashboardFile}'");
}
}
public function RenderEditor(WebPage $oPage)
{
$oDashboard = $this->GetDashboard();
if ($oDashboard != null)
{
$oDashboard->RenderEditor($oPage);
}
else
{
$oPage->p("Error: failed to load dashboard file: '{$this->sDashboardFile}'");
}
}
public function AddDashlet($oDashlet)
{
$oDashboard = $this->GetDashboard();
if ($oDashboard != null)
{
$oDashboard->AddDashlet($oDashlet);
$oDashboard->Save();
}
else
{
$oPage->p("Error: failed to load dashboard file: '{$this->sDashboardFile}'");
}
}
}
/**
* A shortcut container is the preferred destination of newly created shortcuts
*/
class ShortcutContainerMenuNode extends MenuNode
{
public function GetHyperlink($aExtraParams)
{
return '';
}
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
}
public function PopulateChildMenus()
{
// Load user shortcuts in DB
//
$oBMSearch = new DBObjectSearch('Shortcut');
$oBMSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oBMSet = new DBObjectSet($oBMSearch, array('friendlyname' => true)); // ascending on friendlyname
$fRank = 1;
while ($oShortcut = $oBMSet->Fetch())
{
$sName = $this->GetMenuId().'_'.$oShortcut->GetKey();
$oShortcutMenu = new ShortcutMenuNode($sName, $oShortcut, $this->GetIndex(), $fRank++);
}
// Complete the tree
//
parent::PopulateChildMenus();
}
}
require_once(APPROOT.'application/shortcut.class.inc.php');
/**
* This class defines a menu item which content is a shortcut.
*/
class ShortcutMenuNode extends MenuNode
{
protected $oShortcut;
/**
* Create a menu item based on a custom template and inserts it into the application's main menu
* @param string $sMenuId Unique identifier of the menu (used to identify the menu for bookmarking, and for getting the labels from the dictionary)
* @param object $oShortcut Shortcut object
* @param integer $iParentIndex ID of the parent menu
* @param float $fRank Number used to order the list, any number will do, but for a given level (i.e same parent) all menus are sorted based on this value
* @param string $sEnableClass Name of class of object
* @param integer $iActionCode Either UR_ACTION_READ, UR_ACTION_MODIFY, UR_ACTION_DELETE, UR_ACTION_BULKREAD, UR_ACTION_BULKMODIFY or UR_ACTION_BULKDELETE
* @param integer $iAllowedResults Expected "rights" for the action: either UR_ALLOWED_YES, UR_ALLOWED_NO, UR_ALLOWED_DEPENDS or a mix of them...
* @return MenuNode
*/
public function __construct($sMenuId, $oShortcut, $iParentIndex, $fRank = 0, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
{
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
$this->oShortcut = $oShortcut;
$this->aReflectionProperties['shortcut'] = $oShortcut->GetKey();
}
public function GetHyperlink($aExtraParams)
{
$sContext = $this->oShortcut->Get('context');
$aContext = unserialize($sContext);
if (isset($aContext['menu']))
{
unset($aContext['menu']);
}
foreach ($aContext as $sArgName => $sArgValue)
{
$aExtraParams[$sArgName] = $sArgValue;
}
return parent::GetHyperlink($aExtraParams);
}
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
$this->oShortcut->RenderContent($oPage, $aExtraParams);
}
public function GetTitle()
{
return $this->oShortcut->Get('name');
}
public function GetLabel()
{
return $this->oShortcut->Get('name');
}
}

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Class NiceWebPage * Class NiceWebPage
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT."/application/webpage.class.inc.php"); require_once(APPROOT."/application/webpage.class.inc.php");
@@ -31,129 +30,30 @@ require_once(APPROOT."/application/webpage.class.inc.php");
class NiceWebPage extends WebPage class NiceWebPage extends WebPage
{ {
var $m_aReadyScripts; var $m_aReadyScripts;
var $m_sRootUrl;
public function __construct($s_title) public function __construct($s_title)
{ {
parent::__construct($s_title); parent::__construct($s_title);
$this->m_aReadyScripts = array(); $this->m_aReadyScripts = array();
$this->add_linked_script("../js/jquery-1.7.1.min.js"); $this->add_linked_script("../js/jquery-1.4.2.min.js");
$this->add_linked_stylesheet('../css/ui-lightness/jquery-ui-1.8.17.custom.css'); //$this->add_linked_script("../js/jquery.history_remote.pack.js");
$this->add_linked_script('../js/jquery-ui-1.8.17.custom.min.js'); $this->add_linked_stylesheet('../css/ui-lightness/jquery-ui-1.8.2.custom.css');
$this->add_linked_script('../js/jquery-ui-1.8.2.custom.min.js');
//$this->add_linked_script("../js/ui.resizable.js");
// $this->add_linked_script("../js/ui.tabs.js");
$this->add_linked_script("../js/hovertip.js"); $this->add_linked_script("../js/hovertip.js");
// table sorting // $this->add_linked_script("../js/jqModal.js");
$this->add_linked_script("../js/jquery.tablesorter.js");
$this->add_linked_script("../js/jquery.tablesorter.pager.js");
$this->add_linked_script("../js/jquery.tablehover.js");
$this->add_linked_script('../js/field_sorter.js');
$this->add_linked_script('../js/datatable.js');
$this->add_linked_script("../js/jquery.positionBy.js");
$this->add_linked_script("../js/jquery.popupmenu.js");
$this->add_ready_script(
<<< EOF
//add new widget called TruncatedList to properly display truncated lists when they are sorted
$.tablesorter.addWidget({
// give the widget a id
id: "truncatedList",
// format is called when the on init and when a sorting has finished
format: function(table)
{
// Check if there is a "truncated" line
this.truncatedList = false;
if ($("tr td.truncated",table).length > 0)
{
this.truncatedList = true;
}
if (this.truncatedList)
{
$("tr td",table).removeClass('truncated');
$("tr:last td",table).addClass('truncated');
}
}
});
$.tablesorter.addWidget({
// give the widget a id
id: "myZebra",
// format is called when the on init and when a sorting has finished
format: function(table)
{
// Replace the 'red even' lines by 'red_even' since most browser do not support 2 classes selector in CSS, etc..
$("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');
$("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
$("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');
$("tbody tr.green_even:odd",table).removeClass('even').removeClass('green_even').addClass('green');
}
});
$("table.listResults").tableHover(); // hover tables
EOF
);
$this->add_linked_stylesheet("../css/light-grey.css"); $this->add_linked_stylesheet("../css/light-grey.css");
// $this->add_linked_stylesheet("../js/themes/light/light.tabs.css");
$this->m_sRootUrl = $this->GetAbsoluteUrlAppRoot(); //$this->add_linked_stylesheet("../css/jquery.tabs-ie.css", "lte IE 7");
$sAbsURLAppRoot = addslashes($this->m_sRootUrl); // $this->add_linked_stylesheet("../css/jqModal.css");
$sAbsURLModulesRoot = addslashes($this->GetAbsoluteUrlModulesRoot()); $this->add_ready_script(' window.setTimeout(hovertipInit, 1);');
$sAppContext = addslashes($this->GetApplicationContext());
$this->add_script(
<<<EOF
function GetAbsoluteUrlAppRoot()
{
return '$sAbsURLAppRoot';
}
function GetAbsoluteUrlModulesRoot()
{
return '$sAbsURLModulesRoot';
}
function AddAppContext(sURL)
{
var sContext = '$sAppContext';
if (sContext.length > 0)
{
if (sURL.indexOf('?') == -1)
{
return sURL+'?'+sContext;
}
return sURL+'&'+sContext;
}
return sURL;
}
EOF
);
}
public function SetRootUrl($sRootUrl)
{
$this->m_sRootUrl = $sRootUrl;
} }
public function small_p($sText) public function small_p($sText)
{ {
$this->add("<p style=\"font-size:smaller\">$sText</p>\n"); $this->add("<p style=\"font-size:smaller\">$sText</p>\n");
} }
public function GetAbsoluteUrlAppRoot()
{
return utils::GetAbsoluteUrlAppRoot();
}
public function GetAbsoluteUrlModulesRoot()
{
return utils::GetAbsoluteUrlModulesRoot();
}
function GetApplicationContext()
{
$oAppContext = new ApplicationContext();
return $oAppContext->GetForLink();
}
// By Rom, used by CSVImport and Advanced search // By Rom, used by CSVImport and Advanced search
public function MakeClassesSelect($sName, $sDefaultValue, $iWidthPx, $iActionCode = null) public function MakeClassesSelect($sName, $sDefaultValue, $iWidthPx, $iActionCode = null)
@@ -200,7 +100,6 @@ EOF
*/ */
public function output() public function output()
{ {
$this->set_base($this->m_sRootUrl.'pages/');
if (count($this->m_aReadyScripts)>0) if (count($this->m_aReadyScripts)>0)
{ {
$this->add_script("\$(document).ready(function() {\n".implode("\n", $this->m_aReadyScripts)."\n});"); $this->add_script("\$(document).ready(function() {\n".implode("\n", $this->m_aReadyScripts)."\n});");

View File

@@ -1,26 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Class PortalWebPage * Class PortalWebPage
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT."/application/nicewebpage.class.inc.php"); require_once(APPROOT."/application/nicewebpage.class.inc.php");
@@ -59,9 +59,7 @@ class PortalWebPage extends NiceWebPage
$this->add_header("Cache-control: no-cache"); $this->add_header("Cache-control: no-cache");
$this->add_linked_stylesheet("../css/jquery.treeview.css"); $this->add_linked_stylesheet("../css/jquery.treeview.css");
$this->add_linked_stylesheet("../css/jquery.autocomplete.css"); $this->add_linked_stylesheet("../css/jquery.autocomplete.css");
$this->add_linked_stylesheet("../css/jquery.multiselect.css");
$sAbsURLAppRoot = addslashes(utils::GetAbsoluteUrlAppRoot()); // Pass it to Javascript scripts $sAbsURLAppRoot = addslashes(utils::GetAbsoluteUrlAppRoot()); // Pass it to Javascript scripts
$sAbsURLModulesRoot = addslashes(utils::GetAbsoluteUrlModulesRoot()); // Pass it to Javascript scripts
$oAppContext = new ApplicationContext(); $oAppContext = new ApplicationContext();
$sAppContext = addslashes($oAppContext->GetForLink()); $sAppContext = addslashes($oAppContext->GetForLink());
if ($sAlternateStyleSheet != '') if ($sAlternateStyleSheet != '')
@@ -87,8 +85,6 @@ 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.min.js');
$this->add_linked_script("../js/ajaxfileupload.js");
$this->add_ready_script( $this->add_ready_script(
<<<EOF <<<EOF
try try
@@ -176,11 +172,6 @@ EOF
return '$sAbsURLAppRoot'; return '$sAbsURLAppRoot';
} }
function GetAbsoluteUrlModulesRoot()
{
return '$sAbsURLModulesRoot';
}
function AddAppContext(sURL) function AddAppContext(sURL)
{ {
var sContext = '$sAppContext'; var sContext = '$sAppContext';
@@ -221,10 +212,8 @@ EOF
} }
EOF EOF
); );
// For Wizard helper to process the ajax replies }
$this->add('<div id="ajax_content"></div>');
}
public function SetCurrentTab($sTabLabel = '') public function SetCurrentTab($sTabLabel = '')
{ {
@@ -255,21 +244,6 @@ EOF
public function output() public function output()
{ {
$sApplicationBanner = '';
if (!MetaModel::DBHasAccess(ACCESS_USER_WRITE))
{
$sReadOnly = Dict::S('UI:AccessRO-Users');
$sAdminMessage = trim(MetaModel::GetConfig()->Get('access_message'));
$sApplicationBanner .= '<div id="admin-banner">';
$sApplicationBanner .= '<img src="../images/locked.png" style="vertical-align:middle;">';
$sApplicationBanner .= '&nbsp;<b>'.$sReadOnly.'</b>';
if (strlen($sAdminMessage) > 0)
{
$sApplicationBanner .= '&nbsp;: '.$sAdminMessage.'';
}
$sApplicationBanner .= '</div>';
}
$sMenu = ''; $sMenu = '';
if ($this->m_bEnableDisconnectButton) if ($this->m_bEnableDisconnectButton)
{ {
@@ -279,7 +253,7 @@ EOF
{ {
$sMenu .= "<a class=\"button\" id=\"{$aMenuItem['id']}\" href=\"{$aMenuItem['hyperlink']}\"><span>".Dict::S($aMenuItem['label'])."</span></a>"; $sMenu .= "<a class=\"button\" id=\"{$aMenuItem['id']}\" href=\"{$aMenuItem['hyperlink']}\"><span>".Dict::S($aMenuItem['label'])."</span></a>";
} }
$this->s_content = '<div id="portal"><div id="welcome">'.$this->m_sWelcomeMsg.'</div><div id="banner"><div id="logo"></div><div id="menu">'.$sMenu.'</div></div>'.$sApplicationBanner.'<div id="content">'.$this->s_content.'</div></div>'; $this->s_content = '<div id="portal"><div id="welcome">'.$this->m_sWelcomeMsg.'</div><div id="banner"><div id="logo"></div><div id="menu">'.$sMenu.'</div></div><div id="content">'.$this->s_content.'</div></div>';
parent::output(); parent::output();
} }
@@ -299,9 +273,13 @@ EOF
{ {
// Home-made and very limited display of an object set // Home-made and very limited display of an object set
$sUniqueId = $sClass.$this->GetUniqueId(); //
$this->add("<div id=\"$sUniqueId\">\n"); // The id here MUST be the same as currentId, otherwise the pagination will be broken //$oSet->Seek(0);// juste pour que le warning soit moins crado
cmdbAbstractObject::DisplaySet($this, $oSet, array('currentId' => $sUniqueId, 'menu' => false, 'zlist' => false, 'extra_fields' => implode(',', $aZList))); //$oSet->Fetch();// juste pour que le warning soit moins crado
//
$this->add("<div id=\"listOf$sClass\">\n");
cmdbAbstractObject::DisplaySet($this, $oSet, array('currentId' => "listOf$sClass", 'menu' => false, 'zlist' => false, 'extra_fields' => implode(',', $aZList)));
$this->add("</div>\n"); $this->add("</div>\n");
} }
else else
@@ -614,7 +592,7 @@ EOF
{ {
$sFieldName = str_replace('->', PARAM_ARROW_SEP, $sAttSpec); $sFieldName = str_replace('->', PARAM_ARROW_SEP, $sAttSpec);
$value = utils::ReadPostedParam($sPrefix.$sFieldName, null, 'raw_data'); $value = utils::ReadPostedParam($sPrefix.$sFieldName, null, 'raw_data');
if (!is_null($value) && (is_array($value) ? count($value)>0 : strlen($value)>0)) if (!is_null($value) && strlen($value) > 0)
{ {
$oFilter->AddConditionAdvanced($sAttSpec, $value); $oFilter->AddConditionAdvanced($sAttSpec, $value);
$iCountParams++; $iCountParams++;
@@ -672,24 +650,26 @@ EOF
} }
} }
if ($oObj->IsModified()) // Record the change
//
$oMyChange = MetaModel::NewObject("CMDBChange");
$oMyChange->Set("date", time());
$sUserString = CMDBChange::GetCurrentUserName();
$oMyChange->Set("userinfo", $sUserString);
$iChangeId = $oMyChange->DBInsert();
$oObj->DBUpdateTracked($oMyChange);
// Trigger ?
//
$aClasses = MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL);
$sClassList = implode(", ", CMDBSource::Quote($aClasses));
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnPortalUpdate AS t WHERE t.target_class IN ($sClassList)"));
while ($oTrigger = $oSet->Fetch())
{ {
// Record the change $oTrigger->DoActivate($oObj->ToArgs('this'));
//
$oObj->DBUpdate();
// Trigger ?
//
$aClasses = MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL);
$sClassList = implode(", ", CMDBSource::Quote($aClasses));
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnPortalUpdate AS t WHERE t.target_class IN ($sClassList)"));
while ($oTrigger = $oSet->Fetch())
{
$oTrigger->DoActivate($oObj->ToArgs('this'));
}
$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");
} }
/** /**
@@ -746,7 +726,7 @@ EOF
$this->m_sWizardId = $sId; $this->m_sWizardId = $sId;
// multipart... needed for file upload // multipart... needed for file upload
$this->add("<form id=\"{$this->m_sWizardId}\" method=\"$sMethod\" enctype=\"multipart/form-data\" onsubmit=\"window.bInSubmit = true;\">\n"); $this->add("<form id=\"{$this->m_sWizardId}\" method=\"$sMethod\" enctype=\"multipart/form-data\">\n");
$aPreviousSteps = $this->GetWizardStepHistory(); $aPreviousSteps = $this->GetWizardStepHistory();
if (utils::ReadParam('step_back', 0) == 1) if (utils::ReadParam('step_back', 0) == 1)

View File

@@ -1,108 +0,0 @@
<?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/>
/**
* Persistent class Event and derived
* Application internal events
* There is also a file log
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
abstract class Query extends cmdbAbstractObject
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,view_in_gui,application",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_query",
"db_key_field" => "id",
"db_finalclass_field" => "realclass",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//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 AttributeText("description", array("allowed_values"=>null, "sql"=>"description", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("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', 'fields')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('description')); // Attributes to be displayed for a list
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
class QueryOQL extends Query
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,view_in_gui,application",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_query_oql",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
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
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
{
parent::DisplayBareProperties($oPage, $bEditMode, $sPrefix, $aExtraParams);
if (!$bEditMode)
{
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?format=spreadsheet&login_mode=basic&query='.$this->GetKey();
$sOql = $this->Get('oql');
$oSearch = DBObjectSearch::FromOQL($sOql);
$aParameters = $oSearch->GetQueryParams();
foreach($aParameters as $sParam => $val)
{
$sUrl .= '&arg_'.$sParam.'=["'.$sParam.'"]';
}
$oPage->p(Dict::S('UI:Query:UrlForExcel').':<br/><textarea cols="80" rows="3" READONLY>'.$sUrl.'</textarea>');
}
}
}
?>

View File

@@ -1,283 +0,0 @@
<?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/>
/**
* Persistent class Shortcut and derived
* Shortcuts of any kind
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
abstract class Shortcut extends DBObject implements iDisplay
{
public static function Init()
{
$aParams = array
(
"category" => "gui,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_shortcut",
"db_key_field" => "id",
"db_finalclass_field" => "realclass",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
//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 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())));
// Display lists
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
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
abstract public function RenderContent(WebPage $oPage, $aExtraParams = array());
protected function OnInsert()
{
$this->Set('user_id', UserRights::GetUserId());
}
public function StartRenameDialog($oPage)
{
$oPage->add('<div id="shortcut_rename_dlg">');
$oForm = new DesignerForm();
$sDefault = $this->Get('name');
$oField = new DesignerTextField('name', Dict::S('Class:Shortcut/Attribute:name'), $sDefault);
$oField->SetMandatory(true);
$oForm->AddField($oField);
$oForm->Render($oPage);
$oPage->add('</div>');
$sDialogTitle = Dict::S('UI:ShortcutRenameDlg:Title');
$sOkButtonLabel = Dict::S('UI:Button:Ok');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$iShortcut = $this->GetKey();
$oPage->add_ready_script(
<<<EOF
function ShortcutRenameOK()
{
var oForm = $(this).find('form');
var sFormId = oForm.attr('id');
var oParams = null;
var aErrors = ValidateForm(sFormId, false);
if (aErrors.length == 0)
{
oParams = ReadFormParams(sFormId);
}
oParams.operation = 'shortcut_rename_go';
oParams.id = $iShortcut;
var me = $(this);
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function(data) {
me.dialog( "close" );
me.remove();
$('body').append(data);
});
}
$('#shortcut_rename_dlg form').bind('submit', function() { return false; });
$('#shortcut_rename_dlg').dialog({
width: 400,
modal: true,
title: '$sDialogTitle',
buttons: [
{ text: "$sOkButtonLabel", click: ShortcutRenameOK},
{ text: "$sCancelButtonLabel", click: function() {
$(this).dialog( "close" ); $(this).remove();
} },
],
close: function() { $(this).remove(); }
});
EOF
);
}
// Minimual implementation of iDisplay: to make the shortcut be listable
//
public static function MapContextParam($sContextParam)
{
return (($sContextParam == 'menu') ? null : $sContextParam);
}
public function GetHilightClass()
{
return HILIGHT_CLASS_NONE;
}
public static function GetUIPage()
{
return '';
}
function DisplayDetails(WebPage $oPage, $bEditMode = false)
{
}
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array())
{
}
// End of the minimal implementation of iDisplay
}
class ShortcutOQL extends Shortcut
{
public static function Init()
{
$aParams = array
(
"category" => "gui,view_in_gui",
"key_type" => "autoincrement",
"name_attcode" => "name",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_shortcut_oql",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
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
// Search criteria
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
$oPage->set_title($this->Get('name'));
$bSearchPane = true;
$bSearchOpen = false;
try
{
OQLMenuNode::RenderOQLSearch($this->Get('oql'), $this->Get('name'), 'shortcut_'.$this->GetKey(), $bSearchPane, $bSearchOpen, $oPage, $aExtraParams);
}
catch (Exception $e)
{
throw new Exception("The OQL shortcut '".$this->Get('name')."' (id: ".$this->GetKey().") could not be displayed: ".$e->getMessage());
}
}
public static function GetCreationForm($sOQL = null)
{
$oForm = new DesignerForm();
// Find a unique default name
// -> The class of the query + an index if necessary
if ($sOQL == null)
{
$sDefault = '';
}
else
{
$oBMSearch = new DBObjectSearch('Shortcut');
$oBMSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oBMSet = new DBObjectSet($oBMSearch);
$aNames = $oBMSet->GetColumnAsArray('name');
$oSearch = DBObjectSearch::FromOQL($sOQL);
$sDefault = utils::MakeUniqueName($oSearch->GetClass(), $aNames);
}
$oField = new DesignerTextField('name', Dict::S('Class:Shortcut/Attribute:name'), $sDefault);
$oField->SetMandatory(true);
$oForm->AddField($oField);
//$oField = new DesignerLongTextField('oql', Dict::S('Class:Shortcut/Attribute:oql'), $sOQL);
//$oField->SetMandatory();
$oField = new DesignerHiddenField('oql', '', $sOQL);
$oForm->AddField($oField);
return $oForm;
}
public static function GetCreationDlgFromOQL($oPage, $sOQL)
{
$oPage->add('<div id="shortcut_creation_dlg">');
$oForm = self::GetCreationForm($sOQL);
$oForm->Render($oPage);
$oPage->add('</div>');
$sDialogTitle = Dict::S('UI:ShortcutListDlg:Title');
$sOkButtonLabel = Dict::S('UI:Button:Ok');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$oAppContext = new ApplicationContext();
$sContext = $oAppContext->GetForLink();
$oPage->add_ready_script(
<<<EOF
function ShortcutCreationOK()
{
var oForm = $('#shortcut_creation_dlg form');
var sFormId = oForm.attr('id');
var oParams = null;
var aErrors = ValidateForm(sFormId, false);
if (aErrors.length == 0)
{
oParams = ReadFormParams(sFormId);
}
oParams.operation = 'shortcut_list_create';
var me = $('#shortcut_creation_dlg');
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?$sContext', oParams, function(data) {
me.dialog( "close" );
me.remove();
$('body').append(data);
});
}
$('#shortcut_creation_dlg form').bind('submit', function() { ShortcutCreationOK(); return false; });
$('#shortcut_creation_dlg').dialog({
width: 400,
modal: true,
title: '$sDialogTitle',
buttons: [
{ text: "$sOkButtonLabel", click: ShortcutCreationOK },
{ text: "$sCancelButtonLabel", click: function() {
$(this).dialog( "close" ); $(this).remove();
} },
],
close: function() { $(this).remove(); }
});
EOF
);
}
}
?>

View File

@@ -1,27 +1,27 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* SqlBlock - display tables or charts, given an SQL query - use cautiously! * SqlBlock - display tables or charts, given an SQL query - use cautiously!
* *
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
@@ -40,15 +40,13 @@ class SqlBlock
protected $m_aColumns; protected $m_aColumns;
protected $m_sTitle; protected $m_sTitle;
protected $m_sType; protected $m_sType;
protected $m_aParams;
public function __construct($sQuery, $aColumns, $sTitle, $sType, $aParams = array()) public function __construct($sQuery, $aColumns, $sTitle, $sType)
{ {
$this->m_sQuery = $sQuery; $this->m_sQuery = $sQuery;
$this->m_aColumns = $aColumns; $this->m_aColumns = $aColumns;
$this->m_sTitle = $sTitle; $this->m_sTitle = $sTitle;
$this->m_sType = $sType; $this->m_sType = $sType;
$this->m_aParams = $aParams;
} }
/** /**
@@ -56,14 +54,9 @@ class SqlBlock
/* /*
* *
* <sqlblock> * <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> * <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')</sql>
* <type>table</type> * <type>table</type>
* <title>UserRequest:Overview-Title</title> * <title>UserRequest:Overview-Title</title>
* <parameter>
* <name>param1</name>
* <type>context</type>
* <mapping>org_id</mapping>
* </parameter>
* <column> * <column>
* <name>Date</name> * <name>Date</name>
* <label>UserRequest:Overview-Date</label> * <label>UserRequest:Overview-Date</label>
@@ -80,11 +73,6 @@ class SqlBlock
* - sql: a (My)SQL query. Do not forget to use html entities (e.g. &lt; for <) * - 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. * - 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 * - 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: specification of a column (not displayed if omitted)
* - column / name: name of the column in the SQL query (use aliases) * - 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 / label: label, typed in clear or given as a dictionnary entry
@@ -156,96 +144,8 @@ class SqlBlock
} }
} }
} }
$aParams = array();
if (isset($oXml->parameter)) return new SqlBlock($sQuery, $aColumns, $sTitle, $sType);
{
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()) public function RenderContent(WebPage $oPage, $aExtraParams = array())
@@ -260,8 +160,7 @@ class SqlBlock
} }
// $oPage->add($this->GetRenderContent($oPage, $aExtraParams, $sId)); // $oPage->add($this->GetRenderContent($oPage, $aExtraParams, $sId));
$sQuery = $this->BuildQuery(); $res = CMDBSource::Query($this->m_sQuery);
$res = CMDBSource::Query($sQuery);
$aQueryCols = CMDBSource::GetColumns($res); $aQueryCols = CMDBSource::GetColumns($res);
// Prepare column definitions (check + give default values) // Prepare column definitions (check + give default values)

View File

@@ -1,49 +1,31 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* File to include to initialize the datamodel in memory * File to include to initialize the datamodel in memory
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT.'/core/cmdbobject.class.inc.php'); require_once(APPROOT.'/core/cmdbobject.class.inc.php');
require_once(APPROOT.'/application/utils.inc.php'); require_once(APPROOT.'/application/utils.inc.php');
session_name('itop-'.md5(APPROOT));
session_start(); MetaModel::Startup(ITOP_CONFIG_FILE);
if (isset($_REQUEST['switch_env']))
{
$sEnv = $_REQUEST['switch_env'];
$_SESSION['itop_env'] = $sEnv;
// 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);
?> ?>

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Class DisplayTemplate * Class DisplayTemplate
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT.'/application/displayblock.class.inc.php'); require_once(APPROOT.'/application/displayblock.class.inc.php');
@@ -283,29 +282,9 @@ class ObjectDetailsTemplate extends DisplayTemplate
$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) $aTemplateFields = $aMatches[1];
{
if (MetaModel::IsValidAttCode(get_class($this->m_oObj), $sAttCode))
{
$aTemplateFields[] = $sAttCode;
}
else
{
$aParams['this->'.$sAttCode] = "<!--Unknown attribute: $sAttCode-->";
}
}
preg_match_all('/\\$this->field\\(([a-z0-9_]+)\\)\\$/', $this->m_sTemplate, $aMatches); preg_match_all('/\\$this->field\\(([a-z0-9_]+)\\)\\$/', $this->m_sTemplate, $aMatches);
foreach ($aMatches[1] as $sAttCode) $aTemplateFields = array_merge($aTemplateFields, $aMatches[1]);
{
if (MetaModel::IsValidAttCode(get_class($this->m_oObj), $sAttCode))
{
$aTemplateFields[] = $sAttCode;
}
else
{
$aParams['this->field('.$sAttCode.')'] = "<!--Unknown attribute: $sAttCode-->";
}
}
$aFieldsComments = (isset($aParams['fieldsComments'])) ? $aParams['fieldsComments'] : array(); $aFieldsComments = (isset($aParams['fieldsComments'])) ? $aParams['fieldsComments'] : array();
$aFieldsMap = array(); $aFieldsMap = array();

View File

@@ -1,6 +1,15 @@
<div style="width:100%;background: #fff url(../images/welcome.jpg) top left no-repeat;"> <div style="width:100%;background: #fff url(../images/welcome.jpg) top left no-repeat;">
<style> <style>
.welcome_popup_cell { .dashboard {
vertical-align:top;
width:50%;
border:0px solid #000;
background-color:#F9F9F1;
padding:10px;
text-align:left;
font-size:10pt;
}
.dashboard2 {
vertical-align:top; vertical-align:top;
width:50%; width:50%;
border:0px solid #000; border:0px solid #000;
@@ -8,7 +17,15 @@ border:0px solid #000;
padding:5px; padding:5px;
text-align:left; text-align:left;
} }
tr td.welcome_popup_cell, tr td.welcome_popup_cell ul {
td.dashboard li {
margin-top: 5px;
display: list-item;
}
td div.display_block {
padding:0;
}
tr td.dashboard2, tr td.dashboard2 ul {
font-size:10pt; font-size:10pt;
} }
</style> </style>
@@ -18,10 +35,10 @@ font-size:10pt;
<p></p> <p></p>
<table border="0" style="padding:10px;border-spacing: 10px;width:100%"> <table border="0" style="padding:10px;border-spacing: 10px;width:100%">
<tr> <tr>
<td class="welcome_popup_cell"> <td class="dashboard2">
<itopstring>UI:WelcomeMenu:LeftBlock</itopstring> <itopstring>UI:WelcomeMenu:LeftBlock</itopstring>
</td> </td>
<td class="welcome_popup_cell"> <td class="dashboard2">
<itopstring>UI:WelcomeMenu:RightBlock</itopstring> <itopstring>UI:WelcomeMenu:RightBlock</itopstring>
</td> </td>
</tr> </tr>

View File

@@ -1,29 +1,24 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* This class records the pending "transactions" corresponding to forms that have not been * This class records the pending "transactions" corresponding to forms that have not been
* submitted yet, in order to prevent double submissions. When created a transaction remains valid * submitted yet, in order to prevent double submissions. When created a transaction remains valid
* until the user's session expires * until the user's session expires
*
* @package iTop * @package iTop
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/ */

View File

@@ -1,20 +1,18 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Class UIExtKeyWidget * Class UIExtKeyWidget
* UI wdiget for displaying and editing external keys when * UI wdiget for displaying and editing external keys when
@@ -54,8 +52,10 @@
* | | +--------+ +-----+ | | * | | +--------+ +-----+ | |
* | +--------------------------------------------+ | * | +--------------------------------------------+ |
* +------------------------------------------------+ * +------------------------------------------------+
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT.'/application/webpage.class.inc.php'); require_once(APPROOT.'/application/webpage.class.inc.php');
@@ -65,8 +65,6 @@ class UIExtKeyWidget
{ {
protected $iId; protected $iId;
protected $sTargetClass; protected $sTargetClass;
protected $sAttCode;
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)
@@ -83,59 +81,44 @@ class UIExtKeyWidget
{ {
$sDisplayStyle = 'select'; // In search mode, always use a drop-down list $sDisplayStyle = 'select'; // In search mode, always use a drop-down list
} }
$oWidget = new UIExtKeyWidget($sTargetClass, $iInputId, $sAttCode, $bSearchMode); $oWidget = new UIExtKeyWidget($sTargetClass, $iInputId);
return $oWidget->Display($oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix, $aArgs, null, $sDisplayStyle); return $oWidget->Display($oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName, $sFormPrefix, $aArgs, $bSearchMode, $sDisplayStyle);
} }
public function __construct($sTargetClass, $iInputId, $sAttCode = '', $bSearchMode = false) public function __construct($sTargetClass, $iInputId)
{ {
$this->sTargetClass = $sTargetClass; $this->sTargetClass = $sTargetClass;
$this->iId = $iInputId; $this->iId = $iInputId;
$this->sAttCode = $sAttCode;
$this->bSearchMode = $bSearchMode;
} }
/** /**
* Get the HTML fragment corresponding to the ext key editing widget * Get the HTML fragment corresponding to the linkset 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 Hash $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, $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 = false, $sDisplayStyle = 'select')
{ {
if (!is_null($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) && (!MetaModel::IsAbstract($this->sTargetClass)) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation); $bCreate = (!$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 = ($bSearchMode) ? '' : 'attr_';
$sHTMLValue = "<span style=\"white-space:nowrap\">"; // no wrap $sHTMLValue = "<span style=\"white-space:nowrap\">"; // no wrap
$sFilter = addslashes($oAllowedValues->GetFilter()->ToOQL()); $sFilter = addslashes($oAllowedValues->GetFilter()->ToOQL());
if($this->bSearchMode) if($bSearchMode)
{ {
$sWizHelper = 'null'; $sWizHelper = 'null';
$sWizHelperJSON = "''"; $sWizHelperJSON = "''";
$sJSSearchMode = 'true';
} }
else else
{ {
if (isset($aArgs['wizHelper'])) $sWizHelper = 'oWizardHelper'.$sFormPrefix;
{ $sWizHelperJSON = $sWizHelper.'.ToJSON()';
$sWizHelper = $aArgs['wizHelper'];
}
else
{
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
}
$sWizHelperJSON = $sWizHelper.'.UpdateWizardToJSON()';
$sJSSearchMode = 'false';
} }
if (is_null($oAllowedValues)) if (is_null($oAllowedValues))
{ {
@@ -169,22 +152,14 @@ class UIExtKeyWidget
$sHelpText = ''; //$this->oAttDef->GetHelpOnEdition(); $sHelpText = ''; //$this->oAttDef->GetHelpOnEdition();
if ($this->bSearchMode) $sHTMLValue = "<select title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" id=\"$this->iId\">\n";
if ($bSearchMode)
{ {
if ($bSearchMultiple) $sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : Dict::S('UI:SearchValue:Any');
{ $sHTMLValue .= "<option value=\"\">$sDisplayValue</option>\n";
$sHTMLValue = "<select class=\"multiselect\" multiple title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$sFieldName}[]\" id=\"$this->iId\">\n";
}
else
{
$sHTMLValue = "<select title=\"$sHelpText\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" id=\"$this->iId\">\n";
$sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : Dict::S('UI:SearchValue:Any');
$sHTMLValue .= "<option value=\"\">$sDisplayValue</option>\n";
}
} }
else else
{ {
$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();
@@ -200,18 +175,14 @@ class UIExtKeyWidget
} }
else else
{ {
$sSelected = (is_array($value) && in_array($key, $value)) || ($value == $key) ? ' selected' : ''; $sSelected = ($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";
if (($this->bSearchMode) && $bSearchMultiple)
{
$oPage->add_ready_script("$('.multiselect').multiselect({header: false, noneSelectedText: '".addslashes(Dict::S('UI:SearchValue:Any'))."', selectedList: 1, selectedText:'".addslashes(Dict::S('UI:SearchValue:NbSelected'))."'});");
}
$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); oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', true, $sWizHelper);
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') } );
@@ -225,15 +196,6 @@ EOF
// Too many choices, use an autocomplete // Too many choices, use an autocomplete
$sSelectMode = 'false'; $sSelectMode = 'false';
// Check that the given value is allowed
$oSearch = $oAllowedValues->GetFilter();
$oSearch->AddCondition('id', $value);
$oSet = new DBObjectSet($oSearch);
if ($oSet->Count() == 0)
{
$value = null;
}
if (is_null($value) || ($value == 0)) // Null values are displayed as '' if (is_null($value) || ($value == 0)) // Null values are displayed as ''
{ {
$sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : ''; $sDisplayValue = isset($aArgs['sDefaultValue']) ? $aArgs['sDefaultValue'] : '';
@@ -251,14 +213,13 @@ EOF
// 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=\"$value\" />\n"; $sHTMLValue .= "<input type=\"hidden\" id=\"$this->iId\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" value=\"$value\" />\n";
$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); oACWidget_{$this->iId} = new ExtKeyWidget('{$this->iId}', '{$this->sTargetClass}', '$sFilter', '$sTitle', false, $sWizHelper);
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', 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 !
$('#label_$this->iId').result( function(event, data, formatted) { OnAutoComplete('{$this->iId}', event, data, formatted); } ); $('#label_$this->iId').result( function(event, data, formatted) { OnAutoComplete('{$this->iId}', event, data, formatted); } );
$('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } ); $('#$this->iId').bind('update', function() { oACWidget_{$this->iId}.Update(); } );
@@ -301,24 +262,13 @@ EOF
return $sHTMLValue; return $sHTMLValue;
} }
public function GetSearchDialog(WebPage $oPage, $sTitle, $oCurrObject = null) public function GetSearchDialog(WebPage $oPage, $sTitle)
{ {
$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.'">';
if ( ($oCurrObject != null) && ($this->sAttCode != '')) $oFilter = new DBObjectSearch($this->sTargetClass);
{ $oSet = new CMDBObjectSet($oFilter);
$oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode); $oBlock = new DisplayBlock($oFilter, 'search', false);
$aParams = array('query_params' => array('this' => $oCurrObject));
$oSet = $oAttDef->GetAllowedValuesAsObjectSet($aParams);
$oFilter = $oSet->GetFilter();
}
else
{
$aParams = array();
$oFilter = new DBObjectSearch($this->sTargetClass);
}
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oBlock = new DisplayBlock($oFilter, 'search', false, $aParams);
$sHTML .= $oBlock->GetDisplay($oPage, $this->iId, array('open' => true, 'currentId' => $this->iId)); $sHTML .= $oBlock->GetDisplay($oPage, $this->iId, array('open' => true, 'currentId' => $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";
@@ -353,15 +303,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);
if (strlen($sRemoteClass) > 0)
{ {
$oFilter->ChangeClass($sRemoteClass); $oFilter = DBObjectSearch::FromOQL($sFilter);
$oBlock = new DisplayBlock($oFilter, 'list', false);
$oBlock->Display($oP, $this->iId.'_results', array('this' => $oObj, 'cssCount'=> '#count_'.$this->iId, 'menu' => false, 'selection_mode' => true, 'selection_type' => 'single')); // Don't display the 'Actions' menu on the results
}
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 '.$sRemoteClass;
$oFilter = DBObjectSearch::FromOQL($sOQL);
$oBlock = new DisplayBlock($oFilter, 'list', false);
$oBlock->Display($oP, $this->iId.'_results', array('cssCount'=> '#count_'.$this->iId, 'menu' => false, 'selection_mode' => true, 'selection_type' => 'single')); // Don't display the 'Actions' menu on the results
} }
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oBlock = new DisplayBlock($oFilter, 'list', false, array('query_params' => array('this' => $oObj)));
$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
} }
/** /**
@@ -378,7 +334,6 @@ EOF
throw new Exception('Implementation: null value for allowed values definition'); throw new Exception('Implementation: null value for allowed values definition');
} }
$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
$oValuesSet->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$aValues = $oValuesSet->GetValues(array('this' => $oObj), $sContains); $aValues = $oValuesSet->GetValues(array('this' => $oObj), $sContains);
foreach($aValues as $sKey => $sFriendlyName) foreach($aValues as $sKey => $sFriendlyName)
{ {
@@ -391,24 +346,14 @@ EOF
*/ */
public function GetObjectName($iObjId) public function GetObjectName($iObjId)
{ {
$aModifierProps = array(); $oObj = MetaModel::GetObject($this->sTargetClass, $iObjId);
$aModifierProps['UserRightsGetSelectFilter']['bSearchMode'] = $this->bSearchMode; return $oObj->GetName();
$oObj = MetaModel::GetObject($this->sTargetClass, $iObjId, false, false, $aModifierProps);
if ($oObj)
{
return $oObj->GetName();
}
else
{
return '';
}
} }
/** /**
* 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) public function GetObjectCreationForm(WebPage $oPage)
{ {
// 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);
@@ -417,27 +362,10 @@ EOF
$oAppContext = new ApplicationContext(); $oAppContext = new ApplicationContext();
$oAppContext->InitObjectFromContext($oNewObj); $oAppContext->InitObjectFromContext($oNewObj);
// 2nd set the default values from the constraint on the external key... if any // 2nd - set values from the page argument 'default'
if ( ($oCurrObject != null) && ($this->sAttCode != ''))
{
$oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode);
$aParams = array('this' => $oCurrObject);
$oSet = $oAttDef->GetAllowedValuesAsObjectSet($aParams);
$aConsts = $oSet->ListConstantFields();
$sClassAlias = $oSet->GetFilter()->GetClassAlias();
if (isset($aConsts[$sClassAlias]))
{
foreach($aConsts[$sClassAlias] as $sAttCode => $value)
{
$oNewObj->Set($sAttCode, $value);
}
}
}
// 3rd - set values from the page argument 'default'
$oNewObj->UpdateObjectFromArg('default'); $oNewObj->UpdateObjectFromArg('default');
$sDialogTitle = ''; $sDialogTitle = addslashes($this->sTitle);
$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");
cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, $oNewObj, array(), array('formPrefix' => $this->iId, 'noRelations' => true)); cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, $oNewObj, array(), array('formPrefix' => $this->iId, 'noRelations' => true));
@@ -463,7 +391,6 @@ EOF
try try
{ {
$oFilter = DBObjectSearch::FromOQL($sFilter); $oFilter = DBObjectSearch::FromOQL($sFilter);
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oSet = new DBObjectSet($oFilter, array(), array('this' => $oObj)); $oSet = new DBObjectSet($oFilter, array(), array('this' => $oObj));
} }
catch(MissingQueryArgument $e) catch(MissingQueryArgument $e)
@@ -472,7 +399,6 @@ EOF
// TODO check if we can improve this behavior... // TODO check if we can improve this behavior...
$sOQL = 'SELECT '.$this->m_sTargetClass; $sOQL = 'SELECT '.$this->m_sTargetClass;
$oFilter = DBObjectSearch::FromOQL($sOQL); $oFilter = DBObjectSearch::FromOQL($sOQL);
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
$oSet = new DBObjectSet($oFilter); $oSet = new DBObjectSet($oFilter);
} }
@@ -498,7 +424,12 @@ EOF
$aErrors = $oObj->UpdateObjectFromPostedForm($this->iId); $aErrors = $oObj->UpdateObjectFromPostedForm($this->iId);
if (count($aErrors) == 0) if (count($aErrors) == 0)
{ {
$oObj->DBInsert(); $oMyChange = MetaModel::NewObject("CMDBChange");
$oMyChange->Set("date", time());
$sUserString = CMDBChange::GetCurrentUserName();
$oMyChange->Set("userinfo", $sUserString);
$iChangeId = $oMyChange->DBInsert();
$oObj->DBInsertTracked($oMyChange);
return array('name' => $oObj->GetName(), 'id' => $oObj->GetKey()); return array('name' => $oObj->GetName(), 'id' => $oObj->GetKey());
} }
else else

View File

@@ -1,28 +1,27 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* 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 Phil Eddies * @author Phil Eddies
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Romain Quetiez <romain.quetiez@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
class UIHTMLEditorWidget class UIHTMLEditorWidget

View File

@@ -1,255 +0,0 @@
<?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 UILinksWidgetDirect
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class UILinksWidgetDirect
{
protected $sClass;
protected $sAttCode;
protected $sInputid;
protected $sNameSuffix;
protected $sLinkedClass;
public function __construct($sClass, $sAttCode, $sInputId, $sNameSuffix = '')
{
$this->sClass = $sClass;
$this->sAttCode = $sAttCode;
$this->sInputid = $sInputId;
$this->sNameSuffix = $sNameSuffix;
$this->aZlist = array();
$this->sLinkedClass = '';
// Compute the list of attributes visible from the given objet:
// All the attributes from the "list" Zlist of the Link class except
// the ExternalKey that points to the current object and its related external fields
$oLinksetDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
$this->sLinkedClass = $oLinksetDef->GetLinkedClass();
$sExtKeyToMe = $oLinksetDef->GetExtKeyToMe();
$aZList = MetaModel::FlattenZList(MetaModel::GetZListItems($this->sLinkedClass, 'list'));
foreach($aZList as $sLinkedAttCode)
{
if ($sLinkedAttCode != $sExtKeyToMe)
{
$oAttDef = MetaModel::GetAttributeDef($this->sLinkedClass, $sLinkedAttCode);
if (!$oAttDef->IsExternalField() || ($oAttDef->GetKeyAttCode() != $sExtKeyToMe) )
{
$this->aZlist[] = $sLinkedAttCode;
}
}
}
}
public function Display(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj)
{
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
switch($oLinksetDef->GetEditMode())
{
case LINKSET_EDITMODE_NONE: // The linkset is read-only
$this->DisplayAsBlock($oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, false /* bDisplayMenu*/);
break;
case LINKSET_EDITMODE_ADDONLY: // The only possible action is to open (in a new window) the form to create a new object
if ($oCurrentObj && !$oCurrentObj->IsNew())
{
$sTargetClass = $oLinksetDef->GetLinkedClass();
$sExtKeyToMe = $oLinksetDef->GetExtKeyToMe();
$sDefault = "default[$sExtKeyToMe]=".$oCurrentObj->GetKey();
$oAppContext = new ApplicationContext();
$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");
}
$this->DisplayAsBlock($oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, false /* bDisplayMenu*/);
break;
case LINKSET_EDITMODE_INPLACE: // The whole linkset can be edited 'in-place'
$this->DisplayEditInPlace($oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj);
break;
case LINKSET_EDITMODE_ACTIONS:
default:
$this->DisplayAsBlock($oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, true /* bDisplayMenu*/);
}
}
protected function DisplayAsBlock(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $bDisplayMenu)
{
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
$sTargetClass = $oLinksetDef->GetLinkedClass();
if ($oCurrentObj && $oCurrentObj->IsNew() && $bDisplayMenu)
{
$oPage->p(Dict::Format('UI:BeforeAdding_Class_ObjectsSaveThisObject', MetaModel::GetName($sTargetClass)));
}
else
{
$oFilter = new DBObjectSearch($sTargetClass);
$oFilter->AddCondition($oLinksetDef->GetExtKeyToMe(), $oCurrentObj->GetKey(),'=');
$aDefaults = array($oLinksetDef->GetExtKeyToMe() => $oCurrentObj->GetKey());
$oAppContext = new ApplicationContext();
foreach($oAppContext->GetNames() as $sKey)
{
// The linked object inherits the parent's value for the context
if (MetaModel::IsValidAttCode($this->sClass, $sKey) && $oCurrentObj)
{
$aDefaults[$sKey] = $oCurrentObj->Get($sKey);
}
}
$aParams = array(
'target_attr' => $oLinksetDef->GetExtKeyToMe(),
'object_id' => $oCurrentObj ? $oCurrentObj->GetKey() : null,
'menu' => $bDisplayMenu,
'default' => $aDefaults,
'table_id' => $this->sClass.'_'.$this->sAttCode,
);
$oBlock = new DisplayBlock($oFilter, 'list', false);
$oBlock->Display($oPage, $this->sInputid, $aParams);
}
}
protected function DisplayEditInPlace(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj)
{
$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)),
);
$sSubmitUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
$sJSONLabels = json_encode($aLabels);
$oPage->add_ready_script("$('#{$this->sInputid}').directlinks({class_name: '$this->sClass', att_code: '$this->sAttCode', input_name:'$sInputName', labels: $sJSONLabels, sumit_to: '$sSubmitUrl' });");
}
public function GetObjectCreationDlg(WebPage $oPage, $sProposedRealClass = '')
{
// 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
$sRealClass = '';
$oPage->add('<div class="wizContainer" style="vertical-align:top;"><div>');
$aSubClasses = MetaModel::EnumChildClasses($this->sLinkedClass, ENUM_CHILD_CLASSES_ALL); // Including the specified class itself
$aPossibleClasses = array();
foreach($aSubClasses as $sCandidateClass)
{
if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES))
{
if ($sCandidateClass == $sProposedRealClass)
{
$sRealClass = $sProposedRealClass;
}
$aPossibleClasses[$sCandidateClass] = MetaModel::GetName($sCandidateClass);
}
}
// Only one of the subclasses can be instantiated...
if (count($aPossibleClasses) == 1)
{
$aKeys = array_keys($aPossibleClasses);
$sRealClass = $aKeys[0];
}
if ($sRealClass != '')
{
$oPage->add("<h1>".MetaModel::GetClassIcon($sRealClass)."&nbsp;".Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($sRealClass))."</h1>\n");
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
$sExtKeyToMe = $oLinksetDef->GetExtKeyToMe();
$aFieldFlags = array( $sExtKeyToMe => OPT_ATT_HIDDEN);
cmdbAbstractObject::DisplayCreationForm($oPage, $sRealClass, null, array(), array('formPrefix' => $this->sInputid, 'noRelations' => true, 'fieldsFlags' => $aFieldFlags));
}
else
{
$sClassLabel = MetaModel::GetName($this->sLinkedClass);
$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="button" onclick="$(\'#'.$this->sInputid.'\').directlinks(\'subclassSelected\');">'.Dict::S('UI:Button:Apply').'</button><span class="indicator" style="display:inline-block;width:16px"></span></nobr></p>');
}
$oPage->add('</div></div>');
}
public function GetObjectModificationDlg()
{
}
protected function GetTableConfig()
{
$aAttribs = array();
$aAttribs['form::select'] = array('label' => "<input type=\"checkbox\" onClick=\"CheckAll('.selectList{$this->sInputid}:not(:disabled)', this.checked);\" class=\"checkAll\"></input>", 'description' => Dict::S('UI:SelectAllToggle+'));
foreach($this->aZlist as $sLinkedAttCode)
{
$oAttDef = MetaModel::GetAttributeDef($this->sLinkedClass, $sLinkedAttCode);
$aAttribs[$sLinkedAttCode] = array('label' => MetaModel::GetLabel($this->sLinkedClass, $sLinkedAttCode), 'description' => $oAttDef->GetOrderByHint());
}
return $aAttribs;
}
public function GetRow($oPage, $sRealClass, $aValues, $iTempId)
{
$aAttribs = $this->GetTableConfig();
if ($sRealClass == '')
{
$sRealClass = $this->sLinkedClass;
}
$oLinkObj = new $sRealClass();
$oLinkObj->UpdateObjectFromPostedForm($this->sInputid);
$aRow = array();
$aRow['form::select'] = '<input type="checkbox" class="selectList'.$this->sInputid.'" value="'.(-$iTempId).'"/>';
foreach($this->aZlist as $sLinkedAttCode)
{
$aRow[$sLinkedAttCode] = $oLinkObj->GetAsHTML($sLinkedAttCode);
}
return $oPage->GetTableRow($aRow, $aAttribs);
}
public function UpdateFromArray($oObj, $aData)
{
}
}

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Class UILinksWidget * Class UILinksWidget
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT.'/application/webpage.class.inc.php'); require_once(APPROOT.'/application/webpage.class.inc.php');
@@ -63,9 +62,8 @@ class UILinksWidget
$this->m_aTableConfig = array(); $this->m_aTableConfig = array();
$this->m_aTableConfig['form::checkbox'] = array( 'label' => "<input class=\"select_all\" type=\"checkbox\" value=\"1\" onClick=\"CheckAll('#linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix} .selection', this.checked); oWidget".$this->m_iInputId.".OnSelectChange();\">", 'description' => Dict::S('UI:SelectAllToggle+')); $this->m_aTableConfig['form::checkbox'] = array( 'label' => "<input class=\"select_all\" type=\"checkbox\" value=\"1\" onClick=\"CheckAll('#linkedset_{$this->m_sAttCode}{$this->m_sNameSuffix} .selection', this.checked); oWidget".$this->m_iInputId.".OnSelectChange();\">", 'description' => Dict::S('UI:SelectAllToggle+'));
foreach(MetaModel::FlattenZList(MetaModel::GetZListItems($this->m_sLinkedClass, 'list')) as $sAttCode) foreach(MetaModel::ListAttributeDefs($this->m_sLinkedClass) as $sAttCode=>$oAttDef)
{ {
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sAttCode);
if ($sStateAttCode == $sAttCode) if ($sStateAttCode == $sAttCode)
{ {
// State attribute is always hidden from the UI // State attribute is always hidden from the UI
@@ -105,94 +103,45 @@ class UILinksWidget
{ {
$sPrefix = "$this->m_sAttCode{$this->m_sNameSuffix}"; $sPrefix = "$this->m_sAttCode{$this->m_sNameSuffix}";
$aRow = array(); $aRow = array();
$aFieldsMap = array();
if(is_object($linkObjOrId)) if(is_object($linkObjOrId))
{ {
$key = $linkObjOrId->GetKey(); $key = $linkObjOrId->GetKey();
$iRemoteObjKey = $linkObjOrId->Get($this->m_sExtKeyToRemote);
$sPrefix .= "[$key]["; $sPrefix .= "[$key][";
$sNameSuffix = "]"; // To make a tabular form $sNameSuffix = "]"; // To make a tabular form
$aArgs['prefix'] = $sPrefix; $aArgs['prefix'] = $sPrefix;
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}{$key}";
$aArgs['this'] = $linkObjOrId; $aArgs['this'] = $linkObjOrId;
$aRow['form::checkbox'] = "<input class=\"selection\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$key\">"; $aRow['form::checkbox'] = "<input class=\"selection\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$key\">";
$aRow['form::checkbox'] .= "<input type=\"hidden\" name=\"attr_{$sPrefix}id{$sNameSuffix}\" value=\"$key\">"; $aRow['form::checkbox'] .= "<input type=\"hidden\" name=\"attr_{$sPrefix}id{$sNameSuffix}\" value=\"$key\">";
foreach($this->m_aEditableFields as $sFieldCode) foreach($this->m_aEditableFields as $sFieldCode)
{ {
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.$linkObjOrId->GetKey().']'; $sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.$linkObjOrId->GetKey().']';
$sSafeId = utils::GetSafeId($sFieldId); $sSafeId = str_replace(array('[',']','-'), '_', $sFieldId);
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode); $oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
$aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $linkObjOrId->Get($sFieldCode), '' /* DisplayValue */, $sSafeId, $sNameSuffix, 0, $aArgs); $aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $linkObjOrId->Get($sFieldCode), '' /* DisplayValue */, $sSafeId, $sNameSuffix, 0, $aArgs);
$aFieldsMap[$sFieldCode] = $sSafeId;
} }
$sState = $linkObjOrId->GetState();
} }
else else
{ {
// form for creating a new record // form for creating a new record
$sPrefix .= "[$linkObjOrId]["; $sPrefix .= "[$linkObjOrId][";
$iRemoteObjKey = -$linkObjOrId;
$oNewLinkObj = MetaModel::NewObject($this->m_sLinkedClass); $oNewLinkObj = MetaModel::NewObject($this->m_sLinkedClass);
$oRemoteObj = MetaModel::GetObject($this->m_sRemoteClass, -$linkObjOrId); $oRemoteObj = MetaModel::GetObject($this->m_sRemoteClass, -$linkObjOrId);
$oNewLinkObj->Set($this->m_sExtKeyToRemote, $oRemoteObj); // Setting the extkey with the object alsoo fills the related external fields $oNewLinkObj->Set($this->m_sExtKeyToRemote, $oRemoteObj); // Setting the extkey with the object alsoo fills the related external fields
$oNewLinkObj->Set($this->m_sExtKeyToMe, $oCurrentObj); // Setting the extkey with the object also fills the related external fields $oNewLinkObj->Set($this->m_sExtKeyToMe, $oCurrentObj); // Setting the extkey with the object alsoo fills the related external fields
$sNameSuffix = "]"; // To make a tabular form $sNameSuffix = "]"; // To make a tabular form
$aArgs['prefix'] = $sPrefix; $aArgs['prefix'] = $sPrefix;
$aArgs['wizHelper'] = "oWizardHelper{$this->m_iInputId}_".(-$linkObjOrId);
$aArgs['this'] = $oNewLinkObj; $aArgs['this'] = $oNewLinkObj;
$aRow['form::checkbox'] = "<input class=\"selection\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$linkObjOrId\">"; $aRow['form::checkbox'] = "<input class=\"selection\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$linkObjOrId\">";
$aRow['form::checkbox'] .= "<input type=\"hidden\" name=\"attr_{$sPrefix}id{$sNameSuffix}\" value=\"\">"; $aRow['form::checkbox'] .= "<input type=\"hidden\" name=\"attr_{$sPrefix}id{$sNameSuffix}\" value=\"\">";
foreach($this->m_aEditableFields as $sFieldCode) foreach($this->m_aEditableFields as $sFieldCode)
{ {
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.$linkObjOrId.']'; $sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.$linkObjOrId.']';
$sSafeId = utils::GetSafeId($sFieldId); $sSafeId = str_replace(array('[',']','-'), '_', $sFieldId);
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode); $oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
$aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $oNewLinkObj->Get($sFieldCode) /* TO DO/ call GetDefaultValue($oObject->ToArgs()) */, '' /* DisplayValue */, $sSafeId /* id */, $sNameSuffix, 0, $aArgs); $aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, '' /* TO DO/ call GetDefaultValue($oObject->ToArgs()) */, '' /* DisplayValue */, $sSafeId /* id */, $sNameSuffix, 0, $aArgs);
$aFieldsMap[$sFieldCode] = $sSafeId;
} }
$sState = '';
$oP->add_script(
<<<EOF
$(".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
});
EOF
);
} }
$sExtKeyToMeId = utils::GetSafeId($sPrefix.$this->m_sExtKeyToMe);
$aFieldsMap[$this->m_sExtKeyToMe] = $sExtKeyToMeId;
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToMeId\" value=\"".$oCurrentObj->GetKey()."\">";
$sExtKeyToRemoteId = utils::GetSafeId($sPrefix.$this->m_sExtKeyToRemote);
$aFieldsMap[$this->m_sExtKeyToRemote] = $sExtKeyToRemoteId;
$aRow['form::checkbox'] .= "<input type=\"hidden\" id=\"$sExtKeyToRemoteId\" value=\"$iRemoteObjKey\">";
$iFieldsCount = count($aFieldsMap);
$sJsonFieldsMap = json_encode($aFieldsMap);
$oP->add_script(
<<<EOF
var {$aArgs['wizHelper']} = new WizardHelper('{$this->m_sLinkedClass}', '', '$sState');
{$aArgs['wizHelper']}.SetFieldsMap($sJsonFieldsMap);
{$aArgs['wizHelper']}.SetFieldsCount($iFieldsCount);
EOF
);
$aRow['static::key'] = $oLinkedObj->GetHyperLink(); $aRow['static::key'] = $oLinkedObj->GetHyperLink();
foreach(MetaModel::GetZListItems($this->m_sRemoteClass, 'list') as $sFieldCode) foreach(MetaModel::GetZListItems($this->m_sRemoteClass, 'list') as $sFieldCode)
{ {
@@ -302,10 +251,10 @@ EOF
EOF EOF
); );
$sHtmlValue .= "<span style=\"float:left;\">&nbsp;&nbsp;&nbsp;<img src=\"../images/tv-item-last.gif\">&nbsp;&nbsp;<input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnRemove\" type=\"button\" value=\"".Dict::S('UI:RemoveLinkedObjectsOf_Class')."\" onClick=\"oWidget{$this->m_iInputId}.RemoveSelected();\" >"; $sHtmlValue .= "<span style=\"float:left;\">&nbsp;&nbsp;&nbsp;<img src=\"../images/tv-item-last.gif\">&nbsp;&nbsp;<input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnRemove\" type=\"button\" value=\"".Dict::S('UI:RemoveLinkedObjectsOf_Class')."\" onClick=\"oWidget{$this->m_iInputId}.RemoveSelected();\" >";
$sHtmlValue .= "&nbsp;&nbsp;&nbsp;<input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnAdd\" type=\"button\" value=\"".Dict::Format('UI:AddLinkedObjectsOf_Class', MetaModel::GetName($this->m_sRemoteClass))."\" onClick=\"oWidget{$this->m_iInputId}.AddObjects();\"><span id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_indicatorAdd\"></span></span>\n"; $sHtmlValue .= "&nbsp;&nbsp;&nbsp;<input id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_btnAdd\" type=\"button\" value=\"".Dict::Format('UI:AddLinkedObjectsOf_Class', MetaModel::GetName($this->m_sRemoteClass))."\" onClick=\"oWidget{$this->m_iInputId}.AddObjects();\"></span>\n";
$sHtmlValue .= "<span style=\"clear:both;\"><p>&nbsp;</p></span>\n"; $sHtmlValue .= "<span style=\"clear:both;\"><p>&nbsp;</p></span>\n";
$sHtmlValue .= "</div>\n"; $sHtmlValue .= "</div>\n";
$oPage->add_at_the_end("<div id=\"dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}\"></div>"); // To prevent adding forms inside the main form $oPage->add_at_the_end($this->GetObjectPickerDialog($oPage), "dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}"); // To prevent adding forms inside the main form
return $sHtmlValue; return $sHtmlValue;
} }
@@ -328,11 +277,12 @@ EOF
return $sTargetClass; return $sTargetClass;
} }
public function GetObjectPickerDialog($oPage, $oCurrentObj) protected function GetObjectPickerDialog($oPage)
{ {
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n"; $sHtml = "<div id=\"dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}\">";
$sHtml .= "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
$oFilter = new DBObjectSearch($this->m_sRemoteClass); $oFilter = new DBObjectSearch($this->m_sRemoteClass);
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter); $oSet = new CMDBObjectSet($oFilter);
$oBlock = new DisplayBlock($oFilter, 'search', false); $oBlock = new DisplayBlock($oFilter, 'search', false);
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}", array('open' => true)); $sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}", array('open' => true));
$sHtml .= "<form id=\"ObjectsAddForm_{$this->m_sAttCode}{$this->m_sNameSuffix}\" OnSubmit=\"return oWidget{$this->m_iInputId}.DoAddObjects(this.id);\">\n"; $sHtml .= "<form id=\"ObjectsAddForm_{$this->m_sAttCode}{$this->m_sNameSuffix}\" OnSubmit=\"return oWidget{$this->m_iInputId}.DoAddObjects(this.id);\">\n";
@@ -343,11 +293,12 @@ EOF
$sHtml .= "<input type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('close');\">&nbsp;&nbsp;<input id=\"btn_ok_{$this->m_sAttCode}{$this->m_sNameSuffix}\" disabled=\"disabled\" type=\"submit\" value=\"".Dict::S('UI:Button:Add')."\">"; $sHtml .= "<input type=\"button\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('close');\">&nbsp;&nbsp;<input id=\"btn_ok_{$this->m_sAttCode}{$this->m_sNameSuffix}\" disabled=\"disabled\" type=\"submit\" value=\"".Dict::S('UI:Button:Add')."\">";
$sHtml .= "</div>\n"; $sHtml .= "</div>\n";
$sHtml .= "</form>\n"; $sHtml .= "</form>\n";
$oPage->add($sHtml); $sHtml .= "</div>\n";
$oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, resizeStop: oWidget{$this->m_iInputId}.UpdateSizes });"); $oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog({ width: $(window).width()*0.8, height: $(window).height()*0.8, autoOpen: false, modal: true, resizeStop: oWidget{$this->m_iInputId}.UpdateSizes });");
$oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('option', {title:'".addslashes(Dict::Format('UI:AddObjectsOf_Class_LinkedWith_Class', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName($this->m_sClass)))."'});"); $oPage->add_ready_script("$('#dlg_{$this->m_sAttCode}{$this->m_sNameSuffix}').dialog('option', {title:'".addslashes(Dict::Format('UI:AddObjectsOf_Class_LinkedWith_Class', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName($this->m_sClass)))."'});");
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix} form').bind('submit.uilinksWizard', oWidget{$this->m_iInputId}.SearchObjectsToAdd);"); $oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix} form').bind('submit.uilinksWizard', oWidget{$this->m_iInputId}.SearchObjectsToAdd);");
$oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}').resize(oWidget{$this->m_iInputId}.UpdateSizes);"); $oPage->add_ready_script("$('#SearchFormToAdd_{$this->m_sAttCode}{$this->m_sNameSuffix}').resize(oWidget{$this->m_iInputId}.UpdateSizes);");
return $sHtml;
} }
/** /**
@@ -401,7 +352,7 @@ EOF
} }
$oSet = new CMDBObjectSet($oFilter); $oSet = new CMDBObjectSet($oFilter);
$oBlock = new DisplayBlock($oFilter, 'list', false); $oBlock = new DisplayBlock($oFilter, 'list', false);
$oBlock->Display($oP, "ResultsToAdd_{$this->m_sAttCode}", array('menu' => false, 'cssCount'=> '#count_'.$this->m_sAttCode.$this->m_sNameSuffix , 'selection_mode' => true, 'table_id' => 'add_'.$this->m_sAttCode)); // Don't display the 'Actions' menu on the results $oBlock->Display($oP, "ResultsToAdd_{$this->m_sAttCode}", array('menu' => false, 'cssCount'=> '#count_'.$this->m_sAttCode.$this->m_sNameSuffix , 'selection_mode' => true)); // Don't display the 'Actions' menu on the results
} }
public function DoAddObjects(WebPage $oP, $oFullSetFilter, $oCurrentObj) public function DoAddObjects(WebPage $oP, $oFullSetFilter, $oCurrentObj)
@@ -422,47 +373,5 @@ EOF
} }
} }
} }
/**
* Initializes the default search parameters based on 1) a 'current' object and 2) the silos defined by the context
* @param DBObject $oSourceObj
* @param DBObjectSearch $oSearch
*/
protected function SetSearchDefaultFromContext($oSourceObj, &$oSearch)
{
$oAppContext = new ApplicationContext();
$sSrcClass = get_class($oSourceObj);
$sDestClass = $oSearch->GetClass();
foreach($oAppContext->GetNames() as $key)
{
// Find the value of the object corresponding to each 'context' parameter
$aCallSpec = array($sSrcClass, 'MapContextParam');
$sAttCode = '';
if (is_callable($aCallSpec))
{
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
}
if (MetaModel::IsValidAttCode($sSrcClass, $sAttCode))
{
$oAttDef = MetaModel::GetAttributeDef($sSrcClass, $sAttCode);
$defaultValue = $oSourceObj->Get($sAttCode);
// Find the attcode for the same 'context' parameter in the destination class
// and sets its value as the default value for the search condition
$aCallSpec = array($sDestClass, 'MapContextParam');
$sAttCode = '';
if (is_callable($aCallSpec))
{
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
}
if (MetaModel::IsValidAttCode($sDestClass, $sAttCode) && !empty($defaultValue))
{
$oSearch->AddCondition($sAttCode, $defaultValue);
}
}
}
}
} }
?> ?>

View File

@@ -1,27 +1,27 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Class UIPasswordWidget * Class UIPasswordWidget
* UI wdiget for displaying and editing one-way encrypted passwords * UI wdiget for displaying and editing one-way encrypted passwords
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT.'/application/webpage.class.inc.php'); require_once(APPROOT.'/application/webpage.class.inc.php');

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Class UILinksWizard * Class UILinksWizard
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
class UILinksWizard class UILinksWizard
@@ -105,7 +104,7 @@ class UILinksWizard
var nbChecked = $('.selection:checked').length; var nbChecked = $('.selection:checked').length;
if (nbChecked > 0) if (nbChecked > 0)
{ {
$('#btnRemove').removeAttr('disabled'); $('#btnRemove').attr('disabled','');
} }
else else
{ {

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Class UIWizard * Class UIWizard
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
class UIWizard class UIWizard

View File

@@ -1,61 +0,0 @@
<?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/>
/**
* Store and retrieve user custom dashboards
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once(APPROOT.'/core/dbobject.class.php');
/**
* This class is used to store, in a persistent manner, a dashboard edited by a user
*/
class UserDashboard extends DBObject
{
public static function Init()
{
$aParams = array
(
"category" => "gui",
"key_type" => "autoincrement",
"name_attcode" => "user_id",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_app_dashboards",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("menu_code", array("allowed_values"=>null, "sql"=>"menu_code", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("contents", array("allowed_values"=>null, "sql"=>"contents", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
}
/**
* Overloading this function here to secure a fix done right before the release
* The real fix should be to implement this verb in DBObject
*/
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null)
{
$this->DBDelete($oDeletionPlan);
}
}
?>

View File

@@ -1,26 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* 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-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT.'/core/dbobject.class.php'); require_once(APPROOT.'/core/dbobject.class.php');
require_once(APPROOT.'/core/userrights.class.inc.php'); require_once(APPROOT.'/core/userrights.class.inc.php');
@@ -77,42 +77,6 @@ class appUserPreferences extends DBObject
self::Save(); self::Save();
} }
/**
* Clears the value for a given preference (or list of preferences that matches a pattern), and updates the database
* @param string $sPattern Code/Pattern of the properties/preferences to reset
* @param boolean $bPattern Whether or not the supplied code is a PCRE pattern
*/
static function UnsetPref($sCodeOrPattern, $bPattern = false)
{
if (self::$oUserPrefs == null)
{
self::Load();
}
$aPrefs = self::$oUserPrefs->Get('preferences');
if ($bPattern)
{
// the supplied code is a pattern, clear all preferences that match
foreach($aPrefs as $sKey => $void)
{
if (preg_match($sCodeOrPattern, $sKey))
{
unset($aPrefs[$sKey]);
}
}
self::$oUserPrefs->Set('preferences', $aPrefs);
}
else
{
unset($aPrefs[$sCodeOrPattern]);
self::$oUserPrefs->Set('preferences', $aPrefs);
}
// Save only if needed
if (self::$oUserPrefs->IsModified())
{
self::Save();
}
}
/** /**
* Call this function to get all the preferences for the user, packed as a JSON object * Call this function to get all the preferences for the user, packed as a JSON object
* @return string JSON representation of the preferences * @return string JSON representation of the preferences

View File

@@ -1,35 +1,32 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Static class utils * Static class utils
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT.'/core/config.class.inc.php'); require_once(APPROOT.'/core/config.class.inc.php');
require_once(APPROOT.'/application/transaction.class.inc.php'); require_once(APPROOT.'/application/transaction.class.inc.php');
define('ITOP_CONFIG_FILE', 'config-itop.php'); define('ITOP_CONFIG_FILE', APPROOT.'/config-itop.php');
define('ITOP_DEFAULT_CONFIG_FILE', APPCONF.ITOP_DEFAULT_ENV.'/'.ITOP_CONFIG_FILE);
define('SERVER_NAME_PLACEHOLDER', '$SERVER_NAME$'); define('SERVER_NAME_PLACEHOLDER', '$SERVER_NAME$');
class FileUploadException extends Exception class FileUploadException extends Exception
@@ -43,12 +40,12 @@ class FileUploadException extends Exception
*/ */
class utils class utils
{ {
private static $oConfig = null; private static $m_sConfigFile = ITOP_CONFIG_FILE;
private static $m_oConfig = null;
private static $m_bCASClient = false; private static $m_bCASClient = false;
// Parameters loaded from a file, parameters of the page/command line still have precedence // Parameters loaded from a file, parameters of the page/command line still have precedence
private static $m_aParamsFromFile = null; private static $m_aParamsFromFile = null;
private static $m_aParamSource = array();
protected static function LoadParamFile($sParamFile) protected static function LoadParamFile($sParamFile)
{ {
@@ -85,7 +82,6 @@ class utils
$sParam = $aMatches[1]; $sParam = $aMatches[1];
$value = trim($aMatches[2]); $value = trim($aMatches[2]);
self::$m_aParamsFromFile[$sParam] = $value; self::$m_aParamsFromFile[$sParam] = $value;
self::$m_aParamSource[$sParam] = $sParamFile;
} }
} }
} }
@@ -103,25 +99,6 @@ class utils
} }
} }
/**
* Return the source file from which the parameter has been found,
* usefull when it comes to pass user credential to a process executed
* in the background
* @param $sName Parameter name
* @return The file name if any, or null
*/
public static function GetParamSourceFile($sName)
{
if (array_key_exists($sName, self::$m_aParamSource))
{
return self::$m_aParamSource[$sName];
}
else
{
return null;
}
}
public static function IsModeCLI() public static function IsModeCLI()
{ {
$sSAPIName = php_sapi_name(); $sSAPIName = php_sapi_name();
@@ -175,18 +152,10 @@ class utils
public static function Sanitize($value, $defaultValue, $sSanitizationFilter) public static function Sanitize($value, $defaultValue, $sSanitizationFilter)
{ {
if ($value === $defaultValue) $retValue = self::Sanitize_Internal($value, $sSanitizationFilter);
if ($retValue === false)
{ {
// Preserve the real default value (can be used to detect missing mandatory parameters) $retValue = $defaultValue;
$retValue = $value;
}
else
{
$retValue = self::Sanitize_Internal($value, $sSanitizationFilter);
if ($retValue === false)
{
$retValue = $defaultValue;
}
} }
return $retValue; return $retValue;
} }
@@ -211,7 +180,6 @@ class utils
$retValue = filter_var($value, FILTER_SANITIZE_SPECIAL_CHARS); $retValue = filter_var($value, FILTER_SANITIZE_SPECIAL_CHARS);
break; break;
case 'context_param':
case 'parameter': case 'parameter':
case 'field_name': case 'field_name':
if (is_array($value)) if (is_array($value))
@@ -238,15 +206,12 @@ class utils
case 'field_name': case 'field_name':
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options"=>array("regexp"=>'/^[A-Za-z0-9_]+(->[A-Za-z0-9_]+)*$/'))); // att_code or att_code->name or AttCode->Name or AttCode->Key2->Name $retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options"=>array("regexp"=>'/^[A-Za-z0-9_]+(->[A-Za-z0-9_]+)*$/'))); // att_code or att_code->name or AttCode->Name or AttCode->Key2->Name
break; break;
case 'context_param':
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options"=>array("regexp"=>'/^[ A-Za-z0-9_=%:+-]*$/')));
break;
} }
} }
break; break;
break;
default: default:
case 'raw_data': case 'raw_data':
$retValue = $value; $retValue = $value;
@@ -464,30 +429,15 @@ class utils
// http://www.spaweditor.com/scripts/regex/index.php // http://www.spaweditor.com/scripts/regex/index.php
} }
static public function GetConfig()
{
if (self::$oConfig == null)
{
$sConfigFile = self::GetConfigFilePath();
if (file_exists($sConfigFile))
{
self::$oConfig = new Config($sConfigFile);
}
else
{
// When executing the setup, the config file may be still missing
self::$oConfig = new Config();
}
}
return self::$oConfig;
}
/** /**
* Returns the absolute URL to the application root path * Returns the absolute URL to the server's root path
* @return string The absolute URL to the application root, without the first slash * @param $sCurrentRelativePath string NO MORE USED, kept for backward compatibility only !
* @param $bForceHTTPS bool True to force HTTPS, false otherwise
* @return string The absolute URL to the server's root, without the first slash
*/ */
static public function GetAbsoluteUrlAppRoot() static public function GetAbsoluteUrlAppRoot()
{ {
$sUrl = self::GetConfig()->Get('app_root_url'); $sUrl = MetaModel::GetConfig()->Get('app_root_url');
if (strpos($sUrl, SERVER_NAME_PLACEHOLDER) > -1) if (strpos($sUrl, SERVER_NAME_PLACEHOLDER) > -1)
{ {
if (isset($_SERVER['SERVER_NAME'])) if (isset($_SERVER['SERVER_NAME']))
@@ -607,25 +557,25 @@ class utils
*/ */
static function InitCASClient() static function InitCASClient()
{ {
$sCASIncludePath = self::GetConfig()->Get('cas_include_path'); $sCASIncludePath = MetaModel::GetConfig()->Get('cas_include_path');
include_once($sCASIncludePath.'/CAS.php'); include_once($sCASIncludePath.'/CAS.php');
$bCASDebug = self::GetConfig()->Get('cas_debug'); $bCASDebug = MetaModel::GetConfig()->Get('cas_debug');
if ($bCASDebug) if ($bCASDebug)
{ {
phpCAS::setDebug(APPROOT.'log/error.log'); phpCAS::setDebug(APPROOT.'/error.log');
} }
if (!self::$m_bCASClient) if (!self::$m_bCASClient)
{ {
// Initialize phpCAS // Initialize phpCAS
$sCASVersion = self::GetConfig()->Get('cas_version'); $sCASVersion = MetaModel::GetConfig()->Get('cas_version');
$sCASHost = self::GetConfig()->Get('cas_host'); $sCASHost = MetaModel::GetConfig()->Get('cas_host');
$iCASPort = self::GetConfig()->Get('cas_port'); $iCASPort = MetaModel::GetConfig()->Get('cas_port');
$sCASContext = self::GetConfig()->Get('cas_context'); $sCASContext = MetaModel::GetConfig()->Get('cas_context');
phpCAS::client($sCASVersion, $sCASHost, $iCASPort, $sCASContext, false /* session already started */); phpCAS::client($sCASVersion, $sCASHost, $iCASPort, $sCASContext, false /* session already started */);
self::$m_bCASClient = true; self::$m_bCASClient = true;
$sCASCACertPath = self::GetConfig()->Get('cas_server_ca_cert_path'); $sCASCACertPath = MetaModel::GetConfig()->Get('cas_server_ca_cert_path');
if (empty($sCASCACertPath)) if (empty($sCASCACertPath))
{ {
// If no certificate authority is provided, do not attempt to validate // If no certificate authority is provided, do not attempt to validate
@@ -651,205 +601,5 @@ class utils
} }
echo "<p><pre>".print_r($aLightTrace, true)."</pre></p>\n"; echo "<p><pre>".print_r($aLightTrace, true)."</pre></p>\n";
} }
/**
* Execute the given iTop PHP script, passing it the current credentials
* Only CLI mode is supported, because of the need to hand the credentials over to the next process
* Throws an exception if the execution fails or could not be attempted (config issue)
* @param string $sScript Name and relative path to the file (relative to the iTop root dir)
* @param hash $aArguments Associative array of 'arg' => 'value'
* @return array(iCode, array(output lines))
*/
/**
*/
static function ExecITopScript($sScriptName, $aArguments)
{
$aDisabled = explode(', ', ini_get('disable_functions'));
if (in_array('exec', $aDisabled))
{
throw new Exception("The PHP exec() function has been disabled on this server");
}
$sPHPExec = trim(self::GetConfig()->Get('php_path'));
if (strlen($sPHPExec) == 0)
{
throw new Exception("The path to php must not be empty. Please set a value for 'php_path' in your configuration file.");
}
$sAuthUser = self::ReadParam('auth_user', '', 'raw_data');
$sAuthPwd = self::ReadParam('auth_pwd', '', 'raw_data');
$sParamFile = self::GetParamSourceFile('auth_user');
if (is_null($sParamFile))
{
$aArguments['auth_user'] = $sAuthUser;
$aArguments['auth_pwd'] = $sAuthPwd;
}
else
{
$aArguments['param_file'] = $sParamFile;
}
$aArgs = array();
foreach($aArguments as $sName => $value)
{
// Note: See comment from the 23-Apr-2004 03:30 in the PHP documentation
// It suggests to rely on pctnl_* function instead of using escapeshellargs
$aArgs[] = "--$sName=".escapeshellarg($value);
}
$sArgs = implode(' ', $aArgs);
$sScript = realpath(APPROOT.$sScriptName);
if (!file_exists($sScript))
{
throw new Exception("Could not find the script file '$sScriptName' from the directory '".APPROOT."'");
}
$sCommand = '"'.$sPHPExec.'" '.escapeshellarg($sScript).' -- '.$sArgs;
if (version_compare(phpversion(), '5.3.0', '<'))
{
if (substr(PHP_OS,0,3) == 'WIN')
{
// Under Windows, and for PHP 5.2.x, the whole command has to be quoted
// Cf PHP doc: http://php.net/manual/fr/function.exec.php, comment from the 27-Dec-2010
$sCommand = '"'.$sCommand.'"';
}
}
$sLastLine = exec($sCommand, $aOutput, $iRes);
if ($iRes == 1)
{
throw new Exception(Dict::S('Core:ExecProcess:Code1')." - ".$sCommand);
}
elseif ($iRes == 255)
{
$sErrors = implode("\n", $aOutput);
throw new Exception(Dict::S('Core:ExecProcess:Code255')." - ".$sCommand.":\n".$sErrors);
}
//$aOutput[] = $sCommand;
return array($iRes, $aOutput);
}
/**
* Get the current environment
*/
public static function GetCurrentEnvironment()
{
if (isset($_SESSION['itop_env']))
{
return $_SESSION['itop_env'];
}
else
{
return ITOP_DEFAULT_ENV;
}
}
/**
* Get the "Back" button to go out of the current environment
*/
public static function GetEnvironmentBackButton()
{
if (isset($_SESSION['itop_return_env']))
{
if (isset($_SESSION['itop_return_url']))
{
$sReturnUrl = $_SESSION['itop_return_url'];
}
else
{
$sReturnUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?switch_env='.$_SESSION['itop_return_env'];
}
return '&nbsp;<button onclick="window;location.href=\''.addslashes($sReturnUrl).'\'">'.Dict::S('UI:Button:Back').'</button>';
}
else
{
return '';
}
}
/**
* Get the "Back" button to go out of the current environment
*/
public static function GetPopupMenuItems($oPage, $iMenuId, $param, &$aActions)
{
foreach (MetaModel::EnumPlugins('iPopupMenuExtension') as $oExtensionInstance)
{
if (is_object($param) && !($param instanceof DBObject))
{
$tmpParam = clone $param; // In case the parameter is an DBObjectSet, clone it to prevent alterations
}
else
{
$tmpParam = $param;
}
foreach($oExtensionInstance->EnumItems($iMenuId, $tmpParam) as $oMenuItem)
{
if (is_object($oMenuItem))
{
$aActions[$oMenuItem->GetUID()] = $oMenuItem->GetMenuItem();
foreach($oMenuItem->GetLinkedScripts() as $sLinkedScript)
{
$oPage->add_linked_script($sLinkedScript);
}
}
}
}
}
/**
* Get target configuration file name (including full path)
*/
public static function GetConfigFilePath($sEnvironment = null)
{
if (is_null($sEnvironment))
{
$sEnvironment = self::GetCurrentEnvironment();
}
return APPCONF.$sEnvironment.'/'.ITOP_CONFIG_FILE;
}
/**
* Returns the absolute URL to the modules root path
* @return string ...
*/
static public function GetAbsoluteUrlModulesRoot()
{
$sUrl = self::GetAbsoluteUrlAppRoot().'env-'.self::GetCurrentEnvironment().'/';
return $sUrl;
}
/**
* Returns a name unique amongst the given list
* @param string $sProposed The default value
* @param array $aExisting An array of existing values (strings)
*/
static public function MakeUniqueName($sProposed, $aExisting)
{
if (in_array($sProposed, $aExisting))
{
$i = 1;
while (in_array($sProposed.$i, $aExisting) && ($i < 50))
{
$i++;
}
return $sProposed.$i;
}
else
{
return $sProposed;
}
}
/**
* Some characters cause troubles with jQuery when used inside DOM IDs, so let's replace them by the safe _ (underscore)
* @param string $sId The ID to sanitize
* @return string The sanitized ID
*/
static public function GetSafeId($sId)
{
return str_replace(array(':', '[', ']', '+', '-'), '_', $sId);
}
} }
?> ?>

View File

@@ -1,45 +1,28 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Class WebPage * Class WebPage
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
/**
* Generic interface common to CLI and Web pages
*/
Interface Page
{
public function output();
public function add($sText);
public function p($sText);
public function pre($sText);
public function add_comment($sText);
public function table($aConfig, $aData, $aParams = array());
}
/** /**
* Simple helper class to ease the production of HTML pages * Simple helper class to ease the production of HTML pages
* *
@@ -51,13 +34,12 @@ Interface Page
* $oPage->p("Hello World !"); * $oPage->p("Hello World !");
* $oPage->output(); * $oPage->output();
*/ */
class WebPage implements Page class WebPage
{ {
protected $s_title; protected $s_title;
protected $s_content; protected $s_content;
protected $s_deferred_content; protected $s_deferred_content;
protected $a_scripts; protected $a_scripts;
protected $a_dict_entries;
protected $a_styles; protected $a_styles;
protected $a_include_scripts; protected $a_include_scripts;
protected $a_include_stylesheets; protected $a_include_stylesheets;
@@ -68,8 +50,6 @@ class WebPage implements Page
protected $sContentType; protected $sContentType;
protected $sContentDisposition; protected $sContentDisposition;
protected $sContentFileName; protected $sContentFileName;
protected $s_sOutputFormat;
protected $a_OutputOptions;
public function __construct($s_title) public function __construct($s_title)
{ {
@@ -77,7 +57,6 @@ class WebPage implements Page
$this->s_content = ""; $this->s_content = "";
$this->s_deferred_content = ''; $this->s_deferred_content = '';
$this->a_scripts = array(); $this->a_scripts = array();
$this->a_dict_entries = array();
$this->a_styles = array(); $this->a_styles = array();
$this->a_linked_scripts = array(); $this->a_linked_scripts = array();
$this->a_linked_stylesheets = array(); $this->a_linked_stylesheets = array();
@@ -88,8 +67,6 @@ class WebPage implements Page
$this->sContentType = ''; $this->sContentType = '';
$this->sContentDisposition = ''; $this->sContentDisposition = '';
$this->sContentFileName = ''; $this->sContentFileName = '';
$this->s_OutputFormat = utils::ReadParam('output_format', 'html');
$this->a_OutputOptions = array();
ob_start(); // Start capturing the output ob_start(); // Start capturing the output
} }
@@ -144,13 +121,6 @@ class WebPage implements Page
$this->add('<pre>'.$s_html.'</pre>'); $this->add('<pre>'.$s_html.'</pre>');
} }
/**
* Add a comment
*/
public function add_comment($sText)
{
$this->add('<!--'.$sText.'-->');
}
/** /**
* Add a paragraph to the body of the page * Add a paragraph to the body of the page
*/ */
@@ -233,16 +203,6 @@ class WebPage implements Page
{ {
// Do nothing silently... this is not supported by this type of page... // Do nothing silently... this is not supported by this type of page...
} }
/**
* Add a dictionary entry for the Javascript side
*/
public function add_dict_entry($s_entryId)
{
$this->a_dict_entries[$s_entryId] = Dict::S($s_entryId);
}
/** /**
* Add some CSS definitions to the header of the page * Add some CSS definitions to the header of the page
*/ */
@@ -391,25 +351,6 @@ class WebPage implements Page
return $sHTMLValue; return $sHTMLValue;
} }
/**
* Discard unexpected output data
* This is a MUST when the Page output is DATA (download of a document, download CSV export, download ...)
*/
public function TrashUnexpectedOutput()
{
// This protection is redundant with a protection implemented in MetaModel::IncludeModule
// which detects such issues while loading module files
// Here, the purpose is to detect and discard characters produced by the code execution (echo)
$sPreviousContent = ob_get_clean();
if (trim($sPreviousContent) != '')
{
if (Utils::GetConfig() && Utils::GetConfig()->Get('debug_report_spurious_chars'))
{
IssueLog::Error("Output already started before downloading file:\nContent was:'$sPreviousContent'\n");
}
}
}
/** /**
* Outputs (via some echo) the complete HTML page by assembling all its elements * Outputs (via some echo) the complete HTML page by assembling all its elements
*/ */
@@ -450,7 +391,6 @@ class WebPage implements Page
} }
echo "</script>\n"; echo "</script>\n";
} }
$this->output_dict_entries();
foreach($this->a_linked_stylesheets as $a_stylesheet) foreach($this->a_linked_stylesheets as $a_stylesheet)
{ {
if ($a_stylesheet['condition'] != "") if ($a_stylesheet['condition'] != "")
@@ -487,11 +427,6 @@ class WebPage implements Page
echo '<div id="at_the_end">'.self::FilterXSS($this->s_deferred_content).'</div>'; echo '<div id="at_the_end">'.self::FilterXSS($this->s_deferred_content).'</div>';
echo "</body>\n"; echo "</body>\n";
echo "</html>\n"; echo "</html>\n";
if (class_exists('MetaModel'))
{
MetaModel::RecordQueryTrace();
}
} }
/** /**
@@ -580,123 +515,5 @@ class WebPage implements Page
{ {
return str_ireplace('<script', '&lt;script', $sHTML); return str_ireplace('<script', '&lt;script', $sHTML);
} }
/**
* What is the currently selected output format
* @return string The selected output format: html, pdf...
*/
public function GetOutputFormat()
{
return $this->s_OutputFormat;
}
/**
* Check whether the desired output format is possible or not
* @param string $sOutputFormat The desired output format: html, pdf...
* @return bool True if the format is Ok, false otherwise
*/
function IsOutputFormatAvailable($sOutputFormat)
{
$bResult = false;
switch($sOutputFormat)
{
case 'html':
$bResult = true; // Always supported
break;
case 'pdf':
$bResult = @is_readable(APPROOT.'lib/MPDF/mpdf.php');
break;
}
return $bResult;
}
/**
* Retrieves the value of a named output option for the given format
* @param string $sFormat The format: html or pdf
* @param string $sOptionName The name of the option
* @return mixed false if the option was never set or the options's value
*/
public function GetOutputOption($sFormat, $sOptionName)
{
if (isset($this->a_OutputOptions[$sFormat][$sOptionName]))
{
return $this->a_OutputOptions[$sFormat][$sOptionName];
}
return false;
}
/**
* Sets a named output option for the given format
* @param string $sFormat The format for which to set the option: html or pdf
* @param string $sOptionName the name of the option
* @param mixed $sValue The value of the option
*/
public function SetOutputOption($sFormat, $sOptionName, $sValue)
{
if (!isset($this->a_OutputOptions[$sFormat]))
{
$this->a_OutputOptions[$sFormat] = array($sOptionName => $sValue);
}
else
{
$this->a_OutputOptions[$sFormat][$sOptionName] = $sValue;
}
}
public function RenderPopupMenuItems($aActions, $aFavoriteActions = array())
{
$sPrevUrl = '';
$sHtml = '';
foreach ($aActions as $aAction)
{
$sClass = isset($aAction['class']) ? " class=\"{$aAction['class']}\"" : "";
$sOnClick = isset($aAction['onclick']) ? " onclick=\"{$aAction['onclick']}\"" : "";
if (empty($aAction['url']))
{
if ($sPrevUrl != '') // Don't output consecutively two separators...
{
$sHtml .= "<li>{$aAction['label']}</li>";
}
$sPrevUrl = '';
}
else
{
$sHtml .= "<li><a href=\"{$aAction['url']}\"$sClass $sOnClick>{$aAction['label']}</a></li>";
$sPrevUrl = $aAction['url'];
}
}
$sHtml .= "</ul></li></ul></div>";
foreach(array_reverse($aFavoriteActions) as $aAction)
{
$sHtml .= "<div class=\"actions_button\"><a href='{$aAction['url']}'>{$aAction['label']}</a></div>";
}
return $sHtml;
}
protected function output_dict_entries()
{
if (count($this->a_dict_entries)>0)
{
echo "<script type=\"text/javascript\">\n";
echo "var Dict = {};\n";
echo "Dict._entries = {};\n";
echo "Dict.S = function(sEntry) {\n";
echo " if (sEntry in Dict._entries)\n";
echo " {\n";
echo " return Dict._entries[sEntry];\n";
echo " }\n";
echo " else\n";
echo " {\n";
echo " return sEntry;\n";
echo " }\n";
echo "};\n";
foreach($this->a_dict_entries as $s_entry => $s_value)
{
echo "Dict._entries['$s_entry'] = '".addslashes($s_value)."';\n";
}
echo "</script>\n";
}
}
} }
?> ?>

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Class WizardHelper * Class WizardHelper
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT.'/application/uiwizard.class.inc.php'); require_once(APPROOT.'/application/uiwizard.class.inc.php');
@@ -77,7 +76,7 @@ class WizardHelper
if ( isset($aLinkedObject[$sLinkedAttCode]) && ($aLinkedObject[$sLinkedAttCode] !== null) ) if ( isset($aLinkedObject[$sLinkedAttCode]) && ($aLinkedObject[$sLinkedAttCode] !== null) )
{ {
$sLinkedAttDef = MetaModel::GetAttributeDef($sLinkedClass, $sLinkedAttCode); $sLinkedAttDef = MetaModel::GetAttributeDef($sLinkedClass, $sLinkedAttCode);
if (($sLinkedAttDef->IsExternalKey()) && ($aLinkedObject[$sLinkedAttCode] != '') && ($aLinkedObject[$sLinkedAttCode] > 0) ) if (($sLinkedAttDef->IsExternalKey()) && ($aLinkedObject[$sLinkedAttCode] != '') && ($aLinkedObject[$sLinkedAttCode] != 0) )
{ {
// For external keys: load the target object so that external fields // For external keys: load the target object so that external fields
// get filled too // get filled too
@@ -109,7 +108,7 @@ class WizardHelper
$oObj->Set($sAttCode, $oDocument); $oObj->Set($sAttCode, $oDocument);
} }
} }
else if (($oAttDef->IsExternalKey()) && (!empty($value)) && ($value > 0) ) else if (($oAttDef->IsExternalKey()) && (!empty($value)) )
{ {
// For external keys: load the target object so that external fields // For external keys: load the target object so that external fields
// get filled too // get filled too
@@ -261,7 +260,7 @@ class WizardHelper
foreach($aLinkObj as $sAttCode => $value) foreach($aLinkObj as $sAttCode => $value)
{ {
$oAttDef = MetaModel::GetAttributeDef($sLinkClass, $sAttCode); $oAttDef = MetaModel::GetAttributeDef($sLinkClass, $sAttCode);
if (($oAttDef->IsExternalKey()) && ($value != '') && ($value > 0)) if (($oAttDef->IsExternalKey()) && ($value != '') )
{ {
// For external keys: load the target object so that external fields // For external keys: load the target object so that external fields
// get filled too // get filled too

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2013 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Class XMLPage * Class XMLPage
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT."/application/webpage.class.inc.php"); require_once(APPROOT."/application/webpage.class.inc.php");
@@ -37,77 +36,65 @@ class XMLPage extends WebPage
var $m_bPassThrough; var $m_bPassThrough;
var $m_bHeaderSent; var $m_bHeaderSent;
function __construct($s_title, $bPassThrough = false) function __construct($s_title, $bPassThrough = false)
{ {
parent::__construct($s_title); parent::__construct($s_title);
$this->m_bPassThrough = $bPassThrough; $this->m_bPassThrough = $bPassThrough;
$this->m_bHeaderSent = false; $this->m_bHeaderSent = false;
$this->add_header("Content-type: text/xml; charset=utf-8"); $this->add_header("Content-type: text/xml; charset=utf-8");
$this->add_header("Cache-control: no-cache"); $this->add_header("Cache-control: no-cache");
$this->add_header("Content-location: export.xml"); $this->add_header("Content-location: export.xml");
} }
public function output() public function output()
{ {
if (!$this->m_bPassThrough) if (!$this->m_bPassThrough)
{ {
$this->s_content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n".trim($this->s_content); $this->add("<?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n");
$this->add_header("Content-Length: ".strlen($this->s_content)); $this->add_header("Content-Length: ".strlen(trim($this->s_content)));
foreach($this->a_headers as $s_header) foreach($this->a_headers as $s_header)
{ {
header($s_header); header($s_header);
} }
echo $this->s_content; echo trim($this->s_content);
} }
if (class_exists('MetaModel')) }
{
MetaModel::RecordQueryTrace(); public function add($sText)
} {
} if (!$this->m_bPassThrough)
{
public function add($sText) parent::add($sText);
{ }
if (!$this->m_bPassThrough) else
{ {
parent::add($sText); if ($this->m_bHeaderSent)
} {
else echo $sText;
{ }
if ($this->m_bHeaderSent) else
{ {
echo $sText; $s_captured_output = ob_get_contents();
} ob_end_clean();
else foreach($this->a_headers as $s_header)
{ {
$s_captured_output = ob_get_contents(); header($s_header);
ob_end_clean(); }
foreach($this->a_headers as $s_header)
{
header($s_header);
}
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n"; echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n";
echo trim($s_captured_output); echo trim($s_captured_output);
echo trim($this->s_content); echo trim($this->s_content);
echo $sText; echo $sText;
$this->m_bHeaderSent = true; $this->m_bHeaderSent = true;
} }
} }
} }
public function small_p($sText) public function small_p($sText)
{ {
} }
public function table($aConfig, $aData, $aParams = array()) public function table($aConfig, $aData, $aParams = array())
{ {
} }
public function TrashUnexpectedOutput()
{
if (!$this->m_bPassThrough)
{
parent::TrashUnexpectedOutput();
}
}
} }
?> ?>

View File

@@ -1,9 +1,5 @@
<?php <?php
define('APPROOT', dirname(__FILE__).'/'); define('APPROOT', dirname(__FILE__).'/');
define('APPCONF', APPROOT.'conf/');
define('ITOP_DEFAULT_ENV', 'production');
if (function_exists('microtime')) if (function_exists('microtime'))
{ {
$fItopStarted = microtime(true); $fItopStarted = microtime(true);

View File

@@ -1,28 +1,27 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Various dev/debug helpers * Various dev/debug helpers
* TODO: cleanup or at least re-organize * TODO: cleanup or at least re-organize
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Persistent classes (internal): user defined actions * Persistent classes (internal): user defined actions
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
@@ -43,7 +42,7 @@ abstract class Action extends cmdbAbstractObject
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array('name'), "reconc_keys" => array(),
"db_table" => "priv_action", "db_table" => "priv_action",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "realclass", "db_finalclass_field" => "realclass",
@@ -107,7 +106,7 @@ abstract class ActionNotification extends Action
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array('name'), "reconc_keys" => array(),
"db_table" => "priv_action_notification", "db_table" => "priv_action_notification",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
@@ -140,7 +139,7 @@ class ActionEmail extends ActionNotification
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "name", "name_attcode" => "name",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array('name'), "reconc_keys" => array(),
"db_table" => "priv_action_email", "db_table" => "priv_action_email",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
@@ -213,12 +212,8 @@ class ActionEmail extends ActionNotification
$aRecipients = array(); $aRecipients = array();
while ($oObj = $oSet->Fetch()) while ($oObj = $oSet->Fetch())
{ {
$sAddress = trim($oObj->Get($sEmailAttCode)); $aRecipients[] = $oObj->Get($sEmailAttCode);
if (strlen($sAddress) > 0) $this->m_iRecipients++;
{
$aRecipients[] = $sAddress;
$this->m_iRecipients++;
}
} }
return implode(', ', $aRecipients); return implode(', ', $aRecipients);
} }
@@ -281,6 +276,7 @@ class ActionEmail extends ActionNotification
protected function _DoExecute($oTrigger, $aContextArgs, &$oLog) protected function _DoExecute($oTrigger, $aContextArgs, &$oLog)
{ {
$sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass(); $sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass();
$aHeaders = array();
try try
{ {
$this->m_iRecipients = 0; $this->m_iRecipients = 0;
@@ -293,23 +289,23 @@ class ActionEmail extends ActionNotification
$sCC = $this->FindRecipients('cc', $aContextArgs); $sCC = $this->FindRecipients('cc', $aContextArgs);
$sBCC = $this->FindRecipients('bcc', $aContextArgs); $sBCC = $this->FindRecipients('bcc', $aContextArgs);
$sFrom = MetaModel::ApplyParams($this->Get('from'), $aContextArgs); $sFrom = $this->Get('from');
$sReplyTo = MetaModel::ApplyParams($this->Get('reply_to'), $aContextArgs); $sReplyTo = $this->Get('reply_to');
$sSubject = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs); $sSubject = MetaModel::ApplyParams($this->Get('subject'), $aContextArgs);
$sBody = MetaModel::ApplyParams($this->Get('body'), $aContextArgs); $sBody = MetaModel::ApplyParams($this->Get('body'), $aContextArgs);
$oObj = $aContextArgs['this->object()']; $oObj = $aContextArgs['this->object()'];
$sMessageId = sprintf('iTop_%s_%d_%f@%s.openitop.org', get_class($oObj), $oObj->GetKey(), microtime(true /* get as float*/), MetaModel::GetEnvironmentId()); $sMessageId = sprintf('<iTop_%s_%d_%f@%s.openitop.org>', get_class($oObj), $oObj->GetKey(), microtime(true /* get as float*/), MetaModel::GetConfig()->Get('session_name'));
$sReference = '<'.$sMessageId.'>'; $sReference = $sMessageId;
$aHeaders['Message-ID'] = $sMessageId;
} }
catch(Exception $e) catch(Exception $e)
{ {
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker); ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
throw $e; throw $e;
} }
ApplicationContext::SetUrlMakerClass($sPreviousUrlMaker);
if (!is_null($oLog)) if (!is_null($oLog))
{ {
// Note: we have to secure this because those values are calculated // Note: we have to secure this because those values are calculated
@@ -323,7 +319,7 @@ class ActionEmail extends ActionNotification
if (isset($sBody)) $oLog->Set('body', $sBody); if (isset($sBody)) $oLog->Set('body', $sBody);
} }
$oEmail = new EMail(); $oEmail = new EMail('', '', '', $aHeaders);
if ($this->IsBeingTested()) if ($this->IsBeingTested())
{ {
@@ -346,7 +342,6 @@ class ActionEmail extends ActionNotification
$oEmail->SetRecipientTO($this->Get('test_recipient')); $oEmail->SetRecipientTO($this->Get('test_recipient'));
$oEmail->SetRecipientFrom($this->Get('test_recipient')); $oEmail->SetRecipientFrom($this->Get('test_recipient'));
$oEmail->SetReferences($sReference); $oEmail->SetReferences($sReference);
$oEmail->SetMessageId($sMessageId);
} }
else else
{ {
@@ -358,18 +353,6 @@ class ActionEmail extends ActionNotification
$oEmail->SetRecipientFrom($sFrom); $oEmail->SetRecipientFrom($sFrom);
$oEmail->SetRecipientReplyTo($sReplyTo); $oEmail->SetRecipientReplyTo($sReplyTo);
$oEmail->SetReferences($sReference); $oEmail->SetReferences($sReference);
$oEmail->SetMessageId($sMessageId);
}
if (isset($aContextArgs['attachments']))
{
$aAttachmentReport = array();
foreach($aContextArgs['attachments'] as $oDocument)
{
$oEmail->AddAttachment($oDocument->GetData(), $oDocument->GetFileName(), $oDocument->GetMimeType());
$aAttachmentReport[] = array($oDocument->GetFileName(), $oDocument->GetMimeType(), strlen($oDocument->GetData()));
}
$oLog->Set('attachments', $aAttachmentReport);
} }
if (empty($this->m_aMailErrors)) if (empty($this->m_aMailErrors))
@@ -408,4 +391,4 @@ class ActionEmail extends ActionNotification
} }
} }
} }
?> ?>

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Utility to import/export the DB from/to a ZIP file * Utility to import/export the DB from/to a ZIP file
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Persistent classes (internal): user defined actions * Persistent classes (internal): user defined actions
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
@@ -139,10 +138,10 @@ class AsyncSendEmail extends AsyncTask
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes(); MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeInteger("version", array("allowed_values"=>null, "sql"=>"version", "default_value"=>Email::ORIGINAL_FORMAT, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("to", array("allowed_values"=>null, "sql"=>"to", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeText("to", array("allowed_values"=>null, "sql"=>"to", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeText("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeLongText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeText("body", array("allowed_values"=>null, "sql"=>"body", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("header", array("allowed_values"=>null, "sql"=>"header", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists // Display lists
// MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'test_recipient', 'from', 'reply_to', 'to', 'cc', 'bcc', 'subject', 'body', 'importance', 'trigger_list')); // Attributes to be displayed for the complete details // MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'test_recipient', 'from', 'reply_to', 'to', 'cc', 'bcc', 'subject', 'body', 'importance', 'trigger_list')); // Attributes to be displayed for the complete details
@@ -152,42 +151,31 @@ class AsyncSendEmail extends AsyncTask
// 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
} }
static public function AddToQueue(EMail $oEMail, $oLog) static public function AddToQueue($sTo, $sSubject, $sBody, $aHeaders, $oLog)
{ {
$oNew = MetaModel::NewObject(__class__); $oNew = MetaModel::NewObject(__class__);
if ($oLog) if ($oLog)
{ {
$oNew->Set('event_id', $oLog->GetKey()); $oNew->Set('event_id', $oLog->GetKey());
} }
$oNew->Set('to', $oEMail->GetRecipientTO(true /* string */)); $oNew->Set('to', $sTo);
$oNew->Set('subject', $oEMail->GetSubject()); $oNew->Set('subject', $sSubject);
$oNew->Set('body', $sBody);
// $oNew->Set('version', 1); $sHeaders = serialize($aHeaders);
// $sMessage = serialize($oEMail); $oNew->Set('header', $sHeaders);
$oNew->Set('version', 2);
$sMessage = $oEMail->SerializeV2();
$oNew->Set('message', $sMessage);
$oNew->DBInsert(); $oNew->DBInsert();
} }
public function DoProcess() public function DoProcess()
{ {
$sMessage = $this->Get('message'); $sTo = $this->Get('to');
$iVersion = (int) $this->Get('version'); $sSubject = $this->Get('subject');
switch($iVersion) $sBody = $this->Get('body');
{ $sHeaders = $this->Get('header');
case Email::FORMAT_V2: $aHeaders = unserialize($sHeaders);
$oEMail = Email::UnSerializeV2($sMessage);
break; $oEmail = new EMail($sTo, $sSubject, $sBody, $aHeaders);
$iRes = $oEmail->Send($aIssues, true /* force synchro !!!!! */);
case Email::ORIGINAL_FORMAT:
$oEMail = unserialize($sMessage);
break;
default:
return 'Unknown version of the serialization format: '.$iVersion;
}
$iRes = $oEMail->Send($aIssues, true /* force synchro !!!!! */);
switch ($iRes) switch ($iRes)
{ {
case EMAIL_SEND_OK: case EMAIL_SEND_OK:
@@ -201,4 +189,4 @@ class AsyncSendEmail extends AsyncTask
} }
} }
} }
?> ?>

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +1,27 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Class BackgroundProcess * Class BackgroundProcess
* Any extension that must be called regularly to be executed in the background * Any extension that must be called regularly to be executed in the background
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
interface iBackgroundProcess interface iBackgroundProcess

View File

@@ -1,34 +1,29 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Bulk change facility (common to interactive and batch usages) * Bulk change facility (common to interactive and batch usages)
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
// The BOM is added at the head of exported UTF-8 CSV data, and removed (if present) from input UTF-8 data.
// This helps MS-Excel (Version > 2007, Windows only) in changing its interpretation of a CSV file (by default Excel reads data as ISO-8859-1 -not 100% sure!)
define('UTF8_BOM', chr(239).chr(187).chr(191)); // 0xEF, 0xBB, 0xBF
/** /**
* BulkChange * BulkChange
* Interpret a given data set and update the DB accordingly (fake mode avail.) * Interpret a given data set and update the DB accordingly (fake mode avail.)
@@ -89,16 +84,15 @@ class CellStatus_Modify extends CellChangeSpec
{ {
protected $m_previousValue; protected $m_previousValue;
public function __construct($proposedValue, $previousValue = null) public function __construct($proposedValue, $previousValue)
{ {
// Unused (could be costly to know -see the case of reconciliation on ext keys) $this->m_previousValue = $previousValue;
//$this->m_previousValue = $previousValue;
parent::__construct($proposedValue); parent::__construct($proposedValue);
} }
public function GetDescription() public function GetDescription()
{ {
return Dict::S('UI:CSVReport-Value-Modified'); return 'Modified';
} }
//public function GetPreviousValue() //public function GetPreviousValue()
@@ -121,9 +115,9 @@ class CellStatus_Issue extends CellStatus_Modify
{ {
if (is_null($this->m_proposedValue)) if (is_null($this->m_proposedValue))
{ {
return Dict::Format('UI:CSVReport-Value-SetIssue', $this->m_sReason); return 'Could not be changed - reason: '.$this->m_sReason;
} }
return Dict::Format('UI:CSVReport-Value-ChangeIssue', $this->m_proposedValue, $this->m_sReason); return 'Could not be changed to '.$this->m_proposedValue.' - reason: '.$this->m_sReason;
} }
} }
@@ -136,7 +130,7 @@ class CellStatus_SearchIssue extends CellStatus_Issue
public function GetDescription() public function GetDescription()
{ {
return Dict::S('UI:CSVReport-Value-NoMatch'); return 'No match';
} }
} }
@@ -149,7 +143,7 @@ class CellStatus_NullIssue extends CellStatus_Issue
public function GetDescription() public function GetDescription()
{ {
return Dict::S('UI:CSVReport-Value-Missing'); return 'Missing mandatory value';
} }
} }
@@ -168,7 +162,7 @@ class CellStatus_Ambiguous extends CellStatus_Issue
public function GetDescription() public function GetDescription()
{ {
$sCount = $this->m_iCount; $sCount = $this->m_iCount;
return Dict::Format('UI:CSVReport-Value-Ambiguous', $sCount); return "Ambiguous: found $sCount objects";
} }
} }
@@ -192,7 +186,7 @@ class RowStatus_NoChange extends RowStatus
{ {
public function GetDescription() public function GetDescription()
{ {
return Dict::S('UI:CSVReport-Row-Unchanged'); return "unchanged";
} }
} }
@@ -200,7 +194,7 @@ class RowStatus_NewObj extends RowStatus
{ {
public function GetDescription() public function GetDescription()
{ {
return Dict::S('UI:CSVReport-Row-Created'); return "created";
} }
} }
@@ -215,7 +209,7 @@ class RowStatus_Modify extends RowStatus
public function GetDescription() public function GetDescription()
{ {
return Dict::Format('UI:CSVReport-Row-Updated', $this->m_iChanged); return "updated ".$this->m_iChanged." cols";
} }
} }
@@ -223,7 +217,7 @@ class RowStatus_Disappeared extends RowStatus_Modify
{ {
public function GetDescription() public function GetDescription()
{ {
return Dict::Format('UI:CSVReport-Row-Disappeared', $this->m_iChanged); return "disappeared, changed ".$this->m_iChanged." cols";
} }
} }
@@ -238,7 +232,7 @@ class RowStatus_Issue extends RowStatus
public function GetDescription() public function GetDescription()
{ {
return Dict::Format('UI:CSVReport-Row-Issue', $this->m_sReason); return 'Issue: '.$this->m_sReason;
} }
} }
@@ -259,9 +253,8 @@ class BulkChange
protected $m_sSynchroScope; // OQL - if specified, then the missing items will be reported protected $m_sSynchroScope; // OQL - if specified, then the missing items will be reported
protected $m_aOnDisappear; // array of attcode => value, values to be set when an object gets out of scope (ignored if no scope has been defined) protected $m_aOnDisappear; // array of attcode => value, values to be set when an object gets out of scope (ignored if no scope has been defined)
protected $m_sDateFormat; // Date format specification, see utils::StringToTime() protected $m_sDateFormat; // Date format specification, see utils::StringToTime()
protected $m_bLocalizedValues; // Values in the data set are localized (see AttributeEnum)
public function __construct($sClass, $aData, $aAttList, $aExtKeys, $aReconcilKeys, $sSynchroScope = null, $aOnDisappear = null, $sDateFormat = null, $bLocalize = false) public function __construct($sClass, $aData, $aAttList, $aExtKeys, $aReconcilKeys, $sSynchroScope = null, $aOnDisappear = null, $sDateFormat = null)
{ {
$this->m_sClass = $sClass; $this->m_sClass = $sClass;
$this->m_aData = $aData; $this->m_aData = $aData;
@@ -271,7 +264,6 @@ class BulkChange
$this->m_sSynchroScope = $sSynchroScope; $this->m_sSynchroScope = $sSynchroScope;
$this->m_aOnDisappear = $aOnDisappear; $this->m_aOnDisappear = $aOnDisappear;
$this->m_sDateFormat = $sDateFormat; $this->m_sDateFormat = $sDateFormat;
$this->m_bLocalizedValues = $bLocalize;
} }
protected $m_bReportHtml = false; protected $m_bReportHtml = false;
@@ -297,9 +289,7 @@ class BulkChange
foreach ($this->m_aExtKeys[$sAttCode] as $sForeignAttCode => $iCol) foreach ($this->m_aExtKeys[$sAttCode] as $sForeignAttCode => $iCol)
{ {
// The foreign attribute is one of our reconciliation key // The foreign attribute is one of our reconciliation key
$oForeignAtt = MetaModel::GetAttributeDef($oExtKey->GetTargetClass(), $sForeignAttCode); $oReconFilter->AddCondition($sForeignAttCode, $aRowData[$iCol], '=');
$value = $oForeignAtt->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues);
$oReconFilter->AddCondition($sForeignAttCode, $value, '=');
$aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]); $aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]);
} }
@@ -341,7 +331,6 @@ class BulkChange
{ {
foreach ($aKeyConfig as $sForeignAttCode => $iCol) foreach ($aKeyConfig as $sForeignAttCode => $iCol)
{ {
// Default reporting
$aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]); $aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]);
} }
if ($oExtKey->IsNullAllowed()) if ($oExtKey->IsNullAllowed())
@@ -351,8 +340,8 @@ class BulkChange
} }
else else
{ {
$aErrors[$sAttCode] = Dict::S('UI:CSVReport-Value-Issue-Null'); $aErrors[$sAttCode] = "Null not allowed";
$aResults[$sAttCode]= new CellStatus_Issue(null, $oTargetObj->Get($sAttCode), Dict::S('UI:CSVReport-Value-Issue-Null')); $aResults[$sAttCode]= new CellStatus_Issue(null, $oTargetObj->Get($sAttCode), 'Null not allowed');
} }
} }
else else
@@ -361,23 +350,14 @@ class BulkChange
foreach ($aKeyConfig as $sForeignAttCode => $iCol) foreach ($aKeyConfig as $sForeignAttCode => $iCol)
{ {
// The foreign attribute is one of our reconciliation key // The foreign attribute is one of our reconciliation key
if ($sForeignAttCode == 'id') $oReconFilter->AddCondition($sForeignAttCode, $aRowData[$iCol], '=');
{
$value = $aRowData[$iCol];
}
else
{
$oForeignAtt = MetaModel::GetAttributeDef($oExtKey->GetTargetClass(), $sForeignAttCode);
$value = $oForeignAtt->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues);
}
$oReconFilter->AddCondition($sForeignAttCode, $value, '=');
$aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]); $aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]);
} }
$oExtObjects = new CMDBObjectSet($oReconFilter); $oExtObjects = new CMDBObjectSet($oReconFilter);
switch($oExtObjects->Count()) switch($oExtObjects->Count())
{ {
case 0: case 0:
$aErrors[$sAttCode] = Dict::S('UI:CSVReport-Value-Issue-NotFound'); $aErrors[$sAttCode] = "Object not found";
$aResults[$sAttCode]= new CellStatus_SearchIssue(); $aResults[$sAttCode]= new CellStatus_SearchIssue();
break; break;
case 1: case 1:
@@ -386,7 +366,7 @@ class BulkChange
$oTargetObj->Set($sAttCode, $oForeignObj->GetKey()); $oTargetObj->Set($sAttCode, $oForeignObj->GetKey());
break; break;
default: default:
$aErrors[$sAttCode] = Dict::Format('UI:CSVReport-Value-Issue-FoundMany', $oExtObjects->Count()); $aErrors[$sAttCode] = "Found ".$oExtObjects->Count()." matches";
$aResults[$sAttCode]= new CellStatus_Ambiguous($oTargetObj->Get($sAttCode), $oExtObjects->Count(), $oReconFilter->ToOql()); $aResults[$sAttCode]= new CellStatus_Ambiguous($oTargetObj->Get($sAttCode), $oExtObjects->Count(), $oReconFilter->ToOql());
} }
} }
@@ -404,11 +384,6 @@ class BulkChange
else else
{ {
$aResults[$sAttCode]= new CellStatus_Modify($iForeignObj, $oTargetObj->GetOriginal($sAttCode)); $aResults[$sAttCode]= new CellStatus_Modify($iForeignObj, $oTargetObj->GetOriginal($sAttCode));
foreach ($aKeyConfig as $sForeignAttCode => $iCol)
{
// Report the change on reconciliation values as well
$aResults[$iCol] = new CellStatus_Modify($aRowData[$iCol]);
}
} }
} }
else else
@@ -426,43 +401,29 @@ class BulkChange
if ($sAttCode == 'id') continue; if ($sAttCode == 'id') continue;
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode); $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
$aReasons = array(); if ($oAttDef->IsLinkSet() && $oAttDef->IsIndirect())
$iFlags = $oTargetObj->GetAttributeFlags($sAttCode, $aReasons);
if ( (($iFlags & OPT_ATT_READONLY) == OPT_ATT_READONLY) && ( $oTargetObj->Get($sAttCode) != $aRowData[$iCol]) )
{
$aErrors[$sAttCode] = Dict::Format('UI:CSVReport-Value-Issue-Readonly', $sAttCode, $oTargetObj->Get($sAttCode), $aRowData[$iCol]);
}
else if ($oAttDef->IsLinkSet() && $oAttDef->IsIndirect())
{ {
try try
{ {
$oSet = $oAttDef->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues); $oSet = $oAttDef->MakeValueFromString($aRowData[$iCol]);
$oTargetObj->Set($sAttCode, $oSet); $oTargetObj->Set($sAttCode, $oSet);
} }
catch(CoreException $e) catch(CoreException $e)
{ {
$aErrors[$sAttCode] = Dict::Format('UI:CSVReport-Value-Issue-Format', $e->getMessage()); $aErrors[$sAttCode] = "Failed to process input: ".$e->getMessage();
} }
} }
else else
{ {
$value = $oAttDef->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues); $res = $oTargetObj->CheckValue($sAttCode, $aRowData[$iCol]);
if (is_null($value) && (strlen($aRowData[$iCol]) > 0)) if ($res === true)
{ {
$aErrors[$sAttCode] = Dict::Format('UI:CSVReport-Value-Issue-NoMatch', $sAttCode); $oTargetObj->Set($sAttCode, $aRowData[$iCol]);
} }
else else
{ {
$res = $oTargetObj->CheckValue($sAttCode, $value); // $res is a string with the error description
if ($res === true) $aErrors[$sAttCode] = "Unexpected value for attribute '$sAttCode': $res";
{
$oTargetObj->Set($sAttCode, $value);
}
else
{
// $res is a string with the error description
$aErrors[$sAttCode] = Dict::Format('UI:CSVReport-Value-Issue-Unknown', $sAttCode, $res);
}
} }
} }
} }
@@ -480,19 +441,17 @@ class BulkChange
{ {
if ($this->m_bReportHtml) if ($this->m_bReportHtml)
{ {
$sCurValue = $oTargetObj->GetAsHTML($sAttCode, $this->m_bLocalizedValues); $sCurValue = $oTargetObj->GetAsHTML($sAttCode);
$sOrigValue = $oTargetObj->GetOriginalAsHTML($sAttCode, $this->m_bLocalizedValues); $sOrigValue = $oTargetObj->GetOriginalAsHTML($sAttCode);
$sInput = htmlentities($aRowData[$iCol], ENT_QUOTES, 'UTF-8');
} }
else else
{ {
$sCurValue = $oTargetObj->GetAsCSV($sAttCode, $this->m_sReportCsvSep, $this->m_sReportCsvDelimiter, $this->m_bLocalizedValues); $sCurValue = $oTargetObj->GetAsCSV($sAttCode, $this->m_sReportCsvSep, $this->m_sReportCsvDelimiter);
$sOrigValue = $oTargetObj->GetOriginalAsCSV($sAttCode, $this->m_sReportCsvSep, $this->m_sReportCsvDelimiter, $this->m_bLocalizedValues); $sOrigValue = $oTargetObj->GetOriginalAsCSV($sAttCode, $this->m_sReportCsvSep, $this->m_sReportCsvDelimiter);
$sInput = $aRowData[$iCol];
} }
if (isset($aErrors[$sAttCode])) if (isset($aErrors[$sAttCode]))
{ {
$aResults[$iCol]= new CellStatus_Issue($aRowData[$iCol], $sOrigValue, $aErrors[$sAttCode]); $aResults[$iCol]= new CellStatus_Issue($sCurValue, $sOrigValue, $aErrors[$sAttCode]);
} }
elseif (array_key_exists($sAttCode, $aChangedFields)) elseif (array_key_exists($sAttCode, $aChangedFields))
{ {
@@ -519,7 +478,7 @@ class BulkChange
if ($res !== true) if ($res !== true)
{ {
// $res contains the error description // $res contains the error description
$aErrors["GLOBAL"] = Dict::Format('UI:CSVReport-Row-Issue-Inconsistent', $res); $aErrors["GLOBAL"] = "Attributes not consistent with each others: $res";
} }
return $aResults; return $aResults;
} }
@@ -583,7 +542,7 @@ class BulkChange
if ($res !== true) if ($res !== true)
{ {
// $res contains the error description // $res contains the error description
$aErrors["GLOBAL"] = Dict::Format('UI:CSVReport-Row-Issue-Inconsistent', $res); $aErrors["GLOBAL"] = "Attributes not consistent with each others: $res";
} }
return $aResults; return $aResults;
} }
@@ -597,7 +556,7 @@ class BulkChange
if (count($aErrors) > 0) if (count($aErrors) > 0)
{ {
$sErrors = implode(', ', $aErrors); $sErrors = implode(', ', $aErrors);
$aResult[$iRow]["__STATUS__"] = new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-Attribute')); $aResult[$iRow]["__STATUS__"] = new RowStatus_Issue("Unexpected attribute value(s)");
return $oTargetObj; return $oTargetObj;
} }
@@ -616,7 +575,7 @@ class BulkChange
if (count($aMissingKeys) > 0) if (count($aMissingKeys) > 0)
{ {
$sMissingKeys = implode(', ', $aMissingKeys); $sMissingKeys = implode(', ', $aMissingKeys);
$aResult[$iRow]["__STATUS__"] = new RowStatus_Issue(Dict::Format('UI:CSVReport-Row-Issue-MissingExtKey', $sMissingKeys)); $aResult[$iRow]["__STATUS__"] = new RowStatus_Issue("Could not be created, due to missing external key(s): $sMissingKeys");
return $oTargetObj; return $oTargetObj;
} }
@@ -650,7 +609,7 @@ class BulkChange
if (count($aErrors) > 0) if (count($aErrors) > 0)
{ {
$sErrors = implode(', ', $aErrors); $sErrors = implode(', ', $aErrors);
$aResult[$iRow]["__STATUS__"] = new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-Attribute')); $aResult[$iRow]["__STATUS__"] = new RowStatus_Issue("Unexpected attribute value(s)");
return; return;
} }
@@ -691,7 +650,7 @@ class BulkChange
if (count($aErrors) > 0) if (count($aErrors) > 0)
{ {
$sErrors = implode(', ', $aErrors); $sErrors = implode(', ', $aErrors);
$aResult[$iRow]["__STATUS__"] = new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-Attribute')); $aResult[$iRow]["__STATUS__"] = new RowStatus_Issue("Unexpected attribute value(s)");
return; return;
} }
@@ -767,8 +726,8 @@ class BulkChange
else else
{ {
// Leave the cell unchanged // Leave the cell unchanged
$aResult[$iRow]["__STATUS__"]= new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-DateFormat')); $aResult[$iRow]["__STATUS__"]= new RowStatus_Issue("wrong date format");
$aResult[$iRow][$sAttCode] = new CellStatus_Issue(null, $this->m_aData[$iRow][$iCol], Dict::S('UI:CSVReport-Row-Issue-DateFormat')); $aResult[$iRow][$sAttCode] = new CellStatus_Issue(null, $this->m_aData[$iRow][$iCol], 'Wrong date format');
} }
} }
} }
@@ -788,106 +747,91 @@ class BulkChange
// An issue at the earlier steps - skip the rest // An issue at the earlier steps - skip the rest
continue; continue;
} }
try $oReconciliationFilter = new CMDBSearchFilter($this->m_sClass);
$bSkipQuery = false;
foreach($this->m_aReconcilKeys as $sAttCode)
{ {
$oReconciliationFilter = new CMDBSearchFilter($this->m_sClass); $valuecondition = null;
$bSkipQuery = false; if (array_key_exists($sAttCode, $this->m_aExtKeys))
foreach($this->m_aReconcilKeys as $sAttCode)
{ {
$valuecondition = null; if ($this->IsNullExternalKeySpec($aRowData, $sAttCode))
if (array_key_exists($sAttCode, $this->m_aExtKeys))
{ {
if ($this->IsNullExternalKeySpec($aRowData, $sAttCode)) $oExtKey = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
if ($oExtKey->IsNullAllowed())
{ {
$oExtKey = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode); $valuecondition = $oExtKey->GetNullValue();
if ($oExtKey->IsNullAllowed()) $aResult[$iRow][$sAttCode] = new CellStatus_Void($oExtKey->GetNullValue());
{
$valuecondition = $oExtKey->GetNullValue();
$aResult[$iRow][$sAttCode] = new CellStatus_Void($oExtKey->GetNullValue());
}
else
{
$aResult[$iRow][$sAttCode] = new CellStatus_NullIssue();
}
} }
else else
{ {
// The value has to be found or verified $aResult[$iRow][$sAttCode] = new CellStatus_NullIssue();
list($sQuery, $aMatches) = $this->ResolveExternalKey($aRowData, $sAttCode, $aResult[$iRow]); }
}
if (count($aMatches) == 1) else
{ {
$oRemoteObj = reset($aMatches); // first item // The value has to be found or verified
$valuecondition = $oRemoteObj->GetKey(); list($sQuery, $aMatches) = $this->ResolveExternalKey($aRowData, $sAttCode, $aResult[$iRow]);
$aResult[$iRow][$sAttCode] = new CellStatus_Void($oRemoteObj->GetKey());
} if (count($aMatches) == 1)
elseif (count($aMatches) == 0) {
{ $oRemoteObj = reset($aMatches); // first item
$aResult[$iRow][$sAttCode] = new CellStatus_SearchIssue(); $valuecondition = $oRemoteObj->GetKey();
} $aResult[$iRow][$sAttCode] = new CellStatus_Void($oRemoteObj->GetKey());
else
{
$aResult[$iRow][$sAttCode] = new CellStatus_Ambiguous(null, count($aMatches), $sQuery);
}
} }
} elseif (count($aMatches) == 0)
else
{
// The value is given in the data row
$iCol = $this->m_aAttList[$sAttCode];
if ($sAttCode == 'id')
{ {
$valuecondition = $aRowData[$iCol]; $aResult[$iRow][$sAttCode] = new CellStatus_SearchIssue();
} }
else else
{ {
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode); $aResult[$iRow][$sAttCode] = new CellStatus_Ambiguous(null, count($aMatches), $sQuery);
$valuecondition = $oAttDef->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues);
} }
} }
if (is_null($valuecondition))
{
$bSkipQuery = true;
}
else
{
$oReconciliationFilter->AddCondition($sAttCode, $valuecondition, '=');
}
}
if ($bSkipQuery)
{
$aResult[$iRow]["__STATUS__"]= new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-Reconciliation'));
} }
else else
{ {
$oReconciliationSet = new CMDBObjectSet($oReconciliationFilter); // The value is given in the data row
switch($oReconciliationSet->Count()) $iCol = $this->m_aAttList[$sAttCode];
{ $valuecondition = $aRowData[$iCol];
case 0: }
$oTargetObj = $this->CreateObject($aResult, $iRow, $aRowData, $oChange); if (is_null($valuecondition))
// $aResult[$iRow]["__STATUS__"]=> set in CreateObject {
$aVisited[] = $oTargetObj->GetKey(); $bSkipQuery = true;
break; }
case 1: else
$oTargetObj = $oReconciliationSet->Fetch(); {
$this->UpdateObject($aResult, $iRow, $oTargetObj, $aRowData, $oChange); $oReconciliationFilter->AddCondition($sAttCode, $valuecondition, '=');
// $aResult[$iRow]["__STATUS__"]=> set in UpdateObject
if (!is_null($this->m_sSynchroScope))
{
$aVisited[] = $oTargetObj->GetKey();
}
break;
default:
// Found several matches, ambiguous
$aResult[$iRow]["__STATUS__"]= new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-Ambiguous'));
$aResult[$iRow]["id"]= new CellStatus_Ambiguous(0, $oReconciliationSet->Count(), $oReconciliationFilter->ToOql());
$aResult[$iRow]["finalclass"]= 'n/a';
}
} }
} }
catch (Exception $e) if ($bSkipQuery)
{ {
$aResult[$iRow]["__STATUS__"]= new RowStatus_Issue(Dict::Format('UI:CSVReport-Row-Issue-Internal', get_class($e), $e->getMessage())); $aResult[$iRow]["__STATUS__"]= new RowStatus_Issue("failed to reconcile");
}
else
{
$oReconciliationSet = new CMDBObjectSet($oReconciliationFilter);
switch($oReconciliationSet->Count())
{
case 0:
$oTargetObj = $this->CreateObject($aResult, $iRow, $aRowData, $oChange);
// $aResult[$iRow]["__STATUS__"]=> set in CreateObject
$aVisited[] = $oTargetObj->GetKey();
break;
case 1:
$oTargetObj = $oReconciliationSet->Fetch();
$this->UpdateObject($aResult, $iRow, $oTargetObj, $aRowData, $oChange);
// $aResult[$iRow]["__STATUS__"]=> set in UpdateObject
if (!is_null($this->m_sSynchroScope))
{
$aVisited[] = $oTargetObj->GetKey();
}
break;
default:
// Found several matches, ambiguous
$aResult[$iRow]["__STATUS__"]= new RowStatus_Issue("ambiguous reconciliation");
$aResult[$iRow]["id"]= new CellStatus_Ambiguous(0, $oReconciliationSet->Count(), $oReconciliationFilter->ToOql());
$aResult[$iRow]["finalclass"]= 'n/a';
}
} }
} }
@@ -964,7 +908,7 @@ class BulkChange
$bLimitExceeded = true; $bLimitExceeded = true;
if (!$bShowAll) if (!$bShowAll)
{ {
$iMaxObjects = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit()); $iMaxObjects = MetaModel::GetConfig()->GetMinDisplayLimit();
$oBulkChanges->SetLimit($iMaxObjects); $oBulkChanges->SetLimit($iMaxObjects);
} }
} }
@@ -973,7 +917,7 @@ class BulkChange
$aDetails = array(); $aDetails = array();
while ($oChange = $oBulkChanges->Fetch()) while ($oChange = $oBulkChanges->Fetch())
{ {
$sDate = '<a href="csvimport.php?step=10&changeid='.$oChange->GetKey().'&'.$oAppContext->GetForLink().'">'.$oChange->Get('date').'</a>'; $sDate = '<a href="?step=10&changeid='.$oChange->GetKey().'&'.$oAppContext->GetForLink().'">'.$oChange->Get('date').'</a>';
$sUser = $oChange->GetUserName(); $sUser = $oChange->GetUserName();
if (preg_match('/^(.*)\\(CSV\\)$/i', $oChange->Get('userinfo'), $aMatches)) if (preg_match('/^(.*)\\(CSV\\)$/i', $oChange->Get('userinfo'), $aMatches))
{ {
@@ -1216,6 +1160,49 @@ EOF
} }
$oPage->table($aConfig, $aDetails); $oPage->table($aConfig, $aDetails);
} }
/**
* Get the user friendly name for an 'extended' attribute code i.e 'name', becomes 'Name' and 'org_id->name' becomes 'Organization->Name'
* @param string $sClassName The name of the class
* @param string $sAttCodeEx Either an attribute code or ext_key_name->att_code
* @return string A user friendly format of the string: AttributeName or AttributeName->ExtAttributeName
*/
public static function GetFriendlyAttCodeName($sClassName, $sAttCodeEx)
{
$sFriendlyName = '';
if (preg_match('/(.+)->(.+)/', $sAttCodeEx, $aMatches) > 0)
{
$sAttribute = $aMatches[1];
$sField = $aMatches[2];
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttribute);
if ($oAttDef->IsExternalKey())
{
$sTargetClass = $oAttDef->GetTargetClass();
$oTargetAttDef = MetaModel::GetAttributeDef($sTargetClass, $sField);
$sFriendlyName = $oAttDef->GetLabel().'->'.$oTargetAttDef->GetLabel();
}
else
{
// hum, hum... should never happen, we'd better raise an exception
throw(new Exception(Dict::Format('UI:CSVImport:ErrorExtendedAttCode', $sAttCodeEx, $sAttribute, $sClassName)));
}
}
else
{
if ($sAttCodeEx == 'id')
{
$sFriendlyName = Dict::S('UI:CSVImport:idField');
}
else
{
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCodeEx);
$sFriendlyName = $oAttDef->GetLabel();
}
}
return $sFriendlyName;
}
} }

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Persistent class (internal) cmdbChange * Persistent class (internal) cmdbChange
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Persistent classes (internal) : cmdbChangeOp and derived * Persistent classes (internal) : cmdbChangeOp and derived
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
@@ -65,19 +64,6 @@ class CMDBChangeOp extends DBObject
{ {
return ''; return '';
} }
/**
* Safety net: in case the change is not given, let's guarantee that it will
* be set to the current ongoing change (or create a new one)
*/
protected function OnInsert()
{
if ($this->Get('change') <= 0)
{
$this->Set('change', CMDBObject::GetCurrentChange());
}
parent::OnInsert();
}
} }
@@ -138,11 +124,6 @@ class CMDBChangeOpDelete extends CMDBChangeOp
); );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes(); MetaModel::Init_InheritAttributes();
// Final class of the object (objclass must be set to the root class for efficiency purposes)
MetaModel::Init_AddAttribute(new AttributeString("fclass", array("allowed_values"=>null, "sql"=>"fclass", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
// Last friendly name of the object
MetaModel::Init_AddAttribute(new AttributeString("fname", array("allowed_values"=>null, "sql"=>"fname", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
} }
/** /**
* Describe (as a text string) the modifications corresponding to this change * Describe (as a text string) the modifications corresponding to this change
@@ -219,6 +200,9 @@ class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
*/ */
public function GetDescription() public function GetDescription()
{ {
// Temporary, until we change the options of GetDescription() -needs a more global revision
$bIsHtml = true;
$sResult = ''; $sResult = '';
$oTargetObjectClass = $this->Get('objclass'); $oTargetObjectClass = $this->Get('objclass');
$oTargetObjectKey = $this->Get('objkey'); $oTargetObjectKey = $this->Get('objkey');
@@ -234,7 +218,76 @@ class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
$sAttName = $oAttDef->GetLabel(); $sAttName = $oAttDef->GetLabel();
$sNewValue = $this->Get('newvalue'); $sNewValue = $this->Get('newvalue');
$sOldValue = $this->Get('oldvalue'); $sOldValue = $this->Get('oldvalue');
$sResult = $oAttDef->GetAsHTMLForHistory($sOldValue, $sNewValue); if ($oAttDef instanceof AttributeEnum)
{
// translate the enum values
$sOldValue = $oAttDef->GetAsHTML($sOldValue);
$sNewValue = $oAttDef->GetAsHTML($sNewValue);
if (strlen($sOldValue) == 0)
{
$sResult = Dict::Format('Change:AttName_SetTo', $sAttName, $sNewValue);
}
else
{
$sResult = Dict::Format('Change:AttName_SetTo_NewValue_PreviousValue_OldValue', $sAttName, $sNewValue, $sOldValue);
}
}
elseif ( (($oAttDef->GetType() == 'String') || ($oAttDef->GetType() == 'Text')) &&
(strlen($sNewValue) > strlen($sOldValue)) )
{
// Check if some text was not appended to the field
if (substr($sNewValue,0, strlen($sOldValue)) == $sOldValue) // Text added at the end
{
$sDelta = substr($sNewValue, strlen($sOldValue));
$sResult = Dict::Format('Change:Text_AppendedTo_AttName', $sDelta, $sAttName);
}
else if (substr($sNewValue, -strlen($sOldValue)) == $sOldValue) // Text added at the beginning
{
$sDelta = substr($sNewValue, 0, strlen($sNewValue) - strlen($sOldValue));
$sResult = Dict::Format('Change:Text_AppendedTo_AttName', $sDelta, $sAttName);
}
else
{
if (strlen($sOldValue) == 0)
{
$sResult = Dict::Format('Change:AttName_SetTo', $sAttName, $sNewValue);
}
else
{
$sResult = Dict::Format('Change:AttName_SetTo_NewValue_PreviousValue_OldValue', $sAttName, $sNewValue, $sOldValue);
}
}
}
elseif($bIsHtml && $oAttDef->IsExternalKey())
{
$sTargetClass = $oAttDef->GetTargetClass();
$sFrom = MetaModel::GetHyperLink($sTargetClass, $sOldValue);
$sTo = MetaModel::GetHyperLink($sTargetClass, $sNewValue);
$sResult = "$sAttName set to $sTo (previous: $sFrom)";
if (strlen($sFrom) == 0)
{
$sResult = Dict::Format('Change:AttName_SetTo', $sAttName, $sTo);
}
else
{
$sResult = Dict::Format('Change:AttName_SetTo_NewValue_PreviousValue_OldValue', $sAttName, $sTo, $sFrom);
}
}
elseif ($oAttDef instanceOf AttributeBlob)
{
$sResult = "#@# Issue... found an attribute for which other type of tracking should be made";
}
else
{
if (strlen($sOldValue) == 0)
{
$sResult = Dict::Format('Change:AttName_SetTo', $sAttName, $sNewValue);
}
else
{
$sResult = Dict::Format('Change:AttName_SetTo_NewValue_PreviousValue_OldValue', $sAttName, $sNewValue, $sOldValue);
}
}
} }
return $sResult; return $sResult;
} }
@@ -286,16 +339,8 @@ class CMDBChangeOpSetAttributeBlob extends CMDBChangeOpSetAttribute
$oMonoObjectSet = new DBObjectSet($oTargetSearch); $oMonoObjectSet = new DBObjectSet($oTargetSearch);
if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES) if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES)
{ {
if (MetaModel::IsValidAttCode($this->Get('objclass'), $this->Get('attcode'))) $oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode'));
{ $sAttName = $oAttDef->GetLabel();
$oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode'));
$sAttName = $oAttDef->GetLabel();
}
else
{
// The attribute was renamed or removed from the object ?
$sAttName = $this->Get('attcode');
}
$oPrevDoc = $this->Get('prevdata'); $oPrevDoc = $this->Get('prevdata');
$sDocView = $oPrevDoc->GetAsHtml(); $sDocView = $oPrevDoc->GetAsHtml();
$sDocView .= "<br/>".Dict::Format('UI:OpenDocumentInNewWindow_',$oPrevDoc->GetDisplayLink(get_class($this), $this->GetKey(), 'prevdata')).", \n"; $sDocView .= "<br/>".Dict::Format('UI:OpenDocumentInNewWindow_',$oPrevDoc->GetDisplayLink(get_class($this), $this->GetKey(), 'prevdata')).", \n";
@@ -350,16 +395,8 @@ class CMDBChangeOpSetAttributeOneWayPassword extends CMDBChangeOpSetAttribute
$oMonoObjectSet = new DBObjectSet($oTargetSearch); $oMonoObjectSet = new DBObjectSet($oTargetSearch);
if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES) if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES)
{ {
if (MetaModel::IsValidAttCode($this->Get('objclass'), $this->Get('attcode'))) $oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode'));
{ $sAttName = $oAttDef->GetLabel();
$oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode'));
$sAttName = $oAttDef->GetLabel();
}
else
{
// The attribute was renamed or removed from the object ?
$sAttName = $this->Get('attcode');
}
$sResult = Dict::Format('Change:AttName_Changed', $sAttName); $sResult = Dict::Format('Change:AttName_Changed', $sAttName);
} }
return $sResult; return $sResult;
@@ -410,16 +447,8 @@ class CMDBChangeOpSetAttributeEncrypted extends CMDBChangeOpSetAttribute
$oMonoObjectSet = new DBObjectSet($oTargetSearch); $oMonoObjectSet = new DBObjectSet($oTargetSearch);
if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES) if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES)
{ {
if (MetaModel::IsValidAttCode($this->Get('objclass'), $this->Get('attcode'))) $oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode'));
{ $sAttName = $oAttDef->GetLabel();
$oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode'));
$sAttName = $oAttDef->GetLabel();
}
else
{
// The attribute was renamed or removed from the object ?
$sAttName = $this->Get('attcode');
}
$sPrevString = $this->Get('prevstring'); $sPrevString = $this->Get('prevstring');
$sResult = Dict::Format('Change:AttName_Changed_PreviousValue_OldValue', $sAttName, $sPrevString); $sResult = Dict::Format('Change:AttName_Changed_PreviousValue_OldValue', $sAttName, $sPrevString);
} }
@@ -473,81 +502,8 @@ class CMDBChangeOpSetAttributeText extends CMDBChangeOpSetAttribute
$oMonoObjectSet = new DBObjectSet($oTargetSearch); $oMonoObjectSet = new DBObjectSet($oTargetSearch);
if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES) if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES)
{ {
if (MetaModel::IsValidAttCode($this->Get('objclass'), $this->Get('attcode'))) $oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode'));
{ $sAttName = $oAttDef->GetLabel();
$oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode'));
$sAttName = $oAttDef->GetLabel();
}
else
{
// The attribute was renamed or removed from the object ?
$sAttName = $this->Get('attcode');
}
$sTextView = '<div>'.$this->GetAsHtml('prevdata').'</div>';
//$sDocView = $oPrevDoc->GetDisplayInline(get_class($this), $this->GetKey(), 'prevdata');
$sResult = Dict::Format('Change:AttName_Changed_PreviousValue_OldValue', $sAttName, $sTextView);
}
return $sResult;
}
}
/**
* Record the modification of a multiline string (text)
*
* @package iTopORM
*/
class CMDBChangeOpSetAttributeLongText extends CMDBChangeOpSetAttribute
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb",
"key_type" => "",
"name_attcode" => "change",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_changeop_setatt_longtext",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeLongText("prevdata", array("allowed_values"=>null, "sql"=>"prevdata", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'userinfo', 'attcode')); // Attributes to be displayed for a list
}
/**
* Describe (as a text string) the modifications corresponding to this change
*/
public function GetDescription()
{
// Temporary, until we change the options of GetDescription() -needs a more global revision
$bIsHtml = true;
$sResult = '';
$oTargetObjectClass = $this->Get('objclass');
$oTargetObjectKey = $this->Get('objkey');
$oTargetSearch = new DBObjectSearch($oTargetObjectClass);
$oTargetSearch->AddCondition('id', $oTargetObjectKey, '=');
$oMonoObjectSet = new DBObjectSet($oTargetSearch);
if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES)
{
if (MetaModel::IsValidAttCode($this->Get('objclass'), $this->Get('attcode')))
{
$oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode'));
$sAttName = $oAttDef->GetLabel();
}
else
{
// The attribute was renamed or removed from the object ?
$sAttName = $this->Get('attcode');
}
$sTextView = '<div>'.$this->GetAsHtml('prevdata').'</div>'; $sTextView = '<div>'.$this->GetAsHtml('prevdata').'</div>';
//$sDocView = $oPrevDoc->GetDisplayInline(get_class($this), $this->GetKey(), 'prevdata'); //$sDocView = $oPrevDoc->GetDisplayInline(get_class($this), $this->GetKey(), 'prevdata');
@@ -606,16 +562,8 @@ class CMDBChangeOpSetAttributeCaseLog extends CMDBChangeOpSetAttribute
$oMonoObjectSet = new DBObjectSet($oTargetSearch); $oMonoObjectSet = new DBObjectSet($oTargetSearch);
if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES) if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES)
{ {
if (MetaModel::IsValidAttCode($this->Get('objclass'), $this->Get('attcode'))) $oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode'));
{ $sAttName = $oAttDef->GetLabel();
$oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode'));
$sAttName = $oAttDef->GetLabel();
}
else
{
// The attribute was renamed or removed from the object ?
$sAttName = $this->Get('attcode');
}
$sResult = Dict::Format('Change:AttName_EntryAdded', $sAttName); $sResult = Dict::Format('Change:AttName_EntryAdded', $sAttName);
} }
return $sResult; return $sResult;
@@ -659,185 +607,4 @@ class CMDBChangeOpPlugin extends CMDBChangeOp
return $this->Get('description'); return $this->Get('description');
} }
} }
/**
* Record added/removed objects from within a link set
*
* @package iTopORM
*/
abstract class CMDBChangeOpSetAttributeLinks extends CMDBChangeOpSetAttribute
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb",
"key_type" => "",
"name_attcode" => "change",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_changeop_links",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
// Note: item class/id points to the link class itself in case of a direct link set (e.g. Server::interface_list => Interface)
// item class/id points to the remote class in case of a indirect link set (e.g. Server::contract_list => Contract)
MetaModel::Init_AddAttribute(new AttributeString("item_class", array("allowed_values"=>null, "sql"=>"item_class", "default_value"=>'', "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("item_id", array("allowed_values"=>null, "sql"=>"item_id", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
}
}
/**
* Record added/removed objects from within a link set
*
* @package iTopORM
*/
class CMDBChangeOpSetAttributeLinksAddRemove extends CMDBChangeOpSetAttributeLinks
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb",
"key_type" => "",
"name_attcode" => "change",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_changeop_links_addremove",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeEnum("type", array("allowed_values"=>new ValueSetEnum('added,removed'), "sql"=>"type", "default_value"=>"added", "is_null_allowed"=>false, "depends_on"=>array())));
}
/**
* Describe (as a text string) the modifications corresponding to this change
*/
public function GetDescription()
{
$sResult = '';
$oTargetObjectClass = $this->Get('objclass');
$oTargetObjectKey = $this->Get('objkey');
$oTargetSearch = new DBObjectSearch($oTargetObjectClass);
$oTargetSearch->AddCondition('id', $oTargetObjectKey, '=');
$oMonoObjectSet = new DBObjectSet($oTargetSearch);
if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES)
{
if (!MetaModel::IsValidAttCode($this->Get('objclass'), $this->Get('attcode'))) return ''; // Protects against renamed attributes...
$oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode'));
$sAttName = $oAttDef->GetLabel();
$sItemDesc = MetaModel::GetHyperLink($this->Get('item_class'), $this->Get('item_id'));
$sResult = $sAttName.' - ';
switch ($this->Get('type'))
{
case 'added':
$sResult .= Dict::Format('Change:LinkSet:Added', $sItemDesc);
break;
case 'removed':
$sResult .= Dict::Format('Change:LinkSet:Removed', $sItemDesc);
break;
}
}
return $sResult;
}
}
/**
* Record attribute changes from within a link set
* A single record redirects to the modifications made within the same change
*
* @package iTopORM
*/
class CMDBChangeOpSetAttributeLinksTune extends CMDBChangeOpSetAttributeLinks
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb",
"key_type" => "",
"name_attcode" => "change",
"state_attcode" => "",
"reconc_keys" => array(),
"db_table" => "priv_changeop_links_tune",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeInteger("link_id", array("allowed_values"=>null, "sql"=>"link_id", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
}
/**
* Describe (as a text string) the modifications corresponding to this change
*/
public function GetDescription()
{
$sResult = '';
$oTargetObjectClass = $this->Get('objclass');
$oTargetObjectKey = $this->Get('objkey');
$oTargetSearch = new DBObjectSearch($oTargetObjectClass);
$oTargetSearch->AddCondition('id', $oTargetObjectKey, '=');
$oMonoObjectSet = new DBObjectSet($oTargetSearch);
if (UserRights::IsActionAllowedOnAttribute($this->Get('objclass'), $this->Get('attcode'), UR_ACTION_READ, $oMonoObjectSet) == UR_ALLOWED_YES)
{
if (!MetaModel::IsValidAttCode($this->Get('objclass'), $this->Get('attcode'))) return ''; // Protects against renamed attributes...
$oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode'));
$sAttName = $oAttDef->GetLabel();
$sLinkClass = $oAttDef->GetLinkedClass();
$aLinkClasses = MetaModel::EnumChildClasses($sLinkClass, ENUM_CHILD_CLASSES_ALL);
// Search for changes on the corresponding link
//
$oSearch = new DBObjectSearch('CMDBChangeOpSetAttribute');
$oSearch->AddCondition('change', $this->Get('change'), '=');
$oSearch->AddCondition('objkey', $this->Get('link_id'), '=');
if (count($aLinkClasses) == 1)
{
// Faster than the whole building of the expression below for just one value ??
$oSearch->AddCondition('objclass', $sLinkClass, '=');
}
else
{
$oField = new FieldExpression('objclass', $oSearch->GetClassAlias());
$sListExpr = '('.implode(', ', CMDBSource::Quote($aLinkClasses)).')';
$sOQLCondition = $oField->Render()." IN $sListExpr";
$oNewCondition = Expression::FromOQL($sOQLCondition);
$oSearch->AddConditionExpression($oNewCondition);
}
$oSet = new DBObjectSet($oSearch);
$aChanges = array();
while ($oChangeOp = $oSet->Fetch())
{
$aChanges[] = $oChangeOp->GetDescription();
}
if (count($aChanges) == 0)
{
return '';
}
$sItemDesc = MetaModel::GetHyperLink($this->Get('item_class'), $this->Get('item_id'));
$sResult = $sAttName.' - ';
$sResult .= Dict::Format('Change:LinkSet:Modified', $sItemDesc);
$sResult .= ' : '.implode(', ', $aChanges);
}
return $sResult;
}
}
?> ?>

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Class cmdbObject * Class cmdbObject
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
@@ -92,124 +91,47 @@ abstract class CMDBObject extends DBObject
protected $m_datUpdated; protected $m_datUpdated;
// Note: this value is static, but that could be changed because it is sometimes a real issue (see update of interfaces / connected_to // Note: this value is static, but that could be changed because it is sometimes a real issue (see update of interfaces / connected_to
protected static $m_oCurrChange = null; protected static $m_oCurrChange = null;
protected static $m_sInfo = null; // null => the information is built in a standard way
/**
* Specify another change (this is mainly for backward compatibility)
*/
public static function SetCurrentChange(CMDBChange $oChange)
{
self::$m_oCurrChange = $oChange;
}
// private function RecordObjCreation(CMDBChange $oChange)
// Todo: simplify the APIs and do not pass the current change as an argument anymore
// SetTrackInfo to be invoked in very few cases (UI.php, CSV import, Data synchro)
// SetCurrentChange is an alternative to SetTrackInfo (csv ?)
// GetCurrentChange to be called ONCE (!) by CMDBChangeOp::OnInsert ($this->Set('change', ..GetCurrentChange())
// GetCurrentChange to create a default change if not already done in the current context
//
/**
* Get a change record (create it if not existing)
*/
public static function GetCurrentChange($bAutoCreate = true)
{ {
if ($bAutoCreate && is_null(self::$m_oCurrChange))
{
self::CreateChange();
}
return self::$m_oCurrChange;
}
/**
* Override the additional information (defaulting to user name)
* A call to this verb should replace every occurence of
* $oMyChange = MetaModel::NewObject("CMDBChange");
* $oMyChange->Set("date", time());
* $oMyChange->Set("userinfo", 'this is done by ... for ...');
* $iChangeId = $oMyChange->DBInsert();
*/
public static function SetTrackInfo($sInfo)
{
self::$m_sInfo = $sInfo;
}
/**
* Get the additional information (defaulting to user name)
*/
protected static function GetTrackInfo()
{
if (is_null(self::$m_sInfo))
{
return CMDBChange::GetCurrentUserName();
}
else
{
return self::$m_sInfo;
}
}
/**
* Create a standard change record (done here 99% of the time, and nearly once per page)
*/
protected static function CreateChange()
{
self::$m_oCurrChange = MetaModel::NewObject("CMDBChange");
self::$m_oCurrChange->Set("date", time());
self::$m_oCurrChange->Set("userinfo", self::GetTrackInfo());
self::$m_oCurrChange->DBInsert();
}
protected function RecordObjCreation()
{
parent::RecordObjCreation();
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpCreate"); $oMyChangeOp = MetaModel::NewObject("CMDBChangeOpCreate");
$oMyChangeOp->Set("change", $oChange->GetKey());
$oMyChangeOp->Set("objclass", get_class($this)); $oMyChangeOp->Set("objclass", get_class($this));
$oMyChangeOp->Set("objkey", $this->GetKey()); $oMyChangeOp->Set("objkey", $this->GetKey());
$iId = $oMyChangeOp->DBInsertNoReload(); $iId = $oMyChangeOp->DBInsertNoReload();
} }
private function RecordObjDeletion(CMDBChange $oChange, $objkey)
protected function RecordObjDeletion($objkey)
{ {
parent::RecordObjDeletion($objkey);
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpDelete"); $oMyChangeOp = MetaModel::NewObject("CMDBChangeOpDelete");
$oMyChangeOp->Set("objclass", MetaModel::GetRootClass(get_class($this))); $oMyChangeOp->Set("change", $oChange->GetKey());
$oMyChangeOp->Set("objclass", get_class($this));
$oMyChangeOp->Set("objkey", $objkey); $oMyChangeOp->Set("objkey", $objkey);
$oMyChangeOp->Set("fclass", get_class($this));
$oMyChangeOp->Set("fname", $this->GetRawName());
$iId = $oMyChangeOp->DBInsertNoReload(); $iId = $oMyChangeOp->DBInsertNoReload();
} }
private function RecordAttChanges(CMDBChange $oChange, array $aValues, array $aOrigValues)
protected function RecordAttChanges(array $aValues, array $aOrigValues)
{ {
parent::RecordAttChanges($aValues, $aOrigValues);
// $aValues is an array of $sAttCode => $value // $aValues is an array of $sAttCode => $value
// //
foreach ($aValues as $sAttCode=> $value) foreach ($aValues as $sAttCode=> $value)
{ {
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode); $oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
if ($oAttDef->IsExternalField()) continue; // #@# temporary
if ($oAttDef->IsLinkSet()) continue; // #@# temporary if ($oAttDef->IsLinkSet()) continue; // #@# temporary
if (array_key_exists($sAttCode, $aOrigValues))
{
$original = $aOrigValues[$sAttCode];
}
else
{
$original = null;
}
if ($oAttDef instanceOf AttributeOneWayPassword) if ($oAttDef instanceOf AttributeOneWayPassword)
{ {
// One Way encrypted passwords' history is stored -one way- encrypted // One Way encrypted passwords' history is stored -one way- encrypted
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeOneWayPassword"); $oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeOneWayPassword");
$oMyChangeOp->Set("change", $oChange->GetKey());
$oMyChangeOp->Set("objclass", get_class($this)); $oMyChangeOp->Set("objclass", get_class($this));
$oMyChangeOp->Set("objkey", $this->GetKey()); $oMyChangeOp->Set("objkey", $this->GetKey());
$oMyChangeOp->Set("attcode", $sAttCode); $oMyChangeOp->Set("attcode", $sAttCode);
if (is_null($original)) if (array_key_exists($sAttCode, $aOrigValues))
{
$original = $aOrigValues[$sAttCode];
}
else
{ {
$original = ''; $original = '';
} }
@@ -220,11 +142,16 @@ abstract class CMDBObject extends DBObject
{ {
// Encrypted string history is stored encrypted // Encrypted string history is stored encrypted
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeEncrypted"); $oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeEncrypted");
$oMyChangeOp->Set("change", $oChange->GetKey());
$oMyChangeOp->Set("objclass", get_class($this)); $oMyChangeOp->Set("objclass", get_class($this));
$oMyChangeOp->Set("objkey", $this->GetKey()); $oMyChangeOp->Set("objkey", $this->GetKey());
$oMyChangeOp->Set("attcode", $sAttCode); $oMyChangeOp->Set("attcode", $sAttCode);
if (is_null($original)) if (array_key_exists($sAttCode, $aOrigValues))
{
$original = $aOrigValues[$sAttCode];
}
else
{ {
$original = ''; $original = '';
} }
@@ -235,46 +162,26 @@ abstract class CMDBObject extends DBObject
{ {
// Data blobs // Data blobs
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeBlob"); $oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeBlob");
$oMyChangeOp->Set("change", $oChange->GetKey());
$oMyChangeOp->Set("objclass", get_class($this)); $oMyChangeOp->Set("objclass", get_class($this));
$oMyChangeOp->Set("objkey", $this->GetKey()); $oMyChangeOp->Set("objkey", $this->GetKey());
$oMyChangeOp->Set("attcode", $sAttCode); $oMyChangeOp->Set("attcode", $sAttCode);
if (is_null($original)) if (array_key_exists($sAttCode, $aOrigValues))
{
$original = $aOrigValues[$sAttCode];
}
else
{ {
$original = new ormDocument(); $original = new ormDocument();
} }
$oMyChangeOp->Set("prevdata", $original); $oMyChangeOp->Set("prevdata", $original);
$iId = $oMyChangeOp->DBInsertNoReload(); $iId = $oMyChangeOp->DBInsertNoReload();
} }
elseif ($oAttDef instanceOf AttributeStopWatch)
{
// Stop watches - record changes for sub items only (they are visible, the rest is not visible)
//
if (is_null($original))
{
$original = new OrmStopWatch();
}
foreach ($oAttDef->ListSubItems() as $sSubItemAttCode => $oSubItemAttDef)
{
$item_value = $oSubItemAttDef->GetValue($value);
$item_original = $oSubItemAttDef->GetValue($original);
if ($item_value != $item_original)
{
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeScalar");
$oMyChangeOp->Set("objclass", get_class($this));
$oMyChangeOp->Set("objkey", $this->GetKey());
$oMyChangeOp->Set("attcode", $sSubItemAttCode);
$oMyChangeOp->Set("oldvalue", $item_original);
$oMyChangeOp->Set("newvalue", $item_value);
$iId = $oMyChangeOp->DBInsertNoReload();
}
}
}
elseif ($oAttDef instanceOf AttributeCaseLog) elseif ($oAttDef instanceOf AttributeCaseLog)
{ {
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeCaseLog"); $oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeCaseLog");
$oMyChangeOp->Set("change", $oChange->GetKey());
$oMyChangeOp->Set("objclass", get_class($this)); $oMyChangeOp->Set("objclass", get_class($this));
$oMyChangeOp->Set("objkey", $this->GetKey()); $oMyChangeOp->Set("objkey", $this->GetKey());
$oMyChangeOp->Set("attcode", $sAttCode); $oMyChangeOp->Set("attcode", $sAttCode);
@@ -282,67 +189,49 @@ abstract class CMDBObject extends DBObject
$oMyChangeOp->Set("lastentry", $value->GetLatestEntryIndex()); $oMyChangeOp->Set("lastentry", $value->GetLatestEntryIndex());
$iId = $oMyChangeOp->DBInsertNoReload(); $iId = $oMyChangeOp->DBInsertNoReload();
} }
elseif ($oAttDef instanceOf AttributeLongText)
{
// Data blobs
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeLongText");
$oMyChangeOp->Set("objclass", get_class($this));
$oMyChangeOp->Set("objkey", $this->GetKey());
$oMyChangeOp->Set("attcode", $sAttCode);
if (!is_null($original) && ($original instanceof ormCaseLog))
{
$original = $original->GetText();
}
$oMyChangeOp->Set("prevdata", $original);
$iId = $oMyChangeOp->DBInsertNoReload();
}
elseif ($oAttDef instanceOf AttributeText) elseif ($oAttDef instanceOf AttributeText)
{ {
// Data blobs // Data blobs
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeText"); $oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeText");
$oMyChangeOp->Set("change", $oChange->GetKey());
$oMyChangeOp->Set("objclass", get_class($this)); $oMyChangeOp->Set("objclass", get_class($this));
$oMyChangeOp->Set("objkey", $this->GetKey()); $oMyChangeOp->Set("objkey", $this->GetKey());
$oMyChangeOp->Set("attcode", $sAttCode); $oMyChangeOp->Set("attcode", $sAttCode);
if (!is_null($original) && ($original instanceof ormCaseLog)) if (array_key_exists($sAttCode, $aOrigValues))
{ {
$original = $original->GetText(); $original = $aOrigValues[$sAttCode];
if ($original instanceof ormCaseLog)
{
$original = $original->GetText();
}
}
else
{
$original = null;
} }
$oMyChangeOp->Set("prevdata", $original); $oMyChangeOp->Set("prevdata", $original);
$iId = $oMyChangeOp->DBInsertNoReload(); $iId = $oMyChangeOp->DBInsertNoReload();
} }
elseif ($oAttDef instanceOf AttributeBoolean)
{
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeScalar");
$oMyChangeOp->Set("objclass", get_class($this));
$oMyChangeOp->Set("objkey", $this->GetKey());
$oMyChangeOp->Set("attcode", $sAttCode);
$oMyChangeOp->Set("oldvalue", $original ? 1 : 0);
$oMyChangeOp->Set("newvalue", $value ? 1 : 0);
$iId = $oMyChangeOp->DBInsertNoReload();
}
elseif ($oAttDef instanceOf AttributeHierarchicalKey)
{
// Hierarchical keys
//
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeScalar");
$oMyChangeOp->Set("objclass", get_class($this));
$oMyChangeOp->Set("objkey", $this->GetKey());
$oMyChangeOp->Set("attcode", $sAttCode);
$oMyChangeOp->Set("oldvalue", $original);
$oMyChangeOp->Set("newvalue", $value[$sAttCode]);
$iId = $oMyChangeOp->DBInsertNoReload();
}
else else
{ {
// Scalars // Scalars
// //
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeScalar"); $oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeScalar");
$oMyChangeOp->Set("change", $oChange->GetKey());
$oMyChangeOp->Set("objclass", get_class($this)); $oMyChangeOp->Set("objclass", get_class($this));
$oMyChangeOp->Set("objkey", $this->GetKey()); $oMyChangeOp->Set("objkey", $this->GetKey());
$oMyChangeOp->Set("attcode", $sAttCode); $oMyChangeOp->Set("attcode", $sAttCode);
$oMyChangeOp->Set("oldvalue", $original);
if (array_key_exists($sAttCode, $aOrigValues))
{
$sOriginalValue = $aOrigValues[$sAttCode];
}
else
{
$sOriginalValue = 'undefined';
}
$oMyChangeOp->Set("oldvalue", $sOriginalValue);
$oMyChangeOp->Set("newvalue", $value); $oMyChangeOp->Set("newvalue", $value);
$iId = $oMyChangeOp->DBInsertNoReload(); $iId = $oMyChangeOp->DBInsertNoReload();
} }
@@ -380,24 +269,32 @@ abstract class CMDBObject extends DBObject
public function DBInsert() public function DBInsert()
{ {
if(!is_object(self::$m_oCurrChange))
{
throw new CoreException("DBInsert() could not be used here, please use DBInsertTracked() instead");
}
return $this->DBInsertTracked_Internal(); return $this->DBInsertTracked_Internal();
} }
public function DBInsertTracked(CMDBChange $oChange, $bSkipStrongSecurity = null) public function DBInsertTracked(CMDBChange $oChange, $bSkipStrongSecurity = null)
{ {
self::SetCurrentChange($oChange);
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_MODIFY); $this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_MODIFY);
$oPreviousChange = self::$m_oCurrChange;
self::$m_oCurrChange = $oChange;
$ret = $this->DBInsertTracked_Internal(); $ret = $this->DBInsertTracked_Internal();
self::$m_oCurrChange = $oPreviousChange;
return $ret; return $ret;
} }
public function DBInsertTrackedNoReload(CMDBChange $oChange, $bSkipStrongSecurity = null) public function DBInsertTrackedNoReload(CMDBChange $oChange, $bSkipStrongSecurity = null)
{ {
self::SetCurrentChange($oChange);
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_MODIFY); $this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_MODIFY);
$oPreviousChange = self::$m_oCurrChange;
self::$m_oCurrChange = $oChange;
$ret = $this->DBInsertTracked_Internal(true); $ret = $this->DBInsertTracked_Internal(true);
self::$m_oCurrChange = $oPreviousChange;
return $ret; return $ret;
} }
@@ -411,18 +308,25 @@ abstract class CMDBObject extends DBObject
{ {
$ret = parent::DBInsert(); $ret = parent::DBInsert();
} }
$this->RecordObjCreation(self::$m_oCurrChange);
return $ret; return $ret;
} }
public function DBClone($newKey = null) public function DBClone($newKey = null)
{ {
if(!self::$m_oCurrChange)
{
throw new CoreException("DBClone() could not be used here, please use DBCloneTracked() instead");
}
return $this->DBCloneTracked_Internal(); return $this->DBCloneTracked_Internal();
} }
public function DBCloneTracked(CMDBChange $oChange, $newKey = null) public function DBCloneTracked(CMDBChange $oChange, $newKey = null)
{ {
self::SetCurrentChange($oChange); $oPreviousChange = self::$m_oCurrChange;
self::$m_oCurrChange = $oChange;
$this->DBCloneTracked_Internal($newKey); $this->DBCloneTracked_Internal($newKey);
self::$m_oCurrChange = $oPreviousChange;
} }
protected function DBCloneTracked_Internal($newKey = null) protected function DBCloneTracked_Internal($newKey = null)
@@ -430,57 +334,128 @@ abstract class CMDBObject extends DBObject
$newKey = parent::DBClone($newKey); $newKey = parent::DBClone($newKey);
$oClone = MetaModel::GetObject(get_class($this), $newKey); $oClone = MetaModel::GetObject(get_class($this), $newKey);
$oClone->RecordObjCreation(self::$m_oCurrChange);
return $newKey; return $newKey;
} }
public function DBUpdate() public function DBUpdate()
{ {
// Copy the changes list before the update (the list should be reset afterwards) if(!self::$m_oCurrChange)
$aChanges = $this->ListChanges();
if (count($aChanges) == 0)
{ {
return; throw new CoreException("DBUpdate() could not be used here, please use DBUpdateTracked() instead");
} }
return $this->DBUpdateTracked_internal();
$ret = parent::DBUpdate();
return $ret;
} }
public function DBUpdateTracked(CMDBChange $oChange, $bSkipStrongSecurity = null) public function DBUpdateTracked(CMDBChange $oChange, $bSkipStrongSecurity = null)
{ {
self::SetCurrentChange($oChange);
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_MODIFY); $this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_MODIFY);
$this->DBUpdate();
$oPreviousChange = self::$m_oCurrChange;
self::$m_oCurrChange = $oChange;
$this->DBUpdateTracked_Internal();
self::$m_oCurrChange = $oPreviousChange;
}
protected function DBUpdateTracked_Internal()
{
// Copy the changes list before the update (the list should be reset afterwards)
$aChanges = $this->ListChanges();
if (count($aChanges) == 0)
{
//throw new CoreWarning("Attempting to update an unchanged object");
return;
}
// Save the original values (will be reset to the new values when the object get written to the DB)
$aOriginalValues = $this->m_aOrigValues;
$ret = parent::DBUpdate();
$this->RecordAttChanges(self::$m_oCurrChange, $aChanges, $aOriginalValues);
return $ret;
} }
public function DBDelete(&$oDeletionPlan = null) public function DBDelete(&$oDeletionPlan = null)
{ {
if(!self::$m_oCurrChange)
{
throw new CoreException("DBDelete() could not be used here, please use DBDeleteTracked() instead");
}
return $this->DBDeleteTracked_Internal($oDeletionPlan); return $this->DBDeleteTracked_Internal($oDeletionPlan);
} }
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null) public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null)
{ {
self::SetCurrentChange($oChange);
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_DELETE); $this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_DELETE);
$oPreviousChange = self::$m_oCurrChange;
self::$m_oCurrChange = $oChange;
$this->DBDeleteTracked_Internal($oDeletionPlan); $this->DBDeleteTracked_Internal($oDeletionPlan);
self::$m_oCurrChange = $oPreviousChange;
} }
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null) protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
{ {
$prevkey = $this->GetKey(); $prevkey = $this->GetKey();
$ret = parent::DBDelete($oDeletionPlan); $ret = parent::DBDelete($oDeletionPlan);
$this->RecordObjDeletion(self::$m_oCurrChange, $prevkey);
return $ret;
}
public static function BulkDelete(DBObjectSearch $oFilter)
{
if(!self::$m_oCurrChange)
{
throw new CoreException("BulkDelete() could not be used here, please use BulkDeleteTracked() instead");
}
return $this->BulkDeleteTracked_Internal($oFilter);
}
public static function BulkDeleteTracked(CMDBChange $oChange, DBObjectSearch $oFilter)
{
$oPreviousChange = self::$m_oCurrChange;
self::$m_oCurrChange = $oChange;
$this->BulkDeleteTracked_Internal($oFilter);
self::$m_oCurrChange = $oPreviousChange;
}
protected static function BulkDeleteTracked_Internal(DBObjectSearch $oFilter)
{
throw new CoreWarning("Change tracking not tested for bulk operations");
// Get the list of objects to delete (and record data before deleting the DB records)
$oObjSet = new CMDBObjectSet($oFilter);
$aObjAndKeys = array(); // array of id=>object
while ($oItem = $oObjSet->Fetch())
{
$aObjAndKeys[$oItem->GetKey()] = $oItem;
}
$oObjSet->FreeResult();
// Delete in one single efficient query
$ret = parent::BulkDelete($oFilter);
// Record... in many queries !!!
foreach($aObjAndKeys as $prevkey=>$oItem)
{
$oItem->RecordObjDeletion(self::$m_oCurrChange, $prevkey);
}
return $ret; return $ret;
} }
public static function BulkUpdate(DBObjectSearch $oFilter, array $aValues) public static function BulkUpdate(DBObjectSearch $oFilter, array $aValues)
{ {
if(!self::$m_oCurrChange)
{
throw new CoreException("BulkUpdate() could not be used here, please use BulkUpdateTracked() instead");
}
return $this->BulkUpdateTracked_Internal($oFilter, $aValues); return $this->BulkUpdateTracked_Internal($oFilter, $aValues);
} }
public static function BulkUpdateTracked(CMDBChange $oChange, DBObjectSearch $oFilter, array $aValues) public static function BulkUpdateTracked(CMDBChange $oChange, DBObjectSearch $oFilter, array $aValues)
{ {
self::SetCurrentChange($oChange); $oPreviousChange = self::$m_oCurrChange;
self::$m_oCurrChange = $oChange;
$this->BulkUpdateTracked_Internal($oFilter, $aValues); $this->BulkUpdateTracked_Internal($oFilter, $aValues);
self::$m_oCurrChange = $oPreviousChange;
} }
protected static function BulkUpdateTracked_Internal(DBObjectSearch $oFilter, array $aValues) protected static function BulkUpdateTracked_Internal(DBObjectSearch $oFilter, array $aValues)
@@ -507,7 +482,7 @@ abstract class CMDBObject extends DBObject
while ($oItem = $oObjSet->Fetch()) while ($oItem = $oObjSet->Fetch())
{ {
$aChangedValues = $oItem->ListChangedValues($aValues); $aChangedValues = $oItem->ListChangedValues($aValues);
$oItem->RecordAttChanges($aChangedValues, $aOriginalValues[$oItem->GetKey()]); $oItem->RecordAttChanges(self::$m_oCurrChange, $aChangedValues, $aOriginalValues[$oItem->GetKey()]);
} }
return $ret; return $ret;
} }

View File

@@ -1,38 +1,36 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* DB Server abstraction * DB Server abstraction
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once('MyHelpers.class.inc.php'); require_once('MyHelpers.class.inc.php');
require_once(APPROOT.'core/kpi.class.inc.php');
class MySQLException extends CoreException class MySQLException extends CoreException
{ {
public function __construct($sIssue, $aContext) public function __construct($sIssue, $aContext)
{ {
$aContext['mysql_error'] = CMDBSource::GetError(); $aContext['mysql_error'] = mysql_error();
$aContext['mysql_errno'] = CMDBSource::GetErrNo();; $aContext['mysql_errno'] = mysql_errno();
parent::__construct($sIssue, $aContext); parent::__construct($sIssue, $aContext);
} }
} }
@@ -58,13 +56,13 @@ class CMDBSource
self::$m_sDBUser = $sUser; self::$m_sDBUser = $sUser;
self::$m_sDBPwd = $sPwd; self::$m_sDBPwd = $sPwd;
self::$m_sDBName = $sSource; self::$m_sDBName = $sSource;
if (!self::$m_resDBLink = @mysqli_connect($sServer, $sUser, $sPwd)) if (!self::$m_resDBLink = mysql_connect($sServer, $sUser, $sPwd))
{ {
throw new MySQLException('Could not connect to the DB server', array('host'=>$sServer, 'user'=>$sUser)); throw new MySQLException('Could not connect to the DB server', array('host'=>$sServer, 'user'=>$sUser));
} }
if (!empty($sSource)) if (!empty($sSource))
{ {
if (!((bool)mysqli_query(self::$m_resDBLink, "USE `$sSource`"))) if (!mysql_select_db($sSource, self::$m_resDBLink))
{ {
throw new MySQLException('Could not select DB', array('host'=>$sServer, 'user'=>$sUser, 'db_name'=>$sSource)); throw new MySQLException('Could not select DB', array('host'=>$sServer, 'user'=>$sUser, 'db_name'=>$sSource));
} }
@@ -120,7 +118,7 @@ class CMDBSource
{ {
// In case we don't have rights to enumerate the databases // In case we don't have rights to enumerate the databases
// Let's try to connect directly // Let's try to connect directly
return @((bool)mysqli_query(self::$m_resDBLink, "USE `$sSource`")); return @mysql_select_db($sSource, self::$m_resDBLink);
} }
} }
@@ -133,7 +131,7 @@ class CMDBSource
public static function SelectDB($sSource) public static function SelectDB($sSource)
{ {
if (!((bool)mysqli_query(self::$m_resDBLink, "USE `$sSource`"))) if (!mysql_select_db($sSource, self::$m_resDBLink))
{ {
throw new MySQLException('Could not select DB', array('db_name'=>$sSource)); throw new MySQLException('Could not select DB', array('db_name'=>$sSource));
} }
@@ -173,30 +171,6 @@ class CMDBSource
return $res; return $res;
} }
public static function GetErrNo()
{
if (self::$m_resDBLink)
{
return mysqli_errno(self::$m_resDBLink);
}
else
{
return mysqli_connect_errno();
}
}
public static function GetError()
{
if (self::$m_resDBLink)
{
return mysqli_error(self::$m_resDBLink);
}
else
{
return mysqli_connect_error();
}
}
public static function DBHost() {return self::$m_sDBHost;} public static function DBHost() {return self::$m_sDBHost;}
public static function DBUser() {return self::$m_sDBUser;} public static function DBUser() {return self::$m_sDBUser;}
public static function DBPwd() {return self::$m_sDBPwd;} public static function DBPwd() {return self::$m_sDBPwd;}
@@ -234,7 +208,7 @@ class CMDBSource
// Quote if not a number or a numeric string // Quote if not a number or a numeric string
if ($bAlways || is_string($value)) if ($bAlways || is_string($value))
{ {
$value = $cQuoteStyle . mysqli_real_escape_string(self::$m_resDBLink, $value) . $cQuoteStyle; $value = $cQuoteStyle . mysql_real_escape_string($value, self::$m_resDBLink) . $cQuoteStyle;
} }
return $value; return $value;
} }
@@ -248,7 +222,7 @@ class CMDBSource
// $sSQLQuery .= MyHelpers::MakeSQLComment($aTraceInf); // $sSQLQuery .= MyHelpers::MakeSQLComment($aTraceInf);
$oKPI = new ExecutionKPI(); $oKPI = new ExecutionKPI();
$result = mysqli_query(self::$m_resDBLink, $sSQLQuery); $result = mysql_query($sSQLQuery, self::$m_resDBLink);
if (!$result) if (!$result)
{ {
throw new MySQLException('Failed to issue SQL query', array('query' => $sSQLQuery)); throw new MySQLException('Failed to issue SQL query', array('query' => $sSQLQuery));
@@ -262,21 +236,15 @@ class CMDBSource
{ {
$sSQL = "SHOW TABLE STATUS LIKE '$sTable'"; $sSQL = "SHOW TABLE STATUS LIKE '$sTable'";
$result = self::Query($sSQL); $result = self::Query($sSQL);
$aRow = mysqli_fetch_assoc($result); $aRow = mysql_fetch_assoc($result);
$iNextInsertId = $aRow['Auto_increment']; $iNextInsertId = $aRow['Auto_increment'];
return $iNextInsertId; return $iNextInsertId;
} }
public static function GetInsertId() public static function GetInsertId()
{ {
$iRes = mysqli_insert_id(self::$m_resDBLink); return mysql_insert_id(self::$m_resDBLink);
if (is_null($iRes))
{
return 0;
}
return $iRes;
} }
public static function InsertInto($sSQLQuery) public static function InsertInto($sSQLQuery)
{ {
if (self::Query($sSQLQuery)) if (self::Query($sSQLQuery))
@@ -293,37 +261,37 @@ class CMDBSource
public static function QueryToScalar($sSql) public static function QueryToScalar($sSql)
{ {
$result = mysqli_query(self::$m_resDBLink, $sSql); $result = mysql_query($sSql, self::$m_resDBLink);
if (!$result) if (!$result)
{ {
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql)); throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
} }
if ($aRow = mysqli_fetch_array($result, MYSQLI_BOTH)) if ($aRow = mysql_fetch_array($result, MYSQL_BOTH))
{ {
$res = $aRow[0]; $res = $aRow[0];
} }
else else
{ {
mysqli_free_result($result); mysql_free_result($result);
throw new MySQLException('Found no result for query', array('query' => $sSql)); throw new MySQLException('Found no result for query', array('query' => $sSql));
} }
mysqli_free_result($result); mysql_free_result($result);
return $res; return $res;
} }
public static function QueryToArray($sSql) public static function QueryToArray($sSql)
{ {
$aData = array(); $aData = array();
$result = mysqli_query(self::$m_resDBLink, $sSql); $result = mysql_query($sSql, self::$m_resDBLink);
if (!$result) if (!$result)
{ {
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql)); throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
} }
while ($aRow = mysqli_fetch_array($result, MYSQLI_BOTH)) while ($aRow = mysql_fetch_array($result, MYSQL_BOTH))
{ {
$aData[] = $aRow; $aData[] = $aRow;
} }
mysqli_free_result($result); mysql_free_result($result);
return $aData; return $aData;
} }
@@ -341,7 +309,7 @@ class CMDBSource
public static function ExplainQuery($sSql) public static function ExplainQuery($sSql)
{ {
$aData = array(); $aData = array();
$result = mysqli_query(self::$m_resDBLink, "EXPLAIN $sSql"); $result = mysql_query("EXPLAIN $sSql", self::$m_resDBLink);
if (!$result) if (!$result)
{ {
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql)); throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
@@ -350,67 +318,62 @@ class CMDBSource
$aNames = self::GetColumns($result); $aNames = self::GetColumns($result);
$aData[] = $aNames; $aData[] = $aNames;
while ($aRow = mysqli_fetch_array($result, MYSQLI_ASSOC)) while ($aRow = mysql_fetch_array($result, MYSQL_ASSOC))
{ {
$aData[] = $aRow; $aData[] = $aRow;
} }
mysqli_free_result($result); mysql_free_result($result);
return $aData; return $aData;
} }
public static function TestQuery($sSql) public static function TestQuery($sSql)
{ {
$result = mysqli_query(self::$m_resDBLink, "EXPLAIN $sSql"); $result = mysql_query("EXPLAIN $sSql", self::$m_resDBLink);
if (!$result) if (!$result)
{ {
return self::GetError(); return mysql_error();
} }
mysqli_free_result($result); mysql_free_result($result);
return ''; return '';
} }
public static function NbRows($result) public static function NbRows($result)
{ {
return mysqli_num_rows($result); return mysql_num_rows($result);
}
public static function AffectedRows()
{
return mysqli_affected_rows(self::$m_resDBLink);
} }
public static function FetchArray($result) public static function FetchArray($result)
{ {
return mysqli_fetch_array($result, MYSQLI_ASSOC); return mysql_fetch_array($result, MYSQL_ASSOC);
} }
public static function GetColumns($result) public static function GetColumns($result)
{ {
$aNames = array(); $aNames = array();
for ($i = 0; $i < (($___mysqli_tmp = mysqli_num_fields($result)) ? $___mysqli_tmp : 0) ; $i++) for ($i = 0; $i < mysql_num_fields($result) ; $i++)
{ {
$meta = mysqli_fetch_field_direct($result, $i); $meta = mysql_fetch_field($result, $i);
if (!$meta) if (!$meta)
{ {
throw new MySQLException('mysql_fetch_field: No information available', array('query'=>$sSql, 'i'=>$i)); throw new MySQLException('mysql_fetch_field: No information available', array('query'=>$sSql, 'i'=>$i));
} }
else else
{ {
$aNames[] = $meta->name; $aNames[] = $meta->name;
} }
} }
return $aNames; return $aNames;
} }
public static function Seek($result, $iRow) public static function Seek($result, $iRow)
{ {
return mysqli_data_seek($result, $iRow); return mysql_data_seek($result, $iRow);
} }
public static function FreeResult($result) public static function FreeResult($result)
{ {
return ((mysqli_free_result($result) || (is_object($result) && (get_class($result) == "mysqli_result"))) ? true : false); return mysql_free_result($result);
} }
public static function IsTable($sTable) public static function IsTable($sTable)
@@ -548,18 +511,18 @@ class CMDBSource
public static function DumpTable($sTable) public static function DumpTable($sTable)
{ {
$sSql = "SELECT * FROM `$sTable`"; $sSql = "SELECT * FROM `$sTable`";
$result = mysqli_query(self::$m_resDBLink, $sSql); $result = mysql_query($sSql, self::$m_resDBLink);
if (!$result) if (!$result)
{ {
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql)); throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
} }
$aRows = array(); $aRows = array();
while ($aRow = mysqli_fetch_array($result, MYSQLI_ASSOC)) while ($aRow = mysql_fetch_array($result, MYSQL_ASSOC))
{ {
$aRows[] = $aRow; $aRows[] = $aRow;
} }
mysqli_free_result($result); mysql_free_result($result);
return $aRows; return $aRows;
} }
@@ -597,12 +560,12 @@ class CMDBSource
} }
$aRes = array(); $aRes = array();
while ($aRow = mysqli_fetch_array($result, MYSQLI_NUM)) while ($aRow = mysql_fetch_array($result, MYSQL_NUM))
{ {
// so far, only one column... // so far, only one column...
$aRes[] = implode('/', $aRow); $aRes[] = implode('/', $aRow);
} }
mysqli_free_result($result); mysql_free_result($result);
// so far, only one line... // so far, only one line...
return implode(', ', $aRes); return implode(', ', $aRes);
} }
@@ -622,14 +585,14 @@ class CMDBSource
throw new CoreException("Current user not allowed to check the status", array('mysql_error' => $e->getMessage())); throw new CoreException("Current user not allowed to check the status", array('mysql_error' => $e->getMessage()));
} }
if (mysqli_num_rows($result) == 0) if (mysql_num_rows($result) == 0)
{ {
return false; return false;
} }
// Returns one single row anytime // Returns one single row anytime
$aRow = mysqli_fetch_array($result, MYSQLI_ASSOC); $aRow = mysql_fetch_array($result, MYSQL_ASSOC);
mysqli_free_result($result); mysql_free_result($result);
if (!isset($aRow['Slave_IO_Running'])) if (!isset($aRow['Slave_IO_Running']))
{ {

View File

@@ -1,122 +0,0 @@
<?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/>
/**
* Any extension to compute things like a stop watch deadline or working hours
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Metric computing for stop watches
*/
interface iMetricComputer
{
public static function GetDescription();
public function ComputeMetric($oObject);
}
/**
* Working time computing for stop watches
*/
interface iWorkingTimeComputer
{
public static function GetDescription();
/**
* Get the date/time corresponding to a given delay in the future from the present
* considering only the valid (open) hours for a specified object
* @param $oObject DBObject The object for which to compute the deadline
* @param $iDuration integer The duration (in seconds) in the future
* @param $oStartDate DateTime The starting point for the computation
* @return DateTime The date/time for the deadline
*/
public function GetDeadline($oObject, $iDuration, DateTime $oStartDate);
/**
* Get duration (considering only open hours) elapsed bewteen two given DateTimes
* @param $oObject DBObject The object for which to compute the duration
* @param $oStartDate DateTime The starting point for the computation (default = now)
* @param $oEndDate DateTime The ending point for the computation (default = now)
* @return integer The duration (number of seconds) of open hours elapsed between the two dates
*/
public function GetOpenDuration($oObject, DateTime $oStartDate, DateTime $oEndDate);
}
/**
* Default implementation oof deadline computing: NO deadline
*/
class DefaultMetricComputer implements iMetricComputer
{
public static function GetDescription()
{
return "Null";
}
public function ComputeMetric($oObject)
{
return null;
}
}
/**
* Default implementation of working time computing
*/
class DefaultWorkingTimeComputer implements iWorkingTimeComputer
{
public static function GetDescription()
{
return "24x7, no holidays";
}
/**
* Get the date/time corresponding to a given delay in the future from the present
* considering only the valid (open) hours for a specified object
* @param $oObject DBObject The object for which to compute the deadline
* @param $iDuration integer The duration (in seconds) in the future
* @param $oStartDate DateTime The starting point for the computation
* @return DateTime The date/time for the deadline
*/
public function GetDeadline($oObject, $iDuration, DateTime $oStartDate)
{
//echo "GetDeadline - default: ".$oStartDate->format('Y-m-d H:i:s')." + $iDuration<br/>\n";
// Default implementation: 24x7, no holidays: to compute the deadline, just add
// the specified duration to the given date/time
$oResult = clone $oStartDate;
$oResult->modify('+'.$iDuration.' seconds');
return $oResult;
}
/**
* Get duration (considering only open hours) elapsed bewteen two given DateTimes
* @param $oObject DBObject The object for which to compute the duration
* @param $oStartDate DateTime The starting point for the computation (default = now)
* @param $oEndDate DateTime The ending point for the computation (default = now)
* @return integer The duration (number of seconds) of open hours elapsed between the two dates
*/
public function GetOpenDuration($oObject, DateTime $oStartDate, DateTime $oEndDate)
{
//echo "GetOpenDuration - default: ".$oStartDate->format('Y-m-d H:i:s')." to ".$oEndDate->format('Y-m-d H:i:s')."<br/>\n";
return abs($oEndDate->format('U') - $oStartDate->format('U'));
}
}
?>

View File

@@ -1,21 +1,18 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
define('ITOP_APPLICATION', 'iTop'); define('ITOP_APPLICATION', 'iTop');
define('ITOP_VERSION', '$ITOP_VERSION$'); define('ITOP_VERSION', '$ITOP_VERSION$');
@@ -30,8 +27,10 @@ define('ACCESS_READONLY', 0);
/** /**
* Configuration read/write * Configuration read/write
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once('coreexception.class.inc.php'); require_once('coreexception.class.inc.php');
@@ -49,7 +48,7 @@ define ('DEFAULT_LOG_ISSUE', true);
define ('DEFAULT_LOG_WEB_SERVICE', true); define ('DEFAULT_LOG_WEB_SERVICE', true);
define ('DEFAULT_LOG_KPI_DURATION', false); define ('DEFAULT_LOG_KPI_DURATION', false);
define ('DEFAULT_LOG_KPI_MEMORY', false); define ('DEFAULT_LOG_KPI_MEMORY', false);
define ('DEFAULT_LOG_QUERIES', false); define ('DEFAULT_DEBUG_QUERIES', false);
define ('DEFAULT_QUERY_CACHE_ENABLED', true); define ('DEFAULT_QUERY_CACHE_ENABLED', true);
@@ -85,14 +84,6 @@ class Config
// New way to store the settings ! // New way to store the settings !
// //
protected $m_aSettings = array( protected $m_aSettings = array(
'app_env_label' => array(
'type' => 'string',
'description' => 'Label displayed to describe the current application environnment, defaults to the environment name (e.g. "production")',
'default' => '',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'app_root_url' => array( 'app_root_url' => array(
'type' => 'string', 'type' => 'string',
'description' => '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)', 'description' => '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)',
@@ -101,14 +92,6 @@ class Config
'source_of_value' => '', 'source_of_value' => '',
'show_in_conf_sample' => true, 'show_in_conf_sample' => true,
), ),
'app_icon_url' => array(
'type' => 'string',
'description' => 'Hyperlink to redirect the user when clicking on the application icon (in the main window, or login/logoff pages)',
'default' => 'http://www.combodo.com/itop',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'skip_check_to_write' => array( 'skip_check_to_write' => array(
'type' => 'bool', 'type' => 'bool',
'description' => 'Disable data format and integrity checks to boost up data load (insert or update)', 'description' => 'Disable data format and integrity checks to boost up data load (insert or update)',
@@ -133,22 +116,6 @@ class Config
'source_of_value' => '', 'source_of_value' => '',
'show_in_conf_sample' => false, 'show_in_conf_sample' => false,
), ),
'query_optimization_enabled' => array(
'type' => 'bool',
'description' => 'The queries are optimized based on the assumption that the DB integrity has been preserved. By disabling the optimization one can ensure that the fetched data is clean... but this can be really slower or not usable at all (some queries will exceed the allowed number of joins in MySQL: 61!)',
'default' => true,
'value' => true,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'query_indentation_enabled' => array(
'type' => 'bool',
'description' => 'For developpers: format the SQL queries for human analysis',
'default' => false,
'value' => false,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'graphviz_path' => array( 'graphviz_path' => array(
'type' => 'string', 'type' => 'string',
'description' => 'Path to the Graphviz "dot" executable for graphing objects lifecycle', 'description' => 'Path to the Graphviz "dot" executable for graphing objects lifecycle',
@@ -157,14 +124,6 @@ class Config
'source_of_value' => '', 'source_of_value' => '',
'show_in_conf_sample' => false, 'show_in_conf_sample' => false,
), ),
'php_path' => array(
'type' => 'string',
'description' => 'Path to the php executable in CLI mode',
'default' => 'php',
'value' => 'php',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'session_name' => array( 'session_name' => array(
'type' => 'string', 'type' => 'string',
'description' => 'The name of the cookie used to store the PHP session id', 'description' => 'The name of the cookie used to store the PHP session id',
@@ -230,14 +189,6 @@ class Config
'source_of_value' => '', 'source_of_value' => '',
'show_in_conf_sample' => false, 'show_in_conf_sample' => false,
), ),
'csv_import_history_display' => array(
'type' => 'bool',
'description' => 'Display the history tab in the import wizard',
'default' => false,
'value' => false,
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'access_mode' => array( 'access_mode' => array(
'type' => 'integer', 'type' => 'integer',
'description' => 'Combination of flags (ACCESS_USER_WRITE | ACCESS_ADMIN_WRITE, or ACCESS_FULL)', 'description' => 'Combination of flags (ACCESS_USER_WRITE | ACCESS_ADMIN_WRITE, or ACCESS_FULL)',
@@ -334,54 +285,6 @@ class Config
'source_of_value' => '', 'source_of_value' => '',
'show_in_conf_sample' => true, 'show_in_conf_sample' => true,
), ),
'email_transport' => array(
'type' => 'string',
'description' => 'Mean to send emails: PHPMail (uses the function mail()) or SMTP (implements the client protocole)',
'default' => "PHPMail",
'value' => "PHPMail",
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'email_transport_smtp.host' => array(
'type' => 'string',
'description' => 'host name or IP address (optional)',
'default' => "localhost",
'value' => "localhost",
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'email_transport_smtp.port' => array(
'type' => 'integer',
'description' => 'port number (optional)',
'default' => 25,
'value' => 25,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'email_transport_smtp.encryption' => array(
'type' => 'string',
'description' => 'tls or ssl (optional)',
'default' => "",
'value' => "",
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'email_transport_smtp.username' => array(
'type' => 'string',
'description' => 'Authentication user (optional)',
'default' => "",
'value' => "",
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'email_transport_smtp.password' => array(
'type' => 'string',
'description' => 'Authentication password (optional)',
'default' => "",
'value' => "",
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'apc_cache.enabled' => array( 'apc_cache.enabled' => array(
'type' => 'bool', 'type' => 'bool',
'description' => 'If set, the APC cache is allowed (the PHP extension must also be active)', 'description' => 'If set, the APC cache is allowed (the PHP extension must also be active)',
@@ -424,7 +327,7 @@ class Config
'default' => '2.0', 'default' => '2.0',
'value' => '', 'value' => '',
'source_of_value' => '', 'source_of_value' => '',
'show_in_conf_sample' => false, 'show_in_conf_sample' => true,
), ),
'cas_host' => array( 'cas_host' => array(
'type' => 'string', 'type' => 'string',
@@ -433,7 +336,7 @@ class Config
'default' => '', 'default' => '',
'value' => '', 'value' => '',
'source_of_value' => '', 'source_of_value' => '',
'show_in_conf_sample' => false, 'show_in_conf_sample' => true,
), ),
'cas_port' => array( 'cas_port' => array(
'type' => 'integer', 'type' => 'integer',
@@ -442,7 +345,7 @@ class Config
'default' => 443, 'default' => 443,
'value' => 443, 'value' => 443,
'source_of_value' => '', 'source_of_value' => '',
'show_in_conf_sample' => false, 'show_in_conf_sample' => true,
), ),
'cas_context' => array( 'cas_context' => array(
'type' => 'string', 'type' => 'string',
@@ -451,7 +354,7 @@ class Config
'default' => '', 'default' => '',
'value' => '', 'value' => '',
'source_of_value' => '', 'source_of_value' => '',
'show_in_conf_sample' => false, 'show_in_conf_sample' => true,
), ),
'cas_server_ca_cert_path' => array( 'cas_server_ca_cert_path' => array(
'type' => 'string', 'type' => 'string',
@@ -460,7 +363,7 @@ class Config
'default' => '', 'default' => '',
'value' => '', 'value' => '',
'source_of_value' => '', 'source_of_value' => '',
'show_in_conf_sample' => false, 'show_in_conf_sample' => true,
), ),
'cas_logout_redirect_service' => array( 'cas_logout_redirect_service' => array(
'type' => 'string', 'type' => 'string',
@@ -469,7 +372,7 @@ class Config
'default' => '', 'default' => '',
'value' => '', 'value' => '',
'source_of_value' => '', 'source_of_value' => '',
'show_in_conf_sample' => false, 'show_in_conf_sample' => true,
), ),
'cas_memberof' => array( 'cas_memberof' => array(
'type' => 'string', 'type' => 'string',
@@ -478,7 +381,7 @@ class Config
'default' => '', 'default' => '',
'value' => '', 'value' => '',
'source_of_value' => '', 'source_of_value' => '',
'show_in_conf_sample' => false, 'show_in_conf_sample' => true,
), ),
'cas_user_synchro' => array( 'cas_user_synchro' => array(
'type' => 'bool', 'type' => 'bool',
@@ -487,16 +390,7 @@ class Config
'default' => 0, 'default' => 0,
'value' => 0, 'value' => 0,
'source_of_value' => '', 'source_of_value' => '',
'show_in_conf_sample' => false, 'show_in_conf_sample' => true,
),
'cas_update_profiles' => array(
'type' => 'bool',
'description' => 'Whether or not to update the profiles of an existing user from the CAS information',
// examples... not used (nor 'description')
'default' => 0,
'value' => 0,
'source_of_value' => '',
'show_in_conf_sample' => false,
), ),
'cas_profile_pattern' => array( 'cas_profile_pattern' => array(
'type' => 'string', 'type' => 'string',
@@ -505,16 +399,7 @@ class Config
'default' => '/^cn=([^,]+),/', 'default' => '/^cn=([^,]+),/',
'value' => '/^cn=([^,]+),/', 'value' => '/^cn=([^,]+),/',
'source_of_value' => '', 'source_of_value' => '',
'show_in_conf_sample' => false, 'show_in_conf_sample' => true,
),
'cas_default_profiles' => array(
'type' => 'string',
'description' => 'A semi-colon separated list of iTop Profiles to use when creating a new user if no profile is retrieved from CAS',
// examples... not used (nor 'description')
'default' => 'Portal user',
'value' => 'Portal user',
'source_of_value' => '',
'show_in_conf_sample' => false,
), ),
'cas_debug' => array( 'cas_debug' => array(
'type' => 'bool', 'type' => 'bool',
@@ -523,7 +408,7 @@ class Config
'default' => false, 'default' => false,
'value' => false, 'value' => false,
'source_of_value' => '', 'source_of_value' => '',
'show_in_conf_sample' => false, 'show_in_conf_sample' => true,
), ),
'deadline_format' => array( 'deadline_format' => array(
'type' => 'string', 'type' => 'string',
@@ -552,60 +437,6 @@ class Config
'source_of_value' => '', 'source_of_value' => '',
'show_in_conf_sample' => true, 'show_in_conf_sample' => true,
), ),
'complex_actions_limit' => array(
'type' => 'integer',
'description' => 'Display the "actions" menu items that require long computation only if the list of objects is contains less objects than this number (0 means no limit)',
// examples... not used
'default' => 50,
'value' => 50,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'synchro_prevent_delete_all' => array(
'type' => 'bool',
'description' => 'Stop the synchro if all the replicas of a data source become obsolete at the same time.',
// examples... not used
'default' => true,
'value' => true,
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'source_dir' => array(
'type' => 'string',
'description' => 'Source directory for the datamodel files. (which gets compiled to env-production).',
// examples... not used
'default' => '',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'csv_file_default_charset' => array(
'type' => 'string',
'description' => 'Character set used by default for downloading and uploading data as a CSV file. Warning: it is case sensitive (uppercase is preferable).',
// examples... not used
'default' => 'ISO-8859-1',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => true,
),
'debug_report_spurious_chars' => array(
'type' => 'bool',
'description' => 'Report, in the error log, the characters found in the output buffer, echoed by mistake in the loaded modules, and potentially corrupting the output',
// examples... not used
'default' => false,
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'impact_analysis_first_tab' => array(
'type' => 'string',
'description' => 'Which tab to display first in the impact analysis view: list or graphics. Graphics are nicer but slower to display when there are many objects',
// examples... not used
'default' => 'graphics',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
); );
public function IsProperty($sPropCode) public function IsProperty($sPropCode)
@@ -664,9 +495,9 @@ class Config
protected $m_bLogNotification; protected $m_bLogNotification;
protected $m_bLogIssue; protected $m_bLogIssue;
protected $m_bLogWebService; protected $m_bLogWebService;
protected $m_bLogKPIDuration; // private setting protected $m_bLogKpiDuration; // private setting
protected $m_bLogKPIMemory; // private setting protected $m_bLogKpiMemory; // private setting
protected $m_bLogQueries; // private setting protected $m_bDebugQueries; // private setting
protected $m_bQueryCacheEnabled; // private setting protected $m_bQueryCacheEnabled; // private setting
/** /**
@@ -722,22 +553,15 @@ class Config
*/ */
protected $m_aCharsets; protected $m_aCharsets;
public function __construct($sConfigFile = null, $bLoadConfig = true) public function __construct($sConfigFile, $bLoadConfig = true)
{ {
$this->m_sFile = $sConfigFile; $this->m_sFile = $sConfigFile;
if (is_null($sConfigFile))
{
$bLoadConfig = false;
}
$this->m_aAppModules = array( $this->m_aAppModules = array(
// Some default modules, always present can be move to an official iTop Module later if needed // Some default modules, always present can be move to an official iTop Module later if needed
'application/transaction.class.inc.php', 'application/transaction.class.inc.php',
'application/menunode.class.inc.php', 'application/menunode.class.inc.php',
'application/user.preferences.class.inc.php', 'application/user.preferences.class.inc.php',
'application/user.dashboard.class.inc.php',
'application/audit.rule.class.inc.php', 'application/audit.rule.class.inc.php',
'application/query.class.inc.php',
// Romain - That's dirty, because those classes are in fact part of the core // Romain - That's dirty, because those classes are in fact part of the core
// but I needed those classes to be derived from cmdbAbstractObject // but I needed those classes to be derived from cmdbAbstractObject
// (to be managed via the GUI) and this class in not really known from // (to be managed via the GUI) and this class in not really known from
@@ -795,12 +619,10 @@ class Config
$this->Verify(); $this->Verify();
} }
// Application root url: set a default value, then normalize it // Application root url: set a default value, then normalize it
/* $sAppRootUrl = trim($this->Get('app_root_url'));
* Does not work in CLI/unattended mode
$sAppRootUrl = trim($this->Get('app_root_url'));
if (strlen($sAppRootUrl) == 0) if (strlen($sAppRootUrl) == 0)
{ {
$sAppRootUrl = utils::GetDefaultUrlAppRoot(); $sAppRootUrl = utils::GetDefaultUrlAppRoot();
} }
if (substr($sAppRootUrl, -1, 1) != '/') if (substr($sAppRootUrl, -1, 1) != '/')
@@ -808,7 +630,6 @@ class Config
$sAppRootUrl .= '/'; $sAppRootUrl .= '/';
} }
$this->Set('app_root_url', $sAppRootUrl); $this->Set('app_root_url', $sAppRootUrl);
*/
} }
protected function CheckFile($sPurpose, $sFileName) protected function CheckFile($sPurpose, $sFileName)
@@ -913,7 +734,7 @@ class Config
$this->m_bLogWebService = isset($MySettings['log_web_service']) ? (bool) trim($MySettings['log_web_service']) : DEFAULT_LOG_WEB_SERVICE; $this->m_bLogWebService = isset($MySettings['log_web_service']) ? (bool) trim($MySettings['log_web_service']) : DEFAULT_LOG_WEB_SERVICE;
$this->m_bLogKPIDuration = isset($MySettings['log_kpi_duration']) ? (bool) trim($MySettings['log_kpi_duration']) : DEFAULT_LOG_KPI_DURATION; $this->m_bLogKPIDuration = isset($MySettings['log_kpi_duration']) ? (bool) trim($MySettings['log_kpi_duration']) : DEFAULT_LOG_KPI_DURATION;
$this->m_bLogKPIMemory = isset($MySettings['log_kpi_memory']) ? (bool) trim($MySettings['log_kpi_memory']) : DEFAULT_LOG_KPI_MEMORY; $this->m_bLogKPIMemory = isset($MySettings['log_kpi_memory']) ? (bool) trim($MySettings['log_kpi_memory']) : DEFAULT_LOG_KPI_MEMORY;
$this->m_bLogQueries = isset($MySettings['log_queries']) ? (bool) trim($MySettings['log_queries']) : DEFAULT_LOG_QUERIES; $this->m_bDebugQueries = isset($MySettings['debug_queries']) ? (bool) trim($MySettings['debug_queries']) : DEFAULT_DEBUG_QUERIES;
$this->m_bQueryCacheEnabled = isset($MySettings['query_cache_enabled']) ? (bool) trim($MySettings['query_cache_enabled']) : DEFAULT_QUERY_CACHE_ENABLED; $this->m_bQueryCacheEnabled = isset($MySettings['query_cache_enabled']) ? (bool) trim($MySettings['query_cache_enabled']) : DEFAULT_QUERY_CACHE_ENABLED;
$this->m_iMinDisplayLimit = isset($MySettings['min_display_limit']) ? trim($MySettings['min_display_limit']) : DEFAULT_MIN_DISPLAY_LIMIT; $this->m_iMinDisplayLimit = isset($MySettings['min_display_limit']) ? trim($MySettings['min_display_limit']) : DEFAULT_MIN_DISPLAY_LIMIT;
@@ -1061,9 +882,9 @@ class Config
return $this->m_bLogKPIMemory; return $this->m_bLogKPIMemory;
} }
public function GetLogQueries() public function GetDebugQueries()
{ {
return $this->m_bLogQueries; return $this->m_bDebugQueries;
} }
public function GetQueryCacheEnabled() public function GetQueryCacheEnabled()
@@ -1230,17 +1051,13 @@ class Config
{ {
$this->m_aCharsets[$sIconvCode] = $sDisplayName; $this->m_aCharsets[$sIconvCode] = $sDisplayName;
} }
public function FileIsWritable()
{
return is_writable($this->m_sFile);
}
public function GetLoadedFile() public function GetLoadedFile()
{ {
if (is_null($this->m_sFile)) return $this->m_sFile;
{
return '';
}
else
{
return $this->m_sFile;
}
} }
/** /**
@@ -1323,115 +1140,64 @@ class Config
fwrite($hFile, "<?php\n"); fwrite($hFile, "<?php\n");
fwrite($hFile, "\n/**\n"); fwrite($hFile, "\n/**\n");
fwrite($hFile, " *\n"); fwrite($hFile, " *\n");
fwrite($hFile, " * Configuration file, generated by the ".ITOP_APPLICATION." configuration wizard\n"); fwrite($hFile, " * phpMyORM configuration file, generated by the iTop configuration wizard\n");
fwrite($hFile, " *\n"); fwrite($hFile, " *\n");
fwrite($hFile, " * The file is used in MetaModel::LoadConfig() which does all the necessary initialization job\n"); fwrite($hFile, " * The file is used in MetaModel::LoadConfig() which does all the necessary initialization job\n");
fwrite($hFile, " *\n"); fwrite($hFile, " *\n");
fwrite($hFile, " */\n"); fwrite($hFile, " */\n");
fwrite($hFile, "\n");
$aConfigSettings = $this->m_aSettings;
// Old fashioned boolean settings
$aBoolValues = array(
'log_global' => $this->m_bLogGlobal,
'log_notification' => $this->m_bLogNotification,
'log_issue' => $this->m_bLogIssue,
'log_web_service' => $this->m_bLogWebService,
'secure_connection_required' => $this->m_bSecureConnectionRequired,
);
foreach($aBoolValues as $sKey => $bValue)
{
$aConfigSettings[$sKey] = array(
'show_in_conf_sample' => true,
'type' => 'bool',
'value' => $bValue,
);
}
// Old fashioned integer settings
$aIntValues = array(
'fast_reload_interval' => $this->m_iFastReloadInterval,
'max_display_limit' => $this->m_iMaxDisplayLimit,
'min_display_limit' => $this->m_iMinDisplayLimit,
'standard_reload_interval' => $this->m_iStandardReloadInterval,
);
foreach($aIntValues as $sKey => $iValue)
{
$aConfigSettings[$sKey] = array(
'show_in_conf_sample' => true,
'type' => 'integer',
'value' => $iValue,
);
}
// Old fashioned remaining values
$aOtherValues = array(
'db_host' => $this->m_sDBHost,
'db_user' => $this->m_sDBUser,
'db_pwd' => $this->m_sDBPwd,
'db_name' => $this->m_sDBName,
'db_subname' => $this->m_sDBSubname,
'db_character_set' => $this->m_sDBCharacterSet,
'db_collation' => $this->m_sDBCollation,
'default_language' => $this->m_sDefaultLanguage,
'allowed_login_types' => $this->m_sAllowedLoginTypes,
'encryption_key' => $this->m_sEncryptionKey,
'csv_import_charsets' => $this->m_aCharsets,
);
foreach($aOtherValues as $sKey => $value)
{
$aConfigSettings[$sKey] = array(
'show_in_conf_sample' => true,
'type' => is_string($value) ? 'string' : 'mixed',
'value' => $value,
);
}
ksort($aConfigSettings);
fwrite($hFile, "\$MySettings = array(\n"); fwrite($hFile, "\$MySettings = array(\n");
foreach($aConfigSettings as $sPropCode => $aSettingInfo) foreach($this->m_aSettings as $sPropCode => $aSettingInfo)
{ {
// Write all values that are either always visible or present in the cloned config file if ($aSettingInfo['show_in_conf_sample'])
if ($aSettingInfo['show_in_conf_sample'] || (!empty($aSettingInfo['source_of_value']) && ($aSettingInfo['source_of_value'] != 'unknown')) )
{ {
$sType = $aSettingInfo['type']; $sType = $this->m_aSettings[$sPropCode]['type'];
switch($sType) switch($sType)
{ {
case 'bool': case 'bool':
$sSeenAs = $aSettingInfo['value'] ? 'true' : 'false'; $sSeenAs = $aSettingInfo['value'] ? '1' : '0';
break; break;
default: default:
$sSeenAs = self::PrettyVarExport($aSettingInfo['value'], "\t"); $sSeenAs = "'".addslashes($aSettingInfo['value'])."'";
}
fwrite($hFile, "\n");
if (isset($aSettingInfo['description']))
{
fwrite($hFile, "\t// $sPropCode: {$aSettingInfo['description']}\n");
}
if (isset($aSettingInfo['default']))
{
$default = $aSettingInfo['default'];
if ($aSettingInfo['type'] == 'bool')
{
$default = $default ? 'true' : 'false';
}
fwrite($hFile, "\t//\tdefault: ".self::PrettyVarExport($aSettingInfo['default'],"\t//\t\t", true)."\n");
} }
fwrite($hFile, "\t'$sPropCode' => $sSeenAs,\n"); fwrite($hFile, "\t'$sPropCode' => $sSeenAs,\n");
} }
} }
fwrite($hFile, ");\n"); fwrite($hFile, "\t'db_host' => '{$this->m_sDBHost}',\n");
fwrite($hFile, "\t'db_user' => '{$this->m_sDBUser}',\n");
fwrite($hFile, "\t'db_pwd' => '".addslashes($this->m_sDBPwd)."',\n");
fwrite($hFile, "\t'db_name' => '{$this->m_sDBName}',\n");
fwrite($hFile, "\t'db_subname' => '{$this->m_sDBSubname}',\n");
fwrite($hFile, "\t'db_character_set' => '{$this->m_sDBCharacterSet}',\n");
fwrite($hFile, "\t'db_collation' => '{$this->m_sDBCollation}',\n");
fwrite($hFile, "\n");
fwrite($hFile, "\t'log_global' => {$this->m_bLogGlobal},\n");
fwrite($hFile, "\t'log_notification' => {$this->m_bLogNotification},\n");
fwrite($hFile, "\t'log_issue' => {$this->m_bLogIssue},\n");
fwrite($hFile, "\t'log_web_service' => {$this->m_bLogWebService},\n");
fwrite($hFile, "\t'min_display_limit' => {$this->m_iMinDisplayLimit},\n");
fwrite($hFile, "\t'max_display_limit' => {$this->m_iMaxDisplayLimit},\n");
fwrite($hFile, "\t'standard_reload_interval' => {$this->m_iStandardReloadInterval},\n");
fwrite($hFile, "\t'fast_reload_interval' => {$this->m_iFastReloadInterval},\n");
fwrite($hFile, "\t'secure_connection_required' => ".($this->m_bSecureConnectionRequired ? 'true' : 'false').",\n");
fwrite($hFile, "\t'default_language' => '{$this->m_sDefaultLanguage}',\n");
fwrite($hFile, "\t'allowed_login_types' => '{$this->m_sAllowedLoginTypes}',\n");
fwrite($hFile, "\t'encryption_key' => '{$this->m_sEncryptionKey}',\n");
$sExport = var_export($this->m_aCharsets, true);
fwrite($hFile, "\t'csv_import_charsets' => $sExport,\n");
fwrite($hFile, ");\n");
fwrite($hFile, "\n"); fwrite($hFile, "\n");
fwrite($hFile, "/**\n *\n * Modules specific settings\n *\n */\n");
fwrite($hFile, "\$MyModuleSettings = array(\n"); fwrite($hFile, "\$MyModuleSettings = array(\n");
foreach ($this->m_aModuleSettings as $sModule => $aProperties) foreach ($this->m_aModuleSettings as $sModule => $aProperties)
{ {
fwrite($hFile, "\t'$sModule' => array (\n"); fwrite($hFile, "\t'$sModule' => array (\n");
foreach ($aProperties as $sProperty => $value) foreach ($aProperties as $sProperty => $value)
{ {
$sNiceExport = self::PrettyVarExport($value, "\t\t"); $sExport = var_export($value, true);
fwrite($hFile, "\t\t'$sProperty' => $sNiceExport,\n"); fwrite($hFile, "\t\t'$sProperty' => $sExport,\n");
} }
fwrite($hFile, "\t),\n"); fwrite($hFile, "\t),\n");
} }
@@ -1502,165 +1268,5 @@ class Config
} }
return $aResult; return $aResult;
} }
/**
* Helper function to initialize a configuration from the page arguments
*/
public function UpdateFromParams($aParamValues, $sModulesDir = null, $bPreserveModuleSettings = false)
{
if (isset($aParamValues['application_path']))
{
$this->Set('app_root_url', $aParamValues['application_path']);
}
if (isset($aParamValues['mode']) && isset($aParamValues['language']))
{
if (($aParamValues['mode'] == 'install') || $this->GetDefaultLanguage() == '')
{
$this->SetDefaultLanguage($aParamValues['language']);
}
}
if (isset($aParamValues['db_server']))
{
$this->SetDBHost($aParamValues['db_server']);
$this->SetDBUser($aParamValues['db_user']);
$this->SetDBPwd($aParamValues['db_pwd']);
$sDBName = $aParamValues['db_name'];
if ($sDBName == '')
{
// Todo - obsolete after the transition to the new setup (2.0) is complete (WARNING: used by the designer)
$sDBName = $aParamValues['new_db_name'];
}
$this->SetDBName($sDBName);
$this->SetDBSubname($aParamValues['db_prefix']);
}
if (!is_null($sModulesDir))
{
if (isset($aParamValues['selected_modules']))
{
$aSelectedModules = explode(',', $aParamValues['selected_modules']);
}
else
{
$aSelectedModules = null;
}
// Initialize the arrays below with default values for the application...
$oEmptyConfig = new Config('dummy_file', false); // Do NOT load any config file, just set the default values
$aAddOns = $oEmptyConfig->GetAddOns();
$aAppModules = $oEmptyConfig->GetAppModules();
$aDataModels = $oEmptyConfig->GetDataModels();
$aWebServiceCategories = $oEmptyConfig->GetWebServiceCategories();
$aDictionaries = $oEmptyConfig->GetDictionaries();
// Merge the values with the ones provided by the modules
// Make sure when don't load the same file twice...
$aModules = ModuleDiscovery::GetAvailableModules(array(APPROOT.$sModulesDir));
foreach($aModules as $sModuleId => $aModuleInfo)
{
list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId);
if (is_null($aSelectedModules) || in_array($sModuleName, $aSelectedModules))
{
if (isset($aModuleInfo['datamodel']))
{
$aDataModels = array_unique(array_merge($aDataModels, $aModuleInfo['datamodel']));
}
if (isset($aModuleInfo['webservice']))
{
$aWebServiceCategories = array_unique(array_merge($aWebServiceCategories, $aModuleInfo['webservice']));
}
if (isset($aModuleInfo['dictionary']))
{
$aDictionaries = array_unique(array_merge($aDictionaries, $aModuleInfo['dictionary']));
}
if (isset($aModuleInfo['settings']))
{
list($sName, $sVersion) = ModuleDiscovery::GetModuleName($sModuleId);
foreach($aModuleInfo['settings'] as $sProperty => $value)
{
if ($bPreserveModuleSettings && isset($this->m_aModuleSettings[$sName][$sProperty]))
{
// Do nothing keep the original value
}
else
{
$this->SetModuleSetting($sName, $sProperty, $value);
}
}
}
if (isset($aModuleInfo['installer']))
{
$sModuleInstallerClass = $aModuleInfo['installer'];
if (!class_exists($sModuleInstallerClass))
{
throw new Exception("Wrong installer class: '$sModuleInstallerClass' is not a PHP class - Module: ".$aModuleInfo['label']);
}
if (!is_subclass_of($sModuleInstallerClass, 'ModuleInstallerAPI'))
{
throw new Exception("Wrong installer class: '$sModuleInstallerClass' is not derived from 'ModuleInstallerAPI' - Module: ".$aModuleInfo['label']);
}
$aCallSpec = array($sModuleInstallerClass, 'BeforeWritingConfig');
call_user_func_array($aCallSpec, array($this));
}
}
}
$this->SetAddOns($aAddOns);
$this->SetAppModules($aAppModules);
$this->SetDataModels($aDataModels);
$this->SetWebServiceCategories($aWebServiceCategories);
$this->SetDictionaries($aDictionaries);
}
}
/**
* Helper: for an array of string, change the prefix when found
*/
protected static function ChangePrefix(&$aStrings, $sSearchPrefix, $sNewPrefix)
{
foreach ($aStrings as &$sFile)
{
if (substr($sFile, 0, strlen($sSearchPrefix)) == $sSearchPrefix)
{
$sFile = $sNewPrefix.substr($sFile, strlen($sSearchPrefix));
}
}
}
/**
* Quick an dirty way to clone a config file into another environment
*/
public function ChangeModulesPath($sSourceEnv, $sTargetEnv)
{
$sSearchPrefix = 'env-'.$sSourceEnv.'/';
$sNewPrefix = 'env-'.$sTargetEnv.'/';
self::ChangePrefix($this->m_aDataModels, $sSearchPrefix, $sNewPrefix);
self::ChangePrefix($this->m_aWebServiceCategories, $sSearchPrefix, $sNewPrefix);
self::ChangePrefix($this->m_aDictionaries, $sSearchPrefix, $sNewPrefix);
}
/**
* Pretty format a var_export'ed value so that (if possible) the identation is preserved on every line
* @param mixed $value The value to export
* @param string $sIdentation The string to use to indent the text
* @param bool $bForceIndentation Forces the identation (enven if it breaks/changes an eval, for example to ouput a value inside a comment)
* @return string The indented export string
*/
protected static function PrettyVarExport($value, $sIdentation, $bForceIndentation = false)
{
$sExport = var_export($value, true);
$sNiceExport = trim(preg_replace("/^/m", "\t\t\t", $sExport));
if (!$bForceIndentation)
{
eval('$aImported='.$sNiceExport.';');
// Check if adding the identations at the beginning of each line
// did not modify the values (in case of a string containing a line break)
if($aImported != $value)
{
$sNiceExport = $sExport;
}
}
return $sNiceExport;
}
} }
?> ?>

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Exception management * Exception management
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* CSV parser * CSV parser
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */

View File

@@ -1,28 +1,27 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* data generator * data generator
* helps the consultants in creating dummy data sets, for various test purposes (validation, usability, scalability) * helps the consultants in creating dummy data sets, for various test purposes (validation, usability, scalability)
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
/** /**

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Class dbObject: the root of persistent classes * Class dbObject: the root of persistent classes
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once('metamodel.class.php'); require_once('metamodel.class.php');
@@ -81,7 +80,7 @@ abstract class DBObject
{ {
$this->m_aCurrValues[$sAttCode] = $oAttDef->GetDefaultValue(); $this->m_aCurrValues[$sAttCode] = $oAttDef->GetDefaultValue();
$this->m_aOrigValues[$sAttCode] = null; $this->m_aOrigValues[$sAttCode] = null;
if ($oAttDef->IsExternalField() || ($oAttDef instanceof AttributeFriendlyName)) if ($oAttDef->IsExternalField())
{ {
// This field has to be read from the DB // This field has to be read from the DB
// Leave the flag unset (optimization) // Leave the flag unset (optimization)
@@ -146,8 +145,8 @@ abstract class DBObject
{ {
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef) foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef)
{ {
if (!$oAttDef->LoadInObject()) continue; @$bIsLoaded = $this->m_aLoadedAtt[$sAttCode];
if (!isset($this->m_aLoadedAtt[$sAttCode]) || !$this->m_aLoadedAtt[$sAttCode]) if ($bIsLoaded !== true)
{ {
return false; return false;
} }
@@ -250,8 +249,6 @@ abstract class DBObject
// Skip links (could not be loaded by the mean of this query) // Skip links (could not be loaded by the mean of this query)
if ($oAttDef->IsLinkSet()) continue; if ($oAttDef->IsLinkSet()) continue;
if (!$oAttDef->LoadInObject()) continue;
// Note: we assume that, for a given attribute, if it can be loaded, // Note: we assume that, for a given attribute, if it can be loaded,
// then one column will be found with an empty suffix, the others have a suffix // then one column will be found with an empty suffix, the others have a suffix
// Take care: the function isset will return false in case the value is null, // Take care: the function isset will return false in case the value is null,
@@ -263,14 +260,7 @@ abstract class DBObject
$value = $oAttDef->FromSQLToValue($aRow, $sAttRef); $value = $oAttDef->FromSQLToValue($aRow, $sAttRef);
$this->m_aCurrValues[$sAttCode] = $value; $this->m_aCurrValues[$sAttCode] = $value;
if (is_object($value)) $this->m_aOrigValues[$sAttCode] = $value;
{
$this->m_aOrigValues[$sAttCode] = clone $value;
}
else
{
$this->m_aOrigValues[$sAttCode] = $value;
}
$this->m_aLoadedAtt[$sAttCode] = true; $this->m_aLoadedAtt[$sAttCode] = true;
} }
else else
@@ -312,39 +302,31 @@ abstract class DBObject
$this->Reload(); $this->Reload();
} }
if ($oAttDef->IsExternalKey()) if ($oAttDef->IsExternalKey() && is_object($value))
{ {
if (is_object($value)) // Setting an external key with a whole object (instead of just an ID)
// let's initialize also the external fields that depend on it
// (useful when building objects in memory and not from a query)
if ( (get_class($value) != $oAttDef->GetTargetClass()) && (!is_subclass_of($value, $oAttDef->GetTargetClass())))
{ {
// Setting an external key with a whole object (instead of just an ID) throw new CoreUnexpectedValue("Trying to set the value of '$sAttCode', to an object of class '".get_class($value)."', whereas it's an ExtKey to '".$oAttDef->GetTargetClass()."'. Ignored");
// let's initialize also the external fields that depend on it }
// (useful when building objects in memory and not from a query) else
if ( (get_class($value) != $oAttDef->GetTargetClass()) && (!is_subclass_of($value, $oAttDef->GetTargetClass()))) {
{ // The object has changed, reset caches
throw new CoreUnexpectedValue("Trying to set the value of '$sAttCode', to an object of class '".get_class($value)."', whereas it's an ExtKey to '".$oAttDef->GetTargetClass()."'. Ignored"); $this->m_bCheckStatus = null;
} $this->m_aAsArgs = null;
$this->m_aCurrValues[$sAttCode] = $value->GetKey();
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sCode => $oDef) foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sCode => $oDef)
{ {
if (($oDef->IsExternalField() || ($oDef instanceof AttributeFriendlyName)) && ($oDef->GetKeyAttCode() == $sAttCode)) if ($oDef->IsExternalField() && ($oDef->GetKeyAttCode() == $sAttCode))
{ {
$this->m_aCurrValues[$sCode] = $value->Get($oDef->GetExtAttCode()); $this->m_aCurrValues[$sCode] = $value->Get($oDef->GetExtAttCode());
} }
} }
} }
else if ($this->m_aCurrValues[$sAttCode] != $value) return;
{
// Setting an external key, but no any other information is available...
// Invalidate the corresponding fields so that they get reloaded in case they are needed (See Get())
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sCode => $oDef)
{
if (($oDef->IsExternalField() || ($oDef instanceof AttributeFriendlyName)) && ($oDef->GetKeyAttCode() == $sAttCode))
{
$this->m_aCurrValues[$sCode] = $oDef->GetDefaultValue();
unset($this->m_aLoadedAtt[$sCode]);
}
}
}
} }
if(!$oAttDef->IsScalar() && !is_object($value)) if(!$oAttDef->IsScalar() && !is_object($value))
{ {
@@ -368,7 +350,6 @@ abstract class DBObject
} }
$realvalue = $oAttDef->MakeRealValue($value, $this); $realvalue = $oAttDef->MakeRealValue($value, $this);
$this->m_aCurrValues[$sAttCode] = $realvalue; $this->m_aCurrValues[$sAttCode] = $realvalue;
// The object has changed, reset caches // The object has changed, reset caches
@@ -415,73 +396,16 @@ abstract class DBObject
public function GetStrict($sAttCode) public function GetStrict($sAttCode)
{ {
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode); if (!array_key_exists($sAttCode, MetaModel::ListAttributeDefs(get_class($this))))
if (!$oAttDef->LoadInObject())
{ {
$sParentAttCode = $oAttDef->GetParentAttCode(); throw new CoreException("Unknown attribute code '$sAttCode' for the class ".get_class($this));
$parentValue = $this->GetStrict($sParentAttCode);
$value = $oAttDef->GetValue($parentValue, $this);
} }
else if ($this->m_bIsInDB && !isset($this->m_aLoadedAtt[$sAttCode]) && !$this->m_bDirty)
{ {
if (isset($this->m_aLoadedAtt[$sAttCode])) // #@# non-scalar attributes.... handle that differently
{ $this->Reload();
// Standard case... we have the information directly
}
elseif ($this->m_bIsInDB && !$this->m_bDirty)
{
// Lazy load (polymorphism): complete by reloading the entire object
// #@# non-scalar attributes.... handle that differently?
$this->Reload();
}
elseif ($sAttCode == 'friendlyname')
{
// The friendly name is not computed and the object is dirty
// Todo: implement the computation of the friendly name based on sprintf()
//
$this->m_aCurrValues[$sAttCode] = '';
}
else
{
// Not loaded... is it related to an external key?
if ($oAttDef->IsExternalField() || ($oAttDef instanceof AttributeFriendlyName))
{
// Let's get the object and compute all of the corresponding attributes
// (i.e not only the requested attribute)
//
$sExtKeyAttCode = $oAttDef->GetKeyAttCode();
if (($iRemote = $this->Get($sExtKeyAttCode)) && ($iRemote > 0)) // Objects in memory have negative IDs
{
$oExtKeyAttDef = MetaModel::GetAttributeDef(get_class($this), $sExtKeyAttCode);
$oRemote = MetaModel::GetObject($oExtKeyAttDef->GetTargetClass(), $iRemote);
}
else
{
$oRemote = null;
}
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sCode => $oDef)
{
if (($oDef->IsExternalField() || ($oDef instanceof AttributeFriendlyName)) && ($oDef->GetKeyAttCode() == $sExtKeyAttCode))
{
if ($oRemote)
{
$this->m_aCurrValues[$sCode] = $oRemote->Get($oDef->GetExtAttCode());
}
else
{
$this->m_aCurrValues[$sCode] = $oDef->GetDefaultValue();
}
$this->m_aLoadedAtt[$sCode] = true;
}
}
}
}
$value = $this->m_aCurrValues[$sAttCode];
} }
$value = $this->m_aCurrValues[$sAttCode];
if ($value instanceof DBObjectSet) if ($value instanceof DBObjectSet)
{ {
$value->Rewind(); $value->Rewind();
@@ -549,7 +473,7 @@ abstract class DBObject
$this->ComputeValues(); $this->ComputeValues();
} }
public function GetAsHTML($sAttCode, $bLocalize = true) public function GetAsHTML($sAttCode)
{ {
$sClass = get_class($this); $sClass = get_class($this);
$oAtt = MetaModel::GetAttributeDef($sClass, $sAttCode); $oAtt = MetaModel::GetAttributeDef($sClass, $sAttCode);
@@ -559,20 +483,12 @@ abstract class DBObject
//return $this->Get($sAttCode.'_friendlyname'); //return $this->Get($sAttCode.'_friendlyname');
$sTargetClass = $oAtt->GetTargetClass(EXTKEY_ABSOLUTE); $sTargetClass = $oAtt->GetTargetClass(EXTKEY_ABSOLUTE);
$iTargetKey = $this->Get($sAttCode); $iTargetKey = $this->Get($sAttCode);
if ($iTargetKey < 0) $sLabel = $this->Get($sAttCode.'_friendlyname');
{ return $this->MakeHyperLink($sTargetClass, $iTargetKey, $sLabel);
// the key points to an object that exists only in memory... no hyperlink points to it yet
return '';
}
else
{
$sLabel = $this->Get($sAttCode.'_friendlyname');
return $this->MakeHyperLink($sTargetClass, $iTargetKey, $sLabel);
}
} }
// That's a standard attribute (might be an ext field or a direct field, etc.) // That's a standard attribute (might be an ext field or a direct field, etc.)
return $oAtt->GetAsHTML($this->Get($sAttCode), $this, $bLocalize); return $oAtt->GetAsHTML($this->Get($sAttCode));
} }
public function GetEditValue($sAttCode) public function GetEditValue($sAttCode)
@@ -605,42 +521,42 @@ abstract class DBObject
} }
else else
{ {
$sEditValue = $oAtt->GetEditValue($this->Get($sAttCode), $this); $sEditValue = $oAtt->GetEditValue($this->Get($sAttCode));
} }
return $sEditValue; return $sEditValue;
} }
public function GetAsXML($sAttCode, $bLocalize = true) public function GetAsXML($sAttCode)
{ {
$oAtt = MetaModel::GetAttributeDef(get_class($this), $sAttCode); $oAtt = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
return $oAtt->GetAsXML($this->Get($sAttCode), $this, $bLocalize); return $oAtt->GetAsXML($this->Get($sAttCode), $this);
} }
public function GetAsCSV($sAttCode, $sSeparator = ',', $sTextQualifier = '"', $bLocalize = true) public function GetAsCSV($sAttCode, $sSeparator = ',', $sTextQualifier = '"')
{ {
$oAtt = MetaModel::GetAttributeDef(get_class($this), $sAttCode); $oAtt = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
return $oAtt->GetAsCSV($this->Get($sAttCode), $sSeparator, $sTextQualifier, $this, $bLocalize); return $oAtt->GetAsCSV($this->Get($sAttCode), $sSeparator, $sTextQualifier, $this);
} }
public function GetOriginalAsHTML($sAttCode, $bLocalize = true) public function GetOriginalAsHTML($sAttCode)
{ {
$oAtt = MetaModel::GetAttributeDef(get_class($this), $sAttCode); $oAtt = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
return $oAtt->GetAsHTML($this->GetOriginal($sAttCode), $this, $bLocalize); return $oAtt->GetAsHTML($this->GetOriginal($sAttCode), $this);
} }
public function GetOriginalAsXML($sAttCode, $bLocalize = true) public function GetOriginalAsXML($sAttCode)
{ {
$oAtt = MetaModel::GetAttributeDef(get_class($this), $sAttCode); $oAtt = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
return $oAtt->GetAsXML($this->GetOriginal($sAttCode), $this, $bLocalize); return $oAtt->GetAsXML($this->GetOriginal($sAttCode), $this);
} }
public function GetOriginalAsCSV($sAttCode, $sSeparator = ',', $sTextQualifier = '"', $bLocalize = true) public function GetOriginalAsCSV($sAttCode, $sSeparator = ',', $sTextQualifier = '"')
{ {
$oAtt = MetaModel::GetAttributeDef(get_class($this), $sAttCode); $oAtt = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
return $oAtt->GetAsCSV($this->GetOriginal($sAttCode), $sSeparator, $sTextQualifier, $this, $bLocalize); return $oAtt->GetAsCSV($this->GetOriginal($sAttCode), $sSeparator, $sTextQualifier, $this);
} }
public static function MakeHyperLink($sObjClass, $sObjKey, $sLabel = '', $sUrlMakerClass = null, $bWithNavigationContext = true) protected static function MakeHyperLink($sObjClass, $sObjKey, $sLabel = '', $sUrlMakerClass = null, $bWithNavigationContext = true)
{ {
if ($sObjKey <= 0) return '<em>'.Dict::S('UI:UndefinedObject').'</em>'; // Objects built in memory have negative IDs if ($sObjKey <= 0) return '<em>'.Dict::S('UI:UndefinedObject').'</em>'; // Objects built in memory have negative IDs
@@ -795,29 +711,6 @@ abstract class DBObject
return MetaModel::GetStateDescription(get_class($this), $sStateValue); return MetaModel::GetStateDescription(get_class($this), $sStateValue);
} }
} }
/**
* Overridable - Define attributes read-only from the end-user perspective
*
* @return array List of attcodes
*/
public static function GetReadOnlyAttributes()
{
return null;
}
/**
* Overridable - Get predefined objects (could be hardcoded)
* The predefined objects will be synchronized with the DB at each install/upgrade
* As soon as a class has predefined objects, then nobody can create nor delete objects
* @return array An array of id => array of attcode => php value(so-called "real value": integer, string, ormDocument, DBObjectSet, etc.)
*/
public static function GetPredefinedObjects()
{
return null;
}
/** /**
* Returns the set of flags (OPT_ATT_HIDDEN, OPT_ATT_READONLY, OPT_ATT_MANDATORY...) * Returns the set of flags (OPT_ATT_HIDDEN, OPT_ATT_READONLY, OPT_ATT_MANDATORY...)
* for the given attribute in the current state of the object * for the given attribute in the current state of the object
@@ -829,16 +722,6 @@ abstract class DBObject
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '') public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
{ {
$iFlags = 0; // By default (if no life cycle) no flag at all $iFlags = 0; // By default (if no life cycle) no flag at all
$aReadOnlyAtts = $this->GetReadOnlyAttributes();
if ($aReadOnlyAtts != null)
{
if (in_array($sAttCode, $aReadOnlyAtts))
{
return OPT_ATT_READONLY;
}
}
$sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this)); $sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this));
if (!empty($sStateAttCode)) if (!empty($sStateAttCode))
{ {
@@ -1049,7 +932,7 @@ abstract class DBObject
$oDeletionPlan->AddToDelete($oReplica, DEL_SILENT); $oDeletionPlan->AddToDelete($oReplica, DEL_SILENT);
if ($oDataSource->GetKey() == SynchroExecution::GetCurrentTaskId()) if ($oDataSource->GetKey() == SynchroDataSource::GetCurrentTaskId())
{ {
// The current task has the right to delete the object // The current task has the right to delete the object
continue; continue;
@@ -1371,26 +1254,6 @@ abstract class DBObject
throw new CoreException("Object not following integrity rules", array('issues' => $sIssues, 'class' => get_class($this), 'id' => $this->GetKey())); throw new CoreException("Object not following integrity rules", array('issues' => $sIssues, 'class' => get_class($this), 'id' => $this->GetKey()));
} }
// Stop watches
$sState = $this->GetState();
if ($sState != '')
{
foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
{
if ($oAttDef instanceof AttributeStopWatch)
{
if (in_array($sState, $oAttDef->GetStates()))
{
// Start the stop watch and compute the deadlines
$oSW = $this->Get($sAttCode);
$oSW->Start($this, $oAttDef);
$oSW->ComputeDeadlines($this, $oAttDef);
$this->Set($sAttCode, $oSW);
}
}
}
}
// First query built upon on the root class, because the ID must be created first // First query built upon on the root class, because the ID must be created first
$this->m_iKey = $this->DBInsertSingleTable($sRootClass); $this->m_iKey = $this->DBInsertSingleTable($sRootClass);
@@ -1425,8 +1288,6 @@ abstract class DBObject
$oTrigger->DoActivate($this->ToArgs('this')); $oTrigger->DoActivate($this->ToArgs('this'));
} }
$this->RecordObjCreation();
return $this->m_iKey; return $this->m_iKey;
} }
@@ -1437,27 +1298,18 @@ abstract class DBObject
return $this->m_iKey; return $this->m_iKey;
} }
public function DBInsertTracked(CMDBChange $oChange) public function DBInsertTracked(CMDBChange $oVoid)
{ {
CMDBObject::SetCurrentChange($oChange);
return $this->DBInsert(); return $this->DBInsert();
} }
public function DBInsertTrackedNoReload(CMDBChange $oChange)
{
CMDBObject::SetCurrentChange($oChange);
return $this->DBInsertNoReload();
}
// Creates a copy of the current object into the database // Creates a copy of the current object into the database
// Returns the id of the newly created object // Returns the id of the newly created object
public function DBClone($iNewKey = null) public function DBClone($iNewKey = null)
{ {
$this->m_bIsInDB = false; $this->m_bIsInDB = false;
$this->m_iKey = $iNewKey; $this->m_iKey = $iNewKey;
$ret = $this->DBInsert(); return $this->DBInsert();
$this->RecordObjCreation();
return $ret;
} }
/** /**
@@ -1480,32 +1332,13 @@ abstract class DBObject
throw new CoreException("DBUpdate: could not update a newly created object, please call DBInsert instead"); throw new CoreException("DBUpdate: could not update a newly created object, please call DBInsert instead");
} }
// Stop watches
$sState = $this->GetState();
if ($sState != '')
{
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode => $oAttDef)
{
if ($oAttDef instanceof AttributeStopWatch)
{
if (in_array($sState, $oAttDef->GetStates()))
{
// Compute or recompute the deadlines
$oSW = $this->Get($sAttCode);
$oSW->ComputeDeadlines($this, $oAttDef);
$this->Set($sAttCode, $oSW);
}
}
}
}
$this->DoComputeValues(); $this->DoComputeValues();
$this->OnUpdate(); $this->OnUpdate();
$aChanges = $this->ListChanges(); $aChanges = $this->ListChanges();
if (count($aChanges) == 0) if (count($aChanges) == 0)
{ {
// Attempting to update an unchanged object //throw new CoreWarning("Attempting to update an unchanged object");
return; return;
} }
@@ -1517,9 +1350,6 @@ abstract class DBObject
throw new CoreException("Object not following integrity rules", array('issues' => $sIssues, 'class' => get_class($this), 'id' => $this->GetKey())); throw new CoreException("Object not following integrity rules", array('issues' => $sIssues, 'class' => get_class($this), 'id' => $this->GetKey()));
} }
// Save the original values (will be reset to the new values when the object get written to the DB)
$aOriginalValues = $this->m_aOrigValues;
$bHasANewExternalKeyValue = false; $bHasANewExternalKeyValue = false;
$aHierarchicalKeys = array(); $aHierarchicalKeys = array();
foreach($aChanges as $sAttCode => $valuecurr) foreach($aChanges as $sAttCode => $valuecurr)
@@ -1597,31 +1427,12 @@ abstract class DBObject
{ {
$this->Reload(); $this->Reload();
} }
else
{
// Reset original values although the object has not been reloaded
foreach ($this->m_aLoadedAtt as $sAttCode => $bLoaded)
{
if ($bLoaded)
{
$value = $this->m_aCurrValues[$sAttCode];
$this->m_aOrigValues[$sAttCode] = is_object($value) ? clone $value : $value;
}
}
}
if (count($aChanges) != 0)
{
$this->RecordAttChanges($aChanges, $aOriginalValues);
}
return $this->m_iKey; return $this->m_iKey;
} }
public function DBUpdateTracked(CMDBChange $oChange) public function DBUpdateTracked(CMDBChange $oVoid)
{ {
CMDBObject::SetCurrentChange($oChange);
return $this->DBUpdate(); return $this->DBUpdate();
} }
@@ -1653,11 +1464,10 @@ abstract class DBObject
protected function DBDeleteSingleObject() protected function DBDeleteSingleObject()
{ {
$this->OnDelete();
if (!MetaModel::DBIsReadOnly()) if (!MetaModel::DBIsReadOnly())
{ {
$this->OnDelete();
$this->RecordObjDeletion($this->m_iKey); // May cause a reload for storing history information
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode => $oAttDef) foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode => $oAttDef)
{ {
if ($oAttDef->IsHierarchicalKey()) if ($oAttDef->IsHierarchicalKey())
@@ -1690,12 +1500,12 @@ abstract class DBObject
{ {
$this->DBDeleteSingleTable($sParentClass); $this->DBDeleteSingleTable($sParentClass);
} }
$this->AfterDelete();
$this->m_bIsInDB = false;
$this->m_iKey = null;
} }
$this->AfterDelete();
$this->m_bIsInDB = false;
$this->m_iKey = null;
} }
// Delete an object... and guarantee data integrity // Delete an object... and guarantee data integrity
@@ -1749,9 +1559,8 @@ abstract class DBObject
return $oDeletionPlan; return $oDeletionPlan;
} }
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null) public function DBDeleteTracked(CMDBChange $oVoid, $bSkipStrongSecurity = null, &$oDeletionPlan = null)
{ {
CMDBObject::SetCurrentChange($oChange);
$this->DBDelete($oDeletionPlan); $this->DBDelete($oDeletionPlan);
} }
@@ -1764,11 +1573,7 @@ abstract class DBObject
return MetaModel::EnumTransitions(get_class($this), $sState); return MetaModel::EnumTransitions(get_class($this), $sState);
} }
/** public function ApplyStimulus($sStimulusCode)
* Designed as an action to be called when a stop watch threshold times out
* or from within the framework
*/
public function ApplyStimulus($sStimulusCode, $bDoNotWrite = false)
{ {
$sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this)); $sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this));
if (empty($sStateAttCode)) return false; if (empty($sStateAttCode)) return false;
@@ -1802,34 +1607,11 @@ abstract class DBObject
// if one call fails, the whole is considered as failed // if one call fails, the whole is considered as failed
if (!$bRet) $bSuccess = false; if (!$bRet) $bSuccess = false;
} }
if ($bSuccess) if ($bSuccess)
{ {
$sClass = get_class($this);
// Stop watches
foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
{
if ($oAttDef instanceof AttributeStopWatch)
{
$oSW = $this->Get($sAttCode);
if (in_array($sNewState, $oAttDef->GetStates()))
{
$oSW->Start($this, $oAttDef);
}
else
{
$oSW->Stop($this, $oAttDef);
}
$this->Set($sAttCode, $oSW);
}
}
if (!$bDoNotWrite)
{
$this->DBWrite();
}
// Change state triggers... // Change state triggers...
$sClass = get_class($this);
$sClassList = implode("', '", MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL)); $sClassList = implode("', '", MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL));
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnStateLeave AS t WHERE t.target_class IN ('$sClassList') AND t.state='$sPreviousState'")); $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnStateLeave AS t WHERE t.target_class IN ('$sClassList') AND t.state='$sPreviousState'"));
while ($oTrigger = $oSet->Fetch()) while ($oTrigger = $oSet->Fetch())
@@ -1847,21 +1629,6 @@ abstract class DBObject
return $bSuccess; return $bSuccess;
} }
/**
* Designed as an action to be called when a stop watch threshold times out
*/
public function ResetStopWatch($sAttCode)
{
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
if (!$oAttDef instanceof AttributeStopWatch)
{
throw new CoreException("Invalid stop watch id: '$sAttCode'");
}
$oSW = $this->Get($sAttCode);
$oSW->Reset($this, $oAttDef);
$this->Set($sAttCode, $oSW);
}
// Make standard context arguments // Make standard context arguments
// Note: Needs to be reviewed because it is currently called once per attribute when an object is written (CheckToWrite / CheckValue) // Note: Needs to be reviewed because it is currently called once per attribute when an object is written (CheckToWrite / CheckValue)
// Several options here: // Several options here:
@@ -1879,7 +1646,7 @@ abstract class DBObject
$aScalarArgs[$sArgName.'->hyperlink()'] = $this->GetHyperlink('iTopStandardURLMaker', false); $aScalarArgs[$sArgName.'->hyperlink()'] = $this->GetHyperlink('iTopStandardURLMaker', false);
$aScalarArgs[$sArgName.'->hyperlink(portal)'] = $this->GetHyperlink('PortalURLMaker', false); $aScalarArgs[$sArgName.'->hyperlink(portal)'] = $this->GetHyperlink('PortalURLMaker', false);
$aScalarArgs[$sArgName.'->name()'] = $this->GetName(); $aScalarArgs[$sArgName.'->name()'] = $this->GetName();
$sClass = get_class($this); $sClass = get_class($this);
foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
{ {
@@ -1889,7 +1656,7 @@ abstract class DBObject
// #@# Note: This has been proven to be quite slow, this can slow down bulk load // #@# Note: This has been proven to be quite slow, this can slow down bulk load
$sAsHtml = $this->GetAsHtml($sAttCode); $sAsHtml = $this->GetAsHtml($sAttCode);
$aScalarArgs[$sArgName.'->html('.$sAttCode.')'] = $sAsHtml; $aScalarArgs[$sArgName.'->html('.$sAttCode.')'] = $sAsHtml;
$aScalarArgs[$sArgName.'->label('.$sAttCode.')'] = $this->GetEditValue($sAttCode); // "Nice" display value, but without HTML tags and entities $aScalarArgs[$sArgName.'->label('.$sAttCode.')'] = strip_tags($sAsHtml);
} }
// Do something for case logs... quick N' dirty... // Do something for case logs... quick N' dirty...
if ($aScalarArgs[$sArgName.'->'.$sAttCode] instanceof ormCaseLog) if ($aScalarArgs[$sArgName.'->'.$sAttCode] instanceof ormCaseLog)
@@ -1899,7 +1666,6 @@ abstract class DBObject
$aScalarArgs[$sArgName.'->head('.$sAttCode.')'] = $oCaseLog->GetLatestEntry(); $aScalarArgs[$sArgName.'->head('.$sAttCode.')'] = $oCaseLog->GetLatestEntry();
} }
} }
$this->m_aAsArgs = $aScalarArgs; $this->m_aAsArgs = $aScalarArgs;
$oKPI->ComputeStats('ToArgs', get_class($this)); $oKPI->ComputeStats('ToArgs', get_class($this));
} }
@@ -1936,152 +1702,6 @@ abstract class DBObject
{ {
} }
/**
* Common to the recording of link set changes (add/remove/modify)
*/
private function PrepareChangeOpLinkSet($iLinkSetOwnerId, $oLinkSet, $sChangeOpClass, $aOriginalValues = null)
{
if ($iLinkSetOwnerId <= 0)
{
return null;
}
if (!is_subclass_of($oLinkSet->GetHostClass(), 'CMDBObject'))
{
// The link set owner class does not keep track of its history
return null;
}
// Determine the linked item class and id
//
if ($oLinkSet->IsIndirect())
{
// The "item" is on the other end (N-N links)
$sExtKeyToRemote = $oLinkSet->GetExtKeyToRemote();
$oExtKeyToRemote = MetaModel::GetAttributeDef(get_class($this), $sExtKeyToRemote);
$sItemClass = $oExtKeyToRemote->GetTargetClass();
if ($aOriginalValues)
{
// Get the value from the original values
$iItemId = $aOriginalValues[$sExtKeyToRemote];
}
else
{
$iItemId = $this->Get($sExtKeyToRemote);
}
}
else
{
// I am the "item" (1-N links)
$sItemClass = get_class($this);
$iItemId = $this->GetKey();
}
// Get the remote object, to determine its exact class
// Possible optimization: implement a tool in MetaModel, to get the final class of an object (not always querying + query reduced to a select on the root table!
$oOwner = MetaModel::GetObject($oLinkSet->GetHostClass(), $iLinkSetOwnerId, false);
if ($oOwner)
{
$sLinkSetOwnerClass = get_class($oOwner);
$oMyChangeOp = MetaModel::NewObject($sChangeOpClass);
$oMyChangeOp->Set("objclass", $sLinkSetOwnerClass);
$oMyChangeOp->Set("objkey", $iLinkSetOwnerId);
$oMyChangeOp->Set("attcode", $oLinkSet->GetCode());
$oMyChangeOp->Set("item_class", $sItemClass);
$oMyChangeOp->Set("item_id", $iItemId);
return $oMyChangeOp;
}
else
{
// Depending on the deletion order, it may happen that the id is already invalid... ignore
return null;
}
}
/**
* This object has been created/deleted, record that as a change in link sets pointing to this (if any)
*/
private function RecordLinkSetListChange($bAdd = true)
{
$aForwardChangeTracking = MetaModel::GetTrackForwardExternalKeys(get_class($this));
foreach(MetaModel::GetTrackForwardExternalKeys(get_class($this)) as $sExtKeyAttCode => $oLinkSet)
{
if (($oLinkSet->GetTrackingLevel() & LINKSET_TRACKING_LIST) == 0) continue;
$iLinkSetOwnerId = $this->Get($sExtKeyAttCode);
$oMyChangeOp = $this->PrepareChangeOpLinkSet($iLinkSetOwnerId, $oLinkSet, 'CMDBChangeOpSetAttributeLinksAddRemove');
if ($oMyChangeOp)
{
if ($bAdd)
{
$oMyChangeOp->Set("type", "added");
}
else
{
$oMyChangeOp->Set("type", "removed");
}
$iId = $oMyChangeOp->DBInsertNoReload();
}
}
}
protected function RecordObjCreation()
{
$this->RecordLinkSetListChange(true);
}
protected function RecordObjDeletion($objkey)
{
$this->RecordLinkSetListChange(false);
}
protected function RecordAttChanges(array $aValues, array $aOrigValues)
{
$aForwardChangeTracking = MetaModel::GetTrackForwardExternalKeys(get_class($this));
foreach(MetaModel::GetTrackForwardExternalKeys(get_class($this)) as $sExtKeyAttCode => $oLinkSet)
{
if (array_key_exists($sExtKeyAttCode, $aValues))
{
if (($oLinkSet->GetTrackingLevel() & LINKSET_TRACKING_LIST) == 0) continue;
// Keep track of link added/removed
//
$iLinkSetOwnerNext = $aValues[$sExtKeyAttCode];
$oMyChangeOp = $this->PrepareChangeOpLinkSet($iLinkSetOwnerNext, $oLinkSet, 'CMDBChangeOpSetAttributeLinksAddRemove');
if ($oMyChangeOp)
{
$oMyChangeOp->Set("type", "added");
$oMyChangeOp->DBInsertNoReload();
}
$iLinkSetOwnerPrevious = $aOrigValues[$sExtKeyAttCode];
$oMyChangeOp = $this->PrepareChangeOpLinkSet($iLinkSetOwnerPrevious, $oLinkSet, 'CMDBChangeOpSetAttributeLinksAddRemove', $aOrigValues);
if ($oMyChangeOp)
{
$oMyChangeOp->Set("type", "removed");
$oMyChangeOp->DBInsertNoReload();
}
}
else
{
// Keep track of link changes
//
if (($oLinkSet->GetTrackingLevel() & LINKSET_TRACKING_DETAILS) == 0) continue;
$iLinkSetOwnerId = $this->Get($sExtKeyAttCode);
$oMyChangeOp = $this->PrepareChangeOpLinkSet($iLinkSetOwnerId, $oLinkSet, 'CMDBChangeOpSetAttributeLinksTune');
if ($oMyChangeOp)
{
$oMyChangeOp->Set("link_id", $this->GetKey());
$iId = $oMyChangeOp->DBInsertNoReload();
}
}
}
}
// Return an empty set for the parent of all // Return an empty set for the parent of all
public static function GetRelationQueries($sRelCode) public static function GetRelationQueries($sRelCode)
{ {
@@ -2242,7 +1862,7 @@ abstract class DBObject
$oSet = $this->GetMasterReplica(); $oSet = $this->GetMasterReplica();
while($aData = $oSet->FetchAssoc()) while($aData = $oSet->FetchAssoc())
{ {
if ($aData['datasource']->GetKey() == SynchroExecution::GetCurrentTaskId()) if ($aData['datasource']->GetKey() == SynchroDataSource::GetCurrentTaskId())
{ {
// Ignore the current task (check to write => ok) // Ignore the current task (check to write => ok)
continue; continue;
@@ -2286,7 +1906,7 @@ abstract class DBObject
} }
// to be continued... // to be continued...
} }
} }
?> ?>

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Define filters for a given class of objects (formerly named "filter") * Define filters for a given class of objects (formerly named "filter")
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
define('TREE_OPERATOR_EQUALS', 0); define('TREE_OPERATOR_EQUALS', 0);
@@ -67,16 +66,6 @@ class DBObjectSearch
$this->m_aRelatedTo = array(); $this->m_aRelatedTo = array();
$this->m_bDataFiltered = false; $this->m_bDataFiltered = false;
$this->m_aParentConditions = array(); $this->m_aParentConditions = array();
$this->m_aModifierProperties = array();
}
/**
* Perform a deep clone (as opposed to "clone" which does copy a reference to the underlying objects
**/
public function DeepClone()
{
return unserialize(serialize($this));
} }
public function AllowAllData() {$this->m_bAllowAllData = true;} public function AllowAllData() {$this->m_bAllowAllData = true;}
@@ -84,18 +73,7 @@ class DBObjectSearch
public function IsDataFiltered() {return $this->m_bDataFiltered; } public function IsDataFiltered() {return $this->m_bDataFiltered; }
public function SetDataFiltered() {$this->m_bDataFiltered = true;} public function SetDataFiltered() {$this->m_bDataFiltered = true;}
public function GetClassName($sAlias) public function GetClassName($sAlias) {return $this->m_aClasses[$sAlias];}
{
if (array_key_exists($sAlias, $this->m_aClasses))
{
return $this->m_aClasses[$sAlias];
}
else
{
throw new CoreException("Invalid class alias '$sAlias'");
}
}
public function GetJoinedClasses() {return $this->m_aClasses;} public function GetJoinedClasses() {return $this->m_aClasses;}
public function GetClass() public function GetClass()
@@ -118,60 +96,6 @@ class DBObjectSearch
return key($this->m_aClasses); return key($this->m_aClasses);
} }
/**
* Change the class (only subclasses are supported as of now, because the conditions must fit the new class)
* Defaults to the first selected class (most of the time it is also the first joined class
*/
public function ChangeClass($sNewClass, $sAlias = null)
{
if (is_null($sAlias))
{
$sAlias = $this->GetClassAlias();
}
else
{
if (!array_key_exists($sAlias, $this->m_aClasses))
{
// discard silently - necessary when recursing on the related nodes (see code below)
return;
}
}
$sCurrClass = $this->GetClassName($sAlias);
if (!MetaModel::IsParentClass($sCurrClass, $sNewClass))
{
throw new Exception("Could not change the search class from '$sCurrClass' to '$sNewClass'. Only child classes are permitted.");
}
// Change for this node
//
$this->m_aSelectedClasses[$sAlias] = $sNewClass;
$this->m_aClasses[$sAlias] = $sNewClass;
// Change for all the related node (yes, this was necessary with some queries - strange effects otherwise)
//
foreach($this->m_aRelatedTo as $aRelatedTo)
{
$aRelatedTo['flt']->ChangeClass($sNewClass, $sAlias);
}
foreach($this->m_aPointingTo as $sExtKeyAttCode=>$aPointingTo)
{
foreach($aPointingTo as $iOperatorCode => $aFilter)
{
foreach($aFilter as $oExtFilter)
{
$oExtFilter->ChangeClass($sNewClass, $sAlias);
}
}
}
foreach($this->m_aReferencedBy as $sForeignClass => $aReferences)
{
foreach($aReferences as $sForeignExtKeyAttCode => $oForeignFilter)
{
$oForeignFilter->ChangeClass($sNewClass, $sAlias);
}
}
}
public function SetSelectedClasses($aNewSet) public function SetSelectedClasses($aNewSet)
{ {
$this->m_aSelectedClasses = array(); $this->m_aSelectedClasses = array();
@@ -191,23 +115,6 @@ class DBObjectSearch
} }
public function SetModifierProperty($sPluginClass, $sProperty, $value)
{
$this->m_aModifierProperties[$sPluginClass][$sProperty] = $value;
}
public function GetModifierProperties($sPluginClass)
{
if (array_key_exists($sPluginClass, $this->m_aModifierProperties))
{
return $this->m_aModifierProperties[$sPluginClass];
}
else
{
return array();
}
}
public function IsAny() public function IsAny()
{ {
// #@# todo - if (!$this->m_oSearchCondition->IsTrue()) return false; // #@# todo - if (!$this->m_oSearchCondition->IsTrue()) return false;
@@ -402,7 +309,7 @@ class DBObjectSearch
{ {
foreach($aPointingTo as $iOperatorCode => $aFilter) foreach($aPointingTo as $iOperatorCode => $aFilter)
{ {
foreach($aFilter as $oExtFilter) foreach($aFilter as $sAlias => $oExtFilter)
{ {
$oExtFilter->RenameParam($sOldName, $sNewName); $oExtFilter->RenameParam($sOldName, $sNewName);
} }
@@ -537,7 +444,7 @@ class DBObjectSearch
* Specify a condition on external keys or link sets * Specify a condition on external keys or link sets
* @param sAttSpec Can be either an attribute code or extkey->[sAttSpec] or linkset->[sAttSpec] and so on, recursively * @param sAttSpec Can be either an attribute code or extkey->[sAttSpec] or linkset->[sAttSpec] and so on, recursively
* Example: infra_list->ci_id->location_id->country * Example: infra_list->ci_id->location_id->country
* @param value The value to match (can be an array => IN(val1, val2...) * @param value The value to match
* @return void * @return void
*/ */
public function AddConditionAdvanced($sAttSpec, $value) public function AddConditionAdvanced($sAttSpec, $value)
@@ -584,18 +491,7 @@ class DBObjectSearch
{ {
// $sAttSpec is an attribute code // $sAttSpec is an attribute code
// //
if (is_array($value)) $this->AddCondition($sAttSpec, $value);
{
$oField = new FieldExpression($sAttSpec, $this->GetClass());
$oListExpr = ListExpression::FromScalars($value);
$oInValues = new BinaryExpression($oField, 'IN', $oListExpr);
$this->AddConditionExpression($oInValues);
}
else
{
$this->AddCondition($sAttSpec, $value);
}
} }
} }
@@ -622,45 +518,31 @@ class DBObjectSearch
{ {
if ($bTranslateMainAlias) if ($bTranslateMainAlias)
{ {
$sOrigAlias = $this->GetFirstJoinedClassAlias(); $sOrigAlias = $this->GetClassAlias();
if (array_key_exists($sOrigAlias, $aClassAliases)) if (array_key_exists($sOrigAlias, $aClassAliases))
{ {
$sNewAlias = MetaModel::GenerateUniqueAlias($aClassAliases, $sOrigAlias, $this->GetFirstJoinedClass()); $sNewAlias = MetaModel::GenerateUniqueAlias($aClassAliases, $sOrigAlias, $this->GetClass());
if (isset($this->m_aSelectedClasses[$sOrigAlias])) //echo "<p>Generating a new alias for $sOrigAlias (already used). It is now: $sNewAlias</p>\n";
{ $this->m_aSelectedClasses[$sNewAlias] = $this->GetClass();
$this->m_aSelectedClasses[$sNewAlias] = $this->GetFirstJoinedClass(); unset($this->m_aSelectedClasses[$sOrigAlias]);
unset($this->m_aSelectedClasses[$sOrigAlias]);
} $this->m_aClasses[$sNewAlias] = $this->GetClass();
unset($this->m_aClasses[$sOrigAlias]);
// TEMPORARY ALGORITHM (m_aClasses is not correctly updated, it is not possible to add a subtree onto a subnode)
// Replace the element at the same position (unset + set is not enough because the hash array is ordered)
$aPrevList = $this->m_aClasses;
$this->m_aClasses = array();
foreach ($aPrevList as $sSomeAlias => $sSomeClass)
{
if ($sSomeAlias == $sOrigAlias)
{
$this->m_aClasses[$sNewAlias] = $sSomeClass; // note: GetFirstJoinedClass now returns '' !!!
}
else
{
$this->m_aClasses[$sSomeAlias] = $sSomeClass;
}
}
// Translate the condition expression with the new alias // Translate the condition expression with the new alias
$aAliasTranslation[$sOrigAlias]['*'] = $sNewAlias; $aAliasTranslation[$sOrigAlias]['*'] = $sNewAlias;
} }
//echo "<p>Adding the alias ".$this->GetClass()." as ".$this->GetClassAlias()."</p>\n";
// add the alias into the filter aliases list // add the alias into the filter aliases list
$aClassAliases[$this->GetFirstJoinedClassAlias()] = $this->GetFirstJoinedClass(); $aClassAliases[$this->GetClassAlias()] = $this->GetClass();
} }
foreach($this->m_aPointingTo as $sExtKeyAttCode=>$aPointingTo) foreach($this->m_aPointingTo as $sExtKeyAttCode=>$aPointingTo)
{ {
foreach($aPointingTo as $iOperatorCode => $aFilter) foreach($aPointingTo as $iOperatorCode => $aFilter)
{ {
foreach($aFilter as $oFilter) foreach($aFilter as $sAlias => $oFilter)
{ {
$oFilter->AddToNameSpace($aClassAliases, $aAliasTranslation); $oFilter->AddToNameSpace($aClassAliases, $aAliasTranslation);
} }
@@ -676,56 +558,8 @@ class DBObjectSearch
} }
} }
// Browse the tree nodes recursively
//
protected function GetNode($sAlias)
{
if ($this->GetFirstJoinedClassAlias() == $sAlias)
{
return $this;
}
else
{
foreach($this->m_aPointingTo as $sExtKeyAttCode=>$aPointingTo)
{
foreach($aPointingTo as $iOperatorCode => $aFilter)
{
foreach($aFilter as $oFilter)
{
$ret = $oFilter->GetNode($sAlias);
if (is_object($ret))
{
return $ret;
}
}
}
}
foreach($this->m_aReferencedBy as $sForeignClass=>$aReferences)
{
foreach($aReferences as $sForeignExtKeyAttCode=>$oForeignFilter)
{
$ret = $oForeignFilter->GetNode($sAlias);
if (is_object($ret))
{
return $ret;
}
}
}
}
// Not found
return null;
}
public function AddCondition_PointingTo(DBObjectSearch $oFilter, $sExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS) public function AddCondition_PointingTo(DBObjectSearch $oFilter, $sExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS)
{ {
// Note: though it seems to be a good practice to clone the given source filter
// (as it was done and fixed an issue in MergeWith())
// this was not implemented here because it was causing a regression (login as admin, select an org, click on any badge)
// root cause: FromOQL relies on the fact that the passed filter can be modified later
// NO: $oFilter = $oFilter->DeepClone();
// See also: Trac #639, and self::AddCondition_ReferencedBy()
$aAliasTranslation = array(); $aAliasTranslation = array();
$res = $this->AddCondition_PointingTo_InNameSpace($oFilter, $sExtKeyAttCode, $this->m_aClasses, $aAliasTranslation, $iOperatorCode); $res = $this->AddCondition_PointingTo_InNameSpace($oFilter, $sExtKeyAttCode, $this->m_aClasses, $aAliasTranslation, $iOperatorCode);
$this->TransferConditionExpression($oFilter, $aAliasTranslation); $this->TransferConditionExpression($oFilter, $aAliasTranslation);
@@ -734,6 +568,7 @@ class DBObjectSearch
protected function AddCondition_PointingTo_InNameSpace(DBObjectSearch $oFilter, $sExtKeyAttCode, &$aClassAliases, &$aAliasTranslation, $iOperatorCode) protected function AddCondition_PointingTo_InNameSpace(DBObjectSearch $oFilter, $sExtKeyAttCode, &$aClassAliases, &$aAliasTranslation, $iOperatorCode)
{ {
//echo "<p style=\"color:green\">Calling: AddCondition_PointingTo_InNameSpace([<pre>".print_r($aClassAliases, true)."</pre></br>], [<pre>".print_r($aAliasTranslation, true)."</pre>]);</p>";
if (!MetaModel::IsValidKeyAttCode($this->GetClass(), $sExtKeyAttCode)) if (!MetaModel::IsValidKeyAttCode($this->GetClass(), $sExtKeyAttCode))
{ {
throw new CoreWarning("The attribute code '$sExtKeyAttCode' is not an external key of the class '{$this->GetClass()}' - the condition will be ignored"); throw new CoreWarning("The attribute code '$sExtKeyAttCode' is not an external key of the class '{$this->GetClass()}' - the condition will be ignored");
@@ -745,24 +580,44 @@ class DBObjectSearch
} }
if(($iOperatorCode != TREE_OPERATOR_EQUALS) && !($oAttExtKey instanceof AttributeHierarchicalKey)) if(($iOperatorCode != TREE_OPERATOR_EQUALS) && !($oAttExtKey instanceof AttributeHierarchicalKey))
{ {
throw new CoreException("The specified tree operator $iOperatorCode is not applicable to the key '{$this->GetClass()}::$sExtKeyAttCode', which is not a HierarchicalKey"); throw new CoreException("The specified tree operator $isOperatorCode is not applicable to the key '{$this->GetClass()}::$sExtKeyAttCode', which is not a HierarchicalKey");
} }
// Find the node on which the new tree must be attached (most of the time it is "this") $bSamePointingTo = false;
$oReceivingFilter = $this->GetNode($this->GetClassAlias()); if (array_key_exists($sExtKeyAttCode, $this->m_aPointingTo))
{
if (array_key_exists($iOperatorCode, $this->m_aPointingTo[$sExtKeyAttCode]))
{
if (array_key_exists($oFilter->GetClassAlias(), $this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode]))
{
//echo "<p style=\"color:red\">[".__LINE__."]this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][".$oFilter->GetFirstJoinedClassAlias()."]:<pre>\n".print_r($this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode], true)."</pre>;</p>";
$bSamePointingTo = true;
}
}
}
$oFilter->AddToNamespace($aClassAliases, $aAliasTranslation); //echo "<p style=\"color:red\">[".__LINE__."]Calling: AddToNameSpace([".implode(',', $aClassAliases)."], [".implode(',', $aAliasTranslation)."]);</p>";
$oReceivingFilter->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][] = $oFilter; if ($bSamePointingTo)
{
//echo "<p style=\"color:red\">[".__LINE__."]AddPointingTo: Merging filters for [$sExtKeyAttCode][$iOperatorCode][".$oFilter->GetClassAlias()."]</p>";
// Same ext key, alias and same operator, merge the filters together
// $sAlias = $oFilter->GetClassAlias();
//echo "<p style=\"color:red\">[".__LINE__."]before: AddToNameSpace(aClassAliases[<pre>\n".print_r($aClassAliases, true)."</pre>], aAliasTranslation[<pre>\n".print_r($aAliasTranslation, true)."</pre>]);</p>";
$oFilter->AddToNamespace($aClassAliases, $aAliasTranslation, true /* Don't translate the main alias */);
//echo "<p style=\"color:blue\">[".__LINE__."]after: AddToNameSpace(aClassAliases[<pre>\n".print_r($aClassAliases, true)."</pre>], aAliasTranslation[<pre>\n".print_r($aAliasTranslation, true)."</pre>]);</p>";
// $this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][$sAlias]->MergeWith($oFilter, $aClassAliases, $aAliasTranslation);
$this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][$oFilter->GetClassAlias()] = $oFilter;
}
else
{
//echo "<p style=\"color:red\">[".__LINE__."]AddPointingTo: Adding a new PointingTo filter for [$sExtKeyAttCode][$iOperatorCode][".$oFilter->GetClassAlias()."]</p>";
$oFilter->AddToNamespace($aClassAliases, $aAliasTranslation);
$this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][$oFilter->GetClassAlias()] = $oFilter;
}
} }
public function AddCondition_ReferencedBy(DBObjectSearch $oFilter, $sForeignExtKeyAttCode) public function AddCondition_ReferencedBy(DBObjectSearch $oFilter, $sForeignExtKeyAttCode)
{ {
// Note: though it seems to be a good practice to clone the given source filter
// (as it was done and fixed an issue in MergeWith())
// this was not implemented here because it was causing a regression (login as admin, select an org, click on any badge)
// root cause: FromOQL relies on the fact that the passed filter can be modified later
// NO: $oFilter = $oFilter->DeepClone();
// See also: Trac #639, and self::AddCondition_PointingTo()
$aAliasTranslation = array(); $aAliasTranslation = array();
$res = $this->AddCondition_ReferencedBy_InNameSpace($oFilter, $sForeignExtKeyAttCode, $this->m_aClasses, $aAliasTranslation); $res = $this->AddCondition_ReferencedBy_InNameSpace($oFilter, $sForeignExtKeyAttCode, $this->m_aClasses, $aAliasTranslation);
$this->TransferConditionExpression($oFilter, $aAliasTranslation); $this->TransferConditionExpression($oFilter, $aAliasTranslation);
@@ -782,26 +637,31 @@ class DBObjectSearch
{ {
throw new CoreException("The specified filter (objects referencing an object of class {$this->GetClass()}) is not compatible with the key '{$sForeignClass}::$sForeignExtKeyAttCode', which is pointing to {$oAttExtKey->GetTargetClass()}"); throw new CoreException("The specified filter (objects referencing an object of class {$this->GetClass()}) is not compatible with the key '{$sForeignClass}::$sForeignExtKeyAttCode', which is pointing to {$oAttExtKey->GetTargetClass()}");
} }
// Find the node on which the new tree must be attached (most of the time it is "this")
$oReceivingFilter = $this->GetNode($this->GetClassAlias());
if (array_key_exists($sForeignClass, $this->m_aReferencedBy) && array_key_exists($sForeignExtKeyAttCode, $this->m_aReferencedBy[$sForeignClass])) if (array_key_exists($sForeignClass, $this->m_aReferencedBy) && array_key_exists($sForeignExtKeyAttCode, $this->m_aReferencedBy[$sForeignClass]))
{ {
$oReceivingFilter->m_aReferencedBy[$sForeignClass][$sForeignExtKeyAttCode]->MergeWith_InNamespace($oFilter, $aClassAliases, $aAliasTranslation); $this->m_aReferencedBy[$sForeignClass][$sForeignExtKeyAttCode]->MergeWith_InNamespace($oFilter, $aClassAliases, $aAliasTranslation);
} }
else else
{ {
$oFilter->AddToNamespace($aClassAliases, $aAliasTranslation); $oFilter->AddToNamespace($aClassAliases, $aAliasTranslation);
// #@# The condition expression found in that filter should not be used - could be another kind of structure like a join spec tree !!!! // #@# The condition expression found in that filter should not be used - could be another kind of structure like a join spec tree !!!!
//$oNewFilter = $oFilter->DeepClone(); //$oNewFilter = clone $oFilter;
//$oNewFilter->ResetCondition(); //$oNewFilter->ResetCondition();
$oReceivingFilter->m_aReferencedBy[$sForeignClass][$sForeignExtKeyAttCode]= $oFilter; $this->m_aReferencedBy[$sForeignClass][$sForeignExtKeyAttCode]= $oFilter;
} }
} }
public function AddCondition_LinkedTo(DBObjectSearch $oLinkFilter, $sExtKeyAttCodeToMe, $sExtKeyAttCodeTarget, DBObjectSearch $oFilterTarget)
{
$oLinkFilterFinal = clone $oLinkFilter;
// todo : new function prototype
$oLinkFilterFinal->AddCondition_PointingTo($sExtKeyAttCodeToMe);
$this->AddCondition_ReferencedBy($oLinkFilterFinal, $sExtKeyAttCodeToMe);
}
public function AddCondition_RelatedTo(DBObjectSearch $oFilter, $sRelCode, $iMaxDepth) public function AddCondition_RelatedTo(DBObjectSearch $oFilter, $sRelCode, $iMaxDepth)
{ {
MyHelpers::CheckValueInArray('relation code', $sRelCode, MetaModel::EnumRelations()); MyHelpers::CheckValueInArray('relation code', $sRelCode, MetaModel::EnumRelations());
@@ -810,7 +670,6 @@ class DBObjectSearch
public function MergeWith($oFilter) public function MergeWith($oFilter)
{ {
$oFilter = $oFilter->DeepClone();
$aAliasTranslation = array(); $aAliasTranslation = array();
$res = $this->MergeWith_InNamespace($oFilter, $this->m_aClasses, $aAliasTranslation); $res = $this->MergeWith_InNamespace($oFilter, $this->m_aClasses, $aAliasTranslation);
$this->TransferConditionExpression($oFilter, $aAliasTranslation); $this->TransferConditionExpression($oFilter, $aAliasTranslation);
@@ -834,7 +693,7 @@ class DBObjectSearch
{ {
foreach($aPointingTo as $iOperatorCode => $aFilter) foreach($aPointingTo as $iOperatorCode => $aFilter)
{ {
foreach($aFilter as $oExtFilter) foreach($aFilter as $sAlias => $oExtFilter)
{ {
$this->AddCondition_PointingTo_InNamespace($oExtFilter, $sExtKeyAttCode, $aClassAliases, $aAliasTranslation, $iOperatorCode); $this->AddCondition_PointingTo_InNamespace($oExtFilter, $sExtKeyAttCode, $aClassAliases, $aAliasTranslation, $iOperatorCode);
} }
@@ -878,47 +737,20 @@ class DBObjectSearch
{ {
return $this->m_aRelatedTo; return $this->m_aRelatedTo;
} }
public function SetInternalParams($aParams)
{
return $this->m_aParams = $aParams;
}
public function GetInternalParams() public function GetInternalParams()
{ {
return $this->m_aParams; return $this->m_aParams;
} }
public function GetQueryParams()
{
$aParams = array();
$this->m_oSearchCondition->Render($aParams, true);
return $aParams;
}
public function ListConstantFields()
{
return $this->m_oSearchCondition->ListConstantFields();
}
public function RenderCondition() public function RenderCondition()
{ {
return $this->m_oSearchCondition->Render($this->m_aParams, false); return $this->m_oSearchCondition->Render($this->m_aParams, false);
} }
/**
* Turn the parameters (:xxx) into scalar values in order to easily
* serialize a search
*/
public function ApplyParameters($aArgs)
{
return $this->m_oSearchCondition->ApplyParameters(array_merge($this->m_aParams, $aArgs));
}
public function serialize($bDevelopParams = false, $aContextParams = null) public function serialize($bDevelopParams = false, $aContextParams = null)
{ {
$sOql = $this->ToOql($bDevelopParams, $aContextParams); $sOql = $this->ToOql($bDevelopParams, $aContextParams);
return base64_encode(serialize(array($sOql, $this->m_aParams, $this->m_aModifierProperties))); return base64_encode(serialize(array($sOql, $this->m_aParams)));
} }
static public function unserialize($sValue) static public function unserialize($sValue)
@@ -929,9 +761,7 @@ class DBObjectSearch
// We've tried to use gzcompress/gzuncompress, but for some specific queries // We've tried to use gzcompress/gzuncompress, but for some specific queries
// it was not working at all (See Trac #193) // it was not working at all (See Trac #193)
// gzuncompress was issuing a warning "data error" and the return object was null // gzuncompress was issuing a warning "data error" and the return object was null
$oRetFilter = self::FromOQL($sOql, $aParams); return self::FromOQL($sOql, $aParams);
$oRetFilter->m_aModifierProperties = $aData[2];
return $oRetFilter;
} }
// SImple BUt Structured Query Languag - SubuSQL // SImple BUt Structured Query Languag - SubuSQL
@@ -1027,7 +857,6 @@ class DBObjectSearch
{ {
$aParams = array_merge($aContextParams, $this->m_aParams); $aParams = array_merge($aContextParams, $this->m_aParams);
} }
$aParams = MetaModel::PrepareQueryArguments($aParams);
} }
else else
{ {
@@ -1038,7 +867,7 @@ class DBObjectSearch
$sSelectedClasses = implode(', ', array_keys($this->m_aSelectedClasses)); $sSelectedClasses = implode(', ', array_keys($this->m_aSelectedClasses));
$sRes = 'SELECT '.$sSelectedClasses.' FROM'; $sRes = 'SELECT '.$sSelectedClasses.' FROM';
$sRes .= ' '.$this->GetFirstJoinedClass().' AS '.$this->GetFirstJoinedClassAlias(); $sRes .= ' '.$this->GetClass().' AS '.$this->GetClassAlias();
$sRes .= $this->ToOQL_Joins(); $sRes .= $this->ToOQL_Joins();
$sRes .= " WHERE ".$this->m_oSearchCondition->Render($aParams, $bRetrofitParams); $sRes .= " WHERE ".$this->m_oSearchCondition->Render($aParams, $bRetrofitParams);
@@ -1057,7 +886,7 @@ class DBObjectSearch
{ {
foreach($aPointingTo as $iOperatorCode => $aFilter) foreach($aPointingTo as $iOperatorCode => $aFilter)
{ {
foreach($aFilter as $oFilter) foreach($aFilter as $sAlias => $oFilter)
{ {
switch($iOperatorCode) switch($iOperatorCode)
{ {
@@ -1098,7 +927,7 @@ class DBObjectSearch
break; break;
} }
$sRes .= ' JOIN '.$oFilter->GetFirstJoinedClass().' AS '.$oFilter->GetFirstJoinedClassAlias().' ON '.$this->GetFirstJoinedClassAlias().'.'.$sExtKey.$sOperator.$oFilter->GetFirstJoinedClassAlias().'.id'; $sRes .= ' JOIN '.$oFilter->GetClass().' AS '.$oFilter->GetClassAlias().' ON '.$this->GetClassAlias().'.'.$sExtKey.$sOperator.$oFilter->GetClassAlias().'.id';
$sRes .= $oFilter->ToOQL_Joins(); $sRes .= $oFilter->ToOQL_Joins();
} }
} }
@@ -1107,7 +936,7 @@ class DBObjectSearch
{ {
foreach($aReferences as $sForeignExtKeyAttCode=>$oForeignFilter) foreach($aReferences as $sForeignExtKeyAttCode=>$oForeignFilter)
{ {
$sRes .= ' JOIN '.$oForeignFilter->GetFirstJoinedClass().' AS '.$oForeignFilter->GetFirstJoinedClassAlias().' ON '.$oForeignFilter->GetFirstJoinedClassAlias().'.'.$sForeignExtKeyAttCode.' = '.$this->GetFirstJoinedClassAlias().'.id'; $sRes .= ' JOIN '.$oForeignFilter->GetClass().' AS '.$oForeignFilter->GetClassAlias().' ON '.$oForeignFilter->GetClassAlias().'.'.$sForeignExtKeyAttCode.' = '.$this->GetClassAlias().'.id';
$sRes .= $oForeignFilter->ToOQL_Joins(); $sRes .= $oForeignFilter->ToOQL_Joins();
} }
} }
@@ -1232,12 +1061,7 @@ class DBObjectSearch
if ($bOQLCacheEnabled && array_key_exists($sQuery, self::$m_aOQLQueries)) if ($bOQLCacheEnabled && array_key_exists($sQuery, self::$m_aOQLQueries))
{ {
// hit! // hit!
$oClone = self::$m_aOQLQueries[$sQuery]->DeepClone(); return clone self::$m_aOQLQueries[$sQuery];
if (!is_null($aParams))
{
$oClone->m_aParams = $aParams;
}
return $oClone;
} }
$oOql = new OqlInterpreter($sQuery); $oOql = new OqlInterpreter($sQuery);
@@ -1248,7 +1072,7 @@ class DBObjectSearch
if (!MetaModel::IsValidClass($sClass)) if (!MetaModel::IsValidClass($sClass))
{ {
throw new UnknownClassOqlException($sQuery, $oOqlQuery->GetClassDetails(), MetaModel::GetClasses()); throw new OqlNormalizeException('Unknown class', $sQuery, $oOqlQuery->GetClassDetails(), MetaModel::GetClasses());
} }
$oResultFilter = new DBObjectSearch($sClass, $sClassAlias); $oResultFilter = new DBObjectSearch($sClass, $sClassAlias);
@@ -1268,7 +1092,7 @@ class DBObjectSearch
$sJoinClassAlias = $oJoinSpec->GetClassAlias(); $sJoinClassAlias = $oJoinSpec->GetClassAlias();
if (!MetaModel::IsValidClass($sJoinClass)) if (!MetaModel::IsValidClass($sJoinClass))
{ {
throw new UnknownClassOqlException($sQuery, $oJoinSpec->GetClassDetails(), MetaModel::GetClasses()); throw new OqlNormalizeException('Unknown class', $sQuery, $oJoinSpec->GetClassDetails(), MetaModel::GetClasses());
} }
if (array_key_exists($sJoinClassAlias, $aAliases)) if (array_key_exists($sJoinClassAlias, $aAliases))
{ {
@@ -1382,7 +1206,7 @@ class DBObjectSearch
if ($bOQLCacheEnabled) if ($bOQLCacheEnabled)
{ {
self::$m_aOQLQueries[$sQuery] = $oResultFilter->DeepClone(); self::$m_aOQLQueries[$sQuery] = clone $oResultFilter;
} }
return $oResultFilter; return $oResultFilter;

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Object set management * Object set management
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
@@ -42,7 +41,7 @@ class DBObjectSet
public function __construct(DBObjectSearch $oFilter, $aOrderBy = array(), $aArgs = array(), $aExtendedDataSpec = null, $iLimitCount = 0, $iLimitStart = 0) public function __construct(DBObjectSearch $oFilter, $aOrderBy = array(), $aArgs = array(), $aExtendedDataSpec = null, $iLimitCount = 0, $iLimitStart = 0)
{ {
$this->m_oFilter = $oFilter->DeepClone(); $this->m_oFilter = $oFilter;
$this->m_aAddedIds = array(); $this->m_aAddedIds = array();
$this->m_aOrderBy = $aOrderBy; $this->m_aOrderBy = $aOrderBy;
$this->m_aArgs = $aArgs; $this->m_aArgs = $aArgs;
@@ -270,18 +269,14 @@ class DBObjectSet
public function GetFilter() public function GetFilter()
{ {
// Make sure that we carry on the parameters of the set with the filter
$oFilter = $this->m_oFilter->DeepClone();
// Note: the arguments found within a set can be object (but not in a filter)
// That's why PrepareQueryArguments must be invoked there
$oFilter->SetInternalParams(array_merge($oFilter->GetInternalParams(), MetaModel::PrepareQueryArguments($this->m_aArgs)));
if (count($this->m_aAddedIds) == 0) if (count($this->m_aAddedIds) == 0)
{ {
return $oFilter; return $this->m_oFilter;
} }
else else
{ {
$oFilter = clone $this->m_oFilter;
$oIdListExpr = ListExpression::FromScalars(array_keys($this->m_aAddedIds)); $oIdListExpr = ListExpression::FromScalars(array_keys($this->m_aAddedIds));
$oIdExpr = new FieldExpression('id', $oFilter->GetClassAlias()); $oIdExpr = new FieldExpression('id', $oFilter->GetClassAlias());
$oIdInList = new BinaryExpression($oIdExpr, 'IN', $oIdListExpr); $oIdInList = new BinaryExpression($oIdExpr, 'IN', $oIdListExpr);
@@ -295,11 +290,6 @@ class DBObjectSet
return $this->m_oFilter->GetClass(); return $this->m_oFilter->GetClass();
} }
public function GetClassAlias()
{
return $this->m_oFilter->GetClassAlias();
}
public function GetSelectedClasses() public function GetSelectedClasses()
{ {
return $this->m_oFilter->GetSelectedClasses(); return $this->m_oFilter->GetSelectedClasses();
@@ -321,19 +311,6 @@ class DBObjectSet
$this->m_iLimitStart = $iLimitStart; $this->m_iLimitStart = $iLimitStart;
} }
public function SetOrderBy($aOrderBy)
{
if ($this->m_aOrderBy != $aOrderBy)
{
$this->m_aOrderBy = $aOrderBy;
if ($this->m_bLoaded)
{
$this->m_bLoaded = false;
$this->Load();
}
}
}
public function GetLimitCount() public function GetLimitCount()
{ {
return $this->m_iLimitCount; return $this->m_iLimitCount;
@@ -344,20 +321,6 @@ class DBObjectSet
return $this->m_iLimitStart; return $this->m_iLimitStart;
} }
public function GetRealSortOrder()
{
// Get the class default sort order if not specified with the API
//
if (empty($this->m_aOrderBy))
{
return MetaModel::GetOrderByDefault($this->m_oFilter->GetClass());
}
else
{
return $this->m_aOrderBy;
}
}
public function Load() public function Load()
{ {
if ($this->m_bLoaded) return; if ($this->m_bLoaded) return;
@@ -366,11 +329,11 @@ class DBObjectSet
if ($this->m_iLimitCount > 0) if ($this->m_iLimitCount > 0)
{ {
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->GetRealSortOrder(), $this->m_aArgs, $this->m_aAttToLoad, $this->m_aExtendedDataSpec, $this->m_iLimitCount, $this->m_iLimitStart); $sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs, $this->m_aAttToLoad, $this->m_aExtendedDataSpec, $this->m_iLimitCount, $this->m_iLimitStart);
} }
else else
{ {
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->GetRealSortOrder(), $this->m_aArgs, $this->m_aAttToLoad, $this->m_aExtendedDataSpec); $sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs, $this->m_aAttToLoad, $this->m_aExtendedDataSpec);
} }
$resQuery = CMDBSource::Query($sSQL); $resQuery = CMDBSource::Query($sSQL);
if (!$resQuery) return; if (!$resQuery) return;
@@ -407,7 +370,7 @@ class DBObjectSet
{ {
if (is_null($this->m_iCount)) if (is_null($this->m_iCount))
{ {
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, array(), $this->m_aArgs, null, null, 0, 0, true); $sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs, null, null, 0, 0, true);
$resQuery = CMDBSource::Query($sSQL); $resQuery = CMDBSource::Query($sSQL);
if (!$resQuery) return 0; if (!$resQuery) return 0;
@@ -724,56 +687,6 @@ class DBObjectSet
$this->Rewind(); $this->Rewind();
return $oCommonObj; return $oCommonObj;
} }
/**
* List the constant fields (and their value) in the given query
* @return Hash [Alias][AttCode] => value
*/
public function ListConstantFields()
{
$aScalarArgs = $this->ExpandArgs();
$aConst = $this->m_oFilter->ListConstantFields();
foreach($aConst as $sClassAlias => $aVals)
{
foreach($aVals as $sCode => $oExpr)
{
if ($oExpr instanceof ScalarExpression)
{
$aConst[$sClassAlias][$sCode] = $oExpr->GetValue();
}
else //Variable
{
$aConst[$sClassAlias][$sCode] = $aScalarArgs[$oExpr->GetName()];
}
}
}
return $aConst;
}
protected function ExpandArgs()
{
$aScalarArgs = $this->m_oFilter->GetInternalParams();
foreach($this->m_aArgs as $sArgName => $value)
{
if (MetaModel::IsValidObject($value))
{
$aScalarArgs = array_merge($aScalarArgs, $value->ToArgs($sArgName));
}
else
{
$aScalarArgs[$sArgName] = (string) $value;
}
}
$aScalarArgs['current_contact_id'] = UserRights::GetContactId();
return $aScalarArgs;
}
public function ApplyParameters()
{
$aScalarArgs = $this->ExpandArgs();
$this->m_oFilter->ApplyParameters($aScalarArgs);
}
} }
/** /**

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Database properties - manage database instances in a complex installation * Database properties - manage database instances in a complex installation
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Algorithm to delete object(s) and maintain data integrity * Class dbObject: the root of persistent classes
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
class DeleteException extends CoreException class DeleteException extends CoreException
@@ -82,9 +81,6 @@ class DeletionPlan
public function ComputeResults() public function ComputeResults()
{ {
$this->m_iToDelete = 0;
$this->m_iToUpdate = 0;
foreach($this->m_aToDelete as $sClass => $aToDelete) foreach($this->m_aToDelete as $sClass => $aToDelete)
{ {
foreach($aToDelete as $iId => $aData) foreach($aToDelete as $iId => $aData)

View File

@@ -1,27 +1,27 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Class Dict * Class Dict
* Management of localizable strings * Management of localizable strings
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
class DictException extends CoreException class DictException extends CoreException
@@ -120,7 +120,7 @@ class Dict
} }
public static function S($sStringCode, $sDefault = null, $bUserLanguageOnly = false) public static function S($sStringCode, $sDefault = null)
{ {
// Attempt to find the string in the user language // Attempt to find the string in the user language
// //
@@ -134,22 +134,19 @@ class Dict
{ {
return $aCurrentDictionary[$sStringCode]; return $aCurrentDictionary[$sStringCode];
} }
if (!$bUserLanguageOnly) // Attempt to find the string in the default language
//
$aDefaultDictionary = self::$m_aData[self::$m_sDefaultLanguage];
if (array_key_exists($sStringCode, $aDefaultDictionary))
{ {
// Attempt to find the string in the default language return $aDefaultDictionary[$sStringCode];
// }
$aDefaultDictionary = self::$m_aData[self::$m_sDefaultLanguage]; // Attempt to find the string in english
if (array_key_exists($sStringCode, $aDefaultDictionary)) //
{ $aDefaultDictionary = self::$m_aData['EN US'];
return $aDefaultDictionary[$sStringCode]; if (array_key_exists($sStringCode, $aDefaultDictionary))
} {
// Attempt to find the string in english return $aDefaultDictionary[$sStringCode];
//
$aDefaultDictionary = self::$m_aData['EN US'];
if (array_key_exists($sStringCode, $aDefaultDictionary))
{
return $aDefaultDictionary[$sStringCode];
}
} }
// Could not find the string... // Could not find the string...
// //
@@ -223,20 +220,6 @@ class Dict
} }
} }
/**
* Clone a string in every language (if it exists in that language)
*/
public static function CloneString($sSourceCode, $sDestCode)
{
foreach(self::$m_aLanguages as $sLanguageCode => $foo)
{
if (isset(self::$m_aData[$sLanguageCode][$sSourceCode]))
{
self::$m_aData[$sLanguageCode][$sDestCode] = self::$m_aData[$sLanguageCode][$sSourceCode];
}
}
}
public static function MakeStats($sLanguageCode, $sLanguageRef = 'EN US') public static function MakeStats($sLanguageCode, $sLanguageRef = 'EN US')
{ {
$aMissing = array(); // Strings missing for the target language $aMissing = array(); // Strings missing for the target language

View File

@@ -1,150 +1,66 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Send an email (abstraction for synchronous/asynchronous modes) * Send an mail (for notification, testing,... purposes)
* #@# TODO - replace by a more sophisticated mean (and update the prototype)
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once(APPROOT.'/lib/swiftmailer/lib/swift_required.php');
Swift_Preferences::getInstance()->setCharset('UTF-8');
define ('EMAIL_SEND_OK', 0); define ('EMAIL_SEND_OK', 0);
define ('EMAIL_SEND_PENDING', 1); define ('EMAIL_SEND_PENDING', 1);
define ('EMAIL_SEND_ERROR', 2); define ('EMAIL_SEND_ERROR', 2);
class EMail class EMail
{ {
// Serialization formats protected $m_sBody;
const ORIGINAL_FORMAT = 1; // Original format, consisting in serializing the whole object, inculding the Swift Mailer's object. protected $m_sSubject;
// Did not work with attachements since their binary representation cannot be stored as a valid UTF-8 string protected $m_sTo;
const FORMAT_V2 = 2; // New format, only the raw data are serialized (base64 encoded if needed) protected $m_aHeaders; // array of key=>value
protected $m_aAttachments;
protected static $m_oConfig = null;
protected $m_aData; // For storing data to serialize
public function LoadConfig($sConfigFile = ITOP_DEFAULT_CONFIG_FILE) public function __construct($sTo = '', $sSubject = '', $sBody = '', $aHeaders = array())
{ {
if (is_null(self::$m_oConfig)) $this->m_sTo = $sTo;
{ $this->m_sSubject = $sSubject;
self::$m_oConfig = new Config($sConfigFile); $this->m_sBody = $sBody;
} $this->m_aHeaders = $aHeaders;
$this->m_aAttachments = array();
} }
protected $m_oMessage; // Errors management : not that simple because we need that function to be
// executed in the background, while making sure that any issue would be reported clearly
protected $m_aMailErrors; //array of strings explaining the issues
public function __construct() public function mail_error_handler($errno, $errstr, $errfile, $errline)
{ {
$this->m_aData = array(); $sCleanMessage= str_replace("mail() [<a href='function.mail'>function.mail</a>]: ", "", $errstr);
$this->m_oMessage = Swift_Message::newInstance(); $this->m_aMailErrors[] = $sCleanMessage;
$oEncoder = new Swift_Mime_ContentEncoder_PlainContentEncoder('8bit');
$this->m_oMessage->setEncoder($oEncoder);
} }
/**
* Custom serialization method
* No longer use the brute force "serialize" method since
* 1) It does not work with binary attachments (since they cannot be stored in a UTF-8 text field)
* 2) The size tends to be quite big (sometimes ten times the size of the email)
*/
public function SerializeV2()
{
return serialize($this->m_aData);
}
/**
* Custom de-serialization method
* @param string $sSerializedMessage The serialized representation of the message
*/
static public function UnSerializeV2($sSerializedMessage)
{
$aData = unserialize($sSerializedMessage);
$oMessage = new Email();
if (array_key_exists('body', $aData))
{
$oMessage->SetBody($aData['body']['body'], $aData['body']['mimeType']);
}
if (array_key_exists('message_id', $aData))
{
$oMessage->SetMessageId($aData['message_id']);
}
if (array_key_exists('bcc', $aData))
{
$oMessage->SetRecipientBCC($aData['bcc']);
}
if (array_key_exists('cc', $aData))
{
$oMessage->SetRecipientCC($aData['cc']);
}
if (array_key_exists('from', $aData))
{
$oMessage->SetRecipientFrom($aData['from']['address'], $aData['from']['label']);
}
if (array_key_exists('reply_to', $aData))
{
$oMessage->SetRecipientReplyTo($aData['reply_to']);
}
if (array_key_exists('to', $aData))
{
$oMessage->SetRecipientTO($aData['to']);
}
if (array_key_exists('subject', $aData))
{
$oMessage->SetSubject($aData['subject']);
}
if (array_key_exists('headers', $aData))
{
foreach($aData['headers'] as $sKey => $sValue)
{
$oMessage->AddToHeader($sKey, $sValue);
}
}
if (array_key_exists('parts', $aData))
{
foreach($aData['parts'] as $aPart)
{
$oMessage->AddPart($aPart['text'], $aPart['mimeType']);
}
}
if (array_key_exists('attachments', $aData))
{
foreach($aData['attachments'] as $aAttachment)
{
$oMessage->AddAttachment(base64_decode($aAttachment['data']), $aAttachment['filename'], $aAttachment['mimeType']);
}
}
return $oMessage;
}
protected function SendAsynchronous(&$aIssues, $oLog = null) protected function SendAsynchronous(&$aIssues, $oLog = null)
{ {
try try
{ {
AsyncSendEmail::AddToQueue($this, $oLog); AsyncSendEmail::AddToQueue($this->m_sTo, $this->m_sSubject, $this->m_sBody, $this->m_aHeaders, $oLog);
} }
catch(Exception $e) catch(Exception $e)
{ {
@@ -157,37 +73,40 @@ class EMail
protected function SendSynchronous(&$aIssues, $oLog = null) protected function SendSynchronous(&$aIssues, $oLog = null)
{ {
$this->LoadConfig(); $sHeaders = 'MIME-Version: 1.0' . "\r\n";
// ! the case is important for MS-Outlook
$sTransport = self::$m_oConfig->Get('email_transport'); if (!array_key_exists('Content-Type', $this->m_aHeaders))
switch ($sTransport)
{ {
case 'SMTP': $sHeaders .= 'Content-Type: text/html; charset=UTF-8' . "\r\n";
$sHost = self::$m_oConfig->Get('email_transport_smtp.host'); }
$sPort = self::$m_oConfig->Get('email_transport_smtp.port'); if (!array_key_exists('Content-Transfer-Encoding', $this->m_aHeaders))
$sEncryption = self::$m_oConfig->Get('email_transport_smtp.encryption'); {
$sUserName = self::$m_oConfig->Get('email_transport_smtp.username'); $sHeaders .= 'Content-Transfer-Encoding: 8bit' . "\r\n";
$sPassword = self::$m_oConfig->Get('email_transport_smtp.password'); }
foreach ($this->m_aHeaders as $sKey => $sValue)
$oTransport = Swift_SmtpTransport::newInstance($sHost, $sPort, $sEncryption); {
if (strlen($sUserName) > 0) $sHeaders .= "$sKey: $sValue\r\n";
{
$oTransport->setUsername($sUserName);
$oTransport->setPassword($sPassword);
}
break;
case 'PHPMail':
default:
$oTransport = Swift_MailTransport::newInstance();
} }
$oMailer = Swift_Mailer::newInstance($oTransport); // Under Windows (not yet proven for Linux/PHP) mail may issue a warning
// that I could not mask (tried error_reporting(), etc.)
$iSent = $oMailer->send($this->m_oMessage); $this->m_aMailErrors = array();
if ($iSent === 0) set_error_handler(array($this, 'mail_error_handler'));
$bRes = mail
(
str_replace(array("\n", "\r"), ' ', $this->m_sTo), // Prevent header injection
str_replace(array("\n", "\r"), ' ', $this->m_sSubject), // Prevent header injection
$this->m_sBody,
$sHeaders
);
restore_error_handler();
if (!$bRes && empty($this->m_aMailErrors))
{ {
$aIssues = array('No valid recipient for this message.'); $this->m_aMailErrors[] = 'Unknown reason';
}
if (count($this->m_aMailErrors) > 0)
{
$aIssues = $this->m_aMailErrors;
return EMAIL_SEND_ERROR; return EMAIL_SEND_ERROR;
} }
else else
@@ -199,6 +118,7 @@ class EMail
public function Send(&$aIssues, $bForceSynchronous = false, $oLog = null) public function Send(&$aIssues, $bForceSynchronous = false, $oLog = null)
{ {
$this->BuildMessage(); // assemble the attachments into the header/body structure
if ($bForceSynchronous) if ($bForceSynchronous)
{ {
return $this->SendSynchronous($aIssues, $oLog); return $this->SendSynchronous($aIssues, $oLog);
@@ -217,175 +137,89 @@ class EMail
} }
} }
public function AddToHeader($sKey, $sValue) protected function AddToHeader($sKey, $sValue)
{ {
if (!array_key_exists('headers', $this->m_aData))
{
$this->m_aData['headers'] = array();
}
$this->m_aData['headers'][$sKey] = $sValue;
if (strlen($sValue) > 0) if (strlen($sValue) > 0)
{ {
$oHeaders = $this->m_oMessage->getHeaders(); $this->m_aHeaders[$sKey] = $sValue;
switch(strtolower($sKey))
{
default:
$oHeaders->addTextHeader($sKey, $sValue);
}
} }
} }
public function SetMessageId($sId)
{
$this->m_aData['message_id'] = $sId;
// Note: Swift will add the angle brackets for you
// so let's remove the angle brackets if present, for historical reasons
$sId = str_replace(array('<', '>'), '', $sId);
$oMsgId = $this->m_oMessage->getHeaders()->get('Message-ID');
$oMsgId->SetId($sId);
}
public function SetReferences($sReferences) public function SetReferences($sReferences)
{ {
$this->AddToHeader('References', $sReferences); $this->AddToHeader('References', $sReferences);
} }
public function SetBody($sBody, $sMimeType = 'text/html') public function SetBody($sBody)
{ {
$this->m_aData['body'] = array('body' => $sBody, 'mimeType' => $sMimeType); $this->m_sBody = $sBody;
$this->m_oMessage->setBody($sBody, $sMimeType);
} }
public function AddPart($sText, $sMimeType = 'text/html') public function SetSubject($aSubject)
{ {
if (!array_key_exists('parts', $this->m_aData)) $this->m_sSubject = $aSubject;
{
$this->m_aData['parts'] = array();
}
$this->m_aData['parts'][] = array('text' => $sText, 'mimeType' => $sMimeType);
$this->m_oMessage->addPart($sText, $sMimeType);
} }
public function AddAttachment($data, $sFileName, $sMimeType)
{
if (!array_key_exists('attachments', $this->m_aData))
{
$this->m_aData['attachments'] = array();
}
$this->m_aData['attachments'][] = array('data' => base64_encode($data), 'filename' => $sFileName, 'mimeType' => $sMimeType);
$this->m_oMessage->attach(Swift_Attachment::newInstance($data, $sFileName, $sMimeType));
}
public function SetSubject($sSubject)
{
$this->m_aData['subject'] = $sSubject;
$this->m_oMessage->setSubject($sSubject);
}
public function GetSubject()
{
return $this->m_oMessage->getSubject();
}
/**
* Helper to transform and sanitize addresses
* - get rid of empty addresses
*/
protected function AddressStringToArray($sAddressCSVList)
{
$aAddresses = array();
foreach(explode(',', $sAddressCSVList) as $sAddress)
{
$sAddress = trim($sAddress);
if (strlen($sAddress) > 0)
{
$aAddresses[] = $sAddress;
}
}
return $aAddresses;
}
public function SetRecipientTO($sAddress) public function SetRecipientTO($sAddress)
{ {
$this->m_aData['to'] = $sAddress; $this->m_sTo = $sAddress;
if (!empty($sAddress))
{
$aAddresses = $this->AddressStringToArray($sAddress);
$this->m_oMessage->setTo($aAddresses);
}
}
public function GetRecipientTO($bAsString = false)
{
$aRes = $this->m_oMessage->getTo();
if ($bAsString)
{
$aStrings = array();
foreach ($aRes as $sEmail => $sName)
{
if (is_null($sName))
{
$aStrings[] = $sEmail;
}
else
{
$sName = str_replace(array('<', '>'), '', $sName);
$aStrings[] = "$sName <$sEmail>";
}
}
return implode(', ', $aStrings);
}
else
{
return $aRes;
}
} }
public function SetRecipientCC($sAddress) public function SetRecipientCC($sAddress)
{ {
$this->m_aData['cc'] = $sAddress; $this->AddToHeader('Cc', $sAddress);
if (!empty($sAddress))
{
$aAddresses = $this->AddressStringToArray($sAddress);
$this->m_oMessage->setCc($aAddresses);
}
} }
public function SetRecipientBCC($sAddress) public function SetRecipientBCC($sAddress)
{ {
$this->m_aData['bcc'] = $sAddress; $this->AddToHeader('Bcc', $sAddress);
if (!empty($sAddress))
{
$aAddresses = $this->AddressStringToArray($sAddress);
$this->m_oMessage->setBcc($aAddresses);
}
} }
public function SetRecipientFrom($sAddress, $sLabel = '') public function SetRecipientFrom($sAddress)
{ {
$this->m_aData['from'] = array('address' => $sAddress, 'label' => $sLabel); $this->AddToHeader('From', $sAddress);
if ($sLabel != '')
{ // This is required on Windows because otherwise I would get the error
$this->m_oMessage->setFrom(array($sAddress => $sLabel)); // "sendmail_from" not set in php.ini" even if it is correctly working
} // (apparently, once it worked the SMTP server won't claim anymore for it)
else if (!empty($sAddress)) ini_set("sendmail_from", $sAddress);
{
$this->m_oMessage->setFrom($sAddress);
}
} }
public function SetRecipientReplyTo($sAddress) public function SetRecipientReplyTo($sAddress)
{ {
$this->m_aData['reply_to'] = $sAddress; $this->AddToHeader('Reply-To', $sAddress);
if (!empty($sAddress))
{
$this->m_oMessage->setReplyTo($sAddress);
}
} }
public function AddAttachment($data, $sFileName, $sMimeType)
{
$this->m_aAttachments[] = array('data' => $data, 'filename' => $sFileName, 'mimeType' => $sMimeType);
}
/**
* Takes care of the attachments (if any) to build the header/body of the message before storing or sending it
*/
protected function BuildMessage()
{
if (count($this->m_aAttachments) == 0) return; // Nothing to do if there are no attachments
$sDelimiter = '== iTopEmailPart---'.md5(date('r', time()))." ==";
$sContentType = isset($this->m_aHeaders['Content-Type']) ? $this->m_aHeaders['Content-Type'] : 'text/html';
$sContentHeader = "Content-Type: $sContentType\r\n";
$this->m_aHeaders['Content-Type'] = "multipart/mixed; boundary=\"{$sDelimiter}\"";
$aAttachments = array();
foreach($this->m_aAttachments as $aAttach)
{
$sAttachmentHeader = "Content-Type: {$aAttach['mimeType']};\r\n Name=\"{$aAttach['filename']}\"\r\n";
$sAttachmentHeader .= "Content-Transfer-Encoding: base64\r\nContent-Disposition: attachment;\r\n filename=\"{$aAttach['filename']}\"\r\n";
$sAttachmentHeader .= "\r\n";
$sAttachment = chunk_split(base64_encode($aAttach['data']));
$aAttachments[] = $sAttachmentHeader.$sAttachment."\r\n";
}
$this->m_sBody = "This is a multi-part message in MIME format.\r\n--".$sDelimiter."\r\n".$sContentHeader."\r\n".$this->m_sBody."\r\n--".$sDelimiter."\r\n";
$this->m_sBody .= implode("--".$sDelimiter."\r\n", $aAttachments);
$this->m_sBody .= "--".$sDelimiter."--";
}
} }
?> ?>

View File

@@ -1,29 +1,28 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* 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-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
class Event extends DBObject implements iDisplay class Event extends DBObject implements iDisplay
@@ -41,7 +40,6 @@ class Event extends DBObject implements iDisplay
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "realclass", "db_finalclass_field" => "realclass",
"display_template" => "", "display_template" => "",
"order_by_default" => array('date' => false)
); );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
//MetaModel::Init_InheritAttributes(); //MetaModel::Init_InheritAttributes();
@@ -105,7 +103,7 @@ class Event extends DBObject implements iDisplay
$this->DisplayBareProperties($oPage, $bEditMode); $this->DisplayBareProperties($oPage, $bEditMode);
} }
function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $sPrefix = '', $aExtraParams = array()) function DisplayBareProperties(WebPage $oPage, $bEditMode = false, $aExtraParams = array())
{ {
if ($bEditMode) return; // Not editable if ($bEditMode) return; // Not editable
@@ -136,7 +134,6 @@ class EventNotification extends Event
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
"display_template" => "", "display_template" => "",
"order_by_default" => array('date' => false)
); );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes(); MetaModel::Init_InheritAttributes();
@@ -169,7 +166,6 @@ class EventNotificationEmail extends EventNotification
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
"display_template" => "", "display_template" => "",
"order_by_default" => array('date' => false)
); );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes(); MetaModel::Init_InheritAttributes();
@@ -178,12 +174,11 @@ class EventNotificationEmail extends EventNotification
MetaModel::Init_AddAttribute(new AttributeText("bcc", array("allowed_values"=>null, "sql"=>"bcc", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeText("bcc", array("allowed_values"=>null, "sql"=>"bcc", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("from", array("allowed_values"=>null, "sql"=>"from", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeText("from", array("allowed_values"=>null, "sql"=>"from", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeText("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeText("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeHTML("body", array("allowed_values"=>null, "sql"=>"body", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeText("body", array("allowed_values"=>null, "sql"=>"body", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeTable("attachments", array("allowed_values"=>null, "sql"=>"attachments", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
// Display lists // Display lists
MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'message', 'trigger_id', 'action_id', 'object_id', 'to', 'cc', 'bcc', 'from', 'subject', 'body', 'attachments')); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('details', array('date', 'userinfo', 'message', 'trigger_id', 'action_id', 'object_id', 'to', 'cc', 'bcc', 'from', 'subject', 'body')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('date', 'message', 'to', 'subject', 'attachments')); // Attributes to be displayed for a list MetaModel::Init_SetZListItems('list', array('date', 'message', 'to', 'subject')); // 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
@@ -207,7 +202,6 @@ class EventIssue extends Event
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
"display_template" => "", "display_template" => "",
"order_by_default" => array('date' => false)
); );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes(); MetaModel::Init_InheritAttributes();
@@ -307,7 +301,6 @@ class EventWebService extends Event
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
"display_template" => "", "display_template" => "",
"order_by_default" => array('date' => false)
); );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes(); MetaModel::Init_InheritAttributes();
@@ -342,28 +335,19 @@ class EventLoginUsage extends Event
"db_table" => "priv_event_loginusage", "db_table" => "priv_event_loginusage",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
"order_by_default" => array('date' => false)
); );
MetaModel::Init_Params($aParams); MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes(); MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
$aZList = array('date', 'user_id'); MetaModel::Init_AddAttribute(new AttributeExternalField("contact_name", array("allowed_values"=>null, "extkey_attcode"=>"user_id", "target_attcode"=>"contactid", "is_null_allowed"=>true, "depends_on"=>array())));
if (MetaModel::IsValidAttCode('Contact', 'name')) MetaModel::Init_AddAttribute(new AttributeExternalField("contact_email", array("allowed_values"=>null, "extkey_attcode"=>"user_id", "target_attcode"=>"email", "is_null_allowed"=>true, "depends_on"=>array())));
{
MetaModel::Init_AddAttribute(new AttributeExternalField("contact_name", array("allowed_values"=>null, "extkey_attcode"=>"user_id", "target_attcode"=>"contactid", "is_null_allowed"=>true, "depends_on"=>array())));
$aZList[] = 'contact_name';
}
if (MetaModel::IsValidAttCode('Contact', 'email'))
{
MetaModel::Init_AddAttribute(new AttributeExternalField("contact_email", array("allowed_values"=>null, "extkey_attcode"=>"user_id", "target_attcode"=>"email", "is_null_allowed"=>true, "depends_on"=>array())));
$aZList[] = 'contact_email';
}
// Display lists // Display lists
MetaModel::Init_SetZListItems('details', array_merge($aZList, array('userinfo', 'message'))); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('details', array('date', 'user_id', 'contact_name', 'contact_email', 'userinfo', 'message')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array_merge($aZList, array('userinfo'))); // Attributes to be displayed for a list MetaModel::Init_SetZListItems('list', array('date', 'user_id', 'contact_name', 'contact_email', 'userinfo')); // Attributes to be displayed for a list
// Search criteria // Search criteria
MetaModel::Init_SetZListItems('standard_search', $aZList); // Criteria of the std search form MetaModel::Init_SetZListItems('standard_search', array('date', 'user_id', 'contact_name', 'contact_email')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form // MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
} }
} }

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* General definition of an expression tree (could be OQL, SQL or whatever) * General definition of an expression tree (could be OQL, SQL or whatever)
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
class MissingQueryArgument extends CoreException class MissingQueryArgument extends CoreException
@@ -37,19 +36,11 @@ abstract class Expression
// recursive rendering (aArgs used as input by default, or used as output if bRetrofitParams set to True // recursive rendering (aArgs used as input by default, or used as output if bRetrofitParams set to True
abstract public function Render(&$aArgs = null, $bRetrofitParams = false); abstract public function Render(&$aArgs = null, $bRetrofitParams = false);
abstract public function ApplyParameters($aArgs);
// recursively builds an array of class => fieldname // recursively builds an array of class => fieldname
abstract public function ListRequiredFields(); abstract public function ListRequiredFields();
// recursively list field parents ($aTable = array of sParent => dummy)
abstract public function CollectUsedParents(&$aTable);
abstract public function IsTrue(); abstract public function IsTrue();
// recursively builds an array of [classAlias][fieldName] => value
abstract public function ListConstantFields();
public function RequiresField($sClass, $sFieldName) public function RequiresField($sClass, $sFieldName)
{ {
// #@# todo - optimize : this is called quite often when building a single query ! // #@# todo - optimize : this is called quite often when building a single query !
@@ -95,19 +86,6 @@ abstract class Expression
} }
abstract public function RenameParam($sOldName, $sNewName); abstract public function RenameParam($sOldName, $sNewName);
/**
* Make the most relevant label, given the value of the expression
*
* @param DBObjectSearch oFilter The context in which this expression has been used
* @param string sValue The value returned by the query, for this expression
* @param string sDefault The default value if no relevant label could be computed
* @return The label
*/
public function MakeValueLabel($oFilter, $sValue, $sDefault)
{
return $sDefault;
}
} }
class SQLExpression extends Expression class SQLExpression extends Expression
@@ -130,10 +108,6 @@ class SQLExpression extends Expression
return $this->m_sSQL; return $this->m_sSQL;
} }
public function ApplyParameters($aArgs)
{
}
public function GetUnresolvedFields($sAlias, &$aUnresolved) public function GetUnresolvedFields($sAlias, &$aUnresolved)
{ {
} }
@@ -147,15 +121,6 @@ class SQLExpression extends Expression
{ {
return array(); return array();
} }
public function CollectUsedParents(&$aTable)
{
}
public function ListConstantFields()
{
return array();
}
public function RenameParam($sOldName, $sNewName) public function RenameParam($sOldName, $sNewName)
{ {
@@ -199,11 +164,11 @@ class BinaryExpression extends Expression
// return true if we are certain that it will be true // return true if we are certain that it will be true
if ($this->m_sOperator == 'AND') if ($this->m_sOperator == 'AND')
{ {
if ($this->m_oLeftExpr->IsTrue() && $this->m_oRightExpr->IsTrue()) return true; if ($this->m_oLeftExpr->IsTrue() && $this->m_oLeftExpr->IsTrue()) return true;
} }
return false; return false;
} }
public function GetLeftExpr() public function GetLeftExpr()
{ {
return $this->m_oLeftExpr; return $this->m_oLeftExpr;
@@ -227,27 +192,7 @@ class BinaryExpression extends Expression
$sRight = $this->GetRightExpr()->Render($aArgs, $bRetrofitParams); $sRight = $this->GetRightExpr()->Render($aArgs, $bRetrofitParams);
return "($sLeft $sOperator $sRight)"; return "($sLeft $sOperator $sRight)";
} }
public function ApplyParameters($aArgs)
{
if ($this->m_oLeftExpr instanceof VariableExpression)
{
$this->m_oLeftExpr = $this->m_oLeftExpr->GetAsScalar($aArgs);
}
else //if ($this->m_oLeftExpr instanceof Expression)
{
$this->m_oLeftExpr->ApplyParameters($aArgs);
}
if ($this->m_oRightExpr instanceof VariableExpression)
{
$this->m_oRightExpr = $this->m_oRightExpr->GetAsScalar($aArgs);
}
else //if ($this->m_oRightExpr instanceof Expression)
{
$this->m_oRightExpr->ApplyParameters($aArgs);
}
}
public function GetUnresolvedFields($sAlias, &$aUnresolved) public function GetUnresolvedFields($sAlias, &$aUnresolved)
{ {
$this->GetLeftExpr()->GetUnresolvedFields($sAlias, $aUnresolved); $this->GetLeftExpr()->GetUnresolvedFields($sAlias, $aUnresolved);
@@ -267,49 +212,6 @@ class BinaryExpression extends Expression
$aRight = $this->GetRightExpr()->ListRequiredFields(); $aRight = $this->GetRightExpr()->ListRequiredFields();
return array_merge($aLeft, $aRight); return array_merge($aLeft, $aRight);
} }
public function CollectUsedParents(&$aTable)
{
$this->GetLeftExpr()->CollectUsedParents($aTable);
$this->GetRightExpr()->CollectUsedParents($aTable);
}
/**
* List all constant expression of the form <field> = <scalar> or <field> = :<variable>
* Could be extended to support <field> = <function><constant_expression>
*/
public function ListConstantFields()
{
$aResult = array();
if ($this->m_sOperator == '=')
{
if (($this->m_oLeftExpr instanceof FieldExpression) && ($this->m_oRightExpr instanceof ScalarExpression))
{
$aResult[$this->m_oLeftExpr->GetParent()][$this->m_oLeftExpr->GetName()] = $this->m_oRightExpr;
}
else if (($this->m_oRightExpr instanceof FieldExpression) && ($this->m_oLeftExpr instanceof ScalarExpression))
{
$aResult[$this->m_oRightExpr->GetParent()][$this->m_oRightExpr->GetName()] = $this->m_oLeftExpr;
}
else if (($this->m_oLeftExpr instanceof FieldExpression) && ($this->m_oRightExpr instanceof VariableExpression))
{
$aResult[$this->m_oLeftExpr->GetParent()][$this->m_oLeftExpr->GetName()] = $this->m_oRightExpr;
}
else if (($this->m_oRightExpr instanceof FieldExpression) && ($this->m_oLeftExpr instanceof VariableExpression))
{
$aResult[$this->m_oRightExpr->GetParent()][$this->m_oRightExpr->GetName()] = $this->m_oLeftExpr;
}
else
{
$aResult = array_merge($this->m_oRightExpr->ListConstantFields(), $this->m_oLeftExpr->ListConstantFields()) ;
}
}
else
{
$aResult = array_merge($this->m_oRightExpr->ListConstantFields(), $this->m_oLeftExpr->ListConstantFields()) ;
}
return $aResult;
}
public function RenameParam($sOldName, $sNewName) public function RenameParam($sOldName, $sNewName)
{ {
@@ -342,13 +244,18 @@ class UnaryExpression extends Expression
// recursive rendering // recursive rendering
public function Render(&$aArgs = null, $bRetrofitParams = false) public function Render(&$aArgs = null, $bRetrofitParams = false)
{ {
return CMDBSource::Quote($this->m_value); if ($bRetrofitParams)
{
$iParamIndex = count($aArgs) + 1; // 1-based indexation
$aArgs['param'.$iParamIndex] = $this->m_value;
return ':param'.$iParamIndex;
}
else
{
return CMDBSource::Quote($this->m_value);
}
} }
public function ApplyParameters($aArgs)
{
}
public function GetUnresolvedFields($sAlias, &$aUnresolved) public function GetUnresolvedFields($sAlias, &$aUnresolved)
{ {
} }
@@ -362,15 +269,6 @@ class UnaryExpression extends Expression
{ {
return array(); return array();
} }
public function CollectUsedParents(&$aTable)
{
}
public function ListConstantFields()
{
return array();
}
public function RenameParam($sOldName, $sNewName) public function RenameParam($sOldName, $sNewName)
{ {
@@ -383,26 +281,12 @@ class ScalarExpression extends UnaryExpression
{ {
public function __construct($value) public function __construct($value)
{ {
if (!is_scalar($value) && !is_null($value)) if (!is_scalar($value))
{ {
throw new CoreException('Attempt to create a scalar expression from a non scalar', array('var_type'=>gettype($value))); throw new CoreException('Attempt to create a scalar expression from a non scalar', array('var_type'=>gettype($value)));
} }
parent::__construct($value); parent::__construct($value);
} }
// recursive rendering
public function Render(&$aArgs = null, $bRetrofitParams = false)
{
if (is_null($this->m_value))
{
$sRet = 'NULL';
}
else
{
$sRet = CMDBSource::Quote($this->m_value);
}
return $sRet;
}
} }
class TrueExpression extends ScalarExpression class TrueExpression extends ScalarExpression
@@ -468,11 +352,6 @@ class FieldExpression extends UnaryExpression
return array($this->m_sParent.'.'.$this->m_sName); return array($this->m_sParent.'.'.$this->m_sName);
} }
public function CollectUsedParents(&$aTable)
{
$aTable[$this->m_sParent] = true;
}
public function GetUnresolvedFields($sAlias, &$aUnresolved) public function GetUnresolvedFields($sAlias, &$aUnresolved)
{ {
if ($this->m_sParent == $sAlias) if ($this->m_sParent == $sAlias)
@@ -480,12 +359,6 @@ class FieldExpression extends UnaryExpression
// Add a reference to the field // Add a reference to the field
$aUnresolved[$this->m_sName] = $this; $aUnresolved[$this->m_sName] = $this;
} }
elseif ($sAlias == '')
{
// An empty alias means "any alias"
// In such a case, the results are indexed differently
$aUnresolved[$this->m_sParent][$this->m_sName] = $this;
}
} }
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true) public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
@@ -520,52 +393,6 @@ class FieldExpression extends UnaryExpression
} }
return $oRet; return $oRet;
} }
/**
* Make the most relevant label, given the value of the expression
*
* @param DBObjectSearch oFilter The context in which this expression has been used
* @param string sValue The value returned by the query, for this expression
* @param string sDefault The default value if no relevant label could be computed
* @return The label
*/
public function MakeValueLabel($oFilter, $sValue, $sDefault)
{
$sAttCode = $this->GetName();
$sParentAlias = $this->GetParent();
$aSelectedClasses = $oFilter->GetSelectedClasses();
$sClass = $aSelectedClasses[$sParentAlias];
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
// Set a default value for the general case
$sRes = $oAttDef->GetAsHtml($sValue);
// Exceptions...
if ($oAttDef->IsExternalKey())
{
$sObjClass = $oAttDef->GetTargetClass();
$iObjKey = (int)$sValue;
if ($iObjKey > 0)
{
$oObject = MetaModel::GetObject($sObjClass, $iObjKey);
$sRes = $oObject->GetHyperlink();
}
else
{
// Undefined
$sRes = DBObject::MakeHyperLink($sObjClass, 0);
}
}
elseif ($oAttDef->IsExternalField())
{
if (is_null($sValue))
{
$sRes = Dict::S('UI:UndefinedObject');
}
}
return $sRes;
}
} }
// Has been resolved into an SQL expression // Has been resolved into an SQL expression
@@ -613,12 +440,12 @@ class VariableExpression extends UnaryExpression
} }
elseif ($bRetrofitParams) elseif ($bRetrofitParams)
{ {
$aArgs[$this->m_sName] = null; //$aArgs[$this->m_sName] = null;
return ':'.$this->m_sName; return ':'.$this->m_sName;
} }
else else
{ {
throw new MissingQueryArgument('Missing query argument', array('expecting'=>$this->m_sName, 'available'=>array_keys($aArgs))); throw new MissingQueryArgument('Missing query argument', array('expecting'=>$this->m_sName, 'available'=>$aArgs));
} }
} }
@@ -629,20 +456,6 @@ class VariableExpression extends UnaryExpression
$this->m_sName = $sNewName; $this->m_sName = $sNewName;
} }
} }
public function GetAsScalar($aArgs)
{
$value = '';
if (array_key_exists($this->m_sName, $aArgs))
{
$value = $aArgs[$this->m_sName];
}
else
{
throw new MissingQueryArgument('Missing query argument', array('expecting'=>$this->m_sName, 'available'=>array_keys($aArgs)));
}
return new ScalarExpression($value);
}
} }
// Temporary, until we implement functions and expression casting! // Temporary, until we implement functions and expression casting!
@@ -688,22 +501,6 @@ class ListExpression extends Expression
return '('.implode(', ', $aRes).')'; return '('.implode(', ', $aRes).')';
} }
public function ApplyParameters($aArgs)
{
$aRes = array();
foreach ($this->m_aExpressions as $idx => $oExpr)
{
if ($oExpr instanceof VariableExpression)
{
$this->m_aExpressions[$idx] = $oExpr->GetAsScalar();
}
else
{
$oExpr->ApplyParameters($aArgs);
}
}
}
public function GetUnresolvedFields($sAlias, &$aUnresolved) public function GetUnresolvedFields($sAlias, &$aUnresolved)
{ {
foreach ($this->m_aExpressions as $oExpr) foreach ($this->m_aExpressions as $oExpr)
@@ -732,24 +529,6 @@ class ListExpression extends Expression
return $aRes; return $aRes;
} }
public function CollectUsedParents(&$aTable)
{
foreach ($this->m_aExpressions as $oExpr)
{
$oExpr->CollectUsedParents($aTable);
}
}
public function ListConstantFields()
{
$aRes = array();
foreach ($this->m_aExpressions as $oExpr)
{
$aRes = array_merge($aRes, $oExpr->ListConstantFields());
}
return $aRes;
}
public function RenameParam($sOldName, $sNewName) public function RenameParam($sOldName, $sNewName)
{ {
$aRes = array(); $aRes = array();
@@ -799,22 +578,6 @@ class FunctionExpression extends Expression
return $this->m_sVerb.'('.implode(', ', $aRes).')'; return $this->m_sVerb.'('.implode(', ', $aRes).')';
} }
public function ApplyParameters($aArgs)
{
$aRes = array();
foreach ($this->m_aArgs as $idx => $oExpr)
{
if ($oExpr instanceof VariableExpression)
{
$this->m_aArgs[$idx] = $oExpr->GetAsScalar($aArgs);
}
else
{
$oExpr->ApplyParameters($aArgs);
}
}
}
public function GetUnresolvedFields($sAlias, &$aUnresolved) public function GetUnresolvedFields($sAlias, &$aUnresolved)
{ {
foreach ($this->m_aArgs as $oExpr) foreach ($this->m_aArgs as $oExpr)
@@ -843,70 +606,13 @@ class FunctionExpression extends Expression
return $aRes; return $aRes;
} }
public function CollectUsedParents(&$aTable)
{
foreach ($this->m_aArgs as $oExpr)
{
$oExpr->CollectUsedParents($aTable);
}
}
public function ListConstantFields()
{
$aRes = array();
foreach ($this->m_aArgs as $oExpr)
{
$aRes = array_merge($aRes, $oExpr->ListConstantFields());
}
return $aRes;
}
public function RenameParam($sOldName, $sNewName) public function RenameParam($sOldName, $sNewName)
{ {
foreach ($this->m_aArgs as $key => $oExpr) foreach ($this->m_aArgs as $key => $oExpr)
{ {
$this->m_aArgs[$key] = $oExpr->RenameParam($sOldName, $sNewName); $this->m_aArgs[$key] = $oExpr->RenameParam($sOldName, $sNewName);
} }
} }
/**
* Make the most relevant label, given the value of the expression
*
* @param DBObjectSearch oFilter The context in which this expression has been used
* @param string sValue The value returned by the query, for this expression
* @param string sDefault The default value if no relevant label could be computed
* @return The label
*/
public function MakeValueLabel($oFilter, $sValue, $sDefault)
{
$sRes = $sDefault;
if (strtolower($this->m_sVerb) == 'date_format')
{
$oFormatExpr = $this->m_aArgs[1];
if ($oFormatExpr->Render() == "'%w'")
{
static $aWeekDayToString = null;
if (is_null($aWeekDayToString))
{
// Init the correspondance table
$aWeekDayToString = array(
0 => Dict::S('DayOfWeek-Sunday'),
1 => Dict::S('DayOfWeek-Monday'),
2 => Dict::S('DayOfWeek-Tuesday'),
3 => Dict::S('DayOfWeek-Wednesday'),
4 => Dict::S('DayOfWeek-Thursday'),
5 => Dict::S('DayOfWeek-Friday'),
6 => Dict::S('DayOfWeek-Saturday')
);
}
if (isset($aWeekDayToString[(int)$sValue]))
{
$sRes = $aWeekDayToString[(int)$sValue];
}
}
}
return $sRes;
}
} }
class IntervalExpression extends Expression class IntervalExpression extends Expression
@@ -942,18 +648,6 @@ class IntervalExpression extends Expression
return 'INTERVAL '.$this->m_oValue->Render($aArgs, $bRetrofitParams).' '.$this->m_sUnit; return 'INTERVAL '.$this->m_oValue->Render($aArgs, $bRetrofitParams).' '.$this->m_sUnit;
} }
public function ApplyParameters($aArgs)
{
if ($this->m_oValue instanceof VariableExpression)
{
$this->m_oValue = $this->m_oValue->GetAsScalar($aArgs);
}
else
{
$this->m_oValue->ApplyParameters($aArgs);
}
}
public function GetUnresolvedFields($sAlias, &$aUnresolved) public function GetUnresolvedFields($sAlias, &$aUnresolved)
{ {
$this->m_oValue->GetUnresolvedFields($sAlias, $aUnresolved); $this->m_oValue->GetUnresolvedFields($sAlias, $aUnresolved);
@@ -968,15 +662,6 @@ class IntervalExpression extends Expression
{ {
return array(); return array();
} }
public function CollectUsedParents(&$aTable)
{
}
public function ListConstantFields()
{
return array();
}
public function RenameParam($sOldName, $sNewName) public function RenameParam($sOldName, $sNewName)
{ {
@@ -1017,22 +702,6 @@ class CharConcatExpression extends Expression
return "CAST(CONCAT(".implode(', ', $aRes).") AS CHAR)"; return "CAST(CONCAT(".implode(', ', $aRes).") AS CHAR)";
} }
public function ApplyParameters($aArgs)
{
$aRes = array();
foreach ($this->m_aExpressions as $idx => $oExpr)
{
if ($oExpr instanceof VariableExpression)
{
$this->m_aExpressions[$idx] = $oExpr->GetAsScalar();
}
else
{
$this->m_aExpressions->ApplyParameters($aArgs);
}
}
}
public function GetUnresolvedFields($sAlias, &$aUnresolved) public function GetUnresolvedFields($sAlias, &$aUnresolved)
{ {
foreach ($this->m_aExpressions as $oExpr) foreach ($this->m_aExpressions as $oExpr)
@@ -1061,24 +730,6 @@ class CharConcatExpression extends Expression
return $aRes; return $aRes;
} }
public function CollectUsedParents(&$aTable)
{
foreach ($this->m_aExpressions as $oExpr)
{
$oExpr->CollectUsedParents($aTable);
}
}
public function ListConstantFields()
{
$aRes = array();
foreach ($this->m_aExpressions as $oExpr)
{
$aRes = array_merge($aRes, $oExpr->ListConstantFields());
}
return $aRes;
}
public function RenameParam($sOldName, $sNewName) public function RenameParam($sOldName, $sNewName)
{ {
foreach ($this->m_aExpressions as $key => $oExpr) foreach ($this->m_aExpressions as $key => $oExpr)
@@ -1119,22 +770,13 @@ class QueryBuilderExpressions
{ {
protected $m_oConditionExpr; protected $m_oConditionExpr;
protected $m_aSelectExpr; protected $m_aSelectExpr;
protected $m_aGroupByExpr;
protected $m_aJoinFields; protected $m_aJoinFields;
protected $m_aClassIds;
public function __construct($oSearch, $aGroupByExpr = null) public function __construct($aSelect, $oCondition)
{ {
$this->m_oConditionExpr = $oSearch->GetCriteria(); $this->m_oConditionExpr = $oCondition;
$this->m_aSelectExpr = array(); $this->m_aSelectExpr = $aSelect;
$this->m_aGroupByExpr = $aGroupByExpr;
$this->m_aJoinFields = array(); $this->m_aJoinFields = array();
$this->m_aClassIds = array();
foreach($oSearch->GetJoinedClasses() as $sClassAlias => $sClass)
{
$this->m_aClassIds[$sClassAlias] = new FieldExpression('id', $sClassAlias);
}
} }
public function GetSelect() public function GetSelect()
@@ -1142,11 +784,6 @@ class QueryBuilderExpressions
return $this->m_aSelectExpr; return $this->m_aSelectExpr;
} }
public function GetGroupBy()
{
return $this->m_aGroupByExpr;
}
public function GetCondition() public function GetCondition()
{ {
return $this->m_oConditionExpr; return $this->m_oConditionExpr;
@@ -1173,20 +810,6 @@ class QueryBuilderExpressions
array_push($this->m_aJoinFields, $oExpression); array_push($this->m_aJoinFields, $oExpression);
} }
/**
* Get tables representing the queried objects
* Could be further optimized: when the first join is an outer join, then the rest can be omitted
*/
public function GetMandatoryTables(&$aTables = null)
{
if (is_null($aTables)) $aTables = array();
foreach($this->m_aClassIds as $sClass => $oExpression)
{
$oExpression->CollectUsedParents($aTables);
}
}
public function GetUnresolvedFields($sAlias, &$aUnresolved) public function GetUnresolvedFields($sAlias, &$aUnresolved)
{ {
$this->m_oConditionExpr->GetUnresolvedFields($sAlias, $aUnresolved); $this->m_oConditionExpr->GetUnresolvedFields($sAlias, $aUnresolved);
@@ -1194,13 +817,6 @@ class QueryBuilderExpressions
{ {
$oExpr->GetUnresolvedFields($sAlias, $aUnresolved); $oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
} }
if ($this->m_aGroupByExpr)
{
foreach($this->m_aGroupByExpr as $sColAlias => $oExpr)
{
$oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
}
}
foreach($this->m_aJoinFields as $oExpression) foreach($this->m_aJoinFields as $oExpression)
{ {
$oExpression->GetUnresolvedFields($sAlias, $aUnresolved); $oExpression->GetUnresolvedFields($sAlias, $aUnresolved);
@@ -1214,22 +830,10 @@ class QueryBuilderExpressions
{ {
$this->m_aSelectExpr[$sColAlias] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved); $this->m_aSelectExpr[$sColAlias] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
} }
if ($this->m_aGroupByExpr)
{
foreach($this->m_aGroupByExpr as $sColAlias => $oExpr)
{
$this->m_aGroupByExpr[$sColAlias] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
}
}
foreach($this->m_aJoinFields as $index => $oExpression) foreach($this->m_aJoinFields as $index => $oExpression)
{ {
$this->m_aJoinFields[$index] = $oExpression->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved); $this->m_aJoinFields[$index] = $oExpression->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
} }
foreach($this->m_aClassIds as $sClass => $oExpression)
{
$this->m_aClassIds[$sClass] = $oExpression->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
}
} }
public function RenameParam($sOldName, $sNewName) public function RenameParam($sOldName, $sNewName)
@@ -1239,13 +843,6 @@ class QueryBuilderExpressions
{ {
$this->m_aSelectExpr[$sColAlias] = $oExpr->RenameParam($sOldName, $sNewName); $this->m_aSelectExpr[$sColAlias] = $oExpr->RenameParam($sOldName, $sNewName);
} }
if ($this->m_aGroupByExpr)
{
foreach($this->m_aGroupByExpr as $sColAlias => $oExpr)
{
$this->m_aGroupByExpr[$sColAlias] = $oExpr->RenameParam($sOldName, $sNewName);
}
}
foreach($this->m_aJoinFields as $index => $oExpression) foreach($this->m_aJoinFields as $index => $oExpression)
{ {
$this->m_aJoinFields[$index] = $oExpression->RenameParam($sOldName, $sNewName); $this->m_aJoinFields[$index] = $oExpression->RenameParam($sOldName, $sNewName);

View File

@@ -1,28 +1,27 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Definition of a filter * Definition of a filter
* Most of the time, a filter corresponds to an attribute, but we could imagine other search criteria * Most of the time, a filter corresponds to an attribute, but we could imagine other search criteria
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
@@ -51,6 +50,21 @@ abstract class FilterDefinition
$this->ConsistencyCheck(); $this->ConsistencyCheck();
} }
public function OverloadParams($aParams)
{
foreach ($aParams as $sParam => $value)
{
if (!array_key_exists($sParam, $this->m_aParams))
{
throw new CoreException("Unknown attribute definition parameter '$sParam', please select a value in {".implode(", ", $this->m_aParams)."}");
}
else
{
$this->m_aParams[$sParam] = $value;
}
}
}
// to be overloaded // to be overloaded
static protected function ListExpectedParams() static protected function ListExpectedParams()
{ {
@@ -156,13 +170,12 @@ class FilterFromAttribute extends FilterDefinition
return array_merge(parent::ListExpectedParams(), array("refattribute")); return array_merge(parent::ListExpectedParams(), array("refattribute"));
} }
public function __construct($oRefAttribute, $sSuffix = '') public function __construct($oRefAttribute, $aParam = array())
{ {
// In this very specific case, the code is the one of the attribute // In this very specific case, the code is the one of the attribute
// (this to get a very very simple syntax upon declaration) // (this to get a very very simple syntax upon declaration)
$aParam = array();
$aParam["refattribute"] = $oRefAttribute; $aParam["refattribute"] = $oRefAttribute;
parent::__construct($oRefAttribute->GetCode().$sSuffix, $aParam); parent::__construct($oRefAttribute->GetCode(), $aParam);
} }
public function GetType() {return "Basic";} public function GetType() {return "Basic";}

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Measures operations duration, memory usage, etc. (and some other KPIs) * Measures operations duration, memory usage, etc. (and some other KPIs)
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
class ExecutionKPI class ExecutionKPI
@@ -192,16 +191,6 @@ class ExecutionKPI
return $output[1] * 1024; return $output[1] * 1024;
} }
} }
static public function memory_get_peak_usage($bRealUsage = false)
{
if (function_exists('memory_get_peak_usage'))
{
return memory_get_peak_usage($bRealUsage);
}
// PHP > 5.2.1 - this verb depends on a compilation option
return 0;
}
} }
class ApplicationStartupKPI extends ExecutionKPI class ApplicationStartupKPI extends ExecutionKPI

View File

@@ -1,26 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* File logging * File logging
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
class FileLog class FileLog

File diff suppressed because it is too large Load Diff

View File

@@ -1,32 +0,0 @@
<?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/>
/**
* Any extension to hook the initialization of the metamodel
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
interface iOnClassInitialization
{
public function OnAfterClassInitialization($sClass);
}
?>

View File

@@ -1,28 +1,27 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Class ModuleHandler * Class ModuleHandler
* Defines the API to implement module specific actions during page execution * Defines the API to implement module specific actions during page execution
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
abstract class ModuleHandlerAPI abstract class ModuleHandlerAPI

View File

@@ -1,27 +1,27 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* OQL syntax analyzer, to be used prior to run the lexical analyzer * OQL syntax analyzer, to be used prior to run the lexical analyzer
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
// Notes (from the source file: oql-lexer.plex) - Romain // Notes (from the source file: oql-lexer.plex) - Romain
@@ -168,7 +168,7 @@ class OQLLexerRaw
'/\GABOVE STRICT/ ', '/\GABOVE STRICT/ ',
'/\GNOT ABOVE/ ', '/\GNOT ABOVE/ ',
'/\GNOT ABOVE STRICT/ ', '/\GNOT ABOVE STRICT/ ',
'/\G(0x[0-9a-fA-F]+|[0-9]+)/ ', '/\G[0-9]+|0x[0-9a-fA-F]+/ ',
'/\G\"([^\\\\\"]|\\\\\"|\\\\\\\\)*\"|'.chr(94).chr(39).'([^\\\\'.chr(39).']|\\\\'.chr(39).'|\\\\\\\\)*'.chr(39).'/ ', '/\G\"([^\\\\\"]|\\\\\"|\\\\\\\\)*\"|'.chr(94).chr(39).'([^\\\\'.chr(39).']|\\\\'.chr(39).'|\\\\\\\\)*'.chr(39).'/ ',
'/\G([_a-zA-Z][_a-zA-Z0-9]*|`[^`]+`)/ ', '/\G([_a-zA-Z][_a-zA-Z0-9]*|`[^`]+`)/ ',
'/\G:([_a-zA-Z][_a-zA-Z0-9]*->[_a-zA-Z][_a-zA-Z0-9]*|[_a-zA-Z][_a-zA-Z0-9]*)/ ', '/\G:([_a-zA-Z][_a-zA-Z0-9]*->[_a-zA-Z][_a-zA-Z0-9]*|[_a-zA-Z][_a-zA-Z0-9]*)/ ',

View File

@@ -1,28 +1,27 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* OQL syntax analyzer, to be used prior to run the lexical analyzer * OQL syntax analyzer, to be used prior to run the lexical analyzer
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
// Notes (from the source file: oql-lexer.plex) - Romain // Notes (from the source file: oql-lexer.plex) - Romain
@@ -141,23 +140,7 @@ above = "ABOVE"
above_strict = "ABOVE STRICT" above_strict = "ABOVE STRICT"
not_above = "NOT ABOVE" not_above = "NOT ABOVE"
not_above_strict = "NOT ABOVE STRICT" not_above_strict = "NOT ABOVE STRICT"
// numval = /[0-9]+|0x[0-9a-fA-F]+/
// WARNING: there seems to be a bug in the Lexer about matching the longest pattern
// when there are alternates in the regexp.
//
// For instance:
// numval = /[0-9]+|0x[0-9a-fA-F]+/
// Does not work: SELECT Toto WHERE name = 'Text0xCTest' => Fails because 0xC is recongnized as a numval (inside the string) instead of a strval !!
//
// Inserting a ^ after the alternate (see comment at the top of this file) does not work either
// numval = /[0-9]+|'.chr(94).'0x[0-9a-fA-F]+/
// SELECT Toto WHERE name = 'Text0xCTest' => works but
// SELECT Toto WHERE id = 0xC => does not work, 'xC' is found as a name (apparently 0 is recognized as a numval and the remaining is a name !)
//
// numval = /([0-9]+|0x[0-9a-fA-F]+)/
// Does not work either, the hexadecimal numbers are not matched properly
// The following seems to work...
numval = /(0x[0-9a-fA-F]+|[0-9]+)/
strval = /"([^\\"]|\\"|\\\\)*"|'.chr(94).chr(39).'([^\\'.chr(39).']|\\'.chr(39).'|\\\\)*'.chr(39).'/ strval = /"([^\\"]|\\"|\\\\)*"|'.chr(94).chr(39).'([^\\'.chr(39).']|\\'.chr(39).'|\\\\)*'.chr(39).'/
name = /([_a-zA-Z][_a-zA-Z0-9]*|`[^`]+`)/ name = /([_a-zA-Z][_a-zA-Z0-9]*|`[^`]+`)/
varname = /:([_a-zA-Z][_a-zA-Z0-9]*->[_a-zA-Z][_a-zA-Z0-9]*|[_a-zA-Z][_a-zA-Z0-9]*)/ varname = /:([_a-zA-Z][_a-zA-Z0-9]*->[_a-zA-Z][_a-zA-Z0-9]*|[_a-zA-Z][_a-zA-Z0-9]*)/

View File

@@ -1,26 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Special handling for OQL syntax errors * Special handling for OQL syntax errors
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
@@ -50,13 +50,7 @@ class OQLException extends CoreException
parent::__construct($sMessage, 0); parent::__construct($sMessage, 0);
} }
public function GetUserFriendlyDescription() public function getHtmlDesc($sHighlightHtmlBegin = '<b>', $sHighlightHtmlEnd = '</b>')
{
// Todo - translate all errors!
return $this->getMessage();
}
public function getHtmlDesc($sHighlightHtmlBegin = '<span style="font-weight: bolder">', $sHighlightHtmlEnd = '</span>')
{ {
$sRet = htmlentities($this->m_MyIssue.", found '".$this->m_sUnexpected."' in: ", ENT_QUOTES, 'UTF-8'); $sRet = htmlentities($this->m_MyIssue.", found '".$this->m_sUnexpected."' in: ", ENT_QUOTES, 'UTF-8');
$sRet .= htmlentities(substr($this->m_sInput, 0, $this->m_iCol), ENT_QUOTES, 'UTF-8'); $sRet .= htmlentities(substr($this->m_sInput, 0, $this->m_iCol), ENT_QUOTES, 'UTF-8');
@@ -77,27 +71,7 @@ class OQLException extends CoreException
return $sRet; return $sRet;
} }
public function GetIssue() static protected function FindClosestString($sInput, $aDictionary)
{
return $this->m_MyIssue;
}
public function GetSuggestions()
{
return $this->m_aExpecting;
}
public function GetWrongWord()
{
return $this->m_sUnexpected;
}
public function GetColumn()
{
return $this->m_iCol;
}
static public function FindClosestString($sInput, $aDictionary)
{ {
// no shortest distance found, yet // no shortest distance found, yet
$fShortest = -1; $fShortest = -1;
@@ -114,7 +88,7 @@ class OQLException extends CoreException
return $sSuggestion; return $sSuggestion;
} }
if (($fDist <= 3) && ($fShortest < 0 || $fDist <= $fShortest)) if ($fShortest < 0 || ($fDist < 4 && $fDist <= $fShortest))
{ {
// set the closest match, and shortest distance // set the closest match, and shortest distance
$sRet = $sSuggestion; $sRet = $sSuggestion;

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Wrapper to execute the parser, lexical analyzer and normalization of an OQL query * Wrapper to execute the parser, lexical analyzer and normalization of an OQL query
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
@@ -32,28 +31,6 @@ class OqlNormalizeException extends OQLException
parent::__construct($sIssue, $sInput, 0, $oName->GetPos(), $oName->GetValue(), $aExpecting); parent::__construct($sIssue, $sInput, 0, $oName->GetPos(), $oName->GetValue(), $aExpecting);
} }
} }
class UnknownClassOqlException extends OqlNormalizeException
{
public function __construct($sInput, OqlName $oName, $aExpecting = null)
{
parent::__construct('Unknown class', $sInput, $oName, $aExpecting);
}
public function GetUserFriendlyDescription()
{
$sWrongClass = $this->GetWrongWord();
$sSuggest = self::FindClosestString($sWrongClass, $this->GetSuggestions());
if ($sSuggest != '')
{
return Dict::Format('UI:OQL:UnknownClassAndFix', $sWrongClass, $sSuggest);
}
else
{
return Dict::Format('UI:OQL:UnknownClassNoFix', $sWrongClass);
}
}
}
class OqlInterpreterException extends OQLException class OqlInterpreterException extends OQLException
{ {

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Classes defined for lexical analyze (see oql-parser.y) * Classes defined for lexical analyze (see oql-parser.y)
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
// Position a string within an OQL query // Position a string within an OQL query

View File

@@ -1,35 +1,31 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2011 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
define('CASELOG_VISIBLE_ITEMS', 2); define('CASELOG_VISIBLE_ITEMS', 2);
define('CASELOG_SEPARATOR', "\n".'========== %1$s : %2$s (%3$d) ============'."\n\n"); define('CASELOG_SEPARATOR', "\n".'========== %1$s : %2$s (%3$d) ============'."\n\n");
//require_once(APPROOT.'/core/userrights.class.inc.php');
//require_once(APPROOT.'/application/webpage.class.inc.php');
/** /**
* Class to store a "case log" in a structured way, keeping track of its successive entries * Class to store a "case log" in a structured way, keeping track of its successive entries
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/ */
class ormCaseLog { class ormCaseLog {
protected $m_sLog; protected $m_sLog;
protected $m_aIndex; protected $m_aIndex;
protected $m_bModified;
/** /**
* Initializes the log with the first (initial) entry * Initializes the log with the first (initial) entry
@@ -40,7 +36,6 @@ class ormCaseLog {
{ {
$this->m_sLog = $sLog; $this->m_sLog = $sLog;
$this->m_aIndex = $aIndex; $this->m_aIndex = $aIndex;
$this->m_bModified = false;
} }
public function GetText() public function GetText()
@@ -58,25 +53,13 @@ class ormCaseLog {
return $this->m_sLog; return $this->m_sLog;
} }
public function ClearModifiedFlag()
{
$this->m_bModified = false;
}
public function GetAsHTML(WebPage $oP = null, $bEditMode = false, $aTransfoHandler = null) public function GetAsHTML(WebPage $oP = null, $bEditMode = false, $aTransfoHandler = null)
{ {
$sHtml = '<table style="width:100%;table-layout:fixed"><tr><td>'; // Use table-layout:fixed to force the with to be independent from the actual content $sHtml = '<table style="width:100%;table-layout:fixed"><tr><td>'; // Use table-layout:fixed to force the with to be independent from the actual content
$iPos = 0; $iPos = 0;
$aIndex = $this->m_aIndex; for($index=count($this->m_aIndex)-1 ; $index >= 0 ; $index--)
if (($bEditMode) && (count($aIndex) > 0) && $this->m_bModified)
{ {
// Don't display the first element, that is still considered as editable if ($index < count($this->m_aIndex) - CASELOG_VISIBLE_ITEMS)
$iPos = $aIndex[0]['separator_length'] + $aIndex[0]['text_length'];
array_shift($aIndex);
}
for($index=count($aIndex)-1 ; $index >= 0 ; $index--)
{
if ($index < count($aIndex) - CASELOG_VISIBLE_ITEMS)
{ {
$sOpen = ''; $sOpen = '';
$sDisplay = 'style="display:none;"'; $sDisplay = 'style="display:none;"';
@@ -86,31 +69,31 @@ class ormCaseLog {
$sOpen = ' open'; $sOpen = ' open';
$sDisplay = ''; $sDisplay = '';
} }
$iPos += $aIndex[$index]['separator_length']; $iPos += $this->m_aIndex[$index]['separator_length'];
$sTextEntry = substr($this->m_sLog, $iPos, $aIndex[$index]['text_length']); $sTextEntry = substr($this->m_sLog, $iPos, $this->m_aIndex[$index]['text_length']);
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sTextEntry, ENT_QUOTES, 'UTF-8')); $sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sTextEntry, ENT_QUOTES, 'UTF-8'));
if (!is_null($aTransfoHandler)) if (!is_null($aTransfoHandler))
{ {
$sTextEntry = call_user_func($aTransfoHandler, $sTextEntry); $sTextEntry = call_user_func($aTransfoHandler, $sTextEntry);
} }
$iPos += $aIndex[$index]['text_length']; $iPos += $this->m_aIndex[$index]['text_length'];
$sEntry = '<div class="caselog_header'.$sOpen.'">'; $sEntry = '<div class="caselog_header'.$sOpen.'">';
// Workaround: PHP < 5.3 cannot unserialize correctly DateTime objects, // Workaround: PHP < 5.3 cannot unserialize correctly DateTime objects,
// therefore we have changed the format. To preserve the compatibility with existing // therefore we have changed the format. To preserve the compatibility with existing
// installations of iTop, both format are allowed: // installations of iTop, both format are allowed:
// the 'date' item is either a DateTime object, or a unix timestamp // the 'date' item is either a DateTime object, or a unix timestamp
if (is_int($aIndex[$index]['date'])) if (is_int($this->m_aIndex[$index]['date']))
{ {
// Unix timestamp // Unix timestamp
$sDate = date(Dict::S('UI:CaseLog:DateFormat'),$aIndex[$index]['date']); $sDate = date(Dict::S('UI:CaseLog:DateFormat'), $this->m_aIndex[$index]['date']);
} }
elseif (is_object($aIndex[$index]['date'])) elseif (is_object($this->m_aIndex[$index]['date']))
{ {
if (version_compare(phpversion(), '5.3.0', '>=')) if (version_compare(phpversion(), '5.3.0', '>='))
{ {
// DateTime // DateTime
$sDate = $aIndex[$index]['date']->format(Dict::S('UI:CaseLog:DateFormat')); $sDate = $this->m_aIndex[$index]['date']->format(Dict::S('UI:CaseLog:DateFormat'));
} }
else else
{ {
@@ -118,7 +101,7 @@ class ormCaseLog {
$sDate = ''; $sDate = '';
} }
} }
$sEntry .= sprintf(Dict::S('UI:CaseLog:Header_Date_UserName'), $sDate, $aIndex[$index]['user_name']); $sEntry .= sprintf(Dict::S('UI:CaseLog:Header_Date_UserName'), $sDate, $this->m_aIndex[$index]['user_name']);
$sEntry .= '</div>'; $sEntry .= '</div>';
$sEntry .= '<div class="caselog_entry"'.$sDisplay.'>'; $sEntry .= '<div class="caselog_entry"'.$sDisplay.'>';
$sEntry .= $sTextEntry; $sEntry .= $sTextEntry;
@@ -167,13 +150,11 @@ class ormCaseLog {
} }
/** /**
* Add a new entry to the log or merge the given text into the currently modified entry * Add a new entry to the log and updates the internal index
* and updates the internal index
* @param $sText string The text of the new entry * @param $sText string The text of the new entry
*/ */
public function AddLogEntry($sText, $sOnBehalfOf = '') public function AddLogEntry($sText, $sOnBehalfOf = '')
{ {
$bMergeEntries = false;
$sDate = date(Dict::S('UI:CaseLog:DateFormat')); $sDate = date(Dict::S('UI:CaseLog:DateFormat'));
if ($sOnBehalfOf == '') if ($sOnBehalfOf == '')
{ {
@@ -184,61 +165,17 @@ class ormCaseLog {
{ {
$iUserId = null; $iUserId = null;
} }
if ($this->m_bModified) $sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, $sOnBehalfOf, $iUserId);
{ $iSepLength = strlen($sSeparator);
$aLatestEntry = end($this->m_aIndex); $iTextlength = strlen($sText);
if ($aLatestEntry['user_name'] != $sOnBehalfOf) $this->m_sLog = $sSeparator.$sText.$this->m_sLog; // Latest entry printed first
{ $this->m_aIndex[] = array(
$bMergeEntries = false; 'user_name' => $sOnBehalfOf,
} 'user_id' => $iUserId,
else 'date' => time(),
{ 'text_length' => $iTextlength,
$bMergeEntries = true; 'separator_length' => $iSepLength,
} );
}
if ($bMergeEntries)
{
$aLatestEntry = end($this->m_aIndex);
$this->m_sLog = substr($this->m_sLog, $aLatestEntry['separator_length']);
$sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, $sOnBehalfOf, $iUserId);
$iSepLength = strlen($sSeparator);
$iTextlength = strlen($sText."\n");
$this->m_sLog = $sSeparator.$sText.$this->m_sLog; // Latest entry printed first
$this->m_aIndex[] = array(
'user_name' => $sOnBehalfOf,
'user_id' => $iUserId,
'date' => time(),
'text_length' => $aLatestEntry['text_length'] + $iTextlength,
'separator_length' => $iSepLength,
);
}
else
{
$sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, $sOnBehalfOf, $iUserId);
$iSepLength = strlen($sSeparator);
$iTextlength = strlen($sText);
$this->m_sLog = $sSeparator.$sText.$this->m_sLog; // Latest entry printed first
$this->m_aIndex[] = array(
'user_name' => $sOnBehalfOf,
'user_id' => $iUserId,
'date' => time(),
'text_length' => $iTextlength,
'separator_length' => $iSepLength,
);
}
$this->m_bModified = true;
}
public function GetModifiedEntry()
{
$sModifiedEntry = '';
if ($this->m_bModified)
{
$sModifiedEntry = $this->GetLatestEntry();
}
return $sModifiedEntry;
} }
/** /**
@@ -263,4 +200,4 @@ class ormCaseLog {
return $iLast; return $iLast;
} }
} }
?> ?>

View File

@@ -1,28 +1,27 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* ormDocument * ormDocument
* encapsulate the behavior of a binary data set that will be stored an attribute of class AttributeBlob * encapsulate the behavior of a binary data set that will be stored an attribute of class AttributeBlob
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */

View File

@@ -1,21 +1,18 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
require_once(APPROOT.'/core/simplecrypt.class.inc.php'); require_once(APPROOT.'/core/simplecrypt.class.inc.php');
@@ -26,8 +23,10 @@ require_once(APPROOT.'/core/simplecrypt.class.inc.php');
* If a cryptographic random number generator is available (on Linux or Windows) * If a cryptographic random number generator is available (on Linux or Windows)
* it will be used for generating the salt. * it will be used for generating the salt.
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
* @package itopORM * @package itopORM
*/ */

View File

@@ -1,456 +0,0 @@
<?php
// Copyright (C) 2010-2013 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
require_once('backgroundprocess.inc.php');
/**
* ormStopWatch
* encapsulate the behavior of a stop watch that will be stored as an attribute of class AttributeStopWatch
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* ormStopWatch
* encapsulate the behavior of a stop watch that will be stored as an attribute of class AttributeStopWatch
*
* @package itopORM
*/
class ormStopWatch
{
protected $iTimeSpent; // seconds
protected $iStarted; // unix time (seconds)
protected $iLastStart; // unix time (seconds)
protected $iStopped; // unix time (seconds)
protected $aThresholds;
/**
* Constructor
*/
public function __construct($iTimeSpent = 0, $iStarted = null, $iLastStart = null, $iStopped = null)
{
$this->iTimeSpent = (int) $iTimeSpent;
$this->iStarted = $iStarted;
$this->iLastStart = $iLastStart;
$this->iStopped = $iStopped;
$this->aThresholds = array();
}
/**
* Necessary for the triggers
*/
public function __toString()
{
return (string) $this->iTimeSpent;
}
public function DefineThreshold($iPercent, $tDeadline = null, $bPassed = false, $bTriggered = false, $iOverrun = null)
{
$this->aThresholds[$iPercent] = array(
'deadline' => $tDeadline, // unix time (seconds)
'passed' => $bPassed,
'triggered' => $bTriggered,
'overrun' => $iOverrun
);
}
public function MarkThresholdAsTriggered($iPercent)
{
$this->aThresholds[$iPercent]['triggered'] = true;
}
public function GetTimeSpent()
{
return $this->iTimeSpent;
}
public function GetStartDate()
{
return $this->iStarted;
}
public function GetLastStartDate()
{
return $this->iLastStart;
}
public function GetStopDate()
{
return $this->iStopped;
}
public function GetThresholdDate($iPercent)
{
if (array_key_exists($iPercent, $this->aThresholds))
{
return $this->aThresholds[$iPercent]['deadline'];
}
else
{
return null;
}
}
public function GetOverrun($iPercent)
{
if (array_key_exists($iPercent, $this->aThresholds))
{
return $this->aThresholds[$iPercent]['overrun'];
}
else
{
return null;
}
}
public function IsThresholdPassed($iPercent)
{
if (array_key_exists($iPercent, $this->aThresholds))
{
return $this->aThresholds[$iPercent]['passed'];
}
else
{
return false;
}
}
public function IsThresholdTriggered($iPercent)
{
if (array_key_exists($iPercent, $this->aThresholds))
{
return $this->aThresholds[$iPercent]['triggered'];
}
else
{
return false;
}
}
public function GetAsHTML($oAttDef, $oHostObject = null)
{
$aProperties = array();
$aProperties['States'] = implode(', ', $oAttDef->GetStates());
if (is_null($this->iLastStart))
{
if (is_null($this->iStarted))
{
$aProperties['Elapsed'] = 'never started';
}
else
{
$aProperties['Elapsed'] = $this->iTimeSpent.' s';
}
}
else
{
$aProperties['Elapsed'] = 'running <img src="../images/indicator.gif">';
}
$aProperties['Started'] = $oAttDef->SecondsToDate($this->iStarted);
$aProperties['LastStart'] = $oAttDef->SecondsToDate($this->iLastStart);
$aProperties['Stopped'] = $oAttDef->SecondsToDate($this->iStopped);
foreach ($this->aThresholds as $iPercent => $aThresholdData)
{
$sThresholdDesc = $oAttDef->SecondsToDate($aThresholdData['deadline']);
if ($aThresholdData['triggered'])
{
$sThresholdDesc .= " <b>TRIGGERED</b>";
}
if ($aThresholdData['overrun'])
{
$sThresholdDesc .= " Overrun:".(int) $aThresholdData['overrun']." sec.";
}
$aProperties[$iPercent.'%'] = $sThresholdDesc;
}
$sRes = "<TABLE>";
$sRes .= "<TBODY>";
foreach ($aProperties as $sProperty => $sValue)
{
$sRes .= "<TR>";
$sCell = str_replace("\n", "<br>\n", $sValue);
$sRes .= "<TD class=\"label\">$sProperty</TD><TD>$sCell</TD>";
$sRes .= "</TR>";
}
$sRes .= "</TBODY>";
$sRes .= "</TABLE>";
return $sRes;
}
protected function ComputeGoal($oObject, $oAttDef)
{
$sMetricComputer = $oAttDef->Get('goal_computing');
$oComputer = new $sMetricComputer();
$aCallSpec = array($oComputer, 'ComputeMetric');
if (!is_callable($aCallSpec))
{
throw new CoreException("Unknown class/verb '$sMetricComputer/ComputeMetric'");
}
$iRet = call_user_func($aCallSpec, $oObject);
return $iRet;
}
protected function ComputeDeadline($oObject, $oAttDef, $iStartTime, $iDurationSec)
{
$sWorkingTimeComputer = $oAttDef->Get('working_time_computing');
$aCallSpec = array($sWorkingTimeComputer, '__construct');
if (!is_callable($aCallSpec))
{
//throw new CoreException("Pas de constructeur pour $sWorkingTimeComputer!");
}
$oComputer = new $sWorkingTimeComputer();
$aCallSpec = array($oComputer, 'GetDeadline');
if (!is_callable($aCallSpec))
{
throw new CoreException("Unknown class/verb '$sWorkingTimeComputer/GetDeadline'");
}
// GetDeadline($oObject, $iDuration, DateTime $oStartDate)
$oStartDate = new DateTime('@'.$iStartTime); // setTimestamp not available in PHP 5.2
$oDeadline = call_user_func($aCallSpec, $oObject, $iDurationSec, $oStartDate);
$iRet = $oDeadline->format('U');
return $iRet;
}
protected function ComputeDuration($oObject, $oAttDef, $iStartTime, $iEndTime)
{
$sWorkingTimeComputer = $oAttDef->Get('working_time_computing');
$oComputer = new $sWorkingTimeComputer();
$aCallSpec = array($oComputer, 'GetOpenDuration');
if (!is_callable($aCallSpec))
{
throw new CoreException("Unknown class/verb '$sWorkingTimeComputer/GetOpenDuration'");
}
// GetOpenDuration($oObject, DateTime $oStartDate, DateTime $oEndDate)
$oStartDate = new DateTime('@'.$iStartTime); // setTimestamp not available in PHP 5.2
$oEndDate = new DateTime('@'.$iEndTime);
$iRet = call_user_func($aCallSpec, $oObject, $oStartDate, $oEndDate);
return $iRet;
}
public function Reset($oObject, $oAttDef)
{
$this->iTimeSpent = 0;
$this->iStarted = null;
$this->iLastStart = null;
$this->iStopped = null;
foreach ($this->aThresholds as $iPercent => &$aThresholdData)
{
$aThresholdData['passed'] = false;
$aThresholdData['triggered'] = false;
$aThresholdData['deadline'] = null;
$aThresholdData['overrun'] = null;
}
}
/**
* Start or continue
* It is the responsibility of the caller to compute the deadlines
* (to avoid computing twice for the same result)
*/
public function Start($oObject, $oAttDef)
{
if (!is_null($this->iLastStart))
{
// Already started
return false;
}
if (is_null($this->iStarted))
{
$this->iStarted = time();
}
$this->iLastStart = time();
$this->iStopped = null;
return true;
}
/**
* Compute or recompute the goal and threshold deadlines
*/
public function ComputeDeadlines($oObject, $oAttDef)
{
if (is_null($this->iLastStart))
{
// Currently stopped - do nothing
return false;
}
$iDurationGoal = $this->ComputeGoal($oObject, $oAttDef);
foreach ($this->aThresholds as $iPercent => &$aThresholdData)
{
if (is_null($iDurationGoal))
{
// No limit: leave null thresholds
$aThresholdData['deadline'] = null;
}
else
{
$iThresholdDuration = round($iPercent * $iDurationGoal / 100);
$aThresholdData['deadline'] = $this->ComputeDeadline($oObject, $oAttDef, $this->iLastStart, $iThresholdDuration - $this->iTimeSpent);
// OR $aThresholdData['deadline'] = $this->ComputeDeadline($oObject, $oAttDef, $this->iStarted, $iThresholdDuration);
}
if (is_null($aThresholdData['deadline']) || ($aThresholdData['deadline'] > time()))
{
// The threshold is in the future, reset
$aThresholdData['passed'] = false;
$aThresholdData['triggered'] = false;
$aThresholdData['overrun'] = null;
}
else
{
// The new threshold is in the past
$aThresholdData['passed'] = true;
// Note: the overrun can be wrong, but the correct algorithm to compute
// the overrun of a deadline in the past requires that the ormStopWatch keeps track of all its history!!!
}
}
return true;
}
/**
* Stop counting if not already done
*/
public function Stop($oObject, $oAttDef)
{
if (is_null($this->iLastStart))
{
// Already stopped
return false;
}
$iElapsed = $this->ComputeDuration($oObject, $oAttDef, $this->iLastStart, time());
$this->iTimeSpent = $this->iTimeSpent + $iElapsed;
foreach ($this->aThresholds as $iPercent => &$aThresholdData)
{
if (!is_null($aThresholdData['deadline']) && (time() > $aThresholdData['deadline']))
{
if ($aThresholdData['overrun'] > 0)
{
// Accumulate from last start
$aThresholdData['overrun'] += $iElapsed;
}
else
{
// First stop after the deadline has been passed
$iOverrun = $this->ComputeDuration($oObject, $oAttDef, $aThresholdData['deadline'], time());
$aThresholdData['overrun'] = $iOverrun;
}
$aThresholdData['passed'] = true;
}
$aThresholdData['deadline'] = null;
}
$this->iLastStart = null;
$this->iStopped = time();
return true;
}
}
/**
* CheckStopWatchThresholds
* Implements the automatic actions
*
* @package itopORM
*/
class CheckStopWatchThresholds implements iBackgroundProcess
{
public function GetPeriodicity()
{
return 10; // seconds
}
public function Process($iTimeLimit)
{
$aList = array();
foreach (MetaModel::GetClasses() as $sClass)
{
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
{
if ($oAttDef instanceof AttributeStopWatch)
{
foreach ($oAttDef->ListThresholds() as $iThreshold => $aThresholdData)
{
$iPercent = $aThresholdData['percent']; // could be different than the index !
$sNow = date('Y-m-d H:i:s');
$sExpression = "SELECT $sClass WHERE {$sAttCode}_laststart AND {$sAttCode}_{$iThreshold}_triggered = 0 AND {$sAttCode}_{$iThreshold}_deadline < '$sNow'";
$oFilter = DBObjectSearch::FromOQL($sExpression);
$oSet = new DBObjectSet($oFilter);
while ((time() < $iTimeLimit) && ($oObj = $oSet->Fetch()))
{
$sClass = get_class($oObj);
$aList[] = $sClass.'::'.$oObj->GetKey().' '.$sAttCode.' '.$iThreshold;
// Execute planned actions
//
foreach ($aThresholdData['actions'] as $aActionData)
{
$sVerb = $aActionData['verb'];
$aParams = $aActionData['params'];
$sParams = implode(', ', $aParams);
$aCallSpec = array($oObj, $sVerb);
call_user_func_array($aCallSpec, $aParams);
}
// Mark the threshold as "triggered"
//
$oSW = $oObj->Get($sAttCode);
$oSW->MarkThresholdAsTriggered($iThreshold);
$oObj->Set($sAttCode, $oSW);
if($oObj->IsModified())
{
CMDBObject::SetTrackInfo("Automatic - threshold triggered");
$oMyChange = CMDBObject::GetCurrentChange();
$oObj->DBUpdateTracked($oMyChange, true /*skip security*/);
}
// Activate any existing trigger
//
$sClassList = implode("', '", MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL));
$oTriggerSet = new DBObjectSet(
DBObjectSearch::FromOQL("SELECT TriggerOnThresholdReached AS t WHERE t.target_class IN ('$sClassList') AND stop_watch_code=:stop_watch_code AND threshold_index = :threshold_index"),
array(), // order by
array('stop_watch_code' => $sAttCode, 'threshold_index' => $iThreshold)
);
while ($oTrigger = $oTriggerSet->Fetch())
{
$oTrigger->DoActivate($oObj->ToArgs('this'));
}
}
}
}
}
}
$iProcessed = count($aList);
return "Triggered $iProcessed threshold(s):".implode(", ", $aList);
}
}

View File

@@ -1,74 +0,0 @@
<?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/>
/**
* Associated with the metamodel -> MakeQuery/MakeQuerySingleTable
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class QueryBuilderContext
{
protected $m_oRootFilter;
protected $m_aClassAliases;
protected $m_aTableAliases;
protected $m_aModifierProperties;
public $m_oQBExpressions;
public function __construct($oFilter, $aModifierProperties, $aGroupByExpr = null)
{
$this->m_oRootFilter = $oFilter;
$this->m_oQBExpressions = new QueryBuilderExpressions($oFilter, $aGroupByExpr);
$this->m_aClassAliases = $oFilter->GetJoinedClasses();
$this->m_aTableAliases = array();
$this->m_aModifierProperties = $aModifierProperties;
}
public function GetRootFilter()
{
return $this->m_oRootFilter;
}
public function GenerateTableAlias($sNewName, $sRealName)
{
return MetaModel::GenerateUniqueAlias($this->m_aTableAliases, $sNewName, $sRealName);
}
public function GenerateClassAlias($sNewName, $sRealName)
{
return MetaModel::GenerateUniqueAlias($this->m_aClassAliases, $sNewName, $sRealName);
}
public function GetModifierProperties($sPluginClass)
{
if (array_key_exists($sPluginClass, $this->m_aModifierProperties))
{
return $this->m_aModifierProperties[$sPluginClass];
}
else
{
return array();
}
}
}
?>

View File

@@ -1,34 +0,0 @@
<?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/>
/**
* Interface iQueryModifier
* Defines the API to tweak queries (e.g. translate data on the fly)
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
interface iQueryModifier
{
public function __construct();
public function GetFieldExpression(QueryBuilderContext &$oBuild, $sClass, $sAttCode, $sColId, Expression $oFieldSQLExp, SQLQuery &$oSelect);
}
?>

View File

@@ -1,595 +0,0 @@
<?php
// Copyright (C) 2013 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* REST/json services
*
* Definition of common structures + the very minimum service provider (manage objects)
*
* @package REST Services
* @copyright Copyright (C) 2013 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
* @api
*/
/**
* Element of the response formed by RestResultWithObjects
*
* @package REST Services
*/
class ObjectResult
{
public $code;
public $message;
public $fields;
/**
* Default constructor
*/
public function __construct()
{
$this->code = RestResult::OK;
$this->message = '';
$this->fields = array();
}
/**
* Helper to make an output value for a given attribute
*
* @param DBObject $oObject The object being reported
* @param string $sAttCode The attribute code (must be valid)
* @return string A scalar representation of the value
*/
protected function MakeResultValue(DBObject $oObject, $sAttCode)
{
if ($sAttCode == 'id')
{
$value = $oObject->GetKey();
}
else
{
$sClass = get_class($oObject);
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef instanceof AttributeLinkedSet)
{
$value = array();
// Make the list of required attributes
// - Skip attributes pointing to the current object (redundant data)
// - Skip link sets refering to the current data (infinite recursion!)
$aRelevantAttributes = array();
$sLnkClass = $oAttDef->GetLinkedClass();
foreach (MetaModel::ListAttributeDefs($sLnkClass) as $sLnkAttCode => $oLnkAttDef)
{
// Skip any attribute of the link that points to the current object
//
if ($sLnkAttCode == $oAttDef->GetExtKeyToMe()) continue;
if (method_exists($oLnkAttDef, 'GetKeyAttCode'))
{
if ($oLnkAttDef->GetKeyAttCode() ==$oAttDef->GetExtKeyToMe()) continue;
}
$aRelevantAttributes[] = $sLnkAttCode;
}
// Iterate on the set and build an array of array of attcode=>value
$oSet = $oObject->Get($sAttCode);
while ($oLnk = $oSet->Fetch())
{
$aLnkValues = array();
foreach ($aRelevantAttributes as $sLnkAttCode)
{
$aLnkValues[$sLnkAttCode] = $this->MakeResultValue($oLnk, $sLnkAttCode);
}
$value[] = $aLnkValues;
}
}
else
{
$value = $oAttDef->GetForJSON($oObject->Get($sAttCode));
}
}
return $value;
}
/**
* Report the value for the given object attribute
*
* @param DBObject $oObject The object being reported
* @param string $sAttCode The attribute code (must be valid)
* @return void
*/
public function AddField(DBObject $oObject, $sAttCode)
{
$this->fields[$sAttCode] = $this->MakeResultValue($oObject, $sAttCode);
}
}
/**
* REST response for services managing objects. Derive this structure to add information and/or constants
*
* @package Extensibility
* @package REST Services
* @api
*/
class RestResultWithObjects extends RestResult
{
public $objects;
/**
* Report the given object
*
* @param int An error code (RestResult::OK is no issue has been found)
* @param string $sMessage Description of the error if any, an empty string otherwise
* @param DBObject $oObject The object being reported
* @param array $aFields An array of attribute codes. List of the attributes to be reported.
* @return void
*/
public function AddObject($iCode, $sMessage, $oObject, $aFields)
{
$oObjRes = new ObjectResult();
$oObjRes->code = $iCode;
$oObjRes->message = $sMessage;
$oObjRes->class = get_class($oObject);
foreach ($aFields as $sAttCode)
{
$oObjRes->AddField($oObject, $sAttCode);
}
$sObjKey = get_class($oObject).'::'.$oObject->GetKey();
$this->objects[$sObjKey] = $oObjRes;
}
}
class RestResultWithRelations extends RestResultWithObjects
{
public $relations;
public function __construct()
{
parent::__construct();
$this->relations = array();
}
public function AddRelation($sSrcKey, $sDestKey)
{
if (!array_key_exists($sSrcKey, $this->relations))
{
$this->relations[$sSrcKey] = array();
}
$this->relations[$sSrcKey][] = array('key' => $sDestKey);
}
}
/**
* Deletion result codes for a target object (either deleted or updated)
*
* @package Extensibility
* @api
* @since 2.0.1
*/
class RestDelete
{
/**
* Result: Object deleted as per the initial request
*/
const OK = 0;
/**
* Result: general issue (user rights or ... ?)
*/
const ISSUE = 1;
/**
* Result: Must be deleted to preserve database integrity
*/
const AUTO_DELETE = 2;
/**
* Result: Must be deleted to preserve database integrity, but that is NOT possible
*/
const AUTO_DELETE_ISSUE = 3;
/**
* Result: Must be deleted to preserve database integrity, but this must be requested explicitely
*/
const REQUEST_EXPLICITELY = 4;
/**
* Result: Must be updated to preserve database integrity
*/
const AUTO_UPDATE = 5;
/**
* Result: Must be updated to preserve database integrity, but that is NOT possible
*/
const AUTO_UPDATE_ISSUE = 6;
}
/**
* Implementation of core REST services (create/get/update... objects)
*
* @package Core
*/
class CoreServices implements iRestServiceProvider
{
/**
* Enumerate services delivered by this class
*
* @param string $sVersion The version (e.g. 1.0) supported by the services
* @return array An array of hash 'verb' => verb, 'description' => description
*/
public function ListOperations($sVersion)
{
$aOps = array();
if ($sVersion == '1.0')
{
$aOps[] = array(
'verb' => 'core/create',
'description' => 'Create an object'
);
$aOps[] = array(
'verb' => 'core/update',
'description' => 'Update an object'
);
$aOps[] = array(
'verb' => 'core/apply_stimulus',
'description' => 'Apply a stimulus to change the state of an object'
);
$aOps[] = array(
'verb' => 'core/get',
'description' => 'Search for objects'
);
$aOps[] = array(
'verb' => 'core/delete',
'description' => 'Delete objects'
);
$aOps[] = array(
'verb' => 'core/get_related',
'description' => 'Get related objects through the specified relation'
);
}
return $aOps;
}
/**
* Enumerate services delivered by this class
* @param string $sVersion The version (e.g. 1.0) supported by the services
* @return RestResult The standardized result structure (at least a message)
* @throws Exception in case of internal failure.
*/
public function ExecOperation($sVersion, $sVerb, $aParams)
{
$oResult = new RestResultWithObjects();
switch ($sVerb)
{
case 'core/create':
RestUtils::InitTrackingComment($aParams);
$sClass = RestUtils::GetClass($aParams, 'class');
$aFields = RestUtils::GetMandatoryParam($aParams, 'fields');
$aShowFields = RestUtils::GetFieldList($sClass, $aParams, 'output_fields');
$oObject = RestUtils::MakeObjectFromFields($sClass, $aFields);
$oObject->DBInsert();
$oResult->AddObject(0, 'created', $oObject, $aShowFields);
break;
case 'core/update':
RestUtils::InitTrackingComment($aParams);
$sClass = RestUtils::GetClass($aParams, 'class');
$key = RestUtils::GetMandatoryParam($aParams, 'key');
$aFields = RestUtils::GetMandatoryParam($aParams, 'fields');
$aShowFields = RestUtils::GetFieldList($sClass, $aParams, 'output_fields');
$oObject = RestUtils::FindObjectFromKey($sClass, $key);
RestUtils::UpdateObjectFromFields($oObject, $aFields);
$oObject->DBUpdate();
$oResult->AddObject(0, 'updated', $oObject, $aShowFields);
break;
case 'core/apply_stimulus':
RestUtils::InitTrackingComment($aParams);
$sClass = RestUtils::GetClass($aParams, 'class');
$key = RestUtils::GetMandatoryParam($aParams, 'key');
$aFields = RestUtils::GetMandatoryParam($aParams, 'fields');
$aShowFields = RestUtils::GetFieldList($sClass, $aParams, 'output_fields');
$sStimulus = RestUtils::GetMandatoryParam($aParams, 'stimulus');
$oObject = RestUtils::FindObjectFromKey($sClass, $key);
RestUtils::UpdateObjectFromFields($oObject, $aFields);
$aTransitions = $oObject->EnumTransitions();
$aStimuli = MetaModel::EnumStimuli(get_class($oObject));
if (!isset($aTransitions[$sStimulus]))
{
// Invalid stimulus
$oResult->code = RestResult::INTERNAL_ERROR;
$oResult->message = "Invalid stimulus: '$sStimulus' on the object ".$oObject->GetName()." in state '".$oObject->GetState()."'";
}
else
{
$aTransition = $aTransitions[$sStimulus];
$sTargetState = $aTransition['target_state'];
$aStates = MetaModel::EnumStates($sClass);
$aTargetStateDef = $aStates[$sTargetState];
$aExpectedAttributes = $aTargetStateDef['attribute_list'];
$aMissingMandatory = array();
foreach($aExpectedAttributes as $sAttCode => $iExpectCode)
{
if ( ($iExpectCode & OPT_ATT_MANDATORY) && ($oObject->Get($sAttCode) == ''))
{
$aMissingMandatory[] = $sAttCode;
}
}
if (count($aMissingMandatory) == 0)
{
// If all the mandatory fields are already present, just apply the transition silently...
if ($oObject->ApplyStimulus($sStimulus))
{
$oObject->DBUpdate();
$oResult->AddObject(0, 'updated', $oObject, $aShowFields);
}
}
else
{
// Missing mandatory attributes for the transition
$oResult->code = RestResult::INTERNAL_ERROR;
$oResult->message = 'Missing mandatory attribute(s) for applying the stimulus: '.implode(', ', $aMissingMandatory).'.';
}
}
break;
case 'core/get':
$sClass = RestUtils::GetClass($aParams, 'class');
$key = RestUtils::GetMandatoryParam($aParams, 'key');
$aShowFields = RestUtils::GetFieldList($sClass, $aParams, 'output_fields');
$oObjectSet = RestUtils::GetObjectSetFromKey($sClass, $key);
while ($oObject = $oObjectSet->Fetch())
{
$oResult->AddObject(0, '', $oObject, $aShowFields);
}
$oResult->message = "Found: ".$oObjectSet->Count();
break;
case 'core/delete':
$sClass = RestUtils::GetClass($aParams, 'class');
$key = RestUtils::GetMandatoryParam($aParams, 'key');
$bSimulate = RestUtils::GetOptionalParam($aParams, 'simulate', false);
$oObjectSet = RestUtils::GetObjectSetFromKey($sClass, $key);
$aObjects = $oObjectSet->ToArray();
$this->DeleteObjects($oResult, $aObjects, $bSimulate);
break;
case 'core/get_related':
$oResult = new RestResultWithRelations();
$sClass = RestUtils::GetClass($aParams, 'class');
$key = RestUtils::GetMandatoryParam($aParams, 'key');
$sRelation = RestUtils::GetMandatoryParam($aParams, 'relation');
$iMaxRecursionDepth = RestUtils::GetOptionalParam($aParams, 'depth', 20 /* = MAX_RECURSION_DEPTH */);
$aShowFields = array('id', 'friendlyname');
$oObjectSet = RestUtils::GetObjectSetFromKey($sClass, $key);
$aIndexByClass = array();
while ($oObject = $oObjectSet->Fetch())
{
$aRelated = array();
$aGraph = array();
$aIndexByClass[get_class($oObject)][$oObject->GetKey()] = null;
$oResult->AddObject(0, '', $oObject, $aShowFields);
$this->GetRelatedObjects($oObject, $sRelation, $iMaxRecursionDepth, $aRelated, $aGraph);
foreach($aRelated as $sClass => $aObjects)
{
foreach($aObjects as $oRelatedObj)
{
$aIndexByClass[get_class($oRelatedObj)][$oRelatedObj->GetKey()] = null;
$oResult->AddObject(0, '', $oRelatedObj, $aShowFields);
}
}
foreach($aGraph as $sSrcKey => $aDestinations)
{
foreach ($aDestinations as $sDestKey)
{
$oResult->AddRelation($sSrcKey, $sDestKey);
}
}
}
if (count($aIndexByClass) > 0)
{
$aStats = array();
foreach ($aIndexByClass as $sClass => $aIds)
{
$aStats[] = $sClass.'= '.count($aIds);
}
$oResult->message = "Scope: ".$oObjectSet->Count()."; Related objects: ".implode(', ', $aStats);
}
else
{
$oResult->message = "Nothing found";
}
break;
default:
// unknown operation: handled at a higher level
}
return $oResult;
}
/**
* Helper for object deletion
*/
public function DeleteObjects($oResult, $aObjects, $bSimulate)
{
$oDeletionPlan = new DeletionPlan();
foreach($aObjects as $oObj)
{
if ($bSimulate)
{
$oObj->CheckToDelete($oDeletionPlan);
}
else
{
$oObj->DBDelete($oDeletionPlan);
}
}
foreach ($oDeletionPlan->ListDeletes() as $sTargetClass => $aDeletes)
{
foreach ($aDeletes as $iId => $aData)
{
$oToDelete = $aData['to_delete'];
$bAutoDel = (($aData['mode'] == DEL_SILENT) || ($aData['mode'] == DEL_AUTO));
if (array_key_exists('issue', $aData))
{
if ($bAutoDel)
{
if (isset($aData['requested_explicitely'])) // i.e. in the initial list of objects to delete
{
$iCode = RestDelete::ISSUE;
$sPlanned = 'Cannot be deleted: '.$aData['issue'];
}
else
{
$iCode = RestDelete::AUTO_DELETE_ISSUE;
$sPlanned = 'Should be deleted automatically... but: '.$aData['issue'];
}
}
else
{
$iCode = RestDelete::REQUEST_EXPLICITELY;
$sPlanned = 'Must be deleted explicitely... but: '.$aData['issue'];
}
}
else
{
if ($bAutoDel)
{
if (isset($aData['requested_explicitely']))
{
$iCode = RestDelete::OK;
$sPlanned = '';
}
else
{
$iCode = RestDelete::AUTO_DELETE;
$sPlanned = 'Deleted automatically';
}
}
else
{
$iCode = RestDelete::REQUEST_EXPLICITELY;
$sPlanned = 'Must be deleted explicitely';
}
}
$oResult->AddObject($iCode, $sPlanned, $oToDelete, array('id', 'friendlyname'));
}
}
foreach ($oDeletionPlan->ListUpdates() as $sRemoteClass => $aToUpdate)
{
foreach ($aToUpdate as $iId => $aData)
{
$oToUpdate = $aData['to_reset'];
if (array_key_exists('issue', $aData))
{
$iCode = RestDelete::AUTO_UPDATE_ISSUE;
$sPlanned = 'Should be updated automatically... but: '.$aData['issue'];
}
else
{
$iCode = RestDelete::AUTO_UPDATE;
$sPlanned = 'Reset external keys: '.$aData['attributes_list'];
}
$oResult->AddObject($iCode, $sPlanned, $oToUpdate, array('id', 'friendlyname'));
}
}
if ($oDeletionPlan->FoundStopper())
{
if ($oDeletionPlan->FoundSecurityIssue())
{
$iRes = RestResult::UNAUTHORIZED;
$sRes = 'Deletion not allowed on some objects';
}
elseif ($oDeletionPlan->FoundManualOperation())
{
$iRes = RestResult::UNSAFE;
$sRes = 'The deletion requires that other objects be deleted/updated, and those operations must be requested explicitely';
}
else
{
$iRes = RestResult::INTERNAL_ERROR;
$sRes = 'Some issues have been encountered. See the list of planned changes for more information about the issue(s).';
}
}
else
{
$iRes = RestResult::OK;
$sRes = 'Deleted: '.count($aObjects);
$iIndirect = $oDeletionPlan->GetTargetCount() - count($aObjects);
if ($iIndirect > 0)
{
$sRes .= ' plus (for DB integrity) '.$iIndirect;
}
}
$oResult->code = $iRes;
if ($bSimulate)
{
$oResult->message = 'SIMULATING: '.$sRes;
}
else
{
$oResult->message = $sRes;
}
}
/**
* Helper function to get the related objects up to the given depth along with the "graph" of the relation
* @param DBObject $oObject Starting point of the computation
* @param string $sRelation Code of the relation (i.e; 'impact', 'depends on'...)
* @param integer $iMaxRecursionDepth Maximum level of recursion
* @param Hash $aRelated Two dimensions hash of the already related objects: array( 'class' => array(key => ))
* @param Hash $aGraph Hash array for the topology of the relation: source => related: array('class:key' => array( DBObjects ))
* @param integer $iRecursionDepth Current level of recursion
*/
protected function GetRelatedObjects(DBObject $oObject, $sRelation, $iMaxRecursionDepth, &$aRelated, &$aGraph, $iRecursionDepth = 1)
{
// Avoid loops
if ((array_key_exists(get_class($oObject), $aRelated)) && (array_key_exists($oObject->GetKey(), $aRelated[get_class($oObject)]))) return;
// Stop at maximum recursion level
if ($iRecursionDepth > $iMaxRecursionDepth) return;
$sSrcKey = get_class($oObject).'::'.$oObject->GetKey();
$aNewRelated = array();
$oObject->GetRelatedObjects($sRelation, 1, $aNewRelated);
foreach($aNewRelated as $sClass => $aObjects)
{
if (!array_key_exists($sSrcKey, $aGraph))
{
$aGraph[$sSrcKey] = array();
}
foreach($aObjects as $oRelatedObject)
{
$aRelated[$sClass][$oRelatedObject->GetKey()] = $oRelatedObject;
$aGraph[$sSrcKey][] = get_class($oRelatedObject).'::'.$oRelatedObject->GetKey();
$this->GetRelatedObjects($oRelatedObject, $sRelation, $iMaxRecursionDepth, $aRelated, $aGraph, $iRecursionDepth+1);
}
}
}
}

View File

@@ -1,20 +1,18 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* SimpleCrypt Class - crypto helpers * SimpleCrypt Class - crypto helpers
@@ -36,9 +34,12 @@
* A string encrypted with one engine can't be decrypted with * A string encrypted with one engine can't be decrypted with
* a different one even if the key is the same. * a different one even if the key is the same.
* *
* @author Miguel Ros <rossoft@gmail.com> * @author Miguel Ros <rossoft@gmail.com>
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @version 0.3
* @license GPL
*/ */
class SimpleCrypt class SimpleCrypt
@@ -220,16 +221,9 @@ class SimpleCryptMcryptEngine implements CryptEngine
{ {
$iv = substr($encrypted_data, 0, mcrypt_enc_get_iv_size($this->td)); $iv = substr($encrypted_data, 0, mcrypt_enc_get_iv_size($this->td));
$string = substr($encrypted_data, mcrypt_enc_get_iv_size($this->td)); $string = substr($encrypted_data, mcrypt_enc_get_iv_size($this->td));
$r = mcrypt_generic_init($this->td, $key, $iv); mcrypt_generic_init($this->td, $key, $iv);
if (($r < 0) || ($r === false)) $decrypted_data = rtrim(mdecrypt_generic($this->td, $string), "\0");
{ mcrypt_generic_deinit($this->td);
$decrypted_data = '** decryption error **';
}
else
{
$decrypted_data = rtrim(mdecrypt_generic($this->td, $string), "\0");
mcrypt_generic_deinit($this->td);
}
return $decrypted_data; return $decrypted_data;
} }

View File

@@ -1,28 +1,27 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* SQLQuery * SQLQuery
* build an mySQL compatible SQL query * build an mySQL compatible SQL query
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
@@ -42,13 +41,11 @@ class SQLQuery
private $m_sTable = ''; private $m_sTable = '';
private $m_sTableAlias = ''; private $m_sTableAlias = '';
private $m_aFields = array(); private $m_aFields = array();
private $m_aGroupBy = array();
private $m_oConditionExpr = null; private $m_oConditionExpr = null;
private $m_bToDelete = true; // The current table must be listed for deletion ? private $m_bToDelete = true; // The current table must be listed for deletion ?
private $m_aValues = array(); // Values to set in case of an update query private $m_aValues = array(); // Values to set in case of an update query
private $m_oSelectedIdField = null; private $m_oSelectedIdField = null;
private $m_aJoinSelects = array(); private $m_aJoinSelects = array();
private $m_bBeautifulQuery = false;
public function __construct($sTable, $sTableAlias, $aFields, $bToDelete = true, $aValues = array(), $oSelectedIdField = null) public function __construct($sTable, $sTableAlias, $aFields, $bToDelete = true, $aValues = array(), $oSelectedIdField = null)
{ {
@@ -65,26 +62,12 @@ class SQLQuery
$this->m_sTable = $sTable; $this->m_sTable = $sTable;
$this->m_sTableAlias = $sTableAlias; $this->m_sTableAlias = $sTableAlias;
$this->m_aFields = $aFields; $this->m_aFields = $aFields;
$this->m_aGroupBy = null;
$this->m_oConditionExpr = null; $this->m_oConditionExpr = null;
$this->m_bToDelete = $bToDelete; $this->m_bToDelete = $bToDelete;
$this->m_aValues = $aValues; $this->m_aValues = $aValues;
$this->m_oSelectedIdField = $oSelectedIdField; $this->m_oSelectedIdField = $oSelectedIdField;
} }
/**
* Perform a deep clone (as opposed to "clone" which does copy a reference to the underlying objects
**/
public function DeepClone()
{
return unserialize(serialize($this));
}
public function GetTableAlias()
{
return $this->m_sTableAlias;
}
public function SetSourceOQL($sOQL) public function SetSourceOQL($sOQL)
{ {
$this->m_SourceOQL = $sOQL; $this->m_SourceOQL = $sOQL;
@@ -118,31 +101,21 @@ class SQLQuery
{ {
$sJoinType = $aJoinInfo["jointype"]; $sJoinType = $aJoinInfo["jointype"];
$oSQLQuery = $aJoinInfo["select"]; $oSQLQuery = $aJoinInfo["select"];
if (isset($aJoinInfo["on_expression"])) $sLeftField = $aJoinInfo["leftfield"];
{ $sRightField = $aJoinInfo["rightfield"];
$sOnCondition = $aJoinInfo["on_expression"]->Render(); $sRightTableAlias = $aJoinInfo["righttablealias"];
echo "<li>Join '$sJoinType', ON ($sOnCondition)".$oSQLQuery->DisplayHtml()."</li>\n"; echo "<li>Join '$sJoinType', $sLeftField, $sRightTableAlias.$sRightField".$oSQLQuery->DisplayHtml()."</li>\n";
}
else
{
$sLeftField = $aJoinInfo["leftfield"];
$sRightField = $aJoinInfo["rightfield"];
$sRightTableAlias = $aJoinInfo["righttablealias"];
echo "<li>Join '$sJoinType', $sLeftField, $sRightTableAlias.$sRightField".$oSQLQuery->DisplayHtml()."</li>\n";
}
} }
echo "</ul>"; echo "</ul>";
} }
$aFrom = array(); $aFrom = array();
$aFields = array(); $aFields = array();
$aGroupBy = array();
$oCondition = null; $oCondition = null;
$aDelTables = array(); $aDelTables = array();
$aSetValues = array(); $aSetValues = array();
$aSelectedIdFields = array(); $aSelectedIdFields = array();
$this->privRender($aFrom, $aFields, $aGroupBy, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields); $this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
echo "From ...<br/>\n"; echo "From ...<br/>\n";
echo "<pre style=\"font-size: smaller;\">\n"; echo "<pre style=\"font-size: smaller;\">\n";
print_r($aFrom); print_r($aFrom);
@@ -154,11 +127,6 @@ class SQLQuery
$this->m_aFields = $aExpressions; $this->m_aFields = $aExpressions;
} }
public function SetGroupBy($aExpressions)
{
$this->m_aGroupBy = $aExpressions;
}
public function SetCondition($oConditionExpr) public function SetCondition($oConditionExpr)
{ {
$this->m_oConditionExpr = $oConditionExpr; $this->m_oConditionExpr = $oConditionExpr;
@@ -228,24 +196,6 @@ class SQLQuery
{ {
return $this->AddJoin("left", $oSQLQuery, $sLeftField, $sRightField); return $this->AddJoin("left", $oSQLQuery, $sLeftField, $sRightField);
} }
public function AddInnerJoinEx(SQLQuery $oSQLQuery, Expression $oOnExpression)
{
$this->m_aJoinSelects[] = array(
"jointype" => 'inner',
"select" => $oSQLQuery,
"on_expression" => $oOnExpression
);
}
public function AddLeftJoinEx(SQLQuery $oSQLQuery, Expression $oOnExpression)
{
$this->m_aJoinSelects[] = array(
"jointype" => 'left',
"select" => $oSQLQuery,
"on_expression" => $oOnExpression
);
}
// Interface, build the SQL query // Interface, build the SQL query
public function RenderDelete($aArgs = array()) public function RenderDelete($aArgs = array())
@@ -253,12 +203,11 @@ class SQLQuery
// The goal will be to complete the list as we build the Joins // The goal will be to complete the list as we build the Joins
$aFrom = array(); $aFrom = array();
$aFields = array(); $aFields = array();
$aGroupBy = array();
$oCondition = null; $oCondition = null;
$aDelTables = array(); $aDelTables = array();
$aSetValues = array(); $aSetValues = array();
$aSelectedIdFields = array(); $aSelectedIdFields = array();
$this->privRender($aFrom, $aFields, $aGroupBy, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields); $this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
// Target: DELETE myAlias1, myAlias2 FROM t1 as myAlias1, t2 as myAlias2, t3 as topreserve WHERE ... // Target: DELETE myAlias1, myAlias2 FROM t1 as myAlias1, t2 as myAlias2, t3 as topreserve WHERE ...
@@ -289,12 +238,11 @@ class SQLQuery
// The goal will be to complete the list as we build the Joins // The goal will be to complete the list as we build the Joins
$aFrom = array(); $aFrom = array();
$aFields = array(); $aFields = array();
$aGroupBy = array();
$oCondition = null; $oCondition = null;
$aDelTables = array(); $aDelTables = array();
$aSetValues = array(); $aSetValues = array();
$aSelectedIdFields = array(); $aSelectedIdFields = array();
$this->privRender($aFrom, $aFields, $aGroupBy, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields); $this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
$sFrom = self::ClauseFrom($aFrom); $sFrom = self::ClauseFrom($aFrom);
$sValues = self::ClauseValues($aSetValues); $sValues = self::ClauseValues($aSetValues);
$sWhere = self::ClauseWhere($oCondition, $aArgs); $sWhere = self::ClauseWhere($oCondition, $aArgs);
@@ -302,39 +250,29 @@ class SQLQuery
} }
// Interface, build the SQL query // Interface, build the SQL query
public function RenderSelect($aOrderBy = array(), $aArgs = array(), $iLimitCount = 0, $iLimitStart = 0, $bGetCount = false, $bBeautifulQuery = false) public function RenderSelect($aOrderBy = array(), $aArgs = array(), $iLimitCount = 0, $iLimitStart = 0, $bGetCount = false)
{ {
$this->m_bBeautifulQuery = $bBeautifulQuery;
$sLineSep = $this->m_bBeautifulQuery ? "\n" : '';
$sIndent = $this->m_bBeautifulQuery ? " " : null;
// The goal will be to complete the lists as we build the Joins // The goal will be to complete the lists as we build the Joins
$aFrom = array(); $aFrom = array();
$aFields = array(); $aFields = array();
$aGroupBy = array();
$oCondition = null; $oCondition = null;
$aDelTables = array(); $aDelTables = array();
$aSetValues = array(); $aSetValues = array();
$aSelectedIdFields = array(); $aSelectedIdFields = array();
$this->privRender($aFrom, $aFields, $aGroupBy, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields); $this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
$sFrom = self::ClauseFrom($aFrom, $sIndent); $sFrom = self::ClauseFrom($aFrom);
$sWhere = self::ClauseWhere($oCondition, $aArgs); $sWhere = self::ClauseWhere($oCondition, $aArgs);
if ($bGetCount) if ($bGetCount)
{ {
if (count($aSelectedIdFields) > 0) if (count($aSelectedIdFields) > 0)
{ {
$aCountFields = array(); $sIDFields = implode(', ', $aSelectedIdFields);
foreach ($aSelectedIdFields as $sFieldExpr) $sSQL = "SELECT COUNT(DISTINCT $sIDFields) AS COUNT FROM $sFrom WHERE $sWhere";
{
$aCountFields[] = "COALESCE($sFieldExpr, 0)"; // Null values are excluded from the count
}
$sCountFields = implode(', ', $aCountFields);
$sSQL = "SELECT$sLineSep COUNT(DISTINCT $sCountFields) AS COUNT$sLineSep FROM $sFrom$sLineSep WHERE $sWhere";
} }
else else
{ {
$sSQL = "SELECT$sLineSep COUNT(*) AS COUNT$sLineSep FROM $sFrom$sLineSep WHERE $sWhere"; $sSQL = "SELECT COUNT(*) AS COUNT FROM $sFrom WHERE $sWhere";
} }
} }
else else
@@ -353,36 +291,11 @@ class SQLQuery
{ {
$sLimit = ''; $sLimit = '';
} }
$sSQL = "SELECT$sLineSep DISTINCT $sSelect$sLineSep FROM $sFrom$sLineSep WHERE $sWhere$sLineSep $sOrderBy$sLineSep $sLimit"; $sSQL = "SELECT DISTINCT $sSelect FROM $sFrom WHERE $sWhere $sOrderBy $sLimit";
} }
return $sSQL; return $sSQL;
} }
// Interface, build the SQL query
public function RenderGroupBy($aArgs = array(), $bBeautifulQuery = false)
{
$this->m_bBeautifulQuery = $bBeautifulQuery;
$sLineSep = $this->m_bBeautifulQuery ? "\n" : '';
$sIndent = $this->m_bBeautifulQuery ? " " : null;
// The goal will be to complete the lists as we build the Joins
$aFrom = array();
$aFields = array();
$aGroupBy = array();
$oCondition = null;
$aDelTables = array();
$aSetValues = array();
$aSelectedIdFields = array();
$this->privRender($aFrom, $aFields, $aGroupBy, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
$sSelect = self::ClauseSelect($aFields);
$sFrom = self::ClauseFrom($aFrom, $sIndent);
$sWhere = self::ClauseWhere($oCondition, $aArgs);
$sGroupBy = self::ClauseGroupBy($aGroupBy);
$sSQL = "SELECT $sSelect,$sLineSep COUNT(*) AS _itop_count_$sLineSep FROM $sFrom$sLineSep WHERE $sWhere$sLineSep GROUP BY $sGroupBy";
return $sSQL;
}
private static function ClauseSelect($aFields) private static function ClauseSelect($aFields)
{ {
$aSelect = array(); $aSelect = array();
@@ -394,12 +307,6 @@ class SQLQuery
return $sSelect; return $sSelect;
} }
private static function ClauseGroupBy($aGroupBy)
{
$sRes = implode(', ', $aGroupBy);
return $sRes;
}
private static function ClauseDelete($aDelTableAliases) private static function ClauseDelete($aDelTableAliases)
{ {
$aDelTables = array(); $aDelTables = array();
@@ -411,30 +318,27 @@ class SQLQuery
return $sDelTables; return $sDelTables;
} }
private static function ClauseFrom($aFrom, $sIndent = null, $iIndentLevel = 0) private static function ClauseFrom($aFrom)
{ {
$sLineBreakLong = $sIndent ? "\n".str_repeat($sIndent, $iIndentLevel + 1) : '';
$sLineBreak = $sIndent ? "\n".str_repeat($sIndent, $iIndentLevel) : '';
$sFrom = ""; $sFrom = "";
foreach ($aFrom as $sTableAlias => $aJoinInfo) foreach ($aFrom as $sTableAlias => $aJoinInfo)
{ {
switch ($aJoinInfo["jointype"]) switch ($aJoinInfo["jointype"])
{ {
case "first": case "first":
$sFrom .= $sLineBreakLong."`".$aJoinInfo["tablename"]."` AS `$sTableAlias`"; $sFrom .= "`".$aJoinInfo["tablename"]."` AS `$sTableAlias`";
$sFrom .= self::ClauseFrom($aJoinInfo["subfrom"], $sIndent, $iIndentLevel + 1); $sFrom .= " ".self::ClauseFrom($aJoinInfo["subfrom"]);
break; break;
case "inner": case "inner":
case "inner_tree": case "inner_tree":
$sFrom .= $sLineBreak."INNER JOIN ($sLineBreakLong`".$aJoinInfo["tablename"]."` AS `$sTableAlias`"; $sFrom .= " INNER JOIN (`".$aJoinInfo["tablename"]."` AS `$sTableAlias`";
$sFrom .= " ".self::ClauseFrom($aJoinInfo["subfrom"], $sIndent, $iIndentLevel + 1); $sFrom .= " ".self::ClauseFrom($aJoinInfo["subfrom"]);
$sFrom .= $sLineBreak.") ON ".$aJoinInfo["joincondition"]; $sFrom .= ") ON ".$aJoinInfo["joincondition"];
break; break;
case "left": case "left":
$sFrom .= $sLineBreak."LEFT JOIN ($sLineBreakLong`".$aJoinInfo["tablename"]."` AS `$sTableAlias`"; $sFrom .= " LEFT JOIN (`".$aJoinInfo["tablename"]."` AS `$sTableAlias`";
$sFrom .= " ".self::ClauseFrom($aJoinInfo["subfrom"], $sIndent, $iIndentLevel + 1); $sFrom .= " ".self::ClauseFrom($aJoinInfo["subfrom"]);
$sFrom .= $sLineBreak.") ON ".$aJoinInfo["joincondition"]; $sFrom .= ") ON ".$aJoinInfo["joincondition"];
break; break;
default: default:
throw new CoreException("Unknown jointype: '".$aJoinInfo["jointype"]."'"); throw new CoreException("Unknown jointype: '".$aJoinInfo["jointype"]."'");
@@ -471,22 +375,21 @@ class SQLQuery
$aOrderBySpec = array(); $aOrderBySpec = array();
foreach($aOrderBy as $sFieldAlias => $bAscending) foreach($aOrderBy as $sFieldAlias => $bAscending)
{ {
// Note: sFieldAlias must have backticks around column aliases $aOrderBySpec[] = '`'.$sFieldAlias.'`'.($bAscending ? " ASC" : " DESC");
$aOrderBySpec[] = $sFieldAlias.($bAscending ? " ASC" : " DESC");
} }
$sOrderBy = implode(", ", $aOrderBySpec); $sOrderBy = implode(", ", $aOrderBySpec);
return $sOrderBy; return $sOrderBy;
} }
// Purpose: prepare the query data, once for all // Purpose: prepare the query data, once for all
private function privRender(&$aFrom, &$aFields, &$aGroupBy, &$oCondition, &$aDelTables, &$aSetValues, &$aSelectedIdFields) private function privRender(&$aFrom, &$aFields, &$oCondition, &$aDelTables, &$aSetValues, &$aSelectedIdFields)
{ {
$sTableAlias = $this->privRenderSingleTable($aFrom, $aFields, $aGroupBy, $aDelTables, $aSetValues, $aSelectedIdFields, '', array('jointype' => 'first')); $sTableAlias = $this->privRenderSingleTable($aFrom, $aFields, $aDelTables, $aSetValues, $aSelectedIdFields, '', array('jointype' => 'first'));
$oCondition = $this->m_oConditionExpr; $oCondition = $this->m_oConditionExpr;
return $sTableAlias; return $sTableAlias;
} }
private function privRenderSingleTable(&$aFrom, &$aFields, &$aGroupBy, &$aDelTables, &$aSetValues, &$aSelectedIdFields, $sCallerAlias = '', $aJoinData) private function privRenderSingleTable(&$aFrom, &$aFields, &$aDelTables, &$aSetValues, &$aSelectedIdFields, $sCallerAlias = '', $aJoinData)
{ {
$aActualTableFields = CMDBSource::GetTableFieldsList($this->m_sTable); $aActualTableFields = CMDBSource::GetTableFieldsList($this->m_sTable);
@@ -509,14 +412,8 @@ class SQLQuery
break; break;
case "inner": case "inner":
case "left": case "left":
if (isset($aJoinData["on_expression"])) // table or tablealias ???
{ $sJoinCond = "`$sCallerAlias`.`{$aJoinData['leftfield']}` = `$sRightTableAlias`.`{$aJoinData['rightfield']}`";
$sJoinCond = $aJoinData["on_expression"]->Render();
}
else
{
$sJoinCond = "`$sCallerAlias`.`{$aJoinData['leftfield']}` = `$sRightTableAlias`.`{$aJoinData['rightfield']}`";
}
$aFrom[$this->m_sTableAlias] = array("jointype"=>$aJoinData['jointype'], "tablename"=>$this->m_sTable, "joincondition"=>"$sJoinCond"); $aFrom[$this->m_sTableAlias] = array("jointype"=>$aJoinData['jointype'], "tablename"=>$this->m_sTable, "joincondition"=>"$sJoinCond");
break; break;
case "inner_tree": case "inner_tree":
@@ -570,17 +467,11 @@ class SQLQuery
{ {
$aFields["`$sAlias`"] = $oExpression->Render(); $aFields["`$sAlias`"] = $oExpression->Render();
} }
if ($this->m_aGroupBy)
{
foreach($this->m_aGroupBy as $sAlias => $oExpression)
{
$aGroupBy["`$sAlias`"] = $oExpression->Render();
}
}
if ($this->m_bToDelete) if ($this->m_bToDelete)
{ {
$aDelTables[] = "`{$this->m_sTableAlias}`"; $aDelTables[] = "`{$this->m_sTableAlias}`";
} }
//echo "<p>in privRenderSingleTable this->m_aValues<pre>".print_r($this->m_aValues, true)."</pre></p>\n";
foreach($this->m_aValues as $sFieldName=>$value) foreach($this->m_aValues as $sFieldName=>$value)
{ {
$aSetValues["`{$this->m_sTableAlias}`.`$sFieldName`"] = $value; // quoted further! $aSetValues["`{$this->m_sTableAlias}`.`$sFieldName`"] = $value; // quoted further!
@@ -597,106 +488,18 @@ class SQLQuery
foreach ($this->m_aJoinSelects as $aJoinData) foreach ($this->m_aJoinSelects as $aJoinData)
{ {
$oRightSelect = $aJoinData["select"]; $oRightSelect = $aJoinData["select"];
// $sJoinType = $aJoinData["jointype"];
// $sLeftField = $aJoinData["leftfield"];
// $sRightField = $aJoinData["rightfield"];
// $sRightTableAlias = $aJoinData["righttablealias"];
$sJoinTableAlias = $oRightSelect->privRenderSingleTable($aTempFrom, $aFields, $aGroupBy, $aDelTables, $aSetValues, $aSelectedIdFields, $this->m_sTableAlias, $aJoinData); $sJoinTableAlias = $oRightSelect->privRenderSingleTable($aTempFrom, $aFields, $aDelTables, $aSetValues, $aSelectedIdFields, $this->m_sTableAlias, $aJoinData);
} }
$aFrom[$this->m_sTableAlias]['subfrom'] = $aTempFrom; $aFrom[$this->m_sTableAlias]['subfrom'] = $aTempFrom;
return $this->m_sTableAlias; return $this->m_sTableAlias;
} }
public function OptimizeJoins($aUsedTables, $bTopCall = true)
{
if ($bTopCall)
{
// Top call: complete the list of tables absolutely required to perform the right query
$this->CollectUsedTables($aUsedTables);
}
$aToDiscard = array();
foreach ($this->m_aJoinSelects as $i => $aJoinInfo)
{
$oSQLQuery = $aJoinInfo["select"];
$sTableAlias = $oSQLQuery->GetTableAlias();
if ($oSQLQuery->OptimizeJoins($aUsedTables, false) && !array_key_exists($sTableAlias, $aUsedTables))
{
$aToDiscard[] = $i;
}
}
foreach ($aToDiscard as $i)
{
unset($this->m_aJoinSelects[$i]);
}
return (count($this->m_aJoinSelects) == 0);
}
protected function CollectUsedTables(&$aTables)
{
$this->m_oConditionExpr->CollectUsedParents($aTables);
foreach($this->m_aFields as $sFieldAlias => $oField)
{
$oField->CollectUsedParents($aTables);
}
if ($this->m_aGroupBy)
{
foreach($this->m_aGroupBy as $sAlias => $oExpression)
{
$oExpression->CollectUsedParents($aTables);
}
}
if (!is_null($this->m_oSelectedIdField))
{
$this->m_oSelectedIdField->CollectUsedParents($aTables);
}
foreach ($this->m_aJoinSelects as $i => $aJoinInfo)
{
$oSQLQuery = $aJoinInfo["select"];
if ($oSQLQuery->HasRequiredTables($aTables))
{
// There is something required in the branch, then this node is a MUST
if (isset($aJoinInfo['righttablealias']))
{
$aTables[$aJoinInfo['righttablealias']] = true;
}
if (isset($aJoinInfo["on_expression"]))
{
$sJoinCond = $aJoinInfo["on_expression"]->CollectUsedParents($aTables);
}
}
}
return $aTables;
}
// Is required in the JOIN, and therefore we must ensure that the join expression will be valid
protected function HasRequiredTables(&$aTables)
{
$bResult = false;
if (array_key_exists($this->m_sTableAlias, $aTables))
{
$bResult = true;
}
foreach ($this->m_aJoinSelects as $i => $aJoinInfo)
{
$oSQLQuery = $aJoinInfo["select"];
if ($oSQLQuery->HasRequiredTables($aTables))
{
// There is something required in the branch, then this node is a MUST
if (isset($aJoinInfo['righttablealias']))
{
$aTables[$aJoinInfo['righttablealias']] = true;
}
if (isset($aJoinInfo["on_expression"]))
{
$sJoinCond = $aJoinInfo["on_expression"]->CollectUsedParents($aTables);
}
$bResult = true;
}
}
// None of the tables is in the list of required tables
return $bResult;
}
} }
?>
?>

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Object lifecycle management: stimulus * Object lifecycle management: stimulus
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */

View File

@@ -1,21 +1,18 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Simple helper class to interpret and transform a template string * Simple helper class to interpret and transform a template string
@@ -24,8 +21,10 @@
* $oString = new TemplateString("Blah $this->friendlyname$ is in location $this->location_id->name$ ('$this->location_id->org_id->name$)"); * $oString = new TemplateString("Blah $this->friendlyname$ is in location $this->location_id->name$ ('$this->location_id->org_id->name$)");
* echo $oString->Render(array('this' => $oContact)); * echo $oString->Render(array('this' => $oContact));
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
/** /**

View File

@@ -1,28 +1,27 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Persistent class Trigger and derived * Persistent class Trigger and derived
* User defined triggers, that may be used in conjunction with user defined actions * User defined triggers, that may be used in conjunction with user defined actions
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
@@ -42,7 +41,7 @@ abstract class Trigger extends cmdbAbstractObject
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "description", "name_attcode" => "description",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array('description'), "reconc_keys" => array(),
"db_table" => "priv_trigger", "db_table" => "priv_trigger",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "realclass", "db_finalclass_field" => "realclass",
@@ -76,19 +75,6 @@ abstract class Trigger extends cmdbAbstractObject
} }
} }
} }
/**
* Check whether the given object is in the scope of this trigger
* and can potentially be the subject of notifications
* @param DBObject $oObject The object to check
* @return bool
*/
public function IsInScope(DBObject $oObject)
{
// By default the answer is no
// Overload this function in your own derived class for a different behavior
return false;
}
} }
abstract class TriggerOnObject extends Trigger abstract class TriggerOnObject extends Trigger
@@ -101,7 +87,7 @@ abstract class TriggerOnObject extends Trigger
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "description", "name_attcode" => "description",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array('description'), "reconc_keys" => array(),
"db_table" => "priv_trigger_onobject", "db_table" => "priv_trigger_onobject",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
@@ -118,18 +104,6 @@ abstract class TriggerOnObject extends Trigger
// 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
} }
/**
* Check whether the given object is in the scope of this trigger
* and can potentially be the subject of notifications
* @param DBObject $oObject The object to check
* @return bool
*/
public function IsInScope(DBObject $oObject)
{
$sRootClass = $this->Get('target_class');
return ($oObject instanceof $sRootClass);
}
} }
/** /**
* To trigger notifications when a ticket is updated from the portal * To trigger notifications when a ticket is updated from the portal
@@ -140,11 +114,11 @@ class TriggerOnPortalUpdate extends TriggerOnObject
{ {
$aParams = array $aParams = array
( (
"category" => "core/cmdb,bizmodel", "category" => "core/cmdb",
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "description", "name_attcode" => "description",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array('description'), "reconc_keys" => array(),
"db_table" => "priv_trigger_onportalupdate", "db_table" => "priv_trigger_onportalupdate",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
@@ -170,7 +144,7 @@ abstract class TriggerOnStateChange extends TriggerOnObject
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "description", "name_attcode" => "description",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array('description'), "reconc_keys" => array(),
"db_table" => "priv_trigger_onstatechange", "db_table" => "priv_trigger_onstatechange",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
@@ -199,7 +173,7 @@ class TriggerOnStateEnter extends TriggerOnStateChange
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "description", "name_attcode" => "description",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array('description'), "reconc_keys" => array(),
"db_table" => "priv_trigger_onstateenter", "db_table" => "priv_trigger_onstateenter",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
@@ -227,7 +201,7 @@ class TriggerOnStateLeave extends TriggerOnStateChange
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "description", "name_attcode" => "description",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array('description'), "reconc_keys" => array(),
"db_table" => "priv_trigger_onstateleave", "db_table" => "priv_trigger_onstateleave",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
@@ -255,7 +229,7 @@ class TriggerOnObjectCreate extends TriggerOnObject
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "description", "name_attcode" => "description",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array('description'), "reconc_keys" => array(),
"db_table" => "priv_trigger_onobjcreate", "db_table" => "priv_trigger_onobjcreate",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
@@ -283,7 +257,7 @@ class lnkTriggerAction extends cmdbAbstractObject
"key_type" => "autoincrement", "key_type" => "autoincrement",
"name_attcode" => "", "name_attcode" => "",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array('action_id', 'trigger_id'), "reconc_keys" => array(""),
"db_table" => "priv_link_action_trigger", "db_table" => "priv_link_action_trigger",
"db_key_field" => "link_id", "db_key_field" => "link_id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
@@ -304,35 +278,4 @@ class lnkTriggerAction extends cmdbAbstractObject
MetaModel::Init_SetZListItems('advanced_search', array('action_id', 'trigger_id', 'order')); // Criteria of the advanced search form MetaModel::Init_SetZListItems('advanced_search', array('action_id', 'trigger_id', 'order')); // Criteria of the advanced search form
} }
} }
class TriggerOnThresholdReached extends TriggerOnObject
{
public static function Init()
{
$aParams = array
(
"category" => "core/cmdb,bizmodel",
"key_type" => "autoincrement",
"name_attcode" => "description",
"state_attcode" => "",
"reconc_keys" => array('description'),
"db_table" => "priv_trigger_threshold",
"db_key_field" => "id",
"db_finalclass_field" => "",
"display_template" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeString("stop_watch_code", array("allowed_values"=>null, "sql"=>"stop_watch_code", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("threshold_index", array("allowed_values"=>null, "sql"=>"threshold_index", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'stop_watch_code', 'threshold_index', 'action_list')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('target_class', 'threshold_index', 'threshold_index')); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
}
?> ?>

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* User rights management API * User rights management API
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
@@ -42,8 +41,6 @@ define('UR_ACTION_BULK_READ', 4); // Export multiple objects
define('UR_ACTION_BULK_MODIFY', 5); // Create/modify multiple objects define('UR_ACTION_BULK_MODIFY', 5); // Create/modify multiple objects
define('UR_ACTION_BULK_DELETE', 6); // Delete multiple objects define('UR_ACTION_BULK_DELETE', 6); // Delete multiple objects
define('UR_ACTION_CREATE', 7); // Instantiate an object
define('UR_ACTION_APPLICATION_DEFINED', 10000); // Application specific actions (CSV import, View schema...) define('UR_ACTION_APPLICATION_DEFINED', 10000); // Application specific actions (CSV import, View schema...)
/** /**
@@ -58,7 +55,7 @@ abstract class UserRightsAddOnAPI
abstract public function Init(); // loads data (possible optimizations) abstract public function Init(); // loads data (possible optimizations)
// Used to build select queries showing only objects visible for the given user // Used to build select queries showing only objects visible for the given user
abstract public function GetSelectFilter($sLogin, $sClass, $aSettings = array()); // returns a filter object abstract public function GetSelectFilter($sLogin, $sClass); // returns a filter object
abstract public function IsActionAllowed($oUser, $sClass, $iActionCode, /*dbObjectSet*/ $oInstanceSet = null); abstract public function IsActionAllowed($oUser, $sClass, $iActionCode, /*dbObjectSet*/ $oInstanceSet = null);
abstract public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, /*dbObjectSet*/ $oInstanceSet = null); abstract public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, /*dbObjectSet*/ $oInstanceSet = null);
@@ -282,7 +279,7 @@ abstract class UserInternal extends User
"name_attcode" => "login", "name_attcode" => "login",
"state_attcode" => "", "state_attcode" => "",
"reconc_keys" => array('login'), "reconc_keys" => array('login'),
"db_table" => "priv_internaluser", "db_table" => "priv_internalUser",
"db_key_field" => "id", "db_key_field" => "id",
"db_finalclass_field" => "", "db_finalclass_field" => "",
); );
@@ -298,35 +295,6 @@ abstract class UserInternal extends User
} }
} }
/**
* Self register extension
*
* @package iTopORM
*/
interface iSelfRegister
{
/**
* Called when no user is found in iTop for the corresponding 'name'. This method
* can create/synchronize the User in iTop with an external source (such as AD/LDAP) on the fly
* @param string $sName The typed-in user name
* @param string $sPassword The typed-in password
* @param string $sLoginMode The login method used (cas|form|basic|url)
* @param string $sAuthentication The authentication method used (any|internal|external)
* @return bool true if the user is a valid one, false otherwise
*/
public static function CheckCredentialsAndCreateUser($sName, $sPassword, $sLoginMode, $sAuthentication);
/**
* Called after the user has been authenticated and found in iTop. This method can
* Update the user's definition on the fly (profiles...) to keep it in sync with an external source
* @param User $oUser The user to update/synchronize
* @param string $sLoginMode The login mode used (cas|form|basic|url)
* @param string $sAuthentication The authentication method used
* @return void
*/
public static function UpdateUser(User $oUser, $sLoginMode, $sAuthentication);
}
/** /**
* User management core API * User management core API
* *
@@ -337,7 +305,6 @@ class UserRights
protected static $m_oAddOn; protected static $m_oAddOn;
protected static $m_oUser; protected static $m_oUser;
protected static $m_oRealUser; protected static $m_oRealUser;
protected static $m_sSelfRegisterAddOn = null;
public static function SelectModule($sModuleName) public static function SelectModule($sModuleName)
{ {
@@ -357,15 +324,6 @@ class UserRights
self::$m_oRealUser = null; self::$m_oRealUser = null;
} }
public static function SelectSelfRegister($sModuleName)
{
if (!class_exists($sModuleName))
{
throw new CoreException("Could not select the class, '$sModuleName' for self register, is not a valid class name");
}
self::$m_sSelfRegisterAddOn = $sModuleName;
}
public static function GetModuleInstance() public static function GetModuleInstance()
{ {
return self::$m_oAddOn; return self::$m_oAddOn;
@@ -403,38 +361,21 @@ class UserRights
return true; return true;
} }
public static function CheckCredentials($sName, $sPassword, $sLoginMode = 'form', $sAuthentication = 'any') public static function CheckCredentials($sName, $sPassword, $sAuthentication = 'any')
{ {
$oUser = self::FindUser($sName, $sAuthentication); $oUser = self::FindUser($sName, $sAuthentication);
if (is_null($oUser)) if (is_null($oUser))
{ {
return self::CheckCredentialsAndCreateUser($sName, $sPassword, $sLoginMode, $sAuthentication); return false;
} }
if (!$oUser->CheckCredentials($sPassword)) if (!$oUser->CheckCredentials($sPassword))
{ {
return false; return false;
} }
self::UpdateUser($oUser, $sLoginMode, $sAuthentication);
return true; return true;
} }
public static function CheckCredentialsAndCreateUser($sName, $sPassword, $sLoginMode, $sAuthentication)
{
if (self::$m_sSelfRegisterAddOn != null)
{
return call_user_func(array(self::$m_sSelfRegisterAddOn, 'CheckCredentialsAndCreateUser'), $sName, $sPassword, $sLoginMode, $sAuthentication);
}
}
public static function UpdateUser($oUser, $sLoginMode, $sAuthentication)
{
if (self::$m_sSelfRegisterAddOn != null)
{
call_user_func(array(self::$m_sSelfRegisterAddOn, 'UpdateUser'), $oUser, $sLoginMode, $sAuthentication);
}
}
public static function TrustWebServerContext() public static function TrustWebServerContext()
{ {
if (!is_null(self::$m_oUser)) if (!is_null(self::$m_oUser))
@@ -650,7 +591,7 @@ class UserRights
return true; return true;
} }
public static function GetSelectFilter($sClass, $aSettings = array()) public static function GetSelectFilter($sClass)
{ {
// When initializing, we need to let everything pass trough // When initializing, we need to let everything pass trough
if (!self::CheckLogin()) return true; if (!self::CheckLogin()) return true;
@@ -659,7 +600,7 @@ class UserRights
if (MetaModel::HasCategory($sClass, 'bizmodel')) if (MetaModel::HasCategory($sClass, 'bizmodel'))
{ {
return self::$m_oAddOn->GetSelectFilter(self::$m_oUser, $sClass, $aSettings); return self::$m_oAddOn->GetSelectFilter(self::$m_oUser, $sClass);
} }
else else
{ {
@@ -674,21 +615,9 @@ class UserRights
if (MetaModel::DBIsReadOnly()) if (MetaModel::DBIsReadOnly())
{ {
if ($iActionCode == UR_ACTION_CREATE) return false;
if ($iActionCode == UR_ACTION_MODIFY) return false; if ($iActionCode == UR_ACTION_MODIFY) return false;
if ($iActionCode == UR_ACTION_DELETE) return false;
if ($iActionCode == UR_ACTION_BULK_MODIFY) return false; if ($iActionCode == UR_ACTION_BULK_MODIFY) return false;
if ($iActionCode == UR_ACTION_DELETE) return false;
if ($iActionCode == UR_ACTION_BULK_DELETE) return false;
}
$aPredefinedObjects = call_user_func(array($sClass, 'GetPredefinedObjects'));
if ($aPredefinedObjects != null)
{
// As opposed to the read-only DB, modifying an object is allowed
// (the constant columns will be marked as read-only)
//
if ($iActionCode == UR_ACTION_CREATE) return false;
if ($iActionCode == UR_ACTION_DELETE) return false;
if ($iActionCode == UR_ACTION_BULK_DELETE) return false; if ($iActionCode == UR_ACTION_BULK_DELETE) return false;
} }
@@ -700,12 +629,6 @@ class UserRights
{ {
$oUser = self::$m_oUser; $oUser = self::$m_oUser;
} }
if ($iActionCode == UR_ACTION_CREATE)
{
// The addons currently DO NOT handle the case "CREATE"
// Therefore it is considered to be equivalent to "MODIFY"
$iActionCode = UR_ACTION_MODIFY;
}
return self::$m_oAddOn->IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet); return self::$m_oAddOn->IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet);
} }
elseif(($iActionCode == UR_ACTION_READ) && MetaModel::HasCategory($sClass, 'view_in_gui')) elseif(($iActionCode == UR_ACTION_READ) && MetaModel::HasCategory($sClass, 'view_in_gui'))
@@ -1042,339 +965,4 @@ class StimulusChecker extends ActionChecker
return $this->iState; return $this->iState;
} }
} }
/**
* Self-register extension to allow the automatic creation & update of CAS users
*
* @package iTopORM
*
*/
class CAS_SelfRegister implements iSelfRegister
{
/**
* Called when no user is found in iTop for the corresponding 'name'. This method
* can create/synchronize the User in iTop with an external source (such as AD/LDAP) on the fly
* @param string $sName The CAS authenticated user name
* @param string $sPassword Ignored
* @param string $sLoginMode The login mode used (cas|form|basic|url)
* @param string $sAuthentication The authentication method used
* @return bool true if the user is a valid one, false otherwise
*/
public static function CheckCredentialsAndCreateUser($sName, $sPassword, $sLoginMode, $sAuthentication)
{
$bOk = true;
if ($sLoginMode != 'cas') return false; // Must be authenticated via CAS
$sCASMemberships = MetaModel::GetConfig()->Get('cas_memberof');
$bFound = false;
if (!empty($sCASMemberships))
{
if (phpCAS::hasAttribute('memberOf'))
{
// A list of groups is specified, the user must a be member of (at least) one of them to pass
$aCASMemberships = array();
$aTmp = explode(';', $sCASMemberships);
setlocale(LC_ALL, "en_US.utf8"); // !!! WARNING: this is needed to have the iconv //TRANSLIT working fine below !!!
foreach($aTmp as $sGroupName)
{
$aCASMemberships[] = trim(iconv('UTF-8', 'ASCII//TRANSLIT', $sGroupName)); // Just in case remove accents and spaces...
}
$aMemberOf = phpCAS::getAttribute('memberOf');
if (!is_array($aMemberOf)) $aMemberOf = array($aMemberOf); // Just one entry, turn it into an array
$aFilteredGroupNames = array();
foreach($aMemberOf as $sGroupName)
{
phpCAS::log("Info: user if a member of the group: ".$sGroupName);
$sGroupName = trim(iconv('UTF-8', 'ASCII//TRANSLIT', $sGroupName)); // Remove accents and spaces as well
$aFilteredGroupNames[] = $sGroupName;
$bIsMember = false;
foreach($aCASMemberships as $sCASPattern)
{
if (self::IsPattern($sCASPattern))
{
if (preg_match($sCASPattern, $sGroupName))
{
$bIsMember = true;
break;
}
}
else if ($sPattern == $sGroupName)
{
$bIsMember = true;
break;
}
}
if ($bIsMember)
{
$bCASUserSynchro = MetaModel::GetConfig()->Get('cas_user_synchro');
if ($bCASUserSynchro)
{
// If needed create a new user for this email/profile
phpCAS::log('Info: cas_user_synchro is ON');
$bOk = self::CreateCASUser(phpCAS::getUser(), $aMemberOf);
if($bOk)
{
$bFound = true;
}
else
{
phpCAS::log("User ".phpCAS::getUser()." cannot be created in iTop. Logging off...");
}
}
else
{
phpCAS::log('Info: cas_user_synchro is OFF');
$bFound = true;
}
break;
}
}
if($bOk && !$bFound)
{
phpCAS::log("User ".phpCAS::getUser().", none of his/her groups (".implode('; ', $aFilteredGroupNames).") match any of the required groups: ".implode('; ', $aCASMemberships));
}
}
else
{
// Too bad, the user is not part of any of the group => not allowed
phpCAS::log("No 'memberOf' attribute found for user ".phpCAS::getUser().". Are you using the SAML protocol (S1) ?");
}
}
else
{
// No membership required, anybody will pass
$bFound = true;
}
if (!$bFound)
{
// The user is not part of the allowed groups, => log out
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php';
$sCASLogoutUrl = MetaModel::GetConfig()->Get('cas_logout_redirect_service');
if (empty($sCASLogoutUrl))
{
$sCASLogoutUrl = $sUrl;
}
phpCAS::logoutWithRedirectService($sCASLogoutUrl); // Redirects to the CAS logout page
// Will never return !
}
return $bFound;
}
/**
* Called after the user has been authenticated and found in iTop. This method can
* Update the user's definition (profiles...) on the fly to keep it in sync with an external source
* @param User $oUser The user to update/synchronize
* @param string $sLoginMode The login mode used (cas|form|basic|url)
* @param string $sAuthentication The authentication method used
* @return void
*/
public static function UpdateUser(User $oUser, $sLoginMode, $sAuthentication)
{
$bCASUpdateProfiles = MetaModel::GetConfig()->Get('cas_update_profiles');
if (($sLoginMode == 'cas') && $bCASUpdateProfiles && (phpCAS::hasAttribute('memberOf')))
{
$aMemberOf = phpCAS::getAttribute('memberOf');
if (!is_array($aMemberOf)) $aMemberOf = array($aMemberOf); // Just one entry, turn it into an array
return self::SetProfilesFromCAS($oUser, $aMemberOf);
}
// No groups defined in CAS or not CAS at all: do nothing...
return true;
}
/**
* Helper method to create a CAS based user
* @param string $sEmail
* @param array $aGroups
* @return bool true on success, false otherwise
*/
protected static function CreateCASUser($sEmail, $aGroups)
{
if (!MetaModel::IsValidClass('URP_Profiles'))
{
phpCAS::log("URP_Profiles is not a valid class. Automatic creation of Users is not supported in this context, sorry.");
return false;
}
$oUser = MetaModel::GetObjectByName('UserExternal', $sEmail, false);
if ($oUser == null)
{
// Create the user, link it to a contact
phpCAS::log("Info: the user '$sEmail' does not exist. A new UserExternal will be created.");
$oSearch = new DBObjectSearch('Person');
$oSearch->AddCondition('email', $sEmail);
$oSet = new DBObjectSet($oSearch);
$iContactId = 0;
switch($oSet->Count())
{
case 0:
phpCAS::log("Error: found no contact with the email: '$sEmail'. Cannot create the user in iTop.");
return false;
case 1:
$oContact = $oSet->Fetch();
$iContactId = $oContact->GetKey();
phpCAS::log("Info: Found 1 contact '".$oContact->GetName()."' (id=$iContactId) corresponding to the email '$sEmail'.");
break;
default:
phpCAS::log("Error: ".$oSet->Count()." contacts have the same email: '$sEmail'. Cannot create a user for this email.");
return false;
}
$oUser = new UserExternal();
$oUser->Set('login', $sEmail);
$oUser->Set('contactid', $iContactId);
$oUser->Set('language', MetaModel::GetConfig()->GetDefaultLanguage());
}
else
{
phpCAS::log("Info: the user '$sEmail' already exists (id=".$oUser->GetKey().").");
}
// Now synchronize the profiles
if (!self::SetProfilesFromCAS($oUser, $aGroups))
{
return false;
}
else
{
if ($oUser->IsNew() || $oUser->IsModified())
{
$oMyChange = MetaModel::NewObject("CMDBChange");
$oMyChange->Set("date", time());
$oMyChange->Set("userinfo", 'CAS/LDAP Synchro');
$oMyChange->DBInsert();
if ($oUser->IsNew())
{
$oUser->DBInsertTracked($oMyChange);
}
else
{
$oUser->DBUpdateTracked($oMyChange);
}
}
return true;
}
}
protected static function SetProfilesFromCAS($oUser, $aGroups)
{
if (!MetaModel::IsValidClass('URP_Profiles'))
{
phpCAS::log("URP_Profiles is not a valid class. Automatic creation of Users is not supported in this context, sorry.");
return false;
}
// read all the existing profiles
$oProfilesSearch = new DBObjectSearch('URP_Profiles');
$oProfilesSet = new DBObjectSet($oProfilesSearch);
$aAllProfiles = array();
while($oProfile = $oProfilesSet->Fetch())
{
$aAllProfiles[strtolower($oProfile->GetName())] = $oProfile->GetKey();
}
// Translate the CAS/LDAP group names into iTop profile names
$aProfiles = array();
$sPattern = MetaModel::GetConfig()->Get('cas_profile_pattern');
foreach($aGroups as $sGroupName)
{
if (preg_match($sPattern, $sGroupName, $aMatches))
{
if (array_key_exists(strtolower($aMatches[1]), $aAllProfiles))
{
$aProfiles[] = $aAllProfiles[strtolower($aMatches[1])];
phpCAS::log("Info: Adding the profile '{$aMatches[1]}' from CAS.");
}
else
{
phpCAS::log("Warning: {$aMatches[1]} is not a valid iTop profile (extracted from group name: '$sGroupName'). Ignored.");
}
}
else
{
phpCAS::log("Info: The CAS group '$sGroupName' does not seem to match an iTop pattern. Ignored.");
}
}
if (count($aProfiles) == 0)
{
phpCAS::log("Info: The user '".$oUser->GetName()."' has no profiles retrieved from CAS. Default profile(s) will be used.");
// Second attempt: check if there is/are valid default profile(s)
$sCASDefaultProfiles = MetaModel::GetConfig()->Get('cas_default_profiles');
$aCASDefaultProfiles = explode(';', $sCASDefaultProfiles);
foreach($aCASDefaultProfiles as $sDefaultProfileName)
{
if (array_key_exists(strtolower($sDefaultProfileName), $aAllProfiles))
{
$aProfiles[] = $aAllProfiles[strtolower($sDefaultProfileName)];
phpCAS::log("Info: Adding the default profile '".$aAllProfiles[strtolower($sDefaultProfileName)]."' from CAS.");
}
else
{
phpCAS::log("Warning: the default profile {$sDefaultProfileName} is not a valid iTop profile. Ignored.");
}
}
if (count($aProfiles) == 0)
{
phpCAS::log("Error: The user '".$oUser->GetName()."' has no profiles in iTop, and therefore cannot be created.");
return false;
}
}
// Now synchronize the profiles
$oProfilesSet = DBObjectSet::FromScratch('URP_UserProfile');
foreach($aProfiles as $iProfileId)
{
$oLink = new URP_UserProfile();
$oLink->Set('profileid', $iProfileId);
$oLink->Set('reason', 'CAS/LDAP Synchro');
$oProfilesSet->AddObject($oLink);
}
$oUser->Set('profile_list', $oProfilesSet);
phpCAS::log("Info: the user '".$oUser->GetName()."' (id=".$oUser->GetKey().") now has the following profiles: '".implode("', '", $aProfiles)."'.");
if ($oUser->IsModified())
{
$oMyChange = MetaModel::NewObject("CMDBChange");
$oMyChange->Set("date", time());
$oMyChange->Set("userinfo", 'CAS/LDAP Synchro');
$oMyChange->DBInsert();
if ($oUser->IsNew())
{
$oUser->DBInsertTracked($oMyChange);
}
else
{
$oUser->DBUpdateTracked($oMyChange);
}
}
return true;
}
/**
* Helper function to check if the supplied string is a litteral string or a regular expression pattern
* @param string $sCASPattern
* @return bool True if it's a regular expression pattern, false otherwise
*/
protected static function IsPattern($sCASPattern)
{
if ((substr($sCASPattern, 0, 1) == '/') && (substr($sCASPattern, -1) == '/'))
{
// the string is enclosed by slashes, let's assume it's a pattern
return true;
}
else
{
return false;
}
}
}
// By default enable the 'CAS_SelfRegister' defined above
UserRights::SelectSelfRegister('CAS_SelfRegister');
?> ?>

View File

@@ -1,27 +1,26 @@
<?php <?php
// Copyright (C) 2010-2012 Combodo SARL // Copyright (C) 2010 Combodo SARL
// //
// This file is part of iTop. // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
// //
// iTop is free software; you can redistribute it and/or modify // This program is distributed in the hope that it will be useful,
// 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 // 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 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 General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/> // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/** /**
* Value set definitions (from a fixed list or from a query, etc.) * Value set definitions (from a fixed list or from a query, etc.)
* *
* @copyright Copyright (C) 2010-2012 Combodo SARL * @author Erwan Taloc <erwan.taloc@combodo.com>
* @license http://opensource.org/licenses/AGPL-3.0 * @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/ */
require_once('MyHelpers.class.inc.php'); require_once('MyHelpers.class.inc.php');
@@ -98,24 +97,17 @@ class ValueSetObjects extends ValueSetDefinition
protected $m_aOrderBy; protected $m_aOrderBy;
protected $m_aExtraConditions; protected $m_aExtraConditions;
private $m_bAllowAllData; private $m_bAllowAllData;
private $m_aModifierProperties;
public function __construct($sFilterExp, $sValueAttCode = '', $aOrderBy = array(), $bAllowAllData = false, $aModifierProperties = array()) public function __construct($sFilterExp, $sValueAttCode = '', $aOrderBy = array(), $bAllowAllData = false)
{ {
$this->m_sContains = ''; $this->m_sContains = '';
$this->m_sFilterExpr = $sFilterExp; $this->m_sFilterExpr = $sFilterExp;
$this->m_sValueAttCode = $sValueAttCode; $this->m_sValueAttCode = $sValueAttCode;
$this->m_aOrderBy = $aOrderBy; $this->m_aOrderBy = $aOrderBy;
$this->m_bAllowAllData = $bAllowAllData; $this->m_bAllowAllData = $bAllowAllData;
$this->m_aModifierProperties = $aModifierProperties;
$this->m_aExtraConditions = array(); $this->m_aExtraConditions = array();
} }
public function SetModifierProperty($sPluginClass, $sProperty, $value)
{
$this->m_aModifierProperties[$sPluginClass][$sProperty] = $value;
}
public function AddCondition(DBObjectSearch $oFilter) public function AddCondition(DBObjectSearch $oFilter)
{ {
$this->m_aExtraConditions[] = $oFilter; $this->m_aExtraConditions[] = $oFilter;
@@ -135,13 +127,6 @@ class ValueSetObjects extends ValueSetDefinition
{ {
$oFilter->MergeWith($oExtraFilter); $oFilter->MergeWith($oExtraFilter);
} }
foreach($this->m_aModifierProperties as $sPluginClass => $aProperties)
{
foreach ($aProperties as $sProperty => $value)
{
$oFilter->SetModifierProperty($sPluginClass, $sProperty, $value);
}
}
return new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs); return new DBObjectSet($oFilter, $this->m_aOrderBy, $aArgs);
} }
@@ -177,13 +162,6 @@ class ValueSetObjects extends ValueSetDefinition
{ {
$oFilter->MergeWith($oExtraFilter); $oFilter->MergeWith($oExtraFilter);
} }
foreach($this->m_aModifierProperties as $sPluginClass => $aProperties)
{
foreach ($aProperties as $sProperty => $value)
{
$oFilter->SetModifierProperty($sPluginClass, $sProperty, $value);
}
}
$oValueExpr = new ScalarExpression('%'.$sContains.'%'); $oValueExpr = new ScalarExpression('%'.$sContains.'%');
$oNameExpr = new FieldExpression('friendlyname', $oFilter->GetClassAlias()); $oNameExpr = new FieldExpression('friendlyname', $oFilter->GetClassAlias());
@@ -209,11 +187,6 @@ class ValueSetObjects extends ValueSetDefinition
{ {
return 'Filter: '.$this->m_sFilterExpr; return 'Filter: '.$this->m_sFilterExpr;
} }
public function GetFilterExpression()
{
return $this->m_sFilterExpr;
}
} }
@@ -305,13 +278,6 @@ class ValueSetEnum extends ValueSetDefinition
$this->m_values = $Values; $this->m_values = $Values;
} }
// Helper to export the datat model
public function GetValueList()
{
$this->LoadValues($aArgs = array());
return $this->m_aValues;
}
protected function LoadValues($aArgs) protected function LoadValues($aArgs)
{ {
if (is_array($this->m_values)) if (is_array($this->m_values))

View File

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

View File

@@ -1,23 +0,0 @@
.ui-multiselect { padding:2px 0 2px 4px; text-align:left }
.ui-multiselect span.ui-icon { float:right }
.ui-multiselect-single .ui-multiselect-checkboxes input { position:absolute !important; top: auto !important; left:-9999px; }
.ui-multiselect-single .ui-multiselect-checkboxes label { padding:5px !important }
.ui-multiselect-header { margin-bottom:3px; padding:3px 0 3px 4px }
.ui-multiselect-header ul { font-size:0.9em }
.ui-multiselect-header ul li { float:left; padding:0 10px 0 0 }
.ui-multiselect-header a { text-decoration:none }
.ui-multiselect-header a:hover { text-decoration:underline }
.ui-multiselect-header span.ui-icon { float:left }
.ui-multiselect-header li.ui-multiselect-close { float:right; text-align:right; padding-right:0 }
.ui-multiselect-menu { display:none; padding:3px; position:absolute; z-index:10000; text-align: left }
.ui-multiselect-checkboxes { position:relative /* fixes bug in IE6/7 */; overflow-y:scroll }
.ui-multiselect-checkboxes label { cursor:default; display:block; border:1px solid transparent; padding:3px 1px }
.ui-multiselect-checkboxes label input { position:relative; top:1px }
.ui-multiselect-checkboxes li { clear:both; font-size:0.9em; padding-right:3px }
.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label { text-align:center; font-weight:bold; border-bottom:1px solid }
.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label a { display:block; padding:3px; margin:1px 0; text-decoration:none }
/* remove label borders in IE6 because IE6 does not support transparency */
* html .ui-multiselect-checkboxes label { border:none }

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