Index: trunk/phase3/includes/AutoLoader.php |
— | — | @@ -660,6 +660,7 @@ |
661 | 661 | 'SpecialFilepath' => 'includes/specials/SpecialFilepath.php', |
662 | 662 | 'SpecialImport' => 'includes/specials/SpecialImport.php', |
663 | 663 | 'SpecialListGroupRights' => 'includes/specials/SpecialListgrouprights.php', |
| 664 | + 'SpecialListusers' => 'includes/specials/SpecialListusers.php', |
664 | 665 | 'SpecialLockdb' => 'includes/specials/SpecialLockdb.php', |
665 | 666 | 'SpecialLog' => 'includes/specials/SpecialLog.php', |
666 | 667 | 'SpecialMergeHistory' => 'includes/specials/SpecialMergeHistory.php', |
— | — | @@ -695,7 +696,6 @@ |
696 | 697 | 'UploadForm' => 'includes/specials/SpecialUpload.php', |
697 | 698 | 'UploadSourceField' => 'includes/specials/SpecialUpload.php', |
698 | 699 | 'UserrightsPage' => 'includes/specials/SpecialUserrights.php', |
699 | | - 'UsersPager' => 'includes/specials/SpecialListusers.php', |
700 | 700 | 'WantedCategoriesPage' => 'includes/specials/SpecialWantedcategories.php', |
701 | 701 | 'WantedFilesPage' => 'includes/specials/SpecialWantedfiles.php', |
702 | 702 | 'WantedPagesPage' => 'includes/specials/SpecialWantedpages.php', |
Index: trunk/phase3/includes/specials/SpecialListusers.php |
— | — | @@ -32,7 +32,7 @@ |
33 | 33 | * |
34 | 34 | * @ingroup SpecialPage |
35 | 35 | */ |
36 | | -class UsersPager extends AlphabeticPager { |
| 36 | +class SpecialListUsers extends QueryPage { |
37 | 37 | |
38 | 38 | function __construct( $par=null ) { |
39 | 39 | global $wgRequest; |
— | — | @@ -61,30 +61,62 @@ |
62 | 62 | $this->requestedUser = $username->getText(); |
63 | 63 | } |
64 | 64 | } |
65 | | - parent::__construct(); |
| 65 | + |
| 66 | + $this->limit = $wgRequest->getVal( 'limit' ); |
| 67 | + $this->offset = $wgRequest->getVal( 'offset' ); |
| 68 | + |
| 69 | + parent::__construct( 'Listusers' ); |
66 | 70 | } |
67 | 71 | |
| 72 | + function isExpensive() { return false; } |
| 73 | + function isCacheable() { return false; } |
| 74 | + function isSyndicated() { return false; } |
| 75 | + function sortDescending() { return false; } |
68 | 76 | |
69 | | - function getIndexField() { |
70 | | - return $this->creationSort ? 'user_id' : 'user_name'; |
| 77 | + function openList( $offset ) { |
| 78 | + return "\n<ul class='special'>\n"; |
71 | 79 | } |
72 | 80 | |
| 81 | + function closeList() { |
| 82 | + return "</ul>\n"; |
| 83 | + } |
| 84 | + |
| 85 | + function linkParameters() { |
| 86 | + return array( |
| 87 | + 'group' => $this->requestedGroup, |
| 88 | + 'editsOnly' => $this->editsOnly, |
| 89 | + 'creationSort' => $this->creationSort, |
| 90 | + 'requestedUser' => $this->requestedUser, |
| 91 | + ); |
| 92 | + } |
| 93 | + |
73 | 94 | function getQueryInfo() { |
| 95 | + |
74 | 96 | global $wgUser; |
75 | 97 | $dbr = wfGetDB( DB_SLAVE ); |
76 | | - $conds = array(); |
| 98 | + $conds = $jconds = array(); |
| 99 | + $tables = array( 'user' ); |
| 100 | + |
77 | 101 | // Don't show hidden names |
78 | 102 | if( !$wgUser->isAllowed('hideuser') ) { |
| 103 | + $tables[] = 'ipblocks'; |
79 | 104 | $conds[] = 'ipb_deleted IS NULL'; |
| 105 | + $jconds['ipblocks'] = array( 'LEFT JOIN', array( |
| 106 | + # Unique index on (ipb_address,ipb_user,ipb_auto) |
| 107 | + 'ipb_address = user_name', |
| 108 | + 'ipb_user = user_id', |
| 109 | + 'ipb_auto = 0', |
| 110 | + 'ipb_deleted = 1', |
| 111 | + ) ); |
80 | 112 | } |
81 | 113 | |
82 | | - $options = array(); |
83 | | - |
84 | 114 | if( $this->requestedGroup != '' ) { |
| 115 | + $tables[] = 'user_groups'; |
85 | 116 | $conds['ug_group'] = $this->requestedGroup; |
86 | | - } else { |
87 | | - //$options['USE INDEX'] = $this->creationSort ? 'PRIMARY' : 'user_name'; |
| 117 | + # Unique index on (ug_user,ug_group) |
| 118 | + $jconds['user_groups'] = array( 'LEFT JOIN', 'user_id = ug_user' ); |
88 | 119 | } |
| 120 | + |
89 | 121 | if( $this->requestedUser != '' ) { |
90 | 122 | # Sorted either by account creation or name |
91 | 123 | if( $this->creationSort ) { |
— | — | @@ -93,28 +125,15 @@ |
94 | 126 | $conds[] = 'user_name >= ' . $dbr->addQuotes( $this->requestedUser ); |
95 | 127 | } |
96 | 128 | } |
| 129 | + |
97 | 130 | if( $this->editsOnly ) { |
98 | 131 | $conds[] = 'user_editcount > 0'; |
99 | 132 | } |
100 | 133 | |
101 | | - $options['GROUP BY'] = $this->creationSort ? 'user_id' : 'user_name'; |
102 | | - |
103 | 134 | $query = array( |
104 | | - 'tables' => array( 'user', 'user_groups', 'ipblocks'), |
105 | | - 'fields' => array( |
106 | | - $this->creationSort ? 'MAX(user_name) AS user_name' : 'user_name', |
107 | | - $this->creationSort ? 'user_id' : 'MAX(user_id) AS user_id', |
108 | | - 'MAX(user_editcount) AS edits', |
109 | | - 'COUNT(ug_group) AS numgroups', |
110 | | - 'MAX(ug_group) AS singlegroup', // the usergroup if there is only one |
111 | | - 'MIN(user_registration) AS creation', |
112 | | - 'MAX(ipb_deleted) AS ipb_deleted' // block/hide status |
113 | | - ), |
114 | | - 'options' => $options, |
115 | | - 'join_conds' => array( |
116 | | - 'user_groups' => array( 'LEFT JOIN', 'user_id=ug_user' ), |
117 | | - 'ipblocks' => array( 'LEFT JOIN', 'user_id=ipb_user AND ipb_deleted=1 AND ipb_auto=0' ), |
118 | | - ), |
| 135 | + 'tables' => $tables, |
| 136 | + 'fields' => '*', |
| 137 | + 'join_conds' => $jconds, |
119 | 138 | 'conds' => $conds |
120 | 139 | ); |
121 | 140 | |
— | — | @@ -122,16 +141,21 @@ |
123 | 142 | return $query; |
124 | 143 | } |
125 | 144 | |
126 | | - function formatRow( $row ) { |
| 145 | + function formatResult( $skin, $row ) { |
127 | 146 | global $wgLang; |
128 | 147 | |
129 | | - if ($row->user_id == 0) #Bug 16487 |
130 | | - return ''; |
| 148 | + if ( $row->user_id == 0 ){ |
| 149 | + #Bug 16487 |
| 150 | + return false; |
| 151 | + } |
131 | 152 | |
132 | | - $userPage = Title::makeTitle( NS_USER, $row->user_name ); |
133 | | - $name = $this->getSkin()->link( $userPage, htmlspecialchars( $userPage->getText() ) ); |
| 153 | + $user = User::newFromId( $row->user_id ); |
| 154 | + $name = $skin->link( |
| 155 | + $user->getUserpage(), |
| 156 | + $user->getName() |
| 157 | + ); |
134 | 158 | |
135 | | - $groups_list = self::getGroups( $row->user_id ); |
| 159 | + $groups_list = array_diff( $user->getEffectiveGroups(), $user->getImplicitGroups() ); |
136 | 160 | if( count( $groups_list ) > 0 ) { |
137 | 161 | $list = array(); |
138 | 162 | foreach( $groups_list as $group ) |
— | — | @@ -142,7 +166,7 @@ |
143 | 167 | } |
144 | 168 | |
145 | 169 | $item = wfSpecialList( $name, $groups ); |
146 | | - if( $row->ipb_deleted ) { |
| 170 | + if( isset( $row->ipb_deleted ) ) { |
147 | 171 | $item = "<span class=\"deleted\">$item</span>"; |
148 | 172 | } |
149 | 173 | |
— | — | @@ -156,29 +180,36 @@ |
157 | 181 | |
158 | 182 | $created = ''; |
159 | 183 | # Some rows may be NULL |
160 | | - if( $row->creation ) { |
161 | | - $d = $wgLang->date( wfTimestamp( TS_MW, $row->creation ), true ); |
162 | | - $t = $wgLang->time( wfTimestamp( TS_MW, $row->creation ), true ); |
163 | | - $created = ' (' . wfMsg( 'usercreated', $d, $t ) . ')'; |
164 | | - $created = htmlspecialchars( $created ); |
| 184 | + if( $row->user_registration ) { |
| 185 | + $d = $wgLang->date( wfTimestamp( TS_MW, $row->user_registration ), true ); |
| 186 | + $t = $wgLang->time( wfTimestamp( TS_MW, $row->user_registration ), true ); |
| 187 | + $created = ' (' . wfMessage( 'usercreated', $d, $t ) . ')'; |
165 | 188 | } |
166 | 189 | |
167 | 190 | wfRunHooks( 'SpecialListusersFormatRow', array( &$item, $row ) ); |
168 | | - return "<li>{$item}{$edits}{$created}</li>"; |
| 191 | + return "{$item}{$edits}{$created}"; |
169 | 192 | } |
170 | 193 | |
171 | | - function getBody() { |
172 | | - if( !$this->mQueryDone ) { |
173 | | - $this->doQuery(); |
174 | | - } |
175 | | - $this->mResult->rewind(); |
| 194 | + function getOrderFields() { |
| 195 | + return $this->creationSort ? array( 'user_id' ) : array( 'user_name' ); |
| 196 | + } |
| 197 | + |
| 198 | + /** |
| 199 | + * Cache page existence for performance |
| 200 | + */ |
| 201 | + function preprocessResults( $db, $res ) { |
176 | 202 | $batch = new LinkBatch; |
177 | | - foreach ( $this->mResult as $row ) { |
178 | | - $batch->addObj( Title::makeTitleSafe( NS_USER, $row->user_name ) ); |
| 203 | + foreach ( $res as $row ) { |
| 204 | + $batch->add( NS_USER, $row->user_name ); |
| 205 | + $batch->add( NS_USER_TALK, $row->user_name ); |
179 | 206 | } |
180 | 207 | $batch->execute(); |
181 | | - $this->mResult->rewind(); |
182 | | - return parent::getBody(); |
| 208 | + |
| 209 | + // Back to start for display |
| 210 | + if ( $db->numRows( $res ) > 0 ) { |
| 211 | + // If there are no rows we get an error seeking. |
| 212 | + $db->dataSeek( $res, 0 ); |
| 213 | + } |
183 | 214 | } |
184 | 215 | |
185 | 216 | function getPageHeader( ) { |
— | — | @@ -198,8 +229,16 @@ |
199 | 230 | $out .= Xml::label( wfMsg( 'group' ), 'group' ) . ' ' . |
200 | 231 | Xml::openElement('select', array( 'name' => 'group', 'id' => 'group' ) ) . |
201 | 232 | Xml::option( wfMsg( 'group-all' ), '' ); |
202 | | - foreach( $this->getAllGroups() as $group => $groupText ) |
203 | | - $out .= Xml::option( $groupText, $group, $group == $this->requestedGroup ); |
| 233 | + |
| 234 | + $groups = array_unique( array_diff( User::getAllGroups(), array( '*', 'user' ) ) ); |
| 235 | + foreach( $groups as $group ){ |
| 236 | + $out .= Xml::option( |
| 237 | + User::getGroupName( $group ), |
| 238 | + $group, |
| 239 | + $group == $this->requestedGroup |
| 240 | + ); |
| 241 | + } |
| 242 | + |
204 | 243 | $out .= Xml::closeElement( 'select' ) . '<br />'; |
205 | 244 | $out .= Xml::checkLabel( wfMsg('listusers-editsonly'), 'editsOnly', 'editsOnly', $this->editsOnly ); |
206 | 245 | $out .= ' '; |
— | — | @@ -209,7 +248,7 @@ |
210 | 249 | wfRunHooks( 'SpecialListusersHeaderForm', array( $this, &$out ) ); |
211 | 250 | |
212 | 251 | # Submit button and form bottom |
213 | | - $out .= Html::hidden( 'limit', $this->mLimit ); |
| 252 | + $out .= Html::hidden( 'limit', $this->limit ); |
214 | 253 | $out .= Xml::submitButton( wfMsg( 'allpagessubmit' ) ); |
215 | 254 | wfRunHooks( 'SpecialListusersHeader', array( $this, &$out ) ); |
216 | 255 | $out .= Xml::closeElement( 'fieldset' ) . |
— | — | @@ -219,45 +258,6 @@ |
220 | 259 | } |
221 | 260 | |
222 | 261 | /** |
223 | | - * Get a list of all explicit groups |
224 | | - * @return array |
225 | | - */ |
226 | | - function getAllGroups() { |
227 | | - $result = array(); |
228 | | - foreach( User::getAllGroups() as $group ) { |
229 | | - $result[$group] = User::getGroupName( $group ); |
230 | | - } |
231 | | - asort( $result ); |
232 | | - return $result; |
233 | | - } |
234 | | - |
235 | | - /** |
236 | | - * Preserve group and username offset parameters when paging |
237 | | - * @return array |
238 | | - */ |
239 | | - function getDefaultQuery() { |
240 | | - $query = parent::getDefaultQuery(); |
241 | | - if( $this->requestedGroup != '' ) |
242 | | - $query['group'] = $this->requestedGroup; |
243 | | - if( $this->requestedUser != '' ) |
244 | | - $query['username'] = $this->requestedUser; |
245 | | - wfRunHooks( 'SpecialListusersDefaultQuery', array( $this, &$query ) ); |
246 | | - return $query; |
247 | | - } |
248 | | - |
249 | | - /** |
250 | | - * Get a list of groups the specified user belongs to |
251 | | - * |
252 | | - * @param $uid Integer: user id |
253 | | - * @return array |
254 | | - */ |
255 | | - protected static function getGroups( $uid ) { |
256 | | - $user = User::newFromId( $uid ); |
257 | | - $groups = array_diff( $user->getEffectiveGroups(), $user->getImplicitGroups() ); |
258 | | - return $groups; |
259 | | - } |
260 | | - |
261 | | - /** |
262 | 262 | * Format a link to a group description page |
263 | 263 | * |
264 | 264 | * @param $group String: group name |
— | — | @@ -269,28 +269,4 @@ |
270 | 270 | $cache[$group] = User::makeGroupLinkHtml( $group, htmlspecialchars( User::getGroupMember( $group ) ) ); |
271 | 271 | return $cache[$group]; |
272 | 272 | } |
273 | | -} |
274 | | - |
275 | | -/** |
276 | | - * constructor |
277 | | - * $par string (optional) A group to list users from |
278 | | - */ |
279 | | -function wfSpecialListusers( $par = null ) { |
280 | | - global $wgOut; |
281 | | - |
282 | | - $up = new UsersPager($par); |
283 | | - |
284 | | - # getBody() first to check, if empty |
285 | | - $usersbody = $up->getBody(); |
286 | | - $s = Xml::openElement( 'div', array('class' => 'mw-spcontent') ); |
287 | | - $s .= $up->getPageHeader(); |
288 | | - if( $usersbody ) { |
289 | | - $s .= $up->getNavigationBar(); |
290 | | - $s .= '<ul>' . $usersbody . '</ul>'; |
291 | | - $s .= $up->getNavigationBar() ; |
292 | | - } else { |
293 | | - $s .= '<p>' . wfMsgHTML('listusers-noresult') . '</p>'; |
294 | | - }; |
295 | | - $s .= Xml::closeElement( 'div' ); |
296 | | - $wgOut->addHTML( $s ); |
297 | | -} |
| 273 | +} |
\ No newline at end of file |
Index: trunk/phase3/includes/SpecialPage.php |
— | — | @@ -144,7 +144,7 @@ |
145 | 145 | 'Preferences' => 'SpecialPreferences', |
146 | 146 | 'Contributions' => 'SpecialContributions', |
147 | 147 | 'Listgrouprights' => 'SpecialListGroupRights', |
148 | | - 'Listusers' => array( 'SpecialPage', 'Listusers' ), |
| 148 | + 'Listusers' => 'SpecialListusers', |
149 | 149 | 'Listadmins' => array( 'SpecialRedirectToSpecial', 'Listadmins', 'Listusers', 'sysop' ), |
150 | 150 | 'Listbots' => array( 'SpecialRedirectToSpecial', 'Listbots', 'Listusers', 'bot' ), |
151 | 151 | 'Activeusers' => 'SpecialActiveUsers', |