From b17c58f17f845ad520857200403c549afe905e09 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Mon, 14 Oct 2024 23:40:58 +0900 Subject: [PATCH 1/7] Implement admin scopes --- modules/module/lang/en.php | 4 ++ modules/module/lang/ko.php | 4 ++ modules/module/models/Permission.php | 64 ++++++++++++++++++++++ modules/module/module.admin.controller.php | 7 ++- modules/module/module.class.php | 12 ++++ modules/module/module.controller.php | 10 +++- modules/module/module.model.php | 52 +++++++++++++++--- modules/module/queries/getModuleAdmin.xml | 3 + modules/module/queries/insertAdminId.xml | 1 + modules/module/schemas/module_admins.xml | 1 + modules/module/tpl/module_grants.html | 17 +++++- 11 files changed, 163 insertions(+), 12 deletions(-) create mode 100644 modules/module/models/Permission.php diff --git a/modules/module/lang/en.php b/modules/module/lang/en.php index 6a81ee07f..d9172183d 100644 --- a/modules/module/lang/en.php +++ b/modules/module/lang/en.php @@ -97,6 +97,10 @@ $lang->about_mobile_page_count = 'You can set the number of page links to move p $lang->about_admin_id = 'You can grant someone permission to manage this module. Please enter the user ID or email address of the person you wish to add.'; $lang->about_grant_deatil = 'Registered users mean users who signed-up to the virtual sites (e.g., cafeXE).'; $lang->about_module = 'Rhymix consists of modules except the basic library. [Module Manage] module will show all installed modules and help you to manage them.'; +$lang->admin_scope = 'Scope of Admin Powers'; +$lang->admin_scopes['moderate:document'] = 'Manage documents'; +$lang->admin_scopes['moderate:comment'] = 'Manage comments'; +$lang->admin_scopes['config:*'] = 'Change settings'; $lang->extra_vars_is_strict = 'Specified values only'; $lang->extra_vars_options = 'Options'; $lang->about_extra_vars_is_strict = 'In single and multiple choice fields, only allow the values specified below. If you change the allowed values, it may affect previous posts.'; diff --git a/modules/module/lang/ko.php b/modules/module/lang/ko.php index 4b4ffe96a..212f0a39a 100644 --- a/modules/module/lang/ko.php +++ b/modules/module/lang/ko.php @@ -96,6 +96,10 @@ $lang->about_mobile_page_count = '목록 하단, 페이지를 이동하는 링 $lang->about_admin_id = '특정 회원에게 이 모듈의 관리 권한을 부여할 수 있습니다. 권한을 부여할 회원의 아이디 또는 이메일 주소를 입력해 주세요.'; $lang->about_grant_deatil = '가입한 사용자는 cafeXE 등 분양형 가상 사이트에 가입을 한 로그인 사용자를 의미합니다.'; $lang->about_module = 'Rhymix는 기본 라이브러리를 제외한 나머지는 모두 모듈로 구성되어 있습니다. 모듈 관리 모듈은 설치된 모든 모듈을 보여주고 관리를 돕습니다.'; +$lang->admin_scope = '관리자 권한 범위'; +$lang->admin_scopes['moderate:document'] = '문서 관리'; +$lang->admin_scopes['moderate:comment'] = '댓글 관리'; +$lang->admin_scopes['config:*'] = '모듈 설정 변경'; $lang->extra_vars_is_strict = '임의입력 금지'; $lang->extra_vars_options = '선택지'; $lang->about_extra_vars_is_strict = '단일/다중 선택에서 미리 주어진 선택지만 입력할 수 있도록 합니다. 선택지를 변경할 경우 기존 게시물에 영향을 줄 수 있습니다.'; diff --git a/modules/module/models/Permission.php b/modules/module/models/Permission.php new file mode 100644 index 000000000..5a3daa591 --- /dev/null +++ b/modules/module/models/Permission.php @@ -0,0 +1,64 @@ +{$scope}) && $scope !== 'scopes') + { + return boolval($this->{$scope}); + } + + if ($this->manager && $this->scopes && preg_match('/^(\w+):(.+)$/', $scope, $matches)) + { + if ($this->scopes === true) + { + return true; + } + if (is_array($this->scopes) && in_array($scope, $this->scopes)) + { + return true; + } + if (is_array($this->scopes) && in_array($matches[1] . ':*', $this->scopes)) + { + return true; + } + } + + return false; + } +} diff --git a/modules/module/module.admin.controller.php b/modules/module/module.admin.controller.php index cc7f6b577..8e4338cfb 100644 --- a/modules/module/module.admin.controller.php +++ b/modules/module/module.admin.controller.php @@ -292,6 +292,11 @@ class ModuleAdminController extends Module // Register Admin ID $oModuleController->deleteAdminId($module_srl); $admin_member = Context::get('admin_member'); + $scopes = Context::get('admin_scopes') ?: null; + if(is_string($scopes) && $scopes !== '') + { + $scopes = explode('|@|', $scopes); + } if($admin_member) { $admin_members = explode(',',$admin_member); @@ -299,7 +304,7 @@ class ModuleAdminController extends Module { $admin_id = trim($admin_id); if(!$admin_id) continue; - $oModuleController->insertAdminId($module_srl, $admin_id); + $oModuleController->insertAdminId($module_srl, $admin_id, $scopes); } } diff --git a/modules/module/module.class.php b/modules/module/module.class.php index e19fc2dbb..8845a2ddd 100644 --- a/modules/module/module.class.php +++ b/modules/module/module.class.php @@ -148,6 +148,12 @@ class Module extends ModuleObject { return true; } + + // check scope column on module_admins table + if (!$oDB->isColumnExists('module_admins', 'scopes')) + { + return true; + } } /** @@ -311,6 +317,12 @@ class Module extends ModuleObject return $output; } } + + // check scope column on module_admins table + if (!$oDB->isColumnExists('module_admins', 'scopes')) + { + $oDB->addColumn('module_admins', 'scopes', 'text', null, null, false, 'member_srl'); + } } /** diff --git a/modules/module/module.controller.php b/modules/module/module.controller.php index 1178cc8ce..93e76cfac 100644 --- a/modules/module/module.controller.php +++ b/modules/module/module.controller.php @@ -806,7 +806,7 @@ class ModuleController extends Module /** * @brief Specify the admin ID to a module */ - function insertAdminId($module_srl, $admin_id) + function insertAdminId($module_srl, $admin_id, $scopes = null) { if (strpos($admin_id, '@') !== false) { @@ -824,6 +824,14 @@ class ModuleController extends Module $args = new stdClass(); $args->module_srl = intval($module_srl); $args->member_srl = $member_info->member_srl; + if (is_array($scopes)) + { + $args->scopes = json_encode(array_values($scopes)); + } + else + { + $args->scopes = new Rhymix\Framework\Parsers\DBQuery\NullValue; + } $output = executeQuery('module.insertAdminId', $args); Rhymix\Framework\Cache::delete("site_and_module:module_admins:" . intval($module_srl)); diff --git a/modules/module/module.model.php b/modules/module/module.model.php index 473185703..4034a53e1 100644 --- a/modules/module/module.model.php +++ b/modules/module/module.model.php @@ -1853,7 +1853,9 @@ class ModuleModel extends Module } /** - * @brief Check if a member is a module administrator + * Check if a member is a module administrator + * + * @return array|bool */ public static function isModuleAdmin($member_info, $module_srl = null) { @@ -1882,14 +1884,22 @@ class ModuleModel extends Module $module_admins = array(); foreach ($output->data as $module_admin) { - $module_admins[$module_admin->member_srl] = true; + $module_admins[$module_admin->member_srl] = $module_admin->scopes ? json_decode($module_admin->scopes) : true; } if ($output->toBool()) { Rhymix\Framework\Cache::set("site_and_module:module_admins:$module_srl", $module_admins, 0, true); } } - return isset($module_admins[$member_info->member_srl]); + + if (isset($module_admins[$member_info->member_srl])) + { + return $module_admins[$member_info->member_srl]; + } + else + { + return false; + } } /** @@ -1900,8 +1910,14 @@ class ModuleModel extends Module $obj = new stdClass(); $obj->module_srl = $module_srl; $output = executeQueryArray('module.getAdminID', $obj); - if(!$output->toBool() || !$output->data) return; - + if (!$output->toBool() || !$output->data) + { + return; + } + foreach ($output->data as $row) + { + $row->scopes = !empty($row->scopes) ? json_decode($row->scopes) : null; + } return $output->data; } @@ -2129,7 +2145,12 @@ class ModuleModel extends Module } /** - * @brief Return privileges(granted) information by using module info, xml info and member info + * Get privileges(granted) information by using module info, xml info and member info + * + * @param object $module_info + * @param object $member_info + * @param ?object $xml_info + * @return Rhymix\Modules\Module\Models\Permission */ public static function getGrant($module_info, $member_info, $xml_info = null) { @@ -2148,8 +2169,6 @@ class ModuleModel extends Module } } - $grant = new stdClass; - // Get information of module.xml if(!$xml_info) { @@ -2172,6 +2191,7 @@ class ModuleModel extends Module $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 @@ -2180,7 +2200,7 @@ class ModuleModel extends Module $grant->{$val} = true; } // If a module manager, grant all (except 'root', 'is_admin') - else if($is_module_admin === true && $val !== 'root' && $val !== 'is_admin') + elseif ($is_module_admin && $val !== 'root' && $val !== 'is_admin') { $grant->{$val} = true; } @@ -2196,6 +2216,20 @@ class ModuleModel extends Module } } + // 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) { diff --git a/modules/module/queries/getModuleAdmin.xml b/modules/module/queries/getModuleAdmin.xml index 55f163796..ef91b3f6c 100644 --- a/modules/module/queries/getModuleAdmin.xml +++ b/modules/module/queries/getModuleAdmin.xml @@ -2,6 +2,9 @@ + + + diff --git a/modules/module/queries/insertAdminId.xml b/modules/module/queries/insertAdminId.xml index 60f1ab088..ed510fcb0 100644 --- a/modules/module/queries/insertAdminId.xml +++ b/modules/module/queries/insertAdminId.xml @@ -5,6 +5,7 @@ + diff --git a/modules/module/schemas/module_admins.xml b/modules/module/schemas/module_admins.xml index 7de4e5545..b98994a83 100644 --- a/modules/module/schemas/module_admins.xml +++ b/modules/module/schemas/module_admins.xml @@ -1,5 +1,6 @@
+
diff --git a/modules/module/tpl/module_grants.html b/modules/module/tpl/module_grants.html index 630c44748..7845360e6 100644 --- a/modules/module/tpl/module_grants.html +++ b/modules/module/tpl/module_grants.html @@ -8,7 +8,7 @@
- +

{$lang->module_admin}

@@ -34,6 +34,21 @@

{$lang->about_admin_id}

+
+ +
+ {@ $default_scopes = array_keys($lang->admin_scopes->getArrayCopy())} + {@ $admin_scopes = $admin_member ? (array_first($admin_member)->scopes ?? $default_scopes) : $default_scopes} + + + +
+
From 008a15bcd5acf9aafa8fbd95c58d092e61548c85 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Mon, 14 Oct 2024 23:41:33 +0900 Subject: [PATCH 2/7] Use admin scopes to check manager privileges --- classes/module/ModuleObject.class.php | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/classes/module/ModuleObject.class.php b/classes/module/ModuleObject.class.php index a203bf9aa..c235289bf 100644 --- a/classes/module/ModuleObject.class.php +++ b/classes/module/ModuleObject.class.php @@ -370,28 +370,36 @@ class ModuleObject extends BaseObject } } // If permission is 'manager', check 'is user have manager privilege(granted)' - else if(preg_match('/^(manager|([a-z0-9\_]+)-managers)$/', $permission, $type)) + else if(preg_match('/^(manager(?::(.+))?|([a-z0-9\_]+)-managers)$/', $permission, $type)) { - if($grant->manager) + // If permission is manager(:scope), check manager privilege and scope + if ($grant->manager) { - return true; + if (empty($type[2])) + { + return true; + } + elseif ($grant->can($type[2])) + { + return true; + } } // If permission is '*-managers', search modules to find manager privilege of the member - if(Context::get('is_logged') && isset($type[2])) + if(Context::get('is_logged') && isset($type[3])) { // Manager privilege of the member is found by search all modules, Pass - if($type[2] == 'all' && ModuleModel::findManagerPrivilege($member_info) !== false) + if($type[3] == 'all' && ModuleModel::findManagerPrivilege($member_info) !== false) { return true; } // Manager privilege of the member is found by search same module as this module, Pass - elseif($type[2] == 'same' && ModuleModel::findManagerPrivilege($member_info, $this->module) !== false) + elseif($type[3] == 'same' && ModuleModel::findManagerPrivilege($member_info, $this->module) !== false) { return true; } // Manager privilege of the member is found by search same module as the module, Pass - elseif(ModuleModel::findManagerPrivilege($member_info, $type[2]) !== false) + elseif(ModuleModel::findManagerPrivilege($member_info, $type[3]) !== false) { return true; } From 8c6beff8590b019bf5c6c18024f73925f92d5054 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Mon, 14 Oct 2024 23:42:06 +0900 Subject: [PATCH 3/7] Apply manager scopes to commonly used modules --- modules/board/conf/module.xml | 20 ++++++++++---------- modules/comment/conf/module.xml | 10 +++++----- modules/document/conf/module.xml | 24 ++++++++++++------------ modules/editor/conf/module.xml | 2 +- modules/file/conf/module.xml | 2 +- modules/point/conf/module.xml | 6 +++--- modules/rss/conf/module.xml | 2 +- 7 files changed, 33 insertions(+), 33 deletions(-) diff --git a/modules/board/conf/module.xml b/modules/board/conf/module.xml index 717fb91cb..da65fbfaa 100644 --- a/modules/board/conf/module.xml +++ b/modules/board/conf/module.xml @@ -116,21 +116,21 @@ - - - - - - - + + + + + + + - - + + - + diff --git a/modules/comment/conf/module.xml b/modules/comment/conf/module.xml index 83841a17a..00e6efbe0 100644 --- a/modules/comment/conf/module.xml +++ b/modules/comment/conf/module.xml @@ -13,8 +13,8 @@ - - + + @@ -23,9 +23,9 @@ - - - + + + diff --git a/modules/document/conf/module.xml b/modules/document/conf/module.xml index 7f7fe8faf..608e364c7 100644 --- a/modules/document/conf/module.xml +++ b/modules/document/conf/module.xml @@ -22,14 +22,14 @@ - - - - - - - - + + + + + + + + @@ -44,11 +44,11 @@ - + - - - + + + diff --git a/modules/editor/conf/module.xml b/modules/editor/conf/module.xml index 61169cbf1..aea50d220 100644 --- a/modules/editor/conf/module.xml +++ b/modules/editor/conf/module.xml @@ -12,7 +12,7 @@ - + diff --git a/modules/file/conf/module.xml b/modules/file/conf/module.xml index 3b0d1da9c..4c5c5f598 100644 --- a/modules/file/conf/module.xml +++ b/modules/file/conf/module.xml @@ -23,7 +23,7 @@ - + diff --git a/modules/point/conf/module.xml b/modules/point/conf/module.xml index 159469433..a455bbc0b 100644 --- a/modules/point/conf/module.xml +++ b/modules/point/conf/module.xml @@ -3,15 +3,15 @@ - + - + - + diff --git a/modules/rss/conf/module.xml b/modules/rss/conf/module.xml index 182f727c1..2bd09130c 100644 --- a/modules/rss/conf/module.xml +++ b/modules/rss/conf/module.xml @@ -7,7 +7,7 @@ - + From 8d8380a36685acd974b0983e9c4affc93207933e Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Mon, 14 Oct 2024 23:42:28 +0900 Subject: [PATCH 4/7] Apply manager scopes to Document and Comment isGranted() --- modules/comment/comment.item.php | 2 +- modules/document/document.item.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/comment/comment.item.php b/modules/comment/comment.item.php index 3be2d3244..096a2f887 100644 --- a/modules/comment/comment.item.php +++ b/modules/comment/comment.item.php @@ -126,7 +126,7 @@ class CommentItem extends BaseObject } $grant = ModuleModel::getGrant(ModuleModel::getModuleInfoByModuleSrl($this->get('module_srl')), $logged_info); - if ($grant->manager) + if ($grant->manager && $grant->can('moderate:comment')) { return $this->grant_cache = true; } diff --git a/modules/document/document.item.php b/modules/document/document.item.php index 4f83caf43..36fdf4c09 100644 --- a/modules/document/document.item.php +++ b/modules/document/document.item.php @@ -218,7 +218,7 @@ class DocumentItem extends BaseObject } $grant = ModuleModel::getGrant(ModuleModel::getModuleInfoByModuleSrl($this->get('module_srl')), $logged_info); - if ($grant->manager) + if ($grant->manager && $grant->can('moderate:document')) { return $this->grant_cache = true; } From a2e5434aec22787dc56cf30e3f886b8db8a17302 Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Mon, 14 Oct 2024 23:42:53 +0900 Subject: [PATCH 5/7] Support manager scopes in Template v2 "can" directive --- common/framework/Template.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/common/framework/Template.php b/common/framework/Template.php index 90302bab9..0049e68d9 100644 --- a/common/framework/Template.php +++ b/common/framework/Template.php @@ -899,19 +899,23 @@ class Template protected function _v2_checkCapability(int $check_type, $capability): bool { $grant = \Context::get('grant'); - if ($check_type === 1) + if (!($grant instanceof \Rhymix\Modules\Module\Models\Permission)) { - return isset($grant->$capability) ? boolval($grant->$capability) : false; + return false; + } + elseif ($check_type === 1) + { + return $grant->can($capability); } elseif ($check_type === 2) { - return isset($grant->$capability) ? !boolval($grant->$capability) : true; + return !$grant->can($capability); } elseif (is_array($capability)) { foreach ($capability as $cap) { - if (isset($grant->$cap) && $grant->$cap) + if ($grant->can($cap)) { return true; } From 64b0d97fbb0342d52dbc158fc64a52e105dbddfa Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Thu, 17 Oct 2024 21:45:17 +0900 Subject: [PATCH 6/7] Add module.getModuleAdminScopes (after) event --- modules/module/module.admin.model.php | 15 +++++++++++++++ modules/module/tpl/module_grants.html | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/modules/module/module.admin.model.php b/modules/module/module.admin.model.php index 72cd82bf1..d2e80c83f 100644 --- a/modules/module/module.admin.model.php +++ b/modules/module/module.admin.model.php @@ -197,6 +197,8 @@ class ModuleAdminModel extends Module // Extract admin ID set in the current module $admin_member = ModuleModel::getAdminId($module_srl) ?: []; Context::set('admin_member', $admin_member); + // Get defined scopes + Context::set('manager_scopes', $this->getModuleAdminScopes()); // Get a list of groups $group_list = MemberModel::getGroups(); Context::set('group_list', $group_list); @@ -286,6 +288,19 @@ class ModuleAdminModel extends Module $this->add('grantList', $grantList); } + /** + * Get defined scopes of module admin. + * + * @return array + */ + public function getModuleAdminScopes(): array + { + $obj = new \stdClass; + $obj->scopes = lang('module.admin_scopes')->getArrayCopy(); + ModuleHandler::triggerCall('module.getModuleAdminScopes', 'after', $obj); + return $obj->scopes; + } + /** * @brief Common:: skin setting page for the module */ diff --git a/modules/module/tpl/module_grants.html b/modules/module/tpl/module_grants.html index 7845360e6..3fd88cc3d 100644 --- a/modules/module/tpl/module_grants.html +++ b/modules/module/tpl/module_grants.html @@ -39,9 +39,9 @@ {$lang->admin_scope}
- {@ $default_scopes = array_keys($lang->admin_scopes->getArrayCopy())} + {@ $default_scopes = array_keys($manager_scopes)} {@ $admin_scopes = $admin_member ? (array_first($admin_member)->scopes ?? $default_scopes) : $default_scopes} - +