mirror of
https://github.com/e107inc/e107.git
synced 2025-08-06 14:46:56 +02:00
Issue #5473 Permissions completed. Tests passing.
This commit is contained in:
@@ -1618,6 +1618,7 @@ class e_admin_dispatcher
|
|||||||
*
|
*
|
||||||
* @return string|array
|
* @return string|array
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public function renderMenu($debug = false)
|
public function renderMenu($debug = false)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -1629,10 +1630,12 @@ class e_admin_dispatcher
|
|||||||
// First loop: Build $var without permissions checks
|
// First loop: Build $var without permissions checks
|
||||||
foreach($adminMenu as $key => $val)
|
foreach($adminMenu as $key => $val)
|
||||||
{
|
{
|
||||||
$parentKey = '';
|
|
||||||
|
// $parentKey = '';
|
||||||
|
|
||||||
$tmp = explode('/', trim($key, '/'), 2); // mode/action
|
$tmp = explode('/', trim($key, '/'), 2); // mode/action
|
||||||
|
|
||||||
|
|
||||||
$isSubItem = !empty($val['group']);
|
$isSubItem = !empty($val['group']);
|
||||||
|
|
||||||
if($isSubItem)
|
if($isSubItem)
|
||||||
@@ -1640,6 +1643,8 @@ class e_admin_dispatcher
|
|||||||
$parentKey = $val['group'] ?? '';
|
$parentKey = $val['group'] ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if(isset($val['selected']) && $val['selected'])
|
if(isset($val['selected']) && $val['selected'])
|
||||||
{
|
{
|
||||||
$selected = $val['selected'] === true ? $key : $val['selected'];
|
$selected = $val['selected'] === true ? $key : $val['selected'];
|
||||||
@@ -1650,7 +1655,7 @@ class e_admin_dispatcher
|
|||||||
|
|
||||||
if($isSubItem)
|
if($isSubItem)
|
||||||
{
|
{
|
||||||
if(!isset($var[$parentKey]))
|
if(empty($var[$parentKey]))
|
||||||
{
|
{
|
||||||
$var[$parentKey] = [
|
$var[$parentKey] = [
|
||||||
'text' => 'Unknown',
|
'text' => 'Unknown',
|
||||||
@@ -1658,21 +1663,43 @@ class e_admin_dispatcher
|
|||||||
'link_id' => str_replace('/', '-', $parentKey)
|
'link_id' => str_replace('/', '-', $parentKey)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
$subKey = str_replace($parentKey . '/', '', $key);
|
|
||||||
$var[$parentKey]['sub'][$subKey] = $processedItem;
|
// Use full key for sub-items to match $adminMenu
|
||||||
|
$subKey = $key;
|
||||||
|
if(!is_array($var[$parentKey]))
|
||||||
|
{
|
||||||
|
$var[$parentKey] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isset($var[$parentKey]['sub'][$subKey]))
|
||||||
|
{
|
||||||
|
$var[$parentKey]['sub'][$subKey] = $processedItem;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$var[$key] = $processedItem;
|
if(!isset($var[$key]))
|
||||||
|
{
|
||||||
|
$var[$key] = $processedItem;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(!$selected)
|
if(!$selected)
|
||||||
{
|
{
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
$selected = $request->getMode() . '/' . $request->getAction();
|
$selected = $request->getMode() . '/' . $request->getAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply permissions restrictions
|
||||||
|
$var = $this->restrictMenuAccess($var, $adminMenu);
|
||||||
|
|
||||||
|
|
||||||
// Second loop: Handle links and collapse attributes without permissions checks
|
// Second loop: Handle links and collapse attributes without permissions checks
|
||||||
foreach($var as $key => &$item)
|
foreach($var as $key => &$item)
|
||||||
{
|
{
|
||||||
@@ -1705,8 +1732,6 @@ class e_admin_dispatcher
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply permissions restrictions
|
|
||||||
$var = $this->restrictMenuAccess($var, $adminMenu);
|
|
||||||
|
|
||||||
if(empty($var))
|
if(empty($var))
|
||||||
{
|
{
|
||||||
@@ -1753,7 +1778,13 @@ class e_admin_dispatcher
|
|||||||
{
|
{
|
||||||
// Check top-level item permissions
|
// Check top-level item permissions
|
||||||
$val = $adminMenu[$key] ?? [];
|
$val = $adminMenu[$key] ?? [];
|
||||||
if((isset($val['perm']) && $val['perm'] !== '' && !$this->hasPerms($val['perm'])) || !$this->hasModeAccess(explode('/', trim($key, '/'), 2)[0]) || !$this->hasRouteAccess($key))
|
|
||||||
|
// Handle single-segment keys (e.g., 'treatment') by using the key as the mode
|
||||||
|
$mode = strpos($key, '/') !== false ? explode('/', trim($key, '/'), 2)[0] : $key;
|
||||||
|
|
||||||
|
// Default to true for hasPerms if perm is unset or empty
|
||||||
|
$hasPerms = isset($val['perm']) && $val['perm'] !== '' ? $this->hasPerms($val['perm']) : true;
|
||||||
|
if(!$hasPerms || !$this->hasModeAccess($mode) || !$this->hasRouteAccess($key))
|
||||||
{
|
{
|
||||||
unset($var[$key]);
|
unset($var[$key]);
|
||||||
continue;
|
continue;
|
||||||
@@ -1766,7 +1797,17 @@ class e_admin_dispatcher
|
|||||||
foreach($item['sub'] as $subKey => &$subItem)
|
foreach($item['sub'] as $subKey => &$subItem)
|
||||||
{
|
{
|
||||||
$subVal = $adminMenu[$subKey] ?? [];
|
$subVal = $adminMenu[$subKey] ?? [];
|
||||||
if(isset($subVal['perm']) && $this->hasPerms($subVal['perm']) && $this->hasRouteAccess($subKey) && $this->hasRouteAccess($parentKey))
|
// Log permissions check for sub-item only when removed
|
||||||
|
if(!isset($subVal['group']) || $subVal['group'] !== $parentKey)
|
||||||
|
{
|
||||||
|
unset($item['sub'][$subKey]);
|
||||||
|
// fwrite(STDOUT, "B. restrictMenuAccess: removing subKey=$subKey, parent=$parentKey, group=" . ($subVal['group'] ?? 'none') . ", perm=" . ($subVal['perm'] ?? 'none') . ", hasPerms=" . var_export(isset($subVal['perm']) && $subVal['perm'] !== '' ? $this->hasPerms($subVal['perm']) : true, true) . ", hasModeAccess=" . var_export($this->hasModeAccess($subMode ?? $subKey), true) . ", hasRouteAccess=" . var_export($this->hasRouteAccess($subKey), true) . ", parentRouteAccess=" . var_export($this->hasRouteAccess($parentKey), true) . "\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$subMode = strpos($subKey, '/') !== false ? explode('/', trim($subKey, '/'), 2)[0] : $subKey;
|
||||||
|
// Default to true for hasPerms if perm is unset or empty
|
||||||
|
$hasPerms = isset($subVal['perm']) && $subVal['perm'] !== '' ? $this->hasPerms($subVal['perm']) : true;
|
||||||
|
if($hasPerms && $this->hasModeAccess($subMode) && $this->hasRouteAccess($subKey) && $this->hasRouteAccess($parentKey))
|
||||||
{
|
{
|
||||||
$hasValidSubItems = true;
|
$hasValidSubItems = true;
|
||||||
}
|
}
|
||||||
@@ -1780,14 +1821,12 @@ class e_admin_dispatcher
|
|||||||
if(!$hasValidSubItems || empty($item['sub']))
|
if(!$hasValidSubItems || empty($item['sub']))
|
||||||
{
|
{
|
||||||
unset($var[$key]);
|
unset($var[$key]);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $var;
|
return $var;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $val
|
* @param $val
|
||||||
* @param $key
|
* @param $key
|
||||||
|
@@ -38,7 +38,7 @@ class e_admin_dispatcherTest extends \Codeception\Test\Unit
|
|||||||
->willReturnCallback(function ($perm)
|
->willReturnCallback(function ($perm)
|
||||||
{
|
{
|
||||||
|
|
||||||
return $perm === 'Y';
|
return $perm === 'P';
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->dp->expects($this->any())
|
$this->dp->expects($this->any())
|
||||||
@@ -86,19 +86,19 @@ class e_admin_dispatcherTest extends \Codeception\Test\Unit
|
|||||||
|
|
||||||
$adminMenu = [
|
$adminMenu = [
|
||||||
'main/list' => ['caption' => 'Manage', 'perm' => '0'],
|
'main/list' => ['caption' => 'Manage', 'perm' => '0'],
|
||||||
'main/create' => ['caption' => 'LAN_CREATE', 'perm' => 'Y'],
|
'main/create' => ['caption' => 'LAN_CREATE', 'perm' => 'P'],
|
||||||
'main/prefs' => ['caption' => 'Settings', 'perm' => 'J', 'icon' => 'fa-cog'],
|
'main/prefs' => ['caption' => 'Settings', 'perm' => 'J', 'icon' => 'fa-cog'],
|
||||||
|
|
||||||
'main/custom' => ['caption' => 'Custom Pages', 'perm' => '0', 'icon' => 'fa-asterisk'],
|
'main/custom' => ['caption' => 'Custom Pages', 'perm' => '0', 'icon' => 'fa-asterisk'],
|
||||||
'main/custom1' => ['group' => 'main/custom', 'caption' => 'Custom Page 1', 'perm' => 'Y'],
|
'main/custom1' => ['group' => 'main/custom', 'caption' => 'Custom Page 1', 'perm' => 'P'],
|
||||||
'main/custom2' => ['group' => 'main/custom', 'caption' => 'Custom Page 2', 'perm' => '0'],
|
'main/custom2' => ['group' => 'main/custom', 'caption' => 'Custom Page 2', 'perm' => '0'],
|
||||||
|
|
||||||
'other/custom' => ['caption' => 'Other Pages', 'perm' => 'Y', 'icon' => 'fa-asterisk'], // should be ignored since no access to sub-items. 'other/custom1' => ['group' => 'other/custom', 'caption' => 'Other Page 1', 'perm' => '0'],
|
'other/custom' => ['caption' => 'Other Pages', 'perm' => 'P', 'icon' => 'fa-asterisk'], // should be ignored since no access to sub-items. 'other/custom1' => ['group' => 'other/custom', 'caption' => 'Other Page 1', 'perm' => '0'],
|
||||||
'other/custom2' => ['group' => 'other/custom', 'caption' => 'Other Page 2', 'perm' => '0'],
|
'other/custom2' => ['group' => 'other/custom', 'caption' => 'Other Page 2', 'perm' => '0'],
|
||||||
|
|
||||||
'misc/custom' => ['caption' => 'Misc Pages', 'perm' => 'Y', 'icon' => 'fa-asterisk'],
|
'misc/custom' => ['caption' => 'Misc Pages', 'perm' => 'P', 'icon' => 'fa-asterisk'],
|
||||||
'misc/custom1' => ['group' => 'misc/custom', 'caption' => 'misc Page 1', 'perm' => '0'],
|
'misc/custom1' => ['group' => 'misc/custom', 'caption' => 'misc Page 1', 'perm' => '0'],
|
||||||
'misc/custom2' => ['group' => 'misc/custom', 'caption' => 'misc Page 2', 'perm' => 'Y'],
|
'misc/custom2' => ['group' => 'misc/custom', 'caption' => 'misc Page 2', 'perm' => 'P'],
|
||||||
];
|
];
|
||||||
|
|
||||||
// Use real setMenuData
|
// Use real setMenuData
|
||||||
@@ -139,24 +139,24 @@ class e_admin_dispatcherTest extends \Codeception\Test\Unit
|
|||||||
|
|
||||||
$adminMenu = [
|
$adminMenu = [
|
||||||
'main/list' => ['caption' => 'Manage', 'perm' => '0'],
|
'main/list' => ['caption' => 'Manage', 'perm' => '0'],
|
||||||
'main/create' => ['caption' => 'LAN_CREATE', 'perm' => 'Y'],
|
'main/create' => ['caption' => 'LAN_CREATE', 'perm' => 'P'],
|
||||||
'main/prefs' => ['caption' => 'Settings', 'perm' => 'Y', 'icon' => 'fa-cog'],
|
'main/prefs' => ['caption' => 'Settings', 'perm' => 'P', 'icon' => 'fa-cog'],
|
||||||
|
|
||||||
'main/custom' => ['caption' => 'Custom Pages', 'perm' => '0', 'icon' => 'fa-asterisk'],
|
'main/custom' => ['caption' => 'Custom Pages', 'perm' => '0', 'icon' => 'fa-asterisk'],
|
||||||
'main/custom1' => ['group' => 'main/custom', 'caption' => 'Custom Page 1', 'perm' => 'Y'],
|
'main/custom1' => ['group' => 'main/custom', 'caption' => 'Custom Page 1', 'perm' => 'P'],
|
||||||
'main/custom2' => ['group' => 'main/custom', 'caption' => 'Custom Page 2', 'perm' => 'Y'],
|
'main/custom2' => ['group' => 'main/custom', 'caption' => 'Custom Page 2', 'perm' => 'P'],
|
||||||
|
|
||||||
'other/custom' => ['caption' => 'Other Pages', 'perm' => 'Y', 'icon' => 'fa-asterisk'],
|
'other/custom' => ['caption' => 'Other Pages', 'perm' => 'P', 'icon' => 'fa-asterisk'],
|
||||||
'other/custom1' => ['group' => 'other/custom', 'caption' => 'Other Page 1', 'perm' => 'Y'],
|
'other/custom1' => ['group' => 'other/custom', 'caption' => 'Other Page 1', 'perm' => 'P'],
|
||||||
'other/custom2' => ['group' => 'other/custom', 'caption' => 'Other Page 2', 'perm' => 'Y'],
|
'other/custom2' => ['group' => 'other/custom', 'caption' => 'Other Page 2', 'perm' => 'P'],
|
||||||
|
|
||||||
'misc/custom' => ['caption' => 'Misc Pages', 'perm' => 'Y', 'icon' => 'fa-asterisk'],
|
'misc/custom' => ['caption' => 'Misc Pages', 'perm' => 'P', 'icon' => 'fa-asterisk'],
|
||||||
'misc/custom1' => ['group' => 'misc/custom', 'caption' => 'misc Page 1', 'perm' => 'Y'],
|
'misc/custom1' => ['group' => 'misc/custom', 'caption' => 'misc Page 1', 'perm' => 'P'],
|
||||||
'misc/custom2' => ['group' => 'misc/custom', 'caption' => 'misc Page 2', 'perm' => 'Y'],
|
'misc/custom2' => ['group' => 'misc/custom', 'caption' => 'misc Page 2', 'perm' => 'P'],
|
||||||
|
|
||||||
'cat/custom' => ['caption' => 'Category Pages', 'perm' => 'Y', 'icon' => 'fa-asterisk'],
|
'cat/custom' => ['caption' => 'Category Pages', 'perm' => 'P', 'icon' => 'fa-asterisk'],
|
||||||
'cat/custom1' => ['group' => 'cat/custom', 'caption' => 'Category Page 1', 'perm' => 'Y'],
|
'cat/custom1' => ['group' => 'cat/custom', 'caption' => 'Category Page 1', 'perm' => 'P'],
|
||||||
'cat/custom2' => ['group' => 'cat/custom', 'caption' => 'Category Page 2', 'perm' => 'Y'],
|
'cat/custom2' => ['group' => 'cat/custom', 'caption' => 'Category Page 2', 'perm' => 'P'],
|
||||||
|
|
||||||
'treatment' => array('caption'=> "Treatment", 'perm' => 'P', 'icon'=>'fas-syringe'),
|
'treatment' => array('caption'=> "Treatment", 'perm' => 'P', 'icon'=>'fas-syringe'),
|
||||||
'treatment/day' => array('group'=>'treatment', 'caption'=> "Treatment Today (Status)", 'perm' => 'P', 'icon'=>'fas-syringe'),
|
'treatment/day' => array('group'=>'treatment', 'caption'=> "Treatment Today (Status)", 'perm' => 'P', 'icon'=>'fas-syringe'),
|
||||||
@@ -208,6 +208,7 @@ class e_admin_dispatcherTest extends \Codeception\Test\Unit
|
|||||||
|
|
||||||
$result = $this->dp->renderMenu(true);
|
$result = $this->dp->renderMenu(true);
|
||||||
|
|
||||||
|
|
||||||
$this::assertNotEmpty($result, 'Render menu result is empty');
|
$this::assertNotEmpty($result, 'Render menu result is empty');
|
||||||
$this::assertArrayNotHasKey('main/list', $result, 'Main list menu item should NOT be present');
|
$this::assertArrayNotHasKey('main/list', $result, 'Main list menu item should NOT be present');
|
||||||
$this::assertNotEmpty($result['main/create'], 'Main create menu item should be present');
|
$this::assertNotEmpty($result['main/create'], 'Main create menu item should be present');
|
||||||
@@ -216,7 +217,10 @@ class e_admin_dispatcherTest extends \Codeception\Test\Unit
|
|||||||
$this::assertArrayNotHasKey('other/custom', $result, 'Other custom group should NOT be present');
|
$this::assertArrayNotHasKey('other/custom', $result, 'Other custom group should NOT be present');
|
||||||
|
|
||||||
$this::assertArrayNotHasKey('cat/custom', $result, 'Category group should NOT be present');
|
$this::assertArrayNotHasKey('cat/custom', $result, 'Category group should NOT be present');
|
||||||
|
$this::assertArrayHasKey('treatment', $result, 'Treatment group should be present '); // This is failing.
|
||||||
|
|
||||||
// $this::assertArrayHasKey('treatment/day', $result, 'Treatment day sub-item should be present'); // This is failing.
|
$this::assertArrayHasKey('schedule/week', $result['treatment']['sub'], 'Treatment Today (Status) should be present '); // This is failing.
|
||||||
|
|
||||||
|
$this::assertArrayHasKey('treatment/day', $result['treatment']['sub'], 'Treatment Today (Scheduled) should be present'); // This is failing.
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1516,7 +1516,7 @@ html { height: auto !important; }
|
|||||||
body { margin-top: 51px; padding: 0 !important; background: #2f2f2f }
|
body { margin-top: 51px; padding: 0 !important; background: #2f2f2f }
|
||||||
.navbar-brand {
|
.navbar-brand {
|
||||||
padding:
|
padding:
|
||||||
10px 17px !important;
|
10px 16px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user