Index: trunk/phase3/includes/AutoLoader.php |
— | — | @@ -680,7 +680,6 @@ |
681 | 681 | 'SpecialImport' => 'includes/specials/SpecialImport.php', |
682 | 682 | 'SpecialListFiles' => 'includes/specials/SpecialListfiles.php', |
683 | 683 | 'SpecialListGroupRights' => 'includes/specials/SpecialListgrouprights.php', |
684 | | - 'SpecialListUsers' => 'includes/specials/SpecialListusers.php', |
685 | 684 | 'SpecialLockdb' => 'includes/specials/SpecialLockdb.php', |
686 | 685 | 'SpecialLog' => 'includes/specials/SpecialLog.php', |
687 | 686 | 'SpecialMergeHistory' => 'includes/specials/SpecialMergeHistory.php', |
— | — | @@ -717,6 +716,7 @@ |
718 | 717 | 'UploadForm' => 'includes/specials/SpecialUpload.php', |
719 | 718 | 'UploadSourceField' => 'includes/specials/SpecialUpload.php', |
720 | 719 | 'UserrightsPage' => 'includes/specials/SpecialUserrights.php', |
| 720 | + 'UsersPager' => 'includes/specials/SpecialListusers.php', |
721 | 721 | 'WantedCategoriesPage' => 'includes/specials/SpecialWantedcategories.php', |
722 | 722 | 'WantedFilesPage' => 'includes/specials/SpecialWantedfiles.php', |
723 | 723 | '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 SpecialListUsers extends QueryPage { |
| 36 | +class UsersPager extends AlphabeticPager { |
37 | 37 | |
38 | 38 | function __construct( $par=null ) { |
39 | 39 | global $wgRequest; |
— | — | @@ -61,62 +61,30 @@ |
62 | 62 | $this->requestedUser = $username->getText(); |
63 | 63 | } |
64 | 64 | } |
65 | | - |
66 | | - $this->limit = $wgRequest->getVal( 'limit' ); |
67 | | - $this->offset = $wgRequest->getVal( 'offset' ); |
68 | | - |
69 | | - parent::__construct( 'Listusers' ); |
| 65 | + parent::__construct(); |
70 | 66 | } |
71 | 67 | |
72 | | - function isExpensive() { return false; } |
73 | | - function isCacheable() { return false; } |
74 | | - function isSyndicated() { return false; } |
75 | | - function sortDescending() { return false; } |
76 | 68 | |
77 | | - function openList( $offset ) { |
78 | | - return "\n<ul class='special'>\n"; |
| 69 | + function getIndexField() { |
| 70 | + return $this->creationSort ? 'user_id' : 'user_name'; |
79 | 71 | } |
80 | 72 | |
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 | | - |
94 | 73 | function getQueryInfo() { |
95 | | - |
96 | 74 | global $wgUser; |
97 | 75 | $dbr = wfGetDB( DB_SLAVE ); |
98 | | - $conds = $jconds = array(); |
99 | | - $tables = array( 'user' ); |
100 | | - |
| 76 | + $conds = array(); |
101 | 77 | // Don't show hidden names |
102 | 78 | if( !$wgUser->isAllowed('hideuser') ) { |
103 | | - $tables[] = 'ipblocks'; |
104 | 79 | $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 | | - ) ); |
112 | 80 | } |
113 | 81 | |
| 82 | + $options = array(); |
| 83 | + |
114 | 84 | if( $this->requestedGroup != '' ) { |
115 | | - $tables[] = 'user_groups'; |
116 | 85 | $conds['ug_group'] = $this->requestedGroup; |
117 | | - # Unique index on (ug_user,ug_group) |
118 | | - $jconds['user_groups'] = array( 'LEFT JOIN', 'user_id = ug_user' ); |
| 86 | + } else { |
| 87 | + //$options['USE INDEX'] = $this->creationSort ? 'PRIMARY' : 'user_name'; |
119 | 88 | } |
120 | | - |
121 | 89 | if( $this->requestedUser != '' ) { |
122 | 90 | # Sorted either by account creation or name |
123 | 91 | if( $this->creationSort ) { |
— | — | @@ -125,15 +93,28 @@ |
126 | 94 | $conds[] = 'user_name >= ' . $dbr->addQuotes( $this->requestedUser ); |
127 | 95 | } |
128 | 96 | } |
129 | | - |
130 | 97 | if( $this->editsOnly ) { |
131 | 98 | $conds[] = 'user_editcount > 0'; |
132 | 99 | } |
133 | 100 | |
| 101 | + $options['GROUP BY'] = $this->creationSort ? 'user_id' : 'user_name'; |
| 102 | + |
134 | 103 | $query = array( |
135 | | - 'tables' => $tables, |
136 | | - 'fields' => '*', |
137 | | - 'join_conds' => $jconds, |
| 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 | + ), |
138 | 119 | 'conds' => $conds |
139 | 120 | ); |
140 | 121 | |
— | — | @@ -141,21 +122,16 @@ |
142 | 123 | return $query; |
143 | 124 | } |
144 | 125 | |
145 | | - function formatResult( $skin, $row ) { |
| 126 | + function formatRow( $row ) { |
146 | 127 | global $wgLang; |
147 | 128 | |
148 | | - if ( $row->user_id == 0 ){ |
149 | | - #Bug 16487 |
150 | | - return false; |
151 | | - } |
| 129 | + if ($row->user_id == 0) #Bug 16487 |
| 130 | + return ''; |
152 | 131 | |
153 | | - $user = User::newFromId( $row->user_id ); |
154 | | - $name = $skin->link( |
155 | | - $user->getUserpage(), |
156 | | - $user->getName() |
157 | | - ); |
| 132 | + $userPage = Title::makeTitle( NS_USER, $row->user_name ); |
| 133 | + $name = $this->getSkin()->link( $userPage, htmlspecialchars( $userPage->getText() ) ); |
158 | 134 | |
159 | | - $groups_list = array_diff( $user->getEffectiveGroups(), $user->getImplicitGroups() ); |
| 135 | + $groups_list = self::getGroups( $row->user_id ); |
160 | 136 | if( count( $groups_list ) > 0 ) { |
161 | 137 | $list = array(); |
162 | 138 | foreach( $groups_list as $group ) |
— | — | @@ -166,7 +142,7 @@ |
167 | 143 | } |
168 | 144 | |
169 | 145 | $item = wfSpecialList( $name, $groups ); |
170 | | - if( isset( $row->ipb_deleted ) ) { |
| 146 | + if( $row->ipb_deleted ) { |
171 | 147 | $item = "<span class=\"deleted\">$item</span>"; |
172 | 148 | } |
173 | 149 | |
— | — | @@ -180,36 +156,29 @@ |
181 | 157 | |
182 | 158 | $created = ''; |
183 | 159 | # Some rows may be NULL |
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 ) . ')'; |
| 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 ); |
188 | 165 | } |
189 | 166 | |
190 | 167 | wfRunHooks( 'SpecialListusersFormatRow', array( &$item, $row ) ); |
191 | | - return "{$item}{$edits}{$created}"; |
| 168 | + return "<li>{$item}{$edits}{$created}</li>"; |
192 | 169 | } |
193 | 170 | |
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 ) { |
| 171 | + function getBody() { |
| 172 | + if( !$this->mQueryDone ) { |
| 173 | + $this->doQuery(); |
| 174 | + } |
| 175 | + $this->mResult->rewind(); |
202 | 176 | $batch = new LinkBatch; |
203 | | - foreach ( $res as $row ) { |
204 | | - $batch->add( NS_USER, $row->user_name ); |
205 | | - $batch->add( NS_USER_TALK, $row->user_name ); |
| 177 | + foreach ( $this->mResult as $row ) { |
| 178 | + $batch->addObj( Title::makeTitleSafe( NS_USER, $row->user_name ) ); |
206 | 179 | } |
207 | 180 | $batch->execute(); |
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 | | - } |
| 181 | + $this->mResult->rewind(); |
| 182 | + return parent::getBody(); |
214 | 183 | } |
215 | 184 | |
216 | 185 | function getPageHeader( ) { |
— | — | @@ -229,16 +198,8 @@ |
230 | 199 | $out .= Xml::label( wfMsg( 'group' ), 'group' ) . ' ' . |
231 | 200 | Xml::openElement('select', array( 'name' => 'group', 'id' => 'group' ) ) . |
232 | 201 | Xml::option( wfMsg( 'group-all' ), '' ); |
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 | | - |
| 202 | + foreach( $this->getAllGroups() as $group => $groupText ) |
| 203 | + $out .= Xml::option( $groupText, $group, $group == $this->requestedGroup ); |
243 | 204 | $out .= Xml::closeElement( 'select' ) . '<br />'; |
244 | 205 | $out .= Xml::checkLabel( wfMsg('listusers-editsonly'), 'editsOnly', 'editsOnly', $this->editsOnly ); |
245 | 206 | $out .= ' '; |
— | — | @@ -248,7 +209,7 @@ |
249 | 210 | wfRunHooks( 'SpecialListusersHeaderForm', array( $this, &$out ) ); |
250 | 211 | |
251 | 212 | # Submit button and form bottom |
252 | | - $out .= Html::hidden( 'limit', $this->limit ); |
| 213 | + $out .= Html::hidden( 'limit', $this->mLimit ); |
253 | 214 | $out .= Xml::submitButton( wfMsg( 'allpagessubmit' ) ); |
254 | 215 | wfRunHooks( 'SpecialListusersHeader', array( $this, &$out ) ); |
255 | 216 | $out .= Xml::closeElement( 'fieldset' ) . |
— | — | @@ -258,6 +219,45 @@ |
259 | 220 | } |
260 | 221 | |
261 | 222 | /** |
| 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 | * Also called by SpecialActiveUsers |
264 | 264 | * @param $group String: group name |
— | — | @@ -269,4 +269,28 @@ |
270 | 270 | $cache[$group] = User::makeGroupLinkHtml( $group, htmlspecialchars( User::getGroupMember( $group ) ) ); |
271 | 271 | return $cache[$group]; |
272 | 272 | } |
273 | | -} |
\ No newline at end of file |
| 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 | +} |
Index: trunk/phase3/includes/SpecialPage.php |
— | — | @@ -134,7 +134,7 @@ |
135 | 135 | 'Preferences' => 'SpecialPreferences', |
136 | 136 | 'Contributions' => 'SpecialContributions', |
137 | 137 | 'Listgrouprights' => 'SpecialListGroupRights', |
138 | | - 'Listusers' => 'SpecialListusers', |
| 138 | + 'Listusers' => array( 'SpecialPage', 'Listusers' ), |
139 | 139 | 'Listadmins' => array( 'SpecialRedirectToSpecial', 'Listadmins', 'Listusers', 'sysop' ), |
140 | 140 | 'Listbots' => array( 'SpecialRedirectToSpecial', 'Listbots', 'Listusers', 'bot' ), |
141 | 141 | 'Activeusers' => 'SpecialActiveUsers', |