diff --git a/conf/default.php b/conf/default.php index 8d52fae..723ad09 100644 --- a/conf/default.php +++ b/conf/default.php @@ -3,6 +3,7 @@ $conf['apr_namespaces'] = ''; $conf['no_apr_namespaces'] = ''; $conf['number_of_approved'] = 1; +$conf['approving_weights'] = ''; $conf['hidereaderbanner'] = 0; $conf['hide drafts'] = 0; $conf['hide_approved_banner'] = 0; diff --git a/conf/metadata.php b/conf/metadata.php index cb9ea4b..e475937 100644 --- a/conf/metadata.php +++ b/conf/metadata.php @@ -3,6 +3,7 @@ $meta['apr_namespaces'] = array('string'); $meta['no_apr_namespaces'] = array('string'); $meta['number_of_approved'] = array('numeric', '_min' => 1); +$meta['approving_weights'] = array('string', '_pattern' => '#^(\w+=\d+&?)*$#'); $meta['hide drafts'] = array('onoff'); $meta['hidereaderbanner'] = array('onoff'); $meta['hide_approved_banner'] = array('onoff'); diff --git a/helper.php b/helper.php index ea8ba15..59c5354 100644 --- a/helper.php +++ b/helper.php @@ -99,7 +99,21 @@ function canApprove() { return false; } - return ($INFO['perm'] >= AUTH_DELETE); + if ($INFO['perm'] >= AUTH_DELETE) { + return true; + } + + if (empty($INFO['userinfo']['grps'])) { + return false; + } + + $approving_weights = $this->getApprovingWeights(); + if ($approving_weights) { + $approving_groups = array_keys($approving_weights); + return !!array_intersect($approving_groups, $INFO['userinfo']['grps']); + } + + return false; } function getRevision($id = null) { @@ -207,7 +221,52 @@ function isRevisionApproved($revision, $id = null) { if (!isset($approvals[$revision])) { return false; } - return (count($approvals[$revision]) >= $this->getConf('number_of_approved')); + + $number_of_approved = $this->getConf('number_of_approved'); + if (count($approvals[$revision]) >= $number_of_approved) { + return true; + } + + $approving_weights = $this->getApprovingWeights(); + if (!$approving_weights) { + return false; + } + + global $auth; + foreach ($approvals[$revision] as $username => $approver) { + $userdata = $auth->getUserData($username); + if (empty($userdata['grps'])) { + continue; + } + + foreach ($approving_weights as $approving_group => $approving_weight) { + if (in_array($approving_group, $userdata['grps'], true)) { + $number_of_approved -= $approving_weight; + if ($number_of_approved <= 0) { + return true; + } + } + } + } + return false; + } + + /** + * @staticvar array $weights + * @return array + */ + private function getApprovingWeights() { + static $weights = null; + if ($weights === null) { + $qs = $this->getConf('approving_weights'); + if ($qs) { + parse_str($qs, $weights); + $weights = array_filter(array_map('intval', $weights)); + } else { + $weights = []; + } + } + return $weights; } function isCurrentRevisionApproved($id = null) { diff --git a/lang/en/settings.php b/lang/en/settings.php index 9f25083..9f31ed6 100644 --- a/lang/en/settings.php +++ b/lang/en/settings.php @@ -3,6 +3,7 @@ $lang['apr_namespaces'] = 'Namespaces this plugin applies to (space separated list).'; $lang['no_apr_namespaces'] = 'Namespaces this plugin does not apply to (space separated list).'; $lang['number_of_approved'] = 'Number of users needed to approve a page.'; +$lang['approving_weights'] = 'Groups and the number of approvals required to approve a page (for example, if number_of_approved=10 and this option is defined as admin=10&moderator=5&user=1, then a page can be approved by one admin, two moderators, ten users, or one moderator and five users)'; $lang['hidereaderbanner'] = 'Hide banner to read only users'; $lang['hide drafts'] = 'Hide drafts to read only users'; $lang['hide_approved_banner'] = 'Hide banner on approved pages';