New special page Special:NewbieContributions to replace Special:Contributions/newbies
[mediawiki.git] / includes / SpecialContributions.php
blob34ab8c3a3ecf552414102c616d285ee666860f3a
1 <?php
3 /**
4 * Special page allowing users to view their own contributions
5 * and those of others.
7 * @package MediaWiki
8 * @subpackage Special pages
9 */
10 class ContributionsPage extends QueryPage {
11 var $user = null;
12 var $namespace = null;
13 var $botmode = false;
15 /**
16 * Constructor.
17 * @param $username username to list contribs for (or "newbies" for extra magic)
19 function __construct( $username ) {
20 $this->user = User::newFromName( $username, false );
23 /**
24 * @return string Name of this special page.
26 function getName() {
27 return 'Contributions';
30 /**
31 * Not expensive, won't work with the query cache anyway.
33 function isExpensive() { return false; }
35 /**
36 * Should we?
38 function isSyndicated() { return false; }
40 /**
41 * Get target user name. May be overridden in subclasses.
42 * @return string username
44 function getUsername() {
45 return $this->user->getName();
48 /**
49 * @return array Extra URL params for self-links.
51 function linkParameters() {
52 $params['target'] = $this->getUsername();
54 if ( isset($this->namespace) )
55 $params['namespace'] = $this->namespace;
57 if ( $this->botmode )
58 $params['bot'] = 1;
60 return $params;
63 /**
64 * Build the list of links to be shown in the subtitle.
65 * @return string Link list for "contribsub" UI message.
67 function getTargetUserLinks() {
68 global $wgSysopUserBans, $wgLang, $wgUser;
70 $skin = $wgUser->getSkin();
72 $username = $this->getUsername();
73 $userpage = $this->user->getUserPage();
74 $userlink = $skin->makeLinkObj( $userpage, $username );
76 // talk page link
77 $tools[] = $skin->makeLinkObj( $userpage->getTalkPage(), $wgLang->getNsText( NS_TALK ) );
79 // block or block log link
80 $id = $this->user->getId();
81 if ( ( $id != 0 && $wgSysopUserBans ) || ( $id == 0 && User::isIP( $username ) ) ) {
82 if( $wgUser->isAllowed( 'block' ) )
83 $tools[] = $skin->makeKnownLinkObj( SpecialPage::getTitleFor( 'Blockip', $username ),
84 wfMsgHtml( 'blocklink' ) );
85 else
86 $tools[] = $skin->makeKnownLinkObj( SpecialPage::getTitleFor( 'Log' ),
87 htmlspecialchars( LogPage::logName( 'block' ) ),
88 'type=block&page=' . $userpage->getPrefixedUrl() );
91 // other logs link
92 $tools[] = $skin->makeKnownLinkObj( SpecialPage::getTitleFor( 'Log' ),
93 wfMsgHtml( 'log' ),
94 'user=' . $userpage->getPartialUrl() );
96 return $userlink . ' (' . implode( ' | ', $tools ) . ')';
99 /**
100 * Generate "For User (...)" message in subtitle. Calls
101 * getTargetUserLinks() for most of the work.
102 * @return string
104 function getSubtitleForTarget() {
105 return wfMsgHtml( 'contribsub', $this->getTargetUserLinks() );
109 * If the user has deleted contributions and we are allowed to
110 * view them, generate a link to Special:DeletedContributions.
111 * @return string
113 function getDeletedContributionsLink() {
114 global $wgUser;
116 if( !$wgUser->isAllowed( 'deletedhistory' ) )
117 return '';
119 $dbr = wfGetDB( DB_SLAVE );
120 $n = $dbr->selectField( 'archive', 'count(*)', array( 'ar_user_text' => $this->getUsername() ), __METHOD__ );
122 if ( $n == 0 )
123 return '';
125 $msg = wfMsg( ( $wgUser->isAllowed( 'delete' ) ? 'thisisdeleted' : 'viewdeleted' ),
126 $wgUser->getSkin()->makeKnownLinkObj(
127 SpecialPage::getTitleFor( 'DeletedContributions', $this->getUsername() ),
128 wfMsgExt( 'restorelink', array( 'parsemag', 'escape' ), $n ) ) );
130 return "<p>$msg</p>";
134 * Construct and output the page subtitle.
136 function outputSubtitle() {
137 global $wgOut;
138 $subtitle = $this->getSubtitleForTarget();
139 // $subtitle .= $this->getDeletedContributionsLink(); NOT YET...
140 $wgOut->setSubtitle( $subtitle );
144 * Construct the namespace selector form.
145 * @return string
147 function getNamespaceForm() {
148 $title = $this->getTitle();
150 $ns = $this->namespace;
151 if ( !isset($ns) )
152 $ns = '';
154 $form = Xml::openElement( 'form', array( 'method' => 'post', 'action' => $title->getLocalUrl() ) );
155 $form .= wfMsgHtml( 'namespace' ) . ' ';
156 $form .= Xml::namespaceSelector( $ns, '' ) . ' ';
157 $form .= Xml::submitButton( wfMsg( 'allpagessubmit' ) );
158 $form .= Xml::hidden( 'offset', $this->offset );
159 $form .= Xml::hidden( 'limit', $this->limit );
160 $form .= Xml::hidden( 'target', $this->getUsername() );
161 if ( $this->botmode )
162 $form .= Xml::hidden( 'bot', 1 );
163 $form .= '</form>';
165 return '<p>' . $form . '</p>';
169 * Build the page header. Also calls outputSubtitle().
170 * @return string
172 function getPageHeader() {
173 $this->outputSubtitle();
174 return $this->getNamespaceForm();
178 * Construct the WHERE clause of the SQL SELECT statement for
179 * this query.
180 * @return string
182 function makeSQLCond( $dbr ) {
183 $cond = ' page_id = rev_page';
184 $cond .= ' AND rev_user_text = ' . $dbr->addQuotes( $this->getUsername() );
186 if ( isset($this->namespace) )
187 $cond .= ' AND page_namespace = ' . (int)$this->namespace;
189 return $cond;
193 * Construct the SQL SELECT statement for this query.
194 * @return string
196 function getSQL() {
197 $dbr = wfGetDB( DB_SLAVE );
199 list( $page, $revision ) = $dbr->tableNamesN( 'page', 'revision' );
201 // XXX: the username and userid fields aren't used for much here,
202 // but some subclasses rely on them more than we do.
204 return "SELECT 'Contributions' as type,
205 page_namespace AS namespace,
206 page_title AS title,
207 rev_timestamp AS value,
208 rev_user AS userid,
209 rev_user_text AS username,
210 rev_minor_edit AS is_minor,
211 page_latest AS cur_id,
212 rev_id AS rev_id,
213 rev_comment AS comment,
214 rev_deleted AS deleted
215 FROM $page, $revision
216 WHERE " . $this->makeSQLCond( $dbr );
220 * Get user links for output row, for subclasses that may want
221 * such functionality.
223 * @param $skin Skin to use
224 * @param $row Result row
225 * @return string
227 function getRowUserLinks( $skin, $row ) { return ''; }
230 * Format a row, providing the timestamp, links to the
231 * page/diff/history and a comment
233 * @param $skin Skin to use
234 * @param $row Result row
235 * @return string
237 function formatResult( $skin, $row ) {
238 global $wgLang, $wgContLang, $wgUser;
240 $dm = $wgContLang->getDirMark();
243 * Cache UI messages in a static array so we don't
244 * have to regenerate them for each row.
246 static $messages;
247 if( !isset( $messages ) ) {
248 foreach( explode( ' ', 'uctop diff newarticle rollbacklink diff hist minoreditletter' ) as $msg )
249 $messages[$msg] = wfMsgExt( $msg, array( 'escape') );
252 $page = Title::makeTitle( $row->namespace, $row->title );
255 * HACK: We need a revision object, so we make a very
256 * heavily stripped-down one. All we really need are
257 * the comment, the title and the deletion bitmask.
259 $rev = new Revision( array(
260 'comment' => $row->comment,
261 'deleted' => $row->deleted,
262 'user_text' => $row->username,
263 'user' => $row->userid,
264 ) );
265 $rev->setTitle( $page );
267 $ts = wfTimestamp( TS_MW, $row->value );
268 $time = $wgLang->timeAndDate( $ts, true );
269 $hist = $skin->makeKnownLinkObj( $page, $messages['hist'], 'action=history' );
271 if ( $rev->userCan( Revision::DELETED_TEXT ) )
272 $diff = $skin->makeKnownLinkObj( $page, $messages['diff'], 'diff=prev&oldid=' . $row->rev_id );
273 else
274 $diff = $messages['diff'];
276 if( $row->is_minor )
277 $mflag = '<span class="minor">' . $messages['minoreditletter'] . '</span> ';
278 else
279 $mflag = '';
281 $link = $skin->makeKnownLinkObj( $page );
282 $comment = $skin->revComment( $rev );
284 $user = $this->getRowUserLinks( $skin, $row ); // for subclasses
286 $notes = '';
288 if( $row->rev_id == $row->cur_id ) {
289 $notes .= ' <strong>' . $messages['uctop'] . '</strong>';
291 if( $wgUser->isAllowed( 'rollback' ) )
292 $notes .= ' ' . $skin->generateRollback( $rev );
295 if( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
296 $time = '<span class="history-deleted">' . $time . '</span>';
297 $notes .= ' ' . wfMsgHtml( 'deletedrev' );
300 return "{$time} ({$hist}) ({$diff}) {$mflag} {$dm}{$link}{$user} {$comment}{$notes}";
305 * Show the special page.
307 function wfSpecialContributions( $par = null ) {
308 global $wgRequest, $wgUser, $wgOut;
310 $username = ( isset($par) ? $par : $wgRequest->getVal( 'target' ) );
312 // compatibility hack
313 if ( $username == 'newbies' ) {
314 $wgOut->redirect( SpecialPage::getTitleFor( 'NewbieContributions' )->getFullURL() );
315 return;
318 $page = new ContributionsPage( $username );
320 if( !$page->user ) {
321 $wgOut->showErrorPage( 'notargettitle', 'notargettext' );
322 return;
325 // hook for Contributionseditcount extension
326 if ( $page->user && $page->user->isLoggedIn() )
327 wfRunHooks( 'SpecialContributionsBeforeMainOutput', $page->user->getId() );
329 $page->namespace = $wgRequest->getIntOrNull( 'namespace' );
330 $page->botmode = ( $wgUser->isAllowed( 'rollback' ) && $wgRequest->getBool( 'bot' ) );
332 list( $limit, $offset ) = wfCheckLimits();
333 return $page->doQuery( $offset, $limit );