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';