diff --git a/addons/userrights/userrightsprofile.class.inc.php b/addons/userrights/userrightsprofile.class.inc.php index 9039cea2c..0e38717d5 100644 --- a/addons/userrights/userrightsprofile.class.inc.php +++ b/addons/userrights/userrightsprofile.class.inc.php @@ -380,7 +380,7 @@ class UserRightsProfile extends UserRightsAddOnAPI $oContact = new Person(); $oContact->Set('name', 'My last name'); - //$oContact->Set('first_name', 'My first name'); + $oContact->Set('first_name', 'My first name'); //$oContact->Set('status', 'available'); $oContact->Set('org_id', $iOrgId); $oContact->Set('email', 'my.email@foo.org'); @@ -421,7 +421,6 @@ class UserRightsProfile extends UserRightsAddOnAPI { SetupProfiles::ComputeITILProfiles(); //SetupProfiles::ComputeBasicProfiles(); - SetupProfiles::DoCreateProfiles(); return true; } @@ -562,16 +561,17 @@ exit; { // load and cache permissions for the current user on the given class // - $aTest = @$this->m_aObjectActionGrants[$oUser->GetKey()][$sClass][$iActionCode]; + $iUser = $oUser->GetKey(); + $aTest = @$this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode]; if (is_array($aTest)) return $aTest; $sAction = self::$m_aActionCodes[$iActionCode]; $iInstancePermission = UR_ALLOWED_NO; $aAttributes = array(); - if (isset($this->m_aUserProfiles[$oUser->GetKey()])) + if (isset($this->m_aUserProfiles[$iUser])) { - foreach($this->m_aUserProfiles[$oUser->GetKey()] as $iProfile => $oProfile) + foreach($this->m_aUserProfiles[$iUser] as $iProfile => $oProfile) { $oGrantRecord = $this->GetProfileActionGrant($iProfile, $sClass, $sAction); if (is_null($oGrantRecord)) @@ -604,7 +604,7 @@ exit; 'permission' => $iInstancePermission, 'attributes' => $aAttributes, ); - $this->m_aObjectActionGrants[$oUser->GetKey()][$sClass][$iActionCode] = $aRes; + $this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode] = $aRes; return $aRes; } @@ -728,13 +728,14 @@ exit; public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null) { // Note: this code is VERY close to the code of IsActionAllowed() + $iUser = $oUser->GetKey(); if (is_null($oInstanceSet)) { $iInstancePermission = UR_ALLOWED_NO; - if (isset($this->m_aUserProfiles[$oUser->GetKey()])) + if (isset($this->m_aUserProfiles[$iUser])) { - foreach($this->m_aUserProfiles[$oUser->GetKey()] as $iProfile => $oProfile) + foreach($this->m_aUserProfiles[$iUser] as $iProfile => $oProfile) { $oGrantRecord = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode); if (!is_null($oGrantRecord)) @@ -751,9 +752,9 @@ exit; while($oObject = $oInstanceSet->Fetch()) { $iInstancePermission = UR_ALLOWED_NO; - if (isset($this->m_aUserProfiles[$oUser->GetKey()])) + if (isset($this->m_aUserProfiles[$iUser])) { - foreach($this->m_aUserProfiles[$oUser->GetKey()] as $iProfile => $oProfile) + foreach($this->m_aUserProfiles[$iUser] as $iProfile => $oProfile) { $oGrantRecord = $this->GetClassStimulusGrant($iProfile, get_class($oObject), $sStimulusCode); if (!is_null($oGrantRecord)) diff --git a/addons/userrights/userrightsprojection.class.inc.php b/addons/userrights/userrightsprojection.class.inc.php index 077d451af..dc4aab1f2 100644 --- a/addons/userrights/userrightsprojection.class.inc.php +++ b/addons/userrights/userrightsprojection.class.inc.php @@ -616,7 +616,7 @@ class UserRightsProjection extends UserRightsAddOnAPI $oContact = new Person(); $oContact->Set('name', 'My last name'); - //$oContact->Set('first_name', 'My first name'); + $oContact->Set('first_name', 'My first name'); //$oContact->Set('status', 'available'); $oContact->Set('org_id', $iOrgId); $oContact->Set('email', 'my.email@foo.org'); diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php index d4c14dd5d..d541eeef6 100644 --- a/core/attributedef.class.inc.php +++ b/core/attributedef.class.inc.php @@ -160,7 +160,6 @@ abstract class AttributeDefinition public function IsExternalField() {return false;} public function IsWritable() {return false;} public function IsNullAllowed() {return true;} - public function GetNullValue() {return null;} public function GetCode() {return $this->m_sCode;} public function GetLabel() {return Dict::S('Class:'.$this->m_sHostClass.'/Attribute:'.$this->m_sCode, $this->m_sCode);} public function GetLabel_Obsolete() @@ -192,6 +191,9 @@ abstract class AttributeDefinition public function GetValuesDef() {return null;} public function GetPrerequisiteAttributes() {return array();} + public function GetNullValue() {return null;} + public function IsNull($proposedValue) {return is_null($proposedValue);} + public function MakeRealValue($proposedValue) {return $proposedValue;} // force an allowed value (type conversion and possibly forces a value as mySQL would do upon writing!) public function GetSQLExpressions() {return array();} // returns suffix/expression pairs (1 in most of the cases), for READING (Select) @@ -205,7 +207,7 @@ abstract class AttributeDefinition return ''; } - public function CheckValue($value) + public function CheckFormat($value) { return true; } @@ -544,12 +546,22 @@ class AttributeInteger extends AttributeDBField } } + public function GetNullValue() + { + return null; + } + public function IsNull($proposedValue) + { + return is_null($proposedValue); + } + public function MakeRealValue($proposedValue) { - //return intval($proposedValue); could work as well + if (is_null($proposedValue)) return null; if ($proposedValue == '') return null; return (int)$proposedValue; } + public function ScalarToSQL($value) { assert(is_numeric($value) || is_null($value)); @@ -577,9 +589,12 @@ class AttributeBoolean extends AttributeInteger public function MakeRealValue($proposedValue) { + if (is_null($proposedValue)) return null; + if ($proposedValue == '') return null; if ((int)$proposedValue) return true; return false; } + public function ScalarToSQL($value) { assert(is_bool($value)); @@ -606,7 +621,7 @@ class AttributeString extends AttributeDBField public function GetEditClass() {return "String";} protected function GetSQLCol() {return "VARCHAR(255)";} - public function CheckValue($value) + public function CheckFormat($value) { $sRegExp = $this->GetValidationPattern(); if (empty($sRegExp)) @@ -659,15 +674,22 @@ class AttributeString extends AttributeDBField } } + public function GetNullValue() + { + return ''; + } + + public function IsNull($proposedValue) + { + return ($proposedValue == ''); + } + public function MakeRealValue($proposedValue) { - if (is_null($proposedValue)) return null; + if (is_null($proposedValue)) return ''; return (string)$proposedValue; - // if (!settype($proposedValue, "string")) - // { - // throw new CoreException("Failed to change the type of '$proposedValue' to a string"); - // } } + public function ScalarToSQL($value) { if (!is_string($value) && !is_null($value)) @@ -1029,14 +1051,6 @@ class AttributeEnum extends AttributeString } return $aLocalizedValues; } - - public function MakeRealValue($proposedValue) - { - // For an enum, let's consider an empty value like a null value - // Could be implemented by changing the UI : no value => let the default value - if ($proposedValue == '') return null; - return parent::MakeRealValue($proposedValue); - } } /** @@ -1420,7 +1434,6 @@ class AttributeExternalKey extends AttributeDBFieldVoid public function GetDefaultValue() {return 0;} public function IsNullAllowed() {return $this->Get("is_null_allowed");} - public function GetNullValue() {return 0;} public function GetBasicFilterOperators() { @@ -1468,8 +1481,20 @@ class AttributeExternalKey extends AttributeDBFieldVoid return $this->Get("on_target_delete"); } + public function GetNullValue() + { + return 0; + } + + public function IsNull($proposedValue) + { + return ($proposedValue == 0); + } + public function MakeRealValue($proposedValue) { + if (is_null($proposedValue)) return 0; + if (MetaModel::IsValidObject($proposedValue)) return $proposedValue->GetKey(); return (int)$proposedValue; } } @@ -1619,11 +1644,24 @@ class AttributeExternalField extends AttributeDefinition return $oExtAttDef->GetBasicFilterSQLExpr($sOpCode, $value); } + public function GetNullValue() + { + $oExtAttDef = $this->GetExtAttDef(); + return $oExtAttDef->GetNullValue(); + } + + public function IsNull($proposedValue) + { + $oExtAttDef = $this->GetExtAttDef(); + return $oExtAttDef->IsNull($proposedValue); + } + public function MakeRealValue($proposedValue) { $oExtAttDef = $this->GetExtAttDef(); return $oExtAttDef->MakeRealValue($proposedValue); } + public function ScalarToSQL($value) { // This one could be used in case of filtering only diff --git a/core/bulkchange.class.inc.php b/core/bulkchange.class.inc.php index 16b0cb18f..7abffa53a 100644 --- a/core/bulkchange.class.inc.php +++ b/core/bulkchange.class.inc.php @@ -320,13 +320,15 @@ class BulkChange // skip the private key, if any if ($sAttCode == 'id') continue; - if (!$oTargetObj->CheckValue($sAttCode, $aRowData[$iCol])) + $res = $oTargetObj->CheckValue($sAttCode, $aRowData[$iCol]); + if ($res === true) { - $aErrors[$sAttCode] = "Unexpected value"; + $oTargetObj->Set($sAttCode, $aRowData[$iCol]); } else { - $oTargetObj->Set($sAttCode, $aRowData[$iCol]); + // $res is a string with the error description + $aErrors[$sAttCode] = "Unexpected value for attribute '$sAttCode': $res"; } } @@ -363,9 +365,11 @@ class BulkChange // Checks // - if (!$oTargetObj->CheckConsistency()) + $res = $oTargetObj->CheckConsistency(); + if ($res !== true) { - $aErrors["GLOBAL"] = "Attributes not consistent with each others"; + // $res contains the error description + $aErrors["GLOBAL"] = "Attributes not consistent with each others: $res"; } return $aResults; } diff --git a/core/coreexception.class.inc.php b/core/coreexception.class.inc.php index da1094b81..b11da9003 100644 --- a/core/coreexception.class.inc.php +++ b/core/coreexception.class.inc.php @@ -107,4 +107,8 @@ class CoreWarning extends CoreException { } +class CoreUnexpectedValue extends CoreException +{ +} + ?> diff --git a/core/dbobject.class.php b/core/dbobject.class.php index 751ec3987..add8bed3a 100644 --- a/core/dbobject.class.php +++ b/core/dbobject.class.php @@ -41,6 +41,9 @@ abstract class DBObject private $m_bDirty = false; // Means: "a modification is ongoing" // The object may have incorrect external keys, then any attempt of reload must be avoided + private $m_bCheckStatus = null; // Means: the object has been verified and is consistent with integrity rules + // if null, then the check has to be performed again to know the status + // otherwise, private $m_bFullyLoaded = false; // Compound objects can be partially loaded private $m_aLoadedAtt = array(); // Compound objects can be partially loaded, array of sAttCode @@ -194,6 +197,7 @@ abstract class DBObject $this->m_aCurrValues = array(); $this->m_aOrigValues = array(); $this->m_aLoadedAtt = array(); + $this->m_bCheckStatus = true; // Get the key // @@ -251,13 +255,8 @@ abstract class DBObject if ($sAttCode == 'finalclass') { // Ignore it - this attribute is set upon object creation and that's it - //throw new CoreWarning('Attempting to set the value for the internal attribute \"finalclass\"', array('current value'=>$this->Get('finalclass'), 'new value'=>$value)); return; } - if (!array_key_exists($sAttCode, MetaModel::ListAttributeDefs(get_class($this)))) - { - throw new CoreException("Unknown attribute code '$sAttCode' for the class ".get_class($this)); - } $oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode); if ($this->m_bIsInDB && !$this->m_bFullyLoaded && !$this->m_bDirty) { @@ -266,12 +265,7 @@ abstract class DBObject // + consistency does not make sense ! $this->Reload(); } - if($oAttDef->IsScalar() && !$oAttDef->IsNullAllowed() && is_null($value)) - { - throw new CoreWarning("null not allowed for attribute '$sAttCode', setting default value"); - $this->m_aCurrValues[$sAttCode] = $oAttDef->GetDefaultValue(); - return; - } + if ($oAttDef->IsExternalKey() && is_object($value)) { // Setting an external key with a whole object (instead of just an ID) @@ -279,11 +273,11 @@ abstract class DBObject // (useful when building objects in memory and not from a query) if ( (get_class($value) != $oAttDef->GetTargetClass()) && (!is_subclass_of($value, $oAttDef->GetTargetClass()))) { - throw new CoreWarning("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_aCurrValues[$sAttCode] = $oAttDef->GetDefaultValue(); + 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"); } else { + $this->m_bCheckStatus = null; $this->m_aCurrValues[$sAttCode] = $value->GetKey(); foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sCode => $oDef) { @@ -297,17 +291,13 @@ abstract class DBObject } if(!$oAttDef->IsScalar() && !is_object($value)) { - throw new CoreWarning("scalar not allowed for attribute '$sAttCode', setting default value (empty list)"); - $this->m_aCurrValues[$sAttCode] = $oAttDef->GetDefaultValue(); - return; + throw new CoreUnexpectedValue("scalar not allowed for attribute '$sAttCode', setting default value (empty list)"); } if($oAttDef->IsLinkSet()) { if((get_class($value) != 'DBObjectSet') && !is_subclass_of($value, 'DBObjectSet')) { - throw new CoreWarning("expecting a set of persistent objects (found a '".get_class($value)."'), setting default value (empty list)"); - $this->m_aCurrValues[$sAttCode] = $oAttDef->GetDefaultValue(); - return; + throw new CoreUnexpectedValue("expecting a set of persistent objects (found a '".get_class($value)."'), setting default value (empty list)"); } $oObjectSet = $value; @@ -316,18 +306,17 @@ abstract class DBObject // not working fine :-( if (!is_subclass_of($sSetClass, $sLinkClass)) if ($sSetClass != $sLinkClass) { - throw new CoreWarning("expecting a set of '$sLinkClass' objects (found a set of '$sSetClass'), setting default value (empty list)"); - $this->m_aCurrValues[$sAttCode] = $oAttDef->GetDefaultValue(); - return; + throw new CoreUnexpectedValue("expecting a set of '$sLinkClass' objects (found a set of '$sSetClass'), setting default value (empty list)"); } } - if ($oAttDef->CheckValue($value)) - { - $this->m_aCurrValues[$sAttCode] = $oAttDef->MakeRealValue($value); - $this->RegisterAsDirty(); // Make sure we do not reload it anymore... before saving it - } + + $realvalue = $oAttDef->MakeRealValue($value); + $this->m_aCurrValues[$sAttCode] = $realvalue; + + $this->m_bCheckStatus = null; + $this->RegisterAsDirty(); // Make sure we do not reload it anymore... before saving it } - + public function Get($sAttCode) { if (!array_key_exists($sAttCode, MetaModel::ListAttributeDefs(get_class($this)))) @@ -599,6 +588,8 @@ abstract class DBObject } // check if the given (or current) value is suitable for the attribute + // return true if successfull + // return the error desciption otherwise public function CheckValue($sAttCode, $value = null) { if (!is_null($value)) @@ -611,44 +602,46 @@ abstract class DBObject } $oAtt = MetaModel::GetAttributeDef(get_class($this), $sAttCode); - if ($oAtt->IsExternalKey()) + if (!$oAtt->IsWritable()) { - if (!$oAtt->IsNullAllowed() || ($toCheck != 0) ) + return true; + } + elseif ($oAtt->IsNull($toCheck)) + { + if ($oAtt->IsNullAllowed()) { - try - { - $oTargetObj = MetaModel::GetObject($oAtt->GetTargetClass(), $toCheck); - return true; - } - catch (CoreException $e) - { - return false; - } + return true; + } + else + { + return "Null not allowed"; } } - elseif ($oAtt->IsWritable() && $oAtt->IsScalar()) + elseif ($oAtt->IsExternalKey()) { - if (is_null($toCheck)) + $sTargetClass = $oAtt->GetTargetClass(); + $oTargetObj = MetaModel::GetObject($sTargetClass, $toCheck, false /*must be found*/, true /*allow all data*/); + if (is_null($oTargetObj)) { - if ($oAtt->IsNullAllowed()) - { - return true; - } - else - { - return false; - } + return "Target object not found ($sTargetClass::$toCheck)"; } - $aValues = $oAtt->GetAllowedValues(); + } + elseif ($oAtt->IsScalar()) + { + $aValues = $oAtt->GetAllowedValues($this->ToArgs()); if (count($aValues) > 0) { if (!array_key_exists($toCheck, $aValues)) { - return false; + return "Value not allowed [$toCheck]"; } } + elseif (!$oAtt->CheckFormat($toCheck)) + { + return "Wrong format [$toCheck]"; + } } - return $oAtt->CheckValue($toCheck); // Check the format + return true; } // check attributes together @@ -657,45 +650,57 @@ abstract class DBObject return true; } - // check if it is allowed to record the new object into the database + // check integrity rules (before inserting or updating the object) // a displayable error is returned - // Note: checks the values and consistency - public function CheckToInsert() + public function DoCheckToWrite() { - $aIssues = array(); + $this->m_aCheckIssues = array(); + foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef) { - if (!$this->CheckValue($sAttCode)) + $res = $this->CheckValue($sAttCode); + if ($res !== true) { - $aIssues[$sAttCode] = array( - 'issue' => 'unexpected value' - ); + // $res contains the error description + $this->m_aCheckIssues[] = "Unexpected value for attribute '$sAttCode': $res"; } } - if (count($aIssues) > 0) + if (count($this->m_aCheckIssues) > 0) { - return array(false, $aIssues); + // No need to check consistency between attributes if any of them has + // an unexpected value + return; } - if (!$this->CheckConsistency()) + $res = $this->CheckConsistency(); + if ($res !== true) { - return array(false, $aIssues); + // $res contains the error description + $this->m_aCheckIssues[] = "Consistency rules not followed: $res"; } - return array(true, $aIssues); } - // check if it is allowed to update the existing object into the database - // a displayable error is returned - // Note: checks the values and consistency - public function CheckToUpdate() + final public function CheckToWrite() { - foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef) + if (false) { - if (!$this->CheckValue($sAttCode)) return false; + return array(true, array()); } - if (!$this->CheckConsistency()) return false; - return true; + + if (is_null($this->m_bCheckStatus)) + { + $this->DoCheckToWrite(); + if (count($this->m_aCheckIssues) == 0) + { + $this->m_bCheckStatus = true; + } + else + { + $this->m_bCheckStatus = false; + } + } + return array($this->m_bCheckStatus, $this->m_aCheckIssues); } - + // check if it is allowed to delete the existing object from the database // a displayable error is returned public function CheckToDelete() @@ -863,10 +868,17 @@ abstract class DBObject { if (empty($this->m_iKey)) { - throw new CoreWarning("Missing key for the object to write - This class is supposed to have a user defined key, not an autonumber"); + throw new CoreWarning("Missing key for the object to write - This class is supposed to have a user defined key, not an autonumber", array('class' => $sRootClass)); } } + // Ultimate check - ensure DB integrity + list($bRes, $aIssues) = $this->CheckToWrite(); + if (!$bRes) + { + throw new CoreException("Object not following integrity rules - it will not be written into the DB", array('class' => $sClass, 'id' => $this->GetKey(), 'issues' => $aIssues)); + } + // First query built upon on the root class, because the ID must be created first $this->m_iKey = $this->DBInsertSingleTable($sRootClass); @@ -951,6 +963,14 @@ abstract class DBObject //throw new CoreWarning("Attempting to update an unchanged object"); return; } + + // Ultimate check - ensure DB integrity + list($bRes, $aIssues) = $this->CheckToWrite(); + if (!$bRes) + { + throw new CoreException("Object not following integrity rules - it will not be written into the DB", array('class' => get_class($this), 'id' => $this->GetKey(), 'issues' => $aIssues)); + } + $bHasANewExternalKeyValue = false; foreach($aChanges as $sAttCode => $valuecurr) { diff --git a/core/metamodel.class.php b/core/metamodel.class.php index 83c1b01ae..b18a23dba 100644 --- a/core/metamodel.class.php +++ b/core/metamodel.class.php @@ -3257,7 +3257,7 @@ abstract class MetaModel return $iTotalHits.' ('.implode(', ', $aRes).')'; } - public static function MakeSingleRow($sClass, $iKey, $bMustBeFound = true) + public static function MakeSingleRow($sClass, $iKey, $bMustBeFound = true, $bAllowAllData = false) { if (!array_key_exists($sClass, self::$aQueryCacheGetObject)) { @@ -3268,6 +3268,10 @@ abstract class MetaModel // or a view... next optimization to come! $oFilter = new DBObjectSearch($sClass); $oFilter->AddCondition('id', 987654321, '='); + if ($bAllowAllData) + { + $oFilter->AllowAllData(); + } $sSQL = self::MakeSelectQuery($oFilter); self::$aQueryCacheGetObject[$sClass] = $sSQL; @@ -3323,10 +3327,10 @@ abstract class MetaModel return new $sClass($aRow, $sClassAlias); } - public static function GetObject($sClass, $iKey, $bMustBeFound = true) + public static function GetObject($sClass, $iKey, $bMustBeFound = true, $bAllowAllData = false) { self::_check_subclass($sClass); - $aRow = self::MakeSingleRow($sClass, $iKey, $bMustBeFound); + $aRow = self::MakeSingleRow($sClass, $iKey, $bMustBeFound, $bAllowAllData); if (empty($aRow)) { return null; diff --git a/core/test.class.inc.php b/core/test.class.inc.php index dd45d16e5..30949936c 100644 --- a/core/test.class.inc.php +++ b/core/test.class.inc.php @@ -395,10 +395,10 @@ abstract class TestBizModel extends TestHandler protected $m_oChange; protected function ObjectToDB($oNew, $bReload = false) { - list($bRes, $aIssues) = $oNew->CheckToInsert(); + list($bRes, $aIssues) = $oNew->CheckToWrite(); if (!$bRes) { - throw new CoreException('Could not create object, unexpected values', array('attributes' => $aIssues)); + throw new CoreException('Could not create object, unexpected values', array('issues' => $aIssues)); } if ($oNew instanceof CMDBObject) { diff --git a/core/userrights.class.inc.php b/core/userrights.class.inc.php index bd4e91e72..e4efc8467 100644 --- a/core/userrights.class.inc.php +++ b/core/userrights.class.inc.php @@ -498,8 +498,8 @@ class UserRights // Need to load some records before the login is performed (user preferences) if (MetaModel::HasCategory($sClass, 'alwaysreadable')) return true; - // ne marche pas... pourquoi? - //if (!self::CheckLogin()) return false; + // When initializing, we need to let everything pass trough + if (!self::CheckLogin()) return true; if (self::IsAdministrator()) return true; @@ -514,7 +514,9 @@ class UserRights public static function IsActionAllowed($sClass, $iActionCode, /*dbObjectSet*/ $oInstanceSet = null, $oUser = null) { - if (!self::CheckLogin()) return false; + // When initializing, we need to let everything pass trough + if (!self::CheckLogin()) return true; + if (self::IsAdministrator($oUser)) return true; @@ -537,7 +539,9 @@ class UserRights public static function IsStimulusAllowed($sClass, $sStimulusCode, /*dbObjectSet*/ $oInstanceSet = null, $oUser = null) { - if (!self::CheckLogin()) return false; + // When initializing, we need to let everything pass trough + if (!self::CheckLogin()) return true; + if (self::IsAdministrator($oUser)) return true; // this module is forbidden for non admins @@ -555,8 +559,8 @@ class UserRights public static function IsActionAllowedOnAttribute($sClass, $sAttCode, $iActionCode, /*dbObjectSet*/ $oInstanceSet = null, $oUser = null) { - if (!self::CheckLogin()) return false; - if (self::IsAdministrator($oUser)) return true; + // When initializing, we need to let everything pass trough + if (!self::CheckLogin()) return true; // this module is forbidden for non admins if (MetaModel::HasCategory($sClass, 'addon/userrights')) return false; diff --git a/dictionaries/dictionary.itop.ui.php b/dictionaries/dictionary.itop.ui.php index b71d888e4..eddc4b8d4 100644 --- a/dictionaries/dictionary.itop.ui.php +++ b/dictionaries/dictionary.itop.ui.php @@ -159,6 +159,25 @@ Dict::Add('EN US', 'English', 'English', array( 'Class:URP_UserProfile/Attribute:reason+' => 'explain why this person may have this role', )); +// +// Class: URP_UserOrg +// + +Dict::Add('EN US', 'English', 'English', array( + 'Class:URP_UserOrg' => 'User organizations', + 'Class:URP_UserOrg+' => 'Allowed organizations', + 'Class:URP_UserProfile/Attribute:userid' => 'User', + 'Class:URP_UserProfile/Attribute:userid+' => 'user account', + 'Class:URP_UserProfile/Attribute:userlogin' => 'Login', + 'Class:URP_UserProfile/Attribute:userlogin+' => 'User\'s login', + 'Class:URP_UserProfile/Attribute:allowed_org_id' => 'Organization', + 'Class:URP_UserProfile/Attribute:allowed_org_id+' => 'Allowed organization', + 'Class:URP_UserProfile/Attribute:allowed_org_name' => 'Organization', + 'Class:URP_UserProfile/Attribute:allowed_org_name+' => 'Allowed organization', + 'Class:URP_UserProfile/Attribute:reason' => 'Reason', + 'Class:URP_UserProfile/Attribute:reason+' => 'explain why this person is allowed to see the data belonging to this organization', +)); + // // Class: URP_ProfileProjection // diff --git a/dictionaries/fr.dictionary.itop.ui.php b/dictionaries/fr.dictionary.itop.ui.php index 4d90e1a2c..c102072e8 100644 --- a/dictionaries/fr.dictionary.itop.ui.php +++ b/dictionaries/fr.dictionary.itop.ui.php @@ -156,7 +156,26 @@ Dict::Add('FR FR', 'French', 'Français', array( 'Class:URP_UserProfile/Attribute:profile' => 'Profil', 'Class:URP_UserProfile/Attribute:profile+' => '', 'Class:URP_UserProfile/Attribute:reason' => 'Raison', - 'Class:URP_UserProfile/Attribute:reason+' => 'Justifie le rôles affecté à cet utilisateur', + 'Class:URP_UserProfile/Attribute:reason+' => 'Justifie le rôle affecté à cet utilisateur', +)); + +// +// Class: URP_UserOrg +// + +Dict::Add('EN US', 'English', 'English', array( + 'Class:URP_UserOrg' => 'Utilisateur/Organisation', + 'Class:URP_UserOrg+' => 'Organizations permises pour l\'utilisateur', + 'Class:URP_UserProfile/Attribute:userid' => 'Utilisateur', + 'Class:URP_UserProfile/Attribute:userid+' => '', + 'Class:URP_UserProfile/Attribute:userlogin' => 'Login', + 'Class:URP_UserProfile/Attribute:userlogin+' => '', + 'Class:URP_UserProfile/Attribute:allowed_org_id' => 'Organisation', + 'Class:URP_UserProfile/Attribute:allowed_org_id+' => '', + 'Class:URP_UserProfile/Attribute:allowed_org_name' => 'Organisation', + 'Class:URP_UserProfile/Attribute:allowed_org_name+' => '', + 'Class:URP_UserProfile/Attribute:reason' => 'Raison', + 'Class:URP_UserProfile/Attribute:reason+' => 'Justifie la permission de voir les données de cette organisation', )); // diff --git a/pages/UI.php b/pages/UI.php index aa6e7b739..a246d632e 100644 --- a/pages/UI.php +++ b/pages/UI.php @@ -874,7 +874,7 @@ try { $oP->p(Dict::Format('UI:Class_Object_NotUpdated', MetaModel::GetName(get_class($oObj)), $oObj->GetName())); } - else if ($oObj->CheckToUpdate()) + else { $oMyChange = MetaModel::NewObject("CMDBChange"); $oMyChange->Set("date", time()); @@ -892,10 +892,6 @@ try $oP->p(Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($oObj)), $oObj->GetName())); } - else - { - $oP->p("".Dict::S('UI:Error:ObjectCannotBeUpdated')."\n"); - } } else { @@ -1215,7 +1211,7 @@ EOF $oObj->Set($sAttCode, $paramValue); } } - if ($oObj->ApplyStimulus($sStimulus) && $oObj->CheckToUpdate()) + if ($oObj->ApplyStimulus($sStimulus)) { $oMyChange = MetaModel::NewObject("CMDBChange"); $oMyChange->Set("date", time()); diff --git a/pages/run_query.php b/pages/run_query.php index d1ef26029..c1ed44f70 100644 --- a/pages/run_query.php +++ b/pages/run_query.php @@ -112,7 +112,6 @@ try echo "FYI: '$sClearText'
\n"; $oFilter = DBObjectSearch::unserialize($sExpression); $sExpression = $oFilter->ToOQL(); - exit; } else { diff --git a/setup/index.php b/setup/index.php index 84904cfc0..e1dd3122c 100644 --- a/setup/index.php +++ b/setup/index.php @@ -411,6 +411,12 @@ function CreateAdminAccount(SetupWebPage $oP, Config $oConfig, $sAdminUser, $sAd { $oP->log('Info - CreateAdminAccount'); InitDataModel($oP, TMP_CONFIG_FILE, false); // load data model and connect to the database + + if (!UserRights::Setup()) + { + return false; + } + if (UserRights::CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage)) { $oP->ok("Administrator account '$sAdminUser' created."); @@ -908,7 +914,7 @@ function SampleDataSelection(SetupWebPage $oP, $aParamValues, $iCurrentStep, Con $oP->add("\n"); AddParamsToForm($oP, $aParamValues, array('sample_data')); - if (CreateAdminAccount($oP, $oConfig, $sAdminUser, $sAdminPwd, $sLanguage) && UserRights::Setup()) + if (CreateAdminAccount($oP, $oConfig, $sAdminUser, $sAdminPwd, $sLanguage)) { $oP->add("

Loading of sample data

\n"); $oP->p("
Do you want to load sample data into the database ? \n"); diff --git a/setup/xmldataloader.class.inc.php b/setup/xmldataloader.class.inc.php index 035c38a1a..8e416a8f9 100644 --- a/setup/xmldataloader.class.inc.php +++ b/setup/xmldataloader.class.inc.php @@ -202,10 +202,12 @@ class XMLDataLoader else { // tested by Romain, little impact on perf (not significant on the intial setup) - if (!$oTargetObj->CheckValue($sAttCode, (string)$oXmlObj->$sAttCode)) + $res = $oTargetObj->CheckValue($sAttCode, (string)$oXmlObj->$sAttCode); + if ($res !== true) { - SetupWebPage::log_error("Value not allowed - $sClass/$iSrcId - $sAttCode: '".$oXmlObj->$sAttCode."'"); - throw(new Exception("Wrong value for attribute $sAttCode: '".$oXmlObj->$sAttCode."'")); + // $res contains the error description + SetupWebPage::log_error("Value not allowed - $sClass/$iSrcId - $sAttCode: '".$oXmlObj->$sAttCode."' ; $res"); + throw(new Exception("Value not allowed - $sClass/$iSrcId - $sAttCode: '".$oXmlObj->$sAttCode."' ; $res")); } $oTargetObj->Set($sAttCode, (string)$oXmlObj->$sAttCode); } diff --git a/webservices/webservices.class.inc.php b/webservices/webservices.class.inc.php index 8af6eca10..8989e51b5 100644 --- a/webservices/webservices.class.inc.php +++ b/webservices/webservices.class.inc.php @@ -280,15 +280,15 @@ class WebServices */ protected function MyObjectSetScalar($sAttCode, $sParamName, $value, &$oTargetObj, &$oRes) { - if ($oTargetObj->CheckValue($sAttCode, $value)) + $res = $oTargetObj->CheckValue($sAttCode, $value); + if ($res === true) { $oTargetObj->Set($sAttCode, $value); } else { - $aAllowedValues = MetaModel::GetAllowedValues_att(get_class($oTargetObj), $sAttCode); - $sValues = implode(', ', $aAllowedValues); - $oRes->LogError("Parameter $sParamName: found '$value' while expecting a value in {".$sValues."}"); + // $res contains the error description + $oRes->LogError("Unexpected value for parameter $sParamName: $res"); } } @@ -483,7 +483,7 @@ class WebServices { if ($oRes->IsOk()) { - list($bRes, $aIssues) = $oTargetObj->CheckToInsert(); + list($bRes, $aIssues) = $oTargetObj->CheckToWrite(); if ($bRes) { $iId = $oTargetObj->DBInsertTrackedNoReload($oChange); @@ -493,6 +493,10 @@ class WebServices else { $oRes->LogError("The ticket could not be created due to forbidden values (or inconsistent values)"); + foreach($aIssues as $iIssue => $sIssue) + { + $oRes->LogError("Issue #$iIssue: $sIssue"); + } } } }