From c89af174102ee06a804b885d49a9149d88aaf95b Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Wed, 21 May 2025 23:00:29 +0900 Subject: [PATCH] Store all grant-related information in Permission class --- modules/module/models/Permission.php | 202 ++++++++++++++++++++++++--- modules/module/module.model.php | 144 +------------------ 2 files changed, 191 insertions(+), 155 deletions(-) diff --git a/modules/module/models/Permission.php b/modules/module/models/Permission.php index 5a3daa591..642dcd512 100644 --- a/modules/module/models/Permission.php +++ b/modules/module/models/Permission.php @@ -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; + } + } } diff --git a/modules/module/module.model.php b/modules/module/module.model.php index 7ed46d06b..e0ae1a57d 100644 --- a/modules/module/module.model.php +++ b/modules/module/module.model.php @@ -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; }