Index: branches/new-checkuser/CheckUser.i18n.en.php |
— | — | @@ -77,12 +77,12 @@ |
78 | 78 | 'checkuser-ipeditcount' => '~$1 from all users', |
79 | 79 | 'checkuser-log-subpage' => 'Log', |
80 | 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', |
| 81 | + 'checkuser-log-user2ip' => '$1 got IP addresses for $2', |
| 82 | + 'checkuser-log-ip2edits' => '$1 got edits for $2', |
| 83 | + 'checkuser-log-ip2user' => '$1 got users for $2', |
| 84 | + 'checkuser-log-ip2edits-xff' => '$1 got edits for XFF $2', |
| 85 | + 'checkuser-log-ip2user-xff' => '$1 got users for XFF $2', |
| 86 | + 'checkuser-log-user2edits' => '$1 got edits for $2', |
87 | 87 | |
88 | 88 | 'checkuser-autocreate-action' => 'was automatically created', |
89 | 89 | 'checkuser-email-action' => 'sent an email to user "$1"', |
— | — | @@ -106,4 +106,5 @@ |
107 | 107 | 'checkuser-last' => 'Last use', |
108 | 108 | 'checkuser-blockinfo' => 'Block info', |
109 | 109 | 'checkuser-expires' => 'Expires', |
| 110 | + 'checkuser-limit' => 'Results to show:', |
110 | 111 | ); |
\ No newline at end of file |
Index: branches/new-checkuser/CheckUser.alias.php |
— | — | @@ -13,6 +13,7 @@ |
14 | 14 | */ |
15 | 15 | $aliases['en'] = array( |
16 | 16 | 'CheckUser' => array( 'CheckUser' ), |
| 17 | + 'CheckUserLog' => array( 'CheckUserLog' ), |
17 | 18 | ); |
18 | 19 | |
19 | 20 | /** Arabic (العربية) */ |
Index: branches/new-checkuser/CheckUserApi.php |
— | — | @@ -56,51 +56,38 @@ |
57 | 57 | |
58 | 58 | public function doUser2IP( &$cuClass, $params, $prop, $limit ) { |
59 | 59 | |
60 | | - $dbParams = $cuClass->doUser2IP( $params, $prop, $limit ); |
| 60 | + $result = $cuClass->doUser2IP( $params, $prop, $limit ); |
61 | 61 | |
62 | 62 | $retArray = array(); |
63 | 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; |
| 64 | + $counter = 0; |
80 | 65 | |
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 | | - } |
| 66 | + foreach( $result[0] as $id => $row ) { |
| 67 | + $retArray[$counter] = array( 'ip' => $row->cuc_ip ); |
| 68 | + |
| 69 | + if( in_array( 'count', $prop ) || is_null( $prop ) ) $retArray[$counter]['count'] = $row->count; |
| 70 | + if( in_array( 'first', $prop ) || is_null( $prop ) ) $retArray[$counter]['first'] = $row->first; |
| 71 | + if( in_array( 'last', $prop ) || is_null( $prop ) ) $retArray[$counter]['last'] = $row->last; |
| 72 | + if( in_array( 'hex', $prop ) || is_null( $prop ) ) $retArray[$counter]['hex'] = $row->cuc_ip_hex; |
| 73 | + if( in_array( 'blockinfo', $prop ) || is_null( $prop ) ) { |
| 74 | + $blockinfo = CheckUser::checkBlockInfo( $row->cuc_ip ); |
| 75 | + if( $blockinfo ) { |
| 76 | + $retArray[$counter]['blockinfo'] = array(); |
| 77 | + $retArray[$counter]['blockinfo']['by'] = $blockinfo->ipb_by_text; |
| 78 | + $retArray[$counter]['blockinfo']['reason'] = $blockinfo->ipb_reason; |
| 79 | + $retArray[$counter]['blockinfo']['timestamp'] = $blockinfo->ipb_timestamp; |
| 80 | + $retArray[$counter]['blockinfo']['expiry'] = $blockinfo->ipb_expiry; |
96 | 81 | } |
97 | | - |
98 | | - $counter++; |
99 | | - |
100 | 82 | } |
| 83 | + if( in_array( 'alledits', $prop ) || is_null( $prop ) ) { |
| 84 | + $retArray[$counter]['alledits'] = CheckUser::getAllEdits( $row->cuc_ip_hex, $result[1] ); |
| 85 | + } |
| 86 | + |
| 87 | + $counter++; |
| 88 | + |
101 | 89 | } |
102 | 90 | |
103 | | - $dbr->freeResult( $ret ); |
104 | | - |
| 91 | + |
105 | 92 | return $retArray; |
106 | 93 | } |
107 | 94 | |
— | — | @@ -128,13 +115,14 @@ |
129 | 116 | ), |
130 | 117 | 'prop' => array( |
131 | 118 | ApiBase::PARAM_ISMULTI => true, |
132 | | - ApiBase::PARAM_DFLT => 'count|first|last|blockinfo', |
| 119 | + ApiBase::PARAM_DFLT => 'count|first|last|blockinfo|alledits', |
133 | 120 | ApiBase::PARAM_TYPE => array( |
134 | 121 | 'count', |
135 | 122 | 'first', |
136 | 123 | 'last', |
137 | 124 | 'hex', |
138 | 125 | 'blockinfo', |
| 126 | + 'alledits', |
139 | 127 | ) |
140 | 128 | ), |
141 | 129 | 'limit' => array( |
Index: branches/new-checkuser/CheckUser.body.php |
— | — | @@ -0,0 +1,183 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class CheckUser { |
| 5 | + |
| 6 | + var $target; |
| 7 | + |
| 8 | + function __construct( $target ) { |
| 9 | + $this->target = $target; |
| 10 | + } |
| 11 | + |
| 12 | + function doUser2IP( $params, $prop = array(), $limit = '' ) { |
| 13 | + |
| 14 | + $userTitle = Title::newFromText( $this->target, NS_USER ); |
| 15 | + if ( !is_null( $userTitle ) ) { |
| 16 | + // normalize the username |
| 17 | + $user = $this->target = $userTitle->getText(); |
| 18 | + } |
| 19 | + |
| 20 | + # IPs are passed in as a blank string |
| 21 | + if ( !$user ) { |
| 22 | + return array( 'error' => 'nouserspecified' ); |
| 23 | + } |
| 24 | + |
| 25 | + # Get ID, works better than text as user may have been renamed |
| 26 | + $user_id = User::idFromName( $user ); |
| 27 | + |
| 28 | + # If user is not IP or nonexistent |
| 29 | + if ( !$user_id ) { |
| 30 | + return array( 'error' => 'nosuchusershort' ); |
| 31 | + } |
| 32 | + |
| 33 | + # Record check... |
| 34 | + if ( !$this->addLogEntry( 'user2ip', 'user', $user, $params['reason'], $user_id ) ) { |
| 35 | + $retArray['warn'] = 'checkuser-log-fail'; |
| 36 | + } |
| 37 | + |
| 38 | + $dbr = wfGetDB( DB_SLAVE ); |
| 39 | + $time_conds = $this->getTimeConds( $params['period'] ); |
| 40 | + # Ordering by the latest timestamp makes a small filesort on the IP list |
| 41 | + $cu_changes = $dbr->tableName( 'cu_changes' ); |
| 42 | + $use_index = $dbr->useIndexClause( 'cuc_user_ip_time' ); |
| 43 | + |
| 44 | + $select = array( |
| 45 | + 'cuc_ip', |
| 46 | + 'cuc_ip_hex', |
| 47 | + 'cuc_user', |
| 48 | + 'COUNT(*) AS count', |
| 49 | + 'MIN(cuc_timestamp) AS first', |
| 50 | + 'MAX(cuc_timestamp) AS last' |
| 51 | + ); |
| 52 | + |
| 53 | + $opts = array( |
| 54 | + 'GROUP BY' => 'cuc_ip,cuc_ip_hex', |
| 55 | + 'ORDER BY' => 'last DESC', |
| 56 | + 'USE INDEX' => 'cuc_user_ip_time' |
| 57 | + ); |
| 58 | + |
| 59 | + if( !empty( $limit ) ) $opts['LIMIT'] = $limit; |
| 60 | + |
| 61 | + $ret = $dbr->select( |
| 62 | + $cu_changes, |
| 63 | + $select, |
| 64 | + array( |
| 65 | + 'cuc_user' => $user_id, |
| 66 | + $time_conds |
| 67 | + ), |
| 68 | + __METHOD__, |
| 69 | + $opts |
| 70 | + ); |
| 71 | + |
| 72 | + if( !$ret->numRows() ) { |
| 73 | + return array(); |
| 74 | + } |
| 75 | + |
| 76 | + return array( $ret, $time_conds ); |
| 77 | + |
| 78 | + } |
| 79 | + |
| 80 | + function doUser2Edits() { |
| 81 | + } |
| 82 | + |
| 83 | + function doIP2User() { |
| 84 | + } |
| 85 | + |
| 86 | + function doIP2Edits() { |
| 87 | + } |
| 88 | + |
| 89 | + protected function addLogEntry( $logType, $targetType, $target, $reason, $targetID = 0 ) { |
| 90 | + global $wgUser; |
| 91 | + |
| 92 | + if ( $targetType == 'ip' ) { |
| 93 | + list( $rangeStart, $rangeEnd ) = IP::parseRange( $target ); |
| 94 | + $targetHex = $rangeStart; |
| 95 | + if ( $rangeStart == $rangeEnd ) { |
| 96 | + $rangeStart = $rangeEnd = ''; |
| 97 | + } |
| 98 | + } else { |
| 99 | + $targetHex = $rangeStart = $rangeEnd = ''; |
| 100 | + } |
| 101 | + |
| 102 | + $dbw = wfGetDB( DB_MASTER ); |
| 103 | + $cul_id = $dbw->nextSequenceValue( 'cu_log_cul_id_seq' ); |
| 104 | + $dbw->insert( 'cu_log', |
| 105 | + array( |
| 106 | + 'cul_id' => $cul_id, |
| 107 | + 'cul_timestamp' => $dbw->timestamp(), |
| 108 | + 'cul_user' => $wgUser->getID(), |
| 109 | + 'cul_user_text' => $wgUser->getName(), |
| 110 | + 'cul_reason' => $reason, |
| 111 | + 'cul_type' => $logType, |
| 112 | + 'cul_target_id' => $targetID, |
| 113 | + 'cul_target_text' => $target, |
| 114 | + 'cul_target_hex' => $targetHex, |
| 115 | + 'cul_range_start' => $rangeStart, |
| 116 | + 'cul_range_end' => $rangeEnd, |
| 117 | + ), __METHOD__ ); |
| 118 | + return true; |
| 119 | + } |
| 120 | + |
| 121 | + function getIPType() { |
| 122 | + } |
| 123 | + |
| 124 | + public static function checkBlockInfo( $name ) { |
| 125 | + $dbr = wfGetDB( DB_SLAVE ); |
| 126 | + |
| 127 | + $ret = $dbr->select( |
| 128 | + 'ipblocks', |
| 129 | + array( |
| 130 | + 'ipb_by_text', |
| 131 | + 'ipb_reason', |
| 132 | + 'ipb_timestamp', |
| 133 | + 'ipb_expiry' |
| 134 | + ), |
| 135 | + array( |
| 136 | + 'ipb_address' => $name |
| 137 | + ), |
| 138 | + __METHOD__ |
| 139 | + ); |
| 140 | + |
| 141 | + |
| 142 | + foreach( $ret as $res ) { |
| 143 | + $return = $res; |
| 144 | + break; |
| 145 | + } |
| 146 | + |
| 147 | + $dbr->freeResult( $ret ); |
| 148 | + |
| 149 | + if( isset( $return ) ) return $return; |
| 150 | + |
| 151 | + return false; |
| 152 | + } |
| 153 | + |
| 154 | + public static function getAllEdits( $hex, $time_conds ) { |
| 155 | + $dbr = wfGetDB( DB_SLAVE ); |
| 156 | + |
| 157 | + $ipedits = $dbr->estimateRowCount( 'cu_changes', '*', |
| 158 | + array( 'cuc_ip_hex' => $hex, $time_conds ), |
| 159 | + __METHOD__ ); |
| 160 | + # If small enough, get a more accurate count |
| 161 | + if ( $ipedits <= 1000 ) { |
| 162 | + $ipedits = $dbr->selectField( 'cu_changes', 'COUNT(*)', |
| 163 | + array( 'cuc_ip_hex' => $hex, $time_conds ), |
| 164 | + __METHOD__ ); |
| 165 | + } |
| 166 | + |
| 167 | + return $ipedits; |
| 168 | + } |
| 169 | + |
| 170 | + protected function getTimeConds( $period ) { |
| 171 | + |
| 172 | + if ( !$period ) { |
| 173 | + return '1 = 1'; |
| 174 | + } |
| 175 | + |
| 176 | + $dbr = wfGetDB( DB_SLAVE ); |
| 177 | + $cutoff_unixtime = time() - ( $period * 24 * 3600 ); |
| 178 | + $cutoff_unixtime = $cutoff_unixtime - ( $cutoff_unixtime % 86400 ); |
| 179 | + $cutoff = $dbr->addQuotes( $dbr->timestamp( $cutoff_unixtime ) ); |
| 180 | + return "cuc_timestamp > $cutoff"; |
| 181 | + } |
| 182 | + |
| 183 | + |
| 184 | +} |
\ No newline at end of file |
Index: branches/new-checkuser/CheckUser.pager.php |
— | — | @@ -0,0 +1,226 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +abstract class CUTablePager extends TablePager { |
| 5 | + |
| 6 | + public $mLimitsShown; |
| 7 | + public $mTimeConds; |
| 8 | + |
| 9 | + function __construct( $result = array(), $index = 'cuc_ip' ) { |
| 10 | + parent::__construct(); |
| 11 | + |
| 12 | + $this->mIndexField = $index; |
| 13 | + $this->mResult = $result[0]; |
| 14 | + $this->mTimeConds = $result[1]; |
| 15 | + |
| 16 | + } |
| 17 | + |
| 18 | + /* This function normally does a database query to get the results; we need |
| 19 | + * to make a pretend result using a FakeResultWrapper. |
| 20 | + */ |
| 21 | + function reallyDoQuery( $offset, $limit, $descending ) { |
| 22 | + global $wgRequest; |
| 23 | + |
| 24 | + $result = array(); |
| 25 | + |
| 26 | + $index = ( $wgRequest->getVal( 'sort' ) ) ? $wgRequest->getVal( 'sort' ) : $this->mIndexField; |
| 27 | + |
| 28 | + if ( $descending ) { |
| 29 | + $operator = '>'; |
| 30 | + |
| 31 | + $obj = new CUSortArray( 'DESC', $index ); |
| 32 | + } else { |
| 33 | + $operator = '<'; |
| 34 | + |
| 35 | + $obj = new CUSortArray( 'ASC', $index ); |
| 36 | + } |
| 37 | + |
| 38 | + $forNow = array(); |
| 39 | + |
| 40 | + foreach( $this->mResult as $row ) { |
| 41 | + $row = (array) $row; |
| 42 | + |
| 43 | + $forNow[] = $this->fixRowResult( $row ); |
| 44 | + } |
| 45 | + |
| 46 | + $this->mResult = $forNow; |
| 47 | + |
| 48 | + usort( $this->mResult, array( $obj, 'run' ) ); |
| 49 | + |
| 50 | + $count = 0; |
| 51 | + foreach( $this->mResult as $res ) { |
| 52 | + |
| 53 | + if ( $offset != '' ) { |
| 54 | + if ( $descending ) { |
| 55 | + if( $res[$this->mIndexField] > $offset ) continue; |
| 56 | + } else { |
| 57 | + if( $res[$this->mIndexField] < $offset ) continue; |
| 58 | + } |
| 59 | + |
| 60 | + } |
| 61 | + |
| 62 | + $result[] = $res; |
| 63 | + |
| 64 | + $count++; |
| 65 | + |
| 66 | + if( $count == $limit ) break; |
| 67 | + } |
| 68 | + |
| 69 | + return new FakeResultWrapper( $result ); |
| 70 | + } |
| 71 | + |
| 72 | + abstract function fixRowResult( $row ); |
| 73 | + |
| 74 | + function getTitle() { |
| 75 | + return SpecialPage::getTitleFor( 'CheckUser', false ); |
| 76 | + } |
| 77 | + |
| 78 | + function isFieldSortable( $field ) { |
| 79 | + return true; |
| 80 | + } |
| 81 | + |
| 82 | + function getQueryInfo() { |
| 83 | + return ''; |
| 84 | + } |
| 85 | + |
| 86 | +} |
| 87 | + |
| 88 | +class CUTablePagerUser2IP extends CUTablePager { |
| 89 | + |
| 90 | + function fixRowResult( $row ) { |
| 91 | + $row['allusers'] = CheckUser::getAllEdits( $row['cuc_ip_hex'], $this->mTimeConds ); |
| 92 | + |
| 93 | + $blockinfo = CheckUser::checkBlockInfo( $row['cuc_ip'] ); |
| 94 | + $row['blockinfo'] = $blockinfo; |
| 95 | + |
| 96 | + if( $blockinfo ) { |
| 97 | + $row['blockinfo'] = array(); |
| 98 | + |
| 99 | + $row['blockinfo']['by'] = $blockinfo->ipb_by_text; |
| 100 | + $row['blockinfo']['reason'] = $blockinfo->ipb_reason; |
| 101 | + $row['blockinfo']['timestamp'] = $blockinfo->ipb_timestamp; |
| 102 | + $row['blockinfo']['expiry'] = $blockinfo->ipb_expiry; |
| 103 | + } |
| 104 | + |
| 105 | + return $row; |
| 106 | + } |
| 107 | + |
| 108 | + function formatValue( $field, $value ) { |
| 109 | + global $wgContLang; |
| 110 | + |
| 111 | + switch( $field ) { |
| 112 | + case 'cuc_ip': |
| 113 | + return '<a href="' . |
| 114 | + $this->getTitle()->escapeLocalURL( 'user=' . urlencode( $value ) . '&reason=' . urlencode( $reason ) ) . '">' . |
| 115 | + htmlspecialchars( $value ) . '</a>' . |
| 116 | + ' (<a href="' . SpecialPage::getTitleFor( 'Blockip' )->escapeLocalURL( 'ip=' . urlencode( $value ) ) . '">' . |
| 117 | + wfMsgHtml( 'blocklink' ) . '</a>)<br /><small>' . |
| 118 | + wfMsgExt( 'checkuser-toollinks', array( 'parseinline' ), urlencode( $value ) ) . '</small>'; |
| 119 | + |
| 120 | + break; |
| 121 | + case 'first': |
| 122 | + return $wgContLang->timeanddate( wfTimestamp( TS_MW, $value ), true ); |
| 123 | + break; |
| 124 | + case 'last': |
| 125 | + return $wgContLang->timeanddate( wfTimestamp( TS_MW, $value ), true ); |
| 126 | + break; |
| 127 | + case 'blockinfo': |
| 128 | + return $this->fixBlockInfo( $value ); |
| 129 | + break; |
| 130 | + } |
| 131 | + |
| 132 | + return $value; |
| 133 | + } |
| 134 | + |
| 135 | + private function fixBlockInfo( $value ) { |
| 136 | + global $wgContLang; |
| 137 | + |
| 138 | + if( !$value ) return ''; |
| 139 | + |
| 140 | + $expirydate = wfMsg( 'checkuser-expires' ) . ' ' . $wgContLang->timeanddate( wfTimestamp( TS_MW, $value['expiry'] ), true ); |
| 141 | + |
| 142 | + if( !is_numeric( $value['expiry'] ) ) { |
| 143 | + $expirydate = ''; |
| 144 | + } |
| 145 | + |
| 146 | + return wfMsgExt( 'checkuser-blockedby', 'parseinline', $value['by'], $value['reason'], $wgContLang->timeanddate( wfTimestamp( TS_MW, $value['timestamp'] ), true ), $expirydate ); |
| 147 | + } |
| 148 | + |
| 149 | + function getCellAttrs( $field, $value ) { |
| 150 | + $retArr = array( 'class' => 'TablePager_col_' . $field ); |
| 151 | + |
| 152 | + if( |
| 153 | + ( $field == 'first' && $value == $this->mCurrentRow->last ) || |
| 154 | + ( $field == 'last' && $value == $this->mCurrentRow->first ) || |
| 155 | + ( $field == 'blockinfo' && !empty( $value ) ) |
| 156 | + ) { |
| 157 | + $retArr['style'] = 'background-color: #FFFFCC;'; |
| 158 | + |
| 159 | + if( $field == 'blockinfo' ) { |
| 160 | + $retArr['style'] .= 'width: 33%;'; |
| 161 | + } |
| 162 | + } |
| 163 | + |
| 164 | + return $retArr; |
| 165 | + } |
| 166 | + |
| 167 | + function getFieldNames() { |
| 168 | + $fields = array( |
| 169 | + $this->getDefaultSort() => wfMsg( 'checkuser-cuc_ip' ), |
| 170 | + 'count' => wfMsg( 'checkuser-count' ), |
| 171 | + 'allusers' => wfMsg( 'checkuser-allusers' ), |
| 172 | + 'first' => wfMsg( 'checkuser-first' ), |
| 173 | + 'last' => wfMsg( 'checkuser-last' ), |
| 174 | + 'blockinfo' => wfMsg( 'checkuser-blockinfo' ), |
| 175 | + ); |
| 176 | + return $fields; |
| 177 | + } |
| 178 | + |
| 179 | + function getDefaultSort() { |
| 180 | + return 'cuc_ip'; |
| 181 | + } |
| 182 | + |
| 183 | +} |
| 184 | + |
| 185 | +class CUSortArray { |
| 186 | + |
| 187 | + var $dir, $index; |
| 188 | + |
| 189 | + function __construct( $dir, $index ) { |
| 190 | + $this->dir = $dir; |
| 191 | + $this->index = $index; |
| 192 | + } |
| 193 | + |
| 194 | + function run( $old, $new ) { |
| 195 | + if( $this->index == "blockinfo" ) { |
| 196 | + |
| 197 | + if( $this->dir == "DESC" ) { |
| 198 | + return $this->runeval( $old, $new ); |
| 199 | + } |
| 200 | + else { |
| 201 | + return $this->runeval( $new, $old ); |
| 202 | + } |
| 203 | + } |
| 204 | + else { |
| 205 | + if( $this->dir == "DESC" ) { |
| 206 | + return strnatcmp( $old[$this->index], $new[$this->index] ); |
| 207 | + } |
| 208 | + else { |
| 209 | + return strnatcmp( $new[$this->index], $old[$this->index] ); |
| 210 | + } |
| 211 | + } |
| 212 | + } |
| 213 | + |
| 214 | + function runeval( $old, $new ) { |
| 215 | + $oper = ( $this->dir == "DESC" ) ? -1 : 1; |
| 216 | + |
| 217 | + if( !isset( $old[$this->index]['timestamp'] ) ) { |
| 218 | + return -1; |
| 219 | + } |
| 220 | + elseif( !isset( $new[$this->index]['timestamp'] ) ) { |
| 221 | + return 1; |
| 222 | + } |
| 223 | + else { |
| 224 | + return $oper * strnatcmp( $old[$this->index]['timestamp'], $new[$this->index]['timestamp'] ); |
| 225 | + } |
| 226 | + } |
| 227 | +} |
\ No newline at end of file |
Index: branches/new-checkuser/CheckUser.php |
— | — | @@ -44,18 +44,22 @@ |
45 | 45 | $wgHooks['ContributionsToolLinks'][] = 'efLoadCheckUserLink'; |
46 | 46 | |
47 | 47 | $wgAutoloadClasses['SpecialCheckUser'] = $dir . 'SpecialCheckUser.php'; |
| 48 | +$wgAutoloadClasses['SpecialCheckUserLog'] = $dir . 'SpecialCheckUserLog.php'; |
48 | 49 | $wgAutoloadClasses['CheckUserApi'] = $dir . 'CheckUserApi.php'; |
49 | 50 | $wgAutoloadClasses['CheckUserApiLog'] = $dir . 'CheckUserApiLog.php'; |
50 | 51 | $wgAutoloadClasses['CheckUser'] = $dir . 'CheckUser.body.php'; |
| 52 | +$wgAutoloadClasses['CUTablePagerUser2IP'] = $dir . 'CheckUser.pager.php'; |
51 | 53 | |
52 | 54 | // Set up the new special page |
53 | 55 | $wgSpecialPages['CheckUser'] = 'SpecialCheckUser'; |
54 | 56 | $wgSpecialPageGroups['CheckUser'] = 'users'; |
| 57 | +$wgSpecialPages['CheckUserLog'] = 'SpecialCheckUserLog'; |
| 58 | +$wgSpecialPageGroups['CheckUserLog'] = 'users'; |
55 | 59 | |
56 | 60 | $wgAPIListModules['checkuser'] = 'CheckUserApi'; |
57 | 61 | $wgAPIListModules['checkuserlog'] = 'CheckUserApiLog'; |
58 | 62 | |
59 | | -$wgExtensionMessagesFiles['CheckUser'] = $dir . 'CheckUser.i18n.en.php'; |
| 63 | +$wgExtensionMessagesFiles['CheckUser'] = $wgExtensionMessagesFiles['CheckUser'] = $dir . 'CheckUser.i18n.en.php'; |
60 | 64 | //FIXME: $wgExtensionMessagesFiles['CheckUser'] = $dir . 'CheckUser.i18n.php'; |
61 | 65 | $wgExtensionAliasesFiles['CheckUser'] = $dir . 'CheckUser.alias.php'; |
62 | 66 | |
Index: branches/new-checkuser/SpecialCheckUser.php |
— | — | @@ -48,7 +48,7 @@ |
49 | 49 | } elseif ( $wgCheckUserForceSummary && !strlen( $reason ) ) { |
50 | 50 | $wgOut->addWikiMsg( 'checkuser-noreason' ); |
51 | 51 | } elseif ( $checktype == 'user2ip' ) { |
52 | | - //$this->doUser2IP( $user, $reason, $period ); |
| 52 | + $this->doUser2IP( $user, $reason, $period ); |
53 | 53 | } elseif ( $xff && $checktype == 'subipedits' ) { |
54 | 54 | $this->doIPEditsRequest( $xff, true, $reason, $period ); |
55 | 55 | } elseif ( $checktype == 'subipedits' ) { |
— | — | @@ -95,7 +95,7 @@ |
96 | 96 | ); |
97 | 97 | } |
98 | 98 | |
99 | | - $form = Xml::openElement( 'form', array( 'name' => 'checkuserform', 'id' => 'checkuserform', 'action' => $action, 'method' => 'post' ) ) . |
| 99 | + $form = Xml::openElement( 'form', array( 'name' => 'checkuserform', 'id' => 'checkuserform', 'action' => $action, 'method' => 'get' ) ) . |
100 | 100 | Xml::openElement( 'fieldset' ) . Xml::openElement( 'legend' ) . wfMsgHtml( 'checkuser-query' ) . Xml::closeElement( 'legend') . |
101 | 101 | Xml::openElement( 'table', array( 'border' => 0, 'cellpadding' => 2 ) ) . Xml::openElement( 'tr' ) . |
102 | 102 | Xml::openElement( 'td' ) . wfMsgHtml( 'checkuser-target' ) . Xml::closeElement( 'td' ) . |
— | — | @@ -125,6 +125,8 @@ |
126 | 126 | Xml::closeElement( 'tr' ) . Xml::openElement( 'tr' ) . |
127 | 127 | $this->getPeriodMenu( $period ) . |
128 | 128 | Xml::closeElement( 'tr' ) . Xml::openElement( 'tr' ) . |
| 129 | + $this->getLimitMenu() . |
| 130 | + Xml::closeElement( 'tr' ) . Xml::openElement( 'tr' ) . |
129 | 131 | Xml::openElement( 'td' ) . |
130 | 132 | Xml::submitButton( wfMsg( 'checkuser-check' ), array( 'id' => 'checkusersubmit', 'name' => 'checkusersubmit' ) ) . |
131 | 133 | Xml::closeElement( 'td' ) . Xml::closeElement( 'tr' ) . Xml::closeElement( 'table' ) . Xml::closeElement( 'fieldset' ) . |
— | — | @@ -176,6 +178,22 @@ |
177 | 179 | return $s; |
178 | 180 | } |
179 | 181 | |
| 182 | + protected function getLimitMenu() { |
| 183 | + global $wgRequest; |
| 184 | + |
| 185 | + $currLimit = $wgRequest->getVal( 'limit' ); |
| 186 | + |
| 187 | + $s = '<td>' . wfMsgHtml( 'checkuser-limit' ) . '</td>'; |
| 188 | + $s .= '<td>' . Xml::openElement( 'select', array( 'name' => 'limit', 'id' => 'limit', 'style' => 'margin-top:.2em;' ) ); |
| 189 | + |
| 190 | + foreach( array( 20, 50, 100, 250, 500, 5000 ) as $limit ) { |
| 191 | + $s .= Xml::option( $limit, $limit, $limit == $currLimit ); |
| 192 | + } |
| 193 | + |
| 194 | + $s .= Xml::closeElement( 'select' ) . "</td>\n"; |
| 195 | + return $s; |
| 196 | + } |
| 197 | + |
180 | 198 | /** |
181 | 199 | * Make a quick JS form for admins to calculate block ranges |
182 | 200 | */ |
— | — | @@ -210,7 +228,7 @@ |
211 | 229 | 'period' => $period |
212 | 230 | ) ); |
213 | 231 | |
214 | | - $pager = new CUTablePager( $result ); |
| 232 | + $pager = new CUTablePagerUser2IP( $result ); |
215 | 233 | |
216 | 234 | $output = |
217 | 235 | $pager->getNavigationBar() . |
— | — | @@ -234,7 +252,7 @@ |
235 | 253 | |
236 | 254 | } |
237 | 255 | |
238 | | -class CUTablePager extends TablePager { |
| 256 | +class CUTablePagerOld extends TablePager { |
239 | 257 | |
240 | 258 | private $mCUSelectParams; |
241 | 259 | private $mBlockInfo; |
— | — | @@ -246,6 +264,8 @@ |
247 | 265 | } |
248 | 266 | |
249 | 267 | function getQueryInfo() { |
| 268 | + $dbr = new wfGetDB( DB_SLAVE ); |
| 269 | + |
250 | 270 | $ret = array( |
251 | 271 | 'tables' => $this->mCUSelectParams[0], |
252 | 272 | 'fields' => $this->mCUSelectParams[1], |
— | — | @@ -271,7 +291,7 @@ |
272 | 292 | //} |
273 | 293 | |
274 | 294 | function isFieldSortable( $field ) { |
275 | | - return true; |
| 295 | + return in_array( $field, array( 'cuc_ip', 'first', 'last' ) ); |
276 | 296 | } |
277 | 297 | |
278 | 298 | function getDefaultSort() { |
— | — | @@ -281,6 +301,8 @@ |
282 | 302 | function formatValue( $name, $value ) { |
283 | 303 | global $wgContLang; |
284 | 304 | |
| 305 | + var_dump( $this->mCurrentRow ); |
| 306 | + |
285 | 307 | switch( $name ) { |
286 | 308 | case 'cuc_ip': |
287 | 309 | $value = '<a href="' . |
— | — | @@ -399,3 +421,6 @@ |
400 | 422 | } |
401 | 423 | |
402 | 424 | } |
| 425 | + |
| 426 | + |
| 427 | + |
Index: branches/new-checkuser/SpecialCheckUserLog.php |
— | — | @@ -0,0 +1,246 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class SpecialCheckUserLog extends SpecialPage { |
| 5 | + |
| 6 | + function __construct() { |
| 7 | + global $wgUser; |
| 8 | + |
| 9 | + parent::__construct( 'CheckUserLog', 'checkuser-log' ); |
| 10 | + } |
| 11 | + |
| 12 | + function execute( $subpage ) { |
| 13 | + global $wgRequest, $wgOut, $wgUser, $wgCheckUserForceSummary; |
| 14 | + |
| 15 | + wfLoadExtensionMessages( 'CheckUserLog' ); |
| 16 | + |
| 17 | + $this->setHeaders(); |
| 18 | + |
| 19 | + if ( !$wgUser->isAllowed( 'checkuser-log' ) ) { |
| 20 | + $wgOut->permissionRequired( 'checkuser-log' ); |
| 21 | + return; |
| 22 | + } |
| 23 | + |
| 24 | + $this->showLog(); |
| 25 | + } |
| 26 | + |
| 27 | + protected function showLog() { |
| 28 | + global $wgRequest, $wgOut, $wgUser; |
| 29 | + |
| 30 | + $type = $wgRequest->getVal( 'cuSearchType' ); |
| 31 | + $target = $wgRequest->getVal( 'cuSearch' ); |
| 32 | + $year = $wgRequest->getIntOrNull( 'year' ); |
| 33 | + $month = $wgRequest->getIntOrNull( 'month' ); |
| 34 | + $error = false; |
| 35 | + $dbr = wfGetDB( DB_SLAVE ); |
| 36 | + $searchConds = false; |
| 37 | + |
| 38 | + $wgOut->setPageTitle( wfMsg( 'checkuser-log' ) ); |
| 39 | + |
| 40 | + $wgOut->addHTML( $wgUser->getSkin()->makeKnownLinkObj( $this->getTitle(), wfMsgHtml( 'checkuser-log-return' ) ) ); |
| 41 | + |
| 42 | + if ( $type === null ) { |
| 43 | + $type = 'target'; |
| 44 | + } elseif ( $type == 'initiator' ) { |
| 45 | + $user = User::newFromName( $target ); |
| 46 | + if ( !$user || !$user->getID() ) { |
| 47 | + $error = 'checkuser-user-nonexistent'; |
| 48 | + } else { |
| 49 | + $searchConds = array( 'cul_user' => $user->getID() ); |
| 50 | + } |
| 51 | + } else /* target */ { |
| 52 | + $type = 'target'; |
| 53 | + // Is it an IP? |
| 54 | + list( $start, $end ) = IP::parseRange( $target ); |
| 55 | + if ( $start !== false ) { |
| 56 | + if ( $start == $end ) { |
| 57 | + $searchConds = array( 'cul_target_hex = ' . $dbr->addQuotes( $start ) . ' OR ' . |
| 58 | + '(cul_range_end >= ' . $dbr->addQuotes( $start ) . ' AND ' . |
| 59 | + 'cul_range_start <= ' . $dbr->addQuotes( $end ) . ')' |
| 60 | + ); |
| 61 | + } else { |
| 62 | + $searchConds = array( |
| 63 | + '(cul_target_hex >= ' . $dbr->addQuotes( $start ) . ' AND ' . |
| 64 | + 'cul_target_hex <= ' . $dbr->addQuotes( $end ) . ') OR ' . |
| 65 | + '(cul_range_end >= ' . $dbr->addQuotes( $start ) . ' AND ' . |
| 66 | + 'cul_range_start <= ' . $dbr->addQuotes( $end ) . ')' |
| 67 | + ); |
| 68 | + } |
| 69 | + } else { |
| 70 | + // Is it a user? |
| 71 | + $user = User::newFromName( $target ); |
| 72 | + if ( $user && $user->getID() ) { |
| 73 | + $searchConds = array( |
| 74 | + 'cul_type' => array( 'userips', 'useredits' ), |
| 75 | + 'cul_target_id' => $user->getID(), |
| 76 | + ); |
| 77 | + } elseif ( $target ) { |
| 78 | + $error = 'checkuser-user-nonexistent'; |
| 79 | + } |
| 80 | + } |
| 81 | + } |
| 82 | + |
| 83 | + $searchTypes = array( 'initiator', 'target' ); |
| 84 | + $select = "<select name=\"cuSearchType\" style='margin-top:.2em;'>\n"; |
| 85 | + foreach ( $searchTypes as $searchType ) { |
| 86 | + if ( $type == $searchType ) { |
| 87 | + $checked = 'selected="selected"'; |
| 88 | + } else { |
| 89 | + $checked = ''; |
| 90 | + } |
| 91 | + $caption = wfMsgHtml( 'checkuser-search-' . $searchType ); |
| 92 | + $select .= "<option value=\"$searchType\" $checked>$caption</option>\n"; |
| 93 | + } |
| 94 | + $select .= '</select>'; |
| 95 | + |
| 96 | + $encTarget = htmlspecialchars( $target ); |
| 97 | + $msgSearch = wfMsgHtml( 'checkuser-search' ); |
| 98 | + $input = "<input type=\"text\" name=\"cuSearch\" value=\"$encTarget\" size=\"40\"/>"; |
| 99 | + $msgSearchForm = wfMsgHtml( 'checkuser-search-form', $select, $input ); |
| 100 | + $formAction = $this->getTitle()->escapeLocalUrl(); |
| 101 | + $msgSearchSubmit = '  ' . wfMsgHtml( 'checkuser-search-submit' ) . '  '; |
| 102 | + |
| 103 | + $s = "<form method='get' action=\"$formAction\">\n" . |
| 104 | + "<fieldset><legend>$msgSearch</legend>\n" . |
| 105 | + "<p>$msgSearchForm</p>\n" . |
| 106 | + "<p>" . $this->getDateMenu( $year, $month ) . "   \n" . |
| 107 | + "<input type=\"submit\" name=\"cuSearchSubmit\" value=\"$msgSearchSubmit\"/></p>\n" . |
| 108 | + "</fieldset></form>\n"; |
| 109 | + $wgOut->addHTML( $s ); |
| 110 | + |
| 111 | + if ( $error !== false ) { |
| 112 | + $wgOut->addWikiText( '<div class="errorbox">' . wfMsg( $error ) . '</div>' ); |
| 113 | + return; |
| 114 | + } |
| 115 | + |
| 116 | + $pager = new CheckUserLogPager( $this, $searchConds, $year, $month ); |
| 117 | + $wgOut->addHTML( |
| 118 | + $pager->getNavigationBar() . |
| 119 | + $pager->getBody() . |
| 120 | + $pager->getNavigationBar() |
| 121 | + ); |
| 122 | + } |
| 123 | + |
| 124 | + /** |
| 125 | + * @return string Formatted HTML |
| 126 | + * @param int $year |
| 127 | + * @param int $month |
| 128 | + */ |
| 129 | + protected function getDateMenu( $year, $month ) { |
| 130 | + # Offset overrides year/month selection |
| 131 | + if ( $month && $month !== - 1 ) { |
| 132 | + $encMonth = intval( $month ); |
| 133 | + } else { |
| 134 | + $encMonth = ''; |
| 135 | + } |
| 136 | + if ( $year ) { |
| 137 | + $encYear = intval( $year ); |
| 138 | + } elseif ( $encMonth ) { |
| 139 | + $thisMonth = intval( gmdate( 'n' ) ); |
| 140 | + $thisYear = intval( gmdate( 'Y' ) ); |
| 141 | + if ( intval( $encMonth ) > $thisMonth ) { |
| 142 | + $thisYear--; |
| 143 | + } |
| 144 | + $encYear = $thisYear; |
| 145 | + } else { |
| 146 | + $encYear = ''; |
| 147 | + } |
| 148 | + return Xml::label( wfMsg( 'year' ), 'year' ) . ' ' . |
| 149 | + Xml::input( 'year', 4, $encYear, array( 'id' => 'year', 'maxlength' => 4 ) ) . |
| 150 | + ' ' . |
| 151 | + Xml::label( wfMsg( 'month' ), 'month' ) . ' ' . |
| 152 | + Xml::monthSelector( $encMonth, - 1 ); |
| 153 | + } |
| 154 | + |
| 155 | +} |
| 156 | + |
| 157 | +class CheckUserLogPager extends ReverseChronologicalPager { |
| 158 | + var $searchConds, $specialPage, $y, $m; |
| 159 | + |
| 160 | + function __construct( $specialPage, $searchConds, $y, $m ) { |
| 161 | + parent::__construct(); |
| 162 | + /* |
| 163 | + $this->messages = array_map( 'wfMsg', |
| 164 | + array( 'comma-separator', 'checkuser-log-userips', 'checkuser-log-ipedits', 'checkuser-log-ipusers', |
| 165 | + 'checkuser-log-ipedits-xff', 'checkuser-log-ipusers-xff' ) );*/ |
| 166 | + |
| 167 | + $this->getDateCond( $y, $m ); |
| 168 | + $this->searchConds = $searchConds ? $searchConds : array(); |
| 169 | + $this->specialPage = $specialPage; |
| 170 | + } |
| 171 | + |
| 172 | + function formatRow( $row ) { |
| 173 | + global $wgLang; |
| 174 | + |
| 175 | + $skin = $this->getSkin(); |
| 176 | + |
| 177 | + if ( $row->cul_reason === '' ) { |
| 178 | + $comment = ''; |
| 179 | + } else { |
| 180 | + $comment = $skin->commentBlock( $row->cul_reason ); |
| 181 | + } |
| 182 | + |
| 183 | + $user = $skin->userLink( $row->cul_user, $row->user_name ); |
| 184 | + |
| 185 | + if ( $row->cul_type == 'userips' || $row->cul_type == 'useredits' ) { |
| 186 | + $target = $skin->userLink( $row->cul_target_id, $row->cul_target_text ) . |
| 187 | + $skin->userToolLinks( $row->cul_target_id, $row->cul_target_text ); |
| 188 | + } else { |
| 189 | + $target = $row->cul_target_text; |
| 190 | + } |
| 191 | + |
| 192 | + return '<li>' . |
| 193 | + $wgLang->timeanddate( wfTimestamp( TS_MW, $row->cul_timestamp ), true ) . |
| 194 | + wfMsg( 'comma-separator' ) . |
| 195 | + wfMsg( |
| 196 | + 'checkuser-log-' . $row->cul_type, |
| 197 | + $user, |
| 198 | + $target |
| 199 | + ) . |
| 200 | + $comment . |
| 201 | + '</li>'; |
| 202 | + } |
| 203 | + |
| 204 | + function getStartBody() { |
| 205 | + if ( $this->getNumRows() ) { |
| 206 | + return '<ul>'; |
| 207 | + } else { |
| 208 | + return ''; |
| 209 | + } |
| 210 | + } |
| 211 | + |
| 212 | + function getEndBody() { |
| 213 | + if ( $this->getNumRows() ) { |
| 214 | + return '</ul>'; |
| 215 | + } else { |
| 216 | + return ''; |
| 217 | + } |
| 218 | + } |
| 219 | + |
| 220 | + function getEmptyBody() { |
| 221 | + return '<p>' . wfMsgHtml( 'checkuser-empty' ) . '</p>'; |
| 222 | + } |
| 223 | + |
| 224 | + function getQueryInfo() { |
| 225 | + $this->searchConds[] = 'user_id = cul_user'; |
| 226 | + return array( |
| 227 | + 'tables' => array( 'cu_log', 'user' ), |
| 228 | + 'fields' => $this->selectFields(), |
| 229 | + 'conds' => $this->searchConds |
| 230 | + ); |
| 231 | + } |
| 232 | + |
| 233 | + function getIndexField() { |
| 234 | + return 'cul_timestamp'; |
| 235 | + } |
| 236 | + |
| 237 | + function getTitle() { |
| 238 | + return $this->specialPage->getTitle(); |
| 239 | + } |
| 240 | + |
| 241 | + function selectFields() { |
| 242 | + return array( |
| 243 | + 'cul_id', 'cul_timestamp', 'cul_user', 'cul_reason', 'cul_type', |
| 244 | + 'cul_target_id', 'cul_target_text', 'user_name' |
| 245 | + ); |
| 246 | + } |
| 247 | +} |