Skip to content

Implementing a weighted approval system #130

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions conf/default.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions conf/metadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
63 changes: 61 additions & 2 deletions helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions lang/en/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
$lang['apr_namespaces'] = 'Namespaces this plugin applies to (space separated list).';
$lang['no_apr_namespaces'] = 'Namespaces this plugin <strong>does not</strong> 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 <i>number_of_approved=10</i> and this option is defined as <i>admin=10&moderator=5&user=1</i>, 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';
Expand Down