Store all grant-related information in Permission class

This commit is contained in:
Kijin Sung 2025-05-21 23:00:29 +09:00
parent d97eb36bbd
commit c89af17410
2 changed files with 191 additions and 155 deletions

View file

@ -7,31 +7,146 @@ class Permission
{
/**
* Default properties.
*
* Note that $is_admin is an alias to $root,
* and $is_site_admin is an alias to $manager.
*/
public $access;
public $root;
public $manager;
public $scopes;
/**
* Alias to $root, kept for backward compatibility only.
*
* @deprecated
* Requirements for this module.
*/
public $is_admin;
protected $_spec = [];
/**
* Alias to $manager, kept for backward compatibility only.
*
* @deprecated
* Scopes for module managers.
*/
public $is_site_admin;
protected $_scopes = [];
/**
* Primary method to determine whether a user is allowed to do something.
* Constructor will be called from ModuleModel::getGrant().
*
* @param array $xml_grant_list
* @param array $module_grants
* @param ?object $module_info
* @param ?object $member_info
*/
public function __construct(array $xml_grant_list, array $module_grants, ?object $module_info = null, ?object $member_info = null)
{
// Collect additional information from module and member info.
$is_module_admin = !empty($module_info->module_srl) ? \ModuleModel::isModuleAdmin($member_info, $module_info->module_srl) : false;
$member_groups = !empty($member_info->group_list) ? array_keys($member_info->group_list) : [];
// Generate the list of default permissions.
$defaults = [
'access' => '',
'root' => 'root',
'manager' => 'manager',
'is_admin' => 'root',
'is_site_admin' => 'root',
];
foreach ($xml_grant_list as $key => $val)
{
$defaults[$key] = $val->default ?? '';
}
// Generate the combined spec for this module.
$this->_spec = $defaults;
foreach ($module_grants as $row)
{
$key = $row->name;
if ($row->group_srl == 0)
{
$this->_spec[$key] = 'guest';
continue;
}
if ($row->group_srl == -1 || $row->group_srl == -2)
{
$this->_spec[$key] = 'member';
continue;
}
if ($row->group_srl == -3)
{
$this->_spec[$key] = 'manager';
continue;
}
if ($row->group_srl > 0)
{
if (!isset($this->_spec[$key]) || !is_array($this->_spec[$key]))
{
$this->_spec[$key] = [];
}
$this->_spec[$key][] = $row->group_srl;
continue;
}
}
// If the spec says nothing about access permissions, it is 'guest' by default.
if (!$this->_spec['access'])
{
$this->_spec['access'] = 'guest';
}
// If the member is an administrator, grant all possible permissions.
if ($member_info && $member_info->is_admin === 'Y')
{
$this->_scopes = true;
foreach ($defaults as $key => $default)
{
$this->{$key} = true;
}
return;
}
elseif ($is_module_admin)
{
$this->_scopes = $is_module_admin;
foreach ($defaults as $key => $default)
{
$this->{$key} = ($default !== 'root');
}
}
// Check if each permission is granted to the current user.
foreach ($this->_spec as $key => $requirement)
{
if ($requirement === 'guest')
{
$this->{$key} = true;
}
elseif ($requirement === 'member')
{
$this->{$key} = ($member_info && $member_info->member_srl);
}
elseif ($requirement === 'manager')
{
$this->{$key} = $this->manager ? true : false;
}
elseif ($requirement === 'root')
{
$this->{$key} = $this->root ? true : false;
}
elseif (is_array($requirement))
{
if (array_intersect($member_groups, $requirement))
{
$this->{$key} = true;
if ($key === 'manager' && $is_module_admin && !$this->_scopes)
{
$this->_scopes = true;
}
}
else
{
$this->{$key} = false;
}
}
}
}
/**
* Find out whether the current user is allowed to do something.
*
* This is more portable than accessing object attributes directly,
* and also supports manager scopes.
*
* @param string $scope
* @return bool
@ -43,17 +158,17 @@ class Permission
return boolval($this->{$scope});
}
if ($this->manager && $this->scopes && preg_match('/^(\w+):(.+)$/', $scope, $matches))
if ($this->manager && $this->_scopes && preg_match('/^(\w+):(.+)$/', $scope, $matches))
{
if ($this->scopes === true)
if ($this->_scopes === true)
{
return true;
}
if (is_array($this->scopes) && in_array($scope, $this->scopes))
if (is_array($this->_scopes) && in_array($scope, $this->_scopes))
{
return true;
}
if (is_array($this->scopes) && in_array($matches[1] . ':*', $this->scopes))
if (is_array($this->_scopes) && in_array($matches[1] . ':*', $this->_scopes))
{
return true;
}
@ -61,4 +176,57 @@ class Permission
return false;
}
/**
* Find out who is allowed to do something.
*
* This method returns 'root', 'manager', 'member', 'guest',
* or an array of group_srls whose members are allowed.
*
* If you pass the name of a scope, the result might vary
* depending on whether you are a module manager.
*
* @param string key
* @return string|array
*/
public function whocan(string $key)
{
if (isset($this->_spec[$key]))
{
return $this->_spec[$key];
}
elseif (preg_match('/^(\w+):(\w+)$/', $key))
{
if ($this->manager)
{
return $this->can($key) ? 'manager' : 'root';
}
else
{
return 'manager';
}
}
else
{
return 'nobody';
}
}
/**
* Magic method to provide deprecated aliases.
*
* @param string $key
* @return mixed
*/
public function __get(string $key)
{
if ($key === 'is_admin' || $key === 'is_site_admin')
{
return $this->root;
}
else
{
return false;
}
}
}

View file

@ -2186,7 +2186,7 @@ class ModuleModel extends Module
*/
public static function getGrant($module_info, $member_info, $xml_info = null)
{
if(empty($module_info->module))
if (empty($module_info->module))
{
$module_info = new stdClass;
$module_info->module = $module_info->module_srl = 0;
@ -2201,148 +2201,16 @@ class ModuleModel extends Module
}
}
// Get information of module.xml
if(!$xml_info)
// Get module grant information
if (!$xml_info)
{
$xml_info = self::getModuleActionXml($module_info->module);
}
$xml_grant_list = isset($xml_info->grant) ? (array)$xml_info->grant : array();
$module_grants = self::getModuleGrants($module_info->module_srl)->data ?: [];
// Get group information of member
$member_group = !empty($member_info->group_list) ? array_keys($member_info->group_list) : array();
$is_module_admin = !empty($module_info->module_srl) ? self::isModuleAdmin($member_info, $module_info->module_srl) : false;
// Get 'privilege name' list from module.xml
$privilege_list = array_keys($xml_grant_list);
// Prepend default 'privilege name'
// manager, is_site_admin not distinguish because of compatibility.
array_unshift($privilege_list, 'access', 'is_admin', 'manager', 'is_site_admin', 'root');
// Unique
$privilege_list = array_unique($privilege_list, SORT_STRING);
// Grant first
$grant = new Rhymix\Modules\Module\Models\Permission;
foreach($privilege_list as $val)
{
// If an administrator, grant all
if($member_info && $member_info->is_admin == 'Y')
{
$grant->{$val} = true;
}
// If a module manager, grant all (except 'root', 'is_admin')
elseif ($is_module_admin && $val !== 'root' && $val !== 'is_admin')
{
$grant->{$val} = true;
}
// If module_srl doesn't exist, grant access
else if(empty($module_info->module_srl) && $val === 'access')
{
$grant->{$val} = true;
}
// Default : not grant
else
{
$grant->{$val} = false;
}
}
// If module admin, add scopes
if ($member_info && $member_info->is_admin == 'Y')
{
$grant->scopes = true;
}
elseif ($is_module_admin)
{
$grant->scopes = $is_module_admin;
}
else
{
$grant->scopes = [];
}
// If access were not granted, check more
if(!$grant->access)
{
$checked = array();
// Grant privileges by information that get from the DB
foreach(self::getModuleGrants($module_info->module_srl)->data as $val)
{
$checked[$val->name] = true;
if($grant->{$val->name})
{
continue;
}
// All user
if($val->group_srl == 0)
{
$grant->{$val->name} = true;
continue;
}
// Log-in member only
if($member_info && $member_info->member_srl)
{
if($val->group_srl == -1 || $val->group_srl == -2)
{
$grant->{$val->name} = true;
}
// Manager only
else if($val->group_srl == -3)
{
if($grant->manager)
{
$grant->{$val->name} = true;
}
}
// If a target is a group
else if(count($member_group) && in_array($val->group_srl, $member_group))
{
$grant->{$val->name} = true;
if ($val->name === 'manager' && !$grant->scopes)
{
$grant->scopes = true;
}
}
}
}
// Grant access by default
if(!isset($checked['access']))
{
$grant->access = true;
}
// Grant privileges by default information of module
foreach($xml_grant_list as $name => $item)
{
if(isset($checked[$name]) || $grant->{$name})
{
continue;
}
// All user
if($item->default == 'guest')
{
$grant->{$name} = true;
continue;
}
// Log-in member only
if($member_info && $member_info->member_srl)
{
if($item->default == 'member' || $item->default == 'site')
{
$grant->{$name} = true;
}
}
}
}
// Generate grant
$grant = new Rhymix\Modules\Module\Models\Permission($xml_grant_list, $module_grants, $module_info, $member_info);
return $__cache = $grant;
}