Index: trunk/phase3/includes/Article.php |
— | — | @@ -1782,6 +1782,8 @@ |
1783 | 1783 | $confirm = $wgRequest->wasPosted() && |
1784 | 1784 | $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ); |
1785 | 1785 | $reason = $wgRequest->getText( 'wpReason' ); |
| 1786 | + # Flag to hide all contents of the archived revisions |
| 1787 | + $suppress = $wgRequest->getVal( 'wpSuppress' ) && $wgUser->isAllowed('deleterevision'); |
1786 | 1788 | |
1787 | 1789 | # This code desperately needs to be totally rewritten |
1788 | 1790 | |
— | — | @@ -1813,7 +1815,7 @@ |
1814 | 1816 | } |
1815 | 1817 | |
1816 | 1818 | if( $confirm ) { |
1817 | | - $this->doDelete( $reason ); |
| 1819 | + $this->doDelete( $reason, $suppress ); |
1818 | 1820 | if( $wgRequest->getCheck( 'wpWatch' ) ) { |
1819 | 1821 | $this->doWatch(); |
1820 | 1822 | } elseif( $this->mTitle->userIsWatching() ) { |
— | — | @@ -1959,7 +1961,14 @@ |
1960 | 1962 | $delcom = htmlspecialchars( wfMsg( 'deletecomment' ) ); |
1961 | 1963 | $token = htmlspecialchars( $wgUser->editToken() ); |
1962 | 1964 | $watch = Xml::checkLabel( wfMsg( 'watchthis' ), 'wpWatch', 'wpWatch', $wgUser->getBoolOption( 'watchdeletion' ) || $this->mTitle->userIsWatching(), array( 'tabindex' => '2' ) ); |
1963 | | - |
| 1965 | + if ( $wgUser->isAllowed( 'deleterevision' ) ) { |
| 1966 | + $supress = "<tr><td> </td><td>"; |
| 1967 | + $supress .= Xml::checkLabel( wfMsg( 'revdelete-suppress' ), 'wpSuppress', 'wpSuppress', false, array( 'tabindex' => '2' ) ); |
| 1968 | + $supress .= "</td></tr>"; |
| 1969 | + } else { |
| 1970 | + $supress = ''; |
| 1971 | + } |
| 1972 | + |
1964 | 1973 | $wgOut->addHTML( " |
1965 | 1974 | <form id='deleteconfirm' method='post' action=\"{$formaction}\"> |
1966 | 1975 | <table border='0'> |
— | — | @@ -1971,6 +1980,7 @@ |
1972 | 1981 | <input type='text' size='60' name='wpReason' id='wpReason' value=\"" . htmlspecialchars( $reason ) . "\" tabindex=\"1\" /> |
1973 | 1982 | </td> |
1974 | 1983 | </tr> |
| 1984 | + $supress |
1975 | 1985 | <tr> |
1976 | 1986 | <td> </td> |
1977 | 1987 | <td>$watch</td> |
— | — | @@ -2009,12 +2019,12 @@ |
2010 | 2020 | /** |
2011 | 2021 | * Perform a deletion and output success or failure messages |
2012 | 2022 | */ |
2013 | | - function doDelete( $reason ) { |
| 2023 | + function doDelete( $reason, $suppress = false ) { |
2014 | 2024 | global $wgOut, $wgUser; |
2015 | 2025 | wfDebug( __METHOD__."\n" ); |
2016 | 2026 | |
2017 | 2027 | if (wfRunHooks('ArticleDelete', array(&$this, &$wgUser, &$reason))) { |
2018 | | - if ( $this->doDeleteArticle( $reason ) ) { |
| 2028 | + if ( $this->doDeleteArticle( $reason, $suppress ) ) { |
2019 | 2029 | $deleted = wfEscapeWikiText( $this->mTitle->getPrefixedText() ); |
2020 | 2030 | |
2021 | 2031 | $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) ); |
— | — | @@ -2037,7 +2047,7 @@ |
2038 | 2048 | * Deletes the article with database consistency, writes logs, purges caches |
2039 | 2049 | * Returns success |
2040 | 2050 | */ |
2041 | | - function doDeleteArticle( $reason ) { |
| 2051 | + function doDeleteArticle( $reason, $suppress = false ) { |
2042 | 2052 | global $wgUseSquid, $wgDeferredUpdateList; |
2043 | 2053 | global $wgUseTrackbacks; |
2044 | 2054 | |
— | — | @@ -2055,6 +2065,17 @@ |
2056 | 2066 | $u = new SiteStatsUpdate( 0, 1, -(int)$this->isCountable( $this->getContent() ), -1 ); |
2057 | 2067 | array_push( $wgDeferredUpdateList, $u ); |
2058 | 2068 | |
| 2069 | + / Bitfields to further supress the content |
| 2070 | + if ( $suppress ) { |
| 2071 | + $bitfield = 0; |
| 2072 | + $bitfield |= Revision::DELETED_TEXT; |
| 2073 | + $bitfield |= Revision::DELETED_COMMENT; |
| 2074 | + $bitfield |= Revision::DELETED_USER; |
| 2075 | + $bitfield |= Revision::DELETED_RESTRICTED; |
| 2076 | + } else { |
| 2077 | + $bitfield = 'rev_deleted'; |
| 2078 | + } |
| 2079 | + |
2059 | 2080 | / For now, shunt the revision data into the archive table. |
2060 | 2081 | / Text is *not* removed from the text table; bulk storage |
2061 | 2082 | / is left intact to avoid breaking block-compression or |
— | — | @@ -2078,7 +2099,7 @@ |
2079 | 2100 | 'ar_text_id' => 'rev_text_id', |
2080 | 2101 | 'ar_text' => '\'\'', / Be explicit to appease |
2081 | 2102 | 'ar_flags' => '\'\'', / MySQL's "strict mode"... |
2082 | | - 'ar_len' => 'rev_len' |
| 2103 | + 'ar_deleted' => $bitfield |
2083 | 2104 | ), array( |
2084 | 2105 | 'page_id' => $id, |
2085 | 2106 | 'page_id = rev_page' |
— | — | @@ -2119,8 +2140,9 @@ |
2120 | 2141 | # Clear caches |
2121 | 2142 | Article::onArticleDelete( $this->mTitle ); |
2122 | 2143 | |
2123 | | - # Log the deletion |
2124 | | - $log = new LogPage( 'delete' ); |
| 2144 | + # Log the deletion, if the page was suppressed, log it at Oversight instead |
| 2145 | + $logtype = ($suppress) ? 'oversight' : 'delete'; |
| 2146 | + $log = new LogPage( $logtype ); |
2125 | 2147 | $log->addEntry( 'delete', $this->mTitle, $reason ); |
2126 | 2148 | |
2127 | 2149 | # Clear the cached article id so the interface doesn't act like we exist |
— | — | @@ -2226,8 +2248,13 @@ |
2227 | 2249 | ); |
2228 | 2250 | } |
2229 | 2251 | |
| 2252 | + $target = Revision::newFromId( $s->rev_id ); |
| 2253 | + # Revision *must* be public and we don't well handle deleted edits on top |
| 2254 | + if ( $target->isDeleted(REVISION::DELETED_TEXT) ) { |
| 2255 | + $wgOut->setPageTitle( wfMsg('rollbackfailed') ); |
| 2256 | + $wgOut->addHTML( wfMsg( 'missingarticle' ) ); |
| 2257 | + } |
2230 | 2258 | # Get the edit summary |
2231 | | - $target = Revision::newFromId( $s->rev_id ); |
2232 | 2259 | $newComment = wfMsgForContent( 'revertpage', $target->getUserText(), $from ); |
2233 | 2260 | $newComment = $wgRequest->getText( 'summary', $newComment ); |
2234 | 2261 | |
— | — | @@ -2405,10 +2432,30 @@ |
2406 | 2433 | ? wfMsg( 'diff' ) |
2407 | 2434 | : $sk->makeKnownLinkObj( $this->mTitle, wfMsg( 'diff' ), 'diff=next&oldid='.$oldid ); |
2408 | 2435 | |
2409 | | - $userlinks = $sk->userLink( $revision->getUser(), $revision->getUserText() ) |
2410 | | - . $sk->userToolLinks( $revision->getUser(), $revision->getUserText() ); |
| 2436 | + $cdel=''; |
| 2437 | + if( $wgUser->isAllowed( 'deleterevision' ) ) { |
| 2438 | + $revdel = SpecialPage::getTitleFor( 'Revisiondelete' ); |
| 2439 | + if( $revision->isCurrent() ) { |
| 2440 | + / We don't handle top deleted edits too well |
| 2441 | + $cdel = wfMsgHtml('rev-delundel'); |
| 2442 | + } else if( !$revision->userCan( Revision::DELETED_RESTRICTED ) ) { |
| 2443 | + / If revision was hidden from sysops |
| 2444 | + $cdel = wfMsgHtml('rev-delundel'); |
| 2445 | + } else { |
| 2446 | + $cdel = $sk->makeKnownLinkObj( $revdel, |
| 2447 | + wfMsgHtml('rev-delundel'), |
| 2448 | + 'target=' . urlencode( $this->mTitle->getPrefixedDbkey() ) . |
| 2449 | + '&oldid=' . urlencode( $oldid ) ); |
| 2450 | + / Bolden oversighted content |
| 2451 | + if( $revision->isDeleted( Revision::DELETED_RESTRICTED ) ) |
| 2452 | + $cdel = "<strong>$cdel</strong>"; |
| 2453 | + } |
| 2454 | + $cdel = "(<small>$cdel</small>)"; |
| 2455 | + } |
2411 | 2456 | |
2412 | | - $r = "\n\t\t\t\t<div id=\"mw-revision-info\">" . wfMsg( 'revision-info', $td, $userlinks ) . "</div>\n" . |
| 2457 | + $userlinks = $sk->revUserTools( $revision, true ); |
| 2458 | + |
| 2459 | + $r = "\n\t\t\t\t<div id=\"mw-revision-info\">" . "<tt>$cdel</tt>" . wfMsg( 'revision-info', $td, $userlinks ) . "</div>\n" . |
2413 | 2460 | "\n\t\t\t\t<div id=\"mw-revision-nav\">" . wfMsg( 'revision-nav', $prevdiff, $prevlink, $lnk, $curdiff, $nextlink, $nextdiff ) . "</div>\n\t\t\t"; |
2414 | 2461 | $wgOut->setSubtitle( $r ); |
2415 | 2462 | } |
Index: trunk/phase3/includes/RecentChange.php |
— | — | @@ -25,6 +25,11 @@ |
26 | 26 | * rc_patrolled boolean whether or not someone has marked this edit as patrolled |
27 | 27 | * rc_old_len integer byte length of the text before the edit |
28 | 28 | * rc_new_len the same after the edit |
| 29 | + * rc_deleted partial deletion |
| 30 | + * rc_logid the log_id value for this log entry (or zero) |
| 31 | + * rc_log_type the log type (or null) |
| 32 | + * rc_log_action the log action (or null) |
| 33 | + * rc_params log params |
29 | 34 | * |
30 | 35 | * mExtra: |
31 | 36 | * prefixedDBkey prefixed db key, used by external app via msg queue |
— | — | @@ -227,8 +232,7 @@ |
228 | 233 | |
229 | 234 | # Makes an entry in the database corresponding to an edit |
230 | 235 | /*static*/ function notifyEdit( $timestamp, &$title, $minor, &$user, $comment, |
231 | | - $oldId, $lastTimestamp, $bot = "default", $ip = '', $oldSize = 0, $newSize = 0, |
232 | | - $newId = 0) |
| 236 | + $oldId, $lastTimestamp, $bot="default", $ip='', $oldSize=0, $newSize=0, $newId=0) |
233 | 237 | { |
234 | 238 | |
235 | 239 | if ( $bot === 'default' ) { |
— | — | @@ -263,7 +267,12 @@ |
264 | 268 | 'rc_patrolled' => 0, |
265 | 269 | 'rc_new' => 0, # obsolete |
266 | 270 | 'rc_old_len' => $oldSize, |
267 | | - 'rc_new_len' => $newSize |
| 271 | + 'rc_new_len' => $newSize, |
| 272 | + 'rc_deleted' => 0, |
| 273 | + 'rc_logid' => 0, |
| 274 | + 'rc_log_type' => null, |
| 275 | + 'rc_log_action' => '', |
| 276 | + 'rc_params' => '' |
268 | 277 | ); |
269 | 278 | |
270 | 279 | $rc->mExtra = array( |
— | — | @@ -284,7 +293,7 @@ |
285 | 294 | * @static |
286 | 295 | */ |
287 | 296 | public static function notifyNew( $timestamp, &$title, $minor, &$user, $comment, $bot = "default", |
288 | | - $ip='', $size = 0, $newId = 0 ) |
| 297 | + $ip='', $size=0, $newId=0 ) |
289 | 298 | { |
290 | 299 | if ( !$ip ) { |
291 | 300 | $ip = wfGetIP(); |
— | — | @@ -292,6 +301,7 @@ |
293 | 302 | $ip = ''; |
294 | 303 | } |
295 | 304 | } |
| 305 | + |
296 | 306 | if ( $bot == 'default' ) { |
297 | 307 | $bot = $user->isAllowed( 'bot' ); |
298 | 308 | } |
— | — | @@ -315,9 +325,14 @@ |
316 | 326 | 'rc_moved_to_title' => '', |
317 | 327 | 'rc_ip' => $ip, |
318 | 328 | 'rc_patrolled' => 0, |
319 | | - 'rc_new' => 1, # obsolete |
| 329 | + 'rc_new' => 1, # obsolete |
320 | 330 | 'rc_old_len' => 0, |
321 | | - 'rc_new_len' => $size |
| 331 | + 'rc_new_len' => $size, |
| 332 | + 'rc_deleted' => 0, |
| 333 | + 'rc_logid' => 0, |
| 334 | + 'rc_log_type' => null, |
| 335 | + 'rc_log_action' => '', |
| 336 | + 'rc_params' => '' |
322 | 337 | ); |
323 | 338 | |
324 | 339 | $rc->mExtra = array( |
— | — | @@ -339,7 +354,7 @@ |
340 | 355 | $ip = ''; |
341 | 356 | } |
342 | 357 | } |
343 | | - |
| 358 | + |
344 | 359 | $rc = new RecentChange; |
345 | 360 | $rc->mAttribs = array( |
346 | 361 | 'rc_timestamp' => $timestamp, |
— | — | @@ -362,6 +377,11 @@ |
363 | 378 | 'rc_patrolled' => 1, |
364 | 379 | 'rc_old_len' => NULL, |
365 | 380 | 'rc_new_len' => NULL, |
| 381 | + 'rc_deleted' => 0, |
| 382 | + 'rc_logid' => 0, # notifyMove not used anymore |
| 383 | + 'rc_log_type' => null, |
| 384 | + 'rc_log_action' => '', |
| 385 | + 'rc_params' => '' |
366 | 386 | ); |
367 | 387 | |
368 | 388 | $rc->mExtra = array( |
— | — | @@ -380,18 +400,14 @@ |
381 | 401 | RecentChange::notifyMove( $timestamp, $oldTitle, $newTitle, $user, $comment, $ip, true ); |
382 | 402 | } |
383 | 403 | |
384 | | - # A log entry is different to an edit in that previous revisions are |
385 | | - # not kept |
386 | | - /*static*/ function notifyLog( $timestamp, &$title, &$user, $comment, $ip='', |
387 | | - $type, $action, $target, $logComment, $params ) |
| 404 | + # A log entry is different to an edit in that previous revisions are not kept |
| 405 | + /*static*/ function notifyLog( $timestamp, &$title, &$user, $actionText = null, $ip='', |
| 406 | + $type, $action, $target, $logComment, $params, $newId=0 ) |
388 | 407 | { |
389 | 408 | if ( !$ip ) { |
390 | 409 | $ip = wfGetIP(); |
391 | | - if ( !$ip ) { |
392 | | - $ip = ''; |
393 | | - } |
| 410 | + if ( !$ip ) $ip = ''; |
394 | 411 | } |
395 | | - |
396 | 412 | $rc = new RecentChange; |
397 | 413 | $rc->mAttribs = array( |
398 | 414 | 'rc_timestamp' => $timestamp, |
— | — | @@ -403,7 +419,7 @@ |
404 | 420 | 'rc_cur_id' => $title->getArticleID(), |
405 | 421 | 'rc_user' => $user->getID(), |
406 | 422 | 'rc_user_text' => $user->getName(), |
407 | | - 'rc_comment' => $comment, |
| 423 | + 'rc_comment' => $logComment, |
408 | 424 | 'rc_this_oldid' => 0, |
409 | 425 | 'rc_last_oldid' => 0, |
410 | 426 | 'rc_bot' => $user->isAllowed( 'bot' ) ? 1 : 0, |
— | — | @@ -414,6 +430,11 @@ |
415 | 431 | 'rc_new' => 0, # obsolete |
416 | 432 | 'rc_old_len' => NULL, |
417 | 433 | 'rc_new_len' => NULL, |
| 434 | + 'rc_deleted' => 0, |
| 435 | + 'rc_logid' => $newId, |
| 436 | + 'rc_log_type' => $type, |
| 437 | + 'rc_log_action' => $action, |
| 438 | + 'rc_params' => $params |
418 | 439 | ); |
419 | 440 | $rc->mExtra = array( |
420 | 441 | 'prefixedDBkey' => $title->getPrefixedDBkey(), |
— | — | @@ -460,6 +481,11 @@ |
461 | 482 | 'rc_new' => $row->page_is_new, # obsolete |
462 | 483 | 'rc_old_len' => $row->rc_old_len, |
463 | 484 | 'rc_new_len' => $row->rc_new_len, |
| 485 | + 'rc_deleted' => $row->rc_deleted, |
| 486 | + 'rc_logid' => $row->rc_logid, |
| 487 | + 'rc_log_type' => $row->rc_log_type, |
| 488 | + 'rc_log_action' => $row->rc_log_action, |
| 489 | + 'rc_params' => $row->rc_params |
464 | 490 | ); |
465 | 491 | |
466 | 492 | $this->mExtra = array(); |
Index: trunk/phase3/includes/SpecialRecentchanges.php |
— | — | @@ -404,7 +404,7 @@ |
405 | 405 | rcFormatDiff( $obj ), |
406 | 406 | $title->getFullURL(), |
407 | 407 | $obj->rc_timestamp, |
408 | | - $obj->rc_user_text, |
| 408 | + ($obj->rc_deleted & Revision::DELETED_USER) ? wfMsgHtml('rev-deleted-user') : $obj->rc_user_text, |
409 | 409 | $talkpage->getFullURL() |
410 | 410 | ); |
411 | 411 | $feed->outItem( $item ); |
— | — | @@ -613,15 +613,18 @@ |
614 | 614 | return rcFormatDiffRow( $titleObj, |
615 | 615 | $row->rc_last_oldid, $row->rc_this_oldid, |
616 | 616 | $timestamp, |
617 | | - $row->rc_comment ); |
| 617 | + ($row->rc_deleted & Revision::DELETED_COMMENT) ? wfMsgHtml('rev-deleted-comment') : $row->rc_comment, |
| 618 | + ($row->rc_deleted & Revision::DELETED_NAME) ? wfMsgHtml('rev-deleted-event') : $row->rc_actiontext ); |
618 | 619 | } |
619 | 620 | |
620 | | -function rcFormatDiffRow( $title, $oldid, $newid, $timestamp, $comment ) { |
| 621 | +function rcFormatDiffRow( $title, $oldid, $newid, $timestamp, $comment, $actiontext='' ) { |
621 | 622 | global $wgFeedDiffCutoff, $wgContLang, $wgUser; |
622 | 623 | $fname = 'rcFormatDiff'; |
623 | 624 | wfProfileIn( $fname ); |
624 | 625 | |
625 | 626 | $skin = $wgUser->getSkin(); |
| 627 | + # log enties |
| 628 | + if( $actiontext ) $comment = "$actiontext $comment"; |
626 | 629 | $completeText = '<p>' . $skin->formatComment( $comment ) . "</p>\n"; |
627 | 630 | |
628 | 631 | if( $title->getNamespace() >= 0 && $title->userCan( 'read' ) ) { |
Index: trunk/phase3/includes/ImagePage.php |
— | — | @@ -508,7 +508,9 @@ |
509 | 509 | $reason = $wgRequest->getVal( 'wpReason' ); |
510 | 510 | $image = $wgRequest->getVal( 'image' ); |
511 | 511 | $oldimage = $wgRequest->getVal( 'oldimage' ); |
512 | | - |
| 512 | + # Flag to hide all contents of the archived revisions |
| 513 | + $suppress = $wgRequest->getVal( 'wpSuppress' ) && $wgUser->isAllowed('deleterevision'); |
| 514 | + |
513 | 515 | # Only sysops can delete images. Previously ordinary users could delete |
514 | 516 | # old revisions, but this is no longer the case. |
515 | 517 | if ( !$wgUser->isAllowed('delete') ) { |
— | — | @@ -536,7 +538,7 @@ |
537 | 539 | # Deleting old images doesn't require confirmation |
538 | 540 | if ( !is_null( $oldimage ) || $confirm ) { |
539 | 541 | if( $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ), $oldimage ) ) { |
540 | | - $this->doDelete( $reason ); |
| 542 | + $this->doDelete( $reason, $suppress ); |
541 | 543 | } else { |
542 | 544 | $wgOut->showFatalError( wfMsg( 'sessionfailure' ) ); |
543 | 545 | } |
— | — | @@ -557,7 +559,7 @@ |
558 | 560 | * Delete an image. |
559 | 561 | * @param $reason User provided reason for deletion. |
560 | 562 | */ |
561 | | - function doDelete( $reason ) { |
| 563 | + function doDelete( $reason, $suppress=false ) { |
562 | 564 | global $wgOut, $wgRequest; |
563 | 565 | |
564 | 566 | $oldimage = $wgRequest->getVal( 'oldimage' ); |
— | — | @@ -571,12 +573,12 @@ |
572 | 574 | $wgOut->showUnexpectedValueError( 'oldimage', htmlspecialchars($oldimage) ); |
573 | 575 | return; |
574 | 576 | } |
575 | | - if ( !$this->doDeleteOldImage( $oldimage ) ) { |
| 577 | + if ( !$this->doDeleteOldImage( $oldimage, $suppress ) ) { |
576 | 578 | return; |
577 | 579 | } |
578 | 580 | $deleted = $oldimage; |
579 | 581 | } else { |
580 | | - $ok = $this->img->delete( $reason ); |
| 582 | + $ok = $this->img->delete( $reason, $suppress ); |
581 | 583 | if( !$ok ) { |
582 | 584 | # If the deletion operation actually failed, bug out: |
583 | 585 | $wgOut->showFileDeleteError( $this->img->getName() ); |
— | — | @@ -587,7 +589,7 @@ |
588 | 590 | # Now we remove the image description page. |
589 | 591 | |
590 | 592 | $article = new Article( $this->mTitle ); |
591 | | - $article->doDeleteArticle( $reason ); # ignore errors |
| 593 | + $article->doDeleteArticle( $reason, $suppress ); # ignore errors |
592 | 594 | |
593 | 595 | $deleted = $this->img->getName(); |
594 | 596 | } |
— | — | @@ -606,11 +608,11 @@ |
607 | 609 | /** |
608 | 610 | * @return success |
609 | 611 | */ |
610 | | - function doDeleteOldImage( $oldimage ) |
| 612 | + function doDeleteOldImage( $oldimage, $suppress=false ) |
611 | 613 | { |
612 | 614 | global $wgOut; |
613 | 615 | |
614 | | - $ok = $this->img->deleteOld( $oldimage, '' ); |
| 616 | + $ok = $this->img->deleteOld( $oldimage, '', $suppress ); |
615 | 617 | if( !$ok ) { |
616 | 618 | # If we actually have a file and can't delete it, throw an error. |
617 | 619 | # Something went awry... |
Index: trunk/phase3/includes/SpecialRevisiondelete.php |
— | — | @@ -2,36 +2,41 @@ |
3 | 3 | |
4 | 4 | /** |
5 | 5 | * Not quite ready for production use yet; need to fix up the restricted mode, |
6 | | - * and provide for preservation across delete/undelete of the page. |
7 | | - * |
8 | | - * To try this out, set up extra permissions something like: |
9 | | - * $wgGroupPermissions['sysop']['deleterevision'] = true; |
10 | | - * $wgGroupPermissions['bureaucrat']['hiderevision'] = true; |
| 6 | + * and provide for preservation across delete/undelete of images. |
11 | 7 | */ |
12 | 8 | |
13 | 9 | function wfSpecialRevisiondelete( $par = null ) { |
14 | 10 | global $wgOut, $wgRequest; |
15 | 11 | |
16 | | - $target = $wgRequest->getVal( 'target' ); |
| 12 | + $target = $wgRequest->getText( 'target' ); |
| 13 | + / handle our many different possible input types |
17 | 14 | $oldid = $wgRequest->getIntArray( 'oldid' ); |
18 | | - |
19 | | - $page = Title::newFromUrl( $target ); |
20 | | - |
| 15 | + $logid = $wgRequest->getIntArray( 'logid' ); |
| 16 | + $arid = $wgRequest->getIntArray( 'arid' ); |
| 17 | + $fileid = $wgRequest->getIntArray( 'fileid' ); |
| 18 | + |
| 19 | + $page = Title::newFromUrl( $target, false ); |
21 | 20 | if( is_null( $page ) ) { |
22 | 21 | $wgOut->showErrorPage( 'notargettitle', 'notargettext' ); |
23 | 22 | return; |
24 | 23 | } |
25 | | - |
26 | | - if( is_null( $oldid ) ) { |
| 24 | + |
| 25 | + $input_types = !is_null( $oldid ) + !is_null( $logid ) + !is_null( $arid ) + !is_null( $fileid ); |
| 26 | + if( $input_types > 1 || $input_types==0 ) { |
| 27 | + /one target set at a time please! |
27 | 28 | $wgOut->showErrorPage( 'revdelete-nooldid-title', 'revdelete-nooldid-text' ); |
28 | 29 | return; |
29 | 30 | } |
30 | 31 | |
31 | | - $form = new RevisionDeleteForm( $wgRequest ); |
| 32 | + $form = new RevisionDeleteForm( $wgRequest, $oldid, $logid, $arid, $fileid ); |
32 | 33 | if( $wgRequest->wasPosted() ) { |
33 | 34 | $form->submit( $wgRequest ); |
34 | | - } else { |
35 | | - $form->show( $wgRequest ); |
| 35 | + } else if( $oldid || $arid ) { |
| 36 | + $form->showRevs( $wgRequest ); |
| 37 | + } else if( $logid ) { |
| 38 | + $form->showEvents( $wgRequest ); |
| 39 | + } else if( $fileid ) { |
| 40 | + $form->showImages( $wgRequest ); |
36 | 41 | } |
37 | 42 | } |
38 | 43 | |
— | — | @@ -40,52 +45,259 @@ |
41 | 46 | * @param Title $page |
42 | 47 | * @param int $oldid |
43 | 48 | */ |
44 | | - function __construct( $request ) { |
| 49 | + function __construct( $request, $oldid, $logid, $arid, $fileid ) { |
45 | 50 | global $wgUser; |
46 | 51 | |
47 | | - $target = $request->getVal( 'target' ); |
48 | | - $this->page = Title::newFromUrl( $target ); |
| 52 | + $target = $request->getText( 'target' ); |
| 53 | + $this->page = Title::newFromUrl( $target, false ); |
49 | 54 | |
50 | 55 | $this->revisions = $request->getIntArray( 'oldid', array() ); |
| 56 | + $this->events = $request->getIntArray( 'logid', array() ); |
| 57 | + $this->archrevs = $request->getIntArray( 'arid', array() ); |
| 58 | + $this->files = $request->getIntArray( 'fileid', array() ); |
51 | 59 | |
52 | 60 | $this->skin = $wgUser->getSkin(); |
| 61 | + |
| 62 | + / log events don't have text to hide, but hiding the page name is useful |
| 63 | + if ( $fileid ) { |
| 64 | + $hide_text_name = array( 'revdelete-hide-image', 'wpHideImage', Image::DELETED_FILE ); |
| 65 | + $this->deletetype='file'; |
| 66 | + } else if ( $logid ) { |
| 67 | + $hide_text_name = array( 'revdelete-hide-name', 'wpHideName', LogViewer::DELETED_ACTION ); |
| 68 | + $this->deletetype='log'; |
| 69 | + } else { |
| 70 | + $hide_text_name = array( 'revdelete-hide-text', 'wpHideText', Revision::DELETED_TEXT ); |
| 71 | + if ( $arid ) $this->deletetype='ar'; |
| 72 | + else $this->deletetype='old'; |
| 73 | + } |
53 | 74 | $this->checks = array( |
54 | | - array( 'revdelete-hide-text', 'wpHideText', Revision::DELETED_TEXT ), |
| 75 | + $hide_text_name, |
55 | 76 | array( 'revdelete-hide-comment', 'wpHideComment', Revision::DELETED_COMMENT ), |
56 | 77 | array( 'revdelete-hide-user', 'wpHideUser', Revision::DELETED_USER ), |
57 | 78 | array( 'revdelete-hide-restricted', 'wpHideRestricted', Revision::DELETED_RESTRICTED ) ); |
58 | 79 | } |
59 | 80 | |
60 | 81 | /** |
| 82 | + * This sets any fields that are true to a bitfield to true on a given bitfield |
| 83 | + * @param $bitfield, running bitfield |
| 84 | + * @param $nbitfield, new bitfiled |
| 85 | + */ |
| 86 | + function setBitfield( $bitfield, $nbitfield ) { |
| 87 | + if ( $nbitfield & Revision::DELETED_TEXT) $bitfield |= Revision::DELETED_TEXT; |
| 88 | + if ( $nbitfield & LogViewer::DELETED_ACTION) $bitfield |= LogViewer::DELETED_ACTION; |
| 89 | + if ( $nbitfield & Image::DELETED_FILE) $bitfield |= Image::DELETED_FILE; |
| 90 | + if ( $nbitfield & Revision::DELETED_COMMENT) $bitfield |= Revision::DELETED_COMMENT; |
| 91 | + if ( $nbitfield & Revision::DELETED_USER) $bitfield |= Revision::DELETED_USER; |
| 92 | + if ( $nbitfield & Revision::DELETED_RESTRICTED) $bitfield |= Revision::DELETED_RESTRICTED; |
| 93 | + return $bitfield; |
| 94 | + } |
| 95 | + |
| 96 | + /** |
| 97 | + * This lets a user set restrictions for live and archived revisions |
61 | 98 | * @param WebRequest $request |
62 | 99 | */ |
63 | | - function show( $request ) { |
64 | | - global $wgOut, $wgUser; |
| 100 | + function showRevs( $request ) { |
| 101 | + global $wgOut, $wgUser, $action; |
65 | 102 | |
66 | | - $wgOut->addWikiText( wfMsg( 'revdelete-selected', $this->page->getPrefixedText() ) ); |
| 103 | + $UserAllowed = true; |
| 104 | + $wgOut->addWikiText( wfMsgHtml( 'revdelete-selected', $this->page->getPrefixedText() ) ); |
67 | 105 | |
| 106 | + $bitfields = 0; |
68 | 107 | $wgOut->addHtml( "<ul>" ); |
69 | | - foreach( $this->revisions as $revid ) { |
70 | | - $rev = Revision::newFromTitle( $this->page, $revid ); |
71 | | - if( !isset( $rev ) ) { |
| 108 | + if ( $this->deletetype=='old') { |
| 109 | + foreach( $this->revisions as $revid ) { |
| 110 | + $rev = Revision::newFromTitle( $this->page, $revid ); |
| 111 | + / Hiding top revisison is bad |
| 112 | + if( !isset( $rev ) || $rev->isCurrent() ) { |
| 113 | + $wgOut->showErrorPage( 'revdelete-nooldid-title', 'revdelete-nooldid-text' ); |
| 114 | + return; |
| 115 | + } else if( !$rev->userCan(Revision::DELETED_RESTRICTED) ) { |
| 116 | + / If a rev is hidden from sysops |
| 117 | + if ( $action != 'submit') { |
| 118 | + $wgOut->permissionRequired( 'hiderevision' ); return; |
| 119 | + } |
| 120 | + $UserAllowed=false; |
| 121 | + } |
| 122 | + $wgOut->addHtml( $this->historyLine( $rev ) ); |
| 123 | + $bitfields = $this->setBitfield( $bitfields, $rev->mDeleted ); |
| 124 | + } |
| 125 | + } else if ( $this->deletetype=='ar') { |
| 126 | + $archive = new PageArchive( $this->page ); |
| 127 | + foreach( $this->archrevs as $revid ) { |
| 128 | + $rev = $archive->getRevision('', $revid ); |
| 129 | + if( !isset( $rev ) ) { |
| 130 | + $wgOut->showErrorPage( 'revdelete-nooldid-title', 'revdelete-nooldid-text' ); |
| 131 | + return; |
| 132 | + } else if( !$rev->userCan(Revision::DELETED_RESTRICTED) ) { |
| 133 | + /if a rev is hidden from sysops |
| 134 | + if ( $action != 'submit') { |
| 135 | + $wgOut->permissionRequired( 'hiderevision' ); return; |
| 136 | + } |
| 137 | + $UserAllowed=false; |
| 138 | + } |
| 139 | + $wgOut->addHtml( $this->historyLine( $rev ) ); |
| 140 | + $bitfields = $this->setBitfield( $bitfields, $rev->mDeleted ); |
| 141 | + } |
| 142 | + } |
| 143 | + $wgOut->addHtml( "</ul>" ); |
| 144 | + |
| 145 | + $wgOut->addWikiText( wfMsgHtml( 'revdelete-text' ) ); |
| 146 | + /Normal sysops can always see what they did, but can't always change it |
| 147 | + if ( !$UserAllowed ) return; |
| 148 | + |
| 149 | + $items = array( |
| 150 | + wfInputLabel( wfMsgHtml( 'revdelete-log' ), 'wpReason', 'wpReason', 60 ), |
| 151 | + wfSubmitButton( wfMsgHtml( 'revdelete-submit' ) ) ); |
| 152 | + $hidden = array( |
| 153 | + wfHidden( 'wpEditToken', $wgUser->editToken() ), |
| 154 | + wfHidden( 'target', $this->page->getPrefixedText() ), |
| 155 | + wfHidden( 'type', $this->deletetype ) ); |
| 156 | + if( $this->deletetype=='old' ) { |
| 157 | + foreach( $this->revisions as $revid ) { |
| 158 | + $hidden[] = wfHidden( 'oldid[]', $revid ); |
| 159 | + } |
| 160 | + } else if( $this->deletetype=='ar' ) { |
| 161 | + foreach( $this->archrevs as $revid ) { |
| 162 | + $hidden[] = wfHidden( 'arid[]', $revid ); |
| 163 | + } |
| 164 | + } |
| 165 | + $special = SpecialPage::getTitleFor( 'Revisiondelete' ); |
| 166 | + $wgOut->addHtml( wfElement( 'form', array( |
| 167 | + 'method' => 'post', |
| 168 | + 'action' => $special->getLocalUrl( 'action=submit' ) ), |
| 169 | + null ) ); |
| 170 | + |
| 171 | + $wgOut->addHtml( '<fieldset><legend>' . wfMsgHtml( 'revdelete-legend' ) . '</legend>' ); |
| 172 | + / FIXME: all items checked for just one rev are checked, even if not set for the others |
| 173 | + foreach( $this->checks as $item ) { |
| 174 | + list( $message, $name, $field ) = $item; |
| 175 | + $wgOut->addHtml( '<div>' . |
| 176 | + wfCheckLabel( wfMsgHtml( $message), $name, $name, $bitfields & $field ) . |
| 177 | + '</div>' ); |
| 178 | + } |
| 179 | + $wgOut->addHtml( '</fieldset>' ); |
| 180 | + foreach( $items as $item ) { |
| 181 | + $wgOut->addHtml( '<p>' . $item . '</p>' ); |
| 182 | + } |
| 183 | + foreach( $hidden as $item ) { |
| 184 | + $wgOut->addHtml( $item ); |
| 185 | + } |
| 186 | + |
| 187 | + $wgOut->addHtml( '</form>' ); |
| 188 | + } |
| 189 | + |
| 190 | + /** |
| 191 | + * This lets a user set restrictions for archived images |
| 192 | + * @param WebRequest $request |
| 193 | + */ |
| 194 | + function showImages( $request ) { |
| 195 | + global $wgOut, $wgUser, $action; |
| 196 | + |
| 197 | + $UserAllowed = true; |
| 198 | + $wgOut->addWikiText( wfMsgHtml( 'revdelete-selected', $this->page->getPrefixedText() ) ); |
| 199 | + |
| 200 | + $bitfields = 0; |
| 201 | + $wgOut->addHtml( "<ul>" ); |
| 202 | + foreach( $this->files as $fileid ) { |
| 203 | + $file = new FSarchivedFile( $this->page, $fileid ); |
| 204 | + if( !isset( $file->mId ) ) { |
| 205 | + $wgOut->showErrorPage( 'revdelete-nooldid-title', 'revdelete-nooldid-text' ); |
| 206 | + return; |
| 207 | + } else if( !$file->userCan(Revision::DELETED_RESTRICTED) ) { |
| 208 | + / If a rev is hidden from sysops |
| 209 | + if ( $action != 'submit') { |
| 210 | + $wgOut->permissionRequired( 'hiderevision' ); return; |
| 211 | + } |
| 212 | + $UserAllowed=false; |
| 213 | + } |
| 214 | + $wgOut->addHtml( $this->uploadLine( $file ) ); |
| 215 | + $bitfields = $this->setBitfield( $bitfields, $file->mDeleted ); |
| 216 | + } |
| 217 | + $wgOut->addHtml( "</ul>" ); |
| 218 | + |
| 219 | + $wgOut->addWikiText( wfMsgHtml( 'revdelete-text' ) ); |
| 220 | + /Normal sysops can always see what they did, but can't always change it |
| 221 | + if ( !$UserAllowed ) return; |
| 222 | + |
| 223 | + $items = array( |
| 224 | + wfInputLabel( wfMsgHtml( 'revdelete-log' ), 'wpReason', 'wpReason', 60 ), |
| 225 | + wfSubmitButton( wfMsgHtml( 'revdelete-submit' ) ) ); |
| 226 | + $hidden = array( |
| 227 | + wfHidden( 'wpEditToken', $wgUser->editToken() ), |
| 228 | + wfHidden( 'target', $this->page->getPrefixedText() ), |
| 229 | + wfHidden( 'type', $this->deletetype ) ); |
| 230 | + foreach( $this->files as $fileid ) { |
| 231 | + $hidden[] = wfHidden( 'fileid[]', $fileid ); |
| 232 | + } |
| 233 | + $special = SpecialPage::getTitleFor( 'Revisiondelete' ); |
| 234 | + $wgOut->addHtml( wfElement( 'form', array( |
| 235 | + 'method' => 'post', |
| 236 | + 'action' => $special->getLocalUrl( 'action=submit' ) ), |
| 237 | + null ) ); |
| 238 | + |
| 239 | + $wgOut->addHtml( '<fieldset><legend>' . wfMsgHtml( 'revdelete-legend' ) . '</legend>' ); |
| 240 | + / FIXME: all items checked for just one file are checked, even if not set for the others |
| 241 | + foreach( $this->checks as $item ) { |
| 242 | + list( $message, $name, $field ) = $item; |
| 243 | + $wgOut->addHtml( '<div>' . |
| 244 | + wfCheckLabel( wfMsgHtml( $message), $name, $name, $bitfields & $field ) . |
| 245 | + '</div>' ); |
| 246 | + } |
| 247 | + $wgOut->addHtml( '</fieldset>' ); |
| 248 | + foreach( $items as $item ) { |
| 249 | + $wgOut->addHtml( '<p>' . $item . '</p>' ); |
| 250 | + } |
| 251 | + foreach( $hidden as $item ) { |
| 252 | + $wgOut->addHtml( $item ); |
| 253 | + } |
| 254 | + |
| 255 | + $wgOut->addHtml( '</form>' ); |
| 256 | + } |
| 257 | + |
| 258 | + /** |
| 259 | + * This lets a user set restrictions for log items |
| 260 | + * @param WebRequest $request |
| 261 | + */ |
| 262 | + function showEvents( $request ) { |
| 263 | + global $wgOut, $wgUser, $action; |
| 264 | + |
| 265 | + $UserAllowed = true; |
| 266 | + $wgOut->addWikiText( wfMsgHtml( 'logdelete-selected', $this->page->getPrefixedText() ) ); |
| 267 | + |
| 268 | + $bitfields = 0; |
| 269 | + $wgOut->addHtml( "<ul>" ); |
| 270 | + foreach( $this->events as $logid ) { |
| 271 | + $log = new LogViewer( $wgRequest ); |
| 272 | + $event = LogReader::newFromTitle( $this->page, $logid ); |
| 273 | + / Don't hide from oversight log!!! |
| 274 | + if( !isset( $event ) || $event->log_type == 'oversight' ) { |
72 | 275 | $wgOut->showErrorPage( 'revdelete-nooldid-title', 'revdelete-nooldid-text' ); |
73 | 276 | return; |
| 277 | + } else if( !$log->userCan($event, Revision::DELETED_RESTRICTED) ) { |
| 278 | + / If an event is hidden from sysops |
| 279 | + if ( $action != 'submit') { |
| 280 | + $wgOut->permissionRequired( 'hiderevision' ); return; |
| 281 | + } |
| 282 | + $UserAllowed=false; |
74 | 283 | } |
75 | | - $wgOut->addHtml( $this->historyLine( $rev ) ); |
76 | | - $bitfields[] = $rev->mDeleted; / FIXME |
| 284 | + $wgOut->addHtml( $this->logLine( $log, $event ) ); |
| 285 | + $bitfields = $this->setBitfield( $bitfields, $event->log_deleted ); |
77 | 286 | } |
78 | 287 | $wgOut->addHtml( "</ul>" ); |
79 | | - |
80 | | - $wgOut->addWikiText( wfMsg( 'revdelete-text' ) ); |
| 288 | + |
| 289 | + $wgOut->addWikiText( wfMsgHtml( 'revdelete-text' ) ); |
| 290 | + /Normal sysops can always see what they did, but can't always change it |
| 291 | + if ( !$UserAllowed ) return; |
81 | 292 | |
82 | 293 | $items = array( |
83 | | - wfInputLabel( wfMsg( 'revdelete-log' ), 'wpReason', 'wpReason', 60 ), |
84 | | - wfSubmitButton( wfMsg( 'revdelete-submit' ) ) ); |
| 294 | + wfInputLabel( wfMsgHtml( 'revdelete-log' ), 'wpReason', 'wpReason', 60 ), |
| 295 | + wfSubmitButton( wfMsgHtml( 'revdelete-submit' ) ) ); |
85 | 296 | $hidden = array( |
86 | 297 | wfHidden( 'wpEditToken', $wgUser->editToken() ), |
87 | | - wfHidden( 'target', $this->page->getPrefixedText() ) ); |
88 | | - foreach( $this->revisions as $revid ) { |
89 | | - $hidden[] = wfHidden( 'oldid[]', $revid ); |
| 298 | + wfHidden( 'target', $this->page->getPrefixedText() ), |
| 299 | + wfHidden( 'type', $this->deletetype ) ); |
| 300 | + foreach( $this->events as $logid ) { |
| 301 | + $hidden[] = wfHidden( 'logid[]', $logid ); |
90 | 302 | } |
91 | 303 | |
92 | 304 | $special = SpecialPage::getTitleFor( 'Revisiondelete' ); |
— | — | @@ -95,10 +307,11 @@ |
96 | 308 | null ) ); |
97 | 309 | |
98 | 310 | $wgOut->addHtml( '<fieldset><legend>' . wfMsgHtml( 'revdelete-legend' ) . '</legend>' ); |
| 311 | + / FIXME: all items checked for just on event are checked, even if not set for the others |
99 | 312 | foreach( $this->checks as $item ) { |
100 | 313 | list( $message, $name, $field ) = $item; |
101 | 314 | $wgOut->addHtml( '<div>' . |
102 | | - wfCheckLabel( wfMsg( $message), $name, $name, $rev->isDeleted( $field ) ) . |
| 315 | + wfCheckLabel( wfMsgHtml( $message), $name, $name, $bitfields & $field ) . |
103 | 316 | '</div>' ); |
104 | 317 | } |
105 | 318 | $wgOut->addHtml( '</fieldset>' ); |
— | — | @@ -119,32 +332,136 @@ |
120 | 333 | function historyLine( $rev ) { |
121 | 334 | global $wgContLang; |
122 | 335 | $date = $wgContLang->timeanddate( $rev->getTimestamp() ); |
| 336 | + |
| 337 | + $difflink=''; $del = ''; |
| 338 | + if( $this->deletetype=='old' ) { |
| 339 | + $difflink = '(' . $this->skin->makeKnownLinkObj( $this->page, wfMsgHtml('diff'), |
| 340 | + '&diff=' . $rev->getId() . '&oldid=prev' ) . ')'; |
| 341 | + $revlink = $this->skin->makeLinkObj( $this->page, $date, 'oldid=' . $rev->getId() ); |
| 342 | + } else if( $this->deletetype=='ar' ) { |
| 343 | + $undelete = SpecialPage::getTitleFor( 'Undelete' ); |
| 344 | + $target = $this->page->getPrefixedText(); |
| 345 | + $revlink = $this->skin->makeLinkObj( $undelete, $date, "target=$target×tamp=" . $rev->getTimestamp() ); |
| 346 | + } |
| 347 | + |
| 348 | + if ( $rev->isDeleted(Revision::DELETED_TEXT) ) { |
| 349 | + $revlink = '<span class="history-deleted">'.$revlink.'</span>'; |
| 350 | + $del = ' <tt>' . wfMsgHtml( 'deletedrev' ) . '</tt>'; |
| 351 | + if ( !$rev->userCan(Revision::DELETED_TEXT) ) { |
| 352 | + $revlink = '<span class="history-deleted">'.$date.'</span>'; |
| 353 | + } |
| 354 | + } |
| 355 | + |
123 | 356 | return |
124 | | - "<li>" . |
125 | | - $this->skin->makeLinkObj( $this->page, $date, 'oldid=' . $rev->getId() ) . |
126 | | - " " . |
127 | | - $this->skin->revUserLink( $rev ) . |
128 | | - " " . |
129 | | - $this->skin->revComment( $rev ) . |
130 | | - "</li>"; |
| 357 | + "<li> $difflink $revlink " . $this->skin->revUserLink( $rev ) . " " . $this->skin->revComment( $rev ) . "$del</li>"; |
131 | 358 | } |
132 | 359 | |
133 | 360 | /** |
| 361 | + * @param Image $file |
| 362 | + * @returns string |
| 363 | + */ |
| 364 | + function uploadLine( $file ) { |
| 365 | + global $wgContLang; |
| 366 | + |
| 367 | + $target = $this->page->getPrefixedText(); |
| 368 | + $date = $wgContLang->timeanddate( $file->mTimestamp, true ); |
| 369 | + |
| 370 | + $del = ''; |
| 371 | + if ( $file->mGroup == 'deleted' ) { |
| 372 | + $undelete = SpecialPage::getTitleFor( 'Undelete' ); |
| 373 | + $pageLink = $this->skin->makeKnownLinkObj( $undelete, $date, "target=$target&file=$file->mKey" ); |
| 374 | + } else { |
| 375 | + $pageLink = $this->skin->makeKnownLinkObj( $this->page, $date, "file=$file->mKey" ); |
| 376 | + } |
| 377 | + if ( $file->isDeleted(Image::DELETED_FILE) ) { |
| 378 | + $pageLink = '<span class="history-deleted">' . $pageLink . '</span>'; |
| 379 | + $del = ' <tt>' . wfMsgHtml( 'deletedrev' ) . '</tt>'; |
| 380 | + if ( !$file->userCan(Image::DELETED_FILE) ) { |
| 381 | + $pageLink = '<span class="history-deleted">'.$date.'</span>'; |
| 382 | + } |
| 383 | + } |
| 384 | + |
| 385 | + $data = wfMsgHtml( 'widthheight', |
| 386 | + $wgContLang->formatNum( $file->mWidth ), |
| 387 | + $wgContLang->formatNum( $file->mHeight ) ) . |
| 388 | + ' (' . wfMsgHtml( 'nbytes', $wgContLang->formatNum( $file->mSize ) ) . ')'; |
| 389 | + |
| 390 | + return |
| 391 | + "<li> $pageLink " . $this->skin->fileUserLink( $file ) . " $data " . $this->skin->fileComment( $file ) . "$del</li>"; |
| 392 | + } |
| 393 | + |
| 394 | + /** |
| 395 | + * @param Revision $rev |
| 396 | + * @returns string |
| 397 | + */ |
| 398 | + function logLine( $log, $event ) { |
| 399 | + global $wgContLang; |
| 400 | + |
| 401 | + $date = $wgContLang->timeanddate( $event->log_timestamp ); |
| 402 | + $paramArray = LogPage::extractParams( $event->log_params ); |
| 403 | + |
| 404 | + if ( !LogViewer::userCan($event,LogViewer::DELETED_ACTION) ) { |
| 405 | + $action = '<span class="history-deleted">' . wfMsgHtml('rev-deleted-event') . '</span>'; |
| 406 | + } else { |
| 407 | + $action = LogPage::actionText( $event->log_type, $event->log_action, $this->page, $this->skin, $paramArray, true, true ); |
| 408 | + if( $event->log_deleted & LogViewer::DELETED_ACTION ) |
| 409 | + $action = '<span class="history-deleted">' . $action . '</span>'; |
| 410 | + } |
| 411 | + return |
| 412 | + "<li>$date" . " " . $this->skin->logUserLink( $event ) . " $action " . $this->skin->logComment( $event ) . "</li>"; |
| 413 | + } |
| 414 | + |
| 415 | + /** |
134 | 416 | * @param WebRequest $request |
135 | 417 | */ |
136 | 418 | function submit( $request ) { |
137 | 419 | $bitfield = $this->extractBitfield( $request ); |
138 | 420 | $comment = $request->getText( 'wpReason' ); |
139 | | - if( $this->save( $bitfield, $comment ) ) { |
140 | | - return $this->success( $request ); |
141 | | - } else { |
142 | | - return $this->show( $request ); |
143 | | - } |
| 421 | + |
| 422 | + $target = $request->getText( 'target' ); |
| 423 | + $title = Title::newFromURL( $target, false ); |
| 424 | + |
| 425 | + if( $this->save( $bitfield, $comment, $title ) ) { |
| 426 | + $this->success( $request ); |
| 427 | + } else if( $request->getCheck( 'oldid' ) || $request->getCheck( 'arid' ) ) { |
| 428 | + return $this->showRevs( $request ); |
| 429 | + } else if( $request->getCheck( 'logid' ) ) { |
| 430 | + return $this->showLogs( $request ); |
| 431 | + } else if( $request->getCheck( 'fileid' ) ) { |
| 432 | + return $this->showImages( $request ); |
| 433 | + } |
144 | 434 | } |
145 | 435 | |
146 | 436 | function success( $request ) { |
147 | 437 | global $wgOut; |
148 | | - $wgOut->addWikiText( 'woo' ); |
| 438 | + |
| 439 | + $wgOut->setPagetitle( wfMsgHtml( 'actioncomplete' ) ); |
| 440 | + |
| 441 | + $target = $request->getText( 'target' ); |
| 442 | + $type = $request->getText( 'type' ); |
| 443 | + |
| 444 | + $title = Title::newFromURL( $target, false ); |
| 445 | + $name = $title->makeName( $title->getNamespace(), $title->getText() ); |
| 446 | + |
| 447 | + $logtitle = SpecialPage::getTitleFor( 'Log' ); |
| 448 | + $loglink = $this->skin->makeKnownLinkObj( $logtitle, wfMsgHtml( 'viewpagelogs' ), |
| 449 | + wfArrayToCGI( array('page' => $name ) ) ); |
| 450 | + $histlink = $this->skin->makeKnownLinkObj( $title, wfMsgHtml( 'revhistory' ), |
| 451 | + wfArrayToCGI( array('action' => 'history' ) ) ); |
| 452 | + |
| 453 | + if ( $title->getNamespace() > -1) |
| 454 | + $wgOut->setSubtitle( '<p>'.$histlink.' / '.$loglink.'</p>' ); |
| 455 | + |
| 456 | + if( $type=='log' ) { |
| 457 | + $wgOut->addWikiText( wfMsgHtml('logdelete-success', $target), false ); |
| 458 | + $this->showEvents( $request ); |
| 459 | + } else if( $type=='old' || $type=='ar' ) { |
| 460 | + $wgOut->addWikiText( wfMsgHtml('revdelete-success', $target), false ); |
| 461 | + $this->showRevs( $request ); |
| 462 | + } else if ( $type=='file' ) { |
| 463 | + $wgOut->addWikiText( wfMsgHtml('revdelete-success', $target), false ); |
| 464 | + $this->showImages( $request ); |
| 465 | + } |
149 | 466 | } |
150 | 467 | |
151 | 468 | /** |
— | — | @@ -163,10 +480,19 @@ |
164 | 481 | return $bitfield; |
165 | 482 | } |
166 | 483 | |
167 | | - function save( $bitfield, $reason ) { |
| 484 | + function save( $bitfield, $reason, $title ) { |
168 | 485 | $dbw = wfGetDB( DB_MASTER ); |
169 | 486 | $deleter = new RevisionDeleter( $dbw ); |
170 | | - $deleter->setVisibility( $this->revisions, $bitfield, $reason ); |
| 487 | + |
| 488 | + if( $this->revisions ) { |
| 489 | + return $deleter->setRevVisibility( $title, $this->revisions, $bitfield, $reason ); |
| 490 | + } else if( $this->events ) { |
| 491 | + return $deleter->setEventVisibility( $title, $this->events, $bitfield, $reason ); |
| 492 | + } else if( $this->archrevs ) { |
| 493 | + return $deleter->setArchiveVisibility( $title, $this->archrevs, $bitfield, $reason ); |
| 494 | + } else if( $this->files ) { |
| 495 | + return $deleter->setFileVisibility( $title, $this->files, $bitfield, $reason ); |
| 496 | + } |
171 | 497 | } |
172 | 498 | } |
173 | 499 | |
— | — | @@ -177,42 +503,192 @@ |
178 | 504 | } |
179 | 505 | |
180 | 506 | /** |
| 507 | + * @param $title, the page these events apply to |
181 | 508 | * @param array $items list of revision ID numbers |
182 | 509 | * @param int $bitfield new rev_deleted value |
183 | 510 | * @param string $comment Comment for log records |
184 | 511 | */ |
185 | | - function setVisibility( $items, $bitfield, $comment ) { |
186 | | - $pages = array(); |
| 512 | + function setRevVisibility( $title, $items, $bitfield, $comment ) { |
| 513 | + global $wgOut; |
187 | 514 | |
| 515 | + $UserAllowedAll = true; |
| 516 | + $pages_count = array(); $pages_revIds = array(); |
188 | 517 | / To work! |
189 | 518 | foreach( $items as $revid ) { |
190 | | - $rev = Revision::newFromId( $revid ); |
191 | | - if( !isset( $rev ) ) { |
| 519 | + $rev = Revision::newFromTitle( $title, $revid ); |
| 520 | + if( !isset( $rev ) || $rev->isCurrent() ) { |
192 | 521 | return false; |
| 522 | + } else if( !$rev->userCan(Revision::DELETED_RESTRICTED) ) { |
| 523 | + $UserAllowedAll=false; |
| 524 | + continue; |
193 | 525 | } |
194 | | - $this->updateRevision( $rev, $bitfield ); |
195 | | - $this->updateRecentChanges( $rev, $bitfield ); |
196 | | - |
| 526 | + $pageid = $rev->getPage(); |
197 | 527 | / For logging, maintain a count of revisions per page |
198 | | - $pageid = $rev->getPage(); |
199 | | - if( isset( $pages[$pageid] ) ) { |
200 | | - $pages[$pageid]++; |
201 | | - } else { |
202 | | - $pages[$pageid] = 1; |
| 528 | + if ( !isset($pages_count[$pageid]) ) { |
| 529 | + $pages_count[$pageid]=0; |
| 530 | + $pages_revIds[$pageid]=array(); |
203 | 531 | } |
| 532 | + / Which pages did we change anything about? |
| 533 | + if ( $rev->mDeleted != $bitfield ) { |
| 534 | + $pages_count[$pageid]++; |
| 535 | + $pages_revIds[$pageid][]=$revid; |
| 536 | + |
| 537 | + $this->updateRevision( $rev, $bitfield ); |
| 538 | + $this->updateRecentChangesEdits( $rev, $bitfield, false ); |
| 539 | + } |
204 | 540 | } |
205 | 541 | |
206 | 542 | / Clear caches... |
207 | | - foreach( $pages as $pageid => $count ) { |
208 | | - $title = Title::newFromId( $pageid ); |
209 | | - $this->updatePage( $title ); |
210 | | - $this->updateLog( $title, $count, $bitfield, $comment ); |
| 543 | + foreach( $pages_count as $pageid => $count ) { |
| 544 | + /Don't log or touch if nothing changed |
| 545 | + if ( $count > 0 ) { |
| 546 | + $title = Title::newFromId( $pageid ); |
| 547 | + $this->updatePage( $title ); |
| 548 | + $this->updateLog( $title, $count, $bitfield, $comment, $title, 'old', $pages_revIds[$pageid] ); |
| 549 | + } |
211 | 550 | } |
| 551 | + / Where all revs allowed to be set? |
| 552 | + if ( !$UserAllowedAll ) { |
| 553 | + /FIXME: still might be confusing??? |
| 554 | + $wgOut->permissionRequired( 'hiderevision' ); return false; |
| 555 | + } |
212 | 556 | |
213 | 557 | return true; |
214 | 558 | } |
215 | 559 | |
| 560 | + /** |
| 561 | + * @param $title, the page these events apply to |
| 562 | + * @param array $items list of revision ID numbers |
| 563 | + * @param int $bitfield new rev_deleted value |
| 564 | + * @param string $comment Comment for log records |
| 565 | + */ |
| 566 | + function setArchiveVisibility( $title, $items, $bitfield, $comment ) { |
| 567 | + global $wgOut; |
| 568 | + |
| 569 | + $UserAllowedAll = true; |
| 570 | + $count = 0; $Id_set = array(); |
| 571 | + / To work! |
| 572 | + $archive = new PageArchive( $title ); |
| 573 | + foreach( $items as $revid ) { |
| 574 | + $rev = $archive->getRevision( '', $revid ); |
| 575 | + if( !isset( $rev ) ) { |
| 576 | + return false; |
| 577 | + } else if( !$rev->userCan(Revision::DELETED_RESTRICTED) ) { |
| 578 | + $UserAllowedAll=false; |
| 579 | + continue; |
| 580 | + } |
| 581 | + / For logging, maintain a count of revisions |
| 582 | + if ( $rev->mDeleted != $bitfield ) { |
| 583 | + $Id_set[]=$revid; |
| 584 | + $count++; |
| 585 | + } |
| 586 | + $this->updateArchive( $rev, $bitfield ); |
| 587 | + } |
| 588 | + |
| 589 | + / Log if something was changed |
| 590 | + if ( $count > 0 ) { |
| 591 | + $this->updateLog( $title, $count, $bitfield, $comment, $title, 'ar', $Id_set ); |
| 592 | + } |
| 593 | + / Where all revs allowed to be set? |
| 594 | + if ( !$UserAllowedAll ) { |
| 595 | + $wgOut->permissionRequired( 'hiderevision' ); return false; |
| 596 | + } |
| 597 | + |
| 598 | + return true; |
| 599 | + } |
| 600 | + |
| 601 | + /** |
| 602 | + * @param $title, the page these events apply to |
| 603 | + * @param array $items list of revision ID numbers |
| 604 | + * @param int $bitfield new rev_deleted value |
| 605 | + * @param string $comment Comment for log records |
| 606 | + */ |
| 607 | + function setFileVisibility( $title, $items, $bitfield, $comment ) { |
| 608 | + global $wgOut; |
| 609 | + |
| 610 | + $UserAllowedAll = true; |
| 611 | + $count = 0; $Id_set = array(); |
| 612 | + / To work! |
| 613 | + foreach( $items as $fileid ) { |
| 614 | + $file = new FSarchivedFile( $title, $fileid ); |
| 615 | + if( !isset( $file ) ) { |
| 616 | + return false; |
| 617 | + } else if( !$file->userCan(Revision::DELETED_RESTRICTED) ) { |
| 618 | + $UserAllowedAll=false; |
| 619 | + continue; |
| 620 | + } |
| 621 | + / For logging, maintain a count of revisions |
| 622 | + if ( $file->mDeleted != $bitfield ) { |
| 623 | + $Id_set[]=$fileid; |
| 624 | + $count++; |
| 625 | + } |
| 626 | + $this->updateFiles( $file, $bitfield ); |
| 627 | + } |
| 628 | + |
| 629 | + / Log if something was changed |
| 630 | + if ( $count > 0 ) { |
| 631 | + $this->updateLog( $title, $count, $bitfield, $comment, $title, 'file', $Id_set ); |
| 632 | + } |
| 633 | + / Where all revs allowed to be set? |
| 634 | + if ( !$UserAllowedAll ) { |
| 635 | + $wgOut->permissionRequired( 'hiderevision' ); return false; |
| 636 | + } |
| 637 | + |
| 638 | + return true; |
| 639 | + } |
| 640 | + |
216 | 641 | /** |
| 642 | + * @param $title, the page these events apply to |
| 643 | + * @param array $items list of log ID numbers |
| 644 | + * @param int $bitfield new log_deleted value |
| 645 | + * @param string $comment Comment for log records |
| 646 | + */ |
| 647 | + function setEventVisibility( $title, $items, $bitfield, $comment ) { |
| 648 | + global $wgOut; |
| 649 | + |
| 650 | + $UserAllowedAll = true; |
| 651 | + $logs_count = array(); $logs_Ids = array(); |
| 652 | + / To work! |
| 653 | + foreach( $items as $logid ) { |
| 654 | + $event = LogReader::newFromTitle( $title, $logid ); |
| 655 | + if( !isset( $event ) ) { |
| 656 | + return false; |
| 657 | + } else if( !LogViewer::userCan($event, Revision::DELETED_RESTRICTED) || $event->log_type == 'oversight' ) { |
| 658 | + / Don't hide from oversight log!!! |
| 659 | + $UserAllowedAll=false; |
| 660 | + continue; |
| 661 | + } |
| 662 | + $logtype = $event->log_type; |
| 663 | + / For logging, maintain a count of events per log type |
| 664 | + if( !isset( $logs_count[$logtype] ) ) { |
| 665 | + $logs_count[$logtype]=0; |
| 666 | + $logs_Ids[$logtype]=array(); |
| 667 | + } |
| 668 | + / Which logs did we change anything about? |
| 669 | + if ( $event->log_deleted != $bitfield ) { |
| 670 | + $logs_Ids[$logtype][]=$logid; |
| 671 | + $logs_count[$logtype]++; |
| 672 | + |
| 673 | + $this->updateLogs( $event, $bitfield ); |
| 674 | + $this->updateRecentChangesLog( $event, $bitfield, true ); |
| 675 | + } |
| 676 | + } |
| 677 | + foreach( $logs_count as $logtype => $count ) { |
| 678 | + /Don't log or touch if nothing changed |
| 679 | + if ( $count > 0 ) { |
| 680 | + $target = SpecialPage::getTitleFor( 'Log', $logtype ); |
| 681 | + $this->updateLog( $target, $count, $bitfield, $comment, $title, 'log', $logs_Ids[$logtype] ); |
| 682 | + } |
| 683 | + } |
| 684 | + / Where all revs allowed to be set? |
| 685 | + if ( !$UserAllowedAll ) { |
| 686 | + $wgOut->permissionRequired( 'hiderevision' ); return false; |
| 687 | + } |
| 688 | + |
| 689 | + return true; |
| 690 | + } |
| 691 | + |
| 692 | + /** |
217 | 693 | * Update the revision's rev_deleted field |
218 | 694 | * @param Revision $rev |
219 | 695 | * @param int $bitfield new rev_deleted bitfield value |
— | — | @@ -225,19 +701,65 @@ |
226 | 702 | } |
227 | 703 | |
228 | 704 | /** |
| 705 | + * Update the revision's rev_deleted field |
| 706 | + * @param Revision $rev |
| 707 | + * @param int $bitfield new rev_deleted bitfield value |
| 708 | + */ |
| 709 | + function updateArchive( $rev, $bitfield ) { |
| 710 | + $this->db->update( 'archive', |
| 711 | + array( 'ar_deleted' => $bitfield ), |
| 712 | + array( 'ar_rev_id' => $rev->getId() ), |
| 713 | + 'RevisionDeleter::updateArchive' ); |
| 714 | + } |
| 715 | + |
| 716 | + /** |
| 717 | + * Update the images's fa_deleted field |
| 718 | + * @param Revision $file |
| 719 | + * @param int $bitfield new rev_deleted bitfield value |
| 720 | + */ |
| 721 | + function updateFiles( $file, $bitfield ) { |
| 722 | + $this->db->update( 'filearchive', |
| 723 | + array( 'fa_deleted' => $bitfield ), |
| 724 | + array( 'fa_id' => $file->mId ), |
| 725 | + 'RevisionDeleter::updateFiles' ); |
| 726 | + } |
| 727 | + |
| 728 | + /** |
| 729 | + * Update the logging log_deleted field |
| 730 | + * @param Revision $rev |
| 731 | + * @param int $bitfield new rev_deleted bitfield value |
| 732 | + */ |
| 733 | + function updateLogs( $event, $bitfield ) { |
| 734 | + $this->db->update( 'logging', |
| 735 | + array( 'log_deleted' => $bitfield ), |
| 736 | + array( 'log_id' => $event->log_id ), |
| 737 | + 'RevisionDeleter::updateLogs' ); |
| 738 | + } |
| 739 | + |
| 740 | + /** |
229 | 741 | * Update the revision's recentchanges record if fields have been hidden |
| 742 | + * @param Revision $event |
| 743 | + * @param int $bitfield new rev_deleted bitfield value |
| 744 | + */ |
| 745 | + function updateRecentChangesLog( $event, $bitfield ) { |
| 746 | + $this->db->update( 'recentchanges', |
| 747 | + array( 'rc_deleted' => $bitfield, |
| 748 | + 'rc_patrolled' => 1), |
| 749 | + array( 'rc_logid' => $event->log_id ), |
| 750 | + 'RevisionDeleter::updateRecentChangesLog' ); |
| 751 | + } |
| 752 | + |
| 753 | + /** |
| 754 | + * Update the revision's recentchanges record if fields have been hidden |
230 | 755 | * @param Revision $rev |
231 | 756 | * @param int $bitfield new rev_deleted bitfield value |
232 | 757 | */ |
233 | | - function updateRecentChanges( $rev, $bitfield ) { |
| 758 | + function updateRecentChangesEdits( $rev, $bitfield ) { |
234 | 759 | $this->db->update( 'recentchanges', |
235 | | - array( |
236 | | - 'rc_user' => ($bitfield & Revision::DELETED_USER) ? 0 : $rev->getUser(), |
237 | | - 'rc_user_text' => ($bitfield & Revision::DELETED_USER) ? wfMsg( 'rev-deleted-user' ) : $rev->getUserText(), |
238 | | - 'rc_comment' => ($bitfield & Revision::DELETED_COMMENT) ? wfMsg( 'rev-deleted-comment' ) : $rev->getComment() ), |
239 | | - array( |
240 | | - 'rc_this_oldid' => $rev->getId() ), |
241 | | - 'RevisionDeleter::updateRecentChanges' ); |
| 760 | + array( 'rc_deleted' => $bitfield, |
| 761 | + 'rc_patrolled' => 1), |
| 762 | + array( 'rc_this_oldid' => $rev->getId() ), |
| 763 | + 'RevisionDeleter::updateRecentChangesEdits' ); |
242 | 764 | } |
243 | 765 | |
244 | 766 | /** |
— | — | @@ -257,11 +779,25 @@ |
258 | 780 | * @param int $bitfield the new rev_deleted value |
259 | 781 | * @param string $comment |
260 | 782 | */ |
261 | | - function updateLog( $title, $count, $bitfield, $comment ) { |
262 | | - $log = new LogPage( 'delete' ); |
263 | | - $reason = "changed $count revisions to $bitfield"; |
264 | | - $reason .= ": $comment"; |
265 | | - $log->addEntry( 'revision', $title, $reason ); |
| 783 | + function updateLog( $title, $count, $bitfield, $comment, $target, $prefix, $items = array() ) { |
| 784 | + / Put things hidden from sysops in the oversight log |
| 785 | + $logtype = ( $bitfield & Revision::DELETED_RESTRICTED ) ? 'oversight' : 'delete'; |
| 786 | + / Add params for effected page and ids |
| 787 | + $params = array( $target->getPrefixedText(), $prefix, implode( ',', $items) ); |
| 788 | + $log = new LogPage( $logtype ); |
| 789 | + if ( $prefix=='log' ) { |
| 790 | + $reason = wfMsgExt('logdelete-logaction', array('parsemag'), $count, $bitfield, $target->getPrefixedText() ); |
| 791 | + if ($comment) $reason .= ": $comment"; |
| 792 | + $log->addEntry( 'event', $title, $reason, $params ); |
| 793 | + } else if ( $prefix=='old' ) { |
| 794 | + $reason = wfMsgExt('revdelete-logaction', array('parsemag'), $count, $bitfield ); |
| 795 | + if ($comment) $reason .= ": $comment"; |
| 796 | + $log->addEntry( 'revision', $title, $reason, $params ); |
| 797 | + } else if ( $prefix=='file' ) { |
| 798 | + $reason = wfMsgExt('revdelete-logaction', array('parsemag'), $count, $bitfield ); |
| 799 | + if ($comment) $reason .= ": $comment"; |
| 800 | + $log->addEntry( 'file', $title, $reason, $params ); |
| 801 | + } |
266 | 802 | } |
267 | 803 | } |
268 | 804 | |
Index: trunk/phase3/includes/Linker.php |
— | — | @@ -830,10 +830,13 @@ |
831 | 831 | /** |
832 | 832 | * Generate a user link if the current user is allowed to view it |
833 | 833 | * @param $rev Revision object. |
| 834 | + * @param $isPublic, bool, show only if all users can see it |
834 | 835 | * @return string HTML |
835 | 836 | */ |
836 | | - function revUserLink( $rev ) { |
837 | | - if( $rev->userCan( Revision::DELETED_USER ) ) { |
| 837 | + function revUserLink( $rev, $isPublic = false ) { |
| 838 | + if( $rev->isDeleted( Revision::DELETED_USER ) && $isPublic ) { |
| 839 | + $link = wfMsgHtml( 'rev-deleted-user' ); |
| 840 | + } else if( $rev->userCan( Revision::DELETED_USER ) ) { |
838 | 841 | $link = $this->userLink( $rev->getRawUser(), $rev->getRawUserText() ); |
839 | 842 | } else { |
840 | 843 | $link = wfMsgHtml( 'rev-deleted-user' ); |
— | — | @@ -843,27 +846,122 @@ |
844 | 847 | } |
845 | 848 | return $link; |
846 | 849 | } |
| 850 | + |
| 851 | + /** |
| 852 | + * Generate a user link if the current user is allowed to view it |
| 853 | + * @param $event, log item. |
| 854 | + * @param $isPublic, bool, show only if all users can see it |
| 855 | + * @return string HTML |
| 856 | + */ |
| 857 | + function logUserLink( $event, $isPublic = false ) { |
| 858 | + if( LogViewer::isDeleted( $event, LogViewer::DELETED_USER ) && $isPublic ) { |
| 859 | + $link = wfMsgHtml( 'rev-deleted-user' ); |
| 860 | + } else if( LogViewer::userCan( $event, LogViewer::DELETED_USER ) ) { |
| 861 | + if ( isset($event->user_name) ) { |
| 862 | + $link = $this->userLink( $event->log_user, $event->user_name ); |
| 863 | + } else { |
| 864 | + $user = $event->log_user; |
| 865 | + $link = $this->userLink( $event->log_user, User::whoIs( $user ) ); |
| 866 | + } |
| 867 | + } else { |
| 868 | + $link = wfMsgHtml( 'rev-deleted-user' ); |
| 869 | + } |
| 870 | + if( LogViewer::isDeleted( $event, LogViewer::DELETED_USER ) ) { |
| 871 | + return '<span class="history-deleted">' . $link . '</span>'; |
| 872 | + } |
| 873 | + return $link; |
| 874 | + } |
847 | 875 | |
848 | 876 | /** |
| 877 | + * Generate a user link if the current user is allowed to view it |
| 878 | + * @param $file, filestore file |
| 879 | + * @param $isPublic, bool, show only if all users can see it |
| 880 | + * @return string HTML |
| 881 | + */ |
| 882 | + function fileUserLink( $file, $isPublic = false ) { |
| 883 | + if( $file->isDeleted( Revision::DELETED_USER ) && $isPublic ) { |
| 884 | + $link = wfMsgHtml( 'rev-deleted-user' ); |
| 885 | + } else if( $file->userCan( Revision::DELETED_USER ) ) { |
| 886 | + $link = $this->userLink( $file->mUser, $file->mUserText ); |
| 887 | + } else { |
| 888 | + $link = wfMsgHtml( 'rev-deleted-user' ); |
| 889 | + } |
| 890 | + if( $file->isDeleted( Revision::DELETED_USER ) ) { |
| 891 | + return '<span class="history-deleted">' . $link . '</span>'; |
| 892 | + } |
| 893 | + return $link; |
| 894 | + } |
| 895 | + |
| 896 | + /** |
849 | 897 | * Generate a user tool link cluster if the current user is allowed to view it |
850 | 898 | * @param $rev Revision object. |
| 899 | + * @param $isPublic, bool, show only if all users can see it |
851 | 900 | * @return string HTML |
852 | 901 | */ |
853 | | - function revUserTools( $rev ) { |
854 | | - if( $rev->userCan( Revision::DELETED_USER ) ) { |
| 902 | + function revUserTools( $rev, $isPublic = false ) { |
| 903 | + if( $rev->isDeleted( Revision::DELETED_USER ) && $isPublic ) { |
| 904 | + $link = wfMsgHtml( 'rev-deleted-user' ); |
| 905 | + } else if( $rev->userCan( Revision::DELETED_USER ) ) { |
855 | 906 | $link = $this->userLink( $rev->getRawUser(), $rev->getRawUserText() ) . |
856 | | - ' ' . |
857 | | - $this->userToolLinks( $rev->getRawUser(), $rev->getRawUserText() ); |
| 907 | + ' ' . $this->userToolLinks( $rev->getRawUser(), $rev->getRawUserText() ); |
858 | 908 | } else { |
859 | 909 | $link = wfMsgHtml( 'rev-deleted-user' ); |
860 | 910 | } |
861 | 911 | if( $rev->isDeleted( Revision::DELETED_USER ) ) { |
| 912 | + return ' <span class="history-deleted">' . $link . '</span>'; |
| 913 | + } |
| 914 | + return " $link"; |
| 915 | + } |
| 916 | + |
| 917 | + /** |
| 918 | + * Generate a user tool link cluster if the current user is allowed to view it |
| 919 | + * @param $event, log item. |
| 920 | + * @param $isPublic, bool, show only if all users can see it |
| 921 | + * @return string HTML |
| 922 | + */ |
| 923 | + function logUserTools( $event, $isPublic = false ) { |
| 924 | + if( LogViewer::isDeleted( $event, LogViewer::DELETED_USER ) && $isPublic ) { |
| 925 | + $link = wfMsgHtml( 'rev-deleted-user' ); |
| 926 | + } else if( LogViewer::userCan( $event, LogViewer::DELETED_USER ) ) { |
| 927 | + if ( isset($event->user_name) ) { |
| 928 | + $link = $this->userLink( $event->log_user, $event->user_name ) . |
| 929 | + ' ' . $this->userToolLinks( $event->log_user, $event->user_name ); |
| 930 | + } else { |
| 931 | + $usertext = User::whoIs( $event->log_user ); |
| 932 | + $link = $this->userLink( $event->log_user, $usertext ) . |
| 933 | + ' ' . $this->userToolLinks( $event->log_user, $usertext ); |
| 934 | + } |
| 935 | + } else { |
| 936 | + $link = wfMsgHtml( 'rev-deleted-user' ); |
| 937 | + } |
| 938 | + if( LogViewer::isDeleted( $event, LogViewer::DELETED_USER ) ) { |
862 | 939 | return '<span class="history-deleted">' . $link . '</span>'; |
863 | 940 | } |
864 | 941 | return $link; |
865 | 942 | } |
866 | | - |
| 943 | + |
867 | 944 | /** |
| 945 | + * Generate a user tool link cluster if the current user is allowed to view it |
| 946 | + * @param $file, filestore file |
| 947 | + * @param $isPublic, bool, show only if all users can see it |
| 948 | + * @return string HTML |
| 949 | + */ |
| 950 | + function fileUserTools( $file, $isPublic = false ) { |
| 951 | + if( $file->isDeleted( Revision::DELETED_USER ) && $isPublic ) { |
| 952 | + $link = wfMsgHtml( 'rev-deleted-user' ); |
| 953 | + } else if( $file->userCan( Revision::DELETED_USER ) ) { |
| 954 | + $link = $this->userLink( $file->mUser, $file->mUserText ) . |
| 955 | + $this->userToolLinks( $file->mUser, $file->mUserText ); |
| 956 | + } else { |
| 957 | + $link = wfMsgHtml( 'rev-deleted-user' ); |
| 958 | + } |
| 959 | + if( $file->isDeleted( Revision::DELETED_USER ) ) { |
| 960 | + return '<span class="history-deleted">' . $link . '</span>'; |
| 961 | + } |
| 962 | + return $link; |
| 963 | + } |
| 964 | + |
| 965 | + /** |
868 | 966 | * This function is called by all recent changes variants, by the page history, |
869 | 967 | * and by the user contributions list. It is responsible for formatting edit |
870 | 968 | * comments. It escapes any HTML in the comment, but adds some CSS to format |
— | — | @@ -985,21 +1083,65 @@ |
986 | 1084 | * |
987 | 1085 | * @param Revision $rev |
988 | 1086 | * @param bool $local Whether section links should refer to local page |
| 1087 | + * @param $isPublic, show only if all users can see it |
989 | 1088 | * @return string HTML |
990 | 1089 | */ |
991 | | - function revComment( Revision $rev, $local = false ) { |
992 | | - if( $rev->userCan( Revision::DELETED_COMMENT ) ) { |
| 1090 | + function revComment( Revision $rev, $local = false, $isPublic = false ) { |
| 1091 | + if( $rev->isDeleted( Revision::DELETED_COMMENT ) && $isPublic ) { |
| 1092 | + $block = " <span class=\"comment\">" . wfMsgHtml( 'rev-deleted-comment' ) . "</span>"; |
| 1093 | + } else if( $rev->userCan( Revision::DELETED_COMMENT ) ) { |
993 | 1094 | $block = $this->commentBlock( $rev->getRawComment(), $rev->getTitle(), $local ); |
994 | 1095 | } else { |
995 | | - $block = " <span class=\"comment\">" . |
996 | | - wfMsgHtml( 'rev-deleted-comment' ) . "</span>"; |
| 1096 | + $block = " <span class=\"comment\">" . wfMsgHtml( 'rev-deleted-comment' ) . "</span>"; |
997 | 1097 | } |
998 | 1098 | if( $rev->isDeleted( Revision::DELETED_COMMENT ) ) { |
999 | 1099 | return " <span class=\"history-deleted\">$block</span>"; |
1000 | 1100 | } |
1001 | 1101 | return $block; |
1002 | 1102 | } |
| 1103 | + |
| 1104 | + /** |
| 1105 | + * Wrap and format the given event's comment block, if the current |
| 1106 | + * user is allowed to view it. |
| 1107 | + * |
| 1108 | + * @param Revision $rev |
| 1109 | + * @return string HTML |
| 1110 | + */ |
| 1111 | + function logComment( $event, $isPublic = false ) { |
| 1112 | + if( LogViewer::isDeleted( $event, LogViewer::DELETED_COMMENT ) && $isPublic ) { |
| 1113 | + $block = ' ' . wfMsgHtml( 'rev-deleted-comment' ); |
| 1114 | + } else if( LogViewer::userCan( $event, LogViewer::DELETED_COMMENT ) ) { |
| 1115 | + $block = $this->commentBlock( LogViewer::getRawComment( $event ) ); |
| 1116 | + } else { |
| 1117 | + $block = ' ' . wfMsgHtml( 'rev-deleted-comment' ); |
| 1118 | + } |
| 1119 | + if( LogViewer::isDeleted( $event, LogViewer::DELETED_COMMENT ) ) { |
| 1120 | + return "<span class=\"history-deleted\">$block</span>"; |
| 1121 | + } |
| 1122 | + return $block; |
| 1123 | + } |
1003 | 1124 | |
| 1125 | + /** |
| 1126 | + * Wrap and format the given file's comment block, if the current |
| 1127 | + * user is allowed to view it. |
| 1128 | + * |
| 1129 | + * @param FileStore file object $file |
| 1130 | + * @return string HTML |
| 1131 | + */ |
| 1132 | + function fileComment( $file, $isPublic = false ) { |
| 1133 | + if( $file->isDeleted( Revision::DELETED_COMMENT ) && $isPublic ) { |
| 1134 | + $block = ' ' . wfMsgHtml( 'rev-deleted-comment' ); |
| 1135 | + } else if( $file->userCan( Revision::DELETED_COMMENT ) ) { |
| 1136 | + $block = $this->commentBlock( $file->mDescription ); |
| 1137 | + } else { |
| 1138 | + $block = ' ' . wfMsgHtml( 'rev-deleted-comment' ); |
| 1139 | + } |
| 1140 | + if( $file->isDeleted( Revision::DELETED_COMMENT ) ) { |
| 1141 | + return "<span class=\"history-deleted\">$block</span>"; |
| 1142 | + } |
| 1143 | + return $block; |
| 1144 | + } |
| 1145 | + |
1004 | 1146 | /** @todo document */ |
1005 | 1147 | function tocIndent() { |
1006 | 1148 | return "\n<ul>"; |
Index: trunk/phase3/includes/Export.php |
— | — | @@ -139,7 +139,10 @@ |
140 | 140 | $fname = "do_list_authors" ; |
141 | 141 | wfProfileIn( $fname ); |
142 | 142 | $this->author_list = "<contributors>"; |
143 | | - $sql = "SELECT DISTINCT rev_user_text,rev_user FROM {$page},{$revision} WHERE page_id=rev_page AND " . $cond ; |
| 143 | + /rev_deleted |
| 144 | + $deleted = '(rev_deleted & '.Revision::DELETED_USER.') !=1 '; |
| 145 | + |
| 146 | + $sql = "SELECT DISTINCT rev_user_text,rev_user FROM {$page},{$revision} WHERE page_id=rev_page AND $deleted AND " . $cond ; |
144 | 147 | $result = $this->db->query( $sql, $fname ); |
145 | 148 | $resultset = $this->db->resultObject( $result ); |
146 | 149 | while( $row = $resultset->fetchObject() ) { |
Index: trunk/phase3/includes/SpecialBlockip.php |
— | — | @@ -45,7 +45,7 @@ |
46 | 46 | var $BlockAddress, $BlockExpiry, $BlockReason; |
47 | 47 | |
48 | 48 | function IPBlockForm( $par ) { |
49 | | - global $wgRequest; |
| 49 | + global $wgRequest, $wgUser; |
50 | 50 | |
51 | 51 | $this->BlockAddress = $wgRequest->getVal( 'wpBlockAddress', $wgRequest->getVal( 'ip', $par ) ); |
52 | 52 | $this->BlockAddress = strtr( $this->BlockAddress, '_', ' ' ); |
— | — | @@ -59,6 +59,8 @@ |
60 | 60 | $this->BlockAnonOnly = $wgRequest->getBool( 'wpAnonOnly', $byDefault ); |
61 | 61 | $this->BlockCreateAccount = $wgRequest->getBool( 'wpCreateAccount', $byDefault ); |
62 | 62 | $this->BlockEnableAutoblock = $wgRequest->getBool( 'wpEnableAutoblock', $byDefault ); |
| 63 | + # Re-check user's rights to hide names, very serious, defaults to 0 |
| 64 | + $this->BlockHideName = $wgRequest->getBool( 'wpHideName', 0 ) && $wgUser->isAllowed( 'hideuser' ); |
63 | 65 | } |
64 | 66 | |
65 | 67 | function showForm( $err ) { |
— | — | @@ -131,6 +133,7 @@ |
132 | 134 | </td> |
133 | 135 | "); |
134 | 136 | } |
| 137 | + |
135 | 138 | $wgOut->addHTML(" |
136 | 139 | </tr> |
137 | 140 | <tr id='wpBlockOther'> |
— | — | @@ -150,31 +153,46 @@ |
151 | 154 | <tr id='wpAnonOnlyRow'> |
152 | 155 | <td> </td> |
153 | 156 | <td align=\"left\"> |
154 | | - " . wfCheckLabel( wfMsg( 'ipbanononly' ), |
| 157 | + " . wfCheckLabel( wfMsgHtml( 'ipbanononly' ), |
155 | 158 | 'wpAnonOnly', 'wpAnonOnly', $this->BlockAnonOnly, |
156 | | - array( 'tabindex' => 4 ) ) . " |
| 159 | + array( 'tabindex' => '4' ) ) . " |
157 | 160 | </td> |
158 | 161 | </tr> |
159 | 162 | <tr id='wpCreateAccountRow'> |
160 | 163 | <td> </td> |
161 | 164 | <td align=\"left\"> |
162 | | - " . wfCheckLabel( wfMsg( 'ipbcreateaccount' ), |
| 165 | + " . wfCheckLabel( wfMsgHtml( 'ipbcreateaccount' ), |
163 | 166 | 'wpCreateAccount', 'wpCreateAccount', $this->BlockCreateAccount, |
164 | | - array( 'tabindex' => 5 ) ) . " |
| 167 | + array( 'tabindex' => '5' ) ) . " |
165 | 168 | </td> |
166 | 169 | </tr> |
167 | 170 | <tr id='wpEnableAutoblockRow'> |
168 | 171 | <td> </td> |
169 | 172 | <td align=\"left\"> |
170 | | - " . wfCheckLabel( wfMsg( 'ipbenableautoblock' ), |
| 173 | + " . wfCheckLabel( wfMsgHtml( 'ipbenableautoblock' ), |
171 | 174 | 'wpEnableAutoblock', 'wpEnableAutoblock', $this->BlockEnableAutoblock, |
172 | | - array( 'tabindex' => 6 ) ) . " |
| 175 | + array( 'tabindex' => '6' ) ) . " |
173 | 176 | </td> |
174 | 177 | </tr> |
| 178 | + "); |
| 179 | + / Allow some users to hide name from block log, blocklist and listusers |
| 180 | + if ( $wgUser->isAllowed( 'hideuser' ) ) { |
| 181 | + $wgOut->addHTML(" |
| 182 | + <tr> |
| 183 | + <td> </td> |
| 184 | + <td align=\"left\"> |
| 185 | + " . wfCheckLabel( wfMsgHtml( 'ipbhidename' ), |
| 186 | + 'wpHideName', 'wpHideName', $this->BlockHideName, |
| 187 | + array( 'tabindex' => '6' ) ) . " |
| 188 | + </td> |
| 189 | + </tr> |
| 190 | + "); |
| 191 | + } |
| 192 | + $wgOut->addHTML(" |
175 | 193 | <tr> |
176 | 194 | <td style='padding-top: 1em'> </td> |
177 | 195 | <td style='padding-top: 1em' align=\"left\"> |
178 | | - " . Xml::submitButton( wfMsg( 'ipbsubmit' ), |
| 196 | + " . Xml::submitButton( wfMsgHtml( 'ipbsubmit' ), |
179 | 197 | array( 'name' => 'wpBlock', 'tabindex' => '7' ) ) . " |
180 | 198 | </td> |
181 | 199 | </tr> |
— | — | @@ -191,8 +209,6 @@ |
192 | 210 | $this->showLogFragment( $wgOut, $user->getUserPage() ); |
193 | 211 | } elseif( preg_match( '/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/', $this->BlockAddress ) ) { |
194 | 212 | $this->showLogFragment( $wgOut, Title::makeTitle( NS_USER, $this->BlockAddress ) ); |
195 | | - } elseif( preg_match( '/^\w{1,4}:\w{1,4}:\w{1,4}:\w{1,4}:\w{1,4}:\w{1,4}:\w{1,4}:\w{1,4}/', $this->BlockAddress ) ) { |
196 | | - $this->showLogFragment( $wgOut, Title::makeTitle( NS_USER, $this->BlockAddress ) ); |
197 | 213 | } |
198 | 214 | } |
199 | 215 | |
— | — | @@ -200,9 +216,12 @@ |
201 | 217 | global $wgOut, $wgUser, $wgSysopUserBans, $wgSysopRangeBans; |
202 | 218 | |
203 | 219 | $userId = 0; |
204 | | - # Expand valid IPv6 addresses, usernames are left as is |
205 | | - $this->BlockAddress = IP::sanitizeIP( $this->BlockAddress ); |
206 | | - # isIPv4() and IPv6() are used for final validation |
| 220 | + $this->BlockAddress = trim( $this->BlockAddress ); |
| 221 | + # Expand valid IPv6 addresses |
| 222 | + if ( IP::isIPv6( $this->BlockAddress ) ) { |
| 223 | + $this->BlockAddress = IP::expandIP( $this->BlockAddress ); |
| 224 | + } |
| 225 | + # The above validation is good enough that those below will suffice from here |
207 | 226 | $rxIP4 = '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'; |
208 | 227 | $rxIP6 = '\w{1,4}:\w{1,4}:\w{1,4}:\w{1,4}:\w{1,4}:\w{1,4}:\w{1,4}:\w{1,4}'; |
209 | 228 | $rxIP = "($rxIP4|$rxIP6)"; |
— | — | @@ -283,7 +302,7 @@ |
284 | 303 | |
285 | 304 | $block = new Block( $this->BlockAddress, $userId, $wgUser->getID(), |
286 | 305 | $this->BlockReason, wfTimestampNow(), 0, $expiry, $this->BlockAnonOnly, |
287 | | - $this->BlockCreateAccount, $this->BlockEnableAutoblock ); |
| 306 | + $this->BlockCreateAccount, $this->BlockEnableAutoblock, $this->BlockHideName); |
288 | 307 | |
289 | 308 | if (wfRunHooks('BlockIp', array(&$block, &$wgUser))) { |
290 | 309 | |
— | — | @@ -300,8 +319,9 @@ |
301 | 320 | $logParams[] = $expirestr; |
302 | 321 | $logParams[] = $this->blockLogFlags(); |
303 | 322 | |
304 | | - # Make log entry |
305 | | - $log = new LogPage( 'block' ); |
| 323 | + # Make log entry, if the name is hidden, put it in the oversight log |
| 324 | + $log_type = ($this->BlockHideName) ? 'oversight' : 'block'; |
| 325 | + $log = new LogPage( $log_type ); |
306 | 326 | $log->addEntry( 'block', Title::makeTitle( NS_USER, $this->BlockAddress ), |
307 | 327 | $this->BlockReason, $logParams ); |
308 | 328 | |
Index: trunk/phase3/includes/ChangesList.php |
— | — | @@ -1,5 +1,6 @@ |
2 | 2 | <?php |
3 | 3 | /** |
| 4 | + * @package MediaWiki |
4 | 5 | * Contain class to show various lists of change: |
5 | 6 | * - what's link here |
6 | 7 | * - related changes |
— | — | @@ -8,14 +9,16 @@ |
9 | 10 | |
10 | 11 | /** |
11 | 12 | * @todo document |
| 13 | + * @package MediaWiki |
12 | 14 | */ |
13 | 15 | class RCCacheEntry extends RecentChange |
14 | 16 | { |
15 | 17 | var $secureName, $link; |
16 | | - var $curlink , $difflink, $lastlink , $usertalklink , $versionlink ; |
| 18 | + var $curlinks, $difflink, $lastlink , $usertalklink , $versionlink ; |
17 | 19 | var $userlink, $timestamp, $watched; |
18 | 20 | |
19 | | - function newFromParent( $rc ) { |
| 21 | + function newFromParent( $rc ) |
| 22 | + { |
20 | 23 | $rc2 = new RCCacheEntry; |
21 | 24 | $rc2->mAttribs = $rc->mAttribs; |
22 | 25 | $rc2->mExtra = $rc->mExtra; |
— | — | @@ -24,13 +27,14 @@ |
25 | 28 | } ; |
26 | 29 | |
27 | 30 | /** |
| 31 | + * @package MediaWiki |
28 | 32 | */ |
29 | 33 | class ChangesList { |
30 | 34 | # Called by history lists and recent changes |
31 | 35 | # |
32 | 36 | |
33 | 37 | /** @todo document */ |
34 | | - function __construct( &$skin ) { |
| 38 | + function ChangesList( &$skin ) { |
35 | 39 | $this->skin =& $skin; |
36 | 40 | $this->preCacheMessages(); |
37 | 41 | } |
— | — | @@ -43,7 +47,7 @@ |
44 | 48 | * @return ChangesList derivative |
45 | 49 | */ |
46 | 50 | public static function newFromUser( &$user ) { |
47 | | - $sk = $user->getSkin(); |
| 51 | + $sk =& $user->getSkin(); |
48 | 52 | $list = NULL; |
49 | 53 | if( wfRunHooks( 'FetchChangesList', array( &$user, &$sk, &$list ) ) ) { |
50 | 54 | return $user->getOption( 'usenewrc' ) ? new EnhancedChangesList( $sk ) : new OldChangesList( $sk ); |
— | — | @@ -77,7 +81,7 @@ |
78 | 82 | : $nothing; |
79 | 83 | $f .= $bot ? '<span class="bot">' . $this->message['boteditletter'] . '</span>' : $nothing; |
80 | 84 | $f .= $patrolled ? '<span class="unpatrolled">!</span>' : $nothing; |
81 | | - return $f; |
| 85 | + return "<tt>$f</tt>"; |
82 | 86 | } |
83 | 87 | |
84 | 88 | /** |
— | — | @@ -103,6 +107,32 @@ |
104 | 108 | } |
105 | 109 | } |
106 | 110 | |
| 111 | + /** |
| 112 | + * int $field one of DELETED_* bitfield constants |
| 113 | + * @return bool |
| 114 | + */ |
| 115 | + function isDeleted( $rc, $field ) { |
| 116 | + return ($rc->mAttribs['rc_deleted'] & $field) == $field; |
| 117 | + } |
| 118 | + |
| 119 | + /** |
| 120 | + * Determine if the current user is allowed to view a particular |
| 121 | + * field of this revision, if it's marked as deleted. |
| 122 | + * @param int $field |
| 123 | + * @return bool |
| 124 | + */ |
| 125 | + function userCan( $rc, $field ) { |
| 126 | + if( ( $rc->mAttribs['rc_deleted'] & $field ) == $field ) { |
| 127 | + global $wgUser; |
| 128 | + $permission = ( $rc->mAttribs['rc_deleted'] & Revision::DELETED_RESTRICTED ) == Revision::DELETED_RESTRICTED |
| 129 | + ? 'hiderevision' |
| 130 | + : 'deleterevision'; |
| 131 | + wfDebug( "Checking for $permission due to $field match on $rc->mAttribs['rc_deleted']\n" ); |
| 132 | + return $wgUser->isAllowed( $permission ); |
| 133 | + } else { |
| 134 | + return true; |
| 135 | + } |
| 136 | + } |
107 | 137 | |
108 | 138 | function insertMove( &$s, $rc ) { |
109 | 139 | # Diff |
— | — | @@ -138,11 +168,12 @@ |
139 | 169 | $s .= '(' . $this->skin->makeKnownLinkObj($title, $logname ) . ')'; |
140 | 170 | } |
141 | 171 | |
142 | | - |
143 | 172 | function insertDiffHist(&$s, &$rc, $unpatrolled) { |
144 | 173 | # Diff link |
145 | | - if( $rc->mAttribs['rc_type'] == RC_NEW || $rc->mAttribs['rc_type'] == RC_LOG ) { |
| 174 | + if( !$this->userCan($rc,Revision::DELETED_TEXT) ) { |
146 | 175 | $diffLink = $this->message['diff']; |
| 176 | + } else if( $rc->mAttribs['rc_type'] == RC_NEW || $rc->mAttribs['rc_type'] == RC_LOG) { |
| 177 | + $diffLink = $this->message['diff']; |
147 | 178 | } else { |
148 | 179 | $rcidparam = $unpatrolled |
149 | 180 | ? array( 'rcid' => $rc->mAttribs['rc_id'] ) |
— | — | @@ -172,7 +203,12 @@ |
173 | 204 | $params = ( $unpatrolled && $rc->mAttribs['rc_type'] == RC_NEW ) |
174 | 205 | ? 'rcid='.$rc->mAttribs['rc_id'] |
175 | 206 | : ''; |
176 | | - $articlelink = ' '. $this->skin->makeKnownLinkObj( $rc->getTitle(), '', $params ); |
| 207 | + if( $this->isDeleted($rc,Revision::DELETED_TEXT) ) { |
| 208 | + $articlelink = $this->skin->makeKnownLinkObj( $rc->getTitle(), '', $params ); |
| 209 | + $articlelink = '<span class="history-deleted">'.$articlelink.'</span>'; |
| 210 | + } else { |
| 211 | + $articlelink = ' '. $this->skin->makeKnownLinkObj( $rc->getTitle(), '', $params ); |
| 212 | + } |
177 | 213 | if($watched) $articlelink = '<strong>'.$articlelink.'</strong>'; |
178 | 214 | global $wgContLang; |
179 | 215 | $articlelink .= $wgContLang->getDirMark(); |
— | — | @@ -188,15 +224,37 @@ |
189 | 225 | |
190 | 226 | /** Insert links to user page, user talk page and eventually a blocking link */ |
191 | 227 | function insertUserRelatedLinks(&$s, &$rc) { |
192 | | - $s .= $this->skin->userLink( $rc->mAttribs['rc_user'], $rc->mAttribs['rc_user_text'] ); |
193 | | - $s .= $this->skin->userToolLinks( $rc->mAttribs['rc_user'], $rc->mAttribs['rc_user_text'] ); |
| 228 | + if ( $this->isDeleted($rc,Revision::DELETED_USER) ) { |
| 229 | + $s .= ' <span class="history-deleted">' . wfMsgHtml('rev-deleted-user') . '</span>'; |
| 230 | + } else { |
| 231 | + $s .= $this->skin->userLink( $rc->mAttribs['rc_user'], $rc->mAttribs['rc_user_text'] ); |
| 232 | + $s .= $this->skin->userToolLinks( $rc->mAttribs['rc_user'], $rc->mAttribs['rc_user_text'] ); |
| 233 | + } |
194 | 234 | } |
195 | 235 | |
| 236 | + /** insert a formatted action */ |
| 237 | + function insertAction(&$s, &$rc) { |
| 238 | + # Add comment |
| 239 | + if( $rc->mAttribs['rc_type'] == RC_LOG ) { |
| 240 | + / log action |
| 241 | + if ( $this->isDeleted($rc,LogViewer::DELETED_ACTION) ) { |
| 242 | + $s .= ' <span class="history-deleted">' . wfMsgHtml('rev-deleted-event') . '</span>'; |
| 243 | + } else { |
| 244 | + $s .= ' ' . LogPage::actionText( $rc->mAttribs['rc_log_type'], $rc->mAttribs['rc_log_action'], $rc->getTitle(), $this->skin, LogPage::extractParams($rc->mAttribs['rc_params']), true, true ); |
| 245 | + } |
| 246 | + } |
| 247 | + } |
| 248 | + |
196 | 249 | /** insert a formatted comment */ |
197 | 250 | function insertComment(&$s, &$rc) { |
198 | 251 | # Add comment |
199 | 252 | if( $rc->mAttribs['rc_type'] != RC_MOVE && $rc->mAttribs['rc_type'] != RC_MOVE_OVER_REDIRECT ) { |
200 | | - $s .= $this->skin->commentBlock( $rc->mAttribs['rc_comment'], $rc->getTitle() ); |
| 253 | + / log comment |
| 254 | + if ( $this->isDeleted($rc,Revision::DELETED_COMMENT) ) { |
| 255 | + $s .= ' <span class="history-deleted">' . wfMsgHtml('rev-deleted-comment') . '</span>'; |
| 256 | + } else { |
| 257 | + $s .= $this->skin->commentBlock( $rc->mAttribs['rc_comment'], $rc->getTitle() ); |
| 258 | + } |
201 | 259 | } |
202 | 260 | } |
203 | 261 | |
— | — | @@ -242,7 +300,6 @@ |
243 | 301 | wfProfileIn( $fname ); |
244 | 302 | |
245 | 303 | # Extract DB fields into local scope |
246 | | - / FIXME: Would be good to replace this extract() call with something that explicitly initializes local variables. |
247 | 304 | extract( $rc->mAttribs ); |
248 | 305 | |
249 | 306 | # Should patrol-related stuff be shown? |
— | — | @@ -252,19 +309,23 @@ |
253 | 310 | |
254 | 311 | $s .= '<li>'; |
255 | 312 | |
256 | | - / moved pages |
| 313 | + / Moved pages |
257 | 314 | if( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) { |
258 | 315 | $this->insertMove( $s, $rc ); |
259 | | - / log entries |
260 | | - } elseif ( $rc_namespace == NS_SPECIAL ) { |
| 316 | + / Log entries (old format) or log targets, and special pages |
| 317 | + } elseif( $rc_namespace == NS_SPECIAL ) { |
261 | 318 | list( $specialName, $specialSubpage ) = SpecialPage::resolveAliasWithSubpage( $rc_title ); |
262 | 319 | if ( $specialName == 'Log' ) { |
263 | 320 | $this->insertLog( $s, $rc->getTitle(), $specialSubpage ); |
264 | 321 | } else { |
265 | 322 | wfDebug( "Unexpected special page in recentchanges\n" ); |
266 | 323 | } |
267 | | - / all other stuff |
268 | | - } else { |
| 324 | + / Log entries |
| 325 | + } elseif( $rc_log_type !='' ) { |
| 326 | + $logtitle = Title::newFromText( "Log/$rc_log_type", NS_SPECIAL ); |
| 327 | + $this->insertLog( $s, $logtitle, $rc_log_type ); |
| 328 | + / All other stuff |
| 329 | + } else { |
269 | 330 | wfProfileIn($fname.'-page'); |
270 | 331 | |
271 | 332 | $this->insertDiffHist($s, $rc, $unpatrolled); |
— | — | @@ -285,10 +346,16 @@ |
286 | 347 | } |
287 | 348 | |
288 | 349 | $this->insertUserRelatedLinks($s,$rc); |
| 350 | + $this->insertAction($s, $rc); |
289 | 351 | $this->insertComment($s, $rc); |
| 352 | + |
| 353 | + # Mark revision as deleted |
| 354 | + if ( $this->isDeleted($rc,Revision::DELETED_TEXT) ) |
| 355 | + $s .= ' <tt>' . wfMsgHtml( 'deletedrev' ) . '</tt>'; |
| 356 | + if($rc->numberofWatchingusers > 0) { |
| 357 | + $s .= ' ' . wfMsg('number_of_watching_users_RCview', $wgContLang->formatNum($rc->numberofWatchingusers)); |
| 358 | + } |
290 | 359 | |
291 | | - $s .= rtrim(' ' . $this->numberofWatchingusers($rc->numberofWatchingusers)); |
292 | | - |
293 | 360 | $s .= "</li>\n"; |
294 | 361 | |
295 | 362 | wfProfileOut( $fname.'-rest' ); |
— | — | @@ -313,7 +380,6 @@ |
314 | 381 | $rc = RCCacheEntry::newFromParent( $baseRC ); |
315 | 382 | |
316 | 383 | # Extract fields from DB into the function scope (rc_xxxx variables) |
317 | | - / FIXME: Would be good to replace this extract() call with something that explicitly initializes local variables. |
318 | 384 | extract( $rc->mAttribs ); |
319 | 385 | $curIdEq = 'curid=' . $rc_cur_id; |
320 | 386 | |
— | — | @@ -335,12 +401,14 @@ |
336 | 402 | $rc->unpatrolled = false; |
337 | 403 | } |
338 | 404 | |
| 405 | + $showrev=true; |
339 | 406 | # Make article link |
340 | 407 | if( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) { |
341 | 408 | $msg = ( $rc_type == RC_MOVE ) ? "1movedto2" : "1movedto2_redir"; |
342 | 409 | $clink = wfMsg( $msg, $this->skin->makeKnownLinkObj( $rc->getTitle(), '', 'redirect=no' ), |
343 | 410 | $this->skin->makeKnownLinkObj( $rc->getMovedToTitle(), '' ) ); |
344 | | - } elseif( $rc_namespace == NS_SPECIAL ) { |
| 411 | + } else if( $rc_namespace == NS_SPECIAL ) { |
| 412 | + / Log entries (old format) and special pages |
345 | 413 | list( $specialName, $logtype ) = SpecialPage::resolveAliasWithSubpage( $rc_title ); |
346 | 414 | if ( $specialName == 'Log' ) { |
347 | 415 | # Log updates, etc |
— | — | @@ -350,7 +418,16 @@ |
351 | 419 | wfDebug( "Unexpected special page in recentchanges\n" ); |
352 | 420 | $clink = ''; |
353 | 421 | } |
354 | | - } elseif( $rc->unpatrolled && $rc_type == RC_NEW ) { |
| 422 | + } elseif ( $rc_log_type !='' ) { |
| 423 | + / Log entries |
| 424 | + $logtitle = Title::newFromText( "Log/$rc_log_type", NS_SPECIAL ); |
| 425 | + $logname = LogPage::logName( $rc_log_type ); |
| 426 | + $clink = '(' . $this->skin->makeKnownLinkObj($logtitle, $logname ) . ')'; |
| 427 | + } if ( $this->isDeleted($rc,Revision::DELETED_TEXT) ) { |
| 428 | + $clink = '<span class="history-deleted">' . $this->skin->makeKnownLinkObj( $rc->getTitle(), '' ) . '</span>'; |
| 429 | + if ( !ChangesList::userCan($rc,Revision::DELETED_TEXT) ) |
| 430 | + $showrev=false; |
| 431 | + } else if( $rc->unpatrolled && $rc_type == RC_NEW ) { |
355 | 432 | # Unpatrolled new page, give rc_id in query |
356 | 433 | $clink = $this->skin->makeKnownLinkObj( $rc->getTitle(), '', "rcid={$rc_id}" ); |
357 | 434 | } else { |
— | — | @@ -373,7 +450,10 @@ |
374 | 451 | $querydiff = $curIdEq."&diff=$rc_this_oldid&oldid=$rc_last_oldid$rcIdQuery"; |
375 | 452 | $aprops = ' tabindex="'.$baseRC->counter.'"'; |
376 | 453 | $curLink = $this->skin->makeKnownLinkObj( $rc->getTitle(), $this->message['cur'], $querycur, '' ,'', $aprops ); |
377 | | - if( $rc_type == RC_NEW || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) { |
| 454 | + if ( !$showrev ) { |
| 455 | + $curLink = $this->message['cur']; |
| 456 | + $diffLink = $this->message['diff']; |
| 457 | + } else if( $rc_type == RC_NEW || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) { |
378 | 458 | if( $rc_type != RC_NEW ) { |
379 | 459 | $curLink = $this->message['cur']; |
380 | 460 | } |
— | — | @@ -383,21 +463,27 @@ |
384 | 464 | } |
385 | 465 | |
386 | 466 | # Make "last" link |
387 | | - if( $rc_last_oldid == 0 || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) { |
| 467 | + if ( !$showrev ) { |
| 468 | + $lastLink = $this->message['last']; |
| 469 | + } else if( $rc_last_oldid == 0 || $rc_type == RC_LOG || $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) { |
388 | 470 | $lastLink = $this->message['last']; |
389 | 471 | } else { |
390 | 472 | $lastLink = $this->skin->makeKnownLinkObj( $rc->getTitle(), $this->message['last'], |
391 | | - $curIdEq.'&diff='.$rc_this_oldid.'&oldid='.$rc_last_oldid . $rcIdQuery ); |
| 473 | + $curIdEq.'&diff='.$rc_this_oldid.'&oldid='.$rc_last_oldid . $rcIdQuery ); |
392 | 474 | } |
| 475 | + |
| 476 | + # Make user links |
| 477 | + if ( $this->isDeleted($rc,Revision::DELETED_USER) ) { |
| 478 | + $rc->userlink = ' <span class="history-deleted">' . wfMsgHtml('rev-deleted-user') . '</span>'; |
| 479 | + } else { |
| 480 | + $rc->userlink = $this->skin->userLink( $rc_user, $rc_user_text ); |
| 481 | + $rc->usertalklink = $this->skin->userToolLinks( $rc_user, $rc_user_text ); |
| 482 | + } |
393 | 483 | |
394 | | - $rc->userlink = $this->skin->userLink( $rc_user, $rc_user_text ); |
395 | | - |
396 | 484 | $rc->lastlink = $lastLink; |
397 | 485 | $rc->curlink = $curLink; |
398 | 486 | $rc->difflink = $diffLink; |
399 | 487 | |
400 | | - $rc->usertalklink = $this->skin->userToolLinks( $rc_user, $rc_user_text ); |
401 | | - |
402 | 488 | # Put accumulated information into the cache, for later display |
403 | 489 | # Page moves go on their own line |
404 | 490 | $title = $rc->getTitle(); |
— | — | @@ -419,10 +505,11 @@ |
420 | 506 | */ |
421 | 507 | function recentChangesBlockGroup( $block ) { |
422 | 508 | global $wgLang, $wgContLang, $wgRCShowChangedSize; |
423 | | - $r = ''; |
| 509 | + $r = '<table cellpadding="0" cellspacing="0"><tr>'; |
424 | 510 | |
425 | 511 | # Collate list of users |
426 | 512 | $isnew = false; |
| 513 | + $namehidden = true; |
427 | 514 | $unpatrolled = false; |
428 | 515 | $userlinks = array(); |
429 | 516 | foreach( $block as $rcObj ) { |
— | — | @@ -430,6 +517,11 @@ |
431 | 518 | if( $rcObj->mAttribs['rc_new'] ) { |
432 | 519 | $isnew = true; |
433 | 520 | } |
| 521 | + / if all log actions to this page were hidden, then don't |
| 522 | + / give the name of the affected page for this block |
| 523 | + if( !($rcObj->mAttribs['rc_deleted'] & LogViewer::DELETED_ACTION) ) { |
| 524 | + $namehidden = false; |
| 525 | + } |
434 | 526 | $u = $rcObj->userlink; |
435 | 527 | if( !isset( $userlinks[$u] ) ) { |
436 | 528 | $userlinks[$u] = 0; |
— | — | @@ -463,24 +555,25 @@ |
464 | 556 | $toggleLink = "javascript:toggleVisibility('$rci','$rcm','$rcl')"; |
465 | 557 | $tl = '<span id="'.$rcm.'"><a href="'.$toggleLink.'">' . $this->sideArrow() . '</a></span>'; |
466 | 558 | $tl .= '<span id="'.$rcl.'" style="display:none"><a href="'.$toggleLink.'">' . $this->downArrow() . '</a></span>'; |
467 | | - $r .= $tl; |
| 559 | + $r .= '<td valign="top">'.$tl; |
468 | 560 | |
469 | 561 | # Main line |
470 | | - $r .= '<tt>'; |
471 | | - $r .= $this->recentChangesFlags( $isnew, false, $unpatrolled, ' ', $bot ); |
| 562 | + $r .= ' '.$this->recentChangesFlags( $isnew, false, $unpatrolled, ' ', $bot ); |
472 | 563 | |
473 | 564 | # Timestamp |
474 | | - $r .= ' '.$block[0]->timestamp.' </tt>'; |
| 565 | + $r .= ' '.$block[0]->timestamp.' </td><td>'; |
475 | 566 | |
476 | 567 | # Article link |
477 | | - $r .= $this->maybeWatchedLink( $block[0]->link, $block[0]->watched ); |
| 568 | + if ( $namehidden ) |
| 569 | + $r .= ' <span class="history-deleted">' . wfMsgHtml('rev-deleted-event') . '</span>'; |
| 570 | + else |
| 571 | + $r .= $this->maybeWatchedLink( $block[0]->link, $block[0]->watched ); |
478 | 572 | $r .= $wgContLang->getDirMark(); |
479 | 573 | |
480 | 574 | $curIdEq = 'curid=' . $block[0]->mAttribs['rc_cur_id']; |
481 | 575 | $currentRevision = $block[0]->mAttribs['rc_this_oldid']; |
482 | 576 | if( $block[0]->mAttribs['rc_type'] != RC_LOG ) { |
483 | 577 | # Changes |
484 | | - |
485 | 578 | $n = count($block); |
486 | 579 | static $nchanges = array(); |
487 | 580 | if ( !isset( $nchanges[$n] ) ) { |
— | — | @@ -490,77 +583,94 @@ |
491 | 584 | |
492 | 585 | $r .= ' ('; |
493 | 586 | |
494 | | - if( $isnew ) { |
| 587 | + if( !ChangesList::userCan($rcObj,Revision::DELETED_TEXT) ) { |
| 588 | + $r .= $nchanges[$n]; |
| 589 | + } else if( $isnew ) { |
495 | 590 | $r .= $nchanges[$n]; |
496 | 591 | } else { |
497 | 592 | $r .= $this->skin->makeKnownLinkObj( $block[0]->getTitle(), |
498 | 593 | $nchanges[$n], $curIdEq."&diff=$currentRevision&oldid=$oldid" ); |
499 | 594 | } |
500 | 595 | |
501 | | - $r .= ') . . '; |
502 | | - |
503 | 596 | # Character difference |
504 | 597 | $chardiff = $rcObj->getCharacterDifference( $block[ count( $block ) - 1 ]->mAttribs['rc_old_len'], |
505 | 598 | $block[0]->mAttribs['rc_new_len'] ); |
506 | 599 | if( $chardiff == '' ) { |
507 | | - $r .= ' ('; |
| 600 | + $r .= '; '; |
508 | 601 | } else { |
509 | | - $r .= ' ' . $chardiff. ' . . ('; |
| 602 | + $r .= '; ' . $chardiff . ' '; |
510 | 603 | } |
511 | | - |
512 | 604 | |
513 | 605 | # History |
514 | | - $r .= $this->skin->makeKnownLinkObj( $block[0]->getTitle(), |
515 | | - $this->message['history'], $curIdEq.'&action=history' ); |
| 606 | + $r .= $this->skin->makeKnownLinkObj( $block[0]->getTitle(), $this->message['history'], $curIdEq.'&action=history' ); |
| 607 | + |
516 | 608 | $r .= ')'; |
517 | 609 | } |
518 | 610 | |
519 | 611 | $r .= $users; |
520 | 612 | |
521 | | - $r .= $this->numberofWatchingusers($block[0]->numberofWatchingusers); |
522 | | - $r .= "<br />\n"; |
| 613 | + if($block[0]->numberofWatchingusers > 0) { |
| 614 | + global $wgContLang; |
| 615 | + $r .= wfMsg('number_of_watching_users_RCview', $wgContLang->formatNum($block[0]->numberofWatchingusers)); |
| 616 | + } |
| 617 | + $r .= "</td></tr></table>\n"; |
523 | 618 | |
524 | 619 | # Sub-entries |
525 | | - $r .= '<div id="'.$rci.'" style="display:none">'; |
| 620 | + $r .= '<div id="'.$rci.'" style="display:none; font-size:95%;"><table cellpadding="0" cellspacing="0">'; |
526 | 621 | foreach( $block as $rcObj ) { |
527 | 622 | # Get rc_xxxx variables |
528 | | - / FIXME: Would be good to replace this extract() call with something that explicitly initializes local variables. |
529 | 623 | extract( $rcObj->mAttribs ); |
530 | 624 | |
531 | | - $r .= $this->spacerArrow(); |
532 | | - $r .= '<tt> '; |
| 625 | + #$r .= '<tr><td valign="top">'.$this->spacerArrow(); |
| 626 | + $r .= '<tr><td valign="top">'.$this->spacerIndent(); |
| 627 | + $r .= ' '; |
533 | 628 | $r .= $this->recentChangesFlags( $rc_new, $rc_minor, $rcObj->unpatrolled, ' ', $rc_bot ); |
534 | | - $r .= ' </tt>'; |
| 629 | + $r .= ' </td><td valign="top">'; |
535 | 630 | |
536 | 631 | $o = ''; |
537 | 632 | if( $rc_this_oldid != 0 ) { |
538 | 633 | $o = 'oldid='.$rc_this_oldid; |
539 | 634 | } |
| 635 | + # Revision link |
540 | 636 | if( $rc_type == RC_LOG ) { |
541 | | - $link = $rcObj->timestamp; |
| 637 | + $link = $rcObj->timestamp.' '; |
| 638 | + } else if( !ChangesList::userCan($rcObj,Revision::DELETED_TEXT) ) { |
| 639 | + $link = '<span class="history-deleted">'.$rcObj->timestamp.'</span> '; |
542 | 640 | } else { |
543 | 641 | $link = $this->skin->makeKnownLinkObj( $rcObj->getTitle(), $rcObj->timestamp, $curIdEq.'&'.$o ); |
| 642 | + if( $this->isDeleted($rcObj,Revision::DELETED_TEXT) ) |
| 643 | + $link = '<span class="history-deleted">'.$link.'</span> '; |
544 | 644 | } |
545 | | - $link = '<tt>'.$link.'</tt>'; |
546 | | - |
547 | 645 | $r .= $link; |
548 | | - $r .= ' ('; |
549 | | - $r .= $rcObj->curlink; |
550 | | - $r .= '; '; |
551 | | - $r .= $rcObj->lastlink; |
552 | | - $r .= ') . . '; |
| 646 | + |
| 647 | + if ( !$rc_log_type ) { |
| 648 | + $r .= ' ('; |
| 649 | + $r .= $rcObj->curlink; |
| 650 | + $r .= '; '; |
| 651 | + $r .= $rcObj->lastlink; |
| 652 | + $r .= ')'; |
| 653 | + } else { |
| 654 | + $logname = LogPage::logName( $rc_log_type ); |
| 655 | + $logtitle = Title::newFromText( "Log/$rc_log_type", NS_SPECIAL ); |
| 656 | + $r .= '(' . $this->skin->makeKnownLinkObj($logtitle, $logname ) . ')'; |
| 657 | + } |
| 658 | + $r .= ' . . '; |
553 | 659 | |
554 | 660 | # Character diff |
555 | 661 | if( $wgRCShowChangedSize ) { |
556 | 662 | $r .= ( $rcObj->getCharacterDifference() == '' ? '' : $rcObj->getCharacterDifference() . ' . . ' ) ; |
557 | 663 | } |
558 | | - |
| 664 | + # User links |
559 | 665 | $r .= $rcObj->userlink; |
560 | 666 | $r .= $rcObj->usertalklink; |
561 | | - $r .= $this->skin->commentBlock( $rc_comment, $rcObj->getTitle() ); |
562 | | - $r .= "<br />\n"; |
| 667 | + / log action |
| 668 | + parent::insertAction($r, $rcObj); |
| 669 | + / log comment |
| 670 | + parent::insertComment($r, $rcObj); |
| 671 | + |
| 672 | + $r .= "</td></tr>\n"; |
563 | 673 | } |
564 | | - $r .= "</div>\n"; |
| 674 | + $r .= "</table></div>\n"; |
565 | 675 | |
566 | 676 | $this->rcCacheIndex++; |
567 | 677 | return $r; |
— | — | @@ -617,8 +727,23 @@ |
618 | 728 | * @access private |
619 | 729 | */ |
620 | 730 | function spacerArrow() { |
| 731 | + /FIXME: problems with FF 1.5x |
621 | 732 | return $this->arrow( '', ' ' ); |
622 | 733 | } |
| 734 | + |
| 735 | + /** |
| 736 | + * Generate HTML for the equivilant of a spacer image for tables |
| 737 | + * @return string HTML <td> tag |
| 738 | + * @access private |
| 739 | + */ |
| 740 | + function spacerColumn() { |
| 741 | + return '<td width="12"></td>'; |
| 742 | + } |
| 743 | + |
| 744 | + / Adds a few spaces |
| 745 | + function spacerIndent() { |
| 746 | + return ' '; |
| 747 | + } |
623 | 748 | |
624 | 749 | /** |
625 | 750 | * Enhanced RC ungrouped line. |
— | — | @@ -628,50 +753,69 @@ |
629 | 754 | global $wgContLang, $wgRCShowChangedSize; |
630 | 755 | |
631 | 756 | # Get rc_xxxx variables |
632 | | - / FIXME: Would be good to replace this extract() call with something that explicitly initializes local variables. |
633 | 757 | extract( $rcObj->mAttribs ); |
634 | 758 | $curIdEq = 'curid='.$rc_cur_id; |
635 | 759 | |
636 | | - $r = ''; |
| 760 | + $r = '<table cellspacing="0" cellpadding="0"><tr><td>'; |
637 | 761 | |
638 | | - # Spacer image |
639 | | - $r .= $this->spacerArrow(); |
640 | | - |
| 762 | + # spacerArrow() causes issues in FF |
| 763 | + $r .= $this->spacerColumn(); |
| 764 | + $r .= '<td valign="top">'; |
| 765 | + |
641 | 766 | # Flag and Timestamp |
642 | | - $r .= '<tt>'; |
643 | | - |
644 | 767 | if( $rc_type == RC_MOVE || $rc_type == RC_MOVE_OVER_REDIRECT ) { |
645 | | - $r .= ' '; |
| 768 | + $r .= ' '; |
646 | 769 | } else { |
647 | | - $r .= $this->recentChangesFlags( $rc_type == RC_NEW, $rc_minor, $rcObj->unpatrolled, ' ', $rc_bot ); |
| 770 | + $r .= ' '.$this->recentChangesFlags( $rc_type == RC_NEW, $rc_minor, $rcObj->unpatrolled, ' ', $rc_bot ); |
648 | 771 | } |
649 | | - $r .= ' '.$rcObj->timestamp.' </tt>'; |
650 | | - |
| 772 | + $r .= ' '.$rcObj->timestamp.' </td><td>'; |
| 773 | + |
651 | 774 | # Article link |
652 | | - $r .= $this->maybeWatchedLink( $rcObj->link, $rcObj->watched ); |
653 | | - |
654 | | - # Diff |
655 | | - $r .= ' ('. $rcObj->difflink .'; '; |
656 | | - |
657 | | - # Hist |
658 | | - $r .= $this->skin->makeKnownLinkObj( $rcObj->getTitle(), wfMsg( 'hist' ), $curIdEq.'&action=history' ) . ') . . '; |
659 | | - |
| 775 | + if ( $rc_log_type !='' ) { |
| 776 | + $logtitle = Title::newFromText( "Log/$rc_log_type", NS_SPECIAL ); |
| 777 | + $logname = LogPage::logName( $rc_log_type ); |
| 778 | + $r .= '(' . $this->skin->makeKnownLinkObj($logtitle, $logname ) . ')'; |
| 779 | + / All other stuff |
| 780 | + } else { |
| 781 | + $r .= $this->maybeWatchedLink( $rcObj->link, $rcObj->watched ); |
| 782 | + } |
| 783 | + if ( $rc_type != RC_LOG ) { |
| 784 | + # Diff |
| 785 | + $r .= ' ('. $rcObj->difflink .'; '; |
| 786 | + # Hist |
| 787 | + $r .= $this->skin->makeKnownLinkObj( $rcObj->getTitle(), wfMsg( 'hist' ), $curIdEq.'&action=history' ) . ')'; |
| 788 | + } |
| 789 | + $r .= ' . . '; |
| 790 | + |
660 | 791 | # Character diff |
661 | 792 | if( $wgRCShowChangedSize ) { |
662 | 793 | $r .= ( $rcObj->getCharacterDifference() == '' ? '' : ' ' . $rcObj->getCharacterDifference() . ' . . ' ) ; |
663 | 794 | } |
664 | 795 | |
665 | 796 | # User/talk |
666 | | - $r .= $rcObj->userlink . $rcObj->usertalklink; |
| 797 | + $r .= ' '.$rcObj->userlink . $rcObj->usertalklink; |
667 | 798 | |
668 | 799 | # Comment |
669 | 800 | if( $rc_type != RC_MOVE && $rc_type != RC_MOVE_OVER_REDIRECT ) { |
670 | | - $r .= $this->skin->commentBlock( $rc_comment, $rcObj->getTitle() ); |
| 801 | + / log action |
| 802 | + if ( $this->isDeleted($rcObj,LogViewer::DELETED_ACTION) ) { |
| 803 | + $r .= ' <span class="history-deleted">' . wfMsgHtml('rev-deleted-event') . '</span>'; |
| 804 | + } else { |
| 805 | + $r .= ' ' . LogPage::actionText( $rc_log_type, $rc_log_action, $rcObj->getTitle(), $this->skin, LogPage::extractParams($rc_params), true, true ); |
| 806 | + } |
| 807 | + / log comment |
| 808 | + if ( $this->isDeleted($rcObj,LogViewer::DELETED_COMMENT) ) { |
| 809 | + $r .= ' <span class="history-deleted">' . wfMsg('rev-deleted-comment') . '</span>'; |
| 810 | + } else { |
| 811 | + $r .= $this->skin->commentBlock( $rc_comment, $rcObj->getTitle() ); |
| 812 | + } |
671 | 813 | } |
672 | 814 | |
673 | | - $r .= $this->numberofWatchingusers($rcObj->numberofWatchingusers); |
| 815 | + if( $rcObj->numberofWatchingusers > 0 ) { |
| 816 | + $r .= wfMsg('number_of_watching_users_RCview', $wgContLang->formatNum($rcObj->numberofWatchingusers)); |
| 817 | + } |
674 | 818 | |
675 | | - $r .= "<br />\n"; |
| 819 | + $r .= "</td></tr></table>\n"; |
676 | 820 | return $r; |
677 | 821 | } |
678 | 822 | |
Index: trunk/phase3/includes/SpecialUndelete.php |
— | — | @@ -99,7 +99,7 @@ |
100 | 100 | function listRevisions() { |
101 | 101 | $dbr = wfGetDB( DB_SLAVE ); |
102 | 102 | $res = $dbr->select( 'archive', |
103 | | - array( 'ar_minor_edit', 'ar_timestamp', 'ar_user', 'ar_user_text', 'ar_comment', 'ar_len' ), |
| 103 | + array( 'ar_minor_edit', 'ar_timestamp', 'ar_user', 'ar_user_text', 'ar_comment', 'ar_rev_id', 'ar_deleted', 'ar_len' ), |
104 | 104 | array( 'ar_namespace' => $this->title->getNamespace(), |
105 | 105 | 'ar_title' => $this->title->getDBkey() ), |
106 | 106 | 'PageArchive::listRevisions', |
— | — | @@ -116,7 +116,7 @@ |
117 | 117 | * @return ResultWrapper |
118 | 118 | * @fixme Does this belong in Image for fuller encapsulation? |
119 | 119 | */ |
120 | | - function listFiles() { |
| 120 | + function listFiles() { |
121 | 121 | if( $this->title->getNamespace() == NS_IMAGE ) { |
122 | 122 | $dbr = wfGetDB( DB_SLAVE ); |
123 | 123 | $res = $dbr->select( 'filearchive', |
— | — | @@ -130,7 +130,8 @@ |
131 | 131 | 'fa_description', |
132 | 132 | 'fa_user', |
133 | 133 | 'fa_user_text', |
134 | | - 'fa_timestamp' ), |
| 134 | + 'fa_timestamp', |
| 135 | + 'fa_deleted' ), |
135 | 136 | array( 'fa_name' => $this->title->getDbKey() ), |
136 | 137 | __METHOD__, |
137 | 138 | array( 'ORDER BY' => 'fa_timestamp DESC' ) ); |
— | — | @@ -151,14 +152,25 @@ |
152 | 153 | $rev = $this->getRevision( $timestamp ); |
153 | 154 | return $rev ? $rev->getText() : null; |
154 | 155 | } |
| 156 | + |
| 157 | + function getRevisionConds( $timestamp, $id ) { |
| 158 | + if ( $id ) { |
| 159 | + $id = intval($id); |
| 160 | + return "ar_rev_id=$id"; |
| 161 | + } else if ( $timestamp ) { |
| 162 | + return "ar_timestamp=$timestamp"; |
| 163 | + } else { |
| 164 | + return 'ar_rev_id=0'; |
| 165 | + } |
| 166 | + } |
155 | 167 | |
156 | 168 | /** |
157 | 169 | * Return a Revision object containing data for the deleted revision. |
158 | | - * Note that the result *may* or *may not* have a null page ID. |
159 | | - * @param string $timestamp |
| 170 | + * Note that the result *may* have a null page ID. |
| 171 | + * @param string $timestamp or $id |
160 | 172 | * @return Revision |
161 | 173 | */ |
162 | | - function getRevision( $timestamp ) { |
| 174 | + function getRevision( $timestamp, $id=null ) { |
163 | 175 | $dbr = wfGetDB( DB_SLAVE ); |
164 | 176 | $row = $dbr->selectRow( 'archive', |
165 | 177 | array( |
— | — | @@ -171,10 +183,11 @@ |
172 | 184 | 'ar_minor_edit', |
173 | 185 | 'ar_flags', |
174 | 186 | 'ar_text_id', |
| 187 | + 'ar_deleted', |
175 | 188 | 'ar_len' ), |
176 | 189 | array( 'ar_namespace' => $this->title->getNamespace(), |
177 | 190 | 'ar_title' => $this->title->getDbkey(), |
178 | | - 'ar_timestamp' => $dbr->timestamp( $timestamp ) ), |
| 191 | + $this->getRevisionConds( $dbr->timestamp($timestamp), $id ) ), |
179 | 192 | __METHOD__ ); |
180 | 193 | if( $row ) { |
181 | 194 | return new Revision( array( |
— | — | @@ -188,7 +201,9 @@ |
189 | 202 | 'user_text' => $row->ar_user_text, |
190 | 203 | 'timestamp' => $row->ar_timestamp, |
191 | 204 | 'minor_edit' => $row->ar_minor_edit, |
192 | | - 'text_id' => $row->ar_text_id ) ); |
| 205 | + 'text_id' => $row->ar_text_id, |
| 206 | + 'deleted' => $row->ar_deleted, |
| 207 | + 'len' => $row->ar_len) ); |
193 | 208 | } else { |
194 | 209 | return null; |
195 | 210 | } |
— | — | @@ -260,7 +275,7 @@ |
261 | 276 | * |
262 | 277 | * @return true on success. |
263 | 278 | */ |
264 | | - function undelete( $timestamps, $comment = '', $fileVersions = array() ) { |
| 279 | + function undelete( $timestamps, $comment = '', $fileVersions = array(), $Unsuppress = false) { |
265 | 280 | / If both the set of text revisions and file revisions are empty, |
266 | 281 | / restore everything. Otherwise, just restore the requested items. |
267 | 282 | $restoreAll = empty( $timestamps ) && empty( $fileVersions ); |
— | — | @@ -268,17 +283,20 @@ |
269 | 284 | $restoreText = $restoreAll || !empty( $timestamps ); |
270 | 285 | $restoreFiles = $restoreAll || !empty( $fileVersions ); |
271 | 286 | |
272 | | - if( $restoreFiles && $this->title->getNamespace() == NS_IMAGE ) { |
273 | | - $img = new Image( $this->title ); |
274 | | - $filesRestored = $img->restore( $fileVersions ); |
| 287 | + if( $restoreText ) { |
| 288 | + $textRestored = $this->undeleteRevisions( $timestamps, $Unsuppress ); |
275 | 289 | } else { |
276 | | - $filesRestored = 0; |
| 290 | + $textRestored = 0; |
277 | 291 | } |
278 | 292 | |
279 | | - if( $restoreText ) { |
280 | | - $textRestored = $this->undeleteRevisions( $timestamps ); |
| 293 | + if ( $restoreText && !$textRestored) { |
| 294 | + / if the image page didn't restore right, don't restore the file either!!! |
| 295 | + $filesRestored = 0; |
| 296 | + } else if( $restoreFiles && $this->title->getNamespace() == NS_IMAGE ) { |
| 297 | + $img = new Image( $this->title ); |
| 298 | + $filesRestored = $img->restore( $fileVersions, $Unsuppress ); |
281 | 299 | } else { |
282 | | - $textRestored = 0; |
| 300 | + $filesRestored = 0; |
283 | 301 | } |
284 | 302 | |
285 | 303 | / Touch the log! |
— | — | @@ -286,14 +304,14 @@ |
287 | 305 | $log = new LogPage( 'delete' ); |
288 | 306 | |
289 | 307 | if( $textRestored && $filesRestored ) { |
290 | | - $reason = wfMsgForContent( 'undeletedrevisions-files', |
| 308 | + $reason = wfMsgExt( 'undeletedrevisions-files', array('parsemag'), |
291 | 309 | $wgContLang->formatNum( $textRestored ), |
292 | 310 | $wgContLang->formatNum( $filesRestored ) ); |
293 | 311 | } elseif( $textRestored ) { |
294 | | - $reason = wfMsgForContent( 'undeletedrevisions', |
| 312 | + $reason = wfMsgExt( 'undeletedrevisions', array('parsemag'), |
295 | 313 | $wgContLang->formatNum( $textRestored ) ); |
296 | 314 | } elseif( $filesRestored ) { |
297 | | - $reason = wfMsgForContent( 'undeletedfiles', |
| 315 | + $reason = wfMsgExt( 'undeletedfiles', array('parsemag'), |
298 | 316 | $wgContLang->formatNum( $filesRestored ) ); |
299 | 317 | } else { |
300 | 318 | wfDebug( "Undelete: nothing undeleted...\n" ); |
— | — | @@ -315,10 +333,11 @@ |
316 | 334 | * @param array $timestamps Pass an empty array to restore all revisions, otherwise list the ones to undelete. |
317 | 335 | * @param string $comment |
318 | 336 | * @param array $fileVersions |
| 337 | + * @param bool $Unsuppress, remove all ar_deleted/fa_deleted restrictions of seletected revs |
319 | 338 | * |
320 | 339 | * @return int number of revisions restored |
321 | 340 | */ |
322 | | - private function undeleteRevisions( $timestamps ) { |
| 341 | + private function undeleteRevisions( $timestamps, $Unsuppress = false ) { |
323 | 342 | global $wgDBtype; |
324 | 343 | |
325 | 344 | $restoreAll = empty( $timestamps ); |
— | — | @@ -362,7 +381,7 @@ |
363 | 382 | } |
364 | 383 | |
365 | 384 | /** |
366 | | - * Restore each revision... |
| 385 | + * Select each archived revision... |
367 | 386 | */ |
368 | 387 | $result = $dbw->select( 'archive', |
369 | 388 | /* fields */ array( |
— | — | @@ -375,6 +394,7 @@ |
376 | 395 | 'ar_minor_edit', |
377 | 396 | 'ar_flags', |
378 | 397 | 'ar_text_id', |
| 398 | + 'ar_deleted', |
379 | 399 | 'ar_len' ), |
380 | 400 | /* WHERE */ array( |
381 | 401 | 'ar_namespace' => $this->title->getNamespace(), |
— | — | @@ -384,15 +404,30 @@ |
385 | 405 | /* options */ array( |
386 | 406 | 'ORDER BY' => 'ar_timestamp' ) |
387 | 407 | ); |
388 | | - if( $dbw->numRows( $result ) < count( $timestamps ) ) { |
| 408 | + $rev_count = $dbw->numRows( $result ); |
| 409 | + if( $rev_count < count( $timestamps ) ) { |
| 410 | + # Remove page stub per failure |
| 411 | + $dbw->delete( 'page', array( 'page_id' => $pageId ), __METHOD__); |
389 | 412 | wfDebug( __METHOD__.": couldn't find all requested rows\n" ); |
390 | 413 | return false; |
391 | 414 | } |
392 | 415 | |
| 416 | + $ret = $dbw->resultObject( $result ); |
| 417 | + / FIXME: We don't currently handle well changing the top revision's settings |
| 418 | + $ret->seek( $rev_count - 1 ); |
| 419 | + $last_row = $ret->fetchObject(); |
| 420 | + if ( !$Unsuppress && $last_row->ar_deleted && $last_row->ar_rev_id > $previousRevId ) { |
| 421 | + # Remove page stub per failure |
| 422 | + $dbw->delete( 'page', array( 'page_id' => $pageId ), __METHOD__); |
| 423 | + wfDebug( __METHOD__.": couldn't find all requested rows or not all of them could be restored\n" ); |
| 424 | + return false; |
| 425 | + } |
| 426 | + |
393 | 427 | $revision = null; |
394 | 428 | $restored = 0; |
395 | | - |
396 | | - while( $row = $dbw->fetchObject( $result ) ) { |
| 429 | + |
| 430 | + $ret->seek( 0 ); |
| 431 | + while( $row = $ret->fetchObject() ) { |
397 | 432 | if( $row->ar_text_id ) { |
398 | 433 | / Revision was deleted in 1.5+; text is in |
399 | 434 | / the regular text table, use the reference. |
— | — | @@ -415,7 +450,8 @@ |
416 | 451 | 'timestamp' => $row->ar_timestamp, |
417 | 452 | 'minor_edit' => $row->ar_minor_edit, |
418 | 453 | 'text_id' => $row->ar_text_id, |
419 | | - 'len' => $row->ar_len |
| 454 | + 'deleted' => ($Unsuppress) ? 0 : $row->ar_deleted, |
| 455 | + 'len' => $row->ar_len |
420 | 456 | ) ); |
421 | 457 | $revision->insertOn( $dbw ); |
422 | 458 | $restored++; |
— | — | @@ -477,6 +513,7 @@ |
478 | 514 | $this->mRestore = $request->getCheck( 'restore' ) && $posted; |
479 | 515 | $this->mPreview = $request->getCheck( 'preview' ) && $posted; |
480 | 516 | $this->mComment = $request->getText( 'wpComment' ); |
| 517 | + $this->mUnsuppress = $request->getVal( 'wpUnsuppress' ) && $wgUser->isAllowed( 'oversight' ); |
481 | 518 | |
482 | 519 | if( $par != "" ) { |
483 | 520 | $this->mTarget = $par; |
— | — | @@ -512,21 +549,25 @@ |
513 | 550 | } |
514 | 551 | |
515 | 552 | function execute() { |
516 | | - global $wgOut; |
| 553 | + global $wgOut, $wgUser; |
517 | 554 | if ( $this->mAllowed ) { |
518 | | - $wgOut->setPagetitle( wfMsg( "undeletepage" ) ); |
| 555 | + $wgOut->setPagetitle( wfMsgHtml( "undeletepage" ) ); |
519 | 556 | } else { |
520 | | - $wgOut->setPagetitle( wfMsg( "viewdeletedpage" ) ); |
| 557 | + $wgOut->setPagetitle( wfMsgHtml( "viewdeletedpage" ) ); |
521 | 558 | } |
522 | 559 | |
523 | 560 | if( is_null( $this->mTargetObj ) ) { |
524 | | - $this->showSearchForm(); |
| 561 | + # Not all users can just browse every deleted page from the list |
| 562 | + if ( $wgUser->isAllowed( 'browsearchive' ) ) { |
| 563 | + $this->showSearchForm(); |
525 | 564 | |
526 | | - # List undeletable articles |
527 | | - if( $this->mSearchPrefix ) { |
528 | | - $result = PageArchive::listPagesByPrefix( |
529 | | - $this->mSearchPrefix ); |
530 | | - $this->showList( $result ); |
| 565 | + # List undeletable articles |
| 566 | + if( $this->mSearchPrefix ) { |
| 567 | + $result = PageArchive::listPagesByPrefix( $this->mSearchPrefix ); |
| 568 | + $this->showList( $result ); |
| 569 | + } |
| 570 | + } else { |
| 571 | + $wgOut->addWikiText( wfMsgHtml( 'undelete-header' ) ); |
531 | 572 | } |
532 | 573 | return; |
533 | 574 | } |
— | — | @@ -534,7 +575,14 @@ |
535 | 576 | return $this->showRevision( $this->mTimestamp ); |
536 | 577 | } |
537 | 578 | if( $this->mFile !== null ) { |
538 | | - return $this->showFile( $this->mFile ); |
| 579 | + $file = new ArchivedFile( $this->mTargetObj, '', $this->mFile ); |
| 580 | + / Check if user is allowed to see this file |
| 581 | + if ( !$file->userCan( Image::DELETED_FILE ) ) { |
| 582 | + $wgOut->permissionRequired( 'hiderevision' ); |
| 583 | + return false; |
| 584 | + } else { |
| 585 | + return $this->showFile( $this->mFile ); |
| 586 | + } |
539 | 587 | } |
540 | 588 | if( $this->mRestore && $this->mAction == "submit" ) { |
541 | 589 | return $this->undelete(); |
— | — | @@ -544,7 +592,7 @@ |
545 | 593 | |
546 | 594 | function showSearchForm() { |
547 | 595 | global $wgOut, $wgScript; |
548 | | - $wgOut->addWikiText( wfMsg( 'undelete-header' ) ); |
| 596 | + $wgOut->addWikiText( wfMsgHtml( 'undelete-header' ) ); |
549 | 597 | |
550 | 598 | $wgOut->addHtml( |
551 | 599 | Xml::openElement( 'form', array( |
— | — | @@ -563,6 +611,7 @@ |
564 | 612 | '</form>' ); |
565 | 613 | } |
566 | 614 | |
| 615 | + / Generic list of deleted pages |
567 | 616 | /* private */ function showList( $result ) { |
568 | 617 | global $wgLang, $wgContLang, $wgUser, $wgOut; |
569 | 618 | |
— | — | @@ -612,11 +661,22 @@ |
613 | 662 | return; |
614 | 663 | } |
615 | 664 | |
| 665 | + if( $rev->isDeleted(Revision::DELETED_TEXT) ) { |
| 666 | + if( !$rev->userCan(Revision::DELETED_TEXT) ) { |
| 667 | + $wgOut->addWikiText( wfMsg( 'rev-deleted-text-permission' ) ); |
| 668 | + return; |
| 669 | + } else { |
| 670 | + $wgOut->addWikiText( wfMsg( 'rev-deleted-text-view' ) ); |
| 671 | + $wgOut->addHTML( '<br/>' ); |
| 672 | + / and we are allowed to see... |
| 673 | + } |
| 674 | + } |
| 675 | + |
616 | 676 | wfRunHooks( 'UndeleteShowRevision', array( $this->mTargetObj, $rev ) ); |
617 | 677 | |
618 | 678 | if( $this->mPreview ) { |
619 | 679 | $wgOut->addHtml( "<hr />\n" ); |
620 | | - $wgOut->addWikiTextTitle( $rev->getText(), $this->mTargetObj, false ); |
| 680 | + $wgOut->addWikiTextTitle( $rev->revText(), $this->mTargetObj, false ); |
621 | 681 | } |
622 | 682 | |
623 | 683 | $wgOut->addHtml( |
— | — | @@ -624,7 +684,7 @@ |
625 | 685 | 'readonly' => true, |
626 | 686 | 'cols' => intval( $wgUser->getOption( 'cols' ) ), |
627 | 687 | 'rows' => intval( $wgUser->getOption( 'rows' ) ) ), |
628 | | - $rev->getText() . "\n" ) . |
| 688 | + $rev->revText() . "\n" ) . |
629 | 689 | wfOpenElement( 'div' ) . |
630 | 690 | wfOpenElement( 'form', array( |
631 | 691 | 'method' => 'post', |
— | — | @@ -674,7 +734,7 @@ |
675 | 735 | /* private */ function showHistory() { |
676 | 736 | global $wgLang, $wgUser, $wgOut; |
677 | 737 | |
678 | | - $sk = $wgUser->getSkin(); |
| 738 | + $this->sk = $wgUser->getSkin(); |
679 | 739 | if ( $this->mAllowed ) { |
680 | 740 | $wgOut->setPagetitle( wfMsg( "undeletepage" ) ); |
681 | 741 | } else { |
— | — | @@ -690,9 +750,10 @@ |
691 | 751 | } |
692 | 752 | */ |
693 | 753 | if ( $this->mAllowed ) { |
694 | | - $wgOut->addWikiText( wfMsg( "undeletehistory" ) ); |
| 754 | + $wgOut->addWikiText( '<p>' . wfMsgHtml( "undeletehistory" ) . '</p>' ); |
| 755 | + $wgOut->addHtml( '<p>' . wfMsgHtml( "undeleterevdel" ) . '</p>' ); |
695 | 756 | } else { |
696 | | - $wgOut->addWikiText( wfMsg( "undeletehistorynoadmin" ) ); |
| 757 | + $wgOut->addWikiText( wfMsgHtml( "undeletehistorynoadmin" ) ); |
697 | 758 | } |
698 | 759 | |
699 | 760 | # List all stored revisions |
— | — | @@ -738,7 +799,16 @@ |
739 | 800 | array( 'page' => $this->mTargetObj->getPrefixedText(), |
740 | 801 | 'type' => 'delete' ) ) ) ); |
741 | 802 | $logViewer->showList( $wgOut ); |
742 | | - |
| 803 | + # Show relevant lines from the oversight log if user is allowed to see it: |
| 804 | + if ( $wgUser->isAllowed( 'oversight' ) ) { |
| 805 | + $wgOut->addHTML( "<h2>" . htmlspecialchars( LogPage::logName( 'oversight' ) ) . "</h2>\n" ); |
| 806 | + $logViewer = new LogViewer( |
| 807 | + new LogReader( |
| 808 | + new FauxRequest( |
| 809 | + array( 'page' => $this->mTargetObj->getPrefixedText(), |
| 810 | + 'type' => 'oversight' ) ) ) ); |
| 811 | + $logViewer->showList( $wgOut ); |
| 812 | + } |
743 | 813 | if( $this->mAllowed && ( $haveRevisions || $haveFiles ) ) { |
744 | 814 | # Format the user-visible controls (comment field, submission button) |
745 | 815 | # in a nice little table |
— | — | @@ -746,6 +816,10 @@ |
747 | 817 | $table .= '<td colspan="2">' . wfMsgWikiHtml( 'undeleteextrahelp' ) . '</td></tr><tr>'; |
748 | 818 | $table .= '<td align="right"><strong>' . wfMsgHtml( 'undeletecomment' ) . '</strong></td>'; |
749 | 819 | $table .= '<td>' . wfInput( 'wpComment', 50, $this->mComment ) . '</td>'; |
| 820 | + if ( $wgUser->isAllowed( 'oversight' ) ) { |
| 821 | + $table .= '</tr><tr><td> </td><td>'; |
| 822 | + $table .= Xml::checkLabel( wfMsg( 'revdelete-unsuppress' ), 'wpUnsuppress', 'wpUnsuppress', false, array( 'tabindex' => '2' ) ); |
| 823 | + } |
750 | 824 | $table .= '</tr><tr><td> </td><td>'; |
751 | 825 | $table .= wfSubmitButton( wfMsg( 'undeletebtn' ), array( 'name' => 'restore' ) ); |
752 | 826 | $table .= wfElement( 'input', array( 'type' => 'reset', 'value' => wfMsg( 'undeletereset' ) ) ); |
— | — | @@ -761,26 +835,48 @@ |
762 | 836 | $target = urlencode( $this->mTarget ); |
763 | 837 | while( $row = $revisions->fetchObject() ) { |
764 | 838 | $ts = wfTimestamp( TS_MW, $row->ar_timestamp ); |
| 839 | + / We don't handle top edits with rev_deleted |
765 | 840 | if ( $this->mAllowed ) { |
766 | | - $checkBox = wfCheck( "ts$ts" ); |
767 | | - $pageLink = $sk->makeKnownLinkObj( $titleObj, |
768 | | - $wgLang->timeanddate( $ts, true ), |
769 | | - "target=$target×tamp=$ts" ); |
| 841 | + $checkBox = wfCheck( "ts$ts", false ); |
| 842 | + $titleObj = SpecialPage::getTitleFor( "Undelete" ); |
| 843 | + $pageLink = $this->getPageLink( $row, $titleObj, $ts, $target ); |
770 | 844 | } else { |
771 | 845 | $checkBox = ''; |
772 | 846 | $pageLink = $wgLang->timeanddate( $ts, true ); |
773 | 847 | } |
774 | | - $userLink = $sk->userLink( $row->ar_user, $row->ar_user_text ) . $sk->userToolLinks( $row->ar_user, $row->ar_user_text ); |
| 848 | + $userLink = $this->getUser( $row ); |
775 | 849 | $stxt = ''; |
776 | 850 | if (!is_null($size = $row->ar_len)) { |
777 | 851 | if ($size == 0) |
778 | 852 | $stxt = wfMsgHtml('historyempty'); |
779 | | - else |
| 853 | + else |
780 | 854 | $stxt = wfMsgHtml('historysize', $wgLang->formatNum( $size ) ); |
781 | 855 | } |
782 | | - $comment = $sk->commentBlock( $row->ar_comment ); |
783 | | - $wgOut->addHTML( "<li>$checkBox $pageLink . . $userLink $stxt $comment</li>\n" ); |
784 | | - |
| 856 | + $comment = $this->getComment( $row ); |
| 857 | + $rd=''; |
| 858 | + if( $wgUser->isAllowed( 'deleterevision' ) ) { |
| 859 | + $revdel = SpecialPage::getTitleFor( 'Revisiondelete' ); |
| 860 | + if( !$this->userCan( $row, Revision::DELETED_RESTRICTED ) ) { |
| 861 | + / If revision was hidden from sysops |
| 862 | + $del = wfMsgHtml( 'rev-delundel' ); |
| 863 | + } else { |
| 864 | + $del = $this->sk->makeKnownLinkObj( $revdel, |
| 865 | + wfMsg( 'rev-delundel' ), |
| 866 | + 'target=' . urlencode( $this->mTarget ) . |
| 867 | + '&arid=' . urlencode( $row->ar_rev_id ) ); |
| 868 | + / Bolden oversighted content |
| 869 | + if( $this->isDeleted( $row, Revision::DELETED_RESTRICTED ) ) |
| 870 | + $del = "<strong>$del</strong>"; |
| 871 | + } |
| 872 | + $rd = "<tt>(<small>$del</small>)</tt>"; |
| 873 | + } |
| 874 | + |
| 875 | + $dflag=''; |
| 876 | + if( $this->isDeleted( $row, Revision::DELETED_TEXT ) ) |
| 877 | + $dflag = ' <tt>' . wfMsgHtml( 'deletedrev' ) . '</tt>'; |
| 878 | + |
| 879 | + / Do we still need checkboxes? |
| 880 | + $wgOut->addHTML( "<li>$checkBox $rd $pageLink . . $userLink $stxt $comment$dflag</li>\n" ); |
785 | 881 | } |
786 | 882 | $revisions->free(); |
787 | 883 | $wgOut->addHTML("</ul>"); |
— | — | @@ -795,17 +891,21 @@ |
796 | 892 | while( $row = $files->fetchObject() ) { |
797 | 893 | $ts = wfTimestamp( TS_MW, $row->fa_timestamp ); |
798 | 894 | if ( $this->mAllowed && $row->fa_storage_key ) { |
799 | | - $checkBox = wfCheck( "fileid" . $row->fa_id ); |
| 895 | + if ( !$this->userCan( $row, Revision::DELETED_RESTRICTED ) ) |
| 896 | + / Grey out boxes to files restricted beyond this user. |
| 897 | + / In the future, all image storage may use FileStore, allowing |
| 898 | + / for such items to be restored and retain their fa_deleted status |
| 899 | + $checkBox = wfCheck( "", false, array("disabled" => "disabled") ); |
| 900 | + else |
| 901 | + $checkBox = wfCheck( "fileid" . $row->fa_id ); |
800 | 902 | $key = urlencode( $row->fa_storage_key ); |
801 | 903 | $target = urlencode( $this->mTarget ); |
802 | | - $pageLink = $sk->makeKnownLinkObj( $titleObj, |
803 | | - $wgLang->timeanddate( $ts, true ), |
804 | | - "target=$target&file=$key" ); |
| 904 | + $pageLink = $this->getFileLink( $row, $titleObj, $ts, $target, $key ); |
805 | 905 | } else { |
806 | 906 | $checkBox = ''; |
807 | 907 | $pageLink = $wgLang->timeanddate( $ts, true ); |
808 | 908 | } |
809 | | - $userLink = $sk->userLink( $row->fa_user, $row->fa_user_text ) . $sk->userToolLinks( $row->fa_user, $row->fa_user_text ); |
| 909 | + $userLink = $this->getFileUser( $row ); |
810 | 910 | $data = |
811 | 911 | wfMsgHtml( 'widthheight', |
812 | 912 | $wgLang->formatNum( $row->fa_width ), |
— | — | @@ -813,8 +913,25 @@ |
814 | 914 | ' (' . |
815 | 915 | wfMsgHtml( 'nbytes', $wgLang->formatNum( $row->fa_size ) ) . |
816 | 916 | ')'; |
817 | | - $comment = $sk->commentBlock( $row->fa_description ); |
818 | | - $wgOut->addHTML( "<li>$checkBox $pageLink . . $userLink $data $comment</li>\n" ); |
| 917 | + $comment = $this->getFileComment( $row ); |
| 918 | + $rd=''; |
| 919 | + if( $wgUser->isAllowed( 'deleterevision' ) ) { |
| 920 | + $revdel = SpecialPage::getTitleFor( 'Revisiondelete' ); |
| 921 | + if( !$this->userCan( $row, Image::DELETED_RESTRICTED ) ) { |
| 922 | + / If revision was hidden from sysops |
| 923 | + $del = wfMsgHtml( 'rev-delundel' ); |
| 924 | + } else { |
| 925 | + $del = $this->sk->makeKnownLinkObj( $revdel, |
| 926 | + wfMsg( 'rev-delundel' ), |
| 927 | + 'target=' . urlencode( $this->mTarget ) . |
| 928 | + '&fileid=' . urlencode( $row->fa_id ) ); |
| 929 | + / Bolden oversighted content |
| 930 | + if( $this->isDeleted( $row, Image::DELETED_RESTRICTED ) ) |
| 931 | + $del = "<strong>$del</strong>"; |
| 932 | + } |
| 933 | + $rd = "<tt>(<small>$del</small>)</tt>"; |
| 934 | + } |
| 935 | + $wgOut->addHTML( "<li>$checkBox $rd $pageLink . . $userLink $data $comment</li>\n" ); |
819 | 936 | } |
820 | 937 | $files->free(); |
821 | 938 | $wgOut->addHTML( "</ul>" ); |
— | — | @@ -830,6 +947,143 @@ |
831 | 948 | return true; |
832 | 949 | } |
833 | 950 | |
| 951 | + /** |
| 952 | + * Fetch revision text link if it's available to all users |
| 953 | + * @return string |
| 954 | + */ |
| 955 | + function getPageLink( $row, $titleObj, $ts, $target ) { |
| 956 | + global $wgLang; |
| 957 | + |
| 958 | + if ( !$this->userCan($row, Revision::DELETED_TEXT) ) { |
| 959 | + return '<span class="history-deleted">' . $wgLang->timeanddate( $ts, true ) . '</span>'; |
| 960 | + } else { |
| 961 | + $link = $this->sk->makeKnownLinkObj( $titleObj, $wgLang->timeanddate( $ts, true ), "target=$target×tamp=$ts" ); |
| 962 | + if ( $this->isDeleted($row, Revision::DELETED_TEXT) ) |
| 963 | + $link = '<span class="history-deleted">' . $link . '</span>'; |
| 964 | + return $link; |
| 965 | + } |
| 966 | + } |
| 967 | + |
| 968 | + /** |
| 969 | + * Fetch image view link if it's available to all users |
| 970 | + * @return string |
| 971 | + */ |
| 972 | + function getFileLink( $row, $titleObj, $ts, $target, $key ) { |
| 973 | + global $wgLang; |
| 974 | + |
| 975 | + if ( !$this->userCan($row, Image::DELETED_FILE) ) { |
| 976 | + return '<span class="history-deleted">' . $wgLang->timeanddate( $ts, true ) . '</span>'; |
| 977 | + } else { |
| 978 | + $link = $this->sk->makeKnownLinkObj( $titleObj, $wgLang->timeanddate( $ts, true ), "target=$target&file=$key" ); |
| 979 | + if ( $this->isDeleted($row, Image::DELETED_FILE) ) |
| 980 | + $link = '<span class="history-deleted">' . $link . '</span>'; |
| 981 | + return $link; |
| 982 | + } |
| 983 | + } |
| 984 | + |
| 985 | + /** |
| 986 | + * Fetch revision's user id if it's available to this user |
| 987 | + * @return string |
| 988 | + */ |
| 989 | + function getUser( $row ) { |
| 990 | + if ( !$this->userCan($row, Revision::DELETED_USER) ) { |
| 991 | + return '<span class="history-deleted">' . wfMsgHtml( 'rev-deleted-user' ) . '</span>'; |
| 992 | + } else { |
| 993 | + $link = $this->sk->userLink( $row->ar_user, $row->ar_user_text ) . $this->sk->userToolLinks( $row->ar_user, $row->ar_user_text ); |
| 994 | + if ( $this->isDeleted($row, Revision::DELETED_USER) ) |
| 995 | + $link = '<span class="history-deleted">' . $link . '</span>'; |
| 996 | + return $link; |
| 997 | + } |
| 998 | + } |
| 999 | + |
| 1000 | + /** |
| 1001 | + * Fetch file's user id if it's available to this user |
| 1002 | + * @return string |
| 1003 | + */ |
| 1004 | + function getFileUser( $row ) { |
| 1005 | + if ( !$this->userCan($row, Image::DELETED_USER) ) { |
| 1006 | + return '<span class="history-deleted">' . wfMsgHtml( 'rev-deleted-user' ) . '</span>'; |
| 1007 | + } else { |
| 1008 | + $link = $this->sk->userLink( $row->fa_user, $row->fa_user_text ) . $this->sk->userToolLinks( $row->fa_user, $row->fa_user_text ); |
| 1009 | + if ( $this->isDeleted($row, Image::DELETED_USER) ) |
| 1010 | + $link = '<span class="history-deleted">' . $link . '</span>'; |
| 1011 | + return $link; |
| 1012 | + } |
| 1013 | + } |
| 1014 | + |
| 1015 | + /** |
| 1016 | + * Fetch revision comment if it's available to this user |
| 1017 | + * @return string |
| 1018 | + */ |
| 1019 | + function getComment( $row ) { |
| 1020 | + if ( !$this->userCan($row, Revision::DELETED_COMMENT) ) { |
| 1021 | + return '<span class="history-deleted"><span class="comment">' . wfMsgHtml( 'rev-deleted-comment' ) . '</span></span>'; |
| 1022 | + } else { |
| 1023 | + $link = $this->sk->commentBlock( $row->ar_comment ); |
| 1024 | + if ( $this->isDeleted($row, Revision::DELETED_COMMENT) ) |
| 1025 | + $link = '<span class="history-deleted">' . $link . '</span>'; |
| 1026 | + return $link; |
| 1027 | + } |
| 1028 | + } |
| 1029 | + |
| 1030 | + /** |
| 1031 | + * Fetch file upload comment if it's available to this user |
| 1032 | + * @return string |
| 1033 | + */ |
| 1034 | + function getFileComment( $row ) { |
| 1035 | + if ( !$this->userCan($row, Image::DELETED_COMMENT) ) { |
| 1036 | + return '<span class="history-deleted"><span class="comment">' . wfMsgHtml( 'rev-deleted-comment' ) . '</span></span>'; |
| 1037 | + } else { |
| 1038 | + $link = $this->sk->commentBlock( $row->fa_description ); |
| 1039 | + if ( $this->isDeleted($row, Image::DELETED_COMMENT) ) |
| 1040 | + $link = '<span class="history-deleted">' . $link . '</span>'; |
| 1041 | + return $link; |
| 1042 | + } |
| 1043 | + } |
| 1044 | + |
| 1045 | + /** |
| 1046 | + * int $field one of DELETED_* bitfield constants |
| 1047 | + * for file or revision rows |
| 1048 | + * @return bool |
| 1049 | + */ |
| 1050 | + function isDeleted( $row, $field ) { |
| 1051 | + if ( isset($row->ar_deleted) ) |
| 1052 | + / page revisions |
| 1053 | + return ($row->ar_deleted & $field) == $field; |
| 1054 | + else if ( isset($row->fa_deleted) ) |
| 1055 | + / files |
| 1056 | + return ($row->fa_deleted & $field) == $field; |
| 1057 | + return false; |
| 1058 | + } |
| 1059 | + |
| 1060 | + /** |
| 1061 | + * Determine if the current user is allowed to view a particular |
| 1062 | + * field of this revision, if it's marked as deleted. |
| 1063 | + * @param int $field |
| 1064 | + * @return bool |
| 1065 | + */ |
| 1066 | + function userCan( $row, $field ) { |
| 1067 | + global $wgUser; |
| 1068 | + |
| 1069 | + if( isset($row->ar_deleted) && ($row->ar_deleted & $field) == $field ) { |
| 1070 | + / page revisions |
| 1071 | + $permission = ( $row->ar_deleted & Revision::DELETED_RESTRICTED ) == Revision::DELETED_RESTRICTED |
| 1072 | + ? 'hiderevision' |
| 1073 | + : 'deleterevision'; |
| 1074 | + wfDebug( "Checking for $permission due to $field match on $row->ar_deleted\n" ); |
| 1075 | + return $wgUser->isAllowed( $permission ); |
| 1076 | + } else if( isset($row->fa_deleted) && ($row->fa_deleted & $field) == $field ) { |
| 1077 | + / files |
| 1078 | + $permission = ( $row->fa_deleted & Image::DELETED_RESTRICTED ) == Image::DELETED_RESTRICTED |
| 1079 | + ? 'hiderevision' |
| 1080 | + : 'deleterevision'; |
| 1081 | + wfDebug( "Checking for $permission due to $field match on $row->fa_deleted\n" ); |
| 1082 | + return $wgUser->isAllowed( $permission ); |
| 1083 | + } else { |
| 1084 | + return true; |
| 1085 | + } |
| 1086 | + } |
| 1087 | + |
834 | 1088 | function undelete() { |
835 | 1089 | global $wgOut, $wgUser; |
836 | 1090 | if( !is_null( $this->mTargetObj ) ) { |
— | — | @@ -838,16 +1092,22 @@ |
839 | 1093 | $ok = $archive->undelete( |
840 | 1094 | $this->mTargetTimestamp, |
841 | 1095 | $this->mComment, |
842 | | - $this->mFileVersions ); |
843 | | - |
| 1096 | + $this->mFileVersions, |
| 1097 | + $this->mUnsuppress ); |
844 | 1098 | if( $ok ) { |
845 | 1099 | $skin = $wgUser->getSkin(); |
846 | 1100 | $link = $skin->makeKnownLinkObj( $this->mTargetObj ); |
847 | 1101 | $wgOut->addHtml( wfMsgWikiHtml( 'undeletedpage', $link ) ); |
848 | 1102 | return true; |
849 | 1103 | } |
| 1104 | + / Give user some idea of what is going on ... |
| 1105 | + / This can happen if the top revision would end up being deleted |
| 1106 | + $wgOut->addHtml( '<p>' . wfMsgHtml( "cannotundelete" ) . '</p>' ); |
| 1107 | + $wgOut->addHtml( '<p>' . wfMsgHtml( "undeleterevdel" ) . '</p>' ); |
| 1108 | + $wgOut->returnToMain( false, $this->mTargetObj ); |
| 1109 | + return false; |
850 | 1110 | } |
851 | | - $wgOut->showFatalError( wfMsg( "cannotundelete" ) ); |
| 1111 | + $wgOut->showFatalError( wfMsgHtml( "cannotundelete" ) ); |
852 | 1112 | return false; |
853 | 1113 | } |
854 | 1114 | } |
Index: trunk/phase3/includes/DifferenceEngine.php |
— | — | @@ -174,14 +174,49 @@ |
175 | 175 | $newminor = wfElement( 'span', array( 'class' => 'minor' ), |
176 | 176 | wfMsg( 'minoreditletter') ) . ' '; |
177 | 177 | } |
| 178 | + |
| 179 | + $rdel = ''; $ldel = ''; |
| 180 | + if( $wgUser->isAllowed( 'deleterevision' ) ) { |
| 181 | + $revdel = SpecialPage::getTitleFor( 'Revisiondelete' ); |
| 182 | + if( !$this->mOldRev->userCan( Revision::DELETED_RESTRICTED ) ) { |
| 183 | + / If revision was hidden from sysops |
| 184 | + $ldel = wfMsgHtml('rev-delundel'); |
| 185 | + } else { |
| 186 | + $ldel = $sk->makeKnownLinkObj( $revdel, |
| 187 | + wfMsgHtml('rev-delundel'), |
| 188 | + 'target=' . urlencode( $this->mOldRev->mTitle->getPrefixedDbkey() ) . |
| 189 | + '&oldid=' . urlencode( $this->mOldRev->getId() ) ); |
| 190 | + / Bolden oversighted content |
| 191 | + if( $this->mOldRev->isDeleted( Revision::DELETED_RESTRICTED ) ) |
| 192 | + $ldel = "<strong>$ldel</strong>"; |
| 193 | + } |
| 194 | + $ldel = " <tt>(<small>$ldel</small>)</tt> "; |
| 195 | + / We don't currently handle well changing the top revision's settings |
| 196 | + if( $this->mNewRev->isCurrent() ) { |
| 197 | + / If revision was hidden from sysops |
| 198 | + $rdel = wfMsgHtml('rev-delundel'); |
| 199 | + } else if( !$this->mNewRev->userCan( Revision::DELETED_RESTRICTED ) ) { |
| 200 | + / If revision was hidden from sysops |
| 201 | + $rdel = wfMsgHtml('rev-delundel'); |
| 202 | + } else { |
| 203 | + $rdel = $sk->makeKnownLinkObj( $revdel, |
| 204 | + wfMsgHtml('rev-delundel'), |
| 205 | + 'target=' . urlencode( $this->mNewRev->mTitle->getPrefixedDbkey() ) . |
| 206 | + '&oldid=' . urlencode( $this->mNewRev->getId() ) ); |
| 207 | + / Bolden oversighted content |
| 208 | + if( $this->mNewRev->isDeleted( Revision::DELETED_RESTRICTED ) ) |
| 209 | + $rdel = "<strong>$rdel</strong>"; |
| 210 | + } |
| 211 | + $rdel = " <tt>(<small>$rdel</small>)</tt> "; |
| 212 | + } |
178 | 213 | |
179 | 214 | $oldHeader = "<strong>{$this->mOldtitle}</strong><br />" . |
180 | | - $sk->revUserTools( $this->mOldRev ) . "<br />" . |
181 | | - $oldminor . $sk->revComment( $this->mOldRev, !$diffOnly ) . "<br />" . |
| 215 | + $sk->revUserTools( $this->mOldRev, true ) . "<br />" . |
| 216 | + $oldminor . $sk->revComment( $this->mOldRev, !$diffOnly, true ) . "$ldel<br />" . |
182 | 217 | $prevlink; |
183 | 218 | $newHeader = "<strong>{$this->mNewtitle}</strong><br />" . |
184 | | - $sk->revUserTools( $this->mNewRev ) . " $rollback<br />" . |
185 | | - $newminor . $sk->revComment( $this->mNewRev, !$diffOnly ) . "<br />" . |
| 219 | + $sk->revUserTools( $this->mNewRev, true ) . " $rollback<br />" . |
| 220 | + $newminor . $sk->revComment( $this->mNewRev, !$diffOnly, true ) . "$rdel<br />" . |
186 | 221 | $nextlink . $patrol; |
187 | 222 | |
188 | 223 | $this->showDiff( $oldHeader, $newHeader ); |
— | — | @@ -202,8 +237,10 @@ |
203 | 238 | |
204 | 239 | $wgOut->addHTML( "<hr /><h2>{$this->mPagetitle}</h2>\n" ); |
205 | 240 | #add deleted rev tag if needed |
206 | | - if ( !$this->mNewRev->userCan(Revision::DELETED_TEXT) ) { |
| 241 | + if( !$this->mNewRev->userCan(Revision::DELETED_TEXT) ) { |
207 | 242 | $wgOut->addWikiText( wfMsg( 'rev-deleted-text-permission' ) ); |
| 243 | + } else if( $this->mNewRev->isDeleted(Revision::DELETED_TEXT) ) { |
| 244 | + $wgOut->addWikiText( wfMsg( 'rev-deleted-text-view' ) ); |
208 | 245 | } |
209 | 246 | |
210 | 247 | if( !$this->mNewRev->isCurrent() ) { |
— | — | @@ -332,20 +369,25 @@ |
333 | 370 | } |
334 | 371 | } |
335 | 372 | |
336 | | - #loadtext is permission safe, this just clears out the diff |
| 373 | + / Loadtext is permission safe, this just clears out the diff |
337 | 374 | if ( !$this->loadText() ) { |
338 | 375 | wfProfileOut( $fname ); |
339 | 376 | return false; |
340 | 377 | } else if ( $this->mOldRev && !$this->mOldRev->userCan(Revision::DELETED_TEXT) ) { |
341 | | - return ''; |
| 378 | + return ''; |
342 | 379 | } else if ( $this->mNewRev && !$this->mNewRev->userCan(Revision::DELETED_TEXT) ) { |
343 | | - return ''; |
| 380 | + return ''; |
344 | 381 | } |
345 | 382 | |
346 | 383 | $difftext = $this->generateDiffBody( $this->mOldtext, $this->mNewtext ); |
347 | 384 | |
348 | 385 | / Save to cache for 7 days |
349 | | - if ( $key !== false && $difftext !== false ) { |
| 386 | + / Only do this for public revs, otherwise an admin can view the diff and a non-admin can nab it! |
| 387 | + if ( $this->mOldRev && $this->mOldRev->isDeleted(Revision::DELETED_TEXT) ) { |
| 388 | + wfIncrStats( 'diff_uncacheable' ); |
| 389 | + } else if ( $this->mNewRev && $this->mNewRev->isDeleted(Revision::DELETED_TEXT) ) { |
| 390 | + wfIncrStats( 'diff_uncacheable' ); |
| 391 | + } else if ( $key !== false && $difftext !== false ) { |
350 | 392 | wfIncrStats( 'diff_cache_miss' ); |
351 | 393 | $wgMemc->set( $key, $difftext, 7*86400 ); |
352 | 394 | } else { |
— | — | @@ -479,13 +521,7 @@ |
480 | 522 | */ |
481 | 523 | function addHeader( $diff, $otitle, $ntitle, $multi = '' ) { |
482 | 524 | global $wgOut; |
483 | | - |
484 | | - if ( $this->mOldRev && $this->mOldRev->isDeleted(Revision::DELETED_TEXT) ) { |
485 | | - $otitle = '<span class="history-deleted">'.$otitle.'</span>'; |
486 | | - } |
487 | | - if ( $this->mNewRev && $this->mNewRev->isDeleted(Revision::DELETED_TEXT) ) { |
488 | | - $ntitle = '<span class="history-deleted">'.$ntitle.'</span>'; |
489 | | - } |
| 525 | + |
490 | 526 | $header = " |
491 | 527 | <table border='0' width='98%' cellpadding='0' cellspacing='4' class='diff'> |
492 | 528 | <tr> |
— | — | @@ -558,6 +594,11 @@ |
559 | 595 | $this->mNewtitle = "<a href='$newLink'>{$this->mPagetitle}</a>" |
560 | 596 | . " (<a href='$newEdit'>" . htmlspecialchars( wfMsg( 'editold' ) ) . "</a>)"; |
561 | 597 | } |
| 598 | + if ( !$this->mNewRev->userCan(Revision::DELETED_TEXT) ) { |
| 599 | + $this->mNewtitle = "<span class='history-deleted'>{$this->mPagetitle}</span>"; |
| 600 | + } else if ( $this->mNewRev->isDeleted(Revision::DELETED_TEXT) ) { |
| 601 | + $this->mNewtitle = '<span class="history-deleted">'.$this->mNewtitle.'</span>'; |
| 602 | + } |
562 | 603 | |
563 | 604 | / Load the old revision object |
564 | 605 | $this->mOldRev = false; |
— | — | @@ -585,11 +626,20 @@ |
586 | 627 | $t = $wgLang->timeanddate( $this->mOldRev->getTimestamp(), true ); |
587 | 628 | $oldLink = $this->mOldPage->escapeLocalUrl( 'oldid=' . $this->mOldid ); |
588 | 629 | $oldEdit = $this->mOldPage->escapeLocalUrl( 'action=edit&oldid=' . $this->mOldid ); |
589 | | - $this->mOldtitle = "<a href='$oldLink'>" . htmlspecialchars( wfMsg( 'revisionasof', $t ) ) |
590 | | - . "</a> (<a href='$oldEdit'>" . htmlspecialchars( wfMsg( 'editold' ) ) . "</a>)"; |
591 | | - /now that we considered old rev, we can make undo link (bug 8133, multi-edit undo) |
| 630 | + $this->mOldPagetitle = htmlspecialchars( wfMsg( 'revisionasof', $t ) ); |
| 631 | + |
| 632 | + $this->mOldtitle = "<a href='$oldLink'>{$this->mOldPagetitle}</a>" |
| 633 | + . "(<a href='$oldEdit'>" . htmlspecialchars( wfMsg( 'editold' ) ) . "</a>)"; |
| 634 | + / Now that we considered old rev, we can make undo link (bug 8133, multi-edit undo) |
592 | 635 | $newUndo = $this->mNewPage->escapeLocalUrl( 'action=edit&undoafter=' . $this->mOldid . '&undoto=' . $this->mNewid); |
593 | | - $this->mNewtitle .= " (<a href='$newUndo'>" . htmlspecialchars( wfMsg( 'editundo' ) ) . "</a>)"; |
| 636 | + if ( $this->mNewRev->userCan(Revision::DELETED_TEXT) ) |
| 637 | + $this->mNewtitle .= " (<a href='$newUndo'>" . htmlspecialchars( wfMsg( 'editundo' ) ) . "</a>)"; |
| 638 | + |
| 639 | + if ( !$this->mOldRev->userCan(Revision::DELETED_TEXT) ) { |
| 640 | + $this->mOldtitle = "<span class='history-deleted'>{$this->mOldPagetitle}</span>"; |
| 641 | + } else if ( $this->mOldRev->isDeleted(Revision::DELETED_TEXT) ) { |
| 642 | + $this->mOldtitle = '<span class="history-deleted">'.$this->mOldtitle.'</span>'; |
| 643 | + } |
594 | 644 | } |
595 | 645 | |
596 | 646 | return true; |
— | — | @@ -610,7 +660,6 @@ |
611 | 661 | return false; |
612 | 662 | } |
613 | 663 | if ( $this->mOldRev ) { |
614 | | - / FIXME: permission tests |
615 | 664 | $this->mOldtext = $this->mOldRev->revText(); |
616 | 665 | if ( $this->mOldtext === false ) { |
617 | 666 | return false; |
Index: trunk/phase3/includes/SpecialLog.php |
— | — | @@ -72,16 +72,70 @@ |
73 | 73 | |
74 | 74 | list( $this->limit, $this->offset ) = $request->getLimitOffset(); |
75 | 75 | } |
| 76 | + |
| 77 | + function newFromTitle( $title, $logid=0 ) { |
| 78 | + $fname = 'LogReader::newFromTitle'; |
76 | 79 | |
| 80 | + $matchId = intval( $logid ); |
| 81 | + $dbr = wfGetDB( DB_SLAVE ); |
| 82 | + $res = $dbr->select( 'logging', array('*'), |
| 83 | + array('log_id' => $matchId, 'log_namespace' => $title->getNamespace(), 'log_title' => $title->getDBkey() ), |
| 84 | + $fname ); |
| 85 | + |
| 86 | + if ( $res ) { |
| 87 | + $ret = $dbr->fetchObject( $res ); |
| 88 | + if ( $ret ) { |
| 89 | + return $ret; |
| 90 | + } |
| 91 | + } |
| 92 | + return null; |
| 93 | + } |
| 94 | + |
| 95 | + function newFromId( $logid ) { |
| 96 | + $fname = 'LogReader::newFromId'; |
| 97 | + |
| 98 | + $matchId = intval( $logid ); |
| 99 | + $dbr = wfGetDB( DB_SLAVE ); |
| 100 | + $res = $dbr->select( 'logging', array('*'), array('log_id' => $matchId ), $fname ); |
| 101 | + |
| 102 | + if ( $res ) { |
| 103 | + $ret = $dbr->fetchObject( $res ); |
| 104 | + if ( $ret ) { |
| 105 | + return $ret; |
| 106 | + } |
| 107 | + } |
| 108 | + return null; |
| 109 | + } |
| 110 | + |
77 | 111 | /** |
78 | 112 | * Set the log reader to return only entries of the given type. |
| 113 | + * Type restrictions enforced here |
79 | 114 | * @param string $type A log type ('upload', 'delete', etc) |
80 | 115 | * @private |
81 | 116 | */ |
82 | 117 | function limitType( $type ) { |
| 118 | + global $wgLogRestrictions, $wgUser; |
| 119 | + |
| 120 | + / Restriction system |
| 121 | + if ( isset($wgLogRestrictions) ) { |
| 122 | + foreach ( $wgLogRestrictions as $logtype => $right ) { |
| 123 | + if ( !$wgUser->isAllowed( $right ) ) { |
| 124 | + $safetype = $this->db->strencode( $logtype ); |
| 125 | + $this->whereClauses[] = "log_type <> '$safetype'"; |
| 126 | + } |
| 127 | + } |
| 128 | + } |
| 129 | + |
83 | 130 | if( empty( $type ) ) { |
84 | 131 | return false; |
85 | 132 | } |
| 133 | + / Can user see this log? |
| 134 | + if ( isset($wgLogRestrictions[$type]) ) { |
| 135 | + if ( !$wgUser->isAllowed( $wgLogRestrictions[$type] ) ) { |
| 136 | + return false; |
| 137 | + } |
| 138 | + } |
| 139 | + |
86 | 140 | $this->type = $type; |
87 | 141 | $safetype = $this->db->strencode( $type ); |
88 | 142 | $this->whereClauses[] = "log_type='$safetype'"; |
— | — | @@ -117,7 +171,7 @@ |
118 | 172 | * @private |
119 | 173 | */ |
120 | 174 | function limitTitle( $page , $pattern ) { |
121 | | - $title = Title::newFromText( $page ); |
| 175 | + $title = Title::newFromURL( $page, false ); |
122 | 176 | if( empty( $page ) || is_null( $title ) ) { |
123 | 177 | return false; |
124 | 178 | } |
— | — | @@ -157,6 +211,7 @@ |
158 | 212 | $logging = $this->db->tableName( "logging" ); |
159 | 213 | $sql = "SELECT /*! STRAIGHT_JOIN */ log_type, log_action, log_timestamp, |
160 | 214 | log_user, user_name, |
| 215 | + log_id, log_deleted, |
161 | 216 | log_namespace, log_title, page_id, |
162 | 217 | log_comment, log_params FROM $logging "; |
163 | 218 | if( !empty( $this->joinClauses ) ) { |
— | — | @@ -217,6 +272,11 @@ |
218 | 273 | * @addtogroup SpecialPage |
219 | 274 | */ |
220 | 275 | class LogViewer { |
| 276 | + const DELETED_ACTION = 1; |
| 277 | + const DELETED_COMMENT = 2; |
| 278 | + const DELETED_USER = 4; |
| 279 | + const DELETED_RESTRICTED = 8; |
| 280 | + |
221 | 281 | /** |
222 | 282 | * @var LogReader $reader |
223 | 283 | */ |
— | — | @@ -230,7 +290,21 @@ |
231 | 291 | global $wgUser; |
232 | 292 | $this->skin = $wgUser->getSkin(); |
233 | 293 | $this->reader =& $reader; |
| 294 | + $this->preCacheMessages(); |
234 | 295 | } |
| 296 | + |
| 297 | + /** |
| 298 | + * As we use the same small set of messages in various methods and that |
| 299 | + * they are called often, we call them once and save them in $this->message |
| 300 | + */ |
| 301 | + function preCacheMessages() { |
| 302 | + / Precache various messages |
| 303 | + if( !isset( $this->message ) ) { |
| 304 | + foreach( explode(' ', 'viewpagelogs revhistory imghistory rev-delundel' ) as $msg ) { |
| 305 | + $this->message[$msg] = wfMsgExt( $msg, array( 'escape') ); |
| 306 | + } |
| 307 | + } |
| 308 | + } |
235 | 309 | |
236 | 310 | /** |
237 | 311 | * Take over the whole output page in $wgOut with the log display. |
— | — | @@ -248,8 +322,125 @@ |
249 | 323 | $this->showError( $wgOut ); |
250 | 324 | } |
251 | 325 | } |
| 326 | + |
| 327 | + /** |
| 328 | + * Determine if the current user is allowed to view a particular |
| 329 | + * field of this event, if it's marked as deleted. |
| 330 | + * @param int $field |
| 331 | + * @return bool |
| 332 | + */ |
| 333 | + function userCan( $event, $field ) { |
| 334 | + if( ( $event->log_deleted & $field ) == $field ) { |
| 335 | + global $wgUser; |
| 336 | + $permission = ( $event->log_deleted & Revision::DELETED_RESTRICTED ) == Revision::DELETED_RESTRICTED |
| 337 | + ? 'hiderevision' |
| 338 | + : 'deleterevision'; |
| 339 | + wfDebug( "Checking for $permission due to $field match on $event->log_deleted\n" ); |
| 340 | + return $wgUser->isAllowed( $permission ); |
| 341 | + } else { |
| 342 | + return true; |
| 343 | + } |
| 344 | + } |
| 345 | + |
| 346 | + /** |
| 347 | + * int $field one of DELETED_* bitfield constants |
| 348 | + * @return bool |
| 349 | + */ |
| 350 | + function isDeleted( $event, $field ) { |
| 351 | + return ($event->log_deleted & $field) == $field; |
| 352 | + } |
| 353 | + |
| 354 | + /** |
| 355 | + * Fetch event's user id if it's available to all users |
| 356 | + * @return int |
| 357 | + */ |
| 358 | + function getUser( $event ) { |
| 359 | + if( $this->isDeleted( $event, Revision::DELETED_USER ) ) { |
| 360 | + return 0; |
| 361 | + } else { |
| 362 | + return $event->log_user; |
| 363 | + } |
| 364 | + } |
252 | 365 | |
253 | 366 | /** |
| 367 | + * Fetch event's user id without regard for the current user's permissions |
| 368 | + * @return string |
| 369 | + */ |
| 370 | + function getRawUser( $event ) { |
| 371 | + return $event->log_user; |
| 372 | + } |
| 373 | + |
| 374 | + /** |
| 375 | + * Fetch event's username if it's available to all users |
| 376 | + * @return string |
| 377 | + */ |
| 378 | + function getUserText( $event ) { |
| 379 | + if( $this->isDeleted( $event, Revision::DELETED_USER ) ) { |
| 380 | + return ""; |
| 381 | + } else { |
| 382 | + if ( isset($event->user_name) ) { |
| 383 | + return $event->user_name; |
| 384 | + } else { |
| 385 | + return User::whoIs( $event->log_user ); |
| 386 | + } |
| 387 | + } |
| 388 | + } |
| 389 | + |
| 390 | + /** |
| 391 | + * Fetch event's username without regard for view restrictions |
| 392 | + * @return string |
| 393 | + */ |
| 394 | + function getRawUserText( $event ) { |
| 395 | + if ( isset($event->user_name) ) { |
| 396 | + return $event->user_name; |
| 397 | + } else { |
| 398 | + return User::whoIs( $event->log_user ); |
| 399 | + } |
| 400 | + } |
| 401 | + |
| 402 | + /** |
| 403 | + * Fetch event comment if it's available to all users |
| 404 | + * @return string |
| 405 | + */ |
| 406 | + function getComment( $event ) { |
| 407 | + if( $this->isDeleted( $event, Revision::DELETED_COMMENT ) ) { |
| 408 | + return ""; |
| 409 | + } else { |
| 410 | + return $event->log_comment; |
| 411 | + } |
| 412 | + } |
| 413 | + |
| 414 | + /** |
| 415 | + * Fetch event comment without regard for the current user's permissions |
| 416 | + * @return string |
| 417 | + */ |
| 418 | + function getRawComment( $event ) { |
| 419 | + return $event->log_comment; |
| 420 | + } |
| 421 | + |
| 422 | + /** |
| 423 | + * Returns the title of the page associated with this entry. |
| 424 | + * @return Title |
| 425 | + */ |
| 426 | + function getTitle( $event ) { |
| 427 | + return Title::makeTitle( $event->log_namespace, $event->log_title ); |
| 428 | + } |
| 429 | + |
| 430 | + /** |
| 431 | + * Return the log action if it's available to all users |
| 432 | + * default is deleted if not specified for security |
| 433 | + * @return Title |
| 434 | + */ |
| 435 | + function logActionText( $log_type, $log_action, $title, $skin, $paramArray, $log_deleted = LogViewer::DELETED_ACTION ) { |
| 436 | + if( $log_deleted & LogViewer::DELETED_ACTION ) { |
| 437 | + return '<span class="history-deleted">' . wfMsgHtml('rev-deleted-event') . '</span>'; |
| 438 | + } else { |
| 439 | + $action = LogPage::actionText( $log_type, $log_action, $title, $this->skin, $paramArray, true, true ); |
| 440 | + return $action; |
| 441 | + } |
| 442 | + } |
| 443 | + |
| 444 | + /** |
254 | 445 | * Load the data from the linked LogReader |
255 | 446 | * Preload the link cache |
256 | 447 | * Initialise numResults |
— | — | @@ -319,7 +510,8 @@ |
320 | 511 | * @private |
321 | 512 | */ |
322 | 513 | function logLine( $s ) { |
323 | | - global $wgLang, $wgUser;; |
| 514 | + global $wgLang, $wgUser; |
| 515 | + |
324 | 516 | $skin = $wgUser->getSkin(); |
325 | 517 | $title = Title::makeTitle( $s->log_namespace, $s->log_title ); |
326 | 518 | $time = $wgLang->timeanddate( wfTimestamp(TS_MW, $s->log_timestamp), true ); |
— | — | @@ -332,12 +524,64 @@ |
333 | 525 | } else { |
334 | 526 | $linkCache->addBadLinkObj( $title ); |
335 | 527 | } |
| 528 | + / User links |
| 529 | + $userLink = $this->skin->logUserTools( $s, true ); |
| 530 | + / Comment |
| 531 | + $comment = $this->skin->logComment( $s, true ); |
336 | 532 | |
337 | | - $userLink = $this->skin->userLink( $s->log_user, $s->user_name ) . $this->skin->userToolLinksRedContribs( $s->log_user, $s->user_name ); |
338 | | - $comment = $this->skin->commentBlock( $s->log_comment ); |
339 | 533 | $paramArray = LogPage::extractParams( $s->log_params ); |
340 | | - $revert = ''; |
341 | | - / show revertmove link |
| 534 | + $revert = ''; $del = ''; |
| 535 | + |
| 536 | + / Some user can hide log items and have review links |
| 537 | + if( $wgUser->isAllowed( 'deleterevision' ) ) { |
| 538 | + $del = $this->showhideLinks( $s, $title ); |
| 539 | + } |
| 540 | + |
| 541 | + / Show restore/unprotect/unblock |
| 542 | + $revert = $this->showReviewLinks( $s, $title, $paramArray ); |
| 543 | + |
| 544 | + / Event description |
| 545 | + $action = $this->logActionText( $s->log_type, $s->log_action, $title, $this->skin, $paramArray, $s->log_deleted ); |
| 546 | + |
| 547 | + $out = "<li><tt>$del</tt> $time $userLink $action $comment <small>$revert</small></li>\n"; |
| 548 | + return $out; |
| 549 | + } |
| 550 | + |
| 551 | + /** |
| 552 | + * @param $s, row object |
| 553 | + * @param $s, title object |
| 554 | + * @private |
| 555 | + */ |
| 556 | + function showhideLinks( $s, $title ) { |
| 557 | + $revdel = SpecialPage::getTitleFor( 'Revisiondelete' ); |
| 558 | + if( !LogViewer::userCan( $s, Revision::DELETED_RESTRICTED ) ) { |
| 559 | + / If event was hidden from sysops |
| 560 | + $del = $this->message['rev-delundel']; |
| 561 | + } else if( $s->log_type == 'oversight' ) { |
| 562 | + / No one should be hiding from the oversight log |
| 563 | + $del = $this->message['rev-delundel']; |
| 564 | + } else { |
| 565 | + $del = $this->skin->makeKnownLinkObj( $revdel, |
| 566 | + $this->message['rev-delundel'], |
| 567 | + 'target=' . urlencode( $title->getPrefixedDbkey() ) . '&logid=' . $s->log_id ); |
| 568 | + / Bolden oversighted content |
| 569 | + if( LogViewer::isDeleted( $s, Revision::DELETED_RESTRICTED ) ) |
| 570 | + $del = "<strong>$del</strong>"; |
| 571 | + } |
| 572 | + return "(<small>$del</small>)"; |
| 573 | + } |
| 574 | + |
| 575 | + /** |
| 576 | + * @param $s, row object |
| 577 | + * @param $title, title object |
| 578 | + * @param $s, param array |
| 579 | + * @private |
| 580 | + */ |
| 581 | + function showReviewLinks( $s, $title, $paramArray ) { |
| 582 | + global $wgUser; |
| 583 | + |
| 584 | + $reviewlink=''; |
| 585 | + / Show revertmove link |
342 | 586 | if ( $s->log_type == 'move' && isset( $paramArray[0] ) ) { |
343 | 587 | $destTitle = Title::newFromText( $paramArray[0] ); |
344 | 588 | if ( $destTitle ) { |
— | — | @@ -349,26 +593,47 @@ |
350 | 594 | '&wpMovetalk=0' ) . ')'; |
351 | 595 | } |
352 | 596 | / show undelete link |
353 | | - } elseif ( $s->log_action == 'delete' && $wgUser->isAllowed( 'delete' ) ) { |
354 | | - $revert = '(' . $this->skin->makeKnownLinkObj( SpecialPage::getTitleFor( 'Undelete' ), |
| 597 | + } else if ( $s->log_action == 'delete' && $wgUser->isAllowed( 'delete' ) ) { |
| 598 | + $reviewlink = $this->skin->makeKnownLinkObj( SpecialPage::getTitleFor( 'Undelete' ), |
355 | 599 | wfMsg( 'undeletebtn' ) , |
356 | | - 'target='. urlencode( $title->getPrefixedDBkey() ) ) . ')'; |
357 | | - |
| 600 | + 'target='. urlencode( $title->getPrefixedDBkey() ) ); |
358 | 601 | / show unblock link |
359 | 602 | } elseif ( $s->log_action == 'block' && $wgUser->isAllowed( 'block' ) ) { |
360 | | - $revert = '(' . $skin->makeKnownLinkObj( SpecialPage::getTitleFor( 'Ipblocklist' ), |
| 603 | + $reviewlink = $this->skin->makeKnownLinkObj( SpecialPage::getTitleFor( 'Ipblocklist' ), |
361 | 604 | wfMsg( 'unblocklink' ), |
362 | | - 'action=unblock&ip=' . urlencode( $s->log_title ) ) . ')'; |
| 605 | + 'action=unblock&ip=' . urlencode( $s->log_title ) ); |
363 | 606 | / show change protection link |
364 | 607 | } elseif ( $s->log_action == 'protect' && $wgUser->isAllowed( 'protect' ) ) { |
365 | | - $revert = '(' . $skin->makeKnownLink( $title->getPrefixedDBkey() , |
| 608 | + $reviewlink = $this->skin->makeKnownLink( $title->getPrefixedDBkey() , |
366 | 609 | wfMsg( 'protect_change' ), |
367 | | - 'action=unprotect' ) . ')'; |
| 610 | + 'action=unprotect' ); |
368 | 611 | } |
369 | | - |
370 | | - $action = LogPage::actionText( $s->log_type, $s->log_action, $title, $this->skin, $paramArray, true, true ); |
371 | | - $out = "<li>$time $userLink $action $comment $revert</li>\n"; |
372 | | - return $out; |
| 612 | + / If an edit was hidden from a page give a review link to the history |
| 613 | + if ( $wgUser->isAllowed( 'deleterevision' ) && isset($paramArray[2]) ) { |
| 614 | + $revdel = SpecialPage::getTitleFor( 'Revisiondelete' ); |
| 615 | + if ( $s->log_action == 'revision' ) { |
| 616 | + $reviewlink = $this->skin->makeKnownLinkObj( $title, $this->message['revhistory'], |
| 617 | + wfArrayToCGI( array('action' => 'history' ) ) ) . ':'; |
| 618 | + } else if ( $s->log_action == 'file' ) { |
| 619 | + / Currently, only deleted file versions can be hidden |
| 620 | + $undelete = SpecialPage::getTitleFor( 'Undelete' ); |
| 621 | + $reviewlink = $this->skin->makeKnownLinkObj( $undelete, $this->message['imghistory'], |
| 622 | + wfArrayToCGI( array('target' => $title->getPrefixedText() ) ) ) . ':'; |
| 623 | + } else if ( $s->log_action == 'event' && isset($paramArray[0]) ) { |
| 624 | + / If this event was to a log, give a review link to logs for that page only |
| 625 | + $reviewlink = $this->skin->makeKnownLinkObj( $title, $this->message['viewpagelogs'], |
| 626 | + wfArrayToCGI( array('page' => $paramArray[0] ) ) ) . ':'; |
| 627 | + } |
| 628 | + / Link to each hidden object ID |
| 629 | + $IdType = $paramArray[1].'id'; |
| 630 | + $Ids = explode( ',', $paramArray[2] ); |
| 631 | + foreach ( $Ids as $id ) { |
| 632 | + $reviewlink .= ' '.$this->skin->makeKnownLinkObj( $revdel, "#$id", |
| 633 | + wfArrayToCGI( array('target' => $paramArray[0], $IdType => $id ) ) ); |
| 634 | + } |
| 635 | + } |
| 636 | + $reviewlink = ( $reviewlink=='' ) ? "" : " ($reviewlink) "; |
| 637 | + return $reviewlink; |
373 | 638 | } |
374 | 639 | |
375 | 640 | /** |
— | — | @@ -409,6 +674,8 @@ |
410 | 675 | * @private |
411 | 676 | */ |
412 | 677 | function getTypeMenu() { |
| 678 | + global $wgLogRestrictions, $wgUser; |
| 679 | + |
413 | 680 | $out = "<select name='type'>\n"; |
414 | 681 | |
415 | 682 | $validTypes = LogPage::validTypes(); |
— | — | @@ -426,7 +693,14 @@ |
427 | 694 | / Third pass generates sorted XHTML content |
428 | 695 | foreach( $m as $text => $type ) { |
429 | 696 | $selected = ($type == $this->reader->queryType()); |
| 697 | + / Restricted types |
| 698 | + if ( isset($wgLogRestrictions[$type]) ) { |
| 699 | + if ( $wgUser->isAllowed( $wgLogRestrictions[$type] ) ) { |
| 700 | + $out .= Xml::option( $text, $type, $selected ) . "\n"; |
| 701 | + } |
| 702 | + } else { |
430 | 703 | $out .= Xml::option( $text, $type, $selected ) . "\n"; |
| 704 | + } |
431 | 705 | } |
432 | 706 | |
433 | 707 | $out .= '</select>'; |
— | — | @@ -484,5 +758,12 @@ |
485 | 759 | } |
486 | 760 | } |
487 | 761 | |
| 762 | +/** |
| 763 | + * Aliases for backwards compatibility with 1.6 |
| 764 | + */ |
| 765 | +define( 'MW_LOG_DELETED_ACTION', LogViewer::DELETED_ACTION ); |
| 766 | +define( 'MW_LOG_DELETED_USER', LogViewer::DELETED_USER ); |
| 767 | +define( 'MW_LOG_DELETED_COMMENT', LogViewer::DELETED_COMMENT ); |
| 768 | +define( 'MW_LOG_DELETED_RESTRICTED', LogViewer::DELETED_RESTRICTED ); |
488 | 769 | |
489 | 770 | ?> |
Index: trunk/phase3/includes/DefaultSettings.php |
— | — | @@ -169,7 +169,7 @@ |
170 | 170 | * is writable to the web server but is not exposed to the internet. |
171 | 171 | * |
172 | 172 | * Set $wgSaveDeletedFiles to true and set up the save path in |
173 | | - * $wgFileStore['deleted']['directory']. |
| 173 | + * $wgFileStore['deleted']['directory'] |
174 | 174 | */ |
175 | 175 | $wgSaveDeletedFiles = false; |
176 | 176 | |
— | — | @@ -983,6 +983,7 @@ |
984 | 984 | $wgGroupPermissions['sysop']['block'] = true; |
985 | 985 | $wgGroupPermissions['sysop']['createaccount'] = true; |
986 | 986 | $wgGroupPermissions['sysop']['delete'] = true; |
| 987 | +$wgGroupPermissions['sysop']['browsearchive'] = true; / can see the deleted page list |
987 | 988 | $wgGroupPermissions['sysop']['deletedhistory'] = true; / can view deleted history entries, but not see or restore the text |
988 | 989 | $wgGroupPermissions['sysop']['editinterface'] = true; |
989 | 990 | $wgGroupPermissions['sysop']['import'] = true; |
— | — | @@ -1005,9 +1006,17 @@ |
1006 | 1007 | / Permission to change users' group assignments |
1007 | 1008 | $wgGroupPermissions['bureaucrat']['userrights'] = true; |
1008 | 1009 | |
1009 | | -/ Experimental permissions, not ready for production use |
| 1010 | +/ Experimental permissions to enable revisiondelete: |
| 1011 | + |
1010 | 1012 | /$wgGroupPermissions['sysop']['deleterevision'] = true; |
| 1013 | +/$wgGroupPermissions['sysop']['hideuser'] = true; |
| 1014 | +/ To see hidden revs |
1011 | 1015 | /$wgGroupPermissions['bureaucrat']['hiderevision'] = true; |
| 1016 | +/ For private log access |
| 1017 | +/$wgGroupPermissions['bureaucrat']['oversight'] = true; |
| 1018 | +/ Also, we may want titles to be effectively hidden |
| 1019 | +/$wgGroupPermissions['sysop']['browsearchive'] = false; |
| 1020 | +/$wgGroupPermissions['bureaucrat']['browsearchive'] = true; |
1012 | 1021 | |
1013 | 1022 | /** |
1014 | 1023 | * The developer group is deprecated, but can be activated if need be |
— | — | @@ -2023,9 +2032,20 @@ |
2024 | 2033 | 'move', |
2025 | 2034 | 'import', |
2026 | 2035 | 'patrol', |
| 2036 | + 'oversight', |
2027 | 2037 | ); |
2028 | 2038 | |
2029 | 2039 | /** |
| 2040 | + * This restricts log access to those who have a certain right |
| 2041 | + * Users without this will not see it in the option menu and can not view it |
| 2042 | + * Restricted logs are not added to recent changes |
| 2043 | + * Logs should remain non-transcludable |
| 2044 | + */ |
| 2045 | +$wgLogRestrictions = array( |
| 2046 | +'oversight' => 'oversight' |
| 2047 | +); |
| 2048 | + |
| 2049 | +/** |
2030 | 2050 | * Lists the message key string for each log type. The localized messages |
2031 | 2051 | * will be listed in the user interface. |
2032 | 2052 | * |
— | — | @@ -2041,6 +2061,7 @@ |
2042 | 2062 | 'move' => 'movelogpage', |
2043 | 2063 | 'import' => 'importlogpage', |
2044 | 2064 | 'patrol' => 'patrol-log-page', |
| 2065 | + 'oversight' => 'oversightlog', |
2045 | 2066 | ); |
2046 | 2067 | |
2047 | 2068 | /** |
— | — | @@ -2059,6 +2080,7 @@ |
2060 | 2081 | 'move' => 'movelogpagetext', |
2061 | 2082 | 'import' => 'importlogpagetext', |
2062 | 2083 | 'patrol' => 'patrol-log-header', |
| 2084 | + 'oversight' => 'overlogpagetext', |
2063 | 2085 | ); |
2064 | 2086 | |
2065 | 2087 | /** |
— | — | @@ -2076,12 +2098,18 @@ |
2077 | 2099 | 'delete/delete' => 'deletedarticle', |
2078 | 2100 | 'delete/restore' => 'undeletedarticle', |
2079 | 2101 | 'delete/revision' => 'revdelete-logentry', |
| 2102 | + 'delete/event' => 'logdelete-logentry', |
2080 | 2103 | 'upload/upload' => 'uploadedimage', |
2081 | 2104 | 'upload/revert' => 'uploadedimage', |
2082 | 2105 | 'move/move' => '1movedto2', |
2083 | 2106 | 'move/move_redir' => '1movedto2_redir', |
2084 | 2107 | 'import/upload' => 'import-logentry-upload', |
2085 | 2108 | 'import/interwiki' => 'import-logentry-interwiki', |
| 2109 | + 'oversight/revision' => 'revdelete-logentry', |
| 2110 | + 'oversight/file' => 'revdelete-logentry', |
| 2111 | + 'oversight/event' => 'logdelete-logentry', |
| 2112 | + 'oversight/delete' => 'deletedarticle', |
| 2113 | + 'oversight/block' => 'blocklogentry', |
2086 | 2114 | ); |
2087 | 2115 | |
2088 | 2116 | /** |
Index: trunk/phase3/includes/PageHistory.php |
— | — | @@ -38,7 +38,21 @@ |
39 | 39 | $this->mTitle =& $article->mTitle; |
40 | 40 | $this->mNotificationTimestamp = NULL; |
41 | 41 | $this->mSkin = $wgUser->getSkin(); |
| 42 | + $this->preCacheMessages(); |
42 | 43 | } |
| 44 | + |
| 45 | + /** |
| 46 | + * As we use the same small set of messages in various methods and that |
| 47 | + * they are called often, we call them once and save them in $this->message |
| 48 | + */ |
| 49 | + function preCacheMessages() { |
| 50 | + / Precache various messages |
| 51 | + if( !isset( $this->message ) ) { |
| 52 | + foreach( explode(' ', 'cur last rev-delundel' ) as $msg ) { |
| 53 | + $this->message[$msg] = wfMsgExt( $msg, array( 'escape') ); |
| 54 | + } |
| 55 | + } |
| 56 | + } |
43 | 57 | |
44 | 58 | /** |
45 | 59 | * Print the history page for an article. |
— | — | @@ -187,35 +201,31 @@ |
188 | 202 | $arbitrary = $this->diffButtons( $rev, $firstInList, $counter ); |
189 | 203 | $link = $this->revLink( $rev ); |
190 | 204 | |
191 | | - $user = $this->mSkin->userLink( $rev->getUser(), $rev->getUserText() ) |
192 | | - . $this->mSkin->userToolLinks( $rev->getUser(), $rev->getUserText() ); |
193 | | - |
194 | 205 | $s .= "($curlink) ($lastlink) $arbitrary"; |
195 | 206 | |
196 | 207 | if( $wgUser->isAllowed( 'deleterevision' ) ) { |
197 | 208 | $revdel = SpecialPage::getTitleFor( 'Revisiondelete' ); |
198 | 209 | if( $firstInList ) { |
199 | | - / We don't currently handle well changing the top revision's settings |
200 | | - $del = wfMsgHtml( 'rev-delundel' ); |
| 210 | + / We don't currently handle well changing the top revision's settings |
| 211 | + $del = $this->message['rev-delundel']; |
201 | 212 | } else if( !$rev->userCan( Revision::DELETED_RESTRICTED ) ) { |
202 | 213 | / If revision was hidden from sysops |
203 | | - $del = wfMsgHtml( 'rev-delundel' ); |
| 214 | + $del = $this->message['rev-delundel']; |
204 | 215 | } else { |
205 | 216 | $del = $this->mSkin->makeKnownLinkObj( $revdel, |
206 | | - wfMsg( 'rev-delundel' ), |
| 217 | + $this->message['rev-delundel'], |
207 | 218 | 'target=' . urlencode( $this->mTitle->getPrefixedDbkey() ) . |
208 | 219 | '&oldid=' . urlencode( $rev->getId() ) ); |
| 220 | + / Bolden oversighted content |
| 221 | + if( $rev->isDeleted( Revision::DELETED_RESTRICTED ) ) |
| 222 | + $del = "<strong>$del</strong>"; |
209 | 223 | } |
210 | | - $s .= " (<small>$del</small>) "; |
| 224 | + $s .= " <tt>(<small>$del</small>)</tt> "; |
211 | 225 | } |
212 | 226 | |
213 | 227 | $s .= " $link"; |
214 | | - #getUser is safe, but this avoids making the invalid untargeted contribs links |
215 | | - if( $row->rev_deleted & Revision::DELETED_USER ) { |
216 | | - $user = '<span class="history-deleted">' . wfMsg('rev-deleted-user') . '</span>'; |
217 | | - } |
218 | | - $s .= " <span class='history-user'>$user</span>"; |
219 | | - |
| 228 | + $s .= $this->mSkin->revUserTools( $rev, true); |
| 229 | + |
220 | 230 | if( $row->rev_minor_edit ) { |
221 | 231 | $s .= ' ' . wfElement( 'span', array( 'class' => 'minor' ), wfMsg( 'minoreditletter') ); |
222 | 232 | } |
— | — | @@ -241,7 +251,7 @@ |
242 | 252 | } |
243 | 253 | #add blurb about text having been deleted |
244 | 254 | if( $row->rev_deleted & Revision::DELETED_TEXT ) { |
245 | | - $s .= ' ' . wfMsgHtml( 'deletedrev' ); |
| 255 | + $s .= ' <tt>' . wfMsgHtml( 'deletedrev' ) . '</tt>'; |
246 | 256 | } |
247 | 257 | if( $wgUser->isAllowed( 'rollback' ) && $latest ) { |
248 | 258 | $s .= ' '.$this->mSkin->generateRollback( $rev ); |
— | — | @@ -269,7 +279,7 @@ |
270 | 280 | |
271 | 281 | /** @todo document */ |
272 | 282 | function curLink( $rev, $latest ) { |
273 | | - $cur = wfMsgExt( 'cur', array( 'escape') ); |
| 283 | + $cur = $this->message['cur']; |
274 | 284 | if( $latest || !$rev->userCan( Revision::DELETED_TEXT ) ) { |
275 | 285 | return $cur; |
276 | 286 | } else { |
— | — | @@ -282,7 +292,7 @@ |
283 | 293 | |
284 | 294 | /** @todo document */ |
285 | 295 | function lastLink( $rev, $next, $counter ) { |
286 | | - $last = wfMsgExt( 'last', array( 'escape' ) ); |
| 296 | + $last = $this->message['last']; |
287 | 297 | if ( is_null( $next ) ) { |
288 | 298 | # Probably no next row |
289 | 299 | return $last; |
Index: trunk/phase3/includes/LogPage.php |
— | — | @@ -50,13 +50,15 @@ |
51 | 51 | function saveContent() { |
52 | 52 | if( wfReadOnly() ) return false; |
53 | 53 | |
54 | | - global $wgUser; |
| 54 | + global $wgUser, $wgLogRestrictions; |
55 | 55 | $fname = 'LogPage::saveContent'; |
56 | 56 | |
57 | 57 | $dbw = wfGetDB( DB_MASTER ); |
58 | 58 | $uid = $wgUser->getID(); |
59 | 59 | |
60 | 60 | $this->timestamp = $now = wfTimestampNow(); |
| 61 | + |
| 62 | + $log_id = $dbw->nextSequenceValue( 'log_log_id_seq' ); |
61 | 63 | $dbw->insert( 'logging', |
62 | 64 | array( |
63 | 65 | 'log_type' => $this->type, |
— | — | @@ -69,20 +71,15 @@ |
70 | 72 | 'log_params' => $this->params |
71 | 73 | ), $fname |
72 | 74 | ); |
| 75 | + $newId = $dbw->insertId(); |
73 | 76 | |
74 | 77 | # And update recentchanges |
75 | 78 | if ( $this->updateRecentChanges ) { |
76 | | - $titleObj = SpecialPage::getTitleFor( 'Log', $this->type ); |
77 | | - $rcComment = $this->actionText; |
78 | | - if( '' != $this->comment ) { |
79 | | - if ($rcComment == '') |
80 | | - $rcComment = $this->comment; |
81 | | - else |
82 | | - $rcComment .= ': ' . $this->comment; |
| 79 | + # Don't add private logs to RC!!! |
| 80 | + if ( !isset($wgLogRestrictions[$this->type]) || $wgLogRestrictions[$this->type]=='*' ) { |
| 81 | + RecentChange::notifyLog( $now, $this->target, $wgUser, $this->actionText, '', |
| 82 | + $this->type, $this->action, $this->target, $this->comment, $this->params, $newId ); |
83 | 83 | } |
84 | | - |
85 | | - RecentChange::notifyLog( $now, $titleObj, $wgUser, $rcComment, '', |
86 | | - $this->type, $this->action, $this->target, $this->comment, $this->params ); |
87 | 84 | } |
88 | 85 | return true; |
89 | 86 | } |
— | — | @@ -122,13 +119,13 @@ |
123 | 120 | */ |
124 | 121 | function logHeader( $type ) { |
125 | 122 | global $wgLogHeaders; |
126 | | - return wfMsg( $wgLogHeaders[$type] ); |
| 123 | + return wfMsgHtml( $wgLogHeaders[$type] ); |
127 | 124 | } |
128 | 125 | |
129 | 126 | /** |
130 | 127 | * @static |
131 | 128 | */ |
132 | | - function actionText( $type, $action, $title = NULL, $skin = NULL, $params = array(), $filterWikilinks=false, $translate=false ) { |
| 129 | + function actionText( $type, $action, $title=NULL, $skin=NULL, $params = array(), $filterWikilinks=false, $translate=false, $forRC=false ) { |
133 | 130 | global $wgLang, $wgContLang, $wgLogActions; |
134 | 131 | |
135 | 132 | $key = "$type/$action"; |
— | — | @@ -185,12 +182,17 @@ |
186 | 183 | } |
187 | 184 | } else { |
188 | 185 | array_unshift( $params, $titleLink ); |
189 | | - if ( $translate && $key == 'block/block' ) { |
| 186 | + / Oversighted blocks show as normal |
| 187 | + if ( $translate && ($key == 'block/block' || $key == 'oversight/block') ) { |
190 | 188 | $params[1] = $wgLang->translateBlockExpiry( $params[1] ); |
191 | 189 | $params[2] = isset( $params[2] ) |
192 | 190 | ? self::formatBlockFlags( $params[2] ) |
193 | 191 | : ''; |
194 | 192 | } |
| 193 | + if ( $forRC ) { |
| 194 | + $params[1] = $wgLang->translateBlockExpiry( $params[1], true ); |
| 195 | + $params[2] = isset( $params[2] ) ? str_replace( ",", ", ", self::formatBlockFlags( $params[2] ) ) : ''; |
| 196 | + } |
195 | 197 | $rv = wfMsgReal( $wgLogActions[$key], $params, true, !$skin ); |
196 | 198 | } |
197 | 199 | } |
— | — | @@ -222,7 +224,7 @@ |
223 | 225 | $this->comment = $comment; |
224 | 226 | $this->params = LogPage::makeParamBlob( $params ); |
225 | 227 | |
226 | | - $this->actionText = LogPage::actionText( $this->type, $action, $target, NULL, $params ); |
| 228 | + $this->actionText = LogPage::actionText( $this->type, $action, $target, NULL, $params, false, false, true ); |
227 | 229 | |
228 | 230 | return $this->saveContent(); |
229 | 231 | } |