SVN:trunk[708]

This commit is contained in:
Denis Flaven
2010-08-27 14:18:58 +00:00
parent af90749778
commit 88efd37525
34 changed files with 1161 additions and 87 deletions

View File

@@ -35,6 +35,7 @@ require_once('../core/cmdbobject.class.inc.php');
require_once('../application/utils.inc.php');
require_once('../application/applicationcontext.class.inc.php');
require_once('../application/ui.linkswidget.class.inc.php');
require_once('../application/ui.passwordwidget.class.inc.php');
abstract class cmdbAbstractObject extends CMDBObject
{
@@ -220,6 +221,7 @@ abstract class cmdbAbstractObject extends CMDBObject
'target_attr' => $oAttDef->GetExtKeyToRemote(),
'view_link' => false,
'menu' => false,
'display_limit' => true, // By default limit the list to speed up the initial load & display
);
}
$oPage->p(MetaModel::GetClassIcon($sTargetClass)." ".$oAttDef->GetDescription());
@@ -1001,6 +1003,12 @@ abstract class cmdbAbstractObject extends CMDBObject
$sHTMLValue = '';
break;
case 'One Way Password':
$oWidget = new UIPasswordWidget($sAttCode, $iId, $sNameSuffix);
$sHTMLValue = $oWidget->Display($oPage, $aArgs);
// Event list & validation is handled directly by the widget
break;
case 'String':
default:
// #@# todo - add context information (depending on dimensions)
@@ -1056,7 +1064,10 @@ abstract class cmdbAbstractObject extends CMDBObject
break;
}
$sPattern = addslashes($oAttDef->GetValidationPattern()); //'^([0-9]+)$';
$oPage->add_ready_script("$('#$iId').bind('".implode(' ', $aEventsList)."', function(evt, sFormId) { return ValidateField('$iId', '$sPattern', $bMandatory, sFormId) } );"); // Bind to a custom event: validate
if (!empty($aEventlist))
{
$oPage->add_ready_script("$('#$iId').bind('".implode(' ', $aEventsList)."', function(evt, sFormId) { return ValidateField('$iId', '$sPattern', $bMandatory, sFormId) } );"); // Bind to a custom event: validate
}
$aDependencies = MetaModel::GetDependentAttributes($sClass, $sAttCode); // List of attributes that depend on the current one
if (count($aDependencies) > 0)
{

View File

@@ -131,27 +131,30 @@ class ApplicationMenu
{
$index = $aMenu['index'];
$oMenu = self::GetMenuNode($index);
$aChildren = self::GetChildren($index);
$sCSSClass = (count($aChildren) > 0) ? ' class="submenu"' : '';
$sHyperlink = $oMenu->GetHyperlink($aExtraParams);
if ($sHyperlink != '')
if ($oMenu->IsEnabled())
{
$oPage->AddToMenu('<li'.$sCSSClass.'><a href="'.$oMenu->GetHyperlink($aExtraParams).'">'.$oMenu->GetTitle().'</a></li>');
}
else
{
$oPage->AddToMenu('<li'.$sCSSClass.'>'.$oMenu->GetTitle().'</li>');
}
$aCurrentMenu = self::$aMenusIndex[$index];
if ($iActiveMenu == $index)
{
$bActive = true;
}
if (count($aChildren) > 0)
{
$oPage->AddToMenu('<ul>');
$bActive |= self::DisplaySubMenu($oPage, $aChildren, $aExtraParams, $iActiveMenu);
$oPage->AddToMenu('</ul>');
$aChildren = self::GetChildren($index);
$sCSSClass = (count($aChildren) > 0) ? ' class="submenu"' : '';
$sHyperlink = $oMenu->GetHyperlink($aExtraParams);
if ($sHyperlink != '')
{
$oPage->AddToMenu('<li'.$sCSSClass.'><a href="'.$oMenu->GetHyperlink($aExtraParams).'">'.$oMenu->GetTitle().'</a></li>');
}
else
{
$oPage->AddToMenu('<li'.$sCSSClass.'>'.$oMenu->GetTitle().'</li>');
}
$aCurrentMenu = self::$aMenusIndex[$index];
if ($iActiveMenu == $index)
{
$bActive = true;
}
if (count($aChildren) > 0)
{
$oPage->AddToMenu('<ul>');
$bActive |= self::DisplaySubMenu($oPage, $aChildren, $aExtraParams, $iActiveMenu);
$oPage->AddToMenu('</ul>');
}
}
}
return $bActive;
@@ -298,6 +301,15 @@ abstract class MenuNode
return $this->AddParams('../pages/UI.php', $aExtraParams);
}
/**
* Tells whether the menu is enabled (i.e. displayed) for the current user
* @return bool True if enabled, false otherwise
*/
public function IsEnabled()
{
return true;
}
public abstract function RenderContent(WebPage $oPage, $aExtraParams = array());
protected function AddParams($sHyperlink, $aExtraParams)
@@ -394,20 +406,23 @@ class OQLMenuNode extends MenuNode
{
protected $sPageTitle;
protected $sOQL;
protected $bSearch;
/**
* Create a menu item based on an OQL query 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 $sPageTitle Title displayed into the page's content (will be looked-up in the dictionnary for translation)
* @param string $sOQL OQL query defining the set of objects to be displayed
* @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 bool $bSearch Whether or not to display a (collapsed) search frame at the top of the page
* @return MenuNode
*/
public function __construct($sMenuId, $sOQL, $iParentIndex, $fRank = 0)
public function __construct($sMenuId, $sOQL, $iParentIndex, $fRank = 0, $bSearch = false)
{
parent::__construct($sMenuId, $iParentIndex, $fRank);
$this->sPageTitle = "Menu:$sMenuId+";
$this->sOQL = $sOQL;
$this->bSearch = $bSearch;
}
public function RenderContent(WebPage $oPage, $aExtraParams = array())
@@ -422,8 +437,16 @@ class OQLMenuNode extends MenuNode
$sIcon = '';
}
// The standard template used for all such pages: a (closed) search form at the top and a list of results at the bottom
$sTemplate = <<<EOF
$sTemplate = '';
if ($this->bSearch)
{
$sTemplate .= <<<EOF
<itopblock BlockClass="DisplayBlock" type="search" asynchronous="false" encoding="text/oql">$this->sOQL</itopblock>
EOF;
}
$sTemplate .= <<<EOF
<p class="page-header">$sIcon<itopstring>$this->sPageTitle</itopstring></p>
<itopblock BlockClass="DisplayBlock" type="list" asynchronous="false" encoding="text/oql">$this->sOQL</itopblock>
EOF;
@@ -431,6 +454,40 @@ EOF;
$oTemplate->Render($oPage, $aExtraParams);
}
}
/**
* This class defines a menu item that displays a search form for the given class of objects
*/
class SearchMenuNode extends MenuNode
{
protected $sPageTitle;
protected $sClass;
/**
* Create a menu item based on an OQL query 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 $sClass The class of objects to search for
* @param string $sPageTitle Title displayed into the page's content (will be looked-up in the dictionnary for translation)
* @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
* @return MenuNode
*/
public function __construct($sMenuId, $sClass, $iParentIndex, $fRank = 0)
{
parent::__construct($sMenuId, $iParentIndex, $fRank);
$this->sPageTitle = "Menu:$sMenuId+";
$this->sClass = $sClass;
}
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
// The standard template used for all such pages: an open search form at the top
$sTemplate = <<<EOF
<itopblock BlockClass="DisplayBlock" type="search" asynchronous="false" encoding="text/oql" parameters="open:true">SELECT $this->sClass</itopblock>
EOF;
$oTemplate = new DisplayTemplate($sTemplate);
$oTemplate->Render($oPage, $aExtraParams);
}
}
/**
* This class defines a menu that points to any web page. It takes only two parameters:
@@ -468,4 +525,60 @@ class WebPageMenuNode extends MenuNode
assert(false); // Shall never be called, the external web page will handle the display by itself
}
}
/**
* This class defines a menu that points to the page for creating a new object of the specified class.
* It take only one parameter: the name of the class
* Note: the parameter menu=xxx (where xxx is the id of the menu itself) will be added to the hyperlink
* in order to make it the active one
*/
class NewObjectMenuNode extends MenuNode
{
protected $sClass;
/**
* Create a menu item that points to the URL for creating a new object, the menu will be added only if the current user has enough
* rights to create such an object (or an object of a child class)
* @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 $sClass URL to the page to load. Use relative URL if you want to keep the application portable !
* @param integer $iParentIndex ID of the parent menu
* @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
* @return MenuNode
*/
public function __construct($sMenuId, $sClass, $iParentIndex, $fRank = 0)
{
parent::__construct($sMenuId, $iParentIndex, $fRank);
$this->sClass = $sClass;
}
public function GetHyperlink($aExtraParams)
{
$sHyperlink = '../pages/UI.php?operation=new&class='.$this->sClass;
$aExtraParams['menu'] = $this->GetIndex();
return $this->AddParams($sHyperlink, $aExtraParams);
}
public function IsEnabled()
{
// Enable this menu, only if the current user has enough rights to create such an object, or an object of
// any child class
$aSubClasses = MetaModel::EnumChildClasses($this->sClass, ENUM_CHILD_CLASSES_ALL); // Including the specified class itself
$bActionIsAllowed = false;
foreach($aSubClasses as $sCandidateClass)
{
if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES))
{
$bActionIsAllowed = true;
break; // Enough for now
}
}
return $bActionIsAllowed;
}
public function RenderContent(WebPage $oPage, $aExtraParams = array())
{
assert(false); // Shall never be called, the external web page will handle the display by itself
}
}
?>

View File

@@ -170,7 +170,7 @@ class DisplayTemplate
case 'itopcheck':
$sClassName = $aAttributes['class'];
if (MetaModel::IsValidClass($sClassName))
if (MetaModel::IsValidClass($sClassName) && UserRights::IsActionAllowed($sClassName, UR_ACTION_READ))
{
$oTemplate = new DisplayTemplate($sContent);
$oTemplate->Render($oPage, array()); // no params to apply, they have already been applied

View File

@@ -0,0 +1,68 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// 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.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// 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
* UI wdiget for displaying and editing one-way encrypted passwords
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @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('../application/webpage.class.inc.php');
require_once('../application/displayblock.class.inc.php');
class UIPasswordWidget
{
protected static $iWidgetIndex = 0;
protected $sAttCode;
protected $sNameSuffix;
protected $iId;
public function __construct($sAttCode, $iInputId, $sNameSuffix = '')
{
self::$iWidgetIndex++;
$this->sAttCode = $sAttCode;
$this->sNameSuffix = $sNameSuffix;
$this->iId = $iInputId;
}
/**
* Get the HTML fragment corresponding to the linkset editing widget
* @param WebPage $oP The web page used for all the output
* @param Hash $aArgs Extra context arguments
* @return string The HTML fragment to be inserted into the page
*/
public function Display(WebPage $oPage, $aArgs = array())
{
$sCode = $this->sAttCode.$this->sNameSuffix;
$iWidgetIndex = self::$iWidgetIndex;
$sHtmlValue = '';
$sHtmlValue = '<input type="password" name="attr_'.$sCode.'" id="'.$this->iId.'" value="*****"/>&nbsp;<span id="v_'.$this->iId.'"></span><br/>';
$sHtmlValue .= '<input type="password" id="'.$this->iId.'_confirm" value="*****"/> '.Dict::S('UI:PasswordConfirm').' <input type="button" value="'.Dict::S('UI:Button:ResetPassword').'" onClick="ResetPwd(\''.$this->iId.'\');">';
$sHtmlValue .= '<input type="hidden" id="'.$this->iId.'_changed" name="attr_'.$sCode.'_changed" value="0"/>';
$oPage->add_ready_script("$('#$this->iId').bind('keyup change', function(evt) { return PasswordFieldChanged('$this->iId') } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#$this->iId').bind('keyup change', function(evt) { return PasswordFieldChanged('$this->iId') } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#$this->iId').bind('keyup change validate', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#{$this->iId}_confirm').bind('keyup change', function(evt, sFormId) { return ValidatePasswordField('$this->iId', sFormId) } );"); // Bind to a custom event: validate
return $sHtmlValue;
}
}
?>

View File

@@ -26,6 +26,7 @@
require_once('MyHelpers.class.inc.php');
require_once('ormdocument.class.inc.php');
require_once('ormpassword.class.inc.php');
/**
* MissingColumnException - sent if an attribute is being created but the column is missing in the row
@@ -377,7 +378,7 @@ class AttributeLinkedSetIndirect extends AttributeLinkedSet
* @package iTopORM
*/
class AttributeDBFieldVoid extends AttributeDefinition
{
{
static protected function ListExpectedParams()
{
return array_merge(parent::ListExpectedParams(), array("allowed_values", "depends_on", "sql"));
@@ -465,7 +466,7 @@ class AttributeDBFieldVoid extends AttributeDefinition
* @package iTopORM
*/
class AttributeDBField extends AttributeDBFieldVoid
{
{
static protected function ListExpectedParams()
{
return array_merge(parent::ListExpectedParams(), array("default_value", "is_null_allowed"));
@@ -861,6 +862,66 @@ class AttributePassword extends AttributeString
}
}
/**
* Map a text column (size < 255) to an attribute that is encrypted in the database
* The encryption is based on a key set per iTop instance. Thus if you export your
* database (in SQL) to someone else without providing the key at the same time
* the encrypted fields will remain encrypted
*
* @package iTopORM
*/
class AttributeEncryptedString extends AttributeString
{
static $sKey = null; // Encryption key used for all encrypted fields
public function __construct($sCode, $aParams)
{
parent::__construct($sCode, $aParams);
if (self::$sKey == null)
{
self::$sKey = MetaModel::GetConfig()->GetEncryptionKey();
}
}
protected function GetSQLCol() {return "TINYBLOB";}
public function GetFilterDefinitions()
{
// Note: due to this, you will get an error if a an encrypted field is declared as a search criteria (see ZLists)
// not allowed to search on encrypted fields !
return array();
}
public function MakeRealValue($proposedValue)
{
if (is_null($proposedValue)) return null;
return (string)$proposedValue;
}
/**
* Decrypt the value when reading from the database
*/
public function FromSQLToValue($aCols, $sPrefix = '')
{
$oSimpleCrypt = new SimpleCrypt();
$sValue = $oSimpleCrypt->Decrypt(self::$sKey, $aCols[$sPrefix]);
return $sValue;
}
/**
* Encrypt the value before storing it in the database
*/
public function GetSQLValues($value)
{
$oSimpleCrypt = new SimpleCrypt();
$encryptedValue = $oSimpleCrypt->Encrypt(self::$sKey, $value);
$aValues = array();
$aValues[$this->Get("sql")] = $encryptedValue;
return $aValues;
}
}
/**
* Map a text column (size > ?) to an attribute
*
@@ -1880,6 +1941,140 @@ class AttributeBlob extends AttributeDefinition
return ''; // Not exportable in XML, or as CDATA + some subtags ??
}
}
/**
* One way encrypted (hashed) password
*/
class AttributeOneWayPassword extends AttributeDefinition
{
static protected function ListExpectedParams()
{
return array_merge(parent::ListExpectedParams(), array("depends_on"));
}
public function GetType() {return "One Way Password";}
public function GetTypeDesc() {return "One Way Password";}
public function GetEditClass() {return "One Way Password";}
public function IsDirectField() {return true;}
public function IsScalar() {return true;}
public function IsWritable() {return true;}
public function GetDefaultValue() {return "";}
public function IsNullAllowed() {return $this->GetOptional("is_null_allowed", false);}
// Facilitate things: allow the user to Set the value from a string or from an ormPassword (already encrypted)
public function MakeRealValue($proposedValue)
{
$oPassword = $proposedValue;
if (!is_object($oPassword))
{
$oPassword = new ormPassword('', '');
$oPassword->SetPassword($proposedValue);
}
return $oPassword;
}
public function GetSQLExpressions()
{
$aColumns = array();
// Note: to optimize things, the existence of the attribute is determined by the existence of one column with an empty suffix
$aColumns[''] = $this->GetCode().'_hash';
$aColumns['_salt'] = $this->GetCode().'_salt';
return $aColumns;
}
public function FromSQLToValue($aCols, $sPrefix = '')
{
if (!isset($aCols[$sPrefix]))
{
$sAvailable = implode(', ', array_keys($aCols));
throw new MissingColumnException("Missing column '$sPrefix' from {$sAvailable}");
}
$hashed = $aCols[$sPrefix];
if (!isset($aCols[$sPrefix.'_salt']))
{
$sAvailable = implode(', ', array_keys($aCols));
throw new MissingColumnException("Missing column '".$sPrefix."_salt' from {$sAvailable}");
}
$sSalt = $aCols[$sPrefix.'_salt'];
$value = new ormPassword($hashed, $sSalt);
return $value;
}
public function GetSQLValues($value)
{
// #@# Optimization: do not load blobs anytime
// As per mySQL doc, selecting blob columns will prevent mySQL from
// using memory in case a temporary table has to be created
// (temporary tables created on disk)
// We will have to remove the blobs from the list of attributes when doing the select
// then the use of Get() should finalize the load
if ($value instanceOf ormPassword)
{
$aValues = array();
$aValues[$this->GetCode().'_hash'] = $value->GetHash();
$aValues[$this->GetCode().'_salt'] = $value->GetSalt();
}
else
{
$aValues = array();
$aValues[$this->GetCode().'_hash'] = '';
$aValues[$this->GetCode().'_salt'] = '';
echo "Writing an empty password !!!";
echo "<pre>\n";
print_r($value);
echo "</pre>\n";
}
return $aValues;
}
public function GetSQLColumns()
{
$aColumns = array();
$aColumns[$this->GetCode().'_hash'] = 'TINYBLOB';
$aColumns[$this->GetCode().'_salt'] = 'TINYBLOB';
return $aColumns;
}
public function GetFilterDefinitions()
{
return array();
// still not working... see later...
}
public function GetBasicFilterOperators()
{
return array();
}
public function GetBasicFilterLooseOperator()
{
return '=';
}
public function GetBasicFilterSQLExpr($sOpCode, $value)
{
return 'true';
}
public function GetAsHTML($value)
{
if (is_object($value))
{
return $value->GetAsHTML();
}
}
public function GetAsCSV($sValue, $sSeparator = ',', $sTextQualifier = '"')
{
return ''; // Not exportable in CSV
}
public function GetAsXML($value)
{
return ''; // Not exportable in XML
}
}
// Indexed array having two dimensions
class AttributeTable extends AttributeText

View File

@@ -102,7 +102,7 @@ class CMDBChangeOpCreate extends CMDBChangeOp
*/
public function GetDescription()
{
return 'Object created';
return Dict::S('Change:ObjectCreated');
}
}
@@ -135,7 +135,7 @@ class CMDBChangeOpDelete extends CMDBChangeOp
*/
public function GetDescription()
{
return 'Object deleted';
return Dict::S('Change:ObjectDeleted');
}
}
@@ -228,16 +228,16 @@ class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
if (substr($sNewValue,0, strlen($sOldValue)) == $sOldValue) // Text added at the end
{
$sDelta = substr($sNewValue, strlen($sOldValue));
$sResult = "$sDelta appended to $sAttName";
$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 = "$sDelta appended to $sAttName";
$sResult = Dict::Format('Change:Text_AppendedTo_AttName', $sDelta, $sAttName);
}
else
{
$sResult = "$sAttName set to $sNewValue (previous value: $sOldValue)";
$sResult = Dict::Format('Change:AttName_SetTo_NewValue_PreviousValue_OldValue', $sAttName, $sNewValue, $sOldValue);
}
}
elseif($bIsHtml && $oAttDef->IsExternalKey())
@@ -253,7 +253,7 @@ class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
}
else
{
$sResult = "$sAttName set to $sNewValue (previous value: $sOldValue)";
$sResult = Dict::Format('Change:Att_SetTo_NewValue_PreviousValue_OldValue', $sAttName, $sNewValue, $sOldValue);
}
}
return $sResult;
@@ -313,7 +313,111 @@ class CMDBChangeOpSetAttributeBlob extends CMDBChangeOpSetAttribute
$sDocView .= "<br/>".Dict::Format('UI:OpenDocumentInNewWindow_',$oPrevDoc->GetDisplayLink(get_class($this), $this->GetKey(), 'prevdata')).", \n";
$sDocView .= Dict::Format('UI:DownloadDocument_', $oPrevDoc->GetDownloadLink(get_class($this), $this->GetKey(), 'prevdata'))."\n";
//$sDocView = $oPrevDoc->GetDisplayInline(get_class($this), $this->GetKey(), 'prevdata');
$sResult = "$sAttName changed, previous value: $sDocView";
$sResult = Dict::Format('Change:AttName_Changed_PreviousValue_OldValue', $sAttName, $sDocView);
}
return $sResult;
}
}
/**
* Safely record the modification of one way encrypted password
*/
class CMDBChangeOpSetAttributeOneWayPassword 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_pwd",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeOneWayPassword("prev_pwd", array("sql" => 'data', "default_value" => '', "is_null_allowed"=> true, "allowed_values" => null, "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)
{
$oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode'));
$sAttName = $oAttDef->GetLabel();
$sResult = Dict::Format('Change:AttName_Changed', $sAttName);
}
return $sResult;
}
}
/**
* Safely record the modification of an encrypted field
*/
class CMDBChangeOpSetAttributeEncrypted 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_encrypted",
"db_key_field" => "id",
"db_finalclass_field" => "",
);
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributeEncryptedString("prevstring", array("sql" => 'data', "default_value" => '', "is_null_allowed"=> true, "allowed_values" => null, "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)
{
$oAttDef = MetaModel::GetAttributeDef($this->Get('objclass'), $this->Get('attcode'));
$sAttName = $oAttDef->GetLabel();
$sPrevString = $this->Get('prevstring');
$sResult = Dict::Format('Change:AttName_Changed_PreviousValue_OldValue', $sAttName, $sPrevString);
}
return $sResult;
}
@@ -370,7 +474,7 @@ class CMDBChangeOpSetAttributeText extends CMDBChangeOpSetAttribute
$sTextView = '<div>'.$this->GetAsHtml('prevdata').'</div>';
//$sDocView = $oPrevDoc->GetDisplayInline(get_class($this), $this->GetKey(), 'prevdata');
$sResult = "$sAttName changed, previous value: $sTextView";
$sResult = Dict::Format('Change:AttName_Changed_PreviousValue_OldValue', $sAttName, $sTextView);
}
return $sResult;
}

View File

@@ -187,7 +187,47 @@ abstract class CMDBObject extends DBObject
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
if ($oAttDef->IsLinkSet()) continue; // #@# temporary
if ($oAttDef instanceOf AttributeBlob)
if ($oAttDef instanceOf AttributeOneWayPassword)
{
// One Way encrypted passwords' history is stored -one way- encrypted
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeOneWayPassword");
$oMyChangeOp->Set("change", $oChange->GetKey());
$oMyChangeOp->Set("objclass", get_class($this));
$oMyChangeOp->Set("objkey", $this->GetKey());
$oMyChangeOp->Set("attcode", $sAttCode);
if (array_key_exists($sAttCode, $aOrigValues))
{
$original = $aOrigValues[$sAttCode];
}
else
{
$original = '';
}
$oMyChangeOp->Set("prev_pwd", $original);
$iId = $oMyChangeOp->DBInsertNoReload();
}
elseif ($oAttDef instanceOf AttributeEncryptedString)
{
// Encrypted string history is stored encrypted
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeEncrypted");
$oMyChangeOp->Set("change", $oChange->GetKey());
$oMyChangeOp->Set("objclass", get_class($this));
$oMyChangeOp->Set("objkey", $this->GetKey());
$oMyChangeOp->Set("attcode", $sAttCode);
if (array_key_exists($sAttCode, $aOrigValues))
{
$original = $aOrigValues[$sAttCode];
}
else
{
$original = '';
}
$oMyChangeOp->Set("prevdata", $original);
$iId = $oMyChangeOp->DBInsertNoReload();
}
elseif ($oAttDef instanceOf AttributeBlob)
{
// Data blobs
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeBlob");

View File

@@ -46,6 +46,7 @@ define ('DEFAULT_SECURE_CONNECTION_REQUIRED', false);
define ('DEFAULT_HTTPS_HYPERLINKS', false);
define ('DEFAULT_ALLOWED_LOGIN_TYPES', 'form|basic|external');
define ('DEFAULT_EXT_AUTH_VARIABLE', '$_SERVER[\'REMOTE_USER\']');
define ('DEFAULT_ENCRYPTION_KEY', '@iT0pEncr1pti0n!'); // We'll use a random value, later...
/**
* Config
@@ -126,6 +127,13 @@ class Config
*/
protected $m_sExtAuthVariable;
/**
* @var string Encryption key used for all attributes of type "encrypted string". Can be set to a random value
* unless you want to import a database from another iTop instance, in which case you must use
* the same encryption key in order to properly decode the encrypted fields
*/
protected $m_sEncryptionKey;
public function __construct($sConfigFile, $bLoadConfig = true)
{
$this->m_sFile = $sConfigFile;
@@ -177,6 +185,7 @@ class Config
$this->m_sDefaultLanguage = 'EN US';
$this->m_sAllowedLoginTypes = DEFAULT_ALLOWED_LOGIN_TYPES;
$this->m_sExtAuthVariable = DEFAULT_EXT_AUTH_VARIABLE;
$this->m_sEncryptionKey = DEFAULT_ENCRYPTION_KEY;
$this->m_aModuleSettings = array();
@@ -278,6 +287,7 @@ class Config
$this->m_sDefaultLanguage = isset($MySettings['default_language']) ? trim($MySettings['default_language']) : 'EN US';
$this->m_sAllowedLoginTypes = isset($MySettings['allowed_login_types']) ? trim($MySettings['allowed_login_types']) : DEFAULT_ALLOWED_LOGIN_TYPES;
$this->m_sExtAuthVariable = isset($MySettings['ext_auth_variable']) ? trim($MySettings['ext_auth_variable']) : DEFAULT_EXT_AUTH_VARIABLE;
$this->m_sEncryptionKey = isset($MySettings['encryption_key']) ? trim($MySettings['encryption_key']) : DEFAULT_ENCRYPTION_KEY;
}
protected function Verify()
@@ -430,6 +440,10 @@ class Config
return $this->m_sDefaultLanguage;
}
public function GetEncryptionKey()
{
return $this->m_sEncryptionKey;
}
public function GetAllowedLoginTypes()
{
@@ -531,6 +545,11 @@ class Config
$this->m_sExtAuthVariable = $sExtAuthVariable;
}
public function SetEncryptionKey($sKey)
{
$this->m_sEncryptionKey = $sKey;
}
public function FileIsWritable()
{
return is_writable($this->m_sFile);
@@ -580,6 +599,7 @@ class Config
fwrite($hFile, "\t'https_hyperlinks' => ".($this->m_bHttpsHyperlinks ? '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");
fwrite($hFile, ");\n");
fwrite($hFile, "\n");

View File

@@ -3216,6 +3216,11 @@ abstract class MetaModel
return self::$m_oConfig->GetModuleSetting($sModule, $sProperty, $defaultvalue);
}
public static function GetConfig()
{
return self::$m_oConfig;
}
protected static $m_aPlugins = array();
public static function RegisterPlugin($sType, $sName, $aInitCallSpec = array())
{

View File

@@ -0,0 +1,119 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// 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.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// 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('../core/simplecrypt.class.inc.php');
/**
* ormPassword
* encapsulate the behavior of a one way encrypted password stored hashed
* with a per password (as random as possible) salt, in order to prevent a "Rainbow table" hack.
* If a cryptographic random number generator is available (on Linux or Windows)
* it will be used for generating the salt.
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @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
*/
class ormPassword
{
protected $m_sHashed;
protected $m_sSalt;
/**
* Constructor, initializes the password from the encrypted values
*/
public function __construct($sHash = '', $sSalt = '')
{
$this->m_sHashed = $sHash;
$this->m_sSalt = $sSalt;
}
/**
* Encrypts the clear text password, with a unique salt
*/
public function SetPassword($sClearTextPassword)
{
$this->m_sSalt = SimpleCrypt::GetNewSalt();
$this->m_sHashed = $this->ComputeHash($sClearTextPassword);
}
/**
* Print the password: displays some stars
* @return string
*/
public function __toString()
{
return '*****'; // Password can not be read
}
public function IsEmpty()
{
return ($this->m_hashed == null);
}
public function GetHash()
{
return $this->m_sHashed;
}
public function GetSalt()
{
return $this->m_sSalt;
}
/**
* Displays the password: displays some stars
* @return string
*/
public function GetAsHTML()
{
return '*****'; // Password can not be read
}
/**
* Check if the supplied clear text password matches the encrypted one
* @param string $sClearTextPassword
* @return boolean True if it matches, false otherwise
*/
public function CheckPassword($sClearTextPassword)
{
$bResult = false;
$sHashedPwd = $this->ComputeHash($sClearTextPassword);
if ($this->m_sHashed == $sHashedPwd)
{
$bResult = true;
}
return $bResult;
}
/**
* Computes the hashed version of a password using a unique salt
* for this password. A unique salt is generated if needed
* @return string
*/
protected function ComputeHash($sClearTextPwd)
{
if ($this->m_sSalt == null)
{
$this->m_sSalt = SimpleCrypt::GetNewSalt();
}
return hash('sha256', $this->m_sSalt.$sClearTextPwd);
}
}
?>

View File

@@ -0,0 +1,235 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// 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.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// 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
* Simple encryption of strings, uses mcrypt or degrades to a pure PHP
* implementation when mcrypt is not present.
* Based on Miguel Ros' work found at:
* http://rossoft.wordpress.com/2006/05/22/simple-encryption-class/
*
* Usage:
* $oSimpleCrypt = new SimpleCrypt();
* $encrypted = $oSimpleCrypt->encrypt('a_key','the_text');
* $sClearText = $oSimpleCrypt->decrypt('a_key',$encrypted);
*
* The result is $plain equals to 'the_text'
*
* You can use a different engine if you don't have Mcrypt:
* $oSimpleCrypt = new SimpleCrypt('Simple');
*
* A string encrypted with one engine can't be decrypted with
* a different one even if the key is the same.
*
* @author Miguel Ros <rossoft@gmail.com>
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @version 0.3
* @license GPL
*/
class SimpleCrypt
{
/**
* Constructor
* @param string $sEngineName Engine for encryption. Values: Simple, Mcrypt
*/
function __construct($sEngineName = 'Mcrypt')
{
if (($sEngineName == 'Mcrypt') && (!function_exists('mcrypt_module_open')))
{
// Defaults to Simple encryption if the mcrypt module is not present
$sEngineName = 'Simple';
}
$sEngineName = 'SimpleCrypt' . $sEngineName . 'Engine';
$this->oEngine = new $sEngineName;
}
/**
* Encrypts the string with the given key
* @param string $key
* @param string $sString Plaintext string
* @return string Ciphered string
*/
function Encrypt($key, $sString)
{
return $this->oEngine->Encrypt($key,$sString);
}
/**
* Decrypts the string by the given key
* @param string $key
* @param string $string Ciphered string
* @return string Plaintext string
*/
function Decrypt($key, $string)
{
return $this->oEngine->Decrypt($key,$string);
}
/**
* Returns a random "salt" value, to be used when "hashing" a password
* using a one-way encryption algorithm, to prevent an attack using a "rainbow table"
* Tryes to use the best available random number generator
* @return string The generated random "salt"
*/
static function GetNewSalt()
{
// Copied from http://www.php.net/manual/en/function.mt-rand.php#83655
// get 128 pseudorandom bits in a string of 16 bytes
$sRandomBits = null;
// Unix/Linux platform?
$fp = @fopen('/dev/urandom','rb');
if ($fp !== FALSE)
{
//echo "Random bits pulled from /dev/urandom<br/>\n";
$sRandomBits .= @fread($fp,16);
@fclose($fp);
}
else
{
// MS-Windows platform?
if (@class_exists('COM'))
{
// http://msdn.microsoft.com/en-us/library/aa388176(VS.85).aspx
try
{
$CAPI_Util = new COM('CAPICOM.Utilities.1');
$sBase64RandomBits = ''.$CAPI_Util->GetRandom(16,0);
// if we ask for binary data PHP munges it, so we
// request base64 return value. We squeeze out the
// redundancy and useless ==CRLF by hashing...
if ($sBase64RandomBits)
{
//echo "Random bits got from CAPICOM.Utilities.1<br/>\n";
$sRandomBits = md5($sBase64RandomBits, TRUE);
}
}
catch (Exception $ex)
{
// echo 'Exception: ' . $ex->getMessage();
}
}
}
if ($sRandomBits == null)
{
// No "strong" random generator available, use PHP's built-in mechanism
//echo "Random bits generated from mt_rand<br/>\n";
mt_srand(crc32(microtime()));
$sRandomBits = '';
for($i = 0; $i < 4; $i++)
{
$sRandomBits .= sprintf('%04x', mt_rand(0, 65535));
}
}
return $sRandomBits;
}
}
/**
* Interface for encryption engines
*/
interface CryptEngine
{
function Encrypt($key, $sString);
function Decrypt($key, $encrypted_data);
}
/**
* Simple Engine doesn't need any PHP extension.
* Every encryption of the same string with the same key
* will return the same encrypted string
*/
class SimpleCryptSimpleEngine implements CryptEngine
{
public function Encrypt($key, $sString)
{
$result = '';
for($i=1; $i<=strlen($sString); $i++)
{
$char = substr($sString, $i-1, 1);
$keychar = substr($key, ($i % strlen($key))-1, 1);
$char = chr(ord($char)+ord($keychar));
$result.=$char;
}
return $result;
}
public function Decrypt($key, $encrypted_data)
{
$result = '';
for($i=1; $i<=strlen($encrypted_data); $i++)
{
$char = substr($encrypted_data, $i-1, 1);
$keychar = substr($key, ($i % strlen($key))-1, 1);
$char = chr(ord($char)-ord($keychar));
$result.=$char;
}
return $result;
}
}
/**
* McryptEngine requires Mcrypt extension
* Every encryption of the same string with the same key
* will return a different encrypted string.
*/
class SimpleCryptMcryptEngine implements CryptEngine
{
var $alg = MCRYPT_BLOWFISH;
var $td = null;
public function __construct()
{
$this->td = mcrypt_module_open($this->alg,'','cbc','');
}
public function Encrypt($key, $sString)
{
$iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($this->td), MCRYPT_RAND); // MCRYPT_RAND is the only choice on Windows prior to PHP 5.3
mcrypt_generic_init($this->td, $key, $iv);
if (empty($sString))
{
$sString = str_repeat("\0", 8);
}
$encrypted_data = mcrypt_generic($this->td, $sString);
mcrypt_generic_deinit($this->td);
return $iv.$encrypted_data;
}
public function Decrypt($key, $encrypted_data)
{
$iv = substr($encrypted_data, 0, mcrypt_enc_get_iv_size($this->td));
$string = substr($encrypted_data, mcrypt_enc_get_iv_size($this->td));
mcrypt_generic_init($this->td, $key, $iv);
$decrypted_data = rtrim(mdecrypt_generic($this->td, $string), "\0");
mcrypt_generic_deinit($this->td);
return $decrypted_data;
}
public function __destruct()
{
mcrypt_module_close($this->td);
}
}
?>

View File

@@ -104,6 +104,15 @@ Dict::Add('EN US', 'English', 'English', array(
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue' => 'New value',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue+' => 'new value of the attribute',
));
// Used by CMDBChangeOp... & derived classes
Dict::Add('EN US', 'English', 'English', array(
'Change:ObjectCreated' => 'Object created',
'Change:ObjectDeleted' => 'Object deleted',
'Change:AttName_SetTo_NewValue_PreviousValue_OldValue' => '%1$s set to %2$s (previous value: %3$s)',
'Change:Text_AppendedTo_AttName' => '%1$s appended to %2$s',
'Change:AttName_Changed_PreviousValue_OldValue' => '%1$s modified, previous value: %2$s',
'Change:AttName_Changed' => '%1$s modified',
));
//
// Class: CMDBChangeOpSetAttributeBlob

View File

@@ -315,7 +315,7 @@ Dict::Add('EN US', 'English', 'English', array(
</ul>
</p>',
'UI:WelcomeMenu:MyCalls' => 'User Requests assigned to me',
'UI:WelcomeMenu:MyCalls' => 'My requests',
'UI:WelcomeMenu:MyIncidents' => 'Incidents assigned to me',
'UI:AllOrganizations' => ' All Organizations ',
'UI:YourSearch' => 'Your Search',
@@ -345,9 +345,11 @@ Dict::Add('EN US', 'English', 'English', array(
'UI:Button:Create' => ' Create ',
'UI:Button:Delete' => ' Delete ! ',
'UI:Button:ChangePassword' => ' Change Password ',
'UI:Button:ResetPassword' => ' Reset Password ',
'UI:SearchToggle' => 'Search',
'UI:ClickToCreateNew' => 'Click here to create a new %1$s',
'UI:SearchFor_Class' => 'Search for %1$s objects',
'UI:NoObjectToDisplay' => 'No object to display.',
'UI:Error:MandatoryTemplateParameter_object_id' => 'Parameter object_id is mandatory when link_attr is specified. Check the definition of the display template.',
'UI:Error:MandatoryTemplateParameter_target_attr' => 'Parameter target_attr is mandatory when link_attr is specified. Check the definition of the display template.',
@@ -383,6 +385,7 @@ Dict::Add('EN US', 'English', 'English', array(
'UI:GroupBy:Count' => 'Count',
'UI:GroupBy:Count+' => 'Number of elements',
'UI:CountOfObjects' => '%1$d objects matching the criteria.',
'UI_CountOfObjectsShort' => '%1$d objects.',
'UI:NoObject_Class_ToDisplay' => 'No %1$s to display',
'UI:History:LastModified_On_By' => 'Last modified on %1$s by %2$s.',
'UI:HistoryTab' => 'History',
@@ -818,6 +821,7 @@ When associated with a trigger, each action is given an "order" number, specifyi
'UI:Deadline_Hours_Minutes' => '%1$dh %2$dmin',
'UI:Deadline_Days_Hours_Minutes' => '%1$dd %2$dh %3$dmin',
'UI:Help' => 'Help',
'UI:PasswordConfirm' => '(Confirm)',
));

View File

@@ -104,6 +104,13 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue' => 'Nuevo valor',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue+' => 'nuevo valor del atributo',
));
// Used by CMDBChangeOp... & derived classes
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Change:AttName_SetTo_NewValue_PreviousValue_OldValue' => '%1$s modificado en %2$s (valor anterior: %3$s)',
'Change:Text_AppendedTo_AttName' => '%1$s añadido a %2$s',
'Change:AttName_Changed_PreviousValue_OldValue' => '%1$s modificado, valor anterior: %2$s',
'Change:AttName_Changed' => '%1$s modificado',
));
//
// Class: CMDBChangeOpSetAttributeBlob

View File

@@ -331,7 +331,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
</ul>
</p>',
'UI:WelcomeMenu:MyCalls' => 'User Requests assigned to me',
'UI:WelcomeMenu:MyCalls' => 'My requests',
'UI:WelcomeMenu:MyIncidents' => 'Incidents assigned to me',
'UI:AllOrganizations' => ' All Organizations ',
'UI:YourSearch' => 'Your Search',
@@ -361,6 +361,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'UI:Button:Create' => ' Create ',
'UI:Button:Delete' => ' Delete ! ',
'UI:Button:ChangePassword' => ' Change Password ',
'UI:Button:ResetPassword' => ' Reset Password ',
'UI:SearchToggle' => 'Search',
'UI:ClickToCreateNew' => 'Click here to create a new %1$s',
@@ -399,6 +400,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'UI:GroupBy:Count' => 'Count',
'UI:GroupBy:Count+' => 'Number of elements',
'UI:CountOfObjects' => '%1$d objects matching the criteria.',
'UI_CountOfObjectsShort' => '%1$d objects.',
'UI:NoObject_Class_ToDisplay' => 'No %1$s to display',
'UI:History:LastModified_On_By' => 'Last modified on %1$s by %2$s.',
'UI:HistoryTab' => 'History',
@@ -829,6 +831,7 @@ When associated with a trigger, each action is given an "order" number, specifyi
'UI:Deadline_Hours_Minutes' => '%1$dh %2$dmin',
'UI:Deadline_Days_Hours_Minutes' => '%1$dd %2$dh %3$dmin',
'UI:Help' => 'Ayuda',
'UI:PasswordConfirm' => '(Confirm)',
));
?>

View File

@@ -33,7 +33,7 @@
// Class: CMDBChange
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:CMDBChange' => 'change',
'Class:CMDBChange+' => 'Changes tracking',
'Class:CMDBChange/Attribute:date' => 'date',
@@ -46,7 +46,7 @@ Dict::Add('EN US', 'French', 'Français', array(
// Class: CMDBChangeOp
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:CMDBChangeOp' => 'change operation',
'Class:CMDBChangeOp+' => 'Change operations tracking',
'Class:CMDBChangeOp/Attribute:change' => 'change',
@@ -67,7 +67,7 @@ Dict::Add('EN US', 'French', 'Français', array(
// Class: CMDBChangeOpCreate
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:CMDBChangeOpCreate' => 'object creation',
'Class:CMDBChangeOpCreate+' => 'Object creation tracking',
));
@@ -76,7 +76,7 @@ Dict::Add('EN US', 'French', 'Français', array(
// Class: CMDBChangeOpDelete
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:CMDBChangeOpDelete' => 'object deletion',
'Class:CMDBChangeOpDelete+' => 'Object deletion tracking',
));
@@ -85,7 +85,7 @@ Dict::Add('EN US', 'French', 'Français', array(
// Class: CMDBChangeOpSetAttribute
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:CMDBChangeOpSetAttribute' => 'object change',
'Class:CMDBChangeOpSetAttribute+' => 'Object properties change tracking',
'Class:CMDBChangeOpSetAttribute/Attribute:attcode' => 'Attribute',
@@ -96,7 +96,7 @@ Dict::Add('EN US', 'French', 'Français', array(
// Class: CMDBChangeOpSetAttributeScalar
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:CMDBChangeOpSetAttributeScalar' => 'property change',
'Class:CMDBChangeOpSetAttributeScalar+' => 'Object scalar properties change tracking',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:oldvalue' => 'Previous value',
@@ -104,12 +104,21 @@ Dict::Add('EN US', 'French', 'Français', array(
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue' => 'New value',
'Class:CMDBChangeOpSetAttributeScalar/Attribute:newvalue+' => 'new value of the attribute',
));
// Used by CMDBChangeOp... & derived classes
Dict::Add('FR FR', 'French', 'Français', array(
'Change:ObjectCreated' => 'Elément créé',
'Change:ObjectDeleted' => 'Elément effacé',
'Change:AttName_SetTo_NewValue_PreviousValue_OldValue' => '%1$s modifié en %2$s (ancienne valeur: %3$s)',
'Change:Text_AppendedTo_AttName' => '%1$s ajouté à %2$s',
'Change:AttName_Changed_PreviousValue_OldValue' => '%1$s modifié, ancienne valeur: %2$s',
'Change:AttName_Changed' => '%1$s modifié',
));
//
// Class: CMDBChangeOpSetAttributeBlob
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:CMDBChangeOpSetAttributeBlob' => 'data change',
'Class:CMDBChangeOpSetAttributeBlob+' => 'data change tracking',
'Class:CMDBChangeOpSetAttributeBlob/Attribute:prevdata' => 'Previous data',
@@ -120,7 +129,7 @@ Dict::Add('EN US', 'French', 'Français', array(
// Class: CMDBChangeOpSetAttributeText
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:CMDBChangeOpSetAttributeText' => 'text change',
'Class:CMDBChangeOpSetAttributeText+' => 'text change tracking',
'Class:CMDBChangeOpSetAttributeText/Attribute:prevdata' => 'Previous data',
@@ -131,7 +140,7 @@ Dict::Add('EN US', 'French', 'Français', array(
// Class: Event
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:Event' => 'Log Event',
'Class:Event+' => 'An application internal event',
'Class:Event/Attribute:message' => 'message',
@@ -148,7 +157,7 @@ Dict::Add('EN US', 'French', 'Français', array(
// Class: EventNotification
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:EventNotification' => 'Notification event',
'Class:EventNotification+' => 'Trace of a notification that has been sent',
'Class:EventNotification/Attribute:trigger_id' => 'Trigger',
@@ -163,7 +172,7 @@ Dict::Add('EN US', 'French', 'Français', array(
// Class: EventNotificationEmail
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:EventNotificationEmail' => 'Email emission event',
'Class:EventNotificationEmail+' => 'Trace of an email that has been sent',
'Class:EventNotificationEmail/Attribute:to' => 'TO',
@@ -184,7 +193,7 @@ Dict::Add('EN US', 'French', 'Français', array(
// Class: EventIssue
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:EventIssue' => 'Issue event',
'Class:EventIssue+' => 'Trace of an issue (warning, error, etc.)',
'Class:EventIssue/Attribute:issue' => 'Issue',
@@ -207,7 +216,7 @@ Dict::Add('EN US', 'French', 'Français', array(
// Class: EventWebService
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:EventWebService' => 'Web service event',
'Class:EventWebService+' => 'Trace of an web service call',
'Class:EventWebService/Attribute:verb' => 'Verb',
@@ -228,7 +237,7 @@ Dict::Add('EN US', 'French', 'Français', array(
// Class: Action
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:Action' => 'action',
'Class:Action+' => 'Custom action',
'Class:Action/Attribute:name' => 'Name',
@@ -253,7 +262,7 @@ Dict::Add('EN US', 'French', 'Français', array(
// Class: ActionNotification
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:ActionNotification' => 'notification',
'Class:ActionNotification+' => 'Notification (abstract)',
));
@@ -262,7 +271,7 @@ Dict::Add('EN US', 'French', 'Français', array(
// Class: ActionEmail
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:ActionEmail' => 'email notification',
'Class:ActionEmail+' => 'Action: Email notification',
'Class:ActionEmail/Attribute:test_recipient' => 'Test recipient',
@@ -295,7 +304,7 @@ Dict::Add('EN US', 'French', 'Français', array(
// Class: Trigger
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:Trigger' => 'trigger',
'Class:Trigger+' => 'Custom event handler',
'Class:Trigger/Attribute:description' => 'Description',
@@ -310,7 +319,7 @@ Dict::Add('EN US', 'French', 'Français', array(
// Class: TriggerOnObject
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:TriggerOnObject' => 'Trigger on a class of objects',
'Class:TriggerOnObject+' => 'Trigger on a given class of objects',
'Class:TriggerOnObject/Attribute:target_class' => 'Target class',
@@ -321,7 +330,7 @@ Dict::Add('EN US', 'French', 'Français', array(
// Class: TriggerOnStateChange
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:TriggerOnStateChange' => 'Trigger on object state change',
'Class:TriggerOnStateChange+' => 'Trigger on object state change',
'Class:TriggerOnStateChange/Attribute:state' => 'State',
@@ -332,7 +341,7 @@ Dict::Add('EN US', 'French', 'Français', array(
// Class: TriggerOnStateEnter
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:TriggerOnStateEnter' => 'Trigger on object entering a state',
'Class:TriggerOnStateEnter+' => 'Trigger on object state change - entering',
));
@@ -341,7 +350,7 @@ Dict::Add('EN US', 'French', 'Français', array(
// Class: TriggerOnStateLeave
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:TriggerOnStateLeave' => 'Trigger on object leaving a state',
'Class:TriggerOnStateLeave+' => 'Trigger on object state change - leaving',
));
@@ -350,7 +359,7 @@ Dict::Add('EN US', 'French', 'Français', array(
// Class: TriggerOnObjectCreate
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:TriggerOnObjectCreate' => 'Trigger on object creation',
'Class:TriggerOnObjectCreate+' => 'Trigger on object creation of [a child class of] the given class',
));
@@ -359,7 +368,7 @@ Dict::Add('EN US', 'French', 'Français', array(
// Class: lnkTriggerAction
//
Dict::Add('EN US', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Class:lnkTriggerAction' => 'Actions-Trigger',
'Class:lnkTriggerAction+' => 'Link between a trigger and an action',
'Class:lnkTriggerAction/Attribute:action_id' => 'Action',

View File

@@ -346,6 +346,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI:Button:Create' => ' Créer ',
'UI:Button:Delete' => ' Supprimer ! ',
'UI:Button:ChangePassword' => ' Changer ! ',
'UI:Button:ResetPassword' => ' Ràz du mot de passe ',
'UI:SearchToggle' => 'Recherche',
@@ -384,6 +385,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI:GroupBy:Count' => 'Nombre',
'UI:GroupBy:Count+' => 'Nombre d\'éléments',
'UI:CountOfObjects' => '%1$d objets correspondants aux critères.',
'UI_CountOfObjectsShort' => '%1$d objets.',
'UI:NoObject_Class_ToDisplay' => 'Aucun objet %1$s à afficher',
'UI:History:LastModified_On_By' => 'Dernière modification par %2$s le %1$s.',
'UI:HistoryTab' => 'Historique',
@@ -829,6 +831,7 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
'UI:Deadline_Hours_Minutes' => '%1$dh %2$dmin',
'UI:Deadline_Days_Hours_Minutes' => '%1$dj %2$dh %3$dmin',
'UI:Help' => 'Aide',
'UI:PasswordConfirm' => '(Confirmer)',
));
?>

View File

@@ -207,3 +207,45 @@ function UpdateDependentFields(aFieldNames)
}
oWizardHelper.AjaxQueryServer();
}
function ResetPwd(id)
{
// Reset the values of the password fields
$('#'+id).val('*****');
$('#'+id+'_confirm').val('*****');
// And reset the flag, to tell it that the password remains unchanged
$('#'+id+'_changed').val(0);
// Visual feedback, None when it's Ok
$('#v_'+id).html('');
}
// Called whenever the content of a one way encrypted password changes
function PasswordFieldChanged(id)
{
// Set the flag, to tell that the password changed
console.log('Password changed');
$('#'+id+'_changed').val(1);
}
// Special validation function for one way encrypted password fields
function ValidatePasswordField(id, sFormId)
{
var bChanged = $('#'+id+'_changed').val();
if (bChanged)
{
if ($('#'+id).val() != $('#'+id+'_confirm').val())
{
oFormErrors['err_'+sFormId]++;
if (oFormErrors['input_'+sFormId] == null)
{
// Let's remember the first input with an error, so that we can put back the focus on it later
oFormErrors['input_'+sFormId] = id;
}
// Visual feedback
$('#v_'+id).html('<img src="../images/validation_error.png" />');
return false;
}
}
$('#v_'+id).html(''); //<img src="../images/validation_ok.png" />');
return true;
}

View File

@@ -44,8 +44,7 @@ class UserLocal extends UserInternal
MetaModel::Init_Params($aParams);
MetaModel::Init_InheritAttributes();
MetaModel::Init_AddAttribute(new AttributePassword("password", array("allowed_values"=>null, "sql"=>"pwd", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeEncryptedString("encrypted_password", array("allowed_values"=>null, "sql"=>"encrypted_pwd", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeOneWayPassword("password", array("allowed_values"=>null, "sql"=>"pwd", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
// Display lists
MetaModel::Init_SetZListItems('details', array('contactid', 'first_name', 'email', 'login', 'password', 'language', 'profile_list', 'allowed_org_list')); // Attributes to be displayed for the complete details
@@ -57,7 +56,14 @@ class UserLocal extends UserInternal
public function CheckCredentials($sPassword)
{
if ($this->Get('password') == $sPassword)
// if ($this->Get('password') == $sPassword)
// {
// return true;
// }
$oPassword = $this->Get('password'); // ormPassword object
// Cannot compare directly the values since they are hashed, so
// Let's ask the password to compare the hashed values
if ($oPassword->CheckPassword($sPassword))
{
return true;
}

View File

@@ -27,6 +27,12 @@ Dict::Add('EN US', 'English', 'English', array(
'Menu:ChangeManagement' => 'Change management',
'Menu:Change:Overview' => 'Overview',
'Menu:Change:Overview+' => '',
'Menu:NewChange' => 'New Change',
'Menu:NewChange+' => 'Create a new Change ticket',
'Menu:SearchChanges' => 'Search for Changes',
'Menu:SearchChanges+' => 'Search for Change tickets',
'Menu:Change:Shortcuts' => 'Shortcuts',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Changes awaiting acceptance',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Changes awaiting approval',

View File

@@ -27,6 +27,12 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Menu:ChangeManagement' => 'Gestión del cambio',
'Menu:Change:Overview' => 'Visión General',
'Menu:Change:Overview+' => '',
'Menu:NewChange' => 'New Change',
'Menu:NewChange+' => 'Create a new Change ticket',
'Menu:SearchChanges' => 'Search for Changes',
'Menu:SearchChanges+' => 'Search for Change tickets',
'Menu:Change:Shortcuts' => 'Shortcuts',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Cambios esperando ser aceptados',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Cambios esperando ser aprovados',

View File

@@ -27,6 +27,12 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Menu:ChangeManagement' => 'Gestion des changements',
'Menu:Change:Overview' => 'Vue d\'ensemble',
'Menu:Change:Overview+' => '',
'Menu:NewChange' => 'Nouveau changement',
'Menu:NewChange+' => 'Créer un nouveau ticket de changement',
'Menu:SearchChanges' => 'Rechercher des changements',
'Menu:SearchChanges+' => 'Rechercher parmi les tickets de changement',
'Menu:Change:Shortcuts' => 'Raccourcis',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Tickets en attente d\'acceptance',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Tickets en attente d\'approbation',

View File

@@ -483,9 +483,12 @@ class EmergencyChange extends ApprovedChange
$oMyMenuGroup = new MenuGroup('ChangeManagement', 50 /* fRank */);
new TemplateMenuNode('Change:Overview', '../modules/itop-change-mgmt-1.0.0/overview.html', $oMyMenuGroup->GetIndex() /* oParent */, 0 /* fRank */);
new OQLMenuNode('MyChanges', 'SELECT Change WHERE agent_id = :current_contact_id', $oMyMenuGroup->GetIndex(), 1 /* fRank */);
new OQLMenuNode('Changes', 'SELECT Change WHERE status != "closed"', $oMyMenuGroup->GetIndex(), 2 /* fRank */);
new OQLMenuNode('WaitingApproval', 'SELECT ApprovedChange WHERE status IN ("plannedscheduled")', $oMyMenuGroup->GetIndex(), 3 /* fRank */);
new OQLMenuNode('WaitingAcceptance', 'SELECT NormalChange WHERE status IN ("new")', $oMyMenuGroup->GetIndex(), 4 /* fRank */);
new NewObjectMenuNode('NewChange', 'Change', $oMyMenuGroup->GetIndex(), 1 /* fRank */);
new SearchMenuNode('SearchChanges', 'Change', $oMyMenuGroup->GetIndex(), 2 /* fRank */);
$oShortcutNode = new TemplateMenuNode('Change:Shortcuts', '', $oMyMenuGroup->GetIndex(), 3 /* fRank */);
new OQLMenuNode('MyChanges', 'SELECT Change WHERE agent_id = :current_contact_id', $oShortcutNode->GetIndex(), 1 /* fRank */);
new OQLMenuNode('Changes', 'SELECT Change WHERE status != "closed"', $oShortcutNode->GetIndex(), 2 /* fRank */);
new OQLMenuNode('WaitingApproval', 'SELECT ApprovedChange WHERE status IN ("plannedscheduled")', $oShortcutNode->GetIndex(), 3 /* fRank */);
new OQLMenuNode('WaitingAcceptance', 'SELECT NormalChange WHERE status IN ("new")', $oShortcutNode->GetIndex(), 4 /* fRank */);
?>

View File

@@ -31,7 +31,10 @@
Dict::Add('FR FR', 'French', 'Français', array(
'Relation:impacts/Description' => 'Eléments impactés par',
'Relation:impacts/VerbUp' => 'Impacte...',
'Relation:impacts/VerbDown' => 'Eléments impactés par...',
'Relation:impacts/VerbDown' => 'Dépend de...',
'Relation:depends on/Description' => 'Eléments dont dépend cet élément',
'Relation:depends on/VerbUp' => 'Dépend de...',
'Relation:depends on/VerbDown' => 'Impacte...',
));

View File

@@ -1474,7 +1474,7 @@ new WebPageMenuNode('Audit', '../pages/audit.php', $iAdminGroup, 33 /* fRank */)
$oTypologyNode = new TemplateMenuNode('Catalogs', '', $iAdminGroup, 50 /* fRank */);
$iTopology = $oTypologyNode->GetIndex();
new OQLMenuNode('Organization', 'SELECT Organization', $iTopology, 10 /* fRank */);
new OQLMenuNode('Organization', 'SELECT Organization', $iTopology, 10 /* fRank */, true /* bSearch */);
new OQLMenuNode('Application', 'SELECT Application', $iTopology, 20 /* fRank */);
new OQLMenuNode('DBServer', 'SELECT DBServer', $iTopology, 40 /* fRank */);
@@ -1486,24 +1486,28 @@ new TemplateMenuNode('ConfigManagementOverview', '../modules/itop-config-mgmt-1.
$oContactNode = new TemplateMenuNode('Contact', '../modules/itop-config-mgmt-1.0.0/contacts_menu.html', $oConfigManagementGroup->GetIndex(), 1 /* fRank */);
new OQLMenuNode('Person', 'SELECT Person', $oContactNode->GetIndex(), 1 /* fRank */);
new OQLMenuNode('Team', 'SELECT Team', $oContactNode->GetIndex(), 2 /* fRank */);
new NewObjectMenuNode('NewContact', 'Contact', $oContactNode->GetIndex(), 1 /* fRank */);
new SearchMenuNode('SearchContacts', 'Contact', $oContactNode->GetIndex(), 2 /* fRank */);
new OQLMenuNode('Person', 'SELECT Person', $oContactNode->GetIndex(), 3 /* fRank */);
new OQLMenuNode('Team', 'SELECT Team', $oContactNode->GetIndex(), 4 /* fRank */);
new OQLMenuNode('Document', 'SELECT Document', $oConfigManagementGroup->GetIndex(), 2 /* fRank */);
new OQLMenuNode('Location', 'SELECT Location', $oConfigManagementGroup->GetIndex(), 3 /* fRank */);
new OQLMenuNode('Document', 'SELECT Document', $oConfigManagementGroup->GetIndex(), 2 /* fRank */, true /* bSearch */);
new OQLMenuNode('Location', 'SELECT Location', $oConfigManagementGroup->GetIndex(), 3 /* fRank */, true /* bSearch */);
$oCINode = new TemplateMenuNode('ConfigManagementCI', '../modules/itop-config-mgmt-1.0.0/cis_menu.html', $oConfigManagementGroup->GetIndex(), 4 /* fRank */);
new NewObjectMenuNode('NewCI', 'FunctionalCI', $oCINode->GetIndex(), 0 /* fRank */);
new SearchMenuNode('SearchCIs', 'FunctionalCI', $oCINode->GetIndex(), 1 /* fRank */);
new OQLMenuNode('BusinessProcess', 'SELECT BusinessProcess', $oCINode->GetIndex(), 0 /* fRank */);
new OQLMenuNode('ApplicationSolution', 'SELECT ApplicationSolution', $oCINode->GetIndex(), 1 /* fRank */);
new OQLMenuNode('BusinessProcess', 'SELECT BusinessProcess', $oCINode->GetIndex(), 2 /* fRank */);
new OQLMenuNode('ApplicationSolution', 'SELECT ApplicationSolution', $oCINode->GetIndex(), 3 /* fRank */);
$oSWNode = new TemplateMenuNode('ConfigManagementSoftware', '', $oCINode->GetIndex(), 2 /* fRank */);
$oSWNode = new TemplateMenuNode('ConfigManagementSoftware', '', $oCINode->GetIndex(), 4 /* fRank */);
new OQLMenuNode('Licence', 'SELECT Licence', $oSWNode->GetIndex(), 0 /* fRank */);
new OQLMenuNode('Patch', 'SELECT Patch', $oSWNode->GetIndex(), 1 /* fRank */);
new OQLMenuNode('ApplicationInstance', 'SELECT SoftwareInstance', $oSWNode->GetIndex(), 2 /* fRank */);
$oHWNode = new TemplateMenuNode('ConfigManagementHardware', '', $oCINode->GetIndex(), 3 /* fRank */);
$oHWNode = new TemplateMenuNode('ConfigManagementHardware', '', $oCINode->GetIndex(), 5 /* fRank */);
new OQLMenuNode('Subnet', 'SELECT Subnet', $oHWNode->GetIndex(), 0 /* fRank */);
new OQLMenuNode('NetworkDevice', 'SELECT NetworkDevice', $oHWNode->GetIndex(), 1 /* fRank */);
new OQLMenuNode('Server', 'SELECT Server', $oHWNode->GetIndex(), 2 /* fRank */);

View File

@@ -28,6 +28,12 @@ Dict::Add('EN US', 'English', 'English', array(
'Menu:IncidentManagement+' => 'Incident Management',
'Menu:Incident:Overview' => 'Overview',
'Menu:Incident:Overview+' => 'Overview',
'Menu:NewIncident' => 'New Incident',
'Menu:NewIncident+' => 'Create a new Incident ticket',
'Menu:SearchIncidents' => 'Search for Incidents',
'Menu:SearchIncidents+' => 'Search for Incident tickets',
'Menu:Incident:Shortcuts' => 'Shortcuts',
'Menu:Incident:Shortcuts+' => '',
'Menu:Incident:MyIncidents' => 'Incidents assigned to me',
'Menu:Incident:MyIncidents+' => 'Incidents assigned to me (as Agent)',
'Menu:Incident:EscalatedIncidents' => 'Escalated Incidents',

View File

@@ -28,6 +28,12 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Menu:IncidentManagement+' => 'Gestión de Incidentes',
'Menu:Incident:Overview' => 'Visión General',
'Menu:Incident:Overview+' => 'Visión General',
'Menu:NewIncident' => 'New Incident',
'Menu:NewIncident+' => 'Create a new Incident ticket',
'Menu:SearchIncidents' => 'Search for Incidents',
'Menu:SearchIncidents+' => 'Search for Incident tickets',
'Menu:Incident:Shortcuts' => 'Shortcuts',
'Menu:Incident:Shortcuts+' => '',
'Menu:Incident:MyIncidents' => 'Incidentes asignados a mí',
'Menu:Incident:MyIncidents+' => 'Incidentes asignados a mí (como Agente)',
'Menu:Incident:EscalatedIncidents' => 'Incidentes Escalados',

View File

@@ -28,6 +28,12 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Menu:IncidentManagement+' => 'Gestion des incidents',
'Menu:Incident:Overview' => 'Vue d\'ensemble',
'Menu:Incident:Overview+' => 'Vue d\'ensemble',
'Menu:NewIncident' => 'Nouvel Incident',
'Menu:NewIncident+' => 'Créer un nouveau ticket d\'incident',
'Menu:SearchIncidents' => 'Rechercher des incidents',
'Menu:SearchIncidents+' => 'Rechercher parmi les tickets d\'incidents',
'Menu:Incident:Shortcuts' => 'Raccourcis',
'Menu:Incident:Shortcuts+' => '',
'Menu:Incident:MyIncidents' => 'Mes tickets',
'Menu:Incident:MyIncidents+' => 'Tickets d\'incident qui me sont assignés',
'Menu:Incident:EscalatedIncidents' => 'Ticket en cours d\'escalade',

View File

@@ -96,8 +96,11 @@ class Incident extends ResponseTicket
$oMyMenuGroup = new MenuGroup('IncidentManagement', 40 /* fRank */);
new TemplateMenuNode('Incident:Overview', '../modules/itop-incident-mgmt-1.0.0/overview.html', $oMyMenuGroup->GetIndex() /* oParent */, 0 /* fRank */);
new OQLMenuNode('Incident:MyIncidents', 'SELECT Incident WHERE agent_id = :current_contact_id', $oMyMenuGroup->GetIndex(), 1 /* fRank */);
new OQLMenuNode('Incident:EscalatedIncidents', 'SELECT Incident WHERE status IN ("escalated_tto", "escalated_ttr")', $oMyMenuGroup->GetIndex(), 2 /* fRank */);
new OQLMenuNode('Incident:OpenIncidents', 'SELECT Incident WHERE status IN ("new", "assigned", "escalated_tto", "escalated_ttr", "resolved")', $oMyMenuGroup->GetIndex(), 3 /* fRank */);
new NewObjectMenuNode('NewIncident', 'Incident', $oMyMenuGroup->GetIndex(), 1 /* fRank */);
new SearchMenuNode('SearchIncidents', 'Incident', $oMyMenuGroup->GetIndex(), 2 /* fRank */);
$oShortcutNode = new TemplateMenuNode('Incident:Shortcuts', '', $oMyMenuGroup->GetIndex(), 3 /* fRank */);
new OQLMenuNode('Incident:MyIncidents', 'SELECT Incident WHERE agent_id = :current_contact_id', $oShortcutNode->GetIndex(), 1 /* fRank */);
new OQLMenuNode('Incident:EscalatedIncidents', 'SELECT Incident WHERE status IN ("escalated_tto", "escalated_ttr")', $oShortcutNode->GetIndex(), 2 /* fRank */);
new OQLMenuNode('Incident:OpenIncidents', 'SELECT Incident WHERE status IN ("new", "assigned", "escalated_tto", "escalated_ttr", "resolved")', $oShortcutNode->GetIndex(), 3 /* fRank */);
?>

View File

@@ -28,6 +28,12 @@ Dict::Add('EN US', 'English', 'English', array(
'Menu:RequestManagement+' => 'Helpdesk',
'Menu:UserRequest:Overview' => 'Overview',
'Menu:UserRequest:Overview+' => 'Overview',
'Menu:NewUserRequest' => 'New User Request',
'Menu:NewUserRequest+' => 'Create a new User Request ticket',
'Menu:SearchUserRequests' => 'Search for User Requests',
'Menu:SearchUserRequests+' => 'Search for User Request tickets',
'Menu:UserRequest:Shortcuts' => 'Shortcuts',
'Menu:UserRequest:Shortcuts+' => '',
'Menu:UserRequest:MyRequests' => 'Requests assigned to me',
'Menu:UserRequest:MyRequests+' => 'Requests assigned to me (as Agent)',
'Menu:UserRequest:EscalatedRequests' => 'Escalated Requests',

View File

@@ -28,6 +28,12 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Menu:RequestManagement+' => 'Servicio de ayuda',
'Menu:UserRequest:Overview' => 'Visión General',
'Menu:UserRequest:Overview+' => 'Visión General',
'Menu:NewUserRequest' => 'New User Request',
'Menu:NewUserRequest+' => 'Create a new User Request ticket',
'Menu:SearchUserRequests' => 'Search for User Requests',
'Menu:SearchUserRequests+' => 'Search for User Request tickets',
'Menu:UserRequest:Shortcuts' => 'Shortcuts',
'Menu:UserRequest:Shortcuts+' => '',
'Menu:UserRequest:MyRequests' => 'Solicitudes asignadas a mí',
'Menu:UserRequest:MyRequests+' => 'Solicitudes asignadas a mí (como Agente)',
'Menu:UserRequest:EscalatedRequests' => 'Solicitudes Escaladas',

View File

@@ -28,6 +28,12 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Menu:RequestManagement+' => 'Gestion des demandes utilisateurs',
'Menu:UserRequest:Overview' => 'Vue d\'ensemble',
'Menu:UserRequest:Overview+' => 'Vue d\'ensemble des demandes utilisateurs',
'Menu:NewUserRequest' => 'Nouvelle demande utilisateur',
'Menu:NewUserRequest+' => 'Créer un nouveau ticket de demande utilisateur',
'Menu:SearchUserRequests' => 'Rechercher des demandes utilisateur',
'Menu:SearchUserRequests+' => 'Rechercher parmi les demandes utilisateur',
'Menu:UserRequest:Shortcuts' => 'Raccourcis',
'Menu:UserRequest:Shortcuts+' => '',
'Menu:UserRequest:MyRequests' => 'Mes demandes',
'Menu:UserRequest:MyRequests+' => 'Demandes utilisateurs qui me sont assignées',
'Menu:UserRequest:EscalatedRequests' => 'Demandes en escalade',

View File

@@ -86,8 +86,11 @@ class UserRequest extends ResponseTicket
$oMyMenuGroup = new MenuGroup('RequestManagement', 30 /* fRank */);
new TemplateMenuNode('UserRequest:Overview', '../modules/itop-request-mgmt-1.0.0/overview.html', $oMyMenuGroup->GetIndex() /* oParent */, 0 /* fRank */);
new OQLMenuNode('UserRequest:MyRequests', 'SELECT UserRequest WHERE agent_id = :current_contact_id', $oMyMenuGroup->GetIndex(), 1 /* fRank */);
new OQLMenuNode('UserRequest:EscalatedRequests', 'SELECT UserRequest WHERE status IN ("escalated_tto", "escalated_ttr")', $oMyMenuGroup->GetIndex(), 2 /* fRank */);
new OQLMenuNode('UserRequest:OpenRequests', 'SELECT UserRequest WHERE status IN ("new", "assigned", "escalated_tto", "escalated_ttr", "frozen", "resolved")', $oMyMenuGroup->GetIndex(), 3 /* fRank */);
new NewObjectMenuNode('NewUserRequest', 'UserRequest', $oMyMenuGroup->GetIndex(), 1 /* fRank */);
new SearchMenuNode('SearchUserRequests', 'UserRequest', $oMyMenuGroup->GetIndex(), 2 /* fRank */);
$oShortcutNode = new TemplateMenuNode('UserRequest:Shortcuts', '', $oMyMenuGroup->GetIndex(), 3 /* fRank */);
new OQLMenuNode('UserRequest:MyRequests', 'SELECT UserRequest WHERE agent_id = :current_contact_id', $oShortcutNode->GetIndex(), 1 /* fRank */);
new OQLMenuNode('UserRequest:EscalatedRequests', 'SELECT UserRequest WHERE status IN ("escalated_tto", "escalated_ttr")', $oShortcutNode->GetIndex(), 2 /* fRank */);
new OQLMenuNode('UserRequest:OpenRequests', 'SELECT UserRequest WHERE status IN ("new", "assigned", "escalated_tto", "escalated_ttr", "frozen", "resolved")', $oShortcutNode->GetIndex(), 3 /* fRank */);
?>

View File

@@ -407,7 +407,7 @@ function UpdateObject(&$oObj)
{
// Non-visible, or read-only attribute, do nothing
}
else if ($oAttDef->GetEditClass() == 'Document')
elseif ($oAttDef->GetEditClass() == 'Document')
{
// There should be an uploaded file with the named attr_<attCode>
$oDocument = utils::ReadPostedDocument('file_'.$sAttCode);
@@ -417,6 +417,17 @@ function UpdateObject(&$oObj)
$oObj->Set($sAttCode, $oDocument);
}
}
elseif ($oAttDef->GetEditClass() == 'One Way Password')
{
// Check if the password was typed/changed
$bChanged = utils::ReadPostedParam("attr_{$sAttCode}_changed", false);
if ($bChanged)
{
// The password has been changed or set
$rawValue = utils::ReadPostedParam("attr_$sAttCode", null);
$oObj->Set($sAttCode, $rawValue);
}
}
else
{
$rawValue = utils::ReadPostedParam("attr_$sAttCode", null);
@@ -769,7 +780,7 @@ try
{
foreach($aSubClasses as $sCandidateClass)
{
if (!MetaModel::IsAbstract($sCandidateClass))
if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES))
{
$aPossibleClasses[$sCandidateClass] = MetaModel::GetName($sCandidateClass);
}