From b5c7cbf5092053fef37af1eee1f447412ad192aa Mon Sep 17 00:00:00 2001 From: Romain Quetiez Date: Fri, 31 Jul 2009 13:18:44 +0000 Subject: [PATCH] User management by profile ready for integration with the UI and some caching has been implemented for the building of queries (both from an OQL or from a programmatic query) SVN:trunk[90] --- .../userrights/userrightsmatrix.class.inc.php | 13 + .../userrights/userrightsnull.class.inc.php | 13 +- .../userrightsprofile.class.inc.php | 433 ++++++++++++++---- core/dbobjectsearch.class.php | 42 +- core/dbobjectset.class.php | 18 + core/expression.class.inc.php | 53 ++- core/metamodel.class.php | 102 ++++- core/userrights.class.inc.php | 57 ++- pages/usermanagement_classproj.php | 9 +- pages/usermanagement_profileproj.php | 9 +- pages/usermanagement_userstatus.php | 285 ++++++++++++ 11 files changed, 884 insertions(+), 150 deletions(-) create mode 100644 pages/usermanagement_userstatus.php diff --git a/addons/userrights/userrightsmatrix.class.inc.php b/addons/userrights/userrightsmatrix.class.inc.php index 8bbe15cc8..80a4b97ee 100644 --- a/addons/userrights/userrightsmatrix.class.inc.php +++ b/addons/userrights/userrightsmatrix.class.inc.php @@ -318,6 +318,19 @@ class UserRightsMatrix extends UserRightsAddOnAPI return false; } + public function GetUserId($sUserName) + { + $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT UserRightsMatrixUsers WHERE login = '$sUserName'")); + if ($oSet->Count() < 1) + { + // todo: throw an exception? + return false; + } + + $oLogin = $oSet->Fetch(); + return $oLogin->Get('userid'); + } + public function GetFilter($sUserName, $sClass) { $oNullFilter = new DBObjectSearch($sClass); diff --git a/addons/userrights/userrightsnull.class.inc.php b/addons/userrights/userrightsnull.class.inc.php index c5480f7ea..0d9656fef 100644 --- a/addons/userrights/userrightsnull.class.inc.php +++ b/addons/userrights/userrightsnull.class.inc.php @@ -34,7 +34,12 @@ class UserRightsNull extends UserRightsAddOnAPI public function CheckCredentials($sUserName, $sPassword) { - return true; + return 1; + } + + public function GetUserId($sUserName) + { + return 1; } public function GetFilter($sUserName, $sClass) @@ -43,17 +48,17 @@ class UserRightsNull extends UserRightsAddOnAPI return $oNullFilter; } - public function IsActionAllowed($sUserName, $sClass, $iActionCode, dbObjectSet $aInstances) + public function IsActionAllowed($iUserId, $sClass, $iActionCode, dbObjectSet $aInstances) { return UR_ALLOWED_YES; } - public function IsStimulusAllowed($sUserName, $sClass, $sStimulusCode, dbObjectSet $aInstances) + public function IsStimulusAllowed($iUserId, $sClass, $sStimulusCode, dbObjectSet $aInstances) { return UR_ALLOWED_YES; } - public function IsActionAllowedOnAttribute($sUserName, $sClass, $sAttCode, $iActionCode, dbObjectSet $aInstances) + public function IsActionAllowedOnAttribute($iUserId, $sClass, $sAttCode, $iActionCode, dbObjectSet $aInstances) { return UR_ALLOWED_YES; } diff --git a/addons/userrights/userrightsprofile.class.inc.php b/addons/userrights/userrightsprofile.class.inc.php index 7b72df453..df80a8caf 100644 --- a/addons/userrights/userrightsprofile.class.inc.php +++ b/addons/userrights/userrightsprofile.class.inc.php @@ -245,23 +245,23 @@ class URP_ProfileProjection extends DBObject public function ProjectUser(URP_Users $oUser) { $sExpr = $this->Get('value'); - if (preg_match('/^\s*([a-zA-Z0-9;]+)\s*$/', $sExpr, $aMatches)) - { - // Constant value(s) - $aRes = explode(';', $aMatches[1]); - } - elseif ($sExpr == '') - { - $aRes = array(''); - } - else - { + if (strtolower(substr($sExpr, 0, 6)) == 'select') + { $sColumn = $this->Get('attribute'); // SELECT... $oValueSetDef = new ValueSetObjects($sExpr, $sColumn); $aValues = $oValueSetDef->GetValues(array('user' => $oUser), ''); $aRes = array_values($aValues); } + elseif ($sExpr == '') + { + $aRes = null; + } + else + { + // Constant value(s) + $aRes = explode(';', trim($sExpr)); + } return $aRes; } } @@ -302,23 +302,23 @@ class URP_ClassProjection extends DBObject public function ProjectObject($oObject) { $sExpr = $this->Get('value'); - if (preg_match('/^\s*([a-zA-Z0-9;]+)\s*$/', $sExpr, $aMatches)) - { - // Constant value(s) - $aRes = explode(';', $aMatches[1]); - } - elseif ($sExpr == '') - { - $aRes = array(''); - } - else - { + if (strtolower(substr($sExpr, 0, 6)) == 'select') + { $sColumn = $this->Get('attribute'); // SELECT... $oValueSetDef = new ValueSetObjects($sExpr, $sColumn); - $aValues = $oValueSetDef->GetValues(array('this' => $oObject), ''); + $aValues = $oValueSetDef->GetValues(array('user' => $oObject), ''); $aRes = array_values($aValues); } + elseif ($sExpr == '') + { + $aRes = null; + } + else + { + // Constant value(s) + $aRes = explode(';', trim($sExpr)); + } return $aRes; } } @@ -389,7 +389,7 @@ class URP_StimulusGrant extends DBObject MetaModel::Init_AddAttribute(new AttributeString("class", array("label"=>"class", "description"=>"class name", "allowed_values"=>null, "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array()))); MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("label"=>"permission", "description"=>"allowed or not allowed?", "allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array()))); - MetaModel::Init_AddAttribute(new AttributeString("stimulus", array("label"=>"action", "description"=>"operations to perform on the given class", "allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); + MetaModel::Init_AddAttribute(new AttributeString("stimulus", array("label"=>"stimulus", "description"=>"stimulus code", "allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array()))); //MetaModel::Init_InheritFilters(); // Common to all grant classes (could be factorized by class inheritence, but this has to be benchmarked) @@ -498,7 +498,7 @@ class UserRightsProfile extends UserRightsAddOnAPI } else { - $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_ClassProjection WHERE class = '$sClass' AND dimensionid = $iDimensionId")); + $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_ClassProjection WHERE class = :class AND dimensionid = :dimension"), array(), array('class'=>$sClass, 'dimension'=>$iDimensionId)); $bAddCell = ($oSet->Count() < 1); } if ($bAddCell) @@ -524,7 +524,7 @@ class UserRightsProfile extends UserRightsAddOnAPI } else { - $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_ProfileProjection WHERE dimensionid = $iDimensionId AND profileid = $iProfileId")); + $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_ProfileProjection WHERE dimensionid = :dimension AND profileid = :profile"), array(), array('dimension'=>$iDimensionId, 'profile'=>$iProfileId)); $bAddCell = ($oSet->Count() < 1); } if ($bAddCell) @@ -557,7 +557,7 @@ class UserRightsProfile extends UserRightsAddOnAPI } else { - $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_ActionGrant WHERE class = '$sClass' AND action = '$sAction' AND profileid = $iProfileId")); + $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_ActionGrant WHERE class = :class AND action = :action AND profileid = :profile"), array(), array('class'=>$sClass, 'action'=>$sAction, 'profile'=>$iProfileId)); $bAddCell = ($oSet->Count() < 1); } if ($bAddCell) @@ -579,7 +579,7 @@ class UserRightsProfile extends UserRightsAddOnAPI } else { - $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_StimulusGrant WHERE class = '$sClass' AND stimulus = '$sStimulusCode' AND profileid = $iProfileId")); + $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_StimulusGrant WHERE class = :class AND stimulus = :stimulus AND profileid = :profile"), array(), array('class'=>$sClass, 'stimulus'=>$sStimulusCode, 'profile'=>$iProfileId)); $bAddCell = ($oSet->Count() < 1); } if ($bAddCell) @@ -621,119 +621,368 @@ class UserRightsProfile extends UserRightsAddOnAPI } } - public function Init() + { + MetaModel::RegisterPlugin('userrights', 'ACbyProfile', array($this, 'CacheData')); + } + + protected $m_aUsers = array(); // id -> object + protected $m_aDimensions = array(); // id -> object + protected $m_aClassProj = array(); // class,dimensionid -> object + protected $m_aProfiles = array(); // id -> object + protected $m_aUserProfiles = array(); // userid,profileid -> object + protected $m_aProPro = array(); // profileid,dimensionid -> object + + protected $m_aClassActionGrants = array(); // profile, class, action -> permission + protected $m_aObjectActionGrants = array(); // userid, class, id, action -> permission, list of attributes + + public function CacheData() { // Could be loaded in a shared memory (?) + + $oUserSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_Users")); + while ($oUser = $oUserSet->Fetch()) + { + $this->m_aUsers[$oUser->GetKey()] = $oUser; + } + + $oDimensionSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_Dimensions")); + while ($oDimension = $oDimensionSet->Fetch()) + { + $this->m_aDimensions[$oDimension->GetKey()] = $oDimension; + } + + $oClassProjSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_ClassProjection")); + while ($oClassProj = $oClassProjSet->Fetch()) + { + $this->m_aClassProjs[$oClassProj->Get('class')][$oClassProj->Get('dimensionid')] = $oClassProj; + } + + $oProfileSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_Profiles")); + while ($oProfile = $oProfileSet->Fetch()) + { + $this->m_aProfiles[$oProfile->GetKey()] = $oProfile; + } + + $oUserProfileSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_UserProfile")); + while ($oUserProfile = $oUserProfileSet->Fetch()) + { + $this->m_aUserProfiles[$oUserProfile->Get('userid')][$oUserProfile->Get('profileid')] = $oUserProfile; + } + + $oProProSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_ProfileProjection")); + while ($oProPro = $oProProSet->Fetch()) + { + $this->m_aProPros[$oProPro->Get('profileid')][$oProPro->Get('dimensionid')] = $oProPro; + } + +/* + echo "
\n";
+		print_r($this->m_aUsers);
+		print_r($this->m_aDimensions);
+		print_r($this->m_aClassProjs);
+		print_r($this->m_aProfiles);
+		print_r($this->m_aUserProfiles);
+		print_r($this->m_aProPros);
+		echo "
\n"; +exit; +*/ + return true; } public function CheckCredentials($sUserName, $sPassword) { - $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_Users WHERE login = '$sUserName'")); + $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_Users WHERE login = :login"), array(), array('login' => $sUserName)); if ($oSet->Count() < 1) { // todo: throw an exception? return false; } - $oLogin = $oSet->Fetch(); - if ($oLogin->Get('password') == $sPassword) + $oUser = $oSet->Fetch(); + if ($oUser->Get('password') == $sPassword) { - return true; + return $oUser->GetKey(); } // todo: throw an exception? return false; } + public function GetUserId($sUserName) + { + $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_Users WHERE login = :login"), array(), array('login' => $sUserName)); + if ($oSet->Count() < 1) + { + // todo: throw an exception? + return false; + } + + $oUser = $oSet->Fetch(); + return $oUser->GetKey(); + } + public function GetFilter($sUserName, $sClass) { $oNullFilter = new DBObjectSearch($sClass); return $oNullFilter; } - public function IsActionAllowed($sUserName, $sClass, $iActionCode, dbObjectSet $aInstances) + protected function GetClassActionGrant($iProfile, $sClass, $sAction) { - // #@# temporary - return true; - if (!array_key_exists($iActionCode, self::$m_aActionCodes)) - { - return UR_ALLOWED_NO; - } - $sAction = self::$m_aActionCodes[$iActionCode]; + $aTest = @$this->m_aClassActionGrants[$iProfile][$sClass][$sAction]; + if (isset($aTest)) return $aTest; - $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_ActionGrant WHERE class = '$sClass' AND action = '$sAction' AND login = '$sUserName'")); + // Get the permission for this profile/class/action + $oSearch = DBObjectSearch::FromOQL("SELECT URP_ActionGrant WHERE class = :class AND action = :action AND profileid = :profile"); + $oSet = new DBObjectSet($oSearch, array(), array('class'=>$sClass, 'action'=>$sAction, 'profile'=>$iProfile)); if ($oSet->Count() < 1) { - return UR_ALLOWED_NO; + return null; } - $oGrantRecord = $oSet->Fetch(); - switch ($oGrantRecord->Get('permission')) - { - case 'yes': - $iRetCode = UR_ALLOWED_YES; - break; - case 'no': - default: - $iRetCode = UR_ALLOWED_NO; - break; - } - return $iRetCode; + + $this->m_aClassActionGrants[$iProfile][$sClass][$sAction] = $oGrantRecord; + return $oGrantRecord; } - public function IsActionAllowedOnAttribute($sUserName, $sClass, $sAttCode, $iActionCode, dbObjectSet $aInstances) + protected function GetObjectActionGrant($oUser, $sClass, $iActionCode, $oObject) { - // #@# temporary - return true; - if (!array_key_exists($iActionCode, self::$m_aActionCodes)) - { - return UR_ALLOWED_NO; - } + // load and cache permissions for the current user on the given object + // + $aTest = @$this->m_aObjectActionGrants[$oUser->GetKey()][$sClass][$oObject->GetKey][$iActionCode]; + if (is_array($aTest)) return $aTest; + $sAction = self::$m_aActionCodes[$iActionCode]; - $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_AttributeGrant WHERE URP_AttributeGrant.class = '$sClass' AND URP_AttributeGrant.attcode = '$sAttCode' AND URP_AttributeGrant.action = '$sAction' AND URP_AttributeGrant.login = '$sUserName'")); - if ($oSet->Count() < 1) + $iInstancePermission = UR_ALLOWED_NO; + $aAttributes = array(); + foreach($this->GetMatchingProfiles($oUser, $oObject) as $iProfile) + { + $oGrantRecord = $this->GetClassActionGrant($iProfile, $sClass, $sAction); + if (is_null($oGrantRecord)) + { + continue; // loop to the next profile + } + elseif ($oGrantRecord->Get('permission') == 'yes') + { + $iInstancePermission = UR_ALLOWED_YES; + + // merge the list of attributes allowed for this profile + $oSearch = DBObjectSearch::FromOQL("SELECT URP_AttributeGrant WHERE actiongrantid = :actiongrantid"); + $oSet = new DBObjectSet($oSearch, array(), array('actiongrantid' => $oGrantRecord->GetKey())); + $aAttributes = array_merge($aAttributes, $oSet->GetColumnAsArray('attcode', false)); + } + } + + $aRes = array( + 'permission' => $iInstancePermission, + 'attributes' => $aAttributes, + ); + $this->m_aObjectActionGrants[$oUser->GetKey()][$sClass][$oObject->GetKey()][$iActionCode] = $aRes; + return $aRes; + } + + public function IsActionAllowed($iUserId, $sClass, $iActionCode, dbObjectSet $oInstances) + { + $oUser = $this->m_aUsers[$iUserId]; + + $oInstances->Rewind(); + while($oObject = $oInstances->Fetch()) + { + $aObjectPermissions = $this->GetObjectActionGrant($oUser, $sClass, $iActionCode, $oObject); + + $iInstancePermission = $aObjectPermissions['permission']; + if (isset($iGlobalPermission)) + { + if ($iInstancePermission != $iGlobalPermission) + { + $iGlobalPermission = UR_ALLOWED_DEPENDS; + } + } + else + { + $iGlobalPermission = $iInstancePermission; + } + } + if (isset($iGlobalPermission)) + { + return $iGlobalPermission; + } + else { return UR_ALLOWED_NO; } - - $oGrantRecord = $oSet->Fetch(); - switch ($oGrantRecord->Get('permission')) - { - case 'yes': - $iRetCode = UR_ALLOWED_YES; - break; - case 'no': - default: - $iRetCode = UR_ALLOWED_NO; - break; - } - return $iRetCode; } - public function IsStimulusAllowed($sUserName, $sClass, $sStimulusCode, dbObjectSet $aInstances) + public function IsActionAllowedOnAttribute($iUserId, $sClass, $sAttCode, $iActionCode, dbObjectSet $oInstances) { - // #@# temporary - return true; - $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_StimulusGrant WHERE class = '$sClass' AND stimulus = '$sStimulusCode' AND login = '$sUserName'")); - if ($oSet->Count() < 1) + $oUser = $this->m_aUsers[$iUserId]; + + $oInstances->Rewind(); + while($oObject = $oInstances->Fetch()) + { + $aObjectPermissions = $this->GetObjectActionGrant($oUser, $sClass, $iActionCode, $oObject); + + $aAttributes = $aObjectPermissions['attributes']; + if (in_array($sAttCode, $aAttributes)) + { + $iInstancePermission = $aObjectPermissions['permission']; + } + else + { + $iInstancePermission = UR_ALLOWED_NO; + } + + if (isset($iGlobalPermission)) + { + if ($iInstancePermission != $iGlobalPermission) + { + $iGlobalPermission = UR_ALLOWED_DEPENDS; + } + } + else + { + $iGlobalPermission = $iInstancePermission; + } + } + if (isset($iGlobalPermission)) + { + return $iGlobalPermission; + } + else { return UR_ALLOWED_NO; } + } - $oGrantRecord = $oSet->Fetch(); - switch ($oGrantRecord->Get('permission')) + public function IsStimulusAllowed($iUserId, $sClass, $sStimulusCode, dbObjectSet $oInstances) + { + $oUser = $this->m_aUsers[$iUserId]; + + // Note: this code is VERY close to the code of IsActionAllowed() + + $oInstances->Rewind(); + while($oObject = $oInstances->Fetch()) { - case 'yes': - $iRetCode = UR_ALLOWED_YES; - break; - case 'no': - default: - $iRetCode = UR_ALLOWED_NO; - break; + $iInstancePermission = UR_ALLOWED_NO; + foreach($this->GetMatchingProfiles($oUser, $oObject) as $iProfile) + { + // Get the permission for this profile/class/stimulus + $oSearch = DBObjectSearch::FromOQL("SELECT URP_StimulusGrant WHERE class = :class AND stimulus = :stimulus AND profileid = :profile"); + $oSet = new DBObjectSet($oSearch, array(), array('class'=>$sClass, 'stimulus'=>$sStimulusCode, 'profile'=>$iProfile)); + if ($oSet->Count() < 1) + { + return UR_ALLOWED_NO; + } + + $oGrantRecord = $oSet->Fetch(); + $sPermission = $oGrantRecord->Get('permission'); + if ($sPermission == 'yes') + { + $iInstancePermission = UR_ALLOWED_YES; + } + } + if (isset($iGlobalPermission)) + { + if ($iInstancePermission != $iGlobalPermission) + { + $iGlobalPermission = UR_ALLOWED_DEPENDS; + } + } + else + { + $iGlobalPermission = $iInstancePermission; + } } - return $iRetCode; + if (isset($iGlobalPermission)) + { + return $iGlobalPermission; + } + else + { + return UR_ALLOWED_NO; + } + } + + protected function GetMatchingProfilesByDim($oUser, $oObject, $oDimension) + { + // + // List profiles for which the user projection overlaps the object projection in the given dimension + // + $iUser = $oUser->GetKey(); + $sClass = get_class($oObject); + $iPKey = $oObject->GetKey(); + $iDimension = $oDimension->GetKey(); + + $aObjectProjection = $this->m_aClassProjs[$sClass][$iDimension]->ProjectObject($oObject); + + $aRes = array(); + foreach ($this->m_aUserProfiles[$iUser] as $iProfile => $oProfile) + { + if (is_null($aObjectProjection)) + { + $aRes[] = $iProfile; + } + else + { + // user projection to be cached on a given page ! + $aUserProjection = $this->m_aProPros[$iProfile][$iDimension]->ProjectUser($oUser); + + if (is_null($aUserProjection)) + { + $aRes[] = $iProfile; + } + else + { + $aMatchingValues = array_intersect($aObjectProjection, $aUserProjection); + if (count($aMatchingValues) > 0) + { + $aRes[] = $iProfile; + } + } + } + } + return $aRes; + } + + protected $m_aMatchingProfiles = array(); // cache of the matching profiles for a given user/object + + protected function GetMatchingProfiles($oUser, $oObject) + { + $iUser = $oUser->GetKey(); + $sClass = get_class($oObject); + $iObject = $oObject->GetKey(); + // + // List profiles for which the user projection overlaps the object projection in each and every dimension + // Caches the result + // + $aTest = @$this->m_aMatchingProfiles[$iUser][$sClass][$iObject]; + if (is_array($aTest)) + { + return $aTest; + } + + $aProfileRes = array(); + foreach ($this->m_aDimensions as $iDimension => $oDimension) + { + foreach ($this->GetMatchingProfilesByDim($oUser, $oObject, $oDimension) as $iProfile) + { + @$aProfileRes[$iProfile] += 1; + } + } + + $aRes = array(); + $iDimCount = count($this->m_aDimensions); + foreach ($aProfileRes as $iProfile => $iMatches) + { + if ($iMatches == $iDimCount) + { + $aRes[] = $iProfile; + } + } + $this->m_aMatchingProfiles[$iUser][$sClass][$iObject] = $aRes; + return $aRes; } } diff --git a/core/dbobjectsearch.class.php b/core/dbobjectsearch.class.php index 236a0b721..e30d3a5fa 100644 --- a/core/dbobjectsearch.class.php +++ b/core/dbobjectsearch.class.php @@ -48,6 +48,7 @@ class DBObjectSearch private $m_sClassAlias; private $m_aClasses; // queried classes (alias => class name) private $m_oSearchCondition; + private $m_aParams; private $m_aFullText; private $m_aPointingTo; private $m_aReferencedBy; @@ -64,6 +65,7 @@ class DBObjectSearch $this->m_sClassAlias = $sClassAlias; $this->m_aClasses = array($sClassAlias => $sClass); $this->m_oSearchCondition = new TrueExpression; + $this->m_aParams = array(); $this->m_aFullText = array(); $this->m_aPointingTo = array(); $this->m_aReferencedBy = array(); @@ -174,6 +176,8 @@ class DBObjectSearch { $oTranslated = $oFilter->GetCriteria()->Translate($aTranslation, false); $this->AddConditionExpression($oTranslated); + // #@# what about collisions in parameter names ??? + $this->m_aParams = array_merge($this->m_aParams, $oFilter->m_aParams); } public function ResetCondition() @@ -232,22 +236,22 @@ class DBObjectSearch break; case 'Contains': - $oRightExpr = new ScalarExpression("%$value%"); + $this->m_aParams[$sFilterCode] = "%$value%"; $sOperator = 'LIKE'; break; case 'Begins with': - $oRightExpr = new ScalarExpression("$value%"); + $this->m_aParams[$sFilterCode] = "$value%"; $sOperator = 'LIKE'; break; case 'Finishes with': - $oRightExpr = new ScalarExpression("%$value"); + $this->m_aParams[$sFilterCode] = "%$value"; $sOperator = 'LIKE'; break; default: - $oRightExpr = new ScalarExpression($value); + $this->m_aParams[$sFilterCode] = $value; $sOperator = $sOpCode; } @@ -262,6 +266,7 @@ class DBObjectSearch case 'Begins with': case 'Finishes with': default: + $oRightExpr = new VariableExpression($sFilterCode); $oNewCondition = new BinaryExpression($oField, $sOperator, $oRightExpr); } @@ -453,10 +458,14 @@ class DBObjectSearch { return $this->m_aRelatedTo; } + public function GetInternalParams() + { + return $this->m_aParams; + } public function RenderCondition() { - return $this->m_oSearchCondition->Render(); + return $this->m_oSearchCondition->Render($this->m_aParams); } public function serialize() @@ -588,11 +597,13 @@ class DBObjectSearch return $retValue; } - public function ToOQL() + public function ToOQL(&$aParams = null) { + $bRetrofitParams = (!is_null($aParams)); + $sRes = "SELECT ".$this->GetClass().' AS '.$this->GetClassAlias(); $sRes .= $this->ToOQL_Joins(); - $sRes .= " WHERE ".$this->m_oSearchCondition->Render(); + $sRes .= " WHERE ".$this->m_oSearchCondition->Render($aParams, $bRetrofitParams); return $sRes; } @@ -762,10 +773,20 @@ class DBObjectSearch } } - static public function FromOQL($sQuery, array $aParams = array(), $oObject = null) + static protected $m_aOQLQueries = array(); + + static public function FromOQL($sQuery) { if (empty($sQuery)) return null; + // Query caching + $bOQLCacheEnabled = true; + if ($bOQLCacheEnabled && array_key_exists($sQuery, self::$m_aOQLQueries)) + { + // hit! + return clone self::$m_aOQLQueries[$sQuery]; + } + $oOql = new OqlInterpreter($sQuery); $oOqlQuery = $oOql->ParseObjectQuery(); @@ -856,6 +877,11 @@ class DBObjectSearch $oResultFilter->m_oSearchCondition = $oResultFilter->OQLExpressionToCondition($sQuery, $oConditionTree, $aAliases); } + if ($bOQLCacheEnabled) + { + self::$m_aOQLQueries[$sQuery] = clone $oResultFilter; + } + return $oResultFilter; } diff --git a/core/dbobjectset.class.php b/core/dbobjectset.class.php index 9e6cf5459..6384864d8 100644 --- a/core/dbobjectset.class.php +++ b/core/dbobjectset.class.php @@ -92,6 +92,24 @@ class DBObjectSet return $aRet; } + public function GetColumnAsArray($sAttCode, $bWithId = true) + { + $aRet = array(); + $this->Rewind(); + while ($oObject = $this->Fetch()) + { + if ($bWithId) + { + $aRet[$oObject->GetKey()] = $oObject->Get($sAttCode); + } + else + { + $aRet[] = $oObject->Get($sAttCode); + } + } + return $aRet; + } + public function GetFilter() { return $this->m_oFilter; diff --git a/core/expression.class.inc.php b/core/expression.class.inc.php index f2646802e..834ac47b7 100644 --- a/core/expression.class.inc.php +++ b/core/expression.class.inc.php @@ -16,8 +16,8 @@ abstract class Expression // recursive translation of identifiers abstract public function Translate($aTranslationData, $bMatchAll = true); - // recursive rendering - abstract public function Render($aArgs = array()); + // recursive rendering (aArgs used as input by default, or used as output if bRetrofitParams set to True + abstract public function Render(&$aArgs = null, $bRetrofitParams = false); // recursively builds an array of class => fieldname abstract public function ListRequiredFields(); @@ -119,11 +119,11 @@ class BinaryExpression extends Expression } // recursive rendering - public function Render($aArgs = array()) + public function Render(&$aArgs = null, $bRetrofitParams = false) { $sOperator = $this->GetOperator(); - $sLeft = $this->GetLeftExpr()->Render($aArgs); - $sRight = $this->GetRightExpr()->Render($aArgs); + $sLeft = $this->GetLeftExpr()->Render($aArgs, $bRetrofitParams); + $sRight = $this->GetRightExpr()->Render($aArgs, $bRetrofitParams); return "($sLeft $sOperator $sRight)"; } @@ -164,9 +164,18 @@ class UnaryExpression extends Expression } // recursive rendering - public function Render($aArgs = array()) + public function Render(&$aArgs = null, $bRetrofitParams = false) { - return CMDBSource::Quote($this->m_value); + if ($bRetrofitParams) + { + $iParamIndex = count($aArgs) + 1; // 1-based indexation + $aArgs['param'.$iParamIndex] = $this->m_value; + return ':param'.$iParamIndex; + } + else + { + return CMDBSource::Quote($this->m_value); + } } public function Translate($aTranslationData, $bMatchAll = true) @@ -228,7 +237,7 @@ class FieldExpression extends UnaryExpression public function GetName() {return $this->m_sName;} // recursive rendering - public function Render($aArgs = array()) + public function Render(&$aArgs = null, $bRetrofitParams = false) { if (empty($this->m_sParent)) { @@ -290,16 +299,16 @@ class VariableExpression extends UnaryExpression public function GetName() {return $this->m_sName;} // recursive rendering - public function Render($aArgs = array()) + public function Render(&$aArgs = null, $bRetrofitParams = false) { - if (array_key_exists($this->m_sName, $aArgs)) - { - return $aArgs[$this->m_sName]; - } - elseif (is_null($aArgs)) + if (is_null($aArgs) || $bRetrofitParams) { return ':'.$this->m_sName; } + elseif (array_key_exists($this->m_sName, $aArgs)) + { + return CMDBSource::Quote($aArgs[$this->m_sName]); + } else { throw new CoreException('Missing query argument', array('expecting'=>$this->m_sName, 'available'=>$aArgs)); @@ -330,12 +339,12 @@ class ListExpression extends Expression } // recursive rendering - public function Render($aArgs = array()) + public function Render(&$aArgs = null, $bRetrofitParams = false) { $aRes = array(); foreach ($this->m_aExpressions as $oExpr) { - $aRes[] = $oExpr->Render($aArgs); + $aRes[] = $oExpr->Render($aArgs, $bRetrofitParams); } return '('.implode(', ', $aRes).')'; } @@ -390,12 +399,12 @@ class FunctionExpression extends Expression } // recursive rendering - public function Render($aArgs = array()) + public function Render(&$aArgs = null, $bRetrofitParams = false) { $aRes = array(); foreach ($this->m_aArgs as $oExpr) { - $aRes[] = $oExpr->Render($aArgs); + $aRes[] = $oExpr->Render($aArgs, $bRetrofitParams); } return $this->m_sVerb.'('.implode(', ', $aRes).')'; } @@ -449,9 +458,9 @@ class IntervalExpression extends Expression } // recursive rendering - public function Render($aArgs = array()) + public function Render(&$aArgs = null, $bRetrofitParams = false) { - return 'INTERVAL '.$this->m_oValue->Render($aArgs).' '.$this->m_sUnit; + return 'INTERVAL '.$this->m_oValue->Render($aArgs, $bRetrofitParams).' '.$this->m_sUnit; } public function Translate($aTranslationData, $bMatchAll = true) @@ -486,12 +495,12 @@ class CharConcatExpression extends Expression } // recursive rendering - public function Render($aArgs = array()) + public function Render(&$aArgs = null, $bRetrofitParams = false) { $aRes = array(); foreach ($this->m_aExpressions as $oExpr) { - $sCol = $oExpr->Render($aArgs); + $sCol = $oExpr->Render($aArgs, $bRetrofitParams); // Concat will be globally NULL if one single argument is null ! $aRes[] = "COALESCE($sCol, '')"; } diff --git a/core/metamodel.class.php b/core/metamodel.class.php index bb7e92a05..cbb0b1637 100644 --- a/core/metamodel.class.php +++ b/core/metamodel.class.php @@ -164,6 +164,10 @@ abstract class MetaModel } } + private static $m_bTraceQueries = true; + private static $m_aQueriesLog = array(); + + private static $m_sDBName = ""; private static $m_sTablePrefix = ""; // table prefix for the current application instance (allow several applications on the same DB) private static $m_Category2Class = array(); @@ -1167,15 +1171,36 @@ abstract class MetaModel return false; } + protected static $m_aQueryStructCache = array(); + public static function MakeSelectQuery(DBObjectSearch $oFilter, $aOrderBy = array(), $aArgs = array()) { - $aTranslation = array(); - $aClassAliases = array(); - $aTableAliases = array(); - $oConditionTree = $oFilter->GetCriteria(); - $oSelect = self::MakeQuery($oFilter->GetClassAlias(), $oConditionTree, $aClassAliases, $aTableAliases, $aTranslation, $oFilter); + // Query caching + // + $bQueryCacheEnabled = true; + $sOqlQuery = $oFilter->ToOql(); + if ($bQueryCacheEnabled) + { + if (array_key_exists($sOqlQuery, self::$m_aQueryStructCache)) + { + // hit! + $oSelect = clone self::$m_aQueryStructCache[$sOqlQuery]; + } + } + + if (!isset($oSelect)) + { + $aTranslation = array(); + $aClassAliases = array(); + $aTableAliases = array(); + $oConditionTree = $oFilter->GetCriteria(); + $oSelect = self::MakeQuery($oFilter->GetClassAlias(), $oConditionTree, $aClassAliases, $aTableAliases, $aTranslation, $oFilter); + + self::$m_aQueryStructCache[$sOqlQuery] = clone $oSelect; + } // Check the order by specification + // foreach ($aOrderBy as $sFieldAlias => $bAscending) { MyHelpers::CheckValueInArray('field name in ORDER BY spec', $sFieldAlias, self::GetAttributesList($oFilter->GetClass())); @@ -1196,7 +1221,7 @@ abstract class MetaModel // Prepare arguments (translate any object into scalars) // - $aScalarArgs = array(); + $aScalarArgs = $oFilter->GetInternalParams(); foreach($aArgs as $sArgName => $value) { if (self::IsValidObject($value)) @@ -1215,9 +1240,41 @@ abstract class MetaModel $aScalarArgs[$sArgName] = (string) $value; } } - - //MyHelpers::var_dump_html($oSelect->RenderSelect($aOrderBy)); - return $oSelect->RenderSelect($aOrderBy, $aScalarArgs); + + // Go + // + $sRes = $oSelect->RenderSelect($aOrderBy, $aScalarArgs); + + if (self::$m_bTraceQueries) + { + $aParams = array(); + if (!array_key_exists($sOqlQuery, self::$m_aQueriesLog)) + { + self::$m_aQueriesLog[$sOqlQuery] = array( + 'sql' => array(), + 'count' => 0, + ); + } + self::$m_aQueriesLog[$sOqlQuery]['count']++; + self::$m_aQueriesLog[$sOqlQuery]['sql'][] = $sRes; + } + + return $sRes; + } + + public static function ShowQueryTrace() + { + $iTotal = 0; + foreach (self::$m_aQueriesLog as $sOql => $aQueryData) + { + echo "

$sOql

\n"; + $iTotal += $aQueryData['count']; + echo '

'.$aQueryData['count'].'

'; + echo '

Example: '.$aQueryData['sql'][0].'

'; + } + echo "

Total

\n"; + echo "

Count of executed queries: $iTotal

"; + echo "

Count of built queries: ".count(self::$m_aQueriesLog)."

"; } public static function MakeDeleteQuery(DBObjectSearch $oFilter) @@ -2390,6 +2447,8 @@ abstract class MetaModel throw new CoreException('Database not found, check your configuration file', array('config_file'=>$sConfigFile, 'db_name'=>self::$m_sDBName)); } } + // Some of the init could not be done earlier (requiring classes to be declared and DB to be accessible) + self::InitPlugins(); } public static function LoadConfig($sConfigFile) @@ -2425,6 +2484,15 @@ abstract class MetaModel CMDBSource::Init($sServer, $sUser, $sPwd); // do not select the DB (could not exist) } + protected static $m_aPlugins = array(); + public static function RegisterPlugin($sType, $sName, $aInitCallSpec = array()) + { + self::$m_aPlugins[$sName] = array( + 'type' => $sType, + 'init' => $aInitCallSpec, + ); + } + protected static function Plugin($sConfigFile, $sModuleType, $sToInclude) { if (!file_exists($sToInclude)) @@ -2434,6 +2502,22 @@ abstract class MetaModel require_once($sToInclude); } + protected static function InitPlugins() + { + foreach(self::$m_aPlugins as $sName => $aData) + { + $aCallSpec = @$aData['init']; + if (count($aCallSpec) == 2) + { + if (!is_callable($aCallSpec)) + { + throw new CoreException('Wrong declaration in plugin', array('plugin' => $aData['name'], 'type' => $aData['type'], 'class' => $aData['class'], 'init' => $aData['init'])); + } + call_user_func($aCallSpec); + } + } + } + // Building an object // // diff --git a/core/userrights.class.inc.php b/core/userrights.class.inc.php index 01428ae73..25b546920 100644 --- a/core/userrights.class.inc.php +++ b/core/userrights.class.inc.php @@ -46,11 +46,12 @@ abstract class UserRightsAddOnAPI { abstract public function Setup(); // initial installation abstract public function Init(); // loads data (possible optimizations) - abstract public function CheckCredentials($iUserId, $sPassword); // returns the id of the user or false - abstract public function GetFilter($iUserId, $sClass); // returns a filter object - abstract public function IsActionAllowed($iUserId, $sClass, $iActionCode, dbObjectSet $aInstances); - abstract public function IsStimulusAllowed($iUserId, $sClass, $sStimulusCode, dbObjectSet $aInstances); - abstract public function IsActionAllowedOnAttribute($iUserId, $sClass, $sAttCode, $iActionCode, dbObjectSet $aInstances); + abstract public function CheckCredentials($sLogin, $sPassword); // returns the id of the user or false + abstract public function GetUserId($sLogin); // returns the id of the user or false + abstract public function GetFilter($sLogin, $sClass); // returns a filter object + abstract public function IsActionAllowed($iUserId, $sClass, $iActionCode, dbObjectSet $oInstances); + abstract public function IsStimulusAllowed($iUserId, $sClass, $sStimulusCode, dbObjectSet $oInstances); + abstract public function IsActionAllowedOnAttribute($iUserId, $sClass, $sAttCode, $iActionCode, dbObjectSet $oInstances); } @@ -148,9 +149,18 @@ class UserRights return self::$m_sUser; } - public static function GetUserId() + public static function GetUserId($sName = '') { - return self::$m_iUserId; + if (empty($sName)) + { + // return current user id + return self::$m_iUserId; + } + else + { + // find the id out of the login string + return self::$m_oAddOn->GetUserId($sName); + } } public static function GetRealUser() @@ -182,28 +192,49 @@ class UserRights return self::$m_oAddOn->GetFilter(self::$m_iUserId, $sClass); } - public static function IsActionAllowed($sClass, $iActionCode, dbObjectSet $aInstances) + public static function IsActionAllowed($sClass, $iActionCode, dbObjectSet $oInstances, $iUserId = null) { if (!MetaModel::HasCategory($sClass, 'bizmodel')) return true; if (!self::CheckLogin()) return false; - return self::$m_oAddOn->IsActionAllowed(self::$m_iUserId, $sClass, $iActionCode, $aInstances); + if (is_null($iUserId)) + { + return self::$m_oAddOn->IsActionAllowed(self::$m_iUserId, $sClass, $iActionCode, $oInstances); + } + else + { + return self::$m_oAddOn->IsActionAllowed($iUserId, $sClass, $iActionCode, $oInstances); + } } - public static function IsStimulusAllowed($sClass, $sStimulusCode, dbObjectSet $aInstances) + public static function IsStimulusAllowed($sClass, $sStimulusCode, dbObjectSet $oInstances, $iUserId = null) { if (!MetaModel::HasCategory($sClass, 'bizmodel')) return true; if (!self::CheckLogin()) return false; - return self::$m_oAddOn->IsStimulusAllowed(self::$m_iUserId, $sClass, $sStimulusCode, $aInstances); + if (is_null($iUserId)) + { + return self::$m_oAddOn->IsStimulusAllowed(self::$m_iUserId, $sClass, $sStimulusCode, $oInstances); + } + else + { + return self::$m_oAddOn->IsStimulusAllowed($iUserId, $sClass, $sStimulusCode, $oInstances); + } } - public static function IsActionAllowedOnAttribute($sClass, $sAttCode, $iActionCode, dbObjectSet $aInstances) + public static function IsActionAllowedOnAttribute($sClass, $sAttCode, $iActionCode, dbObjectSet $oInstances, $iUserId = null) { if (!MetaModel::HasCategory($sClass, 'bizmodel')) return true; if (!self::CheckLogin()) return false; - return self::$m_oAddOn->IsActionAllowedOnAttribute(self::$m_iUserId, $sClass, $sAttCode, $iActionCode, $aInstances); + if (is_null($iUserId)) + { + return self::$m_oAddOn->IsActionAllowedOnAttribute(self::$m_iUserId, $sClass, $sAttCode, $iActionCode, $oInstances); + } + else + { + return self::$m_oAddOn->IsActionAllowedOnAttribute($iUserId, $sClass, $sAttCode, $iActionCode, $oInstances); + } } } diff --git a/pages/usermanagement_classproj.php b/pages/usermanagement_classproj.php index a2e8f7195..826f04111 100644 --- a/pages/usermanagement_classproj.php +++ b/pages/usermanagement_classproj.php @@ -55,7 +55,14 @@ function ComputeProjections($oPage, $sScope) $oDimension->CheckProjectionSpec($aClassProjs[$sClass][$iDimension]); $aValues = $aClassProjs[$sClass][$iDimension]->ProjectObject($oObject); - $sValues = implode(', ', $aValues); + if (is_null($aValues)) + { + $sValues = ''; + } + else + { + $sValues = implode(', ', $aValues); + } $oObjectProj['dim'.$oDimension->GetKey()] = htmlentities($sValues); } diff --git a/pages/usermanagement_profileproj.php b/pages/usermanagement_profileproj.php index a7497d0e0..4ca6d6aa5 100644 --- a/pages/usermanagement_profileproj.php +++ b/pages/usermanagement_profileproj.php @@ -65,7 +65,14 @@ function ComputeProjections($oPage) $oDimension->CheckProjectionSpec($aProPros[$iProfile][$iDimension]); $aValues = $aProPros[$iProfile][$iDimension]->ProjectUser($oUser); - $sValues = implode(', ', $aValues); + if (is_null($aValues)) + { + $sValues = ''; + } + else + { + $sValues = implode(', ', $aValues); + } $aUserProfileProj['dim'.$oDimension->GetKey()] = htmlentities($sValues); } diff --git a/pages/usermanagement_userstatus.php b/pages/usermanagement_userstatus.php new file mode 100644 index 000000000..475e39ad8 --- /dev/null +++ b/pages/usermanagement_userstatus.php @@ -0,0 +1,285 @@ +Fetch()) + { + $aDimensions[$oDimension->GetKey()] = $oDimension; + } + + // Load the class projections for a further usage + // + $aClassProj = array(); + $oClassProjSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_ClassProjection")); + while ($oClassProj = $oClassProjSet->Fetch()) + { + $aClassProjs[$oClassProj->Get('class')][$oClassProj->Get('dimensionid')] = $oClassProj; + } + + // Setup display structure + // + $aDisplayConfig = array(); + foreach ($aDimensions as $iDimension => $oDimension) + { + $aDisplayConfig['dim'.$oDimension->GetKey()] = array('label' => $oDimension->GetName(), 'description' => $oDimension->Get('description')); + } + + // Load objects + // + $aDisplayData = array(); + $sClass = get_class($oObject); + $aObjectProj = array(); + foreach ($aDimensions as $iDimension => $oDimension) + { + // #@# to be moved, may be time consuming + $oDimension->CheckProjectionSpec($aClassProjs[$sClass][$iDimension]); + + $aValues = $aClassProjs[$sClass][$iDimension]->ProjectObject($oObject); + if (is_null($aValues)) + { + $sValues = ''; + } + else + { + $sValues = implode(', ', $aValues); + } + $oObjectProj['dim'.$oDimension->GetKey()] = htmlentities($sValues); + } + + $aDisplayData[] = $oObjectProj; + + $oPage->table($aDisplayConfig, $aDisplayData); +} + + +function ComputeUserProjections($oPage, $oUser) +{ + // Load the profiles for a further usage + // + $aProfiles = array(); + $oProfileSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_Profiles")); + while ($oProfile = $oProfileSet->Fetch()) + { + $aProfiles[$oProfile->GetKey()] = $oProfile; + } + + // Load the dimensions for a further usage + // + $aDimensions = array(); + $oDimensionSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_Dimensions")); + while ($oDimension = $oDimensionSet->Fetch()) + { + $aDimensions[$oDimension->GetKey()] = $oDimension; + } + + // Load the profile projections for a further usage + // + $aProPro = array(); + $oProProSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_ProfileProjection")); + while ($oProPro = $oProProSet->Fetch()) + { + $aProPros[$oProPro->Get('profileid')][$oProPro->Get('dimensionid')] = $oProPro; + } + + // Setup display structure + // + $aDisplayConfig = array(); + $aDisplayConfig['profile'] = array('label' => 'Profile', 'description' => 'Profile in which the projection is specified'); + foreach ($aDimensions as $iDimension => $oDimension) + { + $aDisplayConfig['dim'.$oDimension->GetKey()] = array('label' => $oDimension->GetName(), 'description' => $oDimension->Get('description')); + } + + // Create a record per profile + // + $aDisplayData = array(); + $oUserProfileSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT URP_UserProfile WHERE userid = :user->id"), array(), array('user' => $oUser)); + while ($oUserProfile = $oUserProfileSet->Fetch()) + { + $iProfile = $oUserProfile->Get('profileid'); + $oProfile = $aProfiles[$iProfile]; + + $aUserProfileProj = array(); + $aUserProfileProj['profile'] = $oProfile->GetName(); + foreach ($aDimensions as $iDimension => $oDimension) + { + // #@# to be moved, may be time consuming + $oDimension->CheckProjectionSpec($aProPros[$iProfile][$iDimension]); + + $aValues = $aProPros[$iProfile][$iDimension]->ProjectUser($oUser); + if (is_null($aValues)) + { + $sValues = ''; + } + else + { + $sValues = implode(', ', $aValues); + } + $aUserProfileProj['dim'.$oDimension->GetKey()] = htmlentities($sValues); + } + + $aDisplayData[] = $aUserProfileProj; + } + + $oPage->table($aDisplayConfig, $aDisplayData); +} + + +function ComputeUserRights($oPage, $oUser, $oObject) +{ + // Set the stage + // + $iUser = $oUser->GetKey(); + $sClass = get_class($oObject); + $iPKey = $oObject->GetKey(); + $oInstances = DBObjectSet::FromArray($sClass, array($oObject)); + $aPermissions = array( + UR_ALLOWED_NO => 'UR_ALLOWED_NO', + UR_ALLOWED_YES => 'UR_ALLOWED_YES', + UR_ALLOWED_DEPENDS => 'UR_ALLOWED_DEPENDS', + ); + $aActions = array( + UR_ACTION_READ => 'Read', + UR_ACTION_MODIFY => 'Modify', + UR_ACTION_DELETE => 'Delete', + UR_ACTION_BULK_READ => 'Bulk Read', + UR_ACTION_BULK_MODIFY => 'Bulk Modify', + UR_ACTION_BULK_DELETE => 'Bulk Delete', + ); + $aAttributeActions = array( + UR_ACTION_READ => 'Read', + UR_ACTION_MODIFY => 'Modify', + UR_ACTION_BULK_READ => 'Bulk Read', + UR_ACTION_BULK_MODIFY => 'Bulk Modify', + ); + + // Determine allowed actions for the object + // + $aDisplayData = array(); + foreach($aActions as $iActionCode => $sActionDesc) + { + $iPermission = UserRights::IsActionAllowed($sClass, $iActionCode, $oInstances, $iUser); + $aDisplayData[] = array( + 'action' => $sActionDesc, + 'permission' => $aPermissions[$iPermission], + ); + } + $aDisplayConfig = array(); + $aDisplayConfig['action'] = array('label' => 'Action', 'description' => ''); + $aDisplayConfig['permission'] = array('label' => 'Permission', 'description' => ''); + $oPage->p('

Actions

'); + $oPage->table($aDisplayConfig, $aDisplayData); + + + // Determine allowed actions for the object + // + $aDisplayData = array(); + foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) + { + if (!$oAttDef->IsDirectField()) continue; + + foreach($aAttributeActions as $iActionCode => $sActionDesc) + { + $iPermission = UserRights::IsActionAllowedOnAttribute($sClass, $sAttCode, $iActionCode, $oInstances, $iUser); + $aDisplayData[] = array( + 'attribute' => $sAttCode, + 'action' => $sActionDesc, + 'permission' => $aPermissions[$iPermission], + ); + } + } + $oPage->p('

Attributes

'); + if (count($aDisplayData) > 0) + { + $aDisplayConfig = array(); + $aDisplayConfig['attribute'] = array('label' => 'Attribute', 'description' => ''); + $aDisplayConfig['action'] = array('label' => 'Action', 'description' => ''); + $aDisplayConfig['permission'] = array('label' => 'Permission', 'description' => ''); + $oPage->table($aDisplayConfig, $aDisplayData); + } + else + { + $oPage->p('none'); + } + + // Determine allowed stimuli + // + $aDisplayData = array(); + foreach(MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus) + { + $iPermission = UserRights::IsStimulusAllowed($sClass, $sStimulusCode, $oInstances, $iUser); + $aDisplayData[] = array( + 'stimulus' => $sStimulusCode, + 'permission' => $aPermissions[$iPermission], + ); + } + $oPage->p('

Stimuli

'); + if (count($aDisplayData) > 0) + { + $aDisplayConfig = array(); + $aDisplayConfig['stimulus'] = array('label' => 'Stimulus', 'description' => ''); + $aDisplayConfig['permission'] = array('label' => 'Permission', 'description' => ''); + $oPage->table($aDisplayConfig, $aDisplayData); + } + else + { + $oPage->p('none'); + } +} + + +require_once('../application/loginwebpage.class.inc.php'); +login_web_page::DoLogin(); // Check user rights and prompt if needed + +// Display the menu on the left +$oContext = new UserContext(); +$oAppContext = new ApplicationContext(); +$iActiveNodeId = utils::ReadParam('menu', -1); +$currentOrganization = utils::ReadParam('org_id', 1); +$iUser = utils::ReadParam('user_id', -1); +$sObjectClass = utils::ReadParam('object_class', ''); +$iObjectId = utils::ReadParam('object_id', 0); + +$oPage = new iTopWebPage("iTop user management - user status", $currentOrganization); +$oPage->no_cache(); + + +if ($iUser == -1) +{ + $oPage->p('Missing parameter "user_id" - current user is '.UserRights::GetUserId()); +} +else +{ + $oUser = MetaModel::GetObject('URP_Users', $iUser); + + $oPage->p('

Projections for user '.$oUser->GetName().'

'); + ComputeUserProjections($oPage, $oUser); + + if (strlen($sObjectClass) != 0) + { + $oObject = MetaModel::GetObject($sObjectClass, $iObjectId); + + $oPage->p('

Projections for object '.$oObject->GetName().'

'); + ComputeObjectProjections($oPage, $oObject); + + $oPage->p('

Resulting rights

'); + ComputeUserRights($oPage, $oUser, $oObject); + } +} + +$oPage->output(); + +?>