]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - includes/specials/SpecialNewpages.php
MediaWiki 1.14.0-scripts
[autoinstalls/mediawiki.git] / includes / specials / SpecialNewpages.php
1 <?php
2
3 /**
4  * implements Special:Newpages
5  * @ingroup SpecialPage
6  */
7 class SpecialNewpages extends SpecialPage {
8
9         // Stored objects
10         protected $opts, $skin;
11
12         // Some internal settings
13         protected $showNavigation = false;
14
15         public function __construct() {
16                 parent::__construct( 'Newpages' );
17                 $this->includable( true );      
18         }
19
20         protected function setup( $par ) {
21                 global $wgRequest, $wgUser, $wgEnableNewpagesUserFilter;
22
23                 // Options
24                 $opts = new FormOptions();
25                 $this->opts = $opts; // bind
26                 $opts->add( 'hideliu', false );
27                 $opts->add( 'hidepatrolled', false );
28                 $opts->add( 'hidebots', false );
29                 $opts->add( 'hideredirs', true );
30                 $opts->add( 'limit', (int)$wgUser->getOption( 'rclimit' ) );
31                 $opts->add( 'offset', '' );
32                 $opts->add( 'namespace', '0' );
33                 $opts->add( 'username', '' );
34                 $opts->add( 'feed', '' );
35
36                 // Set values
37                 $opts->fetchValuesFromRequest( $wgRequest );
38                 if ( $par ) $this->parseParams( $par );
39
40                 // Validate
41                 $opts->validateIntBounds( 'limit', 0, 5000 );
42                 if( !$wgEnableNewpagesUserFilter ) {
43                         $opts->setValue( 'username', '' );
44                 }
45
46                 // Store some objects
47                 $this->skin = $wgUser->getSkin();
48         }
49
50         protected function parseParams( $par ) {
51                 global $wgLang;
52                 $bits = preg_split( '/\s*,\s*/', trim( $par ) );
53                 foreach ( $bits as $bit ) {
54                         if ( 'shownav' == $bit )
55                                 $this->showNavigation = true;
56                         if ( 'hideliu' === $bit )
57                                 $this->opts->setValue( 'hideliu', true );
58                         if ( 'hidepatrolled' == $bit )
59                                 $this->opts->setValue( 'hidepatrolled', true );
60                         if ( 'hidebots' == $bit )
61                                 $this->opts->setValue( 'hidebots', true );
62                         if ( 'showredirs' == $bit )
63                                 $this->opts->setValue( 'hideredirs', false );
64                         if ( is_numeric( $bit ) )
65                                 $this->opts->setValue( 'limit', intval( $bit ) );
66
67                         $m = array();
68                         if ( preg_match( '/^limit=(\d+)$/', $bit, $m ) )
69                                 $this->opts->setValue( 'limit', intval($m[1]) );
70                         // PG offsets not just digits!
71                         if ( preg_match( '/^offset=([^=]+)$/', $bit, $m ) )
72                                 $this->opts->setValue( 'offset',  intval($m[1]) );
73                         if ( preg_match( '/^username=(.*)$/', $bit, $m ) )
74                                 $this->opts->setValue( 'username', $m[1] );
75                         if ( preg_match( '/^namespace=(.*)$/', $bit, $m ) ) {
76                                 $ns = $wgLang->getNsIndex( $m[1] );
77                                 if( $ns !== false ) {
78                                         $this->opts->setValue( 'namespace',  $ns );
79                                 }
80                         }
81                 }
82         }
83
84         /**
85          * Show a form for filtering namespace and username
86          *
87          * @param string $par
88          * @return string
89          */
90         public function execute( $par ) {
91                 global $wgLang, $wgUser, $wgOut;
92
93                 $this->setHeaders();
94                 $this->outputHeader();
95
96                 $this->showNavigation = !$this->including(); // Maybe changed in setup
97                 $this->setup( $par );
98
99                 if( !$this->including() ) {
100                         // Settings
101                         $this->form();
102
103                         $this->setSyndicated();
104                         $feedType = $this->opts->getValue( 'feed' );
105                         if( $feedType ) {
106                                 return $this->feed( $feedType );
107                         }
108                 }
109
110                 $pager = new NewPagesPager( $this, $this->opts );
111                 $pager->mLimit = $this->opts->getValue( 'limit' );
112                 $pager->mOffset = $this->opts->getValue( 'offset' );
113
114                 if( $pager->getNumRows() ) {
115                         $navigation = '';
116                         if ( $this->showNavigation ) $navigation = $pager->getNavigationBar();
117                         $wgOut->addHTML( $navigation . $pager->getBody() . $navigation );
118                 } else {
119                         $wgOut->addWikiMsg( 'specialpage-empty' );
120                 }
121         }
122
123         protected function filterLinks() {
124                 global $wgGroupPermissions, $wgUser;
125
126                 // show/hide links
127                 $showhide = array( wfMsgHtml( 'show' ), wfMsgHtml( 'hide' ) );
128
129                 // Option value -> message mapping
130                 $filters = array(
131                         'hideliu' => 'rcshowhideliu',
132                         'hidepatrolled' => 'rcshowhidepatr',
133                         'hidebots' => 'rcshowhidebots',
134                         'hideredirs' => 'whatlinkshere-hideredirs'
135                 );
136
137                 // Disable some if needed
138                 if ( $wgGroupPermissions['*']['createpage'] !== true )
139                         unset($filters['hideliu']);
140
141                 if ( !$wgUser->useNPPatrol() )
142                         unset($filters['hidepatrolled']);
143
144                 $links = array();
145                 $changed = $this->opts->getChangedValues();
146                 unset($changed['offset']); // Reset offset if query type changes
147
148                 $self = $this->getTitle();
149                 foreach ( $filters as $key => $msg ) {
150                         $onoff = 1 - $this->opts->getValue($key);
151                         $link = $this->skin->link( $self, $showhide[$onoff], array(),
152                                  array( $key => $onoff ) + $changed
153                         );
154                         $links[$key] = wfMsgHtml( $msg, $link );
155                 }
156
157                 return implode( ' | ', $links );
158         }
159
160         protected function form() {
161                 global $wgOut, $wgEnableNewpagesUserFilter, $wgScript;
162
163                 // Consume values
164                 $this->opts->consumeValue( 'offset' ); // don't carry offset, DWIW
165                 $namespace = $this->opts->consumeValue( 'namespace' );
166                 $username = $this->opts->consumeValue( 'username' );
167
168                 // Check username input validity
169                 $ut = Title::makeTitleSafe( NS_USER, $username );
170                 $userText = $ut ? $ut->getText() : '';
171
172                 // Store query values in hidden fields so that form submission doesn't lose them
173                 $hidden = array();
174                 foreach ( $this->opts->getUnconsumedValues() as $key => $value ) {
175                         $hidden[] = Xml::hidden( $key, $value );
176                 }
177                 $hidden = implode( "\n", $hidden );
178
179                 $form = Xml::openElement( 'form', array( 'action' => $wgScript ) ) .
180                         Xml::hidden( 'title', $this->getTitle()->getPrefixedDBkey() ) .
181                         Xml::fieldset( wfMsg( 'newpages' ) ) .
182                         Xml::openElement( 'table', array( 'id' => 'mw-newpages-table' ) ) .
183                         "<tr>
184                                 <td class='mw-label'>" .
185                                         Xml::label( wfMsg( 'namespace' ), 'namespace' ) .
186                                 "</td>
187                                 <td class='mw-input'>" .
188                                         Xml::namespaceSelector( $namespace, 'all' ) .
189                                 "</td>
190                         </tr>" .
191                         ($wgEnableNewpagesUserFilter ?
192                         "<tr>
193                                 <td class='mw-label'>" .
194                                         Xml::label( wfMsg( 'newpages-username' ), 'mw-np-username' ) .
195                                 "</td>
196                                 <td class='mw-input'>" .
197                                         Xml::input( 'username', 30, $userText, array( 'id' => 'mw-np-username' ) ) .
198                                 "</td>
199                         </tr>" : "" ) .
200                         "<tr> <td></td>
201                                 <td class='mw-submit'>" .
202                                         Xml::submitButton( wfMsg( 'allpagessubmit' ) ) .
203                                 "</td>
204                         </tr>" .
205                         "<tr>
206                                 <td></td>
207                                 <td class='mw-input'>" .
208                                         $this->filterLinks() .
209                                 "</td>
210                         </tr>" .
211                         Xml::closeElement( 'table' ) .
212                         Xml::closeElement( 'fieldset' ) .
213                         $hidden .
214                         Xml::closeElement( 'form' );
215
216                 $wgOut->addHTML( $form );
217         }
218
219         protected function setSyndicated() {
220                 global $wgOut;
221                 $queryParams = array(
222                         'namespace' => $this->opts->getValue( 'namespace' ),
223                         'username' => $this->opts->getValue( 'username' )
224                 );
225                 $wgOut->setSyndicated( true );
226                 $wgOut->setFeedAppendQuery( wfArrayToCGI( $queryParams ) );
227         }
228
229         /**
230          * Format a row, providing the timestamp, links to the page/history, size, user links, and a comment
231          *
232          * @param $skin Skin to use
233          * @param $result Result row
234          * @return string
235          */
236         public function formatRow( $result ) {
237                 global $wgLang, $wgContLang, $wgUser;
238                 $dm = $wgContLang->getDirMark();
239
240                 $title = Title::makeTitleSafe( $result->rc_namespace, $result->rc_title );
241                 $time = $wgLang->timeAndDate( $result->rc_timestamp, true );
242                 $plink = $this->skin->makeKnownLinkObj( $title, '', $this->patrollable( $result ) ? 'rcid=' . $result->rc_id : '' );
243                 $hist = $this->skin->makeKnownLinkObj( $title, wfMsgHtml( 'hist' ), 'action=history' );
244                 $length = wfMsgExt( 'nbytes', array( 'parsemag', 'escape' ),
245                         $wgLang->formatNum( $result->length ) );
246                 $ulink = $this->skin->userLink( $result->rc_user, $result->rc_user_text ) . ' ' .
247                         $this->skin->userToolLinks( $result->rc_user, $result->rc_user_text );
248                 $comment = $this->skin->commentBlock( $result->rc_comment );
249                 $css = $this->patrollable( $result ) ? " class='not-patrolled'" : '';
250
251                 return "<li{$css}>{$time} {$dm}{$plink} ({$hist}) {$dm}[{$length}] {$dm}{$ulink} {$comment}</li>\n";
252         }
253
254         /**
255          * Should a specific result row provide "patrollable" links?
256          *
257          * @param $result Result row
258          * @return bool
259          */
260         protected function patrollable( $result ) {
261                 global $wgUser;
262                 return ( $wgUser->useNPPatrol() && !$result->rc_patrolled );
263         }
264
265         /**
266          * Output a subscription feed listing recent edits to this page.
267          * @param string $type
268          */
269         protected function feed( $type ) {
270                 global $wgFeed, $wgFeedClasses, $wgFeedLimit;
271
272                 if ( !$wgFeed ) {
273                         global $wgOut;
274                         $wgOut->addWikiMsg( 'feed-unavailable' );
275                         return;
276                 }
277
278                 if( !isset( $wgFeedClasses[$type] ) ) {
279                         global $wgOut;
280                         $wgOut->addWikiMsg( 'feed-invalid' );
281                         return;
282                 }
283
284                 $feed = new $wgFeedClasses[$type](
285                         $this->feedTitle(),
286                         wfMsgExt( 'tagline', 'parsemag' ),
287                         $this->getTitle()->getFullUrl() );
288
289                 $pager = new NewPagesPager( $this, $this->opts );
290                 $limit = $this->opts->getValue( 'limit' );
291                 $pager->mLimit = min( $limit, $wgFeedLimit );
292
293                 $feed->outHeader();
294                 if( $pager->getNumRows() > 0 ) {
295                         while( $row = $pager->mResult->fetchObject() ) {
296                                 $feed->outItem( $this->feedItem( $row ) );
297                         }
298                 }
299                 $feed->outFooter();
300         }
301
302         protected function feedTitle() {
303                 global $wgContLanguageCode, $wgSitename;
304                 $page = SpecialPage::getPage( 'Newpages' );
305                 $desc = $page->getDescription();
306                 return "$wgSitename - $desc [$wgContLanguageCode]";
307         }
308
309         protected function feedItem( $row ) {
310                 $title = Title::MakeTitle( intval( $row->rc_namespace ), $row->rc_title );
311                 if( $title ) {
312                         $date = $row->rc_timestamp;
313                         $comments = $title->getTalkPage()->getFullURL();
314
315                         return new FeedItem(
316                                 $title->getPrefixedText(),
317                                 $this->feedItemDesc( $row ),
318                                 $title->getFullURL(),
319                                 $date,
320                                 $this->feedItemAuthor( $row ),
321                                 $comments);
322                 } else {
323                         return NULL;
324                 }
325         }
326
327         protected function feedItemAuthor( $row ) {
328                 return isset( $row->rc_user_text ) ? $row->rc_user_text : '';
329         }
330
331         protected function feedItemDesc( $row ) {
332                 $revision = Revision::newFromId( $row->rev_id );
333                 if( $revision ) {
334                         return '<p>' . htmlspecialchars( $revision->getUserText() ) . ': ' .
335                                 htmlspecialchars( FeedItem::stripComment( $revision->getComment() ) ) . 
336                                 "</p>\n<hr />\n<div>" .
337                                 nl2br( htmlspecialchars( $revision->getText() ) ) . "</div>";
338                 }
339                 return '';
340         }
341 }
342
343 /**
344  * @ingroup SpecialPage Pager
345  */
346 class NewPagesPager extends ReverseChronologicalPager {
347         // Stored opts
348         protected $opts, $mForm;
349
350         function __construct( $form, FormOptions $opts ) {
351                 parent::__construct();
352                 $this->mForm = $form;
353                 $this->opts = $opts;
354         }
355
356         function getTitle() {
357                 static $title = null;
358                 if ( $title === null )
359                         $title = $this->mForm->getTitle();
360                 return $title;
361         }
362
363         function getQueryInfo() {
364                 global $wgEnableNewpagesUserFilter, $wgGroupPermissions, $wgUser;
365                 $conds = array();
366                 $conds['rc_new'] = 1;
367
368                 $namespace = $this->opts->getValue( 'namespace' );
369                 $namespace = ( $namespace === 'all' ) ? false : intval( $namespace );
370
371                 $username = $this->opts->getValue( 'username' );
372                 $user = Title::makeTitleSafe( NS_USER, $username );
373
374                 if( $namespace !== false ) {
375                         $conds['rc_namespace'] = $namespace;
376                         $rcIndexes = array( 'new_name_timestamp' );
377                 } else {
378                         $rcIndexes = array( 'rc_timestamp' );
379                 }
380                 $conds[] = 'page_id = rc_cur_id';
381
382                 # $wgEnableNewpagesUserFilter - temp WMF hack
383                 if( $wgEnableNewpagesUserFilter && $user ) {
384                         $conds['rc_user_text'] = $user->getText();
385                         $rcIndexes = 'rc_user_text';
386                 # If anons cannot make new pages, don't "exclude logged in users"!
387                 } elseif( $wgGroupPermissions['*']['createpage'] && $this->opts->getValue( 'hideliu' ) ) {
388                         $conds['rc_user'] = 0;
389                 }
390                 # If this user cannot see patrolled edits or they are off, don't do dumb queries!
391                 if( $this->opts->getValue( 'hidepatrolled' ) && $wgUser->useNPPatrol() ) {
392                         $conds['rc_patrolled'] = 0;
393                 }
394                 if( $this->opts->getValue( 'hidebots' ) ) {
395                         $conds['rc_bot'] = 0;
396                 }
397
398                 if ( $this->opts->getValue( 'hideredirs' ) ) {
399                         $conds['page_is_redirect'] = 0;
400                 }
401
402                 return array(
403                         'tables' => array( 'recentchanges', 'page' ),
404                         'fields' => 'rc_namespace,rc_title, rc_cur_id, rc_user,rc_user_text,rc_comment,
405                                 rc_timestamp,rc_patrolled,rc_id,page_len as length, page_latest as rev_id',
406                         'conds' => $conds,
407                         'options' => array( 'USE INDEX' => array('recentchanges' => $rcIndexes) )
408                 );
409         }
410
411         function getIndexField() {
412                 return 'rc_timestamp';
413         }
414
415         function formatRow( $row ) {
416                 return $this->mForm->formatRow( $row );
417         }
418
419         function getStartBody() {
420                 # Do a batch existence check on pages
421                 $linkBatch = new LinkBatch();
422                 while( $row = $this->mResult->fetchObject() ) {
423                         $linkBatch->add( NS_USER, $row->rc_user_text );
424                         $linkBatch->add( NS_USER_TALK, $row->rc_user_text );
425                         $linkBatch->add( $row->rc_namespace, $row->rc_title );
426                 }
427                 $linkBatch->execute();
428                 return "<ul>";
429         }
430
431         function getEndBody() {
432                 return "</ul>";
433         }
434 }