diff --git a/core/metamodel.class.php b/core/metamodel.class.php index 5aaecbd5c..af087a51a 100644 --- a/core/metamodel.class.php +++ b/core/metamodel.class.php @@ -1967,15 +1967,30 @@ abstract class MetaModel { return array_unique(self::$m_aRootClasses); } - public static function EnumParentClasses($sClass, $iOption = ENUM_PARENT_CLASSES_EXCLUDELEAF) + public static function EnumParentClasses($sClass, $iOption = ENUM_PARENT_CLASSES_EXCLUDELEAF, $bRootFirst = true) { self::_check_subclass($sClass); - if ($iOption == ENUM_PARENT_CLASSES_EXCLUDELEAF) + if ($bRootFirst) { - return self::$m_aParentClasses[$sClass]; + $aRes = self::$m_aParentClasses[$sClass]; + } + else + { + $aRes = array_reverse(self::$m_aParentClasses[$sClass], true); + } + if ($iOption != ENUM_PARENT_CLASSES_EXCLUDELEAF) + { + if ($bRootFirst) + { + // Leaf class at the end + $aRes[] = $sClass; + } + else + { + // Leaf class on top + array_unshift($aRes, $sClass); + } } - $aRes = self::$m_aParentClasses[$sClass]; - $aRes[] = $sClass; return $aRes; } public static function EnumChildClasses($sClass, $iOption = ENUM_CHILD_CLASSES_EXCLUDETOP) diff --git a/setup/compiler.class.inc.php b/setup/compiler.class.inc.php index f4e54aff3..862bdf40f 100644 --- a/setup/compiler.class.inc.php +++ b/setup/compiler.class.inc.php @@ -1110,6 +1110,24 @@ EOF; return $sPHP; } // function CompileMenu + /** + * Helper to compute the grant, taking any existing grant into account + */ + protected function CumulateGrant(&$aGrants, $sKey, $bGrant) + { + if (isset($aGrants[$sKey])) + { + if (!$bGrant) + { + $aGrants[$sKey] = false; + } + } + else + { + $aGrants[$sKey] = $bGrant; + } + } + protected function CompileUserRights($oUserRightsNode) { static $aActionsInShort = array( @@ -1121,6 +1139,36 @@ EOF; 'bulk delete' => 'bd', ); + // Preliminary : create an index so that links will be taken into account implicitely + $aLinkToClasses = array(); + $oClasses = $this->oFactory->ListAllClasses(); + foreach($oClasses as $oClass) + { + $bIsLink = false; + $oProperties = $oClass->GetOptionalElement('properties'); + if ($oProperties) + { + $bIsLink = (bool) $this->GetPropNumber($oProperties, 'is_link', 0); + } + if ($bIsLink) + { + foreach($this->oFactory->ListFields($oClass) as $oField) + { + $sAttType = $oField->getAttribute('xsi:type'); + + if (($sAttType == 'AttributeExternalKey') || ($sAttType == 'AttributeHierarchicalKey')) + { + $sOnTargetDel = $oField->GetChildText('on_target_delete'); + if ($sOnTargetDel == 'DEL_AUTO') + { + $sTargetClass = $oField->GetChildText('target_class'); + $aLinkToClasses[$oClass->getAttribute('id')][] = $sTargetClass; + } + } + } + } + } + // Groups // $aGroupClasses = array(); @@ -1187,38 +1235,14 @@ EOF; { if ($sType == 'stimulus') { - $sGrantKey = $iProfile.'_'.$sClass.'_s_'.$sAction; - $sGrantKeyPlus = $iProfile.'_'.$sClass.'+_s_'.$sAction; // subclasses inherit this grant + $this->CumulateGrant($aGrants, $iProfile.'_'.$sClass.'_s_'.$sAction, $bGrant); + $this->CumulateGrant($aGrants, $iProfile.'_'.$sClass.'+_s_'.$sAction, $bGrant); // subclasses inherit this grant } else { $sAction = $aActionsInShort[$sType]; - $sGrantKey = $iProfile.'_'.$sClass.'_'.$sAction; - $sGrantKeyPlus = $iProfile.'_'.$sClass.'+_'.$sAction; // subclasses inherit this grant - } - // The class itself - if (isset($aGrants[$sGrantKey])) - { - if (!$bGrant) - { - $aGrants[$sGrantKey] = false; - } - } - else - { - $aGrants[$sGrantKey] = $bGrant; - } - // The subclasses - if (isset($aGrants[$sGrantKeyPlus])) - { - if (!$bGrant) - { - $aGrants[$sGrantKeyPlus] = false; - } - } - else - { - $aGrants[$sGrantKeyPlus] = $bGrant; + $this->CumulateGrant($aGrants, $iProfile.'_'.$sClass.'_'.$sAction, $bGrant); + $this->CumulateGrant($aGrants, $iProfile.'_'.$sClass.'+_'.$sAction, $bGrant); // subclasses inherit this grant } } } @@ -1232,6 +1256,7 @@ EOF; $sProfiles = var_export($aProfiles, true); $sGrants = var_export($aGrants, true); + $sLinkToClasses = var_export($aLinkToClasses, true); $sPHP = << YES + // - 100% undefined => undefined + // - otherwise => NO + // + + // Having write allowed on the remote class implies write + delete on the N-N link class + if (\$sAction == 'd') + { + \$sRemoteAction = 'w'; + } + elseif (\$sAction == 'bd') + { + \$sRemoteAction = 'bw'; + } + else + { + \$sRemoteAction = \$sAction; + } + + foreach (self::\$aLINKTOCLASSES[\$sClass] as \$sRemoteClass) + { + \$bUndefined = true; + \$bGrant = self::GetProfileActionGrant(\$iProfileId, \$sRemoteClass, \$sAction); + if (\$bGrant === true) + { + return true; + } + if (\$bGrant === false) + { + \$bUndefined = false; + } + } + if (!\$bUndefined) + { + return false; + } + } + + // 4 - All + // \$sGrantKey = \$iProfileId.'_*_'.\$sAction; if (isset(self::\$aGRANTS[\$sGrantKey])) { return self::\$aGRANTS[\$sGrantKey]; } + + // Still undefined for this class return null; }