Alex Monk has uploaded a new change for review.
https://gerrit.wikimedia.org/r/74678
Change subject: WIP - Special:GroupPermissions (CA-like group editor)
......................................................................
WIP - Special:GroupPermissions (CA-like group editor)
This currently relies on CentralAuth because there's a lot of useful i18n
messages there that'll
be annoying to move (it's also missing qqq docs, messages.inc entries, etc.)
For now I would just like feedback on the rest. Those messages should be moved
to core before
merging though of course.
Bug: 27035
Change-Id: I16917a36b7d80fa33d25392b39b8bb73c53b305c
---
M includes/AutoLoader.php
M includes/DefaultSettings.php
M includes/SpecialPageFactory.php
M includes/Wiki.php
M includes/installer/MysqlUpdater.php
A includes/specials/SpecialGroupPermissions.php
M languages/messages/MessagesEn.php
A maintenance/archives/patch-groups.sql
A maintenance/migrateGroupsToDatabase.php
9 files changed, 329 insertions(+), 1 deletion(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core
refs/changes/78/74678/1
diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php
index 33a244b..3d27fca 100644
--- a/includes/AutoLoader.php
+++ b/includes/AutoLoader.php
@@ -943,6 +943,7 @@
'SpecialEmailUser' => 'includes/specials/SpecialEmailuser.php',
'SpecialExport' => 'includes/specials/SpecialExport.php',
'SpecialFilepath' => 'includes/specials/SpecialFilepath.php',
+ 'SpecialGroupPermissions' =>
'includes/specials/SpecialGroupPermissions.php',
'SpecialImport' => 'includes/specials/SpecialImport.php',
'SpecialJavaScriptTest' =>
'includes/specials/SpecialJavaScriptTest.php',
'SpecialListFiles' => 'includes/specials/SpecialListfiles.php',
diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php
index d660f50..91c6e3c 100644
--- a/includes/DefaultSettings.php
+++ b/includes/DefaultSettings.php
@@ -3951,6 +3951,33 @@
#$wgGroupPermissions['bureaucrat']['userrights-interwiki'] = true;
// Permission to export pages including linked pages regardless of
$wgExportMaxLinkDepth
#$wgGroupPermissions['bureaucrat']['override-export-depth'] = true;
+// Permission to edit group permissions
+#$wgGroupConfigSource = 'database';
+#$wgGroupPermissions['bureaucrat']['editgrouppermissions'] = true;
+$wgRestrictedRights = array(
+ 'bigdelete',
+ 'siteadmin',
+ 'suppressionlog',
+ 'suppressrevision',
+ 'userrights-interwiki',
+
+ # Rights defined by extensions. These should remain listed in core for
security reasons (people using an old version of an extension with a new
version of core etc.), but extensions should also add to it (duplicates won't
really hurt)
+ 'centralauth-oversight',
+ 'centralauth-lock',
+ 'centralauth-unmerge',
+
+ 'checkuser',
+ 'checkuser-log',
+
+ 'globalblock',
+ 'globalgroupmembership',
+ 'globalgrouppermissions',
+ 'globalunblock',
+
+ 'hiderevision',
+ 'oversight',
+ 'hideuser',
+);
#$wgGroupPermissions['sysop']['deletelogentry'] = true;
#$wgGroupPermissions['sysop']['deleterevision'] = true;
diff --git a/includes/SpecialPageFactory.php b/includes/SpecialPageFactory.php
index a53b901..4734c95 100644
--- a/includes/SpecialPageFactory.php
+++ b/includes/SpecialPageFactory.php
@@ -101,6 +101,7 @@
'Listbots' => 'SpecialListBots',
'Userrights' => 'UserrightsPage',
'EditWatchlist' => 'SpecialEditWatchlist',
+ 'GroupPermissions' => 'SpecialGroupPermissions',
// Recent changes and logs
'Newimages' => 'SpecialNewFiles',
diff --git a/includes/Wiki.php b/includes/Wiki.php
index f8f699c..307d927 100644
--- a/includes/Wiki.php
+++ b/includes/Wiki.php
@@ -496,7 +496,7 @@
}
private function main() {
- global $wgUseFileCache, $wgTitle, $wgUseAjax;
+ global $wgUseFileCache, $wgTitle, $wgUseAjax,
$wgGroupConfigSource, $wgGroupPermissions;
wfProfileIn( __METHOD__ );
@@ -519,6 +519,20 @@
return;
}
+ if ( $wgGroupConfigSource == 'database' ) {
+ $wgGroupPermissions = array(); // !
+ foreach ( wfGetDB( DB_SLAVE )->select(
+ 'groups',
+ array( 'group_internal_name',
'group_permissions' ),
+ array(),
+ __METHOD__
+ ) as $row ) {
+ foreach ( json_decode( $row->group_permissions
) as $permission => $value ) {
+
$wgGroupPermissions[$row->group_internal_name][$permission] = $value;
+ }
+ }
+ }
+
// Send Ajax requests to the Ajax dispatcher.
if ( $wgUseAjax && $request->getVal( 'action', 'view' ) ==
'ajax' ) {
diff --git a/includes/installer/MysqlUpdater.php
b/includes/installer/MysqlUpdater.php
index df1f610..2664ad2 100644
--- a/includes/installer/MysqlUpdater.php
+++ b/includes/installer/MysqlUpdater.php
@@ -231,6 +231,7 @@
// 1.22
array( 'doIwlinksIndexNonUnique' ),
array( 'addIndex', 'iwlinks', 'iwl_prefix_from_title',
'patch-iwlinks-from-title-index.sql' ),
+ array( 'addTable', 'groups', 'patch-groups.sql' ),
);
}
diff --git a/includes/specials/SpecialGroupPermissions.php
b/includes/specials/SpecialGroupPermissions.php
new file mode 100644
index 0000000..f5e10fe
--- /dev/null
+++ b/includes/specials/SpecialGroupPermissions.php
@@ -0,0 +1,213 @@
+<?php
+/*
+Lots of this file is heavily based on CentralAuth's
SpecialGlobalGroupPermissionss
+TODO: Move loads of i18n stuff to core
+*/
+class SpecialGroupPermissions extends SpecialPage {
+ public function __construct() {
+ parent::__construct( 'GroupPermissions' );
+ }
+
+ public function execute( $subpage ) {
+ if ( !$this->userCanExecute( $this->getUser() ) ) {
+ $this->displayRestrictionError();
+ return;
+ }
+
+ $this->getOutput()->setPageTitle( $this->msg(
'grouppermissions' ) );
+ $this->getOutput()->setRobotPolicy( "noindex,nofollow" );
+ $this->getOutput()->setArticleRelated( false );
+ $this->getOutput()->enableClientCache( false );
+
+ if ( $subpage == '' ) {
+ $subpage = $this->getRequest()->getVal( 'wpGroup' );
+ }
+
+ if ( $subpage != '' && $this->getUser()->matchEditToken(
$this->getRequest()->getVal( 'wpEditToken' ) ) ) {
+ $this->doSubmit( $subpage );
+ } elseif ( $subpage != '' ) {
+ $this->buildGroupView( $subpage );
+ } else {
+ $this->buildMainView();
+ }
+ }
+
+ private function userCanEdit( User $user ) {
+ return $user->isAllowed( 'editgrouppermissions' );
+ }
+
+ private function buildMainView() {
+ global $wgScript, $wgGroupPermissions;
+
+ $groups = array_keys( $wgGroupPermissions );
+
+ // Existing groups
+ $html = Xml::fieldset( $this->msg(
'centralauth-existinggroup-legend' )->text() );
+
+ $this->getOutput()->addHTML( $html );
+
+ if ( count( $groups ) ) {
+ $this->getOutput()->addWikiMsg(
'grouppermissions-grouplistheader' );
+ $this->getOutput()->addHTML( '<ul>' );
+
+ foreach ( $groups as $group ) {
+ $text = $this->msg(
+ 'grouppermissions-grouplistitem',
+ $group == '*' ? '<nowiki>*</nowiki>' :
User::getGroupName( $group ),
+ $group,
+ '<span
class="centralauth-globalgroupperms-groupname">' . $group . '</span>'
+ )->parse();
+
+ $this->getOutput()->addHTML( "<li> $text </li>"
);
+ }
+ } else {
+ $this->getOutput()->addWikiMsg(
'centralauth-globalgroupperms-nogroups' );
+ }
+
+ $this->getOutput()->addHTML( Xml::closeElement( 'ul' ) .
Xml::closeElement( 'fieldset' ) );
+
+ if ( $this->userCanEdit( $this->getUser() ) ) {
+ // "Create a group" prompt
+ $html = Xml::fieldset( $this->msg(
'centralauth-newgroup-legend' )->text() );
+ $html .= $this->msg( 'centralauth-newgroup-intro'
)->parseAsBlock();
+ $html .= Xml::openElement( 'form', array( 'method' =>
'post', 'action' => $wgScript, 'name' => 'centralauth-globalgroups-newgroup' )
);
+ $html .= Html::hidden( 'title',
SpecialPage::getTitleFor( 'GroupPermissions' )->getPrefixedText() );
+
+ $fields = array(
'centralauth-globalgroupperms-newgroupname' => Xml::input( 'wpGroup' ) );
+
+ $html .= Xml::buildForm( $fields,
'centralauth-globalgroupperms-creategroup-submit' );
+ $html .= Xml::closeElement( 'form' );
+ $html .= Xml::closeElement( 'fieldset' );
+
+ $this->getOutput()->addHTML( $html );
+ }
+ }
+
+ /**
+ * @param $group
+ */
+ private function buildGroupView( $group ) {
+ global $wgImplicitGroups;
+ $editable = $this->userCanEdit( $this->getUser() );
+
+ $subtitleMessage = $editable ? 'centralauth-editgroup-subtitle'
: 'centralauth-editgroup-subtitle-readonly';
+ $this->getOutput()->setSubtitle( $this->msg( $subtitleMessage,
$group ) );
+
+ $fieldsetClass = $editable ? 'mw-centralauth-editgroup' :
'mw-centralauth-editgroup-readonly';
+ $html = Xml::fieldset( $this->msg(
'centralauth-editgroup-fieldset', $group )->text(), false, array( 'class' =>
$fieldsetClass ) );
+
+ if ( $editable ) {
+ $html .= Xml::openElement( 'form', array( 'method' =>
'post', 'action' => SpecialPage::getTitleFor( 'GroupPermissions', $group
)->getLocalUrl(), 'name' => 'centralauth-globalgroups-newgroup' ) );
+ $html .= Html::hidden( 'wpGroup', $group );
+ $html .= Html::hidden( 'wpEditToken',
$this->getUser()->getEditToken() );
+ }
+
+ $fields = array( 'centralauth-editgroup-name' => $group );
+
+ $fields['grouppermissions-grouptype'] = $this->msg(
'grouppermissions-' . ( in_array( $group, $wgImplicitGroups ) ? 'im' : 'ex' ) .
'plicit' );
+
+ if ( $group != '*' ) {
+ if ( $this->getUser()->isAllowed( 'editinterface' ) ) {
+ # Show edit link only to user with the
editinterface right
+ $fields['centralauth-editgroup-display'] =
$this->msg( 'centralauth-editgroup-display-edit', $group, User::getGroupName(
$group ) )->parse();
+ $fields['centralauth-editgroup-member'] =
$this->msg( 'centralauth-editgroup-member-edit', $group, User::getGroupMember(
$group ) )->parse();
+ } else {
+ $fields['centralauth-editgroup-display'] =
User::getGroupName( $group );
+ $fields['centralauth-editgroup-member'] =
User::getGroupMember( $group );
+ }
+ }
+
+ if ( !in_array( $group, $wgImplicitGroups ) ) {
+ $fields['centralauth-editgroup-members'] = $this->msg(
'grouppermissions-members-link', $group, User::getGroupMember( $group )
)->parse();
+ }
+ $fields['centralauth-editgroup-perms'] =
$this->buildCheckboxes( $group );
+
+ if ( $editable ) {
+ $fields['centralauth-editgroup-reason'] = Xml::input(
'wpReason', 60 );
+ }
+
+ $html .= Xml::buildForm( $fields, $editable ?
'grouppermissions-submit' : null );
+
+ if ( $editable ) {
+ $html .= Xml::closeElement( 'form' );
+ }
+
+ $html .= Xml::closeElement( 'fieldset' );
+
+ $this->getOutput()->addHTML( $html );
+
+ $this->showLogFragment( $group, $this->getOutput() );
+ }
+
+ /**
+ * @param $group
+ * @return string
+ */
+ function buildCheckboxes( $group ) {
+ global $wgGroupPermissions, $wgGroupConfigSource,
$wgRestrictedRights;
+ $rights = User::getAllRights();
+ $assignedRights = array();
+ if ( isset( $wgGroupPermissions[$group] ) ) {
+ foreach ( $wgGroupPermissions[$group] as $permission =>
$value ) {
+ if ( $value ) {
+ $assignedRights[] = $permission;
+ }
+ }
+ }
+
+ sort( $rights );
+
+ $checkboxes = array();
+
+ foreach ( $rights as $right ) {
+ # Build a checkbox.
+ $checked = in_array( $right, $assignedRights );
+
+ $desc = $this->getOutput()->parseInline(
User::getRightDescription( $right ) ) . ' ' .
+ Xml::element( 'code', null,
$this->msg( 'parentheses', $right )->text() );
+
+ $disabled = !( $this->getUser()->isAllowed(
'editgrouppermissions' ) && $wgGroupConfigSource == 'database' && !in_array(
$right, $wgRestrictedRights ) );
+ $checkbox = Xml::check( "wpRightAssigned-$right",
$checked,
+ array_merge( $disabled ? array( 'disabled' =>
'disabled' ) : array(), array( 'id' => "wpRightAssigned-$right" ) ) );
+ $label = Xml::tags( 'label', array( 'for' =>
"wpRightAssigned-$right" ),
+ $desc );
+
+ $liClass = $checked ?
'mw-centralauth-editgroup-checked' : 'mw-centralauth-editgroup-unchecked';
+ $checkboxes[] = Html::rawElement( 'li', array( 'class'
=> $liClass ), "$checkbox $label" );
+ }
+
+ $count = count( $checkboxes );
+
+ $firstCol = round( $count / 2 );
+
+ $checkboxes1 = array_slice( $checkboxes, 0, $firstCol );
+ $checkboxes2 = array_slice( $checkboxes, $firstCol );
+
+ $html = '<table><tbody><tr><td><ul>';
+
+ foreach ( $checkboxes1 as $cb ) {
+ $html .= $cb;
+ }
+
+ $html .= '</ul></td><td><ul>';
+
+ foreach ( $checkboxes2 as $cb ) {
+ $html .= $cb;
+ }
+
+ $html .= '</ul></td></tr></tbody></table>';
+
+ return $html;
+ }
+
+ /**
+ * @param $group
+ * @param $output OutputPage
+ */
+ protected function showLogFragment( $group, $output ) {
+ $title = SpecialPage::getTitleFor( 'ListUsers', $group );
+ $logPage = new LogPage( 'rights' );
+ $output->addHTML( Xml::element( 'h2', null,
$logPage->getName()->text() . "\n" ) );
+ LogEventsList::showLogExtract( $output, 'rights',
$title->getPrefixedText() );
+ }
+}
diff --git a/languages/messages/MessagesEn.php
b/languages/messages/MessagesEn.php
index c5dba69..137c0f4 100644
--- a/languages/messages/MessagesEn.php
+++ b/languages/messages/MessagesEn.php
@@ -398,6 +398,7 @@
'Fewestrevisions' => array( 'FewestRevisions' ),
'FileDuplicateSearch' => array( 'FileDuplicateSearch' ),
'Filepath' => array( 'FilePath' ),
+ 'GroupPermissions' => array( 'GroupPermissions' ),
'Import' => array( 'Import' ),
'Invalidateemail' => array( 'InvalidateEmail' ),
'JavaScriptTest' => array( 'JavaScriptTest' ),
@@ -4970,4 +4971,15 @@
# Image rotation
'rotate-comment' => 'Image rotated by $1 {{PLURAL:$1|degree|degrees}}
clockwise',
+# Special:GroupPermissions
+'grouppermissions' => 'Group permissions',
+'grouppermissions-grouplistitem' => '$1
([[Special:GroupPermissions/$2|view/edit]])',
+'grouppermissions-grouplistheader' => 'The following groups have been
configured.
+You may view or edit the permissions assigned to a group, if you have
permission to.
+A group may be deleted by removing all rights from it.',
+'grouppermissions-members-link' => '[[Special:ListUsers/$1|List of users with
$2 rights]]',
+'grouppermissions-submit' => 'Save group changes',
+'grouppermissions-grouptype' => 'Group type',
+'grouppermissions-implicit' => 'Implicit',
+'grouppermissions-explicit' => 'Explicit',
);
diff --git a/maintenance/archives/patch-groups.sql
b/maintenance/archives/patch-groups.sql
new file mode 100644
index 0000000..cb672c3
--- /dev/null
+++ b/maintenance/archives/patch-groups.sql
@@ -0,0 +1,4 @@
+CREATE TABLE IF NOT EXISTS /*_*/groups (
+ group_internal_name varbinary(32) NOT NULL,
+ group_permissions BLOB
+) /*$wgDBTableOptions*/;
diff --git a/maintenance/migrateGroupsToDatabase.php
b/maintenance/migrateGroupsToDatabase.php
new file mode 100644
index 0000000..d5a11d9
--- /dev/null
+++ b/maintenance/migrateGroupsToDatabase.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Migrates groups from config to database.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+require_once( __DIR__ . '/Maintenance.php' );
+
+/**
+ * Maintenance script that migrates groups from config to database.
+ *
+ * @ingroup Maintenance
+ */
+class MigrateGroupsToDatabase extends Maintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = "Migrates groups from config to
database.";
+ }
+
+ public function execute() {
+ global $wgGroupPermissions;
+ $db = wfGetDB( DB_MASTER );
+
+ if ( $db->select( 'groups', 'COUNT(*)', array(), __METHOD__
)->fetchRow()[0] != 0 ) {
+ $this->error( "Groups table already has information.",
1 );
+ }
+
+ foreach ( $wgGroupPermissions as $group => $rightsMap ) {
+ $dataToInsert[] = array( 'group_internal_name' =>
$group, 'group_permissions' => json_encode( $rightsMap ) );
+ }
+
+ $db->insert( 'groups', $dataToInsert, __METHOD__ );
+ $this->output( "Done! Now set \$wgGroupConfigSource =
'database';\n" );
+ }
+}
+
+$maintClass = "MigrateGroupsToDatabase";
+require_once( RUN_MAINTENANCE_IF_MAIN );
--
To view, visit https://gerrit.wikimedia.org/r/74678
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I16917a36b7d80fa33d25392b39b8bb73c53b305c
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Alex Monk <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits