r87202 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r87201‎ | r87202 | r87203 >
Date:18:41, 1 May 2011
Author:reedy
Status:ok
Tags:
Comment:
Move special classes into special folder
Modified paths:
  • /trunk/extensions/CentralAuth/CentralAuth.php (modified) (history)
  • /trunk/extensions/CentralAuth/SpecialAutoLogin.php (deleted) (history)
  • /trunk/extensions/CentralAuth/SpecialCentralAuth.php (deleted) (history)
  • /trunk/extensions/CentralAuth/SpecialGlobalGroupMembership.php (deleted) (history)
  • /trunk/extensions/CentralAuth/SpecialGlobalGroupPermissions.php (deleted) (history)
  • /trunk/extensions/CentralAuth/SpecialGlobalUsers.php (deleted) (history)
  • /trunk/extensions/CentralAuth/SpecialMergeAccount.php (deleted) (history)
  • /trunk/extensions/CentralAuth/SpecialWikiSets.php (deleted) (history)
  • /trunk/extensions/CentralAuth/specials (added) (history)
  • /trunk/extensions/CentralAuth/specials/SpecialAutoLogin.php (added) (history)
  • /trunk/extensions/CentralAuth/specials/SpecialCentralAuth.php (added) (history)
  • /trunk/extensions/CentralAuth/specials/SpecialGlobalGroupMembership.php (added) (history)
  • /trunk/extensions/CentralAuth/specials/SpecialGlobalGroupPermissions.php (added) (history)
  • /trunk/extensions/CentralAuth/specials/SpecialGlobalUsers.php (added) (history)
  • /trunk/extensions/CentralAuth/specials/SpecialMergeAccount.php (added) (history)
  • /trunk/extensions/CentralAuth/specials/SpecialWikiSets.php (added) (history)

Diff [purge]

Index: trunk/extensions/CentralAuth/SpecialGlobalGroupMembership.php
@@ -1,111 +0,0 @@
2 -<?php
3 -/**
4 - * Equivalent of Special:Userrights for global groups.
5 - *
6 - * @ingroup Extensions
7 - */
8 -
9 -class SpecialGlobalGroupMembership extends UserrightsPage {
10 - var $mGlobalUser;
11 -
12 - function __construct() {
13 - SpecialPage::__construct( 'GlobalGroupMembership' );
14 -
15 - global $wgUser;
16 - $this->mGlobalUser = CentralAuthUser::getInstance( $wgUser );
17 - }
18 -
19 - function getSuccessURL() {
20 - $knownWikis = $this->mGlobalUser->listAttached();
21 - $title = $this->getTitle( $this->mTarget );
22 - return $title->getFullURL( 'wpKnownWiki=' . urlencode( $knownWikis[0] ) );
23 - }
24 -
25 - /**
26 - * Output a form to allow searching for a user
27 - */
28 - function switchForm() {
29 - global $wgOut, $wgScript, $wgRequest;
30 -
31 - $knownwiki = $wgRequest->getVal( 'wpKnownWiki' );
32 - $knownwiki = $knownwiki ? $knownwiki : wfWikiId();
33 -
34 - // Generate wiki selector
35 - $selector = new XmlSelect( 'wpKnownWiki', 'wpKnownWiki', $knownwiki );
36 -
37 - foreach ( CentralAuthUser::getWikiList() as $wiki ) {
38 - $selector->addOption( $wiki );
39 - }
40 -
41 - $wgOut->addModuleStyles( 'mediawiki.special' );
42 - $wgOut->addHTML(
43 - Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript, 'name' => 'uluser', 'id' => 'mw-userrights-form1' ) ) .
44 - Html::hidden( 'title', $this->getTitle() ) .
45 - Xml::openElement( 'fieldset' ) .
46 - Xml::element( 'legend', array(), wfMsg( 'userrights-lookup-user' ) ) .
47 - Xml::inputLabel( wfMsg( 'userrights-user-editname' ), 'user', 'username', 30, $this->mTarget ) . ' <br />' .
48 - Xml::label( wfMsg( 'centralauth-globalgrouppermissions-knownwiki' ), 'wpKnownWiki' ) . ' ' .
49 - $selector->getHTML() . '<br />' .
50 - Xml::submitButton( wfMsg( 'editusergroup' ) ) .
51 - Xml::closeElement( 'fieldset' ) .
52 - Xml::closeElement( 'form' ) . "\n"
53 - );
54 - }
55 -
56 - function changeableGroups() {
57 - # # Should be a global user
58 - if ( !$this->mGlobalUser->exists() || !$this->mGlobalUser->isAttached() ) {
59 - return array();
60 - }
61 -
62 - $allGroups = CentralAuthUser::availableGlobalGroups();
63 -
64 - # # Permission MUST be gained from global rights.
65 - if ( $this->mGlobalUser->hasGlobalPermission( 'globalgroupmembership' ) ) {
66 - # specify addself and removeself as empty arrays -- bug 16098
67 - return array( 'add' => $allGroups, 'remove' => $allGroups, 'add-self' => array(), 'remove-self' => array() );
68 - } else {
69 - return array( 'add' => array(), 'remove' => array(), 'add-self' => array(), 'remove-self' => array() );
70 - }
71 - }
72 -
73 - function fetchUser( $username ) {
74 - global $wgRequest;
75 -
76 - $knownwiki = $wgRequest->getVal( 'wpKnownWiki' );
77 -
78 - $user = CentralAuthGroupMembershipProxy::newFromName( $username );
79 -
80 - if ( !$user ) {
81 - return Status::newFatal( 'nosuchusershort', $username );
82 - } elseif ( !$wgRequest->getCheck( 'saveusergroups' ) && !$user->attachedOn( $knownwiki ) ) {
83 - return Status::newFatal( 'centralauth-globalgroupmembership-badknownwiki',
84 - $username, $knownwiki );
85 - }
86 -
87 - return Status::newGood( $user );
88 - }
89 -
90 - protected static function getAllGroups() {
91 - return CentralAuthUser::availableGlobalGroups();
92 - }
93 -
94 - protected function showLogFragment( $user, $output ) {
95 - $pageTitle = Title::makeTitleSafe( NS_USER, $user->getName() );
96 - $output->addHTML( Xml::element( 'h2', null, LogPage::logName( 'gblrights' ) . "\n" ) );
97 - LogEventsList::showLogExtract( $output, 'gblrights', $pageTitle->getPrefixedText() );
98 - }
99 -
100 - function addLogEntry( $user, $oldGroups, $newGroups, $reason ) {
101 - $log = new LogPage( 'gblrights' );
102 -
103 - $log->addEntry( 'usergroups',
104 - $user->getUserPage(),
105 - $reason,
106 - array(
107 - $this->makeGroupNameList( $oldGroups ),
108 - $this->makeGroupNameList( $newGroups )
109 - )
110 - );
111 - }
112 -}
Index: trunk/extensions/CentralAuth/SpecialAutoLogin.php
@@ -1,86 +0,0 @@
2 -<?php
3 -if ( !defined( 'MEDIAWIKI' ) ) {
4 - die( 'CentralAuth' );
5 -}
6 -
7 -/**
8 - * Unlisted Special page to set requisite cookies for being logged into this wiki.
9 - *
10 - * @ingroup Extensions
11 - */
12 -class SpecialAutoLogin extends UnlistedSpecialPage {
13 - function __construct() {
14 - parent::__construct( 'AutoLogin' );
15 - }
16 -
17 - function execute( $par ) {
18 - global $wgRequest, $wgOut, $wgMemc;
19 -
20 - $tempToken = $wgRequest->getVal( 'token' );
21 - $logout = $wgRequest->getBool( 'logout' );
22 -
23 - # Don't cache error messages
24 - $wgOut->enableClientCache( false );
25 -
26 - if ( strlen( $tempToken ) == 0 ) {
27 - $this->setHeaders();
28 - $wgOut->addWikiMsg( 'centralauth-autologin-desc' );
29 - return;
30 - }
31 -
32 - $key = CentralAuthUser::memcKey( 'login-token', $tempToken );
33 - $data = $wgMemc->get( $key );
34 - $wgMemc->delete( $key );
35 -
36 - if ( !$data ) {
37 - $msg = 'Token is invalid or has expired';
38 - wfDebug( __METHOD__ . ": $msg\n" );
39 - $this->setHeaders();
40 - $wgOut->addWikiText( $msg );
41 - return;
42 - }
43 -
44 - $userName = $data['userName'];
45 - $token = $data['token'];
46 - $remember = $data['remember'];
47 -
48 - if ( $data['wiki'] != wfWikiID() ) {
49 - $msg = 'Bad token (wrong wiki)';
50 - wfDebug( __METHOD__ . ": $msg\n" );
51 - $this->setHeaders();
52 - $wgOut->addWikiText( $msg );
53 - return;
54 - }
55 -
56 - $centralUser = new CentralAuthUser( $userName );
57 - $loginResult = $centralUser->authenticateWithToken( $token );
58 -
59 - if ( $loginResult != 'ok' ) {
60 - $msg = "Bad token: $loginResult";
61 - wfDebug( __METHOD__ . ": $msg\n" );
62 - $this->setHeaders();
63 - $wgOut->addWikiText( $msg );
64 - return;
65 - }
66 -
67 - // Auth OK.
68 - if ( $logout ) {
69 - $centralUser->deleteGlobalCookies();
70 - } else {
71 - $centralUser->setGlobalCookies( $remember );
72 - }
73 -
74 - $wgOut->disable();
75 -
76 - wfResetOutputBuffers();
77 - header( 'Cache-Control: no-cache' );
78 - header( 'Content-Type: image/png' );
79 -
80 - global $wgCentralAuthLoginIcon;
81 - if ( $wgCentralAuthLoginIcon ) {
82 - readfile( $wgCentralAuthLoginIcon );
83 - } else {
84 - readfile( dirname( __FILE__ ) . '/1x1.png' );
85 - }
86 - }
87 -}
Index: trunk/extensions/CentralAuth/SpecialWikiSets.php
@@ -1,293 +0,0 @@
2 -<?php
3 -/**
4 - * Special page to allow to edit "wikisets" which are used to restrict
5 - * specific global group permissions to certain wikis.
6 - *
7 - * @file
8 - * @ingroup Extensions
9 - */
10 -
11 -if ( !defined( 'MEDIAWIKI' ) ) {
12 - echo "CentralAuth extension\n";
13 - exit( 1 );
14 -}
15 -
16 -
17 -class SpecialWikiSets extends SpecialPage {
18 - var $mCanEdit;
19 -
20 - function __construct() {
21 - parent::__construct( 'WikiSets' );
22 - }
23 -
24 - function getDescription() {
25 - return wfMsg( 'centralauth-editset' );
26 - }
27 -
28 - function execute( $subpage ) {
29 - global $wgRequest, $wgOut, $wgUser;
30 -
31 - $this->mCanEdit = $wgUser->isAllowed( 'globalgrouppermissions' );
32 -
33 - $this->setHeaders();
34 -
35 - if ( strpos( $subpage, 'delete/' ) === 0 && $this->mCanEdit ) {
36 - $subpage = substr( $subpage, 7 ); // Remove delete/ part
37 - if ( is_numeric( $subpage ) ) {
38 - if ( $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ) )
39 - $this->doDelete( $subpage );
40 - else
41 - $this->buildDeleteView( $subpage );
42 - } else {
43 - $this->buildMainView();
44 - }
45 - } else {
46 - if ( $subpage ) {
47 - $set = is_numeric( $subpage ) ? WikiSet::newFromId( $subpage ) : WikiSet::newFromName( $subpage );
48 - if ( $set ) {
49 - $subpage = $set->getID();
50 - } else {
51 - $wgOut->setPageTitle( wfMsg( 'error' ) );
52 - $error = wfMsgExt( 'centralauth-editset-notfound', array( 'escapenoentities' ), $subpage );
53 - $this->buildMainView( "<strong class='error'>{$error}</strong>" );
54 - return;
55 - }
56 - }
57 -
58 - if ( ( $subpage || $subpage === '0' ) && $this->mCanEdit && $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ) ) {
59 - $this->doSubmit( $subpage );
60 - } else if ( ( $subpage || $subpage === '0' ) && is_numeric( $subpage ) ) {
61 - $this->buildSetView( $subpage );
62 - } else {
63 - $this->buildMainView();
64 - }
65 - }
66 - }
67 -
68 - function buildMainView( $msg = '' ) {
69 - global $wgOut, $wgUser;
70 - $sk = $wgUser->getSkin();
71 -
72 - $msgPostfix = $this->mCanEdit ? 'rw' : 'ro';
73 - $legend = wfMsg( "centralauth-editset-legend-{$msgPostfix}" );
74 - $wgOut->addHTML( "<fieldset><legend>{$legend}</legend>" );
75 - if ( $msg )
76 - $wgOut->addHTML( $msg );
77 - $wgOut->addWikiMsg( "centralauth-editset-intro-{$msgPostfix}" );
78 - $wgOut->addHTML( '<ul>' );
79 -
80 - $sets = WikiSet::getAllWikiSets();
81 - foreach ( $sets as $set ) {
82 - $text = wfMsgExt( "centralauth-editset-item-{$msgPostfix}", array( 'parseinline' ), $set->getName(), $set->getID() );
83 - $wgOut->addHTML( "<li>{$text}</li>" );
84 - }
85 -
86 - if ( $this->mCanEdit ) {
87 - $target = SpecialPage::getTitleFor( 'WikiSets', '0' );
88 - $newlink = $sk->makeLinkObj( $target, wfMsgHtml( 'centralauth-editset-new' ) );
89 - $wgOut->addHTML( "<li>{$newlink}</li>" );
90 - }
91 -
92 - $wgOut->addHTML( '</ul></fieldset>' );
93 - }
94 -
95 - function buildSetView( $subpage, $error = false, $name = null, $type = null, $wikis = null, $reason = null ) {
96 - global $wgOut, $wgUser;
97 -
98 - $wgOut->setSubtitle( wfMsgExt( 'centralauth-editset-subtitle', 'parseinline' ) );
99 -
100 - $set = $subpage ? WikiSet::newFromID( $subpage ) : null;
101 - if ( !$name ) $name = $set ? $set->getName() : '';
102 - if ( !$type ) $type = $set ? $set->getType() : WikiSet::OPTIN;
103 - if ( !$wikis ) $wikis = implode( "\n", $set ? $set->getWikisRaw() : array() );
104 - else $wikis = implode( "\n", $wikis );
105 - $url = SpecialPage::getTitleFor( 'WikiSets', $subpage )->getLocalUrl();
106 - if ( $this->mCanEdit ) {
107 - $legend = wfMsgHtml( 'centralauth-editset-legend-' . ( $set ? 'edit' : 'new' ), $name );
108 - } else {
109 - $legend = wfMsgHtml( 'centralauth-editset-legend-view', $name );
110 - }
111 -
112 - $wgOut->addHTML( "<fieldset><legend>{$legend}</legend>" );
113 -
114 - if ( $set ) {
115 - $groups = $set->getRestrictedGroups();
116 - if ( $groups ) {
117 - $usage = "<ul>\n";
118 - foreach ( $groups as $group )
119 - $usage .= "<li>" . wfMsgExt( 'centralauth-editset-grouplink', 'parseinline', $group ) . "</li>\n";
120 - $usage .= "</ul>";
121 - } else {
122 - $usage = wfMsgExt( 'centralauth-editset-nouse', 'parse' );
123 - }
124 - } else {
125 - $usage = '';
126 - }
127 -
128 - if ( $this->mCanEdit ) {
129 - if ( $error ) {
130 - $wgOut->addHTML( "<strong class='error'>{$error}</strong>" );
131 - }
132 - $wgOut->addHTML( "<form action='{$url}' method='post'>" );
133 -
134 - $form = array();
135 - $form['centralauth-editset-name'] = Xml::input( 'wpName', false, $name );
136 - if ( $usage ) {
137 - $form['centralauth-editset-usage'] = $usage;
138 - }
139 - $form['centralauth-editset-type'] = $this->buildTypeSelector( 'wpType', $type );
140 - $form['centralauth-editset-wikis'] = Xml::textarea( 'wpWikis', $wikis );
141 - $form['centralauth-editset-reason'] = Xml::input( 'wpReason', false, $reason );
142 -
143 - $wgOut->addHTML( Xml::buildForm( $form, 'centralauth-editset-submit' ) );
144 -
145 - $edittoken = Html::hidden( 'wpEditToken', $wgUser->editToken() );
146 - $wgOut->addHTML( "<p>{$edittoken}</p></form></fieldset>" );
147 - } else {
148 - $form = array();
149 - $form['centralauth-editset-name'] = htmlspecialchars( $name );
150 - $form['centralauth-editset-usage'] = $usage;
151 - $form['centralauth-editset-type'] = wfMsg( "centralauth-editset-{$type}" );
152 - $form['centralauth-editset-wikis'] = $this->buildWikiList( $set->getWikisRaw() );
153 -
154 - $wgOut->addHTML( Xml::buildForm( $form ) );
155 - }
156 - }
157 -
158 - function buildTypeSelector( $name, $value ) {
159 - $select = new XmlSelect( $name, 'set-type', $value );
160 - foreach ( array( WikiSet::OPTIN, WikiSet::OPTOUT ) as $type ) {
161 - $select->addOption( wfMsg( "centralauth-editset-{$type}" ), $type );
162 - }
163 - return $select->getHTML();
164 - }
165 -
166 - function buildWikiList( $list ) {
167 - sort( $list );
168 - $html = '<ul>';
169 - foreach ( $list as $wiki ) {
170 - $escWiki = htmlspecialchars( $wiki );
171 - $html .= "<li>{$escWiki}</li>";
172 - }
173 - $html .= '</ul>';
174 - return $html;
175 - }
176 -
177 - function buildDeleteView( $subpage ) {
178 - global $wgOut, $wgUser;
179 - $wgOut->setSubtitle( wfMsgExt( 'centralauth-editset-subtitle', 'parseinline' ) );
180 -
181 - $set = WikiSet::newFromID( $subpage );
182 - if ( !$set ) {
183 - $this->buildMainView( '<strong class="error">' . wfMsgHtml( 'centralauth-editset-notfound', $subpage ) . '</strong>' );
184 - return;
185 - }
186 -
187 - $legend = wfMsgHtml( 'centralauth-editset-legend-delete', $set->getName() );
188 - $form = array( 'centralauth-editset-reason' => Xml::input( 'wpReason' ) );
189 - $url = htmlspecialchars( SpecialPage::getTitleFor( 'WikiSets', "delete/{$subpage}" )->getLocalUrl() );
190 - $edittoken = Html::hidden( 'wpEditToken', $wgUser->editToken() );
191 -
192 - $wgOut->addHTML( "<fieldset><legend>{$legend}</legend><form action='{$url}' method='post'>" );
193 - $wgOut->addHTML( Xml::buildForm( $form, 'centralauth-editset-submit-delete' ) );
194 - $wgOut->addHTML( "<p>{$edittoken}</p></form></fieldset>" );
195 - }
196 -
197 - function doSubmit( $id ) {
198 - global $wgRequest, $wgContLang;
199 -
200 - $name = $wgContLang->ucfirst( $wgRequest->getVal( 'wpName' ) );
201 - $type = $wgRequest->getVal( 'wpType' );
202 - $wikis = array_unique( preg_split( '/(\s+|\s*\W\s*)/', $wgRequest->getVal( 'wpWikis' ), -1, PREG_SPLIT_NO_EMPTY ) );
203 - $reason = $wgRequest->getVal( 'wpReason' );
204 - $set = WikiSet::newFromId( $id );
205 -
206 - if ( !Title::newFromText( $name ) ) {
207 - $this->buildSetView( $id, wfMsgHtml( 'centralauth-editset-badname' ), $name, $type, $wikis, $reason );
208 - return;
209 - }
210 - if ( ( !$id || $set->getName() != $name ) && WikiSet::newFromName( $name ) ) {
211 - $this->buildSetView( $id, wfMsgHtml( 'centralauth-editset-setexists' ), $name, $type, $wikis, $reason );
212 - return;
213 - }
214 - if ( !in_array( $type, array( WikiSet::OPTIN, WikiSet::OPTOUT ) ) ) {
215 - $this->buildSetView( $id, wfMsgHtml( 'centralauth-editset-badtype' ), $name, $type, $wikis, $reason );
216 - return;
217 - }
218 - if ( !$wikis ) {
219 - $this->buildSetView( $id, wfMsgHtml( 'centralauth-editset-nowikis' ), $name, $type, $wikis, $reason );
220 - return;
221 - }
222 - $badwikis = array();
223 - $allwikis = CentralAuthUser::getWikiList();
224 - foreach ( $wikis as $wiki ) {
225 - if ( !in_array( $wiki, $allwikis ) ) {
226 - $badwikis[] = $wiki;
227 - }
228 - }
229 - if ( $badwikis ) {
230 - $this->buildSetView( $id, wfMsgExt( 'centralauth-editset-badwikis', array( 'escapenoentities', 'parsemag' ),
231 - implode( ', ', $badwikis ), count( $badwikis ) ), $name, $type, $wikis, $reason );
232 - return;
233 - }
234 -
235 - if ( $set ) {
236 - $oldname = $set->getName();
237 - $oldtype = $set->getType();
238 - $oldwikis = $set->getWikisRaw();
239 - } else {
240 - $set = new WikiSet();
241 - $oldname = $oldtype = null; $oldwikis = array();
242 - }
243 - $set->setName( $name );
244 - $set->setType( $type );
245 - $set->setWikisRaw( $wikis );
246 - $set->commit();
247 -
248 - // Now logging
249 - $log = new LogPage( 'gblrights' );
250 - $title = SpecialPage::getTitleFor( 'WikiSets', $set->getID() );
251 - if ( !$oldname ) {
252 - // New set
253 - $log->addEntry( 'newset', $title, $reason, array( $name, $type, implode( ', ', $wikis ) ) );
254 - } else {
255 - if ( $oldname != $name ) {
256 - $log->addEntry( 'setrename', $title, $reason, array( $name, $oldname ) );
257 - }
258 - if ( $oldtype != $type ) {
259 - $log->addEntry( 'setnewtype', $title, $reason, array( $name, $oldtype, $type ) );
260 - }
261 - $added = implode( ', ', array_diff( $wikis, $oldwikis ) );
262 - $removed = implode( ', ', array_diff( $oldwikis, $wikis ) );
263 - if ( $added || $removed ) {
264 - $log->addEntry( 'setchange', $title, $reason, array( $name, $added, $removed ) );
265 - }
266 - }
267 -
268 - global $wgUser, $wgOut;
269 - $sk = $wgUser->getSkin();
270 - $returnLink = $sk->makeKnownLinkObj( $this->getTitle(), wfMsg( 'centralauth-editset-return' ) );
271 -
272 - $wgOut->addHTML( '<strong class="success">' . wfMsgHtml( 'centralauth-editset-success' ) . '</strong> <p>' . $returnLink . '</p>' );
273 - }
274 -
275 - function doDelete( $set ) {
276 - global $wgRequest;
277 -
278 - $set = WikiSet::newFromID( $set );
279 - if ( !$set ) {
280 - $this->buildMainView( '<strong class="error">' . wfMsgHtml( 'centralauth-editset-notfound', $subpage ) . '</strong>' );
281 - return;
282 - }
283 -
284 - $reason = $wgRequest->getVal( 'wpReason' );
285 - $name = $set->getName();
286 - $set->delete();
287 -
288 - $title = SpecialPage::getTitleFor( 'WikiSets', $set->getID() );
289 - $log = new LogPage( 'gblrights' );
290 - $log->addEntry( 'deleteset', $title, $reason, array( $name ) );
291 -
292 - $this->buildMainView( '<strong class="success">' . wfMsg( 'centralauth-editset-success-delete' ) . '</strong>' );
293 - }
294 -}
Index: trunk/extensions/CentralAuth/SpecialGlobalGroupPermissions.php
@@ -1,370 +0,0 @@
2 -<?php
3 -# This file is part of MediaWiki.
4 -
5 -# MediaWiki is free software: you can redistribute it and/or modify
6 -# it under the terms of version 2 of the GNU General Public License
7 -# as published by the Free Software Foundation.
8 -
9 -# MediaWiki is distributed in the hope that it will be useful,
10 -# but WITHOUT ANY WARRANTY; without even the implied warranty of
11 -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 -# GNU General Public License for more details.
13 -
14 -/**
15 - * Special page to allow managing global groups
16 - * Prototype for a similar system in core.
17 - *
18 - * @file
19 - * @ingroup Extensions
20 - */
21 -
22 -if ( !defined( 'MEDIAWIKI' ) ) {
23 - echo "CentralAuth extension\n";
24 - exit( 1 );
25 -}
26 -
27 -class SpecialGlobalGroupPermissions extends SpecialPage {
28 - function __construct() {
29 - parent::__construct( 'GlobalGroupPermissions' );
30 - }
31 -
32 - function userCanEdit( $user ) {
33 - $globalUser = CentralAuthUser::getInstance( $user );
34 -
35 - # # Should be a global user
36 - if ( !$globalUser->exists() || !$globalUser->isAttached() ) {
37 - return false;
38 - }
39 -
40 - # # Permission MUST be gained from global rights.
41 - return $globalUser->hasGlobalPermission( 'globalgrouppermissions' );
42 - }
43 -
44 - function execute( $subpage ) {
45 - global $wgRequest, $wgOut, $wgUser;
46 -
47 - if ( !$this->userCanExecute( $wgUser ) ) {
48 - $this->displayRestrictionError();
49 - return;
50 - }
51 -
52 - $wgOut->setPageTitle( wfMsg( 'globalgrouppermissions' ) );
53 - $wgOut->setRobotPolicy( "noindex,nofollow" );
54 - $wgOut->setArticleRelated( false );
55 - $wgOut->enableClientCache( false );
56 -
57 - if ( $subpage == '' ) {
58 - $subpage = $wgRequest->getVal( 'wpGroup' );
59 - }
60 -
61 - if ( $subpage != '' && $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ) ) {
62 - $this->doSubmit( $subpage );
63 - } else if ( $subpage != '' ) {
64 - $this->buildGroupView( $subpage );
65 - } else {
66 - $this->buildMainView();
67 - }
68 - }
69 -
70 - function buildMainView() {
71 - global $wgOut, $wgUser, $wgScript;
72 -
73 - $groups = CentralAuthUser::availableGlobalGroups();
74 -
75 - // Existing groups
76 - $html = Xml::fieldset( wfMsg( 'centralauth-existinggroup-legend' ) );
77 -
78 - $wgOut->addHTML( $html );
79 -
80 - if ( count( $groups ) ) {
81 - $wgOut->addWikiMsg( 'centralauth-globalgroupperms-grouplist' );
82 - $wgOut->addHTML( '<ul>' );
83 -
84 - foreach ( $groups as $group ) {
85 - $text = wfMsgExt( 'centralauth-globalgroupperms-grouplistitem', array( 'parseinline' ), User::getGroupName( $group ), $group, '<span class="centralauth-globalgroupperms-groupname">' . $group . '</span>' );
86 -
87 - $wgOut->addHTML( "<li> $text </li>" );
88 - }
89 - } else {
90 - $wgOut->addWikiMsg( 'centralauth-globalgroupperms-nogroups' );
91 - }
92 -
93 - $wgOut->addHTML( Xml::closeElement( 'ul' ) . Xml::closeElement( 'fieldset' ) );
94 -
95 - if ( $this->userCanEdit( $wgUser ) ) {
96 - // "Create a group" prompt
97 - $html = Xml::fieldset( wfMsg( 'centralauth-newgroup-legend' ) );
98 - $html .= wfMsgExt( 'centralauth-newgroup-intro', array( 'parse' ) );
99 - $html .= Xml::openElement( 'form', array( 'method' => 'post', 'action' => $wgScript, 'name' => 'centralauth-globalgroups-newgroup' ) );
100 - $html .= Html::hidden( 'title', SpecialPage::getTitleFor( 'GlobalGroupPermissions' )->getPrefixedText() );
101 -
102 - $fields = array( 'centralauth-globalgroupperms-newgroupname' => Xml::input( 'wpGroup' ) );
103 -
104 - $html .= Xml::buildForm( $fields, 'centralauth-globalgroupperms-creategroup-submit' );
105 - $html .= Xml::closeElement( 'form' );
106 - $html .= Xml::closeElement( 'fieldset' );
107 -
108 - $wgOut->addHTML( $html );
109 - }
110 - }
111 -
112 - function buildGroupView( $group ) {
113 - global $wgOut, $wgUser;
114 -
115 - $editable = $this->userCanEdit( $wgUser );
116 -
117 - $wgOut->setSubtitle( wfMsg( 'centralauth-editgroup-subtitle', $group ) );
118 -
119 - $html = Xml::fieldset( wfMsg( 'centralauth-editgroup-fieldset', $group ) );
120 -
121 - if ( $editable ) {
122 - $html .= Xml::openElement( 'form', array( 'method' => 'post', 'action' => SpecialPage::getTitleFor( 'GlobalGroupPermissions', $group )->getLocalUrl(), 'name' => 'centralauth-globalgroups-newgroup' ) );
123 - $html .= Html::hidden( 'wpGroup', $group );
124 - $html .= Html::hidden( 'wpEditToken', $wgUser->editToken() );
125 - }
126 -
127 - $fields = array();
128 -
129 - $fields['centralauth-editgroup-name'] = $group;
130 - $fields['centralauth-editgroup-display'] = wfMsgExt( 'centralauth-editgroup-display-edit', array( 'parseinline' ), $group, User::getGroupName( $group ) );
131 - $fields['centralauth-editgroup-member'] = wfMsgExt( 'centralauth-editgroup-member-edit', array( 'parseinline' ), $group, User::getGroupMember( $group ) );
132 - $fields['centralauth-editgroup-members'] = wfMsgExt( 'centralauth-editgroup-members-link', array( 'parseinline' ), $group, User::getGroupMember( $group ) );
133 - $fields['centralauth-editgroup-restrictions'] = $this->buildWikiSetSelector( $group );
134 - $fields['centralauth-editgroup-perms'] = $this->buildCheckboxes( $group );
135 -
136 - if ( $editable ) {
137 - $fields['centralauth-editgroup-reason'] = Xml::input( 'wpReason', 60 );
138 - }
139 -
140 - $html .= Xml::buildForm( $fields, $editable ? 'centralauth-editgroup-submit' : null );
141 -
142 - if ( $editable )
143 - $html .= Xml::closeElement( 'form' );
144 -
145 - $html .= Xml::closeElement( 'fieldset' );
146 -
147 - $wgOut->addHTML( $html );
148 -
149 - $this->showLogFragment( $group, $wgOut );
150 - }
151 -
152 - function buildWikiSetSelector( $group ) {
153 - $sets = WikiSet::getAllWikiSets();
154 - $default = WikiSet::getWikiSetForGroup( $group );
155 -
156 - global $wgUser;
157 - if ( !$this->userCanEdit( $wgUser ) )
158 - return htmlspecialchars( $default );
159 -
160 - $select = new XmlSelect( 'set', 'wikiset', $default );
161 - $select->addOption( wfMsg( 'centralauth-editgroup-noset' ), '0' );
162 - foreach ( $sets as $set ) {
163 - $select->addOption( $set->getName(), $set->getID() );
164 - }
165 -
166 - $editlink = wfMsgExt( "centralauth-editgroup-editsets", array( "parseinline" ) );
167 - return $select->getHTML() . "&#160;{$editlink}";
168 - }
169 -
170 - function buildCheckboxes( $group ) {
171 - global $wgUser, $wgOut;
172 -
173 - $editable = $this->userCanEdit( $wgUser );
174 -
175 - $rights = User::getAllRights();
176 - $assignedRights = $this->getAssignedRights( $group );
177 -
178 - sort( $rights );
179 -
180 - $checkboxes = array();
181 - $attribs = array();
182 -
183 - if ( !$editable )
184 - $attribs['disabled'] = 'disabled';
185 -
186 - foreach ( $rights as $right ) {
187 - # Build a checkbox.
188 - $checked = in_array( $right, $assignedRights );
189 -
190 - $desc = $wgOut->parseInline( User::getRightDescription( $right ) ) . ' ' .
191 - Xml::element( 'tt', null, wfMsg( 'parentheses', $right ) );
192 -
193 - $checkbox = Xml::check( "wpRightAssigned-$right", $checked, $attribs );
194 - $label = Xml::tags( 'label', array( 'for' => "wpRightAssigned-$right" ),
195 - $desc );
196 -
197 - $checkboxes[] = "<li>$checkbox&#160;$label</li>";
198 - }
199 -
200 - $count = count( $checkboxes );
201 -
202 - $firstCol = round( $count / 2 );
203 -
204 - $checkboxes1 = array_slice( $checkboxes, 0, $firstCol );
205 - $checkboxes2 = array_slice( $checkboxes, $firstCol );
206 -
207 - $html = '<table><tbody><tr><td><ul>';
208 -
209 - foreach ( $checkboxes1 as $cb ) {
210 - $html .= $cb;
211 - }
212 -
213 - $html .= '</ul></td><td><ul>';
214 -
215 - foreach ( $checkboxes2 as $cb ) {
216 - $html .= $cb;
217 - }
218 -
219 - $html .= '</ul></td></tr></tbody></table>';
220 -
221 - return $html;
222 - }
223 -
224 - function getAssignedRights( $group ) {
225 - return CentralAuthUser::globalGroupPermissions( $group );
226 - }
227 -
228 - function doSubmit( $group ) {
229 - global $wgRequest, $wgOut, $wgUser;
230 -
231 - // Paranoia -- the edit token shouldn't match anyway
232 - if ( !$this->userCanEdit( $wgUser ) )
233 - return;
234 -
235 - $newRights = array();
236 - $addRights = array();
237 - $removeRights = array();
238 - $oldRights = $this->getAssignedRights( $group );
239 - $allRights = User::getAllRights();
240 -
241 - $reason = $wgRequest->getVal( 'wpReason', '' );
242 -
243 - foreach ( $allRights as $right ) {
244 - $alreadyAssigned = in_array( $right, $oldRights );
245 -
246 - if ( $wgRequest->getCheck( "wpRightAssigned-$right" ) ) {
247 - $newRights[] = $right;
248 - }
249 -
250 - if ( !$alreadyAssigned && $wgRequest->getCheck( "wpRightAssigned-$right" ) ) {
251 - $addRights[] = $right;
252 - } else if ( $alreadyAssigned && !$wgRequest->getCheck( "wpRightAssigned-$right" ) ) {
253 - $removeRights[] = $right;
254 - } # Otherwise, do nothing.
255 - }
256 -
257 - // Assign the rights.
258 - if ( count( $addRights ) > 0 )
259 - $this->grantRightsToGroup( $group, $addRights );
260 - if ( count( $removeRights ) > 0 )
261 - $this->revokeRightsFromGroup( $group, $removeRights );
262 -
263 - // Log it
264 - if ( !( count( $addRights ) == 0 && count( $removeRights ) == 0 ) )
265 - $this->addLogEntry( $group, $addRights, $removeRights, $reason );
266 -
267 - // Change set
268 - $current = WikiSet::getWikiSetForGroup( $group );
269 - $new = $wgRequest->getVal( 'set' );
270 - if ( $current != $new ) {
271 - $this->setRestrictions( $group, $new );
272 - $this->addLogEntry2( $group, $current, $new, $reason );
273 - }
274 -
275 - $this->invalidateRightsCache( $group );
276 -
277 - // Display success
278 - $wgOut->setSubTitle( wfMsg( 'centralauth-editgroup-success' ) );
279 - $wgOut->addWikiMsg( 'centralauth-editgroup-success-text', $group );
280 - }
281 -
282 - function revokeRightsFromGroup( $group, $rights ) {
283 - $dbw = CentralAuthUser::getCentralDB();
284 -
285 - # Delete from the DB
286 - $dbw->delete( 'global_group_permissions', array( 'ggp_group' => $group, 'ggp_permission' => $rights ), __METHOD__ );
287 - }
288 -
289 - function grantRightsToGroup( $group, $rights ) {
290 - $dbw = CentralAuthUser::getCentralDB();
291 -
292 - if ( !is_array( $rights ) ) {
293 - $rights = array( $rights );
294 - }
295 -
296 - $insertRows = array();
297 - foreach ( $rights as $right ) {
298 - $insertRows[] = array( 'ggp_group' => $group, 'ggp_permission' => $right );
299 - }
300 -
301 - # Replace into the DB
302 - $dbw->replace( 'global_group_permissions', array( 'ggp_group', 'ggp_permission' ), $insertRows, __METHOD__ );
303 - }
304 -
305 - protected function showLogFragment( $group, $output ) {
306 - $title = SpecialPage::getTitleFor( 'GlobalUsers', $group );
307 - $output->addHTML( Xml::element( 'h2', null, LogPage::logName( 'gblrights' ) . "\n" ) );
308 - LogEventsList::showLogExtract( $output, 'gblrights', $title->getPrefixedText() );
309 - }
310 -
311 - function addLogEntry( $group, $addRights, $removeRights, $reason ) {
312 - $log = new LogPage( 'gblrights' );
313 -
314 - $log->addEntry( 'groupprms2',
315 - SpecialPage::getTitleFor( 'GlobalUsers', $group ),
316 - $reason,
317 - array(
318 - $this->makeRightsList( $addRights ),
319 - $this->makeRightsList( $removeRights )
320 - )
321 - );
322 - }
323 -
324 - function makeRightsList( $ids ) {
325 - return (bool)count( $ids ) ? implode( ', ', $ids ) : wfMsgForContent( 'rightsnone' );
326 - }
327 -
328 - function setRestrictions( $group, $set ) {
329 - $dbw = CentralAuthUser::getCentralDB();
330 - if ( $set == 0 ) {
331 - $dbw->delete( 'global_group_restrictions', array( 'ggr_group' => $group ), __METHOD__ );
332 - } else {
333 - $dbw->replace( 'global_group_restrictions', array( 'ggr_group' ),
334 - array( 'ggr_group' => $group, 'ggr_set' => $set, ), __METHOD__ );
335 - }
336 - return (bool)$dbw->affectedRows();
337 - }
338 -
339 - function addLogEntry2( $group, $old, $new, $reason ) {
340 - $log = new LogPage( 'gblrights' );
341 -
342 - $log->addEntry( 'groupprms3',
343 - SpecialPage::getTitleFor( 'GlobalUsers', $group ),
344 - $reason,
345 - array(
346 - $this->getWikiSetName( $old ),
347 - $this->getWikiSetName( $new ),
348 - )
349 - );
350 - }
351 -
352 - function getWikiSetName( $id ) {
353 - if ( $id )
354 - return WikiSet::newFromID( $id )->getName();
355 - else
356 - return wfMsgForContent( 'centralauth-editgroup-noset' );
357 - }
358 -
359 - function invalidateRightsCache( $group ) {
360 - // Figure out all the users in this group.
361 - $dbr = CentralAuthUser::getCentralDB();
362 -
363 - $res = $dbr->select( array( 'global_user_groups', 'globaluser' ), 'gu_name', array( 'gug_group' => $group, 'gu_id=gug_user' ), __METHOD__ );
364 -
365 - // Invalidate their rights cache.
366 - foreach ( $res as $row ) {
367 - $cu = new CentralAuthUser( $row->gu_name );
368 - $cu->quickInvalidateCache();
369 - }
370 - }
371 -}
Index: trunk/extensions/CentralAuth/SpecialCentralAuth.php
@@ -1,633 +0,0 @@
2 -<?php
3 -class SpecialCentralAuth extends SpecialPage {
4 - var $mUserName, $mCanUnmerge, $mCanLock, $mCanOversight, $mCanEdit;
5 - var $mGlobalUser, $mAttachedLocalAccounts, $mUnattachedLocalAccounts;
6 -
7 - function __construct() {
8 - parent::__construct( 'CentralAuth' );
9 - }
10 -
11 - function execute( $subpage ) {
12 - global $wgOut;
13 - global $wgExtensionAssetsPath, $wgCentralAuthStyleVersion;
14 - global $wgUser, $wgRequest, $wgContLang;
15 - $this->setHeaders();
16 -
17 - $this->mCanUnmerge = $wgUser->isAllowed( 'centralauth-unmerge' );
18 - $this->mCanLock = $wgUser->isAllowed( 'centralauth-lock' );
19 - $this->mCanOversight = $wgUser->isAllowed( 'centralauth-oversight' );
20 - $this->mCanEdit = $this->mCanUnmerge || $this->mCanLock || $this->mCanOversight;
21 -
22 - $wgOut->addExtensionStyle( "{$wgExtensionAssetsPath}/CentralAuth/centralauth.css?" .
23 - $wgCentralAuthStyleVersion );
24 - $wgOut->addScriptFile( "{$wgExtensionAssetsPath}/CentralAuth/centralauth.js?" .
25 - $wgCentralAuthStyleVersion );
26 - $this->addMergeMethodDescriptions();
27 -
28 - $this->mUserName =
29 - trim(
30 - str_replace( '_', ' ',
31 - $wgRequest->getText( 'target', $subpage ) ) );
32 -
33 - $this->mUserName = $wgContLang->ucfirst( $this->mUserName );
34 -
35 - $this->mPosted = $wgRequest->wasPosted();
36 - $this->mMethod = $wgRequest->getVal( 'wpMethod' );
37 - $this->mWikis = (array)$wgRequest->getArray( 'wpWikis' );
38 -
39 - // Possible demo states
40 -
41 - // success, all accounts merged
42 - // successful login, some accounts merged, others left
43 - // successful login, others left
44 - // not account owner, others left
45 -
46 - // is owner / is not owner
47 - // did / did not merge some accounts
48 - // do / don't have more accounts to merge
49 -
50 - if ( $this->mUserName === '' ) {
51 - # First time through
52 - $wgOut->addWikiMsg( 'centralauth-admin-intro' );
53 - $this->showUsernameForm();
54 - return;
55 - }
56 -
57 - $this->mGlobalUser = $globalUser = new CentralAuthUser( $this->mUserName );
58 -
59 - if ( !$globalUser->exists() ||
60 - ( $globalUser->isOversighted() && !$this->mCanOversight ) ) {
61 - $this->showError( 'centralauth-admin-nonexistent', $this->mUserName );
62 - $this->showUsernameForm();
63 - return;
64 - }
65 -
66 - $continue = true;
67 - if ( $this->mCanEdit && $this->mPosted ) {
68 - $continue = $this->doSubmit();
69 - }
70 -
71 - $this->mAttachedLocalAccounts = $this->mGlobalUser->queryAttached();
72 - $this->mUnattachedLocalAccounts = $this->mGlobalUser->queryUnattached();
73 -
74 - $this->showUsernameForm();
75 - if ( $continue ) {
76 - $this->showInfo();
77 - if ( $this->mCanLock )
78 - $this->showStatusForm();
79 - if ( $this->mCanUnmerge )
80 - $this->showActionForm( 'delete' );
81 - if ( $this->mCanEdit )
82 - $this->showLogExtract();
83 - $this->showWikiLists();
84 - }
85 - }
86 -
87 - /** Returns true if the normal form should be displayed */
88 - function doSubmit() {
89 - $deleted = false;
90 - $globalUser = $this->mGlobalUser;
91 - global $wgUser, $wgRequest;
92 - if ( !$wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ) ) {
93 - $this->showError( 'centralauth-token-mismatch' );
94 - } elseif ( $this->mMethod == 'unmerge' && $this->mCanUnmerge ) {
95 - $status = $globalUser->adminUnattach( $this->mWikis );
96 - if ( !$status->isGood() ) {
97 - $this->showStatusError( $status->getWikiText() );
98 - } else {
99 - global $wgLang;
100 - $this->showSuccess( 'centralauth-admin-unmerge-success',
101 - $wgLang->formatNum( $status->successCount ),
102 - /* deprecated */ $status->successCount );
103 - }
104 - } elseif ( $this->mMethod == 'delete' && $this->mCanUnmerge ) {
105 - $status = $globalUser->adminDelete();
106 - if ( !$status->isGood() ) {
107 - $this->showStatusError( $status->getWikiText() );
108 - } else {
109 - $this->showSuccess( 'centralauth-admin-delete-success', $this->mUserName );
110 - $deleted = true;
111 - $this->logAction( 'delete', $this->mUserName, $wgRequest->getVal( 'reason' ) );
112 - }
113 - } elseif ( $this->mMethod == 'set-status' && $this->mCanLock ) {
114 - $setLocked = $wgRequest->getBool( 'wpStatusLocked' );
115 - $setHidden = $wgRequest->getVal( 'wpStatusHidden' );
116 - $isLocked = $globalUser->isLocked();
117 - $oldHiddenLevel = $globalUser->getHiddenLevel();
118 - $lockStatus = $hideStatus = null;
119 - $added = array();
120 - $removed = array();
121 -
122 - // Sanitizing input value...
123 - $hiddenLevels = array(
124 - CentralAuthUser::HIDDEN_NONE,
125 - CentralAuthUser::HIDDEN_LISTS,
126 - CentralAuthUser::HIDDEN_OVERSIGHT );
127 - if ( !in_array( $setHidden, $hiddenLevels ) )
128 - $setHidden = '';
129 -
130 - if ( !$isLocked && $setLocked ) {
131 - $lockStatus = $globalUser->adminLock();
132 - $added[] = wfMsgForContent( 'centralauth-log-status-locked' );
133 - } elseif ( $isLocked && !$setLocked ) {
134 - $lockStatus = $globalUser->adminUnlock();
135 - $removed[] = wfMsgForContent( 'centralauth-log-status-locked' );
136 - }
137 -
138 - $reason = $wgRequest->getText( 'wpReasonList' );
139 - $reasonDetail = $wgRequest->getText( 'wpReason' );
140 - if ( $reason == 'other' ) {
141 - $reason = $reasonDetail;
142 - } elseif ( $reasonDetail ) {
143 - $reason .= wfMsgForContent( 'colon-separator' ) . $reasonDetail;
144 - }
145 -
146 - if ( $oldHiddenLevel != $setHidden ) {
147 - $hideStatus = $globalUser->adminSetHidden( $setHidden );
148 - switch( $setHidden ) {
149 - case CentralAuthUser::HIDDEN_NONE:
150 - $removed[] = $oldHiddenLevel == CentralAuthUser::HIDDEN_OVERSIGHT ?
151 - wfMsgForContent( 'centralauth-log-status-oversighted' ) :
152 - wfMsgForContent( 'centralauth-log-status-hidden' );
153 - break;
154 - case CentralAuthUser::HIDDEN_LISTS:
155 - $added[] = wfMsgForContent( 'centralauth-log-status-hidden' );
156 - if ( $oldHiddenLevel == CentralAuthUser::HIDDEN_OVERSIGHT )
157 - $removed[] = wfMsgForContent( 'centralauth-log-status-oversighted' );
158 - break;
159 - case CentralAuthUser::HIDDEN_OVERSIGHT:
160 - $added[] = wfMsgForContent( 'centralauth-log-status-oversighted' );
161 - if ( $oldHiddenLevel == CentralAuthUser::HIDDEN_LISTS )
162 - $removed[] = wfMsgForContent( 'centralauth-log-status-hidden' );
163 - break;
164 - }
165 -
166 - if ( $setHidden == CentralAuthUser::HIDDEN_OVERSIGHT )
167 - $globalUser->suppress( $reason );
168 - elseif ( $oldHiddenLevel == CentralAuthUser::HIDDEN_OVERSIGHT )
169 - $globalUser->unsuppress( $reason );
170 - }
171 -
172 - $good =
173 - ( is_null( $lockStatus ) || $lockStatus->isGood() ) &&
174 - ( is_null( $hideStatus ) || $hideStatus->isGood() );
175 -
176 - // Logging etc
177 - if ( $good && ( count( $added ) || count( $removed ) ) ) {
178 - $added = count( $added ) ?
179 - implode( ', ', $added ) : wfMsgForContent( 'centralauth-log-status-none' );
180 - $removed = count( $removed ) ?
181 - implode( ', ', $removed ) : wfMsgForContent( 'centralauth-log-status-none' );
182 -
183 - $this->logAction(
184 - 'setstatus',
185 - $this->mUserName,
186 - $reason,
187 - array( $added, $removed ),
188 - $setHidden == CentralAuthUser::HIDDEN_OVERSIGHT
189 - );
190 - $this->showSuccess( 'centralauth-admin-setstatus-success', $this->mUserName );
191 - } elseif ( !$good ) {
192 - if ( !is_null( $lockStatus ) && !$lockStatus->isGood() ) {
193 - $this->showStatusError( $lockStatus->getWikiText() );
194 - }
195 - if ( !is_null( $hideStatus ) && !$hideStatus->isGood() ) {
196 - $this->showStatusError( $hideStatus->getWikiText() );
197 - }
198 - }
199 - } else {
200 - $this->showError( 'centralauth-admin-bad-input' );
201 - }
202 - return !$deleted;
203 - }
204 -
205 - function showStatusError( $wikitext ) {
206 - global $wgOut;
207 - $wrap = Xml::tags( 'div', array( 'class' => 'error' ), $wikitext );
208 - $wgOut->addHTML( $wgOut->parse( $wrap, /*linestart*/true, /*uilang*/true ) );
209 - }
210 -
211 - function showError( /* varargs */ ) {
212 - global $wgOut;
213 - $args = func_get_args();
214 - $wgOut->wrapWikiMsg( '<div class="error">$1</div>', $args );
215 - }
216 -
217 -
218 - function showSuccess( /* varargs */ ) {
219 - global $wgOut;
220 - $args = func_get_args();
221 - $wgOut->wrapWikiMsg( '<div class="success">$1</div>', $args );
222 - }
223 -
224 - function showUsernameForm() {
225 - global $wgOut, $wgScript;
226 - $lookup = $this->mCanEdit ?
227 - wfMsg( 'centralauth-admin-lookup-rw' ) :
228 - wfMsg( 'centralauth-admin-lookup-ro' );
229 - $wgOut->addHTML(
230 - Xml::openElement( 'form', array(
231 - 'method' => 'get',
232 - 'action' => $wgScript ) ) .
233 - '<fieldset>' .
234 - Xml::element( 'legend', array(), wfMsg( 'centralauth-admin-manage' ) ) .
235 - Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) .
236 - '<p>' .
237 - Xml::inputLabel( wfMsg( 'centralauth-admin-username' ),
238 - 'target', 'target', 25, $this->mUserName ) .
239 - '</p>' .
240 - '<p>' .
241 - Xml::submitButton( $lookup ) .
242 - '</p>' .
243 - '</fieldset>' .
244 - '</form>'
245 - );
246 - }
247 -
248 - function prettyTimespan( $span ) {
249 - global $wgLang;
250 - $units = array(
251 - 'seconds' => 60,
252 - 'minutes' => 60,
253 - 'hours' => 24,
254 - 'days' => 30.417,
255 - 'months' => 12,
256 - 'years' => 1 );
257 - foreach ( $units as $unit => $chunk ) {
258 - // Used messaged (to make sure that grep finds them):
259 - // 'centralauth-seconds-ago', 'centralauth-minutes-ago', 'centralauth-hours-ago'
260 - // 'centralauth-days-ago', 'centralauth-months-ago', 'centralauth-years-ago'
261 - if ( $span < 2 * $chunk ) {
262 - return wfMsgExt( "centralauth-$unit-ago", 'parsemag', $wgLang->formatNum( $span ) );
263 - }
264 - $span = intval( $span / $chunk );
265 - }
266 - return wfMsgExt( "centralauth-$unit-ago", 'parsemag', $wgLang->formatNum( $span ) );
267 - }
268 -
269 - function showInfo() {
270 - $globalUser = $this->mGlobalUser;
271 -
272 - global $wgOut, $wgLang;
273 - $reg = $globalUser->getRegistration();
274 - $age = $this->prettyTimespan( wfTimestamp( TS_UNIX ) - wfTimestamp( TS_UNIX, $reg ) );
275 - $attribs = array(
276 - 'id' => $globalUser->getId(),
277 - 'registered' => $wgLang->timeanddate( $reg ) . " ($age)",
278 - 'home' => $this->determineHomeWiki(),
279 - 'editcount' => $wgLang->formatNum( $this->evaluateTotalEditcount() ),
280 - 'locked' => $globalUser->isLocked() ? wfMsg( 'centralauth-admin-yes' ) : wfMsg( 'centralauth-admin-no' ),
281 - 'hidden' => $this->formatHiddenLevel( $globalUser->getHiddenLevel() ) );
282 - $out = '<fieldset id="mw-centralauth-info">';
283 - $out .= '<legend>' . wfMsgHtml( 'centralauth-admin-info-header' ) . '</legend>';
284 - foreach ( $attribs as $tag => $data ) {
285 - $out .= '<p><strong>' . wfMsgHtml( "centralauth-admin-info-$tag" ) . '</strong> ' .
286 - htmlspecialchars( $data ) . '</p>';
287 - }
288 - $out .= '</fieldset>';
289 - $wgOut->addHTML( $out );
290 - }
291 -
292 - function showWikiLists() {
293 - global $wgOut;
294 - $merged = $this->mAttachedLocalAccounts;
295 - $remainder = $this->mUnattachedLocalAccounts;
296 -
297 - $legend = $this->mCanUnmerge ?
298 - wfMsgHtml( 'centralauth-admin-list-legend-rw' ) :
299 - wfMsgHtml( 'centralauth-admin-list-legend-ro' );
300 -
301 - $wgOut->addHTML( "<fieldset><legend>{$legend}</legend>" );
302 - $wgOut->addHTML( $this->listHeader() );
303 - $wgOut->addHTML( $this->listMerged( $merged ) );
304 - if ( $remainder )
305 - $wgOut->addHTML( $this->listRemainder( $remainder ) );
306 - $wgOut->addHTML( $this->listFooter() );
307 - $wgOut->addHTML( '</fieldset>' );
308 - }
309 -
310 - function listHeader() {
311 - global $wgUser;
312 - return
313 - Xml::openElement( 'form',
314 - array(
315 - 'method' => 'post',
316 - 'action' =>
317 - $this->getTitle( $this->mUserName )->getLocalUrl( 'action=submit' ),
318 - 'id' => 'mw-centralauth-merged' ) ) .
319 - Html::hidden( 'wpMethod', 'unmerge' ) .
320 - Html::hidden( 'wpEditToken', $wgUser->editToken() ) .
321 - Xml::openElement( 'table', array( 'class' => 'wikitable sortable mw-centralauth-wikislist' ) ) . "\n" .
322 - '<thead><tr>' .
323 - ( $this->mCanUnmerge ? '<th></th>' : '' ) .
324 - '<th>' . wfMsgHtml( 'centralauth-admin-list-localwiki' ) . '</th>' .
325 - '<th>' . wfMsgHtml( 'centralauth-admin-list-attached-on' ) . '</th>' .
326 - '<th>' . wfMsgHtml( 'centralauth-admin-list-method' ) . '</th>' .
327 - '<th>' . wfMsgHtml( 'centralauth-admin-list-blocked' ) . '</th>' .
328 - '<th>' . wfMsgHtml( 'centralauth-admin-list-editcount' ) . '</th>' .
329 - '</tr></thead>' .
330 - '<tbody>';
331 - }
332 -
333 - function listFooter() {
334 - $footer = '';
335 - if ( $this->mCanUnmerge )
336 - $footer .=
337 - '<tr>' .
338 - '<td style="border-right: none"></td>' .
339 - '<td style="border-left: none" colspan="5">' .
340 - Xml::submitButton( wfMsg( 'centralauth-admin-unmerge' ) ) .
341 - '</td>' .
342 - '</tr>';
343 - $footer .= '</tbody></table></form>';
344 - return $footer;
345 - }
346 -
347 - function listMerged( $list ) {
348 - ksort( $list );
349 - return implode( "\n", array_map( array( $this, 'listMergedWikiItem' ), $list ) );
350 - }
351 -
352 - function listRemainder( $list ) {
353 - ksort( $list );
354 - $notMerged = wfMsgExt( 'centralauth-admin-unattached', array( 'parseinline' ) );
355 - $rows = array();
356 - foreach ( $list as $row ) {
357 - $rows[] = '<tr class="unattached-row"><td>' .
358 - ( $this->mCanUnmerge ? '</td><td>' : '' ) .
359 - $this->foreignUserLink( $row['wiki'] ) .
360 - "</td><td colspan='4'>{$notMerged}</td></tr>\n";
361 - }
362 - return implode( $rows );
363 - }
364 -
365 - function listMergedWikiItem( $row ) {
366 - global $wgLang;
367 - return '<tr>' .
368 - ( $this->mCanUnmerge ? '<td>' . $this->adminCheck( $row['wiki'] ) . '</td>' : '' ) .
369 - '<td>' . $this->foreignUserLink( $row['wiki'] ) . '</td>' .
370 - '<td>' .
371 - // invisible, to make this column sortable
372 - Html::element( 'span', array( 'style' => 'display: none' ), htmlspecialchars( $row['attachedTimestamp'] ) ) .
373 - // visible date and time in users preference
374 - htmlspecialchars( $wgLang->timeanddate( $row['attachedTimestamp'] ) ) .
375 - '</td>' .
376 - '<td style="text-align: center">' . $this->formatMergeMethod( $row['attachedMethod'] ) . '</td>' .
377 - '<td>' . $this->formatBlockStatus( $row ) . '</td>' .
378 - '<td style="text-align: right">' . $this->formatEditcount( $row ) . '</td>' .
379 - '</tr>';
380 - }
381 -
382 - function formatMergeMethod( $method ) {
383 - global $wgExtensionAssetsPath;
384 -
385 - $img = htmlspecialchars( "{$wgExtensionAssetsPath}/CentralAuth/icons/merged-{$method}.png" );
386 - $brief = wfMsgHtml( "centralauth-merge-method-{$method}" );
387 - return "<img src=\"{$img}\" alt=\"{$brief}\" title=\"{$brief}\"/>" .
388 - "<span class=\"merge-method-help\" title=\"{$brief}\" onclick=\"showMethodHint('{$method}')\">(?)</span>";
389 - }
390 -
391 - function formatBlockStatus( $row ) {
392 - if ( $row['blocked'] ) {
393 - if ( $row['block-expiry'] == 'infinity' ) {
394 - $reason = $row['block-reason'];
395 - return wfMsgExt( 'centralauth-admin-blocked-indef', 'parseinline', array( $reason ) );
396 - } else {
397 - global $wgLang;
398 - $expiry = $wgLang->timeanddate( $row['block-expiry'] );
399 - $expiryd = $wgLang->date( $row['block-expiry'] );
400 - $expiryt = $wgLang->time( $row['block-expiry'] );
401 - $reason = $row['block-reason'];
402 -
403 - $text = wfMsgExt( 'centralauth-admin-blocked', 'parseinline', array( $expiry, $reason, $expiryd, $expiryt ) );
404 - }
405 - } else {
406 - $text = wfMsgExt( 'centralauth-admin-notblocked', 'parseinline' );
407 - }
408 -
409 - return $this->foreignLink(
410 - $row['wiki'],
411 - 'Special:Log/block',
412 - $text,
413 - wfMsg( 'centralauth-admin-blocklog' ),
414 - 'page=User:' . urlencode( $this->mUserName ) );
415 - }
416 -
417 - function formatEditcount( $row ) {
418 - global $wgLang;
419 - return $this->foreignLink(
420 - $row['wiki'],
421 - 'Special:Contributions/' . $this->mUserName,
422 - $wgLang->formatNum( intval( $row['editCount'] ) ),
423 - 'contributions' );
424 - }
425 -
426 - function formatHiddenLevel( $level ) {
427 - switch( $level ) {
428 - case CentralAuthUser::HIDDEN_NONE:
429 - return wfMsg( 'centralauth-admin-no' );
430 - case CentralAuthUser::HIDDEN_LISTS:
431 - return wfMsg( 'centralauth-admin-hidden-list' );
432 - case CentralAuthUser::HIDDEN_OVERSIGHT:
433 - return wfMsg( 'centralauth-admin-hidden-oversight' );
434 - }
435 - }
436 -
437 - function tableRow( $element, $cols ) {
438 - return "<tr><$element>" .
439 - implode( "</$element><$element>", $cols ) .
440 - "</$element></tr>";
441 - }
442 -
443 - function foreignLink( $wikiID, $title, $text, $hint = '', $params = '' ) {
444 - if ( $wikiID instanceof WikiReference ) {
445 - $wiki = $wikiID;
446 - } else {
447 - $wiki = WikiMap::getWiki( $wikiID );
448 - if ( !$wiki ) {
449 - throw new MWException( "Invalid wiki: $wikiID" );
450 - }
451 - }
452 -
453 - $url = $wiki->getUrl( $title );
454 - if ( $params )
455 - $url .= '?' . $params;
456 - return Xml::element( 'a',
457 - array(
458 - 'href' => $url,
459 - 'title' => $hint,
460 - ),
461 - $text );
462 - }
463 -
464 - function foreignUserLink( $wikiID ) {
465 - $wiki = WikiMap::getWiki( $wikiID );
466 - if ( !$wiki ) {
467 - throw new MWException( "Invalid wiki: $wikiID" );
468 - }
469 -
470 - $wikiname = $wiki->getDisplayName();
471 - return $this->foreignLink(
472 - $wiki,
473 - 'User:' . $this->mUserName,
474 - $wikiname,
475 - wfMsg( 'centralauth-foreign-link', $this->mUserName, $wikiname ) );
476 -
477 - }
478 -
479 - function adminCheck( $wikiID ) {
480 - return
481 - Xml::check( 'wpWikis[]', false, array( 'value' => $wikiID ) );
482 - }
483 -
484 - function showActionForm( $action ) {
485 - global $wgOut, $wgUser;
486 - $wgOut->addHTML(
487 - Xml::fieldset( wfMsg( "centralauth-admin-{$action}-title" ) ) .
488 - Xml::openElement( 'form', array(
489 - 'method' => 'POST',
490 - 'action' => $this->getTitle()->getFullUrl( 'target=' . urlencode( $this->mUserName ) ),
491 - 'id' => "mw-centralauth-$action" ) ) .
492 - Html::hidden( 'wpMethod', $action ) .
493 - Html::hidden( 'wpEditToken', $wgUser->editToken() ) .
494 - wfMsgExt( "centralauth-admin-{$action}-description", 'parse' ) .
495 - Xml::buildForm(
496 - array( 'centralauth-admin-reason' => Xml::input( 'reason',
497 - false, false, array( 'id' => "{$action}-reason" ) ) ),
498 - "centralauth-admin-{$action}-button"
499 - ) .
500 - '</form></fieldset>' );
501 - }
502 -
503 - function showStatusForm() {
504 - // Allows locking, hiding, locking and hiding.
505 - global $wgUser, $wgOut;
506 - $form = '';
507 - $form .= Xml::fieldset( wfMsg( 'centralauth-admin-status' ) );
508 - $form .= Html::hidden( 'wpMethod', 'set-status' );
509 - $form .= Html::hidden( 'wpEditToken', $wgUser->editToken() );
510 - $form .= wfMsgExt( 'centralauth-admin-status-intro', 'parse' );
511 -
512 - // Radio buttons
513 - $radioLocked =
514 - Xml::radioLabel(
515 - wfMsgExt( 'centralauth-admin-status-locked-no', array( 'parseinline' ) ),
516 - 'wpStatusLocked',
517 - '0',
518 - 'mw-centralauth-status-locked-no',
519 - !$this->mGlobalUser->isLocked() ) .
520 - '<br />' .
521 - Xml::radioLabel(
522 - wfMsgExt( 'centralauth-admin-status-locked-yes', array( 'parseinline' ) ),
523 - 'wpStatusLocked',
524 - '1',
525 - 'mw-centralauth-status-locked-yes',
526 - $this->mGlobalUser->isLocked() );
527 - $radioHidden =
528 - Xml::radioLabel(
529 - wfMsgExt( 'centralauth-admin-status-hidden-no', array( 'parseinline' ) ),
530 - 'wpStatusHidden',
531 - CentralAuthUser::HIDDEN_NONE,
532 - 'mw-centralauth-status-hidden-no',
533 - $this->mGlobalUser->getHiddenLevel() == CentralAuthUser::HIDDEN_NONE ) .
534 - '<br />' .
535 - Xml::radioLabel(
536 - wfMsgExt( 'centralauth-admin-status-hidden-list', array( 'parseinline' ) ),
537 - 'wpStatusHidden',
538 - CentralAuthUser::HIDDEN_LISTS,
539 - 'mw-centralauth-status-hidden-list',
540 - $this->mGlobalUser->getHiddenLevel() == CentralAuthUser::HIDDEN_LISTS ) .
541 - '<br />';
542 - if ( $this->mCanOversight ) {
543 - $radioHidden .= Xml::radioLabel(
544 - wfMsgExt( 'centralauth-admin-status-hidden-oversight', array( 'parseinline' ) ),
545 - 'wpStatusHidden',
546 - CentralAuthUser::HIDDEN_OVERSIGHT,
547 - 'mw-centralauth-status-hidden-oversight',
548 - $this->mGlobalUser->getHiddenLevel() == CentralAuthUser::HIDDEN_OVERSIGHT
549 - );
550 - }
551 -
552 - // Reason
553 - $reasonList = Xml::listDropDown(
554 - 'wpReasonList',
555 - wfMsgForContent( 'centralauth-admin-status-reasons' ),
556 - wfMsgForContent( 'ipbreasonotherlist' )
557 - );
558 - $reasonField = Xml::input( 'wpReason', 45, false );
559 -
560 - $form .= Xml::buildForm(
561 - array(
562 - 'centralauth-admin-status-locked' => $radioLocked,
563 - 'centralauth-admin-status-hidden' => $radioHidden,
564 - 'centralauth-admin-reason' => $reasonList,
565 - 'centralauth-admin-reason-other' => $reasonField ),
566 - 'centralauth-admin-status-submit'
567 - );
568 -
569 - $form .= '</fieldset>';
570 - $form = Xml::tags(
571 - 'form',
572 - array(
573 - 'method' => 'POST',
574 - 'action' => $this->getTitle()->getFullURL(
575 - array( 'target' => $this->mUserName )
576 - ),
577 - ),
578 - $form
579 - );
580 - $wgOut->addHTML( $form );
581 - }
582 -
583 - function showLogExtract() {
584 - global $wgOut;
585 - $user = $this->mGlobalUser->getName();
586 - $text = '';
587 - $numRows = LogEventsList::showLogExtract(
588 - $text,
589 - array( 'globalauth', 'suppress' ),
590 - Title::newFromText( "User:{$user}@global" )->getPrefixedText(),
591 - '',
592 - array( 'showIfEmpty' => true ) );
593 - if ( $numRows ) {
594 - $wgOut->addHTML( Xml::fieldset( wfMsg( 'centralauth-admin-logsnippet' ), $text ) );
595 - }
596 - }
597 -
598 - function determineHomeWiki() {
599 - foreach ( $this->mAttachedLocalAccounts as $wiki => $acc ) {
600 - if ( $acc['attachedMethod'] == 'primary' || $acc['attachedMethod'] == 'new' ) {
601 - return $wiki;
602 - }
603 - }
604 -
605 - // Home account can be renamed or unmerged
606 - return wfMsgHtml( 'centralauth-admin-nohome' );
607 - }
608 -
609 - function evaluateTotalEditcount() {
610 - $total = 0;
611 - foreach ( $this->mAttachedLocalAccounts as $acc ) {
612 - $total += $acc['editCount'];
613 - }
614 - return $total;
615 - }
616 -
617 - function addMergeMethodDescriptions() {
618 - global $wgOut, $wgLang;
619 - $js = "wgMergeMethodDescriptions = {\n";
620 - foreach ( array( 'primary', 'new', 'empty', 'password', 'mail', 'admin', 'login' ) as $method ) {
621 - $short = Xml::encodeJsVar( $wgLang->ucfirst( wfMsgHtml( "centralauth-merge-method-{$method}" ) ) );
622 - $desc = Xml::encodeJsVar( wfMsgWikiHtml( "centralauth-merge-method-{$method}-desc" ) );
623 - $js .= "\t'{$method}' : { 'short' : {$short}, 'desc' : {$desc} },\n";
624 - }
625 - $js .= "}";
626 - $wgOut->addInlineScript( $js );
627 - }
628 -
629 - function logAction( $action, $target, $reason = '', $params = array(), $suppressLog = false ) {
630 - $logType = $suppressLog ? 'suppress' : 'globalauth'; // Not centralauth because of some weird length limitiations
631 - $log = new LogPage( $logType );
632 - $log->addEntry( $action, Title::newFromText( "User:{$target}@global" ), $reason, $params );
633 - }
634 -}
Index: trunk/extensions/CentralAuth/SpecialMergeAccount.php
@@ -1,518 +0,0 @@
2 -<?php
3 -
4 -class SpecialMergeAccount extends SpecialPage {
5 - function __construct() {
6 - parent::__construct( 'MergeAccount', 'centralauth-merge' );
7 - }
8 -
9 - function execute( $subpage ) {
10 - global $wgOut, $wgUser;
11 - $this->setHeaders();
12 -
13 - if ( !$this->userCanExecute( $wgUser ) ) {
14 - $wgOut->addWikiMsg( 'centralauth-merge-denied' );
15 - $wgOut->addWikiMsg( 'centralauth-readmore-text' );
16 - return;
17 - }
18 -
19 - if ( !$wgUser->isLoggedIn() ) {
20 - $wgOut->addWikiMsg( 'centralauth-merge-notlogged' );
21 - $wgOut->addWikiMsg( 'centralauth-readmore-text' );
22 -
23 - return;
24 - }
25 -
26 - if ( wfReadOnly() ) {
27 - $wgOut->setPagetitle( wfMsg( 'readonly' ) );
28 - $wgOut->addWikiMsg( 'readonlytext', wfReadOnlyReason() );
29 - return;
30 - }
31 -
32 - global $wgUser, $wgRequest;
33 - $this->mUserName = $wgUser->getName();
34 -
35 - $this->mAttemptMerge = $wgRequest->wasPosted();
36 -
37 - $this->mMergeAction = $wgRequest->getVal( 'wpMergeAction' );
38 - $this->mPassword = $wgRequest->getVal( 'wpPassword' );
39 - $this->mWikiIDs = $wgRequest->getArray( 'wpWikis' );
40 - $this->mSessionToken = $wgRequest->getVal( 'wpMergeSessionToken' );
41 - $this->mSessionKey = pack( "H*", $wgRequest->getVal( 'wpMergeSessionKey' ) );
42 -
43 - // Possible demo states
44 -
45 - // success, all accounts merged
46 - // successful login, some accounts merged, others left
47 - // successful login, others left
48 - // not account owner, others left
49 -
50 - // is owner / is not owner
51 - // did / did not merge some accounts
52 - // do / don't have more accounts to merge
53 -
54 - if ( $this->mAttemptMerge ) {
55 - switch( $this->mMergeAction ) {
56 - case "dryrun":
57 - return $this->doDryRunMerge();
58 - case "initial":
59 - return $this->doInitialMerge();
60 - case "cleanup":
61 - return $this->doCleanupMerge();
62 - case "attach":
63 - return $this->doAttachMerge();
64 - case "remove":
65 - return $this->doUnattach();
66 - default:
67 - return $this->invalidAction();
68 - }
69 - }
70 -
71 - $globalUser = new CentralAuthUser( $this->mUserName );
72 - if ( $globalUser->exists() ) {
73 - if ( $globalUser->isAttached() ) {
74 - $this->showCleanupForm();
75 - } else {
76 - $this->showAttachForm();
77 - }
78 - } else {
79 - $this->showWelcomeForm();
80 - }
81 - }
82 -
83 - /**
84 - * To pass potentially multiple passwords from one form submission
85 - * to another while previewing the merge behavior, we can store them
86 - * in the server-side session information.
87 - *
88 - * We'd rather not have plaintext passwords floating about on disk
89 - * or memcached, so the session store is obfuscated with simple XOR
90 - * encryption. The key is passed in the form instead of the session
91 - * data, so they won't be found floating in the same place.
92 - */
93 - private function initSession() {
94 - global $wgUser;
95 - $this->mSessionToken = $wgUser->generateToken();
96 -
97 - // Generate a random binary string
98 - $key = '';
99 - for ( $i = 0; $i < 128; $i++ ) {
100 - $key .= chr( mt_rand( 0, 255 ) );
101 - }
102 - $this->mSessionKey = $key;
103 - }
104 -
105 - private function getWorkingPasswords() {
106 - wfSuppressWarnings();
107 - $passwords = unserialize(
108 - gzinflate(
109 - $this->xorString(
110 - $_SESSION['wsCentralAuthMigration'][$this->mSessionToken],
111 - $this->mSessionKey ) ) );
112 - wfRestoreWarnings();
113 - if ( is_array( $passwords ) ) {
114 - return $passwords;
115 - }
116 - return array();
117 - }
118 -
119 - private function addWorkingPassword( $password ) {
120 - $passwords = $this->getWorkingPasswords();
121 - if ( !in_array( $password, $passwords ) ) {
122 - $passwords[] = $password;
123 - }
124 -
125 - // Lightly obfuscate the passwords while we're storing them,
126 - // just to make us feel better about them floating around.
127 - $_SESSION['wsCentralAuthMigration'][$this->mSessionToken] =
128 - $this->xorString(
129 - gzdeflate(
130 - serialize(
131 - $passwords ) ),
132 - $this->mSessionKey );
133 - }
134 -
135 - private function clearWorkingPasswords() {
136 - unset( $_SESSION['wsCentralAuthMigration'][$this->mSessionToken] );
137 - }
138 -
139 - function xorString( $text, $key ) {
140 - if ( $key != '' ) {
141 - for ( $i = 0; $i < strlen( $text ); $i++ ) {
142 - $text[$i] = chr( 0xff & ( ord( $text[$i] ) ^ ord( $key[$i % strlen( $key )] ) ) );
143 - }
144 - }
145 - return $text;
146 - }
147 -
148 - function doDryRunMerge() {
149 - global $wgUser, $wgRequest, $wgOut, $wgCentralAuthDryRun;
150 - $globalUser = new CentralAuthUser( $wgUser->getName() );
151 -
152 - if ( $globalUser->exists() ) {
153 - throw new MWException( "Already exists -- race condition" );
154 - }
155 -
156 - if ( $wgCentralAuthDryRun ) {
157 - $wgOut->addWikiMsg( 'centralauth-notice-dryrun' );
158 - }
159 -
160 - $password = $wgRequest->getVal( 'wpPassword' );
161 - $this->addWorkingPassword( $password );
162 - $passwords = $this->getWorkingPasswords();
163 -
164 - $home = false;
165 - $attached = array();
166 - $unattached = array();
167 - $methods = array();
168 - $status = $globalUser->migrationDryRun( $passwords, $home, $attached, $unattached, $methods );
169 -
170 - if ( $status->isGood() ) {
171 - // This is the global account or matched it
172 - if ( count( $unattached ) == 0 ) {
173 - // Everything matched -- very convenient!
174 - $wgOut->addWikiMsg( 'centralauth-merge-dryrun-complete' );
175 - } else {
176 - $wgOut->addWikiMsg( 'centralauth-merge-dryrun-incomplete' );
177 - }
178 -
179 - if ( count( $unattached ) > 0 ) {
180 - $wgOut->addHTML( $this->step2PasswordForm( $unattached ) );
181 - $wgOut->addWikiMsg( 'centralauth-merge-dryrun-or' );
182 - }
183 -
184 - $subAttached = array_diff( $attached, array( $home ) );
185 - $wgOut->addHTML( $this->step3ActionForm( $home, $subAttached, $methods ) );
186 - } else {
187 - // Show error message from status
188 - $wgOut->addHTML( '<div class="errorbox" style="float:none;">' );
189 - $wgOut->addWikiText( $status->getWikiText() );
190 - $wgOut->addHTML( '</div>' );
191 -
192 - // Show wiki list if required
193 - if ( $status->hasMessage( 'centralauth-blocked-text' )
194 - || $status->hasMessage( 'centralauth-merge-home-password' ) )
195 - {
196 - $out = '<h2>' . wfMsgHtml( 'centralauth-list-home-title' ) . '</h2>';
197 - $out .= wfMsgExt( 'centralauth-list-home-dryrun', 'parse' );
198 - $out .= $this->listAttached( array( $home ), array( $home => 'primary' ) );
199 - $wgOut->addHTML( $out );
200 - }
201 -
202 - // Show password box
203 - $wgOut->addHTML( $this->step1PasswordForm() );
204 - }
205 - }
206 -
207 - function doInitialMerge() {
208 - global $wgUser, $wgCentralAuthDryRun;
209 - $globalUser = new CentralAuthUser( $wgUser->getName() );
210 -
211 - if ( $wgCentralAuthDryRun ) {
212 - return $this->dryRunError();
213 - }
214 -
215 - if ( $globalUser->exists() ) {
216 - throw new MWException( "Already exists -- race condition" );
217 - }
218 -
219 - $passwords = $this->getWorkingPasswords();
220 - if ( empty( $passwords ) ) {
221 - throw new MWException( "Submission error -- invalid input" );
222 - }
223 -
224 - $globalUser->storeAndMigrate( $passwords );
225 - $this->clearWorkingPasswords();
226 -
227 - $this->showCleanupForm();
228 - }
229 -
230 - function doCleanupMerge() {
231 - global $wgUser, $wgRequest, $wgOut, $wgCentralAuthDryRun;
232 - $globalUser = new CentralAuthUser( $wgUser->getName() );
233 -
234 - if ( !$globalUser->exists() ) {
235 - throw new MWException( "User doesn't exist -- race condition?" );
236 - }
237 -
238 - if ( !$globalUser->isAttached() ) {
239 - throw new MWException( "Can't cleanup merge if not already attached." );
240 - }
241 -
242 - if ( $wgCentralAuthDryRun ) {
243 - return $this->dryRunError();
244 - }
245 - $password = $wgRequest->getText( 'wpPassword' );
246 -
247 - $attached = array();
248 - $unattached = array();
249 - $ok = $globalUser->attemptPasswordMigration( $password, $attached, $unattached );
250 - $this->clearWorkingPasswords();
251 -
252 - if ( !$ok ) {
253 - if ( empty( $attached ) ) {
254 - $wgOut->addWikiMsg( 'centralauth-finish-noconfirms' );
255 - } else {
256 - $wgOut->addWikiMsg( 'centralauth-finish-incomplete' );
257 - }
258 - }
259 - $this->showCleanupForm();
260 - }
261 -
262 - function doAttachMerge() {
263 - global $wgUser, $wgRequest, $wgOut, $wgCentralAuthDryRun;
264 - $globalUser = new CentralAuthUser( $wgUser->getName() );
265 -
266 - if ( !$globalUser->exists() ) {
267 - throw new MWException( "User doesn't exist -- race condition?" );
268 - }
269 -
270 - if ( $globalUser->isAttached() ) {
271 - throw new MWException( "Already attached -- race condition?" );
272 - }
273 -
274 - if ( $wgCentralAuthDryRun ) {
275 - return $this->dryRunError();
276 - }
277 - $password = $wgRequest->getText( 'wpPassword' );
278 - if ( $globalUser->authenticate( $password ) == 'ok' ) {
279 - $globalUser->attach( wfWikiID(), 'password' );
280 - $wgOut->addWikiMsg( 'centralauth-attach-success' );
281 - $this->showCleanupForm();
282 - } else {
283 - $wgOut->addHTML(
284 - '<div class="errorbox">' .
285 - wfMsg( 'wrongpassword' ) .
286 - '</div>' .
287 - $this->attachActionForm() );
288 - }
289 - }
290 -
291 - private function showWelcomeForm() {
292 - global $wgOut, $wgCentralAuthDryRun;
293 -
294 - if ( $wgCentralAuthDryRun ) {
295 - $wgOut->addWikiMsg( 'centralauth-notice-dryrun' );
296 - }
297 -
298 - $wgOut->addWikiMsg( 'centralauth-merge-welcome' );
299 - $wgOut->addWikiMsg( 'centralauth-readmore-text' );
300 -
301 - $this->initSession();
302 - $wgOut->addHTML(
303 - $this->passwordForm(
304 - 'dryrun',
305 - wfMsg( 'centralauth-merge-step1-title' ),
306 - wfMsg( 'centralauth-merge-step1-detail' ),
307 - wfMsg( 'centralauth-merge-step1-submit' ) )
308 - );
309 - }
310 -
311 - function showCleanupForm() {
312 - global $wgUser;
313 - $globalUser = new CentralAuthUser( $wgUser->getName() );
314 -
315 - $merged = $globalUser->listAttached();
316 - $remainder = $globalUser->listUnattached();
317 - $this->showStatus( $merged, $remainder );
318 - }
319 -
320 - function showAttachForm() {
321 - global $wgOut, $wgUser;
322 - $globalUser = new CentralAuthUser( $wgUser->getName() );
323 - $merged = $globalUser->listAttached();
324 - $wgOut->addWikiMsg( 'centralauth-attach-list-attached', $this->mUserName );
325 - $wgOut->addHTML( $this->listAttached( $merged ) );
326 - $wgOut->addHTML( $this->attachActionForm() );
327 - }
328 -
329 - function showStatus( $merged, $remainder ) {
330 - global $wgOut;
331 -
332 - if ( count( $remainder ) > 0 ) {
333 - $wgOut->setPageTitle( wfMsg( 'centralauth-incomplete' ) );
334 - $wgOut->addWikiMsg( 'centralauth-incomplete-text' );
335 - } else {
336 - $wgOut->setPageTitle( wfMsg( 'centralauth-complete' ) );
337 - $wgOut->addWikiMsg( 'centralauth-complete-text' );
338 - }
339 - $wgOut->addWikiMsg( 'centralauth-readmore-text' );
340 -
341 - if ( $merged ) {
342 - $wgOut->addHTML( '<hr />' );
343 - $wgOut->addWikiMsg( 'centralauth-list-attached',
344 - $this->mUserName );
345 - $wgOut->addHTML( $this->listAttached( $merged ) );
346 - }
347 -
348 - if ( $remainder ) {
349 - $wgOut->addHTML( '<hr />' );
350 - $wgOut->addWikiMsg( 'centralauth-list-unattached',
351 - $this->mUserName );
352 - $wgOut->addHTML( $this->listUnattached( $remainder ) );
353 -
354 - // Try the password form!
355 - $wgOut->addHTML( $this->passwordForm(
356 - 'cleanup',
357 - wfMsg( 'centralauth-finish-title' ),
358 - wfMsgExt( 'centralauth-finish-text', array( 'parse' ) ),
359 - wfMsg( 'centralauth-finish-login' ) ) );
360 - }
361 - }
362 -
363 - function listAttached( $wikiList, $methods = array() ) {
364 - return $this->listWikis( $wikiList, $methods );
365 - }
366 -
367 - function listUnattached( $wikiList ) {
368 - return $this->listWikis( $wikiList );
369 - }
370 -
371 - function listWikis( $list, $methods = array() ) {
372 - asort( $list );
373 - return $this->formatList( $list, $methods, array( $this, 'listWikiItem' ) );
374 - }
375 -
376 - function formatList( $items, $methods, $callback ) {
377 - if ( !$items ) {
378 - return '';
379 - } else {
380 - $itemMethods = array();
381 - foreach ( $items as $item ) {
382 - $itemMethods[] = isset( $methods[$item] ) ? $methods[$item] : '';
383 - }
384 - return "<ul>\n<li>" .
385 - implode( "</li>\n<li>",
386 - array_map( $callback, $items, $itemMethods ) ) .
387 - "</li>\n</ul>\n";
388 - }
389 - }
390 -
391 - function listWikiItem( $wikiID, $method ) {
392 - return
393 - $this->foreignUserLink( $wikiID ) . ( $method ? ' (' . wfMsgHtml( "centralauth-merge-method-$method" ) . ')' : '' );
394 - }
395 -
396 - function foreignUserLink( $wikiID ) {
397 - $wiki = WikiMap::getWiki( $wikiID );
398 - if ( !$wiki ) {
399 - throw new MWException( "no wiki for $wikiID" );
400 - }
401 -
402 - $hostname = $wiki->getDisplayName();
403 - $userPageName = 'User:' . $this->mUserName;
404 - $url = $wiki->getUrl( $userPageName );
405 - return Xml::element( 'a',
406 - array(
407 - 'href' => $url,
408 - 'title' => wfMsg( 'centralauth-foreign-link',
409 - $this->mUserName,
410 - $hostname ),
411 - ),
412 - $hostname );
413 - }
414 -
415 - private function actionForm( $action, $title, $text ) {
416 - global $wgUser;
417 - return
418 - '<div id="userloginForm">' .
419 - Xml::openElement( 'form',
420 - array(
421 - 'method' => 'post',
422 - 'action' => $this->getTitle()->getLocalUrl( 'action=submit' ) ) ) .
423 - Xml::element( 'h2', array(), $title ) .
424 - Html::hidden( 'wpEditToken', $wgUser->editToken() ) .
425 - Html::hidden( 'wpMergeAction', $action ) .
426 - Html::hidden( 'wpMergeSessionToken', $this->mSessionToken ) .
427 - Html::hidden( 'wpMergeSessionKey', bin2hex( $this->mSessionKey ) ) .
428 -
429 - $text .
430 -
431 - Xml::closeElement( 'form' ) .
432 -
433 - '<br clear="all" />' .
434 -
435 - '</div>';
436 - }
437 -
438 - private function passwordForm( $action, $title, $text, $submit ) {
439 - return $this->actionForm(
440 - $action,
441 - $title,
442 - $text .
443 - '<table>' .
444 - '<tr>' .
445 - '<td>' .
446 - Xml::label(
447 - wfMsg( 'centralauth-finish-password' ),
448 - 'wpPassword1' ) .
449 - '</td>' .
450 - '<td>' .
451 - Xml::input(
452 - 'wpPassword', 20, '',
453 - array(
454 - 'type' => 'password',
455 - 'id' => 'wpPassword1' ) ) .
456 - '</td>' .
457 - '</tr>' .
458 - '<tr>' .
459 - '<td></td>' .
460 - '<td>' .
461 - Xml::submitButton( $submit,
462 - array( 'name' => 'wpLogin' ) ) .
463 - '</td>' .
464 - '</tr>' .
465 - '</table>' );
466 - }
467 -
468 - private function step1PasswordForm() {
469 - return $this->passwordForm(
470 - 'dryrun',
471 - wfMsg( 'centralauth-merge-step1-title' ),
472 - wfMsg( 'centralauth-merge-step1-detail' ),
473 - wfMsg( 'centralauth-merge-step1-submit' ) );
474 - }
475 -
476 - private function step2PasswordForm( $unattached ) {
477 - global $wgUser;
478 - return $this->passwordForm(
479 - 'dryrun',
480 - wfMsg( 'centralauth-merge-step2-title' ),
481 - wfMsgExt( 'centralauth-merge-step2-detail', 'parse', $wgUser->getName() ) .
482 - $this->listUnattached( $unattached ),
483 - wfMsg( 'centralauth-merge-step2-submit' ) );
484 - }
485 -
486 - private function step3ActionForm( $home, $attached, $methods ) {
487 - global $wgUser;
488 - return $this->actionForm(
489 - 'initial',
490 - wfMsg( 'centralauth-merge-step3-title' ),
491 - wfMsgExt( 'centralauth-merge-step3-detail', 'parse', $wgUser->getName() ) .
492 - '<h3>' . wfMsgHtml( 'centralauth-list-home-title' ) . '</h3>' .
493 - wfMsgExt( 'centralauth-list-home-dryrun', 'parse' ) .
494 - $this->listAttached( array( $home ), $methods ) .
495 - ( count( $attached )
496 - ? ( '<h3>' . wfMsgHtml( 'centralauth-list-attached-title' ) . '</h3>' .
497 - wfMsgExt( 'centralauth-list-attached-dryrun', 'parse', $wgUser->getName() ) )
498 - : '' ) .
499 - $this->listAttached( $attached, $methods ) .
500 - '<p>' .
501 - Xml::submitButton( wfMsg( 'centralauth-merge-step3-submit' ),
502 - array( 'name' => 'wpLogin' ) ) .
503 - '</p>'
504 - );
505 - }
506 -
507 - private function attachActionForm() {
508 - return $this->passwordForm(
509 - 'attach',
510 - wfMsg( 'centralauth-attach-title' ),
511 - wfMsg( 'centralauth-attach-text' ),
512 - wfMsg( 'centralauth-attach-submit' ) );
513 - }
514 -
515 - private function dryRunError() {
516 - global $wgOut;
517 - $wgOut->addWikiMsg( 'centralauth-disabled-dryrun' );
518 - }
519 -}
Index: trunk/extensions/CentralAuth/SpecialGlobalUsers.php
@@ -1,155 +0,0 @@
2 -<?php
3 -
4 -class SpecialGlobalUsers extends SpecialPage {
5 - function __construct() {
6 - parent::__construct( 'GlobalUsers' );
7 - }
8 -
9 - function execute( $par ) {
10 - global $wgOut, $wgRequest, $wgContLang;
11 - $this->setHeaders();
12 -
13 - $pg = new GlobalUsersPager();
14 -
15 - if ( $par ) {
16 - $pg->setGroup( $par );
17 - }
18 - $rqGroup = $wgRequest->getVal( 'group' );
19 - if ( $rqGroup ) {
20 - $pg->setGroup( $rqGroup );
21 - }
22 - $rqUsername = $wgContLang->ucfirst( $wgRequest->getVal( 'username' ) );
23 - if ( $rqUsername ) {
24 - $pg->setUsername( $rqUsername );
25 - }
26 -
27 - $wgOut->addHTML( $pg->getPageHeader() );
28 - $wgOut->addHTML( $pg->getNavigationBar() );
29 - $wgOut->addHTML( '<ul>' . $pg->getBody() . '</ul>' );
30 - $wgOut->addHTML( $pg->getNavigationBar() );
31 - }
32 -}
33 -
34 -class GlobalUsersPager extends UsersPager {
35 - protected $requestedGroup = false, $requestedUser;
36 -
37 - function __construct() {
38 - parent::__construct();
39 - $this->mDb = CentralAuthUser::getCentralSlaveDB();
40 - }
41 -
42 - function setGroup( $group = '' ) {
43 - if ( !$group ) {
44 - $this->requestedGroup = false;
45 - return;
46 - }
47 - $groups = array_keys( $this->getAllGroups() );
48 - $this->requestedGroup = $group;
49 - }
50 -
51 - function setUsername( $username = '' ) {
52 - if ( !$username ) {
53 - $this->requestedUser = false;
54 - return;
55 - }
56 - $this->requestedUser = $username;
57 - }
58 -
59 - function getIndexField() {
60 - return 'gu_name';
61 - }
62 -
63 - function getDefaultQuery() {
64 - $query = parent::getDefaultQuery();
65 - if ( !isset( $query['group'] ) && $this->requestedGroup ) {
66 - $query['group'] = $this->requestedGroup;
67 - }
68 - return $this->mDefaultQuery = $query;
69 -
70 - }
71 -
72 - function getQueryInfo() {
73 - $localwiki = wfWikiID();
74 - $conds = array( 'gu_hidden' => CentralAuthUser::HIDDEN_NONE );
75 -
76 - if ( $this->requestedGroup ) {
77 - $conds['gug_group'] = $this->requestedGroup;
78 - }
79 -
80 - if ( $this->requestedUser ) {
81 - $conds[] = 'gu_name >= ' . $this->mDb->addQuotes( $this->requestedUser );
82 - }
83 -
84 - return array(
85 - 'tables' => " (globaluser LEFT JOIN localuser ON gu_name = lu_name AND lu_wiki = '{$localwiki}') LEFT JOIN global_user_groups ON gu_id = gug_user ",
86 - 'fields' => array( 'gu_id', 'gu_name', 'gu_locked', 'lu_attached_method', 'COUNT(gug_group) AS gug_numgroups', 'MAX(gug_group) AS gug_singlegroup' ),
87 - 'conds' => $conds,
88 - 'options' => array( 'GROUP BY' => 'gu_name' ),
89 - );
90 - }
91 -
92 - /**
93 - * Formats a row
94 - * @param object $row The row to be formatted for output
95 - * @return string HTML li element with username and info about this user
96 - */
97 - function formatRow( $row ) {
98 - global $wgLang;
99 - $user = htmlspecialchars( $row->gu_name );
100 - $info = array();
101 - if ( $row->gu_locked ) {
102 - $info[] = wfMsg( 'centralauth-listusers-locked' );
103 - }
104 - if ( $row->lu_attached_method ) {
105 - $info[] = wfMsg( 'centralauth-listusers-attached', $row->gu_name );
106 - } else {
107 - $info[] = wfMsg( 'centralauth-listusers-nolocal' );
108 - }
109 - $groups = $this->getUserGroups( $row );
110 -
111 - if ( $groups ) {
112 - $info[] = $groups;
113 - }
114 - $info = $wgLang->commaList( $info );
115 - return Html::rawElement( 'li', array(), wfMsgExt( 'centralauth-listusers-item', array('parseinline'), $user, $info ) );
116 - }
117 -
118 - function getBody() {
119 - if ( !$this->mQueryDone ) {
120 - $this->doQuery();
121 - }
122 - $batch = new LinkBatch;
123 -
124 - $this->mResult->rewind();
125 -
126 - foreach ( $this->mResult as $row ) {
127 - $batch->addObj( Title::makeTitleSafe( NS_USER, $row->gu_name ) );
128 - }
129 - $batch->execute();
130 - $this->mResult->rewind();
131 - return AlphabeticPager::getBody();
132 - }
133 -
134 - protected function getUserGroups( $row ) {
135 - if ( !$row->gug_numgroups ) {
136 - return false;
137 - }
138 - if ( $row->gug_numgroups == 1 ) {
139 - return User::makeGroupLinkWiki( $row->gug_singlegroup, User::getGroupMember( $row->gug_singlegroup ) );
140 - }
141 - $result = $this->mDb->select( 'global_user_groups', 'gug_group', array( 'gug_user' => $row->gu_id ), __METHOD__ );
142 - $rights = array();
143 - foreach ( $result as $row2 ) {
144 - $rights[] = User::makeGroupLinkWiki( $row2->gug_group, User::getGroupMember( $row2->gug_group ) );
145 - }
146 - return implode( ', ', $rights );
147 - }
148 -
149 - public function getAllGroups() {
150 - $result = array();
151 - foreach ( CentralAuthUser::availableGlobalGroups() as $group ) {
152 - $result[$group] = User::getGroupName( $group );
153 - }
154 - return $result;
155 - }
156 -}
Index: trunk/extensions/CentralAuth/CentralAuth.php
@@ -145,21 +145,21 @@
146146 * Initialization of the autoloaders, and special extension pages.
147147 */
148148 $caBase = dirname( __FILE__ );
149 -$wgAutoloadClasses['SpecialCentralAuth'] = "$caBase/SpecialCentralAuth.php";
150 -$wgAutoloadClasses['SpecialMergeAccount'] = "$caBase/SpecialMergeAccount.php";
151 -$wgAutoloadClasses['SpecialGlobalUsers'] = "$caBase/SpecialGlobalUsers.php";
 149+$wgAutoloadClasses['SpecialCentralAuth'] = "$caBase/specials/SpecialCentralAuth.php";
 150+$wgAutoloadClasses['SpecialMergeAccount'] = "$caBase/specials/SpecialMergeAccount.php";
 151+$wgAutoloadClasses['SpecialGlobalUsers'] = "$caBase/specials/SpecialGlobalUsers.php";
152152 $wgAutoloadClasses['CentralAuthUser'] = "$caBase/CentralAuthUser.php";
153153 $wgAutoloadClasses['CentralAuthPlugin'] = "$caBase/CentralAuthPlugin.php";
154154 $wgAutoloadClasses['CentralAuthHooks'] = "$caBase/CentralAuthHooks.php";
155155 $wgAutoloadClasses['CentralAuthSuppressUserJob'] = "$caBase/SuppressUserJob.php";
156156 $wgAutoloadClasses['WikiSet'] = "$caBase/WikiSet.php";
157 -$wgAutoloadClasses['SpecialAutoLogin'] = "$caBase/SpecialAutoLogin.php";
 157+$wgAutoloadClasses['SpecialAutoLogin'] = "$caBase/specials/SpecialAutoLogin.php";
158158 $wgAutoloadClasses['CentralAuthUserArray'] = "$caBase/CentralAuthUserArray.php";
159159 $wgAutoloadClasses['CentralAuthUserArrayFromResult'] = "$caBase/CentralAuthUserArray.php";
160 -$wgAutoloadClasses['SpecialGlobalGroupMembership'] = "$caBase/SpecialGlobalGroupMembership.php";
 160+$wgAutoloadClasses['SpecialGlobalGroupMembership'] = "$caBase/specials/SpecialGlobalGroupMembership.php";
161161 $wgAutoloadClasses['CentralAuthGroupMembershipProxy'] = "$caBase/CentralAuthGroupMembershipProxy.php";
162 -$wgAutoloadClasses['SpecialGlobalGroupPermissions'] = "$caBase/SpecialGlobalGroupPermissions.php";
163 -$wgAutoloadClasses['SpecialWikiSets'] = "$caBase/SpecialWikiSets.php";
 162+$wgAutoloadClasses['SpecialGlobalGroupPermissions'] = "$caBase/specials/SpecialGlobalGroupPermissions.php";
 163+$wgAutoloadClasses['SpecialWikiSets'] = "$caBase/specials/SpecialWikiSets.php";
164164 $wgAutoloadClasses['ApiQueryGlobalUserInfo'] = "$caBase/ApiQueryGlobalUserInfo.php";
165165
166166 $wgExtensionMessagesFiles['SpecialCentralAuth'] = "$caBase/CentralAuth.i18n.php";
Index: trunk/extensions/CentralAuth/specials/SpecialGlobalGroupMembership.php
@@ -0,0 +1,111 @@
 2+<?php
 3+/**
 4+ * Equivalent of Special:Userrights for global groups.
 5+ *
 6+ * @ingroup Extensions
 7+ */
 8+
 9+class SpecialGlobalGroupMembership extends UserrightsPage {
 10+ var $mGlobalUser;
 11+
 12+ function __construct() {
 13+ SpecialPage::__construct( 'GlobalGroupMembership' );
 14+
 15+ global $wgUser;
 16+ $this->mGlobalUser = CentralAuthUser::getInstance( $wgUser );
 17+ }
 18+
 19+ function getSuccessURL() {
 20+ $knownWikis = $this->mGlobalUser->listAttached();
 21+ $title = $this->getTitle( $this->mTarget );
 22+ return $title->getFullURL( 'wpKnownWiki=' . urlencode( $knownWikis[0] ) );
 23+ }
 24+
 25+ /**
 26+ * Output a form to allow searching for a user
 27+ */
 28+ function switchForm() {
 29+ global $wgOut, $wgScript, $wgRequest;
 30+
 31+ $knownwiki = $wgRequest->getVal( 'wpKnownWiki' );
 32+ $knownwiki = $knownwiki ? $knownwiki : wfWikiId();
 33+
 34+ // Generate wiki selector
 35+ $selector = new XmlSelect( 'wpKnownWiki', 'wpKnownWiki', $knownwiki );
 36+
 37+ foreach ( CentralAuthUser::getWikiList() as $wiki ) {
 38+ $selector->addOption( $wiki );
 39+ }
 40+
 41+ $wgOut->addModuleStyles( 'mediawiki.special' );
 42+ $wgOut->addHTML(
 43+ Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript, 'name' => 'uluser', 'id' => 'mw-userrights-form1' ) ) .
 44+ Html::hidden( 'title', $this->getTitle() ) .
 45+ Xml::openElement( 'fieldset' ) .
 46+ Xml::element( 'legend', array(), wfMsg( 'userrights-lookup-user' ) ) .
 47+ Xml::inputLabel( wfMsg( 'userrights-user-editname' ), 'user', 'username', 30, $this->mTarget ) . ' <br />' .
 48+ Xml::label( wfMsg( 'centralauth-globalgrouppermissions-knownwiki' ), 'wpKnownWiki' ) . ' ' .
 49+ $selector->getHTML() . '<br />' .
 50+ Xml::submitButton( wfMsg( 'editusergroup' ) ) .
 51+ Xml::closeElement( 'fieldset' ) .
 52+ Xml::closeElement( 'form' ) . "\n"
 53+ );
 54+ }
 55+
 56+ function changeableGroups() {
 57+ # # Should be a global user
 58+ if ( !$this->mGlobalUser->exists() || !$this->mGlobalUser->isAttached() ) {
 59+ return array();
 60+ }
 61+
 62+ $allGroups = CentralAuthUser::availableGlobalGroups();
 63+
 64+ # # Permission MUST be gained from global rights.
 65+ if ( $this->mGlobalUser->hasGlobalPermission( 'globalgroupmembership' ) ) {
 66+ # specify addself and removeself as empty arrays -- bug 16098
 67+ return array( 'add' => $allGroups, 'remove' => $allGroups, 'add-self' => array(), 'remove-self' => array() );
 68+ } else {
 69+ return array( 'add' => array(), 'remove' => array(), 'add-self' => array(), 'remove-self' => array() );
 70+ }
 71+ }
 72+
 73+ function fetchUser( $username ) {
 74+ global $wgRequest;
 75+
 76+ $knownwiki = $wgRequest->getVal( 'wpKnownWiki' );
 77+
 78+ $user = CentralAuthGroupMembershipProxy::newFromName( $username );
 79+
 80+ if ( !$user ) {
 81+ return Status::newFatal( 'nosuchusershort', $username );
 82+ } elseif ( !$wgRequest->getCheck( 'saveusergroups' ) && !$user->attachedOn( $knownwiki ) ) {
 83+ return Status::newFatal( 'centralauth-globalgroupmembership-badknownwiki',
 84+ $username, $knownwiki );
 85+ }
 86+
 87+ return Status::newGood( $user );
 88+ }
 89+
 90+ protected static function getAllGroups() {
 91+ return CentralAuthUser::availableGlobalGroups();
 92+ }
 93+
 94+ protected function showLogFragment( $user, $output ) {
 95+ $pageTitle = Title::makeTitleSafe( NS_USER, $user->getName() );
 96+ $output->addHTML( Xml::element( 'h2', null, LogPage::logName( 'gblrights' ) . "\n" ) );
 97+ LogEventsList::showLogExtract( $output, 'gblrights', $pageTitle->getPrefixedText() );
 98+ }
 99+
 100+ function addLogEntry( $user, $oldGroups, $newGroups, $reason ) {
 101+ $log = new LogPage( 'gblrights' );
 102+
 103+ $log->addEntry( 'usergroups',
 104+ $user->getUserPage(),
 105+ $reason,
 106+ array(
 107+ $this->makeGroupNameList( $oldGroups ),
 108+ $this->makeGroupNameList( $newGroups )
 109+ )
 110+ );
 111+ }
 112+}
Property changes on: trunk/extensions/CentralAuth/specials/SpecialGlobalGroupMembership.php
___________________________________________________________________
Added: svn:eol-style
1113 + native
Index: trunk/extensions/CentralAuth/specials/SpecialGlobalGroupPermissions.php
@@ -0,0 +1,370 @@
 2+<?php
 3+# This file is part of MediaWiki.
 4+
 5+# MediaWiki is free software: you can redistribute it and/or modify
 6+# it under the terms of version 2 of the GNU General Public License
 7+# as published by the Free Software Foundation.
 8+
 9+# MediaWiki is distributed in the hope that it will be useful,
 10+# but WITHOUT ANY WARRANTY; without even the implied warranty of
 11+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 12+# GNU General Public License for more details.
 13+
 14+/**
 15+ * Special page to allow managing global groups
 16+ * Prototype for a similar system in core.
 17+ *
 18+ * @file
 19+ * @ingroup Extensions
 20+ */
 21+
 22+if ( !defined( 'MEDIAWIKI' ) ) {
 23+ echo "CentralAuth extension\n";
 24+ exit( 1 );
 25+}
 26+
 27+class SpecialGlobalGroupPermissions extends SpecialPage {
 28+ function __construct() {
 29+ parent::__construct( 'GlobalGroupPermissions' );
 30+ }
 31+
 32+ function userCanEdit( $user ) {
 33+ $globalUser = CentralAuthUser::getInstance( $user );
 34+
 35+ # # Should be a global user
 36+ if ( !$globalUser->exists() || !$globalUser->isAttached() ) {
 37+ return false;
 38+ }
 39+
 40+ # # Permission MUST be gained from global rights.
 41+ return $globalUser->hasGlobalPermission( 'globalgrouppermissions' );
 42+ }
 43+
 44+ function execute( $subpage ) {
 45+ global $wgRequest, $wgOut, $wgUser;
 46+
 47+ if ( !$this->userCanExecute( $wgUser ) ) {
 48+ $this->displayRestrictionError();
 49+ return;
 50+ }
 51+
 52+ $wgOut->setPageTitle( wfMsg( 'globalgrouppermissions' ) );
 53+ $wgOut->setRobotPolicy( "noindex,nofollow" );
 54+ $wgOut->setArticleRelated( false );
 55+ $wgOut->enableClientCache( false );
 56+
 57+ if ( $subpage == '' ) {
 58+ $subpage = $wgRequest->getVal( 'wpGroup' );
 59+ }
 60+
 61+ if ( $subpage != '' && $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ) ) {
 62+ $this->doSubmit( $subpage );
 63+ } else if ( $subpage != '' ) {
 64+ $this->buildGroupView( $subpage );
 65+ } else {
 66+ $this->buildMainView();
 67+ }
 68+ }
 69+
 70+ function buildMainView() {
 71+ global $wgOut, $wgUser, $wgScript;
 72+
 73+ $groups = CentralAuthUser::availableGlobalGroups();
 74+
 75+ // Existing groups
 76+ $html = Xml::fieldset( wfMsg( 'centralauth-existinggroup-legend' ) );
 77+
 78+ $wgOut->addHTML( $html );
 79+
 80+ if ( count( $groups ) ) {
 81+ $wgOut->addWikiMsg( 'centralauth-globalgroupperms-grouplist' );
 82+ $wgOut->addHTML( '<ul>' );
 83+
 84+ foreach ( $groups as $group ) {
 85+ $text = wfMsgExt( 'centralauth-globalgroupperms-grouplistitem', array( 'parseinline' ), User::getGroupName( $group ), $group, '<span class="centralauth-globalgroupperms-groupname">' . $group . '</span>' );
 86+
 87+ $wgOut->addHTML( "<li> $text </li>" );
 88+ }
 89+ } else {
 90+ $wgOut->addWikiMsg( 'centralauth-globalgroupperms-nogroups' );
 91+ }
 92+
 93+ $wgOut->addHTML( Xml::closeElement( 'ul' ) . Xml::closeElement( 'fieldset' ) );
 94+
 95+ if ( $this->userCanEdit( $wgUser ) ) {
 96+ // "Create a group" prompt
 97+ $html = Xml::fieldset( wfMsg( 'centralauth-newgroup-legend' ) );
 98+ $html .= wfMsgExt( 'centralauth-newgroup-intro', array( 'parse' ) );
 99+ $html .= Xml::openElement( 'form', array( 'method' => 'post', 'action' => $wgScript, 'name' => 'centralauth-globalgroups-newgroup' ) );
 100+ $html .= Html::hidden( 'title', SpecialPage::getTitleFor( 'GlobalGroupPermissions' )->getPrefixedText() );
 101+
 102+ $fields = array( 'centralauth-globalgroupperms-newgroupname' => Xml::input( 'wpGroup' ) );
 103+
 104+ $html .= Xml::buildForm( $fields, 'centralauth-globalgroupperms-creategroup-submit' );
 105+ $html .= Xml::closeElement( 'form' );
 106+ $html .= Xml::closeElement( 'fieldset' );
 107+
 108+ $wgOut->addHTML( $html );
 109+ }
 110+ }
 111+
 112+ function buildGroupView( $group ) {
 113+ global $wgOut, $wgUser;
 114+
 115+ $editable = $this->userCanEdit( $wgUser );
 116+
 117+ $wgOut->setSubtitle( wfMsg( 'centralauth-editgroup-subtitle', $group ) );
 118+
 119+ $html = Xml::fieldset( wfMsg( 'centralauth-editgroup-fieldset', $group ) );
 120+
 121+ if ( $editable ) {
 122+ $html .= Xml::openElement( 'form', array( 'method' => 'post', 'action' => SpecialPage::getTitleFor( 'GlobalGroupPermissions', $group )->getLocalUrl(), 'name' => 'centralauth-globalgroups-newgroup' ) );
 123+ $html .= Html::hidden( 'wpGroup', $group );
 124+ $html .= Html::hidden( 'wpEditToken', $wgUser->editToken() );
 125+ }
 126+
 127+ $fields = array();
 128+
 129+ $fields['centralauth-editgroup-name'] = $group;
 130+ $fields['centralauth-editgroup-display'] = wfMsgExt( 'centralauth-editgroup-display-edit', array( 'parseinline' ), $group, User::getGroupName( $group ) );
 131+ $fields['centralauth-editgroup-member'] = wfMsgExt( 'centralauth-editgroup-member-edit', array( 'parseinline' ), $group, User::getGroupMember( $group ) );
 132+ $fields['centralauth-editgroup-members'] = wfMsgExt( 'centralauth-editgroup-members-link', array( 'parseinline' ), $group, User::getGroupMember( $group ) );
 133+ $fields['centralauth-editgroup-restrictions'] = $this->buildWikiSetSelector( $group );
 134+ $fields['centralauth-editgroup-perms'] = $this->buildCheckboxes( $group );
 135+
 136+ if ( $editable ) {
 137+ $fields['centralauth-editgroup-reason'] = Xml::input( 'wpReason', 60 );
 138+ }
 139+
 140+ $html .= Xml::buildForm( $fields, $editable ? 'centralauth-editgroup-submit' : null );
 141+
 142+ if ( $editable )
 143+ $html .= Xml::closeElement( 'form' );
 144+
 145+ $html .= Xml::closeElement( 'fieldset' );
 146+
 147+ $wgOut->addHTML( $html );
 148+
 149+ $this->showLogFragment( $group, $wgOut );
 150+ }
 151+
 152+ function buildWikiSetSelector( $group ) {
 153+ $sets = WikiSet::getAllWikiSets();
 154+ $default = WikiSet::getWikiSetForGroup( $group );
 155+
 156+ global $wgUser;
 157+ if ( !$this->userCanEdit( $wgUser ) )
 158+ return htmlspecialchars( $default );
 159+
 160+ $select = new XmlSelect( 'set', 'wikiset', $default );
 161+ $select->addOption( wfMsg( 'centralauth-editgroup-noset' ), '0' );
 162+ foreach ( $sets as $set ) {
 163+ $select->addOption( $set->getName(), $set->getID() );
 164+ }
 165+
 166+ $editlink = wfMsgExt( "centralauth-editgroup-editsets", array( "parseinline" ) );
 167+ return $select->getHTML() . "&#160;{$editlink}";
 168+ }
 169+
 170+ function buildCheckboxes( $group ) {
 171+ global $wgUser, $wgOut;
 172+
 173+ $editable = $this->userCanEdit( $wgUser );
 174+
 175+ $rights = User::getAllRights();
 176+ $assignedRights = $this->getAssignedRights( $group );
 177+
 178+ sort( $rights );
 179+
 180+ $checkboxes = array();
 181+ $attribs = array();
 182+
 183+ if ( !$editable )
 184+ $attribs['disabled'] = 'disabled';
 185+
 186+ foreach ( $rights as $right ) {
 187+ # Build a checkbox.
 188+ $checked = in_array( $right, $assignedRights );
 189+
 190+ $desc = $wgOut->parseInline( User::getRightDescription( $right ) ) . ' ' .
 191+ Xml::element( 'tt', null, wfMsg( 'parentheses', $right ) );
 192+
 193+ $checkbox = Xml::check( "wpRightAssigned-$right", $checked, $attribs );
 194+ $label = Xml::tags( 'label', array( 'for' => "wpRightAssigned-$right" ),
 195+ $desc );
 196+
 197+ $checkboxes[] = "<li>$checkbox&#160;$label</li>";
 198+ }
 199+
 200+ $count = count( $checkboxes );
 201+
 202+ $firstCol = round( $count / 2 );
 203+
 204+ $checkboxes1 = array_slice( $checkboxes, 0, $firstCol );
 205+ $checkboxes2 = array_slice( $checkboxes, $firstCol );
 206+
 207+ $html = '<table><tbody><tr><td><ul>';
 208+
 209+ foreach ( $checkboxes1 as $cb ) {
 210+ $html .= $cb;
 211+ }
 212+
 213+ $html .= '</ul></td><td><ul>';
 214+
 215+ foreach ( $checkboxes2 as $cb ) {
 216+ $html .= $cb;
 217+ }
 218+
 219+ $html .= '</ul></td></tr></tbody></table>';
 220+
 221+ return $html;
 222+ }
 223+
 224+ function getAssignedRights( $group ) {
 225+ return CentralAuthUser::globalGroupPermissions( $group );
 226+ }
 227+
 228+ function doSubmit( $group ) {
 229+ global $wgRequest, $wgOut, $wgUser;
 230+
 231+ // Paranoia -- the edit token shouldn't match anyway
 232+ if ( !$this->userCanEdit( $wgUser ) )
 233+ return;
 234+
 235+ $newRights = array();
 236+ $addRights = array();
 237+ $removeRights = array();
 238+ $oldRights = $this->getAssignedRights( $group );
 239+ $allRights = User::getAllRights();
 240+
 241+ $reason = $wgRequest->getVal( 'wpReason', '' );
 242+
 243+ foreach ( $allRights as $right ) {
 244+ $alreadyAssigned = in_array( $right, $oldRights );
 245+
 246+ if ( $wgRequest->getCheck( "wpRightAssigned-$right" ) ) {
 247+ $newRights[] = $right;
 248+ }
 249+
 250+ if ( !$alreadyAssigned && $wgRequest->getCheck( "wpRightAssigned-$right" ) ) {
 251+ $addRights[] = $right;
 252+ } else if ( $alreadyAssigned && !$wgRequest->getCheck( "wpRightAssigned-$right" ) ) {
 253+ $removeRights[] = $right;
 254+ } # Otherwise, do nothing.
 255+ }
 256+
 257+ // Assign the rights.
 258+ if ( count( $addRights ) > 0 )
 259+ $this->grantRightsToGroup( $group, $addRights );
 260+ if ( count( $removeRights ) > 0 )
 261+ $this->revokeRightsFromGroup( $group, $removeRights );
 262+
 263+ // Log it
 264+ if ( !( count( $addRights ) == 0 && count( $removeRights ) == 0 ) )
 265+ $this->addLogEntry( $group, $addRights, $removeRights, $reason );
 266+
 267+ // Change set
 268+ $current = WikiSet::getWikiSetForGroup( $group );
 269+ $new = $wgRequest->getVal( 'set' );
 270+ if ( $current != $new ) {
 271+ $this->setRestrictions( $group, $new );
 272+ $this->addLogEntry2( $group, $current, $new, $reason );
 273+ }
 274+
 275+ $this->invalidateRightsCache( $group );
 276+
 277+ // Display success
 278+ $wgOut->setSubTitle( wfMsg( 'centralauth-editgroup-success' ) );
 279+ $wgOut->addWikiMsg( 'centralauth-editgroup-success-text', $group );
 280+ }
 281+
 282+ function revokeRightsFromGroup( $group, $rights ) {
 283+ $dbw = CentralAuthUser::getCentralDB();
 284+
 285+ # Delete from the DB
 286+ $dbw->delete( 'global_group_permissions', array( 'ggp_group' => $group, 'ggp_permission' => $rights ), __METHOD__ );
 287+ }
 288+
 289+ function grantRightsToGroup( $group, $rights ) {
 290+ $dbw = CentralAuthUser::getCentralDB();
 291+
 292+ if ( !is_array( $rights ) ) {
 293+ $rights = array( $rights );
 294+ }
 295+
 296+ $insertRows = array();
 297+ foreach ( $rights as $right ) {
 298+ $insertRows[] = array( 'ggp_group' => $group, 'ggp_permission' => $right );
 299+ }
 300+
 301+ # Replace into the DB
 302+ $dbw->replace( 'global_group_permissions', array( 'ggp_group', 'ggp_permission' ), $insertRows, __METHOD__ );
 303+ }
 304+
 305+ protected function showLogFragment( $group, $output ) {
 306+ $title = SpecialPage::getTitleFor( 'GlobalUsers', $group );
 307+ $output->addHTML( Xml::element( 'h2', null, LogPage::logName( 'gblrights' ) . "\n" ) );
 308+ LogEventsList::showLogExtract( $output, 'gblrights', $title->getPrefixedText() );
 309+ }
 310+
 311+ function addLogEntry( $group, $addRights, $removeRights, $reason ) {
 312+ $log = new LogPage( 'gblrights' );
 313+
 314+ $log->addEntry( 'groupprms2',
 315+ SpecialPage::getTitleFor( 'GlobalUsers', $group ),
 316+ $reason,
 317+ array(
 318+ $this->makeRightsList( $addRights ),
 319+ $this->makeRightsList( $removeRights )
 320+ )
 321+ );
 322+ }
 323+
 324+ function makeRightsList( $ids ) {
 325+ return (bool)count( $ids ) ? implode( ', ', $ids ) : wfMsgForContent( 'rightsnone' );
 326+ }
 327+
 328+ function setRestrictions( $group, $set ) {
 329+ $dbw = CentralAuthUser::getCentralDB();
 330+ if ( $set == 0 ) {
 331+ $dbw->delete( 'global_group_restrictions', array( 'ggr_group' => $group ), __METHOD__ );
 332+ } else {
 333+ $dbw->replace( 'global_group_restrictions', array( 'ggr_group' ),
 334+ array( 'ggr_group' => $group, 'ggr_set' => $set, ), __METHOD__ );
 335+ }
 336+ return (bool)$dbw->affectedRows();
 337+ }
 338+
 339+ function addLogEntry2( $group, $old, $new, $reason ) {
 340+ $log = new LogPage( 'gblrights' );
 341+
 342+ $log->addEntry( 'groupprms3',
 343+ SpecialPage::getTitleFor( 'GlobalUsers', $group ),
 344+ $reason,
 345+ array(
 346+ $this->getWikiSetName( $old ),
 347+ $this->getWikiSetName( $new ),
 348+ )
 349+ );
 350+ }
 351+
 352+ function getWikiSetName( $id ) {
 353+ if ( $id )
 354+ return WikiSet::newFromID( $id )->getName();
 355+ else
 356+ return wfMsgForContent( 'centralauth-editgroup-noset' );
 357+ }
 358+
 359+ function invalidateRightsCache( $group ) {
 360+ // Figure out all the users in this group.
 361+ $dbr = CentralAuthUser::getCentralDB();
 362+
 363+ $res = $dbr->select( array( 'global_user_groups', 'globaluser' ), 'gu_name', array( 'gug_group' => $group, 'gu_id=gug_user' ), __METHOD__ );
 364+
 365+ // Invalidate their rights cache.
 366+ foreach ( $res as $row ) {
 367+ $cu = new CentralAuthUser( $row->gu_name );
 368+ $cu->quickInvalidateCache();
 369+ }
 370+ }
 371+}
Property changes on: trunk/extensions/CentralAuth/specials/SpecialGlobalGroupPermissions.php
___________________________________________________________________
Added: svn:eol-style
1372 + native
Index: trunk/extensions/CentralAuth/specials/SpecialCentralAuth.php
@@ -0,0 +1,633 @@
 2+<?php
 3+class SpecialCentralAuth extends SpecialPage {
 4+ var $mUserName, $mCanUnmerge, $mCanLock, $mCanOversight, $mCanEdit;
 5+ var $mGlobalUser, $mAttachedLocalAccounts, $mUnattachedLocalAccounts;
 6+
 7+ function __construct() {
 8+ parent::__construct( 'CentralAuth' );
 9+ }
 10+
 11+ function execute( $subpage ) {
 12+ global $wgOut;
 13+ global $wgExtensionAssetsPath, $wgCentralAuthStyleVersion;
 14+ global $wgUser, $wgRequest, $wgContLang;
 15+ $this->setHeaders();
 16+
 17+ $this->mCanUnmerge = $wgUser->isAllowed( 'centralauth-unmerge' );
 18+ $this->mCanLock = $wgUser->isAllowed( 'centralauth-lock' );
 19+ $this->mCanOversight = $wgUser->isAllowed( 'centralauth-oversight' );
 20+ $this->mCanEdit = $this->mCanUnmerge || $this->mCanLock || $this->mCanOversight;
 21+
 22+ $wgOut->addExtensionStyle( "{$wgExtensionAssetsPath}/CentralAuth/centralauth.css?" .
 23+ $wgCentralAuthStyleVersion );
 24+ $wgOut->addScriptFile( "{$wgExtensionAssetsPath}/CentralAuth/centralauth.js?" .
 25+ $wgCentralAuthStyleVersion );
 26+ $this->addMergeMethodDescriptions();
 27+
 28+ $this->mUserName =
 29+ trim(
 30+ str_replace( '_', ' ',
 31+ $wgRequest->getText( 'target', $subpage ) ) );
 32+
 33+ $this->mUserName = $wgContLang->ucfirst( $this->mUserName );
 34+
 35+ $this->mPosted = $wgRequest->wasPosted();
 36+ $this->mMethod = $wgRequest->getVal( 'wpMethod' );
 37+ $this->mWikis = (array)$wgRequest->getArray( 'wpWikis' );
 38+
 39+ // Possible demo states
 40+
 41+ // success, all accounts merged
 42+ // successful login, some accounts merged, others left
 43+ // successful login, others left
 44+ // not account owner, others left
 45+
 46+ // is owner / is not owner
 47+ // did / did not merge some accounts
 48+ // do / don't have more accounts to merge
 49+
 50+ if ( $this->mUserName === '' ) {
 51+ # First time through
 52+ $wgOut->addWikiMsg( 'centralauth-admin-intro' );
 53+ $this->showUsernameForm();
 54+ return;
 55+ }
 56+
 57+ $this->mGlobalUser = $globalUser = new CentralAuthUser( $this->mUserName );
 58+
 59+ if ( !$globalUser->exists() ||
 60+ ( $globalUser->isOversighted() && !$this->mCanOversight ) ) {
 61+ $this->showError( 'centralauth-admin-nonexistent', $this->mUserName );
 62+ $this->showUsernameForm();
 63+ return;
 64+ }
 65+
 66+ $continue = true;
 67+ if ( $this->mCanEdit && $this->mPosted ) {
 68+ $continue = $this->doSubmit();
 69+ }
 70+
 71+ $this->mAttachedLocalAccounts = $this->mGlobalUser->queryAttached();
 72+ $this->mUnattachedLocalAccounts = $this->mGlobalUser->queryUnattached();
 73+
 74+ $this->showUsernameForm();
 75+ if ( $continue ) {
 76+ $this->showInfo();
 77+ if ( $this->mCanLock )
 78+ $this->showStatusForm();
 79+ if ( $this->mCanUnmerge )
 80+ $this->showActionForm( 'delete' );
 81+ if ( $this->mCanEdit )
 82+ $this->showLogExtract();
 83+ $this->showWikiLists();
 84+ }
 85+ }
 86+
 87+ /** Returns true if the normal form should be displayed */
 88+ function doSubmit() {
 89+ $deleted = false;
 90+ $globalUser = $this->mGlobalUser;
 91+ global $wgUser, $wgRequest;
 92+ if ( !$wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ) ) {
 93+ $this->showError( 'centralauth-token-mismatch' );
 94+ } elseif ( $this->mMethod == 'unmerge' && $this->mCanUnmerge ) {
 95+ $status = $globalUser->adminUnattach( $this->mWikis );
 96+ if ( !$status->isGood() ) {
 97+ $this->showStatusError( $status->getWikiText() );
 98+ } else {
 99+ global $wgLang;
 100+ $this->showSuccess( 'centralauth-admin-unmerge-success',
 101+ $wgLang->formatNum( $status->successCount ),
 102+ /* deprecated */ $status->successCount );
 103+ }
 104+ } elseif ( $this->mMethod == 'delete' && $this->mCanUnmerge ) {
 105+ $status = $globalUser->adminDelete();
 106+ if ( !$status->isGood() ) {
 107+ $this->showStatusError( $status->getWikiText() );
 108+ } else {
 109+ $this->showSuccess( 'centralauth-admin-delete-success', $this->mUserName );
 110+ $deleted = true;
 111+ $this->logAction( 'delete', $this->mUserName, $wgRequest->getVal( 'reason' ) );
 112+ }
 113+ } elseif ( $this->mMethod == 'set-status' && $this->mCanLock ) {
 114+ $setLocked = $wgRequest->getBool( 'wpStatusLocked' );
 115+ $setHidden = $wgRequest->getVal( 'wpStatusHidden' );
 116+ $isLocked = $globalUser->isLocked();
 117+ $oldHiddenLevel = $globalUser->getHiddenLevel();
 118+ $lockStatus = $hideStatus = null;
 119+ $added = array();
 120+ $removed = array();
 121+
 122+ // Sanitizing input value...
 123+ $hiddenLevels = array(
 124+ CentralAuthUser::HIDDEN_NONE,
 125+ CentralAuthUser::HIDDEN_LISTS,
 126+ CentralAuthUser::HIDDEN_OVERSIGHT );
 127+ if ( !in_array( $setHidden, $hiddenLevels ) )
 128+ $setHidden = '';
 129+
 130+ if ( !$isLocked && $setLocked ) {
 131+ $lockStatus = $globalUser->adminLock();
 132+ $added[] = wfMsgForContent( 'centralauth-log-status-locked' );
 133+ } elseif ( $isLocked && !$setLocked ) {
 134+ $lockStatus = $globalUser->adminUnlock();
 135+ $removed[] = wfMsgForContent( 'centralauth-log-status-locked' );
 136+ }
 137+
 138+ $reason = $wgRequest->getText( 'wpReasonList' );
 139+ $reasonDetail = $wgRequest->getText( 'wpReason' );
 140+ if ( $reason == 'other' ) {
 141+ $reason = $reasonDetail;
 142+ } elseif ( $reasonDetail ) {
 143+ $reason .= wfMsgForContent( 'colon-separator' ) . $reasonDetail;
 144+ }
 145+
 146+ if ( $oldHiddenLevel != $setHidden ) {
 147+ $hideStatus = $globalUser->adminSetHidden( $setHidden );
 148+ switch( $setHidden ) {
 149+ case CentralAuthUser::HIDDEN_NONE:
 150+ $removed[] = $oldHiddenLevel == CentralAuthUser::HIDDEN_OVERSIGHT ?
 151+ wfMsgForContent( 'centralauth-log-status-oversighted' ) :
 152+ wfMsgForContent( 'centralauth-log-status-hidden' );
 153+ break;
 154+ case CentralAuthUser::HIDDEN_LISTS:
 155+ $added[] = wfMsgForContent( 'centralauth-log-status-hidden' );
 156+ if ( $oldHiddenLevel == CentralAuthUser::HIDDEN_OVERSIGHT )
 157+ $removed[] = wfMsgForContent( 'centralauth-log-status-oversighted' );
 158+ break;
 159+ case CentralAuthUser::HIDDEN_OVERSIGHT:
 160+ $added[] = wfMsgForContent( 'centralauth-log-status-oversighted' );
 161+ if ( $oldHiddenLevel == CentralAuthUser::HIDDEN_LISTS )
 162+ $removed[] = wfMsgForContent( 'centralauth-log-status-hidden' );
 163+ break;
 164+ }
 165+
 166+ if ( $setHidden == CentralAuthUser::HIDDEN_OVERSIGHT )
 167+ $globalUser->suppress( $reason );
 168+ elseif ( $oldHiddenLevel == CentralAuthUser::HIDDEN_OVERSIGHT )
 169+ $globalUser->unsuppress( $reason );
 170+ }
 171+
 172+ $good =
 173+ ( is_null( $lockStatus ) || $lockStatus->isGood() ) &&
 174+ ( is_null( $hideStatus ) || $hideStatus->isGood() );
 175+
 176+ // Logging etc
 177+ if ( $good && ( count( $added ) || count( $removed ) ) ) {
 178+ $added = count( $added ) ?
 179+ implode( ', ', $added ) : wfMsgForContent( 'centralauth-log-status-none' );
 180+ $removed = count( $removed ) ?
 181+ implode( ', ', $removed ) : wfMsgForContent( 'centralauth-log-status-none' );
 182+
 183+ $this->logAction(
 184+ 'setstatus',
 185+ $this->mUserName,
 186+ $reason,
 187+ array( $added, $removed ),
 188+ $setHidden == CentralAuthUser::HIDDEN_OVERSIGHT
 189+ );
 190+ $this->showSuccess( 'centralauth-admin-setstatus-success', $this->mUserName );
 191+ } elseif ( !$good ) {
 192+ if ( !is_null( $lockStatus ) && !$lockStatus->isGood() ) {
 193+ $this->showStatusError( $lockStatus->getWikiText() );
 194+ }
 195+ if ( !is_null( $hideStatus ) && !$hideStatus->isGood() ) {
 196+ $this->showStatusError( $hideStatus->getWikiText() );
 197+ }
 198+ }
 199+ } else {
 200+ $this->showError( 'centralauth-admin-bad-input' );
 201+ }
 202+ return !$deleted;
 203+ }
 204+
 205+ function showStatusError( $wikitext ) {
 206+ global $wgOut;
 207+ $wrap = Xml::tags( 'div', array( 'class' => 'error' ), $wikitext );
 208+ $wgOut->addHTML( $wgOut->parse( $wrap, /*linestart*/true, /*uilang*/true ) );
 209+ }
 210+
 211+ function showError( /* varargs */ ) {
 212+ global $wgOut;
 213+ $args = func_get_args();
 214+ $wgOut->wrapWikiMsg( '<div class="error">$1</div>', $args );
 215+ }
 216+
 217+
 218+ function showSuccess( /* varargs */ ) {
 219+ global $wgOut;
 220+ $args = func_get_args();
 221+ $wgOut->wrapWikiMsg( '<div class="success">$1</div>', $args );
 222+ }
 223+
 224+ function showUsernameForm() {
 225+ global $wgOut, $wgScript;
 226+ $lookup = $this->mCanEdit ?
 227+ wfMsg( 'centralauth-admin-lookup-rw' ) :
 228+ wfMsg( 'centralauth-admin-lookup-ro' );
 229+ $wgOut->addHTML(
 230+ Xml::openElement( 'form', array(
 231+ 'method' => 'get',
 232+ 'action' => $wgScript ) ) .
 233+ '<fieldset>' .
 234+ Xml::element( 'legend', array(), wfMsg( 'centralauth-admin-manage' ) ) .
 235+ Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) .
 236+ '<p>' .
 237+ Xml::inputLabel( wfMsg( 'centralauth-admin-username' ),
 238+ 'target', 'target', 25, $this->mUserName ) .
 239+ '</p>' .
 240+ '<p>' .
 241+ Xml::submitButton( $lookup ) .
 242+ '</p>' .
 243+ '</fieldset>' .
 244+ '</form>'
 245+ );
 246+ }
 247+
 248+ function prettyTimespan( $span ) {
 249+ global $wgLang;
 250+ $units = array(
 251+ 'seconds' => 60,
 252+ 'minutes' => 60,
 253+ 'hours' => 24,
 254+ 'days' => 30.417,
 255+ 'months' => 12,
 256+ 'years' => 1 );
 257+ foreach ( $units as $unit => $chunk ) {
 258+ // Used messaged (to make sure that grep finds them):
 259+ // 'centralauth-seconds-ago', 'centralauth-minutes-ago', 'centralauth-hours-ago'
 260+ // 'centralauth-days-ago', 'centralauth-months-ago', 'centralauth-years-ago'
 261+ if ( $span < 2 * $chunk ) {
 262+ return wfMsgExt( "centralauth-$unit-ago", 'parsemag', $wgLang->formatNum( $span ) );
 263+ }
 264+ $span = intval( $span / $chunk );
 265+ }
 266+ return wfMsgExt( "centralauth-$unit-ago", 'parsemag', $wgLang->formatNum( $span ) );
 267+ }
 268+
 269+ function showInfo() {
 270+ $globalUser = $this->mGlobalUser;
 271+
 272+ global $wgOut, $wgLang;
 273+ $reg = $globalUser->getRegistration();
 274+ $age = $this->prettyTimespan( wfTimestamp( TS_UNIX ) - wfTimestamp( TS_UNIX, $reg ) );
 275+ $attribs = array(
 276+ 'id' => $globalUser->getId(),
 277+ 'registered' => $wgLang->timeanddate( $reg ) . " ($age)",
 278+ 'home' => $this->determineHomeWiki(),
 279+ 'editcount' => $wgLang->formatNum( $this->evaluateTotalEditcount() ),
 280+ 'locked' => $globalUser->isLocked() ? wfMsg( 'centralauth-admin-yes' ) : wfMsg( 'centralauth-admin-no' ),
 281+ 'hidden' => $this->formatHiddenLevel( $globalUser->getHiddenLevel() ) );
 282+ $out = '<fieldset id="mw-centralauth-info">';
 283+ $out .= '<legend>' . wfMsgHtml( 'centralauth-admin-info-header' ) . '</legend>';
 284+ foreach ( $attribs as $tag => $data ) {
 285+ $out .= '<p><strong>' . wfMsgHtml( "centralauth-admin-info-$tag" ) . '</strong> ' .
 286+ htmlspecialchars( $data ) . '</p>';
 287+ }
 288+ $out .= '</fieldset>';
 289+ $wgOut->addHTML( $out );
 290+ }
 291+
 292+ function showWikiLists() {
 293+ global $wgOut;
 294+ $merged = $this->mAttachedLocalAccounts;
 295+ $remainder = $this->mUnattachedLocalAccounts;
 296+
 297+ $legend = $this->mCanUnmerge ?
 298+ wfMsgHtml( 'centralauth-admin-list-legend-rw' ) :
 299+ wfMsgHtml( 'centralauth-admin-list-legend-ro' );
 300+
 301+ $wgOut->addHTML( "<fieldset><legend>{$legend}</legend>" );
 302+ $wgOut->addHTML( $this->listHeader() );
 303+ $wgOut->addHTML( $this->listMerged( $merged ) );
 304+ if ( $remainder )
 305+ $wgOut->addHTML( $this->listRemainder( $remainder ) );
 306+ $wgOut->addHTML( $this->listFooter() );
 307+ $wgOut->addHTML( '</fieldset>' );
 308+ }
 309+
 310+ function listHeader() {
 311+ global $wgUser;
 312+ return
 313+ Xml::openElement( 'form',
 314+ array(
 315+ 'method' => 'post',
 316+ 'action' =>
 317+ $this->getTitle( $this->mUserName )->getLocalUrl( 'action=submit' ),
 318+ 'id' => 'mw-centralauth-merged' ) ) .
 319+ Html::hidden( 'wpMethod', 'unmerge' ) .
 320+ Html::hidden( 'wpEditToken', $wgUser->editToken() ) .
 321+ Xml::openElement( 'table', array( 'class' => 'wikitable sortable mw-centralauth-wikislist' ) ) . "\n" .
 322+ '<thead><tr>' .
 323+ ( $this->mCanUnmerge ? '<th></th>' : '' ) .
 324+ '<th>' . wfMsgHtml( 'centralauth-admin-list-localwiki' ) . '</th>' .
 325+ '<th>' . wfMsgHtml( 'centralauth-admin-list-attached-on' ) . '</th>' .
 326+ '<th>' . wfMsgHtml( 'centralauth-admin-list-method' ) . '</th>' .
 327+ '<th>' . wfMsgHtml( 'centralauth-admin-list-blocked' ) . '</th>' .
 328+ '<th>' . wfMsgHtml( 'centralauth-admin-list-editcount' ) . '</th>' .
 329+ '</tr></thead>' .
 330+ '<tbody>';
 331+ }
 332+
 333+ function listFooter() {
 334+ $footer = '';
 335+ if ( $this->mCanUnmerge )
 336+ $footer .=
 337+ '<tr>' .
 338+ '<td style="border-right: none"></td>' .
 339+ '<td style="border-left: none" colspan="5">' .
 340+ Xml::submitButton( wfMsg( 'centralauth-admin-unmerge' ) ) .
 341+ '</td>' .
 342+ '</tr>';
 343+ $footer .= '</tbody></table></form>';
 344+ return $footer;
 345+ }
 346+
 347+ function listMerged( $list ) {
 348+ ksort( $list );
 349+ return implode( "\n", array_map( array( $this, 'listMergedWikiItem' ), $list ) );
 350+ }
 351+
 352+ function listRemainder( $list ) {
 353+ ksort( $list );
 354+ $notMerged = wfMsgExt( 'centralauth-admin-unattached', array( 'parseinline' ) );
 355+ $rows = array();
 356+ foreach ( $list as $row ) {
 357+ $rows[] = '<tr class="unattached-row"><td>' .
 358+ ( $this->mCanUnmerge ? '</td><td>' : '' ) .
 359+ $this->foreignUserLink( $row['wiki'] ) .
 360+ "</td><td colspan='4'>{$notMerged}</td></tr>\n";
 361+ }
 362+ return implode( $rows );
 363+ }
 364+
 365+ function listMergedWikiItem( $row ) {
 366+ global $wgLang;
 367+ return '<tr>' .
 368+ ( $this->mCanUnmerge ? '<td>' . $this->adminCheck( $row['wiki'] ) . '</td>' : '' ) .
 369+ '<td>' . $this->foreignUserLink( $row['wiki'] ) . '</td>' .
 370+ '<td>' .
 371+ // invisible, to make this column sortable
 372+ Html::element( 'span', array( 'style' => 'display: none' ), htmlspecialchars( $row['attachedTimestamp'] ) ) .
 373+ // visible date and time in users preference
 374+ htmlspecialchars( $wgLang->timeanddate( $row['attachedTimestamp'] ) ) .
 375+ '</td>' .
 376+ '<td style="text-align: center">' . $this->formatMergeMethod( $row['attachedMethod'] ) . '</td>' .
 377+ '<td>' . $this->formatBlockStatus( $row ) . '</td>' .
 378+ '<td style="text-align: right">' . $this->formatEditcount( $row ) . '</td>' .
 379+ '</tr>';
 380+ }
 381+
 382+ function formatMergeMethod( $method ) {
 383+ global $wgExtensionAssetsPath;
 384+
 385+ $img = htmlspecialchars( "{$wgExtensionAssetsPath}/CentralAuth/icons/merged-{$method}.png" );
 386+ $brief = wfMsgHtml( "centralauth-merge-method-{$method}" );
 387+ return "<img src=\"{$img}\" alt=\"{$brief}\" title=\"{$brief}\"/>" .
 388+ "<span class=\"merge-method-help\" title=\"{$brief}\" onclick=\"showMethodHint('{$method}')\">(?)</span>";
 389+ }
 390+
 391+ function formatBlockStatus( $row ) {
 392+ if ( $row['blocked'] ) {
 393+ if ( $row['block-expiry'] == 'infinity' ) {
 394+ $reason = $row['block-reason'];
 395+ return wfMsgExt( 'centralauth-admin-blocked-indef', 'parseinline', array( $reason ) );
 396+ } else {
 397+ global $wgLang;
 398+ $expiry = $wgLang->timeanddate( $row['block-expiry'] );
 399+ $expiryd = $wgLang->date( $row['block-expiry'] );
 400+ $expiryt = $wgLang->time( $row['block-expiry'] );
 401+ $reason = $row['block-reason'];
 402+
 403+ $text = wfMsgExt( 'centralauth-admin-blocked', 'parseinline', array( $expiry, $reason, $expiryd, $expiryt ) );
 404+ }
 405+ } else {
 406+ $text = wfMsgExt( 'centralauth-admin-notblocked', 'parseinline' );
 407+ }
 408+
 409+ return $this->foreignLink(
 410+ $row['wiki'],
 411+ 'Special:Log/block',
 412+ $text,
 413+ wfMsg( 'centralauth-admin-blocklog' ),
 414+ 'page=User:' . urlencode( $this->mUserName ) );
 415+ }
 416+
 417+ function formatEditcount( $row ) {
 418+ global $wgLang;
 419+ return $this->foreignLink(
 420+ $row['wiki'],
 421+ 'Special:Contributions/' . $this->mUserName,
 422+ $wgLang->formatNum( intval( $row['editCount'] ) ),
 423+ 'contributions' );
 424+ }
 425+
 426+ function formatHiddenLevel( $level ) {
 427+ switch( $level ) {
 428+ case CentralAuthUser::HIDDEN_NONE:
 429+ return wfMsg( 'centralauth-admin-no' );
 430+ case CentralAuthUser::HIDDEN_LISTS:
 431+ return wfMsg( 'centralauth-admin-hidden-list' );
 432+ case CentralAuthUser::HIDDEN_OVERSIGHT:
 433+ return wfMsg( 'centralauth-admin-hidden-oversight' );
 434+ }
 435+ }
 436+
 437+ function tableRow( $element, $cols ) {
 438+ return "<tr><$element>" .
 439+ implode( "</$element><$element>", $cols ) .
 440+ "</$element></tr>";
 441+ }
 442+
 443+ function foreignLink( $wikiID, $title, $text, $hint = '', $params = '' ) {
 444+ if ( $wikiID instanceof WikiReference ) {
 445+ $wiki = $wikiID;
 446+ } else {
 447+ $wiki = WikiMap::getWiki( $wikiID );
 448+ if ( !$wiki ) {
 449+ throw new MWException( "Invalid wiki: $wikiID" );
 450+ }
 451+ }
 452+
 453+ $url = $wiki->getUrl( $title );
 454+ if ( $params )
 455+ $url .= '?' . $params;
 456+ return Xml::element( 'a',
 457+ array(
 458+ 'href' => $url,
 459+ 'title' => $hint,
 460+ ),
 461+ $text );
 462+ }
 463+
 464+ function foreignUserLink( $wikiID ) {
 465+ $wiki = WikiMap::getWiki( $wikiID );
 466+ if ( !$wiki ) {
 467+ throw new MWException( "Invalid wiki: $wikiID" );
 468+ }
 469+
 470+ $wikiname = $wiki->getDisplayName();
 471+ return $this->foreignLink(
 472+ $wiki,
 473+ 'User:' . $this->mUserName,
 474+ $wikiname,
 475+ wfMsg( 'centralauth-foreign-link', $this->mUserName, $wikiname ) );
 476+
 477+ }
 478+
 479+ function adminCheck( $wikiID ) {
 480+ return
 481+ Xml::check( 'wpWikis[]', false, array( 'value' => $wikiID ) );
 482+ }
 483+
 484+ function showActionForm( $action ) {
 485+ global $wgOut, $wgUser;
 486+ $wgOut->addHTML(
 487+ Xml::fieldset( wfMsg( "centralauth-admin-{$action}-title" ) ) .
 488+ Xml::openElement( 'form', array(
 489+ 'method' => 'POST',
 490+ 'action' => $this->getTitle()->getFullUrl( 'target=' . urlencode( $this->mUserName ) ),
 491+ 'id' => "mw-centralauth-$action" ) ) .
 492+ Html::hidden( 'wpMethod', $action ) .
 493+ Html::hidden( 'wpEditToken', $wgUser->editToken() ) .
 494+ wfMsgExt( "centralauth-admin-{$action}-description", 'parse' ) .
 495+ Xml::buildForm(
 496+ array( 'centralauth-admin-reason' => Xml::input( 'reason',
 497+ false, false, array( 'id' => "{$action}-reason" ) ) ),
 498+ "centralauth-admin-{$action}-button"
 499+ ) .
 500+ '</form></fieldset>' );
 501+ }
 502+
 503+ function showStatusForm() {
 504+ // Allows locking, hiding, locking and hiding.
 505+ global $wgUser, $wgOut;
 506+ $form = '';
 507+ $form .= Xml::fieldset( wfMsg( 'centralauth-admin-status' ) );
 508+ $form .= Html::hidden( 'wpMethod', 'set-status' );
 509+ $form .= Html::hidden( 'wpEditToken', $wgUser->editToken() );
 510+ $form .= wfMsgExt( 'centralauth-admin-status-intro', 'parse' );
 511+
 512+ // Radio buttons
 513+ $radioLocked =
 514+ Xml::radioLabel(
 515+ wfMsgExt( 'centralauth-admin-status-locked-no', array( 'parseinline' ) ),
 516+ 'wpStatusLocked',
 517+ '0',
 518+ 'mw-centralauth-status-locked-no',
 519+ !$this->mGlobalUser->isLocked() ) .
 520+ '<br />' .
 521+ Xml::radioLabel(
 522+ wfMsgExt( 'centralauth-admin-status-locked-yes', array( 'parseinline' ) ),
 523+ 'wpStatusLocked',
 524+ '1',
 525+ 'mw-centralauth-status-locked-yes',
 526+ $this->mGlobalUser->isLocked() );
 527+ $radioHidden =
 528+ Xml::radioLabel(
 529+ wfMsgExt( 'centralauth-admin-status-hidden-no', array( 'parseinline' ) ),
 530+ 'wpStatusHidden',
 531+ CentralAuthUser::HIDDEN_NONE,
 532+ 'mw-centralauth-status-hidden-no',
 533+ $this->mGlobalUser->getHiddenLevel() == CentralAuthUser::HIDDEN_NONE ) .
 534+ '<br />' .
 535+ Xml::radioLabel(
 536+ wfMsgExt( 'centralauth-admin-status-hidden-list', array( 'parseinline' ) ),
 537+ 'wpStatusHidden',
 538+ CentralAuthUser::HIDDEN_LISTS,
 539+ 'mw-centralauth-status-hidden-list',
 540+ $this->mGlobalUser->getHiddenLevel() == CentralAuthUser::HIDDEN_LISTS ) .
 541+ '<br />';
 542+ if ( $this->mCanOversight ) {
 543+ $radioHidden .= Xml::radioLabel(
 544+ wfMsgExt( 'centralauth-admin-status-hidden-oversight', array( 'parseinline' ) ),
 545+ 'wpStatusHidden',
 546+ CentralAuthUser::HIDDEN_OVERSIGHT,
 547+ 'mw-centralauth-status-hidden-oversight',
 548+ $this->mGlobalUser->getHiddenLevel() == CentralAuthUser::HIDDEN_OVERSIGHT
 549+ );
 550+ }
 551+
 552+ // Reason
 553+ $reasonList = Xml::listDropDown(
 554+ 'wpReasonList',
 555+ wfMsgForContent( 'centralauth-admin-status-reasons' ),
 556+ wfMsgForContent( 'ipbreasonotherlist' )
 557+ );
 558+ $reasonField = Xml::input( 'wpReason', 45, false );
 559+
 560+ $form .= Xml::buildForm(
 561+ array(
 562+ 'centralauth-admin-status-locked' => $radioLocked,
 563+ 'centralauth-admin-status-hidden' => $radioHidden,
 564+ 'centralauth-admin-reason' => $reasonList,
 565+ 'centralauth-admin-reason-other' => $reasonField ),
 566+ 'centralauth-admin-status-submit'
 567+ );
 568+
 569+ $form .= '</fieldset>';
 570+ $form = Xml::tags(
 571+ 'form',
 572+ array(
 573+ 'method' => 'POST',
 574+ 'action' => $this->getTitle()->getFullURL(
 575+ array( 'target' => $this->mUserName )
 576+ ),
 577+ ),
 578+ $form
 579+ );
 580+ $wgOut->addHTML( $form );
 581+ }
 582+
 583+ function showLogExtract() {
 584+ global $wgOut;
 585+ $user = $this->mGlobalUser->getName();
 586+ $text = '';
 587+ $numRows = LogEventsList::showLogExtract(
 588+ $text,
 589+ array( 'globalauth', 'suppress' ),
 590+ Title::newFromText( "User:{$user}@global" )->getPrefixedText(),
 591+ '',
 592+ array( 'showIfEmpty' => true ) );
 593+ if ( $numRows ) {
 594+ $wgOut->addHTML( Xml::fieldset( wfMsg( 'centralauth-admin-logsnippet' ), $text ) );
 595+ }
 596+ }
 597+
 598+ function determineHomeWiki() {
 599+ foreach ( $this->mAttachedLocalAccounts as $wiki => $acc ) {
 600+ if ( $acc['attachedMethod'] == 'primary' || $acc['attachedMethod'] == 'new' ) {
 601+ return $wiki;
 602+ }
 603+ }
 604+
 605+ // Home account can be renamed or unmerged
 606+ return wfMsgHtml( 'centralauth-admin-nohome' );
 607+ }
 608+
 609+ function evaluateTotalEditcount() {
 610+ $total = 0;
 611+ foreach ( $this->mAttachedLocalAccounts as $acc ) {
 612+ $total += $acc['editCount'];
 613+ }
 614+ return $total;
 615+ }
 616+
 617+ function addMergeMethodDescriptions() {
 618+ global $wgOut, $wgLang;
 619+ $js = "wgMergeMethodDescriptions = {\n";
 620+ foreach ( array( 'primary', 'new', 'empty', 'password', 'mail', 'admin', 'login' ) as $method ) {
 621+ $short = Xml::encodeJsVar( $wgLang->ucfirst( wfMsgHtml( "centralauth-merge-method-{$method}" ) ) );
 622+ $desc = Xml::encodeJsVar( wfMsgWikiHtml( "centralauth-merge-method-{$method}-desc" ) );
 623+ $js .= "\t'{$method}' : { 'short' : {$short}, 'desc' : {$desc} },\n";
 624+ }
 625+ $js .= "}";
 626+ $wgOut->addInlineScript( $js );
 627+ }
 628+
 629+ function logAction( $action, $target, $reason = '', $params = array(), $suppressLog = false ) {
 630+ $logType = $suppressLog ? 'suppress' : 'globalauth'; // Not centralauth because of some weird length limitiations
 631+ $log = new LogPage( $logType );
 632+ $log->addEntry( $action, Title::newFromText( "User:{$target}@global" ), $reason, $params );
 633+ }
 634+}
Property changes on: trunk/extensions/CentralAuth/specials/SpecialCentralAuth.php
___________________________________________________________________
Added: svn:eol-style
1635 + native
Index: trunk/extensions/CentralAuth/specials/SpecialMergeAccount.php
@@ -0,0 +1,518 @@
 2+<?php
 3+
 4+class SpecialMergeAccount extends SpecialPage {
 5+ function __construct() {
 6+ parent::__construct( 'MergeAccount', 'centralauth-merge' );
 7+ }
 8+
 9+ function execute( $subpage ) {
 10+ global $wgOut, $wgUser;
 11+ $this->setHeaders();
 12+
 13+ if ( !$this->userCanExecute( $wgUser ) ) {
 14+ $wgOut->addWikiMsg( 'centralauth-merge-denied' );
 15+ $wgOut->addWikiMsg( 'centralauth-readmore-text' );
 16+ return;
 17+ }
 18+
 19+ if ( !$wgUser->isLoggedIn() ) {
 20+ $wgOut->addWikiMsg( 'centralauth-merge-notlogged' );
 21+ $wgOut->addWikiMsg( 'centralauth-readmore-text' );
 22+
 23+ return;
 24+ }
 25+
 26+ if ( wfReadOnly() ) {
 27+ $wgOut->setPagetitle( wfMsg( 'readonly' ) );
 28+ $wgOut->addWikiMsg( 'readonlytext', wfReadOnlyReason() );
 29+ return;
 30+ }
 31+
 32+ global $wgUser, $wgRequest;
 33+ $this->mUserName = $wgUser->getName();
 34+
 35+ $this->mAttemptMerge = $wgRequest->wasPosted();
 36+
 37+ $this->mMergeAction = $wgRequest->getVal( 'wpMergeAction' );
 38+ $this->mPassword = $wgRequest->getVal( 'wpPassword' );
 39+ $this->mWikiIDs = $wgRequest->getArray( 'wpWikis' );
 40+ $this->mSessionToken = $wgRequest->getVal( 'wpMergeSessionToken' );
 41+ $this->mSessionKey = pack( "H*", $wgRequest->getVal( 'wpMergeSessionKey' ) );
 42+
 43+ // Possible demo states
 44+
 45+ // success, all accounts merged
 46+ // successful login, some accounts merged, others left
 47+ // successful login, others left
 48+ // not account owner, others left
 49+
 50+ // is owner / is not owner
 51+ // did / did not merge some accounts
 52+ // do / don't have more accounts to merge
 53+
 54+ if ( $this->mAttemptMerge ) {
 55+ switch( $this->mMergeAction ) {
 56+ case "dryrun":
 57+ return $this->doDryRunMerge();
 58+ case "initial":
 59+ return $this->doInitialMerge();
 60+ case "cleanup":
 61+ return $this->doCleanupMerge();
 62+ case "attach":
 63+ return $this->doAttachMerge();
 64+ case "remove":
 65+ return $this->doUnattach();
 66+ default:
 67+ return $this->invalidAction();
 68+ }
 69+ }
 70+
 71+ $globalUser = new CentralAuthUser( $this->mUserName );
 72+ if ( $globalUser->exists() ) {
 73+ if ( $globalUser->isAttached() ) {
 74+ $this->showCleanupForm();
 75+ } else {
 76+ $this->showAttachForm();
 77+ }
 78+ } else {
 79+ $this->showWelcomeForm();
 80+ }
 81+ }
 82+
 83+ /**
 84+ * To pass potentially multiple passwords from one form submission
 85+ * to another while previewing the merge behavior, we can store them
 86+ * in the server-side session information.
 87+ *
 88+ * We'd rather not have plaintext passwords floating about on disk
 89+ * or memcached, so the session store is obfuscated with simple XOR
 90+ * encryption. The key is passed in the form instead of the session
 91+ * data, so they won't be found floating in the same place.
 92+ */
 93+ private function initSession() {
 94+ global $wgUser;
 95+ $this->mSessionToken = $wgUser->generateToken();
 96+
 97+ // Generate a random binary string
 98+ $key = '';
 99+ for ( $i = 0; $i < 128; $i++ ) {
 100+ $key .= chr( mt_rand( 0, 255 ) );
 101+ }
 102+ $this->mSessionKey = $key;
 103+ }
 104+
 105+ private function getWorkingPasswords() {
 106+ wfSuppressWarnings();
 107+ $passwords = unserialize(
 108+ gzinflate(
 109+ $this->xorString(
 110+ $_SESSION['wsCentralAuthMigration'][$this->mSessionToken],
 111+ $this->mSessionKey ) ) );
 112+ wfRestoreWarnings();
 113+ if ( is_array( $passwords ) ) {
 114+ return $passwords;
 115+ }
 116+ return array();
 117+ }
 118+
 119+ private function addWorkingPassword( $password ) {
 120+ $passwords = $this->getWorkingPasswords();
 121+ if ( !in_array( $password, $passwords ) ) {
 122+ $passwords[] = $password;
 123+ }
 124+
 125+ // Lightly obfuscate the passwords while we're storing them,
 126+ // just to make us feel better about them floating around.
 127+ $_SESSION['wsCentralAuthMigration'][$this->mSessionToken] =
 128+ $this->xorString(
 129+ gzdeflate(
 130+ serialize(
 131+ $passwords ) ),
 132+ $this->mSessionKey );
 133+ }
 134+
 135+ private function clearWorkingPasswords() {
 136+ unset( $_SESSION['wsCentralAuthMigration'][$this->mSessionToken] );
 137+ }
 138+
 139+ function xorString( $text, $key ) {
 140+ if ( $key != '' ) {
 141+ for ( $i = 0; $i < strlen( $text ); $i++ ) {
 142+ $text[$i] = chr( 0xff & ( ord( $text[$i] ) ^ ord( $key[$i % strlen( $key )] ) ) );
 143+ }
 144+ }
 145+ return $text;
 146+ }
 147+
 148+ function doDryRunMerge() {
 149+ global $wgUser, $wgRequest, $wgOut, $wgCentralAuthDryRun;
 150+ $globalUser = new CentralAuthUser( $wgUser->getName() );
 151+
 152+ if ( $globalUser->exists() ) {
 153+ throw new MWException( "Already exists -- race condition" );
 154+ }
 155+
 156+ if ( $wgCentralAuthDryRun ) {
 157+ $wgOut->addWikiMsg( 'centralauth-notice-dryrun' );
 158+ }
 159+
 160+ $password = $wgRequest->getVal( 'wpPassword' );
 161+ $this->addWorkingPassword( $password );
 162+ $passwords = $this->getWorkingPasswords();
 163+
 164+ $home = false;
 165+ $attached = array();
 166+ $unattached = array();
 167+ $methods = array();
 168+ $status = $globalUser->migrationDryRun( $passwords, $home, $attached, $unattached, $methods );
 169+
 170+ if ( $status->isGood() ) {
 171+ // This is the global account or matched it
 172+ if ( count( $unattached ) == 0 ) {
 173+ // Everything matched -- very convenient!
 174+ $wgOut->addWikiMsg( 'centralauth-merge-dryrun-complete' );
 175+ } else {
 176+ $wgOut->addWikiMsg( 'centralauth-merge-dryrun-incomplete' );
 177+ }
 178+
 179+ if ( count( $unattached ) > 0 ) {
 180+ $wgOut->addHTML( $this->step2PasswordForm( $unattached ) );
 181+ $wgOut->addWikiMsg( 'centralauth-merge-dryrun-or' );
 182+ }
 183+
 184+ $subAttached = array_diff( $attached, array( $home ) );
 185+ $wgOut->addHTML( $this->step3ActionForm( $home, $subAttached, $methods ) );
 186+ } else {
 187+ // Show error message from status
 188+ $wgOut->addHTML( '<div class="errorbox" style="float:none;">' );
 189+ $wgOut->addWikiText( $status->getWikiText() );
 190+ $wgOut->addHTML( '</div>' );
 191+
 192+ // Show wiki list if required
 193+ if ( $status->hasMessage( 'centralauth-blocked-text' )
 194+ || $status->hasMessage( 'centralauth-merge-home-password' ) )
 195+ {
 196+ $out = '<h2>' . wfMsgHtml( 'centralauth-list-home-title' ) . '</h2>';
 197+ $out .= wfMsgExt( 'centralauth-list-home-dryrun', 'parse' );
 198+ $out .= $this->listAttached( array( $home ), array( $home => 'primary' ) );
 199+ $wgOut->addHTML( $out );
 200+ }
 201+
 202+ // Show password box
 203+ $wgOut->addHTML( $this->step1PasswordForm() );
 204+ }
 205+ }
 206+
 207+ function doInitialMerge() {
 208+ global $wgUser, $wgCentralAuthDryRun;
 209+ $globalUser = new CentralAuthUser( $wgUser->getName() );
 210+
 211+ if ( $wgCentralAuthDryRun ) {
 212+ return $this->dryRunError();
 213+ }
 214+
 215+ if ( $globalUser->exists() ) {
 216+ throw new MWException( "Already exists -- race condition" );
 217+ }
 218+
 219+ $passwords = $this->getWorkingPasswords();
 220+ if ( empty( $passwords ) ) {
 221+ throw new MWException( "Submission error -- invalid input" );
 222+ }
 223+
 224+ $globalUser->storeAndMigrate( $passwords );
 225+ $this->clearWorkingPasswords();
 226+
 227+ $this->showCleanupForm();
 228+ }
 229+
 230+ function doCleanupMerge() {
 231+ global $wgUser, $wgRequest, $wgOut, $wgCentralAuthDryRun;
 232+ $globalUser = new CentralAuthUser( $wgUser->getName() );
 233+
 234+ if ( !$globalUser->exists() ) {
 235+ throw new MWException( "User doesn't exist -- race condition?" );
 236+ }
 237+
 238+ if ( !$globalUser->isAttached() ) {
 239+ throw new MWException( "Can't cleanup merge if not already attached." );
 240+ }
 241+
 242+ if ( $wgCentralAuthDryRun ) {
 243+ return $this->dryRunError();
 244+ }
 245+ $password = $wgRequest->getText( 'wpPassword' );
 246+
 247+ $attached = array();
 248+ $unattached = array();
 249+ $ok = $globalUser->attemptPasswordMigration( $password, $attached, $unattached );
 250+ $this->clearWorkingPasswords();
 251+
 252+ if ( !$ok ) {
 253+ if ( empty( $attached ) ) {
 254+ $wgOut->addWikiMsg( 'centralauth-finish-noconfirms' );
 255+ } else {
 256+ $wgOut->addWikiMsg( 'centralauth-finish-incomplete' );
 257+ }
 258+ }
 259+ $this->showCleanupForm();
 260+ }
 261+
 262+ function doAttachMerge() {
 263+ global $wgUser, $wgRequest, $wgOut, $wgCentralAuthDryRun;
 264+ $globalUser = new CentralAuthUser( $wgUser->getName() );
 265+
 266+ if ( !$globalUser->exists() ) {
 267+ throw new MWException( "User doesn't exist -- race condition?" );
 268+ }
 269+
 270+ if ( $globalUser->isAttached() ) {
 271+ throw new MWException( "Already attached -- race condition?" );
 272+ }
 273+
 274+ if ( $wgCentralAuthDryRun ) {
 275+ return $this->dryRunError();
 276+ }
 277+ $password = $wgRequest->getText( 'wpPassword' );
 278+ if ( $globalUser->authenticate( $password ) == 'ok' ) {
 279+ $globalUser->attach( wfWikiID(), 'password' );
 280+ $wgOut->addWikiMsg( 'centralauth-attach-success' );
 281+ $this->showCleanupForm();
 282+ } else {
 283+ $wgOut->addHTML(
 284+ '<div class="errorbox">' .
 285+ wfMsg( 'wrongpassword' ) .
 286+ '</div>' .
 287+ $this->attachActionForm() );
 288+ }
 289+ }
 290+
 291+ private function showWelcomeForm() {
 292+ global $wgOut, $wgCentralAuthDryRun;
 293+
 294+ if ( $wgCentralAuthDryRun ) {
 295+ $wgOut->addWikiMsg( 'centralauth-notice-dryrun' );
 296+ }
 297+
 298+ $wgOut->addWikiMsg( 'centralauth-merge-welcome' );
 299+ $wgOut->addWikiMsg( 'centralauth-readmore-text' );
 300+
 301+ $this->initSession();
 302+ $wgOut->addHTML(
 303+ $this->passwordForm(
 304+ 'dryrun',
 305+ wfMsg( 'centralauth-merge-step1-title' ),
 306+ wfMsg( 'centralauth-merge-step1-detail' ),
 307+ wfMsg( 'centralauth-merge-step1-submit' ) )
 308+ );
 309+ }
 310+
 311+ function showCleanupForm() {
 312+ global $wgUser;
 313+ $globalUser = new CentralAuthUser( $wgUser->getName() );
 314+
 315+ $merged = $globalUser->listAttached();
 316+ $remainder = $globalUser->listUnattached();
 317+ $this->showStatus( $merged, $remainder );
 318+ }
 319+
 320+ function showAttachForm() {
 321+ global $wgOut, $wgUser;
 322+ $globalUser = new CentralAuthUser( $wgUser->getName() );
 323+ $merged = $globalUser->listAttached();
 324+ $wgOut->addWikiMsg( 'centralauth-attach-list-attached', $this->mUserName );
 325+ $wgOut->addHTML( $this->listAttached( $merged ) );
 326+ $wgOut->addHTML( $this->attachActionForm() );
 327+ }
 328+
 329+ function showStatus( $merged, $remainder ) {
 330+ global $wgOut;
 331+
 332+ if ( count( $remainder ) > 0 ) {
 333+ $wgOut->setPageTitle( wfMsg( 'centralauth-incomplete' ) );
 334+ $wgOut->addWikiMsg( 'centralauth-incomplete-text' );
 335+ } else {
 336+ $wgOut->setPageTitle( wfMsg( 'centralauth-complete' ) );
 337+ $wgOut->addWikiMsg( 'centralauth-complete-text' );
 338+ }
 339+ $wgOut->addWikiMsg( 'centralauth-readmore-text' );
 340+
 341+ if ( $merged ) {
 342+ $wgOut->addHTML( '<hr />' );
 343+ $wgOut->addWikiMsg( 'centralauth-list-attached',
 344+ $this->mUserName );
 345+ $wgOut->addHTML( $this->listAttached( $merged ) );
 346+ }
 347+
 348+ if ( $remainder ) {
 349+ $wgOut->addHTML( '<hr />' );
 350+ $wgOut->addWikiMsg( 'centralauth-list-unattached',
 351+ $this->mUserName );
 352+ $wgOut->addHTML( $this->listUnattached( $remainder ) );
 353+
 354+ // Try the password form!
 355+ $wgOut->addHTML( $this->passwordForm(
 356+ 'cleanup',
 357+ wfMsg( 'centralauth-finish-title' ),
 358+ wfMsgExt( 'centralauth-finish-text', array( 'parse' ) ),
 359+ wfMsg( 'centralauth-finish-login' ) ) );
 360+ }
 361+ }
 362+
 363+ function listAttached( $wikiList, $methods = array() ) {
 364+ return $this->listWikis( $wikiList, $methods );
 365+ }
 366+
 367+ function listUnattached( $wikiList ) {
 368+ return $this->listWikis( $wikiList );
 369+ }
 370+
 371+ function listWikis( $list, $methods = array() ) {
 372+ asort( $list );
 373+ return $this->formatList( $list, $methods, array( $this, 'listWikiItem' ) );
 374+ }
 375+
 376+ function formatList( $items, $methods, $callback ) {
 377+ if ( !$items ) {
 378+ return '';
 379+ } else {
 380+ $itemMethods = array();
 381+ foreach ( $items as $item ) {
 382+ $itemMethods[] = isset( $methods[$item] ) ? $methods[$item] : '';
 383+ }
 384+ return "<ul>\n<li>" .
 385+ implode( "</li>\n<li>",
 386+ array_map( $callback, $items, $itemMethods ) ) .
 387+ "</li>\n</ul>\n";
 388+ }
 389+ }
 390+
 391+ function listWikiItem( $wikiID, $method ) {
 392+ return
 393+ $this->foreignUserLink( $wikiID ) . ( $method ? ' (' . wfMsgHtml( "centralauth-merge-method-$method" ) . ')' : '' );
 394+ }
 395+
 396+ function foreignUserLink( $wikiID ) {
 397+ $wiki = WikiMap::getWiki( $wikiID );
 398+ if ( !$wiki ) {
 399+ throw new MWException( "no wiki for $wikiID" );
 400+ }
 401+
 402+ $hostname = $wiki->getDisplayName();
 403+ $userPageName = 'User:' . $this->mUserName;
 404+ $url = $wiki->getUrl( $userPageName );
 405+ return Xml::element( 'a',
 406+ array(
 407+ 'href' => $url,
 408+ 'title' => wfMsg( 'centralauth-foreign-link',
 409+ $this->mUserName,
 410+ $hostname ),
 411+ ),
 412+ $hostname );
 413+ }
 414+
 415+ private function actionForm( $action, $title, $text ) {
 416+ global $wgUser;
 417+ return
 418+ '<div id="userloginForm">' .
 419+ Xml::openElement( 'form',
 420+ array(
 421+ 'method' => 'post',
 422+ 'action' => $this->getTitle()->getLocalUrl( 'action=submit' ) ) ) .
 423+ Xml::element( 'h2', array(), $title ) .
 424+ Html::hidden( 'wpEditToken', $wgUser->editToken() ) .
 425+ Html::hidden( 'wpMergeAction', $action ) .
 426+ Html::hidden( 'wpMergeSessionToken', $this->mSessionToken ) .
 427+ Html::hidden( 'wpMergeSessionKey', bin2hex( $this->mSessionKey ) ) .
 428+
 429+ $text .
 430+
 431+ Xml::closeElement( 'form' ) .
 432+
 433+ '<br clear="all" />' .
 434+
 435+ '</div>';
 436+ }
 437+
 438+ private function passwordForm( $action, $title, $text, $submit ) {
 439+ return $this->actionForm(
 440+ $action,
 441+ $title,
 442+ $text .
 443+ '<table>' .
 444+ '<tr>' .
 445+ '<td>' .
 446+ Xml::label(
 447+ wfMsg( 'centralauth-finish-password' ),
 448+ 'wpPassword1' ) .
 449+ '</td>' .
 450+ '<td>' .
 451+ Xml::input(
 452+ 'wpPassword', 20, '',
 453+ array(
 454+ 'type' => 'password',
 455+ 'id' => 'wpPassword1' ) ) .
 456+ '</td>' .
 457+ '</tr>' .
 458+ '<tr>' .
 459+ '<td></td>' .
 460+ '<td>' .
 461+ Xml::submitButton( $submit,
 462+ array( 'name' => 'wpLogin' ) ) .
 463+ '</td>' .
 464+ '</tr>' .
 465+ '</table>' );
 466+ }
 467+
 468+ private function step1PasswordForm() {
 469+ return $this->passwordForm(
 470+ 'dryrun',
 471+ wfMsg( 'centralauth-merge-step1-title' ),
 472+ wfMsg( 'centralauth-merge-step1-detail' ),
 473+ wfMsg( 'centralauth-merge-step1-submit' ) );
 474+ }
 475+
 476+ private function step2PasswordForm( $unattached ) {
 477+ global $wgUser;
 478+ return $this->passwordForm(
 479+ 'dryrun',
 480+ wfMsg( 'centralauth-merge-step2-title' ),
 481+ wfMsgExt( 'centralauth-merge-step2-detail', 'parse', $wgUser->getName() ) .
 482+ $this->listUnattached( $unattached ),
 483+ wfMsg( 'centralauth-merge-step2-submit' ) );
 484+ }
 485+
 486+ private function step3ActionForm( $home, $attached, $methods ) {
 487+ global $wgUser;
 488+ return $this->actionForm(
 489+ 'initial',
 490+ wfMsg( 'centralauth-merge-step3-title' ),
 491+ wfMsgExt( 'centralauth-merge-step3-detail', 'parse', $wgUser->getName() ) .
 492+ '<h3>' . wfMsgHtml( 'centralauth-list-home-title' ) . '</h3>' .
 493+ wfMsgExt( 'centralauth-list-home-dryrun', 'parse' ) .
 494+ $this->listAttached( array( $home ), $methods ) .
 495+ ( count( $attached )
 496+ ? ( '<h3>' . wfMsgHtml( 'centralauth-list-attached-title' ) . '</h3>' .
 497+ wfMsgExt( 'centralauth-list-attached-dryrun', 'parse', $wgUser->getName() ) )
 498+ : '' ) .
 499+ $this->listAttached( $attached, $methods ) .
 500+ '<p>' .
 501+ Xml::submitButton( wfMsg( 'centralauth-merge-step3-submit' ),
 502+ array( 'name' => 'wpLogin' ) ) .
 503+ '</p>'
 504+ );
 505+ }
 506+
 507+ private function attachActionForm() {
 508+ return $this->passwordForm(
 509+ 'attach',
 510+ wfMsg( 'centralauth-attach-title' ),
 511+ wfMsg( 'centralauth-attach-text' ),
 512+ wfMsg( 'centralauth-attach-submit' ) );
 513+ }
 514+
 515+ private function dryRunError() {
 516+ global $wgOut;
 517+ $wgOut->addWikiMsg( 'centralauth-disabled-dryrun' );
 518+ }
 519+}
Property changes on: trunk/extensions/CentralAuth/specials/SpecialMergeAccount.php
___________________________________________________________________
Added: svn:keywords
1520 + LastChangedDate LastChangedRevision
Added: svn:eol-style
2521 + native
Index: trunk/extensions/CentralAuth/specials/SpecialAutoLogin.php
@@ -0,0 +1,86 @@
 2+<?php
 3+if ( !defined( 'MEDIAWIKI' ) ) {
 4+ die( 'CentralAuth' );
 5+}
 6+
 7+/**
 8+ * Unlisted Special page to set requisite cookies for being logged into this wiki.
 9+ *
 10+ * @ingroup Extensions
 11+ */
 12+class SpecialAutoLogin extends UnlistedSpecialPage {
 13+ function __construct() {
 14+ parent::__construct( 'AutoLogin' );
 15+ }
 16+
 17+ function execute( $par ) {
 18+ global $wgRequest, $wgOut, $wgMemc;
 19+
 20+ $tempToken = $wgRequest->getVal( 'token' );
 21+ $logout = $wgRequest->getBool( 'logout' );
 22+
 23+ # Don't cache error messages
 24+ $wgOut->enableClientCache( false );
 25+
 26+ if ( strlen( $tempToken ) == 0 ) {
 27+ $this->setHeaders();
 28+ $wgOut->addWikiMsg( 'centralauth-autologin-desc' );
 29+ return;
 30+ }
 31+
 32+ $key = CentralAuthUser::memcKey( 'login-token', $tempToken );
 33+ $data = $wgMemc->get( $key );
 34+ $wgMemc->delete( $key );
 35+
 36+ if ( !$data ) {
 37+ $msg = 'Token is invalid or has expired';
 38+ wfDebug( __METHOD__ . ": $msg\n" );
 39+ $this->setHeaders();
 40+ $wgOut->addWikiText( $msg );
 41+ return;
 42+ }
 43+
 44+ $userName = $data['userName'];
 45+ $token = $data['token'];
 46+ $remember = $data['remember'];
 47+
 48+ if ( $data['wiki'] != wfWikiID() ) {
 49+ $msg = 'Bad token (wrong wiki)';
 50+ wfDebug( __METHOD__ . ": $msg\n" );
 51+ $this->setHeaders();
 52+ $wgOut->addWikiText( $msg );
 53+ return;
 54+ }
 55+
 56+ $centralUser = new CentralAuthUser( $userName );
 57+ $loginResult = $centralUser->authenticateWithToken( $token );
 58+
 59+ if ( $loginResult != 'ok' ) {
 60+ $msg = "Bad token: $loginResult";
 61+ wfDebug( __METHOD__ . ": $msg\n" );
 62+ $this->setHeaders();
 63+ $wgOut->addWikiText( $msg );
 64+ return;
 65+ }
 66+
 67+ // Auth OK.
 68+ if ( $logout ) {
 69+ $centralUser->deleteGlobalCookies();
 70+ } else {
 71+ $centralUser->setGlobalCookies( $remember );
 72+ }
 73+
 74+ $wgOut->disable();
 75+
 76+ wfResetOutputBuffers();
 77+ header( 'Cache-Control: no-cache' );
 78+ header( 'Content-Type: image/png' );
 79+
 80+ global $wgCentralAuthLoginIcon;
 81+ if ( $wgCentralAuthLoginIcon ) {
 82+ readfile( $wgCentralAuthLoginIcon );
 83+ } else {
 84+ readfile( dirname( __FILE__ ) . '/1x1.png' );
 85+ }
 86+ }
 87+}
Property changes on: trunk/extensions/CentralAuth/specials/SpecialAutoLogin.php
___________________________________________________________________
Added: svn:eol-style
188 + native
Index: trunk/extensions/CentralAuth/specials/SpecialGlobalUsers.php
@@ -0,0 +1,155 @@
 2+<?php
 3+
 4+class SpecialGlobalUsers extends SpecialPage {
 5+ function __construct() {
 6+ parent::__construct( 'GlobalUsers' );
 7+ }
 8+
 9+ function execute( $par ) {
 10+ global $wgOut, $wgRequest, $wgContLang;
 11+ $this->setHeaders();
 12+
 13+ $pg = new GlobalUsersPager();
 14+
 15+ if ( $par ) {
 16+ $pg->setGroup( $par );
 17+ }
 18+ $rqGroup = $wgRequest->getVal( 'group' );
 19+ if ( $rqGroup ) {
 20+ $pg->setGroup( $rqGroup );
 21+ }
 22+ $rqUsername = $wgContLang->ucfirst( $wgRequest->getVal( 'username' ) );
 23+ if ( $rqUsername ) {
 24+ $pg->setUsername( $rqUsername );
 25+ }
 26+
 27+ $wgOut->addHTML( $pg->getPageHeader() );
 28+ $wgOut->addHTML( $pg->getNavigationBar() );
 29+ $wgOut->addHTML( '<ul>' . $pg->getBody() . '</ul>' );
 30+ $wgOut->addHTML( $pg->getNavigationBar() );
 31+ }
 32+}
 33+
 34+class GlobalUsersPager extends UsersPager {
 35+ protected $requestedGroup = false, $requestedUser;
 36+
 37+ function __construct() {
 38+ parent::__construct();
 39+ $this->mDb = CentralAuthUser::getCentralSlaveDB();
 40+ }
 41+
 42+ function setGroup( $group = '' ) {
 43+ if ( !$group ) {
 44+ $this->requestedGroup = false;
 45+ return;
 46+ }
 47+ $groups = array_keys( $this->getAllGroups() );
 48+ $this->requestedGroup = $group;
 49+ }
 50+
 51+ function setUsername( $username = '' ) {
 52+ if ( !$username ) {
 53+ $this->requestedUser = false;
 54+ return;
 55+ }
 56+ $this->requestedUser = $username;
 57+ }
 58+
 59+ function getIndexField() {
 60+ return 'gu_name';
 61+ }
 62+
 63+ function getDefaultQuery() {
 64+ $query = parent::getDefaultQuery();
 65+ if ( !isset( $query['group'] ) && $this->requestedGroup ) {
 66+ $query['group'] = $this->requestedGroup;
 67+ }
 68+ return $this->mDefaultQuery = $query;
 69+
 70+ }
 71+
 72+ function getQueryInfo() {
 73+ $localwiki = wfWikiID();
 74+ $conds = array( 'gu_hidden' => CentralAuthUser::HIDDEN_NONE );
 75+
 76+ if ( $this->requestedGroup ) {
 77+ $conds['gug_group'] = $this->requestedGroup;
 78+ }
 79+
 80+ if ( $this->requestedUser ) {
 81+ $conds[] = 'gu_name >= ' . $this->mDb->addQuotes( $this->requestedUser );
 82+ }
 83+
 84+ return array(
 85+ 'tables' => " (globaluser LEFT JOIN localuser ON gu_name = lu_name AND lu_wiki = '{$localwiki}') LEFT JOIN global_user_groups ON gu_id = gug_user ",
 86+ 'fields' => array( 'gu_id', 'gu_name', 'gu_locked', 'lu_attached_method', 'COUNT(gug_group) AS gug_numgroups', 'MAX(gug_group) AS gug_singlegroup' ),
 87+ 'conds' => $conds,
 88+ 'options' => array( 'GROUP BY' => 'gu_name' ),
 89+ );
 90+ }
 91+
 92+ /**
 93+ * Formats a row
 94+ * @param object $row The row to be formatted for output
 95+ * @return string HTML li element with username and info about this user
 96+ */
 97+ function formatRow( $row ) {
 98+ global $wgLang;
 99+ $user = htmlspecialchars( $row->gu_name );
 100+ $info = array();
 101+ if ( $row->gu_locked ) {
 102+ $info[] = wfMsg( 'centralauth-listusers-locked' );
 103+ }
 104+ if ( $row->lu_attached_method ) {
 105+ $info[] = wfMsg( 'centralauth-listusers-attached', $row->gu_name );
 106+ } else {
 107+ $info[] = wfMsg( 'centralauth-listusers-nolocal' );
 108+ }
 109+ $groups = $this->getUserGroups( $row );
 110+
 111+ if ( $groups ) {
 112+ $info[] = $groups;
 113+ }
 114+ $info = $wgLang->commaList( $info );
 115+ return Html::rawElement( 'li', array(), wfMsgExt( 'centralauth-listusers-item', array('parseinline'), $user, $info ) );
 116+ }
 117+
 118+ function getBody() {
 119+ if ( !$this->mQueryDone ) {
 120+ $this->doQuery();
 121+ }
 122+ $batch = new LinkBatch;
 123+
 124+ $this->mResult->rewind();
 125+
 126+ foreach ( $this->mResult as $row ) {
 127+ $batch->addObj( Title::makeTitleSafe( NS_USER, $row->gu_name ) );
 128+ }
 129+ $batch->execute();
 130+ $this->mResult->rewind();
 131+ return AlphabeticPager::getBody();
 132+ }
 133+
 134+ protected function getUserGroups( $row ) {
 135+ if ( !$row->gug_numgroups ) {
 136+ return false;
 137+ }
 138+ if ( $row->gug_numgroups == 1 ) {
 139+ return User::makeGroupLinkWiki( $row->gug_singlegroup, User::getGroupMember( $row->gug_singlegroup ) );
 140+ }
 141+ $result = $this->mDb->select( 'global_user_groups', 'gug_group', array( 'gug_user' => $row->gu_id ), __METHOD__ );
 142+ $rights = array();
 143+ foreach ( $result as $row2 ) {
 144+ $rights[] = User::makeGroupLinkWiki( $row2->gug_group, User::getGroupMember( $row2->gug_group ) );
 145+ }
 146+ return implode( ', ', $rights );
 147+ }
 148+
 149+ public function getAllGroups() {
 150+ $result = array();
 151+ foreach ( CentralAuthUser::availableGlobalGroups() as $group ) {
 152+ $result[$group] = User::getGroupName( $group );
 153+ }
 154+ return $result;
 155+ }
 156+}
Property changes on: trunk/extensions/CentralAuth/specials/SpecialGlobalUsers.php
___________________________________________________________________
Added: svn:eol-style
1157 + native
Index: trunk/extensions/CentralAuth/specials/SpecialWikiSets.php
@@ -0,0 +1,293 @@
 2+<?php
 3+/**
 4+ * Special page to allow to edit "wikisets" which are used to restrict
 5+ * specific global group permissions to certain wikis.
 6+ *
 7+ * @file
 8+ * @ingroup Extensions
 9+ */
 10+
 11+if ( !defined( 'MEDIAWIKI' ) ) {
 12+ echo "CentralAuth extension\n";
 13+ exit( 1 );
 14+}
 15+
 16+
 17+class SpecialWikiSets extends SpecialPage {
 18+ var $mCanEdit;
 19+
 20+ function __construct() {
 21+ parent::__construct( 'WikiSets' );
 22+ }
 23+
 24+ function getDescription() {
 25+ return wfMsg( 'centralauth-editset' );
 26+ }
 27+
 28+ function execute( $subpage ) {
 29+ global $wgRequest, $wgOut, $wgUser;
 30+
 31+ $this->mCanEdit = $wgUser->isAllowed( 'globalgrouppermissions' );
 32+
 33+ $this->setHeaders();
 34+
 35+ if ( strpos( $subpage, 'delete/' ) === 0 && $this->mCanEdit ) {
 36+ $subpage = substr( $subpage, 7 ); // Remove delete/ part
 37+ if ( is_numeric( $subpage ) ) {
 38+ if ( $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ) )
 39+ $this->doDelete( $subpage );
 40+ else
 41+ $this->buildDeleteView( $subpage );
 42+ } else {
 43+ $this->buildMainView();
 44+ }
 45+ } else {
 46+ if ( $subpage ) {
 47+ $set = is_numeric( $subpage ) ? WikiSet::newFromId( $subpage ) : WikiSet::newFromName( $subpage );
 48+ if ( $set ) {
 49+ $subpage = $set->getID();
 50+ } else {
 51+ $wgOut->setPageTitle( wfMsg( 'error' ) );
 52+ $error = wfMsgExt( 'centralauth-editset-notfound', array( 'escapenoentities' ), $subpage );
 53+ $this->buildMainView( "<strong class='error'>{$error}</strong>" );
 54+ return;
 55+ }
 56+ }
 57+
 58+ if ( ( $subpage || $subpage === '0' ) && $this->mCanEdit && $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ) ) {
 59+ $this->doSubmit( $subpage );
 60+ } else if ( ( $subpage || $subpage === '0' ) && is_numeric( $subpage ) ) {
 61+ $this->buildSetView( $subpage );
 62+ } else {
 63+ $this->buildMainView();
 64+ }
 65+ }
 66+ }
 67+
 68+ function buildMainView( $msg = '' ) {
 69+ global $wgOut, $wgUser;
 70+ $sk = $wgUser->getSkin();
 71+
 72+ $msgPostfix = $this->mCanEdit ? 'rw' : 'ro';
 73+ $legend = wfMsg( "centralauth-editset-legend-{$msgPostfix}" );
 74+ $wgOut->addHTML( "<fieldset><legend>{$legend}</legend>" );
 75+ if ( $msg )
 76+ $wgOut->addHTML( $msg );
 77+ $wgOut->addWikiMsg( "centralauth-editset-intro-{$msgPostfix}" );
 78+ $wgOut->addHTML( '<ul>' );
 79+
 80+ $sets = WikiSet::getAllWikiSets();
 81+ foreach ( $sets as $set ) {
 82+ $text = wfMsgExt( "centralauth-editset-item-{$msgPostfix}", array( 'parseinline' ), $set->getName(), $set->getID() );
 83+ $wgOut->addHTML( "<li>{$text}</li>" );
 84+ }
 85+
 86+ if ( $this->mCanEdit ) {
 87+ $target = SpecialPage::getTitleFor( 'WikiSets', '0' );
 88+ $newlink = $sk->makeLinkObj( $target, wfMsgHtml( 'centralauth-editset-new' ) );
 89+ $wgOut->addHTML( "<li>{$newlink}</li>" );
 90+ }
 91+
 92+ $wgOut->addHTML( '</ul></fieldset>' );
 93+ }
 94+
 95+ function buildSetView( $subpage, $error = false, $name = null, $type = null, $wikis = null, $reason = null ) {
 96+ global $wgOut, $wgUser;
 97+
 98+ $wgOut->setSubtitle( wfMsgExt( 'centralauth-editset-subtitle', 'parseinline' ) );
 99+
 100+ $set = $subpage ? WikiSet::newFromID( $subpage ) : null;
 101+ if ( !$name ) $name = $set ? $set->getName() : '';
 102+ if ( !$type ) $type = $set ? $set->getType() : WikiSet::OPTIN;
 103+ if ( !$wikis ) $wikis = implode( "\n", $set ? $set->getWikisRaw() : array() );
 104+ else $wikis = implode( "\n", $wikis );
 105+ $url = SpecialPage::getTitleFor( 'WikiSets', $subpage )->getLocalUrl();
 106+ if ( $this->mCanEdit ) {
 107+ $legend = wfMsgHtml( 'centralauth-editset-legend-' . ( $set ? 'edit' : 'new' ), $name );
 108+ } else {
 109+ $legend = wfMsgHtml( 'centralauth-editset-legend-view', $name );
 110+ }
 111+
 112+ $wgOut->addHTML( "<fieldset><legend>{$legend}</legend>" );
 113+
 114+ if ( $set ) {
 115+ $groups = $set->getRestrictedGroups();
 116+ if ( $groups ) {
 117+ $usage = "<ul>\n";
 118+ foreach ( $groups as $group )
 119+ $usage .= "<li>" . wfMsgExt( 'centralauth-editset-grouplink', 'parseinline', $group ) . "</li>\n";
 120+ $usage .= "</ul>";
 121+ } else {
 122+ $usage = wfMsgExt( 'centralauth-editset-nouse', 'parse' );
 123+ }
 124+ } else {
 125+ $usage = '';
 126+ }
 127+
 128+ if ( $this->mCanEdit ) {
 129+ if ( $error ) {
 130+ $wgOut->addHTML( "<strong class='error'>{$error}</strong>" );
 131+ }
 132+ $wgOut->addHTML( "<form action='{$url}' method='post'>" );
 133+
 134+ $form = array();
 135+ $form['centralauth-editset-name'] = Xml::input( 'wpName', false, $name );
 136+ if ( $usage ) {
 137+ $form['centralauth-editset-usage'] = $usage;
 138+ }
 139+ $form['centralauth-editset-type'] = $this->buildTypeSelector( 'wpType', $type );
 140+ $form['centralauth-editset-wikis'] = Xml::textarea( 'wpWikis', $wikis );
 141+ $form['centralauth-editset-reason'] = Xml::input( 'wpReason', false, $reason );
 142+
 143+ $wgOut->addHTML( Xml::buildForm( $form, 'centralauth-editset-submit' ) );
 144+
 145+ $edittoken = Html::hidden( 'wpEditToken', $wgUser->editToken() );
 146+ $wgOut->addHTML( "<p>{$edittoken}</p></form></fieldset>" );
 147+ } else {
 148+ $form = array();
 149+ $form['centralauth-editset-name'] = htmlspecialchars( $name );
 150+ $form['centralauth-editset-usage'] = $usage;
 151+ $form['centralauth-editset-type'] = wfMsg( "centralauth-editset-{$type}" );
 152+ $form['centralauth-editset-wikis'] = $this->buildWikiList( $set->getWikisRaw() );
 153+
 154+ $wgOut->addHTML( Xml::buildForm( $form ) );
 155+ }
 156+ }
 157+
 158+ function buildTypeSelector( $name, $value ) {
 159+ $select = new XmlSelect( $name, 'set-type', $value );
 160+ foreach ( array( WikiSet::OPTIN, WikiSet::OPTOUT ) as $type ) {
 161+ $select->addOption( wfMsg( "centralauth-editset-{$type}" ), $type );
 162+ }
 163+ return $select->getHTML();
 164+ }
 165+
 166+ function buildWikiList( $list ) {
 167+ sort( $list );
 168+ $html = '<ul>';
 169+ foreach ( $list as $wiki ) {
 170+ $escWiki = htmlspecialchars( $wiki );
 171+ $html .= "<li>{$escWiki}</li>";
 172+ }
 173+ $html .= '</ul>';
 174+ return $html;
 175+ }
 176+
 177+ function buildDeleteView( $subpage ) {
 178+ global $wgOut, $wgUser;
 179+ $wgOut->setSubtitle( wfMsgExt( 'centralauth-editset-subtitle', 'parseinline' ) );
 180+
 181+ $set = WikiSet::newFromID( $subpage );
 182+ if ( !$set ) {
 183+ $this->buildMainView( '<strong class="error">' . wfMsgHtml( 'centralauth-editset-notfound', $subpage ) . '</strong>' );
 184+ return;
 185+ }
 186+
 187+ $legend = wfMsgHtml( 'centralauth-editset-legend-delete', $set->getName() );
 188+ $form = array( 'centralauth-editset-reason' => Xml::input( 'wpReason' ) );
 189+ $url = htmlspecialchars( SpecialPage::getTitleFor( 'WikiSets', "delete/{$subpage}" )->getLocalUrl() );
 190+ $edittoken = Html::hidden( 'wpEditToken', $wgUser->editToken() );
 191+
 192+ $wgOut->addHTML( "<fieldset><legend>{$legend}</legend><form action='{$url}' method='post'>" );
 193+ $wgOut->addHTML( Xml::buildForm( $form, 'centralauth-editset-submit-delete' ) );
 194+ $wgOut->addHTML( "<p>{$edittoken}</p></form></fieldset>" );
 195+ }
 196+
 197+ function doSubmit( $id ) {
 198+ global $wgRequest, $wgContLang;
 199+
 200+ $name = $wgContLang->ucfirst( $wgRequest->getVal( 'wpName' ) );
 201+ $type = $wgRequest->getVal( 'wpType' );
 202+ $wikis = array_unique( preg_split( '/(\s+|\s*\W\s*)/', $wgRequest->getVal( 'wpWikis' ), -1, PREG_SPLIT_NO_EMPTY ) );
 203+ $reason = $wgRequest->getVal( 'wpReason' );
 204+ $set = WikiSet::newFromId( $id );
 205+
 206+ if ( !Title::newFromText( $name ) ) {
 207+ $this->buildSetView( $id, wfMsgHtml( 'centralauth-editset-badname' ), $name, $type, $wikis, $reason );
 208+ return;
 209+ }
 210+ if ( ( !$id || $set->getName() != $name ) && WikiSet::newFromName( $name ) ) {
 211+ $this->buildSetView( $id, wfMsgHtml( 'centralauth-editset-setexists' ), $name, $type, $wikis, $reason );
 212+ return;
 213+ }
 214+ if ( !in_array( $type, array( WikiSet::OPTIN, WikiSet::OPTOUT ) ) ) {
 215+ $this->buildSetView( $id, wfMsgHtml( 'centralauth-editset-badtype' ), $name, $type, $wikis, $reason );
 216+ return;
 217+ }
 218+ if ( !$wikis ) {
 219+ $this->buildSetView( $id, wfMsgHtml( 'centralauth-editset-nowikis' ), $name, $type, $wikis, $reason );
 220+ return;
 221+ }
 222+ $badwikis = array();
 223+ $allwikis = CentralAuthUser::getWikiList();
 224+ foreach ( $wikis as $wiki ) {
 225+ if ( !in_array( $wiki, $allwikis ) ) {
 226+ $badwikis[] = $wiki;
 227+ }
 228+ }
 229+ if ( $badwikis ) {
 230+ $this->buildSetView( $id, wfMsgExt( 'centralauth-editset-badwikis', array( 'escapenoentities', 'parsemag' ),
 231+ implode( ', ', $badwikis ), count( $badwikis ) ), $name, $type, $wikis, $reason );
 232+ return;
 233+ }
 234+
 235+ if ( $set ) {
 236+ $oldname = $set->getName();
 237+ $oldtype = $set->getType();
 238+ $oldwikis = $set->getWikisRaw();
 239+ } else {
 240+ $set = new WikiSet();
 241+ $oldname = $oldtype = null; $oldwikis = array();
 242+ }
 243+ $set->setName( $name );
 244+ $set->setType( $type );
 245+ $set->setWikisRaw( $wikis );
 246+ $set->commit();
 247+
 248+ // Now logging
 249+ $log = new LogPage( 'gblrights' );
 250+ $title = SpecialPage::getTitleFor( 'WikiSets', $set->getID() );
 251+ if ( !$oldname ) {
 252+ // New set
 253+ $log->addEntry( 'newset', $title, $reason, array( $name, $type, implode( ', ', $wikis ) ) );
 254+ } else {
 255+ if ( $oldname != $name ) {
 256+ $log->addEntry( 'setrename', $title, $reason, array( $name, $oldname ) );
 257+ }
 258+ if ( $oldtype != $type ) {
 259+ $log->addEntry( 'setnewtype', $title, $reason, array( $name, $oldtype, $type ) );
 260+ }
 261+ $added = implode( ', ', array_diff( $wikis, $oldwikis ) );
 262+ $removed = implode( ', ', array_diff( $oldwikis, $wikis ) );
 263+ if ( $added || $removed ) {
 264+ $log->addEntry( 'setchange', $title, $reason, array( $name, $added, $removed ) );
 265+ }
 266+ }
 267+
 268+ global $wgUser, $wgOut;
 269+ $sk = $wgUser->getSkin();
 270+ $returnLink = $sk->makeKnownLinkObj( $this->getTitle(), wfMsg( 'centralauth-editset-return' ) );
 271+
 272+ $wgOut->addHTML( '<strong class="success">' . wfMsgHtml( 'centralauth-editset-success' ) . '</strong> <p>' . $returnLink . '</p>' );
 273+ }
 274+
 275+ function doDelete( $set ) {
 276+ global $wgRequest;
 277+
 278+ $set = WikiSet::newFromID( $set );
 279+ if ( !$set ) {
 280+ $this->buildMainView( '<strong class="error">' . wfMsgHtml( 'centralauth-editset-notfound', $subpage ) . '</strong>' );
 281+ return;
 282+ }
 283+
 284+ $reason = $wgRequest->getVal( 'wpReason' );
 285+ $name = $set->getName();
 286+ $set->delete();
 287+
 288+ $title = SpecialPage::getTitleFor( 'WikiSets', $set->getID() );
 289+ $log = new LogPage( 'gblrights' );
 290+ $log->addEntry( 'deleteset', $title, $reason, array( $name ) );
 291+
 292+ $this->buildMainView( '<strong class="success">' . wfMsg( 'centralauth-editset-success-delete' ) . '</strong>' );
 293+ }
 294+}
Property changes on: trunk/extensions/CentralAuth/specials/SpecialWikiSets.php
___________________________________________________________________
Added: svn:mergeinfo
1295 Merged /branches/wmf/1.17wmf1/extensions/CentralAuth/SpecialWikiSets.php:r81956
Added: svn:eol-style
2296 + native

Status & tagging log