Index: branches/new-checkuser/CheckUser.i18n.php |
— | — | @@ -97,6 +97,7 @@ |
98 | 98 | [http://www.ip2location.com/$1 Geolocate] · |
99 | 99 | [http://toolserver.org/~overlordq/scripts/checktor.fcgi?ip=$1 Tor check] · |
100 | 100 | [http://ws.arin.net/whois/?queryinput=$1 WHOIS]]</span>', # do not translate or duplicate this message to other languages |
| 101 | + 'checkuser-xff' => 'XFF', |
101 | 102 | ); |
102 | 103 | |
103 | 104 | /** Message documentation (Message documentation) |
Index: branches/new-checkuser/CheckUser.i18n.en.php |
— | — | @@ -0,0 +1,109 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Internationalisation file for CheckUser extension. |
| 5 | + * |
| 6 | + * @file |
| 7 | + * @ingroup Extensions |
| 8 | + */ |
| 9 | + |
| 10 | +$messages = array(); |
| 11 | + |
| 12 | +/** English |
| 13 | + * @author Tim Starling |
| 14 | + * @author Aaron Schulz |
| 15 | + */ |
| 16 | +$messages['en'] = array( |
| 17 | + 'checkuser-summary' => 'This tool scans recent changes to retrieve the IP addresses used by a user or show the edit/user data for an IP address. |
| 18 | +Users and edits by a client IP address can be retrieved via XFF headers by appending the IP address with "/xff". IPv4 (CIDR 16-32) and IPv6 (CIDR 96-128) are supported. |
| 19 | +No more than 5,000 edits will be returned for performance reasons. |
| 20 | +Use this in accordance with policy.', |
| 21 | + 'checkuser-desc' => 'Grants users with the appropriate permission the ability to check user\'s IP addresses and other information', |
| 22 | + 'checkuser-logcase' => 'The log search is case sensitive.', |
| 23 | + 'checkuser' => 'Check user', |
| 24 | + 'checkuser-contribs' => 'check user IP addresses', |
| 25 | + 'group-checkuser' => 'Check users', |
| 26 | + 'group-checkuser-member' => 'Check user', |
| 27 | + 'right-checkuser' => "Check user's IP addresses and other information", |
| 28 | + 'right-checkuser-log' => 'View the checkuser log', |
| 29 | + 'grouppage-checkuser' => '{{ns:project}}:Check user', |
| 30 | + 'checkuser-reason' => 'Reason:', |
| 31 | + 'checkuser-showlog' => 'Show log', |
| 32 | + 'checkuser-log' => 'CheckUser log', |
| 33 | + 'checkuser-query' => 'Query recent changes', |
| 34 | + 'checkuser-target' => 'IP address or username:', |
| 35 | + 'checkuser-users' => 'Get users', |
| 36 | + 'checkuser-edits' => 'Get edits from IP address', |
| 37 | + 'checkuser-ips' => 'Get IP addresses', |
| 38 | + 'checkuser-account' => 'Get account edits', |
| 39 | + 'checkuser-search' => 'Search', |
| 40 | + 'checkuser-period' => 'Duration:', |
| 41 | + 'checkuser-week-1' => 'last week', |
| 42 | + 'checkuser-week-2' => 'last two weeks', |
| 43 | + 'checkuser-month' => 'last 30 days', |
| 44 | + 'checkuser-all' => 'all', |
| 45 | + 'checkuser-cidr-label' => 'Find common range and affected IP addresses for a list of IP addresses', |
| 46 | + 'checkuser-cidr-res' => 'Common CIDR:', |
| 47 | + 'checkuser-empty' => 'The log contains no items.', |
| 48 | + 'checkuser-nomatch' => 'No matches found.', |
| 49 | + 'checkuser-nomatch-edits' => 'No matches found. |
| 50 | +Last edit was on $1 at $2.', |
| 51 | + 'checkuser-check' => 'Check', |
| 52 | + 'checkuser-log-fail' => 'Unable to add log entry', |
| 53 | + 'checkuser-nolog' => 'No log file found.', |
| 54 | + 'checkuser-blocked' => 'Blocked', |
| 55 | + 'checkuser-gblocked' => 'Blocked globally', |
| 56 | + 'checkuser-locked' => 'Locked', |
| 57 | + 'checkuser-wasblocked' => 'Previously blocked', |
| 58 | + 'checkuser-localonly' => 'Not unified', |
| 59 | + 'checkuser-massblock' => 'Block selected users', |
| 60 | + 'checkuser-massblock-text' => 'Selected accounts will be blocked indefinitely, with autoblocking enabled and account creation disabled. |
| 61 | + IP addresses will be blocked for 1 week for IP users only and with account creation disabled.', |
| 62 | + 'checkuser-blocktag' => 'Replace user pages with:', |
| 63 | + 'checkuser-blocktag-talk' => 'Replace talk pages with:', |
| 64 | + 'checkuser-massblock-commit' => 'Block selected users', |
| 65 | + 'checkuser-block-success' => '\'\'\'The {{PLURAL:$2|user|users}} $1 {{PLURAL:$2|is|are}} now blocked.\'\'\'', |
| 66 | + 'checkuser-block-failure' => '\'\'\'No users blocked.\'\'\'', |
| 67 | + 'checkuser-block-limit' => 'Too many users selected.', |
| 68 | + 'checkuser-block-noreason' => 'You must give a reason for the blocks.', |
| 69 | + 'checkuser-noreason' => 'You must give a reason for this query.', |
| 70 | + 'checkuser-accounts' => '$1 new {{PLURAL:$1|account|accounts}}', |
| 71 | + 'checkuser-too-many' => 'Too many results (according to query estimate), please narrow down the CIDR. |
| 72 | +Here are the IPs used (5000 max, sorted by address):', |
| 73 | + 'checkuser-user-nonexistent' => 'The specified user does not exist.', |
| 74 | + 'checkuser-search-form' => 'Find log entries where the $1 is $2', |
| 75 | + 'checkuser-search-submit' => 'Search', |
| 76 | + 'checkuser-search-initiator' => 'initiator', |
| 77 | + 'checkuser-search-target' => 'target', |
| 78 | + 'checkuser-ipeditcount' => '~$1 from all users', |
| 79 | + 'checkuser-log-subpage' => 'Log', |
| 80 | + 'checkuser-log-return' => 'Return to CheckUser main form', |
| 81 | + 'checkuser-log-userips' => '$1 got IP addresses for $2', |
| 82 | + 'checkuser-log-ipedits' => '$1 got edits for $2', |
| 83 | + 'checkuser-log-ipusers' => '$1 got users for $2', |
| 84 | + 'checkuser-log-ipedits-xff' => '$1 got edits for XFF $2', |
| 85 | + 'checkuser-log-ipusers-xff' => '$1 got users for XFF $2', |
| 86 | + 'checkuser-log-useredits' => '$1 got edits for $2', |
| 87 | + |
| 88 | + 'checkuser-autocreate-action' => 'was automatically created', |
| 89 | + 'checkuser-email-action' => 'sent an email to user "$1"', |
| 90 | + 'checkuser-reset-action' => 'reset password for user "$1"', |
| 91 | + |
| 92 | + 'checkuser-toollinks' => '---- |
| 93 | + <span class="plainlinks">[http://openrbl.org/query?$1 RDNS] • |
| 94 | +[http://www.robtex.com/rbls/$1.html RBLs] • |
| 95 | +[http://www.dnsstuff.com/tools/tracert.ch?ip=$1 Traceroute] <br /> |
| 96 | +[http://www.ip2location.com/$1 Geolocate] • |
| 97 | +[http://toolserver.org/~overlordq/scripts/checktor.fcgi?ip=$1 Tor] • |
| 98 | +[http://ws.arin.net/whois/?queryinput=$1 WHOIS]</span>', # do not translate or duplicate this message to other languages |
| 99 | + 'checkuser-xff' => 'XFF', |
| 100 | + 'checkuser-blockedby' => 'Blocked by [[User:$1|$1]] on $3 with reason: "<nowiki>$2</nowiki>". $4', |
| 101 | + 'checkuser-type' => 'Type of check:', |
| 102 | + |
| 103 | + 'checkuser-cuc_ip' => 'IP', |
| 104 | + 'checkuser-allusers' => 'All edits', |
| 105 | + 'checkuser-count' => 'Edits', |
| 106 | + 'checkuser-first' => 'First use', |
| 107 | + 'checkuser-last' => 'Last use', |
| 108 | + 'checkuser-blockinfo' => 'Block info', |
| 109 | + 'checkuser-expires' => 'Expires', |
| 110 | +); |
\ No newline at end of file |
Index: branches/new-checkuser/CheckUserApi.php |
— | — | @@ -6,7 +6,7 @@ |
7 | 7 | parent::__construct( $query, $moduleName, 'cu' ); |
8 | 8 | } |
9 | 9 | |
10 | | - public function execute( $resultPageSet = null ) { |
| 10 | + public function execute() { |
11 | 11 | global $wgUser; |
12 | 12 | |
13 | 13 | // Before doing anything at all, let's check permissions |
— | — | @@ -22,38 +22,86 @@ |
23 | 23 | if ( !isset( $params['type'] ) ) { |
24 | 24 | $this->dieUsageMsg( array( 'missingparam', 'cutype' ) ); |
25 | 25 | } |
26 | | - if ( !isset( $params['reason'] ) ) { |
27 | | - $params['reason'] = ''; |
28 | | - } |
29 | 26 | if ( !isset( $params['period'] ) ) { |
30 | 27 | $params['period'] = 0; |
31 | 28 | } |
32 | 29 | |
33 | | - $result = new CheckUser( $params['target'] ); |
| 30 | + $endResult = array(); |
34 | 31 | |
35 | | - switch( $params['type'] ) { |
36 | | - case "user2ip": |
37 | | - $result = $result->doUser2IP( $params, $params['prop'], 'LIMIT ' . $params['limit'] ); |
38 | | - break; |
39 | | - case "user2edits": |
40 | | - $result = $result->doUser2Edits( $params['reason'], $params['period'] ); |
41 | | - break; |
42 | | - case "ip2user": |
43 | | - $result = $result->doIP2User( $params['reason'], $params['period'] ); |
44 | | - break; |
45 | | - case "ip2edits": |
46 | | - $result = $result->doIP2Edits( $params['reason'], $params['period'] ); |
47 | | - break; |
| 32 | + foreach( $params['target'] as $target ) { |
| 33 | + $result = new CheckUser( $target ); |
48 | 34 | |
| 35 | + switch( $params['type'] ) { |
| 36 | + case "user2ip": |
| 37 | + $ips = $this->doUser2IP( $result, $params, $params['prop'], $params['limit'] ); |
| 38 | + $endResult[] = array( 'target' => $result->target, 'ips' => $ips ); |
| 39 | + break; |
| 40 | + case "user2edits": |
| 41 | + $endResult[] = $result->doUser2Edits( $params['reason'], $params['period'] ); |
| 42 | + break; |
| 43 | + case "ip2user": |
| 44 | + $endResult[] = $result->doIP2User( $params['reason'], $params['period'] ); |
| 45 | + break; |
| 46 | + case "ip2edits": |
| 47 | + $endResult[] = $result->doIP2Edits( $params['reason'], $params['period'] ); |
| 48 | + break; |
| 49 | + |
| 50 | + } |
49 | 51 | } |
50 | 52 | |
51 | 53 | $this->getResult()->setIndexedTagName( $result, 'checkuser' ); |
52 | | - $this->getResult()->addValue( 'query', $this->getModuleName(), $result ); |
| 54 | + $this->getResult()->addValue( 'query', $this->getModuleName(), $endResult ); |
53 | 55 | |
54 | 56 | } |
55 | 57 | |
56 | | - public function executeGenerator( $resultPageSet ) { |
57 | | - $this->execute( $resultPageSet ); |
| 58 | + public function doUser2IP( &$cuClass, $params, $prop, $limit ) { |
| 59 | + |
| 60 | + $dbParams = $cuClass->doUser2IP( $params, $prop, $limit ); |
| 61 | + |
| 62 | + $retArray = array(); |
| 63 | + |
| 64 | + $dbr = wfGetDB( DB_SLAVE ); |
| 65 | + |
| 66 | + //$dbr->setFlag( DBO_DEBUG ); |
| 67 | + |
| 68 | + $ret = $dbr->select( |
| 69 | + $dbParams[0], |
| 70 | + $dbParams[1], |
| 71 | + $dbParams[2], |
| 72 | + __METHOD__, |
| 73 | + $dbParams[3] |
| 74 | + ); |
| 75 | + |
| 76 | + if ( !$dbr->numRows( $ret ) ) { |
| 77 | + return $retArray; |
| 78 | + } else { |
| 79 | + $counter = 0; |
| 80 | + |
| 81 | + foreach( $ret as $id => $row ) { |
| 82 | + $retArray[$counter] = array( 'ip' => $row->cuc_ip ); |
| 83 | + |
| 84 | + if( in_array( 'count', $prop ) || is_null( $prop ) ) $retArray[$counter]['count'] = $row->count; |
| 85 | + if( in_array( 'first', $prop ) || is_null( $prop ) ) $retArray[$counter]['first'] = $row->first; |
| 86 | + if( in_array( 'last', $prop ) || is_null( $prop ) ) $retArray[$counter]['last'] = $row->last; |
| 87 | + if( in_array( 'hex', $prop ) || is_null( $prop ) ) $retArray[$counter]['hex'] = $row->cuc_ip_hex; |
| 88 | + if( in_array( 'blockinfo', $prop ) || is_null( $prop ) ) { |
| 89 | + $blockinfo = CheckUser::checkBlockInfo( $row->cuc_ip ); |
| 90 | + if( $blockinfo ) { |
| 91 | + $retArray[$counter]['blockinfo']['by'] = $blockinfo->ipb_by_text; |
| 92 | + $retArray[$counter]['blockinfo']['reason'] = $blockinfo->ipb_reason; |
| 93 | + $retArray[$counter]['blockinfo']['timestamp'] = $blockinfo->ipb_timestamp; |
| 94 | + $retArray[$counter]['blockinfo']['expiry'] = $blockinfo->ipb_expiry; |
| 95 | + } |
| 96 | + } |
| 97 | + |
| 98 | + $counter++; |
| 99 | + |
| 100 | + } |
| 101 | + } |
| 102 | + |
| 103 | + $dbr->freeResult( $ret ); |
| 104 | + |
| 105 | + return $retArray; |
58 | 106 | } |
59 | 107 | |
60 | 108 | |
— | — | @@ -64,12 +112,20 @@ |
65 | 113 | public function getAllowedParams() { |
66 | 114 | return array( |
67 | 115 | 'target' => array( |
| 116 | + ApiBase::PARAM_ISMULTI => true, |
68 | 117 | ApiBase::PARAM_TYPE => 'user', |
69 | 118 | ), |
70 | 119 | 'type' => array( |
71 | 120 | ApiBase::PARAM_TYPE => array( 'user2ip', 'user2edits', 'ip2user', 'ip2edits' ), |
72 | 121 | ), |
73 | | - 'reason' => 'string', |
| 122 | + 'reason' => array( |
| 123 | + ApiBase::PARAM_DFLT => '', |
| 124 | + ApiBase::PARAM_TYPE => 'string' |
| 125 | + ), |
| 126 | + 'period' => array( |
| 127 | + ApiBase::PARAM_DFLT => 30, |
| 128 | + ApiBase::PARAM_TYPE => 'integer' |
| 129 | + ), |
74 | 130 | 'prop' => array( |
75 | 131 | ApiBase::PARAM_ISMULTI => true, |
76 | 132 | ApiBase::PARAM_DFLT => 'count|first|last|blockinfo', |
Index: branches/new-checkuser/CheckUser.php |
— | — | @@ -55,7 +55,8 @@ |
56 | 56 | $wgAPIListModules['checkuser'] = 'CheckUserApi'; |
57 | 57 | $wgAPIListModules['checkuserlog'] = 'CheckUserApiLog'; |
58 | 58 | |
59 | | -$wgExtensionMessagesFiles['CheckUser'] = $dir . 'CheckUser.i18n.php'; |
| 59 | +$wgExtensionMessagesFiles['CheckUser'] = $dir . 'CheckUser.i18n.en.php'; |
| 60 | +//FIXME: $wgExtensionMessagesFiles['CheckUser'] = $dir . 'CheckUser.i18n.php'; |
60 | 61 | $wgExtensionAliasesFiles['CheckUser'] = $dir . 'CheckUser.alias.php'; |
61 | 62 | |
62 | 63 | // New user rights |
Index: branches/new-checkuser/SpecialCheckUser.php |
— | — | @@ -5,35 +5,192 @@ |
6 | 6 | function __construct() { |
7 | 7 | global $wgUser; |
8 | 8 | |
9 | | - if ( $wgUser->isAllowed( 'checkuser' ) || !$wgUser->isAllowed( 'checkuser-log' ) ) { |
10 | | - parent::__construct( 'CheckUser', 'checkuser' ); |
11 | | - } else { |
12 | | - parent::__construct( 'CheckUser', 'checkuser-log' ); |
13 | | - } |
| 9 | + parent::__construct( 'CheckUser', 'checkuser' ); |
| 10 | + |
| 11 | + wfLoadExtensionMessages( 'CheckUser' ); |
14 | 12 | } |
15 | 13 | |
16 | | - function excecute( $subpage ) { |
| 14 | + function execute( $subpage ) { |
| 15 | + global $wgRequest, $wgOut, $wgUser, $wgCheckUserForceSummary; |
17 | 16 | |
18 | 17 | wfLoadExtensionMessages( 'CheckUser' ); |
19 | 18 | |
| 19 | + $this->setHeaders(); |
| 20 | + |
| 21 | + if ( !$wgUser->isAllowed( 'checkuser' ) ) { |
| 22 | + if ( $wgUser->isAllowed( 'checkuser-log' ) ) { |
| 23 | + $wgOut->addWikiText( wfMsg( 'checkuser-summary' ) . |
| 24 | + "\n\n[[" . SpecialPage::getTitleFor( 'CheckUserLog', false ) . |
| 25 | + '|' . wfMsg( 'checkuser-showlog' ) . ']]' |
| 26 | + ); |
| 27 | + return; |
| 28 | + } |
| 29 | + |
| 30 | + $wgOut->permissionRequired( 'checkuser' ); |
| 31 | + return; |
| 32 | + } |
| 33 | + |
| 34 | + $user = trim( $wgRequest->getText( 'user' ) ); |
| 35 | + $reason = $wgRequest->getText( 'reason' ); |
| 36 | + $blockreason = $wgRequest->getText( 'blockreason' ); |
| 37 | + $checktype = $wgRequest->getVal( 'checktype' ); |
| 38 | + $period = $wgRequest->getInt( 'period' ); |
| 39 | + $users = $wgRequest->getArray( 'users' ); |
| 40 | + $tag = $wgRequest->getBool( 'usetag' ) ? trim( $wgRequest->getVal( 'tag' ) ) : ''; |
| 41 | + $talkTag = $wgRequest->getBool( 'usettag' ) ? trim( $wgRequest->getVal( 'talktag' ) ) : ''; |
| 42 | + $xff = $wgRequest->getBool( 'xff' ); |
| 43 | + |
| 44 | + $this->doForm( $user, $reason, $checktype, $xff, $period ); |
| 45 | + # Perform one of the various submit operations... |
| 46 | + if ( $wgRequest->wasPosted() |1 ) { //FIXME |
| 47 | + if ( $wgRequest->getVal( 'action' ) === 'block' ) { |
| 48 | + $this->doMassUserBlock( $users, $blockreason, $tag, $talkTag ); |
| 49 | + } elseif ( $wgCheckUserForceSummary && !strlen( $reason ) ) { |
| 50 | + $wgOut->addWikiMsg( 'checkuser-noreason' ); |
| 51 | + } elseif ( $checktype == 'user2ip' ) { |
| 52 | + //$this->doUser2IP( $user, $reason, $period ); |
| 53 | + } elseif ( $xff && $checktype == 'subipedits' ) { |
| 54 | + $this->doIPEditsRequest( $xff, true, $reason, $period ); |
| 55 | + } elseif ( $checktype == 'subipedits' ) { |
| 56 | + $this->doIPEditsRequest( $ip, false, $reason, $period ); |
| 57 | + } elseif ( $xff && $checktype == 'subipusers' ) { |
| 58 | + $this->doIPUsersRequest( $xff, true, $reason, $period, $tag, $talkTag ); |
| 59 | + } elseif ( $checktype == 'subipusers' ) { |
| 60 | + $this->doIPUsersRequest( $ip, false, $reason, $period, $tag, $talkTag ); |
| 61 | + } elseif ( $checktype == 'subuseredits' ) { |
| 62 | + $this->doUserEditsRequest( $user, $reason, $period ); |
| 63 | + } |
| 64 | + } |
| 65 | + |
| 66 | + # Add CIDR calculation convenience form |
| 67 | + $this->addJsCIDRForm(); |
| 68 | + $this->addStyles(); |
| 69 | + |
20 | 70 | } |
21 | 71 | |
22 | | - function preCacheMessages() { |
| 72 | + protected function doForm( $user, $reason, $checktype, $xff, $period ) { |
| 73 | + global $wgOut, $wgUser; |
| 74 | + |
| 75 | + $action = $this->getTitle()->escapeLocalUrl(); |
| 76 | + |
| 77 | + # Fill in requested type if it makes sense |
| 78 | + $encipusers = $encipedits = $encuserips = $encuseredits = 0; |
| 79 | + if ( $checktype == 'ip2user' ) { |
| 80 | + $encipusers = 1; |
| 81 | + } elseif ( $checktype == 'ip2edits' ) { |
| 82 | + $encipedits = 1; |
| 83 | + } elseif ( $checktype == 'user2ip' ) { |
| 84 | + $encuserips = 1; |
| 85 | + } elseif ( $checktype == 'user2edits' ) { |
| 86 | + $encuseredits = 1; |
| 87 | + # Defaults otherwise |
| 88 | + } else { |
| 89 | + $encuserips = 1; |
| 90 | + } |
| 91 | + |
| 92 | + if ( $wgUser->isAllowed( 'checkuser-log' ) ) { |
| 93 | + $wgOut->addWikiText( wfMsg( 'checkuser-summary' ) . |
| 94 | + "\n\n[[" . SpecialPage::getTitleFor( 'CheckUserLog', false ) . |
| 95 | + '|' . wfMsg( 'checkuser-showlog' ) . ']]' |
| 96 | + ); |
| 97 | + } |
| 98 | + |
| 99 | + $form = Xml::openElement( 'form', array( 'name' => 'checkuserform', 'id' => 'checkuserform', 'action' => $action, 'method' => 'post' ) ) . |
| 100 | + Xml::openElement( 'fieldset' ) . Xml::openElement( 'legend' ) . wfMsgHtml( 'checkuser-query' ) . Xml::closeElement( 'legend') . |
| 101 | + Xml::openElement( 'table', array( 'border' => 0, 'cellpadding' => 2 ) ) . Xml::openElement( 'tr' ) . |
| 102 | + Xml::openElement( 'td' ) . wfMsgHtml( 'checkuser-target' ) . Xml::closeElement( 'td' ) . |
| 103 | + Xml::openElement( 'td' ) . Xml::input( 'user', 46, $user, array( 'id' => 'checktarget' ) ) . |
| 104 | + '  '. Xml::check( 'xff', $xff ) . ' ' . Xml::label( wfMsg( 'checkuser-xff' ), 'xff' ) . Xml::closeElement( 'td' ) . |
| 105 | + |
| 106 | + Xml::closeElement( 'tr' ) . Xml::openElement( 'tr' ) . |
| 107 | + |
| 108 | + Xml::openElement( 'td' ) . wfMsgHtml( 'checkuser-type' ) . Xml::closeElement( 'td' ) . |
| 109 | + Xml::openElement( 'td', array( 'class' => 'checkuserradios' ) ) . |
| 110 | + Xml::openElement( 'table', array( 'border' => 0, 'cellpadding' => 3 ) ) . |
| 111 | + Xml::openElement( 'tr' ) . |
| 112 | + |
| 113 | + Xml::openElement( 'td' ) . Xml::radio( 'checktype', 'user2ip', $encuserips, array( 'id' => 'subuserips' ) ) . ' ' . |
| 114 | + Xml::label( wfMsg( 'checkuser-ips' ), 'subuserips' ) . Xml::closeElement( 'td' ) . |
| 115 | + Xml::openElement( 'td' ) . Xml::radio( 'checktype', 'user2edits', $encuseredits, array( 'id' => 'subuseredits' ) ) . ' ' . |
| 116 | + Xml::label( wfMsg( 'checkuser-account' ), 'subuseredits' ) . Xml::closeElement( 'td' ) . |
| 117 | + Xml::openElement( 'td' ) . Xml::radio( 'checktype', 'ip2user', $encipusers, array( 'id' => 'subipusers' ) ) . ' ' . |
| 118 | + Xml::label( wfMsg( 'checkuser-users' ), 'subipusers' ) . Xml::closeElement( 'td' ) . |
| 119 | + Xml::openElement( 'td' ) . Xml::radio( 'checktype', 'ip2edits', $encipedits, array( 'id' => 'subipedits' ) ) . ' ' . |
| 120 | + Xml::label( wfMsg( 'checkuser-edits' ), 'subipedits' ) . Xml::closeElement( 'td' ) . |
| 121 | + |
| 122 | + Xml::closeElement( 'tr' ) . Xml::closeElement( 'table' ) . Xml::closeElement( 'td' ) . |
| 123 | + Xml::closeElement( 'tr' ) . Xml::openElement( 'tr' ) . |
| 124 | + Xml::openElement( 'td' ) . wfMsgHtml( 'checkuser-reason' ) . Xml::closeElement( 'td' ) . |
| 125 | + Xml::openElement( 'td' ) . Xml::input( 'reason', 46, $reason, array( 'maxlength' => '255', 'id' => 'checkreason' ) ) . Xml::closeElement( 'td' ) . |
| 126 | + Xml::closeElement( 'tr' ) . Xml::openElement( 'tr' ) . |
| 127 | + $this->getPeriodMenu( $period ) . |
| 128 | + Xml::closeElement( 'tr' ) . Xml::openElement( 'tr' ) . |
| 129 | + Xml::openElement( 'td' ) . |
| 130 | + Xml::submitButton( wfMsg( 'checkuser-check' ), array( 'id' => 'checkusersubmit', 'name' => 'checkusersubmit' ) ) . |
| 131 | + Xml::closeElement( 'td' ) . Xml::closeElement( 'tr' ) . Xml::closeElement( 'table' ) . Xml::closeElement( 'fieldset' ) . |
| 132 | + Xml::closeElement( 'form' ); |
| 133 | + |
| 134 | + |
| 135 | + # Output form |
| 136 | + $wgOut->addHTML( $form ); |
23 | 137 | } |
24 | 138 | |
25 | | - function getLogSubpageTitle() { |
| 139 | + /** |
| 140 | + * As we use the same small set of messages in various methods and that |
| 141 | + * they are called often, we call them once and save them in $this->message |
| 142 | + */ |
| 143 | + protected function preCacheMessages() { |
| 144 | + // Precache various messages |
| 145 | + if ( !isset( $this->message ) ) { |
| 146 | + foreach ( explode( ' ', 'diff hist minoreditletter newpageletter blocklink log' ) as $msg ) { |
| 147 | + $this->message[$msg] = wfMsgExt( $msg, array( 'escape' ) ); |
| 148 | + } |
| 149 | + } |
26 | 150 | } |
27 | 151 | |
28 | | - function doForm() { |
| 152 | + function getLogSubpageTitle() { |
29 | 153 | } |
30 | 154 | |
31 | | - function addStyles() { |
| 155 | + /** |
| 156 | + * Add CSS/JS |
| 157 | + */ |
| 158 | + protected function addStyles() { |
| 159 | + global $wgScriptPath, $wgCheckUserStyleVersion, $wgOut; |
| 160 | + // FIXME, use Html:: |
| 161 | + $encJSFile = htmlspecialchars( "$wgScriptPath/extensions/CheckUser/checkuser.js?$wgCheckUserStyleVersion" ); |
| 162 | + $wgOut->addScript( "<script type=\"text/javascript\" src=\"$encJSFile\"></script>" ); |
32 | 163 | } |
33 | 164 | |
34 | | - function getPeriodMenu() { |
| 165 | + /** |
| 166 | + * Get a selector of time period options |
| 167 | + * @param int $selected, selected level |
| 168 | + */ |
| 169 | + protected function getPeriodMenu( $selected = null ) { |
| 170 | + $s = '<td>' . wfMsgHtml( 'checkuser-period' ) . '</td>'; |
| 171 | + $s .= '<td>' . Xml::openElement( 'select', array( 'name' => 'period', 'id' => 'period', 'style' => 'margin-top:.2em;' ) ); |
| 172 | + $s .= Xml::option( wfMsg( 'checkuser-week-1' ), 7, $selected === 7 ); |
| 173 | + $s .= Xml::option( wfMsg( 'checkuser-week-2' ), 14, $selected === 14 ); |
| 174 | + $s .= Xml::option( wfMsg( 'checkuser-month' ), 31, $selected === 31 ); |
| 175 | + $s .= Xml::option( wfMsg( 'checkuser-all' ), 0, $selected === 0 ); |
| 176 | + $s .= Xml::closeElement( 'select' ) . "</td>\n"; |
| 177 | + return $s; |
35 | 178 | } |
36 | 179 | |
37 | | - function addJSCIDRForm() { |
| 180 | + /** |
| 181 | + * Make a quick JS form for admins to calculate block ranges |
| 182 | + */ |
| 183 | + protected function addJsCIDRForm() { |
| 184 | + global $wgOut; |
| 185 | + |
| 186 | + $s = '<fieldset id="mw-checkuser-cidrform" style="display:none; clear:both;">' . |
| 187 | + '<legend>' . wfMsgHtml( 'checkuser-cidr-label' ) . '</legend>'; |
| 188 | + $s .= '<textarea id="mw-checkuser-iplist" rows="5" cols="50" onkeyup="updateCIDRresult()" onclick="updateCIDRresult()"></textarea><br />'; |
| 189 | + $s .= wfMsgHtml( 'checkuser-cidr-res' ) . ' ' . |
| 190 | + Xml::input( 'mw-checkuser-cidr-res', 35, '', array( 'id' => 'mw-checkuser-cidr-res' ) ) . |
| 191 | + ' <strong id="mw-checkuser-ipnote"></strong>'; |
| 192 | + $s .= '</fieldset>'; |
| 193 | + |
| 194 | + $wgOut->addHTML( $s ); |
38 | 195 | } |
39 | 196 | |
40 | 197 | function doMassUserBlock() { |
— | — | @@ -42,12 +199,27 @@ |
43 | 200 | function noMatchesMessage() { |
44 | 201 | } |
45 | 202 | |
46 | | - function checkReason() { |
| 203 | + function doUser2IP( $user, $reason, $period ) { |
| 204 | + global $wgOut; |
| 205 | + |
| 206 | + $checkuser = new CheckUser( $user ); |
| 207 | + |
| 208 | + $result = $checkuser->doUser2IP( array( |
| 209 | + 'target' => $user, |
| 210 | + 'reason' => $reason, |
| 211 | + 'period' => $period |
| 212 | + ) ); |
| 213 | + |
| 214 | + $pager = new CUTablePager( $result ); |
| 215 | + |
| 216 | + $output = |
| 217 | + $pager->getNavigationBar() . |
| 218 | + $pager->getBody() . |
| 219 | + $pager->getNavigationBar(); |
| 220 | + |
| 221 | + $wgOut->addHTML( $output ); |
47 | 222 | } |
48 | 223 | |
49 | | - function doUser2IP() { |
50 | | - } |
51 | | - |
52 | 224 | function doUser2Edits() { |
53 | 225 | } |
54 | 226 | |
— | — | @@ -63,4 +235,167 @@ |
64 | 236 | } |
65 | 237 | |
66 | 238 | class CUTablePager extends TablePager { |
67 | | -} |
\ No newline at end of file |
| 239 | + |
| 240 | + private $mCUSelectParams; |
| 241 | + private $mBlockInfo; |
| 242 | + |
| 243 | + function __construct( $result ) { |
| 244 | + $this->mCUSelectParams = $result; |
| 245 | + |
| 246 | + parent::__construct(); |
| 247 | + } |
| 248 | + |
| 249 | + function getQueryInfo() { |
| 250 | + $ret = array( |
| 251 | + 'tables' => $this->mCUSelectParams[0], |
| 252 | + 'fields' => $this->mCUSelectParams[1], |
| 253 | + 'conds' => $this->mCUSelectParams[2], |
| 254 | + 'options' => $this->mCUSelectParams[3] |
| 255 | + ); |
| 256 | + |
| 257 | + if( isset( $ret['options']['ORDER BY'] ) ) { |
| 258 | + unset( $ret['options']['ORDER BY'] ); |
| 259 | + } |
| 260 | + |
| 261 | + return $ret; |
| 262 | + } |
| 263 | + |
| 264 | + function getIndexField() { |
| 265 | + return 'cuc_ip'; |
| 266 | + } |
| 267 | + |
| 268 | + //function formatRow( $row ) { |
| 269 | + //$title = Title::newFromDBkey( $row->cuc_ip ); |
| 270 | + //$s = '<td><a href="' /* . $title->getFullURL()*/ . '">' . $row->cuc_ip . '</a></li>'; |
| 271 | + //return $s; |
| 272 | + //} |
| 273 | + |
| 274 | + function isFieldSortable( $field ) { |
| 275 | + return true; |
| 276 | + } |
| 277 | + |
| 278 | + function getDefaultSort() { |
| 279 | + return 'cuc_ip'; |
| 280 | + } |
| 281 | + |
| 282 | + function formatValue( $name, $value ) { |
| 283 | + global $wgContLang; |
| 284 | + |
| 285 | + switch( $name ) { |
| 286 | + case 'cuc_ip': |
| 287 | + $value = '<a href="' . |
| 288 | + $this->getTitle()->escapeLocalURL( 'user=' . urlencode( $value ) . '&reason=' . urlencode( $reason ) ) . '">' . |
| 289 | + htmlspecialchars( $value ) . '</a>' . |
| 290 | + ' (<a href="' . SpecialPage::getTitleFor( 'Blockip' )->escapeLocalURL( 'ip=' . urlencode( $value ) ) . '">' . |
| 291 | + wfMsgHtml( 'blocklink' ) . '</a>)<br /><small>' . |
| 292 | + wfMsgExt( 'checkuser-toollinks', array( 'parseinline' ), urlencode( $value ) ) . '</small>'; |
| 293 | + |
| 294 | + break; |
| 295 | + case 'count': |
| 296 | + $dbr = wfGetDB( DB_SLAVE ); |
| 297 | + $dbr->setFlag( DBO_DEBUG ); |
| 298 | + |
| 299 | + # If we get some results, it helps to know if the IP in general |
| 300 | + # has a lot more edits, e.g. "tip of the iceberg"... |
| 301 | + $ipedits = $dbr->estimateRowCount( 'cu_changes', '*', |
| 302 | + array( 'cuc_ip_hex' => $this->mCurrentRow->cuc_ip_hex, $this->mCUSelectParams[2][0] ), |
| 303 | + __METHOD__ ); |
| 304 | + # If small enough, get a more accurate count |
| 305 | + if ( $ipedits <= 1000 ) { |
| 306 | + $ipedits = $dbr->selectField( 'cu_changes', 'COUNT(*)', |
| 307 | + array( 'cuc_ip_hex' => $this->mCurrentRow->cuc_ip_hex, $this->mCUSelectParams[2][0] ), |
| 308 | + __METHOD__ ); |
| 309 | + } |
| 310 | + |
| 311 | + $value .= '<td>' . $ipedits . '</td>'; |
| 312 | + break; |
| 313 | + |
| 314 | + case 'first': |
| 315 | + return $wgContLang->timeanddate( wfTimestamp( TS_MW, $value ), true ); |
| 316 | + break; |
| 317 | + case 'last': |
| 318 | + $ret = $wgContLang->timeanddate( wfTimestamp( TS_MW, $value ), true ); |
| 319 | + |
| 320 | + $ret .= '</td>'; |
| 321 | + |
| 322 | + if( $this->mBlockInfo ) { |
| 323 | + $ret .= '<td style="background-color: #FFFFCC;">'; |
| 324 | + } |
| 325 | + else { |
| 326 | + $ret .= '<td>'; |
| 327 | + } |
| 328 | + |
| 329 | + $ret .= $this->fixBlockInfo( $this->mBlockInfo ) . '</td>'; |
| 330 | + //Wow, that's hacky. |
| 331 | + |
| 332 | + return $ret; |
| 333 | + } |
| 334 | + |
| 335 | + return $value; |
| 336 | + } |
| 337 | + |
| 338 | + function fixBlockInfo( $info ) { |
| 339 | + global $wgContLang; |
| 340 | + |
| 341 | + $this->mBlockInfo = $info; |
| 342 | + |
| 343 | + if( !$info ) return ''; |
| 344 | + |
| 345 | + $expirydate = wfMsg( 'checkuser-expires' ) . ' ' . $wgContLang->timeanddate( wfTimestamp( TS_MW, $info->ipb_expiry ), true ); |
| 346 | + |
| 347 | + if( !is_numeric( $info->ipb_expiry ) ) { |
| 348 | + $expirydate = ''; |
| 349 | + } |
| 350 | + |
| 351 | + return wfMsgExt( 'checkuser-blockedby', 'parseinline', $info->ipb_by_text, $info->ipb_reason, $wgContLang->timeanddate( wfTimestamp( TS_MW, $info->ipb_timestamp ), true ), $expirydate ); |
| 352 | + } |
| 353 | + |
| 354 | + function getCellAttrs( $field, $value ) { |
| 355 | + $retArr = array( 'class' => 'TablePager_col_' . $field ); |
| 356 | + |
| 357 | + if( |
| 358 | + ( $field == 'first' && $value == $this->mCurrentRow->last ) || |
| 359 | + ( $field == 'last' && $value == $this->mCurrentRow->first ) |
| 360 | + ) { |
| 361 | + $retArr['style'] = 'background-color: #FFFFCC;'; |
| 362 | + } |
| 363 | + |
| 364 | + return $retArr; |
| 365 | + } |
| 366 | + |
| 367 | + function getFieldNames() { |
| 368 | + $fields = array( |
| 369 | + $this->getDefaultSort() => wfMsg( 'checkuser-cuc_ip' ), |
| 370 | + 'count' => wfMsg( 'checkuser-count' ), |
| 371 | + 'allusers' => wfMsg( 'checkuser-allusers' ), |
| 372 | + 'first' => wfMsg( 'checkuser-first' ), |
| 373 | + 'last' => wfMsg( 'checkuser-last' ), |
| 374 | + 'blockinfo' => wfMsg( 'checkuser-blockinfo' ), |
| 375 | + ); |
| 376 | + return $fields; |
| 377 | + } |
| 378 | + |
| 379 | + function getTitle() { |
| 380 | + return SpecialPage::getTitleFor( 'CheckUser', false ); |
| 381 | + } |
| 382 | + |
| 383 | + function formatRow( $row ) { |
| 384 | + $this->mCurrentRow = $row; # In case formatValue etc need to know |
| 385 | + $this->mBlockInfo = CheckUser::checkBlockInfo( $this->mCurrentRow->cuc_ip ); |
| 386 | + |
| 387 | + $s = Xml::openElement( 'tr', $this->getRowAttrs($row) ); |
| 388 | + $fieldNames = $this->getFieldNames(); |
| 389 | + foreach ( $fieldNames as $field => $name ) { |
| 390 | + if( $field == 'blockinfo' || $field == 'allusers' ) continue; |
| 391 | + $value = isset( $row->$field ) ? $row->$field : null; |
| 392 | + $formatted = strval( $this->formatValue( $field, $value ) ); |
| 393 | + if ( $formatted == '' ) { |
| 394 | + $formatted = ' '; |
| 395 | + } |
| 396 | + $s .= Xml::tags( 'td', $this->getCellAttrs( $field, $value ), $formatted ); |
| 397 | + } |
| 398 | + $s .= "</tr>\n"; |
| 399 | + return $s; |
| 400 | + } |
| 401 | + |
| 402 | +} |