r83909 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r83908‎ | r83909 | r83910 >
Date:16:09, 14 March 2011
Author:happy-melon
Status:resolved (Comments)
Tags:
Comment:
Complete the trinity of blocking frontend interfaces by rewriting SpecialIpblocklist:
* Move and rename to SpecialBlockList
* Use an HTMLForm in GET mode for the options form
* Use TablePager to organise the results more nicely
* Standardise the filtration for IPs and IP ranges, so looking at blocks for a range will now also show rangeblocks which contain the range
* General tidy up
Modified paths:
  • /trunk/extensions/CheckUser/CheckUser_body.php (modified) (history)
  • /trunk/phase3/includes/AutoLoader.php (modified) (history)
  • /trunk/phase3/includes/DefaultSettings.php (modified) (history)
  • /trunk/phase3/includes/Pager.php (modified) (history)
  • /trunk/phase3/includes/SpecialPage.php (modified) (history)
  • /trunk/phase3/includes/specials/SpecialBlock.php (modified) (history)
  • /trunk/phase3/includes/specials/SpecialBlockList.php (added) (history)
  • /trunk/phase3/includes/specials/SpecialIpblocklist.php (deleted) (history)
  • /trunk/phase3/languages/messages/MessagesEn.php (modified) (history)
  • /trunk/phase3/maintenance/language/messages.inc (modified) (history)
  • /trunk/phase3/resources/mediawiki.special/mediawiki.special.css (modified) (history)

Diff [purge]

Index: trunk/phase3/maintenance/language/messages.inc
@@ -2086,15 +2086,20 @@
20872087 'unblocked-id',
20882088 'ipblocklist',
20892089 'ipblocklist-legend',
2090 - 'ipblocklist-username',
2091 - 'ipblocklist-sh-userblocks',
2092 - 'ipblocklist-sh-tempblocks',
2093 - 'ipblocklist-sh-addressblocks',
 2090+ 'blocklist-userblocks',
 2091+ 'blocklist-tempblocks',
 2092+ 'blocklist-addressblocks',
 2093+ 'blocklist-timestamp',
 2094+ 'blocklist-target',
 2095+ 'blocklist-expiry',
 2096+ 'blocklist-by',
 2097+ 'blocklist-params',
 2098+ 'blocklist-reason',
20942099 'ipblocklist-summary',
20952100 'ipblocklist-submit',
20962101 'ipblocklist-localblock',
20972102 'ipblocklist-otherblocks',
2098 - 'blocklistline',
 2103+
20992104 'infiniteblock',
21002105 'expiringblock',
21012106 'anononlyblock',
Index: trunk/phase3/includes/AutoLoader.php
@@ -603,8 +603,8 @@
604604 'FewestrevisionsPage' => 'includes/specials/SpecialFewestrevisions.php',
605605 'FileDuplicateSearchPage' => 'includes/specials/SpecialFileDuplicateSearch.php',
606606 'IPBlockForm' => 'includes/specials/SpecialBlock.php',
607 - 'IPBlocklistPager' => 'includes/specials/SpecialIpblocklist.php',
608 - 'IPUnblockForm' => 'includes/specials/SpecialIpblocklist.php',
 607+ 'BlockListPager' => 'includes/specials/SpecialBlockList.php',
 608+ 'SpecialBlockList' => 'includes/specials/SpecialBlockList.php',
609609 'ImportReporter' => 'includes/specials/SpecialImport.php',
610610 'ImportStreamSource' => 'includes/Import.php',
611611 'ImportStringSource' => 'includes/Import.php',
Index: trunk/phase3/includes/DefaultSettings.php
@@ -4948,7 +4948,7 @@
49494949 'Listusers' => 'users',
49504950 'Activeusers' => 'users',
49514951 'Listgrouprights' => 'users',
4952 - 'Ipblocklist' => 'users',
 4952+ 'BlockList' => 'users',
49534953 'Contributions' => 'users',
49544954 'Emailuser' => 'users',
49554955 'Listadmins' => 'users',
Index: trunk/phase3/includes/specials/SpecialIpblocklist.php
@@ -1,383 +0,0 @@
2 -<?php
3 -/**
4 - * Implements Special:ipblocklist
5 - *
6 - * This program is free software; you can redistribute it and/or modify
7 - * it under the terms of the GNU General Public License as published by
8 - * the Free Software Foundation; either version 2 of the License, or
9 - * (at your option) any later version.
10 - *
11 - * This program is distributed in the hope that it will be useful,
12 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 - * GNU General Public License for more details.
15 - *
16 - * You should have received a copy of the GNU General Public License along
17 - * with this program; if not, write to the Free Software Foundation, Inc.,
18 - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 - * http://www.gnu.org/copyleft/gpl.html
20 - *
21 - * @file
22 - * @ingroup SpecialPage
23 - */
24 -
25 -/**
26 - * A special page that lists existing blocks and allows users with the 'block'
27 - * permission to remove blocks
28 - *
29 - * @ingroup SpecialPage
30 - */
31 -class IPUnblockForm extends SpecialPage {
32 - var $ip;
33 - var $hideuserblocks, $hidetempblocks, $hideaddressblocks;
34 -
35 - function __construct() {
36 - parent::__construct( 'Ipblocklist' );
37 - }
38 -
39 - /**
40 - * Main execution point
41 - *
42 - * @param $ip part of title: Special:Ipblocklist/<ip>.
43 - */
44 - function execute( $ip ) {
45 - global $wgUser, $wgOut, $wgRequest;
46 -
47 - $this->setHeaders();
48 - $this->outputHeader();
49 -
50 - $ip = $wgRequest->getVal( 'ip', $ip );
51 - $this->ip = trim( $wgRequest->getVal( 'wpUnblockAddress', $ip ) );
52 - $this->hideuserblocks = $wgRequest->getBool( 'hideuserblocks' );
53 - $this->hidetempblocks = $wgRequest->getBool( 'hidetempblocks' );
54 - $this->hideaddressblocks = $wgRequest->getBool( 'hideaddressblocks' );
55 -
56 - $action = $wgRequest->getText( 'action' );
57 -
58 - if( $action == 'unblock' || $action == 'submit' && $wgRequest->wasPosted() ) {
59 - # B/C @since 1.18: Unblock interface is now at Special:Unblock
60 - $title = SpecialPage::getTitleFor( 'Unblock', $this->ip );
61 - $wgOut->redirect( $title->getFullUrl() );
62 - return;
63 - } else {
64 - # Just show the block list
65 - $this->showList( '' );
66 - }
67 - }
68 -
69 - function showList( $msg ) {
70 - global $wgOut, $wgUser;
71 -
72 - if ( $msg != '' ) {
73 - $wgOut->setSubtitle( $msg );
74 - }
75 -
76 - // Purge expired entries on one in every 10 queries
77 - if ( !mt_rand( 0, 10 ) ) {
78 - Block::purgeExpired();
79 - }
80 -
81 - $conds = array();
82 - // Is user allowed to see all the blocks?
83 - if ( !$wgUser->isAllowed( 'hideuser' ) )
84 - $conds['ipb_deleted'] = 0;
85 - if ( $this->ip == '' ) {
86 - // No extra conditions
87 - } elseif ( substr( $this->ip, 0, 1 ) == '#' ) {
88 - $conds['ipb_id'] = substr( $this->ip, 1 );
89 - // Single IPs
90 - } elseif ( IP::isIPAddress( $this->ip ) && strpos( $this->ip, '/' ) === false ) {
91 - $iaddr = IP::toHex( $this->ip );
92 - if( $iaddr ) {
93 - # Only scan ranges which start in this /16, this improves search speed
94 - # Blocks should not cross a /16 boundary.
95 - $range = substr( $iaddr, 0, 4 );
96 - // Fixme -- encapsulate this sort of query-building.
97 - $dbr = wfGetDB( DB_SLAVE );
98 - $encIp = $dbr->addQuotes( IP::sanitizeIP( $this->ip ) );
99 - $encAddr = $dbr->addQuotes( $iaddr );
100 - $conds[] = "(ipb_address = $encIp) OR
101 - (ipb_range_start" . $dbr->buildLike( $range, $dbr->anyString() ) . " AND
102 - ipb_range_start <= $encAddr
103 - AND ipb_range_end >= $encAddr)";
104 - } else {
105 - $conds['ipb_address'] = IP::sanitizeIP( $this->ip );
106 - }
107 - $conds['ipb_auto'] = 0;
108 - // IP range
109 - } elseif ( IP::isIPAddress( $this->ip ) ) {
110 - $conds['ipb_address'] = Block::normaliseRange( $this->ip );
111 - $conds['ipb_auto'] = 0;
112 - } else {
113 - $user = User::newFromName( $this->ip );
114 - if ( $user && ( $id = $user->getId() ) != 0 ) {
115 - $conds['ipb_user'] = $id;
116 - } else {
117 - // Uh...?
118 - $conds['ipb_address'] = $this->ip;
119 - $conds['ipb_auto'] = 0;
120 - }
121 - }
122 - // Apply filters
123 - if( $this->hideuserblocks ) {
124 - $conds['ipb_user'] = 0;
125 - }
126 - if( $this->hidetempblocks ) {
127 - $conds['ipb_expiry'] = 'infinity';
128 - }
129 - if( $this->hideaddressblocks ) {
130 - $conds[] = "ipb_user != 0 OR ipb_range_end > ipb_range_start";
131 - }
132 -
133 - // Search form
134 - $wgOut->addHTML( $this->searchForm() );
135 -
136 - // Check for other blocks, i.e. global/tor blocks
137 - $otherBlockLink = array();
138 - wfRunHooks( 'OtherBlockLogLink', array( &$otherBlockLink, $this->ip ) );
139 -
140 - // Show additional header for the local block only when other blocks exists.
141 - // Not necessary in a standard installation without such extensions enabled
142 - if( count( $otherBlockLink ) ) {
143 - $wgOut->addHTML(
144 - Html::rawElement( 'h2', array(), wfMsg( 'ipblocklist-localblock' ) ) . "\n"
145 - );
146 - }
147 - $pager = new IPBlocklistPager( $this, $conds );
148 - if ( $pager->getNumRows() ) {
149 - $wgOut->addHTML(
150 - $pager->getNavigationBar() .
151 - Html::rawElement( 'ul', null, $pager->getBody() ) .
152 - $pager->getNavigationBar()
153 - );
154 - } elseif ( $this->ip != '') {
155 - $wgOut->addWikiMsg( 'ipblocklist-no-results' );
156 - } else {
157 - $wgOut->addWikiMsg( 'ipblocklist-empty' );
158 - }
159 -
160 - if( count( $otherBlockLink ) ) {
161 - $wgOut->addHTML(
162 - Html::rawElement( 'h2', array(), wfMsgExt( 'ipblocklist-otherblocks', 'parseinline', count( $otherBlockLink ) ) ) . "\n"
163 - );
164 - $list = '';
165 - foreach( $otherBlockLink as $link ) {
166 - $list .= Html::rawElement( 'li', array(), $link ) . "\n";
167 - }
168 - $wgOut->addHTML( Html::rawElement( 'ul', array( 'class' => 'mw-ipblocklist-otherblocks' ), $list ) . "\n" );
169 - }
170 -
171 - }
172 -
173 - function searchForm() {
174 - global $wgScript, $wgLang;
175 -
176 - $showhide = array( wfMsg( 'show' ), wfMsg( 'hide' ) );
177 - $nondefaults = array();
178 - if( $this->hideuserblocks ) {
179 - $nondefaults['hideuserblocks'] = $this->hideuserblocks;
180 - }
181 - if( $this->hidetempblocks ) {
182 - $nondefaults['hidetempblocks'] = $this->hidetempblocks;
183 - }
184 - if( $this->hideaddressblocks ) {
185 - $nondefaults['hideaddressblocks'] = $this->hideaddressblocks;
186 - }
187 - $ubLink = $this->makeOptionsLink( $showhide[1-$this->hideuserblocks],
188 - array( 'hideuserblocks' => 1-$this->hideuserblocks ), $nondefaults);
189 - $tbLink = $this->makeOptionsLink( $showhide[1-$this->hidetempblocks],
190 - array( 'hidetempblocks' => 1-$this->hidetempblocks ), $nondefaults);
191 - $sipbLink = $this->makeOptionsLink( $showhide[1-$this->hideaddressblocks],
192 - array( 'hideaddressblocks' => 1-$this->hideaddressblocks ), $nondefaults);
193 -
194 - $links = array();
195 - $links[] = wfMsgHtml( 'ipblocklist-sh-userblocks', $ubLink );
196 - $links[] = wfMsgHtml( 'ipblocklist-sh-tempblocks', $tbLink );
197 - $links[] = wfMsgHtml( 'ipblocklist-sh-addressblocks', $sipbLink );
198 - $hl = $wgLang->pipeList( $links );
199 -
200 - return
201 - Html::rawElement( 'form', array( 'action' => $wgScript ),
202 - Html::hidden( 'title', $this->getTitle()->getPrefixedDbKey() ) .
203 - Html::openElement( 'fieldset' ) .
204 - Html::element( 'legend', null, wfMsg( 'ipblocklist-legend' ) ) .
205 - Xml::inputLabel( wfMsg( 'ipblocklist-username' ), 'ip', 'ip', /* size */ false, $this->ip ) .
206 - '&#160;' .
207 - Xml::submitButton( wfMsg( 'ipblocklist-submit' ) ) . '<br />' .
208 - $hl .
209 - Html::closeElement( 'fieldset' )
210 - );
211 - }
212 -
213 - /**
214 - * Makes change an option link which carries all the other options
215 - *
216 - * @param $title see Title
217 - * @param $override Array: special query string options, will override the
218 - * ones in $options
219 - * @param $options Array: query string options
220 - * @param $active Boolean: whether to display the link in bold
221 - */
222 - function makeOptionsLink( $title, $override, $options, $active = false ) {
223 - global $wgUser;
224 - $sk = $wgUser->getSkin();
225 - $params = $override + $options;
226 - return $sk->link( $this->getTitle(), htmlspecialchars( $title ),
227 - ( $active ? array( 'style'=>'font-weight: bold;' ) : array() ), $params, array( 'known' ) );
228 - }
229 -
230 - /**
231 - * Callback function to output a block
232 - *
233 - * @param $block Block
234 - */
235 - function formatRow( $block ) {
236 - global $wgUser, $wgLang, $wgBlockAllowsUTEdit;
237 -
238 - wfProfileIn( __METHOD__ );
239 -
240 - static $sk=null, $msg=null;
241 -
242 - if( is_null( $sk ) )
243 - $sk = $wgUser->getSkin();
244 - if( is_null( $msg ) ) {
245 - $msg = array();
246 - $keys = array( 'infiniteblock', 'expiringblock', 'unblocklink', 'change-blocklink',
247 - 'anononlyblock', 'createaccountblock', 'noautoblockblock', 'emailblock', 'blocklist-nousertalk', 'blocklistline' );
248 - foreach( $keys as $key ) {
249 - $msg[$key] = wfMsgHtml( $key );
250 - }
251 - }
252 -
253 - # Prepare links to the blocker's user and talk pages
254 - $blocker_id = $block->getBy();
255 - $blocker_name = $block->getByName();
256 - $blocker = $sk->userLink( $blocker_id, $blocker_name );
257 - $blocker .= $sk->userToolLinks( $blocker_id, $blocker_name );
258 -
259 - # Prepare links to the block target's user and contribs. pages (as applicable, don't do it for autoblocks)
260 - if( $block->mAuto ) {
261 - $target = $block->getRedactedName(); # Hide the IP addresses of auto-blocks; privacy
262 - } else {
263 - $target = $sk->userLink( $block->mUser, $block->mAddress )
264 - . $sk->userToolLinks( $block->mUser, $block->mAddress, false, Linker::TOOL_LINKS_NOBLOCK );
265 - }
266 -
267 - $formattedTime = htmlspecialchars( $wgLang->timeanddate( $block->mTimestamp, true ) );
268 -
269 - $properties = array();
270 - $properties[] = Block::formatExpiry( $block->mExpiry );
271 - if ( $block->mAnonOnly ) {
272 - $properties[] = $msg['anononlyblock'];
273 - }
274 - if ( $block->mCreateAccount ) {
275 - $properties[] = $msg['createaccountblock'];
276 - }
277 - if (!$block->mEnableAutoblock && $block->mUser ) {
278 - $properties[] = $msg['noautoblockblock'];
279 - }
280 -
281 - if ( $block->mBlockEmail && $block->mUser ) {
282 - $properties[] = $msg['emailblock'];
283 - }
284 -
285 - if ( !$block->mAllowUsertalk && $wgBlockAllowsUTEdit ) {
286 - $properties[] = $msg['blocklist-nousertalk'];
287 - }
288 -
289 - $properties = $wgLang->commaList( $properties );
290 -
291 - $line = wfMsgReplaceArgs( $msg['blocklistline'], array( $formattedTime, $blocker, $target, $properties ) );
292 -
293 - $changeblocklink = '';
294 - $toolLinks = '';
295 - if ( $wgUser->isAllowed( 'block' ) ) {
296 - $unblocklink = $sk->link( $this->getTitle(),
297 - $msg['unblocklink'],
298 - array(),
299 - array( 'action' => 'unblock', 'id' => $block->mId ),
300 - 'known' );
301 -
302 - # Create changeblocklink for all blocks with exception of autoblocks
303 - if( !$block->mAuto ) {
304 - $changeblocklink = wfMsgExt( 'pipe-separator', 'escapenoentities' ) .
305 - $sk->link( SpecialPage::getTitleFor( 'Block', $block->mAddress ),
306 - $msg['change-blocklink'],
307 - array(), array(), 'known' );
308 - }
309 - $toolLinks = "($unblocklink$changeblocklink)";
310 - }
311 -
312 - $comment = $sk->commentBlock( htmlspecialchars($block->mReason) );
313 -
314 - $s = "{$line} $comment";
315 - if ( $block->mHideName )
316 - $s = '<span class="history-deleted">' . $s . '</span>';
317 -
318 - wfProfileOut( __METHOD__ );
319 - return "<li>$s $toolLinks</li>\n";
320 - }
321 -}
322 -
323 -/**
324 - * @todo document
325 - * @ingroup Pager
326 - */
327 -class IPBlocklistPager extends ReverseChronologicalPager {
328 - public $mForm, $mConds;
329 -
330 - function __construct( $form, $conds = array() ) {
331 - $this->mForm = $form;
332 - $this->mConds = $conds;
333 - parent::__construct();
334 - }
335 -
336 - function getStartBody() {
337 - wfProfileIn( __METHOD__ );
338 - # Do a link batch query
339 - $this->mResult->seek( 0 );
340 - $lb = new LinkBatch;
341 -
342 - /*
343 - while ( $row = $this->mResult->fetchObject() ) {
344 - $lb->addObj( Title::makeTitleSafe( NS_USER, $row->user_name ) );
345 - $lb->addObj( Title::makeTitleSafe( NS_USER_TALK, $row->user_name ) );
346 - $lb->addObj( Title::makeTitleSafe( NS_USER, $row->ipb_address ) );
347 - $lb->addObj( Title::makeTitleSafe( NS_USER_TALK, $row->ipb_address ) );
348 - }*/
349 - # Faster way
350 - # Usernames and titles are in fact related by a simple substitution of space -> underscore
351 - # The last few lines of Title::secureAndSplit() tell the story.
352 - foreach ( $this->mResult as $row ) {
353 - $name = str_replace( ' ', '_', $row->ipb_by_text );
354 - $lb->add( NS_USER, $name );
355 - $lb->add( NS_USER_TALK, $name );
356 - $name = str_replace( ' ', '_', $row->ipb_address );
357 - $lb->add( NS_USER, $name );
358 - $lb->add( NS_USER_TALK, $name );
359 - }
360 - $lb->execute();
361 - wfProfileOut( __METHOD__ );
362 - return '';
363 - }
364 -
365 - function formatRow( $row ) {
366 - $block = new Block;
367 - $block->initFromRow( $row );
368 - return $this->mForm->formatRow( $block );
369 - }
370 -
371 - function getQueryInfo() {
372 - $conds = $this->mConds;
373 - $conds[] = 'ipb_expiry>' . $this->mDb->addQuotes( $this->mDb->timestamp() );
374 - return array(
375 - 'tables' => 'ipblocks',
376 - 'fields' => '*',
377 - 'conds' => $conds,
378 - );
379 - }
380 -
381 - function getIndexField() {
382 - return 'ipb_timestamp';
383 - }
384 -}
Index: trunk/phase3/includes/specials/SpecialBlockList.php
@@ -0,0 +1,424 @@
 2+<?php
 3+/**
 4+ * Implements Special:BlockList
 5+ *
 6+ * This program is free software; you can redistribute it and/or modify
 7+ * it under the terms of the GNU General Public License as published by
 8+ * the Free Software Foundation; either version 2 of the License, or
 9+ * (at your option) any later version.
 10+ *
 11+ * This program is distributed in the hope that it will be useful,
 12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 14+ * GNU General Public License for more details.
 15+ *
 16+ * You should have received a copy of the GNU General Public License along
 17+ * with this program; if not, write to the Free Software Foundation, Inc.,
 18+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 19+ * http://www.gnu.org/copyleft/gpl.html
 20+ *
 21+ * @file
 22+ * @ingroup SpecialPage
 23+ */
 24+
 25+/**
 26+ * A special page that lists existing blocks
 27+ *
 28+ * @ingroup SpecialPage
 29+ */
 30+class SpecialBlockList extends SpecialPage {
 31+
 32+ protected $target, $options;
 33+
 34+ function __construct() {
 35+ parent::__construct( 'BlockList' );
 36+ }
 37+
 38+ /**
 39+ * Main execution point
 40+ *
 41+ * @param $par String title fragment
 42+ */
 43+ public function execute( $par ) {
 44+ global $wgUser, $wgOut, $wgRequest;
 45+
 46+ $this->setHeaders();
 47+ $this->outputHeader();
 48+ $wgOut->setPageTitle( wfMsg( 'ipblocklist' ) );
 49+ $wgOut->addModuleStyles( 'mediawiki.special' );
 50+
 51+ $par = $wgRequest->getVal( 'ip', $par );
 52+ $this->target = trim( $wgRequest->getVal( 'wpTarget', $par ) );
 53+
 54+ $this->options = $wgRequest->getArray( 'wpOptions' );
 55+
 56+ $action = $wgRequest->getText( 'action' );
 57+
 58+ if( $action == 'unblock' || $action == 'submit' && $wgRequest->wasPosted() ) {
 59+ # B/C @since 1.18: Unblock interface is now at Special:Unblock
 60+ $title = SpecialPage::getTitleFor( 'Unblock', $this->target );
 61+ $wgOut->redirect( $title->getFullUrl() );
 62+ return;
 63+ }
 64+
 65+ # Just show the block list
 66+ $fields = array(
 67+ 'Target' => array(
 68+ 'type' => 'text',
 69+ 'label-message' => 'ipaddressorusername',
 70+ 'tabindex' => '1',
 71+ 'size' => '45',
 72+ ),
 73+ 'Options' => array(
 74+ 'type' => 'multiselect',
 75+ 'options' => array(
 76+ wfMsg( 'blocklist-userblocks' ) => 'userblocks',
 77+ wfMsg( 'blocklist-tempblocks' ) => 'tempblocks',
 78+ wfMsg( 'blocklist-addressblocks' ) => 'addressblocks',
 79+ ),
 80+ 'cssclass' => 'mw-htmlform-multiselect-flatlist',
 81+ ),
 82+ );
 83+ $form = new HTMLForm( $fields );
 84+ $form->setTitle( $this->getTitle() );
 85+ $form->setMethod( 'get' );
 86+ $form->setWrapperLegend( wfMsg( 'ipblocklist-legend' ) );
 87+ $form->setSubmitText( wfMsg( 'ipblocklist-submit' ) );
 88+ $form->prepareForm();
 89+
 90+ $form->displayForm( '' );
 91+ $this->showList();
 92+ }
 93+
 94+ /**
 95+ * Get the component of an IP address which is certain to be the same between an IP
 96+ * address and a rangeblock containing that IP address.
 97+ * @todo: should be in IP.php??
 98+ * @param $ip String
 99+ * @return String
 100+ */
 101+ protected static function getIpFragment( $ip ){
 102+ global $wgBlockCIDRLimit;
 103+ if( IP::isIPv4( $ip ) ){
 104+ $hexAddress = IP::toHex( $ip );
 105+ return substr( $hexAddress, 0, wfBaseconvert( $wgBlockCIDRLimit['IPv4'], 10, 16 ) );
 106+ } elseif( IP::isIPv6( $ip ) ) {
 107+ $hexAddress = substr( IP::toHex( $ip ), 2 );
 108+ return 'v6-' . substr( $hexAddress, 0, wfBaseconvert( $wgBlockCIDRLimit['IPv6'], 10, 16 ) );
 109+ } else {
 110+ return null;
 111+ }
 112+ }
 113+
 114+ function showList() {
 115+ global $wgOut, $wgUser;
 116+
 117+ # Purge expired entries on one in every 10 queries
 118+ if ( !mt_rand( 0, 10 ) ) {
 119+ Block::purgeExpired();
 120+ }
 121+
 122+ $conds = array();
 123+ # Is the user allowed to see hidden blocks?
 124+ if ( !$wgUser->isAllowed( 'hideuser' ) ){
 125+ $conds['ipb_deleted'] = 0;
 126+ }
 127+
 128+ if ( $this->target !== '' ){
 129+ list( $target, $type ) = Block::parseTarget( $this->target );
 130+
 131+ switch( $type ){
 132+ case Block::TYPE_ID:
 133+ $conds['ipb_id'] = $target;
 134+ break;
 135+
 136+ case Block::TYPE_IP:
 137+ case BLock::TYPE_RANGE:
 138+ list( $start, $end ) = IP::parseRange( $target );
 139+ # Per bug 14634, we want to include relevant active rangeblocks; for
 140+ # rangeblocks, we want to include larger ranges which enclose the given
 141+ # range. We know that all blocks must be smaller than $wgBlockCIDRLimit,
 142+ # so we can improve performance by filtering on a LIKE clause
 143+ $chunk = self::getIpFragment( $start );
 144+ $dbr = wfGetDB( DB_SLAVE );
 145+ $like = $dbr->buildLike( $chunk, $dbr->anyString() );
 146+
 147+ # Fairly hard to make a malicious SQL statement out of hex characters,
 148+ # but stranger things have happened...
 149+ $safeStart = $dbr->addQuotes( IP::toHex( $start ) );
 150+ $safeEnd = $dbr->addQuotes( IP::toHex( $end ) );
 151+ $safeTarget = $dbr->addQuotes( IP::toHex( $target ) );
 152+
 153+ # TODO: abstract this away
 154+ $conds[] = "(ipb_address = $safeTarget) OR
 155+ (ipb_range_start $like AND ipb_range_start <= $safeStart AND ipb_range_end >= $safeEnd)";
 156+ $conds['ipb_auto'] = 0;
 157+ break;
 158+
 159+ case Block::TYPE_USER:
 160+ $conds['ipb_address'] = (string)$this->target;
 161+ $conds['ipb_auto'] = 0;
 162+ break;
 163+ }
 164+ }
 165+
 166+ # Apply filters
 167+ if( in_array( 'userblocks', $this->options ) ) {
 168+ $conds['ipb_user'] = 0;
 169+ }
 170+ if( in_array( 'tempblocks', $this->options ) ) {
 171+ $conds['ipb_expiry'] = 'infinity';
 172+ }
 173+ if( in_array( 'addressblocks', $this->options ) ) {
 174+ $conds[] = "ipb_user != 0 OR ipb_range_end > ipb_range_start";
 175+ }
 176+
 177+ # Check for other blocks, i.e. global/tor blocks
 178+ $otherBlockLink = array();
 179+ wfRunHooks( 'OtherBlockLogLink', array( &$otherBlockLink, $this->target ) );
 180+
 181+ # Show additional header for the local block only when other blocks exists.
 182+ # Not necessary in a standard installation without such extensions enabled
 183+ if( count( $otherBlockLink ) ) {
 184+ $wgOut->addHTML(
 185+ Html::rawElement( 'h2', array(), wfMsg( 'ipblocklist-localblock' ) ) . "\n"
 186+ );
 187+ }
 188+
 189+ $pager = new BlockListPager( $this, $conds );
 190+ if ( $pager->getNumRows() ) {
 191+ $wgOut->addHTML(
 192+ $pager->getNavigationBar() .
 193+ $pager->getBody().
 194+ $pager->getNavigationBar()
 195+ );
 196+
 197+ } elseif ( $this->target ) {
 198+ $wgOut->addWikiMsg( 'ipblocklist-no-results' );
 199+
 200+ } else {
 201+ $wgOut->addWikiMsg( 'ipblocklist-empty' );
 202+ }
 203+
 204+ if( count( $otherBlockLink ) ) {
 205+ $wgOut->addHTML(
 206+ Html::rawElement(
 207+ 'h2',
 208+ array(),
 209+ wfMsgExt(
 210+ 'ipblocklist-otherblocks',
 211+ 'parseinline',
 212+ count( $otherBlockLink )
 213+ )
 214+ ) . "\n"
 215+ );
 216+ $list = '';
 217+ foreach( $otherBlockLink as $link ) {
 218+ $list .= Html::rawElement( 'li', array(), $link ) . "\n";
 219+ }
 220+ $wgOut->addHTML( Html::rawElement( 'ul', array( 'class' => 'mw-ipblocklist-otherblocks' ), $list ) . "\n" );
 221+ }
 222+ }
 223+}
 224+
 225+class BlockListPager extends TablePager {
 226+ protected $conds;
 227+ protected $page;
 228+
 229+ function __construct( $page, $conds ) {
 230+ $this->page = $page;
 231+ $this->conds = $conds;
 232+ $this->mDefaultDirection = true;
 233+ parent::__construct();
 234+ }
 235+
 236+ function getFieldNames() {
 237+ global $wgUser;
 238+ static $headers = null;
 239+
 240+ if ( $headers == array() ) {
 241+ $headers = array(
 242+ 'ipb_timestamp' => 'blocklist-timestamp',
 243+ 'ipb_target' => 'blocklist-target',
 244+ 'ipb_expiry' => 'blocklist-expiry',
 245+ 'ipb_by' => 'blocklist-by',
 246+ 'ipb_params' => 'blocklist-params',
 247+ 'ipb_reason' => 'blocklist-reason',
 248+ );
 249+ $headers = array_map( 'wfMsg', $headers );
 250+ }
 251+
 252+ return $headers;
 253+ }
 254+
 255+ function formatValue( $name, $value ) {
 256+ global $wgOut, $wgLang, $wgUser;
 257+
 258+ static $sk, $msg;
 259+ if ( empty( $sk ) ) {
 260+ $sk = $wgUser->getSkin();
 261+ $msg = array(
 262+ 'anononlyblock',
 263+ 'createaccountblock',
 264+ 'noautoblockblock',
 265+ 'emailblock',
 266+ 'blocklist-nousertalk',
 267+ 'unblocklink',
 268+ 'change-blocklink',
 269+ );
 270+ $msg = array_combine( $msg, array_map( 'wfMessage', $msg ) );
 271+ }
 272+
 273+ $row = $this->mCurrentRow;
 274+ $formatted = '';
 275+
 276+ switch( $name ) {
 277+ case 'ipb_timestamp':
 278+ $formatted = $wgLang->timeanddate( $value );
 279+ break;
 280+
 281+ case 'ipb_target':
 282+ if( $row->ipb_auto ){
 283+ $formatted = wfMessage( 'autoblockid', $row->ipb_id );
 284+ } else {
 285+ list( $target, $type ) = Block::parseTarget( $row->ipb_address );
 286+ switch( $type ){
 287+ case Block::TYPE_USER:
 288+ case Block::TYPE_IP:
 289+ $formatted = $sk->userLink( $target->getId(), $target );
 290+ $formatted .= $sk->userToolLinks(
 291+ $target->getId(),
 292+ $target,
 293+ false,
 294+ Linker::TOOL_LINKS_NOBLOCK
 295+ );
 296+ break;
 297+ case Block::TYPE_RANGE:
 298+ $formatted = htmlspecialchars( $target );
 299+ }
 300+ }
 301+ break;
 302+
 303+ case 'ipb_expiry':
 304+ $formatted = $wgLang->timeanddate( $value );
 305+ if( $wgUser->isAllowed( 'block' ) ){
 306+ if( $row->ipb_auto ){
 307+ $links[] = $sk->linkKnown(
 308+ SpecialPage::getTitleFor( 'Unblock' ),
 309+ $msg['unblocklink'],
 310+ array(),
 311+ array( 'wpTarget' => "#{$row->ipb_id}" )
 312+ );
 313+ } else {
 314+ $links[] = $sk->linkKnown(
 315+ SpecialPage::getTitleFor( 'Unblock', $row->ipb_address ),
 316+ $msg['unblocklink']
 317+ );
 318+ $links[] = $sk->linkKnown(
 319+ SpecialPage::getTitleFor( 'Block', $row->ipb_address ),
 320+ $msg['change-blocklink']
 321+ );
 322+ }
 323+ $formatted .= ' ' . Html::rawElement(
 324+ 'span',
 325+ array( 'class' => 'mw-blocklist-actions' ),
 326+ "[{$wgLang->pipeList($links)}]"
 327+ );
 328+ }
 329+ break;
 330+
 331+ case 'ipb_by':
 332+ $user = User::newFromId( $value );
 333+ if( $user instanceof User ){
 334+ $formatted = $sk->userLink( $user->getId(), $user->getName() );
 335+ $formatted .= $sk->userToolLinks( $user->getId(), $user->getName() );
 336+ }
 337+ break;
 338+
 339+ case 'ipb_reason':
 340+ $formatted = $sk->commentBlock( $value );
 341+ break;
 342+
 343+ case 'ipb_params':
 344+ $properties = array();
 345+ if ( $row->ipb_anon_only ) {
 346+ $properties[] = $msg['anononlyblock'];
 347+ }
 348+ if ( $row->ipb_create_account ) {
 349+ $properties[] = $msg['createaccountblock'];
 350+ }
 351+ if ( !$row->ipb_enable_autoblock ) {
 352+ $properties[] = $msg['noautoblockblock'];
 353+ }
 354+
 355+ if ( $row->ipb_block_email ) {
 356+ $properties[] = $msg['emailblock'];
 357+ }
 358+
 359+ if ( !$row->ipb_allow_usertalk ) {
 360+ $properties[] = $msg['blocklist-nousertalk'];
 361+ }
 362+
 363+ $formatted = $wgLang->commaList( $properties );
 364+ break;
 365+
 366+ default:
 367+ $formatted = "Unable to format $name";
 368+ break;
 369+ }
 370+
 371+ return $formatted;
 372+ }
 373+
 374+ function getQueryInfo() {
 375+ $info = array(
 376+ 'tables' => array( 'ipblocks' ),
 377+ 'fields' => array(
 378+ 'ipb_id',
 379+ 'ipb_address',
 380+ 'ipb_by',
 381+ 'ipb_reason',
 382+ 'ipb_timestamp',
 383+ 'ipb_auto',
 384+ 'ipb_anon_only',
 385+ 'ipb_create_account',
 386+ 'ipb_enable_autoblock',
 387+ 'ipb_expiry',
 388+ 'ipb_range_start',
 389+ 'ipb_range_end',
 390+ 'ipb_deleted',
 391+ 'ipb_block_email',
 392+ 'ipb_allow_usertalk',
 393+ ),
 394+ 'conds' => $this->conds,
 395+ );
 396+
 397+ global $wgUser;
 398+ # Is the user allowed to see hidden blocks?
 399+ if ( !$wgUser->isAllowed( 'hideuser' ) ){
 400+ $conds['ipb_deleted'] = 0;
 401+ }
 402+
 403+ return $info;
 404+ }
 405+
 406+ public function getTableClass(){
 407+ return 'TablePager mw-blocklist';
 408+ }
 409+
 410+ function getIndexField() {
 411+ return 'ipb_timestamp';
 412+ }
 413+
 414+ function getDefaultSort() {
 415+ return 'ipb_timestamp';
 416+ }
 417+
 418+ function isFieldSortable( $name ) {
 419+ return false;
 420+ }
 421+
 422+ function getTitle() {
 423+ return $this->mPage->getTitle();
 424+ }
 425+}
Property changes on: trunk/phase3/includes/specials/SpecialBlockList.php
___________________________________________________________________
Added: svn:eol-style
1426 + native
Added: svn:keywords
2427 + Author Date Id Revision
Index: trunk/phase3/includes/specials/SpecialBlock.php
@@ -308,7 +308,7 @@
309309
310310 # Link to the block list
311311 $links[] = $skin->linkKnown(
312 - SpecialPage::getTitleFor( 'Ipblocklist' ),
 312+ SpecialPage::getTitleFor( 'BlockList' ),
313313 wfMsg( 'ipb-blocklist' )
314314 );
315315
Index: trunk/phase3/includes/SpecialPage.php
@@ -138,7 +138,7 @@
139139 # Users and rights
140140 'Block' => 'SpecialBlock',
141141 'Unblock' => 'SpecialUnblock',
142 - 'Ipblocklist' => 'IPUnblockForm',
 142+ 'BlockList' => 'SpecialBlockList',
143143 'Resetpass' => 'SpecialResetpass',
144144 'DeletedContributions' => 'DeletedContributionsPage',
145145 'Preferences' => 'SpecialPreferences',
Index: trunk/phase3/includes/Pager.php
@@ -51,7 +51,7 @@
5252 *
5353 * Subclassing the pager to implement concrete functionality should be fairly
5454 * simple, please see the examples in HistoryPage.php and
55 - * SpecialIpblocklist.php. You just need to override formatRow(),
 55+ * SpecialBlockList.php. You just need to override formatRow(),
5656 * getQueryInfo() and getIndexField(). Don't forget to call the parent
5757 * constructor if you override it.
5858 *
Index: trunk/phase3/languages/messages/MessagesEn.php
@@ -405,7 +405,7 @@
406406 'Filepath' => array( 'FilePath' ),
407407 'Import' => array( 'Import' ),
408408 'Invalidateemail' => array( 'InvalidateEmail' ),
409 - 'Ipblocklist' => array( 'BlockList', 'ListBlocks', 'IPBlockList' ),
 409+ 'BlockList' => array( 'BlockList', 'ListBlocks', 'IPBlockList' ),
410410 'LinkSearch' => array( 'LinkSearch' ),
411411 'Listadmins' => array( 'ListAdmins' ),
412412 'Listbots' => array( 'ListBots' ),
@@ -1592,7 +1592,7 @@
15931593 # Suppression log
15941594 'suppressionlog' => 'Suppression log',
15951595 'suppressionlogtext' => 'Below is a list of deletions and blocks involving content hidden from administrators.
1596 -See the [[Special:IPBlockList|IP block list]] for the list of currently operational bans and blocks.',
 1596+See the [[Special:BlockList|IP block list]] for the list of currently operational bans and blocks.',
15971597
15981598 # Revision move
15991599 'moverevlogentry' => 'moved {{PLURAL:$3|one revision|$3 revisions}} from $1 to $2',
@@ -3072,15 +3072,19 @@
30733073 'unblocked-id' => 'Block $1 has been removed',
30743074 'ipblocklist' => 'Blocked IP addresses and usernames',
30753075 'ipblocklist-legend' => 'Find a blocked user',
3076 -'ipblocklist-username' => 'Username or IP address:',
3077 -'ipblocklist-sh-userblocks' => '$1 account blocks',
3078 -'ipblocklist-sh-tempblocks' => '$1 temporary blocks',
3079 -'ipblocklist-sh-addressblocks' => '$1 single IP blocks',
 3076+'blocklist-userblocks' => 'Hide account blocks',
 3077+'blocklist-tempblocks' => 'Hide temporary blocks',
 3078+'blocklist-addressblocks' => 'Hide single IP blocks',
 3079+'blocklist-timestamp' => 'Timestamp',
 3080+'blocklist-target' => 'Target',
 3081+'blocklist-expiry' => 'Expires',
 3082+'blocklist-by' => 'Blocking admin',
 3083+'blocklist-params' => 'Block parameters',
 3084+'blocklist-reason' => 'Reason',
30803085 'ipblocklist-summary' => '', # do not translate or duplicate this message to other languages
30813086 'ipblocklist-submit' => 'Search',
30823087 'ipblocklist-localblock' => 'Local block',
30833088 'ipblocklist-otherblocks' => 'Other {{PLURAL:$1|block|blocks}}',
3084 -'blocklistline' => '$1, $2 blocked $3 ($4)',
30853089 'infiniteblock' => 'infinite',
30863090 'expiringblock' => 'expires on $1 at $2',
30873091 'anononlyblock' => 'anon. only',
Index: trunk/phase3/resources/mediawiki.special/mediawiki.special.css
@@ -37,6 +37,13 @@
3838 font-weight: bold;
3939 }
4040
 41+/**** Special:BlockList ****/
 42+table.mw-blocklist span.mw-usertoollinks,
 43+span.mw-blocklist-actions{
 44+ white-space: nowrap;
 45+ font-size: 90%;
 46+}
 47+
4148 /**** Special:Contributions ****/
4249 .mw-uctop {
4350 font-weight: bold;
Index: trunk/extensions/CheckUser/CheckUser_body.php
@@ -499,7 +499,7 @@
500500
501501 protected function getIPBlockInfo( $ip ) {
502502 static $blocklist;
503 - $blocklist = SpecialPage::getTitleFor( 'Ipblocklist' );
 503+ $blocklist = SpecialPage::getTitleFor( 'BlockList' );
504504 $block = new Block();
505505 $block->fromMaster( false ); // use slaves
506506 if ( $block->load( $ip, 0 ) ) {
@@ -1032,7 +1032,7 @@
10331033 protected function userBlockFlags( $ip, $userId, $user ) {
10341034 static $logs, $blocklist;
10351035 $logs = SpecialPage::getTitleFor( 'Log' );
1036 - $blocklist = SpecialPage::getTitleFor( 'Ipblocklist' );
 1036+ $blocklist = SpecialPage::getTitleFor( 'BlockList' );
10371037 $block = new Block();
10381038 $block->fromMaster( false ); // use slaves
10391039 $flags = array();

Follow-up revisions

RevisionCommit summaryAuthorDate
r83960Fix for r83909: Add new messag to avoid lt;blocklist&gt; on Special:SpecialPages...raymond20:46, 14 March 2011
r83963Fix for r83909: rename the corresponding -summary message. Forgotten to Crtl-...raymond21:00, 14 March 2011
r83966Follow-up r83909, fix errors seen on TWN reported in CRhappy-melon21:10, 14 March 2011
r83973Follow-up r83909: fix error on TWNhappy-melon22:26, 14 March 2011
r84003Follow-up r83909: The message key is named 'ipadressedorusername'raymond08:16, 15 March 2011
r84004Follow-up r83909: Use 'parentheses' message for consistency instead of hardco...raymond08:37, 15 March 2011
r84269Follow-up r83909, r83825: update special page aliases for all languages.happy-melon21:42, 18 March 2011
r99100FU r83909: restore preprocessing stage to cache link existence using LinkBatc...happy-melon13:25, 6 October 2011

Comments

#Comment by Nikerabbit (talk | contribs)   16:43, 14 March 2011

Have extensions been checked for the Ipblocklist -> BlockList change?

#Comment by Happy-melon (talk | contribs)   16:54, 14 March 2011

Everything in svn should be correct in terms of PHP code. There are still quite a lot of references in messages (98 in /extensions/Crosswiki/Crosswiki.i18n.php, for instance), which should resolve but should nonetheless be updated in due course; and a few random occurences in comments and non-code files.

#Comment by Raymond (talk | contribs)   20:19, 14 March 2011

Some errors on TWN:

PHP Warning:  in_array() expects parameter 2 to be array, null given in /www/w/includes/specials/SpecialBlockList.php on line 166
PHP Warning:  in_array() expects parameter 2 to be array, null given in /www/w/includes/specials/SpecialBlockList.php on line 169
PHP Warning:  in_array() expects parameter 2 to be array, null given in /www/w/includes/specials/SpecialBlockList.php on line 172
PHP Notice:  Undefined property: BlockListPager::$mPage in /www/w/includes/specials/SpecialBlockList.php on line 422
PHP Fatal error:  Call to a member function getTitle() on a non-object in /www/w/includes/specials/SpecialBlockList.php on line 422
#Comment by Happy-melon (talk | contribs)   21:11, 14 March 2011

Should be fixed by r83966.

#Comment by Raymond (talk | contribs)   08:45, 15 March 2011

The URL parameters looks very uncommons: http://translatewiki.net/wiki/Special:BlockList?wpTarget=&wpOptions[]=userblocks&wpOptions[]=tempblocks&wpOptions[]=addressblocks

It seems it works but it this intended?

#Comment by Happy-melon (talk | contribs)   15:11, 15 March 2011

That's the way MultiSelect fields work, and as you say the URL links work fine. I do notice, however, that the format is not recognised by the internal link syntax, I've fixed that in r84022.

#Comment by Duplicatebug (talk | contribs)   20:17, 18 March 2011

Please update the other Messages*.php-Files, because there are no local aliases for Special:BlockList in all languages unequal to en. Or it is bad to reuse the local aliases? Thanks.

#Comment by Happy-melon (talk | contribs)   20:47, 18 March 2011

Not being a speaker of all 243 languages, I don't know whether the old aliases are appropriate for the new name; whether they're a literal transliteration of "Ipblocklist" (in which case they need to be updated, not just renamed) or a proper translation of "page which lists blocks". Hence why we have translatewiki.

#Comment by Nikerabbit (talk | contribs)   20:50, 18 March 2011

Old aliases should always keep working.

#Comment by Aaron Schulz (talk | contribs)   20:24, 16 June 2011

Can TWN handle the renaming of the 'ipblocklist' messages?

#Comment by Aaron Schulz (talk | contribs)   21:12, 16 June 2011
+ $formatted = wfMessage( 'autoblockid', $row->ipb_id );

How does that work? Should it return HTML?

+ static $headers = null;

Why does getFieldNames() use a static var? Is it called often or something?

line 123 	if ( !$wgUser->isAllowed( 'hideuser' ) ){

This check is already there in the Pager class.

+	protected static function getIpFragment( $ip ){
+		global $wgBlockCIDRLimit;
+		if( IP::isIPv4( $ip ) ){
+			$hexAddress = IP::toHex( $ip );
+			return substr( $hexAddress, 0,  wfBaseconvert( $wgBlockCIDRLimit['IPv4'], 10, 16 ) );
+		} elseif( IP::isIPv6( $ip ) ) {
+			$hexAddress = substr( IP::toHex( $ip ), 2 );
+			return 'v6-' . substr( $hexAddress, 0,  wfBaseconvert( $wgBlockCIDRLimit['IPv6'], 10, 16 ) );

I don't think this works like you think. Try:

$hexAddress = IP::toHex( '122.114.14.5' );
var_dump( $hexAddress  );
var_dump( wfBaseconvert( 16, 10, 16 ) );
var_dump( $hexAddress, 0, wfBaseconvert( 16, 10, 16 ) );

Which gives...

string(8) "7A720E05"
string(2) "10"
string(8) "7A720E05"

If the min prefix is 16 bits, and each hex char is 4 bits, you'd want floor(16/4) = 4. Maybe use ($wgBlockCIDRLimit['IPv4']/4) in place of " wfBaseconvert( $wgBlockCIDRLimit['IPv4'], 10, 16 )" and likewise for v6?

#Comment by Aaron Schulz (talk | contribs)   21:17, 16 June 2011

Gah, for the test code, I meant:

$hexAddress = IP::toHex( '122.114.14.5' );
var_dump( $hexAddress  );
var_dump( wfBaseconvert( 16, 10, 16 ) );
var_dump( substr( $hexAddress, 0, wfBaseconvert( 16, 10, 16 ) ) );
#Comment by Aaron Schulz (talk | contribs)   22:34, 17 June 2011

Looks like getIpFragment() was fixed in r84358.

#Comment by Happy-melon (talk | contribs)   22:00, 26 June 2011
+ $formatted = wfMessage( 'autoblockid', $row->ipb_id );

How does that work? Should it return HTML?

The Message class has a __toString() magic method.

+ static $headers = null;

Why does getFieldNames() use a static var? Is it called often or something?

Actually no, it's not. Doesn't do any harm, per se, though.

#Comment by Aaron Schulz (talk | contribs)   22:06, 26 June 2011

I'd very much prefer if you just call parse() or what not on the message to be more explicit :)

#Comment by Aaron Schulz (talk | contribs)   21:26, 17 July 2011

Did this one myself (r91918).

#Comment by Tim Starling (talk | contribs)   01:42, 29 September 2011

This is a serious performance regression. Removing the LinkBatch and ipb_by_text code results in 3 DB queries being done for each block, with a noticeable performance impact in production.

#Comment by Aaron Schulz (talk | contribs)   22:36, 3 November 2011

Handled by r100254.

Status & tagging log